Hi everyone

I've been playing around some more with generating digital waveforms on the Teensy 3.1. I can get what I needed via bit-banging, but I wanted to try the same using the teensy's eDMA capability.

What I need is a way to write out a buffer of data to PORT D using periodic triggered DMA

I'm monitoring pins 14 and 2 (which are the 2 LSBs for PORTD) with my logic analyser. I'm attempting to use the PIT to trigger a DMA operation.

My assumption was that every time I trigger a DMA operation, the controller would transfer a byte from my buffer (bufferA in this case) to the GPIOD_PDOR register, letting me get HW timed waveform signals. By manipulating the PIT_LDVAL0 value for PIT, I can control the waveform generation rate.

What I see instead is that changing PIT_LDVAL0 does not affect the signal generation rate at all. The max frequency for the LSB i'm seeing is about 470Hz and changing the PIT counter does not affect that rate at all. And this is not a constant rate either. In the screenshot, you can see the signal pulse width is not regular.

Click image for larger version. 

Name:	pulsewidth.PNG 
Views:	116 
Size:	56.1 KB 
ID:	5551

Is there something I'm missing?

I looked at the following threads for reference, but I could not find an example of generating waveforms on multiple pins via DMA. Most of the examples were for digital reads on a Port.

https://forum.pjrc.com/threads/31507-Dastardly-DMA
https://forum.pjrc.com/threads/29247...r-5-MHz-Signal


Here is my code. There were no dma configuration errors reported and I can tell the PIT is running by printing out its current value in the loop()

Thanks.

Code:
#include "Arduino.h"
#include "DMAChannel.h"

const uint16_t N = 4;
unsigned char bufferA[] = { 0x0, 0x3, 0x2, 0x1 };
volatile bool dmaEnabled = false;
DMAChannel dmaChannel0;

/*
set the first 8 pins pins for PortD as
output pins
*/
void setupOutputPins()
{
    // enable clock gate for Port D
    SIM_SCGC5 |= SIM_SCGC5_PORTD;

    // pins for PortD
    byte pinTable[] = { 2, 14, 7, 8, 6, 20, 21, 5 };
    for (uint8_t i = 0; i < sizeof(pinTable)/sizeof(pinTable[0]); i++)
    {
        // this way of setting pins as output seems to work
        pinMode(pinTable[i], OUTPUT);
    }
}

void dmaInterrupt()
{
    Serial.println("Interrupt");
}

void SetupPIT() {

    // PIT clock gate enabled
    SIM_SCGC6 |= SIM_SCGC6_PIT;

    // PIT module enabled
    PIT_MCR = 0;

    // write 1 to clean timer interrupt flag
    PIT_TFLG0 = PIT_TFLG_TIF;

    // set timer 0 for 15 cycles
    PIT_LDVAL0 = 15; 
}

void EnablePIT()
{
    // enable timer 0
    PIT_TCTRL0 = PIT_TCTRL_TEN; 
}


void SetupDMA()
{
    Serial.println("about to configure DMA channel 0");
    dmaChannel0.channel = 0;
    dmaChannel0.sourceBuffer(bufferA, N);
    Serial.println("set up source buffer");

    dmaChannel0.attachInterrupt(dmaInterrupt);
    Serial.println("attached interrupt");

    Serial.println("configuration destination DMA");
    dmaChannel0.TCD->DADDR = &GPIOD_PDOR;
    dmaChannel0.TCD->DOFF = 0;
    dmaChannel0.TCD->ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(0); 

    // set the DMA source and enable triggering
    //DMAMUX0_CHCFG0 |= (DMAMUX_ENABLE | DMAMUX_TRIG | DMAMUX_SOURCE_ALWAYS0); 
    dmaChannel0.triggerContinuously();
    //DMAMUX0_CHCFG0 |= (DMAMUX_ENABLE | DMAMUX_TRIG | DMAMUX_SOURCE_PORTD); 
    //dmaChannel0.transferSize(1);
    //dmaChannel0.transferCount(1);
    dmaChannel0.enable();

    Serial.println("DMA Setup complete");
} 

void setup()
{
    while (!Serial);
    delay(100);
    Serial.println("DMA Test");

    setupOutputPins();
    Serial.println("output pins configured");

    SetupPIT();

    // initialize output to low
    GPIOD_PDOR = 0x0; 

    SetupDMA();
    EnablePIT();

}

void loop()
{
    //if (dmaChannel0.error())
    //{
    //    Serial.println("DMA channel 0 error");
    //}
    //Serial.println(PIT_CVAL0);
}