Pages: [1]   Go Down
Author Topic: timer interrupt missing a beat  (Read 866 times)
0 Members and 1 Guest are viewing this topic.
Leighton Buzzard, UK
Offline Offline
Edison Member
*
Karma: 21
Posts: 1339
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
// 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();
}
Logged

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

0
Offline Offline
Shannon Member
****
Karma: 200
Posts: 11694
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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?
Logged

[ I won't respond to messages, use the forum please ]

Leighton Buzzard, UK
Offline Offline
Edison Member
*
Karma: 21
Posts: 1339
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

er copied from here

I tried setting TIMSK1 to 0 before setting OCTE1A
no difference

TCCR1A and B already cleared
« Last Edit: February 04, 2012, 08:30:42 am by mmcp42 » Logged

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

Leighton Buzzard, UK
Offline Offline
Edison Member
*
Karma: 21
Posts: 1339
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

ok the setTimer routine now looks like this, but still has the odd random hiccup
Code:
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();
}
Logged

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

UK
Offline Offline
Shannon Member
****
Karma: 222
Posts: 12549
-
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

I only provide help via the forum - please do not contact me for private consultancy.

Leighton Buzzard, UK
Offline Offline
Edison Member
*
Karma: 21
Posts: 1339
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

fair point smiley
Logged

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

Leighton Buzzard, UK
Offline Offline
Edison Member
*
Karma: 21
Posts: 1339
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

ok removed the sei() and cli()
still taking a rest every now and then smiley-sad
Logged

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

UK
Offline Offline
Shannon Member
****
Karma: 222
Posts: 12549
-
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

ok removed the sei() and cli()
still taking a rest every now and then smiley-sad

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?
Logged

I only provide help via the forum - please do not contact me for private consultancy.

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
// 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)
   
}
Logged

Leighton Buzzard, UK
Offline Offline
Edison Member
*
Karma: 21
Posts: 1339
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

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

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I have code running off timer 2 to control a stepper

her's the code - blast away

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

Er, isn't that Timer 1?

Modified for Timer 1:

Code:
// 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)
   
}
Logged

Leighton Buzzard, UK
Offline Offline
Edison Member
*
Karma: 21
Posts: 1339
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Logged

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

UK
Offline Offline
Shannon Member
****
Karma: 222
Posts: 12549
-
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

I only provide help via the forum - please do not contact me for private consultancy.

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I tried to change the speed by just doing this:

Code:
  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.
Logged

Leighton Buzzard, UK
Offline Offline
Edison Member
*
Karma: 21
Posts: 1339
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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!
« Last Edit: February 04, 2012, 03:47:52 pm by mmcp42 » Logged

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

Pages: [1]   Go Up
Jump to: