Serial to SPI Programmer

Build an SPI Encapsulation Link

David Kitson

Issue 25, August 2019

This article includes additional downloadable resources.
Please log in to access.

Log in

Everything you ever wanted to know about SPI and a few things you didn't, all controlled from the comfort of your PC.


Have you ever wanted to control a small Arduino or Raspberry Pi display straight from your PC? How about reading accelerometers from a chip for a programming project? Or have you wanted to build your own in-system programmer so you can make the leap to embedded projects without all the complexity of having to remove chips so you can plug them into the burner?

Then this project is for you. It’s an SPI bootstrap programmer so that you can program a bigger, better SPI programmer that can do much more than just program other chips. It can talk to and read SPI devices, displays and peripherals as well. And it all works from a standard serial port, on any platform, and can be operated by human-readable strings from a serial terminal application such as Putty or Kitty, or even Hyperterminal.

This Project is Useful For:

  • Starting out with embedded control chips or microcontrollers
  • A cheap low-cost universal SPI programmer for Atmel 8051 processors, AVR and PIC chips
  • Controlling SPI devices straight from your PC
  • Debugging and learning about SPI
  • Optimising initialisation strings for SPI devices, without a library
  • People who want to learn about Digital Logic projects and Electronics Basics


At the heart of this project is one of the most misunderstood and maligned protocols common to modern microcontrollers and MCUs - SPI, or Serial Peripheral Interface.

SPI is one of the few widely used defacto standards in existence, which leads to a lot of versions and variations with very little thought given to compatibility between manufacturers. This, in turn, results in many problems that can be encountered when using this protocol with a new device, especially if you don’t have a well-made library to help out, and even then things can still go wrong.

Upon completing this fairly basic circuit, you will be able to write an SPI bridge program in assembly language to an Atmel (Microchip) AT89LP2052 or AT89LP4052 which will let you talk SPI via a common TTL RS-232 cable. The SPI bridge takes standard commands over a serial port and converts them to SPI data, then both writes and reads the data on the SPI bus via the chip’s SPI port. However, because it’s machine and human-readable, you can literally craft SPI control strings on the fly, and accessing an SPI device, such as a display, is no more difficult than cutting and pasting a text document into a terminal program. This makes writing initialisation code easy, and verifying it even easier.

You can then also use this new SPI Encapsulation Link bridge to program other SPI programmable processors, using the in-system-programmable (ISP) capability. You can even download the SPI bridge into an in-circuit MCU and access the board’s SPI devices as if they were connected to your PC via the serial port.

Most of all, you don’t need a complicated or expensive SPI programming device, because you can build this one with just a few common components. This first project builds the bootstrap programmer, and the next project will show you how to use the SPI Encapsulation Link to control and operate SPI peripherals directly.

If you just want the bootstrap programmer to program many ATS and ATLP series 8051’s, PICs, TINY’s and AVRs, you can probably omit the Atmel AT89LP2052 or AT89LP4052, but including the chip and using the SPIEL interface is still a better choice for programming other devices, as it can then read the SPI link as well.


So the question you might be asking yourself now is: "What is SPI?" Why do you need to know about SPI and why would you use it, even if you’re not an embedded programmer?

SPI is a really common protocol used in things ranging from Canon autofocus lenses, SD cards and TF chips, LCD and LED displays, acceleration sensors, electronic compasses, non-volatile memory chips and even common chips like ADCs and DACs. Even the new FLIR thermal imaging Lepton cores use a protocol variation called Video over SPI that literally sends digital video signals over this serial bus.

Using SPI can be difficult, with two major problems. The first is that it can often be quite challenging to get the protocols that run over SPI working on microcontrollers due to the large number of variables in accessing an SPI chip, with no common standard across vendors. The second is that there are no SPI interfaces for the PC so you can’t just connect up a PC to your SPI devices and start using them.

Often, when working with SPI from a PC, a proprietary interface is required that interprets commands from the computer and then uses an on-interface SPI connection to talk to the chips. Most of these only have the capability to program a small number of chips, and no capability to talk directly to peripherals at all.

This project solves that dilemma in two parts. Firstly, it creates a low-cost directly-accessible SPI based programmer that plugs into a USB port and operates as a normal RS-232 asynchronous port. Using it, that you can program MCUs such as the AT89LP2052, which are In-System Programmable, or ISP. ISP means you can install the chip into a circuit and just program it via a jumper cable to save having to remove it for external programming. If you need firmware updates, ISP simplifies the process.

The second part of this project will revolve around using the newly-created SPI Encapsulation Link to make an open-source ISP SPI Super-Bridge that encapsulates ISP instructions over the same serial port used to program it. This can be used as a debugging tool for SPI devices, as well as a microcontroller programmer if you want to program MCUs.


