DMA with MKR1010. Improving Freqency of Sinus

Hello there,

i am to generate a sine wave with the maximum possible frequency on the mkr1010. About the resolution of the DAc and the number of samples I could thus already generate a sine of 25kHz, see the following code:

#define DAC_RESOLUTION 12
#define MAX_SAMPLES 10

int i = 0; 
// Frequency 25kHz
static int sineTable[MAX_SAMPLES] = 
{
0x800,0xcb3,0xf9b,0xf9b,0xcb3,
0x800,0x34c,0x64,0x64,0x34c,
};


void setup() {
  
  analogWriteResolution(DAC_RESOLUTION);  
  analogReadResolution(DAC_RESOLUTION);
}

void loop() {
  
  // Iteration of Datapoints
   i = (i+1) % MAX_SAMPLES;

// write wave data to DAC0
  analogWrite(A0, sineTable[i]);  // write the selected waveform on DAC0
}

The sine is quite badly resolved but through a filter it looks better again. However, I was told to generate an even higher frequency via DMA. However, I find nothing on the Internet to control the registers for the MKR1010 and since I use Arduino for the first time, I am also a little overwhelmed. Does anyone have tips or tutorials available?

Translated with DeepL Translate: The world's most accurate translator (free version)

Please post a picture of that.

This finds a few references to DMA with SAMD on Arduino: arduino samd dma - Google Search - including a library from Adafruit...

I have found the results on google too. But its difficult to understand the Libraries without any examples

Hi @mc_umitosch

Here's some example code generating a 25kHz sine wave on A0, using the DAC, DMAC and a timebase triggered by timer TCC0:

// Output sine wave with a frequency of 25kHz on analog pin A0 using the DAC, DMAC and a timebase triggered by TCC0
volatile uint16_t sintable1[64];

volatile DmacDescriptor wrb[DMAC_CH_NUM] __attribute__ ((aligned (16)));                   // Write-back DMAC descriptors
volatile DmacDescriptor descriptor_section[DMAC_CH_NUM] __attribute__ ((aligned (16)));    // DMAC channel descriptors
DmacDescriptor descriptor __attribute__ ((aligned (16)));                                  // Place holder descriptor

void setup()
{
  for (uint16_t i = 0; i < 64; i++)                                 // Calculate the first sine table with 64 entries
  {
    sintable1[i] = (uint16_t)((sinf(2 * PI * (float)i / 64) * 511) + 512);
  }
  
  analogWriteResolution(10);                                        // Set the DAC's resolution to 10-bits
  analogWrite(A0, 0);                                               // Initialise the DAC
  
  DMAC->BASEADDR.reg = (uint32_t)descriptor_section;                // Set the descriptor section base address
  DMAC->WRBADDR.reg = (uint32_t)wrb;                                // Set the write-back descriptor base adddress
  DMAC->CTRL.reg = DMAC_CTRL_DMAENABLE | DMAC_CTRL_LVLEN(0xf);      // Enable the DMAC and priority levels

  DMAC->CHID.reg = DMAC_CHID_ID(0);                                 // Select DMAC channel 0
  DMAC->CHCTRLB.reg = DMAC_CHCTRLB_LVL(0) |                         // Set DMAC priority to level 0 (lowest)
                      DMAC_CHCTRLB_TRIGSRC(TCC0_DMAC_ID_OVF) |      // Trigger on timer TCC0 overflow
                      DMAC_CHCTRLB_TRIGACT_BEAT;                    // Trigger every beat
  descriptor.DESCADDR.reg = (uint32_t)&descriptor_section[0];                   // Set up a circular descriptor
  descriptor.SRCADDR.reg = (uint32_t)&sintable1[0] + 64 * sizeof(uint16_t);     // Read the current value in the sine table
  descriptor.DSTADDR.reg = (uint32_t)&DAC->DATA.reg;                            // Copy it into the DAC data register
  descriptor.BTCNT.reg = 64;                                                    // This takes the number of sine table entries = 64 beats
  descriptor.BTCTRL.reg = DMAC_BTCTRL_BEATSIZE_HWORD |              // Set the beat size to 16-bits (Half Word)
                          DMAC_BTCTRL_SRCINC |                      // Increment the source address every beat
                          DMAC_BTCTRL_VALID;                        // Flag the descriptor as valid
  memcpy((void*)&descriptor_section[0], &descriptor, sizeof(DmacDescriptor));  // Copy to the channel 0 descriptor  

  GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN |         // Enable GCLK
                      GCLK_CLKCTRL_GEN_GCLK0 |     // Select GCLK0
                      GCLK_CLKCTRL_ID_TCC0_TCC1;   // Select GCLK0 as the clock source for timers: TCC0 and TCC1
 
  TCC0->WAVE.reg = TCC_WAVE_WAVEGEN_NFRQ;          // Setup TCC0 in Normal Frequency (NFRQ) mode
  while (TCC0->SYNCBUSY.bit.WAVE);                 // Wait for synchronization
  
  TCC0->PER.reg = 29;                              // 25kHz sine wave, 64 samples: 48MHz / (25000 * 64) - 1
  while(TCC0->SYNCBUSY.bit.PER);                   // Wait for synchronization
 
  TCC0->CTRLA.bit.ENABLE = 1;                      // Enable the TCC0 output
  while (TCC0->SYNCBUSY.bit.ENABLE);               // Wait for synchronization
 
  DMAC->CHID.reg = DMAC_CHID_ID(0);                // Select DMAC channel 
  DMAC->CHCTRLA.reg |= DMAC_CHCTRLA_ENABLE;        // Enable DMAC channel 
}

void loop() {}

1 Like

Hi @MartinL

thank u really much. That example helped me a lot!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.