DMA not generating Interrupt

Manuel Schalk

New member
Hi everyone,

I am currently trying to wrap my head around the eDMA on the Teensy4.1. I wrote a simple program that copies two 32-bit numbers from a buffer to another buffer using eDMA's software activation. The numbers stored in the source buffer are both incremented afterwards.
My problem is now, that the DMA does not generate an interrupt when the major loop has finished, even though (I think) I have everything configured correctly to do so. In the loop I am polling on a flag that should be set in the ISR when the DMA is done. My code works if I check the DONE bit in the CSR register directly (commented out in my code). I appreciate any help!
Here is the code:

Code:
#include <Arduino.h>

volatile int32_t src[2];
volatile int32_t dest[2];
volatile int32_t readFlag = 0;

void isr()
{
  Serial.println("Got to isr!");
  readFlag = 1;
  return;
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  while(!Serial){}
  delay(50);

  CCM_CCGR5 |= CCM_CCGR5_DMA(CCM_CCGR_ON);
  delay(50);
	DMA_CR = DMA_CR_GRP1PRI | DMA_CR_EMLM | DMA_CR_EDBG;
	DMA_CERQ = 0;
	DMA_CERR = 0;
	DMA_CEEI = 0;
	DMA_CINT = 0;
	uint32_t *p = (uint32_t *)(0x400E9000);
	*p++ = 0;
	*p++ = 0;
	*p++ = 0;
	*p++ = 0;
	*p++ = 0;
	*p++ = 0;
	*p++ = 0;
	*p++ = 0;

  DMA_TCD0_SADDR = src;
	DMA_TCD0_SOFF = (int16_t) 4;
	DMA_TCD0_ATTR = (uint16_t) (DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2));
	DMA_TCD0_NBYTES_MLNO = 8;
	DMA_TCD0_SLAST = -8;
	DMA_TCD0_DOFF = (int16_t) 4;
	DMA_TCD0_CITER_ELINKNO = (uint16_t) 1;
	DMA_TCD0_DLASTSGA = -8;
	DMA_TCD0_BITER_ELINKNO = (uint16_t) 1;
	DMA_TCD0_CSR = DMA_TCD_CSR_INTMAJOR;
	DMA_TCD0_DADDR = dest;

  DMA_SERQ = 0;
  attachInterruptVector(IRQ_DMA_CH0, isr);
  NVIC_ENABLE_IRQ(IRQ_DMA_CH0);

  src[0] = 5;
  src[1] = 100;

  DMA_TCD0_CSR = DMA_TCD_CSR_START;
}

void loop() {
  // put your main code here, to run repeatedly:
  delay(500);
  if(readFlag)
  //if (DMA_TCD0_CSR & DMA_TCD_CSR_DONE)
  {
    readFlag = 0;
    Serial.print(dest[0]);
    Serial.print("\t");
    Serial.println(dest[1]);
    src[0] += 1;
    src[1] +=1;
    DMA_TCD0_CSR = DMA_TCD_CSR_START;
  }
}
 
Off the top of my head, you're geting rid of the DMA_TCD_CSR_INTMAJOR flag when you assign (instead of OR) DMA_TCD_CSR_START to DMA_TCD0_CSR.
There is a special register (SSRT) that you can use to manually start a DMA channel without modifying the CSR register.
 
Oh, you're right! Thank you so much.
I also had to clear the interrupt request writing to the CINT register otherwise the ISR is called indefinetely. It works as intended now, thanks again!
 
Back
Top