Forum Rule: Always post complete source code & details to reproduce any issue!
Page 14 of 15 FirstFirst ... 4 12 13 14 15 LastLast
Results 326 to 350 of 353

Thread: TeensyTimerTool

  1. #326
    Forum keeps timing me out. Lost my post. Got the signal running fast enough for me. Now trying to make the period variable. You advised me to use setPeriod. In the wiki, there is also a setNextPeriod. I tried setPeriod, and there seems to be sort of a delay. Guess that is understandable because the change is asynchronous. Is setNextPeriod supposed to eliminate the delay?

    My first attempt at dynamic change of the timer was not good. Forgot to change based on integer periods, and did it based on time. Oops. This resulted in changing the period before the period was up. Not pretty. Maybe tomorrow I will be able to make that work.

    My lathe does have linear encoders, but in the beginning, I will only work on spindle position and lead screw position. I want to be able to cut different threads with out changing gears, or to move the carriage very slow for a good finish. If that works out well, I will integrate in the linear encoders. But first, I need to take baby steps.

  2. #327
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    16,188
    @clinker8 - not had that 'timeout' hit here in some time. After logging back into that thread check the lower left corner of the 'reply' box for "restore" as content seems to be stored on some time period during edits.

  3. #328
    Seem to be a slow writer The restore content got the post before, but not the one I was writing. Oh well, managed to recover!

  4. #329
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    1,849
    Forum keeps timing me out. Lost my post. Got the signal running fast enough for me. Now trying to make the period variable. You advised me to use setPeriod. In the wiki, there is also a setNextPeriod. I tried setPeriod, and there seems to be sort of a delay. Guess that is understandable because the change is asynchronous. Is setNextPeriod supposed to eliminate the delay?
    setPeriod changes the period immediately. I.e., it will end the current period and restart the timer with the new period. setNextPeriod is supposed to set a new period after the current one is done to prevent partial periods. There should be no delay (other than the time needed for executing ) in both functions.

    I kind of remember having issues with setNextPeriod some time ago but didn't look into it deeper. So, let me know if setNextPeriod is not working as expected.

  5. #330
    Quote Originally Posted by luni View Post
    setPeriod changes the period immediately. I.e., it will end the current period and restart the timer with the new period. setNextPeriod is supposed to set a new period after the current one is done to prevent partial periods. There should be no delay (other than the time needed for executing ) in both functions.

    I kind of remember having issues with setNextPeriod some time ago but didn't look into it deeper. So, let me know if setNextPeriod is not working as expected.
    setNextPeriod doesn't seem to work at all in my code, but setPeriod seems ok. Ok in the sense that at least there are 4 pulses of the same period, then 4 more at a different period. The last long pulse is sort of strange, but I think it is still "forward". setNextPeriod does not change the waveform, at least not in my code.
    Code:
    #include "TeensyTimerTool.h"
    
    using namespace TeensyTimerTool;
    
    // for Teensy 4.1 only
    
    PeriodicTimer t1(GPT1);
    PeriodicTimer t2(GPT2);
    
    float maxperiod, periodincrement;
    int maxcount, gpt2period;
    volatile bool forward;
    volatile float period;
    float initperiod;
    
    #define A 1
    #define B 2
    
    // Callbacks
    
    void a_ns( )
    {
      static int state=0;
      switch (state & 3) {
        case 0:
        { 
          if (forward) { digitalWriteFast(A, HIGH); digitalWriteFast(B, LOW); }
          else { digitalWriteFast(A, LOW); digitalWriteFast(B, HIGH); }
          break;
        }
        case 1:
        { 
          if (forward) { digitalWriteFast(A, HIGH); digitalWriteFast(B, HIGH); }
          else { digitalWriteFast(A, HIGH); digitalWriteFast(B, HIGH); }
          break;
        }
        case 2:
        {
          if(forward) { digitalWriteFast(A, LOW); digitalWriteFast(B, HIGH); }
          else { digitalWriteFast(A, HIGH); digitalWriteFast(B, LOW); }
          break;
        }
        case 3:
        {
          digitalWriteFast(A, LOW); digitalWriteFast(B, LOW); 
          // same for both fwd and reverse
          break;
        }
      }
      state++;
    }
    
    void slowtime()
    {
      bool test1;
      test1 = false;
    
      period += periodincrement;
      if (period > maxperiod) 
      {
        period = initperiod;
        digitalWriteFast(3, HIGH);  // add timing mark to detect beginning
        delayNanoseconds(20);
        digitalWriteFast(3, LOW);
      }
      if (test1)
      {
        t1.setNextPeriod(period);
        t2.setNextPeriod(period*16);
      }
      else
      {
        t1.setPeriod(period);
        t2.setPeriod(period*16);
      }
    }
    
    void setup() {
      // put your setup code here, to run once:
      for(unsigned pin=1; pin<=3; pin++) pinMode(pin, OUTPUT);
      
      Serial.begin(9600);
      //while(!Serial) delay(10);
      
      initperiod = 1.0;
      gpt2period = 16*initperiod;  // interrupt every 4 full pulses
      
      period = initperiod;  // initial start interrupt period us.  Real period is 4x.
      periodincrement = 1.0;
      maxperiod = 100*periodincrement;  // 
      Serial.print("max period = "); Serial.print(maxperiod);
      forward = true;
      t1.begin( a_ns, period); // default time is in us.  Min value is 0.25.
      t2.begin( slowtime, gpt2period);
    }
    
    void loop() {
      // put your main code here, to run repeatedly:
      
    
    }
    if test1 is true, (using setNextPeriod) the code fails to create the varying waveform. If false, (using setPeriod) the waveform looks ok.

    Click image for larger version. 

