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

Thread: TimerOne: interval is half the value after start() on Teensy 3.6

  1. #1
    Junior Member
    Join Date
    May 2021
    Posts
    16

    TimerOne: interval is half the value after start() on Teensy 3.6

    I'm trying to change the period for TimerOne, but the interval after start() is half the specified period.

    In the following code, I ask for a period of 1000 microseconds, but get pulses every 500 microseconds. The problem goes away if I remove the stop/setPeriod/start from the handler, and exists if I just have the start.

    Expected behavior: the start() call in timerInterrupt should start the interval at the beginning.

    Do I need to do something different to start the timer from the beginning of the interval?

    Code:
    #include <TimerOne.h>
    
    #define PIN_DEBUG 6
    
    void timerInterrupt() {
      Timer1.stop();
      Timer1.setPeriod(1000);
      Timer1.start();
      digitalWrite(PIN_DEBUG, HIGH);
      digitalWrite(PIN_DEBUG, LOW);
    }
    
    void setup() {
      pinMode(PIN_DEBUG, OUTPUT);
      Timer1.initialize(1000);
      Timer1.attachInterrupt(timerInterrupt);
      Timer1.start();
    }
    
    void loop() {
    }
    (My ultimate goal is to read serial data from an input, using timer interrupts to sample the data in the middle of a pulse, and restarting the timing on a signal edge. But the time intervals are half of what I specify. The code above is simplified to show the problem, so it's not actually useful.)

  2. #2
    Junior Member
    Join Date
    May 2021
    Posts
    16

    TimerOne: interval is half the value after start() on Teensy 3.6

    I did some investigation, and here's a slightly simpler version that illustrates my problem.
    Summary: The first timer interrupt after start() happens at half the specified interval.
    Expected behavior: Timer interrupts every 1000 microseconds as specified. Pulses on pin 6 every 1000 microseconds
    Observed behavior: Looking at the oscilloscope, the first gap between pulses is 500 microseconds, but the following are 1000 microseconds.
    Underlying cause: the timer uses CPWMS mode, which counts the timer up and down. The first interrupt fires after going up, while subsequent cycles go down and then up which takes twice as long.

    This seems like a bug to me. Is there an alternative way to get a timer interrupt after 1000 microseconds?

    Code:
    #include <TimerOne.h>
    
    #define PIN_DEBUG 6
    
    void timerInterrupt() {
      digitalWrite(PIN_DEBUG, HIGH);
      delayMicroseconds(50); // Small delay so the pulse shows up on the oscilloscope
      digitalWrite(PIN_DEBUG, LOW);
    }
    
    void setup() {
      pinMode(PIN_DEBUG, OUTPUT);
      Timer1.initialize(1000); // Timer should fire every 1000 microseconds
      Timer1.attachInterrupt(timerInterrupt);
      digitalWrite(PIN_DEBUG, HIGH); // Pulse to indicate the timer start time.
      delayMicroseconds(50);
      digitalWrite(PIN_DEBUG, LOW);
      Timer1.start();
    }
    
    void loop() {}

  3. #3
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    1,850
    TimerOne is a compatibility wrapper around the native IntervalTimer. So, unless you need to write code compatible to AVR you'd be better of with an IntervalTimer. This code generates a 50Ás pulse every 1000Ás:

    Code:
    constexpr int PIN_DEBUG = 6;
    
    void timerInterrupt()
    {
        digitalWriteFast(PIN_DEBUG, HIGH);
        delayMicroseconds(50); // Small delay so the pulse shows up on the oscilloscope
        digitalWriteFast(PIN_DEBUG, LOW);
    }
    
    IntervalTimer t;
    
    void setup()
    {
        pinMode(PIN_DEBUG, OUTPUT);
    
    
        digitalWriteFast(PIN_DEBUG, HIGH); // Pulse to indicate the timer start time.
        delayMicroseconds(50);
        digitalWriteFast(PIN_DEBUG, LOW);
    
        t.begin(timerInterrupt, 1000);
    }
    
    void loop() {}
    (My ultimate goal is to read serial data from an input, using timer interrupts to sample the data in the middle of a pulse, and restarting the timing on a signal edge. But the time intervals are half of what I specify. The code above is simplified to show the problem, so it's not actually useful.)
    You might be interested to use the TeensyTimerTool for this. Here an example which generates a 50Ás pulse 1ms after a rising edge on the signal input pin. For testing it generates a 100Hz signal on pin 0. I connected this pin to the signal pin.

    Code:
    #include "TeensyTimerTool.h"
    using namespace TeensyTimerTool;
    
    constexpr unsigned pin_debug  = 6;
    constexpr unsigned pin_signal = 14;
    
    OneShotTimer timer(TCK); // use a software timer (TCK) here, to avoid the usual interrupt difficulties.
    
    void onTimer()
    {
        digitalWriteFast(pin_debug, HIGH);
        delayMicroseconds(50); // Small delay so the pulse shows up on the oscilloscope
        digitalWriteFast(pin_debug, LOW);
    
       // do your stuff here
    }
    
    void onEdgeReceived()
    {
        timer.trigger(1000); // trigger the one shot timer whenever you detect an edge on pin_signal
    }
    
    void setup()
    {
        pinMode(pin_debug, OUTPUT);
        pinMode(pin_signal, INPUT_PULLDOWN);
        pinMode(0, OUTPUT);
    
        timer.begin(onTimer);                               // intialize timer and attach the onTimer callback to it
        attachInterrupt(pin_signal, onEdgeReceived, RISING); // call onEdgeReceived on a rising edge on pin_signal
    
        // for testing only
        analogWriteFrequency(0, 100); // generate a 10Hz signal on pin 0, connect to pin_signal for testing
        analogWrite(0, 128);
    }
    
    void loop()
    {
    }
    LA Output:

    Click image for larger version. 

Name:	Screenshot 2022-04-05 082054.jpg 
Views:	7 
Size:	29.5 KB 
ID:	28017

    Hope I understood your goal correctly....

  4. #4
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    16,214
    Quote Originally Posted by luni View Post
    TimerOne is a compatibility wrapper around the native IntervalTimer. So, unless you need to write code compatible to AVR you'd be better of with an IntervalTimer. This code generates a 50Ás pulse every 1000Ás:

    ....
    Good point @luni - that explains why the code looks as it does.

    Plugged this in to the StaticTrace (posted on another thread) versus the TimerOne version and it is much more accurate using the same cycle counter tracking.

    Timer1 indeed had a bad first interval and all after that were 16 cycles too long.

    Swapping in the IntervalTimer most always hits right on 600,000 cycles. The first is 5 or 6 cycles short - but the init setting of 'last cycle count' for diff at the start could account for that - and rare instances showing - or + 6 cycles on the count.

  5. #5
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    1,850
    I had a look at TimerOne, actually it uses an FTM Timer, not an IntervalTimer under the hood. Anyway, the Intervaltimer seems to be a better fit.

  6. #6
    Junior Member
    Join Date
    May 2021
    Posts
    16
    Thank you luni and defragster for your detailed replies! I opened a bug to track this: https://github.com/PaulStoffregen/TimerOne/issues/55

Posting Permissions

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