Go Down

Topic: Implemeting two specific PWM outputs on PA17 and PA19 on SAMD21 (Read 887 times) previous topic - next topic

new_to_due

Hey Guys
I looking for some help on implementing two pwm waveforms on a feather M0. They are to control two switches that cant be on at the same time. A sketch of the waveforms required is attached. The other issue is to have two bursts of the waveform only. The current code I have attached uses a interupt and a count but unfortunately it still give me a minimum of three bursts.

With some help from the forum I was able to implement these waveform on the Arduino Due using complementary waveforms and dead-time but unfortunately the due cannot be used for the project and I need to use the feather M0. So im back to the drawing board in my knowledge.

The code I have so far gives two out puts one at 60us and one for 720us. If i could implement dead time on the second output so it starts after 120us this would achieve the aim of 60us on one  pin then a break of 60us and then a 600us on the second pin. However I dont know how to do this as much as Ive looked through the datasheet so I'm not sure if this can be done.  If anyone has any other way i could achieve the wave forms attached it would be greatly appreciated. My time is running out.

The current code is:

Code: [Select]

// Output 140Hz PWM on timer TCC0 (D12) and TCC2 (D13) on Adafruit Feather M0
void setup()
{
  REG_GCLK_GENDIV = GCLK_GENDIV_DIV(4) |          // Divide the 48MHz clock source by divisor 1: 48MHz/4=12MHz
                    GCLK_GENDIV_ID(4);            // Select Generic Clock (GCLK) 4
  while (GCLK->STATUS.bit.SYNCBUSY);              // Wait for synchronization

  REG_GCLK_GENCTRL = GCLK_GENCTRL_IDC |           // Set the duty cycle to 50/50 HIGH/LOW
                     GCLK_GENCTRL_GENEN |         // Enable GCLK4
                     GCLK_GENCTRL_SRC_DFLL48M |   // Set the 48MHz clock source
                     GCLK_GENCTRL_ID(4);          // Select GCLK4
  while (GCLK->STATUS.bit.SYNCBUSY);              // Wait for synchronization

  // Enable the port multiplexer for the digital pin  D13(PA17)), D12(PA19)

  PORT->Group[g_APinDescription[13].ulPort].PINCFG[g_APinDescription[13].ulPin].bit.PMUXEN = 1;

  PORT->Group[g_APinDescription[12].ulPort].PINCFG[g_APinDescription[12].ulPin].bit.PMUXEN = 1;

  // Connect the TCC0 timer to digital output D13 = PA17 = ODD - port pins are paired odd PMUO and even PMUXE
  // F & E specify the timers: TCC0, TCC1 and TCC2
  PORT->Group[g_APinDescription[13].ulPort].PMUX[g_APinDescription[13].ulPin >> 1].reg = PORT_PMUX_PMUXO_E ;
  PORT->Group[g_APinDescription[12].ulPort].PMUX[g_APinDescription[12].ulPin >> 1].reg = PORT_PMUX_PMUXO_F ;

  // Feed GCLK4 to TCC2 (and TC3)
  REG_GCLK_CLKCTRL = GCLK_CLKCTRL_CLKEN |         // Enable GCLK4 to TCC2 (and TC3)
                     GCLK_CLKCTRL_GEN_GCLK4 |     // Select GCLK4
                     GCLK_CLKCTRL_ID_TCC2_TC3;    // Feed GCLK4 to TCC2 (and TC3)
  while (GCLK->STATUS.bit.SYNCBUSY);              // Wait for synchronization

  // Feed GCLK4 to TCC0 and TCC1
  REG_GCLK_CLKCTRL = GCLK_CLKCTRL_CLKEN |         // Enable GCLK4 to TCC0 and TCC1
                     GCLK_CLKCTRL_GEN_GCLK4 |     // Select GCLK4
                     GCLK_CLKCTRL_ID_TCC0_TCC1;   // Feed GCLK4 to TCC0 and TCC1
  while (GCLK->STATUS.bit.SYNCBUSY);              // Wait for synchronization

  NVIC_SetPriority(TCC0_IRQn, 0);    // Set the Nested Vector Interrupt Controller (NVIC) priority for TCC0 to 0 (highest)
  NVIC_EnableIRQ(TCC0_IRQn);         // Connect TCC0 to Nested Vector Interrupt Controller (NVIC)
 
 
  // Dual slope PWM operation: timers countinuously count up to PER register value then down 0

  REG_TCC2_WAVE |= TCC_WAVE_WAVEGEN_NPWM;        //single slope
  while (TCC2->SYNCBUSY.bit.WAVE);               // Wait for synchronization

  // Dual slope PWM operation: timers countinuously count up to PER register value then down 0

  REG_TCC0_WAVE |= TCC_WAVE_WAVEGEN_NPWM;        //single slope
  while (TCC0->SYNCBUSY.bit.WAVE);               // Wait for synchronization

  // Each timer counts up to a maximum or TOP value set by the PER register,
  // this determines the frequency of the PWM operation:
  REG_TCC2_PER = 43165;                          // Set the frequency of the PWM on TCC2 to 140Hz
  while (TCC2->SYNCBUSY.bit.PER);                // Wait for synchronization

  // Each timer counts up to a maximum or TOP value set by the PER register,
  // this determines the frequency of the PWM operation:
  REG_TCC0_PER = 43165;                          // Set the frequency of the PWM on TCC0 to 140Hz
  while (TCC0->SYNCBUSY.bit.PER);                // Wait for synchronization

  // Set the PWM signal to output 0%duty cycle

  REG_TCC2_CC1 = 0;                      // TCC2 CC1 - on D13 initialise to 0% duty Cycle
  while (TCC2->SYNCBUSY.bit.CC1);       // Wait for synchronization

  REG_TCC0_CC3 = 0;                           // TCC0 CC1 - on D12 initialise to 0% duty Cycle
  while (TCC0->SYNCBUSY.bit.CC3);                 // Wait for synchronization

  // Divide the 48MHz signal by 4 giving 12MHz TCC2 timer tick and enable the outputs

  REG_TCC2_CTRLA |= TCC_CTRLA_ENABLE;             // Enable the TCC2 output
  while (TCC2->SYNCBUSY.bit.ENABLE);              // Wait for synchronization

  // Divide the 48MHz signal by 4 giving 12MHz TCC0 timer tick and enable the outputs

  REG_TCC0_CTRLA |= TCC_CTRLA_ENABLE;             // Enable the TCC0 output
  while (TCC0->SYNCBUSY.bit.ENABLE);              // Wait for synchronization
}

