About three months ago I blogged about my first keyboard PCB design, a diode-free PCB for an existing 36-key ergonomic case. Since this summary of my journey into keyboard madness, I learnt how to write my own ZMK keyboard firmware, as a precursor to designing a version with Bluetooth. This time I also had to learn some basic CAD to modify the keyboard case. And here it is, the Gamma Omega "Hesse", a Bluetooth diode-free 36-key ergonomic keyboard.
![]() |
Front & back of the "Hesse" keyboard PCB |
Picking a controller
I initially wanted to just swap out the Raspberry Pi Pico controller used in my Gamma Omega TC36K design for one with Bluetooth support. In theory I could have used a Pico W variant, but ZMK doesn't support their wireless module (yet), and the battery life is thought to be shorter with these controllers. Wanting to stick with the Graph Theory diode-free approach, I looked into what controllers were available with ZMK support, battery charging circuitry, and lots of GPIO pins...
Although on the expensive side, the 30 GPIO nRF52840 based MechWild PillBug would have worked - but unfortunately this has been unavailable for some time.
There was only one real candidate, the Nice!Nano v2 or the cheaper mass produced near clone, the Supermini NRF52840 (aka the ProMicro NRF52840). The catch was these have "only" 21 GPIO pins, and I was using 26 for the TC36K.
Picking a graph
Drawing on my earlier planning surveying bipartite graphs for use wiring a keyboard, before settling on the Tutte-Coxetter Graph for a 6-key rollover keyboard, I had a different front runner: The Hesse Configuration Incidence Graph, also known by the less memorable moniker of the Incidence graph of the affine plane of order 3.
This is only girth 6, just like the Heawood Graph used in the first Graph Theory based keyboard, meaning it has only 4-key roll-over. i.e. Pressing 5 or more keys can be ambiguous, and trigger ghost keypresses. That was what drew me to the girth 8 Tutte-Coxeter Graph for 6-key roll-over, being able to press any 6-keys without worrying about this. On reflection, I think I can work with 4-key roll-over (even though I am using a lot of combos, including lots of 3-key chords for typing Japanese kana).
![]() |
The Hesse Configuration Graph |
So, the Hesse Configuration is 9 points (drawn here in a 3x3 grid) on 12 lines (three vertical, three horizontal, three diagonal down-right, three diagonal up-right). This is on an affine plane, represented here by the curved sections on four of the diagonals (making the flower like design). Each point is on four lines (9x4=36 connections), or equivalently each line crosses three points (12x3=36 connections). The incidence graph is the connectivity of how those 9 points and 12 lines are connected, which is a bipartite graph of 9+12=21 nodes, and 36 edges.
The 9x12 bipartite matrix of that incidence graph becomes the sparse scanning matrix of this keyboard (shown below). The 12 lines become the 12 scanning columns (and literal columns of the keyboard including the left and right thumbs, each with three keys), and the 9 points become the scanning rows (each with four keys).
Sadly I failed to find or invent a pretty way to draw the Hesse Configuration Incidence Graph (21 nodes or vertices, 36 edges), so I have instead opted for this representation of the Hesse Configuration itself (9 points and 12 lines) as the keyboard silk-screen art.
PCB Wiring
Drawing on my past experience with Ergogen and KiCad, turning this graph into wiring went quite easily for me this time, only the back of one envelope was needed for the initial plan! The allocation of keys to matrix elements and scanning matrix rows and columns to GPIO pins was arbitrary and down to how easy it was to layout the PCB traces. A simple analysis with NetworkX didn't flag any problematic key combinations. Here is the matrix with the GPIO pin assignments (defined here in the firmware):
GPIO | D8 | D7 | D1 | D2 | D6 | D9 | 1.07 | D15 | D18 | D19 | 1.01 | 1.02 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
D0 | Q | W | E | R | ||||||||
D10 | Z | B | L3 | R1 | ||||||||
D4 | A | H | U | , | ||||||||
D3 | S | G | Y | L | ||||||||
D16 | X | L1 | M | ; | ||||||||
D14 | C | R2 | N | / | ||||||||
D21 | D | L2 | I | O | ||||||||
D5 | V | R3 | J | . | ||||||||
D20 | F | T | K | P |
The keys here are labeled as per Qwerty, with L3, L2, L1, R1, R2, and R3 for the thumbs:
Q | W | E | R | T | Y | U | I | O | P | |
---|---|---|---|---|---|---|---|---|---|---|
A | S | D | F | G | H | J | K | L | ; | |
Z | X | C | V | B | N | M | , | . | / | |
L3 | L2 | L1 | R1 | R2 | R3 |
GPIO pins P1.01, P1.02 and P1.07 are the trio of extra pins this controller adds in the middle of the board compared to the standard Pro-Micro convention of 18 GPIO pins labelled D0 to D19.
I used the Ergogen router utility to pre-wire the repetitive per column bits, and a KiCad copy-traces tool to reduce manual copy-and-paste as I tweaked the placement of the battery connection and reset switches & regenerated the PCB layout. I also used the new Ergogen keep-out footprint, perhaps my radio keep-out is larger than needed?
Controller differences
Compared to the Raspberry Pi Pico controller used in the original Gamma Omega keyboard and my TC36K variant which was mounted on headers face down, the USB port of the Nice!Nano v2 is lower (within the controller board, not on top of it). I opted to use faux-castellation (no headers) and mount it face up putting the USB port in about the same place, and make the LEDs face up so more visible.
Here is the controller is drawn in KiCad using a pretty Nice!Nano v2 footprint. As can be seen by substituting the equivalent SuperMini nRF52840 clone footprint, their trio of extra pins are offset slightly. I have therefore added a small cut-out at the bottom under the controller in the radio keep-out zone which is to access those offset pins on the clone version (at the locations marked with three circles) by soldering a short jumper:
![]() |
KiCad screenshot of Nice!Nano v2 with cutout at bottom |
Battery circuitry
The Nice!Nano v2 and its clones have built in circuitry for managing a LiPo rechargeable battery, so just two wires to connect - optionally via a physical on/off switch. That was a complication in the case design I avoided by opting to depend on the ZMK deep sleep mode. The catch is that the reset button needs to be available to wake the keyboard back up again.
Having the battery wires soldered directly to the board was not appealing. I am using a JST PH 2.0 battery connection. There are smaller connectors, but there was room in this case design, and you can buy suitable batteries with this connector easily.
ZMK Firmware
I started by writing and testing ZMK firmware for my Raspberry Pi Pico (RP2040) based Gamma Omega TC36K design, after which doing ZMK firmware for the Gamma Omega Hesse was very easy with the smaller matrix and different controller being simple changes. People on the ZMK Discord channel were very helpful.
FreeCAD
Learning enough FreeCAD to make the required case design changes was the hardest and most time demanding part of this project. See my first steps in removing parts from a STEP file. It got easier.
The way I was initially cross checking between KiCad and FreeCAD was a still frustrating (adding the step files of the case to the controller footprint) as the viewer controls are limited. Switching to importing the PCB into FreeCAD with the KiCad StepUpMod plugin for FreeCAD worked much better, and revealed I had missed an important Z-offset earlier.
![]() |
Gamma Omega "Hesse" case and PCB in FreeCAD |
Unlike many controllers, this one lacks an integrated reset button, so this design needs an external reset button. And that means case modifications. I considered a hole on the underside of the case using a through-the-board reverse mounted switch design, but that's impractical for waking up the keyboard. A simple hole in the top of the case and a tall enough vertical button would be easy, but not so pretty and would probably get pressed accidentally. Using part of the case to press a button (like the Forager split keyboard or later Visorbearer 32-key keyboard) would have been elegant, but too much for me as a CAD beginner.
There are sideways reset and on/off switches often used with low profile keyboards, but the case tolerances looked tricky (they might not stick out enough). I opted for a rotated version of the common 6x6mm push switches which come with button shafts of various lengths. I can decide the button length once I have the case and PCB in hand... as long as the hole lines up!
I did copy an idea from the Visorbearer keyboard for a thin bit of the case surface with a light tunnel underneath leading to the LEDs - which in my case are on the controller. I am optimistic these will be visible and muted to a reasonable level (the naked LEDs are a bit bright).
Fabrication
Again, I ordered the case and PCBs from JLCPLC:
- PCB defaults except purple finish, lead free HASL finish, and removed the order number from the board, and asked for the confirmation step. USD $16.50 for five.
- Hesse top case in JLC Black resin (with default sanding finish) at USD $16.55
- Hesse bottom case in random X resin (discouted lucky dip) at just USD $3.72
Their prices were almost exactly the same prices as my TC36K order in July.
I also added a set of Chicago Stenographer keycaps to try out, although with the Hesse being Bluetooth and portable that will probably just get MKB keycaps.
No comments:
Post a Comment