Using DMA + DAC on SAMD51

hello
currently I wrote this code for a SAMD51 board to produce three pulse waveform at different frequencies, mix/sum them, and output the result using the internal 12 bit DAC.
In this example I'm using TCC1 at 120KHz to update the DAC, and TCC0 at about 21.4KHz to produce a 2.14KHz pulse waveform (the timers runs at 10x the desired frequency so that I can get different pulse width settings). There will be other two timers to produce "freq2" and "freq3" in the same fashion of TCC0.

Other than the 2.14KHz wave and its upper harmonics, I noticed that I get a strong and unwanted 210Hz harmonic.
If I move the "analogWrite" call inside loop(), the output is clean and that harmonic disappears.
If I run the TCC1 faster, that harmonic gets quieter.

I guess the right way to do this (since the sketch will be doing many other things too) would be using the DMA to refresh the DAC value (probably running at its full 1MSPS rate), instead of using an interrupt and a call to analogWrite.
Do you have any example of how I should configure the DAC and the DMA to do this?

also, out of curiosity, why that harmonic gets generated? is it due to the two timers running/computing the output at different sample rates?

thank you

#define PULSE_WIDTH 2
volatile int freq1_count = 0;
volatile uint8_t freq1 = 0;
volatile uint8_t freq2 = 0;
volatile uint8_t freq3 = 0;

void setup() {

  pinMode(DAC0, OUTPUT);
  DAC->DACCTRL[0].bit.CCTRL = 1;
  DAC->DACCTRL[1].bit.CCTRL = 1;
  analogWriteResolution(12);
  analogWrite(DAC0, 0);
  
  GCLK->GENCTRL[7].reg = GCLK_GENCTRL_DIV(1) | GCLK_GENCTRL_IDC |  GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_DFLL;
  while (GCLK->SYNCBUSY.bit.GENCTRL7);
  GCLK->PCHCTRL[25].reg = GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN_GCLK7;

  TCC0->CTRLA.reg = TC_CTRLA_PRESCALER_DIV8 | TC_CTRLA_PRESCSYNC_PRESC;
  TCC0->WAVE.reg = TC_WAVE_WAVEGEN_NPWM;
  while (TCC0->SYNCBUSY.bit.WAVE);
  TCC0->PER.reg = 280;
  while (TCC0->SYNCBUSY.bit.PER);
  TCC0->CC[0].reg = 280/2;
  while (TCC0->SYNCBUSY.bit.CC0);
  TCC0->CTRLA.bit.ENABLE = 1;
  while (TCC0->SYNCBUSY.bit.ENABLE);

  TCC1->CTRLA.reg = TC_CTRLA_PRESCALER_DIV8 | TC_CTRLA_PRESCSYNC_PRESC;
  TCC1->WAVE.reg = TC_WAVE_WAVEGEN_NPWM;
  while (TCC1->SYNCBUSY.bit.WAVE);
  TCC1->PER.reg = 50;
  while (TCC1->SYNCBUSY.bit.PER);
  TCC1->CC[0].reg = 50;
  while (TCC1->SYNCBUSY.bit.CC0);
  TCC1->CTRLA.bit.ENABLE = 1;
  while (TCC1->SYNCBUSY.bit.ENABLE);
  
  void __disable_irq(void);
  
  NVIC_SetPriority(TCC0_1_IRQn, 0);
  NVIC_EnableIRQ(TCC0_1_IRQn);
  TCC0->INTENSET.bit.MC0 = 1;
  while (TCC0->SYNCBUSY.reg > 0);
  
  NVIC_SetPriority(TCC1_1_IRQn, 0);
  NVIC_EnableIRQ(TCC1_1_IRQn);
  TCC1->INTENSET.bit.MC0 = 1;
  while (TCC1->SYNCBUSY.reg > 0);
 
  void __enable_irq(void);
  
}

void TCC1_1_Handler(void) {
  TCC1->INTFLAG.bit.MC0 = 1;
  analogWrite(DAC0, (1365*freq1) + (1365*freq2) + (1365*freq3));
} 

void TCC0_1_Handler(void) {
  TCC0->INTFLAG.bit.MC0 = 1;
  freq1_count = (freq1_count+1)%10;
  freq1_count > PULSE_WIDTH ? freq1 = HIGH : freq1 = LOW;
}

void loop() {

}

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