Tiva-C Launchpad GPIO Interrupts

Keywords:Embedded systems, ARM, TM4C123GXL, GPIO

Code Link: Source Code Github Keil MDK5 – ARM Assembly

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.

Tutorial Scenario:

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.

Figure-1: Red LED and SW2 interfacing to GPIO PF.0,1

This tutorial has the following main configurations.

  1. Configuring PF.1 as a Digital output for Red LED – covered in previous tutorial.
  2. Configuring PF.0 as a Digital input for reading push button SW2 – covered in previous tutorial.
  3. Enabling Edge triggered Interrupt for PF.0. This is covered in this tutorial.
  4. 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.

Figure-2: Enabling Interrupt for GPIOx

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.

Figure-3: Button bounce effect

  1. PF.0 Remains at Logic-1 (high) – Figure-3(a)
  2. 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).
  3. 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.

Figure-3: GPIO Interrupt Sense (GPIOIS) Register

  • 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.

Figure-5: GPIO Interrupt Both Edges (GPIOIBE)

  • 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.

Figure-5: GPIO Interrupt Event (GPIOIEV) Register

  • 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.

Figure-6: GPIO Interrupt Mask (GPIOIM) Register

  • 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 [2]. 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.
Figure-7: Set Enable (ENx) Register

  • 0: Interrupt is disabled.
  • 1: Interrupt is enabled.

From Table 2-9 (Pg#105) in TM4C123GH6PM datasheet [2], the interrupt No for GIPOF port is 30 – Figure-8, which is covered by EN0(Interrupt 0-31).

Figure-8: GPIOF Interrupt Entry in Vector Table

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.

Within 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

Note: This tutorial doesn’t cover GPIO configuration as a Digital input (required for PF.0) and as a Digital output (required for PF.1). These are covered in the tutorials here  and  here.

For complete source code refer to the Github links given at the start of this tutorial.

Video Demonstration:

The irregular toggle of LED is due to push button bounce effect as shown in Figure-2(c).

References:



58 thoughts on “Tiva-C Launchpad GPIO Interrupts”

Leave a Reply

Your email address will not be published. Required fields are marked *