qmk_me

QMK Firmware userspace, keyboards, & keymaps
git clone git://git.pngu.org.org/qmk_me
Log | Files | Refs | Submodules | README | LICENSE

commit 6086cc84330797308619567a2f6f52e980c630c1
parent fc810e56f9dd34d55244bbd91a88999075cdc831
Author: Jack Sangdahl <jack@pngu.org>
Date:   Sat, 25 Oct 2025 13:10:08 -0600

Initial unzahl firmware

Diffstat:
Akeyboards/unzahl/config.h | 32++++++++++++++++++++++++++++++++
Akeyboards/unzahl/halconf.h | 9+++++++++
Akeyboards/unzahl/keyboard.json | 133+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Akeyboards/unzahl/keymaps/default/keymap.json | 13+++++++++++++
Akeyboards/unzahl/matrix.c | 81+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Akeyboards/unzahl/mcuconf.h | 14++++++++++++++
Akeyboards/unzahl/readme.md | 25+++++++++++++++++++++++++
Akeyboards/unzahl/rules.mk | 1+
Mutil/link.sh | 1+
9 files changed, 309 insertions(+), 0 deletions(-)

diff --git a/keyboards/unzahl/config.h b/keyboards/unzahl/config.h @@ -0,0 +1,32 @@ +// Copyright 2025 jack@pngu.org +// SPDX-License-Identifier: GPL-2.0-or-later +#pragma once + +#define WS2812_PWM_DRIVER PWMD17 +#define WS2812_PWM_CHANNEL 1 +#define WS2812_PWM_PAL_MODE 10 +#define WS2812_PWM_DMA_STREAM STM32_DMA1_STREAM1 +#define WS2812_PWM_DMA_CHANNEL 1 +#define WS2812_PWM_DMAMUX_ID STM32_DMAMUX1_TIM17_UP + +#define SPI_DRIVER SPID1 +#define SPI_SCK_PIN A5 +#define SPI_SCK_PAL_MODE 5 +#define SPI_MOSI_PIN A7 +#define SPI_MOSI_PAL_MODE 5 +#define SPI_MISO_PIN A6 +#define SPI_MISO_PAL_MODE 5 + +#define I2C1_SDA_PIN B8 +#define I2C1_SCL_PIN B9 + +#define EXTERNAL_FLASH_SPI_MODE 0 +#define EXTERNAL_FLASH_SPI_SLAVE_SELECT_PIN B10 +#define EXTERNAL_FLASH_SPI_CLOCK_DIVISOR 4 +#define EXTERNAL_FLASH_SIZE (16 * 1024 * 1024) + +#define MATRIX_COLS 7 +#define MATRIX_ROWS 5 +#define SHIFT_REG_CS_PIN A3 +#define SHIFT_REG_SPI_DIVISOR 8 +#define MATRIX_ROW_PINS {B3, A15, A1, B7, B6} diff --git a/keyboards/unzahl/halconf.h b/keyboards/unzahl/halconf.h @@ -0,0 +1,9 @@ +// Copyright 2025 jack@pngu.org +// SPDX-License-Identifier: GPL-2.0-or-later +#pragma once + +#define HAL_USE_PWM TRUE +#define HAL_USE_SPI TRUE +#define HAL_USE_I2C TRUE + +#include_next <halconf.h> diff --git a/keyboards/unzahl/keyboard.json b/keyboards/unzahl/keyboard.json @@ -0,0 +1,133 @@ +{ + "manufacturer": "pngu.org", + "keyboard_name": "unzahl", + "maintainer": "jack", + "bootloader": "stm32-dfu", + "diode_direction": "COL2ROW", + "eeprom": { + "driver": "wear_leveling", + "wear_leveling": { + "backing_size": 32768, + "driver": "spi_flash" + } + }, + "encoder": { + "rotary": [ + {"pin_a": "A14", "pin_b": "A13"} + ] + }, + "features": { + "bootmagic": true, + "rgb_matrix": true, + "encoder": true, + "oled": false + }, + "matrix_pins": { + "custom": true, + "custom_lite": true + }, + "processor": "STM32G431", + "rgb_matrix": { + "driver": "ws2812", + "layout": [ + {"matrix": [0, 0], "x": 84, "y": 64, "flags": 4}, + {"matrix": [0, 0], "x": 48, "y": 64, "flags": 4}, + {"matrix": [2, 0], "x": 0, "y": 42, "flags": 4}, + {"matrix": [0, 0], "x": 24, "y": 42, "flags": 4}, + {"matrix": [0, 0], "x": 48, "y": 42, "flags": 4}, + {"matrix": [0, 0], "x": 72, "y": 42, "flags": 4}, + {"matrix": [0, 0], "x": 96, "y": 42, "flags": 4}, + {"matrix": [0, 0], "x": 96, "y": 21, "flags": 4}, + {"matrix": [0, 0], "x": 72, "y": 21, "flags": 4}, + {"matrix": [0, 0], "x": 48, "y": 21, "flags": 4}, + {"matrix": [0, 0], "x": 24, "y": 21, "flags": 4}, + {"matrix": [0, 0], "x": 0, "y": 21, "flags": 4}, + {"matrix": [0, 0], "x": 0, "y": 0, "flags": 4}, + {"matrix": [0, 0], "x": 24, "y": 0, "flags": 4}, + {"matrix": [0, 0], "x": 48, "y": 0, "flags": 4}, + {"matrix": [0, 0], "x": 72, "y": 0, "flags": 4}, + {"matrix": [0, 0], "x": 96, "y": 0, "flags": 4}, + {"matrix": [0, 0], "x": 120, "y": 0, "flags": 4}, + {"matrix": [0, 0], "x": 144, "y": 0, "flags": 4}, + {"matrix": [0, 0], "x": 168, "y": 0, "flags": 4}, + {"matrix": [0, 0], "x": 192, "y": 0, "flags": 4}, + {"matrix": [0, 0], "x": 224, "y": 0, "flags": 4}, + {"matrix": [0, 0], "x": 224, "y": 21, "flags": 4}, + {"matrix": [0, 0], "x": 192, "y": 21, "flags": 4}, + {"matrix": [0, 0], "x": 168, "y": 21, "flags": 4}, + {"matrix": [0, 0], "x": 144, "y": 21, "flags": 4}, + {"matrix": [0, 0], "x": 120, "y": 21, "flags": 4}, + {"matrix": [0, 0], "x": 120, "y": 42, "flags": 4}, + {"matrix": [0, 0], "x": 144, "y": 42, "flags": 4}, + {"matrix": [0, 0], "x": 168, "y": 42, "flags": 4}, + {"matrix": [0, 0], "x": 192, "y": 42, "flags": 4}, + {"matrix": [0, 0], "x": 224, "y": 42, "flags": 4}, + {"matrix": [0, 0], "x": 168, "y": 64, "flags": 4}, + {"matrix": [0, 0], "x": 132, "y": 64, "flags": 4}, + {"x": 132, "y": 50, "flags": 1}, + {"x": 168, "y": 50, "flags": 1}, + {"x": 224, "y": 30, "flags": 1}, + {"x": 224, "y": 10, "flags": 1}, + {"x": 168, "y": 10, "flags": 1}, + {"x": 120, "y": 10, "flags": 1}, + {"x": 96, "y": 10, "flags": 1}, + {"x": 48, "y": 10, "flags": 1}, + {"x": 0, "y": 10, "flags": 1}, + {"x": 0, "y": 30, "flags": 1}, + {"x": 48, "y": 50, "flags": 1}, + {"x": 84, "y": 50, "flags": 1} + ], + "sleep": true + }, + "url": "https://git.pngu.org/unzahl", + "usb": { + "device_version": "1.0.0", + "pid": "0x0000", + "vid": "0x6A73" + }, + "ws2812": { + "driver": "pwm", + "pin": "B5" + }, + "layouts": { + "LAYOUT": { + "layout": [ + {"matrix": [0, 0], "x": 0, "y": 0}, + {"matrix": [0, 1], "x": 1, "y": 0}, + {"matrix": [1, 1], "x": 2, "y": 0}, + {"matrix": [0, 2], "x": 3, "y": 0}, + {"matrix": [0, 3], "x": 4, "y": 0}, + {"matrix": [1, 3], "x": 5, "y": 0}, + {"matrix": [3, 3], "x": 6, "y": 0}, + {"matrix": [0, 4], "x": 7, "y": 0}, + {"matrix": [1, 5], "x": 8, "y": 0}, + {"matrix": [0, 5], "x": 9, "y": 0}, + {"matrix": [0, 6], "x": 10, "y": 0}, + {"matrix": [1, 0], "x": 0, "y": 1}, + {"matrix": [3, 0], "x": 1, "y": 1}, + {"matrix": [2, 1], "x": 2, "y": 1}, + {"matrix": [1, 2], "x": 3, "y": 1}, + {"matrix": [2, 3], "x": 4, "y": 1}, + {"matrix": [4, 3], "x": 6, "y": 1}, + {"matrix": [1, 4], "x": 7, "y": 1}, + {"matrix": [2, 5], "x": 8, "y": 1}, + {"matrix": [2, 6], "x": 9, "y": 1}, + {"matrix": [1, 6], "x": 10, "y": 1}, + {"matrix": [2, 0], "x": 0, "y": 2}, + {"matrix": [4, 0], "x": 1, "y": 2}, + {"matrix": [3, 1], "x": 2, "y": 2}, + {"matrix": [2, 2], "x": 3, "y": 2}, + {"matrix": [3, 2], "x": 4, "y": 2}, + {"matrix": [4, 4], "x": 6, "y": 2}, + {"matrix": [2, 4], "x": 7, "y": 2}, + {"matrix": [3, 5], "x": 8, "y": 2}, + {"matrix": [4, 6], "x": 9, "y": 2}, + {"matrix": [3, 6], "x": 10, "y": 2}, + {"matrix": [4, 1], "x": 1.75, "y": 3, "w": 1.25}, + {"matrix": [4, 2], "x": 3, "y": 3, "w": 2}, + {"matrix": [3, 4], "x": 6, "y": 3, "w": 2}, + {"matrix": [4, 5], "x": 8, "y": 3, "w": 1.25} + ] + } + } +} diff --git a/keyboards/unzahl/keymaps/default/keymap.json b/keyboards/unzahl/keymaps/default/keymap.json @@ -0,0 +1,13 @@ +{ + "keyboard": "unzahl", + "keymap": "default", + "layout": "LAYOUT", + "layers": [ + [ + "KC_Q", "KC_W", "KC_E", "KC_R", "KC_T", "KC_MPLY", "KC_Y", "KC_U", "KC_I", "KC_O", "KC_P", + "KC_A", "KC_S", "KC_D", "KC_F", "KC_G", "KC_H", "KC_J", "KC_K", "KC_L", "KC_SCLN", + "KC_Z", "KC_X", "KC_C", "KC_V", "KC_B", "KC_N", "KC_M", "KC_COMM", "KC_DOT", "KC_SLSH", + "KC_ENT", "KC_SPC", "KC_SPC", "KC_ENT" + ] + ] +} diff --git a/keyboards/unzahl/matrix.c b/keyboards/unzahl/matrix.c @@ -0,0 +1,81 @@ +// Copyright 2025 jack@pngu.org +// SPDX-License-Identifier: GPL-2.0-or-later +#include "matrix.h" +#include <string.h> +#include "spi_master.h" +#include "debug.h" + +static int matrix_size = MATRIX_ROWS * sizeof(matrix_row_t); +matrix_row_t old_matrix[MATRIX_ROWS]; +pin_t matrix_row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS; +static bool shift_reg_spi_locked = false; + +void sem_lock(bool value) { shift_reg_spi_locked = value; } + +bool sem_locked(void) { return shift_reg_spi_locked; } + +void shift_reg_spi_stop(void) { + spi_stop(); + sem_lock(false); +} + +bool shift_reg_spi_start(void) { + if (!spi_start(SHIFT_REG_CS_PIN, false, 0, SHIFT_REG_SPI_DIVISOR)) { + dprintf("74HC595: Failed to start SPI\n"); + shift_reg_spi_stop(); + return false; + } + sem_lock(true); + return true; +} + +void shift_reg_spi_send_byte(uint8_t data) { + shift_reg_spi_start(); + gpio_write_pin_low(SHIFT_REG_CS_PIN); + matrix_io_delay(); + spi_write(data); + matrix_io_delay(); + gpio_write_pin_high(SHIFT_REG_CS_PIN); + shift_reg_spi_stop(); +} + +void clear_columns(void) { + uint8_t value = 0b0000000; + shift_reg_spi_send_byte(value); +} + +void set_column(int shift) { + uint8_t shift_byte = ((uint8_t)1 << shift); + dprintf("74HC595: byte %d sent\n", shift_byte); + shift_reg_spi_send_byte(shift_byte); +} + +void matrix_init_custom(void) { + spi_init(); + for (uint8_t i = 0; i < MATRIX_ROWS; i++) + gpio_set_pin_input_low(matrix_row_pins[i]); + gpio_write_pin_high(SHIFT_REG_CS_PIN); + gpio_set_pin_output(SHIFT_REG_CS_PIN); + clear_columns(); +} + +bool matrix_scan_custom(matrix_row_t current_matrix[]) { + if (sem_locked()) + return false; + bool matrix_changed = false; + memset(current_matrix, 0, matrix_size); + for (uint8_t i = 0; i < MATRIX_COLS; i++) { + dprintf("74HC595: Column %d\n", i); + set_column(i); + matrix_io_delay(); + for (uint8_t j = 0; j < MATRIX_ROWS; j++) + current_matrix[j] |= ((gpio_read_pin(matrix_row_pins[j]) ? 1 : 0) << i); + } + matrix_changed = memcmp(current_matrix, old_matrix, matrix_size) != 0; + memcpy(old_matrix, current_matrix, matrix_size); + if (matrix_changed) + matrix_print(); + clear_columns(); + matrix_io_delay(); + return matrix_changed; +} diff --git a/keyboards/unzahl/mcuconf.h b/keyboards/unzahl/mcuconf.h @@ -0,0 +1,14 @@ +// Copyright 2025 jack@pngu.org +// SPDX-License-Identifier: GPL-2.0-or-later +#pragma once + +#include_next <mcuconf.h> + +#undef STM32_PWM_USE_TIM17 +#define STM32_PWM_USE_TIM17 TRUE + +#undef STM32_SPI_USE_SPI1 +#define STM32_SPI_USE_SPI1 TRUE + +#undef STM32_I2C_USE_I2C1 +#define STM32_I2C_USE_I2C1 TRUE diff --git a/keyboards/unzahl/readme.md b/keyboards/unzahl/readme.md @@ -0,0 +1,25 @@ +# Unzahl + +![image](https://git.pngu.org/unzahl/about/img/pcb_bottom.svg) + +* Keyboard Maintainer: [jack@pngu.org](mailto:jack@pngu.org) +* Hardware Supported: PCB with integrated STM32G431 microcontroller +* Hardware Availability: [git/sweep](https://git.pngu.org/unzahl) + +Make example for this keyboard (after setting up your build environment): + + make unzahl:default + +Flashing example for this keyboard: + + make unzahl:default:flash + +See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs). + +## Bootloader + +Enter the bootloader in 3 ways: + +* **Bootmagic reset**: Hold down the key at (0,0) in the matrix and plug in the keyboard +* **Physical reset button**: Tap reset button on back of PCB +* **Keycode in layout**: Press the key mapped to `QK_BOOT` if it is available diff --git a/keyboards/unzahl/rules.mk b/keyboards/unzahl/rules.mk @@ -0,0 +1 @@ +SRC += matrix.c diff --git a/util/link.sh b/util/link.sh @@ -46,4 +46,5 @@ link() { link endgame link locus link sweep +link unzahl link xyz60