The first thing to understand about the differences between RS232 and SPI is that one is asynchronous and the other is synchronous. RS232 follows rigid timing specifications, and both the sender and receiver require accurate clocks to participate in the data flow.

SPI on the other hand is synchronous. A clock signal is transmitted, along with a Slave Select (SS) signal, to identify to the receiver how to handle the data. The bits don’t have to be transmitted at any particular rate and it’s possible to pause in the middle of transmission without losing a bit or a byte.

Aside from that, most SPI protocols transfer the most significant bit first, while RS232 transfers the least significant bit first. So while the order that the bits are transmitted in is usually reversed, never assume anything with SPI. Even if the bit order was the same, the circuitry that reconstructs the clock signal itself is quite complex, and so it’s not a good idea to attempt to go from one to the other directly.

Also, that doesn’t address the issue of the slave select signal, especially if you’re using a 4-wire RS232-TTL interface which only has RX, TX, +5V, and GND. Without other signals, there’s no way to set the control bit. Even if you do, many SPI devices want a reset line, and displays often even ask for a data/command bit as well.

These are all problems this project needs to address. The first, clock generation, is solved by a simple timing circuit that reconstructs a synchronous clock from the asynchronous signal. Then it automatically generates the Slave Select signal to activate the SPI slave device. It does this with a relatively common 4093 Quad NAND Schmitt trigger logic IC, a few capacitors and resistors, before feeding the output through a set of jumpers straight into the SPI bus of the target 89LP2052 microcontroller. This circuit integrates four common functions, and with some carefully crafted serial packets to trigger the logic, reconstructs a valid SPI signal.

The choice of the 4093 was due to the low-voltage tolerance of 4000 series logic chips and the very sensitive input gates to reduce the load on the RS232 TTL interface output.

ASYNC byte and a SYNCHRONOUS byte.


This circuit uses a 4093 CMOS Quad-NAND Schmitt trigger to process the signals from the serial port. It’s a simple logic chip with four gates and no smarts, and if both gates are at logic level “1” then the output is at logic level “0”. For any other input combination, the output is at logic level “1”. Other than this, it’s a Schmitt trigger. This is an important distinction.

Most logic devices decide that the middle voltage between GND and the supply voltage is the difference between a 0 and a 1, and any voltage around that point could be either.

A Schmitt trigger defines a voltage level that is definitely a 0 and a voltage level that is definitely a 1, and they are well apart. The middle zone then becomes whatever the last state was. So if a “0” is 1.5V and a “1” is 2.5V and the input was last a “1” then if the voltage is 1.6V, it’s still a “1” and will remain like that until the voltage gets to 1.5V. At that point, the input becomes a logic “0” and will remain like that even if the input goes back to 1.6V and will stay a “0” until the voltage reaches 2.5V. It does that by feeding the output back into the input internally like an op-amp to stop circuit noise from causing glitching on the output. It’s an important characteristic for us, because we’re going to use that analogue nature of the op-amp-like input to build some timer circuits. Four of them in fact.

We start our circuit with two NAND gates wired together [1] & [2].

The 10kΩ resistor and 330nF capacitor [1] provide the SET function, and the 10kΩ and 22nF capacitor [2] automatically provide the RESET function.

These two NAND gates wired together form the heart of this circuit and form what is known as an SR, or SET/RESET flipflop, or latch. As long as the two outside inputs are normally held high, then it will catch even a millisecond-short pulse on the SET input and latch it in, changing the state of the output (flip) until a similar signal occurs on the RESET and it returns to the prior state (flop). It’s a form of data register. On top of that, the reset output is wired back into itself via a 10k resistor, and the input to the reset circuit is tied to a small 22nF capacitor. Normally, if you tie the reset output to the input, the reset circuit will oscillate at the frequency of the maximum rate that the chip can self-oscillate at, but in this case, as the RESET output goes low, it slowly discharges the capacitor via a 10k resistor. It takes around 140 to 220 microseconds to discharge the capacitor to the point where it causes the input to register a “low” and reset the flip-flop. This then charges the capacitor as well, completing the reset.

Two things to note here, ALL of the component values are critical in this kind of circuit, so while it is a digital chip, and digital isn’t generally all that fussy about component values, this is an analogue circuit and uses the Schmitt trigger analogue inputs of the gate.

In the text in the article is references to the parts of the circuit:

[1] The SET circuit of the SET/RESET FlipFlop

[2] The Self-RESET circuit of the SET/RESET FlipFlop

[3] The Clock Pulse Generation Circuit

[4] The Slave Select Generation Circuit

[5] Jumpers On = Program MCU. Off = MCU controls SPI and Async

Early Prototype:

