TC5 interrupt configuration hangs

Hi
I was configuring TC5 interrupt.But whenever I am writing to TC5->COUNT16.CC[0].reg & then check for the sync,it never executes afterwards.I simply inserted some breakpoints but i am stuck at Breakpoint4 in TcConfig().Please take a look at the code

int state;

void TcConfig(int sampleRate)
{

  //First configure Generic Clock(GENCTRL related Setting)
  GCLK->GENCTRL.reg |= GCLK_GENCTRL_IDC |  //50-50 Duty(Though,it will not reflect on any output pin)
                       GCLK_GENCTRL_GENEN |        //Enable generic clock generator
                       GCLK_GENCTRL_SRC_DFLL48M |  //48MHz clock PLL clock as the input
                       GCLK_GENCTRL_ID(4);         //Select GCLK 4
  while (GCLK->STATUS.bit.SYNCBUSY);

  SerialUSB.println("Braekpoint1");

  //Configure Divisor of Input Clock for GENCTRL(GENDIV Related Settings)
  GCLK->GENDIV.reg |= GCLK_GENDIV_DIV(48) |         //Select clock divisor as 48 i.e GCLK4 output will be 48/48 = 1MHz
                      GCLK_GENDIV_ID(4);           //GCLK4
  while (GCLK->STATUS.bit.SYNCBUSY);

  SerialUSB.println("Braekpoint2");

  //Now configure GCLK4 & Feed it's output to TC5(CLKCTRL related settings)
  GCLK->CLKCTRL.reg |= GCLK_CLKCTRL_CLKEN |         // Enable Generic Clock
                       GCLK_CLKCTRL_GEN_GCLK4 |     // Select GCLK4
                       GCLK_CLKCTRL_ID(GCM_TC4_TC5);  //Feed GCLK4 output to TC5
  while (GCLK->STATUS.bit.SYNCBUSY);

  SerialUSB.println("Braekpoint3");

  //Now,configure TC5
  /*
  TC5->COUNT16.CTRLA.reg &= ~TC_CTRLA_ENABLE; //Disable TC5 before Edit
  while (TC5->COUNT16.STATUS.reg & TC_STATUS_SYNCBUSY); //Wait for sync
  */

  TC5->COUNT16.CTRLA.reg |= TC_CTRLA_MODE_COUNT16 |  //16 Bit Mode
                            TC_CTRLA_PRESCALER_DIV1024  | //1024 Prescaler
                            TC_CTRLA_WAVEGEN_MFRQ;  //Match Frequency Mode
  while (TC5->COUNT16.STATUS.reg & TC_STATUS_SYNCBUSY);// Wait for sync

  SerialUSB.println("Braekpoint4");

  TC5->COUNT16.CC[0].reg = 500;// Set the CC register
  while (TC5->COUNT16.STATUS.reg & TC_STATUS_SYNCBUSY);

  SerialUSB.println("Braekpoint5");

  TC5->COUNT16.CTRLA.reg |= TC_CTRLA_ENABLE;  //Enable TC5
  while (TC5->COUNT16.STATUS.reg & TC_STATUS_SYNCBUSY);// Wait for sync

  SerialUSB.println("Braekpoint6");

  NVIC_DisableIRQ(TC5_IRQn);
  NVIC_ClearPendingIRQ(TC5_IRQn);
  NVIC_SetPriority(TC5_IRQn, 0);
  NVIC_EnableIRQ(TC5_IRQn);

  SerialUSB.println("Braekpoint7");

  TC5->COUNT16.INTENSET.bit.MC0 = 1;
  while (TC5->COUNT16.STATUS.reg & TC_STATUS_SYNCBUSY);// Wait for sync

  SerialUSB.println("Braekpoint8");
}

void TcStart(void)
{
  TC5->COUNT16.CTRLA.reg |= TC_CTRLA_ENABLE; //set the CTRLA register
  while (TC5->COUNT16.STATUS.reg & TC_STATUS_SYNCBUSY);
}


void TC5_Handler (void) {
  //YOUR CODE HERE
  if (state == true) {
    digitalWrite(LED_BUILTIN, HIGH);
  } else {
    digitalWrite(LED_BUILTIN, LOW);
  }
  state = !state;
  // END OF YOUR CODE
  TC5->COUNT16.INTFLAG.bit.MC0 = 1; //Writing a 1 to INTFLAG.bit.MC0 clears the interrupt so that it will run again
}


void setup() {
  // put your setup code here, to run once:
  pinMode(LED_BUILTIN, OUTPUT);
  SerialUSB.begin(115200);
  while (!SerialUSB);
  TcConfig(500);
  TcStart(); //starts the timer
}

