Metro M4 Express ATSAMD51 PWM Frequency and Resolution

Hi Jim,

A TC4 channel 1 pin can be found on the Metro M4 Express' digital pin 4, aka port pin PB13.

All that needs to be changed is the digital pin number for the pin configuration (PINCFG) and multiplexer (PMUX) registers from 7 to 4, and as we're now using an odd port pin number (PB13), the PMUX bitfield definition to odd:

PORT->Group[g_APinDescription[4].ulPort].PINCFG[g_APinDescription[4].ulPin].bit.PMUXEN = 1;
 
PORT->Group[g_APinDescription[4].ulPort].PMUX[g_APinDescription[4].ulPin >> 1].reg |= PORT_PMUX_PMUXO(4);

Here's a full example of the TC4 timer set-up to output 50Hz with a 50% duty-cycle on digtial pin D4:

//Set-up timer TC4 to output 50Hz, 50% duty-cycle on digital pin D4
void setup() {
  // Set up the generic clock (GCLK6) used to clock timers
  GCLK->GENCTRL[6].reg = GCLK_GENCTRL_DIV(3) |       // Divide the 48MHz clock source by divisor 3: 48MHz/3 = 16MHz
                         GCLK_GENCTRL_IDC |          // Set the duty cycle to 50/50 HIGH/LOW
                         GCLK_GENCTRL_GENEN |        // Enable GCLK6
                         GCLK_GENCTRL_SRC_DFLL;      // Generate from 48MHz DFLL clock source
                         //GCLK_GENCTRL_SRC_DPLL1;     // Generate from 100MHz DPLL clock source
                         //GCLK_GENCTRL_SRC_DPLL0;     // Generate from 120MHz DPLL clock source
  while (GCLK->SYNCBUSY.bit.GENCTRL6);               // Wait for synchronization 

  GCLK->PCHCTRL[30].reg = GCLK_PCHCTRL_CHEN |        // Enable perhipheral channel
                         GCLK_PCHCTRL_GEN_GCLK6;     // Connect generic clock 6 to TC4, PCHCTRL[30]

  // Enable the peripheral multiplexer on pin D4
  PORT->Group[g_APinDescription[4].ulPort].PINCFG[g_APinDescription[4].ulPin].bit.PMUXEN = 1;
 
  // Set D4 (Port PB13) the peripheral multiplexer to peripheral (even) E(4): TC4, Channel 1 (peripheral A=0, B=1, C=2, D=3, E=4, etc)
  PORT->Group[g_APinDescription[4].ulPort].PMUX[g_APinDescription[4].ulPin >> 1].reg |= PORT_PMUX_PMUXO(4);
 
  TC4->COUNT16.CTRLA.reg = TC_CTRLA_PRESCALER_DIV16 | // Set prescaler to 16, 16MHz/16 = 1MHz
                           TC_CTRLA_PRESCSYNC_PRESC | // Set the reset/reload to trigger on prescaler clock
                           TC_CTRLA_MODE_COUNT16;     // Set the counter to 16-bit mode

  TC4->COUNT16.WAVE.reg = TC_WAVE_WAVEGEN_MPWM;       // Set-up TC4 timer for Match PWM mode (MPWM)
  
  TC4->COUNT16.CC[0].reg = 19999;                    // Use CC0 register as TOP value, set for 50Hz PWM
  while (TC4->COUNT16.SYNCBUSY.bit.CC0);             // Wait for synchronization

  TC4->COUNT16.CC[1].reg = 9999;                     // Set the duty cycle to 50% (CC1 half of CC0)
  while (TC4->COUNT16.SYNCBUSY.bit.CC1);             // Wait for synchronization

  TC4->COUNT16.CTRLA.bit.ENABLE = 1;                 // Enable timer TC4
  while (TC4->COUNT16.SYNCBUSY.bit.ENABLE);          // Wait for synchronization
}

void loop() {}