athornsb 0 Posted April 22, 2013 Share Posted April 22, 2013 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. Quote Link to post Share on other sites
RobG 1,892 Posted April 22, 2013 Share Posted April 22, 2013 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. Quote Link to post Share on other sites
ike 53 Posted April 22, 2013 Share Posted April 22, 2013 It's stupid to wait in ISR. athornsb modify this code http://bennthomsen.wordpress.com/ti-msp430-launchpad/using-the-switches/ to suit your needs. Quote Link to post Share on other sites
roadrunner84 466 Posted April 22, 2013 Share Posted April 22, 2013 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; } Quote Link to post Share on other sites
athornsb 0 Posted April 22, 2013 Author Share Posted April 22, 2013 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. Quote Link to post Share on other sites
RobG 1,892 Posted April 22, 2013 Share Posted April 22, 2013 Why don't you just use WDT? P2 ISR starts WDT (32ms delay) WDT ISR reads P2IN and stops WDT Quote Link to post Share on other sites
athornsb 0 Posted April 22, 2013 Author Share Posted April 22, 2013 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. Quote Link to post Share on other sites
ike 53 Posted April 22, 2013 Share Posted April 22, 2013 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. athornsb 1 Quote Link to post Share on other sites
RobG 1,892 Posted April 22, 2013 Share Posted April 22, 2013 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 " */ ike and athornsb 2 Quote Link to post Share on other sites
athornsb 0 Posted April 22, 2013 Author Share Posted April 22, 2013 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. Quote Link to post Share on other sites
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.