Skip to main content
Arduino

Return to Answer

+ note on saguard from HardwareSerial.
Source Link
Edgar Bonet
  • 45.1k
  • 4
  • 42
  • 81

Edit: As Juraj points out in a comment, the HardwareSerial code now implements a workaround against this problem : if it detects it has to wait with interrupts disabled, it takes care of calling the interrupt handler itself. This is a (relatively) late addition to the HardwareSerial code. Their authors presumably witnessed too many beginners doing debug prints from interrupt handlers and being bitten by this issue. Note that it is a workaround, not a solution: it will often make the critical section last for an unreasonably long time.

I wouldn't rely on similar APIs, or even on other cores, systematically implementing this kind of safeguards though: some library authors just trust the user to not do silly things.

Edit: As Juraj points out in a comment, the HardwareSerial code now implements a workaround against this problem : if it detects it has to wait with interrupts disabled, it takes care of calling the interrupt handler itself. This is a (relatively) late addition to the HardwareSerial code. Their authors presumably witnessed too many beginners doing debug prints from interrupt handlers and being bitten by this issue. Note that it is a workaround, not a solution: it will often make the critical section last for an unreasonably long time.

I wouldn't rely on similar APIs, or even on other cores, systematically implementing this kind of safeguards though: some library authors just trust the user to not do silly things.

Source Link
Edgar Bonet
  • 45.1k
  • 4
  • 42
  • 81

John Romkey provided you an excellent answer. I am adding this just to provide another perspective, hopefully complementary.

Interrupts are meant to handle the most time-critical tasks. Those tasks that cannot wait for the next loop() iteration, such as counting a pulse from an encoder, or getting a byte out of the UART receive buffer. If you delay them too much, they may miss their deadline, resulting in unreliable operation of the whole program (counter missing pulses, UART missing bytes...).

Sometimes you have a piece of code that cannot afford being interrupted. Maybe it is extremely time-critical, like the generation in software of a pulse that is exactly 0.5 μs wide. More commonly it will be reading data from memory that is being modified by an interrupt handler, and you don't want that data to be modified in the middle of the read operation. Such pieces of code are called critical sections, and you keep them safe in between noInterrupts() and interrupts(). If an interrupt request fires while the program is running a critical section, the request is put on hold and serviced only when the critical section is done. This adds some latency to the interrupt which, if excessive, can lead to the interrupt missing its deadline. This is the reason critical sections should be kept as short as possible.

You have been told that interrupt handlers should be kept as short as possible, but I am not sure you know why it is so. The fundamental reason is that interrupt handlers are themselves critical sections. While a handler is running, other interrupts are blocked. On some architectures (notably not AVR, I don't know about the ESP), only interrupts of lower priority are blocked, but it is still an issue. The rationale for keeping those handlers short applies equally to any critical section.

Now, just to provide an example of the sort of bad things that can happen if you block interrupts unnecessarily, consider this piece of code:

noInterrupts();
Serial.println("Inside critical section.");
interrupts();

What this does is put the string "Inside critical section." in a software buffer. Not a huge task you may say. Actually pushing the bytes out to the UART is the job of an interrupt handler, triggered by the UART when it is ready to accept a new byte. But then what happens if there is not enough free space in the buffer for the string? In this case, Serial.println() waits in a busy loop. It waits for the interrupt to move bytes out of the buffer and make space for the new string. But wait, we have just disabled interrupts... See the problem? This is the reason it is generally advised to never Serial.print() inside an interrupt handler. The same applies to any critical section.

AltStyle によって変換されたページ (->オリジナル) /