Search code examples
cgame-developmentstm32f4

Avoid Input Latency while reading input from keyboard loop


I'm just starting win STM32 and am trying to write some code which tries to accept input from user keypress, and vary the blink-rate of 2 LEDs or blink them alternatively, or at the same time. So, I have 3 Keys(2 keys each for inc/dec, and one key for mode), and 2 LEDs. The loop section looks something like this:

  /* USER CODE BEGIN WHILE */
  const uint32_t step = 50u;
  const uint32_t max_interval = 500u;

  uint32_t interval = max_interval;
  short mode = 0;
  while (1)
  {
    volatile GPIO_PinState wakeup = HAL_GPIO_ReadPin(WAKEUP_GPIO_Port, WAKEUP_Pin);
    mode = (wakeup == GPIO_PIN_RESET? 0: 1);

    if(mode == 1) {
        HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_RESET);
    }

    HAL_GPIO_TogglePin(LED2_GPIO_Port, LED2_Pin);
    HAL_GPIO_TogglePin(LED2_GPIO_Port, LED3_Pin);

    volatile GPIO_PinState key0 = HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin);
    volatile GPIO_PinState key1 = HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin);
    if(key0 == GPIO_PIN_RESET)
        interval -= (interval==step? 0: step);

    if(key1 == GPIO_PIN_RESET)
        interval += (interval==max_interval? 0: step);

    HAL_Delay(interval);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

Now, depending on the HAL_Delay(interval), the loop would get a chance to check for key-input, whose purpose is to control the blink rate. Is there some way, I can untie this latency for key-input? The microcontroller in question is STM32F407VET6, and I'm using CubeIDE. It would be nice to have a single-threaded solution.


Solution

  • Some delay for key input is unavoidable, unless you have some hardware-debounced keys. Normally, when hitting a key, the transition is not a single edge, but some burst of level changes until the mechanics settle. One way to do debouncing would be to have a periodic interval timer (e.g. at 1khz rate) and you check each time the level of a key. If it is high, you count a counter up. If it is low, you count a counter down and then you have 2 thresholds (hysteresis) in the count values, when you consider it a button down or button up transition. Since all that works in the interrupt, you could then push the key event into a FIFO (queue) and in your "main thread", you can pull the events at convenient occasions.

    If there is also a programmable timer on your hardware, you could use that to toggle the output pins for the LED and your main loop would then simply be along the lines:

    void mainloop() {
      while (true) {
        KeyEvent_t key;
        nextKeyEvent(&key);
        switch (key) {
           case BUTTON1_DOWN: 
             reduceBlinkRate();
             break;
           case BUTTON2_DOWN:
             increaseBlinkRate();
             break;
           default:
             // skillful doing nothing (e.g. to save power)
             break;
        }
      }
    }