void loop() {
 // Output a burst of 2 PWM pulses at 142Hz, 30% duty cycle every second
  TCC0 ->INTENSET.bit.OVF = 1;                     // Enable overflow (OVF) interrupts on TCC0
  delay(2000);                                    // Wait 2 seconds
}
void TCC0_Handler()
{
  static volatile uint32_t counter;
 
  if (TCC0->INTENSET.bit.OVF && TCC0->INTFLAG.bit.OVF )
  {
    if (counter == 0)
    {
      counter++;
        REG_TCC0_CCB3 = 363;                           // TCC0 CC1 - on D12 set to 50%Duty Cycle
        while (TCC0->SYNCBUSY.bit.CC3);                  // Wait for synchronization
        REG_TCC2_CCB1 = 4351;                            // TCC2 CC1 - on D13 set to 50%Duty Cycle
        while (TCC2->SYNCBUSY.bit.CC1);                   // Wait for synchronization
    }
    else if (counter < 3)                           // Have we counted up to 10?
    {
      counter++;                                      // Increment the counter and continue     
    }
    else
    {
      counter = 0;                                    // Reset the counter     
      REG_TCC0_CCB3 = 0;                              // TCC0 CC3 - on D12 set to 0%Duty Cycle
      while (TCC0->SYNCBUSY.bit.CC3);                 // Wait for synchronization
      REG_TCC2_CCB1 = 0;                              // TCC2 CC1 - on D13 set to 0%Duty Cycle
      while (TCC2->SYNCBUSY.bit.CC1);                 // Wait for synchronization
      TCC0->INTENCLR.bit.OVF = 1;                     // Disable overflow (OVF) interrupts on TCC0     
    }
    TCC0->INTFLAG.bit.OVF = 1;                        // Clear the interrupt flag   
  }
}



Thank you in advance for any help
New_to_Due

MartinL

Hi new_to_due,

The easiest way to generate the pulses you require on the SAMD21 is to use the standard RAMP2 operation, rather than messing about with dead-time insertion and output override, like we had to do on the Arduino Due: https://forum.arduino.cc/index.php?topic=573751.0.

