Skip to content

ZX Raspberry Version 2

In which our hero downsizes radically

A couple of months ago we held the first in the ‘regeneration’ of the Milton Keynes Raspberry Jam. I took along my ZX Raspberry for all to see and wonder over. One eager and Sinclair-experienced attendee soon put me in my place. “Shame it’s so laggy”, he said. Ah. A brief defence of the necessary compromises in design ensued but I had to admit he was right, it was laggy; too laggy to be of any real use if you finally want that Jetpac high-score.

A couple of weeks later, in one of those classic ‘shower’ moments, I realised that the build was vastly overcomplicated. Recent Raspberry Pis have more than enough GPIO inputs for the ZX Spectrum’s keyboard matrix (13) and my experiences with the Atarpi project had shown me that handling keyboard inputs in Raspian had come a long way.

So here’s the original ZX Raspberry:

And here’s our version 2:

Keep it simple, right? This version takes all the keyboard lines direct to the GPIO (with a switch for handling keyboard modes) and uses a Python script to scan the keyboard for presses which uses the python-uinput module to inject those keypresses into the kernel. Did I think Python would work? Not for a second. It did. Brilliantly. The new ZX Raspberry v2 is significantly more responsive and the Raspberry Pi Zero W has plenty of horsepower to run everything.

I also decided to move to RetroPie as the OS for this project as it is just so good and refined. Setup was a breeze and Fuse works perfectly. I’ve finally got rid of that dratted mouse pointer too. As a bonus, the bluetooth capabilities of the Zero W mean I could pair a PS3 controller and use it as a Kempston joystick. Again, never expected it to work. Again, worked perfectly.

My ZX Raspberry v2 made its debut at the second Milton Keynes Raspberry Jam last weekend. There were no complaints*.

* Ok, one. “Have you got Chuckie Egg?” “Does this look like a BBC to you?”

UPDATE: After many requests, I’ve made the Python keyboard scanning script available on Github along with some notes to get you started.