void loop() {
}

Hmm... not sure. You might set MODE early on just to make sure that it's COUNT16. Also I see some things in the arduino source code which suggests that TC5 might be used by the Tone library, not sure if that might trip you up even if you're not using Tone.

Another guess: when you do GCLK->CLKCTRL.reg |= ... perhaps just use equals (=) instead, to avoid pulling in whatever was last in that register.

Hi SHARANYADAS,

I ran your code and modified it slightly to get it working.

The main changes were:

  1. Removing the read-modify-write (or |=) and register synchronization, where it wasn't required.

  2. Set the prescaler and counter synchronization bitfield in the TC5's CTRLA register to: TC_CTRLA_PRESCSYNC_PRESC, this causes the timer to overflow on the prescaler clock, rather than the generic clock.

  3. Changed the interrupt flag from MC0 (Match Compare 0) to OVF (Overflow).

Here's the modified code:

int state;

void TcConfig(int sampleRate)
{

  //First configure Generic Clock(GENCTRL related Setting)
  GCLK->GENCTRL.reg = GCLK_GENCTRL_IDC |  //50-50 Duty(Though,it will not reflect on any output pin)
                      GCLK_GENCTRL_GENEN |        //Enable generic clock generator
                      GCLK_GENCTRL_SRC_DFLL48M |  //48MHz clock PLL clock as the input
                      GCLK_GENCTRL_ID(4);         //Select GCLK 4
  while (GCLK->STATUS.bit.SYNCBUSY);

  SerialUSB.println("Braekpoint1");

  //Configure Divisor of Input Clock for GENCTRL(GENDIV Related Settings)
  GCLK->GENDIV.reg = GCLK_GENDIV_DIV(48) |         //Select clock divisor as 48 i.e GCLK4 output will be 48/48 = 1MHz
                     GCLK_GENDIV_ID(4);           //GCLK4
 
  SerialUSB.println("Braekpoint2");

  //Now configure GCLK4 & Feed it's output to TC5(CLKCTRL related settings)
  GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN |         // Enable Generic Clock
                      GCLK_CLKCTRL_GEN_GCLK4 |     // Select GCLK4
                      GCLK_CLKCTRL_ID(GCM_TC4_TC5);  //Feed GCLK4 output to TC5

  SerialUSB.println("Braekpoint3");

  TC5->COUNT16.CTRLA.reg = TC_CTRLA_PRESCSYNC_PRESC | // Overflow on prescaler clock
                           TC_CTRLA_MODE_COUNT16 |  //16 Bit Mode
                           TC_CTRLA_PRESCALER_DIV1024  | //1024 Prescaler
                           TC_CTRLA_WAVEGEN_MFRQ;  //Match Frequency Mode

  SerialUSB.println("Braekpoint4");

  TC5->COUNT16.CC[0].reg = 500;// Set the CC register
  while (TC5->COUNT16.STATUS.bit.SYNCBUSY);

  SerialUSB.println("Braekpoint5");

  TC5->COUNT16.CTRLA.bit.ENABLE = 1;  //Enable TC5
  while (TC5->COUNT16.STATUS.bit.SYNCBUSY);// Wait for sync

  SerialUSB.println("Braekpoint6");

  NVIC_DisableIRQ(TC5_IRQn);
  NVIC_ClearPendingIRQ(TC5_IRQn);
  NVIC_SetPriority(TC5_IRQn, 0);
  NVIC_EnableIRQ(TC5_IRQn);

  SerialUSB.println("Braekpoint7");

  TC5->COUNT16.INTENSET.bit.OVF = 1;

  SerialUSB.println("Braekpoint8");
}

void TcStart(void)
{
  TC5->COUNT16.CTRLA.bit.ENABLE = 1; //set the CTRLA register
  while (TC5->COUNT16.STATUS.bit.SYNCBUSY);
}


void TC5_Handler (void) {
  //YOUR CODE HERE
  if (state == true) {
    digitalWrite(LED_BUILTIN, HIGH);
  } else {
    digitalWrite(LED_BUILTIN, LOW);
  }
  state = !state;
  // END OF YOUR CODE
  TC5->COUNT16.INTFLAG.bit.OVF = 1; //Writing a 1 to INTFLAG.bit.OVF clears the interrupt so that it will run again
}


void setup() {
  // put your setup code here, to run once:
  pinMode(LED_BUILTIN, OUTPUT);
  SerialUSB.begin(115200);
  while (!SerialUSB);
  TcConfig(500);
  TcStart(); //starts the timer
}

void loop() {
}

On my board, the built-in LED blinks on and off every second.