SPI Transactions used with real-time SPI devices

Status
Not open for further replies.

stevech

Well-known member
How does SPI Transactions stand now, for use with real-time SPI devices that interrupt upon an event, such as message arrivals in communications (wireless, ethernet, etc), or any other such device?

With just one such real-time device... when there are is no other transaction in progress, the real-time SPI device's interrupt can be safely enabled. When there is a brief transaction, the interrupt is masked until that transaction completes its use of the shared SPI port. If a real-time event occurred while the other transaction was using the SPI port, the real-time device's ISR would be delayed - which is OK if the delay due to interrupt masking is not so long as to block another real time event.

With 2+ such real-time devices, each with an ISR using the SPI, one can do as the above, disabling both ISRs while a transaction is using the SPI. This assumes that the two real-time SPI devices do not allow nested interrupts, i.e., where one can interrupt the other's ISR - as doing so would cause the SPI port ownership exclusion scheme to fail.

Besides communications devices that interrupt based on messages (received and transmit complete), there are multi-channel SPI ADCs that might interrupt every 100uSec and the ISR wants to quickly read and store a sample. With the high interrupt rate, these are a challenge.

So what's the status ?
 
Regarding "what's the status", it's officially released as of Teensyduino 1.20+Arduino 1.0.5 and in Arduino 1.5.8.

Some of the most commonly used libraries are using SPI transactions, but many other libs are not (yet).

Your message has a lot of comments, but it's not really clear to me which are questions, so I'm going to just stick to "what's the status".
 
What exactly are interested in? Is it the maximum latency between an interrupt request and the actual transmission of data inside the ISR? Only you can work those out.

What you might be able to do is: Don't do the SPI transactions in the ISRs, but let the device's ISRs just queue up requests. Then handle the requests in the main loop. You might also introduce priorities, and detect missed events. If the devices are too fast for the CPU, they are just that: too fast.
 
Sorry I wasn't clear... let me try to be more concrete.

Your response here can help others with the same need.

Using SPI for data radio transceiver interface. Competing for use of the SPI with ADCs (running 100Ksps or more). Maybe SD card in the mix.
Need to know (generally, not detail)

Can the SPI Transactions API do something like the following...

Radio transmitting: Do an SPI transaction to own the SPI port to send data, commence transmission. Give back ownership of SPI port until transmit-complete interrupt happens (say, 20mSec later). The API will mask/disable the interrupt from the radio if the SPI port is allocated to some other requesting device. When the SPI port becomes uncommitted (idle), the radio's interrupt request would be reenabled so that the radio ISR can use the port. This can work if the other SPI port function does not use the port more than about 1-2 mSec - because the transmit complete interrupt needs to be serviced so the radio can turn-around to receive mode in order to catch the ACK to the transmission. The ACK comes very fast, after transmit complete. The radio software shouldn't hog/own the SPI port from start of transmit to receipt of ACK - that's 10's of mSec at high bit rates and longer at low radio bit rates.

Radio receive:
Most of the time, the radio is quiescent in the receiver-on mode, anticipating an arriving message at any time. On receipt, the radio raises an interrupt request. If the SPI port is in use by some other SPI function, then the API would have masked the radio interrupt to prevent the radio ISR from using the SPI port. When the port is no longer in use, the radio's interrupt mask would be removed. The ISR would then run immediately if a reception had occurred while the radio interrupt was masked out. That's OK if the delay is small, e.g., less than the ACK timeout (say, 10mSec), and less than back to back incoming messages (say, 10-50mSec).

So these are examples of SPI port sharing, where the radio, being real-time, spontaneous, can't tolerate much latency in owning the SPI port to read interrupt cause or at non-interrupt level, transfer a packet payload to/from the radio (packets in these kind of radios are small- 60 bytes or so).

The above is typical of a wireless sensor system where sensor sampling is high rate ADCs and wireless reporting is the usual reliable datagram method (like a minimal TCP), with unsolicited incoming messages as well as sensor reports whenever sensor threshold events occur.

Now extrapolate to a device type with much faster events than as above, and with SPI port sharing needed. E.g., a proper interrupt-driven ethernet interface, or fast ADCs.

I hope this helps you understand the need, for real time, latency sensitive SPI I/O, and can help you to generalize how the SPI Transactions can meet these needs. The solution may be tight application-specific code to mix polling with interrupts... but polling is CPU-wasteful and crude. Or avoid contention with a software SPI for low byte-rates (as are these low cost radio transceivers), where the ISR sets flags for a state machine in the non-ISR level. It would seem that a software SPI could leave interrupts for other on and the slave would tolerate some stretched clock periods. So long as there are no badly designed ISRs with long code times.

Oh for 2+ SPI ports! I haven't found an "SPI port expander" chip.

steve
 
Last edited:
Q1: Can the latency be achieved?
Q2: There is no magic, I suppose, if a function owns the SPI port too long, for a transfer, the 2mSec or so latency cannot be achieved?
 
A1: "maybe" or "we don't have enough information"
A2: correct

Really, if the latency can be achieved depends on many more details. I'd say that it can be done. Create some worst case scenarios and see what would happen. You haven't given us e.g. the speed your SPI would be running at, and if there are any other blocking parts in your code that might delay an SPI response to an interrupt request
 
Yes, exactly, Christoph is correct.

The worst-case latency which your radio library must wait depends on how long any other SPI code you're using keeps its SPI tranactions open.

There is no special magic inside the SPI library to limit latency. Latency is entirely determined by how long those other libraries are designed. But the SPI transaction code is designed to be extremely efficient, so it doesn't add much overhead. In fact, one of the issues that took months to resolve with the Arduino devs involved concerns about performance. Alternate approaches were investigated, but they turned out to be too heavy (especially on 8 bit AVR).

