Overview of STM32F4xx Interrupts

Keywords: Embedded systems, ARM, STM32F4, Interrupts, NVIC, EXTI

Code Link: Source Code Github Keil- Bare-Metal

Code Link: Source Code Github Keil- HAL Libraries

On a very broad level, an interrupt is a signal to a processor emitted by on-chip/off-chip hardware or software indicating an event that relatively needs immediate CPU attention.

Another rough term used interchangeably with interrupts is Exceptions. Interrupts are vectored events, i.e. they are predefined and the processor knows where to seek Help (associated handler called Interrupt Service Routine-ISR) if an interrupts occurs (Vector Table). Upon an interrupt event, the processor state is stacked (current registers contents are saved on stack) and upon exiting interrupt, the processor state is restored. Also when an interrupt occurs, the current instruction is completed before the processor jumps to associated Interrupt Service Routine ISR.

Exception on the other hand may or may not be vectored events. Also upon an exception, the processor state may not be stacked. Upon an exception, the processor leave the current instruction execution. While interrupts are always predefined/expected to occur if enabled except Non-Maskable (NMI) ones, Exceptions on the other hand may occur any time e.g. divide by 0 or an illegal instruction execution etc.
Lets define some terms.

ISR:

ISR stands for Interrupt Service Routine. Its a software routine/function/method that hardware invokes in response to an interrupt. They are also called interrupt handlers.

Interrupt Priority:

Interrupt Priority, a number (either +ive or -ive) that indicates relative importance of an interrupt. i.e. which interrupt should be served first if multiple interrupts occurred simultaneously.

Vector Table:

An “interrupt vector table” (IVT) is a data structure that associates a list of interrupt handlers (ISR) addresses with a list of predefined interrupt requests in a table of interrupt vectors [1]. Each entry of the interrupt vector table, called an interrupt vector, is either the address of an interrupt handler (ISR) (e.g. ARMv7) or a bunch of memory locations in which ISR should be implemented or jump to ISR is implemented (earlier ARM cores). For example, the Figure-1 shows ARM Cortex-M4 Vector Table.

Figure-1: ARM Cortex-M4 Vector Table

As STM32F4xx devices are build around ARM Cortex-M cores whose main Interrupt handling entity is NVIC, so let’s discuss ARM Cortex-M NVIC first.

ARM Cortex-M NVIC:

The ARM Cortex-M series processors features an integral nested vectored interrupt controller (NVIC) to provide interrupt handling capabilities. The nested vectored interrupt controller (NVIC) is the main entity integrated on ARM processor cores to facilitates low-latency exception and interrupt handling and helps power management.

In ARM Cortex-M0, Cortex-M0+ and Cortex-M1 processors the NVIC supports up to 32 interrupt requests (IRQ), a non-maskable interrupt (NMI) and various system exceptions. On Cortex-M3/4/4F, the NVIC functionality has been tremendously enhanced. On Cortex M3/4/4F, the NVIC supports 256 different interrupt vectors. Out of these 256, there are 16 fixed on-core exceptions called system exceptions some of which have fixed priorities. The remaining 240 (265-16) are left to the silicon implementor to connect/map their own modules/peripherals (GPIOs, UART etc.) interrupt requests (IRQs) on these lines.

Figure-2: ARM NVIC

Note: The processor automatically stacks its state on receiving NVIC interrupt/exception and unstacks this state on exception exit.

STM32F4xx Interrupts:

STM32F4xx implement 82/92 of 240 NVIC interrupts depending on device xx i.e. on STM32F4xx 82/92 of NVIC lines are connected to various on-SoC peripherals covering both internal and external interrupts. These lines have 16 programmable priorities. The various connections of STM32F407xx on-chip peripheral to NVIC is shown in the Listing-1.

/*ADDRESS                 ISR               */

