Skip to content

Commit

Permalink
drivers: i2s: Fix TX transfer stopping issue in some corner cases
Browse files Browse the repository at this point in the history
In previous implementions, when there is no buffers in TX queue in a TX
callback context, TX will be stopped immediately. It is not correct
because there may still TX blocks in DMA TX transfer queue.
TX should only be stopped when DMA queue is empty and no more in I2S TX
queue.
Another modification is to set correct TX water FIFO level.

Signed-off-by: Raymond Lei <[email protected]>
  • Loading branch information
Raymond0225 committed Jan 14, 2025
1 parent 2e75e18 commit 872df4f
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 5 deletions.
38 changes: 34 additions & 4 deletions drivers/i2s/i2s_mcux_sai.c
Original file line number Diff line number Diff line change
Expand Up @@ -308,11 +308,23 @@ static void i2s_dma_tx_callback(const struct device *dma_dev, void *arg, uint32_
/* TX queue has drained */
strm->state = I2S_STATE_READY;
LOG_DBG("TX stream has stopped");
} else {
strm->state = I2S_STATE_ERROR;
LOG_ERR("TX Failed to reload DMA");
goto disabled_exit_no_drop;
}

LOG_WRN("TX input queue empty!");
if (strm->free_tx_dma_blocks >= MAX_TX_DMA_BLOCKS) {
/* In running state, no TX blocks for transferring, so stop
* TX (This will disable bit clock to avoid dummy bits
* received in RX side.
*/
const struct i2s_mcux_config *dev_cfg = dev->config;
I2S_Type *base = (I2S_Type *)dev_cfg->base;

SAI_TxEnable(base, false);
LOG_WRN("TX is paused.");
}
goto disabled_exit_no_drop;
goto enabled_exit;


disabled_exit_no_drop:
i2s_tx_stream_disable(dev, false);
Expand Down Expand Up @@ -596,6 +608,7 @@ static int i2s_mcux_config(const struct device *dev, enum i2s_dir dir,
LOG_DBG("tx slab block_size = %d", (uint32_t)i2s_cfg->mem_slab->info.block_size);
LOG_DBG("tx slab buffer = 0x%x", (uint32_t)i2s_cfg->mem_slab->buffer);

config.fifo.fifoWatermark = (uint32_t)FSL_FEATURE_SAI_FIFO_COUNTn(base) - 1;
/* set bit clock divider */
SAI_TxSetConfig(base, &config);
dev_data->tx.start_channel = config.startChannel;
Expand Down Expand Up @@ -975,6 +988,23 @@ static int i2s_mcux_write(const struct device *dev, void *mem_block, size_t size
return ret;
}

if (strm->state == I2S_STATE_RUNNING && strm->free_tx_dma_blocks >= MAX_TX_DMA_BLOCKS) {
uint8_t blocks_queued = 0;
const struct i2s_mcux_config *dev_cfg = dev->config;
I2S_Type *base = (I2S_Type *)dev_cfg->base;
/* As DMA has been stopped because reloading failure in TX callback,
* here is a good place to reload it and resume TX.
*/
ret = i2s_tx_reload_multiple_dma_blocks(dev, &blocks_queued);
if (ret == 0 && blocks_queued > 0) {
SAI_TxEnable(base, true);
LOG_WRN("TX is resumed");
} else {
LOG_ERR("TX block reload err, TX is not resumed");
return ret;
}
}

return ret;
}

Expand Down
2 changes: 1 addition & 1 deletion west.yml
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ manifest:
groups:
- hal
- name: hal_nxp
revision: b5f6470ec7ccd7f1c9a2c929fa93eae9fb001d9e
revision: pull/490/head
path: modules/hal/nxp
groups:
- hal
Expand Down

0 comments on commit 872df4f

Please sign in to comment.