Don't reenable interrupts in the ISR

The unselect() method, liberally called directly and indirectly
from the interrupt handler, always reenables interrupts after it's
done. In ISRs, interrupts are disabled by default, and although
reenabling is allowed, the interrupt handler doesn't seem to have
reentrant code. Therefore, only reenable when not in an ISR.

This was causing problems in certain circumstances, e.g. with
an Arduino Ethernet shield, most packet receptions would cause
resets.
This commit is contained in:
Mark Bergsma 2016-06-04 20:22:45 +02:00
parent ca93c49b22
commit 2133bbfe79
2 changed files with 13 additions and 3 deletions

View File

@ -41,6 +41,7 @@ volatile uint8_t RFM69::PAYLOADLEN;
volatile uint8_t RFM69::ACK_REQUESTED; volatile uint8_t RFM69::ACK_REQUESTED;
volatile uint8_t RFM69::ACK_RECEIVED; // should be polled immediately after sending a packet with ACK request volatile uint8_t RFM69::ACK_RECEIVED; // should be polled immediately after sending a packet with ACK request
volatile int16_t RFM69::RSSI; // most accurate RSSI during reception (closest to the reception) volatile int16_t RFM69::RSSI; // most accurate RSSI during reception (closest to the reception)
volatile bool RFM69::_inISR;
RFM69* RFM69::selfPointer; RFM69* RFM69::selfPointer;
bool RFM69::initialize(uint8_t freqBand, uint8_t nodeID, uint8_t networkID) bool RFM69::initialize(uint8_t freqBand, uint8_t nodeID, uint8_t networkID)
@ -109,6 +110,7 @@ bool RFM69::initialize(uint8_t freqBand, uint8_t nodeID, uint8_t networkID)
while (((readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00) && millis()-start < timeout); // wait for ModeReady while (((readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00) && millis()-start < timeout); // wait for ModeReady
if (millis()-start >= timeout) if (millis()-start >= timeout)
return false; return false;
_inISR = false;
attachInterrupt(_interruptNum, RFM69::isr0, RISING); attachInterrupt(_interruptNum, RFM69::isr0, RISING);
selfPointer = this; selfPointer = this;
@ -353,7 +355,7 @@ void RFM69::interruptHandler() {
} }
// internal function // internal function
void RFM69::isr0() { selfPointer->interruptHandler(); } void RFM69::isr0() { _inISR = true; selfPointer->interruptHandler(); _inISR = false; }
// internal function // internal function
void RFM69::receiveBegin() { void RFM69::receiveBegin() {
@ -460,7 +462,7 @@ void RFM69::unselect() {
SPCR = _SPCR; SPCR = _SPCR;
SPSR = _SPSR; SPSR = _SPSR;
#endif #endif
interrupts(); maybeInterrupts();
} }
// true = disable filtering to capture all frames on network // true = disable filtering to capture all frames on network
@ -788,3 +790,9 @@ void RFM69::rcCalibration()
writeReg(REG_OSC1, RF_OSC1_RCCAL_START); writeReg(REG_OSC1, RF_OSC1_RCCAL_START);
while ((readReg(REG_OSC1) & RF_OSC1_RCCAL_DONE) == 0x00); while ((readReg(REG_OSC1) & RF_OSC1_RCCAL_DONE) == 0x00);
} }
inline void RFM69::maybeInterrupts()
{
// Only reenable interrupts if we're not being called from the ISR
if (!_inISR) interrupts();
}

View File

@ -131,6 +131,7 @@ class RFM69 {
static void isr0(); static void isr0();
void virtual interruptHandler(); void virtual interruptHandler();
virtual void interruptHook(uint8_t CTLbyte) {}; virtual void interruptHook(uint8_t CTLbyte) {};
static volatile bool _inISR;
virtual void sendFrame(uint8_t toAddress, const void* buffer, uint8_t size, bool requestACK=false, bool sendACK=false); virtual void sendFrame(uint8_t toAddress, const void* buffer, uint8_t size, bool requestACK=false, bool sendACK=false);
static RFM69* selfPointer; static RFM69* selfPointer;
@ -151,6 +152,7 @@ class RFM69 {
virtual void setHighPowerRegs(bool onOff); virtual void setHighPowerRegs(bool onOff);
virtual void select(); virtual void select();
virtual void unselect(); virtual void unselect();
inline void maybeInterrupts();
}; };
#endif #endif