dragonlock2.github.io/_posts/2018-07-17-stm32-gaming-keypad.md
2023-07-09 16:35:04 -07:00

106 lines
5.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: STM32 Gaming Keypad
date: 2018-07-17
categories: projects
excerpt: A fun little keypad mostly used to make sure I don't break my keyboard with how much gaming I do.
header:
teaser: /assets/img/2018/stm32keypad-top.jpg
gallery:
- image_path: /assets/img/2018/stm32keypad-top.jpg
- image_path: /assets/img/2018/stm32keypad-back.jpg
---
<sub>Written 8-28-19</sub>
Since I recently found out about the STM32 Blue Pill board, I saw it as the perfect opportunity to dive right into learning ARM. The STM32 Blue Pill board costs only about $2 on eBay and boasts a number of advantages over standard Arduino boards. The one thing I was always interested in was building a gaming keypad. Of course, I couldve just used an Arduino Leonardo or a Teensy, but then I wouldnt really be learning anything and itd cost more.
After doing some research, I came across this [website](https://notes.iopush.net/stm32-custom-usb-hid-step-by-step-2/) which was invaluable in getting started with using the STM32 as a HID device. The gist is you send reports that contain your input data in the format specified by your device descriptor. With the basics down, I got to designing the keypad.
## Hardware
During the school year, I found out that Arrow was selling Cherry MX switches for $0.22 each. I immediately snatched up 25 Cherry MX Greens for myself. Unfortunately, theyve since gone way up in price, at least for small quantities.
First, I used EasyEDA to design a board that could hold all the switches. Since I just needed a plate to add rigidity and hold switches in place, I didnt add any traces.
{% include figure image_path="/assets/img/2018/stm32keypad-pcb.jpg" %}
Then I launched Fusion 360 and modeled a case for the board.
{% include figure image_path="/assets/img/2018/stm32keypad-cad.jpg" %}
Next I looked into making keycaps. Due to the tight spacing I used to fit 24 switches onto the limited size of my FR4, it wasnt compatible with standard keycaps. Trying some caps on Thingiverse, I found one that had a good fit and was relatively easy to bring into Fusion 360 and modify.
{% include figure image_path="/assets/img/2018/stm32keypad-cap.jpg" %}
After making the PCB using my hybrid mill etch method and printing out the parts, I got to assembly. It was a bit hard cramming all the wires in, but I eventually did it and hot glued everything down.
{% include gallery %}
## Software
After finishing the hardware, I got onto writing the code. I started by making a device descriptor that could send two different reports, one for mouse commands and one for keyboard commands. The computer distinguishes these two reports using a report id. I used this [tool](https://www.usb.org/document-library/hid-descriptor-tool) to help out.
{% highlight C %}
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x06, // Usage (Keyboard)
0xA1, 0x01, // Collection (Application)
0x85, 0x02, // Report ID (2)
0x05, 0x07, // Usage Page (Kbrd/Keypad)
0x75, 0x01, // Report Size (1)
0x95, 0x08, // Report Count (8)
0x19, 0xE0, // Usage Minimum (0xE0)
0x29, 0xE7, // Usage Maximum (0xE7)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x95, 0x06, // Report Count (6)
0x75, 0x08, // Report Size (8)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x65, // Logical Maximum (101)
0x05, 0x07, // Usage Page (Kbrd/Keypad)
0x19, 0x00, // Usage Minimum (0x00)
0x29, 0x65, // Usage Maximum (0x65)
0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, // End Collection
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x02, // Usage (Mouse)
0xA1, 0x01, // Collection (Application)
0x85, 0x01, // Report ID(1)
0x09, 0x01, // Usage (Pointer)
0xA1, 0x00, // Collection (Physical)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (0x01)
0x29, 0x03, // Usage Maximum (0x03)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x95, 0x03, // Report Count (3)
0x75, 0x01, // Report Size (1)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x95, 0x01, // Report Count (1)
0x75, 0x05, // Report Size (5)
0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x09, 0x38, // Usage (Wheel)
0x15, 0x81, // Logical Minimum (-127)
0x25, 0x7F, // Logical Maximum (127)
0x75, 0x08, // Report Size (8)
0x95, 0x03, // Report Count (3)
0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
0xC0, // End Collection
0xC0, // End Collection */
// 95 bytes
{% endhighlight %}
After that I wrote the structs for the reports and the code to handle each switchs keypress. Heres my [code](https://gist.github.com/dragonlock2/ae8e986bfac5201c19ba32f75179c6cb). I dont like the large, repetitive switch case statement, but its what I came up with at the time and is pretty user friendly. Its currently setup to play Destiny 2.
#### Sources: (Check these out!)
- <https://notes.iopush.net/stm32-custom-usb-hid-step-by-step-2/>
- <https://eleccelerator.com/tutorial-about-usb-hid-report-descriptors/>
- <https://www.usb.org/document-library/hid-descriptor-tool>
- <http://eleccelerator.com/usbdescreqparser/>