auspex: an open 5x12 Hall-effect keyboard
auspex is an open-source 5x12 ortholinear keyboard with Hall-effect (HE) switches: its own PCB, FR4 plate and case, on open firmware. This page is the hub of the series about it: why it exists, what each part is and why it beat the alternatives, and which page covers which part of the build. It was developed under the working name gridlock, which is the name its board files and firmware still carry.
TL;DR:
- No commercial ortholinear HE keyboard exists (checked 2026-10-10 and 2026-10-26), and a 2026-11-03 survey of open HE PCBs found no 5x12 board either. The closest open ortholinear HE PCB is a 70-key board on a Full-Speed MCU.
- The stack is the one the fab-proven HE60 v2.1 uses: AT32F405RCT7 (on-chip USB 2.0 High-Speed PHY, which is what 8 kHz polling needs), libhmk firmware (QMK upstream has no HE feature set), 8x SN74LV4051A 8:1 muxes, 60x MT9102ET Hall sensors.
- Scan rate is 8 select steps x (mux settle + 8 ADC conversions): at most ~11.4 kHz computed at the shipped 5 us settle, ~14.0 kHz at 3 us (upper bounds; timer and DMA overhead not counted). The real settle comes from a sweep at bring-up.
- Every part is on the bottom layer, so the board is assembled on one side; the switches have no electrical pins, so the build needs no soldering.
- The pre-fab review found the USB data pair routed as two uncoupled traces on rev 1. It may still enumerate at High-Speed; bring-up has to prove it. A custom DRC rule now flags the pair, and the gate holds rev 1’s violations as a known baseline that fails on any new one.
Why it exists
Section titled “Why it exists”The author types on a 5x12 ortholinear board (a Boardsource Equals 60; its QMK keymaps are in Creating QMK, VIA, and Vial keymaps) and wanted the HE gaming features on that layout: a per-key actuation point, rapid trigger, per-key calibration and 8 kHz polling. Two searches came back empty:
- Commercial: no ortholinear HE or TMR keyboard was on sale when checked on 2026-10-10 and re-checked on 2026-10-26.
- Open source: the 2026-11-03 GitHub survey found no 5x12 HE board. The closest open ortholinear HE PCB is KHEops70 (13x5+5 = 70 keys, STM32F303, GPL-3.0, fab files published), then HE75 (75 keys in a GH60 outline, no licence file, and its README says “I haven’t ordered the first set of boards yet”).1 Every other open HE PCB found is row-staggered, split or a macropad.2
The layout is new; the circuit blocks come from peppapighs’ HE60 v2.1, a 60% staggered HE board released 2026-04-29 with its BOM and pick-and-place files, on the same MCU, mux, sensor and firmware.3 HE60 is GPL-3.0, auspex copies its symbols and footprints, and so the whole auspex project is GPL-3.0.
What it is
Section titled “What it is”| Item | Value | Source |
|---|---|---|
| Layout | 5 x 12 = 60 keys, 1u | board definition |
| Polling target | 8 kHz (one report per 125 us) | libhmk on AT32F405 |
| Scan rate | at most ~11.4 kHz computed at 5 us settle | arithmetic, below |
| Features | per-key actuation, rapid trigger, null bind (SOCD), dynamic keystroke, tap-hold, automatic calibration, XInput, web configurator | libhmk v1.8.14 |
| Profiles / layers | 4 / 4 | keyboard.json |
| Board | 230.60 x 97.25 mm, 4 layers, 1.6 mm | board file |
| Switches | Gateron Magnetic Jade Ultra (KS-20 family), 30/40 gf, 3.2 mm travel | Gateron product page5 |
| Licence | GPL-3.0 | follows from the HE60 reuse |
Architecture
Section titled “Architecture”The sensors, the muxes and the MCU’s analog supply (VDDA) share one LDO rail, as on HE60, so supply noise moves the sensor output and the ADC reference together. Each sensor sits on the bottom of the PCB directly under its switch’s stem, where the switch’s magnet is, and reads the field through the board.6
Which part, and why
Section titled “Which part, and why”MCU: AT32F405RCT7
Section titled “MCU: AT32F405RCT7”8 kHz polling means one HID report per USB High-Speed microframe (125 us). Full-Speed USB (12 Mbps) caps polling at about 1 kHz, so the MCU needs a High-Speed (480 Mbps) port and, to stay single-chip, an on-chip High-Speed PHY.
| MCU | USB | Open HE firmware | Verdict |
|---|---|---|---|
| AT32F405RCT7 | High-Speed, on-chip PHY7 | libhmk (at32f405xx backend, 8 kHz) | picked |
| RP2040 / RP2350 | Full-Speed only (USB 1.1 controller and PHY)89 | QMK forks and modules | 1 kHz ceiling |
| STM32F446 | no High-Speed PHY on chip | libhmk (stm32f446xx, Full-Speed) | 1 kHz ceiling |
| STM32F303 (KHEops70, HE75 lineage) | Full-Speed | QMK forks | 1 kHz ceiling |
| WCH CH32V307 | High-Speed, on-chip PHY | none; a libhmk port would be needed | fallback if AT32 stock runs out |
The AT32F405RCT7 is a 216 MHz part in LQFP-64 and one 12-bit ADC with up to 16 external channels (auspex uses 8).7 Its High-Speed PHY takes its 480 MHz clock from a PLL on the external 12 MHz crystal, and the datasheet rules out every other clock source, so the 12 MHz crystal is mandatory; keyboard.json carries it as "hse_value": 12000000. The CH32V307 row is there because it is what the Venom 60 HE class of commercial boards appears to use (from a teardown of the related Venom 87 HE, not the 60 itself), with TI TMUX1308 8:1 muxes; it has the PHY and no open HE firmware.10
On 2026-11-03 JLC listed 209 AT32F405RCT7 in stock. Stock and prices perish; check them at order time.
Firmware: libhmk
Section titled “Firmware: libhmk”QMK upstream has no HE feature set. The feature request “Standard functions for analog keyboards”, opened 2025-12-13, drew a reply that nothing like it exists in QMK (from a contributor building HE support in a fork), and GitHub’s stale bot closed it as not planned on 2026-05-26 with no maintainer decision.11 The maintained open HE firmware with High-Speed USB support is libhmk (GPL-3.0, pinned at v1.8.1, commit 1d2b2e2).4 It is configured from a web app without recompiling, so the board definition is one keyboard.json and the keymap moves to the configurator.
libhmk’s HID descriptor sets the polling interval to 1 microframe (8 kHz) when its high polling rate option is on, and to 4 (2^(4-1) = 8 microframes, 1 kHz) when it is off.12 8 kHz has a cost on the host: the PC has to service the USB controller every 125 us, and Fixing merged reports from an 8 kHz mouse on Windows shows what a late DPC does to that.
libhmk also smooths every key with an exponential moving average (alpha 1/16, overridable), updated once per main-loop pass. The lag it adds depends on the loop rate, which has not been measured yet.
Muxes: 8x SN74LV4051A, shared select
Section titled “Muxes: 8x SN74LV4051A, shared select”Eight 8:1 analog muxes give 64 positions for 60 keys; the 4 spare channels are tied to ground, as HE60 v2.1 does with its 3 (9 muxes, 72 positions, 69 keys). All eight share the three select lines (MUX_SEL0..2 on PB5-PB7), and each mux output goes to its own ADC pin, so one select step presents 8 sensors at once.13 The 2026-10-10 plan had four 16:1 CD74HC4067s, which need 16 select steps per scan against 8. All four boards in libhmk’s keyboards/ directory use parallel 8:1 muxes, and libhmk’s scan code assumes that layout: shared select lines, one ADC channel per mux.
TI’s TMUX1308 is a pin-compatible alternative (only pin 7 differs, ground vs not connected), cheaper on 2026-11-03 at JLC ($0.2416 vs $0.3442 at quantity 1).14 Its on-resistance is about 4 times higher: 120 ohm typical at 3.3 V against the SN74LV4051A’s 30 ohm typical at 3 V (the LV4051A has no 3.3 V row). Both are far below the AT32 ADC’s source-impedance limit at 7.5-cycle sampling.
Sensors: 60x MT9102ET
Section titled “Sensors: 60x MT9102ET”The MT9102ET is a ratiometric linear Hall sensor in SOT-23: 1.600 mV/Gs typical at 3.3 V, 6.0 mA typical, with a range of only +/-850 Gs at 3.3 V.15 HE60 v2.1 uses it 69 times. The range sets the switch choice: the Gateron KS-20 White and Orange are specified at 905 +/-80 Gs at bottom-out, above the sensor’s +/-850 Gs range, so they were ruled out (a 1.6 mm board lowers the field at the sensor, by an amount nobody has measured). The Jade Ultra that was bought is specified at 122 Gs at rest and 550 Gs at bottom-out, over a 1.2 mm PCB, which leaves headroom under 850 Gs.5 All switches on a board must have the same magnet polarity: polarity decides which way the sensor output moves, and libhmk’s invert_adc is one setting for the whole board.
Sixty sensors at 6 mA is 360 mA on the analog LDO. The review put the TLV75733 in its SOT-23-5 package at about 0.6 W, with the junction near 150 C at 40 C ambient on the JEDEC thermal estimate. HE60 v2.1 runs the same part with 69 sensors (414 mA), and the 4-layer planes sink heat better than the JEDEC test board, so the regulator’s temperature gets measured at bring-up before anything changes.
Scan rate arithmetic
Section titled “Scan rate arithmetic”One full scan is 8 select steps. Each step waits for the muxes to settle, then converts the 8 ADC inputs in turn:
scan time = 8 x (settle + 8 x conversion)
One conversion at libhmk’s 7.5-cycle sample time is 7.5 + 12.5 = 20 ADC cycles. libhmk divides the 216 MHz AHB clock by 8, so the ADC runs at 27 MHz (the datasheet maximum is 28 MHz): one conversion takes 0.741 us, and the 8 conversions in a step take 5.93 us.7
| Mux settle | Scan time | Scan rate | Status |
|---|---|---|---|
| 20 us (libhmk default) | 207.4 us | ~4.8 kHz | computed |
5 us (shipped, "delay": 5 in keyboard.json) | 87.4 us | ~11.4 kHz | computed |
| 3 us | 71.4 us | ~14.0 kHz | computed; only if the muxes settle that fast |
All three rows are arithmetic on datasheet values and are upper bounds: the formula leaves out the timer start and DMA interrupt time in each select step. The settle time the board needs is found at bring-up by sweeping analog.delay with one key bottomed out and watching the next channel on the same mux: crosstalk there means the mux has not settled. A sample is on average half a scan old, about 36 us at 14 kHz, so going past ~14 kHz with more muxes could save at most that much; it is not a goal.
Board: 4 layers, one side, no solder
Section titled “Board: 4 layers, one side, no solder”| Layer | Carries |
|---|---|
| F.Cu | signals + ground fill |
| In1.Cu | +3V3A analog supply plane |
| In2.Cu | ground plane, next to the parts layer |
| B.Cu | every part, most routing, ground fill |
HE60 is a 2-layer board. Moving to 4 layers puts a continuous ground plane under the muxes, the MCU and the routing, with a copper-free window under each sensor, and a plane on the analog rail. The layer survey of open HE boards found that every fabricated one leaves a copper-free window over each sensor; auspex has 60 of them, with no vias and no fill, on F.Cu, In1.Cu and In2.Cu.
Every part is on B.Cu because JLC’s Economic PCBA assembles one side only, and double-sided assembly forces the Standard service with higher setup and stencil costs. The switches go on top and need nothing electrical from the board: the KS-20 has no leads to solder, only plastic pegs and a magnet on the stem axis. Gateron lists the Jade Ultra in the KS-20 family (SKU KS-20GFW10B045NW-Y106);5 no Ultra drawing was found, so the footprint follows the KS-20 White drawing, two holes of 1.70 +/-0.05 mm,16 which HE60’s footprint drills at 1.75 mm.6 The switches clip into the FR4 plate, and the plate is screwed to the PCB with M2x10 screws through 3.4 mm spacers, 5.0 mm from plate top to PCB top as the MX figure asks. On an HE board, flex between the plate and the sensors reads as key travel, so any softness belongs between that plate-PCB pair and the case. With the PCBA from the fab, the assembly is screws, switches and keycaps, with no soldering iron.
The order, including the 4-layer form settings that keep Economic PCBA available, is in Ordering a 4-layer bottom-side PCBA and FR4 plate at JLC.
What the pre-fab review found
Section titled “What the pre-fab review found”Five automated reviewer agents ran in parallel (electrical, PCB and fab, firmware, mechanical, tooling and docs) after rev 1 was ordered, and a judge agent checked the evidence behind each finding that affects the design. Of 17 findings, this is the one that bears on the 8 kHz goal:
| Finding | Evidence | Consequence |
|---|---|---|
| The USB data pair between the ESD part and the MCU is routed as two separate, uncoupled traces | sampling every 0.1 mm of D+: 9.8 mm sits 5 mm or more from D-, 16.2 mm at 2-5 mm, only 1.2 mm within 0.5 mm; HE60 runs its pair within 1 mm for 70 mm | estimated 100-116 ohm differential against the 90 ohm +/-15 % target; the run is about 30 mm, so it may still enumerate at High-Speed. Bring-up has to prove High-Speed first |
The reviewer called the routing tolerable for a Full-Speed link; the judge raised it to a rev 1 risk because the link is High-Speed, the reason the board uses an AT32F405. The autorouter does not couple the pair, so the rev 2 fix is in the rules: the board’s custom DRC rules now require the pair to be coupled (gap 0.10-0.25 mm, at most 5 mm uncoupled, at most 1.0 mm skew). Rev 1 breaks all three (gap up to 5.1 mm, 32 mm uncoupled, 2.9 mm skew); the gate holds those exact violations as a known rev 1 baseline that a rev 2 change must remove, and any other hit fails it. How the checks are built, and how each one is shown to fail on a known-bad board, is in A PCB as code, and proving its checks.
Two other findings affected the case: the milled cavity’s inside corners collided with the PCB’s square corners and with a square brass weight, and the case checks had passed both. Those are in A keyboard case in build123d with DFM checks.
Artery’s AN0290 reference design
Section titled “Artery’s AN0290 reference design”Artery publishes its own AT32F405 magnetic-keyboard demo: a 68-key board with 8 kHz polling and a 16 kHz scan, with application note AN0290 v2.0.0 (2026-01-22) and a 9-page schematic.17 The repository has no PCB layout and no licence file, so its ideas can be read but its files cannot be copied. It was found after rev 1 was ordered, so nothing in it changed rev 1; it is the second data point for rev 2.
| Block | Artery AN0290 | auspex rev 1 (HE60-derived) |
|---|---|---|
| Hall sensor | HX49ESO x68 | MT9102ET x60 |
| Sensor and mux supply | 4.65 V from a buck-boost then an adjustable LDO, ferrite on its input | +3V3A from a TLV75733 on VBUS |
| Analog mux | ADG708 x9 on the 4.65 V rail | SN74LV4051A x8 on +3V3A |
| ADC inputs | series resistor + unpopulated capacitor footprint per input | direct |
| Reference check | 2.5 V reference into an ADC channel to track supply drift | none |
| Select lines | PC13-PC15 | PB5-PB7 |
| Filtering | EMA plus two Kalman filters | EMA (libhmk) |
A higher sensor supply gives a larger output span per gauss, and the mux’s on-resistance is one term in the settle time the scan-rate table depends on. Both designs need the same two things for the PHY: the 12 MHz crystal and a 12k resistor on OTGHS1_R.
Status
Section titled “Status”| Item | State on 2026-11-05 |
|---|---|
| Rev 1 PCB (4-layer, PCBA) and FR4 plate | ordered 2026-11-04 |
| Switches | bought (Jade Ultra) |
| Firmware | builds; keyboard.json validates against the pinned libhmk schema |
| Case | modelled; FDM and CNC variants with printability checks |
| High-Speed enumeration, 8 kHz, scan rate, settle, noise floor | not measured; bring-up |
| USB vendor and product IDs | placeholder |
| Calibration defaults | HE60 values, placeholders until bring-up |
Series map
Section titled “Series map”| Page | Type | Covers |
|---|---|---|
| This page | reference | why the board exists, the stack and why, the review, status |
| Keyboard typing height | reference | desk-to-keytop height: what the standard asks for, and how case, plate and keycap profile add up |
| A PCB as code, and proving its checks | reference | schematic, placement and routing from code, the gates, and fault injection that proves each gate fails |
| Ordering a 4-layer bottom-side PCBA and FR4 plate at JLC | guide | the order pack, the form settings, rotation checks |
| A keyboard case in build123d with DFM checks | guide | the case from code, collision and printability checks, FDM and CNC |
Two more pages follow once there is something to write them from: porting a QMK keymap to libhmk, and bring-up with the measured numbers.
Which do I pick
Section titled “Which do I pick”For someone building an HE board of their own, the choices above reduce to this:
- If you need 8 kHz polling, you need an MCU with an on-chip USB High-Speed PHY. If 1 kHz is enough, a Full-Speed MCU works: STM32F446 with libhmk, or an RP2040 with a QMK fork.
- With a High-Speed PHY, AT32F405 with libhmk is the combination with maintained open firmware. CH32V307 has the PHY but needs a libhmk port; it is the fallback if AT32 stock runs out.
- If an open HE board already exists in your layout, start from it. If not (a 5x12 ortholinear has none), build the layout new from the HE60 v2.1 blocks on the same stack.
References
Section titled “References”-
jridgewell, “HE75,” GitHub. https://github.com/jridgewell/HE75 ↩
-
mgsg, “KHEops70,” GitHub. https://github.com/mgsg/KHEops70 ↩
-
peppapighs, “HE60,” GitHub. https://github.com/peppapighs/HE60 ↩
-
peppapighs, “libhmk,” GitHub. https://github.com/peppapighs/libhmk ↩ ↩2
-
Gateron, “Gateron Magnetic Jade Ultra Switch Set,” Gateron. https://www.gateron.com/products/gateron-magnetic-jade-ultra-switch-set ↩ ↩2 ↩3
-
peppapighs, “HE60 v2.1 MX-1U footprint,” GitHub. https://raw.githubusercontent.com/peppapighs/HE60/v2.1/HE60/lib/HE60.pretty/MX-1U.kicad_mod ↩ ↩2
-
Artery, “AT32F405/402 Series Datasheet, Ver 2.02,” Artery Technology. https://arterychip.com/download/DS/DS_AT32F405_402_V2.02_EN.pdf ↩ ↩2 ↩3
-
Raspberry Pi, “RP2040 Datasheet,” Raspberry Pi. https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf ↩
-
Raspberry Pi, “RP2350 Datasheet,” Raspberry Pi. https://datasheets.raspberrypi.com/rp2350/rp2350-datasheet.pdf ↩
-
beginms, “Venom 87 HE teardown” (in Korean), blog.beginms.com. https://blog.beginms.com/703/ ↩
-
QMK, “Standard functions for analog keyboards (issue #25875),” GitHub. https://github.com/qmk/qmk_firmware/issues/25875 ↩
-
peppapighs, “libhmk v1.8.1 src/usb_descriptors.c,” GitHub. https://github.com/peppapighs/libhmk/blob/1d2b2e2101fa4509700a24152d33335ddfda8240/src/usb_descriptors.c ↩
-
Texas Instruments, “SN74LV4051A 8-Channel Analog Multiplexer/Demultiplexer,” TI. https://www.ti.com/lit/ds/symlink/sn74lv4051a.pdf ↩
-
Texas Instruments, “TMUX1308/TMUX1309 datasheet, SCDS426E,” TI. https://www.ti.com/lit/ds/symlink/tmux1308.pdf ↩
-
NOVOSENSE, “MT9102 Linear Hall Sensor Datasheet,” NOVOSENSE. https://www.novosns.com/datasheet/MT9102A/MT9102.pdf ↩
-
Gateron, “SPEC-KS-20T-001, Keyboard Switch KS-20TF10B045NW-X72 (magnetic White), specification and drawing,” mirrored in keyboardio keyswitch_documentation, GitHub. https://github.com/keyboardio/keyswitch_documentation/raw/master/datasheets/Gateron/KS20_HallEffect.pdf ↩
-
Artery, “AN0290 AT32F405 High-speed USB Magnetic Switch Keyboard Application Note V2.0.0,” GitHub. https://github.com/ArteryTek/High-Speed_USB_Magnetic_Switch_Keyboard/blob/23ca86e0a9277553377be79047353b366fab71d6/AT32F405/Doc/AN0290_AT32F405_High-speed_USB_Magnetic_Switch_Keyboard_Application_Note_V2.0.0_EN.pdf ↩
Linked from
- A keyboard case in build123d, checked before the vendor checks it
- A PCB as code, and proving its checks work
- Creating QMK, VIA, and Vial keymaps
- Fixing merged reports from an 8 kHz mouse on Windows
- Keyboard typing height: standards, the case stack and keycap profiles
- Ordering a 4-layer keyboard PCBA and plate at JLCPCB