Hi @LeCrAm
To set up non-inverting and inverting complemtary PWM outputs, it's necessary to enable dead time insertion on the selected TCC0's CC channel, (be it CC0, CC1, CC2 or CC3.
Furthermore, when using complentary timer outputs on the SAMD21, by default each TCC0 CCx channel: CC0, CC1, CC2 and CC3, maps on to both it's respective non-inverting timer outputs: WO[0], WO[1], WO[2] and WO[3] and inverting WO[4], WO[5], WO[6] and WO[7]. For example, TCC0 channel CC3 maps on to non-inverting output WO[3] and inverting WO[7].
I mention "by default" because it's possible to change the CCx to WO[x] mapping in the TCC0 WEXCTRL register's OTMX bitfield. The SAMD21 datasheet specifies the applications for which the various OTMX settings are intended, but it can be used to simply add flexibility over which timer outputs to select.
The code below sets up 20kHz complementary PWM, configured for oneshot operation on channel CC3 with the non-inverting output WO[3] on port pin PA19 (Arduino Zero D12) and inverting WO[7] on PA21 (Arduino Zero D7). The oneshot operation is triggered every second in the loop().
Another point to note is that with oneshot operation, it's necessary to set the non-recoverable fault output state (non-inverting = 0, inverting = 1), otherwise the timer outputs will float once the triggered oneshot timer period has elapsed.
It's also possible offset the complementary pulse edges by inserting addition "dead-time" GCLK cycles for both low and high sided outputs, (I've included this feature in the code, but have commented these lines out).
Anyway, here's the example program:
// Output 20kHz with non-inverting and inverting complementary PWM on timer TCC0 with dead-time insertion and oneshot operation
// Digital pins D12 (PA19) non-inverting and D7 (PA21) inverting
void setup()
{
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | // Enable GCLK0
GCLK_CLKCTRL_GEN_GCLK0 | // Select GCLK0
GCLK_CLKCTRL_ID_TCC0_TCC1; // Use 48MHz GCLK0 as the clock source for timers TCC0 and TCC1
// Enable the port multiplexer for the digital pins D12 (PA19) and D7 (PA21)
PORT->Group[PORTA].PINCFG[19].bit.PMUXEN = 1;
PORT->Group[PORTA].PINCFG[21].bit.PMUXEN = 1;
// Connect the TCC0 timer to the port output D12 (PA19) and D7 (PA21) - port pins are paired odd PMUXO and even PMUXE
// D12 (PA19) -> TCC0/WO[3] and its complementary inverting pair: D7 (PA21) -> TCC0/WO[7]
PORT->Group[PORTA].PMUX[19 >> 1].reg |= PORT_PMUX_PMUXO_F;// | PORT_PMUX_PMUXE_F;
PORT->Group[PORTA].PMUX[21 >> 1].reg |= PORT_PMUX_PMUXO_F;// | PORT_PMUX_PMUXE_F;
TCC0->WAVE.reg = TCC_WAVE_WAVEGEN_NPWM; // Setup single slope PWM on TCC0
while (TCC0->SYNCBUSY.bit.WAVE); // Wait for synchronization
TCC0->WEXCTRL.reg = //TCC_WEXCTRL_DTHS(100) | // Add high side dead-time delay of 100 GLCK pulses
//TCC_WEXCTRL_DTLS(100) | // Add low side dead-time delay of 100 GCLK pulses
TCC_WEXCTRL_DTIEN3 | // Enable dead-time insertion on channel CC3
TCC_WEXCTRL_OTMX(0); // Set non-inverting D12 WO[3] and D7 WO[7] to channel CC3
TCC0->DRVCTRL.reg |= TCC_DRVCTRL_NRV7 | // Enable the non-recoverable timer output state after oneshot pulse
TCC_DRVCTRL_NRE7 | // WO[3] output 0 (0V), WO[7] output 1 (3.3V)
TCC_DRVCTRL_NRE3; // (by coincidence WO[7] happens to be on D7)
TCC0->PER.reg = 2399; // Set the frequency of the PWM on TCC0 to 20kHz
while(TCC0->SYNCBUSY.bit.PER); // Wait for synchronization
TCC0->CC[3].reg = 1200; // TCC0 CC3 - 50% duty-cucle on non-inverted output D12 and inverted output D7
while(TCC0->SYNCBUSY.bit.CC0); // Wait for synchronization
TCC0->CTRLBSET.reg = TCC_CTRLBSET_ONESHOT; // Enable oneshot operation
while(TCC0->SYNCBUSY.bit.CTRLB); // Wait for synchronization
TCC0->CTRLA.bit.ENABLE = 1; // Enable the TCC0 output
while (TCC0->SYNCBUSY.bit.ENABLE); // Wait for synchronization
}
void loop()
{
TCC0->CTRLBSET.reg = TCC_CTRLBSET_CMD_RETRIGGER; // Retrigger ONESHOT operation on TCC0
while (TCC0->SYNCBUSY.bit.CTRLB); // Wait for synchronization
delay(1000); // One second delay
}