Skip to content

Commit 6a859c7

Browse files
committed
drivers: i2s: esp32: allow deferred processing of an empty tx queue
Allows to defer processing of an empty tx queue when tx_callback is executed. This prevents error conditions if the tx dma interrupt is generated too early, as occurs with esp32 and esp32s2. Signed-off-by: Marcio Ribeiro <[email protected]>
1 parent c631540 commit 6a859c7

File tree

2 files changed

+71
-26
lines changed

2 files changed

+71
-26
lines changed

drivers/i2s/Kconfig.esp32

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ config I2S_ESP32
88
depends on DT_HAS_ESPRESSIF_ESP32_I2S_ENABLED
99
select DMA if DT_HAS_ESPRESSIF_ESP32_GDMA_ENABLED
1010
help
11-
Enables the ESP32 I2S driver (GDMA SoCs only).
11+
Enables the ESP32 I2S driver.
1212

1313
if I2S_ESP32
1414

@@ -31,4 +31,10 @@ config I2S_ESP32_DMA_DESC_NUM_MAX
3131
help
3232
Max number of link descriptor available for DMA transfers on each I2S channel
3333

34+
config I2S_ESP32_ALLOWED_EMPTY_TX_QUEUE_DEFERRAL_TIME_MS
35+
int "ESP32 I2S empty TX queue processing deferral time"
36+
default 0
37+
help
38+
Allowed deferral time for processing an empty tx queue in milliseconds
39+
3440
endif

drivers/i2s/i2s_esp32.c

Lines changed: 64 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,10 @@ struct i2s_esp32_cfg {
9696

9797
struct i2s_esp32_data {
9898
i2s_hal_clock_info_t clk_info;
99+
#if I2S_ESP32_IS_DIR_EN(tx)
100+
struct k_timer tx_deferred_transfer_timer;
101+
const struct device *dev;
102+
#endif
99103
};
100104

101105
uint32_t i2s_esp32_get_source_clk_freq(i2s_clock_src_t clk_src)
@@ -348,6 +352,47 @@ static void i2s_esp32_rx_stop_transfer(const struct device *dev)
348352

349353
#if I2S_ESP32_IS_DIR_EN(tx)
350354

355+
void i2s_esp32_tx_compl_transfer(struct k_timer *timer)
356+
{
357+
struct i2s_esp32_data *dev_data =
358+
CONTAINER_OF(timer, struct i2s_esp32_data, tx_deferred_transfer_timer);
359+
const struct device *dev = dev_data->dev;
360+
const struct i2s_esp32_cfg *const dev_cfg = dev->config;
361+
const struct i2s_esp32_stream *stream = &dev_cfg->tx;
362+
struct queue_item item;
363+
int err;
364+
365+
if (stream->data->state == I2S_STATE_STOPPING) {
366+
if (k_msgq_num_used_get(&stream->data->queue) == 0 ||
367+
stream->data->stop_without_draining == true) {
368+
stream->data->state = I2S_STATE_READY;
369+
goto tx_disable;
370+
}
371+
}
372+
373+
err = k_msgq_get(&stream->data->queue, &item, K_NO_WAIT);
374+
if (err < 0) {
375+
stream->data->state = I2S_STATE_ERROR;
376+
LOG_ERR("TX queue empty: %d", err);
377+
goto tx_disable;
378+
}
379+
380+
stream->data->mem_block = item.buffer;
381+
stream->data->mem_block_len = item.size;
382+
383+
err = i2s_esp32_restart_dma(dev, I2S_DIR_TX);
384+
if (err < 0) {
385+
stream->data->state = I2S_STATE_ERROR;
386+
LOG_ERR("Failed to restart TX transfer: %d", err);
387+
goto tx_disable;
388+
}
389+
390+
return;
391+
392+
tx_disable:
393+
stream->conf->stop_transfer(dev);
394+
}
395+
351396
#if SOC_GDMA_SUPPORTED
352397
static void i2s_esp32_tx_callback(const struct device *dma_dev, void *arg, uint32_t channel,
353398
int status)
@@ -356,10 +401,9 @@ static void i2s_esp32_tx_callback(void *arg, int status)
356401
#endif /* SOC_GDMA_SUPPORTED */
357402
{
358403
const struct device *dev = (const struct device *)arg;
404+
struct i2s_esp32_data *dev_data = dev->data;
359405
const struct i2s_esp32_cfg *const dev_cfg = dev->config;
360406
const struct i2s_esp32_stream *stream = &dev_cfg->tx;
361-
struct queue_item item;
362-
int err;
363407

364408
if (!stream->data->dma_pending) {
365409
return;
@@ -385,29 +429,16 @@ static void i2s_esp32_tx_callback(void *arg, int status)
385429
goto tx_disable;
386430
}
387431

388-
if (stream->data->state == I2S_STATE_STOPPING) {
389-
if (k_msgq_num_used_get(&stream->data->queue) == 0 ||
390-
stream->data->stop_without_draining == true) {
391-
stream->data->state = I2S_STATE_READY;
392-
goto tx_disable;
393-
}
394-
}
395-
396-
err = k_msgq_get(&stream->data->queue, &item, K_NO_WAIT);
397-
if (err < 0) {
398-
stream->data->state = I2S_STATE_ERROR;
399-
LOG_ERR("TX queue empty: %d", err);
400-
goto tx_disable;
401-
}
402-
403-
stream->data->mem_block = item.buffer;
404-
stream->data->mem_block_len = item.size;
405-
406-
err = i2s_esp32_restart_dma(dev, I2S_DIR_TX);
407-
if (err < 0) {
408-
stream->data->state = I2S_STATE_ERROR;
409-
LOG_ERR("Failed to restart TX transfer: %d", err);
410-
goto tx_disable;
432+
#if CONFIG_I2S_ESP32_ALLOWED_EMPTY_TX_QUEUE_DEFERRAL_TIME_MS
433+
if (k_msgq_num_used_get(&stream->data->queue) == 0) {
434+
k_timer_start(&dev_data->tx_deferred_transfer_timer,
435+
K_MSEC(CONFIG_I2S_ESP32_ALLOWED_EMPTY_TX_QUEUE_DEFERRAL_TIME_MS),
436+
K_NO_WAIT);
437+
} else {
438+
#else
439+
{
440+
#endif
441+
i2s_esp32_tx_compl_transfer(&dev_data->tx_deferred_transfer_timer);
411442
}
412443

413444
return;
@@ -769,6 +800,14 @@ static int i2s_esp32_initialize(const struct device *dev)
769800
#if !SOC_GDMA_SUPPORTED
770801
const i2s_hal_context_t *hal = &(dev_cfg->hal);
771802
#endif /* !SOC_GDMA_SUPPORTED */
803+
804+
#if I2S_ESP32_IS_DIR_EN(tx)
805+
struct i2s_esp32_data *dev_data = dev->data;
806+
807+
dev_data->dev = dev;
808+
k_timer_init(&dev_data->tx_deferred_transfer_timer, i2s_esp32_tx_compl_transfer, NULL);
809+
#endif /* I2S_ESP32_IS_DIR_EN(tx) */
810+
772811
if (!device_is_ready(clk_dev)) {
773812
LOG_ERR("clock control device not ready");
774813
return -ENODEV;

0 commit comments

Comments
 (0)