TeensyTimerTool Versions Save

Generic Interface to Teensy Timers

v1.3.0

1 year ago

Switches to inplace_function for callbacks. Fixes a namespace issue when used together with the EncoderTool

v1.1.0

1 year ago

This version replaces the heavy std::function based callback system with a smaller implementation (https://github.com/luni64/staticFunctional). The change should be transparent to users, so please report any observed incompatibilities or peculiarities.

You can still configure the library to use a traditional function pointer based void(*callback)(void) callback system. But, with the new smaller staticFunctional::function based system there should be no reason to do so.

Please note: staticFunctional requires the new toolchain introduced with Teensyduino 1.58 beta. Older teensyduino versions will fall back to the function pointer based 'void(*callback)()' system automatically.

v1.0.0

1 year ago

To be compatible to the new gcc 11.3 toolchain I needed to remove the frequency uitility (timers accepted 3.45_MHz , 17kHz etc as period parameter). The corresponding header (frequency.h) was a wild hack which is not accepted anymore by the new gcc. Lets hope that future implementations of allow frequency types in addition to duration types.

v0.4.3

2 years ago

This is just a sync release to trigger an update of the Arduino library manager

v0.4.1

2 years ago

New features:

The example shows how to use this timer to print out the relative drift between the 32kHz RTC crystal the the main 24MHz crystal.

#include "TeensyTimerTool.h"
using namespace TeensyTimerTool;

PeriodicTimer t1(TCK_RTC);

constexpr uint32_t period = 500'000; //µs

void callback()
{
    static uint32_t start = micros();
    static uint32_t idx   = 0;

    uint32_t now          = micros() - start;
    uint32_t expected     = idx++ * period;
    int32_t delta         = now - expected;
    float drift           = 1E6 * delta / expected;  // ppm

    Serial.printf("t: %d µs,  rel. drift: %.2f ppm\n", now, drift);
}

void setup(){
    t1.begin(callback, period);
}

void loop(){
}
  • Added setPeriod and setNextPeriod to the TCK, PIT, GPT and TMR timers.

    • setPeriod tries to change the current period to a new value. This of course only works if the new period is longer than the old period or the change request comes early enough in the current period. In case the change request comes 'too late' the current period will end, the callback will be called and the next period has the correct period
    • setNextPeriod sets the new period after the current period. This never generates a wrong period in between (as can happen with setPeriod)
  • Destructors should work correctly now. I.e. you can use the timers as local variables. Leaving the scope while the timer runs will gracefully stop it and release allocated hardware resources.

Misc

  • Large restructuring of the code. This might have generated bugs. PLEASE report any unusual behavior in the issues section.

v0.3.1

3 years ago

Just a quick update to add frequency literals to the list of possible arguments for the begin() functions of periodic timers. (Please note the required underscore prefix to the literals)

timer.begin(isr, 100_kHz);       // instead of      10 (µs)
timer.begin(isr, 0.25_MHz);      // instead of       4 (µs)
timer.begin(isr, 5_kHz + 10_Hz); // instead of 100'200 (µs)

v0.3.0

3 years ago

This is just a small update to be compatible to the std::chrono::duration and the corresponding nice user defined literals. I.e. instead of passing in microseconds to begin() and trigger(), you can now also use std::chrono::durations. Here some examples:

 timer[0].trigger(10ms);                                  // 10 ms
 timer[1].trigger(0.5s + 10ms);                           // 510 ms
 timer[2].trigger(2.5 * 0.3s + 20000us / 2);              // 760 ms
 timer[3].trigger(milliseconds(50) + microseconds(5000)); // 55ms

which makes a much nicer interface.

v0.2.1

3 years ago

New Features

The OneShotTimers now provide a possibility to directly trigger them with a precalculated reload value. Since the normal trigger function involves a float calculation to convert the trigger time to the counter reload value it makes sense to precalculate it if you need to repeatedly trigger a signal with high frequency. This helps reducing processor load and timing errors for the slower processors like T3.2 which don't have a floating point unit. For a T4 the savings are quite insignificant.

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

    OneShotTimer t1(GPT1);     // use  GPT1 for the test
    t1.begin([] { digitalWriteFast(1, LOW); });

    // normal triggering -----------------------------------------------------
    for (int i = 0; i < 3; i++)
    {
        digitalWriteFast(1, HIGH); // set pin
        t1.trigger(10);            // reset after 10µs
        delayMicroseconds(50);
    }
    delayMicroseconds(100);

    // direct triggering -----------------------------------------------------
    uint32_t reload;
    t1.getTriggerReload(10, &reload); // precalculate the reload value for a 10µs delay time

    for (int i = 0; i < 3; i++)
    {
        digitalWriteFast(1, HIGH); // set pin
        t1.triggerDirect(reload);  // reset after 10µs
        delayMicroseconds(50);
    }
}

