From 2133bbfe799eb50b99b76429ef4d71027a8ed7a0 Mon Sep 17 00:00:00 2001 From: Mark Bergsma Date: Sat, 4 Jun 2016 20:22:45 +0200 Subject: [PATCH] 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. --- RFM69.cpp | 14 +++++++++++--- RFM69.h | 2 ++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/RFM69.cpp b/RFM69.cpp index 81cf4e6..a1e1eeb 100644 --- a/RFM69.cpp +++ b/RFM69.cpp @@ -41,6 +41,7 @@ volatile uint8_t RFM69::PAYLOADLEN; volatile uint8_t RFM69::ACK_REQUESTED; 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 bool RFM69::_inISR; RFM69* RFM69::selfPointer; 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 if (millis()-start >= timeout) return false; + _inISR = false; attachInterrupt(_interruptNum, RFM69::isr0, RISING); selfPointer = this; @@ -353,7 +355,7 @@ void RFM69::interruptHandler() { } // internal function -void RFM69::isr0() { selfPointer->interruptHandler(); } +void RFM69::isr0() { _inISR = true; selfPointer->interruptHandler(); _inISR = false; } // internal function void RFM69::receiveBegin() { @@ -460,7 +462,7 @@ void RFM69::unselect() { SPCR = _SPCR; SPSR = _SPSR; #endif - interrupts(); + maybeInterrupts(); } // true = disable filtering to capture all frames on network @@ -787,4 +789,10 @@ void RFM69::rcCalibration() { writeReg(REG_OSC1, RF_OSC1_RCCAL_START); while ((readReg(REG_OSC1) & RF_OSC1_RCCAL_DONE) == 0x00); -} \ No newline at end of file +} + +inline void RFM69::maybeInterrupts() +{ + // Only reenable interrupts if we're not being called from the ISR + if (!_inISR) interrupts(); +} diff --git a/RFM69.h b/RFM69.h index 72feb86..82a46be 100644 --- a/RFM69.h +++ b/RFM69.h @@ -131,6 +131,7 @@ class RFM69 { static void isr0(); void virtual interruptHandler(); 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); static RFM69* selfPointer; @@ -151,6 +152,7 @@ class RFM69 { virtual void setHighPowerRegs(bool onOff); virtual void select(); virtual void unselect(); + inline void maybeInterrupts(); }; #endif