TeensyTimerTool

Never mind, this forum is here to help... Let me know if something is unclear in the documentation.
 
TeensyTimerTool + serialEvent1 together

Hi,

I am using TeensyTimerTool and serialEvent1 in example code.
Code:
#include "TeensyTimerTool.h"

using namespace TeensyTimerTool;

PeriodicTimer myTimer(GPT1);
//PeriodicTimer myTimer;

//IntervalTimer myTimer;
while I am setting up GPT1 PeriodicTimer I am not able to get serialEvent1 working.
I am using GPT1 so later on I can setup Interrupt priority to higher level.

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

//PeriodicTimer myTimer(GPT1);
//PeriodicTimer myTimer;

IntervalTimer myTimer;

and if I move to IntervalTimer then serialEvent1 works fine. Is TeensyTimerTool or GPT1 is being used by serialEvent1 as well?
I am not sure what is correct way to use both together.

Here is my complete code:
Code:
#include "TeensyTimerTool.h"

using namespace TeensyTimerTool;

PeriodicTimer myTimer(GPT1);
//PeriodicTimer myTimer;

//IntervalTimer myTimer;

unsigned char StreamData = 0;
unsigned long time1,time2,time3,time4 = 0;

unsigned char count = 0;

void TimerFunction()
{
  time2 = micros();
  Serial1.println(time2 - time1);
  time1 = time2;
  if(StreamData == 1)
  {
    Serial.println(count);
    count++;
    if(count >= 10)
    {
      count = 0;
    }
  }
}

void setup()
{
  Serial1.begin(115200);
  myTimer.begin(TimerFunction,1'000'000);  // 1 Sec
}

void loop()
{
  
}

void serialEvent1()
{
  char RxByte;
  while(Serial1.available() > 0)
  {
    RxByte = Serial1.read();
    Serial.write(RxByte);
    if(RxByte == 'S')
    {
      Serial1.println("Started");
      StreamData = 1;
    }
    else if(RxByte == 'E')
    {
      Serial1.println("Stopped");
      StreamData = 0;      
    }
  }
}
 
Sorry for that. The reason is that the TeensyTimerTool overrides the yield function which is also taking care of the SerialEvent stuff. I'll make that configurable and update the lib later today.
 
Sorry for that. The reason is that the TeensyTimerTool overrides the yield function which is also taking care of the SerialEvent stuff. I'll make that configurable and update the lib later today.

You mean changes so we can set if we want to overrides yield function or not?
 
Exactly, thats the idea

That would be really great if we have options for the same. While on other hand if we have real hardware serial interrupt then that may work out temporary, Do you have any idea if we have real hardware interrupt for Serial1 on Teensy4.0?
 
That would be really great if we have options

I implemented the feature in version v0.1.4 on GitHub (should be available in the Arduino library manager in a couple of hours). You can find the complete config documentation here: https://github.com/luni64/TeensyTimerTool/wiki/Configuration

You can select between the following options (Standard: YIELD_OPTIMIZED)
Code:
    #define YIELD_NONE       0                  // Doesn't override yield at all, make sure to call TeensyTimerTool::Tick as often as possible
    #define YIELD_STANDARD   1                  // Uses the standard yield function and adds a call to TeensyTimerTool::Tick() lots of overhead in yield...
    #define YIELD_OPTIMIZED  2                  // Generate an optimized yield which only calls TeensyTimerTool::Tick()

    #define YIELD_TYPE YIELD_OPTIMIZED          // Select the required yield strategy here

  • None: Doesn't touch the stock yield()
  • Standard: Adds a call to tick() to the end of the stock yield() (lots of overhead, I suggest to use this only if you really use SerialEvents or the EventManager ...)
  • Optimized: Replaces the stock yield by a yield which only calls the tick() function (default setting, same behaviour as before)

You can change the settings globally or in your project scope. For the project scope settings you need to do a clean build. If you feel insecure about that try the global setting first.


Hope that helps, let me know if you need support.
 
I implemented the feature in version v0.1.4 on GitHub (should be available in the Arduino library manager in a couple of hours). You can find the complete config documentation here: https://github.com/luni64/TeensyTimerTool/wiki/Configuration

You can select between the following options (Standard: YIELD_OPTIMIZED)
Code:
    #define YIELD_NONE       0                  // Doesn't override yield at all, make sure to call TeensyTimerTool::Tick as often as possible
    #define YIELD_STANDARD   1                  // Uses the standard yield function and adds a call to TeensyTimerTool::Tick() lots of overhead in yield...
    #define YIELD_OPTIMIZED  2                  // Generate an optimized yield which only calls TeensyTimerTool::Tick()

    #define YIELD_TYPE YIELD_OPTIMIZED          // Select the required yield strategy here

  • None: Doesn't touch the stock yield()
  • Standard: Adds a call to tick() to the end of the stock yield() (lots of overhead, I suggest to use this only if you really use SerialEvents or the EventManager ...)
  • Optimized: Replaces the stock yield by a yield which only calls the tick() function (default setting, same behaviour as before)

