-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improper EXTI reset in HAL_GPIO_DeInit() #1
Comments
Scenario: Firmware configures a GPIO for EXTI line interrupt on falling edge. In hardware the GPIO is pulled to Vdd by a pull-up resistor. After the falling edge is detected (single instance), the firmware reconfigures the GPIO pin for a different purpose. Problem: EXTI line interrupt is triggered twice, while in fact only one falling edge is generated on the I/O pin. Root cause: Improper EXTI reset order in HAL_GPIO_DeInit(). After the first time the EXTI line interrupt is fired, the firmware calls HAL_GPIO_DeInit() to de-initialize the GPIO pin because the resource is not needed anymore. Because the way the code is ordered in HAL_GPIO_DeInit(), '1'-to-'0' transition might be arise in the "Input data register" because the mode is reset to Analog High Impedance mode. This disable the internal Schmitt trigger, which continuously produces a '0' on its output. If the I/O was pulled high by pull-up resistor, a '1'-to-'0' transition triggers the EXTI line edge detector and fires the IRQ because the EXTI line configuration registers are not yet reset at this point in HAL_GPIO_DeInit(). Solution: Reorder the EXTI reset code in HAL_GPIO_DeInit() to disable the EXIT line interrupt before switching the value of EXTI line multiplexer and resetting the mode of the GPIO pin to analog high-impedance mode. Fixes STMicroelectronics#1.
Dear @jelledevleeschouwer, First of all, allow me to thank you for this detailed report. The accuracy of your analysis is remarkable. We are already aware of this issue and have fixed it internally. The fix will be available in a future release. Unfortunately we cannot share a date for the moment. We count on your patience and comprehension. However, I would like to ask you about what you described in the "Follow-up problem 2" section. Could you systematically reproduce the issue while still having the the line multiplexer reset before the EXTI is masked? Thank you in advance for your answer and thank you once more for this detailed report. With regards, |
ST Internal Reference: 77661 |
Any reply from your side about what you described in the "Follow-up problem 2" section? With regards, |
Hi @ALABSTM, Yes, at the time I could reproduce the problem described in "Follow-up problem 2", but I don't have the time to try and reproduce the issue right now. But the idea is simple, no? Imagine you have a GPIO (say, PB6) with external pull-up configured as digital input with EXTI interrupt on a falling edge. In rest, on the PB6 GPIO a high level '1' is present. But let's imagine you call HAL_GPIO_DeInit() now with a fix for the first issue as follows: /*------------------------- EXTI Mode Configuration --------------------*/
/* Clear the External Interrupt or Event for the current IO */
tmp = SYSCFG->EXTICR[position >> 2U];
tmp &= (((uint32_t)0x0FU) << (4U * (position & 0x03U)));
if(tmp == (GPIO_GET_INDEX(GPIOx) << (4U * (position & 0x03U))))
{
tmp = ((uint32_t)0x0FU) << (4U * (position & 0x03U));
SYSCFG->EXTICR[position >> 2U] &= ~tmp;
/* Clear EXTI line configuration */
EXTI->IMR &= ~((uint32_t)iocurrent);
EXTI->EMR &= ~((uint32_t)iocurrent);
/* Clear Rising Falling edge configuration */
EXTI->RTSR &= ~((uint32_t)iocurrent);
EXTI->FTSR &= ~((uint32_t)iocurrent);
}
/*------------------------- GPIO Mode Configuration --------------------*/
/* Configure IO Direction in Input Floting Mode */
GPIOx->MODER |= (GPIO_MODER_MODE0 << (position * 2U));
/* ... */ The code addresses If at this point, the PA6 GPIO was now configured as Digital Input and a low value '0' is produced on that GPIO, a '1'-to-'0' (falling edge) will be detected by the EXTI "edge detect cricuitry" and thus will set the Pending Interrupt flag on line 6 (PIF6) in the EXTI_PR register. This is the behavior that I observed. Could that be plausible, or am I missing something? Thanks, |
I hope you are fine. I noticed you attached p-r #2 to this issue. The fix you proposed is already covered by the one published in the frame of v1.10.3. I assume the p-r covers both problems 1 and 2 you described above. Please allow me then to close this issue. Thank you for your comprehension and thank you again for your detailed and well structured report. With regards, |
Dear @ALABSTM,
TL;DR
The
HAL_GPIO_DeInit()
contains a bug related to the order in which GPIO configuration and EXTI configuration is reset to its "reset defaults". The issue seems not to be present in other HAL drivers, such as for example in stm32f4xx_hal_driver. In those HAL drivers, disabling the EXTI interrupt comes before resetting the GPIO configuration as it should be.Scenario
Let's assume you have an active low switch (switch with external pull-up) connected to a GPIO pin and one would like to trigger an EXTI interrupt on the falling edge when closing that switch. But, in the meantime (since number of GPIO pins is limited), that GPIO is shared with another hardware resource. In rest, the GPIO is configured for that latter/second resource. One would typically see the following scenario to switch to input with EXTI interrupt on falling edge:
GPIO_MODE_IT_FALLING
and all boiler plate code usingGPIO_Init()
.GPIO_Init()
.Problem
In the scenario above, when that hardware resource is for example an output and the output isn't driven, the EXTI interrupt might fire since a '1'-to-'0' transition is observed on the EXTI line and that EXTI interrupt is still enabled.
Cause
The only way to clear EXTI configuration is by using
HAL_GPIO_DeInit()
Solution
Use
HAL_GPIO_DeInit()
to clear EXTI configuration to reset defaults.Follow-up problem 1
The solution for the problem causes another problem: in
HAL_GPIO_DeInit()
the I/O mode is reset to analog high impedance before the EXTI is disabled!stm32l0xx_hal_driver/Src/stm32l0xx_hal_gpio.c
Lines 311 to 336 in b6be1fc
The GPIO analog high impedance configuration disables the internal TTL Schmitt trigger producing a '0' on its ouput (See Figure 26 on page 242 in RM0376). Again, a '1'-to-'0' transition is observed on the EXTI line and that EXTI interrupt is still enabled. The EXTI interrupt will fire again.
Cause
The code block responsible for resetting the I/O mode of the GPIO comes before the code block responsible for resetting the EXTI configuration.
Solution
Swap the two code blocks in HAL_GPIO_DeInit() around.
Follow-up problem 2
There is still another problem in the code block responsible for resetting the EXTI configuration itself: the line multiplexer is reset before the EXTI is masked! This means that somehow the input data on GPIOA is '0', again a '1'-to-'0' transition is observed on the EXTI line and that EXTI interrupt is still enabled. The EXTI interrupt will fire again.
Cause
The code resetting the EXTI line multiplexer:
stm32l0xx_hal_driver/Src/stm32l0xx_hal_gpio.c
Lines 332 to 333 in b6be1fc
comes before the code resetting the EXTI interrupt masks:
stm32l0xx_hal_driver/Src/stm32l0xx_hal_gpio.c
Lines 335 to 341 in b6be1fc
Solution
Swap the two code blocks around.
What do you think? Could you please take a look at this?
Thanks,
Best regards,
Jelle De Vleeschouwer
The text was updated successfully, but these errors were encountered: