PS2 keyboard for ZX Spectrum (or clone)

ZX Spectrum and other computers of that period use proprietary keyboards with direct connection to some specific chip or connected directly to computer bus. Old keyboards are damaged from elementals or time, and sometimes are not very user friendly compared to standard ones. Goal of this project is to connect old and obsolete (!) PS/2 style keyboard to ANY old computer. This project is tested on ZX Spectrum CPLD clone, but mimics the original ZX 40 keys keyboard. Why not a USB keyboard? Because it limits to the narrower selection of MCU’s and USB HID is way more complex to implement.

This project consists of one easy part and one very rare part- CPLD. I think that maybe it is possible to directly connect without CPLD (or glue logic) with modern MCU, but my CPLD ZX spectrum uses “turbo mode” with 5MHz CPU clock and speed of keyboard scan is too fast for MCU pins.

How does it work? It is crazy multi conversion:

  1. Key press is connecting the matrix on the keyboard. Keyboard detects this and converts keypress to scan data. This data is transmitted serially to the PS/2 interface.
  2. MCU collects PS/2 data, decodes from scan code to ASCII.
  3. ASCII key codes with modificators are combined for extra key combinations and stored in the key buffer.
  4. The key buffer can hold up to 10 keystrokes (+modifiers). So multistroke is possible (especially for games). Multistroke is limited by keyboard hardware, not this project.
  5. All data is converted to a 40 bit key code matrix (8 columns, 5 rows) for the ZX computer.
  6. All 40 bits are shifted serially to CPLD at fast speed (2+ Mbit/s, depends on CPLD and connections) DMA SPI.
  7. CPLD decodes the bit stream and emulates keyboard hardware.

CPLD Hardware:
CPLD block diagram
Shiftreg is simple 40 bits shifting register to store SPI data, following with 40 bits latch register. This looks like five 74HC595 connected in serial. Last module is combinatory logic. It is written in Verilog:

module keyboard( keys, col, row);

input [39:0]keys;
input [7:0]col;
output [4:0]row;

assign row[4]=(col & keys[7:0]) !=0;
assign row[3]=(col & keys[15:8]) !=0;
assign row[2]=(col & keys[23:16]) !=0;
assign row[1]=(col & keys[31:24]) !=0;
assign row[0]=(col & keys[39:32]) !=0;



(my design uses inverted row/col. Depending on real hardware these buses may be inverted)

I am using a cheap STM32F103 MCU from China, Bluepill format (it can be a fake one, with smaller RAM/ROM size). All software is written using GCC and STM32CubeMX. All source code and compiled binaries are on the bottom of the page. PS/2 write is not implemented, now it just resets the keyboard on Esc key press. I have tested 3 keyboards and one has some strange bug- sometimes it starts translating some strange data if keys are pressed very fast or very long. Pressing Esc stops this chaos and inits keyboard interface.

Standard PS/2 keyboard has more keys than the ZX Spectrum, so some keys are redefined for more convenient usage: Like “;” and “:” pair- pressing dedicated key for semicolon and shift generates specific ZX spectrum keystroke. Same for “/?”, “=+”, “Backspace” and some other keys. Also, the numeric keypad is working too. “Caps lock” is working too, but LEDs are not used (because I do not implement PS/2 write properly and also, that it may not indicate real status of the computer). “Shitf”, “Alt” and “Control” are in use, but the logic is strange. And it is not my fault- it is Sinclair.

All source code and compiled binaries:
PS2 for ZX Spectrum source code, plain GCC for STM32F103.

Example Quartus project: Quartus archive. Will fit to EPM7128 or bigger chip.

Do not forget 5V/3V logic conversion. STM is not tolerating 5V logic very well.

Posted in FPGA, MCU | Leave a comment

Sinclair QL – modifications for EPROM

I have Sinclair QL, “issue 5” with 3 EPROM chips. One of the chips is riding on the other chip. And yes, it is the original solution from Sinclair engineers- they were pressed by Apple computers new product and they had to make it fast. This computer had some problems- the screen was filled with garbage and nothing was working. Looks like a RAM issue, but original firmware is not very good at diagnostics. It is very nice that there is a third party ROM for this computer and it is possible to download ROM image. This ROM image will not fit to single ROM in current configuration and it is quite crazy to piggyback ROM chips. This topic is also commercialized in retrocomputer world, but there is very simple fix.

First, I just placed a small PCB to test the computer and check RAM. The RAM was good, problems were in piggyback ROM.
big EPROM on Sinclair QL
(Some images are clickable)

Computer requests ROM’s chip select rising HIGH ROM_OEH. Typical EPROM chips use inverted CS/OE pin. So, I placed a 74HC00 chip to invert the signal. And one wire for the missing address pin.
Continue reading

Posted in Anything | Tagged , , | Leave a comment

Real easy Video fix for ZX Spectrum +2 (gray, “Toast Rack”)

I bought a ZX Spectrum +2 gray (toast rack) for my retrocomputer collection and it was the fail. The video output was bad and also there is a serious problem with RAM or ULA. But this article is about making perfect video output without fancy tuning. This article is a bit rude- I was searching the internets for more information and almost all data I found is copy paste of people without any deep analysis. Also, I found that about everything for this computer is deeply commercialized compared to Atari ones. Also, schematics and documentation are shitty.

So here is the starting PCB of ZX Spectrum +2, marked Amstrad 0500 ISS3 (Z70500):
ZX Spectrum +2 PCB 0500 ISS3 Z70500
(press on image for bigger)

Continue reading

Posted in Anything | Tagged , , , | Leave a comment

Printer from calculator, part 2

Continued from part 1.
The printer from the calculator is a neat toy, but we want a real USB printer. So, using my new STM32F103 CubeMX USB printer class for communication with the host computer and some tricky INT based software from me, I built a real working* printer. The asterix near working has meaning- there is a problem with printing one text combination and I don’t know how to change the color of the print and how to print first (rightmost) symbols.

STM32F103 USB printer device class citizen

All software is module based. One module is USB stack, one module is USB printer device class, one module is interface with real printer hardware. There is one trick with USB device software- the USB INT level must be lower than INT used for printer mechanics. Yes, the printer is interrupt driven and completely asynchronous from the main body loop.
My software and compiled binary is for a slightly bigger chip – STM32F103RET6 (512kB ROM, 64kB RAM), but it is usable with regular blue pill PCB (If China people put at least the same size chip as in real blue pill. I had some weird problems with alieexpres blue pill boards, so I build my “white pill” boards).

Warning, do not rebuild STM CubeMX project in source code. The Cube program will overwrite my printer class.
STM32F103RET6 USB printer device source code and binary – printing on Citizen CX-123II calculator printer.

It was fun, but I lost interest continuing this Citizen printer. It can print only numbers and there is no real documentation.

Posted in Anything, MCU | Tagged , , , , | Leave a comment

Printer from calculator, part 1

In a pile of e-waste I found a printing calculator, Citizen CX-123II. It is a regular calculator (with some wicky calculations), but with a printer- all output from the screen are hard-copied to paper roll. It can print only numbers and some special symbols. But it has two colors- red and white.

Citizen printing calculator Citizen CX-123II
The printer inside (printer module or body) is made by Espon, M-71T. But I didn’t find any documentation about this device. The only way to play with it is reverse engineering. There are only a few lines connecting the printer to the mainboard, so I hooked my logic analyzer and watched what was happening when printing.

logic analyzer output for Epson M-71 printer
The hardware inside the calculator (regarding printer) is very simple – two transistors and 3 lines directly going to MCU. Printing is “very intensive” job for a calculator’s MCU- even LCD images are switched off during printing. Mainly because the printer is asynchronous and MCU must wait for specific data on those 3 lines. Meanwhile output lines are very simple- just motor (PWM) power and single pulse for print. Depending on print pulse timing, different symbols are printed. And more, depending on the time used to hold the print command, new line and maybe color is selected. (I didn’t manage to decode how color is changed and how the first [leftmost] character is printed).

Epson printer to MCU
There are some tricks in this mechanical device, like it is impossible to print two nearby symbols on a rubber stamp (“1234..”) because mechanics are too slow, but there is no problem printing alternative patterns (“1357..”). So, when printing some numbers, the printer is printing slower and some numbers are printed at a remarkable speed.
The Printer is about a 5V device (~4V for motor, 5V for clutch), meanwhile the STM32F103 device I used is a 3V device. But using two mosfets from computer mainboards made good interface and level shifting. Input data from the rotor position encoder is used with MCU pullup- automagic 3V interface. This encoder is a mechanical switching device, there is very bouncy data from it. In my software, I used quite complicated debouncing software tricks. But all software stuff is in the next article.

