Thank you for the responses - they have been quite helpful, and have clarified the questions I have. I am fairly confident SPI will work well enough for this project, but the prospect of adding discrete line drivers/buffers to each signal vs. the use of a single-chip per device method like RS485 does make RS485 sound like an easier to implement solution from a hardware standpoint. Getting differential signal transmission for better noise tolerance (I don't think the noise level in the environment this will be implemented on will be high, but you never know), built-in level conversion (no need to convert 3.3V to 5V, just get 3.3V and 5V RS485 drivers for each device), not having to consider propagation delay when the slave sends data back to the master, and built-in line driving capabilities seems like a sweet deal.
You can get by without much noise threshold, or shielding, for quite a long time, but expect nuisance errors. This is especially critical for SPI clock, but for data and everything else, expect random bit flips, dropped frames, lost connections and all that.
To have a reliable connection, the logic threshold needs to exceed the expected noise level by a fair margin.
Noise is expected statistically. At most
times, it might be quiet, with pops and bursts seen here and there. In most
places, it might be quiet, except for some areas where it may be incessant and intense (like at the base of a radio antenna).
The recommendation for typical commercial stuff is 3V conducted or 3V/m radiated. So, a cable will have on the order of 3V/m * length induced on it, in such a field, at frequencies where its length happens to be resonant. Except it's usually a bit worse, just because of that: resonance. The Q factor of the cable (how much damping (ferrite beads, resistors) there is on it, and how strongly its voltage couples to the RF field) tells how much worse.
So, signals with a threshold around 3V, are an awful idea to put on a cable. The 15V range that the RS-232, 422/485 and such standards provide is excellent for many situations.
You can get by with less threshold, if the signal is tightly coupled to its reference: this is how you get differential signals. You must still observe common mode limitations of the circuitry, hence why RS485 receivers have a 12V CM input range, even though the threshold is merely ~100mV plus to minus (and the driven signal is only a couple volts at the strongest).
You can get by with even less than that, if the cable is well shielded. USB, HDMI -- most high speed interfaces really, are
only possible with shielded cables. The shielding must be solid, from end to end, for this to work!
(Ethernet is the standout, as it's transformer isolated, differential and unshielded. They really gilded the lily when they created it. It's good, and with good reason! The common mode range is 1.5kV, though the RF immunity isn't
quite that good. The transformers have common mode rejection in the 30dB or better range, so, for a ~1V signal level, it would be expected to drop out at >15V noise -- which is comparable to RS485 and such.
)
Tim, it sounds like using RS422 in the configuration you mentioned is very much like using a full duplex RS485 configuration, but it also sounds like it would only work for one "master" device and one "slave" device, since the protocol technically requires the transmitting device to always be driving. My setup uses a single master and three slave devices, all of which are within a few inches of each other at the end of the 50 ft transmission line.
So at this point, my design will use rs485 (max485 on the Arduinos and max3072 on the Pi). If I think it will be useful, I'll post a schematic. But I'll most likely just use a readily available reference design, so my specific implementation should be pretty generic.
Yeah, consolidating your data into one channel is a good idea. The simplest would be to add extra channel(s) for addressing, as a straight-through CS for each device (3 pairs of CS). That can be improved with addressing (two pairs --> 1-of-4 selector), or multiplexing (make an address register that's selected somehow).
I suppose best would be this: no extra pairs, just the single CS pair. CS high: address register enabled. Transmit a frame --> latch in a new address. (So, you get 256 addresses for free, but only need the 3. So, uh, it's scalable...
) CS low: device enabled (address --> selector, with /CS --> enable). To reset the line state, toggle CS twice (thus de-asserting both the device and address registers, serving the same purpose as de-asserting CS in a normal SPI transaction).
Obviously, this is
a bit of added logic just for a few devices, so, another interesting method if the need arises, but not necessary here...
Another for the record: I am a very recent EE grad so I should technically know all about the perils of line transmission and while the topic is somewhat familiar, the class that went over the subject matter was the one class that I very nearly failed. Besides this, it is one thing to do some abstract homework problems asking about propagation delay and maximum voltages seen by the transmitter, and a very different thing to actually sit there with an oscilloscope trying to figure out why your signal starts tripping out once you plug your transmission cable in. And then there's being presented with half a dozen or more communication protocols, half of which have never been seen (by me) before.
Ah, nice. Do take the time to read up on various standards -- there's very little they teach (and
can teach) about all these things. There's too much to cover, so it's up to you to figure things out later.
You surely learned about logic voltage (or current) thresholds. That's mostly what these simplest of interfaces are: a voltage, current and time specification. Nothing could be simpler.
The signal goes on a cable (whether it be single ended or differential), from a source with a nominal open-circuit voltage, with some source impedance or current capability, and speed determined by a bandwidth, rise time or slew rate. For differential signals, there's also the common mode range, rejection ratio (CMRR), and output balance (how much CM the driver produces).
It's also not well stated anywhere, but almost all logic and driver outputs are some variation on "switch to +V / -V" (where the "switch" is usually something mostly resistive when on, and mostly open circuit when off).
CMOS logic gates are the cleanest and most common example. Take the 74HC family: it's effectively ~70 ohms pulling up, and ~40 ohms pulling down. The equivalent circuit is a Thevenin source, with a voltage of VDD or VSS, and that resistance in series.
If a manufacturer doesn't tell you what kind of output a chip has, it's pretty safe to assume it's a CMOS output, and will have a rail-to-rail voltage range!
Old fashioned TTL is similar, but the pull-up voltage is more like 3.5V (not VCC), and the resistances are asymmetrical, more like ~100 ohms up and ~20 ohms down.
RS-422/485 drivers are basically this type: CMOS switches. They have lower resistance than a logic driver, and are made to deliver higher currents, continuously. For 485, there are also series diodes to prevent backflow when not asserting the line. (But while driving the line, the line voltages are firmly referenced to the driver's supply/ground, so the common mode voltage is well defined.)
LVDS drivers are an example that doesn't fit this pattern. They are nominally constant current outputs, so that the driven output voltage is rather small (a couple 100mV). The output isn't a perfect CCS, though, because that would leave common mode voltage undefined. As it turns out, they design these so that the common mode voltage is held around VDD/2, with a modest impedance (100s ohms), so that the common mode voltage is still well defined.
None of the above standards make any presumption about what coding is used on the line! RS-232 is often colloquially understood to mean asynchronous serial -- after its most common application (the computer serial port, among many others back through history). But there's no specification in the standard about this, and you can run whatever you like (synchronous serial, SPI, any arbitrary data stream), within the limitations of that standard (namely, the voltage, current and speed).
Other standards most definitely do: CANbus is kind of a mash-up of RS-485 (using a multi-master, differential line interface), I2C (the drivers are on/off, not high/low as in RS-485), and, I forget what the nuts-and-bolts of the actual line coding / protocol is, but it's packet based and very error tolerant.
Tim