RAMP2 operation interleaves the two PWM channels with the period register (PER) and buffered period register (PERB) being automatically swapped each cycle, to account for the differing periods (and pulse widths) on each channel.

The interrupt service routine (ISR) then is activated to set-up two pulses on each of the two channels and then shut itself down once the total of 4 pulses have been sent.

The following code sets up timer TCC2 for standard RAMP2 operation on digital pins D11 and D13, generating two pulses on each channel every second:

Code: [Select]
// Use the TCC2 timer's standard RAMP2 Operation
void setup()
{
  GCLK->GENDIV.reg = GCLK_GENDIV_DIV(3) |          // Divide the 48MHz clock source by divisor 3: 48MHz/3=16MHz
                     GCLK_GENDIV_ID(4);            // Select Generic Clock (GCLK) 4
  while (GCLK->STATUS.bit.SYNCBUSY);               // Wait for synchronization

  GCLK->GENCTRL.reg = GCLK_GENCTRL_IDC |           // Set the duty cycle to 50/50 HIGH/LOW
                      GCLK_GENCTRL_GENEN |         // Enable GCLK4
                      GCLK_GENCTRL_SRC_DFLL48M |   // Set the 48MHz clock source
                      GCLK_GENCTRL_ID(4);          // Select GCLK4
  while (GCLK->STATUS.bit.SYNCBUSY);               // Wait for synchronization

  // Enable the port multiplexer for the 2 PWM channels on D11 and D13
  PORT->Group[g_APinDescription[11].ulPort].PINCFG[g_APinDescription[11].ulPin].bit.PMUXEN = 1;
  PORT->Group[g_APinDescription[13].ulPort].PINCFG[g_APinDescription[13].ulPin].bit.PMUXEN = 1;
 
  // Connect the TCC2 timer to the port outputs - port pins are paired odd PMUO and even PMUXE
  // F & E specify the timers: TCC0, TCC1 and TCC2
  PORT->Group[g_APinDescription[11].ulPort].PMUX[g_APinDescription[11].ulPin >> 1].reg = PORT_PMUX_PMUXO_E | PORT_PMUX_PMUXE_E;
 
  // Feed GCLK4 to TCC2 and TC3
  GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN |         // Enable GCLK4 to TCC2 and TC3
                      GCLK_CLKCTRL_GEN_GCLK4 |     // Select GCLK4
                      GCLK_CLKCTRL_ID_TCC2_TC3;    // Feed GCLK4 to TCC2 and TC3
  while (GCLK->STATUS.bit.SYNCBUSY);               // Wait for synchronization

  NVIC_SetPriority(TCC2_IRQn, 0);    // Set the Nested Vector Interrupt Controller (NVIC) priority for TCC2 to 0 (highest)
  NVIC_EnableIRQ(TCC2_IRQn);         // Connect TCC2 to Nested Vector Interrupt Controller (NVIC)

  // Interleave TCC2 channels 0 and 1
  TCC2->WAVE.reg = //TCC_WAVE_CICCEN0 |              // Enable the circular counter compare CC0 <--> CCB0 buffer
                   TCC_WAVE_CIPEREN |              // Enable the circular period PER <--> PERB buffer
                   TCC_WAVE_RAMP_RAMP2 |           // Enable alternative ramp 2 operation (RAMP2A)
                   TCC_WAVE_WAVEGEN_NPWM;          // Set the PWM output to normal (single slope) PWM mode
  while (TCC2->SYNCBUSY.bit.WAVE);                 // Wait for synchronization

  TCC2->PER.reg = 119;                             // Set the frequency of the PWM on PER to 120us for the first channel on D11
  while (TCC2->SYNCBUSY.bit.PER);                  // Wait for synchronization
  TCC2->PERB.reg = 7027;                            // Set the frequency of the PWM on PERB to 7027us for the second channel on D13
  while (TCC2->SYNCBUSY.bit.PERB);                 // Wait for synchronization
 
  // The CCx/CCBx register values corresponds to the pulse width in microseconds (us)
  TCC2->CC[0].reg = 0;                             // Set initial pulse width to 0us for the first channel on D11
  while (TCC2->SYNCBUSY.bit.CC0);                  // Wait for synchronization
  TCC2->CC[1].reg = 0;                             // Set initial pulse width to 0us for the second channel on D13
  while (TCC2->SYNCBUSY.bit.CC1);                  // Wait for synchronization

  TCC2->CTRLA.reg = TCC_CTRLA_PRESCALER_DIV16 |    // Set prescaler to 16, 16MHz/16 = 1MHz
                    TCC_CTRLA_PRESCSYNC_PRESC;     // Set the reset/reload to trigger on prescaler clock
                     
  TCC2->CTRLA.bit.ENABLE = 1;                      // Enable the TCC2 counter
  while (TCC2->SYNCBUSY.bit.ENABLE);               // Wait for synchronization
}