0x00000000           	  __initial_sp               ; Top of Stack
0x00000004           	  Reset_Handler              ; Reset Handler
0x00000008           	  NMI_Handler                ; NMI Handler
     .        		  HardFault_Handler          ; Hard Fault Handler
     .        		  MemManage_Handler          ; MPU Fault Handler
     .        		  BusFault_Handler           ; Bus Fault Handler
     .        		  UsageFault_Handler         ; Usage Fault Handler
     .            	  0                          ; Reserved
			  0                          ; Reserved
			  0                          ; Reserved
			  0                          ; Reserved
			  SVC_Handler                ; SVCall Handler
			  DebugMon_Handler           ; Debug Monitor Handler
			  0                          ; Reserved
			  PendSV_Handler             ; PendSV Handler
			  SysTick_Handler            ; SysTick Handler

			  ; External Interrupts
			  WWDG_IRQHandler                   ; Window WatchDog                                        
			  PVD_IRQHandler                    ; PVD through EXTI Line detection                        
			  TAMP_STAMP_IRQHandler             ; Tamper and TimeStamps through the EXTI line            
			  RTC_WKUP_IRQHandler               ; RTC Wakeup through the EXTI line                       
			  FLASH_IRQHandler                  ; FLASH                                           
			  RCC_IRQHandler                    ; RCC                                             
			  EXTI0_IRQHandler                  ; EXTI Line0                                             
			  EXTI1_IRQHandler                  ; EXTI Line1                                             
			  EXTI2_IRQHandler                  ; EXTI Line2                                             
			  EXTI3_IRQHandler                  ; EXTI Line3                                             
			  EXTI4_IRQHandler                  ; EXTI Line4                                             
			  DMA1_Stream0_IRQHandler           ; DMA1 Stream 0                                   
			  DMA1_Stream1_IRQHandler           ; DMA1 Stream 1                                   
			  DMA1_Stream2_IRQHandler           ; DMA1 Stream 2                                   
			  DMA1_Stream3_IRQHandler           ; DMA1 Stream 3                                   
			  DMA1_Stream4_IRQHandler           ; DMA1 Stream 4                                   
			  DMA1_Stream5_IRQHandler           ; DMA1 Stream 5                                   
			  DMA1_Stream6_IRQHandler           ; DMA1 Stream 6                                   
			  ADC_IRQHandler                    ; ADC1, ADC2 and ADC3s                            
			  CAN1_TX_IRQHandler                ; CAN1 TX                                                
			  CAN1_RX0_IRQHandler               ; CAN1 RX0                                               
			  CAN1_RX1_IRQHandler               ; CAN1 RX1                                               
			  CAN1_SCE_IRQHandler               ; CAN1 SCE                                               
			  EXTI9_5_IRQHandler                ; External Line[9:5]s                                    
			  TIM1_BRK_TIM9_IRQHandler          ; TIM1 Break and TIM9                   
			  TIM1_UP_TIM10_IRQHandler          ; TIM1 Update and TIM10                 
			  TIM1_TRG_COM_TIM11_IRQHandler     ; TIM1 Trigger and Commutation and TIM11
			  TIM1_CC_IRQHandler                ; TIM1 Capture Compare                                   
			  TIM2_IRQHandler                   ; TIM2                                            
			  TIM3_IRQHandler                   ; TIM3                                            
			  TIM4_IRQHandler                   ; TIM4                                            
			  I2C1_EV_IRQHandler                ; I2C1 Event                                             
			  I2C1_ER_IRQHandler                ; I2C1 Error                                             
			  I2C2_EV_IRQHandler                ; I2C2 Event                                             
			  I2C2_ER_IRQHandler                ; I2C2 Error                                               
			  SPI1_IRQHandler                   ; SPI1                                            
			  SPI2_IRQHandler                   ; SPI2                                            
			  USART1_IRQHandler                 ; USART1                                          
			  USART2_IRQHandler                 ; USART2                                          
			  USART3_IRQHandler                 ; USART3                                          
			  EXTI15_10_IRQHandler              ; External Line[15:10]s                                  
			  RTC_Alarm_IRQHandler              ; RTC Alarm (A and B) through EXTI Line                  
			  OTG_FS_WKUP_IRQHandler            ; USB OTG FS Wakeup through EXTI line                        
			  TIM8_BRK_TIM12_IRQHandler         ; TIM8 Break and TIM12                  
			  TIM8_UP_TIM13_IRQHandler          ; TIM8 Update and TIM13                 
			  TIM8_TRG_COM_TIM14_IRQHandler     ; TIM8 Trigger and Commutation and TIM14
			  TIM8_CC_IRQHandler                ; TIM8 Capture Compare                                   
			  DMA1_Stream7_IRQHandler           ; DMA1 Stream7                                           
			  FMC_IRQHandler                    ; FMC                                             
			  SDIO_IRQHandler                   ; SDIO                                            
			  TIM5_IRQHandler                   ; TIM5                                            
			  SPI3_IRQHandler                   ; SPI3                                            
			  UART4_IRQHandler                  ; UART4                                           
			  UART5_IRQHandler                  ; UART5                                           
			  TIM6_DAC_IRQHandler               ; TIM6 and DAC1&2 underrun errors                   
			  TIM7_IRQHandler                   ; TIM7                   
			  DMA2_Stream0_IRQHandler           ; DMA2 Stream 0                                   
			  DMA2_Stream1_IRQHandler           ; DMA2 Stream 1                                   
			  DMA2_Stream2_IRQHandler           ; DMA2 Stream 2                                   
			  DMA2_Stream3_IRQHandler           ; DMA2 Stream 3                                   
			  DMA2_Stream4_IRQHandler           ; DMA2 Stream 4                                   
			  ETH_IRQHandler                    ; Ethernet                                        
			  ETH_WKUP_IRQHandler               ; Ethernet Wakeup through EXTI line                      
			  CAN2_TX_IRQHandler                ; CAN2 TX                                                
			  CAN2_RX0_IRQHandler               ; CAN2 RX0                                               
			  CAN2_RX1_IRQHandler               ; CAN2 RX1                                               
			  CAN2_SCE_IRQHandler               ; CAN2 SCE                                               
			  OTG_FS_IRQHandler                 ; USB OTG FS                                      
			  DMA2_Stream5_IRQHandler           ; DMA2 Stream 5                                   
			  DMA2_Stream6_IRQHandler           ; DMA2 Stream 6                                   
			  DMA2_Stream7_IRQHandler           ; DMA2 Stream 7                                   
			  USART6_IRQHandler                 ; USART6                                           
			  I2C3_EV_IRQHandler                ; I2C3 event                                             
			  I2C3_ER_IRQHandler                ; I2C3 error                                             
			  OTG_HS_EP1_OUT_IRQHandler         ; USB OTG HS End Point 1 Out                      
			  OTG_HS_EP1_IN_IRQHandler          ; USB OTG HS End Point 1 In                       
			  OTG_HS_WKUP_IRQHandler            ; USB OTG HS Wakeup through EXTI                         
			  OTG_HS_IRQHandler                 ; USB OTG HS                                      
			  DCMI_IRQHandler                   ; DCMI  
			  0                                 ; Reserved				                              
			  HASH_RNG_IRQHandler               ; Hash and Rng
