mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 03:00:34 +03:00
feat(i2s): release i2s tx sync APIs
This commit is contained in:
@@ -12,5 +12,5 @@ endif()
|
||||
|
||||
idf_component_register(SRCS ${srcs}
|
||||
PRIV_REQUIRES unity esp_driver_pcnt spi_flash
|
||||
esp_driver_gpio esp_driver_i2s esp_driver_uart esp_psram
|
||||
esp_driver_gpio esp_driver_i2s esp_driver_uart esp_psram esp_driver_gptimer
|
||||
WHOLE_ARCHIVE)
|
||||
|
||||
@@ -25,6 +25,11 @@
|
||||
#include "driver/i2s_std.h"
|
||||
#include "driver/i2s_common.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#if SOC_I2S_SUPPORTS_TX_FIFO_SYNC
|
||||
#include "driver/i2s_etm.h"
|
||||
#include "driver/gptimer.h"
|
||||
#include "esp_etm.h"
|
||||
#endif
|
||||
#if SOC_I2S_SUPPORTS_PDM
|
||||
#include "driver/i2s_pdm.h"
|
||||
#endif
|
||||
@@ -1278,6 +1283,144 @@ TEST_CASE("I2S_rate_tunning", "[i2s]")
|
||||
TEST_ESP_OK(i2s_del_channel(rx_handle));
|
||||
}
|
||||
|
||||
#if SOC_I2S_SUPPORTS_TX_FIFO_SYNC
|
||||
#define I2S_TX_SYNC_TEST_TIMER_RES_HZ (1000 * 1000)
|
||||
#define I2S_TX_SYNC_TEST_ALARM_COUNT (5000)
|
||||
#define I2S_TX_SYNC_TEST_IDEAL_CNT (1000)
|
||||
#define I2S_TX_SYNC_TEST_MANUAL_THRESH (64)
|
||||
#define I2S_TX_SYNC_TEST_BUF_SIZE (4096)
|
||||
|
||||
typedef struct {
|
||||
SemaphoreHandle_t sem;
|
||||
int32_t diff_count;
|
||||
} i2s_tx_sync_test_ctx_t;
|
||||
|
||||
static IRAM_ATTR bool i2s_tx_sync_test_callback(i2s_chan_handle_t handle, const i2s_sync_event_data_t *event, void *user_ctx)
|
||||
{
|
||||
(void)handle;
|
||||
i2s_tx_sync_test_ctx_t *ctx = (i2s_tx_sync_test_ctx_t *)user_ctx;
|
||||
ctx->diff_count = event->diff_count;
|
||||
|
||||
BaseType_t need_yield = pdFALSE;
|
||||
xSemaphoreGiveFromISR(ctx->sem, &need_yield);
|
||||
return need_yield == pdTRUE;
|
||||
}
|
||||
|
||||
TEST_CASE("I2S TX sync callback is triggered by GPTimer ETM alarm", "[i2s][etm]")
|
||||
{
|
||||
i2s_chan_handle_t tx_handle = NULL;
|
||||
gptimer_handle_t timer = NULL;
|
||||
esp_etm_event_handle_t timer_event = NULL;
|
||||
esp_etm_task_handle_t i2s_sync_task = NULL;
|
||||
esp_etm_channel_handle_t etm_channel = NULL;
|
||||
uint8_t *buf = NULL;
|
||||
|
||||
i2s_tx_sync_test_ctx_t cb_ctx = {
|
||||
.sem = xSemaphoreCreateBinary(),
|
||||
};
|
||||
TEST_ASSERT_NOT_NULL(cb_ctx.sem);
|
||||
|
||||
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER);
|
||||
chan_cfg.dma_desc_num = 4;
|
||||
chan_cfg.dma_frame_num = 256;
|
||||
i2s_std_config_t std_cfg = {
|
||||
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(48000),
|
||||
.slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO),
|
||||
.gpio_cfg = I2S_TEST_MASTER_DEFAULT_PIN,
|
||||
};
|
||||
std_cfg.gpio_cfg.mclk = -1;
|
||||
#if CONFIG_IDF_TARGET_ESP32S31
|
||||
std_cfg.clk_cfg.clk_src = I2S_CLK_SRC_APLL;
|
||||
#endif
|
||||
|
||||
TEST_ESP_OK(i2s_new_channel(&chan_cfg, &tx_handle, NULL));
|
||||
TEST_ESP_OK(i2s_channel_init_std_mode(tx_handle, &std_cfg));
|
||||
|
||||
buf = (uint8_t *)calloc(1, I2S_TX_SYNC_TEST_BUF_SIZE);
|
||||
TEST_ASSERT_NOT_NULL(buf);
|
||||
size_t bytes_loaded = 0;
|
||||
TEST_ESP_OK(i2s_channel_preload_data(tx_handle, buf, I2S_TX_SYNC_TEST_BUF_SIZE, &bytes_loaded));
|
||||
TEST_ASSERT_GREATER_THAN(0, bytes_loaded);
|
||||
|
||||
i2s_tx_fifo_sync_config_t sync_cfg = {
|
||||
.auto_suppl_thresh = 0,
|
||||
.manual_suppl_thresh = I2S_TX_SYNC_TEST_MANUAL_THRESH,
|
||||
.ideal_cnt = I2S_TX_SYNC_TEST_IDEAL_CNT,
|
||||
.suppl_mode = I2S_TX_FIFO_SYNC_SUPPL_MODE_LAST_DATA,
|
||||
};
|
||||
i2s_intr_event_callbacks_t intr_cbs = {
|
||||
.on_tx_sync = i2s_tx_sync_test_callback,
|
||||
};
|
||||
TEST_ESP_OK(i2s_channel_config_tx_fifo_sync(tx_handle, &sync_cfg));
|
||||
TEST_ESP_OK(i2s_channel_register_intr_event_callback(tx_handle, &intr_cbs, &cb_ctx));
|
||||
|
||||
uint32_t bclk_count = 0;
|
||||
uint32_t fifo_count = 0;
|
||||
int32_t diff_count = 0;
|
||||
TEST_ESP_OK(i2s_channel_get_sync_count(tx_handle, &bclk_count, &fifo_count, true));
|
||||
TEST_ESP_OK(i2s_channel_get_sync_count(tx_handle, NULL, NULL, false));
|
||||
TEST_ESP_OK(i2s_channel_get_sync_diff_count(tx_handle, &diff_count, true));
|
||||
TEST_ESP_OK(i2s_channel_get_sync_diff_count(tx_handle, NULL, false));
|
||||
printf("TX sync API before start: diff=%"PRId32", fifo=%"PRIu32", bclk=%"PRIu32"\n",
|
||||
diff_count, fifo_count, bclk_count);
|
||||
|
||||
i2s_etm_task_config_t i2s_task_cfg = {
|
||||
.task_type = I2S_ETM_TASK_SYNC_FIFO,
|
||||
};
|
||||
TEST_ESP_OK(i2s_new_etm_task(tx_handle, &i2s_task_cfg, &i2s_sync_task));
|
||||
|
||||
gptimer_config_t timer_cfg = {
|
||||
.clk_src = GPTIMER_CLK_SRC_DEFAULT,
|
||||
.direction = GPTIMER_COUNT_UP,
|
||||
.resolution_hz = I2S_TX_SYNC_TEST_TIMER_RES_HZ,
|
||||
};
|
||||
TEST_ESP_OK(gptimer_new_timer(&timer_cfg, &timer));
|
||||
gptimer_alarm_config_t alarm_cfg = {
|
||||
.alarm_count = I2S_TX_SYNC_TEST_ALARM_COUNT,
|
||||
};
|
||||
TEST_ESP_OK(gptimer_set_alarm_action(timer, &alarm_cfg));
|
||||
|
||||
gptimer_etm_event_config_t timer_event_cfg = {
|
||||
.event_type = GPTIMER_ETM_EVENT_ALARM_MATCH,
|
||||
};
|
||||
TEST_ESP_OK(gptimer_new_etm_event(timer, &timer_event_cfg, &timer_event));
|
||||
|
||||
esp_etm_channel_config_t etm_cfg = {};
|
||||
TEST_ESP_OK(esp_etm_new_channel(&etm_cfg, &etm_channel));
|
||||
TEST_ESP_OK(esp_etm_channel_connect(etm_channel, timer_event, i2s_sync_task));
|
||||
TEST_ESP_OK(esp_etm_channel_enable(etm_channel));
|
||||
|
||||
TEST_ESP_OK(gptimer_enable(timer));
|
||||
TEST_ESP_OK(gptimer_start(timer));
|
||||
TEST_ESP_OK(i2s_channel_enable(tx_handle));
|
||||
|
||||
bool callback_triggered = xSemaphoreTake(cb_ctx.sem, pdMS_TO_TICKS(100)) == pdTRUE;
|
||||
printf("TX sync callback: triggered=%d, diff=%"PRId32"\n", callback_triggered, cb_ctx.diff_count);
|
||||
|
||||
TEST_ESP_OK(gptimer_stop(timer));
|
||||
TEST_ESP_OK(i2s_channel_disable(tx_handle));
|
||||
intr_cbs.on_tx_sync = NULL;
|
||||
TEST_ESP_OK(i2s_channel_register_intr_event_callback(tx_handle, &intr_cbs, NULL));
|
||||
TEST_ESP_OK(gptimer_disable(timer));
|
||||
TEST_ESP_OK(esp_etm_channel_disable(etm_channel));
|
||||
|
||||
TEST_ESP_OK(esp_etm_del_event(timer_event));
|
||||
TEST_ESP_OK(esp_etm_del_task(i2s_sync_task));
|
||||
TEST_ESP_OK(esp_etm_del_channel(etm_channel));
|
||||
TEST_ESP_OK(gptimer_del_timer(timer));
|
||||
TEST_ESP_OK(i2s_del_channel(tx_handle));
|
||||
vSemaphoreDelete(cb_ctx.sem);
|
||||
free(buf);
|
||||
|
||||
TEST_ASSERT_TRUE(callback_triggered);
|
||||
|
||||
/* SYNC_CHECK fires at 0.005 s. About 48000 * 2 * 0.005 = 480 samples
|
||||
* are sent, so ideal_cnt 1000 should produce diff_count around -520.
|
||||
*/
|
||||
TEST_ASSERT_INT32_WITHIN(52, -520, cb_ctx.diff_count);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_CASE("i2s_destination_test", "[i2s]")
|
||||
{
|
||||
i2s_chan_handle_t tx = NULL;
|
||||
|
||||
Reference in New Issue
Block a user