Timer very low frequency ?

I am trying to set a very low frequency for TC4, on 16 bits mode,

So for 48Mhz/3=16Mhz, pre scale 256: 16M/256=62.74Khz

Then if I set the timer counter to 62,745, it should tick on 1Hz, and I do get 1Hz. But, if I want lets say 4Hz, so I set the counter to: 62,745/4= 15,686

It stay on 1Hz, and any lower number for the counter, even 100, still produce only 1Hz. Only changing the pre scale to a lower one, changes the frequency.

What is wrong here and how do i get 4/5hz ?

      void startTimer(long n)
      {
      
              
              REG_GCLK_GENDIV = GCLK_GENDIV_DIV(3) |          // Divide the 48MHz clock source by divisor 3: 48MHz/3=16MHz
                          GCLK_GENDIV_ID(4);            // Select Generic Clock (GCLK) 4
              while (GCLK->STATUS.bit.SYNCBUSY);              // Wait for synchronization
              
              REG_GCLK_GENCTRL = GCLK_GENCTRL_IDC |           // Set the duty cycle to 50/50 HIGH/LOW
                           GCLK_GENCTRL_GENEN |         // Enable GCLK4
                           GCLK_GENCTRL_SRC_DFLL48M |   // Set the 48MHz clock source
                           GCLK_GENCTRL_ID(4);          // Select GCLK4
              while (GCLK->STATUS.bit.SYNCBUSY);              // Wait for synchronization
              
              // Feed GCLK4 to TC4 and TC5
              REG_GCLK_CLKCTRL = GCLK_CLKCTRL_CLKEN |         // Enable GCLK4 to TC4 and TC5
                           GCLK_CLKCTRL_GEN_GCLK4 |     // Select GCLK4
                           GCLK_CLKCTRL_ID_TC4_TC5;     // Feed the GCLK4 to TC4 and TC5
              while (GCLK->STATUS.bit.SYNCBUSY);              // Wait for synchronization
              
              REG_TC4_CTRLA |= TC_CTRLA_MODE_COUNT16;           // Set the counter to 8-bit mode
              while (TC4->COUNT16.STATUS.bit.SYNCBUSY);        // Wait for synchronization 
              
              REG_TC4_COUNT16_CC0 = n;                      // Set the TC4 CC0 register to some arbitary value
              while (TC4->COUNT16.STATUS.bit.SYNCBUSY);        // Wait for synchronization
              //REG_TC4_COUNT8_CC1 = 0xAA;                      // Set the TC4 CC1 register to some arbitary value
              //while (TC4->COUNT8.STATUS.bit.SYNCBUSY);        // Wait for synchronization
              //REG_TC4_COUNT8_PER = 0xFF;                      // Set the PER (period) register to its maximum value
              //while (TC4->COUNT8.STATUS.bit.SYNCBUSY);        // Wait for synchronization
              
              //NVIC_DisableIRQ(TC4_IRQn);
              //NVIC_ClearPendingIRQ(TC4_IRQn);
              NVIC_SetPriority(TC4_IRQn, 0);    // Set the Nested Vector Interrupt Controller (NVIC) priority for TC4 to 0 (highest) 
              NVIC_EnableIRQ(TC4_IRQn);         // Connect TC4 to Nested Vector Interrupt Controller (NVIC) 
              
              REG_TC4_INTFLAG |= TC_INTFLAG_MC1 | TC_INTFLAG_MC0 | TC_INTFLAG_OVF;        // Clear the interrupt flags
              REG_TC4_INTENSET = TC_INTENSET_MC1 | TC_INTENSET_MC0 | TC_INTENSET_OVF;     // Enable TC4 interrupts
              // REG_TC4_INTENCLR = TC_INTENCLR_MC1 | TC_INTENCLR_MC0 | TC_INTENCLR_OVF;     // Disable TC4 interrupts
              
              REG_TC4_CTRLA |= TC_CTRLA_PRESCALER_DIV256 |     // Set prescaler to 64, 16MHz/64 = 256kHz
                         TC_CTRLA_ENABLE;               // Enable TC4
              while (TC4->COUNT16.STATUS.bit.SYNCBUSY);        // Wait for synchronization       
      }
      
      


        
        void TC4_Handler()                              
        {     
          // Check for overflow (OVF) interrupt 
          if (TC4->COUNT16.INTFLAG.bit.OVF && TC4->COUNT16.INTENSET.bit.OVF)             
          {
                  timerTick();
                  REG_TC4_INTFLAG = TC_INTFLAG_OVF;         // Clear the OVF interrupt flag 
          }
}

