Electronic – ARM Cortex-M3 Interrupts and Interrupt service routine &interrupt handler

armcembeddedinterrupts

I am trying to understand arm architecture and i got stuck with one concept, i.e, INTERRUPT SERVICE ROUTINE. I had gone NVIC structure for HARDWARE & SOFTWARE interrupts. But at some point i got confused how that particular function is called when an interrupt occurs. All those functions are already defined like for TIMER-6, TIM6_IRQHandler(). How can i update this particular function with user defined function (means any function).

Any reference document or link will be appreciated.
Working IDE is EWARM.
Testing Controller STM32L152RE.

Best Answer

The default interrupt handlers are usually defined as weak symbols somewhere in the startup code.

This means that you can write your own function with exactly the same name and during link time it will "win" over a weak function (otherwise you would get a link error claiming duplicate symbol names).

Example for an STM32L432. This is a piece of the startup code you get from CubeMX (ST's project generation tool). Cut for clarity.

/**
 * @brief  This is the code that gets called when the processor receives an
 *         unexpected interrupt.  This simply enters an infinite loop, preserving
 *         the system state for examination by a debugger.
 *
 * @param  None
 * @retval : None
*/
    .section    .text.Default_Handler,"ax",%progbits
Default_Handler:
Infinite_Loop:
    b   Infinite_Loop
    .size   Default_Handler, .-Default_Handler
/******************************************************************************
*
* The minimal vector table for a Cortex-M4.  Note that the proper constructs
* must be placed on this to ensure that it ends up at physical address
* 0x0000.0000.
*
******************************************************************************/
    .section    .isr_vector,"a",%progbits
    .type   g_pfnVectors, %object
    .size   g_pfnVectors, .-g_pfnVectors


g_pfnVectors:
    .word   _estack
    .word   Reset_Handler
    .word   NMI_Handler
    .word   HardFault_Handler
    .word   MemManage_Handler
    .word   BusFault_Handler
    .word   UsageFault_Handler
    .word   0
    .word   0
    .word   0
    .word   0
    .word   SVC_Handler
    .word   DebugMon_Handler
    .word   0
    .word   PendSV_Handler
    .word   SysTick_Handler
    .word   WWDG_IRQHandler
    .word   PVD_PVM_IRQHandler
    .word   TAMP_STAMP_IRQHandler
    .word   RTC_WKUP_IRQHandler
    .word   FLASH_IRQHandler
    .word   RCC_IRQHandler
    .word   EXTI0_IRQHandler
    .word   EXTI1_IRQHandler
    .word   EXTI2_IRQHandler
    .word   EXTI3_IRQHandler
    .word   EXTI4_IRQHandler
    .word   DMA1_Channel1_IRQHandler
    .word   DMA1_Channel2_IRQHandler
    .word   DMA1_Channel3_IRQHandler
    .word   DMA1_Channel4_IRQHandler
    .word   DMA1_Channel5_IRQHandler
    .word   DMA1_Channel6_IRQHandler
    .word   DMA1_Channel7_IRQHandler
    .word   ADC1_IRQHandler
    .word   CAN1_TX_IRQHandler
    .word   CAN1_RX0_IRQHandler
    .word   CAN1_RX1_IRQHandler
    .word   CAN1_SCE_IRQHandler
    .word   EXTI9_5_IRQHandler
    .word   TIM1_BRK_TIM15_IRQHandler
    .word   TIM1_UP_TIM16_IRQHandler
    .word   TIM1_TRG_COM_IRQHandler
    .word   TIM1_CC_IRQHandler
    .word   TIM2_IRQHandler
    <------------- cut -------------->   
/*******************************************************************************
*
* Provide weak aliases for each Exception handler to the Default_Handler.
* As they are weak aliases, any function with the same name will override
* this definition.
*
*******************************************************************************/

  .weak NMI_Handler
    .thumb_set NMI_Handler,Default_Handler

  .weak HardFault_Handler
    .thumb_set HardFault_Handler,Default_Handler

  .weak MemManage_Handler
    .thumb_set MemManage_Handler,Default_Handler

  .weak BusFault_Handler
    .thumb_set BusFault_Handler,Default_Handler

    .weak   UsageFault_Handler
    .thumb_set UsageFault_Handler,Default_Handler

    .weak   SVC_Handler
    .thumb_set SVC_Handler,Default_Handler

    .weak   DebugMon_Handler
    .thumb_set DebugMon_Handler,Default_Handler

    .weak   PendSV_Handler
    .thumb_set PendSV_Handler,Default_Handler

    .weak   SysTick_Handler
    .thumb_set SysTick_Handler,Default_Handler

    .weak   WWDG_IRQHandler
    .thumb_set WWDG_IRQHandler,Default_Handler

    .weak   PVD_PVM_IRQHandler
    .thumb_set PVD_PVM_IRQHandler,Default_Handler

    .weak   TAMP_STAMP_IRQHandler
    .thumb_set TAMP_STAMP_IRQHandler,Default_Handler

    .weak   RTC_WKUP_IRQHandler
    .thumb_set RTC_WKUP_IRQHandler,Default_Handler

    .weak   FLASH_IRQHandler
    .thumb_set FLASH_IRQHandler,Default_Handler

    .weak   RCC_IRQHandler
    .thumb_set RCC_IRQHandler,Default_Handler

    .weak   EXTI0_IRQHandler
    .thumb_set EXTI0_IRQHandler,Default_Handler

    .weak   EXTI1_IRQHandler
    .thumb_set EXTI1_IRQHandler,Default_Handler

    .weak   EXTI2_IRQHandler
    .thumb_set EXTI2_IRQHandler,Default_Handler

    .weak   EXTI3_IRQHandler
    .thumb_set EXTI3_IRQHandler,Default_Handler

    .weak   EXTI4_IRQHandler
    .thumb_set EXTI4_IRQHandler,Default_Handler

    .weak   DMA1_Channel1_IRQHandler
    .thumb_set DMA1_Channel1_IRQHandler,Default_Handler

    .weak   DMA1_Channel2_IRQHandler
    .thumb_set DMA1_Channel2_IRQHandler,Default_Handler

    .weak   DMA1_Channel3_IRQHandler
    .thumb_set DMA1_Channel3_IRQHandler,Default_Handler

    .weak   DMA1_Channel4_IRQHandler
    .thumb_set DMA1_Channel4_IRQHandler,Default_Handler

    .weak   DMA1_Channel5_IRQHandler
    .thumb_set DMA1_Channel5_IRQHandler,Default_Handler

    .weak   DMA1_Channel6_IRQHandler
    .thumb_set DMA1_Channel6_IRQHandler,Default_Handler

    .weak   DMA1_Channel7_IRQHandler
    .thumb_set DMA1_Channel7_IRQHandler,Default_Handler

    .weak   ADC1_IRQHandler
    .thumb_set ADC1_IRQHandler,Default_Handler

    .weak   CAN1_TX_IRQHandler
    .thumb_set CAN1_TX_IRQHandler,Default_Handler

    .weak   CAN1_RX0_IRQHandler
    .thumb_set CAN1_RX0_IRQHandler,Default_Handler

    .weak   CAN1_RX1_IRQHandler
    .thumb_set CAN1_RX1_IRQHandler,Default_Handler

    .weak   CAN1_SCE_IRQHandler
    .thumb_set CAN1_SCE_IRQHandler,Default_Handler
    <----------- cut ---------------->

    /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

You don't need any assembly knowledge to understand it. The first thing is the Default_Handler routine. It is just an empty infinite loop. b Infinite_Loop means jump (branch) to the place where the label Infinite_Loop is placed, just an infinite loop.

Later on you have a definition of all handler symbols (+initial stack pointer), for example ADC1_IRQHandler (the interrupt that gets fired when ADC has done something).

Next a weak linkage is provided that points every of the handlers to the Default_Handler. If you enable ADC interrupts and not provide your own handler the default handler will be executed (which means that your CPU will lock up in an infinite loop, I prefer to put a breakpoint instruction in the default handler because it is much more visible in a debugger, than just seeing the board frozen).

To override the weak linkage you have to implement a function with the same name anywhere in your project. For example you can implement this function in main.c:

void ADC1_IRQHandler(void){
//save the measurement, do something...
}

The linker will simply pick your function instead of the weak one.

Due to the nice design of Cortex-M you don't have to use special attributes for the handler function (like for example the ISR() macro for AVR cores), so the interrupt handler (from CPU point of view) is a function just like as every other.