I have to write a C program to toggle an LED using an external interrupt on STM32F103(72MHz System Clock). I have initialized EXTI3 on the Falling edge and the ISR Handler toggles an led at high frequency input on external interrupt sensing pin there are delay between sensing and execution of ISR (Approximately 2.6uSec, almost 188 system clock pulse). Where does this delay come from?

I am Attaching my code blow, I have verify my micro-controller clock by writing timer 1 PWM for specific frequency (witch is calculated by the clock frequency 72MHz).

Here Is my code:

#include "stm32f10x.h"

                //LED PUTPUT
                //JTAG-DP Disabled and SW-DP Disabled PA13, PA14, PA15 PB3 and PB4 Release from JTAG-DP/SW-DP module
                //Reset default Value Reset value: 0x4444 4444(ALL INPUT ARE FLOATING) to 0x00000000 (General purpose output push-pull )
                //01: Output mode, max speed 10 MHz.
                //10: Output mode, max speed 2 MHz.
                //11: Output mode, max speed 50 MHz.
                    RCC->APB2ENR |=RCC_APB2ENR_AFIOEN;\
                    AFIO->MAPR |=AFIO_MAPR_SWJ_CFG_DISABLE;\
                    GPIOA->CRH &=~(GPIO_CRH_CNF13|GPIO_CRH_CNF14);\
                    GPIOA->CRH |=(GPIO_CRH_MODE13|GPIO_CRH_MODE14);\
                    GPIOA->ODR &=~(GPIO_ODR_ODR13|GPIO_ODR_ODR14);\
                    GPIOC->CRH &=~(GPIO_CRH_CNF13);\
                    GPIOC->CRH |=GPIO_CRH_MODE13;\
                    GPIOC->BSRR |=GPIO_BRR_BR13;//Set LED(active Low) BIT PC13 High
                    //GPIOC->ODR |=(1<<13);//PIN PC13 is High

#define LED0_ON()           GPIOC->ODR |=GPIO_ODR_ODR13
#define LED0_OFF()          GPIOC->ODR &=~GPIO_ODR_ODR13
#define LED1_ON()           GPIOA->ODR |=GPIO_ODR_ODR13
#define LED1_OFF()          GPIOA->ODR &=~GPIO_ODR_ODR13
#define LED2_ON()           GPIOA->ODR |=GPIO_ODR_ODR14
#define LED2_OFF()          GPIOA->ODR &=~GPIO_ODR_ODR14
#define LED0_TOGGLE()           GPIOC->ODR ^=GPIO_ODR_ODR13
#define LED1_TOGGLE()           GPIOA->ODR ^=GPIO_ODR_ODR13
#define LED2_TOGGLE()           GPIOA->ODR ^=GPIO_ODR_ODR14

#define DEL 1000

void LED_SWITCH_INIT(void);
void interrupt_enable(void);
void Blink_LED(uint32_t del);
void delay(uint32_t del);

int main(void)

void LED_SWITCH_INIT(void){
        RCC->APB2ENR |=RCC_APB2ENR_IOPBEN;//Clock Enable For Port B
        //LED PUTPUT
        //SWITCH INPUT 176
        AFIO->MAPR =AFIO_MAPR_SWJ_CFG_DISABLE;  //TAG-DP Disabled and SW-DP Disabled



        AFIO->EXTICR[0] |=AFIO_EXTICR1_EXTI3_PB;    //Select EXT3 on PORTB for External interrupt3
        EXTI->IMR |=EXTI_IMR_MR3;//|EXTI_IMR_MR19;  // (0)Select PIN PB3/* Interrupt mask register (EXTI_IMR) */
        //EXTI->IMR |=EXTI_IMR_MR5;
        //EXTI->EMR |= EXTI_EMR_MR3;//|EXTI_EMR_MR19; ///* Event mask register (EXTI_EMR) */
        EXTI->RTSR |=EXTI_RTSR_TR3; ////0: Rising trigger disabled (for Event and Interrupt) for input line
        //EXTI->FTSR |=EXTI_FTSR_TR3;   //1: Falling trigger enabled (for Event and Interrupt) for input line.
    /* Falling trigger selection register (EXTI_FTSR) */
        //EXTI->FTSR |=EXTI_FTSR_TR5;
    /* Rising trigger selection register (EXTI_RTSR) */
        //EXTI->RTSR |=EXTI_RTSR_TR5;
    /* Pending register (EXTI_PR) */
        EXTI->PR |=EXTI_PR_PR3; //Clear Interrupt Flag
        //NVIC IRQ See Interrupt Enable faction */

void interrupt_enable(void){
    unsigned int priority = 0,Group=0;

    /* bits[7:4] used for Group Priority
       N/A used for Sub-Group Priority */

    priority = NVIC_EncodePriority(Group,0,0);
    /*0= Priority Grouping, 0= Group Priority, 0= Sub-Priority*/

    NVIC_SetPriority(EXTI3_IRQn,priority);//Set new Priority




void EXTI3_IRQHandler(void){//
    if ((EXTI->PR&EXTI_PR_PR3)) {
        EXTI->PR |=EXTI_PR_PR3; //Clear the EXTI line 3 pending bit
  • 4
    \$\begingroup\$ How did you measure 2.6 uSec? \$\endgroup\$ – kjgregory Dec 21 '17 at 21:43
  • \$\begingroup\$ The word is interrupt latency. It is time to acknowledge interrupt + pushing registers for a return point + jumping to new address. \$\endgroup\$ – MaNyYaCk Dec 22 '17 at 0:58
  • \$\begingroup\$ Please edit your question, and at the bottom of your question, add the C source code to your program (which I hope is small). Then select all that source code (and only the source code) and click the {} icon above the text box, to correctly format the selected text as "code" . \$\endgroup\$ – SamGibson Dec 22 '17 at 5:14
  • \$\begingroup\$ How do you know that your MCU runs at 72 MHz? The timing seems about correct when running on the default 8MHz internal oscillator. \$\endgroup\$ – Turbo J Dec 22 '17 at 13:37

When an interrupt occurs, ISR has to be executed by the controller. However in between the occurence of interrupt and starting of ISR execution, following things are typically done by the controller:

  1. Finish the execution of whatever instruction it was executing at the time of occurrence of the interrupt.

  2. Context saving ( pushing all regs and the address of next instruction to be executed, to stack )

  3. Jump to the interrupt vector table and resolve the address of ISR. i.e., where the corresponding ISR is sitting ?

Finally the ISR will start executing. These factors make up the delay, what we call interrupt latency. And in your case it is 2.6 us.


There is always an inherit latency (delay) from the time an event trigger has been set, in this case a MPU pin is brought high or low. However not only is there a clock cycle delay from the 4-phase clock that drives most all CPU/MPU cores, any existing code in process must reach a safe point where it can be interrupted. If you did not define an interrupt window in your main code where interrupts are enabled for so many uS, then disabled whether an ISR call was pending or not, then the reaction time to an ISR call is unknown.

I insert at the re-entry loop of each block of code (that might maintain 'state' for some time) a ISR routine called IWIN, which stands for interrupt window. It alone enables interrupts at a known point in the code for 10uS or so. It allows pending interrupts to run then exit. If no ISR is pending then IWIN times-out, disables interrupts and returns to main code.

Remember that all triggers, either by hardware or software, have a pending status before an ISR can handle them. You should define where interrupts are allowed to avoid unpredictable behavior in your program. Even so existing code needs to complete to a safe point before it should check for ISR status.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.