cancel
Showing results for 
Search instead for 
Did you mean: 

STM32L432 EXTI strange behaviour

tompa
Associate II

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... 

12 REPLIES 12
gbm
Lead III

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.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice
tompa
Associate II

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...  

 

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.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice
tompa
Associate II

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);
  }
}

 

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.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice
Uwe Bonnes
Principal III

Consider to use the timer encoder hardware for the encoder task. Using interrupt  for encoder task is error prone.

tompa
Associate II

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.

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... 


@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

If smoke escapes your device, put the smoke back in. It'll still work as a conversation piece. If you find my answers useful, click the Accept as Solution button so that way others can see the solution.