Teensy4.0 | TimerOne Library issue

HallMark

Well-known member
Board:- Teensy 4.0
Teensyduino:- 1.51
TimerOne Library:- https://github.com/PaulStoffregen/TimerOne

I created simple Blink code

Code:
#include <TimerOne.h>

const int led = LED_BUILTIN;  // the pin with a LED

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  pinMode(led, OUTPUT);
  Timer1.initialize(100000);
  Timer1.attachInterrupt(blinkLED); // blinkLED to run every 0.10 seconds
}

void loop() {
  // put your main code here, to run repeatedly:
}

// The interrupt will blink the LED, and keep
// track of how many times it has blinked.
int ledState = LOW;
volatile unsigned long blinkCount = 0; // use volatile for shared variables

unsigned long guTime1, guTime2 = 0;
void blinkLED(void)
{
  guTime2 = micros();
  if (ledState == LOW) {
    ledState = HIGH;
    blinkCount = blinkCount + 1;  // increase when LED turns on
  } else {
    ledState = LOW;
  }
  digitalWrite(led, ledState);
  Serial.println(guTime2-guTime1);
  guTime1 = guTime2;
}

This only works properly with 150 MHz and 24 Mhz. This is not working with 600 MHz selection.
 
Yep it looks like, at 600mhz the slowest the code shows, the timer one code shows:
Code:
void initialize(unsigned long microseconds=1000000) __attribute__((always_inline)) {
	setPeriod(microseconds);
    }
    void setPeriod(unsigned long microseconds) __attribute__((always_inline)) {
	uint32_t period = (float)F_BUS_ACTUAL * (float)microseconds * 0.0000005f;
	uint32_t prescale = 0;
	while (period > 32767) {
		period = period >> 1;
		if (++prescale > 7) {
			prescale = 7;	// when F_BUS is 150 MHz, longest
			period = 32767; // period is [COLOR="#FF0000"]55922 [/COLOR]us (~17.9 Hz)
			break;
		}
	}
 
@Frank - I think what he is noticing is if you run at 150 MHz, the serial Output shows:
Code:
100001
100001
100001
100001
100001
Or a 10th of a second
But at 600 MHz you see
Code:
55923
55924
55923
55923
55923
 
Yep it looks like, at 600mhz the slowest the code shows, the timer one code shows:
Code:
void initialize(unsigned long microseconds=1000000) __attribute__((always_inline)) {
	setPeriod(microseconds);
    }
    void setPeriod(unsigned long microseconds) __attribute__((always_inline)) {
	uint32_t period = (float)F_BUS_ACTUAL * (float)microseconds * 0.0000005f;
	uint32_t prescale = 0;
	while (period > 32767) {
		period = period >> 1;
		if (++prescale > 7) {
			prescale = 7;	// when F_BUS is 150 MHz, longest
			period = 32767; // period is [COLOR="#FF0000"]55922 [/COLOR]us (~17.9 Hz)
			break;
		}
	}

I see so with 600 MHz Smallest we can setup is 55922 us?
 
I believe that is the longest period you can specify at 600Mhz, which is reflected in your output.

Of course you do have other alternatives, like use the Interval Timer library.
 
I believe that is the longest period you can specify at 600Mhz, which is reflected in your output.

Of course you do have other alternatives, like use the Interval Timer library.

Yes, I was using that and thought TimerOne might be better options for Interrupt priority set and all.
Do we have any list of default interrupt priorities for Teensy 4.0?
 
I believe they all start out at priority 128. You can use priority method on your interrupt handler to set them to something else.

You might also be able to use @luni's TeensyTimerTool stuff, to create a timer. I don't think he has any code directly in this timer code to set an Interrupt priority, but maybe, else maybe can somehow ask the class for something that will get you back to the ISR number?
 
Here the link to the TeensyTimerTool stuff: https://github.com/luni64/TeensyTimerTool It currently handles FTM, GPT, QUAD timers and a software timer (PIT is under construction). It doesn't touch the interrupt priority (currently) so, you can easily set that from outside the framework with the usual call to NVIC_SET_PRIORITY
 
Here the link to the TeensyTimerTool stuff: https://github.com/luni64/TeensyTimerTool It currently handles FTM, GPT, QUAD timers and a software timer (PIT is under construction). It doesn't touch the interrupt priority (currently) so, you can easily set that from outside the framework with the usual call to NVIC_SET_PRIORITY

Thank you Kurt and Luni, I was not aware about this library. Let me look into detail for this one.
Do we have the any list for Teensy 4 INTERRUPT NAME list?. I checked interrupt.c
 
You probably mean the IRQ numbers? They are in imxrt.h for the Teensy 4. If you want to change the priority for say the GPT1 timer module to 48 you'd do a

Code:
NVIC_SET_PRIORITY(IRQ_GPT1, 48);

Here a copy of the numbers:

Code:
enum IRQ_NUMBER_t {
        IRQ_DMA_CH0 =           0,
        IRQ_DMA_CH1 =           1,
        IRQ_DMA_CH2 =           2,
        IRQ_DMA_CH3 =           3,
        IRQ_DMA_CH4 =           4,
        IRQ_DMA_CH5 =           5,
        IRQ_DMA_CH6 =           6,
        IRQ_DMA_CH7 =           7,
        IRQ_DMA_CH8 =           8,
        IRQ_DMA_CH9 =           9,
        IRQ_DMA_CH10 =          10,
        IRQ_DMA_CH11 =          11,
        IRQ_DMA_CH12 =          12,
        IRQ_DMA_CH13 =          13,
        IRQ_DMA_CH14 =          14,
        IRQ_DMA_CH15 =          15,
        IRQ_DMA_ERROR =         16,
        IRQ_CTI0 =              17,
        IRQ_CTI1 =              18,
        IRQ_CORE_ERROR =        19, // TODO - name?
        IRQ_LPUART1 =           20,
        IRQ_LPUART2 =           21,
        IRQ_LPUART3 =           22,
        IRQ_LPUART4 =           23,
        IRQ_LPUART5 =           24,
        IRQ_LPUART6 =           25,
        IRQ_LPUART7 =           26,
        IRQ_LPUART8 =           27,
        IRQ_LPI2C1 =            28,
        IRQ_LPI2C2 =            29,
        IRQ_LPI2C3 =            30,
        IRQ_LPI2C4 =            31,
        IRQ_LPSPI1 =            32,
        IRQ_LPSPI2 =            33,
        IRQ_LPSPI3 =            34,
        IRQ_LPSPI4 =            35,
        IRQ_CAN1 =              36,
        IRQ_CAN2 =              37,
        IRQ_ADDR_ERR =          38, // TODO: name?
        IRQ_KPP =               39,
        IRQ_TSC_DIG =           40,
        IRQ_GPR_IRQ =           41,
        IRQ_LCDIF =             42,
        IRQ_CSI =               43,
        IRQ_PXP =               44,
        IRQ_WDOG2 =             45,
        IRQ_SNVS_IRQ =          46,
        IRQ_SNVS_SECURITY =     47,
        IRQ_SNVS_ONOFF =        48,
        IRQ_CSU =               49,
        IRQ_DCP0 =              50, // TODO: ???
        IRQ_DCP1 =              51, // TODO: ???
        IRQ_DCP2 =              52, // TODO: ???
        IRQ_TRNG =              53,
        IRQ_SJC_IRQ =           54,
        IRQ_BEE =               55,
        IRQ_SAI1 =              56,
        IRQ_SAI2 =              57,
        IRQ_SAI3_RX =           58,
        IRQ_SAI3_TX =           59,
        IRQ_SPDIF =             60,
        IRQ_BROWNOUT0 =         61,
        IRQ_Reserved1 =         62,
        IRQ_TEMPERATURE =       63,
        IRQ_TEMPERATURE_PANIC = 64,
        IRQ_USBPHY0 =           65,
        IRQ_USBPHY1 =           66,
        IRQ_ADC1 =              67,
        IRQ_ADC2 =              68,
        IRQ_DCDC =              69,
        IRQ_SOFTWARE =          70,
        IRQ_Reserved2 =         71,
        IRQ_GPIO1_INT0 =        72,
        IRQ_GPIO1_INT1 =        73,
        IRQ_GPIO1_INT2 =        74,
        IRQ_GPIO1_INT3 =        75,
        IRQ_GPIO1_INT4 =        76,
        IRQ_GPIO1_INT5 =        77,
        IRQ_GPIO1_INT6 =        78,
        IRQ_GPIO1_INT7 =        79,
        IRQ_GPIO1_0_15 =        80,
        IRQ_GPIO1_16_31 =       81,
        IRQ_GPIO2_0_15 =        82,
        IRQ_GPIO2_16_31 =       83,
        IRQ_GPIO3_0_15 =        84,
        IRQ_GPIO3_16_31 =       85,
        IRQ_GPIO4_0_15 =        86,
        IRQ_GPIO4_16_31 =       87,
        IRQ_GPIO5_0_15 =        88,
        IRQ_GPIO5_16_31 =       89,
        IRQ_FLEXIO1 =           90,
        IRQ_FLEXIO2 =           91,
        IRQ_WDOG1 =             92,
        IRQ_RTWDOG =            93,
        IRQ_EWM =               94,
        IRQ_CCM1 =              95,
        IRQ_CCM2 =              96,
        IRQ_GPC =               97,
        IRQ_SRC =               98,
        IRQ_Reserved3 =         99,
        IRQ_GPT1 =              100,
        IRQ_GPT2 =              101,
        IRQ_FLEXPWM1_0 =        102,
        IRQ_FLEXPWM1_1 =        103,
        IRQ_FLEXPWM1_2 =        104,
        IRQ_FLEXPWM1_3 =        105,
        IRQ_FLEXPWM1_FAULT =    106,
        IRQ_FLEXSPI2 =          107, // RT1060 only
        IRQ_FLEXSPI =           108,
        IRQ_SEMC =              109,
        IRQ_SDHC1 =             110,
        IRQ_SDHC2 =             111,
        IRQ_USB2 =              112,
        IRQ_USB1 =              113,
        IRQ_ENET =              114,
        IRQ_ENET_TIMER =        115,
        IRQ_XBAR1_01 =          116,
        IRQ_XBAR1_23 =          117,
        IRQ_ADC_ETC0 =          118,
        IRQ_ADC_ETC1 =          119,
        IRQ_ADC_ETC2 =          120,
        IRQ_ADC_ETC_ERR =       121,
        IRQ_PIT =               122,
        IRQ_ACMP0 =             123,
        IRQ_ACMP1 =             124,
        IRQ_ACMP2 =             125,
        IRQ_ACMP3 =             126,
        IRQ_Reserved4 =         127,
        IRQ_Reserved5 =         128,
        IRQ_ENC1 =              129,
        IRQ_ENC2 =              130,
        IRQ_ENC3 =              131,
        IRQ_ENC4 =              132,
        IRQ_QTIMER1 =           133,
        IRQ_QTIMER2 =           134,
        IRQ_QTIMER3 =           135,
        IRQ_QTIMER4 =           136,
        IRQ_FLEXPWM2_0 =        137,
        IRQ_FLEXPWM2_1 =        138,
        IRQ_FLEXPWM2_2 =        139,
        IRQ_FLEXPWM2_3 =        140,
        IRQ_FLEXPWM2_FAULT =    141,
        IRQ_FLEXPWM3_0 =        142,
        IRQ_FLEXPWM3_1 =        143,
        IRQ_FLEXPWM3_2 =        144,
        IRQ_FLEXPWM3_3 =        145,
        IRQ_FLEXPWM3_FAULT =    146,
        IRQ_FLEXPWM4_0 =        147,
        IRQ_FLEXPWM4_1 =        148,
        IRQ_FLEXPWM4_2 =        149,
        IRQ_FLEXPWM4_3 =        150,
        IRQ_FLEXPWM4_FAULT =    151,
        IRQ_ENET2 =             152, // RT1060 only
        IRQ_ENET2_TIMER =       153, // RT1060 only
        IRQ_CAN3 =              154, // RT1060 only
        IRQ_Reserved6 =         155,
        IRQ_FLEXIO3 =           156, // RT1060 only
        IRQ_GPIO6789 =          157, // RT1060 only
        IRQ_SJC_DEBUG =         158,
        IRQ_NMI_WAKEUP =        159
};
 
@luni - was also wondering if it would make sense in one or more of your classes to have a method which returns the IRQ number associated with that object?
And/Or have a method like IntervalTImer (priority) where if appropriate they could set the underlying Interrupt handlers IRQ priority?
 
@luni - was also wondering if it would make sense in one or more of your classes to have a method which returns the IRQ number associated with that object?
And/Or have a method like IntervalTImer (priority) where if appropriate they could set the underlying Interrupt handlers IRQ priority?

That would be really good if we can get that return back so we can make sure to setup numbers. Right now I am using one Digital Pin interrupt and IntervalTimer so let me find out which one is suitable for me from above list.
 
Technically this would be possible, but it might be confusing for the average user.

  • The priority is not bound to the actual timer but to its parent module. I.e. for a T4 all PITs or all 4 Timers of a TMR module have the same priority. (BTW, for the PITs this changed from the T3x where each IntervalTimer had its own priority).
  • If you use a timer from the pool you don't even know from which module this timer comes. Setting the priority might be even more confusing
  • The library also provides software timers which don't have a settable priority at all
The design goal of the library was to provide an easy to use and generic interface to basic functionality of the timers. But of course I'm willing to improve the interface. Any input on how the interface should look like would be welcome. Anyway, here an example how to set the priority for a GPT1 based timer. Adaption to the other modules (FTM, TMR) is straight forward.

Code:
#include "TeensyTimerTool.h"
using namespace TeensyTimerTool;

void toggle()
{
  digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN));
}

PeriodicTimer t1(GPT1);

void setup()
{
  pinMode(LED_BUILTIN,OUTPUT);

  t1.begin(toggle, 100'000);
  NVIC_SET_PRIORITY(IRQ_GPT1, 16);
}

void loop()
{
}
 
Back
Top