Hi All,
I have been having some issues with the attachInterrupt() function and have discovered a curiosity in the way that the compiler creates the interrupt table.
First off here are my calls to attachInterrupt():
//setup interrupts
attachInterrupt(3, INT1_ISR, FALLING);
attachInterrupt(4, INT2_ISR, FALLING);
Here are my two ISRs:
void INT1_ISR()
{
static unsigned long last_interrupt_time=0;
unsigned long interrupt_time = millis();
if((interrupt_time-last_interrupt_time)>500)
{
/* Interupt Code Goes Here */
if(initFlag)
{
cli();
stepperMotor.setCurrentPosition(-10*STEPS_PER_INCH);
initFlag=false;
}
else
{
printStatus("Hard Stop 1", 0);
stepperMotor.setCurrentPosition(0);
}
}
last_interrupt_time = interrupt_time;
}
void INT2_ISR()
{
static unsigned long last_interrupt_time=0;
unsigned long interrupt_time = millis();
if((interrupt_time-last_interrupt_time)>500)
{
/* Interupt Code Goes Here */
printStatus("Hard Stop 2", 0);
stepperMotor.setCurrentPosition(0);
}
last_interrupt_time = interrupt_time;
}
The issue that I have been having is that if either INT3 or INT4 triggers it will call INT1_ISR. If I switch the order of the interrupts(switch 3 and 4 in the function calls) then it will always call INT2_ISR. I checked on my board and there is no cross talk between the pins on the arduino. I checked to make sure that I didn't have any typos and for all the usual mistakes that can lead to this kind of issue. The next thing I did is disassemble the .elf
I traced through the execution and it looks like it is following proper function call protocols (as one would assume from a compiler) from the setup where the attachInterrupt() function is called all the way through the completion of the ISR. I was stumped for a couple of weeks but I noticed something odd about the interrupt table today.
Here is the interrupt table:
00000000 <__vectors>:
0: 04 c1 rjmp .+520 ; 0x20a <__dtors_end>
2: 00 00 nop
4: 0c 94 45 0c jmp 0x188a ; 0x188a <__vector_1>
8: 0c 94 76 0c jmp 0x18ec ; 0x18ec <__vector_2>
c: 0c 94 a7 0c jmp 0x194e ; 0x194e <__vector_3>
10: 0c 94 d8 0c jmp 0x19b0 ; 0x19b0 <__vector_4>
14: 0c 94 09 0d jmp 0x1a12 ; 0x1a12 <__vector_5>
18: 0c 94 3a 0d jmp 0x1a74 ; 0x1a74 <__vector_6>
1c: 0c 94 6b 0d jmp 0x1ad6 ; 0x1ad6 <__vector_7>
20: 0c 94 9c 0d jmp 0x1b38 ; 0x1b38 <__vector_8>
24: 1f c1 rjmp .+574 ; 0x264 <__bad_interrupt>
26: 00 00 nop
28: 1d c1 rjmp .+570 ; 0x264 <__bad_interrupt>
2a: 00 00 nop
2c: 1b c1 rjmp .+566 ; 0x264 <__bad_interrupt>
2e: 00 00 nop
30: 19 c1 rjmp .+562 ; 0x264 <__bad_interrupt>
32: 00 00 nop
34: 17 c1 rjmp .+558 ; 0x264 <__bad_interrupt>
36: 00 00 nop
38: 15 c1 rjmp .+554 ; 0x264 <__bad_interrupt>
3a: 00 00 nop
3c: 13 c1 rjmp .+550 ; 0x264 <__bad_interrupt>
3e: 00 00 nop
40: 11 c1 rjmp .+546 ; 0x264 <__bad_interrupt>
42: 00 00 nop
44: 0f c1 rjmp .+542 ; 0x264 <__bad_interrupt>
46: 00 00 nop
48: 0d c1 rjmp .+538 ; 0x264 <__bad_interrupt>
4a: 00 00 nop
4c: 0b c1 rjmp .+534 ; 0x264 <__bad_interrupt>
4e: 00 00 nop
50: 09 c1 rjmp .+530 ; 0x264 <__bad_interrupt>
52: 00 00 nop
54: 07 c1 rjmp .+526 ; 0x264 <__bad_interrupt>
56: 00 00 nop
58: 05 c1 rjmp .+522 ; 0x264 <__bad_interrupt>
5a: 00 00 nop
5c: 0c 94 cd 0d jmp 0x1b9a ; 0x1b9a <__vector_23>
60: 01 c1 rjmp .+514 ; 0x264 <__bad_interrupt>
62: 00 00 nop
64: 0c 94 f4 0f jmp 0x1fe8 ; 0x1fe8 <__vector_25>
68: 0c 94 38 11 jmp 0x2270 ; 0x2270 <__vector_26>
6c: fb c0 rjmp .+502 ; 0x264 <__bad_interrupt>
6e: 00 00 nop
70: f9 c0 rjmp .+498 ; 0x264 <__bad_interrupt>
72: 00 00 nop
74: f7 c0 rjmp .+494 ; 0x264 <__bad_interrupt>
76: 00 00 nop
78: f5 c0 rjmp .+490 ; 0x264 <__bad_interrupt>
7a: 00 00 nop
7c: f3 c0 rjmp .+486 ; 0x264 <__bad_interrupt>
7e: 00 00 nop
80: f1 c0 rjmp .+482 ; 0x264 <__bad_interrupt>
82: 00 00 nop
84: ef c0 rjmp .+478 ; 0x264 <__bad_interrupt>
86: 00 00 nop
88: ed c0 rjmp .+474 ; 0x264 <__bad_interrupt>
8a: 00 00 nop
8c: eb c0 rjmp .+470 ; 0x264 <__bad_interrupt>
8e: 00 00 nop
90: 0c 94 34 10 jmp 0x2068 ; 0x2068 <__vector_36>
94: 0c 94 77 11 jmp 0x22ee ; 0x22ee <__vector_37>
98: e5 c0 rjmp .+458 ; 0x264 <__bad_interrupt>
9a: 00 00 nop
9c: e3 c0 rjmp .+454 ; 0x264 <__bad_interrupt>
9e: 00 00 nop
a0: e1 c0 rjmp .+450 ; 0x264 <__bad_interrupt>
a2: 00 00 nop
a4: df c0 rjmp .+446 ; 0x264 <__bad_interrupt>
a6: 00 00 nop
a8: dd c0 rjmp .+442 ; 0x264 <__bad_interrupt>
aa: 00 00 nop
ac: db c0 rjmp .+438 ; 0x264 <__bad_interrupt>
ae: 00 00 nop
b0: d9 c0 rjmp .+434 ; 0x264 <__bad_interrupt>
b2: 00 00 nop
b4: d7 c0 rjmp .+430 ; 0x264 <__bad_interrupt>
b6: 00 00 nop
b8: d5 c0 rjmp .+426 ; 0x264 <__bad_interrupt>
ba: 00 00 nop
bc: d3 c0 rjmp .+422 ; 0x264 <__bad_interrupt>
be: 00 00 nop
c0: d1 c0 rjmp .+418 ; 0x264 <__bad_interrupt>
c2: 00 00 nop
c4: cf c0 rjmp .+414 ; 0x264 <__bad_interrupt>
c6: 00 00 nop
c8: cd c0 rjmp .+410 ; 0x264 <__bad_interrupt>
ca: 00 00 nop
cc: 0c 94 74 10 jmp 0x20e8 ; 0x20e8 <__vector_51>
d0: 0c 94 b6 11 jmp 0x236c ; 0x236c <__vector_52>
d4: c7 c0 rjmp .+398 ; 0x264 <__bad_interrupt>
d6: 00 00 nop
d8: 0c 94 b4 10 jmp 0x2168 ; 0x2168 <__vector_54>
dc: 0c 94 f5 11 jmp 0x23ea ; 0x23ea <__vector_55>
e0: c1 c0 rjmp .+386 ; 0x264 <__bad_interrupt>
What is weird is that the addresses for the interrupts on this table do not conform to the addresses listed on the interrupt table on page 105 of the ATMega2560 Datasheet.
Here is a link to the datasheet for those who don't have it on hand: http://www.atmel.com/images/doc2549.pdf
In the datasheet each vector takes two addresses in memory. For example INT3's location in the table in the datasheet is 0x08 and INT4's is 0x0A. However in the disassembled arduino code INT3's location is 0x0c and INT4's is 0x10. This change is giving me conflicting information as to what is going on.
First off, the jmp command, which is what is being used in both interrupt tables requires 4 bytes. However the same command is referenced as being used in the vector table in the datasheet and the addresses are completely different. I am wondering whether this difference is what is causing the error. The thing that has me thinking this is the cause is I have never seen an architecture which varies the size of the commands in the vector table. I know that RJMP only uses 1 word for the instruction and thus would fit better in the table in the datasheet but that is not what is used by the compiler nor is it the command mentioned in the datasheet. I don't understand how the processor would be able to discern which interrupt vector address to execute upon interrupts based upon the size of the command. What I am wondering if it is happening is if the interrupt vector is perhaps pointing to the wrong place and sliding down and executing the same interrupt both times.
Anyways I would be curious to hear thoughts about this problem. I am fairly experienced with both Arduino, AVR, micro-controller architectures and Assembly but it is completely possible I am off my rocker for this one.
Thanks,
Julian