void loop()
{   
}

image

-> For a T3.2 @96MHz the time to trigger reduces by about 2µs which can be significant for high speed applications.

v.0.2.0

3 years ago

The 32bit cycle counter (ARM_DWT_CYCCNT) which is used for the TCK timers overflows quite fast (e.g. every 7s on a T4@600MHz). I therefore added a variant of the TCK timers which extends ARM_DWT_CYCCNT to 64bit (v0.2.0). This allows for periods up to to full 2^32 microseconds (4295 seconds, 71.6 minutes). The new timer works on all T3.x and T4.x boards. I'll add the documentation to the TeensyTimerTool WIKI in the next days.

Here a small T4 sketch which prints out the overflow duration of the timers currently available with the TeensyTimerTool. The sketch was run in standard configuration, i.e., F_CPU=600MHz, GPT & PIT @24MHz, QUAD @150MHz with prescaler: PSC_AUTO.

#include "TeensyTimerTool.h"
using namespace TeensyTimerTool;

PeriodicTimer t1(TCK);
PeriodicTimer t2(TCK64);  // <-- new
PeriodicTimer t3(GPT1);
PeriodicTimer t4(TMR3);
PeriodicTimer t5(PIT);

PeriodicTimer blink(TCK);

void empty(){}

void setup()
{
    while (!Serial) {}

    t1.begin(empty, 1'000);
    t2.begin(empty, 1'000);
    t3.begin(empty, 1'000);
    t4.begin(empty, 1'000);
    t5.begin(empty, 1'000);

    Serial.printf("TCK:           %8.3f seconds\n", t1.getMaxPeriod());
    Serial.printf("TCK64:         %8.3f seconds\n", t2.getMaxPeriod());    // <-- new
    Serial.printf("GPT(@24MHz)    %8.3f seconds\n", t3.getMaxPeriod());
    Serial.printf("QUAD(PSC_AUTO) %8.3f seconds\n", t4.getMaxPeriod());
    Serial.printf("PIT(@24MHz)    %8.3f seconds\n", t5.getMaxPeriod());

    pinMode(LED_BUILTIN, OUTPUT);
    blink.begin([] { digitalToggle(LED_BUILTIN); }, 300'000); // heart beat
}

void loop()
{
}

And here the output

TCK:              6.711 seconds
TCK64:         4294.967 seconds
GPT(@24MHz)     178.957 seconds
QUAD(PSC_AUTO)    0.056 seconds
PIT(@24MHz)     178.957 seconds

v0.1.11

3 years ago

Start / Stop Timers

Quick Example:

#include "TeensyTimerTool.h"
using namespace TeensyTimerTool;

PeriodicTimer t1;

void setup()
{
    while (!Serial) {}
    TeensyTimerTool::attachErrFunc(ErrorHandler(Serial)); // optional, print errors on Serial
    pinMode(13, OUTPUT);

    t1.begin([] { digitalToggleFast(13); }, 50'000); //Blink

    delay(2000);  // stop timer after 2s
    t1.stop();

    delay(2000);  // restart after 2s
    t1.start();
}

void loop()
{
}

Begin Timer in Stopped mode

#include "TeensyTimerTool.h"
using namespace TeensyTimerTool;

PeriodicTimer t1;

void setup()
{
    while (!Serial) {}
    TeensyTimerTool::attachErrFunc(ErrorHandler(Serial)); // optional, print errors on Serial
    pinMode(13, OUTPUT);

    t1.begin([] { digitalToggleFast(13); }, 50'000, false); // Prepare timer but dont start (last parameter = false)

    delay(2000);  // start timer after 2s
    t1.start();
}

void loop()
{
}