Загрузка данных
/* This function is executed in the interrupt context */
static void i2s_dma_tx_callback(const struct device *dma_dev, void *arg, uint32_t channel,
int status)
{
const struct device *dev = (struct device *)arg;
struct i2s_dev_data *dev_data = dev->data;
struct stream *strm = &dev_data->tx;
uint8_t blocks_queued;
void *buffer = NULL;
int ret;
LOG_DBG("tx cb");
ret = k_msgq_get(&strm->out_queue, &buffer, K_NO_WAIT);
if (ret == 0) {
/* transmission complete. free the buffer */
k_mem_slab_free(strm->cfg.mem_slab, buffer);
(strm->free_tx_dma_blocks)++;
} else {
LOG_ERR("no buf in out_queue for channel %u", channel);
}
if (strm->free_tx_dma_blocks > MAX_TX_DMA_BLOCKS) {
strm->state = I2S_STATE_ERROR;
LOG_ERR("free_tx_dma_blocks exceeded maximum, now %d", strm->free_tx_dma_blocks);
goto disabled_exit_no_drop;
}
/* Received a STOP trigger, terminate TX immediately */
if (strm->last_block) {
strm->state = I2S_STATE_READY;
LOG_DBG("TX STOPPED last_block set");
goto disabled_exit_no_drop;
}
if (ret) {
/* k_msgq_get() returned error, and was not last_block */
strm->state = I2S_STATE_ERROR;
goto disabled_exit_no_drop;
}
if (strm->state != I2S_STATE_RUNNING && strm->state != I2S_STATE_STOPPING) {
goto disabled_exit_drop;
}
ret = i2s_tx_reload_multiple_dma_blocks(dev, &blocks_queued);
if (ret) {
strm->state = I2S_STATE_ERROR;
goto disabled_exit_no_drop;
}
if (blocks_queued || (strm->free_tx_dma_blocks < MAX_TX_DMA_BLOCKS)) {
goto enabled_exit;
}
/* all DMA blocks are free but no blocks were queued */
if (strm->state == I2S_STATE_STOPPING) {
/* TX queue has drained */
strm->state = I2S_STATE_READY;
LOG_DBG("TX stream has stopped");
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 enabled_exit;
disabled_exit_no_drop:
i2s_tx_stream_disable(dev, false);
return;
disabled_exit_drop:
i2s_tx_stream_disable(dev, true);
return;
enabled_exit:
return;
}
static void i2s_dma_rx_callback(const struct device *dma_dev, void *arg, uint32_t channel,
int status)
{
struct device *dev = (struct device *)arg;
const struct i2s_mcux_config *dev_cfg = dev->config;
I2S_Type *base = (I2S_Type *)dev_cfg->base;
struct i2s_dev_data *dev_data = dev->data;
struct stream *strm = &dev_data->rx;
void *buffer;
int ret;
LOG_DBG("RX cb");
if (strm->state == I2S_STATE_ERROR) {
i2s_rx_stream_disable(dev, true, true);
}
if (strm->state != I2S_STATE_STOPPING && strm->state != I2S_STATE_RUNNING) {
return;
}
/* retrieve buffer from input queue */
ret = k_msgq_get(&strm->in_queue, &buffer, K_NO_WAIT);
__ASSERT_NO_MSG(ret == 0);
/* put buffer to output queue */
ret = k_msgq_put(&strm->out_queue, &buffer, K_NO_WAIT);
if (ret != 0) {
LOG_ERR("buffer %p -> out_queue %p err %d", buffer, &strm->out_queue, ret);
goto error;
}
if (strm->state == I2S_STATE_STOPPING) {
i2s_rx_stream_disable(dev, true, false);
/* Received a STOP/DRAIN trigger */
strm->state = I2S_STATE_READY;
return;
}
/* Now the only possible case is the running state */
/* allocate new buffer for next audio frame */
ret = k_mem_slab_alloc(strm->cfg.mem_slab, &buffer, K_NO_WAIT);
if (ret != 0) {
LOG_ERR("buffer alloc from slab %p err %d", strm->cfg.mem_slab, ret);
goto error;
}
uint32_t data_path = strm->start_channel;
ret = dma_reload(dev_data->dev_dma, strm->dma_channel,
(uint32_t)&base->RDR[data_path], (uint32_t)buffer,
strm->cfg.block_size);
if (ret != 0) {
LOG_ERR("dma_reload() failed with error 0x%x", ret);
goto error;
}
/* put buffer in input queue */
ret = k_msgq_put(&strm->in_queue, &buffer, K_NO_WAIT);
if (ret != 0) {
LOG_ERR("%p -> in_queue %p err %d", buffer, &strm->in_queue, ret);
}
return;
error:
i2s_rx_stream_disable(dev, false, false);
strm->state = I2S_STATE_ERROR;
}
[00:01:59.069,000] <err> dev_i2s_mcux: buffer 0x2004b780 -> out_queue 0x800045a4 err -35
[00:01:59.466,000] <wrn> dev_i2s_mcux: TX input queue empty!
[00:01:59.467,000] <wrn> dev_i2s_mcux: TX is paused.