Last visit was: Wed Dec 01, 2021 7:03 pm
It is currently Wed Dec 01, 2021 7:03 pm

 [ 15 posts ] 
 Implementing SPI on an 8-bit traditional data bus cpu 
Author Message

Joined: Mon Aug 14, 2017 8:23 am
Posts: 157
SPI is almost universal these days, for peripherals, LCDs, sensors, memory, uSD cards, GPIO expanders etc, etc. It's also a really neat way to communicate between 2 systems.

The downside is that it is not implemented on the classic cpus - such as 6502, Z80 etc, creating an additional problem to interface these processors to modern peripherals.

Ideally, the solution would be a simple SPI transceiver that could be connected to a traditional 8-bit bus.

A partial solution was suggested on the forum nearly a year ago involving bit-banging SPI, and then a faster hardware proposal making use of the 74HC299 universal shift register. ... =30#p74650

The desire is to create an SPI Master which can connect to the 8-bit bus.

Write a byte to it, with A0 low to send to the peripheral, and then read back from it with A1 high - that would be perfect. Further logic would be needed to set up a group of slave-select signals. suggested a solution using the 74HC299, but this would require additional logic to create a gated burst of 8 clock pulses to accompany the MOSI data. After the 8 clocks, the SPI clock returns to an idle state.

Could this be done with a single chip solution? Perhaps an ATmega328p ?

Any suggestions appreciated.

Thu Feb 04, 2021 5:10 pm

Joined: Tue Dec 18, 2018 11:25 am
Posts: 40
Location: Hampshire, UK.
Something like this?
But it is for a 16 or 32 bit interface, and probably an overkill using an ICE40 FPGA though.

Thu Feb 04, 2021 7:55 pm

Joined: Sat Nov 28, 2020 4:18 pm
Posts: 123
Yeah, I mean, it can be done with a microcontroller or cpld/fpga. An ATTINY is likely the smallest microcontroller you could use (probably not the cheapest though, hard to beat an arm for that), and I think you could find one with a built-in oscillator, so it can be a single-chip solution.

But if you wanted to avoid using a microcontroller or programmable logic device, you would probably need to consider running the main system clock at SPI speeds (40x?) and then dividing the clock down for the CPU while running the 74x299 at the higher clock rate.

Another option that's still lots of chips is to have a QSPI device, some way to initialize it into QSPI mode, and then an 10 way multiplexer to put the command, a 24-bit address then 8 bits of data (for a write) on the bus 4 bits at a time. For reading you could use 2 4-bit registers (74x173) to store the data temporarily for the cpu to read. You still need the faster SPI clock, but the entire transaction could happen in just 10 (or 12?) cycles of that clock. This could, of course, be done in a small CPLD -- potentially even an ATF1508 or similar.

I had the idea of having two QSPI devices to make an 8 bit bus, but the logistics are weird... you'd always read or write two bytes at a time.

Fri Feb 05, 2021 12:54 pm

Joined: Mon Aug 14, 2017 8:23 am
Posts: 157
Thanks for your suggestions - much appreciated.

The 74HCT299 looks almost ideal to create a fast serial link between two devices.

What is needed is some device that will create a Slave Select signal and a train of 8 gated clock pulses. This could possibly be as simple as an ATtiny85.

For TTL enthusiasts, it would need 3 flip-flops to create a Modulo-8 counter and some gating logic. A 4-bit counter and a quad nand might be all that is needed.

Fri Feb 05, 2021 1:57 pm

Joined: Wed Jan 09, 2013 6:54 pm
Posts: 1647
I think there's plenty you can do with a preloadable 4 bit down counter: indeed I think Jeff has offerings over on the 6502 forum.
For example:

Fri Feb 05, 2021 4:38 pm

Joined: Mon Aug 14, 2017 8:23 am
Posts: 157
Thanks Ed,

This afternoon I have been having a tinker on "Digital" simulator.

The 74xx163 is definitely useful here, just need to get the clock gating to produce a burst of 8 clocks.

Fri Feb 05, 2021 5:19 pm

Joined: Mon Aug 14, 2017 8:23 am
Posts: 157
Here is a first attempt at a SPI clock burst generator.


Fundamentally we need to AND gate the clock with a pulse that is high for 8 clock pulses.

We need a way to trigger the signal with a momentary pulse, and after generating an output of eight clock pulses, the circuit resets and goes back to an idle state.

We could use QD of the 74xx163 counter to provide the gating signal.

However I have used QC and QD XORed together which goes high when the count reaches 4 and goes low when the count reaches 12. This gives us the means to generate a slave select signal which is low for the full 16 clock pulses.

The button the left initiates the sequence toggling the flip-flop high, and enabling the counter via its ENP input.

The 8 cycles clock burst is created by AND gating the clock with QC^QD.

The RCO (Ripple Carry Out) goes high at count 15 and is inverted by the XOR gate. This signal toggles the flip-flop to zero and inhibits the counter.

This is a first attempt, and I am sure there is scope for further logic reduction.

You do not have the required permissions to view the files attached to this post.

Sat Feb 06, 2021 12:56 pm

Joined: Tue Dec 18, 2018 11:25 am
Posts: 40
Location: Hampshire, UK.
There have been attempts to make SPI SD card interfaces for the Z80 (RC2014).

These may have useful ways of generating the gated clock pulses.

Sat Feb 06, 2021 2:57 pm

Joined: Mon Aug 14, 2017 8:23 am
Posts: 157
Thanks for the links.

The 3rd one looks the most interesting, using a 74xx163 and a NAND to generate the gated pulses.

The combination of the 74xx165 to send serial data and the 74xx595 to receive it is a recurring theme, but I still think this could be simplified using the 74xx299.

It might need an address latch, so that A0 and A1 can be latched and used to select the mode of the '299, and of course a clock burst generator.

Sat Feb 06, 2021 4:32 pm

Joined: Mon Aug 14, 2017 8:23 am
Posts: 157
Having looked at the 3rd option, I'm not sure how the 74xx163 can ever start counting with QD tied to ENT.

The counter will always be disabled if ENT is low, and QD will always be low after power-up.


Sat Feb 06, 2021 5:42 pm

Joined: Mon Aug 14, 2017 8:23 am
Posts: 157
Hi All,

I'm not sure whether my grey matter going rusty through lack of exercise, but it has taken a lot longer than expected to implement the basics of SPI in discrete TTL ICs.

Inspired by Dr. Jefyll's use of the 74163 as the basis of the SPI sequencer, I came up with the following state machine design using just 3 ICs to create both the slave-select /SS and the gated serial clock SCK. These form the basic signals needed to control an SPI peripheral.

The 74138 decoder on the right is redundant to the design, as decoding counter state 9 can be done with a single NAND gate.

The dual D-type flip flop IC2 synchronises the trigger pulse to the negative phase of the clock (IC2A), and also provides a toggle style flip-flop (IC2B) to both start and stop/clear the 74163 counter.

On startup the counter is at state 0 and disabled. A positive pulse on the Trigger input is ultimately latched in IC2B and this releases the counter from its cleared state and enables it to count upwards towards state 9. The NAND gate detects state 9, sets the flip-flop and this resets the counter.

The result is a burst of 8 positive going clock pulses and a low going slave-select signal - as shown.

The single low going LATCH pulse can be generated from the /SS signal and a monostable - more on this later.



In the next part I will look at how the 74299 universal shift register can be used with this SPI Sequencer to complete an SPI Master which can be interfaced to a traditional 8-bit bus.

You do not have the required permissions to view the files attached to this post.

Mon Feb 15, 2021 10:55 pm

Joined: Wed Apr 24, 2013 9:40 pm
Posts: 206
Location: Huntsville, AL

I think that you'll not be happy with the synchronous assertion and deassertion of nSS at the end of each byte transferred.

I suggest that you simply assert / deassert nSS asynchronously from a simple register as needed. Of course, it has to be asserted low before the first clock, and deasserted after the last clock; somewhat like you've shown. However, each assertion of nSS clears the internal SPI state machine in SPI-capable devices like Serial EPROMs and SRAMs. By deasserting nSS after each 8-bit transfer and reasserting at the start of each transfer, you're causing that internal state machine to be reset. Thus, you'll never be able to send anything other than the command byte to such devices.

When you control the nSS from a register, you can then send the command byte, and address bytes, and any data bytes (for writes) or dummy bytes (for reads) of the SPI device.

Michael A.

Tue Feb 16, 2021 12:07 am

Joined: Mon Aug 14, 2017 8:23 am
Posts: 157
Michael - thankyou for the advice - much appreciated.

