From 62ae0efa54a22a6e21e81f0527fd8cbd9862c557 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Mon, 15 Jan 2024 17:33:48 +0800 Subject: [PATCH] feat(i2s): support i2s legacy driver on p4 --- components/driver/deprecated/i2s_legacy.c | 91 +++++++++++++++---- .../driver/test_apps/.build-test-rules.yml | 4 - .../legacy_i2s_driver/main/test_legacy_i2s.c | 8 +- .../legacy_i2s_driver/pytest_legacy_i2s.py | 2 +- .../i2s_test_apps/test_inc/test_i2s.h | 16 ++-- .../test_apps/.build-test-rules.yml | 6 -- .../test_apps/i2s/pytest_i2s.py | 2 +- 7 files changed, 88 insertions(+), 41 deletions(-) diff --git a/components/driver/deprecated/i2s_legacy.c b/components/driver/deprecated/i2s_legacy.c index 172b750c0d..8325646366 100644 --- a/components/driver/deprecated/i2s_legacy.c +++ b/components/driver/deprecated/i2s_legacy.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -29,6 +29,11 @@ #include "hal/clk_tree_ll.h" #endif +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE +#include "hal/cache_hal.h" +#include "hal/cache_ll.h" +#endif + #if SOC_I2S_SUPPORTS_DAC #include "hal/dac_ll.h" #include "hal/dac_types.h" @@ -56,6 +61,12 @@ #include "esp_pm.h" #include "esp_efuse.h" #include "esp_rom_gpio.h" +#include "esp_dma_utils.h" + +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE +#include "esp_cache.h" +#endif + #include "esp_private/i2s_platform.h" #include "esp_private/periph_ctrl.h" #include "esp_private/esp_clk.h" @@ -178,11 +189,14 @@ static bool IRAM_ATTR i2s_dma_rx_callback(gdma_channel_handle_t dma_chan, gdma_e BaseType_t tmp = 0; int dummy; i2s_event_t i2s_event; - uint32_t finish_desc; + lldesc_t *finish_desc; if (p_i2s->rx) { - finish_desc = event_data->rx_eof_desc_addr; - i2s_event.size = ((lldesc_t *)finish_desc)->size; + finish_desc = (lldesc_t *)event_data->rx_eof_desc_addr; +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE + esp_cache_msync((void *)finish_desc->buf, p_i2s->rx->buf_size, ESP_CACHE_MSYNC_FLAG_INVALIDATE); +#endif + i2s_event.size = finish_desc->size; if (xQueueIsQueueFullFromISR(p_i2s->rx->queue)) { xQueueReceiveFromISR(p_i2s->rx->queue, &dummy, &tmp); need_awoke |= tmp; @@ -192,7 +206,7 @@ static bool IRAM_ATTR i2s_dma_rx_callback(gdma_channel_handle_t dma_chan, gdma_e need_awoke |= tmp; } } - xQueueSendFromISR(p_i2s->rx->queue, &(((lldesc_t *)finish_desc)->buf), &tmp); + xQueueSendFromISR(p_i2s->rx->queue, &finish_desc->buf, &tmp); need_awoke |= tmp; if (p_i2s->i2s_queue) { i2s_event.type = I2S_EVENT_RX_DONE; @@ -210,10 +224,10 @@ static bool IRAM_ATTR i2s_dma_tx_callback(gdma_channel_handle_t dma_chan, gdma_e BaseType_t tmp = 0; int dummy; i2s_event_t i2s_event; - uint32_t finish_desc; + lldesc_t *finish_desc; if (p_i2s->tx) { - finish_desc = event_data->tx_eof_desc_addr; - i2s_event.size = ((lldesc_t *)finish_desc)->size; + finish_desc = (lldesc_t *)event_data->tx_eof_desc_addr; + i2s_event.size = finish_desc->size; if (xQueueIsQueueFullFromISR(p_i2s->tx->queue)) { xQueueReceiveFromISR(p_i2s->tx->queue, &dummy, &tmp); need_awoke |= tmp; @@ -225,9 +239,13 @@ static bool IRAM_ATTR i2s_dma_tx_callback(gdma_channel_handle_t dma_chan, gdma_e } } if (p_i2s->tx_desc_auto_clear) { - memset((void *) (((lldesc_t *)finish_desc)->buf), 0, p_i2s->tx->buf_size); + uint8_t *sent_buf = (uint8_t *)finish_desc->buf; + memset(sent_buf, 0, p_i2s->tx->buf_size); +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE + esp_cache_msync(sent_buf, p_i2s->tx->buf_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M); +#endif } - xQueueSendFromISR(p_i2s->tx->queue, &(((lldesc_t *)finish_desc)->buf), &tmp); + xQueueSendFromISR(p_i2s->tx->queue, &finish_desc->buf, &tmp); need_awoke |= tmp; if (p_i2s->i2s_queue) { i2s_event.type = I2S_EVENT_TX_DONE; @@ -499,7 +517,35 @@ static inline uint32_t i2s_get_buf_size(i2s_port_t i2s_num) uint32_t bytes_per_frame = bytes_per_sample * p_i2s[i2s_num]->active_slot; p_i2s[i2s_num]->dma_frame_num = (p_i2s[i2s_num]->dma_frame_num * bytes_per_frame > I2S_DMA_BUFFER_MAX_SIZE) ? I2S_DMA_BUFFER_MAX_SIZE / bytes_per_frame : p_i2s[i2s_num]->dma_frame_num; - return p_i2s[i2s_num]->dma_frame_num * bytes_per_frame; + uint32_t bufsize = p_i2s[i2s_num]->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 = p_i2s[i2s_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 = p_i2s[i2s_num]->dma_frame_num; // Reset the frame num + bufsize = aligned_frame_num * bytes_per_frame; // Reset the bufsize + } + } + if (bufsize / bytes_per_frame != p_i2s[i2s_num]->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); + } +#else + /* 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; + bufsize = frame_num * bytes_per_frame; + ESP_LOGW(TAG, "dma frame num is out of dma buffer size, limited to %"PRIu32, frame_num); + } +#endif + return bufsize; } static esp_err_t i2s_delete_dma_buffer(i2s_port_t i2s_num, i2s_dma_t *dma_obj) @@ -526,15 +572,17 @@ static esp_err_t i2s_alloc_dma_buffer(i2s_port_t i2s_num, i2s_dma_t *dma_obj) ESP_GOTO_ON_FALSE(dma_obj, ESP_ERR_INVALID_ARG, err, TAG, "I2S DMA object can't be NULL"); uint32_t buf_cnt = p_i2s[i2s_num]->dma_desc_num; + size_t desc_size = 0; for (int cnt = 0; cnt < buf_cnt; cnt++) { /* Allocate DMA buffer */ - dma_obj->buf[cnt] = (char *) heap_caps_calloc(dma_obj->buf_size, sizeof(char), MALLOC_CAP_DMA); + esp_dma_calloc(1, sizeof(char) * dma_obj->buf_size, (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA), (void **)&dma_obj->buf[cnt], NULL); ESP_GOTO_ON_FALSE(dma_obj->buf[cnt], ESP_ERR_NO_MEM, err, TAG, "Error malloc dma buffer"); - /* Initialize DMA buffer to 0 */ - memset(dma_obj->buf[cnt], 0, dma_obj->buf_size); +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE + esp_cache_msync(dma_obj->buf[cnt], dma_obj->buf_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M); +#endif - /* Allocate DMA descpriptor */ - dma_obj->desc[cnt] = (lldesc_t *) heap_caps_calloc(1, sizeof(lldesc_t), MALLOC_CAP_DMA); + /* Allocate DMA descriptor */ + esp_dma_calloc(1, sizeof(lldesc_t), MALLOC_CAP_DEFAULT, (void **)&dma_obj->desc[cnt], &desc_size); ESP_GOTO_ON_FALSE(dma_obj->desc[cnt], ESP_ERR_NO_MEM, err, TAG, "Error malloc dma description entry"); } /* DMA descriptor must be initialize after all descriptor has been created, otherwise they can't be linked together as a chain */ @@ -549,6 +597,9 @@ static esp_err_t i2s_alloc_dma_buffer(i2s_port_t i2s_num, i2s_dma_t *dma_obj) dma_obj->desc[cnt]->offset = 0; /* Link to the next descriptor */ dma_obj->desc[cnt]->empty = (uint32_t)((cnt < (buf_cnt - 1)) ? (dma_obj->desc[cnt + 1]) : dma_obj->desc[0]); +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE + esp_cache_msync(dma_obj->desc[cnt], desc_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M); +#endif } if (p_i2s[i2s_num]->dir & I2S_DIR_RX) { i2s_ll_rx_set_eof_num(p_i2s[i2s_num]->hal.dev, dma_obj->buf_size); @@ -1659,7 +1710,7 @@ esp_err_t i2s_write(i2s_port_t i2s_num, const void *src, size_t size, size_t *by } p_i2s[i2s_num]->tx->rw_pos = 0; } - ESP_LOGD(TAG, "size: %d, rw_pos: %d, buf_size: %d, curr_ptr: %d", size, p_i2s[i2s_num]->tx->rw_pos, p_i2s[i2s_num]->tx->buf_size, (int)p_i2s[i2s_num]->tx->curr_ptr); + ESP_LOGD(TAG, "size: %d, rw_pos: %d, buf_size: %d, curr_ptr: %p", size, p_i2s[i2s_num]->tx->rw_pos, p_i2s[i2s_num]->tx->buf_size, p_i2s[i2s_num]->tx->curr_ptr); data_ptr = (char *)p_i2s[i2s_num]->tx->curr_ptr; data_ptr += p_i2s[i2s_num]->tx->rw_pos; bytes_can_write = p_i2s[i2s_num]->tx->buf_size - p_i2s[i2s_num]->tx->rw_pos; @@ -1667,6 +1718,9 @@ esp_err_t i2s_write(i2s_port_t i2s_num, const void *src, size_t size, size_t *by bytes_can_write = size; } memcpy(data_ptr, src_byte, bytes_can_write); +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE + esp_cache_msync((void *)(p_i2s[i2s_num]->tx->curr_ptr), p_i2s[i2s_num]->tx->buf_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M); +#endif size -= bytes_can_write; src_byte += bytes_can_write; p_i2s[i2s_num]->tx->rw_pos += bytes_can_write; @@ -1737,6 +1791,9 @@ esp_err_t i2s_write_expand(i2s_port_t i2s_num, const void *src, size_t size, siz memcpy(&data_ptr[j], (const char *)(src + *bytes_written), aim_bytes - zero_bytes); (*bytes_written) += (aim_bytes - zero_bytes); } +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE + esp_cache_msync((void *)p_i2s[i2s_num]->tx->curr_ptr, p_i2s[i2s_num]->tx->buf_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M); +#endif size -= bytes_can_write; p_i2s[i2s_num]->tx->rw_pos += bytes_can_write; } diff --git a/components/driver/test_apps/.build-test-rules.yml b/components/driver/test_apps/.build-test-rules.yml index 2fbaf62088..213bd2d97f 100644 --- a/components/driver/test_apps/.build-test-rules.yml +++ b/components/driver/test_apps/.build-test-rules.yml @@ -13,10 +13,6 @@ 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/legacy_adc_driver: disable: diff --git a/components/driver/test_apps/i2s_test_apps/legacy_i2s_driver/main/test_legacy_i2s.c b/components/driver/test_apps/i2s_test_apps/legacy_i2s_driver/main/test_legacy_i2s.c index 26d38344bb..5547280042 100644 --- a/components/driver/test_apps/i2s_test_apps/legacy_i2s_driver/main/test_legacy_i2s.c +++ b/components/driver/test_apps/i2s_test_apps/legacy_i2s_driver/main/test_legacy_i2s.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -447,11 +447,11 @@ TEST_CASE("I2S_TDM_loopback_test_with_master_tx_and_rx", "[i2s_legacy]") i2s_test_io_config(I2S_TEST_MODE_LOOPBACK); printf("\r\nheap size: %"PRIu32"\n", esp_get_free_heap_size()); - uint8_t *data_wr = (uint8_t *)malloc(sizeof(uint8_t) * 400); + uint8_t *data_wr = (uint8_t *)calloc(1, sizeof(uint8_t) * 400); size_t i2s_bytes_write = 0; size_t bytes_read = 0; int length = 0; - uint8_t *i2s_read_buff = (uint8_t *)malloc(sizeof(uint8_t) * 10000); + uint8_t *i2s_read_buff = (uint8_t *)calloc(1, sizeof(uint8_t) * 10000); for (int i = 0; i < 100; i++) { data_wr[i] = i + 1; @@ -880,7 +880,7 @@ static void i2s_test_common_sample_rate(i2s_port_t id) 96000, 128000, 144000, 196000 }; int real_pulse = 0; -#if CONFIG_IDF_ENV_FPGA +#if CONFIG_IDF_ENV_FPGA || CONFIG_IDF_TARGET_ESP32P4 // Limit the test sample rate on FPGA platform due to the low frequency it supports. int case_cnt = 10; #else diff --git a/components/driver/test_apps/i2s_test_apps/legacy_i2s_driver/pytest_legacy_i2s.py b/components/driver/test_apps/i2s_test_apps/legacy_i2s_driver/pytest_legacy_i2s.py index 2a0385d7d9..e7ae5f6d37 100644 --- a/components/driver/test_apps/i2s_test_apps/legacy_i2s_driver/pytest_legacy_i2s.py +++ b/components/driver/test_apps/i2s_test_apps/legacy_i2s_driver/pytest_legacy_i2s.py @@ -1,6 +1,5 @@ # SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Apache-2.0 - import pytest from pytest_embedded import Dut @@ -11,6 +10,7 @@ from pytest_embedded import Dut @pytest.mark.esp32s3 @pytest.mark.esp32c6 @pytest.mark.esp32h2 +@pytest.mark.esp32p4 @pytest.mark.generic @pytest.mark.parametrize( 'config', 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 1adaf4e1fc..6bc13f3eca 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-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -45,13 +45,13 @@ extern "C" { #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 +#define MASTER_MCK_IO 36 +#define MASTER_BCK_IO 4 +#define MASTER_WS_IO 5 +#define SLAVE_BCK_IO 7 +#define SLAVE_WS_IO 8 +#define DATA_IN_IO 2 +#define DATA_OUT_IO 3 #else #define MASTER_MCK_IO 0 #define MASTER_BCK_IO 4 diff --git a/components/esp_driver_i2s/test_apps/.build-test-rules.yml b/components/esp_driver_i2s/test_apps/.build-test-rules.yml index 855a23e910..fa1041bd86 100644 --- a/components/esp_driver_i2s/test_apps/.build-test-rules.yml +++ b/components/esp_driver_i2s/test_apps/.build-test-rules.yml @@ -3,13 +3,8 @@ components/esp_driver_i2s/test_apps/i2s: disable: - if: SOC_I2S_SUPPORTED != 1 - disable_test: - - if: IDF_TARGET == "esp32p4" - temporary: true - reason: lack of runners depends_components: - esp_driver_i2s - - esp_driver_gpio - esp_driver_pcnt components/esp_driver_i2s/test_apps/i2s_multi_dev: @@ -22,4 +17,3 @@ components/esp_driver_i2s/test_apps/i2s_multi_dev: reason: lack of runners depends_components: - esp_driver_i2s - - esp_driver_gpio diff --git a/components/esp_driver_i2s/test_apps/i2s/pytest_i2s.py b/components/esp_driver_i2s/test_apps/i2s/pytest_i2s.py index ff8922cabc..44017eb692 100644 --- a/components/esp_driver_i2s/test_apps/i2s/pytest_i2s.py +++ b/components/esp_driver_i2s/test_apps/i2s/pytest_i2s.py @@ -1,6 +1,5 @@ # SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Apache-2.0 - import pytest from pytest_embedded import Dut @@ -11,6 +10,7 @@ from pytest_embedded import Dut @pytest.mark.esp32c6 @pytest.mark.esp32s3 @pytest.mark.esp32h2 +@pytest.mark.esp32p4 @pytest.mark.generic @pytest.mark.parametrize( 'config',