refactor(adc): refactor dma ll functions on adc continuous mode

This commit is contained in:
gaoxu 2024-03-12 11:12:48 +08:00
parent 0bbee51829
commit bc98bdc087
12 changed files with 621 additions and 440 deletions

View File

@ -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);

View File

@ -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)

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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
/**