Search code examples
c++armembeddedpwmsamd21

SAMD21: how to set PWM using TCC?


I'm programming a SAMD21 and I need PWM.

When I chose pin with F function TCC0 output: PA22 - TCC0/WO[4] PA23 - TCC0/WO[5]

I successfully configured TCC0 base counter:

// enable clock for TCC0 - disable clock masking
PM->APBCMASK.reg |= PM_APBCMASK_TCC0;

// set GCLK1 as source to the TCC0 counter
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_GEN(1) | GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_ID(0x1A);
while(!SYSCTRL->PCLKSR.bit.DFLLRDY);

// set counter
TCC0->CTRLA.reg |= TCC_CTRLA_PRESCALER_DIV64; // setting prescaler
TCC0->WAVE.reg |=  TCC_WAVE_WAVEGEN_NPWM | TCC_WAVE_POL0;
while (TCC0->SYNCBUSY.bit.WAVE);

// set TOP (PER) value of counter - frequency
TCC0->CTRLA.bit.RESOLUTION = 0;
TCC0->PER.reg = 48'000'000 / (100 * 64) - 1; // Fpwm = Fglk / (PRESC(PER+1))  --> PER = Fglk / (Fpwm * PRESC) - 1
while (TCC0->SYNCBUSY.bit.PER);

But the problem was how to configure the compare channels - the SAMD21 has only 4 compare channels (CC) but I want output to WO[4] and WO[5].

How can I connect given compare channels to WO[x] pins?

EDIT:

I have also configured pins for mutiplexing (not sure if correctly):

PORT->Group[0].PINCFG->reg |= (1 << PIN_PA22) | (1 << PIN_PA23);
PORT->Group[0].PMUX->bit.PMUXE = (0x5 << (PIN_PA22/2));
PORT->Group[0].PMUX->bit.PMUXO = (0x5 << (PIN_PA23/2 + 1));

Solution

  • There is a PWM library you can re-use code from; it comes with a table (under "extras") with timers, output pins, output channels, pin multiplexers etc.

    The library was written (by me) for SAMD21G-based Arduinos, but all the mappings and code you need are there, and it may help you in your efforts.