Question about interrupt behavior

Hey guys,

I have been doing some researching and can't find exactly what i'm looking for.

When an interrupt is triggered, does it exit the main code after the current line is finished processing, or does it IMMEDIATELY exit and call the ISR?

For example if your program is running a line of code that takes 100 cycles to complete. If the line is half way finished (50 cycles left) when the interrupt is triggered, does it process the ISR, then return and finish the remaining 50 cycles to finish the line that was interrupted?

Thanks!

While I'm at it if anyone knows the answer to another question I had (about serial coms with the arduino due) here is a link to it... I think it got buried before anyone with the answer saw it. :slight_smile:

https://forum.arduino.cc/index.php?topic=354965.0

If an interrupt occures while interrupts are enabled, the ISR will be entered
after the completion of the current instruction.

Generally there is no 1:1 line (C++) to instruction (ASM) mapping.

The granularity of interrupts is the machine instruction, not lines of code nor clock cycles.
After each instruction completes any pending interrupts are checked for and the highest
priority one is vectored to (pushing the program counter on the stack). Most machine instructions
take a few cycles.

In particular if your code is reading an integer (2 bytes on the Uno), the interrupt can happen
between reading the individual bytes of the variable (since the ATmega chips are 8-bit machines).

This is why if using volatile variables more than a single byte you have to protect their
access from the main program using noInterrupts() / interrupts().

It would interrupt between machine code level instructions.
Meaning it could interrupt any where in some C code line.
If you need to protect a simple operation and can tolerate
the delay in servicing the interrupts you'd be using, you can
disable the interrupts for a line and then re-enable them
after.
I don't recall the exact instructions but I know we have others that
will help you with that.
Another way to deal with it is have a flag value that you clear
before the line.
You'd then set it in your interrupt.
Do something you can recover from and check the flag.
If still cleared you know you made it through without interference
from that interrupt.
Dwight
I see Mark had the interrupt control words for you.

Thanks for the replies guys, I think I am getting it now.

Just to be sure I understand it correctly, the code I write is compiled into a completely different set of commands before it is sent to the arduino, and the interrupt happens at the end of the current -machine- instruction, which is different from the instructions I put in a line of my pre-compiled code.

For instance if I wrote... Serial.println("bla"); it might be broken up into multiple commands in the machine code (no experience with all of that)? If Serial.println is broken into... three lines of machine code for example, and the interrupt occurred during the first of those three, it would handle the ISR after the first line of machine code, then return and finish the last two lines, at which point my Serial.println would be completed and send the serial data?

Serial.println("foo"); and the like mostly get translated into a single call-instruction,
which jumps to a subroutine consisting of arbitrary lines (saving the return address into the stack).

Interrupts do not care about C++ lines, they just interrupt the normal
flow of execution and return to that point after execuion of the ISR.
So ISRs have to save all registers before execution and to restore them before returning,
adding significant overhead to the ISR.

Soronemus:
For instance if I wrote... Serial.println("bla"); it might be broken up into multiple commands in the machine code (no experience with all of that)? If Serial.println is broken into... three lines of machine code for example, and the interrupt occurred during the first of those three, it would handle the ISR after the first line of machine code, then return and finish the last two lines, at which point my Serial.println would be completed and send the serial data?

That is a good description of what happens. Except that Serial.println() might involve hundreds of lines of machine code. A single machine code instruction does very little - for example it may move a byte from one place to another.

If you are interested the Atmel datasheets include a summary of the machine code instructions.

...R

Whandall:
Serial.println("foo"); and the like mostly get translated into a single call-instruction,
which jumps to a subroutine consisting of arbitrary lines (saving the return address into the stack).

No, it won't. Any function call with arguments will compile to at least several instructions (to fetch the arguments and build the stack frame), and EXECUTION of that function may involve tens, hundreds, thousands, or even tens of thousands of instructions.

Regards,
Ray L.

If the interrupt is more critical than the running code, her is an alternate
way to handle it.

void OneSecISR() { 
/* Interrupt happened from external 1 second interrupt
* from an external time reference, such as a DS3231
*/
  uSecCpu = micros();
}


loop() {
.........
do {
     CurrentuSec = uSecCpu;
     } while ( CurrentuSec != uSecCpu );
........
}

If an interrupt happened some time while reading
uSecCpu, it will automatically get a clean copy of it.
Dwight

What? If non-interrupt code is reading uSecCpu it may well be half-way through loading it into a variable (or comparing it to something) and then the ISR changes it in the middle. This is very bad. You can't handle that in the ISR. Code which accesses variables like that have to be "guarded" to stop interrupts. eg.

unsigned long foo;
noInterrupts ();
foo = uSecCpu;
interrupts ();

Now you are safe, as you can't be interrupted while getting a copy of uSecCpu.

If you look at my code, I was just showing an alternative way to handle the problem.
If the value changes when you read it twice, it must have changed because of the interrupt.
You just keep reading it until it doesn't change.
This doesn't work for all kind of data but for the simple case I showed where the value incremented
it works fine.
You don't always have to turn off interrupts, depending on the interrupt it may not be desirable
to disable interrupts even for a few extra cycles.
Dwight

That might work, although I am worried a bit that a subtle train of events might give you a bad reading in the assignment, and then a bad reading on the compare.

You don't need to obsess too much over disabling interrupts for a couple of cycles. Every time timer 0 overflows you get an interrupt to process incrementing the variable used by millis. Brief periods with interrupts off are normal on a processor. If they weren't, interrupts would be no use.