Added MCU support for ArteryTek AT32F415 (#23445)

This commit is contained in:
HorrorTroll 2024-11-21 13:28:28 +07:00 committed by GitHub
parent 074bbbfb21
commit 39161b9ee7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
32 changed files with 1065 additions and 63 deletions

View File

@ -215,7 +215,7 @@ else
COMMON_VPATH += $(PLATFORM_PATH)/$(PLATFORM_KEY)/$(DRIVER_DIR)/flash
COMMON_VPATH += $(DRIVER_PATH)/flash
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
OPT_DEFS += -DEEPROM_DRIVER -DEEPROM_WEAR_LEVELING
SRC += eeprom_driver.c eeprom_wear_leveling.c

View File

@ -92,6 +92,7 @@
"GD32VF103",
"WB32F3G71",
"WB32FQ95",
"AT32F415",
"atmega16u2",
"atmega32u2",
"atmega16u4",
@ -216,6 +217,7 @@
"type": "string",
"enum": [
"apm32-dfu",
"at32-dfu",
"atmel-dfu",
"bootloadhid",
"caterina",

View File

@ -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)
* [WB32FQ95xx](http://www.westberrytech.com)
### Artery (AT32)
* [AT32F415](https://www.arterychip.com/en/product/AT32F415.jsp)
### 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)

View File

@ -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 |
|`usbasploader`|USBasp |`16C0:05DC` |libusbK|
|`apm32-dfu` |APM32 DFU ISP Mode |`314B:0106` |WinUSB |
|`at32-dfu` |AT32 Bootloader DFU |`2E3C:DF11` |WinUSB |
|`stm32-dfu` |STM32 BOOTLOADER |`0483:DF11` |WinUSB |
|`gd32v-dfu` |GD32V BOOTLOADER |`28E9:0189` |WinUSB |
|`kiibohd` |Kiibohd DFU Bootloader |`1C11:B007` |WinUSB |

View File

@ -345,6 +345,39 @@ Flashing sequence:
3. Flash a .bin file
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
Keyboards may opt into supporting the tinyuf2 bootloader. This is currently only supported on F303/F401/F411.

View 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

View 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

View 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>

View 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"
}
}

View 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

View File

@ -0,0 +1,3 @@
# Artery AT-START-F415 Board Onekey
To trigger keypress, short together pins *B3* and *B4*.

View File

@ -22,7 +22,7 @@ QMK_FIRMWARE_UPSTREAM = 'qmk/qmk_firmware'
MAX_KEYBOARD_SUBFOLDERS = 5
# 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
VUSB_PROCESSORS = 'atmega32a', 'atmega328p', 'atmega328', 'attiny85'
@ -55,6 +55,7 @@ MCU2BOOTLOADER = {
"GD32VF103": "gd32v-dfu",
"WB32F3G71": "wb32-dfu",
"WB32FQ95": "wb32-dfu",
"AT32F415": "at32-dfu",
"atmega16u2": "atmel-dfu",
"atmega32u2": "atmel-dfu",
"atmega16u4": "atmel-dfu",
@ -93,6 +94,7 @@ BOOTLOADER_VIDS_PIDS = {
'apm32-dfu': {("314b", "0106")},
'gd32v-dfu': {("28e9", "0189")},
'wb32-dfu': {("342d", "dfa0")},
'at32-dfu': {("2e3c", "df11")},
'bootloadhid': {("16c0", "05df")},
'usbasploader': {("16c0", "05dc")},
'usbtinyisp': {("1782", "0c9f")},

View 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;
}

View 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_ */

View File

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

View 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 BOARD_OTG_VBUSIG
#define USB_ENDPOINTS_ARE_REORDERABLE
#ifndef EARLY_INIT_PERFORM_BOOTLOADER_JUMP
# define EARLY_INIT_PERFORM_BOOTLOADER_JUMP TRUE
#endif

View 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 */

View File

@ -26,6 +26,7 @@
# stm32-dfu STM32 USB DFU in ROM
# apm32-dfu APM32 USB DFU in ROM
# wb32-dfu WB32 USB DFU in ROM
# at32-dfu AT32 USB DFU in ROM
# tinyuf2 TinyUF2
# rp2040 Raspberry Pi RP2040
# Current options for RISC-V:
@ -119,6 +120,14 @@ ifeq ($(strip $(BOOTLOADER)), wb32-dfu)
OPT_DEFS += -DBOOTLOADER_WB32_DFU
BOOTLOADER_TYPE = wb32_dfu
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)),)
ifneq ($(strip $(BOOTLOADER)),)

