TeensyTimerTool

It is supposed to do the second.

However, as joepasquariello mentioned, those functions are currently not implemented for the FTM timers. As a first fix I implemented the setNextPeriod() function which changes the next period after you call it. Implementing setPeriod() (i.e. hard stop the current timer and restart with a new period) is kind of difficult since all FTM Channels of one module use the same underlying counter. I'll see if I can work around this on the weekend.

You can find the new code in the "fixFTM" Branch on the gitHub repo.

@luni, it looks to me like the new setPeriod() in your fixFTM branch will do what you want. Because you have FTMEN=0 in the FTMx_MODE registers, and you are using output compare, writes to the CV registers take effect on the next FTM clock, so they "override" the current period. The code in start() does the right thing, i.e. add the new period (in clocks) to the current value of the FTM clock CNT.

Code:
    errorCode FTM_Channel::start()
    {
        ci->chRegs->CV = regs->CNT + ci->reload;     // compare value (current counter + pReload)
        ci->chRegs->SC &= ~FTM_CSC_CHF;              // reset timer flag
        ci->chRegs->SC = FTM_CSC_MSA | FTM_CSC_CHIE; // enable interrupts
        return errorCode::OK;
    }

    errorCode FTM_Channel::stop()
    {
        ci->chRegs->SC &= ~FTM_CSC_CHIE; // enable interrupts
        ci->chRegs->SC &= ~FTM_CSC_CHF;  // reset timer flag

        return errorCode::OK;
    }

    // errorCode FTM_Channel::setPeriod(float us)
    // {
    //     stop();
    //     ci->reload = ticksFromMicros(us);
    //     start();
    //     return errorCode::OK;
    // }

    errorCode FTM_Channel::setNextPeriod(float us)
    {
        ci->reload = ticksFromMicros(us);
        return errorCode::OK;
    }
 
Hi luni,

thanks for the follow up, I see the fixFTM branch and the new commit you pushed up to the repository. I noticed this commented-out block:

Code:
    errorCode FTM_Channel::setPeriod(float us)
    {
        stop();
        ci->reload = ticksFromMicros(us);
        start();
        return errorCode::OK;
    }

This looks like it has the functionality I want (going back to my original desire, to ensure that the period of the purple trace starts perfectly aligned with the pulse shown in the yellow trace)

Previously, I was calling stop() and then start() again, but I realized that this just temporarily pauses the timer and then un-pauses it again (which is not what I wanted).
 