Prototyping on a breadboard was likely to cause noise when testing the circuit with an oscilloscope, so David made a quick prototype using perfboard, as you see here.

This saved David from designing and etching a PCB that we describe later in the article.

We don't describe how to build your own prototype in this article, but you can simply follow the circuit diagram if you wish to make your own.

The oscilloscope screenshots that you see on the following pages were from this prototype.

140 to 220 microseconds may seem like a big range for a timing circuit, but we'll get back to that later. What’s important is this means our SR latch is now wired as a timer. Once activated, it will remain set for a specific period, of between 140 to 220 microseconds, then it will automatically reset itself. So it’s function is to take a short pulse, and stretch it out for a relatively well-defined period of time, depending on how long it’s been since it was last set. This kind of circuit is also known as a pulse stretcher.

Now let’s add a signal to trigger it. We want to use the TxD from the USB cable to start our timer. When the start bit goes low, we can use that to activate our flip-flop, because we know valid serial data will be present on the TxD line in about 100 microseconds, and will remain valid for another 200 microseconds after that. Astute techs might notice at the moment that the 140 to 220 microsecond delay of our latch circuit is right in the middle of that range. That’s because we’ll use the latch outputs from the SR Flipflop to derive the clocking signal for the SPI.

But we don’t know what the first bit transition will be for the TxD line and having random bits of data on the input to the latch is going to cause problems. So, we need to clean that up, and generate a single pulse from the start bit to avoid that problem.

First, the downgoing edge of the start bit passes through the 330nF capacitor, and the resistor on the other side is tied high to maintain the normal input of the latch. This gives us a pulse of a few microseconds each time we get a start bit falling edge and lets us ensure that our timer will activate ONLY on a start bit, bit, continuing to run for the specified period after that.

Note: In all the oscilloscope images, the yellow trace is the asynchronous signal from our USB serial cable, as a reference point for all other signals. The blue trace is the signal taken from different places on the board.

In the image shown above, the yellow trace shows the start bit with a negative transition. The blue is the signal that can be found on Pin 6 [1] and should be a 1 to 2 microsecond pulse that only occurs when the TxD line (yellow) has a high-speed negative edge. The upward spike seen further to the right is the positive edge being suppressed by the in-chip diode protection circuit. Often a separate diode is used, but at the power levels we’re using, the protection diodes in the 4093 chip are more than adequate to cancel the overvoltage of the positive edge transition.

The start bit is about 100 microseconds long, as can be seen on the trace. Valid data follows immediately after this bit, starting with the least significant bit of the asynchronous byte.

This means that around 200 microseconds later, give or take a little for charge allowance, our timer will generate an edge transition at the same time a valid bit is present on the TxD line. Since it contains data, we can run TxD straight through to the SPI bus as the “MOSI” signal since it’s going to have valid MOSI data when the SR latch timer expires. Now we just need to generate a clock signal from the SR latch expiry.

When the start bit hits, within about a microsecond, the output of the SET gate goes high, and stays that way until the timer completes at which point it resets.

The blue trace shows how the SET gate output follows the start bit - or any negative transition in the TxD line - and then stays high for around 220uS. The Output of the RESET gate then mirrors this, starting high and going low. The blue trace can be seen on Pin 4 of the 4093 IC.

The output of the RESET gate on Pin 3 is the opposite of Pin 4, and this feeds back to its input on PIN1 via a resistor, charging and discharging a capacitor also attached to that pin.

This oscilloscope image shows the full data from two bytes of data sent on the TxD line, with four negative transitions, and the corresponding timer sawtooth wave this generates through the RC circuit at the flip-flop on Pin 1 (blue). This sawtooth signal causes the Schmitt trigger to reset when the voltage gets to about 1.5V, resetting the timer.

When the timer resets, the output from pin 4 of the 4093 goes low again. This is the signal edge we want to use to generate the SPI clock since there should be valid data on TxD at this point. We push this signal through a very small capacitor, 2.2nF, of which the other side is held high by a 10K resistor. This leads to around a 25 microsecond negative pulse, which then recharges slowly. This is run back into a NAND gate to both inputs, wired as an inverter, which turns it into a 25 microsecond POSITIVE transition pulse. Now we have a valid clock pulse that occurs at the same time that the data on the TxD line is valid for the SPI. With this, we have successfully generated our clock signal.

Output of Pin 4 after passing through the 2.2nF capacitor. Prior to cleaning up and inverting it, and can be found on Pin 12 and 13 [3].
The cleaned up clock signal is found on Pin 11 and should look like this.

We run this output pulse through another NAND gate, at both inputs, so it becomes a Schmitt trigger inverter. This cleans the pulse to provide a clean clock pulse at the correct time. In this case, sending the data 1001.

