Description
Originally posted in arduino/Arduino#2449 by @PaulStoffregen:
Please do not mistake the issue I'm about to describe with the transaction scope discussion.
Also, please let me preface this with the caveat that it's still very preliminary. I'm actively working on the nRF8001 library, and it's still very much a work-in-progress.
Nordic's nRF8001 seems to be exposing a weakness in the API, which I didn't consider until now. I had considered the RFM69 radio modules, Wiznet ethernet chips, and CC3000 Wifi module in the design of this API. In all those cases, the chip requests service by asserting an interrupt signal. CC3000 is a bit strange, but I'm not going to discuss is right now.
The problem with nRF8001 is the request to initiate communication is done by asserting chip select, which then causes the chip to request an interrupt. SPI transfers must be blocked during that request-to-interrupt time. The trouble is SPI.beginTransaction() disables all registered interrupts, including the one for nRF8001, which prevents the ISR from responding.
At the moment, I'm working with a kludge where I just turn that specific interrupt back on. That may be the final answer. It may be perfectly acceptable to just leave the SPI API as it is, and accept that nRF8001 (and any future chips from Nordic or others) require this workaround.
Or perhaps the SPI API should be able to accommodate this sort of case? Ideally, what's needed is for beginTransaction() to disable the interrupts being used by all other SPI libraries. That's probably much easier to achieve on Cosa, since each library creates an instance of SPI. On Arduino, we're trying to work within the legacy of the SPI library being a thin, static-only C++ wrapper. Requiring sketches and libraries to create instances of the SPI library is probably far too large of an API change to even consider.
Perhaps beginTransaction() could have an alternate/overloaded version that disables all but a specific interrupt. Or perhaps just a function to re-enable the interrupt would work? Or just pushing the responsibility to do that onto the nRF8001 library may be the answer... but that does mean the nRF8001 lib couldn't rely on the SPI lib and core library to fully abstract the hardware.
Well, unless we end up implementing enableInterrupt() and disableInterrupt() or similar core lib functions, as Matthijs has already worked on.
In hingsight, I really should have worked on nRF8001 much earlier. Sorry about that, and really, the last thing I wanted to do was make this SPI stuff even more complicated. Sadly, it seems Nordic has used a design which requires us to acquire exclusive access to the SPI bus, then assert a chip select, and then respond to the falling edge or low level of an interrupt signal, which doesn't assert until the chip select is asserted.