Monday, May 2, 2011

To DMA or not to DMA - part 2

After my first try with the DMA controller on the XMEGA was a success (after a lot of wasted time), I decided to continue and use another DMA channel for reading the audio data from the SD card...
So I swapped the pins from the card's SPI interface (USART in master SPI mode) and started writing code. The trick with reading from SPI is that you have to write to SPI in the same time, because the MCU is the master and the card is the slave. So I actually configured 2 DMA channels just for reading data from the card. One writes blocks of 0xFF's and the other channel reads the answers. My idea was to start reading a sector (send commands, etc) then transfer the data block in 32 byte chunks using DMA. When the buffer had data, start transferring it to the audio decoder via another DMA channel. If the buffer is full, pause the transfer from the SD card and if the buffer is empty, pause the transfer to the audio decoder. In the end, the data transfer would've been done by the DMA controller and some interrupts.

And here I found a bug. After some segments (32 byte chunks) are read from the card, the vs1053 dma channel starts sending them to the audio decoder and the dma channel that is supposed to read data from the card doesn't read everything (1-2 bytes remain unread). This problem occurs when the VS1053 DMA channel triggers an interrupt. If I stop the VS1053 dma channel entirely, the reading from the SD card goes well, but when an interrupt is triggered by the VS DMA channel, the SD read DMA channel leaves 1-2 bytes unread or the SD write channel leaves 1-2 bytes unwritten and this blocks the reading from the card because an interrupt never gets triggered.

I didn't found a way around this issue... If anybody has any suggestions, please leave a comment below.


  1. Andrei, im trying to do something similar, saving to and retrieving data on SD card, using DMA on the xmega.
    I tried following the example by stromflo (last piece of code in section 8) without much luck.
    I see on my oscope something is happening on the MOSI line, but i can never get things to read back. your doing direct memory blocks right, meaning no FATfs?

    mind if you send me your version (buggy or not) I need some hints, or help figuring this out.

    the non-dma way is too slow for me.


  2. Actually, I am using a file system (FAT16/32). But I read entire blocks when I've figured out which blocks to read.

    I gave up reading from SD card using DMA because I couldn't use DMA for SD card and DMA for the audio decoder in the same time. I couldn't get rid of the bug that is described in this post. So I decided to use DMA only to send data to the audio decoder and read data from the SD card classically.

    This way is better for me because I am designing a new version for the audio player that will have a hard drive and I couldn't read from the HDD with the DMAc. Also I will read the data streamed from the online stations via the ethernet controller and again it would be pretty complicated to use DMA.

    Hope I've been of help.
    Maybe you could tell me what are you trying to transfer and I could give you alternatives.

  3. im trying to use the xmega dma as a datalogger, logging from ADC directly to SD card, using DMA.

    I am able to read/write to classically(non-DMA) to SD card, but i want to gather data faster.

    I want to reach a point where i go from ADC to SD card using DMA, and read sd card to uart serial to pc, classical method. were you ever able to write to sd card using DMA?


  4. I haven't tried to write to the card (I am doing playback, no recording yet). It should be possible but I think you will face the same problem as me. I would try transferring from ADC to SRAM with DMA (huge buffer 4-8KB) and write to the card as soon as there is enough data (at least one sector). I don't think you can achieve very high continuous bitrates but still, it would be pretty fast.