SAMD51 DAC using DMA seems too fast?

Go To Last Post
2 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello Everyone,

I'm working on implementing some code using the SAMD51 on the Adafruit Metro M4 express.

I create a single period sinusoid (4000 samples long) and block-write it using DMA to the DAC at what I thought was 1M Sample/second.

Problem is:  the sinusoid when looked at on the scope has a period of 200uS - which would make it a whopping 20M Samples/second - seems incorrect....

the DMA is triggered every 800uS - which looks good on the scope (time between pulses).

Can anyone tell me what I'm missing here - I'm sure that I'll be kicking myself...

thank you in advance for any help!

 

Code using arduino IDE follows........

 

 

#define HWORDS 4000
uint16_t data[HWORDS];
float phase = 3.14159 * 2./HWORDS;
int i;
static DmacDescriptor descriptor1 __attribute__((aligned(16)));

void dma_init() {
  
   static DmacDescriptor descriptor __attribute__((aligned(16)));
   static DmacDescriptor descriptor1 __attribute__((aligned(16)));
   static DmacDescriptor wrb __attribute__((aligned(16)));
   static uint32_t chnl0 = 0;  // DMA channel

    DMAC->BASEADDR.reg = (uint32_t)&descriptor1;   
    DMAC->WRBADDR.reg = (uint32_t)&wrb;           
    DMAC->CTRL.bit.LVLEN0 =1 ; 
    DMAC->CTRL.bit.LVLEN1 =1 ;                    
    DMAC->CTRL.bit.LVLEN2 =1 ;                    
    DMAC->CTRL.bit.LVLEN3 =1 ;                    
    DMAC->CTRL.bit.DMAENABLE = 1;                
    DMAC->Channel[0].CHCTRLA.reg = DMAC_CHCTRLA_TRIGSRC(0x0) |   // Set DMAC t0 software trigger
                                 DMAC_CHCTRLA_TRIGACT_BLOCK;                // DMAC block transfer
    descriptor1.DESCADDR.reg = (uint32_t) &descriptor1;
    descriptor1.BTCTRL.bit.VALID    = 0x1; //Its a valid channel
    descriptor1.BTCTRL.bit.BEATSIZE = 0x1;  // HWORD.
    descriptor1.BTCTRL.bit.SRCINC   = 0x1;   //Source increment is enabled
    descriptor1.BTCTRL.bit.DSTINC   = 0x0;   //Destination increment disabled
    descriptor1.BTCNT.reg           = HWORDS;   //HWORDS points to send
    descriptor1.SRCADDR.reg         = (uint32_t)&data + 2*HWORDS;   //send from the data vevtor
    descriptor1.DSTADDR.reg         = (uint32_t)&DAC->DATA[1].reg;   //to the DAC output
    // start channel
    DMAC ->Channel[0].CHCTRLA.bit.ENABLE = 0x1;     //OK
    DMAC->CTRL.bit.DMAENABLE = 1;
}

void dac_init(){
    GCLK->GENCTRL[7].reg = GCLK_GENCTRL_DIV(4) |       // Divide the 48MHz clock source by divisor 4: 48MHz/4 = 12MHz (max for DAC)
                         GCLK_GENCTRL_GENEN |        // Enable GCLK7
                         GCLK_GENCTRL_SRC_DFLL;      // Select 48MHz DFLL clock source
           
  while (GCLK->SYNCBUSY.bit.GENCTRL7);               
    GCLK->PCHCTRL[42].reg = GCLK_PCHCTRL_CHEN |        // Enable the DAC peripheral channel
                              GCLK_PCHCTRL_GEN_GCLK7;    // Connect generic clock 7 to DAC
    MCLK->APBDMASK.bit.DAC_ = 1;
    DAC->CTRLA.bit.SWRST = 1;
    while(DAC->CTRLA.bit.SWRST);
    DAC->DACCTRL[1].reg = DAC_DACCTRL_REFRESH(2) |
          DAC_DACCTRL_CCTRL_CC12M |
          DAC_DACCTRL_ENABLE;// |
          DAC_DACCTRL_LEFTADJ;
    DAC->CTRLA.reg = DAC_CTRLA_ENABLE;
    while(DAC->SYNCBUSY.bit.ENABLE);
    while(!DAC->STATUS.bit.READY1);
    PORT->Group[0].DIRSET.reg = (1 << 2);
    PORT->Group[0].PINCFG[5].bit.PMUXEN = 1;
    PORT->Group[0].PMUX[1].bit.PMUXE = 1;
}

void setup() {
  for (i=0;i<HWORDS;i++) data[i]= 4*(sinf(i*phase) * 510.0f + 512.0f);  //Make a single-period sine wave.
  dac_init();
  dma_init();   
}

void loop() {
  DMAC->SWTRIGCTRL.reg |= (1 << 0);  //Software trigger to set off the DAC
  delayMicroseconds(800);
}

 

 

 

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

More discussion (and, I think a solution) here:  https://forums.adafruit.com/view...