From 0b0f25c30d4309b01692b3fe2c935cc1c64a5793 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Wed, 2 Aug 2023 19:21:54 +0800 Subject: [PATCH] feat(i2s): supported getting the tx sync count and specify interrupt flags --- components/driver/dac/esp32/dac_dma.c | 1 + components/driver/deprecated/i2s_legacy.c | 69 +++-- components/driver/i2s/i2s_common.c | 123 ++++++-- components/driver/i2s/i2s_pdm.c | 20 +- components/driver/i2s/i2s_private.h | 16 +- components/driver/i2s/i2s_std.c | 13 +- components/driver/i2s/i2s_tdm.c | 17 +- .../driver/i2s/include/driver/i2s_common.h | 2 + .../driver/i2s/include/driver/i2s_pdm.h | 40 +-- .../driver/include/esp_private/i2s_sync.h | 71 +++++ .../driver/test_apps/.build-test-rules.yml | 16 + .../test_apps/i2s_test_apps/i2s/README.md | 4 +- .../i2s_test_apps/i2s/main/test_i2s.c | 9 +- .../i2s_test_apps/i2s/main/test_i2s_iram.c | 23 +- .../i2s_test_apps/i2s_multi_dev/README.md | 4 +- .../i2s_test_apps/legacy_i2s_driver/README.md | 4 +- .../i2s_test_apps/test_inc/test_i2s.h | 10 +- components/hal/esp32/include/hal/i2s_ll.h | 23 ++ components/hal/esp32c3/include/hal/i2s_ll.h | 23 ++ components/hal/esp32c6/include/hal/i2s_ll.h | 8 +- components/hal/esp32h2/include/hal/i2s_ll.h | 8 +- .../hal/esp32p4/include/hal/clk_gate_ll.h | 16 - .../hal/esp32p4/include/{ => hal}/i2s_ll.h | 290 ++++++++++++++---- components/hal/esp32s2/include/hal/i2s_ll.h | 24 ++ components/hal/esp32s3/include/hal/i2s_ll.h | 33 ++ components/hal/i2s_hal.c | 2 +- components/soc/esp32c3/i2s_periph.c | 2 +- components/soc/esp32c6/i2s_periph.c | 2 +- components/soc/esp32h2/i2s_periph.c | 2 +- components/soc/esp32p4/i2s_periph.c | 9 +- .../esp32p4/include/soc/Kconfig.soc_caps.in | 12 +- .../soc/esp32p4/include/soc/clk_tree_defs.h | 3 +- components/soc/esp32p4/include/soc/rtc.h | 38 +++ components/soc/esp32p4/include/soc/soc_caps.h | 2 + components/soc/esp32s3/i2s_periph.c | 4 +- examples/peripherals/.build-test-rules.yml | 24 +- .../i2s/i2s_codec/i2s_es8311/README.md | 4 +- 37 files changed, 749 insertions(+), 222 deletions(-) create mode 100644 components/driver/include/esp_private/i2s_sync.h rename components/hal/esp32p4/include/{ => hal}/i2s_ll.h (76%) diff --git a/components/driver/dac/esp32/dac_dma.c b/components/driver/dac/esp32/dac_dma.c index c5f8223a90..b5bd20e9b9 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" diff --git a/components/driver/deprecated/i2s_legacy.c b/components/driver/deprecated/i2s_legacy.c index f687cf9170..9397275979 100644 --- a/components/driver/deprecated/i2s_legacy.c +++ b/components/driver/deprecated/i2s_legacy.c @@ -58,6 +58,14 @@ 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_RCC_IS_INDEPENDENT +#define I2S_RCC_ATOMIC() PERIPH_RCC_ATOMIC() +#define I2S_RCC_ENV_DECLARE (void)__DECLARE_RCC_ATOMIC_ENV +#else +#define I2S_RCC_ATOMIC() +#define I2S_RCC_ENV_DECLARE +#endif + #define I2S_DMA_BUFFER_MAX_SIZE 4092 #if SOC_I2S_SUPPORTS_ADC_DAC @@ -1021,11 +1029,14 @@ 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_RCC_ATOMIC() { + I2S_RCC_ENV_DECLARE; + 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,15 @@ 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_RCC_ATOMIC() { + I2S_RCC_ENV_DECLARE; + // 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); + } } periph_rtc_apll_release(); } @@ -1556,11 +1559,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_RCC_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 */ @@ -1904,8 +1909,9 @@ esp_err_t i2s_platform_acquire_occupation(int id, const char *comp_name) 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)); + I2S_RCC_ATOMIC() { + i2s_ll_enable_clock(I2S_LL_GET_HW(id)); + } } portEXIT_CRITICAL(&i2s_spinlock[id]); return ret; @@ -1920,8 +1926,9 @@ esp_err_t i2s_platform_release_occupation(int 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)); + I2S_RCC_ATOMIC() { + i2s_ll_disable_clock(I2S_LL_GET_HW(id)); + } } portEXIT_CRITICAL(&i2s_spinlock[id]); return ret; diff --git a/components/driver/i2s/i2s_common.c b/components/driver/i2s/i2s_common.c index d1e7f2dbde..41dde28b77 100644 --- a/components/driver/i2s/i2s_common.c +++ b/components/driver/i2s/i2s_common.c @@ -25,6 +25,11 @@ #include "soc/soc_caps.h" #include "hal/gpio_hal.h" #include "hal/i2s_hal.h" +#if CONFIG_IDF_TARGET_ESP32P4 +#include "hal/cache_hal.h" +#include "hal/cache_ll.h" +#include "rom/cache.h" +#endif #if SOC_I2S_SUPPORTS_ADC_DAC #include "hal/adc_ll.h" @@ -35,7 +40,6 @@ #endif #include "esp_private/i2s_platform.h" -#include "esp_private/periph_ctrl.h" #include "esp_private/esp_clk.h" #include "driver/gpio.h" @@ -261,6 +265,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; @@ -330,6 +335,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 CONFIG_IDF_TARGET_ESP32P4 + /* bufsize need to align with cache line size */ + uint32_t alignment = cache_hal_get_cache_line_size(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 +373,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; } @@ -372,13 +400,20 @@ esp_err_t i2s_alloc_dma_desc(i2s_chan_handle_t handle, uint32_t num, uint32_t bu handle->dma.desc_num = num; handle->dma.buf_size = bufsize; +#if SOC_GDMA_TRIG_PERIPH_I2S0_BUS == SOC_GDMA_BUS_AHB + uint32_t alignment = 32; + uint32_t desc_size = alignment; +#else + uint32_t alignment = 4; + uint32_t desc_size = sizeof(lldesc_t); +#endif /* Descriptors must be in the internal RAM */ 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); 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 *) heap_caps_aligned_calloc(alignment, 1, desc_size, I2S_DMA_ALLOC_CAPS); 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 *) heap_caps_aligned_calloc(alignment, 1, bufsize * sizeof(uint8_t), I2S_DMA_ALLOC_CAPS); + 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 CONFIG_IDF_TARGET_ESP32P4 + Cache_WriteBack_Addr(CACHE_MAP_L1_DCACHE, (uint32_t)(handle->dma.desc[i]), desc_size); +#endif } if (handle->dir == I2S_DIR_RX) { i2s_ll_rx_set_eof_num(handle->controller->hal.dev, bufsize); @@ -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 CONFIG_IDF_TARGET_ESP32P4 + Cache_Invalidate_Addr(CACHE_MAP_L1_DCACHE, (uint32_t)finish_desc->buf, handle->dma.buf_size); +#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 CONFIG_IDF_TARGET_ESP32P4 + Cache_WriteBack_Addr(CACHE_MAP_L1_DCACHE, (uint32_t)sent_buf, handle->dma.buf_size); +#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_flags ? handle->intr_flags : ESP_INTR_FLAG_LOWMED; /* Initialize I2S module interrupt */ if (handle->dir == I2S_DIR_TX) { esp_intr_alloc_intrstatus(i2s_periph_signal[port_id].irq, intr_flag, @@ -771,6 +815,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_flags = chan_cfg->intr_flags; 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 +829,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_flags = chan_cfg->intr_flags; 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 +867,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_RCC_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 +1026,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 +1054,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 +1069,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 CONFIG_IDF_TARGET_ESP32P4 + Cache_WriteBack_Addr(CACHE_MAP_L1_DCACHE, (uint32_t)(tx_handle->dma.curr_ptr + tx_handle->dma.rw_pos), (uint32_t)bytes_can_load); +#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 +1082,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 +1129,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 CONFIG_IDF_TARGET_ESP32P4 + Cache_WriteBack_Addr(CACHE_MAP_L1_DCACHE, (uint32_t)data_ptr, (uint32_t)bytes_can_write); +#endif size -= bytes_can_write; src_byte += bytes_can_write; handle->dma.rw_pos += bytes_can_write; @@ -1146,8 +1201,9 @@ esp_err_t i2s_platform_acquire_occupation(int id, const char *comp_name) 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)); + I2S_RCC_ATOMIC() { + i2s_ll_enable_clock(I2S_LL_GET_HW(id)); + } } else { occupied_comp = g_i2s.comp_name[id]; ret = ESP_ERR_NOT_FOUND; @@ -1167,8 +1223,9 @@ esp_err_t i2s_platform_release_occupation(int id) 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)); + I2S_RCC_ATOMIC() { + i2s_ll_disable_clock(I2S_LL_GET_HW(id)); + } } else { ret = ESP_ERR_INVALID_STATE; } @@ -1183,3 +1240,25 @@ size_t inline i2s_platform_get_dma_buffer_offset(void) * 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); } + +#if SOC_I2S_SUPPORTS_TX_SYNC_CNT +uint32_t i2s_sync_get_bclk_count(i2s_chan_handle_t tx_handle) +{ + return i2s_ll_tx_get_bclk_sync_count(tx_handle->controller->hal.dev); +} + +uint32_t i2s_sync_get_fifo_count(i2s_chan_handle_t tx_handle) +{ + return i2s_ll_tx_get_fifo_sync_count(tx_handle->controller->hal.dev); +} + +void i2s_sync_reset_bclk_count(i2s_chan_handle_t tx_handle) +{ + 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..2426e896fe 100644 --- a/components/driver/i2s/i2s_pdm.c +++ b/components/driver/i2s/i2s_pdm.c @@ -70,7 +70,10 @@ 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_RCC_ATOMIC() { + I2S_RCC_ENV_DECLARE; + 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 +190,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 +357,10 @@ 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_RCC_ATOMIC() { + I2S_RCC_ENV_DECLARE; + 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 +470,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_private.h b/components/driver/i2s/i2s_private.h index 23dfe79f5f..802eb32fbb 100644 --- a/components/driver/i2s/i2s_private.h +++ b/components/driver/i2s/i2s_private.h @@ -16,8 +16,10 @@ #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,22 @@ 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_RCC_IS_INDEPENDENT +#define I2S_RCC_ATOMIC() PERIPH_RCC_ATOMIC() +#define I2S_RCC_ENV_DECLARE (void)__DECLARE_RCC_ATOMIC_ENV +#else +#define I2S_RCC_ATOMIC() +#define I2S_RCC_ENV_DECLARE +#endif + #define I2S_NULL_POINTER_CHECK(tag, p) ESP_RETURN_ON_FALSE((p), ESP_ERR_INVALID_ARG, tag, "input parameter '"#p"' is NULL") /** @@ -61,6 +71,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 +99,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_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 */ diff --git a/components/driver/i2s/i2s_std.c b/components/driver/i2s/i2s_std.c index 2570e3b4b2..0b32139c21 100644 --- a/components/driver/i2s/i2s_std.c +++ b/components/driver/i2s/i2s_std.c @@ -77,10 +77,13 @@ 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_RCC_ATOMIC() { + I2S_RCC_ENV_DECLARE; + 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 +229,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..b4353f8c83 100644 --- a/components/driver/i2s/i2s_tdm.c +++ b/components/driver/i2s/i2s_tdm.c @@ -79,10 +79,13 @@ 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_RCC_ATOMIC() { + I2S_RCC_ENV_DECLARE; + 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 +235,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 +276,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..fb2c99a4f1 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_flags = 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_flags; /*!< Flags used to allocate the interrupt. One or multiple (ORred) ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info */ } 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 d8bd632c99..11601166aa 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, \ + .hpf_en = true, \ + .hpf_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,23 +66,7 @@ extern "C" { .bclk_div = 8, \ } -#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, \ /* TODO: maybe need an enum */ -} -#endif // SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER + /** * @brief I2S slot configuration for pdm rx mode @@ -329,8 +331,8 @@ typedef struct { i2s_pdm_sig_scale_t sinc_scale; /*!< Sinc filter scaling value */ #if SOC_I2S_HW_VERSION_2 i2s_pdm_tx_line_mode_t line_mode; /*!< PDM TX line mode, one-line codec, one-line dac, two-line dac mode can be selected */ - 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 */ + bool hpf_en; /*!< High pass filter enable */ + float hpf_cut_off_freq_hz; /*!< High pass filter cut-off frequency, range 23.3Hz ~ 185Hz, see cut-off frequency sheet above */ uint32_t sd_dither; /*!< Sigma-delta filter dither */ uint32_t sd_dither2; /*!< Sigma-delta filter dither2 */ #endif // SOC_I2S_HW_VERSION_2 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 a419ea6c2e..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,9 +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)); -#if SOC_I2S_SUPPORTS_PLL_F160M || SOC_I2S_SUPPORTS_PLL_F96M +// ESP32-P4 has no PLL except XTAL +#if !CONFIG_IDF_TARGET_ESP32P4 i2s_test_common_sample_rate(rx_handle, &std_cfg.clk_cfg); -#endif // SOC_I2S_SUPPORTS_PLL_F160M || SOC_I2S_SUPPORTS_PLL_F96M +#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); @@ -882,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/hal/esp32/include/hal/i2s_ll.h b/components/hal/esp32/include/hal/i2s_ll.h index c03f56ce02..d718d17a34 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" @@ -90,12 +91,23 @@ static inline void i2s_ll_dma_enable_eof_on_fifo_empty(i2s_dev_t *hw, bool en) */ static inline void i2s_ll_enable_clock(i2s_dev_t *hw) { + if (hw == &I2S0) { + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST); + } else { + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S1_CLK_EN); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S1_RST); + } if (hw->clkm_conf.clk_en == 0) { hw->clkm_conf.clk_en = 1; hw->conf2.val = 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_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_clock(__VA_ARGS__) + /** * @brief I2S module disable clock. * @@ -106,8 +118,19 @@ static inline void i2s_ll_disable_clock(i2s_dev_t *hw) if (hw->clkm_conf.clk_en == 1) { hw->clkm_conf.clk_en = 0; } + if (hw == &I2S0) { + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN); + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST); + } else { + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S1_CLK_EN); + DPORT_SET_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_disable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_disable_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 1bf9d1ecc4..e79f5ec9c5 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" @@ -43,9 +44,15 @@ extern "C" { */ static inline void i2s_ll_enable_clock(i2s_dev_t *hw) { + SYSTEM.perip_clk_en0.reg_i2s1_clk_en = 1; + SYSTEM.perip_rst_en0.reg_i2s1_rst = 0; hw->tx_clkm_conf.clk_en = 1; } +/// 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_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_clock(__VA_ARGS__) + /** * @brief I2S module disable I2S clock. * @@ -54,8 +61,14 @@ static inline void i2s_ll_enable_clock(i2s_dev_t *hw) static inline void i2s_ll_disable_clock(i2s_dev_t *hw) { hw->tx_clkm_conf.clk_en = 0; + SYSTEM.perip_clk_en0.reg_i2s1_clk_en = 0; + SYSTEM.perip_rst_en0.reg_i2s1_rst = 1; } +/// 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_disable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_disable_clock(__VA_ARGS__) + /** * @brief Enable I2S tx module clock * @@ -86,6 +99,11 @@ static inline void i2s_ll_tx_disable_clock(i2s_dev_t *hw) hw->tx_clkm_conf.tx_clk_active = 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 +// i2s_ll_tx_disable_clock don't need RCC ENV actually, but still defined here for compatiblity +#define i2s_ll_tx_disable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_tx_disable_clock(__VA_ARGS__) + /** * @brief Disable I2S rx module clock * @@ -96,6 +114,11 @@ static inline void i2s_ll_rx_disable_clock(i2s_dev_t *hw) hw->rx_clkm_conf.rx_clk_active = 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 +// i2s_ll_rx_disable_clock don't need RCC ENV actually, but still defined here for compatiblity +#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 * diff --git a/components/hal/esp32c6/include/hal/i2s_ll.h b/components/hal/esp32c6/include/hal/i2s_ll.h index 33da02f677..86c5788fbf 100644 --- a/components/hal/esp32c6/include/hal/i2s_ll.h +++ b/components/hal/esp32c6/include/hal/i2s_ll.h @@ -44,8 +44,8 @@ extern "C" { */ static inline void i2s_ll_enable_clock(i2s_dev_t *hw) { - // The clock gate enabling is moved to `periph_module_enable` - (void)hw; + PCR.i2s_conf.i2s_clk_en = 1; + PCR.i2s_conf.i2s_rst_en = 0; } /** @@ -55,8 +55,8 @@ static inline void i2s_ll_enable_clock(i2s_dev_t *hw) */ static inline void i2s_ll_disable_clock(i2s_dev_t *hw) { - // The clock gate disabling is moved to `periph_module_disable` - (void)hw; + PCR.i2s_conf.i2s_clk_en = 0; + PCR.i2s_conf.i2s_rst_en = 1; } /** diff --git a/components/hal/esp32h2/include/hal/i2s_ll.h b/components/hal/esp32h2/include/hal/i2s_ll.h index c7cd73dd4f..9f9e648ce8 100644 --- a/components/hal/esp32h2/include/hal/i2s_ll.h +++ b/components/hal/esp32h2/include/hal/i2s_ll.h @@ -45,8 +45,8 @@ extern "C" { */ static inline void i2s_ll_enable_clock(i2s_dev_t *hw) { - // The clock gate enabling is moved to `periph_module_enable` - (void)hw; + PCR.i2s_conf.i2s_clk_en = 1; + PCR.i2s_conf.i2s_rst_en = 0; } /** @@ -56,8 +56,8 @@ static inline void i2s_ll_enable_clock(i2s_dev_t *hw) */ static inline void i2s_ll_disable_clock(i2s_dev_t *hw) { - // The clock gate disabling is moved to `periph_module_disable` - (void)hw; + PCR.i2s_conf.i2s_clk_en = 0; + PCR.i2s_conf.i2s_rst_en = 1; } /** 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/i2s_ll.h b/components/hal/esp32p4/include/hal/i2s_ll.h similarity index 76% rename from components/hal/esp32p4/include/i2s_ll.h rename to components/hal/esp32p4/include/hal/i2s_ll.h index c2ce486e04..3d7027ede3 100644 --- a/components/hal/esp32p4/include/i2s_ll.h +++ b/components/hal/esp32p4/include/hal/i2s_ll.h @@ -17,7 +17,7 @@ #include "hal/assert.h" #include "soc/i2s_periph.h" #include "soc/i2s_struct.h" -#include "soc/pcr_struct.h" +#include "soc/hp_sys_clkrst_struct.h" #include "hal/i2s_types.h" @@ -26,6 +26,7 @@ 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) @@ -53,10 +54,30 @@ typedef struct { */ static inline void i2s_ll_enable_clock(i2s_dev_t *hw) { - // The clock gate enabling is moved to `periph_module_enable` - (void)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.soc_clk_ctrl2.reg_i2s0_apb_clk_en = 1; + HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_i2s0_apb = 0; + break; + case 1: + HP_SYS_CLKRST.soc_clk_ctrl2.reg_i2s1_apb_clk_en = 1; + HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_i2s1_apb = 0; + break; + case 2: + HP_SYS_CLKRST.soc_clk_ctrl2.reg_i2s2_apb_clk_en = 1; + HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_i2s2_apb = 0; + break; + default: + // Never reach + HAL_ASSERT(false); + } } +/// 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_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_clock(__VA_ARGS__) + /** * @brief I2S module disable I2S clock. * @@ -64,10 +85,30 @@ static inline void i2s_ll_enable_clock(i2s_dev_t *hw) */ static inline void i2s_ll_disable_clock(i2s_dev_t *hw) { - // The clock gate disabling is moved to `periph_module_disable` - (void)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.soc_clk_ctrl2.reg_i2s0_apb_clk_en = 0; + HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_i2s0_apb = 1; + break; + case 1: + HP_SYS_CLKRST.soc_clk_ctrl2.reg_i2s1_apb_clk_en = 0; + HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_i2s1_apb = 1; + break; + case 2: + HP_SYS_CLKRST.soc_clk_ctrl2.reg_i2s2_apb_clk_en = 0; + HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_i2s2_apb = 1; + break; + default: + // Never reach + HAL_ASSERT(false); + } } +/// 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_disable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_disable_clock(__VA_ARGS__) + /** * @brief Enable I2S tx module clock * @@ -75,8 +116,18 @@ static inline void i2s_ll_disable_clock(i2s_dev_t *hw) */ static inline void i2s_ll_tx_enable_clock(i2s_dev_t *hw) { - (void)hw; - PCR.i2s_tx_clkm_conf.i2s_tx_clkm_en = 1; + // 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; + } } /** @@ -86,8 +137,18 @@ static inline void i2s_ll_tx_enable_clock(i2s_dev_t *hw) */ static inline void i2s_ll_rx_enable_clock(i2s_dev_t *hw) { - (void)hw; - PCR.i2s_rx_clkm_conf.i2s_rx_clkm_en = 1; + // 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; + } } /** @@ -97,10 +158,24 @@ static inline void i2s_ll_rx_enable_clock(i2s_dev_t *hw) */ static inline void i2s_ll_tx_disable_clock(i2s_dev_t *hw) { - (void)hw; - PCR.i2s_tx_clkm_conf.i2s_tx_clkm_en = 0; + // 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 * @@ -108,10 +183,24 @@ static inline void i2s_ll_tx_disable_clock(i2s_dev_t *hw) */ static inline void i2s_ll_rx_disable_clock(i2s_dev_t *hw) { - (void)hw; - PCR.i2s_rx_clkm_conf.i2s_rx_clkm_en = 0; + // 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 * @@ -119,8 +208,18 @@ static inline void i2s_ll_rx_disable_clock(i2s_dev_t *hw) */ static inline void i2s_ll_mclk_bind_to_tx_clk(i2s_dev_t *hw) { - (void)hw; - PCR.i2s_rx_clkm_conf.i2s_mclk_sel = 0; + // 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; + } } /** @@ -130,8 +229,18 @@ static inline void i2s_ll_mclk_bind_to_tx_clk(i2s_dev_t *hw) */ static inline void i2s_ll_mclk_bind_to_rx_clk(i2s_dev_t *hw) { - (void)hw; - PCR.i2s_rx_clkm_conf.i2s_mclk_sel = 1; + // 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; + } } /** @@ -200,6 +309,22 @@ static inline void i2s_ll_rx_reset_fifo(i2s_dev_t *hw) 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"); + break; + } +} + /** * @brief Set TX source clock * @@ -208,18 +333,18 @@ static inline void i2s_ll_rx_reset_fifo(i2s_dev_t *hw) */ static inline void i2s_ll_tx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src) { - (void)hw; - switch (src) - { - case I2S_CLK_SRC_XTAL: - PCR.i2s_tx_clkm_conf.i2s_tx_clkm_sel = 0; - break; - case I2S_CLK_SRC_APLL: - PCR.i2s_tx_clkm_conf.i2s_tx_clkm_sel = 1; - break; - default: - HAL_ASSERT(false && "unsupported clock source"); - break; + // 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; } } @@ -231,18 +356,18 @@ static inline void i2s_ll_tx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src) */ static inline void i2s_ll_rx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src) { - (void)hw; - switch (src) - { - case I2S_CLK_SRC_XTAL: - PCR.i2s_rx_clkm_conf.i2s_rx_clkm_sel = 0; - break; - case I2S_CLK_SRC_APLL: - PCR.i2s_rx_clkm_conf.i2s_rx_clkm_sel = 1; - break; - default: - HAL_ASSERT(false && "unsupported clock source"); - break; + // 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; } } @@ -269,14 +394,30 @@ static inline void i2s_ll_tx_set_bck_div_num(i2s_dev_t *hw, uint32_t val) */ 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) { - (void)hw; - HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.i2s_tx_clkm_conf, i2s_tx_clkm_div_num, div_int); - typeof(PCR.i2s_tx_clkm_div_conf) div = {}; - div.i2s_tx_clkm_div_x = x; - div.i2s_tx_clkm_div_y = y; - div.i2s_tx_clkm_div_z = z; - div.i2s_tx_clkm_div_yn1 = yn1; - PCR.i2s_tx_clkm_div_conf.val = div.val; + // 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; + } } /** @@ -291,14 +432,30 @@ static inline void i2s_ll_tx_set_raw_clk_div(i2s_dev_t *hw, uint32_t div_int, ui */ 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) { - (void)hw; - HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.i2s_rx_clkm_conf, i2s_rx_clkm_div_num, div_int); - typeof(PCR.i2s_rx_clkm_div_conf) div = {}; - div.i2s_rx_clkm_div_x = x; - div.i2s_rx_clkm_div_y = y; - div.i2s_rx_clkm_div_z = z; - div.i2s_rx_clkm_div_yn1 = yn1; - PCR.i2s_rx_clkm_div_conf.val = div.val; + // 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; + } } /** @@ -890,13 +1047,12 @@ static inline uint32_t i2s_ll_tx_get_pdm_fs(i2s_dev_t *hw) * @brief Enable RX PDM mode. * * @param hw Peripheral I2S hardware instance address. - * @param pdm_enable Set true to RX enable PDM mode */ -static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw, bool pdm_enable) +static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw) { - hw->rx_conf.rx_pdm_en = pdm_enable; - hw->rx_conf.rx_tdm_en = !pdm_enable; - hw->rx_pdm2pcm_conf.rx_pdm2pcm_en = pdm_enable; + hw->rx_conf.rx_pdm_en = 1; + hw->rx_conf.rx_tdm_en = 0; + hw->rx_pdm2pcm_conf.rx_pdm2pcm_en = 1; } /** @@ -1198,6 +1354,7 @@ static inline void i2s_ll_tx_pdm_line_mode(i2s_dev_t *hw, i2s_pdm_tx_line_mode_t * * @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; @@ -1209,8 +1366,9 @@ static inline void i2s_ll_tx_reset_fifo_sync_counter(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. * @return - * count value + * 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; @@ -1221,6 +1379,7 @@ static inline uint32_t i2s_ll_tx_get_fifo_sync_count(i2s_dev_t *hw) * * @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; @@ -1232,9 +1391,10 @@ static inline void i2s_ll_tx_reset_bclk_sync_counter(i2s_dev_t *hw) * * @param hw Peripheral I2S hardware instance address. * @return - * count value + * fifo count value */ -static inline void i2s_ll_tx_get_bclk_sync_count(i2s_dev_t *hw) +__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; } diff --git a/components/hal/esp32s2/include/hal/i2s_ll.h b/components/hal/esp32s2/include/hal/i2s_ll.h index 30d481d9c8..f8791f1d19 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" @@ -87,6 +89,13 @@ static inline void i2s_ll_dma_enable_eof_on_fifo_empty(i2s_dev_t *hw, bool en) */ static inline void i2s_ll_enable_clock(i2s_dev_t *hw) { + if (hw == &I2S0) { + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST); + } else { + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S1_CLK_EN); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S1_RST); + } if (hw->clkm_conf.clk_en == 0) { hw->clkm_conf.clk_sel = 2; hw->clkm_conf.clk_en = 1; @@ -94,6 +103,10 @@ static inline void i2s_ll_enable_clock(i2s_dev_t *hw) } } +/// 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_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_clock(__VA_ARGS__) + /** * @brief I2S module disable clock. * @@ -104,8 +117,19 @@ static inline void i2s_ll_disable_clock(i2s_dev_t *hw) if (hw->clkm_conf.clk_en == 1) { hw->clkm_conf.clk_en = 0; } + if (hw == &I2S0) { + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN); + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST); + } else { + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S1_CLK_EN); + DPORT_SET_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_disable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_disable_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 4880c6850d..ac4d99f859 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" @@ -44,9 +45,20 @@ extern "C" { */ static inline void i2s_ll_enable_clock(i2s_dev_t *hw) { + if (hw == &I2S0) { + SYSTEM.perip_clk_en0.i2s0_clk_en = 1; + SYSTEM.perip_rst_en0.i2s0_rst = 0; + } else { + SYSTEM.perip_clk_en0.i2s1_clk_en = 1; + SYSTEM.perip_rst_en0.i2s1_rst = 0; + } hw->tx_clkm_conf.clk_en = 1; } +/// 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_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_clock(__VA_ARGS__) + /** * @brief I2S module disable I2S clock. * @@ -55,8 +67,19 @@ static inline void i2s_ll_enable_clock(i2s_dev_t *hw) static inline void i2s_ll_disable_clock(i2s_dev_t *hw) { hw->tx_clkm_conf.clk_en = 0; + if (hw == &I2S0) { + SYSTEM.perip_clk_en0.i2s0_clk_en = 0; + SYSTEM.perip_rst_en0.i2s0_rst = 1; + } else { + SYSTEM.perip_clk_en0.i2s1_clk_en = 0; + SYSTEM.perip_rst_en0.i2s1_rst = 1; + } } +/// 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_disable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_disable_clock(__VA_ARGS__) + /** * @brief Enable I2S tx module clock * @@ -87,6 +110,11 @@ static inline void i2s_ll_tx_disable_clock(i2s_dev_t *hw) hw->tx_clkm_conf.tx_clk_active = 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 +// i2s_ll_tx_disable_clock don't need RCC ENV actually, but still defined here for compatiblity +#define i2s_ll_tx_disable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_tx_disable_clock(__VA_ARGS__) + /** * @brief Disable I2S rx module clock * @@ -97,6 +125,11 @@ static inline void i2s_ll_rx_disable_clock(i2s_dev_t *hw) hw->rx_clkm_conf.rx_clk_active = 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 +// i2s_ll_rx_disable_clock don't need RCC ENV actually, but still defined here for compatiblity +#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 * diff --git a/components/hal/i2s_hal.c b/components/hal/i2s_hal.c index 1803bd51f8..15653cce84 100644 --- a/components/hal/i2s_hal.c +++ b/components/hal/i2s_hal.c @@ -243,7 +243,7 @@ void i2s_hal_pdm_set_rx_slot(i2s_hal_context_t *hal, bool is_slave, const i2s_ha i2s_ll_rx_set_active_chan_mask(hal->dev, slot_mask); #endif // SOC_I2S_HW_VERSION_1 -#if SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER // TODO: add this macro to soc_caps +#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); 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/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/esp32p4/i2s_periph.c b/components/soc/esp32p4/i2s_periph.c index 66225f77c1..39078caab4 100644 --- a/components/soc/esp32p4/i2s_periph.c +++ b/components/soc/esp32p4/i2s_periph.c @@ -13,6 +13,7 @@ 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, @@ -31,11 +32,12 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { .data_in_sigs[2] = I2S0_I_SD2_PAD_IN_IDX, .data_in_sigs[3] = I2S0_I_SD3_PAD_IN_IDX, - .irq = -1, + .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, @@ -54,11 +56,12 @@ 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, }, [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, @@ -77,7 +80,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_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 28c867a876..fbc3963a49 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -67,11 +67,11 @@ config SOC_RMT_SUPPORTED bool default y -config SOC_I2C_SUPPORTED +config SOC_I2S_SUPPORTED bool default y -config SOC_I2S_SUPPORTED +config SOC_I2C_SUPPORTED bool default y @@ -471,6 +471,10 @@ 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 @@ -1127,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 7137ba4a12..664e5d4b7b 100644 --- a/components/soc/esp32p4/include/soc/clk_tree_defs.h +++ b/components/soc/esp32p4/include/soc/clk_tree_defs.h @@ -338,7 +338,7 @@ typedef enum { /** * @brief Array initializer for all supported clock sources of I2S */ -#define SOC_I2S_CLKS {SOC_MOD_CLK_XTAL, SOC_MOD_CLK_APLL} +#define SOC_I2S_CLKS {SOC_MOD_CLK_XTAL, SOC_MOD_CLK_APLL, I2S_CLK_SRC_EXTERNAL} /** * @brief I2S clock source enum @@ -347,6 +347,7 @@ 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/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 a4343f13d9..984d1526f9 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -251,6 +251,7 @@ #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 @@ -515,6 +516,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/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/examples/peripherals/.build-test-rules.yml b/examples/peripherals/.build-test-rules.yml index 1622658bec..d5bc6686d6 100644 --- a/examples/peripherals/.build-test-rules.yml +++ b/examples/peripherals/.build-test-rules.yml @@ -55,28 +55,48 @@ examples/peripherals/i2c/i2c_tools: examples/peripherals/i2s/i2s_basic/i2s_pdm: disable: - 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 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 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) or IDF_TARGET == "esp32p4" + - 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: IDF_TARGET == "esp32p4" + - 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