Name:	PXL_20220507_152012879_500.jpg 
Views:	11 
Size:	53.9 KB 
ID:	28317Click image for larger version. 

Name:	PXL_20220507_152100932_500.jpg 
Views:	7 
Size:	49.9 KB 
ID:	28318

  6. #331
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    1,849
    Thanks, I'll have a look. But this will take some time (working on another project currently...)
    Quick Idea, can you change the GPT1/GPT2 to PIT and see if it works then?

  7. #332
    Quote Originally Posted by luni View Post
    Thanks, I'll have a look. But this will take some time (working on another project currently...)
    Quick Idea, can you change the GPT1/GPT2 to PIT and see if it works then?
    Tried using PIT. Ok with setPeriod, follows the pattern. Something is off with setNextPeriod, It stalls for 1.4ms, then behaves as expected when the pulses get longer. It is like it is either blocking somewhere, or just taking too long for a while. After 1.4ms, setNextPeriod seems to work. And it continues to work until the max quarter period is set (100us). Then resets to 1us but stays at 1us for 1.4ms. Do not get this behavior with setPeriod.

    First file: setPeriod. Second file: setNextPeriod
    Click image for larger version. 

Name:	SDS01setPeriod.jpg 
Views:	10 
Size:	98.7 KB 
ID:	28320Click image for larger version. 

