Stumped by Interrupt code

This is a problem of my own, but coincidentally I just noticed Dingbat’s post and this may help him
I want to sync my 1mSec interrupts (which work fine have used similar code before) to the 10mSec main period. I have got nice clean pulses every 10mSec into pin2.
I can’t quite see why this does not work (erratic and extra pulses as the LED flashes slightly faster)
Removing the interrupt source allows normal operation.
The code should work by making the ext interrupt the 10th pulse which would otherwise be provided by the timer interrupt albeit with a slightly increased period. This occurs only once after a power failure
Any ideas, anyone?

/* REAL TIME CLOCK WITH PROGRMMABLE TWO CHANNEL SWITCHING
// ------------------------------------------------------
5 digit comm anode LED display
10 pushbuttons for input
1 interrupt input 100Hz
DS1302 RTC for backup time keeping only. Normal time keeping synced to mains for long term accuracy
2 channel relay outputs.

Platform: Arduino pro Mini 16MHz
IDE: Arduino 0021
V0.1 Nov 14 2010 Set up timer2 interrupt at 1mS and extenal interrupt every 10mS.

*/
//--------------------------------------------------------------------------------------------
#include <EEPROM.h>
volatile byte intrptCounter;
volatile int flashCounter;
volatile boolean mainsFailFlag=0;
boolean ledState=1;

#define testLed 13
void setup(){
//set up timer 2 control registers here
OCR2A = 125; //initialise compare register for first interrupt
TCCR2A = B00000000; //select Normal Mode,freerunning counter, no connection to hardware pins
TCCR2B = B00000101; //normal, prescaler equals clock/128. With 16Mhz clock this gives an 8uSec clock to the TCNT2
TIMSK2 = B00000010; //generate interrupt on output compare match A
pinMode(testLed,OUTPUT);
pinMode(12,OUTPUT);
attachInterrupt(0,mainsInterrupt,RISING); // makes digital pin 2 trigger an interrupt
//Serial.begin(19200);
}
// ------------------ end of setup ------------------
void mainsInterrupt() {
TCNT2=0; // resync timer to mains interrupt
OCR2A =125;
intrptCounter=0;
mainsFailFlag=0;
flashCounter +=1;

}
// ----------- end of external interrupt ------------
ISR (TIMER2_COMPA_vect){

intrptCounter+=1; // will normally only reach 9 and is set to zero by mainsInterrupt function
if (intrptCounter>9){
mainsFailFlag=1;
}
if (intrptCounter==9 && mainsFailFlag== 0){
OCR2A +=150; //this would generate a 1.2 mSec interrupt if mains interrupt does NOT occur

}
else{
OCR2A +=125; //this generate a 1mSec interrupt for all interrupts except where external mains interrupt is expected.
}
flashCounter +=1;
//Serial.print(flashCounter);
}
// --------------- end timer interrupt ---------------

void loop(){
flashLed(); // just tests the 1mSec interrupt by flashing Led every second
}

//-------------------------------------------------------

void flashLed() {
if(flashCounter>=1000){
flashCounter=0;
ledState= !ledState;

digitalWrite(testLed,ledState);

}
}
//

I'm having a difficult time understanding what it is you want to accomplish so I can't provide any specific fix.

But I can comment on two things...

  1. OCR2A = 125 gives an interrupt every 992.0634921 hertz not 1000 hertz. The output compare value needs to be 124.

  2. You need to protect flashCounter with a critical section when you access it in loop.

Hi Coding Badly,
at this stage all I am trying to do is to generate a stream of 1mSec interrupts to drive various routines (time keeping, display multiplex, pushbuttons etc). So they need to be synced to mains for long term accuracy.
Regarding point 1, if OCRA =1 then it would interrupt every 8 microseconds. So if OCRA=125 why would it not interrupt every 8 x 125=1mSec.
Could you please explain what I am missing.
Point 2. Not sure what you mean by protect.
Again, all is stable until ext intrpt is applied. I will add code to look at the interrupt stream next. (probably should have done that first)

Hi Coding Badly,

Greetings.

at this stage all I am trying to do is to generate a stream of 1mSec interrupts to drive various routines (time keeping, display multiplex, pushbuttons etc). So they need to be synced to mains for long term accuracy.

