Jump to content
Sign in to follow this  
JasonP

MSP432 digitalRead() / Interrupt not working?

Recommended Posts

Hello Everyone,

 

I am working with the MSP432 launchpad in Energia and I can't seem to use digitalRead() in and ISR?  I'm hoping that someone can give me some indication as to why or find the bug in my code ;)

 

This is for a rotary encoder and the interrupts must fire on both Rising and Falling Edges.  This Is why I try to determine the state of the pin that was just interrupted.  The ISR's will be a bit more complex for the actual encoding but first I need to be able to read the state of the pins.

 

Thanks Guys!


const int encoder0PinA = 11;
const int encoder0PinB = 31;

volatile int pinACount = 0;
volatile int pinBCount = 0;

volatile bool Aflag = false;
volatile bool Bflag = false;


///////////////////////////////////////////////////////////////////////////////////
//////////////////////////////   S E T U P   //////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
void setup(){
  
  Serial.begin(9600);
  Serial.println("COUNTER STARTING UP");
 
  pinMode(11,INPUT);
  pinMode(31,INPUT);
  attachInterrupt(encoder0PinA, doEncoderA, CHANGE); 
  attachInterrupt(encoder0PinB, doEncoderB, CHANGE);

}

///////////////////////////////////////////////////////////////////////////////////
////////////////////////////////   L O O P   //////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
void loop(){
  
  // SANITY CHECK
  
  Serial.println(digitalRead(11));  // Here to see that the pin does change states 
  Serial.println(digitalRead(31));  // Here to see that the pin does change states
  

  Serial.print("A Flag: ");
  Serial.print(Aflag);         // I never see either of these get set to 1.
  Serial.print("  B Flag: ");
  Serial.println(Bflag);
 ;
  Serial.println();
  delay(500);

}


void doEncoderA(){
  
 Aflag = digitalRead(encoder0PinA);
 

}


void doEncoderB(){

 Bflag = digitalRead(encoder0PinB);
 
}

Share this post


Link to post
Share on other sites

It seems that you have stumbled on a bug. I was able to reproduce it.

Odd thing is that I am able to read a pin that has not seen attachedInterrupt() and see the flag change if I digitalRead() that pin in the interrupt routine.

 

I'll look into it.

 

Robert

Share this post


Link to post
Share on other sites

Would you please be so kind to file an issue on github here: https://github.com/energia/Energia/issues

 

Thanks!

 

Robert

 

Robert, 

 

I have created the new issue found here: https://github.com/energia/Energia/issues/873  

Also I was wondering if you can think of a workaround in the meantime?  We are trying to have a working prototype by next week.

 

Thank You.

Share this post


Link to post
Share on other sites

I modified the code to use the buttons so that I didn't have to hook up an encoder.  Something in Energia doesn't process "CHANGE" from the attachInterrupt() function properly either.  It works as expected on a F5529 and catches rising and falling edges but not on the MSP432.

 

@@JasonP - The following "works" but will only catch one edge

const int encoder0PinA = PUSH1;
const int encoder0PinB = PUSH2;

volatile int pinACount = 0;
volatile int pinBCount = 0;

volatile bool Aflag = false;
volatile bool Bflag = false;


///////////////////////////////////////////////////////////////////////////////////
//////////////////////////////   S E T U P   //////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
void setup(){

  Serial.begin(115200);
  Serial.println("COUNTER STARTING UP");

  pinMode(encoder0PinA,INPUT_PULLUP);
  pinMode(encoder0PinB,INPUT_PULLUP);
  attachInterrupt(encoder0PinA, doEncoderA, CHANGE); 
  attachInterrupt(encoder0PinB, doEncoderB, CHANGE);

}

///////////////////////////////////////////////////////////////////////////////////
////////////////////////////////   L O O P   //////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
void loop(){

  // SANITY CHECK

  Serial.println(digitalRead(encoder0PinA));  // Here to see that the pin does change states 
  Serial.println(pinACount);
  Serial.println(digitalRead(encoder0PinB));  // Here to see that the pin does change states
  Serial.println(pinBCount);

  Serial.print("A Flag: ");
  Serial.print(Aflag);         // I never see either of these get set to 1.
  Serial.print("  B Flag: ");
  Serial.println(Bflag);
  ;
  Serial.println();
  delay(500);
}

