Interesting thing with using interrupts on leonardo

Hi all, just would like some insight into this weird thing I'm observing regarding ISRs

Now i know that the use of a delay within the ISR is unnecessary and not good practice and additionally, it is my understanding that within an ISR delay routines do not function anyhow!

So I have read:

"The delay() function uses the milliseconds interrupt. Inside an interrupt handler,
all other interrupts are suspended so the millis() counter doesn't count and delay() never ends."

And from the Arduino reference site:

" ...delay() won’t work and the value returned by millis() will not increment... "

But just doing some fiddling I noticed that the delay function appears to (kinda) "work" within the ISR. It's like it still increments, though improperly. Although this quirk isn't a problem, I just wanted to understand what really is going on under the hood

From my attachment example:

Everything appears to function as it should, after uploading and running this code with line 15 commented out. And keeping the interrupt active by pulling pin 7 to ground, I get the LED on pin 13 lit up, suppose it is actually flickering really fast as it should by the code in the ISR..

But, when un-commenting line 15 and doing the same thing, the LED blinks !WTF?! however it's at a faster rate than the delay would suggest! Changing the delay value changes the rate too..

So what is actually going on here? Or have i done something wrong with my code, I'm only a novice and still learning, just keen to get some answer or at least some direction for more research.

Cheers.

main.cpp (383 Bytes)

Are you actually running that on a Leonardo? What blink frequency do you get with the 500000 delay() call?

I cannot find anything in the core library that would explain why this should work. I thought about the watchdog resetting the board but the standard bootloader of the Leonardo disables the watchdog at boot time.

Have you tried to connect the LED to another pin? Pin 13 LED is blinked in bootloader too so you might be fooled that it's your code that let it blink.

Why would you want to have a delay() in an ISR.

The code in an ISR should be designed to complete as quickly as possible - 100 microsecs would be a long time.

...R

Thanks so much for the response pylon

Good thinking about the watchdog timer, but would i see the changing rates with adjusting the delay if that were the case??

I don't have access to my scope at the moment, but will update when i get that blink frequency. However ill try your suggestions and see what happens.

I do agree with Robbin2 and don't intend to use a delay in the ISR but i just WANT to know why this IS happening.. I know everyone must think that's nuts but when you take reference material as correct and accurate its just weird..

Perhaps the correct wording from the arduino reference should be:

" ...delay() won't work properly and the value returned by millis() will not increment... "

well at least for the delay part, dont have a clue about millis.. one digression at a time huh.

Thanks again

UPDATE:
I reassigned the output pin and i get the same results. Using my "eyeball" scope i get a frequency of 5s for that 500,000ms delay in the ISR. Changing that delay to 100,000ms gets about 1s.. give or take 200ms haven't had my eyes calibrated for ages though :wink:

Change

attachInterrupt(digitalPinToInterrupt(7), isrFunction, LOW);

to

attachInterrupt(digitalPinToInterrupt(7), isrFunction, FALLING);

I think what is happening when you press the button is that the the ISR is being continuously called and when it exits the counter gets a chance to increment a bit.

Quite possibly that's the case, but how does the value for the delay stay retained to decrement on the next ISR call?

Especially so as the delay value is initialised in the function and not stored, well as far as I understand anyhow.

Thanks for that idea, it's definitely got me thinking about things more.

So after reading through the data sheet and as much of the Arduino reference i could, and after some other tests I've come to this conclusion:

  1. ISR's as we all should know are to execute as quickly as possible, of course placing a delay here is unreasonable and defeats the purpose of an ISR.

  2. Considering point 1. ISR's really shouldn't have calls to other functions and if such is needed, a flag could be set to have any function outside the scope of the ISR to run after the ISR trigger. A call to another function from the ISR will execute but the process continues as it should, while disabling any other interrupts till the return to the ISR.

  3. Recalling that any further interrupts are disabled explains why delay and millis don't function as they require interrupts generated from the mcu's internal timers to generate timed intervals.

  4. But however if the ISR is continuously called an runs with a delay function within it. The delay "kinda" tries to work anyhow. As to what is exactly happening within this delay execution i can only guess. But i imagine its related to the lack of timer interrupts during this erroneously run delay routine and some other "black magic" that makes it increment improperly when really it shouldn't at all.

Thanks everyone for the help. Cheers!

ISR's really shouldn't have calls to other functions

No that is fine.