In terms of "status", I want to emphasize the SPI transaction API is "stable" and "final". Additional convenience functions may be added in the future (one is already being discussed), but the actual SPI transaction stuff is finished. Arduino officially published it in 1.5.8. I published it in Teensyduino 1.20. Several libraries are already ported and many more will be soon. Some libraries (notable SD) hold their transactions open longer than necessary, and over time those will improve (contributions are of course welcome...)

The SPI transaction API in the SPI library is not going to change. It's done. The only changes worth talking about now are porting more libraries to using SPI transactions, and how long various libraries might hold a transaction and ways to minimize those times. The SPI transaction layer itself absolutely is completed and finalized.

Steve, you've brought this up so many times before, so I want to be as absolutely clear as possible. Much work remains to be done with porting and improving how the many SPI-based libraries use transactions. But the actual SPI transaction layer in the SPI library is finalized and more or less "set in stone" now.
 
Give it a try, steve! Make yourself an overview of what your code does, when it does it, and how long each step takes. If you see that everything that should be done within a second can be done within a second, proceed.

Then use the "standard" tools and libraries, implement, and test test test. Only then you can find bottlenecks and try to remove them. Only optimize if you need to.
 
Yes indeed, please, just give it a try. If you're using RadioHead and other libs that already support SPI transactions, odds are pretty good things will just work.

If you do find a bug, please take the time to whittle your code down to a (hopefully small) test case that reproduces the problem. Just 1 reproducible bug report will do far more good than an infinite number of messages talking about abstract latency requirements. I can't make any specific promises in advance, especially regarding a time frame for fixes, but I do believe it's safe to say I'm the one guy in all of the Arduino world who's really put a lot of work into improving the SPI library. I really do want to make all this stuff work well, with good performance, not only for Teensy but for everyone on all Arduino compatible boards. Aside from actually fixing stuff and sending pull requests, the best way to help this ongoing effort is with reproducible bug reports!
 
I know what my and RH's code does in detail. I did a careful design, and I've pored over the scope displays of real timing of interrupts and TX/RX. What I cannot control is the latency issues arising in wireless, where a message can arrive at any time. And back-to back with little inter-message time gaps. Most esp. ACKs right after a transmission finishes. I have to deal with all the wireless timing and that's my issue. What I don't understand well enough, and was the reason for the inquiry in this thread, is what I can expect other libraries' SPI usage to do in terms of how long the radio's interrupt can be masked. I have the radio timing AND the ADC timing (external SPI ADCs - perhaps 100 uSec per sample interrupts or polling, perhaps 5K sps per channel, 16 channels per chip, perhaps 2 chips per MCU. I have yet to do that code. Just got the T.I. ADC's eval kit for the chip: http://www.ti.com/product/ads1258. Several chips per MCU. Many MCUs- networked via Wireless.

I will try to find time to use the released version of SPI Transactions.
I tried it mid-way through the beta - and it caused a deadlock/hang where the radio's interrupt line was stuck true per the 'scope. Paul placed the blame on the RFM69 and a possible end-case in timing. Semtech, chip maker, says no reports of such in years of high volume production. This became a long diversion, though we tried to reproduce the timing and fault Paul observed, but using other software.

I have 10 radios and one gateway running, working with bursty transmissions and collisions avoidance to keep the latency for 10 messages with the same root timing source - to get all to the gateway and in to a PC in 100mSec. Time slotting.

I'd much rather find a chip to add SPI ports than deal with SPI port access latency that might get fouled up by some library I didn't write. Such as SD card w/ FAT?
I can deal with that, by just avoiding use of the SD card during live operations (i.e., make SD card I/O "post-mission") - as some of the long delays in SD I/O may be unavoidable.

steve
 
Last edited:
I tried it mid-way through the beta - and it caused a deadlock/hang where the radio's interrupt line was stuck true per the 'scope. Paul placed the blame on the RFM69 and a possible end-case in timing. Semtech, chip maker, says no reports of such in years of high volume production.

I did have an issue where unrelated SPI activity seemed to cause the RFM69 to stop working. I posted a test case which pretty clearly showed it was merely having extra SPI activity, unrelated to a specific library. Perhaps you saw that code?

I heard from one other person who believed the trouble was due to RF leaking from the SPI clock to the radio antenna. As I recall, you suggested trying different settings for slower bitrates, where the radio would have more tolerance for RF noise. At the time, I tested with RadioHead's defaults only.

Since then, I haven't done more with the RFM69. I did send a PCB to OSH Park to make the next round of experimenting easier. So far, it's still sitting in a box of RFM69 stuff, to be tested again someday when I have more time. At the moment, that's looking unlikely to happen anytime soon.
 
I've got a lot of RF69HW's in use in a prototype - on AVR and some on Teensy. Does a great job for a $4 FSK transceiver, at 125Kbps FSK.
Decision time on this project - on whether to use Teensy vs. alternatives, two of which I've built/adapted code. A driving criteria whether it's necessary to have two MCUs - one to manage ADCs (SPI) and do basic signal processing, and another MCU for communications and other housekeeping. If we go with two as a pair, times dozens of pairs like this, the SPI contention issue is lessened. Battery powered, no USB (hence remote programming is essential - but maybe that can come from uTasker's bootloader and a radio interface I provide for it.

I think HopeRF has a run rate of thousands per month on RFM69s. For the HVAC world.
 
Status
Not open for further replies.
Back
Top