Finally, because we still need a Slave Select signal, we do something else with the same output from the SET side of the flip-flop latch. We run it through a diode into a VERY small capacitor, just 100 picofarads, to charge it up. This capacitor has to be very small, because we don’t want to delay the output of the timer circuit by slowing down the SET function, so it charges it up within a microsecond, and will take around a millisecond to discharge to the point that it is seen as a logic "0" again.

This shows the rapid charge and slow discharge of the 100pF capacitor and can be found on Pin 8 and 9 [4].

Because this small capacitor is discharged slowly by a very big resistor - 10MΩ - it takes a while to charge even though its value is tiny. This resistor needs to be big because of this.

Incoming bits are encoded at around 2 bits per millisecond, so if a stream of bits continues to be sent across the serial port, then this output will remain low for the duration we’re sending data.

Troubleshooting This Build:

When building a digital project like this, having some electronic tools on your bench, such as a digital multimeter, is a must-have for troubleshooting.

COMPONENTS: The first step is to check all of your components. Read the resistor codes on the side of the resistors and the numbers on the side of the capacitors. Check the chips are installed the right way up, and that they have the appropriate voltage present. Make sure you have the correct serial port selected, and have signals on the line from the PC. The LED should flash when uploading, although quite dimly.

MULTIMETER: Measure resistors to ensure you have them correct. Sometimes resistor packs are labelled incorrectly, which happened to us while assembling this project. Check that the voltages present are what is expected. Check each trace on the circuit board to make sure it’s not shorted to another somewhere.

LOGIC PROBE: These don’t measure voltages, but they do know what a 1 and a 0 look like, and show you quickly. If both are showing, that means it’s changing between the two. They should detect pulses, such as communications pulses on the TX line from the PC, and the signal pulses generated by the Quad NAND gate circuitry. These can be detected as per the operational description and oscilloscope images. Check out our logic probe project from Issue 14, which is available in kit form from Jaycar and Altronics.

OSILLOSCOPE: Important when working with circuits that oscillate or that change state a lot. They show voltage in the time domain, and often come with two probes, and sometimes even three or four. Check on the pins mentioned in the article. Do you see the same signal? If not, that’s a pretty good indication that there may be a fault with that part of the circuit.

LOGIC ANALYSER: Logic Analyzers are like a multichannel logic probe. Smaller ones usually start at around 8 probes, and expand out from there. Attach the ground line to the ground line on the 10pin ISP header. You can pick up TxD, Clock and Select on pins 1,2 and 4. You can also watch pins 3,5,7,8 and 9 to cover all aspects of this circuit, though some are controlled by the AT89LP2052/4052 chip.

As we’re ONLY sending data, and this output changes within a few microseconds of the start bit leading edge, and remains high until the last bit has been sent, we now have a signal that tells us when data is on the line prior to the clock signal indicating that a bit is available. It’s still the wrong polarity though, and we need to clean it up and return it to being digital, so we run it back through another NAND gate with tied inputs to invert and clean up the signal.

We pass this signal from the 100pF capacitor into the remaining NAND gate set up as an inverter an inverter [4]. This gives us a clean square wave that serves as the Slave Select signal on pin 10.

The jumpers [5] serve to control whether the SPI signals are supplied via the bootstrap circuit to the bus, or directly by the microcontroller’s SPI interface.

With the generation of the Slave Select signal, our makeshift bootstrap SPI interface is complete, and we have all the functional parts of a valid SPI signal generated from our serial port TxD line, demultiplexed by time into three valid signals. Our work here is done - now it’s all back to the PC to generate the correct bitstream to activate the SPI circuit and push data down the line.

As a final note, we also use the Slave Select signal to run a LED, via a 10K resistor. Of note, CMOS chips don’t have a lot of power like TTL chips. Around 0.5mA of power in fact. So we need a 10K or larger resistor to make sure we don’t overuse that signal to run the LED, which would stop us from using it as an SPI signal. It means that the LED is dull, but it’s still bright enough to see, even though it’s only running on a few hundred microamps.

This wouldn’t be enough power to run a TTL chip, so our bootstrap programmer can only talk to SPI devices that are also CMOS. Fortunately, our AT89LP4052 microcontroller is a CMOS chip and has high impedance inputs, so will read this signal correctly.

Our First-Stage serial to SPI interface is now complete, and we’ll use that to program the microcontroller, which can then operate as a high-speed Second-Stage serial to SPI interface for next month’s project.

The Build:

Serial to SPI Programmer