0x0000018C	          FPU_IRQHandler                    ; FPU

Listing-1: STM32F407 Vector Table

The interrupts on STM32F4xx can be categorized into the following layers.

Figure-3: STM32F4 External Interrupt Controller

As can be seen from Figure-3, the ultimate controlling entity is ARM Core and its integrated NVIC on top of which there is STM32F4 External Interrupt/Event Controller (EXTI). The STM32F4 implements a rich number of on-chip peripherals almost each capable of generating an event or interrupt. Especially if we look at the rich number of GPIOs on STM32F, which are about 170 in number. Connecting each GPIOx Pin to one IRQ on NVIC will create much redundancy on NVIC controller and also complexity of silicon connections. In order to solve this issue, and accommodate the large number of GPIOs on limited number of IRQ lines, STM has implemented another module called External Interrupt/Event Controller (EXTI).

EXTI provides a flexible multiplexing of GPIO pins on NVIC IRQs. For example on STM32F407-Discovery, The EXTI maps GPIOs on just 7 NVIC IRQs. i.e. EXTI0,EXTI1,EXTI2,EXTI3,EXTI4,EXTI9-5,EXTI15-10. Apart from GPIOs, few other peripherals like USB OTG, PVD, RTC, Ethernet etc. are too connected to NVIC via EXTI. In short on STM32F4xx, EXTI maps total 23 NVIC IRQs out of 240. Out of this 23, there 16 (0-15) lines map GPIOs while the remaining 7 (16-22) are connected to other peripheral like RTC, RVD, USB OTG etc. For more details, refer to STM32F4xx datasheet.

The beauty of EXTI controller is; it doesn’t only provides Hardware interrupts (interrupt generated by a hardware module) but also Software interrupts i.e. virtual interrupts can also be generated by the embedded software by writing to appropriate registers on EXTI.

The following Figure-4 shows a broad overview of peripherals interfaced to EXTI and subsequently to NVIC.

Figure-4: STM32F4xx EXTI, NVIC, Core interface

As shown in Figure-5, EXTI0-to-EXTi15 maps external GPIOs to NVIC. EXTIx line maps GPIOs.x Pins i.e. EXTI0 line maps GPIOs.0 of GPIO ports i.e. PA.0, PB.0 … PI.0. Similarly EXTI.1 line maps GPIOs.1 of GPIO ports and so on. At a time only one GPIO Pin can interrupt EXTIx line. i.e. for example one of PA.0, PB.0 … PI.0 pin can send interrupt on EXTI0 line. The following Figure-4 shows STM32F4-Discovery GPIOs mapping on EXTI lines.

Figure-5: STM32F4-Discovery GPIOs Pins to EXTI lines multiplexing

The desired pin to send interrupt on EXTIx line can be selected via SYSCFG_EXTICRx RegisterS.

Figure-6: STM32F4-Discovery SYSCFG_EXTICR1-4 Registers, x = 1 – 15

In order to select which PINx should generate interrupt on EXTIx line, the appropriate bits for EXTIx must be set in SYSCFG_EXTICR1-4 Registers as given bellow.
EXTIx[3:0]: EXTI x configuration (x = 0 to 15) in SYSCFG_EXTICR1-4 Registers.
0000: PA[x] pin
0001: PB[x] pin
0010: PC[x] pin
0011: PD[x] pin
0100: PE[x] pin
0101: PF[x] pin
0110: PG[x] pin
0111: PH[x] pin
1000: PI[x] pin

