Counting microsecond ticks using the Teensy 3.1. Programmed in C

Status
Not open for further replies.
Hello all.

I'm currently working on a project where I need to count the amount of microsecond / millisecond ticks. I'm wondering if there's just a simple register that counts up every milli/microsecond and I can read that register to get the current value? I'm doing all of this in C.

Any guidence would be excellent. Thanks
 
Thanks for the reply. I've looked at that solution but it disables interrupts which I'm trying to avoid if possible. Would the FTMx be able to be used for this?
 
Yes, you can use the FTMx timer modules to count time with high precision, down to about 21 nanoseconds (one cycle of a 48 MHz clock). You have to configure them to set the timer source, prescaler values, rollover count etc. As you will find from the documentation https://www.pjrc.com/teensy/K20P64M72SF1RM.pdf there is quite a bit of setup to do.

I looked into something similar a while back, to measure an external frequency https://forum.pjrc.com/threads/28037-Teensy-3-1-and-K20-FlexTimer-config-for-FreqMeasure but I haven't finished that project yet.
 
Last edited:
Where did you get the idea that the timing functions disable interrupts? They don't.

One of the big tips for getting things working with Arduino and Teensyduino is to look for an easy way first. Usually a library. Don't immediately jump into low-level coding configuring hardware timers, etc. Paul and the rest of the community have done an amazing amount of amazing work to make functionality accessible without guru-level knowledge. Even if your ultimate goal is to learn all that register bit twiddling, it's still good to start with something that works and experiment to figure out why it works and what else it could do.
 
Thanks for the reply. I've looked at that solution but it disables interrupts which I'm trying to avoid if possible. Would the FTMx be able to be used for this?
I also wonder why the concern about disabling interrupts - microseconds() in the library is a good way to measure time in between 1,000Hz systick interrupts but using the hardware counter that yields the systick interval.
 
From the link in p#2 is https://www.pjrc.com/teensy/td_timing_elaspedMillis.html

I've used elapsedMicros or elapsedMillis a couple ways to watch time go by. You set it to zero and next time you see it you check the value and you know how long it has been. For raw timing look at that count set it to zero and do as you please. As long as you expect to see it before it rolls over (11+ hours micros or 49+ days Millis) - it won't have a periodic rollover based on start time some hours or days later.

There is a way to read the cpu cycle counter directly noted here: https://forum.pjrc.com/threads/28407-Teensyduino-access-to-counting-cpu-cycles?p=78536&viewfull=1#post78536
This will give you seconds broken into "speed of the processor" parts to some nano seconds - but will leave you doing math around more frequent rollover events.
 
Where did you get the idea that the timing functions disable interrupts? They don't.

One of the big tips for getting things working with Arduino and Teensyduino is to look for an easy way first. Usually a library. Don't immediately jump into low-level coding configuring hardware timers, etc. Paul and the rest of the community have done an amazing amount of amazing work to make functionality accessible without guru-level knowledge. Even if your ultimate goal is to learn all that register bit twiddling, it's still good to start with something that works and experiment to figure out why it works and what else it could do.

I looked at the teensyduino code for the micro() and it disables interrupts
 
Reading microseconds does indeed disable interrupts, but only very briefly. The low-level code is here:

https://github.com/PaulStoffregen/cores/blob/master/teensy3/pins_teensy.c#L1068

Those three things need to be read without an interrupt occurring. The alternative is to read them repetitively, until 2 consecutive readings are consistent. That's what Arduino does on Due:

https://github.com/arduino/Arduino/blob/master/hardware/arduino/sam/cores/arduino/wiring.c#L41

Their way has the advantage that interrupts aren't disabled. But it requires reading everything twice, and extra code to check if the 3 numbers are consistent... so it's slower.

My gut feeling is micros() wants to be fast. It's used by elapsedMicros() and other code which obviously wants higher timing precision than millis() can give. I must confess, I haven't studied the exact timing of both approaches. Their's might be well under 1 microsecond.

Mine does disable interrupts, but the disable time is only 3 load instructions. Actually, I haven't checked if the compiler is putting extra register setup overhead into the interrupt disable region, so it might be a few more instructions to set up registers with the 3 addresses.

If anyone wants to dig into really analyzing the actual timing of these 2 approaches, I'm certainly willing to consider changing. This is one of hundreds of little optimizations I've thought about, but (so far) haven't put much real work into pursuing.

But if millisecond resolution is enough, millis() or elapsedMillis never disables interrupts. It just reads the 32 bit count, which is an atomic read since we have a 32 bit bus. :)
 
I don't normally use interrupts, so I'm curious: What is the net effect of disabling interrupts for a few instructions? Doesn't that just mean that the interrupt latency is increased by that amount? Are you guaranteed some maximum interrupt latency, if you don't disable interrupts?
 
Reading microseconds does indeed disable interrupts, but only very briefly. The low-level code is here:

https://github.com/PaulStoffregen/cores/blob/master/teensy3/pins_teensy.c#L1068

Those three things need to be read without an interrupt occurring. The alternative is to read them repetitively, until 2 consecutive readings are consistent. That's what Arduino does on Due:

https://github.com/arduino/Arduino/blob/master/hardware/arduino/sam/cores/arduino/wiring.c#L41

Their way has the advantage that interrupts aren't disabled. But it requires reading everything twice, and extra code to check if the 3 numbers are consistent... so it's slower.

My gut feeling is micros() wants to be fast. It's used by elapsedMicros() and other code which obviously wants higher timing precision than millis() can give. I must confess, I haven't studied the exact timing of both approaches. Their's might be well under 1 microsecond.

Mine does disable interrupts, but the disable time is only 3 load instructions. Actually, I haven't checked if the compiler is putting extra register setup overhead into the interrupt disable region, so it might be a few more instructions to set up registers with the 3 addresses.

If anyone wants to dig into really analyzing the actual timing of these 2 approaches, I'm certainly willing to consider changing. This is one of hundreds of little optimizations I've thought about, but (so far) haven't put much real work into pursuing.

But if millisecond resolution is enough, millis() or elapsedMillis never disables interrupts. It just reads the 32 bit count, which is an atomic read since we have a 32 bit bus. :)

Thanks a lot for your valuable information Paul and everybody else. I will sure pop back here again if I never need any help. Mills() would also work for my project also. I will look the code once I get the chance :-D
 
What is the net effect of disabling interrupts for a few instructions? Doesn't that just mean that the interrupt latency is increased by that amount?

Yes, exactly, the effect is possibly adding interrupt latency, if the interrupt occurs during that time.

Are you guaranteed some maximum interrupt latency, if you don't disable interrupts?

Yes, you are. Well, sort of. ARM designed the Cortex-M processors to have low interrupt latency, as long as interrupts are enabled and another interrupt of equal or higher priority isn't already running. The actual latency guarantee is complicated somewhat by flash memory caching (and wait states for cache misses), bus arbitration for DMA, extra bus cycles added by the peripheral bridges and bit manipulation engine, and maybe some other stuff I don't know about.
 
Beware some non-PJRC library code derived from AVR code may exist that disables interrupts for an imprudently long period of time.

Best to stick with PJRC's Paul-ified libraries.
 
Status
Not open for further replies.
Back
Top