Help with Timer Interrupt

Status
Not open for further replies.

GOB

Active member
Hi Folks,

I am trying to implement a timer interrupt and I am having trouble getting started.

I am trying TimerOne and TimerThree from here:

https://www.pjrc.com/teensy/td_libs_TimerOne.html

on a teensy 3.1 .

A question:


When I run the TimerOne interrupt example

Code:
#include <TimerOne.h>

// This example uses the timer interrupt to blink an LED
// and also demonstrates how to share a variable between
// the interrupt and the main program.

const int led = LED_BUILTIN;  // the pin with a LED

void setup(void)
{
  pinMode(led, OUTPUT);
  Timer1.initialize(150000);
  Timer1.attachInterrupt(blinkLED); // blinkLED to run every 0.15 seconds
  Serial.begin(9600);
}


// The interrupt will blink the LED, and keep
// track of how many times it has blinked.
int ledState = LOW;
volatile unsigned long blinkCount = 0; // use volatile for shared variables

void blinkLED(void)
{
  if (ledState == LOW) {
    ledState = HIGH;
    blinkCount = blinkCount + 1;  // increase when LED turns on
  } else {
    ledState = LOW;
  }
  digitalWrite(led, ledState);
}


// The main program will print the blink count
// to the Arduino Serial Monitor
void loop(void)
{
  unsigned long blinkCopy;  // holds a copy of the blinkCount

  // to read a variable which the interrupt code writes, we
  // must temporarily disable interrupts, to be sure it will
  // not change while we are reading.  To minimize the time
  // with interrupts off, just quickly make a copy, and then
  // use the copy while allowing the interrupt to keep working.
  noInterrupts();
  blinkCopy = blinkCount;
  interrupts();

  Serial.print("blinkCount = ");
  Serial.println(blinkCopy);
  delay(100);
}

even when I change the value set in

Timer1.initialize(150000);

I can't get the blink interval of the LED to change - If I want an interval of say, 1 sec, I change the value to

Timer1.initialize(1000000);

but the LED still blinks fast.

When I look in the serial monitor, I see that blink count gets repeated a number of times before incrementing (Edit: now I understand this is just related to the delay length in the main loop and how that relates to the frequency of the interrupt)

Thanks for all your help, much appreciated!
 
Last edited:
I know you copied the example as is, but isn't delay(100) too short considering the timer interrupts every 150ms? Maybe change that to delay(500)?
 
Thanks for the reply, doughboy - but I don't think that is it. When I change that delay it basically just affects how many times the "blinkcount" gets reported per blink. Thanks though.
 
right, and that was the point, don't you think updating every 100ms is too excessive?
if the blink time is not changing when you change the program, make sure the new program is actually uploaded.
or rather than using TimerOne/Three library, just use IntervalTimer, I think it is better.
 
Yeah, I can't get the LED to blink more slowly is the issue. Pretty sure that it is uploaded as all other changes I make (i.e. different Serial.println for debugging) take effect.

Thanks again.
 
doughboy is correct - your code is doing what you tell it to.

Make a COPY2 of the blink count and don't reprint the count unless copy and copy2 are different. When you print count - also update copy2

Then you can take out you delay altogether. [unless you need an overt delay() they often lead to issues now or later and are best avoided]

This will print ONCE per change - no matter how slowly the timer fires - or fast down to the speed of the Loop&USB speed.
 
Update code sample to include something like this
Code:
unsigned long blinkCopy2 = 0; // use for tracking change

void loop(void)
{
  unsigned long blinkCopy;  // holds a copy of the blinkCount

  noInterrupts();
  blinkCopy = blinkCount;
  interrupts();

  if ( blinkCopy != blinkCopy2 )
{
  blinkCopy2 = blinkCopy;
  Serial.print("blinkCount = ");
  Serial.println(blinkCopy);
}
}

This will toggle interrupts OFF a lot - which is not ideal.

Does VOLATILE void the need for taking the interrupts down?
 
Last edited:
I see what GOB is seeing...I can't get the LED to pulse slower than 358ms when Timer1.intialize(358000). Anything above 358000, the period remains 358ms, while below that the period is correct.
 
Hi folks, thanks for all the replies.

defragster -- I don't really care about the blinkcount, I understand how that works. The issue is just as whodaguy is having, getting the LED to pulse more slowly.

Could it have something to do with processor speed?

I am using IntervalTimer now and that is working.
 
ok, now I see. The magic keyword here is it does not work past 358ms.

If you look at the code of TimerOne, that is the limit.
I think if FBUS is 48mhz, then the limit is 349525us.
I think the TimeOne library page should mention this and to suggest to use IntervalTimer if interval > this value is needed.

Code:
const unsigned long cycles = (F_BUS / 2000000) * microseconds;
	if (cycles < TIMER1_RESOLUTION) {
		clockSelectBits = 0;
		pwmPeriod = cycles;
	} else
	if (cycles < TIMER1_RESOLUTION * 2) {
		clockSelectBits = 1;
		pwmPeriod = cycles >> 1;
	} else
	if (cycles < TIMER1_RESOLUTION * 4) {
		clockSelectBits = 2;
		pwmPeriod = cycles >> 2;
	} else
	if (cycles < TIMER1_RESOLUTION * 8) {
		clockSelectBits = 3;
		pwmPeriod = cycles >> 3;
	} else
	if (cycles < TIMER1_RESOLUTION * 16) {
		clockSelectBits = 4;
		pwmPeriod = cycles >> 4;
	} else
	if (cycles < TIMER1_RESOLUTION * 32) {
		clockSelectBits = 5;
		pwmPeriod = cycles >> 5;
	} else
	if (cycles < TIMER1_RESOLUTION * 64) {
		clockSelectBits = 6;
		pwmPeriod = cycles >> 6;
	} else
	if (cycles < TIMER1_RESOLUTION * 128) {
		clockSelectBits = 7;
		pwmPeriod = cycles >> 7;
	} else {
		clockSelectBits = 7;
		pwmPeriod = TIMER1_RESOLUTION - 1;
	}

use IntervalTimer instead,
 
Last edited:
My bad for misreading - when I ran that sample (some weeks ago) I saw it working as expected - but only counting blinks by eye.

<edit>: I coded a version to read the elapsed micros indeed it stops at : 349519-349520

And indeed rewriting with IntervalTimer is a good solution
 
Last edited:
I let the interrupts run (no off_on) with my T_3.1 and not detecting an issue with the interval timer at 1000us.

Had to slow the USB print down to now and then - as somewhere under 20,000us it can't keep up and goes offline.
 
Ok, the correct value of the limit is 349520. I incorrectly used 65526 in my previous calculation. It should be 65535.

cycles = micros * FBUS/2000000 = micros * 24;

limit is cycles = 65535 * 128 = micros * 24
solve for micros = 65535*128/24 = 349520
 
Status
Not open for further replies.
Back
Top