ESP32 In MicroPython: Interrupts |
Written by Mike James & Harry Fairhead | |||||
Wednesday, 03 April 2024 | |||||
Page 4 of 4
Race Conditions and StarvationImplementing an ISR is a step into the complex world of asynchronous programs and if this is something of interest see Programmer’s Python: Async,ISBN:978-1871962765. The biggest new problem that asynchronicity introduces is the possibility of race conditions. A race condition occurs when two sections of code modify a shared resource in such an uncontrolled way that the final outcome depends on the timing of the code execution. Race conditions are particularly difficult to debug because they look random and the tendency is to think that they are due to faulty hardware and, worse, an intermittent fault. It is difficult to provide a clear and simple example of a race condition for the ESP32 because real time programming is inherently difficult to test. In addition, the implementation of interrupt handling in the ESP32 is at a higher level than raw interrupts in the sense that an ISR, once started, runs to completion. That is, ISRs are not interrupted. This means that it is the code in the main thread of execution which is interrupted and is the source of any race conditions. So while race conditions happen, they are difficult to demonstrate. Consider the problem of setting a byte array to either all ones or all zeros. In an ideal world this data structure would always be in either one of the two states – the setting would be atomic and not interruptible. However, the main thread can be interrupted both within and between MicroPython instructions. The following program uses an interrupt on GPIO4 to set a byte array to zero and a while loop in the main program to set it to all ones: import time from machine import Pin data = bytearray(b'\xf0\xf1\xf2') def myHandler(pin): global data for i in range(3): data[i]=0 pin = Pin(4, Pin.IN, Pin.PULL_DOWN) pin.irq(myHandler, Pin.IRQ_RISING) while True: for i in range(3): data[i] = 255 if data[0]!=data[1] or If you run this program you will discover that the byte array is often in a state that is a mix of the two: bytearray(b'\x00\x00\xff') bytearray(b'\x00\xff\xff') bytearray(b'\x00\xff\xff') bytearray(b'\x00\xff\xff') bytearray(b'\x00\xff\xff') bytearray(b'\x00\x00\xff') This occurs frequently even with interrupts occurring at ten per second. What happens is that the for loop starts to set the byte array to all ones a byte at a time. If an interrupt occurs during this process then the bytes are set to zero and when the loop restarts only the remaining bytes are set to all ones. If you don’t want the byte array to be in an inconsistent state then you need to disable the ISR while the main thread is using it: from machine import Pin data=bytearray(b'\xf0\xf1\xf2') def myHandler(pin): global data for i in range(3): data[i] = 0 print(data) pin = Pin(4, Pin.IN, Pin.PULL_DOWN) pin.irq(myHandler, Pin.IRQ_RISING) while True: pin.irq(None, Pin.IRQ_RISING) for i in range(3): data[i] = 255 if data[0]!=data[1] or data[1]!=data[2] or data[2]!=data[0]: print(data) pin.irq(myHandler, Pin.IRQ_RISING) This now works and you never see an inconsistent state for the byte array but now the ISR hardly ever gets to run. It only gets called once per while loop iteration and this severely limits its responsiveness. This is an example of “starvation” where one process hogs the CPU for so much of the time other processes fail to make much progress. In this case it is the ISR that is slowed down but a CPU hogging ISR can slow the main program down in exactly the same way. Notice the way that we set None as an ISR to disable the interrupt. In theory you can use: s=machine.disable_irq() print("doing something useful") machine.enable_irq(s) to create sections of code where interrupts cannot occur, but notice that this disables all interrupts, including timer ticks and this generally causes the ESP32 to crash. In chapter but not in this extract:
Summary
Programming the ESP32in MicroPythonBy Harry Fairhead & Mike JamesBuy from Amazon. ContentsPreface
<ASIN:187196282X>
Comments
or email your comment to: comments@i-programmer.info To be informed about new articles on I Programmer, sign up for our weekly newsletter, subscribe to the RSS feed and follow us on Twitter, Facebook or Linkedin. |
|||||
Last Updated ( Wednesday, 03 April 2024 ) |