Skip to content

Commit af204f9

Browse files
committed
Interrupt cleanup
Fixes issue of reentrant calls to nointerrupts() exposed functional replacements to cli sei and SREG when dealing with interrupts InterruptLock class to auto stop and restore interrupt level Fix user ISR calls to be like Arduino with interrupts disabled fully.
1 parent 88834ac commit af204f9

File tree

5 files changed

+58
-18
lines changed

5 files changed

+58
-18
lines changed

hardware/esp8266com/esp8266/cores/esp8266/Arduino.h

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -137,17 +137,50 @@ void timer0_detachInterrupt(void);
137137
void ets_intr_lock();
138138
void ets_intr_unlock();
139139

140-
// level (0-15),
141-
// level 15 will disable ALL interrupts,
142-
// level 0 will disable most software interrupts
140+
#ifndef __STRINGIFY
141+
#define __STRINGIFY(a) #a
142+
#endif
143+
144+
// these low level routines provide a replacement for SREG interrupt save that AVR uses
145+
// but are esp8266 specific. A normal use pattern is like
146+
//
147+
//{
148+
// uint32_t savedPS = xt_rsil(1); // this routine will allow level 2 and above
149+
// // do work here
150+
// xt_wsr_ps(savedPS); // restore the state
151+
//}
143152
//
144-
#define xt_disable_interrupts(state, level) __asm__ __volatile__("rsil %0," __STRINGIFY(level) : "=a" (state))
145-
#define xt_enable_interrupts(state) __asm__ __volatile__("wsr %0,ps; isync" :: "a" (state) : "memory")
153+
// level (0-15), interrupts of the given level and above will be active
154+
// level 15 will disable ALL interrupts,
155+
// level 0 will enable ALL interrupts,
156+
//
157+
#define xt_rsil(level) (__extension__({uint32_t state; __asm__ __volatile__("rsil %0," __STRINGIFY(level) : "=a" (state)); state;}))
158+
#define xt_wsr_ps(state) __asm__ __volatile__("wsr %0,ps; isync" :: "a" (state) : "memory")
159+
160+
#define interrupts() xt_rsil(0)
161+
#define noInterrupts() xt_rsil(15)
146162

147-
extern uint32_t interruptsState;
163+
// this auto class wraps up xt_rsil so your code can be simplier, but can only be
164+
// used in an ino or cpp files. A normal use pattern is like
165+
//
166+
//{
167+
// {
168+
// InterruptLock(1); // this routine will allow level 2 and above
169+
// // do work within interrupt lock here
170+
// }
171+
// do work outside of interrupt lock here outside its scope
172+
//}
173+
//
174+
#define InterruptLock(intrLevel) \
175+
class _AutoDisableIntr { \
176+
public: \
177+
_AutoDisableIntr() { _savedPS = xt_rsil(intrLevel); } \
178+
~_AutoDisableIntr() { xt_wsr_ps(_savedPS); } \
179+
private: \
180+
uint32_t _savedPS; \
181+
}; \
182+
_AutoDisableIntr _autoDisableIntr
148183

149-
#define interrupts() xt_enable_interrupts(interruptsState)
150-
#define noInterrupts() __asm__ __volatile__("rsil %0,15" : "=a" (interruptsState))
151184

152185
#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )
153186
#define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() )

hardware/esp8266com/esp8266/cores/esp8266/core_esp8266_timer.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,13 @@ static volatile timercallback timer1_user_cb = NULL;
3232
void timer1_isr_handler(void *para){
3333
if ((T1C & ((1 << TCAR) | (1 << TCIT))) == 0) TEIE &= ~TEIE1;//edge int disable
3434
T1I = 0;
35-
if (timer1_user_cb) timer1_user_cb();
35+
if (timer1_user_cb) {
36+
// to make ISR compatible to Arduino AVR model where interrupts are disabled
37+
// we disable them before we call the client ISR
38+
uint32_t savedPS = xt_rsil(15); // stop other interrupts
39+
timer1_user_cb();
40+
xt_wsr_ps(savedPS);
41+
}
3642
}
3743

3844
void timer1_isr_init(){
@@ -72,7 +78,11 @@ static volatile timercallback timer0_user_cb = NULL;
7278

7379
void timer0_isr_handler(void* para){
7480
if (timer0_user_cb) {
81+
// to make ISR compatible to Arduino AVR model where interrupts are disabled
82+
// we disable them before we call the client ISR
83+
uint32_t savedPS = xt_rsil(15); // stop other interrupts
7584
timer0_user_cb();
85+
xt_wsr_ps(savedPS);
7686
}
7787
}
7888

hardware/esp8266com/esp8266/cores/esp8266/core_esp8266_wiring_digital.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,11 @@ void interrupt_handler(void *arg) {
123123
if (handler->fn &&
124124
(handler->mode == CHANGE ||
125125
(handler->mode & 1) == digitalRead(i))) {
126+
// to make ISR compatible to Arduino AVR model where interrupts are disabled
127+
// we disable them before we call the client ISR
128+
uint32_t savedPS = xt_rsil(15); // stop other interrupts
126129
handler->fn();
130+
xt_wsr_ps(savedPS);
127131
}
128132
}
129133
ETS_GPIO_INTR_ENABLE();
@@ -152,9 +156,6 @@ extern void __detachInterrupt(uint8_t pin) {
152156
}
153157
}
154158

155-
// stored state for the noInterrupts/interrupts methods
156-
uint32_t interruptsState = 0;
157-
158159
void initPins() {
159160
//Disable UART interrupts
160161
system_set_os_print(0);

hardware/esp8266com/esp8266/libraries/Servo/src/esp8266/Servo.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,6 @@ static uint8_t s_servoCount = 0; // the total number of attached s_se
5959
//------------------------------------------------------------------------------
6060
template <class T> void Servo_Handler(T* timer)
6161
{
62-
noInterrupts();
63-
6462
uint8_t servoIndex;
6563

6664
// clear interrupt
@@ -101,8 +99,6 @@ template <class T> void Servo_Handler(T* timer)
10199

102100
timer->setEndOfCycle();
103101
}
104-
105-
interrupts();
106102
}
107103

108104
static void initISR(ServoTimerSequence timerId)

hardware/esp8266com/esp8266/tools/sdk/include/ets_sys.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ inline bool ETS_INTR_WITHINISR()
6565
{
6666
uint32_t ps;
6767
__asm__ __volatile__("rsr %0,ps":"=a" (ps));
68-
// PS.EXCM bit check
69-
return ((ps & (1 << 4)) != 0);
68+
// PS.INTLEVEL check
69+
return ((ps & 0x0f) != 0);
7070
}
7171

7272
inline uint32_t ETS_INTR_ENABLED(void)

0 commit comments

Comments
 (0)