46676547d9
AVR chips often run at less than z80's system clock. This means that our SPI relay needs to have its own clock to properly communicate with it. This means that the delay between OUT and IN can't be hardcoded to 2 NOPs anymore. It needs to be configurable.
137 lines
5.1 KiB
Markdown
137 lines
5.1 KiB
Markdown
# Accessing a MicroSD card
|
|
|
|
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.
|
|
|
|
Due to the way IO works in z80, implementing SPI through it as a bit awkward:
|
|
You can't really keep pins high and low on an IO line. You need some kind of
|
|
intermediary between z80 IOs and SPI.
|
|
|
|
There are many ways to achieve this. This recipe explains how to build your own
|
|
hacked off SPI relay for the RC2014. It can then be used with the SD Card
|
|
subsystem (B420) to drive a SD card.
|
|
|
|
## Gathering parts
|
|
|
|
* A RC2014 Classic
|
|
* A MicroSD breakout board. I use Adafruit's.
|
|
* A proto board + header pins with 39 positions so we can make a RC2014 card.
|
|
* Diodes, resistors and stuff
|
|
* 40106 (Inverter gates)
|
|
* 4011 (NAND gates)
|
|
* 74xx139 (Decoder)
|
|
* 74xx161 (Binary counter)
|
|
* 74xx165 (Parallel input shift register)
|
|
* 74xx595 (Shift register)
|
|
|
|
## Building the SPI relay
|
|
|
|
The [schematic][schematic] supplied with this recipe works well with `sdc.fs`.
|
|
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,
|
|
loaded in parallel mode from the z80 bus and a shift register that takes the
|
|
serial input from `MISO` and has its output wired to the z80 bus.
|
|
|
|
These two shift registers are clocked by a binary counter that clocks exactly
|
|
8 times whenever a write operation on port `4` occurs. Those 8 clocks send
|
|
data we've just received in the `74xx165` into `MOSI` and get `MISO` into the
|
|
`74xx595`.
|
|
|
|
The `74xx139` then takes care of activating the right ICs on the right
|
|
combinations of `IORQ/WR/RD/Axx`.
|
|
|
|
The rest of the ICs is fluff around this all.
|
|
|
|
My first idea was to implement the relay with an AVR microcontroller to
|
|
minimize the number of ICs, but it's too slow. We have to be able to respond
|
|
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].
|
|
|
|
This board uses port `4` for SPI data, port `5` to pull `CS` low and port `6`
|
|
to pull it high. Port `7` is unused but monopolized by the card.
|
|
|
|
Advice 1: If you make your own design, double check propagation delays!
|
|
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
|
|
and SPI connector). Those jumpers will be useful when you need to mess with
|
|
polarity in your many tinkering sessions to come.
|
|
|
|
Advice 3: Make input `CLK` override-able. SD cards are plenty fast enough for us
|
|
to use the system clock, but you might want to interact with devices that
|
|
require a slower clock.
|
|
|
|
## Building your binary
|
|
|
|
The binary built in the base recipe doesn't have SDC drivers. You'll need to
|
|
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
|
|
our xcomp block (likely, B599). Open it.
|
|
|
|
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
|
|
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 can then load the driver with `596 LOAD`. This driver provides
|
|
`(spix)`, `(spie)` and `(spid)` which are then used in the SDC driver.
|
|
|
|
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:
|
|
|
|
423 436 LOADR ( sdc )
|
|
|
|
You also need to add `BLK$` to the init sequence.
|
|
|
|
Build it (run `make pack` in `cvm/` first to ensure an up-to-date blkfs) and
|
|
write it to EEPROM.
|
|
|
|
## Testing in the emulator
|
|
|
|
The RC2014 emulator includes SDC emulation. You can attach a SD card image to
|
|
it by invoking it with a second argument:
|
|
|
|
../../../emul/hw/rc2014/classic os.bin ../../../cvm/blkfs
|
|
|
|
You will then run with a SD card having the contents from `/blk`.
|
|
|
|
## Usage
|
|
|
|
First, the SD card needs to be initialized
|
|
|
|
SDC$
|
|
|
|
If there is no error message, we're fine. Then, we need to hook `BLK@*` and
|
|
`BLK!*` into the SDC driver:
|
|
|
|
' SDC@ BLK@* !
|
|
' SDC! BLK!* !
|
|
|
|
And thats it! You have full access to disk block mechanism:
|
|
|
|
105 LOAD
|
|
BROWSE
|
|
|
|
(at this moment, the driver is a bit slow though...)
|
|
|
|
## How do I fill my SD card with Collapse OS' FS?
|
|
|
|
Very easy. You see that `/emul/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`,
|
|
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
|