aboutsummaryrefslogtreecommitdiff
path: root/platforms
diff options
context:
space:
mode:
Diffstat (limited to 'platforms')
-rw-r--r--platforms/arm_atsam/_timer.h19
-rw-r--r--platforms/arm_atsam/_wait.h22
-rw-r--r--platforms/arm_atsam/atomic_util.h37
-rw-r--r--platforms/arm_atsam/bootloader.c57
-rw-r--r--platforms/arm_atsam/eeprom.c184
-rw-r--r--platforms/arm_atsam/flash.mk11
-rw-r--r--platforms/arm_atsam/gpio.h77
-rw-r--r--platforms/arm_atsam/pin_defs.h84
-rw-r--r--platforms/arm_atsam/platform.c21
-rw-r--r--platforms/arm_atsam/platform.mk67
-rw-r--r--platforms/arm_atsam/platform_deps.h18
-rw-r--r--platforms/arm_atsam/suspend.c77
-rw-r--r--platforms/arm_atsam/timer.c19
-rw-r--r--platforms/atomic_util.h32
-rw-r--r--platforms/avr/_print.h33
-rw-r--r--platforms/avr/_timer.h19
-rw-r--r--platforms/avr/_wait.h49
-rw-r--r--platforms/avr/atomic_util.h22
-rw-r--r--platforms/avr/bootloader.c293
-rw-r--r--platforms/avr/bootloader_size.c21
-rw-r--r--platforms/avr/drivers/analog.c23
-rw-r--r--platforms/avr/drivers/analog.h3
-rw-r--r--platforms/avr/drivers/audio_pwm.h17
-rw-r--r--platforms/avr/drivers/audio_pwm_hardware.c332
-rw-r--r--platforms/avr/drivers/i2c_master.c56
-rw-r--r--platforms/avr/drivers/i2c_master.h2
-rw-r--r--platforms/avr/drivers/ps2/ps2_io.c51
-rw-r--r--platforms/avr/drivers/ps2/ps2_usart.c227
-rw-r--r--platforms/avr/drivers/uart.c26
-rw-r--r--platforms/avr/drivers/uart.h8
-rw-r--r--platforms/avr/flash.mk9
-rw-r--r--platforms/avr/gpio.h49
-rw-r--r--platforms/avr/pin_defs.h128
-rw-r--r--platforms/avr/platform.c21
-rw-r--r--platforms/avr/platform.mk179
-rw-r--r--platforms/avr/platform_deps.h20
-rw-r--r--platforms/avr/printf.c20
-rw-r--r--platforms/avr/printf.mk2
-rw-r--r--platforms/avr/sleep_led.c124
-rw-r--r--platforms/avr/suspend.c152
-rw-r--r--platforms/avr/timer.c133
-rw-r--r--platforms/avr/timer_avr.h39
-rw-r--r--platforms/avr/xprintf.S498
-rw-r--r--platforms/avr/xprintf.h103
-rw-r--r--platforms/bootloader.h21
-rw-r--r--platforms/chibios/_timer.h19
-rw-r--r--platforms/chibios/_wait.c89
-rw-r--r--platforms/chibios/_wait.h60
-rw-r--r--platforms/chibios/atomic_util.h37
-rw-r--r--platforms/chibios/boards/BLACKPILL_STM32_F401/configs/mcuconf.h71
-rw-r--r--platforms/chibios/boards/BLACKPILL_STM32_F411/configs/mcuconf.h65
-rw-r--r--platforms/chibios/boards/GENERIC_STM32_F405XG/board/board.mk9
-rw-r--r--platforms/chibios/boards/GENERIC_STM32_F405XG/configs/board.h28
-rw-r--r--platforms/chibios/boards/GENERIC_STM32_F405XG/configs/config.h23
-rw-r--r--platforms/chibios/boards/GENERIC_STM32_F405XG/configs/mcuconf.h352
-rw-r--r--platforms/chibios/boards/GENERIC_STM32_F407XE/configs/mcuconf.h3
-rw-r--r--platforms/chibios/boards/GENERIC_STM32_F446XE/configs/mcuconf.h108
-rw-r--r--platforms/chibios/boards/GENERIC_STM32_G431XB/configs/mcuconf.h15
-rw-r--r--platforms/chibios/boards/GENERIC_STM32_G474XE/configs/mcuconf.h15
-rw-r--r--platforms/chibios/boards/QMK_PROTON_C/configs/chconf.h2
-rw-r--r--platforms/chibios/boards/QMK_PROTON_C/configs/config.h9
-rw-r--r--platforms/chibios/boards/SIPEED_LONGAN_NANO/board/board.mk9
-rw-r--r--platforms/chibios/boards/SIPEED_LONGAN_NANO/configs/chconf.h23
-rw-r--r--platforms/chibios/boards/SIPEED_LONGAN_NANO/configs/mcuconf.h302
-rw-r--r--platforms/chibios/boards/common/configs/chconf.h2
-rw-r--r--platforms/chibios/boards/common/ld/STM32F401xC.ld85
-rw-r--r--platforms/chibios/boards/common/ld/STM32F401xE.ld85
-rw-r--r--platforms/chibios/boards/common/ld/STM32F405xG.ld86
-rw-r--r--platforms/chibios/boards/common/ld/STM32F411xE.ld85
-rw-r--r--platforms/chibios/bootloader.c145
-rw-r--r--platforms/chibios/chibios_config.h78
-rw-r--r--platforms/chibios/drivers/analog.c8
-rw-r--r--platforms/chibios/drivers/audio_dac.h126
-rw-r--r--platforms/chibios/drivers/audio_dac_additive.c335
-rw-r--r--platforms/chibios/drivers/audio_dac_basic.c245
-rw-r--r--platforms/chibios/drivers/audio_pwm.h40
-rw-r--r--platforms/chibios/drivers/audio_pwm_hardware.c144
-rw-r--r--platforms/chibios/drivers/audio_pwm_software.c164
-rw-r--r--platforms/chibios/drivers/i2c_master.c37
-rw-r--r--platforms/chibios/drivers/i2c_master.h27
-rw-r--r--platforms/chibios/drivers/ps2/ps2_io.c55
-rw-r--r--platforms/chibios/drivers/serial.c2
-rw-r--r--platforms/chibios/drivers/serial_usart.c10
-rw-r--r--platforms/chibios/drivers/spi_master.c31
-rw-r--r--platforms/chibios/drivers/spi_master.h6
-rw-r--r--platforms/chibios/drivers/uart.c16
-rw-r--r--platforms/chibios/drivers/uart.h8
-rw-r--r--platforms/chibios/drivers/ws2812.c4
-rw-r--r--platforms/chibios/drivers/ws2812_pwm.c48
-rw-r--r--platforms/chibios/drivers/ws2812_spi.c27
-rw-r--r--platforms/chibios/eeprom_stm32.c687
-rw-r--r--platforms/chibios/eeprom_stm32.h33
-rw-r--r--platforms/chibios/eeprom_stm32_defs.h74
-rw-r--r--platforms/chibios/eeprom_teensy.c795
-rw-r--r--platforms/chibios/flash.mk2
-rw-r--r--platforms/chibios/flash_stm32.c208
-rw-r--r--platforms/chibios/flash_stm32.h44
-rw-r--r--platforms/chibios/gd32v_compatibility.h120
-rw-r--r--platforms/chibios/gpio.h50
-rw-r--r--platforms/chibios/pin_defs.h323
-rw-r--r--platforms/chibios/platform.c22
-rw-r--r--platforms/chibios/platform.mk439
-rw-r--r--platforms/chibios/platform_deps.h19
-rw-r--r--platforms/chibios/sleep_led.c192
-rw-r--r--platforms/chibios/suspend.c92
-rw-r--r--platforms/chibios/syscall-fallbacks.c111
-rw-r--r--platforms/chibios/timer.c47
-rw-r--r--platforms/chibios/wait.c41
-rw-r--r--platforms/common.mk12
-rw-r--r--platforms/eeprom.h21
-rw-r--r--platforms/gpio.h22
-rw-r--r--platforms/pin_defs.h23
-rw-r--r--platforms/progmem.h19
-rw-r--r--platforms/sleep_led.h17
-rw-r--r--platforms/suspend.h20
-rw-r--r--platforms/test/_wait.h22
-rw-r--r--platforms/test/bootloader.c19
-rw-r--r--platforms/test/eeprom.c95
-rw-r--r--platforms/test/eeprom_stm32_tests.cpp438
-rw-r--r--platforms/test/flash_stm32_mock.c49
-rw-r--r--platforms/test/hal.h18
-rw-r--r--platforms/test/platform.c21
-rw-r--r--platforms/test/platform.h18
-rw-r--r--platforms/test/platform.mk34
-rw-r--r--platforms/test/platform_deps.h18
-rw-r--r--platforms/test/rules.mk24
-rw-r--r--platforms/test/suspend.c15
-rw-r--r--platforms/test/testlist.mk1
-rw-r--r--platforms/test/timer.c33
-rw-r--r--platforms/timer.h67
-rw-r--r--platforms/wait.h30
131 files changed, 10646 insertions, 232 deletions
diff --git a/platforms/arm_atsam/_timer.h b/platforms/arm_atsam/_timer.h
new file mode 100644
index 000000000..77402b612
--- /dev/null
+++ b/platforms/arm_atsam/_timer.h
@@ -0,0 +1,19 @@
1/* Copyright 2021 Simon Arlott
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#pragma once
17
18// The platform is 32-bit, so prefer 32-bit timers to avoid overflow
19#define FAST_TIMER_T_SIZE 32
diff --git a/platforms/arm_atsam/_wait.h b/platforms/arm_atsam/_wait.h
new file mode 100644
index 000000000..41b686b56
--- /dev/null
+++ b/platforms/arm_atsam/_wait.h
@@ -0,0 +1,22 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#pragma once
17
18#include "clks.h"
19
20#define wait_ms(ms) CLK_delay_ms(ms)
21#define wait_us(us) CLK_delay_us(us)
22#define waitInputPinDelay()
diff --git a/platforms/arm_atsam/atomic_util.h b/platforms/arm_atsam/atomic_util.h
new file mode 100644
index 000000000..848542d23
--- /dev/null
+++ b/platforms/arm_atsam/atomic_util.h
@@ -0,0 +1,37 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#pragma once
17
18#include "samd51j18a.h"
19
20static __inline__ uint8_t __interrupt_disable__(void) {
21 __disable_irq();
22
23 return 1;
24}
25
26static __inline__ void __interrupt_enable__(const uint8_t *__s) {
27 __enable_irq();
28
29 __asm__ volatile("" ::: "memory");
30 (void)__s;
31}
32
33#define ATOMIC_BLOCK(type) for (type, __ToDo = __interrupt_disable__(); __ToDo; __ToDo = 0)
34#define ATOMIC_FORCEON uint8_t sreg_save __attribute__((__cleanup__(__interrupt_enable__))) = 0
35
36#define ATOMIC_BLOCK_RESTORESTATE _Static_assert(0, "ATOMIC_BLOCK_RESTORESTATE not implemented")
37#define ATOMIC_BLOCK_FORCEON ATOMIC_BLOCK(ATOMIC_FORCEON)
diff --git a/platforms/arm_atsam/bootloader.c b/platforms/arm_atsam/bootloader.c
new file mode 100644
index 000000000..9015b00aa
--- /dev/null
+++ b/platforms/arm_atsam/bootloader.c
@@ -0,0 +1,57 @@
1/* Copyright 2017 Fred Sundvik
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "bootloader.h"
18#include "samd51j18a.h"
19#include "md_bootloader.h"
20
21// Set watchdog timer to reset. Directs the bootloader to stay in programming mode.
22void bootloader_jump(void) {
23#ifdef KEYBOARD_massdrop_ctrl
24 // CTRL keyboards released with bootloader version below must use RAM method. Otherwise use WDT method.
25 uint8_t ver_ram_method[] = "v2.18Jun 22 2018 17:28:08"; // The version to match (NULL terminated by compiler)
26 uint8_t *ver_check = ver_ram_method; // Pointer to version match string for traversal
27 uint8_t *ver_rom = (uint8_t *)0x21A0; // Pointer to address in ROM where this specific bootloader version would exist
28
29 while (*ver_check && *ver_rom == *ver_check) { // While there are check version characters to match and bootloader's version matches check's version
30 ver_check++; // Move check version pointer to next character
31 ver_rom++; // Move ROM version pointer to next character
32 }
33
34 if (!*ver_check) { // If check version pointer is NULL, all characters have matched
35 *MAGIC_ADDR = BOOTLOADER_MAGIC; // Set magic number into RAM
36 NVIC_SystemReset(); // Perform system reset
37 while (1) {
38 } // Won't get here
39 }
40#endif
41
42 WDT->CTRLA.bit.ENABLE = 0;
43 while (WDT->SYNCBUSY.bit.ENABLE) {
44 }
45 while (WDT->CTRLA.bit.ENABLE) {
46 }
47 WDT->CONFIG.bit.WINDOW = 0;
48 WDT->CONFIG.bit.PER = 0;
49 WDT->EWCTRL.bit.EWOFFSET = 0;
50 WDT->CTRLA.bit.ENABLE = 1;
51 while (WDT->SYNCBUSY.bit.ENABLE) {
52 }
53 while (!WDT->CTRLA.bit.ENABLE) {
54 }
55 while (1) {
56 } // Wait on timeout
57}
diff --git a/platforms/arm_atsam/eeprom.c b/platforms/arm_atsam/eeprom.c
new file mode 100644
index 000000000..ff1a69262
--- /dev/null
+++ b/platforms/arm_atsam/eeprom.c
@@ -0,0 +1,184 @@
1/* Copyright 2017 Fred Sundvik
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#include "eeprom.h"
17#include "debug.h"
18#include "samd51j18a.h"
19#include "core_cm4.h"
20#include "component/nvmctrl.h"
21
22#ifndef EEPROM_SIZE
23# include "eeconfig.h"
24# define EEPROM_SIZE (((EECONFIG_SIZE + 3) / 4) * 4) // based off eeconfig's current usage, aligned to 4-byte sizes, to deal with LTO
25#endif
26
27#ifndef MAX
28# define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
29#endif
30
31#ifndef BUSY_RETRIES
32# define BUSY_RETRIES 10000
33#endif
34
35// #define DEBUG_EEPROM_OUTPUT
36
37/*
38 * Debug print utils
39 */
40#if defined(DEBUG_EEPROM_OUTPUT)
41# define eeprom_printf(fmt, ...) xprintf(fmt, ##__VA_ARGS__);
42#else /* NO_DEBUG */
43# define eeprom_printf(fmt, ...)
44#endif /* NO_DEBUG */
45
46__attribute__((aligned(4))) static uint8_t buffer[EEPROM_SIZE] = {0};
47volatile uint8_t * SmartEEPROM8 = (uint8_t *)SEEPROM_ADDR;
48
49static inline bool eeprom_is_busy(void) {
50 int timeout = BUSY_RETRIES;
51 while (NVMCTRL->SEESTAT.bit.BUSY && timeout-- > 0)
52 ;
53
54 return NVMCTRL->SEESTAT.bit.BUSY;
55}
56
57static uint32_t get_virtual_eeprom_size(void) {
58 // clang-format off
59 static const uint32_t VIRTUAL_EEPROM_MAP[11][8] = {
60 /* 4 8 16 32 64 128 256 512 */
61 /* 0*/ { 0, 0, 0, 0, 0, 0, 0, 0 },
62 /* 1*/ { 512, 1024, 2048, 4096, 4096, 4096, 4096, 4096 },
63 /* 2*/ { 512, 1024, 2048, 4096, 8192, 8192, 8192, 8192 },
64 /* 3*/ { 512, 1024, 2048, 4096, 8192, 16384, 16384, 16384 },
65 /* 4*/ { 512, 1024, 2048, 4096, 8192, 16384, 16384, 16384 },
66 /* 5*/ { 512, 1024, 2048, 4096, 8192, 16384, 32768, 32768 },
67 /* 6*/ { 512, 1024, 2048, 4096, 8192, 16384, 32768, 32768 },
68 /* 7*/ { 512, 1024, 2048, 4096, 8192, 16384, 32768, 32768 },
69 /* 8*/ { 512, 1024, 2048, 4096, 8192, 16384, 32768, 32768 },
70 /* 9*/ { 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536 },
71 /*10*/ { 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536 },
72 };
73 // clang-format on
74
75 static uint32_t virtual_eeprom_size = UINT32_MAX;
76 if (virtual_eeprom_size == UINT32_MAX) {
77 virtual_eeprom_size = VIRTUAL_EEPROM_MAP[NVMCTRL->SEESTAT.bit.PSZ][NVMCTRL->SEESTAT.bit.SBLK];
78 }
79 // eeprom_printf("get_virtual_eeprom_size:: %d:%d:%d\n", NVMCTRL->SEESTAT.bit.PSZ, NVMCTRL->SEESTAT.bit.SBLK, virtual_eeprom_size);
80 return virtual_eeprom_size;
81}
82
83uint8_t eeprom_read_byte(const uint8_t *addr) {
84 uintptr_t offset = (uintptr_t)addr;
85 if (offset >= MAX(EEPROM_SIZE, get_virtual_eeprom_size())) {
86 eeprom_printf("eeprom_read_byte:: out of bounds\n");
87 return 0x0;
88 }
89
90 if (get_virtual_eeprom_size() == 0) {
91 return buffer[offset];
92 }
93
94 if (eeprom_is_busy()) {
95 eeprom_printf("eeprom_write_byte:: timeout\n");
96 return 0x0;
97 }
98
99 return SmartEEPROM8[offset];
100}
101
102void eeprom_write_byte(uint8_t *addr, uint8_t value) {
103 uintptr_t offset = (uintptr_t)addr;
104 if (offset >= MAX(EEPROM_SIZE, get_virtual_eeprom_size())) {
105 eeprom_printf("eeprom_write_byte:: out of bounds\n");
106 return;
107 }
108
109 if (get_virtual_eeprom_size() == 0) {
110 buffer[offset] = value;
111 return;
112 }
113
114 if (eeprom_is_busy()) {
115 eeprom_printf("eeprom_write_byte:: timeout\n");
116 return;
117 }
118
119 SmartEEPROM8[offset] = value;
120}
121
122uint16_t eeprom_read_word(const uint16_t *addr) {
123 const uint8_t *p = (const uint8_t *)addr;
124 return eeprom_read_byte(p) | (eeprom_read_byte(p + 1) << 8);
125}
126
127uint32_t eeprom_read_dword(const uint32_t *addr) {
128 const uint8_t *p = (const uint8_t *)addr;
129 return eeprom_read_byte(p) | (eeprom_read_byte(p + 1) << 8) | (eeprom_read_byte(p + 2) << 16) | (eeprom_read_byte(p + 3) << 24);
130}
131
132void eeprom_read_block(void *buf, const void *addr, size_t len) {
133 const uint8_t *p = (const uint8_t *)addr;
134 uint8_t * dest = (uint8_t *)buf;
135 while (len--) {
136 *dest++ = eeprom_read_byte(p++);
137 }
138}
139
140void eeprom_write_word(uint16_t *addr, uint16_t value) {
141 uint8_t *p = (uint8_t *)addr;
142 eeprom_write_byte(p++, value);
143 eeprom_write_byte(p, value >> 8);
144}
145
146void eeprom_write_dword(uint32_t *addr, uint32_t value) {
147 uint8_t *p = (uint8_t *)addr;
148 eeprom_write_byte(p++, value);
149 eeprom_write_byte(p++, value >> 8);
150 eeprom_write_byte(p++, value >> 16);
151 eeprom_write_byte(p, value >> 24);
152}
153
154void eeprom_write_block(const void *buf, void *addr, size_t len) {
155 uint8_t * p = (uint8_t *)addr;
156 const uint8_t *src = (const uint8_t *)buf;
157 while (len--) {
158 eeprom_write_byte(p++, *src++);
159 }
160}
161
162void eeprom_update_byte(uint8_t *addr, uint8_t value) { eeprom_write_byte(addr, value); }
163
164void eeprom_update_word(uint16_t *addr, uint16_t value) {
165 uint8_t *p = (uint8_t *)addr;
166 eeprom_write_byte(p++, value);
167 eeprom_write_byte(p, value >> 8);
168}
169
170void eeprom_update_dword(uint32_t *addr, uint32_t value) {
171 uint8_t *p = (uint8_t *)addr;
172 eeprom_write_byte(p++, value);
173 eeprom_write_byte(p++, value >> 8);
174 eeprom_write_byte(p++, value >> 16);
175 eeprom_write_byte(p, value >> 24);
176}
177
178void eeprom_update_block(const void *buf, void *addr, size_t len) {
179 uint8_t * p = (uint8_t *)addr;
180 const uint8_t *src = (const uint8_t *)buf;
181 while (len--) {
182 eeprom_write_byte(p++, *src++);
183 }
184}
diff --git a/platforms/arm_atsam/flash.mk b/platforms/arm_atsam/flash.mk
index f31d4b4d9..8152610ce 100644
--- a/platforms/arm_atsam/flash.mk
+++ b/platforms/arm_atsam/flash.mk
@@ -3,9 +3,20 @@
3# Architecture or project specific options 3# Architecture or project specific options
4# 4#
5 5
6MDLOADER_CLI ?= mdloader
7
8define EXEC_MDLOADER
9 $(MDLOADER_CLI) --first --download $(BUILD_DIR)/$(TARGET).bin --restart
10endef
11
12mdloader: bin
13 $(call EXEC_MDLOADER)
14
6flash: bin 15flash: bin
7ifneq ($(strip $(PROGRAM_CMD)),) 16ifneq ($(strip $(PROGRAM_CMD)),)
8 $(UNSYNC_OUTPUT_CMD) && $(PROGRAM_CMD) 17 $(UNSYNC_OUTPUT_CMD) && $(PROGRAM_CMD)
18else ifeq ($(strip $(ARM_ATSAM)),SAMD51J18A)
19 $(UNSYNC_OUTPUT_CMD) && $(call EXEC_MDLOADER)
9else 20else
10 $(PRINT_OK); $(SILENT) || printf "$(MSG_FLASH_ARCH)" 21 $(PRINT_OK); $(SILENT) || printf "$(MSG_FLASH_ARCH)"
11endif 22endif
diff --git a/platforms/arm_atsam/gpio.h b/platforms/arm_atsam/gpio.h
new file mode 100644
index 000000000..915ed0ef4
--- /dev/null
+++ b/platforms/arm_atsam/gpio.h
@@ -0,0 +1,77 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#pragma once
17
18#include "stdint.h"
19#include "samd51j18a.h"
20
21#include "pin_defs.h"
22
23typedef uint8_t pin_t;
24
25#define SAMD_PORT(pin) ((pin & 0x20) >> 5)
26#define SAMD_PIN(pin) (pin & 0x1f)
27#define SAMD_PIN_MASK(pin) (1 << (pin & 0x1f))
28
29#define setPinInput(pin) \
30 do { \
31 PORT->Group[SAMD_PORT(pin)].PINCFG[SAMD_PIN(pin)].bit.INEN = 1; \
32 PORT->Group[SAMD_PORT(pin)].DIRCLR.reg = SAMD_PIN_MASK(pin); \
33 } while (0)
34
35#define setPinInputHigh(pin) \
36 do { \
37 PORT->Group[SAMD_PORT(pin)].DIRCLR.reg = SAMD_PIN_MASK(pin); \
38 PORT->Group[SAMD_PORT(pin)].OUTSET.reg = SAMD_PIN_MASK(pin); \
39 PORT->Group[SAMD_PORT(pin)].PINCFG[SAMD_PIN(pin)].bit.INEN = 1; \
40 PORT->Group[SAMD_PORT(pin)].PINCFG[SAMD_PIN(pin)].bit.PULLEN = 1; \
41 } while (0)
42
43#define setPinInputLow(pin) \
44 do { \
45 PORT->Group[SAMD_PORT(pin)].DIRCLR.reg = SAMD_PIN_MASK(pin); \
46 PORT->Group[SAMD_PORT(pin)].OUTCLR.reg = SAMD_PIN_MASK(pin); \
47 PORT->Group[SAMD_PORT(pin)].PINCFG[SAMD_PIN(pin)].bit.INEN = 1; \
48 PORT->Group[SAMD_PORT(pin)].PINCFG[SAMD_PIN(pin)].bit.PULLEN = 1; \
49 } while (0)
50
51#define setPinOutput(pin) \
52 do { \
53 PORT->Group[SAMD_PORT(pin)].DIRSET.reg = SAMD_PIN_MASK(pin); \
54 PORT->Group[SAMD_PORT(pin)].OUTCLR.reg = SAMD_PIN_MASK(pin); \
55 } while (0)
56
57#define writePinHigh(pin) \
58 do { \
59 PORT->Group[SAMD_PORT(pin)].OUTSET.reg = SAMD_PIN_MASK(pin); \
60 } while (0)
61
62#define writePinLow(pin) \
63 do { \
64 PORT->Group[SAMD_PORT(pin)].OUTCLR.reg = SAMD_PIN_MASK(pin); \
65 } while (0)
66
67#define writePin(pin, level) \
68 do { \
69 if (level) \
70 PORT->Group[SAMD_PORT(pin)].OUTSET.reg = SAMD_PIN_MASK(pin); \
71 else \
72 PORT->Group[SAMD_PORT(pin)].OUTCLR.reg = SAMD_PIN_MASK(pin); \
73 } while (0)
74
75#define readPin(pin) ((PORT->Group[SAMD_PORT(pin)].IN.reg & SAMD_PIN_MASK(pin)) != 0)
76
77#define togglePin(pin) (PORT->Group[SAMD_PORT(pin)].OUTTGL.reg = SAMD_PIN_MASK(pin))
diff --git a/platforms/arm_atsam/pin_defs.h b/platforms/arm_atsam/pin_defs.h
new file mode 100644
index 000000000..5b50b2391
--- /dev/null
+++ b/platforms/arm_atsam/pin_defs.h
@@ -0,0 +1,84 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#pragma once
17
18#include "samd51j18a.h"
19
20#define A00 PIN_PA00
21#define A01 PIN_PA01
22#define A02 PIN_PA02
23#define A03 PIN_PA03
24#define A04 PIN_PA04
25#define A05 PIN_PA05
26#define A06 PIN_PA06
27#define A07 PIN_PA07
28#define A08 PIN_PA08
29#define A09 PIN_PA09
30#define A10 PIN_PA10
31#define A11 PIN_PA11
32#define A12 PIN_PA12
33#define A13 PIN_PA13
34#define A14 PIN_PA14
35#define A15 PIN_PA15
36#define A16 PIN_PA16
37#define A17 PIN_PA17
38#define A18 PIN_PA18
39#define A19 PIN_PA19
40#define A20 PIN_PA20
41#define A21 PIN_PA21
42#define A22 PIN_PA22
43#define A23 PIN_PA23
44#define A24 PIN_PA24
45#define A25 PIN_PA25
46#define A26 PIN_PA26
47#define A27 PIN_PA27
48#define A28 PIN_PA28
49#define A29 PIN_PA29
50#define A30 PIN_PA30
51#define A31 PIN_PA31
52
53#define B00 PIN_PB00
54#define B01 PIN_PB01
55#define B02 PIN_PB02
56#define B03 PIN_PB03
57#define B04 PIN_PB04
58#define B05 PIN_PB05
59#define B06 PIN_PB06
60#define B07 PIN_PB07
61#define B08 PIN_PB08
62#define B09 PIN_PB09
63#define B10 PIN_PB10
64#define B11 PIN_PB11
65#define B12 PIN_PB12
66#define B13 PIN_PB13
67#define B14 PIN_PB14
68#define B15 PIN_PB15
69#define B16 PIN_PB16
70#define B17 PIN_PB17
71#define B18 PIN_PB18
72#define B19 PIN_PB19
73#define B20 PIN_PB20
74#define B21 PIN_PB21
75#define B22 PIN_PB22
76#define B23 PIN_PB23
77#define B24 PIN_PB24
78#define B25 PIN_PB25
79#define B26 PIN_PB26
80#define B27 PIN_PB27
81#define B28 PIN_PB28
82#define B29 PIN_PB29
83#define B30 PIN_PB30
84#define B31 PIN_PB31
diff --git a/platforms/arm_atsam/platform.c b/platforms/arm_atsam/platform.c
new file mode 100644
index 000000000..3e35b4fe4
--- /dev/null
+++ b/platforms/arm_atsam/platform.c
@@ -0,0 +1,21 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "platform_deps.h"
18
19void platform_setup(void) {
20 // do nothing
21}
diff --git a/platforms/arm_atsam/platform.mk b/platforms/arm_atsam/platform.mk
new file mode 100644
index 000000000..b49bf764d
--- /dev/null
+++ b/platforms/arm_atsam/platform.mk
@@ -0,0 +1,67 @@
1# Hey Emacs, this is a -*- makefile -*-
2##############################################################################
3# Compiler settings
4#
5CC = $(CC_PREFIX) arm-none-eabi-gcc
6OBJCOPY = arm-none-eabi-objcopy
7OBJDUMP = arm-none-eabi-objdump
8SIZE = arm-none-eabi-size
9AR = arm-none-eabi-ar
10NM = arm-none-eabi-nm
11HEX = $(OBJCOPY) -O $(FORMAT) -R .eeprom -R .fuse -R .lock -R .signature
12EEP = $(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT)
13BIN =
14
15COMMON_VPATH += $(LIB_PATH)/arm_atsam/packs/atmel/SAMD51_DFP/1.0.70/include
16COMMON_VPATH += $(LIB_PATH)/arm_atsam/packs/arm/cmsis/5.0.1/CMSIS/Include
17
18COMPILEFLAGS += -funsigned-char
19COMPILEFLAGS += -funsigned-bitfields
20COMPILEFLAGS += -ffunction-sections
21COMPILEFLAGS += -fshort-enums
22COMPILEFLAGS += -fno-inline-small-functions
23COMPILEFLAGS += -fno-strict-aliasing
24COMPILEFLAGS += -mfloat-abi=hard
25COMPILEFLAGS += -mfpu=fpv4-sp-d16
26COMPILEFLAGS += -mthumb
27
28#ALLOW_WARNINGS = yes
29
30CFLAGS += $(COMPILEFLAGS)
31
32CXXFLAGS += $(COMPILEFLAGS)
33CXXFLAGS += -fno-exceptions -std=c++11
34
35LDFLAGS +=-Wl,--gc-sections
36LDFLAGS += -Wl,-Map="%OUT%%PROJ_NAME%.map"
37LDFLAGS += -Wl,--start-group
38LDFLAGS += -Wl,--end-group
39LDFLAGS += --specs=rdimon.specs
40LDFLAGS += -T$(LIB_PATH)/arm_atsam/packs/atmel/SAMD51_DFP/1.0.70/gcc/gcc/samd51j18a_flash.ld
41
42OPT_DEFS += -DPROTOCOL_ARM_ATSAM
43
44MCUFLAGS = -mcpu=$(MCU)
45MCUFLAGS += -D__$(ARM_ATSAM)__
46
47# List any extra directories to look for libraries here.
48# Each directory must be seperated by a space.
49# Use forward slashes for directory separators.
50# For a directory that has spaces, enclose it in quotes.
51EXTRALIBDIRS =
52
53cpfirmware: warn-arm_atsam
54.INTERMEDIATE: warn-arm_atsam
55warn-arm_atsam: $(FIRMWARE_FORMAT)
56 $(info @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@)
57 $(info This MCU support package has a lack of support from the upstream provider (Massdrop).)
58 $(info There are currently questions about valid licensing, and at this stage it's likely)
59 $(info their boards and supporting code will be removed from QMK in the near future. Please)
60 $(info contact Massdrop for support, and encourage them to align their future board design)
61 $(info choices to gain proper license compatibility with QMK.)
62 $(info @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@)
63
64# Convert hex to bin.
65bin: $(BUILD_DIR)/$(TARGET).hex
66 $(OBJCOPY) -Iihex -Obinary $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin
67 $(COPY) $(BUILD_DIR)/$(TARGET).bin $(TARGET).bin;
diff --git a/platforms/arm_atsam/platform_deps.h b/platforms/arm_atsam/platform_deps.h
new file mode 100644
index 000000000..f296d1d53
--- /dev/null
+++ b/platforms/arm_atsam/platform_deps.h
@@ -0,0 +1,18 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#pragma once
17
18// here just to please the build
diff --git a/platforms/arm_atsam/suspend.c b/platforms/arm_atsam/suspend.c
new file mode 100644
index 000000000..e51426128
--- /dev/null
+++ b/platforms/arm_atsam/suspend.c
@@ -0,0 +1,77 @@
1#include "matrix.h"
2#include "i2c_master.h"
3#include "md_rgb_matrix.h"
4#include "suspend.h"
5
6/** \brief Suspend idle
7 *
8 * FIXME: needs doc
9 */
10void suspend_idle(uint8_t time) { /* Note: Not used anywhere currently */
11}
12
13/** \brief Run user level Power down
14 *
15 * FIXME: needs doc
16 */
17__attribute__((weak)) void suspend_power_down_user(void) {}
18
19/** \brief Run keyboard level Power down
20 *
21 * FIXME: needs doc
22 */
23__attribute__((weak)) void suspend_power_down_kb(void) { suspend_power_down_user(); }
24
25/** \brief Suspend power down
26 *
27 * FIXME: needs doc
28 */
29void suspend_power_down(void) {
30#ifdef RGB_MATRIX_ENABLE
31 I2C3733_Control_Set(0); // Disable LED driver
32#endif
33
34 suspend_power_down_kb();
35}
36
37__attribute__((weak)) void matrix_power_up(void) {}
38__attribute__((weak)) void matrix_power_down(void) {}
39bool suspend_wakeup_condition(void) {
40 matrix_power_up();
41 matrix_scan();
42 matrix_power_down();
43 for (uint8_t r = 0; r < MATRIX_ROWS; r++) {
44 if (matrix_get_row(r)) return true;
45 }
46 return false;
47}
48
49/** \brief run user level code immediately after wakeup
50 *
51 * FIXME: needs doc
52 */
53__attribute__((weak)) void suspend_wakeup_init_user(void) {}
54
55/** \brief run keyboard level code immediately after wakeup
56 *
57 * FIXME: needs doc
58 */
59__attribute__((weak)) void suspend_wakeup_init_kb(void) { suspend_wakeup_init_user(); }
60
61/** \brief run immediately after wakeup
62 *
63 * FIXME: needs doc
64 */
65void suspend_wakeup_init(void) {
66#ifdef RGB_MATRIX_ENABLE
67# ifdef USE_MASSDROP_CONFIGURATOR
68 if (led_enabled) {
69 I2C3733_Control_Set(1);
70 }
71# else
72 I2C3733_Control_Set(1);
73# endif
74#endif
75
76 suspend_wakeup_init_kb();
77}
diff --git a/platforms/arm_atsam/timer.c b/platforms/arm_atsam/timer.c
new file mode 100644
index 000000000..b835dd5e7
--- /dev/null
+++ b/platforms/arm_atsam/timer.c
@@ -0,0 +1,19 @@
1#include "samd51j18a.h"
2#include "timer.h"
3#include "tmk_core/protocol/arm_atsam/clks.h"
4
5void set_time(uint64_t tset) { ms_clk = tset; }
6
7void timer_init(void) { timer_clear(); }
8
9uint16_t timer_read(void) { return (uint16_t)ms_clk; }
10
11uint32_t timer_read32(void) { return (uint32_t)ms_clk; }
12
13uint64_t timer_read64(void) { return ms_clk; }
14
15uint16_t timer_elapsed(uint16_t tlast) { return TIMER_DIFF_16(timer_read(), tlast); }
16
17uint32_t timer_elapsed32(uint32_t tlast) { return TIMER_DIFF_32(timer_read32(), tlast); }
18
19void timer_clear(void) { set_time(0); }
diff --git a/platforms/atomic_util.h b/platforms/atomic_util.h
new file mode 100644
index 000000000..2c95302a1
--- /dev/null
+++ b/platforms/atomic_util.h
@@ -0,0 +1,32 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#pragma once
17
18// Macro to help make GPIO and other controls atomic.
19
20#ifndef IGNORE_ATOMIC_BLOCK
21# if __has_include_next("atomic_util.h")
22# include_next "atomic_util.h" /* Include the platforms atomic.h */
23# else
24# define ATOMIC_BLOCK _Static_assert(0, "ATOMIC_BLOCK not implemented")
25# define ATOMIC_BLOCK_RESTORESTATE _Static_assert(0, "ATOMIC_BLOCK_RESTORESTATE not implemented")
26# define ATOMIC_BLOCK_FORCEON _Static_assert(0, "ATOMIC_BLOCK_FORCEON not implemented")
27# endif
28#else /* do nothing atomic macro */
29# define ATOMIC_BLOCK for (uint8_t __ToDo = 1; __ToDo; __ToDo = 0)
30# define ATOMIC_BLOCK_RESTORESTATE ATOMIC_BLOCK
31# define ATOMIC_BLOCK_FORCEON ATOMIC_BLOCK
32#endif
diff --git a/platforms/avr/_print.h b/platforms/avr/_print.h
new file mode 100644
index 000000000..5c1fdd26d
--- /dev/null
+++ b/platforms/avr/_print.h
@@ -0,0 +1,33 @@
1/* Copyright 2012 Jun Wako <wakojun@gmail.com> */
2/* Very basic print functions, intended to be used with usb_debug_only.c
3 * http://www.pjrc.com/teensy/
4 * Copyright (c) 2008 PJRC.COM, LLC
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24#pragma once
25
26#include "avr/xprintf.h"
27
28// Create user & normal print defines
29#define print(s) xputs(PSTR(s))
30#define println(s) xputs(PSTR(s "\r\n"))
31#define uprint(s) xputs(PSTR(s))
32#define uprintln(s) xputs(PSTR(s "\r\n"))
33#define uprintf(fmt, ...) __xprintf(PSTR(fmt), ##__VA_ARGS__) \ No newline at end of file
diff --git a/platforms/avr/_timer.h b/platforms/avr/_timer.h
new file mode 100644
index 000000000..b81e0f68b
--- /dev/null
+++ b/platforms/avr/_timer.h
@@ -0,0 +1,19 @@
1/* Copyright 2021 Simon Arlott
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#pragma once
17
18// The platform is 8-bit, so prefer 16-bit timers to reduce code size
19#define FAST_TIMER_T_SIZE 16
diff --git a/platforms/avr/_wait.h b/platforms/avr/_wait.h
new file mode 100644
index 000000000..683db6ae5
--- /dev/null
+++ b/platforms/avr/_wait.h
@@ -0,0 +1,49 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#pragma once
17
18#include <util/delay.h>
19
20#define wait_ms(ms) \
21 do { \
22 if (__builtin_constant_p(ms)) { \
23 _delay_ms(ms); \
24 } else { \
25 for (uint16_t i = ms; i > 0; i--) { \
26 _delay_ms(1); \
27 } \
28 } \
29 } while (0)
30#define wait_us(us) \
31 do { \
32 if (__builtin_constant_p(us)) { \
33 _delay_us(us); \
34 } else { \
35 for (uint16_t i = us; i > 0; i--) { \
36 _delay_us(1); \
37 } \
38 } \
39 } while (0)
40#define wait_cpuclock(n) __builtin_avr_delay_cycles(n)
41#define CPU_CLOCK F_CPU
42
43/* The AVR series GPIOs have a one clock read delay for changes in the digital input signal.
44 * But here's more margin to make it two clocks. */
45#ifndef GPIO_INPUT_PIN_DELAY
46# define GPIO_INPUT_PIN_DELAY 2
47#endif
48
49#define waitInputPinDelay() wait_cpuclock(GPIO_INPUT_PIN_DELAY)
diff --git a/platforms/avr/atomic_util.h b/platforms/avr/atomic_util.h
new file mode 100644
index 000000000..7c5d2e7dc
--- /dev/null
+++ b/platforms/avr/atomic_util.h
@@ -0,0 +1,22 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#pragma once
17
18/* atomic macro for AVR */
19#include <util/atomic.h>
20
21#define ATOMIC_BLOCK_RESTORESTATE ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
22#define ATOMIC_BLOCK_FORCEON ATOMIC_BLOCK(ATOMIC_FORCEON)
diff --git a/platforms/avr/bootloader.c b/platforms/avr/bootloader.c
new file mode 100644
index 000000000..c0272903b
--- /dev/null
+++ b/platforms/avr/bootloader.c
@@ -0,0 +1,293 @@
1#include <stdint.h>
2#include <stdbool.h>
3#include <avr/io.h>
4#include <avr/eeprom.h>
5#include <avr/interrupt.h>
6#include <avr/wdt.h>
7#include <util/delay.h>
8#include "bootloader.h"
9#include <avr/boot.h>
10
11#ifdef PROTOCOL_LUFA
12# include <LUFA/Drivers/USB/USB.h>
13#endif
14
15/** \brief Bootloader Size in *bytes*
16 *
17 * AVR Boot section size are defined by setting BOOTSZ fuse in fact. Consult with your MCU datasheet.
18 * Note that 'Word'(2 bytes) size and address are used in datasheet while TMK uses 'Byte'.
19 *
20 * Size of Bootloaders in bytes:
21 * Atmel DFU loader(ATmega32U4) 4096
22 * Atmel DFU loader(AT90USB128) 8192
23 * LUFA bootloader(ATmega32U4) 4096
24 * Arduino Caterina(ATmega32U4) 4096
25 * USBaspLoader(ATmega***) 2048
26 * Teensy halfKay(ATmega32U4) 512
27 * Teensy++ halfKay(AT90USB128) 1024
28 *
29 * AVR Boot section is located at the end of Flash memory like the followings.
30 *
31 * byte Atmel/LUFA(ATMega32u4) byte Atmel(AT90SUB128)
32 * 0x0000 +---------------+ 0x00000 +---------------+
33 * | | | |
34 * | | | |
35 * | Application | | Application |
36 * | | | |
37 * = = = =
38 * | | 32KB-4KB | | 128KB-8KB
39 * 0x7000 +---------------+ 0x1E000 +---------------+
40 * | Bootloader | 4KB | Bootloader | 8KB
41 * 0x7FFF +---------------+ 0x1FFFF +---------------+
42 *
43 *
44 * byte Teensy(ATMega32u4) byte Teensy++(AT90SUB128)
45 * 0x0000 +---------------+ 0x00000 +---------------+
46 * | | | |
47 * | | | |
48 * | Application | | Application |
49 * | | | |
50 * = = = =
51 * | | 32KB-512B | | 128KB-1KB
52 * 0x7E00 +---------------+ 0x1FC00 +---------------+
53 * | Bootloader | 512B | Bootloader | 1KB
54 * 0x7FFF +---------------+ 0x1FFFF +---------------+
55 */
56#define FLASH_SIZE (FLASHEND + 1L)
57
58#if !defined(BOOTLOADER_SIZE)
59uint16_t bootloader_start;
60#endif
61
62// compatibility between ATMega8 and ATMega88
63#if !defined(MCUCSR)
64# if defined(MCUSR)
65# define MCUCSR MCUSR
66# endif
67#endif
68
69/** \brief Entering the Bootloader via Software
70 *
71 * http://www.fourwalledcubicle.com/files/LUFA/Doc/120730/html/_page__software_bootloader_start.html
72 */
73#define BOOTLOADER_RESET_KEY 0xB007B007
74uint32_t reset_key __attribute__((section(".noinit,\"aw\",@nobits;")));
75
76/** \brief initialize MCU status by watchdog reset
77 *
78 * FIXME: needs doc
79 */
80__attribute__((weak)) void bootloader_jump(void) {
81#if !defined(BOOTLOADER_SIZE)
82 uint8_t high_fuse = boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS);
83
84 if (high_fuse & ~(FUSE_BOOTSZ0 & FUSE_BOOTSZ1)) {
85 bootloader_start = (FLASH_SIZE - 512) >> 1;
86 } else if (high_fuse & ~(FUSE_BOOTSZ1)) {
87 bootloader_start = (FLASH_SIZE - 1024) >> 1;
88 } else if (high_fuse & ~(FUSE_BOOTSZ0)) {
89 bootloader_start = (FLASH_SIZE - 2048) >> 1;
90 } else {
91 bootloader_start = (FLASH_SIZE - 4096) >> 1;
92 }
93#endif
94
95 // Something like this might work, but it compiled larger than the block above
96 // bootloader_start = FLASH_SIZE - (256 << (~high_fuse & 0b110 >> 1));
97
98#if defined(BOOTLOADER_HALFKAY)
99 // http://www.pjrc.com/teensy/jump_to_bootloader.html
100 cli();
101 // disable watchdog, if enabled (it's not)
102 // disable all peripherals
103 // a shutdown call might make sense here
104 UDCON = 1;
105 USBCON = (1 << FRZCLK); // disable USB
106 UCSR1B = 0;
107 _delay_ms(5);
108# if defined(__AVR_AT90USB162__) // Teensy 1.0
109 EIMSK = 0;
110 PCICR = 0;
111 SPCR = 0;
112 ACSR = 0;
113 EECR = 0;
114 TIMSK0 = 0;
115 TIMSK1 = 0;
116 UCSR1B = 0;
117 DDRB = 0;
118 DDRC = 0;
119 DDRD = 0;
120 PORTB = 0;
121 PORTC = 0;
122 PORTD = 0;
123 asm volatile("jmp 0x3E00");
124# elif defined(__AVR_ATmega32U4__) // Teensy 2.0
125 EIMSK = 0;
126 PCICR = 0;
127 SPCR = 0;
128 ACSR = 0;
129 EECR = 0;
130 ADCSRA = 0;
131 TIMSK0 = 0;
132 TIMSK1 = 0;
133 TIMSK3 = 0;
134 TIMSK4 = 0;
135 UCSR1B = 0;
136 TWCR = 0;
137 DDRB = 0;
138 DDRC = 0;
139 DDRD = 0;
140 DDRE = 0;
141 DDRF = 0;
142 TWCR = 0;
143 PORTB = 0;
144 PORTC = 0;
145 PORTD = 0;
146 PORTE = 0;
147 PORTF = 0;
148 asm volatile("jmp 0x7E00");
149# elif defined(__AVR_AT90USB646__) // Teensy++ 1.0
150 EIMSK = 0;
151 PCICR = 0;
152 SPCR = 0;
153 ACSR = 0;
154 EECR = 0;
155 ADCSRA = 0;
156 TIMSK0 = 0;
157 TIMSK1 = 0;
158 TIMSK2 = 0;
159 TIMSK3 = 0;
160 UCSR1B = 0;
161 TWCR = 0;
162 DDRA = 0;
163 DDRB = 0;
164 DDRC = 0;
165 DDRD = 0;
166 DDRE = 0;
167 DDRF = 0;
168 PORTA = 0;
169 PORTB = 0;
170 PORTC = 0;
171 PORTD = 0;
172 PORTE = 0;
173 PORTF = 0;
174 asm volatile("jmp 0xFC00");
175# elif defined(__AVR_AT90USB1286__) // Teensy++ 2.0
176 EIMSK = 0;
177 PCICR = 0;
178 SPCR = 0;
179 ACSR = 0;
180 EECR = 0;
181 ADCSRA = 0;
182 TIMSK0 = 0;
183 TIMSK1 = 0;
184 TIMSK2 = 0;
185 TIMSK3 = 0;
186 UCSR1B = 0;
187 TWCR = 0;
188 DDRA = 0;
189 DDRB = 0;
190 DDRC = 0;
191 DDRD = 0;
192 DDRE = 0;
193 DDRF = 0;
194 PORTA = 0;
195 PORTB = 0;
196 PORTC = 0;
197 PORTD = 0;
198 PORTE = 0;
199 PORTF = 0;
200 asm volatile("jmp 0x1FC00");
201# endif
202
203#elif defined(BOOTLOADER_CATERINA)
204 // this block may be optional
205 // TODO: figure it out
206
207 uint16_t *const bootKeyPtr = (uint16_t *)0x0800;
208
209 // Value used by Caterina bootloader use to determine whether to run the
210 // sketch or the bootloader programmer.
211 uint16_t bootKey = 0x7777;
212
213 *bootKeyPtr = bootKey;
214
215 // setup watchdog timeout
216 wdt_enable(WDTO_60MS);
217
218 while (1) {
219 } // wait for watchdog timer to trigger
220
221#elif defined(BOOTLOADER_USBASP)
222 // Taken with permission of Stephan Baerwolf from https://github.com/tinyusbboard/API/blob/master/apipage.c
223 wdt_enable(WDTO_15MS);
224 wdt_reset();
225 asm volatile("cli \n\t"
226 "ldi r29 , %[ramendhi] \n\t"
227 "ldi r28 , %[ramendlo] \n\t"
228# if (FLASHEND > 131071)
229 "ldi r18 , %[bootaddrhi] \n\t"
230 "st Y+, r18 \n\t"
231# endif
232 "ldi r18 , %[bootaddrme] \n\t"
233 "st Y+, r18 \n\t"
234 "ldi r18 , %[bootaddrlo] \n\t"
235 "st Y+, r18 \n\t"
236 "out %[mcucsrio], __zero_reg__ \n\t"
237 "bootloader_startup_loop%=: \n\t"
238 "rjmp bootloader_startup_loop%= \n\t"
239 :
240 : [mcucsrio] "I"(_SFR_IO_ADDR(MCUCSR)),
241# if (FLASHEND > 131071)
242 [ramendhi] "M"(((RAMEND - 2) >> 8) & 0xff), [ramendlo] "M"(((RAMEND - 2) >> 0) & 0xff), [bootaddrhi] "M"((((FLASH_SIZE - BOOTLOADER_SIZE) >> 1) >> 16) & 0xff),
243# else
244 [ramendhi] "M"(((RAMEND - 1) >> 8) & 0xff), [ramendlo] "M"(((RAMEND - 1) >> 0) & 0xff),
245# endif
246 [bootaddrme] "M"((((FLASH_SIZE - BOOTLOADER_SIZE) >> 1) >> 8) & 0xff), [bootaddrlo] "M"((((FLASH_SIZE - BOOTLOADER_SIZE) >> 1) >> 0) & 0xff));
247
248#else // Assume remaining boards are DFU, even if the flag isn't set
249
250# if !(defined(__AVR_ATmega32A__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__) || defined(__AVR_ATtiny85__)) // no USB - maybe BOOTLOADER_BOOTLOADHID instead though?
251 UDCON = 1;
252 USBCON = (1 << FRZCLK); // disable USB
253 UCSR1B = 0;
254 _delay_ms(5); // 5 seems to work fine
255# endif
256
257# ifdef BOOTLOADER_BOOTLOADHID
258 // force bootloadHID to stay in bootloader mode, so that it waits
259 // for a new firmware to be flashed
260 eeprom_write_byte((uint8_t *)1, 0x00);
261# endif
262
263 // watchdog reset
264 reset_key = BOOTLOADER_RESET_KEY;
265 wdt_enable(WDTO_250MS);
266 for (;;)
267 ;
268#endif
269}
270
271/* this runs before main() */
272void bootloader_jump_after_watchdog_reset(void) __attribute__((used, naked, section(".init3")));
273void bootloader_jump_after_watchdog_reset(void) {
274#ifndef BOOTLOADER_HALFKAY
275 if ((MCUCSR & (1 << WDRF)) && reset_key == BOOTLOADER_RESET_KEY) {
276 reset_key = 0;
277
278 // My custom USBasploader requires this to come up.
279 MCUCSR = 0;
280
281 // Seems like Teensy halfkay loader requires clearing WDRF and disabling watchdog.
282 MCUCSR &= ~(1 << WDRF);
283 wdt_disable();
284
285// This is compled into 'icall', address should be in word unit, not byte.
286# ifdef BOOTLOADER_SIZE
287 ((void (*)(void))((FLASH_SIZE - BOOTLOADER_SIZE) >> 1))();
288# else
289 asm("ijmp" ::"z"(bootloader_start));
290# endif
291 }
292#endif
293}
diff --git a/platforms/avr/bootloader_size.c b/platforms/avr/bootloader_size.c
new file mode 100644
index 000000000..a029f9321
--- /dev/null
+++ b/platforms/avr/bootloader_size.c
@@ -0,0 +1,21 @@
1// Copyright 2017 Jack Humbert
2//
3// This program is free software: you can redistribute it and/or modify
4// it under the terms of the GNU General Public License as published by
5// the Free Software Foundation, either version 2 of the License, or
6// (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU General Public License
14// along with this program. If not, see <http://www.gnu.org/licenses/>.
15
16#include <avr/io.h>
17#include <avr/boot.h>
18
19// clang-format off
20// this is not valid C - it's for computing the size available on the chip
21AVR_SIZE: FLASHEND + 1 - BOOTLOADER_SIZE
diff --git a/platforms/avr/drivers/analog.c b/platforms/avr/drivers/analog.c
index 8d299ffdb..628835cce 100644
--- a/platforms/avr/drivers/analog.c
+++ b/platforms/avr/drivers/analog.c
@@ -23,29 +23,6 @@ static uint8_t aref = ADC_REF_POWER;
23 23
24void analogReference(uint8_t mode) { aref = mode & (_BV(REFS1) | _BV(REFS0)); } 24void analogReference(uint8_t mode) { aref = mode & (_BV(REFS1) | _BV(REFS0)); }
25 25
26// Arduino compatible pin input
27int16_t analogRead(uint8_t pin) {
28#if defined(__AVR_ATmega32U4__)
29 // clang-format off
30 static const uint8_t PROGMEM pin_to_mux[] = {
31 //A0 A1 A2 A3 A4 A5
32 //F7 F6 F5 F4 F1 F0
33 0x07, 0x06, 0x05, 0x04, 0x01, 0x00,
34 //A6 A7 A8 A9 A10 A11
35 //D4 D7 B4 B5 B6 D6
36 0x20, 0x22, 0x23, 0x24, 0x25, 0x21
37 };
38 // clang-format on
39 if (pin >= 12) return 0;
40 return adc_read(pgm_read_byte(pin_to_mux + pin));
41#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__)
42 if (pin >= 8) return 0;
43 return adc_read(pin);
44#else
45 return 0;
46#endif
47}
48
49int16_t analogReadPin(pin_t pin) { return adc_read(pinToMux(pin)); } 26int16_t analogReadPin(pin_t pin) { return adc_read(pinToMux(pin)); }
50 27
51uint8_t pinToMux(pin_t pin) { 28uint8_t pinToMux(pin_t pin) {
diff --git a/platforms/avr/drivers/analog.h b/platforms/avr/drivers/analog.h
index 058882450..fa2fb0d89 100644
--- a/platforms/avr/drivers/analog.h
+++ b/platforms/avr/drivers/analog.h
@@ -22,8 +22,7 @@
22#ifdef __cplusplus 22#ifdef __cplusplus
23extern "C" { 23extern "C" {
24#endif 24#endif
25void analogReference(uint8_t mode); 25void analogReference(uint8_t mode);
26int16_t analogRead(uint8_t pin);
27 26
28int16_t analogReadPin(pin_t pin); 27int16_t analogReadPin(pin_t pin);
29uint8_t pinToMux(pin_t pin); 28uint8_t pinToMux(pin_t pin);
diff --git a/platforms/avr/drivers/audio_pwm.h b/platforms/avr/drivers/audio_pwm.h
new file mode 100644
index 000000000..d6eb3571d
--- /dev/null
+++ b/platforms/avr/drivers/audio_pwm.h
@@ -0,0 +1,17 @@
1/* Copyright 2020 Jack Humbert
2 * Copyright 2020 JohSchneider
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17#pragma once
diff --git a/platforms/avr/drivers/audio_pwm_hardware.c b/platforms/avr/drivers/audio_pwm_hardware.c
new file mode 100644
index 000000000..df03a4558
--- /dev/null
+++ b/platforms/avr/drivers/audio_pwm_hardware.c
@@ -0,0 +1,332 @@
1/* Copyright 2016 Jack Humbert
2 * Copyright 2020 JohSchneider
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#if defined(__AVR__)
19# include <avr/pgmspace.h>
20# include <avr/interrupt.h>
21# include <avr/io.h>
22#endif
23
24#include "audio.h"
25
26extern bool playing_note;
27extern bool playing_melody;
28extern uint8_t note_timbre;
29
30#define CPU_PRESCALER 8
31
32/*
33 Audio Driver: PWM
34
35 drive up to two speakers through the AVR PWM hardware-peripheral, using timer1 and/or timer3 on Atmega32U4.
36
37 the primary channel_1 can be connected to either pin PC4 PC5 or PC6 (the later being used by most AVR based keyboards) with a PMW signal generated by timer3
38 and an optional secondary channel_2 on either pin PB5, PB6 or PB7, with a PWM signal from timer1
39
40 alternatively, the PWM pins on PORTB can be used as only/primary speaker
41*/
42
43#if defined(AUDIO_PIN) && (AUDIO_PIN != C4) && (AUDIO_PIN != C5) && (AUDIO_PIN != C6) && (AUDIO_PIN != B5) && (AUDIO_PIN != B6) && (AUDIO_PIN != B7) && (AUDIO_PIN != D5)
44# error "Audio feature enabled, but no suitable pin selected as AUDIO_PIN - see docs/feature_audio under the AVR settings for available options."
45#endif
46
47#if (AUDIO_PIN == C4) || (AUDIO_PIN == C5) || (AUDIO_PIN == C6)
48# define AUDIO1_PIN_SET
49# define AUDIO1_TIMSKx TIMSK3
50# define AUDIO1_TCCRxA TCCR3A
51# define AUDIO1_TCCRxB TCCR3B
52# define AUDIO1_ICRx ICR3
53# define AUDIO1_WGMx0 WGM30
54# define AUDIO1_WGMx1 WGM31
55# define AUDIO1_WGMx2 WGM32
56# define AUDIO1_WGMx3 WGM33
57# define AUDIO1_CSx0 CS30
58# define AUDIO1_CSx1 CS31
59# define AUDIO1_CSx2 CS32
60
61# if (AUDIO_PIN == C6)
62# define AUDIO1_COMxy0 COM3A0
63# define AUDIO1_COMxy1 COM3A1
64# define AUDIO1_OCIExy OCIE3A
65# define AUDIO1_OCRxy OCR3A
66# define AUDIO1_PIN C6
67# define AUDIO1_TIMERx_COMPy_vect TIMER3_COMPA_vect
68# elif (AUDIO_PIN == C5)
69# define AUDIO1_COMxy0 COM3B0
70# define AUDIO1_COMxy1 COM3B1
71# define AUDIO1_OCIExy OCIE3B
72# define AUDIO1_OCRxy OCR3B
73# define AUDIO1_PIN C5
74# define AUDIO1_TIMERx_COMPy_vect TIMER3_COMPB_vect
75# elif (AUDIO_PIN == C4)
76# define AUDIO1_COMxy0 COM3C0
77# define AUDIO1_COMxy1 COM3C1
78# define AUDIO1_OCIExy OCIE3C
79# define AUDIO1_OCRxy OCR3C
80# define AUDIO1_PIN C4
81# define AUDIO1_TIMERx_COMPy_vect TIMER3_COMPC_vect
82# endif
83#endif
84
85#if defined(AUDIO_PIN) && defined(AUDIO_PIN_ALT) && (AUDIO_PIN == AUDIO_PIN_ALT)
86# error "Audio feature: AUDIO_PIN and AUDIO_PIN_ALT on the same pin makes no sense."
87#endif
88
89#if ((AUDIO_PIN == B5) && ((AUDIO_PIN_ALT == B6) || (AUDIO_PIN_ALT == B7))) || ((AUDIO_PIN == B6) && ((AUDIO_PIN_ALT == B5) || (AUDIO_PIN_ALT == B7))) || ((AUDIO_PIN == B7) && ((AUDIO_PIN_ALT == B5) || (AUDIO_PIN_ALT == B6)))
90# error "Audio feature: PORTB as AUDIO_PIN and AUDIO_PIN_ALT at the same time is not supported."
91#endif
92
93#if defined(AUDIO_PIN_ALT) && (AUDIO_PIN_ALT != B5) && (AUDIO_PIN_ALT != B6) && (AUDIO_PIN_ALT != B7)
94# error "Audio feature: the pin selected as AUDIO_PIN_ALT is not supported."
95#endif
96
97#if (AUDIO_PIN == B5) || (AUDIO_PIN == B6) || (AUDIO_PIN == B7) || (AUDIO_PIN_ALT == B5) || (AUDIO_PIN_ALT == B6) || (AUDIO_PIN_ALT == B7) || (AUDIO_PIN == D5)
98# define AUDIO2_PIN_SET
99# define AUDIO2_TIMSKx TIMSK1
100# define AUDIO2_TCCRxA TCCR1A
101# define AUDIO2_TCCRxB TCCR1B
102# define AUDIO2_ICRx ICR1
103# define AUDIO2_WGMx0 WGM10
104# define AUDIO2_WGMx1 WGM11
105# define AUDIO2_WGMx2 WGM12
106# define AUDIO2_WGMx3 WGM13
107# define AUDIO2_CSx0 CS10
108# define AUDIO2_CSx1 CS11
109# define AUDIO2_CSx2 CS12
110
111# if (AUDIO_PIN == B5) || (AUDIO_PIN_ALT == B5)
112# define AUDIO2_COMxy0 COM1A0
113# define AUDIO2_COMxy1 COM1A1
114# define AUDIO2_OCIExy OCIE1A
115# define AUDIO2_OCRxy OCR1A
116# define AUDIO2_PIN B5
117# define AUDIO2_TIMERx_COMPy_vect TIMER1_COMPA_vect
118# elif (AUDIO_PIN == B6) || (AUDIO_PIN_ALT == B6)
119# define AUDIO2_COMxy0 COM1B0
120# define AUDIO2_COMxy1 COM1B1
121# define AUDIO2_OCIExy OCIE1B
122# define AUDIO2_OCRxy OCR1B
123# define AUDIO2_PIN B6
124# define AUDIO2_TIMERx_COMPy_vect TIMER1_COMPB_vect
125# elif (AUDIO_PIN == B7) || (AUDIO_PIN_ALT == B7)
126# define AUDIO2_COMxy0 COM1C0
127# define AUDIO2_COMxy1 COM1C1
128# define AUDIO2_OCIExy OCIE1C
129# define AUDIO2_OCRxy OCR1C
130# define AUDIO2_PIN B7
131# define AUDIO2_TIMERx_COMPy_vect TIMER1_COMPC_vect
132# elif (AUDIO_PIN == D5) && defined(__AVR_ATmega32A__)
133# pragma message "Audio support for ATmega32A is experimental and can cause crashes."
134# undef AUDIO2_TIMSKx
135# define AUDIO2_TIMSKx TIMSK
136# define AUDIO2_COMxy0 COM1A0
137# define AUDIO2_COMxy1 COM1A1
138# define AUDIO2_OCIExy OCIE1A
139# define AUDIO2_OCRxy OCR1A
140# define AUDIO2_PIN D5
141# define AUDIO2_TIMERx_COMPy_vect TIMER1_COMPA_vect
142# endif
143#endif
144
145// C6 seems to be the assumed default by many existing keyboard - but sill warn the user
146#if !defined(AUDIO1_PIN_SET) && !defined(AUDIO2_PIN_SET)
147# pragma message "Audio feature enabled, but no suitable pin selected - see docs/feature_audio under the AVR settings for available options. Don't expect to hear anything... :-)"
148// TODO: make this an error - go through the breaking-change-process and change all keyboards to the new define
149#endif
150// -----------------------------------------------------------------------------
151
152#ifdef AUDIO1_PIN_SET
153static float channel_1_frequency = 0.0f;
154void channel_1_set_frequency(float freq) {
155 if (freq == 0.0f) // a pause/rest is a valid "note" with freq=0
156 {
157 // disable the output, but keep the pwm-ISR going (with the previous
158 // frequency) so the audio-state keeps getting updated
159 // Note: setting the duty-cycle 0 is not possible on non-inverting PWM mode - see the AVR data-sheet
160 AUDIO1_TCCRxA &= ~(_BV(AUDIO1_COMxy1) | _BV(AUDIO1_COMxy0));
161 return;
162 } else {
163 AUDIO1_TCCRxA |= _BV(AUDIO1_COMxy1); // enable output, PWM mode
164 }
165
166 channel_1_frequency = freq;
167
168 // set pwm period
169 AUDIO1_ICRx = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER));
170 // and duty cycle
171 AUDIO1_OCRxy = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre / 100);
172}
173
174void channel_1_start(void) {
175 // enable timer-counter ISR
176 AUDIO1_TIMSKx |= _BV(AUDIO1_OCIExy);
177 // enable timer-counter output
178 AUDIO1_TCCRxA |= _BV(AUDIO1_COMxy1);
179}
180
181void channel_1_stop(void) {
182 // disable timer-counter ISR
183 AUDIO1_TIMSKx &= ~_BV(AUDIO1_OCIExy);
184 // disable timer-counter output
185 AUDIO1_TCCRxA &= ~(_BV(AUDIO1_COMxy1) | _BV(AUDIO1_COMxy0));
186}
187#endif
188
189#ifdef AUDIO2_PIN_SET
190static float channel_2_frequency = 0.0f;
191void channel_2_set_frequency(float freq) {
192 if (freq == 0.0f) {
193 AUDIO2_TCCRxA &= ~(_BV(AUDIO2_COMxy1) | _BV(AUDIO2_COMxy0));
194 return;
195 } else {
196 AUDIO2_TCCRxA |= _BV(AUDIO2_COMxy1);
197 }
198
199 channel_2_frequency = freq;
200
201 AUDIO2_ICRx = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER));
202 AUDIO2_OCRxy = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre / 100);
203}
204
205float channel_2_get_frequency(void) { return channel_2_frequency; }
206
207void channel_2_start(void) {
208 AUDIO2_TIMSKx |= _BV(AUDIO2_OCIExy);
209 AUDIO2_TCCRxA |= _BV(AUDIO2_COMxy1);
210}
211
212void channel_2_stop(void) {
213 AUDIO2_TIMSKx &= ~_BV(AUDIO2_OCIExy);
214 AUDIO2_TCCRxA &= ~(_BV(AUDIO2_COMxy1) | _BV(AUDIO2_COMxy0));
215}
216#endif
217
218void audio_driver_initialize() {
219#ifdef AUDIO1_PIN_SET
220 channel_1_stop();
221 setPinOutput(AUDIO1_PIN);
222#endif
223
224#ifdef AUDIO2_PIN_SET
225 channel_2_stop();
226 setPinOutput(AUDIO2_PIN);
227#endif
228
229 // TCCR3A / TCCR3B: Timer/Counter #3 Control Registers TCCR3A/TCCR3B, TCCR1A/TCCR1B
230 // Compare Output Mode (COM3An and COM1An) = 0b00 = Normal port operation
231 // OC3A -- PC6
232 // OC3B -- PC5
233 // OC3C -- PC4
234 // OC1A -- PB5
235 // OC1B -- PB6
236 // OC1C -- PB7
237
238 // Waveform Generation Mode (WGM3n) = 0b1110 = Fast PWM Mode 14. Period = ICR3, Duty Cycle OCR3A)
239 // OCR3A - PC6
240 // OCR3B - PC5
241 // OCR3C - PC4
242 // OCR1A - PB5
243 // OCR1B - PB6
244 // OCR1C - PB7
245
246 // Clock Select (CS3n) = 0b010 = Clock / 8
247#ifdef AUDIO1_PIN_SET
248 // initialize timer-counter
249 AUDIO1_TCCRxA = (0 << AUDIO1_COMxy1) | (0 << AUDIO1_COMxy0) | (1 << AUDIO1_WGMx1) | (0 << AUDIO1_WGMx0);
250 AUDIO1_TCCRxB = (1 << AUDIO1_WGMx3) | (1 << AUDIO1_WGMx2) | (0 << AUDIO1_CSx2) | (1 << AUDIO1_CSx1) | (0 << AUDIO1_CSx0);
251#endif
252
253#ifdef AUDIO2_PIN_SET
254 AUDIO2_TCCRxA = (0 << AUDIO2_COMxy1) | (0 << AUDIO2_COMxy0) | (1 << AUDIO2_WGMx1) | (0 << AUDIO2_WGMx0);
255 AUDIO2_TCCRxB = (1 << AUDIO2_WGMx3) | (1 << AUDIO2_WGMx2) | (0 << AUDIO2_CSx2) | (1 << AUDIO2_CSx1) | (0 << AUDIO2_CSx0);
256#endif
257}
258
259void audio_driver_stop() {
260#ifdef AUDIO1_PIN_SET
261 channel_1_stop();
262#endif
263
264#ifdef AUDIO2_PIN_SET
265 channel_2_stop();
266#endif
267}
268
269void audio_driver_start(void) {
270#ifdef AUDIO1_PIN_SET
271 channel_1_start();
272 if (playing_note) {
273 channel_1_set_frequency(audio_get_processed_frequency(0));
274 }
275#endif
276
277#if !defined(AUDIO1_PIN_SET) && defined(AUDIO2_PIN_SET)
278 channel_2_start();
279 if (playing_note) {
280 channel_2_set_frequency(audio_get_processed_frequency(0));
281 }
282#endif
283}
284
285static volatile uint32_t isr_counter = 0;
286#ifdef AUDIO1_PIN_SET
287ISR(AUDIO1_TIMERx_COMPy_vect) {
288 isr_counter++;
289 if (isr_counter < channel_1_frequency / (CPU_PRESCALER * 8)) return;
290
291 isr_counter = 0;
292 bool state_changed = audio_update_state();
293
294 if (!playing_note && !playing_melody) {
295 channel_1_stop();
296# ifdef AUDIO2_PIN_SET
297 channel_2_stop();
298# endif
299 return;
300 }
301
302 if (state_changed) {
303 channel_1_set_frequency(audio_get_processed_frequency(0));
304# ifdef AUDIO2_PIN_SET
305 if (audio_get_number_of_active_tones() > 1) {
306 channel_2_set_frequency(audio_get_processed_frequency(1));
307 } else {
308 channel_2_stop();
309 }
310# endif
311 }
312}
313#endif
314
315#if !defined(AUDIO1_PIN_SET) && defined(AUDIO2_PIN_SET)
316ISR(AUDIO2_TIMERx_COMPy_vect) {
317 isr_counter++;
318 if (isr_counter < channel_2_frequency / (CPU_PRESCALER * 8)) return;
319
320 isr_counter = 0;
321 bool state_changed = audio_update_state();
322
323 if (!playing_note && !playing_melody) {
324 channel_2_stop();
325 return;
326 }
327
328 if (state_changed) {
329 channel_2_set_frequency(audio_get_processed_frequency(0));
330 }
331}
332#endif
diff --git a/platforms/avr/drivers/i2c_master.c b/platforms/avr/drivers/i2c_master.c
index 2773e0077..111b55d6b 100644
--- a/platforms/avr/drivers/i2c_master.c
+++ b/platforms/avr/drivers/i2c_master.c
@@ -202,6 +202,25 @@ i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data,
202 return status; 202 return status;
203} 203}
204 204
205i2c_status_t i2c_writeReg16(uint8_t devaddr, uint16_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout) {
206 i2c_status_t status = i2c_start(devaddr | 0x00, timeout);
207 if (status >= 0) {
208 status = i2c_write(regaddr >> 8, timeout);
209
210 if (status >= 0) {
211 status = i2c_write(regaddr & 0xFF, timeout);
212
213 for (uint16_t i = 0; i < length && status >= 0; i++) {
214 status = i2c_write(data[i], timeout);
215 }
216 }
217 }
218
219 i2c_stop();
220
221 return status;
222}
223
205i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) { 224i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) {
206 i2c_status_t status = i2c_start(devaddr, timeout); 225 i2c_status_t status = i2c_start(devaddr, timeout);
207 if (status < 0) { 226 if (status < 0) {
@@ -235,6 +254,43 @@ error:
235 return (status < 0) ? status : I2C_STATUS_SUCCESS; 254 return (status < 0) ? status : I2C_STATUS_SUCCESS;
236} 255}
237 256
257i2c_status_t i2c_readReg16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) {
258 i2c_status_t status = i2c_start(devaddr, timeout);
259 if (status < 0) {
260 goto error;
261 }
262
263 status = i2c_write(regaddr >> 8, timeout);
264 if (status < 0) {
265 goto error;
266 }
267 status = i2c_write(regaddr & 0xFF, timeout);
268 if (status < 0) {
269 goto error;
270 }
271
272 status = i2c_start(devaddr | 0x01, timeout);
273
274 for (uint16_t i = 0; i < (length - 1) && status >= 0; i++) {
275 status = i2c_read_ack(timeout);
276 if (status >= 0) {
277 data[i] = status;
278 }
279 }
280
281 if (status >= 0) {
282 status = i2c_read_nack(timeout);
283 if (status >= 0) {
284 data[(length - 1)] = status;
285 }
286 }
287
288error:
289 i2c_stop();
290
291 return (status < 0) ? status : I2C_STATUS_SUCCESS;
292}
293
238void i2c_stop(void) { 294void i2c_stop(void) {
239 // transmit STOP condition 295 // transmit STOP condition
240 TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO); 296 TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);
diff --git a/platforms/avr/drivers/i2c_master.h b/platforms/avr/drivers/i2c_master.h
index e5af73364..2d95846db 100644
--- a/platforms/avr/drivers/i2c_master.h
+++ b/platforms/avr/drivers/i2c_master.h
@@ -39,5 +39,7 @@ int16_t i2c_read_nack(uint16_t timeout);
39i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout); 39i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout);
40i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout); 40i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout);
41i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout); 41i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout);
42i2c_status_t i2c_writeReg16(uint8_t devaddr, uint16_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout);
42i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout); 43i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);
44i2c_status_t i2c_readReg16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);
43void i2c_stop(void); 45void i2c_stop(void);
diff --git a/platforms/avr/drivers/ps2/ps2_io.c b/platforms/avr/drivers/ps2/ps2_io.c
new file mode 100644
index 000000000..7c826fbf1
--- /dev/null
+++ b/platforms/avr/drivers/ps2/ps2_io.c
@@ -0,0 +1,51 @@
1#include <stdbool.h>
2#include "ps2_io.h"
3#include "gpio.h"
4#include "wait.h"
5
6/* Check port settings for clock and data line */
7#if !(defined(PS2_CLOCK_PIN))
8# error "PS/2 clock setting is required in config.h"
9#endif
10
11#if !(defined(PS2_DATA_PIN))
12# error "PS/2 data setting is required in config.h"
13#endif
14
15/*
16 * Clock
17 */
18void clock_init(void) {}
19
20void clock_lo(void) {
21 // Transition from input with pull-up to output low via Hi-Z instead of output high
22 writePinLow(PS2_CLOCK_PIN);
23 setPinOutput(PS2_CLOCK_PIN);
24}
25
26void clock_hi(void) { setPinInputHigh(PS2_CLOCK_PIN); }
27
28bool clock_in(void) {
29 setPinInputHigh(PS2_CLOCK_PIN);
30 wait_us(1);
31 return readPin(PS2_CLOCK_PIN);
32}
33
34/*
35 * Data
36 */
37void data_init(void) {}
38
39void data_lo(void) {
40 // Transition from input with pull-up to output low via Hi-Z instead of output high
41 writePinLow(PS2_DATA_PIN);
42 setPinOutput(PS2_DATA_PIN);
43}
44
45void data_hi(void) { setPinInputHigh(PS2_DATA_PIN); }
46
47bool data_in(void) {
48 setPinInputHigh(PS2_DATA_PIN);
49 wait_us(1);
50 return readPin(PS2_DATA_PIN);
51}
diff --git a/platforms/avr/drivers/ps2/ps2_usart.c b/platforms/avr/drivers/ps2/ps2_usart.c
new file mode 100644
index 000000000..151cfcd68
--- /dev/null
+++ b/platforms/avr/drivers/ps2/ps2_usart.c
@@ -0,0 +1,227 @@
1/*
2Copyright 2010,2011,2012,2013 Jun WAKO <wakojun@gmail.com>
3
4This software is licensed with a Modified BSD License.
5All of this is supposed to be Free Software, Open Source, DFSG-free,
6GPL-compatible, and OK to use in both free and proprietary applications.
7Additions and corrections to this file are welcome.
8
9
10Redistribution and use in source and binary forms, with or without
11modification, are permitted provided that the following conditions are met:
12
13* Redistributions of source code must retain the above copyright
14 notice, this list of conditions and the following disclaimer.
15
16* Redistributions in binary form must reproduce the above copyright
17 notice, this list of conditions and the following disclaimer in
18 the documentation and/or other materials provided with the
19 distribution.
20
21* Neither the name of the copyright holders nor the names of
22 contributors may be used to endorse or promote products derived
23 from this software without specific prior written permission.
24
25THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
29LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35POSSIBILITY OF SUCH DAMAGE.
36*/
37
38/*
39 * PS/2 protocol USART version
40 */
41
42#include <stdbool.h>
43#include <avr/interrupt.h>
44#include <util/delay.h>
45#include "gpio.h"
46#include "ps2.h"
47#include "ps2_io.h"
48#include "print.h"
49
50#ifndef PS2_CLOCK_DDR
51# define PS2_CLOCK_DDR PORTx_ADDRESS(PS2_CLOCK_PIN)
52#endif
53#ifndef PS2_CLOCK_BIT
54# define PS2_CLOCK_BIT (PS2_CLOCK_PIN & 0xF)
55#endif
56#ifndef PS2_DATA_DDR
57# define PS2_DATA_DDR PORTx_ADDRESS(PS2_DATA_PIN)
58#endif
59#ifndef PS2_DATA_BIT
60# define PS2_DATA_BIT (PS2_DATA_PIN & 0xF)
61#endif
62
63#define WAIT(stat, us, err) \
64 do { \
65 if (!wait_##stat(us)) { \
66 ps2_error = err; \
67 goto ERROR; \
68 } \
69 } while (0)
70
71uint8_t ps2_error = PS2_ERR_NONE;
72
73static inline uint8_t pbuf_dequeue(void);
74static inline void pbuf_enqueue(uint8_t data);
75static inline bool pbuf_has_data(void);
76static inline void pbuf_clear(void);
77
78void ps2_host_init(void) {
79 idle(); // without this many USART errors occur when cable is disconnected
80 PS2_USART_INIT();
81 PS2_USART_RX_INT_ON();
82 // POR(150-2000ms) plus BAT(300-500ms) may take 2.5sec([3]p.20)
83 //_delay_ms(2500);
84}
85
86uint8_t ps2_host_send(uint8_t data) {
87 bool parity = true;
88 ps2_error = PS2_ERR_NONE;
89
90 PS2_USART_OFF();
91
92 /* terminate a transmission if we have */
93 inhibit();
94 _delay_us(100); // [4]p.13
95
96 /* 'Request to Send' and Start bit */
97 data_lo();
98 clock_hi();
99 WAIT(clock_lo, 10000, 10); // 10ms [5]p.50
100
101 /* Data bit[2-9] */
102 for (uint8_t i = 0; i < 8; i++) {
103 _delay_us(15);
104 if (data & (1 << i)) {
105 parity = !parity;
106 data_hi();
107 } else {
108 data_lo();
109 }
110 WAIT(clock_hi, 50, 2);
111 WAIT(clock_lo, 50, 3);
112 }
113
114 /* Parity bit */
115 _delay_us(15);
116 if (parity) {
117 data_hi();
118 } else {
119 data_lo();
120 }
121 WAIT(clock_hi, 50, 4);
122 WAIT(clock_lo, 50, 5);
123
124 /* Stop bit */
125 _delay_us(15);
126 data_hi();
127
128 /* Ack */
129 WAIT(data_lo, 50, 6);
130 WAIT(clock_lo, 50, 7);
131
132 /* wait for idle state */
133 WAIT(clock_hi, 50, 8);
134 WAIT(data_hi, 50, 9);
135
136 idle();
137 PS2_USART_INIT();
138 PS2_USART_RX_INT_ON();
139 return ps2_host_recv_response();
140ERROR:
141 idle();
142 PS2_USART_INIT();
143 PS2_USART_RX_INT_ON();
144 return 0;
145}
146
147uint8_t ps2_host_recv_response(void) {
148 // Command may take 25ms/20ms at most([5]p.46, [3]p.21)
149 uint8_t retry = 25;
150 while (retry-- && !pbuf_has_data()) {
151 _delay_ms(1);
152 }
153 return pbuf_dequeue();
154}
155
156uint8_t ps2_host_recv(void) {
157 if (pbuf_has_data()) {
158 ps2_error = PS2_ERR_NONE;
159 return pbuf_dequeue();
160 } else {
161 ps2_error = PS2_ERR_NODATA;
162 return 0;
163 }
164}
165
166ISR(PS2_USART_RX_VECT) {
167 // TODO: request RESEND when error occurs?
168 uint8_t error = PS2_USART_ERROR; // USART error should be read before data
169 uint8_t data = PS2_USART_RX_DATA;
170 if (!error) {
171 pbuf_enqueue(data);
172 } else {
173 xprintf("PS2 USART error: %02X data: %02X\n", error, data);
174 }
175}
176
177/* send LED state to keyboard */
178void ps2_host_set_led(uint8_t led) {
179 ps2_host_send(0xED);
180 ps2_host_send(led);
181}
182
183/*--------------------------------------------------------------------
184 * Ring buffer to store scan codes from keyboard
185 *------------------------------------------------------------------*/
186#define PBUF_SIZE 32
187static uint8_t pbuf[PBUF_SIZE];
188static uint8_t pbuf_head = 0;
189static uint8_t pbuf_tail = 0;
190static inline void pbuf_enqueue(uint8_t data) {
191 uint8_t sreg = SREG;
192 cli();
193 uint8_t next = (pbuf_head + 1) % PBUF_SIZE;
194 if (next != pbuf_tail) {
195 pbuf[pbuf_head] = data;
196 pbuf_head = next;
197 } else {
198 print("pbuf: full\n");
199 }
200 SREG = sreg;
201}
202static inline uint8_t pbuf_dequeue(void) {
203 uint8_t val = 0;
204
205 uint8_t sreg = SREG;
206 cli();
207 if (pbuf_head != pbuf_tail) {
208 val = pbuf[pbuf_tail];
209 pbuf_tail = (pbuf_tail + 1) % PBUF_SIZE;
210 }
211 SREG = sreg;
212
213 return val;
214}
215static inline bool pbuf_has_data(void) {
216 uint8_t sreg = SREG;
217 cli();
218 bool has_data = (pbuf_head != pbuf_tail);
219 SREG = sreg;
220 return has_data;
221}
222static inline void pbuf_clear(void) {
223 uint8_t sreg = SREG;
224 cli();
225 pbuf_head = pbuf_tail = 0;
226 SREG = sreg;
227}
diff --git a/platforms/avr/drivers/uart.c b/platforms/avr/drivers/uart.c
index c6abcb6fe..01cf6b1fb 100644
--- a/platforms/avr/drivers/uart.c
+++ b/platforms/avr/drivers/uart.c
@@ -100,7 +100,7 @@ void uart_init(uint32_t baud) {
100} 100}
101 101
102// Transmit a byte 102// Transmit a byte
103void uart_putchar(uint8_t c) { 103void uart_write(uint8_t data) {
104 uint8_t i; 104 uint8_t i;
105 105
106 i = tx_buffer_head + 1; 106 i = tx_buffer_head + 1;
@@ -110,27 +110,39 @@ void uart_putchar(uint8_t c) {
110 while (tx_buffer_tail == i) 110 while (tx_buffer_tail == i)
111 ; // wait until space in buffer 111 ; // wait until space in buffer
112 // cli(); 112 // cli();
113 tx_buffer[i] = c; 113 tx_buffer[i] = data;
114 tx_buffer_head = i; 114 tx_buffer_head = i;
115 UCSRnB = (1 << RXENn) | (1 << TXENn) | (1 << RXCIEn) | (1 << UDRIEn); 115 UCSRnB = (1 << RXENn) | (1 << TXENn) | (1 << RXCIEn) | (1 << UDRIEn);
116 // sei(); 116 // sei();
117} 117}
118 118
119// Receive a byte 119// Receive a byte
120uint8_t uart_getchar(void) { 120uint8_t uart_read(void) {
121 uint8_t c, i; 121 uint8_t data, i;
122 122
123 while (rx_buffer_head == rx_buffer_tail) 123 while (rx_buffer_head == rx_buffer_tail)
124 ; // wait for character 124 ; // wait for character
125 i = rx_buffer_tail + 1; 125 i = rx_buffer_tail + 1;
126 if (i >= RX_BUFFER_SIZE) i = 0; 126 if (i >= RX_BUFFER_SIZE) i = 0;
127 c = rx_buffer[i]; 127 data = rx_buffer[i];
128 rx_buffer_tail = i; 128 rx_buffer_tail = i;
129 return c; 129 return data;
130}
131
132void uart_transmit(const uint8_t *data, uint16_t length) {
133 for (uint16_t i = 0; i < length; i++) {
134 uart_write(data[i]);
135 }
136}
137
138void uart_receive(uint8_t *data, uint16_t length) {
139 for (uint16_t i = 0; i < length; i++) {
140 data[i] = uart_read();
141 }
130} 142}
131 143
132// Return whether the number of bytes waiting in the receive buffer is nonzero. 144// Return whether the number of bytes waiting in the receive buffer is nonzero.
133// Call this before uart_getchar() to check if it will need 145// Call this before uart_read() to check if it will need
134// to wait for a byte to arrive. 146// to wait for a byte to arrive.
135bool uart_available(void) { 147bool uart_available(void) {
136 uint8_t head, tail; 148 uint8_t head, tail;
diff --git a/platforms/avr/drivers/uart.h b/platforms/avr/drivers/uart.h
index 602eb3d8b..e2dc664ed 100644
--- a/platforms/avr/drivers/uart.h
+++ b/platforms/avr/drivers/uart.h
@@ -28,8 +28,12 @@
28 28
29void uart_init(uint32_t baud); 29void uart_init(uint32_t baud);
30 30
31void uart_putchar(uint8_t c); 31void uart_write(uint8_t data);
32 32
33uint8_t uart_getchar(void); 33uint8_t uart_read(void);
34
35void uart_transmit(const uint8_t *data, uint16_t length);
36
37void uart_receive(uint8_t *data, uint16_t length);
34 38
35bool uart_available(void); 39bool uart_available(void);
diff --git a/platforms/avr/flash.mk b/platforms/avr/flash.mk
index 985cb60e5..6d50e7253 100644
--- a/platforms/avr/flash.mk
+++ b/platforms/avr/flash.mk
@@ -130,6 +130,15 @@ avrdude-split-right: $(BUILD_DIR)/$(TARGET).hex check-size cpfirmware
130 $(call EXEC_AVRDUDE,eeprom-righthand.eep) 130 $(call EXEC_AVRDUDE,eeprom-righthand.eep)
131 131
132define EXEC_USBASP 132define EXEC_USBASP
133 if $(AVRDUDE_PROGRAMMER) -p $(AVRDUDE_MCU) -c usbasp 2>&1 | grep -q "could not find USB device with"; then \
134 printf "$(MSG_BOOTLOADER_NOT_FOUND_QUICK_RETRY)" ;\
135 sleep $(BOOTLOADER_RETRY_TIME) ;\
136 until $(AVRDUDE_PROGRAMMER) -p $(AVRDUDE_MCU) -c usbasp 2>&1 | (! grep -q "could not find USB device with"); do\
137 printf "." ;\
138 sleep $(BOOTLOADER_RETRY_TIME) ;\
139 done ;\
140 printf "\n" ;\
141 fi
133 $(AVRDUDE_PROGRAMMER) -p $(AVRDUDE_MCU) -c usbasp -U flash:w:$(BUILD_DIR)/$(TARGET).hex 142 $(AVRDUDE_PROGRAMMER) -p $(AVRDUDE_MCU) -c usbasp -U flash:w:$(BUILD_DIR)/$(TARGET).hex
134endef 143endef
135 144
diff --git a/platforms/avr/gpio.h b/platforms/avr/gpio.h
new file mode 100644
index 000000000..e9be68491
--- /dev/null
+++ b/platforms/avr/gpio.h
@@ -0,0 +1,49 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#pragma once
17
18#include <avr/io.h>
19#include "pin_defs.h"
20
21typedef uint8_t pin_t;
22
23/* Operation of GPIO by pin. */
24
25#define setPinInput(pin) (DDRx_ADDRESS(pin) &= ~_BV((pin)&0xF), PORTx_ADDRESS(pin) &= ~_BV((pin)&0xF))
26#define setPinInputHigh(pin) (DDRx_ADDRESS(pin) &= ~_BV((pin)&0xF), PORTx_ADDRESS(pin) |= _BV((pin)&0xF))
27#define setPinInputLow(pin) _Static_assert(0, "AVR processors cannot implement an input as pull low")
28#define setPinOutput(pin) (DDRx_ADDRESS(pin) |= _BV((pin)&0xF))
29
30#define writePinHigh(pin) (PORTx_ADDRESS(pin) |= _BV((pin)&0xF))
31#define writePinLow(pin) (PORTx_ADDRESS(pin) &= ~_BV((pin)&0xF))
32#define writePin(pin, level) ((level) ? writePinHigh(pin) : writePinLow(pin))
33
34#define readPin(pin) ((bool)(PINx_ADDRESS(pin) & _BV((pin)&0xF)))
35
36#define togglePin(pin) (PORTx_ADDRESS(pin) ^= _BV((pin)&0xF))
37
38/* Operation of GPIO by port. */
39
40typedef uint8_t port_data_t;
41
42#define readPort(port) PINx_ADDRESS(port)
43
44#define setPortBitInput(port, bit) (DDRx_ADDRESS(port) &= ~_BV((bit)&0xF), PORTx_ADDRESS(port) &= ~_BV((bit)&0xF))
45#define setPortBitInputHigh(port, bit) (DDRx_ADDRESS(port) &= ~_BV((bit)&0xF), PORTx_ADDRESS(port) |= _BV((bit)&0xF))
46#define setPortBitOutput(port, bit) (DDRx_ADDRESS(port) |= _BV((bit)&0xF))
47
48#define writePortBitLow(port, bit) (PORTx_ADDRESS(port) &= ~_BV((bit)&0xF))
49#define writePortBitHigh(port, bit) (PORTx_ADDRESS(port) |= _BV((bit)&0xF))
diff --git a/platforms/avr/pin_defs.h b/platforms/avr/pin_defs.h
new file mode 100644
index 000000000..23d948041
--- /dev/null
+++ b/platforms/avr/pin_defs.h
@@ -0,0 +1,128 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#pragma once
17
18#include <avr/io.h>
19
20#define PORT_SHIFTER 4 // this may be 4 for all AVR chips
21
22// If you want to add more to this list, reference the PINx definitions in these header
23// files: https://github.com/vancegroup-mirrors/avr-libc/tree/master/avr-libc/include/avr
24
25#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega16U4__)
26# define ADDRESS_BASE 0x00
27# define PINB_ADDRESS 0x3
28# define PINC_ADDRESS 0x6
29# define PIND_ADDRESS 0x9
30# define PINE_ADDRESS 0xC
31# define PINF_ADDRESS 0xF
32#elif defined(__AVR_AT90USB162__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__)
33# define ADDRESS_BASE 0x00
34# define PINB_ADDRESS 0x3
35# define PINC_ADDRESS 0x6
36# define PIND_ADDRESS 0x9
37#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__)
38# define ADDRESS_BASE 0x00
39# define PINA_ADDRESS 0x0
40# define PINB_ADDRESS 0x3
41# define PINC_ADDRESS 0x6
42# define PIND_ADDRESS 0x9
43# define PINE_ADDRESS 0xC
44# define PINF_ADDRESS 0xF
45#elif defined(__AVR_ATmega32A__)
46# define ADDRESS_BASE 0x10
47# define PIND_ADDRESS 0x0
48# define PINC_ADDRESS 0x3
49# define PINB_ADDRESS 0x6
50# define PINA_ADDRESS 0x9
51#elif defined(__AVR_ATtiny85__)
52# define ADDRESS_BASE 0x10
53# define PINB_ADDRESS 0x6
54#else
55# error "Pins are not defined"
56#endif
57
58#define PINDEF(port, pin) ((PIN##port##_ADDRESS << PORT_SHIFTER) | pin)
59
60#define _PIN_ADDRESS(p, offset) _SFR_IO8(ADDRESS_BASE + ((p) >> PORT_SHIFTER) + (offset))
61// Port X Input Pins Address
62#define PINx_ADDRESS(p) _PIN_ADDRESS(p, 0)
63// Port X Data Direction Register, 0:input 1:output
64#define DDRx_ADDRESS(p) _PIN_ADDRESS(p, 1)
65// Port X Data Register
66#define PORTx_ADDRESS(p) _PIN_ADDRESS(p, 2)
67
68/* I/O pins */
69#ifdef PORTA
70# define A0 PINDEF(A, 0)
71# define A1 PINDEF(A, 1)
72# define A2 PINDEF(A, 2)
73# define A3 PINDEF(A, 3)
74# define A4 PINDEF(A, 4)
75# define A5 PINDEF(A, 5)
76# define A6 PINDEF(A, 6)
77# define A7 PINDEF(A, 7)
78#endif
79#ifdef PORTB
80# define B0 PINDEF(B, 0)
81# define B1 PINDEF(B, 1)
82# define B2 PINDEF(B, 2)
83# define B3 PINDEF(B, 3)
84# define B4 PINDEF(B, 4)
85# define B5 PINDEF(B, 5)
86# define B6 PINDEF(B, 6)
87# define B7 PINDEF(B, 7)
88#endif
89#ifdef PORTC
90# define C0 PINDEF(C, 0)
91# define C1 PINDEF(C, 1)
92# define C2 PINDEF(C, 2)
93# define C3 PINDEF(C, 3)
94# define C4 PINDEF(C, 4)
95# define C5 PINDEF(C, 5)
96# define C6 PINDEF(C, 6)
97# define C7 PINDEF(C, 7)
98#endif
99#ifdef PORTD
100# define D0 PINDEF(D, 0)
101# define D1 PINDEF(D, 1)
102# define D2 PINDEF(D, 2)
103# define D3 PINDEF(D, 3)
104# define D4 PINDEF(D, 4)
105# define D5 PINDEF(D, 5)
106# define D6 PINDEF(D, 6)
107# define D7 PINDEF(D, 7)
108#endif
109#ifdef PORTE
110# define E0 PINDEF(E, 0)
111# define E1 PINDEF(E, 1)
112# define E2 PINDEF(E, 2)
113# define E3 PINDEF(E, 3)
114# define E4 PINDEF(E, 4)
115# define E5 PINDEF(E, 5)
116# define E6 PINDEF(E, 6)
117# define E7 PINDEF(E, 7)
118#endif
119#ifdef PORTF
120# define F0 PINDEF(F, 0)
121# define F1 PINDEF(F, 1)
122# define F2 PINDEF(F, 2)
123# define F3 PINDEF(F, 3)
124# define F4 PINDEF(F, 4)
125# define F5 PINDEF(F, 5)
126# define F6 PINDEF(F, 6)
127# define F7 PINDEF(F, 7)
128#endif
diff --git a/platforms/avr/platform.c b/platforms/avr/platform.c
new file mode 100644
index 000000000..3e35b4fe4
--- /dev/null
+++ b/platforms/avr/platform.c
@@ -0,0 +1,21 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "platform_deps.h"
18
19void platform_setup(void) {
20 // do nothing
21}
diff --git a/platforms/avr/platform.mk b/platforms/avr/platform.mk
new file mode 100644
index 000000000..b45108736
--- /dev/null
+++ b/platforms/avr/platform.mk
@@ -0,0 +1,179 @@
1# Hey Emacs, this is a -*- makefile -*-
2##############################################################################
3# Compiler settings
4#
5CC = $(CC_PREFIX) avr-gcc
6OBJCOPY = avr-objcopy
7OBJDUMP = avr-objdump
8SIZE = avr-size
9AR = avr-ar
10NM = avr-nm
11HEX = $(OBJCOPY) -O $(FORMAT) -R .eeprom -R .fuse -R .lock -R .signature
12EEP = $(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT)
13BIN =
14
15COMPILEFLAGS += -funsigned-char
16COMPILEFLAGS += -funsigned-bitfields
17COMPILEFLAGS += -ffunction-sections
18COMPILEFLAGS += -fdata-sections
19COMPILEFLAGS += -fpack-struct
20COMPILEFLAGS += -fshort-enums
21
22ASFLAGS += $(AVR_ASFLAGS)
23
24CFLAGS += $(COMPILEFLAGS) $(AVR_CFLAGS)
25CFLAGS += -fno-inline-small-functions
26CFLAGS += -fno-strict-aliasing
27
28CXXFLAGS += $(COMPILEFLAGS)
29CXXFLAGS += -fno-exceptions -std=c++11
30
31LDFLAGS +=-Wl,--gc-sections
32
33OPT_DEFS += -DF_CPU=$(F_CPU)UL
34
35MCUFLAGS = -mmcu=$(MCU)
36
37# List any extra directories to look for libraries here.
38# Each directory must be seperated by a space.
39# Use forward slashes for directory separators.
40# For a directory that has spaces, enclose it in quotes.
41EXTRALIBDIRS =
42
43
44#---------------- External Memory Options ----------------
45
46# 64 KB of external RAM, starting after internal RAM (ATmega128!),
47# used for variables (.data/.bss) and heap (malloc()).
48#EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff
49
50# 64 KB of external RAM, starting after internal RAM (ATmega128!),
51# only used for heap (malloc()).
52#EXTMEMOPTS = -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x80ffff
53
54EXTMEMOPTS =
55
56#---------------- Debugging Options ----------------
57
58# Debugging format.
59# Native formats for AVR-GCC's -g are dwarf-2 [default] or stabs.
60# AVR Studio 4.10 requires dwarf-2.
61# AVR [Extended] COFF format requires stabs, plus an avr-objcopy run.
62DEBUG = dwarf-2
63
64# For simulavr only - target MCU frequency.
65DEBUG_MFREQ = $(F_CPU)
66
67# Set the DEBUG_UI to either gdb or insight.
68# DEBUG_UI = gdb
69DEBUG_UI = insight
70
71# Set the debugging back-end to either avarice, simulavr.
72DEBUG_BACKEND = avarice
73#DEBUG_BACKEND = simulavr
74
75# GDB Init Filename.
76GDBINIT_FILE = __avr_gdbinit
77
78# When using avarice settings for the JTAG
79JTAG_DEV = /dev/com1
80
81# Debugging port used to communicate between GDB / avarice / simulavr.
82DEBUG_PORT = 4242
83
84# Debugging host used to communicate between GDB / avarice / simulavr, normally
85# just set to localhost unless doing some sort of crazy debugging when
86# avarice is running on a different computer.
87DEBUG_HOST = localhost
88
89#============================================================================
90
91# Convert hex to bin.
92bin: $(BUILD_DIR)/$(TARGET).hex
93ifeq ($(BOOTLOADER),lufa-ms)
94 $(eval BIN_PADDING=$(shell n=`expr 32768 - $(BOOTLOADER_SIZE)` && echo $$(($$n)) || echo 0))
95 $(OBJCOPY) -Iihex -Obinary $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin --pad-to $(BIN_PADDING)
96else
97 $(OBJCOPY) -Iihex -Obinary $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin
98endif
99 $(COPY) $(BUILD_DIR)/$(TARGET).bin $(TARGET).bin;
100
101# copy bin to FLASH.bin
102flashbin: bin
103 $(COPY) $(BUILD_DIR)/$(TARGET).bin FLASH.bin;
104
105# Generate avr-gdb config/init file which does the following:
106# define the reset signal, load the target file, connect to target, and set
107# a breakpoint at main().
108gdb-config:
109 @$(REMOVE) $(GDBINIT_FILE)
110 @echo define reset >> $(GDBINIT_FILE)
111 @echo SIGNAL SIGHUP >> $(GDBINIT_FILE)
112 @echo end >> $(GDBINIT_FILE)
113 @echo file $(BUILD_DIR)/$(TARGET).elf >> $(GDBINIT_FILE)
114 @echo target remote $(DEBUG_HOST):$(DEBUG_PORT) >> $(GDBINIT_FILE)
115ifeq ($(DEBUG_BACKEND),simulavr)
116 @echo load >> $(GDBINIT_FILE)
117endif
118 @echo break main >> $(GDBINIT_FILE)
119
120debug: gdb-config $(BUILD_DIR)/$(TARGET).elf
121ifeq ($(DEBUG_BACKEND), avarice)
122 @echo Starting AVaRICE - Press enter when "waiting to connect" message displays.
123 @$(WINSHELL) /c start avarice --jtag $(JTAG_DEV) --erase --program --file \
124 $(BUILD_DIR)/$(TARGET).elf $(DEBUG_HOST):$(DEBUG_PORT)
125 @$(WINSHELL) /c pause
126
127else
128 @$(WINSHELL) /c start simulavr --gdbserver --device $(MCU) --clock-freq \
129 $(DEBUG_MFREQ) --port $(DEBUG_PORT)
130endif
131 @$(WINSHELL) /c start avr-$(DEBUG_UI) --command=$(GDBINIT_FILE)
132
133
134
135
136# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
137COFFCONVERT = $(OBJCOPY) --debugging
138COFFCONVERT += --change-section-address .data-0x800000
139COFFCONVERT += --change-section-address .bss-0x800000
140COFFCONVERT += --change-section-address .noinit-0x800000
141COFFCONVERT += --change-section-address .eeprom-0x810000
142
143
144
145coff: $(BUILD_DIR)/$(TARGET).elf
146 @$(SECHO) $(MSG_COFF) $(BUILD_DIR)/$(TARGET).cof
147 $(COFFCONVERT) -O coff-avr $< $(BUILD_DIR)/$(TARGET).cof
148
149
150extcoff: $(BUILD_DIR)/$(TARGET).elf
151 @$(SECHO) $(MSG_EXTENDED_COFF) $(BUILD_DIR)/$(TARGET).cof
152 $(COFFCONVERT) -O coff-ext-avr $< $(BUILD_DIR)/$(TARGET).cof
153
154ifeq ($(strip $(BOOTLOADER)), qmk-dfu)
155QMK_BOOTLOADER_TYPE = DFU
156else ifeq ($(strip $(BOOTLOADER)), qmk-hid)
157QMK_BOOTLOADER_TYPE = HID
158endif
159
160bootloader:
161ifeq ($(strip $(QMK_BOOTLOADER_TYPE)),)
162 $(error Please set BOOTLOADER to "qmk-dfu" or "qmk-hid" first!)
163else
164 make -C lib/lufa/Bootloaders/$(QMK_BOOTLOADER_TYPE)/ clean
165 $(QMK_BIN) generate-dfu-header --quiet --keyboard $(KEYBOARD) --output lib/lufa/Bootloaders/$(QMK_BOOTLOADER_TYPE)/Keyboard.h
166 $(eval MAX_SIZE=$(shell n=`$(CC) -E -mmcu=$(MCU) -D__ASSEMBLER__ $(CFLAGS) $(OPT_DEFS) platforms/avr/bootloader_size.c 2> /dev/null | sed -ne 's/\r//;/^#/n;/^AVR_SIZE:/,$${s/^AVR_SIZE: //;p;}'` && echo $$(($$n)) || echo 0))
167 $(eval PROGRAM_SIZE_KB=$(shell n=`expr $(MAX_SIZE) / 1024` && echo $$(($$n)) || echo 0))
168 $(eval BOOT_SECTION_SIZE_KB=$(shell n=`expr $(BOOTLOADER_SIZE) / 1024` && echo $$(($$n)) || echo 0))
169 $(eval FLASH_SIZE_KB=$(shell n=`expr $(PROGRAM_SIZE_KB) + $(BOOT_SECTION_SIZE_KB)` && echo $$(($$n)) || echo 0))
170 make -C lib/lufa/Bootloaders/$(QMK_BOOTLOADER_TYPE)/ MCU=$(MCU) ARCH=$(ARCH) F_CPU=$(F_CPU) FLASH_SIZE_KB=$(FLASH_SIZE_KB) BOOT_SECTION_SIZE_KB=$(BOOT_SECTION_SIZE_KB)
171 printf "Bootloader$(QMK_BOOTLOADER_TYPE).hex copied to $(TARGET)_bootloader.hex\n"
172 cp lib/lufa/Bootloaders/$(QMK_BOOTLOADER_TYPE)/Bootloader$(QMK_BOOTLOADER_TYPE).hex $(TARGET)_bootloader.hex
173endif
174
175production: $(BUILD_DIR)/$(TARGET).hex bootloader cpfirmware
176 @cat $(BUILD_DIR)/$(TARGET).hex | awk '/^:00000001FF/ == 0' > $(TARGET)_production.hex
177 @cat $(TARGET)_bootloader.hex >> $(TARGET)_production.hex
178 echo "File sizes:"
179 $(SIZE) $(TARGET).hex $(TARGET)_bootloader.hex $(TARGET)_production.hex
diff --git a/platforms/avr/platform_deps.h b/platforms/avr/platform_deps.h
new file mode 100644
index 000000000..45d9dcebf
--- /dev/null
+++ b/platforms/avr/platform_deps.h
@@ -0,0 +1,20 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#pragma once
17
18#include <avr/pgmspace.h>
19#include <avr/io.h>
20#include <avr/interrupt.h>
diff --git a/platforms/avr/printf.c b/platforms/avr/printf.c
new file mode 100644
index 000000000..9ad7a3869
--- /dev/null
+++ b/platforms/avr/printf.c
@@ -0,0 +1,20 @@
1/*
2Copyright 2011 Jun Wako <wakojun@gmail.com>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17#include "xprintf.h"
18#include "sendchar.h"
19
20void print_set_sendchar(sendchar_func_t func) { xdev_out(func); }
diff --git a/platforms/avr/printf.mk b/platforms/avr/printf.mk
new file mode 100644
index 000000000..060ad88c5
--- /dev/null
+++ b/platforms/avr/printf.mk
@@ -0,0 +1,2 @@
1TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/xprintf.S
2TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/printf.c
diff --git a/platforms/avr/sleep_led.c b/platforms/avr/sleep_led.c
new file mode 100644
index 000000000..9a3b52abe
--- /dev/null
+++ b/platforms/avr/sleep_led.c
@@ -0,0 +1,124 @@
1#include <stdint.h>
2#include <avr/io.h>
3#include <avr/interrupt.h>
4#include <avr/pgmspace.h>
5#include "led.h"
6#include "sleep_led.h"
7
8#ifndef SLEEP_LED_TIMER
9# define SLEEP_LED_TIMER 1
10#endif
11
12#if SLEEP_LED_TIMER == 1
13# define TCCRxB TCCR1B
14# define TIMERx_COMPA_vect TIMER1_COMPA_vect
15# if defined(__AVR_ATmega32A__) // This MCU has only one TIMSK register
16# define TIMSKx TIMSK
17# else
18# define TIMSKx TIMSK1
19# endif
20# define OCIExA OCIE1A
21# define OCRxx OCR1A
22#elif SLEEP_LED_TIMER == 3
23# define TCCRxB TCCR3B
24# define TIMERx_COMPA_vect TIMER3_COMPA_vect
25# define TIMSKx TIMSK3
26# define OCIExA OCIE3A
27# define OCRxx OCR3A
28#else
29error("Invalid SLEEP_LED_TIMER config")
30#endif
31
32/* Software PWM
33 * ______ ______ __
34 * | ON |___OFF___| ON |___OFF___| ....
35 * |<-------------->|<-------------->|<- ....
36 * PWM period PWM period
37 *
38 * 256 interrupts/period[resolution]
39 * 64 periods/second[frequency]
40 * 256*64 interrupts/second
41 * F_CPU/(256*64) clocks/interrupt
42 */
43#define SLEEP_LED_TIMER_TOP F_CPU / (256 * 64)
44
45/** \brief Sleep LED initialization
46 *
47 * FIXME: needs doc
48 */
49void sleep_led_init(void) {
50 /* Timer1 setup */
51 /* CTC mode */
52 TCCRxB |= _BV(WGM12);
53 /* Clock selelct: clk/1 */
54 TCCRxB |= _BV(CS10);
55 /* Set TOP value */
56 uint8_t sreg = SREG;
57 cli();
58 OCRxx = SLEEP_LED_TIMER_TOP;
59 SREG = sreg;
60}
61
62/** \brief Sleep LED enable
63 *
64 * FIXME: needs doc
65 */
66void sleep_led_enable(void) {
67 /* Enable Compare Match Interrupt */
68 TIMSKx |= _BV(OCIExA);
69}
70
71/** \brief Sleep LED disable
72 *
73 * FIXME: needs doc
74 */
75void sleep_led_disable(void) {
76 /* Disable Compare Match Interrupt */
77 TIMSKx &= ~_BV(OCIExA);
78}
79
80/** \brief Sleep LED toggle
81 *
82 * FIXME: needs doc
83 */
84void sleep_led_toggle(void) {
85 /* Disable Compare Match Interrupt */
86 TIMSKx ^= _BV(OCIExA);
87}
88
89/** \brief Breathing Sleep LED brighness(PWM On period) table
90 *
91 * (64[steps] * 4[duration]) / 64[PWM periods/s] = 4 second breath cycle
92 *
93 * https://www.wolframalpha.com/input/?i=sin%28x%2F64*pi%29**8+*+255%2C+x%3D0+to+63
94 * (0..63).each {|x| p ((sin(x/64.0*PI)**8)*255).to_i }
95 */
96static const uint8_t breathing_table[64] PROGMEM = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 6, 10, 15, 23, 32, 44, 58, 74, 93, 113, 135, 157, 179, 199, 218, 233, 245, 252, 255, 252, 245, 233, 218, 199, 179, 157, 135, 113, 93, 74, 58, 44, 32, 23, 15, 10, 6, 4, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
97
98ISR(TIMERx_COMPA_vect) {
99 /* Software PWM
100 * timer:1111 1111 1111 1111
101 * \_____/\/ \_______/____ count(0-255)
102 * \ \______________ duration of step(4)
103 * \__________________ index of step table(0-63)
104 */
105 static union {
106 uint16_t row;
107 struct {
108 uint8_t count : 8;
109 uint8_t duration : 2;
110 uint8_t index : 6;
111 } pwm;
112 } timer = {.row = 0};
113
114 timer.row++;
115
116 // LED on
117 if (timer.pwm.count == 0) {
118 led_set(1 << USB_LED_CAPS_LOCK);
119 }
120 // LED off
121 if (timer.pwm.count == pgm_read_byte(&breathing_table[timer.pwm.index])) {
122 led_set(0);
123 }
124}
diff --git a/platforms/avr/suspend.c b/platforms/avr/suspend.c
new file mode 100644
index 000000000..b614746e6
--- /dev/null
+++ b/platforms/avr/suspend.c
@@ -0,0 +1,152 @@
1#include <stdbool.h>
2#include <avr/sleep.h>
3#include <avr/wdt.h>
4#include <avr/interrupt.h>
5#include "matrix.h"
6#include "action.h"
7#include "suspend.h"
8#include "timer.h"
9#include "led.h"
10#include "host.h"
11
12#ifdef PROTOCOL_LUFA
13# include "lufa.h"
14#endif
15#ifdef PROTOCOL_VUSB
16# include "vusb.h"
17#endif
18
19/** \brief Suspend idle
20 *
21 * FIXME: needs doc
22 */
23void suspend_idle(uint8_t time) {
24 cli();
25 set_sleep_mode(SLEEP_MODE_IDLE);
26 sleep_enable();
27 sei();
28 sleep_cpu();
29 sleep_disable();
30}
31
32// TODO: This needs some cleanup
33
34#if !defined(NO_SUSPEND_POWER_DOWN) && defined(WDT_vect)
35
36// clang-format off
37#define wdt_intr_enable(value) \
38__asm__ __volatile__ ( \
39 "in __tmp_reg__,__SREG__" "\n\t" \
40 "cli" "\n\t" \
41 "wdr" "\n\t" \
42 "sts %0,%1" "\n\t" \
43 "out __SREG__,__tmp_reg__" "\n\t" \
44 "sts %0,%2" "\n\t" \
45 : /* no outputs */ \
46 : "M" (_SFR_MEM_ADDR(_WD_CONTROL_REG)), \
47 "r" (_BV(_WD_CHANGE_BIT) | _BV(WDE)), \
48 "r" ((uint8_t) ((value & 0x08 ? _WD_PS3_MASK : 0x00) | _BV(WDIE) | (value & 0x07))) \
49 : "r0" \
50)
51// clang-format on
52
53/** \brief Power down MCU with watchdog timer
54 *
55 * wdto: watchdog timer timeout defined in <avr/wdt.h>
56 * WDTO_15MS
57 * WDTO_30MS
58 * WDTO_60MS
59 * WDTO_120MS
60 * WDTO_250MS
61 * WDTO_500MS
62 * WDTO_1S
63 * WDTO_2S
64 * WDTO_4S
65 * WDTO_8S
66 */
67static uint8_t wdt_timeout = 0;
68
69/** \brief Power down
70 *
71 * FIXME: needs doc
72 */
73static void power_down(uint8_t wdto) {
74 wdt_timeout = wdto;
75
76 // Watchdog Interrupt Mode
77 wdt_intr_enable(wdto);
78
79 // TODO: more power saving
80 // See PicoPower application note
81 // - I/O port input with pullup
82 // - prescale clock
83 // - BOD disable
84 // - Power Reduction Register PRR
85 set_sleep_mode(SLEEP_MODE_PWR_DOWN);
86 sleep_enable();
87 sei();
88 sleep_cpu();
89 sleep_disable();
90
91 // Disable watchdog after sleep
92 wdt_disable();
93}
94#endif
95
96/** \brief Suspend power down
97 *
98 * FIXME: needs doc
99 */
100void suspend_power_down(void) {
101#ifdef PROTOCOL_LUFA
102 if (USB_DeviceState == DEVICE_STATE_Configured) return;
103#endif
104#ifdef PROTOCOL_VUSB
105 if (!vusb_suspended) return;
106#endif
107
108 suspend_power_down_quantum();
109
110#ifndef NO_SUSPEND_POWER_DOWN
111 // Enter sleep state if possible (ie, the MCU has a watchdog timeout interrupt)
112# if defined(WDT_vect)
113 power_down(WDTO_15MS);
114# endif
115#endif
116}
117
118__attribute__((weak)) void matrix_power_up(void) {}
119__attribute__((weak)) void matrix_power_down(void) {}
120bool suspend_wakeup_condition(void) {
121 matrix_power_up();
122 matrix_scan();
123 matrix_power_down();
124 for (uint8_t r = 0; r < MATRIX_ROWS; r++) {
125 if (matrix_get_row(r)) return true;
126 }
127 return false;
128}
129
130/** \brief run immediately after wakeup
131 *
132 * FIXME: needs doc
133 */
134void suspend_wakeup_init(void) {
135 // clear keyboard state
136 clear_keyboard();
137
138 suspend_wakeup_init_quantum();
139}
140
141#if !defined(NO_SUSPEND_POWER_DOWN) && defined(WDT_vect)
142/* watchdog timeout */
143ISR(WDT_vect) {
144 // compensate timer for sleep
145 switch (wdt_timeout) {
146 case WDTO_15MS:
147 timer_count += 15 + 2; // WDTO_15MS + 2(from observation)
148 break;
149 default:;
150 }
151}
152#endif
diff --git a/platforms/avr/timer.c b/platforms/avr/timer.c
new file mode 100644
index 000000000..c2e6c6e08
--- /dev/null
+++ b/platforms/avr/timer.c
@@ -0,0 +1,133 @@
1/*
2Copyright 2011 Jun Wako <wakojun@gmail.com>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#include <avr/io.h>
19#include <avr/interrupt.h>
20#include <util/atomic.h>
21#include <stdint.h>
22#include "timer_avr.h"
23#include "timer.h"
24
25// counter resolution 1ms
26// NOTE: union { uint32_t timer32; struct { uint16_t dummy; uint16_t timer16; }}
27volatile uint32_t timer_count;
28
29/** \brief timer initialization
30 *
31 * FIXME: needs doc
32 */
33void timer_init(void) {
34#if TIMER_PRESCALER == 1
35 uint8_t prescaler = _BV(CS00);
36#elif TIMER_PRESCALER == 8
37 uint8_t prescaler = _BV(CS01);
38#elif TIMER_PRESCALER == 64
39 uint8_t prescaler = _BV(CS00) | _BV(CS01);
40#elif TIMER_PRESCALER == 256
41 uint8_t prescaler = _BV(CS02);
42#elif TIMER_PRESCALER == 1024
43 uint8_t prescaler = _BV(CS00) | _BV(CS02);
44#else
45# error "Timer prescaler value is not valid"
46#endif
47
48#if defined(__AVR_ATmega32A__)
49 // Timer0 CTC mode
50 TCCR0 = _BV(WGM01) | prescaler;
51
52 OCR0 = TIMER_RAW_TOP;
53 TIMSK = _BV(OCIE0);
54#elif defined(__AVR_ATtiny85__)
55 // Timer0 CTC mode
56 TCCR0A = _BV(WGM01);
57 TCCR0B = prescaler;
58
59 OCR0A = TIMER_RAW_TOP;
60 TIMSK = _BV(OCIE0A);
61#else
62 // Timer0 CTC mode
63 TCCR0A = _BV(WGM01);
64 TCCR0B = prescaler;
65
66 OCR0A = TIMER_RAW_TOP;
67 TIMSK0 = _BV(OCIE0A);
68#endif
69}
70
71/** \brief timer clear
72 *
73 * FIXME: needs doc
74 */
75inline void timer_clear(void) {
76 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { timer_count = 0; }
77}
78
79/** \brief timer read
80 *
81 * FIXME: needs doc
82 */
83inline uint16_t timer_read(void) {
84 uint32_t t;
85
86 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { t = timer_count; }
87
88 return (t & 0xFFFF);
89}
90
91/** \brief timer read32
92 *
93 * FIXME: needs doc
94 */
95inline uint32_t timer_read32(void) {
96 uint32_t t;
97
98 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { t = timer_count; }
99
100 return t;
101}
102
103/** \brief timer elapsed
104 *
105 * FIXME: needs doc
106 */
107inline uint16_t timer_elapsed(uint16_t last) {
108 uint32_t t;
109
110 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { t = timer_count; }
111
112 return TIMER_DIFF_16((t & 0xFFFF), last);
113}
114
115/** \brief timer elapsed32
116 *
117 * FIXME: needs doc
118 */
119inline uint32_t timer_elapsed32(uint32_t last) {
120 uint32_t t;
121
122 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { t = timer_count; }
123
124 return TIMER_DIFF_32(t, last);
125}
126
127// excecuted once per 1ms.(excess for just timer count?)
128#ifndef __AVR_ATmega32A__
129# define TIMER_INTERRUPT_VECTOR TIMER0_COMPA_vect
130#else
131# define TIMER_INTERRUPT_VECTOR TIMER0_COMP_vect
132#endif
133ISR(TIMER_INTERRUPT_VECTOR, ISR_NOBLOCK) { timer_count++; }
diff --git a/platforms/avr/timer_avr.h b/platforms/avr/timer_avr.h
new file mode 100644
index 000000000..c1b726bd0
--- /dev/null
+++ b/platforms/avr/timer_avr.h
@@ -0,0 +1,39 @@
1/*
2Copyright 2011 Jun Wako <wakojun@gmail.com>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#pragma once
19
20#include <stdint.h>
21
22#ifndef TIMER_PRESCALER
23# if F_CPU > 16000000
24# define TIMER_PRESCALER 256
25# elif F_CPU > 2000000
26# define TIMER_PRESCALER 64
27# elif F_CPU > 250000
28# define TIMER_PRESCALER 8
29# else
30# define TIMER_PRESCALER 1
31# endif
32#endif
33#define TIMER_RAW_FREQ (F_CPU / TIMER_PRESCALER)
34#define TIMER_RAW TCNT0
35#define TIMER_RAW_TOP (TIMER_RAW_FREQ / 1000)
36
37#if (TIMER_RAW_TOP > 255)
38# error "Timer0 can't count 1ms at this clock freq. Use larger prescaler."
39#endif
diff --git a/platforms/avr/xprintf.S b/platforms/avr/xprintf.S
new file mode 100644
index 000000000..c5a414c35
--- /dev/null
+++ b/platforms/avr/xprintf.S
@@ -0,0 +1,498 @@
1;---------------------------------------------------------------------------;
2; Extended itoa, puts, printf and atoi (C)ChaN, 2011
3;---------------------------------------------------------------------------;
4
5 // Base size is 152 bytes
6#define CR_CRLF 0 // Convert \n to \r\n (+10 bytes)
7#define USE_XPRINTF 1 // Enable xprintf function (+194 bytes)
8#define USE_XSPRINTF 0 // Add xsprintf function (+78 bytes)
9#define USE_XFPRINTF 0 // Add xfprintf function (+54 bytes)
10#define USE_XATOI 0 // Enable xatoi function (+182 bytes)
11
12
13#if FLASHEND > 0x1FFFF
14#error xitoa module does not support 256K devices
15#endif
16
17.nolist
18#include <avr/io.h> // Include device specific definitions.
19.list
20
21#ifdef SPM_PAGESIZE // Recent devices have "lpm Rd,Z+" and "movw".
22.macro _LPMI reg
23 lpm \reg, Z+
24.endm
25.macro _MOVW dh,dl, sh,sl
26 movw \dl, \sl
27.endm
28#else // Earlier devices do not have "lpm Rd,Z+" nor "movw".
29.macro _LPMI reg
30 lpm
31 mov \reg, r0
32 adiw ZL, 1
33.endm
34.macro _MOVW dh,dl, sh,sl
35 mov \dl, \sl
36 mov \dh, \sh
37.endm
38#endif
39
40
41
42;---------------------------------------------------------------------------
43; Stub function to forward to user output function
44;
45;Prototype: void xputc (char chr // a character to be output
46; );
47;Size: 12/12 words
48
49.section .bss
50.global xfunc_out ; xfunc_out must be initialized before using this module.
51xfunc_out: .ds.w 1
52.section .text
53
54
55.func xputc
56.global xputc
57xputc:
58#if CR_CRLF
59 cpi r24, 10 ;LF --> CRLF
60 brne 1f ;
61 ldi r24, 13 ;
62 rcall 1f ;
63 ldi r24, 10 ;/
641:
65#endif
66 push ZH
67 push ZL
68 lds ZL, xfunc_out+0 ;Pointer to the registered output function.
69 lds ZH, xfunc_out+1 ;/
70 sbiw ZL, 0 ;Skip if null
71 breq 2f ;/
72 icall
732: pop ZL
74 pop ZH
75 ret
76.endfunc
77
78
79
80;---------------------------------------------------------------------------
81; Direct ROM string output
82;
83;Prototype: void xputs (const char *str_p // rom string to be output
84; );
85
86.func xputs
87.global xputs
88xputs:
89 _MOVW ZH,ZL, r25,r24 ; Z = pointer to rom string
901: _LPMI r24
91 cpi r24, 0
92 breq 2f
93 rcall xputc
94 rjmp 1b
952: ret
96.endfunc
97
98
99;---------------------------------------------------------------------------
100; Extended direct numeral string output (32bit version)
101;
102;Prototype: void xitoa (long value, // value to be output
103; char radix, // radix
104; char width); // minimum width
105;
106
107.func xitoa
108.global xitoa
109xitoa:
110 ;r25:r22 = value, r20 = base, r18 = digits
111 clr r31 ;r31 = stack level
112 ldi r30, ' ' ;r30 = sign
113 ldi r19, ' ' ;r19 = filler
114 sbrs r20, 7 ;When base indicates signd format and the value
115 rjmp 0f ;is minus, add a '-'.
116 neg r20 ;
117 sbrs r25, 7 ;
118 rjmp 0f ;
119 ldi r30, '-' ;
120 com r22 ;
121 com r23 ;
122 com r24 ;
123 com r25 ;
124 adc r22, r1 ;
125 adc r23, r1 ;
126 adc r24, r1 ;
127 adc r25, r1 ;/
1280: sbrs r18, 7 ;When digits indicates zero filled,
129 rjmp 1f ;filler is '0'.
130 neg r18 ;
131 ldi r19, '0' ;/
132 ;----- string conversion loop
1331: ldi r21, 32 ;r26 = r25:r22 % r20
134 clr r26 ;r25:r22 /= r20
1352: lsl r22 ;
136 rol r23 ;
137 rol r24 ;
138 rol r25 ;
139 rol r26 ;
140 cp r26, r20 ;
141 brcs 3f ;
142 sub r26, r20 ;
143 inc r22 ;
1443: dec r21 ;
145 brne 2b ;/
146 cpi r26, 10 ;r26 is a numeral digit '0'-'F'
147 brcs 4f ;
148 subi r26, -7 ;
1494: subi r26, -'0' ;/
150 push r26 ;Stack it
151 inc r31 ;/
152 cp r22, r1 ;Repeat until r25:r22 gets zero
153 cpc r23, r1 ;
154 cpc r24, r1 ;
155 cpc r25, r1 ;
156 brne 1b ;/
157
158 cpi r30, '-' ;Minus sign if needed
159 brne 5f ;
160 push r30 ;
161 inc r31 ;/
1625: cp r31, r18 ;Filler
163 brcc 6f ;
164 push r19 ;
165 inc r31 ;
166 rjmp 5b ;/
167
1686: pop r24 ;Flush stacked digits and exit
169 rcall xputc ;
170 dec r31 ;
171 brne 6b ;/
172
173 ret
174.endfunc
175
176
177
178;---------------------------------------------------------------------------;
179; Formatted string output (16/32bit version)
180;
181;Prototype:
182; void __xprintf (const char *format_p, ...);
183; void __xsprintf(char*, const char *format_p, ...);
184; void __xfprintf(void(*func)(char), const char *format_p, ...);
185;
186
187#if USE_XPRINTF
188
189.func xvprintf
190xvprintf:
191 ld ZL, Y+ ;Z = pointer to format string
192 ld ZH, Y+ ;/
193
1940: _LPMI r24 ;Get a format char
195 cpi r24, 0 ;End of format string?
196 breq 90f ;/
197 cpi r24, '%' ;Is format?
198 breq 20f ;/
1991: rcall xputc ;Put a normal character
200 rjmp 0b ;/
20190: ret
202
20320: ldi r18, 0 ;r18: digits
204 clt ;T: filler
205 _LPMI r21 ;Get flags
206 cpi r21, '%' ;Is a %?
207 breq 1b ;/
208 cpi r21, '0' ;Zero filled?
209 brne 23f ;
210 set ;/
21122: _LPMI r21 ;Get width
21223: cpi r21, '9'+1 ;
213 brcc 24f ;
214 subi r21, '0' ;
215 brcs 90b ;
216 lsl r18 ;
217 mov r0, r18 ;
218 lsl r18 ;
219 lsl r18 ;
220 add r18, r0 ;
221 add r18, r21 ;
222 rjmp 22b ;/
223
22424: brtc 25f ;get value (low word)
225 neg r18 ;
22625: ld r24, Y+ ;
227 ld r25, Y+ ;/
228 cpi r21, 'c' ;Is type character?
229 breq 1b ;/
230 cpi r21, 's' ;Is type RAM string?
231 breq 50f ;/
232 cpi r21, 'S' ;Is type ROM string?
233 breq 60f ;/
234 _MOVW r23,r22,r25,r24 ;r25:r22 = value
235 clr r24 ;
236 clr r25 ;
237 clt ;/
238 cpi r21, 'l' ;Is long int?
239 brne 26f ;
240 ld r24, Y+ ;get value (high word)
241 ld r25, Y+ ;
242 set ;
243 _LPMI r21 ;/
24426: cpi r21, 'd' ;Is type signed decimal?
245 brne 27f ;/
246 ldi r20, -10 ;
247 brts 40f ;
248 sbrs r23, 7 ;
249 rjmp 40f ;
250 ldi r24, -1 ;
251 ldi r25, -1 ;
252 rjmp 40f ;/
25327: cpi r21, 'u' ;Is type unsigned decimal?
254 ldi r20, 10 ;
255 breq 40f ;/
256 cpi r21, 'X' ;Is type hexdecimal?
257 ldi r20, 16 ;
258 breq 40f ;/
259 cpi r21, 'b' ;Is type binary?
260 ldi r20, 2 ;
261 breq 40f ;/
262 ret ;abort
26340: push ZH ;Output the value
264 push ZL ;
265 rcall xitoa ;
26642: pop ZL ;
267 pop ZH ;
268 rjmp 0b ;/
269
27050: push ZH ;Put a string on the RAM
271 push ZL
272 _MOVW ZH,ZL, r25,r24
27351: ld r24, Z+
274 cpi r24, 0
275 breq 42b
276 rcall xputc
277 rjmp 51b
278
27960: push ZH ;Put a string on the ROM
280 push ZL
281 rcall xputs
282 rjmp 42b
283.endfunc
284
285
286.func __xprintf
287.global __xprintf
288__xprintf:
289 push YH
290 push YL
291 in YL, _SFR_IO_ADDR(SPL)
292#ifdef SPH
293 in YH, _SFR_IO_ADDR(SPH)
294#else
295 clr YH
296#endif
297 adiw YL, 5 ;Y = pointer to arguments
298 rcall xvprintf
299 pop YL
300 pop YH
301 ret
302.endfunc
303
304
305#if USE_XSPRINTF
306
307.func __xsprintf
308putram:
309 _MOVW ZH,ZL, r15,r14
310 st Z+, r24
311 _MOVW r15,r14, ZH,ZL
312 ret
313.global __xsprintf
314__xsprintf:
315 push YH
316 push YL
317 in YL, _SFR_IO_ADDR(SPL)
318#ifdef SPH
319 in YH, _SFR_IO_ADDR(SPH)
320#else
321 clr YH
322#endif
323 adiw YL, 5 ;Y = pointer to arguments
324 lds ZL, xfunc_out+0 ;Save registered output function
325 lds ZH, xfunc_out+1 ;
326 push ZL ;
327 push ZH ;/
328 ldi ZL, lo8(pm(putram));Set local output function
329 ldi ZH, hi8(pm(putram));
330 sts xfunc_out+0, ZL ;
331 sts xfunc_out+1, ZH ;/
332 push r15 ;Initialize pointer to string buffer
333 push r14 ;
334 ld r14, Y+ ;
335 ld r15, Y+ ;/
336 rcall xvprintf
337 _MOVW ZH,ZL, r15,r14 ;Terminate string
338 st Z, r1 ;
339 pop r14 ;
340 pop r15 ;/
341 pop ZH ;Restore registered output function
342 pop ZL ;
343 sts xfunc_out+0, ZL ;
344 sts xfunc_out+1, ZH ;/
345 pop YL
346 pop YH
347 ret
348.endfunc
349#endif
350
351
352#if USE_XFPRINTF
353.func __xfprintf
354.global __xfprintf
355__xfprintf:
356 push YH
357 push YL
358 in YL, _SFR_IO_ADDR(SPL)
359#ifdef SPH
360 in YH, _SFR_IO_ADDR(SPH)
361#else
362 clr YH
363#endif
364 adiw YL, 5 ;Y = pointer to arguments
365 lds ZL, xfunc_out+0 ;Save registered output function
366 lds ZH, xfunc_out+1 ;
367 push ZL ;
368 push ZH ;/
369 ld ZL, Y+ ;Set output function
370 ld ZH, Y+ ;
371 sts xfunc_out+0, ZL ;
372 sts xfunc_out+1, ZH ;/
373 rcall xvprintf
374 pop ZH ;Restore registered output function
375 pop ZL ;
376 sts xfunc_out+0, ZL ;
377 sts xfunc_out+1, ZH ;/
378 pop YL
379 pop YH
380 ret
381.endfunc
382#endif
383
384#endif
385
386
387
388;---------------------------------------------------------------------------
389; Extended numeral string input
390;
391;Prototype:
392; char xatoi ( /* 1: Successful, 0: Failed */
393; const char **str, /* pointer to pointer to source string */
394; long *res /* result */
395; );
396;
397
398
399#if USE_XATOI
400.func xatoi
401.global xatoi
402xatoi:
403 _MOVW r1, r0, r23, r22
404 _MOVW XH, XL, r25, r24
405 ld ZL, X+
406 ld ZH, X+
407 clr r18 ;r21:r18 = 0;
408 clr r19 ;
409 clr r20 ;
410 clr r21 ;/
411 clt ;T = 0;
412
413 ldi r25, 10 ;r25 = 10;
414 rjmp 41f ;/
41540: adiw ZL, 1 ;Z++;
41641: ld r22, Z ;r22 = *Z;
417 cpi r22, ' ' ;if(r22 == ' ') continue
418 breq 40b ;/
419 brcs 70f ;if(r22 < ' ') error;
420 cpi r22, '-' ;if(r22 == '-') {
421 brne 42f ; T = 1;
422 set ; continue;
423 rjmp 40b ;}
42442: cpi r22, '9'+1 ;if(r22 > '9') error;
425 brcc 70f ;/
426 cpi r22, '0' ;if(r22 < '0') error;
427 brcs 70f ;/
428 brne 51f ;if(r22 > '0') cv_start;
429 ldi r25, 8 ;r25 = 8;
430 adiw ZL, 1 ;r22 = *(++Z);
431 ld r22, Z ;/
432 cpi r22, ' '+1 ;if(r22 <= ' ') exit;
433 brcs 80f ;/
434 cpi r22, 'b' ;if(r22 == 'b') {
435 brne 43f ; r25 = 2;
436 ldi r25, 2 ; cv_start;
437 rjmp 50f ;}
43843: cpi r22, 'x' ;if(r22 != 'x') error;
439 brne 51f ;/
440 ldi r25, 16 ;r25 = 16;
441
44250: adiw ZL, 1 ;Z++;
443 ld r22, Z ;r22 = *Z;
44451: cpi r22, ' '+1 ;if(r22 <= ' ') break;
445 brcs 80f ;/
446 cpi r22, 'a' ;if(r22 >= 'a') r22 =- 0x20;
447 brcs 52f ;
448 subi r22, 0x20 ;/
44952: subi r22, '0' ;if((r22 -= '0') < 0) error;
450 brcs 70f ;/
451 cpi r22, 10 ;if(r22 >= 10) {
452 brcs 53f ; r22 -= 7;
453 subi r22, 7 ; if(r22 < 10)
454 cpi r22, 10 ;
455 brcs 70f ;}
45653: cp r22, r25 ;if(r22 >= r25) error;
457 brcc 70f ;/
45860: ldi r24, 33 ;r21:r18 *= r25;
459 sub r23, r23 ;
46061: brcc 62f ;
461 add r23, r25 ;
46262: lsr r23 ;
463 ror r21 ;
464 ror r20 ;
465 ror r19 ;
466 ror r18 ;
467 dec r24 ;
468 brne 61b ;/
469 add r18, r22 ;r21:r18 += r22;
470 adc r19, r24 ;
471 adc r20, r24 ;
472 adc r21, r24 ;/
473 rjmp 50b ;repeat
474
47570: ldi r24, 0
476 rjmp 81f
47780: ldi r24, 1
47881: brtc 82f
479 clr r22
480 com r18
481 com r19
482 com r20
483 com r21
484 adc r18, r22
485 adc r19, r22
486 adc r20, r22
487 adc r21, r22
48882: st -X, ZH
489 st -X, ZL
490 _MOVW XH, XL, r1, r0
491 st X+, r18
492 st X+, r19
493 st X+, r20
494 st X+, r21
495 clr r1
496 ret
497.endfunc
498#endif
diff --git a/platforms/avr/xprintf.h b/platforms/avr/xprintf.h
new file mode 100644
index 000000000..80834f171
--- /dev/null
+++ b/platforms/avr/xprintf.h
@@ -0,0 +1,103 @@
1/*---------------------------------------------------------------------------
2 Extended itoa, puts and printf (C)ChaN, 2011
3-----------------------------------------------------------------------------*/
4
5#pragma once
6
7#include <inttypes.h>
8#include <avr/pgmspace.h>
9
10#ifdef __cplusplus
11extern "C" {
12#endif
13
14extern void (*xfunc_out)(uint8_t);
15#define xdev_out(func) xfunc_out = (void (*)(uint8_t))(func)
16
17/* This is a pointer to user defined output function. It must be initialized
18 before using this modle.
19*/
20
21void xputc(char chr);
22
23/* This is a stub function to forward outputs to user defined output function.
24 All outputs from this module are output via this function.
25*/
26
27/*-----------------------------------------------------------------------------*/
28void xputs(const char *string_p);
29
30/* The string placed in the ROM is forwarded to xputc() directly.
31 */
32
33/*-----------------------------------------------------------------------------*/
34void xitoa(long value, char radix, char width);
35
36/* Extended itoa().
37
38 value radix width output
39 100 10 6 " 100"
40 100 10 -6 "000100"
41 100 10 0 "100"
42 4294967295 10 0 "4294967295"
43 4294967295 -10 0 "-1"
44 655360 16 -8 "000A0000"
45 1024 16 0 "400"
46 0x55 2 -8 "01010101"
47*/
48
49/*-----------------------------------------------------------------------------*/
50#define xprintf(format, ...) __xprintf(PSTR(format), ##__VA_ARGS__)
51#define xsprintf(str, format, ...) __xsprintf(str, PSTR(format), ##__VA_ARGS__)
52#define xfprintf(func, format, ...) __xfprintf(func, PSTR(format), ##__VA_ARGS__)
53
54void __xprintf(const char *format_p, ...); /* Send formatted string to the registered device */
55// void __xsprintf(char*, const char *format_p, ...); /* Put formatted string to the memory */
56// void __xfprintf(void(*func)(uint8_t), const char *format_p, ...); /* Send formatted string to the specified device */
57
58/* Format string is placed in the ROM. The format flags is similar to printf().
59
60 %[flag][width][size]type
61
62 flag
63 A '0' means filled with '0' when output is shorter than width.
64 ' ' is used in default. This is effective only numeral type.
65 width
66 Minimum width in decimal number. This is effective only numeral type.
67 Default width is zero.
68 size
69 A 'l' means the argument is long(32bit). Default is short(16bit).
70 This is effective only numeral type.
71 type
72 'c' : Character, argument is the value
73 's' : String placed on the RAM, argument is the pointer
74 'S' : String placed on the ROM, argument is the pointer
75 'd' : Signed decimal, argument is the value
76 'u' : Unsigned decimal, argument is the value
77 'X' : Hexdecimal, argument is the value
78 'b' : Binary, argument is the value
79 '%' : '%'
80
81*/
82
83/*-----------------------------------------------------------------------------*/
84char xatoi(char **str, long *ret);
85
86/* Get value of the numeral string.
87
88 str
89 Pointer to pointer to source string
90
91 "0b11001010" binary
92 "0377" octal
93 "0xff800" hexdecimal
94 "1250000" decimal
95 "-25000" decimal
96
97 ret
98 Pointer to return value
99*/
100
101#ifdef __cplusplus
102}
103#endif
diff --git a/platforms/bootloader.h b/platforms/bootloader.h
new file mode 100644
index 000000000..25ebd9528
--- /dev/null
+++ b/platforms/bootloader.h
@@ -0,0 +1,21 @@
1/*
2Copyright 2011 Jun Wako <wakojun@gmail.com>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#pragma once
19
20/* give code for your bootloader to come up if needed */
21void bootloader_jump(void);
diff --git a/platforms/chibios/_timer.h b/platforms/chibios/_timer.h
new file mode 100644
index 000000000..77402b612
--- /dev/null
+++ b/platforms/chibios/_timer.h
@@ -0,0 +1,19 @@
1/* Copyright 2021 Simon Arlott
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#pragma once
17
18// The platform is 32-bit, so prefer 32-bit timers to avoid overflow
19#define FAST_TIMER_T_SIZE 32
diff --git a/platforms/chibios/_wait.c b/platforms/chibios/_wait.c
new file mode 100644
index 000000000..1fbea2dd5
--- /dev/null
+++ b/platforms/chibios/_wait.c
@@ -0,0 +1,89 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef __OPTIMIZE__
18# pragma message "Compiler optimizations disabled; wait_cpuclock() won't work as designed"
19#endif
20
21#define CLOCK_DELAY_NOP8 "nop\n\t nop\n\t nop\n\t nop\n\t nop\n\t nop\n\t nop\n\t nop\n\t"
22
23__attribute__((always_inline)) static inline void wait_cpuclock(unsigned int n) { /* n: 1..135 */
24 /* The argument n must be a constant expression.
25 * That way, compiler optimization will remove unnecessary code. */
26 if (n < 1) {
27 return;
28 }
29 if (n > 8) {
30 unsigned int n8 = n / 8;
31 n = n - n8 * 8;
32 switch (n8) {
33 case 16:
34 asm volatile(CLOCK_DELAY_NOP8::: "memory");
35 case 15:
36 asm volatile(CLOCK_DELAY_NOP8::: "memory");
37 case 14:
38 asm volatile(CLOCK_DELAY_NOP8::: "memory");
39 case 13:
40 asm volatile(CLOCK_DELAY_NOP8::: "memory");
41 case 12:
42 asm volatile(CLOCK_DELAY_NOP8::: "memory");
43 case 11:
44 asm volatile(CLOCK_DELAY_NOP8::: "memory");
45 case 10:
46 asm volatile(CLOCK_DELAY_NOP8::: "memory");
47 case 9:
48 asm volatile(CLOCK_DELAY_NOP8::: "memory");
49 case 8:
50 asm volatile(CLOCK_DELAY_NOP8::: "memory");
51 case 7:
52 asm volatile(CLOCK_DELAY_NOP8::: "memory");
53 case 6:
54 asm volatile(CLOCK_DELAY_NOP8::: "memory");
55 case 5:
56 asm volatile(CLOCK_DELAY_NOP8::: "memory");
57 case 4:
58 asm volatile(CLOCK_DELAY_NOP8::: "memory");
59 case 3:
60 asm volatile(CLOCK_DELAY_NOP8::: "memory");
61 case 2:
62 asm volatile(CLOCK_DELAY_NOP8::: "memory");
63 case 1:
64 asm volatile(CLOCK_DELAY_NOP8::: "memory");
65 case 0:
66 break;
67 }
68 }
69 switch (n) {
70 case 8:
71 asm volatile("nop" ::: "memory");
72 case 7:
73 asm volatile("nop" ::: "memory");
74 case 6:
75 asm volatile("nop" ::: "memory");
76 case 5:
77 asm volatile("nop" ::: "memory");
78 case 4:
79 asm volatile("nop" ::: "memory");
80 case 3:
81 asm volatile("nop" ::: "memory");
82 case 2:
83 asm volatile("nop" ::: "memory");
84 case 1:
85 asm volatile("nop" ::: "memory");
86 case 0:
87 break;
88 }
89}
diff --git a/platforms/chibios/_wait.h b/platforms/chibios/_wait.h
new file mode 100644
index 000000000..2f36c64a2
--- /dev/null
+++ b/platforms/chibios/_wait.h
@@ -0,0 +1,60 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#pragma once
17
18#include <ch.h>
19#include <hal.h>
20
21/* chThdSleepX of zero maps to infinite - so we map to a tiny delay to still yield */
22#define wait_ms(ms) \
23 do { \
24 if (ms != 0) { \
25 chThdSleepMilliseconds(ms); \
26 } else { \
27 chThdSleepMicroseconds(1); \
28 } \
29 } while (0)
30
31#ifdef WAIT_US_TIMER
32void wait_us(uint16_t duration);
33#else
34# define wait_us(us) \
35 do { \
36 if (us != 0) { \
37 chThdSleepMicroseconds(us); \
38 } else { \
39 chThdSleepMicroseconds(1); \
40 } \
41 } while (0)
42#endif
43
44#include "_wait.c"
45
46/* For GPIOs on ARM-based MCUs, the input pins are sampled by the clock of the bus
47 * to which the GPIO is connected.
48 * The connected buses differ depending on the various series of MCUs.
49 * And since the instruction execution clock of the CPU and the bus clock of GPIO are different,
50 * there is a delay of several clocks to read the change of the input signal.
51 *
52 * Define this delay with the GPIO_INPUT_PIN_DELAY macro.
53 * If the GPIO_INPUT_PIN_DELAY macro is not defined, the following default values will be used.
54 * (A fairly large value of 0.25 microseconds is set.)
55 */
56#ifndef GPIO_INPUT_PIN_DELAY
57# define GPIO_INPUT_PIN_DELAY (CPU_CLOCK / 1000000L / 4)
58#endif
59
60#define waitInputPinDelay() wait_cpuclock(GPIO_INPUT_PIN_DELAY)
diff --git a/platforms/chibios/atomic_util.h b/platforms/chibios/atomic_util.h
new file mode 100644
index 000000000..897504515
--- /dev/null
+++ b/platforms/chibios/atomic_util.h
@@ -0,0 +1,37 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#pragma once
17
18#include <ch.h>
19
20static __inline__ uint8_t __interrupt_disable__(void) {
21 chSysLock();
22
23 return 1;
24}
25
26static __inline__ void __interrupt_enable__(const uint8_t *__s) {
27 chSysUnlock();
28
29 __asm__ volatile("" ::: "memory");
30 (void)__s;
31}
32
33#define ATOMIC_BLOCK(type) for (type, __ToDo = __interrupt_disable__(); __ToDo; __ToDo = 0)
34#define ATOMIC_FORCEON uint8_t sreg_save __attribute__((__cleanup__(__interrupt_enable__))) = 0
35
36#define ATOMIC_BLOCK_RESTORESTATE _Static_assert(0, "ATOMIC_BLOCK_RESTORESTATE not implemented")
37#define ATOMIC_BLOCK_FORCEON ATOMIC_BLOCK(ATOMIC_FORCEON)
diff --git a/platforms/chibios/boards/BLACKPILL_STM32_F401/configs/mcuconf.h b/platforms/chibios/boards/BLACKPILL_STM32_F401/configs/mcuconf.h
index ba6e934fe..a21fd7bd1 100644
--- a/platforms/chibios/boards/BLACKPILL_STM32_F401/configs/mcuconf.h
+++ b/platforms/chibios/boards/BLACKPILL_STM32_F401/configs/mcuconf.h
@@ -1,5 +1,5 @@
1/* 1/*
2 ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio 2 ChibiOS - Copyright (C) 2006..2020 Giovanni Di Sirio
3 3
4 Licensed under the Apache License, Version 2.0 (the "License"); 4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License. 5 you may not use this file except in compliance with the License.
@@ -32,11 +32,15 @@
32 */ 32 */
33 33
34#define STM32F4xx_MCUCONF 34#define STM32F4xx_MCUCONF
35#define STM32F401_MCUCONF
35 36
36/* 37/*
37 * HAL driver system settings. 38 * HAL driver system settings.
38 */ 39 */
39#define STM32_NO_INIT FALSE 40#define STM32_NO_INIT FALSE
41#define STM32_PVD_ENABLE FALSE
42#define STM32_PLS STM32_PLS_LEV0
43#define STM32_BKPRAM_ENABLE FALSE
40#define STM32_HSI_ENABLED TRUE 44#define STM32_HSI_ENABLED TRUE
41#define STM32_LSI_ENABLED TRUE 45#define STM32_LSI_ENABLED TRUE
42#define STM32_HSE_ENABLED TRUE 46#define STM32_HSE_ENABLED TRUE
@@ -44,13 +48,13 @@
44#define STM32_CLOCK48_REQUIRED TRUE 48#define STM32_CLOCK48_REQUIRED TRUE
45#define STM32_SW STM32_SW_PLL 49#define STM32_SW STM32_SW_PLL
46#define STM32_PLLSRC STM32_PLLSRC_HSE 50#define STM32_PLLSRC STM32_PLLSRC_HSE
47#define STM32_PLLM_VALUE 25 51#define STM32_PLLM_VALUE 25
48#define STM32_PLLN_VALUE 336 52#define STM32_PLLN_VALUE 336
49#define STM32_PLLP_VALUE 4 53#define STM32_PLLP_VALUE 4
50#define STM32_PLLQ_VALUE 7 54#define STM32_PLLQ_VALUE 7
51#define STM32_HPRE STM32_HPRE_DIV1 55#define STM32_HPRE STM32_HPRE_DIV1
52#define STM32_PPRE1 STM32_PPRE1_DIV4 56#define STM32_PPRE1 STM32_PPRE1_DIV4
53#define STM32_PPRE2 STM32_PPRE2_DIV2 57#define STM32_PPRE2 STM32_PPRE2_DIV2
54#define STM32_RTCSEL STM32_RTCSEL_LSI 58#define STM32_RTCSEL STM32_RTCSEL_LSI
55#define STM32_RTCPRE_VALUE 8 59#define STM32_RTCPRE_VALUE 8
56#define STM32_MCO1SEL STM32_MCO1SEL_HSI 60#define STM32_MCO1SEL STM32_MCO1SEL_HSI
@@ -60,9 +64,6 @@
60#define STM32_I2SSRC STM32_I2SSRC_CKIN 64#define STM32_I2SSRC STM32_I2SSRC_CKIN
61#define STM32_PLLI2SN_VALUE 192 65#define STM32_PLLI2SN_VALUE 192
62#define STM32_PLLI2SR_VALUE 5 66#define STM32_PLLI2SR_VALUE 5
63#define STM32_PVD_ENABLE FALSE
64#define STM32_PLS STM32_PLS_LEV0
65#define STM32_BKPRAM_ENABLE FALSE
66 67
67/* 68/*
68 * IRQ system settings. 69 * IRQ system settings.
@@ -82,6 +83,19 @@
82#define STM32_IRQ_EXTI21_PRIORITY 15 83#define STM32_IRQ_EXTI21_PRIORITY 15
83#define STM32_IRQ_EXTI22_PRIORITY 15 84#define STM32_IRQ_EXTI22_PRIORITY 15
84 85
86#define STM32_IRQ_TIM1_BRK_TIM9_PRIORITY 7
87#define STM32_IRQ_TIM1_UP_TIM10_PRIORITY 7
88#define STM32_IRQ_TIM1_TRGCO_TIM11_PRIORITY 7
89#define STM32_IRQ_TIM1_CC_PRIORITY 7
90#define STM32_IRQ_TIM2_PRIORITY 7
91#define STM32_IRQ_TIM3_PRIORITY 7
92#define STM32_IRQ_TIM4_PRIORITY 7
93#define STM32_IRQ_TIM5_PRIORITY 7
94
95#define STM32_IRQ_USART1_PRIORITY 12
96#define STM32_IRQ_USART2_PRIORITY 12
97#define STM32_IRQ_USART6_PRIORITY 12
98
85/* 99/*
86 * ADC driver system settings. 100 * ADC driver system settings.
87 */ 101 */
@@ -101,14 +115,8 @@
101#define STM32_GPT_USE_TIM4 FALSE 115#define STM32_GPT_USE_TIM4 FALSE
102#define STM32_GPT_USE_TIM5 FALSE 116#define STM32_GPT_USE_TIM5 FALSE
103#define STM32_GPT_USE_TIM9 FALSE 117#define STM32_GPT_USE_TIM9 FALSE
118#define STM32_GPT_USE_TIM10 FALSE
104#define STM32_GPT_USE_TIM11 FALSE 119#define STM32_GPT_USE_TIM11 FALSE
105#define STM32_GPT_TIM1_IRQ_PRIORITY 7
106#define STM32_GPT_TIM2_IRQ_PRIORITY 7
107#define STM32_GPT_TIM3_IRQ_PRIORITY 7
108#define STM32_GPT_TIM4_IRQ_PRIORITY 7
109#define STM32_GPT_TIM5_IRQ_PRIORITY 7
110#define STM32_GPT_TIM9_IRQ_PRIORITY 7
111#define STM32_GPT_TIM11_IRQ_PRIORITY 7
112 120
113/* 121/*
114 * I2C driver system settings. 122 * I2C driver system settings.
@@ -155,29 +163,20 @@
155#define STM32_ICU_USE_TIM4 FALSE 163#define STM32_ICU_USE_TIM4 FALSE
156#define STM32_ICU_USE_TIM5 FALSE 164#define STM32_ICU_USE_TIM5 FALSE
157#define STM32_ICU_USE_TIM9 FALSE 165#define STM32_ICU_USE_TIM9 FALSE
158#define STM32_ICU_TIM1_IRQ_PRIORITY 7 166#define STM32_ICU_USE_TIM10 FALSE
159#define STM32_ICU_TIM2_IRQ_PRIORITY 7 167#define STM32_ICU_USE_TIM11 FALSE
160#define STM32_ICU_TIM3_IRQ_PRIORITY 7
161#define STM32_ICU_TIM4_IRQ_PRIORITY 7
162#define STM32_ICU_TIM5_IRQ_PRIORITY 7
163#define STM32_ICU_TIM9_IRQ_PRIORITY 7
164 168
165/* 169/*
166 * PWM driver system settings. 170 * PWM driver system settings.
167 */ 171 */
168#define STM32_PWM_USE_ADVANCED FALSE
169#define STM32_PWM_USE_TIM1 FALSE 172#define STM32_PWM_USE_TIM1 FALSE
170#define STM32_PWM_USE_TIM2 FALSE 173#define STM32_PWM_USE_TIM2 FALSE
171#define STM32_PWM_USE_TIM3 FALSE 174#define STM32_PWM_USE_TIM3 FALSE
172#define STM32_PWM_USE_TIM4 FALSE 175#define STM32_PWM_USE_TIM4 FALSE
173#define STM32_PWM_USE_TIM5 FALSE 176#define STM32_PWM_USE_TIM5 FALSE
174#define STM32_PWM_USE_TIM9 FALSE 177#define STM32_PWM_USE_TIM9 FALSE
175#define STM32_PWM_TIM1_IRQ_PRIORITY 7 178#define STM32_PWM_USE_TIM10 FALSE
176#define STM32_PWM_TIM2_IRQ_PRIORITY 7 179#define STM32_PWM_USE_TIM11 FALSE
177#define STM32_PWM_TIM3_IRQ_PRIORITY 7
178#define STM32_PWM_TIM4_IRQ_PRIORITY 7
179#define STM32_PWM_TIM5_IRQ_PRIORITY 7
180#define STM32_PWM_TIM9_IRQ_PRIORITY 7
181 180
182/* 181/*
183 * SERIAL driver system settings. 182 * SERIAL driver system settings.
@@ -185,9 +184,6 @@
185#define STM32_SERIAL_USE_USART1 FALSE 184#define STM32_SERIAL_USE_USART1 FALSE
186#define STM32_SERIAL_USE_USART2 FALSE 185#define STM32_SERIAL_USE_USART2 FALSE
187#define STM32_SERIAL_USE_USART6 FALSE 186#define STM32_SERIAL_USE_USART6 FALSE
188#define STM32_SERIAL_USART1_PRIORITY 12
189#define STM32_SERIAL_USART2_PRIORITY 12
190#define STM32_SERIAL_USART6_PRIORITY 12
191 187
192/* 188/*
193 * SPI driver system settings. 189 * SPI driver system settings.
@@ -227,9 +223,6 @@
227#define STM32_UART_USART2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6) 223#define STM32_UART_USART2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6)
228#define STM32_UART_USART6_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 2) 224#define STM32_UART_USART6_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 2)
229#define STM32_UART_USART6_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 7) 225#define STM32_UART_USART6_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 7)
230#define STM32_UART_USART1_IRQ_PRIORITY 12
231#define STM32_UART_USART2_IRQ_PRIORITY 12
232#define STM32_UART_USART6_IRQ_PRIORITY 12
233#define STM32_UART_USART1_DMA_PRIORITY 0 226#define STM32_UART_USART1_DMA_PRIORITY 0
234#define STM32_UART_USART2_DMA_PRIORITY 0 227#define STM32_UART_USART2_DMA_PRIORITY 0
235#define STM32_UART_USART6_DMA_PRIORITY 0 228#define STM32_UART_USART6_DMA_PRIORITY 0
@@ -241,9 +234,7 @@
241#define STM32_USB_USE_OTG1 TRUE 234#define STM32_USB_USE_OTG1 TRUE
242#define STM32_USB_OTG1_IRQ_PRIORITY 14 235#define STM32_USB_OTG1_IRQ_PRIORITY 14
243#define STM32_USB_OTG1_RX_FIFO_SIZE 512 236#define STM32_USB_OTG1_RX_FIFO_SIZE 512
244#define STM32_USB_OTG_THREAD_PRIO NORMALPRIO+1 237#define STM32_USB_HOST_WAKEUP_DURATION 2
245#define STM32_USB_OTG_THREAD_STACK_SIZE 128
246#define STM32_USB_OTGFIFO_FILL_BASEPRI 0
247 238
248/* 239/*
249 * WDG driver system settings. 240 * WDG driver system settings.
diff --git a/platforms/chibios/boards/BLACKPILL_STM32_F411/configs/mcuconf.h b/platforms/chibios/boards/BLACKPILL_STM32_F411/configs/mcuconf.h
index 0394ff56b..131c84766 100644
--- a/platforms/chibios/boards/BLACKPILL_STM32_F411/configs/mcuconf.h
+++ b/platforms/chibios/boards/BLACKPILL_STM32_F411/configs/mcuconf.h
@@ -1,5 +1,5 @@
1/* 1/*
2 ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio 2 ChibiOS - Copyright (C) 2006..2020 Giovanni Di Sirio
3 3
4 Licensed under the Apache License, Version 2.0 (the "License"); 4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License. 5 you may not use this file except in compliance with the License.
@@ -32,11 +32,15 @@
32 */ 32 */
33 33
34#define STM32F4xx_MCUCONF 34#define STM32F4xx_MCUCONF
35#define STM32F411_MCUCONF
35 36
36/* 37/*
37 * HAL driver system settings. 38 * HAL driver system settings.
38 */ 39 */
39#define STM32_NO_INIT FALSE 40#define STM32_NO_INIT FALSE
41#define STM32_PVD_ENABLE FALSE
42#define STM32_PLS STM32_PLS_LEV0
43#define STM32_BKPRAM_ENABLE FALSE
40#define STM32_HSI_ENABLED TRUE 44#define STM32_HSI_ENABLED TRUE
41#define STM32_LSI_ENABLED TRUE 45#define STM32_LSI_ENABLED TRUE
42#define STM32_HSE_ENABLED TRUE 46#define STM32_HSE_ENABLED TRUE
@@ -60,9 +64,6 @@
60#define STM32_I2SSRC STM32_I2SSRC_CKIN 64#define STM32_I2SSRC STM32_I2SSRC_CKIN
61#define STM32_PLLI2SN_VALUE 192 65#define STM32_PLLI2SN_VALUE 192
62#define STM32_PLLI2SR_VALUE 5 66#define STM32_PLLI2SR_VALUE 5
63#define STM32_PVD_ENABLE FALSE
64#define STM32_PLS STM32_PLS_LEV0
65#define STM32_BKPRAM_ENABLE FALSE
66 67
67/* 68/*
68 * IRQ system settings. 69 * IRQ system settings.
@@ -82,6 +83,19 @@
82#define STM32_IRQ_EXTI21_PRIORITY 15 83#define STM32_IRQ_EXTI21_PRIORITY 15
83#define STM32_IRQ_EXTI22_PRIORITY 15 84#define STM32_IRQ_EXTI22_PRIORITY 15
84 85
86#define STM32_IRQ_TIM1_BRK_TIM9_PRIORITY 7
87#define STM32_IRQ_TIM1_UP_TIM10_PRIORITY 7
88#define STM32_IRQ_TIM1_TRGCO_TIM11_PRIORITY 7
89#define STM32_IRQ_TIM1_CC_PRIORITY 7
90#define STM32_IRQ_TIM2_PRIORITY 7
91#define STM32_IRQ_TIM3_PRIORITY 7
92#define STM32_IRQ_TIM4_PRIORITY 7
93#define STM32_IRQ_TIM5_PRIORITY 7
94
95#define STM32_IRQ_USART1_PRIORITY 12
96#define STM32_IRQ_USART2_PRIORITY 12
97#define STM32_IRQ_USART6_PRIORITY 12
98
85/* 99/*
86 * ADC driver system settings. 100 * ADC driver system settings.
87 */ 101 */
@@ -101,14 +115,8 @@
101#define STM32_GPT_USE_TIM4 FALSE 115#define STM32_GPT_USE_TIM4 FALSE
102#define STM32_GPT_USE_TIM5 FALSE 116#define STM32_GPT_USE_TIM5 FALSE
103#define STM32_GPT_USE_TIM9 FALSE 117#define STM32_GPT_USE_TIM9 FALSE
118#define STM32_GPT_USE_TIM10 FALSE
104#define STM32_GPT_USE_TIM11 FALSE 119#define STM32_GPT_USE_TIM11 FALSE
105#define STM32_GPT_TIM1_IRQ_PRIORITY 7
106#define STM32_GPT_TIM2_IRQ_PRIORITY 7
107#define STM32_GPT_TIM3_IRQ_PRIORITY 7
108#define STM32_GPT_TIM4_IRQ_PRIORITY 7
109#define STM32_GPT_TIM5_IRQ_PRIORITY 7
110#define STM32_GPT_TIM9_IRQ_PRIORITY 7
111#define STM32_GPT_TIM11_IRQ_PRIORITY 7
112 120
113/* 121/*
114 * I2C driver system settings. 122 * I2C driver system settings.
@@ -155,29 +163,28 @@
155#define STM32_ICU_USE_TIM4 FALSE 163#define STM32_ICU_USE_TIM4 FALSE
156#define STM32_ICU_USE_TIM5 FALSE 164#define STM32_ICU_USE_TIM5 FALSE
157#define STM32_ICU_USE_TIM9 FALSE 165#define STM32_ICU_USE_TIM9 FALSE
158#define STM32_ICU_TIM1_IRQ_PRIORITY 7 166#define STM32_ICU_USE_TIM10 FALSE
159#define STM32_ICU_TIM2_IRQ_PRIORITY 7 167#define STM32_ICU_USE_TIM11 FALSE
160#define STM32_ICU_TIM3_IRQ_PRIORITY 7
161#define STM32_ICU_TIM4_IRQ_PRIORITY 7
162#define STM32_ICU_TIM5_IRQ_PRIORITY 7
163#define STM32_ICU_TIM9_IRQ_PRIORITY 7
164 168
165/* 169/*
166 * PWM driver system settings. 170 * PWM driver system settings.
167 */ 171 */
168#define STM32_PWM_USE_ADVANCED FALSE
169#define STM32_PWM_USE_TIM1 FALSE 172#define STM32_PWM_USE_TIM1 FALSE
170#define STM32_PWM_USE_TIM2 FALSE 173#define STM32_PWM_USE_TIM2 FALSE
171#define STM32_PWM_USE_TIM3 FALSE 174#define STM32_PWM_USE_TIM3 FALSE
172#define STM32_PWM_USE_TIM4 FALSE 175#define STM32_PWM_USE_TIM4 FALSE
173#define STM32_PWM_USE_TIM5 FALSE 176#define STM32_PWM_USE_TIM5 FALSE
174#define STM32_PWM_USE_TIM9 FALSE 177#define STM32_PWM_USE_TIM9 FALSE
175#define STM32_PWM_TIM1_IRQ_PRIORITY 7 178#define STM32_PWM_USE_TIM10 FALSE
176#define STM32_PWM_TIM2_IRQ_PRIORITY 7 179#define STM32_PWM_USE_TIM11 FALSE
177#define STM32_PWM_TIM3_IRQ_PRIORITY 7 180
178#define STM32_PWM_TIM4_IRQ_PRIORITY 7 181/*
179#define STM32_PWM_TIM5_IRQ_PRIORITY 7 182 * RTC driver system settings.
180#define STM32_PWM_TIM9_IRQ_PRIORITY 7 183 */
184#define STM32_RTC_PRESA_VALUE 32
185#define STM32_RTC_PRESS_VALUE 1024
186#define STM32_RTC_CR_INIT 0
187#define STM32_RTC_TAMPCR_INIT 0
181 188
182/* 189/*
183 * SERIAL driver system settings. 190 * SERIAL driver system settings.
@@ -185,9 +192,6 @@
185#define STM32_SERIAL_USE_USART1 FALSE 192#define STM32_SERIAL_USE_USART1 FALSE
186#define STM32_SERIAL_USE_USART2 FALSE 193#define STM32_SERIAL_USE_USART2 FALSE
187#define STM32_SERIAL_USE_USART6 FALSE 194#define STM32_SERIAL_USE_USART6 FALSE
188#define STM32_SERIAL_USART1_PRIORITY 12
189#define STM32_SERIAL_USART2_PRIORITY 12
190#define STM32_SERIAL_USART6_PRIORITY 12
191 195
192/* 196/*
193 * SPI driver system settings. 197 * SPI driver system settings.
@@ -227,9 +231,6 @@
227#define STM32_UART_USART2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6) 231#define STM32_UART_USART2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6)
228#define STM32_UART_USART6_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 2) 232#define STM32_UART_USART6_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 2)
229#define STM32_UART_USART6_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 7) 233#define STM32_UART_USART6_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 7)
230#define STM32_UART_USART1_IRQ_PRIORITY 12
231#define STM32_UART_USART2_IRQ_PRIORITY 12
232#define STM32_UART_USART6_IRQ_PRIORITY 12
233#define STM32_UART_USART1_DMA_PRIORITY 0 234#define STM32_UART_USART1_DMA_PRIORITY 0
234#define STM32_UART_USART2_DMA_PRIORITY 0 235#define STM32_UART_USART2_DMA_PRIORITY 0
235#define STM32_UART_USART6_DMA_PRIORITY 0 236#define STM32_UART_USART6_DMA_PRIORITY 0
@@ -241,9 +242,7 @@
241#define STM32_USB_USE_OTG1 TRUE 242#define STM32_USB_USE_OTG1 TRUE
242#define STM32_USB_OTG1_IRQ_PRIORITY 14 243#define STM32_USB_OTG1_IRQ_PRIORITY 14
243#define STM32_USB_OTG1_RX_FIFO_SIZE 512 244#define STM32_USB_OTG1_RX_FIFO_SIZE 512
244#define STM32_USB_OTG_THREAD_PRIO NORMALPRIO+1 245#define STM32_USB_HOST_WAKEUP_DURATION 2
245#define STM32_USB_OTG_THREAD_STACK_SIZE 128
246#define STM32_USB_OTGFIFO_FILL_BASEPRI 0
247 246
248/* 247/*
249 * WDG driver system settings. 248 * WDG driver system settings.
diff --git a/platforms/chibios/boards/GENERIC_STM32_F405XG/board/board.mk b/platforms/chibios/boards/GENERIC_STM32_F405XG/board/board.mk
new file mode 100644
index 000000000..6c837bb8e
--- /dev/null
+++ b/platforms/chibios/boards/GENERIC_STM32_F405XG/board/board.mk
@@ -0,0 +1,9 @@
1# List of all the board related files.
2BOARDSRC = $(CHIBIOS)/os/hal/boards/ST_STM32F4_DISCOVERY/board.c
3
4# Required include directories
5BOARDINC = $(CHIBIOS)/os/hal/boards/ST_STM32F4_DISCOVERY
6
7# Shared variables
8ALLCSRC += $(BOARDSRC)
9ALLINC += $(BOARDINC) \ No newline at end of file
diff --git a/platforms/chibios/boards/GENERIC_STM32_F405XG/configs/board.h b/platforms/chibios/boards/GENERIC_STM32_F405XG/configs/board.h
new file mode 100644
index 000000000..8cb771bc1
--- /dev/null
+++ b/platforms/chibios/boards/GENERIC_STM32_F405XG/configs/board.h
@@ -0,0 +1,28 @@
1/* Copyright 2020 Nick Brassel (tzarc)
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <https://www.gnu.org/licenses/>.
15 */
16#pragma once
17
18#define STM32_HSECLK 12000000
19// The following is required to disable the pull-down on PA9, when PA9 is used for the keyboard matrix:
20#define BOARD_OTG_NOVBUSSENS
21
22#include_next "board.h"
23
24#undef STM32_HSE_BYPASS
25
26#undef STM32F407xx
27#define STM32F405xG
28#define STM32F405xx
diff --git a/platforms/chibios/boards/GENERIC_STM32_F405XG/configs/config.h b/platforms/chibios/boards/GENERIC_STM32_F405XG/configs/config.h
new file mode 100644
index 000000000..cc52a953e
--- /dev/null
+++ b/platforms/chibios/boards/GENERIC_STM32_F405XG/configs/config.h
@@ -0,0 +1,23 @@
1/* Copyright 2021 Andrei Purdea
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17/* Address for jumping to bootloader on STM32 chips. */
18/* It is chip dependent, the correct number can be looked up by checking against ST's application note AN2606.
19 */
20#define STM32_BOOTLOADER_ADDRESS 0x1FFF0000
21#ifndef EARLY_INIT_PERFORM_BOOTLOADER_JUMP
22# define EARLY_INIT_PERFORM_BOOTLOADER_JUMP TRUE
23#endif
diff --git a/platforms/chibios/boards/GENERIC_STM32_F405XG/configs/mcuconf.h b/platforms/chibios/boards/GENERIC_STM32_F405XG/configs/mcuconf.h
new file mode 100644
index 000000000..908a580a9
--- /dev/null
+++ b/platforms/chibios/boards/GENERIC_STM32_F405XG/configs/mcuconf.h
@@ -0,0 +1,352 @@
1/*
2 ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15*/
16
17#ifndef MCUCONF_H
18#define MCUCONF_H
19
20/*
21 * STM32F4xx drivers configuration.
22 * The following settings override the default settings present in
23 * the various device driver implementation headers.
24 * Note that the settings for each driver only have effect if the whole
25 * driver is enabled in halconf.h.
26 *
27 * IRQ priorities:
28 * 15...0 Lowest...Highest.
29 *
30 * DMA priorities:
31 * 0...3 Lowest...Highest.
32 */
33
34#define STM32F4xx_MCUCONF
35#define STM32F405_MCUCONF
36#define STM32F415_MCUCONF
37#define STM32F407_MCUCONF
38#define STM32F417_MCUCONF
39
40/*
41 * HAL driver system settings.
42 */
43#define STM32_NO_INIT FALSE
44#define STM32_PVD_ENABLE FALSE
45#define STM32_PLS STM32_PLS_LEV0
46#define STM32_BKPRAM_ENABLE FALSE
47#define STM32_HSI_ENABLED TRUE
48#define STM32_LSI_ENABLED TRUE
49#define STM32_HSE_ENABLED TRUE
50#define STM32_LSE_ENABLED FALSE
51#define STM32_CLOCK48_REQUIRED TRUE
52#define STM32_SW STM32_SW_PLL
53#define STM32_PLLSRC STM32_PLLSRC_HSE
54#define STM32_PLLM_VALUE 12
55#define STM32_PLLN_VALUE 336
56#define STM32_PLLP_VALUE 2
57#define STM32_PLLQ_VALUE 7
58#define STM32_HPRE STM32_HPRE_DIV1
59#define STM32_PPRE1 STM32_PPRE1_DIV4
60#define STM32_PPRE2 STM32_PPRE2_DIV2
61#define STM32_RTCSEL STM32_RTCSEL_LSI
62#define STM32_RTCPRE_VALUE 8
63#define STM32_MCO1SEL STM32_MCO1SEL_HSI
64#define STM32_MCO1PRE STM32_MCO1PRE_DIV1
65#define STM32_MCO2SEL STM32_MCO2SEL_SYSCLK
66#define STM32_MCO2PRE STM32_MCO2PRE_DIV5
67#define STM32_I2SSRC STM32_I2SSRC_CKIN
68#define STM32_PLLI2SN_VALUE 192
69#define STM32_PLLI2SR_VALUE 5
70
71/*
72 * IRQ system settings.
73 */
74#define STM32_IRQ_EXTI0_PRIORITY 6
75#define STM32_IRQ_EXTI1_PRIORITY 6
76#define STM32_IRQ_EXTI2_PRIORITY 6
77#define STM32_IRQ_EXTI3_PRIORITY 6
78#define STM32_IRQ_EXTI4_PRIORITY 6
79#define STM32_IRQ_EXTI5_9_PRIORITY 6
80#define STM32_IRQ_EXTI10_15_PRIORITY 6
81#define STM32_IRQ_EXTI16_PRIORITY 6
82#define STM32_IRQ_EXTI17_PRIORITY 15
83#define STM32_IRQ_EXTI18_PRIORITY 6
84#define STM32_IRQ_EXTI19_PRIORITY 6
85#define STM32_IRQ_EXTI20_PRIORITY 6
86#define STM32_IRQ_EXTI21_PRIORITY 15
87#define STM32_IRQ_EXTI22_PRIORITY 15
88
89/*
90 * ADC driver system settings.
91 */
92#define STM32_ADC_ADCPRE ADC_CCR_ADCPRE_DIV4
93#define STM32_ADC_USE_ADC1 FALSE
94#define STM32_ADC_USE_ADC2 FALSE
95#define STM32_ADC_USE_ADC3 FALSE
96#define STM32_ADC_ADC1_DMA_STREAM STM32_DMA_STREAM_ID(2, 4)
97#define STM32_ADC_ADC2_DMA_STREAM STM32_DMA_STREAM_ID(2, 2)
98#define STM32_ADC_ADC3_DMA_STREAM STM32_DMA_STREAM_ID(2, 1)
99#define STM32_ADC_ADC1_DMA_PRIORITY 2
100#define STM32_ADC_ADC2_DMA_PRIORITY 2
101#define STM32_ADC_ADC3_DMA_PRIORITY 2
102#define STM32_ADC_IRQ_PRIORITY 6
103#define STM32_ADC_ADC1_DMA_IRQ_PRIORITY 6
104#define STM32_ADC_ADC2_DMA_IRQ_PRIORITY 6
105#define STM32_ADC_ADC3_DMA_IRQ_PRIORITY 6
106
107/*
108 * CAN driver system settings.
109 */
110#define STM32_CAN_USE_CAN1 FALSE
111#define STM32_CAN_USE_CAN2 FALSE
112#define STM32_CAN_CAN1_IRQ_PRIORITY 11
113#define STM32_CAN_CAN2_IRQ_PRIORITY 11
114
115/*
116 * DAC driver system settings.
117 */
118#define STM32_DAC_DUAL_MODE FALSE
119#define STM32_DAC_USE_DAC1_CH1 FALSE
120#define STM32_DAC_USE_DAC1_CH2 FALSE
121#define STM32_DAC_DAC1_CH1_IRQ_PRIORITY 10
122#define STM32_DAC_DAC1_CH2_IRQ_PRIORITY 10
123#define STM32_DAC_DAC1_CH1_DMA_PRIORITY 2
124#define STM32_DAC_DAC1_CH2_DMA_PRIORITY 2
125#define STM32_DAC_DAC1_CH1_DMA_STREAM STM32_DMA_STREAM_ID(1, 5)
126#define STM32_DAC_DAC1_CH2_DMA_STREAM STM32_DMA_STREAM_ID(1, 6)
127
128/*
129 * GPT driver system settings.
130 */
131#define STM32_GPT_USE_TIM1 FALSE
132#define STM32_GPT_USE_TIM2 FALSE
133#define STM32_GPT_USE_TIM3 FALSE
134#define STM32_GPT_USE_TIM4 FALSE
135#define STM32_GPT_USE_TIM5 FALSE
136#define STM32_GPT_USE_TIM6 FALSE
137#define STM32_GPT_USE_TIM7 FALSE
138#define STM32_GPT_USE_TIM8 FALSE
139#define STM32_GPT_USE_TIM9 FALSE
140#define STM32_GPT_USE_TIM11 FALSE
141#define STM32_GPT_USE_TIM12 FALSE
142#define STM32_GPT_USE_TIM14 FALSE
143#define STM32_GPT_TIM1_IRQ_PRIORITY 7
144#define STM32_GPT_TIM2_IRQ_PRIORITY 7
145#define STM32_GPT_TIM3_IRQ_PRIORITY 7
146#define STM32_GPT_TIM4_IRQ_PRIORITY 7
147#define STM32_GPT_TIM5_IRQ_PRIORITY 7
148#define STM32_GPT_TIM6_IRQ_PRIORITY 7
149#define STM32_GPT_TIM7_IRQ_PRIORITY 7
150#define STM32_GPT_TIM8_IRQ_PRIORITY 7
151#define STM32_GPT_TIM9_IRQ_PRIORITY 7
152#define STM32_GPT_TIM11_IRQ_PRIORITY 7
153#define STM32_GPT_TIM12_IRQ_PRIORITY 7
154#define STM32_GPT_TIM14_IRQ_PRIORITY 7
155
156/*
157 * I2C driver system settings.
158 */
159#define STM32_I2C_USE_I2C1 FALSE
160#define STM32_I2C_USE_I2C2 FALSE
161#define STM32_I2C_USE_I2C3 FALSE
162#define STM32_I2C_BUSY_TIMEOUT 50
163#define STM32_I2C_I2C1_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0)
164#define STM32_I2C_I2C1_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6)
165#define STM32_I2C_I2C2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2)
166#define STM32_I2C_I2C2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7)
167#define STM32_I2C_I2C3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2)
168#define STM32_I2C_I2C3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4)
169#define STM32_I2C_I2C1_IRQ_PRIORITY 5
170#define STM32_I2C_I2C2_IRQ_PRIORITY 5
171#define STM32_I2C_I2C3_IRQ_PRIORITY 5
172#define STM32_I2C_I2C1_DMA_PRIORITY 3
173#define STM32_I2C_I2C2_DMA_PRIORITY 3
174#define STM32_I2C_I2C3_DMA_PRIORITY 3
175#define STM32_I2C_DMA_ERROR_HOOK(i2cp) osalSysHalt("DMA failure")
176
177/*
178 * I2S driver system settings.
179 */
180#define STM32_I2S_USE_SPI2 FALSE
181#define STM32_I2S_USE_SPI3 FALSE
182#define STM32_I2S_SPI2_IRQ_PRIORITY 10
183#define STM32_I2S_SPI3_IRQ_PRIORITY 10
184#define STM32_I2S_SPI2_DMA_PRIORITY 1
185#define STM32_I2S_SPI3_DMA_PRIORITY 1
186#define STM32_I2S_SPI2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 3)
187#define STM32_I2S_SPI2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4)
188#define STM32_I2S_SPI3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0)
189#define STM32_I2S_SPI3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7)
190#define STM32_I2S_DMA_ERROR_HOOK(i2sp) osalSysHalt("DMA failure")
191
192/*
193 * ICU driver system settings.
194 */
195#define STM32_ICU_USE_TIM1 FALSE
196#define STM32_ICU_USE_TIM2 FALSE
197#define STM32_ICU_USE_TIM3 FALSE
198#define STM32_ICU_USE_TIM4 FALSE
199#define STM32_ICU_USE_TIM5 FALSE
200#define STM32_ICU_USE_TIM8 FALSE
201#define STM32_ICU_USE_TIM9 FALSE
202#define STM32_ICU_TIM1_IRQ_PRIORITY 7
203#define STM32_ICU_TIM2_IRQ_PRIORITY 7
204#define STM32_ICU_TIM3_IRQ_PRIORITY 7
205#define STM32_ICU_TIM4_IRQ_PRIORITY 7
206#define STM32_ICU_TIM5_IRQ_PRIORITY 7
207#define STM32_ICU_TIM8_IRQ_PRIORITY 7
208#define STM32_ICU_TIM9_IRQ_PRIORITY 7
209
210/*
211 * MAC driver system settings.
212 */
213#define STM32_MAC_TRANSMIT_BUFFERS 2
214#define STM32_MAC_RECEIVE_BUFFERS 4
215#define STM32_MAC_BUFFERS_SIZE 1522
216#define STM32_MAC_PHY_TIMEOUT 100
217#define STM32_MAC_ETH1_CHANGE_PHY_STATE TRUE
218#define STM32_MAC_ETH1_IRQ_PRIORITY 13
219#define STM32_MAC_IP_CHECKSUM_OFFLOAD 0
220
221/*
222 * PWM driver system settings.
223 */
224#define STM32_PWM_USE_ADVANCED FALSE
225#define STM32_PWM_USE_TIM1 FALSE
226#define STM32_PWM_USE_TIM2 FALSE
227#define STM32_PWM_USE_TIM3 FALSE
228#define STM32_PWM_USE_TIM4 FALSE
229#define STM32_PWM_USE_TIM5 FALSE
230#define STM32_PWM_USE_TIM8 FALSE
231#define STM32_PWM_USE_TIM9 FALSE
232#define STM32_PWM_TIM1_IRQ_PRIORITY 7
233#define STM32_PWM_TIM2_IRQ_PRIORITY 7
234#define STM32_PWM_TIM3_IRQ_PRIORITY 7
235#define STM32_PWM_TIM4_IRQ_PRIORITY 7
236#define STM32_PWM_TIM5_IRQ_PRIORITY 7
237#define STM32_PWM_TIM8_IRQ_PRIORITY 7
238#define STM32_PWM_TIM9_IRQ_PRIORITY 7
239
240/*
241 * RTC driver system settings.
242 */
243#define STM32_RTC_PRESA_VALUE 32
244#define STM32_RTC_PRESS_VALUE 1024
245#define STM32_RTC_CR_INIT 0
246#define STM32_RTC_TAMPCR_INIT 0
247
248/*
249 * SDC driver system settings.
250 */
251#define STM32_SDC_SDIO_DMA_PRIORITY 3
252#define STM32_SDC_SDIO_IRQ_PRIORITY 9
253#define STM32_SDC_WRITE_TIMEOUT_MS 1000
254#define STM32_SDC_READ_TIMEOUT_MS 1000
255#define STM32_SDC_CLOCK_ACTIVATION_DELAY 10
256#define STM32_SDC_SDIO_UNALIGNED_SUPPORT TRUE
257#define STM32_SDC_SDIO_DMA_STREAM STM32_DMA_STREAM_ID(2, 3)
258
259/*
260 * SERIAL driver system settings.
261 */
262#define STM32_SERIAL_USE_USART1 FALSE
263#define STM32_SERIAL_USE_USART2 FALSE
264#define STM32_SERIAL_USE_USART3 FALSE
265#define STM32_SERIAL_USE_UART4 FALSE
266#define STM32_SERIAL_USE_UART5 FALSE
267#define STM32_SERIAL_USE_USART6 FALSE
268#define STM32_SERIAL_USART1_PRIORITY 12
269#define STM32_SERIAL_USART2_PRIORITY 12
270#define STM32_SERIAL_USART3_PRIORITY 12
271#define STM32_SERIAL_UART4_PRIORITY 12
272#define STM32_SERIAL_UART5_PRIORITY 12
273#define STM32_SERIAL_USART6_PRIORITY 12
274
275/*
276 * SPI driver system settings.
277 */
278#define STM32_SPI_USE_SPI1 FALSE
279#define STM32_SPI_USE_SPI2 FALSE
280#define STM32_SPI_USE_SPI3 FALSE
281#define STM32_SPI_SPI1_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 0)
282#define STM32_SPI_SPI1_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 3)
283#define STM32_SPI_SPI2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 3)
284#define STM32_SPI_SPI2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4)
285#define STM32_SPI_SPI3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0)
286#define STM32_SPI_SPI3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7)
287#define STM32_SPI_SPI1_DMA_PRIORITY 1
288#define STM32_SPI_SPI2_DMA_PRIORITY 1
289#define STM32_SPI_SPI3_DMA_PRIORITY 1
290#define STM32_SPI_SPI1_IRQ_PRIORITY 10
291#define STM32_SPI_SPI2_IRQ_PRIORITY 10
292#define STM32_SPI_SPI3_IRQ_PRIORITY 10
293#define STM32_SPI_DMA_ERROR_HOOK(spip) osalSysHalt("DMA failure")
294
295/*
296 * ST driver system settings.
297 */
298#define STM32_ST_IRQ_PRIORITY 8
299#define STM32_ST_USE_TIMER 2
300
301/*
302 * UART driver system settings.
303 */
304#define STM32_UART_USE_USART1 FALSE
305#define STM32_UART_USE_USART2 FALSE
306#define STM32_UART_USE_USART3 FALSE
307#define STM32_UART_USE_UART4 FALSE
308#define STM32_UART_USE_UART5 FALSE
309#define STM32_UART_USE_USART6 FALSE
310#define STM32_UART_USART1_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 5)
311#define STM32_UART_USART1_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 7)
312#define STM32_UART_USART2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 5)
313#define STM32_UART_USART2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6)
314#define STM32_UART_USART3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 1)
315#define STM32_UART_USART3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 3)
316#define STM32_UART_UART4_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2)
317#define STM32_UART_UART4_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4)
318#define STM32_UART_UART5_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0)
319#define STM32_UART_UART5_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7)
320#define STM32_UART_USART6_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 2)
321#define STM32_UART_USART6_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 7)
322#define STM32_UART_USART1_IRQ_PRIORITY 12
323#define STM32_UART_USART2_IRQ_PRIORITY 12
324#define STM32_UART_USART3_IRQ_PRIORITY 12
325#define STM32_UART_UART4_IRQ_PRIORITY 12
326#define STM32_UART_UART5_IRQ_PRIORITY 12
327#define STM32_UART_USART6_IRQ_PRIORITY 12
328#define STM32_UART_USART1_DMA_PRIORITY 0
329#define STM32_UART_USART2_DMA_PRIORITY 0
330#define STM32_UART_USART3_DMA_PRIORITY 0
331#define STM32_UART_UART4_DMA_PRIORITY 0
332#define STM32_UART_UART5_DMA_PRIORITY 0
333#define STM32_UART_USART6_DMA_PRIORITY 0
334#define STM32_UART_DMA_ERROR_HOOK(uartp) osalSysHalt("DMA failure")
335
336/*
337 * USB driver system settings.
338 */
339#define STM32_USB_USE_OTG1 TRUE
340#define STM32_USB_USE_OTG2 FALSE
341#define STM32_USB_OTG1_IRQ_PRIORITY 14
342#define STM32_USB_OTG2_IRQ_PRIORITY 14
343#define STM32_USB_OTG1_RX_FIFO_SIZE 512
344#define STM32_USB_OTG2_RX_FIFO_SIZE 1024
345#define STM32_USB_HOST_WAKEUP_DURATION 2
346
347/*
348 * WDG driver system settings.
349 */
350#define STM32_WDG_USE_IWDG FALSE
351
352#endif /* MCUCONF_H */
diff --git a/platforms/chibios/boards/GENERIC_STM32_F407XE/configs/mcuconf.h b/platforms/chibios/boards/GENERIC_STM32_F407XE/configs/mcuconf.h
index 4be47fe1b..928ee56c7 100644
--- a/platforms/chibios/boards/GENERIC_STM32_F407XE/configs/mcuconf.h
+++ b/platforms/chibios/boards/GENERIC_STM32_F407XE/configs/mcuconf.h
@@ -344,9 +344,6 @@
344#define STM32_USB_OTG2_RX_FIFO_SIZE 1024 344#define STM32_USB_OTG2_RX_FIFO_SIZE 1024
345#define STM32_USB_HOST_WAKEUP_DURATION 2 345#define STM32_USB_HOST_WAKEUP_DURATION 2
346 346
347#define STM32_USB_OTG_THREAD_PRIO NORMALPRIO+1
348#define STM32_USB_OTG_THREAD_STACK_SIZE 128
349
350/* 347/*
351 * WDG driver system settings. 348 * WDG driver system settings.
352 */ 349 */
diff --git a/platforms/chibios/boards/GENERIC_STM32_F446XE/configs/mcuconf.h b/platforms/chibios/boards/GENERIC_STM32_F446XE/configs/mcuconf.h
index d2de75590..566c146c2 100644
--- a/platforms/chibios/boards/GENERIC_STM32_F446XE/configs/mcuconf.h
+++ b/platforms/chibios/boards/GENERIC_STM32_F446XE/configs/mcuconf.h
@@ -1,5 +1,5 @@
1/* 1/*
2 ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio 2 ChibiOS - Copyright (C) 2006..2020 Giovanni Di Sirio
3 3
4 Licensed under the Apache License, Version 2.0 (the "License"); 4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License. 5 you may not use this file except in compliance with the License.
@@ -32,11 +32,15 @@
32 */ 32 */
33 33
34#define STM32F4xx_MCUCONF 34#define STM32F4xx_MCUCONF
35#define STM32F446_MCUCONF
35 36
36/* 37/*
37 * HAL driver system settings. 38 * HAL driver system settings.
38 */ 39 */
39#define STM32_NO_INIT FALSE 40#define STM32_NO_INIT FALSE
41#define STM32_PVD_ENABLE FALSE
42#define STM32_PLS STM32_PLS_LEV0
43#define STM32_BKPRAM_ENABLE FALSE
40#define STM32_HSI_ENABLED FALSE 44#define STM32_HSI_ENABLED FALSE
41#define STM32_LSI_ENABLED TRUE 45#define STM32_LSI_ENABLED TRUE
42#define STM32_HSE_ENABLED TRUE 46#define STM32_HSE_ENABLED TRUE
@@ -70,9 +74,6 @@
70#define STM32_SAI1SEL STM32_SAI2SEL_PLLR 74#define STM32_SAI1SEL STM32_SAI2SEL_PLLR
71#define STM32_SAI2SEL STM32_SAI2SEL_PLLR 75#define STM32_SAI2SEL STM32_SAI2SEL_PLLR
72#define STM32_CK48MSEL STM32_CK48MSEL_PLLALT 76#define STM32_CK48MSEL STM32_CK48MSEL_PLLALT
73#define STM32_PVD_ENABLE FALSE
74#define STM32_PLS STM32_PLS_LEV0
75#define STM32_BKPRAM_ENABLE FALSE
76 77
77/* 78/*
78 * IRQ system settings. 79 * IRQ system settings.
@@ -92,6 +93,30 @@
92#define STM32_IRQ_EXTI21_PRIORITY 15 93#define STM32_IRQ_EXTI21_PRIORITY 15
93#define STM32_IRQ_EXTI22_PRIORITY 15 94#define STM32_IRQ_EXTI22_PRIORITY 15
94 95
96#define STM32_IRQ_TIM1_BRK_TIM9_PRIORITY 7
97#define STM32_IRQ_TIM1_UP_TIM10_PRIORITY 7
98#define STM32_IRQ_TIM1_TRGCO_TIM11_PRIORITY 7
99#define STM32_IRQ_TIM1_CC_PRIORITY 7
100#define STM32_IRQ_TIM2_PRIORITY 7
101#define STM32_IRQ_TIM3_PRIORITY 7
102#define STM32_IRQ_TIM4_PRIORITY 7
103#define STM32_IRQ_TIM5_PRIORITY 7
104#define STM32_IRQ_TIM6_PRIORITY 7
105#define STM32_IRQ_TIM7_PRIORITY 7
106#define STM32_IRQ_TIM8_BRK_TIM12_PRIORITY 7
107#define STM32_IRQ_TIM8_UP_TIM13_PRIORITY 7
108#define STM32_IRQ_TIM8_TRGCO_TIM14_PRIORITY 7
109#define STM32_IRQ_TIM8_CC_PRIORITY 7
110
111#define STM32_IRQ_USART1_PRIORITY 12
112#define STM32_IRQ_USART2_PRIORITY 12
113#define STM32_IRQ_USART3_PRIORITY 12
114#define STM32_IRQ_UART4_PRIORITY 12
115#define STM32_IRQ_UART5_PRIORITY 12
116#define STM32_IRQ_USART6_PRIORITY 12
117#define STM32_IRQ_UART7_PRIORITY 12
118#define STM32_IRQ_UART8_PRIORITY 12
119
95/* 120/*
96 * ADC driver system settings. 121 * ADC driver system settings.
97 */ 122 */
@@ -143,21 +168,11 @@
143#define STM32_GPT_USE_TIM7 FALSE 168#define STM32_GPT_USE_TIM7 FALSE
144#define STM32_GPT_USE_TIM8 FALSE 169#define STM32_GPT_USE_TIM8 FALSE
145#define STM32_GPT_USE_TIM9 FALSE 170#define STM32_GPT_USE_TIM9 FALSE
171#define STM32_GPT_USE_TIM10 FALSE
146#define STM32_GPT_USE_TIM11 FALSE 172#define STM32_GPT_USE_TIM11 FALSE
147#define STM32_GPT_USE_TIM12 FALSE 173#define STM32_GPT_USE_TIM12 FALSE
174#define STM32_GPT_USE_TIM13 FALSE
148#define STM32_GPT_USE_TIM14 FALSE 175#define STM32_GPT_USE_TIM14 FALSE
149#define STM32_GPT_TIM1_IRQ_PRIORITY 7
150#define STM32_GPT_TIM2_IRQ_PRIORITY 7
151#define STM32_GPT_TIM3_IRQ_PRIORITY 7
152#define STM32_GPT_TIM4_IRQ_PRIORITY 7
153#define STM32_GPT_TIM5_IRQ_PRIORITY 7
154#define STM32_GPT_TIM6_IRQ_PRIORITY 7
155#define STM32_GPT_TIM7_IRQ_PRIORITY 7
156#define STM32_GPT_TIM8_IRQ_PRIORITY 7
157#define STM32_GPT_TIM9_IRQ_PRIORITY 7
158#define STM32_GPT_TIM11_IRQ_PRIORITY 7
159#define STM32_GPT_TIM12_IRQ_PRIORITY 7
160#define STM32_GPT_TIM14_IRQ_PRIORITY 7
161 176
162/* 177/*
163 * I2C driver system settings. 178 * I2C driver system settings.
@@ -205,13 +220,11 @@
205#define STM32_ICU_USE_TIM5 FALSE 220#define STM32_ICU_USE_TIM5 FALSE
206#define STM32_ICU_USE_TIM8 FALSE 221#define STM32_ICU_USE_TIM8 FALSE
207#define STM32_ICU_USE_TIM9 FALSE 222#define STM32_ICU_USE_TIM9 FALSE
208#define STM32_ICU_TIM1_IRQ_PRIORITY 7 223#define STM32_ICU_USE_TIM10 FALSE
209#define STM32_ICU_TIM2_IRQ_PRIORITY 7 224#define STM32_ICU_USE_TIM11 FALSE
210#define STM32_ICU_TIM3_IRQ_PRIORITY 7 225#define STM32_ICU_USE_TIM12 FALSE
211#define STM32_ICU_TIM4_IRQ_PRIORITY 7 226#define STM32_ICU_USE_TIM13 FALSE
212#define STM32_ICU_TIM5_IRQ_PRIORITY 7 227#define STM32_ICU_USE_TIM14 FALSE
213#define STM32_ICU_TIM8_IRQ_PRIORITY 7
214#define STM32_ICU_TIM9_IRQ_PRIORITY 7
215 228
216/* 229/*
217 * MAC driver system settings. 230 * MAC driver system settings.
@@ -227,7 +240,6 @@
227/* 240/*
228 * PWM driver system settings. 241 * PWM driver system settings.
229 */ 242 */
230#define STM32_PWM_USE_ADVANCED FALSE
231#define STM32_PWM_USE_TIM1 FALSE 243#define STM32_PWM_USE_TIM1 FALSE
232#define STM32_PWM_USE_TIM2 FALSE 244#define STM32_PWM_USE_TIM2 FALSE
233#define STM32_PWM_USE_TIM3 FALSE 245#define STM32_PWM_USE_TIM3 FALSE
@@ -235,13 +247,19 @@
235#define STM32_PWM_USE_TIM5 FALSE 247#define STM32_PWM_USE_TIM5 FALSE
236#define STM32_PWM_USE_TIM8 FALSE 248#define STM32_PWM_USE_TIM8 FALSE
237#define STM32_PWM_USE_TIM9 FALSE 249#define STM32_PWM_USE_TIM9 FALSE
238#define STM32_PWM_TIM1_IRQ_PRIORITY 7 250#define STM32_PWM_USE_TIM10 FALSE
239#define STM32_PWM_TIM2_IRQ_PRIORITY 7 251#define STM32_PWM_USE_TIM11 FALSE
240#define STM32_PWM_TIM3_IRQ_PRIORITY 7 252#define STM32_PWM_USE_TIM12 FALSE
241#define STM32_PWM_TIM4_IRQ_PRIORITY 7 253#define STM32_PWM_USE_TIM13 FALSE
242#define STM32_PWM_TIM5_IRQ_PRIORITY 7 254#define STM32_PWM_USE_TIM14 FALSE
243#define STM32_PWM_TIM8_IRQ_PRIORITY 7 255
244#define STM32_PWM_TIM9_IRQ_PRIORITY 7 256/*
257 * RTC driver system settings.
258 */
259#define STM32_RTC_PRESA_VALUE 32
260#define STM32_RTC_PRESS_VALUE 1024
261#define STM32_RTC_CR_INIT 0
262#define STM32_RTC_TAMPCR_INIT 0
245 263
246/* 264/*
247 * SDC driver system settings. 265 * SDC driver system settings.
@@ -265,14 +283,6 @@
265#define STM32_SERIAL_USE_USART6 FALSE 283#define STM32_SERIAL_USE_USART6 FALSE
266#define STM32_SERIAL_USE_UART7 FALSE 284#define STM32_SERIAL_USE_UART7 FALSE
267#define STM32_SERIAL_USE_UART8 FALSE 285#define STM32_SERIAL_USE_UART8 FALSE
268#define STM32_SERIAL_USART1_PRIORITY 12
269#define STM32_SERIAL_USART2_PRIORITY 12
270#define STM32_SERIAL_USART3_PRIORITY 12
271#define STM32_SERIAL_UART4_PRIORITY 12
272#define STM32_SERIAL_UART5_PRIORITY 12
273#define STM32_SERIAL_USART6_PRIORITY 12
274#define STM32_SERIAL_UART7_PRIORITY 12
275#define STM32_SERIAL_UART8_PRIORITY 12
276 286
277/* 287/*
278 * SPI driver system settings. 288 * SPI driver system settings.
@@ -281,6 +291,8 @@
281#define STM32_SPI_USE_SPI2 FALSE 291#define STM32_SPI_USE_SPI2 FALSE
282#define STM32_SPI_USE_SPI3 FALSE 292#define STM32_SPI_USE_SPI3 FALSE
283#define STM32_SPI_USE_SPI4 FALSE 293#define STM32_SPI_USE_SPI4 FALSE
294#define STM32_SPI_USE_SPI5 FALSE
295#define STM32_SPI_USE_SPI6 FALSE
284#define STM32_SPI_SPI1_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 0) 296#define STM32_SPI_SPI1_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 0)
285#define STM32_SPI_SPI1_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 3) 297#define STM32_SPI_SPI1_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 3)
286#define STM32_SPI_SPI2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 3) 298#define STM32_SPI_SPI2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 3)
@@ -289,14 +301,22 @@
289#define STM32_SPI_SPI3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7) 301#define STM32_SPI_SPI3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7)
290#define STM32_SPI_SPI4_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 0) 302#define STM32_SPI_SPI4_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 0)
291#define STM32_SPI_SPI4_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 1) 303#define STM32_SPI_SPI4_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 1)
304#define STM32_SPI_SPI5_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 3)
305#define STM32_SPI_SPI5_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 4)
306#define STM32_SPI_SPI6_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 6)
307#define STM32_SPI_SPI6_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 5)
292#define STM32_SPI_SPI1_DMA_PRIORITY 1 308#define STM32_SPI_SPI1_DMA_PRIORITY 1
293#define STM32_SPI_SPI2_DMA_PRIORITY 1 309#define STM32_SPI_SPI2_DMA_PRIORITY 1
294#define STM32_SPI_SPI3_DMA_PRIORITY 1 310#define STM32_SPI_SPI3_DMA_PRIORITY 1
295#define STM32_SPI_SPI4_DMA_PRIORITY 1 311#define STM32_SPI_SPI4_DMA_PRIORITY 1
312#define STM32_SPI_SPI5_DMA_PRIORITY 1
313#define STM32_SPI_SPI6_DMA_PRIORITY 1
296#define STM32_SPI_SPI1_IRQ_PRIORITY 10 314#define STM32_SPI_SPI1_IRQ_PRIORITY 10
297#define STM32_SPI_SPI2_IRQ_PRIORITY 10 315#define STM32_SPI_SPI2_IRQ_PRIORITY 10
298#define STM32_SPI_SPI3_IRQ_PRIORITY 10 316#define STM32_SPI_SPI3_IRQ_PRIORITY 10
299#define STM32_SPI_SPI4_IRQ_PRIORITY 10 317#define STM32_SPI_SPI4_IRQ_PRIORITY 10
318#define STM32_SPI_SPI5_IRQ_PRIORITY 10
319#define STM32_SPI_SPI6_IRQ_PRIORITY 10
300#define STM32_SPI_DMA_ERROR_HOOK(spip) osalSysHalt("DMA failure") 320#define STM32_SPI_DMA_ERROR_HOOK(spip) osalSysHalt("DMA failure")
301 321
302/* 322/*
@@ -326,12 +346,6 @@
326#define STM32_UART_UART5_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7) 346#define STM32_UART_UART5_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7)
327#define STM32_UART_USART6_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 2) 347#define STM32_UART_USART6_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 2)
328#define STM32_UART_USART6_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 7) 348#define STM32_UART_USART6_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 7)
329#define STM32_UART_USART1_IRQ_PRIORITY 12
330#define STM32_UART_USART2_IRQ_PRIORITY 12
331#define STM32_UART_USART3_IRQ_PRIORITY 12
332#define STM32_UART_UART4_IRQ_PRIORITY 12
333#define STM32_UART_UART5_IRQ_PRIORITY 12
334#define STM32_UART_USART6_IRQ_PRIORITY 12
335#define STM32_UART_USART1_DMA_PRIORITY 0 349#define STM32_UART_USART1_DMA_PRIORITY 0
336#define STM32_UART_USART2_DMA_PRIORITY 0 350#define STM32_UART_USART2_DMA_PRIORITY 0
337#define STM32_UART_USART3_DMA_PRIORITY 0 351#define STM32_UART_USART3_DMA_PRIORITY 0
@@ -349,9 +363,7 @@
349#define STM32_USB_OTG2_IRQ_PRIORITY 14 363#define STM32_USB_OTG2_IRQ_PRIORITY 14
350#define STM32_USB_OTG1_RX_FIFO_SIZE 512 364#define STM32_USB_OTG1_RX_FIFO_SIZE 512
351#define STM32_USB_OTG2_RX_FIFO_SIZE 1024 365#define STM32_USB_OTG2_RX_FIFO_SIZE 1024
352#define STM32_USB_OTG_THREAD_PRIO LOWPRIO 366#define STM32_USB_HOST_WAKEUP_DURATION 2
353#define STM32_USB_OTG_THREAD_STACK_SIZE 128
354#define STM32_USB_OTGFIFO_FILL_BASEPRI 0
355 367
356/* 368/*
357 * WDG driver system settings. 369 * WDG driver system settings.
diff --git a/platforms/chibios/boards/GENERIC_STM32_G431XB/configs/mcuconf.h b/platforms/chibios/boards/GENERIC_STM32_G431XB/configs/mcuconf.h
index 182d4885d..d11502830 100644
--- a/platforms/chibios/boards/GENERIC_STM32_G431XB/configs/mcuconf.h
+++ b/platforms/chibios/boards/GENERIC_STM32_G431XB/configs/mcuconf.h
@@ -40,9 +40,24 @@
40 */ 40 */
41#define STM32_NO_INIT FALSE 41#define STM32_NO_INIT FALSE
42#define STM32_VOS STM32_VOS_RANGE1 42#define STM32_VOS STM32_VOS_RANGE1
43#define STM32_PWR_BOOST TRUE
43#define STM32_PWR_CR2 (PWR_CR2_PLS_LEV0) 44#define STM32_PWR_CR2 (PWR_CR2_PLS_LEV0)
44#define STM32_PWR_CR3 (PWR_CR3_EIWF) 45#define STM32_PWR_CR3 (PWR_CR3_EIWF)
45#define STM32_PWR_CR4 (0U) 46#define STM32_PWR_CR4 (0U)
47#define STM32_PWR_PUCRA (0U)
48#define STM32_PWR_PDCRA (0U)
49#define STM32_PWR_PUCRB (0U)
50#define STM32_PWR_PDCRB (0U)
51#define STM32_PWR_PUCRC (0U)
52#define STM32_PWR_PDCRC (0U)
53#define STM32_PWR_PUCRD (0U)
54#define STM32_PWR_PDCRD (0U)
55#define STM32_PWR_PUCRE (0U)
56#define STM32_PWR_PDCRE (0U)
57#define STM32_PWR_PUCRF (0U)
58#define STM32_PWR_PDCRF (0U)
59#define STM32_PWR_PUCRG (0U)
60#define STM32_PWR_PDCRG (0U)
46#define STM32_HSI16_ENABLED TRUE 61#define STM32_HSI16_ENABLED TRUE
47#define STM32_HSI48_ENABLED TRUE 62#define STM32_HSI48_ENABLED TRUE
48#define STM32_HSE_ENABLED FALSE 63#define STM32_HSE_ENABLED FALSE
diff --git a/platforms/chibios/boards/GENERIC_STM32_G474XE/configs/mcuconf.h b/platforms/chibios/boards/GENERIC_STM32_G474XE/configs/mcuconf.h
index 117e920e3..5710e2cb4 100644
--- a/platforms/chibios/boards/GENERIC_STM32_G474XE/configs/mcuconf.h
+++ b/platforms/chibios/boards/GENERIC_STM32_G474XE/configs/mcuconf.h
@@ -42,9 +42,24 @@
42 */ 42 */
43#define STM32_NO_INIT FALSE 43#define STM32_NO_INIT FALSE
44#define STM32_VOS STM32_VOS_RANGE1 44#define STM32_VOS STM32_VOS_RANGE1
45#define STM32_PWR_BOOST TRUE
45#define STM32_PWR_CR2 (PWR_CR2_PLS_LEV0) 46#define STM32_PWR_CR2 (PWR_CR2_PLS_LEV0)
46#define STM32_PWR_CR3 (PWR_CR3_EIWF) 47#define STM32_PWR_CR3 (PWR_CR3_EIWF)
47#define STM32_PWR_CR4 (0U) 48#define STM32_PWR_CR4 (0U)
49#define STM32_PWR_PUCRA (0U)
50#define STM32_PWR_PDCRA (0U)
51#define STM32_PWR_PUCRB (0U)
52#define STM32_PWR_PDCRB (0U)
53#define STM32_PWR_PUCRC (0U)
54#define STM32_PWR_PDCRC (0U)
55#define STM32_PWR_PUCRD (0U)
56#define STM32_PWR_PDCRD (0U)
57#define STM32_PWR_PUCRE (0U)
58#define STM32_PWR_PDCRE (0U)
59#define STM32_PWR_PUCRF (0U)
60#define STM32_PWR_PDCRF (0U)
61#define STM32_PWR_PUCRG (0U)
62#define STM32_PWR_PDCRG (0U)
48#define STM32_HSI16_ENABLED TRUE 63#define STM32_HSI16_ENABLED TRUE
49#define STM32_HSI48_ENABLED TRUE 64#define STM32_HSI48_ENABLED TRUE
50#define STM32_HSE_ENABLED FALSE 65#define STM32_HSE_ENABLED FALSE
diff --git a/platforms/chibios/boards/QMK_PROTON_C/configs/chconf.h b/platforms/chibios/boards/QMK_PROTON_C/configs/chconf.h
index a1cbf6808..f81233296 100644
--- a/platforms/chibios/boards/QMK_PROTON_C/configs/chconf.h
+++ b/platforms/chibios/boards/QMK_PROTON_C/configs/chconf.h
@@ -40,7 +40,7 @@
40 40
41/** 41/**
42 * @brief System time counter resolution. 42 * @brief System time counter resolution.
43 * @note Allowed values are 16 or 32 bits. 43 * @note Allowed values are 16, 32 or 64 bits.
44 */ 44 */
45#if !defined(CH_CFG_ST_RESOLUTION) 45#if !defined(CH_CFG_ST_RESOLUTION)
46#define CH_CFG_ST_RESOLUTION 32 46#define CH_CFG_ST_RESOLUTION 32
diff --git a/platforms/chibios/boards/QMK_PROTON_C/configs/config.h b/platforms/chibios/boards/QMK_PROTON_C/configs/config.h
index a73f0c0b4..fa1a73c35 100644
--- a/platforms/chibios/boards/QMK_PROTON_C/configs/config.h
+++ b/platforms/chibios/boards/QMK_PROTON_C/configs/config.h
@@ -18,3 +18,12 @@
18#ifndef EARLY_INIT_PERFORM_BOOTLOADER_JUMP 18#ifndef EARLY_INIT_PERFORM_BOOTLOADER_JUMP
19# define EARLY_INIT_PERFORM_BOOTLOADER_JUMP TRUE 19# define EARLY_INIT_PERFORM_BOOTLOADER_JUMP TRUE
20#endif 20#endif
21
22#ifdef CONVERT_TO_PROTON_C
23# ifndef I2C1_SDA_PIN
24# define I2C1_SDA_PIN D1
25# endif
26# ifndef I2C1_SCL_PIN
27# define I2C1_SCL_PIN D0
28# endif
29#endif
diff --git a/platforms/chibios/boards/SIPEED_LONGAN_NANO/board/board.mk b/platforms/chibios/boards/SIPEED_LONGAN_NANO/board/board.mk
new file mode 100644
index 000000000..960fc2678
--- /dev/null
+++ b/platforms/chibios/boards/SIPEED_LONGAN_NANO/board/board.mk
@@ -0,0 +1,9 @@
1# List of all the board related files.
2BOARDSRC = ${CHIBIOS_CONTRIB}/os/hal/boards/SIPEED_LONGAN_NANO/board.c
3
4# Required include directories
5BOARDINC = ${CHIBIOS_CONTRIB}/os/hal/boards/SIPEED_LONGAN_NANO
6
7# Shared variables
8ALLCSRC += $(BOARDSRC)
9ALLINC += $(BOARDINC)
diff --git a/platforms/chibios/boards/SIPEED_LONGAN_NANO/configs/chconf.h b/platforms/chibios/boards/SIPEED_LONGAN_NANO/configs/chconf.h
new file mode 100644
index 000000000..6e5adb0fe
--- /dev/null
+++ b/platforms/chibios/boards/SIPEED_LONGAN_NANO/configs/chconf.h
@@ -0,0 +1,23 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17/* To compile the ChibiOS syscall stubs with picolibc
18 * the _reent struct has to be defined. */
19#if !defined(_FROM_ASM_) && defined(USE_PICOLIBC)
20struct _reent;
21#endif
22
23#include_next <chconf.h> \ No newline at end of file
diff --git a/platforms/chibios/boards/SIPEED_LONGAN_NANO/configs/mcuconf.h b/platforms/chibios/boards/SIPEED_LONGAN_NANO/configs/mcuconf.h
new file mode 100644
index 000000000..ab086567e
--- /dev/null
+++ b/platforms/chibios/boards/SIPEED_LONGAN_NANO/configs/mcuconf.h
@@ -0,0 +1,302 @@
1/*
2 ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
3 ChibiOS - Copyright (C) 2021 Stefan Kerkmann
4
5 Licensed under the Apache License, Version 2.0 (the "License");
6 you may not use this file except in compliance with the License.
7 You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16*/
17
18#pragma once
19
20#define GD32VF103_MCUCONF
21#define GD32VF103CB
22
23/*
24 * GD32VF103 drivers configuration.
25 * The following settings override the default settings present in
26 * the various device driver implementation headers.
27 * Note that the settings for each driver only have effect if the whole
28 * driver is enabled in halconf.h.
29 *
30 * IRQ priorities:
31 * 0...15 Lowest...Highest.
32 *
33 * DMA priorities:
34 * 0...3 Lowest...Highest.
35 */
36
37/*
38 * HAL driver system settings.
39*/
40
41#if defined(OVERCLOCK_120MHZ)
42/* (8MHz / 2) * 30 = 120MHz Sysclock */
43#define GD32_ALLOW_120MHZ_SYSCLK
44#define GD32_PLLMF_VALUE 30
45#define GD32_USBFSPSC GD32_USBFSPSC_DIV2P5
46#else
47/* (8MHz / 2) * 24 = 96MHz Sysclock */
48#define GD32_PLLMF_VALUE 24
49#define GD32_USBFSPSC GD32_USBFSPSC_DIV2
50#endif
51
52#define GD32_NO_INIT FALSE
53#define GD32_IRC8M_ENABLED TRUE
54#define GD32_IRC40K_ENABLED FALSE
55#define GD32_HXTAL_ENABLED TRUE
56#define GD32_LXTAL_ENABLED FALSE
57#define GD32_SCS GD32_SCS_PLL
58#define GD32_PLLSEL GD32_PLLSEL_PREDV0
59#define GD32_PREDV0SEL GD32_PREDV0SEL_HXTAL
60#define GD32_PREDV0_VALUE 2
61#define GD32_PREDV1_VALUE 2
62#define GD32_PLL1MF_VALUE 14
63#define GD32_PLL2MF_VALUE 13
64#define GD32_AHBPSC GD32_AHBPSC_DIV1
65#define GD32_APB1PSC GD32_APB1PSC_DIV2
66#define GD32_APB2PSC GD32_APB2PSC_DIV1
67#define GD32_ADCPSC GD32_ADCPSC_DIV16
68#define GD32_USB_CLOCK_REQUIRED TRUE
69#define GD32_I2S_CLOCK_REQUIRED FALSE
70#define GD32_CKOUT0SEL GD32_CKOUT0SEL_NOCLOCK
71#define GD32_RTCSRC GD32_RTCSRC_NOCLOCK
72#define GD32_PVD_ENABLE FALSE
73#define GD32_LVDT GD32_LVDT_LEV0
74
75/*
76 * ECLIC system settings.
77 */
78#define ECLIC_TRIGGER_DEFAULT ECLIC_POSTIVE_EDGE_TRIGGER
79#define ECLIC_DMA_TRIGGER ECLIC_TRIGGER_DEFAULT
80
81/*
82 * IRQ system settings.
83 */
84#define GD32_IRQ_EXTI0_PRIORITY 6
85#define GD32_IRQ_EXTI1_PRIORITY 6
86#define GD32_IRQ_EXTI2_PRIORITY 6
87#define GD32_IRQ_EXTI3_PRIORITY 6
88#define GD32_IRQ_EXTI4_PRIORITY 6
89#define GD32_IRQ_EXTI5_9_PRIORITY 6
90#define GD32_IRQ_EXTI10_15_PRIORITY 6
91#define GD32_IRQ_EXTI0_TRIGGER ECLIC_TRIGGER_DEFAULT
92#define GD32_IRQ_EXTI1_TRIGGER ECLIC_TRIGGER_DEFAULT
93#define GD32_IRQ_EXTI2_TRIGGER ECLIC_TRIGGER_DEFAULT
94#define GD32_IRQ_EXTI3_TRIGGER ECLIC_TRIGGER_DEFAULT
95#define GD32_IRQ_EXTI4_TRIGGER ECLIC_TRIGGER_DEFAULT
96#define GD32_IRQ_EXTI5_9_TRIGGER ECLIC_TRIGGER_DEFAULT
97#define GD32_IRQ_EXTI10_15_TRIGGER ECLIC_TRIGGER_DEFAULT
98
99/*
100 * ADC driver system settings.
101 */
102#define GD32_ADC_USE_ADC0 FALSE
103#define GD32_ADC_ADC0_DMA_PRIORITY 2
104#define GD32_ADC_ADC0_IRQ_PRIORITY 6
105
106/*
107 * CAN driver system settings.
108 */
109#define GD32_CAN_USE_CAN0 FALSE
110#define GD32_CAN_CAN0_IRQ_PRIORITY 11
111#define GD32_CAN_USE_CAN1 FALSE
112#define GD32_CAN_CAN1_IRQ_PRIORITY 11
113#define GD32_CAN_CAN0_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT
114#define GD32_CAN_CAN1_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT
115
116/*
117 * CRC driver system settings.
118 */
119#define GD32_CRC_USE_CRC0 FALSE
120#define GD32_CRC_CRC0_DMA_IRQ_PRIORITY 14
121#define GD32_CRC_CRC0_DMA_PRIORITY 2
122#define GD32_CRC_CRC0_DMA_STREAM GD32_DMA_STREAM_ID(0, 0)
123#define CRC_USE_DMA FALSE
124#define CRCSW_USE_CRC1 FALSE
125#define CRCSW_CRC32_TABLE FALSE
126#define CRCSW_CRC16_TABLE FALSE
127#define CRCSW_PROGRAMMABLE FALSE
128
129/*
130 * DAC driver system settings.
131 */
132#define GD32_DAC_USE_DAC_CH1 FALSE
133#define GD32_DAC_USE_DAC_CH2 FALSE
134
135/*
136 * GPT driver system settings.
137 */
138#define GD32_GPT_USE_TIM0 FALSE
139#define GD32_GPT_USE_TIM1 FALSE
140#define GD32_GPT_USE_TIM2 FALSE
141#define GD32_GPT_USE_TIM3 FALSE
142#define GD32_GPT_USE_TIM4 FALSE
143#define GD32_GPT_TIM0_IRQ_PRIORITY 7
144#define GD32_GPT_TIM1_IRQ_PRIORITY 7
145#define GD32_GPT_TIM2_IRQ_PRIORITY 7
146#define GD32_GPT_TIM3_IRQ_PRIORITY 7
147#define GD32_GPT_TIM4_IRQ_PRIORITY 7
148#define GD32_GPT_TIM0_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT
149#define GD32_GPT_TIM1_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT
150#define GD32_GPT_TIM2_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT
151#define GD32_GPT_TIM3_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT
152#define GD32_GPT_TIM4_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT
153#define GD32_GPT_TIM5_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT
154#define GD32_GPT_TIM6_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT
155
156/*
157 * I2S driver system settings.
158 */
159#define GD32_I2S_USE_SPI1 FALSE
160#define GD32_I2S_USE_SPI2 FALSE
161#define GD32_I2S_SPI1_IRQ_PRIORITY 10
162#define GD32_I2S_SPI2_IRQ_PRIORITY 10
163#define GD32_I2S_SPI1_DMA_PRIORITY 1
164#define GD32_I2S_SPI2_DMA_PRIORITY 1
165#define GD32_I2S_DMA_ERROR_HOOK(i2sp) osalSysHalt("DMA failure")
166
167/*
168 * I2C driver system settings.
169 */
170#define GD32_I2C_USE_I2C0 FALSE
171#define GD32_I2C_USE_I2C1 FALSE
172#define GD32_I2C_BUSY_TIMEOUT 50
173#define GD32_I2C_I2C0_IRQ_PRIORITY 10
174#define GD32_I2C_I2C1_IRQ_PRIORITY 5
175#define GD32_I2C_I2C0_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT
176#define GD32_I2C_I2C1_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT
177#define GD32_I2C_I2C0_DMA_PRIORITY 2
178#define GD32_I2C_I2C1_DMA_PRIORITY 2
179#define GD32_I2C_DMA_ERROR_HOOK(i2cp) osalSysHalt("DMA failure")
180
181/*
182 * ICU driver system settings.
183 */
184#define GD32_ICU_USE_TIM0 FALSE
185#define GD32_ICU_USE_TIM1 FALSE
186#define GD32_ICU_USE_TIM2 FALSE
187#define GD32_ICU_USE_TIM3 FALSE
188#define GD32_ICU_USE_TIM4 FALSE
189#define GD32_ICU_TIM0_IRQ_PRIORITY 7
190#define GD32_ICU_TIM1_IRQ_PRIORITY 7
191#define GD32_ICU_TIM2_IRQ_PRIORITY 7
192#define GD32_ICU_TIM3_IRQ_PRIORITY 7
193#define GD32_ICU_TIM4_IRQ_PRIORITY 7
194#define GD32_ICU_TIM0_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT
195#define GD32_ICU_TIM1_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT
196#define GD32_ICU_TIM2_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT
197#define GD32_ICU_TIM3_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT
198#define GD32_ICU_TIM4_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT
199
200/*
201 * PWM driver system settings.
202 */
203#define GD32_PWM_USE_ADVANCED FALSE
204#define GD32_PWM_USE_TIM0 FALSE
205#define GD32_PWM_USE_TIM1 FALSE
206#define GD32_PWM_USE_TIM2 FALSE
207#define GD32_PWM_USE_TIM3 FALSE
208#define GD32_PWM_USE_TIM4 FALSE
209#define GD32_PWM_TIM0_IRQ_PRIORITY 10
210#define GD32_PWM_TIM1_IRQ_PRIORITY 10
211#define GD32_PWM_TIM2_IRQ_PRIORITY 10
212#define GD32_PWM_TIM3_IRQ_PRIORITY 10
213#define GD32_PWM_TIM4_IRQ_PRIORITY 10
214#define GD32_PWM_TIM0_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT
215#define GD32_PWM_TIM1_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT
216#define GD32_PWM_TIM2_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT
217#define GD32_PWM_TIM3_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT
218#define GD32_PWM_TIM4_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT
219
220/*
221 * RTC driver system settings.
222 */
223#define GD32_RTC_IRQ_PRIORITY 15
224#define GD32_RTC_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT
225
226/*
227 * SERIAL driver system settings.
228 */
229#define GD32_SERIAL_USE_USART0 FALSE
230#define GD32_SERIAL_USE_USART1 FALSE
231#define GD32_SERIAL_USE_USART2 FALSE
232#define GD32_SERIAL_USE_UART3 FALSE
233#define GD32_SERIAL_USE_UART4 FALSE
234#define GD32_SERIAL_USART0_PRIORITY 10
235#define GD32_SERIAL_USART1_PRIORITY 10
236#define GD32_SERIAL_USART2_PRIORITY 10
237#define GD32_SERIAL_UART3_PRIORITY 10
238#define GD32_SERIAL_UART4_PRIORITY 10
239#define GD32_SERIAL_USART0_TRIGGER ECLIC_TRIGGER_DEFAULT
240#define GD32_SERIAL_USART1_TRIGGER ECLIC_TRIGGER_DEFAULT
241#define GD32_SERIAL_USART2_TRIGGER ECLIC_TRIGGER_DEFAULT
242#define GD32_SERIAL_UART3_TRIGGER ECLIC_TRIGGER_DEFAULT
243#define GD32_SERIAL_UART4_TRIGGER ECLIC_TRIGGER_DEFAULT
244
245/*
246 * SPI driver system settings.
247 */
248#define GD32_SPI_USE_SPI0 FALSE
249#define GD32_SPI_USE_SPI1 FALSE
250#define GD32_SPI_USE_SPI2 FALSE
251#define GD32_SPI_SPI0_DMA_PRIORITY 1
252#define GD32_SPI_SPI1_DMA_PRIORITY 1
253#define GD32_SPI_SPI2_DMA_PRIORITY 1
254#define GD32_SPI_SPI0_IRQ_PRIORITY 10
255#define GD32_SPI_SPI1_IRQ_PRIORITY 10
256#define GD32_SPI_SPI2_IRQ_PRIORITY 10
257#define GD32_SPI_DMA_ERROR_HOOK(spip) osalSysHalt("DMA failure")
258
259/*
260 * ST driver system settings.
261 */
262#define GD32_ST_IRQ_PRIORITY 10
263#define GD32_ST_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT
264#define GD32_ST_USE_TIMER 1
265
266/*
267 * UART driver system settings.
268 */
269#define GD32_UART_USE_USART0 FALSE
270#define GD32_UART_USE_USART1 FALSE
271#define GD32_UART_USE_USART2 FALSE
272#define GD32_UART_USE_UART3 FALSE
273#define GD32_UART_USE_UART4 FALSE
274#define GD32_UART_USART0_IRQ_PRIORITY 10
275#define GD32_UART_USART1_IRQ_PRIORITY 10
276#define GD32_UART_USART2_IRQ_PRIORITY 10
277#define GD32_UART_UART3_IRQ_PRIORITY 10
278#define GD32_UART_UART4_IRQ_PRIORITY 10
279#define GD32_UART_USART0_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT
280#define GD32_UART_USART1_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT
281#define GD32_UART_USART2_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT
282#define GD32_UART_UART3_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT
283#define GD32_UART_UART4_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT
284#define GD32_UART_USART0_DMA_PRIORITY 3
285#define GD32_UART_USART1_DMA_PRIORITY 3
286#define GD32_UART_USART2_DMA_PRIORITY 3
287#define GD32_UART_UART3_DMA_PRIORITY 3
288#define GD32_UART_UART4_DMA_PRIORITY 3
289#define GD32_UART_DMA_ERROR_HOOK(uartp) osalSysHalt("DMA failure")
290
291/*
292 * USB driver system settings.
293 */
294#define GD32_USB_USE_USBFS TRUE
295#define GD32_USB_USBFS_IRQ_PRIORITY 10
296#define GD32_USB_USBFS_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT
297#define GD32_USB_USBFS_RX_FIFO_SIZE 256
298
299/*
300 * WDG driver system settings.
301 */
302#define GD32_WDG_USE_FWDGT FALSE
diff --git a/platforms/chibios/boards/common/configs/chconf.h b/platforms/chibios/boards/common/configs/chconf.h
index 44327a82d..18ad609ca 100644
--- a/platforms/chibios/boards/common/configs/chconf.h
+++ b/platforms/chibios/boards/common/configs/chconf.h
@@ -40,7 +40,7 @@
40 40
41/** 41/**
42 * @brief System time counter resolution. 42 * @brief System time counter resolution.
43 * @note Allowed values are 16 or 32 bits. 43 * @note Allowed values are 16, 32 or 64 bits.
44 */ 44 */
45#if !defined(CH_CFG_ST_RESOLUTION) 45#if !defined(CH_CFG_ST_RESOLUTION)
46#define CH_CFG_ST_RESOLUTION 32 46#define CH_CFG_ST_RESOLUTION 32
diff --git a/platforms/chibios/boards/common/ld/STM32F401xC.ld b/platforms/chibios/boards/common/ld/STM32F401xC.ld
new file mode 100644
index 000000000..8fae66cec
--- /dev/null
+++ b/platforms/chibios/boards/common/ld/STM32F401xC.ld
@@ -0,0 +1,85 @@
1/*
2 ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15*/
16
17/*
18 * STM32F401xC memory setup.
19 */
20MEMORY
21{
22 flash0 (rx) : org = 0x08000000, len = 16k /* Sector 0 - Init code as ROM bootloader assumes application starts here */
23 flash1 (rx) : org = 0x08004000, len = 16k /* Sector 1 - Emulated eeprom */
24 flash2 (rx) : org = 0x08008000, len = 256k - 32k /* Sector 2..6 - Rest of firmware */
25 flash3 (rx) : org = 0x00000000, len = 0
26 flash4 (rx) : org = 0x00000000, len = 0
27 flash5 (rx) : org = 0x00000000, len = 0
28 flash6 (rx) : org = 0x00000000, len = 0
29 flash7 (rx) : org = 0x00000000, len = 0
30 ram0 (wx) : org = 0x20000000, len = 64k
31 ram1 (wx) : org = 0x00000000, len = 0
32 ram2 (wx) : org = 0x00000000, len = 0
33 ram3 (wx) : org = 0x00000000, len = 0
34 ram4 (wx) : org = 0x00000000, len = 0
35 ram5 (wx) : org = 0x00000000, len = 0
36 ram6 (wx) : org = 0x00000000, len = 0
37 ram7 (wx) : org = 0x00000000, len = 0
38}
39
40/* For each data/text section two region are defined, a virtual region
41 and a load region (_LMA suffix).*/
42
43/* Flash region to be used for exception vectors.*/
44REGION_ALIAS("VECTORS_FLASH", flash0);
45REGION_ALIAS("VECTORS_FLASH_LMA", flash0);
46
47/* Flash region to be used for constructors and destructors.*/
48REGION_ALIAS("XTORS_FLASH", flash2);
49REGION_ALIAS("XTORS_FLASH_LMA", flash2);
50
51/* Flash region to be used for code text.*/
52REGION_ALIAS("TEXT_FLASH", flash2);
53REGION_ALIAS("TEXT_FLASH_LMA", flash2);
54
55/* Flash region to be used for read only data.*/
56REGION_ALIAS("RODATA_FLASH", flash2);
57REGION_ALIAS("RODATA_FLASH_LMA", flash2);
58
59/* Flash region to be used for various.*/
60REGION_ALIAS("VARIOUS_FLASH", flash2);
61REGION_ALIAS("VARIOUS_FLASH_LMA", flash2);
62
63/* Flash region to be used for RAM(n) initialization data.*/
64REGION_ALIAS("RAM_INIT_FLASH_LMA", flash2);
65
66/* RAM region to be used for Main stack. This stack accommodates the processing
67 of all exceptions and interrupts.*/
68REGION_ALIAS("MAIN_STACK_RAM", ram0);
69
70/* RAM region to be used for the process stack. This is the stack used by
71 the main() function.*/
72REGION_ALIAS("PROCESS_STACK_RAM", ram0);
73
74/* RAM region to be used for data segment.*/
75REGION_ALIAS("DATA_RAM", ram0);
76REGION_ALIAS("DATA_RAM_LMA", flash2);
77
78/* RAM region to be used for BSS segment.*/
79REGION_ALIAS("BSS_RAM", ram0);
80
81/* RAM region to be used for the default heap.*/
82REGION_ALIAS("HEAP_RAM", ram0);
83
84/* Generic rules inclusion.*/
85INCLUDE rules.ld
diff --git a/platforms/chibios/boards/common/ld/STM32F401xE.ld b/platforms/chibios/boards/common/ld/STM32F401xE.ld
new file mode 100644
index 000000000..69af7ed71
--- /dev/null
+++ b/platforms/chibios/boards/common/ld/STM32F401xE.ld
@@ -0,0 +1,85 @@
1/*
2 ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15*/
16
17/*
18 * STM32F401xE memory setup.
19 */
20MEMORY
21{
22 flash0 (rx) : org = 0x08000000, len = 16k /* Sector 0 - Init code as ROM bootloader assumes application starts here */
23 flash1 (rx) : org = 0x08004000, len = 16k /* Sector 1 - Emulated eeprom */
24 flash2 (rx) : org = 0x08008000, len = 512k - 32k /* Sector 2..7 - Rest of firmware */
25 flash3 (rx) : org = 0x00000000, len = 0
26 flash4 (rx) : org = 0x00000000, len = 0
27 flash5 (rx) : org = 0x00000000, len = 0
28 flash6 (rx) : org = 0x00000000, len = 0
29 flash7 (rx) : org = 0x00000000, len = 0
30 ram0 (wx) : org = 0x20000000, len = 96k
31 ram1 (wx) : org = 0x00000000, len = 0
32 ram2 (wx) : org = 0x00000000, len = 0
33 ram3 (wx) : org = 0x00000000, len = 0
34 ram4 (wx) : org = 0x00000000, len = 0
35 ram5 (wx) : org = 0x00000000, len = 0
36 ram6 (wx) : org = 0x00000000, len = 0
37 ram7 (wx) : org = 0x00000000, len = 0
38}
39
40/* For each data/text section two region are defined, a virtual region
41 and a load region (_LMA suffix).*/
42
43/* Flash region to be used for exception vectors.*/
44REGION_ALIAS("VECTORS_FLASH", flash0);
45REGION_ALIAS("VECTORS_FLASH_LMA", flash0);
46
47/* Flash region to be used for constructors and destructors.*/
48REGION_ALIAS("XTORS_FLASH", flash2);
49REGION_ALIAS("XTORS_FLASH_LMA", flash2);
50
51/* Flash region to be used for code text.*/
52REGION_ALIAS("TEXT_FLASH", flash2);
53REGION_ALIAS("TEXT_FLASH_LMA", flash2);
54
55/* Flash region to be used for read only data.*/
56REGION_ALIAS("RODATA_FLASH", flash2);
57REGION_ALIAS("RODATA_FLASH_LMA", flash2);
58
59/* Flash region to be used for various.*/
60REGION_ALIAS("VARIOUS_FLASH", flash2);
61REGION_ALIAS("VARIOUS_FLASH_LMA", flash2);
62
63/* Flash region to be used for RAM(n) initialization data.*/
64REGION_ALIAS("RAM_INIT_FLASH_LMA", flash2);
65
66/* RAM region to be used for Main stack. This stack accommodates the processing
67 of all exceptions and interrupts.*/
68REGION_ALIAS("MAIN_STACK_RAM", ram0);
69
70/* RAM region to be used for the process stack. This is the stack used by
71 the main() function.*/
72REGION_ALIAS("PROCESS_STACK_RAM", ram0);
73
74/* RAM region to be used for data segment.*/
75REGION_ALIAS("DATA_RAM", ram0);
76REGION_ALIAS("DATA_RAM_LMA", flash2);
77
78/* RAM region to be used for BSS segment.*/
79REGION_ALIAS("BSS_RAM", ram0);
80
81/* RAM region to be used for the default heap.*/
82REGION_ALIAS("HEAP_RAM", ram0);
83
84/* Generic rules inclusion.*/
85INCLUDE rules.ld
diff --git a/platforms/chibios/boards/common/ld/STM32F405xG.ld b/platforms/chibios/boards/common/ld/STM32F405xG.ld
new file mode 100644
index 000000000..b7d0baa21
--- /dev/null
+++ b/platforms/chibios/boards/common/ld/STM32F405xG.ld
@@ -0,0 +1,86 @@
1/*
2 ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15*/
16
17/*
18 * STM32F405xG memory setup.
19 * Note: Use of ram1 and ram2 is mutually exclusive with use of ram0.
20 */
21MEMORY
22{
23 flash0 (rx) : org = 0x08000000, len = 16k /* Sector 0 - Init code as ROM bootloader assumes application starts here */
24 flash1 (rx) : org = 0x08004000, len = 16k /* Sector 1 - Emulated eeprom */
25 flash2 (rx) : org = 0x08008000, len = 1M - 32k /* Sector 2..6 - Rest of firmware */
26 flash3 (rx) : org = 0x00000000, len = 0
27 flash4 (rx) : org = 0x00000000, len = 0
28 flash5 (rx) : org = 0x00000000, len = 0
29 flash6 (rx) : org = 0x00000000, len = 0
30 flash7 (rx) : org = 0x00000000, len = 0
31 ram0 (wx) : org = 0x20000000, len = 128k /* SRAM1 + SRAM2 */
32 ram1 (wx) : org = 0x20000000, len = 112k /* SRAM1 */
33 ram2 (wx) : org = 0x2001C000, len = 16k /* SRAM2 */
34 ram3 (wx) : org = 0x00000000, len = 0
35 ram4 (wx) : org = 0x10000000, len = 64k /* CCM SRAM */
36 ram5 (wx) : org = 0x40024000, len = 4k /* BCKP SRAM */
37 ram6 (wx) : org = 0x00000000, len = 0
38 ram7 (wx) : org = 0x00000000, len = 0
39}
40
41/* For each data/text section two region are defined, a virtual region
42 and a load region (_LMA suffix).*/
43
44/* Flash region to be used for exception vectors.*/
45REGION_ALIAS("VECTORS_FLASH", flash0);
46REGION_ALIAS("VECTORS_FLASH_LMA", flash0);
47
48/* Flash region to be used for constructors and destructors.*/
49REGION_ALIAS("XTORS_FLASH", flash2);
50REGION_ALIAS("XTORS_FLASH_LMA", flash2);
51
52/* Flash region to be used for code text.*/
53REGION_ALIAS("TEXT_FLASH", flash2);
54REGION_ALIAS("TEXT_FLASH_LMA", flash2);
55
56/* Flash region to be used for read only data.*/
57REGION_ALIAS("RODATA_FLASH", flash2);
58REGION_ALIAS("RODATA_FLASH_LMA", flash2);
59
60/* Flash region to be used for various.*/
61REGION_ALIAS("VARIOUS_FLASH", flash2);
62REGION_ALIAS("VARIOUS_FLASH_LMA", flash2);
63
64/* Flash region to be used for RAM(n) initialization data.*/
65REGION_ALIAS("RAM_INIT_FLASH_LMA", flash2);
66
67/* RAM region to be used for Main stack. This stack accommodates the processing
68 of all exceptions and interrupts.*/
69REGION_ALIAS("MAIN_STACK_RAM", ram0);
70
71/* RAM region to be used for the process stack. This is the stack used by
72 the main() function.*/
73REGION_ALIAS("PROCESS_STACK_RAM", ram0);
74
75/* RAM region to be used for data segment.*/
76REGION_ALIAS("DATA_RAM", ram0);
77REGION_ALIAS("DATA_RAM_LMA", flash2);
78
79/* RAM region to be used for BSS segment.*/
80REGION_ALIAS("BSS_RAM", ram0);
81
82/* RAM region to be used for the default heap.*/
83REGION_ALIAS("HEAP_RAM", ram0);
84
85/* Generic rules inclusion.*/
86INCLUDE rules.ld
diff --git a/platforms/chibios/boards/common/ld/STM32F411xE.ld b/platforms/chibios/boards/common/ld/STM32F411xE.ld
new file mode 100644
index 000000000..aea8084b5
--- /dev/null
+++ b/platforms/chibios/boards/common/ld/STM32F411xE.ld
@@ -0,0 +1,85 @@
1/*
2 ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15*/
16
17/*
18 * STM32F411xE memory setup.
19 */
20MEMORY
21{
22 flash0 (rx) : org = 0x08000000, len = 16k /* Sector 0 - Init code as ROM bootloader assumes application starts here */
23 flash1 (rx) : org = 0x08004000, len = 16k /* Sector 1 - Emulated eeprom */
24 flash2 (rx) : org = 0x08008000, len = 512k - 32k /* Sector 2..7 - Rest of firmware */
25 flash3 (rx) : org = 0x00000000, len = 0
26 flash4 (rx) : org = 0x00000000, len = 0
27 flash5 (rx) : org = 0x00000000, len = 0
28 flash6 (rx) : org = 0x00000000, len = 0
29 flash7 (rx) : org = 0x00000000, len = 0
30 ram0 (wx) : org = 0x20000000, len = 128k
31 ram1 (wx) : org = 0x00000000, len = 0
32 ram2 (wx) : org = 0x00000000, len = 0
33 ram3 (wx) : org = 0x00000000, len = 0
34 ram4 (wx) : org = 0x00000000, len = 0
35 ram5 (wx) : org = 0x00000000, len = 0
36 ram6 (wx) : org = 0x00000000, len = 0
37 ram7 (wx) : org = 0x00000000, len = 0
38}
39
40/* For each data/text section two region are defined, a virtual region
41 and a load region (_LMA suffix).*/
42
43/* Flash region to be used for exception vectors.*/
44REGION_ALIAS("VECTORS_FLASH", flash0);
45REGION_ALIAS("VECTORS_FLASH_LMA", flash0);
46
47/* Flash region to be used for constructors and destructors.*/
48REGION_ALIAS("XTORS_FLASH", flash2);
49REGION_ALIAS("XTORS_FLASH_LMA", flash2);
50
51/* Flash region to be used for code text.*/
52REGION_ALIAS("TEXT_FLASH", flash2);
53REGION_ALIAS("TEXT_FLASH_LMA", flash2);
54
55/* Flash region to be used for read only data.*/
56REGION_ALIAS("RODATA_FLASH", flash2);
57REGION_ALIAS("RODATA_FLASH_LMA", flash2);
58
59/* Flash region to be used for various.*/
60REGION_ALIAS("VARIOUS_FLASH", flash2);
61REGION_ALIAS("VARIOUS_FLASH_LMA", flash2);
62
63/* Flash region to be used for RAM(n) initialization data.*/
64REGION_ALIAS("RAM_INIT_FLASH_LMA", flash2);
65
66/* RAM region to be used for Main stack. This stack accommodates the processing
67 of all exceptions and interrupts.*/
68REGION_ALIAS("MAIN_STACK_RAM", ram0);
69
70/* RAM region to be used for the process stack. This is the stack used by
71 the main() function.*/
72REGION_ALIAS("PROCESS_STACK_RAM", ram0);
73
74/* RAM region to be used for data segment.*/
75REGION_ALIAS("DATA_RAM", ram0);
76REGION_ALIAS("DATA_RAM_LMA", flash2);
77
78/* RAM region to be used for BSS segment.*/
79REGION_ALIAS("BSS_RAM", ram0);
80
81/* RAM region to be used for the default heap.*/
82REGION_ALIAS("HEAP_RAM", ram0);
83
84/* Generic rules inclusion.*/
85INCLUDE rules.ld
diff --git a/platforms/chibios/bootloader.c b/platforms/chibios/bootloader.c
new file mode 100644
index 000000000..5cadadeee
--- /dev/null
+++ b/platforms/chibios/bootloader.c
@@ -0,0 +1,145 @@
1#include "bootloader.h"
2
3#include <ch.h>
4#include <hal.h>
5#include "wait.h"
6
7/* This code should be checked whether it runs correctly on platforms */
8#define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0))
9#define BOOTLOADER_MAGIC 0xDEADBEEF
10#define MAGIC_ADDR (unsigned long *)(SYMVAL(__ram0_end__) - 4)
11
12#ifndef STM32_BOOTLOADER_DUAL_BANK
13# define STM32_BOOTLOADER_DUAL_BANK FALSE
14#endif
15
16#ifdef BOOTLOADER_TINYUF2
17
18# define DBL_TAP_MAGIC 0xf01669ef // From tinyuf2's board_api.h
19
20// defined by linker script
21extern uint32_t _board_dfu_dbl_tap[];
22# define DBL_TAP_REG _board_dfu_dbl_tap[0]
23
24void bootloader_jump(void) {
25 DBL_TAP_REG = DBL_TAP_MAGIC;
26 NVIC_SystemReset();
27}
28
29void enter_bootloader_mode_if_requested(void) { /* not needed, no two-stage reset */
30}
31
32#elif STM32_BOOTLOADER_DUAL_BANK
33
34// Need pin definitions
35# include "config_common.h"
36
37# ifndef STM32_BOOTLOADER_DUAL_BANK_GPIO
38# error "No STM32_BOOTLOADER_DUAL_BANK_GPIO defined, don't know which pin to toggle"
39# endif
40
41# ifndef STM32_BOOTLOADER_DUAL_BANK_POLARITY
42# define STM32_BOOTLOADER_DUAL_BANK_POLARITY 0
43# endif
44
45# ifndef STM32_BOOTLOADER_DUAL_BANK_DELAY
46# define STM32_BOOTLOADER_DUAL_BANK_DELAY 100000
47# endif
48
49extern uint32_t __ram0_end__;
50
51__attribute__((weak)) void bootloader_jump(void) {
52 // For STM32 MCUs with dual-bank flash, and we're incapable of jumping to the bootloader. The first valid flash
53 // bank is executed unconditionally after a reset, so it doesn't enter DFU unless BOOT0 is high. Instead, we do
54 // it with hardware...in this case, we pull a GPIO high/low depending on the configuration, connects 3.3V to
55 // BOOT0's RC charging circuit, lets it charge the capacitor, and issue a system reset. See the QMK discord
56 // #hardware channel pins for an example circuit.
57 palSetPadMode(PAL_PORT(STM32_BOOTLOADER_DUAL_BANK_GPIO), PAL_PAD(STM32_BOOTLOADER_DUAL_BANK_GPIO), PAL_MODE_OUTPUT_PUSHPULL);
58# if STM32_BOOTLOADER_DUAL_BANK_POLARITY
59 palSetPad(PAL_PORT(STM32_BOOTLOADER_DUAL_BANK_GPIO), PAL_PAD(STM32_BOOTLOADER_DUAL_BANK_GPIO));
60# else
61 palClearPad(PAL_PORT(STM32_BOOTLOADER_DUAL_BANK_GPIO), PAL_PAD(STM32_BOOTLOADER_DUAL_BANK_GPIO));
62# endif
63
64 // Wait for a while for the capacitor to charge
65 wait_ms(100);
66
67 // Issue a system reset to get the ROM bootloader to execute, with BOOT0 high
68 NVIC_SystemReset();
69}
70
71void enter_bootloader_mode_if_requested(void) {} // not needed at all, but if anybody attempts to invoke it....
72
73#elif defined(STM32_BOOTLOADER_ADDRESS) // STM32_BOOTLOADER_DUAL_BANK
74
75extern uint32_t __ram0_end__;
76
77__attribute__((weak)) void bootloader_jump(void) {
78 *MAGIC_ADDR = BOOTLOADER_MAGIC; // set magic flag => reset handler will jump into boot loader
79 NVIC_SystemReset();
80}
81
82void enter_bootloader_mode_if_requested(void) {
83 unsigned long *check = MAGIC_ADDR;
84 if (*check == BOOTLOADER_MAGIC) {
85 *check = 0;
86 __set_CONTROL(0);
87 __set_MSP(*(__IO uint32_t *)STM32_BOOTLOADER_ADDRESS);
88 __enable_irq();
89
90 typedef void (*BootJump_t)(void);
91 BootJump_t boot_jump = *(BootJump_t *)(STM32_BOOTLOADER_ADDRESS + 4);
92 boot_jump();
93 while (1)
94 ;
95 }
96}
97
98#elif defined(GD32VF103)
99
100# define DBGMCU_KEY_UNLOCK 0x4B5A6978
101# define DBGMCU_CMD_RESET 0x1
102
103__IO uint32_t *DBGMCU_KEY = (uint32_t *)DBGMCU_BASE + 0x0CU;
104__IO uint32_t *DBGMCU_CMD = (uint32_t *)DBGMCU_BASE + 0x08U;
105
106__attribute__((weak)) void bootloader_jump(void) {
107 /* The MTIMER unit of the GD32VF103 doesn't have the MSFRST
108 * register to generate a software reset request.
109 * BUT instead two undocumented registers in the debug peripheral
110 * that allow issueing a software reset. WHO would need the MSFRST
111 * register anyway? Source:
112 * https://github.com/esmil/gd32vf103inator/blob/master/include/gd32vf103/dbg.h */
113 *DBGMCU_KEY = DBGMCU_KEY_UNLOCK;
114 *DBGMCU_CMD = DBGMCU_CMD_RESET;
115}
116
117void enter_bootloader_mode_if_requested(void) { /* Jumping to bootloader is not possible from user code. */
118}
119
120#elif defined(KL2x) || defined(K20x) || defined(MK66F18) || defined(MIMXRT1062) // STM32_BOOTLOADER_DUAL_BANK // STM32_BOOTLOADER_ADDRESS
121/* Kinetis */
122
123# if defined(BOOTLOADER_KIIBOHD)
124/* Kiibohd Bootloader (MCHCK and Infinity KB) */
125# define SCB_AIRCR_VECTKEY_WRITEMAGIC 0x05FA0000
126const uint8_t sys_reset_to_loader_magic[] = "\xff\x00\x7fRESET TO LOADER\x7f\x00\xff";
127__attribute__((weak)) void bootloader_jump(void) {
128 void *volatile vbat = (void *)VBAT;
129 __builtin_memcpy(vbat, (const void *)sys_reset_to_loader_magic, sizeof(sys_reset_to_loader_magic));
130 // request reset
131 SCB->AIRCR = SCB_AIRCR_VECTKEY_WRITEMAGIC | SCB_AIRCR_SYSRESETREQ_Msk;
132}
133
134# else /* defined(BOOTLOADER_KIIBOHD) */
135/* Default for Kinetis - expecting an ARM Teensy */
136# include "wait.h"
137__attribute__((weak)) void bootloader_jump(void) {
138 wait_ms(100);
139 __BKPT(0);
140}
141# endif /* defined(BOOTLOADER_KIIBOHD) */
142
143#else /* neither STM32 nor KINETIS */
144__attribute__((weak)) void bootloader_jump(void) {}
145#endif
diff --git a/platforms/chibios/chibios_config.h b/platforms/chibios/chibios_config.h
new file mode 100644
index 000000000..ad2f808a9
--- /dev/null
+++ b/platforms/chibios/chibios_config.h
@@ -0,0 +1,78 @@
1/* Copyright 2019
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#pragma once
17
18#ifndef USB_VBUS_PIN
19# define SPLIT_USB_DETECT // Force this on when dedicated pin is not used
20#endif
21
22// STM32 compatibility
23#if defined(MCU_STM32)
24# define CPU_CLOCK STM32_SYSCLK
25
26# if defined(STM32F1XX)
27# define USE_GPIOV1
28# define PAL_MODE_ALTERNATE_OPENDRAIN PAL_MODE_STM32_ALTERNATE_OPENDRAIN
29# define PAL_MODE_ALTERNATE_PUSHPULL PAL_MODE_STM32_ALTERNATE_PUSHPULL
30# else
31# define PAL_OUTPUT_TYPE_OPENDRAIN PAL_STM32_OTYPE_OPENDRAIN
32# define PAL_OUTPUT_TYPE_PUSHPULL PAL_STM32_OTYPE_PUSHPULL
33# define PAL_OUTPUT_SPEED_HIGHEST PAL_STM32_OSPEED_HIGHEST
34# define PAL_PUPDR_FLOATING PAL_STM32_PUPDR_FLOATING
35# endif
36
37# if defined(STM32F1XX) || defined(STM32F2XX) || defined(STM32F4XX) || defined(STM32L1XX)
38# define USE_I2CV1
39# endif
40#endif
41
42// GD32 compatibility
43#if defined(MCU_GD32V)
44# define CPU_CLOCK GD32_SYSCLK
45
46# if defined(GD32VF103)
47# define USE_GPIOV1
48# define USE_I2CV1
49# define PAL_MODE_ALTERNATE_OPENDRAIN PAL_MODE_GD32_ALTERNATE_OPENDRAIN
50# define PAL_MODE_ALTERNATE_PUSHPULL PAL_MODE_GD32_ALTERNATE_PUSHPULL
51# endif
52#endif
53
54#if defined(GD32VF103)
55/* This chip has the same API as STM32F103, but uses different names for literally the same thing.
56 * As of 4.7.2021 QMK is tailored to use STM32 defines/names, for compatibility sake
57 * we just redefine the GD32 names. */
58# include "gd32v_compatibility.h"
59#endif
60
61// teensy compatibility
62#if defined(MCU_KINETIS)
63# define CPU_CLOCK KINETIS_SYSCLK_FREQUENCY
64
65# if defined(K20x) || defined(KL2x)
66# define USE_I2CV1
67# define USE_I2CV1_CONTRIB // for some reason a bunch of ChibiOS-Contrib boards only have clock_speed
68# define USE_GPIOV1
69# endif
70#endif
71
72#if defined(HT32)
73# define CPU_CLOCK HT32_CK_SYS_FREQUENCY
74# define PAL_MODE_ALTERNATE PAL_HT32_MODE_AF
75# define PAL_OUTPUT_TYPE_OPENDRAIN (PAL_HT32_MODE_OD | PAL_HT32_MODE_DIR)
76# define PAL_OUTPUT_TYPE_PUSHPULL PAL_HT32_MODE_DIR
77# define PAL_OUTPUT_SPEED_HIGHEST 0
78#endif
diff --git a/platforms/chibios/drivers/analog.c b/platforms/chibios/drivers/analog.c
index b1081623d..eb437665f 100644
--- a/platforms/chibios/drivers/analog.c
+++ b/platforms/chibios/drivers/analog.c
@@ -38,7 +38,7 @@
38// Otherwise assume V3 38// Otherwise assume V3
39#if defined(STM32F0XX) || defined(STM32L0XX) 39#if defined(STM32F0XX) || defined(STM32L0XX)
40# define USE_ADCV1 40# define USE_ADCV1
41#elif defined(STM32F1XX) || defined(STM32F2XX) || defined(STM32F4XX) 41#elif defined(STM32F1XX) || defined(STM32F2XX) || defined(STM32F4XX) || defined(GD32VF103)
42# define USE_ADCV2 42# define USE_ADCV2
43#endif 43#endif
44 44
@@ -75,7 +75,7 @@
75 75
76/* User configurable ADC options */ 76/* User configurable ADC options */
77#ifndef ADC_COUNT 77#ifndef ADC_COUNT
78# if defined(STM32F0XX) || defined(STM32F1XX) || defined(STM32F4XX) 78# if defined(STM32F0XX) || defined(STM32F1XX) || defined(STM32F4XX) || defined(GD32VF103)
79# define ADC_COUNT 1 79# define ADC_COUNT 1
80# elif defined(STM32F3XX) 80# elif defined(STM32F3XX)
81# define ADC_COUNT 4 81# define ADC_COUNT 4
@@ -122,7 +122,7 @@ static ADCConversionGroup adcConversionGroup = {
122 .cfgr1 = ADC_CFGR1_CONT | ADC_RESOLUTION, 122 .cfgr1 = ADC_CFGR1_CONT | ADC_RESOLUTION,
123 .smpr = ADC_SAMPLING_RATE, 123 .smpr = ADC_SAMPLING_RATE,
124#elif defined(USE_ADCV2) 124#elif defined(USE_ADCV2)
125# if !defined(STM32F1XX) 125# if !defined(STM32F1XX) && !defined(GD32VF103)
126 .cr2 = ADC_CR2_SWSTART, // F103 seem very unhappy with, F401 seems very unhappy without... 126 .cr2 = ADC_CR2_SWSTART, // F103 seem very unhappy with, F401 seems very unhappy without...
127# endif 127# endif
128 .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), 128 .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),
@@ -220,7 +220,7 @@ __attribute__((weak)) adc_mux pinToMux(pin_t pin) {
220 case F9: return TO_MUX( ADC_CHANNEL_IN7, 2 ); 220 case F9: return TO_MUX( ADC_CHANNEL_IN7, 2 );
221 case F10: return TO_MUX( ADC_CHANNEL_IN8, 2 ); 221 case F10: return TO_MUX( ADC_CHANNEL_IN8, 2 );
222# endif 222# endif
223#elif defined(STM32F1XX) 223#elif defined(STM32F1XX) || defined(GD32VF103)
224 case A0: return TO_MUX( ADC_CHANNEL_IN0, 0 ); 224 case A0: return TO_MUX( ADC_CHANNEL_IN0, 0 );
225 case A1: return TO_MUX( ADC_CHANNEL_IN1, 0 ); 225 case A1: return TO_MUX( ADC_CHANNEL_IN1, 0 );
226 case A2: return TO_MUX( ADC_CHANNEL_IN2, 0 ); 226 case A2: return TO_MUX( ADC_CHANNEL_IN2, 0 );
diff --git a/platforms/chibios/drivers/audio_dac.h b/platforms/chibios/drivers/audio_dac.h
new file mode 100644
index 000000000..07cd622ea
--- /dev/null
+++ b/platforms/chibios/drivers/audio_dac.h
@@ -0,0 +1,126 @@
1/* Copyright 2019 Jack Humbert
2 * Copyright 2020 JohSchneider
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17#pragma once
18
19#ifndef A4
20# define A4 PAL_LINE(GPIOA, 4)
21#endif
22#ifndef A5
23# define A5 PAL_LINE(GPIOA, 5)
24#endif
25
26/**
27 * Size of the dac_buffer arrays. All must be the same size.
28 */
29#define AUDIO_DAC_BUFFER_SIZE 256U
30
31/**
32 * Highest value allowed sample value.
33
34 * since the DAC is limited to 12 bit, the absolute max is 0xfff = 4095U;
35 * lower values adjust the peak-voltage aka volume down.
36 * adjusting this value has only an effect on a sample-buffer whose values are
37 * are NOT pregenerated - see square-wave
38 */
39#ifndef AUDIO_DAC_SAMPLE_MAX
40# define AUDIO_DAC_SAMPLE_MAX 4095U
41#endif
42
43#if !defined(AUDIO_DAC_SAMPLE_RATE) && !defined(AUDIO_MAX_SIMULTANEOUS_TONES) && !defined(AUDIO_DAC_QUALITY_VERY_LOW) && !defined(AUDIO_DAC_QUALITY_LOW) && !defined(AUDIO_DAC_QUALITY_HIGH) && !defined(AUDIO_DAC_QUALITY_VERY_HIGH)
44# define AUDIO_DAC_QUALITY_SANE_MINIMUM
45#endif
46
47/**
48 * These presets allow you to quickly switch between quality settings for
49 * the DAC. The sample rate and maximum number of simultaneous tones roughly
50 * has an inverse relationship - slightly higher sample rates may be possible.
51 *
52 * NOTE: a high sample-rate results in a higher cpu-load, which might lead to
53 * (audible) discontinuities and/or starve other processes of cpu-time
54 * (like RGB-led back-lighting, ...)
55 */
56#ifdef AUDIO_DAC_QUALITY_VERY_LOW
57# define AUDIO_DAC_SAMPLE_RATE 11025U
58# define AUDIO_MAX_SIMULTANEOUS_TONES 8
59#endif
60
61#ifdef AUDIO_DAC_QUALITY_LOW
62# define AUDIO_DAC_SAMPLE_RATE 22050U
63# define AUDIO_MAX_SIMULTANEOUS_TONES 4
64#endif
65
66#ifdef AUDIO_DAC_QUALITY_HIGH
67# define AUDIO_DAC_SAMPLE_RATE 44100U
68# define AUDIO_MAX_SIMULTANEOUS_TONES 2
69#endif
70
71#ifdef AUDIO_DAC_QUALITY_VERY_HIGH
72# define AUDIO_DAC_SAMPLE_RATE 88200U
73# define AUDIO_MAX_SIMULTANEOUS_TONES 1
74#endif
75
76#ifdef AUDIO_DAC_QUALITY_SANE_MINIMUM
77/* a sane-minimum config: with a trade-off between cpu-load and tone-range
78 *
79 * the (currently) highest defined note is NOTE_B8 with 7902Hz; if we now
80 * aim for an even even multiple of the buffer-size, we end up with:
81 * ( roundUptoPow2(highest note / AUDIO_DAC_BUFFER_SIZE) * nyquist-rate * AUDIO_DAC_BUFFER_SIZE)
82 * 7902/256 = 30.867 * 2 * 256 ~= 16384
83 * which works out (but the 'scope shows some sampling artifacts with lower harmonics :-P)
84 */
85# define AUDIO_DAC_SAMPLE_RATE 16384U
86# define AUDIO_MAX_SIMULTANEOUS_TONES 8
87#endif
88
89/**
90 * Effective bit-rate of the DAC. 44.1khz is the standard for most audio - any
91 * lower will sacrifice perceptible audio quality. Any higher will limit the
92 * number of simultaneous tones. In most situations, a tenth (1/10) of the
93 * sample rate is where notes become unbearable.
94 */
95#ifndef AUDIO_DAC_SAMPLE_RATE
96# define AUDIO_DAC_SAMPLE_RATE 44100U
97#endif
98
99/**
100 * The number of tones that can be played simultaneously. If too high a value
101 * is used here, the keyboard will freeze and glitch-out when that many tones
102 * are being played.
103 */
104#ifndef AUDIO_MAX_SIMULTANEOUS_TONES
105# define AUDIO_MAX_SIMULTANEOUS_TONES 2
106#endif
107
108/**
109 * The default value of the DAC when not playing anything. Certain hardware
110 * setups may require a high (AUDIO_DAC_SAMPLE_MAX) or low (0) value here.
111 * Since multiple added sine waves tend to oscillate around the midpoint,
112 * and possibly never/rarely reach either 0 of MAX, 1/2 MAX can be a
113 * reasonable default value.
114 */
115#ifndef AUDIO_DAC_OFF_VALUE
116# define AUDIO_DAC_OFF_VALUE AUDIO_DAC_SAMPLE_MAX / 2
117#endif
118
119#if AUDIO_DAC_OFF_VALUE > AUDIO_DAC_SAMPLE_MAX
120# error "AUDIO_DAC: OFF_VALUE may not be larger than SAMPLE_MAX"
121#endif
122
123/**
124 *user overridable sample generation/processing
125 */
126uint16_t dac_value_generate(void);
diff --git a/platforms/chibios/drivers/audio_dac_additive.c b/platforms/chibios/drivers/audio_dac_additive.c
new file mode 100644
index 000000000..db304adb8
--- /dev/null
+++ b/platforms/chibios/drivers/audio_dac_additive.c
@@ -0,0 +1,335 @@
1/* Copyright 2016-2019 Jack Humbert
2 * Copyright 2020 JohSchneider
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "audio.h"
19#include <ch.h>
20#include <hal.h>
21
22/*
23 Audio Driver: DAC
24
25 which utilizes the dac unit many STM32 are equipped with, to output a modulated waveform from samples stored in the dac_buffer_* array who are passed to the hardware through DMA
26
27 it is also possible to have a custom sample-LUT by implementing/overriding 'dac_value_generate'
28
29 this driver allows for multiple simultaneous tones to be played through one single channel by doing additive wave-synthesis
30*/
31
32#if !defined(AUDIO_PIN)
33# error "Audio feature enabled, but no suitable pin selected as AUDIO_PIN - see docs/feature_audio under 'ARM (DAC additive)' for available options."
34#endif
35#if defined(AUDIO_PIN_ALT) && !defined(AUDIO_PIN_ALT_AS_NEGATIVE)
36# pragma message "Audio feature: AUDIO_PIN_ALT set, but not AUDIO_PIN_ALT_AS_NEGATIVE - pin will be left unused; audio might still work though."
37#endif
38
39#if !defined(AUDIO_PIN_ALT)
40// no ALT pin defined is valid, but the c-ifs below need some value set
41# define AUDIO_PIN_ALT PAL_NOLINE
42#endif
43
44#if !defined(AUDIO_DAC_SAMPLE_WAVEFORM_SINE) && !defined(AUDIO_DAC_SAMPLE_WAVEFORM_TRIANGLE) && !defined(AUDIO_DAC_SAMPLE_WAVEFORM_SQUARE) && !defined(AUDIO_DAC_SAMPLE_WAVEFORM_TRAPEZOID)
45# define AUDIO_DAC_SAMPLE_WAVEFORM_SINE
46#endif
47
48#ifdef AUDIO_DAC_SAMPLE_WAVEFORM_SINE
49/* one full sine wave over [0,2*pi], but shifted up one amplitude and left pi/4; for the samples to start at 0
50 */
51static const dacsample_t dac_buffer_sine[AUDIO_DAC_BUFFER_SIZE] = {
52 // 256 values, max 4095
53 0x0, 0x1, 0x2, 0x6, 0xa, 0xf, 0x16, 0x1e, 0x27, 0x32, 0x3d, 0x4a, 0x58, 0x67, 0x78, 0x89, 0x9c, 0xb0, 0xc5, 0xdb, 0xf2, 0x10a, 0x123, 0x13e, 0x159, 0x175, 0x193, 0x1b1, 0x1d1, 0x1f1, 0x212, 0x235, 0x258, 0x27c, 0x2a0, 0x2c6, 0x2ed, 0x314, 0x33c, 0x365, 0x38e, 0x3b8, 0x3e3, 0x40e, 0x43a, 0x467, 0x494, 0x4c2, 0x4f0, 0x51f, 0x54e, 0x57d, 0x5ad, 0x5dd, 0x60e, 0x63f, 0x670, 0x6a1, 0x6d3, 0x705, 0x737, 0x769, 0x79b, 0x7cd, 0x800, 0x832, 0x864, 0x896, 0x8c8, 0x8fa, 0x92c, 0x95e, 0x98f, 0x9c0, 0x9f1, 0xa22, 0xa52, 0xa82, 0xab1, 0xae0, 0xb0f, 0xb3d, 0xb6b, 0xb98, 0xbc5, 0xbf1, 0xc1c, 0xc47, 0xc71, 0xc9a, 0xcc3, 0xceb, 0xd12, 0xd39, 0xd5f, 0xd83, 0xda7, 0xdca, 0xded, 0xe0e, 0xe2e, 0xe4e, 0xe6c, 0xe8a, 0xea6, 0xec1, 0xedc, 0xef5, 0xf0d, 0xf24, 0xf3a, 0xf4f, 0xf63, 0xf76, 0xf87, 0xf98, 0xfa7, 0xfb5, 0xfc2, 0xfcd, 0xfd8, 0xfe1, 0xfe9, 0xff0, 0xff5, 0xff9, 0xffd, 0xffe,
54 0xfff, 0xffe, 0xffd, 0xff9, 0xff5, 0xff0, 0xfe9, 0xfe1, 0xfd8, 0xfcd, 0xfc2, 0xfb5, 0xfa7, 0xf98, 0xf87, 0xf76, 0xf63, 0xf4f, 0xf3a, 0xf24, 0xf0d, 0xef5, 0xedc, 0xec1, 0xea6, 0xe8a, 0xe6c, 0xe4e, 0xe2e, 0xe0e, 0xded, 0xdca, 0xda7, 0xd83, 0xd5f, 0xd39, 0xd12, 0xceb, 0xcc3, 0xc9a, 0xc71, 0xc47, 0xc1c, 0xbf1, 0xbc5, 0xb98, 0xb6b, 0xb3d, 0xb0f, 0xae0, 0xab1, 0xa82, 0xa52, 0xa22, 0x9f1, 0x9c0, 0x98f, 0x95e, 0x92c, 0x8fa, 0x8c8, 0x896, 0x864, 0x832, 0x800, 0x7cd, 0x79b, 0x769, 0x737, 0x705, 0x6d3, 0x6a1, 0x670, 0x63f, 0x60e, 0x5dd, 0x5ad, 0x57d, 0x54e, 0x51f, 0x4f0, 0x4c2, 0x494, 0x467, 0x43a, 0x40e, 0x3e3, 0x3b8, 0x38e, 0x365, 0x33c, 0x314, 0x2ed, 0x2c6, 0x2a0, 0x27c, 0x258, 0x235, 0x212, 0x1f1, 0x1d1, 0x1b1, 0x193, 0x175, 0x159, 0x13e, 0x123, 0x10a, 0xf2, 0xdb, 0xc5, 0xb0, 0x9c, 0x89, 0x78, 0x67, 0x58, 0x4a, 0x3d, 0x32, 0x27, 0x1e, 0x16, 0xf, 0xa, 0x6, 0x2, 0x1};
55#endif // AUDIO_DAC_SAMPLE_WAVEFORM_SINE
56#ifdef AUDIO_DAC_SAMPLE_WAVEFORM_TRIANGLE
57static const dacsample_t dac_buffer_triangle[AUDIO_DAC_BUFFER_SIZE] = {
58 // 256 values, max 4095
59 0x0, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0, 0x100, 0x120, 0x140, 0x160, 0x180, 0x1a0, 0x1c0, 0x1e0, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0x3c0, 0x3e0, 0x400, 0x420, 0x440, 0x460, 0x480, 0x4a0, 0x4c0, 0x4e0, 0x500, 0x520, 0x540, 0x560, 0x580, 0x5a0, 0x5c0, 0x5e0, 0x600, 0x620, 0x640, 0x660, 0x680, 0x6a0, 0x6c0, 0x6e0, 0x700, 0x720, 0x740, 0x760, 0x780, 0x7a0, 0x7c0, 0x7e0, 0x800, 0x81f, 0x83f, 0x85f, 0x87f, 0x89f, 0x8bf, 0x8df, 0x8ff, 0x91f, 0x93f, 0x95f, 0x97f, 0x99f, 0x9bf, 0x9df, 0x9ff, 0xa1f, 0xa3f, 0xa5f, 0xa7f, 0xa9f, 0xabf, 0xadf, 0xaff, 0xb1f, 0xb3f, 0xb5f, 0xb7f, 0xb9f, 0xbbf, 0xbdf, 0xbff, 0xc1f, 0xc3f, 0xc5f, 0xc7f, 0xc9f, 0xcbf, 0xcdf, 0xcff, 0xd1f, 0xd3f, 0xd5f, 0xd7f, 0xd9f, 0xdbf, 0xddf, 0xdff, 0xe1f, 0xe3f, 0xe5f, 0xe7f, 0xe9f, 0xebf, 0xedf, 0xeff, 0xf1f, 0xf3f, 0xf5f, 0xf7f, 0xf9f, 0xfbf, 0xfdf,
60 0xfff, 0xfdf, 0xfbf, 0xf9f, 0xf7f, 0xf5f, 0xf3f, 0xf1f, 0xeff, 0xedf, 0xebf, 0xe9f, 0xe7f, 0xe5f, 0xe3f, 0xe1f, 0xdff, 0xddf, 0xdbf, 0xd9f, 0xd7f, 0xd5f, 0xd3f, 0xd1f, 0xcff, 0xcdf, 0xcbf, 0xc9f, 0xc7f, 0xc5f, 0xc3f, 0xc1f, 0xbff, 0xbdf, 0xbbf, 0xb9f, 0xb7f, 0xb5f, 0xb3f, 0xb1f, 0xaff, 0xadf, 0xabf, 0xa9f, 0xa7f, 0xa5f, 0xa3f, 0xa1f, 0x9ff, 0x9df, 0x9bf, 0x99f, 0x97f, 0x95f, 0x93f, 0x91f, 0x8ff, 0x8df, 0x8bf, 0x89f, 0x87f, 0x85f, 0x83f, 0x81f, 0x800, 0x7e0, 0x7c0, 0x7a0, 0x780, 0x760, 0x740, 0x720, 0x700, 0x6e0, 0x6c0, 0x6a0, 0x680, 0x660, 0x640, 0x620, 0x600, 0x5e0, 0x5c0, 0x5a0, 0x580, 0x560, 0x540, 0x520, 0x500, 0x4e0, 0x4c0, 0x4a0, 0x480, 0x460, 0x440, 0x420, 0x400, 0x3e0, 0x3c0, 0x3a0, 0x380, 0x360, 0x340, 0x320, 0x300, 0x2e0, 0x2c0, 0x2a0, 0x280, 0x260, 0x240, 0x220, 0x200, 0x1e0, 0x1c0, 0x1a0, 0x180, 0x160, 0x140, 0x120, 0x100, 0xe0, 0xc0, 0xa0, 0x80, 0x60, 0x40, 0x20};
61#endif // AUDIO_DAC_SAMPLE_WAVEFORM_TRIANGLE
62#ifdef AUDIO_DAC_SAMPLE_WAVEFORM_SQUARE
63static const dacsample_t dac_buffer_square[AUDIO_DAC_BUFFER_SIZE] = {
64 [0 ... AUDIO_DAC_BUFFER_SIZE / 2 - 1] = 0, // first and
65 [AUDIO_DAC_BUFFER_SIZE / 2 ... AUDIO_DAC_BUFFER_SIZE - 1] = AUDIO_DAC_SAMPLE_MAX, // second half
66};
67#endif // AUDIO_DAC_SAMPLE_WAVEFORM_SQUARE
68/*
69// four steps: 0, 1/3, 2/3 and 1
70static const dacsample_t dac_buffer_staircase[AUDIO_DAC_BUFFER_SIZE] = {
71 [0 ... AUDIO_DAC_BUFFER_SIZE/3 -1 ] = 0,
72 [AUDIO_DAC_BUFFER_SIZE / 4 ... AUDIO_DAC_BUFFER_SIZE / 2 -1 ] = AUDIO_DAC_SAMPLE_MAX / 3,
73 [AUDIO_DAC_BUFFER_SIZE / 2 ... 3 * AUDIO_DAC_BUFFER_SIZE / 4 -1 ] = 2 * AUDIO_DAC_SAMPLE_MAX / 3,
74 [3 * AUDIO_DAC_BUFFER_SIZE / 4 ... AUDIO_DAC_BUFFER_SIZE -1 ] = AUDIO_DAC_SAMPLE_MAX,
75}
76*/
77#ifdef AUDIO_DAC_SAMPLE_WAVEFORM_TRAPEZOID
78static const dacsample_t dac_buffer_trapezoid[AUDIO_DAC_BUFFER_SIZE] = {0x0, 0x1f, 0x7f, 0xdf, 0x13f, 0x19f, 0x1ff, 0x25f, 0x2bf, 0x31f, 0x37f, 0x3df, 0x43f, 0x49f, 0x4ff, 0x55f, 0x5bf, 0x61f, 0x67f, 0x6df, 0x73f, 0x79f, 0x7ff, 0x85f, 0x8bf, 0x91f, 0x97f, 0x9df, 0xa3f, 0xa9f, 0xaff, 0xb5f, 0xbbf, 0xc1f, 0xc7f, 0xcdf, 0xd3f, 0xd9f, 0xdff, 0xe5f, 0xebf, 0xf1f, 0xf7f, 0xfdf, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
79 0xfff, 0xfdf, 0xf7f, 0xf1f, 0xebf, 0xe5f, 0xdff, 0xd9f, 0xd3f, 0xcdf, 0xc7f, 0xc1f, 0xbbf, 0xb5f, 0xaff, 0xa9f, 0xa3f, 0x9df, 0x97f, 0x91f, 0x8bf, 0x85f, 0x7ff, 0x79f, 0x73f, 0x6df, 0x67f, 0x61f, 0x5bf, 0x55f, 0x4ff, 0x49f, 0x43f, 0x3df, 0x37f, 0x31f, 0x2bf, 0x25f, 0x1ff, 0x19f, 0x13f, 0xdf, 0x7f, 0x1f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
80#endif // AUDIO_DAC_SAMPLE_WAVEFORM_TRAPEZOID
81
82static dacsample_t dac_buffer_empty[AUDIO_DAC_BUFFER_SIZE] = {AUDIO_DAC_OFF_VALUE};
83
84/* keep track of the sample position for for each frequency */
85static float dac_if[AUDIO_MAX_SIMULTANEOUS_TONES] = {0.0};
86
87static float active_tones_snapshot[AUDIO_MAX_SIMULTANEOUS_TONES] = {0, 0};
88static uint8_t active_tones_snapshot_length = 0;
89
90typedef enum {
91 OUTPUT_SHOULD_START,
92 OUTPUT_RUN_NORMALLY,
93 // path 1: wait for zero, then change/update active tones
94 OUTPUT_TONES_CHANGED,
95 OUTPUT_REACHED_ZERO_BEFORE_TONE_CHANGE,
96 // path 2: hardware should stop, wait for zero then turn output off = stop the timer
97 OUTPUT_SHOULD_STOP,
98 OUTPUT_REACHED_ZERO_BEFORE_OFF,
99 OUTPUT_OFF,
100 OUTPUT_OFF_1,
101 OUTPUT_OFF_2, // trailing off: giving the DAC two more conversion cycles until the AUDIO_DAC_OFF_VALUE reaches the output, then turn the timer off, which leaves the output at that level
102 number_of_output_states
103} output_states_t;
104output_states_t state = OUTPUT_OFF_2;
105
106/**
107 * Generation of the waveform being passed to the callback. Declared weak so users
108 * can override it with their own wave-forms/noises.
109 */
110__attribute__((weak)) uint16_t dac_value_generate(void) {
111 // DAC is running/asking for values but snapshot length is zero -> must be playing a pause
112 if (active_tones_snapshot_length == 0) {
113 return AUDIO_DAC_OFF_VALUE;
114 }
115
116 /* doing additive wave synthesis over all currently playing tones = adding up
117 * sine-wave-samples for each frequency, scaled by the number of active tones
118 */
119 uint16_t value = 0;
120 float frequency = 0.0f;
121
122 for (uint8_t i = 0; i < active_tones_snapshot_length; i++) {
123 /* Note: a user implementation does not have to rely on the active_tones_snapshot, but
124 * could directly query the active frequencies through audio_get_processed_frequency */
125 frequency = active_tones_snapshot[i];
126
127 dac_if[i] = dac_if[i] + ((frequency * AUDIO_DAC_BUFFER_SIZE) / AUDIO_DAC_SAMPLE_RATE) * 2 / 3;
128 /*Note: the 2/3 are necessary to get the correct frequencies on the
129 * DAC output (as measured with an oscilloscope), since the gpt
130 * timer runs with 3*AUDIO_DAC_SAMPLE_RATE; and the DAC callback
131 * is called twice per conversion.*/
132
133 dac_if[i] = fmod(dac_if[i], AUDIO_DAC_BUFFER_SIZE);
134
135 // Wavetable generation/lookup
136 uint16_t dac_i = (uint16_t)dac_if[i];
137
138#if defined(AUDIO_DAC_SAMPLE_WAVEFORM_SINE)
139 value += dac_buffer_sine[dac_i] / active_tones_snapshot_length;
140#elif defined(AUDIO_DAC_SAMPLE_WAVEFORM_TRIANGLE)
141 value += dac_buffer_triangle[dac_i] / active_tones_snapshot_length;
142#elif defined(AUDIO_DAC_SAMPLE_WAVEFORM_TRAPEZOID)
143 value += dac_buffer_trapezoid[dac_i] / active_tones_snapshot_length;
144#elif defined(AUDIO_DAC_SAMPLE_WAVEFORM_SQUARE)
145 value += dac_buffer_square[dac_i] / active_tones_snapshot_length;
146#endif
147 /*
148 // SINE
149 value += dac_buffer_sine[dac_i] / active_tones_snapshot_length / 3;
150 // TRIANGLE
151 value += dac_buffer_triangle[dac_i] / active_tones_snapshot_length / 3;
152 // SQUARE
153 value += dac_buffer_square[dac_i] / active_tones_snapshot_length / 3;
154 //NOTE: combination of these three wave-forms is more exemplary - and doesn't sound particularly good :-P
155 */
156
157 // STAIRS (mostly usefully as test-pattern)
158 // value_avg = dac_buffer_staircase[dac_i] / active_tones_snapshot_length;
159 }
160
161 return value;
162}
163
164/**
165 * DAC streaming callback. Does all of the main computing for playing songs.
166 *
167 * Note: chibios calls this CB twice: during the 'half buffer event', and the 'full buffer event'.
168 */
169static void dac_end(DACDriver *dacp) {
170 dacsample_t *sample_p = (dacp)->samples;
171
172 // work on the other half of the buffer
173 if (dacIsBufferComplete(dacp)) {
174 sample_p += AUDIO_DAC_BUFFER_SIZE / 2; // 'half_index'
175 }
176
177 for (uint8_t s = 0; s < AUDIO_DAC_BUFFER_SIZE / 2; s++) {
178 if (OUTPUT_OFF <= state) {
179 sample_p[s] = AUDIO_DAC_OFF_VALUE;
180 continue;
181 } else {
182 sample_p[s] = dac_value_generate();
183 }
184
185 /* zero crossing (or approach, whereas zero == DAC_OFF_VALUE, which can be configured to anything from 0 to DAC_SAMPLE_MAX)
186 * ============================*=*========================== AUDIO_DAC_SAMPLE_MAX
187 * * *
188 * * *
189 * ---------------------------------------------------------
190 * * * } AUDIO_DAC_SAMPLE_MAX/100
191 * --------------------------------------------------------- AUDIO_DAC_OFF_VALUE
192 * * * } AUDIO_DAC_SAMPLE_MAX/100
193 * ---------------------------------------------------------
194 * *
195 * * *
196 * * *
197 * =====*=*================================================= 0x0
198 */
199 if (((sample_p[s] + (AUDIO_DAC_SAMPLE_MAX / 100)) > AUDIO_DAC_OFF_VALUE) && // value approaches from below
200 (sample_p[s] < (AUDIO_DAC_OFF_VALUE + (AUDIO_DAC_SAMPLE_MAX / 100))) // or above
201 ) {
202 if ((OUTPUT_SHOULD_START == state) && (active_tones_snapshot_length > 0)) {
203 state = OUTPUT_RUN_NORMALLY;
204 } else if (OUTPUT_TONES_CHANGED == state) {
205 state = OUTPUT_REACHED_ZERO_BEFORE_TONE_CHANGE;
206 } else if (OUTPUT_SHOULD_STOP == state) {
207 state = OUTPUT_REACHED_ZERO_BEFORE_OFF;
208 }
209 }
210
211 // still 'ramping up', reset the output to OFF_VALUE until the generated values reach that value, to do a smooth handover
212 if (OUTPUT_SHOULD_START == state) {
213 sample_p[s] = AUDIO_DAC_OFF_VALUE;
214 }
215
216 if ((OUTPUT_SHOULD_START == state) || (OUTPUT_REACHED_ZERO_BEFORE_OFF == state) || (OUTPUT_REACHED_ZERO_BEFORE_TONE_CHANGE == state)) {
217 uint8_t active_tones = MIN(AUDIO_MAX_SIMULTANEOUS_TONES, audio_get_number_of_active_tones());
218 active_tones_snapshot_length = 0;
219 // update the snapshot - once, and only on occasion that something changed;
220 // -> saves cpu cycles (?)
221 for (uint8_t i = 0; i < active_tones; i++) {
222 float freq = audio_get_processed_frequency(i);
223 if (freq > 0) { // disregard 'rest' notes, with valid frequency 0.0f; which would only lower the resulting waveform volume during the additive synthesis step
224 active_tones_snapshot[active_tones_snapshot_length++] = freq;
225 }
226 }
227
228 if ((0 == active_tones_snapshot_length) && (OUTPUT_REACHED_ZERO_BEFORE_OFF == state)) {
229 state = OUTPUT_OFF;
230 }
231 if (OUTPUT_REACHED_ZERO_BEFORE_TONE_CHANGE == state) {
232 state = OUTPUT_RUN_NORMALLY;
233 }
234 }
235 }
236
237 // update audio internal state (note position, current_note, ...)
238 if (audio_update_state()) {
239 if (OUTPUT_SHOULD_STOP != state) {
240 state = OUTPUT_TONES_CHANGED;
241 }
242 }
243
244 if (OUTPUT_OFF <= state) {
245 if (OUTPUT_OFF_2 == state) {
246 // stopping timer6 = stopping the DAC at whatever value it is currently pushing to the output = AUDIO_DAC_OFF_VALUE
247 gptStopTimer(&GPTD6);
248 } else {
249 state++;
250 }
251 }
252}
253
254static void dac_error(DACDriver *dacp, dacerror_t err) {
255 (void)dacp;
256 (void)err;
257
258 chSysHalt("DAC failure. halp");
259}
260
261static const GPTConfig gpt6cfg1 = {.frequency = AUDIO_DAC_SAMPLE_RATE * 3,
262 .callback = NULL,
263 .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */
264 .dier = 0U};
265
266static const DACConfig dac_conf = {.init = AUDIO_DAC_OFF_VALUE, .datamode = DAC_DHRM_12BIT_RIGHT};
267
268/**
269 * @note The DAC_TRG(0) here selects the Timer 6 TRGO event, which is triggered
270 * on the rising edge after 3 APB1 clock cycles, causing our gpt6cfg1.frequency
271 * to be a third of what we expect.
272 *
273 * Here are all the values for DAC_TRG (TSEL in the ref manual)
274 * TIM15_TRGO 0b011
275 * TIM2_TRGO 0b100
276 * TIM3_TRGO 0b001
277 * TIM6_TRGO 0b000
278 * TIM7_TRGO 0b010
279 * EXTI9 0b110
280 * SWTRIG 0b111
281 */
282static const DACConversionGroup dac_conv_cfg = {.num_channels = 1U, .end_cb = dac_end, .error_cb = dac_error, .trigger = DAC_TRG(0b000)};
283
284void audio_driver_initialize() {
285 if ((AUDIO_PIN == A4) || (AUDIO_PIN_ALT == A4)) {
286 palSetLineMode(A4, PAL_MODE_INPUT_ANALOG);
287 dacStart(&DACD1, &dac_conf);
288 }
289 if ((AUDIO_PIN == A5) || (AUDIO_PIN_ALT == A5)) {
290 palSetLineMode(A5, PAL_MODE_INPUT_ANALOG);
291 dacStart(&DACD2, &dac_conf);
292 }
293
294 /* enable the output buffer, to directly drive external loads with no additional circuitry
295 *
296 * see: AN4566 Application note: Extending the DAC performance of STM32 microcontrollers
297 * Note: Buffer-Off bit -> has to be set 0 to enable the output buffer
298 * Note: enabling the output buffer imparts an additional dc-offset of a couple mV
299 *
300 * this is done here, reaching directly into the stm32 registers since chibios has not implemented BOFF handling yet
301 * (see: chibios/os/hal/ports/STM32/todo.txt '- BOFF handling in DACv1.'
302 */
303 DACD1.params->dac->CR &= ~DAC_CR_BOFF1;
304 DACD2.params->dac->CR &= ~DAC_CR_BOFF2;
305
306 if (AUDIO_PIN == A4) {
307 dacStartConversion(&DACD1, &dac_conv_cfg, dac_buffer_empty, AUDIO_DAC_BUFFER_SIZE);
308 } else if (AUDIO_PIN == A5) {
309 dacStartConversion(&DACD2, &dac_conv_cfg, dac_buffer_empty, AUDIO_DAC_BUFFER_SIZE);
310 }
311
312 // no inverted/out-of-phase waveform (yet?), only pulling AUDIO_PIN_ALT to AUDIO_DAC_OFF_VALUE
313#if defined(AUDIO_PIN_ALT_AS_NEGATIVE)
314 if (AUDIO_PIN_ALT == A4) {
315 dacPutChannelX(&DACD1, 0, AUDIO_DAC_OFF_VALUE);
316 } else if (AUDIO_PIN_ALT == A5) {
317 dacPutChannelX(&DACD2, 0, AUDIO_DAC_OFF_VALUE);
318 }
319#endif
320
321 gptStart(&GPTD6, &gpt6cfg1);
322}
323
324void audio_driver_stop(void) { state = OUTPUT_SHOULD_STOP; }
325
326void audio_driver_start(void) {
327 gptStartContinuous(&GPTD6, 2U);
328
329 for (uint8_t i = 0; i < AUDIO_MAX_SIMULTANEOUS_TONES; i++) {
330 dac_if[i] = 0.0f;
331 active_tones_snapshot[i] = 0.0f;
332 }
333 active_tones_snapshot_length = 0;
334 state = OUTPUT_SHOULD_START;
335}
diff --git a/platforms/chibios/drivers/audio_dac_basic.c b/platforms/chibios/drivers/audio_dac_basic.c
new file mode 100644
index 000000000..fac651350
--- /dev/null
+++ b/platforms/chibios/drivers/audio_dac_basic.c
@@ -0,0 +1,245 @@
1/* Copyright 2016-2020 Jack Humbert
2 * Copyright 2020 JohSchneider
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "audio.h"
19#include "ch.h"
20#include "hal.h"
21
22/*
23 Audio Driver: DAC
24
25 which utilizes both channels of the DAC unit many STM32 are equipped with to output a modulated square-wave, from precomputed samples stored in a buffer, which is passed to the hardware through DMA
26
27 this driver can either be used to drive to separate speakers, wired to A4+Gnd and A5+Gnd, which allows two tones to be played simultaneously
28 OR
29 one speaker wired to A4+A5 with the AUDIO_PIN_ALT_AS_NEGATIVE define set - see docs/feature_audio
30
31*/
32
33#if !defined(AUDIO_PIN)
34# pragma message "Audio feature enabled, but no suitable pin selected as AUDIO_PIN - see docs/feature_audio under 'ARM (DAC basic)' for available options."
35// TODO: make this an 'error' instead; go through a breaking change, and add AUDIO_PIN A5 to all keyboards currently using AUDIO on STM32 based boards? - for now: set the define here
36# define AUDIO_PIN A5
37#endif
38// check configuration for ONE speaker, connected to both DAC pins
39#if defined(AUDIO_PIN_ALT_AS_NEGATIVE) && !defined(AUDIO_PIN_ALT)
40# error "Audio feature: AUDIO_PIN_ALT_AS_NEGATIVE set, but no pin configured as AUDIO_PIN_ALT"
41#endif
42
43#ifndef AUDIO_PIN_ALT
44// no ALT pin defined is valid, but the c-ifs below need some value set
45# define AUDIO_PIN_ALT -1
46#endif
47
48#if !defined(AUDIO_STATE_TIMER)
49# define AUDIO_STATE_TIMER GPTD8
50#endif
51
52// square-wave
53static const dacsample_t dac_buffer_1[AUDIO_DAC_BUFFER_SIZE] = {
54 // First half is max, second half is 0
55 [0 ... AUDIO_DAC_BUFFER_SIZE / 2 - 1] = AUDIO_DAC_SAMPLE_MAX,
56 [AUDIO_DAC_BUFFER_SIZE / 2 ... AUDIO_DAC_BUFFER_SIZE - 1] = 0,
57};
58
59// square-wave
60static const dacsample_t dac_buffer_2[AUDIO_DAC_BUFFER_SIZE] = {
61 // opposite of dac_buffer above
62 [0 ... AUDIO_DAC_BUFFER_SIZE / 2 - 1] = 0,
63 [AUDIO_DAC_BUFFER_SIZE / 2 ... AUDIO_DAC_BUFFER_SIZE - 1] = AUDIO_DAC_SAMPLE_MAX,
64};
65
66GPTConfig gpt6cfg1 = {.frequency = AUDIO_DAC_SAMPLE_RATE,
67 .callback = NULL,
68 .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */
69 .dier = 0U};
70GPTConfig gpt7cfg1 = {.frequency = AUDIO_DAC_SAMPLE_RATE,
71 .callback = NULL,
72 .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */
73 .dier = 0U};
74
75static void gpt_audio_state_cb(GPTDriver *gptp);
76GPTConfig gptStateUpdateCfg = {.frequency = 10,
77 .callback = gpt_audio_state_cb,
78 .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */
79 .dier = 0U};
80
81static const DACConfig dac_conf_ch1 = {.init = AUDIO_DAC_OFF_VALUE, .datamode = DAC_DHRM_12BIT_RIGHT};
82static const DACConfig dac_conf_ch2 = {.init = AUDIO_DAC_OFF_VALUE, .datamode = DAC_DHRM_12BIT_RIGHT};
83
84/**
85 * @note The DAC_TRG(0) here selects the Timer 6 TRGO event, which is triggered
86 * on the rising edge after 3 APB1 clock cycles, causing our gpt6cfg1.frequency
87 * to be a third of what we expect.
88 *
89 * Here are all the values for DAC_TRG (TSEL in the ref manual)
90 * TIM15_TRGO 0b011
91 * TIM2_TRGO 0b100
92 * TIM3_TRGO 0b001
93 * TIM6_TRGO 0b000
94 * TIM7_TRGO 0b010
95 * EXTI9 0b110
96 * SWTRIG 0b111
97 */
98static const DACConversionGroup dac_conv_grp_ch1 = {.num_channels = 1U, .trigger = DAC_TRG(0b000)};
99static const DACConversionGroup dac_conv_grp_ch2 = {.num_channels = 1U, .trigger = DAC_TRG(0b010)};
100
101void channel_1_start(void) {
102 gptStart(&GPTD6, &gpt6cfg1);
103 gptStartContinuous(&GPTD6, 2U);
104 palSetPadMode(GPIOA, 4, PAL_MODE_INPUT_ANALOG);
105}
106
107void channel_1_stop(void) {
108 gptStopTimer(&GPTD6);
109 palSetPadMode(GPIOA, 4, PAL_MODE_OUTPUT_PUSHPULL);
110 palSetPad(GPIOA, 4);
111}
112
113static float channel_1_frequency = 0.0f;
114void channel_1_set_frequency(float freq) {
115 channel_1_frequency = freq;
116
117 channel_1_stop();
118 if (freq <= 0.0) // a pause/rest has freq=0
119 return;
120
121 gpt6cfg1.frequency = 2 * freq * AUDIO_DAC_BUFFER_SIZE;
122 channel_1_start();
123}
124float channel_1_get_frequency(void) { return channel_1_frequency; }
125
126void channel_2_start(void) {
127 gptStart(&GPTD7, &gpt7cfg1);
128 gptStartContinuous(&GPTD7, 2U);
129 palSetPadMode(GPIOA, 5, PAL_MODE_INPUT_ANALOG);
130}
131
132void channel_2_stop(void) {
133 gptStopTimer(&GPTD7);
134 palSetPadMode(GPIOA, 5, PAL_MODE_OUTPUT_PUSHPULL);
135 palSetPad(GPIOA, 5);
136}
137
138static float channel_2_frequency = 0.0f;
139void channel_2_set_frequency(float freq) {
140 channel_2_frequency = freq;
141
142 channel_2_stop();
143 if (freq <= 0.0) // a pause/rest has freq=0
144 return;
145
146 gpt7cfg1.frequency = 2 * freq * AUDIO_DAC_BUFFER_SIZE;
147 channel_2_start();
148}
149float channel_2_get_frequency(void) { return channel_2_frequency; }
150
151static void gpt_audio_state_cb(GPTDriver *gptp) {
152 if (audio_update_state()) {
153#if defined(AUDIO_PIN_ALT_AS_NEGATIVE)
154 // one piezo/speaker connected to both audio pins, the generated square-waves are inverted
155 channel_1_set_frequency(audio_get_processed_frequency(0));
156 channel_2_set_frequency(audio_get_processed_frequency(0));
157
158#else // two separate audio outputs/speakers
159 // primary speaker on A4, optional secondary on A5
160 if (AUDIO_PIN == A4) {
161 channel_1_set_frequency(audio_get_processed_frequency(0));
162 if (AUDIO_PIN_ALT == A5) {
163 if (audio_get_number_of_active_tones() > 1) {
164 channel_2_set_frequency(audio_get_processed_frequency(1));
165 } else {
166 channel_2_stop();
167 }
168 }
169 }
170
171 // primary speaker on A5, optional secondary on A4
172 if (AUDIO_PIN == A5) {
173 channel_2_set_frequency(audio_get_processed_frequency(0));
174 if (AUDIO_PIN_ALT == A4) {
175 if (audio_get_number_of_active_tones() > 1) {
176 channel_1_set_frequency(audio_get_processed_frequency(1));
177 } else {
178 channel_1_stop();
179 }
180 }
181 }
182#endif
183 }
184}
185
186void audio_driver_initialize() {
187 if ((AUDIO_PIN == A4) || (AUDIO_PIN_ALT == A4)) {
188 palSetPadMode(GPIOA, 4, PAL_MODE_INPUT_ANALOG);
189 dacStart(&DACD1, &dac_conf_ch1);
190
191 // initial setup of the dac-triggering timer is still required, even
192 // though it gets reconfigured and restarted later on
193 gptStart(&GPTD6, &gpt6cfg1);
194 }
195
196 if ((AUDIO_PIN == A5) || (AUDIO_PIN_ALT == A5)) {
197 palSetPadMode(GPIOA, 5, PAL_MODE_INPUT_ANALOG);
198 dacStart(&DACD2, &dac_conf_ch2);
199
200 gptStart(&GPTD7, &gpt7cfg1);
201 }
202
203 /* enable the output buffer, to directly drive external loads with no additional circuitry
204 *
205 * see: AN4566 Application note: Extending the DAC performance of STM32 microcontrollers
206 * Note: Buffer-Off bit -> has to be set 0 to enable the output buffer
207 * Note: enabling the output buffer imparts an additional dc-offset of a couple mV
208 *
209 * this is done here, reaching directly into the stm32 registers since chibios has not implemented BOFF handling yet
210 * (see: chibios/os/hal/ports/STM32/todo.txt '- BOFF handling in DACv1.'
211 */
212 DACD1.params->dac->CR &= ~DAC_CR_BOFF1;
213 DACD2.params->dac->CR &= ~DAC_CR_BOFF2;
214
215 // start state-updater
216 gptStart(&AUDIO_STATE_TIMER, &gptStateUpdateCfg);
217}
218
219void audio_driver_stop(void) {
220 if ((AUDIO_PIN == A4) || (AUDIO_PIN_ALT == A4)) {
221 gptStopTimer(&GPTD6);
222
223 // stop the ongoing conversion and put the output in a known state
224 dacStopConversion(&DACD1);
225 dacPutChannelX(&DACD1, 0, AUDIO_DAC_OFF_VALUE);
226 }
227
228 if ((AUDIO_PIN == A5) || (AUDIO_PIN_ALT == A5)) {
229 gptStopTimer(&GPTD7);
230
231 dacStopConversion(&DACD2);
232 dacPutChannelX(&DACD2, 0, AUDIO_DAC_OFF_VALUE);
233 }
234 gptStopTimer(&AUDIO_STATE_TIMER);
235}
236
237void audio_driver_start(void) {
238 if ((AUDIO_PIN == A4) || (AUDIO_PIN_ALT == A4)) {
239 dacStartConversion(&DACD1, &dac_conv_grp_ch1, (dacsample_t *)dac_buffer_1, AUDIO_DAC_BUFFER_SIZE);
240 }
241 if ((AUDIO_PIN == A5) || (AUDIO_PIN_ALT == A5)) {
242 dacStartConversion(&DACD2, &dac_conv_grp_ch2, (dacsample_t *)dac_buffer_2, AUDIO_DAC_BUFFER_SIZE);
243 }
244 gptStartContinuous(&AUDIO_STATE_TIMER, 2U);
245}
diff --git a/platforms/chibios/drivers/audio_pwm.h b/platforms/chibios/drivers/audio_pwm.h
new file mode 100644
index 000000000..86cab916e
--- /dev/null
+++ b/platforms/chibios/drivers/audio_pwm.h
@@ -0,0 +1,40 @@
1/* Copyright 2020 Jack Humbert
2 * Copyright 2020 JohSchneider
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17#pragma once
18
19#if !defined(AUDIO_PWM_DRIVER)
20// NOTE: Timer2 seems to be used otherwise in QMK, otherwise we could default to A5 (= TIM2_CH1, with PWMD2 and alternate-function(1))
21# define AUDIO_PWM_DRIVER PWMD1
22#endif
23
24#if !defined(AUDIO_PWM_CHANNEL)
25// NOTE: sticking to the STM data-sheet numbering: TIMxCH1 to TIMxCH4
26// default: STM32F303CC PA8+TIM1_CH1 -> 1
27# define AUDIO_PWM_CHANNEL 1
28#endif
29
30#if !defined(AUDIO_PWM_PAL_MODE)
31// pin-alternate function: see the data-sheet for which pin needs what AF to connect to TIMx_CHy
32// default: STM32F303CC PA8+TIM1_CH1 -> 6
33# define AUDIO_PWM_PAL_MODE 6
34#endif
35
36#if !defined(AUDIO_STATE_TIMER)
37// timer used to trigger updates in the audio-system, configured/enabled in chibios mcuconf.
38// Tim6 is the default for "larger" STMs, smaller ones might not have this one (enabled) and need to switch to a different one (e.g.: STM32F103 has only Tim1-Tim4)
39# define AUDIO_STATE_TIMER GPTD6
40#endif
diff --git a/platforms/chibios/drivers/audio_pwm_hardware.c b/platforms/chibios/drivers/audio_pwm_hardware.c
new file mode 100644
index 000000000..cd40019ee
--- /dev/null
+++ b/platforms/chibios/drivers/audio_pwm_hardware.c
@@ -0,0 +1,144 @@
1/* Copyright 2020 Jack Humbert
2 * Copyright 2020 JohSchneider
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18/*
19Audio Driver: PWM
20
21the duty-cycle is always kept at 50%, and the pwm-period is adjusted to match the frequency of a note to be played back.
22
23this driver uses the chibios-PWM system to produce a square-wave on specific output pins that are connected to the PWM hardware.
24The hardware directly toggles the pin via its alternate function. see your MCUs data-sheet for which pin can be driven by what timer - looking for TIMx_CHy and the corresponding alternate function.
25
26 */
27
28#include "audio.h"
29#include "ch.h"
30#include "hal.h"
31
32#if !defined(AUDIO_PIN)
33# error "Audio feature enabled, but no pin selected - see docs/feature_audio under the ARM PWM settings"
34#endif
35
36extern bool playing_note;
37extern bool playing_melody;
38extern uint8_t note_timbre;
39
40static PWMConfig pwmCFG = {
41 .frequency = 100000, /* PWM clock frequency */
42 // CHIBIOS-BUG? can't set the initial period to <2, or the pwm (hard or software) takes ~130ms with .frequency=500000 for a pwmChangePeriod to take effect; with no output=silence in the meantime
43 .period = 2, /* initial PWM period (in ticks) 1S (1/10kHz=0.1mS 0.1ms*10000 ticks=1S) */
44 .callback = NULL, /* no callback, the hardware directly toggles the pin */
45 .channels =
46 {
47#if AUDIO_PWM_CHANNEL == 4
48 {PWM_OUTPUT_DISABLED, NULL}, /* channel 0 -> TIMx_CH1 */
49 {PWM_OUTPUT_DISABLED, NULL}, /* channel 1 -> TIMx_CH2 */
50 {PWM_OUTPUT_DISABLED, NULL}, /* channel 2 -> TIMx_CH3 */
51 {PWM_OUTPUT_ACTIVE_HIGH, NULL} /* channel 3 -> TIMx_CH4 */
52#elif AUDIO_PWM_CHANNEL == 3
53 {PWM_OUTPUT_DISABLED, NULL},
54 {PWM_OUTPUT_DISABLED, NULL},
55 {PWM_OUTPUT_ACTIVE_HIGH, NULL}, /* TIMx_CH3 */
56 {PWM_OUTPUT_DISABLED, NULL}
57#elif AUDIO_PWM_CHANNEL == 2
58 {PWM_OUTPUT_DISABLED, NULL},
59 {PWM_OUTPUT_ACTIVE_HIGH, NULL}, /* TIMx_CH2 */
60 {PWM_OUTPUT_DISABLED, NULL},
61 {PWM_OUTPUT_DISABLED, NULL}
62#else /*fallback to CH1 */
63 {PWM_OUTPUT_ACTIVE_HIGH, NULL}, /* TIMx_CH1 */
64 {PWM_OUTPUT_DISABLED, NULL},
65 {PWM_OUTPUT_DISABLED, NULL},
66 {PWM_OUTPUT_DISABLED, NULL}
67#endif
68 },
69};
70
71static float channel_1_frequency = 0.0f;
72void channel_1_set_frequency(float freq) {
73 channel_1_frequency = freq;
74
75 if (freq <= 0.0) // a pause/rest has freq=0
76 return;
77
78 pwmcnt_t period = (pwmCFG.frequency / freq);
79 pwmChangePeriod(&AUDIO_PWM_DRIVER, period);
80 pwmEnableChannel(&AUDIO_PWM_DRIVER, AUDIO_PWM_CHANNEL - 1,
81 // adjust the duty-cycle so that the output is for 'note_timbre' duration HIGH
82 PWM_PERCENTAGE_TO_WIDTH(&AUDIO_PWM_DRIVER, (100 - note_timbre) * 100));
83}
84
85float channel_1_get_frequency(void) { return channel_1_frequency; }
86
87void channel_1_start(void) {
88 pwmStop(&AUDIO_PWM_DRIVER);
89 pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG);
90}
91
92void channel_1_stop(void) { pwmStop(&AUDIO_PWM_DRIVER); }
93
94static void gpt_callback(GPTDriver *gptp);
95GPTConfig gptCFG = {
96 /* a whole note is one beat, which is - per definition in musical_notes.h - set to 64
97 the longest note is BREAVE_DOT=128+64=192, the shortest SIXTEENTH=4
98 the tempo (which might vary!) is in bpm (beats per minute)
99 therefore: if the timer ticks away at .frequency = (60*64)Hz,
100 and the .interval counts from 64 downwards - audio_update_state is
101 called just often enough to not miss any notes
102 */
103 .frequency = 60 * 64,
104 .callback = gpt_callback,
105};
106
107void audio_driver_initialize(void) {
108 pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG);
109
110 // connect the AUDIO_PIN to the PWM hardware
111#if defined(USE_GPIOV1) // STM32F103C8
112 palSetLineMode(AUDIO_PIN, PAL_MODE_ALTERNATE_PUSHPULL);
113#else // GPIOv2 (or GPIOv3 for f4xx, which is the same/compatible at this command)
114 palSetLineMode(AUDIO_PIN, PAL_MODE_ALTERNATE(AUDIO_PWM_PAL_MODE));
115#endif
116
117 gptStart(&AUDIO_STATE_TIMER, &gptCFG);
118}
119
120void audio_driver_start(void) {
121 channel_1_stop();
122 channel_1_start();
123
124 if (playing_note || playing_melody) {
125 gptStartContinuous(&AUDIO_STATE_TIMER, 64);
126 }
127}
128
129void audio_driver_stop(void) {
130 channel_1_stop();
131 gptStopTimer(&AUDIO_STATE_TIMER);
132}
133
134/* a regular timer task, that checks the note to be currently played
135 * and updates the pwm to output that frequency
136 */
137static void gpt_callback(GPTDriver *gptp) {
138 float freq; // TODO: freq_alt
139
140 if (audio_update_state()) {
141 freq = audio_get_processed_frequency(0); // freq_alt would be index=1
142 channel_1_set_frequency(freq);
143 }
144}
diff --git a/platforms/chibios/drivers/audio_pwm_software.c b/platforms/chibios/drivers/audio_pwm_software.c
new file mode 100644
index 000000000..15c3e98b6
--- /dev/null
+++ b/platforms/chibios/drivers/audio_pwm_software.c
@@ -0,0 +1,164 @@
1/* Copyright 2020 Jack Humbert
2 * Copyright 2020 JohSchneider
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18/*
19Audio Driver: PWM
20
21the duty-cycle is always kept at 50%, and the pwm-period is adjusted to match the frequency of a note to be played back.
22
23this driver uses the chibios-PWM system to produce a square-wave on any given output pin in software
24- a pwm callback is used to set/clear the configured pin.
25
26 */
27#include "audio.h"
28#include "ch.h"
29#include "hal.h"
30
31#if !defined(AUDIO_PIN)
32# error "Audio feature enabled, but no pin selected - see docs/feature_audio under the ARM PWM settings"
33#endif
34extern bool playing_note;
35extern bool playing_melody;
36extern uint8_t note_timbre;
37
38static void pwm_audio_period_callback(PWMDriver *pwmp);
39static void pwm_audio_channel_interrupt_callback(PWMDriver *pwmp);
40
41static PWMConfig pwmCFG = {
42 .frequency = 100000, /* PWM clock frequency */
43 // CHIBIOS-BUG? can't set the initial period to <2, or the pwm (hard or software) takes ~130ms with .frequency=500000 for a pwmChangePeriod to take effect; with no output=silence in the meantime
44 .period = 2, /* initial PWM period (in ticks) 1S (1/10kHz=0.1mS 0.1ms*10000 ticks=1S) */
45 .callback = pwm_audio_period_callback,
46 .channels =
47 {
48 // software-PWM just needs another callback on any channel
49 {PWM_OUTPUT_ACTIVE_HIGH, pwm_audio_channel_interrupt_callback}, /* channel 0 -> TIMx_CH1 */
50 {PWM_OUTPUT_DISABLED, NULL}, /* channel 1 -> TIMx_CH2 */
51 {PWM_OUTPUT_DISABLED, NULL}, /* channel 2 -> TIMx_CH3 */
52 {PWM_OUTPUT_DISABLED, NULL} /* channel 3 -> TIMx_CH4 */
53 },
54};
55
56static float channel_1_frequency = 0.0f;
57void channel_1_set_frequency(float freq) {
58 channel_1_frequency = freq;
59
60 if (freq <= 0.0) // a pause/rest has freq=0
61 return;
62
63 pwmcnt_t period = (pwmCFG.frequency / freq);
64 pwmChangePeriod(&AUDIO_PWM_DRIVER, period);
65
66 pwmEnableChannel(&AUDIO_PWM_DRIVER, AUDIO_PWM_CHANNEL - 1,
67 // adjust the duty-cycle so that the output is for 'note_timbre' duration HIGH
68 PWM_PERCENTAGE_TO_WIDTH(&AUDIO_PWM_DRIVER, (100 - note_timbre) * 100));
69}
70
71float channel_1_get_frequency(void) { return channel_1_frequency; }
72
73void channel_1_start(void) {
74 pwmStop(&AUDIO_PWM_DRIVER);
75 pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG);
76
77 pwmEnablePeriodicNotification(&AUDIO_PWM_DRIVER);
78 pwmEnableChannelNotification(&AUDIO_PWM_DRIVER, AUDIO_PWM_CHANNEL - 1);
79}
80
81void channel_1_stop(void) {
82 pwmStop(&AUDIO_PWM_DRIVER);
83
84 palClearLine(AUDIO_PIN); // leave the line low, after last note was played
85
86#if defined(AUDIO_PIN_ALT) && defined(AUDIO_PIN_ALT_AS_NEGATIVE)
87 palClearLine(AUDIO_PIN_ALT); // leave the line low, after last note was played
88#endif
89}
90
91// generate a PWM signal on any pin, not necessarily the one connected to the timer
92static void pwm_audio_period_callback(PWMDriver *pwmp) {
93 (void)pwmp;
94 palClearLine(AUDIO_PIN);
95
96#if defined(AUDIO_PIN_ALT) && defined(AUDIO_PIN_ALT_AS_NEGATIVE)
97 palSetLine(AUDIO_PIN_ALT);
98#endif
99}
100static void pwm_audio_channel_interrupt_callback(PWMDriver *pwmp) {
101 (void)pwmp;
102 if (channel_1_frequency > 0) {
103 palSetLine(AUDIO_PIN); // generate a PWM signal on any pin, not necessarily the one connected to the timer
104#if defined(AUDIO_PIN_ALT) && defined(AUDIO_PIN_ALT_AS_NEGATIVE)
105 palClearLine(AUDIO_PIN_ALT);
106#endif
107 }
108}
109
110static void gpt_callback(GPTDriver *gptp);
111GPTConfig gptCFG = {
112 /* a whole note is one beat, which is - per definition in musical_notes.h - set to 64
113 the longest note is BREAVE_DOT=128+64=192, the shortest SIXTEENTH=4
114 the tempo (which might vary!) is in bpm (beats per minute)
115 therefore: if the timer ticks away at .frequency = (60*64)Hz,
116 and the .interval counts from 64 downwards - audio_update_state is
117 called just often enough to not miss anything
118 */
119 .frequency = 60 * 64,
120 .callback = gpt_callback,
121};
122
123void audio_driver_initialize(void) {
124 pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG);
125
126 palSetLineMode(AUDIO_PIN, PAL_MODE_OUTPUT_PUSHPULL);
127 palClearLine(AUDIO_PIN);
128
129#if defined(AUDIO_PIN_ALT) && defined(AUDIO_PIN_ALT_AS_NEGATIVE)
130 palSetLineMode(AUDIO_PIN_ALT, PAL_MODE_OUTPUT_PUSHPULL);
131 palClearLine(AUDIO_PIN_ALT);
132#endif
133
134 pwmEnablePeriodicNotification(&AUDIO_PWM_DRIVER); // enable pwm callbacks
135 pwmEnableChannelNotification(&AUDIO_PWM_DRIVER, AUDIO_PWM_CHANNEL - 1);
136
137 gptStart(&AUDIO_STATE_TIMER, &gptCFG);
138}
139
140void audio_driver_start(void) {
141 channel_1_stop();
142 channel_1_start();
143
144 if (playing_note || playing_melody) {
145 gptStartContinuous(&AUDIO_STATE_TIMER, 64);
146 }
147}
148
149void audio_driver_stop(void) {
150 channel_1_stop();
151 gptStopTimer(&AUDIO_STATE_TIMER);
152}
153
154/* a regular timer task, that checks the note to be currently played
155 * and updates the pwm to output that frequency
156 */
157static void gpt_callback(GPTDriver *gptp) {
158 float freq; // TODO: freq_alt
159
160 if (audio_update_state()) {
161 freq = audio_get_processed_frequency(0); // freq_alt would be index=1
162 channel_1_set_frequency(freq);
163 }
164}
diff --git a/platforms/chibios/drivers/i2c_master.c b/platforms/chibios/drivers/i2c_master.c
index fc4bb2ab3..63e85ae87 100644
--- a/platforms/chibios/drivers/i2c_master.c
+++ b/platforms/chibios/drivers/i2c_master.c
@@ -63,16 +63,16 @@ __attribute__((weak)) void i2c_init(void) {
63 is_initialised = true; 63 is_initialised = true;
64 64
65 // Try releasing special pins for a short time 65 // Try releasing special pins for a short time
66 palSetPadMode(I2C1_SCL_BANK, I2C1_SCL, PAL_MODE_INPUT); 66 palSetLineMode(I2C1_SCL_PIN, PAL_MODE_INPUT);
67 palSetPadMode(I2C1_SDA_BANK, I2C1_SDA, PAL_MODE_INPUT); 67 palSetLineMode(I2C1_SDA_PIN, PAL_MODE_INPUT);
68 68
69 chThdSleepMilliseconds(10); 69 chThdSleepMilliseconds(10);
70#if defined(USE_GPIOV1) 70#if defined(USE_GPIOV1)
71 palSetPadMode(I2C1_SCL_BANK, I2C1_SCL, I2C1_SCL_PAL_MODE); 71 palSetLineMode(I2C1_SCL_PIN, I2C1_SCL_PAL_MODE);
72 palSetPadMode(I2C1_SDA_BANK, I2C1_SDA, I2C1_SDA_PAL_MODE); 72 palSetLineMode(I2C1_SDA_PIN, I2C1_SDA_PAL_MODE);
73#else 73#else
74 palSetPadMode(I2C1_SCL_BANK, I2C1_SCL, PAL_MODE_ALTERNATE(I2C1_SCL_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN); 74 palSetLineMode(I2C1_SCL_PIN, PAL_MODE_ALTERNATE(I2C1_SCL_PAL_MODE) | PAL_OUTPUT_TYPE_OPENDRAIN);
75 palSetPadMode(I2C1_SDA_BANK, I2C1_SDA, PAL_MODE_ALTERNATE(I2C1_SDA_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN); 75 palSetLineMode(I2C1_SDA_PIN, PAL_MODE_ALTERNATE(I2C1_SDA_PAL_MODE) | PAL_OUTPUT_TYPE_OPENDRAIN);
76#endif 76#endif
77 } 77 }
78} 78}
@@ -102,7 +102,7 @@ i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data,
102 i2cStart(&I2C_DRIVER, &i2cconfig); 102 i2cStart(&I2C_DRIVER, &i2cconfig);
103 103
104 uint8_t complete_packet[length + 1]; 104 uint8_t complete_packet[length + 1];
105 for (uint8_t i = 0; i < length; i++) { 105 for (uint16_t i = 0; i < length; i++) {
106 complete_packet[i + 1] = data[i]; 106 complete_packet[i + 1] = data[i];
107 } 107 }
108 complete_packet[0] = regaddr; 108 complete_packet[0] = regaddr;
@@ -111,6 +111,21 @@ i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data,
111 return chibios_to_qmk(&status); 111 return chibios_to_qmk(&status);
112} 112}
113 113
114i2c_status_t i2c_writeReg16(uint8_t devaddr, uint16_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout) {
115 i2c_address = devaddr;
116 i2cStart(&I2C_DRIVER, &i2cconfig);
117
118 uint8_t complete_packet[length + 2];
119 for (uint16_t i = 0; i < length; i++) {
120 complete_packet[i + 2] = data[i];
121 }
122 complete_packet[0] = regaddr >> 8;
123 complete_packet[1] = regaddr & 0xFF;
124
125 msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), complete_packet, length + 2, 0, 0, TIME_MS2I(timeout));
126 return chibios_to_qmk(&status);
127}
128
114i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) { 129i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) {
115 i2c_address = devaddr; 130 i2c_address = devaddr;
116 i2cStart(&I2C_DRIVER, &i2cconfig); 131 i2cStart(&I2C_DRIVER, &i2cconfig);
@@ -118,4 +133,12 @@ i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16
118 return chibios_to_qmk(&status); 133 return chibios_to_qmk(&status);
119} 134}
120 135
136i2c_status_t i2c_readReg16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) {
137 i2c_address = devaddr;
138 i2cStart(&I2C_DRIVER, &i2cconfig);
139 uint8_t register_packet[2] = {regaddr >> 8, regaddr & 0xFF};
140 msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), register_packet, 2, data, length, TIME_MS2I(timeout));
141 return chibios_to_qmk(&status);
142}
143
121void i2c_stop(void) { i2cStop(&I2C_DRIVER); } 144void i2c_stop(void) { i2cStop(&I2C_DRIVER); }
diff --git a/platforms/chibios/drivers/i2c_master.h b/platforms/chibios/drivers/i2c_master.h
index c68109acb..5f082e9d1 100644
--- a/platforms/chibios/drivers/i2c_master.h
+++ b/platforms/chibios/drivers/i2c_master.h
@@ -27,24 +27,11 @@
27#include <ch.h> 27#include <ch.h>
28#include <hal.h> 28#include <hal.h>
29 29
30#ifdef I2C1_BANK 30#ifndef I2C1_SCL_PIN
31# define I2C1_SCL_BANK I2C1_BANK 31# define I2C1_SCL_PIN B6
32# define I2C1_SDA_BANK I2C1_BANK
33#endif 32#endif
34 33#ifndef I2C1_SDA_PIN
35#ifndef I2C1_SCL_BANK 34# define I2C1_SDA_PIN B7
36# define I2C1_SCL_BANK GPIOB
37#endif
38
39#ifndef I2C1_SDA_BANK
40# define I2C1_SDA_BANK GPIOB
41#endif
42
43#ifndef I2C1_SCL
44# define I2C1_SCL 6
45#endif
46#ifndef I2C1_SDA
47# define I2C1_SDA 7
48#endif 35#endif
49 36
50#ifdef USE_I2CV1 37#ifdef USE_I2CV1
@@ -83,10 +70,10 @@
83 70
84#ifdef USE_GPIOV1 71#ifdef USE_GPIOV1
85# ifndef I2C1_SCL_PAL_MODE 72# ifndef I2C1_SCL_PAL_MODE
86# define I2C1_SCL_PAL_MODE PAL_MODE_STM32_ALTERNATE_OPENDRAIN 73# define I2C1_SCL_PAL_MODE PAL_MODE_ALTERNATE_OPENDRAIN
87# endif 74# endif
88# ifndef I2C1_SDA_PAL_MODE 75# ifndef I2C1_SDA_PAL_MODE
89# define I2C1_SDA_PAL_MODE PAL_MODE_STM32_ALTERNATE_OPENDRAIN 76# define I2C1_SDA_PAL_MODE PAL_MODE_ALTERNATE_OPENDRAIN
90# endif 77# endif
91#else 78#else
92// The default PAL alternate modes are used to signal that the pins are used for I2C 79// The default PAL alternate modes are used to signal that the pins are used for I2C
@@ -109,5 +96,7 @@ i2c_status_t i2c_start(uint8_t address);
109i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout); 96i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout);
110i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout); 97i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout);
111i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout); 98i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout);
99i2c_status_t i2c_writeReg16(uint8_t devaddr, uint16_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout);
112i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout); 100i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);
101i2c_status_t i2c_readReg16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);
113void i2c_stop(void); 102void i2c_stop(void);
diff --git a/platforms/chibios/drivers/ps2/ps2_io.c b/platforms/chibios/drivers/ps2/ps2_io.c
new file mode 100644
index 000000000..906d85d84
--- /dev/null
+++ b/platforms/chibios/drivers/ps2/ps2_io.c
@@ -0,0 +1,55 @@
1#include <stdbool.h>
2#include "ps2_io.h"
3
4// chibiOS headers
5#include "ch.h"
6#include "hal.h"
7
8/* Check port settings for clock and data line */
9#if !(defined(PS2_CLOCK_PIN))
10# error "PS/2 clock setting is required in config.h"
11#endif
12
13#if !(defined(PS2_DATA_PIN))
14# error "PS/2 data setting is required in config.h"
15#endif
16
17/*
18 * Clock
19 */
20void clock_init(void) {}
21
22void clock_lo(void) {
23 palSetLineMode(PS2_CLOCK_PIN, PAL_MODE_OUTPUT_OPENDRAIN);
24 palWriteLine(PS2_CLOCK_PIN, PAL_LOW);
25}
26
27void clock_hi(void) {
28 palSetLineMode(PS2_CLOCK_PIN, PAL_MODE_OUTPUT_OPENDRAIN);
29 palWriteLine(PS2_CLOCK_PIN, PAL_HIGH);
30}
31
32bool clock_in(void) {
33 palSetLineMode(PS2_CLOCK_PIN, PAL_MODE_INPUT);
34 return palReadLine(PS2_CLOCK_PIN);
35}
36
37/*
38 * Data
39 */
40void data_init(void) {}
41
42void data_lo(void) {
43 palSetLineMode(PS2_DATA_PIN, PAL_MODE_OUTPUT_OPENDRAIN);
44 palWriteLine(PS2_DATA_PIN, PAL_LOW);
45}
46
47void data_hi(void) {
48 palSetLineMode(PS2_DATA_PIN, PAL_MODE_OUTPUT_OPENDRAIN);
49 palWriteLine(PS2_DATA_PIN, PAL_HIGH);
50}
51
52bool data_in(void) {
53 palSetLineMode(PS2_DATA_PIN, PAL_MODE_INPUT);
54 return palReadLine(PS2_DATA_PIN);
55}
diff --git a/platforms/chibios/drivers/serial.c b/platforms/chibios/drivers/serial.c
index f54fbcee4..ef6f0aa8d 100644
--- a/platforms/chibios/drivers/serial.c
+++ b/platforms/chibios/drivers/serial.c
@@ -19,7 +19,7 @@
19# error "chSysPolledDelayX method not supported on this platform" 19# error "chSysPolledDelayX method not supported on this platform"
20#else 20#else
21# undef wait_us 21# undef wait_us
22# define wait_us(x) chSysPolledDelayX(US2RTC(STM32_SYSCLK, x)) 22# define wait_us(x) chSysPolledDelayX(US2RTC(CPU_CLOCK, x))
23#endif 23#endif
24 24
25#ifndef SELECT_SOFT_SERIAL_SPEED 25#ifndef SELECT_SOFT_SERIAL_SPEED
diff --git a/platforms/chibios/drivers/serial_usart.c b/platforms/chibios/drivers/serial_usart.c
index ea4473791..124e4be68 100644
--- a/platforms/chibios/drivers/serial_usart.c
+++ b/platforms/chibios/drivers/serial_usart.c
@@ -104,9 +104,9 @@ static inline bool receive(uint8_t* destination, const size_t size) {
104__attribute__((weak)) void usart_init(void) { 104__attribute__((weak)) void usart_init(void) {
105# if defined(MCU_STM32) 105# if defined(MCU_STM32)
106# if defined(USE_GPIOV1) 106# if defined(USE_GPIOV1)
107 palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_STM32_ALTERNATE_OPENDRAIN); 107 palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE_OPENDRAIN);
108# else 108# else
109 palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE(SERIAL_USART_TX_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN); 109 palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE(SERIAL_USART_TX_PAL_MODE) | PAL_OUTPUT_TYPE_OPENDRAIN);
110# endif 110# endif
111 111
112# if defined(USART_REMAP) 112# if defined(USART_REMAP)
@@ -125,11 +125,11 @@ __attribute__((weak)) void usart_init(void) {
125__attribute__((weak)) void usart_init(void) { 125__attribute__((weak)) void usart_init(void) {
126# if defined(MCU_STM32) 126# if defined(MCU_STM32)
127# if defined(USE_GPIOV1) 127# if defined(USE_GPIOV1)
128 palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_STM32_ALTERNATE_PUSHPULL); 128 palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE_PUSHPULL);
129 palSetLineMode(SERIAL_USART_RX_PIN, PAL_MODE_INPUT); 129 palSetLineMode(SERIAL_USART_RX_PIN, PAL_MODE_INPUT);
130# else 130# else
131 palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE(SERIAL_USART_TX_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); 131 palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE(SERIAL_USART_TX_PAL_MODE) | PAL_OUTPUT_TYPE_PUSHPULL | PAL_OUTPUT_SPEED_HIGHEST);
132 palSetLineMode(SERIAL_USART_RX_PIN, PAL_MODE_ALTERNATE(SERIAL_USART_RX_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); 132 palSetLineMode(SERIAL_USART_RX_PIN, PAL_MODE_ALTERNATE(SERIAL_USART_RX_PAL_MODE) | PAL_OUTPUT_TYPE_PUSHPULL | PAL_OUTPUT_SPEED_HIGHEST);
133# endif 133# endif
134 134
135# if defined(USART_REMAP) 135# if defined(USART_REMAP)
diff --git a/platforms/chibios/drivers/spi_master.c b/platforms/chibios/drivers/spi_master.c
index 28ddcbb2b..c592369dd 100644
--- a/platforms/chibios/drivers/spi_master.c
+++ b/platforms/chibios/drivers/spi_master.c
@@ -42,9 +42,9 @@ __attribute__((weak)) void spi_init(void) {
42 palSetPadMode(PAL_PORT(SPI_MOSI_PIN), PAL_PAD(SPI_MOSI_PIN), SPI_MOSI_PAL_MODE); 42 palSetPadMode(PAL_PORT(SPI_MOSI_PIN), PAL_PAD(SPI_MOSI_PIN), SPI_MOSI_PAL_MODE);
43 palSetPadMode(PAL_PORT(SPI_MISO_PIN), PAL_PAD(SPI_MISO_PIN), SPI_MISO_PAL_MODE); 43 palSetPadMode(PAL_PORT(SPI_MISO_PIN), PAL_PAD(SPI_MISO_PIN), SPI_MISO_PAL_MODE);
44#else 44#else
45 palSetPadMode(PAL_PORT(SPI_SCK_PIN), PAL_PAD(SPI_SCK_PIN), PAL_MODE_ALTERNATE(SPI_SCK_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); 45 palSetPadMode(PAL_PORT(SPI_SCK_PIN), PAL_PAD(SPI_SCK_PIN), PAL_MODE_ALTERNATE(SPI_SCK_PAL_MODE) | PAL_OUTPUT_TYPE_PUSHPULL | PAL_OUTPUT_SPEED_HIGHEST);
46 palSetPadMode(PAL_PORT(SPI_MOSI_PIN), PAL_PAD(SPI_MOSI_PIN), PAL_MODE_ALTERNATE(SPI_MOSI_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); 46 palSetPadMode(PAL_PORT(SPI_MOSI_PIN), PAL_PAD(SPI_MOSI_PIN), PAL_MODE_ALTERNATE(SPI_MOSI_PAL_MODE) | PAL_OUTPUT_TYPE_PUSHPULL | PAL_OUTPUT_SPEED_HIGHEST);
47 palSetPadMode(PAL_PORT(SPI_MISO_PIN), PAL_PAD(SPI_MISO_PIN), PAL_MODE_ALTERNATE(SPI_MISO_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); 47 palSetPadMode(PAL_PORT(SPI_MISO_PIN), PAL_PAD(SPI_MISO_PIN), PAL_MODE_ALTERNATE(SPI_MISO_PAL_MODE) | PAL_OUTPUT_TYPE_PUSHPULL | PAL_OUTPUT_SPEED_HIGHEST);
48#endif 48#endif
49 } 49 }
50} 50}
@@ -110,6 +110,31 @@ bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
110 spiConfig.tar0 |= SPIx_CTARn_BR(8); 110 spiConfig.tar0 |= SPIx_CTARn_BR(8);
111 break; 111 break;
112 } 112 }
113
114#elif defined(HT32)
115 spiConfig.cr0 = SPI_CR0_SELOEN;
116 spiConfig.cr1 = SPI_CR1_MODE | 8; // 8 bits and in master mode
117
118 if (lsbFirst) {
119 spiConfig.cr1 |= SPI_CR1_FIRSTBIT;
120 }
121
122 switch (mode) {
123 case 0:
124 spiConfig.cr1 |= SPI_CR1_FORMAT_MODE0;
125 break;
126 case 1:
127 spiConfig.cr1 |= SPI_CR1_FORMAT_MODE1;
128 break;
129 case 2:
130 spiConfig.cr1 |= SPI_CR1_FORMAT_MODE2;
131 break;
132 case 3:
133 spiConfig.cr1 |= SPI_CR1_FORMAT_MODE3;
134 break;
135 }
136
137 spiConfig.cpr = (roundedDivisor - 1) >> 1;
113#else 138#else
114 spiConfig.cr1 = 0; 139 spiConfig.cr1 = 0;
115 140
diff --git a/platforms/chibios/drivers/spi_master.h b/platforms/chibios/drivers/spi_master.h
index b5a6ef143..6a3ce481f 100644
--- a/platforms/chibios/drivers/spi_master.h
+++ b/platforms/chibios/drivers/spi_master.h
@@ -33,7 +33,7 @@
33 33
34#ifndef SPI_SCK_PAL_MODE 34#ifndef SPI_SCK_PAL_MODE
35# if defined(USE_GPIOV1) 35# if defined(USE_GPIOV1)
36# define SPI_SCK_PAL_MODE PAL_MODE_STM32_ALTERNATE_PUSHPULL 36# define SPI_SCK_PAL_MODE PAL_MODE_ALTERNATE_PUSHPULL
37# else 37# else
38# define SPI_SCK_PAL_MODE 5 38# define SPI_SCK_PAL_MODE 5
39# endif 39# endif
@@ -45,7 +45,7 @@
45 45
46#ifndef SPI_MOSI_PAL_MODE 46#ifndef SPI_MOSI_PAL_MODE
47# if defined(USE_GPIOV1) 47# if defined(USE_GPIOV1)
48# define SPI_MOSI_PAL_MODE PAL_MODE_STM32_ALTERNATE_PUSHPULL 48# define SPI_MOSI_PAL_MODE PAL_MODE_ALTERNATE_PUSHPULL
49# else 49# else
50# define SPI_MOSI_PAL_MODE 5 50# define SPI_MOSI_PAL_MODE 5
51# endif 51# endif
@@ -57,7 +57,7 @@
57 57
58#ifndef SPI_MISO_PAL_MODE 58#ifndef SPI_MISO_PAL_MODE
59# if defined(USE_GPIOV1) 59# if defined(USE_GPIOV1)
60# define SPI_MISO_PAL_MODE PAL_MODE_STM32_ALTERNATE_PUSHPULL 60# define SPI_MISO_PAL_MODE PAL_MODE_ALTERNATE_PUSHPULL
61# else 61# else
62# define SPI_MISO_PAL_MODE 5 62# define SPI_MISO_PAL_MODE 5
63# endif 63# endif
diff --git a/platforms/chibios/drivers/uart.c b/platforms/chibios/drivers/uart.c
index 030335b34..297c1892c 100644
--- a/platforms/chibios/drivers/uart.c
+++ b/platforms/chibios/drivers/uart.c
@@ -29,22 +29,26 @@ void uart_init(uint32_t baud) {
29 serialConfig.speed = baud; 29 serialConfig.speed = baud;
30 30
31#if defined(USE_GPIOV1) 31#if defined(USE_GPIOV1)
32 palSetLineMode(SD1_TX_PIN, PAL_MODE_STM32_ALTERNATE_OPENDRAIN); 32 palSetLineMode(SD1_TX_PIN, PAL_MODE_ALTERNATE_OPENDRAIN);
33 palSetLineMode(SD1_RX_PIN, PAL_MODE_STM32_ALTERNATE_OPENDRAIN); 33 palSetLineMode(SD1_RX_PIN, PAL_MODE_ALTERNATE_OPENDRAIN);
34#else 34#else
35 palSetLineMode(SD1_TX_PIN, PAL_MODE_ALTERNATE(SD1_TX_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN); 35 palSetLineMode(SD1_TX_PIN, PAL_MODE_ALTERNATE(SD1_TX_PAL_MODE) | PAL_OUTPUT_TYPE_OPENDRAIN);
36 palSetLineMode(SD1_RX_PIN, PAL_MODE_ALTERNATE(SD1_RX_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN); 36 palSetLineMode(SD1_RX_PIN, PAL_MODE_ALTERNATE(SD1_RX_PAL_MODE) | PAL_OUTPUT_TYPE_OPENDRAIN);
37#endif 37#endif
38 sdStart(&SERIAL_DRIVER, &serialConfig); 38 sdStart(&SERIAL_DRIVER, &serialConfig);
39 } 39 }
40} 40}
41 41
42void uart_putchar(uint8_t c) { sdPut(&SERIAL_DRIVER, c); } 42void uart_write(uint8_t data) { sdPut(&SERIAL_DRIVER, c); }
43 43
44uint8_t uart_getchar(void) { 44uint8_t uart_read(void) {
45 msg_t res = sdGet(&SERIAL_DRIVER); 45 msg_t res = sdGet(&SERIAL_DRIVER);
46 46
47 return (uint8_t)res; 47 return (uint8_t)res;
48} 48}
49 49
50void uart_transmit(const uint8_t *data, uint16_t length) { sdWrite(&SERIAL_DRIVER, data, length); }
51
52void uart_receive(uint8_t *data, uint16_t length) { sdRead(&SERIAL_DRIVER, data, length); }
53
50bool uart_available(void) { return !sdGetWouldBlock(&SERIAL_DRIVER); } 54bool uart_available(void) { return !sdGetWouldBlock(&SERIAL_DRIVER); }
diff --git a/platforms/chibios/drivers/uart.h b/platforms/chibios/drivers/uart.h
index b4e20e9fd..5bc487590 100644
--- a/platforms/chibios/drivers/uart.h
+++ b/platforms/chibios/drivers/uart.h
@@ -70,8 +70,12 @@
70 70
71void uart_init(uint32_t baud); 71void uart_init(uint32_t baud);
72 72
73void uart_putchar(uint8_t c); 73void uart_write(uint8_t data);
74 74
75uint8_t uart_getchar(void); 75uint8_t uart_read(void);
76
77void uart_transmit(const uint8_t *data, uint16_t length);
78
79void uart_receive(uint8_t *data, uint16_t length);
76 80
77bool uart_available(void); 81bool uart_available(void);
diff --git a/platforms/chibios/drivers/ws2812.c b/platforms/chibios/drivers/ws2812.c
index 0d12e2fb7..b46c46ae5 100644
--- a/platforms/chibios/drivers/ws2812.c
+++ b/platforms/chibios/drivers/ws2812.c
@@ -6,7 +6,7 @@
6/* Adapted from https://github.com/bigjosh/SimpleNeoPixelDemo/ */ 6/* Adapted from https://github.com/bigjosh/SimpleNeoPixelDemo/ */
7 7
8#ifndef NOP_FUDGE 8#ifndef NOP_FUDGE
9# if defined(STM32F0XX) || defined(STM32F1XX) || defined(STM32F3XX) || defined(STM32F4XX) || defined(STM32L0XX) 9# if defined(STM32F0XX) || defined(STM32F1XX) || defined(GD32VF103) || defined(STM32F3XX) || defined(STM32F4XX) || defined(STM32L0XX)
10# define NOP_FUDGE 0.4 10# define NOP_FUDGE 0.4
11# else 11# else
12# error("NOP_FUDGE configuration required") 12# error("NOP_FUDGE configuration required")
@@ -23,7 +23,7 @@
23#endif 23#endif
24 24
25#define NUMBER_NOPS 6 25#define NUMBER_NOPS 6
26#define CYCLES_PER_SEC (STM32_SYSCLK / NUMBER_NOPS * NOP_FUDGE) 26#define CYCLES_PER_SEC (CPU_CLOCK / NUMBER_NOPS * NOP_FUDGE)
27#define NS_PER_SEC (1000000000L) // Note that this has to be SIGNED since we want to be able to check for negative values of derivatives 27#define NS_PER_SEC (1000000000L) // Note that this has to be SIGNED since we want to be able to check for negative values of derivatives
28#define NS_PER_CYCLE (NS_PER_SEC / CYCLES_PER_SEC) 28#define NS_PER_CYCLE (NS_PER_SEC / CYCLES_PER_SEC)
29#define NS_TO_CYCLES(n) ((n) / NS_PER_CYCLE) 29#define NS_TO_CYCLES(n) ((n) / NS_PER_CYCLE)
diff --git a/platforms/chibios/drivers/ws2812_pwm.c b/platforms/chibios/drivers/ws2812_pwm.c
index e6af55b6b..c17b9cd4e 100644
--- a/platforms/chibios/drivers/ws2812_pwm.c
+++ b/platforms/chibios/drivers/ws2812_pwm.c
@@ -5,7 +5,9 @@
5/* Adapted from https://github.com/joewa/WS2812-LED-Driver_ChibiOS/ */ 5/* Adapted from https://github.com/joewa/WS2812-LED-Driver_ChibiOS/ */
6 6
7#ifdef RGBW 7#ifdef RGBW
8# error "RGBW not supported" 8# define WS2812_CHANNELS 4
9#else
10# define WS2812_CHANNELS 3
9#endif 11#endif
10 12
11#ifndef WS2812_PWM_DRIVER 13#ifndef WS2812_PWM_DRIVER
@@ -40,15 +42,15 @@
40// Default Push Pull 42// Default Push Pull
41#ifndef WS2812_EXTERNAL_PULLUP 43#ifndef WS2812_EXTERNAL_PULLUP
42# if defined(USE_GPIOV1) 44# if defined(USE_GPIOV1)
43# define WS2812_OUTPUT_MODE PAL_MODE_STM32_ALTERNATE_PUSHPULL 45# define WS2812_OUTPUT_MODE PAL_MODE_ALTERNATE_PUSHPULL
44# else 46# else
45# define WS2812_OUTPUT_MODE PAL_MODE_ALTERNATE(WS2812_PWM_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL | PAL_STM32_OSPEED_HIGHEST | PAL_STM32_PUPDR_FLOATING 47# define WS2812_OUTPUT_MODE PAL_MODE_ALTERNATE(WS2812_PWM_PAL_MODE) | PAL_OUTPUT_TYPE_PUSHPULL | PAL_OUTPUT_SPEED_HIGHEST | PAL_PUPDR_FLOATING
46# endif 48# endif
47#else 49#else
48# if defined(USE_GPIOV1) 50# if defined(USE_GPIOV1)
49# define WS2812_OUTPUT_MODE PAL_MODE_STM32_ALTERNATE_OPENDRAIN 51# define WS2812_OUTPUT_MODE PAL_MODE_ALTERNATE_OPENDRAIN
50# else 52# else
51# define WS2812_OUTPUT_MODE PAL_MODE_ALTERNATE(WS2812_PWM_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN | PAL_STM32_OSPEED_HIGHEST | PAL_STM32_PUPDR_FLOATING 53# define WS2812_OUTPUT_MODE PAL_MODE_ALTERNATE(WS2812_PWM_PAL_MODE) | PAL_OUTPUT_TYPE_OPENDRAIN | PAL_OUTPUT_SPEED_HIGHEST | PAL_PUPDR_FLOATING
52# endif 54# endif
53#endif 55#endif
54 56
@@ -59,7 +61,7 @@
59 61
60/* --- PRIVATE CONSTANTS ---------------------------------------------------- */ 62/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
61 63
62#define WS2812_PWM_FREQUENCY (STM32_SYSCLK / 2) /**< Clock frequency of PWM, must be valid with respect to system clock! */ 64#define WS2812_PWM_FREQUENCY (CPU_CLOCK / 2) /**< Clock frequency of PWM, must be valid with respect to system clock! */
63#define WS2812_PWM_PERIOD (WS2812_PWM_FREQUENCY / WS2812_PWM_TARGET_PERIOD) /**< Clock period in ticks. 1 / 800kHz = 1.25 uS (as per datasheet) */ 65#define WS2812_PWM_PERIOD (WS2812_PWM_FREQUENCY / WS2812_PWM_TARGET_PERIOD) /**< Clock period in ticks. 1 / 800kHz = 1.25 uS (as per datasheet) */
64 66
65/** 67/**
@@ -68,8 +70,9 @@
68 * The reset period for each frame is defined in WS2812_TRST_US. 70 * The reset period for each frame is defined in WS2812_TRST_US.
69 * Calculate the number of zeroes to add at the end assuming 1.25 uS/bit: 71 * Calculate the number of zeroes to add at the end assuming 1.25 uS/bit:
70 */ 72 */
73#define WS2812_COLOR_BITS (WS2812_CHANNELS * 8)
71#define WS2812_RESET_BIT_N (1000 * WS2812_TRST_US / 1250) 74#define WS2812_RESET_BIT_N (1000 * WS2812_TRST_US / 1250)
72#define WS2812_COLOR_BIT_N (RGBLED_NUM * 24) /**< Number of data bits */ 75#define WS2812_COLOR_BIT_N (RGBLED_NUM * WS2812_COLOR_BITS) /**< Number of data bits */
73#define WS2812_BIT_N (WS2812_COLOR_BIT_N + WS2812_RESET_BIT_N) /**< Total number of bits in a frame */ 76#define WS2812_BIT_N (WS2812_COLOR_BIT_N + WS2812_RESET_BIT_N) /**< Total number of bits in a frame */
74 77
75/** 78/**
@@ -114,7 +117,7 @@
114 * 117 *
115 * @return The bit index 118 * @return The bit index
116 */ 119 */
117#define WS2812_BIT(led, byte, bit) (24 * (led) + 8 * (byte) + (7 - (bit))) 120#define WS2812_BIT(led, byte, bit) (WS2812_COLOR_BITS * (led) + 8 * (byte) + (7 - (bit)))
118 121
119#if (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_GRB) 122#if (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_GRB)
120/** 123/**
@@ -228,6 +231,20 @@
228# define WS2812_BLUE_BIT(led, bit) WS2812_BIT((led), 0, (bit)) 231# define WS2812_BLUE_BIT(led, bit) WS2812_BIT((led), 0, (bit))
229#endif 232#endif
230 233
234#ifdef RGBW
235/**
236 * @brief Determine the index in @ref ws2812_frame_buffer "the frame buffer" of a given white bit
237 *
238 * @note The white byte is the last byte in the color packet
239 *
240 * @param[in] led: The led index [0, @ref WS2812_LED_N)
241 * @param[in] bit: The bit index [0, 7]
242 *
243 * @return The bit index
244 */
245# define WS2812_WHITE_BIT(led, bit) WS2812_BIT((led), 3, (bit))
246#endif
247
231/* --- PRIVATE VARIABLES ---------------------------------------------------- */ 248/* --- PRIVATE VARIABLES ---------------------------------------------------- */
232 249
233static uint32_t ws2812_frame_buffer[WS2812_BIT_N + 1]; /**< Buffer for a frame */ 250static uint32_t ws2812_frame_buffer[WS2812_BIT_N + 1]; /**< Buffer for a frame */
@@ -296,6 +313,17 @@ void ws2812_write_led(uint16_t led_number, uint8_t r, uint8_t g, uint8_t b) {
296 ws2812_frame_buffer[WS2812_BLUE_BIT(led_number, bit)] = ((b >> bit) & 0x01) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0; 313 ws2812_frame_buffer[WS2812_BLUE_BIT(led_number, bit)] = ((b >> bit) & 0x01) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0;
297 } 314 }
298} 315}
316void ws2812_write_led_rgbw(uint16_t led_number, uint8_t r, uint8_t g, uint8_t b, uint8_t w) {
317 // Write color to frame buffer
318 for (uint8_t bit = 0; bit < 8; bit++) {
319 ws2812_frame_buffer[WS2812_RED_BIT(led_number, bit)] = ((r >> bit) & 0x01) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0;
320 ws2812_frame_buffer[WS2812_GREEN_BIT(led_number, bit)] = ((g >> bit) & 0x01) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0;
321 ws2812_frame_buffer[WS2812_BLUE_BIT(led_number, bit)] = ((b >> bit) & 0x01) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0;
322#ifdef RGBW
323 ws2812_frame_buffer[WS2812_WHITE_BIT(led_number, bit)] = ((w >> bit) & 0x01) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0;
324#endif
325 }
326}
299 327
300// Setleds for standard RGB 328// Setleds for standard RGB
301void ws2812_setleds(LED_TYPE* ledarray, uint16_t leds) { 329void ws2812_setleds(LED_TYPE* ledarray, uint16_t leds) {
@@ -306,6 +334,10 @@ void ws2812_setleds(LED_TYPE* ledarray, uint16_t leds) {
306 } 334 }
307 335
308 for (uint16_t i = 0; i < leds; i++) { 336 for (uint16_t i = 0; i < leds; i++) {
337#ifdef RGBW
338 ws2812_write_led_rgbw(i, ledarray[i].r, ledarray[i].g, ledarray[i].b, ledarray[i].w);
339#else
309 ws2812_write_led(i, ledarray[i].r, ledarray[i].g, ledarray[i].b); 340 ws2812_write_led(i, ledarray[i].r, ledarray[i].g, ledarray[i].b);
341#endif
310 } 342 }
311} 343}
diff --git a/platforms/chibios/drivers/ws2812_spi.c b/platforms/chibios/drivers/ws2812_spi.c
index fe14b478a..62722f466 100644
--- a/platforms/chibios/drivers/ws2812_spi.c
+++ b/platforms/chibios/drivers/ws2812_spi.c
@@ -3,10 +3,6 @@
3 3
4/* Adapted from https://github.com/gamazeps/ws2812b-chibios-SPIDMA/ */ 4/* Adapted from https://github.com/gamazeps/ws2812b-chibios-SPIDMA/ */
5 5
6#ifdef RGBW
7# error "RGBW not supported"
8#endif
9
10// Define the spi your LEDs are plugged to here 6// Define the spi your LEDs are plugged to here
11#ifndef WS2812_SPI 7#ifndef WS2812_SPI
12# define WS2812_SPI SPID1 8# define WS2812_SPI SPID1
@@ -24,15 +20,15 @@
24// Default Push Pull 20// Default Push Pull
25#ifndef WS2812_EXTERNAL_PULLUP 21#ifndef WS2812_EXTERNAL_PULLUP
26# if defined(USE_GPIOV1) 22# if defined(USE_GPIOV1)
27# define WS2812_MOSI_OUTPUT_MODE PAL_MODE_STM32_ALTERNATE_PUSHPULL 23# define WS2812_MOSI_OUTPUT_MODE PAL_MODE_ALTERNATE_PUSHPULL
28# else 24# else
29# define WS2812_MOSI_OUTPUT_MODE PAL_MODE_ALTERNATE(WS2812_SPI_MOSI_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL 25# define WS2812_MOSI_OUTPUT_MODE PAL_MODE_ALTERNATE(WS2812_SPI_MOSI_PAL_MODE) | PAL_OUTPUT_TYPE_PUSHPULL
30# endif 26# endif
31#else 27#else
32# if defined(USE_GPIOV1) 28# if defined(USE_GPIOV1)
33# define WS2812_MOSI_OUTPUT_MODE PAL_MODE_STM32_ALTERNATE_OPENDRAIN 29# define WS2812_MOSI_OUTPUT_MODE PAL_MODE_ALTERNATE_OPENDRAIN
34# else 30# else
35# define WS2812_MOSI_OUTPUT_MODE PAL_MODE_ALTERNATE(WS2812_SPI_MOSI_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN 31# define WS2812_MOSI_OUTPUT_MODE PAL_MODE_ALTERNATE(WS2812_SPI_MOSI_PAL_MODE) | PAL_OUTPUT_TYPE_OPENDRAIN
36# endif 32# endif
37#endif 33#endif
38 34
@@ -68,14 +64,18 @@
68#endif 64#endif
69 65
70#if defined(USE_GPIOV1) 66#if defined(USE_GPIOV1)
71# define WS2812_SCK_OUTPUT_MODE PAL_MODE_STM32_ALTERNATE_PUSHPULL 67# define WS2812_SCK_OUTPUT_MODE PAL_MODE_ALTERNATE_PUSHPULL
72#else 68#else
73# define WS2812_SCK_OUTPUT_MODE PAL_MODE_ALTERNATE(WS2812_SPI_SCK_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL 69# define WS2812_SCK_OUTPUT_MODE PAL_MODE_ALTERNATE(WS2812_SPI_SCK_PAL_MODE) | PAL_OUTPUT_TYPE_PUSHPULL
74#endif 70#endif
75 71
76#define BYTES_FOR_LED_BYTE 4 72#define BYTES_FOR_LED_BYTE 4
77#define NB_COLORS 3 73#ifdef RGBW
78#define BYTES_FOR_LED (BYTES_FOR_LED_BYTE * NB_COLORS) 74# define WS2812_CHANNELS 4
75#else
76# define WS2812_CHANNELS 3
77#endif
78#define BYTES_FOR_LED (BYTES_FOR_LED_BYTE * WS2812_CHANNELS)
79#define DATA_SIZE (BYTES_FOR_LED * RGBLED_NUM) 79#define DATA_SIZE (BYTES_FOR_LED * RGBLED_NUM)
80#define RESET_SIZE (1000 * WS2812_TRST_US / (2 * 1250)) 80#define RESET_SIZE (1000 * WS2812_TRST_US / (2 * 1250))
81#define PREAMBLE_SIZE 4 81#define PREAMBLE_SIZE 4
@@ -116,6 +116,9 @@ static void set_led_color_rgb(LED_TYPE color, int pos) {
116 for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE + j] = get_protocol_eq(color.g, j); 116 for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE + j] = get_protocol_eq(color.g, j);
117 for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE * 2 + j] = get_protocol_eq(color.r, j); 117 for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE * 2 + j] = get_protocol_eq(color.r, j);
118#endif 118#endif
119#ifdef RGBW
120 for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE * 4 + j] = get_protocol_eq(color.w, j);
121#endif
119} 122}
120 123
121void ws2812_init(void) { 124void ws2812_init(void) {
diff --git a/platforms/chibios/eeprom_stm32.c b/platforms/chibios/eeprom_stm32.c
new file mode 100644
index 000000000..acc6a4851
--- /dev/null
+++ b/platforms/chibios/eeprom_stm32.c
@@ -0,0 +1,687 @@
1/*
2 * This software is experimental and a work in progress.
3 * Under no circumstances should these files be used in relation to any critical system(s).
4 * Use of these files is at your own risk.
5 *
6 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
7 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
8 * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
9 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
10 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
11 * DEALINGS IN THE SOFTWARE.
12 *
13 * This files are free to use from http://engsta.com/stm32-flash-memory-eeprom-emulator/ by
14 * Artur F.
15 *
16 * Modifications for QMK and STM32F303 by Yiancar
17 * Modifications to add flash wear leveling by Ilya Zhuravlev
18 * Modifications to increase flash density by Don Kjer
19 */
20
21#include <stdio.h>
22#include <stdbool.h>
23#include "util.h"
24#include "debug.h"
25#include "eeprom_stm32.h"
26#include "flash_stm32.h"
27
28/*
29 * We emulate eeprom by writing a snapshot compacted view of eeprom contents,
30 * followed by a write log of any change since that snapshot:
31 *
32 * === SIMULATED EEPROM CONTENTS ===
33 *
34 * ┌─ Compacted ┬ Write Log ─┐
35 * │............│[BYTE][BYTE]│
36 * │FFFF....FFFF│[WRD0][WRD1]│
37 * │FFFFFFFFFFFF│[WORD][NEXT]│
38 * │....FFFFFFFF│[BYTE][WRD0]│
39 * ├────────────┼────────────┤
40 * └──PAGE_BASE │ │
41 * PAGE_LAST─┴─WRITE_BASE │
42 * WRITE_LAST ┘
43 *
44 * Compacted contents are the 1's complement of the actual EEPROM contents.
45 * e.g. An 'FFFF' represents a '0000' value.
46 *
47 * The size of the 'compacted' area is equal to the size of the 'emulated' eeprom.
48 * The size of the compacted-area and write log are configurable, and the combined
49 * size of Compacted + WriteLog is a multiple FEE_PAGE_SIZE, which is MCU dependent.
50 * Simulated Eeprom contents are located at the end of available flash space.
51 *
52 * The following configuration defines can be set:
53 *
54 * FEE_PAGE_COUNT # Total number of pages to use for eeprom simulation (Compact + Write log)
55 * FEE_DENSITY_BYTES # Size of simulated eeprom. (Defaults to half the space allocated by FEE_PAGE_COUNT)
56 * NOTE: The current implementation does not include page swapping,
57 * and FEE_DENSITY_BYTES will consume that amount of RAM as a cached view of actual EEPROM contents.
58 *
59 * The maximum size of FEE_DENSITY_BYTES is currently 16384. The write log size equals
60 * FEE_PAGE_COUNT * FEE_PAGE_SIZE - FEE_DENSITY_BYTES.
61 * The larger the write log, the less frequently the compacted area needs to be rewritten.
62 *
63 *
64 * *** General Algorithm ***
65 *
66 * During initialization:
67 * The contents of the Compacted-flash area are loaded and the 1's complement value
68 * is cached into memory (e.g. 0xFFFF in Flash represents 0x0000 in cache).
69 * Write log entries are processed until a 0xFFFF is reached.
70 * Each log entry updates a byte or word in the cache.
71 *
72 * During reads:
73 * EEPROM contents are given back directly from the cache in memory.
74 *
75 * During writes:
76 * The contents of the cache is updated first.
77 * If the Compacted-flash area corresponding to the write address is unprogrammed, the 1's complement of the value is written directly into Compacted-flash
78 * Otherwise:
79 * If the write log is full, erase both the Compacted-flash area and the Write log, then write cached contents to the Compacted-flash area.
80 * Otherwise a Write log entry is constructed and appended to the next free position in the Write log.
81 *
82 *
83 * *** Write Log Structure ***
84 *
85 * Write log entries allow for optimized byte writes to addresses below 128. Writing 0 or 1 words are also optimized when word-aligned.
86 *
87 * === WRITE LOG ENTRY FORMATS ===
88 *
89 * ╔═══ Byte-Entry ══╗
90 * ║0XXXXXXX║YYYYYYYY║
91 * ║ └──┬──┘║└──┬───┘║
92 * ║ Address║ Value ║
93 * ╚════════╩════════╝
94 * 0 <= Address < 0x80 (128)
95 *
96 * ╔ Word-Encoded 0 ╗
97 * ║100XXXXXXXXXXXXX║
98 * ║ │└─────┬─────┘║
99 * ║ │Address >> 1 ║
100 * ║ └── Value: 0 ║
101 * ╚════════════════╝
102 * 0 <= Address <= 0x3FFE (16382)
103 *
104 * ╔ Word-Encoded 1 ╗
105 * ║101XXXXXXXXXXXXX║
106 * ║ │└─────┬─────┘║
107 * ║ │Address >> 1 ║
108 * ║ └── Value: 1 ║
109 * ╚════════════════╝
110 * 0 <= Address <= 0x3FFE (16382)
111 *
112 * ╔═══ Reserved ═══╗
113 * ║110XXXXXXXXXXXXX║
114 * ╚════════════════╝
115 *
116 * ╔═══════════ Word-Next ═══════════╗
117 * ║111XXXXXXXXXXXXX║YYYYYYYYYYYYYYYY║
118 * ║ └─────┬─────┘║└───────┬──────┘║
119 * ║(Address-128)>>1║ ~Value ║
120 * ╚════════════════╩════════════════╝
121 * ( 0 <= Address < 0x0080 (128): Reserved)
122 * 0x80 <= Address <= 0x3FFE (16382)
123 *
124 * Write Log entry ranges:
125 * 0x0000 ... 0x7FFF - Byte-Entry; address is (Entry & 0x7F00) >> 4; value is (Entry & 0xFF)
126 * 0x8000 ... 0x9FFF - Word-Encoded 0; address is (Entry & 0x1FFF) << 1; value is 0
127 * 0xA000 ... 0xBFFF - Word-Encoded 1; address is (Entry & 0x1FFF) << 1; value is 1
128 * 0xC000 ... 0xDFFF - Reserved
129 * 0xE000 ... 0xFFBF - Word-Next; address is (Entry & 0x1FFF) << 1 + 0x80; value is ~(Next_Entry)
130 * 0xFFC0 ... 0xFFFE - Reserved
131 * 0xFFFF - Unprogrammed
132 *
133 */
134
135#include "eeprom_stm32_defs.h"
136#if !defined(FEE_PAGE_SIZE) || !defined(FEE_PAGE_COUNT) || !defined(FEE_MCU_FLASH_SIZE) || !defined(FEE_PAGE_BASE_ADDRESS)
137# error "not implemented."
138#endif
139
140/* These bits are used for optimizing encoding of bytes, 0 and 1 */
141#define FEE_WORD_ENCODING 0x8000
142#define FEE_VALUE_NEXT 0x6000
143#define FEE_VALUE_RESERVED 0x4000
144#define FEE_VALUE_ENCODED 0x2000
145#define FEE_BYTE_RANGE 0x80
146
147/* Addressable range 16KByte: 0 <-> (0x1FFF << 1) */
148#define FEE_ADDRESS_MAX_SIZE 0x4000
149
150/* Flash word value after erase */
151#define FEE_EMPTY_WORD ((uint16_t)0xFFFF)
152
153/* Size of combined compacted eeprom and write log pages */
154#define FEE_DENSITY_MAX_SIZE (FEE_PAGE_COUNT * FEE_PAGE_SIZE)
155
156#ifndef FEE_MCU_FLASH_SIZE_IGNORE_CHECK /* *TODO: Get rid of this check */
157# if FEE_DENSITY_MAX_SIZE > (FEE_MCU_FLASH_SIZE * 1024)
158# pragma message STR(FEE_DENSITY_MAX_SIZE) " > " STR(FEE_MCU_FLASH_SIZE * 1024)
159# error emulated eeprom: FEE_DENSITY_MAX_SIZE is greater than available flash size
160# endif
161#endif
162
163/* Size of emulated eeprom */
164#ifdef FEE_DENSITY_BYTES
165# if (FEE_DENSITY_BYTES > FEE_DENSITY_MAX_SIZE)
166# pragma message STR(FEE_DENSITY_BYTES) " > " STR(FEE_DENSITY_MAX_SIZE)
167# error emulated eeprom: FEE_DENSITY_BYTES exceeds FEE_DENSITY_MAX_SIZE
168# endif
169# if (FEE_DENSITY_BYTES == FEE_DENSITY_MAX_SIZE)
170# pragma message STR(FEE_DENSITY_BYTES) " == " STR(FEE_DENSITY_MAX_SIZE)
171# warning emulated eeprom: FEE_DENSITY_BYTES leaves no room for a write log. This will greatly increase the flash wear rate!
172# endif
173# if FEE_DENSITY_BYTES > FEE_ADDRESS_MAX_SIZE
174# pragma message STR(FEE_DENSITY_BYTES) " > " STR(FEE_ADDRESS_MAX_SIZE)
175# error emulated eeprom: FEE_DENSITY_BYTES is greater than FEE_ADDRESS_MAX_SIZE allows
176# endif
177# if ((FEE_DENSITY_BYTES) % 2) == 1
178# error emulated eeprom: FEE_DENSITY_BYTES must be even
179# endif
180#else
181/* Default to half of allocated space used for emulated eeprom, half for write log */
182# define FEE_DENSITY_BYTES (FEE_PAGE_COUNT * FEE_PAGE_SIZE / 2)
183#endif
184
185/* Size of write log */
186#ifdef FEE_WRITE_LOG_BYTES
187# if ((FEE_DENSITY_BYTES + FEE_WRITE_LOG_BYTES) > FEE_DENSITY_MAX_SIZE)
188# pragma message STR(FEE_DENSITY_BYTES) " + " STR(FEE_WRITE_LOG_BYTES) " > " STR(FEE_DENSITY_MAX_SIZE)
189# error emulated eeprom: FEE_WRITE_LOG_BYTES exceeds remaining FEE_DENSITY_MAX_SIZE
190# endif
191# if ((FEE_WRITE_LOG_BYTES) % 2) == 1
192# error emulated eeprom: FEE_WRITE_LOG_BYTES must be even
193# endif
194#else
195/* Default to use all remaining space */
196# define FEE_WRITE_LOG_BYTES (FEE_PAGE_COUNT * FEE_PAGE_SIZE - FEE_DENSITY_BYTES)
197#endif
198
199/* Start of the emulated eeprom compacted flash area */
200#define FEE_COMPACTED_BASE_ADDRESS FEE_PAGE_BASE_ADDRESS
201/* End of the emulated eeprom compacted flash area */
202#define FEE_COMPACTED_LAST_ADDRESS (FEE_COMPACTED_BASE_ADDRESS + FEE_DENSITY_BYTES)
203/* Start of the emulated eeprom write log */
204#define FEE_WRITE_LOG_BASE_ADDRESS FEE_COMPACTED_LAST_ADDRESS
205/* End of the emulated eeprom write log */
206#define FEE_WRITE_LOG_LAST_ADDRESS (FEE_WRITE_LOG_BASE_ADDRESS + FEE_WRITE_LOG_BYTES)
207
208#if defined(DYNAMIC_KEYMAP_EEPROM_MAX_ADDR) && (DYNAMIC_KEYMAP_EEPROM_MAX_ADDR >= FEE_DENSITY_BYTES)
209# error emulated eeprom: DYNAMIC_KEYMAP_EEPROM_MAX_ADDR is greater than the FEE_DENSITY_BYTES available
210#endif
211
212/* In-memory contents of emulated eeprom for faster access */
213/* *TODO: Implement page swapping */
214static uint16_t WordBuf[FEE_DENSITY_BYTES / 2];
215static uint8_t *DataBuf = (uint8_t *)WordBuf;
216
217/* Pointer to the first available slot within the write log */
218static uint16_t *empty_slot;
219
220// #define DEBUG_EEPROM_OUTPUT
221
222/*
223 * Debug print utils
224 */
225
226#if defined(DEBUG_EEPROM_OUTPUT)
227
228# define debug_eeprom debug_enable
229# define eeprom_println(s) println(s)
230# define eeprom_printf(fmt, ...) xprintf(fmt, ##__VA_ARGS__);
231
232#else /* NO_DEBUG */
233
234# define debug_eeprom false
235# define eeprom_println(s)
236# define eeprom_printf(fmt, ...)
237
238#endif /* NO_DEBUG */
239
240void print_eeprom(void) {
241#ifndef NO_DEBUG
242 int empty_rows = 0;
243 for (uint16_t i = 0; i < FEE_DENSITY_BYTES; i++) {
244 if (i % 16 == 0) {
245 if (i >= FEE_DENSITY_BYTES - 16) {
246 /* Make sure we display the last row */
247 empty_rows = 0;
248 }
249 /* Check if this row is uninitialized */
250 ++empty_rows;
251 for (uint16_t j = 0; j < 16; j++) {
252 if (DataBuf[i + j]) {
253 empty_rows = 0;
254 break;
255 }
256 }
257 if (empty_rows > 1) {
258 /* Repeat empty row */
259 if (empty_rows == 2) {
260 /* Only display the first repeat empty row */
261 println("*");
262 }
263 i += 15;
264 continue;
265 }
266 xprintf("%04x", i);
267 }
268 if (i % 8 == 0) print(" ");
269
270 xprintf(" %02x", DataBuf[i]);
271 if ((i + 1) % 16 == 0) {
272 println("");
273 }
274 }
275#endif
276}
277
278uint16_t EEPROM_Init(void) {
279 /* Load emulated eeprom contents from compacted flash into memory */
280 uint16_t *src = (uint16_t *)FEE_COMPACTED_BASE_ADDRESS;
281 uint16_t *dest = (uint16_t *)DataBuf;
282 for (; src < (uint16_t *)FEE_COMPACTED_LAST_ADDRESS; ++src, ++dest) {
283 *dest = ~*src;
284 }
285
286 if (debug_eeprom) {
287 println("EEPROM_Init Compacted Pages:");
288 print_eeprom();
289 println("EEPROM_Init Write Log:");
290 }
291
292 /* Replay write log */
293 uint16_t *log_addr;
294 for (log_addr = (uint16_t *)FEE_WRITE_LOG_BASE_ADDRESS; log_addr < (uint16_t *)FEE_WRITE_LOG_LAST_ADDRESS; ++log_addr) {
295 uint16_t address = *log_addr;
296 if (address == FEE_EMPTY_WORD) {
297 break;
298 }
299 /* Check for lowest 128-bytes optimization */
300 if (!(address & FEE_WORD_ENCODING)) {
301 uint8_t bvalue = (uint8_t)address;
302 address >>= 8;
303 DataBuf[address] = bvalue;
304 eeprom_printf("DataBuf[0x%02x] = 0x%02x;\n", address, bvalue);
305 } else {
306 uint16_t wvalue;
307 /* Check if value is in next word */
308 if ((address & FEE_VALUE_NEXT) == FEE_VALUE_NEXT) {
309 /* Read value from next word */
310 if (++log_addr >= (uint16_t *)FEE_WRITE_LOG_LAST_ADDRESS) {
311 break;
312 }
313 wvalue = ~*log_addr;
314 if (!wvalue) {
315 eeprom_printf("Incomplete write at log_addr: 0x%04x;\n", (uint32_t)log_addr);
316 /* Possibly incomplete write. Ignore and continue */
317 continue;
318 }
319 address &= 0x1FFF;
320 address <<= 1;
321 /* Writes to addresses less than 128 are byte log entries */
322 address += FEE_BYTE_RANGE;
323 } else {
324 /* Reserved for future use */
325 if (address & FEE_VALUE_RESERVED) {
326 eeprom_printf("Reserved encoded value at log_addr: 0x%04x;\n", (uint32_t)log_addr);
327 continue;
328 }
329 /* Optimization for 0 or 1 values. */
330 wvalue = (address & FEE_VALUE_ENCODED) >> 13;
331 address &= 0x1FFF;
332 address <<= 1;
333 }
334 if (address < FEE_DENSITY_BYTES) {
335 eeprom_printf("DataBuf[0x%04x] = 0x%04x;\n", address, wvalue);
336 *(uint16_t *)(&DataBuf[address]) = wvalue;
337 } else {
338 eeprom_printf("DataBuf[0x%04x] cannot be set to 0x%04x [BAD ADDRESS]\n", address, wvalue);
339 }
340 }
341 }
342
343 empty_slot = log_addr;
344
345 if (debug_eeprom) {
346 println("EEPROM_Init Final DataBuf:");
347 print_eeprom();
348 }
349
350 return FEE_DENSITY_BYTES;
351}
352
353/* Clear flash contents (doesn't touch in-memory DataBuf) */
354static void eeprom_clear(void) {
355 FLASH_Unlock();
356
357 for (uint16_t page_num = 0; page_num < FEE_PAGE_COUNT; ++page_num) {
358 eeprom_printf("FLASH_ErasePage(0x%04x)\n", (uint32_t)(FEE_PAGE_BASE_ADDRESS + (page_num * FEE_PAGE_SIZE)));
359 FLASH_ErasePage(FEE_PAGE_BASE_ADDRESS + (page_num * FEE_PAGE_SIZE));
360 }
361
362 FLASH_Lock();
363
364 empty_slot = (uint16_t *)FEE_WRITE_LOG_BASE_ADDRESS;
365 eeprom_printf("eeprom_clear empty_slot: 0x%08x\n", (uint32_t)empty_slot);
366}
367
368/* Erase emulated eeprom */
369void EEPROM_Erase(void) {
370 eeprom_println("EEPROM_Erase");
371 /* Erase compacted pages and write log */
372 eeprom_clear();
373 /* re-initialize to reset DataBuf */
374 EEPROM_Init();
375}
376
377/* Compact write log */
378static uint8_t eeprom_compact(void) {
379 /* Erase compacted pages and write log */
380 eeprom_clear();
381
382 FLASH_Unlock();
383
384 FLASH_Status final_status = FLASH_COMPLETE;
385
386 /* Write emulated eeprom contents from memory to compacted flash */
387 uint16_t *src = (uint16_t *)DataBuf;
388 uintptr_t dest = FEE_COMPACTED_BASE_ADDRESS;
389 uint16_t value;
390 for (; dest < FEE_COMPACTED_LAST_ADDRESS; ++src, dest += 2) {
391 value = *src;
392 if (value) {
393 eeprom_printf("FLASH_ProgramHalfWord(0x%04x, 0x%04x)\n", (uint32_t)dest, ~value);
394 FLASH_Status status = FLASH_ProgramHalfWord(dest, ~value);
395 if (status != FLASH_COMPLETE) final_status = status;
396 }
397 }
398
399 FLASH_Lock();
400
401 if (debug_eeprom) {
402 println("eeprom_compacted:");
403 print_eeprom();
404 }
405
406 return final_status;
407}
408
409static uint8_t eeprom_write_direct_entry(uint16_t Address) {
410 /* Check if we can just write this directly to the compacted flash area */
411 uintptr_t directAddress = FEE_COMPACTED_BASE_ADDRESS + (Address & 0xFFFE);
412 if (*(uint16_t *)directAddress == FEE_EMPTY_WORD) {
413 /* Write the value directly to the compacted area without a log entry */
414 uint16_t value = ~*(uint16_t *)(&DataBuf[Address & 0xFFFE]);
415 /* Early exit if a write isn't needed */
416 if (value == FEE_EMPTY_WORD) return FLASH_COMPLETE;
417
418 FLASH_Unlock();
419
420 eeprom_printf("FLASH_ProgramHalfWord(0x%08x, 0x%04x) [DIRECT]\n", (uint32_t)directAddress, value);
421 FLASH_Status status = FLASH_ProgramHalfWord(directAddress, value);
422
423 FLASH_Lock();
424 return status;
425 }
426 return 0;
427}
428
429static uint8_t eeprom_write_log_word_entry(uint16_t Address) {
430 FLASH_Status final_status = FLASH_COMPLETE;
431
432 uint16_t value = *(uint16_t *)(&DataBuf[Address]);
433 eeprom_printf("eeprom_write_log_word_entry(0x%04x): 0x%04x\n", Address, value);
434
435 /* MSB signifies the lowest 128-byte optimization is not in effect */
436 uint16_t encoding = FEE_WORD_ENCODING;
437 uint8_t entry_size;
438 if (value <= 1) {
439 encoding |= value << 13;
440 entry_size = 2;
441 } else {
442 encoding |= FEE_VALUE_NEXT;
443 entry_size = 4;
444 /* Writes to addresses less than 128 are byte log entries */
445 Address -= FEE_BYTE_RANGE;
446 }
447
448 /* if we can't find an empty spot, we must compact emulated eeprom */
449 if (empty_slot > (uint16_t *)(FEE_WRITE_LOG_LAST_ADDRESS - entry_size)) {
450 /* compact the write log into the compacted flash area */
451 return eeprom_compact();
452 }
453
454 /* Word log writes should be word-aligned. Take back a bit */
455 Address >>= 1;
456 Address |= encoding;
457
458 /* ok we found a place let's write our data */
459 FLASH_Unlock();
460
461 /* address */
462 eeprom_printf("FLASH_ProgramHalfWord(0x%08x, 0x%04x)\n", (uint32_t)empty_slot, Address);
463 final_status = FLASH_ProgramHalfWord((uintptr_t)empty_slot++, Address);
464
465 /* value */
466 if (encoding == (FEE_WORD_ENCODING | FEE_VALUE_NEXT)) {
467 eeprom_printf("FLASH_ProgramHalfWord(0x%08x, 0x%04x)\n", (uint32_t)empty_slot, ~value);
468 FLASH_Status status = FLASH_ProgramHalfWord((uintptr_t)empty_slot++, ~value);
469 if (status != FLASH_COMPLETE) final_status = status;
470 }
471
472 FLASH_Lock();
473
474 return final_status;
475}
476
477static uint8_t eeprom_write_log_byte_entry(uint16_t Address) {
478 eeprom_printf("eeprom_write_log_byte_entry(0x%04x): 0x%02x\n", Address, DataBuf[Address]);
479
480 /* if couldn't find an empty spot, we must compact emulated eeprom */
481 if (empty_slot >= (uint16_t *)FEE_WRITE_LOG_LAST_ADDRESS) {
482 /* compact the write log into the compacted flash area */
483 return eeprom_compact();
484 }
485
486 /* ok we found a place let's write our data */
487 FLASH_Unlock();
488
489 /* Pack address and value into the same word */
490 uint16_t value = (Address << 8) | DataBuf[Address];
491
492 /* write to flash */
493 eeprom_printf("FLASH_ProgramHalfWord(0x%08x, 0x%04x)\n", (uint32_t)empty_slot, value);
494 FLASH_Status status = FLASH_ProgramHalfWord((uintptr_t)empty_slot++, value);
495
496 FLASH_Lock();
497
498 return status;
499}
500
501uint8_t EEPROM_WriteDataByte(uint16_t Address, uint8_t DataByte) {
502 /* if the address is out-of-bounds, do nothing */
503 if (Address >= FEE_DENSITY_BYTES) {
504 eeprom_printf("EEPROM_WriteDataByte(0x%04x, 0x%02x) [BAD ADDRESS]\n", Address, DataByte);
505 return FLASH_BAD_ADDRESS;
506 }
507
508 /* if the value is the same, don't bother writing it */
509 if (DataBuf[Address] == DataByte) {
510 eeprom_printf("EEPROM_WriteDataByte(0x%04x, 0x%02x) [SKIP SAME]\n", Address, DataByte);
511 return 0;
512 }
513
514 /* keep DataBuf cache in sync */
515 DataBuf[Address] = DataByte;
516 eeprom_printf("EEPROM_WriteDataByte DataBuf[0x%04x] = 0x%02x\n", Address, DataBuf[Address]);
517
518 /* perform the write into flash memory */
519 /* First, attempt to write directly into the compacted flash area */
520 FLASH_Status status = eeprom_write_direct_entry(Address);
521 if (!status) {
522 /* Otherwise append to the write log */
523 if (Address < FEE_BYTE_RANGE) {
524 status = eeprom_write_log_byte_entry(Address);
525 } else {
526 status = eeprom_write_log_word_entry(Address & 0xFFFE);
527 }
528 }
529 if (status != 0 && status != FLASH_COMPLETE) {
530 eeprom_printf("EEPROM_WriteDataByte [STATUS == %d]\n", status);
531 }
532 return status;
533}
534
535uint8_t EEPROM_WriteDataWord(uint16_t Address, uint16_t DataWord) {
536 /* if the address is out-of-bounds, do nothing */
537 if (Address >= FEE_DENSITY_BYTES) {
538 eeprom_printf("EEPROM_WriteDataWord(0x%04x, 0x%04x) [BAD ADDRESS]\n", Address, DataWord);
539 return FLASH_BAD_ADDRESS;
540 }
541
542 /* Check for word alignment */
543 FLASH_Status final_status = FLASH_COMPLETE;
544 if (Address % 2) {
545 final_status = EEPROM_WriteDataByte(Address, DataWord);
546 FLASH_Status status = EEPROM_WriteDataByte(Address + 1, DataWord >> 8);
547 if (status != FLASH_COMPLETE) final_status = status;
548 if (final_status != 0 && final_status != FLASH_COMPLETE) {
549 eeprom_printf("EEPROM_WriteDataWord [STATUS == %d]\n", final_status);
550 }
551 return final_status;
552 }
553
554 /* if the value is the same, don't bother writing it */
555 uint16_t oldValue = *(uint16_t *)(&DataBuf[Address]);
556 if (oldValue == DataWord) {
557 eeprom_printf("EEPROM_WriteDataWord(0x%04x, 0x%04x) [SKIP SAME]\n", Address, DataWord);
558 return 0;
559 }
560
561 /* keep DataBuf cache in sync */
562 *(uint16_t *)(&DataBuf[Address]) = DataWord;
563 eeprom_printf("EEPROM_WriteDataWord DataBuf[0x%04x] = 0x%04x\n", Address, *(uint16_t *)(&DataBuf[Address]));
564
565 /* perform the write into flash memory */
566 /* First, attempt to write directly into the compacted flash area */
567 final_status = eeprom_write_direct_entry(Address);
568 if (!final_status) {
569 /* Otherwise append to the write log */
570 /* Check if we need to fall back to byte write */
571 if (Address < FEE_BYTE_RANGE) {
572 final_status = FLASH_COMPLETE;
573 /* Only write a byte if it has changed */
574 if ((uint8_t)oldValue != (uint8_t)DataWord) {
575 final_status = eeprom_write_log_byte_entry(Address);
576 }
577 FLASH_Status status = FLASH_COMPLETE;
578 /* Only write a byte if it has changed */
579 if ((oldValue >> 8) != (DataWord >> 8)) {
580 status = eeprom_write_log_byte_entry(Address + 1);
581 }
582 if (status != FLASH_COMPLETE) final_status = status;
583 } else {
584 final_status = eeprom_write_log_word_entry(Address);
585 }
586 }
587 if (final_status != 0 && final_status != FLASH_COMPLETE) {
588 eeprom_printf("EEPROM_WriteDataWord [STATUS == %d]\n", final_status);
589 }
590 return final_status;
591}
592
593uint8_t EEPROM_ReadDataByte(uint16_t Address) {
594 uint8_t DataByte = 0xFF;
595
596 if (Address < FEE_DENSITY_BYTES) {
597 DataByte = DataBuf[Address];
598 }
599
600 eeprom_printf("EEPROM_ReadDataByte(0x%04x): 0x%02x\n", Address, DataByte);
601
602 return DataByte;
603}
604
605uint16_t EEPROM_ReadDataWord(uint16_t Address) {
606 uint16_t DataWord = 0xFFFF;
607
608 if (Address < FEE_DENSITY_BYTES - 1) {
609 /* Check word alignment */
610 if (Address % 2) {
611 DataWord = DataBuf[Address] | (DataBuf[Address + 1] << 8);
612 } else {
613 DataWord = *(uint16_t *)(&DataBuf[Address]);
614 }
615 }
616
617 eeprom_printf("EEPROM_ReadDataWord(0x%04x): 0x%04x\n", Address, DataWord);
618
619 return DataWord;
620}
621
622/*****************************************************************************
623 * Bind to eeprom_driver.c
624 *******************************************************************************/
625void eeprom_driver_init(void) { EEPROM_Init(); }
626
627void eeprom_driver_erase(void) { EEPROM_Erase(); }
628
629void eeprom_read_block(void *buf, const void *addr, size_t len) {
630 const uint8_t *src = (const uint8_t *)addr;
631 uint8_t * dest = (uint8_t *)buf;
632
633 /* Check word alignment */
634 if (len && (uintptr_t)src % 2) {
635 /* Read the unaligned first byte */
636 *dest++ = EEPROM_ReadDataByte((const uintptr_t)src++);
637 --len;
638 }
639
640 uint16_t value;
641 bool aligned = ((uintptr_t)dest % 2 == 0);
642 while (len > 1) {
643 value = EEPROM_ReadDataWord((const uintptr_t)((uint16_t *)src));
644 if (aligned) {
645 *(uint16_t *)dest = value;
646 dest += 2;
647 } else {
648 *dest++ = value;
649 *dest++ = value >> 8;
650 }
651 src += 2;
652 len -= 2;
653 }
654 if (len) {
655 *dest = EEPROM_ReadDataByte((const uintptr_t)src);
656 }
657}
658
659void eeprom_write_block(const void *buf, void *addr, size_t len) {
660 uint8_t * dest = (uint8_t *)addr;
661 const uint8_t *src = (const uint8_t *)buf;
662
663 /* Check word alignment */
664 if (len && (uintptr_t)dest % 2) {
665 /* Write the unaligned first byte */
666 EEPROM_WriteDataByte((uintptr_t)dest++, *src++);
667 --len;
668 }
669
670 uint16_t value;
671 bool aligned = ((uintptr_t)src % 2 == 0);
672 while (len > 1) {
673 if (aligned) {
674 value = *(uint16_t *)src;
675 } else {
676 value = *(uint8_t *)src | (*(uint8_t *)(src + 1) << 8);
677 }
678 EEPROM_WriteDataWord((uintptr_t)((uint16_t *)dest), value);
679 dest += 2;
680 src += 2;
681 len -= 2;
682 }
683
684 if (len) {
685 EEPROM_WriteDataByte((uintptr_t)dest, *src);
686 }
687}
diff --git a/platforms/chibios/eeprom_stm32.h b/platforms/chibios/eeprom_stm32.h
new file mode 100644
index 000000000..8fcfb556b
--- /dev/null
+++ b/platforms/chibios/eeprom_stm32.h
@@ -0,0 +1,33 @@
1/*
2 * This software is experimental and a work in progress.
3 * Under no circumstances should these files be used in relation to any critical system(s).
4 * Use of these files is at your own risk.
5 *
6 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
7 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
8 * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
9 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
10 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
11 * DEALINGS IN THE SOFTWARE.
12 *
13 * This files are free to use from http://engsta.com/stm32-flash-memory-eeprom-emulator/ by
14 * Artur F.
15 *
16 * Modifications for QMK and STM32F303 by Yiancar
17 *
18 * This library assumes 8-bit data locations. To add a new MCU, please provide the flash
19 * page size and the total flash size in Kb. The number of available pages must be a multiple
20 * of 2. Only half of the pages account for the total EEPROM size.
21 * This library also assumes that the pages are not used by the firmware.
22 */
23
24#pragma once
25
26uint16_t EEPROM_Init(void);
27void EEPROM_Erase(void);
28uint8_t EEPROM_WriteDataByte(uint16_t Address, uint8_t DataByte);
29uint8_t EEPROM_WriteDataWord(uint16_t Address, uint16_t DataWord);
30uint8_t EEPROM_ReadDataByte(uint16_t Address);
31uint16_t EEPROM_ReadDataWord(uint16_t Address);
32
33void print_eeprom(void);
diff --git a/platforms/chibios/eeprom_stm32_defs.h b/platforms/chibios/eeprom_stm32_defs.h
new file mode 100644
index 000000000..66904f247
--- /dev/null
+++ b/platforms/chibios/eeprom_stm32_defs.h
@@ -0,0 +1,74 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#pragma once
17
18#include <hal.h>
19
20#if !defined(FEE_PAGE_SIZE) || !defined(FEE_PAGE_COUNT)
21# if defined(STM32F103xB) || defined(STM32F042x6) || defined(GD32VF103C8) || defined(GD32VF103CB)
22# ifndef FEE_PAGE_SIZE
23# define FEE_PAGE_SIZE 0x400 // Page size = 1KByte
24# endif
25# ifndef FEE_PAGE_COUNT
26# define FEE_PAGE_COUNT 2 // How many pages are used
27# endif
28# elif defined(STM32F103xE) || defined(STM32F303xC) || defined(STM32F072xB) || defined(STM32F070xB)
29# ifndef FEE_PAGE_SIZE
30# define FEE_PAGE_SIZE 0x800 // Page size = 2KByte
31# endif
32# ifndef FEE_PAGE_COUNT
33# define FEE_PAGE_COUNT 4 // How many pages are used
34# endif
35# elif defined(STM32F401xC) || defined(STM32F401xE) || defined(STM32F405xG) || defined(STM32F411xE)
36# ifndef FEE_PAGE_SIZE
37# define FEE_PAGE_SIZE 0x4000 // Page size = 16KByte
38# endif
39# ifndef FEE_PAGE_COUNT
40# define FEE_PAGE_COUNT 1 // How many pages are used
41# endif
42# endif
43#endif
44
45#if !defined(FEE_MCU_FLASH_SIZE)
46# if defined(STM32F042x6)
47# define FEE_MCU_FLASH_SIZE 32 // Size in Kb
48# elif defined(GD32VF103C8)
49# define FEE_MCU_FLASH_SIZE 64 // Size in Kb
50# elif defined(STM32F103xB) || defined(STM32F072xB) || defined(STM32F070xB) || defined(GD32VF103CB)
51# define FEE_MCU_FLASH_SIZE 128 // Size in Kb
52# elif defined(STM32F303xC) || defined(STM32F401xC)
53# define FEE_MCU_FLASH_SIZE 256 // Size in Kb
54# elif defined(STM32F103xE) || defined(STM32F401xE) || defined(STM32F411xE)
55# define FEE_MCU_FLASH_SIZE 512 // Size in Kb
56# elif defined(STM32F405xG)
57# define FEE_MCU_FLASH_SIZE 1024 // Size in Kb
58# endif
59#endif
60
61/* Start of the emulated eeprom */
62#if !defined(FEE_PAGE_BASE_ADDRESS)
63# if defined(STM32F401xC) || defined(STM32F401xE) || defined(STM32F405xG) || defined(STM32F411xE)
64# ifndef FEE_PAGE_BASE_ADDRESS
65# define FEE_PAGE_BASE_ADDRESS 0x08004000 // bodge to force 2nd 16k page
66# endif
67# else
68# ifndef FEE_FLASH_BASE
69# define FEE_FLASH_BASE 0x8000000
70# endif
71/* Default to end of flash */
72# define FEE_PAGE_BASE_ADDRESS ((uintptr_t)(FEE_FLASH_BASE) + FEE_MCU_FLASH_SIZE * 1024 - (FEE_PAGE_COUNT * FEE_PAGE_SIZE))
73# endif
74#endif
diff --git a/platforms/chibios/eeprom_teensy.c b/platforms/chibios/eeprom_teensy.c
new file mode 100644
index 000000000..97da6f9e1
--- /dev/null
+++ b/platforms/chibios/eeprom_teensy.c
@@ -0,0 +1,795 @@
1#include <ch.h>
2#include <hal.h>
3
4#include "eeconfig.h"
5
6/*************************************/
7/* Hardware backend */
8/* */
9/* Code from PJRC/Teensyduino */
10/*************************************/
11
12/* Teensyduino Core Library
13 * http://www.pjrc.com/teensy/
14 * Copyright (c) 2013 PJRC.COM, LLC.
15 *
16 * Permission is hereby granted, free of charge, to any person obtaining
17 * a copy of this software and associated documentation files (the
18 * "Software"), to deal in the Software without restriction, including
19 * without limitation the rights to use, copy, modify, merge, publish,
20 * distribute, sublicense, and/or sell copies of the Software, and to
21 * permit persons to whom the Software is furnished to do so, subject to
22 * the following conditions:
23 *
24 * 1. The above copyright notice and this permission notice shall be
25 * included in all copies or substantial portions of the Software.
26 *
27 * 2. If the Software is incorporated into a build system that allows
28 * selection among a list of target devices, then similar target
29 * devices manufactured by PJRC.COM must be included in the list of
30 * target devices and selectable in the same manner.
31 *
32 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
33 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
34 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
35 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
36 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
37 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
38 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39 * SOFTWARE.
40 */
41
42#define SMC_PMSTAT_RUN ((uint8_t)0x01)
43#define SMC_PMSTAT_HSRUN ((uint8_t)0x80)
44
45#define F_CPU KINETIS_SYSCLK_FREQUENCY
46
47static inline int kinetis_hsrun_disable(void) {
48#if defined(MK66F18)
49 if (SMC->PMSTAT == SMC_PMSTAT_HSRUN) {
50// First, reduce the CPU clock speed, but do not change
51// the peripheral speed (F_BUS). Serial1 & Serial2 baud
52// rates will be impacted, but most other peripherals
53// will continue functioning at the same speed.
54# if F_CPU == 256000000 && F_BUS == 64000000
55 SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(1, 3, 1, 7); // TODO: TEST
56# elif F_CPU == 256000000 && F_BUS == 128000000
57 SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(1, 1, 1, 7); // TODO: TEST
58# elif F_CPU == 240000000 && F_BUS == 60000000
59 SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(1, 3, 1, 7); // ok
60# elif F_CPU == 240000000 && F_BUS == 80000000
61 SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(2, 2, 2, 8); // ok
62# elif F_CPU == 240000000 && F_BUS == 120000000
63 SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(1, 1, 1, 7); // ok
64# elif F_CPU == 216000000 && F_BUS == 54000000
65 SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(1, 3, 1, 7); // ok
66# elif F_CPU == 216000000 && F_BUS == 72000000
67 SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(2, 2, 2, 8); // ok
68# elif F_CPU == 216000000 && F_BUS == 108000000
69 SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(1, 1, 1, 7); // ok
70# elif F_CPU == 192000000 && F_BUS == 48000000
71 SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(1, 3, 1, 7); // ok
72# elif F_CPU == 192000000 && F_BUS == 64000000
73 SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(2, 2, 2, 8); // ok
74# elif F_CPU == 192000000 && F_BUS == 96000000
75 SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(1, 1, 1, 7); // ok
76# elif F_CPU == 180000000 && F_BUS == 60000000
77 SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(2, 2, 2, 8); // ok
78# elif F_CPU == 180000000 && F_BUS == 90000000
79 SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(1, 1, 1, 7); // ok
80# elif F_CPU == 168000000 && F_BUS == 56000000
81 SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(2, 2, 2, 5); // ok
82# elif F_CPU == 144000000 && F_BUS == 48000000
83 SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(2, 2, 2, 5); // ok
84# elif F_CPU == 144000000 && F_BUS == 72000000
85 SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(1, 1, 1, 5); // ok
86# elif F_CPU == 120000000 && F_BUS == 60000000
87 SIM->CLKDIV1 = SIM_CLKDIV1_OUTDIV1(KINETIS_CLKDIV1_OUTDIV1 - 1) | SIM_CLKDIV1_OUTDIV2(KINETIS_CLKDIV1_OUTDIV2 - 1) |
88# if defined(MK66F18)
89 SIM_CLKDIV1_OUTDIV3(KINETIS_CLKDIV1_OUTDIV3 - 1) |
90# endif
91 SIM_CLKDIV1_OUTDIV4(KINETIS_CLKDIV1_OUTDIV4 - 1);
92# else
93 return 0;
94# endif
95 // Then turn off HSRUN mode
96 SMC->PMCTRL = SMC_PMCTRL_RUNM_SET(0);
97 while (SMC->PMSTAT == SMC_PMSTAT_HSRUN)
98 ; // wait
99 return 1;
100 }
101#endif
102 return 0;
103}
104
105static inline int kinetis_hsrun_enable(void) {
106#if defined(MK66F18)
107 if (SMC->PMSTAT == SMC_PMSTAT_RUN) {
108 // Turn HSRUN mode on
109 SMC->PMCTRL = SMC_PMCTRL_RUNM_SET(3);
110 while (SMC->PMSTAT != SMC_PMSTAT_HSRUN) {
111 ;
112 } // wait
113// Then configure clock for full speed
114# if F_CPU == 256000000 && F_BUS == 64000000
115 SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 3, 0, 7);
116# elif F_CPU == 256000000 && F_BUS == 128000000
117 SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 1, 0, 7);
118# elif F_CPU == 240000000 && F_BUS == 60000000
119 SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 3, 0, 7);
120# elif F_CPU == 240000000 && F_BUS == 80000000
121 SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 2, 0, 7);
122# elif F_CPU == 240000000 && F_BUS == 120000000
123 SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 1, 0, 7);
124# elif F_CPU == 216000000 && F_BUS == 54000000
125 SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 3, 0, 7);
126# elif F_CPU == 216000000 && F_BUS == 72000000
127 SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 2, 0, 7);
128# elif F_CPU == 216000000 && F_BUS == 108000000
129 SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 1, 0, 7);
130# elif F_CPU == 192000000 && F_BUS == 48000000
131 SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 3, 0, 6);
132# elif F_CPU == 192000000 && F_BUS == 64000000
133 SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 2, 0, 6);
134# elif F_CPU == 192000000 && F_BUS == 96000000
135 SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 1, 0, 6);
136# elif F_CPU == 180000000 && F_BUS == 60000000
137 SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 2, 0, 6);
138# elif F_CPU == 180000000 && F_BUS == 90000000
139 SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 1, 0, 6);
140# elif F_CPU == 168000000 && F_BUS == 56000000
141 SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 2, 0, 5);
142# elif F_CPU == 144000000 && F_BUS == 48000000
143 SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 2, 0, 4);
144# elif F_CPU == 144000000 && F_BUS == 72000000
145 SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIVS(0, 1, 0, 4);
146# elif F_CPU == 120000000 && F_BUS == 60000000
147 SIM->CLKDIV1 = SIM_CLKDIV1_OUTDIV1(KINETIS_CLKDIV1_OUTDIV1 - 1) | SIM_CLKDIV1_OUTDIV2(KINETIS_CLKDIV1_OUTDIV2 - 1) |
148# if defined(MK66F18)
149 SIM_CLKDIV1_OUTDIV3(KINETIS_CLKDIV1_OUTDIV3 - 1) |
150# endif
151 SIM_CLKDIV1_OUTDIV4(KINETIS_CLKDIV1_OUTDIV4 - 1);
152# else
153 return 0;
154# endif
155 return 1;
156 }
157#endif
158 return 0;
159}
160
161#if defined(K20x) || defined(MK66F18) /* chip selection */
162/* Teensy 3.0, 3.1, 3.2; mchck; infinity keyboard */
163
164// The EEPROM is really RAM with a hardware-based backup system to
165// flash memory. Selecting a smaller size EEPROM allows more wear
166// leveling, for higher write endurance. If you edit this file,
167// set this to the smallest size your application can use. Also,
168// due to Freescale's implementation, writing 16 or 32 bit words
169// (aligned to 2 or 4 byte boundaries) has twice the endurance
170// compared to writing 8 bit bytes.
171//
172# ifndef EEPROM_SIZE
173# define EEPROM_SIZE 32
174# endif
175
176/*
177 ^^^ Here be dragons:
178 NXP AppNote AN4282 section 3.1 states that partitioning must only be done once.
179 Once EEPROM partitioning is done, the size is locked to this initial configuration.
180 Attempts to modify the EEPROM_SIZE setting may brick your board.
181*/
182
183// Writing unaligned 16 or 32 bit data is handled automatically when
184// this is defined, but at a cost of extra code size. Without this,
185// any unaligned write will cause a hard fault exception! If you're
186// absolutely sure all 16 and 32 bit writes will be aligned, you can
187// remove the extra unnecessary code.
188//
189# define HANDLE_UNALIGNED_WRITES
190
191# if defined(K20x)
192# define EEPROM_MAX 2048
193# define EEPARTITION 0x03 // all 32K dataflash for EEPROM, none for Data
194# define EEESPLIT 0x30 // must be 0x30 on these chips
195# elif defined(MK66F18)
196# define EEPROM_MAX 4096
197# define EEPARTITION 0x05 // 128K dataflash for EEPROM, 128K for Data
198# define EEESPLIT 0x10 // best endurance: 0x00 = first 12%, 0x10 = first 25%, 0x30 = all equal
199# endif
200
201// Minimum EEPROM Endurance
202// ------------------------
203# if (EEPROM_SIZE == 4096)
204# define EEESIZE 0x02
205# elif (EEPROM_SIZE == 2048) // 35000 writes/byte or 70000 writes/word
206# define EEESIZE 0x03
207# elif (EEPROM_SIZE == 1024) // 75000 writes/byte or 150000 writes/word
208# define EEESIZE 0x04
209# elif (EEPROM_SIZE == 512) // 155000 writes/byte or 310000 writes/word
210# define EEESIZE 0x05
211# elif (EEPROM_SIZE == 256) // 315000 writes/byte or 630000 writes/word
212# define EEESIZE 0x06
213# elif (EEPROM_SIZE == 128) // 635000 writes/byte or 1270000 writes/word
214# define EEESIZE 0x07
215# elif (EEPROM_SIZE == 64) // 1275000 writes/byte or 2550000 writes/word
216# define EEESIZE 0x08
217# elif (EEPROM_SIZE == 32) // 2555000 writes/byte or 5110000 writes/word
218# define EEESIZE 0x09
219# endif
220
221/** \brief eeprom initialization
222 *
223 * FIXME: needs doc
224 */
225void eeprom_initialize(void) {
226 uint32_t count = 0;
227 uint16_t do_flash_cmd[] = {0xf06f, 0x037f, 0x7003, 0x7803, 0xf013, 0x0f80, 0xd0fb, 0x4770};
228 uint8_t status;
229
230 if (FTFL->FCNFG & FTFL_FCNFG_RAMRDY) {
231 uint8_t stat = FTFL->FSTAT & 0x70;
232 if (stat) FTFL->FSTAT = stat;
233
234 // FlexRAM is configured as traditional RAM
235 // We need to reconfigure for EEPROM usage
236 kinetis_hsrun_disable();
237 FTFL->FCCOB0 = 0x80; // PGMPART = Program Partition Command
238 FTFL->FCCOB3 = 0;
239 FTFL->FCCOB4 = EEESPLIT | EEESIZE;
240 FTFL->FCCOB5 = EEPARTITION;
241 __disable_irq();
242 // do_flash_cmd() must execute from RAM. Luckily the C syntax is simple...
243 (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&(FTFL->FSTAT));
244 __enable_irq();
245 kinetis_hsrun_enable();
246 status = FTFL->FSTAT;
247 if (status & (FTFL_FSTAT_RDCOLERR | FTFL_FSTAT_ACCERR | FTFL_FSTAT_FPVIOL)) {
248 FTFL->FSTAT = (status & (FTFL_FSTAT_RDCOLERR | FTFL_FSTAT_ACCERR | FTFL_FSTAT_FPVIOL));
249 return; // error
250 }
251 }
252 // wait for eeprom to become ready (is this really necessary?)
253 while (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) {
254 if (++count > 200000) break;
255 }
256}
257
258# define FlexRAM ((volatile uint8_t *)0x14000000)
259
260/** \brief eeprom read byte
261 *
262 * FIXME: needs doc
263 */
264uint8_t eeprom_read_byte(const uint8_t *addr) {
265 uint32_t offset = (uint32_t)addr;
266 if (offset >= EEPROM_SIZE) return 0;
267 if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
268 return FlexRAM[offset];
269}
270
271/** \brief eeprom read word
272 *
273 * FIXME: needs doc
274 */
275uint16_t eeprom_read_word(const uint16_t *addr) {
276 uint32_t offset = (uint32_t)addr;
277 if (offset >= EEPROM_SIZE - 1) return 0;
278 if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
279 return *(uint16_t *)(&FlexRAM[offset]);
280}
281
282/** \brief eeprom read dword
283 *
284 * FIXME: needs doc
285 */
286uint32_t eeprom_read_dword(const uint32_t *addr) {
287 uint32_t offset = (uint32_t)addr;
288 if (offset >= EEPROM_SIZE - 3) return 0;
289 if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
290 return *(uint32_t *)(&FlexRAM[offset]);
291}
292
293/** \brief eeprom read block
294 *
295 * FIXME: needs doc
296 */
297void eeprom_read_block(void *buf, const void *addr, uint32_t len) {
298 uint32_t offset = (uint32_t)addr;
299 uint8_t *dest = (uint8_t *)buf;
300 uint32_t end = offset + len;
301
302 if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
303 if (end > EEPROM_SIZE) end = EEPROM_SIZE;
304 while (offset < end) {
305 *dest++ = FlexRAM[offset++];
306 }
307}
308
309/** \brief eeprom is ready
310 *
311 * FIXME: needs doc
312 */
313int eeprom_is_ready(void) { return (FTFL->FCNFG & FTFL_FCNFG_EEERDY) ? 1 : 0; }
314
315/** \brief flexram wait
316 *
317 * FIXME: needs doc
318 */
319static void flexram_wait(void) {
320 while (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) {
321 // TODO: timeout
322 }
323}
324
325/** \brief eeprom_write_byte
326 *
327 * FIXME: needs doc
328 */
329void eeprom_write_byte(uint8_t *addr, uint8_t value) {
330 uint32_t offset = (uint32_t)addr;
331
332 if (offset >= EEPROM_SIZE) return;
333 if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
334 if (FlexRAM[offset] != value) {
335 kinetis_hsrun_disable();
336 uint8_t stat = FTFL->FSTAT & 0x70;
337 if (stat) FTFL->FSTAT = stat;
338 FlexRAM[offset] = value;
339 flexram_wait();
340 kinetis_hsrun_enable();
341 }
342}
343
344/** \brief eeprom write word
345 *
346 * FIXME: needs doc
347 */
348void eeprom_write_word(uint16_t *addr, uint16_t value) {
349 uint32_t offset = (uint32_t)addr;
350
351 if (offset >= EEPROM_SIZE - 1) return;
352 if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
353# ifdef HANDLE_UNALIGNED_WRITES
354 if ((offset & 1) == 0) {
355# endif
356 if (*(uint16_t *)(&FlexRAM[offset]) != value) {
357 kinetis_hsrun_disable();
358 uint8_t stat = FTFL->FSTAT & 0x70;
359 if (stat) FTFL->FSTAT = stat;
360 *(uint16_t *)(&FlexRAM[offset]) = value;
361 flexram_wait();
362 kinetis_hsrun_enable();
363 }
364# ifdef HANDLE_UNALIGNED_WRITES
365 } else {
366 if (FlexRAM[offset] != value) {
367 kinetis_hsrun_disable();
368 uint8_t stat = FTFL->FSTAT & 0x70;
369 if (stat) FTFL->FSTAT = stat;
370 FlexRAM[offset] = value;
371 flexram_wait();
372 kinetis_hsrun_enable();
373 }
374 if (FlexRAM[offset + 1] != (value >> 8)) {
375 kinetis_hsrun_disable();
376 uint8_t stat = FTFL->FSTAT & 0x70;
377 if (stat) FTFL->FSTAT = stat;
378 FlexRAM[offset + 1] = value >> 8;
379 flexram_wait();
380 kinetis_hsrun_enable();
381 }
382 }
383# endif
384}
385
386/** \brief eeprom write dword
387 *
388 * FIXME: needs doc
389 */
390void eeprom_write_dword(uint32_t *addr, uint32_t value) {
391 uint32_t offset = (uint32_t)addr;
392
393 if (offset >= EEPROM_SIZE - 3) return;
394 if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
395# ifdef HANDLE_UNALIGNED_WRITES
396 switch (offset & 3) {
397 case 0:
398# endif
399 if (*(uint32_t *)(&FlexRAM[offset]) != value) {
400 kinetis_hsrun_disable();
401 uint8_t stat = FTFL->FSTAT & 0x70;
402 if (stat) FTFL->FSTAT = stat;
403 *(uint32_t *)(&FlexRAM[offset]) = value;
404 flexram_wait();
405 kinetis_hsrun_enable();
406 }
407 return;
408# ifdef HANDLE_UNALIGNED_WRITES
409 case 2:
410 if (*(uint16_t *)(&FlexRAM[offset]) != value) {
411 kinetis_hsrun_disable();
412 uint8_t stat = FTFL->FSTAT & 0x70;
413 if (stat) FTFL->FSTAT = stat;
414 *(uint16_t *)(&FlexRAM[offset]) = value;
415 flexram_wait();
416 kinetis_hsrun_enable();
417 }
418 if (*(uint16_t *)(&FlexRAM[offset + 2]) != (value >> 16)) {
419 kinetis_hsrun_disable();
420 uint8_t stat = FTFL->FSTAT & 0x70;
421 if (stat) FTFL->FSTAT = stat;
422 *(uint16_t *)(&FlexRAM[offset + 2]) = value >> 16;
423 flexram_wait();
424 kinetis_hsrun_enable();
425 }
426 return;
427 default:
428 if (FlexRAM[offset] != value) {
429 kinetis_hsrun_disable();
430 uint8_t stat = FTFL->FSTAT & 0x70;
431 if (stat) FTFL->FSTAT = stat;
432 FlexRAM[offset] = value;
433 flexram_wait();
434 kinetis_hsrun_enable();
435 }
436 if (*(uint16_t *)(&FlexRAM[offset + 1]) != (value >> 8)) {
437 kinetis_hsrun_disable();
438 uint8_t stat = FTFL->FSTAT & 0x70;
439 if (stat) FTFL->FSTAT = stat;
440 *(uint16_t *)(&FlexRAM[offset + 1]) = value >> 8;
441 flexram_wait();
442 kinetis_hsrun_enable();
443 }
444 if (FlexRAM[offset + 3] != (value >> 24)) {
445 kinetis_hsrun_disable();
446 uint8_t stat = FTFL->FSTAT & 0x70;
447 if (stat) FTFL->FSTAT = stat;
448 FlexRAM[offset + 3] = value >> 24;
449 flexram_wait();
450 kinetis_hsrun_enable();
451 }
452 }
453# endif
454}
455
456/** \brief eeprom write block
457 *
458 * FIXME: needs doc
459 */
460void eeprom_write_block(const void *buf, void *addr, uint32_t len) {
461 uint32_t offset = (uint32_t)addr;
462 const uint8_t *src = (const uint8_t *)buf;
463
464 if (offset >= EEPROM_SIZE) return;
465 if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
466 if (len >= EEPROM_SIZE) len = EEPROM_SIZE;
467 if (offset + len >= EEPROM_SIZE) len = EEPROM_SIZE - offset;
468 kinetis_hsrun_disable();
469 while (len > 0) {
470 uint32_t lsb = offset & 3;
471 if (lsb == 0 && len >= 4) {
472 // write aligned 32 bits
473 uint32_t val32;
474 val32 = *src++;
475 val32 |= (*src++ << 8);
476 val32 |= (*src++ << 16);
477 val32 |= (*src++ << 24);
478 if (*(uint32_t *)(&FlexRAM[offset]) != val32) {
479 uint8_t stat = FTFL->FSTAT & 0x70;
480 if (stat) FTFL->FSTAT = stat;
481 *(uint32_t *)(&FlexRAM[offset]) = val32;
482 flexram_wait();
483 }
484 offset += 4;
485 len -= 4;
486 } else if ((lsb == 0 || lsb == 2) && len >= 2) {
487 // write aligned 16 bits
488 uint16_t val16;
489 val16 = *src++;
490 val16 |= (*src++ << 8);
491 if (*(uint16_t *)(&FlexRAM[offset]) != val16) {
492 uint8_t stat = FTFL->FSTAT & 0x70;
493 if (stat) FTFL->FSTAT = stat;
494 *(uint16_t *)(&FlexRAM[offset]) = val16;
495 flexram_wait();
496 }
497 offset += 2;
498 len -= 2;
499 } else {
500 // write 8 bits
501 uint8_t val8 = *src++;
502 if (FlexRAM[offset] != val8) {
503 uint8_t stat = FTFL->FSTAT & 0x70;
504 if (stat) FTFL->FSTAT = stat;
505 FlexRAM[offset] = val8;
506 flexram_wait();
507 }
508 offset++;
509 len--;
510 }
511 }
512 kinetis_hsrun_enable();
513}
514
515/*
516void do_flash_cmd(volatile uint8_t *fstat)
517{
518 *fstat = 0x80;
519 while ((*fstat & 0x80) == 0) ; // wait
520}
52100000000 <do_flash_cmd>:
522 0: f06f 037f mvn.w r3, #127 ; 0x7f
523 4: 7003 strb r3, [r0, #0]
524 6: 7803 ldrb r3, [r0, #0]
525 8: f013 0f80 tst.w r3, #128 ; 0x80
526 c: d0fb beq.n 6 <do_flash_cmd+0x6>
527 e: 4770 bx lr
528*/
529
530#elif defined(KL2x) /* chip selection */
531/* Teensy LC (emulated) */
532
533# define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0))
534
535extern uint32_t __eeprom_workarea_start__;
536extern uint32_t __eeprom_workarea_end__;
537
538# define EEPROM_SIZE 128
539
540static uint32_t flashend = 0;
541
542void eeprom_initialize(void) {
543 const uint16_t *p = (uint16_t *)SYMVAL(__eeprom_workarea_start__);
544
545 do {
546 if (*p++ == 0xFFFF) {
547 flashend = (uint32_t)(p - 2);
548 return;
549 }
550 } while (p < (uint16_t *)SYMVAL(__eeprom_workarea_end__));
551 flashend = (uint32_t)(p - 1);
552}
553
554uint8_t eeprom_read_byte(const uint8_t *addr) {
555 uint32_t offset = (uint32_t)addr;
556 const uint16_t *p = (uint16_t *)SYMVAL(__eeprom_workarea_start__);
557 const uint16_t *end = (const uint16_t *)((uint32_t)flashend);
558 uint16_t val;
559 uint8_t data = 0xFF;
560
561 if (!end) {
562 eeprom_initialize();
563 end = (const uint16_t *)((uint32_t)flashend);
564 }
565 if (offset < EEPROM_SIZE) {
566 while (p <= end) {
567 val = *p++;
568 if ((val & 255) == offset) data = val >> 8;
569 }
570 }
571 return data;
572}
573
574static void flash_write(const uint16_t *code, uint32_t addr, uint32_t data) {
575 // with great power comes great responsibility....
576 uint32_t stat;
577 *(uint32_t *)&(FTFA->FCCOB3) = 0x06000000 | (addr & 0x00FFFFFC);
578 *(uint32_t *)&(FTFA->FCCOB7) = data;
579 __disable_irq();
580 (*((void (*)(volatile uint8_t *))((uint32_t)code | 1)))(&(FTFA->FSTAT));
581 __enable_irq();
582 stat = FTFA->FSTAT & (FTFA_FSTAT_RDCOLERR | FTFA_FSTAT_ACCERR | FTFA_FSTAT_FPVIOL);
583 if (stat) {
584 FTFA->FSTAT = stat;
585 }
586 MCM->PLACR |= MCM_PLACR_CFCC;
587}
588
589void eeprom_write_byte(uint8_t *addr, uint8_t data) {
590 uint32_t offset = (uint32_t)addr;
591 const uint16_t *p, *end = (const uint16_t *)((uint32_t)flashend);
592 uint32_t i, val, flashaddr;
593 uint16_t do_flash_cmd[] = {0x2380, 0x7003, 0x7803, 0xb25b, 0x2b00, 0xdafb, 0x4770};
594 uint8_t buf[EEPROM_SIZE];
595
596 if (offset >= EEPROM_SIZE) return;
597 if (!end) {
598 eeprom_initialize();
599 end = (const uint16_t *)((uint32_t)flashend);
600 }
601 if (++end < (uint16_t *)SYMVAL(__eeprom_workarea_end__)) {
602 val = (data << 8) | offset;
603 flashaddr = (uint32_t)end;
604 flashend = flashaddr;
605 if ((flashaddr & 2) == 0) {
606 val |= 0xFFFF0000;
607 } else {
608 val <<= 16;
609 val |= 0x0000FFFF;
610 }
611 flash_write(do_flash_cmd, flashaddr, val);
612 } else {
613 for (i = 0; i < EEPROM_SIZE; i++) {
614 buf[i] = 0xFF;
615 }
616 val = 0;
617 for (p = (uint16_t *)SYMVAL(__eeprom_workarea_start__); p < (uint16_t *)SYMVAL(__eeprom_workarea_end__); p++) {
618 val = *p;
619 if ((val & 255) < EEPROM_SIZE) {
620 buf[val & 255] = val >> 8;
621 }
622 }
623 buf[offset] = data;
624 for (flashaddr = (uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__); flashaddr < (uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_end__); flashaddr += 1024) {
625 *(uint32_t *)&(FTFA->FCCOB3) = 0x09000000 | flashaddr;
626 __disable_irq();
627 (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&(FTFA->FSTAT));
628 __enable_irq();
629 val = FTFA->FSTAT & (FTFA_FSTAT_RDCOLERR | FTFA_FSTAT_ACCERR | FTFA_FSTAT_FPVIOL);
630 ;
631 if (val) FTFA->FSTAT = val;
632 MCM->PLACR |= MCM_PLACR_CFCC;
633 }
634 flashaddr = (uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__);
635 for (i = 0; i < EEPROM_SIZE; i++) {
636 if (buf[i] == 0xFF) continue;
637 if ((flashaddr & 2) == 0) {
638 val = (buf[i] << 8) | i;
639 } else {
640 val = val | (buf[i] << 24) | (i << 16);
641 flash_write(do_flash_cmd, flashaddr, val);
642 }
643 flashaddr += 2;
644 }
645 flashend = flashaddr;
646 if ((flashaddr & 2)) {
647 val |= 0xFFFF0000;
648 flash_write(do_flash_cmd, flashaddr, val);
649 }
650 }
651}
652
653/*
654void do_flash_cmd(volatile uint8_t *fstat)
655{
656 *fstat = 0x80;
657 while ((*fstat & 0x80) == 0) ; // wait
658}
65900000000 <do_flash_cmd>:
660 0: 2380 movs r3, #128 ; 0x80
661 2: 7003 strb r3, [r0, #0]
662 4: 7803 ldrb r3, [r0, #0]
663 6: b25b sxtb r3, r3
664 8: 2b00 cmp r3, #0
665 a: dafb bge.n 4 <do_flash_cmd+0x4>
666 c: 4770 bx lr
667*/
668
669uint16_t eeprom_read_word(const uint16_t *addr) {
670 const uint8_t *p = (const uint8_t *)addr;
671 return eeprom_read_byte(p) | (eeprom_read_byte(p + 1) << 8);
672}
673
674uint32_t eeprom_read_dword(const uint32_t *addr) {
675 const uint8_t *p = (const uint8_t *)addr;
676 return eeprom_read_byte(p) | (eeprom_read_byte(p + 1) << 8) | (eeprom_read_byte(p + 2) << 16) | (eeprom_read_byte(p + 3) << 24);
677}
678
679void eeprom_read_block(void *buf, const void *addr, uint32_t len) {
680 const uint8_t *p = (const uint8_t *)addr;
681 uint8_t * dest = (uint8_t *)buf;
682 while (len--) {
683 *dest++ = eeprom_read_byte(p++);
684 }
685}
686
687int eeprom_is_ready(void) { return 1; }
688
689void eeprom_write_word(uint16_t *addr, uint16_t value) {
690 uint8_t *p = (uint8_t *)addr;
691 eeprom_write_byte(p++, value);
692 eeprom_write_byte(p, value >> 8);
693}
694
695void eeprom_write_dword(uint32_t *addr, uint32_t value) {
696 uint8_t *p = (uint8_t *)addr;
697 eeprom_write_byte(p++, value);
698 eeprom_write_byte(p++, value >> 8);
699 eeprom_write_byte(p++, value >> 16);
700 eeprom_write_byte(p, value >> 24);
701}
702
703void eeprom_write_block(const void *buf, void *addr, uint32_t len) {
704 uint8_t * p = (uint8_t *)addr;
705 const uint8_t *src = (const uint8_t *)buf;
706 while (len--) {
707 eeprom_write_byte(p++, *src++);
708 }
709}
710
711#else
712// No EEPROM supported, so emulate it
713
714# ifndef EEPROM_SIZE
715# include "eeconfig.h"
716# define EEPROM_SIZE (((EECONFIG_SIZE + 3) / 4) * 4) // based off eeconfig's current usage, aligned to 4-byte sizes, to deal with LTO
717# endif
718__attribute__((aligned(4))) static uint8_t buffer[EEPROM_SIZE];
719
720uint8_t eeprom_read_byte(const uint8_t *addr) {
721 uint32_t offset = (uint32_t)addr;
722 return buffer[offset];
723}
724
725void eeprom_write_byte(uint8_t *addr, uint8_t value) {
726 uint32_t offset = (uint32_t)addr;
727 buffer[offset] = value;
728}
729
730uint16_t eeprom_read_word(const uint16_t *addr) {
731 const uint8_t *p = (const uint8_t *)addr;
732 return eeprom_read_byte(p) | (eeprom_read_byte(p + 1) << 8);
733}
734
735uint32_t eeprom_read_dword(const uint32_t *addr) {
736 const uint8_t *p = (const uint8_t *)addr;
737 return eeprom_read_byte(p) | (eeprom_read_byte(p + 1) << 8) | (eeprom_read_byte(p + 2) << 16) | (eeprom_read_byte(p + 3) << 24);
738}
739
740void eeprom_read_block(void *buf, const void *addr, size_t len) {
741 const uint8_t *p = (const uint8_t *)addr;
742 uint8_t * dest = (uint8_t *)buf;
743 while (len--) {
744 *dest++ = eeprom_read_byte(p++);
745 }
746}
747
748void eeprom_write_word(uint16_t *addr, uint16_t value) {
749 uint8_t *p = (uint8_t *)addr;
750 eeprom_write_byte(p++, value);
751 eeprom_write_byte(p, value >> 8);
752}
753
754void eeprom_write_dword(uint32_t *addr, uint32_t value) {
755 uint8_t *p = (uint8_t *)addr;
756 eeprom_write_byte(p++, value);
757 eeprom_write_byte(p++, value >> 8);
758 eeprom_write_byte(p++, value >> 16);
759 eeprom_write_byte(p, value >> 24);
760}
761
762void eeprom_write_block(const void *buf, void *addr, size_t len) {
763 uint8_t * p = (uint8_t *)addr;
764 const uint8_t *src = (const uint8_t *)buf;
765 while (len--) {
766 eeprom_write_byte(p++, *src++);
767 }
768}
769
770#endif /* chip selection */
771// The update functions just calls write for now, but could probably be optimized
772
773void eeprom_update_byte(uint8_t *addr, uint8_t value) { eeprom_write_byte(addr, value); }
774
775void eeprom_update_word(uint16_t *addr, uint16_t value) {
776 uint8_t *p = (uint8_t *)addr;
777 eeprom_write_byte(p++, value);
778 eeprom_write_byte(p, value >> 8);
779}
780
781void eeprom_update_dword(uint32_t *addr, uint32_t value) {
782 uint8_t *p = (uint8_t *)addr;
783 eeprom_write_byte(p++, value);
784 eeprom_write_byte(p++, value >> 8);
785 eeprom_write_byte(p++, value >> 16);
786 eeprom_write_byte(p, value >> 24);
787}
788
789void eeprom_update_block(const void *buf, void *addr, size_t len) {
790 uint8_t * p = (uint8_t *)addr;
791 const uint8_t *src = (const uint8_t *)buf;
792 while (len--) {
793 eeprom_write_byte(p++, *src++);
794 }
795}
diff --git a/platforms/chibios/flash.mk b/platforms/chibios/flash.mk
index c0b32c2f2..31f69595d 100644
--- a/platforms/chibios/flash.mk
+++ b/platforms/chibios/flash.mk
@@ -82,6 +82,8 @@ else ifeq ($(strip $(MCU_FAMILY)),MIMXRT1062)
82 $(UNSYNC_OUTPUT_CMD) && $(call EXEC_TEENSY) 82 $(UNSYNC_OUTPUT_CMD) && $(call EXEC_TEENSY)
83else ifeq ($(strip $(MCU_FAMILY)),STM32) 83else ifeq ($(strip $(MCU_FAMILY)),STM32)
84 $(UNSYNC_OUTPUT_CMD) && $(call EXEC_DFU_UTIL) 84 $(UNSYNC_OUTPUT_CMD) && $(call EXEC_DFU_UTIL)
85else ifeq ($(strip $(MCU_FAMILY)),GD32V)
86 $(UNSYNC_OUTPUT_CMD) && $(call EXEC_DFU_UTIL)
85else 87else
86 $(PRINT_OK); $(SILENT) || printf "$(MSG_FLASH_BOOTLOADER)" 88 $(PRINT_OK); $(SILENT) || printf "$(MSG_FLASH_BOOTLOADER)"
87endif 89endif
diff --git a/platforms/chibios/flash_stm32.c b/platforms/chibios/flash_stm32.c
new file mode 100644
index 000000000..72c41b8b7
--- /dev/null
+++ b/platforms/chibios/flash_stm32.c
@@ -0,0 +1,208 @@
1/*
2 * This software is experimental and a work in progress.
3 * Under no circumstances should these files be used in relation to any critical system(s).
4 * Use of these files is at your own risk.
5 *
6 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
7 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
8 * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
9 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
10 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
11 * DEALINGS IN THE SOFTWARE.
12 *
13 * This files are free to use from https://github.com/rogerclarkmelbourne/Arduino_STM32 and
14 * https://github.com/leaflabs/libmaple
15 *
16 * Modifications for QMK and STM32F303 by Yiancar
17 */
18
19#include <hal.h>
20#include "flash_stm32.h"
21
22#if defined(STM32F1XX)
23# define FLASH_SR_WRPERR FLASH_SR_WRPRTERR
24#endif
25
26#if defined(MCU_GD32V)
27/* GigaDevice GD32VF103 is a STM32F103 clone at heart. */
28# include "gd32v_compatibility.h"
29#endif
30
31#if defined(STM32F4XX)
32# define FLASH_SR_PGERR (FLASH_SR_PGSERR | FLASH_SR_PGPERR | FLASH_SR_PGAERR)
33
34# define FLASH_KEY1 0x45670123U
35# define FLASH_KEY2 0xCDEF89ABU
36
37static uint8_t ADDR2PAGE(uint32_t Page_Address) {
38 switch (Page_Address) {
39 case 0x08000000 ... 0x08003FFF:
40 return 0;
41 case 0x08004000 ... 0x08007FFF:
42 return 1;
43 case 0x08008000 ... 0x0800BFFF:
44 return 2;
45 case 0x0800C000 ... 0x0800FFFF:
46 return 3;
47 }
48
49 // TODO: bad times...
50 return 7;
51}
52#endif
53
54/* Delay definition */
55#define EraseTimeout ((uint32_t)0x00000FFF)
56#define ProgramTimeout ((uint32_t)0x0000001F)
57
58#define ASSERT(exp) (void)((0))
59
60/**
61 * @brief Inserts a time delay.
62 * @param None
63 * @retval None
64 */
65static void delay(void) {
66 __IO uint32_t i = 0;
67 for (i = 0xFF; i != 0; i--) {
68 }
69}
70
71/**
72 * @brief Returns the FLASH Status.
73 * @param None
74 * @retval FLASH Status: The returned value can be: FLASH_BUSY, FLASH_ERROR_PG,
75 * FLASH_ERROR_WRP or FLASH_COMPLETE
76 */
77FLASH_Status FLASH_GetStatus(void) {
78 if ((FLASH->SR & FLASH_SR_BSY) == FLASH_SR_BSY) return FLASH_BUSY;
79
80 if ((FLASH->SR & FLASH_SR_PGERR) != 0) return FLASH_ERROR_PG;
81
82 if ((FLASH->SR & FLASH_SR_WRPERR) != 0) return FLASH_ERROR_WRP;
83
84#if defined(FLASH_OBR_OPTERR)
85 if ((FLASH->SR & FLASH_OBR_OPTERR) != 0) return FLASH_ERROR_OPT;
86#endif
87
88 return FLASH_COMPLETE;
89}
90
91/**
92 * @brief Waits for a Flash operation to complete or a TIMEOUT to occur.
93 * @param Timeout: FLASH progamming Timeout
94 * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG,
95 * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
96 */
97FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout) {
98 FLASH_Status status;
99
100 /* Check for the Flash Status */
101 status = FLASH_GetStatus();
102 /* Wait for a Flash operation to complete or a TIMEOUT to occur */
103 while ((status == FLASH_BUSY) && (Timeout != 0x00)) {
104 delay();
105 status = FLASH_GetStatus();
106 Timeout--;
107 }
108 if (Timeout == 0) status = FLASH_TIMEOUT;
109 /* Return the operation status */
110 return status;
111}
112
113/**
114 * @brief Erases a specified FLASH page.
115 * @param Page_Address: The page address to be erased.
116 * @retval FLASH Status: The returned value can be: FLASH_BUSY, FLASH_ERROR_PG,
117 * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
118 */
119FLASH_Status FLASH_ErasePage(uint32_t Page_Address) {
120 FLASH_Status status = FLASH_COMPLETE;
121 /* Check the parameters */
122 ASSERT(IS_FLASH_ADDRESS(Page_Address));
123 /* Wait for last operation to be completed */
124 status = FLASH_WaitForLastOperation(EraseTimeout);
125
126 if (status == FLASH_COMPLETE) {
127 /* if the previous operation is completed, proceed to erase the page */
128#if defined(FLASH_CR_SNB)
129 FLASH->CR &= ~FLASH_CR_SNB;
130 FLASH->CR |= FLASH_CR_SER | (ADDR2PAGE(Page_Address) << FLASH_CR_SNB_Pos);
131#else
132 FLASH->CR |= FLASH_CR_PER;
133 FLASH->AR = Page_Address;
134#endif
135 FLASH->CR |= FLASH_CR_STRT;
136
137 /* Wait for last operation to be completed */
138 status = FLASH_WaitForLastOperation(EraseTimeout);
139 if (status != FLASH_TIMEOUT) {
140 /* if the erase operation is completed, disable the configured Bits */
141#if defined(FLASH_CR_SNB)
142 FLASH->CR &= ~(FLASH_CR_SER | FLASH_CR_SNB);
143#else
144 FLASH->CR &= ~FLASH_CR_PER;
145#endif
146 }
147 FLASH->SR = (FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPERR);
148 }
149 /* Return the Erase Status */
150 return status;
151}
152
153/**
154 * @brief Programs a half word at a specified address.
155 * @param Address: specifies the address to be programmed.
156 * @param Data: specifies the data to be programmed.
157 * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG,
158 * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
159 */
160FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data) {
161 FLASH_Status status = FLASH_BAD_ADDRESS;
162
163 if (IS_FLASH_ADDRESS(Address)) {
164 /* Wait for last operation to be completed */
165 status = FLASH_WaitForLastOperation(ProgramTimeout);
166 if (status == FLASH_COMPLETE) {
167 /* if the previous operation is completed, proceed to program the new data */
168
169#if defined(FLASH_CR_PSIZE)
170 FLASH->CR &= ~FLASH_CR_PSIZE;
171 FLASH->CR |= FLASH_CR_PSIZE_0;
172#endif
173 FLASH->CR |= FLASH_CR_PG;
174 *(__IO uint16_t*)Address = Data;
175 /* Wait for last operation to be completed */
176 status = FLASH_WaitForLastOperation(ProgramTimeout);
177 if (status != FLASH_TIMEOUT) {
178 /* if the program operation is completed, disable the PG Bit */
179 FLASH->CR &= ~FLASH_CR_PG;
180 }
181 FLASH->SR = (FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPERR);
182 }
183 }
184 return status;
185}
186
187/**
188 * @brief Unlocks the FLASH Program Erase Controller.
189 * @param None
190 * @retval None
191 */
192void FLASH_Unlock(void) {
193 if (FLASH->CR & FLASH_CR_LOCK) {
194 /* Authorize the FPEC Access */
195 FLASH->KEYR = FLASH_KEY1;
196 FLASH->KEYR = FLASH_KEY2;
197 }
198}
199
200/**
201 * @brief Locks the FLASH Program Erase Controller.
202 * @param None
203 * @retval None
204 */
205void FLASH_Lock(void) {
206 /* Set the Lock Bit to lock the FPEC and the FCR */
207 FLASH->CR |= FLASH_CR_LOCK;
208}
diff --git a/platforms/chibios/flash_stm32.h b/platforms/chibios/flash_stm32.h
new file mode 100644
index 000000000..6c66642ec
--- /dev/null
+++ b/platforms/chibios/flash_stm32.h
@@ -0,0 +1,44 @@
1/*
2 * This software is experimental and a work in progress.
3 * Under no circumstances should these files be used in relation to any critical system(s).
4 * Use of these files is at your own risk.
5 *
6 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
7 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
8 * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
9 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
10 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
11 * DEALINGS IN THE SOFTWARE.
12 *
13 * This files are free to use from https://github.com/rogerclarkmelbourne/Arduino_STM32 and
14 * https://github.com/leaflabs/libmaple
15 *
16 * Modifications for QMK and STM32F303 by Yiancar
17 */
18
19#pragma once
20
21#ifdef __cplusplus
22extern "C" {
23#endif
24
25#include <stdint.h>
26
27#ifdef FLASH_STM32_MOCKED
28extern uint8_t FlashBuf[MOCK_FLASH_SIZE];
29#endif
30
31typedef enum { FLASH_BUSY = 1, FLASH_ERROR_PG, FLASH_ERROR_WRP, FLASH_ERROR_OPT, FLASH_COMPLETE, FLASH_TIMEOUT, FLASH_BAD_ADDRESS } FLASH_Status;
32
33#define IS_FLASH_ADDRESS(ADDRESS) (((ADDRESS) >= 0x08000000) && ((ADDRESS) < 0x0807FFFF))
34
35FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout);
36FLASH_Status FLASH_ErasePage(uint32_t Page_Address);
37FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data);
38
39void FLASH_Unlock(void);
40void FLASH_Lock(void);
41
42#ifdef __cplusplus
43}
44#endif
diff --git a/platforms/chibios/gd32v_compatibility.h b/platforms/chibios/gd32v_compatibility.h
new file mode 100644
index 000000000..f4dcfd8c5
--- /dev/null
+++ b/platforms/chibios/gd32v_compatibility.h
@@ -0,0 +1,120 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#pragma once
18
19/* GD32VF103 has the same API as STM32F103, but uses different names for literally the same thing.
20 * As of 23.7.2021 QMK is tailored to use STM32 defines/names, for compatibility sake
21 * we just redefine the GD32 names. */
22
23/* Close your eyes kids. */
24#define MCU_STM32
25
26/* AFIO redefines */
27#define MAPR PCF0
28#define AFIO_MAPR_USART1_REMAP AFIO_PCF0_USART0_REMAP
29#define AFIO_MAPR_USART2_REMAP AFIO_PCF0_USART1_REMAP
30#define AFIO_MAPR_USART3_REMAP_PARTIALREMAP AFIO_PCF0_USART2_REMAP_PARTIALREMAP
31#define AFIO_MAPR_USART3_REMAP_FULLREMAP AFIO_PCF0_USART2_REMAP_FULLREMAP
32
33/* DMA redefines. */
34#define STM32_DMA_STREAM(stream) GD32_DMA_STREAM(stream)
35#define STM32_DMA_STREAM_ID(peripheral, channel) GD32_DMA_STREAM_ID(peripheral - 1, channel - 1)
36#define STM32_DMA_CR_DIR_M2P GD32_DMA_CTL_DIR_M2P
37#define STM32_DMA_CR_PSIZE_WORD GD32_DMA_CTL_PWIDTH_WORD
38#define STM32_DMA_CR_MSIZE_WORD GD32_DMA_CTL_MWIDTH_WORD
39#define STM32_DMA_CR_MINC GD32_DMA_CTL_MNAGA
40#define STM32_DMA_CR_CIRC GD32_DMA_CTL_CMEN
41#define STM32_DMA_CR_PL GD32_DMA_CTL_PRIO
42#define STM32_DMA_CR_CHSEL GD32_DMA_CTL_CHSEL
43#define cr1 ctl0
44#define cr2 ctl1
45#define cr3 ctl2
46#define dier dmainten
47
48/* ADC redefines */
49#if HAL_USE_ADC
50# define STM32_ADC_USE_ADC1 GD32_ADC_USE_ADC0
51
52# define smpr1 sampt0
53# define smpr2 sampt1
54# define sqr1 rsq0
55# define sqr2 rsq1
56# define sqr3 rsq2
57
58# define ADC_SMPR2_SMP_AN0 ADC_SAMPT1_SMP_SPT0
59# define ADC_SMPR2_SMP_AN1 ADC_SAMPT1_SMP_SPT1
60# define ADC_SMPR2_SMP_AN2 ADC_SAMPT1_SMP_SPT2
61# define ADC_SMPR2_SMP_AN3 ADC_SAMPT1_SMP_SPT3
62# define ADC_SMPR2_SMP_AN4 ADC_SAMPT1_SMP_SPT4
63# define ADC_SMPR2_SMP_AN5 ADC_SAMPT1_SMP_SPT5
64# define ADC_SMPR2_SMP_AN6 ADC_SAMPT1_SMP_SPT6
65# define ADC_SMPR2_SMP_AN7 ADC_SAMPT1_SMP_SPT7
66# define ADC_SMPR2_SMP_AN8 ADC_SAMPT1_SMP_SPT8
67# define ADC_SMPR2_SMP_AN9 ADC_SAMPT1_SMP_SPT9
68
69# define ADC_SMPR1_SMP_AN10 ADC_SAMPT0_SMP_SPT10
70# define ADC_SMPR1_SMP_AN11 ADC_SAMPT0_SMP_SPT11
71# define ADC_SMPR1_SMP_AN12 ADC_SAMPT0_SMP_SPT12
72# define ADC_SMPR1_SMP_AN13 ADC_SAMPT0_SMP_SPT13
73# define ADC_SMPR1_SMP_AN14 ADC_SAMPT0_SMP_SPT14
74# define ADC_SMPR1_SMP_AN15 ADC_SAMPT0_SMP_SPT15
75
76# define ADC_SQR3_SQ1_N ADC_RSQ2_RSQ1_N
77#endif
78
79/* FLASH redefines */
80#if defined(EEPROM_ENABLE)
81# define SR STAT
82# define FLASH_SR_BSY FLASH_STAT_BUSY
83# define FLASH_SR_PGERR FLASH_STAT_PGERR
84# define FLASH_SR_EOP FLASH_STAT_ENDF
85# define FLASH_SR_WRPRTERR FLASH_STAT_WPERR
86# define FLASH_SR_WRPERR FLASH_SR_WRPRTERR
87# define FLASH_OBR_OPTERR FLASH_OBSTAT_OBERR
88# define AR ADDR
89# define CR CTL
90# define FLASH_CR_PER FLASH_CTL_PER
91# define FLASH_CR_STRT FLASH_CTL_START
92# define FLASH_CR_LOCK FLASH_CTL_LK
93# define FLASH_CR_PG FLASH_CTL_PG
94# define KEYR KEY
95#endif
96
97/* Serial USART redefines. */
98#if HAL_USE_SERIAL
99# if !defined(SERIAL_USART_CR1)
100# define SERIAL_USART_CR1 (USART_CTL0_PCEN | USART_CTL0_PM | USART_CTL0_WL) // parity enable, odd parity, 9 bit length
101# endif
102# if !defined(SERIAL_USART_CR2)
103# define SERIAL_USART_CR2 (USART_CTL1_STB_1) // 2 stop bits
104# endif
105# if !defined(SERIAL_USART_CR3)
106# define SERIAL_USART_CR3 0x0
107# endif
108# define USART_CR3_HDSEL USART_CTL2_HDEN
109# define CCR CHCV
110#endif
111
112/* SPI redefines. */
113#if HAL_USE_SPI
114# define SPI_CR1_LSBFIRST SPI_CTL0_LF
115# define SPI_CR1_CPHA SPI_CTL0_CKPH
116# define SPI_CR1_CPOL SPI_CTL0_CKPL
117# define SPI_CR1_BR_0 SPI_CTL0_PSC_0
118# define SPI_CR1_BR_1 SPI_CTL0_PSC_1
119# define SPI_CR1_BR_2 SPI_CTL0_PSC_2
120#endif
diff --git a/platforms/chibios/gpio.h b/platforms/chibios/gpio.h
new file mode 100644
index 000000000..4d057f1ca
--- /dev/null
+++ b/platforms/chibios/gpio.h
@@ -0,0 +1,50 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#pragma once
17
18#include <hal.h>
19#include "pin_defs.h"
20
21typedef ioline_t pin_t;
22
23/* Operation of GPIO by pin. */
24
25#define setPinInput(pin) palSetLineMode(pin, PAL_MODE_INPUT)
26#define setPinInputHigh(pin) palSetLineMode(pin, PAL_MODE_INPUT_PULLUP)
27#define setPinInputLow(pin) palSetLineMode(pin, PAL_MODE_INPUT_PULLDOWN)
28#define setPinOutput(pin) palSetLineMode(pin, PAL_MODE_OUTPUT_PUSHPULL)
29
30#define writePinHigh(pin) palSetLine(pin)
31#define writePinLow(pin) palClearLine(pin)
32#define writePin(pin, level) ((level) ? (writePinHigh(pin)) : (writePinLow(pin)))
33
34#define readPin(pin) palReadLine(pin)
35
36#define togglePin(pin) palToggleLine(pin)
37
38/* Operation of GPIO by port. */
39
40typedef uint16_t port_data_t;
41
42#define readPort(pin) palReadPort(PAL_PORT(pin))
43
44#define setPortBitInput(pin, bit) palSetPadMode(PAL_PORT(pin), bit, PAL_MODE_INPUT)
45#define setPortBitInputHigh(pin, bit) palSetPadMode(PAL_PORT(pin), bit, PAL_MODE_INPUT_PULLUP)
46#define setPortBitInputLow(pin, bit) palSetPadMode(PAL_PORT(pin), bit, PAL_MODE_INPUT_PULLDOWN)
47#define setPortBitOutput(pin, bit) palSetPadMode(PAL_PORT(pin), bit, PAL_MODE_OUTPUT_PUSHPULL)
48
49#define writePortBitLow(pin, bit) palClearLine(PAL_LINE(PAL_PORT(pin), bit))
50#define writePortBitHigh(pin, bit) palSetLine(PAL_LINE(PAL_PORT(pin), bit))
diff --git a/platforms/chibios/pin_defs.h b/platforms/chibios/pin_defs.h
new file mode 100644
index 000000000..c03f8de0c
--- /dev/null
+++ b/platforms/chibios/pin_defs.h
@@ -0,0 +1,323 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#pragma once
17
18// Defines mapping for Proton C replacement
19#ifdef CONVERT_TO_PROTON_C
20// Left side (front)
21# define D3 PAL_LINE(GPIOA, 9)
22# define D2 PAL_LINE(GPIOA, 10)
23// GND
24// GND
25# define D1 PAL_LINE(GPIOB, 7)
26# define D0 PAL_LINE(GPIOB, 6)
27# define D4 PAL_LINE(GPIOB, 5)
28# define C6 PAL_LINE(GPIOB, 4)
29# define D7 PAL_LINE(GPIOB, 3)
30# define E6 PAL_LINE(GPIOB, 2)
31# define B4 PAL_LINE(GPIOB, 1)
32# define B5 PAL_LINE(GPIOB, 0)
33
34// Right side (front)
35// RAW
36// GND
37// RESET
38// VCC
39# define F4 PAL_LINE(GPIOA, 2)
40# define F5 PAL_LINE(GPIOA, 1)
41# define F6 PAL_LINE(GPIOA, 0)
42# define F7 PAL_LINE(GPIOB, 8)
43# define B1 PAL_LINE(GPIOB, 13)
44# define B3 PAL_LINE(GPIOB, 14)
45# define B2 PAL_LINE(GPIOB, 15)
46# define B6 PAL_LINE(GPIOB, 9)
47
48// LEDs (only D5/C13 uses an actual LED)
49# ifdef CONVERT_TO_PROTON_C_RXLED
50# define D5 PAL_LINE(GPIOC, 14)
51# define B0 PAL_LINE(GPIOC, 13)
52# else
53# define D5 PAL_LINE(GPIOC, 13)
54# define B0 PAL_LINE(GPIOC, 14)
55# endif
56#else
57# define A0 PAL_LINE(GPIOA, 0)
58# define A1 PAL_LINE(GPIOA, 1)
59# define A2 PAL_LINE(GPIOA, 2)
60# define A3 PAL_LINE(GPIOA, 3)
61# define A4 PAL_LINE(GPIOA, 4)
62# define A5 PAL_LINE(GPIOA, 5)
63# define A6 PAL_LINE(GPIOA, 6)
64# define A7 PAL_LINE(GPIOA, 7)
65# define A8 PAL_LINE(GPIOA, 8)
66# define A9 PAL_LINE(GPIOA, 9)
67# define A10 PAL_LINE(GPIOA, 10)
68# define A11 PAL_LINE(GPIOA, 11)
69# define A12 PAL_LINE(GPIOA, 12)
70# define A13 PAL_LINE(GPIOA, 13)
71# define A14 PAL_LINE(GPIOA, 14)
72# define A15 PAL_LINE(GPIOA, 15)
73# define A16 PAL_LINE(GPIOA, 16)
74# define A17 PAL_LINE(GPIOA, 17)
75# define A18 PAL_LINE(GPIOA, 18)
76# define A19 PAL_LINE(GPIOA, 19)
77# define A20 PAL_LINE(GPIOA, 20)
78# define A21 PAL_LINE(GPIOA, 21)
79# define A22 PAL_LINE(GPIOA, 22)
80# define A23 PAL_LINE(GPIOA, 23)
81# define A24 PAL_LINE(GPIOA, 24)
82# define A25 PAL_LINE(GPIOA, 25)
83# define A26 PAL_LINE(GPIOA, 26)
84# define A27 PAL_LINE(GPIOA, 27)
85# define A28 PAL_LINE(GPIOA, 28)
86# define A29 PAL_LINE(GPIOA, 29)
87# define A30 PAL_LINE(GPIOA, 30)
88# define A31 PAL_LINE(GPIOA, 31)
89# define A32 PAL_LINE(GPIOA, 32)
90# define B0 PAL_LINE(GPIOB, 0)
91# define B1 PAL_LINE(GPIOB, 1)
92# define B2 PAL_LINE(GPIOB, 2)
93# define B3 PAL_LINE(GPIOB, 3)
94# define B4 PAL_LINE(GPIOB, 4)
95# define B5 PAL_LINE(GPIOB, 5)
96# define B6 PAL_LINE(GPIOB, 6)
97# define B7 PAL_LINE(GPIOB, 7)
98# define B8 PAL_LINE(GPIOB, 8)
99# define B9 PAL_LINE(GPIOB, 9)
100# define B10 PAL_LINE(GPIOB, 10)
101# define B11 PAL_LINE(GPIOB, 11)
102# define B12 PAL_LINE(GPIOB, 12)
103# define B13 PAL_LINE(GPIOB, 13)
104# define B14 PAL_LINE(GPIOB, 14)
105# define B15 PAL_LINE(GPIOB, 15)
106# define B16 PAL_LINE(GPIOB, 16)
107# define B17 PAL_LINE(GPIOB, 17)
108# define B18 PAL_LINE(GPIOB, 18)
109# define B19 PAL_LINE(GPIOB, 19)
110# define B20 PAL_LINE(GPIOB, 20)
111# define B21 PAL_LINE(GPIOB, 21)
112# define B22 PAL_LINE(GPIOB, 22)
113# define B23 PAL_LINE(GPIOB, 23)
114# define B24 PAL_LINE(GPIOB, 24)
115# define B25 PAL_LINE(GPIOB, 25)
116# define B26 PAL_LINE(GPIOB, 26)
117# define B27 PAL_LINE(GPIOB, 27)
118# define B28 PAL_LINE(GPIOB, 28)
119# define B29 PAL_LINE(GPIOB, 29)
120# define B30 PAL_LINE(GPIOB, 30)
121# define B31 PAL_LINE(GPIOB, 31)
122# define B32 PAL_LINE(GPIOB, 32)
123# define C0 PAL_LINE(GPIOC, 0)
124# define C1 PAL_LINE(GPIOC, 1)
125# define C2 PAL_LINE(GPIOC, 2)
126# define C3 PAL_LINE(GPIOC, 3)
127# define C4 PAL_LINE(GPIOC, 4)
128# define C5 PAL_LINE(GPIOC, 5)
129# define C6 PAL_LINE(GPIOC, 6)
130# define C7 PAL_LINE(GPIOC, 7)
131# define C8 PAL_LINE(GPIOC, 8)
132# define C9 PAL_LINE(GPIOC, 9)
133# define C10 PAL_LINE(GPIOC, 10)
134# define C11 PAL_LINE(GPIOC, 11)
135# define C12 PAL_LINE(GPIOC, 12)
136# define C13 PAL_LINE(GPIOC, 13)
137# define C14 PAL_LINE(GPIOC, 14)
138# define C15 PAL_LINE(GPIOC, 15)
139# define C16 PAL_LINE(GPIOC, 16)
140# define C17 PAL_LINE(GPIOC, 17)
141# define C18 PAL_LINE(GPIOC, 18)
142# define C19 PAL_LINE(GPIOC, 19)
143# define C20 PAL_LINE(GPIOC, 20)
144# define C21 PAL_LINE(GPIOC, 21)
145# define C22 PAL_LINE(GPIOC, 22)
146# define C23 PAL_LINE(GPIOC, 23)
147# define C24 PAL_LINE(GPIOC, 24)
148# define C25 PAL_LINE(GPIOC, 25)
149# define C26 PAL_LINE(GPIOC, 26)
150# define C27 PAL_LINE(GPIOC, 27)
151# define C28 PAL_LINE(GPIOC, 28)
152# define C29 PAL_LINE(GPIOC, 29)
153# define C30 PAL_LINE(GPIOC, 30)
154# define C31 PAL_LINE(GPIOC, 31)
155# define C32 PAL_LINE(GPIOC, 32)
156# define D0 PAL_LINE(GPIOD, 0)
157# define D1 PAL_LINE(GPIOD, 1)
158# define D2 PAL_LINE(GPIOD, 2)
159# define D3 PAL_LINE(GPIOD, 3)
160# define D4 PAL_LINE(GPIOD, 4)
161# define D5 PAL_LINE(GPIOD, 5)
162# define D6 PAL_LINE(GPIOD, 6)
163# define D7 PAL_LINE(GPIOD, 7)
164# define D8 PAL_LINE(GPIOD, 8)
165# define D9 PAL_LINE(GPIOD, 9)
166# define D10 PAL_LINE(GPIOD, 10)
167# define D11 PAL_LINE(GPIOD, 11)
168# define D12 PAL_LINE(GPIOD, 12)
169# define D13 PAL_LINE(GPIOD, 13)
170# define D14 PAL_LINE(GPIOD, 14)
171# define D15 PAL_LINE(GPIOD, 15)
172# define D16 PAL_LINE(GPIOD, 16)
173# define D17 PAL_LINE(GPIOD, 17)
174# define D18 PAL_LINE(GPIOD, 18)
175# define D19 PAL_LINE(GPIOD, 19)
176# define D20 PAL_LINE(GPIOD, 20)
177# define D21 PAL_LINE(GPIOD, 21)
178# define D22 PAL_LINE(GPIOD, 22)
179# define D23 PAL_LINE(GPIOD, 23)
180# define D24 PAL_LINE(GPIOD, 24)
181# define D25 PAL_LINE(GPIOD, 25)
182# define D26 PAL_LINE(GPIOD, 26)
183# define D27 PAL_LINE(GPIOD, 27)
184# define D28 PAL_LINE(GPIOD, 28)
185# define D29 PAL_LINE(GPIOD, 29)
186# define D30 PAL_LINE(GPIOD, 30)
187# define D31 PAL_LINE(GPIOD, 31)
188# define D32 PAL_LINE(GPIOD, 32)
189# define E0 PAL_LINE(GPIOE, 0)
190# define E1 PAL_LINE(GPIOE, 1)
191# define E2 PAL_LINE(GPIOE, 2)
192# define E3 PAL_LINE(GPIOE, 3)
193# define E4 PAL_LINE(GPIOE, 4)
194# define E5 PAL_LINE(GPIOE, 5)
195# define E6 PAL_LINE(GPIOE, 6)
196# define E7 PAL_LINE(GPIOE, 7)
197# define E8 PAL_LINE(GPIOE, 8)
198# define E9 PAL_LINE(GPIOE, 9)
199# define E10 PAL_LINE(GPIOE, 10)
200# define E11 PAL_LINE(GPIOE, 11)
201# define E12 PAL_LINE(GPIOE, 12)
202# define E13 PAL_LINE(GPIOE, 13)
203# define E14 PAL_LINE(GPIOE, 14)
204# define E15 PAL_LINE(GPIOE, 15)
205# define E16 PAL_LINE(GPIOE, 16)
206# define E17 PAL_LINE(GPIOE, 17)
207# define E18 PAL_LINE(GPIOE, 18)
208# define E19 PAL_LINE(GPIOE, 19)
209# define E20 PAL_LINE(GPIOE, 20)
210# define E21 PAL_LINE(GPIOE, 21)
211# define E22 PAL_LINE(GPIOE, 22)
212# define E23 PAL_LINE(GPIOE, 23)
213# define E24 PAL_LINE(GPIOE, 24)
214# define E25 PAL_LINE(GPIOE, 25)
215# define E26 PAL_LINE(GPIOE, 26)
216# define E27 PAL_LINE(GPIOE, 27)
217# define E28 PAL_LINE(GPIOE, 28)
218# define E29 PAL_LINE(GPIOE, 29)
219# define E30 PAL_LINE(GPIOE, 30)
220# define E31 PAL_LINE(GPIOE, 31)
221# define E32 PAL_LINE(GPIOE, 32)
222# define F0 PAL_LINE(GPIOF, 0)
223# define F1 PAL_LINE(GPIOF, 1)
224# define F2 PAL_LINE(GPIOF, 2)
225# define F3 PAL_LINE(GPIOF, 3)
226# define F4 PAL_LINE(GPIOF, 4)
227# define F5 PAL_LINE(GPIOF, 5)
228# define F6 PAL_LINE(GPIOF, 6)
229# define F7 PAL_LINE(GPIOF, 7)
230# define F8 PAL_LINE(GPIOF, 8)
231# define F9 PAL_LINE(GPIOF, 9)
232# define F10 PAL_LINE(GPIOF, 10)
233# define F11 PAL_LINE(GPIOF, 11)
234# define F12 PAL_LINE(GPIOF, 12)
235# define F13 PAL_LINE(GPIOF, 13)
236# define F14 PAL_LINE(GPIOF, 14)
237# define F15 PAL_LINE(GPIOF, 15)
238# define G0 PAL_LINE(GPIOG, 0)
239# define G1 PAL_LINE(GPIOG, 1)
240# define G2 PAL_LINE(GPIOG, 2)
241# define G3 PAL_LINE(GPIOG, 3)
242# define G4 PAL_LINE(GPIOG, 4)
243# define G5 PAL_LINE(GPIOG, 5)
244# define G6 PAL_LINE(GPIOG, 6)
245# define G7 PAL_LINE(GPIOG, 7)
246# define G8 PAL_LINE(GPIOG, 8)
247# define G9 PAL_LINE(GPIOG, 9)
248# define G10 PAL_LINE(GPIOG, 10)
249# define G11 PAL_LINE(GPIOG, 11)
250# define G12 PAL_LINE(GPIOG, 12)
251# define G13 PAL_LINE(GPIOG, 13)
252# define G14 PAL_LINE(GPIOG, 14)
253# define G15 PAL_LINE(GPIOG, 15)
254# define H0 PAL_LINE(GPIOH, 0)
255# define H1 PAL_LINE(GPIOH, 1)
256# define H2 PAL_LINE(GPIOH, 2)
257# define H3 PAL_LINE(GPIOH, 3)
258# define H4 PAL_LINE(GPIOH, 4)
259# define H5 PAL_LINE(GPIOH, 5)
260# define H6 PAL_LINE(GPIOH, 6)
261# define H7 PAL_LINE(GPIOH, 7)
262# define H8 PAL_LINE(GPIOH, 8)
263# define H9 PAL_LINE(GPIOH, 9)
264# define H10 PAL_LINE(GPIOH, 10)
265# define H11 PAL_LINE(GPIOH, 11)
266# define H12 PAL_LINE(GPIOH, 12)
267# define H13 PAL_LINE(GPIOH, 13)
268# define H14 PAL_LINE(GPIOH, 14)
269# define H15 PAL_LINE(GPIOH, 15)
270# define I0 PAL_LINE(GPIOI, 0)
271# define I1 PAL_LINE(GPIOI, 1)
272# define I2 PAL_LINE(GPIOI, 2)
273# define I3 PAL_LINE(GPIOI, 3)
274# define I4 PAL_LINE(GPIOI, 4)
275# define I5 PAL_LINE(GPIOI, 5)
276# define I6 PAL_LINE(GPIOI, 6)
277# define I7 PAL_LINE(GPIOI, 7)
278# define I8 PAL_LINE(GPIOI, 8)
279# define I9 PAL_LINE(GPIOI, 9)
280# define I10 PAL_LINE(GPIOI, 10)
281# define I11 PAL_LINE(GPIOI, 11)
282# define I12 PAL_LINE(GPIOI, 12)
283# define I13 PAL_LINE(GPIOI, 13)
284# define I14 PAL_LINE(GPIOI, 14)
285# define I15 PAL_LINE(GPIOI, 15)
286# define J0 PAL_LINE(GPIOJ, 0)
287# define J1 PAL_LINE(GPIOJ, 1)
288# define J2 PAL_LINE(GPIOJ, 2)
289# define J3 PAL_LINE(GPIOJ, 3)
290# define J4 PAL_LINE(GPIOJ, 4)
291# define J5 PAL_LINE(GPIOJ, 5)
292# define J6 PAL_LINE(GPIOJ, 6)
293# define J7 PAL_LINE(GPIOJ, 7)
294# define J8 PAL_LINE(GPIOJ, 8)
295# define J9 PAL_LINE(GPIOJ, 9)
296# define J10 PAL_LINE(GPIOJ, 10)
297# define J11 PAL_LINE(GPIOJ, 11)
298# define J12 PAL_LINE(GPIOJ, 12)
299# define J13 PAL_LINE(GPIOJ, 13)
300# define J14 PAL_LINE(GPIOJ, 14)
301# define J15 PAL_LINE(GPIOJ, 15)
302// Keyboards can `#define KEYBOARD_REQUIRES_GPIOK` if they need to access GPIO-K pins. These conflict with a whole
303// bunch of layout definitions, so it's intentionally left out unless absolutely required -- in that case, the
304// keyboard designer should use a different symbol when defining their layout macros.
305# ifdef KEYBOARD_REQUIRES_GPIOK
306# define K0 PAL_LINE(GPIOK, 0)
307# define K1 PAL_LINE(GPIOK, 1)
308# define K2 PAL_LINE(GPIOK, 2)
309# define K3 PAL_LINE(GPIOK, 3)
310# define K4 PAL_LINE(GPIOK, 4)
311# define K5 PAL_LINE(GPIOK, 5)
312# define K6 PAL_LINE(GPIOK, 6)
313# define K7 PAL_LINE(GPIOK, 7)
314# define K8 PAL_LINE(GPIOK, 8)
315# define K9 PAL_LINE(GPIOK, 9)
316# define K10 PAL_LINE(GPIOK, 10)
317# define K11 PAL_LINE(GPIOK, 11)
318# define K12 PAL_LINE(GPIOK, 12)
319# define K13 PAL_LINE(GPIOK, 13)
320# define K14 PAL_LINE(GPIOK, 14)
321# define K15 PAL_LINE(GPIOK, 15)
322# endif
323#endif
diff --git a/platforms/chibios/platform.c b/platforms/chibios/platform.c
new file mode 100644
index 000000000..d4a229f27
--- /dev/null
+++ b/platforms/chibios/platform.c
@@ -0,0 +1,22 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "platform_deps.h"
18
19void platform_setup(void) {
20 halInit();
21 chSysInit();
22} \ No newline at end of file
diff --git a/platforms/chibios/platform.mk b/platforms/chibios/platform.mk
new file mode 100644
index 000000000..1c8d43007
--- /dev/null
+++ b/platforms/chibios/platform.mk
@@ -0,0 +1,439 @@
1# Hey Emacs, this is a -*- makefile -*-
2##############################################################################
3# Architecture or project specific options
4#
5
6# Stack size to be allocated to the Cortex-M process stack. This stack is
7# the stack used by the main() thread.
8ifeq ($(USE_PROCESS_STACKSIZE),)
9 USE_PROCESS_STACKSIZE = 0x800
10endif
11
12# Stack size to the allocated to the Cortex-M main/exceptions stack. This
13# stack is used for processing interrupts and exceptions.
14ifeq ($(USE_EXCEPTIONS_STACKSIZE),)
15 USE_EXCEPTIONS_STACKSIZE = 0x400
16endif
17
18#
19# Architecture or project specific options
20##############################################################################
21
22##############################################################################
23# Project, sources and paths
24#
25
26# Imported source files and paths
27OPT_OS = chibios
28CHIBIOS = $(TOP_DIR)/lib/chibios
29CHIBIOS_CONTRIB = $(TOP_DIR)/lib/chibios-contrib
30
31#
32# Startup, Port and Platform support selection
33##############################################################################
34
35ifeq ($(strip $(MCU)), risc-v)
36 # RISC-V Support
37 # As of 7.4.2021 there is only one supported RISC-V platform in Chibios-Contrib,
38 # therefore all required settings are hard-coded
39 STARTUP_MK = $(CHIBIOS_CONTRIB)/os/common/startup/RISCV-ECLIC/compilers/GCC/mk/startup_$(MCU_STARTUP).mk
40 PORT_V = $(CHIBIOS_CONTRIB)/os/common/ports/RISCV-ECLIC/compilers/GCC/mk/port.mk
41 RULESPATH = $(CHIBIOS_CONTRIB)/os/common/startup/RISCV-ECLIC/compilers/GCC
42 PLATFORM_MK = $(CHIBIOS_CONTRIB)/os/hal/ports/GD/GD32VF103/platform.mk
43else
44 # ARM Support
45 CHIBIOS_PORT ?=
46 ifeq ("$(CHIBIOS_PORT)","")
47 CHIBIOS_PORT = ARMv$(ARMV)-M
48 endif
49
50 # Startup files. Try a few different locations, for compability with old versions and
51 # for things hardware in the contrib repository
52 STARTUP_MK = $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC/mk/startup_$(MCU_STARTUP).mk
53 ifeq ("$(wildcard $(STARTUP_MK))","")
54 STARTUP_MK = $(CHIBIOS)/os/common/startup/ARMCMx/compilers/GCC/mk/startup_$(MCU_STARTUP).mk
55 ifeq ("$(wildcard $(STARTUP_MK))","")
56 STARTUP_MK = $(CHIBIOS_CONTRIB)/os/common/startup/ARMCMx/compilers/GCC/mk/startup_$(MCU_STARTUP).mk
57 endif
58 endif
59
60 # Port files. Try a few different locations, for compability with old versions and
61 # for things hardware in the contrib repository
62 PORT_V = $(CHIBIOS)/os/common/ports/$(CHIBIOS_PORT)/compilers/GCC/mk/port.mk
63 ifeq ("$(wildcard $(PORT_V))","")
64 PORT_V = $(CHIBIOS)/os/rt/ports/ARMCMx/compilers/GCC/mk/port_v$(ARMV)m.mk
65 ifeq ("$(wildcard $(PORT_V))","")
66 PORT_V = $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC/mk/port_v$(ARMV)m.mk
67 endif
68 endif
69
70 # Rules location. Try a few different locations, for compability with old versions and
71 # for things hardware in the contrib repository
72 RULESPATH = $(CHIBIOS)/os/common/ports/$(CHIBIOS_PORT)/compilers/GCC
73 ifeq ("$(wildcard $(RULESPATH)/rules.mk)","")
74 RULESPATH = $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC
75 ifeq ("$(wildcard $(RULESPATH)/rules.mk)","")
76 RULESPATH = $(CHIBIOS)/os/common/startup/ARMCMx/compilers/GCC
77 endif
78 endif
79endif
80
81ifeq ("$(PLATFORM_NAME)","")
82 PLATFORM_NAME = platform
83endif
84
85ifeq ("$(wildcard $(PLATFORM_MK))","")
86 PLATFORM_MK = $(CHIBIOS)/os/hal/ports/$(MCU_FAMILY)/$(MCU_SERIES)/$(PLATFORM_NAME).mk
87 ifeq ("$(wildcard $(PLATFORM_MK))","")
88 PLATFORM_MK = $(CHIBIOS_CONTRIB)/os/hal/ports/$(MCU_FAMILY)/$(MCU_SERIES)/$(PLATFORM_NAME).mk
89 endif
90endif
91
92include $(STARTUP_MK)
93include $(PORT_V)
94include $(PLATFORM_MK)
95
96#
97# Board support selection.
98##############################################################################
99
100BOARD_MK :=
101
102ifneq ("$(wildcard $(KEYBOARD_PATH_5)/boards/$(BOARD)/board.mk)","")
103 BOARD_PATH = $(KEYBOARD_PATH_5)
104 BOARD_MK += $(KEYBOARD_PATH_5)/boards/$(BOARD)/board.mk
105else ifneq ("$(wildcard $(KEYBOARD_PATH_4)/boards/$(BOARD)/board.mk)","")
106 BOARD_PATH = $(KEYBOARD_PATH_4)
107 BOARD_MK += $(KEYBOARD_PATH_4)/boards/$(BOARD)/board.mk
108else ifneq ("$(wildcard $(KEYBOARD_PATH_3)/boards/$(BOARD)/board.mk)","")
109 BOARD_PATH = $(KEYBOARD_PATH_3)
110 BOARD_MK += $(KEYBOARD_PATH_3)/boards/$(BOARD)/board.mk
111else ifneq ("$(wildcard $(KEYBOARD_PATH_2)/boards/$(BOARD)/board.mk)","")
112 BOARD_PATH = $(KEYBOARD_PATH_2)
113 BOARD_MK += $(KEYBOARD_PATH_2)/boards/$(BOARD)/board.mk
114else ifneq ("$(wildcard $(KEYBOARD_PATH_1)/boards/$(BOARD)/board.mk)","")
115 BOARD_PATH = $(KEYBOARD_PATH_1)
116 BOARD_MK += $(KEYBOARD_PATH_1)/boards/$(BOARD)/board.mk
117else ifneq ("$(wildcard $(TOP_DIR)/platforms/chibios/boards/$(BOARD)/board/board.mk)","")
118 BOARD_PATH = $(TOP_DIR)/platforms/chibios/boards/$(BOARD)
119 BOARD_MK += $(TOP_DIR)/platforms/chibios/boards/$(BOARD)/board/board.mk
120 KEYBOARD_PATHS += $(BOARD_PATH)/configs
121 ifneq ("$(wildcard $(BOARD_PATH)/rules.mk)","")
122 include $(BOARD_PATH)/rules.mk
123 endif
124endif
125
126ifeq ("$(wildcard $(BOARD_MK))","")
127 BOARD_MK = $(CHIBIOS)/os/hal/boards/$(BOARD)/board.mk
128 ifeq ("$(wildcard $(BOARD_MK))","")
129 BOARD_MK = $(CHIBIOS_CONTRIB)/os/hal/boards/$(BOARD)/board.mk
130 endif
131endif
132
133include $(BOARD_MK)
134
135#
136# Bootloader selection.
137##############################################################################
138
139# Set bootloader address if supplied.
140ifdef STM32_BOOTLOADER_ADDRESS
141 OPT_DEFS += -DSTM32_BOOTLOADER_ADDRESS=$(STM32_BOOTLOADER_ADDRESS)
142endif
143
144# Work out if we need to set up the include for the bootloader definitions
145ifneq ("$(wildcard $(KEYBOARD_PATH_5)/bootloader_defs.h)","")
146 OPT_DEFS += -include $(KEYBOARD_PATH_5)/bootloader_defs.h
147else ifneq ("$(wildcard $(KEYBOARD_PATH_5)/boards/$(BOARD)/bootloader_defs.h)","")
148 OPT_DEFS += -include $(KEYBOARD_PATH_5)/boards/$(BOARD)/bootloader_defs.h
149else ifneq ("$(wildcard $(KEYBOARD_PATH_4)/bootloader_defs.h)","")
150 OPT_DEFS += -include $(KEYBOARD_PATH_4)/bootloader_defs.h
151else ifneq ("$(wildcard $(KEYBOARD_PATH_4)/boards/$(BOARD)/bootloader_defs.h)","")
152 OPT_DEFS += -include $(KEYBOARD_PATH_4)/boards/$(BOARD)/bootloader_defs.h
153else ifneq ("$(wildcard $(KEYBOARD_PATH_3)/bootloader_defs.h)","")
154 OPT_DEFS += -include $(KEYBOARD_PATH_3)/bootloader_defs.h
155else ifneq ("$(wildcard $(KEYBOARD_PATH_3)/boards/$(BOARD)/bootloader_defs.h)","")
156 OPT_DEFS += -include $(KEYBOARD_PATH_3)/boards/$(BOARD)/bootloader_defs.h
157else ifneq ("$(wildcard $(KEYBOARD_PATH_2)/bootloader_defs.h)","")
158 OPT_DEFS += -include $(KEYBOARD_PATH_2)/bootloader_defs.h
159else ifneq ("$(wildcard $(KEYBOARD_PATH_2)/boards/$(BOARD)/bootloader_defs.h)","")
160 OPT_DEFS += -include $(KEYBOARD_PATH_2)/boards/$(BOARD)/bootloader_defs.h
161else ifneq ("$(wildcard $(KEYBOARD_PATH_1)/bootloader_defs.h)","")
162 OPT_DEFS += -include $(KEYBOARD_PATH_1)/bootloader_defs.h
163else ifneq ("$(wildcard $(KEYBOARD_PATH_1)/boards/$(BOARD)/bootloader_defs.h)","")
164 OPT_DEFS += -include $(KEYBOARD_PATH_1)/boards/$(BOARD)/bootloader_defs.h
165else ifneq ("$(wildcard $(BOARD_PATH)/configs/bootloader_defs.h)","")
166 OPT_DEFS += -include $(BOARD_PATH)/configs/bootloader_defs.h
167endif
168
169#
170# ChibiOS config selection.
171##############################################################################
172
173# Work out the config file directories
174ifneq ("$(wildcard $(KEYBOARD_PATH_5)/chconf.h)","")
175 CHCONFDIR = $(KEYBOARD_PATH_5)
176else ifneq ("$(wildcard $(KEYBOARD_PATH_4)/chconf.h)","")
177 CHCONFDIR = $(KEYBOARD_PATH_4)
178else ifneq ("$(wildcard $(KEYBOARD_PATH_3)/chconf.h)","")
179 CHCONFDIR = $(KEYBOARD_PATH_3)
180else ifneq ("$(wildcard $(KEYBOARD_PATH_2)/chconf.h)","")
181 CHCONFDIR = $(KEYBOARD_PATH_2)
182else ifneq ("$(wildcard $(KEYBOARD_PATH_1)/chconf.h)","")
183 CHCONFDIR = $(KEYBOARD_PATH_1)
184else ifneq ("$(wildcard $(TOP_DIR)/platforms/chibios/boards/$(BOARD)/configs/chconf.h)","")
185 CHCONFDIR = $(TOP_DIR)/platforms/chibios/boards/$(BOARD)/configs
186else ifneq ("$(wildcard $(TOP_DIR)/platforms/boards/chibios/common/configs/chconf.h)","")
187 CHCONFDIR = $(TOP_DIR)/platforms/chibios/boards/common/configs
188endif
189
190#
191# HAL config selection.
192##############################################################################
193
194ifneq ("$(wildcard $(KEYBOARD_PATH_5)/halconf.h)","")
195 HALCONFDIR = $(KEYBOARD_PATH_5)
196else ifneq ("$(wildcard $(KEYBOARD_PATH_4)/halconf.h)","")
197 HALCONFDIR = $(KEYBOARD_PATH_4)
198else ifneq ("$(wildcard $(KEYBOARD_PATH_3)/halconf.h)","")
199 HALCONFDIR = $(KEYBOARD_PATH_3)
200else ifneq ("$(wildcard $(KEYBOARD_PATH_2)/halconf.h)","")
201 HALCONFDIR = $(KEYBOARD_PATH_2)
202else ifneq ("$(wildcard $(KEYBOARD_PATH_1)/halconf.h)","")
203 HALCONFDIR = $(KEYBOARD_PATH_1)
204else ifneq ("$(wildcard $(TOP_DIR)/platforms/chibios/boards/$(BOARD)/configs/halconf.h)","")
205 HALCONFDIR = $(TOP_DIR)/platforms/chibios/boards/$(BOARD)/configs
206else ifneq ("$(wildcard $(TOP_DIR)/platforms/chibios/boards/common/configs/halconf.h)","")
207 HALCONFDIR = $(TOP_DIR)/platforms/chibios/boards/common/configs
208endif
209
210#
211# Linker script selection.
212##############################################################################
213
214ifneq ("$(wildcard $(KEYBOARD_PATH_5)/ld/$(MCU_LDSCRIPT).ld)","")
215 LDSCRIPT = $(KEYBOARD_PATH_5)/ld/$(MCU_LDSCRIPT).ld
216else ifneq ("$(wildcard $(KEYBOARD_PATH_4)/ld/$(MCU_LDSCRIPT).ld)","")
217 LDSCRIPT = $(KEYBOARD_PATH_4)/ld/$(MCU_LDSCRIPT).ld
218else ifneq ("$(wildcard $(KEYBOARD_PATH_3)/ld/$(MCU_LDSCRIPT).ld)","")
219 LDSCRIPT = $(KEYBOARD_PATH_3)/ld/$(MCU_LDSCRIPT).ld
220else ifneq ("$(wildcard $(KEYBOARD_PATH_2)/ld/$(MCU_LDSCRIPT).ld)","")
221 LDSCRIPT = $(KEYBOARD_PATH_2)/ld/$(MCU_LDSCRIPT).ld
222else ifneq ("$(wildcard $(KEYBOARD_PATH_1)/ld/$(MCU_LDSCRIPT).ld)","")
223 LDSCRIPT = $(KEYBOARD_PATH_1)/ld/$(MCU_LDSCRIPT).ld
224else ifneq ("$(wildcard $(TOP_DIR)/platforms/chibios/boards/$(BOARD)/ld/$(MCU_LDSCRIPT).ld)","")
225 LDFLAGS += -L$(TOP_DIR)/platforms/chibios/boards/$(BOARD)/ld
226 LDSCRIPT = $(TOP_DIR)/platforms/chibios/boards/$(BOARD)/ld/$(MCU_LDSCRIPT).ld
227else ifneq ("$(wildcard $(TOP_DIR)/platforms/chibios/boards/common/ld/$(MCU_LDSCRIPT).ld)","")
228 LDSCRIPT = $(TOP_DIR)/platforms/chibios/boards/common/ld/$(MCU_LDSCRIPT).ld
229else ifneq ("$(wildcard $(STARTUPLD_CONTRIB)/$(MCU_LDSCRIPT).ld)","")
230 LDSCRIPT = $(STARTUPLD_CONTRIB)/$(MCU_LDSCRIPT).ld
231 USE_CHIBIOS_CONTRIB = yes
232else
233 LDSCRIPT = $(STARTUPLD)/$(MCU_LDSCRIPT).ld
234endif
235
236#
237# Include ChibiOS makefiles.
238##############################################################################
239
240# HAL-OSAL files (optional).
241include $(CHIBIOS)/os/hal/hal.mk
242-include $(CHIBIOS)/os/hal/osal/rt/osal.mk # ChibiOS <= 19.x
243-include $(CHIBIOS)/os/hal/osal/rt-nil/osal.mk # ChibiOS >= 20.x
244# RTOS files (optional).
245include $(CHIBIOS)/os/rt/rt.mk
246# Other files (optional).
247include $(CHIBIOS)/os/hal/lib/streams/streams.mk
248
249PLATFORM_SRC = \
250 $(STARTUPSRC) \
251 $(KERNSRC) \
252 $(PORTSRC) \
253 $(OSALSRC) \
254 $(HALSRC) \
255 $(PLATFORMSRC) \
256 $(BOARDSRC) \
257 $(STREAMSSRC) \
258 $(CHIBIOS)/os/various/syscalls.c \
259 $(PLATFORM_COMMON_DIR)/syscall-fallbacks.c \
260 $(PLATFORM_COMMON_DIR)/wait.c
261
262# Ensure the ASM files are not subjected to LTO -- it'll strip out interrupt handlers otherwise.
263QUANTUM_LIB_SRC += $(STARTUPASM) $(PORTASM) $(OSALASM) $(PLATFORMASM)
264
265PLATFORM_SRC := $(patsubst $(TOP_DIR)/%,%,$(PLATFORM_SRC))
266
267EXTRAINCDIRS += $(CHIBIOS)/os/license $(CHIBIOS)/os/oslib/include \
268 $(TOP_DIR)/platforms/chibios/boards/$(BOARD)/configs \
269 $(TOP_DIR)/platforms/chibios/boards/common/configs \
270 $(HALCONFDIR) $(CHCONFDIR) \
271 $(STARTUPINC) $(KERNINC) $(PORTINC) $(OSALINC) \
272 $(HALINC) $(PLATFORMINC) $(BOARDINC) $(TESTINC) \
273 $(STREAMSINC) $(CHIBIOS)/os/various $(COMMON_VPATH)
274
275#
276# ChibiOS-Contrib
277##############################################################################
278
279# Work out if we're using ChibiOS-Contrib by checking if halconf_community.h exists
280ifneq ("$(wildcard $(KEYBOARD_PATH_5)/halconf_community.h)","")
281 USE_CHIBIOS_CONTRIB = yes
282else ifneq ("$(wildcard $(KEYBOARD_PATH_4)/halconf_community.h)","")
283 USE_CHIBIOS_CONTRIB = yes
284else ifneq ("$(wildcard $(KEYBOARD_PATH_3)/halconf_community.h)","")
285 USE_CHIBIOS_CONTRIB = yes
286else ifneq ("$(wildcard $(KEYBOARD_PATH_2)/halconf_community.h)","")
287 USE_CHIBIOS_CONTRIB = yes
288else ifneq ("$(wildcard $(KEYBOARD_PATH_1)/halconf_community.h)","")
289 USE_CHIBIOS_CONTRIB = yes
290else ifneq ("$(wildcard $(TOP_DIR)/platforms/chibios/boards/$(BOARD)/configs/halconf_community.h)","")
291 USE_CHIBIOS_CONTRIB = yes
292endif
293
294ifeq ($(strip $(USE_CHIBIOS_CONTRIB)),yes)
295 include $(CHIBIOS_CONTRIB)/os/hal/hal.mk
296 PLATFORM_SRC += $(PLATFORMSRC_CONTRIB) $(HALSRC_CONTRIB)
297 EXTRAINCDIRS += $(PLATFORMINC_CONTRIB) $(HALINC_CONTRIB) $(CHIBIOS_CONTRIB)/os/various
298endif
299
300#
301# Project, sources and paths
302##############################################################################
303
304##############################################################################
305# Injected configs
306#
307ifneq ("$(wildcard $(BOARD_PATH)/configs/config.h)","")
308 CONFIG_H += $(BOARD_PATH)/configs/config.h
309endif
310ifneq ("$(wildcard $(BOARD_PATH)/configs/post_config.h)","")
311 POST_CONFIG_H += $(BOARD_PATH)/configs/post_config.h
312endif
313
314##############################################################################
315# Compiler and Linker configuration
316#
317
318# Use defined stack sizes of the main thread in linker scripts
319SHARED_LDSYMBOLS = -Wl,--defsym=__process_stack_size__=$(USE_PROCESS_STACKSIZE),--defsym=__main_stack_size__=$(USE_EXCEPTIONS_STACKSIZE)
320
321# Shared Compiler flags for all toolchains
322SHARED_CFLAGS = -fomit-frame-pointer \
323 -ffunction-sections \
324 -fdata-sections \
325 -fno-common \
326 -fshort-wchar
327
328# Shared Linker flags for all toolchains
329SHARED_LDFLAGS = -T $(LDSCRIPT) \
330 -Wl,--gc-sections \
331 -nostartfiles
332
333ifeq ($(strip $(MCU)), risc-v)
334 # RISC-V toolchain specific configuration
335 # Find suitable GCC compiler
336 ifeq ($(strip $(TOOLCHAIN)),)
337 ifneq ($(shell which riscv32-unknown-elf-gcc 2>/dev/null),)
338 TOOLCHAIN = riscv32-unknown-elf-
339 else
340 ifneq ($(shell which riscv64-unknown-elf-gcc 2>/dev/null),)
341 TOOLCHAIN = riscv64-unknown-elf-
342 else
343 $(error "No RISC-V toolchain found. Can't find riscv32-unknown-elf-gcc or riscv64-unknown-elf-gcc found in your systems PATH variable. Please install a valid toolchain and make it accessible!")
344 endif
345 endif
346 endif
347
348 # Default to compiling with picolibc for RISC-V targets if available, which
349 # is available by default on distributions based on Debian 11+.
350 ifeq ($(shell $(TOOLCHAIN)gcc --specs=picolibc.specs -E - 2>/dev/null >/dev/null </dev/null ; echo $$?),0)
351 # Toolchain specific Compiler flags Note that we still link with our own
352 # linker script by providing it via the -T flag in SHARED_LDFLAGS.
353 TOOLCHAIN_CFLAGS = --specs=picolibc.specs
354
355 # picolibc internally uses __heap_start and __heap_end instead of the
356 # defacto chibios linker script standard __heap_base__ and __heap_end__
357 # therefore we introduce these symbols as an alias.
358 TOOLCHAIN_LDSYMBOLS = -Wl,--defsym=__heap_start=__heap_base__,--defsym=__heap_end=__heap_end__
359
360 # Tell QMK that we are compiling with picolibc.
361 OPT_DEFS += -DUSE_PICOLIBC
362 endif
363
364 # MCU architecture flags
365 MCUFLAGS = -march=$(MCU_ARCH) \
366 -mabi=$(MCU_ABI) \
367 -mcmodel=$(MCU_CMODEL) \
368 -mstrict-align
369else
370 # ARM toolchain specific configuration
371 TOOLCHAIN ?= arm-none-eabi-
372
373 # Toolchain specific Linker flags
374 TOOLCHAIN_LDFLAGS = -Wl,--no-wchar-size-warning \
375 --specs=nano.specs
376
377 # MCU architecture flags
378 MCUFLAGS = -mcpu=$(MCU) \
379 -mthumb -DTHUMB_PRESENT \
380 -mno-thumb-interwork -DTHUMB_NO_INTERWORKING \
381 -mno-unaligned-access
382
383 # Some ARM cores like the M4 and M7 have floating point units which can be enabled
384 USE_FPU ?= no
385
386 ifneq ($(USE_FPU),no)
387 OPT_DEFS += -DCORTEX_USE_FPU=TRUE
388
389 # Default is single precision floats
390 USE_FPU_OPT ?= -mfloat-abi=hard \
391 -mfpu=fpv4-sp-d16 \
392 -fsingle-precision-constant
393
394 MCUFLAGS += $(USE_FPU_OPT)
395 else
396 OPT_DEFS += -DCORTEX_USE_FPU=FALSE
397 endif
398endif
399
400# Assembler flags
401ASFLAGS += $(SHARED_ASFLAGS) $(TOOLCHAIN_ASFLAGS)
402
403# C Compiler flags
404CFLAGS += $(SHARED_CFLAGS) $(TOOLCHAIN_CFLAGS)
405
406# C++ Compiler flags
407CXXFLAGS += $(CFLAGS) $(SHARED_CXXFLAGS) $(TOOLCHAIN_CXXFLAGS) -fno-rtti
408
409# Linker flags
410LDFLAGS += $(SHARED_LDFLAGS) $(SHARED_LDSYMBOLS) $(TOOLCHAIN_LDFLAGS) $(TOOLCHAIN_LDSYMBOLS) $(MCUFLAGS)
411
412# Tell QMK that we are hosting it on ChibiOS.
413OPT_DEFS += -DPROTOCOL_CHIBIOS
414
415# Workaround to stop ChibiOS from complaining about new GCC -- it's been fixed for 7/8/9 already
416OPT_DEFS += -DPORT_IGNORE_GCC_VERSION_CHECK=1
417
418# Construct GCC toolchain
419CC = $(CC_PREFIX) $(TOOLCHAIN)gcc
420OBJCOPY = $(TOOLCHAIN)objcopy
421OBJDUMP = $(TOOLCHAIN)objdump
422SIZE = $(TOOLCHAIN)size
423AR = $(TOOLCHAIN)ar
424NM = $(TOOLCHAIN)nm
425HEX = $(OBJCOPY) -O $(FORMAT)
426EEP =
427BIN = $(OBJCOPY) -O binary
428
429##############################################################################
430# Make targets
431#
432
433DEBUG = gdb
434
435# List any extra directories to look for libraries here.
436EXTRALIBDIRS = $(RULESPATH)/ld
437
438bin: $(BUILD_DIR)/$(TARGET).bin sizeafter
439 $(COPY) $(BUILD_DIR)/$(TARGET).bin $(TARGET).bin;
diff --git a/platforms/chibios/platform_deps.h b/platforms/chibios/platform_deps.h
new file mode 100644
index 000000000..8243dcec5
--- /dev/null
+++ b/platforms/chibios/platform_deps.h
@@ -0,0 +1,19 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#pragma once
17
18#include <hal.h>
19#include "chibios_config.h"
diff --git a/platforms/chibios/sleep_led.c b/platforms/chibios/sleep_led.c
new file mode 100644
index 000000000..477056a45
--- /dev/null
+++ b/platforms/chibios/sleep_led.c
@@ -0,0 +1,192 @@
1#include <ch.h>
2#include <hal.h>
3
4#include "led.h"
5#include "sleep_led.h"
6
7/* All right, we go the "software" way: timer, toggle LED in interrupt.
8 * Based on hasu's code for AVRs.
9 * Use LP timer on Kinetises, TIM14 on STM32F0.
10 */
11
12#ifndef SLEEP_LED_GPT_DRIVER
13# if defined(STM32F0XX)
14# define SLEEP_LED_GPT_DRIVER GPTD14
15# endif
16#endif
17
18#if defined(KL2x) || defined(K20x) || defined(SLEEP_LED_GPT_DRIVER) /* common parts for timers/interrupts */
19
20/* Breathing Sleep LED brighness(PWM On period) table
21 * (64[steps] * 4[duration]) / 64[PWM periods/s] = 4 second breath cycle
22 *
23 * http://www.wolframalpha.com/input/?i=%28sin%28+x%2F64*pi%29**8+*+255%2C+x%3D0+to+63
24 * (0..63).each {|x| p ((sin(x/64.0*PI)**8)*255).to_i }
25 */
26static const uint8_t breathing_table[64] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 6, 10, 15, 23, 32, 44, 58, 74, 93, 113, 135, 157, 179, 199, 218, 233, 245, 252, 255, 252, 245, 233, 218, 199, 179, 157, 135, 113, 93, 74, 58, 44, 32, 23, 15, 10, 6, 4, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
27
28void sleep_led_timer_callback(void) {
29 /* Software PWM
30 * timer:1111 1111 1111 1111
31 * \_____/\/ \_______/____ count(0-255)
32 * \ \______________ duration of step(4)
33 * \__________________ index of step table(0-63)
34 */
35
36 // this works for cca 65536 irqs/sec
37 static union {
38 uint16_t row;
39 struct {
40 uint8_t count : 8;
41 uint8_t duration : 2;
42 uint8_t index : 6;
43 } pwm;
44 } timer = {.row = 0};
45
46 timer.row++;
47
48 // LED on
49 if (timer.pwm.count == 0) {
50 led_set(1 << USB_LED_CAPS_LOCK);
51 }
52 // LED off
53 if (timer.pwm.count == breathing_table[timer.pwm.index]) {
54 led_set(0);
55 }
56}
57
58#endif /* common parts for known platforms */
59
60#if defined(KL2x) || defined(K20x) /* platform selection: familiar Kinetis chips */
61
62/* Use Low Power Timer (LPTMR) */
63# define TIMER_INTERRUPT_VECTOR KINETIS_LPTMR0_IRQ_VECTOR
64# define RESET_COUNTER LPTMR0->CSR |= LPTMRx_CSR_TCF
65
66/* LPTMR clock options */
67# define LPTMR_CLOCK_MCGIRCLK 0 /* 4MHz clock */
68# define LPTMR_CLOCK_LPO 1 /* 1kHz clock */
69# define LPTMR_CLOCK_ERCLK32K 2 /* external 32kHz crystal */
70# define LPTMR_CLOCK_OSCERCLK 3 /* output from OSC */
71
72/* Work around inconsistencies in Freescale naming */
73# if !defined(SIM_SCGC5_LPTMR)
74# define SIM_SCGC5_LPTMR SIM_SCGC5_LPTIMER
75# endif
76
77/* interrupt handler */
78OSAL_IRQ_HANDLER(TIMER_INTERRUPT_VECTOR) {
79 OSAL_IRQ_PROLOGUE();
80
81 sleep_led_timer_callback();
82
83 /* Reset the counter */
84 RESET_COUNTER;
85
86 OSAL_IRQ_EPILOGUE();
87}
88
89/* Initialise the timer */
90void sleep_led_init(void) {
91 /* Make sure the clock to the LPTMR is enabled */
92 SIM->SCGC5 |= SIM_SCGC5_LPTMR;
93 /* Reset LPTMR settings */
94 LPTMR0->CSR = 0;
95 /* Set the compare value */
96 LPTMR0->CMR = 0; // trigger on counter value (i.e. every time)
97
98/* Set up clock source and prescaler */
99/* Software PWM
100 * ______ ______ __
101 * | ON |___OFF___| ON |___OFF___| ....
102 * |<-------------->|<-------------->|<- ....
103 * PWM period PWM period
104 *
105 * R interrupts/period[resolution]
106 * F periods/second[frequency]
107 * R * F interrupts/second
108 */
109
110/* === OPTION 1 === */
111# if 0
112 // 1kHz LPO
113 // No prescaler => 1024 irqs/sec
114 // Note: this is too slow for a smooth breathe
115 LPTMR0->PSR = LPTMRx_PSR_PCS(LPTMR_CLOCK_LPO)|LPTMRx_PSR_PBYP;
116# endif /* OPTION 1 */
117
118/* === OPTION 2 === */
119# if 1
120 // nMHz IRC (n=4 on KL25Z, KL26Z and K20x; n=2 or 8 on KL27Z)
121 MCG->C2 |= MCG_C2_IRCS; // fast (4MHz) internal ref clock
122# if defined(KL27) // divide the 8MHz IRC by 2, to have the same MCGIRCLK speed as others
123 MCG->MC |= MCG_MC_LIRC_DIV2_DIV2;
124# endif /* KL27 */
125 MCG->C1 |= MCG_C1_IRCLKEN; // enable internal ref clock
126 // to work in stop mode, also MCG_C1_IREFSTEN
127 // Divide 4MHz by 2^N (N=6) => 62500 irqs/sec =>
128 // => approx F=61, R=256, duration = 4
129 LPTMR0->PSR = LPTMRx_PSR_PCS(LPTMR_CLOCK_MCGIRCLK) | LPTMRx_PSR_PRESCALE(6);
130# endif /* OPTION 2 */
131
132/* === OPTION 3 === */
133# if 0
134 // OSC output (external crystal), usually 8MHz or 16MHz
135 OSC0->CR |= OSC_CR_ERCLKEN; // enable ext ref clock
136 // to work in stop mode, also OSC_CR_EREFSTEN
137 // Divide by 2^N
138 LPTMR0->PSR = LPTMRx_PSR_PCS(LPTMR_CLOCK_OSCERCLK)|LPTMRx_PSR_PRESCALE(7);
139# endif /* OPTION 3 */
140 /* === END OPTIONS === */
141
142 /* Interrupt on TCF set (compare flag) */
143 nvicEnableVector(LPTMR0_IRQn, 2); // vector, priority
144 LPTMR0->CSR |= LPTMRx_CSR_TIE;
145}
146
147void sleep_led_enable(void) {
148 /* Enable the timer */
149 LPTMR0->CSR |= LPTMRx_CSR_TEN;
150}
151
152void sleep_led_disable(void) {
153 /* Disable the timer */
154 LPTMR0->CSR &= ~LPTMRx_CSR_TEN;
155}
156
157void sleep_led_toggle(void) {
158 /* Toggle the timer */
159 LPTMR0->CSR ^= LPTMRx_CSR_TEN;
160}
161
162#elif defined(SLEEP_LED_GPT_DRIVER)
163
164static void gptTimerCallback(GPTDriver *gptp) {
165 (void)gptp;
166 sleep_led_timer_callback();
167}
168
169static const GPTConfig gptcfg = {1000000, gptTimerCallback, 0, 0};
170
171/* Initialise the timer */
172void sleep_led_init(void) { gptStart(&SLEEP_LED_GPT_DRIVER, &gptcfg); }
173
174void sleep_led_enable(void) { gptStartContinuous(&SLEEP_LED_GPT_DRIVER, gptcfg.frequency / 0xFFFF); }
175
176void sleep_led_disable(void) { gptStopTimer(&SLEEP_LED_GPT_DRIVER); }
177
178void sleep_led_toggle(void) { (SLEEP_LED_GPT_DRIVER.state == GPT_READY) ? sleep_led_enable() : sleep_led_disable(); }
179
180#else /* platform selection: not on familiar chips */
181
182void sleep_led_init(void) {}
183
184void sleep_led_enable(void) { led_set(1 << USB_LED_CAPS_LOCK); }
185
186void sleep_led_disable(void) { led_set(0); }
187
188void sleep_led_toggle(void) {
189 // not implemented
190}
191
192#endif /* platform selection */
diff --git a/platforms/chibios/suspend.c b/platforms/chibios/suspend.c
new file mode 100644
index 000000000..9310a9992
--- /dev/null
+++ b/platforms/chibios/suspend.c
@@ -0,0 +1,92 @@
1/* TODO */
2
3#include <ch.h>
4#include <hal.h>
5
6#include "matrix.h"
7#include "action.h"
8#include "action_util.h"
9#include "mousekey.h"
10#include "programmable_button.h"
11#include "host.h"
12#include "suspend.h"
13#include "led.h"
14#include "wait.h"
15
16/** \brief suspend idle
17 *
18 * FIXME: needs doc
19 */
20void suspend_idle(uint8_t time) {
21 // TODO: this is not used anywhere - what units is 'time' in?
22 wait_ms(time);
23}
24
25/** \brief suspend power down
26 *
27 * FIXME: needs doc
28 */
29void suspend_power_down(void) {
30 suspend_power_down_quantum();
31 // on AVR, this enables the watchdog for 15ms (max), and goes to
32 // SLEEP_MODE_PWR_DOWN
33
34 wait_ms(17);
35}
36
37/** \brief suspend wakeup condition
38 *
39 * FIXME: needs doc
40 */
41__attribute__((weak)) void matrix_power_up(void) {}
42__attribute__((weak)) void matrix_power_down(void) {}
43bool suspend_wakeup_condition(void) {
44 matrix_power_up();
45 matrix_scan();
46 matrix_power_down();
47 for (uint8_t r = 0; r < MATRIX_ROWS; r++) {
48 if (matrix_get_row(r)) return true;
49 }
50 return false;
51}
52
53/** \brief run user level code immediately after wakeup
54 *
55 * FIXME: needs doc
56 */
57__attribute__((weak)) void suspend_wakeup_init_user(void) {}
58
59/** \brief run keyboard level code immediately after wakeup
60 *
61 * FIXME: needs doc
62 */
63__attribute__((weak)) void suspend_wakeup_init_kb(void) { suspend_wakeup_init_user(); }
64
65/** \brief suspend wakeup condition
66 *
67 * run immediately after wakeup
68 * FIXME: needs doc
69 */
70void suspend_wakeup_init(void) {
71 // clear keyboard state
72 // need to do it manually, because we're running from ISR
73 // and clear_keyboard() calls print
74 // so only clear the variables in memory
75 // the reports will be sent from main.c afterwards
76 // or if the PC asks for GET_REPORT
77 clear_mods();
78 clear_weak_mods();
79 clear_keys();
80#ifdef MOUSEKEY_ENABLE
81 mousekey_clear();
82#endif /* MOUSEKEY_ENABLE */
83#ifdef PROGRAMMABLE_BUTTON_ENABLE
84 programmable_button_clear();
85#endif /* PROGRAMMABLE_BUTTON_ENABLE */
86#ifdef EXTRAKEY_ENABLE
87 host_system_send(0);
88 host_consumer_send(0);
89#endif /* EXTRAKEY_ENABLE */
90
91 suspend_wakeup_init_quantum();
92}
diff --git a/platforms/chibios/syscall-fallbacks.c b/platforms/chibios/syscall-fallbacks.c
new file mode 100644
index 000000000..7150a4632
--- /dev/null
+++ b/platforms/chibios/syscall-fallbacks.c
@@ -0,0 +1,111 @@
1/* Copyright 2021 Nick Brassel, QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include <errno.h>
18#include <sys/stat.h>
19#include <sys/types.h>
20
21/* To compile the ChibiOS syscall stubs with picolibc
22 * the _reent struct has to be defined. */
23#if defined(USE_PICOLIBC)
24struct _reent;
25struct timeval;
26#endif
27
28#pragma GCC diagnostic ignored "-Wmissing-prototypes"
29
30__attribute__((weak, used)) int _open_r(struct _reent *r, const char *path, int flag, int m) {
31 __errno_r(r) = ENOENT;
32 return -1;
33}
34
35__attribute__((weak, used)) int _lseek_r(struct _reent *r, int file, int ptr, int dir) {
36 __errno_r(r) = EBADF;
37 return -1;
38}
39
40__attribute__((weak, used)) int _read_r(struct _reent *r, int file, char *ptr, int len) {
41 __errno_r(r) = EBADF;
42 return -1;
43}
44
45__attribute__((weak, used)) int _write_r(struct _reent *r, int file, char *ptr, int len) {
46 __errno_r(r) = EBADF;
47 return -1;
48}
49
50__attribute__((weak, used)) int _close_r(struct _reent *r, int file) {
51 __errno_r(r) = EBADF;
52 return -1;
53}
54
55__attribute__((weak, used)) int _link_r(struct _reent *r, const char *oldpath, const char *newpath) {
56 __errno_r(r) = EPERM;
57 return -1;
58}
59
60__attribute__((weak, used)) int _unlink_r(struct _reent *r, const char *path) {
61 __errno_r(r) = EPERM;
62 return -1;
63}
64
65__attribute__((weak, used)) clock_t _times_r(struct _reent *r, void *t) {
66 __errno_r(r) = EFAULT;
67 return -1;
68}
69
70__attribute__((weak, used)) int _fstat_r(struct _reent *r, int file, struct stat *st) {
71 __errno_r(r) = EBADF;
72 return -1;
73}
74
75__attribute__((weak, used)) int _isatty_r(struct _reent *r, int fd) {
76 __errno_r(r) = EBADF;
77 return 0;
78}
79
80__attribute__((weak, used)) caddr_t _sbrk_r(struct _reent *r, int incr) {
81 __errno_r(r) = ENOMEM;
82 return (caddr_t)-1;
83}
84
85__attribute__((weak, used)) int _kill(int pid, int sig) {
86 errno = EPERM;
87 return -1;
88}
89
90__attribute__((weak, used)) pid_t _getpid(void) { return 1; }
91
92__attribute__((weak, used)) void _fini(void) { return; }
93
94__attribute__((weak, used, noreturn)) void _exit(int i) {
95 while (1)
96 ;
97}
98
99__attribute__((weak, used)) int _gettimeofday_r(struct _reent *r, struct timeval *t, void *tzp) {
100 __errno_r(r) = EPERM;
101 return -1;
102}
103
104__attribute__((weak, used)) void *__dso_handle;
105
106__attribute__((weak, used)) void __cxa_pure_virtual(void) {
107 while (1)
108 ;
109}
110
111#pragma GCC diagnostic pop
diff --git a/platforms/chibios/timer.c b/platforms/chibios/timer.c
new file mode 100644
index 000000000..9f664e1f7
--- /dev/null
+++ b/platforms/chibios/timer.c
@@ -0,0 +1,47 @@
1#include <ch.h>
2
3#include "timer.h"
4
5static uint32_t reset_point = 0;
6#if CH_CFG_ST_RESOLUTION < 32
7static uint32_t last_systime = 0;
8static uint32_t overflow = 0;
9#endif
10
11void timer_init(void) { timer_clear(); }
12
13void timer_clear(void) {
14 reset_point = (uint32_t)chVTGetSystemTime();
15#if CH_CFG_ST_RESOLUTION < 32
16 last_systime = reset_point;
17 overflow = 0;
18#endif
19}
20
21uint16_t timer_read(void) { return (uint16_t)timer_read32(); }
22
23uint32_t timer_read32(void) {
24 uint32_t systime = (uint32_t)chVTGetSystemTime();
25
26#if CH_CFG_ST_RESOLUTION < 32
27 // If/when we need to support 64-bit chips, this may need to be modified to match the native bit-ness of the MCU.
28 // At this point, the only SysTick resolution allowed other than 32 is 16 bit.
29 // In the 16-bit case, at:
30 // - CH_CFG_ST_FREQUENCY = 100000, overflow will occur every ~0.65 seconds
31 // - CH_CFG_ST_FREQUENCY = 10000, overflow will occur every ~6.5 seconds
32 // - CH_CFG_ST_FREQUENCY = 1000, overflow will occur every ~65 seconds
33 // With this implementation, as long as we ensure a timer read happens at least once during the overflow period, timing should be accurate.
34 if (systime < last_systime) {
35 overflow += ((uint32_t)1) << CH_CFG_ST_RESOLUTION;
36 }
37
38 last_systime = systime;
39 return (uint32_t)TIME_I2MS(systime - reset_point + overflow);
40#else
41 return (uint32_t)TIME_I2MS(systime - reset_point);
42#endif
43}
44
45uint16_t timer_elapsed(uint16_t last) { return TIMER_DIFF_16(timer_read(), last); }
46
47uint32_t timer_elapsed32(uint32_t last) { return TIMER_DIFF_32(timer_read32(), last); }
diff --git a/platforms/chibios/wait.c b/platforms/chibios/wait.c
new file mode 100644
index 000000000..56fd6ffce
--- /dev/null
+++ b/platforms/chibios/wait.c
@@ -0,0 +1,41 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include <ch.h>
18#include <hal.h>
19
20#include "_wait.h"
21
22#ifdef WAIT_US_TIMER
23void wait_us(uint16_t duration) {
24 static const GPTConfig gpt_cfg = {1000000, NULL, 0, 0}; /* 1MHz timer, no callback */
25
26 if (duration == 0) {
27 duration = 1;
28 }
29
30 /*
31 * Only use this timer on the main thread;
32 * other threads need to use their own timer.
33 */
34 if (chThdGetSelfX() == &ch.mainthread && duration < (1ULL << (sizeof(gptcnt_t) * 8))) {
35 gptStart(&WAIT_US_TIMER, &gpt_cfg);
36 gptPolledDelay(&WAIT_US_TIMER, duration);
37 } else {
38 chThdSleepMicroseconds(duration);
39 }
40}
41#endif
diff --git a/platforms/common.mk b/platforms/common.mk
new file mode 100644
index 000000000..f7a0fc702
--- /dev/null
+++ b/platforms/common.mk
@@ -0,0 +1,12 @@
1PLATFORM_COMMON_DIR = $(PLATFORM_PATH)/$(PLATFORM_KEY)
2
3TMK_COMMON_SRC += \
4 $(PLATFORM_COMMON_DIR)/platform.c \
5 $(PLATFORM_COMMON_DIR)/suspend.c \
6 $(PLATFORM_COMMON_DIR)/timer.c \
7 $(PLATFORM_COMMON_DIR)/bootloader.c \
8
9# Search Path
10VPATH += $(PLATFORM_PATH)
11VPATH += $(PLATFORM_PATH)/$(PLATFORM_KEY)
12VPATH += $(PLATFORM_PATH)/$(PLATFORM_KEY)/$(DRIVER_DIR)
diff --git a/platforms/eeprom.h b/platforms/eeprom.h
new file mode 100644
index 000000000..f5b3f0ad5
--- /dev/null
+++ b/platforms/eeprom.h
@@ -0,0 +1,21 @@
1#pragma once
2
3#if defined(__AVR__) && !defined(EEPROM_DRIVER)
4# include <avr/eeprom.h>
5#else
6# include <stdint.h>
7# include <stdlib.h>
8
9uint8_t eeprom_read_byte(const uint8_t *__p);
10uint16_t eeprom_read_word(const uint16_t *__p);
11uint32_t eeprom_read_dword(const uint32_t *__p);
12void eeprom_read_block(void *__dst, const void *__src, size_t __n);
13void eeprom_write_byte(uint8_t *__p, uint8_t __value);
14void eeprom_write_word(uint16_t *__p, uint16_t __value);
15void eeprom_write_dword(uint32_t *__p, uint32_t __value);
16void eeprom_write_block(const void *__src, void *__dst, size_t __n);
17void eeprom_update_byte(uint8_t *__p, uint8_t __value);
18void eeprom_update_word(uint16_t *__p, uint16_t __value);
19void eeprom_update_dword(uint32_t *__p, uint32_t __value);
20void eeprom_update_block(const void *__src, void *__dst, size_t __n);
21#endif
diff --git a/platforms/gpio.h b/platforms/gpio.h
new file mode 100644
index 000000000..b47f6f8e4
--- /dev/null
+++ b/platforms/gpio.h
@@ -0,0 +1,22 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#pragma once
17
18#include "pin_defs.h"
19
20#if __has_include_next("gpio.h")
21# include_next "gpio.h" /* Include the platforms gpio.h */
22#endif \ No newline at end of file
diff --git a/platforms/pin_defs.h b/platforms/pin_defs.h
new file mode 100644
index 000000000..ea730138f
--- /dev/null
+++ b/platforms/pin_defs.h
@@ -0,0 +1,23 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#pragma once
17
18// useful for direct pin mapping
19#define NO_PIN (pin_t)(~0)
20
21#if __has_include_next("pin_defs.h")
22# include_next "pin_defs.h" /* Include the platforms pin_defs.h */
23#endif
diff --git a/platforms/progmem.h b/platforms/progmem.h
new file mode 100644
index 000000000..a70d8e299
--- /dev/null
+++ b/platforms/progmem.h
@@ -0,0 +1,19 @@
1#pragma once
2
3#if defined(__AVR__)
4# include <avr/pgmspace.h>
5#else
6# include <string.h>
7# define PROGMEM
8# define __flash
9# define PSTR(x) x
10# define PGM_P const char*
11# define memcpy_P(dest, src, n) memcpy(dest, src, n)
12# define pgm_read_byte(address_short) *((uint8_t*)(address_short))
13# define pgm_read_word(address_short) *((uint16_t*)(address_short))
14# define pgm_read_dword(address_short) *((uint32_t*)(address_short))
15# define pgm_read_ptr(address_short) *((void**)(address_short))
16# define strcmp_P(s1, s2) strcmp(s1, s2)
17# define strcpy_P(dest, src) strcpy(dest, src)
18# define strlen_P(src) strlen(src)
19#endif
diff --git a/platforms/sleep_led.h b/platforms/sleep_led.h
new file mode 100644
index 000000000..38f80a660
--- /dev/null
+++ b/platforms/sleep_led.h
@@ -0,0 +1,17 @@
1#pragma once
2
3#ifdef SLEEP_LED_ENABLE
4
5void sleep_led_init(void);
6void sleep_led_enable(void);
7void sleep_led_disable(void);
8void sleep_led_toggle(void);
9
10#else
11
12# define sleep_led_init()
13# define sleep_led_enable()
14# define sleep_led_disable()
15# define sleep_led_toggle()
16
17#endif
diff --git a/platforms/suspend.h b/platforms/suspend.h
new file mode 100644
index 000000000..081735f90
--- /dev/null
+++ b/platforms/suspend.h
@@ -0,0 +1,20 @@
1#pragma once
2
3#include <stdint.h>
4#include <stdbool.h>
5
6void suspend_idle(uint8_t timeout);
7void suspend_power_down(void);
8bool suspend_wakeup_condition(void);
9void suspend_wakeup_init(void);
10
11void suspend_wakeup_init_user(void);
12void suspend_wakeup_init_kb(void);
13void suspend_wakeup_init_quantum(void);
14void suspend_power_down_user(void);
15void suspend_power_down_kb(void);
16void suspend_power_down_quantum(void);
17
18#ifndef USB_SUSPEND_WAKEUP_DELAY
19# define USB_SUSPEND_WAKEUP_DELAY 0
20#endif
diff --git a/platforms/test/_wait.h b/platforms/test/_wait.h
new file mode 100644
index 000000000..4e22f593b
--- /dev/null
+++ b/platforms/test/_wait.h
@@ -0,0 +1,22 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#pragma once
17
18#include <inttypes.h>
19
20void wait_ms(uint32_t ms);
21#define wait_us(us) wait_ms(us / 1000)
22#define waitInputPinDelay()
diff --git a/platforms/test/bootloader.c b/platforms/test/bootloader.c
new file mode 100644
index 000000000..5155d9ff0
--- /dev/null
+++ b/platforms/test/bootloader.c
@@ -0,0 +1,19 @@
1/* Copyright 2017 Fred Sundvik
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "bootloader.h"
18
19void bootloader_jump(void) {}
diff --git a/platforms/test/eeprom.c b/platforms/test/eeprom.c
new file mode 100644
index 000000000..5c8e69dae
--- /dev/null
+++ b/platforms/test/eeprom.c
@@ -0,0 +1,95 @@
1/* Copyright 2017 Fred Sundvik
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "eeprom.h"
18
19#define EEPROM_SIZE 32
20
21static uint8_t buffer[EEPROM_SIZE];
22
23uint8_t eeprom_read_byte(const uint8_t *addr) {
24 uintptr_t offset = (uintptr_t)addr;
25 return buffer[offset];
26}
27
28void eeprom_write_byte(uint8_t *addr, uint8_t value) {
29 uintptr_t offset = (uintptr_t)addr;
30 buffer[offset] = value;
31}
32
33uint16_t eeprom_read_word(const uint16_t *addr) {
34 const uint8_t *p = (const uint8_t *)addr;
35 return eeprom_read_byte(p) | (eeprom_read_byte(p + 1) << 8);
36}
37
38uint32_t eeprom_read_dword(const uint32_t *addr) {
39 const uint8_t *p = (const uint8_t *)addr;
40 return eeprom_read_byte(p) | (eeprom_read_byte(p + 1) << 8) | (eeprom_read_byte(p + 2) << 16) | (eeprom_read_byte(p + 3) << 24);
41}
42
43void eeprom_read_block(void *buf, const void *addr, size_t len) {
44 const uint8_t *p = (const uint8_t *)addr;
45 uint8_t * dest = (uint8_t *)buf;
46 while (len--) {
47 *dest++ = eeprom_read_byte(p++);
48 }
49}
50
51void eeprom_write_word(uint16_t *addr, uint16_t value) {
52 uint8_t *p = (uint8_t *)addr;
53 eeprom_write_byte(p++, value);
54 eeprom_write_byte(p, value >> 8);
55}
56
57void eeprom_write_dword(uint32_t *addr, uint32_t value) {
58 uint8_t *p = (uint8_t *)addr;
59 eeprom_write_byte(p++, value);
60 eeprom_write_byte(p++, value >> 8);
61 eeprom_write_byte(p++, value >> 16);
62 eeprom_write_byte(p, value >> 24);
63}
64
65void eeprom_write_block(const void *buf, void *addr, size_t len) {
66 uint8_t * p = (uint8_t *)addr;
67 const uint8_t *src = (const uint8_t *)buf;
68 while (len--) {
69 eeprom_write_byte(p++, *src++);
70 }
71}
72
73void eeprom_update_byte(uint8_t *addr, uint8_t value) { eeprom_write_byte(addr, value); }
74
75void eeprom_update_word(uint16_t *addr, uint16_t value) {
76 uint8_t *p = (uint8_t *)addr;
77 eeprom_write_byte(p++, value);
78 eeprom_write_byte(p, value >> 8);
79}
80
81void eeprom_update_dword(uint32_t *addr, uint32_t value) {
82 uint8_t *p = (uint8_t *)addr;
83 eeprom_write_byte(p++, value);
84 eeprom_write_byte(p++, value >> 8);
85 eeprom_write_byte(p++, value >> 16);
86 eeprom_write_byte(p, value >> 24);
87}
88
89void eeprom_update_block(const void *buf, void *addr, size_t len) {
90 uint8_t * p = (uint8_t *)addr;
91 const uint8_t *src = (const uint8_t *)buf;
92 while (len--) {
93 eeprom_write_byte(p++, *src++);
94 }
95}
diff --git a/platforms/test/eeprom_stm32_tests.cpp b/platforms/test/eeprom_stm32_tests.cpp
new file mode 100644
index 000000000..5bc8d8790
--- /dev/null
+++ b/platforms/test/eeprom_stm32_tests.cpp
@@ -0,0 +1,438 @@
1/* Copyright 2021 by Don Kjer
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "gtest/gtest.h"
18
19extern "C" {
20#include "flash_stm32.h"
21#include "eeprom_stm32.h"
22#include "eeprom.h"
23}
24
25/* Mock Flash Parameters:
26 *
27 * === Large Layout ===
28 * flash size: 65536
29 * page size: 2048
30 * density pages: 16
31 * Simulated EEPROM size: 16384
32 *
33 * FlashBuf Layout:
34 * [Unused | Compact | Write Log ]
35 * [0......|32768......|49152......65535]
36 *
37 * === Tiny Layout ===
38 * flash size: 1024
39 * page size: 512
40 * density pages: 1
41 * Simulated EEPROM size: 256
42 *
43 * FlashBuf Layout:
44 * [Unused | Compact | Write Log ]
45 * [0......|512......|768......1023]
46 *
47 */
48
49#define EEPROM_SIZE (FEE_PAGE_SIZE * FEE_PAGE_COUNT / 2)
50#define LOG_SIZE EEPROM_SIZE
51#define LOG_BASE (MOCK_FLASH_SIZE - LOG_SIZE)
52#define EEPROM_BASE (LOG_BASE - EEPROM_SIZE)
53
54/* Log encoding helpers */
55#define BYTE_VALUE(addr, value) (((addr) << 8) | (value))
56#define WORD_ZERO(addr) (0x8000 | ((addr) >> 1))
57#define WORD_ONE(addr) (0xA000 | ((addr) >> 1))
58#define WORD_NEXT(addr) (0xE000 | (((addr)-0x80) >> 1))
59
60class EepromStm32Test : public testing::Test {
61 public:
62 EepromStm32Test() {}
63 ~EepromStm32Test() {}
64
65 protected:
66 void SetUp() override { EEPROM_Erase(); }
67
68 void TearDown() override {
69#ifdef EEPROM_DEBUG
70 dumpEepromDataBuf();
71#endif
72 }
73};
74
75TEST_F(EepromStm32Test, TestErase) {
76 EEPROM_WriteDataByte(0, 0x42);
77 EEPROM_Erase();
78 EXPECT_EQ(EEPROM_ReadDataByte(0), 0);
79 EXPECT_EQ(EEPROM_ReadDataByte(1), 0);
80}
81
82TEST_F(EepromStm32Test, TestReadGarbage) {
83 uint8_t garbage = 0x3c;
84 for (int i = 0; i < MOCK_FLASH_SIZE; ++i) {
85 garbage ^= 0xa3;
86 garbage += i;
87 FlashBuf[i] = garbage;
88 }
89 EEPROM_Init(); // Just verify we don't crash
90}
91
92TEST_F(EepromStm32Test, TestWriteBadAddress) {
93 EXPECT_EQ(EEPROM_WriteDataByte(EEPROM_SIZE, 0x42), FLASH_BAD_ADDRESS);
94 EXPECT_EQ(EEPROM_WriteDataWord(EEPROM_SIZE - 1, 0xbeef), FLASH_BAD_ADDRESS);
95 EXPECT_EQ(EEPROM_WriteDataWord(EEPROM_SIZE, 0xbeef), FLASH_BAD_ADDRESS);
96}
97
98TEST_F(EepromStm32Test, TestReadBadAddress) {
99 EXPECT_EQ(EEPROM_ReadDataByte(EEPROM_SIZE), 0xFF);
100 EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE - 1), 0xFFFF);
101 EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE), 0xFFFF);
102 EXPECT_EQ(eeprom_read_dword((uint32_t*)(EEPROM_SIZE - 4)), 0);
103 EXPECT_EQ(eeprom_read_dword((uint32_t*)(EEPROM_SIZE - 3)), 0xFF000000);
104 EXPECT_EQ(eeprom_read_dword((uint32_t*)EEPROM_SIZE), 0xFFFFFFFF);
105}
106
107TEST_F(EepromStm32Test, TestReadByte) {
108 /* Direct compacted-area baseline: Address < 0x80 */
109 FlashBuf[EEPROM_BASE + 2] = ~0xef;
110 FlashBuf[EEPROM_BASE + 3] = ~0xbe;
111 /* Direct compacted-area baseline: Address >= 0x80 */
112 FlashBuf[EEPROM_BASE + EEPROM_SIZE - 2] = ~0x78;
113 FlashBuf[EEPROM_BASE + EEPROM_SIZE - 1] = ~0x56;
114 /* Check values */
115 EEPROM_Init();
116 EXPECT_EQ(EEPROM_ReadDataByte(2), 0xef);
117 EXPECT_EQ(EEPROM_ReadDataByte(3), 0xbe);
118 EXPECT_EQ(EEPROM_ReadDataByte(EEPROM_SIZE - 2), 0x78);
119 EXPECT_EQ(EEPROM_ReadDataByte(EEPROM_SIZE - 1), 0x56);
120 /* Write Log byte value */
121 FlashBuf[LOG_BASE] = 0x65;
122 FlashBuf[LOG_BASE + 1] = 3;
123 /* Write Log word value */
124 *(uint16_t*)&FlashBuf[LOG_BASE + 2] = WORD_NEXT(EEPROM_SIZE - 2);
125 *(uint16_t*)&FlashBuf[LOG_BASE + 4] = ~0x9abc;
126 /* Check values */
127 EEPROM_Init();
128 EXPECT_EQ(EEPROM_ReadDataByte(2), 0xef);
129 EXPECT_EQ(EEPROM_ReadDataByte(3), 0x65);
130 EXPECT_EQ(EEPROM_ReadDataByte(EEPROM_SIZE - 2), 0xbc);
131 EXPECT_EQ(EEPROM_ReadDataByte(EEPROM_SIZE - 1), 0x9a);
132}
133
134TEST_F(EepromStm32Test, TestWriteByte) {
135 /* Direct compacted-area baseline: Address < 0x80 */
136 EEPROM_WriteDataByte(2, 0xef);
137 EEPROM_WriteDataByte(3, 0xbe);
138 /* Direct compacted-area baseline: Address >= 0x80 */
139 EEPROM_WriteDataByte(EEPROM_SIZE - 2, 0x78);
140 EEPROM_WriteDataByte(EEPROM_SIZE - 1, 0x56);
141 /* Check values */
142 /* First write in each aligned word should have been direct */
143 EXPECT_EQ(FlashBuf[EEPROM_BASE + 2], (uint8_t)~0xef);
144 EXPECT_EQ(FlashBuf[EEPROM_BASE + EEPROM_SIZE - 2], (uint8_t)~0x78);
145
146 /* Second write per aligned word requires a log entry */
147 EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE], BYTE_VALUE(3, 0xbe));
148 EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 2], WORD_NEXT(EEPROM_SIZE - 1));
149 EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 4], (uint16_t)~0x5678);
150}
151
152TEST_F(EepromStm32Test, TestByteRoundTrip) {
153 /* Direct compacted-area: Address < 0x80 */
154 EEPROM_WriteDataWord(0, 0xdead);
155 EEPROM_WriteDataByte(2, 0xef);
156 EEPROM_WriteDataByte(3, 0xbe);
157 /* Direct compacted-area: Address >= 0x80 */
158 EEPROM_WriteDataByte(EEPROM_SIZE - 2, 0x78);
159 EEPROM_WriteDataByte(EEPROM_SIZE - 1, 0x56);
160 /* Check values */
161 EEPROM_Init();
162 EXPECT_EQ(EEPROM_ReadDataByte(0), 0xad);
163 EXPECT_EQ(EEPROM_ReadDataByte(1), 0xde);
164 EXPECT_EQ(EEPROM_ReadDataByte(2), 0xef);
165 EXPECT_EQ(EEPROM_ReadDataByte(3), 0xbe);
166 EXPECT_EQ(EEPROM_ReadDataByte(EEPROM_SIZE - 2), 0x78);
167 EXPECT_EQ(EEPROM_ReadDataByte(EEPROM_SIZE - 1), 0x56);
168 /* Write log entries */
169 EEPROM_WriteDataByte(2, 0x80);
170 EEPROM_WriteDataByte(EEPROM_SIZE - 2, 0x3c);
171 /* Check values */
172 EEPROM_Init();
173 EXPECT_EQ(EEPROM_ReadDataByte(2), 0x80);
174 EXPECT_EQ(EEPROM_ReadDataByte(3), 0xbe);
175 EXPECT_EQ(EEPROM_ReadDataByte(EEPROM_SIZE - 2), 0x3c);
176 EXPECT_EQ(EEPROM_ReadDataByte(EEPROM_SIZE - 1), 0x56);
177}
178
179TEST_F(EepromStm32Test, TestReadWord) {
180 /* Direct compacted-area baseline: Address < 0x80 */
181 FlashBuf[EEPROM_BASE + 0] = ~0xad;
182 FlashBuf[EEPROM_BASE + 1] = ~0xde;
183 /* Direct compacted-area baseline: Address >= 0x80 */
184 FlashBuf[EEPROM_BASE + 200] = ~0xcd;
185 FlashBuf[EEPROM_BASE + 201] = ~0xab;
186 FlashBuf[EEPROM_BASE + EEPROM_SIZE - 4] = ~0x34;
187 FlashBuf[EEPROM_BASE + EEPROM_SIZE - 3] = ~0x12;
188 FlashBuf[EEPROM_BASE + EEPROM_SIZE - 2] = ~0x78;
189 FlashBuf[EEPROM_BASE + EEPROM_SIZE - 1] = ~0x56;
190 /* Check values */
191 EEPROM_Init();
192 EXPECT_EQ(EEPROM_ReadDataWord(0), 0xdead);
193 EXPECT_EQ(EEPROM_ReadDataWord(200), 0xabcd);
194 EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE - 4), 0x1234);
195 EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE - 2), 0x5678);
196 /* Write Log word zero-encoded */
197 *(uint16_t*)&FlashBuf[LOG_BASE] = WORD_ZERO(200);
198 /* Write Log word one-encoded */
199 *(uint16_t*)&FlashBuf[LOG_BASE + 2] = WORD_ONE(EEPROM_SIZE - 4);
200 /* Write Log word value */
201 *(uint16_t*)&FlashBuf[LOG_BASE + 4] = WORD_NEXT(EEPROM_SIZE - 2);
202 *(uint16_t*)&FlashBuf[LOG_BASE + 6] = ~0x9abc;
203 /* Check values */
204 EEPROM_Init();
205 EXPECT_EQ(EEPROM_ReadDataWord(200), 0);
206 EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE - 4), 1);
207 EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE - 2), 0x9abc);
208}
209
210TEST_F(EepromStm32Test, TestWriteWord) {
211 /* Direct compacted-area: Address < 0x80 */
212 EEPROM_WriteDataWord(0, 0xdead); // Aligned
213 EEPROM_WriteDataWord(3, 0xbeef); // Unaligned
214 /* Direct compacted-area: Address >= 0x80 */
215 EEPROM_WriteDataWord(200, 0xabcd); // Aligned
216 EEPROM_WriteDataWord(203, 0x9876); // Unaligned
217 EEPROM_WriteDataWord(EEPROM_SIZE - 4, 0x1234);
218 EEPROM_WriteDataWord(EEPROM_SIZE - 2, 0x5678);
219 /* Write Log word zero-encoded */
220 EEPROM_WriteDataWord(EEPROM_SIZE - 4, 0);
221 /* Write Log word one-encoded */
222 EEPROM_WriteDataWord(EEPROM_SIZE - 2, 1);
223 /* Write Log word value aligned */
224 EEPROM_WriteDataWord(200, 0x4321); // Aligned
225 /* Write Log word value unaligned */
226 EEPROM_WriteDataByte(202, 0x3c); // Set neighboring byte
227 EEPROM_WriteDataWord(203, 0xcdef); // Unaligned
228 /* Check values */
229 /* Direct compacted-area */
230 EXPECT_EQ(*(uint16_t*)&FlashBuf[EEPROM_BASE], (uint16_t)~0xdead);
231 EXPECT_EQ(*(uint16_t*)&FlashBuf[EEPROM_BASE + 3], (uint16_t)~0xbeef);
232 EXPECT_EQ(*(uint16_t*)&FlashBuf[EEPROM_BASE + 200], (uint16_t)~0xabcd);
233 EXPECT_EQ(FlashBuf[EEPROM_BASE + 203], (uint8_t)~0x76);
234 EXPECT_EQ(FlashBuf[EEPROM_BASE + 204], (uint8_t)~0x98);
235 EXPECT_EQ(*(uint16_t*)&FlashBuf[EEPROM_BASE + EEPROM_SIZE - 4], (uint16_t)~0x1234);
236 EXPECT_EQ(*(uint16_t*)&FlashBuf[EEPROM_BASE + EEPROM_SIZE - 2], (uint16_t)~0x5678);
237 /* Write Log word zero-encoded */
238 EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE], WORD_ZERO(EEPROM_SIZE - 4));
239 /* Write Log word one-encoded */
240 EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 2], WORD_ONE(EEPROM_SIZE - 2));
241 /* Write Log word value aligned */
242 EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 4], WORD_NEXT(200));
243 EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 6], (uint16_t)~0x4321);
244 /* Write Log word value unaligned */
245 EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 8], WORD_NEXT(202));
246 EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 10], (uint16_t)~0x763c);
247 EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 12], WORD_NEXT(202));
248 EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 14], (uint16_t)~0xef3c);
249 EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 16], WORD_NEXT(204));
250 EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 18], (uint16_t)~0x00cd);
251}
252
253TEST_F(EepromStm32Test, TestWordRoundTrip) {
254 /* Direct compacted-area: Address < 0x80 */
255 EEPROM_WriteDataWord(0, 0xdead); // Aligned
256 EEPROM_WriteDataWord(3, 0xbeef); // Unaligned
257 /* Direct compacted-area: Address >= 0x80 */
258 EEPROM_WriteDataWord(200, 0xabcd); // Aligned
259 EEPROM_WriteDataWord(203, 0x9876); // Unaligned
260 EEPROM_WriteDataWord(EEPROM_SIZE - 4, 0x1234);
261 EEPROM_WriteDataWord(EEPROM_SIZE - 2, 0x5678);
262 /* Check values */
263 EEPROM_Init();
264 EXPECT_EQ(EEPROM_ReadDataWord(0), 0xdead);
265 EXPECT_EQ(EEPROM_ReadDataWord(3), 0xbeef);
266 EXPECT_EQ(EEPROM_ReadDataWord(200), 0xabcd);
267 EXPECT_EQ(EEPROM_ReadDataWord(203), 0x9876);
268 EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE - 4), 0x1234);
269 EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE - 2), 0x5678);
270
271 /* Write Log word zero-encoded */
272 EEPROM_WriteDataWord(EEPROM_SIZE - 4, 0);
273 /* Write Log word one-encoded */
274 EEPROM_WriteDataWord(EEPROM_SIZE - 2, 1);
275 /* Write Log word value aligned */
276 EEPROM_WriteDataWord(200, 0x4321); // Aligned
277 /* Write Log word value unaligned */
278 EEPROM_WriteDataByte(202, 0x3c); // Set neighboring byte
279 EEPROM_WriteDataWord(203, 0xcdef); // Unaligned
280 /* Check values */
281 EEPROM_Init();
282 EXPECT_EQ(EEPROM_ReadDataWord(200), 0x4321);
283 EXPECT_EQ(EEPROM_ReadDataByte(202), 0x3c);
284 EXPECT_EQ(EEPROM_ReadDataWord(203), 0xcdef);
285 EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE - 4), 0);
286 EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE - 2), 1);
287}
288
289TEST_F(EepromStm32Test, TestByteWordBoundary) {
290 /* Direct compacted-area write */
291 EEPROM_WriteDataWord(0x7e, 0xdead);
292 EEPROM_WriteDataWord(0x80, 0xbeef);
293 /* Byte log entry */
294 EEPROM_WriteDataByte(0x7f, 0x3c);
295 /* Word log entry */
296 EEPROM_WriteDataByte(0x80, 0x18);
297 /* Check values */
298 EEPROM_Init();
299 EXPECT_EQ(EEPROM_ReadDataWord(0x7e), 0x3cad);
300 EXPECT_EQ(EEPROM_ReadDataWord(0x80), 0xbe18);
301 EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE], BYTE_VALUE(0x7f, 0x3c));
302 EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 2], WORD_NEXT(0x80));
303 EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 4], (uint16_t)~0xbe18);
304 /* Byte log entries */
305 EEPROM_WriteDataWord(0x7e, 0xcafe);
306 /* Check values */
307 EEPROM_Init();
308 EXPECT_EQ(EEPROM_ReadDataWord(0x7e), 0xcafe);
309 EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 6], BYTE_VALUE(0x7e, 0xfe));
310 EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 8], BYTE_VALUE(0x7f, 0xca));
311 /* Byte and Word log entries */
312 EEPROM_WriteDataWord(0x7f, 0xba5e);
313 /* Check values */
314 EEPROM_Init();
315 EXPECT_EQ(EEPROM_ReadDataWord(0x7f), 0xba5e);
316 EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 10], BYTE_VALUE(0x7f, 0x5e));
317 EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 12], WORD_NEXT(0x80));
318 EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 14], (uint16_t)~0xbeba);
319 /* Word log entry */
320 EEPROM_WriteDataWord(0x80, 0xf00d);
321 /* Check values */
322 EEPROM_Init();
323 EXPECT_EQ(EEPROM_ReadDataWord(0x80), 0xf00d);
324 EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 16], WORD_NEXT(0x80));
325 EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 18], (uint16_t)~0xf00d);
326}
327
328TEST_F(EepromStm32Test, TestDWordRoundTrip) {
329 /* Direct compacted-area: Address < 0x80 */
330 eeprom_write_dword((uint32_t*)0, 0xdeadbeef); // Aligned
331 eeprom_write_dword((uint32_t*)9, 0x12345678); // Unaligned
332 /* Direct compacted-area: Address >= 0x80 */
333 eeprom_write_dword((uint32_t*)200, 0xfacef00d);
334 eeprom_write_dword((uint32_t*)(EEPROM_SIZE - 4), 0xba5eba11); // Aligned
335 eeprom_write_dword((uint32_t*)(EEPROM_SIZE - 9), 0xcafed00d); // Unaligned
336 /* Check direct values */
337 EEPROM_Init();
338 EXPECT_EQ(eeprom_read_dword((uint32_t*)0), 0xdeadbeef);
339 EXPECT_EQ(eeprom_read_dword((uint32_t*)9), 0x12345678);
340 EXPECT_EQ(eeprom_read_dword((uint32_t*)200), 0xfacef00d);
341 EXPECT_EQ(eeprom_read_dword((uint32_t*)(EEPROM_SIZE - 4)), 0xba5eba11); // Aligned
342 EXPECT_EQ(eeprom_read_dword((uint32_t*)(EEPROM_SIZE - 9)), 0xcafed00d); // Unaligned
343 /* Write Log byte encoded */
344 eeprom_write_dword((uint32_t*)0, 0xdecafbad);
345 eeprom_write_dword((uint32_t*)9, 0x87654321);
346 /* Write Log word encoded */
347 eeprom_write_dword((uint32_t*)200, 1);
348 /* Write Log word value aligned */
349 eeprom_write_dword((uint32_t*)(EEPROM_SIZE - 4), 0xdeadc0de); // Aligned
350 eeprom_write_dword((uint32_t*)(EEPROM_SIZE - 9), 0x6789abcd); // Unaligned
351 /* Check log values */
352 EEPROM_Init();
353 EXPECT_EQ(eeprom_read_dword((uint32_t*)0), 0xdecafbad);
354 EXPECT_EQ(eeprom_read_dword((uint32_t*)9), 0x87654321);
355 EXPECT_EQ(eeprom_read_dword((uint32_t*)200), 1);
356 EXPECT_EQ(eeprom_read_dword((uint32_t*)(EEPROM_SIZE - 4)), 0xdeadc0de); // Aligned
357 EXPECT_EQ(eeprom_read_dword((uint32_t*)(EEPROM_SIZE - 9)), 0x6789abcd); // Unaligned
358}
359
360TEST_F(EepromStm32Test, TestBlockRoundTrip) {
361 char src0[] = "0123456789abcdef";
362 void* src1 = (void*)&src0[1];
363 /* Various alignments of src & dst, Address < 0x80 */
364 eeprom_write_block(src0, (void*)0, sizeof(src0));
365 eeprom_write_block(src0, (void*)21, sizeof(src0));
366 eeprom_write_block(src1, (void*)40, sizeof(src0) - 1);
367 eeprom_write_block(src1, (void*)61, sizeof(src0) - 1);
368 /* Various alignments of src & dst, Address >= 0x80 */
369 eeprom_write_block(src0, (void*)140, sizeof(src0));
370 eeprom_write_block(src0, (void*)161, sizeof(src0));
371 eeprom_write_block(src1, (void*)180, sizeof(src0) - 1);
372 eeprom_write_block(src1, (void*)201, sizeof(src0) - 1);
373
374 /* Check values */
375 EEPROM_Init();
376
377 char dstBuf[256] = {0};
378 char* dst0a = (char*)dstBuf;
379 char* dst0b = (char*)&dstBuf[20];
380 char* dst1a = (char*)&dstBuf[41];
381 char* dst1b = (char*)&dstBuf[61];
382 char* dst0c = (char*)&dstBuf[80];
383 char* dst0d = (char*)&dstBuf[100];
384 char* dst1c = (char*)&dstBuf[121];
385 char* dst1d = (char*)&dstBuf[141];
386 eeprom_read_block((void*)dst0a, (void*)0, sizeof(src0));
387 eeprom_read_block((void*)dst0b, (void*)21, sizeof(src0));
388 eeprom_read_block((void*)dst1a, (void*)40, sizeof(src0) - 1);
389 eeprom_read_block((void*)dst1b, (void*)61, sizeof(src0) - 1);
390 eeprom_read_block((void*)dst0c, (void*)140, sizeof(src0));
391 eeprom_read_block((void*)dst0d, (void*)161, sizeof(src0));
392 eeprom_read_block((void*)dst1c, (void*)180, sizeof(src0) - 1);
393 eeprom_read_block((void*)dst1d, (void*)201, sizeof(src0) - 1);
394 EXPECT_EQ(strcmp((char*)src0, dst0a), 0);
395 EXPECT_EQ(strcmp((char*)src0, dst0b), 0);
396 EXPECT_EQ(strcmp((char*)src0, dst0c), 0);
397 EXPECT_EQ(strcmp((char*)src0, dst0d), 0);
398 EXPECT_EQ(strcmp((char*)src1, dst1a), 0);
399 EXPECT_EQ(strcmp((char*)src1, dst1b), 0);
400 EXPECT_EQ(strcmp((char*)src1, dst1c), 0);
401 EXPECT_EQ(strcmp((char*)src1, dst1d), 0);
402}
403
404TEST_F(EepromStm32Test, TestCompaction) {
405 /* Direct writes */
406 eeprom_write_dword((uint32_t*)0, 0xdeadbeef);
407 eeprom_write_byte((uint8_t*)4, 0x3c);
408 eeprom_write_word((uint16_t*)6, 0xd00d);
409 eeprom_write_dword((uint32_t*)150, 0xcafef00d);
410 eeprom_write_dword((uint32_t*)200, 0x12345678);
411 /* Fill write log entries */
412 uint32_t i;
413 uint32_t val = 0xd8453c6b;
414 for (i = 0; i < (LOG_SIZE / (sizeof(uint32_t) * 2)); i++) {
415 val ^= 0x593ca5b3;
416 val += i;
417 eeprom_write_dword((uint32_t*)200, val);
418 }
419 /* Check values pre-compaction */
420 EEPROM_Init();
421 EXPECT_EQ(eeprom_read_dword((uint32_t*)0), 0xdeadbeef);
422 EXPECT_EQ(eeprom_read_byte((uint8_t*)4), 0x3c);
423 EXPECT_EQ(eeprom_read_word((uint16_t*)6), 0xd00d);
424 EXPECT_EQ(eeprom_read_dword((uint32_t*)150), 0xcafef00d);
425 EXPECT_EQ(eeprom_read_dword((uint32_t*)200), val);
426 EXPECT_NE(*(uint16_t*)&FlashBuf[LOG_BASE], 0xFFFF);
427 EXPECT_NE(*(uint16_t*)&FlashBuf[LOG_BASE + LOG_SIZE - 2], 0xFFFF);
428 /* Run compaction */
429 eeprom_write_byte((uint8_t*)4, 0x1f);
430 EEPROM_Init();
431 EXPECT_EQ(eeprom_read_dword((uint32_t*)0), 0xdeadbeef);
432 EXPECT_EQ(eeprom_read_byte((uint8_t*)4), 0x1f);
433 EXPECT_EQ(eeprom_read_word((uint16_t*)6), 0xd00d);
434 EXPECT_EQ(eeprom_read_dword((uint32_t*)150), 0xcafef00d);
435 EXPECT_EQ(eeprom_read_dword((uint32_t*)200), val);
436 EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE], 0xFFFF);
437 EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + LOG_SIZE - 2], 0xFFFF);
438}
diff --git a/platforms/test/flash_stm32_mock.c b/platforms/test/flash_stm32_mock.c
new file mode 100644
index 000000000..222a004bc
--- /dev/null
+++ b/platforms/test/flash_stm32_mock.c
@@ -0,0 +1,49 @@
1/* Copyright 2021 by Don Kjer
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include <string.h>
18#include <stdbool.h>
19#include "flash_stm32.h"
20
21uint8_t FlashBuf[MOCK_FLASH_SIZE] = {0};
22
23static bool flash_locked = true;
24
25FLASH_Status FLASH_ErasePage(uint32_t Page_Address) {
26 if (flash_locked) return FLASH_ERROR_WRP;
27 Page_Address -= (uintptr_t)FlashBuf;
28 Page_Address -= (Page_Address % FEE_PAGE_SIZE);
29 if (Page_Address >= MOCK_FLASH_SIZE) return FLASH_BAD_ADDRESS;
30 memset(&FlashBuf[Page_Address], '\xff', FEE_PAGE_SIZE);
31 return FLASH_COMPLETE;
32}
33
34FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data) {
35 if (flash_locked) return FLASH_ERROR_WRP;
36 Address -= (uintptr_t)FlashBuf;
37 if (Address >= MOCK_FLASH_SIZE) return FLASH_BAD_ADDRESS;
38 uint16_t oldData = *(uint16_t*)&FlashBuf[Address];
39 if (oldData == 0xFFFF || Data == 0) {
40 *(uint16_t*)&FlashBuf[Address] = Data;
41 return FLASH_COMPLETE;
42 } else {
43 return FLASH_ERROR_PG;
44 }
45}
46
47FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout) { return FLASH_COMPLETE; }
48void FLASH_Unlock(void) { flash_locked = false; }
49void FLASH_Lock(void) { flash_locked = true; }
diff --git a/platforms/test/hal.h b/platforms/test/hal.h
new file mode 100644
index 000000000..2d268ad54
--- /dev/null
+++ b/platforms/test/hal.h
@@ -0,0 +1,18 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#pragma once
17
18// Just here to please eeprom tests
diff --git a/platforms/test/platform.c b/platforms/test/platform.c
new file mode 100644
index 000000000..8ddceeda8
--- /dev/null
+++ b/platforms/test/platform.c
@@ -0,0 +1,21 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "platform_deps.h"
18
19void platform_setup(void) {
20 // do nothing
21} \ No newline at end of file
diff --git a/platforms/test/platform.h b/platforms/test/platform.h
new file mode 100644
index 000000000..f296d1d53
--- /dev/null
+++ b/platforms/test/platform.h
@@ -0,0 +1,18 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#pragma once
17
18// here just to please the build
diff --git a/platforms/test/platform.mk b/platforms/test/platform.mk
new file mode 100644
index 000000000..eb2424ec5
--- /dev/null
+++ b/platforms/test/platform.mk
@@ -0,0 +1,34 @@
1SYSTEM_TYPE := $(shell gcc -dumpmachine)
2GCC_VERSION := $(shell gcc --version 2>/dev/null)
3
4CC = $(CC_PREFIX) gcc
5OBJCOPY =
6OBJDUMP =
7SIZE =
8AR =
9NM =
10HEX =
11EEP =
12BIN =
13
14
15COMPILEFLAGS += -funsigned-char
16ifeq ($(findstring clang, ${GCC_VERSION}),)
17COMPILEFLAGS += -funsigned-bitfields
18endif
19COMPILEFLAGS += -ffunction-sections
20COMPILEFLAGS += -fdata-sections
21COMPILEFLAGS += -fshort-enums
22ifneq ($(findstring mingw, ${SYSTEM_TYPE}),)
23COMPILEFLAGS += -mno-ms-bitfields
24endif
25
26CFLAGS += $(COMPILEFLAGS)
27ifeq ($(findstring clang, ${GCC_VERSION}),)
28CFLAGS += -fno-inline-small-functions
29endif
30CFLAGS += -fno-strict-aliasing
31
32CXXFLAGS += $(COMPILEFLAGS)
33CXXFLAGS += -fno-exceptions
34CXXFLAGS += -std=gnu++11
diff --git a/platforms/test/platform_deps.h b/platforms/test/platform_deps.h
new file mode 100644
index 000000000..f296d1d53
--- /dev/null
+++ b/platforms/test/platform_deps.h
@@ -0,0 +1,18 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#pragma once
17
18// here just to please the build
diff --git a/platforms/test/rules.mk b/platforms/test/rules.mk
new file mode 100644
index 000000000..66b853d8e
--- /dev/null
+++ b/platforms/test/rules.mk
@@ -0,0 +1,24 @@
1eeprom_stm32_DEFS := -DFLASH_STM32_MOCKED -DNO_PRINT -DFEE_FLASH_BASE=FlashBuf
2eeprom_stm32_tiny_DEFS := $(eeprom_stm32_DEFS) \
3 -DFEE_MCU_FLASH_SIZE=1 \
4 -DMOCK_FLASH_SIZE=1024 \
5 -DFEE_PAGE_SIZE=512 \
6 -DFEE_PAGE_COUNT=1
7eeprom_stm32_large_DEFS := $(eeprom_stm32_DEFS) \
8 -DFEE_MCU_FLASH_SIZE=64 \
9 -DMOCK_FLASH_SIZE=65536 \
10 -DFEE_PAGE_SIZE=2048 \
11 -DFEE_PAGE_COUNT=16
12
13eeprom_stm32_INC := \
14 $(PLATFORM_PATH)/chibios/
15eeprom_stm32_tiny_INC := $(eeprom_stm32_INC)
16eeprom_stm32_large_INC := $(eeprom_stm32_INC)
17
18eeprom_stm32_SRC := \
19 $(TOP_DIR)/drivers/eeprom/eeprom_driver.c \
20 $(PLATFORM_PATH)/$(PLATFORM_KEY)/eeprom_stm32_tests.cpp \
21 $(PLATFORM_PATH)/$(PLATFORM_KEY)/flash_stm32_mock.c \
22 $(PLATFORM_PATH)/chibios/eeprom_stm32.c
23eeprom_stm32_tiny_SRC := $(eeprom_stm32_SRC)
24eeprom_stm32_large_SRC := $(eeprom_stm32_SRC)
diff --git a/platforms/test/suspend.c b/platforms/test/suspend.c
new file mode 100644
index 000000000..76b705967
--- /dev/null
+++ b/platforms/test/suspend.c
@@ -0,0 +1,15 @@
1/* Copyright 2017 Fred Sundvik
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
diff --git a/platforms/test/testlist.mk b/platforms/test/testlist.mk
new file mode 100644
index 000000000..51a9638bb
--- /dev/null
+++ b/platforms/test/testlist.mk
@@ -0,0 +1 @@
TEST_LIST += eeprom_stm32_tiny eeprom_stm32_large
diff --git a/platforms/test/timer.c b/platforms/test/timer.c
new file mode 100644
index 000000000..61c3a0020
--- /dev/null
+++ b/platforms/test/timer.c
@@ -0,0 +1,33 @@
1/* Copyright 2017 Fred Sundvik
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "timer.h"
18
19static uint32_t current_time = 0;
20
21void timer_init(void) { current_time = 0; }
22
23void timer_clear(void) { current_time = 0; }
24
25uint16_t timer_read(void) { return current_time & 0xFFFF; }
26uint32_t timer_read32(void) { return current_time; }
27uint16_t timer_elapsed(uint16_t last) { return TIMER_DIFF_16(timer_read(), last); }
28uint32_t timer_elapsed32(uint32_t last) { return TIMER_DIFF_32(timer_read32(), last); }
29
30void set_time(uint32_t t) { current_time = t; }
31void advance_time(uint32_t ms) { current_time += ms; }
32
33void wait_ms(uint32_t ms) { advance_time(ms); }
diff --git a/platforms/timer.h b/platforms/timer.h
new file mode 100644
index 000000000..02e39e79e
--- /dev/null
+++ b/platforms/timer.h
@@ -0,0 +1,67 @@
1/*
2Copyright 2011 Jun Wako <wakojun@gmail.com>
3Copyright 2021 Simon Arlott
4
5This program is free software: you can redistribute it and/or modify
6it under the terms of the GNU General Public License as published by
7the Free Software Foundation, either version 2 of the License, or
8(at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19#pragma once
20
21#if __has_include_next("_timer.h")
22# include_next "_timer.h" /* Include the platform's _timer.h */
23#endif
24
25#include <stdint.h>
26
27#define TIMER_DIFF(a, b, max) ((max == UINT8_MAX) ? ((uint8_t)((a) - (b))) : ((max == UINT16_MAX) ? ((uint16_t)((a) - (b))) : ((max == UINT32_MAX) ? ((uint32_t)((a) - (b))) : ((a) >= (b) ? (a) - (b) : (max) + 1 - (b) + (a)))))
28#define TIMER_DIFF_8(a, b) TIMER_DIFF(a, b, UINT8_MAX)
29#define TIMER_DIFF_16(a, b) TIMER_DIFF(a, b, UINT16_MAX)
30#define TIMER_DIFF_32(a, b) TIMER_DIFF(a, b, UINT32_MAX)
31#define TIMER_DIFF_RAW(a, b) TIMER_DIFF_8(a, b)
32
33#ifdef __cplusplus
34extern "C" {
35#endif
36
37extern volatile uint32_t timer_count;
38
39void timer_init(void);
40void timer_clear(void);
41uint16_t timer_read(void);
42uint32_t timer_read32(void);
43uint16_t timer_elapsed(uint16_t last);
44uint32_t timer_elapsed32(uint32_t last);
45
46// Utility functions to check if a future time has expired & autmatically handle time wrapping if checked / reset frequently (half of max value)
47#define timer_expired(current, future) ((uint16_t)(current - future) < UINT16_MAX / 2)
48#define timer_expired32(current, future) ((uint32_t)(current - future) < UINT32_MAX / 2)
49
50// Use an appropriate timer integer size based on architecture (16-bit will overflow sooner)
51#if FAST_TIMER_T_SIZE < 32
52# define TIMER_DIFF_FAST(a, b) TIMER_DIFF_16(a, b)
53# define timer_expired_fast(current, future) timer_expired(current, future)
54typedef uint16_t fast_timer_t;
55fast_timer_t inline timer_read_fast(void) { return timer_read(); }
56fast_timer_t inline timer_elapsed_fast(fast_timer_t last) { return timer_elapsed(last); }
57#else
58# define TIMER_DIFF_FAST(a, b) TIMER_DIFF_32(a, b)
59# define timer_expired_fast(current, future) timer_expired32(current, future)
60typedef uint32_t fast_timer_t;
61fast_timer_t inline timer_read_fast(void) { return timer_read32(); }
62fast_timer_t inline timer_elapsed_fast(fast_timer_t last) { return timer_elapsed32(last); }
63#endif
64
65#ifdef __cplusplus
66}
67#endif
diff --git a/platforms/wait.h b/platforms/wait.h
new file mode 100644
index 000000000..cf7180fb0
--- /dev/null
+++ b/platforms/wait.h
@@ -0,0 +1,30 @@
1/* Copyright 2021 QMK
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#pragma once
17
18#include <inttypes.h>
19
20#ifdef __cplusplus
21extern "C" {
22#endif
23
24#if __has_include_next("_wait.h")
25# include_next "_wait.h" /* Include the platforms _wait.h */
26#endif
27
28#ifdef __cplusplus
29}
30#endif