Shift with a timer

Status
Not open for further replies.

michastro

Member
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
 
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
 
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
 
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.
 
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
 
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(){
}
 
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)
 
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(){
}
 
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.
 
... 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()
{
}
 
Thanks for your answer, the reason of my problem was compteur unssigned long and not uint32_t, I am stupid.
Thanks again
Michel
 
Status
Not open for further replies.
Back
Top