Reputation: 23
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));
Upvotes: 1
Views: 1892
Reputation: 2183
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.
Upvotes: 0
Reputation: 213266
NOTE: PORT->Group[0].PMUX
is an array! Which decays into a pointer to the first element if you do PMUX->bit
, so it compiles, but it is wrong. You are setting the first element instead of the pin PIN_PA22/2
that you are interested in.
The routing PMUX
register type in the ASF register map looks like this:
typedef union {
struct {
uint8_t PMUXE:4; /*!< bit: 0.. 3 Peripheral Multiplexing for Even-Numbered Pin */
uint8_t PMUXO:4; /*!< bit: 4.. 7 Peripheral Multiplexing for Odd-Numbered Pin */
} bit; /*!< Structure used for bit access */
uint8_t reg; /*!< Type used for register access */
} PORT_PMUX_Type;
Meaning you can either write to the 8 bit reg
or the 4 bit bit
nibbles. You seem to do the latter. If 0x05
is the "magic number" obtained by the manual, you should write this one both to the "even" and the "odd" nibble. That is:
PORT->Group[0].PMUX[PIN_PA22/2].bit.PMUXE = (0x5 << 4);
PORT->Group[0].PMUX[PIN_PA22/2].bit.PMUXO = (0x5 << 0);
Or if you will, you can alternatively use pointless ASF bloatware macros to hide away "scary" bitwise logic:
PORT->Group[0].PMUX[PIN_PA22/2].reg = PORT_PMUX_PMUXE(0x5) | PORT_PMUX_PMUXO(0x5);
If you don't get these right, there will be no activity on the pin at all.
Upvotes: 0