Parts Required:JaycarAltronicsCore Electronics
1 × Atmel 89LP4052 or 89LP2052^---
1 × 4093 Quad Nand Schmitt Trigger ICZC4093Z4093-
1 × Tactile SwitchSP0603S1119ADA1490
4 × 0.1 Header JumpersHM3240P5450-
1 × 20 Pin DIP IC SocketPI6504P0568-
1 × 14 Pin DIP IC SocketPI6501P0560PRT-07939
1 × 10 Way DIL HeaderPP1100P5010-
1 × 6 Way DIL HeaderHM3250P5410PRT-12791
1 × Male Pin Header StripP5430HM3211POLOLU-965
1 × 11.0592MHz Crystal or Resonator (11MHz is OK )-V1065FIT0295
1 × 3mm Diffused LED (Any colour)ZD0110Z0700POLOLU-1070
1 × 10M 1/4W Resistor*RR0660R7094-
1 × 4M7 1/4W Resistor*RR1664R7090-
1 × 100K 1/4W Resistor*RR0620R7606-
4 × 10K 1/4W Resistor*RR0596R7582COM-11508
4 × 0R0 links (you can also use wire links here)RR1502R7005-
1 × Wire Link (use cutoff resistor leg)---
1 × 22uF Tantalum Capacitor*RZ6658R2642AADA2193#
2 × 0.1uF Monolithic Capacitors*RC5496R2930AFIT0118
1 × 22nF (223) Ceramic Capacitor*RC5352R2850FIT0118
1 × 2.2nF (222) Ceramic Capacitor*RC5340R2837FIT0118
1 × 330pF (331) Ceramic Capacitor*RC5330R2828FIT0118
1 × 100pF (101) Ceramic Capacitor*RC5324R2822FIT0118
1 × USB to RS232-TTL interface XC4594**XC4594**Z6522018-USB-PL2303HX
1 × Packet or Female to Female Header PinsWC6027P1017CEO5098

Parts Required:

* Quantity required, may only be sold in packs

** Not the correct board, but will do the task. Will require some manual wiring with leads.

† Comes in a packet of 35 pieces, but not too badly priced.

# Electrolytic – Can be used instead of tantalum.

^ 89LP2052 will work, but 89LP4052 is recommended. Both are inexpensively available on eBay and other sites.


Once you have all the parts, you might choose to make it on breadboard, or since it’s simple enough you might want to make up your own PCB for it. You might even want to copy a board and make it a part of a kit. The circuit board was designed in FREEPCB, which is the only completely free PCB software I’ve been able to find that doesn’t ask anything of its users. I’ve included the schematic and PCB file in case anyone wants to change it for their application. Visit the Resources section of the DIYODE website article to find the files.

The PCB itself is simple, single-sided, and has just a few links to replace an upper-side circuit board. It’s simple enough to make at home with a basic photoresist kit or with a PCB Mill. I have been making photoresist PCBs for decades, and now have switched to a PCB mill, as they take care of drilling and make an easy run of such simple circuits. You’ll need at least a 0.4mm or 16 thou bit, or smaller, though the clearances are designed to be further than 1/64 so you might even get away with a 0.5mm or 20 thou bit. It’s fairly tolerant that way, although tracks do run between chip pins. As long as the through-holes in the IC pads aren’t broken by the drill, you’re fine to use a bigger mill bit.

When assembling, install IC sockets first, or just the chips if you don’t use sockets. Then install the headers, and finally the remaining components. It has been designed to assemble in that order for maximum ease of assembly and hand soldering.

Note: It’s best to install a socket for the 89LP2052 or 89LP4052 as you can use this board to program them. You can then also modify a jump-board to allow programming of smaller MCUs directly, such as the 89LP214 (14 pin) and 89LP216 (16 pin) from the same hardware, as well as large 40 pin chips in the 89S series that feature SPI programming. It is worth noting, however, that the RESET polarity does change in some cases, but the SPI signals themselves are usually fairly consistent.


The Gerber files contain only bottom layer circuits - If making at home, be sure to check that the text is the right way around.


The top silkscreen provides details of which components go where, making it a quick reference to use even if you aren’t putting it on the board.

The header pins in the centre and next to CONN1 aren’t marked but are easy enough to locate - just use the pictures of the finished board as a reference if you aren’t sure. There are four headers, two dual-inline and two single-inline. There is room for a polarised header at the SPI interface end, but you can just break pieces off a DIL and SIL header section to fill all four header positions if you don’t have the IDC style header.


