From bc98bdc087e497b3c905c38ccb82ff4819b6cf33 Mon Sep 17 00:00:00 2001 From: gaoxu Date: Tue, 12 Mar 2024 11:12:48 +0800 Subject: [PATCH] refactor(adc): refactor dma ll functions on adc continuous mode --- components/driver/deprecated/adc_dma_legacy.c | 144 +++++---- components/esp_adc/CMakeLists.txt | 7 + components/esp_adc/adc_continuous.c | 280 +++++------------- components/esp_adc/adc_continuous_internal.h | 15 +- components/esp_adc/adc_dma_internal.h | 37 +++ components/esp_adc/esp32/adc_dma.c | 91 ++++++ components/esp_adc/esp32s2/adc_dma.c | 93 ++++++ components/esp_adc/gdma/adc_dma.c | 69 +++++ .../esp_adc/include/esp_private/adc_dma.h | 81 +++++ components/esp_adc/linker.lf | 4 - components/hal/adc_hal.c | 180 +++-------- components/hal/include/hal/adc_hal.h | 60 +--- 12 files changed, 621 insertions(+), 440 deletions(-) create mode 100644 components/esp_adc/adc_dma_internal.h create mode 100644 components/esp_adc/esp32/adc_dma.c create mode 100644 components/esp_adc/esp32s2/adc_dma.c create mode 100644 components/esp_adc/gdma/adc_dma.c create mode 100644 components/esp_adc/include/esp_private/adc_dma.h diff --git a/components/driver/deprecated/adc_dma_legacy.c b/components/driver/deprecated/adc_dma_legacy.c index d91f7771d2..d821e687cd 100644 --- a/components/driver/deprecated/adc_dma_legacy.c +++ b/components/driver/deprecated/adc_dma_legacy.c @@ -57,6 +57,54 @@ extern portMUX_TYPE rtc_spinlock; //TODO: Will be placed in the appropriate posi #define INTERNAL_BUF_NUM 5 +#if SOC_AHB_GDMA_VERSION == 1 +#define ADC_GDMA_HOST 0 +#define ADC_DMA_INTR_MASK GDMA_LL_EVENT_RX_SUC_EOF +#define ADC_DMA_INTR_MASK GDMA_LL_EVENT_RX_SUC_EOF +#define adc_dma_start(adc_dma, addr) gdma_start(s_adc_digi_ctx->rx_dma_channel, (intptr_t)addr) +#define adc_dma_stop(adc_dma) gdma_stop(s_adc_digi_ctx->rx_dma_channel) +#define adc_dma_reset(adc_dma) gdma_reset(s_adc_digi_ctx->rx_dma_channel) +#define adc_dma_clear_intr(adc_dma) +#define adc_dma_enable_intr(adc_dma) +#define adc_dma_disable_intr(adc_dma) +#define adc_dma_deinit(adc_dma) do { \ + gdma_disconnect(s_adc_digi_ctx->rx_dma_channel); \ + gdma_del_channel(s_adc_digi_ctx->rx_dma_channel); \ + } while (0) + +#elif CONFIG_IDF_TARGET_ESP32S2 +#define ADC_DMA_SPI_HOST SPI3_HOST +#define ADC_DMA_INTR_MASK SPI_LL_INTR_IN_SUC_EOF +#define adc_dma_start(adc_dma, addr) spi_dma_ll_rx_start(s_adc_digi_ctx->adc_spi_dev, s_adc_digi_ctx->spi_dma_ctx->rx_dma_chan.chan_id, (lldesc_t *)addr) +#define adc_dma_stop(adc_dma) spi_dma_ll_rx_stop(s_adc_digi_ctx->adc_spi_dev, s_adc_digi_ctx->spi_dma_ctx->rx_dma_chan.chan_id); +#define adc_dma_reset(adc_dma) spi_dma_ll_rx_reset(s_adc_digi_ctx->adc_spi_dev, s_adc_digi_ctx->spi_dma_ctx->rx_dma_chan.chan_id); +#define adc_dma_clear_intr(adc_dma) spi_ll_clear_intr(s_adc_digi_ctx->adc_spi_dev, ADC_DMA_INTR_MASK) +#define adc_dma_enable_intr(adc_dma) spi_ll_enable_intr(s_adc_digi_ctx->adc_spi_dev, ADC_DMA_INTR_MASK); +#define adc_dma_disable_intr(adc_dma) spi_ll_disable_intr(s_adc_digi_ctx->adc_spi_dev, ADC_DMA_INTR_MASK); +#define adc_dma_deinit(adc_dma) do { \ + esp_intr_free(s_adc_digi_ctx->intr_hdl); \ + spicommon_dma_chan_free(s_adc_digi_ctx->spi_dma_ctx); \ + spicommon_periph_free(ADC_DMA_SPI_HOST); \ + } while (0) + +#elif CONFIG_IDF_TARGET_ESP32 +#define ADC_DMA_I2S_HOST I2S_NUM_0 +#define ADC_DMA_INTR_MASK BIT(9) +#define adc_dma_start(adc_dma, addr) do { \ + i2s_ll_enable_dma(s_adc_digi_ctx->adc_i2s_dev, true); \ + i2s_ll_rx_start_link(s_adc_digi_ctx->adc_i2s_dev, (uint32_t)addr); \ + } while (0) +#define adc_dma_stop(adc_dma) i2s_ll_rx_stop_link(s_adc_digi_ctx->adc_i2s_dev); +#define adc_dma_reset(adc_dma) i2s_ll_rx_reset_dma(s_adc_digi_ctx->adc_i2s_dev); +#define adc_dma_clear_intr(adc_dma) i2s_ll_clear_intr_status(s_adc_digi_ctx->adc_i2s_dev, ADC_DMA_INTR_MASK); +#define adc_dma_enable_intr(adc_dma) i2s_ll_enable_intr(s_adc_digi_ctx->adc_i2s_dev, ADC_DMA_INTR_MASK, true); +#define adc_dma_disable_intr(adc_dma) i2s_ll_enable_intr(s_adc_digi_ctx->adc_i2s_dev, ADC_DMA_INTR_MASK, false); +#define adc_dma_deinit(adc_dma) do { \ + esp_intr_free(s_adc_digi_ctx->intr_hdl); \ + i2s_platform_release_occupation(ADC_DMA_I2S_HOST); \ + } while (0) +#endif + /*--------------------------------------------------------------- Digital Controller Context ---------------------------------------------------------------*/ @@ -69,9 +117,11 @@ typedef struct adc_digi_context_t { spi_host_device_t spi_host; //ADC uses this SPI DMA spi_dma_ctx_t *spi_dma_ctx; //spi_dma context intr_handle_t intr_hdl; //Interrupt handler + spi_dev_t *adc_spi_dev ; #elif CONFIG_IDF_TARGET_ESP32 i2s_port_t i2s_host; //ADC uses this I2S DMA intr_handle_t intr_hdl; //Interrupt handler + i2s_dev_t *adc_i2s_dev; #endif RingbufHandle_t ringbuf_hdl; //RX ringbuffer handler intptr_t rx_eof_desc_addr; //eof descriptor address of RX channel @@ -163,17 +213,8 @@ esp_err_t adc_digi_deinitialize(void) free(s_adc_digi_ctx->rx_dma_buf); free(s_adc_digi_ctx->hal.rx_desc); free(s_adc_digi_ctx->hal_digi_ctrlr_cfg.adc_pattern); -#if SOC_GDMA_SUPPORTED - gdma_disconnect(s_adc_digi_ctx->rx_dma_channel); - gdma_del_channel(s_adc_digi_ctx->rx_dma_channel); -#elif CONFIG_IDF_TARGET_ESP32S2 - esp_intr_free(s_adc_digi_ctx->intr_hdl); - spicommon_dma_chan_free(s_adc_digi_ctx->spi_dma_ctx); - spicommon_periph_free(s_adc_digi_ctx->spi_host); -#elif CONFIG_IDF_TARGET_ESP32 - esp_intr_free(s_adc_digi_ctx->intr_hdl); - i2s_platform_release_occupation(s_adc_digi_ctx->i2s_host); -#endif + + adc_dma_deinit(s_adc_digi_ctx); free(s_adc_digi_ctx); s_adc_digi_ctx = NULL; @@ -266,57 +307,46 @@ esp_err_t adc_digi_initialize(const adc_digi_init_config_t *init_config) }; gdma_register_rx_event_callbacks(s_adc_digi_ctx->rx_dma_channel, &cbs, s_adc_digi_ctx); - int dma_chan; - gdma_get_channel_id(s_adc_digi_ctx->rx_dma_channel, &dma_chan); - #elif CONFIG_IDF_TARGET_ESP32S2 //ADC utilises SPI3 DMA on ESP32S2 bool spi_success = false; - uint32_t dma_chan = 0; - spi_success = spicommon_periph_claim(SPI3_HOST, "adc"); - ret = spicommon_dma_chan_alloc(SPI3_HOST, SPI_DMA_CH_AUTO, &s_adc_digi_ctx->spi_dma_ctx); - if (ret == ESP_OK) { - s_adc_digi_ctx->spi_host = SPI3_HOST; - } - if (!spi_success || (s_adc_digi_ctx->spi_host != SPI3_HOST)) { + spi_success = spicommon_periph_claim(ADC_DMA_SPI_HOST, "adc"); + ret = spicommon_dma_chan_alloc(ADC_DMA_SPI_HOST, SPI_DMA_CH_AUTO, &(s_adc_digi_ctx->spi_dma_ctx)); + if (ret != ESP_OK || spi_success != ESP_OK) { + goto cleanup; + } + if (!spi_success || (s_adc_digi_ctx->spi_host != ADC_DMA_SPI_HOST)) { goto cleanup; } - dma_chan = s_adc_digi_ctx->spi_dma_ctx->rx_dma_chan.chan_id; - ret = esp_intr_alloc(spicommon_irqdma_source_for_host(s_adc_digi_ctx->spi_host), 0, adc_dma_intr_handler, + ret = esp_intr_alloc(spicommon_irqdma_source_for_host(ADC_DMA_SPI_HOST), 0, adc_dma_intr_handler, (void *)s_adc_digi_ctx, &s_adc_digi_ctx->intr_hdl); if (ret != ESP_OK) { goto cleanup; } - + s_adc_digi_ctx->adc_spi_dev = SPI_LL_GET_HW(ADC_DMA_SPI_HOST); #elif CONFIG_IDF_TARGET_ESP32 //ADC utilises I2S0 DMA on ESP32 - uint32_t dma_chan = 0; - ret = i2s_platform_acquire_occupation(I2S_NUM_0, "adc"); + ret = i2s_platform_acquire_occupation(ADC_DMA_I2S_HOST, "adc"); if (ret != ESP_OK) { + ret = ESP_ERR_NOT_FOUND; goto cleanup; } s_adc_digi_ctx->i2s_host = I2S_NUM_0; - ret = esp_intr_alloc(i2s_periph_signal[s_adc_digi_ctx->i2s_host].irq, 0, adc_dma_intr_handler, + + ret = esp_intr_alloc(i2s_periph_signal[ADC_DMA_I2S_HOST].irq, 0, adc_dma_intr_handler, (void *)s_adc_digi_ctx, &s_adc_digi_ctx->intr_hdl); if (ret != ESP_OK) { goto cleanup; } + s_adc_digi_ctx->adc_i2s_dev = I2S_LL_GET_HW(ADC_DMA_I2S_HOST); #endif adc_hal_dma_config_t config = { -#if SOC_GDMA_SUPPORTED - .dev = (void *)GDMA_LL_GET_HW(0), -#elif CONFIG_IDF_TARGET_ESP32S2 - .dev = (void *)SPI_LL_GET_HW(s_adc_digi_ctx->spi_host), -#elif CONFIG_IDF_TARGET_ESP32 - .dev = (void *)I2S_LL_GET_HW(s_adc_digi_ctx->i2s_host), -#endif .eof_desc_num = INTERNAL_BUF_NUM, .eof_step = dma_desc_num_per_frame, - .dma_chan = dma_chan, .eof_num = init_config->conv_num_each_intr / SOC_ADC_DIGI_DATA_BYTES_PER_CONV }; adc_hal_dma_ctx_config(&s_adc_digi_ctx->hal, &config); @@ -348,16 +378,24 @@ static IRAM_ATTR void adc_dma_intr_handler(void *arg) adc_digi_context_t *ctx = (adc_digi_context_t *)arg; bool need_yield = false; - bool conversion_finish = adc_hal_check_event(&ctx->hal, ADC_HAL_DMA_INTR_MASK); +#if CONFIG_IDF_TARGET_ESP32S2 + bool conversion_finish = spi_ll_get_intr(s_adc_digi_ctx->adc_spi_dev, ADC_DMA_INTR_MASK); if (conversion_finish) { - adc_hal_digi_clr_intr(&s_adc_digi_ctx->hal, ADC_HAL_DMA_INTR_MASK); - - intptr_t desc_addr = adc_hal_get_desc_addr(&ctx->hal); - + spi_ll_clear_intr(s_adc_digi_ctx->adc_spi_dev, ADC_DMA_INTR_MASK); + intptr_t desc_addr = spi_dma_ll_get_in_suc_eof_desc_addr(s_adc_digi_ctx->adc_spi_dev, s_adc_digi_ctx->spi_dma_ctx->rx_dma_chan.chan_id); ctx->rx_eof_desc_addr = desc_addr; need_yield = s_adc_dma_intr(ctx); } - +#elif CONFIG_IDF_TARGET_ESP32 + bool conversion_finish = i2s_ll_get_intr_status(s_adc_digi_ctx->adc_i2s_dev) & ADC_DMA_INTR_MASK; + if (conversion_finish) { + i2s_ll_clear_intr_status(s_adc_digi_ctx->adc_i2s_dev, ADC_DMA_INTR_MASK); + uint32_t desc_addr; + i2s_ll_rx_get_eof_des_addr(s_adc_digi_ctx->adc_i2s_dev, &desc_addr); + ctx->rx_eof_desc_addr = (intptr_t)desc_addr; + need_yield = s_adc_dma_intr(ctx); + } +#endif if (need_yield) { portYIELD_FROM_ISR(); } @@ -433,8 +471,16 @@ esp_err_t adc_digi_start(void) adc_hal_digi_init(&s_adc_digi_ctx->hal); adc_hal_digi_controller_config(&s_adc_digi_ctx->hal, &s_adc_digi_ctx->hal_digi_ctrlr_cfg); - //start conversion - adc_hal_digi_start(&s_adc_digi_ctx->hal, s_adc_digi_ctx->rx_dma_buf); + adc_dma_stop(s_adc_digi_ctx); + adc_hal_digi_connect(false); + + adc_dma_reset(s_adc_digi_ctx); + adc_hal_digi_reset(); + adc_hal_digi_dma_link(&s_adc_digi_ctx->hal, s_adc_digi_ctx->rx_dma_buf); + + adc_dma_start(s_adc_digi_ctx, s_adc_digi_ctx->hal.rx_desc); + adc_hal_digi_connect(true); + adc_hal_digi_enable(true); return ESP_OK; } @@ -447,14 +493,12 @@ esp_err_t adc_digi_stop(void) } s_adc_digi_ctx->driver_start_flag = 0; - //disable the in suc eof intrrupt - adc_hal_digi_dis_intr(&s_adc_digi_ctx->hal, ADC_HAL_DMA_INTR_MASK); - //clear the in suc eof interrupt - adc_hal_digi_clr_intr(&s_adc_digi_ctx->hal, ADC_HAL_DMA_INTR_MASK); - //stop ADC - adc_hal_digi_stop(&s_adc_digi_ctx->hal); + adc_dma_stop(s_adc_digi_ctx); + adc_hal_digi_enable(false); + adc_hal_digi_connect(false); + + adc_hal_digi_deinit(); - adc_hal_digi_deinit(&s_adc_digi_ctx->hal); #if CONFIG_PM_ENABLE if (s_adc_digi_ctx->pm_lock) { esp_pm_lock_release(s_adc_digi_ctx->pm_lock); diff --git a/components/esp_adc/CMakeLists.txt b/components/esp_adc/CMakeLists.txt index 180ef6e8cf..e8a3e96aef 100644 --- a/components/esp_adc/CMakeLists.txt +++ b/components/esp_adc/CMakeLists.txt @@ -19,6 +19,13 @@ if(CONFIG_SOC_ADC_DMA_SUPPORTED) if(CONFIG_SOC_ADC_MONITOR_SUPPORTED) list(APPEND srcs "adc_monitor.c") endif() + if(CONFIG_SOC_GDMA_SUPPORTED) + list(APPEND srcs "gdma/adc_dma.c") + elseif(${target} STREQUAL "esp32") + list(APPEND srcs "esp32/adc_dma.c") + elseif(${target} STREQUAL "esp32s2") + list(APPEND srcs "esp32s2/adc_dma.c") + endif() endif() if(CONFIG_SOC_ADC_DIG_IIR_FILTER_SUPPORTED) diff --git a/components/esp_adc/adc_continuous.c b/components/esp_adc/adc_continuous.c index 8d380a343f..9fecdf51be 100644 --- a/components/esp_adc/adc_continuous.c +++ b/components/esp_adc/adc_continuous.c @@ -35,18 +35,8 @@ #include "hal/dma_types.h" #include "esp_memory_utils.h" #include "adc_continuous_internal.h" -//For DMA -#if SOC_GDMA_SUPPORTED -#include "esp_private/gdma.h" -#elif CONFIG_IDF_TARGET_ESP32S2 -#include "hal/spi_types.h" -#include "esp_private/spi_common_internal.h" -#elif CONFIG_IDF_TARGET_ESP32 -#include "hal/i2s_types.h" -#include "driver/i2s_types.h" -#include "soc/i2s_periph.h" -#include "esp_private/i2s_platform.h" -#endif +#include "esp_private/adc_dma.h" +#include "adc_dma_internal.h" static const char *ADC_TAG = "adc_continuous"; @@ -61,14 +51,66 @@ extern portMUX_TYPE rtc_spinlock; //TODO: Will be placed in the appropriate posi /*--------------------------------------------------------------- ADC Continuous Read Mode (via DMA) ---------------------------------------------------------------*/ -//Function to address transaction -static bool s_adc_dma_intr(adc_continuous_ctx_t *adc_digi_ctx); -#if SOC_GDMA_SUPPORTED -static bool adc_dma_in_suc_eof_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data); -#else -static void adc_dma_intr_handler(void *arg); -#endif +static IRAM_ATTR bool adc_dma_intr(adc_continuous_ctx_t *adc_digi_ctx) +{ + BaseType_t taskAwoken = 0; + bool need_yield = false; + BaseType_t ret; + adc_hal_dma_desc_status_t status = false; + uint8_t *finished_buffer = NULL; + uint32_t finished_size = 0; + + while (1) { + status = adc_hal_get_reading_result(&adc_digi_ctx->hal, adc_digi_ctx->rx_eof_desc_addr, &finished_buffer, &finished_size); + if (status != ADC_HAL_DMA_DESC_VALID) { + break; + } + + ret = xRingbufferSendFromISR(adc_digi_ctx->ringbuf_hdl, finished_buffer, finished_size, &taskAwoken); + need_yield |= (taskAwoken == pdTRUE); + + if (adc_digi_ctx->cbs.on_conv_done) { + adc_continuous_evt_data_t edata = { + .conv_frame_buffer = finished_buffer, + .size = finished_size, + }; + if (adc_digi_ctx->cbs.on_conv_done(adc_digi_ctx, &edata, adc_digi_ctx->user_data)) { + need_yield |= true; + } + } + + if (ret == pdFALSE) { + if (adc_digi_ctx->flags.flush_pool) { + size_t actual_size = 0; + uint8_t *old_data = xRingbufferReceiveUpToFromISR(adc_digi_ctx->ringbuf_hdl, &actual_size, adc_digi_ctx->ringbuf_size); + /** + * Replace by ringbuffer reset API when this API is ready. + * Now we do mannual reset. + * For old_data == NULL condition (equals to the future ringbuffer reset fail condition), we don't care this time data, + * as this only happens when the ringbuffer size is small, new data will be filled in soon. + */ + if (old_data) { + vRingbufferReturnItemFromISR(adc_digi_ctx->ringbuf_hdl, old_data, &taskAwoken); + xRingbufferSendFromISR(adc_digi_ctx->ringbuf_hdl, finished_buffer, finished_size, &taskAwoken); + if (taskAwoken == pdTRUE) { + need_yield |= true; + } + } + } + + //ringbuffer overflow happens before + if (adc_digi_ctx->cbs.on_pool_ovf) { + adc_continuous_evt_data_t edata = {}; + if (adc_digi_ctx->cbs.on_pool_ovf(adc_digi_ctx, &edata, adc_digi_ctx->user_data)) { + need_yield |= true; + } + } + } + } + + return need_yield; +} static int8_t adc_digi_get_io_num(adc_unit_t adc_unit, uint8_t adc_channel) { @@ -165,80 +207,16 @@ esp_err_t adc_continuous_new_handle(const adc_continuous_handle_cfg_t *hdl_confi } #endif //CONFIG_PM_ENABLE -#if SOC_GDMA_SUPPORTED - //alloc rx gdma channel - gdma_channel_alloc_config_t rx_alloc_config = { - .direction = GDMA_CHANNEL_DIRECTION_RX, - }; - ret = gdma_new_channel(&rx_alloc_config, &adc_ctx->rx_dma_channel); + ret = adc_dma_init(&adc_ctx->adc_dma); + adc_ctx->adc_intr_func = adc_dma_intr; if (ret != ESP_OK) { goto cleanup; } - gdma_connect(adc_ctx->rx_dma_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_ADC, 0)); - - gdma_strategy_config_t strategy_config = { - .auto_update_desc = true, - .owner_check = true - }; - gdma_apply_strategy(adc_ctx->rx_dma_channel, &strategy_config); - - gdma_rx_event_callbacks_t cbs = { - .on_recv_eof = adc_dma_in_suc_eof_callback - }; - gdma_register_rx_event_callbacks(adc_ctx->rx_dma_channel, &cbs, adc_ctx); - - int dma_chan; - gdma_get_channel_id(adc_ctx->rx_dma_channel, &dma_chan); - -#elif CONFIG_IDF_TARGET_ESP32S2 - //ADC utilises SPI3 DMA on ESP32S2 - bool spi_success = false; - uint32_t dma_chan = 0; - - spi_success = spicommon_periph_claim(SPI3_HOST, "adc"); - ret = spicommon_dma_chan_alloc(SPI3_HOST, SPI_DMA_CH_AUTO, &adc_ctx->spi_dma_ctx); - if (ret == ESP_OK) { - adc_ctx->spi_host = SPI3_HOST; - } - if (!spi_success || (adc_ctx->spi_host != SPI3_HOST)) { - goto cleanup; - } - dma_chan = adc_ctx->spi_dma_ctx->rx_dma_chan.chan_id; - - ret = esp_intr_alloc(spicommon_irqdma_source_for_host(adc_ctx->spi_host), ESP_INTR_FLAG_IRAM, adc_dma_intr_handler, - (void *)adc_ctx, &adc_ctx->dma_intr_hdl); - if (ret != ESP_OK) { - goto cleanup; - } - -#elif CONFIG_IDF_TARGET_ESP32 - //ADC utilises I2S0 DMA on ESP32 - uint32_t dma_chan = 0; - ret = i2s_platform_acquire_occupation(I2S_NUM_0, "adc"); - if (ret != ESP_OK) { - ret = ESP_ERR_NOT_FOUND; - goto cleanup; - } - - adc_ctx->i2s_host = I2S_NUM_0; - ret = esp_intr_alloc(i2s_periph_signal[adc_ctx->i2s_host].irq, ESP_INTR_FLAG_IRAM, adc_dma_intr_handler, - (void *)adc_ctx, &adc_ctx->dma_intr_hdl); - if (ret != ESP_OK) { - goto cleanup; - } -#endif + ret = adc_dma_intr_event_init(adc_ctx); adc_hal_dma_config_t config = { -#if SOC_GDMA_SUPPORTED - .dev = (void *)GDMA_LL_GET_HW(0), -#elif CONFIG_IDF_TARGET_ESP32S2 - .dev = (void *)SPI_LL_GET_HW(adc_ctx->spi_host), -#elif CONFIG_IDF_TARGET_ESP32 - .dev = (void *)I2S_LL_GET_HW(adc_ctx->i2s_host), -#endif .eof_desc_num = INTERNAL_BUF_NUM, .eof_step = dma_desc_num_per_frame, - .dma_chan = dma_chan, .eof_num = hdl_config->conv_frame_size / SOC_ADC_DIGI_DATA_BYTES_PER_CONV }; adc_hal_dma_ctx_config(&adc_ctx->hal, &config); @@ -261,97 +239,6 @@ cleanup: return ret; } -#if SOC_GDMA_SUPPORTED -static IRAM_ATTR bool adc_dma_in_suc_eof_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data) -{ - assert(event_data); - adc_continuous_ctx_t *ctx = (adc_continuous_ctx_t *)user_data; - ctx->rx_eof_desc_addr = event_data->rx_eof_desc_addr; - return s_adc_dma_intr(user_data); -} - -#else -static IRAM_ATTR void adc_dma_intr_handler(void *arg) -{ - adc_continuous_ctx_t *ctx = (adc_continuous_ctx_t *)arg; - bool need_yield = false; - - bool conversion_finish = adc_hal_check_event(&ctx->hal, ADC_HAL_DMA_INTR_MASK); - if (conversion_finish) { - adc_hal_digi_clr_intr(&ctx->hal, ADC_HAL_DMA_INTR_MASK); - - intptr_t desc_addr = adc_hal_get_desc_addr(&ctx->hal); - - ctx->rx_eof_desc_addr = desc_addr; - need_yield = s_adc_dma_intr(ctx); - } - - if (need_yield) { - portYIELD_FROM_ISR(); - } -} -#endif - -static IRAM_ATTR bool s_adc_dma_intr(adc_continuous_ctx_t *adc_digi_ctx) -{ - BaseType_t taskAwoken = 0; - bool need_yield = false; - BaseType_t ret; - adc_hal_dma_desc_status_t status = false; - uint8_t *finished_buffer = NULL; - uint32_t finished_size = 0; - - while (1) { - status = adc_hal_get_reading_result(&adc_digi_ctx->hal, adc_digi_ctx->rx_eof_desc_addr, &finished_buffer, &finished_size); - if (status != ADC_HAL_DMA_DESC_VALID) { - break; - } - - ret = xRingbufferSendFromISR(adc_digi_ctx->ringbuf_hdl, finished_buffer, finished_size, &taskAwoken); - need_yield |= (taskAwoken == pdTRUE); - - if (adc_digi_ctx->cbs.on_conv_done) { - adc_continuous_evt_data_t edata = { - .conv_frame_buffer = finished_buffer, - .size = finished_size, - }; - if (adc_digi_ctx->cbs.on_conv_done(adc_digi_ctx, &edata, adc_digi_ctx->user_data)) { - need_yield |= true; - } - } - - if (ret == pdFALSE) { - if (adc_digi_ctx->flags.flush_pool) { - size_t actual_size = 0; - uint8_t *old_data = xRingbufferReceiveUpToFromISR(adc_digi_ctx->ringbuf_hdl, &actual_size, adc_digi_ctx->ringbuf_size); - /** - * Replace by ringbuffer reset API when this API is ready. - * Now we do mannual reset. - * For old_data == NULL condition (equals to the future ringbuffer reset fail condition), we don't care this time data, - * as this only happens when the ringbuffer size is small, new data will be filled in soon. - */ - if (old_data) { - vRingbufferReturnItemFromISR(adc_digi_ctx->ringbuf_hdl, old_data, &taskAwoken); - xRingbufferSendFromISR(adc_digi_ctx->ringbuf_hdl, finished_buffer, finished_size, &taskAwoken); - if (taskAwoken == pdTRUE) { - need_yield |= true; - } - } - } - - //ringbuffer overflow happens before - if (adc_digi_ctx->cbs.on_pool_ovf) { - adc_continuous_evt_data_t edata = {}; - if (adc_digi_ctx->cbs.on_pool_ovf(adc_digi_ctx, &edata, adc_digi_ctx->user_data)) { - need_yield |= true; - } - } - } - } - - return need_yield; -} - esp_err_t adc_continuous_start(adc_continuous_handle_t handle) { ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_STATE, ADC_TAG, "The driver isn't initialised"); @@ -398,10 +285,20 @@ esp_err_t adc_continuous_start(adc_continuous_handle_t handle) } adc_hal_digi_init(&handle->hal); - adc_hal_digi_controller_config(&handle->hal, &handle->hal_digi_ctrlr_cfg); - //start conversion - adc_hal_digi_start(&handle->hal, handle->rx_dma_buf); + adc_hal_digi_controller_config(&handle->hal, &handle->hal_digi_ctrlr_cfg); + adc_hal_digi_enable(false); + + adc_dma_stop(handle->adc_dma); + adc_hal_digi_connect(false); + + adc_dma_reset(handle->adc_dma); + adc_hal_digi_reset(); + adc_hal_digi_dma_link(&handle->hal, handle->rx_dma_buf); + + adc_dma_start(handle->adc_dma, handle->hal.rx_desc); + adc_hal_digi_connect(true); + adc_hal_digi_enable(true); return ESP_OK; } @@ -412,19 +309,16 @@ esp_err_t adc_continuous_stop(adc_continuous_handle_t handle) ESP_RETURN_ON_FALSE(handle->fsm == ADC_FSM_STARTED, ESP_ERR_INVALID_STATE, ADC_TAG, "The driver is already stopped"); handle->fsm = ADC_FSM_INIT; - //disable the in suc eof intrrupt - adc_hal_digi_dis_intr(&handle->hal, ADC_HAL_DMA_INTR_MASK); - //clear the in suc eof interrupt - adc_hal_digi_clr_intr(&handle->hal, ADC_HAL_DMA_INTR_MASK); - //stop ADC - adc_hal_digi_stop(&handle->hal); + adc_dma_stop(handle->adc_dma); + adc_hal_digi_enable(false); + adc_hal_digi_connect(false); #if ADC_LL_WORKAROUND_CLEAR_EOF_COUNTER periph_module_reset(PERIPH_SARADC_MODULE); adc_hal_digi_clr_eof(); #endif - adc_hal_digi_deinit(&handle->hal); + adc_hal_digi_deinit(); if (handle->use_adc2) { adc_lock_release(ADC_UNIT_2); @@ -492,17 +386,7 @@ esp_err_t adc_continuous_deinit(adc_continuous_handle_t handle) free(handle->rx_dma_buf); free(handle->hal.rx_desc); free(handle->hal_digi_ctrlr_cfg.adc_pattern); -#if SOC_GDMA_SUPPORTED - gdma_disconnect(handle->rx_dma_channel); - gdma_del_channel(handle->rx_dma_channel); -#elif CONFIG_IDF_TARGET_ESP32S2 - esp_intr_free(handle->dma_intr_hdl); - spicommon_dma_chan_free(handle->spi_dma_ctx); - spicommon_periph_free(handle->spi_host); -#elif CONFIG_IDF_TARGET_ESP32 - esp_intr_free(handle->dma_intr_hdl); - i2s_platform_release_occupation(handle->i2s_host); -#endif + adc_dma_deinit(handle->adc_dma); free(handle); handle = NULL; diff --git a/components/esp_adc/adc_continuous_internal.h b/components/esp_adc/adc_continuous_internal.h index 64d6ad2a5f..03ae5d970a 100644 --- a/components/esp_adc/adc_continuous_internal.h +++ b/components/esp_adc/adc_continuous_internal.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -26,6 +26,7 @@ #include "esp_adc/adc_filter.h" #include "esp_adc/adc_monitor.h" +#include "adc_dma_internal.h" #ifdef __cplusplus extern "C" { @@ -47,6 +48,7 @@ typedef enum { typedef struct adc_iir_filter_t adc_iir_filter_t; typedef struct adc_monitor_t adc_monitor_t; typedef struct adc_continuous_ctx_t adc_continuous_ctx_t; +typedef bool (*adc_dma_intr_func_t)(adc_continuous_ctx_t *adc_digi_ctx); /** * @brief ADC iir filter context @@ -74,15 +76,6 @@ struct adc_monitor_t { struct adc_continuous_ctx_t { uint8_t *rx_dma_buf; //dma buffer adc_hal_dma_ctx_t hal; //hal context -#if SOC_GDMA_SUPPORTED - gdma_channel_handle_t rx_dma_channel; //dma rx channel handle -#elif CONFIG_IDF_TARGET_ESP32S2 - spi_host_device_t spi_host; //ADC uses this SPI DMA - spi_dma_ctx_t *spi_dma_ctx; //spi_dma context -#elif CONFIG_IDF_TARGET_ESP32 - i2s_port_t i2s_host; //ADC uses this I2S DMA -#endif - intr_handle_t dma_intr_hdl; //DMA Interrupt handler RingbufHandle_t ringbuf_hdl; //RX ringbuffer handler void* ringbuf_storage; //Ringbuffer storage buffer void* ringbuf_struct; //Ringbuffer structure buffer @@ -106,6 +99,8 @@ struct adc_continuous_ctx_t { #if SOC_ADC_MONITOR_SUPPORTED adc_monitor_t *adc_monitor[SOC_ADC_DIGI_MONITOR_NUM]; // adc monitor context #endif + adc_dma_t adc_dma; + adc_dma_intr_func_t adc_intr_func; }; #ifdef __cplusplus diff --git a/components/esp_adc/adc_dma_internal.h b/components/esp_adc/adc_dma_internal.h new file mode 100644 index 0000000000..5cdc73e2ba --- /dev/null +++ b/components/esp_adc/adc_dma_internal.h @@ -0,0 +1,37 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "esp_intr_alloc.h" +#include "hal/dma_types.h" +#include "hal/adc_hal.h" +#include "adc_continuous_internal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief ADC DMA context + */ +typedef struct { +#if SOC_GDMA_SUPPORTED + gdma_channel_handle_t gdma_chan; +#elif CONFIG_IDF_TARGET_ESP32S2 +//On ESP32S2, there is no gdma, so use SPI DMA to transmit data + spi_dma_ctx_t *spi_dma_ctx; + spi_dev_t *adc_spi_dev; +#elif CONFIG_IDF_TARGET_ESP32 +//On ESP32, there is no gdma, so use I2S DMA to transmit data + i2s_dev_t *adc_i2s_dev; +#endif + intr_handle_t dma_intr_hdl; +} adc_dma_t; + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_adc/esp32/adc_dma.c b/components/esp_adc/esp32/adc_dma.c new file mode 100644 index 0000000000..4ba169883a --- /dev/null +++ b/components/esp_adc/esp32/adc_dma.c @@ -0,0 +1,91 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * This file is a target specific for DAC DMA peripheral + * Target: ESP32 + * DAC DMA peripheral (data source): I2S0 (i.e. use I2S DMA to transmit data) + * DAC DMA interrupt source: I2S0 + * DAC digital controller clock source: I2S ws signal (root clock: D2PLL or APLL) + */ + +#include "hal/i2s_types.h" +#include "driver/i2s_types.h" +#include "soc/i2s_periph.h" +#include "esp_private/i2s_platform.h" +#include "esp_private/adc_dma.h" +#include "hal/i2s_ll.h" + +#define ADC_DMA_I2S_HOST ADC_HAL_DMA_I2S_HOST +#define ADC_DMA_INTR_MASK BIT(9) + +static IRAM_ATTR void adc_dma_intr_handler(void *arg) +{ + adc_continuous_ctx_t *ctx = (adc_continuous_ctx_t *)arg; + bool need_yield = false; + + bool conversion_finish = i2s_ll_get_intr_status(ctx->adc_dma.adc_i2s_dev) & ADC_DMA_INTR_MASK; + if (conversion_finish) { + i2s_ll_clear_intr_status(ctx->adc_dma.adc_i2s_dev, ADC_DMA_INTR_MASK); + uint32_t desc_addr; + i2s_ll_rx_get_eof_des_addr(ctx->adc_dma.adc_i2s_dev, &desc_addr); + ctx->rx_eof_desc_addr = (intptr_t)desc_addr; + need_yield = ctx->adc_intr_func(ctx); + } + + if (need_yield) { + portYIELD_FROM_ISR(); + } +} + +esp_err_t adc_dma_intr_event_init(adc_continuous_ctx_t *adc_ctx) +{ + return (esp_intr_alloc(i2s_periph_signal[ADC_DMA_I2S_HOST].irq, ESP_INTR_FLAG_IRAM, adc_dma_intr_handler, + (void *)adc_ctx, &adc_ctx->adc_dma.dma_intr_hdl)); +} + +esp_err_t adc_dma_init(adc_dma_t *adc_dma) +{ + esp_err_t ret = ESP_OK; + //ADC utilises I2S0 DMA on ESP32 + ret = i2s_platform_acquire_occupation(ADC_DMA_I2S_HOST, "adc"); + if (ret != ESP_OK) { + return ESP_ERR_NOT_FOUND; + } + adc_dma->adc_i2s_dev = I2S_LL_GET_HW(ADC_DMA_I2S_HOST); + return ESP_OK; +} + +esp_err_t adc_dma_deinit(adc_dma_t adc_dma) +{ + esp_intr_free(adc_dma.dma_intr_hdl); + i2s_platform_release_occupation(ADC_DMA_I2S_HOST); + return ESP_OK; +} + +esp_err_t adc_dma_start(adc_dma_t adc_dma, dma_descriptor_t *addr) +{ + i2s_ll_clear_intr_status(adc_dma.adc_i2s_dev, ADC_DMA_INTR_MASK); + i2s_ll_enable_intr(adc_dma.adc_i2s_dev, ADC_DMA_INTR_MASK, true); + + i2s_ll_enable_dma(adc_dma.adc_i2s_dev, true); + i2s_ll_rx_start_link(adc_dma.adc_i2s_dev, (uint32_t)addr); + return ESP_OK; +} + +esp_err_t adc_dma_stop(adc_dma_t adc_dma) +{ + i2s_ll_enable_intr(adc_dma.adc_i2s_dev, ADC_DMA_INTR_MASK, false); + i2s_ll_clear_intr_status(adc_dma.adc_i2s_dev, ADC_DMA_INTR_MASK); + i2s_ll_rx_stop_link(adc_dma.adc_i2s_dev); + return ESP_OK; +} + +esp_err_t adc_dma_reset(adc_dma_t adc_dma) +{ + i2s_ll_rx_reset_dma(adc_dma.adc_i2s_dev); + return ESP_OK; +} diff --git a/components/esp_adc/esp32s2/adc_dma.c b/components/esp_adc/esp32s2/adc_dma.c new file mode 100644 index 0000000000..1b6be919f5 --- /dev/null +++ b/components/esp_adc/esp32s2/adc_dma.c @@ -0,0 +1,93 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * This file is a target specific for DAC DMA peripheral + * Target: ESP32-S2 + * DAC DMA peripheral (data source): SPI3 (i.e. use SPI DMA to transmit data) + * DAC DMA interrupt source: SPI3 + * DAC digital controller clock source: DIG_SARADC_CLK (root clock: APB or APLL) + */ + +#include "hal/spi_types.h" +#include "hal/spi_ll.h" +#include "esp_private/spi_common_internal.h" +#include "esp_private/adc_dma.h" + +#define ADC_DMA_SPI_HOST SPI3_HOST +#define ADC_DMA_INTR_MASK SPI_LL_INTR_IN_SUC_EOF + +static IRAM_ATTR void adc_dma_intr_handler(void *arg) +{ + adc_continuous_ctx_t *ctx = (adc_continuous_ctx_t *)arg; + bool need_yield = false; + + bool conversion_finish = spi_ll_get_intr(ctx->adc_dma.adc_spi_dev, ADC_DMA_INTR_MASK); + if (conversion_finish) { + spi_ll_clear_intr(ctx->adc_dma.adc_spi_dev, ADC_DMA_INTR_MASK); + intptr_t desc_addr = spi_dma_ll_get_in_suc_eof_desc_addr(ctx->adc_dma.adc_spi_dev, ctx->adc_dma.spi_dma_ctx->rx_dma_chan.chan_id); + ctx->rx_eof_desc_addr = desc_addr; + need_yield = ctx->adc_intr_func(ctx); + } + + if (need_yield) { + portYIELD_FROM_ISR(); + } +} + +esp_err_t adc_dma_intr_event_init(adc_continuous_ctx_t *adc_ctx) +{ + return (esp_intr_alloc(spicommon_irqdma_source_for_host(ADC_DMA_SPI_HOST), ESP_INTR_FLAG_IRAM, adc_dma_intr_handler, + (void *)adc_ctx, &adc_ctx->adc_dma.dma_intr_hdl)); +} + +esp_err_t adc_dma_init(adc_dma_t *adc_dma) +{ + esp_err_t ret = ESP_OK; + //ADC utilises SPI3 DMA on ESP32S2 + bool spi_success = false; + spi_success = spicommon_periph_claim(ADC_DMA_SPI_HOST, "adc"); + if (spi_success != true) { + return ESP_FAIL; + } + ret = spicommon_dma_chan_alloc(SPI3_HOST, SPI_DMA_CH_AUTO, &(adc_dma->spi_dma_ctx)); + if (ret != ESP_OK) { + return ret; + } + adc_dma->adc_spi_dev = SPI_LL_GET_HW(ADC_DMA_SPI_HOST); + + return ESP_OK; +} + +esp_err_t adc_dma_deinit(adc_dma_t adc_dma) +{ + esp_intr_free(adc_dma.dma_intr_hdl); + spicommon_dma_chan_free(adc_dma.spi_dma_ctx); + spicommon_periph_free(ADC_DMA_SPI_HOST); + return ESP_OK; +} + +esp_err_t adc_dma_start(adc_dma_t adc_dma, dma_descriptor_t *addr) +{ + spi_ll_clear_intr(adc_dma.adc_spi_dev, ADC_DMA_INTR_MASK); + spi_ll_enable_intr(adc_dma.adc_spi_dev, ADC_DMA_INTR_MASK); + spi_dma_ll_rx_start(adc_dma.adc_spi_dev, adc_dma.spi_dma_ctx->rx_dma_chan.chan_id, (lldesc_t *)addr); + return ESP_OK; +} + +esp_err_t adc_dma_stop(adc_dma_t adc_dma) +{ + spi_ll_disable_intr(adc_dma.adc_spi_dev, ADC_DMA_INTR_MASK); + spi_ll_clear_intr(adc_dma.adc_spi_dev, ADC_DMA_INTR_MASK); + spi_dma_ll_rx_stop(adc_dma.adc_spi_dev, adc_dma.spi_dma_ctx->rx_dma_chan.chan_id); + return ESP_OK; +} + +esp_err_t adc_dma_reset(adc_dma_t adc_dma) +{ + spi_dma_ll_rx_reset(adc_dma.adc_spi_dev, adc_dma.spi_dma_ctx->rx_dma_chan.chan_id); + return ESP_OK; +} diff --git a/components/esp_adc/gdma/adc_dma.c b/components/esp_adc/gdma/adc_dma.c new file mode 100644 index 0000000000..7e5e33343d --- /dev/null +++ b/components/esp_adc/gdma/adc_dma.c @@ -0,0 +1,69 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_private/gdma.h" +#include "esp_private/adc_dma.h" + +static IRAM_ATTR bool adc_dma_in_suc_eof_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data) +{ + assert(event_data); + adc_continuous_ctx_t *ctx = (adc_continuous_ctx_t *)user_data; + ctx->rx_eof_desc_addr = event_data->rx_eof_desc_addr; + return ctx->adc_intr_func(user_data); +} + +esp_err_t adc_dma_intr_event_init(adc_continuous_ctx_t *adc_ctx) +{ + gdma_rx_event_callbacks_t cbs = { + .on_recv_eof = adc_dma_in_suc_eof_callback + }; + gdma_register_rx_event_callbacks(adc_ctx->adc_dma.gdma_chan, &cbs, adc_ctx); + return ESP_OK; +} + +esp_err_t adc_dma_init(adc_dma_t *adc_dma) +{ + esp_err_t ret = ESP_OK; + //alloc rx gdma channel + gdma_channel_alloc_config_t rx_alloc_config = { + .direction = GDMA_CHANNEL_DIRECTION_RX, + }; + ret = gdma_new_channel(&rx_alloc_config, &(adc_dma->gdma_chan)); + if (ret != ESP_OK) { + return ret; + } + gdma_connect(adc_dma->gdma_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_ADC, 0)); + + gdma_strategy_config_t strategy_config = { + .auto_update_desc = true, + .owner_check = true + }; + gdma_apply_strategy(adc_dma->gdma_chan, &strategy_config); + + return ESP_OK; +} + +esp_err_t adc_dma_deinit(adc_dma_t adc_dma) +{ + gdma_disconnect(adc_dma.gdma_chan); + gdma_del_channel(adc_dma.gdma_chan); + return ESP_OK; +} + +esp_err_t adc_dma_start(adc_dma_t adc_dma, dma_descriptor_t *addr) +{ + return gdma_start(adc_dma.gdma_chan, (intptr_t)addr); +} + +esp_err_t adc_dma_stop(adc_dma_t adc_dma) +{ + return gdma_stop(adc_dma.gdma_chan); +} + +esp_err_t adc_dma_reset(adc_dma_t adc_dma) +{ + return gdma_reset(adc_dma.gdma_chan); +} diff --git a/components/esp_adc/include/esp_private/adc_dma.h b/components/esp_adc/include/esp_private/adc_dma.h new file mode 100644 index 0000000000..b8d81a7924 --- /dev/null +++ b/components/esp_adc/include/esp_private/adc_dma.h @@ -0,0 +1,81 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "esp_intr_alloc.h" +#include "hal/dma_types.h" +#include "hal/adc_hal.h" +#include "../adc_continuous_internal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Initialize DMA interrupt event + * + * @param[in] adc_ctx ADC continuous mode driver handle + * + * @return + * - ESP_OK: On success + */ +esp_err_t adc_dma_intr_event_init(adc_continuous_ctx_t *adc_ctx); + +/** + * @brief Initialize DMA on ADC continuous mode + * + * @param[in] adc_dma ADC DMA context + * + * @return + * - ESP_OK: On success + */ +esp_err_t adc_dma_init(adc_dma_t *adc_dma); + +/** + * @brief Deinitialize DMA on ADC continuous mode + * + * @param[in] adc_dma ADC DMA context + * + * @return + * - ESP_OK: On success + */ +esp_err_t adc_dma_deinit(adc_dma_t adc_dma); + +/** + * @brief Start DMA on ADC continuous mode + * + * @param[in] adc_dma ADC DMA context + * @param[in] addr ADC DMA descriptor + * + * @return + * - ESP_OK: On success + */ +esp_err_t adc_dma_start(adc_dma_t adc_dma, dma_descriptor_t *addr); + +/** + * @brief Stop DMA on ADC continuous mode + * + * @param[in] adc_dma ADC DMA context + * + * @return + * - ESP_OK: On success + */ +esp_err_t adc_dma_stop(adc_dma_t adc_dma); + +/** + * @brief Reset DMA on ADC continuous mode + * + * @param[in] adc_dma ADC DMA context + * + * @return + * - ESP_OK: On success + */ +esp_err_t adc_dma_reset(adc_dma_t adc_dma); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_adc/linker.lf b/components/esp_adc/linker.lf index 755c83f1d6..855ebe7cbd 100644 --- a/components/esp_adc/linker.lf +++ b/components/esp_adc/linker.lf @@ -19,7 +19,3 @@ entries: adc_hal_common: adc_hal_calibration_init (noflash) if ADC_CONTINUOUS_ISR_IRAM_SAFE = y || GDMA_ISR_IRAM_SAFE = y: adc_hal: adc_hal_get_reading_result (noflash) - if IDF_TARGET_ESP32 = y || IDF_TARGET_ESP32S2 = y: - adc_hal: adc_hal_check_event (noflash) - adc_hal: adc_hal_digi_clr_intr (noflash) - adc_hal: adc_hal_get_desc_addr (noflash) diff --git a/components/hal/adc_hal.c b/components/hal/adc_hal.c index 12c203212a..bb62c05de9 100644 --- a/components/hal/adc_hal.c +++ b/components/hal/adc_hal.c @@ -16,70 +16,6 @@ #include "hal/i2s_hal.h" #include "hal/i2s_types.h" #include "soc/i2s_struct.h" -#endif - -#if CONFIG_IDF_TARGET_ESP32S2 -//ADC utilises SPI3 DMA on ESP32S2 -#include "hal/spi_ll.h" -#include "soc/spi_struct.h" -#endif - -/*--------------------------------------------------------------- - Define all ADC DMA required operations here ----------------------------------------------------------------*/ -#if SOC_AHB_GDMA_VERSION == 1 -#define adc_dma_ll_rx_clear_intr(dev, chan, mask) gdma_ll_rx_clear_interrupt_status(dev, chan, mask) -#define adc_dma_ll_rx_enable_intr(dev, chan, mask) gdma_ll_rx_enable_interrupt(dev, chan, mask, true) -#define adc_dma_ll_rx_disable_intr(dev, chan, mask) gdma_ll_rx_enable_interrupt(dev, chan, mask, false) -#define adc_dma_ll_rx_reset_channel(dev, chan) gdma_ll_rx_reset_channel(dev, chan) -#define adc_dma_ll_rx_stop(dev, chan) gdma_ll_rx_stop(dev, chan) -#define adc_dma_ll_rx_start(dev, chan, addr) do { \ - gdma_ll_rx_set_desc_addr(dev, chan, (uint32_t)addr); \ - gdma_ll_rx_start(dev, chan); \ - } while (0) -#define adc_ll_digi_dma_set_eof_num(dev, num) adc_ll_digi_dma_set_eof_num(num) -#define adc_ll_digi_reset(dev) adc_ll_digi_reset() -#define adc_ll_digi_trigger_enable(dev) adc_ll_digi_trigger_enable() -#define adc_ll_digi_trigger_disable(dev) adc_ll_digi_trigger_disable() - -//ADC utilises SPI3 DMA on ESP32S2 -#elif CONFIG_IDF_TARGET_ESP32S2 -#define adc_dma_ll_rx_get_intr(dev, mask) spi_ll_get_intr(dev, mask) -#define adc_dma_ll_rx_clear_intr(dev, chan, mask) spi_ll_clear_intr(dev, mask) -#define adc_dma_ll_rx_enable_intr(dev, chan, mask) spi_ll_enable_intr(dev, mask) -#define adc_dma_ll_rx_disable_intr(dev, chan, mask) spi_ll_disable_intr(dev, mask) -#define adc_dma_ll_rx_reset_channel(dev, chan) spi_dma_ll_rx_reset(dev, chan) -#define adc_dma_ll_rx_stop(dev, chan) spi_dma_ll_rx_stop(dev, chan) -#define adc_dma_ll_rx_start(dev, chan, addr) spi_dma_ll_rx_start(dev, chan, addr) -#define adc_dma_ll_get_in_suc_eof_desc_addr(dev, chan) spi_dma_ll_get_in_suc_eof_desc_addr(dev, chan) -#define adc_ll_digi_dma_set_eof_num(dev, num) adc_ll_digi_dma_set_eof_num(num) -#define adc_ll_digi_reset(dev) adc_ll_digi_reset() -#define adc_ll_digi_trigger_enable(dev) adc_ll_digi_trigger_enable() -#define adc_ll_digi_trigger_disable(dev) adc_ll_digi_trigger_disable() - -//ADC utilises I2S0 DMA on ESP32 -#else //CONFIG_IDF_TARGET_ESP32 -#define adc_dma_ll_rx_get_intr(dev, mask) ({i2s_ll_get_intr_status(dev) & mask;}) -#define adc_dma_ll_rx_clear_intr(dev, chan, mask) i2s_ll_clear_intr_status(dev, mask) -#define adc_dma_ll_rx_enable_intr(dev, chan, mask) do {((i2s_dev_t *)(dev))->int_ena.val |= mask;} while (0) -#define adc_dma_ll_rx_disable_intr(dev, chan, mask) do {((i2s_dev_t *)(dev))->int_ena.val &= ~mask;} while (0) -#define adc_dma_ll_rx_reset_channel(dev, chan) i2s_ll_rx_reset_dma(dev) -#define adc_dma_ll_rx_stop(dev, chan) i2s_ll_rx_stop_link(dev) -#define adc_dma_ll_rx_start(dev, chan, address) do { \ - ((i2s_dev_t *)(dev))->in_link.addr = (uint32_t)(address); \ - i2s_ll_enable_dma(dev, 1); \ - ((i2s_dev_t *)(dev))->in_link.start = 1; \ - } while (0) -#define adc_dma_ll_get_in_suc_eof_desc_addr(dev, chan) ({uint32_t addr; i2s_ll_rx_get_eof_des_addr(dev, &addr); addr;}) -#define adc_ll_digi_dma_set_eof_num(dev, num) do {((i2s_dev_t *)(dev))->rx_eof_num = num;} while (0) -#define adc_ll_digi_reset(dev) do { \ - i2s_ll_rx_reset(dev); \ - i2s_ll_rx_reset_fifo(dev); \ - } while (0) -#define adc_ll_digi_trigger_enable(dev) i2s_ll_rx_start(dev) -#define adc_ll_digi_trigger_disable(dev) i2s_ll_rx_stop(dev) -#define adc_ll_digi_dma_enable() adc_ll_digi_set_data_source(1) //Will this influence I2S0 -#define adc_ll_digi_dma_disable() adc_ll_digi_set_data_source(0) //ESP32 ADC uses the DMA through I2S. The I2S needs to be configured. #define I2S_BASE_CLK (160 * 1000 * 1000) @@ -88,17 +24,25 @@ #define ADC_LL_CLKM_DIV_B_DEFAULT 0 #define ADC_LL_CLKM_DIV_A_DEFAULT 1 +i2s_dev_t *adc_hal_i2s_dev = I2S_LL_GET_HW(ADC_HAL_DMA_I2S_HOST); + +#define adc_ll_digi_dma_set_eof_num(num) i2s_ll_rx_set_eof_num(adc_hal_i2s_dev, (num) * 4) +#define adc_ll_digi_reset() do { \ + i2s_ll_rx_reset(adc_hal_i2s_dev); \ + i2s_ll_rx_reset_fifo(adc_hal_i2s_dev); \ + } while (0) +#define adc_ll_digi_trigger_enable() i2s_ll_rx_start(adc_hal_i2s_dev) +#define adc_ll_digi_trigger_disable() i2s_ll_rx_stop(adc_hal_i2s_dev) +#define adc_ll_digi_dma_enable() adc_ll_digi_set_data_source(1) //Will this influence I2S0 +#define adc_ll_digi_dma_disable() adc_ll_digi_set_data_source(0) + #endif - - void adc_hal_dma_ctx_config(adc_hal_dma_ctx_t *hal, const adc_hal_dma_config_t *config) { hal->desc_dummy_head.next = hal->rx_desc; - hal->dev = config->dev; hal->eof_desc_num = config->eof_desc_num; hal->eof_step = config->eof_step; - hal->dma_chan = config->dma_chan; hal->eof_num = config->eof_num; } @@ -113,30 +57,28 @@ void adc_hal_digi_init(adc_hal_dma_ctx_t *hal) adc_ll_digi_output_invert(ADC_UNIT_2, ADC_LL_DIGI_DATA_INVERT_DEFAULT(ADC_UNIT_2)); adc_ll_digi_set_clk_div(ADC_LL_DIGI_SAR_CLK_DIV_DEFAULT); - adc_dma_ll_rx_clear_intr(hal->dev, hal->dma_chan, ADC_HAL_DMA_INTR_MASK); - adc_dma_ll_rx_enable_intr(hal->dev, hal->dma_chan, ADC_HAL_DMA_INTR_MASK); - adc_ll_digi_dma_set_eof_num(hal->dev, hal->eof_num); + adc_ll_digi_dma_set_eof_num(hal->eof_num); #if CONFIG_IDF_TARGET_ESP32 - i2s_ll_rx_set_sample_bit(hal->dev, SAMPLE_BITS, SAMPLE_BITS); - i2s_ll_rx_enable_mono_mode(hal->dev, 1); - i2s_ll_rx_force_enable_fifo_mod(hal->dev, 1); - i2s_ll_rx_enable_right_first(hal->dev, false); - i2s_ll_rx_enable_msb_shift(hal->dev, false); - i2s_ll_rx_set_ws_width(hal->dev, 16); - i2s_ll_rx_select_std_slot(hal->dev, I2S_STD_SLOT_LEFT, false); - i2s_ll_enable_builtin_adc_dac(hal->dev, 1); + i2s_ll_rx_set_sample_bit(adc_hal_i2s_dev, SAMPLE_BITS, SAMPLE_BITS); + i2s_ll_rx_enable_mono_mode(adc_hal_i2s_dev, 1); + i2s_ll_rx_force_enable_fifo_mod(adc_hal_i2s_dev, 1); + i2s_ll_rx_enable_right_first(adc_hal_i2s_dev, false); + i2s_ll_rx_enable_msb_shift(adc_hal_i2s_dev, false); + i2s_ll_rx_set_ws_width(adc_hal_i2s_dev, 16); + i2s_ll_rx_select_std_slot(adc_hal_i2s_dev, I2S_STD_SLOT_LEFT, false); + i2s_ll_enable_builtin_adc_dac(adc_hal_i2s_dev, 1); #endif adc_oneshot_ll_disable_all_unit(); } -void adc_hal_digi_deinit(adc_hal_dma_ctx_t *hal) +void adc_hal_digi_deinit() { - adc_ll_digi_trigger_disable(hal->dev); + adc_ll_digi_trigger_disable(); adc_ll_digi_dma_disable(); adc_ll_digi_clear_pattern_table(ADC_UNIT_1); adc_ll_digi_clear_pattern_table(ADC_UNIT_2); - adc_ll_digi_reset(hal->dev); + adc_ll_digi_reset(); adc_ll_digi_controller_clk_disable(); } @@ -180,14 +122,14 @@ static void adc_hal_digi_sample_freq_config(adc_hal_dma_ctx_t *hal, adc_continuo adc_ll_digi_controller_clk_div(ADC_LL_CLKM_DIV_NUM_DEFAULT, ADC_LL_CLKM_DIV_B_DEFAULT, ADC_LL_CLKM_DIV_A_DEFAULT); adc_ll_digi_clk_sel(clk_src); #else - i2s_ll_rx_clk_set_src(hal->dev, I2S_CLK_SRC_DEFAULT); /*!< Clock from PLL_D2_CLK(160M)*/ + i2s_ll_rx_clk_set_src(adc_hal_i2s_dev, I2S_CLK_SRC_DEFAULT); /*!< Clock from PLL_D2_CLK(160M)*/ uint32_t bclk_div = 16; uint32_t bclk = sample_freq_hz * 2; uint32_t mclk = bclk * bclk_div; hal_utils_clk_div_t mclk_div = {}; i2s_hal_calc_mclk_precise_division(I2S_BASE_CLK, mclk, &mclk_div); - i2s_ll_rx_set_mclk(hal->dev, &mclk_div); - i2s_ll_rx_set_bck_div_num(hal->dev, bclk_div); + i2s_ll_rx_set_mclk(adc_hal_i2s_dev, &mclk_div); + i2s_ll_rx_set_bck_div_num(adc_hal_i2s_dev, bclk_div); #endif } @@ -234,13 +176,20 @@ void adc_hal_digi_controller_config(adc_hal_dma_ctx_t *hal, const adc_hal_digi_c adc_hal_digi_sample_freq_config(hal, cfg->clk_src, cfg->clk_src_freq_hz, cfg->sample_freq_hz); } -static void adc_hal_digi_dma_link_descriptors(dma_descriptor_t *desc, uint8_t *data_buf, uint32_t per_eof_size, uint32_t eof_step, uint32_t eof_num) + +void adc_hal_digi_dma_link(adc_hal_dma_ctx_t *hal, uint8_t *data_buf) { + dma_descriptor_t *desc = hal->rx_desc; + uint32_t per_eof_size = hal->eof_num * SOC_ADC_DIGI_DATA_BYTES_PER_CONV; + uint32_t eof_step = hal->eof_step; + uint32_t eof_num = hal->eof_desc_num; + HAL_ASSERT(((uint32_t)data_buf % 4) == 0); HAL_ASSERT((per_eof_size % 4) == 0); uint32_t n = 0; dma_descriptor_t *desc_head = desc; + hal->cur_desc_ptr = &hal->desc_dummy_head; while (eof_num--) { uint32_t eof_size = per_eof_size; @@ -266,40 +215,6 @@ static void adc_hal_digi_dma_link_descriptors(dma_descriptor_t *desc, uint8_t *d desc[n-1].next = desc_head; } -void adc_hal_digi_start(adc_hal_dma_ctx_t *hal, uint8_t *data_buf) -{ - //stop peripheral and DMA - adc_hal_digi_stop(hal); - - //reset DMA - adc_dma_ll_rx_reset_channel(hal->dev, hal->dma_chan); - //reset peripheral - adc_ll_digi_reset(hal->dev); - - //reset the current descriptor address - hal->cur_desc_ptr = &hal->desc_dummy_head; - adc_hal_digi_dma_link_descriptors(hal->rx_desc, data_buf, hal->eof_num * SOC_ADC_DIGI_DATA_BYTES_PER_CONV, hal->eof_step, hal->eof_desc_num); - - //start DMA - adc_dma_ll_rx_start(hal->dev, hal->dma_chan, (lldesc_t *)hal->rx_desc); - //connect DMA and peripheral - adc_ll_digi_dma_enable(); - //start ADC - adc_ll_digi_trigger_enable(hal->dev); -} - -#if !SOC_GDMA_SUPPORTED -intptr_t adc_hal_get_desc_addr(adc_hal_dma_ctx_t *hal) -{ - return adc_dma_ll_get_in_suc_eof_desc_addr(hal->dev, hal->dma_chan); -} - -bool adc_hal_check_event(adc_hal_dma_ctx_t *hal, uint32_t mask) -{ - return adc_dma_ll_rx_get_intr(hal->dev, mask); -} -#endif //#if !SOC_GDMA_SUPPORTED - adc_hal_dma_desc_status_t adc_hal_get_reading_result(adc_hal_dma_ctx_t *hal, const intptr_t eof_desc_addr, uint8_t **buffer, uint32_t *len) { HAL_ASSERT(hal->cur_desc_ptr); @@ -343,24 +258,27 @@ valid: return ADC_HAL_DMA_DESC_VALID; } -void adc_hal_digi_clr_intr(adc_hal_dma_ctx_t *hal, uint32_t mask) +void adc_hal_digi_enable(bool enable) { - adc_dma_ll_rx_clear_intr(hal->dev, hal->dma_chan, mask); + if (enable) { + adc_ll_digi_trigger_enable(); + } else { + adc_ll_digi_trigger_disable(); + } } -void adc_hal_digi_dis_intr(adc_hal_dma_ctx_t *hal, uint32_t mask) +void adc_hal_digi_connect(bool enable) { - adc_dma_ll_rx_disable_intr(hal->dev, hal->dma_chan, mask); + if (enable) { + adc_ll_digi_dma_enable(); + } else { + adc_ll_digi_dma_disable(); + } } -void adc_hal_digi_stop(adc_hal_dma_ctx_t *hal) +void adc_hal_digi_reset(void) { - //stop ADC - adc_ll_digi_trigger_disable(hal->dev); - //stop DMA - adc_dma_ll_rx_stop(hal->dev, hal->dma_chan); - //disconnect DMA and peripheral - adc_ll_digi_dma_disable(); + adc_ll_digi_reset(); } #if ADC_LL_WORKAROUND_CLEAR_EOF_COUNTER diff --git a/components/hal/include/hal/adc_hal.h b/components/hal/include/hal/adc_hal.h index c085bb177e..f237613327 100644 --- a/components/hal/include/hal/adc_hal.h +++ b/components/hal/include/hal/adc_hal.h @@ -33,12 +33,8 @@ extern "C" { #endif -#if SOC_GDMA_SUPPORTED -#define ADC_HAL_DMA_INTR_MASK GDMA_LL_EVENT_RX_SUC_EOF -#elif CONFIG_IDF_TARGET_ESP32S2 -#define ADC_HAL_DMA_INTR_MASK SPI_LL_INTR_IN_SUC_EOF -#else //CONFIG_IDF_TARGET_ESP32 -#define ADC_HAL_DMA_INTR_MASK BIT(9) +#if CONFIG_IDF_TARGET_ESP32 +#define ADC_HAL_DMA_I2S_HOST 0 #endif /** @@ -54,10 +50,8 @@ typedef enum adc_hal_dma_desc_status_t { * @brief Configuration of the HAL */ typedef struct adc_hal_dma_config_t { - void *dev; ///< DMA peripheral address uint32_t eof_desc_num; ///< Number of dma descriptors that is eof uint32_t eof_step; ///< Number of linked descriptors that is one eof - uint32_t dma_chan; ///< DMA channel to be used uint32_t eof_num; ///< Bytes between 2 in_suc_eof interrupts } adc_hal_dma_config_t; @@ -73,10 +67,8 @@ typedef struct adc_hal_dma_ctx_t { dma_descriptor_t *cur_desc_ptr; ///< Pointer to the current descriptor /**< these need to be configured by `adc_hal_dma_config_t` via driver layer*/ - void *dev; ///< DMA address uint32_t eof_desc_num; ///< Number of dma descriptors that is eof uint32_t eof_step; ///< Number of linked descriptors that is one eof - uint32_t dma_chan; ///< DMA channel to be used uint32_t eof_num; ///< Words between 2 in_suc_eof interrupts } adc_hal_dma_ctx_t; @@ -123,9 +115,8 @@ void adc_hal_digi_init(adc_hal_dma_ctx_t *hal); /** * Digital controller deinitialization. * - * @param hal Context of the HAL */ -void adc_hal_digi_deinit(adc_hal_dma_ctx_t *hal); +void adc_hal_digi_deinit(void); /** * @brief Initialize the hal context @@ -144,33 +135,12 @@ void adc_hal_dma_ctx_config(adc_hal_dma_ctx_t *hal, const adc_hal_dma_config_t * void adc_hal_digi_controller_config(adc_hal_dma_ctx_t *hal, const adc_hal_digi_ctrlr_cfg_t *cfg); /** - * @brief Start Conversion + * @brief Link DMA descriptor * * @param hal Context of the HAL * @param data_buf Pointer to the data buffer, the length should be multiple of ``desc_max_num`` and ``eof_num`` in ``adc_hal_dma_ctx_t`` */ -void adc_hal_digi_start(adc_hal_dma_ctx_t *hal, uint8_t *data_buf); - -#if !SOC_GDMA_SUPPORTED -/** - * @brief Get the DMA descriptor that Hardware has finished processing. - * - * @param hal Context of the HAL - * - * @return DMA descriptor address - */ -intptr_t adc_hal_get_desc_addr(adc_hal_dma_ctx_t *hal); - -/** - * @brief Check the hardware interrupt event - * - * @param hal Context of the HAL - * @param mask Event mask - * - * @return True: the event is triggered. False: the event is not triggered yet. - */ -bool adc_hal_check_event(adc_hal_dma_ctx_t *hal, uint32_t mask); -#endif +void adc_hal_digi_dma_link(adc_hal_dma_ctx_t *hal, uint8_t *data_buf); /** * @brief Get the ADC reading result @@ -185,27 +155,23 @@ bool adc_hal_check_event(adc_hal_dma_ctx_t *hal, uint32_t mask); adc_hal_dma_desc_status_t adc_hal_get_reading_result(adc_hal_dma_ctx_t *hal, const intptr_t eof_desc_addr, uint8_t **buffer, uint32_t *len); /** - * @brief Clear interrupt + * @brief Enable or disable ADC digital controller * - * @param hal Context of the HAL - * @param mask mask of the interrupt + * @param enable true to enable, false to disable */ -void adc_hal_digi_clr_intr(adc_hal_dma_ctx_t *hal, uint32_t mask); +void adc_hal_digi_enable(bool enable); /** - * @brief Enable interrupt + * @brief Enable pr disable output data to DMA from adc digital controller. * - * @param hal Context of the HAL - * @param mask mask of the interrupt + * @param enable true to enable, false to disable */ -void adc_hal_digi_dis_intr(adc_hal_dma_ctx_t *hal, uint32_t mask); +void adc_hal_digi_connect(bool enable); /** - * @brief Stop conversion - * - * @param hal Context of the HAL + * @brief Reset adc digital controller. */ -void adc_hal_digi_stop(adc_hal_dma_ctx_t *hal); +void adc_hal_digi_reset(void); #if ADC_LL_WORKAROUND_CLEAR_EOF_COUNTER /**