Restoring a non-working keyboard using QMK and RP2040

It happens that sometimes keyboards break, and if membrane keyboards usually have little value and it is easier to just buy a new one, then mechanical ones are noticeably more expensive and it makes sense to restore them. When it comes to mechanical keyboard breakdowns and repairs, it usually comes down to replacing the failed switches, but what if the controller fails?

`

How and why

It all started with the fact that a friend's ViewSonic KU520 keyboard in the full-size version with 104 keys (there is also a TKL version with the same name) simply had the controller leg rotted off. Whether there was active flux not washed off or something else, I don't know, but as it turned out later, it was not alone, and several other legs were also ready to fall off. Maybe someone can solder to the tails sticking out of the chip less than a millimeter, but I can't. And it's not about that, after all, the controller can fail for various reasons. You could probably look for the same one, then look for how and what to flash it with, and maybe someone will write about it on tekkix someday. The controller was Holtek HT68FB560. I will show a more universal method suitable for a much larger number of keyboards.

I will restore functionality using QMK and the RP2040 microcontroller. In general, QMK usually comes up in the context of creating custom keyboards or in the context of connecting some non-standard old keyboards to a modern PC, and not in terms of repairing and restoring the functionality of ordinary modern mechanical keyboards. QMK (Quantum Mechanical Keyboard) is an open-source firmware for keyboard microcontrollers with Atmel AVR architecture and some ARM, i.e. various ATmega, STM32, RP2040 and etc. You can choose what suits you best in terms of the number of pins, and what you like more. In my case, it's the Raspberry Pi RP2040 in the SuperMini version.

Microcontroller

Why exactly the RP2040 in this version, because there are versions that are slightly larger and, accordingly, it is more convenient to solder them? Because of the size.

The board fits perfectly in the free space on the keyboard where there are no buttons.

In general, they can be slightly different even in this design. There may be 2 or one button, additional LEDs, and most importantly, different pin layouts, so you need to look carefully. On the QMK website, there is a warning that the labels may not match the pins. On my board, the silkscreen is such that the 29th pin can be confused with the 24th.

RP2040 specifications:

  • Dual-core Arm Cortex-M0+ processor, flexible clock running up to 133 MHz

  • 264kB on-chip SRAM

  • 2 × UART, 2 × SPI controllers, 2 × I2C controllers, 16 × PWM channels

  • 1 × USB 1.1 controller and PHY, with host and device support

  • 8 × Programmable I/O (PIO) state machines for custom peripheral support

  • Operating temperature -40°C to +85°C

  • Drag-and-drop programming using mass storage over USB

  • Low-power sleep and dormant modes

  • Temperature sensor

  • Accelerated integer and floating-point libraries on-chip

If you look at the RP2040 specifications, you might think that using it for a keyboard is like shooting sparrows with a cannon, but with comparable (even slightly lower) cost to the Holtek HT68FB560, why not.

Soldering

Before soldering anything (and choosing a controller too), you need to ring out the keyboard to understand what kind of matrix is here. You can read about what a keyboard matrix is, for example, here. Armed with a multimeter, we draw up a diagram of columns and rows, simultaneously looking at how the diodes are connected.

Using QMK software to configure keyboard keys

A 17x8 matrix was obtained, which means we will need 25 outputs directly to the keys and plus 3 more for the LED indicators. Total 28. The comrade said that he does not need the backlight, he still turns it off, so I did not restore it, although QMK supports various types of backlighting. Some of the outputs are on the back of the board.

We solder all the wires to the board, and then to the columns and rows on the keyboard board, not forgetting about the LED indicators. A red LED is soldered to the 25th pin on the board, on which you can check the operation of the Num Lock indication, for example. Moreover, output 25 is separate, so you can solder the keyboard LED, leaving this one in place, let it illuminate the darkness inside the keyboard with its red light. I soldered the LEDs through resistors. So that nothing moves anywhere, I glued the board and all the wires on the board where they could move with hot glue.

You don't need to evaluate the quality of the soldering, I know it's "excellent". But even if I, with rather mediocre soldering skills, managed, then you will succeed too. The hardware part is ready, let's move on to the software part.

Firmware

To create firmware for Windows, you can use QMK MSYS. Since the RP2040 is flashed simply by dropping the firmware onto it in flash drive mode, you don't need to install any drivers when installing QMK MSYS.

We launch QMK MSYS and at the first launch you need to execute the command:

qmk setup

Next, we create a new keyboard:

qmk new-keyboard

Here, sequentially answering questions, we set the name of the keyboard, layout, type of controller. Since I have a regular full-size keyboard, the layout will be fullsize_ansi. The controller is promicro_rp2040. After that, a folder with the name of the keyboard will be formed, in my case it is viewsonic_ku520, where we are interested in the keyboard.json file, which needs to be edited in accordance with the matrix, outputs to the LEDs, etc. Here you also need to specify diode_direction, in my case it is ROW2COL.

Diode_direction can be set in two directions:

ROW2COL - diodes are directed from rows to columns (cathodes are connected to columns). COL2ROW - diodes are directed from columns to rows (cathodes are connected to rows).

Also, bootmagic can be enabled here, this is a button on the keyboard that will perform the same function as the physical BOOT button on the board, namely to switch the RP2040 to flash mode. It is usually assigned to Esc.

Result:

keyboard.json
{
    "manufacturer": "ViewSonic",
    "keyboard_name": "ku520",
    "maintainer": "Ivan",
    "development_board": "promicro_rp2040",
    "diode_direction": "ROW2COL",
    "features": {
        "bootmagic": true,
        "command": false,
        "console": false,
        "extrakey": true,
        "mousekey": false,
        "nkro": true
    },
	"indicators": {
        "caps_lock": "GP27",
        "num_lock": "GP25",
        "scroll_lock": "GP28"
    },
    "matrix_pins": {
        "cols": ["GP0", "GP1", "GP2", "GP3", "GP4", "GP5", "GP6", "GP7", "GP8", "GP9", "GP10", "GP11", "GP12", "GP13", "GP14", "GP15", "GP26"],
        "rows": ["GP17", "GP18", "GP19", "GP20", "GP21", "GP22", "GP23", "GP24"]
    },
    "url": "",
    "usb": {
        "device_version": "1.0.0",
		"max_power": 100,
        "pid": "0x0000",
        "vid": "0xFEED"
    },
	"bootmagic": {
        "matrix": [0, 0]
    },
    "layouts": {
        "LAYOUT_fullsize_ansi": {
            "layout": [
                {"label": "Esc", "matrix": [0, 0], "x": 0, "y": 0},
                {"label": "F1", "matrix": [0, 1], "x": 2, "y": 0},
                {"label": "F2", "matrix": [0, 2], "x": 3, "y": 0},
                {"label": "F3", "matrix": [0, 3], "x": 4, "y": 0},
                {"label": "F4", "matrix": [0, 4], "x": 5, "y": 0},
                {"label": "F5", "matrix": [0, 5], "x": 6.5, "y": 0},
                {"label": "F6", "matrix": [0, 6], "x": 7.5, "y": 0},
                {"label": "F7", "matrix": [0, 7], "x": 8.5, "y": 0},
                {"label": "F8", "matrix": [0, 8], "x": 9.5, "y": 0},
                {"label": "F9", "matrix": [0, 9], "x": 11, "y": 0},
                {"label": "F10", "matrix": [0, 10], "x": 12, "y": 0},
                {"label": "F11", "matrix": [0, 11], "x": 13, "y": 0},
                {"label": "F12", "matrix": [0, 12], "x": 14, "y": 0},
                {"label": "PrtSc", "matrix": [1, 13], "x": 15.25, "y": 0},
                {"label": "ScrLock", "matrix": [1, 14], "x": 16.25, "y": 0},
                {"label": "Pause", "matrix": [1, 15], "x": 17.25, "y": 0},

                {"label": "`", "matrix": [1, 0], "x": 0, "y": 1.25},
                {"label": "1", "matrix": [1, 1], "x": 1, "y": 1.25},
                {"label": "2", "matrix": [1, 2], "x": 2, "y": 1.25},
                {"label": "3", "matrix": [1, 3], "x": 3, "y": 1.25},
                {"label": "4", "matrix": [1, 4], "x": 4, "y": 1.25},
                {"label": "5", "matrix": [1, 5], "x": 5, "y": 1.25},
                {"label": "6", "matrix": [1, 6], "x": 6, "y": 1.25},
                {"label": "7", "matrix": [1, 7], "x": 7, "y": 1.25},
                {"label": "8", "matrix": [1, 8], "x": 8, "y": 1.25},
                {"label": "9", "matrix": [1, 9], "x": 9, "y": 1.25},
                {"label": "0", "matrix": [1, 10], "x": 10, "y": 1.25},
                {"label": "-", "matrix": [1, 11], "x": 11, "y": 1.25},
                {"label": "+", "matrix": [1, 12], "x": 12, "y": 1.25},
                {"label": "Backspace", "matrix": [3, 12], "x": 13, "y": 1.25, "w": 2},
                {"label": "Ins", "matrix": [2, 13], "x": 15.25, "y": 1.25},
                {"label": "Home", "matrix": [2, 14], "x": 16.25, "y": 1.25},
                {"label": "PgUp", "matrix": [2, 15], "x": 17.25, "y": 1.25},
                {"label": "NumLock", "matrix": [0, 13], "x": 18.5, "y": 1.25},
                {"label": "/", "matrix": [0, 14], "x": 19.5, "y": 1.25},
                {"label": "*", "matrix": [0, 15], "x": 20.5, "y": 1.25},
                {"label": "-", "matrix": [0, 16], "x": 21.5, "y": 1.25},

                {"label": "Tab", "matrix": [2, 0], "x": 0, "y": 2.25, "w": 1.5},
                {"label": "Q", "matrix": [2, 1], "x": 1.5, "y": 2.25},
                {"label": "W", "matrix": [2, 2], "x": 2.5, "y": 2.25},
                {"label": "E", "matrix": [2, 3], "x": 3.5, "y": 2.25},
                {"label": "R", "matrix": [2, 4], "x": 4.5, "y": 2.25},
                {"label": "T", "matrix": [2, 5], "x": 5.5, "y": 2.25},
                {"label": "Y", "matrix": [2, 6], "x": 6.5, "y": 2.25},
                {"label": "U", "matrix": [2, 7], "x": 7.5, "y": 2.25},
                {"label": "I", "matrix": [2, 8], "x": 8.5, "y": 2.25},
                {"label": "O", "matrix": [2, 9], "x": 9.5, "y": 2.25},
                {"label": "P", "matrix": [2, 10], "x": 10.5, "y": 2.25},
                {"label": "{", "matrix": [2, 11], "x": 11.5, "y": 2.25},
                {"label": "}", "matrix": [2, 12], "x": 12.5, "y": 2.25},
                {"label": "|", "matrix": [4, 12], "x": 13.5, "y": 2.25, "w": 1.5},
                {"label": "Del", "matrix": [3, 13], "x": 15.25, "y": 2.25},
                {"label": "End", "matrix": [3, 14], "x": 16.25, "y": 2.25},
                {"label": "PgDn", "matrix": [3, 15], "x": 17.25, "y": 2.25},
                {"label": "7", "matrix": [5, 13], "x": 18.5, "y": 2.25},
                {"label": "8", "matrix": [5, 15], "x": 19.5, "y": 2.25},
                {"label": "9", "matrix": [2, 16], "x": 20.5, "y": 2.25},
                {"label": "+", "matrix": [1, 16], "x": 21.5, "y": 2.25, "h": 2},

                {"label": "CapsLock", "matrix": [3, 0], "x": 0, "y": 3.25, "w": 1.75},
                {"label": "A", "matrix": [3, 1], "x": 1.75, "y": 3.25},
                {"label": "S", "matrix": [3, 2], "x": 2.75, "y": 3.25},
                {"label": "D", "matrix": [3, 3], "x": 3.75, "y": 3.25},
                {"label": "F", "matrix": [3, 4], "x": 4.75, "y": 3.25},
                {"label": "G", "matrix": [3, 5], "x": 5.75, "y": 3.25},
                {"label": "H", "matrix": [3, 6], "x": 6.75, "y": 3.25},
                {"label": "J", "matrix": [3, 7], "x": 7.75, "y": 3.25},
                {"label": "K", "matrix": [3, 8], "x": 8.75, "y": 3.25},
                {"label": "L", "matrix": [3, 9], "x": 9.75, "y": 3.25},
                {"label": "

								    

							    
Comments

    Relevant news on the topic "Hardware"