diff --git a/components/driver/gdma.c b/components/driver/gdma.c index 5250d49eac..c883318e2f 100644 --- a/components/driver/gdma.c +++ b/components/driver/gdma.c @@ -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; diff --git a/components/driver/include/esp_private/gdma.h b/components/driver/include/esp_private/gdma.h index 88a45b56cf..f888cd5bc9 100644 --- a/components/driver/include/esp_private/gdma.h +++ b/components/driver/include/esp_private/gdma.h @@ -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`