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);
}
Interrupt functions are (briefly) described in Chapter 11 Interrpts and events, Section 11.1.3 Interrupt and exception vectors.
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()
.