Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some improvement to adc_continuous and i2s_common (IDFGH-11855) #12944

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
21 changes: 21 additions & 0 deletions components/esp_adc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,27 @@ menu "ADC and ADC Calibration"
If you stick to this, you can enable this option to force use ADC2 under above conditions.
For more details, you can search for errata on espressif website.

config ADC_DIGI_CLK_DIV_DEFAULT
bool "Use default adc clk divisor"
depends on !IDF_TARGET_ESP32
default y
help
Force use of default digital controller clk divisors.

config ADC_SARADC_TARGET_CLK
int "Set SARADC target clock frequency"
depends on !ADC_DIGI_CLK_DIV_DEFAULT
default 5280000
help
The SARADC clock frequency will be set to the nearest integer multiple of sample freq.
The fractional divisor parameters will be calculated at runtime.

config ADC_CONTINUOUS_NUM_DMA
int "Set the number of DMA buffers"
default 5
help
Configure the number of DMA buffers used by adc

config ADC_ENABLE_DEBUG_LOG
bool "Enable ADC debug log"
default n
Expand Down
90 changes: 55 additions & 35 deletions components/esp_adc/adc_continuous.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,11 @@ extern portMUX_TYPE rtc_spinlock; //TODO: Will be placed in the appropriate posi
#define ADC_ENTER_CRITICAL() portENTER_CRITICAL(&rtc_spinlock)
#define ADC_EXIT_CRITICAL() portEXIT_CRITICAL(&rtc_spinlock)

#ifndef CONFIG_ADC_CONTINUOUS_NUM_DMA
#define INTERNAL_BUF_NUM 5
#else
#define INTERNAL_BUF_NUM CONFIG_ADC_CONTINUOUS_NUM_DMA
#endif