I am groping my way through this personal challenge a few bits at a time.

I currently use nSS to ensure that only 8 clock pulses are gated to the shift register. I understand the significance of multibyte transfers to the likes of SPI RAM where nSS needs to remain asserted for the duration of the transfer.

Tue Feb 16, 2021 1:49 am

Joined: Mon Aug 14, 2017 8:23 am
Posts: 157
In this post I describe the operation of the Master and Slave shift registers.

I found that there was very little practical information on the 74xx299 online, as mostly other shift registers such as the 74xx166 and 74xx595 are covered as various Arduino I/O extenders.

The 74xx299 is a universal 8-bit shift register which supports a parallel 8-bit tristate I/O bus. It has serial inputs and outputs that support both serial loading either in a left shift or right shift direction.

As such it offers parallel to serial and serial to parallel conversion, in a single device which is compatible with a typical 8-bit microprocessor bus.

The NXP datasheet is here, which shows the internal structure. Note that the NXP pin names are slightly different to those I have used which were from TI. ... 4HC299.pdf

As a convenient analogy, in one respect think of it as a single 8-bit storage register, which can be written to or read back from - but with the added advantage that it can exchange data with other devices over a serial link.

The 74xx299 has 4 modes of operation, controlled by the S1 and S0 pins:


In addition, it has two active low tristate controls G1 and G0. Taking either of these high will put the output pins into high impedance mode, allowing tristate operation on a bus. When parallel load mode is selected with S1 and S0 both high, the bus pins are automatically put into high-Z mode, allowing data to be loaded from the bus.

There is an active low asynchronous clear, which will reset all the internal flip-flops.

For accessing the serial data, there are two inputs SL and SR for accepting serial data for left shift and right shift modes, and two serial outputs QA' and QH' which give a direct (non tristate) connection to the first and eighth internal flip-flops.

On a single clock input, data is shifted on the rising edge of the clock.

With all these pins, it took a bit of figuring out how best to control the device using signals that are compatible with the familiar SPI bus. To simplify the problem, I decided to adopt a left shift convention, but equally right shift would be equally applicable, as the internal structure of the shift-register is entirely symmetrical with no preference to either mode.

In left shift mode, serial data will enter via the SL input pin (18) and be shifted out lsb first through the QA' output pin (8).

To connect two registers together in a master-slave configuration, the QA' of the master is effectively MOSI and connects to the slave SL, and the slave QA' is MISO and connects back to the master SL pin.

The first diagram shows the basic connections for master-slave operation using the standard SPI signal naming conventions.


In this configuration the contents of the master will be transferred to the slave, and the slave contents simultaneously transferred to the master by applying 8 clock pulses to the SCK line. Performing this circular transfer of data between devices is the basis of SPI communications.

All it needs is a shared clock line, two signal lines for full-duplex operation and some means of enabling the slave device.

Compared to the complexity of asynchronous serial communications involving UARTs, baud rates, handshaking, parity, start and stop bits, voltage level converters, synchronous serial communications is a breeze.

With modern HC TTL, clock frequencies of tens of MHz are possible. At 5V supply the 74HC299 (NXP) has a maximum clock frequency of 50MHz, well above the speed requirements of a classic microprocessor bus.

When I first learnt this behaviour of shift registers some 35+ years ago, I was fascinated that such a useful function could be obtained from such a relatively simple device, even more so when some years later when it became the fundamental operation behind SPI.

Below is the test circuit that I have been simulating using H. Neeman's "Digital simulator". I have added push buttons for convenient manual loading of the register and LEDS and 7-segment displays to indigate the contents of each register.

Unused input pins are shown with the square symbol. During simulation thes pins default to logic zero.

I have created a new Github repository for this exploration:


You do not have the required permissions to view the files attached to this post.

Tue Feb 16, 2021 12:06 pm

Joined: Mon Oct 07, 2019 2:41 am
Posts: 273
SD cards alas are "fly in the oinment", they need dual speeds ( config ) and normal and have fussy chip selects.
Circuit looks good. Ben.

Wed Feb 17, 2021 3:07 am
 [ 15 posts ] 

Who is online

Users browsing this forum: CCBot and 0 guests

You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Jump to:  
Powered by phpBB® Forum Software © phpBB Group
Designed by ST Software