Reading TC Sometimes Returns Same Value

Please tell us which board you are using.
For CircuitPython issues, ask in the Adafruit CircuitPython forum.

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
HAAhqojm
 
Posts: 2
Joined: Wed Jan 18, 2023 8:49 pm

Reading TC Sometimes Returns Same Value

Post by HAAhqojm »

Hi everyone, I have a SAMD51 which I am programming under the Arduino IDE.
I can't post the entire source code for my project, but the specific issue I am having is that I have configured a 32bit timer to run on TC0+TC1 (DIV16 prescalar, normal mode, no interrupts on match or rollover) using a modified GCLK4: changed the divider from 4 to 3, giving a 16 MHz clock instead of the default (as per the Adafruit library for this board) 12 MHz . This produces a tick every us and all I wish to do for my application is read out the timer value at various points in my code, both on the main loop and inside ISRs. Please don't say "just use micros()" because there are other reasons for not doing so. Regardless, I believe there is still merit in understanding the situation described below and working out how to fix it.

My code for reading the timer looks like this:

Code: Select all

uint32_t ReadTimer() {
    // write READSYNC command to the Control B Set register
    TC0->COUNT32.CTRLBSET.reg = TC_CTRLBSET_CMD_READSYNC;
  
   // Wait for sync
    while (TC0->COUNT32.SYNCBUSY.bit.ENABLE);
  
    // Get the 32bit value from the timer
   return TC0->COUNT32.COUNT.reg;
}
This certainly works. However, when I have a particular code pattern: the ReadTimer() function is being called from the main loop but there are interrupts present (for example, on an input pin) doing other things (i.e. not calling ReadTimer() themselves) then at random I find that the timer sometimes returns the same value on two subsequent calls, and then on the next call it will have incremented twice as much. An obvious possibility is that the second result is genuine, and the task was simply faster than expected, but I've performed a series of tests, including running micros() alongside my own timer and am confident that this is not the case - time has passed, but the new count value has not been updated on the register.

I suspect this is due to some ISR happening while my ReadTimer() function is trying to work on the main loop and the read sync is lost - though I'd then expect the read to return 0 rather than the last value used, so I'm far from having a deep understanding of this.

A potential workaround is to keep a local record of the last result returned by the read, and if it hasn't changed, then try the read again. This seems a little ugly and will cause wasteful delays if I do end up calling the function in rapid succession (for whatever reason, intentional or otherwise). I'd rather understand what is occurring and whether there is something more elegant, like mastering the sync system.

Thank you in advance if you are able to offer any assistance.

User avatar
adafruit_support_mike
 
Posts: 67446
Joined: Thu Feb 11, 2010 2:51 pm

Re: Reading TC Sometimes Returns Same Value

Post by adafruit_support_mike »

Your timer routine is probably getting preempted by some other interrupt.

ARM microcontrollers have a Nested Vector Interrupt Controller (NVIC) that allows higher-priority interrupts to suspend interrupt handlers with lower priority. Ideally the higher-priority interrupt handler will complete its task then hand control back to the handler with the next-lower priority if one is waiting.

There are also several libraries and interrupt handlers that do time-critical work, so the first thing their handlers do is disable any other interrupts.

My guess is that you're seeing the latter. The TC and TCC peripherals use interrupts to let the rest of the system know the counter has matched the target value or rolled over.

User avatar
HAAhqojm
 
Posts: 2
Joined: Wed Jan 18, 2023 8:49 pm

Re: Reading TC Sometimes Returns Same Value

Post by HAAhqojm »

Thank you very much for your reply, but I am afraid there may be some confusion.
My timer counter (TC) is not raising any interrupts, nor do I want it to. The TC is simply counting (and overflowing when it needs to) and I am simply wishing to read the value of the counter.
The sample code I posted appears to work, but it can't be the full story because it is sometimes returning the same counter value on consecutive reads, despite (in this one example, measuring the time between pulses coming in at 500 Hz) 2000 us passing. I believe I know it to be a timer issue because the next read returns 4000 us.
There is no doubt that this is related to interrupts running, but those are "other" interrupts unrelated to this TC. Maybe the root issue is that reading the counter is not an atomic operation, the register is set, we wait for sync, then we read the value. What is the expected impact of any other ISR running during that sequence of commands?

Locked
Please be positive and constructive with your questions and comments.

Return to “Itsy Bitsy Boards”