Hi Miruta22,
If you require the highest PWM resolution possible on all three channels then it's necessary to 3 separate timers: TCC0, TCC1 and TCC2. The timers operate independently from one another.
The following code for the MKRZero outputs 15kHz on D2, 10kHz on D3 and 1kHz on the MOSI pin with a 50% duty-cycle:
// Output 15kHz, 10kHz and 1kHz PWM on timers TCC0, TCC1 and TCC2 respectively
void setup()
{
GCLK->GENDIV.reg = 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
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 3 PWM channels: timer TCC0 outputs
const uint8_t pwmPins[] = { 2, 3, MOSI };
for (uint8_t i = 0; i < 3; i++)
{
PORT->Group[g_APinDescription[pwmPins[i]].ulPort].PINCFG[g_APinDescription[pwmPins[i]].ulPin].bit.PMUXEN = 1;
}
// Connect the TCC0 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[2].ulPort].PMUX[g_APinDescription[2].ulPin >> 1].reg = PORT_PMUX_PMUXO_F | PORT_PMUX_PMUXE_E;
PORT->Group[g_APinDescription[MOSI].ulPort].PMUX[g_APinDescription[MOSI].ulPin >> 1].reg |= 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
TCC0->PER.reg = 3199; // Set the frequency of the PWM on TCC0 to 15kHz
while (TCC0->SYNCBUSY.bit.PER);
TCC1->PER.reg = 4799; // Set the frequency of the PWM on TCC1 to 10kHz
while (TCC1->SYNCBUSY.bit.PER);
TCC2->PER.reg = 47999; // Set the frequency of the PWM on TCC2 to 1kHz
while (TCC2->SYNCBUSY.bit.PER);
// The CCBx register value corresponds to the pulsewidth in microseconds (us)
TCC0->CC[3].reg = 1599; // TCC0 CC3 - 50% duty cycle on D3
while (TCC0->SYNCBUSY.bit.CC3);
TCC1->CC[0].reg = 2399; // TCC1 CC0 - 50% duty cycle on D2
while (TCC1->SYNCBUSY.bit.CC0);
TCC2->CC[0].reg = 23999; // TCC2 CC0 - 50% duty cycle on MOSI
while (TCC2->SYNCBUSY.bit.CC0);
TCC0->CTRLA.bit.ENABLE = 1; // Enable the TCC0 counter
while (TCC0->SYNCBUSY.bit.ENABLE); // Wait for synchronization
TCC1->CTRLA.bit.ENABLE = 1; // Enable the TCC1 counter
while (TCC1->SYNCBUSY.bit.ENABLE); // Wait for synchronization
TCC2->CTRLA.bit.ENABLE = 1; // Enable the TCC2 counter
while (TCC2->SYNCBUSY.bit.ENABLE); // Wait for synchronization
}
void loop() { }