This configuration supports two modes:
- Standalone Mode: Right keyboard acts as central, connects directly to host
- Dongle Mode: Dedicated dongle with display acts as central, both keyboards connect to it
- ZMK CONFIG FOR THE CHARYBDIS 4X6 WIRELESS SPLIT KEYBOARD ZEPHYR 4.1
Here is the BOM for this project: BOM Charybdis 4x6 Wireless
- 1x Seeeduino XIAO BLE (nRF52840) - Dongle central
- 1x Prospector Display Module - Custom OLED display
- 1x Nice!Nano v2 (nRF52840) - Dongle central
- 1x OLED Display (SSD1306, I2C) - Generic OLED module
- 128x32 (0.91" OLED) - Use
dongle_nice_32shield - 128x64 (0.96" OLED) - Use
dongle_nice_64shield
- 128x32 (0.91" OLED) - Use
- Uses zmk-dongle-display module
- 1x Seeeduino XIAO BLE (nRF52840) - Dongle central
- 1x Prospector Display Module - Custom OLED display
- Uses zmk-dongle-screen module (YADS) (currently disabled - Zephyr 4.1 compatibility pending)
- Alternative firmware for Prospector hardware with different features
This repository includes a ZMK Tester Shield (tester_pro_micro) for troubleshooting and testing Pro Micro-compatible boards (Nice!Nano, Seeeduino XIAO, etc.). The tester shield maps all 18 available GPIO pins (D0-D10, D14-D16, D18-D21) to virtual "keys" that output "PIN X" when triggered, helping you verify all GPIO pins are working correctly before assembling your keyboard.
How to use:
- Flash
tester_pro_micro-nice_nano-zmk.uf2to your controller (see Building Firmware) - Connect the board via USB to your computer
- Open a text editor
- Connect a switch or wire from any GPIO pin to GND and trigger it
- The board will output "PIN X" where X is the pin number (e.g., "PIN 14")
The tester runs in USB-only mode (no BLE) and includes two physical layouts for ZMK Studio visualization.
zmk-config-charybdis/
├── boards/ # Module-based shields (Zephyr 4.1+ recommended layout)
│ └── shields/
│ ├── charybdis/ # Charybdis shield configuration
│ │ ├── charybdis.dtsi # Common device tree (keyboard layout, kscan)
│ │ ├── charybdis_layers.h # Shared layer definitions
│ │ ├── charybdis_trackball_processors.dtsi # Shared trackball processing config
│ │ ├── charybdis_right_common.dtsi # Shared right keyboard hardware config
│ │ ├── charybdis_left.conf # Left side Kconfig options (empty)
│ │ ├── charybdis_left.overlay # Left side device tree overlay
│ │ ├── charybdis_right_standalone.conf # Right side Kconfig (standalone mode)
│ │ ├── charybdis_right_standalone.overlay # Right side overlay (standalone mode)
│ │ ├── dongle_charybdis_right.conf # Symlink → charybdis_right_standalone.conf
│ │ ├── dongle_charybdis_right.overlay # Right side overlay (dongle mode)
│ │ ├── dongle_common.dtsi # Base shared dongle config (all variants)
│ │ ├── dongle_nice_common.dtsi # Nice!Nano platform common config
│ │ ├── dongle_prospector_common.dtsi # Prospector platform common config
│ │ ├── dongle_prospector.conf # Prospector dongle Kconfig options
│ │ ├── dongle_prospector.overlay # Prospector dongle device tree overlay
│ │ ├── dongle_nice_32.conf # Nice!Nano dongle 32px Kconfig options
│ │ ├── dongle_nice_32.overlay # Nice!Nano dongle 32px device tree overlay
│ │ ├── dongle_nice_64.conf # Nice!Nano dongle 64px Kconfig options
│ │ ├── dongle_nice_64.overlay # Nice!Nano dongle 64px device tree overlay
│ │ ├── Kconfig.defconfig # Shield Kconfig definitions
│ │ └── Kconfig.shield # Shield Kconfig options
│ └── tester_pro_micro/ # Pro Micro GPIO tester shield
│ ├── Kconfig.shield # Shield identifier
│ ├── Kconfig.defconfig # Shield defaults (USB-only, no BLE)
│ ├── tester_pro_micro.zmk.yml # Shield metadata
│ ├── tester_pro_micro.overlay # GPIO pin definitions (18 pins)
│ ├── tester_pro_micro.keymap # Pin test macros
│ └── tester_pro_micro-layouts.dtsi # Physical layouts (pinout + single row)
├── config/ # Main ZMK configuration directory (keymap + west manifest)
│ ├── charybdis.conf # Global ZMK configuration
│ ├── charybdis.keymap # Keymap definition file
│ ├── charybdis.zmk.yml # ZMK build configuration
│ ├── info.json # Repository metadata
│ └── west.yml # West manifest (see West.yml section below)
├── manual_build/ # Local build scripts
│ ├── build.py # Interactive build script
│ └── BUILD_README.md # Build instructions
├── docs/ # Documentation
│ ├── bom/ # Bill of Materials
│ │ ├── stl/ # 3D Print files
│ │ │ ├── charybdis_left_base.stl
│ │ │ ├── charybdis_left_button.stl
│ │ │ ├── charybdis_left_case.stl
│ │ │ ├── scylla_right_base.stl
│ │ │ ├── scylla_right_button.stl
│ │ │ └── scylla_right_case.stl
│ │ └── readme.md
│ ├── keymap/ # Keymap documentation
│ │ ├── config.yaml # Keymap drawer configuration
│ │ ├── keymap.yaml # Base keymap definition
│ │ ├── keymap.svg # Generated: Visual keymap (created by render.sh)
│ │ └── render.sh # Script to parse keymap and generate SVG
│ └── picture/ # Images
│ └── wireless-charybdis.png
├── build.yaml # GitHub Actions build configuration
├── zephyr/
│ └── module.yml # Zephyr module marker (enables discovering boards/shields/)
└── readme.md # This file
charybdis_layers.h: Layer definitions (BASE, POINTER, LOWER, RAISE, SYMBOLS, SCROLL, SNIPING) used across all shieldscharybdis_trackball_processors.dtsi: Shared trackball input processing configurations (snipe/scroll/move modes)charybdis_right_common.dtsi: Common hardware config for both right keyboard variants (GPIO, SPI, trackball device)dongle_charybdis_right.conf: Symlink tocharybdis_right_standalone.conf(identical hardware config)
config/charybdis.keymap: Defines all key layers, behaviors, and bindingsboards/shields/charybdis/charybdis.dtsi: Shared device tree definitions (keyboard matrix, kscan, physical layout)charybdis_left.overlay: Left side configuration (same for both modes)charybdis_right_standalone.overlay: Right side for standalone mode (processes trackball locally)dongle_charybdis_right.overlay: Right side for dongle mode (forwards trackball to dongle)dongle_common.dtsi: Base shared configuration for all dongle variants (matrix, input split, physical layout)dongle_nice_common.dtsi: Nice!Nano platform-specific common config (KSCAN, I2C)dongle_prospector_common.dtsi: Prospector platform-specific common config (KSCAN)dongle_prospector.overlay: Prospector dongle configuration (receives trackball from right peripheral)dongle_nice_32.overlay: Nice!Nano dongle with 128x32 OLED displaydongle_nice_64.overlay: Nice!Nano dongle with 128x64 OLED displayconfig/west.yml: Defines external dependencies (see West.yml section below)
In standalone mode, the right keyboard acts as the central device:
- Left keyboard: Peripheral (Nice!Nano v2)
- Right keyboard: Central with trackball (Nice!Nano v2)
- Connection: Left → Right → Host Computer
In dongle mode, a dedicated dongle acts as the central device with a display:
- Left keyboard: Peripheral (Nice!Nano v2)
- Right keyboard: Peripheral with trackball (Nice!Nano v2)
- Dongle Options:
- Prospector: Seeeduino XIAO BLE with custom Prospector display module
- Nice!Nano: Nice!Nano v2 with generic OLED (I2C)
- 128x32 OLED (0.91") - Use
dongle_nice_32shield - 128x64 OLED (0.96") - Use
dongle_nice_64shield
- 128x32 OLED (0.91") - Use
- Connection: Left → Dongle ← Right, Dongle → Host Computer
- Pairing Order: Pair left keyboard first, then right keyboard for correct battery display
- Power: USB powered (no sleep mode needed)
- Active layer indicator with layer names
- Split battery status for both peripherals
- Peripheral connection status indicators
- Caps Word indicator
- Fixed brightness (50%) without ambient light sensor
- Display: Prospector 1.69" IPS LCD
- Features: Uses YADS (Yet Another Dongle Screen) firmware
- Battery: Detailed battery status for central and peripherals
- WPM: Words Per Minute graph/indicator
- Brightness: Adjustable brightness with keyboard control
- System: Connection status, layer indication, modifiers
- Sleep: Deep sleep support for power saving
- Status: Currently disabled pending Zephyr 4.1 compatibility fix (issue #29)
Two variants are available based on OLED display size:
128x32 OLED (dongle_nice_32):
- Display: 128x32 OLED (SSD1306) via I2C (0.91" module)
- Active layer name with center alignment and scrolling support
- Peripheral battery levels (left + right keyboards)
- HID indicators (CAPS, NUM, SCROLL lock)
- Output status (USB/BLE connection)
- Active modifiers display (Shift, Ctrl, Alt, GUI)
- Display timeout: 5 minutes (configurable)
- Optimized for 32px height: Bongo cat disabled, modifiers optional
128x64 OLED (dongle_nice_64):
- Display: 128x64 OLED (SSD1306) via I2C (0.96" module)
- Active layer name with center alignment and scrolling support
- Peripheral battery levels (left + right keyboards)
- HID indicators (CAPS, NUM, SCROLL lock)
- Output status (USB/BLE connection)
- Active modifiers display (Shift, Ctrl, Alt, GUI)
- Bongo cat enabled (more vertical space available)
- Display timeout: 5 minutes (configurable)
Wiring (Nice!Nano to OLED):
- VCC → 3.3V
- GND → GND
- SDA → Pin 2
- SCL → Pin 3
The config/west.yml file defines the ZMK firmware dependencies and external modules used in this configuration.
remotes:
- name: zmkfirmware
url-base: https://github.com/zmkfirmware
- name: badjeff
url-base: https://github.com/badjeff
- name: carrefinho
url-base: https://github.com/carrefinho
- name: englmaxi
url-base: https://github.com/englmaxi
# - name: janpfischer # disabled - Zephyr 4.1 issues
# url-base: https://github.com/janpfischerzmkfirmware: The main ZMK firmware repository, containing the core ZMK application codebadjeff: Repository containing the PMW3610 trackball driver used for the Charybdis trackball. See zmk-pmw3610-driver for full configuration options.carrefinho: Repository containing the Prospector display module for the dongle. See prospector-zmk-module for display configuration options.englmaxi: Repository containing the OLED dongle display module. See zmk-dongle-display.janpfischer: (disabled) Repository containing the YADS (Yet Another Dongle Screen) module. See zmk-dongle-screen.
projects:
- name: zmk
remote: zmkfirmware
revision: main
import: app/west.yml
- name: zmk-pmw3610-driver
remote: badjeff
revision: zmk-0.4
- name: prospector-zmk-module
remote: carrefinho
revision: core/zephyr-4-1
- name: zmk-dongle-display
remote: englmaxi
revision: main
# - name: zmk-dongle-screen # disabled - Zephyr 4.1 issues
# remote: janpfischer
# revision: upgrade-4.1-
zmk:- Purpose: Main ZMK firmware application
- Source:
zmkfirmwareremote - Version:
mainbranch - Import: Includes additional dependencies from
app/west.ymlin the ZMK repository
-
zmk-pmw3610-driver:- Purpose: PMW3610 trackball sensor driver for ZMK
- Source:
badjeffremote - Version:
zmk-0.4branch (PMW3610-alt compatible + Zephyr 4.1 updates) - Note: This driver provides device tree bindings and driver code for the PMW3610 trackball sensor used on the Charybdis right side
-
prospector-zmk-module:- Purpose: Custom OLED display module for Seeeduino XIAO BLE dongle with ZMK Studio support
- Source:
carrefinhoremote - Version:
core/zephyr-4-1branch - Note: Provides the
prospector_adaptershield for dongle mode, includes widgets for layer display, battery status, and connection indicators
-
zmk-dongle-display:- Purpose: Generic OLED display module for Nice!Nano dongle (128x32/128x64 displays)
- Source:
englmaxiremote - Version:
mainbranch - Note: Provides the
dongle_displayshield for generic I2C OLED displays (SSD1306). Supports both 128x32 and 128x64 displays with configurable widgets. Usedongle_nice_32shield for 32px displays ordongle_nice_64shield for 64px displays.
-
zmk-dongle-screen: (disabled)- Purpose: YADS (Yet Another Dongle Screen) module for Prospector dongle with ST7789V display
- Source:
janpfischerremote - Version:
upgrade-4.1branch - Status: Currently disabled pending Zephyr 4.1 compatibility fix (issue #29)
- Note: Provides the
dongle_screenshield for ST7789V-based displays. Features include WPM widget, ambient light sensor support, brightness control via keyboard, and customizable status screen.
self:
path: configpath: config: Tells west that this repository's configuration files are located in theconfig/directory
Can be updated at /config/charybdis.keymap and rendered with render.sh
Generated with Keymap Drawer
The trackball sensitivity can be adjusted at both hardware and software levels.
The PMW3610 trackball sensor CPI (Counts Per Inch) is configured in boards/shields/charybdis/charybdis_right_common.dtsi:
trackball: trackball@0 {
compatible = "pixart,pmw3610";
cpi = <800>; // Change this value
// ...
};
Common CPI values:
400- Low sensitivity (more physical movement needed)800- Default, balanced sensitivity1200- High sensitivity1600- Very high sensitivity
Software scaling is configured per layer in boards/shields/charybdis/charybdis_trackball_processors.dtsi. The trackball has three different modes with independent sensitivity settings:
// Normal cursor movement (BASE and POINTER layers)
move {
layers = <BASE POINTER>;
input-processors = <&zip_xy_scaler 7 6>; // multiplier divisor
};
// Precise movement (SNIPING layer)
snipe {
layers = <SNIPING>;
input-processors = <&zip_xy_scaler 1 3>; // 1/3 speed for precision
};
// Scroll mode (SCROLL layer)
scroll {
layers = <SCROLL>;
input-processors = <&zip_xy_scaler 1 10>; // Adjust scroll speed
};
The scaler uses the formula: output = (input × multiplier) / divisor
Examples:
<&zip_xy_scaler 2 1>- Doubles movement speed (input × 2 / 1)<&zip_xy_scaler 1 2>- Halves movement speed (input × 1 / 2)<&zip_xy_scaler 7 6>- Slightly faster than 1:1 (input × 7 / 6)
To adjust sensitivity:
| Goal | Change | Example |
|---|---|---|
| Faster cursor | Increase multiplier or decrease divisor | 7 6 → 8 6 or 7 5 |
| Slower cursor | Decrease multiplier or increase divisor | 7 6 → 6 6 or 7 7 |
| Faster scroll | Decrease divisor | 1 10 → 1 5 |
| Slower scroll | Increase divisor | 1 10 → 1 15 |
For more details on input processors, see:
This configuration includes support for ZMK Studio, which allows you to interactively configure and test your keyboard layout.
The physical layout for ZMK Studio is defined in boards/shields/charybdis/charybdis.dtsi in the charybdis_6col_layout section. This defines the physical key positions, sizes, and rotations needed for the visual representation in ZMK Studio.
ZMK Studio support is enabled by default via the build configuration in build.yaml.
Standalone mode - Right keyboard has ZMK Studio:
- board: nice_nano
shield: charybdis_right_standalone
snippet: studio-rpc-usb-uart
cmake-args: -DCONFIG_ZMK_STUDIO=yDongle mode - Multiple dongles have ZMK Studio:
Prospector dongle:
- board: xiao_ble
shield: dongle_prospector prospector_adapter
snippet: studio-rpc-usb-uart
cmake-args: -DCONFIG_ZMK_STUDIO=yNice!Nano dongles (both 32px and 64px):
- board: nice_nano
shield: dongle_nice_32 dongle_display # or dongle_nice_64
snippet: studio-rpc-usb-uart
cmake-args: -DCONFIG_ZMK_STUDIO=yTo disable ZMK Studio support, comment out the snippet and cmake-args lines in the respective build configuration.
To unlock ZMK Studio for configuration, press all three right thumb keys simultaneously:
- RET (Return/Enter)
- SYMBOLS (hold) / SPACE (tap)
- RAISE (hold) / BSPC (tap)
This combo is defined in config/charybdis.keymap as combo_studio_unlock using key positions 53, 54, and 55.
Push changes to your repository and GitHub Actions will automatically build firmware for all configurations defined in build.yaml. Firmware files will be available in the Actions artifacts as a firmware.zip file containing:
charybdis_left-nice_nano-zmk.uf2charybdis_right_standalone-nice_nano-zmk.uf2dongle_charybdis_right-nice_nano-zmk.uf2dongle_prospector prospector_adapter-xiao_ble-zmk.uf2dongle_nice_32 dongle_display-nice_nano-zmk.uf2dongle_nice_64 dongle_display-nice_nano-zmk.uf2tester_pro_micro-nice_nano-zmk.uf2settings_reset-nice_nano-zmk.uf2settings_reset-xiao_ble-zmk.uf2
For local building using Docker, see manual_build/BUILD_README.md for detailed instructions.
The interactive build script provides options for:
- charybdis_left - Left keyboard (works with both modes)
- charybdis_right_standalone - Right keyboard for standalone mode (Nice!Nano)
- dongle_charybdis_right - Right keyboard for dongle mode (Nice!Nano)
- dongle_prospector prospector_adapter - Dongle with Prospector display (XIAO BLE)
- dongle_nice_32 dongle_display - Nice!Nano dongle with 128x32 OLED
- dongle_nice_64 dongle_display - Nice!Nano dongle with 128x64 OLED
- tester_pro_micro - GPIO pin tester for Pro Micro-compatible boards
- settings_reset - Reset stored settings
Note: Local builds use a dedicated workspace under manual_build/west-workspace/ and should behave the same as CI. If a specific configuration fails locally, prefer building in GitHub Actions and then iterate locally once the dependency/workspace is stable.
Built firmware files are automatically copied to manual_build/artifacts/output/ with descriptive names.
- Double-press the reset button on the board to enter bootloader mode
- The board will appear as a USB drive
- Copy the appropriate
.uf2file to the USB drive - The board will automatically flash and restart
- Flash
settings_reset-nice_nano-zmk.uf2to both keyboards - Flash
charybdis_left-nice_nano-zmk.uf2to the left keyboard - Flash
charybdis_right_standalone-nice_nano-zmk.uf2to the right keyboard - The keyboards will automatically pair with each other
-
Flash settings reset and dongle firmware (choose your dongle type):
a) Prospector Dongle (Seeeduino XIAO BLE):
- Flash
settings_reset-nice_nano-zmk.uf2to both keyboards - Flash
settings_reset-xiao_ble-zmk.uf2to the dongle - Flash
dongle_prospector prospector_adapter-xiao_ble-zmk.uf2to the dongle
b) YADS Prospector Dongle (Seeeduino XIAO BLE):
- Flash
settings_reset-nice_nano-zmk.uf2to both keyboards - Flash
settings_reset-xiao_ble-zmk.uf2to the dongle - Flash
dongle_yads_prospector dongle_screen-xiao_ble-zmk.uf2to the dongle
c) Nice!Nano Dongle (Nice!Nano v2)
- Flash
settings_reset-nice_nano-zmk.uf2to all three devices (left, right, dongle) - Flash the appropriate dongle firmware to the dongle:
- 128x32 OLED:
dongle_nice_32 dongle_display-nice_nano-zmk.uf2 - 128x64 OLED:
dongle_nice_64 dongle_display-nice_nano-zmk.uf2
- 128x32 OLED:
- Connect OLED display to dongle via I2C (SDA→Pin 2, SCL→Pin 3)
- Flash
-
Flash
charybdis_left-nice_nano-zmk.uf2to the left keyboard -
Flash
dongle_charybdis_right-nice_nano-zmk.uf2to the right keyboard -
Important: Pair the left keyboard to the dongle first, then pair the right keyboard
- Flash
tester_pro_micro-nice_nano-zmk.uf2(or your board variant) to the controller - Connect the board via USB to your computer
- Open a text editor or terminal
- Connect a switch or wire from any GPIO pin to GND and trigger it
- The board will output "PIN X" where X is the pin number (e.g., "PIN 14")
- Test all pins you want to verify
Note: The tester firmware disables Bluetooth and runs in USB-only mode for simplicity.
