Category Archives: Pi Spectrum

Now that the keyboard is fully converted to USB and working, the top half of the Spectrum is finished. Everything else (our computer) goes in the bottom. In this post, I’ll talk about installing the Raspberry Pi and by the end we will have the finished article! The bits you will need for this part of the project are:

Your Speccy’s lower casing

Raspberry Pi (I used a model-B) with SD card and OS installed

Type-A male to female USB extension cable (the shorter and more flexible the better)

The USB-Speccy Keyboard (top half) at the end, along with the casing screws

Before we begin, it’s good to know your Pi is in working order with an OS of your choice installed. If it’s your first time with a Pi, stop here and play with it first, ensuring it is desktop-ready and you know how to use it. If you want something that requires minimal setup I recommend buying a starter pack, which has the operating system pre-installed on an SD card for you. Please also enable the VGA now if you are using a HDMI to VGA adapter. A tutorial on how to do it can be found here.

Preparing the Pi

If you too have a model-B Pi, the first thing you’ll notice is that it doesn’t fit inside the Spectrum; the stacked USB sockets and Ethernet port are too tall to fit inside the casing. The best way to remove these is with an airgun. I also removed my audio and composite ports so that I could put the Pi wherever best suited me. With all except my audio port removed, my Pi looked like this:

Raspberry Pi with Ethernet, USB and Composite ports removed

We’ll talk about reusing some of the ports later. The plug-in parts are your Micro-B USB extension for power, SD card with the OS and the HDMI cable / HDMI to VGA if you are using one of those. Have these plugged in when you do any placements of components inside the case; you want to make sure that these all go to where they need to be before you fix anything down.

The first thing to do is restore USB capability, using your USB hub. Snip your USB plug off the hub wire, leaving as much wire on the hub as possible, and strip the four wires so you can solder them. You may also want to tin the wires’ tips. Remove the hub casing. You will likely get more wire and the USB ports will sit lower in the case. Now you need to solder the hub’s USB wire directly into the USB socket connectors on the Pi. I’ve colour-coded the holes for you below.

Holes for soldering new USB connections to the Rapsberry Pi, with colour-coding

If you wish to install a second internal hub (though room is very tight), you can repeat the same colour sequence with the empty row in front of the one indicated. You can now place your USB hub (and Pi) inside the case. The expansion card slot at the back of the Spectrum is the ideal place to put larger ports such as your USB hub. Hopefully, two of the ports face internally and two externally. One of the internal ports is for the keyboard and the other for your wireless dongle, so you can have Wi-Fi built in.

Adding components

Now is the time to prepare your video output. The model-B comes with a composite out and a mini HDMI connection. HDMI cables tend to be bulky and inflexible so I didn’t want a HDMI extension inside my Speccy; instead I opted for a VGA adapter. As with the USB hub, it was necessary to strip away the casing to fit it into a tighter space. Again, have this plugged in when you make the final placement of the Pi. You can see how I arranged my USB and VGA ports below.

USB and VGA ports placed in the expansion bay of the ZX Spectrum’s lower casing

If like me you want the keep the power socket in the original power socket’s place, also take care that any ports you place in the expansion bay leave sufficient room for your USB Micro-B extension on the right-hand side.

This is good time to reconnect audio and composite ports. Solder long wires to the composite and audio connectors. Now you can place them on the appropriate holes at the back and judge how long the wires will need to be, as shown below.

Reconnecting the external ports to the Raspberry Pi

Still leaving more length than you require, strip and tin the wires, then solder them to the Pi, carefully matching each connection to where it originally went.

Fixing all the components

Lay everything down one last time and ensure everything fits in place, adjusting any cables that may be bent into a springy position that is likely to pop out or dislodge something. Also make a final check of how your top half fits on to your bottom half to ensure your Arduino fits and the membranes won’t be damaged. If you’re happy with how it all goes in, you can now glue everything down. I used a glue gun for this – be excessive with your ports because they are going to get wiggled and may come away. I found that type-A USB heads made the perfect spacers to raise my power, composite and audio sockets at the back, lining them up nicely with the holes.

I also glued my internal cables down, but left the Pi unglued. It is effectively suspended by all the cabling attached to it, so it places no pressure on the board’s sockets. You could glue sponges underneath and overhead to cushion it if you wish, but ensure you’re not putting the sponges where the pi will get hot!!!

