Merge branch 'bugfix/add_spinlock_for_dma_channel' into 'release/v4.4'

gdma: add spin lock for gdma channel (v4.4)

See merge request espressif/esp-idf!17855
This commit is contained in:
morris
2022-04-24 18:16:58 +08:00
4 changed files with 30 additions and 6 deletions

View File

@ -87,6 +87,7 @@ struct gdma_pair_t {
struct gdma_channel_t {
gdma_pair_t *pair; // which pair the channel belongs to
intr_handle_t intr; // per-channel interrupt handle
portMUX_TYPE spinlock; // channel level spinlock
gdma_channel_direction_t direction; // channel direction
int periph_id; // Peripheral instance ID, indicates which peripheral is connected to this GDMA channel
size_t sram_alignment; // alignment for memory in SRAM
@ -200,6 +201,7 @@ search_done:
*ret_chan = &alloc_rx_channel->base; // return the installed channel
}
(*ret_chan)->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
ESP_LOGD(TAG, "new %s channel (%d,%d) at %p", (config->direction == GDMA_CHANNEL_DIRECTION_TX) ? "tx" : "rx",
group->group_id, pair->pair_id, *ret_chan);
return ESP_OK;
@ -451,10 +453,11 @@ esp_err_t gdma_start(gdma_channel_handle_t dma_chan, intptr_t desc_base_addr)
esp_err_t ret = ESP_OK;
gdma_pair_t *pair = NULL;
gdma_group_t *group = NULL;
ESP_GOTO_ON_FALSE(dma_chan, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
ESP_GOTO_ON_FALSE_ISR(dma_chan, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
pair = dma_chan->pair;
group = pair->group;
portENTER_CRITICAL_SAFE(&dma_chan->spinlock);
if (dma_chan->direction == GDMA_CHANNEL_DIRECTION_RX) {
gdma_ll_rx_set_desc_addr(group->hal.dev, pair->pair_id, desc_base_addr);
gdma_ll_rx_start(group->hal.dev, pair->pair_id);
@ -462,6 +465,7 @@ esp_err_t gdma_start(gdma_channel_handle_t dma_chan, intptr_t desc_base_addr)
gdma_ll_tx_set_desc_addr(group->hal.dev, pair->pair_id, desc_base_addr);
gdma_ll_tx_start(group->hal.dev, pair->pair_id);
}
portEXIT_CRITICAL_SAFE(&dma_chan->spinlock);
err:
return ret;
@ -472,15 +476,17 @@ esp_err_t gdma_stop(gdma_channel_handle_t dma_chan)
esp_err_t ret = ESP_OK;
gdma_pair_t *pair = NULL;
gdma_group_t *group = NULL;
ESP_GOTO_ON_FALSE(dma_chan, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
ESP_GOTO_ON_FALSE_ISR(dma_chan, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
pair = dma_chan->pair;
group = pair->group;
portENTER_CRITICAL_SAFE(&dma_chan->spinlock);
if (dma_chan->direction == GDMA_CHANNEL_DIRECTION_RX) {
gdma_ll_rx_stop(group->hal.dev, pair->pair_id);
} else {
gdma_ll_tx_stop(group->hal.dev, pair->pair_id);
}
portEXIT_CRITICAL_SAFE(&dma_chan->spinlock);
err:
return ret;
@ -491,15 +497,17 @@ esp_err_t gdma_append(gdma_channel_handle_t dma_chan)
esp_err_t ret = ESP_OK;
gdma_pair_t *pair = NULL;
gdma_group_t *group = NULL;
ESP_GOTO_ON_FALSE(dma_chan, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
ESP_GOTO_ON_FALSE_ISR(dma_chan, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
pair = dma_chan->pair;
group = pair->group;
portENTER_CRITICAL_SAFE(&dma_chan->spinlock);
if (dma_chan->direction == GDMA_CHANNEL_DIRECTION_RX) {
gdma_ll_rx_restart(group->hal.dev, pair->pair_id);
} else {
gdma_ll_tx_restart(group->hal.dev, pair->pair_id);
}
portEXIT_CRITICAL_SAFE(&dma_chan->spinlock);
err:
return ret;
@ -510,15 +518,17 @@ esp_err_t gdma_reset(gdma_channel_handle_t dma_chan)
esp_err_t ret = ESP_OK;
gdma_pair_t *pair = NULL;
gdma_group_t *group = NULL;
ESP_GOTO_ON_FALSE(dma_chan, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
ESP_GOTO_ON_FALSE_ISR(dma_chan, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
pair = dma_chan->pair;
group = pair->group;
portENTER_CRITICAL_SAFE(&dma_chan->spinlock);
if (dma_chan->direction == GDMA_CHANNEL_DIRECTION_RX) {
gdma_ll_rx_reset_channel(group->hal.dev, pair->pair_id);
} else {
gdma_ll_tx_reset_channel(group->hal.dev, pair->pair_id);
}
portEXIT_CRITICAL_SAFE(&dma_chan->spinlock);
err:
return ret;

View File

@ -269,6 +269,9 @@ esp_err_t gdma_register_rx_event_callbacks(gdma_channel_handle_t dma_chan, gdma_
/**
* @brief Set DMA descriptor address and start engine
*
* @note This function is allowed to run within ISR context
* @note This function is also allowed to run when Cache is disabled, if `CONFIG_GDMA_CTRL_FUNC_IN_IRAM` is enabled
*
* @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel`
* @param[in] desc_base_addr Base address of descriptors (usually the descriptors are chained into a link or ring)
* @return
@ -281,6 +284,9 @@ esp_err_t gdma_start(gdma_channel_handle_t dma_chan, intptr_t desc_base_addr);
/**
* @brief Stop DMA engine
*
* @note This function is allowed to run within ISR context
* @note This function is also allowed to run when Cache is disabled, if `CONFIG_GDMA_CTRL_FUNC_IN_IRAM` is enabled
*
* @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel`
* @return
* - ESP_OK: Stop DMA engine successfully
@ -291,6 +297,9 @@ esp_err_t gdma_stop(gdma_channel_handle_t dma_chan);
/**
* @brief Make the appended descriptors be aware to the DMA engine
*
* @note This function is allowed to run within ISR context
* @note This function is also allowed to run when Cache is disabled, if `CONFIG_GDMA_CTRL_FUNC_IN_IRAM` is enabled
* @note This API could also resume a paused DMA engine, make sure new descriptors have been appended to the descriptor chain before calling it.
*
* @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel`
@ -303,6 +312,9 @@ esp_err_t gdma_append(gdma_channel_handle_t dma_chan);
/**
* @brief Reset DMA channel FIFO and internal finite state machine
*
* @note This function is allowed to run within ISR context
* @note This function is also allowed to run when Cache is disabled, if `CONFIG_GDMA_CTRL_FUNC_IN_IRAM` is enabled
* @note Resetting a DMA channel won't break the connection with the target peripheral
*
* @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel`

View File

@ -98,7 +98,8 @@ typedef struct {
unsigned int dc_as_cmd_phase: 1; /*!< D/C line value is encoded into SPI transaction command phase */
unsigned int dc_low_on_data: 1; /*!< If this flag is enabled, DC line = 0 means transfer data, DC line = 1 means transfer command; vice versa */
unsigned int octal_mode: 1; /*!< transmit with octal mode (8 data lines), this mode is used to simulate Intel 8080 timing */
} flags;
unsigned int lsb_first: 1; /*!< transmit LSB bit first */
} flags; /*!< Extra flags to fine-tune the SPI device */
} esp_lcd_panel_io_spi_config_t;
/**

View File

@ -65,7 +65,8 @@ esp_err_t esp_lcd_new_panel_io_spi(esp_lcd_spi_bus_handle_t bus, const esp_lcd_p
ESP_GOTO_ON_FALSE(spi_panel_io, ESP_ERR_NO_MEM, err, TAG, "no mem for spi panel io");
spi_device_interface_config_t devcfg = {
.flags = SPI_DEVICE_HALFDUPLEX, // only use TX path, so half duplex is enough
// currently the driver only supports TX path, so half duplex is enough
.flags = SPI_DEVICE_HALFDUPLEX | (io_config->flags.lsb_first ? SPI_DEVICE_TXBIT_LSBFIRST : 0),
.clock_speed_hz = io_config->pclk_hz,
.mode = io_config->spi_mode,
.spics_io_num = io_config->cs_gpio_num,