Hi Daniel,
Here's some code that runs the TCC1 timer PWM at 50% duty-cycle, 40kHz on D9:
// Output 40kHz PWM on timer TCC1 (10-bit resolution)
void setup()
{
REG_GCLK_GENDIV = GCLK_GENDIV_DIV(1) | // Divide the 48MHz clock source by divisor 1: 48MHz/1=48MHz
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 PWM channel on pin D9
PORT->Group[g_APinDescription[9].ulPort].PINCFG[g_APinDescription[9].ulPin].bit.PMUXEN = 1;
// Connect the TCC1 timer to the port outputs - port pins are paired odd PMUO and even PMUXE
// F & E peripherals specify the timers: TCC0, TCC1 and TCC2
PORT->Group[g_APinDescription[9].ulPort].PMUX[g_APinDescription[9].ulPin >> 1].reg |= PORT_PMUX_PMUXO_E;
// 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
// Normal (single slope) PWM operation: timers countinuously count up to PER register value and then is reset to 0
REG_TCC1_WAVE |= TCC_WAVE_WAVEGEN_NPWM; // Setup single slope PWM on TCC1
while (TCC1->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: 959 = 50kHz
REG_TCC1_PER = 1199; // Set the frequency of the PWM on TCC1 to 40kHz
while(TCC1->SYNCBUSY.bit.PER);
// The CCBx register value corresponds to the pulsewidth in microseconds (us)
REG_TCC1_CC1 = 599; // Set the duty cycle of the PWM on TCC1 to 50%
while(TCC1->SYNCBUSY.bit.CC1);
// Enable TCC1 timer
REG_TCC1_CTRLA |= TCC_CTRLA_PRESCALER_DIV1 | // Divide GCLK4 by 1
TCC_CTRLA_ENABLE; // Enable the TCC0 output
while (TCC1->SYNCBUSY.bit.ENABLE); // Wait for synchronization
}
void loop() { }
Unfortunately, there isn't much information on how to set things up. The best source of information is the SAMD21 datasheet.
The register definitions are stored (at least on my Windows machine) at:
C:\Users\Computer\AppData\Local\Arduino15\packages\arduino\tools\CMSIS\4.0.0-atmel\Device\ATMEL\samd21\include... directory.
In this directory there are two sub-directories, "instance" and "component".
The "instance" directory contains the header files with definitions for each instance of peripheral, for example: "tcc0.h", "tcc1.h", etc...
The "component" directory contains the header files with definitions for peripheral's register bitfields, for instance "tcc.h". This is common to all TCC peripherals, so in this case there's only on file per peripheral.
In the present code it seems that both TCC0 and TCC1 are used ? (Feed GCLK 4 to...)
The SAMD21 hardware doesn't offer the option of clocking the TCC timers with separate generic clocks. The generic clock is instead fed to timer pairs: TCC0 & TCC1, TCC2 & TC3, and finally TC4 & TC5.
In the present code the generic clock is fed to timer TCC0 and to timer TCC1, but TCC1 isn't being used.
Kind regards,
Martin