feat(i2s): support i2s legacy driver on p4

This commit is contained in:
laokaiyao 2024-01-15 17:33:48 +08:00
parent 2ab552a241
commit 62ae0efa54
7 changed files with 88 additions and 41 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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