This looks like it has the functionality I want (going back to my original desire, to ensure that the period of the purple trace starts perfectly aligned with the pulse shown in the yellow trace)
As mentioned above, the setPeriod functionality does not seem to work as intended (at least during my very first tests it didn't stop the period but did the same as SetNextPeriod()). I'll have a closer look on this and Joe's results on the weekend. Anyway, feel free to uncomment and see if it will work for your needs.

Can you elaborate a bit what you want to achieve in the end? Looks like you have got some external 1Hz signal and you want to sync a 10Hz signal to it? If so, I'd rather let an IntervalTimer running and use the external signal to finetune the frequency of it. I.e., something like this (modulo details):
  • Use the timer callback to save a current timestamp (e.g. using the cycle counter)
  • Use the pinInterrupt callback to calculate the time difference to the last timestamp.
  • Use this difference to adjust the Intervaltimer period on the fly. Maybe a simple PID would help to adjust the period.
 
  • Use the timer callback to save a current timestamp (e.g. using the cycle counter)
  • Use the pinInterrupt callback to calculate the time difference to the last timestamp.
  • Use this difference to adjust the Intervaltimer period on the fly. Maybe a simple PID would help to adjust the period.
Hi luni, this is an interesting idea, yeah a PID would be one way to achieve this, thank you!
 
I just published a new release of the TeensyTimerTool (v1.0.1) .

Two main changes:
  • To be compatible with the new toolchain (1.58beta) I needed to remove the capability to enter timer periods in frequency units (e.g. 12.3_kHz etc). Since this was a wild hack anyway I'm not too sorry. Hope that nobody used this feature in production code. The usual time based units (e.g. 42ms, 145.5us, 800ns etc) still work of course.
  • I changed the underlying callback system from std::function (quite heavy) to my new staticFunctional library. staticFunctional has a much smaller memory footprint and doesn't use any dynamic memory. Ideally, library users should not note any difference.
    Please note: The new system is only active if you use the new 1.58beta toolchain (GCC version >= v7). Using the old toolchain (GCC v5.4) the TimerTool will fall back to function based void(*callback)() callbacks automatically.

Please let me know if you find any incompatibilities or other bugs
 
Hello, I'm trying to integrate some other code that uses TeensyTimerTool into my project that uses TeensyThreads. The thread code no longer gets called. The following demonstrates this:

Code:
#include <Arduino.h>
#include "TeensyThreads.h"
#include "TeensyTimerTool.h"
using namespace TeensyTimerTool;

PeriodicTimer t1; // generate a timer from the pool (Pool: 2xGPT, 16xTMR(QUAD), 20xTCK)

void blinkthread() {
  while (1) {
    Serial.println("Thread - blinkthread()");
    threads.delay(500);
  }
}

void callback()
{
  Serial.println("Timer - callback()");
}

void setup() {
  delay(1000);
  t1.begin(callback, 50'000);
  threads.addThread(blinkthread);
}

void loop() {
}

What can I do so that they will work together in the same project? I'm running TTT 1.3.0 and TT 1.0.2 on a T4.1/T MicroMod. Many thanks.
 
I have absolutely no experience with TeensyThreads. Can it be that TeensyThreads uses the GPT1 timer for thread switching?

If you use a PeriodicTimer without specifiying the used timer module it uses timers from a pool, the content of which is defined here: https://github.com/luni64/TeensyTimerTool/wiki/Configuration#available-settings I.e. the first timer it uses is GPT1, then GPT2 etc.

Try specifiying the used module by e.g.

Code:
PeriodicTimer t1(PIT); // use one of the 4 PIT timer channels
PeriodicTimer t2(TCK); // use a software based timer
//...

You find a list of available timers here: https://github.com/luni64/TeensyTimerTool/wiki/Supported-Timers
 
I have absolutely no experience with TeensyThreads. Can it be that TeensyThreads uses the GPT1 timer for thread switching?

Yes, that's the reason. I tried the timer definition below, and it worked. However, the OP should be aware that print/println are no re-entrant, so it's not OK to call Serial.print/println from a task and also from an ISR, as the ISR may eventually step on the task. Generally speaking, don't use print/println in ISRs, and if you want to use them within a TeensyThreads task, you should either (a) surround them with lock/unlock statements (or whatever those are called in TeensyThreads), or (b) define a very long time slice for TeensyThreads so that it effectively becomes cooperative, and not preemptive. That has been discussed on some forum threads.

Code:
PeriodicTimer t1(TMR1); // First channel on TMR1 aka QUAD timer module. (TMR1 - TMR4, four 16bit channels each)
 
Hello,

today I updated some tools and libraries on my dev computer. Now projects don't compile anymore (VScode). It's related to TTT. Teensy 3.2 :

Code:
lib/TeensyTimerTool/src/TimerModules/RTC//RTC.cpp: In function 'TeensyTimerTool::ITimerChannel* TeensyTimerTool::RTC_t::getTimer()':
lib/TeensyTimerTool/src/TimerModules/RTC//RTC.cpp:24:35: error: 'IRQ_SNVS_IRQ' was not declared in this scope
   24 |             attachInterruptVector(IRQ_SNVS_IRQ, isr);
      |                                   ^~~~~~~~~~~~
make: *** [makefile:214: .vsteensy/build/lib/TeensyTimerTool/src/TimerModules/RTC//RTC.cpp.o] Error 1
make: *** Waiting for unfinished jobs....

Can someone help me with this please ?
Thank you,
Manu

P.S. : I use Teensyduino 1.58
 
Hello,

today I updated some tools and libraries on my dev computer. Now projects don't compile anymore (VScode). It's related to TTT. Teensy 3.2 :

Code:
lib/TeensyTimerTool/src/TimerModules/RTC//RTC.cpp: In function 'TeensyTimerTool::ITimerChannel* TeensyTimerTool::RTC_t::getTimer()':
lib/TeensyTimerTool/src/TimerModules/RTC//RTC.cpp:24:35: error: 'IRQ_SNVS_IRQ' was not declared in this scope
   24 |             attachInterruptVector(IRQ_SNVS_IRQ, isr);
      |                                   ^~~~~~~~~~~~
make: *** [makefile:214: .vsteensy/build/lib/TeensyTimerTool/src/TimerModules/RTC//RTC.cpp.o] Error 1
make: *** Waiting for unfinished jobs....

Can someone help me with this please ?
Thank you,
Manu

P.S. : I use Teensyduino 1.58

Seems that was a recent T_4.x specific change where IRQ_SNVS_IRQ exists and is used for a new RTC based timer.

@luni will need to #ifdef that - going back a version of TTT will get rid of that conflict, unless that were just edited out until it can be updated.
 
Sorry, as defragster mentioned I forgot to enable the RTC timer for T4x boards only. Should be fixed in 1.4.1. @Manu: can you try if it compiles now?
 
Hey Luni,

Is there a way to control the priority of timer callbacks using this library?
I haven't seen anything in this thread or in the documentation about this.
 
You can set the priority directly using the NVIC. Note that the priority can only be set for a complete timer module, not for the individual channels of a module. For example, if you set the priority of the TMR2 module, all 4 channels of this module will get the same priority. Here is an example of how to set the priority of GPT1, the 4 channels of TMR2 and the 4 channels of PIT:

C++:
#include "Arduino.h"
#include "TeensyTimerTool.h"

using namespace TeensyTimerTool;

PeriodicTimer T1(GPT1);
PeriodicTimer T2(TMR2);
PeriodicTimer T3(PIT);

void setup()
{
    T1.begin([]{Serial.println("GPT1");}, 100ms);
    T2.begin([]{Serial.println("TMR2-CH1");}, 50ms);
    T3.begin([]{Serial.println("PIT-CH1");}, 0.2s);

    NVIC_SET_PRIORITY(IRQ_GPT1, 128);
    NVIC_SET_PRIORITY(IRQ_QTIMER2, 16);
    NVIC_SET_PRIORITY(IRQ_PIT, 32);
}

void loop(){}
 
Back
Top