/* * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include #include "sdkconfig.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/semphr.h" #include "unity.h" #include "driver/i2s_std.h" #include "esp_attr.h" #include "soc/soc_caps.h" #include "esp_private/i2s_platform.h" #include "esp_private/spi_flash_os.h" #include "../../test_inc/test_i2s.h" #if CONFIG_I2S_ISR_IRAM_SAFE #define GET_DMA_BUFFERS_BY_OFFSET(base_addr, offset) (uint8_t **)(*((uint32_t *)base_addr + offset)) static bool IRAM_ATTR test_i2s_tx_done_callback(i2s_chan_handle_t handle, i2s_event_data_t *event, void *user_ctx) { int *is_triggered = (int *)user_ctx; if (*(uint8_t *)(event->data) != 0) { *is_triggered = 1; } return false; } static void IRAM_ATTR test_i2s_iram_write(i2s_chan_handle_t tx_handle) { // Get the DMA buf pointer via the offset of 'bufs' field in i2s_channel_t struct size_t offset = i2s_platform_get_dma_buffer_offset() / sizeof(uint32_t); // Get the offset and transfer to unit 'uint32_t' (i.e. 4 bytes) uint8_t **dma_bufs = GET_DMA_BUFFERS_BY_OFFSET(tx_handle, offset); // 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; } // enable cache and non-iram ISR handlers spi_flash_guard_get()->end(); } TEST_CASE("i2s_iram_interrupt_safe", "[i2s]") { i2s_chan_handle_t tx_chan = NULL; 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; 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), .slot_cfg = I2S_STD_MSB_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO), .gpio_cfg = { .mclk = MASTER_MCK_IO, .bclk = MASTER_BCK_IO, .ws = MASTER_WS_IO, .dout = DATA_OUT_IO, .din = DATA_OUT_IO, // same gpio to loopback .invert_flags = { .mclk_inv = false, .bclk_inv = false, .ws_inv = false, }, }, }; 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; 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_enable(tx_chan)); TEST_ESP_OK(i2s_channel_enable(rx_chan)); uint8_t *recv_buf = (uint8_t *)calloc(1, 2000); TEST_ASSERT(recv_buf != NULL); size_t r_bytes; int i = 0; test_i2s_iram_write(tx_chan); 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) { goto finish; } } } finish: TEST_ESP_OK(i2s_channel_disable(tx_chan)); TEST_ESP_OK(i2s_channel_disable(rx_chan)); TEST_ESP_OK(i2s_del_channel(tx_chan)); TEST_ESP_OK(i2s_del_channel(rx_chan)); TEST_ASSERT(i < (2000 - 100)); for (int j = 1; j <= 100; j++) { TEST_ASSERT_EQUAL_UINT8(recv_buf[i++], j); } TEST_ASSERT(is_triggerred); free(recv_buf); } #endif // CONFIG_PCNT_ISR_IRAM_SAFE