Working through setting up SAI with DMA for K22. SAI was very easy, clear documentation. DMA is a little more convoluted with a variety of data structures used between TWR Examples (which incorporate the soundcard API), AN4520, AN4800, and eDMA APIs. I need to clarify some things, so let's start with this :
1) EDMA_DRV_RequestChannel works in terms of assigning a channel using either the kEDMAAnyChannel, or by directly selecting the channel I want. Verified with the return argument however :
"chn : The pointer to the eDMA channel state...The use must pass the memory for this run-time state structure and the eDMA peripheral driver fills out the members. This run-time..."
The only member it seems to fill out is channel, so my assumption is that the remaining members will be filled by the later functions? (According to the API example, this should be fine)
2)But, when I go to fire off the next function EDMA_DRV_ConfigLoopTransfer, I'm dumping in to default handler. I have the fsl_edma_irq.c included, and the functions are showing up, so I know the default IRQs set in SETUP are available, or at least appear to be.
The subfunction it's tanking at is:
/* Set the software TCD memory to default value. */
memset(stcdAddr, 0, number * sizeof(edma_software_tcd_t));
Any clues?
Solved! Go to Solution.
Here is the answer to all of this, and yes loop mode is certainly what I need to use.
Here's an example for using SAI w/EDMA without the SND API (K22).
Reading a possible reason for the failure being :
* @param stcd Memory pointing to software TCDs. The user must prepare this memory block. The required
* memory size is equal to a "period" * size of(edma_software_tcd_t). At the same time, the "stcd"
* must align with 32 bytes. If not, an error occurs in the eDMA driver.
I changed my initialization of the tcd variable to:
edma_software_tcd_t *i2s0_dma_tcd = (edma_software_tcd_t *) OSA_MemAlloc(sizeof(edma_software_tcd_t));
This seems to work, but I still am not totally clear on how the ConfigLoopTransfer relates back to the settings of eDMA controller itself.
Can someone verify the following arguments for me from EDMA_DRV_ConfigLoopTransfer:
* @param size Size to be transferred on every DMA write/read. Source/Dest share the same write/read
* size. ----> SIZE IN TOTAL BYTES? SIZE IN UNITS OF THE ALREADY ESTABLISHED DATA WIDTH? ALIGNED DATA FROM SAI FIFO? CONFUSED.
* @param bytesOnEachRequest Size write/read for every trigger of the DMA request.--> In bytes....
* @param totalLength Total length of Memory. ---> IN BYTES OR ?
* @param number A number of the descriptor that is configured for this transfer configuration. ---> NEWB QUESTION, BUT WHAT IS THE DESCRIPTOR IN THIS CASE? IS IT THE SAME AS THE CHANNEL NUMBER? IS IT THE MUXID? I'm just not clear on this value.
Crashing Example #1 :
/***** I2S FORMAT STRUCTURE ******/
i2s_data_format.bits = 16;
i2s_data_format.sample_rate = 16000;
i2s_data_format.mclk = 256 * i2s_data_format.sample_rate;
i2s_data_format.mono_streo = kSaiMono;
/***** RECEIVER SETTINGS *****/
i2s_config.bclk_source = kSaiBclkSourceMclkDiv;
i2s_config.channel = 0;
i2s_config.mclk_divide_enable = true;
i2s_config.mclk_source = kSaiMclkSourceSysclk;
i2s_config.protocol = kSaiBusI2SLeft;
i2s_config.slave_master = kSaiMaster;
i2s_config.sync_mode = kSaiModeAsync;
i2s_config.watermark = 8;
/***** LOOP SETUP *****/
i2s_dma_loop_setup.dmaChanNum = 0;
i2s_dma_loop_setup.dmaCh = &dmaCh0;
i2s_dma_loop_setup.type = kEDMAPeripheralToMemory;
i2s_dma_loop_setup.chSource = kDmaRequestMux0I2S0Rx;
fifobase = SAI_HAL_RxGetFifoAddr((uint32_t)I2S0_BASE, 1);
i2s_dma_loop_setup.srcAddr = (uint32_t)fifobase;
i2s_dma_loop_setup.destAddr = (uint32_t)&audio_buffer[0];
i2s_dma_loop_setup.length = sizeof(audio_buffer);
i2s_dma_loop_setup.size = 1;
i2s_dma_loop_setup.watermark = 1;
i2s_dma_loop_setup.period = 1;
i2s_dma_loop_setup.dmaCallBack = spectrum_edma_callback;
..... Send some values to codec over I2C .....
SAI_DRV_RxInit(0, &i2s_config, &i2s_state);
SAI_DRV_RxConfigDataFormat(0, &i2s_data_format);
..... Send some more values to codec over I2C .....
setup_edma_loop(&i2s_dma_loop_setup); // FUNCTION BORROWED FROM EDSPI EXAMPLE...
SAI_HAL_RxSetDmaCmd(I2S0_BASE, kSaiDmaReqFIFORequest ,true);
EDMA_DRV_StartChannel(&dmaCh0);
SAI_DRV_RxStartModule(0);
Hi Donald
Why you need a loop mode? I see you need to get RX data from codec. the edma_setup_loop is in the dspi_edma_demo to get a SPI0/1 loop for testing edma.
Here is the answer to all of this, and yes loop mode is certainly what I need to use.
Here's an example for using SAI w/EDMA without the SND API (K22).
Why use loop mode -
"Configure the TCD chain in a loop way. Audio playback/Record is the common case."
Straight out of your API documentation.
I'd like to circular buffer, and wasn't sure if I should use loop mode, or modulo. The edma_setup_loop gave me a clear understanding of the EDMA_ConfigLoopTransfer function because the data structure for edam_setup_loop was clearer to me in terms of what value needed to be what for my needs.
Matching :
i2s_config.channel = 1
To
fifobase = SAI_HAL_RxGetFifoAddr((uint32_t)I2S0_BASE, 1);
alleviates crashing into default handler, however I'm still only seeing 0's on my audio buffer...