Posted in MCU | Tagged | Leave a comment

ARM:0018 STM32CubeMX hack – printer class device

This article is about printer class device for STM32F103 and STM32CubeMX.
Somehow there is NO printer device class example in whole internet. There ar CDC or HID examples copied from same STM32CubeMX example with minimal explanation, few of mass storage device samples (without real usability), some audio device. But there is no PRINTER CLASS example at all. Looks like that everybody is using printers and nobody is designing printers. Meanwhile, printer is very simple device- it receives some data from host and reports few bytes of status data. So here is my project- printer class device for STM32F103 MCU. Project is based of canned CDC example, with light modifications. I don’t know how to make CubeMX templates. So if you rebuild project using Cube software, some of files will be overwritten, some added. Do not rebuild project using cube.

What my project can do:

  • Connects to host computer (Windows, Mac, Linux) and enumerates as printer class device.
  • Printer reports 1248 id string. If string is properly coded, host OS recognizes printer model. Example printer is “text only” – no drivers needed.
  • Printer can “print”- example code just translate raw data using USART. Error state, “paper out” is send to host, but interpretation of data depens on OS and printer driver used.
  • Printer is fully “plug and play”.
  • I don’t have enough documentation about “MS descriptor”. Theoretically it is special descriptor request (0xEE), but somehow it is not working. Maybe it is dependant of OS and printer driver.

How to make clone of my project or incorporate to you existing desing. Start STM32CubeMX, configure all your pins and devices, select USB device and CDC class. Then, manually remove all the stuff related to CDC class and copy printer class files. There are minor changes (not very useful) in USB core library (mainly for MS Windows tricks), it is noted in comments as “levo”.

The only interesting file for end user is “printer_hardware.c” – it is few subroutines to pass control for USB device to physical printer software.  It is like interface for printer interface :).

Older version of software, for analysis only:

