Skip to content

GPIO (General Purpose Input/Output) External Interrupts ​

Introduction ​

In the previous experiment, we learned how to setup GPIO pins and used them to control LEDs. In this experiment, we will learn how to use GPIO pins as inputs (switches, sensors, etc.) and how to configure them to generate external interrupts. We will use the switches on the LaunchPad to generate interrupts and toggle the LEDs.

Components ​

  • Ek-TM4C123GXL LaunchPad
  • USB A to Micro-B cable

Switch Bouncing and Debouncing ​

When a mechanical switch is pressed or released, the contacts of the switch bounce before settling down. This bouncing can cause multiple interrupts to be generated for a single press or release event. To avoid this, we need to debounce the switch. Debouncing is the process of removing the noise caused by the bouncing of the switch contacts.

There are two ways to debounce a switch:

  • Hardware Debouncing: In hardware debouncing, a capacitor is connected in parallel with the switch to filter out the noise.
  • Software Debouncing: In software debouncing, we use a timer/delay to wait for a certain amount of time before reading the state of the switch.

In this experiment, we will use software debouncing to debounce the switches.

alt text

Switch configuration ​

The switches on the LaunchPad are connected to the GPIO pins of port F. We will configure the switches as inputs and enable the internal pull-up resistors. The internal pull-up resistors will pull the pins high when the switches are open. When the switches are closed, the pins will be pulled low, pulling the pin (high/low) is essential as a floating pin can cause false interrupts/readings.

Registers used for switch configuration ​

  1. GPIODIR GPIO Direction register: Used to set the direction of the pins in the port. Writing a 1 to a bit in the register will set the corresponding pin to output, and writing a 0 will set the pin to input.
  2. GPIODEN GPIO Digital Enable register: Used to enable the digital functionality of the pins in the port. Writing a 1 to a bit in the register will enable the digital functionality of the corresponding pin, and writing a 0 will disable the digital functionality.
  3. GPIOPUR GPIO Pull-Up register: Used to enable the internal pull-up resistors of the pins in the port. Writing a 1 to a bit in the register will enable the pull-up resistor of the corresponding pin, and writing a 0 will disable the pull-up resistor.
  4. GPIOPDR GPIO Pull-Down register: Used to enable the internal pull-down resistors of the pins in the port. Writing a 1 to a bit in the register will enable the pull-down resistor of the corresponding pin, and writing a 0 will disable the pull-down resistor.

External Interrupts ​

An external interrupt is an interrupt generated by an external device or peripheral. In this experiment, we will configure the GPIO pins connected to the switches as external interrupt sources. We will use the GPIO ports' interrupt registers to configure the pins to generate interrupts on the rising edge, falling edge, or both.

Registers used for external interrupts ​

  1. GPIOIS GPIO Interrupt Sense register: Used to set the interrupt detection type (level or edge) for the pins in the port. Writing a 1 to a bit in the register will set the corresponding pin to level-sensitive, and writing a 0 will set the pin to edge-sensitive.
  2. GPIOIBE GPIO Interrupt Both Edges register: Used to enable interrupts on both edges of the pins in the port. Writing a 1 to a bit in the register will enable interrupts on both edges of the corresponding pin, and writing a 0 will disable interrupts on both edges.
  3. GPIOIEV GPIO Interrupt Event register: Used to set the interrupt event type (rising or falling edge) for the pins in the port. Writing a 1 to a bit in the register will set the corresponding pin to rising edge, and writing a 0 will set the pin to falling edge.
  4. GPIOIM GPIO Interrupt Mask register: Used to enable/disable interrupts for the pins in the port. Writing a 1 to a bit in the register will enable the interrupt for the corresponding pin, and writing a 0 will disable the interrupt.
  5. GPIOMIS GPIO Masked Interrupt Status register: Used to read the masked interrupt status of the pins in the port. Reading 1 from a bit in the register indicates that the corresponding pin has caused an interrupt.
  6. GPIOICR GPIO Interrupt Clear register: Used to clear the interrupt flag for the pins in the port. Writing a 1 to a bit in the register will clear the interrupt flag for the corresponding pin.
  7. NVICEN0 Nested Vector Interrupt Controller Enable register: Used to enable the interrupt in the Nested Vector Interrupt Controller (NVIC). Writing a 1 to a bit in the register will enable the interrupt in the NVIC. The port F interrupt is connected to the NVIC interrupt number 30.

GPIO PINS with Special Considiration ​

The GPIOCR register has a built-in safeguard to prevent accidental reconfiguration of pins that are critical for NMI (Non-Maskable Interrupt) and JTAG/SWD (Serial Wire Debug) connectivity. By default, the NMI and JTAG/SWD pins in the GPIOCR register are set to 0, meaning they are protected from unintended modifications. To intentionally repurpose these pins for GPIO functionality, specific steps must be taken to write to the GPIOLOCK, GPIOCR, and associated registers (refer to the "Signal Tables" on page 1329 for the relevant pin numbers).

Since this protection applies only to the NMI and JTAG/SWD pins, the other bits in the GPIOCR registers are hardwired to 1. This ensures that you can always commit new values to control registers like GPIOAFSEL, GPIOPUR, GPIOPDR, and GPIODEN for non-critical pins without special unlocking steps.

If you need to unlock certain pins, such as GPIO pin 0 of port F, write 0x4C4F434B to the GPIOLOCK register. Then, set the appropriate GPIOCR register bit to 1 to enable configuration.

alt text

Examples ​

Example 1: Reading input using Polling ​

polling.c
c
//Program 1 
#include "TM4C123GH6PM.h" 
int main(void) { 
    unsigned int state; 
    SYSCTL->RCGCGPIO |= 0x20;   /* enable clock to GPIOF */ 
    GPIOF->LOCK = 0x4C4F434B;   // unlockGPIOCR register 
    GPIOF->CR = 0x01;           
    // Enable GPIOPUR register enable to commit 
    GPIOF->PUR |= 0x10;        
    GPIOF->DIR |= 0x02;          
    GPIOF->DEN |= 0x12;         
    // Enable Pull Up resistor PF4 
    //set PF1 as an output and PF4 as an input pin 
    // Enable PF1 and PF4 as a digital GPIO pins  
    while(1) {    
        state = GPIOF->DATA & 0x10; 
	if (state == 0) {
	    GPIOF->DATA |= 0x2;
	} else {
	    GPIOF->DATA = 0x0;
	}
    } 
}

Example 2: External Interrupts ​

interrupt.c
c
//Program 2 
/*PORTF PF0 and PF4 fall edge interrupt example*/ 
/*This GPIO interrupt example code controls green LED with switches SW1 and SW2 external interrupts */ 
#include "TM4C123.h"                    
int main(void) 
{ 
    SYSCTL->RCGCGPIO |= (1<<5);   /* Set bit5 of RCGCGPIO to enable clock to PORTF*/ 
        
    /* PORTF0 has special function, need to unlock to modify */ 
    GPIOF->LOCK = 0x4C4F434B;   /* unlock commit register */ 
    GPIOF->CR = 0x01;           /* make PORTF0 configurable */ 
    GPIOF->LOCK = 0;            /* lock commit register */ 


    /*Initialize PF3 as a digital output, PF0 and PF4 as digital input pins */ 

    GPIOF->DIR &= ~(1<<4)|~(1<<0);  /* Set PF4 and PF0 as a digital input pins */ 
    GPIOF->DIR |= (1<<3);           /* Set PF3 as digital output to control green LED */ 
    GPIOF->DEN |= (1<<4)|(1<<3)|(1<<0);             /* make PORTF4-0 digital pins */ 
    GPIOF->PUR |= (1<<4)|(1<<0);             /* enable pull up for PORTF4, 0 */ 
        
    /* configure PORTF4, 0 for falling edge trigger interrupt */ 
    GPIOF->IS  &= ~(1<<4)|~(1<<0);        /* make bit 4, 0 edge sensitive */ 
    GPIOF->IBE &=~(1<<4)|~(1<<0);         /* trigger is controlled by IEV */ 
    GPIOF->IEV &= ~(1<<4)|~(1<<0);        /* falling edge trigger */ 
    GPIOF->ICR |= (1<<4)|(1<<0);          /* clear any prior interrupt */ 
    GPIOF->IM  |= (1<<4)|(1<<0);          /* unmask interrupt */ 
        
    /* enable interrupt in NVIC and set priority to 3 */ 
    // NVIC->IP[30] = 3 << 5;     /* set interrupt priority to 3 */ 
    NVIC->ISER[0] |= (1<<30);  /* enable IRQ30 (D30 of ISER[0]) */ 
     
    while(1) 
    { 
    } 
} 
 
/* SW1 is connected to PF4 pin, SW2 is connected to PF0. */ 
/* Both of them trigger PORTF falling edge interrupt */ 
void GPIOF_Handler(void) {  
    if (GPIOF->MIS & 0x10) { /* check if interrupt causes by PF4 SW1*/    
        GPIOF->DATA |= (1<<3); 
        GPIOF->ICR |= 0x10; /* clear the interrupt flag */ 
    }  
    else if (GPIOF->MIS & 0x01) {  /* check if interrupt causes by PF0/SW2 */ 
       
        GPIOF->DATA &= ~0x08; 
        GPIOF->ICR |= 0x01; /* clear the interrupt flag */ 
    } 
}

Labwork ​

1. Modify Program 1 (using polling technique) to toggle the green LED with the press of a switch SW1.
The switch on PF4 will be configured as input, and the LED on PF3 (green LED) will be used as output.
At each press of the switch, the LED will toggle its present state — i.e., the LED will turn ON if it was OFF previously.

Note: The needed time for the user to press the push button is approximately 200 ms.
The speed of the TM4C123G controller is very high, so the while (true) loop will be executed many times during this period (200 ms).
This means the button may appear to have been pressed many times, though the user pressed it only once.
Therefore, some delay is required after detecting a button click.


2. Modify Program 2 (using interrupt technique) so the onboard LEDs light on in the following sequence R → B → G, continuously,
whenever the onboard SW1 is pressed. On the other hand, the LEDs should light up in the reverse sequence G → B → R, continuously,
when SW2 is pressed. Each LED should stay ON for the same amount of time (e.g., around 0.5 seconds), and the sequence should keep repeating infinitely.


3. Write a program that changes the color of the onboard LED using the two onboard push button keys.
When the board is turned on, only the RED LED should be ON.

  • When the right-side key is pressed, the GREEN LED should be ON (alone).
  • When the left-side key is pressed, the BLUE LED should be ON (alone)