Combining SPI DMA (SPI mode SD card) and I2S DMA

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Combining SPI DMA (SPI mode SD card) and I2S DMA

1,099 Views
jeremygordon
Contributor II

Hi,

I'm having problems trying to combine two working "bare metal" implementations I created and looking for guidance or tips. Short version, I'm not sure I understand how to get multiple DMA channels to play nice together.

I'm using a custom K20 based board I designed running at 72mhz, and I used the bare minimum of processor expert to configure the system clocks, etc. I'm also using MQX Lite, for tasks and light weight events.

I have a working "bare metal" SPI mode SD card implementation using a from scratch implementation of diskio.c for FatFS, but I used the Kintetis SDK source code as a guide to get a three channel SPI/DMA implementation working. The first DMA channel is for SPI receive, the second DMA channel copies bytes to a temporary location where it is combined with the SPI control flags, and the third DMA channel copies from the temporary location to the SPI PUSHR to transmit. I'm able to get this reading data from an SD card in SPI mode at ~18mhz.

I also have a working "bare metal" I2S implementation that I wrote talking to a codec and using DMA to play back stereo 44.1khz 16-bit audio. My playback is of a sin(x) wave generated in my DMA half complete ISR routine.

My goal is to have audio data DMA'd from the SD card into a buffer then DMA'd to the I2S to the audio codec.

My initial implementation is to set an event in the DMA half complete ISR routine for the I2S. In my task, I have a while loop waiting on the event. When it gets the event, I read 512 bytes from the SD card into the opposite half of the buffer from the one being read by the DMA->I2S.

--- I2S (audio codec)

DMA0 = 1024/2 buffer->I2S

--- SPI (SD card)

DMA1 = 32-bit SPI command->SPI PUSHR

DMA2 = 512 byte memory->32-bit SPI command

DMA3 = 512 byte memory->SPI POPR

I've tried setting the priorities up as 0, 1, 2, 3 respectively on the three DMA channels with the ECP bit enabled, and I've enabled BWC to throttle them a bit, but I keep getting I2S transmit fifo under run errors indicating I'm not feeding the I2S fast enough but unless my math is totally off I should more than be able to feed the 44.1khz 16-bit stereo from 18mhz clocked SPI.

Anyone have any suggestions on samples or documentation, or tips on architecture for something like this?

Thanks!

Jeremy

Labels (1)
Tags (4)
1 Reply

613 Views
isaacavila
NXP Employee
NXP Employee

Hello Jeremy,

First of all, I will recommend you to use ping pong buffer to feed I2S data. This way, you can be sure to have enough data to send to codec and avoid I2S's underrun errors. (You can be filling one buffer from SD card when I2S is taking data from another buffer that was previously filled.)

As a consideration, buffer size should be large enough to store the amount of data that will be sent to codec when another reading from SD card is taking place. For example, If you send 512 bytes (16 bits, estereo) to codec, you should read data every 2.9ms (512 bytes / 2 bytes per sample = 256 samples / 2 channels = 128 samples per channel; If you are sampling 44.1kHz, it should take 128 / 44100Hz = 2.9 ms).

Here is an application note that talks about ping-pong buffer implementation using I2S http://cache.freescale.com/files/32bit/doc/app_note/AN4369.pdf

I hope this can help you.

Best Regards,

Isaac

----------------------------------------------------------------------------------------------------------------------------------------

Note: If this post answers your question, please click the Correct Answer button. Thank you!

----------------------------------------------------------------------------------------------------------------------------------------