Как стать автором
Обновить

Восстановление нерабочей клавиатуры с помощью QMK и RP2040

Уровень сложностиПростой
Время на прочтение9 мин
Количество просмотров5.4K

Привет, Хабр!

Так бывает, что иногда клавиатуры ломаются и если мембранные клавиатуры обычно представляют малую ценность и проще просто купить новую, то вот механические заметно дороже и их имеет смысл восстанавливать. Когда речь о поломках механических клавиатур и их ремонте, то как правило всё сводится к замене вышедших из строя переключателей, но вот что делать если вышел из строя контроллер?

Как и почему

Началось всё с того, что у товарища сломалась клавиатура ViewSonic KU520 в полноразмерной версии на 104 клавиши (есть ещё TKL версия с тем же названием), в которой просто отгнила ножка контроллера. Был ли там активный флюс не отмыт или ещё что, я не знаю, но как потом выяснилось она была не одна, а ещё несколько ножек тоже были готовы отвалиться. Может кто-то и умеет подпаиваться к хвостикам торчащим из чипа меньше чем на миллиметр, но я нет. Да и речь не об этом, в конце концов контроллер может выйти из строя по разным причинам. Можно наверное было поискать такой же, потом поискать как и чем его прошивать и возможно кто-то когда-то напишет об этом на Хабре. Контроллер был Holtek HT68FB560. Я же покажу более универсальный способ подходящий для гораздо большего числа клавиатур.

Восстанавливать работоспособность я буду с помощью QMK и микроконтроллера RP2040. Вообще речь заходит про QMK обычно в контексте создания кастомных клавиатур или в контексте подключения каких-нибудь нестандартных старых клавиатур к современному ПК, а не в плане ремонта и восстановления работоспособности обычных современных механических клавиатур. QMK (QuantumMechanicalKeyboard) — прошивка с открытым исходным кодом для микроконтроллеров клавиатур с архитектурой AtmelAVR и некоторых ARM, т.е. различные ATmega, STM32, RP2040 и т.д. Выбирать можно то, что вам больше подходит по количеству выводов, ну и больше нравится. В моём случае это Raspberry Pi RP2040 в исполнении SuperMini.

RP2040 SuperMini
RP2040 SuperMini

Микроконтроллер

Почему собственно RP2040 именно в таком исполнении, ведь есть же версии, которые чуть побольше и соответственно паять их поудобнее? Из-за размеров.

Размеры RP2040 SuperMini
Размеры RP2040 SuperMini

Платка идеально ложится на свободное место на клавиатуре где нет кнопок.

Место для будущей платки. Старый контроллер удалён.
Место для будущей платки. Старый контроллер удалён.

Вообще они бывают немного разные даже в таком исполнении. Может быть 2 или одна кнопка, дополнительные светодиоды и самое главное разное расположение выводов, так что смотреть нужно внимательно. На сайте QMK есть предупреждение, что могут не совпадать надписи с выводами. У меня на платке шелкография такова, что 29-й вывод можно спутать с 24-м.

Распиновка лицевая сторона
Распиновка лицевая сторона
Распиновка обратная сторона
Распиновка обратная сторона

Спецификации RP2040:

  • 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

Если посмотреть на спецификации RP2040 можно подумать, что применять его для клавиатуры это как стрелять из пушки по воробьям, но при сопоставимой (даже чуть меньшей) стоимости с Holtek HT68FB560 почему бы и нет.

Пайка

Прежде чем что-то паять (да и выбирать контроллер тоже) нужно прозвонить клавиатуру, дабы понять какая здесь матрица. О том, что такое матрица клавиатуры можно почитать например здесь. Вооружившись мультиметром составляем схему столбцов и строк, попутно смотря как подключены диоды.

Древние рукописи с описанием столбцов и строк клавиатуры
Древние рукописи с описанием столбцов и строк клавиатуры

