Jump to content
tripwire

Polling the reset button (S1) on MSP-EXP430G2

Recommended Posts

I've been working on a project for MSP-EXP430G2 which requires two buttons and hit the problem that S1 is set up as a reset button. Unlike S2 it's not connected to a regular GPIO pin; instead it's connected to the nRST/NMI pin.

I looked for information on using the reset button as a user input and found some examples, but they all used the NMI ISR to track rising and falling edges. For example, see this post from the 43oh blog: Using the MSP430G2xx1 nRST NMI Pin as an Input.

I really wanted some way to sample the current state of the button directly, which is tricky because there's no PxIN equivalent for the NMI input. Here's a snippet demonstrating the method I ended up using:

#include <msp430.h> 

int main(void)
{
    WDTCTL = WDTPW | WDTHOLD;

    P1DIR = BIT0;
    P1OUT = 0;

    while(1)
    {
        // Poll S1
        WDTCTL = WDTPW | WDTHOLD | WDTNMI;                      // Detect NMI rising edges
        IFG1 &= ~NMIIFG;                                        // Clear latched value
        WDTCTL = WDTPW | WDTHOLD | WDTNMI | WDTNMIES;           // Detect NMI falling edges
        unsigned char buttonPressed = (IFG1 & NMIIFG) ? 1 : 0;  // Read latched value

        if(buttonPressed)
        {
            P1OUT |= BIT0;
        }
        else
        {
            P1OUT &= ~BIT0;
        }

        __delay_cycles(20000);
    }
}

The nice thing about this is that the polling code is self-contained and can be dropped in wherever you like.

How it works

The schematic for the reset/NMI pin in the G2 family looks like this:

RST_schematic.png.9ac93144f1899b2fae42a7f4e688927f.png

The output of a rising-edge detector is latched to give the value of NMIIFG. If the WDTNMIIES bit is set an inverter is switched in ahead of the edge detector so it detects falling edges instead.

To poll the state of the nRST/NMI pin WDTNMIES is cleared, followed by NMIIFG. Next WDTNMIES is set high and finally NMIIFG is read.

When read, the NMIIFG bit will be set if:

  • S1 was pressed between when WDTNMIES went high and NMIIFG was read
  • S1 was released between when NMIIFG was cleared and WDTNMIES went high (ie it was pressed but you just released it)

The internal switch controlled by WDTNMIES is used to force an edge transition. This is what lets the edge detector output high even if the button was held down for a long time. Note that NMIIE is not set, so the NMI interrupt is never requested.

Warnings

These warnings apply to any use of the nRST/NMI pin for user input:

  • S1 cannot be used while SBW debugging is active. You need to disable or "free run" the debugger so the two functions don't interfere with each other
  • If S1 is held down and the MCU crashes or resets it will be held in reset until you release the button.

Share this post


Link to post
Share on other sites

The few times I have needed to do this, I used interrupt handlers that did nothing but set or reset a bit to reflect the state.

Share this post


Link to post
Share on other sites
On 10/28/2018 at 5:56 PM, enl said:

The few times I have needed to do this, I used interrupt handlers that did nothing but set or reset a bit to reflect the state.

Yes, that's the method described in the blog post I linked. I just posted this as an alternative because I've not seen it before. Indeed, I've seen it claimed that the interrupt handler is the only possible way to track the reset button state.

12 hours ago, Rei Vilo said:

Wouldn't be easier to buy an external switch and connect it to any GPIO available?

You could do that if you have a spare GPIO and don't mind having a loose switch. Even then, it's only four lines of code to poll the reset button...

Share this post


Link to post
Share on other sites

It is a clever solution, and I learned a few things I hadn't realized about the interrupt flags, but I do think it is a solution in search of a problem.

To me, it isn't that the interrupt handler is the only way, or always the best way, but that it is simple and has a low penalty in cycle usage and power, relative to polling this way. Fewer clock cycles per loop (single mask to check one bit, rather than several changes to control register states and masks), and, since this is likely to be a rare event at code speed, net minimal hit. Without working out the numbers, I would guess that each NMI costs about twice as much as each polling loop hit in this example (cycles and power), versus much greater saving each loop for the polling operation.

Also, the NMI handler is a natural fit to dropping to lowest power states (though the '430 is better than many processor families with regard to wake up from assorted conditions) and allowing the handler to wake up for the polling loop. Can you tell I am not a fan of delay functions that do not sleep the processor? [My first experience with this involved halt on a Z80, with a line frequency-- actually video frame rate-- wake-up used for delay in 8.3ms increments in conjunction with processor HALT... This allowed for wake up as needed, and, by the standard of the times, moderate power savings]

 

Please do correct me if I am missing something here... This isn't something I have really considered with this processor before.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×