Published inMakesRaspberry PiVintage Tech


  1. Great stuff! I’ve just ordered a replica case from Retro Radionics with the idea of doing the keyboard mod and maybe the Pi later but the cleanness of this has changed my mind.

    I have an original Model B and original Zero gathering dust. I guess there’s enough Pins on the Model B for this but the Zero could potentially be switched into gadget mode and be a USB keyboard in addition.

  2. Jozef Gallik Jozef Gallik

    Hello, great work!
    I had an idea to make just simple keyboard version for PC with emulator from my old Didaktik Gama (Czechoslovakian Spectrum clone) and found your page. After seeing you using Raspberry Pi for the complete standalone HW/SW emulator, I followed your path and seized your knowledge with version 2 (Raspberry Pi only and Retropie) 🙂
    Now, the job is done, waiting just for some additional extension cables and fan to finish the back design of the keyboard nicely with all connectors and ventilation.

    I would like to report just couple hickups to you:

    1. the libsuinput library didn’t install on my system based on your guide for some reason and as I am not very skilled with linux, fortunately I have found help on the library home site as alternative way descibed below:
    git clone
    cd libsuinput
    make install

    2. The Raspberry Pi is overheating, so I checked and it seems that the Python running is getting 100% of CPU, while Fuse only something around 20% – not sure how the CPU is running on 120%, expecting that each core has it’s own 100%.. Anyway, is there some way how to make the script use some kind of interruptions or so, so that it’s not taking that much CPU, please?

    3. Not sure if it’s possible, or it’s more of an OS issue, but the ZX keyboard is not usable in linux CLI where each keypress generates at least 3-10 characters typed instead of making a delay after first character written after keypress. Also, we cannot use backspace (shift+0) and we have no other alternative on ZX keyboard. I will try to check and maybe update the script myself, but as I never worked in Python, it will take some time and maybe you have already tried..

    4. Not anything wrong with your guide, just reporting that Didaktics have same type of keyboard as original Spectrum, just the order of pins is different, so I had to connect the 8 pin part of cable pin by pin, each time testing the keys captured. Nothing too difficult.

    That’s all I can remember just now from top of my head. Anyway, great thanks for your guide here, it saves me huge amount of time and also made me ending up with even more enhanced version of the system comparing to what I was about to build first, based only on Arduino board.


    • PJ PJ

      Hi Jozef,

      Interesting stuff. I haven’t had the CPU problem, nor have I had the cli ‘repeat’ issues you report. try adding some time.sleep(10) after a keypress detection to ‘de-bounce’ it. I’ll have a think about it and report any insights here.

      • Jozef Gallik Jozef Gallik

        Hi PJ,
        yes, that is what I did and it helped me to reduce the repetitive key presses together with the CPU load – from 100% to 1.5% with time.sleep(.05).
        Currently tried to control the fan within the same script, but not successful yet. I am used to debug things, but not sure how to do that with python, especially when it starts after boot.. I think I will need to stop that first and run normally..

        • Keith Coles Keith Coles

          Could you give some guidance of where to put this command? I’m having the same issue.

          • Keith Keith

            No worries chaps I have worked out a solution. Entering the stop as follows:
            (The #entered by keef and the line below are what I entered)
            # Set high
            wiringpi.digitalWrite(addressLines[addressLine], 1)

            #entered by keef

            except KeyboardInterrupt:

            This removed my 100% CPU load and it now sits at a respectable 3% on a pi zero.

            Could I be cheeky enough to suggest that it is entered into the GitHub script?



          • PJ PJ

            Absolutely, I’ll do that. There’s been some activity on this project that I’ll be announcing in the very near future.

          • PJ PJ

            I’ve now added this to the github repository (along with some other long-overdue tidy-ups)

          • Keith Keith

            Finally got round to looking at your edits / long overdue tidyups 🙂 Noted that you swapped the timings for the short press and long press. I have implemented that on mine. Didn’t want to totally replace the code as on mine I had edited quite a bit (Like adding other keys to the alternative key list like full stop, comma, other function keys, etc.

            I continue to be impressed with the elegance of it 🙂

            Many thanks,


  3. Dean Woodyatt Dean Woodyatt

    Thankyou so much for this article. I’ve knocked up a PCB for this and would love to send you one over free for you to play with. let me know where to send it to. The PCB is partially tested and now working for the keyboard matrix bit, just slowly figuring out the emulator side of things. happy to send some pics,

    Oh, and recently spotted the Magpi article, congrats!,

    • PJ PJ

      Hi Dean. Thanks, it was great to be featured! Would love to see the pics. Email me at

  4. Dan Dan

    Hi PJ! I’m trying to turn an old timex Sinclair into a similar device, the keyboard matrix is the same. I was going to use your original tutorial, but this way seems easier.

    I’m getting thrown off by the pin assignments on the github, think you could explain it to me? I’ve used matrix keypads, but never a keyboard before, in my previous experience you just wire the matrix to GPIOs one set as outputs the others as input. Maybe something is different about this keyboard? Why does it have a 3.3v line in? Why does it have 2 ground connections? Is there a reason you didn’t just use all the generic GPIO pins?

    17 <–this is the 3.3v line? why are we connecting to that. – KB1 / 1
    27 <–isn't this a reserved pin for ID_SC? – KB1 / 2
    22 <—GPIO25 makes sense – KB1 / 3
    18 <—-GPIO24 makes sense – KB1 / 4
    23 <—GPIO11, but this is the SPI_CLK pin, which i need for something else. can I reassign?- KB1 / 5

    5 GPIO3 but also the I2C SCL pin – KB2 / 1
    6 GND pin? why? – KB2 / 2
    13 GPIO 2 – KB2 / 3
    19 GPIO12 (but also an SPI pin)- KB2 / 4
    26 GPIO26 – KB2 / 5
    16 GPIO4 – KB2 / 6
    20 Ground again? – KB2 / 7
    21 GPIO13 (but also another SPI pin) – KB2 / 8

    • PJ PJ

      All the pins stated are GPIOn. So, 17 == GPIO17, i.e. They are the Broadcom numbers. Apologies if that was unclear! I’ll update the Readme.

      • Dan Dan

        Doh! So Obvious , I was over thinking it! Can’t wait to try this out. Thanks for the info!

  5. Keith Keith

    Hi. Thanks for this. I now have my Pi speccy fully built and working. Started out with the guide published in Magpi magazine but wish I had come here instead.

    Anyone here that used the Magpie guide and has ended up here in desperation a few observations.

    The Magpie instructions are broke. Use the one in the github link above.

    If you get an error when creating the install file of the scanner run sudo apt-get install autoreconf as this was missing from my Jessie build (Not Magpi’s fault so may be worth putting above).

    The Magpi connection guide is different. (I had connected mine up before installing the software). However although the keyboard works fine with the layout from the Magpi guide the switch does not. This needed moving from GPIO21 to GPIO12. After this the switch acted as it should.

    Took me a few hours to get round these issues so thought I had better share.

    Off to play my beloved Ultimate games now 🙂

    Thanks again. Keith.

    • Keith Keith

      Apologies the install for the failing build should have been sudo apt-get install dh-autoreconf.

      Not sudo apt-get install autoreconf

      • PJ PJ

        Yes, it looks like a section of instructions went missing in the MagPi article at some point. Glad you got things sorted out. A Version 3 is in the works!

        • Keith Keith

          Luckily I used molex connectors on my leads. They are a bitch to crimp but save on issues when you have to move the connections around on the PI. There is enough voidspace in the top section of the speccy 48 case for a pi zero with GPIO pins with the molex connectors on the top. This saved on desoldering to move the switch from 21 to 12. I would recommend it to anyone who is poor at soldering (My age has been derogatory to my eyesight and my soldering skills have taken a hit. I used to be able to solder a gnats proboscis to an ants antenna but alas no more.)

  6. Ales Ales

    Marvellous job. Can i change back from “MagPi Article Mappings” to “Original Mappings” Or i have to change anything else?


    • PJ PJ

      Please feel free to use whichever mappings you wish. The latest version on Github has both, just comment out the ones you don’t want.

  7. Ales Ales

    Wonderful. But I have a problem. The keyboard works only in the test. What kind of suggestion, where did I make a mistake?

    • PJ PJ

      The script needs to be running *all the time* in the background for this to work. Follow the steps on to set the script up as a service so it runs on boot. Then the keyboard will work all the time.

      • Ales Ales

        I’m stupid. I forgot what folder I have
        Not this:
        /usr/bin/python /home/pi/
        But this
        /usr/bin/python /home/pi/zxscanner/

        Now it’s working 🙂

        Thank you very much PJ

  8. ElShiftos ElShiftos

    Hi all and thanks for this, PJ!

    Despite following the instructions to the letter (a few times), I haven’t been able to get the script to output any characters. ‘Sudo modprobe uinput’ runs without error, and ‘sudo python’ starts and says ‘running’, and displays characters entered on a USB keayboard I have connected.

    I am installing this in Jessie, and didn’t see any error messages at any stage of the install. I have set the .py file to ‘original mappings.’ Instead of wiring the keyboard at this stage I am using a jumper wire to short rows and columns, one at a time, as per the following:

    17 – KB1 / 1
    27 – KB1 / 2
    22 – KB1 / 3
    18 – KB1 / 4
    23 – KB1 / 5


    5 – KB2 / 1
    6 – KB2 / 2
    13 – KB2 / 3
    19 – KB2 / 4
    26 – KB2 / 5
    16 – KB2 / 6
    20 – KB2 / 7
    21 – KB2 / 8

    One question: When I run ‘sudo modprobe uinput’, does it start process that can be shown by running ‘ps -aux |grep uinput’?

    Any help with this would be much appreciated

    • ElShiftos ElShiftos

      Please ignore my previous post as it decided to start working. I don’t know what I did but it may have been fixed by an ‘apt update/upgrade’!

      • PJ PJ

        That’s great news! Well done on getting it working. I’m tempted to look at 9-pin joystick over GPIO. I think there are enough lines left over. If we used some characters not present on the Speccy keyboard we could configure Fuse to use them for input. i.e. [ ] { } | = U D L R F .

  9. ElShiftos ElShiftos

    This is great. I couldn’t have proceeded with my Pi-in-a-speccy-case project without your coding talents!

    For the next revision, can I offer a suggestion to include a 9-pin joystick port using GPIO pins? I’ve made a hack using the board from and old USB joystick, but it’s not elegant and takes up valuable space in the speccy case.

    For me, the biggest hurdle with both Fuse and USP is that they use the left analog stick as directional input, which seems illogical and should really be the D-pad.


  10. ElShiftos ElShiftos

    Some further thoughts and observations now that my pi-in-a-speccy is nearing completion! 🙂

    mpg123 needs to be installed for the ‘ding’ sounds to work when pressing the mode switch. I made some custom sounds using an online speech synthesiser 🙂

    The ‘save snapshot’ function in Fuse requires the TAB key to enter a name for the snapshot. I’m not a coder, but even I found it rather easy to modify the .py file to implement this.

    Regarding the joystick idea….
    I don’t think a GPIO joystick will work in Fuse without modifying the source (sdljoystick.c?). Fuse only allows mapping of alpha-numeric keys, not special characters.
    Another option might be to emulate the left analog stick of a real joystick, either in code on the Pi or an external device such as a Pro Micro.

    • ElShiftos ElShiftos

      Tinkerboy’s gamepad code for the Pro Micro might be a solution to the joystick issue in Fuse. I’ve got as far as modifying it to prove that switches can provide joystick movement data, but that’s as far as I go with my limited programming knowledge 🙁

      Tell me if I’m OT here!

  11. Pomme Pomme

    I have just finished to upgrade from your first version with the arduino to this one. The result is nice: keys are now responding perfectly 🙂
    I just changed the mapping of the Gpio because I switched the lines on KB2,
    I still use Pipaos with Fuse auto-booting (but with the mouse cursor), but I find that booting the Pi to have a “@ 1982 Sinclair Research Ltd” when linux starts is fun. And fuse with a linescan option give a great picture.
    Thank you !

    • PJ PJ

      The latest version of FUSE-sdl (you’ll need to compile from source) removes the cursor!

      • Pomme Pomme

        I will try, thanks 🙂 I already compiled the previous version so it should be ok.

        • Pomme Pomme

          I installed fuse 1.56, and no mouse cursor anymore 🙂

          On the pi zero, I needed to add some swap to compile with no error, something like this:
          dd if=/dev/zero of=/mnt/sda1/swap.file bs=1M count=1024
          chmod 600 /mnt/sda1/swap.file
          mkswap /mnt/sda1/swap.file
          swapon /mnt/sda1/swap.file

          And I forgot to use the “–with-sdl” flag on the ./configure step the first time (and the binary change from “fuse-sdl” to “fuse” in the .profile).

          Now the speccy is perfect with piapos !

  12. ElShiftos ElShiftos

    Can I ask which versions of PipaOS and Fuse you guys are using?

    I’m still running Raspbian Jessie and Fuse 1.1.1 because it’s the only combination I could get to work. It would be nice to have something that boots quicker because Raspbian is rather slow on a Pi zero.


    • PJ PJ

      PipaOS was Stretch I think, and Fuse 1.5.2 built from source

  13. ElShiftos ElShiftos

    Using PipaOS Strectch, Fuse 1.5.2, and having installed all required dependencies, I have hit a brick wall with this message: checking for SDL – version >= 1.2.4… no
    I have 1.2.15, and according to, that IS the last version before libsdl2.

    I appreciate this might be OT, but I don’t who else to ask, other than those that have made it work!

    • PJ PJ

      1.2.15 should be fine. I’m guessing it can’t find it? From my notes (assuming you have the source files):

      # Dependancies
      sudo apt install build-essentials libglib2.0-dev automake libsdl1.2-dev bison flex mp123
      sudo ldconfig

      # Build libspectrum & fuse
      cd ~/zxraspberry3/libspectrum-1.4.1/
      automake –add-missing
      sudo make install

      cd ~/zxraspberry3/fuse-1.5.2/
      automake –add-missing
      ./configure –with-sdl –without-gtk –without-gpm
      sudo make install

  14. ElShiftos ElShiftos

    Thanks for the reply PJ.

    Following your notes above, I was able to compile and make fuse without errors, however, when I run fuse, all I get is a blank screen. It must be running to some degree because I am able to exit back to the command line with F10 and Enter.

    This is exactly the same issue I encountered when installing the pre-compiled fuse (v1.3.4 iirc) from the apt repository in Raspbian sctretch.

    Weird huh?!

    • PJ PJ

      I had that a lot, and it came down to console resolution. Only certain ones worked.

  15. ElShiftos ElShiftos

    I just went through a load of group/mode options on both a tv and a monitor, and guess what? Blank screen every time! 🙁

  16. ElShiftos ElShiftos

    Giving a little back here….
    A Pro Micro, plus the ‘Examples\joystick\Gamepad Example’ code included with the IDE = a quick and easy way to interface a 9-pin joystick to fuse.

    • PJ PJ

      NICE! Once Eletromagnetic Field is over, I may well look at a new version and document the whole thing.

Leave a Reply

Your email address will not be published. Required fields are marked *