Teensy 3.x library for tick timer?

Status
Not open for further replies.

Tady

Well-known member
Hello.

I am looking in to how to use the timers on Teensy 3.x to specify ticks instead of microseconds (IntervalRimer).
I need to port some AVR code that uses compare match but it needs to go below 1 microsecond so I can't use IntervalTimer

Thank you
 
TICKS is processor cycles? … read that as 'millis' timer ticks at first … and this timer really runs on F_BUS according to code below which is some half or less of F_CPU.

Reading the PJRC page a float value for the 'microseconds' can be supplied:: https://www.pjrc.com/teensy/td_timing_IntervalTimer.html

That is a portion of a us.

When this is the code that interprets the float into cycles of the F_BUS:
Code:
	bool begin(void (*funct)(), float microseconds) {
		if (microseconds <= 0 || microseconds > MAX_PERIOD) return false;
		uint32_t cycles = (float)(F_BUS / 1000000) * microseconds - 0.5;
		if (cycles < 36) return false;
		return beginCycles(funct, cycles);
	}

F_BUS is set based on F_CPU - those can be printed or used in the code as needed to get the needed # of resultant cycles referring to the Teensy 3 code above.
 
but it needs to go below 1 microsecond so I can't use IntervalTimer

IntervalTimer's microseconds input supports using a floating point number which gets converted to timer ticks, so you can get better than 1 us resolution.

But the fastest rate IntervalTimer allows is 36 cycles of F_BUS. That's a safety feature meant to prevent settings where 1 timer instance consumes 100% of the CPU time with interrupt overhead. If you really want faster, you can edit IntervalTimer.h to lower or remove this limit.

If that still doesn't meet your needs, you can commandeer the PIT interrupt with attachInterruptVector() and write your own low-level code. Of course, doing that means all libraries and featuring needing IntervalTimer will no longer work.
 
IIRC will be 60 MHz.

As suggested in p#2 you can find it like this::

Code:
setup() {
while ( !Serial );
Serial.print( "F_BUS == " );
Serial.println( F_BUS );
...
 
Also remember to use FASTRUN on any interrupt function you're going to try to run so often. Teensy 3.2 has a tiny cache for the flash, so you really want to use this so the function is allocated in single cycle RAM.

You'll still burn up a tremendous number of CPU cycles entering and exiting the interrupt so often, but at least the flash wait states for cache misses won't be part of that huge overhead.
 
Thank you! Didn't know that F_BUS returns the value :) but as Paul said the Library is limited to 36 if I understand correctly. I did some calculations and I think I need abou 170ns resolution. But with 36MHz in theory i can go 27ns?
 
Thank you! Didn't know that F_BUS returns the value :) but as Paul said the Library is limited to 36 if I understand correctly. I did some calculations and I think I need abou 170ns resolution. But with 36MHz in theory i can go 27ns?

Indeed what Paul noted is shown in p#2 code :: if (cycles < 36) return false;

That would be 36 cycles of 60M/sec?

And yes, F_BUS is a #define on T_3.x set at compile time and it is a printable value for reference as in the p#2 code.
 
But with 36MHz in theory i can go 27ns?

Only if your theory doesn't take the realities of interrupt overhead into account.

The ARM processor has to flush and refill its 3 stage pipeline, push several registers onto the stack, and do some other stuff just to start running your interrupt routine. The reverse of all that stuff happens when you exit. In a best case scenario, entry and exit consume 24 F_CPU cycles. But that's not all the overhead. Your code has to actually *do* something, which probably means initializing registers with addresses and then actually performing LD or ST instructions with those addresses. The ARM ABI lets your function clobber about half the CPU's registers, which are the ones the ARM core will automatically push onto the stack while entering your interrupt function. If your code does anything of reasonable complexity, the compiler will automatically use more of the registers, meaning code gets added to push those onto the stack, as well as pop them upon exit. If your code calls other functions, they get this same ABI which means more register shuffling. Normally this sort of overhead is just the normal expectation of C programming. But when you try to push to this sort of extreme performance, all these little details matter quite a lot.

If you really want to get into this sort of intense optimization, you really should read Joseph Yiu's "Definitive Guide" book. There's a link on the datasheets page.

https://www.pjrc.com/teensy/datasheets.html

The 36 cycle limit exists for a good reason. Maybe it's somewhat conservative, but probably not by much. If you really won't want that arbitrary limit, just edit IntervalTimer.h. But when your code appears to completely lock up, which can happen even with the limit if you put even a moderate amount of code into your interrupt function, remember the possibility that the CPU is executing only your interrupt function and all lower priority interrupts and your main program are getting zero CPU time. That situation is very difficult and confusing to troubleshoot, which is the reason the arbitrary limit exists.
 
However, on Teensy 4.0 where the CPU runs at 600 MHz and the processor has a pair of 64 bit paths to tightly coupled memory, perhaps the overhead could possibly be low enough? With overclocking to 960 MHz, those ~24 CPU cycles of overhead could get down into the 27 ns range....
 
I will try with T3.2 i think it will be great. I bouth a 4.0 and I still don't know what to use this beast for🤣 except blik a LED :D
 
However, on Teensy 4.0 where the CPU runs at 600 MHz and the processor has a pair of 64 bit paths to tightly coupled memory, perhaps the overhead could possibly be low enough? With overclocking to 960 MHz, those ~24 CPU cycles of overhead could get down into the 27 ns range....

I did some testing with the PIT performance of the T4-Beta board: https://forum.pjrc.com/threads/54711-Teensy-4-0-First-Beta-Test?p=195467&viewfull=1#post195467 and some posts later on. I found that you can't go much faster than 1MHz with the PIT. I didn't dive very deep into it but I identified two problems (might be wrong)


I didn't find time yet to redo the tests with the T4 (IMXRT1062 vs IMXRT1052) maybe the access to the registers is faster now. Would be very much interested in any test results if available

Edit: Here some tests: https://forum.pjrc.com/threads/57959-Teensy-4-IntervalTimer-Max-Speed?p=218577&viewfull=1#post218577
 
Last edited:
Status
Not open for further replies.
Back
Top