Arduino ZERO timer reading counter value

Hi

I have a Arduino Zero board with a working TCC0 timer but I am not able to read the counter value, writing works. The following program demonstrates my problem by reading the counter value with the main loop and printing it via serial link.

Any ideas?

/**
 * @author Markus Bader
 * @brief this program demonstrates a read timer count problem on an Arduino Zero board
 * @email markus.bader@tuwien.ac.at
 */

int pin_ovf_led = 13;  // debug pin for overflow led 
unsigned int loop_count = 0;
unsigned int irq_ovf_count = 0;

void setup() {

  pinMode(pin_ovf_led, OUTPUT);   // for debug leds
  digitalWrite(pin_ovf_led, LOW); // for debug leds
  Serial.begin(9600);

  Tcc* TCCx = (Tcc*) GetTC(0); // get timer struct
  
  // Enable clock for TCCx 
  REG_GCLK_CLKCTRL = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID_TCC0_TCC1) ;
  while ( GCLK->STATUS.bit.SYNCBUSY == 1 ); // wait for sync 


  TCCx->CTRLA.reg &= ~TCC_CTRLA_ENABLE;   // Disable TCCx
  while (TCCx->SYNCBUSY.bit.ENABLE == 1); // wait for sync 


  TCCx->CTRLA.reg |= TCC_CTRLA_PRESCALER_DIV256;   // Set perscaler


  TCCx->WAVE.reg |= TCC_WAVE_WAVEGEN_NFRQ;   // Set wave form configuration 
  while (TCCx->SYNCBUSY.bit.WAVE == 1);      // wait for sync 

  TCCx->PER.reg = 0xFFFF;              // Set counter Top using the PER register  
  while (TCCx->SYNCBUSY.bit.PER == 1); // wait for sync 

  TCCx->CC[0].reg = 0xFFF;
  while (TCCx->SYNCBUSY.bit.CC0 == 1); // wait for sync 
  
  // Interrupts 
  TCCx->INTENSET.reg = 0;                 // disable all interrupts
  TCCx->INTENSET.reg |= TCC_INTENSET_OVF; // enable overfollow

  // Enable InterruptVector
  NVIC_EnableIRQ(TCC0_IRQn);

  // Enable TCCx
  TCCx->CTRLA.reg |= TCC_CTRLA_ENABLE ;
  while (TCCx->SYNCBUSY.bit.ENABLE == 1); // wait for sync 

}

void loop() {
  // dummy
  Tcc* TCCx = (Tcc*) GetTC(0);       // get timer struct
  delay(250);

  /** 
   *   ///////                   ------- Problem ------------                 //////////
   *   The counter value is allays zero or the value writing within the interrupt routine
  **/
   
  uint32_t counter = TCCx->COUNT.reg;
  while (TCCx->SYNCBUSY.bit.COUNT == 1); // I am not shure if I need this sync
  
  char msg[0xFF];
  sprintf(msg, "%4u: COUNT = %6X", loop_count, counter);  
  Serial.println(msg);   // debug print via serial port
  loop_count++;
}

void TCC0_Handler()
{
  Tcc* TCCx = (Tcc*) GetTC(0);       // get timer struct
  if (TCCx->INTFLAG.bit.OVF == 1) {  // A overflow caused the interrupt
    digitalWrite(pin_ovf_led, irq_ovf_count % 2); // for debug leds
    TCCx->INTFLAG.bit.OVF = 0x01;    // writing a one clears the flag ovf flag
    irq_ovf_count++;                 // for debug leds
    // TCCx->COUNT.reg = 0xFFFF;     // uncommenting this linke shows the writing works
    // while (TCCx->SYNCBUSY.bit.COUNT == 1); // wait for sync 
  }
}

If it's any consolation, my Arduino Zero is experiencing the same issue.

I've set up timers TCC0, TCC1 and TCC2 to output PWM on all of their respective output pins and they're all whirring away nicely, so I know the counters are being clocked. However, when I attempt to read the COUNT register of the respective timer, it just returns 0.

I think the issue might have something to do with read synchronization.

On page 87 the SAMD21 datasheet states:

The modules using a distributed synchronizer register synchronization scheme are: SERCOM USART, SERCOM SPI, SERCOM I2C, I2S, TCC, USB.

Then on page 91 it details the read sync for the distributed synchronizer register synchronization scheme, as required by the TCC's COUNT registers (page 721):

13.3.2.3 General read synchronization Before any read of a core register, the user must check that the related bit in SYNCBUSY register is cleared. Read access to core register is always immediate but the return value is reliable only if a synchonization of this core register is not going.

To my mind, this means that for a sync read you just need to test the COUNT bit of the TCC's SYNCBUSY register before reading the COUNT register itself:

while(TCC0->SYNCBUSY.bit.COUNT);
Serial.println(REG_TCC0_COUNT, HEX);

I've tried this for TCC0, TCC1 and TCC2, but all their COUNT registers return 0. Unfortunately, there doesn't appear to be any code samples out there. Most of the Atmel literature covers their own ASF API and not direct register access.

TC3 works though.

The following code sets up TC3 to clock at 2MHz and reads it every second:

// Setup TC3 as a 16 bit counter at 2MHz and display the COUNT register every second
void setup() 
{ 
  Serial.begin(115200);
  
  REG_GCLK_GENDIV = GCLK_GENDIV_DIV(3) |    // Divide the 48MHz system clock by 3 = 16MHz
                    GCLK_GENDIV_ID(5);      // Set division on Generic Clock Generator (GCLK) 5
  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 GCLK 5
                     GCLK_GENCTRL_SRC_DFLL48M |   // Set the clock source to 48MHz 
                     GCLK_GENCTRL_ID(5);          // Set clock source on GCLK 5
  while (GCLK->STATUS.bit.SYNCBUSY);              // Wait for synchronization

  REG_GCLK_CLKCTRL = GCLK_CLKCTRL_CLKEN |         // Enable the generic clock...
                     GCLK_CLKCTRL_GEN_GCLK5 |     // ....on GCLK5
                     GCLK_CLKCTRL_ID_TCC2_TC3;    // Feed the GCLK5 to TCC2 and TC3
  while (GCLK->STATUS.bit.SYNCBUSY);              // Wait for synchronization

  REG_TC3_CTRLA |= TC_CTRLA_PRESCALER_DIV8 |      // Set prescaler to 8, 16MHz/8 = 2MHz
                   TC_CTRLA_ENABLE;               // Enable TC3
  while (TC3->COUNT16.STATUS.bit.SYNCBUSY);       // Wait for synchronization

  REG_TC3_READREQ = TC_READREQ_RCONT |            // Enable a continuous read request
                    TC_READREQ_ADDR(0x10);        // Offset of the 16 bit COUNT register
  while (TC3->COUNT16.STATUS.bit.SYNCBUSY);       // Wait for (read) synchronization
}

void loop() 
{ 
  Serial.println(REG_TC3_COUNT16_COUNT);          // Display the TC3 counter
  delay(1000);                                    // Wait 1 second
}

It just produces numbers between 0 and 65535, but proves that the TC3 COUNT register is being read.

Hi MartinL

Thanks for your help, I got it working with the TC counter but not with the TCC

I am encountering the same problem with TCC modules. I get zero values when reading the COUNT register. I am using direct register access.