> I wonder how hard it'd be to build an SPI interface with discrete logic?
You mean so you can just read and write whole bytes and instructions, read status, etc., instead of bit-banging? It doesn't seem like it would take much. I've always bit-banged them on 6522 pins. It's very easy to do, both in hardware and software, but you certainly won't hit 40Mb/s that way.
About SPI modes (I'll skip quoting your two paragraphs): Without looking through every datasheet I have on SPI parts again, I'll comment from memory. I really should write up a synchronous-serial primer for the primers and tutorials section though, because there's a wealth of synchronous-serial parts to be taken advantage of and most people on this forum seem to be unfamiliar with it all in spite of how easy it is.
Code: Select all
| ck on | ck on (data is changed immediately
| rising | falling following opposite edge)
------------+--------+--------+
idle ck lo | mode 0 | mode 1 |
------------+--------+--------+
idle ck hi | mode 3 | mode 2 |
+--------+--------+
Modes 0 (idle clock
low) and mode 3 (idle clock
high) require the data to be valid and stable before the
rising clock edge. Slave parts can change the logic state of their data-out pin on the falling edge since both master and slave latch the incoming data on the rising edge and some parts can be daisy-chained. (Daisy-chained parts would all have to be connected to the same select line.) Mode 1 (idle clock low) and mode 2 (idle clock high) require data to be valid and stable before the
falling clock edge. I don't really see where the difference between mode 0 and mode 3 would matter much since a possible falling edge before the first rising edge after a select line goes down is not going to confuse any parts. According to a 40-page data sheet in front of me, the Atmel Dataflash AT45DB642 8Mx8 serial flash memory (kind of small by today's standards) works in modes 0 and 3, apparently without knowing or caring which of these two modes you're using. The master still puts the first instruction bit on the data line before the first rising edge regardless, and the slave isn't going to send any data anyway until it has decoded an instruction telling it what to do. The possible exception I can think of is the situation where parts are daisy-chained, but I've never done that and I don't think all parts even
can be daisy-chained. Maybe that's for something like using dumb logic shift registers like the 74HC595 (serial-to-parallel) or the 74HC165 (parallel-to-serial).
You could mix parts that work in the different modes on the same SPI, as long as you don't
simultaneously select mulitple parts that are made or set to operate in conflicting modes. That would mostly mean no daisy-chaining of parts that don't all work in the same mode-- hardly a penalty! For addressing SPI parts one at a time (or one chain at a time), you would just set the master to operate in the appropriate mode for the part or chain you're about to select. If some parts can go faster than others and you want maximum speed, you would also set the clock speed appropriately before communicating with each part.
Bytes are always sent most significant bit first. All data frames are 8-bit. There is no extra acknowledge bit like I²C has, no parity, start, or stop bits, etc.. As you can see, the 6522's SR is nearly compatible with SPI modes 0 and 3. Right now I don't remember what keeps it from being 100% compatible.
Microwire is essentially SPI mode 0, except that you supposedly can't ever daisy-chain Microwire parts.
You can use the same SPI master's clock and data lines (with a pull-up on the data) for I²C too as long as you observe a few rules:
1. SPI mode must be 0 or 3, not 1 or 2 (because of rule #2:)
2. Never transition the master's data-out line while the clock is high unless you intend to produce a start or stop condition on I²C.
3. (obvious:) Don't have an SPI or Microwire select line low when addressing I²C parts.
The official spec. says I²C's clock and data lines are supposed to remain high when inactive; but in my limited experience, it simply doesn't matter what these lines do between the time a "stop" condition is generated and when the next "start" condition is generated. Maybe the idea is that low-power devices can scavenge their power from these lines between low pulses, like 1-Wire.