LowPowerLab Forum

Hardware support => RF - Range - Antennas - RFM69 library => Topic started by: stevenfalco on June 08, 2017, 10:51:40 AM

Title: Bug fix for interrupt lockups
Post by: stevenfalco on June 08, 2017, 10:51:40 AM
I have a board with both Ethernet2 and RFM69 hardware.  It has been locking up after a few minutes of operation, and I've finally tracked down the problem.

The RFM69 driver uses SPI in interrupt context.  If the Ethernet2 driver is in the middle of a SPI transaction at the moment that an RFM69 interrupt hits, then the Ethernet2 SPI transaction is corrupted.  This results in the SPI interface locking up, and the application freezes.

I made the following simple change:

@@ -106,6 +106,7 @@ bool RFM69::initialize(uint8_t freqBand, uint8_t nodeID, uint8_t networkID)
   if (millis()-start >= timeout)
     return false;
   _inISR = false;
+  SPI.usingInterrupt(_interruptNum);
   attachInterrupt(_interruptNum, RFM69::isr0, RISING);
   selfPointer = this;

This fixes the problem and completely eliminates the lockup.

The fix is available here: git@github.com:stevefalco/RFM69.git

Please review and merge it.

There is a larger additional change that should be made.  In particular, the RFM69 library should be using SPI.beginTransaction() and SPI.endTransaction().  This is necessary for the RFM69 library to respect other SPI devices that wish to use interrupts.

In other words, SPI.usingInterrupt() declares your desire to use SPI in interrupt context, whereas SPI.beginTransaction() and SPI.endTransaction() perform the actual interrupt enable/disable operations.  For proper cooperative behavior, both sets of calls should be used by all SPI device drivers.
Title: Re: Bug fix for interrupt lockups
Post by: Felix on June 08, 2017, 11:05:49 AM
Thanks for sharing your work,
This topic was covered on a few occasions before. For the reasons below, this type of arduino version specific transaction code was not merged into RFM69:

- RFM69 library implements SPI transactions in a more basic way, not using the Arduino SPI.beginTransaction() which is not available on older IDE versions or other platforms
- other libraries that use SPI may be poorly implemented and don't respect any possible current SPI transaction
Title: Re: Bug fix for interrupt lockups
Post by: stevenfalco on June 08, 2017, 11:28:31 AM
Ok, but the existing RFM69 library doesn't "play nice" with the Ethernet2 library.  I.e., you cannot use both without suffering from the lockup that I've been seeing.  Surely we need a solution for that.

Perhaps ifdefs could be used to allow older IDEs to continue to use the RFM69 library.

I have pushed an additional change to my version on github, which replaces the RFM69::select() / unselect() logic with calls to SPI.beginTransaction() / SPI.endTransaction().  This also lets me remove the _inISR flag and RFM69::maybeInterrupts() functions.

Please let me know how to proceed, because I'd really like to see the official library be able to coexist with other SPI devices.  Lockups like this are no fun - I spent a few days chasing it.