Загрузка данных


/* 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.