Name:	SDS03setNextPeriod.jpg 
Views:	5 
Size:	76.2 KB 
ID:	28321

  8. #333
    Member
    Join Date
    Jun 2015
    Location
    Palm Springs, CA
    Posts
    55
    This all looks complicated and requiring knowledge of interrupts and low-level coding. Is there a simple way to do PWM like AnalogWrite? I'm just trying to do 16,17, or 18-bit dimming of LED's. The default max of AnalogWrite is actually 15 bits, even when resolution is set to 16.

  9. #334
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    1,849
    Sorry, the TimerTool does not implement any PWM functionality. However, the features of the 32bit GPT timers look promising for this.
    This all looks complicated and requiring knowledge of interrupts and low-level coding
    Yes

  10. #335
    Hi Luni,

    I'm using the TTT in one-shot mode to manage a screen timeout on an attached OLED but it isn't behaving as expected.

    I've used the following code (this is just part of my code, not all of it)

    Code:
    OneShotTimer timeoutTimer(GPT2); // used to determine when to shut the screen off
    
    timeoutTimer.begin(screenTimeoutISR);
    
    uint32_t timeoutMillis[3] = {10000, 1800000, 3600000}; // timeout time in mS, 15mins, 30mins, 60mins (900000, 1800000, 3600000)
    
    void setup() {
      if (timeOutOn) {
        timeoutTimer.trigger(timeoutMillis[timeoutTime] * 1000);
      }
    }
    
    void screenTimeoutISR() {
      Serial.println("SCREEN TIMED OUT");
      timeoutTimer.stop();
      screenTimedOut = 1;
      clearTheDisplay();
    }
    If timeoutTime == 0 then the timeoutTimer will trigger fine after 10 seconds but if i increase timeoutMillis[0] to 900,000 then the timeoutTimer is triggered right after it starts.

    So what is the maximum time for a OneShotTimer on GPT2? I assumed that since the GPT2 timer is 32-bit the maximum value would be 4,294,967,296 but using a time of 900,000 * 1000 = 900,000,000 doesn't seem to work properly. I'm assuming that it is because of the time i am setting in the trigger.

    Cheers

    NM

  11. #336
    p.s. i've been able to determine that the largest value i can put into timeoutMillis[0] is 178,956 which is 178,956,000 when it is put into the timeoutTimer.trigger(); function. Any values larger than this cause the timeoutTimer to trigger instantly after being called.

    I'm also assuming that the value for a OneShotTimer.trigger() is in microseconds.

    e.g.
    Code:
    timeoutTimer.trigger(178,956,000);

  12. #337
    Quote Originally Posted by NuttyMonk View Post
    p.s. i've been able to determine that the largest value i can put into timeoutMillis[0] is 178,956 which is 178,956,000 when it is put into the timeoutTimer.trigger(); function. Any values larger than this cause the timeoutTimer to trigger instantly after being called.

    I'm also assuming that the value for a OneShotTimer.trigger() is in microseconds.
    The default clock frequency for T4.x GPT and PIT timers in TeensyTimerTool is 24 MHz, so max period in 32 bits is (2^32)/24e6 = 178.95697 seconds. There are both 32- and 64-bit software-based timers (TCK). At 64 bits, the CycleCounter64 timers have max period ~630 years. For non-critical timeouts in the range of minutes to hours to days, you could just use elapsedMillis(), though you would have to poll it, as opposed to having a callback on timeout.

  13. #338
    Quote Originally Posted by joepasquariello View Post
    The default clock frequency for T4.x GPT and PIT timers in TeensyTimerTool is 24 MHz, so max period in 32 bits is (2^32)/24e6 = 178.95697 seconds. There are both 32- and 64-bit software-based timers (TCK). At 64 bits, the CycleCounter64 timers have max period ~630 years. For non-critical timeouts in the range of minutes to hours to days, you could just use elapsedMillis(), though you would have to poll it, as opposed to having a callback on timeout.
    Hi Joe,

    i am looking to use a callback routine instead of polling using elapsedMillis if i can. I've been weeding elapsedMillis/Micros out of my project and if i can get this working it'll stay out.. I had been trying to use the TCK64 timer but it acts funny unlike when i try using the GPT or TMR timers.

    I am using the timer callback routine to turn off the screen on an attached OLED screen. I can turn the screen back on by pressing any of the buttons on the project. Sometimes when i push a button when the screen is on the screen turns off and sometimes when the screen is off and i push a button the screen turns back on then instantly turns off again. This doesn't happen with the other hardware timers. I'm not sure if there is any specific thing i am doing wrong with my code or extra measures i need to use with the software timers that i am not employing.

    Cheers

    NM

  14. #339
    Quote Originally Posted by NuttyMonk View Post
    i am looking to use a callback routine instead of polling using elapsedMillis if i can. I've been weeding elapsedMillis/Micros out of my project and if i can get this working it'll stay out.. I had been trying to use the TCK64 timer but it acts funny unlike when i try using the GPT or TMR timers.

    I am using the timer callback routine to turn off the screen on an attached OLED screen. I can turn the screen back on by pressing any of the buttons on the project. Sometimes when i push a button when the screen is on the screen turns off and sometimes when the screen is off and i push a button the screen turns back on then instantly turns off again. This doesn't happen with the other hardware timers. I'm not sure if there is any specific thing i am doing wrong with my code or extra measures i need to use with the software timers that i am not employing.
    I can understand the desire to have timers with callbacks, but it sounds like you may not have all of the necessary logic to stop/start/reset those timers when events occur, such as pushing a button. The timers are nice because your code appears less cluttered, but the complexity is still there, and is maybe harder to get right and to keep right as your design evolves. If you have a state machine or a loop of some sort to manage things at a high level, having a few elapsedMillis objects might not be so bad. The right tool for the job, as they say.

  15. #340
    Quote Originally Posted by joepasquariello View Post
    I can understand the desire to have timers with callbacks, but it sounds like you may not have all of the necessary logic to stop/start/reset those timers when events occur, such as pushing a button. The timers are nice because your code appears less cluttered, but the complexity is still there, and is maybe harder to get right and to keep right as your design evolves. If you have a state machine or a loop of some sort to manage things at a high level, having a few elapsedMillis objects might not be so bad. The right tool for the job, as they say.
    Yeah, been thinking that myself. Oh well, back to the way it was.

    Thanks for your help Joe.

    Cheers

    NM

  16. #341
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    1,849
    Quote Originally Posted by NuttyMonk View Post
    Hi Luni,
    So what is the maximum time for a OneShotTimer on GPT2? I assumed that since the GPT2 timer is 32-bit the maximum value would be 4,294,967,296 but using a time of 900,000 * 1000 = 900,000,000 doesn't seem to work properly. I'm assuming that it is because of the time i am setting in the trigger.
    See here https://github.com/luni64/TeensyTime...m-timer-period for information how to find out the max supported timer period for the various hard/software timers available.
    Here the results for a T4.x @600MHz
    Code:
    TCK:               5.00 seconds
    TCK64:           634.20 years
    TCK_RTC:         634.20 years
    GPT(@24MHz)      178.96 seconds
    TMR(PSC_AUTO)     55.92 milliseconds
    PIT(@24MHz)      178.96 seconds
    ... i am looking to use a callback routine instead of polling using elapsedMillis if i can. I've been weeding elapsedMillis/Micros out of my project and if i can get this working it'll stay out.. I had been trying to use the TCK64 timer but it acts funny unlike when i try using the GPT or TMR timers.
    What exactly do you mean with "acts funny"? I'm always interested in improving my libraries, so, can you post some ideally small code showing the effect? As long as you don't have code which blocks for very long times (seconds) they should work without issues.


    sometimes when i push a button when the screen is on the screen turns off and sometimes when the screen is off and i push a button the screen turns back on then instantly turns off again.
    As joepasquariello also mentioned, this sounds like some general logic issue in your code? Again, if you want me to look into it I'd need some compileable code.

    Yeah, been thinking that myself. Oh well, back to the way it was.
    Actually, simply switching off a screen after a given time does sound like a perfect use case for a oneShot timer. Basically, the TCK versions are doing the same as you would do with polling a elapsedMillis, they are just polling the cycleCounter right before loop is called (actually whenever yield() is called) and invoke your callback when the count is larger than the precalculated target. So, nothing mystical about them.

  17. #342
    Quote Originally Posted by luni View Post
    What exactly do you mean with "acts funny"? I'm always interested in improving my libraries, so, can you post some ideally small code showing the effect? As long as you don't have code which blocks for very long times (seconds) they should work without issues.

    As joepasquariello also mentioned, this sounds like some general logic issue in your code? Again, if you want me to look into it I'd need some compileable code.
    It's probably my code. I have about 3k lines of code and i'm using 5 or 6 timers so i'm probably doing something wrong somewhere. I just went back to elapsedMillis for this as, based on your comments, it seemed to not be any different than using a TCK timer.

    Quote Originally Posted by luni View Post
    Basically, the TCK versions are doing the same as you would do with polling a elapsedMillis, they are just polling the cycleCounter right before loop is called (actually whenever yield() is called) and invoke your callback when the count is larger than the precalculated target.
    What is the yield() you mention here?

    Cheers

    NM

  18. #343
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    16,188
    yield() is the one 'runtime' feature that goes with Arduino.

    When called directly, and called with calls to delay() and on each exit of loop() before it is called again.

    What yield does is check an existing SerialEvent() functions in a non-interrupt fashion in those cases.

    TCK based timers take advantage of yield() being called regularly (when they are and loop doesn't stall where delay and yield are not called) to update timer status and process requested responses.

  19. #344
    Junior Member
    Join Date
    Aug 2022
    Posts
    4
    Quote Originally Posted by luni View Post
    setPeriod changes the period immediately. I.e., it will end the current period and restart the timer with the new period.
    Question: my understanding was that my timer t1 would be reset when setPeriod() is called, but that appears to not work with the FTM timer(s) - or am I doing something wrong?

    Context: I want to re-start a PeriodicTimer (1st channel of FTM1, specifically) any time I detect a rising edge on one of my GPIO lines. These rising edges come once per second, see yellow scope trace.
    I want my periodicTimer (t1) to go through 10 whole cycles (purple trace) of 100 ms each, and neither "lead" nor "lag" the rising edge on the HW input pin (yellow). i.e. they should be "in sync".

    I have set FTM_DEFAULT_PSC to PSC_128 in the defaultConfig.h.

    Code:
    using namespace TeensyTimerTool;
    using namespace std::chrono_literals;
    
    PeriodicTimer t1(FTM1);
    
    constexpr auto period_ms = 50ms;
    
    // some more functions, etc.
    
    void my_hw_interrupt_callback() {
        digitalWriteFast(t1_output_pin, HIGH);  // always start on a rising edge
        t1.setPeriod(period_ms);  // setPeriod causes immediate restart, and sets the specified period (I think?)
            
        count = 0;
        count++;
      }
    
    void my_timer_1_callback() {
        if (count <= 10) {
            bool t1_output_state = digitalReadFast(t1_output_pin);
            if (t1_output_state == HIGH) {
                digitalWriteFast(t1_output_pin, LOW);
              } else {
                digitalWriteFast(t1_output_pin, HIGH);
                count++;  // add to the count each time we output a rising edge
              }
          }
      }
    
    void setup() {
        // some other setup things
    
        t1.begin(my_timer_1_callback, period_ms, true);  // initialize, and start right away
        attachInterrupt(digitalPinToInterrupt(my_hw_interrupt_pin), my_hw_interrupt_callback, RISING);
    }
    
    void loop() {}
    Click image for larger version. 

Name:	not_synced_to_pulse.png 
Views:	7 
Size:	22.4 KB 
ID:	29089
    Last edited by mikeg88; 08-03-2022 at 03:21 AM.

  20. #345
    With a PeriodicTimer, the timer starts when you call begin(), so you could call t1.begin() in the hw_interrupt function instead of in setup(), and then stop the timer after 10 calls to timer_callback(). I think the issue may be that setPeriod(), doesn't stop/restart the timer, but rather sets the period for the *next* period.

  21. #346
    Junior Member
    Join Date
    Aug 2022
    Posts
    4
    Thanks joepasquariello,

    Quote Originally Posted by joepasquariello View Post
    With a PeriodicTimer, the timer starts when you call begin(), so you could call t1.begin() in the hw_interrupt function instead of in setup(), and then stop the timer after 10 calls to timer_callback()
    ...understood, and then I guess the next time the hw_interrupt is triggered, the call to t1.begin() will cause the t1 timer to start from zero again? I'm concerned that t1.begin() might be "slow" (I don't know what it needs to do under the hood to get the timer t1 initialized - maybe it's quick, maybe not ?)

    Quote Originally Posted by joepasquariello View Post
    I think the issue may be that setPeriod(), doesn't stop/restart the timer, but rather sets the period for the *next* period.
    I think setNextPeriod does this

  22. #347
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    1,849
    SetPeriod is supposed to change the period of a running timer, i.e. it is supposed to end the current period and start again with the new period (updatePeriod might have been a better name...)
    SetNextPeriod is supposed to finish the current period and change to the new period after.

    I don't use the FTMs a lot, definitely possible that something is wrong here.I'll have a look later today.

    t1.begin() might be "slow" (I don't know what it needs to do under the hood to get the timer t1 initialized - maybe it's quick, maybe not ?)
    This of course depends on your definition of slow/quick. begin(...) sets up the timer channel and the callback. I don't have a measurment available but I estimate that this should not take more than a small number of microseconds. You can also setup the timer without starting it (set the optional third parameter to false). You can then call its start() method to actually start it. start() only sets some bits in a register and should be as fast as possible.

  23. #348
    Junior Member
    Join Date
    Aug 2022
    Posts
    4
    Hi luni,

    Quote Originally Posted by luni View Post
    SetPeriod is supposed to change the period of a running timer, i.e. it is supposed to end the current period and start again with the new period
    ...when you say "end the current period", does this mean:
    1. wait for the remaining time in the current period to finish, then start again with the new period
    2. don't wait for the remaining time in the current period to finish, start again with the new period immediately

  24. #349
    Quote Originally Posted by mikeg88 View Post
    Hi luni,


    ...when you say "end the current period", does this mean:
    1. wait for the remaining time in the current period to finish, then start again with the new period
    2. don't wait for the remaining time in the current period to finish, start again with the new period immediately
    I checked the source code, and it looks like setPeriod() is not implemented for FTM, so that may explain why that function is not doing what you want. It looks like t1.trigger() will do what you want, i.e. stop the current period and start a new one, so please try replacing t1.setPeriod(period) with t1.trigger().

  25. #350
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    1,849
    Quote Originally Posted by mikeg88 View Post
    Hi luni,
    ...when you say "end the current period", does this mean:
    1. wait for the remaining time in the current period to finish, then start again with the new period
    2. don't wait for the remaining time in the current period to finish, start again with the new period immediately
    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.

    Here some test code which will toggle pin0 every 5ms. After 200ms it changes the toggle period to 1ms. Pin 1 marks the time when the switch happened.
    Code:
    #include "Arduino.h"
    #include "TeensyTimerTool.h"
    using namespace TeensyTimerTool;
    
    PeriodicTimer t1(FTM0);
    
    void setup()
    {
        TeensyTimerTool::attachErrFunc(ErrorHandler(Serial));  // always good to enable error messages when developing
        pinMode(0, OUTPUT);
        pinMode(1, OUTPUT);
    
        while (!Serial) {}
    
        t1.begin([] { digitalToggleFast(0); }, 5ms); // isr just toggles pin 0, start period 5ms
    
        delay(200);
        digitalToggleFast(1);
        t1.setNextPeriod(1ms);
    
        delay(200);
        t1.stop();
    }
    
    void loop()
    {
    }
    Click image for larger version. 

Name:	Screenshot 2022-08-04 075957.jpg 
Views:	3 
Size:	31.0 KB 
ID:	29104

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •