diff --git a/keyboards/hazel/bad_wings/config.h b/keyboards/hazel/bad_wings/config.h new file mode 100644 index 0000000000..4730172835 --- /dev/null +++ b/keyboards/hazel/bad_wings/config.h @@ -0,0 +1,19 @@ +// Copyright 2023 Jason Hazel (@jasonhazel) +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#define SPI_SCK_PIN GP2 +#define SPI_MOSI_PIN GP3 +#define SPI_MISO_PIN GP4 + +#define SHIFTREG_MATRIX_COL_CS GP0 +#define SHIFTREG_DIVISOR 8 +#define SHIFTREG_ROWS 5 +#define SHIFTREG_COLS 8 + +#define MATRIX_ROW_PINS_SR { GP26, GP27, GP28, GP29, GP6 } + +#define POINTING_DEVICE_CS_PIN GP1 +#define CIRQUE_PINNACLE_DIAMETER_MM 35 +#define POINTING_DEVICE_ROTATION_90 \ No newline at end of file diff --git a/keyboards/hazel/bad_wings/halconf.h b/keyboards/hazel/bad_wings/halconf.h new file mode 100644 index 0000000000..ed9500fe75 --- /dev/null +++ b/keyboards/hazel/bad_wings/halconf.h @@ -0,0 +1,12 @@ +// Copyright 2023 Jason Hazel (@jasonhazel) +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#define HAL_USE_SPI TRUE +#define HAL_USE_I2C TRUE +#define HAL_USE_PWM TRUE +#define SPI_USE_WAIT TRUE +#define SPI_SELECT_MODE SPI_SELECT_MODE_PAD + +#include_next \ No newline at end of file diff --git a/keyboards/hazel/bad_wings/info.json b/keyboards/hazel/bad_wings/info.json new file mode 100644 index 0000000000..f57889bc2d --- /dev/null +++ b/keyboards/hazel/bad_wings/info.json @@ -0,0 +1,66 @@ +{ + "keyboard_name": "Bad Wings", + "manufacturer": "Hazel", + "maintainer": "jasonhazel", + "url": "https://shop.hazel.cc/products/bad-wings", + "usb": { + "vid": "0x4A48", + "pid": "0x4257", + "device_version": "1.0.0" + }, + "processor": "RP2040", + "bootloader": "rp2040", + "matrix_size": { + "cols": 8, + "rows": 5 + }, + "diode_direction": "COL2ROW", + "features": { + "bootmagic": true, + "deferred_exec": true, + "nkro": false + }, + "community_layouts": [ "split_3x5_3" ], + "layouts": { + "LAYOUT_split_3x5_3": { + "layout": [ + { "label": "K00", "matrix": [0, 0], "w": 1, "x": 0, "y": 0.75 }, + { "label": "K10", "matrix": [1, 0], "w": 1, "x": 1, "y": 0.5 }, + { "label": "K20", "matrix": [2, 0], "w": 1, "x": 2, "y": 0 }, + { "label": "K30", "matrix": [3, 0], "w": 1, "x": 3, "y": 0.25 }, + { "label": "K40", "matrix": [4, 0], "w": 1, "x": 4, "y": 0.36 }, + { "label": "K44", "matrix": [4, 4], "w": 1, "x": 8, "y": 0.36 }, + { "label": "K34", "matrix": [3, 4], "w": 1, "x": 9, "y": 0.25 }, + { "label": "K24", "matrix": [2, 4], "w": 1, "x": 10, "y": 0 }, + { "label": "K14", "matrix": [1, 4], "w": 1, "x": 11, "y": 0.5 }, + { "label": "K04", "matrix": [0, 4], "w": 1, "x": 12, "y": 0.75 }, + { "label": "K01", "matrix": [0, 1], "w": 1, "x": 0, "y": 1.75 }, + { "label": "K11", "matrix": [1, 1], "w": 1, "x": 1, "y": 1.5 }, + { "label": "K21", "matrix": [2, 1], "w": 1, "x": 2, "y": 1 }, + { "label": "K31", "matrix": [3, 1], "w": 1, "x": 3, "y": 1.25 }, + { "label": "K41", "matrix": [4, 1], "w": 1, "x": 4, "y": 1.36 }, + { "label": "K45", "matrix": [4, 5], "w": 1, "x": 8, "y": 1.36 }, + { "label": "K35", "matrix": [3, 5], "w": 1, "x": 9, "y": 1.25 }, + { "label": "K25", "matrix": [2, 5], "w": 1, "x": 10, "y": 1 }, + { "label": "K15", "matrix": [1, 5], "w": 1, "x": 11, "y": 1.5 }, + { "label": "K05", "matrix": [0, 5], "w": 1, "x": 12, "y": 1.75 }, + { "label": "K02", "matrix": [0, 2], "w": 1, "x": 0, "y": 2.75 }, + { "label": "K12", "matrix": [1, 2], "w": 1, "x": 1, "y": 2.5 }, + { "label": "K22", "matrix": [2, 2], "w": 1, "x": 2, "y": 2 }, + { "label": "K32", "matrix": [3, 2], "w": 1, "x": 3, "y": 2.25 }, + { "label": "K42", "matrix": [4, 2], "w": 1, "x": 4, "y": 2.36 }, + { "label": "K46", "matrix": [4, 6], "w": 1, "x": 8, "y": 2.36 }, + { "label": "K36", "matrix": [3, 6], "w": 1, "x": 9, "y": 2.25 }, + { "label": "K26", "matrix": [2, 6], "w": 1, "x": 10, "y": 2 }, + { "label": "K16", "matrix": [1, 6], "w": 1, "x": 11, "y": 2.5 }, + { "label": "K06", "matrix": [0, 6], "w": 1, "x": 12, "y": 2.75 }, + { "label": "K23", "matrix": [2, 3], "w": 1, "x": 3, "y": 3.25 }, + { "label": "K33", "matrix": [3, 3], "w": 1, "x": 4, "y": 3.36 }, + { "label": "K43", "matrix": [4, 3], "w": 1, "x": 5, "y": 3.47 }, + { "label": "K47", "matrix": [4, 7], "w": 1, "x": 7, "y": 3.47 }, + { "label": "K37", "matrix": [3, 7], "w": 1, "x": 8, "y": 3.36 }, + { "label": "K27", "matrix": [2, 7], "w": 1, "x": 9, "y": 3.25 } + ] + } + } +} \ No newline at end of file diff --git a/keyboards/hazel/bad_wings/keymaps/default/config.h b/keyboards/hazel/bad_wings/keymaps/default/config.h new file mode 100644 index 0000000000..bd395ec9e5 --- /dev/null +++ b/keyboards/hazel/bad_wings/keymaps/default/config.h @@ -0,0 +1,16 @@ +// Copyright 2023 Jason Hazel (@jasonhazel) +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#define TAPPING_TERM 200 +#define PERMISSIVE_HOLD +#define IGNORE_MOD_TAP_INTERRUPT +#define TAPPING_FORCE_HOLD +#define TAPPING_TERM_PER_KEY +#define ONESHOT_TAP_TOGGLE 10 +#define ONESHOT_TIMEOUT 500 +#define DOUBLE_TAP_SHIFT_TURNS_ON_CAPS_WORD +#define CIRQUE_PINNACLE_TAP_ENABLE +#define CIRQUE_PINNACLE_POSITION_MODE CIRQUE_PINNACLE_ABSOLUTE_MODE +#define CIRQUE_DEVICE_GESTURES_SCROLL_ENABLE \ No newline at end of file diff --git a/keyboards/hazel/bad_wings/keymaps/default/keymap.c b/keyboards/hazel/bad_wings/keymaps/default/keymap.c new file mode 100644 index 0000000000..e9adc7cc2e --- /dev/null +++ b/keyboards/hazel/bad_wings/keymaps/default/keymap.c @@ -0,0 +1,35 @@ +// Copyright 2023 Jason Hazel (@jasonhazel) +// SPDX-License-Identifier: GPL-3.0-or-later + +#include QMK_KEYBOARD_H + +layer_state_t layer_state_set_user(layer_state_t state) { + return update_tri_layer_state(state, 1, 2, 3); +} + +const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { + [0] = LAYOUT_split_3x5_3( + KC_Q, KC_W, KC_E, KC_R, KC_T, 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_QUOT, \ + KC_Z, LGUI_T(KC_X), LALT_T(KC_C), KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, \ + KC_LCTL, OSL(1), OSM(MOD_LSFT), KC_SPC, LT(2, KC_BSPC), KC_ENT + ), + [1] = LAYOUT_split_3x5_3( + KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_RBRC, KC_RCBR, KC_RPRN, KC_RABK, KC_NO, \ + KC_GRV, KC_TILD, KC_UNDS, KC_EQL, KC_NO, KC_LBRC, KC_LCBR, KC_LPRN, KC_LABK, KC_BACKSLASH, \ + KC_NO, KC_NO, KC_PLUS, KC_MINS, KC_NO, KC_NO, KC_NO, KC_COLN, KC_DOT, KC_SCLN, \ + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS + ), + [2] = LAYOUT_split_3x5_3( + KC_EXLM, KC_AT, KC_HASH, KC_DLR, KC_PERC, KC_CIRC, KC_AMPR, KC_ASTR, KC_PIPE, KC_NO, \ + KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, \ + KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_DOT, KC_NO, \ + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS + ), + [3] = LAYOUT_split_3x5_3( + KC_ESC, KC_F1, KC_F4, KC_F7, KC_F10, KC_NO, KC_HOME, KC_UP, KC_END, KC_BSPC, \ + KC_TAB, KC_F2, KC_F5, KC_F8, KC_F11, KC_NO, KC_LEFT, KC_DOWN, KC_RIGHT, KC_ENT, \ + KC_NO, KC_F3, KC_F6, KC_F9, KC_F12, KC_NO, KC_MPRV, KC_MPLY, KC_MNXT, KC_DEL, \ + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS + ) +}; \ No newline at end of file diff --git a/keyboards/hazel/bad_wings/keymaps/default/rules.mk b/keyboards/hazel/bad_wings/keymaps/default/rules.mk new file mode 100644 index 0000000000..cb8ebf227e --- /dev/null +++ b/keyboards/hazel/bad_wings/keymaps/default/rules.mk @@ -0,0 +1,2 @@ +MOUSEKEY_ENABLE = yes +EXTRAKEY_ENABLE = yes \ No newline at end of file diff --git a/keyboards/hazel/bad_wings/matrix.c b/keyboards/hazel/bad_wings/matrix.c new file mode 100644 index 0000000000..496bebd58f --- /dev/null +++ b/keyboards/hazel/bad_wings/matrix.c @@ -0,0 +1,137 @@ +// Copyright 2022 @sadekbaroudi (Sadek Baroudi) +// Copyright 2023 @jasonhazel (Jason Hazel) +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "quantum.h" +#include "spi_master.h" +#include /* memset */ +#include /* close */ +#include "quantum.h" +#include "matrix.h" + +#if (!defined(SHIFTREG_MATRIX_COL_CS)) +# error Missing shift register I/O pin definitions +#endif + +int matrixArraySize = SHIFTREG_ROWS * sizeof(matrix_row_t); +matrix_row_t oldMatrix[SHIFTREG_ROWS]; + +#define SHIFTREG_OUTPUT_BITS 8 +pin_t rowPinsSR[SHIFTREG_ROWS] = MATRIX_ROW_PINS_SR; + +// semaphore to make sure SPI doesn't get called multiple times +static bool shiftRegisterSPILocked = false; + +void semaphore_lock(bool value) { + shiftRegisterSPILocked = value; +} + +bool semaphore_is_locked(void) { + return shiftRegisterSPILocked; +} + +void sr_74hc595_spi_stop(void) { + spi_stop(); + semaphore_lock(false); +} + +bool sr_74hc595_spi_start(void) { + if (!spi_start(SHIFTREG_MATRIX_COL_CS, false, 0, SHIFTREG_DIVISOR)) { + dprintf("74hc595 matrix: failed to start spi\n"); + sr_74hc595_spi_stop(); + return false; + } + + semaphore_lock(true); + wait_us(1); // not sure if I need this + return true; +} + +bool sr_74hc595_spi_send_byte(uint8_t data) { + sr_74hc595_spi_start(); + writePinLow(SHIFTREG_MATRIX_COL_CS); + matrix_io_delay(); + spi_write(data); + matrix_io_delay(); + writePinHigh(SHIFTREG_MATRIX_COL_CS); + sr_74hc595_spi_stop(); + return true; +} + +/** + * Set the entire shift register to be full of inactive bits + */ +void clearColumns(void) { + uint8_t value = 0b00000000; + sr_74hc595_spi_send_byte(value); +} + +void setColumn(int columnShift, bool test_run) { + uint8_t columnShiftByte = ((uint8_t)1 << columnShift); + if(test_run) { + dprintf("byte sent: %d\n", columnShiftByte); + } + sr_74hc595_spi_send_byte(columnShiftByte); +} + +/* + * override of the qmk intialization function + */ +void matrix_init_custom(void) { + wait_ms(300); + spi_init(); + // Set up the initial states for all the row pins + for (int r = 0; r < SHIFTREG_ROWS; r++) { + // Note: This needs to use the internal pull down resistors, and atmegas do *not* support that + setPinInputLow(rowPinsSR[r]); + } + + // Set the CS to low by default, and specify as an output pin + writePinHigh(SHIFTREG_MATRIX_COL_CS); // should be high when using SPI? + setPinOutput(SHIFTREG_MATRIX_COL_CS); + + // Since it's the init, deactivate all the columns. We'll activate once we get to the matrix scan + clearColumns(); +} + +bool matrix_scan_custom(matrix_row_t current_matrix[]) { + // respect the semaphore + if (semaphore_is_locked()) { + return false; + } + + // Keep track of if something was modified + bool matrix_has_changed = false; + + // reset the current matrix, as we'll be updating and comparing to the old matrix + memset(current_matrix, 0, matrixArraySize); + + + bool debug_output = false; + // Loop through the columns, activating one at a time, and read the rows, and place in the new current_matrix + for (int c = 0; c < SHIFTREG_COLS; c++) { + if (debug_output) { + dprintf("column iteration: %d\n", c); + } + setColumn(c, debug_output); + matrix_io_delay(); + + for (int r = 0; r < SHIFTREG_ROWS; r++) { + current_matrix[r] |= ((readPin(rowPinsSR[r]) ? 1 : 0) << c); + } + } + + matrix_has_changed = memcmp(current_matrix, oldMatrix, matrixArraySize) != 0; + memcpy(oldMatrix, current_matrix, matrixArraySize); + + if (matrix_has_changed) { + matrix_print(); + } + + + // Deactivate all the columns for the next run. + clearColumns(); + matrix_io_delay(); + + return matrix_has_changed; +} diff --git a/keyboards/hazel/bad_wings/mcuconf.c b/keyboards/hazel/bad_wings/mcuconf.c new file mode 100644 index 0000000000..9ed5ae7efb --- /dev/null +++ b/keyboards/hazel/bad_wings/mcuconf.c @@ -0,0 +1,11 @@ +// Copyright 2023 Jason Hazel (@jasonhazel) +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include_next "mcuconf.h" + +#undef RP_SPI_USE_SPI0 +#define RP_SPI_USE_SPI0 TRUE +#undef RP_I2C_USE_I2C1 +#define RP_I2C_USE_I2C1 TRUE \ No newline at end of file diff --git a/keyboards/hazel/bad_wings/readme.md b/keyboards/hazel/bad_wings/readme.md new file mode 100644 index 0000000000..0b0f643745 --- /dev/null +++ b/keyboards/hazel/bad_wings/readme.md @@ -0,0 +1,27 @@ +# Bad Wings + +![Bad Wings](https://i.imgur.com/QpfcEj8h.png) + +36 key unibody split + +* Keyboard Maintainer: [Jason Hazel](https://github.com/jasonhazel) +* Hardware Supported: Bad Wings v1 +* Hardware Availability: [Hazel's Garage](https://shop.hazel.cc/products/bad-wings) + +Make example for this keyboard (after setting up your build environment): + + make hazel/bad_wings:default + +Flashing example for this keyboard: + + make hazel/bad_wings: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 top-left key and plug in the keyboard +* **Physical reset button**: Hold Xiao B button, press Xiao R button, release B +* **Keycode in layout**: There is no key mapped to `QK_BOOT` in the pre-created keymaps, but you may assign this key in any keymaps you create \ No newline at end of file diff --git a/keyboards/hazel/bad_wings/rules.mk b/keyboards/hazel/bad_wings/rules.mk new file mode 100644 index 0000000000..1001af0186 --- /dev/null +++ b/keyboards/hazel/bad_wings/rules.mk @@ -0,0 +1,10 @@ +TRI_LAYER_ENABLE = yes +CAPS_WORD_ENABLE = yes + +SRC += matrix.c + +QUANTUM_LIB_SRC += spi_master.c +CUSTOM_MATRIX = lite + +POINTING_DEVICE_DRIVER = cirque_pinnacle_spi +POINTING_DEVICE_ENABLE = yes