STM32F411: free an external interrupt flag?

I bought the STM32F411 core, and now I'm trying to understand the various pieces of HAL. Starting with external interrupts, it seemed like a good idea, because there is a button on the board that is connected to PC13. So I set up a simple switch mode. The code below is a bit simplified:

#define LED_PIN GPIO_PIN_5 #define BTN_PIN GPIO_PIN_13 static uint32_t blink_period = 250; int main(void) { HAL_Init(); SystemClock_Config(); __GPIOA_CLK_ENABLE(); GPIO_InitTypeDef pinConfig; pinConfig.Pin = (LED_PIN); pinConfig.Pull = GPIO_NOPULL; pinConfig.Mode = GPIO_MODE_OUTPUT_PP; pinConfig.Speed = GPIO_SPEED_FAST; HAL_GPIO_Init(GPIOA, &pinConfig); __GPIOC_CLK_ENABLE(); pinConfig.Pin = (BTN_PIN); pinConfig.Pull = GPIO_NOPULL; pinConfig.Mode = GPIO_MODE_IT_FALLING; pinConfig.Speed = GPIO_SPEED_LOW; HAL_GPIO_Init(GPIOC, &pinConfig); HAL_NVIC_SetPriority(EXTI15_10_IRQn, 0x0F, 0x00); HAL_NVIC_EnableIRQ(EXTI15_10_IRQn); while (1) { HAL_GPIO_TogglePin(GPIOA, LED_PIN); HAL_Delay(blink_period); } } void EXTI15_10_IRQHandler(void) { HAL_GPIO_EXTI_IRQHandler(BTN_PIN); } void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if(GPIO_Pin == BTN_PIN) { if (blink_period == 500) { blink_period = 250; } else { blink_period = 500; } } } 

When I press the button, an interrupt is generated, and the blinking frequency changes from 1 to 2 Hz (or vice versa). It works as intended, but why? I forgot to clear the pending interrupt flag, so the ISR should be called again and again. The technical description clearly states that

When the selected edge appears on the external interrupt line, an interrupt request is generated. A pending bit corresponding to the interrupt line is also set. This request is reset by writing '1 to the pending register.

Reading a little further shows that this is slightly different for events:

When the selected edge appears in the event line, an event pulse is generated. The deferred bit corresponding to the event line is not set.

However, I do not set the button output mode to any of the GPIO_MODE_EVT_... modes, so I do not use the event mechanism (to be honest, I still do not know what it is - I just think that I am not using it. Any hints are welcome).

So, somewhere I would have to call void HAL_NVIC_ClearPendingIRQ (IRQn_Type IRQn) , right? It seems that software does not need to clear the flag, since the ISR is not called more than once per falling edge. I added a breakpoint in HAL_GPIO_EXTI_Callback to test this.

Edit

As indicated in the comments, the flag clear code is in the ST implementation of the GPIO interrupt handler:

 void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin) { /* EXTI line interrupt detected */ if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET) { __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin); HAL_GPIO_EXTI_Callback(GPIO_Pin); } } 

This handler must be called by the actual ISR (which runs in my code), and it clears the pending flag corresponding to the GPIO_Pin argument. So I have to write an ISR that sorts which flags are set and call HAL_GPIO_EXTI_IRQHandler for each, which in turn calls my HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) , again using pin as an argument. For each external interrupt, the number of contacts will be checked approximately ~ 3 times (in the ISR, in the handler, and in the callback)!

If this is the solution, I want to return my problem.

+5
source share
1 answer

You do not need to call HAL_NVIC_ClearPendingIRQ (IRQn_Type IRQn) , because the waiting bit in the NVIC will be automatically cleared when you enter HAL_GPIO_EXTI_IRQHandler .

The implementation of HAL_GPIO_EXTI_IRQHandler() clears the deferred bit in the peripheral rather than in the NVIC. If it did not clear the pending bit by calling __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin) , then the handler will be called again and again. The fact is that you must distinguish between the interrupt waiting bit in the peripheral device and the waiting bit in the NVIC.

+3
source

Source: https://habr.com/ru/post/1207514/


All Articles