title: STM32F411: is clearing an external interrupt flag really necessary?
body: <p>I've bought an STM32F411 nucleo board and now I'm trying to understand various bits and pieces of the HAL. Starting with external interrupts seemed to be a good idea, because the board has a push button which is connected to PC13. So I've set up a simple toggle-the-frequency blinky. The code below is a bit simplified:</p>
  
  <pre><code>#define LED_PIN GPIO_PIN_5
  #define BTN_PIN GPIO_PIN_13
  
  static uint32_t blink_period = 250;
  
  int main(void)
  {
    HAL_Init();
    SystemClock_Config();
  
    __GPIOA_CLK_ENABLE();
    GPIO_InitTypeDef pinConfig;
    pinConfig.Pin = (LED_PIN);
    pinConfig.Pull = GPIO_NOPULL;
    pinConfig.Mode = GPIO_MODE_OUTPUT_PP;
    pinConfig.Speed = GPIO_SPEED_FAST;
    HAL_GPIO_Init(GPIOA, &amp;pinConfig);
  
    __GPIOC_CLK_ENABLE();
    pinConfig.Pin = (BTN_PIN);
    pinConfig.Pull = GPIO_NOPULL;
    pinConfig.Mode = GPIO_MODE_IT_FALLING;
    pinConfig.Speed = GPIO_SPEED_LOW;
    HAL_GPIO_Init(GPIOC, &amp;pinConfig);
    HAL_NVIC_SetPriority(EXTI15_10_IRQn, 0x0F, 0x00);
    HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
  
    while (1)
    {
      HAL_GPIO_TogglePin(GPIOA, LED_PIN);
      HAL_Delay(blink_period);
    }
  }
  
  void EXTI15_10_IRQHandler(void)
  {
    HAL_GPIO_EXTI_IRQHandler(BTN_PIN);
  }
  
  void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
  {
    if(GPIO_Pin == BTN_PIN)
    {
      if (blink_period == 500)
      {
        blink_period = 250;
      }
      else
      {
        blink_period = 500;
      }
    }
  }
  </code></pre>
  
  <p>When I push the button, an interrupt is generated and the blinky frequency changes from 1 to 2 Hz (or vice-versa). This works as intended, but why? I forgot to clear the pending interrupt flag, so the ISR should be called over and over. The datasheet clearly states that</p>
  
  <blockquote>
    <p>When the selected edge occurs on the external interrupt line, an interrupt request is generated. The pending bit corresponding to the interrupt line is also set. This request is
    reset by writing a ‘1’ in the pending register.</p>
  </blockquote>
  
  <p>Reading a bit further reveals that this is a bit different for <em>events</em>:</p>
  
  <blockquote>
    <p>When the selected edge occurs on the event line, an event pulse is generated. The pending bit corresponding to the event line is not set.</p>
  </blockquote>
  
  <p>However, I'm not setting the button pin mode to any of the <code>GPIO_MODE_EVT_...</code> modes so I'm not using the event mechanism (to be honest I don't yet know what that even is - I just think that I'm not using it. Any hints are welcome).</p>
  
  <p>So somewhere I should have to call <code>void HAL_NVIC_ClearPendingIRQ (IRQn_Type IRQn)</code>, shouldn't I? It seems that clearing the flag by software is not necessary, because the ISR is not called more than once per falling edge. I've added a breakpoint in <code>HAL_GPIO_EXTI_Callback</code> to verify this.</p>
  
  <h2><strong>Edit</strong></h2>
  
  <p>As mentioned in the comments, the flag clearing code is in ST's implementation of the GPIO interrupt handler:</p>
  
  <pre><code>void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
  {
    /* EXTI line interrupt detected */
    if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET)
    {
      __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
      HAL_GPIO_EXTI_Callback(GPIO_Pin);
    }
  }
  </code></pre>
  
  <p>This handler needs to be called by the actual ISR (which is done in my code) and it clears the pending flag corresponding to the GPIO_Pin argument. So I have to write an ISR which sorts out which flags are set, and call <code>HAL_GPIO_EXTI_IRQHandler</code> for each, which in turn calls my <code>HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)</code>, again with the pin as an argument. For each external interrupt, the pin number would get checked some ~3 times (in the ISR, in the handler and in the callback)!</p>
  
  <p>If that is the solution, I want my problem back.</p>