diff options
| author | Joel Challis <git@zvecr.com> | 2021-11-19 18:41:02 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-11-19 10:41:02 -0800 |
| commit | 2728603fe6d73e805a539d337fd01051c46ca806 (patch) | |
| tree | 5c83ffc7efa112da870bd5d8502a9d91d4792f35 /platforms/chibios | |
| parent | 43b9e23bae12916d5161f03700c9bfe46737324b (diff) | |
| download | qmk_firmware-2728603fe6d73e805a539d337fd01051c46ca806.tar.gz qmk_firmware-2728603fe6d73e805a539d337fd01051c46ca806.zip | |
Move tmk_core/common/<plat> (#13918)
Diffstat (limited to 'platforms/chibios')
| -rw-r--r-- | platforms/chibios/_timer.h | 19 | ||||
| -rw-r--r-- | platforms/chibios/_wait.c | 89 | ||||
| -rw-r--r-- | platforms/chibios/_wait.h | 60 | ||||
| -rw-r--r-- | platforms/chibios/atomic_util.h | 37 | ||||
| -rw-r--r-- | platforms/chibios/bootloader.c | 145 | ||||
| -rw-r--r-- | platforms/chibios/chibios_config.h | 78 | ||||
| -rw-r--r-- | platforms/chibios/eeprom_stm32.c | 687 | ||||
| -rw-r--r-- | platforms/chibios/eeprom_stm32.h | 33 | ||||
| -rw-r--r-- | platforms/chibios/eeprom_stm32_defs.h | 74 | ||||
| -rw-r--r-- | platforms/chibios/eeprom_teensy.c | 795 | ||||
| -rw-r--r-- | platforms/chibios/flash_stm32.c | 208 | ||||
| -rw-r--r-- | platforms/chibios/flash_stm32.h | 44 | ||||
| -rw-r--r-- | platforms/chibios/gd32v_compatibility.h | 120 | ||||
| -rw-r--r-- | platforms/chibios/gpio.h | 50 | ||||
| -rw-r--r-- | platforms/chibios/pin_defs.h | 323 | ||||
| -rw-r--r-- | platforms/chibios/platform.c | 22 | ||||
| -rw-r--r-- | platforms/chibios/platform.mk | 436 | ||||
| -rw-r--r-- | platforms/chibios/platform_deps.h | 19 | ||||
| -rw-r--r-- | platforms/chibios/sleep_led.c | 192 | ||||
| -rw-r--r-- | platforms/chibios/suspend.c | 92 | ||||
| -rw-r--r-- | platforms/chibios/syscall-fallbacks.c | 110 | ||||
| -rw-r--r-- | platforms/chibios/timer.c | 47 | ||||
| -rw-r--r-- | platforms/chibios/wait.c | 41 |
23 files changed, 3721 insertions, 0 deletions
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 | ||
| 32 | void 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 | |||
| 20 | static __inline__ uint8_t __interrupt_disable__(void) { | ||
| 21 | chSysLock(); | ||
| 22 | |||
| 23 | return 1; | ||
| 24 | } | ||
| 25 | |||
| 26 | static __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/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 | ||
| 21 | extern uint32_t _board_dfu_dbl_tap[]; | ||
| 22 | # define DBL_TAP_REG _board_dfu_dbl_tap[0] | ||
| 23 | |||
| 24 | void bootloader_jump(void) { | ||
| 25 | DBL_TAP_REG = DBL_TAP_MAGIC; | ||
| 26 | NVIC_SystemReset(); | ||
| 27 | } | ||
| 28 | |||
| 29 | void 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 | |||
| 49 | extern 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 | |||
| 71 | void 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 | |||
| 75 | extern 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 | |||
| 82 | void 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 | |||
| 117 | void 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 | ||
| 126 | const 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/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 */ | ||
| 214 | static uint16_t WordBuf[FEE_DENSITY_BYTES / 2]; | ||
| 215 | static uint8_t *DataBuf = (uint8_t *)WordBuf; | ||
| 216 | |||
| 217 | /* Pointer to the first available slot within the write log */ | ||
| 218 | static 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 | |||
| 240 | void 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 | |||
| 278 | uint16_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) */ | ||
| 354 | static 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 */ | ||
| 369 | void 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 */ | ||
| 378 | static 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 | |||
| 409 | static 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 | |||
| 429 | static 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 | |||
| 477 | static 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 | |||
| 501 | uint8_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 | |||
| 535 | uint8_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 | |||
| 593 | uint8_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 | |||
| 605 | uint16_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 | *******************************************************************************/ | ||
| 625 | void eeprom_driver_init(void) { EEPROM_Init(); } | ||
| 626 | |||
| 627 | void eeprom_driver_erase(void) { EEPROM_Erase(); } | ||
| 628 | |||
| 629 | void 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 | |||
| 659 | void 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 | |||
| 26 | uint16_t EEPROM_Init(void); | ||
| 27 | void EEPROM_Erase(void); | ||
| 28 | uint8_t EEPROM_WriteDataByte(uint16_t Address, uint8_t DataByte); | ||
| 29 | uint8_t EEPROM_WriteDataWord(uint16_t Address, uint16_t DataWord); | ||
| 30 | uint8_t EEPROM_ReadDataByte(uint16_t Address); | ||
| 31 | uint16_t EEPROM_ReadDataWord(uint16_t Address); | ||
| 32 | |||
| 33 | void 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 | |||
| 47 | static 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 | |||
| 105 | static 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 | */ | ||
| 225 | void 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 | */ | ||
| 264 | uint8_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 | */ | ||
| 275 | uint16_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 | */ | ||
| 286 | uint32_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 | */ | ||
| 297 | void 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 | */ | ||
| 313 | int eeprom_is_ready(void) { return (FTFL->FCNFG & FTFL_FCNFG_EEERDY) ? 1 : 0; } | ||
| 314 | |||
| 315 | /** \brief flexram wait | ||
| 316 | * | ||
| 317 | * FIXME: needs doc | ||
| 318 | */ | ||
| 319 | static 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 | */ | ||
| 329 | void 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 | */ | ||
| 348 | void 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 | */ | ||
| 390 | void 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 | */ | ||
| 460 | void 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 | /* | ||
| 516 | void do_flash_cmd(volatile uint8_t *fstat) | ||
| 517 | { | ||
| 518 | *fstat = 0x80; | ||
| 519 | while ((*fstat & 0x80) == 0) ; // wait | ||
| 520 | } | ||
| 521 | 00000000 <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 | |||
| 535 | extern uint32_t __eeprom_workarea_start__; | ||
| 536 | extern uint32_t __eeprom_workarea_end__; | ||
| 537 | |||
| 538 | # define EEPROM_SIZE 128 | ||
| 539 | |||
| 540 | static uint32_t flashend = 0; | ||
| 541 | |||
| 542 | void 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 | |||
| 554 | uint8_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 | |||
| 574 | static 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 | |||
| 589 | void 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 | /* | ||
| 654 | void do_flash_cmd(volatile uint8_t *fstat) | ||
| 655 | { | ||
| 656 | *fstat = 0x80; | ||
| 657 | while ((*fstat & 0x80) == 0) ; // wait | ||
| 658 | } | ||
| 659 | 00000000 <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 | |||
| 669 | uint16_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 | |||
| 674 | uint32_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 | |||
| 679 | void 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 | |||
| 687 | int eeprom_is_ready(void) { return 1; } | ||
| 688 | |||
| 689 | void 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 | |||
| 695 | void 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 | |||
| 703 | void 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 | |||
| 720 | uint8_t eeprom_read_byte(const uint8_t *addr) { | ||
| 721 | uint32_t offset = (uint32_t)addr; | ||
| 722 | return buffer[offset]; | ||
| 723 | } | ||
| 724 | |||
| 725 | void eeprom_write_byte(uint8_t *addr, uint8_t value) { | ||
| 726 | uint32_t offset = (uint32_t)addr; | ||
| 727 | buffer[offset] = value; | ||
| 728 | } | ||
| 729 | |||
| 730 | uint16_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 | |||
| 735 | uint32_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 | |||
| 740 | void 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 | |||
| 748 | void 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 | |||
| 754 | void 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 | |||
| 762 | void 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 | |||
| 773 | void eeprom_update_byte(uint8_t *addr, uint8_t value) { eeprom_write_byte(addr, value); } | ||
| 774 | |||
| 775 | void 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 | |||
| 781 | void 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 | |||
| 789 | void 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_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 | |||
| 37 | static 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 | */ | ||
| 65 | static 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 | */ | ||
| 77 | FLASH_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 | */ | ||
| 97 | FLASH_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 | */ | ||
| 119 | FLASH_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 | */ | ||
| 160 | FLASH_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 | */ | ||
| 192 | void 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 | */ | ||
| 205 | void 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 | ||
| 22 | extern "C" { | ||
| 23 | #endif | ||
| 24 | |||
| 25 | #include <stdint.h> | ||
| 26 | |||
| 27 | #ifdef FLASH_STM32_MOCKED | ||
| 28 | extern uint8_t FlashBuf[MOCK_FLASH_SIZE]; | ||
| 29 | #endif | ||
| 30 | |||
| 31 | typedef 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 | |||
| 35 | FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout); | ||
| 36 | FLASH_Status FLASH_ErasePage(uint32_t Page_Address); | ||
| 37 | FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data); | ||
| 38 | |||
| 39 | void FLASH_Unlock(void); | ||
| 40 | void 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 | |||
| 21 | typedef 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 | |||
| 40 | typedef 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 | |||
| 19 | void 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..6b298732c --- /dev/null +++ b/platforms/chibios/platform.mk | |||
| @@ -0,0 +1,436 @@ | |||
| 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. | ||
| 8 | ifeq ($(USE_PROCESS_STACKSIZE),) | ||
| 9 | USE_PROCESS_STACKSIZE = 0x800 | ||
| 10 | endif | ||
| 11 | |||
| 12 | # Stack size to the allocated to the Cortex-M main/exceptions stack. This | ||
| 13 | # stack is used for processing interrupts and exceptions. | ||
| 14 | ifeq ($(USE_EXCEPTIONS_STACKSIZE),) | ||
| 15 | USE_EXCEPTIONS_STACKSIZE = 0x400 | ||
| 16 | endif | ||
| 17 | |||
| 18 | # | ||
| 19 | # Architecture or project specific options | ||
| 20 | ############################################################################## | ||
| 21 | |||
| 22 | ############################################################################## | ||
| 23 | # Project, sources and paths | ||
| 24 | # | ||
| 25 | |||
| 26 | # Imported source files and paths | ||
| 27 | OPT_OS = chibios | ||
| 28 | CHIBIOS = $(TOP_DIR)/lib/chibios | ||
| 29 | CHIBIOS_CONTRIB = $(TOP_DIR)/lib/chibios-contrib | ||
| 30 | |||
| 31 | # | ||
| 32 | # Startup, Port and Platform support selection | ||
| 33 | ############################################################################## | ||
| 34 | |||
| 35 | ifeq ($(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 | ||
| 43 | else | ||
| 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 | ||
| 79 | endif | ||
| 80 | |||
| 81 | ifeq ("$(PLATFORM_NAME)","") | ||
| 82 | PLATFORM_NAME = platform | ||
| 83 | endif | ||
| 84 | |||
| 85 | ifeq ("$(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 | ||
| 90 | endif | ||
| 91 | |||
| 92 | include $(STARTUP_MK) | ||
| 93 | include $(PORT_V) | ||
| 94 | include $(PLATFORM_MK) | ||
| 95 | |||
| 96 | # | ||
| 97 | # Board support selection. | ||
| 98 | ############################################################################## | ||
| 99 | |||
| 100 | BOARD_MK := | ||
| 101 | |||
| 102 | ifneq ("$(wildcard $(KEYBOARD_PATH_5)/boards/$(BOARD)/board.mk)","") | ||
| 103 | BOARD_PATH = $(KEYBOARD_PATH_5) | ||
| 104 | BOARD_MK += $(KEYBOARD_PATH_5)/boards/$(BOARD)/board.mk | ||
| 105 | else 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 | ||
| 108 | else 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 | ||
| 111 | else 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 | ||
| 114 | else 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 | ||
| 117 | else 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 | ||
| 124 | endif | ||
| 125 | |||
| 126 | ifeq ("$(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 | ||
| 131 | endif | ||
| 132 | |||
| 133 | include $(BOARD_MK) | ||
| 134 | |||
| 135 | # | ||
| 136 | # Bootloader selection. | ||
| 137 | ############################################################################## | ||
| 138 | |||
| 139 | # Set bootloader address if supplied. | ||
| 140 | ifdef STM32_BOOTLOADER_ADDRESS | ||
| 141 | OPT_DEFS += -DSTM32_BOOTLOADER_ADDRESS=$(STM32_BOOTLOADER_ADDRESS) | ||
| 142 | endif | ||
| 143 | |||
| 144 | # Work out if we need to set up the include for the bootloader definitions | ||
| 145 | ifneq ("$(wildcard $(KEYBOARD_PATH_5)/bootloader_defs.h)","") | ||
| 146 | OPT_DEFS += -include $(KEYBOARD_PATH_5)/bootloader_defs.h | ||
| 147 | else ifneq ("$(wildcard $(KEYBOARD_PATH_5)/boards/$(BOARD)/bootloader_defs.h)","") | ||
| 148 | OPT_DEFS += -include $(KEYBOARD_PATH_5)/boards/$(BOARD)/bootloader_defs.h | ||
| 149 | else ifneq ("$(wildcard $(KEYBOARD_PATH_4)/bootloader_defs.h)","") | ||
| 150 | OPT_DEFS += -include $(KEYBOARD_PATH_4)/bootloader_defs.h | ||
| 151 | else ifneq ("$(wildcard $(KEYBOARD_PATH_4)/boards/$(BOARD)/bootloader_defs.h)","") | ||
| 152 | OPT_DEFS += -include $(KEYBOARD_PATH_4)/boards/$(BOARD)/bootloader_defs.h | ||
| 153 | else ifneq ("$(wildcard $(KEYBOARD_PATH_3)/bootloader_defs.h)","") | ||
| 154 | OPT_DEFS += -include $(KEYBOARD_PATH_3)/bootloader_defs.h | ||
| 155 | else ifneq ("$(wildcard $(KEYBOARD_PATH_3)/boards/$(BOARD)/bootloader_defs.h)","") | ||
| 156 | OPT_DEFS += -include $(KEYBOARD_PATH_3)/boards/$(BOARD)/bootloader_defs.h | ||
| 157 | else ifneq ("$(wildcard $(KEYBOARD_PATH_2)/bootloader_defs.h)","") | ||
| 158 | OPT_DEFS += -include $(KEYBOARD_PATH_2)/bootloader_defs.h | ||
| 159 | else ifneq ("$(wildcard $(KEYBOARD_PATH_2)/boards/$(BOARD)/bootloader_defs.h)","") | ||
| 160 | OPT_DEFS += -include $(KEYBOARD_PATH_2)/boards/$(BOARD)/bootloader_defs.h | ||
| 161 | else ifneq ("$(wildcard $(KEYBOARD_PATH_1)/bootloader_defs.h)","") | ||
| 162 | OPT_DEFS += -include $(KEYBOARD_PATH_1)/bootloader_defs.h | ||
| 163 | else ifneq ("$(wildcard $(KEYBOARD_PATH_1)/boards/$(BOARD)/bootloader_defs.h)","") | ||
| 164 | OPT_DEFS += -include $(KEYBOARD_PATH_1)/boards/$(BOARD)/bootloader_defs.h | ||
| 165 | else ifneq ("$(wildcard $(BOARD_PATH)/configs/bootloader_defs.h)","") | ||
| 166 | OPT_DEFS += -include $(BOARD_PATH)/configs/bootloader_defs.h | ||
| 167 | endif | ||
| 168 | |||
| 169 | # | ||
| 170 | # ChibiOS config selection. | ||
| 171 | ############################################################################## | ||
| 172 | |||
| 173 | # Work out the config file directories | ||
| 174 | ifneq ("$(wildcard $(KEYBOARD_PATH_5)/chconf.h)","") | ||
| 175 | CHCONFDIR = $(KEYBOARD_PATH_5) | ||
| 176 | else ifneq ("$(wildcard $(KEYBOARD_PATH_4)/chconf.h)","") | ||
| 177 | CHCONFDIR = $(KEYBOARD_PATH_4) | ||
| 178 | else ifneq ("$(wildcard $(KEYBOARD_PATH_3)/chconf.h)","") | ||
| 179 | CHCONFDIR = $(KEYBOARD_PATH_3) | ||
| 180 | else ifneq ("$(wildcard $(KEYBOARD_PATH_2)/chconf.h)","") | ||
| 181 | CHCONFDIR = $(KEYBOARD_PATH_2) | ||
| 182 | else ifneq ("$(wildcard $(KEYBOARD_PATH_1)/chconf.h)","") | ||
| 183 | CHCONFDIR = $(KEYBOARD_PATH_1) | ||
| 184 | else ifneq ("$(wildcard $(TOP_DIR)/platforms/chibios/boards/$(BOARD)/configs/chconf.h)","") | ||
| 185 | CHCONFDIR = $(TOP_DIR)/platforms/chibios/boards/$(BOARD)/configs | ||
| 186 | else ifneq ("$(wildcard $(TOP_DIR)/platforms/boards/chibios/common/configs/chconf.h)","") | ||
| 187 | CHCONFDIR = $(TOP_DIR)/platforms/chibios/boards/common/configs | ||
| 188 | endif | ||
| 189 | |||
| 190 | # | ||
| 191 | # HAL config selection. | ||
| 192 | ############################################################################## | ||
| 193 | |||
| 194 | ifneq ("$(wildcard $(KEYBOARD_PATH_5)/halconf.h)","") | ||
| 195 | HALCONFDIR = $(KEYBOARD_PATH_5) | ||
| 196 | else ifneq ("$(wildcard $(KEYBOARD_PATH_4)/halconf.h)","") | ||
| 197 | HALCONFDIR = $(KEYBOARD_PATH_4) | ||
| 198 | else ifneq ("$(wildcard $(KEYBOARD_PATH_3)/halconf.h)","") | ||
| 199 | HALCONFDIR = $(KEYBOARD_PATH_3) | ||
| 200 | else ifneq ("$(wildcard $(KEYBOARD_PATH_2)/halconf.h)","") | ||
| 201 | HALCONFDIR = $(KEYBOARD_PATH_2) | ||
| 202 | else ifneq ("$(wildcard $(KEYBOARD_PATH_1)/halconf.h)","") | ||
| 203 | HALCONFDIR = $(KEYBOARD_PATH_1) | ||
| 204 | else ifneq ("$(wildcard $(TOP_DIR)/platforms/chibios/boards/$(BOARD)/configs/halconf.h)","") | ||
| 205 | HALCONFDIR = $(TOP_DIR)/platforms/chibios/boards/$(BOARD)/configs | ||
| 206 | else ifneq ("$(wildcard $(TOP_DIR)/platforms/chibios/boards/common/configs/halconf.h)","") | ||
| 207 | HALCONFDIR = $(TOP_DIR)/platforms/chibios/boards/common/configs | ||
| 208 | endif | ||
| 209 | |||
| 210 | # | ||
| 211 | # Linker script selection. | ||
| 212 | ############################################################################## | ||
| 213 | |||
| 214 | ifneq ("$(wildcard $(KEYBOARD_PATH_5)/ld/$(MCU_LDSCRIPT).ld)","") | ||
| 215 | LDSCRIPT = $(KEYBOARD_PATH_5)/ld/$(MCU_LDSCRIPT).ld | ||
| 216 | else ifneq ("$(wildcard $(KEYBOARD_PATH_4)/ld/$(MCU_LDSCRIPT).ld)","") | ||
| 217 | LDSCRIPT = $(KEYBOARD_PATH_4)/ld/$(MCU_LDSCRIPT).ld | ||
| 218 | else ifneq ("$(wildcard $(KEYBOARD_PATH_3)/ld/$(MCU_LDSCRIPT).ld)","") | ||
| 219 | LDSCRIPT = $(KEYBOARD_PATH_3)/ld/$(MCU_LDSCRIPT).ld | ||
| 220 | else ifneq ("$(wildcard $(KEYBOARD_PATH_2)/ld/$(MCU_LDSCRIPT).ld)","") | ||
| 221 | LDSCRIPT = $(KEYBOARD_PATH_2)/ld/$(MCU_LDSCRIPT).ld | ||
| 222 | else ifneq ("$(wildcard $(KEYBOARD_PATH_1)/ld/$(MCU_LDSCRIPT).ld)","") | ||
| 223 | LDSCRIPT = $(KEYBOARD_PATH_1)/ld/$(MCU_LDSCRIPT).ld | ||
| 224 | else 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 | ||
| 227 | else ifneq ("$(wildcard $(TOP_DIR)/platforms/chibios/boards/common/ld/$(MCU_LDSCRIPT).ld)","") | ||
| 228 | LDSCRIPT = $(TOP_DIR)/platforms/chibios/boards/common/ld/$(MCU_LDSCRIPT).ld | ||
| 229 | else ifneq ("$(wildcard $(STARTUPLD_CONTRIB)/$(MCU_LDSCRIPT).ld)","") | ||
| 230 | LDSCRIPT = $(STARTUPLD_CONTRIB)/$(MCU_LDSCRIPT).ld | ||
| 231 | USE_CHIBIOS_CONTRIB = yes | ||
| 232 | else | ||
| 233 | LDSCRIPT = $(STARTUPLD)/$(MCU_LDSCRIPT).ld | ||
| 234 | endif | ||
| 235 | |||
| 236 | # | ||
| 237 | # Include ChibiOS makefiles. | ||
| 238 | ############################################################################## | ||
| 239 | |||
| 240 | # HAL-OSAL files (optional). | ||
| 241 | include $(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). | ||
| 245 | include $(CHIBIOS)/os/rt/rt.mk | ||
| 246 | # Other files (optional). | ||
| 247 | include $(CHIBIOS)/os/hal/lib/streams/streams.mk | ||
| 248 | |||
| 249 | PLATFORM_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. | ||
| 263 | QUANTUM_LIB_SRC += $(STARTUPASM) $(PORTASM) $(OSALASM) $(PLATFORMASM) | ||
| 264 | |||
| 265 | PLATFORM_SRC := $(patsubst $(TOP_DIR)/%,%,$(PLATFORM_SRC)) | ||
| 266 | |||
| 267 | EXTRAINCDIRS += $(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 | ||
| 280 | ifneq ("$(wildcard $(KEYBOARD_PATH_5)/halconf_community.h)","") | ||
| 281 | USE_CHIBIOS_CONTRIB = yes | ||
| 282 | else ifneq ("$(wildcard $(KEYBOARD_PATH_4)/halconf_community.h)","") | ||
| 283 | USE_CHIBIOS_CONTRIB = yes | ||
| 284 | else ifneq ("$(wildcard $(KEYBOARD_PATH_3)/halconf_community.h)","") | ||
| 285 | USE_CHIBIOS_CONTRIB = yes | ||
| 286 | else ifneq ("$(wildcard $(KEYBOARD_PATH_2)/halconf_community.h)","") | ||
| 287 | USE_CHIBIOS_CONTRIB = yes | ||
| 288 | else ifneq ("$(wildcard $(KEYBOARD_PATH_1)/halconf_community.h)","") | ||
| 289 | USE_CHIBIOS_CONTRIB = yes | ||
| 290 | else ifneq ("$(wildcard $(TOP_DIR)/platforms/chibios/boards/$(BOARD)/configs/halconf_community.h)","") | ||
| 291 | USE_CHIBIOS_CONTRIB = yes | ||
| 292 | endif | ||
| 293 | |||
| 294 | ifeq ($(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 | ||
| 298 | endif | ||
| 299 | |||
| 300 | # | ||
| 301 | # Project, sources and paths | ||
| 302 | ############################################################################## | ||
| 303 | |||
| 304 | ############################################################################## | ||
| 305 | # Injected configs | ||
| 306 | # | ||
| 307 | ifneq ("$(wildcard $(BOARD_PATH)/configs/config.h)","") | ||
| 308 | CONFIG_H += $(BOARD_PATH)/configs/config.h | ||
| 309 | endif | ||
| 310 | ifneq ("$(wildcard $(BOARD_PATH)/configs/post_config.h)","") | ||
| 311 | POST_CONFIG_H += $(BOARD_PATH)/configs/post_config.h | ||
| 312 | endif | ||
| 313 | |||
| 314 | ############################################################################## | ||
| 315 | # Compiler and Linker configuration | ||
| 316 | # | ||
| 317 | |||
| 318 | # Use defined stack sizes of the main thread in linker scripts | ||
| 319 | LDSYMBOLS =--defsym=__process_stack_size__=$(USE_PROCESS_STACKSIZE),--defsym=__main_stack_size__=$(USE_EXCEPTIONS_STACKSIZE) | ||
| 320 | |||
| 321 | # Shared Compiler flags for all toolchains | ||
| 322 | SHARED_CFLAGS = -fomit-frame-pointer \ | ||
| 323 | -ffunction-sections \ | ||
| 324 | -fdata-sections \ | ||
| 325 | -fno-common \ | ||
| 326 | -fshort-wchar | ||
| 327 | |||
| 328 | # Shared Linker flags for all toolchains | ||
| 329 | SHARED_LDFLAGS = -T $(LDSCRIPT) \ | ||
| 330 | -Wl,$(LDSYMBOLS) \ | ||
| 331 | -Wl,--gc-sections \ | ||
| 332 | -nostartfiles | ||
| 333 | |||
| 334 | ifeq ($(strip $(MCU)), risc-v) | ||
| 335 | # RISC-V toolchain specific configuration | ||
| 336 | # Find suitable GCC compiler | ||
| 337 | ifeq ($(strip $(TOOLCHAIN)),) | ||
| 338 | ifneq ($(shell which riscv32-unknown-elf-gcc 2>/dev/null),) | ||
| 339 | TOOLCHAIN = riscv32-unknown-elf- | ||
| 340 | else | ||
| 341 | ifneq ($(shell which riscv64-unknown-elf-gcc 2>/dev/null),) | ||
| 342 | TOOLCHAIN = riscv64-unknown-elf- | ||
| 343 | else | ||
| 344 | $(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!") | ||
| 345 | endif | ||
| 346 | endif | ||
| 347 | endif | ||
| 348 | |||
| 349 | # Default to compiling with picolibc for RISC-V targets if available, | ||
| 350 | # which is available by default on current (bullseye) debian based systems. | ||
| 351 | ifeq ($(shell $(TOOLCHAIN)gcc --specs=picolibc.specs -E - 2>/dev/null >/dev/null </dev/null ; echo $$?),0) | ||
| 352 | # Toolchain specific Compiler flags | ||
| 353 | # Note that we still link with our own linker script | ||
| 354 | # by providing it via the -T flag above. | ||
| 355 | TOOLCHAIN_CFLAGS = --specs=picolibc.specs | ||
| 356 | |||
| 357 | # Tell QMK that we are compiling with picolibc. | ||
| 358 | OPT_DEFS += -DUSE_PICOLIBC | ||
| 359 | endif | ||
| 360 | |||
| 361 | # MCU architecture flags | ||
| 362 | MCUFLAGS = -march=$(MCU_ARCH) \ | ||
| 363 | -mabi=$(MCU_ABI) \ | ||
| 364 | -mcmodel=$(MCU_CMODEL) \ | ||
| 365 | -mstrict-align | ||
| 366 | else | ||
| 367 | # ARM toolchain specific configuration | ||
| 368 | TOOLCHAIN ?= arm-none-eabi- | ||
| 369 | |||
| 370 | # Toolchain specific Linker flags | ||
| 371 | TOOLCHAIN_LDFLAGS = -Wl,--no-wchar-size-warning \ | ||
| 372 | --specs=nano.specs | ||
| 373 | |||
| 374 | # MCU architecture flags | ||
| 375 | MCUFLAGS = -mcpu=$(MCU) \ | ||
| 376 | -mthumb -DTHUMB_PRESENT \ | ||
| 377 | -mno-thumb-interwork -DTHUMB_NO_INTERWORKING \ | ||
| 378 | -mno-unaligned-access | ||
| 379 | |||
| 380 | # Some ARM cores like the M4 and M7 have floating point units which can be enabled | ||
| 381 | USE_FPU ?= no | ||
| 382 | |||
| 383 | ifneq ($(USE_FPU),no) | ||
| 384 | OPT_DEFS += -DCORTEX_USE_FPU=TRUE | ||
| 385 | |||
| 386 | # Default is single precision floats | ||
| 387 | USE_FPU_OPT ?= -mfloat-abi=hard \ | ||
| 388 | -mfpu=fpv4-sp-d16 \ | ||
| 389 | -fsingle-precision-constant | ||
| 390 | |||
| 391 | MCUFLAGS += $(USE_FPU_OPT) | ||
| 392 | else | ||
| 393 | OPT_DEFS += -DCORTEX_USE_FPU=FALSE | ||
| 394 | endif | ||
| 395 | endif | ||
| 396 | |||
| 397 | # Assembler flags | ||
| 398 | ASFLAGS += $(SHARED_ASFLAGS) $(TOOLCHAIN_ASFLAGS) | ||
| 399 | |||
| 400 | # C Compiler flags | ||
| 401 | CFLAGS += $(SHARED_CFLAGS) $(TOOLCHAIN_CFLAGS) | ||
| 402 | |||
| 403 | # C++ Compiler flags | ||
| 404 | CXXFLAGS += $(CFLAGS) $(SHARED_CXXFLAGS) $(TOOLCHAIN_CXXFLAGS) -fno-rtti | ||
| 405 | |||
| 406 | # Linker flags | ||
| 407 | LDFLAGS += $(SHARED_LDFLAGS) $(TOOLCHAIN_LDFLAGS) $(MCUFLAGS) | ||
| 408 | |||
| 409 | # Tell QMK that we are hosting it on ChibiOS. | ||
| 410 | OPT_DEFS += -DPROTOCOL_CHIBIOS | ||
| 411 | |||
| 412 | # Workaround to stop ChibiOS from complaining about new GCC -- it's been fixed for 7/8/9 already | ||
| 413 | OPT_DEFS += -DPORT_IGNORE_GCC_VERSION_CHECK=1 | ||
| 414 | |||
| 415 | # Construct GCC toolchain | ||
| 416 | CC = $(CC_PREFIX) $(TOOLCHAIN)gcc | ||
| 417 | OBJCOPY = $(TOOLCHAIN)objcopy | ||
| 418 | OBJDUMP = $(TOOLCHAIN)objdump | ||
| 419 | SIZE = $(TOOLCHAIN)size | ||
| 420 | AR = $(TOOLCHAIN)ar | ||
| 421 | NM = $(TOOLCHAIN)nm | ||
| 422 | HEX = $(OBJCOPY) -O $(FORMAT) | ||
| 423 | EEP = | ||
| 424 | BIN = $(OBJCOPY) -O binary | ||
| 425 | |||
| 426 | ############################################################################## | ||
| 427 | # Make targets | ||
| 428 | # | ||
| 429 | |||
| 430 | DEBUG = gdb | ||
| 431 | |||
| 432 | # List any extra directories to look for libraries here. | ||
| 433 | EXTRALIBDIRS = $(RULESPATH)/ld | ||
| 434 | |||
| 435 | bin: $(BUILD_DIR)/$(TARGET).bin sizeafter | ||
| 436 | $(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 | */ | ||
| 26 | static 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 | |||
| 28 | void 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 */ | ||
| 78 | OSAL_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 */ | ||
| 90 | void 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 | |||
| 147 | void sleep_led_enable(void) { | ||
| 148 | /* Enable the timer */ | ||
| 149 | LPTMR0->CSR |= LPTMRx_CSR_TEN; | ||
| 150 | } | ||
| 151 | |||
| 152 | void sleep_led_disable(void) { | ||
| 153 | /* Disable the timer */ | ||
| 154 | LPTMR0->CSR &= ~LPTMRx_CSR_TEN; | ||
| 155 | } | ||
| 156 | |||
| 157 | void sleep_led_toggle(void) { | ||
| 158 | /* Toggle the timer */ | ||
| 159 | LPTMR0->CSR ^= LPTMRx_CSR_TEN; | ||
| 160 | } | ||
| 161 | |||
| 162 | #elif defined(SLEEP_LED_GPT_DRIVER) | ||
| 163 | |||
| 164 | static void gptTimerCallback(GPTDriver *gptp) { | ||
| 165 | (void)gptp; | ||
| 166 | sleep_led_timer_callback(); | ||
| 167 | } | ||
| 168 | |||
| 169 | static const GPTConfig gptcfg = {1000000, gptTimerCallback, 0, 0}; | ||
| 170 | |||
| 171 | /* Initialise the timer */ | ||
| 172 | void sleep_led_init(void) { gptStart(&SLEEP_LED_GPT_DRIVER, &gptcfg); } | ||
| 173 | |||
| 174 | void sleep_led_enable(void) { gptStartContinuous(&SLEEP_LED_GPT_DRIVER, gptcfg.frequency / 0xFFFF); } | ||
| 175 | |||
| 176 | void sleep_led_disable(void) { gptStopTimer(&SLEEP_LED_GPT_DRIVER); } | ||
| 177 | |||
| 178 | void 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 | |||
| 182 | void sleep_led_init(void) {} | ||
| 183 | |||
| 184 | void sleep_led_enable(void) { led_set(1 << USB_LED_CAPS_LOCK); } | ||
| 185 | |||
| 186 | void sleep_led_disable(void) { led_set(0); } | ||
| 187 | |||
| 188 | void 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 | */ | ||
| 20 | void 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 | */ | ||
| 29 | void 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) {} | ||
| 43 | bool 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 | */ | ||
| 70 | void 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..4569879c7 --- /dev/null +++ b/platforms/chibios/syscall-fallbacks.c | |||
| @@ -0,0 +1,110 @@ | |||
| 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) | ||
| 24 | struct _reent; | ||
| 25 | #endif | ||
| 26 | |||
| 27 | #pragma GCC diagnostic ignored "-Wmissing-prototypes" | ||
| 28 | |||
| 29 | __attribute__((weak, used)) int _open_r(struct _reent *r, const char *path, int flag, int m) { | ||
| 30 | __errno_r(r) = ENOENT; | ||
| 31 | return -1; | ||
| 32 | } | ||
| 33 | |||
| 34 | __attribute__((weak, used)) int _lseek_r(struct _reent *r, int file, int ptr, int dir) { | ||
| 35 | __errno_r(r) = EBADF; | ||
| 36 | return -1; | ||
| 37 | } | ||
| 38 | |||
| 39 | __attribute__((weak, used)) int _read_r(struct _reent *r, int file, char *ptr, int len) { | ||
| 40 | __errno_r(r) = EBADF; | ||
| 41 | return -1; | ||
| 42 | } | ||
| 43 | |||
| 44 | __attribute__((weak, used)) int _write_r(struct _reent *r, int file, char *ptr, int len) { | ||
| 45 | __errno_r(r) = EBADF; | ||
| 46 | return -1; | ||
| 47 | } | ||
| 48 | |||
| 49 | __attribute__((weak, used)) int _close_r(struct _reent *r, int file) { | ||
| 50 | __errno_r(r) = EBADF; | ||
| 51 | return -1; | ||
| 52 | } | ||
| 53 | |||
| 54 | __attribute__((weak, used)) int _link_r(struct _reent *r, const char *oldpath, const char *newpath) { | ||
| 55 | __errno_r(r) = EPERM; | ||
| 56 | return -1; | ||
| 57 | } | ||
| 58 | |||
| 59 | __attribute__((weak, used)) int _unlink_r(struct _reent *r, const char *path) { | ||
| 60 | __errno_r(r) = EPERM; | ||
| 61 | return -1; | ||
| 62 | } | ||
| 63 | |||
| 64 | __attribute__((weak, used)) clock_t _times_r(struct _reent *r, void *t) { | ||
| 65 | __errno_r(r) = EFAULT; | ||
| 66 | return -1; | ||
| 67 | } | ||
| 68 | |||
| 69 | __attribute__((weak, used)) int _fstat_r(struct _reent *r, int file, struct stat *st) { | ||
| 70 | __errno_r(r) = EBADF; | ||
| 71 | return -1; | ||
| 72 | } | ||
| 73 | |||
| 74 | __attribute__((weak, used)) int _isatty_r(struct _reent *r, int fd) { | ||
| 75 | __errno_r(r) = EBADF; | ||
| 76 | return 0; | ||
| 77 | } | ||
| 78 | |||
| 79 | __attribute__((weak, used)) caddr_t _sbrk_r(struct _reent *r, int incr) { | ||
| 80 | __errno_r(r) = ENOMEM; | ||
| 81 | return (caddr_t)-1; | ||
| 82 | } | ||
| 83 | |||
| 84 | __attribute__((weak, used)) int _kill(int pid, int sig) { | ||
| 85 | errno = EPERM; | ||
| 86 | return -1; | ||
| 87 | } | ||
| 88 | |||
| 89 | __attribute__((weak, used)) pid_t _getpid(void) { return 1; } | ||
| 90 | |||
| 91 | __attribute__((weak, used)) void _fini(void) { return; } | ||
| 92 | |||
| 93 | __attribute__((weak, used, noreturn)) void _exit(int i) { | ||
| 94 | while (1) | ||
| 95 | ; | ||
| 96 | } | ||
| 97 | |||
| 98 | __attribute__((weak, used)) int _gettimeofday_r(struct _reent *r, struct timeval *t, void *tzp) { | ||
| 99 | __errno_r(r) = EPERM; | ||
| 100 | return -1; | ||
| 101 | } | ||
| 102 | |||
| 103 | __attribute__((weak, used)) void *__dso_handle; | ||
| 104 | |||
| 105 | __attribute__((weak, used)) void __cxa_pure_virtual(void) { | ||
| 106 | while (1) | ||
| 107 | ; | ||
| 108 | } | ||
| 109 | |||
| 110 | #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 | |||
| 5 | static uint32_t reset_point = 0; | ||
| 6 | #if CH_CFG_ST_RESOLUTION < 32 | ||
| 7 | static uint32_t last_systime = 0; | ||
| 8 | static uint32_t overflow = 0; | ||
| 9 | #endif | ||
| 10 | |||
| 11 | void timer_init(void) { timer_clear(); } | ||
| 12 | |||
| 13 | void 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 | |||
| 21 | uint16_t timer_read(void) { return (uint16_t)timer_read32(); } | ||
| 22 | |||
| 23 | uint32_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 | |||
| 45 | uint16_t timer_elapsed(uint16_t last) { return TIMER_DIFF_16(timer_read(), last); } | ||
| 46 | |||
| 47 | uint32_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 | ||
| 23 | void 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 | ||
