SAMD51 PWM on TCC0:2

Hi all,

For some background on this:

I have made some backpacks for Adafruit Trinket M0, Feather M9 and ItsyBitsy M0. I was successful in modifying the variant.h and vatiant.cpp files to tweak some of the pin mapping to allow me to get 4 (trinket M0) and 8 (feather and ItsyBitsy M0) independent PWM channels. I then re-worked the analogWrite() funtion to be fastAnalogWrite() so I could have higher resolution at higher frequencies. This was successful with all the M0 chips I've used and even created a custom board based on the trinket M0's SAMD21E18A chip.

So where I am at now:

Since the ItsyBitsy had an M4 variant I thought why not use the existing backpack for the M0 variant and see if I can do the same with a SAMD51 chip. I modified the variant.h and variant.cpp files (could only get 6 PWM without reworking the backpack but to some minor timer pin changes). I am also now updating my fastAnalogWrite() function to update the correct registers on the SAMD51. I have had luck with 5 of the PWM channels but am banging my head against the wall with the 6th. I don't know if I am missing something, but here what I have so far.

I am using the following pin/time combo:
PA18 TCC0/WO[6]
PA19 TCC1/WO[3]
PA21 TCC0/WO[1]
PA22 TCC1/WO[6]
PA23 TCC0/WO[3]
PA30 TCC2/WO[0]

I can get all working except for PA18 TCC0/WO[6]. I can toggle the pic on an doff so I know it's physically wired. The interesting thing is that PA22 happens to have an alternate TCC that is TCC0/WO[2] which is functionally the same TCC output. SO if I modify PA22 to use TCC2/WO[2] it works. And it works when I write to PA18 or PA22. But nothing happens on the PA18 pin. But writing to PA18 TCC0/WO[6] updates PA22 TCC0/WO[2]. So the code in theory is updating the registers properly and since it works with PA21 TCC0/WO[1] and PA23 TCC0/WO[3] it is working with the TCC0 timer module. I just can't figure out why I am not getting any PWM output on PA18 TCC0/WO[6]

variant.cpp definitions for above port/tccx

{ PORTA,  18, PIO_DIGITAL, PIN_ATTR_PWM_G, No_ADC_Channel, TCC0_CH2, NOT_ON_TIMER, EXTERNAL_INT_2 }, // D7
{ PORTA,  19, PIO_DIGITAL, PIN_ATTR_PWM_F, No_ADC_Channel, TCC1_CH3, TC3_CH1, EXTERNAL_INT_3 }, // D9
{ PORTA,  21, PIO_DIGITAL, PIN_ATTR_PWM_G, No_ADC_Channel, TCC0_CH1, NOT_ON_TIMER, EXTERNAL_INT_5 }, // D11
{ PORTA,  22, PIO_DIGITAL, PIN_ATTR_PWM_G, No_ADC_Channel, TCC0_CH2, NOT_ON_TIMER, EXTERNAL_INT_6 }, // D13
{ PORTA,  23, PIO_DIGITAL, PIN_ATTR_PWM_G, No_ADC_Channel, TCC0_CH3, NOT_ON_TIMER, EXTERNAL_INT_7 }, // D12

fastAnalogWrite (SAMD51 TCCx section)

else {
 	// -- Configure TCC
    if (showInit) Serial.print(" Configure TCC");
 	Tcc* TCCx = (Tcc*) GetTC(pinDesc.ulPWMChannel);

 	TCCx->CTRLA.bit.SWRST = 1;
 	while (TCCx->SYNCBUSY.bit.SWRST);

 	// Disable TCCx
 	TCCx->CTRLA.bit.ENABLE = 0;
 	while (TCCx->SYNCBUSY.bit.ENABLE);
 	// Set prescaler to 1/256
 	TCCx->CTRLA.reg = TCC_CTRLA_PRESCALER_DIV1 | TCC_CTRLA_PRESCSYNC_GCLK;
    if (showInit) Serial.println(" TCC_CTRLA_PRESCALER_DIV1");
    // Set TCCx as normal PWM
 	TCCx->WAVE.reg = TCC_WAVE_WAVEGEN_NPWM;
 	while ( TCCx->SYNCBUSY.bit.WAVE );

 	while (TCCx->SYNCBUSY.bit.CC0 || TCCx->SYNCBUSY.bit.CC1);
 	// Set the initial value
 	TCCx->CC[tcChannel].reg = (uint16_t) dutyCycle;
 	while (TCCx->SYNCBUSY.bit.CC0 || TCCx->SYNCBUSY.bit.CC1);
 	// Set PER to required resolution (10, 12 or 13 bit)
 	TCCx->PER.reg = (uint16_t) pwmResolution;
 	while (TCCx->SYNCBUSY.bit.PER);
 	// Enable TCCx
 	TCCx->CTRLA.bit.ENABLE = 1;
 	while (TCCx->SYNCBUSY.bit.ENABLE);
 }

Any help to point out something I may not be aware of or not thought to check. I have tried putting the PWM initialization code at the end of setup() to make sure nothing is overwriting the output configuration. I am at a loss as to why this particular pin is giving me grief. D7 (PA18) is not used for any SERCOM functions and is only defined in the variant files as a digital pin with PWM capability.

Thank you in advance.

Darren

@unlimited_design

Hi Darren,

This issue is because the SAMD51's TCC0 timer has six separate channels (0 to 5), as opposed to the SAMD21's four (0 to 3). This means that the repeated output for TCC0/WO[6] on PA18 should be channel 0 (TCC0_CH0) rather than channel 2 (TCC0_CH2).

Hi Martin,

Thank you. I knew I was overlooking something simple. I glossed over the section 6.2.7 on the datasheet which lists this exact information. Much appreciated.