1

I want to implement long-press button to turn a device on. I use external interrupt button to launch the timer on press, and stop and reset it on release of the button. If you hold the button enough (1 sec) it will call a Timer_Update event and turn on LED.

However, when I load my code to the Discovery and press reset, the first press of the user button lights the LED immediately as if the interrupt is generated at the very first launch of the Timer. Then it works properly - changes LED state if you hold the button for >= 1sec.

Project is generated via CubeMX

This is button interrupt handler

    void EXTI0_IRQHandler(void)
{
  /* USER CODE BEGIN EXTI0_IRQn 0 */
    static uint8_t is_pressed = 0;
  /* USER CODE END EXTI0_IRQn 0 */
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
  /* USER CODE BEGIN EXTI0_IRQn 1 */
    if (!is_pressed) {
        HAL_TIM_Base_Start_IT(&htim7);
        HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_13);
        is_pressed = 1;
    }
    else {
        HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_13);
        HAL_TIM_Base_Stop_IT(&htim7);
        __HAL_TIM_SET_COUNTER(&htim7, 0);
        is_pressed = 0;
    }
  /* USER CODE END EXTI0_IRQn 1 */
}

This is Timer interrupt handler

    void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_14);
    HAL_TIM_Base_Stop_IT(htim);
    __HAL_TIM_SET_COUNTER(htim, 0);
}

The trigger event for the Timer in CubeMX is set as "Update Event"

Lundin
  • 195,001
  • 40
  • 254
  • 396
Warpony
  • 31
  • 5
  • Why everyone thinks that using interrupts for processing buttons is the best solution? Buttons usually generating bounces at every press and release, this can call interrupt more times and can cause unexpected behavior. – vlk Jun 14 '18 at 14:05
  • @vlk I will bother debouncing the button later, I have several other important functions depending on interrupts by timers, and if I can't solve this "simple" problem it means I don't understand the way the timer interrupt works, this may cause my program malfunction later. – Warpony Jun 14 '18 at 19:27

2 Answers2

1

Well it is a bug in the generated code. During timer initialization the call TIM_Base_SetConfig is called. This call has as a side effect that update interrupt bit is set in the SR. This means that when interrupt are enable in the HAL_TIM_Base_Start_IT immediately an interrupt is generated. This is what you are experiencing. See also https://www.youtube.com/watch?v=3yvY7pLMHAg 5:40. There also a HAL compatible fix is explained.

jan sunman
  • 11
  • 1
0

I would recommend the following implementation:

  1. Setup EXTI pin for rising and falling edges
  2. Check pin state in interrupt handler(instead of is_pressed variable)

EXTI handler can be implemented like below:

#define BUTTON_GPIO                GPIOA
#define BUTTON_PIN                 GPIO_PIN_0
#define BUTTON_PRESSED_STATE       GPIO_PIN_RESET

void EXTI0_IRQHandler(void)
{        
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);

    if (HAL_GPIO_ReadPin(BUTTON_GPIO, BUTTON_PIN) == BUTTON_PRESSED_STATE ) {
        HAL_TIM_Base_Start_IT(&htim7);
        __HAL_TIM_SET_COUNTER(&htim7, 0);
        HAL_GPIO_WritePin(GPIOG, GPIO_PIN_13, GPIO_PIN_RESET);
    } else {
        HAL_GPIO_WritePin(GPIOG, GPIO_PIN_13, GPIO_PIN_SET);
        HAL_TIM_Base_Stop_IT(&htim7);
    }
}
denis krasutski
  • 618
  • 4
  • 9
  • Thank you for the answer, I have already tried it and the ReadPin function seemed not to be working with EXTI configured pin, or may be I was doing something wrong. Nevertheless, the problem still remains - timer calls it's interrupt as soon as it starts at the first time. Adding "First run" variable to the timer handler seems too crutchy to me. – Warpony Jun 16 '18 at 09:36
  • 1. EXTI configuration doesn't affect to HAL_GPIO_ReadPin, it must work without any limitation 2. Did you clear EXTI flags after configuration pin and before enabling IRQ? Call `__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0)` before `HAL_NVIC_EnableIRQ(EXTI0_IRQn)` – denis krasutski Jun 18 '18 at 09:04