timer interrupt missing a beat

I have code running off timer 2 to control a stepper
works ok most of the time
every now and then it misses a beat
put a scope on it and it confirms
it's almost as if the interrupt doesn't fire

her's the code - blast away
it's meant to increase then decrease the frequency

// stepper pin
//============
#define STEPPIN   12

// avr-libc library includes
//==========================
#include <avr/io.h>
#include <avr/interrupt.h>

// interrupt service routine
//==========================
ISR(TIMER1_COMPA_vect)
{
  // fire the stepper one pulse
  //===========================
  digitalWrite(STEPPIN, HIGH);
  digitalWrite(STEPPIN, LOW);
}

void setup(void)
{
  // set stepper pin as output 
  //==========================
  pinMode(STEPPIN, OUTPUT);
}

void loop(void)
{
  int i;

  for (i=30; i>10; i--)
  {
    // speed up
    //=========
    setTimer(i);
    delay(2000);
  }
  for (i=10; i<30; i++)
  {
    // slow down
    //==========
    setTimer(i);
    delay(2000);
  }
}

void setTimer(int time)
{
  // set up the timer
  //=================
  cli();             

  // set entire TCCR1A, TCCRIB register to 0
  //========================================
  TCCR1A = 0;
  TCCR1B = 0;
   
  // set compare match register to desired timer count
  //==================================================
  OCR1A = time;
  
  // turn on CTC mode:
  //==================
  TCCR1B |= (1 << WGM12);
  
  // Set CS12 bit for prescaler /256
  //================================
  TCCR1B |= (1 << CS12);
  
  // enable timer compare interrupt
  //===============================
  TIMSK1 |= (1 << OCIE1A);
  
  // enable global interrupts
  //=========================
  sei();
}

You seem to only be setting one bit of the counter mode field - you should overwrite them all to ensure you get the mode you think...

Why disabling interrupts when setting up the timer?

er copied from here

I tried setting TIMSK1 to 0 before setting OCTE1A
no difference

TCCR1A and B already cleared

ok the setTimer routine now looks like this, but still has the odd random hiccup

void setTimer(int time)
{
  // set up the timer
  //=================
  cli();             

  // set entire TCCR1A, TCCRIB register to 0
  //========================================
  OCR1A = 0;
  TCCR1A = 0;
  TCCR1B = 0;
  TIMSK1 = 0;
   
  // set compare match register to desired timer count
  //==================================================
  OCR1A = time;
  
  // turn on CTC mode:
  //==================
  TCCR1B |= (1 << WGM12);
  
  // Set CS12 bit for prescaler /256
  //================================
  TCCR1B |= (1 << CS12);
  
  // enable timer compare interrupt
  //===============================
  TIMSK1 |= (1 << OCIE1A);
  
  // enable global interrupts
  //=========================
  sei();
}

You seem to be disabling interrupts briefly ten times a second. Is it any surprise that occasionally you miss an interrupt?

fair point :slight_smile:

ok removed the sei() and cli()
still taking a rest every now and then :frowning:

mmcp42:
ok removed the sei() and cli()
still taking a rest every now and then :frowning:

Could this simply be because you're reconfiguring the timer while it is running? If it's about to fire and you reconfigure it, how long do you wait until it actually fires? It'd be reasonable for it to start timing from zero when you reconfigure it, wouldn't it?

The effect is subtle on the scope, but I think I see what you mean.

I'm inclined to agree with PeterH that changing the timer while it is running is likely to introduce glitches, but it seems to me that they are inside the 2-second intervals.

Timer 2 has a higher interrupt priority than Timer 0, however once Timer 0 fires interrupts will be disabled regardless of interrupt priority. My guess is that this defers your ISR slightly.

This modified version uses the timer itself to toggle the output pin (now D11). This gives a different waveform (so you may have to double the frequency?) but as far as I can see has less glitches:

// stepper pin
//============
#define STEPPIN   11

void setup(void)
{
  // set stepper pin as output 
  //==========================
  pinMode(STEPPIN, OUTPUT);
}

void loop(void)
{
  int i;

  for (i=30; i>10; i--)
  {
    // speed up
    //=========
    setTimer(i);
    delay(2000);
  }
  for (i=10; i<30; i++)
  {
    // slow down
    //==========
    setTimer(i);
    delay(2000);
  }
}

void setTimer(int time)
{
  // set up the timer
  //=================        

  // set entire TCCR1A, TCCRIB register to 0
  //========================================
  OCR1A = 0;
  TCCR1A = 0;
  TCCR1B = 0;
  TIMSK1 = 0;
   
  // set compare match register to desired timer count
  //==================================================
  OCR1A = time;
  
  // turn on CTC mode:
  //==================
  TCCR1B |= (1 << WGM12);
  
  // Set CS12 bit for prescaler /256
  //================================
  TCCR1B |= (1 << CS12);
  

  // toggle D11 on match  
  TCCR2A = _BV (COM2A0);  // toggle OC2A on Compare Match (D11)
    
}

thanks Peter and Nick
i'll glare at the code some more!
(especially TCCR2A)

mmcp42:
I have code running off timer 2 to control a stepper

her's the code - blast away

  // set entire TCCR1A, TCCRIB register to 0

//========================================
  TCCR1A = 0;
  TCCR1B = 0;

Er, isn't that Timer 1?

Modified for Timer 1:

// stepper pin
//============
#define STEPPIN   9

void setup(void)
{
  // set stepper pin as output 
  //==========================
  pinMode(STEPPIN, OUTPUT);
}

void loop(void)
{
  int i;

  for (i=30; i>10; i--)
  {
    // speed up
    //=========
    setTimer(i);
    delay(2000);
  }
  for (i=10; i<30; i++)
  {
    // slow down
    //==========
    setTimer(i);
    delay(2000);
  }
}

void setTimer(int time)
{
  // set up the timer
  //=================        

  // set entire TCCR1A, TCCRIB register to 0
  //========================================
  OCR1A = 0;
  TCCR1A = 0;
  TCCR1B = 0;
  TIMSK1 = 0;
   
  // set compare match register to desired timer count
  //==================================================
  OCR1A = time;
  
  // turn on CTC mode:
  //==================
  TCCR1B |= (1 << WGM12);
  
  // Set CS12 bit for prescaler /256
  //================================
  TCCR1B |= (1 << CS12);

  // toggle D9 on match  
  TCCR1A = _BV (COM1A0);  // toggle OC1A on Compare Match (D9)
    
}

oh my word!
luckily it's only the thread title that's actually wrong

Would it to be feasible to do the timer adjustments within the timer ISR, so that you know they're happening at/about the start of the interrupt period? You would continue to schedule them in loop() and just set a flag/variable to tell the ISR to reconfigure the timer at the next interrupt.

I tried to change the speed by just doing this:

  OCR1A = time;

(and not set up the timer again). But it seems to ignore me. I suspect that the counter limit is cached, but my reading of the datasheet suggests it should be cached in this case. However if you could work around that, that is probably the simpler way.

in the end what I did was went for a much faster (25 microsecond) interrupt
then set a counter
the ISR decrements my counter and fires the stepper when it reaches zero
then pcks up the next value

seems to work glitch free now!

many thanks for all your input
learnt a lot today!