Получилась матрица 17х8, а значит нам потребуется 25 выводов непосредственно на клавиши и плюс ещё 3 на светодиодные индикаторы. Итого 28. Товарищ сказал, что подсветка ему не нужна, он всё равно её выключает, так что её восстановлением я не занимался, хотя QMK поддерживает различные виды подсветки. Часть выводов находится с обратной стороны платки.

Кусок шлейфа от FDD хорошо подходит для обратной стороны
Кусок шлейфа от FDD хорошо подходит для обратной стороны

Припаиваем все провода к платке, а затем к столбцам и строкам на плате клавиатуры, не забывая про светодиоды индикаторы. На 25-ом выводе на платке припаян красный светодиод на котором можно проверить работу индикации Num Lock например. Причем выход 25 есть отдельно, так что светодиод клавиатуры можно подпаять, оставив этот на своём месте, пусть освещает своим красным светом мрак внутри клавиатуры. Светодиоды припаивал через резисторы. Чтобы нигде ничего не двигалось приклеил термоклеем плату и все провода на плате где они могли двигаться.

Спагетти пайка
Спагетти пайка

Качество пайки можете не оценивать, я знаю что оно "великолепное". Но если даже я, с довольно посредственными навыками пайки, справился, то и у вас получится. Аппаратная часть готова, приступим к программной.

Прошивка

Для создания прошивки под Windows можно использовать QMK MSYS. Поскольку RP2040 прошивается просто закидыванием прошивки на него в режиме флешки, драйвера при установке QMK MSYS можно никакие не ставить.

Запускаем QMK MSYS и при первом запуске нужно выполнить команду:

qmk setup

Далее создаём новую клавиатуру:

qmk new-keyboard

Здесь последовательно отвечая на вопросы задаём название клавиатуры, раскладку, тип контроллера. Поскольку у меня обычная полноразмерная клавиатура, раскладка будет fullsize_ansi. Контроллер promicro_rp2040. После чего сформируется папка с названием клавиатуры, в моём случае это viewsonic_ku520, где нас интересует файл keyboard.json, который нужно отредактировать в соответствии с матрицей, выводами на светодиоды и т.п. Тут нужно указать так же diode_direction, в моём случае это ROW2COL.

Diode_direction может быть настроено в двух направлениях:

ROW2COL - диоды направлены от строк к столбцам (катоды подключены к столбцам). COL2ROW - диоды направлены от столбцов к строкам (катоды подключены к строкам).

Так же здесь можно включить bootmagic, это кнопка на клавиатуре, которая будет выполнять ту же функцию, что и физическая кнопка BOOT на платке, а именно переводить RP2040 в режим флешки. Обычно её назначают на Esc.