NOTE: Refer to STM32F4 datasheet for more details on SYSCFG_EXTICR1-4 Registers

One of the key difference between NVIC and EXTI is that, upon receiving interrupt from NVIC, the interrupt flags are cleared implicitly when ISR is called while interrupts coming from EXTI must be cleared manually/explicitly in ISR.

NOTE: Interrupts coming from EXTI controller must be cleared (flag bits) explicitly in corresponding ISR otherwise it will keep interrupting ARM Core thus subsequently calling ISR in infinite loop.

Sample Application:

Now that we understand STM32F4 interrupts main blocks, its time to develop a simple application covering both EXTI and NVIC.
In this application we will configure GPIOA Pin.0 (PA.0) as input to generate an interrupt on rising edge of incoming signal. The signal to PA.0 is given from PD.14 (RED-LED) as a square wave. Upon receiving interrupt, PD.15 (BLUE-LED) is toggled i.e. on each rising edge of signal from PD.14 (connected to PA.0 with external jumper), the PD.15 (BLUE-LED) is toggled.

Figure-7: LEDs blinking on PA.0 Interrupt

As can be seen from the above figure, the frequency of BLUE-LED (PD.15) should be half of RED-LED (PD.14) as it is toggled in alternate cycles edges.
Following are steps to configure configure sample application interrupt.

  1. Configure PD.14 and PD.15 as digital output.
  2. Configure PA.0 as Input
  3. Configure EXTI.0 to generate interrupt on PA.0 input signal Rising edge
  4. Implement ISR to handle EXTI.0 interrupt

1. To configure PD.14 and PD.15 as output, refer to the following detail tutorial or refer to the source code link given at the top.

2. To configure PA.0 as input, refer to the following detail tutorial or refer to the source code link given at the top.

3. These are the main steps of this Sample Application. First of all, enable SYSCFG controller to enable Pin selection on EXTI.x multiplexer as shown in above Figure-5.

/*
    enable clock to syscfg for pin selection.
*/
__setbit(RCC->APB2ENR, 14);

As shown in Figure-5, PA.0 pin is connected to EXTI.0 so next step is to configure EXTI.0 via EXTICRx (Figure-6) register to listen to PA.0 pin input signal. From EXTICR bits, PA.0 can be selected by clearing bits 0,1,2,3 (0000).

/*
    connect PA.0 to EXTI.0
    EXTICR[3-0] = 0b0000
*/
__clearbit(SYSCFG->EXTICR[0],0);
__clearbit(SYSCFG->EXTICR[0],1);
__clearbit(SYSCFG->EXTICR[0],2);
__clearbit(SYSCFG->EXTICR[0],3);

Next enable EXTI.0 line itself via EXTI_IMR register.

/*
    Enable Interrupt on EXTI0 line
*/ 
__setbit(EXTI->IMR, 0);

Configure EXTI.0 to forward interrupt/event to NVIC on RISING edge of input signal on PA.0.

/*
    trigger interrupt on rising edge
*/
__setbit(EXTI->RTSR, 0);

Finally inform NVIC to expect interrupt on IRQ No. 6 (to which EXTI0 is connected).

/*
    Now EXTI has been configured, finally
    enable IRQn.6 to accept interrupt.
*/
   
NVIC_EnableIRQ(EXTI0_IRQn);

Now that configuration is complete, it time to write ISR which will be called automatically whenever a rising edge is detected on PA.0. As can be seen from above Listing-1, the ISR name in vector table for EXTI0 is:

EXTI0_IRQHandler        ; EXTI Line0

Just copy-past the ISR name and implement it with return type void and parameters void. In the following code, we have implemented the EXTI0 ISR as:

void EXTI0_IRQHandler (void) {
    
    /*
        Clear the pending interrupt
    */
    __setbit (EXTI->PR, 0);
    
    /* 
        toggle the led to confirm that interrupt
        has called the ISR.
    */
    __togglebit(GPIOD->ODR, 15);
}

As shown in above code snippet, the first step is to clear the EXTI0 interrupt otherwise it will keep calling ISR again and again. Next is to toggle BLUE-LED (PD.15) to indicate that ISR is called (Sample Application purpose).

Now all the configurations have been made, now its time to give input signal to PA.0. For this simple application we have choose to produce square wave of PD.14 and feed it to PA.0 as shown in Figure-7.

while (1) {

    /* generate square wave on PD.14 */
    __togglebit(GPIOD->ODR, 14);

    for ( i = 0; i < 1000000; ++i);
}

NOTE: For complete code visit Github Link given at the top.

My apologies for that invisible jumper between PA.0 and PD.14.

References:

[1] – Reference manual-RM0090



22 thoughts on “Overview of STM32F4xx Interrupts”

Leave a Reply

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