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);