mirror of
https://github.com/qmk/qmk_firmware.git
synced 2025-03-13 06:54:08 +00:00
Merge remote-tracking branch 'origin/develop' into xap
This commit is contained in:
commit
6298984d12
@ -219,7 +219,7 @@ else
|
|||||||
COMMON_VPATH += $(PLATFORM_PATH)/$(PLATFORM_KEY)/$(DRIVER_DIR)/flash
|
COMMON_VPATH += $(PLATFORM_PATH)/$(PLATFORM_KEY)/$(DRIVER_DIR)/flash
|
||||||
COMMON_VPATH += $(DRIVER_PATH)/flash
|
COMMON_VPATH += $(DRIVER_PATH)/flash
|
||||||
SRC += eeprom_driver.c eeprom_legacy_emulated_flash.c legacy_flash_ops.c
|
SRC += eeprom_driver.c eeprom_legacy_emulated_flash.c legacy_flash_ops.c
|
||||||
else ifneq ($(filter $(MCU_SERIES),STM32F1xx STM32F3xx STM32F4xx STM32L4xx STM32G4xx WB32F3G71xx WB32FQ95xx GD32VF103),)
|
else ifneq ($(filter $(MCU_SERIES),STM32F1xx STM32F3xx STM32F4xx STM32L4xx STM32G4xx WB32F3G71xx WB32FQ95xx AT32F415 GD32VF103),)
|
||||||
# Wear-leveling EEPROM implementation, backed by MCU flash
|
# Wear-leveling EEPROM implementation, backed by MCU flash
|
||||||
OPT_DEFS += -DEEPROM_DRIVER -DEEPROM_WEAR_LEVELING
|
OPT_DEFS += -DEEPROM_DRIVER -DEEPROM_WEAR_LEVELING
|
||||||
SRC += eeprom_driver.c eeprom_wear_leveling.c
|
SRC += eeprom_driver.c eeprom_wear_leveling.c
|
||||||
|
@ -36,6 +36,7 @@ GENERIC_FEATURES = \
|
|||||||
HAPTIC \
|
HAPTIC \
|
||||||
KEY_LOCK \
|
KEY_LOCK \
|
||||||
KEY_OVERRIDE \
|
KEY_OVERRIDE \
|
||||||
|
LAYER_LOCK \
|
||||||
LEADER \
|
LEADER \
|
||||||
MAGIC \
|
MAGIC \
|
||||||
MOUSEKEY \
|
MOUSEKEY \
|
||||||
|
@ -3,5 +3,12 @@
|
|||||||
"0x7C20": "!delete!", // old QK_OUTPUT_AUTO
|
"0x7C20": "!delete!", // old QK_OUTPUT_AUTO
|
||||||
"0x7C21": "!delete!", // old QK_OUTPUT_USB
|
"0x7C21": "!delete!", // old QK_OUTPUT_USB
|
||||||
"0x7C22": "!delete!", // old QK_OUTPUT_BLUETOOTH
|
"0x7C22": "!delete!", // old QK_OUTPUT_BLUETOOTH
|
||||||
|
"0x7C7B": {
|
||||||
|
"group": "quantum",
|
||||||
|
"key": "QK_LAYER_LOCK",
|
||||||
|
"aliases": [
|
||||||
|
"QK_LLCK"
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,6 +64,9 @@
|
|||||||
"WEAR_LEVELING_BACKING_SIZE": {"info_key": "eeprom.wear_leveling.backing_size", "value_type": "int", "to_json": false},
|
"WEAR_LEVELING_BACKING_SIZE": {"info_key": "eeprom.wear_leveling.backing_size", "value_type": "int", "to_json": false},
|
||||||
"WEAR_LEVELING_LOGICAL_SIZE": {"info_key": "eeprom.wear_leveling.logical_size", "value_type": "int", "to_json": false},
|
"WEAR_LEVELING_LOGICAL_SIZE": {"info_key": "eeprom.wear_leveling.logical_size", "value_type": "int", "to_json": false},
|
||||||
|
|
||||||
|
// Layer locking
|
||||||
|
"LAYER_LOCK_IDLE_TIMEOUT": {"info_key": "layer_lock.timeout", "value_type": "int"},
|
||||||
|
|
||||||
// Indicators
|
// Indicators
|
||||||
"LED_CAPS_LOCK_PIN": {"info_key": "indicators.caps_lock"},
|
"LED_CAPS_LOCK_PIN": {"info_key": "indicators.caps_lock"},
|
||||||
"LED_NUM_LOCK_PIN": {"info_key": "indicators.num_lock"},
|
"LED_NUM_LOCK_PIN": {"info_key": "indicators.num_lock"},
|
||||||
|
@ -92,6 +92,7 @@
|
|||||||
"GD32VF103",
|
"GD32VF103",
|
||||||
"WB32F3G71",
|
"WB32F3G71",
|
||||||
"WB32FQ95",
|
"WB32FQ95",
|
||||||
|
"AT32F415",
|
||||||
"atmega16u2",
|
"atmega16u2",
|
||||||
"atmega32u2",
|
"atmega32u2",
|
||||||
"atmega16u4",
|
"atmega16u4",
|
||||||
@ -216,6 +217,7 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": [
|
||||||
"apm32-dfu",
|
"apm32-dfu",
|
||||||
|
"at32-dfu",
|
||||||
"atmel-dfu",
|
"atmel-dfu",
|
||||||
"bootloadhid",
|
"bootloadhid",
|
||||||
"caterina",
|
"caterina",
|
||||||
@ -373,6 +375,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"keycodes": {"$ref": "qmk.definitions.v1#/keycode_decl_array"},
|
"keycodes": {"$ref": "qmk.definitions.v1#/keycode_decl_array"},
|
||||||
|
"layer_lock": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"timeout": {"$ref": "qmk.definitions.v1#/unsigned_int"}
|
||||||
|
}
|
||||||
|
},
|
||||||
"layout_aliases": {
|
"layout_aliases": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": {"$ref": "qmk.definitions.v1#/layout_macro"}
|
"additionalProperties": {"$ref": "qmk.definitions.v1#/layout_macro"}
|
||||||
|
@ -123,6 +123,7 @@
|
|||||||
{ "text": "Key Lock", "link": "/features/key_lock" },
|
{ "text": "Key Lock", "link": "/features/key_lock" },
|
||||||
{ "text": "Key Overrides", "link": "/features/key_overrides" },
|
{ "text": "Key Overrides", "link": "/features/key_overrides" },
|
||||||
{ "text": "Layers", "link": "/feature_layers" },
|
{ "text": "Layers", "link": "/feature_layers" },
|
||||||
|
{ "text": "Layer Lock", "link": "/features/layer_lock" },
|
||||||
{ "text": "One Shot Keys", "link": "/one_shot_keys" },
|
{ "text": "One Shot Keys", "link": "/one_shot_keys" },
|
||||||
{ "text": "OS Detection", "link": "/features/os_detection" },
|
{ "text": "OS Detection", "link": "/features/os_detection" },
|
||||||
{ "text": "Raw HID", "link": "/features/rawhid" },
|
{ "text": "Raw HID", "link": "/features/rawhid" },
|
||||||
|
@ -57,6 +57,10 @@ You can also use any ARM chip with USB that [ChibiOS](https://www.chibios.org) s
|
|||||||
* [WB32F3G71xx](http://www.westberrytech.com)
|
* [WB32F3G71xx](http://www.westberrytech.com)
|
||||||
* [WB32FQ95xx](http://www.westberrytech.com)
|
* [WB32FQ95xx](http://www.westberrytech.com)
|
||||||
|
|
||||||
|
### Artery (AT32)
|
||||||
|
|
||||||
|
* [AT32F415](https://www.arterychip.com/en/product/AT32F415.jsp)
|
||||||
|
|
||||||
### NXP (Kinetis)
|
### NXP (Kinetis)
|
||||||
|
|
||||||
* [MKL26Z64](https://www.nxp.com/products/processors-and-microcontrollers/arm-microcontrollers/general-purpose-mcus/kl-series-cortex-m0-plus/kinetis-kl2x-72-96-mhz-usb-ultra-low-power-microcontrollers-mcus-based-on-arm-cortex-m0-plus-core:KL2x)
|
* [MKL26Z64](https://www.nxp.com/products/processors-and-microcontrollers/arm-microcontrollers/general-purpose-mcus/kl-series-cortex-m0-plus/kinetis-kl2x-72-96-mhz-usb-ultra-low-power-microcontrollers-mcus-based-on-arm-cortex-m0-plus-core:KL2x)
|
||||||
|
@ -98,6 +98,7 @@ The device name here is the name that appears in Zadig, and may not be what the
|
|||||||
|`bootloadhid` |HIDBoot |`16C0:05DF` |HidUsb |
|
|`bootloadhid` |HIDBoot |`16C0:05DF` |HidUsb |
|
||||||
|`usbasploader`|USBasp |`16C0:05DC` |libusbK|
|
|`usbasploader`|USBasp |`16C0:05DC` |libusbK|
|
||||||
|`apm32-dfu` |APM32 DFU ISP Mode |`314B:0106` |WinUSB |
|
|`apm32-dfu` |APM32 DFU ISP Mode |`314B:0106` |WinUSB |
|
||||||
|
|`at32-dfu` |AT32 Bootloader DFU |`2E3C:DF11` |WinUSB |
|
||||||
|`stm32-dfu` |STM32 BOOTLOADER |`0483:DF11` |WinUSB |
|
|`stm32-dfu` |STM32 BOOTLOADER |`0483:DF11` |WinUSB |
|
||||||
|`gd32v-dfu` |GD32V BOOTLOADER |`28E9:0189` |WinUSB |
|
|`gd32v-dfu` |GD32V BOOTLOADER |`28E9:0189` |WinUSB |
|
||||||
|`kiibohd` |Kiibohd DFU Bootloader |`1C11:B007` |WinUSB |
|
|`kiibohd` |Kiibohd DFU Bootloader |`1C11:B007` |WinUSB |
|
||||||
|
@ -17,6 +17,9 @@ These functions allow you to activate layers in various ways. Note that layers a
|
|||||||
* `TO(layer)` - activates *layer* and de-activates all other layers (except your default layer). This function is special, because instead of just adding/removing one layer to your active layer stack, it will completely replace your current active layers, uniquely allowing you to replace higher layers with a lower one. This is activated on keydown (as soon as the key is pressed).
|
* `TO(layer)` - activates *layer* and de-activates all other layers (except your default layer). This function is special, because instead of just adding/removing one layer to your active layer stack, it will completely replace your current active layers, uniquely allowing you to replace higher layers with a lower one. This is activated on keydown (as soon as the key is pressed).
|
||||||
* `TT(layer)` - Layer Tap-Toggle. If you hold the key down, *layer* is activated, and then is de-activated when you let go (like `MO`). If you repeatedly tap it, the layer will be toggled on or off (like `TG`). It needs 5 taps by default, but you can change this by defining `TAPPING_TOGGLE` -- for example, `#define TAPPING_TOGGLE 2` to toggle on just two taps.
|
* `TT(layer)` - Layer Tap-Toggle. If you hold the key down, *layer* is activated, and then is de-activated when you let go (like `MO`). If you repeatedly tap it, the layer will be toggled on or off (like `TG`). It needs 5 taps by default, but you can change this by defining `TAPPING_TOGGLE` -- for example, `#define TAPPING_TOGGLE 2` to toggle on just two taps.
|
||||||
|
|
||||||
|
See also the [Layer Lock key](features/layer_lock), which locks the highest
|
||||||
|
active layer until pressed again.
|
||||||
|
|
||||||
### Caveats {#caveats}
|
### Caveats {#caveats}
|
||||||
|
|
||||||
Currently, the `layer` argument of `LT()` is limited to layers 0-15, and the `kc` argument to the [Basic Keycode set](keycodes_basic), meaning you can't use keycodes like `LCTL()`, `KC_TILD`, or anything greater than `0xFF`. This is because QMK uses 16-bit keycodes, of which 4 bits are used for the function identifier and 4 bits for the layer, leaving only 8 bits for the keycode.
|
Currently, the `layer` argument of `LT()` is limited to layers 0-15, and the `kc` argument to the [Basic Keycode set](keycodes_basic), meaning you can't use keycodes like `LCTL()`, `KC_TILD`, or anything greater than `0xFF`. This is because QMK uses 16-bit keycodes, of which 4 bits are used for the function identifier and 4 bits for the layer, leaving only 8 bits for the keycode.
|
||||||
|
139
docs/features/layer_lock.md
Normal file
139
docs/features/layer_lock.md
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
# Layer Lock
|
||||||
|
|
||||||
|
Some [layer switches](../feature_layers#switching-and-toggling-layers) access
|
||||||
|
the layer by holding the key, including momentary layer `MO(layer)` and layer
|
||||||
|
tap `LT(layer, key)` keys. You may sometimes need to stay on the layer for a
|
||||||
|
long period of time. Layer Lock "locks" the current layer to stay on, supposing
|
||||||
|
it was accessed by one of:
|
||||||
|
|
||||||
|
* `MO(layer)` momentary layer switch
|
||||||
|
* `LT(layer, key)` layer tap
|
||||||
|
* `OSL(layer)` one-shot layer
|
||||||
|
* `TT(layer)` layer tap toggle
|
||||||
|
* `LM(layer, mod)` layer-mod key (the layer is locked, but not the mods)
|
||||||
|
|
||||||
|
Press the Layer Lock key again to unlock the layer. Additionally, when a layer
|
||||||
|
is locked, layer switch keys that turn off the layer such as `TO(other_layer)`
|
||||||
|
will unlock it.
|
||||||
|
|
||||||
|
|
||||||
|
## How do I enable Layer Lock
|
||||||
|
|
||||||
|
In your rules.mk, add:
|
||||||
|
|
||||||
|
```make
|
||||||
|
LAYER_LOCK_ENABLE = yes
|
||||||
|
```
|
||||||
|
|
||||||
|
Pick a key in your keymap on a layer you intend to lock, and assign it the
|
||||||
|
keycode `QK_LAYER_LOCK` (short alias `QK_LLCK`). Note that locking the base
|
||||||
|
layer has no effect, so typically, this key is used on layers above the base
|
||||||
|
layer.
|
||||||
|
|
||||||
|
|
||||||
|
## Example use
|
||||||
|
|
||||||
|
Consider a keymap with the following base layer.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
The highlighted key is a momentary layer switch `MO(NAV)`. Holding it accesses a
|
||||||
|
navigation layer.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
Holding the NAV key is fine for brief use, but awkward to continue holding when
|
||||||
|
using navigation functions continuously. The Layer Lock key comes to the rescue:
|
||||||
|
|
||||||
|
1. Hold the NAV key, activating the navigation layer.
|
||||||
|
2. Tap Layer Lock.
|
||||||
|
3. Release NAV. The navigation layer stays on.
|
||||||
|
4. Make use of the arrow keys, etc.
|
||||||
|
5. Tap Layer Lock or NAV again to turn the navigation layer back off.
|
||||||
|
|
||||||
|
A variation that would also work is to put the Layer Lock key on the base layer
|
||||||
|
and make other layers transparent (`KC_TRNS`) in that position. Pressing the
|
||||||
|
Layer Lock key locks (or unlocks) the highest active layer, regardless of which
|
||||||
|
layer the Layer Lock key is on.
|
||||||
|
|
||||||
|
|
||||||
|
## Idle timeout
|
||||||
|
|
||||||
|
Optionally, Layer Lock may be configured to unlock if the keyboard is idle
|
||||||
|
for some time. In config.h, define `LAYER_LOCK_IDLE_TIMEOUT` in units of
|
||||||
|
milliseconds:
|
||||||
|
|
||||||
|
```c
|
||||||
|
#define LAYER_LOCK_IDLE_TIMEOUT 60000 // Turn off after 60 seconds.
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Functions
|
||||||
|
|
||||||
|
Use the following functions to query and manipulate the layer lock state.
|
||||||
|
|
||||||
|
| Function | Description |
|
||||||
|
|----------------------------|------------------------------------|
|
||||||
|
| `is_layer_locked(layer)` | Checks whether `layer` is locked. |
|
||||||
|
| `layer_lock_on(layer)` | Locks and turns on `layer`. |
|
||||||
|
| `layer_lock_off(layer)` | Unlocks and turns off `layer`. |
|
||||||
|
| `layer_lock_invert(layer)` | Toggles whether `layer` is locked. |
|
||||||
|
|
||||||
|
|
||||||
|
## Representing the current Layer Lock state
|
||||||
|
|
||||||
|
There is an optional callback `layer_lock_set_user()` that gets called when a
|
||||||
|
layer is locked or unlocked. This is useful to represent the current lock state
|
||||||
|
for instance by setting an LED. In keymap.c, define
|
||||||
|
|
||||||
|
```c
|
||||||
|
bool layer_lock_set_user(layer_state_t locked_layers) {
|
||||||
|
// Do something like `set_led(is_layer_locked(NAV));`
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The argument `locked_layers` is a bitfield in which the kth bit is on if the kth
|
||||||
|
layer is locked. Alternatively, you can use `is_layer_locked(layer)` to check if
|
||||||
|
a given layer is locked.
|
||||||
|
|
||||||
|
|
||||||
|
## Combine Layer Lock with a mod-tap
|
||||||
|
|
||||||
|
It is possible to create a [mod-tap MT key](../mod_tap) that acts as a modifier
|
||||||
|
on hold and Layer Lock on tap. Since Layer Lock is not a [basic
|
||||||
|
keycode](../keycodes_basic), attempting `MT(mod, QK_LLCK)` is invalid does not
|
||||||
|
work directly, yet this effect can be achieved through [changing the tap
|
||||||
|
function](../mod_tap#changing-tap-function). For example, the following
|
||||||
|
implements a `SFTLLCK` key that acts as Shift on hold and Layer Lock on tap:
|
||||||
|
|
||||||
|
```c
|
||||||
|
#define SFTLLCK LSFT_T(KC_0)
|
||||||
|
|
||||||
|
// Use SFTLLCK in your keymap...
|
||||||
|
|
||||||
|
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
|
||||||
|
switch (keycode) {
|
||||||
|
case SFTLLCK:
|
||||||
|
if (record->tap.count) {
|
||||||
|
if (record->event.pressed) {
|
||||||
|
// Toggle the lock on the highest layer.
|
||||||
|
layer_lock_invert(get_highest_layer(layer_state));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Other macros...
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In the above, `KC_0` is an arbitrary placeholder for the tapping keycode. This
|
||||||
|
keycode will never be sent, so any basic keycode will do. In
|
||||||
|
`process_record_user()`, the tap press event is changed to toggle the lock on
|
||||||
|
the highest layer. Layer Lock can be combined with a [layer-tap LT
|
||||||
|
key](../feature_layers#switching-and-toggling-layers) similarly.
|
||||||
|
|
@ -345,6 +345,39 @@ Flashing sequence:
|
|||||||
3. Flash a .bin file
|
3. Flash a .bin file
|
||||||
4. Reset the device into application mode (may be done automatically)
|
4. Reset the device into application mode (may be done automatically)
|
||||||
|
|
||||||
|
## AT32 DFU
|
||||||
|
|
||||||
|
All AT32 MCUs come preloaded with a factory bootloader that cannot be modified nor deleted.
|
||||||
|
|
||||||
|
To ensure compatibility with the AT32-DFU bootloader, make sure this block is present in your `rules.mk`:
|
||||||
|
|
||||||
|
```make
|
||||||
|
# Bootloader selection
|
||||||
|
BOOTLOADER = at32-dfu
|
||||||
|
```
|
||||||
|
|
||||||
|
Compatible flashers:
|
||||||
|
|
||||||
|
* [dfu-util](https://dfu-util.sourceforge.net/) / `:dfu-util` target in QMK (recommended command line)
|
||||||
|
```
|
||||||
|
dfu-util -a 0 -d 2E3C:DF11 -s 0x8000000:leave -D <filename>
|
||||||
|
```
|
||||||
|
|
||||||
|
Flashing sequence:
|
||||||
|
|
||||||
|
1. Enter the bootloader using any of the following methods:
|
||||||
|
* Tap the `QK_BOOT` keycode
|
||||||
|
* If a reset circuit is present, tap the `RESET` button on the PCB; some boards may also have a toggle switch that must be flipped
|
||||||
|
* Otherwise, you need to bridge `BOOT0` to VCC (via `BOOT0` button or jumper), short `RESET` to GND (via `RESET` button or jumper), and then let go of the `BOOT0` bridge
|
||||||
|
2. Wait for the OS to detect the device
|
||||||
|
3. Flash a .bin file
|
||||||
|
4. Reset the device into application mode (may be done automatically)
|
||||||
|
|
||||||
|
### `make` Targets
|
||||||
|
|
||||||
|
* `:dfu-util`: Waits until an AT32 bootloader device is available, and then flashes the firmware.
|
||||||
|
* `:dfu-util-split-left` and `:dfu-util-split-right`: Flashes the firmware as with `:dfu-util`, but also sets the handedness setting in EEPROM.
|
||||||
|
|
||||||
## tinyuf2
|
## tinyuf2
|
||||||
|
|
||||||
Keyboards may opt into supporting the tinyuf2 bootloader. This is currently only supported on F303/F401/F411.
|
Keyboards may opt into supporting the tinyuf2 bootloader. This is currently only supported on F303/F401/F411.
|
||||||
|
@ -387,6 +387,14 @@ See also: [Key Lock](features/key_lock)
|
|||||||
|---------|--------------------------------------------------------------|
|
|---------|--------------------------------------------------------------|
|
||||||
|`QK_LOCK`|Hold down the next key pressed, until the key is pressed again|
|
|`QK_LOCK`|Hold down the next key pressed, until the key is pressed again|
|
||||||
|
|
||||||
|
## Layer Lock {#layer-lock}
|
||||||
|
|
||||||
|
See also: [Layer Lock](features/layer_lock)
|
||||||
|
|
||||||
|
|Key |Aliases |Description |
|
||||||
|
|---------------|---------|----------------------------------|
|
||||||
|
|`QK_LAYER_LOCK`|`QK_LLCK`|Locks or unlocks the highest layer|
|
||||||
|
|
||||||
## Layer Switching {#layer-switching}
|
## Layer Switching {#layer-switching}
|
||||||
|
|
||||||
See also: [Layer Switching](feature_layers#switching-and-toggling-layers)
|
See also: [Layer Switching](feature_layers#switching-and-toggling-layers)
|
||||||
|
10
keyboards/handwired/onekey/at_start_f415/board.h
Normal file
10
keyboards/handwired/onekey/at_start_f415/board.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// Copyright 2023-2024 HorrorTroll <https://github.com/HorrorTroll>
|
||||||
|
// Copyright 2023-2024 Zhaqian <https://github.com/zhaqian12>
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include_next <board.h>
|
||||||
|
|
||||||
|
#undef AT32F415KB
|
||||||
|
#define AT32F415RC
|
10
keyboards/handwired/onekey/at_start_f415/config.h
Normal file
10
keyboards/handwired/onekey/at_start_f415/config.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// Copyright 2023-2024 HorrorTroll <https://github.com/HorrorTroll>
|
||||||
|
// Copyright 2023-2024 Zhaqian <https://github.com/zhaqian12>
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define ADC_PIN A0
|
||||||
|
|
||||||
|
#define BACKLIGHT_PWM_DRIVER PWMD5
|
||||||
|
#define BACKLIGHT_PWM_CHANNEL 1
|
13
keyboards/handwired/onekey/at_start_f415/halconf.h
Normal file
13
keyboards/handwired/onekey/at_start_f415/halconf.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// Copyright 2023-2024 HorrorTroll <https://github.com/HorrorTroll>
|
||||||
|
// Copyright 2023-2024 Zhaqian <https://github.com/zhaqian12>
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define HAL_USE_ADC TRUE
|
||||||
|
|
||||||
|
#define HAL_USE_I2C TRUE
|
||||||
|
|
||||||
|
#define HAL_USE_PWM TRUE
|
||||||
|
|
||||||
|
#include_next <halconf.h>
|
20
keyboards/handwired/onekey/at_start_f415/keyboard.json
Normal file
20
keyboards/handwired/onekey/at_start_f415/keyboard.json
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"keyboard_name": "Onekey AT-START-F415",
|
||||||
|
"processor": "AT32F415",
|
||||||
|
"bootloader": "at32-dfu",
|
||||||
|
"usb": {
|
||||||
|
"shared_endpoint": {
|
||||||
|
"keyboard": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"matrix_pins": {
|
||||||
|
"cols": ["B3"],
|
||||||
|
"rows": ["B4"]
|
||||||
|
},
|
||||||
|
"backlight": {
|
||||||
|
"pin": "A0"
|
||||||
|
},
|
||||||
|
"ws2812": {
|
||||||
|
"pin": "B0"
|
||||||
|
}
|
||||||
|
}
|
16
keyboards/handwired/onekey/at_start_f415/mcuconf.h
Normal file
16
keyboards/handwired/onekey/at_start_f415/mcuconf.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// Copyright 2023-2024 HorrorTroll <https://github.com/HorrorTroll>
|
||||||
|
// Copyright 2023-2024 Zhaqian <https://github.com/zhaqian12>
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include_next <mcuconf.h>
|
||||||
|
|
||||||
|
#undef AT32_ADC_USE_ADC1
|
||||||
|
#define AT32_ADC_USE_ADC1 TRUE
|
||||||
|
|
||||||
|
#undef AT32_I2C_USE_I2C1
|
||||||
|
#define AT32_I2C_USE_I2C1 TRUE
|
||||||
|
|
||||||
|
#undef AT32_PWM_USE_TMR5
|
||||||
|
#define AT32_PWM_USE_TMR5 TRUE
|
3
keyboards/handwired/onekey/at_start_f415/readme.md
Normal file
3
keyboards/handwired/onekey/at_start_f415/readme.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Artery AT-START-F415 Board Onekey
|
||||||
|
|
||||||
|
To trigger keypress, short together pins *B3* and *B4*.
|
@ -22,7 +22,7 @@ QMK_FIRMWARE_UPSTREAM = 'qmk/qmk_firmware'
|
|||||||
MAX_KEYBOARD_SUBFOLDERS = 5
|
MAX_KEYBOARD_SUBFOLDERS = 5
|
||||||
|
|
||||||
# Supported processor types
|
# Supported processor types
|
||||||
CHIBIOS_PROCESSORS = 'cortex-m0', 'cortex-m0plus', 'cortex-m3', 'cortex-m4', 'MKL26Z64', 'MK20DX128', 'MK20DX256', 'MK64FX512', 'MK66FX1M0', 'RP2040', 'STM32F042', 'STM32F072', 'STM32F103', 'STM32F303', 'STM32F401', 'STM32F405', 'STM32F407', 'STM32F411', 'STM32F446', 'STM32G431', 'STM32G474', 'STM32H723', 'STM32H733', 'STM32L412', 'STM32L422', 'STM32L432', 'STM32L433', 'STM32L442', 'STM32L443', 'GD32VF103', 'WB32F3G71', 'WB32FQ95'
|
CHIBIOS_PROCESSORS = 'cortex-m0', 'cortex-m0plus', 'cortex-m3', 'cortex-m4', 'MKL26Z64', 'MK20DX128', 'MK20DX256', 'MK64FX512', 'MK66FX1M0', 'RP2040', 'STM32F042', 'STM32F072', 'STM32F103', 'STM32F303', 'STM32F401', 'STM32F405', 'STM32F407', 'STM32F411', 'STM32F446', 'STM32G431', 'STM32G474', 'STM32H723', 'STM32H733', 'STM32L412', 'STM32L422', 'STM32L432', 'STM32L433', 'STM32L442', 'STM32L443', 'GD32VF103', 'WB32F3G71', 'WB32FQ95', 'AT32F415'
|
||||||
LUFA_PROCESSORS = 'at90usb162', 'atmega16u2', 'atmega32u2', 'atmega16u4', 'atmega32u4', 'at90usb646', 'at90usb647', 'at90usb1286', 'at90usb1287', None
|
LUFA_PROCESSORS = 'at90usb162', 'atmega16u2', 'atmega32u2', 'atmega16u4', 'atmega32u4', 'at90usb646', 'at90usb647', 'at90usb1286', 'at90usb1287', None
|
||||||
VUSB_PROCESSORS = 'atmega32a', 'atmega328p', 'atmega328', 'attiny85'
|
VUSB_PROCESSORS = 'atmega32a', 'atmega328p', 'atmega328', 'attiny85'
|
||||||
|
|
||||||
@ -55,6 +55,7 @@ MCU2BOOTLOADER = {
|
|||||||
"GD32VF103": "gd32v-dfu",
|
"GD32VF103": "gd32v-dfu",
|
||||||
"WB32F3G71": "wb32-dfu",
|
"WB32F3G71": "wb32-dfu",
|
||||||
"WB32FQ95": "wb32-dfu",
|
"WB32FQ95": "wb32-dfu",
|
||||||
|
"AT32F415": "at32-dfu",
|
||||||
"atmega16u2": "atmel-dfu",
|
"atmega16u2": "atmel-dfu",
|
||||||
"atmega32u2": "atmel-dfu",
|
"atmega32u2": "atmel-dfu",
|
||||||
"atmega16u4": "atmel-dfu",
|
"atmega16u4": "atmel-dfu",
|
||||||
@ -93,6 +94,7 @@ BOOTLOADER_VIDS_PIDS = {
|
|||||||
'apm32-dfu': {("314b", "0106")},
|
'apm32-dfu': {("314b", "0106")},
|
||||||
'gd32v-dfu': {("28e9", "0189")},
|
'gd32v-dfu': {("28e9", "0189")},
|
||||||
'wb32-dfu': {("342d", "dfa0")},
|
'wb32-dfu': {("342d", "dfa0")},
|
||||||
|
'at32-dfu': {("2e3c", "df11")},
|
||||||
'bootloadhid': {("16c0", "05df")},
|
'bootloadhid': {("16c0", "05df")},
|
||||||
'usbasploader': {("16c0", "05dc")},
|
'usbasploader': {("16c0", "05dc")},
|
||||||
'usbtinyisp': {("1782", "0c9f")},
|
'usbtinyisp': {("1782", "0c9f")},
|
||||||
|
101
platforms/chibios/boards/GENERIC_AT32_F415XX/board/board.c
Normal file
101
platforms/chibios/boards/GENERIC_AT32_F415XX/board/board.c
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||||
|
ChibiOS - Copyright (C) 2023..2024 HorrorTroll
|
||||||
|
ChibiOS - Copyright (C) 2023..2024 Zhaqian
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "hal.h"
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver local definitions. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver exported variables. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver local variables and types. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief PAL setup.
|
||||||
|
* @details Digital I/O ports static configuration as defined in @p board.h.
|
||||||
|
* This variable is used by the HAL when initializing the PAL driver.
|
||||||
|
*/
|
||||||
|
#if HAL_USE_PAL || defined(__DOXYGEN__)
|
||||||
|
const PALConfig pal_default_config =
|
||||||
|
{
|
||||||
|
{VAL_GPIOAODT, VAL_GPIOACFGLR, VAL_GPIOACFGHR},
|
||||||
|
{VAL_GPIOBODT, VAL_GPIOBCFGLR, VAL_GPIOBCFGHR},
|
||||||
|
#if AT32_HAS_GPIOC
|
||||||
|
{VAL_GPIOCODT, VAL_GPIOCCFGLR, VAL_GPIOCCFGHR},
|
||||||
|
#endif
|
||||||
|
{VAL_GPIODODT, VAL_GPIODCFGLR, VAL_GPIODCFGHR},
|
||||||
|
#if AT32_HAS_GPIOF
|
||||||
|
{VAL_GPIOFODT, VAL_GPIOFCFGLR, VAL_GPIOFCFGHR},
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver local functions. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver interrupt handlers. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver exported functions. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Early initialization code.
|
||||||
|
* @details System clocks are initialized before everything else.
|
||||||
|
*/
|
||||||
|
void __early_init(void) {
|
||||||
|
at32_clock_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if HAL_USE_SDC || defined(__DOXYGEN__)
|
||||||
|
/**
|
||||||
|
* @brief SDC card detection.
|
||||||
|
*/
|
||||||
|
bool sdc_lld_is_card_inserted(SDCDriver *sdcp) {
|
||||||
|
static bool last_status = false;
|
||||||
|
|
||||||
|
if (blkIsTransferring(sdcp))
|
||||||
|
return last_status;
|
||||||
|
return last_status = (bool)palReadPad(GPIOC, GPIOC_PIN11);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SDC card write protection detection.
|
||||||
|
*/
|
||||||
|
bool sdc_lld_is_write_protected(SDCDriver *sdcp) {
|
||||||
|
|
||||||
|
(void)sdcp;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif /* HAL_USE_SDC */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Board-specific initialization code.
|
||||||
|
* @note You can add your board-specific code here.
|
||||||
|
*/
|
||||||
|
void boardInit(void) {
|
||||||
|
IOMUX->REMAP |= IOMUX_REMAP_SWJTAG_MUX_JTAGDIS;
|
||||||
|
}
|
207
platforms/chibios/boards/GENERIC_AT32_F415XX/board/board.h
Normal file
207
platforms/chibios/boards/GENERIC_AT32_F415XX/board/board.h
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
/*
|
||||||
|
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
|
||||||
|
ChibiOS - Copyright (C) 2023..2024 HorrorTroll
|
||||||
|
ChibiOS - Copyright (C) 2023..2024 Zhaqian
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _BOARD_H_
|
||||||
|
#define _BOARD_H_
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver constants. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Setup for a Generic AT32F415 board.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Board identifier.
|
||||||
|
*/
|
||||||
|
#define BOARD_GENERIC_AT32_F415XX
|
||||||
|
#define BOARD_NAME "GENERIC AT32F415 board"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Board oscillators-related settings.
|
||||||
|
*/
|
||||||
|
#if !defined(AT32_LEXTCLK)
|
||||||
|
#define AT32_LEXTCLK 32768
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(AT32_HEXTCLK)
|
||||||
|
#define AT32_HEXTCLK 8000000
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MCU type, supported types are defined in ./os/hal/platforms/hal_lld.h.
|
||||||
|
*/
|
||||||
|
#define AT32F415KB
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IO pins assignments.
|
||||||
|
*/
|
||||||
|
#define GPIOA_PIN0 0U
|
||||||
|
#define GPIOA_PIN1 1U
|
||||||
|
#define GPIOA_PIN2 2U
|
||||||
|
#define GPIOA_PIN3 3U
|
||||||
|
#define GPIOA_PIN4 4U
|
||||||
|
#define GPIOA_PIN5 5U
|
||||||
|
#define GPIOA_PIN6 6U
|
||||||
|
#define GPIOA_PIN7 7U
|
||||||
|
#define GPIOA_PIN8 8U
|
||||||
|
#define GPIOA_PIN9 9U
|
||||||
|
#define GPIOA_PIN10 10U
|
||||||
|
#define GPIOA_PIN11 11U
|
||||||
|
#define GPIOA_PIN12 12U
|
||||||
|
#define GPIOA_SWDIO 13U
|
||||||
|
#define GPIOA_SWCLK 14U
|
||||||
|
#define GPIOA_PIN15 15U
|
||||||
|
|
||||||
|
#define GPIOB_PIN0 0U
|
||||||
|
#define GPIOB_PIN1 1U
|
||||||
|
#define GPIOB_PIN2 2U
|
||||||
|
#define GPIOB_PIN3 3U
|
||||||
|
#define GPIOB_PIN4 4U
|
||||||
|
#define GPIOB_PIN5 5U
|
||||||
|
#define GPIOB_PIN6 6U
|
||||||
|
#define GPIOB_PIN7 7U
|
||||||
|
#define GPIOB_PIN8 8U
|
||||||
|
#define GPIOB_PIN9 9U
|
||||||
|
#define GPIOB_PIN10 10U
|
||||||
|
#define GPIOB_PIN11 11U
|
||||||
|
#define GPIOB_PIN12 12U
|
||||||
|
#define GPIOB_PIN13 13U
|
||||||
|
#define GPIOB_PIN14 14U
|
||||||
|
#define GPIOB_PIN15 15U
|
||||||
|
|
||||||
|
#define GPIOC_PIN0 0U
|
||||||
|
#define GPIOC_PIN1 1U
|
||||||
|
#define GPIOC_PIN2 2U
|
||||||
|
#define GPIOC_PIN3 3U
|
||||||
|
#define GPIOC_PIN4 4U
|
||||||
|
#define GPIOC_PIN5 5U
|
||||||
|
#define GPIOC_PIN6 6U
|
||||||
|
#define GPIOC_PIN7 7U
|
||||||
|
#define GPIOC_PIN8 8U
|
||||||
|
#define GPIOC_PIN9 9U
|
||||||
|
#define GPIOC_PIN10 10U
|
||||||
|
#define GPIOC_PIN11 11U
|
||||||
|
#define GPIOC_PIN12 12U
|
||||||
|
#define GPIOC_PIN13 13U
|
||||||
|
#define GPIOC_PIN14 14U
|
||||||
|
#define GPIOC_PIN15 15U
|
||||||
|
|
||||||
|
#define GPIOD_HEXT_IN 0U
|
||||||
|
#define GPIOD_HEXT_OUT 1U
|
||||||
|
#define GPIOD_PIN2 2U
|
||||||
|
|
||||||
|
#define GPIOF_PIN4 4U
|
||||||
|
#define GPIOF_PIN5 5U
|
||||||
|
#define GPIOF_PIN6 6U
|
||||||
|
#define GPIOF_PIN7 7U
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver pre-compile time settings. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Derived constants and error checks. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver data structures and types. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver macros. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* I/O ports initial setup, this configuration is established soon after reset
|
||||||
|
* in the initialization code.
|
||||||
|
*
|
||||||
|
* The digits have the following meaning:
|
||||||
|
* 0 - Analog input.
|
||||||
|
* 1 - Push Pull output 10MHz.
|
||||||
|
* 2 - Push Pull output 2MHz.
|
||||||
|
* 3 - Push Pull output 50MHz.
|
||||||
|
* 4 - Digital input.
|
||||||
|
* 5 - Open Drain output 10MHz.
|
||||||
|
* 6 - Open Drain output 2MHz.
|
||||||
|
* 7 - Open Drain output 50MHz.
|
||||||
|
* 8 - Digital input with Pull-Up or Pull-Down resistor depending on ODT.
|
||||||
|
* 9 - Alternate Push Pull output 10MHz.
|
||||||
|
* A - Alternate Push Pull output 2MHz.
|
||||||
|
* B - Alternate Push Pull output 50MHz.
|
||||||
|
* C - Reserved.
|
||||||
|
* D - Alternate Open Drain output 10MHz.
|
||||||
|
* E - Alternate Open Drain output 2MHz.
|
||||||
|
* F - Alternate Open Drain output 50MHz.
|
||||||
|
* Please refer to the AT32 Reference Manual for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Port A setup.
|
||||||
|
*/
|
||||||
|
#define VAL_GPIOACFGLR 0x88888B88 /* PA7...PA0 */
|
||||||
|
#define VAL_GPIOACFGHR 0x888888B8 /* PA15...PA8 */
|
||||||
|
#define VAL_GPIOAODT 0xFFFFFFFF
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Port B setup.
|
||||||
|
*/
|
||||||
|
#define VAL_GPIOBCFGLR 0x88888888 /* PB7...PB0 */
|
||||||
|
#define VAL_GPIOBCFGHR 0x88888888 /* PB15...PB8 */
|
||||||
|
#define VAL_GPIOBODT 0xFFFFFFFF
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Port C setup.
|
||||||
|
*/
|
||||||
|
#define VAL_GPIOCCFGLR 0x88888888 /* PC7...PC0 */
|
||||||
|
#define VAL_GPIOCCFGHR 0x88888888 /* PC15...PC8 */
|
||||||
|
#define VAL_GPIOCODT 0xFFFFFFFF
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Port D setup.
|
||||||
|
* Everything input with pull-up except:
|
||||||
|
* PD0 - Normal input (GPIOD_HEXT_IN).
|
||||||
|
* PD1 - Normal input (GPIOD_HEXT_OUT).
|
||||||
|
*/
|
||||||
|
#define VAL_GPIODCFGLR 0x88888844 /* PD7...PD0 */
|
||||||
|
#define VAL_GPIODCFGHR 0x88888888 /* PD15...PD8 */
|
||||||
|
#define VAL_GPIODODT 0xFFFFFFFF
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Port F setup.
|
||||||
|
*/
|
||||||
|
#define VAL_GPIOFCFGLR 0x88888888 /* PF7...PF0 */
|
||||||
|
#define VAL_GPIOFCFGHR 0x88888888 /* PF15...PF8 */
|
||||||
|
#define VAL_GPIOFODT 0xFFFFFFFF
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* External declarations. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
#if !defined(_FROM_ASM_)
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
void boardInit(void);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif /* _FROM_ASM_ */
|
||||||
|
|
||||||
|
#endif /* _BOARD_H_ */
|
@ -0,0 +1,9 @@
|
|||||||
|
# List of all the board related files.
|
||||||
|
BOARDSRC = $(BOARD_PATH)/board/board.c
|
||||||
|
|
||||||
|
# Required include directories
|
||||||
|
BOARDINC = $(BOARD_PATH)/board
|
||||||
|
|
||||||
|
# Shared variables
|
||||||
|
ALLCSRC += $(BOARDSRC)
|
||||||
|
ALLINC += $(BOARDINC)
|
@ -0,0 +1,13 @@
|
|||||||
|
// Copyright 2023-2024 HorrorTroll <https://github.com/HorrorTroll>
|
||||||
|
// Copyright 2023-2024 Zhaqian <https://github.com/zhaqian12>
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define BOARD_OTG_VBUSIG
|
||||||
|
|
||||||
|
#define USB_ENDPOINTS_ARE_REORDERABLE
|
||||||
|
|
||||||
|
#ifndef EARLY_INIT_PERFORM_BOOTLOADER_JUMP
|
||||||
|
# define EARLY_INIT_PERFORM_BOOTLOADER_JUMP TRUE
|
||||||
|
#endif
|
236
platforms/chibios/boards/GENERIC_AT32_F415XX/configs/mcuconf.h
Normal file
236
platforms/chibios/boards/GENERIC_AT32_F415XX/configs/mcuconf.h
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
/*
|
||||||
|
ChibiOS - Copyright (C) 2006..2020 Giovanni Di Sirio
|
||||||
|
ChibiOS - Copyright (C) 2023..2024 HorrorTroll
|
||||||
|
ChibiOS - Copyright (C) 2023..2024 Zhaqian
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MCUCONF_H
|
||||||
|
#define MCUCONF_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AT32F415 drivers configuration.
|
||||||
|
* The following settings override the default settings present in
|
||||||
|
* the various device driver implementation headers.
|
||||||
|
* Note that the settings for each driver only have effect if the whole
|
||||||
|
* driver is enabled in halconf.h.
|
||||||
|
*
|
||||||
|
* IRQ priorities:
|
||||||
|
* 15...0 Lowest...Highest.
|
||||||
|
*
|
||||||
|
* DMA priorities:
|
||||||
|
* 0...3 Lowest...Highest.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define AT32F415_MCUCONF
|
||||||
|
|
||||||
|
/*
|
||||||
|
* General settings.
|
||||||
|
*/
|
||||||
|
#define AT32_NO_INIT FALSE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* HAL driver system settings.
|
||||||
|
*/
|
||||||
|
#define AT32_HICK_ENABLED TRUE
|
||||||
|
#define AT32_LICK_ENABLED FALSE
|
||||||
|
#define AT32_HEXT_ENABLED TRUE
|
||||||
|
#define AT32_LEXT_ENABLED FALSE
|
||||||
|
#define AT32_SCLKSEL AT32_SCLKSEL_PLL
|
||||||
|
#define AT32_PLLRCS AT32_PLLRCS_HEXT
|
||||||
|
#define AT32_PLLHEXTDIV AT32_PLLHEXTDIV_DIV1
|
||||||
|
#define AT32_PLLCFGEN AT32_PLLCFGEN_SOLID
|
||||||
|
#define AT32_PLLMULT_VALUE 18
|
||||||
|
#define AT32_PLL_FR_VALUE 4
|
||||||
|
#define AT32_PLL_MS_VALUE 1
|
||||||
|
#define AT32_PLL_NS_VALUE 72
|
||||||
|
#define AT32_AHBDIV AT32_AHBDIV_DIV1
|
||||||
|
#define AT32_APB1DIV AT32_APB1DIV_DIV2
|
||||||
|
#define AT32_APB2DIV AT32_APB2DIV_DIV2
|
||||||
|
#define AT32_ADCDIV AT32_ADCDIV_DIV4
|
||||||
|
#define AT32_USB_CLOCK_REQUIRED TRUE
|
||||||
|
#define AT32_USBDIV AT32_USBDIV_DIV3
|
||||||
|
#define AT32_CLKOUT_SEL AT32_CLKOUT_SEL_NOCLOCK
|
||||||
|
#define AT32_CLKOUTDIV AT32_CLKOUTDIV_DIV1
|
||||||
|
#define AT32_ERTCSEL AT32_ERTCSEL_HEXTDIV
|
||||||
|
#define AT32_PVM_ENABLE FALSE
|
||||||
|
#define AT32_PVMSEL AT32_PVMSEL_LEV1
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IRQ system settings.
|
||||||
|
*/
|
||||||
|
#define AT32_IRQ_EXINT0_PRIORITY 6
|
||||||
|
#define AT32_IRQ_EXINT1_PRIORITY 6
|
||||||
|
#define AT32_IRQ_EXINT2_PRIORITY 6
|
||||||
|
#define AT32_IRQ_EXINT3_PRIORITY 6
|
||||||
|
#define AT32_IRQ_EXINT4_PRIORITY 6
|
||||||
|
#define AT32_IRQ_EXINT5_9_PRIORITY 6
|
||||||
|
#define AT32_IRQ_EXINT10_15_PRIORITY 6
|
||||||
|
#define AT32_IRQ_EXINT16_PRIORITY 6
|
||||||
|
#define AT32_IRQ_EXINT17_PRIORITY 15
|
||||||
|
#define AT32_IRQ_EXINT18_PRIORITY 6
|
||||||
|
#define AT32_IRQ_EXINT19_PRIORITY 6
|
||||||
|
#define AT32_IRQ_EXINT20_PRIORITY 6
|
||||||
|
#define AT32_IRQ_EXINT21_PRIORITY 15
|
||||||
|
#define AT32_IRQ_EXINT22_PRIORITY 15
|
||||||
|
|
||||||
|
#define AT32_IRQ_TMR1_BRK_TMR9_PRIORITY 7
|
||||||
|
#define AT32_IRQ_TMR1_OVF_TMR10_PRIORITY 7
|
||||||
|
#define AT32_IRQ_TMR1_HALL_TMR11_PRIORITY 7
|
||||||
|
#define AT32_IRQ_TMR1_CH_PRIORITY 7
|
||||||
|
#define AT32_IRQ_TMR2_PRIORITY 7
|
||||||
|
#define AT32_IRQ_TMR3_PRIORITY 7
|
||||||
|
#define AT32_IRQ_TMR4_PRIORITY 7
|
||||||
|
#define AT32_IRQ_TMR5_PRIORITY 7
|
||||||
|
|
||||||
|
#define AT32_IRQ_USART1_PRIORITY 12
|
||||||
|
#define AT32_IRQ_USART2_PRIORITY 12
|
||||||
|
#define AT32_IRQ_USART3_PRIORITY 12
|
||||||
|
#define AT32_IRQ_UART4_PRIORITY 12
|
||||||
|
#define AT32_IRQ_UART5_PRIORITY 12
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ADC driver system settings.
|
||||||
|
*/
|
||||||
|
#define AT32_ADC_USE_ADC1 FALSE
|
||||||
|
#define AT32_ADC_ADC1_DMA_PRIORITY 2
|
||||||
|
#define AT32_ADC_ADC1_IRQ_PRIORITY 6
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CAN driver system settings.
|
||||||
|
*/
|
||||||
|
#define AT32_CAN_USE_CAN1 FALSE
|
||||||
|
#define AT32_CAN_CAN1_IRQ_PRIORITY 11
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DMA driver system settings.
|
||||||
|
*/
|
||||||
|
#define AT32_DMA_USE_DMAMUX TRUE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GPT driver system settings.
|
||||||
|
*/
|
||||||
|
#define AT32_GPT_USE_TMR1 FALSE
|
||||||
|
#define AT32_GPT_USE_TMR2 FALSE
|
||||||
|
#define AT32_GPT_USE_TMR3 FALSE
|
||||||
|
#define AT32_GPT_USE_TMR4 FALSE
|
||||||
|
#define AT32_GPT_USE_TMR5 FALSE
|
||||||
|
#define AT32_GPT_USE_TMR9 FALSE
|
||||||
|
#define AT32_GPT_USE_TMR10 FALSE
|
||||||
|
#define AT32_GPT_USE_TMR11 FALSE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* I2C driver system settings.
|
||||||
|
*/
|
||||||
|
#define AT32_I2C_USE_I2C1 FALSE
|
||||||
|
#define AT32_I2C_USE_I2C2 FALSE
|
||||||
|
#define AT32_I2C_BUSY_TIMEOUT 50
|
||||||
|
#define AT32_I2C_I2C1_IRQ_PRIORITY 5
|
||||||
|
#define AT32_I2C_I2C2_IRQ_PRIORITY 5
|
||||||
|
#define AT32_I2C_I2C1_DMA_PRIORITY 3
|
||||||
|
#define AT32_I2C_I2C2_DMA_PRIORITY 3
|
||||||
|
#define AT32_I2C_DMA_ERROR_HOOK(i2cp) osalSysHalt("DMA failure")
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ICU driver system settings.
|
||||||
|
*/
|
||||||
|
#define AT32_ICU_USE_TMR1 FALSE
|
||||||
|
#define AT32_ICU_USE_TMR2 FALSE
|
||||||
|
#define AT32_ICU_USE_TMR3 FALSE
|
||||||
|
#define AT32_ICU_USE_TMR4 FALSE
|
||||||
|
#define AT32_ICU_USE_TMR5 FALSE
|
||||||
|
#define AT32_ICU_USE_TMR9 FALSE
|
||||||
|
#define AT32_ICU_USE_TMR10 FALSE
|
||||||
|
#define AT32_ICU_USE_TMR11 FALSE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PWM driver system settings.
|
||||||
|
*/
|
||||||
|
#define AT32_PWM_USE_TMR1 FALSE
|
||||||
|
#define AT32_PWM_USE_TMR2 FALSE
|
||||||
|
#define AT32_PWM_USE_TMR3 FALSE
|
||||||
|
#define AT32_PWM_USE_TMR4 FALSE
|
||||||
|
#define AT32_PWM_USE_TMR5 FALSE
|
||||||
|
#define AT32_PWM_USE_TMR9 FALSE
|
||||||
|
#define AT32_PWM_USE_TMR10 FALSE
|
||||||
|
#define AT32_PWM_USE_TMR11 FALSE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RTC driver system settings.
|
||||||
|
*/
|
||||||
|
#define AT32_ERTC_DIVA_VALUE 32
|
||||||
|
#define AT32_ERTC_DIVB_VALUE 1024
|
||||||
|
#define AT32_ERTC_CTRL_INIT 0
|
||||||
|
#define AT32_ERTC_TAMP_INIT 0
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SDC driver system settings.
|
||||||
|
*/
|
||||||
|
#define AT32_SDC_SDIO_DMA_PRIORITY 3
|
||||||
|
#define AT32_SDC_SDIO_IRQ_PRIORITY 9
|
||||||
|
#define AT32_SDC_WRITE_TIMEOUT_MS 1000
|
||||||
|
#define AT32_SDC_READ_TIMEOUT_MS 1000
|
||||||
|
#define AT32_SDC_CLOCK_ACTIVATION_DELAY 10
|
||||||
|
#define AT32_SDC_SDIO_UNALIGNED_SUPPORT TRUE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SERIAL driver system settings.
|
||||||
|
*/
|
||||||
|
#define AT32_SERIAL_USE_USART1 FALSE
|
||||||
|
#define AT32_SERIAL_USE_USART2 FALSE
|
||||||
|
#define AT32_SERIAL_USE_USART3 FALSE
|
||||||
|
#define AT32_SERIAL_USE_UART4 FALSE
|
||||||
|
#define AT32_SERIAL_USE_UART5 FALSE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SPI driver system settings.
|
||||||
|
*/
|
||||||
|
#define AT32_SPI_USE_SPI1 FALSE
|
||||||
|
#define AT32_SPI_USE_SPI2 FALSE
|
||||||
|
#define AT32_SPI_SPI1_DMA_PRIORITY 1
|
||||||
|
#define AT32_SPI_SPI2_DMA_PRIORITY 1
|
||||||
|
#define AT32_SPI_SPI1_IRQ_PRIORITY 10
|
||||||
|
#define AT32_SPI_SPI2_IRQ_PRIORITY 10
|
||||||
|
#define AT32_SPI_DMA_ERROR_HOOK(spip) osalSysHalt("DMA failure")
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ST driver system settings.
|
||||||
|
*/
|
||||||
|
#define AT32_ST_IRQ_PRIORITY 8
|
||||||
|
#define AT32_ST_USE_TIMER 2
|
||||||
|
|
||||||
|
/*
|
||||||
|
* UART driver system settings.
|
||||||
|
*/
|
||||||
|
#define AT32_UART_USE_USART1 FALSE
|
||||||
|
#define AT32_UART_USE_USART2 FALSE
|
||||||
|
#define AT32_UART_USE_USART3 FALSE
|
||||||
|
#define AT32_UART_USART1_DMA_PRIORITY 0
|
||||||
|
#define AT32_UART_USART2_DMA_PRIORITY 0
|
||||||
|
#define AT32_UART_USART3_DMA_PRIORITY 0
|
||||||
|
#define AT32_UART_DMA_ERROR_HOOK(uartp) osalSysHalt("DMA failure")
|
||||||
|
|
||||||
|
/*
|
||||||
|
* USB driver system settings.
|
||||||
|
*/
|
||||||
|
#define AT32_USB_USE_OTG1 TRUE
|
||||||
|
#define AT32_USB_OTG1_IRQ_PRIORITY 14
|
||||||
|
#define AT32_USB_OTG1_RX_FIFO_SIZE 512
|
||||||
|
|
||||||
|
/*
|
||||||
|
* WDG driver system settings.
|
||||||
|
*/
|
||||||
|
#define AT32_WDG_USE_WDT FALSE
|
||||||
|
|
||||||
|
#endif /* MCUCONF_H */
|
@ -26,6 +26,7 @@
|
|||||||
# stm32-dfu STM32 USB DFU in ROM
|
# stm32-dfu STM32 USB DFU in ROM
|
||||||
# apm32-dfu APM32 USB DFU in ROM
|
# apm32-dfu APM32 USB DFU in ROM
|
||||||
# wb32-dfu WB32 USB DFU in ROM
|
# wb32-dfu WB32 USB DFU in ROM
|
||||||
|
# at32-dfu AT32 USB DFU in ROM
|
||||||
# tinyuf2 TinyUF2
|
# tinyuf2 TinyUF2
|
||||||
# rp2040 Raspberry Pi RP2040
|
# rp2040 Raspberry Pi RP2040
|
||||||
# Current options for RISC-V:
|
# Current options for RISC-V:
|
||||||
@ -119,6 +120,14 @@ ifeq ($(strip $(BOOTLOADER)), wb32-dfu)
|
|||||||
OPT_DEFS += -DBOOTLOADER_WB32_DFU
|
OPT_DEFS += -DBOOTLOADER_WB32_DFU
|
||||||
BOOTLOADER_TYPE = wb32_dfu
|
BOOTLOADER_TYPE = wb32_dfu
|
||||||
endif
|
endif
|
||||||
|
ifeq ($(strip $(BOOTLOADER)), at32-dfu)
|
||||||
|
OPT_DEFS += -DBOOTLOADER_AT32_DFU
|
||||||
|
BOOTLOADER_TYPE = at32_dfu
|
||||||
|
|
||||||
|
# Options to pass to dfu-util when flashing
|
||||||
|
DFU_ARGS ?= -d 2E3C:DF11 -a 0 -s 0x08000000:leave
|
||||||
|
DFU_SUFFIX_ARGS ?= -v 2E3C -p DF11
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(strip $(BOOTLOADER_TYPE)),)
|
ifeq ($(strip $(BOOTLOADER_TYPE)),)
|
||||||
ifneq ($(strip $(BOOTLOADER)),)
|
ifneq ($(strip $(BOOTLOADER)),)
|
||||||
|
83
platforms/chibios/bootloaders/at32_dfu.c
Normal file
83
platforms/chibios/bootloaders/at32_dfu.c
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
// Copyright 2021-2023 QMK
|
||||||
|
// Copyright 2023-2024 HorrorTroll <https://github.com/HorrorTroll>
|
||||||
|
// Copyright 2023-2024 Zhaqian <https://github.com/zhaqian12>
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "bootloader.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#include <ch.h>
|
||||||
|
#include <hal.h>
|
||||||
|
#include "wait.h"
|
||||||
|
|
||||||
|
#ifndef AT32_BOOTLOADER_RAM_SYMBOL
|
||||||
|
# define AT32_BOOTLOADER_RAM_SYMBOL __ram0_end__
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern uint32_t AT32_BOOTLOADER_RAM_SYMBOL;
|
||||||
|
|
||||||
|
/* This code should be checked whether it runs correctly on platforms */
|
||||||
|
#define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0))
|
||||||
|
#define BOOTLOADER_MAGIC 0xDEADBEEF
|
||||||
|
#define MAGIC_ADDR (unsigned long *)(SYMVAL(AT32_BOOTLOADER_RAM_SYMBOL) - 4)
|
||||||
|
|
||||||
|
__attribute__((weak)) void bootloader_marker_enable(void) {
|
||||||
|
uint32_t *marker = (uint32_t *)MAGIC_ADDR;
|
||||||
|
*marker = BOOTLOADER_MAGIC; // set magic flag => reset handler will jump into boot loader
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((weak)) bool bootloader_marker_active(void) {
|
||||||
|
const uint32_t *marker = (const uint32_t *)MAGIC_ADDR;
|
||||||
|
return (*marker == BOOTLOADER_MAGIC) ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((weak)) void bootloader_marker_disable(void) {
|
||||||
|
uint32_t *marker = (uint32_t *)MAGIC_ADDR;
|
||||||
|
*marker = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((weak)) void bootloader_jump(void) {
|
||||||
|
bootloader_marker_enable();
|
||||||
|
NVIC_SystemReset();
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((weak)) void mcu_reset(void) {
|
||||||
|
NVIC_SystemReset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void enter_bootloader_mode_if_requested(void) {
|
||||||
|
if (bootloader_marker_active()) {
|
||||||
|
bootloader_marker_disable();
|
||||||
|
|
||||||
|
struct system_memory_vector_t {
|
||||||
|
uint32_t stack_top;
|
||||||
|
void (*entrypoint)(void);
|
||||||
|
};
|
||||||
|
const struct system_memory_vector_t *bootloader = (const struct system_memory_vector_t *)(AT32_BOOTLOADER_ADDRESS);
|
||||||
|
|
||||||
|
__disable_irq();
|
||||||
|
|
||||||
|
#if defined(__MPU_PRESENT) && (__MPU_PRESENT == 1U)
|
||||||
|
ARM_MPU_Disable();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SysTick->CTRL = 0;
|
||||||
|
SysTick->VAL = 0;
|
||||||
|
SysTick->LOAD = 0;
|
||||||
|
|
||||||
|
// Clear interrupt enable and interrupt pending registers
|
||||||
|
for (int i = 0; i < ARRAY_SIZE(NVIC->ICER); i++) {
|
||||||
|
NVIC->ICER[i] = 0xFFFFFFFF;
|
||||||
|
NVIC->ICPR[i] = 0xFFFFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
__set_CONTROL(0);
|
||||||
|
__set_MSP(bootloader->stack_top);
|
||||||
|
__enable_irq();
|
||||||
|
|
||||||
|
// Jump to bootloader
|
||||||
|
bootloader->entrypoint();
|
||||||
|
while (true) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -142,6 +142,19 @@
|
|||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// AT32 compatibility
|
||||||
|
#if defined(MCU_AT32)
|
||||||
|
# define CPU_CLOCK AT32_SYSCLK
|
||||||
|
|
||||||
|
# if defined(AT32F415)
|
||||||
|
# define USE_GPIOV1
|
||||||
|
# define USE_I2CV1
|
||||||
|
# define PAL_MODE_ALTERNATE_OPENDRAIN PAL_MODE_AT32_ALTERNATE_OPENDRAIN
|
||||||
|
# define PAL_MODE_ALTERNATE_PUSHPULL PAL_MODE_AT32_ALTERNATE_PUSHPULL
|
||||||
|
# define AUDIO_PWM_PAL_MODE PAL_MODE_ALTERNATE_PUSHPULL
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(GD32VF103)
|
#if defined(GD32VF103)
|
||||||
/* This chip has the same API as STM32F103, but uses different names for literally the same thing.
|
/* This chip has the same API as STM32F103, but uses different names for literally the same thing.
|
||||||
* As of 4.7.2021 QMK is tailored to use STM32 defines/names, for compatibility sake
|
* As of 4.7.2021 QMK is tailored to use STM32 defines/names, for compatibility sake
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
# error "You need to set HAL_USE_ADC to TRUE in your halconf.h to use the ADC."
|
# error "You need to set HAL_USE_ADC to TRUE in your halconf.h to use the ADC."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !RP_ADC_USE_ADC1 && !STM32_ADC_USE_ADC1 && !STM32_ADC_USE_ADC2 && !STM32_ADC_USE_ADC3 && !STM32_ADC_USE_ADC4 && !WB32_ADC_USE_ADC1
|
#if !RP_ADC_USE_ADC1 && !STM32_ADC_USE_ADC1 && !STM32_ADC_USE_ADC2 && !STM32_ADC_USE_ADC3 && !STM32_ADC_USE_ADC4 && !WB32_ADC_USE_ADC1 && !AT32_ADC_USE_ADC1
|
||||||
# error "You need to set one of the 'xxx_ADC_USE_ADCx' settings to TRUE in your mcuconf.h to use the ADC."
|
# error "You need to set one of the 'xxx_ADC_USE_ADCx' settings to TRUE in your mcuconf.h to use the ADC."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -45,7 +45,7 @@
|
|||||||
// Otherwise assume V3
|
// Otherwise assume V3
|
||||||
#if defined(STM32F0XX) || defined(STM32L0XX)
|
#if defined(STM32F0XX) || defined(STM32L0XX)
|
||||||
# define USE_ADCV1
|
# define USE_ADCV1
|
||||||
#elif defined(STM32F1XX) || defined(STM32F2XX) || defined(STM32F4XX) || defined(GD32VF103) || defined(WB32F3G71xx) || defined(WB32FQ95xx)
|
#elif defined(STM32F1XX) || defined(STM32F2XX) || defined(STM32F4XX) || defined(GD32VF103) || defined(WB32F3G71xx) || defined(WB32FQ95xx) || defined(AT32F415)
|
||||||
# define USE_ADCV2
|
# define USE_ADCV2
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -82,7 +82,7 @@
|
|||||||
|
|
||||||
/* User configurable ADC options */
|
/* User configurable ADC options */
|
||||||
#ifndef ADC_COUNT
|
#ifndef ADC_COUNT
|
||||||
# if defined(RP2040) || defined(STM32F0XX) || defined(STM32F1XX) || defined(STM32F4XX) || defined(GD32VF103) || defined(WB32F3G71xx) || defined(WB32FQ95xx)
|
# if defined(RP2040) || defined(STM32F0XX) || defined(STM32F1XX) || defined(STM32F4XX) || defined(GD32VF103) || defined(WB32F3G71xx) || defined(WB32FQ95xx) || defined(AT32F415)
|
||||||
# define ADC_COUNT 1
|
# define ADC_COUNT 1
|
||||||
# elif defined(STM32F3XX) || defined(STM32G4XX)
|
# elif defined(STM32F3XX) || defined(STM32G4XX)
|
||||||
# define ADC_COUNT 4
|
# define ADC_COUNT 4
|
||||||
@ -142,11 +142,16 @@ static ADCConversionGroup adcConversionGroup = {
|
|||||||
.cfgr1 = ADC_CFGR1_CONT | ADC_RESOLUTION,
|
.cfgr1 = ADC_CFGR1_CONT | ADC_RESOLUTION,
|
||||||
.smpr = ADC_SAMPLING_RATE,
|
.smpr = ADC_SAMPLING_RATE,
|
||||||
#elif defined(USE_ADCV2)
|
#elif defined(USE_ADCV2)
|
||||||
# if !defined(STM32F1XX) && !defined(GD32VF103) && !defined(WB32F3G71xx) && !defined(WB32FQ95xx)
|
# if !defined(STM32F1XX) && !defined(GD32VF103) && !defined(WB32F3G71xx) && !defined(WB32FQ95xx) && !defined(AT32F415)
|
||||||
.cr2 = ADC_CR2_SWSTART, // F103 seem very unhappy with, F401 seems very unhappy without...
|
.cr2 = ADC_CR2_SWSTART, // F103 seem very unhappy with, F401 seems very unhappy without...
|
||||||
# endif
|
# endif
|
||||||
|
# if defined(AT32F415)
|
||||||
|
.spt2 = ADC_SPT2_CSPT_AN0(ADC_SAMPLING_RATE) | ADC_SPT2_CSPT_AN1(ADC_SAMPLING_RATE) | ADC_SPT2_CSPT_AN2(ADC_SAMPLING_RATE) | ADC_SPT2_CSPT_AN3(ADC_SAMPLING_RATE) | ADC_SPT2_CSPT_AN4(ADC_SAMPLING_RATE) | ADC_SPT2_CSPT_AN5(ADC_SAMPLING_RATE) | ADC_SPT2_CSPT_AN6(ADC_SAMPLING_RATE) | ADC_SPT2_CSPT_AN7(ADC_SAMPLING_RATE) | ADC_SPT2_CSPT_AN8(ADC_SAMPLING_RATE) | ADC_SPT2_CSPT_AN9(ADC_SAMPLING_RATE),
|
||||||
|
.spt1 = ADC_SPT1_CSPT_AN10(ADC_SAMPLING_RATE) | ADC_SPT1_CSPT_AN11(ADC_SAMPLING_RATE) | ADC_SPT1_CSPT_AN12(ADC_SAMPLING_RATE) | ADC_SPT1_CSPT_AN13(ADC_SAMPLING_RATE) | ADC_SPT1_CSPT_AN14(ADC_SAMPLING_RATE) | ADC_SPT1_CSPT_AN15(ADC_SAMPLING_RATE),
|
||||||
|
# else
|
||||||
.smpr2 = ADC_SMPR2_SMP_AN0(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN1(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN2(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN3(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN4(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN5(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN6(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN7(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN8(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN9(ADC_SAMPLING_RATE),
|
.smpr2 = ADC_SMPR2_SMP_AN0(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN1(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN2(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN3(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN4(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN5(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN6(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN7(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN8(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN9(ADC_SAMPLING_RATE),
|
||||||
.smpr1 = ADC_SMPR1_SMP_AN10(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN11(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN12(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN13(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN14(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN15(ADC_SAMPLING_RATE),
|
.smpr1 = ADC_SMPR1_SMP_AN10(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN11(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN12(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN13(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN14(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN15(ADC_SAMPLING_RATE),
|
||||||
|
# endif
|
||||||
#elif defined(RP2040)
|
#elif defined(RP2040)
|
||||||
// RP2040 does not have any extra config here
|
// RP2040 does not have any extra config here
|
||||||
#else
|
#else
|
||||||
@ -242,7 +247,7 @@ __attribute__((weak)) adc_mux pinToMux(pin_t pin) {
|
|||||||
case F9: return TO_MUX( ADC_CHANNEL_IN7, 2 );
|
case F9: return TO_MUX( ADC_CHANNEL_IN7, 2 );
|
||||||
case F10: return TO_MUX( ADC_CHANNEL_IN8, 2 );
|
case F10: return TO_MUX( ADC_CHANNEL_IN8, 2 );
|
||||||
# endif
|
# endif
|
||||||
#elif defined(STM32F1XX) || defined(GD32VF103) || defined(WB32F3G71xx) || defined(WB32FQ95xx)
|
#elif defined(STM32F1XX) || defined(GD32VF103) || defined(WB32F3G71xx) || defined(WB32FQ95xx) || defined(AT32F415)
|
||||||
case A0: return TO_MUX( ADC_CHANNEL_IN0, 0 );
|
case A0: return TO_MUX( ADC_CHANNEL_IN0, 0 );
|
||||||
case A1: return TO_MUX( ADC_CHANNEL_IN1, 0 );
|
case A1: return TO_MUX( ADC_CHANNEL_IN1, 0 );
|
||||||
case A2: return TO_MUX( ADC_CHANNEL_IN2, 0 );
|
case A2: return TO_MUX( ADC_CHANNEL_IN2, 0 );
|
||||||
@ -344,7 +349,7 @@ __attribute__((weak)) adc_mux pinToMux(pin_t pin) {
|
|||||||
|
|
||||||
static inline ADCDriver* intToADCDriver(uint8_t adcInt) {
|
static inline ADCDriver* intToADCDriver(uint8_t adcInt) {
|
||||||
switch (adcInt) {
|
switch (adcInt) {
|
||||||
#if RP_ADC_USE_ADC1 || STM32_ADC_USE_ADC1 || WB32_ADC_USE_ADC1
|
#if RP_ADC_USE_ADC1 || STM32_ADC_USE_ADC1 || WB32_ADC_USE_ADC1 || AT32_ADC_USE_ADC1
|
||||||
case 0:
|
case 0:
|
||||||
return &ADCD1;
|
return &ADCD1;
|
||||||
#endif
|
#endif
|
||||||
@ -391,7 +396,11 @@ int16_t adc_read(adc_mux mux) {
|
|||||||
// TODO: fix previous assumption of only 1 input...
|
// TODO: fix previous assumption of only 1 input...
|
||||||
adcConversionGroup.chselr = 1 << mux.input; /*no macro to convert N to ADC_CHSELR_CHSEL1*/
|
adcConversionGroup.chselr = 1 << mux.input; /*no macro to convert N to ADC_CHSELR_CHSEL1*/
|
||||||
#elif defined(USE_ADCV2)
|
#elif defined(USE_ADCV2)
|
||||||
|
# if defined(AT32F415)
|
||||||
|
adcConversionGroup.osq3 = ADC_OSQ3_OSN1_N(mux.input);
|
||||||
|
# else
|
||||||
adcConversionGroup.sqr3 = ADC_SQR3_SQ1_N(mux.input);
|
adcConversionGroup.sqr3 = ADC_SQR3_SQ1_N(mux.input);
|
||||||
|
# endif
|
||||||
#elif defined(RP2040)
|
#elif defined(RP2040)
|
||||||
adcConversionGroup.channel_mask = 1 << mux.input;
|
adcConversionGroup.channel_mask = 1 << mux.input;
|
||||||
#else
|
#else
|
||||||
|
@ -9,6 +9,17 @@
|
|||||||
|
|
||||||
#if defined(SERIAL_USART_CONFIG)
|
#if defined(SERIAL_USART_CONFIG)
|
||||||
static QMKSerialConfig serial_config = SERIAL_USART_CONFIG;
|
static QMKSerialConfig serial_config = SERIAL_USART_CONFIG;
|
||||||
|
#elif defined(MCU_AT32) /* AT32 MCUs */
|
||||||
|
static QMKSerialConfig serial_config = {
|
||||||
|
.speed = (SERIAL_USART_SPEED),
|
||||||
|
.ctrl1 = (SERIAL_USART_CTRL1),
|
||||||
|
.ctrl2 = (SERIAL_USART_CTRL2),
|
||||||
|
# if !defined(SERIAL_USART_FULL_DUPLEX)
|
||||||
|
.ctrl3 = ((SERIAL_USART_CTRL3) | USART_CTRL3_SLBEN) /* activate half-duplex mode */
|
||||||
|
# else
|
||||||
|
.ctrl3 = (SERIAL_USART_CTRL3)
|
||||||
|
# endif
|
||||||
|
};
|
||||||
#elif defined(MCU_STM32) /* STM32 MCUs */
|
#elif defined(MCU_STM32) /* STM32 MCUs */
|
||||||
static QMKSerialConfig serial_config = {
|
static QMKSerialConfig serial_config = {
|
||||||
# if HAL_USE_SERIAL
|
# if HAL_USE_SERIAL
|
||||||
@ -160,7 +171,7 @@ inline bool serial_transport_receive_blocking(uint8_t* destination, const size_t
|
|||||||
* @brief Initiate pins for USART peripheral. Half-duplex configuration.
|
* @brief Initiate pins for USART peripheral. Half-duplex configuration.
|
||||||
*/
|
*/
|
||||||
__attribute__((weak)) void usart_init(void) {
|
__attribute__((weak)) void usart_init(void) {
|
||||||
# if defined(MCU_STM32) /* STM32 MCUs */
|
# if defined(MCU_STM32) || defined(MCU_AT32) /* STM32 and AT32 MCUs */
|
||||||
# if defined(USE_GPIOV1)
|
# if defined(USE_GPIOV1)
|
||||||
palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE_OPENDRAIN);
|
palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE_OPENDRAIN);
|
||||||
# else
|
# else
|
||||||
@ -183,7 +194,7 @@ __attribute__((weak)) void usart_init(void) {
|
|||||||
* @brief Initiate pins for USART peripheral. Full-duplex configuration.
|
* @brief Initiate pins for USART peripheral. Full-duplex configuration.
|
||||||
*/
|
*/
|
||||||
__attribute__((weak)) void usart_init(void) {
|
__attribute__((weak)) void usart_init(void) {
|
||||||
# if defined(MCU_STM32) /* STM32 MCUs */
|
# if defined(MCU_STM32) || defined(MCU_AT32) /* STM32 and AT32 MCUs */
|
||||||
# if defined(USE_GPIOV1)
|
# if defined(USE_GPIOV1)
|
||||||
palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE_PUSHPULL);
|
palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE_PUSHPULL);
|
||||||
palSetLineMode(SERIAL_USART_RX_PIN, PAL_MODE_INPUT);
|
palSetLineMode(SERIAL_USART_RX_PIN, PAL_MODE_INPUT);
|
||||||
|
@ -74,40 +74,75 @@ typedef SIOConfig QMKSerialConfig;
|
|||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(USART_CR1_M0)
|
#if defined(MCU_STM32) /* STM32 MCUs */
|
||||||
# define USART_CR1_M0 USART_CR1_M // some platforms (f1xx) dont have this so
|
# if !defined(USART_CR1_M0)
|
||||||
#endif
|
# define USART_CR1_M0 USART_CR1_M // some platforms (f1xx) dont have this so
|
||||||
|
# endif
|
||||||
|
|
||||||
#if !defined(SERIAL_USART_CR1)
|
# if !defined(SERIAL_USART_CR1)
|
||||||
# define SERIAL_USART_CR1 (USART_CR1_PCE | USART_CR1_PS | USART_CR1_M0) // parity enable, odd parity, 9 bit length
|
# define SERIAL_USART_CR1 (USART_CR1_PCE | USART_CR1_PS | USART_CR1_M0) // parity enable, odd parity, 9 bit length
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
#if !defined(SERIAL_USART_CR2)
|
# if !defined(SERIAL_USART_CR2)
|
||||||
# define SERIAL_USART_CR2 (USART_CR2_STOP_1) // 2 stop bits
|
# define SERIAL_USART_CR2 (USART_CR2_STOP_1) // 2 stop bits
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
#if !defined(SERIAL_USART_CR3)
|
# if !defined(SERIAL_USART_CR3)
|
||||||
# define SERIAL_USART_CR3 0
|
# define SERIAL_USART_CR3 0
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
#if defined(USART1_REMAP)
|
# if defined(USART1_REMAP)
|
||||||
# define USART_REMAP \
|
# define USART_REMAP \
|
||||||
do { \
|
do { \
|
||||||
(AFIO->MAPR |= AFIO_MAPR_USART1_REMAP); \
|
(AFIO->MAPR |= AFIO_MAPR_USART1_REMAP); \
|
||||||
} while (0)
|
} while (0)
|
||||||
#elif defined(USART2_REMAP)
|
# elif defined(USART2_REMAP)
|
||||||
# define USART_REMAP \
|
# define USART_REMAP \
|
||||||
do { \
|
do { \
|
||||||
(AFIO->MAPR |= AFIO_MAPR_USART2_REMAP); \
|
(AFIO->MAPR |= AFIO_MAPR_USART2_REMAP); \
|
||||||
} while (0)
|
} while (0)
|
||||||
#elif defined(USART3_PARTIALREMAP)
|
# elif defined(USART3_PARTIALREMAP)
|
||||||
# define USART_REMAP \
|
# define USART_REMAP \
|
||||||
do { \
|
do { \
|
||||||
(AFIO->MAPR |= AFIO_MAPR_USART3_REMAP_PARTIALREMAP); \
|
(AFIO->MAPR |= AFIO_MAPR_USART3_REMAP_PARTIALREMAP); \
|
||||||
} while (0)
|
} while (0)
|
||||||
#elif defined(USART3_FULLREMAP)
|
# elif defined(USART3_FULLREMAP)
|
||||||
# define USART_REMAP \
|
# define USART_REMAP \
|
||||||
do { \
|
do { \
|
||||||
(AFIO->MAPR |= AFIO_MAPR_USART3_REMAP_FULLREMAP); \
|
(AFIO->MAPR |= AFIO_MAPR_USART3_REMAP_FULLREMAP); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
# endif
|
||||||
|
#elif defined(MCU_AT32) /* AT32 MCUs */
|
||||||
|
# if !defined(USART_CTRL1_DBN0)
|
||||||
|
# define USART_CTRL1_DBN0 USART_CTRL1_DBN
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if !defined(SERIAL_USART_CTRL1)
|
||||||
|
# define SERIAL_USART_CTRL1 (USART_CTRL1_PEN | USART_CTRL1_PSEL | USART_CTRL1_DBN0) // parity enable, odd parity, 9 bit length
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if !defined(SERIAL_USART_CTRL2)
|
||||||
|
# define SERIAL_USART_CTRL2 (USART_CTRL2_STOPBN_1) // 2 stop bits
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if !defined(SERIAL_USART_CTRL3)
|
||||||
|
# define SERIAL_USART_CTRL3 0
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if defined(USART1_REMAP)
|
||||||
|
# define USART_REMAP \
|
||||||
|
do { \
|
||||||
|
(IOMUX->REMAP |= IOMUX_REMAP_USART1_MUX); \
|
||||||
|
} while (0)
|
||||||
|
# elif defined(USART3_PARTIALREMAP)
|
||||||
|
# define USART_REMAP \
|
||||||
|
do { \
|
||||||
|
(IOMUX->REMAP |= IOMUX_REMAP_USART3_MUX_MUX1); \
|
||||||
|
} while (0)
|
||||||
|
# elif defined(USART3_FULLREMAP)
|
||||||
|
# define USART_REMAP \
|
||||||
|
do { \
|
||||||
|
(IOMUX->REMAP |= IOMUX_REMAP_USART3_MUX_MUX2); \
|
||||||
|
} while (0)
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
@ -103,9 +103,15 @@ bool spi_start_extended(spi_start_config_t *start_config) {
|
|||||||
roundedDivisor <<= 1;
|
roundedDivisor <<= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# if defined(AT32F415)
|
||||||
|
if (roundedDivisor < 2 || roundedDivisor > 1024) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
# else
|
||||||
if (roundedDivisor < 2 || roundedDivisor > 256) {
|
if (roundedDivisor < 2 || roundedDivisor > 256) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(K20x) || defined(KL2x)
|
#if defined(K20x) || defined(KL2x)
|
||||||
@ -240,6 +246,59 @@ bool spi_start_extended(spi_start_config_t *start_config) {
|
|||||||
spiConfig.SSPCR0 |= SPI_SSPCR0_SPH; // Clock phase: sample on second edge transition
|
spiConfig.SSPCR0 |= SPI_SSPCR0_SPH; // Clock phase: sample on second edge transition
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#elif defined(AT32F415)
|
||||||
|
spiConfig.ctrl1 = 0;
|
||||||
|
|
||||||
|
if (lsbFirst) {
|
||||||
|
spiConfig.ctrl1 |= SPI_CTRL1_LTF;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
spiConfig.ctrl1 |= SPI_CTRL1_CLKPHA;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
spiConfig.ctrl1 |= SPI_CTRL1_CLKPOL;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
spiConfig.ctrl1 |= SPI_CTRL1_CLKPHA | SPI_CTRL1_CLKPOL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (roundedDivisor) {
|
||||||
|
case 2:
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
spiConfig.ctrl1 |= SPI_CTRL1_MDIV_0;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
spiConfig.ctrl1 |= SPI_CTRL1_MDIV_1;
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
spiConfig.ctrl1 |= SPI_CTRL1_MDIV_1 | SPI_CTRL1_MDIV_0;
|
||||||
|
break;
|
||||||
|
case 32:
|
||||||
|
spiConfig.ctrl1 |= SPI_CTRL1_MDIV_2;
|
||||||
|
break;
|
||||||
|
case 64:
|
||||||
|
spiConfig.ctrl1 |= SPI_CTRL1_MDIV_2 | SPI_CTRL1_MDIV_0;
|
||||||
|
break;
|
||||||
|
case 128:
|
||||||
|
spiConfig.ctrl1 |= SPI_CTRL1_MDIV_2 | SPI_CTRL1_MDIV_1;
|
||||||
|
break;
|
||||||
|
case 256:
|
||||||
|
spiConfig.ctrl1 |= SPI_CTRL1_MDIV_2 | SPI_CTRL1_MDIV_1 | SPI_CTRL1_MDIV_0;
|
||||||
|
break;
|
||||||
|
case 512:
|
||||||
|
spiConfig.ctrl2 |= SPI_CTRL1_MDIV_3;
|
||||||
|
break;
|
||||||
|
case 1024:
|
||||||
|
spiConfig.ctrl2 |= SPI_CTRL1_MDIV_3;
|
||||||
|
spiConfig.ctrl1 |= SPI_CTRL1_MDIV_0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
spiConfig.cr1 = 0;
|
spiConfig.cr1 = 0;
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ static inline uint32_t detect_flash_size(void) {
|
|||||||
#elif defined(FLASH_SIZE)
|
#elif defined(FLASH_SIZE)
|
||||||
return FLASH_SIZE;
|
return FLASH_SIZE;
|
||||||
#elif defined(FLASHSIZE_BASE)
|
#elif defined(FLASHSIZE_BASE)
|
||||||
# if defined(QMK_MCU_SERIES_STM32F0XX) || defined(QMK_MCU_SERIES_STM32F1XX) || defined(QMK_MCU_SERIES_STM32F3XX) || defined(QMK_MCU_SERIES_STM32F4XX) || defined(QMK_MCU_SERIES_STM32G4XX) || defined(QMK_MCU_SERIES_STM32L0XX) || defined(QMK_MCU_SERIES_STM32L4XX) || defined(QMK_MCU_SERIES_GD32VF103)
|
# if defined(QMK_MCU_SERIES_STM32F0XX) || defined(QMK_MCU_SERIES_STM32F1XX) || defined(QMK_MCU_SERIES_STM32F3XX) || defined(QMK_MCU_SERIES_STM32F4XX) || defined(QMK_MCU_SERIES_STM32G4XX) || defined(QMK_MCU_SERIES_STM32L0XX) || defined(QMK_MCU_SERIES_STM32L4XX) || defined(QMK_MCU_SERIES_AT32F415) || defined(QMK_MCU_SERIES_GD32VF103)
|
||||||
return ((*(uint32_t *)FLASHSIZE_BASE) & 0xFFFFU) << 10U; // this register has the flash size in kB, so we convert it to bytes
|
return ((*(uint32_t *)FLASHSIZE_BASE) & 0xFFFFU) << 10U; // this register has the flash size in kB, so we convert it to bytes
|
||||||
# elif defined(QMK_MCU_SERIES_STM32L1XX)
|
# elif defined(QMK_MCU_SERIES_STM32L1XX)
|
||||||
# error This MCU family has an uncommon flash size register definition and has not been implemented. Perhaps try using the true EEPROM on the MCU instead?
|
# error This MCU family has an uncommon flash size register definition and has not been implemented. Perhaps try using the true EEPROM on the MCU instead?
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
# define BACKING_STORE_WRITE_SIZE 4 // from hal_efl_lld.c
|
# define BACKING_STORE_WRITE_SIZE 4 // from hal_efl_lld.c
|
||||||
# elif defined(QMK_MCU_FAMILY_WB32)
|
# elif defined(QMK_MCU_FAMILY_WB32)
|
||||||
# define BACKING_STORE_WRITE_SIZE 8 // from hal_efl_lld.c
|
# define BACKING_STORE_WRITE_SIZE 8 // from hal_efl_lld.c
|
||||||
|
# elif defined(QMK_MCU_FAMILY_AT32)
|
||||||
|
# define BACKING_STORE_WRITE_SIZE 2 // from hal_efl_lld.c
|
||||||
# elif defined(QMK_MCU_FAMILY_STM32)
|
# elif defined(QMK_MCU_FAMILY_STM32)
|
||||||
# if defined(STM32_FLASH_LINE_SIZE) // from some family's stm32_registry.h file
|
# if defined(STM32_FLASH_LINE_SIZE) // from some family's stm32_registry.h file
|
||||||
# define BACKING_STORE_WRITE_SIZE (STM32_FLASH_LINE_SIZE)
|
# define BACKING_STORE_WRITE_SIZE (STM32_FLASH_LINE_SIZE)
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
/* Adapted from https://github.com/bigjosh/SimpleNeoPixelDemo/ */
|
/* Adapted from https://github.com/bigjosh/SimpleNeoPixelDemo/ */
|
||||||
|
|
||||||
#ifndef WS2812_BITBANG_NOP_FUDGE
|
#ifndef WS2812_BITBANG_NOP_FUDGE
|
||||||
# if defined(STM32F0XX) || defined(STM32F1XX) || defined(GD32VF103) || defined(STM32F3XX) || defined(STM32F4XX) || defined(STM32L0XX) || defined(WB32F3G71xx) || defined(WB32FQ95xx)
|
# if defined(STM32F0XX) || defined(STM32F1XX) || defined(GD32VF103) || defined(STM32F3XX) || defined(STM32F4XX) || defined(STM32L0XX) || defined(WB32F3G71xx) || defined(WB32FQ95xx) || defined(AT32F415)
|
||||||
# define WS2812_BITBANG_NOP_FUDGE 0.4
|
# define WS2812_BITBANG_NOP_FUDGE 0.4
|
||||||
# else
|
# else
|
||||||
# if defined(RP2040)
|
# if defined(RP2040)
|
||||||
|
@ -40,6 +40,9 @@
|
|||||||
#if (STM32_DMA_SUPPORTS_DMAMUX == TRUE) && !defined(WS2812_PWM_DMAMUX_ID)
|
#if (STM32_DMA_SUPPORTS_DMAMUX == TRUE) && !defined(WS2812_PWM_DMAMUX_ID)
|
||||||
# error "please consult your MCU's datasheet and specify in your config.h: #define WS2812_PWM_DMAMUX_ID STM32_DMAMUX1_TIM?_UP"
|
# error "please consult your MCU's datasheet and specify in your config.h: #define WS2812_PWM_DMAMUX_ID STM32_DMAMUX1_TIM?_UP"
|
||||||
#endif
|
#endif
|
||||||
|
#if (AT32_DMA_SUPPORTS_DMAMUX == TRUE) && !defined(WS2812_PWM_DMAMUX_CHANNEL) && !defined(WS2812_PWM_DMAMUX_ID)
|
||||||
|
# error "please consult your MCU's datasheet and specify in your config.h: #define WS2812_PWM_DMAMUX_CHANNEL 1, #define WS2812_PWM_DMAMUX_ID AT32_DMAMUX_TMR?_OVERFLOW"
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Summarize https://www.st.com/resource/en/application_note/an4013-stm32-crossseries-timer-overview-stmicroelectronics.pdf to
|
/* Summarize https://www.st.com/resource/en/application_note/an4013-stm32-crossseries-timer-overview-stmicroelectronics.pdf to
|
||||||
* figure out if we are using a 32bit timer. This is needed to setup the DMA controller correctly.
|
* figure out if we are using a 32bit timer. This is needed to setup the DMA controller correctly.
|
||||||
@ -269,6 +272,14 @@ typedef uint32_t ws2812_buffer_t;
|
|||||||
# define WS2812_PWM_DMA_PERIPHERAL_WIDTH STM32_DMA_CR_PSIZE_HWORD
|
# define WS2812_PWM_DMA_PERIPHERAL_WIDTH STM32_DMA_CR_PSIZE_HWORD
|
||||||
typedef uint16_t ws2812_buffer_t;
|
typedef uint16_t ws2812_buffer_t;
|
||||||
# endif
|
# endif
|
||||||
|
#elif defined(AT32F415)
|
||||||
|
# define WS2812_PWM_DMA_MEMORY_WIDTH AT32_DMA_CCTRL_MWIDTH_BYTE
|
||||||
|
# if defined(WS2812_PWM_TIMER_32BIT)
|
||||||
|
# define WS2812_PWM_DMA_PERIPHERAL_WIDTH AT32_DMA_CCTRL_PWIDTH_WORD
|
||||||
|
# else
|
||||||
|
# define WS2812_PWM_DMA_PERIPHERAL_WIDTH AT32_DMA_CCTRL_PWIDTH_HWORD
|
||||||
|
# endif
|
||||||
|
typedef uint8_t ws2812_buffer_t;
|
||||||
#else
|
#else
|
||||||
# define WS2812_PWM_DMA_MEMORY_WIDTH STM32_DMA_CR_MSIZE_BYTE
|
# define WS2812_PWM_DMA_MEMORY_WIDTH STM32_DMA_CR_MSIZE_BYTE
|
||||||
# if defined(WS2812_PWM_TIMER_32BIT)
|
# if defined(WS2812_PWM_TIMER_32BIT)
|
||||||
@ -309,8 +320,13 @@ void ws2812_init(void) {
|
|||||||
[0 ... 3] = {.mode = PWM_OUTPUT_DISABLED, .callback = NULL}, // Channels default to disabled
|
[0 ... 3] = {.mode = PWM_OUTPUT_DISABLED, .callback = NULL}, // Channels default to disabled
|
||||||
[WS2812_PWM_CHANNEL - 1] = {.mode = WS2812_PWM_OUTPUT_MODE, .callback = NULL}, // Turn on the channel we care about
|
[WS2812_PWM_CHANNEL - 1] = {.mode = WS2812_PWM_OUTPUT_MODE, .callback = NULL}, // Turn on the channel we care about
|
||||||
},
|
},
|
||||||
|
#if defined(AT32F415)
|
||||||
|
.ctrl2 = 0,
|
||||||
|
.iden = AT32_TMR_IDEN_OVFDEN, // DMA on update event for next period
|
||||||
|
#else
|
||||||
.cr2 = 0,
|
.cr2 = 0,
|
||||||
.dier = TIM_DIER_UDE, // DMA on update event for next period
|
.dier = TIM_DIER_UDE, // DMA on update event for next period
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
//#pragma GCC diagnostic pop // Restore command-line warning options
|
//#pragma GCC diagnostic pop // Restore command-line warning options
|
||||||
|
|
||||||
@ -321,6 +337,11 @@ void ws2812_init(void) {
|
|||||||
dmaStreamSetSource(WS2812_PWM_DMA_STREAM, ws2812_frame_buffer);
|
dmaStreamSetSource(WS2812_PWM_DMA_STREAM, ws2812_frame_buffer);
|
||||||
dmaStreamSetDestination(WS2812_PWM_DMA_STREAM, &(WS2812_PWM_DRIVER.tim->CCR[WS2812_PWM_CHANNEL - 1])); // Ziel ist der An-Zeit im Cap-Comp-Register
|
dmaStreamSetDestination(WS2812_PWM_DMA_STREAM, &(WS2812_PWM_DRIVER.tim->CCR[WS2812_PWM_CHANNEL - 1])); // Ziel ist der An-Zeit im Cap-Comp-Register
|
||||||
dmaStreamSetMode(WS2812_PWM_DMA_STREAM, WB32_DMA_CHCFG_HWHIF(WS2812_PWM_DMA_CHANNEL) | WB32_DMA_CHCFG_DIR_M2P | WB32_DMA_CHCFG_PSIZE_WORD | WB32_DMA_CHCFG_MSIZE_WORD | WB32_DMA_CHCFG_MINC | WB32_DMA_CHCFG_CIRC | WB32_DMA_CHCFG_TCIE | WB32_DMA_CHCFG_PL(3));
|
dmaStreamSetMode(WS2812_PWM_DMA_STREAM, WB32_DMA_CHCFG_HWHIF(WS2812_PWM_DMA_CHANNEL) | WB32_DMA_CHCFG_DIR_M2P | WB32_DMA_CHCFG_PSIZE_WORD | WB32_DMA_CHCFG_MSIZE_WORD | WB32_DMA_CHCFG_MINC | WB32_DMA_CHCFG_CIRC | WB32_DMA_CHCFG_TCIE | WB32_DMA_CHCFG_PL(3));
|
||||||
|
#elif defined(AT32F415)
|
||||||
|
dmaStreamAlloc(WS2812_PWM_DMA_STREAM - AT32_DMA_STREAM(0), 10, NULL, NULL);
|
||||||
|
dmaStreamSetPeripheral(WS2812_PWM_DMA_STREAM, &(WS2812_PWM_DRIVER.tmr->CDT[WS2812_PWM_CHANNEL - 1])); // Ziel ist der An-Zeit im Cap-Comp-Register
|
||||||
|
dmaStreamSetMemory0(WS2812_PWM_DMA_STREAM, ws2812_frame_buffer);
|
||||||
|
dmaStreamSetMode(WS2812_PWM_DMA_STREAM, AT32_DMA_CCTRL_DTD_M2P | WS2812_PWM_DMA_PERIPHERAL_WIDTH | WS2812_PWM_DMA_MEMORY_WIDTH | AT32_DMA_CCTRL_MINCM | AT32_DMA_CCTRL_LM | AT32_DMA_CCTRL_CHPL(3));
|
||||||
#else
|
#else
|
||||||
dmaStreamAlloc(WS2812_PWM_DMA_STREAM - STM32_DMA_STREAM(0), 10, NULL, NULL);
|
dmaStreamAlloc(WS2812_PWM_DMA_STREAM - STM32_DMA_STREAM(0), 10, NULL, NULL);
|
||||||
dmaStreamSetPeripheral(WS2812_PWM_DMA_STREAM, &(WS2812_PWM_DRIVER.tim->CCR[WS2812_PWM_CHANNEL - 1])); // Ziel ist der An-Zeit im Cap-Comp-Register
|
dmaStreamSetPeripheral(WS2812_PWM_DMA_STREAM, &(WS2812_PWM_DRIVER.tim->CCR[WS2812_PWM_CHANNEL - 1])); // Ziel ist der An-Zeit im Cap-Comp-Register
|
||||||
@ -335,6 +356,11 @@ void ws2812_init(void) {
|
|||||||
dmaSetRequestSource(WS2812_PWM_DMA_STREAM, WS2812_PWM_DMAMUX_ID);
|
dmaSetRequestSource(WS2812_PWM_DMA_STREAM, WS2812_PWM_DMAMUX_ID);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if (AT32_DMA_SUPPORTS_DMAMUX == TRUE)
|
||||||
|
// If the MCU has a DMAMUX we need to assign the correct resource
|
||||||
|
dmaSetRequestSource(WS2812_PWM_DMA_STREAM, WS2812_PWM_DMAMUX_CHANNEL, WS2812_PWM_DMAMUX_ID);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Start DMA
|
// Start DMA
|
||||||
dmaStreamEnable(WS2812_PWM_DMA_STREAM);
|
dmaStreamEnable(WS2812_PWM_DMA_STREAM);
|
||||||
|
|
||||||
|
@ -40,26 +40,53 @@
|
|||||||
|
|
||||||
// Define SPI config speed
|
// Define SPI config speed
|
||||||
// baudrate should target 3.2MHz
|
// baudrate should target 3.2MHz
|
||||||
|
#if defined(AT32F415)
|
||||||
|
# if WS2812_SPI_DIVISOR == 2
|
||||||
|
# define WS2812_SPI_DIVISOR_CTRL1_MDIV_X (0)
|
||||||
|
# elif WS2812_SPI_DIVISOR == 4
|
||||||
|
# define WS2812_SPI_DIVISOR_CTRL1_MDIV_X (SPI_CTRL1_MDIV_0)
|
||||||
|
# elif WS2812_SPI_DIVISOR == 8
|
||||||
|
# define WS2812_SPI_DIVISOR_CTRL1_MDIV_X (SPI_CTRL1_MDIV_1)
|
||||||
|
# elif WS2812_SPI_DIVISOR == 16 // default
|
||||||
|
# define WS2812_SPI_DIVISOR_CTRL1_MDIV_X (SPI_CTRL1_MDIV_1 | SPI_CTRL1_MDIV_0)
|
||||||
|
# elif WS2812_SPI_DIVISOR == 32
|
||||||
|
# define WS2812_SPI_DIVISOR_CTRL1_MDIV_X (SPI_CTRL1_MDIV_2)
|
||||||
|
# elif WS2812_SPI_DIVISOR == 64
|
||||||
|
# define WS2812_SPI_DIVISOR_CTRL1_MDIV_X (SPI_CTRL1_MDIV_2 | SPI_CTRL1_MDIV_0)
|
||||||
|
# elif WS2812_SPI_DIVISOR == 128
|
||||||
|
# define WS2812_SPI_DIVISOR_CTRL1_MDIV_X (SPI_CTRL1_MDIV_2 | SPI_CTRL1_MDIV_1)
|
||||||
|
# elif WS2812_SPI_DIVISOR == 256
|
||||||
|
# define WS2812_SPI_DIVISOR_CTRL1_MDIV_X (SPI_CTRL1_MDIV_2 | SPI_CTRL1_MDIV_1 | SPI_CTRL1_MDIV_0)
|
||||||
|
# elif WS2812_SPI_DIVISOR == 512
|
||||||
|
# define WS2812_SPI_DIVISOR_CTRL2_MDIV_X (SPI_CTRL1_MDIV_3)
|
||||||
|
# elif WS2812_SPI_DIVISOR == 1024
|
||||||
|
# define WS2812_SPI_DIVISOR_CTRL2_MDIV_X (SPI_CTRL1_MDIV_3)
|
||||||
|
# define WS2812_SPI_DIVISOR_CTRL1_MDIV_X (SPI_CTRL1_MDIV_0)
|
||||||
|
# else
|
||||||
|
# error "Configured WS2812_SPI_DIVISOR value is not supported at this time."
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
// F072 fpclk = 48MHz
|
// F072 fpclk = 48MHz
|
||||||
// 48/16 = 3Mhz
|
// 48/16 = 3Mhz
|
||||||
#if WS2812_SPI_DIVISOR == 2
|
# if WS2812_SPI_DIVISOR == 2
|
||||||
# define WS2812_SPI_DIVISOR_CR1_BR_X (0)
|
# define WS2812_SPI_DIVISOR_CR1_BR_X (0)
|
||||||
#elif WS2812_SPI_DIVISOR == 4
|
# elif WS2812_SPI_DIVISOR == 4
|
||||||
# define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_0)
|
# define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_0)
|
||||||
#elif WS2812_SPI_DIVISOR == 8
|
# elif WS2812_SPI_DIVISOR == 8
|
||||||
# define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_1)
|
# define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_1)
|
||||||
#elif WS2812_SPI_DIVISOR == 16 // default
|
# elif WS2812_SPI_DIVISOR == 16 // default
|
||||||
# define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_1 | SPI_CR1_BR_0)
|
# define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_1 | SPI_CR1_BR_0)
|
||||||
#elif WS2812_SPI_DIVISOR == 32
|
# elif WS2812_SPI_DIVISOR == 32
|
||||||
# define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_2)
|
# define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_2)
|
||||||
#elif WS2812_SPI_DIVISOR == 64
|
# elif WS2812_SPI_DIVISOR == 64
|
||||||
# define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_2 | SPI_CR1_BR_0)
|
# define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_2 | SPI_CR1_BR_0)
|
||||||
#elif WS2812_SPI_DIVISOR == 128
|
# elif WS2812_SPI_DIVISOR == 128
|
||||||
# define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_2 | SPI_CR1_BR_1)
|
# define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_2 | SPI_CR1_BR_1)
|
||||||
#elif WS2812_SPI_DIVISOR == 256
|
# elif WS2812_SPI_DIVISOR == 256
|
||||||
# define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_2 | SPI_CR1_BR_1 | SPI_CR1_BR_0)
|
# define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_2 | SPI_CR1_BR_1 | SPI_CR1_BR_0)
|
||||||
#else
|
# else
|
||||||
# error "Configured WS2812_SPI_DIVISOR value is not supported at this time."
|
# error "Configured WS2812_SPI_DIVISOR value is not supported at this time."
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Use SPI circular buffer
|
// Use SPI circular buffer
|
||||||
@ -176,8 +203,16 @@ void ws2812_init(void) {
|
|||||||
NULL, // error_cb
|
NULL, // error_cb
|
||||||
PAL_PORT(WS2812_DI_PIN),
|
PAL_PORT(WS2812_DI_PIN),
|
||||||
PAL_PAD(WS2812_DI_PIN),
|
PAL_PAD(WS2812_DI_PIN),
|
||||||
|
# if defined(AT32F415)
|
||||||
|
WS2812_SPI_DIVISOR_CTRL1_MDIV_X,
|
||||||
|
# if (WS2812_SPI_DIVISOR == 512 || WS2812_SPI_DIVISOR == 1024)
|
||||||
|
WS2812_SPI_DIVISOR_CTRL2_MDIV_X,
|
||||||
|
# endif
|
||||||
|
0
|
||||||
|
# else
|
||||||
WS2812_SPI_DIVISOR_CR1_BR_X,
|
WS2812_SPI_DIVISOR_CR1_BR_X,
|
||||||
0
|
0
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -113,6 +113,8 @@ else ifeq ($(strip $(MCU_FAMILY)),STM32)
|
|||||||
$(UNSYNC_OUTPUT_CMD) && $(call EXEC_DFU_UTIL)
|
$(UNSYNC_OUTPUT_CMD) && $(call EXEC_DFU_UTIL)
|
||||||
else ifeq ($(strip $(MCU_FAMILY)),WB32)
|
else ifeq ($(strip $(MCU_FAMILY)),WB32)
|
||||||
$(UNSYNC_OUTPUT_CMD) && $(call EXEC_WB32_DFU_UPDATER)
|
$(UNSYNC_OUTPUT_CMD) && $(call EXEC_WB32_DFU_UPDATER)
|
||||||
|
else ifeq ($(strip $(MCU_FAMILY)),AT32)
|
||||||
|
$(UNSYNC_OUTPUT_CMD) && $(call EXEC_DFU_UTIL)
|
||||||
else ifeq ($(strip $(MCU_FAMILY)),GD32V)
|
else ifeq ($(strip $(MCU_FAMILY)),GD32V)
|
||||||
$(UNSYNC_OUTPUT_CMD) && $(call EXEC_DFU_UTIL)
|
$(UNSYNC_OUTPUT_CMD) && $(call EXEC_DFU_UTIL)
|
||||||
else
|
else
|
||||||
|
@ -809,6 +809,40 @@ ifneq ($(findstring WB32FQ95, $(MCU)),)
|
|||||||
WB32_BOOTLOADER_ADDRESS ?= 0x1FFFE000
|
WB32_BOOTLOADER_ADDRESS ?= 0x1FFFE000
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifneq ($(findstring AT32F415, $(MCU)),)
|
||||||
|
# Cortex version
|
||||||
|
MCU = cortex-m4
|
||||||
|
|
||||||
|
# ARM version, CORTEX-M0/M1 are 6, CORTEX-M3/M4/M7 are 7
|
||||||
|
ARMV = 7
|
||||||
|
|
||||||
|
## chip/board settings
|
||||||
|
# - the next two should match the directories in
|
||||||
|
# <chibios[-contrib]>/os/hal/ports/$(MCU_PORT_NAME)/$(MCU_SERIES)
|
||||||
|
# OR
|
||||||
|
# <chibios[-contrib]>/os/hal/ports/$(MCU_FAMILY)/$(MCU_SERIES)
|
||||||
|
MCU_FAMILY = AT32
|
||||||
|
MCU_SERIES = AT32F415
|
||||||
|
|
||||||
|
# Linker script to use
|
||||||
|
# - it should exist either in <chibios>/os/common/startup/ARMCMx/compilers/GCC/ld/
|
||||||
|
# or <keyboard_dir>/ld/
|
||||||
|
MCU_LDSCRIPT ?= AT32F415xB
|
||||||
|
|
||||||
|
# Startup code to use
|
||||||
|
# - it should exist in <chibios>/os/common/startup/ARMCMx/compilers/GCC/mk/
|
||||||
|
MCU_STARTUP ?= at32f415
|
||||||
|
|
||||||
|
# Board: it should exist either in <chibios>/os/hal/boards/,
|
||||||
|
# <keyboard_dir>/boards/, or drivers/boards/
|
||||||
|
BOARD ?= GENERIC_AT32_F415XX
|
||||||
|
|
||||||
|
USE_FPU ?= no
|
||||||
|
|
||||||
|
# Bootloader address for AT32 DFU
|
||||||
|
AT32_BOOTLOADER_ADDRESS ?= 0x1FFFAC00
|
||||||
|
endif
|
||||||
|
|
||||||
ifneq ($(findstring GD32VF103, $(MCU)),)
|
ifneq ($(findstring GD32VF103, $(MCU)),)
|
||||||
# RISC-V
|
# RISC-V
|
||||||
MCU = risc-v
|
MCU = risc-v
|
||||||
|
@ -155,6 +155,10 @@ ifdef WB32_BOOTLOADER_ADDRESS
|
|||||||
OPT_DEFS += -DWB32_BOOTLOADER_ADDRESS=$(WB32_BOOTLOADER_ADDRESS)
|
OPT_DEFS += -DWB32_BOOTLOADER_ADDRESS=$(WB32_BOOTLOADER_ADDRESS)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifdef AT32_BOOTLOADER_ADDRESS
|
||||||
|
OPT_DEFS += -DAT32_BOOTLOADER_ADDRESS=$(AT32_BOOTLOADER_ADDRESS)
|
||||||
|
endif
|
||||||
|
|
||||||
# Work out if we need to set up the include for the bootloader definitions
|
# Work out if we need to set up the include for the bootloader definitions
|
||||||
ifneq ("$(wildcard $(KEYBOARD_PATH_5)/bootloader_defs.h)","")
|
ifneq ("$(wildcard $(KEYBOARD_PATH_5)/bootloader_defs.h)","")
|
||||||
OPT_DEFS += -include $(KEYBOARD_PATH_5)/bootloader_defs.h
|
OPT_DEFS += -include $(KEYBOARD_PATH_5)/bootloader_defs.h
|
||||||
|
@ -140,6 +140,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#ifdef OS_DETECTION_ENABLE
|
#ifdef OS_DETECTION_ENABLE
|
||||||
# include "os_detection.h"
|
# include "os_detection.h"
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(LAYER_LOCK_ENABLE) && LAYER_LOCK_IDLE_TIMEOUT > 0
|
||||||
|
# include "layer_lock.h"
|
||||||
|
#endif // LAYER_LOCK_ENABLE
|
||||||
|
|
||||||
static uint32_t last_input_modification_time = 0;
|
static uint32_t last_input_modification_time = 0;
|
||||||
uint32_t last_input_activity_time(void) {
|
uint32_t last_input_activity_time(void) {
|
||||||
@ -655,6 +658,10 @@ void quantum_task(void) {
|
|||||||
#ifdef SECURE_ENABLE
|
#ifdef SECURE_ENABLE
|
||||||
secure_task();
|
secure_task();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(LAYER_LOCK_ENABLE) && LAYER_LOCK_IDLE_TIMEOUT > 0
|
||||||
|
layer_lock_task();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \brief Main task that is repeatedly called as fast as possible. */
|
/** \brief Main task that is repeatedly called as fast as possible. */
|
||||||
|
@ -759,6 +759,7 @@ enum qk_keycode_defines {
|
|||||||
QK_TRI_LAYER_UPPER = 0x7C78,
|
QK_TRI_LAYER_UPPER = 0x7C78,
|
||||||
QK_REPEAT_KEY = 0x7C79,
|
QK_REPEAT_KEY = 0x7C79,
|
||||||
QK_ALT_REPEAT_KEY = 0x7C7A,
|
QK_ALT_REPEAT_KEY = 0x7C7A,
|
||||||
|
QK_LAYER_LOCK = 0x7C7B,
|
||||||
QK_KB_0 = 0x7E00,
|
QK_KB_0 = 0x7E00,
|
||||||
QK_KB_1 = 0x7E01,
|
QK_KB_1 = 0x7E01,
|
||||||
QK_KB_2 = 0x7E02,
|
QK_KB_2 = 0x7E02,
|
||||||
@ -1445,6 +1446,7 @@ enum qk_keycode_defines {
|
|||||||
TL_UPPR = QK_TRI_LAYER_UPPER,
|
TL_UPPR = QK_TRI_LAYER_UPPER,
|
||||||
QK_REP = QK_REPEAT_KEY,
|
QK_REP = QK_REPEAT_KEY,
|
||||||
QK_AREP = QK_ALT_REPEAT_KEY,
|
QK_AREP = QK_ALT_REPEAT_KEY,
|
||||||
|
QK_LLCK = QK_LAYER_LOCK,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Range Helpers
|
// Range Helpers
|
||||||
@ -1501,7 +1503,7 @@ enum qk_keycode_defines {
|
|||||||
#define IS_UNDERGLOW_KEYCODE(code) ((code) >= QK_UNDERGLOW_TOGGLE && (code) <= QK_UNDERGLOW_SPEED_DOWN)
|
#define IS_UNDERGLOW_KEYCODE(code) ((code) >= QK_UNDERGLOW_TOGGLE && (code) <= QK_UNDERGLOW_SPEED_DOWN)
|
||||||
#define IS_RGB_KEYCODE(code) ((code) >= RGB_MODE_PLAIN && (code) <= RGB_MODE_TWINKLE)
|
#define IS_RGB_KEYCODE(code) ((code) >= RGB_MODE_PLAIN && (code) <= RGB_MODE_TWINKLE)
|
||||||
#define IS_RGB_MATRIX_KEYCODE(code) ((code) >= QK_RGB_MATRIX_ON && (code) <= QK_RGB_MATRIX_SPEED_DOWN)
|
#define IS_RGB_MATRIX_KEYCODE(code) ((code) >= QK_RGB_MATRIX_ON && (code) <= QK_RGB_MATRIX_SPEED_DOWN)
|
||||||
#define IS_QUANTUM_KEYCODE(code) ((code) >= QK_BOOTLOADER && (code) <= QK_ALT_REPEAT_KEY)
|
#define IS_QUANTUM_KEYCODE(code) ((code) >= QK_BOOTLOADER && (code) <= QK_LAYER_LOCK)
|
||||||
#define IS_KB_KEYCODE(code) ((code) >= QK_KB_0 && (code) <= QK_KB_31)
|
#define IS_KB_KEYCODE(code) ((code) >= QK_KB_0 && (code) <= QK_KB_31)
|
||||||
#define IS_USER_KEYCODE(code) ((code) >= QK_USER_0 && (code) <= QK_USER_31)
|
#define IS_USER_KEYCODE(code) ((code) >= QK_USER_0 && (code) <= QK_USER_31)
|
||||||
|
|
||||||
@ -1527,6 +1529,6 @@ enum qk_keycode_defines {
|
|||||||
#define UNDERGLOW_KEYCODE_RANGE QK_UNDERGLOW_TOGGLE ... QK_UNDERGLOW_SPEED_DOWN
|
#define UNDERGLOW_KEYCODE_RANGE QK_UNDERGLOW_TOGGLE ... QK_UNDERGLOW_SPEED_DOWN
|
||||||
#define RGB_KEYCODE_RANGE RGB_MODE_PLAIN ... RGB_MODE_TWINKLE
|
#define RGB_KEYCODE_RANGE RGB_MODE_PLAIN ... RGB_MODE_TWINKLE
|
||||||
#define RGB_MATRIX_KEYCODE_RANGE QK_RGB_MATRIX_ON ... QK_RGB_MATRIX_SPEED_DOWN
|
#define RGB_MATRIX_KEYCODE_RANGE QK_RGB_MATRIX_ON ... QK_RGB_MATRIX_SPEED_DOWN
|
||||||
#define QUANTUM_KEYCODE_RANGE QK_BOOTLOADER ... QK_ALT_REPEAT_KEY
|
#define QUANTUM_KEYCODE_RANGE QK_BOOTLOADER ... QK_LAYER_LOCK
|
||||||
#define KB_KEYCODE_RANGE QK_KB_0 ... QK_KB_31
|
#define KB_KEYCODE_RANGE QK_KB_0 ... QK_KB_31
|
||||||
#define USER_KEYCODE_RANGE QK_USER_0 ... QK_USER_31
|
#define USER_KEYCODE_RANGE QK_USER_0 ... QK_USER_31
|
||||||
|
81
quantum/layer_lock.c
Normal file
81
quantum/layer_lock.c
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
// Copyright 2022-2023 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "layer_lock.h"
|
||||||
|
#include "quantum_keycodes.h"
|
||||||
|
|
||||||
|
#ifndef NO_ACTION_LAYER
|
||||||
|
// The current lock state. The kth bit is on if layer k is locked.
|
||||||
|
layer_state_t locked_layers = 0;
|
||||||
|
|
||||||
|
// Layer Lock timer to disable layer lock after X seconds inactivity
|
||||||
|
# if defined(LAYER_LOCK_IDLE_TIMEOUT) && LAYER_LOCK_IDLE_TIMEOUT > 0
|
||||||
|
uint32_t layer_lock_timer = 0;
|
||||||
|
|
||||||
|
void layer_lock_task(void) {
|
||||||
|
if (locked_layers && timer_elapsed32(layer_lock_timer) > LAYER_LOCK_IDLE_TIMEOUT) {
|
||||||
|
layer_lock_all_off();
|
||||||
|
layer_lock_timer = timer_read32();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# endif // LAYER_LOCK_IDLE_TIMEOUT > 0
|
||||||
|
|
||||||
|
bool is_layer_locked(uint8_t layer) {
|
||||||
|
return locked_layers & ((layer_state_t)1 << layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void layer_lock_invert(uint8_t layer) {
|
||||||
|
const layer_state_t mask = (layer_state_t)1 << layer;
|
||||||
|
if ((locked_layers & mask) == 0) { // Layer is being locked.
|
||||||
|
# ifndef NO_ACTION_ONESHOT
|
||||||
|
if (layer == get_oneshot_layer()) {
|
||||||
|
reset_oneshot_layer(); // Reset so that OSL doesn't turn layer off.
|
||||||
|
}
|
||||||
|
# endif // NO_ACTION_ONESHOT
|
||||||
|
layer_on(layer);
|
||||||
|
# if defined(LAYER_LOCK_IDLE_TIMEOUT) && LAYER_LOCK_IDLE_TIMEOUT > 0
|
||||||
|
layer_lock_timer = timer_read32();
|
||||||
|
# endif // LAYER_LOCK_IDLE_TIMEOUT > 0
|
||||||
|
} else { // Layer is being unlocked.
|
||||||
|
layer_off(layer);
|
||||||
|
}
|
||||||
|
layer_lock_set_kb(locked_layers ^= mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implement layer_lock_on/off by deferring to layer_lock_invert.
|
||||||
|
void layer_lock_on(uint8_t layer) {
|
||||||
|
if (!is_layer_locked(layer)) {
|
||||||
|
layer_lock_invert(layer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void layer_lock_off(uint8_t layer) {
|
||||||
|
if (is_layer_locked(layer)) {
|
||||||
|
layer_lock_invert(layer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void layer_lock_all_off(void) {
|
||||||
|
layer_and(~locked_layers);
|
||||||
|
locked_layers = 0;
|
||||||
|
layer_lock_set_kb(locked_layers);
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((weak)) bool layer_lock_set_kb(layer_state_t locked_layers) {
|
||||||
|
return layer_lock_set_user(locked_layers);
|
||||||
|
}
|
||||||
|
__attribute__((weak)) bool layer_lock_set_user(layer_state_t locked_layers) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif // NO_ACTION_LAYER
|
135
quantum/layer_lock.h
Normal file
135
quantum/layer_lock.h
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
// Copyright 2022-2023 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file layer_lock.h
|
||||||
|
* @brief Layer Lock, a key to stay in the current layer.
|
||||||
|
*
|
||||||
|
* Overview
|
||||||
|
* --------
|
||||||
|
*
|
||||||
|
* Layers are often accessed by holding a button, e.g. with a momentary layer
|
||||||
|
* switch `MO(layer)` or layer tap `LT(layer, key)` key. But you may sometimes
|
||||||
|
* want to "lock" or "toggle" the layer so that it stays on without having to
|
||||||
|
* hold down a button. One way to do that is with a tap-toggle `TT` layer key,
|
||||||
|
* but here is an alternative.
|
||||||
|
*
|
||||||
|
* This library implements a "Layer Lock key". When tapped, it "locks" the
|
||||||
|
* highest layer to stay active, assuming the layer was activated by one of the
|
||||||
|
* following keys:
|
||||||
|
*
|
||||||
|
* * `MO(layer)` momentary layer switch
|
||||||
|
* * `LT(layer, key)` layer tap
|
||||||
|
* * `OSL(layer)` one-shot layer
|
||||||
|
* * `TT(layer)` layer tap toggle
|
||||||
|
* * `LM(layer, mod)` layer-mod key (the layer is locked, but not the mods)
|
||||||
|
*
|
||||||
|
* Tapping the Layer Lock key again unlocks and turns off the layer.
|
||||||
|
*
|
||||||
|
* @note When a layer is "locked", other layer keys such as `TO(layer)` or
|
||||||
|
* manually calling `layer_off(layer)` will override and unlock the layer.
|
||||||
|
*
|
||||||
|
* Configuration
|
||||||
|
* -------------
|
||||||
|
*
|
||||||
|
* Optionally, a timeout may be defined so that Layer Lock disables
|
||||||
|
* automatically if not keys are pressed for `LAYER_LOCK_IDLE_TIMEOUT`
|
||||||
|
* milliseconds. Define `LAYER_LOCK_IDLE_TIMEOUT` in your config.h, for instance
|
||||||
|
*
|
||||||
|
* #define LAYER_LOCK_IDLE_TIMEOUT 60000 // Turn off after 60 seconds.
|
||||||
|
*
|
||||||
|
* and call `layer_lock_task()` from your `matrix_scan_user()` in keymap.c:
|
||||||
|
*
|
||||||
|
* void matrix_scan_user(void) {
|
||||||
|
* layer_lock_task();
|
||||||
|
* // Other tasks...
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* For full documentation, see
|
||||||
|
* <https://getreuer.info/posts/keyboards/layer-lock>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "action_layer.h"
|
||||||
|
#include "action_util.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler function for Layer Lock.
|
||||||
|
*
|
||||||
|
* In your keymap, define a custom keycode to use for Layer Lock. Then handle
|
||||||
|
* Layer Lock from your `process_record_user` function by calling
|
||||||
|
* `process_layer_lock`, passing your custom keycode for the `lock_keycode` arg:
|
||||||
|
*
|
||||||
|
* #include "features/layer_lock.h"
|
||||||
|
*
|
||||||
|
* bool process_record_user(uint16_t keycode, keyrecord_t* record) {
|
||||||
|
* if (!process_layer_lock(keycode, record, LLOCK)) { return false; }
|
||||||
|
* // Your macros ...
|
||||||
|
*
|
||||||
|
* return true;
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef NO_ACTION_LAYER
|
||||||
|
/** Returns true if `layer` is currently locked. */
|
||||||
|
bool is_layer_locked(uint8_t layer);
|
||||||
|
|
||||||
|
/** Locks and turns on `layer`. */
|
||||||
|
void layer_lock_on(uint8_t layer);
|
||||||
|
|
||||||
|
/** Unlocks and turns off `layer`. */
|
||||||
|
void layer_lock_off(uint8_t layer);
|
||||||
|
|
||||||
|
/** Unlocks and turns off all locked layers. */
|
||||||
|
void layer_lock_all_off(void);
|
||||||
|
|
||||||
|
/** Toggles whether `layer` is locked. */
|
||||||
|
void layer_lock_invert(uint8_t layer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional callback that gets called when a layer is locked or unlocked.
|
||||||
|
*
|
||||||
|
* This is useful to represent the current lock state, e.g. by setting an LED or
|
||||||
|
* playing a sound. In your keymap, define
|
||||||
|
*
|
||||||
|
* void layer_lock_set_user(layer_state_t locked_layers) {
|
||||||
|
* // Do something like `set_led(is_layer_locked(NAV));`
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @param locked_layers Bitfield in which the kth bit represents whether the
|
||||||
|
* kth layer is on.
|
||||||
|
*/
|
||||||
|
bool layer_lock_set_kb(layer_state_t locked_layers);
|
||||||
|
bool layer_lock_set_user(layer_state_t locked_layers);
|
||||||
|
|
||||||
|
void layer_lock_task(void);
|
||||||
|
#else // NO_ACTION_LAYER
|
||||||
|
static inline bool is_layer_locked(uint8_t layer) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static inline void layer_lock_on(uint8_t layer) {}
|
||||||
|
static inline void layer_lock_off(uint8_t layer) {}
|
||||||
|
static inline void layer_lock_all_off(void) {}
|
||||||
|
static inline void layer_lock_invert(uint8_t layer) {}
|
||||||
|
static inline bool layer_lock_set_kb(layer_state_t locked_layers) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
static inline bool layer_lock_set_user(layer_state_t locked_layers) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
static inline void layer_lock_task(void) {}
|
||||||
|
#endif // NO_ACTION_LAYER
|
95
quantum/process_keycode/process_layer_lock.c
Normal file
95
quantum/process_keycode/process_layer_lock.c
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
// Copyright 2022-2023 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file layer_lock.c
|
||||||
|
* @brief Layer Lock implementation
|
||||||
|
*
|
||||||
|
* For full documentation, see
|
||||||
|
* <https://getreuer.info/posts/keyboards/layer-lock>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "layer_lock.h"
|
||||||
|
#include "process_layer_lock.h"
|
||||||
|
#include "quantum_keycodes.h"
|
||||||
|
#include "action_util.h"
|
||||||
|
|
||||||
|
// The current lock state. The kth bit is on if layer k is locked.
|
||||||
|
extern layer_state_t locked_layers;
|
||||||
|
#if defined(LAYER_LOCK_IDLE_TIMEOUT) && LAYER_LOCK_IDLE_TIMEOUT > 0
|
||||||
|
extern uint32_t layer_lock_timer;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Handles an event on an `MO` or `TT` layer switch key.
|
||||||
|
static bool handle_mo_or_tt(uint8_t layer, keyrecord_t* record) {
|
||||||
|
if (is_layer_locked(layer)) {
|
||||||
|
if (record->event.pressed) { // On press, unlock the layer.
|
||||||
|
layer_lock_invert(layer);
|
||||||
|
}
|
||||||
|
return false; // Skip default handling.
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool process_layer_lock(uint16_t keycode, keyrecord_t* record) {
|
||||||
|
#ifndef NO_ACTION_LAYER
|
||||||
|
# if defined(LAYER_LOCK_IDLE_TIMEOUT) && LAYER_LOCK_IDLE_TIMEOUT > 0
|
||||||
|
layer_lock_timer = timer_read32();
|
||||||
|
# endif // LAYER_LOCK_IDLE_TIMEOUT > 0
|
||||||
|
|
||||||
|
// The intention is that locked layers remain on. If something outside of
|
||||||
|
// this feature turned any locked layers off, unlock them.
|
||||||
|
if ((locked_layers & ~layer_state) != 0) {
|
||||||
|
layer_lock_set_kb(locked_layers &= layer_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keycode == QK_LAYER_LOCK) {
|
||||||
|
if (record->event.pressed) { // The layer lock key was pressed.
|
||||||
|
layer_lock_invert(get_highest_layer(layer_state));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (keycode) {
|
||||||
|
case QK_MOMENTARY ... QK_MOMENTARY_MAX: // `MO(layer)` keys.
|
||||||
|
return handle_mo_or_tt(QK_MOMENTARY_GET_LAYER(keycode), record);
|
||||||
|
|
||||||
|
case QK_LAYER_TAP_TOGGLE ... QK_LAYER_TAP_TOGGLE_MAX: // `TT(layer)`.
|
||||||
|
return handle_mo_or_tt(QK_LAYER_TAP_TOGGLE_GET_LAYER(keycode), record);
|
||||||
|
|
||||||
|
case QK_LAYER_MOD ... QK_LAYER_MOD_MAX: { // `LM(layer, mod)`.
|
||||||
|
uint8_t layer = QK_LAYER_MOD_GET_LAYER(keycode);
|
||||||
|
if (is_layer_locked(layer)) {
|
||||||
|
if (record->event.pressed) { // On press, unlock the layer.
|
||||||
|
layer_lock_invert(layer);
|
||||||
|
} else { // On release, clear the mods.
|
||||||
|
clear_mods();
|
||||||
|
send_keyboard_report();
|
||||||
|
}
|
||||||
|
return false; // Skip default handling.
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
# ifndef NO_ACTION_TAPPING
|
||||||
|
case QK_LAYER_TAP ... QK_LAYER_TAP_MAX: // `LT(layer, key)` keys.
|
||||||
|
if (record->tap.count == 0 && !record->event.pressed && is_layer_locked(QK_LAYER_TAP_GET_LAYER(keycode))) {
|
||||||
|
// Release event on a held layer-tap key where the layer is locked.
|
||||||
|
return false; // Skip default handling so that layer stays on.
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
# endif // NO_ACTION_TAPPING
|
||||||
|
}
|
||||||
|
#endif // NO_ACTION_LAYER
|
||||||
|
return true;
|
||||||
|
}
|
69
quantum/process_keycode/process_layer_lock.h
Normal file
69
quantum/process_keycode/process_layer_lock.h
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
// Copyright 2022-2023 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file layer_lock.h
|
||||||
|
* @brief Layer Lock, a key to stay in the current layer.
|
||||||
|
*
|
||||||
|
* Overview
|
||||||
|
* --------
|
||||||
|
*
|
||||||
|
* Layers are often accessed by holding a button, e.g. with a momentary layer
|
||||||
|
* switch `MO(layer)` or layer tap `LT(layer, key)` key. But you may sometimes
|
||||||
|
* want to "lock" or "toggle" the layer so that it stays on without having to
|
||||||
|
* hold down a button. One way to do that is with a tap-toggle `TT` layer key,
|
||||||
|
* but here is an alternative.
|
||||||
|
*
|
||||||
|
* This library implements a "Layer Lock key". When tapped, it "locks" the
|
||||||
|
* highest layer to stay active, assuming the layer was activated by one of the
|
||||||
|
* following keys:
|
||||||
|
*
|
||||||
|
* * `MO(layer)` momentary layer switch
|
||||||
|
* * `LT(layer, key)` layer tap
|
||||||
|
* * `OSL(layer)` one-shot layer
|
||||||
|
* * `TT(layer)` layer tap toggle
|
||||||
|
* * `LM(layer, mod)` layer-mod key (the layer is locked, but not the mods)
|
||||||
|
*
|
||||||
|
* Tapping the Layer Lock key again unlocks and turns off the layer.
|
||||||
|
*
|
||||||
|
* @note When a layer is "locked", other layer keys such as `TO(layer)` or
|
||||||
|
* manually calling `layer_off(layer)` will override and unlock the layer.
|
||||||
|
*
|
||||||
|
* Configuration
|
||||||
|
* -------------
|
||||||
|
*
|
||||||
|
* Optionally, a timeout may be defined so that Layer Lock disables
|
||||||
|
* automatically if not keys are pressed for `LAYER_LOCK_IDLE_TIMEOUT`
|
||||||
|
* milliseconds. Define `LAYER_LOCK_IDLE_TIMEOUT` in your config.h, for instance
|
||||||
|
*
|
||||||
|
* #define LAYER_LOCK_IDLE_TIMEOUT 60000 // Turn off after 60 seconds.
|
||||||
|
*
|
||||||
|
* and call `layer_lock_task()` from your `matrix_scan_user()` in keymap.c:
|
||||||
|
*
|
||||||
|
* void matrix_scan_user(void) {
|
||||||
|
* layer_lock_task();
|
||||||
|
* // Other tasks...
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* For full documentation, see
|
||||||
|
* <https://getreuer.info/posts/keyboards/layer-lock>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "action.h"
|
||||||
|
|
||||||
|
bool process_layer_lock(uint16_t keycode, keyrecord_t* record);
|
@ -76,6 +76,10 @@
|
|||||||
# include "process_unicode_common.h"
|
# include "process_unicode_common.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef LAYER_LOCK_ENABLE
|
||||||
|
# include "process_layer_lock.h"
|
||||||
|
#endif // LAYER_LOCK_ENABLE
|
||||||
|
|
||||||
#ifdef AUDIO_ENABLE
|
#ifdef AUDIO_ENABLE
|
||||||
# ifndef GOODBYE_SONG
|
# ifndef GOODBYE_SONG
|
||||||
# define GOODBYE_SONG SONG(GOODBYE_SOUND)
|
# define GOODBYE_SONG SONG(GOODBYE_SOUND)
|
||||||
@ -400,6 +404,9 @@ bool process_record_quantum(keyrecord_t *record) {
|
|||||||
#ifdef TRI_LAYER_ENABLE
|
#ifdef TRI_LAYER_ENABLE
|
||||||
process_tri_layer(keycode, record) &&
|
process_tri_layer(keycode, record) &&
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef LAYER_LOCK_ENABLE
|
||||||
|
process_layer_lock(keycode, record) &&
|
||||||
|
#endif
|
||||||
#ifdef BLUETOOTH_ENABLE
|
#ifdef BLUETOOTH_ENABLE
|
||||||
process_connection(keycode, record) &&
|
process_connection(keycode, record) &&
|
||||||
#endif
|
#endif
|
||||||
|
@ -244,6 +244,10 @@ extern layer_state_t layer_state;
|
|||||||
# include "os_detection.h"
|
# include "os_detection.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef LAYER_LOCK_ENABLE
|
||||||
|
# include "layer_lock.h"
|
||||||
|
#endif // LAYER_LOCK_ENABLE
|
||||||
|
|
||||||
void set_single_default_layer(uint8_t default_layer);
|
void set_single_default_layer(uint8_t default_layer);
|
||||||
void set_single_persistent_default_layer(uint8_t default_layer);
|
void set_single_persistent_default_layer(uint8_t default_layer);
|
||||||
|
|
||||||
|
8
tests/layer_lock/config.h
Normal file
8
tests/layer_lock/config.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// Copyright 2021 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "test_common.h"
|
||||||
|
|
||||||
|
#define LAYER_LOCK_IDLE_TIMEOUT 1000
|
8
tests/layer_lock/test.mk
Normal file
8
tests/layer_lock/test.mk
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# Copyright 2021 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------------
|
||||||
|
# Keep this file, even if it is empty, as a marker that this folder contains tests
|
||||||
|
# --------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
LAYER_LOCK_ENABLE = yes
|
284
tests/layer_lock/test_layer_lock.cpp
Normal file
284
tests/layer_lock/test_layer_lock.cpp
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
// Copyright 2021 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "keycodes.h"
|
||||||
|
#include "test_common.hpp"
|
||||||
|
|
||||||
|
using testing::_;
|
||||||
|
|
||||||
|
class LayerLock : public TestFixture {};
|
||||||
|
|
||||||
|
TEST_F(LayerLock, LayerLockState) {
|
||||||
|
TestDriver driver;
|
||||||
|
KeymapKey key_a = KeymapKey(0, 0, 0, KC_A);
|
||||||
|
KeymapKey key_b = KeymapKey(1, 0, 0, KC_B);
|
||||||
|
KeymapKey key_c = KeymapKey(2, 0, 0, KC_C);
|
||||||
|
KeymapKey key_d = KeymapKey(3, 0, 0, KC_C);
|
||||||
|
|
||||||
|
set_keymap({key_a, key_b, key_c, key_d});
|
||||||
|
|
||||||
|
EXPECT_FALSE(is_layer_locked(1));
|
||||||
|
EXPECT_FALSE(is_layer_locked(2));
|
||||||
|
EXPECT_FALSE(is_layer_locked(3));
|
||||||
|
|
||||||
|
layer_lock_invert(1); // Layer 1: unlocked -> locked
|
||||||
|
layer_lock_on(2); // Layer 2: unlocked -> locked
|
||||||
|
layer_lock_off(3); // Layer 3: stays unlocked
|
||||||
|
|
||||||
|
// Layers 1 and 2 are now on.
|
||||||
|
EXPECT_TRUE(layer_state_is(1));
|
||||||
|
EXPECT_TRUE(layer_state_is(2));
|
||||||
|
// Layers 1 and 2 are now locked.
|
||||||
|
EXPECT_TRUE(is_layer_locked(1));
|
||||||
|
EXPECT_TRUE(is_layer_locked(2));
|
||||||
|
EXPECT_FALSE(is_layer_locked(3));
|
||||||
|
|
||||||
|
layer_lock_invert(1); // Layer 1: locked -> unlocked
|
||||||
|
layer_lock_on(2); // Layer 2: stays locked
|
||||||
|
layer_lock_on(3); // Layer 3: unlocked -> locked
|
||||||
|
|
||||||
|
EXPECT_FALSE(layer_state_is(1));
|
||||||
|
EXPECT_TRUE(layer_state_is(2));
|
||||||
|
EXPECT_TRUE(layer_state_is(3));
|
||||||
|
EXPECT_FALSE(is_layer_locked(1));
|
||||||
|
EXPECT_TRUE(is_layer_locked(2));
|
||||||
|
EXPECT_TRUE(is_layer_locked(3));
|
||||||
|
|
||||||
|
layer_lock_invert(1); // Layer 1: unlocked -> locked
|
||||||
|
layer_lock_off(2); // Layer 2: locked -> unlocked
|
||||||
|
|
||||||
|
EXPECT_TRUE(layer_state_is(1));
|
||||||
|
EXPECT_FALSE(layer_state_is(2));
|
||||||
|
EXPECT_TRUE(layer_state_is(3));
|
||||||
|
EXPECT_TRUE(is_layer_locked(1));
|
||||||
|
EXPECT_FALSE(is_layer_locked(2));
|
||||||
|
EXPECT_TRUE(is_layer_locked(3));
|
||||||
|
|
||||||
|
layer_lock_all_off(); // Layers 1 and 3: locked -> unlocked
|
||||||
|
|
||||||
|
EXPECT_FALSE(layer_state_is(1));
|
||||||
|
EXPECT_FALSE(layer_state_is(2));
|
||||||
|
EXPECT_FALSE(layer_state_is(3));
|
||||||
|
EXPECT_FALSE(is_layer_locked(1));
|
||||||
|
EXPECT_FALSE(is_layer_locked(2));
|
||||||
|
EXPECT_FALSE(is_layer_locked(3));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(LayerLock, LayerLockMomentaryTest) {
|
||||||
|
TestDriver driver;
|
||||||
|
KeymapKey key_layer = KeymapKey(0, 0, 0, MO(1));
|
||||||
|
KeymapKey key_a = KeymapKey(0, 1, 0, KC_A);
|
||||||
|
KeymapKey key_trns = KeymapKey(1, 0, 0, KC_TRNS);
|
||||||
|
KeymapKey key_ll = KeymapKey(1, 1, 0, QK_LAYER_LOCK);
|
||||||
|
|
||||||
|
set_keymap({key_layer, key_a, key_trns, key_ll});
|
||||||
|
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
key_layer.press();
|
||||||
|
run_one_scan_loop();
|
||||||
|
EXPECT_TRUE(layer_state_is(1));
|
||||||
|
EXPECT_FALSE(is_layer_locked(1));
|
||||||
|
VERIFY_AND_CLEAR(driver);
|
||||||
|
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
tap_key(key_ll);
|
||||||
|
EXPECT_TRUE(layer_state_is(1));
|
||||||
|
EXPECT_TRUE(is_layer_locked(1));
|
||||||
|
VERIFY_AND_CLEAR(driver);
|
||||||
|
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
key_layer.release();
|
||||||
|
run_one_scan_loop();
|
||||||
|
EXPECT_TRUE(layer_state_is(1));
|
||||||
|
EXPECT_TRUE(is_layer_locked(1));
|
||||||
|
VERIFY_AND_CLEAR(driver);
|
||||||
|
|
||||||
|
// Pressing Layer Lock again unlocks the lock.
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
key_ll.press();
|
||||||
|
run_one_scan_loop();
|
||||||
|
EXPECT_FALSE(layer_state_is(1));
|
||||||
|
EXPECT_FALSE(is_layer_locked(1));
|
||||||
|
VERIFY_AND_CLEAR(driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(LayerLock, LayerLockLayerTapTest) {
|
||||||
|
TestDriver driver;
|
||||||
|
KeymapKey key_layer = KeymapKey(0, 0, 0, LT(1, KC_B));
|
||||||
|
KeymapKey key_a = KeymapKey(0, 1, 0, KC_A);
|
||||||
|
KeymapKey key_trns = KeymapKey(1, 0, 0, KC_TRNS);
|
||||||
|
KeymapKey key_ll = KeymapKey(1, 1, 0, QK_LAYER_LOCK);
|
||||||
|
|
||||||
|
set_keymap({key_layer, key_a, key_trns, key_ll});
|
||||||
|
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
key_layer.press();
|
||||||
|
idle_for(TAPPING_TERM);
|
||||||
|
run_one_scan_loop();
|
||||||
|
EXPECT_TRUE(layer_state_is(1));
|
||||||
|
VERIFY_AND_CLEAR(driver);
|
||||||
|
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
tap_key(key_ll);
|
||||||
|
EXPECT_TRUE(layer_state_is(1));
|
||||||
|
EXPECT_TRUE(is_layer_locked(1));
|
||||||
|
VERIFY_AND_CLEAR(driver);
|
||||||
|
|
||||||
|
// Pressing Layer Lock again unlocks the lock.
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
key_ll.press();
|
||||||
|
run_one_scan_loop();
|
||||||
|
EXPECT_FALSE(layer_state_is(1));
|
||||||
|
EXPECT_FALSE(is_layer_locked(1));
|
||||||
|
VERIFY_AND_CLEAR(driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(LayerLock, LayerLockOneshotTapTest) {
|
||||||
|
TestDriver driver;
|
||||||
|
KeymapKey key_layer = KeymapKey(0, 0, 0, OSL(1));
|
||||||
|
KeymapKey key_a = KeymapKey(0, 1, 0, KC_A);
|
||||||
|
KeymapKey key_trns = KeymapKey(1, 0, 0, KC_TRNS);
|
||||||
|
KeymapKey key_ll = KeymapKey(1, 1, 0, QK_LAYER_LOCK);
|
||||||
|
|
||||||
|
set_keymap({key_layer, key_a, key_trns, key_ll});
|
||||||
|
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
tap_key(key_layer);
|
||||||
|
run_one_scan_loop();
|
||||||
|
EXPECT_TRUE(layer_state_is(1));
|
||||||
|
VERIFY_AND_CLEAR(driver);
|
||||||
|
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
tap_key(key_ll);
|
||||||
|
run_one_scan_loop();
|
||||||
|
EXPECT_TRUE(layer_state_is(1));
|
||||||
|
EXPECT_TRUE(is_layer_locked(1));
|
||||||
|
VERIFY_AND_CLEAR(driver);
|
||||||
|
|
||||||
|
// Pressing Layer Lock again unlocks the lock.
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
key_ll.press();
|
||||||
|
run_one_scan_loop();
|
||||||
|
EXPECT_FALSE(layer_state_is(1));
|
||||||
|
EXPECT_FALSE(is_layer_locked(1));
|
||||||
|
VERIFY_AND_CLEAR(driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(LayerLock, LayerLockOneshotHoldTest) {
|
||||||
|
TestDriver driver;
|
||||||
|
KeymapKey key_layer = KeymapKey(0, 0, 0, OSL(1));
|
||||||
|
KeymapKey key_a = KeymapKey(0, 1, 0, KC_A);
|
||||||
|
KeymapKey key_trns = KeymapKey(1, 0, 0, KC_TRNS);
|
||||||
|
KeymapKey key_ll = KeymapKey(1, 1, 0, QK_LAYER_LOCK);
|
||||||
|
|
||||||
|
set_keymap({key_layer, key_a, key_trns, key_ll});
|
||||||
|
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
key_layer.press();
|
||||||
|
idle_for(TAPPING_TERM);
|
||||||
|
run_one_scan_loop();
|
||||||
|
EXPECT_TRUE(layer_state_is(1));
|
||||||
|
VERIFY_AND_CLEAR(driver);
|
||||||
|
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
tap_key(key_ll);
|
||||||
|
run_one_scan_loop();
|
||||||
|
EXPECT_TRUE(layer_state_is(1));
|
||||||
|
VERIFY_AND_CLEAR(driver);
|
||||||
|
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
key_layer.release();
|
||||||
|
run_one_scan_loop();
|
||||||
|
EXPECT_TRUE(layer_state_is(1));
|
||||||
|
EXPECT_TRUE(is_layer_locked(1));
|
||||||
|
VERIFY_AND_CLEAR(driver);
|
||||||
|
|
||||||
|
// Pressing Layer Lock again unlocks the lock.
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
key_ll.press();
|
||||||
|
run_one_scan_loop();
|
||||||
|
EXPECT_FALSE(layer_state_is(1));
|
||||||
|
EXPECT_FALSE(is_layer_locked(1));
|
||||||
|
VERIFY_AND_CLEAR(driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(LayerLock, LayerLockTimeoutTest) {
|
||||||
|
TestDriver driver;
|
||||||
|
KeymapKey key_layer = KeymapKey(0, 0, 0, MO(1));
|
||||||
|
KeymapKey key_a = KeymapKey(0, 1, 0, KC_A);
|
||||||
|
KeymapKey key_trns = KeymapKey(1, 0, 0, KC_TRNS);
|
||||||
|
KeymapKey key_ll = KeymapKey(1, 1, 0, QK_LAYER_LOCK);
|
||||||
|
|
||||||
|
set_keymap({key_layer, key_a, key_trns, key_ll});
|
||||||
|
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
key_layer.press();
|
||||||
|
run_one_scan_loop();
|
||||||
|
EXPECT_TRUE(layer_state_is(1));
|
||||||
|
VERIFY_AND_CLEAR(driver);
|
||||||
|
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
tap_key(key_ll);
|
||||||
|
EXPECT_TRUE(layer_state_is(1));
|
||||||
|
VERIFY_AND_CLEAR(driver);
|
||||||
|
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
key_layer.release();
|
||||||
|
run_one_scan_loop();
|
||||||
|
EXPECT_TRUE(layer_state_is(1));
|
||||||
|
EXPECT_TRUE(is_layer_locked(1));
|
||||||
|
VERIFY_AND_CLEAR(driver);
|
||||||
|
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
idle_for(LAYER_LOCK_IDLE_TIMEOUT);
|
||||||
|
run_one_scan_loop();
|
||||||
|
EXPECT_FALSE(layer_state_is(1));
|
||||||
|
EXPECT_FALSE(is_layer_locked(1));
|
||||||
|
VERIFY_AND_CLEAR(driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(LayerLock, ToKeyOverridesLayerLock) {
|
||||||
|
TestDriver driver;
|
||||||
|
KeymapKey key_layer = KeymapKey(0, 0, 0, MO(1));
|
||||||
|
KeymapKey key_to0 = KeymapKey(1, 0, 0, TO(0));
|
||||||
|
KeymapKey key_ll = KeymapKey(1, 1, 0, QK_LAYER_LOCK);
|
||||||
|
|
||||||
|
set_keymap({key_layer, key_to0, key_ll});
|
||||||
|
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
layer_lock_on(1);
|
||||||
|
run_one_scan_loop();
|
||||||
|
EXPECT_TRUE(layer_state_is(1));
|
||||||
|
EXPECT_TRUE(is_layer_locked(1));
|
||||||
|
VERIFY_AND_CLEAR(driver);
|
||||||
|
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
tap_key(key_to0); // TO(0) overrides Layer Lock and unlocks layer 1.
|
||||||
|
EXPECT_FALSE(layer_state_is(1));
|
||||||
|
EXPECT_FALSE(is_layer_locked(1));
|
||||||
|
VERIFY_AND_CLEAR(driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(LayerLock, LayerClearOverridesLayerLock) {
|
||||||
|
TestDriver driver;
|
||||||
|
KeymapKey key_layer = KeymapKey(0, 0, 0, MO(1));
|
||||||
|
KeymapKey key_a = KeymapKey(0, 1, 0, KC_A);
|
||||||
|
KeymapKey key_ll = KeymapKey(1, 1, 0, QK_LAYER_LOCK);
|
||||||
|
|
||||||
|
set_keymap({key_layer, key_a, key_ll});
|
||||||
|
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
layer_lock_on(1);
|
||||||
|
run_one_scan_loop();
|
||||||
|
EXPECT_TRUE(layer_state_is(1));
|
||||||
|
EXPECT_TRUE(is_layer_locked(1));
|
||||||
|
VERIFY_AND_CLEAR(driver);
|
||||||
|
|
||||||
|
EXPECT_REPORT(driver, (KC_A));
|
||||||
|
layer_clear(); // layer_clear() overrides Layer Lock and unlocks layer 1.
|
||||||
|
key_a.press();
|
||||||
|
run_one_scan_loop();
|
||||||
|
EXPECT_FALSE(layer_state_is(1));
|
||||||
|
EXPECT_FALSE(is_layer_locked(1));
|
||||||
|
VERIFY_AND_CLEAR(driver);
|
||||||
|
}
|
@ -699,6 +699,7 @@ std::map<uint16_t, std::string> KEYCODE_ID_TABLE = {
|
|||||||
{QK_TRI_LAYER_UPPER, "QK_TRI_LAYER_UPPER"},
|
{QK_TRI_LAYER_UPPER, "QK_TRI_LAYER_UPPER"},
|
||||||
{QK_REPEAT_KEY, "QK_REPEAT_KEY"},
|
{QK_REPEAT_KEY, "QK_REPEAT_KEY"},
|
||||||
{QK_ALT_REPEAT_KEY, "QK_ALT_REPEAT_KEY"},
|
{QK_ALT_REPEAT_KEY, "QK_ALT_REPEAT_KEY"},
|
||||||
|
{QK_LAYER_LOCK, "QK_LAYER_LOCK"},
|
||||||
{QK_KB_0, "QK_KB_0"},
|
{QK_KB_0, "QK_KB_0"},
|
||||||
{QK_KB_1, "QK_KB_1"},
|
{QK_KB_1, "QK_KB_1"},
|
||||||
{QK_KB_2, "QK_KB_2"},
|
{QK_KB_2, "QK_KB_2"},
|
||||||
|
Loading…
Reference in New Issue
Block a user