void doEncoderA(){
  pinACount++;
  if (Aflag == 0) {
    Aflag = 1;
  }
  else {
    Aflag = 0;
  }
}

void doEncoderB(){
  pinBCount++;
  if (Bflag == 0) {
    Bflag = 1;
  }
  else {
    Bflag = 0;
  }
}

Share this post


Link to post
Share on other sites

@@Fmilburn,  Thanks for mentioning that.  That explains what I have been seeing but I did not pick up on that.  I was going insane here trying to figure out why my arduino based code that has worked flawlessly isn't working at all.  I hope these issues can get resolved soon.  

 

@@energia, Has an issue been created for the attachInterrupt(CHANGE) problem that @@Fmilburn just mentioned?

Share this post


Link to post
Share on other sites

I think the proposed Aflag ^= 1 workaround does not really solve your problem. You still only get an interrupt on one of the transitions (high-low or low-high), but instead of reading the current pin state, you simply inverse the current state of the variable.

 

From reading the e2e thread and without reading at the datasheet, it looks like the MSP432 hardware only supports configuring the interrupt for one of the transitions at a time, i.e. no native support of CHANGE.

 

It could be worked around by re-configuring within the interrupt. E.g. if currently high, trigger on going low; if currently low, trigger on going high. Calling attachInterrupt within the interrupt probably won't work, so you'd have to go to the register level to implement that.

 

Maybe there's already an Energia library for reading quadrature encoders that takes care of those low-level details.

Share this post


Link to post
Share on other sites

@@chicken,  Your'e right.  It doesn't really solve the problem.  I posted a followup over there after I pulled my head out and realized that is not an actual workaround.  Re-establishing the interrupt within the interrupt might work.  I know detaching and reattaching inside an interrupt does work on my arduino.  I might have to try that.  I really didn't want to have to refresh on C but maybe I will have to... Or revert back to arduino. :unsure:

Share this post


Link to post
Share on other sites

A little wasteful of GPIO and code space perhaps, but could you not send the encoder's signals to two pins each and attach rising and falling interrupt handlers / functions to those pins separately?

Share this post


Link to post
Share on other sites

Okay... put something together... a little simplified, but using the EMT abilities... and "CHANGE". One part eschews using Serial for debugging and sets up the "Aflag" variable and configures pin 11 as in input with an interrupt handler using CHANGE, the handler does a "NOT" on the Aflag variable when called, and loop() sets the RED LED to the Aflag state. The other is a "thread" which sets up another pin (12) to automatically turn on and off every 1/10 second.

 

So, create new sketch in Energia and put the following in it:

const int encoder0PinA = 11;

volatile bool Aflag;

void setup(){

  pinMode(encoder0PinA,INPUT);
  Aflag = digitalRead(encoder0PinA);
  attachInterrupt(encoder0PinA, doEncoderA, CHANGE); 

  pinMode(78, OUTPUT); // RED single LED on board
}

void loop(){
    digitalWrite(78, Aflag);
}

void doEncoderA(){
  Aflag = !Aflag;
}
Then make a new tab, name it "blink", then paste the following code in:

void setupBlink() {
  pinMode(12, OUTPUT);
  digitalWrite(12,HIGH);
}

void loopBlink() {
  delay(100);
  digitalWrite(12, LOW);
  delay(100);
  digitalWrite(12,HIGH);
}
Then, connect a jumper between pins 11 and 12 and upload the program.

 

"CHANGE" does in fact work... this way at least.

 

Makes me wonder if using a physical switch without debouncing, or something with Serial might be culprit...?

 

*edit: changed the value in the delay() in "blink" to a few different values and couldn't see any issues.

 

*edit-2: tried to do digitalRead() in the interrupt and that still does not work.

Share this post


Link to post
Share on other sites

@@abecedarian,  Thanks for the Idea of using two pins for the interrupt rising and falling.  This actually would solve most of my issues as I would then truly know the state of the pin.... I think.    Also thanks for this little sample sketch I will try running it later today.. HA I was going to ask if you tried different delays since 100mS vs 200mS might be hard to tell, but I see in your edit you did that  ;)   The GPIO thing isn't really an issue for us.  Thanks again.

