Interrupt latency on a STM32F303 MCU
Problem

Well you have to look at the functions you are using, you can't just make assumptions on the speed of code you haven't looked at:

This is the EXTI_GetITStatus function:

ITStatus EXTI_GetITStatus   (   uint32_t    EXTI_Line    )  
{
  ITStatus bitstatus = RESET;
  uint32_t enablestatus = 0;

  /* Check the parameters */
  assert_param(IS_GET_EXTI_LINE(EXTI_Line));

  enablestatus =  *(__IO uint32_t *) (((uint32_t) &amp;(EXTI-&gt;IMR)) + ((EXTI_Line) &gt;&gt; 5 ) * 0x20) &amp; (uint32_t)(1 &lt;&lt; (EXTI_Line &amp; 0x1F));

  if ( (((*(__IO uint32_t *) (((uint32_t) &amp;(EXTI-&gt;PR)) + (((EXTI_Line) &gt;&gt; 5 ) * 0x20) )) &amp; (uint32_t)(1 &lt;&lt; (EXTI_Line &amp; 0x1F))) != (uint32_t)RESET) &amp;&amp; (enablestatus != (uint32_t)RESET))
  {
    bitstatus = SET;
  }
  else
  {
    bitstatus = RESET;
  }
  return bitstatus;

}


As you can see, this is not a simple thing requiring just a cycle or two.

Next is your LED toggle function:

void STM_EVAL_LEDToggle (   Led_TypeDef     Led  )  
{
  GPIO_PORT[Led]-&gt;ODR ^= GPIO_PIN[Led];
}


So here you have some array indexing and a read modify write to toggle the LED.

HALs often end up creating a good amount of overhead because they must take care of wrong settings and wrong usage of the functions. The needed parameter checking and also the translation from a simple parameter to a bit in the register can take a serious amount of computing (well for a time critical interrupt at least).

So in your case, you should implement your interrupt bare metal directly on the registers and not rely on any HAL.



Example solution

For example something like:

if (EXTI-&gt;PR &amp; EXTI_PR_PR6)
{
    GPIOE-&gt;BSRR = GPIO_BSRR_BS_8;
    EXTI-&gt;PR = EXTI_PR_PR6;
}


Note: this will not toggle the LED but simply set it. There is no atomic toggle available on the STM GPIOs. I also don't like the if construct I used, but it generates faster assembly then my preferred if (EXTI_PR_PR6 == (EXTI-&gt;PR &amp; EXTI_PR_PR6)).

A toggle variant could be something along these lines:

static bool LEDstate = false;
if (EXTI-&gt;PR &amp; EXTI_PR_PR6)
{
    if (!LEDstate)
    {
        GPIOE-&gt;BSRR = GPIO_BSRR_BS_8;
        LEDstate = true;
    }
    else
    {
        GPIOE-&gt;BSRR = GPIO_BSRR_BR_8;
        LEDstate = false;
    }
    EXTI-&gt;PR = EXTI_PR_PR6;
}


Using a variable residing in RAM instead of using the ODR register should be faster, especially when you use 72 MHz, because access to the peripherals can be slower due to synchronization between different clock domains and peripheral clocks simply running at a lower frequency. Of course, you may not change the state of the LED outside of the interrupt for the toggle to work correctly. Or the variable must be global (then you have to use the volatile keyword when declaring it) and you have to change it everywhere accordingly.

Also note, that I'm using C++, hence the bool and not some uint8_t type or similar to implement a flag. Although if speed is your primary concern you should probably opt for a uint32_t for the flag as this will always be aligned correctly and not generate additional code when accessing.

The simplification is possible because you hopefully know what you are doing and always keep it that way. If you really just have a single interrupt enabled for the EXTI9_5 handler you can get rid of the pending register check altogether, reducing the number of cycles even further.

This leads to another optimization potential: use a EXTI line which has a single interrupt like one of EXTI1 to EXTI4. There you don't have to perform a check whether the correct line has triggered your interrupt.