0

I'm trying to use Timer1 to get fired once a certain event occurs (about 1ms after the event). Using the timer to get a periodic interrupt works fine, but the very first interrupt fires immediately, rather than after the time I want it.

#include <Arduino.h>

void setup() {
  Serial.begin(115200);
  Serial.println("start");
}

#define ENTRIES 5
long stack[ENTRIES+1];
int ctr = 0;

ISR(TIMER1_OVF_vect) {
  cli();
  TCNT1 = 50000;

  // if (micros() - stack[0] < 500) return; // work around guard would skip stray 1st interrupt

  stack[ctr++] = micros();

  if (ctr > ENTRIES)
    TIMSK1 &= ~(1 << TOIE1);

  sei();
}

void loop() {
  if (ctr > ENTRIES) {
    for (int i = 0; i < ENTRIES-1; i++) {
      Serial.print(i);
      Serial.print(": ");
      Serial.println(stack[i+1] - stack[i]);
    }
    ctr = 0;
  }

  if (!Serial.available()) return;
  char c = Serial.read();
  if (c == 't') {
    Serial.println("testing");

    stack[0] = micros();
    ctr = 1;
    cli(); 

    TCNT1 = 64000; // tick in around 1ms
    TCCR1A = 0;
    TCCR1B = (1 << CS10); // no prescaler
    TIMSK1 |= (1 << TOIE1); // enable timer overflow interrupt

    sei();
  }
}

When you enter t on the console it enables the interrupt and - unexpectedly - the timer fires at once. The next one comes after 1ms. A sample output looks like

start
testing
0: 8
1: 980
2: 980
3: 980
testing
0: 8
1: 980
2: 980
3: 980

Uncommenting the guard yields

start
testing
0: 988
1: 972
2: 976
3: 976

How can I modify my code (except setting a guard in the beginning of the ISR) so it is triggered once AFTER 1ms.

1

Interrupt flags are set even without interrupt enable flags, so there is pending overflow that you didin't cleared. And guess what happens after enabling TOIE1 flag. It gets handled by ISR. That's on behalf of Arduino's analogWrite() PWM outputs (all timers are up and running in 8bit mode and 1.024ms period).

Btw global interrupts are disabled and reenabled inside of ISR handler by hardware so you shouldn't have cli() and sei() in it.

Also there is another issue - counter mode is preset to 8bits and much bigger prescaler, so the first round is way off.

void setup() {
  Serial.begin(115200);
  Serial.println("start");
}

#define ENTRIES 5
long stack[ENTRIES+1];
int ctr = 0;

ISR(TIMER1_OVF_vect) {
  TCNT1 = 50000U;
  stack[ctr++] = micros();
  if (ctr > ENTRIES)  TIMSK1 &= ~(1 << TOIE1);
}

void loop() {
  if (ctr > ENTRIES) {
    for (int i = 0; i < ENTRIES-1; i++) {
      Serial.print(i);
      Serial.print(": ");
      Serial.println(stack[i+1] - stack[i]);
    }
    ctr = 0;
  }

  if (!Serial.available()) return;
  char c = Serial.read();
  if (c == 't') {
    Serial.println("testing");

    stack[0] = micros();
    ctr = 1;

    TCCR1A = 0;           // you have to change the timer mode before changes
    TCCR1B = 0;           // stop the timer
    TIFR1 |= _BV(TOV1);   // clear the overflow interrupt flag by writing 1 to it
    TCNT1  = 50000U;      // tick in around 1ms / this makes more sense if it's set correctly
    TCCR1B = _BV(CS10);   // no prescaler ?????  REALLY???? this one is prescale by 8
    TIMSK1 |= _BV(TOIE1); // enable timer overflow interrupt
  }
}
  • That looks like a live saver :-) Too tired now, but will check this tomorrow! Thanks – qwerty_so Dec 2 '17 at 22:07
  • That got me wake and it's exactly what I was looking for. Thanks also for the info about the interrupt handling :-) – qwerty_so Dec 2 '17 at 22:53
  • Ah, and one remark about the remark: The compiler knows that TCNT1 is an unsigned and will coerce literal numbers correctly. So TCNT1 = 50000; works as well. – qwerty_so Dec 2 '17 at 22:57
  • @thomaskilian it wasn't about signess. More likely about previous setting by Arduino. You were using the value 64000. Anyway it's better to use unsigned literals especially for bit shifts. – KIIV Dec 2 '17 at 23:09
  • 64000 < 64k = 64512 – qwerty_so Dec 2 '17 at 23:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.