Delay in Interrupt kicking in?

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
}

you need at least declare the vars used in the interrupt as volatile.

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.

At least, this is the way my Nano clone behaves.

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.

Cheers, Rob

  attachInterrupt(0, every250uS, CHANGE);

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.

Replace that line with a simple:

  every250uS();

and see what a difference it makes.

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 for you help so far, Rob

You don't need any interrupts to get the timer to toggle a pin. I have numerous examples here:

As for interrupts:

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 :slight_smile: ).
In particular concerning an interrupt with 500uS between triggering events, which in the following table is the correct choice?

  n  -- Prescale 1   --  -- Prescale 8   --  -- Prescale 64  --  -- Prescale 256 --  -- Prescale 1024--
     Freq (Hz) Per (uS)  Freq (Hz) Per (uS)  Freq (Hz) Per (uS)  Freq (Hz) Per (uS)  Freq (Hz) Per (uS)

124:   128,000    7.813     16,000   62.500      2,000  500.000        500 2000.000        125 8000.000  
...
249:    64,000   15.625      8,000  125.000      1,000 1000.000        250 4000.000         63 16000.000

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?

Cheers, Rob

You can work it out from the clock frequency. Assuming a 16 MHz clock you have a period of 62.5 nS.

Prescale by 256 and that gives a clock pulse every:

0.0000000625 * 256 = 16 µS

Now if you count up to 125 (with OCR2A = 124) then you have

16 * 125 = 2000 µS

(as in the table above).

The inverse of that is:

1 / 0.002 = 500

So the pin will toggle 500 times a second. However as it takes two toggles to complete a cycle that would really give you a 250 Hz square wave.

As I said, however, you shouldn't need interrupts. His measured discrepancies would at least partly be due to the time taken to service the interrupt.

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.

Thanks again Nick,

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 :slight_smile: ), 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?

Thanks again for your interest and assistance,

Rob

Well you said 500 mS, and mS is the abbreviation for milliseconds, not microseconds (which is µS or uS if you can't type µ on your keyboard).

but what state is it in when it is first turned on?

Probably where you left it. You could set TCNT1 to zero before starting.

Hi Nick,

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?

Cheers, Rob

No, that has nothing to do with timer interrupts.