Teensy 4 and TimerOne Issue

tcottle

Well-known member
I'm in the process of converting over one of our products that use the impossible to get Teensy 3.2 to the more available Teensy 4.0. I've turned up a bug in the TimerOne library

I'm running on a Win10 laptop using Visual Studio 2022 (V 17.2.3) and the Visual Micro plugin (latest issue). Arduino 1.8.19 Teensyduino 1.56

Here is the minimum code that shows the issue:

Code:
 #include <TimerOne.h>

volatile long offset = 100; 

void setup()
{
	pinMode(0, OUTPUT);
	digitalWrite(0, LOW);
	Timer1.initialize(1000); // 1mS
	Timer1.attachInterrupt(Timer1_ISR);
	Timer1.start();
}

void loop()
{

}

void Timer1_ISR(void) {
	if (digitalRead(0) == LOW) {
		digitalWrite(0, HIGH);
		Timer1.initialize(offset);
	}
	else {
		digitalWrite(0, LOW);
		Timer1.initialize(1000 - offset);
	}
	Timer1.restart();
}

On a Teensy 3.2 here is the output

Teensy 3.2.png

and on a Teensy 4.0 here is the output. Note that the duty cycle is wrong and the timebase changed

Teensy 4.0.png

and a secondary issue in the Teensy 3.2. The durations are 1/2 of what I expected. I expected a pulse train high for 0.1mS and low for 0.9mS. In my original 3.2 production code I just multiplied by 2 and moved on ...
 
Hi,

I think you are not supposed to call 'initialize' multiple times... This codes seems to work correctly:

Code:
#include <TimerOne.h>

volatile long offset = 100; 

void setup()
{
  pinMode(0, OUTPUT);
  digitalWrite(0, LOW);
  Timer1.initialize(1000); // 1mS
  Timer1.attachInterrupt(Timer1_ISR);
  Timer1.start();
}

void loop()
{

}

void Timer1_ISR(void) {
  if (digitalRead(0) == LOW) {
    digitalWrite(0, HIGH);
    Timer1.setPeriod(offset);
  }
  else {
    digitalWrite(0, LOW);
    Timer1.setPeriod(1000-offset);
  }
  //Timer1.restart();
}
 
It might depend on what your real needs are. If for example you ware simply wanting a simple pulse every MS(1000us) and have the pulse to be about 100us...

You can do that, doing something like:
Code:
void setup() {
  analogWriteResolution(10);
  analogWriteFrequency(0, 1000.0);
  analogWrite(0, 102);
}

void loop() {
  
}
screenshot.jpg
 
Vindar and Kurt - Thanks! I made the changes that Vindar recommended. Curiously the waveform is inverted(!) and the timing is different between the 3.2 and 4.0. At least the periods are correct for the 4.0

The blue trace is the 4.0 and the yellow is the 3.2. They are not synched so the edges do not line up

RigolDS2.png

In TimerOne.h, the initialize method is an alias for setPeriod with a default value of 1S. Likewise restart is an alias of start

The start method also calls stop() so it looks like the correct way of using the timer is to load in your desired period via intialize/setPeriod and then call start/resume if you want the change to implement immediately (before the timer counts down to zero and reloads).
 

Attachments

  • RigolDS0.png
    RigolDS0.png
    64.1 KB · Views: 101
  • RigolDS1.png
    RigolDS1.png
    81.7 KB · Views: 106
You are welcome.

Glad you are getting it to work.

If it were me, I personally wonder about using Timer1 unless I was also wanting to use this on other boards like Arduino UNO as I believe this library was setup primarily for ATMega based processors.

But again don't know your requirements. So hard to give specific suggestions.

For simple outputs of fixed pulses or the like, without needing/wanting to process interrupts and the like, PWM can work well for this.
https://www.pjrc.com/teensy/td_pulse.html

For Simple Timers, I would tend to use the IntervalTimer: Lots of forum threads on this also: https://www.pjrc.com/teensy/td_timing_IntervalTimer.html

Or for more advanced things @luni has created a very nice library: https://github.com/luni64/TeensyTimerTool

Good luck
 
Last edited:
Yeah I came to the same conclusion. IntervalTimer seems to be a better library. At least it give the same results over the different Teensy models :D
 
I had a related issue. I'm working on a project using Teensy 4.1. Among other features, it includes a 4 inch 480x320 SPI display with PWM backligght control. Pin 25 was used for this purpose. But TimerOne screwed-up PWM output. Duty cycle was half the expected one: when I analog-wrote 255, duty cycle was 50%. It wasn't possible to get more than 50% duty cycle (analog-writing 511 resulted in 50% duty cycle, too). And PWM frequency changed. Switching to IntervalTimer cured the issue.
 
Just for the records, some images. Oscilloscope screen capture after analog-writing 230 to pin 25. All normal.

tek0214.png
 
Back
Top