Last post we have figured out how to make the LED blink and learn some GPIO functions including: write, toggle and read. In this STM32F0 tutorial, we will learn how to configure, use GPIOs as external interrupt signal to trigger an LED without depending on main loop routine with CubeMX. We will:

  1. Understand some basic knowledge about interrupts of STM32F0
  2. Configure the STM32CubeMX project and synchronize files with Source Insight
  3. Test some code and see what we can do next with this Interrupt controller.

Interrupts are some kinds of emergent signals that may pop up to the CPU and request it to pause the main program to execute some critical code at some other places, which is called Interrupt handler or Interrupt service routine (ISR), and jump back, resume the main program from where it is paused. Therefore, it can be used to handle some events at unexpected moment that does not require much execution time.  For example, you have a very long code and many long delay in your main routine, but you also need your program to act quickly when there are input from user or other devices such as input button or sensors that requires periodically readout. So, interrupt handler will help you to do that instead of putting a lot of wasted condition checking syntax inside the main program to catch the input events.

Some properties to achieve reliable interrupt handlers that we need to remember:

  1. The code inside the interrupt handler must be as brief as possible.
  2. Never use delay or wait or any kind of interval inside the interrupt handler.
  3. Their shared variables must be carefully managed.

Nested vectored interrupt controller (NVIC)

This is what you may not hear about when working with 8bit microcontroller such as AVR or PIC. The NVIC and the processor core interface are closely coupled, which enables low latency interrupt processing and efficient processing of late arriving interrupts. All interrupts including the core exceptions are managed by the NVIC. The STM32F0 has more than 30 interrupts which depend on the STM32F0 device line. Each interrupt corresponds with a physical address (interrupt vector) which is simply used to indicate the position of the interrupt handler so that it can jump correctly. The vector table can be found in the STM32F0 reference manual (p. 218).

vector tablevector table1

The NVIC has the ability to handle interrupts with different priorities as seen from the table above, the smaller number the priority column is, the higher priority it is. The priority can be changed by user from the program. There are many interrupts source: EXTI line, Timer, ADC,… and we will focus first on the external interrupt lines (red dot in the table).

STM32F0 support the nesting of interrupts, which means during the execution of a low priority interrupt handler, a high priority service can pre-empt and the low priority handler is suspended, and resume when the high priority handler completed.

figure_2_nested_interrupt

Source: http://community.arm.com/docs/DOC-2607

 External Interrupt

Turn back to the main part of this tutorial, I will show how to use the external interrupt of the STM32F0. The proposed problem is that you have a very long delay in your main loop that you can not catch the input button correctly. In this case, please watch and follow the video below to get it run initially before we dig deeper. First part of the video states the problem then following with interrupt solution.

The code in the video:

 So why do we choose EXTI0_1 ?

 What makes me really interested in STM32 is that all of the IO pins can be used as the external interrupt line (EXTI) while AVR only has 2 fixed pins for that. However, it does not mean that you can use all 55 pins of the STM32F051 as EXTI lines at the same time.  In fact, we can use up to 16 EXTI lines simultaneously due to the following  external interrupt GPIO mapping:

external interrupt   So it means that you cannot use PA0 and PB0 as EXTI lines at the same time but PA0 and PB1 is ok. The User button on the STM32F0 kit was connected to PA0 as follow:

button_sch Obviously, EXTI0 is the one we need. Besides, EXTI0 and EXTI1 share the same interrupt handler (vector EXTI0_1 in the vector table) so just need to make sure that you check which one is triggered inside the handler (not mentioned in the video). Moreover, EXTI2 and EXTI3 share the EXTI2_3 handler and EXTI4 to EXTI15 will share the EXTI4_15 handler.

Next, what about the signal edge (falling, rising) ?

The falling and rising edge of the signal is simply the transition from high to low and vice versa.

irq_sign

Since we want to fire the interrupt when the button is both pressed and released, we need to configure it to detect both edge in the CubeMX as in the video. You can change to detect only one edge as well depend on your input signal.

It’s your turn !

Now, simple exercise for you. You can try using the button and EXTI to control 2 LEDs on the kit. When you press the button, the green LED will blink slowly, let’s say 2 seconds delay and the blue LED blinks faster at 0.2s. When you release the button, reverse the LEDs: green blinks fast, blue blinks slowly. It would be nice if you can share you result in the comment 😀

Next tutorial will be about Timer and Counter 🙂

Comments

comments

21 Thoughts on “STM32F0 Tutorial 3: External Interrupts

  1. Onia on 22/03/2015 at 1:03 AM said:

    Excellent!

  2. Sukru on 14/06/2015 at 7:13 PM said:

    Hey dude i am waiting for your timer tutorial.When are you gonna put it?

    • Le Tan Phuc on 14/06/2015 at 7:37 PM said:

      Haha, really busy these days, hopefully next week I will be able to make it.

      • Sukru on 15/06/2015 at 11:39 PM said:

        I did your exercise and it works but i have some questions.How can i make leds have own delay ?

  3. Le Tan Phuc on 16/06/2015 at 5:22 PM said:

    Do you mean you want to blink many LEDs with different delay periods ? You can use only one timer interrupt to do that. Basically, you need to create 1ms or 5ms or 10ms timer interrupt base, depend on what resolution you want. Then inside the timer interrupt routine, you can toggle the leds based on the time stamp. For example:
    void interrupt() //10ms timer interrupt
    {
    count++;
    if (count%5==0) toggle(LED1); //LED1 blinks every 50ms
    if (count%10==0) toggle(LED2); //LED2 blinks every 100ms

    if (count==50) count=0; //reset count after reaching 500ms
    }
    This way can be used to control RC servos as well and usually be used for low level MCU with one or two timers only. The STM32’s timers are really advanced with many function that it will take me some times to do the tutorial. But I will try to make it this week.

  4. Sukru on 17/06/2015 at 6:59 PM said:

    You really are a good teacher and person thanks for respond :))

  5. Iran Espinoza on 20/06/2015 at 3:10 AM said:

    Hi Le Tan Phuc, You know how I can display a variable in stmstudio, used in the file of interruption? for example, a counter variable anyone, if I declared in main.c, and make operations in main.c, I can visualize, but if i use it, in stm32f0xx_it.c, I need to declare here, but I can not see in stmstudio . You know why? thanks in advance.

    • Le Tan Phuc on 20/06/2015 at 12:27 PM said:

      Hi Iran,

      In case you declare a global variable (outside of any function) the “stm32f0xx_it.c” file, you still can check it using STMStudio, I have tried and it is possible. I think that you declare a local variable inside a void so that it will not be used for the whole program and then, there will be no fixed address for that variable. So, for short, only global variable can be monitored.

  6. Iran Espinoza on 13/07/2015 at 12:17 AM said:

    Ok, thx! There’s so much to learn! sorry for the late answer!

  7. Mike M. on 20/11/2015 at 11:19 PM said:

    Hi!

    Handling the interrupt like this is not really how the HAL code expects you to do it. Instead you should create the function:

    void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
    {
    }

    This function is called from the HAL interrupt handler.

    Thanks for your awesome tutorials!

    -Mike

    • Le Tan Phuc on 21/11/2015 at 12:14 AM said:

      Hi Mike, thank you for your suggestion. For other peripherals’ interrupt I use the same way as yours. Just in this external interrupt tutorial, I put the toggle part inside the ‘Stm32f0xx_it.c’ file because at the time making this, I was still influenced by the way I used interrupt with the old library v3.5 🙂

    • i caant understand whats it doing ,i also looked at hal driver user manual.
      but i cant understand can someone explainit??

  8. Nice tutorials.
    Please make a tutorial on usart with HAL library for stm32
    I am using stm32f401 nucleo

    • Le Tan Phuc on 31/12/2015 at 10:37 AM said:

      Hi, I’ve already done the uart tutorial for STM32F0, you can check on home page

  9. What happen if, say, I set PA0 as output and PB0 as input. I used Exti Line 0 to watch for Rising and falling Edge at PB0. Do the interrupt happen on that line if I set PA0 from low to high or high to low since PA0 and PB0 multiplexed in same Exti Line

  10. is your question just solvable bye timer??

  11. OMG it worked for me
    **main file:

    long x,i;

    while (1)
    {
    switch (x)
    {
    case 0:
    HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_2);
    break;

    case 1:
    if (i%5==0)HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_2);
    break;
    }

    i++;
    HAL_Delay(50);

    switch (x)
    {
    case 0:
    if (i%5==0)HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_3);
    break;

    case 1:
    HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_3);
    break;
    }

    if(i==501)i=1;
    }

    **interupt file:

    extern long x;

    x=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);

    i used stm32f103rbt ,maybe u need some ping remap;
    for me :
    pin 0 = key
    pin 2,3 = LED

    thank u man u’re really good,keep up the great work;

  12. ping=pin ,sorry!

  13. Ashish Malpani on 15/06/2016 at 4:03 PM said:

    Without using timers or multiple interrupts, is it possible to solve the problem that you stated?

Post Navigation