You can change the settings globally or in your project scope. For the project scope settings you need to do a clean build. If you feel insecure about that try the global setting first.


Hope that helps, let me know if you need support.

Ok, Let me try this out and update you if this is working on the example I shared or not. I think I didn't understand the real use of yield/tick function. If I changed the settings to NONE then I need to call yield in timer function as well correct?
I tried this way.
Code:
void TimerFunction()
{
  time2 = micros();
  Serial1.println(time2 - time1);
  time1 = time2;
  if(StreamData == 1)
  {
    Serial.println(count);
    count++;
    if(count >= 10)
    {
      count = 0;
    }
  }
  yield();
}

BTW:- Github Readme.MD file have wrong url to this forum post.
 
Last edited:
I didn't understand the real use of yield/tick function.

Here an hopefully clear explanation how the software timers work:

  • The software timers (i.e. the TCK timers) are driven by calling a tick function as often as possible. In this tick function the library reads the cycle counter and invokes the timer callback if it is time.
  • Instead of calling the tick function yourself (e.g. in loop) the TeensyTimerTool calls the tick function for you by adding the tick call at the end of yield (standard configuration since v0.1.5).
  • yield is a function which is called by Teensyduino whenever it has time. E.g. between calls to loop or during delay and so on.
  • Thus, yield is a perfect place to do stuff in the background:
    • Teensyduino is using yield for calls to the SerialEvent handlers and the event manager
    • The TeensyTimerTool uses yield to tick its software timers
    • Other libraries might do different stuff as well....

The new version (v0.1.5) gives you the following options for ticking the software timers:
  • YIELD_STANDARD: (default setting since v0.1.5). This does not replace the standard yield but just adds the tick function at the end. So, SerialEvents will work, but the software timers are slightly less efficient.
  • YIELD_OPTIMIZE: (old default setting). Replaces the yield function by one which just ticks the timers and does nothing else. This is very efficient but of course the SerialEvent stuff is not working with this setting.
  • YIELD_NONE: This does not touch yield at all, so you need to tick the timer yourself

For your application you should use YIELD_STANDARD (new default since v0.1.5), then everything should work without changes to your code.

If I changed the settings to NONE then I need to call yield in timer function as well correct?
No, don't do that. Here an example how to call tick manually, i.e., if you want to use YIELD_NONE and want to use the software timers (of course, if you don't use the software timers you don't have to tick the library).

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

PeriodicTimer t1(TCK);

void isr()
{
  Serial.printf("ISR called at t = %d ms\n", millis());
}