Download STM32CubeMX USB PRINTER CLASS demo code (source and compiled hex for bluepill STM32F103C8.

There was error is “plug & play” section. Small change, but it caused bigger change in other source code- printer response is not always same size as host request size. This caused buffer overrun and garbage reported to host. Also, there was error in 1284 string report- I forgot to add size of the report to the body of report (this is compatibility with LPT cable) :

/* ************************************************************************
Low-level function to report 1284 id string
Input: pointer to buffer
Returns: length of the string
************************************************************************ */
uint16_t printer_hardware_id(unsigned char * pbuf)
static unsigned char Id1284String[] = "00MFG:Generic;MDL:Generic_/_Text_Only;CMD:1284.4;CLS:PRINTER;DES:TTY;";

uint16_t length=sizeof(Id1284String);
Id1284String[0]=(length >>8) & 0xFF;
Id1284String[1]=length & 0xFF;
// IEEE 1284 device ID string (including length in the first two bytes in big endian format).
return length;

USB report
Better version of printer device source code:
New version of USB PRINTER device for STM32f103 (STM32CunbeMX) with proper lenght in printer internals description.

Posted in Anything, MCU | Tagged , , , | Leave a comment

Cutting PCB panels for new universal STM board

I’ve noticed, that Chinese made “Blue Pill” PCB has fake chips. Some chips are with smaller ROM and RAM size, some chips behaves a bit strange. Also, several mine projects are getting bigger and bigger. Recently, I acquired several bigger chips (STM32F103RET6), from one local hardware company- they just utilized leftovers from warehouse. For this chip I designed new PCB with all pins exposed to standard 0,1″ headers, added USB connector and several mandatory elements. I squeezed all components to 5x5cm square. Minimal PCB size (for same price) is 10x10cm, so with the magic of copy-paste I quadrupled my PCB. There is option for cutting PCB in PCB-house, but it is quite expensive. Also, this extra cost increase value of PCB to such level, that I must pay the taxes for it. And the worst- I must pay “custom documents filling” fee (about 6x the small PCB price). My decision- I will cut PCB by myself.

From some paper dust particle board scraps and drawer holders (sliders) I build parallel moving “table” and glued “dremel” to base. Now I can cut nice, straight lines. And main thing- the cut lines are repeatable.

particle board and drawer slider for nice PCB panel cutting
Continue reading

Posted in Anything | Tagged , | 1 Comment

Crazy ’80s – computer design with style

When I hear somebody talking that Apple is the pioneer in the computer design, I always want to show photo of Atari XL series:
Atari 800xl 600xl 1020 1050 1027 series case design

These ones are not the all, they are only ones from my personal collection. Remember, it was introduced in 1982! Full set of distinctive devices: two versions of computers, disk drive and two interesting printers (one is plotter, not printer).

Posted in Anything | Tagged , | Leave a comment

Capacitive soil moisture sensor – designed by retarded

There is a cheap, made in China product called “capacitive soil moisture sensor”. Some black PCB with few components and no coating:
Capacitive soil moisture sensor- crap from China
There are lots of “duino” projects for this sensor. But there are lots of comments about this sensor not working or working strangely and erratically. For my future project I need such a sensor, so I bought one to analyze.

Circuit diagram (schematics) for this “device” is something like this:
schematics of capacitive soil moisture sensor
It is a bit simplified schematics, but I think it is more real compared to internet ones.

The 555 timer is generating high frequency voltage (1.7MHz) to the sensor plate “capacitor” via R1 limiting resistor. This resistor and “moisture” capacitor C1(Cx) is AC voltage divider. Resulting voltage is rectified with diode D1 and smoothered with a C3 capacitor and loaded with a very high resistance R2 resistor (sometimes missing). Resulting DC voltage (with extreme low current) is directly fed to the ADC of the MCU. This is the first error- not all MCU ADC input have such high impedance (resistance), also some parasitic voltages may be present on ADC pin with such high resistance. Also, any contamination of the PCB will drastically change ADC readings. We need to add voltage follower (op amp) to keep impedance high and stable. Also, isolation of PCB is important. Not only in the ADC part, but also on 555 timer to keep it running stable.This sensor (at least mine) does not work from a 3V power source. Maybe there is a very fake 555 timer. Need to investigate it more.

Possible improvements:
1. isolating coating with varnish. Maybe even some epoxy or UV curing one.
2. Remake of AC source. Maybe some crystal oscillator here? Or use something from nearby MCU.
3. Add voltage follower for impedance matching.or… use completely other hardware. something like an advanced capacitive touch controller like MPR121.

The MPR121 uses a constant DC current capacitance sensing scheme. It can measure capacitances ranging from 10 pF to over 2000 pF with a resolution up to 0.01 pF. The device does this by varying the amount of charge current and charge time applied to the sensing inputs.

Posted in Anything, Vandalising | Tagged , | 1 Comment

ARM:0017 – go to sleep clock

This is a “gamers” clock. It sits near the monitor and shows the real time and time computer is on. This is achieved using USB as power supply. Also, the same USB port is used to set the clock. Battery (in this version- super capacitor) is used only to keep the RTC clock on while it is not displaying time.

All components are easily obtainable and are cheap. I think the box for the clock is the most expensive and labor intensive part.

RTC OLED clock bluepill
There are only few components: Bluepill bloard (STM32F103), small OLED screen on I2C bus (optional bus terminators – 10K resistors if missing on screen PCB), supercapacitor (or 3V backup lithium battery) with charging circuit (diode and current limiting resistor). I am using supercap because batteries are dying, meanwhile this capacitor is forever. Supercaps charge is smaller than battery and it keeps RTC for shorter time length, but this is a frequently used clock and it recharges every time the computer is on. Charging batteries is not recommended.

This clock uses a USB COM (CDC) device for communication with the computer and setting the time. To set time, send a time string to the clock and it will be current settings. To do it automagically use windows CMD script, only change port number:

set /p x=%TIME% \\.\COM12

This script is so strange as there are problems in Windows bat files when port numbers are big. This script eliminates possible problems with port naming, also it does not send extra data (like CRLF) to the clock. Clock’s firmware filters data, but there may be some bugs.
If the time is not set, do like with any other “windows” device- remove it and reattach to USB.

Full source code and compiled binaries for the Bluepill are here.

One notable moment in source code is adjusting RTC clock speed. There is a bug in the current version of the cubeMX software. So there is work around:

#define RTC_AUTO_1_SECOND 32767

To keep crystal clock division with a real crystal clock we need to redefine RTC_AUTO_1_SECOND value. Change it to your crystal clock frequency. Fine tuning of the clock is achieved using regular documented ways:


Zeroes are values not used in this MCU. Read manual for further information.

This is the final clock image:
Now it is in “alert” mode, indicating that the user is sitting near the computer for too long a time. Time to finish all games.

Close up of the OLED screen:

Posted in Anything, MCU | Tagged , , , | Leave a comment