It is certainly possible, although I do not think there is any clean
way of doing it...
Here is an idea that may work: right before the switch statement,
you save the current context with the setjmp()
function.
Then, in the ISR, you restore that context with longjmp()
. This is
kind of like a goto statement that works across functions:
#include <setjmp.h>
jmp_buf env;
ISR(FOO_vect) {
expression = ...;
longjmp(env, 1); // go to start of loop
}
void loop() {
setjmp(env); // landing point from ISR exit
switch (expression) {
...
}
}
Notice that the normal exit sequence of an ISR (the reti
instruction)
re-enables the interrupts. Since we are skipping this exit sequence, we
have to enable them explicitly upon return from setjmp()
interrupts are re-enabled not by the reti
instruction but by longjmp()
restoring the CPU's status register.
Warning: This is a (very dirty) hack that I have not tested. If I
were to use this trick, I would first:
- Carefully examine the generated assembly to convince myself it does
the right thing.
- Test, test, test...
In case of problems, debugging this may be harder than just testing the
expression inside every slow function you have.
Addendum: Although I am saying that there is no clean way of doing
what you intend, there certainly is a clean way of achieving the same
end result: just make sure your switch statements return fast. My
preferred way of doing this would be to make sure no function ever
waits. For example:
- A routine reading sensors would not wait for them to respond. Instead,
it would return immediately if no reading is available. If a reading
is available, it would retrieve it, send a query to the next sensor
in the list, then return.
- A communication routine would not wait for complete messages. Instead,
it would return immediately if no byte is available. If a byte is
available, it would buffer it and return. Unless it's the last byte of
a complete message, in which case it would process the message.
Obviously this could require a heavy refactoring of your code, probably
using finite state machines (see for example the tutorials
here
and here). It may be easier to
just test whether the expression has changed inside every busy-wait loop
you have, as recommended by Gerben's and Nick's answers.