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.
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.
spi_flash_write
and according to the reference it disables interrupts while writing to flash. – Juraj Nov 22 '19 at 14:45