Here is my project with all the components in place.

Raspberry Pi integrated into a ZX Spectrum with working USB-Spectrum keyboard

The final thing before you put the casing back together is to use your type-A USB extension cable. If you have the spare wire and a male and female USB type-A connector, you can easily make a tiny extension cable. I used 5cm sections of single-core wire. Ensure the connectors are the same way up and join the connectors as shown below. This will be very compact and bend according to the positions of the hub and Arduino, so it is ideal for minimising physical stress on the components.

Diagram for a USB extension cable (type-A)

Plug one end into your USB hub on the bottom, using an internal port. Then plug the other end into the Leonardo or LeoStick on the top. That’s it – that’s your ZX Spectrum’s keyboard connected to the Raspberry Pi. Nice and easy to put together, or take apart again if you need to.

You can now place the two halves together (careful not to squish anything – especially your membrane ribbons), and pop the screws back in. Congratulations on your Speccy-Pi with working USB-Spectrum keyboard! I hope you’ve enjoyed this project as much as I did.

In a previous post, I walked you through building the hardware bits for plugging your ZX Spectrum keyboard into the Arduino. If you aren’t familiar with the post you can find it here. In this post, I’ll run through matrices and how the driver is written using the Arduino IDE. If your are a confident coder and want to skip this, you can get a copy of the complete code on the resources page.

The key information for writing the program that we gathered in the making of the hardware interface were:

The film with 5 contacts has the Data lines

The Data lines use pinsA0-A4 and have pull-up resistors to +5V

The film with 8 contacts has the Address lines and uses digital pins 2-9

The Keyboard is arranged in a 5×8 matrix (Data x Address)

How a keyboard matrix works

A keyboard matrix is a grid of wires, such as the Address and Data lines forming the 5×8 grid in the Spectrum. Each Key is a button that intersects one row with one column (the crosses on the grid) and all the buttons are physically held open by default. This means that the rows and columns are not connected and no current (or voltage) is passed from a row to a column or vice versa.There are two types of matrix, pull-up and pull-down. You can find out more about the operational differences here.

The original Spectrum keyboard used a pull-up configuration and we know that the Arduino can stand multiple button presses in that scenario, so that’s the one we’ll use. The thing to remember is that on is low in our matrix, not high. So when a key is pressed it is a low voltage that we need to trigger and then look for. Below is how the matrix actually works:

A 4×4 pull-up keyboard matrix showing the sequence of detecting a button press

In the above images, the button connecting the second column to the second row is pressed. To start with, everything is held high. The first column is changed to low, and the controller checks the voltage at each row to see if there is a drop (first image). No buttons on that column are pressed so all rows stay at 5V. The first column returns high, and the second column is sent low (second image). The rows are sequentially checked again. The pressed button on the second row is connecting the +5V supply of the second row to the 0V of the second column via the resistor (third image). The controller detects the 0V on that row and knows that the second button of the second column is the letter ‘j’ so outputs a ‘j’ keystroke. The cycle then carries down the rows and along the columns, then repeats (fourth image).

In a nutshell, that’s how a matrix works. So, in practice all our keyboard driver has to do is perform the same cycle of lowering each column and sequentially checking the rows on that column for 0V. Then it can look-up which keystroke to output to the USB.

Writing the software

I’m providing the software driver here for you to look at as we run through putting it together. If you are new to coding for Arduino, have a blank sketch open and you can put the code together as we go. Here is the complete code for you to copy into a new sketch:

What this program will give us is the letters A-Z in upper and lower case, the numbers 0-9, a SPACE, BACKSPACE, CAPS-LOCK and RETURN. This covers the basics of what you’ll need to use the computer; believe me, with a tiny space button in the bottom corner, you wouldn’t want to do word processing on this keyboard. All our keys will be wired in and accounted for so if you do want to make every function on the keyboard work, you can add them into the program later.

Fiirst, change your Board to the Leonardo, or the LeoStick (the board profile and instructions for which can be found here). Go to Tools > Board and select the one you are using.

The integers ‘dataNo’ and ‘addressNo’ specify the numbers of rows and columns respectively. As such, the ‘KeyMap’ character array is 8 across by 5 down (matching our keyboard membrane connectors) and two deep for upper and lower case. The ‘dataPin’ and ‘address’ arrays match our soldered pin numbers and are used to easily setup and use the keyboard connections (or easily modify them without changing the functional code). The blank spaces at the bottom are the SPACE (A4, 2), RETURN (A4, 3), BACKSPACE (A3, 2) and CAPS-LOCK (A4, 4).

