Once finding the libraries in C:\Users\%USERNAME%\AppData\Local\Arduino15\packages\adafruit\tools\CMSIS-Atmel\1.2.2\CMSIS\Device\ATMEL\same51\include\ and searching register names the correlation with the datasheet became a bit clearer. The configurations of the TCC0 is a lot similar to the SAMD51 but configuring the GCLK and PORT mapping is a bit different. A lot of help already from shawnhymel's blog and his reference to MartinL on the arduino forms leading into the right direction.
Here's my 20 kHz with configurable dutycycles for pin 12 (PA22) and 13 (PA23), where pin 13 is inverted:
Code: Select all
int period = 48*50 - 3;
void setupTimers()
{
// Enable and configure generic clock generator 6
REG_GCLK_GENCTRL6 = GCLK_GENCTRL_IDC | // Set the duty cycle to 50/50 HIGH/LOW
GCLK_GENCTRL_GENEN | // Enable GCLK4
GCLK_GENCTRL_SRC_DFLL | // Set the 120MHz clock source
4; // Divide
while (GCLK->SYNCBUSY.reg); // Wait for synchronization
// Feed GCLK4 to TCC0 and TCC1
REG_GCLK_PCHCTRL25 = GCLK_PCHCTRL_BANNED | // Enable GCLK4 to TCC0 and TCC1
GCLK_PCHCTRL_GEN_GCLK6; // Select GCLK5
while (GCLK->SYNCBUSY.reg); // Wait for synchronization
/////// TCC0 //////
// Divide counter by 1 giving 48 MHz (20.83 ns) on each TCC0 tick
TCC0->CTRLA.reg |= TCC_CTRLA_PRESCALER(TCC_CTRLA_PRESCALER_DIV1_Val);
// Use "Normal PWM" (single-slope PWM): count up to PER, match on CC[n]
TCC0->WAVE.reg = TCC_WAVE_WAVEGEN_NPWM | TCC_WAVE_POL(1 << 3); // Select NPWM as waveform, invert channel 3
while (TCC0->SYNCBUSY.bit.WAVE); // Wait for synchronization
// Set the period (the number to count to (TOP) before resetting timer)
TCC0->PER.reg = period;
while (TCC0->SYNCBUSY.bit.PER);
// Set PWM signal duty cycle
// n for CC[n] is determined by n = x % 4 where x is from WO[x]
TCC0->CC[2].reg = period * dutycycleW / 255;
TCC0->CC[3].reg = period * (255-4) / 255;
while (TCC0->SYNCBUSY.bit.CC2 || TCC0->SYNCBUSY.bit.CC3);
///////// PINS //////
// Enable the port multiplexer for PA22
PORT->Group[PORTA].PINCFG[22].reg |= PORT_PINCFG_PMUXEN;
//PORT->Group[PORTA].PINCFG[22].reg &= ~PORT_PINCFG_PMUXEN; // disable mux
// Connect TCC0 timer to PA22.
// Odd pin num (2*n + 1): use PMUXO
// Even pin num (2*n): use PMUXE
PORT->Group[PORTA].PMUX[22/2].reg = PORT_PMUX_PMUXE(MUX_PA22G_TCC0_WO2);
// Enable the port multiplexer for PA23
PORT->Group[PORTA].PINCFG[23].reg |= PORT_PINCFG_PMUXEN;
// Connect TCC0 timer to PA23.
// Odd pin num (2*n + 1): use PMUXO
// Even pin num (2*n): use PMUXE
PORT->Group[PORTA].PMUX[23/2].reg |= PORT_PMUX_PMUXO(MUX_PA23G_TCC0_WO3);
/////// TCC1 //////
// Divide counter by 1 giving 48 MHz (20.83 ns) on each TCC0 tick
/*TCC1->CTRLA.reg |= TCC_CTRLA_PRESCALER(TCC_CTRLA_PRESCALER_DIV1_Val);
// Use "Normal PWM" (single-slope PWM): count up to PER, match on CC[n]
TCC1->WAVE.reg = TCC_WAVE_WAVEGEN_NPWM | TCC_WAVE_POL(63); // Select NPWM as waveform, invert all channels
while (TCC1->SYNCBUSY.bit.WAVE); // Wait for synchronization
// Set the period (the number to count to (TOP) before resetting timer)
TCC1->PER.reg = period;
while (TCC1->SYNCBUSY.bit.PER);
// Set PWM signal duty cycle
// n for CC[n] is determined by n = x % 4 where x is from WO[x]
TCC1->CC[3].reg = period * 254 / 255;
while (TCC1->SYNCBUSY.bit.CC3);
///////// PINS //////
// Enable the port multiplexer for PA23
PORT->Group[PORTA].PINCFG[23].reg |= PORT_PINCFG_PMUXEN;
// Connect TCC0 timer to PA23. Function F is TCC0/WO[2] for PA18.
// Odd pin num (2*n + 1): use PMUXO
// Even pin num (2*n): use PMUXE
PORT->Group[PORTA].PMUX[23/2].reg |= PORT_PMUX_PMUXO(MUX_PA23F_TCC1_WO7);
*/
// Enable output (start PWM)
TCC0->CTRLA.reg |= (TCC_CTRLA_ENABLE);
//TCC1->CTRLA.reg |= (TCC_CTRLA_ENABLE);
// Wait for synchronization*/
while (TCC0->SYNCBUSY.bit.ENABLE || TCC1->SYNCBUSY.bit.ENABLE);
}