Hi smerrett79,
The simplest way to interleave two PWM signals on to a single channel output is to use both the TCC timer's duty-cycle and period circular buffers.
In this mode both the Counter Compare: CCx and buffered equivalent: CCBx are loaded with the required duty-cycles. The same goes for the period registers: PER and PERB. At the end of each timer cycle the timer switches or cycles between them effectively interleaving two channels on to a single output.
Here's an example that sets up circular buffers for CC[0]/CCB[0] and PER/PERB on timer TCC0, output on D2 (Arduino Zero) or port pin PA14. The two interleaved channels output 50% duty-cycle at 100Hz and 200Hz frequencies:
// Use the TCC0 timer with circular CC and PER buffers to interleave two PWM signals on to a single channel (channel 0)
void setup()
{
// Feed GCLK0 to TCC0 and TCC1
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | // Enable GCLK0
GCLK_CLKCTRL_GEN_GCLK0 | // Select GCLK0 at 48MHz
GCLK_CLKCTRL_ID_TCC0_TCC1; // Feed GCLK4 to TCC0 and TCC1
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
// Enable the port multiplexer for the PWM channel TCC0 WO[0] on D2
PORT->Group[g_APinDescription[2].ulPort].PINCFG[g_APinDescription[2].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 TCC0
PORT->Group[g_APinDescription[2].ulPort].PMUX[g_APinDescription[2].ulPin >> 1].reg |= PORT_PMUX_PMUXE_F;
// Interleave TCC0 two PWM signals on to a single channel using the CC and PER circular buffers
TCC0->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_WAVEGEN_NPWM; // Set the PWM output to normal (single slope) PWM mode
while (TCC0->SYNCBUSY.bit.WAVE); // Wait for synchronization
TCC0->PER.reg = 239999; // Set the frequency of the PWM on PER to 200Hz on D2
while (TCC0->SYNCBUSY.bit.PER); // Wait for synchronization
TCC0->PERB.reg = 479999; // Set the frequency of the PWM on PERB to 100Hz on D2
while (TCC0->SYNCBUSY.bit.PERB); // Wait for synchronization
TCC0->CC[0].reg = 120000; // Set the duty-cycle to 50%
while (TCC0->SYNCBUSY.bit.CC0); // Wait for synchronization
TCC0->CCB[0].reg = 240000; // Set the duty-cycle to 50%
while (TCC0->SYNCBUSY.bit.CCB0); // Wait for synchronization
TCC0->CTRLA.bit.ENABLE = 1; // Enable the TCC0 counter
while (TCC0->SYNCBUSY.bit.ENABLE); // Wait for synchronization
}
void loop() {}
Here's the output on the scope:
To change the period or duty-cycle over set number of cycles without disrupting the output, it's possible use the event system to get a second timer to count TCC0 cycles and get this second timer to call an interrupt service routine, in order to change the CC[0]/CCB[0] and/or PER/PER[0] registers.