Note: This driver will work for any keyboard matrix. All you need to do for a different keyboard is set the size variables, pins and key map for your keyboard in the above code. The rest will work as is. If you are using a pull-down configuration, simply swap all the HIGHs and LOWs over, which we’ll come to soon.

Now we just need to declare a few more variables for our program logic. The boolean variable, ‘wasReleased’ will help to ensure that the keyboard outputs one keystroke per press, giving you ‘n’ instead of ‘nnnnnnnnnnnnnn’. Pop these in directly below the above code.

boolean wasReleased = true;
int reRelease = 0;
int capital = 0;

We can now move into the setup() section of the sketch. In this section we need to setup the pins and put them into a ready state if required, then initiate our keyboard function. Rather than specifying each pin individually, we can use for loops to save repetition, hence the above arrays, ‘dataPin’ and ‘address’ contain our pin numbers that we can refer to here. The first cycles through our digital pins (the address lines). These are the ones we set to HIGH or LOW, so we declare each as an output and set it to its default HIGH state.

Likewise, the second runs through the analog pins (our data lines) and declares each as an input.

for(int d=0; d<dataNo; d++)
{
pinMode(dataPin[d], INPUT);
}

Finally, we initiate the USB interface for use as an interface device.

Keyboard.begin();

That’s the end of our setup() section. We can now move on to the loop(), where the remainder of the code will reside. As we go, I’ll put ‘…’ where the next chunk of code will go. This will cycle the address lines and check the data lines, then output the appropriate keystroke. Basically, we will again use for loops with the following structure:

A for loop to cycle the address lines, which cycles the address line it is using LOW at the start and back to HIGH at the end:

While the address line is low, we need to run through the data lines to see if any of them are low, indicating a button press. So, where the ‘…’ is, we will use another for loop.

for(int tData=0; tData<dataNo; tData++)
{
...
}

We now need to read Each data line. A pressed button will send the data line LOW, which in binary is the integer 0 (and thus, HIGH would be a 1). As such, the integer ‘pressed’ is assigned the binary value of the data line. We can then test that value with the if() statement of ‘if(pressed == 0)’. The ‘reRelease’ integer is incremented to keep a count of how many data line checks are performed between button presses, enabling us to see if all the keys are released before allowing more keystrokes.

At this point we enter into a key press being detected. A keystroke should only be allowed once per button press (if it is the first for that button press), giving us ‘n’ and not ‘nnnnnnnnnnnnn’. Therefore, we test the boolean ‘wasReleased’ using another if() statement.

Whether or not we send a keystroke through the USB, we need to do some housekeeping here. The ‘Keyboard.releaseAll()’ method ensures that any keystrokes being sent to USB are discontinued. The ‘capital’ integer shifts places on the innermost position of the ‘keyMap’ array. As such, if it is being pressed for a second time to toggle off, it must be reset to the lowercase position of 0. Lastly, if a key press has been detected, the program needs to lock out of sending more keystrokes until all keys have been released. Consequently, the ‘reRelease’ count must be reset to 0 and our ‘wasReleased’ set to false.

Assuming, the current cycle is the first of this key press (so ‘wasReleased’ is true), we come to registering our keystroke to the USB.

Special characters, CAPS-LOCK, BACKSPACE and RETURN don’t fit into an array of characters and so must be handled individually. As such, each has an if() statement pointing to the specific combination of address and data for that key. The first line increments ‘capital’ to shift the case position when the CAPS-LOCK is used. The ‘else’ on the next line means that the CAPS-LOCK is CAPS-LOCK and not SHIFT; this matches the button label and greatly simplifies our key press logic. If the key press is a letter, number or space, the last line references the current data line, address line and capital state to select the appropriate letter from our key map.

Finally, the last thing that we must do is re-enable our keystrokes if all the keys have been released, so this chunk goes before the final ‘}’ at the end of the loop().

if (reRelease > (dataNo*addressNo))
{
wasReleased = true;
}

This simply checks that our ‘reRelease’ count is greater than the size of the ‘keyMap’ array (and so has got passed the key it detected last time). If so, it changes ‘wasReleased’ to true, re-enabling keystrokes to be sent to USB.