/*---------------------------------------------------------------
ADC Continuous Read Mode (via DMA)
Expand All @@ -63,7 +67,7 @@ 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;
BaseType_t ret = 0;
adc_hal_dma_desc_status_t status = false;
uint8_t *finished_buffer = NULL;
uint32_t finished_size = 0;
Expand All @@ -80,8 +84,10 @@ static IRAM_ATTR bool adc_dma_intr(adc_continuous_ctx_t *adc_digi_ctx)
}
#endif

ret = xRingbufferSendFromISR(adc_digi_ctx->ringbuf_hdl, finished_buffer, finished_size, &taskAwoken);
need_yield |= (taskAwoken == pdTRUE);
if (adc_digi_ctx->ringbuf_hdl) {
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 = {
Expand All @@ -93,30 +99,32 @@ static IRAM_ATTR bool adc_dma_intr(adc_continuous_ctx_t *adc_digi_ctx)
}
}

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 manual 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;
if (adc_digi_ctx->ringbuf_hdl) {
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 manual 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;
//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;
}
}
}
}
Expand Down Expand Up @@ -179,18 +187,22 @@ esp_err_t adc_continuous_new_handle(const adc_continuous_handle_cfg_t *hdl_confi

//ringbuffer storage/struct buffer
adc_ctx->ringbuf_size = hdl_config->max_store_buf_size;
adc_ctx->ringbuf_storage = heap_caps_calloc(1, hdl_config->max_store_buf_size, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
adc_ctx->ringbuf_struct = heap_caps_calloc(1, sizeof(StaticRingbuffer_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
if (!adc_ctx->ringbuf_storage || !adc_ctx->ringbuf_struct) {
ret = ESP_ERR_NO_MEM;
goto cleanup;
}
if (hdl_config->max_store_buf_size) {
adc_ctx->ringbuf_storage = heap_caps_calloc(1, hdl_config->max_store_buf_size, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
adc_ctx->ringbuf_struct = heap_caps_calloc(1, sizeof(StaticRingbuffer_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
if (!adc_ctx->ringbuf_storage || !adc_ctx->ringbuf_struct) {
ret = ESP_ERR_NO_MEM;
goto cleanup;
}

//ringbuffer
adc_ctx->ringbuf_hdl = xRingbufferCreateStatic(hdl_config->max_store_buf_size, RINGBUF_TYPE_BYTEBUF, adc_ctx->ringbuf_storage, adc_ctx->ringbuf_struct);
if (!adc_ctx->ringbuf_hdl) {
ret = ESP_ERR_NO_MEM;
goto cleanup;
//ringbuffer
adc_ctx->ringbuf_hdl = xRingbufferCreateStatic(hdl_config->max_store_buf_size, RINGBUF_TYPE_BYTEBUF, adc_ctx->ringbuf_storage, adc_ctx->ringbuf_struct);
if (!adc_ctx->ringbuf_hdl) {
ret = ESP_ERR_NO_MEM;
goto cleanup;
}
} else {
adc_ctx->ringbuf_hdl = NULL;
}

//malloc internal buffer used by DMA
Expand Down Expand Up @@ -389,6 +401,10 @@ esp_err_t adc_continuous_read(adc_continuous_handle_t handle, uint8_t *buf, uint
uint8_t *data = NULL;
size_t size = 0;

if (!handle->ringbuf_hdl) {
*out_length = 0;
return ret;
}
ticks_to_wait = timeout_ms / portTICK_PERIOD_MS;
if (timeout_ms == ADC_MAX_DELAY) {
ticks_to_wait = portMAX_DELAY;
Expand Down Expand Up @@ -562,6 +578,10 @@ esp_err_t adc_continuous_flush_pool(adc_continuous_handle_t handle)
size_t actual_size = 0;
uint8_t *old_data = NULL;

if (!handle->ringbuf_hdl) {
return ESP_OK;
}

while ((old_data = xRingbufferReceiveUpTo(handle->ringbuf_hdl, &actual_size, 0, handle->ringbuf_size))) {
vRingbufferReturnItem(handle->ringbuf_hdl, old_data);
}
Expand Down
7 changes: 7 additions & 0 deletions components/esp_driver_i2s/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ menu "ESP-Driver:I2S Configurations"
Ensure the I2S interrupt is IRAM-Safe by allowing the interrupt handler to be
executable when the cache is disabled (e.g. SPI Flash write).

config I2S_FORCE_FRAC_DIVISOR
bool "Force fractional divisor for PDM mode on v2 HW"
default y
help
Force fractional part of clock divisor to known value.
This seems to help reducing noise.

config I2S_ENABLE_DEBUG_LOG
bool "Enable I2S debug log"
default n
Expand Down
4 changes: 3 additions & 1 deletion components/esp_driver_i2s/i2s_pdm.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,12 @@ static esp_err_t i2s_pdm_tx_set_clock(i2s_chan_handle_t handle, const i2s_pdm_tx
I2S_CLOCK_SRC_ATOMIC() {
i2s_hal_set_tx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src);
}
#if SOC_I2S_HW_VERSION_2
#if SOC_I2S_HW_VERSION_2 && I2S_FORCE_FRAC_DIVISOR
/* Work around for PDM TX clock, overwrite the raw division directly to reduce the noise
* This set of coefficients is a special division to reduce the background noise in PDM TX mode */
i2s_ll_tx_set_raw_clk_div(handle->controller->hal.dev, clk_info.mclk_div, 1, 1, 0, 0);
#else
#warning "I2S PDM clock workaround disabled"
#endif
portEXIT_CRITICAL(&g_i2s.spinlock);

