Description
I think there is a problem with disabling/restoring interrupts in some cases. Interrupts may be disabled permanently.
noInterrupts/interrupts saves and restores interrupt state to a global.
#define xt_disable_interrupts(state, level) __asm__ __volatile__("rsil %%0," __STRINGIFY(level) : "=a" (state))
#define xt_enable_interrupts(state) __asm__ __volatile__("wsr %%0,ps; isync" :: "a" (state) : "memory")
extern uint32_t interruptsState;
#define interrupts() xt_enable_interrupts(interruptsState)
#define noInterrupts() __asm__ __volatile__("rsil %%0,15" : "=a" (interruptsState))
In the following, assuming interrupts are enabled before calling f2(), interrupts will be disabled after returning from f2().
void f1() {
noInterrupts(); // (2) Save interruptsState (interrupts disabled on entry)
...
interrupts(); // (3) Restore interrupts from interruptsState (disabled)
}
void f2() {
noInterrupts(); // (1) Save interruptsState and disable interrupts
...
f1();
...
interrupts(); // (4) Restore interrupts from interrupstState (disabled)
}
I am not familiar with ESP8266 ASM so perhaps I am missing something. Or is there a requirement for functions that call noInterrupts to never call another function that calls noInterrupts?
AVR code saves SREG (status register), disables interrupts, then restores SREG. Each function has its own copy of SREG to ensure correct save/restore of the interrupt state.
Assuming interrupts are enabled when f2() is called, interrupts are enabled at the end of f2(), not f1(). This looks correct. ARM code does something similar.
void f1() {
uint8_t sreg = SREG;
noInterrupts(); // (2) Save SREG, interrupts disabled before entry
...
SREG = sreg; // (3) Restore SREG, interrupts still disabled
}
void f2() {
uint8_t sreg = SREG;
noInterrupts(); // (1) Save SREG, interrupts were enabled but
// now disabled.
...
f1();
...
SREG = sreg; // (4) Restore SREG, enables interrupts.
}