void loop() {
  // Output a burst of two PWM pulses on each channel every second
  TCC2->INTENSET.bit.OVF = 1;                      // Enable overflow (OVF) interrupts on TCC2
  delay(1000);                                     // Wait 1 second
}

void TCC2_Handler()
{
  static volatile uint32_t counter;
 
  if (TCC2->INTENSET.bit.OVF && TCC2->INTFLAG.bit.OVF)
  {
    if (counter == 0)
    {
      if (TCC2->STATUS.bit.IDX == 0)               // Sync the first cycle to Ramp A
      {
        TCC2->INTFLAG.bit.OVF = 1;                 // Clear the interrupt flag   
        return;                                    // Exit this interrupt service routine (ISR) and wait for next cycle
      }
      counter++;                                   // Increment the counter and continue 
      TCC2->CCB[0].reg = 59;                       // Set pulse width to 60us for the first channel on D11
      while (TCC2->SYNCBUSY.bit.CCB0);             // Wait for synchronization
      TCC2->CCB[1].reg = 599;                      // Set the pulse width to 600us for the second channel on D13
      while (TCC2->SYNCBUSY.bit.CCB1);             // Wait for synchronization 
    }
    else if (counter < 4)                          // Have we counted up to 4 timer cycles?
    {
      counter++;                                   // Increment the counter and continue
    }
    else
    {
      counter = 0;                                 // Reset the counter         
      TCC2->CCB[0].reg = 0;                        // Set pulse width to 0us for the first channel on D11
      while (TCC2->SYNCBUSY.bit.CCB0);             // Wait for synchronization
      TCC2->CCB[1].reg = 0;                        // Set the pulse width to 0us for the second channel on D13
      while (TCC2->SYNCBUSY.bit.CCB1);             // Wait for synchronization
      TCC2->INTENCLR.bit.OVF = 1;                  // Disable overflow (OVF) interrupts on TCC2     
    }
    TCC2->INTFLAG.bit.OVF = 1;                     // Clear the interrupt flag   
  }
}

Here's your requirement:



Here's the output, (in this image I've shortened the extended period of the longer pulses, in order to show all four pulses together):


new_to_due

Hello MartinL

Once again you have given a great answer. And I can now see Ramp2 operation in the datasheet.
Im wondering though is there anyway to do such an operation on two odd channels such as PA017 and PA19 (D12 and D13 on the feather M0) it seems this operation can only be used on odd/even pin pairs of the same timer output is that correct?.

 I ask this because these are the only two pins I have available on my project for this function and it will not be easy to change it unfortunately.

Thankyou
New_to_Due

MartinL

Hi new_to_due,

Implementing the RAMP2 code got me thinking that it would be possible to implement the two interleaved channels, just by simply changing the waveforms' duty-cycle period every other cycle in software in the interrupt service routine. This is instead of using fancy hardware functionality like dead-time insertion or RAMP2 operation.

I've written two sketches that implement your waveforms using this simpler method. The Arduino Due implementation I've posted on the Arduino Due forum, in the thead I linked to above.

The Arduino Zero/Feather M0 implementation here uses D12 and D13 using timers TCC0 and TCC2 on the separate respective channels. The two timers should be synchronized to each other by the fact that they're both clocked from generic clock 4 (GCLK4), I just attempt to start them as close as possible to each other by simply enabling one after the other, before synchronizing their respective registers.

This code outputs the same waveforms on D12 and D13 using timers TCC0 channel 3 and TCC2 channel 1:

