attachInterrupt() hang, USB port IO (Maybe solved, see last post.)

Hi All

I got strange hang problem.

in loop(), I have a lot of I/O activities with USB port using Arduino serial port monitor. And also read user input strings from UBS port, based on the input, do some activities.

Based on user input, the code will call attachInterrupt() or detachInterrupt() or print out other hardware and sensor information if user has no input.

unsigned short rptnum = digitalPinToInterrupt(pinindex); unsigned short rptmod = RISING; attachInterrupt(rptnum, rpm, rptmod );

or

unsigned short rptnum = digitalPinToInterrupt(pinindex); unsigned short rptmod = RISING; detachInterrupt(rptnum);

void rpm(){ // some code.... }

The problem is, sometime , the call attachInterrupt() hangs. Sometime it is OK. Especially after loop () is printing out many information using Serial.print(). If the code receives input asking to call attachInterrupt(), it hangs.

If the first user input calls for attachInterrupt(), it will OK. but later call will hang.

If comment out attachInterrupt(), no hangs anymore.

Do the attach interrupt only once (in setup?).

If you want to ignore interrupts, just set a volatile bool isrBlocked that you check in the isr.

It dynamically call attachInterrupt based on user input. So it will call many times. Of case, before it is called for the same pin, a detach should be called. Or call for another pin.

It is not in setup, it is in loop().

the following code:The code :

char* msg = "abcdefghijklmnopqrstuvwxyz\n";

Serial.print(msg);

attachInterrupt(rptnum, rpm, rptmod );

sometime it only prints out truncated string. If comment out attachInterrupt(), it will print out whole string. very strange.

changshen: It is not in setup, it is in loop().

That is the problem.

If you want do attach/detach in loop(), hey, its your Arduino and your problem.

The following test code exactly calls attach dynamically in loop() and has no problem. The reading from sensor works perfectly. I am thinking may be the real code is too big and it causes some problem. The real code has the same logical structure, just has a lot of other stuff and the code is very big. I cannot think any reason why it hangs, and sometime not hangs.

#include <arduino.h>

volatile int index=0;
volatile int count2=0;
volatile int count3=0;

int ComPortRate = 9600;
char readin=’ ';
unsigned short rptnum=0;
unsigned short rptmod = RISING;
unsigned short pin2 = 2; //sensor pin
unsigned short pin3 = 3; //sensor pin

void rpm2(){
count2++;
}

void rpm3(){
count3++;
}
void setup() {
interrupts();
Serial.begin(ComPortRate);
Serial.flush();
}

char ReadComByte()
{
char s = ‘\0’;
if (Serial.available() > 0)
{
s = (char)Serial.read();
}
return s;
}

void loop() {
if(index==0) {
index++;
Serial.print(“pindex = “);
Serial.print(index);
Serial.print(”\n”);
}
else {
readin = ReadComByte();
if(readin==‘a’){
rptnum = digitalPinToInterrupt(pin2);
if(rptnum>=0) {
attachInterrupt(rptnum, rpm2,rptmod);
Serial.print(" Attach pin 2 rptnum = “);
Serial.print(rptnum);
Serial.print(”\n");
}
}
else if (readin==‘d’){
rptnum = digitalPinToInterrupt(pin2);
if(rptnum>=0){
detachInterrupt(rptnum);
Serial.print(" Detach pin 2, rptnum = “);
Serial.print(rptnum);
Serial.print(”\n");
}
}
if(readin==‘x’){
rptnum = digitalPinToInterrupt(pin3);
if(rptnum>=0) {
attachInterrupt(rptnum, rpm3,rptmod);
Serial.print(" Attach pin 3 rptnum = “);
Serial.print(rptnum);
Serial.print(”\n");
}
}
else if (readin==‘y’){
rptnum = digitalPinToInterrupt(pin3);
if(rptnum>=0){
detachInterrupt(rptnum);
Serial.print(" Detach pin 3, rptnum = “);
Serial.print(rptnum);
Serial.print(”\n");
}
}
else if(readin==‘2’){
Serial.print(“pin 2 count = “);
Serial.print(count2);
Serial.print(”\n”);
count2=0;
}
else if(readin==‘3’){
Serial.print(“pin 3 count = “);
Serial.print(count3);
Serial.print(”\n”);
count3=0;
}
}
}

I am thinking may be the real code is too big and it causes some problem.

No your not thinking - POST ALL YOUR CODE. There is no point in posting a bit of code that (you say) works and then hoping we can figure out whats wrong with a different load of code!

Mark

Stop attaching and detaching interrupts it's total point less!

Mark

Please read the two posts by Nick Gammon at the top of this Forum on the correct way to post code here using code tags. Not using code tags can mangle your source code.

Edit: Also, given the way you've written the code, what happens if I type in an 'A' instead of 'a'? Are you assuming that users never enter capital letters?

Hi ALL
Due to some reasons (employer) I could not post whole code, just a test code to make the points. Since it is a test code, I am not worry about strange user input.

The real code has the same logic structure. Just has more “else if/switch” blocks and many sub routines to handle other actions.

BTW, attach and detach dynamically have its meaning. The reason is to hot swap or to add sensors in running time.

#include <arduino.h>

volatile int index=0;
volatile int count2=0;
volatile int count3=0;

int  ComPortRate    = 9600;
char readin=' ';
unsigned short rptnum=0;
unsigned short rptmod = RISING;
unsigned short pin2 = 2;  //sensor pin
unsigned short pin3 = 3;  //sensor pin


void rpm2(){
  count2++;
}

void rpm3(){
  count3++;
}
void setup() {
  interrupts();
  Serial.begin(ComPortRate);    
  Serial.flush();  
}

char ReadComByte()
{ 
  char s = '\0';
  if (Serial.available() > 0) 
  {   
      s = (char)Serial.read();
  }   
  return s;
}


void loop() {      
      if(index==0)  {
        index++;
        Serial.print("pindex = ");
        Serial.print(index);
        Serial.print("\n");
        }
      else  {
        readin = ReadComByte();
        if(readin=='a'){
          rptnum = digitalPinToInterrupt(pin2);
          if(rptnum>=0) {
            attachInterrupt(rptnum, rpm2,rptmod);
            Serial.print(" Attach pin 2 rptnum = ");
            Serial.print(rptnum);
            Serial.print("\n");
          }
        }
        else if (readin=='d'){
          rptnum = digitalPinToInterrupt(pin2);
          if(rptnum>=0){
            detachInterrupt(rptnum);
            Serial.print(" Detach pin 2,  rptnum = ");
            Serial.print(rptnum);
            Serial.print("\n");
          }
        }
        if(readin=='x'){
          rptnum = digitalPinToInterrupt(pin3);
          if(rptnum>=0) {
            attachInterrupt(rptnum, rpm3,rptmod);
            Serial.print(" Attach pin 3 rptnum = ");
            Serial.print(rptnum);
            Serial.print("\n");
          }
        }
        else if (readin=='y'){
          rptnum = digitalPinToInterrupt(pin3);
          if(rptnum>=0){
            detachInterrupt(rptnum);
            Serial.print(" Detach pin 3,  rptnum = ");
            Serial.print(rptnum);
            Serial.print("\n");
          }
        }
        else if(readin=='2'){          
          Serial.print("pin 2 count = ");
          Serial.print(count2);
          Serial.print("\n");
          count2=0;
        }
        else if(readin=='3'){          
          Serial.print("pin 3 count = ");
          Serial.print(count3);
          Serial.print("\n");
          count3=0;
        }
      }  
}

Since it is a test code, I am not worry about strange user input.

Kind of a dumb attitude to take as it reflects laziness plus it is so easy to fix:

      s = toupper(Serial.read());   // Now it doesn't matter if input is 'A' or 'a'

If you want to use lower case letters, use tolower() instead.

You need to think about how ReadComByte() works. Even when there is no bytes to be read, it returns '\0' and your main loop just keeps calling it and running the if statements with no reason. It's not a fatal flaw but shows us that you should have similar flaws in your actual proprietary code. Sorry that I can't help with code that can't be posted.

More info.

attach and detach put together, will not hang. comment out detach causes hang

unsigned short intrruptnum = digitalPinToInterrupt(2);

delay(1000);
attachInterrupt(intrruptnum, rpm, RISING);
delay(1000);
detachInterrupt(intrruptnum);
delay(1000);

This proves that the code structure has no problem. Something I could not understand.

changshen:
This proves that the code structure has no problem.

I disagree.

But it proofs that you do not want suggestions.

May you live in interresting times.

The real code has the same logic structure. Just has more "else if/switch" blocks and many sub routines to handle other actions.

It sounds to me like you are running out of memory.

Hot-swapping hardware is stupid.

That is possible that memory maybe the issue. But today I find interesting things. I change rptmod to hard coded. The problem is gone.

And the pin default voltage is at LOW so this maybe the reason that the "LOW" case causes hang as well. I am trying to clean and optimize the code to make the code smaller, see if this helps. Anyway this is very interesting phenomenon and I do not understand yet. Will this be a board design bug?

BTW, the code is not so big. Here is the usage information: Sketch uses 29,108 bytes (11%) of program storage space. Maximum is 253,952 bytes. Global variables use 3,698 bytes (45%) of dynamic memory, leaving 4,494 bytes for local variables. Maximum is 8,192 bytes.

The code has those volatile data and static data as seen below in code section, will this cause problem?

//attachInterrupt(rptnum , rpm, LOW); //this cause hang problem //attachInterrupt(rptnum , rpm, HIGH); //this has no problem //attachInterrupt(rptnum , rpm, CHANGE); //this has no problem //attachInterrupt(rptnum , rpm, FALLING); //this has no problem //attachInterrupt(rptnum , rpm, RISING); //this has no problem

volatile MyDataStructure myDataStructure [70];  //total 1680 bytes
volatile time_t mytimes[2];                                //total has 8 bytes 
volatile int mydata[8];                                       //total 16 bytes

static unsigned int inD[4];                                 //total 8 bytes


volatile int count = 0;

void myfunc(){
   unsigned short pinindex= 2;
   unsigned short rptmod = RISING;
   unsigned short rptnum = digitalPinToInterrupt(pinindex);
   //attachInterrupt(rptnum , rpm, rptmod ); //this cause hang problem
   //attachInterrupt(rptnum , rpm, LOW); //this cause hang problem
   //attachInterrupt(rptnum , rpm, HIGH); //this has no problem 
   //attachInterrupt(rptnum , rpm, CHANGE); //this has no problem 
   //attachInterrupt(rptnum , rpm, FALLING); //this has no problem 
   attachInterrupt(rptnum , rpm, RISING);   //this has no problem !!!
}


void rpm(){
    count++;
}

Great!

Now edit the title of your original post (not the contents of the post) to add [SOLVED] to the subject line. This is an important solution that will be useful to many other people.

Using a constant in place of an integer is not the solution.

It probably just uses the magic byte less on the stack, because rptmod gets optimized away.

   unsigned short rptmod = RISING;
   unsigned short rptnum = digitalPinToInterrupt(pinindex);
   attachInterrupt(rptnum , rpm, rptmod );  // both call do exactly the same thing
   attachInterrupt(rptnum , rpm, RISING);   // both call do exactly the same thing

I need do more test to confirm this is the case. BTW, we still don't understand why if this is the case.