Go Down

Topic: timer interrupt missing a beat (Read 1 time) previous topic - next topic

mmcp42

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
Code: [Select]

// 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();
}
there are only 10 types of people
them that understands binary
and them that doesn't

MarkT

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?
[ I won't respond to messages, use the forum please ]

mmcp42

#2
Feb 04, 2012, 02:27 pm Last Edit: Feb 04, 2012, 02:30 pm by mmcp42 Reason: 1
er copied from here

I tried setting TIMSK1 to 0 before setting OCTE1A
no difference

TCCR1A and B already cleared
there are only 10 types of people
them that understands binary
and them that doesn't

mmcp42

ok the setTimer routine now looks like this, but still has the odd random hiccup
Code: [Select]

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();
}
there are only 10 types of people
them that understands binary
and them that doesn't

PeterH

You seem to be disabling interrupts briefly ten times a second. Is it any surprise that occasionally you miss an interrupt?
I only provide help via the forum - please do not contact me for private consultancy.

mmcp42

there are only 10 types of people
them that understands binary
and them that doesn't

mmcp42

ok removed the sei() and cli()
still taking a rest every now and then :(
there are only 10 types of people
them that understands binary
and them that doesn't

PeterH


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


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?
I only provide help via the forum - please do not contact me for private consultancy.

Nick Gammon

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:

Code: [Select]
// 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)
   
}
http://www.gammon.com.au/electronics

mmcp42

thanks Peter and Nick
i'll glare at the code some more!
(especially TCCR2A)
there are only 10 types of people
them that understands binary
and them that doesn't

Nick Gammon


I have code running off timer 2 to control a stepper

her's the code - blast away

Code: [Select]

  // set entire TCCR1A, TCCRIB register to 0
  //========================================
  TCCR1A = 0;
  TCCR1B = 0;
   



Er, isn't that Timer 1?

Modified for Timer 1:

Code: [Select]
// 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)
   
}
http://www.gammon.com.au/electronics

mmcp42

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

there are only 10 types of people
them that understands binary
and them that doesn't

PeterH

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 only provide help via the forum - please do not contact me for private consultancy.

Nick Gammon

I tried to change the speed by just doing this:

Code: [Select]
  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.
http://www.gammon.com.au/electronics

mmcp42

#14
Feb 04, 2012, 09:37 pm Last Edit: Feb 04, 2012, 09:47 pm by mmcp42 Reason: 1
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!
there are only 10 types of people
them that understands binary
and them that doesn't

Go Up