That’s the complete keyboard driver. As above, the complete and downloadable document version (with comments) can be found in this post or on the resources page. Please let me know if you have any questions about either this program or the physical interface covered in the earlier post here.

A keyboard matrix is a grid of wires interconnected by physical switches (buttons), such as the Address and Data lines forming the 5×8 grid in the Spectrum. Each Key is a button that intersects one row with one column (the crosses on the grid) and all the buttons are physically held open by default. This means that the rows and columns are not connected and no current (or voltage) is passed from a row to a column or vice versa.

When dealing with multiple connections that operate in parallel on a single circuit (such as keyboard matrices or an RGB LED), the convention is to have everything high by default and look for something going low as your triggered response. This is because if you have everything low and turn one thing high (left image below), current disperses and depending on your circuit can cause erroneous signalling and under-current issues. This can make controllers and sensitive components fault or reset. You can see below an example of how this might happen, if you pressed three buttons on a matrix:

Electrical matrices with multiple buttons pressed at once: signal-to-high on the left and signal-to-low on the right

In the left image you can see that all the lines are low (black). Because the resistors keep the rows at 0V by default, this is a pull-down configuration. A vertical line is held high to activate that column of buttons (+5V introduced) and three buttons are pressed simultaneously. Current is passed along two lines and two columns and is at best halved by the parallel resistors on the rows.

On the right you can see a pull-up configuration, because the resistors hold the rows high. When the vertical line is held low and the same three buttons are pressed; all that happens is that the rows all remain high, which in turn hold the second column high. Most microcontrollers (including Arduino) have over-current protection, so this shouldn’t cause any faults.

Either configuration has pros and cons and both are commonly used in button matrices. Since the second (pull-up) matrix is how the original Spectrum keyboard worked and we know the Arduino can stand multiple button presses in that scenario, that’s the one we’ll use.

In the last post, I extracted the Keyboard connections from the motherboard and removed the motherboard itself, leaving an empty case to work with.

Building the hardware interface

If you are reading this as instructional for your own project, please read the whole post before following with your own project, so that you don’t have to redo any work. I’m starting with my go-to hardware platform, the Arduino. In particular, the Arduino LeoStick has caught my eye for a while and has the USB connection on the PCB – no cable! That makes it perfect for a tight space. You can find all the information you need to get it going with your Arduino IDE at the LeoStick link provided. Alternatively, the Arduino Leonardo would work just as well and is supported by the Arduino IDE as standard.

To find out how the keyboard connections worked, I found this schematic (under the ‘Keyboard Scanning’ heading), which basically gives me the following pieces of information:

The film with 5 contacts has the Data lines

The Data lines have pull-up resistors to +5V

The film with 8 contacts has the Address lines

The Keyboard is arranged in a 5×8 matrix (Data x Address)

I’ll tackle how a matrix works in the next section as I cover writing the software, suffice it to say that the important thing now is that my data lines are individually held high. To diagrammatically represent the above information:

Connections for a ZX82 Spectrum as they appear on the motherboard, with corresponding Arduino pins

Wiring to the Arduino

I have included the pin order for you to connect the Arduino pins in the above diagram. I recommend soldering the wires and resistors first, then placing the PCBs down where you are going to have them (mine sit in the top recess of the lid). That way you can ensure that the connectors’ metal contacts are on the side of the membrane that has the exposed connections before you solder them. The placement of the connections needed to be flexible so as not to tug or stress the keyboard membrane. As such, I cut down two blank prototyping PCBs to be big enough to attach the keyboard connectors, plus my resistors and wires to the Arduino. Personally, 10KΩ resistors are always my go-to resistor, so that’s what I used. The wires, resistors and PCB board together only cost a few pounds and are fairly easy to work with. When you do this, leave your Arduino wires longer than you need. You can shorten them once you’ve sorted out the placements of everything.

My PCBs with connectors looked like this.

ZX82 Spectrum keyboard connections ready for Arduino

The resistors on the data PCB (right) all connect from the connector to the yellow 5V wire at the top of the PCB.

The address lines are the ones changed by the controller (our independent variable) and the data lines are the ones tested (our dependent variable). So, the address lines connect to the digital pins (marked with numbers 0-13) and the data lines are connected to the analog input pins (marked A0-A4) in the above sequence.

