STM32L432 EXTI strange behaviour
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
2024-10-22 5:24 AM - last edited on 2024-10-22 1:17 PM by mƎALLEm
Hi,
I have three buttons - START, STOP and CH_SELECT which are serviced using EXTI interrupts. I have also a rotary encoder (A and B pins). Every button line is serviced on a separate IRQ line. Debouncing of the switch and rotary encoder pins is handled in HAL_GPIO_EXTI Callback function.
The code is actually working but sometimes, actually very often, code snippet of wrong button is executed. When I pressing for example button START sometimes I get “STOP button pressed” or “CH_SELECT_button pressed” randomly. Rotary encoder works very well. Am I missing something, every help is really appreciated.
Microcontrooller is STM32L431 with 80MHz master clock. I am using STM32CubeIDE 1.16.1
Those are my EXTI handlers (in stm32l4xx_it.c file):
void EXTI4_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(STOP_BUTTON_Pin);
}
void EXTI9_5_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(START_BUTTON_Pin);
}
void EXTI15_10_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(A_Pin);
HAL_GPIO_EXTI_IRQHandler(B_Pin);
HAL_GPIO_EXTI_IRQHandler(CH_SELECT_Pin);
}
This is my callback function (in main.c file):
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
uint32_t currentTime = HAL_GetTick();
if ((currentTime - lastDebounceTime) < DEBOUNCE_DELAY_ENCODER) {
return;
}
lastDebounceTime = currentTime;
if (GPIO_Pin == A_Pin) {
if (HAL_GPIO_ReadPin(B_GPIO_Port, B_Pin) == GPIO_PIN_SET) {
encoderValue+=20;
if(encoderValue>2666) encoderValue=0;
} else {
encoderValue-=20;
if(encoderValue<0) encoderValue=2666;
}
}
if (GPIO_Pin == B_Pin) {
if (HAL_GPIO_ReadPin(A_GPIO_Port, A_Pin) == GPIO_PIN_SET) {
encoderValue-=20;
if(encoderValue<0) encoderValue=2666;
} else {
encoderValue+=20;
if(encoderValue>2666) encoderValue=0;
}
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, encoderValue);
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, encoderValue);
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_3, encoderValue);
}
//START button
if (GPIO_Pin == START_BUTTON_Pin) {
if ((currentTime - last_start_button_tick) > DEBOUNCE_DELAY_BUTTON) {
last_start_button_tick = currentTime;
treatment_time=0;
start_treatment=1;
TIM1->CR1 |= TIM_CR1_CEN; //start timer1
//printf("start button pressed\n\r");
flag=1;
}
}
//STOP button
if (GPIO_Pin == STOP_BUTTON_Pin) {
if ((currentTime - last_stop_button_tick) > DEBOUNCE_DELAY_BUTTON) {
last_stop_button_tick = currentTime;
start_treatment=0;
//printf("stop button pressed\n\r");
flag=2;
}
}
//CH_SELECT button
if (GPIO_Pin == CH_SELECT_Pin) {
if ((currentTime - last_ch_select_tick) > DEBOUNCE_DELAY_BUTTON) {
last_ch_select_tick = currentTime;
//printf("CH_SELECT button pressed\n\r");
flag=3;
}
}
}
I am printing debug messages in the main loop:
while(1) {
if(flag==1) { printf("START button pressed\n\r"); flag=0;}
if(flag==2) { printf("STOP button pressed\n\r"); flag=0;}
if(flag==3) { printf("CH_SELECT button pressed\n\r"); flag=0;}
//…
//…
}
AND my debounce values are:
const uint32_t DEBOUNCE_DELAY_ENCODER = 50;
const uint32_t DEBOUNCE_DELAY_BUTTON = 50;
Thank you very much, I really appreciated any advice...
- Labels:
-
GPIO-EXTI
-
Interrupt
-
STM32L4 Series
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
2024-10-22 5:33 AM - edited 2024-10-22 5:35 AM
Declare flag as volatile. Rewrite the handler code to use "else if" instead of just "if" - its not possible to enter more than one if anyway.
Even better: don't use EXTI at all. It makes no sense. Do it all in timer interrupt with 20 ms period.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
2024-10-22 9:36 AM
Hello gbm,
Thank you very much for your reply,
yes flag is declared as volatile and all the tick variables also, I tried also to do a printf from interrupt (only for debugging purpose) but the problem persists...
Uh, not to use EXTI is also an interesting idea for think about it but now I wonder why this is not working properly...
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
2024-10-22 9:45 AM
In your code, if any of A, B or Select is pressed, you call the handlers for all three of them instead of checking which pin caused the interrupt and invoking only the handler for that pin. That's the problem.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
2024-10-22 10:29 AM
Uhhhh!!! You are right! But unfortunately still the same problem... :(
My handlers are now:
void EXTI4_IRQHandler(void)
{
if (__HAL_GPIO_EXTI_GET_IT(STOP_BUTTON_Pin) != RESET) {
__HAL_GPIO_EXTI_CLEAR_IT(STOP_BUTTON_Pin);
HAL_GPIO_EXTI_Callback(STOP_BUTTON_Pin);
}
void EXTI9_5_IRQHandler(void)
{
if (__HAL_GPIO_EXTI_GET_IT(START_BUTTON_Pin) != RESET) {
__HAL_GPIO_EXTI_CLEAR_IT(START_BUTTON_Pin);
HAL_GPIO_EXTI_Callback(START_BUTTON_Pin);
}
}
void EXTI15_10_IRQHandler(void)
{
if (__HAL_GPIO_EXTI_GET_IT(A_Pin) != RESET) {
__HAL_GPIO_EXTI_CLEAR_IT(A_Pin);
HAL_GPIO_EXTI_Callback(A_Pin);
}
else if (__HAL_GPIO_EXTI_GET_IT(B_Pin) != RESET) {
__HAL_GPIO_EXTI_CLEAR_IT(B_Pin);
HAL_GPIO_EXTI_Callback(B_Pin);
}
else if (__HAL_GPIO_EXTI_GET_IT(CH_SELECT_Pin) != RESET) {
__HAL_GPIO_EXTI_CLEAR_IT(CH_SELECT_Pin);
HAL_GPIO_EXTI_Callback(CH_SELECT_Pin);
}
}
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
2024-10-22 12:16 PM
You use single debounce variable for all inputs - maybe it's the reason - it masks some encoder events.
All of this would be much easier without pin interrupts.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
2024-10-22 12:57 PM
Consider to use the timer encoder hardware for the encoder task. Using interrupt for encoder task is error prone.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
2024-10-22 1:16 PM
Uh I have different ticks variables (last_stop_button_tick, last_start_button_tick and last_ch_select_tick). lastDebounceTime is actually only for decoder debouncing - maybe decoder should be written in the same way as buttons but I tried to completely remove decoder and the situation is the same...
Unfortunately I can't implement timer interrupt for polling the buttons because in the main I have a very time demanding task - I need to generate very precise pulses of 1 to 15us width and with repetition rate of 10Hz to 500Hz.
And during that pulses my buttons should be active (enabled) so interrupt of some 50ms for buttons polling will ruine
my pulses timing.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
2024-10-22 1:22 PM
Hello Uwe Bonnes,
Thank you very much for your reply,
uh I have a finished PCB so I can't do that unfortunately.
Actually my encoder is working very well... My buttons are acting strange...
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
2024-10-22 4:13 PM
@tompa wrote:Uh I have different ticks variables (last_stop_button_tick, last_start_button_tick and last_ch_select_tick). lastDebounceTime is actually only for decoder debouncing - maybe decoder should be written in the same way as buttons but I tried to completely remove decoder and the situation is the same...
Unfortunately I can't implement timer interrupt for polling the buttons because in the main I have a very time demanding task - I need to generate very precise pulses of 1 to 15us width and with repetition rate of 10Hz to 500Hz.
And during that pulses my buttons should be active (enabled) so interrupt of some 50ms for buttons polling will ruine
my pulses timing.
Instead of doing your pulses in main. why don't you use a timer in pulse mode?
As for button debouncing, I don't see any code where you check a timer after the button is pressed for at lease n amount of ms?
See this video to use a timer callback for debouncing a switch and many other uses.
https://www.youtube.com/watch?v=o0qhmXR5LD0
TimerCallback tutorial! | UART and DMA Idle tutorial!
If you find my solution useful, please click the Accept as Solution so others see the solution.
