ESP32 In MicroPython: Interrupts
Written by Mike James & Harry Fairhead   
Wednesday, 03 April 2024
Article Index
ESP32 In MicroPython: Interrupts
esppython360 Interrupt Service Routine Restrictions
Race Conditions and Starvation

Interrupts are hard but not in MicroPython. This extract from Programming the ESP32 in MicroPython, part of the I Programmer Library, shows you how to get started with interrupts and when not to use them.

Programming the ESP32in MicroPython

By Harry Fairhead & Mike James


Buy from Amazon.



  1. The ESP32 – Before We Begin
  2. Getting Started
  3. Getting Started With The GPIO 
  4. Simple Output
  5. Some Electronics
  6. Simple Input
  7. Advanced Input – Interrupts
  8. Pulse Width Modulation
    PWM And The Duty Cycle
  9. Controlling Motors And Servos
  10. Getting Started With The SPI Bus
  11. Using Analog Sensors
    Analog Input
  12. Using The I2C Bus
    : I2C, HTU21D And Slow Reading 
  13. One-Wire Protocols
  14. The Serial Port
  15. Using WiFi
  16. Sockets
    Client Sockets
    SSL Client Sockets***NEW!
  17. Asyncio And Servers
  18. Direct To The Hardware
    Using Hardware Registers 


When you start to work with multiple inputs that mean a range of different things, input really becomes a challenge. You can control much of the complexity using finite state machines and similar organizational principles, but sooner or later you are going to have to deal with the problem of input when your program isn’t ready for it. Sudden urgent unexpected input is the most difficult to deal with and when in this situation it is natural to think of the interrupt because this is the essence of urgent! However, things are much more complicated than they seem at first and so we need to consider when and where it is appropriate to give up polling for an event and change to responding to an interrupt.

Interrupts Considered Harmful?

An interrupt is a hardware mechanism that stops the computer doing whatever it is currently doing and makes it transfer its attention to running an interrupt handler. You can think of an interrupt as an event flag that, when set, interrupts the current program to run the assigned interrupt handler.

Using interrupts means the outside world decides when the computer should pay attention to input and there is no need for a polling loop. Most hardware people think that interrupts are the solution to everything and polling is inelegant and only to be used when you can’t use an interrupt. This is far from the reality. There is a general feeling that real-time programming and interrupts go together and if you are not using an interrupt you are probably doing something wrong. In fact, the truth is that if you are using an interrupt you are probably doing something wrong. So much so that some organizations are convinced that interrupts are so dangerous that they are banned from being used at all.

Interrupts are only really useful when you have a low-frequency condition that needs to be dealt with on a high-priority basis. The reason is that polling for an event that rarely occurs is a time waster and treating the rare event using an interrupt makes reasonable sense. Interrupts can simplify the logic of your program, but rarely does using an interrupt speed things up because the overhead involved in interrupt handling is usually quite high. 

If you have a polling loop that takes 100ms to poll all inputs and there is an input that demands attention in under 60ms then clearly the polling loop is not going to be good enough. Using an interrupt allows the high-priority event to interrupt the polling loop and be processed in less than 100ms. However, if this happens very often the polling loop will cease to work as intended. An alternative is to simply make the polling loop check the input twice per loop.

For a more real-world example, suppose you want to react to a doorbell push button. You could write a polling loop that simply checks the button status repeatedly and forever or you could write an interrupt service routine (ISR) to respond to the doorbell. The processor would be free to get on with other things until the doorbell was pushed when it would stop what it was doing and transfer its attention to the ISR. 

How good a design this is depends on how much the doorbell has to interact with the rest of the program and how many doorbell pushes you are expecting. It takes time to respond to the doorbell push and then the ISR has to run to completion - what is going to happen if another doorbell push happens while the first push is still being processed? Some processors have provision for forming a queue of interrupts, but that doesn't help with the fact that the process can only handle one interrupt at a time. Of course, the same is true of a polling loop, but if you can't handle the throughput of events with a polling loop, you can't handle it using an interrupt either, because interrupts add the time to transfer to the ISR and back again. 

Finally, before you dismiss the idea of having a processor do nothing but ask repeatedly "is the doorbell pressed", consider what else it has to do. If the answer is "not much" then a polling loop might well be your simplest option. Also, if the processor has multiple cores, then the fastest way of dealing with any external event is to use one of the cores in a fast polling loop. This can be considered to be a software emulation of a hardware interrupt – not to be confused with a software interrupt or trap, which is a hardware interrupt triggered by software.

If you are going to use interrupts to service input then a good design is to use the interrupt handler to feed an event queue. This at least lowers the chance that input will be missed.

Despite their attraction, interrupts are usually a poor choice for anything other than low-frequency events that need to be dealt with quickly. 

Last Updated ( Wednesday, 03 April 2024 )