Skip to content

GPIO Inputs and Interrupt Handling ​

Complete Lab Manual

For the complete experiment including learning objectives, theoretical background, and detailed explanations, download the PDF manual: Download Experiment 5 PDF

Examples ​

The following examples demonstrate GPIO input configuration using polling and interrupt-based approaches.

Example 1: Reading Switch Input Using Polling ​

This example continuously polls the state of SW1 (PF4) and turns on the red LED (PF1) when the button is pressed.

c
#include "TM4C123.h" 

#define RED_LED 0x02
#define SWITCH 0x10

int main(void) { 
    unsigned int state;      
    SYSCTL->RCGCGPIO |= (1<<5); 			// Enable Port F
    GPIOF->PUR |= SWITCH;                   // Enable pull-up resistor on PF4
    GPIOF->DIR |= RED_LED;                  // Set PF1 as an output pin and PF4 as an input pin
    GPIOF->DEN |= (RED_LED | SWITCH);       // Enable PF1 and PF4 as a digital GPIO pins
    while(1) {    
        state = GPIOF->DATA & SWITCH;       // Read the state of the switch
        if (state == 0) {                   // If the switch is pressed (since it's Pull-up)
            GPIOF->DATA |= RED_LED;         // Turn on the LED
        } else {                            // If the switch is not pressed
            GPIOF->DATA &= ~RED_LED;        // Turn off the LED
        }
    } 
}

Explanation:

  • GPIOF->PUR |= SWITCH; enables the internal pull-up resistor on PF4.
  • The while(1) loop continuously reads the switch state.
  • When state == 0, the button is pressed (pull-up makes it active-low).
  • The LED is controlled directly in the main loop without interrupts.

Example 2: Interrupt-Driven Switch Input ​

This example configures SW1 and SW2 to generate interrupts on button presses and toggles the green LED in the ISR.

c
#include "TM4C123.h"   

#define GREEN_LED 0x08
#define SW1 0x10
#define SW2 0x01

int main(void) 
{ 
    SYSCTL->RCGCGPIO |= (1<<5);             // Enable clock to GPIOF

    GPIOF->LOCK = 0x4C4F434B;               // unlock commit register
    GPIOF->CR = 0x01;                       // make PORTF0 configurable


    // PINS Configurations
    GPIOF->DIR &= ~(SW1 | SW2);             // Set SW1, SW2 as input pins
    GPIOF->DIR |= GREEN_LED;                // Set GREEN_LED as output pin

    GPIOF->DEN |= (GREEN_LED | SW1 | SW2);  // Enable digital function for GREEN_LED, SW1, SW2
    GPIOF->PUR |= (SW1 | SW2);              // Enable pull-up resistors on SW1, SW2

    // Interrupt Configurations
    GPIOF->IS  &= ~(SW1 | SW2);             // SW1, SW2 are edge-sensitive
    GPIOF->IBE &= ~(SW1 | SW2);             // SW1, SW2 are not both edges
    GPIOF->IEV &= ~(SW1 | SW2);             // falling edge trigger
    GPIOF->ICR |= (SW1 | SW2);              // clear any prior interrupt
    GPIOF->IM  |= (SW1 | SW2);              // unmask interrupt

    // Enable Interrupts
    NVIC->ISER[0] |= (1<<30);       				// enable interrupt 30 in NVIC
    // NVIC_EnableIRQ(GPIOF_IRQn);  				// Alternative way using CMSIS function
    while(1) 
    { 
    } 
} 

void GPIOF_Handler(void) {  
    if (GPIOF->MIS & SW1) {                 // check if interrupt causes by PF4/SW1
        GPIOF->DATA |= GREEN_LED;           // turn on green LED
        GPIOF->ICR |= SW1;                  // clear the interrupt flag
    }  
    else if (GPIOF->MIS & SW2) {            // check if interrupt causes by PF0/SW2
        GPIOF->DATA &= ~GREEN_LED;          // turn off green LED
        GPIOF->ICR |= SW2;                  // clear the interrupt flag
    } 
}

Explanation:

  • GPIOF->LOCK = 0x4C4F434B; unlocks Port F for PF0 configuration.
  • GPIOF->CR = 0x01; allows changes to PF0.
  • GPIOF->IS &= ~(SW1 | SW2); configures edge-sensitive interrupts.
  • GPIOF->IEV &= ~(SW1 | SW2); selects falling-edge trigger (button press).
  • GPIOF->ICR |= (SW1 | SW2); clears any prior interrupt flags before enabling.
  • GPIOF->IM |= (SW1 | SW2); unmasks (enables) interrupts for SW1 and SW2.
  • NVIC->ISER[0] |= (1<<30); enables GPIO Port F interrupt in NVIC.
  • The ISR checks GPIOF->MIS to identify which switch caused the interrupt.
  • Each interrupt flag must be cleared with GPIOF->ICR to prevent re-triggering.

Tasks ​

Task 1: Toggle LED Using Polling ​

Modify Example 1 to toggle the green LED (PF3) with each press of SW1 (PF4). The LED should change state (ON→OFF or OFF→ON) every time the button is pressed and released.

Requirements:

  • Use polling to detect button presses.
  • Implement software debouncing by adding a delay after detecting a press.
  • Toggle the LED state instead of simply turning it on or off.
  • Ensure the LED changes state only once per button press.

Task 2: LED Sequence Using Interrupts ​

Modify Example 2 to cycle through LED colors using interrupts:

  • Pressing SW1 (PF4) cycles through: Red β†’ Blue β†’ Green β†’ Red...
  • Pressing SW2 (PF0) cycles through: Yellow β†’ Magenta β†’ Cyan β†’ Yellow...

Requirements:

  • Use interrupt-driven input handling.
  • Maintain separate state variables for each button's LED sequence.
  • Update the LED color in the ISR based on the current state.
  • Clear interrupt flags properly to avoid repeated triggering.

Hint: Use a global variable (e.g., sw1_state) to track the current position in the sequence. In the ISR, increment the state and use a switch-case or modulo operation to cycle through colors. Refer to the LED color table in Experiment 4 for LED color codes.