Expand Down
3 changes: 3 additions & 0 deletions components/esp_hw_support/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@ if(NOT non_os_build)
if(CONFIG_SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX OR CONFIG_SOC_GPIO_CLOCKOUT_BY_IO_MUX)
list(APPEND srcs "esp_clock_output.c")
endif()
if(CONFIG_SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY)
set_source_files_properties(sleep_modes.c PROPERTIES COMPILE_OPTIONS -mtext-section-literals)
endif()
else()
if(ESP_TEE_BUILD)
list(APPEND srcs "esp_clk.c" "hw_random.c")
Expand Down
6 changes: 6 additions & 0 deletions components/esp_hw_support/sleep_modes.c
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,12 @@ static void __attribute__((section(".rtc.entry.text"))) esp_wake_stub_entry(void
{
#define _SYM2STR(s) # s
#define SYM2STR(s) _SYM2STR(s)
goto __after_literal;
__asm__ __volatile__ (
".literal_position \n"
".align 4 \n"
);
__after_literal:

#ifdef __riscv
__asm__ __volatile__ (
Expand Down
25 changes: 24 additions & 1 deletion components/hal/adc_hal.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
#include "sdkconfig.h"
#include "hal/adc_hal.h"
#include "hal/assert.h"
#include "hal/hal_utils.h"
#include "soc/lldesc.h"
#include "soc/soc_caps.h"
#include "hal/log.h"

#if CONFIG_IDF_TARGET_ESP32
//ADC utilises I2S0 DMA on ESP32
Expand Down Expand Up @@ -119,11 +121,32 @@ static adc_ll_digi_convert_mode_t get_convert_mode(adc_digi_convert_mode_t conve
static void adc_hal_digi_sample_freq_config(adc_hal_dma_ctx_t *hal, adc_continuous_clk_src_t clk_src, uint32_t clk_src_freq_hz, uint32_t sample_freq_hz)
{
#if !CONFIG_IDF_TARGET_ESP32
uint32_t interval = clk_src_freq_hz / (ADC_LL_CLKM_DIV_NUM_DEFAULT + ADC_LL_CLKM_DIV_A_DEFAULT / ADC_LL_CLKM_DIV_B_DEFAULT + 1) / 2 / sample_freq_hz;
#if CONFIG_ADC_DIGI_CLK_DIV_DEFAULT
uint32_t interval = (((long long)clk_src_freq_hz<<10) / (((long long)ADC_LL_CLKM_DIV_NUM_DEFAULT<<10) + ((long long)ADC_LL_CLKM_DIV_B_DEFAULT<<10) / ADC_LL_CLKM_DIV_A_DEFAULT) /sample_freq_hz +1) /2;
//set sample interval
adc_ll_digi_set_trigger_interval(interval);
//Here we set the clock divider factor to make the digital clock to 5M Hz
adc_ll_digi_controller_clk_div(ADC_LL_CLKM_DIV_NUM_DEFAULT, ADC_LL_CLKM_DIV_B_DEFAULT, ADC_LL_CLKM_DIV_A_DEFAULT);
#else
uint32_t interval;
hal_utils_clk_info_t digi_clk_info = {
.src_freq_hz = clk_src_freq_hz,
.exp_freq_hz = (CONFIG_ADC_SARADC_TARGET_CLK/sample_freq_hz)*sample_freq_hz,
.max_integ = APB_SARADC_CLKM_DIV_NUM,
.min_integ = 1,
.max_fract = APB_SARADC_CLKM_DIV_A,
};
hal_utils_clk_div_t clk_div;
hal_utils_calc_clk_div_frac_fast(&digi_clk_info, &clk_div);
interval = (((long long)clk_src_freq_hz<<10) / (((long long)(clk_div.integer)<<10) + ((long long)(clk_div.numerator)<<10) / clk_div.denominator ) / sample_freq_hz +1) /2;

HAL_EARLY_LOGD("ADC_HAL","sclk = %ld, Div = %ld + %ld/%ld, Interval = %ld, Fs = %ld", clk_src_freq_hz, clk_div.integer, clk_div.numerator, clk_div.denominator, interval, (int32_t)(((int64_t)clk_src_freq_hz*clk_div.denominator / ((clk_div.integer*clk_div.denominator + clk_div.numerator) * interval ) +1) /2));

//set sample interval
adc_ll_digi_set_trigger_interval(interval);
//Here we set the clock divider factor to make the digital clock to CONFIG_ADC_SARADC_TARGET_CLK Hz
adc_ll_digi_controller_clk_div(clk_div.integer-1, clk_div.denominator, clk_div.numerator);
#endif
adc_ll_digi_clk_sel(clk_src);
#else
i2s_ll_rx_clk_set_src(adc_hal_i2s_dev, I2S_CLK_SRC_DEFAULT); /*!< Clock from PLL_D2_CLK(160M)*/
Expand Down
4 changes: 2 additions & 2 deletions components/hal/esp32s3/include/hal/adc_ll.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ extern "C" {
#define ADC_LL_DIGI_SAR_CLK_DIV_DEFAULT (1)

#define ADC_LL_CLKM_DIV_NUM_DEFAULT 15
#define ADC_LL_CLKM_DIV_B_DEFAULT 1
#define ADC_LL_CLKM_DIV_A_DEFAULT 0
#define ADC_LL_CLKM_DIV_B_DEFAULT 5
#define ADC_LL_CLKM_DIV_A_DEFAULT 33
#define ADC_LL_DEFAULT_CONV_LIMIT_EN 0
#define ADC_LL_DEFAULT_CONV_LIMIT_NUM 10

Expand Down
6 changes: 6 additions & 0 deletions components/hal/esp32s3/include/hal/i2s_ll.h
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,9 @@ static inline void i2s_ll_tx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src)
case I2S_CLK_SRC_XTAL:
hw->tx_clkm_conf.tx_clk_sel = 0;
break;
case I2S_CLK_SRC_PLL_D2:
hw->tx_clkm_conf.tx_clk_sel = 1;
break;
case I2S_CLK_SRC_PLL_160M:
hw->tx_clkm_conf.tx_clk_sel = 2;
break;
Expand All @@ -257,6 +260,9 @@ static inline void i2s_ll_rx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src)
case I2S_CLK_SRC_XTAL:
hw->rx_clkm_conf.rx_clk_sel = 0;
break;
case I2S_CLK_SRC_PLL_D2:
hw->rx_clkm_conf.rx_clk_sel = 1;
break;
case I2S_CLK_SRC_PLL_160M:
hw->rx_clkm_conf.rx_clk_sel = 2;
break;
Expand Down
5 changes: 4 additions & 1 deletion components/hal/i2s_hal.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "soc/soc.h"
#include "hal/assert.h"
#include "hal/i2s_hal.h"
#include "hal/log.h"

#if SOC_I2S_HW_VERSION_2 && (SOC_I2S_SUPPORTS_PDM_TX || SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER)
/* PDM tx high pass filter cut-off frequency and coefficients list
Expand Down Expand Up @@ -58,7 +59,7 @@ void i2s_hal_calc_mclk_precise_division(uint32_t sclk, uint32_t mclk, hal_utils_
.min_integ = 1,
.max_fract = I2S_LL_CLK_FRAC_DIV_AB_MAX,
};
hal_utils_calc_clk_div_frac_accurate(&i2s_clk_info, mclk_div);
hal_utils_calc_clk_div_frac_fast(&i2s_clk_info, mclk_div);
}

void i2s_hal_init(i2s_hal_context_t *hal, int port_id)
Expand Down Expand Up @@ -114,6 +115,8 @@ void i2s_hal_set_tx_clock(i2s_hal_context_t *hal, const i2s_hal_clock_info_t *cl
i2s_hal_calc_mclk_precise_division(clk_info->sclk, clk_info->mclk, &mclk_div);
i2s_ll_tx_set_mclk(hal->dev, &mclk_div);
i2s_ll_tx_set_bck_div_num(hal->dev, clk_info->bclk_div);
HAL_EARLY_LOGD("I2S_HAL","src_clk = %ld, div = %ld + %ld/%ld, bdiv = %d, Fs = %ld",clk_info->sclk, mclk_div.integer, mclk_div.numerator, mclk_div.denominator, clk_info->bclk_div,
(int32_t)((((int64_t)clk_info->sclk*mclk_div.denominator) / ((mclk_div.integer*mclk_div.denominator + mclk_div.numerator)*clk_info->bclk_div)+64)/128) );
} else {
i2s_ll_tx_clk_set_src(hal->dev, clk_src);
}
Expand Down
1 change: 1 addition & 0 deletions components/soc/esp32s3/include/soc/clk_tree_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@ typedef enum {
*/
typedef enum {
I2S_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the default source clock */
I2S_CLK_SRC_PLL_D2 = SOC_MOD_CLK_PLL_D2, /*!< Select PLL_D2 as the source clock */
I2S_CLK_SRC_PLL_160M = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the source clock */
I2S_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */
I2S_CLK_SRC_EXTERNAL = -1, /*!< Select external clock as source clock */
Expand Down
Loading