Troubleshooting should be according to the functional description we provided earlier, allowing each logical section of the circuit to be checked independently of the other sections. This can be done with an oscilloscope, or just a multimeter to check for any shorts across the isolation routes. A cheap $33 logic analyser (eg. Core Electronics TOL-15033) is sufficient if attached on the 6-pin DIP header in the middle of the board or the 10 pin IDC header at the end of the board, with the three SPI outputs being accessible at the middle of the board once the jumpers are removed. On removing the jumpers, and connecting the logic-analyser to the three pins closest to the 4093 chip, any signal not correct will tell you which section of the board isn’t working. This is a good alternative to an oscilloscope if you can’t find the problem, which can occur in isolation milling as sometimes bits of copper get bent back instead of being removed. A multimeter can help find shorts between tracks too and will suffice for troublehshooting, with patience.

The signals available to a logic analyser, from top to bottom on the 6-pin DIP header, are TxD from the USB, Clock and Slave Select respectively.

The jumpers in the middle of the board connect the bootstrap programmer (the 4093 programmer) in MASTER mode to the MCU which is programmed in SLAVE mode. The jumper on the side, next to the SPI interface header determines whether the SPI header is in master or slave mode. When it is up (towards pin-1 of the header) the MCU is in SLAVE mode, and the reset from the SPI connector is connected to the reset of the MCU. In this mode, the MCU can be reprogrammed by another board connected to it.

If the jumper is down, in the default position, then it drives the reset line of the SPI header connection from output 3, which allows you to control the reset line of whatever device it’s attached to.

It should be noted that in the Atmel version of the SPI header, the RESET pin is not connected, and has been removed, allowing that position to be used as a key, so there’s no right or wrong way to connect that pin, other than to be aware of what it does and how it’s connected to the MCU. The Atmel SPI port pinouts also don’t support the three additional output bits, and these are usually either grounded or not connected. As such, if you’re not using these pins, set them low as a standard procedure prior to activating the SPI outputs.


Generating the bitstream to drive the programmer.

We now know that to set up the correct signals for the SPI circuitry and NAND decoder, we need a start bit, and valid data for around 200 microseconds, then a stop bit. Four bits in total. We could simulate that by just sending a start bit and two data bits then waiting until the next byte to send another, but that’s slow, and wastes bits. If we use the implicit start bit, then bit 0,1 and 2 as the first data bits, then fix bits 3 and 4 as the next stop and start bits, then use bits 6,7 and 8 as the second data bits, we can encode two symbols per byte, which gives us an effective data rate of 2400 bits per second with a symbol carrier rate of 9600 baud.

Thus, for each byte transmitted, our frame should look like this;

Start, Bit0, Bit0, Bit0, 1, 0, Bit1, Bit1, Bit1, Stop

If we work that out to four combinations, we end up with four possible symbols representing two bits;

08H = 00 (MSB left)
0FH = 10 (MSB left)
E8H = 01 (MSB left)
EFH = 11 (MSB left)

By breaking up a transmission byte into four symbols, we can then send them down the serial port without delays in transmission and the circuit will reconstruct the byte in SPI serial format, with a synchronous clock and a slave select signal.


Programming the Atmel AT89LP4052 (or the AT89LP2052 for that matter).

The source code of the programmer fits within a single 2K window, so either chip is suited for programming without modification. The actual code for that chip, and the details on how to use it as a full SPI bridge, will be in the next article, though the hex file is included with this project so you can test the programmer. You can download this from the resources section of the DIYODE website.

Programming the AT89LP4052 requires an SPI interface. We have that. You need to reset the chip - we have a reset button on top which can be held down for the duration of programming. You also need an AT89LP2052 in-circuit. We have all of that. Now we just need the hex-file of the program and a short program to generate the correct data stream, which will consist of some preamble bytes to put the processor into programming mode, an erase instruction (optional. You can just rewrite it without erasing), a PAGE write instruction with the correct address taken from the HEX file, and the subsequent characters from the HEX file related to that page converted to four-symbols-per-byte and transmitted through the serial port.

Each byte to the AT89LP4052 has a prefix to let the chip controller know that it’s supposed to be listening. For other chips in the series, it’s usually AA55, which is actually a common bootstrap code dating back to floppy and hard disks, but in the case of this processor, they shortened it to just AA.

That’s at the start of the programming command summary (see table) so we want to “Program Enable” the chip.


Note, after each command, we want a pause before sending the next command, because that will cause the SS signal to go high, completing the command.

Then we want to Chip Erase.


Then we want to program the first page, or even individual bytes since this processor supports it, with the program string. It starts with “AA50” for “Write Code Pages”... or bytes.

The first line of the HEX file from the assembler is;


That translates to (in order of the bytes)

Byte Count: 06 bytes
Low Address - 0000 ( Origin ) 
Record Type - 00H (Data to program)
Data - six bytes 020080020034
Checksum 42

Converted to a programming string we want to write the following then:

AA50 0000 020080020034

Our program should ask the user to press and hold the RESET button on the programmer now, and then transfer the file to the bootstrap programmer. Having a pause here or waiting for a keypress first is a good idea.

