Как сделать полноценную USB-клавиатуру из модуля ноутбука MSI
Существуют пользователи, которые с легкостью меняют периферию и адаптируются к обновкам за считанные дни. Но это точно не про мою супругу. Она обожает клавиатуру своего лэптопа MSI GS75, и настолько сильно, что ни одна из опробованных нами альтернатив не смогла её заменить.
Я перепробовал множество вариантов: одни разочаровывали ходом клавиш, другие требовали слишком больших усилий при нажатии, огорчали эргономикой или специфическими тактильными ощущениями. Казалось бы, рынок современной периферии безграничен, однако идеала найти так и не удалось. В какой-то момент меня осенила мысль: зачем продолжать поиски, если безупречная клавиатура уже есть в наличии? Оставалось лишь заставить её функционировать автономно от компьютера.
Так стартовал этот домашний эксперимент, плавно переросший в глубокое исследование клавиатурной матрицы, создание двух поколений печатных плат на базе STM32, написание оригинального USB HID-стека и войну с ложными срабатываниями. На сегодняшний день у меня уже готов полноценный прототип: 102 клавиши, разъём USB Type-C, поддержка клавиши Fn и медиакомбинаций, режим NKRO, а также встроенная диагностическая утилита.
В этой публикации я поделюсь опытом проектирования, расскажу о встреченных трудностях и объясню, почему самым сложным этапом оказалось вовсе не создание платы, а корректная программная обработка нажатий.
С чего начать, когда у клавиатуры отсутствует USB-интерфейс?
Главная сложность заключается в том, что клавиатурный модуль ноутбука не является самостоятельным USB-девайсом. Обычные внешние устройства укомплектованы собственным контроллером, обрабатывающим сигналы. В случае с лэптопом эту задачу выполняет материнская плата. Наружу же выведен лишь гибкий шлейф с проводниками, напрямую контактирующими с дорожками клавиш.
У моей модели для основных кнопок предусмотрен 26-контактный шлейф. Возникает закономерный вопрос: как задействовать 102 клавиши через такое скромное количество выводов? Секрет кроется в матричной архитектуре. Вместо отдельной жилы для каждой кнопки применяется пересечение линий строк и столбцов. Конкретная клавиша замыкает уникальную пару проводников. Контроллер циклически опрашивает линии и по пересечению активных контактов вычисляет нажатую кнопку.
Тем не менее, главная интрига крылась в отсутствии официальной распиновки. Было абсолютно непонятно, какой именно контакт шлейфа отвечает за конкретную строку или столбец, каково их общее соотношение и какие именно пары замыкаются при активации той или иной клавиши.
Конечно, можно было вооружиться мультиметром и методично прозванивать дорожки вручную, но перспектива возиться с сотней кнопок и их комбинациями не вдохновляла. Поэтому был выбран более элегантный путь — спроектировать универсальный адаптер, а распиновку вычислить программным методом.
Первая плата: 26 загадочных сигналов
В качестве «мозга» устройства я выбрал микроконтроллер STM32F411RET6. Это производительный чип с поддержкой аппаратного USB Full Speed, внушительным арсеналом портов ввода-вывода и комфортной средой для отладки.
Поскольку точное назначение линий оставалось загадкой, все 26 выводов шлейфа были заведены напрямую на GPIO микроконтроллера. Это позволяло на программном уровне менять конфигурацию портов и тестировать соединения «на лету», избегая редизайна платы. Помимо самой микросхемы STM32, схема потребовала установки разъема шлейфа, порта USB Type-C, стабилизатора питания на 3,3 В, кварцевого резонатора и отладочных интерфейсов.
Двухслойный текстолит и пространственные ребусы
Плата проектировалась двухслойной. На первый взгляд задача казалась элементарной: один микроконтроллер, горстка пассивки и пара разъемов. Однако в процессе разводки выяснилось, что наиболее уязвимым местом является область сопряжения 26 контактов шлейфа с пинами STM32.
Из разъема шлейфа выходил плотный пучок дорожек, которые требовалось развести по разным сторонам чипа, избегая паутины переходных отверстий и избыточных петель. В какой-то момент стало очевидно, что проще скорректировать принципиальную схему, чем мучиться с трассировкой. Я неоднократно переназначал GPIO микроконтроллера, добиваясь наиболее логичного и чистого распределения сигналов.
В этом и заключается гибкость современных MCU: если интерфейс не привязан жестко к специализированным аппаратным выводам, проще переконфигурировать порты в софте, чем прокладывать дорожки через всю плату. Главное — не забыть синхронизировать изменения со схемой и прошивкой.
Боевое крещение миниатюрной пайкой
К этапу сборки меня ждал еще один увлекательный вызов — первый опыт ручного монтажа столь мелких SMD-компонентов. В интерфейсе CAD-системы элементы кажутся крупными и аккуратными, но в реальности некоторые из них настолько микроскопические, что работать с ними обычным паяльником без оптического увеличения просто нереально.
Для этих целей я приобрел тринокулярный микроскоп, который моментально стал главным помощником в домашней лаборатории. Под многократным увеличением контроль позиционирования деталей, качества пайки и поиска возможных микрозамыканий вышел совершенно на новый уровень.
После завершения монтажа настало время софта. Первую ревизию я прошивал посредством интерфейса SWD через отладчик ST-Link, что отлично подходило для первичной настройки и отладки.
Восстановление неизвестной распиновки
Этот этап оказался едва ли не самым захватывающим во всей разработке. На старте мы обладали лишь фактом: нажатие клавиши замыкает пару контактов шлейфа. Но каких именно? Для ответа я написал диагностическую прошивку, циклически сканирующую все 26 линий.
Алгоритм функционировал следующим образом:
-
Один из выводов STM32 переводился в режим выхода с открытым стоком и притягивался к земляному потенциалу.
-
Остальные 25 выводов настраивались как входы с внутренней подтяжкой к питанию.
-
Микроконтроллер фиксировал линии, на которых уровень сигнала проседал до нуля.
-
Затем активным становился следующий вывод, и цикл повторялся.
Таким образом осуществлялся полный перекрестный опрос всех 26 контактов. На данном этапе это было критически важно, так как четкого разделения на строки и столбцы еще не существовало.
Автоматизируем измерения для 102 клавиш
Чтобы избежать ручного прозвона сотен кнопок, я написал вспомогательный скрипт на Python — gs75_matrix_mapper.py, работающий в тандеме с отладочной прошивкой. Сначала утилита сканировала исходное состояние матрицы на предмет залипаний. Затем она последовательно предлагала нажать каждую клавишу, автоматически определяла замкнувшуюся пару контактов и верифицировала стабильность сигнала.
К примеру, для клавиши Esc программа зафиксировала связку FPC21–FPC26, успешно подтвержденную серией из пяти идентичных замеров. После отпускания кнопки скрипт автоматически переключался на следующий элемент — F1.
Открываю COM17 @ 115200...
UART: PONG получен.
Baseline: ничего не нажимайте.
baseline 01/10: 0 directed edge(s)
...
baseline 10/10: 0 directed edge(s)
Baseline выбран: 0 edge(s), 10/10 одинаковых снимков.
Нажмите Enter, чтобы начать карту ОДИНОЧНЫХ клавиш...
[1/102] Esc
================================================
Нажмите и УДЕРЖИВАЙТЕ: Esc
Скрипт сам обнаружит нажатие.
Зафиксировано (5/5 одинаковых снимков):
FPC21->FPC26
Теперь ОТПУСТИТЕ клавишу(и)...
[2/102] F1
================================================
Нажмите и УДЕРЖИВАЙТЕ: F1
Фактически мне удалось превратить процесс реверс-инжиниринга в полностью автоматизированный процесс: софт давал команду, контроллер собирал телеметрию, а результаты аккуратно складывались в JSON-структуру. Каждое одиночное нажатие перепроверялось пять раз. Все 102 клавиши были локализованы без единой ошибки. На финальном этапе я проверил сложные комбинации, чтобы убедиться в абсолютной точности построенной модели.
Итоги картирования
Анализ данных показал, что перед нами матрица формата 8 × 18:
-
8 линий отведены под строки — контакты FPC17–FPC24;
-
18 линий образуют столбцы — контакты FPC1–FPC16, а также FPC25 и FPC26.
В сумме такая конфигурация дает 144 возможных узла, из которых задействовано 102. Полученная карта была экспортирована в конфигурационный файл.
Любопытно, что физическое расположение кнопок на клавиатуре не имеет ничего общего с их электрической топологией. Соседние на корпусе клавиши могут находиться на совершенно разных концах матрицы, поэтому попытки выстроить карту «на глаз» были бы обречены на провал.
На тот момент казалось, что самые суровые испытания позади: матрица расшифрована, контакты известны, осталось лишь оформить стандартный HID-драйвер. Но дальнейшая практика преподнесла сюрпризы.
Фантомные нажатия (Ghosting): когда устройство живет своей жизнью
В матричных клавиатурах, лишенных развязывающих диодов на каждой кнопке, неизбежно проявляется эффект фантомных нажатий (ghosting). Если представить четыре клавиши, образующие вершины условного прямоугольника на пересечении линий, то при одновременном нажатии трех из них физика процесса создает паразитный путь тока. В результате контроллер ошибочно фиксирует замыкание и в четвертом углу, хотя его никто не трогал.
Во время тестирования я проверил комбинации, формирующие подобные геометрические фигуры. Все 20 специально выбранных тестовых сочетаний продемонстрировали электрическую неоднозначность: софт физически не мог отличить реальное нажатие трех кнопок от четырех. Это фундаментальное ограничение «железа».
Создавай я матрицу с нуля, проблема решалась бы установкой диодов возле каждого свитча. Но здесь использовался готовый ноутбучный модуль, ковырять который паяльником не было никакого желания. Пришлось искать программное решение.
Почему нельзя просто «вычислить» фантом
Интуитивное решение кажется простым: если система видит замкнутый прямоугольник, нужно вычислить лишний угол и отбросить его. Проблема в том, что электрически все четыре точки выглядят абсолютно идентично. У прошивки нет точных данных о том, какая именно клавиша была нажата пользователем, а какая появилась из-за паразитных токов.
Поэтому был внедрен консервативный фильтр неопределенных состояний. Он отслеживает конфигурацию матрицы, сохраняет ранее подтвержденные активные нажатия, пока они удерживаются, но блокирует регистрацию новых сомнительных сигналов до тех пор, пока электрическая схема не придет в норму.
У этого метода есть минусы — некоторые быстрые легитимные нажатия могут на мгновение подавляться. Зато он полностью исключает появление фантомных символов на экране. Примечательно, что анализировать приходится все 144 координаты, включая пустые ячейки, иначе алгоритм упустит паразитные связи, влияющие на детекцию ghosting.
Именно на этом этапе проект перестал быть простым считывателем контактов, превратившись в интеллектуальную систему мониторинга с учетом физических ограничений.
От физических контактов к USB HID протоколу
Получив точную карту матрицы, я переписал диагностический код в полноценный драйвер. Вместо брутфорса всех 26 линий алгоритм стал последовательно возбуждать 8 строк и считывать состояние 18 столбцов. Полный цикл опроса отрабатывает за 1 миллисекунду, обеспечивая кадровую частоту в 1000 Гц. Для каждого узла матрицы настроен независимый фильтр дребезга контактов длительностью 5 мс.
Итоговый конвейер обработки выглядит так:
Сканирование матрицы → фильтрация дребезга → подавление ghosting → формирование логического состояния → обработка Fn → генерация USB HID отчета.
Тонкости передачи HID-отчетов
Протокол USB HID поддерживается современными ОС «из коробки», избавляя от необходимости писать кастомные драйверы. Однако контроллер должен не просто передавать факт нажатия, но и корректно работать с многопальцевыми комбинациями, модификаторами (Ctrl, Shift, Alt) и динамическими режимами.
В прошивке реализованы два типа HID-отчетов:
Boot Protocol (6KRO) — базовый формат размером 8 байт, передающий до шести одновременных нажатий плюс модификаторы.
Report Protocol (NKRO) — расширенный 22-байтный формат с битовой картой всех клавиш. Он снимает искусственное ограничение на количество одновременно обрабатываемых нажатий, транслируя в систему все легитимные сигналы, распознанные матрицей.
Впрочем, NKRO не отменяет физических ограничений ghosting, но позволяет выжать максимум из имеющегося железа.
Разрабатывая проект, я активно задействовал UART для отладки. Чип транслировал в консоль состояние матрицы, статус детектора фантомных нажатий и параметры шины USB.
Здесь меня поджидала классическая ловушка: вывод отладочных логов в UART отнимает процессорное время, а опрос клавиатуры должен идти непрерывно.
Проблема решилась разделением задач. Сканирование и фильтрация выполняются в жестком системном тике по таймеру. События изменений складываются в кольцевой буфер очереди, тогда как отправка HID-пакетов и логирование разнесены по разным потокам. Благодаря этому отладочный вывод не тормозит опрос матрицы и не приводит к потере кратковременных нажатий.
Для удобства настройки предусмотрен набор команд: INFO, RAW, DUMP, GHOST, KEYS и USBINFO. Это позволило точечно диагностировать проблемы: видеть, регистрирует ли процессор замыкание «в железе», пропускает ли его логика и доходит ли сигнал до операционной системы.
Как быть с клавишей Fn и мультимедиа?
Главная особенность ноутбучных клавиатур — наличие модификатора Fn. В штатном режиме его обрабатывает встроенный контроллер материнской платы. Поскольку в нашем случае он отсутствует, всю логику Fn пришлось запрограммировать с нуля.
Я создал программный уровень, распознающий нажатие Fn и трансформирующий определенные комбинации в корректные HID-команды:
|
Комбинация |
Функция |
|
Fn + Num0 |
Отключение / включение звука (Mute) |
|
Fn + ← |
Уменьшение громкости |
|
Fn + → |
Увеличение громкости |
|
Fn + PageUp |
Home |
|
Fn + PageDown |
End |
С мультимедийными клавишами всплыл интересный нюанс стандарта USB HID. Стандартные символы используют страницу Keyboard/Keypad, но управление звуком корректнее транслировать через отдельную спецификацию Consumer Control.
Первая попытка завязать регулировку громкости на стандартные клавиатурные коды в Windows ожидаемо провалилась. Добавление независимого HID-интерфейса Consumer Control мгновенно решило проблему. Этот пример отлично иллюстрирует, что работающий базовый USB-интерфейс — это еще не гарантия полноценного функционирования всех специфических кнопок.
Вторая ревизия печатной платы: работа над ошибками
Первые полевые испытания показали необходимость доработки «железа». Во второй ревизии платы я сохранил общую концепцию подключения, но основательно переработал вспомогательные цепи и заложил задел на будущее. На борту появились аппаратные кнопки BOOT и RESET, оптимизирована система питания, добавлены элементы мониторинга энергопотребления для будущего контроллера подсветки.
Саму подсветку я осознанно вынес за рамки основной матрицы: она запитывается от отдельного шлейфа и управляется автономно. Еще одним полезным апгрейдом стала возможность прошивки микроконтроллера напрямую по USB.
Отказ от обязательного ST-Link
Если первую плату приходилось прошивать через программатор, то на второй плате появилась пара кнопок BOOT и RESET, обеспечивающих доступ к системному бутлоадеру STM32. Это позволяет переводить чип в режим DFU и заливать свежий софт через обычный USB-кабель. Внешний программатор теперь нужен разве что для глубокой отладки.
При этом важно не путать режим USB DFU (используемый для обновления прошивки самого MCU) и USB HID Boot Protocol (стандарт клавиатуры). Несмотря на схожесть терминов, это совершенно разные вещи.
Вторая ревизия платы осталась двухслойной. Трассировка вновь потребовала терпения и времени, так как плотность компонентов возросла. Зато теперь у меня было четкое понимание того, какие схемотехнические решения экономят место, а какие лишь создают проблемы при разводке.
Первое включение и тесты
Самый волнительный момент в любом хардверном проекте — когда после монтажа и прошивки устройство оживает и начинает выполнять возложенные на него задачи. В моем случае компьютер должен был опознать самодельный адаптер как стандартное HID-устройство.
Для тестирования я использовал популярные веб-сервисы проверки клавиатур, поочередно нажимая каждую кнопку. Плата Rev.2 успешно прошла экзамен: заработали все 102 клавиши, навигационные стрелки, медиа-атрибуты и клавиши управления громкостью. Разъем USB-C функционировал корректно при любой ориентации кабеля, а диагностический режим исправно выдавал отчеты в терминал.
Параллельно для логики прошивки были написаны автоматизированные юнит-тесты. На данный момент комплекс включает 151 тест в семи категориях CTest. Они проверяют корректность сканирования матрицы, фильтрацию дребезга, логику антигостинга, формирование HID-пакетов и парсинг команд. Автотесты не заменяют реальное «железо», но позволяют безопасно рефакторить код, не опасаясь сломать уже работающий функционал.
Промежуточные итоги
Конечно, говорить о финале проекта преждевременно. Базовые функции реализованы, однако впереди еще цикл стресс-тестов силовой части питания и проверка энергосберегающих режимов. Тем не менее, главная цель достигнута: ноутбучная клавиатура успешно функционирует отдельно от своего донора.
Что оказалось самым сложным?
Если судить о проекте поверхностно, может показаться, что сложнее всего было развести 26 сигнальных линий на двух слоях текстолита. И отчасти это правда — мне пришлось не раз перекраивать принципиальную схему и перетрассировать плату. Монтаж микроскопической мелочевки под микроскопом также потребовал сноровки.
Но если взглянуть на задачу шире, главное испытание крылось в другом.
Самым трудным оказалось обеспечить бесшовное преобразование хаотичных электрических замыканий неизвестной матрицы в стандартизированные события операционной системы. Мало просто узнать распиновку и опросить строки — нужно было построить математическую модель поведения устройства.
Пришлось экспериментально изучать физику клавиатуры, бороться с паразитным ghosting, писать фильтры дребезга, развязывать диагностику и опрос в реальном времени. Все эти компоненты должны работать как швейцарские часы. Именно поэтому ключом к успеху стали не дорогие компоненты, а возможность глубокой инструментальной диагностики на каждом шаге.
Планы на будущее
Изначально я преследовал лишь одну цель — получить удобную клавиатуру с привычной раскладкой. Теперь, когда техническая база готова, хочется довести проект до логического завершения. Следующая амбициозная задача — запустить штатную RGB-подсветку MSI GS75. С ней всё интереснее, так как она задействует отдельный шлейф и уникальный протокол управления.
Для реверс-инжиниринга подсветки я уже проектирую вспомогательную плату и пишу тестовую прошивку. Этому исследованию я планирую посвятить следующую статью. В перспективе — разработка собственной платы подсветки и интеграция её поддержки в основной клавиатурный контроллер.
Ну и венцом проекта должна стать механика: 3D-сканирование клавиатурного блока, проектирование прочного корпуса и печать его на 3D-принтере. На выходе получится эксклюзивная кастомная клавиатура авторской разработки.
А началась эта история с того, что на рынке просто не нашлось подходящей клавиатуры.
Xiaomi выпустила умный чайник Mijia Smart Health Pot 2 Pro с магнитным фильтром, 11 режимами нагрева и суточной поддержкой тепла
Смартфоны Honor 700 с батареей на 9000 мАч и камерой 200 Мп доступны для предзаказа до официального анонса
М.Видео: денежный объём продаж HDD и SSD вырос на 41,5% год к году
МТС Линк добавил ИИ-отчёт по вопросам и активности участников вебинаров
Застой длиною в 7 лет: Samsung Galaxy S27 не получит более мощную зарядку
Tantor возглавил рейтинг графических платформ управления СУБД CNewsMarket
На Земле обнаружили марсианский метеорит возрастом свыше 4,1 млрд лет
Начало магнитной бури ожидается в ночь на 31 октября