Every way an interrupt or a task hands data to the rest of the program
A volatile flag, a critical section, a ring buffer, a FreeRTOS queue, semaphore or mutex, or a spinlock across cores. Who writes, who reads, and how much data decide which.
Ask who produces the data and who consumes it (an interrupt
handler, a task, loop(), the other core), how big it is, and
whether events can arrive faster than they are handled.
- One flag or one small value from an interrupt to
loop()→ avolatilevariable the handler sets andloop()reads. volatile makes every access happen; it does not make a multi-byte read atomic. - A multi-byte value or several related variables → read them
inside a short critical section (
noInterrupts()…interrupts()), so the handler can't change them halfway. - A stream of events from an interrupt → a single-producer,
single-consumer ring buffer, storing before publishing the index,
sized for the longest time
loop()can be away. - Between FreeRTOS tasks → a queue for data, a binary semaphore to
signal from an interrupt (
xSemaphoreGiveFromISR), a mutex to guard a shared resource, taken and given on every path. - Across the ESP32-S3's two cores →
noInterrupts()only stops this core; protect shared data with a portMUX spinlock or an RTOS primitive. - Large blocks from a peripheral → let DMA copy them, with double buffering so the processor works on one buffer while the other fills.
In every case keep the handler short: record and flag in the handler, and do the slow work (printing, maths) outside it.
Interrupt to loop()
Section
Writing safe ISRs
Short handlers that record and flag, volatile shared variables, and critical sections for multi-byte reads.
Term
volatile
Term
torn read
A stream of events
Section
Ring buffers
N slots hold at most N − 1 values; one writer, one reader, store before publishing.
Term
ring buffer
Example
Between tasks
Section
Queues, semaphores and mutexes
A queue for data, a binary semaphore to signal from an interrupt, a mutex to guard a resource.
What goes wrong when the sharing is unprotected, or locked in the wrong order.
Term
queue
Term
mutex
Term
semaphore
Across two cores
Section
ESP32 cores and tasks
Where loop() and the Wi-Fi tasks run, and why two cores make shared data harder to protect.
Term
spinlock
Big blocks without the processor
Section
DMA, where supported
A hardware copier between a peripheral and memory, and double buffering that overruns if the consumer is too slow.