Полученный результат:

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": ";", "matrix": [3, 10], "x": 10.75, "y": 3.25},
                {"label": "'", "matrix": [3, 11], "x": 11.75, "y": 3.25},
                {"label": "Enter", "matrix": [5, 12], "x": 12.75, "y": 3.25, "w": 2.25},
                {"label": "4", "matrix": [6, 13], "x": 18.5, "y": 3.25},
                {"label": "5", "matrix": [6, 15], "x": 19.5, "y": 3.25},
                {"label": "6", "matrix": [3, 16], "x": 20.5, "y": 3.25},
				
                {"label": "LShift", "matrix": [4, 0], "x": 0, "y": 4.25, "w": 2.25},
                {"label": "Z", "matrix": [4, 2], "x": 2.25, "y": 4.25},
                {"label": "X", "matrix": [4, 3], "x": 3.25, "y": 4.25},
                {"label": "C", "matrix": [4, 4], "x": 4.25, "y": 4.25},
                {"label": "V", "matrix": [4, 5], "x": 5.25, "y": 4.25},
                {"label": "B", "matrix": [4, 6], "x": 6.25, "y": 4.25},
                {"label": "N", "matrix": [4, 7], "x": 7.25, "y": 4.25},
                {"label": "M", "matrix": [4, 8], "x": 8.25, "y": 4.25},
                {"label": "<", "matrix": [4, 9], "x": 9.25, "y": 4.25},
                {"label": ">", "matrix": [4, 10], "x": 10.25, "y": 4.25},
                {"label": "?", "matrix": [4, 11], "x": 11.25, "y": 4.25},
                {"label": "RShift", "matrix": [5, 11], "x": 12.25, "y": 4.25, "w": 2.75},
                {"label": "Up", "matrix": [4, 14], "x": 16.25, "y": 4.25},
                {"label": "1", "matrix": [7, 14], "x": 18.5, "y": 4.25},
                {"label": "2", "matrix": [7, 15], "x": 19.5, "y": 4.25},
                {"label": "3", "matrix": [4, 16], "x": 20.5, "y": 4.25},
                {"label": "Enter", "matrix": [6, 16], "x": 21.5, "y": 4.25, "h": 2},
				
                {"label": "LCtrl", "matrix": [5, 0], "x": 0, "y": 5.25, "w": 1.25},
                {"label": "Win", "matrix": [5, 1], "x": 1.25, "y": 5.25, "w": 1.25},
                {"label": "LAlt", "matrix": [5, 2], "x": 2.5, "y": 5.25, "w": 1.25},
                {"label": "Space", "matrix": [5, 4], "x": 3.75, "y": 5.25, "w": 6.25},
                {"label": "RAlt", "matrix": [5, 7], "x": 10, "y": 5.25, "w": 1.25},
                {"label": "Fn", "matrix": [5, 8], "x": 11.25, "y": 5.25, "w": 1.25},
                {"label": "Menu", "matrix": [5, 9], "x": 12.5, "y": 5.25, "w": 1.25},
                {"label": "RCtrl", "matrix": [5, 10], "x": 13.75, "y": 5.25, "w": 1.25},
                {"label": "Left", "matrix": [4, 13], "x": 15.25, "y": 5.25},
                {"label": "Down", "matrix": [5, 14], "x": 16.25, "y": 5.25},
                {"label": "Right", "matrix": [4, 15], "x": 17.25, "y": 5.25},
                {"label": "0", "matrix": [6, 14], "x": 18.5, "y": 5.25, "w": 2},
                {"label": ".", "matrix": [5, 16], "x": 20.5, "y": 5.25}
            ]
        }
    }
}

Теперь в QMK MSYS нужно выполнить команду:

qmk compile -kb viewsonic_ku520 -km default

чтобы сформировалась прошивка viewsonic_ku520_default.uf2, которая будет лежать в папке qmk_firmware. После чего подключаем нашу разобранную клавиатуру к USB порту ПК с зажатой кнопкой BOOT на платке, закидываем прошивку на флешку. Процесс прошивки должен запуститься сразу, после чего перезагрузка и если все сделано правильно, клавиатура должна заработать как надо.

Проверить работоспособность можно в QMK Toolbox, в котором имеется Key Tester.

Все клавиши работают
Все клавиши работают

QMK Toolbox может пригодиться и для прошивки, если используется какой-то другой контроллер.

Вот собственно и всё. Можно собирать клавиатуру и пользоваться.

Заключение

Хотелось просто обратить внимание на то, что такой ремонт возможен, так как в отличии от тех кто делает кастомные клавиатуры, люди которые просто столкнулся с необходимостью ремонта, возможно даже не будут знать о существовании QMK. Так же хотелось описать, что-то простое. Слои, макросы VIA, это всё можно уже сделать потом если понадобится, тем более, что для прошивки теперь достаточно просто подключить клавиатуру с зажатой клавишей Esc даже не разбирая её. Надеюсь кому-то это действительно поможет оживить их клавиатуру, а на этом у меня всё.

Теги:
Хабы:
+33
Комментарии8

Публикации

Истории

Ближайшие события

22 – 24 ноября
Хакатон «AgroCode Hack Genetics'24»
Онлайн
28 ноября
Конференция «TechRec: ITHR CAMPUS»
МоскваОнлайн
2 – 18 декабря
Yandex DataLens Festival 2024
МоскваОнлайн
11 – 13 декабря
Международная конференция по AI/ML «AI Journey»
МоскваОнлайн
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань