Jump to content
Sign in to follow this  
athornsb

Timer0_A0 and Port 2 interrupt priority issue.

Recommended Posts

Hey all.  I'm using an msp430g2553 to output an integer to an LCD and let that integer to be modified with a rotating gray code switch.  I am attempting to debounce the switch by sampling its value every 1ms for 5ms (5 samples)  each time the switch interrupt fires.  I am trying to accomplish this with the following code:

 

 for(i=0; i<SAMPLE_NUM; i++) {
       ms=0;
       while(ms==0)
       { //do nothing until at least 1 ms has elapsed
       }
       gray0_val = P2IN&GRAY0;  //latch current port pin values
       gray1_val = P2IN&GRAY1;

 

The issue is at line 2-3 where I reset a 1ms global variable counter.  This gets incremented by my timer 0 A0 interrupt at a rate of 12000Hz.  (yes I know thats not exactly 1 ms, but it doesnt matter)  After I reset the variable, the idea is to wait until the timer interrupt increments it again and then sample the gray code switch value.  However, instead my code is getting stuck here, and it's preventing the timer interrupt from ever firing.

 

I looked up ISR priorities in the user guide, and it appears that the timer interrupt priority is higher than port 2.  That means that in theory this SHOULD work, but something is going wrong.  If you guys could help me solve it that would be great!!

 

 

P.S.  I know its not usually good practice to interrupt an interrupt, but we are close to a deadline and this is the easiest way we've come up with to debounce effectively.

Share this post


Link to post
Share on other sites

You are clearly trying to nest your interrupts (don't confuse priority with nesting.) Just set GIE bit right before while in your port 2 ISR and all should work fine.

Share this post


Link to post
Share on other sites

Instead of having lengthy (timewise) code in your interrupt, wake from the interrupt and execute this code from the main loop. If you have any code running in the main loop that should be executed on another wake up, use boolean flags to conditionally run that code.

bool debounce_flag, other_flag;

#pragma vector=SOME_VECTOR
__interrupt void SOME_ISR(void)
{
  if (should_debounce)
    debounce_flag = true;
  if (some_other_condition)
    other_flag = true;
  if (debounce_flag || other_flag)
    __low_power_mode_off_on_exit();
}

int main(void)
{
  while(1)
  {
    _BIS_SR(LPM0_bits + GIE);
    _no_operation();
    if(debounce_flag)
    {
      debounce_flag = false;
      execute_some_debounce_code();
    }
    if(other_flag)
    {
      other_flag = false;
      execute_other_code();
    }
  }
  return 0;
}

Share this post


Link to post
Share on other sites

Hey road runner, could you explain how that main code functions?  I need my code to stay in low power mode 3 as much of the time as possible (it's a low-power solar application).  It would be ideal to have a debounce flag, controlled by my timer ISR, that could wake the CPU temporarily to sample the value of the gray code switch.

 

Ike thanks, but I don't think that debounce code will work for my application.  That code appears to check the switch only so often to avoid the stutter you typically get with a bunch button.  However with a rotary gray code switch, I need more of an average.  At the moment when you turn the switch, some of the extra oscillations trigger subsequent interrupts and you cant smoothly/reliably change the value on the screen.  What I hope to do is the first time the switch triggers the interrupt, set in motion a series of 1ms separated samples.  After n number of samples i just want to see whether more 0s or 1s were seen on each of the two pins.

Share this post


Link to post
Share on other sites

Rob,  my only worry is if 32ms may be too long for a rotary encoder.  That would give me a maximum of 30 position changes/second which seems reasonable, I just don't want to end up missing more than 1-2 position changes since that could confuse the software about which direction its spinning.  Since your option is the easiest in terms of how much extra code I have to write I think I'll try that first.

Share this post


Link to post
Share on other sites

Ike thanks, but I don't think that debounce code will work for my application.  

Of course that code will not work for your application, as I told you: You will have to modify it.

With WDT_MDLY_8 you have 8ms and with WDT_MDLY_0_5 you have 0.5ms intervals, if you use fSMCLK @ 1MHz.

Share this post


Link to post
Share on other sites

Rob,  my only worry is if 32ms may be too long for a rotary encoder.  That would give me a maximum of 30 position changes/second which seems reasonable, I just don't want to end up missing more than 1-2 position changes since that could confuse the software about which direction its spinning.  Since your option is the easiest in terms of how much extra code I have to write I think I'll try that first.

 

How fast is the encoder spinning? How many contacts does it have, two?

 

You can get the code from the example app that is loaded on every LaunchPad.

 

Here are your WDT options (from the header file,) and remember that you can always change your clock to get different intervals. 

/* WDT-interval times [1ms] coded with Bits 0-2 */
/* WDT is clocked by fSMCLK (assumed 1MHz) */
#define WDT_MDLY_32     /* 32ms interval (default) */
#define WDT_MDLY_8      /* 8ms     " */
#define WDT_MDLY_0_5    /* 0.5ms   " */
#define WDT_MDLY_0_064  /* 0.064ms " */
/* WDT is clocked by fACLK (assumed 32KHz) */
#define WDT_ADLY_1000   /* 1000ms  " */
#define WDT_ADLY_250    /* 250ms   " */
#define WDT_ADLY_16     /* 16ms    " */
#define WDT_ADLY_1_9    /* 1.9ms   " */

Share this post


Link to post
Share on other sites

Thanks to both of you.  I used something similar to what you both mentioned.  Since I need LPM3 for my application, I used the basic principles you two mentioned except with my VLO sourced timer A0.  I essentially wrote my existing encoder interrupt into the timer with a way to measure delay.  Now all I do in my encoder interrupt is:

 

       inactivity=0;   //reset the inactivity counter
     sample_flag=1;
     P2IE &= ~GRAY0;    //deactivate further switch interrupts
     P2IE &= ~GRAY1;
 
Once the delay has been measured with the timer and a sample taken, it clears the P2IFG flags and reactivates the two interrupts.  This prevents the encoder interrupt from firing many times, and hopefully introduces enough delay to get a good reading from the two pins.  I haven't tested it with our hardware yet, but I expect this may work.

 

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...