Here are the PCBs just placed in an Arduino Uno so that you can see what it looks like wired up. If you use the Leonardo, as you may be aware, the pin layouts for the Leonardo and Uno are the same, so you can copy this exactly.

ZX82 Spectrum keyboard connections wired to an Arduino Uno

You can see the data lines in green going to the A0-4 pins, the blue address lines going to the D2-9 pins and the yellow +5v wire going to a VCC connection. I used digital pins 2-9 rather than 0-7 because digital pins 0 and 1 are used for the serial connection (Tx and Rx) which will be used by the USB connection, so in your own, leave digital pins 0 and 1 unconnected(use pins 2-9). Once soldered to the LeoStick and laid into the lid, my Spectrum-USB Arduino keyboard adapter looked like this.

Arduino LeoStick connected to ZX Spectrum keyboard connectors

At this stage I tested my soldering by setting all the pin numbers (<pin>) to output:

pinMode(<pin>, OUTPUT);

and then setting them to +5V:

digitalWrite(<pin>, HIGH);

That way, I could run over all the keyboard connections in the connectors (and the +5V side of the resitors) with a multimeter and check each for +5V, ensuring good connections. Once happy, I fixed the PCBs in line with the membrane connections using a glue gun as shown in the image above. Once you’re really happy with the placement of the connections and they are really secure then you can carefully plug the membrane back in. Since the membrane is so delicate, I kept the films as sheltered and uncreased as possible by gently packing them into the more spacious top section of the upper case as shown below. The masking tape held them flat so as to minimise movement as the case is opened and closed.

ZX Spectrum membrane plugged into Arduino

In the next post, I’ll cover writing the software to make the keyboard output the button presses to USB.

The first thing to do is open the Spectrum up, to remove the bit I don’t need; yep, that whole computer is on one PCB. Fitting then that the Raspberry Pi has been so popular in replacing it. Anyway, I bought mine for £20.00 off eBay in maybe / maybe-not working condition and without power adapter. All I need is the case so it really didn’t matter whether it worked.

Undoing the screws on the bottom is all you need to open it up. You can see how the Keyboard connects to the motherboard / entire computer.

At this point I had no idea if the keyboard worked because the films crack really easily. When you open yours, handle with great care and pull the connections out (vertically upwards) from the board with delicacy and patience. If it breaks you can get replacement keyboard films here but you have to get the lid apart to put the new one in, which it tricky!

Harvesting parts

Once I removed the keyboard membrane from the connector ports the lid came away. A few more screws later and I had the empty case. I marked the bottom for now with masking tape so I could see where the ports roughly were.

The empty ZX82 with keyboard ports marked

Since the ribbons are flat metal strips on tape – not exactly a standard connection these days, I decided to keep the original connectors, so unsoldered them from the board. When you turn your motherboard over, they’re about the only connections that are laterally oriented, so they are easy to tell apart from the surrounding components.

Once removed I had:

A lower case

An upper case with keyboard membrane

Two keyboard connectors (note they are different lengths)

This is all you’ll need to harvest from your Spectrum. You can discard the motherboard as you wish. I’m saving mine for future projects. In the next post, I’ll talk about building the keyboard interface.

Project in a sentence: Build a Raspberry Pi Spectrum with working keyboard that’s easy for you to build too!

The Raspberry Pi plus a good old ZX Spectrum (affectionately, ‘the Speccy’) seem like the match made in heaven. The retro desktop UI of the Pi harks back to the days of simpler computing for which Sinclair’s Spectrum series, along with it’s entourage of clones, were so iconic. As I’m sure you have seen, there are plenty of projects out there for combining the two. One of my favourites is this insanely packed and beautifully crafted build named the Frankenspectrum.

The project

So far I’ve seen Pi-Speccys with working keyboards, Speccy Pi cases (no working keyboards) and Speccys turned into USB keyboards. They all use either a specialised PCB which is not to my taste or budget, or hack a USB keyboard to get the electrical inputs, then run software to remap the key the computer receives to the one you actually pressed. Personally, I like the idea of the keyboard working properly as a USB Keyboard that you can plug in and it goes, so I’m going to try to do just that and fit a Raspberry Pi in too. My budget is £100.

As we go, I’ll provide you with links for any resources you may need and share any code to make things work.