Got it.

Regarding point 1, if OCRA =1 then it would interrupt every 8 microseconds. So if OCRA=125 why would it not interrupt every 8 x 125=1mSec.
Could you please explain what I am missing.

From the datasheet…
“A match will set the Output Compare Flag (OCF2A or OCF2B) at the next timer clock cycle. If the corresponding interrupt is enabled, the Output Compare Flag generates an Output Compare interrupt.”

In addition, all the frequency calculations add one to the OCR register.

Point 2. Not sure what you mean by protect

Does this bring any clarity…
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1261124850

Hi CB, got point 1. I thought it meant input to the the timer. Read post about protection. Never leave home without it. Will play on with code and let you know.

got point 1. I thought it meant input to the the timer.

I've been tripped up by that as well. Consider this... How should the hardware behave if OCR is zero?

Read post about protection. Never leave home without it.

:D

Will play on with code and let you know.

Thanks.

Hi CB,
Now working. Hardware is NOW making nice clean external interrupts!
Protected: I think this now qualifies as safe. Note that none of the routines will ever suffer an interrupt if kept safely within the interrupt period.
OCRA=124? Nope. It really does need to be 125. I checked with frequency counter on pin 12.(1000Hz vs 1009Hz) Maybe the data sheet is misleading. Anyway here’s the code:

#include <EEPROM.h>
volatile byte intrptCounter;
volatile int flashCounter;
volatile boolean mainsFailFlag=0;
volatile boolean doRoutinesFlag=0;
boolean ledState=1;

#define testLed 13
void setup(){
//set up timer 2 control registers here
OCR2A = 125; //initialise compare register for first interrupt
TCCR2A = B00000000; //select Normal Mode,freerunning counter, no connection to hardware pins
TCCR2B = B00000101; //normal, prescaler equals clock/128. With 16Mhz clock this gives an 8uSec clock to the TCNT2
TIMSK2 = B00000010; //generate interrupt on output compare match A
pinMode(testLed,OUTPUT);
pinMode(12,OUTPUT);
pinMode(11,OUTPUT);
attachInterrupt(0,mainsInterrupt,RISING); // makes digital pin 2 trigger an interrupt

}
// ------------------ end of setup ------------------
void mainsInterrupt() {
TCNT2=0; // resync timer to mains interrupt
OCR2A =125;
intrptCounter=0;
mainsFailFlag=0;
flashCounter +=1;
digitalWrite(11,1);
digitalWrite(11,0);
doRoutinesFlag=1;
}
// ----------- end of external interrupt ------------
ISR (TIMER2_COMPA_vect){

intrptCounter+=1; // will normally only reach 9 and is set to zero by mainsInterrupt function
if (intrptCounter>9){
mainsFailFlag=1;
}
if (intrptCounter==9 && mainsFailFlag== 0){
OCR2A +=150; //this would generate a 1.2 mSec interrupt if mains interrupt does NOT occur

}
else{
OCR2A +=125; //this generate a 1mSec interrupt for all interrupts except where external mains interrupt is expected.
}
flashCounter +=1;
digitalWrite(12,1);
digitalWrite(12,0);
doRoutinesFlag=1;
}
// --------------- end timer interrupt ---------------

void loop(){
if (doRoutinesFlag==1){ // just keep checking the flag
doRoutinesFlag=0;
//none of the following will ever be interrupted unless they collectively take loger than 1mSec
flashLed(); // just tests the 1mSec interrupt by flashing Led every second
//do all other routines here
}
}

//-------------------------------------------------------

void flashLed() {
if(flashCounter>=1000){
flashCounter=0;
ledState= !ledState;

digitalWrite(testLed,ledState);
Serial.print(flashCounter);
}
}

Now working. Hardware is NOW making nice clean external interrupts!

Excellent.

OCRA=124? Nope. It really does need to be 125. I checked with frequency counter on pin 12.(1000Hz vs 1009Hz) Maybe the data sheet is misleading.

Good to know. Thanks.

doRoutinesFlag is fine because it is a single byte. flashCounter is not. You need to disable interrupts when reading or writing it from loop (and anything called from loop like flashLed).