From be8a0d08f272404e81226b40fd3c7166f948904b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20G=C3=BCrtler?= Date: Thu, 25 May 2023 10:08:50 +0200 Subject: [PATCH] gdma: implement descriptor error callback Merges https://github.com/espressif/esp-idf/pull/11499 --- components/esp_hw_support/dma/gdma.c | 25 ++++++++++++++++++- components/esp_hw_support/dma/gdma_priv.h | 4 ++- .../esp_hw_support/include/esp_private/gdma.h | 10 +++----- 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/components/esp_hw_support/dma/gdma.c b/components/esp_hw_support/dma/gdma.c index 8247b07af7..4375a5b79b 100644 --- a/components/esp_hw_support/dma/gdma.c +++ b/components/esp_hw_support/dma/gdma.c @@ -391,6 +391,9 @@ esp_err_t gdma_register_tx_event_callbacks(gdma_channel_handle_t dma_chan, gdma_ if (cbs->on_trans_eof) { ESP_GOTO_ON_FALSE(esp_ptr_in_iram(cbs->on_trans_eof), ESP_ERR_INVALID_ARG, err, TAG, "on_trans_eof not in IRAM"); } + if (cbs->on_descr_err) { + ESP_GOTO_ON_FALSE(esp_ptr_in_iram(cbs->on_descr_err), ESP_ERR_INVALID_ARG, err, TAG, "on_descr_err not in IRAM"); + } if (user_data) { ESP_GOTO_ON_FALSE(esp_ptr_internal(user_data), ESP_ERR_INVALID_ARG, err, TAG, "user context not in internal RAM"); } @@ -402,9 +405,11 @@ esp_err_t gdma_register_tx_event_callbacks(gdma_channel_handle_t dma_chan, gdma_ // enable/disable GDMA interrupt events for TX channel portENTER_CRITICAL(&pair->spinlock); gdma_ll_tx_enable_interrupt(group->hal.dev, pair->pair_id, GDMA_LL_EVENT_TX_EOF, cbs->on_trans_eof != NULL); + gdma_ll_tx_enable_interrupt(group->hal.dev, pair->pair_id, GDMA_LL_EVENT_TX_DESC_ERROR, cbs->on_descr_err != NULL); portEXIT_CRITICAL(&pair->spinlock); tx_chan->on_trans_eof = cbs->on_trans_eof; + tx_chan->on_descr_err = cbs->on_descr_err; tx_chan->user_data = user_data; ESP_GOTO_ON_ERROR(esp_intr_enable(dma_chan->intr), err, TAG, "enable interrupt failed"); @@ -427,6 +432,9 @@ esp_err_t gdma_register_rx_event_callbacks(gdma_channel_handle_t dma_chan, gdma_ if (cbs->on_recv_eof) { ESP_GOTO_ON_FALSE(esp_ptr_in_iram(cbs->on_recv_eof), ESP_ERR_INVALID_ARG, err, TAG, "on_recv_eof not in IRAM"); } + if (cbs->on_descr_err) { + ESP_GOTO_ON_FALSE(esp_ptr_in_iram(cbs->on_descr_err), ESP_ERR_INVALID_ARG, err, TAG, "on_descr_err not in IRAM"); + } if (user_data) { ESP_GOTO_ON_FALSE(esp_ptr_internal(user_data), ESP_ERR_INVALID_ARG, err, TAG, "user context not in internal RAM"); } @@ -438,9 +446,11 @@ esp_err_t gdma_register_rx_event_callbacks(gdma_channel_handle_t dma_chan, gdma_ // enable/disable GDMA interrupt events for RX channel portENTER_CRITICAL(&pair->spinlock); gdma_ll_rx_enable_interrupt(group->hal.dev, pair->pair_id, GDMA_LL_EVENT_RX_SUC_EOF, cbs->on_recv_eof != NULL); + gdma_ll_rx_enable_interrupt(group->hal.dev, pair->pair_id, GDMA_LL_EVENT_RX_DESC_ERROR, cbs->on_descr_err != NULL); portEXIT_CRITICAL(&pair->spinlock); rx_chan->on_recv_eof = cbs->on_recv_eof; + rx_chan->on_descr_err = cbs->on_descr_err; rx_chan->user_data = user_data; ESP_GOTO_ON_ERROR(esp_intr_enable(dma_chan->intr), err, TAG, "enable interrupt failed"); @@ -726,6 +736,13 @@ static void IRAM_ATTR gdma_default_rx_isr(void *args) } } } + if (intr_status & GDMA_LL_EVENT_RX_DESC_ERROR) { + if (rx_chan && rx_chan->on_descr_err) { + if (rx_chan->on_descr_err(&rx_chan->base, NULL, rx_chan->user_data)) { + need_yield = true; + } + } + } if (need_yield) { portYIELD_FROM_ISR(); @@ -753,7 +770,13 @@ static void IRAM_ATTR gdma_default_tx_isr(void *args) } } } - + if (intr_status & GDMA_LL_EVENT_TX_DESC_ERROR) { + if (tx_chan && tx_chan->on_descr_err) { + if (tx_chan->on_descr_err(&tx_chan->base, NULL, tx_chan->user_data)) { + need_yield = true; + } + } + } if (need_yield) { portYIELD_FROM_ISR(); } diff --git a/components/esp_hw_support/dma/gdma_priv.h b/components/esp_hw_support/dma/gdma_priv.h index 572a3502d1..a47aa4b05c 100644 --- a/components/esp_hw_support/dma/gdma_priv.h +++ b/components/esp_hw_support/dma/gdma_priv.h @@ -76,12 +76,14 @@ struct gdma_tx_channel_t { gdma_channel_t base; // GDMA channel, base class void *user_data; // user registered DMA event data gdma_event_callback_t on_trans_eof; // TX EOF callback + gdma_event_callback_t on_descr_err; // Descriptor error callback }; struct gdma_rx_channel_t { gdma_channel_t base; // GDMA channel, base class void *user_data; // user registered DMA event data - gdma_event_callback_t on_recv_eof; // RX EOF callback + gdma_event_callback_t on_recv_eof; // RX EOF callback + gdma_event_callback_t on_descr_err; // Descriptor error callback }; #ifdef __cplusplus diff --git a/components/esp_hw_support/include/esp_private/gdma.h b/components/esp_hw_support/include/esp_private/gdma.h index bf5d97dd32..0c5cda8f61 100644 --- a/components/esp_hw_support/include/esp_private/gdma.h +++ b/components/esp_hw_support/include/esp_private/gdma.h @@ -52,7 +52,6 @@ typedef struct { /** * @brief Type of GDMA event data - * */ typedef struct { union { @@ -64,31 +63,30 @@ typedef struct { /** * @brief Type of GDMA event callback * @param dma_chan GDMA channel handle, created from `gdma_new_channel` - * @param event_data GDMA event data + * @param event_data GDMA event data. Different event share the same data structure, but the caller may only use a few or none of the data members. * @param user_data User registered data from `gdma_register_tx_event_callbacks` or `gdma_register_rx_event_callbacks` * * @return Whether a task switch is needed after the callback function returns, * this is usually due to the callback wakes up some high priority task. - * */ typedef bool (*gdma_event_callback_t)(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data); /** * @brief Group of supported GDMA TX callbacks * @note The callbacks are all running under ISR environment - * */ typedef struct { gdma_event_callback_t on_trans_eof; /*!< Invoked when TX engine meets EOF descriptor */ + gdma_event_callback_t on_descr_err; /*!< Invoked when DMA encounters a descriptor error */ } gdma_tx_event_callbacks_t; /** * @brief Group of supported GDMA RX callbacks * @note The callbacks are all running under ISR environment - * */ typedef struct { - gdma_event_callback_t on_recv_eof; /*!< Invoked when RX engine meets EOF descriptor */ + gdma_event_callback_t on_recv_eof; /*!< Invoked when RX engine meets EOF descriptor */ + gdma_event_callback_t on_descr_err; /*!< Invoked when DMA encounters a descriptor error */ } gdma_rx_event_callbacks_t; /**