Code: [Select]
// Use the TCC0 and TCC2 to generate two interleaved PWM signals of differing duty-cycle and period
void setup()
{
  GCLK->GENDIV.reg = GCLK_GENDIV_DIV(3) |          // Divide the 48MHz clock source by divisor 3: 48MHz/3=16MHz
                     GCLK_GENDIV_ID(4);            // Select Generic Clock (GCLK) 4
  while (GCLK->STATUS.bit.SYNCBUSY);               // Wait for synchronization

  GCLK->GENCTRL.reg = GCLK_GENCTRL_IDC |           // Set the duty cycle to 50/50 HIGH/LOW
                      GCLK_GENCTRL_GENEN |         // Enable GCLK4
                      GCLK_GENCTRL_SRC_DFLL48M |   // Set the 48MHz clock source
                      GCLK_GENCTRL_ID(4);          // Select GCLK4
  while (GCLK->STATUS.bit.SYNCBUSY);               // Wait for synchronization

  // Enable the port multiplexer for the 2 PWM channels on D12 and D13
  PORT->Group[g_APinDescription[12].ulPort].PINCFG[g_APinDescription[12].ulPin].bit.PMUXEN = 1;
  PORT->Group[g_APinDescription[13].ulPort].PINCFG[g_APinDescription[13].ulPin].bit.PMUXEN = 1;
 
  // Connect the TCC2 timer to the port outputs - port pins are paired odd PMUO and even PMUXE
  // F & E specify the timers: TCC0, TCC1 and TCC2
  PORT->Group[g_APinDescription[12].ulPort].PMUX[g_APinDescription[12].ulPin >> 1].reg = PORT_PMUX_PMUXO_F;// | PORT_PMUX_PMUXE_E;
  PORT->Group[g_APinDescription[11].ulPort].PMUX[g_APinDescription[11].ulPin >> 1].reg = PORT_PMUX_PMUXO_E;// | PORT_PMUX_PMUXE_E;

  // Feed GCLK4 to TCC0 and TCC1
  GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN |         // Enable GCLK4 to TCC0 and TCC1
                      GCLK_CLKCTRL_GEN_GCLK4 |     // Select GCLK4
                      GCLK_CLKCTRL_ID_TCC0_TCC1;   // Feed GCLK4 to TCC0 and TCC1
  while (GCLK->STATUS.bit.SYNCBUSY);               // Wait for synchronization
 
  // Feed GCLK4 to TCC2 and TC3
  GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN |         // Enable GCLK4 to TCC2 and TC3
                      GCLK_CLKCTRL_GEN_GCLK4 |     // Select GCLK4
                      GCLK_CLKCTRL_ID_TCC2_TC3;    // Feed GCLK4 to TCC2 and TC3
  while (GCLK->STATUS.bit.SYNCBUSY);               // Wait for synchronization

  NVIC_SetPriority(TCC0_IRQn, 0);    // Set the Nested Vector Interrupt Controller (NVIC) priority for TCC0 to 0 (highest)
  NVIC_EnableIRQ(TCC0_IRQn);         // Connect TCC0 to Nested Vector Interrupt Controller (NVIC)
  //NVIC_SetPriority(TCC2_IRQn, 0);    // Set the Nested Vector Interrupt Controller (NVIC) priority for TCC2 to 0 (highest)
  //NVIC_EnableIRQ(TCC2_IRQn);         // Connect TCC2 to Nested Vector Interrupt Controller (NVIC)

  TCC0->WAVE.reg = TCC_WAVE_WAVEGEN_NPWM;          // Set the PWM output to normal (single slope) PWM mode
  while (TCC0->SYNCBUSY.bit.WAVE);                 // Wait for synchronization
  TCC2->WAVE.reg = TCC_WAVE_WAVEGEN_NPWM;          // Set the PWM output to normal (single slope) PWM mode
  while (TCC2->SYNCBUSY.bit.WAVE);                 // Wait for synchronization

  TCC0->PER.reg = 119;                             // Set the frequency of the PWM on PER to 120us for the first channel on D12
  while (TCC0->SYNCBUSY.bit.PER);                  // Wait for synchronization
  TCC2->PER.reg = 119;                            // Set the frequency of the PWM on PERB to 120us for the second channel on D13
  while (TCC2->SYNCBUSY.bit.PER);                  // Wait for synchronization
 
  // The CCx register values corresponds to the pulse width in microseconds (us)
  TCC0->CC[3].reg = 0;                             // Set initial pulse width to 0us for the first channel on D12
  while (TCC0->SYNCBUSY.bit.CC3);                  // Wait for synchronization
  TCC2->CC[1].reg = 0;                             // Set initial pulse width to 0us for the second channel on D13
  while (TCC2->SYNCBUSY.bit.CC1);                  // Wait for synchronization

  TCC0->CTRLA.reg = TCC_CTRLA_PRESCALER_DIV16 |    // Set prescaler to 16, 16MHz/16 = 1MHz
                    TCC_CTRLA_PRESCSYNC_PRESC;     // Set the reset/reload to trigger on prescaler clock
  TCC2->CTRLA.reg = TCC_CTRLA_PRESCALER_DIV16 |    // Set prescaler to 16, 16MHz/16 = 1MHz
                    TCC_CTRLA_PRESCSYNC_PRESC;     // Set the reset/reload to trigger on prescaler clock
                     
  TCC0->CTRLA.bit.ENABLE = 1;                      // Enable the TCC0 counter
  TCC2->CTRLA.bit.ENABLE = 1;                      // Enable the TCC2 counter
  while (TCC0->SYNCBUSY.bit.ENABLE);               // Wait for synchronization
  while (TCC2->SYNCBUSY.bit.ENABLE);               // Wait for synchronization
}

