ISR Never Gets Called

This (above bold line) is simply RONG!

Ok, I made simple program to test it:


a=0x55;
result = PINB&1; 
b=0xAA;

and the result is here:


000005a2 <.LBB125>:
 5a2:   85 e5           ldi     r24, 0x55       ; 85
 5a4:   80 93 21 01     sts     0x0121, r24     ; 0x800121 <a>

000005a8 <.Loc.295>:
 5a8:   83 b1           in      r24, 0x03       ; 3
 5aa:   81 70           andi    r24, 0x01       ; 1

000005ac <.Loc.297>:
 5ac:   80 93 20 01     sts     0x0120, r24     ; 0x800120 <result>

000005b0 <.Loc.298>:
 5b0:   8a ea           ldi     r24, 0xAA       ; 170
 5b2:   80 93 1f 01     sts     0x011F, r24     ; 0x80011f <b>

000005b6 <.Loc.300>:

So it takes 4 cycles


in      r24, 0x03		;# 1 cycles, 2 bytes
andi    r24, 0x01		;# 1 cycles, 2 bytes

sts     0x0120, r24		;# 2 cycles, 4 bytes

In the case of the AVR, it's not the interrupt latency of the chip that is the limiting factor (It's a bit complicated to figure out, since there is both some hardware latency for the external interrupt synchronization logic AND the SW interrupt latency of the CPU (the CPU logic takes 4 to 7 cycles, and a return takes 4.)

The big consumer of cycles comes from the compiler and its choice of interfaces, and the Arduino attachInterrupt() is especially expensive. Minimally, C thinks it has to save the status register and ensure that the "known zero" register is zero:

 252:	1f 92       	push	r1
 254:	0f 92       	push	r0
 256:	0f b6       	in	r0, 0x3f	; 63
 258:	0f 92       	push	r0
 25a:	11 24       	eor	r1, r1

That's 8 cycles (and a similar number on exit from the ISR.) It'll also need to save any registers that the ISR function itself actually uses. (6 registers or 12cycles for the Uno timer interrupt, for example.)

But for ISRs that call other C or C++ code, it also has to save all of the registers that C allows to be modified by the called function, and there are 12 of them (24 cycles.) And then attachInterrupt has to load up the actual destination and do an indirect call. (7 more cycles.)

So that's about 4+7+30+7 or 48 cycles from the time you wiggle a pin till the time the function you supplied starts executing, and perhaps 40 cycles to exit the ISR.

IMPLEMENT_ISR(INT0_vect, EXTERNAL_INT_0)
IMPLEMENT_ISR(INT1_vect, EXTERNAL_INT_1)
 2e6:	1f 92       	push	r1
 2e8:	0f 92       	push	r0
 2ea:	0f b6       	in	r0, 0x3f	; 63
 2ec:	0f 92       	push	r0
 2ee:	11 24       	eor	r1, r1
 2f0:	2f 93       	push	r18
 2f2:	3f 93       	push	r19
 2f4:	4f 93       	push	r20
 2f6:	5f 93       	push	r21
 2f8:	6f 93       	push	r22
 2fa:	7f 93       	push	r23
 2fc:	8f 93       	push	r24
 2fe:	9f 93       	push	r25
 300:	af 93       	push	r26
 302:	bf 93       	push	r27
 304:	ef 93       	push	r30
 306:	ff 93       	push	r31
 308:	e0 91 02 01 	lds	r30, 0x0102	; 0x800102 <__data_start+0x2>
 30c:	f0 91 03 01 	lds	r31, 0x0103	; 0x800103 <__data_start+0x3>
 310:	09 95       	icall
 312:	ff 91       	pop	r31
 314:	ef 91       	pop	r30
 316:	bf 91       	pop	r27
 318:	af 91       	pop	r26
 31a:	9f 91       	pop	r25
 31c:	8f 91       	pop	r24
 31e:	7f 91       	pop	r23
 320:	6f 91       	pop	r22
 322:	5f 91       	pop	r21
 324:	4f 91       	pop	r20
 326:	3f 91       	pop	r19
 328:	2f 91       	pop	r18
 32a:	0f 90       	pop	r0
 32c:	0f be       	out	0x3f, r0	; 63
 32e:	0f 90       	pop	r0
 330:	1f 90       	pop	r1
 332:	18 95       	reti

Add the annoyance of probably having to do that for each "bounce" of your switch contact...

Well, at least two cycles (if "result" is a function-local register.)
There's a single "test bit in IO register and skip if 0/1" instruction that you could use if you're just TESTING the bit, but it takes up to 3 cycles (depending on whether it skips or not, and whether the instruction is skips is one or two words.)
Lots slower if your use digitalRead() to read the pin :frowning:

But that's a bit of a red herring. The "latency" to your function isn't dependent on the timing of the instruction that checks the bit, it's dependent on EVERYTHING ELSE that happens in between the times that you check the bit. Ie, if you poll in loop(), the latency is dependent on the length of all the code that executes in loop. If your loop() takes 1000 cycles (which I don't think is unusual), then the ~100 cycles of overhead for an ISR starts to seem pretty reasonable. OTOH, if your loop doesn't do anything but wait for the ISR to set a variable, polling looks more attractive (OTTH, if your loop isn't doing anything, who cares how fast it's going?)

By "interrupt latency", I simply understand the time/cycles (16 clock cycles for a 4 cycle duration ISR) being taken by the AVR MCU during automatic execution of the following tasks once triggered by an (external) interrupting signal. In other words: iterrupt latency refers to the absolute time difference between exiting MLP (Main Line Program) and resuming MLP in an interrupt process.

  1. Finishing the current instruction, (1 cycle)
  2. Disabling global interrupt flag, (1 cycle)
  3. Saving return address onto stack (not executing push). (3/4 clock cycle)
  4. Loading the ISR address into PC, (1 clock cycle)
  5. Finishing the ISR, (variable: say, max 4 clock cycles for a very short ISR)
  6. Enabling global interrupt flag, and (1 clock cycles)
  7. Retrieving the return address from stack and loads into PC to resume
    the interrupted program (the Main Line Program). (4 clock cycles)

In between three and four is another JMP instruction, since the "ISR Address" is a 4byte space in the vector table (usually contain a "JMP ISRn." If you're not using many interrupts, you can sometimes get away with positioning the entire ISR in the vector table, but that's considered pretty questionable.)

And then all the status and register saving I mentioned. The AVR hardware doesn't save ANY state other than the PC.

I think manipulation of the Global Interrupt flag happens concurrently with other stuff - RET and RETI both take 4 cycles. And the other interrupt flag clearing that happens "when an ISR is executed" isn't documented to add any additional time, either.

In ATmega328P AVR, the flash/code memory is word (16-bit) organized. Is it possible for the CPU to read 16-bit code in one cycle like 8086 which can read code from both banks (odd/evn) in one machine cycle?

Yes, AVR have most instruction 2bytes=1word and does them in 1 cycle, 4bytes=2words instructions does usually in 2 cycles.

Yes, code fetches are 16bits at a time and take one cycle (normally overlapped with execution of the previous instruction, giving you one cycle per instruction unless you break the pipeline (branch and skip instructions.))

However, there are no instructions for fetching 16bit DATA from flash...