View 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) {
}
}
}

View File

@ -142,6 +142,19 @@
# 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)
/* 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

View File

@ -22,7 +22,7 @@
# error "You need to set HAL_USE_ADC to TRUE in your halconf.h to use the ADC."
#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."
#endif
@ -45,7 +45,7 @@
// Otherwise assume V3
#if defined(STM32F0XX) || defined(STM32L0XX)
# 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
#endif
@ -82,7 +82,7 @@
/* User configurable ADC options */
#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
# elif defined(STM32F3XX) || defined(STM32G4XX)
# define ADC_COUNT 4
@ -142,11 +142,16 @@ static ADCConversionGroup adcConversionGroup = {
.cfgr1 = ADC_CFGR1_CONT | ADC_RESOLUTION,
.smpr = ADC_SAMPLING_RATE,
#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...
# 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),
.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)
// RP2040 does not have any extra config here
#else
@ -242,7 +247,7 @@ __attribute__((weak)) adc_mux pinToMux(pin_t pin) {
case F9: return TO_MUX( ADC_CHANNEL_IN7, 2 );
case F10: return TO_MUX( ADC_CHANNEL_IN8, 2 );
# 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 A1: return TO_MUX( ADC_CHANNEL_IN1, 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) {
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:
return &ADCD1;
#endif
@ -391,7 +396,11 @@ int16_t adc_read(adc_mux mux) {
// TODO: fix previous assumption of only 1 input...
adcConversionGroup.chselr = 1 << mux.input; /*no macro to convert N to ADC_CHSELR_CHSEL1*/
#elif defined(USE_ADCV2)
# if defined(AT32F415)
adcConversionGroup.osq3 = ADC_OSQ3_OSN1_N(mux.input);
# else
adcConversionGroup.sqr3 = ADC_SQR3_SQ1_N(mux.input);
# endif
#elif defined(RP2040)
adcConversionGroup.channel_mask = 1 << mux.input;
#else

View File

@ -9,6 +9,17 @@
#if defined(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 */
static QMKSerialConfig serial_config = {
# 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.
*/
__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)
palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE_OPENDRAIN);
# else
@ -183,7 +194,7 @@ __attribute__((weak)) void usart_init(void) {
* @brief Initiate pins for USART peripheral. Full-duplex configuration.
*/
__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)
palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE_PUSHPULL);
palSetLineMode(SERIAL_USART_RX_PIN, PAL_MODE_INPUT);

View File

@ -74,40 +74,75 @@ typedef SIOConfig QMKSerialConfig;
# endif
#endif
#if !defined(USART_CR1_M0)
#if defined(MCU_STM32) /* STM32 MCUs */
# if !defined(USART_CR1_M0)
# define USART_CR1_M0 USART_CR1_M // some platforms (f1xx) dont have this so
#endif
# 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
#endif
# endif
#if !defined(SERIAL_USART_CR2)
# if !defined(SERIAL_USART_CR2)
# 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
#endif
# endif
#if defined(USART1_REMAP)
# if defined(USART1_REMAP)
# define USART_REMAP \
do { \
(AFIO->MAPR |= AFIO_MAPR_USART1_REMAP); \
} while (0)
#elif defined(USART2_REMAP)
# elif defined(USART2_REMAP)
# define USART_REMAP \
do { \
(AFIO->MAPR |= AFIO_MAPR_USART2_REMAP); \
} while (0)
#elif defined(USART3_PARTIALREMAP)
# elif defined(USART3_PARTIALREMAP)
# define USART_REMAP \
do { \
(AFIO->MAPR |= AFIO_MAPR_USART3_REMAP_PARTIALREMAP); \
} while (0)
#elif defined(USART3_FULLREMAP)
# elif defined(USART3_FULLREMAP)
# define USART_REMAP \
do { \
(AFIO->MAPR |= AFIO_MAPR_USART3_REMAP_FULLREMAP); \
} 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

