luni64 / TeensyTimerTool

Generic Interface to Teensy Timers
MIT License
82 stars 18 forks source link

Forum Link #1

Closed Defragster closed 4 years ago

Defragster commented 4 years ago

Hi Luni - looks like nice work. I got here from a forum thread. Always nice to get back to a forum thread from the github? that is ... place a link in Read.Me to : https://forum.pjrc.com/threads/59112-TeensyTimerTool

luni64 commented 4 years ago

Good point, added the link. However, there is not much (i.e., zero ) resonance on the forum. Looks like it does not interest a lot of people. :-)

Defragster commented 4 years ago

I saw it an see it as a cool thing - in fact your callback with params looks very cool! Just haven't added my usual 'nice work' yet for lack of more context to add yet.

If I read right the callbacks don't have to be no param _isr() type. That is much easier to use and work with having 'context'!

This - especially with the TCK's - seems like it could be a good way to extend PJRC's EventResponder function? Paul wants to develop that as a way to get more async operation completed - but avoid calling back from within interrupts where life is complicated and restricted and time sensitive.

luni64 commented 4 years ago

If I read right the callbacks don't have to be no param _isr() type. That is much easier to use and work with having 'context'!

Yes basically you can throw anything callable to it. This makes a lot of things much easier to implement. My favorite are lambdas, i.e. functions you define "on the fly", i.e. directly in the argument of the begin functions. Here an example together with pins.h which makes it pretty expressive.

#include "TeensyTimerTool.h"
#include "pins.h"

using namespace TeensyTimerTool;
using namespace pins;

pin<13> LED(OUTPUT);
Timer timer;

void setup()
{
    timer.beginOneShot([] { LED = LOW; });  // define the callback "in  place"
}

void loop()
{
    LED = HIGH;
    timer.trigger(25'000);
    delay(1'000);
}

This - especially with the TCK's - seems like it could be a good way to extend PJRC's EventResponder function? Paul wants to develop that as a way to get more async operation completed - but avoid calling back from within interrupts where life is complicated and restricted and time sensitive.

I never used the EventResponder, so can't comment on it. But yes, having a more modern interface to callbacks will be usefull. Especially as it still accepts the normal function pointers, so beginners won't even notice.

Defragster commented 4 years ago

Cool - possibilities with code! EventResponder is a WIP - it runs in the yield() context - which is what ties it to similarity to TCK's.

When I read {missed} the 'begin' on forum in ".beginOneShot" - it left me puzzled - went to github and saw example again and it then the '.trigger' clicked { inadvertent but telling pun }

Question: can .trigger be used on anything but a OneShot? That is can a normal timer based event be fired on demand with a .trigger?

luni64 commented 4 years ago

Question: can .trigger be used on anything but a OneShot? That is can a normal timer based event be fired on demand with a .trigger?

Trigger will start a one-shot timer. The callback will be called exactly once after the time given in "trigger". After that the timer stops itself and can be triggered again. You can not use it on a periodic timer (wouldn't make sense? Maybe I misunderstood the question....)

Your remark about callbacks with parameters triggered :-) another example which I just uploaded. It defines a callback which takes a reference to an int which will be printed out in the callback. If you change the variable on the fly the new value will be printed. Here a copy:

#include "TeensyTimerTool.h"
using namespace TeensyTimerTool;

void callback(int& someInt, int cnt)  // this callback has context, i.e. parameter
{
    for (int i = 0; i < cnt; i++)     // whenn called, print out someInt cnt times
    {
        Serial.print(someInt);
        Serial.print(" | ");
    }
    Serial.println();
}

//==============================================================

Timer t;
int number = 0;

void setup()
{
    t.beginPeriodic([] { callback(number, 5); }, 50'000);
}

void loop()
{
    number++;     // change every second
    delay(1000);
}

image

Defragster commented 4 years ago

Indeed that was the question - since a .trigger is only valid on a OneShot that is noteworthy given it isn't named .triggerOneShot() - so just an issue of naming. I didn't expect that it would - although there might be a time where during runtime after seeing some condition 'X' a periodic timer might need to be specifically triggered 'out of order' now or in some 'specific' time from now given that 'X' just happened.

Callback with params looks very useful and powerful.

Teensy_4 can cycle loop() over 5-7 million/sec - up to 20M when there is no yield() code and loop() is very 'empty' and there are no calls to delay() or other things needing attention. I'll have to try monitoring that - something like?:

t.beginPeriodic([] { callback(loopCnt); }, 1,000,000);
with static loopCnt, and loop(){ loopCnt++; //… }
void callback(int& someInt)  // this callback has context, i.e. parameter
{
        Serial.print("loop()/sec=");
        Serial.println(someInt);
        someInt=0;
}

The other related Teensy cool thing is https://github.com/ftrias/TeensyThreads - this outside code is part of TeensyDuino install for a reason - not sure how this TeensyTimerTool complements or works with that?

luni64 commented 4 years ago

Here working code:

#include "TeensyTimerTool.h"
using namespace TeensyTimerTool;

void callback(int &someInt) // this callback has context, i.e. parameter
{
    Serial.printf("loop()/sec= %d\n", someInt);    
    someInt = 0;
}

//==============================================================

Timer t;
int loopCnt = 0;

void setup()
{
    t.beginPeriodic([] { callback(loopCnt); }, 1'000'000);
}

void loop()
{
    loopCnt++;    
}

image

luni64 commented 4 years ago

Or even shorter:

#include "TeensyTimerTool.h"
using namespace TeensyTimerTool;

Timer t;
int loopCnt = 0;

void setup()
{
    t.beginPeriodic([] 
    {
        Serial.printf("loop()/sec= %d\n", loopCnt);
        loopCnt = 0;
    }, 1'000'000);
}

void loop()
{
    loopCnt++;    
}

Same output of course. (BTW: lambdas work with function pointers as well. -> the above example works exactly the same if you use a standard intervaltimer )

Defragster commented 4 years ago

I actually wrote the above as well - posting on forum to show.

luni64 commented 4 years ago

Here the result for the IntervalTimer: image