PDA

View Full Version : Mini project: do something with dma



christoph
10-16-2013, 10:33 PM
There seem to be few examples of DMA usage for the teensy 3 (the Cortex-M4 is my first step away from AVRs, so I'm probably not good at finding suitable tutorials and such), so I just tried it.

My first steps: transfer 1 (and then 2) bytes from memory location A to memory location B, no peripherals involved.

Why 1 or 2? Just to see if just 1 is transferred if I want 1, and if 2 are transferred when I want 2. After reading the relevant sections of the datasheet and the "Quick Reference User Guide", it was pretty simple. The different modes for some of the registers (NBYTES, CITER, BITER) were a bit puzzling, but somehow it all made sense. I use the teensyduino libs in Code::Blocks, so no setup() and loop() but just a main():

#include <WProgram.h>

int main(void)
{
/** prepare LED **/
pinMode(LED_BUILTIN, 1);
/** source and destination **/
static uint8_t source[2] = {0xAA, 0xBB};
static uint8_t dest[2] = {0};

/** configure dma channel 0 **/
DMA_TCD0_SADDR = source; // source address
DMA_TCD0_SOFF = 1; // after each read, increment source address by 1
DMA_TCD0_ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(0); // 8 bits source and dest
DMA_TCD0_NBYTES_MLNO = 2; // minor byte count
DMA_TCD0_SLAST = 0; // offset added to source address after completion of major loop
DMA_TCD0_DADDR = dest; // destination address
DMA_TCD0_DOFF = 1; // after each write, increment destination address by 1
DMA_TCD0_CITER_ELINKNO = 1; // major loop count (must match CITER)
DMA_TCD0_DLASTSGA = 0; // offset added to dest address after completion of major loop
DMA_TCD0_BITER_ELINKNO = 1; // major loop count (must match BITER)
DMA_TCD0_CSR = 0; // no special features

/** start dma transfer **/
DMA_SSRT = DMA_SSRT_SSRT(0);

/** wait for transfer to be completed **/
while(!(DMA_TCD0_CSR & DMA_TCD_CSR_DONE));

if ((dest[0] == 0xAA) && (dest[1] == 0))
{
digitalWriteFast(LED_BUILTIN, 1);
while(1);
}
else
if ((dest[0] == 0xAA) && (dest[1] == 0xBB))
{
while (1)
{
digitalWriteFast(LED_BUILTIN, 1);
delay(250);
digitalWriteFast(LED_BUILTIN, 0);
delay(250);
}
}
else
{
while (1)
{
digitalWriteFast(LED_BUILTIN, 1);
delay(500);
digitalWriteFast(LED_BUILTIN, 0);
delay(500);
}
}
}


When DMA_TCD0_NBYTES_MLNO is set to 1, the LED is just on. When it is set to two, it flashes twice a second, just as planned. Messing around with the source values makes it flash once a second.

PaulStoffregen
10-16-2013, 11:04 PM
Here's an old thread with a memcpy based on DMA.

http://forum.pjrc.com/threads/18237-teensy-3-0-memory-to-memory-DMA-help

As far as I know, the only published libraries with DMA so far are OctoWS2811 and Hyple's work on audio (http://forum.pjrc.com/threads/15748-Teensy3-I2S-with-DMA).

I'm planning to publish a DMA-based audio library soon. It will have 4 DMA objects, I2S in, I2S out, PWM out and ADC in.

The USB stack uses DMA, but it's completely different than the general purpose DMA controller.

christoph
10-17-2013, 07:21 AM
I didn't see that thread, thanks! I searched for DMA using the forum search, but it didn't show any results. Maybe the search term is too short?