Sending timers to specific pins for Adafruit Feather M0

I am trying to send TCC0 to pins D0 and D1 for the Adafruit Feather M0 with a specific frequency of 40kHz using the 8Mhz internal oscillator. I have found a lot of code for setting up the Generic Clock from a MartinL in similar forum posts but I cannot seem to figure out why my code is not working. The main issue is that I am not great with code and trying to understand the port multiplexer and what the example code is doing is not proving to be easy. The following lines are the only lines that have direct correlation to the pins, and they deal with the port multiplexing:

// Enable the port multiplexer for the digital pin D0/PA11 (Left Forward)
  PORT->Group[ PORTA ].PINCFG[ 11 ].bit.PMUXEN = 1;

  PORT->Group[ PORTA ].PMUX[ 11 ].reg = PORT_PMUX_PMUXO_F | PORT_PMUX_PMUXE_F;

The only other instance I can see that there is any type of control is with the timers "control/capture" registers. The lines below set the PWM for supposedly D0/PA11 and P1/PA10 but I do not see what makes these line correlate with those specific pins, I have not been able to find a table with timers and their control/capture registers and what pins they are connected to.

// Initialize the PWM signal to output 50% duty cycle
  TCC0->CC[2].reg = 50;         // TCC0 CC2 - on D0/PA11
  while (TCC0->SYNCBUSY.bit.CC2); //Wait for Synch
  TCC0->CC[3].reg = 50;         // TCC0 CC3 - on D1/PA10
  while (TCC0->SYNCBUSY.bit.CC3); //Wait for Synch

In the above code it is given that for timer 0 the control/capture register number 2 is for D0 and CC3 is for D1. I'm not sure where this comes from, I will include my setup() code below, any and all help is extremely appreciated.

void setup() {

  // Configure Generic Clock 4 to 8Mhz
  GCLK->GENDIV.reg =
    GCLK_GENDIV_ID(4) |
    GCLK_GENDIV_DIV(1); // Keep 8MHz timing
  while(GCLK->STATUS.bit.SYNCBUSY); //Wait for Synch

  // Set up GCLK4 to use the internal 8MHz oscillator
  GCLK->GENCTRL.reg =
    GCLK_GENCTRL_IDC | // Duty Cycle set to 50/50 HIGH/LOW
    GCLK_GENCTRL_GENEN;
    GCLK_GENCTRL_SRC_OSC8M |
    GCLK_GENCTRL_ID(4);
  while(GCLK->STATUS.bit.SYNCBUSY); //Wait for Synch

  // Enable the port multiplexer for the digital pin D0/PA11 (Left Forward)
  PORT->Group[PORTA].PINCFG[11].bit.PMUXEN = 1;

  // Enable the port multiplexer for the digital pin D1/PA10 (Left Backward)
  PORT->Group[PORTA].PINCFG[10].bit.PMUXEN = 1;

  //Send GCLK4 to TCC0
  GCLK->CLKCTRL.reg =
    GCLK_CLKCTRL_CLKEN | //Enable GCLK
    GCLK_CLKCTRL_GEN_GCLK4 | //Select GCK4
    GCLK_CLKCTRL_ID_TCC0_TCC1; //Send GCLK4 to TCC0
  while(GCLK->STATUS.bit.SYNCBUSY); //Wait for Synch

  //Set freq of PWM on TCC0 to 40kHz
  //Freq = GCLK_Freq/(2*N*PER)
  TCC0->PER.reg = 100;
  while (TCC0->SYNCBUSY.bit.PER); //Wait for Synch

  // Initialize the PWM signal to output 0% duty cycle
  TCC0->CC[2].reg = 50;         // TCC0 CC2 - on D0/PA11
  while (TCC0->SYNCBUSY.bit.CC2); //Wait for Synch
  TCC0->CC[3].reg = 50;         // TCC0 CC3 - on D1/PA10
  while (TCC0->SYNCBUSY.bit.CC3); //Wait for Synch

  //Enable TCC0 output and keep the 48Mhz
  TCC0->CTRLA.bit.ENABLE = 1; // Enable the TCC0 output
  while (TCC0->SYNCBUSY.bit.ENABLE);

  // Connect the TCC timers to the port outputs - port pins are paired odd PMUO and even PMUXE
  // F & E specify the timers: TCC0 & TCC1
  PORT->Group[PORTA].PMUX[11].reg = PORT_PMUX_PMUXO_F | PORT_PMUX_PMUXE_F; 
  PORT->Group[PORTA].PMUX[10].reg = PORT_PMUX_PMUXO_F | PORT_PMUX_PMUXE_F;

This would be good question to post on the Adafruit forum. Adafruit engineers support their products fairly well.

Hi @nathanieln-15

Looking at your code, I think that you just need to divide the PMUX for index 10 by 2 (or in other word shift right by one place >> 1) and delete the line for index 11:

// Connect the TCC timers to the port outputs - port pins are paired odd PMUO and even PMUXE
// F & E specify the timers: TCC0 & TCC1
PORT->Group[PORTA].PMUX[10 >> 1].reg = PORT_PMUX_PMUXO_F | PORT_PMUX_PMUXE_F;

The reason is that the PMUX registers control the port multiplexer switches for port pin even and odd pairs, for example PA00 & PA01, PA02 & PA03, PA04 & PA05, etc... This means that there are half the number of PMUX registers as port pins, which in turn requires the index to be divided by 2.

As PA10 & PA11 are even and odd pairs they can be controlled by a single PMUX register.

Will do, and how would controlling the duty cycle in the main loop function look? I am trying to alter the duty cycle based upon an input and I noticed the CCB registers being used in the example code I found. Is there a way to alter the duty cycle on the two pins separately, or would I need to set up a new timer? I am working on an H-Bridge so I would like to be able to send two different PWM signals to the corresponding transistors to have speed control of the motor operating forwards and backwards. It seems like CCB[2] is used for pin D0 and CCB[3] is used for pin D1 so that makes me think they can be controlled separately. Also if this is the case, could I be directed to some type of table or link to show which or how the compare/capture registers are connected to the different pins. Thanks

Also, connecting pins D0 and D1 to an oscilloscope, I do not a signal when the duty cycle is set to 50%. Is there anything that needs to be enabled to allow the GCLK, PORT, timers, or any other function to work?

Have you looked at the source code to see how the Arduino analogWrite() function is implemented? That might provide some clues for your custom implementation.

Hi @nathanieln-15

If your requirement is to control a brushed DC motor, it's much easier to use a dedicated MOSFET based, brushed DC motor controller board from the likes of Pololu (or their distributors):

Care has to be taken when controlling a custom H-bridge circuit that you don't get shoot-through, where the transistor switching effectively shorts out the circuit. However this can be prevented by using complementary PWM together with dead-time insertion that slightly offsets the switching signals:

The SAMD21 microcontroller is capable of complementary PWM with dead-time insertion, should you choose to go down that route.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.