Share this post


Link to post
Share on other sites

After waking up this morning, I put a blink sketch on a G2553 LP in order to emulate the signal a Hall effect sensor or similar might output to the system. I connected that to the 432 and the LED on the 432 toggles on only one edge.

 

So I need to correct myself: "CHANGE" is not working in the sketch I posted above. Must've been an illusion. ;)

 

Anyhow, I tried the two-pin, two-interrupt thing, and kept the G2553LP as a "signal generator"-

 

On the 432:

const int encoder0PinA1 = 11;
const int encoder0PinA2 = 12;

volatile bool Aflag;


///////////////////////////////////////////////////////////////////////////////////
//////////////////////////////   S E T U P   //////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
void setup(){

  pinMode(78, OUTPUT); // RED single LED on board
  pinMode(encoder0PinA1,INPUT);
  pinMode(encoder0PinA2,INPUT);

  // set Aflag to whatever state the pin is in on start up
  // in case the interrupts don't trigger early enough
  Aflag = digitalRead(encoder0PinA1); 

  attachInterrupt(encoder0PinA1, doRisingEncoderA, RISING); 
  attachInterrupt(encoder0PinA2, doFallingEncoderA, FALLING); 
}

///////////////////////////////////////////////////////////////////////////////////
////////////////////////////////   L O O P   //////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
void loop(){
  digitalWrite(78, Aflag);
}

void doRisingEncoderA(){
  Aflag = true;
}

void doFallingEncoderA(){
  Aflag = false;
}
On the G2553LP:

void setup() {
  pinMode(RED_LED,OUTPUT);
  digitalWrite(RED_LED,HIGH);
}

void loop() {
  delay(100);
  digitalWrite(RED_LED, LOW);
  delay(100);
  digitalWrite(RED_LED, HIGH);
}
On the G2553LP, I left the RED LED jumper on.

I ran a jumper from the G2553LP pin 2(LED1) to a row on a breadboard, then ran two jumpers from that row to the 432's pins 11 and 12. Essentially:

G2553 pin 2 ------+------ pin 11 432LP
                  +------ pin 12 432LP
The RED LED's on both boards blink together, at the same rate, so the 432 is catching both the rising and falling edges of the single output from the G2553.

Share this post


Link to post
Share on other sites

@@abecedarian,  Ha ha I was just writing to say thank you to everyone that has pitched in and helped me, especially you!  Honestly I don't see a better workaround for the time being and things are actually working flawless.  Spitting the two interrupts into two is actually nice as each interrupt is much simpler.  Thanks again.

//////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////   I N T E R R U P T    ////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////
void risingA(){

 // Must be a low-to-high on channel A
 
Ahigh = true; // The pin must be high to get here.
  // check channel B to see which way encoder is turning
  if (!Bhigh) {  
    encoder0Pos++;         // CW
    direction = 1;
  }  
  else {
    encoder0Pos--;         // CCW
    direction = 2;
  }
}

//////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////   I N T E R R U P T    ////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////
void fallingA(){
  // must be a high-to-low edge on channel A 
  Ahigh = false;  
  // check channel B to see which way encoder is turning  
  if (Bhigh) {   
    encoder0Pos++;          // CW
    direction = 1;
  } 
  else { 
    encoder0Pos--;         // CCW
    direction = 2;
  } 
}

//////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////   I N T E R R U P T    ////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////
void risingB(){
  // Must be a low-to-high on channel B
  Bhigh = true;
   // check channel A to see which way encoder is turning
  if (Ahigh) {  
    encoder0Pos++;         // CW
    direction = 1;
  } 
  else {
    encoder0Pos--;         // CCW
    direction = 2;
  }
}

//////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////   I N T E R R U P T    ////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////
void fallingB(){
Bhigh = false;
// must be a high-to-low on channel B
  sensblast = false; 
 // check channel B to see which way encoder is turning  
  if (!Ahigh) {   
    encoder0Pos++;          // CW
    direction = 1;
  } 
  else {
      encoder0Pos--;         // CCW
      direction = 2;
  }   
}

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this  

×
×
  • Create New...