Comments 61
Поражает упорство , и есть результат!
Без обид, столько было затрачено сил, при этом в самой клавиатуре ничего толком не поменялось по сравнению со стоком - какой в этом был смысл? Своя прошивка?
Если Вы хотели клавиатуру только с low-profile и подсветкой - чем не подошел Havit/Keychron?
Я тоже разрабатываю свою клавиатуру, но именно потому, что найти то, что я хочу в продаже просто не реально. А хочу я, на самом деле много:
low-profile brown
даблшоты
подсветку символов, а не щелей
возможность изменения подсветки при смене языка, и вообще апи для нее
полную, нормальную раскладку с г-образным Enter и нормальной длиной шифтов.
отстегивающуюся на магнитах подставку под запястье
отстегивающийся на магнитах num-pad, который можно пристегнуть как слева, так и справа + он может отдельно работать сам по себе по USB
регулятор громкости в виде ролика (а не крутилки) над стрелкой курсора "вправо"
такой-же регулятор над стрелкой курсора "влево", отвечающий за яркость подсветки и ее переключение
медиа-клавиши плей/пауза/вперед/назад и индикаторы клавиатуры снизу под пробелом
верхняя часть клавы полностью из куска гнутого алюминия
Еще раз - не в коем случае не хочу ничем обидеть - но у вас не понятно зачем кастом и внешний вид весьма на любителя, при этом очень много сил было потрачено.
Думаю что автор получил удовольствие от процесса разработки и прокачал разные навыки.
Скорее всего после какого-то времени он задумается над улучшениями и сможет сделать себе улучшенную версию соответстующую его желаниям.
Кстати, вот я бы (это моё личное имхо) отказался от цифровой части клавиатуры, как-то не использовал её никогда, да и место она на столе занимает. В своё время купил себе tenkeyless клавиатуру и пользуюсь ей уже много лет.
Тут скорее не разработка ради клавиатуры, а клавиатура ради разработки и изучения.
Если рассматривать эту клавиатуру, как цель, то она мало того, что не стоит того, так и выходит дороже готовой от Logitech (на момент когда та стоила до 10к).
А так сейчас стоят low-profile brown; подсветка символов, а не щелей (на фото видна подсветка щелей, но я по максимуму закрыл кейкапом свет и глазами этот ареол не виден, так как это мне тоже не нравится на ноутбуке); спасибо за идею по изменению подсветки при смене языка, нужно будет подумать над этим, идея здравая. А остальное, это всего первая и последняя попытка, повторять вышеуказанное в статье я не планирую)
клавиши плей/пауза/вперед/назад и индикаторы клавиатуры снизу под пробелом
А почему не над F1-F12?
отстегивающийся на магнитах num-pad
Великолепная идея:)
Я почему-то тоже ожидал чего-то интересного в стиле Corne/Jorne/Dao, Dactyl Manuform или ещё каких-то вариантов. Ведь там открывается буквально кроличья нора! А тот вариант, который сделал автор, можно купить в магазине, зачем паяльник брать в руки даже не очень понятно.
Не, конечно, каждый развлекается как хочет, но всё же это же сколько времени на сборку, документирование процесса, а потом ещё и статью оформить...
Я бы добавил беспроводной интерфейс с беспроводной зарядкой от встроеной в стол зарядки
Сначала хотел поставить HC-05 (перешитый в RN-42), чтобы была возможность подключения по BT, но все беспроводные клавиатуры (в моем случае) всегда висели на USB-зарядке. Ещё в BT в стандартном HID (в RN-42) только один девайс - либо клавиатура (массив дескриптора для передачи передается по UART в BT-модуль), либо мультимедийное устройство. Не увидел возможности одновременной передачи и клавиатуры и мультимедиа. Возможно, нужно повнимательней почитать.
Правильно ли я понимаю, что выбранные свичи упираются в плату? А как усилие нажатий передаётся с платы на корпус?
Можно сэкономить точки пайки, использовав сдвоенные диоды в корпусе sot-23
По опыту (правда с "высокими" свичами) широкие кейкапы на 1 свиче без стабилизатора -- оч. хреново. Со стабилизаторами -- замечательно. Заодно и пробел можно один широкий, а не расщеплённый.
Для быстрой разборки свичей можно было бы напечатать открывашку вроде такой: https://www.thingiverse.com/thing:3097933
Для чего нужны диоды в матрице? Ведь можно при сканировании переключать на выход текущую строку, а остальные переводить в z-состояние.
В таком случае возникают коллизии или фантомные нажатия (если я правильно вас понял), когда в матрице 2х2 нажаты любые три кнопки, то четвертая тоже становится "нажатой". Для обычной работы этим можно пренебречь.
Ожидал от кастома, что это будет наконец-то клавиатура без ограничений на количество нажатых клавиш. Я ошибался?
Ничто не мешает организовать Nx6KRO.
NKRO можно организовать двумя способами:
Использовать Custom HID, а на ПК ответная часть, но тогда увеличится input lag
Организовать внутри несколько точек монтирования, в таком варианте каждая точка монтирования добавляет 6 одновременно нажатых клавиш. Стандарт HID не предоставляет возможности сделать "стандартную NKRO" клавиатуру, только с такими "Хаками". Так делают почти все бренды. 2 точки монтирования для клавиатуры я делал, с моей не решённой проблемой получалось 10KRO
А разве нельзя быть HID-клавиатурой на фулспиде? Тогда вроде как и размер пакета 64 байта, в него дофига сканкодов влезет.
Как я понял из стандарта, HID дескриптор отчёта для клавиатуры определен однозначно. Чтобы использовать полный пакет в 64 байта, нужно становиться Custom HID девайсом и обрабатывать данные на уровне софта на ПК.
Я конечно могу ошибаться, но как минимум, любая нестандартная конфигурация HID клавиатуры не будет работать в BIOS.
И то верно.
Вот так выглядит термин "Изобретать велосипед" в исполнении электронщиков.....
Сколько времени занял весь процесс?
Глядя на все эти принтеры и распечатки мне вспомнился человек с паяльником для полипропилена
Человек, к которому в руки попадает пяльник для полипропилена - опасен для окружающих. Он начинает паять. Сначала он паяет то, ради чего паяльник заводился - воду себе. Потом паяет воду соседу. Паяет воду знакомым и малознакомым людям. Потом он начинает паять то, что к воде отношения не имеет: ПП санки, вешалки. Когда дома большая часть мебели и детских игрушек становится из ПП, он несколько сбавляет темп, но... грядёт весна, и человек выезжает на дачу. И вот над садоводческим товариществом разносится его радостный крик, и на участке, трубы которого быстро меняются на полипропилен, начинают возводится строения из белых труб: теплицы, беседки, заборы, поддержка для растений. Человек сделал бы из ПП мангал, но тут никак - не держит, собака, температуру!
А из-за массивного, устрашающего и наводящего на мысли о Мордоре забора на человека, мучающегося с полипропиленовым мангалом, поглядывает сосед со сварочным аппаратом. У него - свой путь.
Поэтому шутки шутками, а и паяльник для полипропилена нужен, и сварочный хотя бы MMA инвертор не менее обязателен одновременно и независимо. :)
Человек сделал бы из ПП мангал, но тут никак - не держит, собака, температуру!
А если бы он хорошо учил физику в школе...
какое счастье, что я с пайки медных труб начал...
Не нашел в свободной продаже стабилизаторов на длинные кейкапы, стал делать без них. По этой причине пробела – два (таких решений встречал много).
А если сделать одну длинную клавишу, которая будет одеваться на оба переключателя? Они же включены параллельно и выдают один и тот же код при нажатии любой?
Только наверное будет лучше разнести их больше, чтобы при нажатии на один из краёв второй не стремился сняться со свича на другой стороне.
В тестовом варианте был единый длинный пробел, который надевался на оба переключателя (кстати, клавиши опрашиваются независимо), но нажимается такая конструкция очень "криво". Один переключатель нажат, второй не нажался, все перекашивает и переключатели начинают покусывать. Если в центр нажимать, то необходимо прикладывать двойное усилие, в общем, моя первостепенная такая идея провалилась.
Для той-же клавиатуры Logitech с подсветкой был хитрый ход - кнопки снимались и красным маркером изнутри красились русские буквы - было ещё нагляднее.
А так - да, здорово! Я думал только меня бесит короткий левый Shift.
Ну и теперь её еще и беспроводную-бы:)
А Enter однорядный по той же причине, по которой два пробела?
Видимо прямоугольные клавиши делать гораздо проще, чем более сложной формы (у ISO она же шестиугольная).
Кстати, при прочих равных характеристиках клав, я предпочту ANSI всем остальным вариантам (хотя в данный момент набираю на раскладке ISO, т.к. варианта с ANSI не было).
Да, как ответил товарищ Grey83, прямоугольные сделать проще. Я не был уверен, что такая поделка дойдет до конца, но если это случится (а это случилось), не хотелось иметь непонятных проблем с одной клавишей, которая нажимается достаточно часто (по сравнению с длинным RightShift, который без стабилизаторов себя чувствует не на 100%). Подумал, что "в следующей версии сделаю лучше, но никакой следующей версии не планирую, наигрался =)
kailр choc v2 свитчи позволили бы не печатать капы, использовать стандартные стабилизаторы, и следовательно меньше гемора. из вариантов существует также возможность купить свитчи с укороченым ходом до срабатывания (1мм против 2) при стандартной длине хода в 4мм + о-ринги которые бы укоролили ход и сделали бы конец нажатия мягким как на ножничной мембранке. и тогда бы вообще бы не возникло даже малейшего гемора относительно всей остальной обвязки
Пользуюсь вот такого же формата клавиатурой, с клавишами Scissors как у ноутбука- a4tech fx60h, ничего не изобретал, пошел и купил за 3к, не стал бы тратить столько времени на то что можно купить.
Цель данного девайса не в самом девайсе, а в получении опыта с каким-никаким полезным результатом. Я очень надеялся, что даже по поверхностной оценке трудозатрат это будет явно видно. Если просуммировать все потраченное время и посчитать "упущенную экономическую выгоду", то можно купить не один десяток готовых клавиатур. Сделал просто потому что "смог". Кто-то марки собирает, кто-то авиамоделированием занимается, а у меня такое "странное" хобби, которое приносит не экономическую выгоду, а эмоциональное удовлетворение.
Не думали в качестве прошивки взять qmk https://github.com/qmk/qmk_firmware ?
К ней есть приложение для макросов и совместимость с конфигуратором rgb подсветки. И про nkro там разведано.
Про qmk видел, знаю что эту прошивку используют почти все, кто делает кастомы. Настраиваемые уровни через GUI, да и в целом, сообщество реализовало много удобных функций, но хотелось поработать с USB на stm32. Это же хардкорный кастом)
PS: спасибо за ссылку, там как раз описаны проблемы с nkro, о которых я отвечал в комментариях. Поизучаю вопрос с неработающей (у меня) 6й клавишей в 6kro.
Добавьте в свою клавиатуру sd карту. Тогда можно будет использовать как аппаратный менеджер паролей. Сразу проект обретёт новое качество.
В целом, прошивка занимает половину памяти, можно организовать MassStorage девайс (на 32кб, что бы он появлялся только при определенных комбинациях), который будет виден как флешка. Но пока не думал о таком.
Планировал разобраться с MassStorage для реализации обновления прошивки, но пока нет времени
Каким образом клавиатура узнает в какую комбинацию ей включать светодиоды numlock?
Там какой-то протокол есть для этого?
Какой mcal вы использовали для stm32:HAL, SPL, libopencm3 и т п.?
Я так понимаю, что многие используют таймер для управления адресными светодиодами из-за простоты, мирясь с чудовищным потреблением памяти (2 байта на бит) или извращаясь с двойным буфером и докидыванием в него на лету. Между тем конкретно на этом контроллере можно запустить управление светодиодами на SPI с потреблением 1 байт на 2 бита и уложиться в допуски по таймингам протокола светодиодов (да, выбор делителя для SPI довольно бедный - только степени двойки, но, т.к.используется USB, то, из-за особенностей системы тактирования этого контроллера, как раз удачно попадаем на нужные тайминги). Или запустить на UART в режиме 7+1 с инверсией выходного сигнала - потребление памяти составит 1 байт на 3 бита (а т.к. 1 светодиоду требуется 24 бита, то как выходит 8 байт на светодиод, что в 6 раз меньше, чем с таймером).
Спасибо, видел реализацию на SPI, но мне хотелось поработать с таймерами на STM32 (сейчас работаю с ШИМ, полумостами и аппаратной защитой), спасибо за информацию, нужно изучить вопрос.
А еще пока писал статью, осознал, что массивом из START_COUNT[48] для генерации сброса, можно было пренебречь. Есть нулевой байт для ШИМ в STOP_COUNT, а так как вызов передачи происходит раз в 10мс, то сброс будет точно реализован.
Чему должна равняться константа HID_EPOUT_SIZE?
Чему должна равняться константа HID_EPOUT_ADDR?
Их нет в STM32_USB_Device_Library.
И потом, получили Вы массив rx_buf, а как его интерпретировать?
Какие байты и биты отвечают за состояние тех трех светодиодов на клавиатуре для xxxLock(ов)?
Битовая последовательности задана в HID_KEYBOARD_ReportDesc
rx_buf - указатель на массив uint8_t. В ReportDescriptor мы хотим получить 1 байт данных, соответственно в полученном rx_buf[0] содержатся состояния светодиодов.
L_NUMLOCK - 0й бит;
L_CAPSLOCK - 1й бит;
L_SCROLLLOCK - 2й бит
Константы:
HID_EPOUT_ADDR = 0x01U
HID_EPOUT_SIZE = 0x01U
Я тоже добавил в свою прошивку USB-Device функцию USBD_HID_DataOut
uint8_t rx_buf[CUSTOM_HID_EPOUT_SIZE] = {0};
uint8_t USBD_HID_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum) {
uint8_t err=USBD_FAIL;
HAL_StatusTypeDef ret=HAL_ERROR;
ret = HAL_PCD_EP_Receive(pdev->pData, CUSTOM_HID_EPOUT_ADDR, rx_buf, CUSTOM_HID_EPOUT_SIZE);
if (HAL_OK==ret) {
err = USBD_OK;
}
return err;
}
uint8_t* USBD_HID_GetData(void) {
return rx_buf;
}
Однако точка остановка показывает, что функцию USBD_HID_DataOut никто не вызывает.
Как сделать так чтобы микроконтроллер вызывал функию USBD_HID_DataOut ?
Какой код должен вызывать USBD_HID_DataOut и при каких условиях?
А если вызывать функцию HAL_PCD_EP_Receive вручную
ret = HAL_PCD_EP_Receive((PCD_HandleTypeDef *) &Node->hpcd_USB_OTG, hid_epout_addr, rx_buf, size);
то она всегда возвращает нули.
в usbd_hid.c:
USBD_ClassTypeDef USBD_HID =
{
USBD_HID_Init,
USBD_HID_DeInit,
USBD_HID_Setup,
NULL, /EP0_TxSent/
NULL, /EP0_RxReady/
USBD_HID_DataIn, /DataIn/
USBD_HID_DataOut, /DataOut/
NULL, /*SOF */
NULL,
NULL,
USBD_HID_GetHSCfgDesc,
USBD_HID_GetFSCfgDesc,
USBD_HID_GetOtherSpeedCfgDesc,
USBD_HID_GetDeviceQualifierDesc,
};
Как понять по какому принципу формируются эти магические циферки в массиве
HID_KEYBOARD_ReportDesc ?
Hidden text
__ALIGN_BEGIN static uint8_t HID_KEYBOARD_ReportDesc[HID_KEYBOARD_REPORT_DESC_SIZE] __ALIGN_END = { 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x06, // USAGE ID (Keyboard) 0xA1, 0x01, // COLLECTION (Application) 0x85, 0x01, // Report ID (1) 0x05, 0x07, // USAGE_PAGE (Keyboard) 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x75, 0x01, // REPORT_SIZE (1) 0x95, 0x08, // REPORT_COUNT (8) 0x81, 0x02, // INPUT (Data,Var,Abs) ;Keys byte 0x05, 0x07, // USAGE_PAGE (Keyboard) 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x65, // LOGICAL_MAXIMUM (101) 0x75, 0x08, // REPORT_SIZE (8) 0x95, 0x06, // REPORT_COUNT (6) 0x81, 0x00, // INPUT (Data Array) 0x05, 0x08, // USAGE_PAGE (LEDs) 0x09, 0x01, // Usage (Num Lock) 0x09, 0x02, // Usage (Caps Lock) 0x09, 0x03, // Usage (Scroll Lock) 0x15, 0x00, // Logical Minimum (0) 0x25, 0x01, // Logical Maximum (1) 0x75, 0x01, // Report Size (1) 0x95, 0x03, // Report Count (3) 0x91, 0x02, // OUTPUT (Constant Array) ;LED report padding 0x75, 0x05, // REPORT_SIZE (5) 0x95, 0x01, // REPORT_COUNT (1) 0x91, 0x01, // OUTPUT (Constant Array) ;LED report padding 0xc0, // END_COLLECTION 0x05, 0x0C, // Usage Page (Consumer) 0x09, 0x01, // Usage (Consumer Control) 0xA1, 0x01, // Collection (Application) 0x85, 0x02, // Report ID (2) 0x05, 0x0C, // Usage Page (Consumer) 0x15, 0x00, // Logical Minimum (0) 0x25, 0x01, // Logical Maximum (1) 0x09, 0xB5, // Usage (Scan Next Track) 0x09, 0xB6, // Usage (Scan Previous Track) 0x09, 0xB7, // Usage (Stop) 0x09, 0xB8, // Usage (Eject) 0x09, 0xCD, // Usage (Play/Pause) 0x09, 0xE2, // Usage (Mute) 0x09, 0xE9, // Usage (Volume Increment) 0x09, 0xEA, // Usage (Volume Decrement) 0x75, 0x01, // Report Size (1) 0x95, 0x08, // Report Count (8) 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) 0xC0, // End Collection };
Есть ли возможность, пожалуйста, прислать полный файл в котором прописан массив HID_KEYBOARD_ReportDesc?
Я прописал константы дескриптора как у Вас HID_KEYBOARD_ReportDesc и после пере сборки клавиатура вообще перестала определяться операционкой.
Hidden text
__ALIGN_BEGIN static uint8_t HID_KEYBOARD_ReportDesc[HID_KEYBOARD_REPORT_DESC_SIZE] __ALIGN_END = { 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x06, // USAGE ID (Keyboard) 0xA1, 0x01, // COLLECTION (Application) 0x85, 0x01, // Report ID (1) 0x05, 0x07, // USAGE_PAGE (Keyboard) 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x75, 0x01, // REPORT_SIZE (1) 0x95, 0x08, // REPORT_COUNT (8) 0x81, 0x02, // INPUT (Data,Var,Abs) ;Keys byte 0x05, 0x07, // USAGE_PAGE (Keyboard) 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x65, // LOGICAL_MAXIMUM (101) 0x75, 0x08, // REPORT_SIZE (8) 0x95, 0x06, // REPORT_COUNT (6) 0x81, 0x00, // INPUT (Data Array) 0x05, 0x08, // USAGE_PAGE (LEDs) 0x09, 0x01, // Usage (Num Lock) 0x09, 0x02, // Usage (Caps Lock) 0x09, 0x03, // Usage (Scroll Lock) 0x15, 0x00, // Logical Minimum (0) 0x25, 0x01, // Logical Maximum (1) 0x75, 0x01, // Report Size (1) 0x95, 0x03, // Report Count (3) 0x91, 0x02, // OUTPUT (Constant Array) ;LED report padding 0x75, 0x05, // REPORT_SIZE (5) 0x95, 0x01, // REPORT_COUNT (1) 0x91, 0x01, // OUTPUT (Constant Array) ;LED report padding 0xc0, // END_COLLECTION 0x05, 0x0C, // Usage Page (Consumer) 0x09, 0x01, // Usage (Consumer Control) 0xA1, 0x01, // Collection (Application) 0x85, 0x02, // Report ID (2) 0x05, 0x0C, // Usage Page (Consumer) 0x15, 0x00, // Logical Minimum (0) 0x25, 0x01, // Logical Maximum (1) 0x09, 0xB5, // Usage (Scan Next Track) 0x09, 0xB6, // Usage (Scan Previous Track) 0x09, 0xB7, // Usage (Stop) 0x09, 0xB8, // Usage (Eject) 0x09, 0xCD, // Usage (Play/Pause) 0x09, 0xE2, // Usage (Mute) 0x09, 0xE9, // Usage (Volume Increment) 0x09, 0xEA, // Usage (Volume Decrement) 0x75, 0x01, // Report Size (1) 0x95, 0x08, // Report Count (8) 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) 0xC0, // End Collection };
а это мой набор дескрипторов который по крайней мере приводит к тому, что клавиатура определяется.
/*KeyBoard*/
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x06, // USAGE (Keyboard)
0xa1, 0x01, // COLLECTION (Application)
0x05, 0x07, // USAGE_PAGE (Keyboard)
0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x08, // REPORT_COUNT (8)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x08, // REPORT_SIZE (8)
0x81, 0x03, // INPUT (Cnst,Var,Abs)
0x95, 0x05, // REPORT_COUNT (5)
0x75, 0x01, // REPORT_SIZE (1)
0x05, 0x08, // USAGE_PAGE (LEDs)
0x19, 0x01, // USAGE_MINIMUM (Num Lock)
0x29, 0x05, // USAGE_MAXIMUM (Kana)
0x91, 0x02, // OUTPUT (Data,Var,Abs)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x03, // REPORT_SIZE (3)
0x91, 0x03, // OUTPUT (Cnst,Var,Abs)
0x95, 0x06, // REPORT_COUNT (6)
0x75, 0x08, // REPORT_SIZE (8)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x65, // LOGICAL_MAXIMUM (101)
0x05, 0x07, // USAGE_PAGE (Keyboard)
0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
0x81, 0x00, // INPUT (Data,Ary,Abs)
0xc0 // END_COLLECTION
Как я клавиатуру изобретал