Each line of the hex file is read in and transferred this way, until the entire file is transmitted. There’s an included HEX file, a pre-prepared download file and a file transfer program included with the downloads for those who want to just skip this step.

So a simple program to transfer this is all that is required. When you get the record type of 01, that means you’ve read in all the code, and it’s time to leave the programming mode and send a message to the screen to release the reset button.

If you want to know more about the INTEL HEX FILE FORMAT, there’s a great article on Wikipedia here that explains it in more detail:

At this point, if you’ve written the bootstrap program correctly, the program should fire up and start sending the data from the hex-file to the RS232 interface. Because there’s an LED attached to the Slave Select line, if it’s working you should see this pulse very dimly.

Once the programming is finished, release the reset button and the SPI bridge should respond with the following message;

SPIEL Online - CC-BY-SA 2017 V1.01.11 David Kitson - ? For help...

Pressing the ? key should then bring up the interactive menu straight from the microcontroller itself, which will then display;

SPI Encapsulation Link (SPIEL) Help Page. Dated 03/07/2019.
V = Activate SPI, W = Deactivate SPI
S = Send bytes to buffer in HEX, non-hex key except SPACE ends. +-Accepted
X = TRANSFER Command in buffer via SPI, #-received=TRANFERED.
  Example S010203-LX---O = Send 0x010203 with SS low.
R = Retrieve buffer contents, preceded with =
? = This Menu
M = show RAM page contents - Increments each time pressed - for debug
Z = Echo CRLF, ~ = Comment
Q = Current settings: Lsb/Msb Neg/Pos 1st/2nd-phase /Divider :
  To change default SPI config use;
  <=Neg-Clock(STD), >=Pos-Clock , Phase-edge &=1st *=2nd
  Clock Speed !=/4 @=/8 #=/32 $=/64 - Bit Order %=LSB-first ^=MSB-first
Control Lines High/Low - P0=T/G P1=Y/H P2=U/J P3(RST)=I/K P4(SS)=O/L
Recommended pinouts
  MOSI  |**|  VCC
  SS    |**|  P0.0
  RST  |**|  P0.1
  SCK  |**|  P0.2
  MISO  |**|  GND

If you get this far, then everything was a success, and you can now disconnect the three jumpers in the middle of the board and start using the SPI bridge.

Once you have gotten this far, you can also download the 8051 assembler from Microchip if you like, and begin writing in 8051 assembly, generating your own HEX files to upload. Otherwise, you can wait for the next month’s article, and use this 8051 based microcontroller to control SPI devices directly from your PC, such as displays and sensor chips.


Once the circuit is complete, you'll need to generate the symbol stream from the PC serial port to make the SPI bootstrap circuit work.

The supplied basic program creates binary strings of the code it wants to send to the MCU via the board's SPI circuits. Once a string is complete, along with any preamble and postamble, it is read a character at a time and through some basic mathematics is converted to a series of bits. These bits are then broken into four groups of two-bits, which are then used to create a string of four symbols for every byte in the original string, which is sent then as a single string to the serial port.

The diagram shows the sequence for “Program Enable”, which can be found on Page 58 of the Atmel Datasheet if you download it from Microchip, and is AAAC53.

You can download a quick example from the website which has been written FREEBASIC. Freebasic is a compiled basic language which is easy to use and is open source and royalty-free. You can download Freebasic from

There’s no error handling here and it’s not very user friendly, but it includes the encoding section, capability to program from a normal intel HEX file, a small terminal for confirming programming (or using the SPIEL program, which is the next project) or just running a debugging waveform which generated the signals in this article. If you want a C++ version, then you probably already know enough to write one from scratch. Feel free to ask for extra details on the DIYODE forum if you want to write your own.


The code is available for download from the resources section of the DIYODE website. Please forgive the rough coding (David is an assembly programmer, not a high level one).

The program starts asking for the COM port that you’re using. If you’re not sure, use Device Manager and look at the COM ports it shows as active - it will be one of these. Then it asks if you want to send input.hex or another file - you can hit enter here. Finally, it asks whether to bootstrap (program) with the B key, go into terminal mode, or run the debug signal routine which just keeps on sending serial data to give the correct waveforms on the circuit for debugging. If you bootstrap, it will go straight to terminal mode when you’re done and will show the initialisation of the MCU if it has been programmed correctly. It also prompts you when to press and hold the reset button, and when to release it once again. There’s an option to send a serial text file to the serial port also in there.

This program reads in each line of HEX data, then repackages it to include programming prefixes, and finally sends it to the output subroutine. This encodes each byte as four symbols and sends them to the serial port in a single burst so that the SS signal is generated correctly. We wouldn’t recommend typing it in - it’s included so you can see how it works - but it’s better to download the source from DIYODE and compile it yourself.

