Search code examples
stm32stm32f0

STM32F030 GPIO interrupt


Trying to get an interrupt on A3, to wake the cpu up from sleep on a rx char, but it's not firing.

What is it that defines which interrupt the GPIO pin will trigger? I can't find it in the reference manual

static void EXTI0_1_IRQHandler_Config(void)
{
  GPIO_InitTypeDef   GPIO_InitStructure;

  /* Enable GPIOA clock */
  __HAL_RCC_GPIOA_CLK_ENABLE();

  GPIO_InitStructure.Mode = GPIO_MODE_IT_RISING;
  GPIO_InitStructure.Pull = GPIO_NOPULL;
  GPIO_InitStructure.Pin = GPIO_PIN_3;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);

  /* Enable and set EXTI line 0 Interrupt to the lowest priority */
  HAL_NVIC_SetPriority(EXTI0_1_IRQn, 2, 0);
  HAL_NVIC_EnableIRQ(EXTI0_1_IRQn);
}

Solution

  • Interrupt functions are (briefly) described in Chapter 11 Interrpts and events, Section 11.1.3 Interrupt and exception vectors.

    enter image description here

    So, the interrupt number is EXTI2_3_IRQn, and you should define EXTI2_3_IRQHandler() to call HAL_GPIO_EXTI_IRQHandler().

    Some background

    There are a couple of steps involved in getting a callback function called when an interrupt request occurs.

    Each interrupt request has an interrupt number assigned to it, see the Position entry in the table above. The number is defined by the hardware, the symbolic name is assigned somewhere in the machine headers.

    typedef enum {
       [...]
       EXTI0_1_IRQn                = 5,      /*!< EXTI Line 0 and 1 Interrupt */
       EXTI2_3_IRQn                = 6,      /*!< EXTI Line 2 and 3 Interrupt */
       [...]
    } IRQn_Type;
    

    There is a corresponding function pointer in the vector table, which should contain the address of the handler function. This vector table is filled out in the startup module, which is called startup_stm32f030x8.s or something similar, and the linker configuration file ensures that the table ends up at the proper physical address when programming the flash.

    g_pfnVectors:
      .word  _estack
      .word  Reset_Handler
      .word  NMI_Handler
      .word  HardFault_Handler
      .word  0
      .word  0
      .word  0
      .word  0
      .word  0
      .word  0
      .word  0
      .word  SVC_Handler
      .word  0
      .word  0
      .word  PendSV_Handler
      .word  SysTick_Handler
      .word  WWDG_IRQHandler                   /* Window WatchDog              */
      .word  0                                 /* Reserved                     */
      .word  RTC_IRQHandler                    /* RTC through the EXTI line    */
      .word  FLASH_IRQHandler                  /* FLASH                        */
      .word  RCC_IRQHandler                    /* RCC                          */
      .word  EXTI0_1_IRQHandler                /* EXTI Line 0 and 1            */
      .word  EXTI2_3_IRQHandler                /* EXTI Line 2 and 3            */
    ...
    

    The entries are in fixed order, since the hardware only cares about the numeric address. Whenever an EXTI2 or EXTI3 event occurs, and IRQ6 is enabled, it jumps to the address at 0x00000058. The table above ensures that the address of EXTI2_3_IRQHandler() goes into the vector table at 0x00000058.

    Digging further in the startup module we find this

    .weak      EXTI0_1_IRQHandler
    .thumb_set EXTI0_1_IRQHandler,Default_Handler
    
    .weak      EXTI2_3_IRQHandler
    .thumb_set EXTI2_3_IRQHandler,Default_Handler
    

    and this

    Default_Handler:
    Infinite_Loop:
      b Infinite_Loop
    

    It means that if there is no definition for EXTI0_1_IRQHandler() or EXTI2_3_IRQHandler(), then they invoke an infinite loop, good for debugging but nothing else. In order to actually use it, you must override this symbol in your program. If you look at the GPIO_EXTI example, it has this handler

    void EXTI0_1_IRQHandler(void)
    {
      HAL_GPIO_EXTI_IRQHandler(USER_BUTTON_PIN);
    }
    

    defined in stm32f0xx_it.c to call HAL_GPIO_EXTI_IRQHandler() when an EXTI0 interrupt occurs. If you'd like to act on EXTI3, then you should have a similar function

    void EXTI2_3_IRQHandler(void)
    {
      HAL_GPIO_EXTI_IRQHandler(3);
    }
    

    to call HAL_GPIO_EXTI_IRQHandler().