From 2dad42edae4579b02d0740c71f679eab99fc3bc8 Mon Sep 17 00:00:00 2001 From: lalalademaxiya1 <66767061+lalalademaxiya1@users.noreply.github.com> Date: Wed, 12 Jan 2022 18:56:15 +0800 Subject: [PATCH] Add rev_0107 and flash support in stm32l433. --- common_features.mk | 6 + keyboards/keychron/q1/chconf.h | 30 + keyboards/keychron/q1/config.h | 13 - keyboards/keychron/q1/halconf.h | 27 + keyboards/keychron/q1/mcuconf.h | 30 + keyboards/keychron/q1/q1.c | 10 - keyboards/keychron/q1/q1.h | 3 +- keyboards/keychron/q1/rev_0100/config.h | 13 +- keyboards/keychron/q1/rev_0100/rev_0100.c | 8 + keyboards/keychron/q1/rev_0102/config.h | 13 +- keyboards/keychron/q1/rev_0102/rev_0102.c | 8 + keyboards/keychron/q1/rev_0107/config.h | 61 ++ .../q1/rev_0107/keymaps/default/info.json | 98 ++++ .../q1/rev_0107/keymaps/default/keymap.c | 135 +++++ .../q1/rev_0107/keymaps/via/info.json | 101 ++++ .../keychron/q1/rev_0107/keymaps/via/keymap.c | 177 ++++++ .../keychron/q1/rev_0107/keymaps/via/rules.mk | 2 + keyboards/keychron/q1/rev_0107/readme.md | 6 + keyboards/keychron/q1/rev_0107/rev_0107.c | 165 ++++++ keyboards/keychron/q1/rev_0107/rev_0107.h | 52 ++ keyboards/keychron/q1/rev_0107/rules.mk | 27 + platforms/chibios/eeprom_stm32_defs.h | 4 +- platforms/chibios/eeprom_stm32_l4.c | 546 ++++++++++++++++++ platforms/chibios/eeprom_stm32_l4.h | 34 ++ platforms/chibios/flash_stm32.c | 47 ++ platforms/chibios/flash_stm32.h | 1 + 26 files changed, 1589 insertions(+), 28 deletions(-) create mode 100644 keyboards/keychron/q1/chconf.h create mode 100644 keyboards/keychron/q1/halconf.h create mode 100644 keyboards/keychron/q1/mcuconf.h create mode 100644 keyboards/keychron/q1/rev_0107/config.h create mode 100644 keyboards/keychron/q1/rev_0107/keymaps/default/info.json create mode 100644 keyboards/keychron/q1/rev_0107/keymaps/default/keymap.c create mode 100644 keyboards/keychron/q1/rev_0107/keymaps/via/info.json create mode 100644 keyboards/keychron/q1/rev_0107/keymaps/via/keymap.c create mode 100644 keyboards/keychron/q1/rev_0107/keymaps/via/rules.mk create mode 100644 keyboards/keychron/q1/rev_0107/readme.md create mode 100644 keyboards/keychron/q1/rev_0107/rev_0107.c create mode 100644 keyboards/keychron/q1/rev_0107/rev_0107.h create mode 100644 keyboards/keychron/q1/rev_0107/rules.mk create mode 100644 platforms/chibios/eeprom_stm32_l4.c create mode 100644 platforms/chibios/eeprom_stm32_l4.h diff --git a/common_features.mk b/common_features.mk index 8c593024f0d1..0fa971a6718f 100644 --- a/common_features.mk +++ b/common_features.mk @@ -189,6 +189,12 @@ else COMMON_VPATH += $(PLATFORM_PATH)/$(PLATFORM_KEY)/$(DRIVER_DIR)/eeprom SRC += eeprom_driver.c SRC += eeprom_stm32_L0_L1.c + else ifneq ($(filter $(MCU_SERIES),STM32L4xx),) + OPT_DEFS += -DEEPROM_DRIVER + COMMON_VPATH += $(DRIVER_PATH)/eeprom + SRC += eeprom_driver.c + SRC += $(PLATFORM_COMMON_DIR)/eeprom_stm32_l4.c + SRC += $(PLATFORM_COMMON_DIR)/flash_stm32.c else # This will effectively work the same as "transient" if not supported by the chip SRC += $(PLATFORM_COMMON_DIR)/eeprom_teensy.c diff --git a/keyboards/keychron/q1/chconf.h b/keyboards/keychron/q1/chconf.h new file mode 100644 index 000000000000..a331fdef3751 --- /dev/null +++ b/keyboards/keychron/q1/chconf.h @@ -0,0 +1,30 @@ +/* Copyright 2020 QMK + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * This file was auto-generated by: + * `qmk chibios-confmigrate -i keyboards/acheron/arctic/chconf.h -r platforms/chibios/common/configs/chconf.h` + */ + +#pragma once + +#define CH_CFG_ST_FREQUENCY 10000 + +#define CH_CFG_OPTIMIZE_SPEED FALSE + +#define CH_CFG_USE_CONDVARS_TIMEOUT FALSE + +#include_next \ No newline at end of file diff --git a/keyboards/keychron/q1/config.h b/keyboards/keychron/q1/config.h index 8107dd62510c..dd810061aa7a 100644 --- a/keyboards/keychron/q1/config.h +++ b/keyboards/keychron/q1/config.h @@ -16,30 +16,17 @@ #pragma once - /* USB Device descriptor parameter */ #define VENDOR_ID 0x3434 #define MANUFACTURER Keychron #define PRODUCT Keychron Q1 -/* key matrix size */ -#define MATRIX_ROWS 6 -#define MATRIX_COLS 15 - /* COL2ROW or ROW2COL */ #define DIODE_DIRECTION ROW2COL /* Set 0 if debouncing isn't needed */ #define DEBOUNCE 5 -/* RGB Matrix Driver Configuration */ -#define DRIVER_COUNT 2 -#define DRIVER_ADDR_1 0b1010000 -#define DRIVER_ADDR_2 0b1011111 - -/* DIP switch */ -#define DIP_SWITCH_MATRIX_GRID { {0,1} } - /* Disable DIP switch in matrix data */ #define MATRIX_MASKED diff --git a/keyboards/keychron/q1/halconf.h b/keyboards/keychron/q1/halconf.h new file mode 100644 index 000000000000..5614639e7975 --- /dev/null +++ b/keyboards/keychron/q1/halconf.h @@ -0,0 +1,27 @@ +/* Copyright 2020 QMK + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * This file was auto-generated by: + * `qmk chibios-confmigrate -i keyboards/nk65/halconf.h -r platforms/chibios/QMK_PROTON_C/configs/halconf.h` + */ + +#pragma once + +#define HAL_USE_I2C TRUE +#define HAL_USE_GPT TRUE + +#include_next \ No newline at end of file diff --git a/keyboards/keychron/q1/mcuconf.h b/keyboards/keychron/q1/mcuconf.h new file mode 100644 index 000000000000..b27214069285 --- /dev/null +++ b/keyboards/keychron/q1/mcuconf.h @@ -0,0 +1,30 @@ +/* Copyright 2020 QMK + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * This file was auto-generated by: + * `qmk chibios-confmigrate -i keyboards/acheron/arctic/mcuconf.h -r platforms/chibios/GENERIC_STM32_F072XB/configs/mcuconf.h` + */ + +#pragma once + +#include_next + +#undef STM32_I2C_USE_I2C1 +#define STM32_I2C_USE_I2C1 TRUE + +#undef STM32_GPT_USE_TIM1 +#define STM32_GPT_USE_TIM1 TRUE \ No newline at end of file diff --git a/keyboards/keychron/q1/q1.c b/keyboards/keychron/q1/q1.c index a316c1fdcfa1..2767fa4f3a1c 100644 --- a/keyboards/keychron/q1/q1.c +++ b/keyboards/keychron/q1/q1.c @@ -16,16 +16,6 @@ #include "q1.h" - -const matrix_row_t matrix_mask[] = { - 0b0111111111111101, - 0b0111111111111111, - 0b0111111111111111, - 0b0111111111111111, - 0b0111111111111111, - 0b0111111111111111, -}; - bool dip_switch_update_kb(uint8_t index, bool active) { if (!dip_switch_update_user(index, active)) { return false;} if (index == 0) { diff --git a/keyboards/keychron/q1/q1.h b/keyboards/keychron/q1/q1.h index eb9a7d69a74c..e30fccd17dd9 100644 --- a/keyboards/keychron/q1/q1.h +++ b/keyboards/keychron/q1/q1.h @@ -18,9 +18,10 @@ #include "quantum.h" - #if defined(KEYBOARD_keychron_q1_rev_0100) # include "rev_0100.h" #elif defined(KEYBOARD_keychron_q1_rev_0102) # include "rev_0102.h" +#elif defined(KEYBOARD_keychron_q1_rev_0107) +# include "rev_0107.h" #endif \ No newline at end of file diff --git a/keyboards/keychron/q1/rev_0100/config.h b/keyboards/keychron/q1/rev_0100/config.h index 435f386a596b..3d70a76a19bd 100644 --- a/keyboards/keychron/q1/rev_0100/config.h +++ b/keyboards/keychron/q1/rev_0100/config.h @@ -16,15 +16,26 @@ #pragma once - /* USB Device descriptor parameter */ #define PRODUCT_ID 0x0100 #define DEVICE_VER 0x0100 +/* key matrix size */ +#define MATRIX_ROWS 6 +#define MATRIX_COLS 15 + /* key matrix pins */ #define MATRIX_ROW_PINS { D3, D2, B3, B2, B1, B0 } #define MATRIX_COL_PINS { D5, D4, D6, D7, B4, B5, B6, C6, C7, F7, F6, F5, F4, F1, F0 } +/* DIP switch */ +#define DIP_SWITCH_MATRIX_GRID { {0,1} } + +/* RGB Matrix Driver Configuration */ +#define DRIVER_COUNT 2 +#define DRIVER_ADDR_1 0b1010000 +#define DRIVER_ADDR_2 0b1011111 + /* RGB Matrix Configuration */ #define DRIVER_1_LED_TOTAL 59 #define DRIVER_2_LED_TOTAL 23 diff --git a/keyboards/keychron/q1/rev_0100/rev_0100.c b/keyboards/keychron/q1/rev_0100/rev_0100.c index f42466952796..6a02a8944d65 100644 --- a/keyboards/keychron/q1/rev_0100/rev_0100.c +++ b/keyboards/keychron/q1/rev_0100/rev_0100.c @@ -16,6 +16,14 @@ #include "quantum.h" +const matrix_row_t matrix_mask[] = { + 0b0111111111111101, + 0b0111111111111111, + 0b0111111111111111, + 0b0111111111111111, + 0b0111111111111111, + 0b0111111111111111, +}; const is31_led PROGMEM g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations diff --git a/keyboards/keychron/q1/rev_0102/config.h b/keyboards/keychron/q1/rev_0102/config.h index a537ab4e0d56..d7b04967805e 100644 --- a/keyboards/keychron/q1/rev_0102/config.h +++ b/keyboards/keychron/q1/rev_0102/config.h @@ -16,15 +16,26 @@ #pragma once - /* USB Device descriptor parameter */ #define PRODUCT_ID 0x0102 #define DEVICE_VER 0x0100 +/* key matrix size */ +#define MATRIX_ROWS 6 +#define MATRIX_COLS 15 + /* key matrix pins */ #define MATRIX_ROW_PINS { D3, D2, B3, B2, B1, B0 } #define MATRIX_COL_PINS { D5, D4, D6, D7, B4, B5, B6, C6, C7, F7, F6, F5, F4, F1, F0 } +/* DIP switch */ +#define DIP_SWITCH_MATRIX_GRID { {0,1} } + +/* RGB Matrix Driver Configuration */ +#define DRIVER_COUNT 2 +#define DRIVER_ADDR_1 0b1010000 +#define DRIVER_ADDR_2 0b1011111 + /* RGB Matrix Configuration */ #define DRIVER_1_LED_TOTAL 59 #define DRIVER_2_LED_TOTAL 24 diff --git a/keyboards/keychron/q1/rev_0102/rev_0102.c b/keyboards/keychron/q1/rev_0102/rev_0102.c index e8a2c85ae366..e1e004f75e04 100644 --- a/keyboards/keychron/q1/rev_0102/rev_0102.c +++ b/keyboards/keychron/q1/rev_0102/rev_0102.c @@ -16,6 +16,14 @@ #include "quantum.h" +const matrix_row_t matrix_mask[] = { + 0b0111111111111101, + 0b0111111111111111, + 0b0111111111111111, + 0b0111111111111111, + 0b0111111111111111, + 0b0111111111111111, +}; const is31_led PROGMEM g_is31_leds[DRIVER_LED_TOTAL] = { /* Refer to IS31 manual for these locations diff --git a/keyboards/keychron/q1/rev_0107/config.h b/keyboards/keychron/q1/rev_0107/config.h new file mode 100644 index 000000000000..034796c7f9ec --- /dev/null +++ b/keyboards/keychron/q1/rev_0107/config.h @@ -0,0 +1,61 @@ +/* Copyright 2021 @ Keychron (https://www.keychron.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +/* USB Device descriptor parameter */ +#define PRODUCT_ID 0x0107 +#define DEVICE_VER 0x0200 + +/* key matrix size */ +#define MATRIX_ROWS 6 +#define MATRIX_COLS 16 + +/* key matrix pins */ +#define MATRIX_ROW_PINS { B5, B4, B3, A15, A14, A13 } +#define MATRIX_COL_PINS { C14, C15, A0, A1, A2, A3, A4, A5, NO_PIN, NO_PIN, NO_PIN, NO_PIN, NO_PIN, NO_PIN, NO_PIN, NO_PIN } + +/* DIP switch */ +#define DIP_SWITCH_MATRIX_GRID { {5,4} } + +/* RGB Matrix Driver Configuration */ +#define DRIVER_COUNT 2 +#define DRIVER_ADDR_1 0b1110111 +#define DRIVER_ADDR_2 0b1110100 + +/* RGB Matrix Configuration */ +#define DRIVER_1_LED_TOTAL 45 +#define DRIVER_2_LED_TOTAL 37 +#define DRIVER_LED_TOTAL (DRIVER_1_LED_TOTAL + DRIVER_2_LED_TOTAL) + +/* Scan phase of led driver set as MSKPHASE_9CHANNEL(defined as 0x03 in CKLED2001.h) */ +#define PHASE_CHANNEL MSKPHASE_9CHANNEL + +/* Set the maxium brightness as 190 in order to limit the current to 450mA */ +#define RGB_MATRIX_MAXIMUM_BRIGHTNESS 190 + +/* Set USB polling rate as 1 milliseconds */ +#define USB_POLLING_INTERVAL_MS 1 + +/* We have 2KB EEPROM size on STM32L432 */ +#define DYNAMIC_KEYMAP_EEPROM_MAX_ADDR 2047 + +/* Encoder used pins */ +#define ENCODERS_PAD_A { A10 } +#define ENCODERS_PAD_B { A8 } + +/* Specifies the number of pulses the encoder registers between each detent */ +#define ENCODER_RESOLUTION 4 diff --git a/keyboards/keychron/q1/rev_0107/keymaps/default/info.json b/keyboards/keychron/q1/rev_0107/keymaps/default/info.json new file mode 100644 index 000000000000..155cabb3b106 --- /dev/null +++ b/keyboards/keychron/q1/rev_0107/keymaps/default/info.json @@ -0,0 +1,98 @@ +{ + "keyboard_name": "Keychron Q1", + "url": "https://github.com/Keychron", + "maintainer": "lalalademaxiya1", + "layouts": { + "LAYOUT_ansi_82": { + "layout": [ + {"label":"Esc", "x":0, "y":0}, + {"label":"F1", "x":1.25, "y":0}, + {"label":"F2", "x":2.25, "y":0}, + {"label":"F3", "x":3.25, "y":0}, + {"label":"F4", "x":4.25, "y":0}, + {"label":"F5", "x":5.5, "y":0}, + {"label":"F6", "x":6.5, "y":0}, + {"label":"F7", "x":7.5, "y":0}, + {"label":"F8", "x":8.5, "y":0}, + {"label":"F9", "x":9.75, "y":0}, + {"label":"F10", "x":10.75, "y":0}, + {"label":"F11", "x":11.75, "y":0}, + {"label":"F12", "x":12.75, "y":0}, + {"label":"Delete", "x":14, "y":0}, + {"label":"Mute", "x":15.25, "y":0}, + + {"label":"~", "x":0, "y":1.25}, + {"label":"!", "x":1, "y":1.25}, + {"label":"@", "x":2, "y":1.25}, + {"label":"#", "x":3, "y":1.25}, + {"label":"$", "x":4, "y":1.25}, + {"label":"%", "x":5, "y":1.25}, + {"label":"^", "x":6, "y":1.25}, + {"label":"&", "x":7, "y":1.25}, + {"label":"*", "x":8, "y":1.25}, + {"label":"(", "x":9, "y":1.25}, + {"label":")", "x":10, "y":1.25}, + {"label":"_", "x":11, "y":1.25}, + {"label":"+", "x":12, "y":1.25}, + {"label":"Backspace", "x":13, "y":1.25, "w":2}, + {"label":"Page Up", "x":15.25, "y":1.25}, + + {"label":"Tab", "x":0, "y":2.25, "w":1.5}, + {"label":"Q", "x":1.5, "y":2.25}, + {"label":"W", "x":2.5, "y":2.25}, + {"label":"E", "x":3.5, "y":2.25}, + {"label":"R", "x":4.5, "y":2.25}, + {"label":"T", "x":5.5, "y":2.25}, + {"label":"Y", "x":6.5, "y":2.25}, + {"label":"U", "x":7.5, "y":2.25}, + {"label":"I", "x":8.5, "y":2.25}, + {"label":"O", "x":9.5, "y":2.25}, + {"label":"P", "x":10.5, "y":2.25}, + {"label":"{", "x":11.5, "y":2.25}, + {"label":"}", "x":12.5, "y":2.25}, + {"label":"|", "x":13.5, "y":2.25, "w":1.5}, + {"label":"Page Down", "x":15.25, "y":2.25}, + + {"label":"Caps Lock", "x":0, "y":3.25, "w":1.75}, + {"label":"A", "x":1.75, "y":3.25}, + {"label":"S", "x":2.75, "y":3.25}, + {"label":"D", "x":3.75, "y":3.25}, + {"label":"F", "x":4.75, "y":3.25}, + {"label":"G", "x":5.75, "y":3.25}, + {"label":"H", "x":6.75, "y":3.25}, + {"label":"J", "x":7.75, "y":3.25}, + {"label":"K", "x":8.75, "y":3.25}, + {"label":"L", "x":9.75, "y":3.25}, + {"label":":", "x":10.75, "y":3.25}, + {"label":"\"", "x":11.75, "y":3.25}, + {"label":"Enter", "x":12.75, "y":3.25, "w":2.25}, + {"label":"Home", "x":15.25, "y":3.25}, + + {"label":"Shift", "x":0, "y":4.25, "w":2.25}, + {"label":"Z", "x":2.25, "y":4.25}, + {"label":"X", "x":3.25, "y":4.25}, + {"label":"C", "x":4.25, "y":4.25}, + {"label":"V", "x":5.25, "y":4.25}, + {"label":"B", "x":6.25, "y":4.25}, + {"label":"N", "x":7.25, "y":4.25}, + {"label":"M", "x":8.25, "y":4.25}, + {"label":"<", "x":9.25, "y":4.25}, + {"label":">", "x":10.25, "y":4.25}, + {"label":"?", "x":11.25, "y":4.25}, + {"label":"Shift", "x":12.25, "y":4.25, "w":1.75}, + {"label":"Up", "x":14.25, "y":4.5}, + + {"label":"Ctrl", "x":0, "y":5.25, "w":1.25}, + {"label":"Win", "x":1.25, "y":5.25, "w":1.25}, + {"label":"Alt", "x":2.5, "y":5.25, "w":1.25}, + {"label":"Space", "x":3.75, "y":5.25, "w":6.25}, + {"label":"Alt", "x":10, "y":5.25}, + {"label":"Fn", "x":11, "y":5.25}, + {"label":"Ctrl", "x":12, "y":5.25}, + {"label":"Left", "x":13.25, "y":5.5}, + {"label":"Down", "x":14.25, "y":5.5}, + {"label":"Right", "x":15.25, "y":5.5} + ] + } + } +} \ No newline at end of file diff --git a/keyboards/keychron/q1/rev_0107/keymaps/default/keymap.c b/keyboards/keychron/q1/rev_0107/keymaps/default/keymap.c new file mode 100644 index 000000000000..20a25b1b3809 --- /dev/null +++ b/keyboards/keychron/q1/rev_0107/keymaps/default/keymap.c @@ -0,0 +1,135 @@ +/* Copyright 2021 @ Keychron (https://www.keychron.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include QMK_KEYBOARD_H + +#ifdef VIA_ENABLE + #define USER_START USER00 +#else + #define USER_START SAFE_RANGE +#endif + +enum layers{ + MAC_BASE, + MAC_FN, + WIN_BASE, + WIN_FN +}; + +enum custom_keycodes { + KC_MISSION_CONTROL = USER_START, + KC_LAUNCHPAD, + KC_LOPTN, + KC_ROPTN, + KC_LCMMD, + KC_RCMMD, + KC_TASK_VIEW, + KC_FILE_EXPLORER +}; + +typedef struct PACKED { + uint8_t len; + uint8_t keycode[2]; +} key_combination_t; + +key_combination_t key_comb_list[2] = { + {2, {KC_LWIN, KC_TAB}}, + {2, {KC_LWIN, KC_E}} +}; + +#define KC_MCTL KC_MISSION_CONTROL +#define KC_LPAD KC_LAUNCHPAD +#define KC_TASK KC_TASK_VIEW +#define KC_FLXP KC_FILE_EXPLORER + +static uint8_t mac_keycode[4] = { KC_LOPT, KC_ROPT, KC_LCMD, KC_RCMD }; + +const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { + [MAC_BASE] = LAYOUT_ansi_82( + KC_ESC, KC_BRID, KC_BRIU, KC_MCTL, KC_LPAD, RGB_VAD, RGB_VAI, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, KC_DEL, KC_MUTE, + KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_PGUP, + KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_PGDN, + KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, KC_HOME, + KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP, + KC_LCTL, KC_LOPTN, KC_LCMMD, KC_SPC, KC_RCMMD,MO(MAC_FN), KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT), + + [MAC_FN] = LAYOUT_ansi_82( + KC_TRNS, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + RGB_TOG, RGB_MOD, RGB_VAI, RGB_HUI, RGB_SAI, RGB_SPI, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, RGB_RMOD, RGB_VAD, RGB_HUD, RGB_SAD, RGB_SPD, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS), + + [WIN_BASE] = LAYOUT_ansi_82( + KC_ESC, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_DEL, KC_MUTE, + KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_PGUP, + KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_PGDN, + KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, KC_HOME, + KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP, + KC_LCTL, KC_LCMD, KC_LALT, KC_SPC, KC_RALT, MO(WIN_FN), KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT), + + [WIN_FN] = LAYOUT_ansi_82( + KC_TRNS, KC_BRID, KC_BRIU, KC_TASK, KC_FLXP, RGB_VAD, RGB_VAI, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + RGB_TOG, RGB_MOD, RGB_VAI, RGB_HUI, RGB_SAI, RGB_SPI, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, RGB_RMOD, RGB_VAD, RGB_HUD, RGB_SAD, RGB_SPD, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS), +}; + +bool process_record_user(uint16_t keycode, keyrecord_t *record) { + switch (keycode) { + case KC_LOPTN: + case KC_ROPTN: + case KC_LCMMD: + case KC_RCMMD: + if (record->event.pressed) { + register_code(mac_keycode[keycode - KC_LOPTN]); + } else { + unregister_code(mac_keycode[keycode - KC_LOPTN]); + } + return false; + case KC_MISSION_CONTROL: + if (record->event.pressed) { + host_consumer_send(0x29F); + } else { + host_consumer_send(0); + } + return false; // Skip all further processing of this key + case KC_LAUNCHPAD: + if (record->event.pressed) { + host_consumer_send(0x2A0); + } else { + host_consumer_send(0); + } + return false; // Skip all further processing of this key + case KC_TASK: + case KC_FLXP: + if (record->event.pressed) { + for (uint8_t i = 0; i < key_comb_list[keycode - KC_TASK].len; i++) { + register_code(key_comb_list[keycode - KC_TASK].keycode[i]); + } + } else { + for (uint8_t i = 0; i < key_comb_list[keycode - KC_TASK].len; i++) { + unregister_code(key_comb_list[keycode - KC_TASK].keycode[i]); + } + } + return false; // Skip all further processing of this key + default: + return true; // Process all other keycodes normally + } +} diff --git a/keyboards/keychron/q1/rev_0107/keymaps/via/info.json b/keyboards/keychron/q1/rev_0107/keymaps/via/info.json new file mode 100644 index 000000000000..20d55233f59f --- /dev/null +++ b/keyboards/keychron/q1/rev_0107/keymaps/via/info.json @@ -0,0 +1,101 @@ +{ + "keyboard_name": "Keychron Q1", + "url": "https://github.com/Keychron", + "maintainer": "lalalademaxiya1", + "layouts": { + "LAYOUT_all": { + "layout": [ + {"label":"Esc", "x":0, "y":0}, + {"label":"F1", "x":1.25, "y":0}, + {"label":"F2", "x":2.25, "y":0}, + {"label":"F3", "x":3.25, "y":0}, + {"label":"F4", "x":4.25, "y":0}, + {"label":"F5", "x":5.5, "y":0}, + {"label":"F6", "x":6.5, "y":0}, + {"label":"F7", "x":7.5, "y":0}, + {"label":"F8", "x":8.5, "y":0}, + {"label":"F9", "x":9.75, "y":0}, + {"label":"F10", "x":10.75, "y":0}, + {"label":"F11", "x":11.75, "y":0}, + {"label":"F12", "x":12.75, "y":0}, + {"label":"Delete", "x":14, "y":0}, + + {"label":"Mute", "x":15.25, "y":0, "w":0.75}, + {"label":"Vol-", "x":16, "y":0, "w":0.75, "h":0.5}, + {"label":"Vol+", "x":16, "y":0.5, "w":0.75, "h":0.5}, + + {"label":"~", "x":0, "y":1.25}, + {"label":"!", "x":1, "y":1.25}, + {"label":"@", "x":2, "y":1.25}, + {"label":"#", "x":3, "y":1.25}, + {"label":"$", "x":4, "y":1.25}, + {"label":"%", "x":5, "y":1.25}, + {"label":"^", "x":6, "y":1.25}, + {"label":"&", "x":7, "y":1.25}, + {"label":"*", "x":8, "y":1.25}, + {"label":"(", "x":9, "y":1.25}, + {"label":")", "x":10, "y":1.25}, + {"label":"_", "x":11, "y":1}, + {"label":"+", "x":12, "y":1.25}, + {"label":"Backspace", "x":13, "y":1.25, "w":2}, + {"label":"Page Up", "x":15.25, "y":1.25}, + + {"label":"Tab", "x":0, "y":2.25, "w":1.5}, + {"label":"Q", "x":1.5, "y":2.25}, + {"label":"W", "x":2.5, "y":2.25}, + {"label":"E", "x":3.5, "y":2.25}, + {"label":"R", "x":4.5, "y":2.25}, + {"label":"T", "x":5.5, "y":2.25}, + {"label":"Y", "x":6.5, "y":2.25}, + {"label":"U", "x":7.5, "y":2.25}, + {"label":"I", "x":8.5, "y":2.25}, + {"label":"O", "x":9.5, "y":2.25}, + {"label":"P", "x":10.5, "y":2.25}, + {"label":"{", "x":11.5, "y":2.25}, + {"label":"}", "x":12.5, "y":2.25}, + {"label":"|", "x":13.5, "y":2.25, "w":1.5}, + {"label":"Page Down", "x":15.25, "y":2.25}, + + {"label":"Caps Lock", "x":0, "y":3.25, "w":1.75}, + {"label":"A", "x":1.75, "y":3.25}, + {"label":"S", "x":2.75, "y":3.25}, + {"label":"D", "x":3.75, "y":3.25}, + {"label":"F", "x":4.75, "y":3.25}, + {"label":"G", "x":5.75, "y":3.25}, + {"label":"H", "x":6.75, "y":3.25}, + {"label":"J", "x":7.75, "y":3.25}, + {"label":"K", "x":8.75, "y":3.25}, + {"label":"L", "x":9.75, "y":3.25}, + {"label":":", "x":10.75, "y":3.25}, + {"label":"\"", "x":11.75, "y":3.25}, + {"label":"Enter", "x":12.75, "y":3.25, "w":2.25}, + {"label":"Home", "x":15.25, "y":3.25}, + + {"label":"Shift", "x":0, "y":4.25, "w":2.25}, + {"label":"Z", "x":2.25, "y":4.25}, + {"label":"X", "x":3.25, "y":4.25}, + {"label":"C", "x":4.25, "y":4.25}, + {"label":"V", "x":5.25, "y":4.25}, + {"label":"B", "x":6.25, "y":4.25}, + {"label":"N", "x":7.25, "y":4.25}, + {"label":"M", "x":8.25, "y":4.25}, + {"label":"<", "x":9.25, "y":4.25}, + {"label":">", "x":10.25, "y":4.25}, + {"label":"?", "x":11.25, "y":4.25}, + {"label":"Shift", "x":12.25, "y":4.25, "w":1.75}, + {"label":"Up", "x":14.25, "y":4.5}, + + {"label":"Ctrl", "x":0, "y":5.25, "w":1.25}, + {"label":"Win", "x":1.25, "y":5.25, "w":1.25}, + {"label":"Alt", "x":2.5, "y":5.25, "w":1.25}, + {"label":"Space", "x":3.75, "y":5.25, "w":6.25}, + {"label":"Alt", "x":10, "y":5.25}, + {"label":"Fn", "x":11, "y":5.25}, + {"label":"Ctrl", "x":12, "y":5.25}, + {"label":"Left", "x":13.25, "y":5.5}, + {"label":"Down", "x":14.25, "y":5.5}, + {"label":"Right", "x":15.25, "y":5.5} + ] + } + } +} diff --git a/keyboards/keychron/q1/rev_0107/keymaps/via/keymap.c b/keyboards/keychron/q1/rev_0107/keymaps/via/keymap.c new file mode 100644 index 000000000000..a2c081765226 --- /dev/null +++ b/keyboards/keychron/q1/rev_0107/keymaps/via/keymap.c @@ -0,0 +1,177 @@ +/* Copyright 2021 @ Keychron (https://www.keychron.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include QMK_KEYBOARD_H + +#ifdef VIA_ENABLE + #define USER_START USER00 +#else + #define USER_START SAFE_RANGE +#endif + +enum layers{ + MAC_BASE, + MAC_FN, + WIN_BASE, + WIN_FN +}; + +enum custom_keycodes { + KC_MISSION_CONTROL = USER_START, + KC_LAUNCHPAD, + KC_LOPTN, + KC_ROPTN, + KC_LCMMD, + KC_RCMMD, + KC_TASK_VIEW, + KC_FILE_EXPLORER +}; + +#define KC_MCTL KC_MISSION_CONTROL +#define KC_LPAD KC_LAUNCHPAD +#define KC_TASK KC_TASK_VIEW +#define KC_FLXP KC_FILE_EXPLORER + +typedef struct PACKED { + uint8_t len; + uint8_t keycode[2]; +} key_combination_t; + +key_combination_t key_comb_list[2] = { + {2, {KC_LWIN, KC_TAB}}, + {2, {KC_LWIN, KC_E}} +}; + +static uint8_t mac_keycode[4] = { KC_LOPT, KC_ROPT, KC_LCMD, KC_RCMD }; + +const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { + [MAC_BASE] = LAYOUT_all( + KC_ESC, KC_BRID, KC_BRIU, KC_MCTL, KC_LPAD, RGB_VAD, RGB_VAI, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, KC_DEL, KC_MUTE, + KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_PGUP, + KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_PGDN, + KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, KC_HOME, + KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP, + KC_LCTL, KC_LOPTN, KC_LCMMD, KC_SPC, KC_VOLD, KC_VOLU, KC_RCMMD,MO(MAC_FN), KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT), + + [MAC_FN] = LAYOUT_all( + KC_TRNS, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_TRNS, RGB_TOG, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + RGB_TOG, RGB_MOD, RGB_VAI, RGB_HUI, RGB_SAI, RGB_SPI, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, RGB_RMOD, RGB_VAD, RGB_HUD, RGB_SAD, RGB_SPD, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, RGB_VAD, RGB_VAI, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS), + + [WIN_BASE] = LAYOUT_all( + KC_ESC, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_DEL, KC_MUTE, + KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_PGUP, + KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_PGDN, + KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, KC_HOME, + KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP, + KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, KC_VOLD, KC_VOLU, KC_RALT, MO(WIN_FN), KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT), + + [WIN_FN] = LAYOUT_all( + KC_TRNS, KC_BRID, KC_BRIU, KC_TASK, KC_FLXP, RGB_VAD, RGB_VAI, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, KC_TRNS, RGB_TOG, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + RGB_TOG, RGB_MOD, RGB_VAI, RGB_HUI, RGB_SAI, RGB_SPI, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, RGB_RMOD, RGB_VAD, RGB_HUD, RGB_SAD, RGB_SPD, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, RGB_VAD, RGB_VAI, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS), +}; + +#if defined(VIA_ENABLE) && defined(ENCODER_ENABLE) + +#define ENCODERS 1 +static uint8_t encoder_state[ENCODERS] = {0}; +static keypos_t encoder_cw[ENCODERS] = {{ 8, 5 }}; +static keypos_t encoder_ccw[ENCODERS] = {{ 7, 5 }}; + +void encoder_action_unregister(void) { + for (int index = 0; index < ENCODERS; ++index) { + if (encoder_state[index]) { + keyevent_t encoder_event = (keyevent_t) { + .key = encoder_state[index] >> 1 ? encoder_cw[index] : encoder_ccw[index], + .pressed = false, + .time = (timer_read() | 1) + }; + encoder_state[index] = 0; + action_exec(encoder_event); + } + } +} + +void encoder_action_register(uint8_t index, bool clockwise) { + keyevent_t encoder_event = (keyevent_t) { + .key = clockwise ? encoder_cw[index] : encoder_ccw[index], + .pressed = true, + .time = (timer_read() | 1) + }; + encoder_state[index] = (clockwise ^ 1) | (clockwise << 1); + action_exec(encoder_event); +} + +void matrix_scan_user(void) { + encoder_action_unregister(); +} + +bool encoder_update_user(uint8_t index, bool clockwise) { + encoder_action_register(index, clockwise); + return false; +}; + +#endif + +bool process_record_user(uint16_t keycode, keyrecord_t *record) { + switch (keycode) { + case KC_LOPTN: + case KC_ROPTN: + case KC_LCMMD: + case KC_RCMMD: + if (record->event.pressed) { + register_code(mac_keycode[keycode - KC_LOPTN]); + } else { + unregister_code(mac_keycode[keycode - KC_LOPTN]); + } + return false; + case KC_MCTL: + if (record->event.pressed) { + host_consumer_send(0x29F); + } else { + host_consumer_send(0); + } + return false; // Skip all further processing of this key + case KC_LPAD: + if (record->event.pressed) { + host_consumer_send(0x2A0); + } else { + host_consumer_send(0); + } + return false; // Skip all further processing of this key + case KC_TASK: + case KC_FLXP: + if (record->event.pressed) { + for (uint8_t i = 0; i < key_comb_list[keycode - KC_TASK].len; i++) { + register_code(key_comb_list[keycode - KC_TASK].keycode[i]); + } + } else { + for (uint8_t i = 0; i < key_comb_list[keycode - KC_TASK].len; i++) { + unregister_code(key_comb_list[keycode - KC_TASK].keycode[i]); + } + } + return false; // Skip all further processing of this key + default: + return true; // Process all other keycodes normally + } +} diff --git a/keyboards/keychron/q1/rev_0107/keymaps/via/rules.mk b/keyboards/keychron/q1/rev_0107/keymaps/via/rules.mk new file mode 100644 index 000000000000..ea7d10f812b3 --- /dev/null +++ b/keyboards/keychron/q1/rev_0107/keymaps/via/rules.mk @@ -0,0 +1,2 @@ +VIA_ENABLE = yes +MOUSEKEY_ENABLE = yes \ No newline at end of file diff --git a/keyboards/keychron/q1/rev_0107/readme.md b/keyboards/keychron/q1/rev_0107/readme.md new file mode 100644 index 000000000000..ae9e93e49529 --- /dev/null +++ b/keyboards/keychron/q1/rev_0107/readme.md @@ -0,0 +1,6 @@ +# The ANSI variant of the Keychron Q1 + +- Add EC11 rotary encoder support. +- Turn colckwise to increase volume and turn anti-colckwise to decrease volume. +- Press top right key pushbutton to mute. + diff --git a/keyboards/keychron/q1/rev_0107/rev_0107.c b/keyboards/keychron/q1/rev_0107/rev_0107.c new file mode 100644 index 000000000000..c8f16309d32e --- /dev/null +++ b/keyboards/keychron/q1/rev_0107/rev_0107.c @@ -0,0 +1,165 @@ +/* Copyright 2021 @ Keychron (https://www.keychron.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "quantum.h" + +const matrix_row_t matrix_mask[] = { + 0b1111111111111111, + 0b1111111111111111, + 0b1111111111111111, + 0b1111111111111111, + 0b1111111111111111, + 0b1111111111101111, +}; + +#ifdef RGB_MATRIX_ENABLE +const ckled2001_led PROGMEM g_ckled2001_leds[DRIVER_LED_TOTAL] = { +/* Refer to IS31 manual for these locations + * driver + * | R location + * | | G location + * | | | B location + * | | | | */ + {0, C_1, A_1, B_1}, + {0, C_2, A_2, B_2}, + {0, C_3, A_3, B_3}, + {0, C_4, A_4, B_4}, + {0, C_5, A_5, B_5}, + {0, C_6, A_6, B_6}, + {0, C_7, A_7, B_7}, + {0, C_8, A_8, B_8}, + {0, C_9, A_9, B_9}, + {0, C_10, A_10, B_10}, + {0, C_11, A_11, B_11}, + {0, C_12, A_12, B_12}, + {0, C_13, A_13, B_13}, + {0, C_14, A_14, B_14}, + {0, C_16, A_16, B_16}, + + {0, I_1, G_1, H_1}, + {0, I_2, G_2, H_2}, + {0, I_3, G_3, H_3}, + {0, I_4, G_4, H_4}, + {0, I_5, G_5, H_5}, + {0, I_6, G_6, H_6}, + {0, I_7, G_7, H_7}, + {0, I_8, G_8, H_8}, + {0, I_9, G_9, H_9}, + {0, I_10, G_10, H_10}, + {0, I_11, G_11, H_11}, + {0, I_12, G_12, H_12}, + {0, I_13, G_13, H_13}, + {0, I_14, G_14, H_14}, + {0, I_16, G_16, H_16}, + + {0, F_1, D_1, E_1}, + {0, F_2, D_2, E_2}, + {0, F_3, D_3, E_3}, + {0, F_4, D_4, E_4}, + {0, F_5, D_5, E_5}, + {0, F_6, D_6, E_6}, + {0, F_7, D_7, E_7}, + {0, F_8, D_8, E_8}, + {0, F_9, D_9, E_9}, + {0, F_10, D_10, E_10}, + {0, F_11, D_11, E_11}, + {0, F_12, D_12, E_12}, + {0, F_13, D_13, E_13}, + {0, F_14, D_14, E_14}, + {0, F_16, D_16, E_16}, + + {1, I_1, G_1, H_1}, + {1, I_2, G_2, H_2}, + {1, I_3, G_3, H_3}, + {1, I_4, G_4, H_4}, + {1, I_5, G_5, H_5}, + {1, I_6, G_6, H_6}, + {1, I_7, G_7, H_7}, + {1, I_8, G_8, H_8}, + {1, I_9, G_9, H_9}, + {1, I_10, G_10, H_10}, + {1, I_11, G_11, H_11}, + {1, I_12, G_12, H_12}, + {1, I_14, G_14, H_14}, + {1, I_16, G_16, H_16}, + + {1, F_1, D_1, E_1}, + {1, F_3, D_3, E_3}, + {1, F_4, D_4, E_4}, + {1, F_5, D_5, E_5}, + {1, F_6, D_6, E_6}, + {1, F_7, D_7, E_7}, + {1, F_8, D_8, E_8}, + {1, F_9, D_9, E_9}, + {1, F_10, D_10, E_10}, + {1, F_11, D_11, E_11}, + {1, F_12, D_12, E_12}, + {1, F_14, D_14, E_14}, + {1, F_15, D_15, E_15}, + + {1, C_1, A_1, B_1}, + {1, C_2, A_2, B_2}, + {1, C_3, A_3, B_3}, + {1, C_7, A_7, B_7}, + {1, C_11, A_11, B_11}, + {1, C_12, A_12, B_12}, + {1, C_13, A_13, B_13}, + {1, C_14, A_14, B_14}, + {1, C_15, A_15, B_15}, + {1, C_16, A_16, B_16}, +}; + +led_config_t g_led_config = { + { + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, NO_LED, 14 }, + { 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, NO_LED, 29 }, + { 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, NO_LED, 44 }, + { 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, NO_LED, 57, NO_LED, 58 }, + { 59, NO_LED, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, NO_LED, 70, 71, NO_LED }, + { 72, 73, 74, NO_LED, NO_LED, NO_LED, 75, NO_LED, NO_LED, NO_LED, 76, 77, 78, 79, 80, 81 }, + }, + { + {0, 0}, {15, 0}, {30, 0}, {45, 0}, {60, 0}, {75, 0}, {90, 0}, {105, 0}, {120, 0}, {135, 0}, {150, 0}, {165, 0}, {180, 0}, {195, 0}, {224, 0}, + {0,13}, {15,13}, {30,13}, {45,13}, {60,13}, {75,13}, {90,13}, {105,13}, {120,13}, {135,13}, {150,13}, {165,13}, {180,13}, {195,13}, {224,13}, + {0,26}, {15,26}, {30,26}, {45,26}, {60,26}, {75,26}, {90,26}, {105,26}, {120,26}, {135,26}, {150,26}, {165,26}, {180,26}, {195,26}, {224,26}, + {0,39}, {15,39}, {30,39}, {45,39}, {60,39}, {75,39}, {90,39}, {105,39}, {120,39}, {135,39}, {150,39}, {165,39}, {195,39}, {224,39}, + {0,52}, {30,52}, {45,52}, {60,52}, {75,52}, {90,52}, {105,52}, {120,52}, {135,52}, {150,52}, {165,52}, {195,52}, {210,52}, + {0,64}, {15,64}, {30,64}, {90,64}, {150,64}, {165,64}, {180,64}, {195,64}, {210,64}, {224,64}, + }, + { + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + } +}; +#endif + +#ifdef ENCODER_ENABLE +bool encoder_update_kb(uint8_t index, bool clockwise) { + if (!encoder_update_user(index, clockwise)) { return false; } + if (index == 0) { + if (clockwise) { + tap_code_delay(KC_VOLU, 10); + } else { + tap_code_delay(KC_VOLD, 10); + } + } + return true; +} +#endif diff --git a/keyboards/keychron/q1/rev_0107/rev_0107.h b/keyboards/keychron/q1/rev_0107/rev_0107.h new file mode 100644 index 000000000000..cd7fd0f9ae4e --- /dev/null +++ b/keyboards/keychron/q1/rev_0107/rev_0107.h @@ -0,0 +1,52 @@ +/* Copyright 2021 @ Keychron (https://www.keychron.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "quantum.h" + +#define XXX KC_NO + +#define LAYOUT_all( \ + K00, K01, K02, K03, K04, K05, K06, K07, K08, K09, K0A, K0B, K0C, K0D, K0F, \ + K10, K11, K12, K13, K14, K15, K16, K17, K18, K19, K1A, K1B, K1C, K1D, K1F, \ + K20, K21, K22, K23, K24, K25, K26, K27, K28, K29, K2A, K2B, K2C, K2D, K2F, \ + K30, K31, K32, K33, K34, K35, K36, K37, K38, K39, K3A, K3B, K3D, K3F, \ + K40, K42, K43, K44, K45, K46, K47, K48, K49, K4A, K4B, K4D, K4E, \ + K50, K51, K52, K56, K57, K58, K5A, K5B, K5C, K5D, K5E, K5F \ +) { \ + { K00, K01, K02, K03, K04, K05, K06, K07, K08, K09, K0A, K0B, K0C, K0D, XXX, K0F }, \ + { K10, K11, K12, K13, K14, K15, K16, K17, K18, K19, K1A, K1B, K1C, K1D, XXX, K1F }, \ + { K20, K21, K22, K23, K24, K25, K26, K27, K28, K29, K2A, K2B, K2C, K2D, XXX, K2F }, \ + { K30, K31, K32, K33, K34, K35, K36, K37, K38, K39, K3A, K3B, XXX, K3D, XXX, K3F }, \ + { K40, XXX, K42, K43, K44, K45, K46, K47, K48, K49, K4A, K4B, XXX, K4D, K4E, XXX }, \ + { K50, K51, K52, XXX, XXX, XXX, K56, K57, K58, XXX, K5A, K5B, K5C, K5D, K5E, K5F } \ +} +#define LAYOUT_ansi_82( \ + K00, K01, K02, K03, K04, K05, K06, K07, K08, K09, K0A, K0B, K0C, K0D, K0F, \ + K10, K11, K12, K13, K14, K15, K16, K17, K18, K19, K1A, K1B, K1C, K1D, K1F, \ + K20, K21, K22, K23, K24, K25, K26, K27, K28, K29, K2A, K2B, K2C, K2D, K2F, \ + K30, K31, K32, K33, K34, K35, K36, K37, K38, K39, K3A, K3B, K3D, K3F, \ + K40, K42, K43, K44, K45, K46, K47, K48, K49, K4A, K4B, K4D, K4E, \ + K50, K51, K52, K56, K5A, K5B, K5C, K5D, K5E, K5F \ +) { \ + { K00, K01, K02, K03, K04, K05, K06, K07, K08, K09, K0A, K0B, K0C, K0D, XXX, K0F }, \ + { K10, K11, K12, K13, K14, K15, K16, K17, K18, K19, K1A, K1B, K1C, K1D, XXX, K1F }, \ + { K20, K21, K22, K23, K24, K25, K26, K27, K28, K29, K2A, K2B, K2C, K2D, XXX, K2F }, \ + { K30, K31, K32, K33, K34, K35, K36, K37, K38, K39, K3A, K3B, XXX, K3D, XXX, K3F }, \ + { K40, XXX, K42, K43, K44, K45, K46, K47, K48, K49, K4A, K4B, XXX, K4D, K4E, XXX }, \ + { K50, K51, K52, XXX, XXX, XXX, K56, XXX, XXX, XXX, K5A, K5B, K5C, K5D, K5E, K5F } \ +} diff --git a/keyboards/keychron/q1/rev_0107/rules.mk b/keyboards/keychron/q1/rev_0107/rules.mk new file mode 100644 index 000000000000..1ab3a4491962 --- /dev/null +++ b/keyboards/keychron/q1/rev_0107/rules.mk @@ -0,0 +1,27 @@ +# MCU name +MCU = STM32L433 + +# Build Options +# change yes to no to disable +# +BOOTMAGIC_ENABLE = yes # Enable Bootmagic Lite +MOUSEKEY_ENABLE = yes # Mouse keys +EXTRAKEY_ENABLE = yes # Audio control and System control +CONSOLE_ENABLE = no # Console for debug +COMMAND_ENABLE = no # Commands for debug and configuration +NKRO_ENABLE = yes # USB N-key Rollover +BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality +RGBLIGHT_ENABLE = no # Enable keyboard RGB underglow +AUDIO_ENABLE = no # Audio output +ENCODER_ENABLE = yes # Enable Encoder +DIP_SWITCH_ENABLE = yes +RGB_MATRIX_ENABLE = yes +RGB_MATRIX_DRIVER = CKLED2001 + +# Enter lower-power sleep mode when on the ChibiOS idle thread +OPT_DEFS += -DCORTEX_ENABLE_WFI_IDLE=TRUE + +# custom matrix setup +CUSTOM_MATRIX = lite + +SRC += matrix.c diff --git a/platforms/chibios/eeprom_stm32_defs.h b/platforms/chibios/eeprom_stm32_defs.h index 66904f247f58..01214ed10721 100644 --- a/platforms/chibios/eeprom_stm32_defs.h +++ b/platforms/chibios/eeprom_stm32_defs.h @@ -25,7 +25,7 @@ # ifndef FEE_PAGE_COUNT # define FEE_PAGE_COUNT 2 // How many pages are used # endif -# elif defined(STM32F103xE) || defined(STM32F303xC) || defined(STM32F072xB) || defined(STM32F070xB) +# elif defined(STM32F103xE) || defined(STM32F303xC) || defined(STM32F072xB) || defined(STM32F070xB) || defined(STM32L432xx) || defined(STM32L443xx) # ifndef FEE_PAGE_SIZE # define FEE_PAGE_SIZE 0x800 // Page size = 2KByte # endif @@ -47,7 +47,7 @@ # define FEE_MCU_FLASH_SIZE 32 // Size in Kb # elif defined(GD32VF103C8) # define FEE_MCU_FLASH_SIZE 64 // Size in Kb -# elif defined(STM32F103xB) || defined(STM32F072xB) || defined(STM32F070xB) || defined(GD32VF103CB) +# elif defined(STM32F103xB) || defined(STM32F072xB) || defined(STM32F070xB) || defined(GD32VF103CB) || defined(STM32L432xx) || defined(STM32L443xx) # define FEE_MCU_FLASH_SIZE 128 // Size in Kb # elif defined(STM32F303xC) || defined(STM32F401xC) # define FEE_MCU_FLASH_SIZE 256 // Size in Kb diff --git a/platforms/chibios/eeprom_stm32_l4.c b/platforms/chibios/eeprom_stm32_l4.c new file mode 100644 index 000000000000..8f33881749bb --- /dev/null +++ b/platforms/chibios/eeprom_stm32_l4.c @@ -0,0 +1,546 @@ +/* + * This software is experimental and a work in progress. + * Under no circumstances should these files be used in relation to any critical system(s). + * Use of these files is at your own risk. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * This files are free to use from http://engsta.com/stm32-flash-memory-eeprom-emulator/ by + * Artur F. + * + * Modifications for QMK and STM32L432 by lalalademaxiya1 & lokher + * + * TODO: Add ECC correction interrupt handler. + */ + +#include +#include +#include +#include "flash_stm32.h" +#include "eeprom_stm32_l4.h" +#include "print.h" +/* + * We emulate eeprom by writing a snapshot compacted view of eeprom contents, + * followed by a write log of any change since that snapshot: + * + * === SIMULATED EEPROM CONTENTS === + * + * ┌─ Compacted─┬─ Write Log ──┐ + * │............│[DWord][DWord]│ + * │FFFF....FFFF│[DWord][DWord]│ + * │FFFFFFFFFFFF│[DWord][DWord]│ + * │....FFFFFFFF│[DWord][DWord]│ + * ├────────────┼──────────────┤ + * └──PAGE_BASE │ │ + * PAGE_LAST─┴─WRITE_BASE │ + * WRITE_LAST ──┘ + * + * Compacted contents are the 1's complement of the actual EEPROM contents. + * e.g. An 'FFFF' represents a '0000' value. + * + * The size of the 'compacted' area is equal to the size of the 'emulated' eeprom. + * The size of the compacted-area and write log are configurable, and the combined + * size of Compacted + WriteLog is a multiple FEE_PAGE_SIZE, which is MCU dependent. + * Simulated Eeprom contents are located at the end of available flash space. + * + * The following configuration defines can be set: + * + * FEE_PAGE_COUNT # Total number of pages to use for eeprom simulation (Compact + Write log) + * FEE_DENSITY_BYTES # Size of simulated eeprom. (Defaults to one pages of FEE_PAGE_COUNT) + * NOTE: The current implementation does not include page swapping, + * and FEE_DENSITY_BYTES will consume that amount of RAM as a cached view of actual EEPROM contents. + * + * The maximum size of FEE_DENSITY_BYTES is currently 8192. The write log size equals + * FEE_PAGE_COUNT * FEE_PAGE_SIZE - FEE_DENSITY_BYTES. + * The larger the write log, the less frequently the compacted area needs to be rewritten. + * + * + * *** General Algorithm *** + * + * During initialization: + * The contents of the Compacted-flash area are loaded and the 1's complement value + * is cached into memory (e.g. 0xFFFF in Flash represents 0x0000 in cache). + * Write log entries are processed until a 0xFFFF is reached. + * Each log entry updates 1/2/4 byte(s) in the cache. + * + * During reads: + * EEPROM contents are given back directly from the cache in memory. + * + * During writes: + * The contents of the cache is updated first. + * If the Compacted-flash area corresponding to the write address is unprogrammed, the 1's complement of the value is written directly into Compacted-flash + * Otherwise: + * If the write log is full, erase both the Compacted-flash area and the Write log, then write cached contents to the Compacted-flash area. + * Otherwise a Write log entry is constructed and appended to the next free position in the Write log. + * + * + * *** Write Log Structure *** + * + * Each log entry compose of double word (2 x 32-bit) due to the minimum program size of STM32L432 flash. + * + * === WRITE LOG ENTRY FORMATS === + * + * ╔══════════ Byte-Entry ═════════╗ + * ║ 00 01 XX XX ║ FF FF FF YY ║ + * ║ └─┬─┘ └─┬─┘ ║ └┘ ║ + * ║ Len Address ║ ~Value ║ + * ╚═══════════════╩═══════════════╝ + * + * ╔══════════ Word-Entry ═════════╗ + * ║ 00 02 XX XX ║ FF FF YY YY ║ + * ║ └─┬─┘ └─┬─┘ ║ └─┬─┘ ║ + * ║ Len Address ║ ~Value ║ + * ╚═══════════════╩═══════════════╝ + * + * ╔══════════ DWord-Entry ═══════╗ + * ║ 00 04 XX XX ║ FF FF FF FF ║ + * ║ └─┬─┘ └─┬─┘ ║ └───┬────┘ ║ + * ║ Len Address ║ ~Value ║ + * ╚═══════════════╩═══════════════╝ + * + */ + +#include "eeprom_stm32_defs.h" +#if !defined(FEE_PAGE_SIZE) || !defined(FEE_PAGE_COUNT) || !defined(FEE_MCU_FLASH_SIZE) || !defined(FEE_PAGE_BASE_ADDRESS) +# error "not implemented." +#endif + +/* These bits indicate that the length of data which was wrote to log space */ +#define FEE_BYTE_FLAG 0x00010000 +#define FEE_WORD_FLAG 0x00020000 +#define FEE_DWORD_FLAG 0x00040000 + +/* Flash byte value after erase */ +#define FEE_EMPTY_BYTE ((uint8_t)0xFF) +/* Flash double byte value after erase */ +#define FEE_EMPTY_DBYTE ((uint16_t)0xFFFF) +/* Flash word value after erase */ +#define FEE_EMPTY_WORD ((uint32_t)0xFFFFFFFF) +/* Flash double word value after erase */ +#define FEE_EMPTY_DWORD ((uint64_t)0xFFFFFFFFFFFFFFFF) + +/* Size of combined compacted eeprom and write log pages */ +#define FEE_DENSITY_MAX_SIZE (FEE_PAGE_COUNT * FEE_PAGE_SIZE) + +#ifndef FEE_MCU_FLASH_SIZE_IGNORE_CHECK /* *TODO: Get rid of this check */ +# if FEE_DENSITY_MAX_SIZE > (FEE_MCU_FLASH_SIZE * 1024) +# pragma message STR(FEE_DENSITY_MAX_SIZE) " > " STR(FEE_MCU_FLASH_SIZE * 1024) +# error emulated eeprom: FEE_DENSITY_MAX_SIZE is greater than available flash size +# endif +#endif + +/* Size of emulated eeprom */ +#ifdef FEE_DENSITY_BYTES +# if (FEE_DENSITY_BYTES > FEE_DENSITY_MAX_SIZE) +# pragma message STR(FEE_DENSITY_BYTES) " > " STR(FEE_DENSITY_MAX_SIZE) +# error emulated eeprom: FEE_DENSITY_BYTES exceeds FEE_DENSITY_MAX_SIZE +# endif +# if (FEE_DENSITY_BYTES == FEE_DENSITY_MAX_SIZE) +# pragma message STR(FEE_DENSITY_BYTES) " == " STR(FEE_DENSITY_MAX_SIZE) +# warning emulated eeprom: FEE_DENSITY_BYTES leaves no room for a write log. This will greatly increase the flash wear rate! +# endif +# if FEE_DENSITY_BYTES > FEE_ADDRESS_MAX_SIZE +# pragma message STR(FEE_DENSITY_BYTES) " > " STR(FEE_ADDRESS_MAX_SIZE) +# error emulated eeprom: FEE_DENSITY_BYTES is greater than FEE_ADDRESS_MAX_SIZE allows +# endif +# if ((FEE_DENSITY_BYTES) % 8) != 0 +# error emulated eeprom: FEE_DENSITY_BYTES must be a multiple of 8 +# endif +#else +/* Default to one page of allocated space used for emulated eeprom, 3 pages for write log */ +# define FEE_DENSITY_BYTES FEE_PAGE_SIZE +#endif + +/* Size of write log */ +#ifdef FEE_WRITE_LOG_BYTES +# if ((FEE_DENSITY_BYTES + FEE_WRITE_LOG_BYTES) > FEE_DENSITY_MAX_SIZE) +# pragma message STR(FEE_DENSITY_BYTES) " + " STR(FEE_WRITE_LOG_BYTES) " > " STR(FEE_DENSITY_MAX_SIZE) +# error emulated eeprom: FEE_WRITE_LOG_BYTES exceeds remaining FEE_DENSITY_MAX_SIZE +# endif +# if ((FEE_WRITE_LOG_BYTES) % 8) != 0 +# error emulated eeprom: FEE_WRITE_LOG_BYTES must be a multiple of 8 +# endif +#else +/* Default to use all remaining space */ +# define FEE_WRITE_LOG_BYTES (FEE_PAGE_COUNT * FEE_PAGE_SIZE - FEE_DENSITY_BYTES) +#endif + +/* In-memory contents of emulated eeprom for faster access */ +/* *TODO: Implement page swapping */ +static uint64_t DWordBuf[FEE_DENSITY_BYTES / 8]; +static uint8_t *DataBuf = (uint8_t *)DWordBuf; + +/* Pointer to the first available slot within the write log */ +static uint32_t *empty_slot; + +/* Start of the emulated eeprom compacted flash area */ +#define FEE_COMPACTED_BASE_ADDRESS FEE_PAGE_BASE_ADDRESS +/* End of the emulated eeprom compacted flash area */ +#define FEE_COMPACTED_LAST_ADDRESS (FEE_COMPACTED_BASE_ADDRESS + FEE_DENSITY_BYTES) +/* Start of the emulated eeprom write log */ +#define FEE_WRITE_LOG_BASE_ADDRESS FEE_COMPACTED_LAST_ADDRESS +/* End of the emulated eeprom write log */ +#define FEE_WRITE_LOG_LAST_ADDRESS (FEE_WRITE_LOG_BASE_ADDRESS + FEE_WRITE_LOG_BYTES) + +uint16_t EEPROM_Init(void) { + /* Load emulated eeprom contents from compacted flash into memory */ + uint32_t *src = (uint32_t *)FEE_COMPACTED_BASE_ADDRESS; + uint32_t *dest = (uint32_t *)DataBuf; + for (; src < (uint32_t *)FEE_COMPACTED_LAST_ADDRESS; ++src, ++dest) { + *dest = ~*src; + } + + /* Replay write log */ + uint32_t *log_addr; + for (log_addr = (uint32_t *)FEE_WRITE_LOG_BASE_ADDRESS; log_addr < (uint32_t *)FEE_WRITE_LOG_LAST_ADDRESS; log_addr += 2) { + uint32_t address = *log_addr; + uint32_t data = ~*(log_addr + 1); + if (address == FEE_EMPTY_WORD) { + break; + } + /* Check if value is in bytes */ + else if ((address & FEE_BYTE_FLAG) == FEE_BYTE_FLAG) { + uint8_t value = (uint8_t)(data & 0xFF); + uint16_t addr = (uint16_t)address; + DataBuf[addr] = value; + } + /* Check if value is in words */ + else if ((address & FEE_WORD_FLAG) == FEE_WORD_FLAG) { + uint16_t value = (uint16_t)(data & 0xFFFF); + uint16_t addr = (uint16_t)address; + *(uint16_t *)(&DataBuf[addr]) = value; + } + /* Check if value is in double words */ + else if ((address & FEE_DWORD_FLAG) == FEE_DWORD_FLAG) { + uint32_t value = data; + uint16_t addr = (uint16_t)address; + *(uint32_t *)(&DataBuf[addr]) = value; + } + } + + empty_slot = log_addr; + + return FEE_DENSITY_BYTES; +} + +/* Clear flash contents (doesn't touch in-memory DataBuf) */ +static void eeprom_clear(void) { + FLASH_Unlock(); + + for (uint16_t page_num = 0; page_num < FEE_PAGE_COUNT; ++page_num) { + FLASH_ErasePage(FEE_PAGE_BASE_ADDRESS + (page_num * FEE_PAGE_SIZE)); + } + + FLASH_Lock(); + + empty_slot = (uint32_t *)FEE_WRITE_LOG_BASE_ADDRESS; +} + +/* Erase emulated eeprom */ +void EEPROM_Erase(void) { + /* Erase compacted pages and write log */ + eeprom_clear(); + /* re-initialize to reset DataBuf */ + EEPROM_Init(); +} + +/* Compact write log */ +static uint8_t eeprom_compact(void) { + /* Erase compacted pages and write log */ + eeprom_clear(); + + FLASH_Unlock(); + + FLASH_Status final_status = FLASH_COMPLETE; + + /* Write emulated eeprom contents from memory to compacted flash */ + uint64_t *src = (uint64_t *)DataBuf; + uint32_t dest = FEE_COMPACTED_BASE_ADDRESS; + uint64_t value; + for (; dest < FEE_COMPACTED_LAST_ADDRESS; ++src, dest += 8) { + value = *src; + if (value) { + FLASH_Status status = FLASH_ProgramDoubleWord(dest, ~value); + if (status != FLASH_COMPLETE) final_status = status; + } + } + + FLASH_Lock(); + + return final_status; +} + +static uint8_t eeprom_write_direct_entry(uint16_t Address) { + /* Check if we can just write this directly to the compacted flash area */ + uint32_t directAddress = FEE_COMPACTED_BASE_ADDRESS + (Address & 0xFFF8); + + /* Write the value directly to the compacted area without a log entry */ + if (*(uint64_t *)directAddress == FEE_EMPTY_DWORD) { + /* Write the value directly to the compacted area without a log entry */ + uint64_t value = ~*(uint64_t *)(&DataBuf[Address & 0xFFF8]); + + /* Early exit if a write isn't needed */ + if (value == FEE_EMPTY_DWORD) return FLASH_COMPLETE; + + FLASH_Unlock(); + + /* write to flash */ + FLASH_Status status = FLASH_ProgramDoubleWord(directAddress, value); + + FLASH_Lock(); + + return status; + } + return 0; +} + +static uint8_t eeprom_write_log_byte_entry(uint16_t Address) { + /* if we can't find an empty spot, we must compact emulated eeprom */ + if (empty_slot >= (uint32_t *)FEE_WRITE_LOG_LAST_ADDRESS) { + /* compact the write log into the compacted flash area */ + return eeprom_compact(); + } + + FLASH_Unlock(); + + /* Pack address and value into the same word */ + uint64_t value = (((uint64_t)(~DataBuf[Address])) << 32) | (FEE_BYTE_FLAG) | Address; + + /* write to flash */ + FLASH_Status status = FLASH_ProgramDoubleWord((uint32_t)empty_slot, value); + + empty_slot += 2; + + FLASH_Lock(); + + return status; +} + +static uint8_t eeprom_write_log_word_entry(uint16_t Address) { + /* if we can't find an empty spot, we must compact emulated eeprom */ + if (empty_slot >= (uint32_t *)FEE_WRITE_LOG_LAST_ADDRESS) { + /* compact the write log into the compacted flash area */ + return eeprom_compact(); + } + + FLASH_Unlock(); + + /* Pack address and value into the same word */ + uint64_t value = (((uint64_t)(~(*(uint16_t *)&DataBuf[Address]))) << 32) | (FEE_WORD_FLAG) | Address; + + /* write to flash */ + FLASH_Status status = FLASH_ProgramDoubleWord((uint32_t)empty_slot, value); + + empty_slot += 2; + + FLASH_Lock(); + + return status; +} + +static uint8_t eeprom_write_log_dword_entry(uint16_t Address) { + /* if we can't find an empty spot, we must compact emulated eeprom */ + if (empty_slot >= (uint32_t *)FEE_WRITE_LOG_LAST_ADDRESS) { + /* compact the write log into the compacted flash area */ + return eeprom_compact(); + } + + FLASH_Unlock(); + + /* Pack address and value into the same word */ + uint64_t value = (((uint64_t)(~(*(uint32_t *)&DataBuf[Address]))) << 32) | (FEE_DWORD_FLAG) | Address; + + /* write to flash */ + FLASH_Status status = FLASH_ProgramDoubleWord((uint32_t)empty_slot, value); + + empty_slot += 2; + + FLASH_Lock(); + + return status; +} + +uint8_t EEPROM_WriteDataByte(uint16_t Address, uint8_t DataByte) { + /* if the address is out-of-bounds, do nothing */ + if (Address >= (FEE_DENSITY_BYTES)) { + return FLASH_BAD_ADDRESS; + } + + /* if the value is the same, don't bother writing it */ + if (DataBuf[Address] == DataByte) { + return 0; + } + + /* keep DataBuf cache in sync */ + DataBuf[Address] = DataByte; + + /* perform the write into flash memory */ + /* First, attempt to write directly into the compacted flash area */ + FLASH_Status status = eeprom_write_direct_entry(Address); + + if (!status) { + eeprom_write_log_byte_entry(Address); + } + + return status; +} + +uint8_t EEPROM_WriteDataWord(uint16_t Address, uint16_t DataWord) { + /* if the address is out-of-bounds, do nothing */ + if (Address >= (FEE_DENSITY_BYTES)) { + return FLASH_BAD_ADDRESS; + } + + /* if the value is the same, don't bother writing it */ + if (*(uint16_t *)&DataBuf[Address] == DataWord) { + return 0; + } + + /* keep DataBuf cache in sync */ + *(uint16_t *)(&DataBuf[Address]) = DataWord; + + /* perform the write into flash memory */ + /* First, attempt to write directly into the compacted flash area */ + FLASH_Status status = eeprom_write_direct_entry(Address); + + if (!status) { + eeprom_write_log_word_entry(Address); + } + + return status; +} + +uint8_t EEPROM_WriteDataDWord(uint16_t Address, uint32_t DataDWord) { + /* if the address is out-of-bounds, do nothing */ + if (Address >= (FEE_DENSITY_BYTES)) { + return FLASH_BAD_ADDRESS; + } + + /* if the value is the same, don't bother writing it */ + if (*(uint32_t *)&DataBuf[Address] == DataDWord) { + return 0; + } + + /* keep DataBuf cache in sync */ + *(uint32_t *)&DataBuf[Address] = DataDWord; + + /* perform the write into flash memory */ + /* First, attempt to write directly into the compacted flash area */ + FLASH_Status status = eeprom_write_direct_entry(Address); + + if (!status) { + eeprom_write_log_dword_entry(Address); + } + + return status; +} + +uint8_t EEPROM_ReadDataByte(uint16_t Address) { + uint8_t DataByte = 0xFF; + + if (Address < FEE_DENSITY_BYTES) { + DataByte = DataBuf[Address]; + } + + return DataByte; +} + +uint16_t EEPROM_ReadDataWord(uint16_t Address) { + uint16_t DataWord = 0xFFFF; + + if (Address < FEE_DENSITY_BYTES - 1) { + /* Check word alignment */ + if (Address % 2) { + DataWord = DataBuf[Address] | (DataBuf[Address + 1] << 8); + } else { + DataWord = *(uint16_t *)(&DataBuf[Address]); + } + } + + return DataWord; +} + +/***************************************************************************** + * Bind to eeprom_driver.c + *******************************************************************************/ +void eeprom_driver_init(void) { EEPROM_Init(); } + +void eeprom_driver_erase(void) { EEPROM_Erase(); } + +void eeprom_read_block(void *buf, const void *addr, size_t len) { + const uint8_t *src = (const uint8_t *)addr; + uint8_t * dest = (uint8_t *)buf; + + /* Check word alignment */ + if (len && (uint32_t)src % 2) { + /* Read the unaligned first byte */ + *dest++ = EEPROM_ReadDataByte((const uintptr_t)((uint16_t *)src)); + --len; + } + + uint16_t value; + bool aligned = ((uint32_t)dest % 2 == 0); + while (len > 1) { + value = EEPROM_ReadDataWord((const uintptr_t)((uint16_t *)src)); + if (aligned) { + *(uint16_t *)dest = value; + dest += 2; + } else { + *dest++ = value; + *dest++ = value >> 8; + } + src += 2; + len -= 2; + } + if (len) { + *dest = EEPROM_ReadDataByte((const uintptr_t)src); + } +} + +void eeprom_write_block(const void *buf, void *addr, size_t len) { + uint8_t * dest = (uint8_t *)addr; + const uint8_t *src = (const uint8_t *)buf; + uint8_t write_len; + + while (len > 0) { + /* Check and try to write double word fisrt */ + if ((uintptr_t)dest % 4 == 0 && len >= 4) { + uint32_t dwvalue; + bool dwaligned = ((uint32_t)src % 4 == 0); + + if (dwaligned) { + dwvalue = *(uint32_t *)src; + } else { + dwvalue = *(uint8_t *)src | (*(uint8_t *)(src + 1) << 8) | (*(uint8_t *)(src + 2) << 16) | (*(uint8_t *)(src + 3) << 24); + } + EEPROM_WriteDataDWord((uintptr_t)((uint16_t *)dest), dwvalue); + write_len = 4; + } + /* Check and try to write word */ + else if ((uintptr_t)dest % 2 == 0 && len >= 2) { + uint16_t wvalue; + bool waligned = ((uintptr_t)src % 2 == 0); + + if (waligned) { + wvalue = *(uint16_t *)src; + } else { + wvalue = *(uint8_t *)src | (*(uint8_t *)(src + 1) << 8); + } + EEPROM_WriteDataWord((uintptr_t)((uint16_t *)dest), wvalue); + write_len = 2; + } else { + /* Write the unaligned or single byte */ + EEPROM_WriteDataByte((uintptr_t)dest++, *src++); + write_len = 1; + } + + dest += write_len; + src += write_len; + len -= write_len; + } +} \ No newline at end of file diff --git a/platforms/chibios/eeprom_stm32_l4.h b/platforms/chibios/eeprom_stm32_l4.h new file mode 100644 index 000000000000..eb29d4d87d22 --- /dev/null +++ b/platforms/chibios/eeprom_stm32_l4.h @@ -0,0 +1,34 @@ +/* + * This software is experimental and a work in progress. + * Under no circumstances should these files be used in relation to any critical system(s). + * Use of these files is at your own risk. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * This files are free to use from http://engsta.com/stm32-flash-memory-eeprom-emulator/ by + * Artur F. + * + * Modifications for QMK and STM32L432 by lalalademaxiya1 & lokher + * + * To add a new MCU, please provide the flash page size and the total flash size in Kb. + * The number of available pages must be at least two. Only one page for the total EEPROM size. + * It is recommend to set the number of log page to 3~5 times of data page for better Wear leveling. + * + */ + +#pragma once + +typedef unsigned long long uint64_t; + +uint16_t EEPROM_Init(void); +void EEPROM_Erase(void); +uint8_t EEPROM_WriteDataByte(uint16_t Address, uint8_t DataByte); +uint8_t EEPROM_WriteDataWord(uint16_t Address, uint16_t DataWord); +uint8_t EEPROM_WriteDataDWord(uint16_t Address, uint32_t DataDWord); +uint8_t EEPROM_ReadDataByte(uint16_t Address); +uint16_t EEPROM_ReadDataWord(uint16_t Address); diff --git a/platforms/chibios/flash_stm32.c b/platforms/chibios/flash_stm32.c index 72c41b8b784d..b40f6eeab3c3 100644 --- a/platforms/chibios/flash_stm32.c +++ b/platforms/chibios/flash_stm32.c @@ -51,6 +51,15 @@ static uint8_t ADDR2PAGE(uint32_t Page_Address) { } #endif +#if defined(STM32L4XX) +# define FLASH_SR_PGERR FLASH_SR_PROGERR +# define FLASH_OBR_OPTERR FLASH_SR_OPERR +# define FLASH_KEY1 0x45670123U +# define FLASH_KEY2 0xCDEF89ABU + +static uint32_t ADDR2PAGE(uint32_t Page_Address) { return (Page_Address - FLASH_BASE) / 0x800; } +#endif + /* Delay definition */ #define EraseTimeout ((uint32_t)0x00000FFF) #define ProgramTimeout ((uint32_t)0x0000001F) @@ -128,6 +137,9 @@ FLASH_Status FLASH_ErasePage(uint32_t Page_Address) { #if defined(FLASH_CR_SNB) FLASH->CR &= ~FLASH_CR_SNB; FLASH->CR |= FLASH_CR_SER | (ADDR2PAGE(Page_Address) << FLASH_CR_SNB_Pos); +#elif defined(FLASH_CR_PNB) + FLASH->CR &= ~FLASH_CR_PNB; + FLASH->CR |= FLASH_CR_PER | (ADDR2PAGE(Page_Address) << FLASH_CR_PNB_Pos); #else FLASH->CR |= FLASH_CR_PER; FLASH->AR = Page_Address; @@ -140,6 +152,8 @@ FLASH_Status FLASH_ErasePage(uint32_t Page_Address) { /* if the erase operation is completed, disable the configured Bits */ #if defined(FLASH_CR_SNB) FLASH->CR &= ~(FLASH_CR_SER | FLASH_CR_SNB); +#elif defined(FLASH_CR_PNB) + FLASH->CR &= ~(FLASH_CR_PER | FLASH_CR_PNB); #else FLASH->CR &= ~FLASH_CR_PER; #endif @@ -184,6 +198,39 @@ FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data) { return status; } +#if defined(STM32L4XX) +/** + * @brief Programs double words at a specified address. + * @param Address: specifies the address to be programmed. + * @param Data: specifies the data to be programmed. + * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG, + * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. + */ +FLASH_Status FLASH_ProgramDoubleWord(uint32_t Address, uint64_t Data) { + FLASH_Status status = FLASH_BAD_ADDRESS; + + if (IS_FLASH_ADDRESS(Address)) { + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(ProgramTimeout); + if (status == FLASH_COMPLETE) { + /* if the previous operation is completed, proceed to program the new data */ + FLASH->CR |= FLASH_CR_PG; + *(__IO uint32_t*)Address = (uint32_t)Data; + __ISB(); + *(__IO uint32_t*)(Address + 4U) = (uint32_t)(Data >> 32); + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(ProgramTimeout); + if (status != FLASH_TIMEOUT) { + /* if the program operation is completed, disable the PG Bit */ + FLASH->CR &= ~FLASH_CR_PG; + } + FLASH->SR = (FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPERR); + } + } + return status; +} +#endif + /** * @brief Unlocks the FLASH Program Erase Controller. * @param None diff --git a/platforms/chibios/flash_stm32.h b/platforms/chibios/flash_stm32.h index 6c66642ec5c7..97f8ea7cfe2b 100644 --- a/platforms/chibios/flash_stm32.h +++ b/platforms/chibios/flash_stm32.h @@ -35,6 +35,7 @@ typedef enum { FLASH_BUSY = 1, FLASH_ERROR_PG, FLASH_ERROR_WRP, FLASH_ERROR_OPT, FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout); FLASH_Status FLASH_ErasePage(uint32_t Page_Address); FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data); +FLASH_Status FLASH_ProgramDoubleWord(uint32_t Address, uint64_t Data); void FLASH_Unlock(void); void FLASH_Lock(void);