Pages: [1] 2 3   Go Down
Author Topic: attachInterrupt() calls wrong function upon interrupt on Arduino Mega2650  (Read 1653 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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():
Code:
//setup interrupts
attachInterrupt(3, INT1_ISR, FALLING); 
attachInterrupt(4, INT2_ISR, FALLING);
Here are my two ISRs:
Code:
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:
Code:
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
Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 654
Posts: 50956
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I am fairly experienced with both Arduino, AVR, micro-controller architectures and Assembly but
you can't figure out how to use a space bar?

What does printStatus() do?

Why are you diddling with interrupts in INT1_ISR?

Why are those two interrupt service routines given such lousy names?
Logged

UK
Offline Offline
Shannon Member
****
Karma: 223
Posts: 12630
-
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Which pins are your interrupting signals coming in on?

I have to agree with PaulS that identifying your interrupt handlers with numbers which are different to the number of the interrupt they handle does not help understand what they are for.
« Last Edit: September 23, 2013, 05:12:59 pm by PeterH » Logged

I only provide help via the forum - please do not contact me for private consultancy.

Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The interrupts are on pins 19 and 20. I was refering to them by the external int number.
http://arduino.cc/en/Reference/AttachInterrupt

Printstatus is a wrapper for the Serial.println function in order to give meaningful output.

I disabled the interrupts at the suggestion of a co-worker. I realize now that it is pointless but it doesn't change the result of the program execution as I added these in as a way to attempt to solve the bounce after the initial problem started.

They have lousy names because I am used to basing the names off which interrupt is running, not what the interrupt does. Different style of doing things but useful in some situations. And I apologize for the bad style. Arduino does not bring out the best in coding style from me.
Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 654
Posts: 50956
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Printstatus is a wrapper for the Serial.println function in order to give meaningful output.
Serial.print() or Serial.println() have no place in an ISR. They require interrupts being enable to shift data out. If the outgoing buffer gets full when interrupts are disabled, as they are in in ISR, there will never be more space available, since data is not being shuffled out, so the Arduino will hang.

Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I agree with you that Serial.printLn has no place in an interrupt. However in this particular case it was not printing enough to fill the buffer (64 bytes) and the interrupt is hardly ever triggered (once every hour or so). It was added in order to help with debugging. The same problem exists regardless of whether there is a print statement or not in the interrupt.
Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 654
Posts: 50956
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
and the interrupt is hardly ever triggered (once every hour or so).
Then, why do you need interrupts? Interrupts are for things that have to be noticed RIGHT NOW! Once an hour is not something that needs to be dealt with immediately.
Logged

USA
Offline Offline
Jr. Member
**
Karma: 4
Posts: 92
If you can't fix it with a hammer, it must be an electrical problem.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

What board are you compiling for? Because when I compile your code I get the following IVT:

Code:
00000000 <__vectors>:
   0: 71 c0        rjmp .+226    ; 0xe4 <__ctors_end>
   2: 00 00        nop
   4: 57 c1        rjmp .+686    ; 0x2b4 <__vector_1>
   6: 00 00        nop
   8: 86 c1        rjmp .+780    ; 0x316 <__vector_2>
   a: 00 00        nop
   c: b5 c1        rjmp .+874    ; 0x378 <__vector_3>
   e: 00 00        nop
  10: e4 c1        rjmp .+968    ; 0x3da <__vector_4>
  12: 00 00        nop
  14: 13 c2        rjmp .+1062    ; 0x43c <__vector_5>
  16: 00 00        nop
  18: 42 c2        rjmp .+1156    ; 0x49e <__vector_6>
  1a: 00 00        nop
  1c: 71 c2        rjmp .+1250    ; 0x500 <__vector_7>
  1e: 00 00        nop
  20: a0 c2        rjmp .+1344    ; 0x562 <__vector_8>
  22: 00 00        nop
  24: 7f c0        rjmp .+254    ; 0x124 <__bad_interrupt>
  ...
Logged


Miramar Beach, Florida
Offline Offline
Faraday Member
**
Karma: 152
Posts: 6194
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I just tested those interrupts on my Mega, and they work fine. There was one surprise I had not noticed before. The two interrupt functions are called once by the "attachInterrupt()" function before any interrupts occur.

edit: What type of circuit are you using to trigger the interrupts? I'm using D25 (output) wired to D21 and D26 (output) wired to D20.
« Last Edit: September 23, 2013, 07:15:48 pm by SurferTim » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I compiled it for the atmega2560. Its strange that it would work fine for you SurferTim and not me. Thanks for the info though. I'll have to go back and see whether I can figure out what the deal is with my setup. Could you tell me which IDE version you are running? I tried it with multiple arduino megas and had the same result.
Thanks for the help.

PaulS -
Just because a hardware interrupt only triggers once every hour doesn't mean that when it does it doesn't need to be serviced immediately. For instance this one services limit switches on a gantry. If the stepper hits the limit, it needs to stop RIGHT NOW.
Logged

UK
Offline Offline
Shannon Member
****
Karma: 223
Posts: 12630
-
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

it needs to stop RIGHT NOW.

How many nanoseconds does your gantry take to stop?
Logged

I only provide help via the forum - please do not contact me for private consultancy.

Miramar Beach, Florida
Offline Offline
Faraday Member
**
Karma: 152
Posts: 6194
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I did not use your code. I used mine. D25 controls INT2 (D21) and D26 controls INT3 (D20). The prestart is the variables before the attachInterrupt() calls and start is after the calls. The serial display is a bit confusing at first, but it is how my brain works.  smiley-confuse
Code:
int twoCount = 0;
int threeCount = 0;

void setup() {
  Serial.begin(9600);
  
  pinMode(25,OUTPUT);
  digitalWrite(25,HIGH);
  
  pinMode(26,OUTPUT);
  digitalWrite(26,HIGH);

  Serial.print("prestart two = ");
  Serial.print(twoCount);
  Serial.print("  prestart three = ");
  Serial.println(threeCount);
  
  attachInterrupt(2,interrupt2test,FALLING);
  attachInterrupt(3,interrupt3test,FALLING);

  Serial.print("start two = ");
  Serial.print(twoCount);
  Serial.print("  start three = ");
  Serial.println(threeCount);
}

void loop() {

  delay(2000);

  digitalWrite(25,LOW);
  digitalWrite(25,HIGH);
  Serial.print("two = ");
  Serial.print(twoCount);
  Serial.print("  three = ");
  Serial.println(threeCount);

  delay(2000);
  
  digitalWrite(26,LOW);
  digitalWrite(26,HIGH);
  Serial.print("three = ");
  Serial.print(threeCount);
  Serial.print("  two = ");
  Serial.println(twoCount);
}

void interrupt2test() {
  twoCount++;
}

void interrupt3test() {
  threeCount++;
}
  
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Peter H - It needs to stop quickly enough such that polling it is not a good option.
Logged

Miramar Beach, Florida
Offline Offline
Faraday Member
**
Karma: 152
Posts: 6194
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I even added some of your interrupt code to mine to see if that affected it, but it didn't. Mine still works fine. ??
Code:
void interrupt2test() {
  twoCount++;

  static unsigned long last_interrupt_time=0;
  unsigned long interrupt_time = millis();
  if((interrupt_time-last_interrupt_time)>500)
  {
      Serial.println("Hard Stop 1");
  }
  last_interrupt_time = interrupt_time;
}

void interrupt3test() {
  threeCount++;
  static unsigned long last_interrupt_time=0;
  unsigned long interrupt_time = millis();
  if((interrupt_time-last_interrupt_time)>500)
  {
      Serial.println("Hard Stop 2");
  }
  last_interrupt_time = interrupt_time;
}

edit: I am compiling with the board set to "Arduino Mega 2560 or Mega ADK".
« Last Edit: September 23, 2013, 07:53:27 pm by SurferTim » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

SurferTim - Thanks for trying to help. Unfortunately I can't post the whole code because it is for a company project and I can only post the isolated snippets that I did. My guess is it  has something to do with either a namespace conflict, the dev enviornment, or the libraries that I am using. I was just posting here to see if I could figure out why the vector table was behaving as it did. Thanks again.
Logged

Pages: [1] 2 3   Go Up
Jump to: