Overview
The next design we will look at is the data register. This subsystem is the piece that actually interfaces with the SPI devices. It is responsible for both sending 8 bits to and receiving 8 bits back from a peripheral, 1 bit at a time (remember, SPI is a serial protocol!)
Design Considerations
Here are the constraints our data register must conform to (many of which are the same as the control register!):
- it needs to fit in well in a 6502 memory-mapped environment
- it must be safe to read and write
- it must be resettable
- it shifts 1 bit out, MSB (most significant bit) first, on each SPI_CLK positive-edge
- it shifts 1 bit in, MSB first, on each SPI_CLK positive-edge
Design
SPI is a serial protocol but the interface to our microcomputer is parallel, so we need to choose parts that can translate between the two. This is the core of the entire device so we need to get this right!
We stated in the project overview that transmission will start when a value is written to the data register, so we'll begin there. For this task, we'll use a 74HC165 8-bit parallel-in/serial out shift register. This shift register supports asynchronous parallel load (will be important later...) and shifts the MSB out on a clock pulse. This chip also has an "inhibit" pin which can be better described as /SHIFT_EN (LOW asserts that shifts are enabled and HIGH inhibits any shifting). So our design for the write side of the data register looks like:
We are using a special clock here, not the main clock and not the divided clock, because we're only supposed to shift 8 bits and then stop which will be covered by another subsystem. Shifting is also inhibited while writing to the register.
Next, we need to be able to read the byte received back from the peripheral. For this, we'll use a 74HC595 serial-in/parallel-out shift register. This shift register takes data in one bit at a time, MSB first, but can output the whole byte when /OE is asserted.
One major quirk of this device is that shifting and saving are 2 separate operations. There are actually 2 registers in this device: SR (the actual shift register) and R (the "register" I guess?) which is the register whose contents are put on the Q lines when /OE is asserted. If we forget to assert /RCLK at the end of our shifting, we will simply see the old contents of the R register, rather than our new shifted in bits.
I also have a pull-up resistor on the MISO line but most devices should already have this so it may not be strictly necessary.
Putting it all together, we get the full design:
Blast From the Past
So, does it work? Sadly, no.
First, we are going to drop one of the design considerations for the data register. We previously stated that this should be resettable. This should be simple, there is a /RES line connected to an active-low /SRCLR pin. Easy! Actually, no. Remember that design quirk from earlier? It turns out asserting this line only resets the shift register and not the register register! Additional logic is needed to assert the RCLK line on reset. Instead, I've decided to drop this requirement because contents of this register do not drive anything else in the device. If users want to read the garbage it boots up with, there is no harm in it.
There are a few other subtle mistakes here that will only become apparent when we examine the next subsystem, the beating heart of SPI Master: the Finite State Machine!
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.