Electronic – GPIO using StellarisWare with LM4F120H5QR LaunchPad. SW2 not working as expected

launchpadstellaristroubleshooting

I am trying to figure out how to properly use StellarisWare, the built in ROM calls, for GPIO. The Stellaris LaunchPad has two switches (SW1, SW2) and three LEDs (RED, GREEN, BLUE).

I wrote a little program that reads the switches and turns on the related LEDs when I push them. Everything works as expected:

  • SW1 lights the green LED;
  • SW2 lights the blue LED;
  • SW1 & 2 simultaneously light the red LED.

This is the code:

#include "driverlib/gpio.c"
#include "driverlib/rom.h"
#include "driverlib/sysctl.h"

#include <stdint.h>

#define LED_RED   GPIO_PIN_1
#define LED_GREEN GPIO_PIN_3
#define LED_BLUE  GPIO_PIN_2

#define SW1 GPIO_PIN_4
#define SW2 GPIO_PIN_0

#define GPIO_PORTF_LOCK_R       (*((volatile unsigned long *)0x40025520))
#define GPIO_PORTF_CR_R         (*((volatile unsigned long *)0x40025524))
#define GPIO_PORTF_DEN_R        (*((volatile unsigned long *)0x4002551C))

int main() {

    // Enable GPIO port
    ROM_SysCtlPeripheralEnable( SYSCTL_PERIPH_GPIOF );

    // Enable LED pins for output
    ROM_GPIOPinTypeGPIOOutput( GPIO_PORTF_BASE , LED_RED | LED_GREEN | LED_BLUE );

    // Enable switch pins for input
    ROM_GPIOPinTypeGPIOInput( GPIO_PORTF_BASE , SW1 | SW2 );

    // Enable switch pins pull up.
    ROM_GPIOPadConfigSet( GPIO_PORTF_BASE , SW1 | SW2 , GPIO_STRENGTH_2MA , GPIO_PIN_TYPE_STD_WPU );

// GPIO Lock (GPIOLOCK)
GPIO_PORTF_LOCK_R = 0x4C4F434BU; // unlock the lock register
// GPIO Commit (GPIOCR)
GPIO_PORTF_CR_R = 0xFF; // enable commit for PORT F
// GPIO Digital Enable (GPIODEN)
GPIO_PORTF_DEN_R = 0xFFU; // enable digital on all pins in PORTF

    while ( 1 ) {
        switch( ROM_GPIOPinRead( GPIO_PORTF_BASE , SW1 | SW2 ) ^ ( SW1 | SW2 ) ) {
            case SW1:
                ROM_GPIOPinWrite( GPIO_PORTF_BASE , LED_RED | LED_GREEN | LED_BLUE , LED_GREEN );
                break;
            case SW2:
                ROM_GPIOPinWrite( GPIO_PORTF_BASE , LED_RED | LED_GREEN | LED_BLUE , LED_BLUE  );
                break;
            case SW1 | SW2:
                ROM_GPIOPinWrite( GPIO_PORTF_BASE , LED_RED | LED_GREEN | LED_BLUE , LED_RED   );
                break;
            default:
                ROM_GPIOPinWrite( GPIO_PORTF_BASE , LED_RED | LED_GREEN | LED_BLUE , 0 );
                break;
        }
    }
}

However, when I skip the six lines starting at // GPIO Lock (GPIOLOCK), the program starts to act in an unexpected way: SW2 is always read low, wheras SW1 is working as expected!

I would expect that there is a StellarisWare ROM call that does "the hard" stuff, but I can't seem to find the right call. So the question is: What (StellarisWare ROM call) am I overlooking here?

Best Answer

On most of the GPIO pins, there are more than one functions associated. On the pin having SW2, there is also an NMI (non-maskable interrupt) attached. This renders the pin to be unlocked first and then it can be used as a GPIO input.

As the comment suggests at line 6, you're basically unlocking SW2 pin to be used as a GPIO. All the pins having an alternate function of NMI are required to be unlocked first in order to be used.

For further details on NMI, you can refer to https://en.wikipedia.org/wiki/Non-maskable_interrupt