Tiva-C Launchpad GPIO Interrupts
In the previous tutorials we demonstrated how to configure GPIOs on TM4C123GXL as a Digital Input/Output. In this tutorial we will combine both of them in a single project and adding an additional feature to it. i.e. Instead of manually continuously polling SW2 (PF.0) to check whether push button has pressed or not, we will add interrupt based approach to be trigger each time button is pressed. Doing this there will be no need to continuously poll button state thus feeing processor for other jobs.
Before proceeding further with this tutorial, it is highly recommended to go through at-least one of the following previous tutorials. This is because we will not explain GPIO configuration as an input/output which are covered in these tutorials. Link to the tutorials are given bellow.
In this tutorial we will configure PF.0 as digital Input to read on-board push button (SW2) connected to it. From TM4C123GXL reference manual, the on-board SW2 is connected to PF.0 pin as shown in Figure-1. Upon button press an interrupt will be generated which will subsequently toggle the on-board Red LED.
This tutorial has the following main configurations.
- Configuring PF.1 as a Digital output for Red LED – covered in previous tutorial.
- Configuring PF.0 as a Digital input for reading push button SW2 – covered in previous tutorial.
- Enabling Edge triggered Interrupt for PF.0. This is covered in this tutorial.
- Defining ISR for PF.0 that will toggle LED. This is covered in this tutorial.
GPIOF is interfaced on APB bus with ARM Cortex-M4 core. Configuring interrupt for PF.0 requires configuration on both GPIOF side and ARM Cortex-M4 NVIC side- Figure-2.
Following are the interrupts configuration steps on GPIO Side.
1. Edge/Level Detection:
GPIO interrupts can be configured to be either edge triggered (either rising or falling edges or both) or level triggered (either on High or Low). It purely depends on application requirements. In our case both conditions are applicable.
Let’s see what happens when push button is pressed.
- PF.0 Remains at Logic-1 (high) – Figure-3(a)
- As soon as the button is pressed, PF.0 get connected to Ground (0V) which brings PF.0 at logic-0 (Low) – Figure-3(b).
- The response Figure-3(b) is an IDEAL response. In reality button press goes through some ripples i.e. bouncing up/down for microseconds before getting stable. This is due to mechanical parts movement. This causes multiple button presses – Figure-3(c). The effect is called button bounce effect.
For the purpose of this tutorial we will configure interrupt for PF.0 as edge triggered as it is the transition point between SW2 released and being pressed.
The edge trigging can be selected for a GPIO pin via GPIO Interrupt Sense (GPIOIS) Register – Figure-4.
- 0: The edge on the corresponding pin is detected (edge-sensitive).
- 1: The level on the corresponding pin is detected (level-sensitive).
As we want PF.0 interrupt to be edge sensitive so let’s clear bit-0 of GPIOIS register.
GPIOIS_APB_REG EQU 0x40025404 ; enable edge detection on PF.0 LDR R1, =GPIOIS_APB_REG LDR R0, [R1] AND R0, R0, #0x3E ; clear bit-0 STR R0, [R1]
2. Edge Selection:
Once we decided that Interrupt needs to be edge triggered, its time to select which edge (Rising/Falling) should trigger interrupt. Also option of interrupt triggering on both edges is also available. As we don’t need to detect both edges so lets first disable both edges detection.
Interrupt on both edges can be enabled/disabled via GPIO Interrupt Both Edges (GPIOIBE) Register – Figure-5.
- 0: Only one edge trigger an interrupt.
- 1: Both edges on the corresponding pin trigger an interrupt.
To disable both edge interrupt trigger for PF.0, let’s clear bit-0 of GPIOIBE Register.
GPIOIBE_APB_REG EQU 0x40025408 ; Interrupt generation is controlled by GPIOIEV reg LDR R1, =GPIOIBE_APB_REG LDR R0, [R1] AND R0, R0, #0x3E ; clear bit-0 STR R0, [R1]
Now that we have disabled interrupt triggering on both edges for PF.0, its time to select which edge either Rising or Falling edge must trigger the interrupt. Specific edge can be selected via GPIO Interrupt Event (GPIOIEV) Register- Figure-6.
- 0: A falling edge or a Low level on the corresponding pin triggers an interrupt.
- 1: A rising edge or a High level on the corresponding pin triggers an interrupt.
As can be seen from Figure-3 (b),(c); when button is pressed, PF.0 goes from High-to-Low i.e. A falling edge in between two states. So we need to detect the falling edge. Let’s do it by clearing bit-0 of GPIOIEV register.
GPIOIBE_APB_REG EQU 0x4002540C ; falling edge (button pressed) generate interrupt LDR R1, =GPIOIEV_APB_REG LDR R0, [R1] AND R0, R0, #0x3E ; clear bit-0 STR R0, [R1]
3. Enable Interrupt on GPIO side:
This was all the configuration we need to configure an interrupt for a GPIO pin. Now that we are done with the configuration, its time to enable interrupt on GPIO side – Figure-2.
Interrupt for a specific GPIO pin can be enabled/disabled via GPIO Interrupt Mask (GPIOIM) Register- Figure-6.
- 0: The interrupt from the corresponding pin is masked.
- 1: The interrupt from the corresponding pin is sent to the interrupt controller.
Let’s enable interrupt for PF.0.
GPIOIM_APB_REG EQU 0x40025410 ; enable interrupt for PF.0 LDR R1, =GPIOIM_APB_REG LDR R0, [R1] ORR R0, R0, #0x01 ; set bit-0 STR R0, [R1]
4. Enable Interrupt at NVIC side:
Now that we have successfully configured GPIO to detect falling edge and generate an interrupt. But the interrupt will only reach ARM Cortex-M core once its also enabled on NVIC side – Figure-2. If you don’t know about ARM NVIC, refer to the following tutorial.
Interrupt in NVIC can be enabled/disabled via ENx (where x=0-4) Registers – Figure-7. Each of ENx register is capable of enabling/disabling 32 interrupts (1-bit for each interrupt). Each Interrupt is assigned a number – see Table 2-9 (Pg#105) in TM4C123GH6PM datasheet . In order to enable an interrupt, respective bit in one of the ENx register needs to be set as per the following interrupts distribution.
- EN0 = Interrupt 0-31.
- EN1 = Interrupt 32-63.
- EN2 = Interrupt 64-95.
- EN3 = Interrupt 96-127.
- EN4 = Interrupt 128-138.
- 0: Interrupt is disabled.
- 1: Interrupt is enabled.
From Table 2-9 (Pg#105) in TM4C123GH6PM datasheet , the interrupt No for GIPOF port is 30 – Figure-8, which is covered by EN0(Interrupt 0-31).
Let’s enable Interrupt for Port-F in NVIC. Remember this will configure interrupts for all pins of GPIOF. Its user responsibility to check which GPIO pin has triggered interrupt within ISR.
; nvic registers NVIC_EN0_REG EQU 0xE000E100 ; register values GPIOF_NVIC_BIT EQU 0x40000000 ; enable GPIO-F interrupt at NVIC side ; assuming the core in previllaged mode LDR R1, =NVIC_EN0_REG LDR R0, =GPIOF_NVIC_BIT STR R0, [R1]
5. GPIOF ISR:
That’s pretty much everything we needed to configure. Now we need an ISR which will be called once interrupt is triggered. From TM4C123GH6PM startup file in Keil, the ISR name for GPIOF is
GPIOF_Handler ISR two thing are done.
1) Interrupt is cleared so that next interrupt can call the ISR.
2) Red LED (PF.1) is toggled.
The following code snippet shows
GPIOF_Handler ISR which will be called each time Push button SW2 (PF.0) is pressed.
GPIOF_Handler PROC EXPORT GPIOF_Handler ; assuming we are only expecting PF.0 interrupt from GPIO-F ; in case of multiple interrupts turned ON, a check is required ; to see which interrupt event has occurred ; clear the interrupt LDR R1, =GPIOICR_APB_REG LDR R0, [R1] ORR R0, R0, #0x1 ; set bit-0 STR R0, [R1] ; read data register value for PF.1 LDR R1, =GPIOFDATA_APB_REG LDR R0, [R1] EOR R0, R0, #0x2 STR R0, [R1] BX LR ENDP
For complete source code refer to the Github links given at the start of this tutorial.
The irregular toggle of LED is due to push button bounce effect as shown in Figure-2(c).