nRF24 / RF24Mesh

OSI Layer 7 Mesh Networking for RF24Network & nrf24L01+ & nrf52x devices
http://nrf24.github.io/RF24Mesh
GNU General Public License v2.0
422 stars 153 forks source link

Problem with other SPI modules and interrupts #125

Closed obdevel closed 5 years ago

obdevel commented 6 years ago

I can successfully communicate between two Arduinos using RF24Mesh and it is generally very stable. However, when I introduce a CAN bus module on the same SPI bus I get problems.

The CAN bus module uses an interrupt to signal the arrival of new data and there seems to be an unpredictable timing issue with RF24/Network/Mesh and access to the SPI bus. Clearly, I can't control when the ISR will be triggered, and everything is mostly ok. However, every so often the radio will stop responding, i.e. network.read() returns nothing, or sometimes message type 0, and 0 in all other header fields, i.e. a blank message. Once this happens, no more radio messages are received by .available(), .peek() or .read(). But I do continue to correctly receive CAN frames on the SPI bus.

The ISR just reads the next message frame from the CAN module (using SPI) and buffers it. I have to use an interrupt because polling is just not quick enough and messages might be dropped.

Does the library expect exclusive access to the SPI bus ? I don't know enough about SPI to know whether it has the concept of atomic transactions.

I am happy to debug if you can give me somewhere to start ? Too much code to post an example, and you'd need a CAN module to reproduce !

Thanks

obdevel commented 6 years ago

Seems this is a limitation of SPI. Interrupts are a no-no if multiple slave devices are present on the bus.

RF24 seems amenable to using SoftSPI to create a separate 'virtual' SPI bus, so I'll give this a try and report back. SoftSPI is implemented in this library: https://github.com/greiman/DigitalIO

TMRh20 commented 6 years ago

I'm thinking you would need both libraries to support interrupts to handle this. If the CAN data could be handled outside of the ISR it might work. I would suggest an alternate SPI bus using software or the UART.

On Sep 20, 2017, at 17:18, obdevel notifications@github.com wrote:

I can successfully communicate between two Arduinos using RF24Mesh and it is generally very stable. However, when I introduce a CAN bus module on the same SPI bus I get problems.

The CAN bus module uses an interrupt to signal the arrival of new data and there seems to be an unpredictable timing issue with RF24/Network/Mesh and access to the SPI bus. Clearly, I can't control when the ISR will be triggered, and everything is mostly ok. However, every so often the radio will stop responding, i.e. network.read() returns nothing, or sometimes message type 0, and 0 in all other header fields, i.e. a blank message. Once this happens, no more radio messages are received by .available(), .peek() or .read(). But I do continue to receive CAN frames on the SPI bus.

The ISR just reads the next message frame from the CAN module (using SPI) and buffers it. I have to use an interrupt because polling is just not quick enough and messages might be dropped.

Does the library expect exclusive access to the SPI bus ? I don't know enough about SPI to know whether it has the concept of atomic transactions.

I am happy to debug if you can give me somewhere to start ? Too much code to post an example, and you'd need a CAN module to reproduce !

Thanks

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub, or mute the thread.

obdevel commented 6 years ago

Thanks for the quick reply although I think we may have crossed. Fortunately your RF24 library seems amenable to SoftSPI so I'll try that.

Unfortunately, CAN frames can arrive at such a rate that polling in loop() (as well as doing other useful work) would mean missed/dropped frames. The CAN hardware doesn't buffer sufficiently either, and as it's a monitor application, I can't filter CAN frames at the h/w level.

Thanks again for the support.

chriskelman commented 6 years ago

I too have found the soft SSPI library to be useful in these situations - I have had to use it to support non-compliant SSPI devices (such as SD card readers) and found that the nRF24 works well using the SSPI interface - while the SD reader hogs the nominal SSPI pins.


From: obdevel notifications@github.com Sent: 21 September 2017 09:58:29 To: nRF24/RF24Mesh Cc: Subscribed Subject: Re: [nRF24/RF24Mesh] Problem with other SPI modules and interrupts (#125)

Thanks for the quick reply although I think we may have crossed. Fortunately your RF24 library seems amenable to SoftSPI so I'll try that.

Unfortunately, CAN frames can arrive at such a rate that polling in loop() (as well as doing other useful work) would mean missed/dropped frames. The CAN hardware doesn't buffer sufficiently either, and as it's a monitor application, I can't filter CAN frames at the h/w level.

Thanks again for the support.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHubhttps://github.com/nRF24/RF24Mesh/issues/125#issuecomment-331013187, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AKyWpuOZjUu3lEj8aTFnLSDK_nCU17_Zks5skaalgaJpZM4Pemb-.

obdevel commented 6 years ago

So ... I seem to have an explanation, and almost a resolution. The other library doesn't implement SPI transactions, so interrupts from the other device were not being masked during RF24 method calls, and thus it was calling SPI methods during RF24 transactions. I'm not surprised it was trampling all over the bus !

I've emailed the author and have quickly hacked the necessary changes into his code. I've also made a call to SPI.usingInterrupt() in my setup() function. That interrupt should now be masked during RF24 bus transactions.

This blog helped a lot: https://dorkbotpdx.org/blog/paul/spi_transactions_in_arduino

Looks ok so far ... but I'll update here later for posterity.