diff --git a/README.md b/README.md index 419f33a..6efa8c3 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,9 @@ They have simple minimal Qwerty layouts including ZKM Studio support to cover ba * [Gamma Omega Hesse](boards/shields/hesse), a Graph Theory based diode-free Bluetooth keyboard with 21 GPIO pins for 36 keys and 4-key roll-over using the Hesse Configuration Incidence Graph. +* [Forager Acid](boards/shields/acid), a Graph Theory based diode-free Bluetooth split + keyboard with 13 GPIO pins for 17 (or 18) keys and 4-key roll-over per half using a + partial Heawood Graph. See also my [QMK keyboard firmware](https://github.com/peterjc/qmk_userspace). diff --git a/boards/shields/acid/Kconfig.defconfig b/boards/shields/acid/Kconfig.defconfig new file mode 100644 index 0000000..41654b6 --- /dev/null +++ b/boards/shields/acid/Kconfig.defconfig @@ -0,0 +1,19 @@ +if SHIELD_ACID_LEFT + +config ZMK_KEYBOARD_NAME + default "Acid" + +config ZMK_SPLIT_ROLE_CENTRAL + default y + +config ZMK_STUDIO + default y + +endif + +if SHIELD_ACID_LEFT || SHIELD_ACID_RIGHT + +config ZMK_SPLIT + default y + +endif diff --git a/boards/shields/acid/Kconfig.shield b/boards/shields/acid/Kconfig.shield new file mode 100644 index 0000000..8a928f2 --- /dev/null +++ b/boards/shields/acid/Kconfig.shield @@ -0,0 +1,7 @@ +# Copyright (c) 2025 Peter J. A. Cock +# SPDX-License-Identifier: MIT + +config SHIELD_ACID_LEFT + def_bool $(shields_list_contains,acid_left) +config SHIELD_ACID_RIGHT + def_bool $(shields_list_contains,acid_right) diff --git a/boards/shields/acid/acid-layouts.dtsi b/boards/shields/acid/acid-layouts.dtsi new file mode 100644 index 0000000..53d65b8 --- /dev/null +++ b/boards/shields/acid/acid-layouts.dtsi @@ -0,0 +1,47 @@ +#include + +/ { + default_layout: default_layout { + compatible = "zmk,physical-layout"; + display-name = "Default Layout"; + transform = <&default_transform>; + + keys // w h x y rot rx ry + = <&key_physical_attrs 100 100 0 61 0 0 0> + , <&key_physical_attrs 100 100 100 28 0 0 0> + , <&key_physical_attrs 100 100 200 0 0 0 0> + , <&key_physical_attrs 100 100 300 17 0 0 0> + , <&key_physical_attrs 100 100 400 28 0 0 0> + , <&key_physical_attrs 100 100 750 28 0 0 0> + , <&key_physical_attrs 100 100 850 17 0 0 0> + , <&key_physical_attrs 100 100 950 0 0 0 0> + , <&key_physical_attrs 100 100 1050 28 0 0 0> + , <&key_physical_attrs 100 100 1150 61 0 0 0> + , <&key_physical_attrs 100 100 0 161 0 0 0> + , <&key_physical_attrs 100 100 100 128 0 0 0> + , <&key_physical_attrs 100 100 200 100 0 0 0> + , <&key_physical_attrs 100 100 300 117 0 0 0> + , <&key_physical_attrs 100 100 400 128 0 0 0> + , <&key_physical_attrs 100 100 750 128 0 0 0> + , <&key_physical_attrs 100 100 850 117 0 0 0> + , <&key_physical_attrs 100 100 950 100 0 0 0> + , <&key_physical_attrs 100 100 1050 128 0 0 0> + , <&key_physical_attrs 100 100 1150 161 0 0 0> + , <&key_physical_attrs 100 100 0 261 0 0 0> + , <&key_physical_attrs 100 100 100 228 0 0 0> + , <&key_physical_attrs 100 100 200 200 0 0 0> + , <&key_physical_attrs 100 100 300 217 0 0 0> + , <&key_physical_attrs 100 100 400 228 0 0 0> + , <&key_physical_attrs 100 100 750 228 0 0 0> + , <&key_physical_attrs 100 100 850 217 0 0 0> + , <&key_physical_attrs 100 100 950 200 0 0 0> + , <&key_physical_attrs 100 100 1050 228 0 0 0> + , <&key_physical_attrs 100 100 1150 261 0 0 0> + , <&key_physical_attrs 100 100 400 350 2500 450 400> + , <&key_physical_attrs 100 100 500 370 2500 450 400> + , <&key_physical_attrs 100 100 650 370 (-2500) 800 400> + , <&key_physical_attrs 100 100 750 350 (-2500) 800 400> + ; + }; +}; + diff --git a/boards/shields/acid/acid.dtsi b/boards/shields/acid/acid.dtsi new file mode 100644 index 0000000..7a0e6ca --- /dev/null +++ b/boards/shields/acid/acid.dtsi @@ -0,0 +1,67 @@ +#include +#include +#include "acid-layouts.dtsi" + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,physical-layout = &default_layout; + }; +}; + +/* By design, the Forager Acid pin assignment and thus wiring matrix is the + * same for the left and right halves, so can define the GPIOs once centrally: + * Columns: P0.10, P1.12 (D7), P1.13 (D8), P1.14 (D9), P0.09, P1.15 (D10) + * Rows: P0.05 (D5), P1.11 (D6), P0.28 (D2), P0.03 (D1), P0.02 (D0), P0.29 (D3), P0.04 (D4) + * + * Could use &xiao_d 7 instead of &gpio0 4 for most of the pins, but not the + * two NFC ones, + */ + +/ { + kscan0: kscan0 { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "col2row"; + wakeup-source; + + col-gpios + = <&gpio0 10 GPIO_OPEN_SOURCE> + , <&gpio1 12 GPIO_OPEN_SOURCE> + , <&gpio1 13 GPIO_OPEN_SOURCE> + , <&gpio1 14 GPIO_OPEN_SOURCE> + , <&gpio0 9 GPIO_OPEN_SOURCE> + , <&gpio1 15 GPIO_OPEN_SOURCE> + ; + + row-gpios + = <&gpio0 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio1 11 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 28 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 3 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 2 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 29 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; +}; + +/* The columns and row value here are the scaning matrix (GPIOs), not physical */ +/* The column number is doubled for the left/right, and col-offset 6 used on right */ +/ { + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <12>; + rows = <7>; + + map = < + RC(0,4) RC(2,3) RC(1,2) RC(0,1) RC(0,0) RC(0,6) RC(0,7) RC(1,8) RC(2,9) RC(0,10) + RC(3,4) RC(3,3) RC(2,2) RC(1,1) RC(2,0) RC(2,6) RC(1,7) RC(2,8) RC(3,9) RC(3,10) + RC(4,4) RC(6,3) RC(4,2) RC(6,1) RC(5,0) RC(5,6) RC(6,7) RC(4,8) RC(6,9) RC(4,10) + RC(5,5) RC(6,5) RC(6,11) RC(5,11) + >; + }; +}; + +&xiao_serial { + status = "disabled"; +}; diff --git a/boards/shields/acid/acid.keymap b/boards/shields/acid/acid.keymap new file mode 100644 index 0000000..1c09549 --- /dev/null +++ b/boards/shields/acid/acid.keymap @@ -0,0 +1,135 @@ +#include +#include +#include +#include + +#define BASE 0 +#define NAV 1 +#define SYM 2 +#define ADJ 3 + +#define AS(keycode) &as LS(keycode) keycode // Autoshift Macro +#define MEH LS(LC(LALT)) + +/ { + behaviors { + as: auto_shift { + compatible = "zmk,behavior-hold-tap"; + #binding-cells = <2>; + tapping-term-ms = <250>; + require-prior-idle-ms = <100>; + flavor = "tap-preferred"; + bindings = <&kp>, <&kp>; + }; + ht: hold_tap { + compatible = "zmk,behavior-hold-tap"; + #binding-cells = <2>; + tapping-term-ms = <200>; + flavor = "balanced"; + bindings = <&kp>, <&kp>; + }; + sabk: shift_to_alt_backspace { + compatible = "zmk,behavior-mod-morph"; + #binding-cells = <0>; + bindings = <&kp BSPC>, <&kp LA(BSPC)>; + mods = <(MOD_LSFT|MOD_RSFT)>; + }; + smart_shift: smart_shift { + compatible = "zmk,behavior-mod-morph"; + #binding-cells = <0>; + bindings = <&sk LSHFT>, <&caps_word>; + mods = <(MOD_LSFT|MOD_RSFT)>; + }; + sym_bspc: left_thumb_hold_tap { + compatible = "zmk,behavior-hold-tap"; + #binding-cells = <2>; + flavor = "tap-preferred"; + tapping-term-ms = <150>; + quick-tap-ms = <200>; + bindings = <&mo>, <&sabk>; + }; + lhm: left_homerow_mods { + compatible = "zmk,behavior-hold-tap"; + #binding-cells = <2>; + flavor = "balanced"; + tapping-term-ms = <280>; + quick-tap-ms = <175>; + require-prior-idle-ms = <150>; + bindings = <&kp>, <&kp>; + hold-trigger-key-positions = <5 6 7 8 9 15 16 17 18 19 25 26 27 28 29 30 31 32 33>; + }; + rhm: right_homerow_mods { + compatible = "zmk,behavior-hold-tap"; + #binding-cells = <2>; + flavor = "balanced"; + tapping-term-ms = <280>; + quick-tap-ms = <175>; + require-prior-idle-ms = <150>; + bindings = <&kp>, <&kp>; + hold-trigger-key-positions = <0 1 2 3 4 10 11 12 13 14 20 21 22 23 24 30 31 32 33>; + }; + }; + + conditional_layers { + compatible = "zmk,conditional-layers"; + tri_layer { + if-layers = <1 2>; + then-layer = <3>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + base { + bindings = < + &kp Q &kp W &kp F &kp P &kp B &kp J &kp L &kp U &kp Y AS(SEMI) + &kp A &lhm LCTRL R &lhm LALT S &lhm LGUI T &kp G &kp M &rhm LGUI N &rhm LALT E &rhm LCTRL I &kp O + &kp Z &kp X &kp C &kp D &kp V &kp K &kp H AS(COMMA) AS(DOT) AS(FSLH) + &sym_bspc 2 0 &smart_shift &smart_shift < NAV SPACE + >; + }; + + nav { + bindings = < + &trans &trans &trans &trans &trans &kp PAGE_UP &kp LC(PG_UP) &kp UP &kp LC(PG_DN) &kp DELETE + &trans &kp LCTRL &kp LALT &kp LGUI &trans &kp PAGE_DOWN &kp LEFT &kp DOWN &kp RIGHT &kp BSLH + &trans &trans &trans &trans &trans &trans &kp HOME &kp END &kp LC(SPACE) &kp LC(SPACE) + &mo SYM &kp LSHFT &trans &trans + >; + }; + + sym { + bindings = < + AS(N1) AS(N2) AS(N3) AS(N4) AS(N5) AS(N6) AS(N7) AS(N8) AS(N9) AS(N0) + AS(GRAVE) &sk LCTRL &sk LALT &sk LGUI &sk LC(LALT) AS(BSLH) AS(MINUS) AS(EQUAL) AS(LBKT) AS(RBKT) + &trans &trans &trans &trans &trans &trans &trans &trans &trans &kp ENTER + &trans &trans &kp LSHFT &mo NAV + >; + }; + + adj { + bindings = < + &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_CLR_ALL &kp C_SLEEP &trans &trans &kp C_BRI_DN &kp C_BRI_UP + &studio_unlock &trans &trans &trans &trans &trans &trans &trans &kp C_VOL_DN &kp C_VOL_UP + &bootloader &trans &trans &trans &trans &trans &trans &trans &trans &bootloader + &trans &trans &trans &trans + >; + }; + }; +}; + +< { + // require-prior-idle-ms = <100>; + tapping-term-ms = <150>; + quick-tap-ms = <200>; +}; + +&mt { + quick-tap-ms = <200>; +}; + +&sk { + release-after-ms = <500>; + quick-release; +}; diff --git a/boards/shields/acid/acid.zmk.yml b/boards/shields/acid/acid.zmk.yml new file mode 100644 index 0000000..8bb9fc8 --- /dev/null +++ b/boards/shields/acid/acid.zmk.yml @@ -0,0 +1,11 @@ +file_format: "1" +id: acid +name: "Forager Acid" +type: shield +requires: [seeeduino_xiao_ble] +features: + - keys + - studio +siblings: + - acid_left + - acid_right diff --git a/boards/shields/acid/acid_left.conf b/boards/shields/acid/acid_left.conf new file mode 100644 index 0000000..f5e0603 --- /dev/null +++ b/boards/shields/acid/acid_left.conf @@ -0,0 +1,2 @@ +CONFIG_NFCT_PINS_AS_GPIOS=y + diff --git a/boards/shields/acid/acid_left.overlay b/boards/shields/acid/acid_left.overlay new file mode 100644 index 0000000..c99fe2d --- /dev/null +++ b/boards/shields/acid/acid_left.overlay @@ -0,0 +1,7 @@ +#include "acid.dtsi" + +&default_transform { + col-offset = <0>; +}; + +/* The GPIO pins are the same, just layout mirrored */ diff --git a/boards/shields/acid/acid_right.conf b/boards/shields/acid/acid_right.conf new file mode 120000 index 0000000..d1a714e --- /dev/null +++ b/boards/shields/acid/acid_right.conf @@ -0,0 +1 @@ +acid_left.conf \ No newline at end of file diff --git a/boards/shields/acid/acid_right.overlay b/boards/shields/acid/acid_right.overlay new file mode 100644 index 0000000..693e2fc --- /dev/null +++ b/boards/shields/acid/acid_right.overlay @@ -0,0 +1,7 @@ +#include "acid.dtsi" + +&default_transform { + col-offset = <6>; +}; + +/* The GPIO pins are the same, just layout mirrored */ diff --git a/build.yaml b/build.yaml index 98b337a..0151d1b 100644 --- a/build.yaml +++ b/build.yaml @@ -26,3 +26,12 @@ include: shield: hesse snippet: studio-rpc-usb-uart cmake-args: -DCONFIG_ZMK_STUDIO=y + - board: seeeduino_xiao_ble + shield: acid_left + snippet: studio-rpc-usb-uart + cmake-args: -DCONFIG_ZMK_STUDIO=y + - board: seeeduino_xiao_ble + shield: acid_right + snippet: studio-rpc-usb-uart + cmake-args: -DCONFIG_ZMK_STUDIO=y +