View File

@ -103,9 +103,15 @@ bool spi_start_extended(spi_start_config_t *start_config) {
roundedDivisor <<= 1;
}
# if defined(AT32F415)
if (roundedDivisor < 2 || roundedDivisor > 1024) {
return false;
}
# else
if (roundedDivisor < 2 || roundedDivisor > 256) {
return false;
}
# endif
#endif
#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
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
spiConfig.cr1 = 0;

View File

@ -33,7 +33,7 @@ static inline uint32_t detect_flash_size(void) {
#elif defined(FLASH_SIZE)
return FLASH_SIZE;
#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
# 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?

View File

@ -16,6 +16,8 @@
# define BACKING_STORE_WRITE_SIZE 4 // from hal_efl_lld.c
# elif defined(QMK_MCU_FAMILY_WB32)
# 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)
# if defined(STM32_FLASH_LINE_SIZE) // from some family's stm32_registry.h file
# define BACKING_STORE_WRITE_SIZE (STM32_FLASH_LINE_SIZE)

View File

@ -11,7 +11,7 @@
/* Adapted from https://github.com/bigjosh/SimpleNeoPixelDemo/ */
#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
# else
# if defined(RP2040)

View File

@ -40,6 +40,9 @@
#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"
#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
* 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
typedef uint16_t ws2812_buffer_t;
# 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
# define WS2812_PWM_DMA_MEMORY_WIDTH STM32_DMA_CR_MSIZE_BYTE
# 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
[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,
.dier = TIM_DIER_UDE, // DMA on update event for next period
#endif
};
//#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);
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));
#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
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
@ -335,6 +356,11 @@ void ws2812_init(void) {
dmaSetRequestSource(WS2812_PWM_DMA_STREAM, WS2812_PWM_DMAMUX_ID);
#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
dmaStreamEnable(WS2812_PWM_DMA_STREAM);

View File

@ -40,26 +40,53 @@
// Define SPI config speed
// 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
// 48/16 = 3Mhz
#if WS2812_SPI_DIVISOR == 2
# if WS2812_SPI_DIVISOR == 2
# 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)
#elif WS2812_SPI_DIVISOR == 8
# elif WS2812_SPI_DIVISOR == 8
# 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)
#elif WS2812_SPI_DIVISOR == 32
# elif WS2812_SPI_DIVISOR == 32
# 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)
#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)
#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)
#else
# else
# error "Configured WS2812_SPI_DIVISOR value is not supported at this time."
# endif
#endif
// Use SPI circular buffer
@ -176,8 +203,16 @@ void ws2812_init(void) {
NULL, // error_cb
PAL_PORT(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,
0
# endif
#endif
};

View File

@ -113,6 +113,8 @@ else ifeq ($(strip $(MCU_FAMILY)),STM32)
$(UNSYNC_OUTPUT_CMD) && $(call EXEC_DFU_UTIL)
else ifeq ($(strip $(MCU_FAMILY)),WB32)
$(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)
$(UNSYNC_OUTPUT_CMD) && $(call EXEC_DFU_UTIL)
else

View File

@ -809,6 +809,40 @@ ifneq ($(findstring WB32FQ95, $(MCU)),)
WB32_BOOTLOADER_ADDRESS ?= 0x1FFFE000
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)),)
# RISC-V
MCU = risc-v

View File

@ -155,6 +155,10 @@ ifdef WB32_BOOTLOADER_ADDRESS
OPT_DEFS += -DWB32_BOOTLOADER_ADDRESS=$(WB32_BOOTLOADER_ADDRESS)
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
ifneq ("$(wildcard $(KEYBOARD_PATH_5)/bootloader_defs.h)","")
OPT_DEFS += -include $(KEYBOARD_PATH_5)/bootloader_defs.h