Hi BenStlr,

If your using the TC timer in 16-bit mode you need to set it to match frequency (MFRQ) mode to have control over the frequency. The PER register doesn't work in this mode. To activate MFRQ just add TC_CTRLA_WAVEGEN_MFRQ to set the required bits your REG_TC4_CTRLA register.

In this mode the value of CC0 becomes the TOP value of the timer. You'll need load the CC0 with the value 15624, enable only CC0 in the interrupt enable set (INTENSET) register and add your code to the CC0 portion of your interrupt handler.

Frequency calculation:

16MHz / (256 * (15624 + 1)) = 4Hz

Have added:

REG_TC4_CTRLA |= TC_CTRLA_WAVEGEN_MFRQ; // A must for 16 bits mode
while (TC4->COUNT16.STATUS.bit.SYNCBUSY); // Wait for synchronization

Works like magic. Thank you.

Martin, is there a reason why if I set a PWM , and then I set the timer in the code I'v showed, then the PWM stops working ? is there a problem for them using the same gclk ?

This is the PWM which I set right before the previous timer I showed :

       REG_GCLK_GENDIV = GCLK_GENDIV_DIV(1) |          // Divide the 48MHz clock source by divisor 1: 48MHz/1=48MHz
                            GCLK_GENDIV_ID(4);            // Select Generic Clock (GCLK) 4
            while (GCLK->STATUS.bit.SYNCBUSY);              // Wait for synchronization
            
            REG_GCLK_GENCTRL = GCLK_GENCTRL_IDC |           // Set the duty cycle to 50/50 HIGH/LOW
                             GCLK_GENCTRL_GENEN |         // Enable GCLK4
                             GCLK_GENCTRL_SRC_DFLL48M |   // Set the 48MHz clock source
                             GCLK_GENCTRL_ID(4);          // Select GCLK4
            while (GCLK->STATUS.bit.SYNCBUSY);              // Wait for synchronization
            
            // Enable the port multiplexer for the digital pin D7 
            PORT->Group[g_APinDescription[7].ulPort].PINCFG[g_APinDescription[7].ulPin].bit.PMUXEN = 1;
            
            // Connect the TCC0 timer to digital output D7 - port pins are paired odd PMUO and even PMUXE
            // F & E specify the timers: TCC0, TCC1 and TCC2
            PORT->Group[g_APinDescription[6].ulPort].PMUX[g_APinDescription[6].ulPin >> 1].reg = PORT_PMUX_PMUXO_F;
            
            // Feed GCLK4 to TCC0 and TCC1
            REG_GCLK_CLKCTRL = GCLK_CLKCTRL_CLKEN |         // Enable GCLK4 to TCC0 and TCC1
                             GCLK_CLKCTRL_GEN_GCLK4 |     // Select GCLK4
                             GCLK_CLKCTRL_ID_TCC0_TCC1;   // Feed GCLK4 to TCC0 and TCC1
            while (GCLK->STATUS.bit.SYNCBUSY);              // Wait for synchronization
            
            // Normal (single slope) PWM operation: timers countinuously count up to PER register value and then is reset to 0
            REG_TCC0_WAVE |= TCC_WAVE_WAVEGEN_NPWM;        // Setup single slope PWM on TCC0
            while (TCC0->SYNCBUSY.bit.WAVE);                // Wait for synchronization      

            
            setPwmFrequency(n);
            
            // Divide the 48MHz signal by 1 giving 48MHz (20.83ns) TCC0 timer tick and enable the outputs
            REG_TCC0_CTRLA |= TCC_CTRLA_PRESCALER_DIV1 |    // Divide GCLK4 by 1
                            TCC_CTRLA_ENABLE;             // Enable the TCC0 output
            while (TCC0->SYNCBUSY.bit.ENABLE);              // Wait for synchronization

Is there a chance that when I read the analog A0, they use the same timer ? when I set both codes, the chip stops printing values.

Is there a chance that when I read the analog A0, they use the same timer ?

In my project I'm using every channel on all the TCC timers: 0, 1 an 2, together with analogRead() on A0, without any issues.

The Arduino core code uses GCLKs 0 to 3, so GCLK4 shouldn't conflict with the ADC or any timer.