I'm using the esp32 as an spi master with a 24 bit ADC which uses SPI to transfer data. The ADC indicates that a new sample is ready to be retrieved by lowering an IO pin connected to the esp32. Should this SPI transaction be done directly in the gpio interrupt handler or in the main loop? I was thinking of maybe just setting a flag in the interrupt handler to indicate that a new sample is ready and then constantly checking that flag in the main loop. This is how I've done this before because I have always been wary of having interrupt routines take too long.
-
2It's up to you and how well it fits in what you are trying to do. You should understand *why* it is bad when ISR is taking too long and see if the reason apply to your case. – Eugene Sh. Jan 11 '19 at 18:35
-
1Please show us some code example for better understanding of the problem. – Hynek Bernard Jan 11 '19 at 18:44
2 Answers
As you use the freeRTOS you should have a task which reads the data from the ADC. The interrupt routine should only notify the (the most effective way is to use direct task notifications) the reader task. So none of your approaches are correct in this case.

- 60,014
- 4
- 34
- 74
You should do as little as possible in an interrupt handler. This is broadly true regardless of the platform or OS you're using.
Non-interrupt level code must lock out interrupts to ensure that data structures and I/O are not interfered with by an interrupt handler.
For instance, in your case you asked whether you should initiate the SPI transaction in the interrupt handler. If you do this, to be safe you'd need to make sure that anywhere you use SPI outside of the interrupt handler locks out interrupts. Otherwise it's possible that you might cause an inconsistent state in the SPI library, or in the hardware you're accessing via SPI, if an interrupt happens and you call the SPI library while it's also executing outside of the interrupt handler.
The same is true of data structures. Suppose you keep a linked list that you use outside of the interrupt handler, and add things to it inside the interrupt handler. If an interrupt happens at just the wrong time you'll corrupt the list structure unless you lock out interrupts when you manipulate or traverse it.
You want to minimize the amount of time that you lock out interrupts - locking them out can interfere with timing and lead to dropped data.
This means you're best off if you do the least possible work in the interrupt handler. Then don't need to lock out interrupts outside of it and you're won't miss interrupts or drop data, and you also won't run the risk of corrupting data structures or putting I/O hardware in an inconsistent state if you forget to lock out interrupts in a vital part of your code.
We usually use a simple variable called a "semaphore" to indicate that an interrupt happened. The interrupt handler may increment the semaphore and the non-interrupt level processing code may decrement it. As long as the compiler can manage the semaphore in a single instruction it will be safe from corruption.
In C, we need to declare the semaphore variable as volatile
, which lets the C compiler know that it may change at any time. The compiler then generates code that doesn't depend on the variable's value remaining the same between operations.
volatile int got_interrupt = 0;
An interrupt handler would simply increment got_interrupt
and the code running outside of the interrupt handler would inspect it and, if it was non-zero, would decrement it and take whatever actions were needed (in your case, call the SPI library).

- 6,218
- 3
- 16
- 12