void setup()
{
    t1.begin(isr, 100'000);
}

void loop()
{
    TeensyTimerTool::tick();
}
 
@luni: Great !
Now I got this working, GPT1 Timer isr as well as serialEvent1 together without any issue. Thank you for this default settings as now the same library is going to work without doing any manual configuration with or without other event isr.
Thanks again.

Note:- Your github readme does not have correct url to this thread.
 
PIT Timers

The TeensyTimerTool now also supports the PIT timers of the T4.0 boards. This might come in handy if you want to use the generic timer interface including one shot timers, the advanced capabilities of the callback system or the possibiltiy to easily switch to a 150MHz clock instead of the standard 24MHz clock. Other than this, there is no advantage to using the Teensyduino IntervalTimers.


Please note that the T4 boards only have one PIT module with 4 channels (The T3.x boards had 4 independent modules with 1 channel each). Thus, using the Teensy 4 PITs in the TeensyTimerTool will interfere with all Teensyduino Interval timers. Of course, if you don't declare a PIT timer it won't touch the standard Interval timers at all.
 
Thank You Luni !

PIT Timers

The TeensyTimerTool now also supports the PIT timers of the T4.0 boards. This might come in handy if you want to use the generic timer interface including one shot timers, the advanced capabilities of the callback system or the possibiltiy to easily switch to a 150MHz clock instead of the standard 24MHz clock. Other than this, there is no advantage to using the Teensyduino IntervalTimers.


Please note that the T4 boards only have one PIT module with 4 channels (The T3.x boards had 4 independent modules with 1 channel each). Thus, using the Teensy 4 PITs in the TeensyTimerTool will interfere with all Teensyduino Interval timers. Of course, if you don't declare a PIT timer it won't touch the standard Interval timers at all.

Very cool update @luni.
I was using IntervalTimer which was based on PIT timer. Let me replace Interval Timer with TeensyTimerTool.
 
Is 0.1.6 the version which supports PIT timers?

Yes, it is v0.1.6. I just fixed a small bug, so might be good to download again... Here a quick example demonstrating periodic and one shot timers and advanced callbacks. It uses simple lambda expressions and generates a 25ms flash on the built in LED every 750ms:

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

PeriodicTimer t1(PIT);
OneShotTimer t2(PIT);

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

    t1.begin([] {digitalWriteFast(LED_BUILTIN, HIGH); t2.trigger(25'000); }, 750'000);
    t2.begin([] {digitalWriteFast(LED_BUILTIN, LOW); });
}

void loop()
{
}
 
IT IS BLINKING FINE! Had a make error breaking defines ...

Hard to parse the "({,(;, …});" in p#139! Nice and functional - and compact and cryptic :)

And knowing the prototype for the two .begin()'s
 
IT IS BLINKING FINE! Had a make error breaking defines ...

I can reproduce your errors with teensyduino < 1.5. My new code relies on the new ARDUINO_TEENSYXX defines of TD1.5. Might be a good idea to add a check for the correct TD Version in the code....

EDIT: Done and uploaded. Generates a compile error message now if you compile with TD<1.5

Hard to parse the "({,(;, …});" in p#139! Nice and functional - and compact and cryptic
I know... it is not a good idea to have too terse code in examples but this time I couldn't resist :)).
 
Actually that was a great example - knowing the applicable prototypes at hand makes it a learning experience. Intermixed types with params diff # and some 'optional like default=true'

I started wondering about c++ about ~30 years back - but never had reason to bother after a few years of 'C only' at work - and even less reason after leaving.

That TD1.5 a good check - my problem was 'other' and fixed now once I saw what was what.

And the code is consistent too:
Code:
T:\tCode\FORUM\TeTimer_CallBack\TeTimer_CallBack.ino Apr  9 2020 13:30:07
952003
1452003
1952003
2452003
2952003
3452003
 …
99952003
100452003
100952003
101452003
101952003

With these showing the micros() on the oneShot:
Code:
	t1.begin([] {digitalWriteFast(LED_BUILTIN, HIGH); t2.trigger(25000); }, [B][U]500000[/U][/B]);
	t2.begin([] {digitalWriteFast(LED_BUILTIN, LOW); Serial.printf("%lu\n", [B][U]micros()[/U][/B]); });

And same results with empty loop() and TCK timers:
Code:
PeriodicTimer t1(TCK);
OneShotTimer t2(TCK);
 
I was looking for the notes/examples on yield like : #define YIELD_TYPE YIELD_OPTIMIZED

Arrgh … now the docs are out of date :: luni64/TeensyTimerTool/wiki/Configuration

like :: #if defined(T4_0)

You may as well add for the future " #if defined(ARDUINO_TEENSY40) || defined(ARDUINO_TEENSY41) " while you are working as Paul is adding in CORES and to the boards.txt and none of that will change with the same 1062 in use.
 
PIT timer and serialEvent1 together

@luni
That yield setting get changed in this new version? Now with PIT/GPT timer with serialEvent1 is not working together as in this firmware I am not receiving anything on Serial1. (It works with intervalTimer anyway)

Code:
/*
 * TeensyTimerTool --> 0.1.6
 * timer library updated to 0.1.6
 */
#include "TeensyTimerTool.h"

using namespace TeensyTimerTool;

PeriodicTimer myTimer(PIT);
//PeriodicTimer myTimer(GPT1);
//PeriodicTimer myTimer(TCK);
//PeriodicTimer myTimer;

//IntervalTimer myTimer;

unsigned char StreamData = 0;
unsigned long time1,time2,time3,time4 = 0;

unsigned char count = 0;

void TimerFunction2()
{
  Serial1.println(micros() - time2);
  if(StreamData == 1)
  {
    Serial.print(".");
  }
  time2 = micros();
}

void TimerFunction()
{
  Serial1.println(micros() - time1);
  if(StreamData == 1)
  {
    Serial.println(count);
    count++;
    if(count >= 10)
    {
      count = 0;
    }
  }
  time1 = micros();
}

void setup()
{
  Serial1.begin(115200);
  myTimer.begin(TimerFunction,1'000'000);  // 1 Sec
  //myTimer2.begin(TimerFunction2,500'000);  // 500 mSec
}

void loop()
{
  //serial1Check();
  delay(5000);
  Serial.println(".");
}

void serialEvent1()
//void serial1Check()
{
  char RxByte;
  while(Serial1.available() > 0)
  {
    RxByte = Serial1.read();
    Serial.write(RxByte);
    if(RxByte == 'S')
    {
      Serial1.println("Started");
      StreamData = 1;
    }
    else if(RxByte == 'E')
    {
      Serial1.println("Stopped");
      StreamData = 0;      
    }
  }
}
 
Last edited:
Sorry, I introduced a silly error in 0.1.6, should be fixed in v0.1.7. Can you give it a try?
 
I was looking for the notes/examples on yield like : #define YIELD_TYPE YIELD_OPTIMIZED

Arrgh … now the docs are out of date :: luni64/TeensyTimerTool/wiki/Configuration

like :: #if defined(T4_0)

You may as well add for the future " #if defined(ARDUINO_TEENSY40) || defined(ARDUINO_TEENSY41) " while you are working as Paul is adding in CORES and to the boards.txt and none of that will change with the same 1062 in use.

Thanks for spotting this, updated the config documentation. I'll add the ARDUINO_TEENSY41 #define in a later version (need to spot all the relevant places frist)
 
Avoid PWM timer clashes

The Teensyduino PWM functionality is provided by various hardware timers. Specifically, FTMx & TPMx for the T3.x boards and TMRx (QUAD) & FlexPWM for the T4 boards. If you need PWM output on some pins make sure not to allocate the corresponding timer. Here https://github.com/luni64/TeensyTimerTool/wiki/Avoid-PWM-timer-clashes some info and a sketch to print out a list showing which pin corresponds to which PWM timer. (And as a bonus: which GPIO register belongs to the pin). Output is sorted by pin, by PWM timer and by GPIO register for easy use.

Below you find the output for the T4.0 which is missing on the table in the PJRC PWM info page.

Code:
-------------------------------
    Sorted by pin number
Pin |  GPIO Reg  |  PWM timer
----|------------|-------------
00  |  GPIO6_03  |  FLEX_PWM1 
01  |  GPIO6_02  |  FLEX_PWM1 
02  |  GPIO9_04  |  FLEX_PWM4 
03  |  GPIO9_05  |  FLEX_PWM4 
04  |  GPIO9_06  |  FLEX_PWM2 
05  |  GPIO9_08  |  FLEX_PWM2 
06  |  GPIO7_10  |  FLEX_PWM2 
07  |  GPIO7_17  |  FLEX_PWM1 
08  |  GPIO7_16  |  FLEX_PWM1 
09  |  GPIO7_11  |  FLEX_PWM2 
10  |  GPIO7_00  |  QUAD1     
11  |  GPIO7_02  |  QUAD1     
12  |  GPIO7_01  |  QUAD1     
13  |  GPIO7_03  |  QUAD2     
14  |  GPIO6_18  |  QUAD3     
15  |  GPIO6_19  |  QUAD3     
16  |  GPIO6_23  |  no pwm    
17  |  GPIO6_22  |  no pwm    
18  |  GPIO6_17  |  QUAD3     
19  |  GPIO6_16  |  QUAD3     
20  |  GPIO6_26  |  no pwm    
21  |  GPIO6_27  |  no pwm    
22  |  GPIO6_24  |  FLEX_PWM4 
23  |  GPIO6_25  |  FLEX_PWM4 
24  |  GPIO6_12  |  FLEX_PWM1 
25  |  GPIO6_13  |  FLEX_PWM1 
26  |  GPIO6_30  |  no pwm    
27  |  GPIO6_31  |  no pwm    
28  |  GPIO8_18  |  FLEX_PWM3 
29  |  GPIO9_31  |  FLEX_PWM3 
30  |  GPIO8_23  |  no pwm    
31  |  GPIO8_22  |  no pwm    
32  |  GPIO7_12  |  no pwm    
33  |  GPIO9_07  |  FLEX_PWM2 
34  |  GPIO8_15  |  FLEX_PWM1 
35  |  GPIO8_14  |  FLEX_PWM1 
36  |  GPIO8_13  |  FLEX_PWM1 
37  |  GPIO8_12  |  FLEX_PWM1 
38  |  GPIO8_17  |  FLEX_PWM1 
39  |  GPIO8_16  |  FLEX_PWM1 

-------------------------------
     Sorted by PWM timer
Pin |  GPIO Reg  |  PWM timer
----|------------|-------------
12  |  GPIO7_01  |  QUAD1     
11  |  GPIO7_02  |  QUAD1     
10  |  GPIO7_00  |  QUAD1     
13  |  GPIO7_03  |  QUAD2     
18  |  GPIO6_17  |  QUAD3     
15  |  GPIO6_19  |  QUAD3     
14  |  GPIO6_18  |  QUAD3     
19  |  GPIO6_16  |  QUAD3     
24  |  GPIO6_12  |  FLEX_PWM1 
01  |  GPIO6_02  |  FLEX_PWM1 
25  |  GPIO6_13  |  FLEX_PWM1 
34  |  GPIO8_15  |  FLEX_PWM1 
35  |  GPIO8_14  |  FLEX_PWM1 
36  |  GPIO8_13  |  FLEX_PWM1 
37  |  GPIO8_12  |  FLEX_PWM1 
38  |  GPIO8_17  |  FLEX_PWM1 
39  |  GPIO8_16  |  FLEX_PWM1 
00  |  GPIO6_03  |  FLEX_PWM1 
08  |  GPIO7_16  |  FLEX_PWM1 
07  |  GPIO7_17  |  FLEX_PWM1 
09  |  GPIO7_11  |  FLEX_PWM2 
04  |  GPIO9_06  |  FLEX_PWM2 
05  |  GPIO9_08  |  FLEX_PWM2 
06  |  GPIO7_10  |  FLEX_PWM2 
33  |  GPIO9_07  |  FLEX_PWM2 
28  |  GPIO8_18  |  FLEX_PWM3 
29  |  GPIO9_31  |  FLEX_PWM3 
23  |  GPIO6_25  |  FLEX_PWM4 
22  |  GPIO6_24  |  FLEX_PWM4 
03  |  GPIO9_05  |  FLEX_PWM4 
02  |  GPIO9_04  |  FLEX_PWM4 
27  |  GPIO6_31  |  no pwm    
17  |  GPIO6_22  |  no pwm    
26  |  GPIO6_30  |  no pwm    
30  |  GPIO8_23  |  no pwm    
31  |  GPIO8_22  |  no pwm    
32  |  GPIO7_12  |  no pwm    
21  |  GPIO6_27  |  no pwm    
20  |  GPIO6_26  |  no pwm    
16  |  GPIO6_23  |  no pwm    

-------------------------------
   Sorted by GPIO register:        
Pin |  GPIO Reg  |  PWM timer
----|------------|-------------
01  |  GPIO6_02  |  FLEX_PWM1 
00  |  GPIO6_03  |  FLEX_PWM1 
24  |  GPIO6_12  |  FLEX_PWM1 
25  |  GPIO6_13  |  FLEX_PWM1 
19  |  GPIO6_16  |  QUAD3     
18  |  GPIO6_17  |  QUAD3     
14  |  GPIO6_18  |  QUAD3     
15  |  GPIO6_19  |  QUAD3     
17  |  GPIO6_22  |  no pwm    
16  |  GPIO6_23  |  no pwm    
22  |  GPIO6_24  |  FLEX_PWM4 
23  |  GPIO6_25  |  FLEX_PWM4 
20  |  GPIO6_26  |  no pwm    
21  |  GPIO6_27  |  no pwm    
26  |  GPIO6_30  |  no pwm    
27  |  GPIO6_31  |  no pwm    
10  |  GPIO7_00  |  QUAD1     
12  |  GPIO7_01  |  QUAD1     
11  |  GPIO7_02  |  QUAD1     
13  |  GPIO7_03  |  QUAD2     
06  |  GPIO7_10  |  FLEX_PWM2 
09  |  GPIO7_11  |  FLEX_PWM2 
32  |  GPIO7_12  |  no pwm    
08  |  GPIO7_16  |  FLEX_PWM1 
07  |  GPIO7_17  |  FLEX_PWM1 
37  |  GPIO8_12  |  FLEX_PWM1 
36  |  GPIO8_13  |  FLEX_PWM1 
35  |  GPIO8_14  |  FLEX_PWM1 
34  |  GPIO8_15  |  FLEX_PWM1 
39  |  GPIO8_16  |  FLEX_PWM1 
38  |  GPIO8_17  |  FLEX_PWM1 
28  |  GPIO8_18  |  FLEX_PWM3 
31  |  GPIO8_22  |  no pwm    
30  |  GPIO8_23  |  no pwm    
02  |  GPIO9_04  |  FLEX_PWM4 
03  |  GPIO9_05  |  FLEX_PWM4 
04  |  GPIO9_06  |  FLEX_PWM2 
33  |  GPIO9_07  |  FLEX_PWM2 
05  |  GPIO9_08  |  FLEX_PWM2 
29  |  GPIO9_31  |  FLEX_PWM3
 
Back
Top