It’s time to try out that “bussed SPI” idea, which could turn the 2×4-pin SPI/ISP connector into a real bus for up to 8 high-speed devices. What I came up with as test case, is to hook up two SPI RAM chips, write different values to each of them, and then read them back to check that the values are correct.
Let’s dive in, which in this electro-world means: grab a breadboard and a bundle of wire jumpers!
At the top, a red USB BUB (v1), and a JeeNode underneath a Bridge Board to bring all the necessary connections onto the breadboard. On the breadboard, from left to right: two 23K256 static RAM chips in 8-pins DIP, and a 74AHC595 shift register as 16-pin DIP package. Apart from the jumper wires, some pull-up resistors, and the scope probes, there are also lots of 0.1 µF decoupling caps. At 8 MHz, they are crucial (as I found out, eventually).
This was (approximately) the code I used for testing (combined with the code in this post):
Here is a scope trace of the result (yes, it’s the same screenshot I posted a few days ago):
There are two decoded SPI signals: MOSI at the top and MISO at the bottom.
What you can see, is that the bytes 0x38 and 0x39 are being read back from one SRAM, immediately followed by the command to write 0x3C and 0x3D – these values then get read back on the next iteration. The values 0x3A and 0x3B end up in the other SRAM. You can also see the slave select setup via the B0 pin for SRAM #1 (0xFD), and a different value for SRAM #2 (0xFB). Note how this needs a mere 2 µs extra to switch SPI slaves.
In short: it all seems to work!
I’ll have to do a lot more testing of course, to find out how reliable this is at this high 8 MHz speed, and how this works out across multiple boards, all stacked up together. But if it does, then this might become a very handy new convention for little “stacker” boards on top of a JeeNode. Look Ma, no extra pins!
The SPI bus: tamed, at last?
I’d like to try this out – any chance you are able to post the full sketch somewhere like Github?
Thanks,
Ian
What about to use even less wires ? Have a look at http://www.romanblack.com/shift1.htm
Michal
It’s a nice trick, but it uses more components, it’s slower, and … it doesn’t actually use less wires (in this context).
Interesting, but IMVHO a small PIC (like 12F508) can handle both faster and bidirectional transfers… I think the final cost would be equivalent to the shift register plus 2 resistors and two capacitors. Less board space, just a bit more “setup” time (well… if you have to go in production you can ask for preloaded code…).
It takes 2 µs to select a device with the shift register (once, subsequent I/O to the same device is instant) – including the s/w overhead on the ATmega. I don’t see how a PIC or ATtiny could keep up with that.
Uh? Where did you take the 2us figure? My comment was just about replacing the shift register + R/C nets with a PIC…
The shift1 method requires 500uS just for the strobe. One ‘1’, seven ‘0, and a strobe take up 16 + 7×45 + 500 = 831us.
With a PIC12F508 (on 4MHz internal osc, 1us per instruction) you could have a software 200Kbps UART (actually up to 330Kbps, but that becomes critical and theoretical): it would be 50us for each byte (8n1). If you prefer standard rates (to offload tx to a UART) then 230k4 is sufficiently near to be feasible. Or you could opt for a slightly costly chip w/ a real UART (maybe w/ I2C slave) onboard and let it do other tasks too (like prioritize interrupts from devices and pass ’em back on a single line, possibly preselecting the device requiring attention). NB: the PIC wouldn’t handle the whole communication, just the selection!
Ah, wait, I was talking about the bussed-SPI schematic in the previous post, and the scope capture shown above, running at 8 MHz. Sorry for the confusion.
Watch out for 2 things: 1) fan-out: if you add too many devices, you’ll need buffers (you could need ’em anyway, just to keep signals cleaner when using long wires) 2) your “addressing” scheme allows for more than one slave device to be active at the same time — consider using a 3-to-8 decoder cascaded with the shift register (you’ll use only 4 bits: 3 for address and one to enable the decoder — the others can be used for LEDs :) ).
Bus length is most certainly an issue to watch out for. Not sure about bus loading, since most slaves are bound to be CMOS devices. As for conflicts: yes, you need to be careful to fill the shift registers only with certain patterns (same as with separate select pins).
I am not PIC fan, but Configurable Logic Cell devices (PIC10F32X PIC12F150x) could implement shift register and device select decoder with just CLC configuration probably (2 µs or less to select device without problems). And you can try utilize them for additional functionality (e.g. single SS wire – first n bits in every SPI transfer as selector, board ID, …)
Ooh… fascinating, those CLC capabilities!