diff --git a/components/driver/CMakeLists.txt b/components/driver/CMakeLists.txt index 0a168abb5a..6af58de63d 100644 --- a/components/driver/CMakeLists.txt +++ b/components/driver/CMakeLists.txt @@ -111,6 +111,7 @@ endif() # I2S related source files if(CONFIG_SOC_I2S_SUPPORTED) list(APPEND srcs "i2s/i2s_common.c" + "i2s/i2s_platform.c" "i2s/i2s_std.c" "deprecated/i2s_legacy.c") if(CONFIG_SOC_I2S_SUPPORTS_PDM) @@ -236,7 +237,7 @@ else() # Can be removed together with legacy drivers) idf_component_register(SRCS "${srcs}" INCLUDE_DIRS ${includes} - PRIV_REQUIRES efuse esp_timer + PRIV_REQUIRES efuse esp_timer esp_mm REQUIRES esp_pm esp_ringbuf freertos soc hal esp_hw_support LDFRAGMENTS ${ldfragments} ) diff --git a/components/driver/dac/esp32/dac_dma.c b/components/driver/dac/esp32/dac_dma.c index c5f8223a90..f1e648f16d 100644 --- a/components/driver/dac/esp32/dac_dma.c +++ b/components/driver/dac/esp32/dac_dma.c @@ -17,6 +17,7 @@ #include "hal/adc_ll.h" #include "hal/i2s_hal.h" #include "hal/i2s_types.h" +#include "hal/clk_tree_ll.h" #include "soc/i2s_periph.h" #include "../dac_priv_dma.h" #include "esp_private/i2s_platform.h" @@ -46,7 +47,7 @@ static const char *TAG = "DAC_DMA"; static uint32_t s_dac_set_apll_freq(uint32_t mclk) { /* Calculate the expected APLL */ - int div = (int)((SOC_APLL_MIN_HZ / mclk) + 1); + int div = (int)((CLK_LL_APLL_MIN_HZ / mclk) + 1); /* apll_freq = mclk * div * when div = 1, hardware will still divide 2 * when div = 0, hardware will divide 255 diff --git a/components/driver/dac/esp32s2/dac_dma.c b/components/driver/dac/esp32s2/dac_dma.c index af9dfb11c6..d13c63f39b 100644 --- a/components/driver/dac/esp32s2/dac_dma.c +++ b/components/driver/dac/esp32s2/dac_dma.c @@ -19,6 +19,7 @@ #include "hal/dac_ll.h" #include "hal/adc_ll.h" #include "hal/hal_utils.h" +#include "hal/clk_tree_ll.h" #include "soc/lldesc.h" #include "soc/soc.h" #include "soc/soc_caps.h" @@ -75,9 +76,9 @@ static esp_err_t s_dac_dma_periph_set_clock(uint32_t freq_hz, bool is_apll){ uint32_t digi_ctrl_freq; // Digital controller clock if (is_apll) { /* Theoretical frequency range (due to the limitation of DAC, the maximum frequency may not reach): - * SOC_APLL_MAX_HZ: 119.24 Hz ~ 67.5 MHz - * SOC_APLL_MIN_HZ: 5.06 Hz ~ 2.65 MHz */ - digi_ctrl_freq = s_dac_set_apll_freq(freq_hz < 120 ? SOC_APLL_MIN_HZ :SOC_APLL_MAX_HZ); + * CLK_LL_APLL_MAX_HZ: 119.24 Hz ~ 67.5 MHz + * CLK_LL_APLL_MIN_HZ: 5.06 Hz ~ 2.65 MHz */ + digi_ctrl_freq = s_dac_set_apll_freq(freq_hz < 120 ? CLK_LL_APLL_MIN_HZ :CLK_LL_APLL_MAX_HZ); ESP_RETURN_ON_FALSE(digi_ctrl_freq, ESP_ERR_INVALID_ARG, TAG, "set APLL coefficients failed"); } else { digi_ctrl_freq = APB_CLK_FREQ; diff --git a/components/driver/deprecated/i2s_legacy.c b/components/driver/deprecated/i2s_legacy.c index 9b7ded0144..494aba2e25 100644 --- a/components/driver/deprecated/i2s_legacy.c +++ b/components/driver/deprecated/i2s_legacy.c @@ -25,6 +25,10 @@ #include "hal/gpio_hal.h" #include "driver/i2s_types_legacy.h" #include "hal/i2s_hal.h" +#if SOC_I2S_SUPPORTS_APLL +#include "hal/clk_tree_ll.h" +#endif + #if SOC_I2S_SUPPORTS_DAC #include "hal/dac_ll.h" #include "hal/dac_types.h" @@ -48,6 +52,7 @@ #include "esp_pm.h" #include "esp_efuse.h" #include "esp_rom_gpio.h" +#include "esp_private/i2s_platform.h" #include "esp_private/periph_ctrl.h" #include "esp_private/esp_clk.h" @@ -58,6 +63,18 @@ static const char *TAG = "i2s(legacy)"; #define I2S_ENTER_CRITICAL(i2s_num) portENTER_CRITICAL(&i2s_spinlock[i2s_num]) #define I2S_EXIT_CRITICAL(i2s_num) portEXIT_CRITICAL(&i2s_spinlock[i2s_num]) +#if SOC_PERIPH_CLK_CTRL_SHARED +#define I2S_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC() +#else +#define I2S_CLOCK_SRC_ATOMIC() +#endif + +#if !SOC_RCC_IS_INDEPENDENT +#define I2S_RCC_ATOMIC() PERIPH_RCC_ATOMIC() +#else +#define I2S_RCC_ATOMIC() +#endif + #define I2S_DMA_BUFFER_MAX_SIZE 4092 #if SOC_I2S_SUPPORTS_ADC_DAC @@ -134,9 +151,6 @@ typedef struct { uint32_t total_slot; /*!< Total slot number */ } i2s_obj_t; -// Record the component name that using I2S peripheral -static const char *comp_using_i2s[SOC_I2S_NUM] = {[0 ... SOC_I2S_NUM - 1] = NULL}; - // Global I2S object pointer static i2s_obj_t *p_i2s[SOC_I2S_NUM] = { [0 ... SOC_I2S_NUM - 1] = NULL, @@ -147,11 +161,6 @@ static portMUX_TYPE i2s_spinlock[SOC_I2S_NUM] = { [0 ... SOC_I2S_NUM - 1] = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED, }; - -__attribute__((weak)) esp_err_t i2s_platform_acquire_occupation(int id, const char *comp_name); - -__attribute__((weak)) esp_err_t i2s_platform_release_occupation(int id); - /*------------------------------------------------------------- I2S DMA operation -------------------------------------------------------------*/ @@ -633,7 +642,7 @@ static uint32_t i2s_config_source_clock(i2s_port_t i2s_num, bool use_apll, uint3 #if SOC_I2S_SUPPORTS_APLL if (use_apll) { /* Calculate the expected APLL */ - int div = (int)((SOC_APLL_MIN_HZ / mclk) + 1); + int div = (int)((CLK_LL_APLL_MIN_HZ / mclk) + 1); /* apll_freq = mclk * div * when div = 1, hardware will still divide 2 * when div = 0, the final mclk will be unpredictable @@ -654,12 +663,12 @@ static uint32_t i2s_config_source_clock(i2s_port_t i2s_num, bool use_apll, uint3 /* In APLL mode, there is no sclk but only mclk, so return 0 here to indicate APLL mode */ return real_freq; } - return I2S_LL_DEFAULT_PLL_CLK_FREQ; + return I2S_LL_DEFAULT_CLK_FREQ; #else if (use_apll) { ESP_LOGW(TAG, "APLL not supported on current chip, use I2S_CLK_SRC_DEFAULT as default clock source"); } - return I2S_LL_DEFAULT_PLL_CLK_FREQ; + return I2S_LL_DEFAULT_CLK_FREQ; #endif } @@ -1021,11 +1030,13 @@ static void i2s_set_clock_legacy(i2s_port_t i2s_num) i2s_clk_config_t *clk_cfg = &p_i2s[i2s_num]->clk_cfg; i2s_hal_clock_info_t clk_info; i2s_calculate_clock(i2s_num, &clk_info); - if (p_i2s[i2s_num]->dir & I2S_DIR_TX) { - i2s_hal_set_tx_clock(&(p_i2s[i2s_num]->hal), &clk_info, clk_cfg->clk_src); - } - if (p_i2s[i2s_num]->dir & I2S_DIR_RX) { - i2s_hal_set_rx_clock(&(p_i2s[i2s_num]->hal), &clk_info, clk_cfg->clk_src); + I2S_CLOCK_SRC_ATOMIC() { + if (p_i2s[i2s_num]->dir & I2S_DIR_TX) { + i2s_hal_set_tx_clock(&(p_i2s[i2s_num]->hal), &clk_info, clk_cfg->clk_src); + } + if (p_i2s[i2s_num]->dir & I2S_DIR_RX) { + i2s_hal_set_rx_clock(&(p_i2s[i2s_num]->hal), &clk_info, clk_cfg->clk_src); + } } } @@ -1479,17 +1490,6 @@ static esp_err_t i2s_init_legacy(i2s_port_t i2s_num, int intr_alloc_flag) ESP_RETURN_ON_ERROR(i2s_realloc_dma_buffer(i2s_num, p_i2s[i2s_num]->rx), TAG, "Allocate I2S dma rx buffer failed"); } - /* Initialize I2S DMA object */ -#if SOC_I2S_HW_VERSION_2 - /* Enable tx/rx submodule clock */ - if (p_i2s[i2s_num]->dir & I2S_DIR_TX) { - i2s_ll_tx_enable_clock(p_i2s[i2s_num]->hal.dev); - } - if (p_i2s[i2s_num]->dir & I2S_DIR_RX) { - i2s_ll_rx_enable_clock(p_i2s[i2s_num]->hal.dev); - } -#endif - return ESP_OK; } @@ -1538,12 +1538,14 @@ esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num) #if SOC_I2S_SUPPORTS_APLL if (obj->use_apll) { - // switch back to PLL clock source - if (obj->dir & I2S_DIR_TX) { - i2s_ll_tx_clk_set_src(obj->hal.dev, I2S_CLK_SRC_DEFAULT); - } - if (obj->dir & I2S_DIR_RX) { - i2s_ll_rx_clk_set_src(obj->hal.dev, I2S_CLK_SRC_DEFAULT); + I2S_CLOCK_SRC_ATOMIC() { + // switch back to PLL clock source + if (obj->dir & I2S_DIR_TX) { + i2s_hal_set_tx_clock(&obj->hal, NULL, I2S_CLK_SRC_DEFAULT); + } + if (obj->dir & I2S_DIR_RX) { + i2s_hal_set_rx_clock(&obj->hal, NULL, I2S_CLK_SRC_DEFAULT); + } } periph_rtc_apll_release(); } @@ -1556,11 +1558,13 @@ esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num) } #endif #if SOC_I2S_HW_VERSION_2 - if (obj->dir & I2S_DIR_TX) { - i2s_ll_tx_disable_clock(obj->hal.dev); - } - if (obj->dir & I2S_DIR_RX) { - i2s_ll_rx_disable_clock(obj->hal.dev); + I2S_CLOCK_SRC_ATOMIC() { + if (obj->dir & I2S_DIR_TX) { + i2s_ll_tx_disable_clock(obj->hal.dev); + } + if (obj->dir & I2S_DIR_RX) { + i2s_ll_rx_disable_clock(obj->hal.dev); + } } #endif /* Disable module clock */ @@ -1896,37 +1900,6 @@ esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin) return ESP_OK; } -esp_err_t i2s_platform_acquire_occupation(int id, const char *comp_name) -{ - esp_err_t ret = ESP_ERR_NOT_FOUND; - ESP_RETURN_ON_FALSE(id < SOC_I2S_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid i2s port id"); - portENTER_CRITICAL(&i2s_spinlock[id]); - if (!comp_using_i2s[id]) { - ret = ESP_OK; - comp_using_i2s[id] = comp_name; - periph_module_enable(i2s_periph_signal[id].module); - i2s_ll_enable_clock(I2S_LL_GET_HW(id)); - } - portEXIT_CRITICAL(&i2s_spinlock[id]); - return ret; -} - -esp_err_t i2s_platform_release_occupation(int id) -{ - esp_err_t ret = ESP_ERR_INVALID_STATE; - ESP_RETURN_ON_FALSE(id < SOC_I2S_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid i2s port id"); - portENTER_CRITICAL(&i2s_spinlock[id]); - if (comp_using_i2s[id]) { - ret = ESP_OK; - comp_using_i2s[id] = NULL; - /* Disable module clock */ - periph_module_disable(i2s_periph_signal[id].module); - i2s_ll_disable_clock(I2S_LL_GET_HW(id)); - } - portEXIT_CRITICAL(&i2s_spinlock[id]); - return ret; -} - /** * @brief This function will be called during start up, to check that the new i2s driver is not running along with the legacy i2s driver */ diff --git a/components/driver/i2s/i2s_common.c b/components/driver/i2s/i2s_common.c index d1e7f2dbde..3a80b15805 100644 --- a/components/driver/i2s/i2s_common.c +++ b/components/driver/i2s/i2s_common.c @@ -25,17 +25,21 @@ #include "soc/soc_caps.h" #include "hal/gpio_hal.h" #include "hal/i2s_hal.h" +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE +#include "hal/cache_hal.h" +#include "hal/cache_ll.h" +#endif #if SOC_I2S_SUPPORTS_ADC_DAC #include "hal/adc_ll.h" #include "driver/adc_i2s_legacy.h" #endif #if SOC_I2S_SUPPORTS_APLL +#include "hal/clk_tree_ll.h" #include "clk_ctrl_os.h" #endif #include "esp_private/i2s_platform.h" -#include "esp_private/periph_ctrl.h" #include "esp_private/esp_clk.h" #include "driver/gpio.h" @@ -47,6 +51,10 @@ #include "esp_intr_alloc.h" #include "esp_check.h" #include "esp_attr.h" +#include "esp_dma_utils.h" +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE +#include "esp_cache.h" +#endif #include "esp_rom_gpio.h" #include "esp_memory_utils.h" @@ -55,18 +63,15 @@ * Set 4092 here to align with 4-byte, so that the position of the slot data in the buffer will be relatively fixed */ #define I2S_DMA_BUFFER_MAX_SIZE (4092) -/** - * @brief Global i2s platform object - * @note For saving all the I2S related information - */ -i2s_platform_t g_i2s = { - .spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED, - .controller[0 ... (SOC_I2S_NUM - 1)] = NULL, // groups will be lazy installed - .comp_name[0 ... (SOC_I2S_NUM - 1)] = NULL, -}; - static const char *TAG = "i2s_common"; +__attribute__((always_inline)) +inline void *i2s_dma_calloc(size_t num, size_t size, uint32_t caps, size_t *actual_size) { + void *ptr = NULL; + esp_dma_calloc(num, size, caps, &ptr, actual_size); + return ptr; +} + /*--------------------------------------------------------------------------- I2S Static APIs ---------------------------------------------------------------------------- @@ -261,6 +266,7 @@ static esp_err_t i2s_register_channel(i2s_controller_t *i2s_obj, i2s_dir_t dir, new_chan->callbacks.on_send_q_ovf = NULL; new_chan->dma.rw_pos = 0; new_chan->dma.curr_ptr = NULL; + new_chan->dma.curr_desc = NULL; new_chan->start = NULL; new_chan->stop = NULL; @@ -292,6 +298,11 @@ err: return ret; } +#ifndef __cplusplus +/* To make sure the i2s_event_callbacks_t is same size as i2s_event_callbacks_internal_t */ +_Static_assert(sizeof(i2s_event_callbacks_t) == sizeof(i2s_event_callbacks_internal_t), "Invalid size of i2s_event_callbacks_t structure"); +#endif + esp_err_t i2s_channel_register_event_callback(i2s_chan_handle_t handle, const i2s_event_callbacks_t *callbacks, void *user_data) { I2S_NULL_POINTER_CHECK(TAG, handle); @@ -330,6 +341,26 @@ uint32_t i2s_get_buf_size(i2s_chan_handle_t handle, uint32_t data_bit_width, uin uint32_t bytes_per_sample = ((data_bit_width + 15) / 16) * 2; uint32_t bytes_per_frame = bytes_per_sample * active_chan; uint32_t bufsize = dma_frame_num * bytes_per_frame; +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE + /* bufsize need to align with cache line size */ + uint32_t alignment = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA); + uint32_t aligned_frame_num = dma_frame_num; + /* To make the buffer aligned with the cache line size, search for the ceil aligned size first, + If the buffer size exceed the max DMA buffer size, toggle the sign to search for the floor aligned size */ + for (int sign = 1; bufsize % alignment != 0; aligned_frame_num += sign) { + bufsize = aligned_frame_num * bytes_per_frame; + /* If the buffer size exceed the max dma size */ + if (bufsize > I2S_DMA_BUFFER_MAX_SIZE) { + sign = -1; // toggle the search sign + aligned_frame_num = dma_frame_num; // Reset the frame num + bufsize = aligned_frame_num * bytes_per_frame; // Reset the bufsize + } + } + if (bufsize / bytes_per_frame != dma_frame_num) { + ESP_LOGW(TAG, "dma frame num is adjusted to %"PRIu32" to algin the dma buffer with %"PRIu32 + ", bufsize = %"PRIu32, bufsize / bytes_per_frame, alignment, bufsize); + } +#endif /* Limit DMA buffer size if it is out of range (DMA buffer limitation is 4092 bytes) */ if (bufsize > I2S_DMA_BUFFER_MAX_SIZE) { uint32_t frame_num = I2S_DMA_BUFFER_MAX_SIZE / bytes_per_frame; @@ -348,18 +379,21 @@ esp_err_t i2s_free_dma_desc(i2s_chan_handle_t handle) for (int i = 0; i < handle->dma.desc_num; i++) { if (handle->dma.bufs[i]) { free(handle->dma.bufs[i]); + handle->dma.bufs[i] = NULL; } if (handle->dma.desc[i]) { free(handle->dma.desc[i]); + handle->dma.desc[i] = NULL; } } if (handle->dma.bufs) { free(handle->dma.bufs); + handle->dma.bufs = NULL; } if (handle->dma.desc) { free(handle->dma.desc); + handle->dma.desc = NULL; } - handle->dma.desc = NULL; return ESP_OK; } @@ -376,9 +410,10 @@ esp_err_t i2s_alloc_dma_desc(i2s_chan_handle_t handle, uint32_t num, uint32_t bu handle->dma.desc = (lldesc_t **)heap_caps_calloc(num, sizeof(lldesc_t *), I2S_MEM_ALLOC_CAPS); ESP_GOTO_ON_FALSE(handle->dma.desc, ESP_ERR_NO_MEM, err, TAG, "create I2S DMA decriptor array failed"); handle->dma.bufs = (uint8_t **)heap_caps_calloc(num, sizeof(uint8_t *), I2S_MEM_ALLOC_CAPS); + size_t desc_size = 0; for (int i = 0; i < num; i++) { /* Allocate DMA descriptor */ - handle->dma.desc[i] = (lldesc_t *) heap_caps_calloc(1, sizeof(lldesc_t), I2S_DMA_ALLOC_CAPS); + handle->dma.desc[i] = (lldesc_t *) i2s_dma_calloc(1, sizeof(lldesc_t), I2S_DMA_ALLOC_CAPS, &desc_size); ESP_GOTO_ON_FALSE(handle->dma.desc[i], ESP_ERR_NO_MEM, err, TAG, "allocate DMA description failed"); handle->dma.desc[i]->owner = 1; handle->dma.desc[i]->eof = 1; @@ -386,15 +421,18 @@ esp_err_t i2s_alloc_dma_desc(i2s_chan_handle_t handle, uint32_t num, uint32_t bu handle->dma.desc[i]->length = bufsize; handle->dma.desc[i]->size = bufsize; handle->dma.desc[i]->offset = 0; - handle->dma.bufs[i] = (uint8_t *) heap_caps_calloc(1, bufsize * sizeof(uint8_t), I2S_DMA_ALLOC_CAPS); + handle->dma.bufs[i] = (uint8_t *) i2s_dma_calloc(1, bufsize * sizeof(uint8_t), I2S_DMA_ALLOC_CAPS, NULL); + ESP_GOTO_ON_FALSE(handle->dma.bufs[i], ESP_ERR_NO_MEM, err, TAG, "allocate DMA buffer failed"); handle->dma.desc[i]->buf = handle->dma.bufs[i]; - ESP_GOTO_ON_FALSE(handle->dma.desc[i]->buf, ESP_ERR_NO_MEM, err, TAG, "allocate DMA buffer failed"); ESP_LOGV(TAG, "desc addr: %8p\tbuffer addr:%8p", handle->dma.desc[i], handle->dma.bufs[i]); } /* Connect DMA descriptor as a circle */ for (int i = 0; i < num; i++) { /* Link to the next descriptor */ STAILQ_NEXT(handle->dma.desc[i], qe) = (i < (num - 1)) ? (handle->dma.desc[i + 1]) : handle->dma.desc[0]; +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE + esp_cache_msync(handle->dma.desc[i], desc_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M); +#endif } if (handle->dir == I2S_DIR_RX) { i2s_ll_rx_set_eof_num(handle->controller->hal.dev, bufsize); @@ -410,14 +448,14 @@ err: static uint32_t i2s_set_get_apll_freq(uint32_t mclk_freq_hz) { /* Calculate the expected APLL */ - int mclk_div = (int)((SOC_APLL_MIN_HZ / mclk_freq_hz) + 1); + int mclk_div = (int)((CLK_LL_APLL_MIN_HZ / mclk_freq_hz) + 1); /* apll_freq = mclk * div * when div = 1, hardware will still divide 2 * when div = 0, the final mclk will be unpredictable * So the div here should be at least 2 */ mclk_div = mclk_div < 2 ? 2 : mclk_div; uint32_t expt_freq = mclk_freq_hz * mclk_div; - if (expt_freq > SOC_APLL_MAX_HZ) { + if (expt_freq > CLK_LL_APLL_MAX_HZ) { ESP_LOGE(TAG, "The required APLL frequency exceed its maximum value"); return 0; } @@ -459,6 +497,9 @@ static bool IRAM_ATTR i2s_dma_rx_callback(gdma_channel_handle_t dma_chan, gdma_e uint32_t dummy; finish_desc = (lldesc_t *)event_data->rx_eof_desc_addr; +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE + esp_cache_msync((void *)finish_desc->buf, handle->dma.buf_size, ESP_CACHE_MSYNC_FLAG_INVALIDATE); +#endif i2s_event_data_t evt = { .data = &(finish_desc->buf), .size = handle->dma.buf_size, @@ -487,7 +528,7 @@ static bool IRAM_ATTR i2s_dma_tx_callback(gdma_channel_handle_t dma_chan, gdma_e lldesc_t *finish_desc; uint32_t dummy; - finish_desc = (lldesc_t *)(event_data->tx_eof_desc_addr); + finish_desc = (lldesc_t *)event_data->tx_eof_desc_addr; i2s_event_data_t evt = { .data = &(finish_desc->buf), .size = handle->dma.buf_size, @@ -505,6 +546,9 @@ static bool IRAM_ATTR i2s_dma_tx_callback(gdma_channel_handle_t dma_chan, gdma_e if (handle->dma.auto_clear) { uint8_t *sent_buf = (uint8_t *)finish_desc->buf; memset(sent_buf, 0, handle->dma.buf_size); +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE + esp_cache_msync(sent_buf, handle->dma.buf_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M); +#endif } xQueueSendFromISR(handle->msg_queue, &(finish_desc->buf), &need_yield2); @@ -646,7 +690,7 @@ esp_err_t i2s_init_dma_intr(i2s_chan_handle_t handle, int intr_flag) gdma_register_rx_event_callbacks(handle->dma.dma_chan, &cb, handle); } #else - intr_flag |= ESP_INTR_FLAG_SHARED; + intr_flag |= handle->intr_prio_flags; /* Initialize I2S module interrupt */ if (handle->dir == I2S_DIR_TX) { esp_intr_alloc_intrstatus(i2s_periph_signal[port_id].irq, intr_flag, @@ -663,10 +707,10 @@ esp_err_t i2s_init_dma_intr(i2s_chan_handle_t handle, int intr_flag) return ESP_OK; } -void i2s_gpio_check_and_set(gpio_num_t gpio, uint32_t signal_idx, bool is_input, bool is_invert) +void i2s_gpio_check_and_set(int gpio, uint32_t signal_idx, bool is_input, bool is_invert) { /* Ignore the pin if pin = I2S_GPIO_UNUSED */ - if (gpio != I2S_GPIO_UNUSED) { + if (gpio != (int)I2S_GPIO_UNUSED) { gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio], PIN_FUNC_GPIO); if (is_input) { /* Set direction, for some GPIOs, the input function are not enabled as default */ @@ -679,9 +723,9 @@ void i2s_gpio_check_and_set(gpio_num_t gpio, uint32_t signal_idx, bool is_input, } } -void i2s_gpio_loopback_set(gpio_num_t gpio, uint32_t out_sig_idx, uint32_t in_sig_idx) +void i2s_gpio_loopback_set(int gpio, uint32_t out_sig_idx, uint32_t in_sig_idx) { - if (gpio != I2S_GPIO_UNUSED) { + if (gpio != (int)I2S_GPIO_UNUSED) { gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio], PIN_FUNC_GPIO); gpio_set_direction(gpio, GPIO_MODE_INPUT_OUTPUT); esp_rom_gpio_connect_out_signal(gpio, out_sig_idx, 0, 0); @@ -689,9 +733,9 @@ void i2s_gpio_loopback_set(gpio_num_t gpio, uint32_t out_sig_idx, uint32_t in_si } } -esp_err_t i2s_check_set_mclk(i2s_port_t id, gpio_num_t gpio_num, i2s_clock_src_t clk_src, bool is_invert) +esp_err_t i2s_check_set_mclk(i2s_port_t id, int gpio_num, i2s_clock_src_t clk_src, bool is_invert) { - if (gpio_num == I2S_GPIO_UNUSED) { + if (gpio_num == (int)I2S_GPIO_UNUSED) { return ESP_OK; } #if CONFIG_IDF_TARGET_ESP32 @@ -740,6 +784,7 @@ esp_err_t i2s_new_channel(const i2s_chan_config_t *chan_cfg, i2s_chan_handle_t * I2S_NULL_POINTER_CHECK(TAG, tx_handle || rx_handle); ESP_RETURN_ON_FALSE(chan_cfg->id < SOC_I2S_NUM || chan_cfg->id == I2S_NUM_AUTO, ESP_ERR_INVALID_ARG, TAG, "invalid I2S port id"); ESP_RETURN_ON_FALSE(chan_cfg->dma_desc_num >= 2, ESP_ERR_INVALID_ARG, TAG, "there should be at least 2 DMA buffers"); + ESP_RETURN_ON_FALSE(chan_cfg->intr_priority >= 0 && chan_cfg->intr_priority <= 7, ESP_ERR_INVALID_ARG, TAG, "intr_priority should be within 0~7"); esp_err_t ret = ESP_OK; i2s_controller_t *i2s_obj = NULL; @@ -771,6 +816,7 @@ esp_err_t i2s_new_channel(const i2s_chan_config_t *chan_cfg, i2s_chan_handle_t * ESP_GOTO_ON_ERROR(i2s_register_channel(i2s_obj, I2S_DIR_TX, chan_cfg->dma_desc_num), err, TAG, "register I2S tx channel failed"); i2s_obj->tx_chan->role = chan_cfg->role; + i2s_obj->tx_chan->intr_prio_flags = chan_cfg->intr_priority ? BIT(chan_cfg->intr_priority) : ESP_INTR_FLAG_LOWMED; i2s_obj->tx_chan->dma.auto_clear = chan_cfg->auto_clear; i2s_obj->tx_chan->dma.desc_num = chan_cfg->dma_desc_num; i2s_obj->tx_chan->dma.frame_num = chan_cfg->dma_frame_num; @@ -784,6 +830,7 @@ esp_err_t i2s_new_channel(const i2s_chan_config_t *chan_cfg, i2s_chan_handle_t * ESP_GOTO_ON_ERROR(i2s_register_channel(i2s_obj, I2S_DIR_RX, chan_cfg->dma_desc_num), err, TAG, "register I2S rx channel failed"); i2s_obj->rx_chan->role = chan_cfg->role; + i2s_obj->rx_chan->intr_prio_flags = chan_cfg->intr_priority ? BIT(chan_cfg->intr_priority) : ESP_INTR_FLAG_LOWMED; i2s_obj->rx_chan->dma.desc_num = chan_cfg->dma_desc_num; i2s_obj->rx_chan->dma.frame_num = chan_cfg->dma_frame_num; i2s_obj->rx_chan->start = i2s_rx_channel_start; @@ -821,10 +868,12 @@ esp_err_t i2s_del_channel(i2s_chan_handle_t handle) bool is_bound = true; #if SOC_I2S_HW_VERSION_2 - if (dir == I2S_DIR_TX) { - i2s_ll_tx_disable_clock(handle->controller->hal.dev); - } else { - i2s_ll_rx_disable_clock(handle->controller->hal.dev); + I2S_CLOCK_SRC_ATOMIC() { + if (dir == I2S_DIR_TX) { + i2s_ll_tx_disable_clock(handle->controller->hal.dev); + } else { + i2s_ll_rx_disable_clock(handle->controller->hal.dev); + } } #endif #if SOC_I2S_SUPPORTS_APLL @@ -978,6 +1027,7 @@ esp_err_t i2s_channel_disable(i2s_chan_handle_t handle) xSemaphoreTake(handle->binary, portMAX_DELAY); /* Reset the descriptor pointer */ handle->dma.curr_ptr = NULL; + handle->dma.curr_desc = NULL; handle->dma.rw_pos = 0; handle->stop(handle); #if CONFIG_PM_ENABLE @@ -1005,11 +1055,11 @@ esp_err_t i2s_channel_preload_data(i2s_chan_handle_t tx_handle, const void *src, xSemaphoreTake(tx_handle->mutex, portMAX_DELAY); /* The pre-load data will be loaded from the first descriptor */ - if (tx_handle->dma.curr_ptr == NULL) { - tx_handle->dma.curr_ptr = tx_handle->dma.desc[0]; + if (tx_handle->dma.curr_desc == NULL) { + tx_handle->dma.curr_desc = tx_handle->dma.desc[0]; + tx_handle->dma.curr_ptr = (void *)tx_handle->dma.desc[0]->buf; tx_handle->dma.rw_pos = 0; } - lldesc_t *desc_ptr = (lldesc_t *)tx_handle->dma.curr_ptr; /* Loop until no bytes in source buff remain or the descriptors are full */ while (remain_bytes) { @@ -1020,7 +1070,10 @@ esp_err_t i2s_channel_preload_data(i2s_chan_handle_t tx_handle, const void *src, break; } /* Load the data from the last loaded position */ - memcpy((uint8_t *)(desc_ptr->buf + tx_handle->dma.rw_pos), data_ptr, bytes_can_load); + memcpy((uint8_t *)(tx_handle->dma.curr_ptr + tx_handle->dma.rw_pos), data_ptr, bytes_can_load); +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE + esp_cache_msync(tx_handle->dma.curr_ptr + tx_handle->dma.rw_pos, bytes_can_load, ESP_CACHE_MSYNC_FLAG_DIR_C2M); +#endif data_ptr += bytes_can_load; // Move forward the data pointer total_loaded_bytes += bytes_can_load; // Add to the total loaded bytes remain_bytes -= bytes_can_load; // Update the remaining bytes to be loaded @@ -1030,9 +1083,9 @@ esp_err_t i2s_channel_preload_data(i2s_chan_handle_t tx_handle, const void *src, /* If the next descriptor is not the first descriptor, keep load to the first descriptor * otherwise all descriptor has been loaded, break directly, the dma buffer position * will remain at the end of the last dma buffer */ - if (STAILQ_NEXT(desc_ptr, qe) != tx_handle->dma.desc[0]) { - desc_ptr = STAILQ_NEXT(desc_ptr, qe); - tx_handle->dma.curr_ptr = (void *)desc_ptr; + if (STAILQ_NEXT((lldesc_t *)tx_handle->dma.curr_desc, qe) != tx_handle->dma.desc[0]) { + tx_handle->dma.curr_desc = STAILQ_NEXT((lldesc_t *)tx_handle->dma.curr_desc, qe); + tx_handle->dma.curr_ptr = (void *)(((lldesc_t *)tx_handle->dma.curr_desc)->buf); tx_handle->dma.rw_pos = 0; } else { break; @@ -1077,6 +1130,9 @@ esp_err_t i2s_channel_write(i2s_chan_handle_t handle, const void *src, size_t si bytes_can_write = size; } memcpy(data_ptr, src_byte, bytes_can_write); +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE + esp_cache_msync(data_ptr, bytes_can_write, ESP_CACHE_MSYNC_FLAG_DIR_C2M); +#endif size -= bytes_can_write; src_byte += bytes_can_write; handle->dma.rw_pos += bytes_can_write; @@ -1131,55 +1187,24 @@ esp_err_t i2s_channel_read(i2s_chan_handle_t handle, void *dest, size_t size, si return ret; } -/*--------------------------------------------------------------------------- - I2S Platform APIs - ---------------------------------------------------------------------------- - Scope: This file and ADC/DAC/LCD driver - ----------------------------------------------------------------------------*/ - -esp_err_t i2s_platform_acquire_occupation(int id, const char *comp_name) +#if SOC_I2S_SUPPORTS_TX_SYNC_CNT +uint32_t i2s_sync_get_bclk_count(i2s_chan_handle_t tx_handle) { - esp_err_t ret = ESP_OK; - const char *occupied_comp = NULL; - ESP_RETURN_ON_FALSE(id < SOC_I2S_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid i2s port id"); - portENTER_CRITICAL(&g_i2s.spinlock); - if ((!g_i2s.controller[id]) && (g_i2s.comp_name[id] == NULL)) { - g_i2s.comp_name[id] = comp_name; - /* Enable module clock */ - periph_module_enable(i2s_periph_signal[id].module); - i2s_ll_enable_clock(I2S_LL_GET_HW(id)); - } else { - occupied_comp = g_i2s.comp_name[id]; - ret = ESP_ERR_NOT_FOUND; - } - portEXIT_CRITICAL(&g_i2s.spinlock); - if (occupied_comp != NULL) { - ESP_LOGW(TAG, "i2s controller %d has been occupied by %s", id, occupied_comp); - } - return ret; + return i2s_ll_tx_get_bclk_sync_count(tx_handle->controller->hal.dev); } -esp_err_t i2s_platform_release_occupation(int id) +uint32_t i2s_sync_get_fifo_count(i2s_chan_handle_t tx_handle) { - esp_err_t ret = ESP_OK; - ESP_RETURN_ON_FALSE(id < SOC_I2S_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid i2s port id"); - portENTER_CRITICAL(&g_i2s.spinlock); - if (!g_i2s.controller[id]) { - g_i2s.comp_name[id] = NULL; - /* Disable module clock */ - periph_module_disable(i2s_periph_signal[id].module); - i2s_ll_disable_clock(I2S_LL_GET_HW(id)); - } else { - ret = ESP_ERR_INVALID_STATE; - } - portEXIT_CRITICAL(&g_i2s.spinlock); - return ret; + return i2s_ll_tx_get_fifo_sync_count(tx_handle->controller->hal.dev); } -// Only used in `test_i2s_iram.c` to write DMA buffer directly -size_t inline i2s_platform_get_dma_buffer_offset(void) +void i2s_sync_reset_bclk_count(i2s_chan_handle_t tx_handle) { - /* Force to transfer address '0' into 'i2s_chan_handle_t' type, - * then find the corresponding field , the address of this field is the offset of this type */ - return (size_t)&(((i2s_chan_handle_t)0)->dma.bufs); + i2s_ll_tx_reset_bclk_sync_counter(tx_handle->controller->hal.dev); } + +void i2s_sync_reset_fifo_count(i2s_chan_handle_t tx_handle) +{ + i2s_ll_tx_reset_fifo_sync_counter(tx_handle->controller->hal.dev); +} +#endif // SOC_I2S_SUPPORTS_TX_SYNC_CNT diff --git a/components/driver/i2s/i2s_pdm.c b/components/driver/i2s/i2s_pdm.c index 7991f6e969..574247c0c8 100644 --- a/components/driver/i2s/i2s_pdm.c +++ b/components/driver/i2s/i2s_pdm.c @@ -70,7 +70,9 @@ static esp_err_t i2s_pdm_tx_set_clock(i2s_chan_handle_t handle, const i2s_pdm_tx portENTER_CRITICAL(&g_i2s.spinlock); /* Set clock configurations in HAL*/ - i2s_hal_set_tx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src); + I2S_CLOCK_SRC_ATOMIC() { + i2s_hal_set_tx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src); + } #if SOC_I2S_HW_VERSION_2 /* 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 */ @@ -187,10 +189,7 @@ esp_err_t i2s_channel_init_pdm_tx_mode(i2s_chan_handle_t handle, const i2s_pdm_t ESP_GOTO_ON_ERROR(i2s_init_dma_intr(handle, I2S_INTR_ALLOC_FLAGS), err, TAG, "initialize dma interrupt failed"); i2s_ll_tx_enable_pdm(handle->controller->hal.dev); -#if SOC_I2S_HW_VERSION_2 - /* Enable clock to start outputting mclk signal. Some codecs will reset once mclk stop */ - i2s_ll_tx_enable_clock(handle->controller->hal.dev); -#endif + #ifdef CONFIG_PM_ENABLE esp_pm_lock_type_t pm_type = ESP_PM_APB_FREQ_MAX; #if SOC_I2S_SUPPORTS_APLL @@ -357,7 +356,9 @@ static esp_err_t i2s_pdm_rx_set_clock(i2s_chan_handle_t handle, const i2s_pdm_rx portENTER_CRITICAL(&g_i2s.spinlock); /* Set clock configurations in HAL*/ - i2s_hal_set_rx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src); + I2S_CLOCK_SRC_ATOMIC() { + i2s_hal_set_rx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src); + } portEXIT_CRITICAL(&g_i2s.spinlock); /* Update the mode info: clock configuration */ @@ -467,10 +468,7 @@ esp_err_t i2s_channel_init_pdm_rx_mode(i2s_chan_handle_t handle, const i2s_pdm_r ESP_GOTO_ON_ERROR(i2s_init_dma_intr(handle, I2S_INTR_ALLOC_FLAGS), err, TAG, "initialize dma interrupt failed"); i2s_ll_rx_enable_pdm(handle->controller->hal.dev); -#if SOC_I2S_HW_VERSION_2 - /* Enable clock to start outputting mclk signal. Some codecs will reset once mclk stop */ - i2s_ll_rx_enable_clock(handle->controller->hal.dev); -#endif + #ifdef CONFIG_PM_ENABLE esp_pm_lock_type_t pm_type = ESP_PM_APB_FREQ_MAX; #if SOC_I2S_SUPPORTS_APLL diff --git a/components/driver/i2s/i2s_platform.c b/components/driver/i2s/i2s_platform.c new file mode 100644 index 0000000000..39d9e87cc2 --- /dev/null +++ b/components/driver/i2s/i2s_platform.c @@ -0,0 +1,78 @@ +/* + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_check.h" +#include "i2s_private.h" + +static const char *TAG = "i2s_platform"; + +/** + * @brief Global i2s platform object + * @note For saving all the I2S related information + */ +i2s_platform_t g_i2s = { + .spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED, + .controller[0 ... (SOC_I2S_NUM - 1)] = NULL, // groups will be lazy installed + .comp_name[0 ... (SOC_I2S_NUM - 1)] = NULL, +}; + +/*--------------------------------------------------------------------------- + I2S Platform APIs + ---------------------------------------------------------------------------- + Scope: This file and ADC/DAC/LCD driver + ----------------------------------------------------------------------------*/ + +esp_err_t i2s_platform_acquire_occupation(int id, const char *comp_name) +{ + esp_err_t ret = ESP_OK; + const char *occupied_comp = NULL; + ESP_RETURN_ON_FALSE(id < SOC_I2S_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid i2s port id"); + portENTER_CRITICAL(&g_i2s.spinlock); + if ((!g_i2s.controller[id]) && (g_i2s.comp_name[id] == NULL)) { + g_i2s.comp_name[id] = comp_name; + /* Enable module clock */ + I2S_RCC_ATOMIC() { + i2s_ll_enable_bus_clock(id, true); + i2s_ll_reset_register(id); + i2s_ll_enable_core_clock(I2S_LL_GET_HW(id), true); + } + } else { + occupied_comp = g_i2s.comp_name[id]; + ret = ESP_ERR_NOT_FOUND; + } + portEXIT_CRITICAL(&g_i2s.spinlock); + if (occupied_comp != NULL) { + ESP_LOGW(TAG, "i2s controller %d has been occupied by %s", id, occupied_comp); + } + return ret; +} + +esp_err_t i2s_platform_release_occupation(int id) +{ + esp_err_t ret = ESP_OK; + ESP_RETURN_ON_FALSE(id < SOC_I2S_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid i2s port id"); + portENTER_CRITICAL(&g_i2s.spinlock); + if (!g_i2s.controller[id]) { + g_i2s.comp_name[id] = NULL; + /* Disable module clock */ + I2S_RCC_ATOMIC() { + i2s_ll_enable_bus_clock(id, false); + i2s_ll_enable_core_clock(I2S_LL_GET_HW(id), false); + } + } else { + ret = ESP_ERR_INVALID_STATE; + } + portEXIT_CRITICAL(&g_i2s.spinlock); + return ret; +} + +// Only used in `test_i2s_iram.c` to write DMA buffer directly +size_t i2s_platform_get_dma_buffer_offset(void) +{ + /* Force to transfer address '0' into 'i2s_chan_handle_t' type, + * then find the corresponding field , the address of this field is the offset of this type */ + return (size_t)&(((i2s_chan_handle_t)0)->dma.bufs); +} diff --git a/components/driver/i2s/i2s_private.h b/components/driver/i2s/i2s_private.h index 23dfe79f5f..9405062ca5 100644 --- a/components/driver/i2s/i2s_private.h +++ b/components/driver/i2s/i2s_private.h @@ -9,15 +9,17 @@ #include "freertos/FreeRTOS.h" #include "soc/lldesc.h" #include "soc/soc_caps.h" -#include "hal/i2s_types.h" +#include "hal/i2s_hal.h" #include "driver/i2s_types.h" #include "freertos/semphr.h" #include "freertos/queue.h" #if SOC_GDMA_SUPPORTED #include "esp_private/gdma.h" #endif +#include "esp_private/periph_ctrl.h" #include "esp_pm.h" #include "esp_err.h" +#include "sdkconfig.h" #ifdef __cplusplus extern "C" { @@ -26,14 +28,26 @@ extern "C" { // If ISR handler is allowed to run whilst cache is disabled, // Make sure all the code and related variables used by the handler are in the SRAM #if CONFIG_I2S_ISR_IRAM_SAFE -#define I2S_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_LOWMED) +#define I2S_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_SHARED) #define I2S_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) #else -#define I2S_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_LOWMED) +#define I2S_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_SHARED) #define I2S_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT #endif //CONFIG_I2S_ISR_IRAM_SAFE #define I2S_DMA_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA) +#if SOC_PERIPH_CLK_CTRL_SHARED +#define I2S_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC() +#else +#define I2S_CLOCK_SRC_ATOMIC() +#endif + +#if !SOC_RCC_IS_INDEPENDENT +#define I2S_RCC_ATOMIC() PERIPH_RCC_ATOMIC() +#else +#define I2S_RCC_ATOMIC() +#endif + #define I2S_NULL_POINTER_CHECK(tag, p) ESP_RETURN_ON_FALSE((p), ESP_ERR_INVALID_ARG, tag, "input parameter '"#p"' is NULL") /** @@ -45,6 +59,28 @@ typedef enum { I2S_CHAN_STATE_RUNNING, /*!< i2s channel is idling (initialized and enabled) */ } i2s_state_t; +/** + * @brief Group of I2S callbacks + * @note The callbacks are all running under ISR environment + * @note When CONFIG_I2S_ISR_IRAM_SAFE is enabled, the callback itself and functions called by it should be placed in IRAM. + * The variables used in the function should be in the SRAM as well. + * @note Declare the internal type to remove the dependency of `i2s_common.h` + */ +typedef struct { + i2s_isr_callback_t on_recv; /**< Callback of data received event, only for rx channel + * The event data includes DMA buffer address and size that just finished receiving data + */ + i2s_isr_callback_t on_recv_q_ovf; /**< Callback of receiving queue overflowed event, only for rx channel + * The event data includes buffer size that has been overwritten + */ + i2s_isr_callback_t on_sent; /**< Callback of data sent event, only for tx channel + * The event data includes DMA buffer address and size that just finished sending data + */ + i2s_isr_callback_t on_send_q_ovf; /**< Callback of sending queue overflowed event, only for tx channel + * The event data includes buffer size that has been overwritten + */ +} i2s_event_callbacks_internal_t; + /** * @brief i2s channel level configurations * @note It performs as channel handle @@ -61,6 +97,7 @@ typedef struct { bool auto_clear; /*!< Set to auto clear DMA TX descriptor, i2s will always send zero automatically if no data to send */ uint32_t rw_pos; /*!< reading/writing pointer position */ void *curr_ptr; /*!< Pointer to current dma buffer */ + void *curr_desc; /*!< Pointer to current dma descriptor used for pre-load */ lldesc_t **desc; /*!< dma descriptor array */ uint8_t **bufs; /*!< dma buffer array */ } i2s_dma_t; @@ -88,6 +125,7 @@ struct i2s_channel_obj_t { i2s_dma_t dma; /*!< i2s dma object */ i2s_state_t state; /*!< i2s driver state. Ensuring the driver working in a correct sequence */ /* Stored configurations */ + int intr_prio_flags;/*!< i2s interrupt priority flags */ void *mode_info; /*!< Slot, clock and gpio information of each mode */ #if SOC_I2S_SUPPORTS_APLL bool apll_en; /*!< Flag of wether APLL enabled */ @@ -101,7 +139,7 @@ struct i2s_channel_obj_t { esp_pm_lock_handle_t pm_lock; /*!< Power management lock, to avoid apb clock frequency changes while i2s is working */ #endif QueueHandle_t msg_queue; /*!< Message queue handler, used for transporting data between interrupt and read/write task */ - i2s_event_callbacks_t callbacks; /*!< Callback functions */ + i2s_event_callbacks_internal_t callbacks; /*!< Callback functions */ void *user_data; /*!< User data for callback functions */ void (*start)(i2s_chan_handle_t); /*!< start tx/rx channel */ void (*stop)(i2s_chan_handle_t); /*!< stop tx/rx channel */ @@ -117,7 +155,7 @@ typedef struct { const char *comp_name[SOC_I2S_NUM]; /*!< The component name that occupied i2s controller */ } i2s_platform_t; -extern i2s_platform_t g_i2s; +extern i2s_platform_t g_i2s; /*!< Global i2s instance for driver internal use */ /** * @brief Initialize I2S DMA interrupt @@ -184,7 +222,7 @@ uint32_t i2s_get_source_clk_freq(i2s_clock_src_t clk_src, uint32_t mclk_freq_hz) * @param is_input Is input gpio * @param is_invert Is invert gpio */ -void i2s_gpio_check_and_set(gpio_num_t gpio, uint32_t signal_idx, bool is_input, bool is_invert); +void i2s_gpio_check_and_set(int gpio, uint32_t signal_idx, bool is_input, bool is_invert); /** * @brief Check gpio validity and output mclk signal @@ -197,7 +235,7 @@ void i2s_gpio_check_and_set(gpio_num_t gpio, uint32_t signal_idx, bool is_input, * - ESP_OK Set mclk output gpio success * - ESP_ERR_INVALID_ARG Invalid GPIO number */ -esp_err_t i2s_check_set_mclk(i2s_port_t id, gpio_num_t gpio_num, i2s_clock_src_t clk_src, bool is_invert); +esp_err_t i2s_check_set_mclk(i2s_port_t id, int gpio_num, i2s_clock_src_t clk_src, bool is_invert); /** * @brief Attach data out signal and data in signal to a same gpio @@ -206,7 +244,7 @@ esp_err_t i2s_check_set_mclk(i2s_port_t id, gpio_num_t gpio_num, i2s_clock_src_t * @param out_sig_idx Data out signal index * @param in_sig_idx Data in signal index */ -void i2s_gpio_loopback_set(gpio_num_t gpio, uint32_t out_sig_idx, uint32_t in_sig_idx); +void i2s_gpio_loopback_set(int gpio, uint32_t out_sig_idx, uint32_t in_sig_idx); #ifdef __cplusplus } diff --git a/components/driver/i2s/i2s_std.c b/components/driver/i2s/i2s_std.c index 2570e3b4b2..715ca04399 100644 --- a/components/driver/i2s/i2s_std.c +++ b/components/driver/i2s/i2s_std.c @@ -77,10 +77,12 @@ static esp_err_t i2s_std_set_clock(i2s_chan_handle_t handle, const i2s_std_clk_c portENTER_CRITICAL(&g_i2s.spinlock); /* Set clock configurations in HAL*/ - if (handle->dir == I2S_DIR_TX) { - i2s_hal_set_tx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src); - } else { - i2s_hal_set_rx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src); + I2S_CLOCK_SRC_ATOMIC() { + if (handle->dir == I2S_DIR_TX) { + i2s_hal_set_tx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src); + } else { + i2s_hal_set_rx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src); + } } portEXIT_CRITICAL(&g_i2s.spinlock); @@ -226,10 +228,8 @@ esp_err_t i2s_channel_init_std_mode(i2s_chan_handle_t handle, const i2s_std_conf /* Enable clock to start outputting mclk signal. Some codecs will reset once mclk stop */ if (handle->dir == I2S_DIR_TX) { i2s_ll_tx_enable_std(handle->controller->hal.dev); - i2s_ll_tx_enable_clock(handle->controller->hal.dev); } else { i2s_ll_rx_enable_std(handle->controller->hal.dev); - i2s_ll_rx_enable_clock(handle->controller->hal.dev); } #endif diff --git a/components/driver/i2s/i2s_tdm.c b/components/driver/i2s/i2s_tdm.c index 5484881dd9..caed5c51a4 100644 --- a/components/driver/i2s/i2s_tdm.c +++ b/components/driver/i2s/i2s_tdm.c @@ -79,10 +79,12 @@ static esp_err_t i2s_tdm_set_clock(i2s_chan_handle_t handle, const i2s_tdm_clk_c portENTER_CRITICAL(&g_i2s.spinlock); /* Set clock configurations in HAL*/ - if (handle->dir == I2S_DIR_TX) { - i2s_hal_set_tx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src); - } else { - i2s_hal_set_rx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src); + I2S_CLOCK_SRC_ATOMIC() { + if (handle->dir == I2S_DIR_TX) { + i2s_hal_set_tx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src); + } else { + i2s_hal_set_rx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src); + } } portEXIT_CRITICAL(&g_i2s.spinlock); @@ -232,10 +234,8 @@ esp_err_t i2s_channel_init_tdm_mode(i2s_chan_handle_t handle, const i2s_tdm_conf /* Enable clock to start outputting mclk signal. Some codecs will reset once mclk stop */ if (handle->dir == I2S_DIR_TX) { i2s_ll_tx_enable_tdm(handle->controller->hal.dev); - i2s_ll_tx_enable_clock(handle->controller->hal.dev); } else { i2s_ll_rx_enable_tdm(handle->controller->hal.dev); - i2s_ll_rx_enable_clock(handle->controller->hal.dev); } #endif #ifdef CONFIG_PM_ENABLE @@ -275,12 +275,12 @@ esp_err_t i2s_channel_reconfig_tdm_clock(i2s_chan_handle_t handle, const i2s_tdm #if SOC_I2S_SUPPORTS_APLL /* Enable APLL and acquire its lock when the clock source is changed to APLL */ - if (clk_cfg->clk_src == I2S_CLK_SRC_APLL && clk_cfg->clk_cfg.clk_src != I2S_CLK_SRC_APLL) { + if (clk_cfg->clk_src == I2S_CLK_SRC_APLL && tdm_cfg->clk_cfg.clk_src != I2S_CLK_SRC_APLL) { periph_rtc_apll_acquire(); handle->apll_en = true; } /* Disable APLL and release its lock when clock source is changed to 160M_PLL */ - if (clk_cfg->clk_src != I2S_CLK_SRC_APLL && clk_cfg->clk_cfg.clk_src == I2S_CLK_SRC_APLL) { + if (clk_cfg->clk_src != I2S_CLK_SRC_APLL && tdm_cfg->clk_cfg.clk_src == I2S_CLK_SRC_APLL) { periph_rtc_apll_release(); handle->apll_en = false; } diff --git a/components/driver/i2s/include/driver/i2s_common.h b/components/driver/i2s/include/driver/i2s_common.h index 819ab0d23f..0b6dc30331 100644 --- a/components/driver/i2s/include/driver/i2s_common.h +++ b/components/driver/i2s/include/driver/i2s_common.h @@ -25,6 +25,7 @@ extern "C" { .dma_desc_num = 6, \ .dma_frame_num = 240, \ .auto_clear = false, \ + .intr_priority = 0, \ } #define I2S_GPIO_UNUSED GPIO_NUM_NC /*!< Used in i2s_gpio_config_t for signals which are not used */ @@ -63,6 +64,7 @@ typedef struct { * it should be the multiple of '3' when the data bit width is 24. */ bool auto_clear; /*!< Set to auto clear DMA TX buffer, i2s will always send zero automatically if no data to send */ + int intr_priority; /*!< I2S interrupt priority, range [0, 7], if set to 0, the driver will try to allocate an interrupt with a relative low priority (1,2,3) */ } i2s_chan_config_t; /** diff --git a/components/driver/i2s/include/driver/i2s_pdm.h b/components/driver/i2s/include/driver/i2s_pdm.h index 2265c7908a..f697c2371b 100644 --- a/components/driver/i2s/include/driver/i2s_pdm.h +++ b/components/driver/i2s/include/driver/i2s_pdm.h @@ -23,6 +23,23 @@ extern "C" { #if SOC_I2S_SUPPORTS_PDM_RX +#if SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER +/** + * @brief PDM format in 2 slots(RX) + * @param bits_per_sample i2s data bit width, only support 16 bits for PDM mode + * @param mono_or_stereo I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO + */ +#define I2S_PDM_RX_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) { \ + .data_bit_width = bits_per_sample, \ + .slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO, \ + .slot_mode = mono_or_stereo, \ + .slot_mask = (mono_or_stereo == I2S_SLOT_MODE_MONO) ? \ + I2S_PDM_SLOT_LEFT : I2S_PDM_SLOT_BOTH, \ + .hp_en = true, \ + .hp_cut_off_freq_hz = 35.5, \ + .amplify_num = 1, \ +} +#else /** * @brief PDM format in 2 slots(RX) * @param bits_per_sample i2s data bit width, only support 16 bits for PDM mode @@ -35,6 +52,7 @@ extern "C" { .slot_mask = (mono_or_stereo == I2S_SLOT_MODE_MONO) ? \ I2S_PDM_SLOT_LEFT : I2S_PDM_SLOT_BOTH, \ } +#endif // SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER /** * @brief i2s default pdm rx clock configuration @@ -48,6 +66,8 @@ extern "C" { .bclk_div = 8, \ } + + /** * @brief I2S slot configuration for pdm rx mode */ @@ -58,6 +78,15 @@ typedef struct { i2s_slot_mode_t slot_mode; /*!< Set mono or stereo mode with I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO */ /* Particular fields */ i2s_pdm_slot_mask_t slot_mask; /*!< Choose the slots to activate */ +#if SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER + bool hp_en; /*!< High pass filter enable */ + float hp_cut_off_freq_hz; /*!< High pass filter cut-off frequency, range 23.3Hz ~ 185Hz, see cut-off frequency sheet above */ + uint32_t amplify_num; /*!< The amplification number of the final conversion result. + * The data that have converted from PDM to PCM module, will time 'amplify_num' additionally to amplify the final result. + * Note that it's only a multiplier of the digital PCM data, not the gain of the analog signal + * range 1~15, default 1 */ +#endif // SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER + } i2s_pdm_rx_slot_config_t; /** diff --git a/components/driver/include/esp_private/i2s_sync.h b/components/driver/include/esp_private/i2s_sync.h new file mode 100644 index 0000000000..83c4190397 --- /dev/null +++ b/components/driver/include/esp_private/i2s_sync.h @@ -0,0 +1,71 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +// DO NOT USE THESE APIS IN YOUR APPLICATIONS +// The following APIs are for internal use, public to other IDF components, but not for users' applications. + +/** + * This file is used for getting the bclk and fifo sending count + * for the synchronization among different I2S ports. + * + * The APIs in this file might be called frequently, so they are made light-weight and flexible to be called + * + * NOTE: These APIs are private for ESP internal usages. + * Please be aware of the risk that APIs might be changed regarding the use case. + */ + +#pragma once + +#include +#include "driver/i2s_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if SOC_I2S_SUPPORTS_TX_SYNC_CNT + +/** + * @brief Get the counter number of BCLK ticks + * @note The BCLK tick count reflects the real data that have sent on line + * + * @param[in] tx_handle The I2S tx channel handle + * @return + * - BCLK tick count + */ +uint32_t i2s_sync_get_bclk_count(i2s_chan_handle_t tx_handle); + +/** + * @brief Get the counter number of fifo + * @note The FIFO count reflects how many slots have processed + * Normally, fifo_cnt = slot_bit_width * bclk_cnt + * If fifo_cnt < slot_bit_width * bclk_cnt, that means some data are still stuck in the I2S controller + * + * @param[in] tx_handle The I2S tx channel handle + * @return + * - FIFO slot count + */ +uint32_t i2s_sync_get_fifo_count(i2s_chan_handle_t tx_handle); + +/** + * @brief Reset the bclk counter + * + * @param[in] tx_handle The I2S tx channel handle + */ +void i2s_sync_reset_bclk_count(i2s_chan_handle_t tx_handle); + +/** + * @brief Reset the fifo counter + * + * @param[in] tx_handle The I2S tx channel handle + */ +void i2s_sync_reset_fifo_count(i2s_chan_handle_t tx_handle); + +#endif // SOC_I2S_SUPPORTS_TX_SYNC_CNT + +#ifdef __cplusplus +} +#endif diff --git a/components/driver/test_apps/.build-test-rules.yml b/components/driver/test_apps/.build-test-rules.yml index f69afb0d59..b1fd554b0c 100644 --- a/components/driver/test_apps/.build-test-rules.yml +++ b/components/driver/test_apps/.build-test-rules.yml @@ -33,15 +33,27 @@ components/driver/test_apps/i2c_test_apps: components/driver/test_apps/i2s_test_apps: disable: - if: SOC_I2S_SUPPORTED != 1 + disable_test: + - if: IDF_TARGET == "esp32p4" + temporary: true + reason: lack of runners components/driver/test_apps/i2s_test_apps/i2s: disable: - if: SOC_I2S_SUPPORTED != 1 + disable_test: + - if: IDF_TARGET == "esp32p4" + temporary: true + reason: lack of runners components/driver/test_apps/i2s_test_apps/i2s_multi_dev: disable: - if: SOC_I2S_SUPPORTED != 1 - if: SOC_I2S_HW_VERSION_2 != 1 + disable_test: + - if: IDF_TARGET == "esp32p4" + temporary: true + reason: lack of runners components/driver/test_apps/i2s_test_apps/legacy_i2s_adc_dac: disable: @@ -50,6 +62,10 @@ components/driver/test_apps/i2s_test_apps/legacy_i2s_adc_dac: components/driver/test_apps/i2s_test_apps/legacy_i2s_driver: disable: - if: SOC_I2S_SUPPORTED != 1 + disable_test: + - if: IDF_TARGET == "esp32p4" + temporary: true + reason: lack of runners components/driver/test_apps/ledc: disable: diff --git a/components/driver/test_apps/i2s_test_apps/i2s/README.md b/components/driver/test_apps/i2s_test_apps/i2s/README.md index 19f1d19a54..a79fcf4c5e 100644 --- a/components/driver/test_apps/i2s_test_apps/i2s/README.md +++ b/components/driver/test_apps/i2s_test_apps/i2s/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | diff --git a/components/driver/test_apps/i2s_test_apps/i2s/main/test_i2s.c b/components/driver/test_apps/i2s_test_apps/i2s/main/test_i2s.c index e9e81cde62..0cbe69b6ff 100644 --- a/components/driver/test_apps/i2s_test_apps/i2s/main/test_i2s.c +++ b/components/driver/test_apps/i2s_test_apps/i2s/main/test_i2s.c @@ -11,6 +11,7 @@ #include "freertos/task.h" #include "freertos/queue.h" #include "freertos/semphr.h" +#include "sdkconfig.h" #include "driver/gpio.h" #include "hal/gpio_hal.h" #include "esp_err.h" @@ -775,7 +776,7 @@ static void i2s_test_common_sample_rate(i2s_chan_handle_t rx_chan, i2s_std_clk_c // pcnt will count the pulse number on WS signal in 100ms TEST_ESP_OK(pcnt_unit_clear_count(pcnt_unit)); TEST_ESP_OK(pcnt_unit_start(pcnt_unit)); - vTaskDelay(pdMS_TO_TICKS(TEST_I2S_PERIOD_MS)); + esp_rom_delay_us(100 * 1000); TEST_ESP_OK(pcnt_unit_stop(pcnt_unit)); TEST_ESP_OK(pcnt_unit_get_count(pcnt_unit, &real_pulse)); printf("[%"PRIu32" Hz] %d pulses, expected %d, err %d\n", test_freq[i], real_pulse, expt_pulse, real_pulse - expt_pulse); @@ -803,7 +804,10 @@ TEST_CASE("I2S_default_PLL_clock_test", "[i2s]") TEST_ESP_OK(i2s_new_channel(&chan_cfg, NULL, &rx_handle)); TEST_ESP_OK(i2s_channel_init_std_mode(rx_handle, &std_cfg)); +// ESP32-P4 has no PLL except XTAL +#if !CONFIG_IDF_TARGET_ESP32P4 i2s_test_common_sample_rate(rx_handle, &std_cfg.clk_cfg); +#endif // CONFIG_IDF_TARGET_ESP32P4 #if SOC_I2S_SUPPORTS_XTAL std_cfg.clk_cfg.clk_src = I2S_CLK_SRC_XTAL; i2s_test_common_sample_rate(rx_handle, &std_cfg.clk_cfg); @@ -880,7 +884,6 @@ TEST_CASE("I2S_package_lost_test", "[i2s]") for (i = 0; i < test_num; i++) { printf("Testing %"PRIu32" Hz sample rate\n", test_freq[i]); std_cfg.clk_cfg.sample_rate_hz = test_freq[i]; - std_cfg.clk_cfg.sample_rate_hz = test_freq[i]; TEST_ESP_OK(i2s_channel_reconfig_std_clock(rx_handle, &std_cfg.clk_cfg)); TEST_ESP_OK(i2s_channel_enable(rx_handle)); for (int j = 0; j < 10; j++) { diff --git a/components/driver/test_apps/i2s_test_apps/i2s/main/test_i2s_iram.c b/components/driver/test_apps/i2s_test_apps/i2s/main/test_i2s_iram.c index 518dcf4b87..021f4f30eb 100644 --- a/components/driver/test_apps/i2s_test_apps/i2s/main/test_i2s_iram.c +++ b/components/driver/test_apps/i2s_test_apps/i2s/main/test_i2s_iram.c @@ -13,6 +13,9 @@ #include "driver/i2s_std.h" #include "esp_attr.h" #include "soc/soc_caps.h" +#if CONFIG_IDF_TARGET_ESP32P4 +#include "rom/cache.h" +#endif #include "esp_private/i2s_platform.h" #include "esp_private/spi_flash_os.h" #include "../../test_inc/test_i2s.h" @@ -39,9 +42,13 @@ static void IRAM_ATTR test_i2s_iram_write(i2s_chan_handle_t tx_handle) // disable cache and non-iram ISR handlers spi_flash_guard_get()->start(); // write data into dma buffer directly, the data in dma buffer will be sent automatically - for (int i=0; i < 100; i++) { - dma_bufs[0][i] = i + 1; + for (int i = 0; i < 400; i++) { + dma_bufs[0][i] = i % 100 + 1; } +#if CONFIG_IDF_TARGET_ESP32P4 + // TODO: need to consider PSRAM if I2S driver supports EDMA + Cache_WriteBack_Addr(CACHE_MAP_L1_DCACHE, (uint32_t)dma_bufs[0], 400); +#endif // enable cache and non-iram ISR handlers spi_flash_guard_get()->end(); } @@ -52,8 +59,8 @@ TEST_CASE("i2s_iram_interrupt_safe", "[i2s]") i2s_chan_handle_t rx_chan = NULL; i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER); - chan_cfg.dma_desc_num = 6; - chan_cfg.dma_frame_num = 200; + chan_cfg.dma_desc_num = 2; + chan_cfg.dma_frame_num = 100; TEST_ESP_OK(i2s_new_channel(&chan_cfg, &tx_chan, &rx_chan)); i2s_std_config_t std_cfg = { .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(16000), @@ -73,14 +80,14 @@ TEST_CASE("i2s_iram_interrupt_safe", "[i2s]") }; TEST_ESP_OK(i2s_channel_init_std_mode(tx_chan, &std_cfg)); TEST_ESP_OK(i2s_channel_init_std_mode(rx_chan, &std_cfg)); - int is_triggerred = 0; + int is_triggered = 0; i2s_event_callbacks_t cbs = { .on_recv = NULL, .on_recv_q_ovf = NULL, .on_sent = test_i2s_tx_done_callback, .on_send_q_ovf = NULL, }; - TEST_ESP_OK(i2s_channel_register_event_callback(tx_chan, &cbs, &is_triggerred)); + TEST_ESP_OK(i2s_channel_register_event_callback(tx_chan, &cbs, &is_triggered)); TEST_ESP_OK(i2s_channel_enable(tx_chan)); TEST_ESP_OK(i2s_channel_enable(rx_chan)); @@ -92,7 +99,7 @@ TEST_CASE("i2s_iram_interrupt_safe", "[i2s]") for (int retry = 0; retry < 3; retry++) { i2s_channel_read(rx_chan, recv_buf, 2000, &r_bytes, pdMS_TO_TICKS(1000)); for (i = 0; i < 2000 - 100; i++) { - if (recv_buf[i] != 0) { + if (recv_buf[i] == 1 && recv_buf[i + 1] == 2) { goto finish; } } @@ -107,7 +114,7 @@ finish: for (int j = 1; j <= 100; j++) { TEST_ASSERT_EQUAL_UINT8(recv_buf[i++], j); } - TEST_ASSERT(is_triggerred); + TEST_ASSERT(is_triggered); free(recv_buf); } diff --git a/components/driver/test_apps/i2s_test_apps/i2s_multi_dev/README.md b/components/driver/test_apps/i2s_test_apps/i2s_multi_dev/README.md index 541c8b1e9a..bb5058d387 100644 --- a/components/driver/test_apps/i2s_test_apps/i2s_multi_dev/README.md +++ b/components/driver/test_apps/i2s_test_apps/i2s_multi_dev/README.md @@ -1,3 +1,3 @@ -| Supported Targets | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S3 | -| ----------------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S3 | +| ----------------- | -------- | -------- | -------- | -------- | -------- | diff --git a/components/driver/test_apps/i2s_test_apps/legacy_i2s_driver/README.md b/components/driver/test_apps/i2s_test_apps/legacy_i2s_driver/README.md index 19f1d19a54..a79fcf4c5e 100644 --- a/components/driver/test_apps/i2s_test_apps/legacy_i2s_driver/README.md +++ b/components/driver/test_apps/i2s_test_apps/legacy_i2s_driver/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | diff --git a/components/driver/test_apps/i2s_test_apps/test_inc/test_i2s.h b/components/driver/test_apps/i2s_test_apps/test_inc/test_i2s.h index 4c1a3763b5..1adaf4e1fc 100644 --- a/components/driver/test_apps/i2s_test_apps/test_inc/test_i2s.h +++ b/components/driver/test_apps/i2s_test_apps/test_inc/test_i2s.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -44,6 +44,14 @@ extern "C" { #define SLAVE_WS_IO 15 #define DATA_IN_IO 19 #define DATA_OUT_IO 18 +#elif CONFIG_IDF_TARGET_ESP32P4 +#define MASTER_MCK_IO 34 +#define MASTER_BCK_IO 35 +#define MASTER_WS_IO 48 +#define SLAVE_BCK_IO 10 +#define SLAVE_WS_IO 11 +#define DATA_IN_IO 12 +#define DATA_OUT_IO 49 #else #define MASTER_MCK_IO 0 #define MASTER_BCK_IO 4 diff --git a/components/esp_hw_support/include/clk_ctrl_os.h b/components/esp_hw_support/include/clk_ctrl_os.h index 519fddee40..99366497fe 100644 --- a/components/esp_hw_support/include/clk_ctrl_os.h +++ b/components/esp_hw_support/include/clk_ctrl_os.h @@ -54,7 +54,7 @@ void periph_rtc_apll_release(void); * @brief Calculate and set APLL coefficients by given frequency * @note Have to call 'periph_rtc_apll_acquire' to enable APLL power before setting frequency * @note This calculation is based on the inequality: - * xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) >= SOC_APLL_MULTIPLIER_OUT_MIN_HZ(350 MHz) + * xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) >= CLK_LL_APLL_MULTIPLIER_MIN_HZ(350 MHz) * It will always calculate the minimum coefficients that can satisfy the inequality above, instead of loop them one by one. * which means more appropriate coefficients are likely to exist. * But this algorithm can meet almost all the cases and the accuracy can be guaranteed as well. diff --git a/components/esp_hw_support/port/esp32/rtc_clk.c b/components/esp_hw_support/port/esp32/rtc_clk.c index 384964e3d3..1856425f2e 100644 --- a/components/esp_hw_support/port/esp32/rtc_clk.c +++ b/components/esp_hw_support/port/esp32/rtc_clk.c @@ -217,7 +217,7 @@ uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm * i.e. xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) >= 350 MHz, '+1' in the following code is to get the ceil value. * With this condition, as we know the 'o_div' can't be greater than 31, then we can calculate the APLL minimum support frequency is * 350 MHz / ((31 + 2) * 2) = 5303031 Hz (for ceil) */ - o_div = (int)(SOC_APLL_MULTIPLIER_OUT_MIN_HZ / (float)(freq * 2) + 1) - 2; + o_div = (int)(CLK_LL_APLL_MULTIPLIER_MIN_HZ / (float)(freq * 2) + 1) - 2; if (o_div > 31) { ESP_HW_LOGE(TAG, "Expected frequency is too small"); return 0; @@ -227,7 +227,7 @@ uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm * i.e. xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) <= 500 MHz, we need to get the floor value in the following code. * With this condition, as we know the 'o_div' can't be smaller than 0, then we can calculate the APLL maximum support frequency is * 500 MHz / ((0 + 2) * 2) = 125000000 Hz */ - o_div = (int)(SOC_APLL_MULTIPLIER_OUT_MAX_HZ / (float)(freq * 2)) - 2; + o_div = (int)(CLK_LL_APLL_MULTIPLIER_MAX_HZ / (float)(freq * 2)) - 2; if (o_div < 0) { ESP_HW_LOGE(TAG, "Expected frequency is too big"); return 0; diff --git a/components/esp_hw_support/port/esp32p4/rtc_clk.c b/components/esp_hw_support/port/esp32p4/rtc_clk.c index 2abac0e6fb..6c67021a9b 100644 --- a/components/esp_hw_support/port/esp32p4/rtc_clk.c +++ b/components/esp_hw_support/port/esp32p4/rtc_clk.c @@ -368,6 +368,22 @@ uint32_t rtc_clk_apb_freq_get(void) return rtc_clk_ahb_freq_get() / clk_ll_apb_get_divider() * MHZ; } +void rtc_clk_apll_enable(bool enable) +{ + // TODO: IDF-7526 +} + +uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm0, uint32_t *_sdm1, uint32_t *_sdm2) +{ + // TODO: IDF-7526 + return 0; +} + +void rtc_clk_apll_coeff_set(uint32_t o_div, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2) +{ + // TODO: IDF-7526 +} + void rtc_dig_clk8m_enable(void) { clk_ll_rc_fast_digi_enable(); diff --git a/components/esp_hw_support/port/esp32s2/rtc_clk.c b/components/esp_hw_support/port/esp32s2/rtc_clk.c index 8c77c4cd88..75558b8f50 100644 --- a/components/esp_hw_support/port/esp32s2/rtc_clk.c +++ b/components/esp_hw_support/port/esp32s2/rtc_clk.c @@ -119,7 +119,7 @@ uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm * i.e. xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) >= 350 MHz, '+1' in the following code is to get the ceil value. * With this condition, as we know the 'o_div' can't be greater than 31, then we can calculate the APLL minimum support frequency is * 350 MHz / ((31 + 2) * 2) = 5303031 Hz (for ceil) */ - o_div = (int)(SOC_APLL_MULTIPLIER_OUT_MIN_HZ / (float)(freq * 2) + 1) - 2; + o_div = (int)(CLK_LL_APLL_MULTIPLIER_MIN_HZ / (float)(freq * 2) + 1) - 2; if (o_div > 31) { ESP_HW_LOGE(TAG, "Expected frequency is too small"); return 0; @@ -129,7 +129,7 @@ uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm * i.e. xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) <= 500 MHz, we need to get the floor value in the following code. * With this condition, as we know the 'o_div' can't be smaller than 0, then we can calculate the APLL maximum support frequency is * 500 MHz / ((0 + 2) * 2) = 125000000 Hz */ - o_div = (int)(SOC_APLL_MULTIPLIER_OUT_MAX_HZ / (float)(freq * 2)) - 2; + o_div = (int)(CLK_LL_APLL_MULTIPLIER_MAX_HZ / (float)(freq * 2)) - 2; if (o_div < 0) { ESP_HW_LOGE(TAG, "Expected frequency is too big"); return 0; diff --git a/components/hal/esp32/include/hal/clk_tree_ll.h b/components/hal/esp32/include/hal/clk_tree_ll.h index 79ea9fc003..67ae94a51a 100644 --- a/components/hal/esp32/include/hal/clk_tree_ll.h +++ b/components/hal/esp32/include/hal/clk_tree_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -73,6 +73,15 @@ extern "C" { #define CLK_LL_XTAL_32K_BOOTSTRAP_DRES_VAL 3 #define CLK_LL_XTAL_32K_BOOTSTRAP_DBIAS_VAL 0 +/* APLL multiplier output frequency range */ +// apll_multiplier_out = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) +#define CLK_LL_APLL_MULTIPLIER_MIN_HZ (350000000) // 350 MHz +#define CLK_LL_APLL_MULTIPLIER_MAX_HZ (500000000) // 500 MHz + +/* APLL output frequency range */ +#define CLK_LL_APLL_MIN_HZ (5303031) // 5.303031 MHz, refer to 'periph_rtc_apll_freq_set' for the calculation +#define CLK_LL_APLL_MAX_HZ (125000000) // 125MHz, refer to 'periph_rtc_apll_freq_set' for the calculation + /** * @brief XTAL32K_CLK enable modes */ diff --git a/components/hal/esp32/include/hal/i2s_ll.h b/components/hal/esp32/include/hal/i2s_ll.h index 8f621d92e2..a6a7a1b15f 100644 --- a/components/hal/esp32/include/hal/i2s_ll.h +++ b/components/hal/esp32/include/hal/i2s_ll.h @@ -18,6 +18,7 @@ #include "hal/misc.h" #include "soc/i2s_periph.h" #include "soc/i2s_struct.h" +#include "soc/dport_reg.h" #include "hal/i2s_types.h" #include "hal/hal_utils.h" @@ -48,7 +49,7 @@ extern "C" { #define I2S_LL_RX_EVENT_MASK I2S_LL_EVENT_RX_EOF #define I2S_LL_PLL_F160M_CLK_FREQ (160 * 1000000) // PLL_F160M_CLK: 160MHz -#define I2S_LL_DEFAULT_PLL_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT +#define I2S_LL_DEFAULT_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT /** * @brief Enable DMA descriptor owner check @@ -84,30 +85,73 @@ static inline void i2s_ll_dma_enable_eof_on_fifo_empty(i2s_dev_t *hw, bool en) } /** - * @brief I2S module general init, enable I2S clock. + * @brief Enable the bus clock for I2S module * - * @param hw Peripheral I2S hardware instance address. + * @param i2s_id The port id of I2S + * @param enable Set true to enable the buf clock */ -static inline void i2s_ll_enable_clock(i2s_dev_t *hw) +static inline void i2s_ll_enable_bus_clock(int i2s_id, bool enable) { - if (hw->clkm_conf.clk_en == 0) { - hw->clkm_conf.clk_en = 1; - hw->conf2.val = 0; + if (enable) { + if (i2s_id == 0) { + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN); + } else { + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S1_CLK_EN); + } + } else if (i2s_id == 1) { + if (i2s_id == 0) { + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN); + } else { + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S1_CLK_EN); + } } } +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define i2s_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_bus_clock(__VA_ARGS__) + + /** - * @brief I2S module disable clock. + * @brief Reset the I2S module + * + * @param i2s_id The port id of I2S + */ +static inline void i2s_ll_reset_register(int i2s_id) +{ + if (i2s_id == 0) { + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST); + } else if (i2s_id == 1) { + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S1_RST); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S1_RST); + } +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define i2s_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_reset_register(__VA_ARGS__) + +/** + * @brief I2S module general init, enable I2S clock. * * @param hw Peripheral I2S hardware instance address. + * @param enable set true to enable the core clock */ -static inline void i2s_ll_disable_clock(i2s_dev_t *hw) +static inline void i2s_ll_enable_core_clock(i2s_dev_t *hw, bool enable) { - if (hw->clkm_conf.clk_en == 1) { + if (enable && !hw->clkm_conf.clk_en) { + hw->clkm_conf.clk_en = 1; + hw->conf2.val = 0; + } else if (!enable && hw->clkm_conf.clk_en) { hw->clkm_conf.clk_en = 0; } } +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define i2s_ll_enable_core_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_core_clock(__VA_ARGS__) + /** * @brief I2S tx msb right enable * diff --git a/components/hal/esp32c3/include/hal/i2s_ll.h b/components/hal/esp32c3/include/hal/i2s_ll.h index 6f8dac94ee..1b7e9de0da 100644 --- a/components/hal/esp32c3/include/hal/i2s_ll.h +++ b/components/hal/esp32c3/include/hal/i2s_ll.h @@ -17,6 +17,7 @@ #include "hal/assert.h" #include "soc/i2s_periph.h" #include "soc/i2s_struct.h" +#include "soc/system_struct.h" #include "hal/i2s_types.h" #include "hal/hal_utils.h" @@ -34,27 +35,56 @@ extern "C" { #define I2S_LL_CLK_FRAC_DIV_AB_MAX 512 // I2S_MCLK = I2S_SRC_CLK / (N + b/a), the a/b register is 9 bit-width #define I2S_LL_PLL_F160M_CLK_FREQ (160 * 1000000) // PLL_F160M_CLK: 160MHz -#define I2S_LL_DEFAULT_PLL_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT +#define I2S_LL_DEFAULT_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT + + +/** + * @brief Enable the bus clock for I2S module + * + * @param i2s_id The port id of I2S + * @param enable Set true to enable the buf clock + */ +static inline void i2s_ll_enable_bus_clock(int i2s_id, bool enable) +{ + (void)i2s_id; + SYSTEM.perip_clk_en0.reg_i2s1_clk_en = enable; +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define i2s_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_bus_clock(__VA_ARGS__) + + +/** + * @brief Reset the I2S module + * + * @param i2s_id The port id of I2S + */ +static inline void i2s_ll_reset_register(int i2s_id) +{ + (void)i2s_id; + SYSTEM.perip_rst_en0.reg_i2s1_rst = 1; + SYSTEM.perip_rst_en0.reg_i2s1_rst = 0; +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define i2s_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_reset_register(__VA_ARGS__) /** * @brief I2S module general init, enable I2S clock. * * @param hw Peripheral I2S hardware instance address. + * @param enable set true to enable the core clock */ -static inline void i2s_ll_enable_clock(i2s_dev_t *hw) +static inline void i2s_ll_enable_core_clock(i2s_dev_t *hw, bool enable) { - hw->tx_clkm_conf.clk_en = 1; + hw->tx_clkm_conf.clk_en = enable; } -/** - * @brief I2S module disable I2S clock. - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_disable_clock(i2s_dev_t *hw) -{ - hw->tx_clkm_conf.clk_en = 0; -} +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define i2s_ll_enable_core_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_core_clock(__VA_ARGS__) /** * @brief Enable I2S tx module clock diff --git a/components/hal/esp32c6/include/hal/i2s_ll.h b/components/hal/esp32c6/include/hal/i2s_ll.h index 687ef3162f..52c15d43f0 100644 --- a/components/hal/esp32c6/include/hal/i2s_ll.h +++ b/components/hal/esp32c6/include/hal/i2s_ll.h @@ -35,28 +35,42 @@ extern "C" { #define I2S_LL_CLK_FRAC_DIV_AB_MAX 512 // I2S_MCLK = I2S_SRC_CLK / (N + b/a), the a/b register is 9 bit-width #define I2S_LL_PLL_F160M_CLK_FREQ (160 * 1000000) // PLL_F160M_CLK: 160MHz -#define I2S_LL_DEFAULT_PLL_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT +#define I2S_LL_DEFAULT_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT + +/** + * + * @param i2s_id The port id of I2S + * @param enable Set true to enable the buf clock + */ +static inline void i2s_ll_enable_bus_clock(int i2s_id, bool enable) +{ + (void)i2s_id; + PCR.i2s_conf.i2s_clk_en = enable; +} + +/** + * @brief Reset the I2S module + * + * @param i2s_id The port id of I2S + */ +static inline void i2s_ll_reset_register(int i2s_id) +{ + (void)i2s_id; + PCR.i2s_conf.i2s_rst_en = 1; + PCR.i2s_conf.i2s_rst_en = 0; +} /** * @brief I2S module general init, enable I2S clock. * * @param hw Peripheral I2S hardware instance address. + * @param enable set true to enable the core clock */ -static inline void i2s_ll_enable_clock(i2s_dev_t *hw) +static inline void i2s_ll_enable_core_clock(i2s_dev_t *hw, bool enable) { - // The clock gate enabling is moved to `periph_module_enable` - (void)hw; -} - -/** - * @brief I2S module disable I2S clock. - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_disable_clock(i2s_dev_t *hw) -{ - // The clock gate disabling is moved to `periph_module_disable` (void)hw; + (void)enable; + // No need to do anything } /** diff --git a/components/hal/esp32h2/include/hal/i2s_ll.h b/components/hal/esp32h2/include/hal/i2s_ll.h index 8ebfa8518b..0baf7101e5 100644 --- a/components/hal/esp32h2/include/hal/i2s_ll.h +++ b/components/hal/esp32h2/include/hal/i2s_ll.h @@ -36,28 +36,42 @@ extern "C" { #define I2S_LL_PLL_F96M_CLK_FREQ (96 * 1000000) // PLL_F96M_CLK: 96MHz #define I2S_LL_PLL_F64M_CLK_FREQ (64 * 1000000) // PLL_F64M_CLK: 64MHz -#define I2S_LL_DEFAULT_PLL_CLK_FREQ I2S_LL_PLL_F96M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT +#define I2S_LL_DEFAULT_CLK_FREQ I2S_LL_PLL_F96M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT + +/** + * + * @param i2s_id The port id of I2S + * @param enable Set true to enable the buf clock + */ +static inline void i2s_ll_enable_bus_clock(int i2s_id, bool enable) +{ + (void)i2s_id; + PCR.i2s_conf.i2s_clk_en = enable; +} + +/** + * @brief Reset the I2S module + * + * @param i2s_id The port id of I2S + */ +static inline void i2s_ll_reset_register(int i2s_id) +{ + (void)i2s_id; + PCR.i2s_conf.i2s_rst_en = 1; + PCR.i2s_conf.i2s_rst_en = 0; +} /** * @brief I2S module general init, enable I2S clock. * * @param hw Peripheral I2S hardware instance address. + * @param enable set true to enable the core clock */ -static inline void i2s_ll_enable_clock(i2s_dev_t *hw) +static inline void i2s_ll_enable_core_clock(i2s_dev_t *hw, bool enable) { - // The clock gate enabling is moved to `periph_module_enable` - (void)hw; -} - -/** - * @brief I2S module disable I2S clock. - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_disable_clock(i2s_dev_t *hw) -{ - // The clock gate disabling is moved to `periph_module_disable` (void)hw; + (void)enable; + // No need to do anything } /** diff --git a/components/hal/esp32p4/include/hal/clk_gate_ll.h b/components/hal/esp32p4/include/hal/clk_gate_ll.h index 48e7a09509..8b21f7dfbb 100644 --- a/components/hal/esp32p4/include/hal/clk_gate_ll.h +++ b/components/hal/esp32p4/include/hal/clk_gate_ll.h @@ -36,12 +36,6 @@ static inline uint32_t periph_ll_get_clk_en_mask(periph_module_t periph) return HP_SYS_CLKRST_REG_I2C0_APB_CLK_EN; case PERIPH_I2C1_MODULE: return HP_SYS_CLKRST_REG_I2C1_APB_CLK_EN; - case PERIPH_I2S0_MODULE: - return HP_SYS_CLKRST_REG_I2S0_TX_CLK_EN | HP_SYS_CLKRST_REG_I2S0_RX_CLK_EN; - case PERIPH_I2S1_MODULE: - return HP_SYS_CLKRST_REG_I2S1_RX_CLK_EN | HP_SYS_CLKRST_REG_I2S1_TX_CLK_EN; - case PERIPH_I2S2_MODULE: - return HP_SYS_CLKRST_REG_I2S2_RX_CLK_EN | HP_SYS_CLKRST_REG_I2S2_TX_CLK_EN; case PERIPH_LCD_MODULE: return HP_SYS_CLKRST_REG_LCD_CLK_EN; case PERIPH_UART0_MODULE: @@ -151,12 +145,6 @@ static inline uint32_t periph_ll_get_rst_en_mask(periph_module_t periph, bool en return HP_SYS_CLKRST_REG_RST_EN_CAN2; case PERIPH_LEDC_MODULE: return HP_SYS_CLKRST_REG_RST_EN_LEDC; - case PERIPH_I2S0_MODULE: - return HP_SYS_CLKRST_REG_RST_EN_I2S0_APB; - case PERIPH_I2S1_MODULE: - return HP_SYS_CLKRST_REG_RST_EN_I2S1_APB; - case PERIPH_I2S2_MODULE: - return HP_SYS_CLKRST_REG_RST_EN_I2S2_APB; case PERIPH_GPSPI2_MODULE: return HP_SYS_CLKRST_REG_RST_EN_SPI2; case PERIPH_GPSPI3_MODULE: @@ -294,10 +282,6 @@ static inline uint32_t periph_ll_get_rst_en_reg(periph_module_t periph) case PERIPH_TWAI1_MODULE: case PERIPH_TWAI2_MODULE: case PERIPH_LEDC_MODULE: - case PERIPH_I2S0_MODULE: - return HP_SYS_CLKRST_HP_RST_EN1_REG; - case PERIPH_I2S1_MODULE: - case PERIPH_I2S2_MODULE: case PERIPH_GPSPI2_MODULE: case PERIPH_GPSPI3_MODULE: case PERIPH_CAM_MODULE: diff --git a/components/hal/esp32p4/include/hal/clk_tree_ll.h b/components/hal/esp32p4/include/hal/clk_tree_ll.h index c3fee0041a..29a38bdfc5 100644 --- a/components/hal/esp32p4/include/hal/clk_tree_ll.h +++ b/components/hal/esp32p4/include/hal/clk_tree_ll.h @@ -30,6 +30,16 @@ extern "C" { #define CLK_LL_PLL_480M_FREQ_MHZ (480) +/* APLL multiplier output frequency range */ +// TODO: IDF-7526 check if the APLL frequency range is same as before +// apll_multiplier_out = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) +#define CLK_LL_APLL_MULTIPLIER_MIN_HZ (350000000) // 350 MHz +#define CLK_LL_APLL_MULTIPLIER_MAX_HZ (500000000) // 500 MHz + +/* APLL output frequency range */ +#define CLK_LL_APLL_MIN_HZ (5303031) // 5.303031 MHz, refer to 'periph_rtc_apll_freq_set' for the calculation +#define CLK_LL_APLL_MAX_HZ (125000000) // 125MHz, refer to 'periph_rtc_apll_freq_set' for the calculation + #define CLK_LL_XTAL32K_CONFIG_DEFAULT() { \ .dac = 3, \ .dres = 3, \ diff --git a/components/hal/esp32p4/include/hal/i2s_ll.h b/components/hal/esp32p4/include/hal/i2s_ll.h new file mode 100644 index 0000000000..c3b69cf98d --- /dev/null +++ b/components/hal/esp32p4/include/hal/i2s_ll.h @@ -0,0 +1,1402 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +// The LL layer for I2S register operations +/******************************************************************************* + * NOTICE + * The hal is not public api, don't use in application code. + * See readme.md in hal/include/hal/readme.md + ******************************************************************************/ + +#pragma once +#include +#include "hal/misc.h" +#include "hal/assert.h" +#include "soc/i2s_periph.h" +#include "soc/i2s_struct.h" +#include "soc/hp_sys_clkrst_struct.h" +#include "hal/i2s_types.h" +#include "hal/hal_utils.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +#define I2S_LL_GET_HW(num) (((num) == 0)? (&I2S0) : ((num) == 1) ? (&I2S1) : (&I2S2)) +#define I2S_LL_GET_ID(hw) (((hw) == &I2S0)? 0 : ((hw) == &I2S1) ? 1 : 2) + +#define I2S_LL_TDM_CH_MASK (0xffff) +#define I2S_LL_PDM_BCK_FACTOR (64) + +#define I2S_LL_CLK_FRAC_DIV_N_MAX 256 // I2S_MCLK = I2S_SRC_CLK / (N + b/a), the N register is 8 bit-width +#define I2S_LL_CLK_FRAC_DIV_AB_MAX 512 // I2S_MCLK = I2S_SRC_CLK / (N + b/a), the a/b register is 9 bit-width + +#define I2S_LL_XTAL_CLK_FREQ (40 * 1000000) // XTAL_CLK: 40MHz +#define I2S_LL_DEFAULT_CLK_FREQ I2S_LL_XTAL_CLK_FREQ // No PLL clock source on P4, use XTAL as default + +/** + * @brief Enable the bus clock for I2S module + * + * @param i2s_id The port id of I2S + * @param enable Set true to enable the buf clock + */ +static inline void i2s_ll_enable_bus_clock(int i2s_id, bool enable) +{ + switch (i2s_id) { + case 0: + HP_SYS_CLKRST.soc_clk_ctrl2.reg_i2s0_apb_clk_en = enable; + return; + case 1: + HP_SYS_CLKRST.soc_clk_ctrl2.reg_i2s1_apb_clk_en = enable; + return; + case 2: + HP_SYS_CLKRST.soc_clk_ctrl2.reg_i2s2_apb_clk_en = enable; + return; + } +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define i2s_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_bus_clock(__VA_ARGS__) + +/** + * @brief Reset the I2S module + * + * @param i2s_id The port id of I2S + */ +static inline void i2s_ll_reset_register(int i2s_id) +{ + switch (i2s_id) { + case 0: + HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_i2s0_apb = 1; + HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_i2s0_apb = 0; + return; + case 1: + HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_i2s1_apb = 1; + HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_i2s1_apb = 0; + return; + case 2: + HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_i2s2_apb = 1; + HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_i2s2_apb = 0; + return; + } +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define i2s_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_reset_register(__VA_ARGS__) + +/** + * @brief I2S module general init, enable I2S clock. + * + * @param hw Peripheral I2S hardware instance address. + * @param enable set true to enable the core clock + */ +static inline void i2s_ll_enable_core_clock(i2s_dev_t *hw, bool enable) +{ + (void)hw; + (void)enable; + // No need to do anything +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define i2s_ll_enable_core_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_core_clock(__VA_ARGS__) + +/** + * @brief Enable I2S tx module clock + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_tx_enable_clock(i2s_dev_t *hw) +{ + // Note: this function involves HP_SYS_CLKRST register which is shared with other peripherals, need lock in upper layer + switch (I2S_LL_GET_ID(hw)) { + case 0: + HP_SYS_CLKRST.peri_clk_ctrl13.reg_i2s0_tx_clk_en = 1; + return; + case 1: + HP_SYS_CLKRST.peri_clk_ctrl15.reg_i2s1_tx_clk_en = 1; + return; + case 2: + HP_SYS_CLKRST.peri_clk_ctrl18.reg_i2s2_tx_clk_en = 1; + return; + } +} + +/** + * @brief Enable I2S rx module clock + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_rx_enable_clock(i2s_dev_t *hw) +{ + // Note: this function involves HP_SYS_CLKRST register which is shared with other peripherals, need lock in upper layer + switch (I2S_LL_GET_ID(hw)) { + case 0: + HP_SYS_CLKRST.peri_clk_ctrl11.reg_i2s0_rx_clk_en = 1; + return; + case 1: + HP_SYS_CLKRST.peri_clk_ctrl14.reg_i2s1_rx_clk_en = 1; + return; + case 2: + HP_SYS_CLKRST.peri_clk_ctrl17.reg_i2s2_rx_clk_en = 1; + return; + } +} + +/** + * @brief Disable I2S tx module clock + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_tx_disable_clock(i2s_dev_t *hw) +{ + // Note: this function involves HP_SYS_CLKRST register which is shared with other peripherals, need lock in upper layer + switch (I2S_LL_GET_ID(hw)) { + case 0: + HP_SYS_CLKRST.peri_clk_ctrl13.reg_i2s0_tx_clk_en = 0; + return; + case 1: + HP_SYS_CLKRST.peri_clk_ctrl15.reg_i2s1_tx_clk_en = 0; + return; + case 2: + HP_SYS_CLKRST.peri_clk_ctrl18.reg_i2s2_tx_clk_en = 0; + return; + } +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define i2s_ll_tx_disable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_tx_disable_clock(__VA_ARGS__) + +/** + * @brief Disable I2S rx module clock + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_rx_disable_clock(i2s_dev_t *hw) +{ + // Note: this function involves HP_SYS_CLKRST register which is shared with other peripherals, need lock in upper layer + switch (I2S_LL_GET_ID(hw)) { + case 0: + HP_SYS_CLKRST.peri_clk_ctrl11.reg_i2s0_rx_clk_en = 0; + return; + case 1: + HP_SYS_CLKRST.peri_clk_ctrl14.reg_i2s1_rx_clk_en = 0; + return; + case 2: + HP_SYS_CLKRST.peri_clk_ctrl17.reg_i2s2_rx_clk_en = 0; + return; + } +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define i2s_ll_rx_disable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_rx_disable_clock(__VA_ARGS__) + +/** + * @brief I2S mclk use tx module clock + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_mclk_bind_to_tx_clk(i2s_dev_t *hw) +{ + // Note: this function involves HP_SYS_CLKRST register which is shared with other peripherals, need lock in upper layer + switch (I2S_LL_GET_ID(hw)) { + case 0: + HP_SYS_CLKRST.peri_clk_ctrl14.reg_i2s0_mst_clk_sel = 0; + return; + case 1: + HP_SYS_CLKRST.peri_clk_ctrl17.reg_i2s1_mst_clk_sel = 0; + return; + case 2: + HP_SYS_CLKRST.peri_clk_ctrl19.reg_i2s2_mst_clk_sel = 0; + return; + } +} + +/** + * @brief I2S mclk use rx module clock + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_mclk_bind_to_rx_clk(i2s_dev_t *hw) +{ + // Note: this function involves HP_SYS_CLKRST register which is shared with other peripherals, need lock in upper layer + switch (I2S_LL_GET_ID(hw)) { + case 0: + HP_SYS_CLKRST.peri_clk_ctrl14.reg_i2s0_mst_clk_sel = 1; + return; + case 1: + HP_SYS_CLKRST.peri_clk_ctrl17.reg_i2s1_mst_clk_sel = 1; + return; + case 2: + HP_SYS_CLKRST.peri_clk_ctrl19.reg_i2s2_mst_clk_sel = 1; + return; + } +} + +/** + * @brief Enable I2S TX slave mode + * + * @param hw Peripheral I2S hardware instance address. + * @param slave_en Set true to enable slave mode + */ +static inline void i2s_ll_tx_set_slave_mod(i2s_dev_t *hw, bool slave_en) +{ + hw->tx_conf.tx_slave_mod = slave_en; +} + +/** + * @brief Enable I2S RX slave mode + * + * @param hw Peripheral I2S hardware instance address. + * @param slave_en Set true to enable slave mode + */ +static inline void i2s_ll_rx_set_slave_mod(i2s_dev_t *hw, bool slave_en) +{ + hw->rx_conf.rx_slave_mod = slave_en; +} + +/** + * @brief Reset I2S TX module + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_tx_reset(i2s_dev_t *hw) +{ + hw->tx_conf.tx_reset = 1; + hw->tx_conf.tx_reset = 0; +} + +/** + * @brief Reset I2S RX module + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_rx_reset(i2s_dev_t *hw) +{ + hw->rx_conf.rx_reset = 1; + hw->rx_conf.rx_reset = 0; +} + +/** + * @brief Reset I2S TX FIFO + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_tx_reset_fifo(i2s_dev_t *hw) +{ + hw->tx_conf.tx_fifo_reset = 1; + hw->tx_conf.tx_fifo_reset = 0; +} + +/** + * @brief Reset I2S RX FIFO + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_rx_reset_fifo(i2s_dev_t *hw) +{ + hw->rx_conf.rx_fifo_reset = 1; + hw->rx_conf.rx_fifo_reset = 0; +} + +static inline uint32_t i2s_ll_get_clk_src(i2s_clock_src_t src) +{ + switch (src) + { + case I2S_CLK_SRC_XTAL: + return 0; + case I2S_CLK_SRC_APLL: + return 1; + case I2S_CLK_SRC_EXTERNAL: + return 2; + default: + HAL_ASSERT(false && "unsupported clock source"); + return -1; + } +} + +/** + * @brief Set TX source clock + * + * @param hw Peripheral I2S hardware instance address. + * @param src I2S source clock. + */ +static inline void i2s_ll_tx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src) +{ + // Note: this function involves HP_SYS_CLKRST register which is shared with other peripherals, need lock in upper layer + uint32_t clk_src = i2s_ll_get_clk_src(src); + switch (I2S_LL_GET_ID(hw)) { + case 0: + HP_SYS_CLKRST.peri_clk_ctrl13.reg_i2s0_tx_clk_src_sel = clk_src; + return; + case 1: + HP_SYS_CLKRST.peri_clk_ctrl15.reg_i2s1_tx_clk_src_sel = clk_src; + return; + case 2: + HP_SYS_CLKRST.peri_clk_ctrl18.reg_i2s2_tx_clk_src_sel = clk_src; + return; + } +} + +/** + * @brief Set RX source clock + * + * @param hw Peripheral I2S hardware instance address. + * @param src I2S source clock + */ +static inline void i2s_ll_rx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src) +{ + // Note: this function involves HP_SYS_CLKRST register which is shared with other peripherals, need lock in upper layer + uint32_t clk_src = i2s_ll_get_clk_src(src); + switch (I2S_LL_GET_ID(hw)) { + case 0: + HP_SYS_CLKRST.peri_clk_ctrl11.reg_i2s0_rx_clk_src_sel = clk_src; + return; + case 1: + HP_SYS_CLKRST.peri_clk_ctrl14.reg_i2s1_rx_clk_src_sel = clk_src; + return; + case 2: + HP_SYS_CLKRST.peri_clk_ctrl17.reg_i2s2_rx_clk_src_sel = clk_src; + return; + } +} + +/** + * @brief Set I2S tx bck div num + * + * @param hw Peripheral I2S hardware instance address. + * @param val value to set tx bck div num + */ +static inline void i2s_ll_tx_set_bck_div_num(i2s_dev_t *hw, uint32_t val) +{ + hw->tx_conf.tx_bck_div_num = val - 1; +} + +/** + * @brief Set I2S tx raw clock division + * + * @param hw Peripheral I2S hardware instance address. + * @param div_int Integer part of division + * @param x div x + * @param y div y + * @param z div z + * @param yn1 yn1 + */ +static inline void i2s_ll_tx_set_raw_clk_div(i2s_dev_t *hw, uint32_t div_int, uint32_t x, uint32_t y, uint32_t z, uint32_t yn1) +{ + // Note: this function involves HP_SYS_CLKRST register which is shared with other peripherals, need lock in upper layer + switch (I2S_LL_GET_ID(hw)) { + case 0: + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl13, reg_i2s0_tx_div_n, div_int); + HP_SYS_CLKRST.peri_clk_ctrl13.reg_i2s0_tx_div_x = x; + HP_SYS_CLKRST.peri_clk_ctrl14.reg_i2s0_tx_div_y = y; + HP_SYS_CLKRST.peri_clk_ctrl14.reg_i2s0_tx_div_z = z; + HP_SYS_CLKRST.peri_clk_ctrl14.reg_i2s0_tx_div_yn1 = yn1; + return; + case 1: + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl16, reg_i2s1_tx_div_n, div_int); + HP_SYS_CLKRST.peri_clk_ctrl16.reg_i2s1_tx_div_x = x; + HP_SYS_CLKRST.peri_clk_ctrl16.reg_i2s1_tx_div_y = y; + HP_SYS_CLKRST.peri_clk_ctrl17.reg_i2s1_tx_div_z = z; + HP_SYS_CLKRST.peri_clk_ctrl17.reg_i2s1_tx_div_yn1 = yn1; + return; + case 2: + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl18, reg_i2s2_tx_div_n, div_int); + HP_SYS_CLKRST.peri_clk_ctrl19.reg_i2s2_tx_div_x = x; + HP_SYS_CLKRST.peri_clk_ctrl19.reg_i2s2_tx_div_y = y; + HP_SYS_CLKRST.peri_clk_ctrl19.reg_i2s2_tx_div_z = z; + HP_SYS_CLKRST.peri_clk_ctrl19.reg_i2s2_tx_div_yn1 = yn1; + return; + } +} + +/** + * @brief Set I2S rx raw clock division + * + * @param hw Peripheral I2S hardware instance address. + * @param div_int Integer part of division + * @param x div x + * @param y div y + * @param z div z + * @param yn1 yn1 + */ +static inline void i2s_ll_rx_set_raw_clk_div(i2s_dev_t *hw, uint32_t div_int, uint32_t x, uint32_t y, uint32_t z, uint32_t yn1) +{ + // Note: this function involves HP_SYS_CLKRST register which is shared with other peripherals, need lock in upper layer + switch (I2S_LL_GET_ID(hw)) { + case 0: + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl12, reg_i2s0_rx_div_n, div_int); + HP_SYS_CLKRST.peri_clk_ctrl12.reg_i2s0_rx_div_x = x; + HP_SYS_CLKRST.peri_clk_ctrl12.reg_i2s0_rx_div_y = y; + HP_SYS_CLKRST.peri_clk_ctrl13.reg_i2s0_rx_div_z = z; + HP_SYS_CLKRST.peri_clk_ctrl13.reg_i2s0_rx_div_yn1 = yn1; + return; + case 1: + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl14, reg_i2s1_rx_div_n, div_int); + HP_SYS_CLKRST.peri_clk_ctrl15.reg_i2s1_rx_div_x = x; + HP_SYS_CLKRST.peri_clk_ctrl15.reg_i2s1_rx_div_y = y; + HP_SYS_CLKRST.peri_clk_ctrl15.reg_i2s1_rx_div_z = z; + HP_SYS_CLKRST.peri_clk_ctrl15.reg_i2s1_rx_div_yn1 = yn1; + return; + case 2: + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl17, reg_i2s2_rx_div_n, div_int); + HP_SYS_CLKRST.peri_clk_ctrl17.reg_i2s2_rx_div_x = x; + HP_SYS_CLKRST.peri_clk_ctrl18.reg_i2s2_rx_div_y = y; + HP_SYS_CLKRST.peri_clk_ctrl18.reg_i2s2_rx_div_z = z; + HP_SYS_CLKRST.peri_clk_ctrl18.reg_i2s2_rx_div_yn1 = yn1; + return; + } +} + +/** + * @brief Configure I2S TX module clock divider + * + * @param hw Peripheral I2S hardware instance address. + * @param mclk_div The mclk division coefficients + */ +static inline void i2s_ll_tx_set_mclk(i2s_dev_t *hw, const hal_utils_clk_div_t *mclk_div) +{ + /* Workaround for inaccurate clock while switching from a relatively low sample rate to a high sample rate + * Set to particular coefficients first then update to the target coefficients, + * otherwise the clock division might be inaccurate. + * the general idea is to set a value that impossible to calculate from the regular decimal */ + i2s_ll_tx_set_raw_clk_div(hw, 7, 317, 7, 3, 0); + + uint32_t div_x = 0; + uint32_t div_y = 0; + uint32_t div_z = 0; + uint32_t div_yn1 = 0; + /* If any of denominator and numerator is 0, set all the coefficients to 0 */ + if (mclk_div->denominator && mclk_div->numerator) { + div_yn1 = mclk_div->numerator * 2 > mclk_div->denominator; + div_z = div_yn1 ? mclk_div->denominator - mclk_div->numerator : mclk_div->numerator; + div_x = mclk_div->denominator / div_z - 1; + div_y = mclk_div->denominator % div_z; + } + i2s_ll_tx_set_raw_clk_div(hw, mclk_div->integer, div_x, div_y, div_z, div_yn1); +} + +/** + * @brief Set I2S rx bck div num + * + * @param hw Peripheral I2S hardware instance address. + * @param val value to set rx bck div num + */ +static inline void i2s_ll_rx_set_bck_div_num(i2s_dev_t *hw, uint32_t val) +{ + hw->rx_conf.rx_bck_div_num = val - 1; +} + +/** + * @brief Configure I2S RX module clock divider + * @note mclk on ESP32 is shared by both TX and RX channel + * + * @param hw Peripheral I2S hardware instance address. + * @param mclk_div The mclk division coefficients + */ +static inline void i2s_ll_rx_set_mclk(i2s_dev_t *hw, const hal_utils_clk_div_t *mclk_div) +{ + /* Workaround for inaccurate clock while switching from a relatively low sample rate to a high sample rate + * Set to particular coefficients first then update to the target coefficients, + * otherwise the clock division might be inaccurate. + * the general idea is to set a value that impossible to calculate from the regular decimal */ + i2s_ll_rx_set_raw_clk_div(hw, 7, 317, 7, 3, 0); + + uint32_t div_x = 0; + uint32_t div_y = 0; + uint32_t div_z = 0; + uint32_t div_yn1 = 0; + /* If any of denominator and numerator is 0, set all the coefficients to 0 */ + if (mclk_div->denominator && mclk_div->numerator) { + div_yn1 = mclk_div->numerator * 2 > mclk_div->denominator; + div_z = div_yn1 ? mclk_div->denominator - mclk_div->numerator : mclk_div->numerator; + div_x = mclk_div->denominator / div_z - 1; + div_y = mclk_div->denominator % div_z; + } + i2s_ll_rx_set_raw_clk_div(hw, mclk_div->integer, div_x, div_y, div_z, div_yn1); +} + +/** + * @brief Start I2S TX + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_tx_start(i2s_dev_t *hw) +{ + // Have to update registers before start + hw->tx_conf.tx_update = 1; + while (hw->tx_conf.tx_update); + hw->tx_conf.tx_start = 1; +} + +/** + * @brief Start I2S RX + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_rx_start(i2s_dev_t *hw) +{ + // Have to update registers before start + hw->rx_conf.rx_update = 1; + while (hw->rx_conf.rx_update); + hw->rx_conf.rx_start = 1; +} + +/** + * @brief Stop I2S TX + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_tx_stop(i2s_dev_t *hw) +{ + hw->tx_conf.tx_start = 0; +} + +/** + * @brief Stop I2S RX + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_rx_stop(i2s_dev_t *hw) +{ + hw->rx_conf.rx_start = 0; +} + +/** + * @brief Configure TX WS signal width + * + * @param hw Peripheral I2S hardware instance address. + * @param width WS width in BCK cycle + */ +static inline void i2s_ll_tx_set_ws_width(i2s_dev_t *hw, int width) +{ + hw->tx_conf1.tx_tdm_ws_width = width - 1; +} + +/** + * @brief Configure RX WS signal width + * + * @param hw Peripheral I2S hardware instance address. + * @param width WS width in BCK cycle + */ +static inline void i2s_ll_rx_set_ws_width(i2s_dev_t *hw, int width) +{ + hw->rx_conf1.rx_tdm_ws_width = width - 1; +} + +/** + * @brief Configure the received length to trigger in_suc_eof interrupt + * + * @param hw Peripheral I2S hardware instance address. + * @param eof_num the byte length to trigger in_suc_eof interrupt + */ +static inline void i2s_ll_rx_set_eof_num(i2s_dev_t *hw, int eof_num) +{ + hw->rx_eof_num.rx_eof_num = eof_num; +} + +/** + * @brief Congfigure TX chan bit and audio data bit + * + * @param hw Peripheral I2S hardware instance address. + * @param chan_bit The chan bit width + * @param data_bit The audio data bit width + */ +static inline void i2s_ll_tx_set_sample_bit(i2s_dev_t *hw, uint8_t chan_bit, int data_bit) +{ + hw->tx_conf1.tx_bits_mod = data_bit - 1; + hw->tx_conf1.tx_tdm_chan_bits = chan_bit - 1; +} + +/** + * @brief Congfigure RX chan bit and audio data bit + * + * @param hw Peripheral I2S hardware instance address. + * @param chan_bit The chan bit width + * @param data_bit The audio data bit width + */ +static inline void i2s_ll_rx_set_sample_bit(i2s_dev_t *hw, uint8_t chan_bit, int data_bit) +{ + hw->rx_conf1.rx_bits_mod = data_bit - 1; + hw->rx_conf1.rx_tdm_chan_bits = chan_bit - 1; +} + +/** + * @brief Configure RX half_sample_bit + * + * @param hw Peripheral I2S hardware instance address. + * @param half_sample_bits half sample bit width + */ +static inline void i2s_ll_tx_set_half_sample_bit(i2s_dev_t *hw, int half_sample_bits) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->tx_conf1, tx_half_sample_bits, half_sample_bits - 1); +} + +/** + * @brief Configure RX half_sample_bit + * + * @param hw Peripheral I2S hardware instance address. + * @param half_sample_bits half sample bit width + */ +static inline void i2s_ll_rx_set_half_sample_bit(i2s_dev_t *hw, int half_sample_bits) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->rx_conf1, rx_half_sample_bits, half_sample_bits - 1); +} + +/** + * @brief Enable TX MSB shift, the data will be launch at the first BCK clock + * + * @param hw Peripheral I2S hardware instance address. + * @param msb_shift_enable Set true to enable MSB shift + */ +static inline void i2s_ll_tx_enable_msb_shift(i2s_dev_t *hw, bool msb_shift_enable) +{ + hw->tx_conf.tx_msb_shift = msb_shift_enable; +} + +/** + * @brief Enable RX MSB shift, the data will be launch at the first BCK clock + * + * @param hw Peripheral I2S hardware instance address. + * @param msb_shift_enable Set true to enable MSB shift + */ +static inline void i2s_ll_rx_enable_msb_shift(i2s_dev_t *hw, bool msb_shift_enable) +{ + hw->rx_conf.rx_msb_shift = msb_shift_enable; +} + +/** + * @brief Configure TX total chan number + * + * @param hw Peripheral I2S hardware instance address. + * @param total_num Total chan number + */ +static inline void i2s_ll_tx_set_chan_num(i2s_dev_t *hw, int total_num) +{ + hw->tx_tdm_ctrl.tx_tdm_tot_chan_num = total_num - 1; +} + +/** + * @brief Configure RX total chan number + * + * @param hw Peripheral I2S hardware instance address. + * @param total_num Total chan number + */ +static inline void i2s_ll_rx_set_chan_num(i2s_dev_t *hw, int total_num) +{ + hw->rx_tdm_ctrl.rx_tdm_tot_chan_num = total_num - 1; +} + +/** + * @brief Set the bimap of the active TX chan, only the active chan can launch audio data. + * + * @param hw Peripheral I2S hardware instance address. + * @param chan_mask mask of tx active chan + */ +static inline void i2s_ll_tx_set_active_chan_mask(i2s_dev_t *hw, uint32_t chan_mask) +{ + uint32_t tdm_ctrl = hw->tx_tdm_ctrl.val; + tdm_ctrl &= 0xFFFF0000; + tdm_ctrl |= chan_mask; + hw->tx_tdm_ctrl.val = tdm_ctrl; +} + +/** + * @brief Set the bimap of the active RX chan, only the active chan can receive audio data. + * + * @param hw Peripheral I2S hardware instance address. + * @param chan_mask mask of rx active chan + */ +static inline void i2s_ll_rx_set_active_chan_mask(i2s_dev_t *hw, uint32_t chan_mask) +{ + uint32_t tdm_ctrl = hw->rx_tdm_ctrl.val; + tdm_ctrl &= 0xFFFF0000; + tdm_ctrl |= chan_mask; + hw->rx_tdm_ctrl.val = tdm_ctrl; +} + +/** + * @brief Set I2S tx chan mode + * + * @param hw Peripheral I2S hardware instance address. + * @param slot_mask select slot to send data + */ +static inline void i2s_ll_tx_select_std_slot(i2s_dev_t *hw, i2s_std_slot_mask_t slot_mask) +{ + /* In mono mode, there only should be one slot enabled, another inactive slot will transmit same data as enabled slot + * Otherwise always enable the first two slots */ + hw->tx_tdm_ctrl.tx_tdm_tot_chan_num = 1; // tx_tdm_tot_chan_num = 2 slots - 1 = 1 + uint32_t chan_mask = 0; + switch (slot_mask) + { + case I2S_STD_SLOT_LEFT: + chan_mask |= 0x01; + break; + case I2S_STD_SLOT_RIGHT: + chan_mask |= 0x02; + break; + case I2S_STD_SLOT_BOTH: + chan_mask |= 0x03; + break; + default: + break; + } + i2s_ll_tx_set_active_chan_mask(hw, chan_mask); +} + +/** + * @brief Set I2S rx chan mode + * + * @param hw Peripheral I2S hardware instance address. + * @param slot_mask select slot to receive data + */ +static inline void i2s_ll_rx_select_std_slot(i2s_dev_t *hw, i2s_std_slot_mask_t slot_mask) +{ + /* In mono mode, there only should be one slot enabled, another inactive slot will transmit same data as enabled slot + * Otherwise always enable the first two slots */ + hw->rx_tdm_ctrl.rx_tdm_tot_chan_num = 1; // rx_tdm_tot_chan_num = 2 slots - 1 = 1 + uint32_t chan_mask = 0; + switch (slot_mask) + { + case I2S_STD_SLOT_LEFT: + chan_mask |= 0x01; + break; + case I2S_STD_SLOT_RIGHT: + chan_mask |= 0x02; + break; + case I2S_STD_SLOT_BOTH: + chan_mask |= 0x03; + break; + default: + break; + } + i2s_ll_rx_set_active_chan_mask(hw, chan_mask); +} + +/** + * @brief PDM slot mode + * + * @param hw Peripheral I2S hardware instance address. + * @param mod Channel mode + * while tx_ws_idle_pol = 0: + * 0: stereo + * 1: Both slots transmit left + * 2: Both slots transmit right + * 3: Left transmits `conf_single_data` right transmits data + * 4: Right transmits `conf_single_data` left transmits data + * while tx_ws_idle_pol = 1: + 0: stereo + * 1: Both slots transmit right + * 2: Both slots transmit left + * 3: Right transmits `conf_single_data` left transmits data + * 4: Left transmits `conf_single_data` right transmits data + */ +static inline void i2s_ll_tx_set_pdm_chan_mod(i2s_dev_t *hw, uint32_t mod) +{ + hw->tx_conf.tx_chan_mod = mod; +} + +/** + * @brief Set TX WS signal pol level + * + * @param hw Peripheral I2S hardware instance address. + * @param ws_pol_level pin level of WS(output) when receiving left channel data + */ +static inline void i2s_ll_tx_set_ws_idle_pol(i2s_dev_t *hw, bool ws_pol_level) +{ + hw->tx_conf.tx_ws_idle_pol = ws_pol_level; +} + +/** + * @brief Set RX WS signal pol level + * + * @param hw Peripheral I2S hardware instance address. + * @param ws_pol_level pin level of WS(input) when receiving left channel data + */ +static inline void i2s_ll_rx_set_ws_idle_pol(i2s_dev_t *hw, bool ws_pol_level) +{ + hw->rx_conf.rx_ws_idle_pol = ws_pol_level; +} + +/** + * @brief Enable I2S TX TDM mode + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_tx_enable_tdm(i2s_dev_t *hw) +{ + hw->tx_conf.tx_pdm_en = false; + hw->tx_conf.tx_tdm_en = true; + hw->tx_pcm2pdm_conf.pcm2pdm_conv_en = false; +} + +/** + * @brief Enable I2S RX TDM mode + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_rx_enable_tdm(i2s_dev_t *hw) +{ + hw->rx_conf.rx_pdm_en = false; + hw->rx_conf.rx_tdm_en = true; + hw->rx_pdm2pcm_conf.rx_pdm2pcm_en = false; +} + +/** + * @brief Enable I2S TX STD mode + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_tx_enable_std(i2s_dev_t *hw) +{ + i2s_ll_tx_enable_tdm(hw); +} + +/** + * @brief Enable I2S RX STD mode + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_rx_enable_std(i2s_dev_t *hw) +{ + i2s_ll_rx_enable_tdm(hw); +} + +/** + * @brief Enable TX PDM mode. + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_tx_enable_pdm(i2s_dev_t *hw) +{ + hw->tx_conf.tx_pdm_en = true; + hw->tx_conf.tx_tdm_en = false; + hw->tx_pcm2pdm_conf.pcm2pdm_conv_en = true; +} + +/** + * @brief Set I2S TX PDM prescale + * + * @param hw Peripheral I2S hardware instance address. + * @param prescale I2S TX PDM prescale + */ +static inline void i2s_ll_tx_set_pdm_prescale(i2s_dev_t *hw, bool prescale) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->tx_pcm2pdm_conf, tx_pdm_prescale, prescale); +} + +/** + * @brief Set I2S TX PDM high pass filter scaling + * + * @param hw Peripheral I2S hardware instance address. + * @param sig_scale I2S TX PDM signal scaling before transmit to the filter + */ +static inline void i2s_ll_tx_set_pdm_hp_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale) +{ + hw->tx_pcm2pdm_conf.tx_pdm_hp_in_shift = sig_scale; +} + +/** + * @brief Set I2S TX PDM low pass filter scaling + * + * @param hw Peripheral I2S hardware instance address. + * @param sig_scale I2S TX PDM signal scaling before transmit to the filter + */ +static inline void i2s_ll_tx_set_pdm_lp_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale) +{ + hw->tx_pcm2pdm_conf.tx_pdm_lp_in_shift = sig_scale; +} + +/** + * @brief Set I2S TX PDM sinc filter scaling + * + * @param hw Peripheral I2S hardware instance address. + * @param sig_scale I2S TX PDM signal scaling before transmit to the filter + */ +static inline void i2s_ll_tx_set_pdm_sinc_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale) +{ + hw->tx_pcm2pdm_conf.tx_pdm_sinc_in_shift = sig_scale; +} + +/** + * @brief Set I2S TX PDM sigma-delta filter scaling + * + * @param hw Peripheral I2S hardware instance address. + * @param sig_scale I2S TX PDM signal scaling before transmit to the filter + */ +static inline void i2s_ll_tx_set_pdm_sd_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale) +{ + hw->tx_pcm2pdm_conf.tx_pdm_sigmadelta_in_shift = sig_scale; +} + +/** + * @brief Set I2S TX PDM high pass filter param0 + * + * @param hw Peripheral I2S hardware instance address. + * @param param The fourth parameter of PDM TX IIR_HP filter stage 1 is (504 + I2S_TX_IIR_HP_MULT12_0[2:0]) + */ +static inline void i2s_ll_tx_set_pdm_hp_filter_param0(i2s_dev_t *hw, uint32_t param) +{ + hw->tx_pcm2pdm_conf1.tx_iir_hp_mult12_0 = param; +} + +/** + * @brief Set I2S TX PDM high pass filter param5 + * + * @param hw Peripheral I2S hardware instance address. + * @param param The fourth parameter of PDM TX IIR_HP filter stage 2 is (504 + I2S_TX_IIR_HP_MULT12_5[2:0]) + */ +static inline void i2s_ll_tx_set_pdm_hp_filter_param5(i2s_dev_t *hw, uint32_t param) +{ + hw->tx_pcm2pdm_conf1.tx_iir_hp_mult12_5 = param; +} + +/** + * @brief Enable I2S TX PDM high pass filter + * + * @param hw Peripheral I2S hardware instance address. + * @param enable Set true to enable I2S TX PDM high pass filter, set false to bypass it + */ +static inline void i2s_ll_tx_enable_pdm_hp_filter(i2s_dev_t *hw, bool enable) +{ + hw->tx_pcm2pdm_conf.tx_pdm_hp_bypass = !enable; +} + +/** + * @brief Set I2S TX PDM sigma-delta codec dither + * + * @param hw Peripheral I2S hardware instance address. + * @param dither I2S TX PDM sigmadelta dither value + */ +static inline void i2s_ll_tx_set_pdm_sd_dither(i2s_dev_t *hw, uint32_t dither) +{ + hw->tx_pcm2pdm_conf.tx_pdm_sigmadelta_dither = dither; +} + +/** + * @brief Set I2S TX PDM sigma-delta codec dither + * + * @param hw Peripheral I2S hardware instance address. + * @param dither2 I2S TX PDM sigmadelta dither2 value + */ +static inline void i2s_ll_tx_set_pdm_sd_dither2(i2s_dev_t *hw, uint32_t dither2) +{ + hw->tx_pcm2pdm_conf.tx_pdm_sigmadelta_dither2 = dither2; +} + +/** + * @brief Set the PDM TX over sampling ratio + * + * @param hw Peripheral I2S hardware instance address. + * @param ovr Over sampling ratio + */ +static inline void i2s_ll_tx_set_pdm_over_sample_ratio(i2s_dev_t *hw, uint32_t ovr) +{ + hw->tx_pcm2pdm_conf.tx_pdm_sinc_osr2 = ovr; +} + +/** + * @brief Configure I2S TX PDM sample rate + * Fpdm = 64*Fpcm*fp/fs + * + * @param hw Peripheral I2S hardware instance address. + * @param fp The fp value of TX PDM filter module group0. + * @param fs The fs value of TX PDM filter module group0. + */ +static inline void i2s_ll_tx_set_pdm_fpfs(i2s_dev_t *hw, uint32_t fp, uint32_t fs) +{ + hw->tx_pcm2pdm_conf1.tx_pdm_fp = fp; + hw->tx_pcm2pdm_conf1.tx_pdm_fs = fs; +} + +/** + * @brief Get I2S TX PDM fp configuration paramater + * + * @param hw Peripheral I2S hardware instance address. + * @return + * - fp configuration paramater + */ +static inline uint32_t i2s_ll_tx_get_pdm_fp(i2s_dev_t *hw) +{ + return hw->tx_pcm2pdm_conf1.tx_pdm_fp; +} + +/** + * @brief Get I2S TX PDM fs configuration paramater + * + * @param hw Peripheral I2S hardware instance address. + * @return + * - fs configuration paramater + */ +static inline uint32_t i2s_ll_tx_get_pdm_fs(i2s_dev_t *hw) +{ + return hw->tx_pcm2pdm_conf1.tx_pdm_fs; +} + +/** + * @brief Enable RX PDM mode. + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw) +{ + hw->rx_conf.rx_pdm_en = 1; + hw->rx_conf.rx_tdm_en = 0; + hw->rx_pdm2pcm_conf.rx_pdm2pcm_en = 1; +} + +/** + * @brief Configure RX PDM downsample + * + * @param hw Peripheral I2S hardware instance address. + * @param dsr PDM downsample configuration paramater + */ +static inline void i2s_ll_rx_set_pdm_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t dsr) +{ + hw->rx_pdm2pcm_conf.rx_pdm_sinc_dsr_16_en = dsr; +} + +/** + * @brief Get RX PDM downsample configuration + * + * @param hw Peripheral I2S hardware instance address. + * @param dsr Pointer to accept PDM downsample configuration + */ +static inline void i2s_ll_rx_get_pdm_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t *dsr) +{ + *dsr = (i2s_pdm_dsr_t)hw->rx_pdm2pcm_conf.rx_pdm_sinc_dsr_16_en; +} + +/** + * @brief Configure RX PDM amplify number + * @note This is the amplification number of the digital amplifier, + * which is added after the PDM to PCM conversion result and mainly used for + * amplify the small PDM signal under the VAD scenario + * pcm_result = pdm_input * amplify_num + * pcm_result = 0 if amplify_num = 0 + * + * @param hw Peripheral I2S hardware instance address. + * @param amp_num PDM RX amplify number + */ +static inline void i2s_ll_rx_set_pdm_amplify_num(i2s_dev_t *hw, uint32_t amp_num) +{ + hw->rx_pdm2pcm_conf.rx_pdm2pcm_amplify_num = amp_num; +} + + +/** + * @brief Set I2S RX PDM high pass filter param0 + * + * @param hw Peripheral I2S hardware instance address. + * @param param The fourth parameter of PDM RX IIR_HP filter stage 1 is (504 + I2S_RX_IIR_HP_MULT12_0[2:0]) + */ +static inline void i2s_ll_rx_set_pdm_hp_filter_param0(i2s_dev_t *hw, uint32_t param) +{ + hw->rx_pdm2pcm_conf.rx_iir_hp_mult12_0 = param; +} + +/** + * @brief Set I2S RX PDM high pass filter param5 + * + * @param hw Peripheral I2S hardware instance address. + * @param param The fourth parameter of PDM RX IIR_HP filter stage 2 is (504 + I2S_RX_IIR_HP_MULT12_5[2:0]) + */ +static inline void i2s_ll_rx_set_pdm_hp_filter_param5(i2s_dev_t *hw, uint32_t param) +{ + hw->rx_pdm2pcm_conf.rx_iir_hp_mult12_5 = param; +} + +/** + * @brief Enable I2S RX PDM high pass filter + * + * @param hw Peripheral I2S hardware instance address. + * @param enable Set true to enable I2S RX PDM high pass filter, set false to bypass it + */ +static inline void i2s_ll_rx_enable_pdm_hp_filter(i2s_dev_t *hw, bool enable) +{ + hw->rx_pdm2pcm_conf.rx_pdm_hp_bypass = !enable; +} + + +/** + * @brief Configura TX a/u-law decompress or compress + * + * @param hw Peripheral I2S hardware instance address. + * @param pcm_cfg PCM configuration paramater + */ +static inline void i2s_ll_tx_set_pcm_type(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) +{ + hw->tx_conf.tx_pcm_conf = pcm_cfg; + hw->tx_conf.tx_pcm_bypass = !pcm_cfg; +} + +/** + * @brief Configure RX a/u-law decompress or compress + * + * @param hw Peripheral I2S hardware instance address. + * @param pcm_cfg PCM configuration paramater + */ +static inline void i2s_ll_rx_set_pcm_type(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) +{ + hw->rx_conf.rx_pcm_conf = pcm_cfg; + hw->rx_conf.rx_pcm_bypass = !pcm_cfg; +} + +/** + * @brief Enable TX audio data left alignment + * + * @param hw Peripheral I2S hardware instance address. + * @param ena Set true to enable left alignment + */ +static inline void i2s_ll_tx_enable_left_align(i2s_dev_t *hw, bool ena) +{ + hw->tx_conf.tx_left_align = ena; +} + +/** + * @brief Enable RX audio data left alignment + * + * @param hw Peripheral I2S hardware instance address. + * @param ena Set true to enable left alignment + */ +static inline void i2s_ll_rx_enable_left_align(i2s_dev_t *hw, bool ena) +{ + hw->rx_conf.rx_left_align = ena; +} + +/** + * @brief Enable TX big endian mode + * + * @param hw Peripheral I2S hardware instance address. + * @param ena Set true to enable big endian mode + */ +static inline void i2s_ll_rx_enable_big_endian(i2s_dev_t *hw, bool ena) +{ + hw->rx_conf.rx_big_endian = ena; +} + +/** + * @brief Enable RX big endian mode + * + * @param hw Peripheral I2S hardware instance address. + * @param ena Set true to enable big endian mode + */ +static inline void i2s_ll_tx_enable_big_endian(i2s_dev_t *hw, bool ena) +{ + hw->tx_conf.tx_big_endian = ena; +} + +/** + * @brief Configure TX bit order + * + * @param hw Peripheral I2S hardware instance address. + * @param lsb_order_ena Set true to enable LSB bit order + */ +static inline void i2s_ll_tx_set_bit_order(i2s_dev_t *hw, bool lsb_order_ena) +{ + hw->tx_conf.tx_bit_order = lsb_order_ena; +} + +/** + * @brief Configure RX bit order + * + * @param hw Peripheral I2S hardware instance address. + * @param lsb_order_ena Set true to enable LSB bit order + */ +static inline void i2s_ll_rx_set_bit_order(i2s_dev_t *hw, bool lsb_order_ena) +{ + hw->rx_conf.rx_bit_order = lsb_order_ena; +} + +/** + * @brief Configure TX skip mask enable + * + * @param hw Peripheral I2S hardware instance address. + * @param skip_mask_ena Set true to skip inactive channels. + */ +static inline void i2s_ll_tx_set_skip_mask(i2s_dev_t *hw, bool skip_mask_ena) +{ + hw->tx_tdm_ctrl.tx_tdm_skip_msk_en = skip_mask_ena; +} + + +/** + * @brief Configure single data + * + * @param hw Peripheral I2S hardware instance address. + * @param data Single data to be set + */ +static inline void i2s_ll_set_single_data(i2s_dev_t *hw, uint32_t data) +{ + hw->conf_single_data.val = data; +} + +/** + * @brief Enable TX mono mode + * @note MONO in hardware means only one channel got data, but another doesn't + * MONO in software means two channel share same data + * This function aims to use MONO in software meaning + * so 'tx_mono' and 'tx_chan_equal' should be enabled at the same time + * + * @param hw Peripheral I2S hardware instance address. + * @param mono_ena Set true to enable mono mde. + */ +static inline void i2s_ll_tx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena) +{ + hw->tx_conf.tx_mono = mono_ena; + hw->tx_conf.tx_chan_equal = mono_ena; +} + +/** + * @brief Enable RX mono mode + * + * @param hw Peripheral I2S hardware instance address. + * @param mono_ena Set true to enable mono mde. + */ +static inline void i2s_ll_rx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena) +{ + hw->rx_conf.rx_mono = mono_ena; + hw->rx_conf.rx_mono_fst_vld = mono_ena; +} + +/** + * @brief Enable loopback mode + * + * @param hw Peripheral I2S hardware instance address. + * @param ena Set true to share BCK and WS signal for tx module and rx module. + */ +static inline void i2s_ll_share_bck_ws(i2s_dev_t *hw, bool ena) +{ + hw->tx_conf.sig_loopback = ena; +} + +/** + * @brief PDM TX DMA data take mode + * + * @param hw Peripheral I2S hardware instance address. + * @param is_mono The DMA data only has one slot (mono) or contains two slots (stereo) + * @param is_fst_valid Whether take the DMA data at the first half period + * Only take effet when 'is_mono' is true + */ +static inline void i2s_ll_tx_pdm_dma_take_mode(i2s_dev_t *hw, bool is_mono, bool is_fst_valid) +{ + hw->tx_conf.tx_mono = is_mono; + hw->tx_conf.tx_mono_fst_vld = is_fst_valid; +} + +/** + * @brief PDM TX slot mode + * @note Mode Left Slot Right Slot Chan Mode WS Pol + * ----------------------------------------------------------------- + * Stereo Left Right 0 x + * ----------------------------------------------------------------- + * Mono Left Left 1 0 + * Mono Right Right 2 0 + * Mono Single Right 3 0 + * Mono Left Single 4 0 + * ----------------------------------------------------------------- + * Mono Right Right 1 1 + * Mono Left Left 2 1 + * Mono Left Single 3 1 + * Mono Single Right 4 1 + * @note The 'Single' above means always sending the value of `conf_single_data` reg + * The default value of `conf_single_data` reg is '0', it is not public for now + * + * @param hw Peripheral I2S hardware instance address. + * @param is_mono The DMA data only has one slot (mono) or contains two slots (stereo) + * @param is_copy Whether the un-selected slot copies the data from the selected one + * If not, the un-selected slot will transmit the data from 'conf_single_data' + * @param mask The slot mask to selet the slot + */ +static inline void i2s_ll_tx_pdm_slot_mode(i2s_dev_t *hw, bool is_mono, bool is_copy, i2s_pdm_slot_mask_t mask) +{ + if (is_mono) { + /* The default tx_ws_idle_pol is false */ + if (is_copy) { + hw->tx_conf.tx_chan_mod = mask == I2S_PDM_SLOT_LEFT ? 1 : 2; + } else { + hw->tx_conf.tx_chan_mod = mask == I2S_PDM_SLOT_LEFT ? 4 : 3; + } + } else { + hw->tx_conf.tx_chan_mod = 0; + } +} + +/** + * @brief PDM TX line mode + * @note Mode DAC Mode 2 lines output + * ------------------------------------------- + * PDM codec 0 1 + * DAC 1-line 1 0 + * DAC 2-line 1 1 + * + * @param hw Peripheral I2S hardware instance address. + * @param line_mode PDM TX line mode + */ +static inline void i2s_ll_tx_pdm_line_mode(i2s_dev_t *hw, i2s_pdm_tx_line_mode_t line_mode) +{ + hw->tx_pcm2pdm_conf.tx_pdm_dac_mode_en = line_mode > I2S_PDM_TX_ONE_LINE_CODEC; + hw->tx_pcm2pdm_conf.tx_pdm_dac_2out_en = line_mode != I2S_PDM_TX_ONE_LINE_DAC; +} + +/** + * @brief Reset TX FIFO synchronization counter + * + * @param hw Peripheral I2S hardware instance address. + */ +__attribute__((always_inline)) +static inline void i2s_ll_tx_reset_fifo_sync_counter(i2s_dev_t *hw) +{ + hw->fifo_cnt.tx_fifo_cnt_rst = 1; + hw->fifo_cnt.tx_fifo_cnt_rst = 0; +} + +/** + * @brief Get TX FIFO synchronization count value + * + * @param hw Peripheral I2S hardware instance address. + * @return + * bclk count value + */ +__attribute__((always_inline)) +static inline uint32_t i2s_ll_tx_get_fifo_sync_count(i2s_dev_t *hw) +{ + return hw->fifo_cnt.tx_fifo_cnt; +} + +/** + * @brief Reset TX bclk synchronization counter + * + * @param hw Peripheral I2S hardware instance address. + */ +__attribute__((always_inline)) +static inline void i2s_ll_tx_reset_bclk_sync_counter(i2s_dev_t *hw) +{ + hw->bck_cnt.tx_bck_cnt_rst = 1; + hw->bck_cnt.tx_bck_cnt_rst = 0; +} + +/** + * @brief Get TX bclk synchronization count value + * + * @param hw Peripheral I2S hardware instance address. + * @return + * fifo count value + */ +__attribute__((always_inline)) +static inline uint32_t i2s_ll_tx_get_bclk_sync_count(i2s_dev_t *hw) +{ + return hw->bck_cnt.tx_bck_cnt; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32s2/include/hal/clk_tree_ll.h b/components/hal/esp32s2/include/hal/clk_tree_ll.h index f7d67937ee..b0505b1ce2 100644 --- a/components/hal/esp32s2/include/hal/clk_tree_ll.h +++ b/components/hal/esp32s2/include/hal/clk_tree_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -47,6 +47,15 @@ extern "C" { #define CLK_LL_APLL_CAL_DELAY_2 0x3f #define CLK_LL_APLL_CAL_DELAY_3 0x1f +/* APLL multiplier output frequency range */ +// apll_multiplier_out = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) +#define CLK_LL_APLL_MULTIPLIER_MIN_HZ (350000000) // 350 MHz +#define CLK_LL_APLL_MULTIPLIER_MAX_HZ (500000000) // 500 MHz + +/* APLL output frequency range */ +#define CLK_LL_APLL_MIN_HZ (5303031) // 5.303031 MHz, refer to 'periph_rtc_apll_freq_set' for the calculation +#define CLK_LL_APLL_MAX_HZ (125000000) // 125MHz, refer to 'periph_rtc_apll_freq_set' for the calculation + #define CLK_LL_XTAL32K_CONFIG_DEFAULT() { \ .dac = 3, \ .dres = 3, \ diff --git a/components/hal/esp32s2/include/hal/i2s_ll.h b/components/hal/esp32s2/include/hal/i2s_ll.h index 4b419047e5..2c97bf157a 100644 --- a/components/hal/esp32s2/include/hal/i2s_ll.h +++ b/components/hal/esp32s2/include/hal/i2s_ll.h @@ -18,6 +18,8 @@ #include "hal/misc.h" #include "soc/i2s_periph.h" #include "soc/i2s_struct.h" +#include "soc/system_reg.h" +#include "soc/dport_access.h" #include "hal/i2s_types.h" #include "hal/hal_utils.h" @@ -45,7 +47,7 @@ extern "C" { #define I2S_LL_RX_EVENT_MASK I2S_LL_EVENT_RX_EOF #define I2S_LL_PLL_F160M_CLK_FREQ (160 * 1000000) // PLL_F160M_CLK: 160MHz -#define I2S_LL_DEFAULT_PLL_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT +#define I2S_LL_DEFAULT_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT /** * @brief Enable DMA descriptor owner check @@ -81,31 +83,73 @@ static inline void i2s_ll_dma_enable_eof_on_fifo_empty(i2s_dev_t *hw, bool en) } /** - * @brief I2S module general init, enable I2S clock. + * @brief Enable the bus clock for I2S module * - * @param hw Peripheral I2S hardware instance address. + * @param i2s_id The port id of I2S + * @param enable Set true to enable the buf clock */ -static inline void i2s_ll_enable_clock(i2s_dev_t *hw) +static inline void i2s_ll_enable_bus_clock(int i2s_id, bool enable) { - if (hw->clkm_conf.clk_en == 0) { - hw->clkm_conf.clk_sel = 2; - hw->clkm_conf.clk_en = 1; - hw->conf2.val = 0; + if (enable) { + if (i2s_id == 0) { + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN); + } else { + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S1_CLK_EN); + } + } else { + if (i2s_id == 0) { + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN); + } else { + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S1_CLK_EN); + } } } +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define i2s_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_bus_clock(__VA_ARGS__) + /** - * @brief I2S module disable clock. + * @brief Reset the I2S module + * + * @param i2s_id The port id of I2S + */ +static inline void i2s_ll_reset_register(int i2s_id) +{ + if (i2s_id == 0) { + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST); + } else { + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S1_RST); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S1_RST); + } +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define i2s_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_reset_register(__VA_ARGS__) + +/** + * @brief I2S module general init, enable I2S clock. * * @param hw Peripheral I2S hardware instance address. + * @param enable set true to enable the core clock */ -static inline void i2s_ll_disable_clock(i2s_dev_t *hw) +static inline void i2s_ll_enable_core_clock(i2s_dev_t *hw, bool enable) { - if (hw->clkm_conf.clk_en == 1) { + if (enable && !hw->clkm_conf.clk_en) { + hw->clkm_conf.clk_sel = 2; + hw->clkm_conf.clk_en = 1; + hw->conf2.val = 0; + } else if (!enable && hw->clkm_conf.clk_en) { hw->clkm_conf.clk_en = 0; } } +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define i2s_ll_enable_core_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_core_clock(__VA_ARGS__) + /** * @brief I2S tx msb right enable * diff --git a/components/hal/esp32s3/include/hal/i2s_ll.h b/components/hal/esp32s3/include/hal/i2s_ll.h index 1beb845b2d..89b53f8c24 100644 --- a/components/hal/esp32s3/include/hal/i2s_ll.h +++ b/components/hal/esp32s3/include/hal/i2s_ll.h @@ -17,6 +17,7 @@ #include "hal/assert.h" #include "soc/i2s_periph.h" #include "soc/i2s_struct.h" +#include "soc/system_struct.h" #include "hal/i2s_types.h" #include "hal/hal_utils.h" @@ -35,27 +36,62 @@ extern "C" { #define I2S_LL_CLK_FRAC_DIV_AB_MAX 512 // I2S_MCLK = I2S_SRC_CLK / (N + b/a), the a/b register is 9 bit-width #define I2S_LL_PLL_F160M_CLK_FREQ (160 * 1000000) // PLL_F160M_CLK: 160MHz -#define I2S_LL_DEFAULT_PLL_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT +#define I2S_LL_DEFAULT_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT + + +/** + * @brief Enable the bus clock for I2S module + * + * @param i2s_id The port id of I2S + * @param enable Set true to enable the buf clock + */ +static inline void i2s_ll_enable_bus_clock(int i2s_id, bool enable) +{ + if (i2s_id == 0) { + SYSTEM.perip_clk_en0.i2s0_clk_en = enable; + } else if (i2s_id == 1) { + SYSTEM.perip_clk_en0.i2s1_clk_en = enable; + } +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define i2s_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_bus_clock(__VA_ARGS__) + +/** + * @brief Reset the I2S module + * + * @param i2s_id The port id of I2S + */ +static inline void i2s_ll_reset_register(int i2s_id) +{ + if (i2s_id == 0) { + SYSTEM.perip_rst_en0.i2s0_rst = 1; + SYSTEM.perip_rst_en0.i2s0_rst = 0; + } else if (i2s_id == 1) { + SYSTEM.perip_rst_en0.i2s1_rst = 1; + SYSTEM.perip_rst_en0.i2s1_rst = 0; + } +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define i2s_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_reset_register(__VA_ARGS__) /** * @brief I2S module general init, enable I2S clock. * * @param hw Peripheral I2S hardware instance address. + * @param enable set true to enable the core clock */ -static inline void i2s_ll_enable_clock(i2s_dev_t *hw) +static inline void i2s_ll_enable_core_clock(i2s_dev_t *hw, bool enable) { - hw->tx_clkm_conf.clk_en = 1; + hw->tx_clkm_conf.clk_en = enable; } -/** - * @brief I2S module disable I2S clock. - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_disable_clock(i2s_dev_t *hw) -{ - hw->tx_clkm_conf.clk_en = 0; -} +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define i2s_ll_enable_core_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_core_clock(__VA_ARGS__) /** * @brief Enable I2S tx module clock diff --git a/components/hal/i2s_hal.c b/components/hal/i2s_hal.c index ee3c94c29c..5ea3de62d6 100644 --- a/components/hal/i2s_hal.c +++ b/components/hal/i2s_hal.c @@ -10,7 +10,7 @@ #include "soc/soc.h" #include "hal/i2s_hal.h" -#if SOC_I2S_HW_VERSION_2 && SOC_I2S_SUPPORTS_PDM_TX +#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 * [0]: cut-off frequency; [1]: param0; [2]: param5 */ static const float cut_off_coef[21][3] = { @@ -22,6 +22,22 @@ static const float cut_off_coef[21][3] = { {63, 4, 7}, {58, 5, 6}, {49, 5, 7}, {46, 6, 6}, {35.5, 6, 7}, {23.3, 7, 7} }; + +static void s_i2s_hal_get_cut_off_coef(float freq, uint32_t *param0, uint32_t *param5) +{ + uint8_t cnt = 0; + float min = 1000; + /* Find the closest cut-off frequency and its coefficients */ + for (int i = 0; i < 21; i++) { + float tmp = cut_off_coef[i][0] < freq ? freq - cut_off_coef[i][0] : cut_off_coef[i][0] - freq; + if (tmp < min) { + min = tmp; + cnt = i; + } + } + *param0 = (uint32_t)cut_off_coef[cnt][1]; + *param5 = (uint32_t)cut_off_coef[cnt][2]; +} #endif /** @@ -49,30 +65,38 @@ void i2s_hal_init(i2s_hal_context_t *hal, int port_id) hal->dev = I2S_LL_GET_HW(port_id); } -void i2s_hal_set_tx_clock(i2s_hal_context_t *hal, const i2s_hal_clock_info_t *clk_info, i2s_clock_src_t clk_src) +void _i2s_hal_set_tx_clock(i2s_hal_context_t *hal, const i2s_hal_clock_info_t *clk_info, i2s_clock_src_t clk_src) { - hal_utils_clk_div_t mclk_div = {}; + if (clk_info) { + hal_utils_clk_div_t mclk_div = {}; #if SOC_I2S_HW_VERSION_2 - i2s_ll_tx_enable_clock(hal->dev); - i2s_ll_mclk_bind_to_tx_clk(hal->dev); + i2s_ll_tx_enable_clock(hal->dev); + i2s_ll_mclk_bind_to_tx_clk(hal->dev); #endif - i2s_ll_tx_clk_set_src(hal->dev, clk_src); - 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); + i2s_ll_tx_clk_set_src(hal->dev, clk_src); + 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); + } else { + i2s_ll_tx_clk_set_src(hal->dev, clk_src); + } } -void i2s_hal_set_rx_clock(i2s_hal_context_t *hal, const i2s_hal_clock_info_t *clk_info, i2s_clock_src_t clk_src) +void _i2s_hal_set_rx_clock(i2s_hal_context_t *hal, const i2s_hal_clock_info_t *clk_info, i2s_clock_src_t clk_src) { - hal_utils_clk_div_t mclk_div = {}; + if (clk_info) { + hal_utils_clk_div_t mclk_div = {}; #if SOC_I2S_HW_VERSION_2 - i2s_ll_rx_enable_clock(hal->dev); - i2s_ll_mclk_bind_to_rx_clk(hal->dev); + i2s_ll_rx_enable_clock(hal->dev); + i2s_ll_mclk_bind_to_rx_clk(hal->dev); #endif - i2s_ll_rx_clk_set_src(hal->dev, clk_src); - i2s_hal_calc_mclk_precise_division(clk_info->sclk, clk_info->mclk, &mclk_div); - i2s_ll_rx_set_mclk(hal->dev, &mclk_div); - i2s_ll_rx_set_bck_div_num(hal->dev, clk_info->bclk_div); + i2s_ll_rx_clk_set_src(hal->dev, clk_src); + i2s_hal_calc_mclk_precise_division(clk_info->sclk, clk_info->mclk, &mclk_div); + i2s_ll_rx_set_mclk(hal->dev, &mclk_div); + i2s_ll_rx_set_bck_div_num(hal->dev, clk_info->bclk_div); + } else { + i2s_ll_rx_clk_set_src(hal->dev, clk_src); + } } /*------------------------------------------------------------------------- @@ -183,20 +207,12 @@ void i2s_hal_pdm_set_tx_slot(i2s_hal_context_t *hal, bool is_slave, const i2s_ha i2s_ll_tx_set_ws_idle_pol(hal->dev, false); /* Slot mode seems not take effect according to the test, leave it default here */ i2s_ll_tx_pdm_slot_mode(hal->dev, is_mono, false, I2S_PDM_SLOT_BOTH); - uint8_t cnt = 0; - float min = 1000; - float expt_cut_off = slot_cfg->pdm_tx.hp_cut_off_freq_hz; - /* Find the closest cut-off frequency and its coefficients */ - for (int i = 0; i < 21; i++) { - float tmp = cut_off_coef[i][0] < expt_cut_off ? expt_cut_off - cut_off_coef[i][0] : cut_off_coef[i][0] - expt_cut_off; - if (tmp < min) { - min = tmp; - cnt = i; - } - } + uint32_t param0; + uint32_t param5; + s_i2s_hal_get_cut_off_coef(slot_cfg->pdm_tx.hp_cut_off_freq_hz, ¶m0, ¶m5); i2s_ll_tx_enable_pdm_hp_filter(hal->dev, slot_cfg->pdm_tx.hp_en); - i2s_ll_tx_set_pdm_hp_filter_param0(hal->dev, cut_off_coef[cnt][1]); - i2s_ll_tx_set_pdm_hp_filter_param5(hal->dev, cut_off_coef[cnt][2]); + i2s_ll_tx_set_pdm_hp_filter_param0(hal->dev, param0); + i2s_ll_tx_set_pdm_hp_filter_param5(hal->dev, param5); i2s_ll_tx_set_pdm_sd_dither(hal->dev, slot_cfg->pdm_tx.sd_dither); i2s_ll_tx_set_pdm_sd_dither2(hal->dev, slot_cfg->pdm_tx.sd_dither2); #endif @@ -233,7 +249,18 @@ void i2s_hal_pdm_set_rx_slot(i2s_hal_context_t *hal, bool is_slave, const i2s_ha uint32_t slot_mask = slot_cfg->slot_mode == I2S_SLOT_MODE_STEREO ? I2S_PDM_SLOT_BOTH : slot_cfg->pdm_rx.slot_mask; #endif // SOC_I2S_SUPPORTS_PDM_RX > 1 i2s_ll_rx_set_active_chan_mask(hal->dev, slot_mask); -#endif // SOC_I2S_SUPPORTS_PDM_RX +#endif // SOC_I2S_HW_VERSION_1 + +#if SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER + uint32_t param0; + uint32_t param5; + s_i2s_hal_get_cut_off_coef(slot_cfg->pdm_rx.hp_cut_off_freq_hz, ¶m0, ¶m5); + i2s_ll_rx_enable_pdm_hp_filter(hal->dev, slot_cfg->pdm_rx.hp_en); + i2s_ll_rx_set_pdm_hp_filter_param0(hal->dev, param0); + i2s_ll_rx_set_pdm_hp_filter_param5(hal->dev, param5); + /* Set the amplification number, the default and the minimum value is 1. 0 will mute the channel */ + i2s_ll_rx_set_pdm_amplify_num(hal->dev, slot_cfg->pdm_rx.amplify_num ? slot_cfg->pdm_rx.amplify_num : 1); +#endif // SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER } void i2s_hal_pdm_enable_rx_channel(i2s_hal_context_t *hal) diff --git a/components/hal/include/hal/i2s_hal.h b/components/hal/include/hal/i2s_hal.h index e1286b876f..bfa5dfe1c2 100644 --- a/components/hal/include/hal/i2s_hal.h +++ b/components/hal/include/hal/i2s_hal.h @@ -91,7 +91,13 @@ typedef struct { /* PDM TX configurations */ struct { i2s_pdm_slot_mask_t slot_mask; /*!< Choose the slots to activate */ - } pdm_rx; /*!< Specific configurations for PDM TX mode */ +#if SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER + bool hp_en; /*!< High pass filter enable */ + float hp_cut_off_freq_hz; /*!< High pass filter cut-off frequency, range 23.3Hz ~ 185Hz, see cut-off frequency sheet above */ + uint32_t amplify_num; /*!< The amplification number of the final conversion result */ +#endif // SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER + + } pdm_rx; /*!< Specific configurations for PDM RX mode */ #endif }; @@ -136,20 +142,35 @@ void i2s_hal_calc_mclk_precise_division(uint32_t sclk, uint32_t mclk, hal_utils_ * @brief Set tx channel clock * * @param hal Context of the HAL layer - * @param clk_info clock information + * @param clk_info clock information, if it is NULL, only set the clock source * @param clk_src clock source */ -void i2s_hal_set_tx_clock(i2s_hal_context_t *hal, const i2s_hal_clock_info_t *clk_info, i2s_clock_src_t clk_src); +void _i2s_hal_set_tx_clock(i2s_hal_context_t *hal, const i2s_hal_clock_info_t *clk_info, i2s_clock_src_t clk_src); + +#if SOC_PERIPH_CLK_CTRL_SHARED +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define i2s_hal_set_tx_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; _i2s_hal_set_tx_clock(__VA_ARGS__) +#else +#define i2s_hal_set_tx_clock(...) _i2s_hal_set_tx_clock(__VA_ARGS__) +#endif /** * @brief Set rx channel clock * * @param hal Context of the HAL layer - * @param clk_info clock information + * @param clk_info clock information, if it is NULL, only set the clock source * @param clk_src clock source */ -void i2s_hal_set_rx_clock(i2s_hal_context_t *hal, const i2s_hal_clock_info_t *clk_info, i2s_clock_src_t clk_src); +void _i2s_hal_set_rx_clock(i2s_hal_context_t *hal, const i2s_hal_clock_info_t *clk_info, i2s_clock_src_t clk_src); +#if SOC_PERIPH_CLK_CTRL_SHARED +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define i2s_hal_set_rx_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; _i2s_hal_set_rx_clock(__VA_ARGS__) +#else +#define i2s_hal_set_rx_clock(...) _i2s_hal_set_rx_clock(__VA_ARGS__) +#endif /*------------------------------------------------------------------------- | STD configuration | diff --git a/components/soc/esp32/include/soc/Kconfig.soc_caps.in b/components/soc/esp32/include/soc/Kconfig.soc_caps.in index a3348e6022..0945f539af 100644 --- a/components/soc/esp32/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32/include/soc/Kconfig.soc_caps.in @@ -811,22 +811,6 @@ config SOC_CLK_APLL_SUPPORTED bool default y -config SOC_APLL_MULTIPLIER_OUT_MIN_HZ - int - default 350000000 - -config SOC_APLL_MULTIPLIER_OUT_MAX_HZ - int - default 500000000 - -config SOC_APLL_MIN_HZ - int - default 5303031 - -config SOC_APLL_MAX_HZ - int - default 125000000 - config SOC_CLK_RC_FAST_D256_SUPPORTED bool default y diff --git a/components/soc/esp32/include/soc/soc_caps.h b/components/soc/esp32/include/soc/soc_caps.h index ab27817b34..a3ebb1c9b5 100644 --- a/components/soc/esp32/include/soc/soc_caps.h +++ b/components/soc/esp32/include/soc/soc_caps.h @@ -1,6 +1,6 @@ /* - * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -399,11 +399,6 @@ /*-------------------------- CLOCK SUBSYSTEM CAPS ----------------------------------------*/ #define SOC_CLK_APLL_SUPPORTED (1) -// apll_multiplier_out = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) -#define SOC_APLL_MULTIPLIER_OUT_MIN_HZ (350000000) // 350 MHz -#define SOC_APLL_MULTIPLIER_OUT_MAX_HZ (500000000) // 500 MHz -#define SOC_APLL_MIN_HZ (5303031) // 5.303031 MHz, refer to 'periph_rtc_apll_freq_set' for the calculation -#define SOC_APLL_MAX_HZ (125000000) // 125MHz, refer to 'periph_rtc_apll_freq_set' for the calculation #define SOC_CLK_RC_FAST_D256_SUPPORTED (1) #define SOC_RTC_SLOW_CLK_SUPPORT_RC_FAST_D256 (1) diff --git a/components/soc/esp32c3/i2s_periph.c b/components/soc/esp32c3/i2s_periph.c index 0aad6d6cad..ec14aa72a2 100644 --- a/components/soc/esp32c3/i2s_periph.c +++ b/components/soc/esp32c3/i2s_periph.c @@ -29,7 +29,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { .data_out_sigs[1] = I2SO_SD1_OUT_IDX, .data_in_sig = I2SI_SD_IN_IDX, - .irq = -1, + .irq = ETS_I2S1_INTR_SOURCE, .module = PERIPH_I2S1_MODULE, } }; diff --git a/components/soc/esp32c6/i2s_periph.c b/components/soc/esp32c6/i2s_periph.c index 3965e936ee..cb0a6a14ff 100644 --- a/components/soc/esp32c6/i2s_periph.c +++ b/components/soc/esp32c6/i2s_periph.c @@ -29,7 +29,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { .data_out_sigs[1] = I2SO_SD1_OUT_IDX, .data_in_sig = I2SI_SD_IN_IDX, - .irq = -1, + .irq = ETS_I2S1_INTR_SOURCE, .module = PERIPH_I2S1_MODULE, } }; diff --git a/components/soc/esp32c6/include/soc/i2s_struct.h b/components/soc/esp32c6/include/soc/i2s_struct.h index e2e4de298c..f7b7f069ad 100644 --- a/components/soc/esp32c6/include/soc/i2s_struct.h +++ b/components/soc/esp32c6/include/soc/i2s_struct.h @@ -240,34 +240,6 @@ typedef union { uint32_t val; } i2s_rx_conf1_reg_t; -/** Type of rx_clkm_conf register - * I2S RX clock configure register - */ -typedef union { - struct { - /** rx_clkm_div_num : R/W; bitpos: [7:0]; default: 2; - * Integral I2S clock divider value - */ - uint32_t rx_clkm_div_num:8; - uint32_t reserved_8:18; - /** rx_clk_active : R/W; bitpos: [26]; default: 0; - * I2S Rx module clock enable signal. - */ - uint32_t rx_clk_active:1; - /** rx_clk_sel : R/W; bitpos: [28:27]; default: 0; - * Select I2S Rx module source clock. 0: XTAL clock. 1: PLL240M. 2: PLL160M. 3: I2S_MCLK_in. - */ - uint32_t rx_clk_sel:2; - /** mclk_sel : R/W; bitpos: [29]; default: 0; - * 0: UseI2S Tx module clock as I2S_MCLK_OUT. 1: UseI2S Rx module clock as - * I2S_MCLK_OUT. - */ - uint32_t mclk_sel:1; - uint32_t reserved_30:2; - }; - uint32_t val; -} i2s_rx_clkm_conf_reg_t; - /** Type of tx_pcm2pdm_conf register * I2S TX PCM2PDM configuration register */ @@ -609,37 +581,6 @@ typedef union { uint32_t val; } i2s_tx_conf1_reg_t; -/** Type of tx_clkm_conf register - * I2S TX clock configure register - */ -typedef union { - struct { - /** tx_clkm_div_num : R/W; bitpos: [7:0]; default: 2; - * Integral I2S TX clock divider value. f_I2S_CLK = f_I2S_CLK_S/(N+b/a). There will be - * (a-b) * n-div and b * (n+1)-div. So the average combination will be: for b <= - * a/2, z * [x * n-div + (n+1)-div] + y * n-div. For b > a/2, z * [n-div + x * - * (n+1)-div] + y * (n+1)-div. - */ - uint32_t tx_clkm_div_num:8; - uint32_t reserved_8:18; - /** tx_clk_active : R/W; bitpos: [26]; default: 0; - * I2S Tx module clock enable signal. - */ - uint32_t tx_clk_active:1; - /** tx_clk_sel : R/W; bitpos: [28:27]; default: 0; - * Select I2S Tx module source clock. 0: XTAL clock. 1: PLL240M. 2: PLL160M. 3: - * I2S_MCLK_in. - */ - uint32_t tx_clk_sel:2; - /** clk_en : R/W; bitpos: [29]; default: 0; - * Set this bit to enable clk gate - */ - uint32_t clk_en:1; - uint32_t reserved_30:2; - }; - uint32_t val; -} i2s_tx_clkm_conf_reg_t; - /** Type of tx_tdm_ctrl register * I2S TX TDM mode control register */ @@ -742,36 +683,6 @@ typedef union { /** Group: RX clock and timing registers */ -/** Type of rx_clkm_div_conf register - * I2S RX module clock divider configure register - */ -typedef union { - struct { - /** rx_clkm_div_z : R/W; bitpos: [8:0]; default: 0; - * For b <= a/2, the value of I2S_RX_CLKM_DIV_Z is b. For b > a/2, the value of - * I2S_RX_CLKM_DIV_Z is (a-b). - */ - uint32_t rx_clkm_div_z:9; - /** rx_clkm_div_y : R/W; bitpos: [17:9]; default: 1; - * For b <= a/2, the value of I2S_RX_CLKM_DIV_Y is (a%b) . For b > a/2, the value of - * I2S_RX_CLKM_DIV_Y is (a%(a-b)). - */ - uint32_t rx_clkm_div_y:9; - /** rx_clkm_div_x : R/W; bitpos: [26:18]; default: 0; - * For b <= a/2, the value of I2S_RX_CLKM_DIV_X is (a/b) - 1. For b > a/2, the value - * of I2S_RX_CLKM_DIV_X is (a/(a-b)) - 1. - */ - uint32_t rx_clkm_div_x:9; - /** rx_clkm_div_yn1 : R/W; bitpos: [27]; default: 0; - * For b <= a/2, the value of I2S_RX_CLKM_DIV_YN1 is 0 . For b > a/2, the value of - * I2S_RX_CLKM_DIV_YN1 is 1. - */ - uint32_t rx_clkm_div_yn1:1; - uint32_t reserved_28:4; - }; - uint32_t val; -} i2s_rx_clkm_div_conf_reg_t; - /** Type of rx_timing register * I2S RX timing control register */ @@ -813,36 +724,6 @@ typedef union { /** Group: TX clock and timing registers */ -/** Type of tx_clkm_div_conf register - * I2S TX module clock divider configure register - */ -typedef union { - struct { - /** tx_clkm_div_z : R/W; bitpos: [8:0]; default: 0; - * For b <= a/2, the value of I2S_TX_CLKM_DIV_Z is b. For b > a/2, the value of - * I2S_TX_CLKM_DIV_Z is (a-b). - */ - uint32_t tx_clkm_div_z:9; - /** tx_clkm_div_y : R/W; bitpos: [17:9]; default: 1; - * For b <= a/2, the value of I2S_TX_CLKM_DIV_Y is (a%b) . For b > a/2, the value of - * I2S_TX_CLKM_DIV_Y is (a%(a-b)). - */ - uint32_t tx_clkm_div_y:9; - /** tx_clkm_div_x : R/W; bitpos: [26:18]; default: 0; - * For b <= a/2, the value of I2S_TX_CLKM_DIV_X is (a/b) - 1. For b > a/2, the value - * of I2S_TX_CLKM_DIV_X is (a/(a-b)) - 1. - */ - uint32_t tx_clkm_div_x:9; - /** tx_clkm_div_yn1 : R/W; bitpos: [27]; default: 0; - * For b <= a/2, the value of I2S_TX_CLKM_DIV_YN1 is 0 . For b > a/2, the value of - * I2S_TX_CLKM_DIV_YN1 is 1. - */ - uint32_t tx_clkm_div_yn1:1; - uint32_t reserved_28:4; - }; - uint32_t val; -} i2s_tx_clkm_div_conf_reg_t; - /** Type of tx_timing register * I2S TX timing control register */ @@ -993,10 +874,7 @@ typedef struct i2s_dev_t { volatile i2s_tx_conf_reg_t tx_conf; volatile i2s_rx_conf1_reg_t rx_conf1; volatile i2s_tx_conf1_reg_t tx_conf1; - volatile i2s_rx_clkm_conf_reg_t rx_clkm_conf; - volatile i2s_tx_clkm_conf_reg_t tx_clkm_conf; - volatile i2s_rx_clkm_div_conf_reg_t rx_clkm_div_conf; - volatile i2s_tx_clkm_div_conf_reg_t tx_clkm_div_conf; + uint32_t reserved_030[4]; volatile i2s_tx_pcm2pdm_conf_reg_t tx_pcm2pdm_conf; volatile i2s_tx_pcm2pdm_conf1_reg_t tx_pcm2pdm_conf1; uint32_t reserved_048[2]; diff --git a/components/soc/esp32h2/i2s_periph.c b/components/soc/esp32h2/i2s_periph.c index 4183de00a6..cf70f2cb94 100644 --- a/components/soc/esp32h2/i2s_periph.c +++ b/components/soc/esp32h2/i2s_periph.c @@ -28,7 +28,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { .data_out_sig = I2SO_SD_OUT_IDX, .data_in_sig = I2SI_SD_IN_IDX, - .irq = -1, + .irq = ETS_I2S1_INTR_SOURCE, .module = PERIPH_I2S1_MODULE, } }; diff --git a/components/soc/esp32h2/include/soc/i2s_struct.h b/components/soc/esp32h2/include/soc/i2s_struct.h index f4ac17a3b0..34f876838f 100644 --- a/components/soc/esp32h2/include/soc/i2s_struct.h +++ b/components/soc/esp32h2/include/soc/i2s_struct.h @@ -240,34 +240,6 @@ typedef union { uint32_t val; } i2s_rx_conf1_reg_t; -/** Type of rx_clkm_conf register - * I2S RX clock configure register - */ -typedef union { - struct { - /** rx_clkm_div_num : R/W; bitpos: [7:0]; default: 2; - * Integral I2S clock divider value - */ - uint32_t rx_clkm_div_num:8; - uint32_t reserved_8:18; - /** rx_clk_active : R/W; bitpos: [26]; default: 0; - * I2S Rx module clock enable signal. - */ - uint32_t rx_clk_active:1; - /** rx_clk_sel : R/W; bitpos: [28:27]; default: 0; - * Select I2S Rx module source clock. 0: no clock. 1: APLL. 2: CLK160. 3: I2S_MCLK_in. - */ - uint32_t rx_clk_sel:2; - /** mclk_sel : R/W; bitpos: [29]; default: 0; - * 0: UseI2S Tx module clock as I2S_MCLK_OUT. 1: UseI2S Rx module clock as - * I2S_MCLK_OUT. - */ - uint32_t mclk_sel:1; - uint32_t reserved_30:2; - }; - uint32_t val; -} i2s_rx_clkm_conf_reg_t; - /** Type of tx_pcm2pdm_conf register * I2S TX PCM2PDM configuration register */ @@ -607,37 +579,6 @@ typedef union { uint32_t val; } i2s_tx_conf1_reg_t; -/** Type of tx_clkm_conf register - * I2S TX clock configure register - */ -typedef union { - struct { - /** tx_clkm_div_num : R/W; bitpos: [7:0]; default: 2; - * Integral I2S TX clock divider value. f_I2S_CLK = f_I2S_CLK_S/(N+b/a). There will be - * (a-b) * n-div and b * (n+1)-div. So the average combination will be: for b <= - * a/2, z * [x * n-div + (n+1)-div] + y * n-div. For b > a/2, z * [n-div + x * - * (n+1)-div] + y * (n+1)-div. - */ - uint32_t tx_clkm_div_num:8; - uint32_t reserved_8:18; - /** tx_clk_active : R/W; bitpos: [26]; default: 0; - * I2S Tx module clock enable signal. - */ - uint32_t tx_clk_active:1; - /** tx_clk_sel : R/W; bitpos: [28:27]; default: 0; - * Select I2S Tx module source clock. 0: XTAL clock. 1: APLL. 2: CLK160. 3: - * I2S_MCLK_in. - */ - uint32_t tx_clk_sel:2; - /** clk_en : R/W; bitpos: [29]; default: 0; - * Set this bit to enable clk gate - */ - uint32_t clk_en:1; - uint32_t reserved_30:2; - }; - uint32_t val; -} i2s_tx_clkm_conf_reg_t; - /** Type of tx_tdm_ctrl register * I2S TX TDM mode control register */ @@ -740,36 +681,6 @@ typedef union { /** Group: RX clock and timing registers */ -/** Type of rx_clkm_div_conf register - * I2S RX module clock divider configure register - */ -typedef union { - struct { - /** rx_clkm_div_z : R/W; bitpos: [8:0]; default: 0; - * For b <= a/2, the value of I2S_RX_CLKM_DIV_Z is b. For b > a/2, the value of - * I2S_RX_CLKM_DIV_Z is (a-b). - */ - uint32_t rx_clkm_div_z:9; - /** rx_clkm_div_y : R/W; bitpos: [17:9]; default: 1; - * For b <= a/2, the value of I2S_RX_CLKM_DIV_Y is (a%b) . For b > a/2, the value of - * I2S_RX_CLKM_DIV_Y is (a%(a-b)). - */ - uint32_t rx_clkm_div_y:9; - /** rx_clkm_div_x : R/W; bitpos: [26:18]; default: 0; - * For b <= a/2, the value of I2S_RX_CLKM_DIV_X is (a/b) - 1. For b > a/2, the value - * of I2S_RX_CLKM_DIV_X is (a/(a-b)) - 1. - */ - uint32_t rx_clkm_div_x:9; - /** rx_clkm_div_yn1 : R/W; bitpos: [27]; default: 0; - * For b <= a/2, the value of I2S_RX_CLKM_DIV_YN1 is 0 . For b > a/2, the value of - * I2S_RX_CLKM_DIV_YN1 is 1. - */ - uint32_t rx_clkm_div_yn1:1; - uint32_t reserved_28:4; - }; - uint32_t val; -} i2s_rx_clkm_div_conf_reg_t; - /** Type of rx_timing register * I2S RX timing control register */ @@ -811,36 +722,6 @@ typedef union { /** Group: TX clock and timing registers */ -/** Type of tx_clkm_div_conf register - * I2S TX module clock divider configure register - */ -typedef union { - struct { - /** tx_clkm_div_z : R/W; bitpos: [8:0]; default: 0; - * For b <= a/2, the value of I2S_TX_CLKM_DIV_Z is b. For b > a/2, the value of - * I2S_TX_CLKM_DIV_Z is (a-b). - */ - uint32_t tx_clkm_div_z:9; - /** tx_clkm_div_y : R/W; bitpos: [17:9]; default: 1; - * For b <= a/2, the value of I2S_TX_CLKM_DIV_Y is (a%b) . For b > a/2, the value of - * I2S_TX_CLKM_DIV_Y is (a%(a-b)). - */ - uint32_t tx_clkm_div_y:9; - /** tx_clkm_div_x : R/W; bitpos: [26:18]; default: 0; - * For b <= a/2, the value of I2S_TX_CLKM_DIV_X is (a/b) - 1. For b > a/2, the value - * of I2S_TX_CLKM_DIV_X is (a/(a-b)) - 1. - */ - uint32_t tx_clkm_div_x:9; - /** tx_clkm_div_yn1 : R/W; bitpos: [27]; default: 0; - * For b <= a/2, the value of I2S_TX_CLKM_DIV_YN1 is 0 . For b > a/2, the value of - * I2S_TX_CLKM_DIV_YN1 is 1. - */ - uint32_t tx_clkm_div_yn1:1; - uint32_t reserved_28:4; - }; - uint32_t val; -} i2s_tx_clkm_div_conf_reg_t; - /** Type of tx_timing register * I2S TX timing control register */ @@ -991,10 +872,7 @@ typedef struct { volatile i2s_tx_conf_reg_t tx_conf; volatile i2s_rx_conf1_reg_t rx_conf1; volatile i2s_tx_conf1_reg_t tx_conf1; - volatile i2s_rx_clkm_conf_reg_t rx_clkm_conf; - volatile i2s_tx_clkm_conf_reg_t tx_clkm_conf; - volatile i2s_rx_clkm_div_conf_reg_t rx_clkm_div_conf; - volatile i2s_tx_clkm_div_conf_reg_t tx_clkm_div_conf; + uint32_t reserved_030[4]; volatile i2s_tx_pcm2pdm_conf_reg_t tx_pcm2pdm_conf; volatile i2s_tx_pcm2pdm_conf1_reg_t tx_pcm2pdm_conf1; uint32_t reserved_048[2]; diff --git a/components/soc/esp32p4/i2s_periph.c b/components/soc/esp32p4/i2s_periph.c index 1e466a3433..39078caab4 100644 --- a/components/soc/esp32p4/i2s_periph.c +++ b/components/soc/esp32p4/i2s_periph.c @@ -11,4 +11,76 @@ Bunch of constants for every I2S peripheral: GPIO signals, irqs, hw addr of registers etc */ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { + [0] = { + .mck_out_sig = I2S0_MCLK_PAD_OUT_IDX, + .mck_in_sig = I2S0_MCLK_PAD_IN_IDX, + + .m_tx_bck_sig = I2S0_O_BCK_PAD_OUT_IDX, + .m_rx_bck_sig = I2S0_I_BCK_PAD_OUT_IDX, + .m_tx_ws_sig = I2S0_O_WS_PAD_OUT_IDX, + .m_rx_ws_sig = I2S0_I_WS_PAD_OUT_IDX, + + .s_tx_bck_sig = I2S0_O_BCK_PAD_IN_IDX, + .s_rx_bck_sig = I2S0_I_BCK_PAD_IN_IDX, + .s_tx_ws_sig = I2S0_O_WS_PAD_IN_IDX, + .s_rx_ws_sig = I2S0_I_WS_PAD_IN_IDX, + + .data_out_sigs[0] = I2S0_O_SD_PAD_OUT_IDX, + .data_out_sigs[1] = I2S0_O_SD1_PAD_OUT_IDX, + .data_in_sigs[0] = I2S0_I_SD_PAD_IN_IDX, + .data_in_sigs[1] = I2S0_I_SD1_PAD_IN_IDX, + .data_in_sigs[2] = I2S0_I_SD2_PAD_IN_IDX, + .data_in_sigs[3] = I2S0_I_SD3_PAD_IN_IDX, + + .irq = ETS_I2S0_INTR_SOURCE, + .module = PERIPH_I2S0_MODULE, + }, + [1] = { + .mck_out_sig = I2S1_MCLK_PAD_OUT_IDX, + .mck_in_sig = I2S1_MCLK_PAD_IN_IDX, + + .m_tx_bck_sig = I2S1_O_BCK_PAD_OUT_IDX, + .m_rx_bck_sig = I2S1_I_BCK_PAD_OUT_IDX, + .m_tx_ws_sig = I2S1_O_WS_PAD_OUT_IDX, + .m_rx_ws_sig = I2S1_I_WS_PAD_OUT_IDX, + + .s_tx_bck_sig = I2S1_O_BCK_PAD_IN_IDX, + .s_rx_bck_sig = I2S1_I_BCK_PAD_IN_IDX, + .s_tx_ws_sig = I2S1_O_WS_PAD_IN_IDX, + .s_rx_ws_sig = I2S1_I_WS_PAD_IN_IDX, + + .data_out_sigs[0] = I2S1_O_SD_PAD_OUT_IDX, + .data_out_sigs[1] = -1, + .data_in_sigs[0] = I2S1_I_SD_PAD_IN_IDX, + .data_in_sigs[1] = -1, + .data_in_sigs[2] = -1, + .data_in_sigs[3] = -1, + + .irq = ETS_I2S1_INTR_SOURCE, + .module = PERIPH_I2S1_MODULE, + }, + [2] = { + .mck_out_sig = I2S2_MCLK_PAD_OUT_IDX, + .mck_in_sig = I2S2_MCLK_PAD_IN_IDX, + + .m_tx_bck_sig = I2S2_O_BCK_PAD_OUT_IDX, + .m_rx_bck_sig = I2S2_I_BCK_PAD_OUT_IDX, + .m_tx_ws_sig = I2S2_O_WS_PAD_OUT_IDX, + .m_rx_ws_sig = I2S2_I_WS_PAD_OUT_IDX, + + .s_tx_bck_sig = I2S2_O_BCK_PAD_IN_IDX, + .s_rx_bck_sig = I2S2_I_BCK_PAD_IN_IDX, + .s_tx_ws_sig = I2S2_O_WS_PAD_IN_IDX, + .s_rx_ws_sig = I2S2_I_WS_PAD_IN_IDX, + + .data_out_sigs[0] = I2S2_O_SD_PAD_OUT_IDX, + .data_out_sigs[1] = -1, + .data_in_sigs[0] = I2S2_I_SD_PAD_IN_IDX, + .data_in_sigs[1] = -1, + .data_in_sigs[2] = -1, + .data_in_sigs[3] = -1, + + .irq = ETS_I2S2_INTR_SOURCE, + .module = PERIPH_I2S2_MODULE, + }, }; diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index 6e71422bd9..fbc3963a49 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -67,6 +67,10 @@ config SOC_RMT_SUPPORTED bool default y +config SOC_I2S_SUPPORTED + bool + default y + config SOC_I2C_SUPPORTED bool default y @@ -433,7 +437,7 @@ config SOC_I2C_SUPPORT_RTC config SOC_I2S_NUM int - default 1 + default 3 config SOC_I2S_HW_VERSION_2 bool @@ -443,7 +447,7 @@ config SOC_I2S_SUPPORTS_XTAL bool default y -config SOC_I2S_SUPPORTS_PLL_F160M +config SOC_I2S_SUPPORTS_APLL bool default y @@ -451,10 +455,42 @@ config SOC_I2S_SUPPORTS_PCM bool default y +config SOC_I2S_SUPPORTS_PDM + bool + default y + +config SOC_I2S_SUPPORTS_PDM_TX + bool + default y + +config SOC_I2S_SUPPORTS_PDM_RX + bool + default y + +config SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER + bool + default y + +config SOC_I2S_SUPPORTS_TX_SYNC_CNT + bool + default y + +config SOC_I2S_SUPPORTS_TDM + bool + default y + config SOC_I2S_PDM_MAX_TX_LINES int default 2 +config SOC_I2S_PDM_MAX_RX_LINES + int + default 4 + +config SOC_I2S_TDM_FULL_DATA_WIDTH + bool + default y + config SOC_LEDC_SUPPORT_PLL_DIV_CLOCK bool default y @@ -1095,6 +1131,10 @@ config SOC_MODEM_CLOCK_IS_INDEPENDENT bool default n +config SOC_CLK_APLL_SUPPORTED + bool + default y + config SOC_CLK_XTAL32K_SUPPORTED bool default y diff --git a/components/soc/esp32p4/include/soc/clk_tree_defs.h b/components/soc/esp32p4/include/soc/clk_tree_defs.h index 32e27ca898..664e5d4b7b 100644 --- a/components/soc/esp32p4/include/soc/clk_tree_defs.h +++ b/components/soc/esp32p4/include/soc/clk_tree_defs.h @@ -150,6 +150,7 @@ typedef enum { SOC_MOD_CLK_XTAL32K, /*!< XTAL32K_CLK comes from the external 32kHz crystal, passing a clock gating to the peripherals */ SOC_MOD_CLK_RC_FAST, /*!< RC_FAST_CLK comes from the internal 20MHz rc oscillator, passing a clock gating to the peripherals */ SOC_MOD_CLK_XTAL, /*!< XTAL_CLK comes from the external 40MHz crystal */ + SOC_MOD_CLK_APLL, /*!< Audio PLL is sourced from PLL, and its frequency is configurable through APLL configuration registers */ SOC_MOD_CLK_INVALID, /*!< Indication of the end of the available module clock sources */ } soc_module_clk_t; @@ -334,6 +335,21 @@ typedef enum { ///////////////////////////////////////////////// I2S ////////////////////////////////////////////////////////////// +/** + * @brief Array initializer for all supported clock sources of I2S + */ +#define SOC_I2S_CLKS {SOC_MOD_CLK_XTAL, SOC_MOD_CLK_APLL, I2S_CLK_SRC_EXTERNAL} + +/** + * @brief I2S clock source enum + */ +typedef enum { + I2S_CLK_SRC_DEFAULT = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the default source clock */ + I2S_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */ + I2S_CLK_SRC_APLL = SOC_MOD_CLK_APLL, /*!< Select APLL as the source clock */ + I2S_CLK_SRC_EXTERNAL = -1, /*!< Select external clock as source clock */ +} soc_periph_i2s_clk_src_t; + /////////////////////////////////////////////////I2C//////////////////////////////////////////////////////////////////// /** diff --git a/components/soc/esp32p4/include/soc/i2s_struct.h b/components/soc/esp32p4/include/soc/i2s_struct.h index 87b35a0da7..6e05f6a2eb 100644 --- a/components/soc/esp32p4/include/soc/i2s_struct.h +++ b/components/soc/esp32p4/include/soc/i2s_struct.h @@ -277,6 +277,92 @@ typedef union { uint32_t val; } i2s_rx_pdm2pcm_conf_reg_t; +/** Type of tx_pcm2pdm_conf register + * I2S TX PCM2PDM configuration register + */ +typedef union { + struct { + /** tx_pdm_hp_bypass : R/W; bitpos: [0]; default: 0; + * I2S TX PDM bypass hp filter or not. The option has been removed. + */ + uint32_t tx_pdm_hp_bypass:1; + /** tx_pdm_sinc_osr2 : R/W; bitpos: [4:1]; default: 2; + * I2S TX PDM OSR2 value + */ + uint32_t tx_pdm_sinc_osr2:4; + /** tx_pdm_prescale : R/W; bitpos: [12:5]; default: 0; + * I2S TX PDM prescale for sigmadelta + */ + uint32_t tx_pdm_prescale:8; + /** tx_pdm_hp_in_shift : R/W; bitpos: [14:13]; default: 1; + * I2S TX PDM sigmadelta scale shift number: 0:/2 , 1:x1 , 2:x2 , 3: x4 + */ + uint32_t tx_pdm_hp_in_shift:2; + /** tx_pdm_lp_in_shift : R/W; bitpos: [16:15]; default: 1; + * I2S TX PDM sigmadelta scale shift number: 0:/2 , 1:x1 , 2:x2 , 3: x4 + */ + uint32_t tx_pdm_lp_in_shift:2; + /** tx_pdm_sinc_in_shift : R/W; bitpos: [18:17]; default: 1; + * I2S TX PDM sigmadelta scale shift number: 0:/2 , 1:x1 , 2:x2 , 3: x4 + */ + uint32_t tx_pdm_sinc_in_shift:2; + /** tx_pdm_sigmadelta_in_shift : R/W; bitpos: [20:19]; default: 1; + * I2S TX PDM sigmadelta scale shift number: 0:/2 , 1:x1 , 2:x2 , 3: x4 + */ + uint32_t tx_pdm_sigmadelta_in_shift:2; + /** tx_pdm_sigmadelta_dither2 : R/W; bitpos: [21]; default: 0; + * I2S TX PDM sigmadelta dither2 value + */ + uint32_t tx_pdm_sigmadelta_dither2:1; + /** tx_pdm_sigmadelta_dither : R/W; bitpos: [22]; default: 1; + * I2S TX PDM sigmadelta dither value + */ + uint32_t tx_pdm_sigmadelta_dither:1; + /** tx_pdm_dac_2out_en : R/W; bitpos: [23]; default: 0; + * I2S TX PDM dac mode enable + */ + uint32_t tx_pdm_dac_2out_en:1; + /** tx_pdm_dac_mode_en : R/W; bitpos: [24]; default: 0; + * I2S TX PDM dac 2channel enable + */ + uint32_t tx_pdm_dac_mode_en:1; + /** pcm2pdm_conv_en : R/W; bitpos: [25]; default: 0; + * I2S TX PDM Converter enable + */ + uint32_t pcm2pdm_conv_en:1; + uint32_t reserved_26:6; + }; + uint32_t val; +} i2s_tx_pcm2pdm_conf_reg_t; + +/** Type of tx_pcm2pdm_conf1 register + * I2S TX PCM2PDM configuration register + */ +typedef union { + struct { + /** tx_pdm_fp : R/W; bitpos: [9:0]; default: 960; + * I2S TX PDM Fp + */ + uint32_t tx_pdm_fp:10; + /** tx_pdm_fs : R/W; bitpos: [19:10]; default: 480; + * I2S TX PDM Fs + */ + uint32_t tx_pdm_fs:10; + /** tx_iir_hp_mult12_5 : R/W; bitpos: [22:20]; default: 7; + * The fourth parameter of PDM TX IIR_HP filter stage 2 is (504 + + * I2S_TX_IIR_HP_MULT12_5[2:0]) + */ + uint32_t tx_iir_hp_mult12_5:3; + /** tx_iir_hp_mult12_0 : R/W; bitpos: [25:23]; default: 7; + * The fourth parameter of PDM TX IIR_HP filter stage 1 is (504 + + * I2S_TX_IIR_HP_MULT12_0[2:0]) + */ + uint32_t tx_iir_hp_mult12_0:3; + uint32_t reserved_26:6; + }; + uint32_t val; +} i2s_tx_pcm2pdm_conf1_reg_t; + /** Type of rx_tdm_ctrl register * I2S TX TDM mode control register */ @@ -371,7 +457,7 @@ typedef union { uint32_t val; } i2s_rx_tdm_ctrl_reg_t; -/** Type of rxeof_num register +/** Type of rx_eof_num register * I2S RX data number control register. */ typedef union { @@ -384,7 +470,7 @@ typedef union { uint32_t reserved_12:20; }; uint32_t val; -} i2s_rxeof_num_reg_t; +} i2s_rx_eof_num_reg_t; /** Group: TX Control and configuration registers */ @@ -530,89 +616,6 @@ typedef union { uint32_t val; } i2s_tx_conf1_reg_t; -/** Type of tx_pcm2pdm_conf register - * I2S TX PCM2PDM configuration register - */ -typedef union { - struct { - uint32_t reserved_0:1; - /** tx_pdm_sinc_osr2 : R/W; bitpos: [4:1]; default: 2; - * I2S TX PDM OSR2 value - */ - uint32_t tx_pdm_sinc_osr2:4; - /** tx_pdm_prescale : R/W; bitpos: [12:5]; default: 0; - * I2S TX PDM prescale for sigmadelta - */ - uint32_t tx_pdm_prescale:8; - /** tx_pdm_hp_in_shift : R/W; bitpos: [14:13]; default: 1; - * I2S TX PDM sigmadelta scale shift number: 0:/2 , 1:x1 , 2:x2 , 3: x4 - */ - uint32_t tx_pdm_hp_in_shift:2; - /** tx_pdm_lp_in_shift : R/W; bitpos: [16:15]; default: 1; - * I2S TX PDM sigmadelta scale shift number: 0:/2 , 1:x1 , 2:x2 , 3: x4 - */ - uint32_t tx_pdm_lp_in_shift:2; - /** tx_pdm_sinc_in_shift : R/W; bitpos: [18:17]; default: 1; - * I2S TX PDM sigmadelta scale shift number: 0:/2 , 1:x1 , 2:x2 , 3: x4 - */ - uint32_t tx_pdm_sinc_in_shift:2; - /** tx_pdm_sigmadelta_in_shift : R/W; bitpos: [20:19]; default: 1; - * I2S TX PDM sigmadelta scale shift number: 0:/2 , 1:x1 , 2:x2 , 3: x4 - */ - uint32_t tx_pdm_sigmadelta_in_shift:2; - /** tx_pdm_sigmadelta_dither2 : R/W; bitpos: [21]; default: 0; - * I2S TX PDM sigmadelta dither2 value - */ - uint32_t tx_pdm_sigmadelta_dither2:1; - /** tx_pdm_sigmadelta_dither : R/W; bitpos: [22]; default: 1; - * I2S TX PDM sigmadelta dither value - */ - uint32_t tx_pdm_sigmadelta_dither:1; - /** tx_pdm_dac_2out_en : R/W; bitpos: [23]; default: 0; - * I2S TX PDM dac mode enable - */ - uint32_t tx_pdm_dac_2out_en:1; - /** tx_pdm_dac_mode_en : R/W; bitpos: [24]; default: 0; - * I2S TX PDM dac 2channel enable - */ - uint32_t tx_pdm_dac_mode_en:1; - /** pcm2pdm_conv_en : R/W; bitpos: [25]; default: 0; - * I2S TX PDM Converter enable - */ - uint32_t pcm2pdm_conv_en:1; - uint32_t reserved_26:6; - }; - uint32_t val; -} i2s_tx_pcm2pdm_conf_reg_t; - -/** Type of tx_pcm2pdm_conf1 register - * I2S TX PCM2PDM configuration register - */ -typedef union { - struct { - /** tx_pdm_fp : R/W; bitpos: [9:0]; default: 960; - * I2S TX PDM Fp - */ - uint32_t tx_pdm_fp:10; - /** tx_pdm_fs : R/W; bitpos: [19:10]; default: 480; - * I2S TX PDM Fs - */ - uint32_t tx_pdm_fs:10; - /** tx_iir_hp_mult12_5 : R/W; bitpos: [22:20]; default: 7; - * The fourth parameter of PDM TX IIR_HP filter stage 2 is (504 + - * I2S_TX_IIR_HP_MULT12_5[2:0]) - */ - uint32_t tx_iir_hp_mult12_5:3; - /** tx_iir_hp_mult12_0 : R/W; bitpos: [25:23]; default: 7; - * The fourth parameter of PDM TX IIR_HP filter stage 1 is (504 + - * I2S_TX_IIR_HP_MULT12_0[2:0]) - */ - uint32_t tx_iir_hp_mult12_0:3; - uint32_t reserved_26:6; - }; - uint32_t val; -} i2s_tx_pcm2pdm_conf1_reg_t; - /** Type of tx_tdm_ctrl register * I2S TX TDM mode control register */ @@ -845,7 +848,7 @@ typedef union { uint32_t val; } i2s_lc_hung_conf_reg_t; -/** Type of conf_sigle_data register +/** Type of conf_single_data register * I2S signal data register */ typedef union { @@ -856,7 +859,7 @@ typedef union { uint32_t single_data:32; }; uint32_t val; -} i2s_conf_sigle_data_reg_t; +} i2s_conf_single_data_reg_t; /** Group: TX status registers */ @@ -986,8 +989,8 @@ typedef struct { volatile i2s_rx_timing_reg_t rx_timing; volatile i2s_tx_timing_reg_t tx_timing; volatile i2s_lc_hung_conf_reg_t lc_hung_conf; - volatile i2s_rxeof_num_reg_t rxeof_num; - volatile i2s_conf_sigle_data_reg_t conf_sigle_data; + volatile i2s_rx_eof_num_reg_t rx_eof_num; + volatile i2s_conf_single_data_reg_t conf_single_data; volatile i2s_state_reg_t state; volatile i2s_etm_conf_reg_t etm_conf; volatile i2s_fifo_cnt_reg_t fifo_cnt; @@ -996,6 +999,9 @@ typedef struct { volatile i2s_date_reg_t date; } i2s_dev_t; +extern i2s_dev_t I2S0; +extern i2s_dev_t I2S1; +extern i2s_dev_t I2S2; #ifndef __cplusplus _Static_assert(sizeof(i2s_dev_t) == 0x84, "Invalid size of i2s_dev_t structure"); diff --git a/components/soc/esp32p4/include/soc/rtc.h b/components/soc/esp32p4/include/soc/rtc.h index a27bacea55..f81d22c205 100644 --- a/components/soc/esp32p4/include/soc/rtc.h +++ b/components/soc/esp32p4/include/soc/rtc.h @@ -486,6 +486,44 @@ bool rtc_dig_8m_enabled(void); */ uint32_t rtc_clk_freq_cal(uint32_t cal_val); +/** + * @brief Enable or disable APLL + * + * Output frequency is given by the formula: + * apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2) + * + * The dividend in this expression should be in the range of 240 - 600 MHz. + * + * In rev. 0 of ESP32, sdm0 and sdm1 are unused and always set to 0. + * + * @param enable true to enable, false to disable + */ +void rtc_clk_apll_enable(bool enable); + +/** + * @brief Calculate APLL clock coeffifcients + * + * @param freq expected APLL frequency + * @param o_div frequency divider, 0..31 + * @param sdm0 frequency adjustment parameter, 0..255 + * @param sdm1 frequency adjustment parameter, 0..255 + * @param sdm2 frequency adjustment parameter, 0..63 + * + * @return + * - 0 Failed + * - else Sucess + */ +uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm0, uint32_t *_sdm1, uint32_t *_sdm2); + +/** + * @brief Set APLL clock coeffifcients + * + * @param o_div frequency divider, 0..31 + * @param sdm0 frequency adjustment parameter, 0..255 + * @param sdm1 frequency adjustment parameter, 0..255 + * @param sdm2 frequency adjustment parameter, 0..63 + */ +void rtc_clk_apll_coeff_set(uint32_t o_div, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2); // -------------------------- CLOCK TREE DEFS ALIAS ---------------------------- // **WARNING**: The following are only for backwards compatibility. diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 2e97a113fc..abc8d3f8b9 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -48,8 +48,9 @@ // #define SOC_EFUSE_SUPPORTED 1 //TODO: IDF-7512 #define SOC_RTC_FAST_MEM_SUPPORTED 1 #define SOC_RTC_MEM_SUPPORTED 1 -// #define SOC_I2S_SUPPORTED 1 //TODO: IDF-6508 #define SOC_RMT_SUPPORTED 1 +#define SOC_I2S_SUPPORTED 1 +// #define SOC_RMT_SUPPORTED 1 //TODO: IDF-7476 // #define SOC_SDM_SUPPORTED 1 //TODO: IDF-7551 // #define SOC_GPSPI_SUPPORTED 1 //TODO: IDF-7502, TODO: IDF-7503 // #define SOC_LEDC_SUPPORTED 1 //TODO: IDF-6510 @@ -240,16 +241,20 @@ #define SOC_I2C_SUPPORT_RTC (1) /*-------------------------- I2S CAPS ----------------------------------------*/ -//TODO: IDF-6508 -#define SOC_I2S_NUM (1U) +#define SOC_I2S_NUM (3U) #define SOC_I2S_HW_VERSION_2 (1) #define SOC_I2S_SUPPORTS_XTAL (1) -#define SOC_I2S_SUPPORTS_PLL_F160M (1) +#define SOC_I2S_SUPPORTS_APLL (1) #define SOC_I2S_SUPPORTS_PCM (1) -// #define SOC_I2S_SUPPORTS_PDM (1) -// #define SOC_I2S_SUPPORTS_PDM_TX (1) -#define SOC_I2S_PDM_MAX_TX_LINES (2) -// #define SOC_I2S_SUPPORTS_TDM (1) +#define SOC_I2S_SUPPORTS_PDM (1) +#define SOC_I2S_SUPPORTS_PDM_TX (1) +#define SOC_I2S_SUPPORTS_PDM_RX (1) +#define SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER (1) +#define SOC_I2S_SUPPORTS_TX_SYNC_CNT (1) +#define SOC_I2S_SUPPORTS_TDM (1) +#define SOC_I2S_PDM_MAX_TX_LINES (2) // On I2S0 +#define SOC_I2S_PDM_MAX_RX_LINES (4) // On I2S0 +#define SOC_I2S_TDM_FULL_DATA_WIDTH (1) /*!< No limitation to data bit width when using multiple slots */ /*-------------------------- LEDC CAPS ---------------------------------------*/ #define SOC_LEDC_SUPPORT_PLL_DIV_CLOCK (1) @@ -510,6 +515,7 @@ #define SOC_CLK_RC_FAST_SUPPORT_CALIBRATION (0) #define SOC_MODEM_CLOCK_IS_INDEPENDENT (0) +#define SOC_CLK_APLL_SUPPORTED (1) /*!< Support Audio PLL */ #define SOC_CLK_XTAL32K_SUPPORTED (1) /*!< Support to connect an external low frequency crystal */ #define SOC_CLK_OSC_SLOW_SUPPORTED (1) /*!< Support to connect an external oscillator, not a crystal */ #define SOC_CLK_RC32K_SUPPORTED (1) /*!< Support an internal 32kHz RC oscillator */ diff --git a/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in index 8643908f4f..f548a06b79 100644 --- a/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in @@ -1035,22 +1035,6 @@ config SOC_CLK_APLL_SUPPORTED bool default y -config SOC_APLL_MULTIPLIER_OUT_MIN_HZ - int - default 350000000 - -config SOC_APLL_MULTIPLIER_OUT_MAX_HZ - int - default 500000000 - -config SOC_APLL_MIN_HZ - int - default 5303031 - -config SOC_APLL_MAX_HZ - int - default 125000000 - config SOC_CLK_RC_FAST_D256_SUPPORTED bool default y diff --git a/components/soc/esp32s2/include/soc/soc_caps.h b/components/soc/esp32s2/include/soc/soc_caps.h index 6a3dff526e..809fb5ffc5 100644 --- a/components/soc/esp32s2/include/soc/soc_caps.h +++ b/components/soc/esp32s2/include/soc/soc_caps.h @@ -446,11 +446,6 @@ /*-------------------------- CLOCK SUBSYSTEM CAPS ----------------------------------------*/ #define SOC_CLK_APLL_SUPPORTED (1) -// apll_multiplier_out = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) -#define SOC_APLL_MULTIPLIER_OUT_MIN_HZ (350000000) // 350 MHz -#define SOC_APLL_MULTIPLIER_OUT_MAX_HZ (500000000) // 500 MHz -#define SOC_APLL_MIN_HZ (5303031) // 5.303031 MHz, refer to 'periph_rtc_apll_freq_set' for the calculation -#define SOC_APLL_MAX_HZ (125000000) // 125MHz, refer to 'periph_rtc_apll_freq_set' for the calculation #define SOC_CLK_RC_FAST_D256_SUPPORTED (1) #define SOC_RTC_SLOW_CLK_SUPPORT_RC_FAST_D256 (1) diff --git a/components/soc/esp32s3/i2s_periph.c b/components/soc/esp32s3/i2s_periph.c index 4966264483..853541bd9e 100644 --- a/components/soc/esp32s3/i2s_periph.c +++ b/components/soc/esp32s3/i2s_periph.c @@ -32,7 +32,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { .data_in_sigs[2] = I2S0I_SD2_IN_IDX, .data_in_sigs[3] = I2S0I_SD3_IN_IDX, - .irq = -1, + .irq = ETS_I2S0_INTR_SOURCE, .module = PERIPH_I2S0_MODULE, }, { @@ -56,7 +56,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { .data_in_sigs[2] = -1, .data_in_sigs[3] = -1, - .irq = -1, + .irq = ETS_I2S1_INTR_SOURCE, .module = PERIPH_I2S1_MODULE, } }; diff --git a/docs/docs_not_updated/esp32h2.txt b/docs/docs_not_updated/esp32h2.txt index a0fd1f872f..fb3d48388c 100644 --- a/docs/docs_not_updated/esp32h2.txt +++ b/docs/docs_not_updated/esp32h2.txt @@ -3,7 +3,6 @@ api-guides/coexist api-guides/cplusplus api-guides/dfu api-guides/index -api-reference/peripherals/i2s api-reference/peripherals/spi_features api-reference/peripherals/sdio_slave api-reference/peripherals/adc_calibration diff --git a/docs/docs_not_updated/esp32p4.txt b/docs/docs_not_updated/esp32p4.txt index 839e965ed4..c4061400c6 100644 --- a/docs/docs_not_updated/esp32p4.txt +++ b/docs/docs_not_updated/esp32p4.txt @@ -111,7 +111,6 @@ api-reference/peripherals/gpio.rst api-reference/peripherals/sdspi_host.rst api-reference/peripherals/dac.rst api-reference/peripherals/spi_slave.rst -api-reference/peripherals/i2s.rst api-reference/peripherals/touch_element.rst api-reference/peripherals/lcd.rst api-reference/peripherals/ana_cmpr.rst diff --git a/docs/en/api-reference/peripherals/i2s.rst b/docs/en/api-reference/peripherals/i2s.rst index c379114a3a..071352c3f6 100644 --- a/docs/en/api-reference/peripherals/i2s.rst +++ b/docs/en/api-reference/peripherals/i2s.rst @@ -116,6 +116,7 @@ ESP32-C3 I2S 0 I2S 0 none I2S 0 none none ESP32-C6 I2S 0 I2S 0 none I2S 0 none none ESP32-S3 I2S 0/1 I2S 0 I2S 0 I2S 0/1 none none ESP32-H2 I2S 0 I2S 0 none I2S 0 none none +ESP32-P4 I2S 0~2 I2S 0 I2S 0 I2S 0~2 none none ========= ======== ======== ======== ======== ======== ========== Standard Mode diff --git a/examples/peripherals/.build-test-rules.yml b/examples/peripherals/.build-test-rules.yml index d0face2c1a..d5bc6686d6 100644 --- a/examples/peripherals/.build-test-rules.yml +++ b/examples/peripherals/.build-test-rules.yml @@ -54,27 +54,49 @@ examples/peripherals/i2c/i2c_tools: examples/peripherals/i2s/i2s_basic/i2s_pdm: disable: - - if: SOC_I2S_SUPPORTS_PDM != 1 + - if: SOC_I2S_SUPPORTS_PDM != 1 or IDF_TARGET == "esp32p4" + disable_test: + - if: IDF_TARGET == "esp32p4" + temporary: true + reason: lack of runners examples/peripherals/i2s/i2s_basic/i2s_std: disable: - - if: SOC_I2S_SUPPORTED != 1 + - if: SOC_I2S_SUPPORTED != 1 or IDF_TARGET == "esp32p4" + disable_test: + - if: IDF_TARGET == "esp32p4" + temporary: true + reason: lack of runners examples/peripherals/i2s/i2s_basic/i2s_tdm: disable: - - if: SOC_I2S_SUPPORTS_TDM != 1 + - if: SOC_I2S_SUPPORTS_TDM != 1 or IDF_TARGET == "esp32p4" + disable_test: + - if: IDF_TARGET == "esp32p4" + temporary: true + reason: lack of runners examples/peripherals/i2s/i2s_codec/i2s_es7210_tdm: disable: - if: SOC_I2S_SUPPORTS_TDM != 1 or (SOC_I2C_SUPPORTED != 1 or SOC_GPSPI_SUPPORTED != 1) reason: rely on I2S TDM mode to receive audio, I2C to config es7210 and SPI to save audio to SD card + disable_test: + - if: IDF_TARGET == "esp32p4" + temporary: true + reason: lack of runners examples/peripherals/i2s/i2s_codec/i2s_es8311: disable: - - if: SOC_I2S_SUPPORTED != 1 or SOC_I2C_SUPPORTED != 1 + - if: (SOC_I2S_SUPPORTED != 1 or SOC_I2C_SUPPORTED != 1) reason: rely on I2S STD mode and I2C to config es7210 + disable_test: + - if: IDF_TARGET == "esp32p4" + temporary: true + reason: lack of runners examples/peripherals/i2s/i2s_recorder: + disable: + - if: SOC_SDMMC_HOST_SUPPORTED != 1 or IDF_TARGET == "esp32p4" enable: - if: SOC_I2S_SUPPORTS_PDM_RX > 0 diff --git a/examples/peripherals/i2s/i2s_codec/i2s_es8311/README.md b/examples/peripherals/i2s/i2s_codec/i2s_es8311/README.md index bbfcf8f9f4..7bd46beba2 100644 --- a/examples/peripherals/i2s/i2s_codec/i2s_es8311/README.md +++ b/examples/peripherals/i2s/i2s_codec/i2s_es8311/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | # I2S ES8311 Example