in IndustrialDeviceController/Software/MT3620_IDC_RTApp/lib/I2S.c [191:306]
int32_t I2S_Output(
I2S *handle, I2S_Format format, unsigned channels, unsigned bits, unsigned rate,
bool (*callback)(void *data, uintptr_t size))
{
if (!handle) {
return ERROR_PARAMETER;
}
if (!handle->open) {
return ERROR_HANDLE_CLOSED;
}
unsigned id = handle->id;
bool enable = (format != I2S_FORMAT_NONE);
bool tdm = false;
mt3620_i2s_sr_t sr = MT3620_I2S_SR_48K;
if (enable) {
if (channels == 0) {
return ERROR_PARAMETER;
}
switch (format) {
case I2S_FORMAT_I2S:
if (channels > 2) {
return ERROR_PARAMETER;
}
break;
case I2S_FORMAT_TDM:
if ((channels > 4) || (channels % 2)) {
return ERROR_UNSUPPORTED;
}
tdm = true;
break;
default:
return ERROR_PARAMETER;
}
if (bits != 16) {
return ERROR_UNSUPPORTED;
}
sr = I2S_SampleRate(rate);
if (sr >= MT3620_I2S_SR_COUNT) {
return ERROR_UNSUPPORTED;
}
}
mt3620_i2s_global_control_t global_control = { .mask = mt3620_i2s[id]->global_control };
if (enable) {
global_control.dl_mono = (channels == 1);
global_control.dl_mono_dup = (channels == 1);
global_control.i2s_out_clk_en = true;
global_control.dl_empty_value_en = true;
global_control.clk_sel_out = MT3620_I2S_CLK_SEL_EXTERNAL;
mt3620_i2s[id]->global_control = global_control.mask;
}
mt3620_i2s_dl_control_t dl_control = { .mask = mt3620_i2s[id]->dl_control };
dl_control.en = enable;
if (enable) {
dl_control.wlen = MT3620_I2S_WLEN_16BIT;
dl_control.src = MT3620_I2S_SRC_SLAVE;
dl_control.fmt = (tdm ? MT3620_I2S_FMT_TDM : MT3620_I2S_FMT_I2S);
dl_control.wsinv = tdm;
dl_control.dlfifo_2deq = (tdm && (channels == 4));
dl_control.sr = sr;
dl_control.bit_per_s = (tdm && (channels == 4) ? 1 : 0);
dl_control.ws_rsync = true; // Functional Spec recommends this be on.
dl_control.msb_offset = 0;
dl_control.ch_per_s = (tdm && (channels == 4) ? 1 : 0);
}
mt3620_i2s[id]->dl_control = dl_control.mask;
if (enable) {
// Enable DMA.
mt3620_dma_global->ch_en_set = (1U << MT3620_I2S_DMA_TX(id));
MT3620_DMA_FIELD_WRITE(MT3620_I2S_DMA_TX(id), start, str, false);
mt3620_dma_con_t dma_con_tx = { .mask = mt3620_dma[MT3620_I2S_DMA_TX(id)].con };
dma_con_tx.dir = 0;
dma_con_tx.iten = true;
dma_con_tx.dreq = true;
dma_con_tx.size = (channels == 1 ? 1 : 2);
mt3620_dma[MT3620_I2S_DMA_TX(id)].con = dma_con_tx.mask;
mt3620_dma[MT3620_I2S_DMA_TX(id)].fixaddr = (void *)mt3620_i2s_fifo[id];
mt3620_dma[MT3620_I2S_DMA_TX(id)].pgmaddr = (void *)I2S_Buffer[id][0];
mt3620_dma[MT3620_I2S_DMA_TX(id)].swptr = 0;
mt3620_dma[MT3620_I2S_DMA_TX(id)].ffsize = (I2S_BUFFER_SIZE >> dma_con_tx.size);
mt3620_dma[MT3620_I2S_DMA_TX(id)].count = (mt3620_dma[MT3620_I2S_DMA_TX(id)].ffsize / 4);
} else {
MT3620_DMA_FIELD_WRITE(MT3620_I2S_DMA_TX(id), start, str, false);
mt3620_dma_global->ch_en_clr = (1U << MT3620_I2S_DMA_TX(id));
}
// Enable DMA handshakes for master mode.
mt3620_i2s_dma_if_control_t dma_if_control = { .mask = mt3620_i2s[id]->dma_if_control };
dma_if_control.dl_dmareq_mi_num = (enable ? 1 : 0);
dma_if_control.dl_ahb_early_en = enable;
dma_if_control.dl_dma_mode_sel = enable;
mt3620_i2s[id]->dma_if_control = dma_if_control.mask;
// Enable I2S.
global_control.en = (enable || handle->in.enable);
global_control.dlfifo_en = enable;
mt3620_i2s[id]->global_control = global_control.mask;
handle->out.enable = enable;
handle->out.channels = channels;
handle->out.callback = callback;
if (enable) {
MT3620_DMA_FIELD_WRITE(MT3620_I2S_DMA_TX(id), start, str, true);
}
return ERROR_NONE;
}