Hello, I am working on a project that requires me to send a precise sequence of signals through a GPIO pin while leaving the CPU free for other tasks, so I'm trying to use DMA to control the pin. However, the DMA channel seems to be unable to write any data to the GPIO registers, and causes an error every time it tries. Here is my test code so far:
when I set the destination address to a normal variable, the DMA works perfectly; print statements show the variable changing correctly, no error is detected, and the interrupt is called when the DMA finishes a cycle. However, when i set the destination to a GPIO port register (GPIO7), the data in the register does not change and the following error code is printed:
According to the IMXRT1060 reference manual, that code means "The last recorded error was a bus error on a destination write". I have tried several different settings for the DMA channel but the same thing always happens. Does anyone know the proper way to write to GPIO using a DMA channel?
Code:
#include "DMAChannel.h"
DMAChannel dma1;
//0x8 is the bit address for GPIO 13, which is on the GPIO7 register.
const uint32_t dmaData[] = {0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000008,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000008,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000008,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000008};
uint32_t testNum = 0;
void setup() {
pinMode(13, OUTPUT);
Serial.begin(115200);
dma1.begin();
//configure DMA using DMAChannel.h
dma1.sourceBuffer(dmaData, sizeof(dmaData));
dma1.destination(GPIO7_DR_TOGGLE);// I have also tried GPIO7_DR and GPIO7_DR_SET
//dma1.destination(testNum); DMA can write to testNum correctly, but not GPIO7_DR_TOGGLE
dma1.attachInterrupt(dmaInterrupt);
dma1.interruptAtCompletion();
dma1.transferSize(4);
dma1.enable();
//configure DMA registers directly. This doesn't work for GPIO either
/*
dma1.TCD->SADDR = dmaData;
dma1.TCD->SOFF = 4;
dma1.TCD->NBYTES = 4;
dma1.TCD->SLAST = -sizeof(dmaData);
dma1.TCD->BITER = sizeof(dmaData) / 4;
dma1.TCD->CITER = sizeof(dmaData) / 4;
dma1.TCD->ATTR_SRC = 2;
dma1.TCD->DADDR = &GPIO7_DR_TOGGLE;
dma1.TCD->DOFF = 0;
dma1.TCD->ATTR_DST = 2;
dma1.TCD->DLASTSGA = 0;
dma1.enable();*/
}
void loop() {
//using manual trigger and delay just for testing purposes
dma1.triggerManual();
delay(100);
Serial.println(GPIO7_DR);
//Serial.println(testNum);
//error occurs only when trying to write to GPIO
if(dma1.error()){
Serial.print("DMA error: ");
Serial.println(DMA_ES, HEX);
}
}
//gets called when writing to testNum, but not GPIO
void dmaInterrupt(){
dma1.clearInterrupt();
Serial.println("DMA finished");
}
when I set the destination address to a normal variable, the DMA works perfectly; print statements show the variable changing correctly, no error is detected, and the interrupt is called when the DMA finishes a cycle. However, when i set the destination to a GPIO port register (GPIO7), the data in the register does not change and the following error code is printed:
Code:
DMA error: 0x80000001
According to the IMXRT1060 reference manual, that code means "The last recorded error was a bus error on a destination write". I have tried several different settings for the DMA channel but the same thing always happens. Does anyone know the proper way to write to GPIO using a DMA channel?