I have a need for a 500ms interrupt to check the progress of a serial input, however the sticking point is the routine I have cobbled together from various sources has produced some surprising results.
When I download the program it may take several seconds to begin flashing the debug LED, ie the interrupt is triggering. However if I press the reset on the Uno board the interrupt program appears to begin instantly, ie the Pin13 LED flashes as expected, straight away.
But I need to be able turn the interrupt “off and on” immediately and not have any delays.
What is it in my program that does not allow the interrupt to be enabled immediately?
Cheers, rob
//===============================================
// Toggle a pin on a timer interrupt
// Use an oscilloscope to see the pin output and
// measure the frequency.
//===============================================
#include <avr/interrupt.h>
#include <avr/io.h>
// toggle this pin during the interrupt so it can be read with an oscope
int pin = 13;
// the current state of the pin
int state = 0;
// set a counter to slow the flash rate of pin 13
word myCounter = 0;
//===============================================
// if using the setup_122, use the TIMER2_OVF_vect
// ISR(TIMER2_OVF_vect)
// if using setup_every250uS, use TIMER2_COMPA_vect
//
// interrupt service routine (ISR) is called when the timer interrupt
ISR(TIMER2_COMPA_vect){
myCounter++;
if (myCounter==200){
//toggle the pin
state = 1 - state;
digitalWrite(pin, state);
myCounter=0;
}
}
//===========================
// Note: enable above: ISR(TIMER2_COMPA_vect)
//
// The ISR above toggles the pin
// Generating a square wave with a period twice the timeout
// 250uS * 2 = 500uS period
// should see this frequency on oscope:
// 1 / 500 uS = 2000Hz
//
// calculate number of ticks
// the master clock is 16Mhz
// 1 / 16Mhz = 62.5ns per tick
// the timeout requires this many ticks
// 250uS / 62.5nS = 4000 ticks
// use prescalar of 32
// 4000 / 32 = 125 prescalar ticks
void every250uS()
{
// set prescalar to "/32" = 011
TCCR2B = _BV(CS21) | _BV(CS20);
// set WGM to CTC mode (010)
// In this mode Timer2 counts up until it matches OCR2A
// we need to use OCR2A instead of the overflow so we can interrupt
// more often
TCCR2A = _BV(WGM21);
// These are actual measurements from oscilloscope:
// 0 : 40409.6hz
// 10 : 22730.3
// 100 : 2475.6
// 124 : 2000.3
// 125 : 1984.4
OCR2A = 124;
// When the OCR2A register matches the Timer2 count, cause an interrupt
TIMSK2 = _BV(OCIE2A);
}
//===========================
void setup()
{
pinMode(pin, OUTPUT);
digitalWrite(pin,HIGH);
//delay(500);
digitalWrite(pin,LOW);
attachInterrupt(0, every250uS, CHANGE);
}
//===========================
void loop()
{
//nothing happens here. It's all in the Setup & ISR
}
So... when an interrupt occurs on INT0 (i.e., pin 2 changes state from high to low or low to high) you configure the timer. When that timer times out you run the timer ISR to count up to when you want to flash the LED. Is that right? Is that what you want it to do?
robwlakes:
When I download the program it may take several seconds to begin flashing the debug LED, ie the interrupt is triggering. However if I press the reset on the Uno board the interrupt program appears to begin instantly, ie the Pin13 LED flashes as expected, straight away.
Sounds like the bootloader. When first powering on, junk may appear on the Arduino's serial input. The bootloader sees this and has to process it in case it's a fimware download. After a little while, bootloader realizes it's just junk and boots your code.
The junk doesn't seem to appear on a reset, so the bootloader quickly boots to your code.
Thanks for your interest in this folks and your prompt replies.
First to "tylernt" the delay before the light begins flashing seems much longer than other programs, eg compared to the simplest blinking LED expt.
Secondly to "robtillaart" I think you are right and I will fix the volatile assignments, however the program will basically remain the same and at the moment appears to work differently in the two situations ie download=slow compared to reset=immediate.
Thirdly to "majenko" your interpretation is probably better than mine. however I did not want any triggering from an input, and if I have that in the code then I have made a mistake. I just wanted an internal time base to compare to an serial input (Manchester) data stream. I need to be able to start the interrupt based clock signal exactly on a quarter of a bit length (250uS), and then use the 500uS clock to sample the pulse polarity every subsequent half bit. So I need to be able start it quick, and stop it as required, or at the very least reset it at that point.
That line will call your every250uS() function whenever the input to pin 2 changes. Your routine will not even start until that first change.
As you haven't turned on the internal pullup, and I assume not connected a pullup or pulldown resistor to pin 2, that pin will be floating. As it is situated next to pin 1, which is part of the serial communications, it will be picking up noise from that pin. When you program the board that pin will be flapping around in the breeze more than if you just reset the board, and so the routine that turns on your clock will be called sooner.
Thanks majenko, that seems to have done the instant start trick. The LEDpin13 begins flashing immediately. And I totally agree with your advice re flapping inputs causing mysterious activity. but interrupts and especially the register bit names and their significance are all a bit of black magic at the moment. However I have used this line
// 124 : 2000.3
// 125 : 1984.4
OCR2A = 124;
And chosen the number 124 as it appears to give as the author says it produces square wave frequency of 2000.3 which is close enough for my 500uS clock? However I think I need a every500uS() routine as I don't want to have to throw away every second cycle (I am just wanting cleanest code).
Plus I am not clear at all how to trigger it within my main code so it is correctly synchronised with the incoming signal?
Thanks Nick,
I have scanned your references below and some other connected ones of yours. Very comprehensive and has helped a little (in that I can only absorb so much at one sitting and not a fault of the documentation ).
In particular concerning an interrupt with 500uS between triggering events, which in the following table is the correct choice?
Is the "Freq (Hz)" the frequency of the interrupt where I would need a n=124 and pre-scale of 256, or does it refer to square wave with period 1000uS hence produces alternating 500uS of high followed by 500uS low?
This appears to be the critical bit of code from the example I listed below:
{
// set prescalar to "/32" = 011
TCCR2B = _BV(CS21) | _BV(CS20);
// set WGM to CTC mode (010)
// In this mode Timer2 counts up until it matches OCR2A
// we need to use OCR2A instead of the overflow so we can interrupt
// more often
TCCR2A = _BV(WGM21);
// These are actual measurements from oscilloscope:
// 0 : 40409.6hz
// 10 : 22730.3
// 100 : 2475.6
// 124 : 2000.3
// 125 : 1984.4
OCR2A = 124;
// When the OCR2A register matches the Timer2 count, cause an interrupt
TIMSK2 = _BV(OCIE2A);
}
The table above uses a pre-scaler of 64 whereas the program uses a pre-scaler of 32, giving 500uS in the former and 250uS in the latter? Am I on the right track?
robwlakes:
I have a need for a 500ms interrupt to check the progress of a serial input ...
Simpler would be to use millis to see when half a second is up, in the main loop, and check your serial input then. You can't do a heap in an interrupt service routine anyway (eg. you can set a flag) and there isn't much point to set a flag to see if 500 mS is up, when you can just find out for yourself.
I have a working routine at the moment that works without interrupts, and uses delays instead of watching micros(),(I can't watch for a half a millis() change ), but it could be worth a try to see if the "watching" micros() idea would work. However I said I am trying to unravel the Dark Art of using interrupts, so while your advice is a sound alternative, I would like to pursue this if I can as it seems to be unravelling a few of the mysteries and revealing considerable potential. I am only using the toggle on the Pin13 at the moment just for debug purposes, I have no intention of producing a square wave.
Thanks for the calculations break down, these in combination with the tables in your listing are a good way to get an overview of what timings are possible.
In my reading so far I can now see how to get a timer running, but what state is it in when it is first turned on? IE does it always begin from "zero count" from the first instance or is is likely to have a random partial delay before the pattern of interrupts begins. How can I make it start so I get a full 500uS delay before the next interrupt?
Should I turn it off and on, or just let it run, and say "reset it" when I need to use it?
I may have slipped up somewhere but I thought I was using uS consistently not mS. Sorry for any confusion caused on my part.
I will try the "setting TCNT1 to zero" idea.
Can I use the attachInterrupt() and detachInterrupt() to start and stop as well? Do they have a built in TNCT1=0?