recipes/rc2014/sdcard: make spi relay design multi-devices

Also, fix the SPI relay driver to properly AND-away the result of
the CTL read.

Tested with a real prototype, works fine.
This commit is contained in:
Virgil Dupras 2020-09-18 19:22:56 -04:00
parent 7dc00179f7
commit 495d2819d2
4 changed files with 39 additions and 48 deletions

View File

@ -2,7 +2,7 @@ CODE (spix) ( n -- n )
HL POP, chkPS, A L LDrr, HL POP, chkPS, A L LDrr,
SPI_DATA OUTiA, SPI_DATA OUTiA,
( wait until xchg is done ) ( wait until xchg is done )
BEGIN, SPI_CTL INAi, A ORr, JRNZ, AGAIN, BEGIN, SPI_CTL INAi, 1 ANDi, JRNZ, AGAIN,
SPI_DATA INAi, SPI_DATA INAi,
L A LDrr, L A LDrr,
HL PUSH, HL PUSH,

View File

@ -1,12 +1,5 @@
# Accessing a MicroSD card # Accessing a MicroSD card
Warning: this recipe is temporarily broken. The schema below hasn't yet been
updated to work with the new SPI relay protocol. If you've already built an
old design, use an earlier commit or work around it in the SPI driver it should
only be a matter of testing the input value for zero-ness to decide whether we
ping the CSLOW or CSHIGH port. If you haven't, wait a little bit before building
one: the upcoming design is better.
SD cards are great because they are accessible directly. No supporting IC is SD cards are great because they are accessible directly. No supporting IC is
necessary. The easiest way to access them is through the SPI protocol. necessary. The easiest way to access them is through the SPI protocol.
@ -25,57 +18,57 @@ subsystem (B420) to drive a SD card.
* A proto board + header pins with 39 positions so we can make a RC2014 card. * A proto board + header pins with 39 positions so we can make a RC2014 card.
* Diodes, resistors and stuff * Diodes, resistors and stuff
* 40106 (Inverter gates) * 40106 (Inverter gates)
* 4011 (NAND gates) * 74xx138 (Decoder)
* 74xx139 (Decoder) * 74xx375 (Latches)
* 74xx125 (Buffer)
* 74xx161 (Binary counter) * 74xx161 (Binary counter)
* 74xx165 (Parallel input shift register) * 74xx165 (Parallel input shift register)
* 74xx595 (Shift register) * 74xx595 (Shift register)
## Building the SPI relay ## Building the SPI relay
The [schematic][schematic] supplied with this recipe works well with the SD ![SPI relay](spirelay.jpg)
Card subsystem (B420). Of course, it's not the only possible design that
works, but I think it's one of the most straighforwards.
The basic idea with this relay is to have one shift register used as input, The schematic above works well with the SD Card subsystem (B420). Of course,
loaded in parallel mode from the z80 bus and a shift register that takes the it's not the only possible design that works, but I think it's one of the most
serial input from `MISO` and has its output wired to the z80 bus. straighforwards.
These two shift registers are clocked by a binary counter that clocks exactly This relay communicates through the z80 bus with 2 ports, `DATA` and `CTL` and
8 times whenever a write operation on port `4` occurs. Those 8 clocks send allows up to 4 devices to be connected to it at once, although only one device
data we've just received in the `74xx165` into `MOSI` and get `MISO` into the can ever be active at once. This schema only has 2 (and the real prototype I've
`74xx595`. built from it), but the '375 has room for 4. In this schema, `DATA` is port 4,
`CTL` is port `5`.
The `74xx139` then takes care of activating the right ICs on the right We activate a device by sending a bitmask to `CTL`, this will end up in the
combinations of `IORQ/WR/RD/Axx`. '375 latches and activate the `SS` pin of one of the device, or deactivate them
all if `0` is sent.
The rest of the ICs is fluff around this all. You then initiate a SPI exchange by sending a byte to send to the `DATA` port.
This byte will end up in the '165 and the '161 counter will be activated,
triggering a clock for the SPI exchange. At each clock, a bit is sent to `MOSI`
from the '161 and received from `MISO` into the '595, which is the byte sent to
the z80 bus when we read from `DATA`.
My first idea was to implement the relay with an AVR microcontroller to When the '161 is wired to the system clock, as it is in the schema, two `NOP`s
minimize the number of ICs, but it's too slow. We have to be able to respond are a sufficient delay between your `DATA` write and subsequent `DATA` read.
within 300ns! Following that, it became necessary to add a 595 and a 165, but
if we're going to add that, why not go the extra mile and get rid of the
microcontroller?
To that end, I was heavily inspired by [this design][inspiration]. However, if you build yourself some kind of clock override and run the '161 at
something slower than the system clock, those 2 `NOP`s will be too quick. That's
where that '125 comes into play. When reading `CTL`, it spits `RUNNING` into
`D0`. This allows you to know when the result of the SPI exchange is ready to be
fetched. Make sure you `AND` away other bits, because they'll be garbage.
This board uses port `4` for SPI data, port `5` to pull `CS` low and port `6` The '138 is to determine our current IORQ mode (`DATA`/`CTL` and `WR/RO`), the
to pull it high. Port `7` is unused but monopolized by the card. '106 is to provide for those `NOT`s sprinkled around.
Advice 1: If you make your own design, double check propagation delays! Please note that this design is inspired by [this design][inspiration].
Some NAND gates, such as the 4093, are too slow to properly respond within
a 300ns limit. For example, in my own prototype, I use a 4093 because that's
what I have in inventory. For the `CS` flip-flop, the propagation delay doesn't
matter. However, it *does* matter for the `SELECT` line, so I don't follow my
own schematic with regards to the `M1` and `A2` lines and use two inverters
instead.
Advice 2: Make `SCK` polarity configurable at all 3 endpoints (the 595, the 165 Advice 1: Make `SCK` polarity configurable at all 3 endpoints (the 595, the 165
and SPI connector). Those jumpers will be useful when you need to mess with and SPI connector). Those jumpers will be useful when you need to mess with
polarity in your many tinkering sessions to come. polarity in your many tinkering sessions to come.
Advice 3: Make input `CLK` override-able. SD cards are plenty fast enough for us Advice 2: Make input `CLK` override-able. SD cards are plenty fast enough for
to use the system clock, but you might want to interact with devices that us to use the system clock, but you might want to interact with devices that
require a slower clock. require a slower clock.
## Building your binary ## Building your binary
@ -85,15 +78,14 @@ assemble a binary with those drivers. To do so, you'll modify the xcomp unit
of the base recipe. Look at `xcomp.fs`, you'll see that we load a block. That's of the base recipe. Look at `xcomp.fs`, you'll see that we load a block. That's
our xcomp block (likely, B599). Open it. our xcomp block (likely, B599). Open it.
First, we need drivers for the SPI relay. This is done by declaring `SPI_DATA`, First, we need drivers for the SPI relay. This is done by declaring `SPI_DATA`
`SPI_CSLOW` and `SPI_CSHIGH`, which are respectively `4`, `5` and `6` in our and `SPI_CTL`, which are respectively `4` and `5` in our relay design.
relay design. We also need to define SPI_DELAY, which we keep to 2 NOPs because
we use the system clock:
: SPI_DELAY NOP, NOP, ; You also need to tell the SDC subsystem which SPI device to activate by defining
the `SDC_DEVID` (1, 2, 4, 8 for device 0, 1, 2 or 3)
You can then load the driver with `596 LOAD`. This driver provides You can then load the driver with `596 LOAD`. This driver provides
`(spix)`, `(spie)` and `(spid)` which are then used in the SDC driver. `(spix)` and `(spie)` which are then used in the SDC driver.
The SDC driver is at B420. It gives you a load range. This means that what The SDC driver is at B420. It gives you a load range. This means that what
you need to insert in `xcomp` will look like: you need to insert in `xcomp` will look like:
@ -139,5 +131,4 @@ Very easy. You see that `/cvm/blkfs` file? You dump it to your raw device.
For example, if the device you get when you insert your SD card is `/dev/sdb`, For example, if the device you get when you insert your SD card is `/dev/sdb`,
then you type `cat emul/blkfs | sudo tee /dev/sdb > /dev/null`. then you type `cat emul/blkfs | sudo tee /dev/sdb > /dev/null`.
[schematic]: spirelay.pdf
[inspiration]: https://www.ecstaticlyrics.com/electronics/SPI/fast_z80_interface.html [inspiration]: https://www.ecstaticlyrics.com/electronics/SPI/fast_z80_interface.html

BIN
recipes/rc2014/spirelay.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.