void loop() {
  // Output a burst of two PWM pulses on each channel every second
  TCC0->INTENSET.bit.OVF = 1;                      // Enable overflow (OVF) interrupts on TCC0 
  delay(1000);                                     // Wait 1 second
}

void TCC0_Handler()
{
  static uint32_t counter;
 
  if (TCC0->INTENSET.bit.OVF && TCC0->INTFLAG.bit.OVF)
  {
    if (counter == 0 || counter == 2)
    {   
      counter++;                                   // Increment the counter and continue 
      TCC0->CCB[3].reg = 59;                       // Set pulse width to 60us for the first channel on D12
      while (TCC0->SYNCBUSY.bit.CCB3);             // Wait for synchronization
      TCC2->CCB[1].reg = 0;                        // Set the pulse width to 0us for the second channel on D13
      while (TCC2->SYNCBUSY.bit.CCB1);             // Wait for synchronization 
      TCC0->PERB.reg = 119;                        // Set the period to 120us for the first channel on D12
      while (TCC0->SYNCBUSY.bit.PERB);             // Wait for synchronization
      TCC2->PERB.reg = 119;                        // Set the period to 120us for the second channel on D13
      while (TCC2->SYNCBUSY.bit.PERB);             // Wait for synchronization 
    }
    else if (counter == 1 || counter == 3)
    {
      counter++;                                   // Increment the counter and continue
      TCC0->CCB[3].reg = 0;                        // Set pulse width to 0us for the first channel on D12
      while (TCC0->SYNCBUSY.bit.CCB3);             // Wait for synchronization
      TCC2->CCB[1].reg = 599;                      // Set the pulse width to 600us for the second channel on D13
      while (TCC2->SYNCBUSY.bit.CCB1);             // Wait for synchronization 
      TCC0->PERB.reg = 7027;                       // Set the period to 7028us for the first channel on D12
      while (TCC0->SYNCBUSY.bit.PERB);             // Wait for synchronization
      TCC2->PERB.reg = 7027;                       // Set the period to 7028us for the second channel on D13
      while (TCC2->SYNCBUSY.bit.PERB);             // Wait for synchronization
    }
    else
    {
      counter = 0;                                 // Reset the counter         
      TCC0->CCB[3].reg = 0;                        // Set pulse width to 0us for the first channel on D12
      while (TCC0->SYNCBUSY.bit.CCB3);             // Wait for synchronization
      TCC2->CCB[1].reg = 0;                        // Set the pulse width to 0us for the second channel on D13
      while (TCC2->SYNCBUSY.bit.CCB1);             // Wait for synchronization
      TCC0->PERB.reg = 119;                        // Set the period to 120us for the first channel on D12
      while (TCC0->SYNCBUSY.bit.PERB);             // Wait for synchronization
      TCC2->PERB.reg = 119;                        // Set the period to 120us for the second channel on D13
      while (TCC2->SYNCBUSY.bit.PERB);             // Wait for synchronization
      TCC0->INTENCLR.bit.OVF = 1;                  // Disable overflow (OVF) interrupts on TCC0   
    }
    TCC0->INTFLAG.bit.OVF = 1;                     // Clear the interrupt flag   
  }
}

voske65

Maybe this helps :
high-speed-pwm-on-arduino-atsamd21

It explains a bit on the timers per pin and odd and even registers in the Arduino Sketch

Go Up