Actions

EmSys

TM4C123 GPIO Port Interrupt Programming

From EdWiki

Revision as of 11:05, 12 March 2020 by Jshankar (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

GPIO Port Interrupt Programming

Interrupt numbers 16 to 255 are assigned to the peripherals. The INT (IRQ) 46 is assigned to the GPIO Port of F. Although PortF has 8 pins, we have only one interrupt assigned to the entire PortF. In other words, when any of the PortF pins trigger an interrupt, they all go to the same address location in the interrupt vector table. It is the job of our Interrupt Service Routine (ISR or interrupt Handler) to find out which pin caused the interrupt.

Interrupt trigger point

When an input pin is connected to an external device to be used for interrupt, we have 5 choices for trigger point. They are:

  • low-level trigger (active Low level),
  • high-level trigger (active High level),
  • rising-edge trigger (positive-edge going from Low to High),
  • falling-Edge trigger (negative-edge going from High to Low),
  • Both edge (rising and falling) trigger.

Upon Reset, all the interrupts are disabled. To enable any interrupt:

  1. Enable the interrupt for a specific peripheral module.
  2. Enable the interrupts at the NVIC module.
  3. Enable the interrupt globally

GPIO Interrupt Control Registers

GPIO Register Tivaware Name Each Bit Value (Lowest 8-Bit) and Each Pin Function
GPIOIS GPIO_PORTx_IS_R Interrupt sense register
Determines level or edge triggered
0: Detect an edge (edge-sensitive) on the pin,
1: Detect a level (level-sensitive) on the pin.
GPIOIBE GPIO_PORTx_IBE_R 0: Interrupt is controlled by GPIOIEV,
1: Both edges on the corresponding pin trigger an interrupt
GPIOIEV GPIO_PORTx_IEV_R GPIO Interrupt Event Register
Determines the detecting edges or levels.
0: A falling edge or a LOW level,
1: A rising edge or a HIGH level triggers an interrupt
GPIOIM GPIO_PORTx_IM_R GPIO Interrupt Mask Register
Masks (disables) or unmask (enable) an interrupt.
0: Interrupt is masked (disabled),
1: Interrupt is unmasked (enabled).
GPIORIS GPIO_PORTx_IS_R GPIO Raw Interrupt Status Register
Indicates the raw interrupt status for a pin.
0: No interrupt occurred on the pin,
1: An interrupt is occurred on the pin.
For the edge-triggered interrupts,
write a 1 to the pin to clear that interrupt.
For level-triggered interrupt, no action is needed.
GPIOMIS GPIO_PORTx_MIS_R GPIO Masked Interrupt Status Register
Indicates the state of the interrupt.
0: No interrupt occurred or the pin has been masked,
1: An interrupt has been occurred.
GPIOICR GPIO_PORTx_ICR_R GPIO Interrupt Clear Register
Clears an edge-triggered interrupt.
0: No action,
1: The corresponded edge-triggered interrupt is cleared.
Table: The bit values and functions for GPIO interrupt controls.
  • All of these registers are 32-bit, but only lowest 8 bits are used and each bit corresponds to each pin in the selected GPIO Port: bit 0 is for pin 0, bit 1 is for pin 1, and so on. The above table shows the bit values and their functions for these registers.
  • Before any exception or interrupt can be applied to any pin on any GPIO Port, all GPIO pins on selected GPIO Port should be initialized and configured via related GPIO registers.

GPIO Interrupt Control Registers Description

GPIO Interrupt sense register (GPIOIS)

Tm4c gpiois r.png

Bit Bit Name Description
7-0 IS GPIO Interrupt Sense
0: The edge on the corresponding pin is detected (edge-sensitive).
1: The level on the corresponding pin is detected (level-sensitive).

First, we must use GPIO Interrupt Sense (GPIOIS) register to decide the level or edge. Only after using the GPIOIS register we need to indicate which level or edge. To do that, we use the GPIO Interrupt Event (GPIOIEV) to decide low-level, high-level, falling, or rising-edge. The GPIO Interrupt Both Edges (GPIOIBE) register bits overwrite the decision in GPIOIEV. Unless both edge interrupt is desired, the bit in GPIOIBE needs to be cleared.

GPIO Interrupt Event Register (GPIOIEV)

Tm4c gpioiev r.png

GPIOIS
(interrupt sense)
GPIOIEV
(Interrupt Event)
0
0
Falling edge
0
1
Rising edge
1
0
Low level
1
1
High level
Table 7.4: Using GPIOIM and GPIOIEV Registers.
  • Since we need a rising edge triggered interrupt at PF4, so writing 1 to the respective bit field will do the same for us.

GPIO Interrupt Both Edge (GPIOIBE)

Tm4c gpioibe r.png

Bit Bit Name Description
7-0 IBE GPIO Interrupt Both Edges
0: Interrupt generation is controlled by the GPIO Interrupt Event (GPIOIEV) register
1: Both edges on the corresponding pin trigger an interrupt


  • Setting the corresponding bit field enables the interrupts for both edges i.e. rising edge and falling edge but our concern is to enable the interrupts for rising edge only. Making the corresponding bit field i.e. PF4 to 0 will allow us to use this register in conjunction with the GPIOIEV register.

GPIO Interrupt Clear Register (GPIOICR)

Tm4c gpioicr r.png

  • The corresponding bit fields in this register clears the interrupt for the respective pin. To ensure that any previous interrupt has been cleared writing 1 to the respective bit field will clear the interrupt on that pin.
  • It is critical that the interrupt handler clears the interrupt flag before returning from interrupt handler. Otherwise the interrupt appears as if it is still pending and the interrupt handler will be executed again and again forever and the program hangs.

GPIO Interrupt Mask Register (GPIOIM)

Tm4c gpioim r.png

  • We need to enable the interrupt capability of a given peripheral at the module level. This should be done after other configurations of that peripheral are done. In the case of I/O ports, each pin can be used as a source of external hardware interrupt. This is done with the GPIO Interrupt Mask (GPIOIM) register.
  • Notice that, the lower 8 bits of this register is used to enable the interrupt capability of each pin of the I/O port. To enable the interrupts for PF0 and PF4 pins, we will need the following:
GPIO_PORTF_IM_R |= 0x11;  /* unmask interrupt */

GPIO Raw Interrupt Status (GPIORIS)

Tm4c gpioris r.png


Bit Bit Name Description
7-0 RIS GPIO Interrupt Raw Status
0: An interrupt condition has not occurred on the corresponding pin.
1: An interrupt condition has occurred on the corresponding pin.


  • For edge-detect interrupts, this bit is cleared by writing a 1 to the corresponding bit in the GPIOICR register.
  • For a GPIO level-detect interrupt, the bit is cleared when the level is deasserted.

GPIO Masked Interrupt Status (GPIOMIS)

Tm4c gpiomis r.png


Bit Bit Name Description
7-0
MIS
GPIO Masked Interrupt Status
0: An interrupt condition on the corresponding pin is masked or has not occurred.
1: An interrupt condition on the corresponding pin has triggered an interrupt to the interrupt controller.


  • For edge-detect interrupts, this bit is cleared by writing a 1 to the corresponding bit in the GPIOICR register.
  • For a GPIO level-detect interrupt, the bit is cleared when the level is deasserted.

NVIC Interrupt Priority Register

TM4C Interrupt Priority.jpg

Bit/Field Name Description
7:5 INTA Interrupt Priority for Interrupt [4n]
This field holds a priority value, 0-7, for the interrupt with the number [4n], where n is the number of the Interrupt Priority register (n=0 for PRI0, and so on). The lower the value, the greater the priority of the corresponding interrupt.
15:13 INTB Interrupt Priority for Interrupt [4n+1]
This field holds a priority value, 0-7, for the interrupt with the number [4n+1], where n is the number of the Interrupt Priority register (n=0 for PRI0, and so on). The lower the value, the greater the priority of the corresponding interrupt.
23:21 INTC Interrupt Priority for Interrupt [4n+2]
This field holds a priority value, 0-7, for the interrupt with the number [4n+2], where n is the number of the Interrupt Priority register (n=0 for PRI0, and so on). The lower the value, the greater the priority of the corresponding interrupt.
31:29 INTD Interrupt Priority for Interrupt [4n+3]
This field holds a priority value, 0-7, for the interrupt with the number [4n+3], where n is the number of the Interrupt Priority register (n=0 for PRI0, and so on). The lower the value, the greater the priority of the corresponding interrupt.


PRIn Register Bit Field Interrupt Source Priority Register Macros
Bits 31:29 Interrupt[IRQ] = Interrupt[4n+3]
NVIC_PRIn_R
Bits 23:21 Interrupt[IRQ] = Interrupt[4n+2]
Bits 15:13 Interrupt[IRQ] = Interrupt[4n+1]
Bits 7:5 Interrupt[IRQ] = Interrupt[4n]
Table 7.5: Priority register bit fields.
  • Table 7.5 represents the priority register bit fields against the interrupt sources. This priority register bit field is 3-bits wide which means that for an interrupt there can be eight priority levels from 000 to 111 and it can be programmed as per the need.
  • n represents the group number of priority registers, for each group n registers NVIC_PRIn can control up to 4 peripheral ranging from 4n to 4n+3.
    To understand this better just take an example, suppose that for an interrupt handler whose IRQ number is 0, in order to satisfy the equation interrupt[4n]=0 the value of n must be zero which corresponds to the NVIC_PRI0_R also this same register can configure the priority levels for 4n to 4n+3 peripherals.
  • In this case the value of n is 0 therefore the same priority level register can be used to configure the interrupts whose IRQ Number are within 4×0 to 4×0+3, which corresponds to the IRQ number 0,1,2,3.
  • In tm4c123gh6pm_startup_ccs_gcc.c file the IRQ number 0 to 3 represents the interrupt handlers for GPIOA to GPIOD respectively. In a program for each interrupt the priority level can be set in the corresponding bit fields.

Table 7.6 shows some of the priority registers on the NVIC. Each register contains an 8-bit priority field for four devices. On the TM4C micro controllers, only the top three bits of the 8-bit field are used. This allows us to specify the interrupt priority level for each device from 0 to 7, with 0 being the highest priority.

Address 31 - 29 23 - 21 15 - 13 7 - 5 Name
0xE000E400 GPIO Port D GPIO Port C GPIO Port B GPIO Port A NVIC_PRI0_R
0xE000E404 SSI0, Rx Tx UART1, Rx Tx UART0, Rx Tx GPIO Port E NVIC_PRI1_R
0xE000E408 PWM Gen 1 PWM Gen 0 PWM Fault I2C0 NVIC_PRI2_R
0xE000E40C ADC Seq 1 ADC Seq 0 Quad Encoder 0 PWM0 Gen 2 NVIC_PRI3_R
0xE000E410 Timer 0A Watchdog ADC Seq 3 ADC Seq 2 NVIC_PRI4_R
0xE000E414 Timer 2A Timer 1B Timer 1A Timer 0B NVIC_PRI5_R
0xE000E418 Comp 2 Comp 1 Comp 0 Timer 2B NVIC_PRI6_R
0xE000E41C GPIO Port G GPIO Port F Flash Control System Control NVIC_PRI7_R
0xE000E420 Timer 3A SSI1, Rx Tx UART2, Rx Tx GPIO Port H NVIC_PRI8_R
0xE000E424 CAN0 Quad Encoder 1 I2C1 Timer 3B NVIC_PRI9_R
0xE000E428 Hibernate Ethernet CAN2 CAN1 NVIC_PRI10_R
0xE000E42C uDMA Error uDMA Soft Tfr PWM Gen 3 USB0 NVIC_PRI11_R
0xE000ED20 SysTick PendSV --- Debug NVIC_SYS_PRI3_R
Table 7.6: Most popular priority registers used in the TM4C123GH6PM NVIC.
  • The interrupt number is loaded into the IPSR register. The servicing of interrupts does not set the I bit in the PRIMASK, so a higher priority interrupt can suspend the execution of a lower priority ISR.
  • If a request of equal or lower priority is generated while an ISR is being executed, that request is postponed until the ISR is completed. In particular, those devices that need prompt service should be given high priority.

Enabling and Disabling an Interrupt

Upon Reset, all the interrupts are disabled. To enable any interrupt we should:

  1. Enable the interrupt for a specific peripheral module.
    This is done with the GPIO Interrupt Mask (GPIOIM) register.
  2. Enable the interrupts at the NVIC module.
  3. Enable the interrupt globally .

Interrupt enabling with all 3 levels

Tm4c123 int enable 3level.png

Figure:Interrupt enabling with all 3 levels


Tm4c gpiom.png

Figure:GPIO Interrupt Mask (GPIOIM)

Interrupt Set Enable Register

It is the interrupt set enable register ranging from NVIC_EN0_R ... NVIC_EN3_R, each ISER register is 32 bit wide that can be used to set the interrupt against the respective IRQ numbers. Each ISER register can be used to enable 32 different types of interrupt sources. For example NVIC_EN0_R is used to enable the interrupt sources whose IRQ numbers are 0-31, similarly the interrupt sources whose IRQ numbers are 32-63 can be enabled by NVIC_EN1_R and so on. The corresponding bit field is required to be set according to the IRQ number of the interrupt sources since each register is 32 bit wide. If the interrupt source whose IRQ number is greater than 31 the corresponding bit number can be calculated by this formula:

bit number = IRQ number - 32(n-1) 

where n=1 for interrupt sources having IRQ number 0-31. Similarly n=2 for interrupt sources having IRQ number 32-63 and so on. For enabling interrupt at PF4 pin writing 1 to the bit field 30 of NVIC_EN0_R will do the same for us, as its IRQ number is 30.

To disable interrupts there are another registers: NVIC_DIS0_R to NVIC_DIS3_R (Interrupt Clear Enable). Writing zeros to the NVIC_EN0_R through NVIC_EN3_R registers has no effect. To disable interrupts we write ones to the corresponding bit in the NVIC_DIS0_R through NVIC_DIS3_R register.

Enable Register 32-Enable Bits Address
0
1
2
3
4
5
6-29
30
31
NVIC_EN0_R PORTA PORTB PORTC PORTD PORTE UART0 ... PORTF PORTG 0xE000E100
NVIC_EN1_R PORTH UART2 SSI1 Timer3A Timer3B I2C1 ... UART6 UART7 0xE000E104
NVIC_EN2_R ... ... ... ... I2C2 I2C3 ... WTimer0A WTimer0B 0xE000E108
NVIC_EN3_R WT1A WT1B WT2A WT2B WT3A WT3B ... GPIOQ2 GPIOQ3 0xE000E10C
Table 7.7: Relationship between each bit on interrupt enable register and related peripheral.

Global interrupt enable/disable

Global interrupt enable/disable allows us with a single instruction to mask all interrupts during the execution of some critical task such as manipulating a common pointer shared by multiple threads. In ARM Cortex M, we do the global enable/disable of interrupts with assembly language instructions of CPSID I (Change processor state-disable interrupts) and CPSIE I (Change processor state-enable interrupts). In C language we use inline assembly language instructions:

void DisableInterrupts(void){__asm ("CPSID  I\n");}
void EnableInterrupts(void){__asm  ("CPSIE  I\n");}

Initialize and Configure GPIO Interrupt Control Registers

To initialize and configure GPIO interrupt controls, one needs to program the GPIOIS, GPIOIBE, GPIOEV, and GPIOIM registers to configure the type, event, and mask of the interrupts for each port. The following steps should be used to do this initialization and configuration process:

  • Configure the GPIOIM register to disable (mask) the undesired pins.
  • Configure the GPIOIS register to indicate the interrupt-triggering type, edge, or level.
  • Configure the GPIOIBE register to indicate if this interrupt is triggered by both edges.
  • Reset the GPIORIS register to 0 to make it ready to set a flag if any interrupt occurred.
  • Configure the GPIOIM register to enable (unmask) the desired pins.

How to configure and set up an interrupt and its handler

Now let’s provide an example to illustrate how to configure and set up an interrupt and its handler based on the above Tables. For example, we want to set up and configure an interrupt for GPIO PortF. Perform the following operations to complete this job:

  1. Find the IRQ number for this interrupt from Table 7.3. The IRQ number for the GPIO PortF is 30.
  2. Based on Table 7.6, obtain the group number of the priority register (n). The IRQ number is 30. In order to make the equation 30 = interrupt[4n + 2] hold, n must be 7. This means that we need to use group 7 priority register NVIC_PRI7_R with bits 23-21 to configure the priority level for the GPIO PortF. Since the IRQ number of this port is 30, we can set the priority level for this port as 5, (101B), in bits 23-21 on the NVIC_PRI7_R. This setup can be written as NVIC_PRI7_R = (NVIC_PRI7_R & 0xFF00FFFF) | 0x00A00000 in the user’s program.
  3. Based on Table 7.7, obtain the bit field in the NVIC Set Enable Register to enable this port. Since the IRQ number of the Port F is 30, the bit 30 in the NVIC_EN0_R register should be set to 1 to enable this port. This setup can be written as NVIC_EN0_R = 0x40000000.
  4. Open tm4c123gh6pm_startup_ccs_gcc.c for editing. This file contains the vector table among other things. Open the file and look for the GPIO PortF vector. You need to carefully find the appropriate vector position and replace IntDefaultHandler with the name of your Interrupt handler.
  5. After going through all these steps an EnableInterrupts() function is called to perform the global interrupt enable function. Note that we have to enable the pull up at PF4 in order to provide high or low input signal.
  6. It is critical that the interrupt handler clears the interrupt flag before returning from interrupt handler. Otherwise the interrupt appears as if it is still pending and the interrupt handler will be executed again and again forever and the program hangs. The PORTF interrupt flag is cleared by writing a 1 to the bit that corresponds to the pin that triggered the interrupt in the GPIO Interrupt Clear Register (GPIOICR). In the case of SW1 (PF4), the interrupt flag is cleared by:
GPIO_PORTF_ICR_R = 0x10;

Note:The ARM Cortex writes are buffered. That means a write does not take effect immediately. It may take many clock cycles before the write to ICR to clear the interrupt flags. When return from interrupt handler and the interrupt flag is still pending, the interrupt handler will be executed again. One way to ensure that interrupt flags are cleared before returning from interrupt handler is to perform a read to force the write to take effect.