TeensyTimerTool

I bet not.
But yes, please have a look! It would be interesting to know it gets optimized away. In this case I would have to review all my sourcecodes... :confused:
 
You win. Looks good.

Code:
    72c:	blx	r1
                    callback();
                    regs->CSCTRL;    // = regs->CSCTRL;
    72e:	ldr.w	r3, [r4, #-4]
    732:	ldrh	r3, [r3, #20]

r3 points to the register block where the CSCTRL is at offset 20
 
Doesn't that get optimized away? Even when volatile? I'll have a look at the assembly...

Again I am totally not the expert... But I know in some other libraries, like ili9431_t3 there are times when we need to read a register, but don't care about the results we may do something like:
Code:
  callback();
  uint8_t dummy __attribute__((unused));
  dummy = regs->CSCTRL;
}
...
 
@Frank: No warning
@Kurt: Thanks, didn't know the unused attribute. Generates exactly the same code

Code:
   72c:	blx r1
                  callback();
                  //regs->CSCTRL;
                  uint16_t dummy __attribute__((unused));
                  dummy = regs->CSCTRL;
   72e:	ldr.w	r3, [r4, #-4]
   732:	ldrh	r3, [r3, #20]
 
The unused attribute prevents warnings by gcc.
In this case, if you don't use "dummy", it is not needed (because of volatile)
You can use it for normal variables which may not be used - for example: if you have codeblocks comment out with #ifdef (i.e. #ifdef __imrtx....) - this way you don't need the #ifdef for the variable, too.

The generated code is exactly the same, with or without attribute unused. The only difference is the warning.

There is an other attribute: used
You can use it for functions that would get optimized away without it. For example irq-handlers that are not referenced at compile-time.

@MichaelMeisser: I hope you'll correct me if I say something wrong or oversimplify.
 
Last edited:
Yes, I originally didn't like the dummy version because it generated a warning. The unused fixes that. The version with unused is somehow more informative but looks clumsy. I think I stay with your first suggestion and a comment.

Frank && Kurt, thanks for the info.
 
There are some new features in the TeensyTimerTool .

  • Instead of declaring generic Timer objects and choose the type (periodic or one-shot) with the corresponding begin functions there is a PeriodicTimer and a OneShotTimer class now. IMHO this makes the code more readable. (The old Timer class is still available but will be obsolete soon) The readme file was adapted accordingly.
  • Added the possibility for adding a user config file in sketch scope. If found, this config file will be used instead of the default config.
    Currently the following is configurable (details):
    • Prescaler value of the TMR(aka QUAD) timers. This allows for finer granulated periods (the smallest setting has a tick period of only 1/150MHz = 6ns).
    • Clock frequency of the GPT / PIT timers (150MHz/24MHz)
    • Content and sequence of the modules in the timer pool
    • Type of the callback system (function pointer vs. std::function)
  • Timer period/delay now additionally accepts floating point values
  • Error Handling moved from a static Timer function to a global TeensyTimerTool function. I.e. use TeensyTimerTool::attachErrFunc() to attach an error handler.
  • Timer period overflow handling. The timers report a warning if the required period/delay is too long. The maximum duration of course depends on the settings for clock, prescaler and the width of the counter register.
    The new function getMaxPeriod() reports the maximum possible period for a timer.

Let me know if somebody misses functionality or stumbles over bugs.
 
Last edited:
Maybe I'm missing something, is there an official way to install this on the Mac version of the Arduino software?
 
With the newer MAC OS releases, Teensyduino could no longer install like it used to. So install Paul has to ship a whole Arduino package with Teensyduino parts installed. Which you can install from the normal place: https://www.pjrc.com/teensy/td_download.html

Hi KurtE, I have Arduino software installed and running fine with my Teensy 4.0... It's the TeensyTimerTool I'm having difficulty with... where should I install the src files?
 
TeensyTimerTool is a normal, Arduino compatible library and you can install it like any other library. In case you never did this, here some info https://www.arduino.cc/en/guide/libraries . Scroll down to the chapter about installing zip libraries or to the chapter describing manual installs. Basically, all you have to do is to copy the library to your libraries folder and restart the IDE. In case you are not familiar with GitHub, here is how you can download the zip:

Anmerkung 2020-03-01 081526.jpg


Alternatively you can 'git clone' it to the library folder which makes updating to new versions very easy. GitHub provides an easy to use tool for simple git tasks: https://desktop.github.com/


Let me know if I misunderstood your question or you observe any difficulties.
 
TeensyTimerTool is a normal, Arduino compatible library and you can install it like any other library. In case you never did this, here some info https://www.arduino.cc/en/guide/libraries . Scroll down to the chapter about installing zip libraries or to the chapter describing manual installs. Basically, all you have to do is to copy the library to your libraries folder and restart the IDE.

Thank you, this was the missing piece of the puzzle...
 
Great, I just requested to add it to the Arduino Library repository. That usually takes a day or two. After it is accepted you can add it directly via the library manager.

The library is still work in progress, please let me know if you find anything weird or if you miss functionality. Current documentation is in the gitHub repo readme hope it is sufficient to use the tool.
 
Ok, so I have a question. I want a periodic interrupt around every 500ns... I have tried all the different timers and none seem to be suitable.

I can post my code, but it is simple, it just toggles the pin 13 every call.
 
The readme suggests this abusive timer might work with:
Code:
Pre-Scaling the TMR channels 
The TMR timers are clocked with 150MHz. Since these timers are only 16bit wide you'd get a maximum period of 1/150MHz * 2^16 = 437µs. For longer periods you can pre-scale the timer clock using the TMR_DEFAULT_PSC. Setting this to 0,1,2..7 leads to a pre-scale value of 1,2,4,...128 respectively. Using say 7 you'd get 128/150MHz = 0.853µs per tick and a maximum period of 128/150MHz * 2^16 = 55.9ms.

Would that be a count of 75 at 150 MHz to get 2 MHz and 500 ns?
 
This:

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

PeriodicTimer t1(GPT1);

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

    t1.begin([] { digitalWriteFast(0, !digitalReadFast(0));}, 0.25);
}

void loop()
{}

Generates a 2MHz signal on pin 0. Using one of the QUADS (TMR) as defragster suggests works as well.

2MHz.jpg

Maybe post your code?
 
Ok, First Test for a 2us pulse:

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

PeriodicTimer event(TMR1);

int pin  = 13;
volatile int state = 0;

void tRun(){
  state = 1 - state;
  digitalWriteFast(pin, state);  
  return;
}


void setup() {
  // put your setup code here, to run once:
  pinMode(pin,OUTPUT);

  event.begin(tRun,2); 

  Serial.begin(115200);

}

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

}

Gives a pulse width of 1.70us (setting the interval to 2.5 has no effect on the pulse width, are you sure it can accept float values?)

Editing to use timer GPT1 give a pulse width of 170ns (actually ~168ns)!!

Using timer TCK gives a pulse width of 2.134us


The same code using the Teensy IntervalTimer, gives a rock solid 2us pulse width.
This running the T4 in stock 600Mhz mode.
 
Last edited:
Gives a pulse width of 1.70us (setting the interval to 2.5 has no effect on the pulse width, are you sure it can accept float values?)

The TMR timers run at a default prescaler of 128, this gives 128/150 = 0.85µs per tick. You need to set the prescaler to a smaller value to increase the granularity. See here https://github.com/luni64/TeensyTimerTool#configuration how to do this. Please note that the TMRs are 16bit only, having a too small prescaler will reduce the max period significantly.

Editing to use timer GPT1 give a pulse width of 170ns (actually ~168ns)!!
That is strange and I never observed that, I'll have a look at it later. Did you try the code I posted above?

Using timer TCK gives a pulse width of 2.134us
The TCK timer is a pure software timer without any interrupts. It relies on being called often enough in the background (yield()) For an empty loop you can expect some 4Mhz call frequency which will result in a precision of about 0.25µs which corresponds to what you observe. In real life applications you can not call it that often and the precision will decrease accordingly. So, better not use a TCK for high frequency applications
 
The TMR timers run at a default prescaler of 128, this gives 128/150 = 0.85µs per tick. You need to set the prescaler to a smaller value to increase the granularity. See here https://github.com/luni64/TeensyTimerTool#configuration how to do this. Please note that the TMRs are 16bit only, having a too small prescaler will reduce the max period significantly.

I have put userConfig.h in the sketch folder, tried each prescaler value from 0 to 7... with a interval value of 0.636 (which should be a good value for a prescaler of 0)... all had no effect... I even tried to set the USE_GPT_PIT_150MHz = true, also no effect... so I don't think the compiler is using this file.

EDIT - Confirmed it's pulling values from this file: /Users/matt/Documents/Arduino/libraries/TeensyTimerTool-master/src/defaultConfig.h not userConfig.h in the sketch folder.


Curiously the pulse width seems to be defaulting to 56.4ms when using fractional interval values.

That is strange and I never observed that, I'll have a look at it later. Did you try the code I posted above?

Your code produces a 2Mhz output, with a pulse width of 240ns

The TCK timer is a pure software timer without any interrupts. It relies on being called often enough in the background (yield()) For an empty loop you can expect some 4Mhz call frequency which will result in a precision of about 0.25µs which corresponds to what you observe. In real life applications you can not call it that often and the precision will decrease accordingly. So, better not use a TCK for high frequency applications

This seems quite useful for less time critical applications.
 
Last edited:
I have put userConfig.h in the sketch folder, tried each prescaler value from 0 to 7... with a interval value of 0.636 (which should be a good value for a prescaler of 0)... all had no effect... I even tried to set the USE_GPT_PIT_150MHz = true, also no effect... so I don't think the compiler is using this file.
As mentioned in the documentation you need to do a clean rebuild (once) when you add a user config. Since the Arduino IDE doesn't provide a "clean" command, it is best is to simply delete the build folder. However, for a quick experiment it is probably is easier to change the settings in the DefaultConfig.h (located in the library folder).

Curiously the pulse width seems to be defaulting to 56.4ms when using fractional interval values.
This is the max value for a prescaler of 128. The timer defaults to max in case of a period error. I assume, the period you set was smaller than 1 tick?

Anyway, I'll have a closer look what is going wrong with your code later.
 
Ok, setting the prescaler to 0 for TMR in the defaultConfig.h file results in both the expected output and accuracy :)

I know we are bound to the Arduino platform limitations, perhaps there is an easier way to adjust the config?
 
I just requested to add it to the Arduino Library repository. That usually takes a day or two.

Just checked the status: the library is online now and can be installed using the standard Arduino library manager (Sketch | Include Libraries | Manage Libraries).
 
Editing to use timer GPT1 give a pulse width of 170ns (actually ~168ns)!!

Checked and can confirm this. There was a bug in the GPT implementation which leads to calling the ISR two times for very fast interrupt service routines. The bug was already fixed but for some reason the fix was commented out. I updated the GitHub repo already, but if you don't want to update you can also add a "DSB" instruction at the end of your ISR.

Code:
void tRun(){
  state = 1 - state;
  digitalWriteFast(pin, state);  
  asm volatile("dsb"); // <---------------------------------
  return;
}


Alternatively you can do

Code:
void tRun()
{
  digitalWriteFast(pin, !digitalReadFast(pin));  
}

which is a little bit less efficient than your code which makes it work as expected.

THANKs for spotting that!
 
Back
Top