From dc8456470d0dcd8b1d35f11cde0e6095956eedce Mon Sep 17 00:00:00 2001 From: Hu Rui Date: Mon, 17 Aug 2026 19:28:07 +0800 Subject: [PATCH] feat(gdma): add tx done and total_eof callbacks --- .../esp_driver_dma/include/esp_private/gdma.h | 2 ++ components/esp_driver_dma/src/gdma.c | 18 ++++++++++++++++++ .../esp_driver_spi/src/gpspi/spi_slave_hd.c | 9 ++++++--- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/components/esp_driver_dma/include/esp_private/gdma.h b/components/esp_driver_dma/include/esp_private/gdma.h index 23819760bbb..2b06a499282 100644 --- a/components/esp_driver_dma/include/esp_private/gdma.h +++ b/components/esp_driver_dma/include/esp_private/gdma.h @@ -61,7 +61,9 @@ typedef bool (*gdma_event_callback_t)(gdma_channel_handle_t dma_chan, gdma_event * @note The callbacks are all running under ISR environment */ typedef struct { + gdma_event_callback_t on_trans_done; /*!< Invoked when TX engine finishes one descriptor */ gdma_event_callback_t on_trans_eof; /*!< Invoked when TX engine meets EOF descriptor */ + gdma_event_callback_t on_trans_total_eof; /*!< Invoked when TX engine reaches the end of the descriptor chain */ gdma_event_callback_t on_descr_err; /*!< Invoked when DMA encounters a descriptor error */ gdma_event_callback_t on_link_switch; /*!< Invoked when TX link list switches to a new descriptor chain */ } gdma_tx_event_callbacks_t; diff --git a/components/esp_driver_dma/src/gdma.c b/components/esp_driver_dma/src/gdma.c index 4991d93cf6a..4ac9fcac3f1 100644 --- a/components/esp_driver_dma/src/gdma.c +++ b/components/esp_driver_dma/src/gdma.c @@ -572,10 +572,18 @@ esp_err_t gdma_register_tx_event_callbacks(gdma_channel_handle_t dma_chan, gdma_ } if (dma_chan->flags.isr_cache_safe) { + if (cbs->on_trans_done) { + ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_trans_done), ESP_ERR_INVALID_ARG, + TAG, "on_trans_done not in IRAM"); + } if (cbs->on_trans_eof) { ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_trans_eof), ESP_ERR_INVALID_ARG, TAG, "on_trans_eof not in IRAM"); } + if (cbs->on_trans_total_eof) { + ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_trans_total_eof), ESP_ERR_INVALID_ARG, + TAG, "on_trans_total_eof not in IRAM"); + } if (cbs->on_descr_err) { ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_descr_err), ESP_ERR_INVALID_ARG, TAG, "on_descr_err not in IRAM"); @@ -595,8 +603,12 @@ esp_err_t gdma_register_tx_event_callbacks(gdma_channel_handle_t dma_chan, gdma_ // enable/disable GDMA interrupt events for TX channel esp_os_enter_critical(&pair->spinlock); + gdma_hal_enable_intr(hal, pair->pair_id, GDMA_CHANNEL_DIRECTION_TX, GDMA_LL_EVENT_TX_DONE, + cbs->on_trans_done != NULL); gdma_hal_enable_intr(hal, pair->pair_id, GDMA_CHANNEL_DIRECTION_TX, GDMA_LL_EVENT_TX_EOF, cbs->on_trans_eof != NULL); + gdma_hal_enable_intr(hal, pair->pair_id, GDMA_CHANNEL_DIRECTION_TX, GDMA_LL_EVENT_TX_TOTAL_EOF, + cbs->on_trans_total_eof != NULL); gdma_hal_enable_intr(hal, pair->pair_id, GDMA_CHANNEL_DIRECTION_TX, GDMA_LL_EVENT_TX_DESC_ERROR, cbs->on_descr_err != NULL); #if GDMA_LL_EVENT_TX_LINK_SWITCH @@ -1045,6 +1057,9 @@ void gdma_default_tx_isr(void *args) uint32_t intr_status = gdma_hal_read_intr_status(hal, pair_id, GDMA_CHANNEL_DIRECTION_TX, false); gdma_hal_clear_intr(hal, pair_id, GDMA_CHANNEL_DIRECTION_TX, intr_status); + if ((intr_status & GDMA_LL_EVENT_TX_DONE) && tx_chan->cbs.on_trans_done) { + need_yield |= tx_chan->cbs.on_trans_done(&tx_chan->base, NULL, tx_chan->user_data); + } if ((intr_status & GDMA_LL_EVENT_TX_EOF) && tx_chan->cbs.on_trans_eof) { uint32_t eof_addr = gdma_hal_get_eof_desc_addr(hal, pair_id, GDMA_CHANNEL_DIRECTION_TX, true); gdma_event_data_t edata = { @@ -1053,6 +1068,9 @@ void gdma_default_tx_isr(void *args) }; need_yield |= tx_chan->cbs.on_trans_eof(&tx_chan->base, &edata, tx_chan->user_data); } + if ((intr_status & GDMA_LL_EVENT_TX_TOTAL_EOF) && tx_chan->cbs.on_trans_total_eof) { + need_yield |= tx_chan->cbs.on_trans_total_eof(&tx_chan->base, NULL, tx_chan->user_data); + } if ((intr_status & GDMA_LL_EVENT_TX_DESC_ERROR) && tx_chan->cbs.on_descr_err) { need_yield |= tx_chan->cbs.on_descr_err(&tx_chan->base, NULL, tx_chan->user_data); } diff --git a/components/esp_driver_spi/src/gpspi/spi_slave_hd.c b/components/esp_driver_spi/src/gpspi/spi_slave_hd.c index 0c32ba5da27..18e04146174 100644 --- a/components/esp_driver_spi/src/gpspi/spi_slave_hd.c +++ b/components/esp_driver_spi/src/gpspi/spi_slave_hd.c @@ -263,11 +263,14 @@ esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *b //Append mode #if SOC_GDMA_SUPPORTED // config gmda event callback for gdma supported chip - gdma_rx_event_callbacks_t txrx_cbs = { + gdma_tx_event_callbacks_t tx_cbs = { + .on_trans_eof = s_spi_slave_hd_append_gdma_isr, + }; + gdma_rx_event_callbacks_t rx_cbs = { .on_recv_eof = s_spi_slave_hd_append_gdma_isr, }; - gdma_register_tx_event_callbacks(host->dma_ctx->tx_dma_chan, (gdma_tx_event_callbacks_t *)&txrx_cbs, host); - gdma_register_rx_event_callbacks(host->dma_ctx->rx_dma_chan, &txrx_cbs, host); + gdma_register_tx_event_callbacks(host->dma_ctx->tx_dma_chan, &tx_cbs, host); + gdma_register_rx_event_callbacks(host->dma_ctx->rx_dma_chan, &rx_cbs, host); #else //On ESP32S2, `cmd7` and `cmd8` are designed as all `spi_dma` events, so use `dma_src` only ret = esp_intr_alloc(spicommon_irqdma_source_for_host(host_id), bus_config->intr_flags, s_spi_slave_hd_append_legacy_isr,