Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 12 of 12

Thread: Shift with a timer

  1. #1

    Shift with a timer

    Hi,
    I am writing a program with a timer wich will be variable in time. For instance, I am testing the way to change the timer count directly by writing to GPT1_OCR1 with a constant time (100ms), but I have a slow shift and I don't understand why. I have tried with 2400000-1, but it's the same.

    Code:
    #include "TeensyTimerTool.h"
    using namespace TeensyTimerTool;
    
    PeriodicTimer myTimer(GPT1);
      unsigned long compteur;
    
    void printCurrentTime(){
      GPT1_OCR1=2400000;
        Serial.printf("Called at: %d\n", micros());
        digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN));
    //  compteur=compteur+120000;
    }
    
    void setup(){
        pinMode(LED_BUILTIN,OUTPUT);
        compteur=2400000;
      myTimer.begin(printCurrentTime, 100ms, false);
      GPT1_OCR1=compteur;
        myTimer.start();
    }
    
    void loop(){
    }
    with the serial monitor, I get this:
    Called at: 400005
    Called at: 500005
    Called at: 600005
    Called at: 700006
    Called at: 800006
    Called at: 900007
    Called at: 1000007
    Called at: 1100008
    Called at: 1200008
    Called at: 1300008
    Called at: 1400009
    Called at: 1500009
    Called at: 1600010
    Called at: 1700010
    Called at: 1800010
    Called at: 1900011

    Thanks for your help
    Michel

  2. #2
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,687
    You shouldn't reset the timer register. Let the library take care of the details.
    Code:
    //  GPT1_OCR1=2400000;
    It will still drift but nowhere near as fast as before.

    Pete

  3. #3
    Is it possible to avoid this drift?

  4. #4
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,687
    This seems to avoid the drift.
    Code:
    #include "TeensyTimerTool.h"
    using namespace TeensyTimerTool;
    
    PeriodicTimer myTimer;
    
    void printCurrentTime()
    {
      Serial.printf("Called at: %d\n", micros());
      digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN));
    }
    
    void setup()
    {
      pinMode(LED_BUILTIN,OUTPUT);
      myTimer.begin(printCurrentTime, 100ms, false);
      myTimer.start();
    }
    
    void loop()
    {
    }
    Pete

  5. #5
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    1,504
    Just did the same :-) Can't observe any drift.

    Edit: looks like you started fiddling around with the register to set a new period while the timer runs? Since the requests for this feature somehow piled up recently I'll implement this asap.

  6. #6
    I have no drift too with your program, but my goal is to control a microstep motor, and to be able to change the speeds every 1s, during a quite long time (several hours), so if I lose some cycle every second, at the end the error could be non negligible. With my previous UNO32 cards, I changed the timer every interrupt (in general around 10ms), and I never lost any cycle. I don't understand very well where is the problem, because when the interrupt arrived it's because the timer counter is zero, so without a stop of the timer, I just change the limit for the next interrupt. Which is important is that time to change the limit is under 1/24000000s, with a clock of 600MhZ, it should not be a problem. I am scratching my head !!!!
    Michel

  7. #7
    I have got a good result with no apparent drift with this code, but why 10 cycles are lost!? It's not the serial.printf because the change of the timer counter is made before.


    Code:
    #include "TeensyTimerTool.h"
    using namespace TeensyTimerTool;
    
    PeriodicTimer myTimer(GPT1);
      unsigned long compteur;
    
    void printCurrentTime(){
      GPT1_OCR1=2400000-10;
        Serial.printf("Called at: %d\n", micros());
        digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN));
    //  compteur=compteur+120000;
    }
    
    void setup(){
        pinMode(LED_BUILTIN,OUTPUT);
        compteur=2400000;
      myTimer.begin(printCurrentTime, 100ms, false);
      GPT1_OCR1=compteur;
        myTimer.start();
    }
    
    void loop(){
    }

  8. #8
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    1,504
    Quote Originally Posted by michastro View Post
    I have got a good result with no apparent drift with this code, but why 10 cycles are lost!?
    Setting the OCR1 register of the GPT timer will reset its counter.

    52.7.5 GPT Output Compare Register 1 (GPTx_OCR1)
    The GPT Compare Register 1 (GPT_OCR1) holds the value that determines when a
    compare event will be generated on Output Compare Channel 1. Any write access to the
    Compare register of Channel 1 while in Restart mode (FRR=0) will reset the GPT
    counter.
    If you set the counter in the OCR-ISR the actual period will be prolonged by the time it takes from the OCR1 event to the code which resets the OCR register. This time will depend on clock frequency and might be influenced by higher priority interrupts.

    It is much better to only change the register if needed. Then only one period has the wrong (slightly longer) value. The PIT timers allow changing the period without resetting the timer (see chap. 53.5.1.1 in the ref manual)

  9. #9
    Hi,
    I have tried with PIT timer, and it's working perfectly, NO DRIFT. Only one problem, I have tried to replace PIT_LDVAL0=2400000-1 with PIT_LDVAL0=compteur, and it doesn't work, I am sure it's a stupid error but I can't see it.

    Code:
    #include "TeensyTimerTool.h"
    using namespace TeensyTimerTool;
    
    PeriodicTimer myTimer(PIT);
      unsigned long compteur;
    
    void printCurrentTime(){
     PIT_LDVAL0=2400000-1;
        Serial.printf("Called at: %d\n", micros());
        digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN));
    }
    
    void setup(){
        pinMode(LED_BUILTIN,OUTPUT);
        compteur=2400000-1;
      myTimer.begin(printCurrentTime, 400ms, false);
        myTimer.start();
    }
    
    void loop(){
    }

  10. #10
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    1,504
    What do you mean by "doesn't work"? Works here without issue.

    I did a few changes to your code to make it easier to analyze results:

    Code:
    #include "Arduino.h"
    #include "TeensyTimerTool.h"
    using namespace TeensyTimerTool;
    
    PeriodicTimer myTimer(PIT);
    uint32_t compteur;
    
    void printCurrentTime()
    {
        static uint32_t t0 = micros();
        PIT_LDVAL0 = compteur;
        Serial.printf("Called at: %.2f\n", (micros()-t0)/1000.0f);
        digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN));
    }
    
    void setup()
    {
        pinMode(LED_BUILTIN, OUTPUT);
        compteur = 24 * 250'000 - 1;  // 250ms
        myTimer.begin(printCurrentTime, 400ms, false);
        myTimer.start();
    }
    
    void loop()
    {
    }
    This prints:
    Code:
    Called at: 0.00
    Called at: 400.00
    Called at: 650.00
    Called at: 900.00
    Called at: 1150.00
    Called at: 1400.00
    Called at: 1650.00
    Called at: 1900.00
    Called at: 2150.00
    Called at: 2400.00
    Called at: 2650.00
    As you see, the first interval is 400ms, the following intervals are 250ms long as intended.

  11. #11
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    1,504
    ... and since you seem to like the std::chrono literals (e.g. ms, s, etc), here a version showing how to set the reload value directly in time units. BTW: calculation of timer ticks is done at compile time...

    Code:
    #include "TeensyTimerTool.h"
    using namespace TeensyTimerTool;
    
    using pit_ticks = duration<uint32_t, std::ratio<1, 24'000'000>>;  // typedef a new duration type which measures time in PIT ticks (1/24MHz)
    
    PeriodicTimer myTimer(PIT);
    pit_ticks compteur;
    
    void printCurrentTime()
    {
        static uint32_t t0 = micros();
    
        PIT_LDVAL0 = compteur.count()-1;
        Serial.printf("Called at: %.2f\n", (micros() - t0) / 1000.0f);
        digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN));
    }
    
    void setup()
    {
        pinMode(LED_BUILTIN, OUTPUT);
        compteur = 250ms;
    
        myTimer.begin(printCurrentTime, 400ms, false);
        myTimer.start();
    }
    
    void loop()
    {
    }

  12. #12
    Thanks for your answer, the reason of my problem was compteur unssigned long and not uint32_t, I am stupid.
    Thanks again
    Michel

Posting Permissions

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