After bootstrapping, the program will enter terminal mode. If you’re greeted with the SPIEL start message, then the programming worked, and you can read about the Phase 2 (next month’s) project which can access SPI chips directly, and program displays straight from the serial port. Once the programming of the 8051 type MCU has been completed, remove the three jumpers from the board to separate the bootstrap SPI circuit from the MCU SPI circuit.

CLOSE IMAGE OF TIMING: Showing the bit positions in the asynchronous data stream relative to the clock signal.

"PROGRAM ENABLE": The "Program Enable" word being sent to the MCU via the SPI, showing the asynchronous symbols used for the encoding.

SPI DECODING: The same stream as in (2), but with SPI decoding turned on, to verify the symbols being converted back to the original data in SPI.

THE COMPLETE SEQUENCE: The complete programming sequence for the MCU, showing RESET, multiple Slave Selects, Clock and MOSI.

It is important to remember to remove the three jumpers before you try using the microcontroller to control the SPI port, or run any code driving the outputs of the microcontroller by making it active, as the MOSI pin and RxD pin are still shorted via one of these jumpers and you will lose connection to the microcontroller if you try. It won’t hurt anything, it’s just annoying. Also, remember while programming that the bootstrap works at 9600 baud while the MCU SPI interface works at 115200 baud.

As an additional benefit to debugging and understanding the flow of symbols to data, I have included the logic analyser images. The full timing operation can be seen in the logic analyser diagrams.

When assembled in a stream, these RS232 symbols can send SPI programming data, such as this “Initialise Chip for Programming” sequence for the AT89LP4052, which contains three SPI bytes, but is sent via twelve serial-port symbols. Finally, the entire sequence of programming 2K of AT89LP2052 processor with 100 millisecond programming intervals can be seen and decoded. The Logic Analyser, in this case, is a simple $33 logic analyser. It can be used to confirm that the BASIC bootstrap programmer produces accurate and correct SPI waveforms.

At this point, you should have a working SPI Encapsulation Link board. Next month, we'll add a Nokia 5110 display, which we’ll program, and show you how to generate a display from a BASIC program, or from a terminal application just by sending serial scripts. We’ll also talk to some other SPI chips and we’ll show you how easy it is to work out the correct way to talk to SPI devices from the datasheets.

AT89LP Series Microcontrollers

The AT89LP series of processor are a 20 MIPS MCU that can be commonly found in packages as small as 14 pin DIP.

These have larger pins, making them suitable for breadboard construction and home projects where size and weight are an issue, but breadboard or prototype board is being used. Being SPI programmable, it is possible to solder them into an application and then design their operational code on the bench while they are installed and operational.

They are ideal for hobby projects such as Radio Control Translation (eg, SBUS or IBUS to PWM or PCM ) as well as applications that require a small, easily soldered chip. The AT89 Series can operate with 3.3V or 5V, and is capable of generating its own clock and reset, requiring no external circuitry.


We have essentially built a programmer so that we can build a better programmer. To be fair, each has its own significant differences, and while the bootstrap programmer is only intended to program the MCU, the circuit has value outside of that. The NAND based programmer is slow (2400 baud) and is fixed with polarity, edge and clock functions, but it’s not limited in the number of bits it can send, so it could be used to program displays in 3-wire mode, though I wouldn’t recommend it, since the encapsulation link is about 50 times faster.

It could be modified to read SPI data too, or to handle JTAG and other requirements. It’s a fairly versatile circuit, but it’s limited in that it requires special symbols to activate it. It really is only intended for solving the chicken-and-egg problem of needing a programmer to build a programmer.

However, at this point, you have a basic SPI programmer that you can always include in other circuits as well, if it’s ever needed. This simple circuit as built also provides a great way to program and talk to an 8051 microcontroller if you want to learn more about writing embedded applications in assembly language.

Assembly language is often considered outdated, but for embedded projects, it’s far more robust and versatile than high level languages, and the CISC architecture of the 89 series not only runs at about twice the speed of RISC architectures, but also the nature of assembly often gives the same advantage over high level software that generates RISC code. These 89 series chips can run at up to 20 MIPS native, so compare well to a RISC chip running at 80 MHz. They are small, cheap and reliable having proven themselves in industrial applications for nearly 40 years.

Building this circuit is not just a fun and educational project - It’s a useful and practical one, and if you want to get into programming CISC architectures for embedded designs, this simple circuit may prove to be one of the most useful ones you ever make.

We look forward to showing you more about the 8051 architecture and the SPI interface standard in David's next project.


David Kitson

David Kitson

Electronics Engineer, specialising in circuits and interest in night vision technology.