diff options
Diffstat (limited to 'platforms')
131 files changed, 10646 insertions, 232 deletions
diff --git a/platforms/arm_atsam/_timer.h b/platforms/arm_atsam/_timer.h new file mode 100644 index 000000000..77402b612 --- /dev/null +++ b/platforms/arm_atsam/_timer.h | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | /* Copyright 2021 Simon Arlott | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 2 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #pragma once | ||
| 17 | |||
| 18 | // The platform is 32-bit, so prefer 32-bit timers to avoid overflow | ||
| 19 | #define FAST_TIMER_T_SIZE 32 | ||
diff --git a/platforms/arm_atsam/_wait.h b/platforms/arm_atsam/_wait.h new file mode 100644 index 000000000..41b686b56 --- /dev/null +++ b/platforms/arm_atsam/_wait.h | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | /* Copyright 2021 QMK | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 3 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #pragma once | ||
| 17 | |||
| 18 | #include "clks.h" | ||
| 19 | |||
| 20 | #define wait_ms(ms) CLK_delay_ms(ms) | ||
| 21 | #define wait_us(us) CLK_delay_us(us) | ||
| 22 | #define waitInputPinDelay() | ||
diff --git a/platforms/arm_atsam/atomic_util.h b/platforms/arm_atsam/atomic_util.h new file mode 100644 index 000000000..848542d23 --- /dev/null +++ b/platforms/arm_atsam/atomic_util.h | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | /* Copyright 2021 QMK | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 3 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #pragma once | ||
| 17 | |||
| 18 | #include "samd51j18a.h" | ||
| 19 | |||
| 20 | static __inline__ uint8_t __interrupt_disable__(void) { | ||
| 21 | __disable_irq(); | ||
| 22 | |||
| 23 | return 1; | ||
| 24 | } | ||
| 25 | |||
| 26 | static __inline__ void __interrupt_enable__(const uint8_t *__s) { | ||
| 27 | __enable_irq(); | ||
| 28 | |||
| 29 | __asm__ volatile("" ::: "memory"); | ||
| 30 | (void)__s; | ||
| 31 | } | ||
| 32 | |||
| 33 | #define ATOMIC_BLOCK(type) for (type, __ToDo = __interrupt_disable__(); __ToDo; __ToDo = 0) | ||
| 34 | #define ATOMIC_FORCEON uint8_t sreg_save __attribute__((__cleanup__(__interrupt_enable__))) = 0 | ||
| 35 | |||
| 36 | #define ATOMIC_BLOCK_RESTORESTATE _Static_assert(0, "ATOMIC_BLOCK_RESTORESTATE not implemented") | ||
| 37 | #define ATOMIC_BLOCK_FORCEON ATOMIC_BLOCK(ATOMIC_FORCEON) | ||
diff --git a/platforms/arm_atsam/bootloader.c b/platforms/arm_atsam/bootloader.c new file mode 100644 index 000000000..9015b00aa --- /dev/null +++ b/platforms/arm_atsam/bootloader.c | |||
| @@ -0,0 +1,57 @@ | |||
| 1 | /* Copyright 2017 Fred Sundvik | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 2 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include "bootloader.h" | ||
| 18 | #include "samd51j18a.h" | ||
| 19 | #include "md_bootloader.h" | ||
| 20 | |||
| 21 | // Set watchdog timer to reset. Directs the bootloader to stay in programming mode. | ||
| 22 | void bootloader_jump(void) { | ||
| 23 | #ifdef KEYBOARD_massdrop_ctrl | ||
| 24 | // CTRL keyboards released with bootloader version below must use RAM method. Otherwise use WDT method. | ||
| 25 | uint8_t ver_ram_method[] = "v2.18Jun 22 2018 17:28:08"; // The version to match (NULL terminated by compiler) | ||
| 26 | uint8_t *ver_check = ver_ram_method; // Pointer to version match string for traversal | ||
| 27 | uint8_t *ver_rom = (uint8_t *)0x21A0; // Pointer to address in ROM where this specific bootloader version would exist | ||
| 28 | |||
| 29 | while (*ver_check && *ver_rom == *ver_check) { // While there are check version characters to match and bootloader's version matches check's version | ||
| 30 | ver_check++; // Move check version pointer to next character | ||
| 31 | ver_rom++; // Move ROM version pointer to next character | ||
| 32 | } | ||
| 33 | |||
| 34 | if (!*ver_check) { // If check version pointer is NULL, all characters have matched | ||
| 35 | *MAGIC_ADDR = BOOTLOADER_MAGIC; // Set magic number into RAM | ||
| 36 | NVIC_SystemReset(); // Perform system reset | ||
| 37 | while (1) { | ||
| 38 | } // Won't get here | ||
| 39 | } | ||
| 40 | #endif | ||
| 41 | |||
| 42 | WDT->CTRLA.bit.ENABLE = 0; | ||
| 43 | while (WDT->SYNCBUSY.bit.ENABLE) { | ||
| 44 | } | ||
| 45 | while (WDT->CTRLA.bit.ENABLE) { | ||
| 46 | } | ||
| 47 | WDT->CONFIG.bit.WINDOW = 0; | ||
| 48 | WDT->CONFIG.bit.PER = 0; | ||
| 49 | WDT->EWCTRL.bit.EWOFFSET = 0; | ||
| 50 | WDT->CTRLA.bit.ENABLE = 1; | ||
| 51 | while (WDT->SYNCBUSY.bit.ENABLE) { | ||
| 52 | } | ||
| 53 | while (!WDT->CTRLA.bit.ENABLE) { | ||
| 54 | } | ||
| 55 | while (1) { | ||
| 56 | } // Wait on timeout | ||
| 57 | } | ||
diff --git a/platforms/arm_atsam/eeprom.c b/platforms/arm_atsam/eeprom.c new file mode 100644 index 000000000..ff1a69262 --- /dev/null +++ b/platforms/arm_atsam/eeprom.c | |||
| @@ -0,0 +1,184 @@ | |||
| 1 | /* Copyright 2017 Fred Sundvik | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 2 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #include "eeprom.h" | ||
| 17 | #include "debug.h" | ||
| 18 | #include "samd51j18a.h" | ||
| 19 | #include "core_cm4.h" | ||
| 20 | #include "component/nvmctrl.h" | ||
| 21 | |||
| 22 | #ifndef EEPROM_SIZE | ||
| 23 | # include "eeconfig.h" | ||
| 24 | # define EEPROM_SIZE (((EECONFIG_SIZE + 3) / 4) * 4) // based off eeconfig's current usage, aligned to 4-byte sizes, to deal with LTO | ||
| 25 | #endif | ||
| 26 | |||
| 27 | #ifndef MAX | ||
| 28 | # define MAX(X, Y) ((X) > (Y) ? (X) : (Y)) | ||
| 29 | #endif | ||
| 30 | |||
| 31 | #ifndef BUSY_RETRIES | ||
| 32 | # define BUSY_RETRIES 10000 | ||
| 33 | #endif | ||
| 34 | |||
| 35 | // #define DEBUG_EEPROM_OUTPUT | ||
| 36 | |||
| 37 | /* | ||
| 38 | * Debug print utils | ||
| 39 | */ | ||
| 40 | #if defined(DEBUG_EEPROM_OUTPUT) | ||
| 41 | # define eeprom_printf(fmt, ...) xprintf(fmt, ##__VA_ARGS__); | ||
| 42 | #else /* NO_DEBUG */ | ||
| 43 | # define eeprom_printf(fmt, ...) | ||
| 44 | #endif /* NO_DEBUG */ | ||
| 45 | |||
| 46 | __attribute__((aligned(4))) static uint8_t buffer[EEPROM_SIZE] = {0}; | ||
| 47 | volatile uint8_t * SmartEEPROM8 = (uint8_t *)SEEPROM_ADDR; | ||
| 48 | |||
| 49 | static inline bool eeprom_is_busy(void) { | ||
| 50 | int timeout = BUSY_RETRIES; | ||
| 51 | while (NVMCTRL->SEESTAT.bit.BUSY && timeout-- > 0) | ||
| 52 | ; | ||
| 53 | |||
| 54 | return NVMCTRL->SEESTAT.bit.BUSY; | ||
| 55 | } | ||
| 56 | |||
| 57 | static uint32_t get_virtual_eeprom_size(void) { | ||
| 58 | // clang-format off | ||
| 59 | static const uint32_t VIRTUAL_EEPROM_MAP[11][8] = { | ||
| 60 | /* 4 8 16 32 64 128 256 512 */ | ||
| 61 | /* 0*/ { 0, 0, 0, 0, 0, 0, 0, 0 }, | ||
| 62 | /* 1*/ { 512, 1024, 2048, 4096, 4096, 4096, 4096, 4096 }, | ||
| 63 | /* 2*/ { 512, 1024, 2048, 4096, 8192, 8192, 8192, 8192 }, | ||
| 64 | /* 3*/ { 512, 1024, 2048, 4096, 8192, 16384, 16384, 16384 }, | ||
| 65 | /* 4*/ { 512, 1024, 2048, 4096, 8192, 16384, 16384, 16384 }, | ||
| 66 | /* 5*/ { 512, 1024, 2048, 4096, 8192, 16384, 32768, 32768 }, | ||
| 67 | /* 6*/ { 512, 1024, 2048, 4096, 8192, 16384, 32768, 32768 }, | ||
| 68 | /* 7*/ { 512, 1024, 2048, 4096, 8192, 16384, 32768, 32768 }, | ||
| 69 | /* 8*/ { 512, 1024, 2048, 4096, 8192, 16384, 32768, 32768 }, | ||
| 70 | /* 9*/ { 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536 }, | ||
| 71 | /*10*/ { 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536 }, | ||
| 72 | }; | ||
| 73 | // clang-format on | ||
| 74 | |||
| 75 | static uint32_t virtual_eeprom_size = UINT32_MAX; | ||
| 76 | if (virtual_eeprom_size == UINT32_MAX) { | ||
| 77 | virtual_eeprom_size = VIRTUAL_EEPROM_MAP[NVMCTRL->SEESTAT.bit.PSZ][NVMCTRL->SEESTAT.bit.SBLK]; | ||
| 78 | } | ||
| 79 | // eeprom_printf("get_virtual_eeprom_size:: %d:%d:%d\n", NVMCTRL->SEESTAT.bit.PSZ, NVMCTRL->SEESTAT.bit.SBLK, virtual_eeprom_size); | ||
| 80 | return virtual_eeprom_size; | ||
| 81 | } | ||
| 82 | |||
| 83 | uint8_t eeprom_read_byte(const uint8_t *addr) { | ||
| 84 | uintptr_t offset = (uintptr_t)addr; | ||
| 85 | if (offset >= MAX(EEPROM_SIZE, get_virtual_eeprom_size())) { | ||
| 86 | eeprom_printf("eeprom_read_byte:: out of bounds\n"); | ||
| 87 | return 0x0; | ||
| 88 | } | ||
| 89 | |||
| 90 | if (get_virtual_eeprom_size() == 0) { | ||
| 91 | return buffer[offset]; | ||
| 92 | } | ||
| 93 | |||
| 94 | if (eeprom_is_busy()) { | ||
| 95 | eeprom_printf("eeprom_write_byte:: timeout\n"); | ||
| 96 | return 0x0; | ||
| 97 | } | ||
| 98 | |||
| 99 | return SmartEEPROM8[offset]; | ||
| 100 | } | ||
| 101 | |||
| 102 | void eeprom_write_byte(uint8_t *addr, uint8_t value) { | ||
| 103 | uintptr_t offset = (uintptr_t)addr; | ||
| 104 | if (offset >= MAX(EEPROM_SIZE, get_virtual_eeprom_size())) { | ||
| 105 | eeprom_printf("eeprom_write_byte:: out of bounds\n"); | ||
| 106 | return; | ||
| 107 | } | ||
| 108 | |||
| 109 | if (get_virtual_eeprom_size() == 0) { | ||
| 110 | buffer[offset] = value; | ||
| 111 | return; | ||
| 112 | } | ||
| 113 | |||
| 114 | if (eeprom_is_busy()) { | ||
| 115 | eeprom_printf("eeprom_write_byte:: timeout\n"); | ||
| 116 | return; | ||
| 117 | } | ||
| 118 | |||
| 119 | SmartEEPROM8[offset] = value; | ||
| 120 | } | ||
| 121 | |||
| 122 | uint16_t eeprom_read_word(const uint16_t *addr) { | ||
| 123 | const uint8_t *p = (const uint8_t *)addr; | ||
| 124 | return eeprom_read_byte(p) | (eeprom_read_byte(p + 1) << 8); | ||
| 125 | } | ||
| 126 | |||
| 127 | uint32_t eeprom_read_dword(const uint32_t *addr) { | ||
| 128 | const uint8_t *p = (const uint8_t *)addr; | ||
| 129 | return eeprom_read_byte(p) | (eeprom_read_byte(p + 1) << 8) | (eeprom_read_byte(p + 2) << 16) | (eeprom_read_byte(p + 3) << 24); | ||
| 130 | } | ||
| 131 | |||
| 132 | void eeprom_read_block(void *buf, const void *addr, size_t len) { | ||
| 133 | const uint8_t *p = (const uint8_t *)addr; | ||
| 134 | uint8_t * dest = (uint8_t *)buf; | ||
| 135 | while (len--) { | ||
| 136 | *dest++ = eeprom_read_byte(p++); | ||
| 137 | } | ||
| 138 | } | ||
| 139 | |||
| 140 | void eeprom_write_word(uint16_t *addr, uint16_t value) { | ||
| 141 | uint8_t *p = (uint8_t *)addr; | ||
| 142 | eeprom_write_byte(p++, value); | ||
| 143 | eeprom_write_byte(p, value >> 8); | ||
| 144 | } | ||
| 145 | |||
| 146 | void eeprom_write_dword(uint32_t *addr, uint32_t value) { | ||
| 147 | uint8_t *p = (uint8_t *)addr; | ||
| 148 | eeprom_write_byte(p++, value); | ||
| 149 | eeprom_write_byte(p++, value >> 8); | ||
| 150 | eeprom_write_byte(p++, value >> 16); | ||
| 151 | eeprom_write_byte(p, value >> 24); | ||
| 152 | } | ||
| 153 | |||
| 154 | void eeprom_write_block(const void *buf, void *addr, size_t len) { | ||
| 155 | uint8_t * p = (uint8_t *)addr; | ||
| 156 | const uint8_t *src = (const uint8_t *)buf; | ||
| 157 | while (len--) { | ||
| 158 | eeprom_write_byte(p++, *src++); | ||
| 159 | } | ||
| 160 | } | ||
| 161 | |||
| 162 | void eeprom_update_byte(uint8_t *addr, uint8_t value) { eeprom_write_byte(addr, value); } | ||
| 163 | |||
| 164 | void eeprom_update_word(uint16_t *addr, uint16_t value) { | ||
| 165 | uint8_t *p = (uint8_t *)addr; | ||
| 166 | eeprom_write_byte(p++, value); | ||
| 167 | eeprom_write_byte(p, value >> 8); | ||
| 168 | } | ||
| 169 | |||
| 170 | void eeprom_update_dword(uint32_t *addr, uint32_t value) { | ||
| 171 | uint8_t *p = (uint8_t *)addr; | ||
| 172 | eeprom_write_byte(p++, value); | ||
| 173 | eeprom_write_byte(p++, value >> 8); | ||
| 174 | eeprom_write_byte(p++, value >> 16); | ||
| 175 | eeprom_write_byte(p, value >> 24); | ||
| 176 | } | ||
| 177 | |||
| 178 | void eeprom_update_block(const void *buf, void *addr, size_t len) { | ||
| 179 | uint8_t * p = (uint8_t *)addr; | ||
| 180 | const uint8_t *src = (const uint8_t *)buf; | ||
| 181 | while (len--) { | ||
| 182 | eeprom_write_byte(p++, *src++); | ||
| 183 | } | ||
| 184 | } | ||
diff --git a/platforms/arm_atsam/flash.mk b/platforms/arm_atsam/flash.mk index f31d4b4d9..8152610ce 100644 --- a/platforms/arm_atsam/flash.mk +++ b/platforms/arm_atsam/flash.mk | |||
| @@ -3,9 +3,20 @@ | |||
| 3 | # Architecture or project specific options | 3 | # Architecture or project specific options |
| 4 | # | 4 | # |
| 5 | 5 | ||
| 6 | MDLOADER_CLI ?= mdloader | ||
| 7 | |||
| 8 | define EXEC_MDLOADER | ||
| 9 | $(MDLOADER_CLI) --first --download $(BUILD_DIR)/$(TARGET).bin --restart | ||
| 10 | endef | ||
| 11 | |||
| 12 | mdloader: bin | ||
| 13 | $(call EXEC_MDLOADER) | ||
| 14 | |||
| 6 | flash: bin | 15 | flash: bin |
| 7 | ifneq ($(strip $(PROGRAM_CMD)),) | 16 | ifneq ($(strip $(PROGRAM_CMD)),) |
| 8 | $(UNSYNC_OUTPUT_CMD) && $(PROGRAM_CMD) | 17 | $(UNSYNC_OUTPUT_CMD) && $(PROGRAM_CMD) |
| 18 | else ifeq ($(strip $(ARM_ATSAM)),SAMD51J18A) | ||
| 19 | $(UNSYNC_OUTPUT_CMD) && $(call EXEC_MDLOADER) | ||
| 9 | else | 20 | else |
| 10 | $(PRINT_OK); $(SILENT) || printf "$(MSG_FLASH_ARCH)" | 21 | $(PRINT_OK); $(SILENT) || printf "$(MSG_FLASH_ARCH)" |
| 11 | endif | 22 | endif |
diff --git a/platforms/arm_atsam/gpio.h b/platforms/arm_atsam/gpio.h new file mode 100644 index 000000000..915ed0ef4 --- /dev/null +++ b/platforms/arm_atsam/gpio.h | |||
| @@ -0,0 +1,77 @@ | |||
| 1 | /* Copyright 2021 QMK | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 3 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #pragma once | ||
| 17 | |||
| 18 | #include "stdint.h" | ||
| 19 | #include "samd51j18a.h" | ||
| 20 | |||
| 21 | #include "pin_defs.h" | ||
| 22 | |||
| 23 | typedef uint8_t pin_t; | ||
| 24 | |||
| 25 | #define SAMD_PORT(pin) ((pin & 0x20) >> 5) | ||
| 26 | #define SAMD_PIN(pin) (pin & 0x1f) | ||
| 27 | #define SAMD_PIN_MASK(pin) (1 << (pin & 0x1f)) | ||
| 28 | |||
| 29 | #define setPinInput(pin) \ | ||
| 30 | do { \ | ||
| 31 | PORT->Group[SAMD_PORT(pin)].PINCFG[SAMD_PIN(pin)].bit.INEN = 1; \ | ||
| 32 | PORT->Group[SAMD_PORT(pin)].DIRCLR.reg = SAMD_PIN_MASK(pin); \ | ||
| 33 | } while (0) | ||
| 34 | |||
| 35 | #define setPinInputHigh(pin) \ | ||
| 36 | do { \ | ||
| 37 | PORT->Group[SAMD_PORT(pin)].DIRCLR.reg = SAMD_PIN_MASK(pin); \ | ||
| 38 | PORT->Group[SAMD_PORT(pin)].OUTSET.reg = SAMD_PIN_MASK(pin); \ | ||
| 39 | PORT->Group[SAMD_PORT(pin)].PINCFG[SAMD_PIN(pin)].bit.INEN = 1; \ | ||
| 40 | PORT->Group[SAMD_PORT(pin)].PINCFG[SAMD_PIN(pin)].bit.PULLEN = 1; \ | ||
| 41 | } while (0) | ||
| 42 | |||
| 43 | #define setPinInputLow(pin) \ | ||
| 44 | do { \ | ||
| 45 | PORT->Group[SAMD_PORT(pin)].DIRCLR.reg = SAMD_PIN_MASK(pin); \ | ||
| 46 | PORT->Group[SAMD_PORT(pin)].OUTCLR.reg = SAMD_PIN_MASK(pin); \ | ||
| 47 | PORT->Group[SAMD_PORT(pin)].PINCFG[SAMD_PIN(pin)].bit.INEN = 1; \ | ||
| 48 | PORT->Group[SAMD_PORT(pin)].PINCFG[SAMD_PIN(pin)].bit.PULLEN = 1; \ | ||
| 49 | } while (0) | ||
| 50 | |||
| 51 | #define setPinOutput(pin) \ | ||
| 52 | do { \ | ||
| 53 | PORT->Group[SAMD_PORT(pin)].DIRSET.reg = SAMD_PIN_MASK(pin); \ | ||
| 54 | PORT->Group[SAMD_PORT(pin)].OUTCLR.reg = SAMD_PIN_MASK(pin); \ | ||
| 55 | } while (0) | ||
| 56 | |||
| 57 | #define writePinHigh(pin) \ | ||
| 58 | do { \ | ||
| 59 | PORT->Group[SAMD_PORT(pin)].OUTSET.reg = SAMD_PIN_MASK(pin); \ | ||
| 60 | } while (0) | ||
| 61 | |||
| 62 | #define writePinLow(pin) \ | ||
| 63 | do { \ | ||
| 64 | PORT->Group[SAMD_PORT(pin)].OUTCLR.reg = SAMD_PIN_MASK(pin); \ | ||
| 65 | } while (0) | ||
| 66 | |||
| 67 | #define writePin(pin, level) \ | ||
| 68 | do { \ | ||
| 69 | if (level) \ | ||
| 70 | PORT->Group[SAMD_PORT(pin)].OUTSET.reg = SAMD_PIN_MASK(pin); \ | ||
| 71 | else \ | ||
| 72 | PORT->Group[SAMD_PORT(pin)].OUTCLR.reg = SAMD_PIN_MASK(pin); \ | ||
| 73 | } while (0) | ||
| 74 | |||
| 75 | #define readPin(pin) ((PORT->Group[SAMD_PORT(pin)].IN.reg & SAMD_PIN_MASK(pin)) != 0) | ||
| 76 | |||
| 77 | #define togglePin(pin) (PORT->Group[SAMD_PORT(pin)].OUTTGL.reg = SAMD_PIN_MASK(pin)) | ||
diff --git a/platforms/arm_atsam/pin_defs.h b/platforms/arm_atsam/pin_defs.h new file mode 100644 index 000000000..5b50b2391 --- /dev/null +++ b/platforms/arm_atsam/pin_defs.h | |||
| @@ -0,0 +1,84 @@ | |||
| 1 | /* Copyright 2021 QMK | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 3 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #pragma once | ||
| 17 | |||
| 18 | #include "samd51j18a.h" | ||
| 19 | |||
| 20 | #define A00 PIN_PA00 | ||
| 21 | #define A01 PIN_PA01 | ||
| 22 | #define A02 PIN_PA02 | ||
| 23 | #define A03 PIN_PA03 | ||
| 24 | #define A04 PIN_PA04 | ||
| 25 | #define A05 PIN_PA05 | ||
| 26 | #define A06 PIN_PA06 | ||
| 27 | #define A07 PIN_PA07 | ||
| 28 | #define A08 PIN_PA08 | ||
| 29 | #define A09 PIN_PA09 | ||
| 30 | #define A10 PIN_PA10 | ||
| 31 | #define A11 PIN_PA11 | ||
| 32 | #define A12 PIN_PA12 | ||
| 33 | #define A13 PIN_PA13 | ||
| 34 | #define A14 PIN_PA14 | ||
| 35 | #define A15 PIN_PA15 | ||
| 36 | #define A16 PIN_PA16 | ||
| 37 | #define A17 PIN_PA17 | ||
| 38 | #define A18 PIN_PA18 | ||
| 39 | #define A19 PIN_PA19 | ||
| 40 | #define A20 PIN_PA20 | ||
| 41 | #define A21 PIN_PA21 | ||
| 42 | #define A22 PIN_PA22 | ||
| 43 | #define A23 PIN_PA23 | ||
| 44 | #define A24 PIN_PA24 | ||
| 45 | #define A25 PIN_PA25 | ||
| 46 | #define A26 PIN_PA26 | ||
| 47 | #define A27 PIN_PA27 | ||
| 48 | #define A28 PIN_PA28 | ||
| 49 | #define A29 PIN_PA29 | ||
| 50 | #define A30 PIN_PA30 | ||
| 51 | #define A31 PIN_PA31 | ||
| 52 | |||
| 53 | #define B00 PIN_PB00 | ||
| 54 | #define B01 PIN_PB01 | ||
| 55 | #define B02 PIN_PB02 | ||
| 56 | #define B03 PIN_PB03 | ||
| 57 | #define B04 PIN_PB04 | ||
| 58 | #define B05 PIN_PB05 | ||
| 59 | #define B06 PIN_PB06 | ||
| 60 | #define B07 PIN_PB07 | ||
| 61 | #define B08 PIN_PB08 | ||
| 62 | #define B09 PIN_PB09 | ||
| 63 | #define B10 PIN_PB10 | ||
| 64 | #define B11 PIN_PB11 | ||
| 65 | #define B12 PIN_PB12 | ||
| 66 | #define B13 PIN_PB13 | ||
| 67 | #define B14 PIN_PB14 | ||
| 68 | #define B15 PIN_PB15 | ||
| 69 | #define B16 PIN_PB16 | ||
| 70 | #define B17 PIN_PB17 | ||
| 71 | #define B18 PIN_PB18 | ||
| 72 | #define B19 PIN_PB19 | ||
| 73 | #define B20 PIN_PB20 | ||
| 74 | #define B21 PIN_PB21 | ||
| 75 | #define B22 PIN_PB22 | ||
| 76 | #define B23 PIN_PB23 | ||
| 77 | #define B24 PIN_PB24 | ||
| 78 | #define B25 PIN_PB25 | ||
| 79 | #define B26 PIN_PB26 | ||
| 80 | #define B27 PIN_PB27 | ||
| 81 | #define B28 PIN_PB28 | ||
| 82 | #define B29 PIN_PB29 | ||
| 83 | #define B30 PIN_PB30 | ||
| 84 | #define B31 PIN_PB31 | ||
diff --git a/platforms/arm_atsam/platform.c b/platforms/arm_atsam/platform.c new file mode 100644 index 000000000..3e35b4fe4 --- /dev/null +++ b/platforms/arm_atsam/platform.c | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | /* Copyright 2021 QMK | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 3 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include "platform_deps.h" | ||
| 18 | |||
| 19 | void platform_setup(void) { | ||
| 20 | // do nothing | ||
| 21 | } | ||
diff --git a/platforms/arm_atsam/platform.mk b/platforms/arm_atsam/platform.mk new file mode 100644 index 000000000..b49bf764d --- /dev/null +++ b/platforms/arm_atsam/platform.mk | |||
| @@ -0,0 +1,67 @@ | |||
| 1 | # Hey Emacs, this is a -*- makefile -*- | ||
| 2 | ############################################################################## | ||
| 3 | # Compiler settings | ||
| 4 | # | ||
| 5 | CC = $(CC_PREFIX) arm-none-eabi-gcc | ||
| 6 | OBJCOPY = arm-none-eabi-objcopy | ||
| 7 | OBJDUMP = arm-none-eabi-objdump | ||
| 8 | SIZE = arm-none-eabi-size | ||
| 9 | AR = arm-none-eabi-ar | ||
| 10 | NM = arm-none-eabi-nm | ||
| 11 | HEX = $(OBJCOPY) -O $(FORMAT) -R .eeprom -R .fuse -R .lock -R .signature | ||
| 12 | EEP = $(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT) | ||
| 13 | BIN = | ||
| 14 | |||
| 15 | COMMON_VPATH += $(LIB_PATH)/arm_atsam/packs/atmel/SAMD51_DFP/1.0.70/include | ||
| 16 | COMMON_VPATH += $(LIB_PATH)/arm_atsam/packs/arm/cmsis/5.0.1/CMSIS/Include | ||
| 17 | |||
| 18 | COMPILEFLAGS += -funsigned-char | ||
| 19 | COMPILEFLAGS += -funsigned-bitfields | ||
| 20 | COMPILEFLAGS += -ffunction-sections | ||
| 21 | COMPILEFLAGS += -fshort-enums | ||
| 22 | COMPILEFLAGS += -fno-inline-small-functions | ||
| 23 | COMPILEFLAGS += -fno-strict-aliasing | ||
| 24 | COMPILEFLAGS += -mfloat-abi=hard | ||
| 25 | COMPILEFLAGS += -mfpu=fpv4-sp-d16 | ||
| 26 | COMPILEFLAGS += -mthumb | ||
| 27 | |||
| 28 | #ALLOW_WARNINGS = yes | ||
| 29 | |||
| 30 | CFLAGS += $(COMPILEFLAGS) | ||
| 31 | |||
| 32 | CXXFLAGS += $(COMPILEFLAGS) | ||
| 33 | CXXFLAGS += -fno-exceptions -std=c++11 | ||
| 34 | |||
| 35 | LDFLAGS +=-Wl,--gc-sections | ||
| 36 | LDFLAGS += -Wl,-Map="%OUT%%PROJ_NAME%.map" | ||
| 37 | LDFLAGS += -Wl,--start-group | ||
| 38 | LDFLAGS += -Wl,--end-group | ||
| 39 | LDFLAGS += --specs=rdimon.specs | ||
| 40 | LDFLAGS += -T$(LIB_PATH)/arm_atsam/packs/atmel/SAMD51_DFP/1.0.70/gcc/gcc/samd51j18a_flash.ld | ||
| 41 | |||
| 42 | OPT_DEFS += -DPROTOCOL_ARM_ATSAM | ||
| 43 | |||
| 44 | MCUFLAGS = -mcpu=$(MCU) | ||
| 45 | MCUFLAGS += -D__$(ARM_ATSAM)__ | ||
| 46 | |||
| 47 | # List any extra directories to look for libraries here. | ||
| 48 | # Each directory must be seperated by a space. | ||
| 49 | # Use forward slashes for directory separators. | ||
| 50 | # For a directory that has spaces, enclose it in quotes. | ||
| 51 | EXTRALIBDIRS = | ||
| 52 | |||
| 53 | cpfirmware: warn-arm_atsam | ||
| 54 | .INTERMEDIATE: warn-arm_atsam | ||
| 55 | warn-arm_atsam: $(FIRMWARE_FORMAT) | ||
| 56 | $(info @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@) | ||
| 57 | $(info This MCU support package has a lack of support from the upstream provider (Massdrop).) | ||
| 58 | $(info There are currently questions about valid licensing, and at this stage it's likely) | ||
| 59 | $(info their boards and supporting code will be removed from QMK in the near future. Please) | ||
| 60 | $(info contact Massdrop for support, and encourage them to align their future board design) | ||
| 61 | $(info choices to gain proper license compatibility with QMK.) | ||
| 62 | $(info @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@) | ||
| 63 | |||
| 64 | # Convert hex to bin. | ||
| 65 | bin: $(BUILD_DIR)/$(TARGET).hex | ||
| 66 | $(OBJCOPY) -Iihex -Obinary $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin | ||
| 67 | $(COPY) $(BUILD_DIR)/$(TARGET).bin $(TARGET).bin; | ||
diff --git a/platforms/arm_atsam/platform_deps.h b/platforms/arm_atsam/platform_deps.h new file mode 100644 index 000000000..f296d1d53 --- /dev/null +++ b/platforms/arm_atsam/platform_deps.h | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | /* Copyright 2021 QMK | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 3 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #pragma once | ||
| 17 | |||
| 18 | // here just to please the build | ||
diff --git a/platforms/arm_atsam/suspend.c b/platforms/arm_atsam/suspend.c new file mode 100644 index 000000000..e51426128 --- /dev/null +++ b/platforms/arm_atsam/suspend.c | |||
| @@ -0,0 +1,77 @@ | |||
| 1 | #include "matrix.h" | ||
| 2 | #include "i2c_master.h" | ||
| 3 | #include "md_rgb_matrix.h" | ||
| 4 | #include "suspend.h" | ||
| 5 | |||
| 6 | /** \brief Suspend idle | ||
| 7 | * | ||
| 8 | * FIXME: needs doc | ||
| 9 | */ | ||
| 10 | void suspend_idle(uint8_t time) { /* Note: Not used anywhere currently */ | ||
| 11 | } | ||
| 12 | |||
| 13 | /** \brief Run user level Power down | ||
| 14 | * | ||
| 15 | * FIXME: needs doc | ||
| 16 | */ | ||
| 17 | __attribute__((weak)) void suspend_power_down_user(void) {} | ||
| 18 | |||
| 19 | /** \brief Run keyboard level Power down | ||
| 20 | * | ||
| 21 | * FIXME: needs doc | ||
| 22 | */ | ||
| 23 | __attribute__((weak)) void suspend_power_down_kb(void) { suspend_power_down_user(); } | ||
| 24 | |||
| 25 | /** \brief Suspend power down | ||
| 26 | * | ||
| 27 | * FIXME: needs doc | ||
| 28 | */ | ||
| 29 | void suspend_power_down(void) { | ||
| 30 | #ifdef RGB_MATRIX_ENABLE | ||
| 31 | I2C3733_Control_Set(0); // Disable LED driver | ||
| 32 | #endif | ||
| 33 | |||
| 34 | suspend_power_down_kb(); | ||
| 35 | } | ||
| 36 | |||
| 37 | __attribute__((weak)) void matrix_power_up(void) {} | ||
| 38 | __attribute__((weak)) void matrix_power_down(void) {} | ||
| 39 | bool suspend_wakeup_condition(void) { | ||
| 40 | matrix_power_up(); | ||
| 41 | matrix_scan(); | ||
| 42 | matrix_power_down(); | ||
| 43 | for (uint8_t r = 0; r < MATRIX_ROWS; r++) { | ||
| 44 | if (matrix_get_row(r)) return true; | ||
| 45 | } | ||
| 46 | return false; | ||
| 47 | } | ||
| 48 | |||
| 49 | /** \brief run user level code immediately after wakeup | ||
| 50 | * | ||
| 51 | * FIXME: needs doc | ||
| 52 | */ | ||
| 53 | __attribute__((weak)) void suspend_wakeup_init_user(void) {} | ||
| 54 | |||
| 55 | /** \brief run keyboard level code immediately after wakeup | ||
| 56 | * | ||
| 57 | * FIXME: needs doc | ||
| 58 | */ | ||
| 59 | __attribute__((weak)) void suspend_wakeup_init_kb(void) { suspend_wakeup_init_user(); } | ||
| 60 | |||
| 61 | /** \brief run immediately after wakeup | ||
| 62 | * | ||
| 63 | * FIXME: needs doc | ||
| 64 | */ | ||
| 65 | void suspend_wakeup_init(void) { | ||
| 66 | #ifdef RGB_MATRIX_ENABLE | ||
| 67 | # ifdef USE_MASSDROP_CONFIGURATOR | ||
| 68 | if (led_enabled) { | ||
| 69 | I2C3733_Control_Set(1); | ||
| 70 | } | ||
| 71 | # else | ||
| 72 | I2C3733_Control_Set(1); | ||
| 73 | # endif | ||
| 74 | #endif | ||
| 75 | |||
| 76 | suspend_wakeup_init_kb(); | ||
| 77 | } | ||
diff --git a/platforms/arm_atsam/timer.c b/platforms/arm_atsam/timer.c new file mode 100644 index 000000000..b835dd5e7 --- /dev/null +++ b/platforms/arm_atsam/timer.c | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | #include "samd51j18a.h" | ||
| 2 | #include "timer.h" | ||
| 3 | #include "tmk_core/protocol/arm_atsam/clks.h" | ||
| 4 | |||
| 5 | void set_time(uint64_t tset) { ms_clk = tset; } | ||
| 6 | |||
| 7 | void timer_init(void) { timer_clear(); } | ||
| 8 | |||
| 9 | uint16_t timer_read(void) { return (uint16_t)ms_clk; } | ||
| 10 | |||
| 11 | uint32_t timer_read32(void) { return (uint32_t)ms_clk; } | ||
| 12 | |||
| 13 | uint64_t timer_read64(void) { return ms_clk; } | ||
| 14 | |||
| 15 | uint16_t timer_elapsed(uint16_t tlast) { return TIMER_DIFF_16(timer_read(), tlast); } | ||
| 16 | |||
| 17 | uint32_t timer_elapsed32(uint32_t tlast) { return TIMER_DIFF_32(timer_read32(), tlast); } | ||
| 18 | |||
| 19 | void timer_clear(void) { set_time(0); } | ||
diff --git a/platforms/atomic_util.h b/platforms/atomic_util.h new file mode 100644 index 000000000..2c95302a1 --- /dev/null +++ b/platforms/atomic_util.h | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | /* Copyright 2021 QMK | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 3 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #pragma once | ||
| 17 | |||
| 18 | // Macro to help make GPIO and other controls atomic. | ||
| 19 | |||
| 20 | #ifndef IGNORE_ATOMIC_BLOCK | ||
| 21 | # if __has_include_next("atomic_util.h") | ||
| 22 | # include_next "atomic_util.h" /* Include the platforms atomic.h */ | ||
| 23 | # else | ||
| 24 | # define ATOMIC_BLOCK _Static_assert(0, "ATOMIC_BLOCK not implemented") | ||
| 25 | # define ATOMIC_BLOCK_RESTORESTATE _Static_assert(0, "ATOMIC_BLOCK_RESTORESTATE not implemented") | ||
| 26 | # define ATOMIC_BLOCK_FORCEON _Static_assert(0, "ATOMIC_BLOCK_FORCEON not implemented") | ||
| 27 | # endif | ||
| 28 | #else /* do nothing atomic macro */ | ||
| 29 | # define ATOMIC_BLOCK for (uint8_t __ToDo = 1; __ToDo; __ToDo = 0) | ||
| 30 | # define ATOMIC_BLOCK_RESTORESTATE ATOMIC_BLOCK | ||
| 31 | # define ATOMIC_BLOCK_FORCEON ATOMIC_BLOCK | ||
| 32 | #endif | ||
diff --git a/platforms/avr/_print.h b/platforms/avr/_print.h new file mode 100644 index 000000000..5c1fdd26d --- /dev/null +++ b/platforms/avr/_print.h | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | /* Copyright 2012 Jun Wako <wakojun@gmail.com> */ | ||
| 2 | /* Very basic print functions, intended to be used with usb_debug_only.c | ||
| 3 | * http://www.pjrc.com/teensy/ | ||
| 4 | * Copyright (c) 2008 PJRC.COM, LLC | ||
| 5 | * | ||
| 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | * of this software and associated documentation files (the "Software"), to deal | ||
| 8 | * in the Software without restriction, including without limitation the rights | ||
| 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | * copies of the Software, and to permit persons to whom the Software is | ||
| 11 | * furnished to do so, subject to the following conditions: | ||
| 12 | * | ||
| 13 | * The above copyright notice and this permission notice shall be included in | ||
| 14 | * all copies or substantial portions of the Software. | ||
| 15 | * | ||
| 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| 22 | * THE SOFTWARE. | ||
| 23 | */ | ||
| 24 | #pragma once | ||
| 25 | |||
| 26 | #include "avr/xprintf.h" | ||
| 27 | |||
| 28 | // Create user & normal print defines | ||
| 29 | #define print(s) xputs(PSTR(s)) | ||
| 30 | #define println(s) xputs(PSTR(s "\r\n")) | ||
| 31 | #define uprint(s) xputs(PSTR(s)) | ||
| 32 | #define uprintln(s) xputs(PSTR(s "\r\n")) | ||
| 33 | #define uprintf(fmt, ...) __xprintf(PSTR(fmt), ##__VA_ARGS__) \ No newline at end of file | ||
diff --git a/platforms/avr/_timer.h b/platforms/avr/_timer.h new file mode 100644 index 000000000..b81e0f68b --- /dev/null +++ b/platforms/avr/_timer.h | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | /* Copyright 2021 Simon Arlott | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 2 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #pragma once | ||
| 17 | |||
| 18 | // The platform is 8-bit, so prefer 16-bit timers to reduce code size | ||
| 19 | #define FAST_TIMER_T_SIZE 16 | ||
diff --git a/platforms/avr/_wait.h b/platforms/avr/_wait.h new file mode 100644 index 000000000..683db6ae5 --- /dev/null +++ b/platforms/avr/_wait.h | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | /* Copyright 2021 QMK | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 3 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #pragma once | ||
| 17 | |||
| 18 | #include <util/delay.h> | ||
| 19 | |||
| 20 | #define wait_ms(ms) \ | ||
| 21 | do { \ | ||
| 22 | if (__builtin_constant_p(ms)) { \ | ||
| 23 | _delay_ms(ms); \ | ||
| 24 | } else { \ | ||
| 25 | for (uint16_t i = ms; i > 0; i--) { \ | ||
| 26 | _delay_ms(1); \ | ||
| 27 | } \ | ||
| 28 | } \ | ||
| 29 | } while (0) | ||
| 30 | #define wait_us(us) \ | ||
| 31 | do { \ | ||
| 32 | if (__builtin_constant_p(us)) { \ | ||
| 33 | _delay_us(us); \ | ||
| 34 | } else { \ | ||
| 35 | for (uint16_t i = us; i > 0; i--) { \ | ||
| 36 | _delay_us(1); \ | ||
| 37 | } \ | ||
| 38 | } \ | ||
| 39 | } while (0) | ||
| 40 | #define wait_cpuclock(n) __builtin_avr_delay_cycles(n) | ||
| 41 | #define CPU_CLOCK F_CPU | ||
| 42 | |||
| 43 | /* The AVR series GPIOs have a one clock read delay for changes in the digital input signal. | ||
| 44 | * But here's more margin to make it two clocks. */ | ||
| 45 | #ifndef GPIO_INPUT_PIN_DELAY | ||
| 46 | # define GPIO_INPUT_PIN_DELAY 2 | ||
| 47 | #endif | ||
| 48 | |||
| 49 | #define waitInputPinDelay() wait_cpuclock(GPIO_INPUT_PIN_DELAY) | ||
diff --git a/platforms/avr/atomic_util.h b/platforms/avr/atomic_util.h new file mode 100644 index 000000000..7c5d2e7dc --- /dev/null +++ b/platforms/avr/atomic_util.h | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | /* Copyright 2021 QMK | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 3 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #pragma once | ||
| 17 | |||
| 18 | /* atomic macro for AVR */ | ||
| 19 | #include <util/atomic.h> | ||
| 20 | |||
| 21 | #define ATOMIC_BLOCK_RESTORESTATE ATOMIC_BLOCK(ATOMIC_RESTORESTATE) | ||
| 22 | #define ATOMIC_BLOCK_FORCEON ATOMIC_BLOCK(ATOMIC_FORCEON) | ||
diff --git a/platforms/avr/bootloader.c b/platforms/avr/bootloader.c new file mode 100644 index 000000000..c0272903b --- /dev/null +++ b/platforms/avr/bootloader.c | |||
| @@ -0,0 +1,293 @@ | |||
| 1 | #include <stdint.h> | ||
| 2 | #include <stdbool.h> | ||
| 3 | #include <avr/io.h> | ||
| 4 | #include <avr/eeprom.h> | ||
| 5 | #include <avr/interrupt.h> | ||
| 6 | #include <avr/wdt.h> | ||
| 7 | #include <util/delay.h> | ||
| 8 | #include "bootloader.h" | ||
| 9 | #include <avr/boot.h> | ||
| 10 | |||
| 11 | #ifdef PROTOCOL_LUFA | ||
| 12 | # include <LUFA/Drivers/USB/USB.h> | ||
| 13 | #endif | ||
| 14 | |||
| 15 | /** \brief Bootloader Size in *bytes* | ||
| 16 | * | ||
| 17 | * AVR Boot section size are defined by setting BOOTSZ fuse in fact. Consult with your MCU datasheet. | ||
| 18 | * Note that 'Word'(2 bytes) size and address are used in datasheet while TMK uses 'Byte'. | ||
| 19 | * | ||
| 20 | * Size of Bootloaders in bytes: | ||
| 21 | * Atmel DFU loader(ATmega32U4) 4096 | ||
| 22 | * Atmel DFU loader(AT90USB128) 8192 | ||
| 23 | * LUFA bootloader(ATmega32U4) 4096 | ||
| 24 | * Arduino Caterina(ATmega32U4) 4096 | ||
| 25 | * USBaspLoader(ATmega***) 2048 | ||
| 26 | * Teensy halfKay(ATmega32U4) 512 | ||
| 27 | * Teensy++ halfKay(AT90USB128) 1024 | ||
| 28 | * | ||
| 29 | * AVR Boot section is located at the end of Flash memory like the followings. | ||
| 30 | * | ||
| 31 | * byte Atmel/LUFA(ATMega32u4) byte Atmel(AT90SUB128) | ||
| 32 | * 0x0000 +---------------+ 0x00000 +---------------+ | ||
| 33 | * | | | | | ||
| 34 | * | | | | | ||
| 35 | * | Application | | Application | | ||
| 36 | * | | | | | ||
| 37 | * = = = = | ||
| 38 | * | | 32KB-4KB | | 128KB-8KB | ||
| 39 | * 0x7000 +---------------+ 0x1E000 +---------------+ | ||
| 40 | * | Bootloader | 4KB | Bootloader | 8KB | ||
| 41 | * 0x7FFF +---------------+ 0x1FFFF +---------------+ | ||
| 42 | * | ||
| 43 | * | ||
| 44 | * byte Teensy(ATMega32u4) byte Teensy++(AT90SUB128) | ||
| 45 | * 0x0000 +---------------+ 0x00000 +---------------+ | ||
| 46 | * | | | | | ||
| 47 | * | | | | | ||
| 48 | * | Application | | Application | | ||
| 49 | * | | | | | ||
| 50 | * = = = = | ||
| 51 | * | | 32KB-512B | | 128KB-1KB | ||
| 52 | * 0x7E00 +---------------+ 0x1FC00 +---------------+ | ||
| 53 | * | Bootloader | 512B | Bootloader | 1KB | ||
| 54 | * 0x7FFF +---------------+ 0x1FFFF +---------------+ | ||
| 55 | */ | ||
| 56 | #define FLASH_SIZE (FLASHEND + 1L) | ||
| 57 | |||
| 58 | #if !defined(BOOTLOADER_SIZE) | ||
| 59 | uint16_t bootloader_start; | ||
| 60 | #endif | ||
| 61 | |||
| 62 | // compatibility between ATMega8 and ATMega88 | ||
| 63 | #if !defined(MCUCSR) | ||
| 64 | # if defined(MCUSR) | ||
| 65 | # define MCUCSR MCUSR | ||
| 66 | # endif | ||
| 67 | #endif | ||
| 68 | |||
| 69 | /** \brief Entering the Bootloader via Software | ||
| 70 | * | ||
| 71 | * http://www.fourwalledcubicle.com/files/LUFA/Doc/120730/html/_page__software_bootloader_start.html | ||
| 72 | */ | ||
| 73 | #define BOOTLOADER_RESET_KEY 0xB007B007 | ||
| 74 | uint32_t reset_key __attribute__((section(".noinit,\"aw\",@nobits;"))); | ||
| 75 | |||
| 76 | /** \brief initialize MCU status by watchdog reset | ||
| 77 | * | ||
| 78 | * FIXME: needs doc | ||
| 79 | */ | ||
| 80 | __attribute__((weak)) void bootloader_jump(void) { | ||
| 81 | #if !defined(BOOTLOADER_SIZE) | ||
| 82 | uint8_t high_fuse = boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS); | ||
| 83 | |||
| 84 | if (high_fuse & ~(FUSE_BOOTSZ0 & FUSE_BOOTSZ1)) { | ||
| 85 | bootloader_start = (FLASH_SIZE - 512) >> 1; | ||
| 86 | } else if (high_fuse & ~(FUSE_BOOTSZ1)) { | ||
| 87 | bootloader_start = (FLASH_SIZE - 1024) >> 1; | ||
| 88 | } else if (high_fuse & ~(FUSE_BOOTSZ0)) { | ||
| 89 | bootloader_start = (FLASH_SIZE - 2048) >> 1; | ||
| 90 | } else { | ||
| 91 | bootloader_start = (FLASH_SIZE - 4096) >> 1; | ||
| 92 | } | ||
| 93 | #endif | ||
| 94 | |||
| 95 | // Something like this might work, but it compiled larger than the block above | ||
| 96 | // bootloader_start = FLASH_SIZE - (256 << (~high_fuse & 0b110 >> 1)); | ||
| 97 | |||
| 98 | #if defined(BOOTLOADER_HALFKAY) | ||
| 99 | // http://www.pjrc.com/teensy/jump_to_bootloader.html | ||
| 100 | cli(); | ||
| 101 | // disable watchdog, if enabled (it's not) | ||
| 102 | // disable all peripherals | ||
| 103 | // a shutdown call might make sense here | ||
| 104 | UDCON = 1; | ||
| 105 | USBCON = (1 << FRZCLK); // disable USB | ||
| 106 | UCSR1B = 0; | ||
| 107 | _delay_ms(5); | ||
| 108 | # if defined(__AVR_AT90USB162__) // Teensy 1.0 | ||
| 109 | EIMSK = 0; | ||
| 110 | PCICR = 0; | ||
| 111 | SPCR = 0; | ||
| 112 | ACSR = 0; | ||
| 113 | EECR = 0; | ||
| 114 | TIMSK0 = 0; | ||
| 115 | TIMSK1 = 0; | ||
| 116 | UCSR1B = 0; | ||
| 117 | DDRB = 0; | ||
| 118 | DDRC = 0; | ||
| 119 | DDRD = 0; | ||
| 120 | PORTB = 0; | ||
| 121 | PORTC = 0; | ||
| 122 | PORTD = 0; | ||
| 123 | asm volatile("jmp 0x3E00"); | ||
| 124 | # elif defined(__AVR_ATmega32U4__) // Teensy 2.0 | ||
| 125 | EIMSK = 0; | ||
| 126 | PCICR = 0; | ||
| 127 | SPCR = 0; | ||
| 128 | ACSR = 0; | ||
| 129 | EECR = 0; | ||
| 130 | ADCSRA = 0; | ||
| 131 | TIMSK0 = 0; | ||
| 132 | TIMSK1 = 0; | ||
| 133 | TIMSK3 = 0; | ||
| 134 | TIMSK4 = 0; | ||
| 135 | UCSR1B = 0; | ||
| 136 | TWCR = 0; | ||
| 137 | DDRB = 0; | ||
| 138 | DDRC = 0; | ||
| 139 | DDRD = 0; | ||
| 140 | DDRE = 0; | ||
| 141 | DDRF = 0; | ||
| 142 | TWCR = 0; | ||
| 143 | PORTB = 0; | ||
| 144 | PORTC = 0; | ||
| 145 | PORTD = 0; | ||
| 146 | PORTE = 0; | ||
| 147 | PORTF = 0; | ||
| 148 | asm volatile("jmp 0x7E00"); | ||
| 149 | # elif defined(__AVR_AT90USB646__) // Teensy++ 1.0 | ||
| 150 | EIMSK = 0; | ||
| 151 | PCICR = 0; | ||
| 152 | SPCR = 0; | ||
| 153 | ACSR = 0; | ||
| 154 | EECR = 0; | ||
| 155 | ADCSRA = 0; | ||
| 156 | TIMSK0 = 0; | ||
| 157 | TIMSK1 = 0; | ||
| 158 | TIMSK2 = 0; | ||
| 159 | TIMSK3 = 0; | ||
| 160 | UCSR1B = 0; | ||
| 161 | TWCR = 0; | ||
| 162 | DDRA = 0; | ||
| 163 | DDRB = 0; | ||
| 164 | DDRC = 0; | ||
| 165 | DDRD = 0; | ||
| 166 | DDRE = 0; | ||
| 167 | DDRF = 0; | ||
| 168 | PORTA = 0; | ||
| 169 | PORTB = 0; | ||
| 170 | PORTC = 0; | ||
| 171 | PORTD = 0; | ||
| 172 | PORTE = 0; | ||
| 173 | PORTF = 0; | ||
| 174 | asm volatile("jmp 0xFC00"); | ||
| 175 | # elif defined(__AVR_AT90USB1286__) // Teensy++ 2.0 | ||
| 176 | EIMSK = 0; | ||
| 177 | PCICR = 0; | ||
| 178 | SPCR = 0; | ||
| 179 | ACSR = 0; | ||
| 180 | EECR = 0; | ||
| 181 | ADCSRA = 0; | ||
| 182 | TIMSK0 = 0; | ||
| 183 | TIMSK1 = 0; | ||
| 184 | TIMSK2 = 0; | ||
| 185 | TIMSK3 = 0; | ||
| 186 | UCSR1B = 0; | ||
| 187 | TWCR = 0; | ||
| 188 | DDRA = 0; | ||
| 189 | DDRB = 0; | ||
| 190 | DDRC = 0; | ||
| 191 | DDRD = 0; | ||
| 192 | DDRE = 0; | ||
| 193 | DDRF = 0; | ||
| 194 | PORTA = 0; | ||
| 195 | PORTB = 0; | ||
| 196 | PORTC = 0; | ||
| 197 | PORTD = 0; | ||
| 198 | PORTE = 0; | ||
| 199 | PORTF = 0; | ||
| 200 | asm volatile("jmp 0x1FC00"); | ||
| 201 | # endif | ||
| 202 | |||
| 203 | #elif defined(BOOTLOADER_CATERINA) | ||
| 204 | // this block may be optional | ||
| 205 | // TODO: figure it out | ||
| 206 | |||
| 207 | uint16_t *const bootKeyPtr = (uint16_t *)0x0800; | ||
| 208 | |||
| 209 | // Value used by Caterina bootloader use to determine whether to run the | ||
| 210 | // sketch or the bootloader programmer. | ||
| 211 | uint16_t bootKey = 0x7777; | ||
| 212 | |||
| 213 | *bootKeyPtr = bootKey; | ||
| 214 | |||
| 215 | // setup watchdog timeout | ||
| 216 | wdt_enable(WDTO_60MS); | ||
| 217 | |||
| 218 | while (1) { | ||
| 219 | } // wait for watchdog timer to trigger | ||
| 220 | |||
| 221 | #elif defined(BOOTLOADER_USBASP) | ||
| 222 | // Taken with permission of Stephan Baerwolf from https://github.com/tinyusbboard/API/blob/master/apipage.c | ||
| 223 | wdt_enable(WDTO_15MS); | ||
| 224 | wdt_reset(); | ||
| 225 | asm volatile("cli \n\t" | ||
| 226 | "ldi r29 , %[ramendhi] \n\t" | ||
| 227 | "ldi r28 , %[ramendlo] \n\t" | ||
| 228 | # if (FLASHEND > 131071) | ||
| 229 | "ldi r18 , %[bootaddrhi] \n\t" | ||
| 230 | "st Y+, r18 \n\t" | ||
| 231 | # endif | ||
| 232 | "ldi r18 , %[bootaddrme] \n\t" | ||
| 233 | "st Y+, r18 \n\t" | ||
| 234 | "ldi r18 , %[bootaddrlo] \n\t" | ||
| 235 | "st Y+, r18 \n\t" | ||
| 236 | "out %[mcucsrio], __zero_reg__ \n\t" | ||
| 237 | "bootloader_startup_loop%=: \n\t" | ||
| 238 | "rjmp bootloader_startup_loop%= \n\t" | ||
| 239 | : | ||
| 240 | : [mcucsrio] "I"(_SFR_IO_ADDR(MCUCSR)), | ||
| 241 | # if (FLASHEND > 131071) | ||
| 242 | [ramendhi] "M"(((RAMEND - 2) >> 8) & 0xff), [ramendlo] "M"(((RAMEND - 2) >> 0) & 0xff), [bootaddrhi] "M"((((FLASH_SIZE - BOOTLOADER_SIZE) >> 1) >> 16) & 0xff), | ||
| 243 | # else | ||
| 244 | [ramendhi] "M"(((RAMEND - 1) >> 8) & 0xff), [ramendlo] "M"(((RAMEND - 1) >> 0) & 0xff), | ||
| 245 | # endif | ||
| 246 | [bootaddrme] "M"((((FLASH_SIZE - BOOTLOADER_SIZE) >> 1) >> 8) & 0xff), [bootaddrlo] "M"((((FLASH_SIZE - BOOTLOADER_SIZE) >> 1) >> 0) & 0xff)); | ||
| 247 | |||
| 248 | #else // Assume remaining boards are DFU, even if the flag isn't set | ||
| 249 | |||
| 250 | # if !(defined(__AVR_ATmega32A__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__) || defined(__AVR_ATtiny85__)) // no USB - maybe BOOTLOADER_BOOTLOADHID instead though? | ||
| 251 | UDCON = 1; | ||
| 252 | USBCON = (1 << FRZCLK); // disable USB | ||
| 253 | UCSR1B = 0; | ||
| 254 | _delay_ms(5); // 5 seems to work fine | ||
| 255 | # endif | ||
| 256 | |||
| 257 | # ifdef BOOTLOADER_BOOTLOADHID | ||
| 258 | // force bootloadHID to stay in bootloader mode, so that it waits | ||
| 259 | // for a new firmware to be flashed | ||
| 260 | eeprom_write_byte((uint8_t *)1, 0x00); | ||
| 261 | # endif | ||
| 262 | |||
| 263 | // watchdog reset | ||
| 264 | reset_key = BOOTLOADER_RESET_KEY; | ||
| 265 | wdt_enable(WDTO_250MS); | ||
| 266 | for (;;) | ||
| 267 | ; | ||
| 268 | #endif | ||
| 269 | } | ||
| 270 | |||
| 271 | /* this runs before main() */ | ||
| 272 | void bootloader_jump_after_watchdog_reset(void) __attribute__((used, naked, section(".init3"))); | ||
| 273 | void bootloader_jump_after_watchdog_reset(void) { | ||
| 274 | #ifndef BOOTLOADER_HALFKAY | ||
| 275 | if ((MCUCSR & (1 << WDRF)) && reset_key == BOOTLOADER_RESET_KEY) { | ||
| 276 | reset_key = 0; | ||
| 277 | |||
| 278 | // My custom USBasploader requires this to come up. | ||
| 279 | MCUCSR = 0; | ||
| 280 | |||
| 281 | // Seems like Teensy halfkay loader requires clearing WDRF and disabling watchdog. | ||
| 282 | MCUCSR &= ~(1 << WDRF); | ||
| 283 | wdt_disable(); | ||
| 284 | |||
| 285 | // This is compled into 'icall', address should be in word unit, not byte. | ||
| 286 | # ifdef BOOTLOADER_SIZE | ||
| 287 | ((void (*)(void))((FLASH_SIZE - BOOTLOADER_SIZE) >> 1))(); | ||
| 288 | # else | ||
| 289 | asm("ijmp" ::"z"(bootloader_start)); | ||
| 290 | # endif | ||
| 291 | } | ||
| 292 | #endif | ||
| 293 | } | ||
diff --git a/platforms/avr/bootloader_size.c b/platforms/avr/bootloader_size.c new file mode 100644 index 000000000..a029f9321 --- /dev/null +++ b/platforms/avr/bootloader_size.c | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | // Copyright 2017 Jack Humbert | ||
| 2 | // | ||
| 3 | // This program is free software: you can redistribute it and/or modify | ||
| 4 | // it under the terms of the GNU General Public License as published by | ||
| 5 | // the Free Software Foundation, either version 2 of the License, or | ||
| 6 | // (at your option) any later version. | ||
| 7 | // | ||
| 8 | // This program is distributed in the hope that it will be useful, | ||
| 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | // GNU General Public License for more details. | ||
| 12 | // | ||
| 13 | // You should have received a copy of the GNU General Public License | ||
| 14 | // along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | |||
| 16 | #include <avr/io.h> | ||
| 17 | #include <avr/boot.h> | ||
| 18 | |||
| 19 | // clang-format off | ||
| 20 | // this is not valid C - it's for computing the size available on the chip | ||
| 21 | AVR_SIZE: FLASHEND + 1 - BOOTLOADER_SIZE | ||
diff --git a/platforms/avr/drivers/analog.c b/platforms/avr/drivers/analog.c index 8d299ffdb..628835cce 100644 --- a/platforms/avr/drivers/analog.c +++ b/platforms/avr/drivers/analog.c | |||
| @@ -23,29 +23,6 @@ static uint8_t aref = ADC_REF_POWER; | |||
| 23 | 23 | ||
| 24 | void analogReference(uint8_t mode) { aref = mode & (_BV(REFS1) | _BV(REFS0)); } | 24 | void analogReference(uint8_t mode) { aref = mode & (_BV(REFS1) | _BV(REFS0)); } |
| 25 | 25 | ||
| 26 | // Arduino compatible pin input | ||
| 27 | int16_t analogRead(uint8_t pin) { | ||
| 28 | #if defined(__AVR_ATmega32U4__) | ||
| 29 | // clang-format off | ||
| 30 | static const uint8_t PROGMEM pin_to_mux[] = { | ||
| 31 | //A0 A1 A2 A3 A4 A5 | ||
| 32 | //F7 F6 F5 F4 F1 F0 | ||
| 33 | 0x07, 0x06, 0x05, 0x04, 0x01, 0x00, | ||
| 34 | //A6 A7 A8 A9 A10 A11 | ||
| 35 | //D4 D7 B4 B5 B6 D6 | ||
| 36 | 0x20, 0x22, 0x23, 0x24, 0x25, 0x21 | ||
| 37 | }; | ||
| 38 | // clang-format on | ||
| 39 | if (pin >= 12) return 0; | ||
| 40 | return adc_read(pgm_read_byte(pin_to_mux + pin)); | ||
| 41 | #elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__) | ||
| 42 | if (pin >= 8) return 0; | ||
| 43 | return adc_read(pin); | ||
| 44 | #else | ||
| 45 | return 0; | ||
| 46 | #endif | ||
| 47 | } | ||
| 48 | |||
| 49 | int16_t analogReadPin(pin_t pin) { return adc_read(pinToMux(pin)); } | 26 | int16_t analogReadPin(pin_t pin) { return adc_read(pinToMux(pin)); } |
| 50 | 27 | ||
| 51 | uint8_t pinToMux(pin_t pin) { | 28 | uint8_t pinToMux(pin_t pin) { |
diff --git a/platforms/avr/drivers/analog.h b/platforms/avr/drivers/analog.h index 058882450..fa2fb0d89 100644 --- a/platforms/avr/drivers/analog.h +++ b/platforms/avr/drivers/analog.h | |||
| @@ -22,8 +22,7 @@ | |||
| 22 | #ifdef __cplusplus | 22 | #ifdef __cplusplus |
| 23 | extern "C" { | 23 | extern "C" { |
| 24 | #endif | 24 | #endif |
| 25 | void analogReference(uint8_t mode); | 25 | void analogReference(uint8_t mode); |
| 26 | int16_t analogRead(uint8_t pin); | ||
| 27 | 26 | ||
| 28 | int16_t analogReadPin(pin_t pin); | 27 | int16_t analogReadPin(pin_t pin); |
| 29 | uint8_t pinToMux(pin_t pin); | 28 | uint8_t pinToMux(pin_t pin); |
diff --git a/platforms/avr/drivers/audio_pwm.h b/platforms/avr/drivers/audio_pwm.h new file mode 100644 index 000000000..d6eb3571d --- /dev/null +++ b/platforms/avr/drivers/audio_pwm.h | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | /* Copyright 2020 Jack Humbert | ||
| 2 | * Copyright 2020 JohSchneider | ||
| 3 | * | ||
| 4 | * This program is free software: you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License as published by | ||
| 6 | * the Free Software Foundation, either version 2 of the License, or | ||
| 7 | * (at your option) any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | ||
| 17 | #pragma once | ||
diff --git a/platforms/avr/drivers/audio_pwm_hardware.c b/platforms/avr/drivers/audio_pwm_hardware.c new file mode 100644 index 000000000..df03a4558 --- /dev/null +++ b/platforms/avr/drivers/audio_pwm_hardware.c | |||
| @@ -0,0 +1,332 @@ | |||
| 1 | /* Copyright 2016 Jack Humbert | ||
| 2 | * Copyright 2020 JohSchneider | ||
| 3 | * | ||
| 4 | * This program is free software: you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License as published by | ||
| 6 | * the Free Software Foundation, either version 2 of the License, or | ||
| 7 | * (at your option) any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #if defined(__AVR__) | ||
| 19 | # include <avr/pgmspace.h> | ||
| 20 | # include <avr/interrupt.h> | ||
| 21 | # include <avr/io.h> | ||
| 22 | #endif | ||
| 23 | |||
| 24 | #include "audio.h" | ||
| 25 | |||
| 26 | extern bool playing_note; | ||
| 27 | extern bool playing_melody; | ||
| 28 | extern uint8_t note_timbre; | ||
| 29 | |||
| 30 | #define CPU_PRESCALER 8 | ||
| 31 | |||
| 32 | /* | ||
| 33 | Audio Driver: PWM | ||
| 34 | |||
| 35 | drive up to two speakers through the AVR PWM hardware-peripheral, using timer1 and/or timer3 on Atmega32U4. | ||
| 36 | |||
| 37 | the primary channel_1 can be connected to either pin PC4 PC5 or PC6 (the later being used by most AVR based keyboards) with a PMW signal generated by timer3 | ||
| 38 | and an optional secondary channel_2 on either pin PB5, PB6 or PB7, with a PWM signal from timer1 | ||
| 39 | |||
| 40 | alternatively, the PWM pins on PORTB can be used as only/primary speaker | ||
| 41 | */ | ||
| 42 | |||
| 43 | #if defined(AUDIO_PIN) && (AUDIO_PIN != C4) && (AUDIO_PIN != C5) && (AUDIO_PIN != C6) && (AUDIO_PIN != B5) && (AUDIO_PIN != B6) && (AUDIO_PIN != B7) && (AUDIO_PIN != D5) | ||
| 44 | # error "Audio feature enabled, but no suitable pin selected as AUDIO_PIN - see docs/feature_audio under the AVR settings for available options." | ||
| 45 | #endif | ||
| 46 | |||
| 47 | #if (AUDIO_PIN == C4) || (AUDIO_PIN == C5) || (AUDIO_PIN == C6) | ||
| 48 | # define AUDIO1_PIN_SET | ||
| 49 | # define AUDIO1_TIMSKx TIMSK3 | ||
| 50 | # define AUDIO1_TCCRxA TCCR3A | ||
| 51 | # define AUDIO1_TCCRxB TCCR3B | ||
| 52 | # define AUDIO1_ICRx ICR3 | ||
| 53 | # define AUDIO1_WGMx0 WGM30 | ||
| 54 | # define AUDIO1_WGMx1 WGM31 | ||
| 55 | # define AUDIO1_WGMx2 WGM32 | ||
| 56 | # define AUDIO1_WGMx3 WGM33 | ||
| 57 | # define AUDIO1_CSx0 CS30 | ||
| 58 | # define AUDIO1_CSx1 CS31 | ||
| 59 | # define AUDIO1_CSx2 CS32 | ||
| 60 | |||
| 61 | # if (AUDIO_PIN == C6) | ||
| 62 | # define AUDIO1_COMxy0 COM3A0 | ||
| 63 | # define AUDIO1_COMxy1 COM3A1 | ||
| 64 | # define AUDIO1_OCIExy OCIE3A | ||
| 65 | # define AUDIO1_OCRxy OCR3A | ||
| 66 | # define AUDIO1_PIN C6 | ||
| 67 | # define AUDIO1_TIMERx_COMPy_vect TIMER3_COMPA_vect | ||
| 68 | # elif (AUDIO_PIN == C5) | ||
| 69 | # define AUDIO1_COMxy0 COM3B0 | ||
| 70 | # define AUDIO1_COMxy1 COM3B1 | ||
| 71 | # define AUDIO1_OCIExy OCIE3B | ||
| 72 | # define AUDIO1_OCRxy OCR3B | ||
| 73 | # define AUDIO1_PIN C5 | ||
| 74 | # define AUDIO1_TIMERx_COMPy_vect TIMER3_COMPB_vect | ||
| 75 | # elif (AUDIO_PIN == C4) | ||
| 76 | # define AUDIO1_COMxy0 COM3C0 | ||
| 77 | # define AUDIO1_COMxy1 COM3C1 | ||
| 78 | # define AUDIO1_OCIExy OCIE3C | ||
| 79 | # define AUDIO1_OCRxy OCR3C | ||
| 80 | # define AUDIO1_PIN C4 | ||
| 81 | # define AUDIO1_TIMERx_COMPy_vect TIMER3_COMPC_vect | ||
| 82 | # endif | ||
| 83 | #endif | ||
| 84 | |||
| 85 | #if defined(AUDIO_PIN) && defined(AUDIO_PIN_ALT) && (AUDIO_PIN == AUDIO_PIN_ALT) | ||
| 86 | # error "Audio feature: AUDIO_PIN and AUDIO_PIN_ALT on the same pin makes no sense." | ||
| 87 | #endif | ||
| 88 | |||
| 89 | #if ((AUDIO_PIN == B5) && ((AUDIO_PIN_ALT == B6) || (AUDIO_PIN_ALT == B7))) || ((AUDIO_PIN == B6) && ((AUDIO_PIN_ALT == B5) || (AUDIO_PIN_ALT == B7))) || ((AUDIO_PIN == B7) && ((AUDIO_PIN_ALT == B5) || (AUDIO_PIN_ALT == B6))) | ||
| 90 | # error "Audio feature: PORTB as AUDIO_PIN and AUDIO_PIN_ALT at the same time is not supported." | ||
| 91 | #endif | ||
| 92 | |||
| 93 | #if defined(AUDIO_PIN_ALT) && (AUDIO_PIN_ALT != B5) && (AUDIO_PIN_ALT != B6) && (AUDIO_PIN_ALT != B7) | ||
| 94 | # error "Audio feature: the pin selected as AUDIO_PIN_ALT is not supported." | ||
| 95 | #endif | ||
| 96 | |||
| 97 | #if (AUDIO_PIN == B5) || (AUDIO_PIN == B6) || (AUDIO_PIN == B7) || (AUDIO_PIN_ALT == B5) || (AUDIO_PIN_ALT == B6) || (AUDIO_PIN_ALT == B7) || (AUDIO_PIN == D5) | ||
| 98 | # define AUDIO2_PIN_SET | ||
| 99 | # define AUDIO2_TIMSKx TIMSK1 | ||
| 100 | # define AUDIO2_TCCRxA TCCR1A | ||
| 101 | # define AUDIO2_TCCRxB TCCR1B | ||
| 102 | # define AUDIO2_ICRx ICR1 | ||
| 103 | # define AUDIO2_WGMx0 WGM10 | ||
| 104 | # define AUDIO2_WGMx1 WGM11 | ||
| 105 | # define AUDIO2_WGMx2 WGM12 | ||
| 106 | # define AUDIO2_WGMx3 WGM13 | ||
| 107 | # define AUDIO2_CSx0 CS10 | ||
| 108 | # define AUDIO2_CSx1 CS11 | ||
| 109 | # define AUDIO2_CSx2 CS12 | ||
| 110 | |||
| 111 | # if (AUDIO_PIN == B5) || (AUDIO_PIN_ALT == B5) | ||
| 112 | # define AUDIO2_COMxy0 COM1A0 | ||
| 113 | # define AUDIO2_COMxy1 COM1A1 | ||
| 114 | # define AUDIO2_OCIExy OCIE1A | ||
| 115 | # define AUDIO2_OCRxy OCR1A | ||
| 116 | # define AUDIO2_PIN B5 | ||
| 117 | # define AUDIO2_TIMERx_COMPy_vect TIMER1_COMPA_vect | ||
| 118 | # elif (AUDIO_PIN == B6) || (AUDIO_PIN_ALT == B6) | ||
| 119 | # define AUDIO2_COMxy0 COM1B0 | ||
| 120 | # define AUDIO2_COMxy1 COM1B1 | ||
| 121 | # define AUDIO2_OCIExy OCIE1B | ||
| 122 | # define AUDIO2_OCRxy OCR1B | ||
| 123 | # define AUDIO2_PIN B6 | ||
| 124 | # define AUDIO2_TIMERx_COMPy_vect TIMER1_COMPB_vect | ||
| 125 | # elif (AUDIO_PIN == B7) || (AUDIO_PIN_ALT == B7) | ||
| 126 | # define AUDIO2_COMxy0 COM1C0 | ||
| 127 | # define AUDIO2_COMxy1 COM1C1 | ||
| 128 | # define AUDIO2_OCIExy OCIE1C | ||
| 129 | # define AUDIO2_OCRxy OCR1C | ||
| 130 | # define AUDIO2_PIN B7 | ||
| 131 | # define AUDIO2_TIMERx_COMPy_vect TIMER1_COMPC_vect | ||
| 132 | # elif (AUDIO_PIN == D5) && defined(__AVR_ATmega32A__) | ||
| 133 | # pragma message "Audio support for ATmega32A is experimental and can cause crashes." | ||
| 134 | # undef AUDIO2_TIMSKx | ||
| 135 | # define AUDIO2_TIMSKx TIMSK | ||
| 136 | # define AUDIO2_COMxy0 COM1A0 | ||
| 137 | # define AUDIO2_COMxy1 COM1A1 | ||
| 138 | # define AUDIO2_OCIExy OCIE1A | ||
| 139 | # define AUDIO2_OCRxy OCR1A | ||
| 140 | # define AUDIO2_PIN D5 | ||
| 141 | # define AUDIO2_TIMERx_COMPy_vect TIMER1_COMPA_vect | ||
| 142 | # endif | ||
| 143 | #endif | ||
| 144 | |||
| 145 | // C6 seems to be the assumed default by many existing keyboard - but sill warn the user | ||
| 146 | #if !defined(AUDIO1_PIN_SET) && !defined(AUDIO2_PIN_SET) | ||
| 147 | # pragma message "Audio feature enabled, but no suitable pin selected - see docs/feature_audio under the AVR settings for available options. Don't expect to hear anything... :-)" | ||
| 148 | // TODO: make this an error - go through the breaking-change-process and change all keyboards to the new define | ||
| 149 | #endif | ||
| 150 | // ----------------------------------------------------------------------------- | ||
| 151 | |||
| 152 | #ifdef AUDIO1_PIN_SET | ||
| 153 | static float channel_1_frequency = 0.0f; | ||
| 154 | void channel_1_set_frequency(float freq) { | ||
| 155 | if (freq == 0.0f) // a pause/rest is a valid "note" with freq=0 | ||
| 156 | { | ||
| 157 | // disable the output, but keep the pwm-ISR going (with the previous | ||
| 158 | // frequency) so the audio-state keeps getting updated | ||
| 159 | // Note: setting the duty-cycle 0 is not possible on non-inverting PWM mode - see the AVR data-sheet | ||
| 160 | AUDIO1_TCCRxA &= ~(_BV(AUDIO1_COMxy1) | _BV(AUDIO1_COMxy0)); | ||
| 161 | return; | ||
| 162 | } else { | ||
| 163 | AUDIO1_TCCRxA |= _BV(AUDIO1_COMxy1); // enable output, PWM mode | ||
| 164 | } | ||
| 165 | |||
| 166 | channel_1_frequency = freq; | ||
| 167 | |||
| 168 | // set pwm period | ||
| 169 | AUDIO1_ICRx = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER)); | ||
| 170 | // and duty cycle | ||
| 171 | AUDIO1_OCRxy = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre / 100); | ||
| 172 | } | ||
| 173 | |||
| 174 | void channel_1_start(void) { | ||
| 175 | // enable timer-counter ISR | ||
| 176 | AUDIO1_TIMSKx |= _BV(AUDIO1_OCIExy); | ||
| 177 | // enable timer-counter output | ||
| 178 | AUDIO1_TCCRxA |= _BV(AUDIO1_COMxy1); | ||
| 179 | } | ||
| 180 | |||
| 181 | void channel_1_stop(void) { | ||
| 182 | // disable timer-counter ISR | ||
| 183 | AUDIO1_TIMSKx &= ~_BV(AUDIO1_OCIExy); | ||
| 184 | // disable timer-counter output | ||
| 185 | AUDIO1_TCCRxA &= ~(_BV(AUDIO1_COMxy1) | _BV(AUDIO1_COMxy0)); | ||
| 186 | } | ||
| 187 | #endif | ||
| 188 | |||
| 189 | #ifdef AUDIO2_PIN_SET | ||
| 190 | static float channel_2_frequency = 0.0f; | ||
| 191 | void channel_2_set_frequency(float freq) { | ||
| 192 | if (freq == 0.0f) { | ||
| 193 | AUDIO2_TCCRxA &= ~(_BV(AUDIO2_COMxy1) | _BV(AUDIO2_COMxy0)); | ||
| 194 | return; | ||
| 195 | } else { | ||
| 196 | AUDIO2_TCCRxA |= _BV(AUDIO2_COMxy1); | ||
| 197 | } | ||
| 198 | |||
| 199 | channel_2_frequency = freq; | ||
| 200 | |||
| 201 | AUDIO2_ICRx = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER)); | ||
| 202 | AUDIO2_OCRxy = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre / 100); | ||
| 203 | } | ||
| 204 | |||
| 205 | float channel_2_get_frequency(void) { return channel_2_frequency; } | ||
| 206 | |||
| 207 | void channel_2_start(void) { | ||
| 208 | AUDIO2_TIMSKx |= _BV(AUDIO2_OCIExy); | ||
| 209 | AUDIO2_TCCRxA |= _BV(AUDIO2_COMxy1); | ||
| 210 | } | ||
| 211 | |||
| 212 | void channel_2_stop(void) { | ||
| 213 | AUDIO2_TIMSKx &= ~_BV(AUDIO2_OCIExy); | ||
| 214 | AUDIO2_TCCRxA &= ~(_BV(AUDIO2_COMxy1) | _BV(AUDIO2_COMxy0)); | ||
| 215 | } | ||
| 216 | #endif | ||
| 217 | |||
| 218 | void audio_driver_initialize() { | ||
| 219 | #ifdef AUDIO1_PIN_SET | ||
| 220 | channel_1_stop(); | ||
| 221 | setPinOutput(AUDIO1_PIN); | ||
| 222 | #endif | ||
| 223 | |||
| 224 | #ifdef AUDIO2_PIN_SET | ||
| 225 | channel_2_stop(); | ||
| 226 | setPinOutput(AUDIO2_PIN); | ||
| 227 | #endif | ||
| 228 | |||
| 229 | // TCCR3A / TCCR3B: Timer/Counter #3 Control Registers TCCR3A/TCCR3B, TCCR1A/TCCR1B | ||
| 230 | // Compare Output Mode (COM3An and COM1An) = 0b00 = Normal port operation | ||
| 231 | // OC3A -- PC6 | ||
| 232 | // OC3B -- PC5 | ||
| 233 | // OC3C -- PC4 | ||
| 234 | // OC1A -- PB5 | ||
| 235 | // OC1B -- PB6 | ||
| 236 | // OC1C -- PB7 | ||
| 237 | |||
| 238 | // Waveform Generation Mode (WGM3n) = 0b1110 = Fast PWM Mode 14. Period = ICR3, Duty Cycle OCR3A) | ||
| 239 | // OCR3A - PC6 | ||
| 240 | // OCR3B - PC5 | ||
| 241 | // OCR3C - PC4 | ||
| 242 | // OCR1A - PB5 | ||
| 243 | // OCR1B - PB6 | ||
| 244 | // OCR1C - PB7 | ||
| 245 | |||
| 246 | // Clock Select (CS3n) = 0b010 = Clock / 8 | ||
| 247 | #ifdef AUDIO1_PIN_SET | ||
| 248 | // initialize timer-counter | ||
| 249 | AUDIO1_TCCRxA = (0 << AUDIO1_COMxy1) | (0 << AUDIO1_COMxy0) | (1 << AUDIO1_WGMx1) | (0 << AUDIO1_WGMx0); | ||
| 250 | AUDIO1_TCCRxB = (1 << AUDIO1_WGMx3) | (1 << AUDIO1_WGMx2) | (0 << AUDIO1_CSx2) | (1 << AUDIO1_CSx1) | (0 << AUDIO1_CSx0); | ||
| 251 | #endif | ||
| 252 | |||
| 253 | #ifdef AUDIO2_PIN_SET | ||
| 254 | AUDIO2_TCCRxA = (0 << AUDIO2_COMxy1) | (0 << AUDIO2_COMxy0) | (1 << AUDIO2_WGMx1) | (0 << AUDIO2_WGMx0); | ||
| 255 | AUDIO2_TCCRxB = (1 << AUDIO2_WGMx3) | (1 << AUDIO2_WGMx2) | (0 << AUDIO2_CSx2) | (1 << AUDIO2_CSx1) | (0 << AUDIO2_CSx0); | ||
| 256 | #endif | ||
| 257 | } | ||
| 258 | |||
| 259 | void audio_driver_stop() { | ||
| 260 | #ifdef AUDIO1_PIN_SET | ||
| 261 | channel_1_stop(); | ||
| 262 | #endif | ||
| 263 | |||
| 264 | #ifdef AUDIO2_PIN_SET | ||
| 265 | channel_2_stop(); | ||
| 266 | #endif | ||
| 267 | } | ||
| 268 | |||
| 269 | void audio_driver_start(void) { | ||
| 270 | #ifdef AUDIO1_PIN_SET | ||
| 271 | channel_1_start(); | ||
| 272 | if (playing_note) { | ||
| 273 | channel_1_set_frequency(audio_get_processed_frequency(0)); | ||
| 274 | } | ||
| 275 | #endif | ||
| 276 | |||
| 277 | #if !defined(AUDIO1_PIN_SET) && defined(AUDIO2_PIN_SET) | ||
| 278 | channel_2_start(); | ||
| 279 | if (playing_note) { | ||
| 280 | channel_2_set_frequency(audio_get_processed_frequency(0)); | ||
| 281 | } | ||
| 282 | #endif | ||
| 283 | } | ||
| 284 | |||
| 285 | static volatile uint32_t isr_counter = 0; | ||
| 286 | #ifdef AUDIO1_PIN_SET | ||
| 287 | ISR(AUDIO1_TIMERx_COMPy_vect) { | ||
| 288 | isr_counter++; | ||
| 289 | if (isr_counter < channel_1_frequency / (CPU_PRESCALER * 8)) return; | ||
| 290 | |||
| 291 | isr_counter = 0; | ||
| 292 | bool state_changed = audio_update_state(); | ||
| 293 | |||
| 294 | if (!playing_note && !playing_melody) { | ||
| 295 | channel_1_stop(); | ||
| 296 | # ifdef AUDIO2_PIN_SET | ||
| 297 | channel_2_stop(); | ||
| 298 | # endif | ||
| 299 | return; | ||
| 300 | } | ||
| 301 | |||
| 302 | if (state_changed) { | ||
| 303 | channel_1_set_frequency(audio_get_processed_frequency(0)); | ||
| 304 | # ifdef AUDIO2_PIN_SET | ||
| 305 | if (audio_get_number_of_active_tones() > 1) { | ||
| 306 | channel_2_set_frequency(audio_get_processed_frequency(1)); | ||
| 307 | } else { | ||
| 308 | channel_2_stop(); | ||
| 309 | } | ||
| 310 | # endif | ||
| 311 | } | ||
| 312 | } | ||
| 313 | #endif | ||
| 314 | |||
| 315 | #if !defined(AUDIO1_PIN_SET) && defined(AUDIO2_PIN_SET) | ||
| 316 | ISR(AUDIO2_TIMERx_COMPy_vect) { | ||
| 317 | isr_counter++; | ||
| 318 | if (isr_counter < channel_2_frequency / (CPU_PRESCALER * 8)) return; | ||
| 319 | |||
| 320 | isr_counter = 0; | ||
| 321 | bool state_changed = audio_update_state(); | ||
| 322 | |||
| 323 | if (!playing_note && !playing_melody) { | ||
| 324 | channel_2_stop(); | ||
| 325 | return; | ||
| 326 | } | ||
| 327 | |||
| 328 | if (state_changed) { | ||
| 329 | channel_2_set_frequency(audio_get_processed_frequency(0)); | ||
| 330 | } | ||
| 331 | } | ||
| 332 | #endif | ||
diff --git a/platforms/avr/drivers/i2c_master.c b/platforms/avr/drivers/i2c_master.c index 2773e0077..111b55d6b 100644 --- a/platforms/avr/drivers/i2c_master.c +++ b/platforms/avr/drivers/i2c_master.c | |||
| @@ -202,6 +202,25 @@ i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, | |||
| 202 | return status; | 202 | return status; |
| 203 | } | 203 | } |
| 204 | 204 | ||
| 205 | i2c_status_t i2c_writeReg16(uint8_t devaddr, uint16_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout) { | ||
| 206 | i2c_status_t status = i2c_start(devaddr | 0x00, timeout); | ||
| 207 | if (status >= 0) { | ||
| 208 | status = i2c_write(regaddr >> 8, timeout); | ||
| 209 | |||
| 210 | if (status >= 0) { | ||
| 211 | status = i2c_write(regaddr & 0xFF, timeout); | ||
| 212 | |||
| 213 | for (uint16_t i = 0; i < length && status >= 0; i++) { | ||
| 214 | status = i2c_write(data[i], timeout); | ||
| 215 | } | ||
| 216 | } | ||
| 217 | } | ||
| 218 | |||
| 219 | i2c_stop(); | ||
| 220 | |||
| 221 | return status; | ||
| 222 | } | ||
| 223 | |||
| 205 | i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) { | 224 | i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) { |
| 206 | i2c_status_t status = i2c_start(devaddr, timeout); | 225 | i2c_status_t status = i2c_start(devaddr, timeout); |
| 207 | if (status < 0) { | 226 | if (status < 0) { |
| @@ -235,6 +254,43 @@ error: | |||
| 235 | return (status < 0) ? status : I2C_STATUS_SUCCESS; | 254 | return (status < 0) ? status : I2C_STATUS_SUCCESS; |
| 236 | } | 255 | } |
| 237 | 256 | ||
| 257 | i2c_status_t i2c_readReg16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) { | ||
| 258 | i2c_status_t status = i2c_start(devaddr, timeout); | ||
| 259 | if (status < 0) { | ||
| 260 | goto error; | ||
| 261 | } | ||
| 262 | |||
| 263 | status = i2c_write(regaddr >> 8, timeout); | ||
| 264 | if (status < 0) { | ||
| 265 | goto error; | ||
| 266 | } | ||
| 267 | status = i2c_write(regaddr & 0xFF, timeout); | ||
| 268 | if (status < 0) { | ||
| 269 | goto error; | ||
| 270 | } | ||
| 271 | |||
| 272 | status = i2c_start(devaddr | 0x01, timeout); | ||
| 273 | |||
| 274 | for (uint16_t i = 0; i < (length - 1) && status >= 0; i++) { | ||
| 275 | status = i2c_read_ack(timeout); | ||
| 276 | if (status >= 0) { | ||
| 277 | data[i] = status; | ||
| 278 | } | ||
| 279 | } | ||
| 280 | |||
| 281 | if (status >= 0) { | ||
| 282 | status = i2c_read_nack(timeout); | ||
| 283 | if (status >= 0) { | ||
| 284 | data[(length - 1)] = status; | ||
| 285 | } | ||
| 286 | } | ||
| 287 | |||
| 288 | error: | ||
| 289 | i2c_stop(); | ||
| 290 | |||
| 291 | return (status < 0) ? status : I2C_STATUS_SUCCESS; | ||
| 292 | } | ||
| 293 | |||
| 238 | void i2c_stop(void) { | 294 | void i2c_stop(void) { |
| 239 | // transmit STOP condition | 295 | // transmit STOP condition |
| 240 | TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO); | 296 | TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO); |
diff --git a/platforms/avr/drivers/i2c_master.h b/platforms/avr/drivers/i2c_master.h index e5af73364..2d95846db 100644 --- a/platforms/avr/drivers/i2c_master.h +++ b/platforms/avr/drivers/i2c_master.h | |||
| @@ -39,5 +39,7 @@ int16_t i2c_read_nack(uint16_t timeout); | |||
| 39 | i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout); | 39 | i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout); |
| 40 | i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout); | 40 | i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout); |
| 41 | i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout); | 41 | i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout); |
| 42 | i2c_status_t i2c_writeReg16(uint8_t devaddr, uint16_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout); | ||
| 42 | i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout); | 43 | i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout); |
| 44 | i2c_status_t i2c_readReg16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout); | ||
| 43 | void i2c_stop(void); | 45 | void i2c_stop(void); |
diff --git a/platforms/avr/drivers/ps2/ps2_io.c b/platforms/avr/drivers/ps2/ps2_io.c new file mode 100644 index 000000000..7c826fbf1 --- /dev/null +++ b/platforms/avr/drivers/ps2/ps2_io.c | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | #include <stdbool.h> | ||
| 2 | #include "ps2_io.h" | ||
| 3 | #include "gpio.h" | ||
| 4 | #include "wait.h" | ||
| 5 | |||
| 6 | /* Check port settings for clock and data line */ | ||
| 7 | #if !(defined(PS2_CLOCK_PIN)) | ||
| 8 | # error "PS/2 clock setting is required in config.h" | ||
| 9 | #endif | ||
| 10 | |||
| 11 | #if !(defined(PS2_DATA_PIN)) | ||
| 12 | # error "PS/2 data setting is required in config.h" | ||
| 13 | #endif | ||
| 14 | |||
| 15 | /* | ||
| 16 | * Clock | ||
| 17 | */ | ||
| 18 | void clock_init(void) {} | ||
| 19 | |||
| 20 | void clock_lo(void) { | ||
| 21 | // Transition from input with pull-up to output low via Hi-Z instead of output high | ||
| 22 | writePinLow(PS2_CLOCK_PIN); | ||
| 23 | setPinOutput(PS2_CLOCK_PIN); | ||
| 24 | } | ||
| 25 | |||
| 26 | void clock_hi(void) { setPinInputHigh(PS2_CLOCK_PIN); } | ||
| 27 | |||
| 28 | bool clock_in(void) { | ||
| 29 | setPinInputHigh(PS2_CLOCK_PIN); | ||
| 30 | wait_us(1); | ||
| 31 | return readPin(PS2_CLOCK_PIN); | ||
| 32 | } | ||
| 33 | |||
| 34 | /* | ||
| 35 | * Data | ||
| 36 | */ | ||
| 37 | void data_init(void) {} | ||
| 38 | |||
| 39 | void data_lo(void) { | ||
| 40 | // Transition from input with pull-up to output low via Hi-Z instead of output high | ||
| 41 | writePinLow(PS2_DATA_PIN); | ||
| 42 | setPinOutput(PS2_DATA_PIN); | ||
| 43 | } | ||
| 44 | |||
| 45 | void data_hi(void) { setPinInputHigh(PS2_DATA_PIN); } | ||
| 46 | |||
| 47 | bool data_in(void) { | ||
| 48 | setPinInputHigh(PS2_DATA_PIN); | ||
| 49 | wait_us(1); | ||
| 50 | return readPin(PS2_DATA_PIN); | ||
| 51 | } | ||
diff --git a/platforms/avr/drivers/ps2/ps2_usart.c b/platforms/avr/drivers/ps2/ps2_usart.c new file mode 100644 index 000000000..151cfcd68 --- /dev/null +++ b/platforms/avr/drivers/ps2/ps2_usart.c | |||
| @@ -0,0 +1,227 @@ | |||
| 1 | /* | ||
| 2 | Copyright 2010,2011,2012,2013 Jun WAKO <wakojun@gmail.com> | ||
| 3 | |||
| 4 | This software is licensed with a Modified BSD License. | ||
| 5 | All of this is supposed to be Free Software, Open Source, DFSG-free, | ||
| 6 | GPL-compatible, and OK to use in both free and proprietary applications. | ||
| 7 | Additions and corrections to this file are welcome. | ||
| 8 | |||
| 9 | |||
| 10 | Redistribution and use in source and binary forms, with or without | ||
| 11 | modification, are permitted provided that the following conditions are met: | ||
| 12 | |||
| 13 | * Redistributions of source code must retain the above copyright | ||
| 14 | notice, this list of conditions and the following disclaimer. | ||
| 15 | |||
| 16 | * Redistributions in binary form must reproduce the above copyright | ||
| 17 | notice, this list of conditions and the following disclaimer in | ||
| 18 | the documentation and/or other materials provided with the | ||
| 19 | distribution. | ||
| 20 | |||
| 21 | * Neither the name of the copyright holders nor the names of | ||
| 22 | contributors may be used to endorse or promote products derived | ||
| 23 | from this software without specific prior written permission. | ||
| 24 | |||
| 25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
| 26 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
| 27 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
| 28 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
| 29 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
| 30 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
| 31 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
| 32 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
| 33 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
| 34 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
| 35 | POSSIBILITY OF SUCH DAMAGE. | ||
| 36 | */ | ||
| 37 | |||
| 38 | /* | ||
| 39 | * PS/2 protocol USART version | ||
| 40 | */ | ||
| 41 | |||
| 42 | #include <stdbool.h> | ||
| 43 | #include <avr/interrupt.h> | ||
| 44 | #include <util/delay.h> | ||
| 45 | #include "gpio.h" | ||
| 46 | #include "ps2.h" | ||
| 47 | #include "ps2_io.h" | ||
| 48 | #include "print.h" | ||
| 49 | |||
| 50 | #ifndef PS2_CLOCK_DDR | ||
| 51 | # define PS2_CLOCK_DDR PORTx_ADDRESS(PS2_CLOCK_PIN) | ||
| 52 | #endif | ||
| 53 | #ifndef PS2_CLOCK_BIT | ||
| 54 | # define PS2_CLOCK_BIT (PS2_CLOCK_PIN & 0xF) | ||
| 55 | #endif | ||
| 56 | #ifndef PS2_DATA_DDR | ||
| 57 | # define PS2_DATA_DDR PORTx_ADDRESS(PS2_DATA_PIN) | ||
| 58 | #endif | ||
| 59 | #ifndef PS2_DATA_BIT | ||
| 60 | # define PS2_DATA_BIT (PS2_DATA_PIN & 0xF) | ||
| 61 | #endif | ||
| 62 | |||
| 63 | #define WAIT(stat, us, err) \ | ||
| 64 | do { \ | ||
| 65 | if (!wait_##stat(us)) { \ | ||
| 66 | ps2_error = err; \ | ||
| 67 | goto ERROR; \ | ||
| 68 | } \ | ||
| 69 | } while (0) | ||
| 70 | |||
| 71 | uint8_t ps2_error = PS2_ERR_NONE; | ||
| 72 | |||
| 73 | static inline uint8_t pbuf_dequeue(void); | ||
| 74 | static inline void pbuf_enqueue(uint8_t data); | ||
| 75 | static inline bool pbuf_has_data(void); | ||
| 76 | static inline void pbuf_clear(void); | ||
| 77 | |||
| 78 | void ps2_host_init(void) { | ||
| 79 | idle(); // without this many USART errors occur when cable is disconnected | ||
| 80 | PS2_USART_INIT(); | ||
| 81 | PS2_USART_RX_INT_ON(); | ||
| 82 | // POR(150-2000ms) plus BAT(300-500ms) may take 2.5sec([3]p.20) | ||
| 83 | //_delay_ms(2500); | ||
| 84 | } | ||
| 85 | |||
| 86 | uint8_t ps2_host_send(uint8_t data) { | ||
| 87 | bool parity = true; | ||
| 88 | ps2_error = PS2_ERR_NONE; | ||
| 89 | |||
| 90 | PS2_USART_OFF(); | ||
| 91 | |||
| 92 | /* terminate a transmission if we have */ | ||
| 93 | inhibit(); | ||
| 94 | _delay_us(100); // [4]p.13 | ||
| 95 | |||
| 96 | /* 'Request to Send' and Start bit */ | ||
| 97 | data_lo(); | ||
| 98 | clock_hi(); | ||
| 99 | WAIT(clock_lo, 10000, 10); // 10ms [5]p.50 | ||
| 100 | |||
| 101 | /* Data bit[2-9] */ | ||
| 102 | for (uint8_t i = 0; i < 8; i++) { | ||
| 103 | _delay_us(15); | ||
| 104 | if (data & (1 << i)) { | ||
| 105 | parity = !parity; | ||
| 106 | data_hi(); | ||
| 107 | } else { | ||
| 108 | data_lo(); | ||
| 109 | } | ||
| 110 | WAIT(clock_hi, 50, 2); | ||
| 111 | WAIT(clock_lo, 50, 3); | ||
| 112 | } | ||
| 113 | |||
| 114 | /* Parity bit */ | ||
| 115 | _delay_us(15); | ||
| 116 | if (parity) { | ||
| 117 | data_hi(); | ||
| 118 | } else { | ||
| 119 | data_lo(); | ||
| 120 | } | ||
| 121 | WAIT(clock_hi, 50, 4); | ||
| 122 | WAIT(clock_lo, 50, 5); | ||
| 123 | |||
| 124 | /* Stop bit */ | ||
| 125 | _delay_us(15); | ||
| 126 | data_hi(); | ||
| 127 | |||
| 128 | /* Ack */ | ||
| 129 | WAIT(data_lo, 50, 6); | ||
| 130 | WAIT(clock_lo, 50, 7); | ||
| 131 | |||
| 132 | /* wait for idle state */ | ||
| 133 | WAIT(clock_hi, 50, 8); | ||
| 134 | WAIT(data_hi, 50, 9); | ||
| 135 | |||
| 136 | idle(); | ||
| 137 | PS2_USART_INIT(); | ||
| 138 | PS2_USART_RX_INT_ON(); | ||
| 139 | return ps2_host_recv_response(); | ||
| 140 | ERROR: | ||
| 141 | idle(); | ||
| 142 | PS2_USART_INIT(); | ||
| 143 | PS2_USART_RX_INT_ON(); | ||
| 144 | return 0; | ||
| 145 | } | ||
| 146 | |||
| 147 | uint8_t ps2_host_recv_response(void) { | ||
| 148 | // Command may take 25ms/20ms at most([5]p.46, [3]p.21) | ||
| 149 | uint8_t retry = 25; | ||
| 150 | while (retry-- && !pbuf_has_data()) { | ||
| 151 | _delay_ms(1); | ||
| 152 | } | ||
| 153 | return pbuf_dequeue(); | ||
| 154 | } | ||
| 155 | |||
| 156 | uint8_t ps2_host_recv(void) { | ||
| 157 | if (pbuf_has_data()) { | ||
| 158 | ps2_error = PS2_ERR_NONE; | ||
| 159 | return pbuf_dequeue(); | ||
| 160 | } else { | ||
| 161 | ps2_error = PS2_ERR_NODATA; | ||
| 162 | return 0; | ||
| 163 | } | ||
| 164 | } | ||
| 165 | |||
| 166 | ISR(PS2_USART_RX_VECT) { | ||
| 167 | // TODO: request RESEND when error occurs? | ||
| 168 | uint8_t error = PS2_USART_ERROR; // USART error should be read before data | ||
| 169 | uint8_t data = PS2_USART_RX_DATA; | ||
| 170 | if (!error) { | ||
| 171 | pbuf_enqueue(data); | ||
| 172 | } else { | ||
| 173 | xprintf("PS2 USART error: %02X data: %02X\n", error, data); | ||
| 174 | } | ||
| 175 | } | ||
| 176 | |||
| 177 | /* send LED state to keyboard */ | ||
| 178 | void ps2_host_set_led(uint8_t led) { | ||
| 179 | ps2_host_send(0xED); | ||
| 180 | ps2_host_send(led); | ||
| 181 | } | ||
| 182 | |||
| 183 | /*-------------------------------------------------------------------- | ||
| 184 | * Ring buffer to store scan codes from keyboard | ||
| 185 | *------------------------------------------------------------------*/ | ||
| 186 | #define PBUF_SIZE 32 | ||
| 187 | static uint8_t pbuf[PBUF_SIZE]; | ||
| 188 | static uint8_t pbuf_head = 0; | ||
| 189 | static uint8_t pbuf_tail = 0; | ||
| 190 | static inline void pbuf_enqueue(uint8_t data) { | ||
| 191 | uint8_t sreg = SREG; | ||
| 192 | cli(); | ||
| 193 | uint8_t next = (pbuf_head + 1) % PBUF_SIZE; | ||
| 194 | if (next != pbuf_tail) { | ||
| 195 | pbuf[pbuf_head] = data; | ||
| 196 | pbuf_head = next; | ||
| 197 | } else { | ||
| 198 | print("pbuf: full\n"); | ||
| 199 | } | ||
| 200 | SREG = sreg; | ||
| 201 | } | ||
| 202 | static inline uint8_t pbuf_dequeue(void) { | ||
| 203 | uint8_t val = 0; | ||
| 204 | |||
| 205 | uint8_t sreg = SREG; | ||
| 206 | cli(); | ||
| 207 | if (pbuf_head != pbuf_tail) { | ||
| 208 | val = pbuf[pbuf_tail]; | ||
| 209 | pbuf_tail = (pbuf_tail + 1) % PBUF_SIZE; | ||
| 210 | } | ||
| 211 | SREG = sreg; | ||
| 212 | |||
| 213 | return val; | ||
| 214 | } | ||
| 215 | static inline bool pbuf_has_data(void) { | ||
| 216 | uint8_t sreg = SREG; | ||
| 217 | cli(); | ||
| 218 | bool has_data = (pbuf_head != pbuf_tail); | ||
| 219 | SREG = sreg; | ||
| 220 | return has_data; | ||
| 221 | } | ||
| 222 | static inline void pbuf_clear(void) { | ||
| 223 | uint8_t sreg = SREG; | ||
| 224 | cli(); | ||
| 225 | pbuf_head = pbuf_tail = 0; | ||
| 226 | SREG = sreg; | ||
| 227 | } | ||
diff --git a/platforms/avr/drivers/uart.c b/platforms/avr/drivers/uart.c index c6abcb6fe..01cf6b1fb 100644 --- a/platforms/avr/drivers/uart.c +++ b/platforms/avr/drivers/uart.c | |||
| @@ -100,7 +100,7 @@ void uart_init(uint32_t baud) { | |||
| 100 | } | 100 | } |
| 101 | 101 | ||
| 102 | // Transmit a byte | 102 | // Transmit a byte |
| 103 | void uart_putchar(uint8_t c) { | 103 | void uart_write(uint8_t data) { |
| 104 | uint8_t i; | 104 | uint8_t i; |
| 105 | 105 | ||
| 106 | i = tx_buffer_head + 1; | 106 | i = tx_buffer_head + 1; |
| @@ -110,27 +110,39 @@ void uart_putchar(uint8_t c) { | |||
| 110 | while (tx_buffer_tail == i) | 110 | while (tx_buffer_tail == i) |
| 111 | ; // wait until space in buffer | 111 | ; // wait until space in buffer |
| 112 | // cli(); | 112 | // cli(); |
| 113 | tx_buffer[i] = c; | 113 | tx_buffer[i] = data; |
| 114 | tx_buffer_head = i; | 114 | tx_buffer_head = i; |
| 115 | UCSRnB = (1 << RXENn) | (1 << TXENn) | (1 << RXCIEn) | (1 << UDRIEn); | 115 | UCSRnB = (1 << RXENn) | (1 << TXENn) | (1 << RXCIEn) | (1 << UDRIEn); |
| 116 | // sei(); | 116 | // sei(); |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | // Receive a byte | 119 | // Receive a byte |
| 120 | uint8_t uart_getchar(void) { | 120 | uint8_t uart_read(void) { |
| 121 | uint8_t c, i; | 121 | uint8_t data, i; |
| 122 | 122 | ||
| 123 | while (rx_buffer_head == rx_buffer_tail) | 123 | while (rx_buffer_head == rx_buffer_tail) |
| 124 | ; // wait for character | 124 | ; // wait for character |
| 125 | i = rx_buffer_tail + 1; | 125 | i = rx_buffer_tail + 1; |
| 126 | if (i >= RX_BUFFER_SIZE) i = 0; | 126 | if (i >= RX_BUFFER_SIZE) i = 0; |
| 127 | c = rx_buffer[i]; | 127 | data = rx_buffer[i]; |
| 128 | rx_buffer_tail = i; | 128 | rx_buffer_tail = i; |
| 129 | return c; | 129 | return data; |
| 130 | } | ||
| 131 | |||
| 132 | void uart_transmit(const uint8_t *data, uint16_t length) { | ||
| 133 | for (uint16_t i = 0; i < length; i++) { | ||
| 134 | uart_write(data[i]); | ||
| 135 | } | ||
| 136 | } | ||
| 137 | |||
| 138 | void uart_receive(uint8_t *data, uint16_t length) { | ||
| 139 | for (uint16_t i = 0; i < length; i++) { | ||
| 140 | data[i] = uart_read(); | ||
| 141 | } | ||
| 130 | } | 142 | } |
| 131 | 143 | ||
| 132 | // Return whether the number of bytes waiting in the receive buffer is nonzero. | 144 | // Return whether the number of bytes waiting in the receive buffer is nonzero. |
| 133 | // Call this before uart_getchar() to check if it will need | 145 | // Call this before uart_read() to check if it will need |
| 134 | // to wait for a byte to arrive. | 146 | // to wait for a byte to arrive. |
| 135 | bool uart_available(void) { | 147 | bool uart_available(void) { |
| 136 | uint8_t head, tail; | 148 | uint8_t head, tail; |
diff --git a/platforms/avr/drivers/uart.h b/platforms/avr/drivers/uart.h index 602eb3d8b..e2dc664ed 100644 --- a/platforms/avr/drivers/uart.h +++ b/platforms/avr/drivers/uart.h | |||
| @@ -28,8 +28,12 @@ | |||
| 28 | 28 | ||
| 29 | void uart_init(uint32_t baud); | 29 | void uart_init(uint32_t baud); |
| 30 | 30 | ||
| 31 | void uart_putchar(uint8_t c); | 31 | void uart_write(uint8_t data); |
| 32 | 32 | ||
| 33 | uint8_t uart_getchar(void); | 33 | uint8_t uart_read(void); |
| 34 | |||
| 35 | void uart_transmit(const uint8_t *data, uint16_t length); | ||
| 36 | |||
| 37 | void uart_receive(uint8_t *data, uint16_t length); | ||
| 34 | 38 | ||
| 35 | bool uart_available(void); | 39 | bool uart_available(void); |
diff --git a/platforms/avr/flash.mk b/platforms/avr/flash.mk index 985cb60e5..6d50e7253 100644 --- a/platforms/avr/flash.mk +++ b/platforms/avr/flash.mk | |||
| @@ -130,6 +130,15 @@ avrdude-split-right: $(BUILD_DIR)/$(TARGET).hex check-size cpfirmware | |||
| 130 | $(call EXEC_AVRDUDE,eeprom-righthand.eep) | 130 | $(call EXEC_AVRDUDE,eeprom-righthand.eep) |
| 131 | 131 | ||
| 132 | define EXEC_USBASP | 132 | define EXEC_USBASP |
| 133 | if $(AVRDUDE_PROGRAMMER) -p $(AVRDUDE_MCU) -c usbasp 2>&1 | grep -q "could not find USB device with"; then \ | ||
| 134 | printf "$(MSG_BOOTLOADER_NOT_FOUND_QUICK_RETRY)" ;\ | ||
| 135 | sleep $(BOOTLOADER_RETRY_TIME) ;\ | ||
| 136 | until $(AVRDUDE_PROGRAMMER) -p $(AVRDUDE_MCU) -c usbasp 2>&1 | (! grep -q "could not find USB device with"); do\ | ||
| 137 | printf "." ;\ | ||
| 138 | sleep $(BOOTLOADER_RETRY_TIME) ;\ | ||
| 139 | done ;\ | ||
| 140 | printf "\n" ;\ | ||
| 141 | fi | ||
| 133 | $(AVRDUDE_PROGRAMMER) -p $(AVRDUDE_MCU) -c usbasp -U flash:w:$(BUILD_DIR)/$(TARGET).hex | 142 | $(AVRDUDE_PROGRAMMER) -p $(AVRDUDE_MCU) -c usbasp -U flash:w:$(BUILD_DIR)/$(TARGET).hex |
| 134 | endef | 143 | endef |
| 135 | 144 | ||
diff --git a/platforms/avr/gpio.h b/platforms/avr/gpio.h new file mode 100644 index 000000000..e9be68491 --- /dev/null +++ b/platforms/avr/gpio.h | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | /* Copyright 2021 QMK | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 3 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #pragma once | ||
| 17 | |||
| 18 | #include <avr/io.h> | ||
| 19 | #include "pin_defs.h" | ||
| 20 | |||
| 21 | typedef uint8_t pin_t; | ||
| 22 | |||
| 23 | /* Operation of GPIO by pin. */ | ||
| 24 | |||
| 25 | #define setPinInput(pin) (DDRx_ADDRESS(pin) &= ~_BV((pin)&0xF), PORTx_ADDRESS(pin) &= ~_BV((pin)&0xF)) | ||
| 26 | #define setPinInputHigh(pin) (DDRx_ADDRESS(pin) &= ~_BV((pin)&0xF), PORTx_ADDRESS(pin) |= _BV((pin)&0xF)) | ||
| 27 | #define setPinInputLow(pin) _Static_assert(0, "AVR processors cannot implement an input as pull low") | ||
| 28 | #define setPinOutput(pin) (DDRx_ADDRESS(pin) |= _BV((pin)&0xF)) | ||
| 29 | |||
| 30 | #define writePinHigh(pin) (PORTx_ADDRESS(pin) |= _BV((pin)&0xF)) | ||
| 31 | #define writePinLow(pin) (PORTx_ADDRESS(pin) &= ~_BV((pin)&0xF)) | ||
| 32 | #define writePin(pin, level) ((level) ? writePinHigh(pin) : writePinLow(pin)) | ||
| 33 | |||
| 34 | #define readPin(pin) ((bool)(PINx_ADDRESS(pin) & _BV((pin)&0xF))) | ||
| 35 | |||
| 36 | #define togglePin(pin) (PORTx_ADDRESS(pin) ^= _BV((pin)&0xF)) | ||
| 37 | |||
| 38 | /* Operation of GPIO by port. */ | ||
| 39 | |||
| 40 | typedef uint8_t port_data_t; | ||
| 41 | |||
| 42 | #define readPort(port) PINx_ADDRESS(port) | ||
| 43 | |||
| 44 | #define setPortBitInput(port, bit) (DDRx_ADDRESS(port) &= ~_BV((bit)&0xF), PORTx_ADDRESS(port) &= ~_BV((bit)&0xF)) | ||
| 45 | #define setPortBitInputHigh(port, bit) (DDRx_ADDRESS(port) &= ~_BV((bit)&0xF), PORTx_ADDRESS(port) |= _BV((bit)&0xF)) | ||
| 46 | #define setPortBitOutput(port, bit) (DDRx_ADDRESS(port) |= _BV((bit)&0xF)) | ||
| 47 | |||
| 48 | #define writePortBitLow(port, bit) (PORTx_ADDRESS(port) &= ~_BV((bit)&0xF)) | ||
| 49 | #define writePortBitHigh(port, bit) (PORTx_ADDRESS(port) |= _BV((bit)&0xF)) | ||
diff --git a/platforms/avr/pin_defs.h b/platforms/avr/pin_defs.h new file mode 100644 index 000000000..23d948041 --- /dev/null +++ b/platforms/avr/pin_defs.h | |||
| @@ -0,0 +1,128 @@ | |||
| 1 | /* Copyright 2021 QMK | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 3 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #pragma once | ||
| 17 | |||
| 18 | #include <avr/io.h> | ||
| 19 | |||
| 20 | #define PORT_SHIFTER 4 // this may be 4 for all AVR chips | ||
| 21 | |||
| 22 | // If you want to add more to this list, reference the PINx definitions in these header | ||
| 23 | // files: https://github.com/vancegroup-mirrors/avr-libc/tree/master/avr-libc/include/avr | ||
| 24 | |||
| 25 | #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega16U4__) | ||
| 26 | # define ADDRESS_BASE 0x00 | ||
| 27 | # define PINB_ADDRESS 0x3 | ||
| 28 | # define PINC_ADDRESS 0x6 | ||
| 29 | # define PIND_ADDRESS 0x9 | ||
| 30 | # define PINE_ADDRESS 0xC | ||
| 31 | # define PINF_ADDRESS 0xF | ||
| 32 | #elif defined(__AVR_AT90USB162__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__) | ||
| 33 | # define ADDRESS_BASE 0x00 | ||
| 34 | # define PINB_ADDRESS 0x3 | ||
| 35 | # define PINC_ADDRESS 0x6 | ||
| 36 | # define PIND_ADDRESS 0x9 | ||
| 37 | #elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) | ||
| 38 | # define ADDRESS_BASE 0x00 | ||
| 39 | # define PINA_ADDRESS 0x0 | ||
| 40 | # define PINB_ADDRESS 0x3 | ||
| 41 | # define PINC_ADDRESS 0x6 | ||
| 42 | # define PIND_ADDRESS 0x9 | ||
| 43 | # define PINE_ADDRESS 0xC | ||
| 44 | # define PINF_ADDRESS 0xF | ||
| 45 | #elif defined(__AVR_ATmega32A__) | ||
| 46 | # define ADDRESS_BASE 0x10 | ||
| 47 | # define PIND_ADDRESS 0x0 | ||
| 48 | # define PINC_ADDRESS 0x3 | ||
| 49 | # define PINB_ADDRESS 0x6 | ||
| 50 | # define PINA_ADDRESS 0x9 | ||
| 51 | #elif defined(__AVR_ATtiny85__) | ||
| 52 | # define ADDRESS_BASE 0x10 | ||
| 53 | # define PINB_ADDRESS 0x6 | ||
| 54 | #else | ||
| 55 | # error "Pins are not defined" | ||
| 56 | #endif | ||
| 57 | |||
| 58 | #define PINDEF(port, pin) ((PIN##port##_ADDRESS << PORT_SHIFTER) | pin) | ||
| 59 | |||
| 60 | #define _PIN_ADDRESS(p, offset) _SFR_IO8(ADDRESS_BASE + ((p) >> PORT_SHIFTER) + (offset)) | ||
| 61 | // Port X Input Pins Address | ||
| 62 | #define PINx_ADDRESS(p) _PIN_ADDRESS(p, 0) | ||
| 63 | // Port X Data Direction Register, 0:input 1:output | ||
| 64 | #define DDRx_ADDRESS(p) _PIN_ADDRESS(p, 1) | ||
| 65 | // Port X Data Register | ||
| 66 | #define PORTx_ADDRESS(p) _PIN_ADDRESS(p, 2) | ||
| 67 | |||
| 68 | /* I/O pins */ | ||
| 69 | #ifdef PORTA | ||
| 70 | # define A0 PINDEF(A, 0) | ||
| 71 | # define A1 PINDEF(A, 1) | ||
| 72 | # define A2 PINDEF(A, 2) | ||
| 73 | # define A3 PINDEF(A, 3) | ||
| 74 | # define A4 PINDEF(A, 4) | ||
| 75 | # define A5 PINDEF(A, 5) | ||
| 76 | # define A6 PINDEF(A, 6) | ||
| 77 | # define A7 PINDEF(A, 7) | ||
| 78 | #endif | ||
| 79 | #ifdef PORTB | ||
| 80 | # define B0 PINDEF(B, 0) | ||
| 81 | # define B1 PINDEF(B, 1) | ||
| 82 | # define B2 PINDEF(B, 2) | ||
| 83 | # define B3 PINDEF(B, 3) | ||
| 84 | # define B4 PINDEF(B, 4) | ||
| 85 | # define B5 PINDEF(B, 5) | ||
| 86 | # define B6 PINDEF(B, 6) | ||
| 87 | # define B7 PINDEF(B, 7) | ||
| 88 | #endif | ||
| 89 | #ifdef PORTC | ||
| 90 | # define C0 PINDEF(C, 0) | ||
| 91 | # define C1 PINDEF(C, 1) | ||
| 92 | # define C2 PINDEF(C, 2) | ||
| 93 | # define C3 PINDEF(C, 3) | ||
| 94 | # define C4 PINDEF(C, 4) | ||
| 95 | # define C5 PINDEF(C, 5) | ||
| 96 | # define C6 PINDEF(C, 6) | ||
| 97 | # define C7 PINDEF(C, 7) | ||
| 98 | #endif | ||
| 99 | #ifdef PORTD | ||
| 100 | # define D0 PINDEF(D, 0) | ||
| 101 | # define D1 PINDEF(D, 1) | ||
| 102 | # define D2 PINDEF(D, 2) | ||
| 103 | # define D3 PINDEF(D, 3) | ||
| 104 | # define D4 PINDEF(D, 4) | ||
| 105 | # define D5 PINDEF(D, 5) | ||
| 106 | # define D6 PINDEF(D, 6) | ||
| 107 | # define D7 PINDEF(D, 7) | ||
| 108 | #endif | ||
| 109 | #ifdef PORTE | ||
| 110 | # define E0 PINDEF(E, 0) | ||
| 111 | # define E1 PINDEF(E, 1) | ||
| 112 | # define E2 PINDEF(E, 2) | ||
| 113 | # define E3 PINDEF(E, 3) | ||
| 114 | # define E4 PINDEF(E, 4) | ||
| 115 | # define E5 PINDEF(E, 5) | ||
| 116 | # define E6 PINDEF(E, 6) | ||
| 117 | # define E7 PINDEF(E, 7) | ||
| 118 | #endif | ||
| 119 | #ifdef PORTF | ||
| 120 | # define F0 PINDEF(F, 0) | ||
| 121 | # define F1 PINDEF(F, 1) | ||
| 122 | # define F2 PINDEF(F, 2) | ||
| 123 | # define F3 PINDEF(F, 3) | ||
| 124 | # define F4 PINDEF(F, 4) | ||
| 125 | # define F5 PINDEF(F, 5) | ||
| 126 | # define F6 PINDEF(F, 6) | ||
| 127 | # define F7 PINDEF(F, 7) | ||
| 128 | #endif | ||
diff --git a/platforms/avr/platform.c b/platforms/avr/platform.c new file mode 100644 index 000000000..3e35b4fe4 --- /dev/null +++ b/platforms/avr/platform.c | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | /* Copyright 2021 QMK | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 3 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include "platform_deps.h" | ||
| 18 | |||
| 19 | void platform_setup(void) { | ||
| 20 | // do nothing | ||
| 21 | } | ||
diff --git a/platforms/avr/platform.mk b/platforms/avr/platform.mk new file mode 100644 index 000000000..b45108736 --- /dev/null +++ b/platforms/avr/platform.mk | |||
| @@ -0,0 +1,179 @@ | |||
| 1 | # Hey Emacs, this is a -*- makefile -*- | ||
| 2 | ############################################################################## | ||
| 3 | # Compiler settings | ||
| 4 | # | ||
| 5 | CC = $(CC_PREFIX) avr-gcc | ||
| 6 | OBJCOPY = avr-objcopy | ||
| 7 | OBJDUMP = avr-objdump | ||
| 8 | SIZE = avr-size | ||
| 9 | AR = avr-ar | ||
| 10 | NM = avr-nm | ||
| 11 | HEX = $(OBJCOPY) -O $(FORMAT) -R .eeprom -R .fuse -R .lock -R .signature | ||
| 12 | EEP = $(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT) | ||
| 13 | BIN = | ||
| 14 | |||
| 15 | COMPILEFLAGS += -funsigned-char | ||
| 16 | COMPILEFLAGS += -funsigned-bitfields | ||
| 17 | COMPILEFLAGS += -ffunction-sections | ||
| 18 | COMPILEFLAGS += -fdata-sections | ||
| 19 | COMPILEFLAGS += -fpack-struct | ||
| 20 | COMPILEFLAGS += -fshort-enums | ||
| 21 | |||
| 22 | ASFLAGS += $(AVR_ASFLAGS) | ||
| 23 | |||
| 24 | CFLAGS += $(COMPILEFLAGS) $(AVR_CFLAGS) | ||
| 25 | CFLAGS += -fno-inline-small-functions | ||
| 26 | CFLAGS += -fno-strict-aliasing | ||
| 27 | |||
| 28 | CXXFLAGS += $(COMPILEFLAGS) | ||
| 29 | CXXFLAGS += -fno-exceptions -std=c++11 | ||
| 30 | |||
| 31 | LDFLAGS +=-Wl,--gc-sections | ||
| 32 | |||
| 33 | OPT_DEFS += -DF_CPU=$(F_CPU)UL | ||
| 34 | |||
| 35 | MCUFLAGS = -mmcu=$(MCU) | ||
| 36 | |||
| 37 | # List any extra directories to look for libraries here. | ||
| 38 | # Each directory must be seperated by a space. | ||
| 39 | # Use forward slashes for directory separators. | ||
| 40 | # For a directory that has spaces, enclose it in quotes. | ||
| 41 | EXTRALIBDIRS = | ||
| 42 | |||
| 43 | |||
| 44 | #---------------- External Memory Options ---------------- | ||
| 45 | |||
| 46 | # 64 KB of external RAM, starting after internal RAM (ATmega128!), | ||
| 47 | # used for variables (.data/.bss) and heap (malloc()). | ||
| 48 | #EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff | ||
| 49 | |||
| 50 | # 64 KB of external RAM, starting after internal RAM (ATmega128!), | ||
| 51 | # only used for heap (malloc()). | ||
| 52 | #EXTMEMOPTS = -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x80ffff | ||
| 53 | |||
| 54 | EXTMEMOPTS = | ||
| 55 | |||
| 56 | #---------------- Debugging Options ---------------- | ||
| 57 | |||
| 58 | # Debugging format. | ||
| 59 | # Native formats for AVR-GCC's -g are dwarf-2 [default] or stabs. | ||
| 60 | # AVR Studio 4.10 requires dwarf-2. | ||
| 61 | # AVR [Extended] COFF format requires stabs, plus an avr-objcopy run. | ||
| 62 | DEBUG = dwarf-2 | ||
| 63 | |||
| 64 | # For simulavr only - target MCU frequency. | ||
| 65 | DEBUG_MFREQ = $(F_CPU) | ||
| 66 | |||
| 67 | # Set the DEBUG_UI to either gdb or insight. | ||
| 68 | # DEBUG_UI = gdb | ||
| 69 | DEBUG_UI = insight | ||
| 70 | |||
| 71 | # Set the debugging back-end to either avarice, simulavr. | ||
| 72 | DEBUG_BACKEND = avarice | ||
| 73 | #DEBUG_BACKEND = simulavr | ||
| 74 | |||
| 75 | # GDB Init Filename. | ||
| 76 | GDBINIT_FILE = __avr_gdbinit | ||
| 77 | |||
| 78 | # When using avarice settings for the JTAG | ||
| 79 | JTAG_DEV = /dev/com1 | ||
| 80 | |||
| 81 | # Debugging port used to communicate between GDB / avarice / simulavr. | ||
| 82 | DEBUG_PORT = 4242 | ||
| 83 | |||
| 84 | # Debugging host used to communicate between GDB / avarice / simulavr, normally | ||
| 85 | # just set to localhost unless doing some sort of crazy debugging when | ||
| 86 | # avarice is running on a different computer. | ||
| 87 | DEBUG_HOST = localhost | ||
| 88 | |||
| 89 | #============================================================================ | ||
| 90 | |||
| 91 | # Convert hex to bin. | ||
| 92 | bin: $(BUILD_DIR)/$(TARGET).hex | ||
| 93 | ifeq ($(BOOTLOADER),lufa-ms) | ||
| 94 | $(eval BIN_PADDING=$(shell n=`expr 32768 - $(BOOTLOADER_SIZE)` && echo $$(($$n)) || echo 0)) | ||
| 95 | $(OBJCOPY) -Iihex -Obinary $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin --pad-to $(BIN_PADDING) | ||
| 96 | else | ||
| 97 | $(OBJCOPY) -Iihex -Obinary $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin | ||
| 98 | endif | ||
| 99 | $(COPY) $(BUILD_DIR)/$(TARGET).bin $(TARGET).bin; | ||
| 100 | |||
| 101 | # copy bin to FLASH.bin | ||
| 102 | flashbin: bin | ||
| 103 | $(COPY) $(BUILD_DIR)/$(TARGET).bin FLASH.bin; | ||
| 104 | |||
| 105 | # Generate avr-gdb config/init file which does the following: | ||
| 106 | # define the reset signal, load the target file, connect to target, and set | ||
| 107 | # a breakpoint at main(). | ||
| 108 | gdb-config: | ||
| 109 | @$(REMOVE) $(GDBINIT_FILE) | ||
| 110 | @echo define reset >> $(GDBINIT_FILE) | ||
| 111 | @echo SIGNAL SIGHUP >> $(GDBINIT_FILE) | ||
| 112 | @echo end >> $(GDBINIT_FILE) | ||
| 113 | @echo file $(BUILD_DIR)/$(TARGET).elf >> $(GDBINIT_FILE) | ||
| 114 | @echo target remote $(DEBUG_HOST):$(DEBUG_PORT) >> $(GDBINIT_FILE) | ||
| 115 | ifeq ($(DEBUG_BACKEND),simulavr) | ||
| 116 | @echo load >> $(GDBINIT_FILE) | ||
| 117 | endif | ||
| 118 | @echo break main >> $(GDBINIT_FILE) | ||
| 119 | |||
| 120 | debug: gdb-config $(BUILD_DIR)/$(TARGET).elf | ||
| 121 | ifeq ($(DEBUG_BACKEND), avarice) | ||
| 122 | @echo Starting AVaRICE - Press enter when "waiting to connect" message displays. | ||
| 123 | @$(WINSHELL) /c start avarice --jtag $(JTAG_DEV) --erase --program --file \ | ||
| 124 | $(BUILD_DIR)/$(TARGET).elf $(DEBUG_HOST):$(DEBUG_PORT) | ||
| 125 | @$(WINSHELL) /c pause | ||
| 126 | |||
| 127 | else | ||
| 128 | @$(WINSHELL) /c start simulavr --gdbserver --device $(MCU) --clock-freq \ | ||
| 129 | $(DEBUG_MFREQ) --port $(DEBUG_PORT) | ||
| 130 | endif | ||
| 131 | @$(WINSHELL) /c start avr-$(DEBUG_UI) --command=$(GDBINIT_FILE) | ||
| 132 | |||
| 133 | |||
| 134 | |||
| 135 | |||
| 136 | # Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB. | ||
| 137 | COFFCONVERT = $(OBJCOPY) --debugging | ||
| 138 | COFFCONVERT += --change-section-address .data-0x800000 | ||
| 139 | COFFCONVERT += --change-section-address .bss-0x800000 | ||
| 140 | COFFCONVERT += --change-section-address .noinit-0x800000 | ||
| 141 | COFFCONVERT += --change-section-address .eeprom-0x810000 | ||
| 142 | |||
| 143 | |||
| 144 | |||
| 145 | coff: $(BUILD_DIR)/$(TARGET).elf | ||
| 146 | @$(SECHO) $(MSG_COFF) $(BUILD_DIR)/$(TARGET).cof | ||
| 147 | $(COFFCONVERT) -O coff-avr $< $(BUILD_DIR)/$(TARGET).cof | ||
| 148 | |||
| 149 | |||
| 150 | extcoff: $(BUILD_DIR)/$(TARGET).elf | ||
| 151 | @$(SECHO) $(MSG_EXTENDED_COFF) $(BUILD_DIR)/$(TARGET).cof | ||
| 152 | $(COFFCONVERT) -O coff-ext-avr $< $(BUILD_DIR)/$(TARGET).cof | ||
| 153 | |||
| 154 | ifeq ($(strip $(BOOTLOADER)), qmk-dfu) | ||
| 155 | QMK_BOOTLOADER_TYPE = DFU | ||
| 156 | else ifeq ($(strip $(BOOTLOADER)), qmk-hid) | ||
| 157 | QMK_BOOTLOADER_TYPE = HID | ||
| 158 | endif | ||
| 159 | |||
| 160 | bootloader: | ||
| 161 | ifeq ($(strip $(QMK_BOOTLOADER_TYPE)),) | ||
| 162 | $(error Please set BOOTLOADER to "qmk-dfu" or "qmk-hid" first!) | ||
| 163 | else | ||
| 164 | make -C lib/lufa/Bootloaders/$(QMK_BOOTLOADER_TYPE)/ clean | ||
| 165 | $(QMK_BIN) generate-dfu-header --quiet --keyboard $(KEYBOARD) --output lib/lufa/Bootloaders/$(QMK_BOOTLOADER_TYPE)/Keyboard.h | ||
| 166 | $(eval MAX_SIZE=$(shell n=`$(CC) -E -mmcu=$(MCU) -D__ASSEMBLER__ $(CFLAGS) $(OPT_DEFS) platforms/avr/bootloader_size.c 2> /dev/null | sed -ne 's/\r//;/^#/n;/^AVR_SIZE:/,$${s/^AVR_SIZE: //;p;}'` && echo $$(($$n)) || echo 0)) | ||
| 167 | $(eval PROGRAM_SIZE_KB=$(shell n=`expr $(MAX_SIZE) / 1024` && echo $$(($$n)) || echo 0)) | ||
| 168 | $(eval BOOT_SECTION_SIZE_KB=$(shell n=`expr $(BOOTLOADER_SIZE) / 1024` && echo $$(($$n)) || echo 0)) | ||
| 169 | $(eval FLASH_SIZE_KB=$(shell n=`expr $(PROGRAM_SIZE_KB) + $(BOOT_SECTION_SIZE_KB)` && echo $$(($$n)) || echo 0)) | ||
| 170 | make -C lib/lufa/Bootloaders/$(QMK_BOOTLOADER_TYPE)/ MCU=$(MCU) ARCH=$(ARCH) F_CPU=$(F_CPU) FLASH_SIZE_KB=$(FLASH_SIZE_KB) BOOT_SECTION_SIZE_KB=$(BOOT_SECTION_SIZE_KB) | ||
| 171 | printf "Bootloader$(QMK_BOOTLOADER_TYPE).hex copied to $(TARGET)_bootloader.hex\n" | ||
| 172 | cp lib/lufa/Bootloaders/$(QMK_BOOTLOADER_TYPE)/Bootloader$(QMK_BOOTLOADER_TYPE).hex $(TARGET)_bootloader.hex | ||
| 173 | endif | ||
| 174 | |||
| 175 | production: $(BUILD_DIR)/$(TARGET).hex bootloader cpfirmware | ||
| 176 | @cat $(BUILD_DIR)/$(TARGET).hex | awk '/^:00000001FF/ == 0' > $(TARGET)_production.hex | ||
| 177 | @cat $(TARGET)_bootloader.hex >> $(TARGET)_production.hex | ||
| 178 | echo "File sizes:" | ||
| 179 | $(SIZE) $(TARGET).hex $(TARGET)_bootloader.hex $(TARGET)_production.hex | ||
diff --git a/platforms/avr/platform_deps.h b/platforms/avr/platform_deps.h new file mode 100644 index 000000000..45d9dcebf --- /dev/null +++ b/platforms/avr/platform_deps.h | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | /* Copyright 2021 QMK | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 3 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #pragma once | ||
| 17 | |||
| 18 | #include <avr/pgmspace.h> | ||
| 19 | #include <avr/io.h> | ||
| 20 | #include <avr/interrupt.h> | ||
diff --git a/platforms/avr/printf.c b/platforms/avr/printf.c new file mode 100644 index 000000000..9ad7a3869 --- /dev/null +++ b/platforms/avr/printf.c | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | /* | ||
| 2 | Copyright 2011 Jun Wako <wakojun@gmail.com> | ||
| 3 | |||
| 4 | This program is free software: you can redistribute it and/or modify | ||
| 5 | it under the terms of the GNU General Public License as published by | ||
| 6 | the Free Software Foundation, either version 2 of the License, or | ||
| 7 | (at your option) any later version. | ||
| 8 | |||
| 9 | This program is distributed in the hope that it will be useful, | ||
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | GNU General Public License for more details. | ||
| 13 | |||
| 14 | You should have received a copy of the GNU General Public License | ||
| 15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | ||
| 17 | #include "xprintf.h" | ||
| 18 | #include "sendchar.h" | ||
| 19 | |||
| 20 | void print_set_sendchar(sendchar_func_t func) { xdev_out(func); } | ||
diff --git a/platforms/avr/printf.mk b/platforms/avr/printf.mk new file mode 100644 index 000000000..060ad88c5 --- /dev/null +++ b/platforms/avr/printf.mk | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/xprintf.S | ||
| 2 | TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/printf.c | ||
diff --git a/platforms/avr/sleep_led.c b/platforms/avr/sleep_led.c new file mode 100644 index 000000000..9a3b52abe --- /dev/null +++ b/platforms/avr/sleep_led.c | |||
| @@ -0,0 +1,124 @@ | |||
| 1 | #include <stdint.h> | ||
| 2 | #include <avr/io.h> | ||
| 3 | #include <avr/interrupt.h> | ||
| 4 | #include <avr/pgmspace.h> | ||
| 5 | #include "led.h" | ||
| 6 | #include "sleep_led.h" | ||
| 7 | |||
| 8 | #ifndef SLEEP_LED_TIMER | ||
| 9 | # define SLEEP_LED_TIMER 1 | ||
| 10 | #endif | ||
| 11 | |||
| 12 | #if SLEEP_LED_TIMER == 1 | ||
| 13 | # define TCCRxB TCCR1B | ||
| 14 | # define TIMERx_COMPA_vect TIMER1_COMPA_vect | ||
| 15 | # if defined(__AVR_ATmega32A__) // This MCU has only one TIMSK register | ||
| 16 | # define TIMSKx TIMSK | ||
| 17 | # else | ||
| 18 | # define TIMSKx TIMSK1 | ||
| 19 | # endif | ||
| 20 | # define OCIExA OCIE1A | ||
| 21 | # define OCRxx OCR1A | ||
| 22 | #elif SLEEP_LED_TIMER == 3 | ||
| 23 | # define TCCRxB TCCR3B | ||
| 24 | # define TIMERx_COMPA_vect TIMER3_COMPA_vect | ||
| 25 | # define TIMSKx TIMSK3 | ||
| 26 | # define OCIExA OCIE3A | ||
| 27 | # define OCRxx OCR3A | ||
| 28 | #else | ||
| 29 | error("Invalid SLEEP_LED_TIMER config") | ||
| 30 | #endif | ||
| 31 | |||
| 32 | /* Software PWM | ||
| 33 | * ______ ______ __ | ||
| 34 | * | ON |___OFF___| ON |___OFF___| .... | ||
| 35 | * |<-------------->|<-------------->|<- .... | ||
| 36 | * PWM period PWM period | ||
| 37 | * | ||
| 38 | * 256 interrupts/period[resolution] | ||
| 39 | * 64 periods/second[frequency] | ||
| 40 | * 256*64 interrupts/second | ||
| 41 | * F_CPU/(256*64) clocks/interrupt | ||
| 42 | */ | ||
| 43 | #define SLEEP_LED_TIMER_TOP F_CPU / (256 * 64) | ||
| 44 | |||
| 45 | /** \brief Sleep LED initialization | ||
| 46 | * | ||
| 47 | * FIXME: needs doc | ||
| 48 | */ | ||
| 49 | void sleep_led_init(void) { | ||
| 50 | /* Timer1 setup */ | ||
| 51 | /* CTC mode */ | ||
| 52 | TCCRxB |= _BV(WGM12); | ||
| 53 | /* Clock selelct: clk/1 */ | ||
| 54 | TCCRxB |= _BV(CS10); | ||
| 55 | /* Set TOP value */ | ||
| 56 | uint8_t sreg = SREG; | ||
| 57 | cli(); | ||
| 58 | OCRxx = SLEEP_LED_TIMER_TOP; | ||
| 59 | SREG = sreg; | ||
| 60 | } | ||
| 61 | |||
| 62 | /** \brief Sleep LED enable | ||
| 63 | * | ||
| 64 | * FIXME: needs doc | ||
| 65 | */ | ||
| 66 | void sleep_led_enable(void) { | ||
| 67 | /* Enable Compare Match Interrupt */ | ||
| 68 | TIMSKx |= _BV(OCIExA); | ||
| 69 | } | ||
| 70 | |||
| 71 | /** \brief Sleep LED disable | ||
| 72 | * | ||
| 73 | * FIXME: needs doc | ||
| 74 | */ | ||
| 75 | void sleep_led_disable(void) { | ||
| 76 | /* Disable Compare Match Interrupt */ | ||
| 77 | TIMSKx &= ~_BV(OCIExA); | ||
| 78 | } | ||
| 79 | |||
| 80 | /** \brief Sleep LED toggle | ||
| 81 | * | ||
| 82 | * FIXME: needs doc | ||
| 83 | */ | ||
| 84 | void sleep_led_toggle(void) { | ||
| 85 | /* Disable Compare Match Interrupt */ | ||
| 86 | TIMSKx ^= _BV(OCIExA); | ||
| 87 | } | ||
| 88 | |||
| 89 | /** \brief Breathing Sleep LED brighness(PWM On period) table | ||
| 90 | * | ||
| 91 | * (64[steps] * 4[duration]) / 64[PWM periods/s] = 4 second breath cycle | ||
| 92 | * | ||
| 93 | * https://www.wolframalpha.com/input/?i=sin%28x%2F64*pi%29**8+*+255%2C+x%3D0+to+63 | ||
| 94 | * (0..63).each {|x| p ((sin(x/64.0*PI)**8)*255).to_i } | ||
| 95 | */ | ||
| 96 | static const uint8_t breathing_table[64] PROGMEM = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 6, 10, 15, 23, 32, 44, 58, 74, 93, 113, 135, 157, 179, 199, 218, 233, 245, 252, 255, 252, 245, 233, 218, 199, 179, 157, 135, 113, 93, 74, 58, 44, 32, 23, 15, 10, 6, 4, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; | ||
| 97 | |||
| 98 | ISR(TIMERx_COMPA_vect) { | ||
| 99 | /* Software PWM | ||
| 100 | * timer:1111 1111 1111 1111 | ||
| 101 | * \_____/\/ \_______/____ count(0-255) | ||
| 102 | * \ \______________ duration of step(4) | ||
| 103 | * \__________________ index of step table(0-63) | ||
| 104 | */ | ||
| 105 | static union { | ||
| 106 | uint16_t row; | ||
| 107 | struct { | ||
| 108 | uint8_t count : 8; | ||
| 109 | uint8_t duration : 2; | ||
| 110 | uint8_t index : 6; | ||
| 111 | } pwm; | ||
| 112 | } timer = {.row = 0}; | ||
| 113 | |||
| 114 | timer.row++; | ||
| 115 | |||
| 116 | // LED on | ||
| 117 | if (timer.pwm.count == 0) { | ||
| 118 | led_set(1 << USB_LED_CAPS_LOCK); | ||
| 119 | } | ||
| 120 | // LED off | ||
| 121 | if (timer.pwm.count == pgm_read_byte(&breathing_table[timer.pwm.index])) { | ||
| 122 | led_set(0); | ||
| 123 | } | ||
| 124 | } | ||
diff --git a/platforms/avr/suspend.c b/platforms/avr/suspend.c new file mode 100644 index 000000000..b614746e6 --- /dev/null +++ b/platforms/avr/suspend.c | |||
| @@ -0,0 +1,152 @@ | |||
| 1 | #include <stdbool.h> | ||
| 2 | #include <avr/sleep.h> | ||
| 3 | #include <avr/wdt.h> | ||
| 4 | #include <avr/interrupt.h> | ||
| 5 | #include "matrix.h" | ||
| 6 | #include "action.h" | ||
| 7 | #include "suspend.h" | ||
| 8 | #include "timer.h" | ||
| 9 | #include "led.h" | ||
| 10 | #include "host.h" | ||
| 11 | |||
| 12 | #ifdef PROTOCOL_LUFA | ||
| 13 | # include "lufa.h" | ||
| 14 | #endif | ||
| 15 | #ifdef PROTOCOL_VUSB | ||
| 16 | # include "vusb.h" | ||
| 17 | #endif | ||
| 18 | |||
| 19 | /** \brief Suspend idle | ||
| 20 | * | ||
| 21 | * FIXME: needs doc | ||
| 22 | */ | ||
| 23 | void suspend_idle(uint8_t time) { | ||
| 24 | cli(); | ||
| 25 | set_sleep_mode(SLEEP_MODE_IDLE); | ||
| 26 | sleep_enable(); | ||
| 27 | sei(); | ||
| 28 | sleep_cpu(); | ||
| 29 | sleep_disable(); | ||
| 30 | } | ||
| 31 | |||
| 32 | // TODO: This needs some cleanup | ||
| 33 | |||
| 34 | #if !defined(NO_SUSPEND_POWER_DOWN) && defined(WDT_vect) | ||
| 35 | |||
| 36 | // clang-format off | ||
| 37 | #define wdt_intr_enable(value) \ | ||
| 38 | __asm__ __volatile__ ( \ | ||
| 39 | "in __tmp_reg__,__SREG__" "\n\t" \ | ||
| 40 | "cli" "\n\t" \ | ||
| 41 | "wdr" "\n\t" \ | ||
| 42 | "sts %0,%1" "\n\t" \ | ||
| 43 | "out __SREG__,__tmp_reg__" "\n\t" \ | ||
| 44 | "sts %0,%2" "\n\t" \ | ||
| 45 | : /* no outputs */ \ | ||
| 46 | : "M" (_SFR_MEM_ADDR(_WD_CONTROL_REG)), \ | ||
| 47 | "r" (_BV(_WD_CHANGE_BIT) | _BV(WDE)), \ | ||
| 48 | "r" ((uint8_t) ((value & 0x08 ? _WD_PS3_MASK : 0x00) | _BV(WDIE) | (value & 0x07))) \ | ||
| 49 | : "r0" \ | ||
| 50 | ) | ||
| 51 | // clang-format on | ||
| 52 | |||
| 53 | /** \brief Power down MCU with watchdog timer | ||
| 54 | * | ||
| 55 | * wdto: watchdog timer timeout defined in <avr/wdt.h> | ||
| 56 | * WDTO_15MS | ||
| 57 | * WDTO_30MS | ||
| 58 | * WDTO_60MS | ||
| 59 | * WDTO_120MS | ||
| 60 | * WDTO_250MS | ||
| 61 | * WDTO_500MS | ||
| 62 | * WDTO_1S | ||
| 63 | * WDTO_2S | ||
| 64 | * WDTO_4S | ||
| 65 | * WDTO_8S | ||
| 66 | */ | ||
| 67 | static uint8_t wdt_timeout = 0; | ||
| 68 | |||
| 69 | /** \brief Power down | ||
| 70 | * | ||
| 71 | * FIXME: needs doc | ||
| 72 | */ | ||
| 73 | static void power_down(uint8_t wdto) { | ||
| 74 | wdt_timeout = wdto; | ||
| 75 | |||
| 76 | // Watchdog Interrupt Mode | ||
| 77 | wdt_intr_enable(wdto); | ||
| 78 | |||
| 79 | // TODO: more power saving | ||
| 80 | // See PicoPower application note | ||
| 81 | // - I/O port input with pullup | ||
| 82 | // - prescale clock | ||
| 83 | // - BOD disable | ||
| 84 | // - Power Reduction Register PRR | ||
| 85 | set_sleep_mode(SLEEP_MODE_PWR_DOWN); | ||
| 86 | sleep_enable(); | ||
| 87 | sei(); | ||
| 88 | sleep_cpu(); | ||
| 89 | sleep_disable(); | ||
| 90 | |||
| 91 | // Disable watchdog after sleep | ||
| 92 | wdt_disable(); | ||
| 93 | } | ||
| 94 | #endif | ||
| 95 | |||
| 96 | /** \brief Suspend power down | ||
| 97 | * | ||
| 98 | * FIXME: needs doc | ||
| 99 | */ | ||
| 100 | void suspend_power_down(void) { | ||
| 101 | #ifdef PROTOCOL_LUFA | ||
| 102 | if (USB_DeviceState == DEVICE_STATE_Configured) return; | ||
| 103 | #endif | ||
| 104 | #ifdef PROTOCOL_VUSB | ||
| 105 | if (!vusb_suspended) return; | ||
| 106 | #endif | ||
| 107 | |||
| 108 | suspend_power_down_quantum(); | ||
| 109 | |||
| 110 | #ifndef NO_SUSPEND_POWER_DOWN | ||
| 111 | // Enter sleep state if possible (ie, the MCU has a watchdog timeout interrupt) | ||
| 112 | # if defined(WDT_vect) | ||
| 113 | power_down(WDTO_15MS); | ||
| 114 | # endif | ||
| 115 | #endif | ||
| 116 | } | ||
| 117 | |||
| 118 | __attribute__((weak)) void matrix_power_up(void) {} | ||
| 119 | __attribute__((weak)) void matrix_power_down(void) {} | ||
| 120 | bool suspend_wakeup_condition(void) { | ||
| 121 | matrix_power_up(); | ||
| 122 | matrix_scan(); | ||
| 123 | matrix_power_down(); | ||
| 124 | for (uint8_t r = 0; r < MATRIX_ROWS; r++) { | ||
| 125 | if (matrix_get_row(r)) return true; | ||
| 126 | } | ||
| 127 | return false; | ||
| 128 | } | ||
| 129 | |||
| 130 | /** \brief run immediately after wakeup | ||
| 131 | * | ||
| 132 | * FIXME: needs doc | ||
| 133 | */ | ||
| 134 | void suspend_wakeup_init(void) { | ||
| 135 | // clear keyboard state | ||
| 136 | clear_keyboard(); | ||
| 137 | |||
| 138 | suspend_wakeup_init_quantum(); | ||
| 139 | } | ||
| 140 | |||
| 141 | #if !defined(NO_SUSPEND_POWER_DOWN) && defined(WDT_vect) | ||
| 142 | /* watchdog timeout */ | ||
| 143 | ISR(WDT_vect) { | ||
| 144 | // compensate timer for sleep | ||
| 145 | switch (wdt_timeout) { | ||
| 146 | case WDTO_15MS: | ||
| 147 | timer_count += 15 + 2; // WDTO_15MS + 2(from observation) | ||
| 148 | break; | ||
| 149 | default:; | ||
| 150 | } | ||
| 151 | } | ||
| 152 | #endif | ||
diff --git a/platforms/avr/timer.c b/platforms/avr/timer.c new file mode 100644 index 000000000..c2e6c6e08 --- /dev/null +++ b/platforms/avr/timer.c | |||
| @@ -0,0 +1,133 @@ | |||
| 1 | /* | ||
| 2 | Copyright 2011 Jun Wako <wakojun@gmail.com> | ||
| 3 | |||
| 4 | This program is free software: you can redistribute it and/or modify | ||
| 5 | it under the terms of the GNU General Public License as published by | ||
| 6 | the Free Software Foundation, either version 2 of the License, or | ||
| 7 | (at your option) any later version. | ||
| 8 | |||
| 9 | This program is distributed in the hope that it will be useful, | ||
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | GNU General Public License for more details. | ||
| 13 | |||
| 14 | You should have received a copy of the GNU General Public License | ||
| 15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #include <avr/io.h> | ||
| 19 | #include <avr/interrupt.h> | ||
| 20 | #include <util/atomic.h> | ||
| 21 | #include <stdint.h> | ||
| 22 | #include "timer_avr.h" | ||
| 23 | #include "timer.h" | ||
| 24 | |||
| 25 | // counter resolution 1ms | ||
| 26 | // NOTE: union { uint32_t timer32; struct { uint16_t dummy; uint16_t timer16; }} | ||
| 27 | volatile uint32_t timer_count; | ||
| 28 | |||
| 29 | /** \brief timer initialization | ||
| 30 | * | ||
| 31 | * FIXME: needs doc | ||
| 32 | */ | ||
| 33 | void timer_init(void) { | ||
| 34 | #if TIMER_PRESCALER == 1 | ||
| 35 | uint8_t prescaler = _BV(CS00); | ||
| 36 | #elif TIMER_PRESCALER == 8 | ||
| 37 | uint8_t prescaler = _BV(CS01); | ||
| 38 | #elif TIMER_PRESCALER == 64 | ||
| 39 | uint8_t prescaler = _BV(CS00) | _BV(CS01); | ||
| 40 | #elif TIMER_PRESCALER == 256 | ||
| 41 | uint8_t prescaler = _BV(CS02); | ||
| 42 | #elif TIMER_PRESCALER == 1024 | ||
| 43 | uint8_t prescaler = _BV(CS00) | _BV(CS02); | ||
| 44 | #else | ||
| 45 | # error "Timer prescaler value is not valid" | ||
| 46 | #endif | ||
| 47 | |||
| 48 | #if defined(__AVR_ATmega32A__) | ||
| 49 | // Timer0 CTC mode | ||
| 50 | TCCR0 = _BV(WGM01) | prescaler; | ||
| 51 | |||
| 52 | OCR0 = TIMER_RAW_TOP; | ||
| 53 | TIMSK = _BV(OCIE0); | ||
| 54 | #elif defined(__AVR_ATtiny85__) | ||
| 55 | // Timer0 CTC mode | ||
| 56 | TCCR0A = _BV(WGM01); | ||
| 57 | TCCR0B = prescaler; | ||
| 58 | |||
| 59 | OCR0A = TIMER_RAW_TOP; | ||
| 60 | TIMSK = _BV(OCIE0A); | ||
| 61 | #else | ||
| 62 | // Timer0 CTC mode | ||
| 63 | TCCR0A = _BV(WGM01); | ||
| 64 | TCCR0B = prescaler; | ||
| 65 | |||
| 66 | OCR0A = TIMER_RAW_TOP; | ||
| 67 | TIMSK0 = _BV(OCIE0A); | ||
| 68 | #endif | ||
| 69 | } | ||
| 70 | |||
| 71 | /** \brief timer clear | ||
| 72 | * | ||
| 73 | * FIXME: needs doc | ||
| 74 | */ | ||
| 75 | inline void timer_clear(void) { | ||
| 76 | ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { timer_count = 0; } | ||
| 77 | } | ||
| 78 | |||
| 79 | /** \brief timer read | ||
| 80 | * | ||
| 81 | * FIXME: needs doc | ||
| 82 | */ | ||
| 83 | inline uint16_t timer_read(void) { | ||
| 84 | uint32_t t; | ||
| 85 | |||
| 86 | ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { t = timer_count; } | ||
| 87 | |||
| 88 | return (t & 0xFFFF); | ||
| 89 | } | ||
| 90 | |||
| 91 | /** \brief timer read32 | ||
| 92 | * | ||
| 93 | * FIXME: needs doc | ||
| 94 | */ | ||
| 95 | inline uint32_t timer_read32(void) { | ||
| 96 | uint32_t t; | ||
| 97 | |||
| 98 | ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { t = timer_count; } | ||
| 99 | |||
| 100 | return t; | ||
| 101 | } | ||
| 102 | |||
| 103 | /** \brief timer elapsed | ||
| 104 | * | ||
| 105 | * FIXME: needs doc | ||
| 106 | */ | ||
| 107 | inline uint16_t timer_elapsed(uint16_t last) { | ||
| 108 | uint32_t t; | ||
| 109 | |||
| 110 | ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { t = timer_count; } | ||
| 111 | |||
| 112 | return TIMER_DIFF_16((t & 0xFFFF), last); | ||
| 113 | } | ||
| 114 | |||
| 115 | /** \brief timer elapsed32 | ||
| 116 | * | ||
| 117 | * FIXME: needs doc | ||
| 118 | */ | ||
| 119 | inline uint32_t timer_elapsed32(uint32_t last) { | ||
| 120 | uint32_t t; | ||
| 121 | |||
| 122 | ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { t = timer_count; } | ||
| 123 | |||
| 124 | return TIMER_DIFF_32(t, last); | ||
| 125 | } | ||
| 126 | |||
| 127 | // excecuted once per 1ms.(excess for just timer count?) | ||
| 128 | #ifndef __AVR_ATmega32A__ | ||
| 129 | # define TIMER_INTERRUPT_VECTOR TIMER0_COMPA_vect | ||
| 130 | #else | ||
| 131 | # define TIMER_INTERRUPT_VECTOR TIMER0_COMP_vect | ||
| 132 | #endif | ||
| 133 | ISR(TIMER_INTERRUPT_VECTOR, ISR_NOBLOCK) { timer_count++; } | ||
diff --git a/platforms/avr/timer_avr.h b/platforms/avr/timer_avr.h new file mode 100644 index 000000000..c1b726bd0 --- /dev/null +++ b/platforms/avr/timer_avr.h | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | /* | ||
| 2 | Copyright 2011 Jun Wako <wakojun@gmail.com> | ||
| 3 | |||
| 4 | This program is free software: you can redistribute it and/or modify | ||
| 5 | it under the terms of the GNU General Public License as published by | ||
| 6 | the Free Software Foundation, either version 2 of the License, or | ||
| 7 | (at your option) any later version. | ||
| 8 | |||
| 9 | This program is distributed in the hope that it will be useful, | ||
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | GNU General Public License for more details. | ||
| 13 | |||
| 14 | You should have received a copy of the GNU General Public License | ||
| 15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #pragma once | ||
| 19 | |||
| 20 | #include <stdint.h> | ||
| 21 | |||
| 22 | #ifndef TIMER_PRESCALER | ||
| 23 | # if F_CPU > 16000000 | ||
| 24 | # define TIMER_PRESCALER 256 | ||
| 25 | # elif F_CPU > 2000000 | ||
| 26 | # define TIMER_PRESCALER 64 | ||
| 27 | # elif F_CPU > 250000 | ||
| 28 | # define TIMER_PRESCALER 8 | ||
| 29 | # else | ||
| 30 | # define TIMER_PRESCALER 1 | ||
| 31 | # endif | ||
| 32 | #endif | ||
| 33 | #define TIMER_RAW_FREQ (F_CPU / TIMER_PRESCALER) | ||
| 34 | #define TIMER_RAW TCNT0 | ||
| 35 | #define TIMER_RAW_TOP (TIMER_RAW_FREQ / 1000) | ||
| 36 | |||
| 37 | #if (TIMER_RAW_TOP > 255) | ||
| 38 | # error "Timer0 can't count 1ms at this clock freq. Use larger prescaler." | ||
| 39 | #endif | ||
diff --git a/platforms/avr/xprintf.S b/platforms/avr/xprintf.S new file mode 100644 index 000000000..c5a414c35 --- /dev/null +++ b/platforms/avr/xprintf.S | |||
| @@ -0,0 +1,498 @@ | |||
| 1 | ;---------------------------------------------------------------------------; | ||
| 2 | ; Extended itoa, puts, printf and atoi (C)ChaN, 2011 | ||
| 3 | ;---------------------------------------------------------------------------; | ||
| 4 | |||
| 5 | // Base size is 152 bytes | ||
| 6 | #define CR_CRLF 0 // Convert \n to \r\n (+10 bytes) | ||
| 7 | #define USE_XPRINTF 1 // Enable xprintf function (+194 bytes) | ||
| 8 | #define USE_XSPRINTF 0 // Add xsprintf function (+78 bytes) | ||
| 9 | #define USE_XFPRINTF 0 // Add xfprintf function (+54 bytes) | ||
| 10 | #define USE_XATOI 0 // Enable xatoi function (+182 bytes) | ||
| 11 | |||
| 12 | |||
| 13 | #if FLASHEND > 0x1FFFF | ||
| 14 | #error xitoa module does not support 256K devices | ||
| 15 | #endif | ||
| 16 | |||
| 17 | .nolist | ||
| 18 | #include <avr/io.h> // Include device specific definitions. | ||
| 19 | .list | ||
| 20 | |||
| 21 | #ifdef SPM_PAGESIZE // Recent devices have "lpm Rd,Z+" and "movw". | ||
| 22 | .macro _LPMI reg | ||
| 23 | lpm \reg, Z+ | ||
| 24 | .endm | ||
| 25 | .macro _MOVW dh,dl, sh,sl | ||
| 26 | movw \dl, \sl | ||
| 27 | .endm | ||
| 28 | #else // Earlier devices do not have "lpm Rd,Z+" nor "movw". | ||
| 29 | .macro _LPMI reg | ||
| 30 | lpm | ||
| 31 | mov \reg, r0 | ||
| 32 | adiw ZL, 1 | ||
| 33 | .endm | ||
| 34 | .macro _MOVW dh,dl, sh,sl | ||
| 35 | mov \dl, \sl | ||
| 36 | mov \dh, \sh | ||
| 37 | .endm | ||
| 38 | #endif | ||
| 39 | |||
| 40 | |||
| 41 | |||
| 42 | ;--------------------------------------------------------------------------- | ||
| 43 | ; Stub function to forward to user output function | ||
| 44 | ; | ||
| 45 | ;Prototype: void xputc (char chr // a character to be output | ||
| 46 | ; ); | ||
| 47 | ;Size: 12/12 words | ||
| 48 | |||
| 49 | .section .bss | ||
| 50 | .global xfunc_out ; xfunc_out must be initialized before using this module. | ||
| 51 | xfunc_out: .ds.w 1 | ||
| 52 | .section .text | ||
| 53 | |||
| 54 | |||
| 55 | .func xputc | ||
| 56 | .global xputc | ||
| 57 | xputc: | ||
| 58 | #if CR_CRLF | ||
| 59 | cpi r24, 10 ;LF --> CRLF | ||
| 60 | brne 1f ; | ||
| 61 | ldi r24, 13 ; | ||
| 62 | rcall 1f ; | ||
| 63 | ldi r24, 10 ;/ | ||
| 64 | 1: | ||
| 65 | #endif | ||
| 66 | push ZH | ||
| 67 | push ZL | ||
| 68 | lds ZL, xfunc_out+0 ;Pointer to the registered output function. | ||
| 69 | lds ZH, xfunc_out+1 ;/ | ||
| 70 | sbiw ZL, 0 ;Skip if null | ||
| 71 | breq 2f ;/ | ||
| 72 | icall | ||
| 73 | 2: pop ZL | ||
| 74 | pop ZH | ||
| 75 | ret | ||
| 76 | .endfunc | ||
| 77 | |||
| 78 | |||
| 79 | |||
| 80 | ;--------------------------------------------------------------------------- | ||
| 81 | ; Direct ROM string output | ||
| 82 | ; | ||
| 83 | ;Prototype: void xputs (const char *str_p // rom string to be output | ||
| 84 | ; ); | ||
| 85 | |||
| 86 | .func xputs | ||
| 87 | .global xputs | ||
| 88 | xputs: | ||
| 89 | _MOVW ZH,ZL, r25,r24 ; Z = pointer to rom string | ||
| 90 | 1: _LPMI r24 | ||
| 91 | cpi r24, 0 | ||
| 92 | breq 2f | ||
| 93 | rcall xputc | ||
| 94 | rjmp 1b | ||
| 95 | 2: ret | ||
| 96 | .endfunc | ||
| 97 | |||
| 98 | |||
| 99 | ;--------------------------------------------------------------------------- | ||
| 100 | ; Extended direct numeral string output (32bit version) | ||
| 101 | ; | ||
| 102 | ;Prototype: void xitoa (long value, // value to be output | ||
| 103 | ; char radix, // radix | ||
| 104 | ; char width); // minimum width | ||
| 105 | ; | ||
| 106 | |||
| 107 | .func xitoa | ||
| 108 | .global xitoa | ||
| 109 | xitoa: | ||
| 110 | ;r25:r22 = value, r20 = base, r18 = digits | ||
| 111 | clr r31 ;r31 = stack level | ||
| 112 | ldi r30, ' ' ;r30 = sign | ||
| 113 | ldi r19, ' ' ;r19 = filler | ||
| 114 | sbrs r20, 7 ;When base indicates signd format and the value | ||
| 115 | rjmp 0f ;is minus, add a '-'. | ||
| 116 | neg r20 ; | ||
| 117 | sbrs r25, 7 ; | ||
| 118 | rjmp 0f ; | ||
| 119 | ldi r30, '-' ; | ||
| 120 | com r22 ; | ||
| 121 | com r23 ; | ||
| 122 | com r24 ; | ||
| 123 | com r25 ; | ||
| 124 | adc r22, r1 ; | ||
| 125 | adc r23, r1 ; | ||
| 126 | adc r24, r1 ; | ||
| 127 | adc r25, r1 ;/ | ||
| 128 | 0: sbrs r18, 7 ;When digits indicates zero filled, | ||
| 129 | rjmp 1f ;filler is '0'. | ||
| 130 | neg r18 ; | ||
| 131 | ldi r19, '0' ;/ | ||
| 132 | ;----- string conversion loop | ||
| 133 | 1: ldi r21, 32 ;r26 = r25:r22 % r20 | ||
| 134 | clr r26 ;r25:r22 /= r20 | ||
| 135 | 2: lsl r22 ; | ||
| 136 | rol r23 ; | ||
| 137 | rol r24 ; | ||
| 138 | rol r25 ; | ||
| 139 | rol r26 ; | ||
| 140 | cp r26, r20 ; | ||
| 141 | brcs 3f ; | ||
| 142 | sub r26, r20 ; | ||
| 143 | inc r22 ; | ||
| 144 | 3: dec r21 ; | ||
| 145 | brne 2b ;/ | ||
| 146 | cpi r26, 10 ;r26 is a numeral digit '0'-'F' | ||
| 147 | brcs 4f ; | ||
| 148 | subi r26, -7 ; | ||
| 149 | 4: subi r26, -'0' ;/ | ||
| 150 | push r26 ;Stack it | ||
| 151 | inc r31 ;/ | ||
| 152 | cp r22, r1 ;Repeat until r25:r22 gets zero | ||
| 153 | cpc r23, r1 ; | ||
| 154 | cpc r24, r1 ; | ||
| 155 | cpc r25, r1 ; | ||
| 156 | brne 1b ;/ | ||
| 157 | |||
| 158 | cpi r30, '-' ;Minus sign if needed | ||
| 159 | brne 5f ; | ||
| 160 | push r30 ; | ||
| 161 | inc r31 ;/ | ||
| 162 | 5: cp r31, r18 ;Filler | ||
| 163 | brcc 6f ; | ||
| 164 | push r19 ; | ||
| 165 | inc r31 ; | ||
| 166 | rjmp 5b ;/ | ||
| 167 | |||
| 168 | 6: pop r24 ;Flush stacked digits and exit | ||
| 169 | rcall xputc ; | ||
| 170 | dec r31 ; | ||
| 171 | brne 6b ;/ | ||
| 172 | |||
| 173 | ret | ||
| 174 | .endfunc | ||
| 175 | |||
| 176 | |||
| 177 | |||
| 178 | ;---------------------------------------------------------------------------; | ||
| 179 | ; Formatted string output (16/32bit version) | ||
| 180 | ; | ||
| 181 | ;Prototype: | ||
| 182 | ; void __xprintf (const char *format_p, ...); | ||
| 183 | ; void __xsprintf(char*, const char *format_p, ...); | ||
| 184 | ; void __xfprintf(void(*func)(char), const char *format_p, ...); | ||
| 185 | ; | ||
| 186 | |||
| 187 | #if USE_XPRINTF | ||
| 188 | |||
| 189 | .func xvprintf | ||
| 190 | xvprintf: | ||
| 191 | ld ZL, Y+ ;Z = pointer to format string | ||
| 192 | ld ZH, Y+ ;/ | ||
| 193 | |||
| 194 | 0: _LPMI r24 ;Get a format char | ||
| 195 | cpi r24, 0 ;End of format string? | ||
| 196 | breq 90f ;/ | ||
| 197 | cpi r24, '%' ;Is format? | ||
| 198 | breq 20f ;/ | ||
| 199 | 1: rcall xputc ;Put a normal character | ||
| 200 | rjmp 0b ;/ | ||
| 201 | 90: ret | ||
| 202 | |||
| 203 | 20: ldi r18, 0 ;r18: digits | ||
| 204 | clt ;T: filler | ||
| 205 | _LPMI r21 ;Get flags | ||
| 206 | cpi r21, '%' ;Is a %? | ||
| 207 | breq 1b ;/ | ||
| 208 | cpi r21, '0' ;Zero filled? | ||
| 209 | brne 23f ; | ||
| 210 | set ;/ | ||
| 211 | 22: _LPMI r21 ;Get width | ||
| 212 | 23: cpi r21, '9'+1 ; | ||
| 213 | brcc 24f ; | ||
| 214 | subi r21, '0' ; | ||
| 215 | brcs 90b ; | ||
| 216 | lsl r18 ; | ||
| 217 | mov r0, r18 ; | ||
| 218 | lsl r18 ; | ||
| 219 | lsl r18 ; | ||
| 220 | add r18, r0 ; | ||
| 221 | add r18, r21 ; | ||
| 222 | rjmp 22b ;/ | ||
| 223 | |||
| 224 | 24: brtc 25f ;get value (low word) | ||
| 225 | neg r18 ; | ||
| 226 | 25: ld r24, Y+ ; | ||
| 227 | ld r25, Y+ ;/ | ||
| 228 | cpi r21, 'c' ;Is type character? | ||
| 229 | breq 1b ;/ | ||
| 230 | cpi r21, 's' ;Is type RAM string? | ||
| 231 | breq 50f ;/ | ||
| 232 | cpi r21, 'S' ;Is type ROM string? | ||
| 233 | breq 60f ;/ | ||
| 234 | _MOVW r23,r22,r25,r24 ;r25:r22 = value | ||
| 235 | clr r24 ; | ||
| 236 | clr r25 ; | ||
| 237 | clt ;/ | ||
| 238 | cpi r21, 'l' ;Is long int? | ||
| 239 | brne 26f ; | ||
| 240 | ld r24, Y+ ;get value (high word) | ||
| 241 | ld r25, Y+ ; | ||
| 242 | set ; | ||
| 243 | _LPMI r21 ;/ | ||
| 244 | 26: cpi r21, 'd' ;Is type signed decimal? | ||
| 245 | brne 27f ;/ | ||
| 246 | ldi r20, -10 ; | ||
| 247 | brts 40f ; | ||
| 248 | sbrs r23, 7 ; | ||
| 249 | rjmp 40f ; | ||
| 250 | ldi r24, -1 ; | ||
| 251 | ldi r25, -1 ; | ||
| 252 | rjmp 40f ;/ | ||
| 253 | 27: cpi r21, 'u' ;Is type unsigned decimal? | ||
| 254 | ldi r20, 10 ; | ||
| 255 | breq 40f ;/ | ||
| 256 | cpi r21, 'X' ;Is type hexdecimal? | ||
| 257 | ldi r20, 16 ; | ||
| 258 | breq 40f ;/ | ||
| 259 | cpi r21, 'b' ;Is type binary? | ||
| 260 | ldi r20, 2 ; | ||
| 261 | breq 40f ;/ | ||
| 262 | ret ;abort | ||
| 263 | 40: push ZH ;Output the value | ||
| 264 | push ZL ; | ||
| 265 | rcall xitoa ; | ||
| 266 | 42: pop ZL ; | ||
| 267 | pop ZH ; | ||
| 268 | rjmp 0b ;/ | ||
| 269 | |||
| 270 | 50: push ZH ;Put a string on the RAM | ||
| 271 | push ZL | ||
| 272 | _MOVW ZH,ZL, r25,r24 | ||
| 273 | 51: ld r24, Z+ | ||
| 274 | cpi r24, 0 | ||
| 275 | breq 42b | ||
| 276 | rcall xputc | ||
| 277 | rjmp 51b | ||
| 278 | |||
| 279 | 60: push ZH ;Put a string on the ROM | ||
| 280 | push ZL | ||
| 281 | rcall xputs | ||
| 282 | rjmp 42b | ||
| 283 | .endfunc | ||
| 284 | |||
| 285 | |||
| 286 | .func __xprintf | ||
| 287 | .global __xprintf | ||
| 288 | __xprintf: | ||
| 289 | push YH | ||
| 290 | push YL | ||
| 291 | in YL, _SFR_IO_ADDR(SPL) | ||
| 292 | #ifdef SPH | ||
| 293 | in YH, _SFR_IO_ADDR(SPH) | ||
| 294 | #else | ||
| 295 | clr YH | ||
| 296 | #endif | ||
| 297 | adiw YL, 5 ;Y = pointer to arguments | ||
| 298 | rcall xvprintf | ||
| 299 | pop YL | ||
| 300 | pop YH | ||
| 301 | ret | ||
| 302 | .endfunc | ||
| 303 | |||
| 304 | |||
| 305 | #if USE_XSPRINTF | ||
| 306 | |||
| 307 | .func __xsprintf | ||
| 308 | putram: | ||
| 309 | _MOVW ZH,ZL, r15,r14 | ||
| 310 | st Z+, r24 | ||
| 311 | _MOVW r15,r14, ZH,ZL | ||
| 312 | ret | ||
| 313 | .global __xsprintf | ||
| 314 | __xsprintf: | ||
| 315 | push YH | ||
| 316 | push YL | ||
| 317 | in YL, _SFR_IO_ADDR(SPL) | ||
| 318 | #ifdef SPH | ||
| 319 | in YH, _SFR_IO_ADDR(SPH) | ||
| 320 | #else | ||
| 321 | clr YH | ||
| 322 | #endif | ||
| 323 | adiw YL, 5 ;Y = pointer to arguments | ||
| 324 | lds ZL, xfunc_out+0 ;Save registered output function | ||
| 325 | lds ZH, xfunc_out+1 ; | ||
| 326 | push ZL ; | ||
| 327 | push ZH ;/ | ||
| 328 | ldi ZL, lo8(pm(putram));Set local output function | ||
| 329 | ldi ZH, hi8(pm(putram)); | ||
| 330 | sts xfunc_out+0, ZL ; | ||
| 331 | sts xfunc_out+1, ZH ;/ | ||
| 332 | push r15 ;Initialize pointer to string buffer | ||
| 333 | push r14 ; | ||
| 334 | ld r14, Y+ ; | ||
| 335 | ld r15, Y+ ;/ | ||
| 336 | rcall xvprintf | ||
| 337 | _MOVW ZH,ZL, r15,r14 ;Terminate string | ||
| 338 | st Z, r1 ; | ||
| 339 | pop r14 ; | ||
| 340 | pop r15 ;/ | ||
| 341 | pop ZH ;Restore registered output function | ||
| 342 | pop ZL ; | ||
| 343 | sts xfunc_out+0, ZL ; | ||
| 344 | sts xfunc_out+1, ZH ;/ | ||
| 345 | pop YL | ||
| 346 | pop YH | ||
| 347 | ret | ||
| 348 | .endfunc | ||
| 349 | #endif | ||
| 350 | |||
| 351 | |||
| 352 | #if USE_XFPRINTF | ||
| 353 | .func __xfprintf | ||
| 354 | .global __xfprintf | ||
| 355 | __xfprintf: | ||
| 356 | push YH | ||
| 357 | push YL | ||
| 358 | in YL, _SFR_IO_ADDR(SPL) | ||
| 359 | #ifdef SPH | ||
| 360 | in YH, _SFR_IO_ADDR(SPH) | ||
| 361 | #else | ||
| 362 | clr YH | ||
| 363 | #endif | ||
| 364 | adiw YL, 5 ;Y = pointer to arguments | ||
| 365 | lds ZL, xfunc_out+0 ;Save registered output function | ||
| 366 | lds ZH, xfunc_out+1 ; | ||
| 367 | push ZL ; | ||
| 368 | push ZH ;/ | ||
| 369 | ld ZL, Y+ ;Set output function | ||
| 370 | ld ZH, Y+ ; | ||
| 371 | sts xfunc_out+0, ZL ; | ||
| 372 | sts xfunc_out+1, ZH ;/ | ||
| 373 | rcall xvprintf | ||
| 374 | pop ZH ;Restore registered output function | ||
| 375 | pop ZL ; | ||
| 376 | sts xfunc_out+0, ZL ; | ||
| 377 | sts xfunc_out+1, ZH ;/ | ||
| 378 | pop YL | ||
| 379 | pop YH | ||
| 380 | ret | ||
| 381 | .endfunc | ||
| 382 | #endif | ||
| 383 | |||
| 384 | #endif | ||
| 385 | |||
| 386 | |||
| 387 | |||
| 388 | ;--------------------------------------------------------------------------- | ||
| 389 | ; Extended numeral string input | ||
| 390 | ; | ||
| 391 | ;Prototype: | ||
| 392 | ; char xatoi ( /* 1: Successful, 0: Failed */ | ||
| 393 | ; const char **str, /* pointer to pointer to source string */ | ||
| 394 | ; long *res /* result */ | ||
| 395 | ; ); | ||
| 396 | ; | ||
| 397 | |||
| 398 | |||
| 399 | #if USE_XATOI | ||
| 400 | .func xatoi | ||
| 401 | .global xatoi | ||
| 402 | xatoi: | ||
| 403 | _MOVW r1, r0, r23, r22 | ||
| 404 | _MOVW XH, XL, r25, r24 | ||
| 405 | ld ZL, X+ | ||
| 406 | ld ZH, X+ | ||
| 407 | clr r18 ;r21:r18 = 0; | ||
| 408 | clr r19 ; | ||
| 409 | clr r20 ; | ||
| 410 | clr r21 ;/ | ||
| 411 | clt ;T = 0; | ||
| 412 | |||
| 413 | ldi r25, 10 ;r25 = 10; | ||
| 414 | rjmp 41f ;/ | ||
| 415 | 40: adiw ZL, 1 ;Z++; | ||
| 416 | 41: ld r22, Z ;r22 = *Z; | ||
| 417 | cpi r22, ' ' ;if(r22 == ' ') continue | ||
| 418 | breq 40b ;/ | ||
| 419 | brcs 70f ;if(r22 < ' ') error; | ||
| 420 | cpi r22, '-' ;if(r22 == '-') { | ||
| 421 | brne 42f ; T = 1; | ||
| 422 | set ; continue; | ||
| 423 | rjmp 40b ;} | ||
| 424 | 42: cpi r22, '9'+1 ;if(r22 > '9') error; | ||
| 425 | brcc 70f ;/ | ||
| 426 | cpi r22, '0' ;if(r22 < '0') error; | ||
| 427 | brcs 70f ;/ | ||
| 428 | brne 51f ;if(r22 > '0') cv_start; | ||
| 429 | ldi r25, 8 ;r25 = 8; | ||
| 430 | adiw ZL, 1 ;r22 = *(++Z); | ||
| 431 | ld r22, Z ;/ | ||
| 432 | cpi r22, ' '+1 ;if(r22 <= ' ') exit; | ||
| 433 | brcs 80f ;/ | ||
| 434 | cpi r22, 'b' ;if(r22 == 'b') { | ||
| 435 | brne 43f ; r25 = 2; | ||
| 436 | ldi r25, 2 ; cv_start; | ||
| 437 | rjmp 50f ;} | ||
| 438 | 43: cpi r22, 'x' ;if(r22 != 'x') error; | ||
| 439 | brne 51f ;/ | ||
| 440 | ldi r25, 16 ;r25 = 16; | ||
| 441 | |||
| 442 | 50: adiw ZL, 1 ;Z++; | ||
| 443 | ld r22, Z ;r22 = *Z; | ||
| 444 | 51: cpi r22, ' '+1 ;if(r22 <= ' ') break; | ||
| 445 | brcs 80f ;/ | ||
| 446 | cpi r22, 'a' ;if(r22 >= 'a') r22 =- 0x20; | ||
| 447 | brcs 52f ; | ||
| 448 | subi r22, 0x20 ;/ | ||
| 449 | 52: subi r22, '0' ;if((r22 -= '0') < 0) error; | ||
| 450 | brcs 70f ;/ | ||
| 451 | cpi r22, 10 ;if(r22 >= 10) { | ||
| 452 | brcs 53f ; r22 -= 7; | ||
| 453 | subi r22, 7 ; if(r22 < 10) | ||
| 454 | cpi r22, 10 ; | ||
| 455 | brcs 70f ;} | ||
| 456 | 53: cp r22, r25 ;if(r22 >= r25) error; | ||
| 457 | brcc 70f ;/ | ||
| 458 | 60: ldi r24, 33 ;r21:r18 *= r25; | ||
| 459 | sub r23, r23 ; | ||
| 460 | 61: brcc 62f ; | ||
| 461 | add r23, r25 ; | ||
| 462 | 62: lsr r23 ; | ||
| 463 | ror r21 ; | ||
| 464 | ror r20 ; | ||
| 465 | ror r19 ; | ||
| 466 | ror r18 ; | ||
| 467 | dec r24 ; | ||
| 468 | brne 61b ;/ | ||
| 469 | add r18, r22 ;r21:r18 += r22; | ||
| 470 | adc r19, r24 ; | ||
| 471 | adc r20, r24 ; | ||
| 472 | adc r21, r24 ;/ | ||
| 473 | rjmp 50b ;repeat | ||
| 474 | |||
| 475 | 70: ldi r24, 0 | ||
| 476 | rjmp 81f | ||
| 477 | 80: ldi r24, 1 | ||
| 478 | 81: brtc 82f | ||
| 479 | clr r22 | ||
| 480 | com r18 | ||
| 481 | com r19 | ||
| 482 | com r20 | ||
| 483 | com r21 | ||
| 484 | adc r18, r22 | ||
| 485 | adc r19, r22 | ||
| 486 | adc r20, r22 | ||
| 487 | adc r21, r22 | ||
| 488 | 82: st -X, ZH | ||
| 489 | st -X, ZL | ||
| 490 | _MOVW XH, XL, r1, r0 | ||
| 491 | st X+, r18 | ||
| 492 | st X+, r19 | ||
| 493 | st X+, r20 | ||
| 494 | st X+, r21 | ||
| 495 | clr r1 | ||
| 496 | ret | ||
| 497 | .endfunc | ||
| 498 | #endif | ||
diff --git a/platforms/avr/xprintf.h b/platforms/avr/xprintf.h new file mode 100644 index 000000000..80834f171 --- /dev/null +++ b/platforms/avr/xprintf.h | |||
| @@ -0,0 +1,103 @@ | |||
| 1 | /*--------------------------------------------------------------------------- | ||
| 2 | Extended itoa, puts and printf (C)ChaN, 2011 | ||
| 3 | -----------------------------------------------------------------------------*/ | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <inttypes.h> | ||
| 8 | #include <avr/pgmspace.h> | ||
| 9 | |||
| 10 | #ifdef __cplusplus | ||
| 11 | extern "C" { | ||
| 12 | #endif | ||
| 13 | |||
| 14 | extern void (*xfunc_out)(uint8_t); | ||
| 15 | #define xdev_out(func) xfunc_out = (void (*)(uint8_t))(func) | ||
| 16 | |||
| 17 | /* This is a pointer to user defined output function. It must be initialized | ||
| 18 | before using this modle. | ||
| 19 | */ | ||
| 20 | |||
| 21 | void xputc(char chr); | ||
| 22 | |||
| 23 | /* This is a stub function to forward outputs to user defined output function. | ||
| 24 | All outputs from this module are output via this function. | ||
| 25 | */ | ||
| 26 | |||
| 27 | /*-----------------------------------------------------------------------------*/ | ||
| 28 | void xputs(const char *string_p); | ||
| 29 | |||
| 30 | /* The string placed in the ROM is forwarded to xputc() directly. | ||
| 31 | */ | ||
| 32 | |||
| 33 | /*-----------------------------------------------------------------------------*/ | ||
| 34 | void xitoa(long value, char radix, char width); | ||
| 35 | |||
| 36 | /* Extended itoa(). | ||
| 37 | |||
| 38 | value radix width output | ||
| 39 | 100 10 6 " 100" | ||
| 40 | 100 10 -6 "000100" | ||
| 41 | 100 10 0 "100" | ||
| 42 | 4294967295 10 0 "4294967295" | ||
| 43 | 4294967295 -10 0 "-1" | ||
| 44 | 655360 16 -8 "000A0000" | ||
| 45 | 1024 16 0 "400" | ||
| 46 | 0x55 2 -8 "01010101" | ||
| 47 | */ | ||
| 48 | |||
| 49 | /*-----------------------------------------------------------------------------*/ | ||
| 50 | #define xprintf(format, ...) __xprintf(PSTR(format), ##__VA_ARGS__) | ||
| 51 | #define xsprintf(str, format, ...) __xsprintf(str, PSTR(format), ##__VA_ARGS__) | ||
| 52 | #define xfprintf(func, format, ...) __xfprintf(func, PSTR(format), ##__VA_ARGS__) | ||
| 53 | |||
| 54 | void __xprintf(const char *format_p, ...); /* Send formatted string to the registered device */ | ||
| 55 | // void __xsprintf(char*, const char *format_p, ...); /* Put formatted string to the memory */ | ||
| 56 | // void __xfprintf(void(*func)(uint8_t), const char *format_p, ...); /* Send formatted string to the specified device */ | ||
| 57 | |||
| 58 | /* Format string is placed in the ROM. The format flags is similar to printf(). | ||
| 59 | |||
| 60 | %[flag][width][size]type | ||
| 61 | |||
| 62 | flag | ||
| 63 | A '0' means filled with '0' when output is shorter than width. | ||
| 64 | ' ' is used in default. This is effective only numeral type. | ||
| 65 | width | ||
| 66 | Minimum width in decimal number. This is effective only numeral type. | ||
| 67 | Default width is zero. | ||
| 68 | size | ||
| 69 | A 'l' means the argument is long(32bit). Default is short(16bit). | ||
| 70 | This is effective only numeral type. | ||
| 71 | type | ||
| 72 | 'c' : Character, argument is the value | ||
| 73 | 's' : String placed on the RAM, argument is the pointer | ||
| 74 | 'S' : String placed on the ROM, argument is the pointer | ||
| 75 | 'd' : Signed decimal, argument is the value | ||
| 76 | 'u' : Unsigned decimal, argument is the value | ||
| 77 | 'X' : Hexdecimal, argument is the value | ||
| 78 | 'b' : Binary, argument is the value | ||
| 79 | '%' : '%' | ||
| 80 | |||
| 81 | */ | ||
| 82 | |||
| 83 | /*-----------------------------------------------------------------------------*/ | ||
| 84 | char xatoi(char **str, long *ret); | ||
| 85 | |||
| 86 | /* Get value of the numeral string. | ||
| 87 | |||
| 88 | str | ||
| 89 | Pointer to pointer to source string | ||
| 90 | |||
| 91 | "0b11001010" binary | ||
| 92 | "0377" octal | ||
| 93 | "0xff800" hexdecimal | ||
| 94 | "1250000" decimal | ||
| 95 | "-25000" decimal | ||
| 96 | |||
| 97 | ret | ||
| 98 | Pointer to return value | ||
| 99 | */ | ||
| 100 | |||
| 101 | #ifdef __cplusplus | ||
| 102 | } | ||
| 103 | #endif | ||
diff --git a/platforms/bootloader.h b/platforms/bootloader.h new file mode 100644 index 000000000..25ebd9528 --- /dev/null +++ b/platforms/bootloader.h | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | /* | ||
| 2 | Copyright 2011 Jun Wako <wakojun@gmail.com> | ||
| 3 | |||
| 4 | This program is free software: you can redistribute it and/or modify | ||
| 5 | it under the terms of the GNU General Public License as published by | ||
| 6 | the Free Software Foundation, either version 2 of the License, or | ||
| 7 | (at your option) any later version. | ||
| 8 | |||
| 9 | This program is distributed in the hope that it will be useful, | ||
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | GNU General Public License for more details. | ||
| 13 | |||
| 14 | You should have received a copy of the GNU General Public License | ||
| 15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #pragma once | ||
| 19 | |||
| 20 | /* give code for your bootloader to come up if needed */ | ||
| 21 | void bootloader_jump(void); | ||
diff --git a/platforms/chibios/_timer.h b/platforms/chibios/_timer.h new file mode 100644 index 000000000..77402b612 --- /dev/null +++ b/platforms/chibios/_timer.h | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | /* Copyright 2021 Simon Arlott | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 2 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #pragma once | ||
| 17 | |||
| 18 | // The platform is 32-bit, so prefer 32-bit timers to avoid overflow | ||
| 19 | #define FAST_TIMER_T_SIZE 32 | ||
diff --git a/platforms/chibios/_wait.c b/platforms/chibios/_wait.c new file mode 100644 index 000000000..1fbea2dd5 --- /dev/null +++ b/platforms/chibios/_wait.c | |||
| @@ -0,0 +1,89 @@ | |||
| 1 | /* Copyright 2021 QMK | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 3 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #ifndef __OPTIMIZE__ | ||
| 18 | # pragma message "Compiler optimizations disabled; wait_cpuclock() won't work as designed" | ||
| 19 | #endif | ||
| 20 | |||
| 21 | #define CLOCK_DELAY_NOP8 "nop\n\t nop\n\t nop\n\t nop\n\t nop\n\t nop\n\t nop\n\t nop\n\t" | ||
| 22 | |||
| 23 | __attribute__((always_inline)) static inline void wait_cpuclock(unsigned int n) { /* n: 1..135 */ | ||
| 24 | /* The argument n must be a constant expression. | ||
| 25 | * That way, compiler optimization will remove unnecessary code. */ | ||
| 26 | if (n < 1) { | ||
| 27 | return; | ||
| 28 | } | ||
| 29 | if (n > 8) { | ||
| 30 | unsigned int n8 = n / 8; | ||
| 31 | n = n - n8 * 8; | ||
| 32 | switch (n8) { | ||
| 33 | case 16: | ||
| 34 | asm volatile(CLOCK_DELAY_NOP8::: "memory"); | ||
| 35 | case 15: | ||
| 36 | asm volatile(CLOCK_DELAY_NOP8::: "memory"); | ||
| 37 | case 14: | ||
| 38 | asm volatile(CLOCK_DELAY_NOP8::: "memory"); | ||
| 39 | case 13: | ||
| 40 | asm volatile(CLOCK_DELAY_NOP8::: "memory"); | ||
| 41 | case 12: | ||
| 42 | asm volatile(CLOCK_DELAY_NOP8::: "memory"); | ||
| 43 | case 11: | ||
| 44 | asm volatile(CLOCK_DELAY_NOP8::: "memory"); | ||
| 45 | case 10: | ||
| 46 | asm volatile(CLOCK_DELAY_NOP8::: "memory"); | ||
| 47 | case 9: | ||
| 48 | asm volatile(CLOCK_DELAY_NOP8::: "memory"); | ||
| 49 | case 8: | ||
| 50 | asm volatile(CLOCK_DELAY_NOP8::: "memory"); | ||
| 51 | case 7: | ||
| 52 | asm volatile(CLOCK_DELAY_NOP8::: "memory"); | ||
| 53 | case 6: | ||
| 54 | asm volatile(CLOCK_DELAY_NOP8::: "memory"); | ||
| 55 | case 5: | ||
| 56 | asm volatile(CLOCK_DELAY_NOP8::: "memory"); | ||
| 57 | case 4: | ||
| 58 | asm volatile(CLOCK_DELAY_NOP8::: "memory"); | ||
| 59 | case 3: | ||
| 60 | asm volatile(CLOCK_DELAY_NOP8::: "memory"); | ||
| 61 | case 2: | ||
| 62 | asm volatile(CLOCK_DELAY_NOP8::: "memory"); | ||
| 63 | case 1: | ||
| 64 | asm volatile(CLOCK_DELAY_NOP8::: "memory"); | ||
| 65 | case 0: | ||
| 66 | break; | ||
| 67 | } | ||
| 68 | } | ||
| 69 | switch (n) { | ||
| 70 | case 8: | ||
| 71 | asm volatile("nop" ::: "memory"); | ||
| 72 | case 7: | ||
| 73 | asm volatile("nop" ::: "memory"); | ||
| 74 | case 6: | ||
| 75 | asm volatile("nop" ::: "memory"); | ||
| 76 | case 5: | ||
| 77 | asm volatile("nop" ::: "memory"); | ||
| 78 | case 4: | ||
| 79 | asm volatile("nop" ::: "memory"); | ||
| 80 | case 3: | ||
| 81 | asm volatile("nop" ::: "memory"); | ||
| 82 | case 2: | ||
| 83 | asm volatile("nop" ::: "memory"); | ||
| 84 | case 1: | ||
| 85 | asm volatile("nop" ::: "memory"); | ||
| 86 | case 0: | ||
| 87 | break; | ||
| 88 | } | ||
| 89 | } | ||
diff --git a/platforms/chibios/_wait.h b/platforms/chibios/_wait.h new file mode 100644 index 000000000..2f36c64a2 --- /dev/null +++ b/platforms/chibios/_wait.h | |||
| @@ -0,0 +1,60 @@ | |||
| 1 | /* Copyright 2021 QMK | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 3 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #pragma once | ||
| 17 | |||
| 18 | #include <ch.h> | ||
| 19 | #include <hal.h> | ||
| 20 | |||
| 21 | /* chThdSleepX of zero maps to infinite - so we map to a tiny delay to still yield */ | ||
| 22 | #define wait_ms(ms) \ | ||
| 23 | do { \ | ||
| 24 | if (ms != 0) { \ | ||
| 25 | chThdSleepMilliseconds(ms); \ | ||
| 26 | } else { \ | ||
| 27 | chThdSleepMicroseconds(1); \ | ||
| 28 | } \ | ||
| 29 | } while (0) | ||
| 30 | |||
| 31 | #ifdef WAIT_US_TIMER | ||
| 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/boards/BLACKPILL_STM32_F401/configs/mcuconf.h b/platforms/chibios/boards/BLACKPILL_STM32_F401/configs/mcuconf.h index ba6e934fe..a21fd7bd1 100644 --- a/platforms/chibios/boards/BLACKPILL_STM32_F401/configs/mcuconf.h +++ b/platforms/chibios/boards/BLACKPILL_STM32_F401/configs/mcuconf.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio | 2 | ChibiOS - Copyright (C) 2006..2020 Giovanni Di Sirio |
| 3 | 3 | ||
| 4 | Licensed under the Apache License, Version 2.0 (the "License"); | 4 | Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | you may not use this file except in compliance with the License. | 5 | you may not use this file except in compliance with the License. |
| @@ -32,11 +32,15 @@ | |||
| 32 | */ | 32 | */ |
| 33 | 33 | ||
| 34 | #define STM32F4xx_MCUCONF | 34 | #define STM32F4xx_MCUCONF |
| 35 | #define STM32F401_MCUCONF | ||
| 35 | 36 | ||
| 36 | /* | 37 | /* |
| 37 | * HAL driver system settings. | 38 | * HAL driver system settings. |
| 38 | */ | 39 | */ |
| 39 | #define STM32_NO_INIT FALSE | 40 | #define STM32_NO_INIT FALSE |
| 41 | #define STM32_PVD_ENABLE FALSE | ||
| 42 | #define STM32_PLS STM32_PLS_LEV0 | ||
| 43 | #define STM32_BKPRAM_ENABLE FALSE | ||
| 40 | #define STM32_HSI_ENABLED TRUE | 44 | #define STM32_HSI_ENABLED TRUE |
| 41 | #define STM32_LSI_ENABLED TRUE | 45 | #define STM32_LSI_ENABLED TRUE |
| 42 | #define STM32_HSE_ENABLED TRUE | 46 | #define STM32_HSE_ENABLED TRUE |
| @@ -44,13 +48,13 @@ | |||
| 44 | #define STM32_CLOCK48_REQUIRED TRUE | 48 | #define STM32_CLOCK48_REQUIRED TRUE |
| 45 | #define STM32_SW STM32_SW_PLL | 49 | #define STM32_SW STM32_SW_PLL |
| 46 | #define STM32_PLLSRC STM32_PLLSRC_HSE | 50 | #define STM32_PLLSRC STM32_PLLSRC_HSE |
| 47 | #define STM32_PLLM_VALUE 25 | 51 | #define STM32_PLLM_VALUE 25 |
| 48 | #define STM32_PLLN_VALUE 336 | 52 | #define STM32_PLLN_VALUE 336 |
| 49 | #define STM32_PLLP_VALUE 4 | 53 | #define STM32_PLLP_VALUE 4 |
| 50 | #define STM32_PLLQ_VALUE 7 | 54 | #define STM32_PLLQ_VALUE 7 |
| 51 | #define STM32_HPRE STM32_HPRE_DIV1 | 55 | #define STM32_HPRE STM32_HPRE_DIV1 |
| 52 | #define STM32_PPRE1 STM32_PPRE1_DIV4 | 56 | #define STM32_PPRE1 STM32_PPRE1_DIV4 |
| 53 | #define STM32_PPRE2 STM32_PPRE2_DIV2 | 57 | #define STM32_PPRE2 STM32_PPRE2_DIV2 |
| 54 | #define STM32_RTCSEL STM32_RTCSEL_LSI | 58 | #define STM32_RTCSEL STM32_RTCSEL_LSI |
| 55 | #define STM32_RTCPRE_VALUE 8 | 59 | #define STM32_RTCPRE_VALUE 8 |
| 56 | #define STM32_MCO1SEL STM32_MCO1SEL_HSI | 60 | #define STM32_MCO1SEL STM32_MCO1SEL_HSI |
| @@ -60,9 +64,6 @@ | |||
| 60 | #define STM32_I2SSRC STM32_I2SSRC_CKIN | 64 | #define STM32_I2SSRC STM32_I2SSRC_CKIN |
| 61 | #define STM32_PLLI2SN_VALUE 192 | 65 | #define STM32_PLLI2SN_VALUE 192 |
| 62 | #define STM32_PLLI2SR_VALUE 5 | 66 | #define STM32_PLLI2SR_VALUE 5 |
| 63 | #define STM32_PVD_ENABLE FALSE | ||
| 64 | #define STM32_PLS STM32_PLS_LEV0 | ||
| 65 | #define STM32_BKPRAM_ENABLE FALSE | ||
| 66 | 67 | ||
| 67 | /* | 68 | /* |
| 68 | * IRQ system settings. | 69 | * IRQ system settings. |
| @@ -82,6 +83,19 @@ | |||
| 82 | #define STM32_IRQ_EXTI21_PRIORITY 15 | 83 | #define STM32_IRQ_EXTI21_PRIORITY 15 |
| 83 | #define STM32_IRQ_EXTI22_PRIORITY 15 | 84 | #define STM32_IRQ_EXTI22_PRIORITY 15 |
| 84 | 85 | ||
| 86 | #define STM32_IRQ_TIM1_BRK_TIM9_PRIORITY 7 | ||
| 87 | #define STM32_IRQ_TIM1_UP_TIM10_PRIORITY 7 | ||
| 88 | #define STM32_IRQ_TIM1_TRGCO_TIM11_PRIORITY 7 | ||
| 89 | #define STM32_IRQ_TIM1_CC_PRIORITY 7 | ||
| 90 | #define STM32_IRQ_TIM2_PRIORITY 7 | ||
| 91 | #define STM32_IRQ_TIM3_PRIORITY 7 | ||
| 92 | #define STM32_IRQ_TIM4_PRIORITY 7 | ||
| 93 | #define STM32_IRQ_TIM5_PRIORITY 7 | ||
| 94 | |||
| 95 | #define STM32_IRQ_USART1_PRIORITY 12 | ||
| 96 | #define STM32_IRQ_USART2_PRIORITY 12 | ||
| 97 | #define STM32_IRQ_USART6_PRIORITY 12 | ||
| 98 | |||
| 85 | /* | 99 | /* |
| 86 | * ADC driver system settings. | 100 | * ADC driver system settings. |
| 87 | */ | 101 | */ |
| @@ -101,14 +115,8 @@ | |||
| 101 | #define STM32_GPT_USE_TIM4 FALSE | 115 | #define STM32_GPT_USE_TIM4 FALSE |
| 102 | #define STM32_GPT_USE_TIM5 FALSE | 116 | #define STM32_GPT_USE_TIM5 FALSE |
| 103 | #define STM32_GPT_USE_TIM9 FALSE | 117 | #define STM32_GPT_USE_TIM9 FALSE |
| 118 | #define STM32_GPT_USE_TIM10 FALSE | ||
| 104 | #define STM32_GPT_USE_TIM11 FALSE | 119 | #define STM32_GPT_USE_TIM11 FALSE |
| 105 | #define STM32_GPT_TIM1_IRQ_PRIORITY 7 | ||
| 106 | #define STM32_GPT_TIM2_IRQ_PRIORITY 7 | ||
| 107 | #define STM32_GPT_TIM3_IRQ_PRIORITY 7 | ||
| 108 | #define STM32_GPT_TIM4_IRQ_PRIORITY 7 | ||
| 109 | #define STM32_GPT_TIM5_IRQ_PRIORITY 7 | ||
| 110 | #define STM32_GPT_TIM9_IRQ_PRIORITY 7 | ||
| 111 | #define STM32_GPT_TIM11_IRQ_PRIORITY 7 | ||
| 112 | 120 | ||
| 113 | /* | 121 | /* |
| 114 | * I2C driver system settings. | 122 | * I2C driver system settings. |
| @@ -155,29 +163,20 @@ | |||
| 155 | #define STM32_ICU_USE_TIM4 FALSE | 163 | #define STM32_ICU_USE_TIM4 FALSE |
| 156 | #define STM32_ICU_USE_TIM5 FALSE | 164 | #define STM32_ICU_USE_TIM5 FALSE |
| 157 | #define STM32_ICU_USE_TIM9 FALSE | 165 | #define STM32_ICU_USE_TIM9 FALSE |
| 158 | #define STM32_ICU_TIM1_IRQ_PRIORITY 7 | 166 | #define STM32_ICU_USE_TIM10 FALSE |
| 159 | #define STM32_ICU_TIM2_IRQ_PRIORITY 7 | 167 | #define STM32_ICU_USE_TIM11 FALSE |
| 160 | #define STM32_ICU_TIM3_IRQ_PRIORITY 7 | ||
| 161 | #define STM32_ICU_TIM4_IRQ_PRIORITY 7 | ||
| 162 | #define STM32_ICU_TIM5_IRQ_PRIORITY 7 | ||
| 163 | #define STM32_ICU_TIM9_IRQ_PRIORITY 7 | ||
| 164 | 168 | ||
| 165 | /* | 169 | /* |
| 166 | * PWM driver system settings. | 170 | * PWM driver system settings. |
| 167 | */ | 171 | */ |
| 168 | #define STM32_PWM_USE_ADVANCED FALSE | ||
| 169 | #define STM32_PWM_USE_TIM1 FALSE | 172 | #define STM32_PWM_USE_TIM1 FALSE |
| 170 | #define STM32_PWM_USE_TIM2 FALSE | 173 | #define STM32_PWM_USE_TIM2 FALSE |
| 171 | #define STM32_PWM_USE_TIM3 FALSE | 174 | #define STM32_PWM_USE_TIM3 FALSE |
| 172 | #define STM32_PWM_USE_TIM4 FALSE | 175 | #define STM32_PWM_USE_TIM4 FALSE |
| 173 | #define STM32_PWM_USE_TIM5 FALSE | 176 | #define STM32_PWM_USE_TIM5 FALSE |
| 174 | #define STM32_PWM_USE_TIM9 FALSE | 177 | #define STM32_PWM_USE_TIM9 FALSE |
| 175 | #define STM32_PWM_TIM1_IRQ_PRIORITY 7 | 178 | #define STM32_PWM_USE_TIM10 FALSE |
| 176 | #define STM32_PWM_TIM2_IRQ_PRIORITY 7 | 179 | #define STM32_PWM_USE_TIM11 FALSE |
| 177 | #define STM32_PWM_TIM3_IRQ_PRIORITY 7 | ||
| 178 | #define STM32_PWM_TIM4_IRQ_PRIORITY 7 | ||
| 179 | #define STM32_PWM_TIM5_IRQ_PRIORITY 7 | ||
| 180 | #define STM32_PWM_TIM9_IRQ_PRIORITY 7 | ||
| 181 | 180 | ||
| 182 | /* | 181 | /* |
| 183 | * SERIAL driver system settings. | 182 | * SERIAL driver system settings. |
| @@ -185,9 +184,6 @@ | |||
| 185 | #define STM32_SERIAL_USE_USART1 FALSE | 184 | #define STM32_SERIAL_USE_USART1 FALSE |
| 186 | #define STM32_SERIAL_USE_USART2 FALSE | 185 | #define STM32_SERIAL_USE_USART2 FALSE |
| 187 | #define STM32_SERIAL_USE_USART6 FALSE | 186 | #define STM32_SERIAL_USE_USART6 FALSE |
| 188 | #define STM32_SERIAL_USART1_PRIORITY 12 | ||
| 189 | #define STM32_SERIAL_USART2_PRIORITY 12 | ||
| 190 | #define STM32_SERIAL_USART6_PRIORITY 12 | ||
| 191 | 187 | ||
| 192 | /* | 188 | /* |
| 193 | * SPI driver system settings. | 189 | * SPI driver system settings. |
| @@ -227,9 +223,6 @@ | |||
| 227 | #define STM32_UART_USART2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6) | 223 | #define STM32_UART_USART2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6) |
| 228 | #define STM32_UART_USART6_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 2) | 224 | #define STM32_UART_USART6_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 2) |
| 229 | #define STM32_UART_USART6_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 7) | 225 | #define STM32_UART_USART6_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 7) |
| 230 | #define STM32_UART_USART1_IRQ_PRIORITY 12 | ||
| 231 | #define STM32_UART_USART2_IRQ_PRIORITY 12 | ||
| 232 | #define STM32_UART_USART6_IRQ_PRIORITY 12 | ||
| 233 | #define STM32_UART_USART1_DMA_PRIORITY 0 | 226 | #define STM32_UART_USART1_DMA_PRIORITY 0 |
| 234 | #define STM32_UART_USART2_DMA_PRIORITY 0 | 227 | #define STM32_UART_USART2_DMA_PRIORITY 0 |
| 235 | #define STM32_UART_USART6_DMA_PRIORITY 0 | 228 | #define STM32_UART_USART6_DMA_PRIORITY 0 |
| @@ -241,9 +234,7 @@ | |||
| 241 | #define STM32_USB_USE_OTG1 TRUE | 234 | #define STM32_USB_USE_OTG1 TRUE |
| 242 | #define STM32_USB_OTG1_IRQ_PRIORITY 14 | 235 | #define STM32_USB_OTG1_IRQ_PRIORITY 14 |
| 243 | #define STM32_USB_OTG1_RX_FIFO_SIZE 512 | 236 | #define STM32_USB_OTG1_RX_FIFO_SIZE 512 |
| 244 | #define STM32_USB_OTG_THREAD_PRIO NORMALPRIO+1 | 237 | #define STM32_USB_HOST_WAKEUP_DURATION 2 |
| 245 | #define STM32_USB_OTG_THREAD_STACK_SIZE 128 | ||
| 246 | #define STM32_USB_OTGFIFO_FILL_BASEPRI 0 | ||
| 247 | 238 | ||
| 248 | /* | 239 | /* |
| 249 | * WDG driver system settings. | 240 | * WDG driver system settings. |
diff --git a/platforms/chibios/boards/BLACKPILL_STM32_F411/configs/mcuconf.h b/platforms/chibios/boards/BLACKPILL_STM32_F411/configs/mcuconf.h index 0394ff56b..131c84766 100644 --- a/platforms/chibios/boards/BLACKPILL_STM32_F411/configs/mcuconf.h +++ b/platforms/chibios/boards/BLACKPILL_STM32_F411/configs/mcuconf.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio | 2 | ChibiOS - Copyright (C) 2006..2020 Giovanni Di Sirio |
| 3 | 3 | ||
| 4 | Licensed under the Apache License, Version 2.0 (the "License"); | 4 | Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | you may not use this file except in compliance with the License. | 5 | you may not use this file except in compliance with the License. |
| @@ -32,11 +32,15 @@ | |||
| 32 | */ | 32 | */ |
| 33 | 33 | ||
| 34 | #define STM32F4xx_MCUCONF | 34 | #define STM32F4xx_MCUCONF |
| 35 | #define STM32F411_MCUCONF | ||
| 35 | 36 | ||
| 36 | /* | 37 | /* |
| 37 | * HAL driver system settings. | 38 | * HAL driver system settings. |
| 38 | */ | 39 | */ |
| 39 | #define STM32_NO_INIT FALSE | 40 | #define STM32_NO_INIT FALSE |
| 41 | #define STM32_PVD_ENABLE FALSE | ||
| 42 | #define STM32_PLS STM32_PLS_LEV0 | ||
| 43 | #define STM32_BKPRAM_ENABLE FALSE | ||
| 40 | #define STM32_HSI_ENABLED TRUE | 44 | #define STM32_HSI_ENABLED TRUE |
| 41 | #define STM32_LSI_ENABLED TRUE | 45 | #define STM32_LSI_ENABLED TRUE |
| 42 | #define STM32_HSE_ENABLED TRUE | 46 | #define STM32_HSE_ENABLED TRUE |
| @@ -60,9 +64,6 @@ | |||
| 60 | #define STM32_I2SSRC STM32_I2SSRC_CKIN | 64 | #define STM32_I2SSRC STM32_I2SSRC_CKIN |
| 61 | #define STM32_PLLI2SN_VALUE 192 | 65 | #define STM32_PLLI2SN_VALUE 192 |
| 62 | #define STM32_PLLI2SR_VALUE 5 | 66 | #define STM32_PLLI2SR_VALUE 5 |
| 63 | #define STM32_PVD_ENABLE FALSE | ||
| 64 | #define STM32_PLS STM32_PLS_LEV0 | ||
| 65 | #define STM32_BKPRAM_ENABLE FALSE | ||
| 66 | 67 | ||
| 67 | /* | 68 | /* |
| 68 | * IRQ system settings. | 69 | * IRQ system settings. |
| @@ -82,6 +83,19 @@ | |||
| 82 | #define STM32_IRQ_EXTI21_PRIORITY 15 | 83 | #define STM32_IRQ_EXTI21_PRIORITY 15 |
| 83 | #define STM32_IRQ_EXTI22_PRIORITY 15 | 84 | #define STM32_IRQ_EXTI22_PRIORITY 15 |
| 84 | 85 | ||
| 86 | #define STM32_IRQ_TIM1_BRK_TIM9_PRIORITY 7 | ||
| 87 | #define STM32_IRQ_TIM1_UP_TIM10_PRIORITY 7 | ||
| 88 | #define STM32_IRQ_TIM1_TRGCO_TIM11_PRIORITY 7 | ||
| 89 | #define STM32_IRQ_TIM1_CC_PRIORITY 7 | ||
| 90 | #define STM32_IRQ_TIM2_PRIORITY 7 | ||
| 91 | #define STM32_IRQ_TIM3_PRIORITY 7 | ||
| 92 | #define STM32_IRQ_TIM4_PRIORITY 7 | ||
| 93 | #define STM32_IRQ_TIM5_PRIORITY 7 | ||
| 94 | |||
| 95 | #define STM32_IRQ_USART1_PRIORITY 12 | ||
| 96 | #define STM32_IRQ_USART2_PRIORITY 12 | ||
| 97 | #define STM32_IRQ_USART6_PRIORITY 12 | ||
| 98 | |||
| 85 | /* | 99 | /* |
| 86 | * ADC driver system settings. | 100 | * ADC driver system settings. |
| 87 | */ | 101 | */ |
| @@ -101,14 +115,8 @@ | |||
| 101 | #define STM32_GPT_USE_TIM4 FALSE | 115 | #define STM32_GPT_USE_TIM4 FALSE |
| 102 | #define STM32_GPT_USE_TIM5 FALSE | 116 | #define STM32_GPT_USE_TIM5 FALSE |
| 103 | #define STM32_GPT_USE_TIM9 FALSE | 117 | #define STM32_GPT_USE_TIM9 FALSE |
| 118 | #define STM32_GPT_USE_TIM10 FALSE | ||
| 104 | #define STM32_GPT_USE_TIM11 FALSE | 119 | #define STM32_GPT_USE_TIM11 FALSE |
| 105 | #define STM32_GPT_TIM1_IRQ_PRIORITY 7 | ||
| 106 | #define STM32_GPT_TIM2_IRQ_PRIORITY 7 | ||
| 107 | #define STM32_GPT_TIM3_IRQ_PRIORITY 7 | ||
| 108 | #define STM32_GPT_TIM4_IRQ_PRIORITY 7 | ||
| 109 | #define STM32_GPT_TIM5_IRQ_PRIORITY 7 | ||
| 110 | #define STM32_GPT_TIM9_IRQ_PRIORITY 7 | ||
| 111 | #define STM32_GPT_TIM11_IRQ_PRIORITY 7 | ||
| 112 | 120 | ||
| 113 | /* | 121 | /* |
| 114 | * I2C driver system settings. | 122 | * I2C driver system settings. |
| @@ -155,29 +163,28 @@ | |||
| 155 | #define STM32_ICU_USE_TIM4 FALSE | 163 | #define STM32_ICU_USE_TIM4 FALSE |
| 156 | #define STM32_ICU_USE_TIM5 FALSE | 164 | #define STM32_ICU_USE_TIM5 FALSE |
| 157 | #define STM32_ICU_USE_TIM9 FALSE | 165 | #define STM32_ICU_USE_TIM9 FALSE |
| 158 | #define STM32_ICU_TIM1_IRQ_PRIORITY 7 | 166 | #define STM32_ICU_USE_TIM10 FALSE |
| 159 | #define STM32_ICU_TIM2_IRQ_PRIORITY 7 | 167 | #define STM32_ICU_USE_TIM11 FALSE |
| 160 | #define STM32_ICU_TIM3_IRQ_PRIORITY 7 | ||
| 161 | #define STM32_ICU_TIM4_IRQ_PRIORITY 7 | ||
| 162 | #define STM32_ICU_TIM5_IRQ_PRIORITY 7 | ||
| 163 | #define STM32_ICU_TIM9_IRQ_PRIORITY 7 | ||
| 164 | 168 | ||
| 165 | /* | 169 | /* |
| 166 | * PWM driver system settings. | 170 | * PWM driver system settings. |
| 167 | */ | 171 | */ |
| 168 | #define STM32_PWM_USE_ADVANCED FALSE | ||
| 169 | #define STM32_PWM_USE_TIM1 FALSE | 172 | #define STM32_PWM_USE_TIM1 FALSE |
| 170 | #define STM32_PWM_USE_TIM2 FALSE | 173 | #define STM32_PWM_USE_TIM2 FALSE |
| 171 | #define STM32_PWM_USE_TIM3 FALSE | 174 | #define STM32_PWM_USE_TIM3 FALSE |
| 172 | #define STM32_PWM_USE_TIM4 FALSE | 175 | #define STM32_PWM_USE_TIM4 FALSE |
| 173 | #define STM32_PWM_USE_TIM5 FALSE | 176 | #define STM32_PWM_USE_TIM5 FALSE |
| 174 | #define STM32_PWM_USE_TIM9 FALSE | 177 | #define STM32_PWM_USE_TIM9 FALSE |
| 175 | #define STM32_PWM_TIM1_IRQ_PRIORITY 7 | 178 | #define STM32_PWM_USE_TIM10 FALSE |
| 176 | #define STM32_PWM_TIM2_IRQ_PRIORITY 7 | 179 | #define STM32_PWM_USE_TIM11 FALSE |
| 177 | #define STM32_PWM_TIM3_IRQ_PRIORITY 7 | 180 | |
| 178 | #define STM32_PWM_TIM4_IRQ_PRIORITY 7 | 181 | /* |
| 179 | #define STM32_PWM_TIM5_IRQ_PRIORITY 7 | 182 | * RTC driver system settings. |
| 180 | #define STM32_PWM_TIM9_IRQ_PRIORITY 7 | 183 | */ |
| 184 | #define STM32_RTC_PRESA_VALUE 32 | ||
| 185 | #define STM32_RTC_PRESS_VALUE 1024 | ||
| 186 | #define STM32_RTC_CR_INIT 0 | ||
| 187 | #define STM32_RTC_TAMPCR_INIT 0 | ||
| 181 | 188 | ||
| 182 | /* | 189 | /* |
| 183 | * SERIAL driver system settings. | 190 | * SERIAL driver system settings. |
| @@ -185,9 +192,6 @@ | |||
| 185 | #define STM32_SERIAL_USE_USART1 FALSE | 192 | #define STM32_SERIAL_USE_USART1 FALSE |
| 186 | #define STM32_SERIAL_USE_USART2 FALSE | 193 | #define STM32_SERIAL_USE_USART2 FALSE |
| 187 | #define STM32_SERIAL_USE_USART6 FALSE | 194 | #define STM32_SERIAL_USE_USART6 FALSE |
| 188 | #define STM32_SERIAL_USART1_PRIORITY 12 | ||
| 189 | #define STM32_SERIAL_USART2_PRIORITY 12 | ||
| 190 | #define STM32_SERIAL_USART6_PRIORITY 12 | ||
| 191 | 195 | ||
| 192 | /* | 196 | /* |
| 193 | * SPI driver system settings. | 197 | * SPI driver system settings. |
| @@ -227,9 +231,6 @@ | |||
| 227 | #define STM32_UART_USART2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6) | 231 | #define STM32_UART_USART2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6) |
| 228 | #define STM32_UART_USART6_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 2) | 232 | #define STM32_UART_USART6_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 2) |
| 229 | #define STM32_UART_USART6_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 7) | 233 | #define STM32_UART_USART6_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 7) |
| 230 | #define STM32_UART_USART1_IRQ_PRIORITY 12 | ||
| 231 | #define STM32_UART_USART2_IRQ_PRIORITY 12 | ||
| 232 | #define STM32_UART_USART6_IRQ_PRIORITY 12 | ||
| 233 | #define STM32_UART_USART1_DMA_PRIORITY 0 | 234 | #define STM32_UART_USART1_DMA_PRIORITY 0 |
| 234 | #define STM32_UART_USART2_DMA_PRIORITY 0 | 235 | #define STM32_UART_USART2_DMA_PRIORITY 0 |
| 235 | #define STM32_UART_USART6_DMA_PRIORITY 0 | 236 | #define STM32_UART_USART6_DMA_PRIORITY 0 |
| @@ -241,9 +242,7 @@ | |||
| 241 | #define STM32_USB_USE_OTG1 TRUE | 242 | #define STM32_USB_USE_OTG1 TRUE |
| 242 | #define STM32_USB_OTG1_IRQ_PRIORITY 14 | 243 | #define STM32_USB_OTG1_IRQ_PRIORITY 14 |
| 243 | #define STM32_USB_OTG1_RX_FIFO_SIZE 512 | 244 | #define STM32_USB_OTG1_RX_FIFO_SIZE 512 |
| 244 | #define STM32_USB_OTG_THREAD_PRIO NORMALPRIO+1 | 245 | #define STM32_USB_HOST_WAKEUP_DURATION 2 |
| 245 | #define STM32_USB_OTG_THREAD_STACK_SIZE 128 | ||
| 246 | #define STM32_USB_OTGFIFO_FILL_BASEPRI 0 | ||
| 247 | 246 | ||
| 248 | /* | 247 | /* |
| 249 | * WDG driver system settings. | 248 | * WDG driver system settings. |
diff --git a/platforms/chibios/boards/GENERIC_STM32_F405XG/board/board.mk b/platforms/chibios/boards/GENERIC_STM32_F405XG/board/board.mk new file mode 100644 index 000000000..6c837bb8e --- /dev/null +++ b/platforms/chibios/boards/GENERIC_STM32_F405XG/board/board.mk | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | # List of all the board related files. | ||
| 2 | BOARDSRC = $(CHIBIOS)/os/hal/boards/ST_STM32F4_DISCOVERY/board.c | ||
| 3 | |||
| 4 | # Required include directories | ||
| 5 | BOARDINC = $(CHIBIOS)/os/hal/boards/ST_STM32F4_DISCOVERY | ||
| 6 | |||
| 7 | # Shared variables | ||
| 8 | ALLCSRC += $(BOARDSRC) | ||
| 9 | ALLINC += $(BOARDINC) \ No newline at end of file | ||
diff --git a/platforms/chibios/boards/GENERIC_STM32_F405XG/configs/board.h b/platforms/chibios/boards/GENERIC_STM32_F405XG/configs/board.h new file mode 100644 index 000000000..8cb771bc1 --- /dev/null +++ b/platforms/chibios/boards/GENERIC_STM32_F405XG/configs/board.h | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | /* Copyright 2020 Nick Brassel (tzarc) | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 3 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #pragma once | ||
| 17 | |||
| 18 | #define STM32_HSECLK 12000000 | ||
| 19 | // The following is required to disable the pull-down on PA9, when PA9 is used for the keyboard matrix: | ||
| 20 | #define BOARD_OTG_NOVBUSSENS | ||
| 21 | |||
| 22 | #include_next "board.h" | ||
| 23 | |||
| 24 | #undef STM32_HSE_BYPASS | ||
| 25 | |||
| 26 | #undef STM32F407xx | ||
| 27 | #define STM32F405xG | ||
| 28 | #define STM32F405xx | ||
diff --git a/platforms/chibios/boards/GENERIC_STM32_F405XG/configs/config.h b/platforms/chibios/boards/GENERIC_STM32_F405XG/configs/config.h new file mode 100644 index 000000000..cc52a953e --- /dev/null +++ b/platforms/chibios/boards/GENERIC_STM32_F405XG/configs/config.h | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | /* Copyright 2021 Andrei Purdea | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 2 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | /* Address for jumping to bootloader on STM32 chips. */ | ||
| 18 | /* It is chip dependent, the correct number can be looked up by checking against ST's application note AN2606. | ||
| 19 | */ | ||
| 20 | #define STM32_BOOTLOADER_ADDRESS 0x1FFF0000 | ||
| 21 | #ifndef EARLY_INIT_PERFORM_BOOTLOADER_JUMP | ||
| 22 | # define EARLY_INIT_PERFORM_BOOTLOADER_JUMP TRUE | ||
| 23 | #endif | ||
diff --git a/platforms/chibios/boards/GENERIC_STM32_F405XG/configs/mcuconf.h b/platforms/chibios/boards/GENERIC_STM32_F405XG/configs/mcuconf.h new file mode 100644 index 000000000..908a580a9 --- /dev/null +++ b/platforms/chibios/boards/GENERIC_STM32_F405XG/configs/mcuconf.h | |||
| @@ -0,0 +1,352 @@ | |||
| 1 | /* | ||
| 2 | ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio | ||
| 3 | |||
| 4 | Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | you may not use this file except in compliance with the License. | ||
| 6 | You may obtain a copy of the License at | ||
| 7 | |||
| 8 | http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | |||
| 10 | Unless required by applicable law or agreed to in writing, software | ||
| 11 | distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | See the License for the specific language governing permissions and | ||
| 14 | limitations under the License. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #ifndef MCUCONF_H | ||
| 18 | #define MCUCONF_H | ||
| 19 | |||
| 20 | /* | ||
| 21 | * STM32F4xx drivers configuration. | ||
| 22 | * The following settings override the default settings present in | ||
| 23 | * the various device driver implementation headers. | ||
| 24 | * Note that the settings for each driver only have effect if the whole | ||
| 25 | * driver is enabled in halconf.h. | ||
| 26 | * | ||
| 27 | * IRQ priorities: | ||
| 28 | * 15...0 Lowest...Highest. | ||
| 29 | * | ||
| 30 | * DMA priorities: | ||
| 31 | * 0...3 Lowest...Highest. | ||
| 32 | */ | ||
| 33 | |||
| 34 | #define STM32F4xx_MCUCONF | ||
| 35 | #define STM32F405_MCUCONF | ||
| 36 | #define STM32F415_MCUCONF | ||
| 37 | #define STM32F407_MCUCONF | ||
| 38 | #define STM32F417_MCUCONF | ||
| 39 | |||
| 40 | /* | ||
| 41 | * HAL driver system settings. | ||
| 42 | */ | ||
| 43 | #define STM32_NO_INIT FALSE | ||
| 44 | #define STM32_PVD_ENABLE FALSE | ||
| 45 | #define STM32_PLS STM32_PLS_LEV0 | ||
| 46 | #define STM32_BKPRAM_ENABLE FALSE | ||
| 47 | #define STM32_HSI_ENABLED TRUE | ||
| 48 | #define STM32_LSI_ENABLED TRUE | ||
| 49 | #define STM32_HSE_ENABLED TRUE | ||
| 50 | #define STM32_LSE_ENABLED FALSE | ||
| 51 | #define STM32_CLOCK48_REQUIRED TRUE | ||
| 52 | #define STM32_SW STM32_SW_PLL | ||
| 53 | #define STM32_PLLSRC STM32_PLLSRC_HSE | ||
| 54 | #define STM32_PLLM_VALUE 12 | ||
| 55 | #define STM32_PLLN_VALUE 336 | ||
| 56 | #define STM32_PLLP_VALUE 2 | ||
| 57 | #define STM32_PLLQ_VALUE 7 | ||
| 58 | #define STM32_HPRE STM32_HPRE_DIV1 | ||
| 59 | #define STM32_PPRE1 STM32_PPRE1_DIV4 | ||
| 60 | #define STM32_PPRE2 STM32_PPRE2_DIV2 | ||
| 61 | #define STM32_RTCSEL STM32_RTCSEL_LSI | ||
| 62 | #define STM32_RTCPRE_VALUE 8 | ||
| 63 | #define STM32_MCO1SEL STM32_MCO1SEL_HSI | ||
| 64 | #define STM32_MCO1PRE STM32_MCO1PRE_DIV1 | ||
| 65 | #define STM32_MCO2SEL STM32_MCO2SEL_SYSCLK | ||
| 66 | #define STM32_MCO2PRE STM32_MCO2PRE_DIV5 | ||
| 67 | #define STM32_I2SSRC STM32_I2SSRC_CKIN | ||
| 68 | #define STM32_PLLI2SN_VALUE 192 | ||
| 69 | #define STM32_PLLI2SR_VALUE 5 | ||
| 70 | |||
| 71 | /* | ||
| 72 | * IRQ system settings. | ||
| 73 | */ | ||
| 74 | #define STM32_IRQ_EXTI0_PRIORITY 6 | ||
| 75 | #define STM32_IRQ_EXTI1_PRIORITY 6 | ||
| 76 | #define STM32_IRQ_EXTI2_PRIORITY 6 | ||
| 77 | #define STM32_IRQ_EXTI3_PRIORITY 6 | ||
| 78 | #define STM32_IRQ_EXTI4_PRIORITY 6 | ||
| 79 | #define STM32_IRQ_EXTI5_9_PRIORITY 6 | ||
| 80 | #define STM32_IRQ_EXTI10_15_PRIORITY 6 | ||
| 81 | #define STM32_IRQ_EXTI16_PRIORITY 6 | ||
| 82 | #define STM32_IRQ_EXTI17_PRIORITY 15 | ||
| 83 | #define STM32_IRQ_EXTI18_PRIORITY 6 | ||
| 84 | #define STM32_IRQ_EXTI19_PRIORITY 6 | ||
| 85 | #define STM32_IRQ_EXTI20_PRIORITY 6 | ||
| 86 | #define STM32_IRQ_EXTI21_PRIORITY 15 | ||
| 87 | #define STM32_IRQ_EXTI22_PRIORITY 15 | ||
| 88 | |||
| 89 | /* | ||
| 90 | * ADC driver system settings. | ||
| 91 | */ | ||
| 92 | #define STM32_ADC_ADCPRE ADC_CCR_ADCPRE_DIV4 | ||
| 93 | #define STM32_ADC_USE_ADC1 FALSE | ||
| 94 | #define STM32_ADC_USE_ADC2 FALSE | ||
| 95 | #define STM32_ADC_USE_ADC3 FALSE | ||
| 96 | #define STM32_ADC_ADC1_DMA_STREAM STM32_DMA_STREAM_ID(2, 4) | ||
| 97 | #define STM32_ADC_ADC2_DMA_STREAM STM32_DMA_STREAM_ID(2, 2) | ||
| 98 | #define STM32_ADC_ADC3_DMA_STREAM STM32_DMA_STREAM_ID(2, 1) | ||
| 99 | #define STM32_ADC_ADC1_DMA_PRIORITY 2 | ||
| 100 | #define STM32_ADC_ADC2_DMA_PRIORITY 2 | ||
| 101 | #define STM32_ADC_ADC3_DMA_PRIORITY 2 | ||
| 102 | #define STM32_ADC_IRQ_PRIORITY 6 | ||
| 103 | #define STM32_ADC_ADC1_DMA_IRQ_PRIORITY 6 | ||
| 104 | #define STM32_ADC_ADC2_DMA_IRQ_PRIORITY 6 | ||
| 105 | #define STM32_ADC_ADC3_DMA_IRQ_PRIORITY 6 | ||
| 106 | |||
| 107 | /* | ||
| 108 | * CAN driver system settings. | ||
| 109 | */ | ||
| 110 | #define STM32_CAN_USE_CAN1 FALSE | ||
| 111 | #define STM32_CAN_USE_CAN2 FALSE | ||
| 112 | #define STM32_CAN_CAN1_IRQ_PRIORITY 11 | ||
| 113 | #define STM32_CAN_CAN2_IRQ_PRIORITY 11 | ||
| 114 | |||
| 115 | /* | ||
| 116 | * DAC driver system settings. | ||
| 117 | */ | ||
| 118 | #define STM32_DAC_DUAL_MODE FALSE | ||
| 119 | #define STM32_DAC_USE_DAC1_CH1 FALSE | ||
| 120 | #define STM32_DAC_USE_DAC1_CH2 FALSE | ||
| 121 | #define STM32_DAC_DAC1_CH1_IRQ_PRIORITY 10 | ||
| 122 | #define STM32_DAC_DAC1_CH2_IRQ_PRIORITY 10 | ||
| 123 | #define STM32_DAC_DAC1_CH1_DMA_PRIORITY 2 | ||
| 124 | #define STM32_DAC_DAC1_CH2_DMA_PRIORITY 2 | ||
| 125 | #define STM32_DAC_DAC1_CH1_DMA_STREAM STM32_DMA_STREAM_ID(1, 5) | ||
| 126 | #define STM32_DAC_DAC1_CH2_DMA_STREAM STM32_DMA_STREAM_ID(1, 6) | ||
| 127 | |||
| 128 | /* | ||
| 129 | * GPT driver system settings. | ||
| 130 | */ | ||
| 131 | #define STM32_GPT_USE_TIM1 FALSE | ||
| 132 | #define STM32_GPT_USE_TIM2 FALSE | ||
| 133 | #define STM32_GPT_USE_TIM3 FALSE | ||
| 134 | #define STM32_GPT_USE_TIM4 FALSE | ||
| 135 | #define STM32_GPT_USE_TIM5 FALSE | ||
| 136 | #define STM32_GPT_USE_TIM6 FALSE | ||
| 137 | #define STM32_GPT_USE_TIM7 FALSE | ||
| 138 | #define STM32_GPT_USE_TIM8 FALSE | ||
| 139 | #define STM32_GPT_USE_TIM9 FALSE | ||
| 140 | #define STM32_GPT_USE_TIM11 FALSE | ||
| 141 | #define STM32_GPT_USE_TIM12 FALSE | ||
| 142 | #define STM32_GPT_USE_TIM14 FALSE | ||
| 143 | #define STM32_GPT_TIM1_IRQ_PRIORITY 7 | ||
| 144 | #define STM32_GPT_TIM2_IRQ_PRIORITY 7 | ||
| 145 | #define STM32_GPT_TIM3_IRQ_PRIORITY 7 | ||
| 146 | #define STM32_GPT_TIM4_IRQ_PRIORITY 7 | ||
| 147 | #define STM32_GPT_TIM5_IRQ_PRIORITY 7 | ||
| 148 | #define STM32_GPT_TIM6_IRQ_PRIORITY 7 | ||
| 149 | #define STM32_GPT_TIM7_IRQ_PRIORITY 7 | ||
| 150 | #define STM32_GPT_TIM8_IRQ_PRIORITY 7 | ||
| 151 | #define STM32_GPT_TIM9_IRQ_PRIORITY 7 | ||
| 152 | #define STM32_GPT_TIM11_IRQ_PRIORITY 7 | ||
| 153 | #define STM32_GPT_TIM12_IRQ_PRIORITY 7 | ||
| 154 | #define STM32_GPT_TIM14_IRQ_PRIORITY 7 | ||
| 155 | |||
| 156 | /* | ||
| 157 | * I2C driver system settings. | ||
| 158 | */ | ||
| 159 | #define STM32_I2C_USE_I2C1 FALSE | ||
| 160 | #define STM32_I2C_USE_I2C2 FALSE | ||
| 161 | #define STM32_I2C_USE_I2C3 FALSE | ||
| 162 | #define STM32_I2C_BUSY_TIMEOUT 50 | ||
| 163 | #define STM32_I2C_I2C1_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0) | ||
| 164 | #define STM32_I2C_I2C1_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6) | ||
| 165 | #define STM32_I2C_I2C2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2) | ||
| 166 | #define STM32_I2C_I2C2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7) | ||
| 167 | #define STM32_I2C_I2C3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2) | ||
| 168 | #define STM32_I2C_I2C3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4) | ||
| 169 | #define STM32_I2C_I2C1_IRQ_PRIORITY 5 | ||
| 170 | #define STM32_I2C_I2C2_IRQ_PRIORITY 5 | ||
| 171 | #define STM32_I2C_I2C3_IRQ_PRIORITY 5 | ||
| 172 | #define STM32_I2C_I2C1_DMA_PRIORITY 3 | ||
| 173 | #define STM32_I2C_I2C2_DMA_PRIORITY 3 | ||
| 174 | #define STM32_I2C_I2C3_DMA_PRIORITY 3 | ||
| 175 | #define STM32_I2C_DMA_ERROR_HOOK(i2cp) osalSysHalt("DMA failure") | ||
| 176 | |||
| 177 | /* | ||
| 178 | * I2S driver system settings. | ||
| 179 | */ | ||
| 180 | #define STM32_I2S_USE_SPI2 FALSE | ||
| 181 | #define STM32_I2S_USE_SPI3 FALSE | ||
| 182 | #define STM32_I2S_SPI2_IRQ_PRIORITY 10 | ||
| 183 | #define STM32_I2S_SPI3_IRQ_PRIORITY 10 | ||
| 184 | #define STM32_I2S_SPI2_DMA_PRIORITY 1 | ||
| 185 | #define STM32_I2S_SPI3_DMA_PRIORITY 1 | ||
| 186 | #define STM32_I2S_SPI2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 3) | ||
| 187 | #define STM32_I2S_SPI2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4) | ||
| 188 | #define STM32_I2S_SPI3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0) | ||
| 189 | #define STM32_I2S_SPI3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7) | ||
| 190 | #define STM32_I2S_DMA_ERROR_HOOK(i2sp) osalSysHalt("DMA failure") | ||
| 191 | |||
| 192 | /* | ||
| 193 | * ICU driver system settings. | ||
| 194 | */ | ||
| 195 | #define STM32_ICU_USE_TIM1 FALSE | ||
| 196 | #define STM32_ICU_USE_TIM2 FALSE | ||
| 197 | #define STM32_ICU_USE_TIM3 FALSE | ||
| 198 | #define STM32_ICU_USE_TIM4 FALSE | ||
| 199 | #define STM32_ICU_USE_TIM5 FALSE | ||
| 200 | #define STM32_ICU_USE_TIM8 FALSE | ||
| 201 | #define STM32_ICU_USE_TIM9 FALSE | ||
| 202 | #define STM32_ICU_TIM1_IRQ_PRIORITY 7 | ||
| 203 | #define STM32_ICU_TIM2_IRQ_PRIORITY 7 | ||
| 204 | #define STM32_ICU_TIM3_IRQ_PRIORITY 7 | ||
| 205 | #define STM32_ICU_TIM4_IRQ_PRIORITY 7 | ||
| 206 | #define STM32_ICU_TIM5_IRQ_PRIORITY 7 | ||
| 207 | #define STM32_ICU_TIM8_IRQ_PRIORITY 7 | ||
| 208 | #define STM32_ICU_TIM9_IRQ_PRIORITY 7 | ||
| 209 | |||
| 210 | /* | ||
| 211 | * MAC driver system settings. | ||
| 212 | */ | ||
| 213 | #define STM32_MAC_TRANSMIT_BUFFERS 2 | ||
| 214 | #define STM32_MAC_RECEIVE_BUFFERS 4 | ||
| 215 | #define STM32_MAC_BUFFERS_SIZE 1522 | ||
| 216 | #define STM32_MAC_PHY_TIMEOUT 100 | ||
| 217 | #define STM32_MAC_ETH1_CHANGE_PHY_STATE TRUE | ||
| 218 | #define STM32_MAC_ETH1_IRQ_PRIORITY 13 | ||
| 219 | #define STM32_MAC_IP_CHECKSUM_OFFLOAD 0 | ||
| 220 | |||
| 221 | /* | ||
| 222 | * PWM driver system settings. | ||
| 223 | */ | ||
| 224 | #define STM32_PWM_USE_ADVANCED FALSE | ||
| 225 | #define STM32_PWM_USE_TIM1 FALSE | ||
| 226 | #define STM32_PWM_USE_TIM2 FALSE | ||
| 227 | #define STM32_PWM_USE_TIM3 FALSE | ||
| 228 | #define STM32_PWM_USE_TIM4 FALSE | ||
| 229 | #define STM32_PWM_USE_TIM5 FALSE | ||
| 230 | #define STM32_PWM_USE_TIM8 FALSE | ||
| 231 | #define STM32_PWM_USE_TIM9 FALSE | ||
| 232 | #define STM32_PWM_TIM1_IRQ_PRIORITY 7 | ||
| 233 | #define STM32_PWM_TIM2_IRQ_PRIORITY 7 | ||
| 234 | #define STM32_PWM_TIM3_IRQ_PRIORITY 7 | ||
| 235 | #define STM32_PWM_TIM4_IRQ_PRIORITY 7 | ||
| 236 | #define STM32_PWM_TIM5_IRQ_PRIORITY 7 | ||
| 237 | #define STM32_PWM_TIM8_IRQ_PRIORITY 7 | ||
| 238 | #define STM32_PWM_TIM9_IRQ_PRIORITY 7 | ||
| 239 | |||
| 240 | /* | ||
| 241 | * RTC driver system settings. | ||
| 242 | */ | ||
| 243 | #define STM32_RTC_PRESA_VALUE 32 | ||
| 244 | #define STM32_RTC_PRESS_VALUE 1024 | ||
| 245 | #define STM32_RTC_CR_INIT 0 | ||
| 246 | #define STM32_RTC_TAMPCR_INIT 0 | ||
| 247 | |||
| 248 | /* | ||
| 249 | * SDC driver system settings. | ||
| 250 | */ | ||
| 251 | #define STM32_SDC_SDIO_DMA_PRIORITY 3 | ||
| 252 | #define STM32_SDC_SDIO_IRQ_PRIORITY 9 | ||
| 253 | #define STM32_SDC_WRITE_TIMEOUT_MS 1000 | ||
| 254 | #define STM32_SDC_READ_TIMEOUT_MS 1000 | ||
| 255 | #define STM32_SDC_CLOCK_ACTIVATION_DELAY 10 | ||
| 256 | #define STM32_SDC_SDIO_UNALIGNED_SUPPORT TRUE | ||
| 257 | #define STM32_SDC_SDIO_DMA_STREAM STM32_DMA_STREAM_ID(2, 3) | ||
| 258 | |||
| 259 | /* | ||
| 260 | * SERIAL driver system settings. | ||
| 261 | */ | ||
| 262 | #define STM32_SERIAL_USE_USART1 FALSE | ||
| 263 | #define STM32_SERIAL_USE_USART2 FALSE | ||
| 264 | #define STM32_SERIAL_USE_USART3 FALSE | ||
| 265 | #define STM32_SERIAL_USE_UART4 FALSE | ||
| 266 | #define STM32_SERIAL_USE_UART5 FALSE | ||
| 267 | #define STM32_SERIAL_USE_USART6 FALSE | ||
| 268 | #define STM32_SERIAL_USART1_PRIORITY 12 | ||
| 269 | #define STM32_SERIAL_USART2_PRIORITY 12 | ||
| 270 | #define STM32_SERIAL_USART3_PRIORITY 12 | ||
| 271 | #define STM32_SERIAL_UART4_PRIORITY 12 | ||
| 272 | #define STM32_SERIAL_UART5_PRIORITY 12 | ||
| 273 | #define STM32_SERIAL_USART6_PRIORITY 12 | ||
| 274 | |||
| 275 | /* | ||
| 276 | * SPI driver system settings. | ||
| 277 | */ | ||
| 278 | #define STM32_SPI_USE_SPI1 FALSE | ||
| 279 | #define STM32_SPI_USE_SPI2 FALSE | ||
| 280 | #define STM32_SPI_USE_SPI3 FALSE | ||
| 281 | #define STM32_SPI_SPI1_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 0) | ||
| 282 | #define STM32_SPI_SPI1_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 3) | ||
| 283 | #define STM32_SPI_SPI2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 3) | ||
| 284 | #define STM32_SPI_SPI2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4) | ||
| 285 | #define STM32_SPI_SPI3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0) | ||
| 286 | #define STM32_SPI_SPI3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7) | ||
| 287 | #define STM32_SPI_SPI1_DMA_PRIORITY 1 | ||
| 288 | #define STM32_SPI_SPI2_DMA_PRIORITY 1 | ||
| 289 | #define STM32_SPI_SPI3_DMA_PRIORITY 1 | ||
| 290 | #define STM32_SPI_SPI1_IRQ_PRIORITY 10 | ||
| 291 | #define STM32_SPI_SPI2_IRQ_PRIORITY 10 | ||
| 292 | #define STM32_SPI_SPI3_IRQ_PRIORITY 10 | ||
| 293 | #define STM32_SPI_DMA_ERROR_HOOK(spip) osalSysHalt("DMA failure") | ||
| 294 | |||
| 295 | /* | ||
| 296 | * ST driver system settings. | ||
| 297 | */ | ||
| 298 | #define STM32_ST_IRQ_PRIORITY 8 | ||
| 299 | #define STM32_ST_USE_TIMER 2 | ||
| 300 | |||
| 301 | /* | ||
| 302 | * UART driver system settings. | ||
| 303 | */ | ||
| 304 | #define STM32_UART_USE_USART1 FALSE | ||
| 305 | #define STM32_UART_USE_USART2 FALSE | ||
| 306 | #define STM32_UART_USE_USART3 FALSE | ||
| 307 | #define STM32_UART_USE_UART4 FALSE | ||
| 308 | #define STM32_UART_USE_UART5 FALSE | ||
| 309 | #define STM32_UART_USE_USART6 FALSE | ||
| 310 | #define STM32_UART_USART1_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 5) | ||
| 311 | #define STM32_UART_USART1_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 7) | ||
| 312 | #define STM32_UART_USART2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 5) | ||
| 313 | #define STM32_UART_USART2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6) | ||
| 314 | #define STM32_UART_USART3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 1) | ||
| 315 | #define STM32_UART_USART3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 3) | ||
| 316 | #define STM32_UART_UART4_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2) | ||
| 317 | #define STM32_UART_UART4_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4) | ||
| 318 | #define STM32_UART_UART5_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0) | ||
| 319 | #define STM32_UART_UART5_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7) | ||
| 320 | #define STM32_UART_USART6_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 2) | ||
| 321 | #define STM32_UART_USART6_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 7) | ||
| 322 | #define STM32_UART_USART1_IRQ_PRIORITY 12 | ||
| 323 | #define STM32_UART_USART2_IRQ_PRIORITY 12 | ||
| 324 | #define STM32_UART_USART3_IRQ_PRIORITY 12 | ||
| 325 | #define STM32_UART_UART4_IRQ_PRIORITY 12 | ||
| 326 | #define STM32_UART_UART5_IRQ_PRIORITY 12 | ||
| 327 | #define STM32_UART_USART6_IRQ_PRIORITY 12 | ||
| 328 | #define STM32_UART_USART1_DMA_PRIORITY 0 | ||
| 329 | #define STM32_UART_USART2_DMA_PRIORITY 0 | ||
| 330 | #define STM32_UART_USART3_DMA_PRIORITY 0 | ||
| 331 | #define STM32_UART_UART4_DMA_PRIORITY 0 | ||
| 332 | #define STM32_UART_UART5_DMA_PRIORITY 0 | ||
| 333 | #define STM32_UART_USART6_DMA_PRIORITY 0 | ||
| 334 | #define STM32_UART_DMA_ERROR_HOOK(uartp) osalSysHalt("DMA failure") | ||
| 335 | |||
| 336 | /* | ||
| 337 | * USB driver system settings. | ||
| 338 | */ | ||
| 339 | #define STM32_USB_USE_OTG1 TRUE | ||
| 340 | #define STM32_USB_USE_OTG2 FALSE | ||
| 341 | #define STM32_USB_OTG1_IRQ_PRIORITY 14 | ||
| 342 | #define STM32_USB_OTG2_IRQ_PRIORITY 14 | ||
| 343 | #define STM32_USB_OTG1_RX_FIFO_SIZE 512 | ||
| 344 | #define STM32_USB_OTG2_RX_FIFO_SIZE 1024 | ||
| 345 | #define STM32_USB_HOST_WAKEUP_DURATION 2 | ||
| 346 | |||
| 347 | /* | ||
| 348 | * WDG driver system settings. | ||
| 349 | */ | ||
| 350 | #define STM32_WDG_USE_IWDG FALSE | ||
| 351 | |||
| 352 | #endif /* MCUCONF_H */ | ||
diff --git a/platforms/chibios/boards/GENERIC_STM32_F407XE/configs/mcuconf.h b/platforms/chibios/boards/GENERIC_STM32_F407XE/configs/mcuconf.h index 4be47fe1b..928ee56c7 100644 --- a/platforms/chibios/boards/GENERIC_STM32_F407XE/configs/mcuconf.h +++ b/platforms/chibios/boards/GENERIC_STM32_F407XE/configs/mcuconf.h | |||
| @@ -344,9 +344,6 @@ | |||
| 344 | #define STM32_USB_OTG2_RX_FIFO_SIZE 1024 | 344 | #define STM32_USB_OTG2_RX_FIFO_SIZE 1024 |
| 345 | #define STM32_USB_HOST_WAKEUP_DURATION 2 | 345 | #define STM32_USB_HOST_WAKEUP_DURATION 2 |
| 346 | 346 | ||
| 347 | #define STM32_USB_OTG_THREAD_PRIO NORMALPRIO+1 | ||
| 348 | #define STM32_USB_OTG_THREAD_STACK_SIZE 128 | ||
| 349 | |||
| 350 | /* | 347 | /* |
| 351 | * WDG driver system settings. | 348 | * WDG driver system settings. |
| 352 | */ | 349 | */ |
diff --git a/platforms/chibios/boards/GENERIC_STM32_F446XE/configs/mcuconf.h b/platforms/chibios/boards/GENERIC_STM32_F446XE/configs/mcuconf.h index d2de75590..566c146c2 100644 --- a/platforms/chibios/boards/GENERIC_STM32_F446XE/configs/mcuconf.h +++ b/platforms/chibios/boards/GENERIC_STM32_F446XE/configs/mcuconf.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio | 2 | ChibiOS - Copyright (C) 2006..2020 Giovanni Di Sirio |
| 3 | 3 | ||
| 4 | Licensed under the Apache License, Version 2.0 (the "License"); | 4 | Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | you may not use this file except in compliance with the License. | 5 | you may not use this file except in compliance with the License. |
| @@ -32,11 +32,15 @@ | |||
| 32 | */ | 32 | */ |
| 33 | 33 | ||
| 34 | #define STM32F4xx_MCUCONF | 34 | #define STM32F4xx_MCUCONF |
| 35 | #define STM32F446_MCUCONF | ||
| 35 | 36 | ||
| 36 | /* | 37 | /* |
| 37 | * HAL driver system settings. | 38 | * HAL driver system settings. |
| 38 | */ | 39 | */ |
| 39 | #define STM32_NO_INIT FALSE | 40 | #define STM32_NO_INIT FALSE |
| 41 | #define STM32_PVD_ENABLE FALSE | ||
| 42 | #define STM32_PLS STM32_PLS_LEV0 | ||
| 43 | #define STM32_BKPRAM_ENABLE FALSE | ||
| 40 | #define STM32_HSI_ENABLED FALSE | 44 | #define STM32_HSI_ENABLED FALSE |
| 41 | #define STM32_LSI_ENABLED TRUE | 45 | #define STM32_LSI_ENABLED TRUE |
| 42 | #define STM32_HSE_ENABLED TRUE | 46 | #define STM32_HSE_ENABLED TRUE |
| @@ -70,9 +74,6 @@ | |||
| 70 | #define STM32_SAI1SEL STM32_SAI2SEL_PLLR | 74 | #define STM32_SAI1SEL STM32_SAI2SEL_PLLR |
| 71 | #define STM32_SAI2SEL STM32_SAI2SEL_PLLR | 75 | #define STM32_SAI2SEL STM32_SAI2SEL_PLLR |
| 72 | #define STM32_CK48MSEL STM32_CK48MSEL_PLLALT | 76 | #define STM32_CK48MSEL STM32_CK48MSEL_PLLALT |
| 73 | #define STM32_PVD_ENABLE FALSE | ||
| 74 | #define STM32_PLS STM32_PLS_LEV0 | ||
| 75 | #define STM32_BKPRAM_ENABLE FALSE | ||
| 76 | 77 | ||
| 77 | /* | 78 | /* |
| 78 | * IRQ system settings. | 79 | * IRQ system settings. |
| @@ -92,6 +93,30 @@ | |||
| 92 | #define STM32_IRQ_EXTI21_PRIORITY 15 | 93 | #define STM32_IRQ_EXTI21_PRIORITY 15 |
| 93 | #define STM32_IRQ_EXTI22_PRIORITY 15 | 94 | #define STM32_IRQ_EXTI22_PRIORITY 15 |
| 94 | 95 | ||
| 96 | #define STM32_IRQ_TIM1_BRK_TIM9_PRIORITY 7 | ||
| 97 | #define STM32_IRQ_TIM1_UP_TIM10_PRIORITY 7 | ||
| 98 | #define STM32_IRQ_TIM1_TRGCO_TIM11_PRIORITY 7 | ||
| 99 | #define STM32_IRQ_TIM1_CC_PRIORITY 7 | ||
| 100 | #define STM32_IRQ_TIM2_PRIORITY 7 | ||
| 101 | #define STM32_IRQ_TIM3_PRIORITY 7 | ||
| 102 | #define STM32_IRQ_TIM4_PRIORITY 7 | ||
| 103 | #define STM32_IRQ_TIM5_PRIORITY 7 | ||
| 104 | #define STM32_IRQ_TIM6_PRIORITY 7 | ||
| 105 | #define STM32_IRQ_TIM7_PRIORITY 7 | ||
| 106 | #define STM32_IRQ_TIM8_BRK_TIM12_PRIORITY 7 | ||
| 107 | #define STM32_IRQ_TIM8_UP_TIM13_PRIORITY 7 | ||
| 108 | #define STM32_IRQ_TIM8_TRGCO_TIM14_PRIORITY 7 | ||
| 109 | #define STM32_IRQ_TIM8_CC_PRIORITY 7 | ||
| 110 | |||
| 111 | #define STM32_IRQ_USART1_PRIORITY 12 | ||
| 112 | #define STM32_IRQ_USART2_PRIORITY 12 | ||
| 113 | #define STM32_IRQ_USART3_PRIORITY 12 | ||
| 114 | #define STM32_IRQ_UART4_PRIORITY 12 | ||
| 115 | #define STM32_IRQ_UART5_PRIORITY 12 | ||
| 116 | #define STM32_IRQ_USART6_PRIORITY 12 | ||
| 117 | #define STM32_IRQ_UART7_PRIORITY 12 | ||
| 118 | #define STM32_IRQ_UART8_PRIORITY 12 | ||
| 119 | |||
| 95 | /* | 120 | /* |
| 96 | * ADC driver system settings. | 121 | * ADC driver system settings. |
| 97 | */ | 122 | */ |
| @@ -143,21 +168,11 @@ | |||
| 143 | #define STM32_GPT_USE_TIM7 FALSE | 168 | #define STM32_GPT_USE_TIM7 FALSE |
| 144 | #define STM32_GPT_USE_TIM8 FALSE | 169 | #define STM32_GPT_USE_TIM8 FALSE |
| 145 | #define STM32_GPT_USE_TIM9 FALSE | 170 | #define STM32_GPT_USE_TIM9 FALSE |
| 171 | #define STM32_GPT_USE_TIM10 FALSE | ||
| 146 | #define STM32_GPT_USE_TIM11 FALSE | 172 | #define STM32_GPT_USE_TIM11 FALSE |
| 147 | #define STM32_GPT_USE_TIM12 FALSE | 173 | #define STM32_GPT_USE_TIM12 FALSE |
| 174 | #define STM32_GPT_USE_TIM13 FALSE | ||
| 148 | #define STM32_GPT_USE_TIM14 FALSE | 175 | #define STM32_GPT_USE_TIM14 FALSE |
| 149 | #define STM32_GPT_TIM1_IRQ_PRIORITY 7 | ||
| 150 | #define STM32_GPT_TIM2_IRQ_PRIORITY 7 | ||
| 151 | #define STM32_GPT_TIM3_IRQ_PRIORITY 7 | ||
| 152 | #define STM32_GPT_TIM4_IRQ_PRIORITY 7 | ||
| 153 | #define STM32_GPT_TIM5_IRQ_PRIORITY 7 | ||
| 154 | #define STM32_GPT_TIM6_IRQ_PRIORITY 7 | ||
| 155 | #define STM32_GPT_TIM7_IRQ_PRIORITY 7 | ||
| 156 | #define STM32_GPT_TIM8_IRQ_PRIORITY 7 | ||
| 157 | #define STM32_GPT_TIM9_IRQ_PRIORITY 7 | ||
| 158 | #define STM32_GPT_TIM11_IRQ_PRIORITY 7 | ||
| 159 | #define STM32_GPT_TIM12_IRQ_PRIORITY 7 | ||
| 160 | #define STM32_GPT_TIM14_IRQ_PRIORITY 7 | ||
| 161 | 176 | ||
| 162 | /* | 177 | /* |
| 163 | * I2C driver system settings. | 178 | * I2C driver system settings. |
| @@ -205,13 +220,11 @@ | |||
| 205 | #define STM32_ICU_USE_TIM5 FALSE | 220 | #define STM32_ICU_USE_TIM5 FALSE |
| 206 | #define STM32_ICU_USE_TIM8 FALSE | 221 | #define STM32_ICU_USE_TIM8 FALSE |
| 207 | #define STM32_ICU_USE_TIM9 FALSE | 222 | #define STM32_ICU_USE_TIM9 FALSE |
| 208 | #define STM32_ICU_TIM1_IRQ_PRIORITY 7 | 223 | #define STM32_ICU_USE_TIM10 FALSE |
| 209 | #define STM32_ICU_TIM2_IRQ_PRIORITY 7 | 224 | #define STM32_ICU_USE_TIM11 FALSE |
| 210 | #define STM32_ICU_TIM3_IRQ_PRIORITY 7 | 225 | #define STM32_ICU_USE_TIM12 FALSE |
| 211 | #define STM32_ICU_TIM4_IRQ_PRIORITY 7 | 226 | #define STM32_ICU_USE_TIM13 FALSE |
| 212 | #define STM32_ICU_TIM5_IRQ_PRIORITY 7 | 227 | #define STM32_ICU_USE_TIM14 FALSE |
| 213 | #define STM32_ICU_TIM8_IRQ_PRIORITY 7 | ||
| 214 | #define STM32_ICU_TIM9_IRQ_PRIORITY 7 | ||
| 215 | 228 | ||
| 216 | /* | 229 | /* |
| 217 | * MAC driver system settings. | 230 | * MAC driver system settings. |
| @@ -227,7 +240,6 @@ | |||
| 227 | /* | 240 | /* |
| 228 | * PWM driver system settings. | 241 | * PWM driver system settings. |
| 229 | */ | 242 | */ |
| 230 | #define STM32_PWM_USE_ADVANCED FALSE | ||
| 231 | #define STM32_PWM_USE_TIM1 FALSE | 243 | #define STM32_PWM_USE_TIM1 FALSE |
| 232 | #define STM32_PWM_USE_TIM2 FALSE | 244 | #define STM32_PWM_USE_TIM2 FALSE |
| 233 | #define STM32_PWM_USE_TIM3 FALSE | 245 | #define STM32_PWM_USE_TIM3 FALSE |
| @@ -235,13 +247,19 @@ | |||
| 235 | #define STM32_PWM_USE_TIM5 FALSE | 247 | #define STM32_PWM_USE_TIM5 FALSE |
| 236 | #define STM32_PWM_USE_TIM8 FALSE | 248 | #define STM32_PWM_USE_TIM8 FALSE |
| 237 | #define STM32_PWM_USE_TIM9 FALSE | 249 | #define STM32_PWM_USE_TIM9 FALSE |
| 238 | #define STM32_PWM_TIM1_IRQ_PRIORITY 7 | 250 | #define STM32_PWM_USE_TIM10 FALSE |
| 239 | #define STM32_PWM_TIM2_IRQ_PRIORITY 7 | 251 | #define STM32_PWM_USE_TIM11 FALSE |
| 240 | #define STM32_PWM_TIM3_IRQ_PRIORITY 7 | 252 | #define STM32_PWM_USE_TIM12 FALSE |
| 241 | #define STM32_PWM_TIM4_IRQ_PRIORITY 7 | 253 | #define STM32_PWM_USE_TIM13 FALSE |
| 242 | #define STM32_PWM_TIM5_IRQ_PRIORITY 7 | 254 | #define STM32_PWM_USE_TIM14 FALSE |
| 243 | #define STM32_PWM_TIM8_IRQ_PRIORITY 7 | 255 | |
| 244 | #define STM32_PWM_TIM9_IRQ_PRIORITY 7 | 256 | /* |
| 257 | * RTC driver system settings. | ||
| 258 | */ | ||
| 259 | #define STM32_RTC_PRESA_VALUE 32 | ||
| 260 | #define STM32_RTC_PRESS_VALUE 1024 | ||
| 261 | #define STM32_RTC_CR_INIT 0 | ||
| 262 | #define STM32_RTC_TAMPCR_INIT 0 | ||
| 245 | 263 | ||
| 246 | /* | 264 | /* |
| 247 | * SDC driver system settings. | 265 | * SDC driver system settings. |
| @@ -265,14 +283,6 @@ | |||
| 265 | #define STM32_SERIAL_USE_USART6 FALSE | 283 | #define STM32_SERIAL_USE_USART6 FALSE |
| 266 | #define STM32_SERIAL_USE_UART7 FALSE | 284 | #define STM32_SERIAL_USE_UART7 FALSE |
| 267 | #define STM32_SERIAL_USE_UART8 FALSE | 285 | #define STM32_SERIAL_USE_UART8 FALSE |
| 268 | #define STM32_SERIAL_USART1_PRIORITY 12 | ||
| 269 | #define STM32_SERIAL_USART2_PRIORITY 12 | ||
| 270 | #define STM32_SERIAL_USART3_PRIORITY 12 | ||
| 271 | #define STM32_SERIAL_UART4_PRIORITY 12 | ||
| 272 | #define STM32_SERIAL_UART5_PRIORITY 12 | ||
| 273 | #define STM32_SERIAL_USART6_PRIORITY 12 | ||
| 274 | #define STM32_SERIAL_UART7_PRIORITY 12 | ||
| 275 | #define STM32_SERIAL_UART8_PRIORITY 12 | ||
| 276 | 286 | ||
| 277 | /* | 287 | /* |
| 278 | * SPI driver system settings. | 288 | * SPI driver system settings. |
| @@ -281,6 +291,8 @@ | |||
| 281 | #define STM32_SPI_USE_SPI2 FALSE | 291 | #define STM32_SPI_USE_SPI2 FALSE |
| 282 | #define STM32_SPI_USE_SPI3 FALSE | 292 | #define STM32_SPI_USE_SPI3 FALSE |
| 283 | #define STM32_SPI_USE_SPI4 FALSE | 293 | #define STM32_SPI_USE_SPI4 FALSE |
| 294 | #define STM32_SPI_USE_SPI5 FALSE | ||
| 295 | #define STM32_SPI_USE_SPI6 FALSE | ||
| 284 | #define STM32_SPI_SPI1_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 0) | 296 | #define STM32_SPI_SPI1_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 0) |
| 285 | #define STM32_SPI_SPI1_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 3) | 297 | #define STM32_SPI_SPI1_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 3) |
| 286 | #define STM32_SPI_SPI2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 3) | 298 | #define STM32_SPI_SPI2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 3) |
| @@ -289,14 +301,22 @@ | |||
| 289 | #define STM32_SPI_SPI3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7) | 301 | #define STM32_SPI_SPI3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7) |
| 290 | #define STM32_SPI_SPI4_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 0) | 302 | #define STM32_SPI_SPI4_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 0) |
| 291 | #define STM32_SPI_SPI4_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 1) | 303 | #define STM32_SPI_SPI4_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 1) |
| 304 | #define STM32_SPI_SPI5_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 3) | ||
| 305 | #define STM32_SPI_SPI5_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 4) | ||
| 306 | #define STM32_SPI_SPI6_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 6) | ||
| 307 | #define STM32_SPI_SPI6_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 5) | ||
| 292 | #define STM32_SPI_SPI1_DMA_PRIORITY 1 | 308 | #define STM32_SPI_SPI1_DMA_PRIORITY 1 |
| 293 | #define STM32_SPI_SPI2_DMA_PRIORITY 1 | 309 | #define STM32_SPI_SPI2_DMA_PRIORITY 1 |
| 294 | #define STM32_SPI_SPI3_DMA_PRIORITY 1 | 310 | #define STM32_SPI_SPI3_DMA_PRIORITY 1 |
| 295 | #define STM32_SPI_SPI4_DMA_PRIORITY 1 | 311 | #define STM32_SPI_SPI4_DMA_PRIORITY 1 |
| 312 | #define STM32_SPI_SPI5_DMA_PRIORITY 1 | ||
| 313 | #define STM32_SPI_SPI6_DMA_PRIORITY 1 | ||
| 296 | #define STM32_SPI_SPI1_IRQ_PRIORITY 10 | 314 | #define STM32_SPI_SPI1_IRQ_PRIORITY 10 |
| 297 | #define STM32_SPI_SPI2_IRQ_PRIORITY 10 | 315 | #define STM32_SPI_SPI2_IRQ_PRIORITY 10 |
| 298 | #define STM32_SPI_SPI3_IRQ_PRIORITY 10 | 316 | #define STM32_SPI_SPI3_IRQ_PRIORITY 10 |
| 299 | #define STM32_SPI_SPI4_IRQ_PRIORITY 10 | 317 | #define STM32_SPI_SPI4_IRQ_PRIORITY 10 |
| 318 | #define STM32_SPI_SPI5_IRQ_PRIORITY 10 | ||
| 319 | #define STM32_SPI_SPI6_IRQ_PRIORITY 10 | ||
| 300 | #define STM32_SPI_DMA_ERROR_HOOK(spip) osalSysHalt("DMA failure") | 320 | #define STM32_SPI_DMA_ERROR_HOOK(spip) osalSysHalt("DMA failure") |
| 301 | 321 | ||
| 302 | /* | 322 | /* |
| @@ -326,12 +346,6 @@ | |||
| 326 | #define STM32_UART_UART5_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7) | 346 | #define STM32_UART_UART5_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7) |
| 327 | #define STM32_UART_USART6_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 2) | 347 | #define STM32_UART_USART6_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 2) |
| 328 | #define STM32_UART_USART6_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 7) | 348 | #define STM32_UART_USART6_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 7) |
| 329 | #define STM32_UART_USART1_IRQ_PRIORITY 12 | ||
| 330 | #define STM32_UART_USART2_IRQ_PRIORITY 12 | ||
| 331 | #define STM32_UART_USART3_IRQ_PRIORITY 12 | ||
| 332 | #define STM32_UART_UART4_IRQ_PRIORITY 12 | ||
| 333 | #define STM32_UART_UART5_IRQ_PRIORITY 12 | ||
| 334 | #define STM32_UART_USART6_IRQ_PRIORITY 12 | ||
| 335 | #define STM32_UART_USART1_DMA_PRIORITY 0 | 349 | #define STM32_UART_USART1_DMA_PRIORITY 0 |
| 336 | #define STM32_UART_USART2_DMA_PRIORITY 0 | 350 | #define STM32_UART_USART2_DMA_PRIORITY 0 |
| 337 | #define STM32_UART_USART3_DMA_PRIORITY 0 | 351 | #define STM32_UART_USART3_DMA_PRIORITY 0 |
| @@ -349,9 +363,7 @@ | |||
| 349 | #define STM32_USB_OTG2_IRQ_PRIORITY 14 | 363 | #define STM32_USB_OTG2_IRQ_PRIORITY 14 |
| 350 | #define STM32_USB_OTG1_RX_FIFO_SIZE 512 | 364 | #define STM32_USB_OTG1_RX_FIFO_SIZE 512 |
| 351 | #define STM32_USB_OTG2_RX_FIFO_SIZE 1024 | 365 | #define STM32_USB_OTG2_RX_FIFO_SIZE 1024 |
| 352 | #define STM32_USB_OTG_THREAD_PRIO LOWPRIO | 366 | #define STM32_USB_HOST_WAKEUP_DURATION 2 |
| 353 | #define STM32_USB_OTG_THREAD_STACK_SIZE 128 | ||
| 354 | #define STM32_USB_OTGFIFO_FILL_BASEPRI 0 | ||
| 355 | 367 | ||
| 356 | /* | 368 | /* |
| 357 | * WDG driver system settings. | 369 | * WDG driver system settings. |
diff --git a/platforms/chibios/boards/GENERIC_STM32_G431XB/configs/mcuconf.h b/platforms/chibios/boards/GENERIC_STM32_G431XB/configs/mcuconf.h index 182d4885d..d11502830 100644 --- a/platforms/chibios/boards/GENERIC_STM32_G431XB/configs/mcuconf.h +++ b/platforms/chibios/boards/GENERIC_STM32_G431XB/configs/mcuconf.h | |||
| @@ -40,9 +40,24 @@ | |||
| 40 | */ | 40 | */ |
| 41 | #define STM32_NO_INIT FALSE | 41 | #define STM32_NO_INIT FALSE |
| 42 | #define STM32_VOS STM32_VOS_RANGE1 | 42 | #define STM32_VOS STM32_VOS_RANGE1 |
| 43 | #define STM32_PWR_BOOST TRUE | ||
| 43 | #define STM32_PWR_CR2 (PWR_CR2_PLS_LEV0) | 44 | #define STM32_PWR_CR2 (PWR_CR2_PLS_LEV0) |
| 44 | #define STM32_PWR_CR3 (PWR_CR3_EIWF) | 45 | #define STM32_PWR_CR3 (PWR_CR3_EIWF) |
| 45 | #define STM32_PWR_CR4 (0U) | 46 | #define STM32_PWR_CR4 (0U) |
| 47 | #define STM32_PWR_PUCRA (0U) | ||
| 48 | #define STM32_PWR_PDCRA (0U) | ||
| 49 | #define STM32_PWR_PUCRB (0U) | ||
| 50 | #define STM32_PWR_PDCRB (0U) | ||
| 51 | #define STM32_PWR_PUCRC (0U) | ||
| 52 | #define STM32_PWR_PDCRC (0U) | ||
| 53 | #define STM32_PWR_PUCRD (0U) | ||
| 54 | #define STM32_PWR_PDCRD (0U) | ||
| 55 | #define STM32_PWR_PUCRE (0U) | ||
| 56 | #define STM32_PWR_PDCRE (0U) | ||
| 57 | #define STM32_PWR_PUCRF (0U) | ||
| 58 | #define STM32_PWR_PDCRF (0U) | ||
| 59 | #define STM32_PWR_PUCRG (0U) | ||
| 60 | #define STM32_PWR_PDCRG (0U) | ||
| 46 | #define STM32_HSI16_ENABLED TRUE | 61 | #define STM32_HSI16_ENABLED TRUE |
| 47 | #define STM32_HSI48_ENABLED TRUE | 62 | #define STM32_HSI48_ENABLED TRUE |
| 48 | #define STM32_HSE_ENABLED FALSE | 63 | #define STM32_HSE_ENABLED FALSE |
diff --git a/platforms/chibios/boards/GENERIC_STM32_G474XE/configs/mcuconf.h b/platforms/chibios/boards/GENERIC_STM32_G474XE/configs/mcuconf.h index 117e920e3..5710e2cb4 100644 --- a/platforms/chibios/boards/GENERIC_STM32_G474XE/configs/mcuconf.h +++ b/platforms/chibios/boards/GENERIC_STM32_G474XE/configs/mcuconf.h | |||
| @@ -42,9 +42,24 @@ | |||
| 42 | */ | 42 | */ |
| 43 | #define STM32_NO_INIT FALSE | 43 | #define STM32_NO_INIT FALSE |
| 44 | #define STM32_VOS STM32_VOS_RANGE1 | 44 | #define STM32_VOS STM32_VOS_RANGE1 |
| 45 | #define STM32_PWR_BOOST TRUE | ||
| 45 | #define STM32_PWR_CR2 (PWR_CR2_PLS_LEV0) | 46 | #define STM32_PWR_CR2 (PWR_CR2_PLS_LEV0) |
| 46 | #define STM32_PWR_CR3 (PWR_CR3_EIWF) | 47 | #define STM32_PWR_CR3 (PWR_CR3_EIWF) |
| 47 | #define STM32_PWR_CR4 (0U) | 48 | #define STM32_PWR_CR4 (0U) |
| 49 | #define STM32_PWR_PUCRA (0U) | ||
| 50 | #define STM32_PWR_PDCRA (0U) | ||
| 51 | #define STM32_PWR_PUCRB (0U) | ||
| 52 | #define STM32_PWR_PDCRB (0U) | ||
| 53 | #define STM32_PWR_PUCRC (0U) | ||
| 54 | #define STM32_PWR_PDCRC (0U) | ||
| 55 | #define STM32_PWR_PUCRD (0U) | ||
| 56 | #define STM32_PWR_PDCRD (0U) | ||
| 57 | #define STM32_PWR_PUCRE (0U) | ||
| 58 | #define STM32_PWR_PDCRE (0U) | ||
| 59 | #define STM32_PWR_PUCRF (0U) | ||
| 60 | #define STM32_PWR_PDCRF (0U) | ||
| 61 | #define STM32_PWR_PUCRG (0U) | ||
| 62 | #define STM32_PWR_PDCRG (0U) | ||
| 48 | #define STM32_HSI16_ENABLED TRUE | 63 | #define STM32_HSI16_ENABLED TRUE |
| 49 | #define STM32_HSI48_ENABLED TRUE | 64 | #define STM32_HSI48_ENABLED TRUE |
| 50 | #define STM32_HSE_ENABLED FALSE | 65 | #define STM32_HSE_ENABLED FALSE |
diff --git a/platforms/chibios/boards/QMK_PROTON_C/configs/chconf.h b/platforms/chibios/boards/QMK_PROTON_C/configs/chconf.h index a1cbf6808..f81233296 100644 --- a/platforms/chibios/boards/QMK_PROTON_C/configs/chconf.h +++ b/platforms/chibios/boards/QMK_PROTON_C/configs/chconf.h | |||
| @@ -40,7 +40,7 @@ | |||
| 40 | 40 | ||
| 41 | /** | 41 | /** |
| 42 | * @brief System time counter resolution. | 42 | * @brief System time counter resolution. |
| 43 | * @note Allowed values are 16 or 32 bits. | 43 | * @note Allowed values are 16, 32 or 64 bits. |
| 44 | */ | 44 | */ |
| 45 | #if !defined(CH_CFG_ST_RESOLUTION) | 45 | #if !defined(CH_CFG_ST_RESOLUTION) |
| 46 | #define CH_CFG_ST_RESOLUTION 32 | 46 | #define CH_CFG_ST_RESOLUTION 32 |
diff --git a/platforms/chibios/boards/QMK_PROTON_C/configs/config.h b/platforms/chibios/boards/QMK_PROTON_C/configs/config.h index a73f0c0b4..fa1a73c35 100644 --- a/platforms/chibios/boards/QMK_PROTON_C/configs/config.h +++ b/platforms/chibios/boards/QMK_PROTON_C/configs/config.h | |||
| @@ -18,3 +18,12 @@ | |||
| 18 | #ifndef EARLY_INIT_PERFORM_BOOTLOADER_JUMP | 18 | #ifndef EARLY_INIT_PERFORM_BOOTLOADER_JUMP |
| 19 | # define EARLY_INIT_PERFORM_BOOTLOADER_JUMP TRUE | 19 | # define EARLY_INIT_PERFORM_BOOTLOADER_JUMP TRUE |
| 20 | #endif | 20 | #endif |
| 21 | |||
| 22 | #ifdef CONVERT_TO_PROTON_C | ||
| 23 | # ifndef I2C1_SDA_PIN | ||
| 24 | # define I2C1_SDA_PIN D1 | ||
| 25 | # endif | ||
| 26 | # ifndef I2C1_SCL_PIN | ||
| 27 | # define I2C1_SCL_PIN D0 | ||
| 28 | # endif | ||
| 29 | #endif | ||
diff --git a/platforms/chibios/boards/SIPEED_LONGAN_NANO/board/board.mk b/platforms/chibios/boards/SIPEED_LONGAN_NANO/board/board.mk new file mode 100644 index 000000000..960fc2678 --- /dev/null +++ b/platforms/chibios/boards/SIPEED_LONGAN_NANO/board/board.mk | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | # List of all the board related files. | ||
| 2 | BOARDSRC = ${CHIBIOS_CONTRIB}/os/hal/boards/SIPEED_LONGAN_NANO/board.c | ||
| 3 | |||
| 4 | # Required include directories | ||
| 5 | BOARDINC = ${CHIBIOS_CONTRIB}/os/hal/boards/SIPEED_LONGAN_NANO | ||
| 6 | |||
| 7 | # Shared variables | ||
| 8 | ALLCSRC += $(BOARDSRC) | ||
| 9 | ALLINC += $(BOARDINC) | ||
diff --git a/platforms/chibios/boards/SIPEED_LONGAN_NANO/configs/chconf.h b/platforms/chibios/boards/SIPEED_LONGAN_NANO/configs/chconf.h new file mode 100644 index 000000000..6e5adb0fe --- /dev/null +++ b/platforms/chibios/boards/SIPEED_LONGAN_NANO/configs/chconf.h | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | /* Copyright 2021 QMK | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 2 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | /* To compile the ChibiOS syscall stubs with picolibc | ||
| 18 | * the _reent struct has to be defined. */ | ||
| 19 | #if !defined(_FROM_ASM_) && defined(USE_PICOLIBC) | ||
| 20 | struct _reent; | ||
| 21 | #endif | ||
| 22 | |||
| 23 | #include_next <chconf.h> \ No newline at end of file | ||
diff --git a/platforms/chibios/boards/SIPEED_LONGAN_NANO/configs/mcuconf.h b/platforms/chibios/boards/SIPEED_LONGAN_NANO/configs/mcuconf.h new file mode 100644 index 000000000..ab086567e --- /dev/null +++ b/platforms/chibios/boards/SIPEED_LONGAN_NANO/configs/mcuconf.h | |||
| @@ -0,0 +1,302 @@ | |||
| 1 | /* | ||
| 2 | ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio | ||
| 3 | ChibiOS - Copyright (C) 2021 Stefan Kerkmann | ||
| 4 | |||
| 5 | Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 6 | you may not use this file except in compliance with the License. | ||
| 7 | You may obtain a copy of the License at | ||
| 8 | |||
| 9 | http://www.apache.org/licenses/LICENSE-2.0 | ||
| 10 | |||
| 11 | Unless required by applicable law or agreed to in writing, software | ||
| 12 | distributed under the License is distributed on an "AS IS" BASIS, | ||
| 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 14 | See the License for the specific language governing permissions and | ||
| 15 | limitations under the License. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #pragma once | ||
| 19 | |||
| 20 | #define GD32VF103_MCUCONF | ||
| 21 | #define GD32VF103CB | ||
| 22 | |||
| 23 | /* | ||
| 24 | * GD32VF103 drivers configuration. | ||
| 25 | * The following settings override the default settings present in | ||
| 26 | * the various device driver implementation headers. | ||
| 27 | * Note that the settings for each driver only have effect if the whole | ||
| 28 | * driver is enabled in halconf.h. | ||
| 29 | * | ||
| 30 | * IRQ priorities: | ||
| 31 | * 0...15 Lowest...Highest. | ||
| 32 | * | ||
| 33 | * DMA priorities: | ||
| 34 | * 0...3 Lowest...Highest. | ||
| 35 | */ | ||
| 36 | |||
| 37 | /* | ||
| 38 | * HAL driver system settings. | ||
| 39 | */ | ||
| 40 | |||
| 41 | #if defined(OVERCLOCK_120MHZ) | ||
| 42 | /* (8MHz / 2) * 30 = 120MHz Sysclock */ | ||
| 43 | #define GD32_ALLOW_120MHZ_SYSCLK | ||
| 44 | #define GD32_PLLMF_VALUE 30 | ||
| 45 | #define GD32_USBFSPSC GD32_USBFSPSC_DIV2P5 | ||
| 46 | #else | ||
| 47 | /* (8MHz / 2) * 24 = 96MHz Sysclock */ | ||
| 48 | #define GD32_PLLMF_VALUE 24 | ||
| 49 | #define GD32_USBFSPSC GD32_USBFSPSC_DIV2 | ||
| 50 | #endif | ||
| 51 | |||
| 52 | #define GD32_NO_INIT FALSE | ||
| 53 | #define GD32_IRC8M_ENABLED TRUE | ||
| 54 | #define GD32_IRC40K_ENABLED FALSE | ||
| 55 | #define GD32_HXTAL_ENABLED TRUE | ||
| 56 | #define GD32_LXTAL_ENABLED FALSE | ||
| 57 | #define GD32_SCS GD32_SCS_PLL | ||
| 58 | #define GD32_PLLSEL GD32_PLLSEL_PREDV0 | ||
| 59 | #define GD32_PREDV0SEL GD32_PREDV0SEL_HXTAL | ||
| 60 | #define GD32_PREDV0_VALUE 2 | ||
| 61 | #define GD32_PREDV1_VALUE 2 | ||
| 62 | #define GD32_PLL1MF_VALUE 14 | ||
| 63 | #define GD32_PLL2MF_VALUE 13 | ||
| 64 | #define GD32_AHBPSC GD32_AHBPSC_DIV1 | ||
| 65 | #define GD32_APB1PSC GD32_APB1PSC_DIV2 | ||
| 66 | #define GD32_APB2PSC GD32_APB2PSC_DIV1 | ||
| 67 | #define GD32_ADCPSC GD32_ADCPSC_DIV16 | ||
| 68 | #define GD32_USB_CLOCK_REQUIRED TRUE | ||
| 69 | #define GD32_I2S_CLOCK_REQUIRED FALSE | ||
| 70 | #define GD32_CKOUT0SEL GD32_CKOUT0SEL_NOCLOCK | ||
| 71 | #define GD32_RTCSRC GD32_RTCSRC_NOCLOCK | ||
| 72 | #define GD32_PVD_ENABLE FALSE | ||
| 73 | #define GD32_LVDT GD32_LVDT_LEV0 | ||
| 74 | |||
| 75 | /* | ||
| 76 | * ECLIC system settings. | ||
| 77 | */ | ||
| 78 | #define ECLIC_TRIGGER_DEFAULT ECLIC_POSTIVE_EDGE_TRIGGER | ||
| 79 | #define ECLIC_DMA_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 80 | |||
| 81 | /* | ||
| 82 | * IRQ system settings. | ||
| 83 | */ | ||
| 84 | #define GD32_IRQ_EXTI0_PRIORITY 6 | ||
| 85 | #define GD32_IRQ_EXTI1_PRIORITY 6 | ||
| 86 | #define GD32_IRQ_EXTI2_PRIORITY 6 | ||
| 87 | #define GD32_IRQ_EXTI3_PRIORITY 6 | ||
| 88 | #define GD32_IRQ_EXTI4_PRIORITY 6 | ||
| 89 | #define GD32_IRQ_EXTI5_9_PRIORITY 6 | ||
| 90 | #define GD32_IRQ_EXTI10_15_PRIORITY 6 | ||
| 91 | #define GD32_IRQ_EXTI0_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 92 | #define GD32_IRQ_EXTI1_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 93 | #define GD32_IRQ_EXTI2_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 94 | #define GD32_IRQ_EXTI3_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 95 | #define GD32_IRQ_EXTI4_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 96 | #define GD32_IRQ_EXTI5_9_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 97 | #define GD32_IRQ_EXTI10_15_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 98 | |||
| 99 | /* | ||
| 100 | * ADC driver system settings. | ||
| 101 | */ | ||
| 102 | #define GD32_ADC_USE_ADC0 FALSE | ||
| 103 | #define GD32_ADC_ADC0_DMA_PRIORITY 2 | ||
| 104 | #define GD32_ADC_ADC0_IRQ_PRIORITY 6 | ||
| 105 | |||
| 106 | /* | ||
| 107 | * CAN driver system settings. | ||
| 108 | */ | ||
| 109 | #define GD32_CAN_USE_CAN0 FALSE | ||
| 110 | #define GD32_CAN_CAN0_IRQ_PRIORITY 11 | ||
| 111 | #define GD32_CAN_USE_CAN1 FALSE | ||
| 112 | #define GD32_CAN_CAN1_IRQ_PRIORITY 11 | ||
| 113 | #define GD32_CAN_CAN0_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 114 | #define GD32_CAN_CAN1_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 115 | |||
| 116 | /* | ||
| 117 | * CRC driver system settings. | ||
| 118 | */ | ||
| 119 | #define GD32_CRC_USE_CRC0 FALSE | ||
| 120 | #define GD32_CRC_CRC0_DMA_IRQ_PRIORITY 14 | ||
| 121 | #define GD32_CRC_CRC0_DMA_PRIORITY 2 | ||
| 122 | #define GD32_CRC_CRC0_DMA_STREAM GD32_DMA_STREAM_ID(0, 0) | ||
| 123 | #define CRC_USE_DMA FALSE | ||
| 124 | #define CRCSW_USE_CRC1 FALSE | ||
| 125 | #define CRCSW_CRC32_TABLE FALSE | ||
| 126 | #define CRCSW_CRC16_TABLE FALSE | ||
| 127 | #define CRCSW_PROGRAMMABLE FALSE | ||
| 128 | |||
| 129 | /* | ||
| 130 | * DAC driver system settings. | ||
| 131 | */ | ||
| 132 | #define GD32_DAC_USE_DAC_CH1 FALSE | ||
| 133 | #define GD32_DAC_USE_DAC_CH2 FALSE | ||
| 134 | |||
| 135 | /* | ||
| 136 | * GPT driver system settings. | ||
| 137 | */ | ||
| 138 | #define GD32_GPT_USE_TIM0 FALSE | ||
| 139 | #define GD32_GPT_USE_TIM1 FALSE | ||
| 140 | #define GD32_GPT_USE_TIM2 FALSE | ||
| 141 | #define GD32_GPT_USE_TIM3 FALSE | ||
| 142 | #define GD32_GPT_USE_TIM4 FALSE | ||
| 143 | #define GD32_GPT_TIM0_IRQ_PRIORITY 7 | ||
| 144 | #define GD32_GPT_TIM1_IRQ_PRIORITY 7 | ||
| 145 | #define GD32_GPT_TIM2_IRQ_PRIORITY 7 | ||
| 146 | #define GD32_GPT_TIM3_IRQ_PRIORITY 7 | ||
| 147 | #define GD32_GPT_TIM4_IRQ_PRIORITY 7 | ||
| 148 | #define GD32_GPT_TIM0_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 149 | #define GD32_GPT_TIM1_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 150 | #define GD32_GPT_TIM2_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 151 | #define GD32_GPT_TIM3_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 152 | #define GD32_GPT_TIM4_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 153 | #define GD32_GPT_TIM5_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 154 | #define GD32_GPT_TIM6_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 155 | |||
| 156 | /* | ||
| 157 | * I2S driver system settings. | ||
| 158 | */ | ||
| 159 | #define GD32_I2S_USE_SPI1 FALSE | ||
| 160 | #define GD32_I2S_USE_SPI2 FALSE | ||
| 161 | #define GD32_I2S_SPI1_IRQ_PRIORITY 10 | ||
| 162 | #define GD32_I2S_SPI2_IRQ_PRIORITY 10 | ||
| 163 | #define GD32_I2S_SPI1_DMA_PRIORITY 1 | ||
| 164 | #define GD32_I2S_SPI2_DMA_PRIORITY 1 | ||
| 165 | #define GD32_I2S_DMA_ERROR_HOOK(i2sp) osalSysHalt("DMA failure") | ||
| 166 | |||
| 167 | /* | ||
| 168 | * I2C driver system settings. | ||
| 169 | */ | ||
| 170 | #define GD32_I2C_USE_I2C0 FALSE | ||
| 171 | #define GD32_I2C_USE_I2C1 FALSE | ||
| 172 | #define GD32_I2C_BUSY_TIMEOUT 50 | ||
| 173 | #define GD32_I2C_I2C0_IRQ_PRIORITY 10 | ||
| 174 | #define GD32_I2C_I2C1_IRQ_PRIORITY 5 | ||
| 175 | #define GD32_I2C_I2C0_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 176 | #define GD32_I2C_I2C1_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 177 | #define GD32_I2C_I2C0_DMA_PRIORITY 2 | ||
| 178 | #define GD32_I2C_I2C1_DMA_PRIORITY 2 | ||
| 179 | #define GD32_I2C_DMA_ERROR_HOOK(i2cp) osalSysHalt("DMA failure") | ||
| 180 | |||
| 181 | /* | ||
| 182 | * ICU driver system settings. | ||
| 183 | */ | ||
| 184 | #define GD32_ICU_USE_TIM0 FALSE | ||
| 185 | #define GD32_ICU_USE_TIM1 FALSE | ||
| 186 | #define GD32_ICU_USE_TIM2 FALSE | ||
| 187 | #define GD32_ICU_USE_TIM3 FALSE | ||
| 188 | #define GD32_ICU_USE_TIM4 FALSE | ||
| 189 | #define GD32_ICU_TIM0_IRQ_PRIORITY 7 | ||
| 190 | #define GD32_ICU_TIM1_IRQ_PRIORITY 7 | ||
| 191 | #define GD32_ICU_TIM2_IRQ_PRIORITY 7 | ||
| 192 | #define GD32_ICU_TIM3_IRQ_PRIORITY 7 | ||
| 193 | #define GD32_ICU_TIM4_IRQ_PRIORITY 7 | ||
| 194 | #define GD32_ICU_TIM0_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 195 | #define GD32_ICU_TIM1_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 196 | #define GD32_ICU_TIM2_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 197 | #define GD32_ICU_TIM3_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 198 | #define GD32_ICU_TIM4_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 199 | |||
| 200 | /* | ||
| 201 | * PWM driver system settings. | ||
| 202 | */ | ||
| 203 | #define GD32_PWM_USE_ADVANCED FALSE | ||
| 204 | #define GD32_PWM_USE_TIM0 FALSE | ||
| 205 | #define GD32_PWM_USE_TIM1 FALSE | ||
| 206 | #define GD32_PWM_USE_TIM2 FALSE | ||
| 207 | #define GD32_PWM_USE_TIM3 FALSE | ||
| 208 | #define GD32_PWM_USE_TIM4 FALSE | ||
| 209 | #define GD32_PWM_TIM0_IRQ_PRIORITY 10 | ||
| 210 | #define GD32_PWM_TIM1_IRQ_PRIORITY 10 | ||
| 211 | #define GD32_PWM_TIM2_IRQ_PRIORITY 10 | ||
| 212 | #define GD32_PWM_TIM3_IRQ_PRIORITY 10 | ||
| 213 | #define GD32_PWM_TIM4_IRQ_PRIORITY 10 | ||
| 214 | #define GD32_PWM_TIM0_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 215 | #define GD32_PWM_TIM1_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 216 | #define GD32_PWM_TIM2_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 217 | #define GD32_PWM_TIM3_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 218 | #define GD32_PWM_TIM4_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 219 | |||
| 220 | /* | ||
| 221 | * RTC driver system settings. | ||
| 222 | */ | ||
| 223 | #define GD32_RTC_IRQ_PRIORITY 15 | ||
| 224 | #define GD32_RTC_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 225 | |||
| 226 | /* | ||
| 227 | * SERIAL driver system settings. | ||
| 228 | */ | ||
| 229 | #define GD32_SERIAL_USE_USART0 FALSE | ||
| 230 | #define GD32_SERIAL_USE_USART1 FALSE | ||
| 231 | #define GD32_SERIAL_USE_USART2 FALSE | ||
| 232 | #define GD32_SERIAL_USE_UART3 FALSE | ||
| 233 | #define GD32_SERIAL_USE_UART4 FALSE | ||
| 234 | #define GD32_SERIAL_USART0_PRIORITY 10 | ||
| 235 | #define GD32_SERIAL_USART1_PRIORITY 10 | ||
| 236 | #define GD32_SERIAL_USART2_PRIORITY 10 | ||
| 237 | #define GD32_SERIAL_UART3_PRIORITY 10 | ||
| 238 | #define GD32_SERIAL_UART4_PRIORITY 10 | ||
| 239 | #define GD32_SERIAL_USART0_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 240 | #define GD32_SERIAL_USART1_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 241 | #define GD32_SERIAL_USART2_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 242 | #define GD32_SERIAL_UART3_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 243 | #define GD32_SERIAL_UART4_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 244 | |||
| 245 | /* | ||
| 246 | * SPI driver system settings. | ||
| 247 | */ | ||
| 248 | #define GD32_SPI_USE_SPI0 FALSE | ||
| 249 | #define GD32_SPI_USE_SPI1 FALSE | ||
| 250 | #define GD32_SPI_USE_SPI2 FALSE | ||
| 251 | #define GD32_SPI_SPI0_DMA_PRIORITY 1 | ||
| 252 | #define GD32_SPI_SPI1_DMA_PRIORITY 1 | ||
| 253 | #define GD32_SPI_SPI2_DMA_PRIORITY 1 | ||
| 254 | #define GD32_SPI_SPI0_IRQ_PRIORITY 10 | ||
| 255 | #define GD32_SPI_SPI1_IRQ_PRIORITY 10 | ||
| 256 | #define GD32_SPI_SPI2_IRQ_PRIORITY 10 | ||
| 257 | #define GD32_SPI_DMA_ERROR_HOOK(spip) osalSysHalt("DMA failure") | ||
| 258 | |||
| 259 | /* | ||
| 260 | * ST driver system settings. | ||
| 261 | */ | ||
| 262 | #define GD32_ST_IRQ_PRIORITY 10 | ||
| 263 | #define GD32_ST_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 264 | #define GD32_ST_USE_TIMER 1 | ||
| 265 | |||
| 266 | /* | ||
| 267 | * UART driver system settings. | ||
| 268 | */ | ||
| 269 | #define GD32_UART_USE_USART0 FALSE | ||
| 270 | #define GD32_UART_USE_USART1 FALSE | ||
| 271 | #define GD32_UART_USE_USART2 FALSE | ||
| 272 | #define GD32_UART_USE_UART3 FALSE | ||
| 273 | #define GD32_UART_USE_UART4 FALSE | ||
| 274 | #define GD32_UART_USART0_IRQ_PRIORITY 10 | ||
| 275 | #define GD32_UART_USART1_IRQ_PRIORITY 10 | ||
| 276 | #define GD32_UART_USART2_IRQ_PRIORITY 10 | ||
| 277 | #define GD32_UART_UART3_IRQ_PRIORITY 10 | ||
| 278 | #define GD32_UART_UART4_IRQ_PRIORITY 10 | ||
| 279 | #define GD32_UART_USART0_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 280 | #define GD32_UART_USART1_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 281 | #define GD32_UART_USART2_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 282 | #define GD32_UART_UART3_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 283 | #define GD32_UART_UART4_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 284 | #define GD32_UART_USART0_DMA_PRIORITY 3 | ||
| 285 | #define GD32_UART_USART1_DMA_PRIORITY 3 | ||
| 286 | #define GD32_UART_USART2_DMA_PRIORITY 3 | ||
| 287 | #define GD32_UART_UART3_DMA_PRIORITY 3 | ||
| 288 | #define GD32_UART_UART4_DMA_PRIORITY 3 | ||
| 289 | #define GD32_UART_DMA_ERROR_HOOK(uartp) osalSysHalt("DMA failure") | ||
| 290 | |||
| 291 | /* | ||
| 292 | * USB driver system settings. | ||
| 293 | */ | ||
| 294 | #define GD32_USB_USE_USBFS TRUE | ||
| 295 | #define GD32_USB_USBFS_IRQ_PRIORITY 10 | ||
| 296 | #define GD32_USB_USBFS_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
| 297 | #define GD32_USB_USBFS_RX_FIFO_SIZE 256 | ||
| 298 | |||
| 299 | /* | ||
| 300 | * WDG driver system settings. | ||
| 301 | */ | ||
| 302 | #define GD32_WDG_USE_FWDGT FALSE | ||
diff --git a/platforms/chibios/boards/common/configs/chconf.h b/platforms/chibios/boards/common/configs/chconf.h index 44327a82d..18ad609ca 100644 --- a/platforms/chibios/boards/common/configs/chconf.h +++ b/platforms/chibios/boards/common/configs/chconf.h | |||
| @@ -40,7 +40,7 @@ | |||
| 40 | 40 | ||
| 41 | /** | 41 | /** |
| 42 | * @brief System time counter resolution. | 42 | * @brief System time counter resolution. |
| 43 | * @note Allowed values are 16 or 32 bits. | 43 | * @note Allowed values are 16, 32 or 64 bits. |
| 44 | */ | 44 | */ |
| 45 | #if !defined(CH_CFG_ST_RESOLUTION) | 45 | #if !defined(CH_CFG_ST_RESOLUTION) |
| 46 | #define CH_CFG_ST_RESOLUTION 32 | 46 | #define CH_CFG_ST_RESOLUTION 32 |
diff --git a/platforms/chibios/boards/common/ld/STM32F401xC.ld b/platforms/chibios/boards/common/ld/STM32F401xC.ld new file mode 100644 index 000000000..8fae66cec --- /dev/null +++ b/platforms/chibios/boards/common/ld/STM32F401xC.ld | |||
| @@ -0,0 +1,85 @@ | |||
| 1 | /* | ||
| 2 | ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio | ||
| 3 | |||
| 4 | Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | you may not use this file except in compliance with the License. | ||
| 6 | You may obtain a copy of the License at | ||
| 7 | |||
| 8 | http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | |||
| 10 | Unless required by applicable law or agreed to in writing, software | ||
| 11 | distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | See the License for the specific language governing permissions and | ||
| 14 | limitations under the License. | ||
| 15 | */ | ||
| 16 | |||
| 17 | /* | ||
| 18 | * STM32F401xC memory setup. | ||
| 19 | */ | ||
| 20 | MEMORY | ||
| 21 | { | ||
| 22 | flash0 (rx) : org = 0x08000000, len = 16k /* Sector 0 - Init code as ROM bootloader assumes application starts here */ | ||
| 23 | flash1 (rx) : org = 0x08004000, len = 16k /* Sector 1 - Emulated eeprom */ | ||
| 24 | flash2 (rx) : org = 0x08008000, len = 256k - 32k /* Sector 2..6 - Rest of firmware */ | ||
| 25 | flash3 (rx) : org = 0x00000000, len = 0 | ||
| 26 | flash4 (rx) : org = 0x00000000, len = 0 | ||
| 27 | flash5 (rx) : org = 0x00000000, len = 0 | ||
| 28 | flash6 (rx) : org = 0x00000000, len = 0 | ||
| 29 | flash7 (rx) : org = 0x00000000, len = 0 | ||
| 30 | ram0 (wx) : org = 0x20000000, len = 64k | ||
| 31 | ram1 (wx) : org = 0x00000000, len = 0 | ||
| 32 | ram2 (wx) : org = 0x00000000, len = 0 | ||
| 33 | ram3 (wx) : org = 0x00000000, len = 0 | ||
| 34 | ram4 (wx) : org = 0x00000000, len = 0 | ||
| 35 | ram5 (wx) : org = 0x00000000, len = 0 | ||
| 36 | ram6 (wx) : org = 0x00000000, len = 0 | ||
| 37 | ram7 (wx) : org = 0x00000000, len = 0 | ||
| 38 | } | ||
| 39 | |||
| 40 | /* For each data/text section two region are defined, a virtual region | ||
| 41 | and a load region (_LMA suffix).*/ | ||
| 42 | |||
| 43 | /* Flash region to be used for exception vectors.*/ | ||
| 44 | REGION_ALIAS("VECTORS_FLASH", flash0); | ||
| 45 | REGION_ALIAS("VECTORS_FLASH_LMA", flash0); | ||
| 46 | |||
| 47 | /* Flash region to be used for constructors and destructors.*/ | ||
| 48 | REGION_ALIAS("XTORS_FLASH", flash2); | ||
| 49 | REGION_ALIAS("XTORS_FLASH_LMA", flash2); | ||
| 50 | |||
| 51 | /* Flash region to be used for code text.*/ | ||
| 52 | REGION_ALIAS("TEXT_FLASH", flash2); | ||
| 53 | REGION_ALIAS("TEXT_FLASH_LMA", flash2); | ||
| 54 | |||
| 55 | /* Flash region to be used for read only data.*/ | ||
| 56 | REGION_ALIAS("RODATA_FLASH", flash2); | ||
| 57 | REGION_ALIAS("RODATA_FLASH_LMA", flash2); | ||
| 58 | |||
| 59 | /* Flash region to be used for various.*/ | ||
| 60 | REGION_ALIAS("VARIOUS_FLASH", flash2); | ||
| 61 | REGION_ALIAS("VARIOUS_FLASH_LMA", flash2); | ||
| 62 | |||
| 63 | /* Flash region to be used for RAM(n) initialization data.*/ | ||
| 64 | REGION_ALIAS("RAM_INIT_FLASH_LMA", flash2); | ||
| 65 | |||
| 66 | /* RAM region to be used for Main stack. This stack accommodates the processing | ||
| 67 | of all exceptions and interrupts.*/ | ||
| 68 | REGION_ALIAS("MAIN_STACK_RAM", ram0); | ||
| 69 | |||
| 70 | /* RAM region to be used for the process stack. This is the stack used by | ||
| 71 | the main() function.*/ | ||
| 72 | REGION_ALIAS("PROCESS_STACK_RAM", ram0); | ||
| 73 | |||
| 74 | /* RAM region to be used for data segment.*/ | ||
| 75 | REGION_ALIAS("DATA_RAM", ram0); | ||
| 76 | REGION_ALIAS("DATA_RAM_LMA", flash2); | ||
| 77 | |||
| 78 | /* RAM region to be used for BSS segment.*/ | ||
| 79 | REGION_ALIAS("BSS_RAM", ram0); | ||
| 80 | |||
| 81 | /* RAM region to be used for the default heap.*/ | ||
| 82 | REGION_ALIAS("HEAP_RAM", ram0); | ||
| 83 | |||
| 84 | /* Generic rules inclusion.*/ | ||
| 85 | INCLUDE rules.ld | ||
diff --git a/platforms/chibios/boards/common/ld/STM32F401xE.ld b/platforms/chibios/boards/common/ld/STM32F401xE.ld new file mode 100644 index 000000000..69af7ed71 --- /dev/null +++ b/platforms/chibios/boards/common/ld/STM32F401xE.ld | |||
| @@ -0,0 +1,85 @@ | |||
| 1 | /* | ||
| 2 | ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio | ||
| 3 | |||
| 4 | Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | you may not use this file except in compliance with the License. | ||
| 6 | You may obtain a copy of the License at | ||
| 7 | |||
| 8 | http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | |||
| 10 | Unless required by applicable law or agreed to in writing, software | ||
| 11 | distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | See the License for the specific language governing permissions and | ||
| 14 | limitations under the License. | ||
| 15 | */ | ||
| 16 | |||
| 17 | /* | ||
| 18 | * STM32F401xE memory setup. | ||
| 19 | */ | ||
| 20 | MEMORY | ||
| 21 | { | ||
| 22 | flash0 (rx) : org = 0x08000000, len = 16k /* Sector 0 - Init code as ROM bootloader assumes application starts here */ | ||
| 23 | flash1 (rx) : org = 0x08004000, len = 16k /* Sector 1 - Emulated eeprom */ | ||
| 24 | flash2 (rx) : org = 0x08008000, len = 512k - 32k /* Sector 2..7 - Rest of firmware */ | ||
| 25 | flash3 (rx) : org = 0x00000000, len = 0 | ||
| 26 | flash4 (rx) : org = 0x00000000, len = 0 | ||
| 27 | flash5 (rx) : org = 0x00000000, len = 0 | ||
| 28 | flash6 (rx) : org = 0x00000000, len = 0 | ||
| 29 | flash7 (rx) : org = 0x00000000, len = 0 | ||
| 30 | ram0 (wx) : org = 0x20000000, len = 96k | ||
| 31 | ram1 (wx) : org = 0x00000000, len = 0 | ||
| 32 | ram2 (wx) : org = 0x00000000, len = 0 | ||
| 33 | ram3 (wx) : org = 0x00000000, len = 0 | ||
| 34 | ram4 (wx) : org = 0x00000000, len = 0 | ||
| 35 | ram5 (wx) : org = 0x00000000, len = 0 | ||
| 36 | ram6 (wx) : org = 0x00000000, len = 0 | ||
| 37 | ram7 (wx) : org = 0x00000000, len = 0 | ||
| 38 | } | ||
| 39 | |||
| 40 | /* For each data/text section two region are defined, a virtual region | ||
| 41 | and a load region (_LMA suffix).*/ | ||
| 42 | |||
| 43 | /* Flash region to be used for exception vectors.*/ | ||
| 44 | REGION_ALIAS("VECTORS_FLASH", flash0); | ||
| 45 | REGION_ALIAS("VECTORS_FLASH_LMA", flash0); | ||
| 46 | |||
| 47 | /* Flash region to be used for constructors and destructors.*/ | ||
| 48 | REGION_ALIAS("XTORS_FLASH", flash2); | ||
| 49 | REGION_ALIAS("XTORS_FLASH_LMA", flash2); | ||
| 50 | |||
| 51 | /* Flash region to be used for code text.*/ | ||
| 52 | REGION_ALIAS("TEXT_FLASH", flash2); | ||
| 53 | REGION_ALIAS("TEXT_FLASH_LMA", flash2); | ||
| 54 | |||
| 55 | /* Flash region to be used for read only data.*/ | ||
| 56 | REGION_ALIAS("RODATA_FLASH", flash2); | ||
| 57 | REGION_ALIAS("RODATA_FLASH_LMA", flash2); | ||
| 58 | |||
| 59 | /* Flash region to be used for various.*/ | ||
| 60 | REGION_ALIAS("VARIOUS_FLASH", flash2); | ||
| 61 | REGION_ALIAS("VARIOUS_FLASH_LMA", flash2); | ||
| 62 | |||
| 63 | /* Flash region to be used for RAM(n) initialization data.*/ | ||
| 64 | REGION_ALIAS("RAM_INIT_FLASH_LMA", flash2); | ||
| 65 | |||
| 66 | /* RAM region to be used for Main stack. This stack accommodates the processing | ||
| 67 | of all exceptions and interrupts.*/ | ||
| 68 | REGION_ALIAS("MAIN_STACK_RAM", ram0); | ||
| 69 | |||
| 70 | /* RAM region to be used for the process stack. This is the stack used by | ||
| 71 | the main() function.*/ | ||
| 72 | REGION_ALIAS("PROCESS_STACK_RAM", ram0); | ||
| 73 | |||
| 74 | /* RAM region to be used for data segment.*/ | ||
| 75 | REGION_ALIAS("DATA_RAM", ram0); | ||
| 76 | REGION_ALIAS("DATA_RAM_LMA", flash2); | ||
| 77 | |||
| 78 | /* RAM region to be used for BSS segment.*/ | ||
| 79 | REGION_ALIAS("BSS_RAM", ram0); | ||
| 80 | |||
| 81 | /* RAM region to be used for the default heap.*/ | ||
| 82 | REGION_ALIAS("HEAP_RAM", ram0); | ||
| 83 | |||
| 84 | /* Generic rules inclusion.*/ | ||
| 85 | INCLUDE rules.ld | ||
diff --git a/platforms/chibios/boards/common/ld/STM32F405xG.ld b/platforms/chibios/boards/common/ld/STM32F405xG.ld new file mode 100644 index 000000000..b7d0baa21 --- /dev/null +++ b/platforms/chibios/boards/common/ld/STM32F405xG.ld | |||
| @@ -0,0 +1,86 @@ | |||
| 1 | /* | ||
| 2 | ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio | ||
| 3 | |||
| 4 | Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | you may not use this file except in compliance with the License. | ||
| 6 | You may obtain a copy of the License at | ||
| 7 | |||
| 8 | http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | |||
| 10 | Unless required by applicable law or agreed to in writing, software | ||
| 11 | distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | See the License for the specific language governing permissions and | ||
| 14 | limitations under the License. | ||
| 15 | */ | ||
| 16 | |||
| 17 | /* | ||
| 18 | * STM32F405xG memory setup. | ||
| 19 | * Note: Use of ram1 and ram2 is mutually exclusive with use of ram0. | ||
| 20 | */ | ||
| 21 | MEMORY | ||
| 22 | { | ||
| 23 | flash0 (rx) : org = 0x08000000, len = 16k /* Sector 0 - Init code as ROM bootloader assumes application starts here */ | ||
| 24 | flash1 (rx) : org = 0x08004000, len = 16k /* Sector 1 - Emulated eeprom */ | ||
| 25 | flash2 (rx) : org = 0x08008000, len = 1M - 32k /* Sector 2..6 - Rest of firmware */ | ||
| 26 | flash3 (rx) : org = 0x00000000, len = 0 | ||
| 27 | flash4 (rx) : org = 0x00000000, len = 0 | ||
| 28 | flash5 (rx) : org = 0x00000000, len = 0 | ||
| 29 | flash6 (rx) : org = 0x00000000, len = 0 | ||
| 30 | flash7 (rx) : org = 0x00000000, len = 0 | ||
| 31 | ram0 (wx) : org = 0x20000000, len = 128k /* SRAM1 + SRAM2 */ | ||
| 32 | ram1 (wx) : org = 0x20000000, len = 112k /* SRAM1 */ | ||
| 33 | ram2 (wx) : org = 0x2001C000, len = 16k /* SRAM2 */ | ||
| 34 | ram3 (wx) : org = 0x00000000, len = 0 | ||
| 35 | ram4 (wx) : org = 0x10000000, len = 64k /* CCM SRAM */ | ||
| 36 | ram5 (wx) : org = 0x40024000, len = 4k /* BCKP SRAM */ | ||
| 37 | ram6 (wx) : org = 0x00000000, len = 0 | ||
| 38 | ram7 (wx) : org = 0x00000000, len = 0 | ||
| 39 | } | ||
| 40 | |||
| 41 | /* For each data/text section two region are defined, a virtual region | ||
| 42 | and a load region (_LMA suffix).*/ | ||
| 43 | |||
| 44 | /* Flash region to be used for exception vectors.*/ | ||
| 45 | REGION_ALIAS("VECTORS_FLASH", flash0); | ||
| 46 | REGION_ALIAS("VECTORS_FLASH_LMA", flash0); | ||
| 47 | |||
| 48 | /* Flash region to be used for constructors and destructors.*/ | ||
| 49 | REGION_ALIAS("XTORS_FLASH", flash2); | ||
| 50 | REGION_ALIAS("XTORS_FLASH_LMA", flash2); | ||
| 51 | |||
| 52 | /* Flash region to be used for code text.*/ | ||
| 53 | REGION_ALIAS("TEXT_FLASH", flash2); | ||
| 54 | REGION_ALIAS("TEXT_FLASH_LMA", flash2); | ||
| 55 | |||
| 56 | /* Flash region to be used for read only data.*/ | ||
| 57 | REGION_ALIAS("RODATA_FLASH", flash2); | ||
| 58 | REGION_ALIAS("RODATA_FLASH_LMA", flash2); | ||
| 59 | |||
| 60 | /* Flash region to be used for various.*/ | ||
| 61 | REGION_ALIAS("VARIOUS_FLASH", flash2); | ||
| 62 | REGION_ALIAS("VARIOUS_FLASH_LMA", flash2); | ||
| 63 | |||
| 64 | /* Flash region to be used for RAM(n) initialization data.*/ | ||
| 65 | REGION_ALIAS("RAM_INIT_FLASH_LMA", flash2); | ||
| 66 | |||
| 67 | /* RAM region to be used for Main stack. This stack accommodates the processing | ||
| 68 | of all exceptions and interrupts.*/ | ||
| 69 | REGION_ALIAS("MAIN_STACK_RAM", ram0); | ||
| 70 | |||
| 71 | /* RAM region to be used for the process stack. This is the stack used by | ||
| 72 | the main() function.*/ | ||
| 73 | REGION_ALIAS("PROCESS_STACK_RAM", ram0); | ||
| 74 | |||
| 75 | /* RAM region to be used for data segment.*/ | ||
| 76 | REGION_ALIAS("DATA_RAM", ram0); | ||
| 77 | REGION_ALIAS("DATA_RAM_LMA", flash2); | ||
| 78 | |||
| 79 | /* RAM region to be used for BSS segment.*/ | ||
| 80 | REGION_ALIAS("BSS_RAM", ram0); | ||
| 81 | |||
| 82 | /* RAM region to be used for the default heap.*/ | ||
| 83 | REGION_ALIAS("HEAP_RAM", ram0); | ||
| 84 | |||
| 85 | /* Generic rules inclusion.*/ | ||
| 86 | INCLUDE rules.ld | ||
diff --git a/platforms/chibios/boards/common/ld/STM32F411xE.ld b/platforms/chibios/boards/common/ld/STM32F411xE.ld new file mode 100644 index 000000000..aea8084b5 --- /dev/null +++ b/platforms/chibios/boards/common/ld/STM32F411xE.ld | |||
| @@ -0,0 +1,85 @@ | |||
| 1 | /* | ||
| 2 | ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio | ||
| 3 | |||
| 4 | Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | you may not use this file except in compliance with the License. | ||
| 6 | You may obtain a copy of the License at | ||
| 7 | |||
| 8 | http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | |||
| 10 | Unless required by applicable law or agreed to in writing, software | ||
| 11 | distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | See the License for the specific language governing permissions and | ||
| 14 | limitations under the License. | ||
| 15 | */ | ||
| 16 | |||
| 17 | /* | ||
| 18 | * STM32F411xE memory setup. | ||
| 19 | */ | ||
| 20 | MEMORY | ||
| 21 | { | ||
| 22 | flash0 (rx) : org = 0x08000000, len = 16k /* Sector 0 - Init code as ROM bootloader assumes application starts here */ | ||
| 23 | flash1 (rx) : org = 0x08004000, len = 16k /* Sector 1 - Emulated eeprom */ | ||
| 24 | flash2 (rx) : org = 0x08008000, len = 512k - 32k /* Sector 2..7 - Rest of firmware */ | ||
| 25 | flash3 (rx) : org = 0x00000000, len = 0 | ||
| 26 | flash4 (rx) : org = 0x00000000, len = 0 | ||
| 27 | flash5 (rx) : org = 0x00000000, len = 0 | ||
| 28 | flash6 (rx) : org = 0x00000000, len = 0 | ||
| 29 | flash7 (rx) : org = 0x00000000, len = 0 | ||
| 30 | ram0 (wx) : org = 0x20000000, len = 128k | ||
| 31 | ram1 (wx) : org = 0x00000000, len = 0 | ||
| 32 | ram2 (wx) : org = 0x00000000, len = 0 | ||
| 33 | ram3 (wx) : org = 0x00000000, len = 0 | ||
| 34 | ram4 (wx) : org = 0x00000000, len = 0 | ||
| 35 | ram5 (wx) : org = 0x00000000, len = 0 | ||
| 36 | ram6 (wx) : org = 0x00000000, len = 0 | ||
| 37 | ram7 (wx) : org = 0x00000000, len = 0 | ||
| 38 | } | ||
| 39 | |||
| 40 | /* For each data/text section two region are defined, a virtual region | ||
| 41 | and a load region (_LMA suffix).*/ | ||
| 42 | |||
| 43 | /* Flash region to be used for exception vectors.*/ | ||
| 44 | REGION_ALIAS("VECTORS_FLASH", flash0); | ||
| 45 | REGION_ALIAS("VECTORS_FLASH_LMA", flash0); | ||
| 46 | |||
| 47 | /* Flash region to be used for constructors and destructors.*/ | ||
| 48 | REGION_ALIAS("XTORS_FLASH", flash2); | ||
| 49 | REGION_ALIAS("XTORS_FLASH_LMA", flash2); | ||
| 50 | |||
| 51 | /* Flash region to be used for code text.*/ | ||
| 52 | REGION_ALIAS("TEXT_FLASH", flash2); | ||
| 53 | REGION_ALIAS("TEXT_FLASH_LMA", flash2); | ||
| 54 | |||
| 55 | /* Flash region to be used for read only data.*/ | ||
| 56 | REGION_ALIAS("RODATA_FLASH", flash2); | ||
| 57 | REGION_ALIAS("RODATA_FLASH_LMA", flash2); | ||
| 58 | |||
| 59 | /* Flash region to be used for various.*/ | ||
| 60 | REGION_ALIAS("VARIOUS_FLASH", flash2); | ||
| 61 | REGION_ALIAS("VARIOUS_FLASH_LMA", flash2); | ||
| 62 | |||
| 63 | /* Flash region to be used for RAM(n) initialization data.*/ | ||
| 64 | REGION_ALIAS("RAM_INIT_FLASH_LMA", flash2); | ||
| 65 | |||
| 66 | /* RAM region to be used for Main stack. This stack accommodates the processing | ||
| 67 | of all exceptions and interrupts.*/ | ||
| 68 | REGION_ALIAS("MAIN_STACK_RAM", ram0); | ||
| 69 | |||
| 70 | /* RAM region to be used for the process stack. This is the stack used by | ||
| 71 | the main() function.*/ | ||
| 72 | REGION_ALIAS("PROCESS_STACK_RAM", ram0); | ||
| 73 | |||
| 74 | /* RAM region to be used for data segment.*/ | ||
| 75 | REGION_ALIAS("DATA_RAM", ram0); | ||
| 76 | REGION_ALIAS("DATA_RAM_LMA", flash2); | ||
| 77 | |||
| 78 | /* RAM region to be used for BSS segment.*/ | ||
| 79 | REGION_ALIAS("BSS_RAM", ram0); | ||
| 80 | |||
| 81 | /* RAM region to be used for the default heap.*/ | ||
| 82 | REGION_ALIAS("HEAP_RAM", ram0); | ||
| 83 | |||
| 84 | /* Generic rules inclusion.*/ | ||
| 85 | INCLUDE rules.ld | ||
diff --git a/platforms/chibios/bootloader.c b/platforms/chibios/bootloader.c new file mode 100644 index 000000000..5cadadeee --- /dev/null +++ b/platforms/chibios/bootloader.c | |||
| @@ -0,0 +1,145 @@ | |||
| 1 | #include "bootloader.h" | ||
| 2 | |||
| 3 | #include <ch.h> | ||
| 4 | #include <hal.h> | ||
| 5 | #include "wait.h" | ||
| 6 | |||
| 7 | /* This code should be checked whether it runs correctly on platforms */ | ||
| 8 | #define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0)) | ||
| 9 | #define BOOTLOADER_MAGIC 0xDEADBEEF | ||
| 10 | #define MAGIC_ADDR (unsigned long *)(SYMVAL(__ram0_end__) - 4) | ||
| 11 | |||
| 12 | #ifndef STM32_BOOTLOADER_DUAL_BANK | ||
| 13 | # define STM32_BOOTLOADER_DUAL_BANK FALSE | ||
| 14 | #endif | ||
| 15 | |||
| 16 | #ifdef BOOTLOADER_TINYUF2 | ||
| 17 | |||
| 18 | # define DBL_TAP_MAGIC 0xf01669ef // From tinyuf2's board_api.h | ||
| 19 | |||
| 20 | // defined by linker script | ||
| 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/drivers/analog.c b/platforms/chibios/drivers/analog.c index b1081623d..eb437665f 100644 --- a/platforms/chibios/drivers/analog.c +++ b/platforms/chibios/drivers/analog.c | |||
| @@ -38,7 +38,7 @@ | |||
| 38 | // Otherwise assume V3 | 38 | // Otherwise assume V3 |
| 39 | #if defined(STM32F0XX) || defined(STM32L0XX) | 39 | #if defined(STM32F0XX) || defined(STM32L0XX) |
| 40 | # define USE_ADCV1 | 40 | # define USE_ADCV1 |
| 41 | #elif defined(STM32F1XX) || defined(STM32F2XX) || defined(STM32F4XX) | 41 | #elif defined(STM32F1XX) || defined(STM32F2XX) || defined(STM32F4XX) || defined(GD32VF103) |
| 42 | # define USE_ADCV2 | 42 | # define USE_ADCV2 |
| 43 | #endif | 43 | #endif |
| 44 | 44 | ||
| @@ -75,7 +75,7 @@ | |||
| 75 | 75 | ||
| 76 | /* User configurable ADC options */ | 76 | /* User configurable ADC options */ |
| 77 | #ifndef ADC_COUNT | 77 | #ifndef ADC_COUNT |
| 78 | # if defined(STM32F0XX) || defined(STM32F1XX) || defined(STM32F4XX) | 78 | # if defined(STM32F0XX) || defined(STM32F1XX) || defined(STM32F4XX) || defined(GD32VF103) |
| 79 | # define ADC_COUNT 1 | 79 | # define ADC_COUNT 1 |
| 80 | # elif defined(STM32F3XX) | 80 | # elif defined(STM32F3XX) |
| 81 | # define ADC_COUNT 4 | 81 | # define ADC_COUNT 4 |
| @@ -122,7 +122,7 @@ static ADCConversionGroup adcConversionGroup = { | |||
| 122 | .cfgr1 = ADC_CFGR1_CONT | ADC_RESOLUTION, | 122 | .cfgr1 = ADC_CFGR1_CONT | ADC_RESOLUTION, |
| 123 | .smpr = ADC_SAMPLING_RATE, | 123 | .smpr = ADC_SAMPLING_RATE, |
| 124 | #elif defined(USE_ADCV2) | 124 | #elif defined(USE_ADCV2) |
| 125 | # if !defined(STM32F1XX) | 125 | # if !defined(STM32F1XX) && !defined(GD32VF103) |
| 126 | .cr2 = ADC_CR2_SWSTART, // F103 seem very unhappy with, F401 seems very unhappy without... | 126 | .cr2 = ADC_CR2_SWSTART, // F103 seem very unhappy with, F401 seems very unhappy without... |
| 127 | # endif | 127 | # endif |
| 128 | .smpr2 = ADC_SMPR2_SMP_AN0(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN1(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN2(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN3(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN4(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN5(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN6(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN7(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN8(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN9(ADC_SAMPLING_RATE), | 128 | .smpr2 = ADC_SMPR2_SMP_AN0(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN1(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN2(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN3(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN4(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN5(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN6(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN7(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN8(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN9(ADC_SAMPLING_RATE), |
| @@ -220,7 +220,7 @@ __attribute__((weak)) adc_mux pinToMux(pin_t pin) { | |||
| 220 | case F9: return TO_MUX( ADC_CHANNEL_IN7, 2 ); | 220 | case F9: return TO_MUX( ADC_CHANNEL_IN7, 2 ); |
| 221 | case F10: return TO_MUX( ADC_CHANNEL_IN8, 2 ); | 221 | case F10: return TO_MUX( ADC_CHANNEL_IN8, 2 ); |
| 222 | # endif | 222 | # endif |
| 223 | #elif defined(STM32F1XX) | 223 | #elif defined(STM32F1XX) || defined(GD32VF103) |
| 224 | case A0: return TO_MUX( ADC_CHANNEL_IN0, 0 ); | 224 | case A0: return TO_MUX( ADC_CHANNEL_IN0, 0 ); |
| 225 | case A1: return TO_MUX( ADC_CHANNEL_IN1, 0 ); | 225 | case A1: return TO_MUX( ADC_CHANNEL_IN1, 0 ); |
| 226 | case A2: return TO_MUX( ADC_CHANNEL_IN2, 0 ); | 226 | case A2: return TO_MUX( ADC_CHANNEL_IN2, 0 ); |
diff --git a/platforms/chibios/drivers/audio_dac.h b/platforms/chibios/drivers/audio_dac.h new file mode 100644 index 000000000..07cd622ea --- /dev/null +++ b/platforms/chibios/drivers/audio_dac.h | |||
| @@ -0,0 +1,126 @@ | |||
| 1 | /* Copyright 2019 Jack Humbert | ||
| 2 | * Copyright 2020 JohSchneider | ||
| 3 | * | ||
| 4 | * This program is free software: you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License as published by | ||
| 6 | * the Free Software Foundation, either version 2 of the License, or | ||
| 7 | * (at your option) any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | ||
| 17 | #pragma once | ||
| 18 | |||
| 19 | #ifndef A4 | ||
| 20 | # define A4 PAL_LINE(GPIOA, 4) | ||
| 21 | #endif | ||
| 22 | #ifndef A5 | ||
| 23 | # define A5 PAL_LINE(GPIOA, 5) | ||
| 24 | #endif | ||
| 25 | |||
| 26 | /** | ||
| 27 | * Size of the dac_buffer arrays. All must be the same size. | ||
| 28 | */ | ||
| 29 | #define AUDIO_DAC_BUFFER_SIZE 256U | ||
| 30 | |||
| 31 | /** | ||
| 32 | * Highest value allowed sample value. | ||
| 33 | |||
| 34 | * since the DAC is limited to 12 bit, the absolute max is 0xfff = 4095U; | ||
| 35 | * lower values adjust the peak-voltage aka volume down. | ||
| 36 | * adjusting this value has only an effect on a sample-buffer whose values are | ||
| 37 | * are NOT pregenerated - see square-wave | ||
| 38 | */ | ||
| 39 | #ifndef AUDIO_DAC_SAMPLE_MAX | ||
| 40 | # define AUDIO_DAC_SAMPLE_MAX 4095U | ||
| 41 | #endif | ||
| 42 | |||
| 43 | #if !defined(AUDIO_DAC_SAMPLE_RATE) && !defined(AUDIO_MAX_SIMULTANEOUS_TONES) && !defined(AUDIO_DAC_QUALITY_VERY_LOW) && !defined(AUDIO_DAC_QUALITY_LOW) && !defined(AUDIO_DAC_QUALITY_HIGH) && !defined(AUDIO_DAC_QUALITY_VERY_HIGH) | ||
| 44 | # define AUDIO_DAC_QUALITY_SANE_MINIMUM | ||
| 45 | #endif | ||
| 46 | |||
| 47 | /** | ||
| 48 | * These presets allow you to quickly switch between quality settings for | ||
| 49 | * the DAC. The sample rate and maximum number of simultaneous tones roughly | ||
| 50 | * has an inverse relationship - slightly higher sample rates may be possible. | ||
| 51 | * | ||
| 52 | * NOTE: a high sample-rate results in a higher cpu-load, which might lead to | ||
| 53 | * (audible) discontinuities and/or starve other processes of cpu-time | ||
| 54 | * (like RGB-led back-lighting, ...) | ||
| 55 | */ | ||
| 56 | #ifdef AUDIO_DAC_QUALITY_VERY_LOW | ||
| 57 | # define AUDIO_DAC_SAMPLE_RATE 11025U | ||
| 58 | # define AUDIO_MAX_SIMULTANEOUS_TONES 8 | ||
| 59 | #endif | ||
| 60 | |||
| 61 | #ifdef AUDIO_DAC_QUALITY_LOW | ||
| 62 | # define AUDIO_DAC_SAMPLE_RATE 22050U | ||
| 63 | # define AUDIO_MAX_SIMULTANEOUS_TONES 4 | ||
| 64 | #endif | ||
| 65 | |||
| 66 | #ifdef AUDIO_DAC_QUALITY_HIGH | ||
| 67 | # define AUDIO_DAC_SAMPLE_RATE 44100U | ||
| 68 | # define AUDIO_MAX_SIMULTANEOUS_TONES 2 | ||
| 69 | #endif | ||
| 70 | |||
| 71 | #ifdef AUDIO_DAC_QUALITY_VERY_HIGH | ||
| 72 | # define AUDIO_DAC_SAMPLE_RATE 88200U | ||
| 73 | # define AUDIO_MAX_SIMULTANEOUS_TONES 1 | ||
| 74 | #endif | ||
| 75 | |||
| 76 | #ifdef AUDIO_DAC_QUALITY_SANE_MINIMUM | ||
| 77 | /* a sane-minimum config: with a trade-off between cpu-load and tone-range | ||
| 78 | * | ||
| 79 | * the (currently) highest defined note is NOTE_B8 with 7902Hz; if we now | ||
| 80 | * aim for an even even multiple of the buffer-size, we end up with: | ||
| 81 | * ( roundUptoPow2(highest note / AUDIO_DAC_BUFFER_SIZE) * nyquist-rate * AUDIO_DAC_BUFFER_SIZE) | ||
| 82 | * 7902/256 = 30.867 * 2 * 256 ~= 16384 | ||
| 83 | * which works out (but the 'scope shows some sampling artifacts with lower harmonics :-P) | ||
| 84 | */ | ||
| 85 | # define AUDIO_DAC_SAMPLE_RATE 16384U | ||
| 86 | # define AUDIO_MAX_SIMULTANEOUS_TONES 8 | ||
| 87 | #endif | ||
| 88 | |||
| 89 | /** | ||
| 90 | * Effective bit-rate of the DAC. 44.1khz is the standard for most audio - any | ||
| 91 | * lower will sacrifice perceptible audio quality. Any higher will limit the | ||
| 92 | * number of simultaneous tones. In most situations, a tenth (1/10) of the | ||
| 93 | * sample rate is where notes become unbearable. | ||
| 94 | */ | ||
| 95 | #ifndef AUDIO_DAC_SAMPLE_RATE | ||
| 96 | # define AUDIO_DAC_SAMPLE_RATE 44100U | ||
| 97 | #endif | ||
| 98 | |||
| 99 | /** | ||
| 100 | * The number of tones that can be played simultaneously. If too high a value | ||
| 101 | * is used here, the keyboard will freeze and glitch-out when that many tones | ||
| 102 | * are being played. | ||
| 103 | */ | ||
| 104 | #ifndef AUDIO_MAX_SIMULTANEOUS_TONES | ||
| 105 | # define AUDIO_MAX_SIMULTANEOUS_TONES 2 | ||
| 106 | #endif | ||
| 107 | |||
| 108 | /** | ||
| 109 | * The default value of the DAC when not playing anything. Certain hardware | ||
| 110 | * setups may require a high (AUDIO_DAC_SAMPLE_MAX) or low (0) value here. | ||
| 111 | * Since multiple added sine waves tend to oscillate around the midpoint, | ||
| 112 | * and possibly never/rarely reach either 0 of MAX, 1/2 MAX can be a | ||
| 113 | * reasonable default value. | ||
| 114 | */ | ||
| 115 | #ifndef AUDIO_DAC_OFF_VALUE | ||
| 116 | # define AUDIO_DAC_OFF_VALUE AUDIO_DAC_SAMPLE_MAX / 2 | ||
| 117 | #endif | ||
| 118 | |||
| 119 | #if AUDIO_DAC_OFF_VALUE > AUDIO_DAC_SAMPLE_MAX | ||
| 120 | # error "AUDIO_DAC: OFF_VALUE may not be larger than SAMPLE_MAX" | ||
| 121 | #endif | ||
| 122 | |||
| 123 | /** | ||
| 124 | *user overridable sample generation/processing | ||
| 125 | */ | ||
| 126 | uint16_t dac_value_generate(void); | ||
diff --git a/platforms/chibios/drivers/audio_dac_additive.c b/platforms/chibios/drivers/audio_dac_additive.c new file mode 100644 index 000000000..db304adb8 --- /dev/null +++ b/platforms/chibios/drivers/audio_dac_additive.c | |||
| @@ -0,0 +1,335 @@ | |||
| 1 | /* Copyright 2016-2019 Jack Humbert | ||
| 2 | * Copyright 2020 JohSchneider | ||
| 3 | * | ||
| 4 | * This program is free software: you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License as published by | ||
| 6 | * the Free Software Foundation, either version 2 of the License, or | ||
| 7 | * (at your option) any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #include "audio.h" | ||
| 19 | #include <ch.h> | ||
| 20 | #include <hal.h> | ||
| 21 | |||
| 22 | /* | ||
| 23 | Audio Driver: DAC | ||
| 24 | |||
| 25 | which utilizes the dac unit many STM32 are equipped with, to output a modulated waveform from samples stored in the dac_buffer_* array who are passed to the hardware through DMA | ||
| 26 | |||
| 27 | it is also possible to have a custom sample-LUT by implementing/overriding 'dac_value_generate' | ||
| 28 | |||
| 29 | this driver allows for multiple simultaneous tones to be played through one single channel by doing additive wave-synthesis | ||
| 30 | */ | ||
| 31 | |||
| 32 | #if !defined(AUDIO_PIN) | ||
| 33 | # error "Audio feature enabled, but no suitable pin selected as AUDIO_PIN - see docs/feature_audio under 'ARM (DAC additive)' for available options." | ||
| 34 | #endif | ||
| 35 | #if defined(AUDIO_PIN_ALT) && !defined(AUDIO_PIN_ALT_AS_NEGATIVE) | ||
| 36 | # pragma message "Audio feature: AUDIO_PIN_ALT set, but not AUDIO_PIN_ALT_AS_NEGATIVE - pin will be left unused; audio might still work though." | ||
| 37 | #endif | ||
| 38 | |||
| 39 | #if !defined(AUDIO_PIN_ALT) | ||
| 40 | // no ALT pin defined is valid, but the c-ifs below need some value set | ||
| 41 | # define AUDIO_PIN_ALT PAL_NOLINE | ||
| 42 | #endif | ||
| 43 | |||
| 44 | #if !defined(AUDIO_DAC_SAMPLE_WAVEFORM_SINE) && !defined(AUDIO_DAC_SAMPLE_WAVEFORM_TRIANGLE) && !defined(AUDIO_DAC_SAMPLE_WAVEFORM_SQUARE) && !defined(AUDIO_DAC_SAMPLE_WAVEFORM_TRAPEZOID) | ||
| 45 | # define AUDIO_DAC_SAMPLE_WAVEFORM_SINE | ||
| 46 | #endif | ||
| 47 | |||
| 48 | #ifdef AUDIO_DAC_SAMPLE_WAVEFORM_SINE | ||
| 49 | /* one full sine wave over [0,2*pi], but shifted up one amplitude and left pi/4; for the samples to start at 0 | ||
| 50 | */ | ||
| 51 | static const dacsample_t dac_buffer_sine[AUDIO_DAC_BUFFER_SIZE] = { | ||
| 52 | // 256 values, max 4095 | ||
| 53 | 0x0, 0x1, 0x2, 0x6, 0xa, 0xf, 0x16, 0x1e, 0x27, 0x32, 0x3d, 0x4a, 0x58, 0x67, 0x78, 0x89, 0x9c, 0xb0, 0xc5, 0xdb, 0xf2, 0x10a, 0x123, 0x13e, 0x159, 0x175, 0x193, 0x1b1, 0x1d1, 0x1f1, 0x212, 0x235, 0x258, 0x27c, 0x2a0, 0x2c6, 0x2ed, 0x314, 0x33c, 0x365, 0x38e, 0x3b8, 0x3e3, 0x40e, 0x43a, 0x467, 0x494, 0x4c2, 0x4f0, 0x51f, 0x54e, 0x57d, 0x5ad, 0x5dd, 0x60e, 0x63f, 0x670, 0x6a1, 0x6d3, 0x705, 0x737, 0x769, 0x79b, 0x7cd, 0x800, 0x832, 0x864, 0x896, 0x8c8, 0x8fa, 0x92c, 0x95e, 0x98f, 0x9c0, 0x9f1, 0xa22, 0xa52, 0xa82, 0xab1, 0xae0, 0xb0f, 0xb3d, 0xb6b, 0xb98, 0xbc5, 0xbf1, 0xc1c, 0xc47, 0xc71, 0xc9a, 0xcc3, 0xceb, 0xd12, 0xd39, 0xd5f, 0xd83, 0xda7, 0xdca, 0xded, 0xe0e, 0xe2e, 0xe4e, 0xe6c, 0xe8a, 0xea6, 0xec1, 0xedc, 0xef5, 0xf0d, 0xf24, 0xf3a, 0xf4f, 0xf63, 0xf76, 0xf87, 0xf98, 0xfa7, 0xfb5, 0xfc2, 0xfcd, 0xfd8, 0xfe1, 0xfe9, 0xff0, 0xff5, 0xff9, 0xffd, 0xffe, | ||
| 54 | 0xfff, 0xffe, 0xffd, 0xff9, 0xff5, 0xff0, 0xfe9, 0xfe1, 0xfd8, 0xfcd, 0xfc2, 0xfb5, 0xfa7, 0xf98, 0xf87, 0xf76, 0xf63, 0xf4f, 0xf3a, 0xf24, 0xf0d, 0xef5, 0xedc, 0xec1, 0xea6, 0xe8a, 0xe6c, 0xe4e, 0xe2e, 0xe0e, 0xded, 0xdca, 0xda7, 0xd83, 0xd5f, 0xd39, 0xd12, 0xceb, 0xcc3, 0xc9a, 0xc71, 0xc47, 0xc1c, 0xbf1, 0xbc5, 0xb98, 0xb6b, 0xb3d, 0xb0f, 0xae0, 0xab1, 0xa82, 0xa52, 0xa22, 0x9f1, 0x9c0, 0x98f, 0x95e, 0x92c, 0x8fa, 0x8c8, 0x896, 0x864, 0x832, 0x800, 0x7cd, 0x79b, 0x769, 0x737, 0x705, 0x6d3, 0x6a1, 0x670, 0x63f, 0x60e, 0x5dd, 0x5ad, 0x57d, 0x54e, 0x51f, 0x4f0, 0x4c2, 0x494, 0x467, 0x43a, 0x40e, 0x3e3, 0x3b8, 0x38e, 0x365, 0x33c, 0x314, 0x2ed, 0x2c6, 0x2a0, 0x27c, 0x258, 0x235, 0x212, 0x1f1, 0x1d1, 0x1b1, 0x193, 0x175, 0x159, 0x13e, 0x123, 0x10a, 0xf2, 0xdb, 0xc5, 0xb0, 0x9c, 0x89, 0x78, 0x67, 0x58, 0x4a, 0x3d, 0x32, 0x27, 0x1e, 0x16, 0xf, 0xa, 0x6, 0x2, 0x1}; | ||
| 55 | #endif // AUDIO_DAC_SAMPLE_WAVEFORM_SINE | ||
| 56 | #ifdef AUDIO_DAC_SAMPLE_WAVEFORM_TRIANGLE | ||
| 57 | static const dacsample_t dac_buffer_triangle[AUDIO_DAC_BUFFER_SIZE] = { | ||
| 58 | // 256 values, max 4095 | ||
| 59 | 0x0, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0, 0x100, 0x120, 0x140, 0x160, 0x180, 0x1a0, 0x1c0, 0x1e0, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0x3c0, 0x3e0, 0x400, 0x420, 0x440, 0x460, 0x480, 0x4a0, 0x4c0, 0x4e0, 0x500, 0x520, 0x540, 0x560, 0x580, 0x5a0, 0x5c0, 0x5e0, 0x600, 0x620, 0x640, 0x660, 0x680, 0x6a0, 0x6c0, 0x6e0, 0x700, 0x720, 0x740, 0x760, 0x780, 0x7a0, 0x7c0, 0x7e0, 0x800, 0x81f, 0x83f, 0x85f, 0x87f, 0x89f, 0x8bf, 0x8df, 0x8ff, 0x91f, 0x93f, 0x95f, 0x97f, 0x99f, 0x9bf, 0x9df, 0x9ff, 0xa1f, 0xa3f, 0xa5f, 0xa7f, 0xa9f, 0xabf, 0xadf, 0xaff, 0xb1f, 0xb3f, 0xb5f, 0xb7f, 0xb9f, 0xbbf, 0xbdf, 0xbff, 0xc1f, 0xc3f, 0xc5f, 0xc7f, 0xc9f, 0xcbf, 0xcdf, 0xcff, 0xd1f, 0xd3f, 0xd5f, 0xd7f, 0xd9f, 0xdbf, 0xddf, 0xdff, 0xe1f, 0xe3f, 0xe5f, 0xe7f, 0xe9f, 0xebf, 0xedf, 0xeff, 0xf1f, 0xf3f, 0xf5f, 0xf7f, 0xf9f, 0xfbf, 0xfdf, | ||
| 60 | 0xfff, 0xfdf, 0xfbf, 0xf9f, 0xf7f, 0xf5f, 0xf3f, 0xf1f, 0xeff, 0xedf, 0xebf, 0xe9f, 0xe7f, 0xe5f, 0xe3f, 0xe1f, 0xdff, 0xddf, 0xdbf, 0xd9f, 0xd7f, 0xd5f, 0xd3f, 0xd1f, 0xcff, 0xcdf, 0xcbf, 0xc9f, 0xc7f, 0xc5f, 0xc3f, 0xc1f, 0xbff, 0xbdf, 0xbbf, 0xb9f, 0xb7f, 0xb5f, 0xb3f, 0xb1f, 0xaff, 0xadf, 0xabf, 0xa9f, 0xa7f, 0xa5f, 0xa3f, 0xa1f, 0x9ff, 0x9df, 0x9bf, 0x99f, 0x97f, 0x95f, 0x93f, 0x91f, 0x8ff, 0x8df, 0x8bf, 0x89f, 0x87f, 0x85f, 0x83f, 0x81f, 0x800, 0x7e0, 0x7c0, 0x7a0, 0x780, 0x760, 0x740, 0x720, 0x700, 0x6e0, 0x6c0, 0x6a0, 0x680, 0x660, 0x640, 0x620, 0x600, 0x5e0, 0x5c0, 0x5a0, 0x580, 0x560, 0x540, 0x520, 0x500, 0x4e0, 0x4c0, 0x4a0, 0x480, 0x460, 0x440, 0x420, 0x400, 0x3e0, 0x3c0, 0x3a0, 0x380, 0x360, 0x340, 0x320, 0x300, 0x2e0, 0x2c0, 0x2a0, 0x280, 0x260, 0x240, 0x220, 0x200, 0x1e0, 0x1c0, 0x1a0, 0x180, 0x160, 0x140, 0x120, 0x100, 0xe0, 0xc0, 0xa0, 0x80, 0x60, 0x40, 0x20}; | ||
| 61 | #endif // AUDIO_DAC_SAMPLE_WAVEFORM_TRIANGLE | ||
| 62 | #ifdef AUDIO_DAC_SAMPLE_WAVEFORM_SQUARE | ||
| 63 | static const dacsample_t dac_buffer_square[AUDIO_DAC_BUFFER_SIZE] = { | ||
| 64 | [0 ... AUDIO_DAC_BUFFER_SIZE / 2 - 1] = 0, // first and | ||
| 65 | [AUDIO_DAC_BUFFER_SIZE / 2 ... AUDIO_DAC_BUFFER_SIZE - 1] = AUDIO_DAC_SAMPLE_MAX, // second half | ||
| 66 | }; | ||
| 67 | #endif // AUDIO_DAC_SAMPLE_WAVEFORM_SQUARE | ||
| 68 | /* | ||
| 69 | // four steps: 0, 1/3, 2/3 and 1 | ||
| 70 | static const dacsample_t dac_buffer_staircase[AUDIO_DAC_BUFFER_SIZE] = { | ||
| 71 | [0 ... AUDIO_DAC_BUFFER_SIZE/3 -1 ] = 0, | ||
| 72 | [AUDIO_DAC_BUFFER_SIZE / 4 ... AUDIO_DAC_BUFFER_SIZE / 2 -1 ] = AUDIO_DAC_SAMPLE_MAX / 3, | ||
| 73 | [AUDIO_DAC_BUFFER_SIZE / 2 ... 3 * AUDIO_DAC_BUFFER_SIZE / 4 -1 ] = 2 * AUDIO_DAC_SAMPLE_MAX / 3, | ||
| 74 | [3 * AUDIO_DAC_BUFFER_SIZE / 4 ... AUDIO_DAC_BUFFER_SIZE -1 ] = AUDIO_DAC_SAMPLE_MAX, | ||
| 75 | } | ||
| 76 | */ | ||
| 77 | #ifdef AUDIO_DAC_SAMPLE_WAVEFORM_TRAPEZOID | ||
| 78 | static const dacsample_t dac_buffer_trapezoid[AUDIO_DAC_BUFFER_SIZE] = {0x0, 0x1f, 0x7f, 0xdf, 0x13f, 0x19f, 0x1ff, 0x25f, 0x2bf, 0x31f, 0x37f, 0x3df, 0x43f, 0x49f, 0x4ff, 0x55f, 0x5bf, 0x61f, 0x67f, 0x6df, 0x73f, 0x79f, 0x7ff, 0x85f, 0x8bf, 0x91f, 0x97f, 0x9df, 0xa3f, 0xa9f, 0xaff, 0xb5f, 0xbbf, 0xc1f, 0xc7f, 0xcdf, 0xd3f, 0xd9f, 0xdff, 0xe5f, 0xebf, 0xf1f, 0xf7f, 0xfdf, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, | ||
| 79 | 0xfff, 0xfdf, 0xf7f, 0xf1f, 0xebf, 0xe5f, 0xdff, 0xd9f, 0xd3f, 0xcdf, 0xc7f, 0xc1f, 0xbbf, 0xb5f, 0xaff, 0xa9f, 0xa3f, 0x9df, 0x97f, 0x91f, 0x8bf, 0x85f, 0x7ff, 0x79f, 0x73f, 0x6df, 0x67f, 0x61f, 0x5bf, 0x55f, 0x4ff, 0x49f, 0x43f, 0x3df, 0x37f, 0x31f, 0x2bf, 0x25f, 0x1ff, 0x19f, 0x13f, 0xdf, 0x7f, 0x1f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; | ||
| 80 | #endif // AUDIO_DAC_SAMPLE_WAVEFORM_TRAPEZOID | ||
| 81 | |||
| 82 | static dacsample_t dac_buffer_empty[AUDIO_DAC_BUFFER_SIZE] = {AUDIO_DAC_OFF_VALUE}; | ||
| 83 | |||
| 84 | /* keep track of the sample position for for each frequency */ | ||
| 85 | static float dac_if[AUDIO_MAX_SIMULTANEOUS_TONES] = {0.0}; | ||
| 86 | |||
| 87 | static float active_tones_snapshot[AUDIO_MAX_SIMULTANEOUS_TONES] = {0, 0}; | ||
| 88 | static uint8_t active_tones_snapshot_length = 0; | ||
| 89 | |||
| 90 | typedef enum { | ||
| 91 | OUTPUT_SHOULD_START, | ||
| 92 | OUTPUT_RUN_NORMALLY, | ||
| 93 | // path 1: wait for zero, then change/update active tones | ||
| 94 | OUTPUT_TONES_CHANGED, | ||
| 95 | OUTPUT_REACHED_ZERO_BEFORE_TONE_CHANGE, | ||
| 96 | // path 2: hardware should stop, wait for zero then turn output off = stop the timer | ||
| 97 | OUTPUT_SHOULD_STOP, | ||
| 98 | OUTPUT_REACHED_ZERO_BEFORE_OFF, | ||
| 99 | OUTPUT_OFF, | ||
| 100 | OUTPUT_OFF_1, | ||
| 101 | OUTPUT_OFF_2, // trailing off: giving the DAC two more conversion cycles until the AUDIO_DAC_OFF_VALUE reaches the output, then turn the timer off, which leaves the output at that level | ||
| 102 | number_of_output_states | ||
| 103 | } output_states_t; | ||
| 104 | output_states_t state = OUTPUT_OFF_2; | ||
| 105 | |||
| 106 | /** | ||
| 107 | * Generation of the waveform being passed to the callback. Declared weak so users | ||
| 108 | * can override it with their own wave-forms/noises. | ||
| 109 | */ | ||
| 110 | __attribute__((weak)) uint16_t dac_value_generate(void) { | ||
| 111 | // DAC is running/asking for values but snapshot length is zero -> must be playing a pause | ||
| 112 | if (active_tones_snapshot_length == 0) { | ||
| 113 | return AUDIO_DAC_OFF_VALUE; | ||
| 114 | } | ||
| 115 | |||
| 116 | /* doing additive wave synthesis over all currently playing tones = adding up | ||
| 117 | * sine-wave-samples for each frequency, scaled by the number of active tones | ||
| 118 | */ | ||
| 119 | uint16_t value = 0; | ||
| 120 | float frequency = 0.0f; | ||
| 121 | |||
| 122 | for (uint8_t i = 0; i < active_tones_snapshot_length; i++) { | ||
| 123 | /* Note: a user implementation does not have to rely on the active_tones_snapshot, but | ||
| 124 | * could directly query the active frequencies through audio_get_processed_frequency */ | ||
| 125 | frequency = active_tones_snapshot[i]; | ||
| 126 | |||
| 127 | dac_if[i] = dac_if[i] + ((frequency * AUDIO_DAC_BUFFER_SIZE) / AUDIO_DAC_SAMPLE_RATE) * 2 / 3; | ||
| 128 | /*Note: the 2/3 are necessary to get the correct frequencies on the | ||
| 129 | * DAC output (as measured with an oscilloscope), since the gpt | ||
| 130 | * timer runs with 3*AUDIO_DAC_SAMPLE_RATE; and the DAC callback | ||
| 131 | * is called twice per conversion.*/ | ||
| 132 | |||
| 133 | dac_if[i] = fmod(dac_if[i], AUDIO_DAC_BUFFER_SIZE); | ||
| 134 | |||
| 135 | // Wavetable generation/lookup | ||
| 136 | uint16_t dac_i = (uint16_t)dac_if[i]; | ||
| 137 | |||
| 138 | #if defined(AUDIO_DAC_SAMPLE_WAVEFORM_SINE) | ||
| 139 | value += dac_buffer_sine[dac_i] / active_tones_snapshot_length; | ||
| 140 | #elif defined(AUDIO_DAC_SAMPLE_WAVEFORM_TRIANGLE) | ||
| 141 | value += dac_buffer_triangle[dac_i] / active_tones_snapshot_length; | ||
| 142 | #elif defined(AUDIO_DAC_SAMPLE_WAVEFORM_TRAPEZOID) | ||
| 143 | value += dac_buffer_trapezoid[dac_i] / active_tones_snapshot_length; | ||
| 144 | #elif defined(AUDIO_DAC_SAMPLE_WAVEFORM_SQUARE) | ||
| 145 | value += dac_buffer_square[dac_i] / active_tones_snapshot_length; | ||
| 146 | #endif | ||
| 147 | /* | ||
| 148 | // SINE | ||
| 149 | value += dac_buffer_sine[dac_i] / active_tones_snapshot_length / 3; | ||
| 150 | // TRIANGLE | ||
| 151 | value += dac_buffer_triangle[dac_i] / active_tones_snapshot_length / 3; | ||
| 152 | // SQUARE | ||
| 153 | value += dac_buffer_square[dac_i] / active_tones_snapshot_length / 3; | ||
| 154 | //NOTE: combination of these three wave-forms is more exemplary - and doesn't sound particularly good :-P | ||
| 155 | */ | ||
| 156 | |||
| 157 | // STAIRS (mostly usefully as test-pattern) | ||
| 158 | // value_avg = dac_buffer_staircase[dac_i] / active_tones_snapshot_length; | ||
| 159 | } | ||
| 160 | |||
| 161 | return value; | ||
| 162 | } | ||
| 163 | |||
| 164 | /** | ||
| 165 | * DAC streaming callback. Does all of the main computing for playing songs. | ||
| 166 | * | ||
| 167 | * Note: chibios calls this CB twice: during the 'half buffer event', and the 'full buffer event'. | ||
| 168 | */ | ||
| 169 | static void dac_end(DACDriver *dacp) { | ||
| 170 | dacsample_t *sample_p = (dacp)->samples; | ||
| 171 | |||
| 172 | // work on the other half of the buffer | ||
| 173 | if (dacIsBufferComplete(dacp)) { | ||
| 174 | sample_p += AUDIO_DAC_BUFFER_SIZE / 2; // 'half_index' | ||
| 175 | } | ||
| 176 | |||
| 177 | for (uint8_t s = 0; s < AUDIO_DAC_BUFFER_SIZE / 2; s++) { | ||
| 178 | if (OUTPUT_OFF <= state) { | ||
| 179 | sample_p[s] = AUDIO_DAC_OFF_VALUE; | ||
| 180 | continue; | ||
| 181 | } else { | ||
| 182 | sample_p[s] = dac_value_generate(); | ||
| 183 | } | ||
| 184 | |||
| 185 | /* zero crossing (or approach, whereas zero == DAC_OFF_VALUE, which can be configured to anything from 0 to DAC_SAMPLE_MAX) | ||
| 186 | * ============================*=*========================== AUDIO_DAC_SAMPLE_MAX | ||
| 187 | * * * | ||
| 188 | * * * | ||
| 189 | * --------------------------------------------------------- | ||
| 190 | * * * } AUDIO_DAC_SAMPLE_MAX/100 | ||
| 191 | * --------------------------------------------------------- AUDIO_DAC_OFF_VALUE | ||
| 192 | * * * } AUDIO_DAC_SAMPLE_MAX/100 | ||
| 193 | * --------------------------------------------------------- | ||
| 194 | * * | ||
| 195 | * * * | ||
| 196 | * * * | ||
| 197 | * =====*=*================================================= 0x0 | ||
| 198 | */ | ||
| 199 | if (((sample_p[s] + (AUDIO_DAC_SAMPLE_MAX / 100)) > AUDIO_DAC_OFF_VALUE) && // value approaches from below | ||
| 200 | (sample_p[s] < (AUDIO_DAC_OFF_VALUE + (AUDIO_DAC_SAMPLE_MAX / 100))) // or above | ||
| 201 | ) { | ||
| 202 | if ((OUTPUT_SHOULD_START == state) && (active_tones_snapshot_length > 0)) { | ||
| 203 | state = OUTPUT_RUN_NORMALLY; | ||
| 204 | } else if (OUTPUT_TONES_CHANGED == state) { | ||
| 205 | state = OUTPUT_REACHED_ZERO_BEFORE_TONE_CHANGE; | ||
| 206 | } else if (OUTPUT_SHOULD_STOP == state) { | ||
| 207 | state = OUTPUT_REACHED_ZERO_BEFORE_OFF; | ||
| 208 | } | ||
| 209 | } | ||
| 210 | |||
| 211 | // still 'ramping up', reset the output to OFF_VALUE until the generated values reach that value, to do a smooth handover | ||
| 212 | if (OUTPUT_SHOULD_START == state) { | ||
| 213 | sample_p[s] = AUDIO_DAC_OFF_VALUE; | ||
| 214 | } | ||
| 215 | |||
| 216 | if ((OUTPUT_SHOULD_START == state) || (OUTPUT_REACHED_ZERO_BEFORE_OFF == state) || (OUTPUT_REACHED_ZERO_BEFORE_TONE_CHANGE == state)) { | ||
| 217 | uint8_t active_tones = MIN(AUDIO_MAX_SIMULTANEOUS_TONES, audio_get_number_of_active_tones()); | ||
| 218 | active_tones_snapshot_length = 0; | ||
| 219 | // update the snapshot - once, and only on occasion that something changed; | ||
| 220 | // -> saves cpu cycles (?) | ||
| 221 | for (uint8_t i = 0; i < active_tones; i++) { | ||
| 222 | float freq = audio_get_processed_frequency(i); | ||
| 223 | if (freq > 0) { // disregard 'rest' notes, with valid frequency 0.0f; which would only lower the resulting waveform volume during the additive synthesis step | ||
| 224 | active_tones_snapshot[active_tones_snapshot_length++] = freq; | ||
| 225 | } | ||
| 226 | } | ||
| 227 | |||
| 228 | if ((0 == active_tones_snapshot_length) && (OUTPUT_REACHED_ZERO_BEFORE_OFF == state)) { | ||
| 229 | state = OUTPUT_OFF; | ||
| 230 | } | ||
| 231 | if (OUTPUT_REACHED_ZERO_BEFORE_TONE_CHANGE == state) { | ||
| 232 | state = OUTPUT_RUN_NORMALLY; | ||
| 233 | } | ||
| 234 | } | ||
| 235 | } | ||
| 236 | |||
| 237 | // update audio internal state (note position, current_note, ...) | ||
| 238 | if (audio_update_state()) { | ||
| 239 | if (OUTPUT_SHOULD_STOP != state) { | ||
| 240 | state = OUTPUT_TONES_CHANGED; | ||
| 241 | } | ||
| 242 | } | ||
| 243 | |||
| 244 | if (OUTPUT_OFF <= state) { | ||
| 245 | if (OUTPUT_OFF_2 == state) { | ||
| 246 | // stopping timer6 = stopping the DAC at whatever value it is currently pushing to the output = AUDIO_DAC_OFF_VALUE | ||
| 247 | gptStopTimer(&GPTD6); | ||
| 248 | } else { | ||
| 249 | state++; | ||
| 250 | } | ||
| 251 | } | ||
| 252 | } | ||
| 253 | |||
| 254 | static void dac_error(DACDriver *dacp, dacerror_t err) { | ||
| 255 | (void)dacp; | ||
| 256 | (void)err; | ||
| 257 | |||
| 258 | chSysHalt("DAC failure. halp"); | ||
| 259 | } | ||
| 260 | |||
| 261 | static const GPTConfig gpt6cfg1 = {.frequency = AUDIO_DAC_SAMPLE_RATE * 3, | ||
| 262 | .callback = NULL, | ||
| 263 | .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */ | ||
| 264 | .dier = 0U}; | ||
| 265 | |||
| 266 | static const DACConfig dac_conf = {.init = AUDIO_DAC_OFF_VALUE, .datamode = DAC_DHRM_12BIT_RIGHT}; | ||
| 267 | |||
| 268 | /** | ||
| 269 | * @note The DAC_TRG(0) here selects the Timer 6 TRGO event, which is triggered | ||
| 270 | * on the rising edge after 3 APB1 clock cycles, causing our gpt6cfg1.frequency | ||
| 271 | * to be a third of what we expect. | ||
| 272 | * | ||
| 273 | * Here are all the values for DAC_TRG (TSEL in the ref manual) | ||
| 274 | * TIM15_TRGO 0b011 | ||
| 275 | * TIM2_TRGO 0b100 | ||
| 276 | * TIM3_TRGO 0b001 | ||
| 277 | * TIM6_TRGO 0b000 | ||
| 278 | * TIM7_TRGO 0b010 | ||
| 279 | * EXTI9 0b110 | ||
| 280 | * SWTRIG 0b111 | ||
| 281 | */ | ||
| 282 | static const DACConversionGroup dac_conv_cfg = {.num_channels = 1U, .end_cb = dac_end, .error_cb = dac_error, .trigger = DAC_TRG(0b000)}; | ||
| 283 | |||
| 284 | void audio_driver_initialize() { | ||
| 285 | if ((AUDIO_PIN == A4) || (AUDIO_PIN_ALT == A4)) { | ||
| 286 | palSetLineMode(A4, PAL_MODE_INPUT_ANALOG); | ||
| 287 | dacStart(&DACD1, &dac_conf); | ||
| 288 | } | ||
| 289 | if ((AUDIO_PIN == A5) || (AUDIO_PIN_ALT == A5)) { | ||
| 290 | palSetLineMode(A5, PAL_MODE_INPUT_ANALOG); | ||
| 291 | dacStart(&DACD2, &dac_conf); | ||
| 292 | } | ||
| 293 | |||
| 294 | /* enable the output buffer, to directly drive external loads with no additional circuitry | ||
| 295 | * | ||
| 296 | * see: AN4566 Application note: Extending the DAC performance of STM32 microcontrollers | ||
| 297 | * Note: Buffer-Off bit -> has to be set 0 to enable the output buffer | ||
| 298 | * Note: enabling the output buffer imparts an additional dc-offset of a couple mV | ||
| 299 | * | ||
| 300 | * this is done here, reaching directly into the stm32 registers since chibios has not implemented BOFF handling yet | ||
| 301 | * (see: chibios/os/hal/ports/STM32/todo.txt '- BOFF handling in DACv1.' | ||
| 302 | */ | ||
| 303 | DACD1.params->dac->CR &= ~DAC_CR_BOFF1; | ||
| 304 | DACD2.params->dac->CR &= ~DAC_CR_BOFF2; | ||
| 305 | |||
| 306 | if (AUDIO_PIN == A4) { | ||
| 307 | dacStartConversion(&DACD1, &dac_conv_cfg, dac_buffer_empty, AUDIO_DAC_BUFFER_SIZE); | ||
| 308 | } else if (AUDIO_PIN == A5) { | ||
| 309 | dacStartConversion(&DACD2, &dac_conv_cfg, dac_buffer_empty, AUDIO_DAC_BUFFER_SIZE); | ||
| 310 | } | ||
| 311 | |||
| 312 | // no inverted/out-of-phase waveform (yet?), only pulling AUDIO_PIN_ALT to AUDIO_DAC_OFF_VALUE | ||
| 313 | #if defined(AUDIO_PIN_ALT_AS_NEGATIVE) | ||
| 314 | if (AUDIO_PIN_ALT == A4) { | ||
| 315 | dacPutChannelX(&DACD1, 0, AUDIO_DAC_OFF_VALUE); | ||
| 316 | } else if (AUDIO_PIN_ALT == A5) { | ||
| 317 | dacPutChannelX(&DACD2, 0, AUDIO_DAC_OFF_VALUE); | ||
| 318 | } | ||
| 319 | #endif | ||
| 320 | |||
| 321 | gptStart(&GPTD6, &gpt6cfg1); | ||
| 322 | } | ||
| 323 | |||
| 324 | void audio_driver_stop(void) { state = OUTPUT_SHOULD_STOP; } | ||
| 325 | |||
| 326 | void audio_driver_start(void) { | ||
| 327 | gptStartContinuous(&GPTD6, 2U); | ||
| 328 | |||
| 329 | for (uint8_t i = 0; i < AUDIO_MAX_SIMULTANEOUS_TONES; i++) { | ||
| 330 | dac_if[i] = 0.0f; | ||
| 331 | active_tones_snapshot[i] = 0.0f; | ||
| 332 | } | ||
| 333 | active_tones_snapshot_length = 0; | ||
| 334 | state = OUTPUT_SHOULD_START; | ||
| 335 | } | ||
diff --git a/platforms/chibios/drivers/audio_dac_basic.c b/platforms/chibios/drivers/audio_dac_basic.c new file mode 100644 index 000000000..fac651350 --- /dev/null +++ b/platforms/chibios/drivers/audio_dac_basic.c | |||
| @@ -0,0 +1,245 @@ | |||
| 1 | /* Copyright 2016-2020 Jack Humbert | ||
| 2 | * Copyright 2020 JohSchneider | ||
| 3 | * | ||
| 4 | * This program is free software: you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License as published by | ||
| 6 | * the Free Software Foundation, either version 2 of the License, or | ||
| 7 | * (at your option) any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #include "audio.h" | ||
| 19 | #include "ch.h" | ||
| 20 | #include "hal.h" | ||
| 21 | |||
| 22 | /* | ||
| 23 | Audio Driver: DAC | ||
| 24 | |||
| 25 | which utilizes both channels of the DAC unit many STM32 are equipped with to output a modulated square-wave, from precomputed samples stored in a buffer, which is passed to the hardware through DMA | ||
| 26 | |||
| 27 | this driver can either be used to drive to separate speakers, wired to A4+Gnd and A5+Gnd, which allows two tones to be played simultaneously | ||
| 28 | OR | ||
| 29 | one speaker wired to A4+A5 with the AUDIO_PIN_ALT_AS_NEGATIVE define set - see docs/feature_audio | ||
| 30 | |||
| 31 | */ | ||
| 32 | |||
| 33 | #if !defined(AUDIO_PIN) | ||
| 34 | # pragma message "Audio feature enabled, but no suitable pin selected as AUDIO_PIN - see docs/feature_audio under 'ARM (DAC basic)' for available options." | ||
| 35 | // TODO: make this an 'error' instead; go through a breaking change, and add AUDIO_PIN A5 to all keyboards currently using AUDIO on STM32 based boards? - for now: set the define here | ||
| 36 | # define AUDIO_PIN A5 | ||
| 37 | #endif | ||
| 38 | // check configuration for ONE speaker, connected to both DAC pins | ||
| 39 | #if defined(AUDIO_PIN_ALT_AS_NEGATIVE) && !defined(AUDIO_PIN_ALT) | ||
| 40 | # error "Audio feature: AUDIO_PIN_ALT_AS_NEGATIVE set, but no pin configured as AUDIO_PIN_ALT" | ||
| 41 | #endif | ||
| 42 | |||
| 43 | #ifndef AUDIO_PIN_ALT | ||
| 44 | // no ALT pin defined is valid, but the c-ifs below need some value set | ||
| 45 | # define AUDIO_PIN_ALT -1 | ||
| 46 | #endif | ||
| 47 | |||
| 48 | #if !defined(AUDIO_STATE_TIMER) | ||
| 49 | # define AUDIO_STATE_TIMER GPTD8 | ||
| 50 | #endif | ||
| 51 | |||
| 52 | // square-wave | ||
| 53 | static const dacsample_t dac_buffer_1[AUDIO_DAC_BUFFER_SIZE] = { | ||
| 54 | // First half is max, second half is 0 | ||
| 55 | [0 ... AUDIO_DAC_BUFFER_SIZE / 2 - 1] = AUDIO_DAC_SAMPLE_MAX, | ||
| 56 | [AUDIO_DAC_BUFFER_SIZE / 2 ... AUDIO_DAC_BUFFER_SIZE - 1] = 0, | ||
| 57 | }; | ||
| 58 | |||
| 59 | // square-wave | ||
| 60 | static const dacsample_t dac_buffer_2[AUDIO_DAC_BUFFER_SIZE] = { | ||
| 61 | // opposite of dac_buffer above | ||
| 62 | [0 ... AUDIO_DAC_BUFFER_SIZE / 2 - 1] = 0, | ||
| 63 | [AUDIO_DAC_BUFFER_SIZE / 2 ... AUDIO_DAC_BUFFER_SIZE - 1] = AUDIO_DAC_SAMPLE_MAX, | ||
| 64 | }; | ||
| 65 | |||
| 66 | GPTConfig gpt6cfg1 = {.frequency = AUDIO_DAC_SAMPLE_RATE, | ||
| 67 | .callback = NULL, | ||
| 68 | .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */ | ||
| 69 | .dier = 0U}; | ||
| 70 | GPTConfig gpt7cfg1 = {.frequency = AUDIO_DAC_SAMPLE_RATE, | ||
| 71 | .callback = NULL, | ||
| 72 | .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */ | ||
| 73 | .dier = 0U}; | ||
| 74 | |||
| 75 | static void gpt_audio_state_cb(GPTDriver *gptp); | ||
| 76 | GPTConfig gptStateUpdateCfg = {.frequency = 10, | ||
| 77 | .callback = gpt_audio_state_cb, | ||
| 78 | .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */ | ||
| 79 | .dier = 0U}; | ||
| 80 | |||
| 81 | static const DACConfig dac_conf_ch1 = {.init = AUDIO_DAC_OFF_VALUE, .datamode = DAC_DHRM_12BIT_RIGHT}; | ||
| 82 | static const DACConfig dac_conf_ch2 = {.init = AUDIO_DAC_OFF_VALUE, .datamode = DAC_DHRM_12BIT_RIGHT}; | ||
| 83 | |||
| 84 | /** | ||
| 85 | * @note The DAC_TRG(0) here selects the Timer 6 TRGO event, which is triggered | ||
| 86 | * on the rising edge after 3 APB1 clock cycles, causing our gpt6cfg1.frequency | ||
| 87 | * to be a third of what we expect. | ||
| 88 | * | ||
| 89 | * Here are all the values for DAC_TRG (TSEL in the ref manual) | ||
| 90 | * TIM15_TRGO 0b011 | ||
| 91 | * TIM2_TRGO 0b100 | ||
| 92 | * TIM3_TRGO 0b001 | ||
| 93 | * TIM6_TRGO 0b000 | ||
| 94 | * TIM7_TRGO 0b010 | ||
| 95 | * EXTI9 0b110 | ||
| 96 | * SWTRIG 0b111 | ||
| 97 | */ | ||
| 98 | static const DACConversionGroup dac_conv_grp_ch1 = {.num_channels = 1U, .trigger = DAC_TRG(0b000)}; | ||
| 99 | static const DACConversionGroup dac_conv_grp_ch2 = {.num_channels = 1U, .trigger = DAC_TRG(0b010)}; | ||
| 100 | |||
| 101 | void channel_1_start(void) { | ||
| 102 | gptStart(&GPTD6, &gpt6cfg1); | ||
| 103 | gptStartContinuous(&GPTD6, 2U); | ||
| 104 | palSetPadMode(GPIOA, 4, PAL_MODE_INPUT_ANALOG); | ||
| 105 | } | ||
| 106 | |||
| 107 | void channel_1_stop(void) { | ||
| 108 | gptStopTimer(&GPTD6); | ||
| 109 | palSetPadMode(GPIOA, 4, PAL_MODE_OUTPUT_PUSHPULL); | ||
| 110 | palSetPad(GPIOA, 4); | ||
| 111 | } | ||
| 112 | |||
| 113 | static float channel_1_frequency = 0.0f; | ||
| 114 | void channel_1_set_frequency(float freq) { | ||
| 115 | channel_1_frequency = freq; | ||
| 116 | |||
| 117 | channel_1_stop(); | ||
| 118 | if (freq <= 0.0) // a pause/rest has freq=0 | ||
| 119 | return; | ||
| 120 | |||
| 121 | gpt6cfg1.frequency = 2 * freq * AUDIO_DAC_BUFFER_SIZE; | ||
| 122 | channel_1_start(); | ||
| 123 | } | ||
| 124 | float channel_1_get_frequency(void) { return channel_1_frequency; } | ||
| 125 | |||
| 126 | void channel_2_start(void) { | ||
| 127 | gptStart(&GPTD7, &gpt7cfg1); | ||
| 128 | gptStartContinuous(&GPTD7, 2U); | ||
| 129 | palSetPadMode(GPIOA, 5, PAL_MODE_INPUT_ANALOG); | ||
| 130 | } | ||
| 131 | |||
| 132 | void channel_2_stop(void) { | ||
| 133 | gptStopTimer(&GPTD7); | ||
| 134 | palSetPadMode(GPIOA, 5, PAL_MODE_OUTPUT_PUSHPULL); | ||
| 135 | palSetPad(GPIOA, 5); | ||
| 136 | } | ||
| 137 | |||
| 138 | static float channel_2_frequency = 0.0f; | ||
| 139 | void channel_2_set_frequency(float freq) { | ||
| 140 | channel_2_frequency = freq; | ||
| 141 | |||
| 142 | channel_2_stop(); | ||
| 143 | if (freq <= 0.0) // a pause/rest has freq=0 | ||
| 144 | return; | ||
| 145 | |||
| 146 | gpt7cfg1.frequency = 2 * freq * AUDIO_DAC_BUFFER_SIZE; | ||
| 147 | channel_2_start(); | ||
| 148 | } | ||
| 149 | float channel_2_get_frequency(void) { return channel_2_frequency; } | ||
| 150 | |||
| 151 | static void gpt_audio_state_cb(GPTDriver *gptp) { | ||
| 152 | if (audio_update_state()) { | ||
| 153 | #if defined(AUDIO_PIN_ALT_AS_NEGATIVE) | ||
| 154 | // one piezo/speaker connected to both audio pins, the generated square-waves are inverted | ||
| 155 | channel_1_set_frequency(audio_get_processed_frequency(0)); | ||
| 156 | channel_2_set_frequency(audio_get_processed_frequency(0)); | ||
| 157 | |||
| 158 | #else // two separate audio outputs/speakers | ||
| 159 | // primary speaker on A4, optional secondary on A5 | ||
| 160 | if (AUDIO_PIN == A4) { | ||
| 161 | channel_1_set_frequency(audio_get_processed_frequency(0)); | ||
| 162 | if (AUDIO_PIN_ALT == A5) { | ||
| 163 | if (audio_get_number_of_active_tones() > 1) { | ||
| 164 | channel_2_set_frequency(audio_get_processed_frequency(1)); | ||
| 165 | } else { | ||
| 166 | channel_2_stop(); | ||
| 167 | } | ||
| 168 | } | ||
| 169 | } | ||
| 170 | |||
| 171 | // primary speaker on A5, optional secondary on A4 | ||
| 172 | if (AUDIO_PIN == A5) { | ||
| 173 | channel_2_set_frequency(audio_get_processed_frequency(0)); | ||
| 174 | if (AUDIO_PIN_ALT == A4) { | ||
| 175 | if (audio_get_number_of_active_tones() > 1) { | ||
| 176 | channel_1_set_frequency(audio_get_processed_frequency(1)); | ||
| 177 | } else { | ||
| 178 | channel_1_stop(); | ||
| 179 | } | ||
| 180 | } | ||
| 181 | } | ||
| 182 | #endif | ||
| 183 | } | ||
| 184 | } | ||
| 185 | |||
| 186 | void audio_driver_initialize() { | ||
| 187 | if ((AUDIO_PIN == A4) || (AUDIO_PIN_ALT == A4)) { | ||
| 188 | palSetPadMode(GPIOA, 4, PAL_MODE_INPUT_ANALOG); | ||
| 189 | dacStart(&DACD1, &dac_conf_ch1); | ||
| 190 | |||
| 191 | // initial setup of the dac-triggering timer is still required, even | ||
| 192 | // though it gets reconfigured and restarted later on | ||
| 193 | gptStart(&GPTD6, &gpt6cfg1); | ||
| 194 | } | ||
| 195 | |||
| 196 | if ((AUDIO_PIN == A5) || (AUDIO_PIN_ALT == A5)) { | ||
| 197 | palSetPadMode(GPIOA, 5, PAL_MODE_INPUT_ANALOG); | ||
| 198 | dacStart(&DACD2, &dac_conf_ch2); | ||
| 199 | |||
| 200 | gptStart(&GPTD7, &gpt7cfg1); | ||
| 201 | } | ||
| 202 | |||
| 203 | /* enable the output buffer, to directly drive external loads with no additional circuitry | ||
| 204 | * | ||
| 205 | * see: AN4566 Application note: Extending the DAC performance of STM32 microcontrollers | ||
| 206 | * Note: Buffer-Off bit -> has to be set 0 to enable the output buffer | ||
| 207 | * Note: enabling the output buffer imparts an additional dc-offset of a couple mV | ||
| 208 | * | ||
| 209 | * this is done here, reaching directly into the stm32 registers since chibios has not implemented BOFF handling yet | ||
| 210 | * (see: chibios/os/hal/ports/STM32/todo.txt '- BOFF handling in DACv1.' | ||
| 211 | */ | ||
| 212 | DACD1.params->dac->CR &= ~DAC_CR_BOFF1; | ||
| 213 | DACD2.params->dac->CR &= ~DAC_CR_BOFF2; | ||
| 214 | |||
| 215 | // start state-updater | ||
| 216 | gptStart(&AUDIO_STATE_TIMER, &gptStateUpdateCfg); | ||
| 217 | } | ||
| 218 | |||
| 219 | void audio_driver_stop(void) { | ||
| 220 | if ((AUDIO_PIN == A4) || (AUDIO_PIN_ALT == A4)) { | ||
| 221 | gptStopTimer(&GPTD6); | ||
| 222 | |||
| 223 | // stop the ongoing conversion and put the output in a known state | ||
| 224 | dacStopConversion(&DACD1); | ||
| 225 | dacPutChannelX(&DACD1, 0, AUDIO_DAC_OFF_VALUE); | ||
| 226 | } | ||
| 227 | |||
| 228 | if ((AUDIO_PIN == A5) || (AUDIO_PIN_ALT == A5)) { | ||
| 229 | gptStopTimer(&GPTD7); | ||
| 230 | |||
| 231 | dacStopConversion(&DACD2); | ||
| 232 | dacPutChannelX(&DACD2, 0, AUDIO_DAC_OFF_VALUE); | ||
| 233 | } | ||
| 234 | gptStopTimer(&AUDIO_STATE_TIMER); | ||
| 235 | } | ||
| 236 | |||
| 237 | void audio_driver_start(void) { | ||
| 238 | if ((AUDIO_PIN == A4) || (AUDIO_PIN_ALT == A4)) { | ||
| 239 | dacStartConversion(&DACD1, &dac_conv_grp_ch1, (dacsample_t *)dac_buffer_1, AUDIO_DAC_BUFFER_SIZE); | ||
| 240 | } | ||
| 241 | if ((AUDIO_PIN == A5) || (AUDIO_PIN_ALT == A5)) { | ||
| 242 | dacStartConversion(&DACD2, &dac_conv_grp_ch2, (dacsample_t *)dac_buffer_2, AUDIO_DAC_BUFFER_SIZE); | ||
| 243 | } | ||
| 244 | gptStartContinuous(&AUDIO_STATE_TIMER, 2U); | ||
| 245 | } | ||
diff --git a/platforms/chibios/drivers/audio_pwm.h b/platforms/chibios/drivers/audio_pwm.h new file mode 100644 index 000000000..86cab916e --- /dev/null +++ b/platforms/chibios/drivers/audio_pwm.h | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | /* Copyright 2020 Jack Humbert | ||
| 2 | * Copyright 2020 JohSchneider | ||
| 3 | * | ||
| 4 | * This program is free software: you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License as published by | ||
| 6 | * the Free Software Foundation, either version 2 of the License, or | ||
| 7 | * (at your option) any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | ||
| 17 | #pragma once | ||
| 18 | |||
| 19 | #if !defined(AUDIO_PWM_DRIVER) | ||
| 20 | // NOTE: Timer2 seems to be used otherwise in QMK, otherwise we could default to A5 (= TIM2_CH1, with PWMD2 and alternate-function(1)) | ||
| 21 | # define AUDIO_PWM_DRIVER PWMD1 | ||
| 22 | #endif | ||
| 23 | |||
| 24 | #if !defined(AUDIO_PWM_CHANNEL) | ||
| 25 | // NOTE: sticking to the STM data-sheet numbering: TIMxCH1 to TIMxCH4 | ||
| 26 | // default: STM32F303CC PA8+TIM1_CH1 -> 1 | ||
| 27 | # define AUDIO_PWM_CHANNEL 1 | ||
| 28 | #endif | ||
| 29 | |||
| 30 | #if !defined(AUDIO_PWM_PAL_MODE) | ||
| 31 | // pin-alternate function: see the data-sheet for which pin needs what AF to connect to TIMx_CHy | ||
| 32 | // default: STM32F303CC PA8+TIM1_CH1 -> 6 | ||
| 33 | # define AUDIO_PWM_PAL_MODE 6 | ||
| 34 | #endif | ||
| 35 | |||
| 36 | #if !defined(AUDIO_STATE_TIMER) | ||
| 37 | // timer used to trigger updates in the audio-system, configured/enabled in chibios mcuconf. | ||
| 38 | // Tim6 is the default for "larger" STMs, smaller ones might not have this one (enabled) and need to switch to a different one (e.g.: STM32F103 has only Tim1-Tim4) | ||
| 39 | # define AUDIO_STATE_TIMER GPTD6 | ||
| 40 | #endif | ||
diff --git a/platforms/chibios/drivers/audio_pwm_hardware.c b/platforms/chibios/drivers/audio_pwm_hardware.c new file mode 100644 index 000000000..cd40019ee --- /dev/null +++ b/platforms/chibios/drivers/audio_pwm_hardware.c | |||
| @@ -0,0 +1,144 @@ | |||
| 1 | /* Copyright 2020 Jack Humbert | ||
| 2 | * Copyright 2020 JohSchneider | ||
| 3 | * | ||
| 4 | * This program is free software: you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License as published by | ||
| 6 | * the Free Software Foundation, either version 2 of the License, or | ||
| 7 | * (at your option) any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | ||
| 17 | |||
| 18 | /* | ||
| 19 | Audio Driver: PWM | ||
| 20 | |||
| 21 | the duty-cycle is always kept at 50%, and the pwm-period is adjusted to match the frequency of a note to be played back. | ||
| 22 | |||
| 23 | this driver uses the chibios-PWM system to produce a square-wave on specific output pins that are connected to the PWM hardware. | ||
| 24 | The hardware directly toggles the pin via its alternate function. see your MCUs data-sheet for which pin can be driven by what timer - looking for TIMx_CHy and the corresponding alternate function. | ||
| 25 | |||
| 26 | */ | ||
| 27 | |||
| 28 | #include "audio.h" | ||
| 29 | #include "ch.h" | ||
| 30 | #include "hal.h" | ||
| 31 | |||
| 32 | #if !defined(AUDIO_PIN) | ||
| 33 | # error "Audio feature enabled, but no pin selected - see docs/feature_audio under the ARM PWM settings" | ||
| 34 | #endif | ||
| 35 | |||
| 36 | extern bool playing_note; | ||
| 37 | extern bool playing_melody; | ||
| 38 | extern uint8_t note_timbre; | ||
| 39 | |||
| 40 | static PWMConfig pwmCFG = { | ||
| 41 | .frequency = 100000, /* PWM clock frequency */ | ||
| 42 | // CHIBIOS-BUG? can't set the initial period to <2, or the pwm (hard or software) takes ~130ms with .frequency=500000 for a pwmChangePeriod to take effect; with no output=silence in the meantime | ||
| 43 | .period = 2, /* initial PWM period (in ticks) 1S (1/10kHz=0.1mS 0.1ms*10000 ticks=1S) */ | ||
| 44 | .callback = NULL, /* no callback, the hardware directly toggles the pin */ | ||
| 45 | .channels = | ||
| 46 | { | ||
| 47 | #if AUDIO_PWM_CHANNEL == 4 | ||
| 48 | {PWM_OUTPUT_DISABLED, NULL}, /* channel 0 -> TIMx_CH1 */ | ||
| 49 | {PWM_OUTPUT_DISABLED, NULL}, /* channel 1 -> TIMx_CH2 */ | ||
| 50 | {PWM_OUTPUT_DISABLED, NULL}, /* channel 2 -> TIMx_CH3 */ | ||
| 51 | {PWM_OUTPUT_ACTIVE_HIGH, NULL} /* channel 3 -> TIMx_CH4 */ | ||
| 52 | #elif AUDIO_PWM_CHANNEL == 3 | ||
| 53 | {PWM_OUTPUT_DISABLED, NULL}, | ||
| 54 | {PWM_OUTPUT_DISABLED, NULL}, | ||
| 55 | {PWM_OUTPUT_ACTIVE_HIGH, NULL}, /* TIMx_CH3 */ | ||
| 56 | {PWM_OUTPUT_DISABLED, NULL} | ||
| 57 | #elif AUDIO_PWM_CHANNEL == 2 | ||
| 58 | {PWM_OUTPUT_DISABLED, NULL}, | ||
| 59 | {PWM_OUTPUT_ACTIVE_HIGH, NULL}, /* TIMx_CH2 */ | ||
| 60 | {PWM_OUTPUT_DISABLED, NULL}, | ||
| 61 | {PWM_OUTPUT_DISABLED, NULL} | ||
| 62 | #else /*fallback to CH1 */ | ||
| 63 | {PWM_OUTPUT_ACTIVE_HIGH, NULL}, /* TIMx_CH1 */ | ||
| 64 | {PWM_OUTPUT_DISABLED, NULL}, | ||
| 65 | {PWM_OUTPUT_DISABLED, NULL}, | ||
| 66 | {PWM_OUTPUT_DISABLED, NULL} | ||
| 67 | #endif | ||
| 68 | }, | ||
| 69 | }; | ||
| 70 | |||
| 71 | static float channel_1_frequency = 0.0f; | ||
| 72 | void channel_1_set_frequency(float freq) { | ||
| 73 | channel_1_frequency = freq; | ||
| 74 | |||
| 75 | if (freq <= 0.0) // a pause/rest has freq=0 | ||
| 76 | return; | ||
| 77 | |||
| 78 | pwmcnt_t period = (pwmCFG.frequency / freq); | ||
| 79 | pwmChangePeriod(&AUDIO_PWM_DRIVER, period); | ||
| 80 | pwmEnableChannel(&AUDIO_PWM_DRIVER, AUDIO_PWM_CHANNEL - 1, | ||
| 81 | // adjust the duty-cycle so that the output is for 'note_timbre' duration HIGH | ||
| 82 | PWM_PERCENTAGE_TO_WIDTH(&AUDIO_PWM_DRIVER, (100 - note_timbre) * 100)); | ||
| 83 | } | ||
| 84 | |||
| 85 | float channel_1_get_frequency(void) { return channel_1_frequency; } | ||
| 86 | |||
| 87 | void channel_1_start(void) { | ||
| 88 | pwmStop(&AUDIO_PWM_DRIVER); | ||
| 89 | pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG); | ||
| 90 | } | ||
| 91 | |||
| 92 | void channel_1_stop(void) { pwmStop(&AUDIO_PWM_DRIVER); } | ||
| 93 | |||
| 94 | static void gpt_callback(GPTDriver *gptp); | ||
| 95 | GPTConfig gptCFG = { | ||
| 96 | /* a whole note is one beat, which is - per definition in musical_notes.h - set to 64 | ||
| 97 | the longest note is BREAVE_DOT=128+64=192, the shortest SIXTEENTH=4 | ||
| 98 | the tempo (which might vary!) is in bpm (beats per minute) | ||
| 99 | therefore: if the timer ticks away at .frequency = (60*64)Hz, | ||
| 100 | and the .interval counts from 64 downwards - audio_update_state is | ||
| 101 | called just often enough to not miss any notes | ||
| 102 | */ | ||
| 103 | .frequency = 60 * 64, | ||
| 104 | .callback = gpt_callback, | ||
| 105 | }; | ||
| 106 | |||
| 107 | void audio_driver_initialize(void) { | ||
| 108 | pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG); | ||
| 109 | |||
| 110 | // connect the AUDIO_PIN to the PWM hardware | ||
| 111 | #if defined(USE_GPIOV1) // STM32F103C8 | ||
| 112 | palSetLineMode(AUDIO_PIN, PAL_MODE_ALTERNATE_PUSHPULL); | ||
| 113 | #else // GPIOv2 (or GPIOv3 for f4xx, which is the same/compatible at this command) | ||
| 114 | palSetLineMode(AUDIO_PIN, PAL_MODE_ALTERNATE(AUDIO_PWM_PAL_MODE)); | ||
| 115 | #endif | ||
| 116 | |||
| 117 | gptStart(&AUDIO_STATE_TIMER, &gptCFG); | ||
| 118 | } | ||
| 119 | |||
| 120 | void audio_driver_start(void) { | ||
| 121 | channel_1_stop(); | ||
| 122 | channel_1_start(); | ||
| 123 | |||
| 124 | if (playing_note || playing_melody) { | ||
| 125 | gptStartContinuous(&AUDIO_STATE_TIMER, 64); | ||
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 129 | void audio_driver_stop(void) { | ||
| 130 | channel_1_stop(); | ||
| 131 | gptStopTimer(&AUDIO_STATE_TIMER); | ||
| 132 | } | ||
| 133 | |||
| 134 | /* a regular timer task, that checks the note to be currently played | ||
| 135 | * and updates the pwm to output that frequency | ||
| 136 | */ | ||
| 137 | static void gpt_callback(GPTDriver *gptp) { | ||
| 138 | float freq; // TODO: freq_alt | ||
| 139 | |||
| 140 | if (audio_update_state()) { | ||
| 141 | freq = audio_get_processed_frequency(0); // freq_alt would be index=1 | ||
| 142 | channel_1_set_frequency(freq); | ||
| 143 | } | ||
| 144 | } | ||
diff --git a/platforms/chibios/drivers/audio_pwm_software.c b/platforms/chibios/drivers/audio_pwm_software.c new file mode 100644 index 000000000..15c3e98b6 --- /dev/null +++ b/platforms/chibios/drivers/audio_pwm_software.c | |||
| @@ -0,0 +1,164 @@ | |||
| 1 | /* Copyright 2020 Jack Humbert | ||
| 2 | * Copyright 2020 JohSchneider | ||
| 3 | * | ||
| 4 | * This program is free software: you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License as published by | ||
| 6 | * the Free Software Foundation, either version 2 of the License, or | ||
| 7 | * (at your option) any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | ||
| 17 | |||
| 18 | /* | ||
| 19 | Audio Driver: PWM | ||
| 20 | |||
| 21 | the duty-cycle is always kept at 50%, and the pwm-period is adjusted to match the frequency of a note to be played back. | ||
| 22 | |||
| 23 | this driver uses the chibios-PWM system to produce a square-wave on any given output pin in software | ||
| 24 | - a pwm callback is used to set/clear the configured pin. | ||
| 25 | |||
| 26 | */ | ||
| 27 | #include "audio.h" | ||
| 28 | #include "ch.h" | ||
| 29 | #include "hal.h" | ||
| 30 | |||
| 31 | #if !defined(AUDIO_PIN) | ||
| 32 | # error "Audio feature enabled, but no pin selected - see docs/feature_audio under the ARM PWM settings" | ||
| 33 | #endif | ||
| 34 | extern bool playing_note; | ||
| 35 | extern bool playing_melody; | ||
| 36 | extern uint8_t note_timbre; | ||
| 37 | |||
| 38 | static void pwm_audio_period_callback(PWMDriver *pwmp); | ||
| 39 | static void pwm_audio_channel_interrupt_callback(PWMDriver *pwmp); | ||
| 40 | |||
| 41 | static PWMConfig pwmCFG = { | ||
| 42 | .frequency = 100000, /* PWM clock frequency */ | ||
| 43 | // CHIBIOS-BUG? can't set the initial period to <2, or the pwm (hard or software) takes ~130ms with .frequency=500000 for a pwmChangePeriod to take effect; with no output=silence in the meantime | ||
| 44 | .period = 2, /* initial PWM period (in ticks) 1S (1/10kHz=0.1mS 0.1ms*10000 ticks=1S) */ | ||
| 45 | .callback = pwm_audio_period_callback, | ||
| 46 | .channels = | ||
| 47 | { | ||
| 48 | // software-PWM just needs another callback on any channel | ||
| 49 | {PWM_OUTPUT_ACTIVE_HIGH, pwm_audio_channel_interrupt_callback}, /* channel 0 -> TIMx_CH1 */ | ||
| 50 | {PWM_OUTPUT_DISABLED, NULL}, /* channel 1 -> TIMx_CH2 */ | ||
| 51 | {PWM_OUTPUT_DISABLED, NULL}, /* channel 2 -> TIMx_CH3 */ | ||
| 52 | {PWM_OUTPUT_DISABLED, NULL} /* channel 3 -> TIMx_CH4 */ | ||
| 53 | }, | ||
| 54 | }; | ||
| 55 | |||
| 56 | static float channel_1_frequency = 0.0f; | ||
| 57 | void channel_1_set_frequency(float freq) { | ||
| 58 | channel_1_frequency = freq; | ||
| 59 | |||
| 60 | if (freq <= 0.0) // a pause/rest has freq=0 | ||
| 61 | return; | ||
| 62 | |||
| 63 | pwmcnt_t period = (pwmCFG.frequency / freq); | ||
| 64 | pwmChangePeriod(&AUDIO_PWM_DRIVER, period); | ||
| 65 | |||
| 66 | pwmEnableChannel(&AUDIO_PWM_DRIVER, AUDIO_PWM_CHANNEL - 1, | ||
| 67 | // adjust the duty-cycle so that the output is for 'note_timbre' duration HIGH | ||
| 68 | PWM_PERCENTAGE_TO_WIDTH(&AUDIO_PWM_DRIVER, (100 - note_timbre) * 100)); | ||
| 69 | } | ||
| 70 | |||
| 71 | float channel_1_get_frequency(void) { return channel_1_frequency; } | ||
| 72 | |||
| 73 | void channel_1_start(void) { | ||
| 74 | pwmStop(&AUDIO_PWM_DRIVER); | ||
| 75 | pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG); | ||
| 76 | |||
| 77 | pwmEnablePeriodicNotification(&AUDIO_PWM_DRIVER); | ||
| 78 | pwmEnableChannelNotification(&AUDIO_PWM_DRIVER, AUDIO_PWM_CHANNEL - 1); | ||
| 79 | } | ||
| 80 | |||
| 81 | void channel_1_stop(void) { | ||
| 82 | pwmStop(&AUDIO_PWM_DRIVER); | ||
| 83 | |||
| 84 | palClearLine(AUDIO_PIN); // leave the line low, after last note was played | ||
| 85 | |||
| 86 | #if defined(AUDIO_PIN_ALT) && defined(AUDIO_PIN_ALT_AS_NEGATIVE) | ||
| 87 | palClearLine(AUDIO_PIN_ALT); // leave the line low, after last note was played | ||
| 88 | #endif | ||
| 89 | } | ||
| 90 | |||
| 91 | // generate a PWM signal on any pin, not necessarily the one connected to the timer | ||
| 92 | static void pwm_audio_period_callback(PWMDriver *pwmp) { | ||
| 93 | (void)pwmp; | ||
| 94 | palClearLine(AUDIO_PIN); | ||
| 95 | |||
| 96 | #if defined(AUDIO_PIN_ALT) && defined(AUDIO_PIN_ALT_AS_NEGATIVE) | ||
| 97 | palSetLine(AUDIO_PIN_ALT); | ||
| 98 | #endif | ||
| 99 | } | ||
| 100 | static void pwm_audio_channel_interrupt_callback(PWMDriver *pwmp) { | ||
| 101 | (void)pwmp; | ||
| 102 | if (channel_1_frequency > 0) { | ||
| 103 | palSetLine(AUDIO_PIN); // generate a PWM signal on any pin, not necessarily the one connected to the timer | ||
| 104 | #if defined(AUDIO_PIN_ALT) && defined(AUDIO_PIN_ALT_AS_NEGATIVE) | ||
| 105 | palClearLine(AUDIO_PIN_ALT); | ||
| 106 | #endif | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | static void gpt_callback(GPTDriver *gptp); | ||
| 111 | GPTConfig gptCFG = { | ||
| 112 | /* a whole note is one beat, which is - per definition in musical_notes.h - set to 64 | ||
| 113 | the longest note is BREAVE_DOT=128+64=192, the shortest SIXTEENTH=4 | ||
| 114 | the tempo (which might vary!) is in bpm (beats per minute) | ||
| 115 | therefore: if the timer ticks away at .frequency = (60*64)Hz, | ||
| 116 | and the .interval counts from 64 downwards - audio_update_state is | ||
| 117 | called just often enough to not miss anything | ||
| 118 | */ | ||
| 119 | .frequency = 60 * 64, | ||
| 120 | .callback = gpt_callback, | ||
| 121 | }; | ||
| 122 | |||
| 123 | void audio_driver_initialize(void) { | ||
| 124 | pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG); | ||
| 125 | |||
| 126 | palSetLineMode(AUDIO_PIN, PAL_MODE_OUTPUT_PUSHPULL); | ||
| 127 | palClearLine(AUDIO_PIN); | ||
| 128 | |||
| 129 | #if defined(AUDIO_PIN_ALT) && defined(AUDIO_PIN_ALT_AS_NEGATIVE) | ||
| 130 | palSetLineMode(AUDIO_PIN_ALT, PAL_MODE_OUTPUT_PUSHPULL); | ||
| 131 | palClearLine(AUDIO_PIN_ALT); | ||
| 132 | #endif | ||
| 133 | |||
| 134 | pwmEnablePeriodicNotification(&AUDIO_PWM_DRIVER); // enable pwm callbacks | ||
| 135 | pwmEnableChannelNotification(&AUDIO_PWM_DRIVER, AUDIO_PWM_CHANNEL - 1); | ||
| 136 | |||
| 137 | gptStart(&AUDIO_STATE_TIMER, &gptCFG); | ||
| 138 | } | ||
| 139 | |||
| 140 | void audio_driver_start(void) { | ||
| 141 | channel_1_stop(); | ||
| 142 | channel_1_start(); | ||
| 143 | |||
| 144 | if (playing_note || playing_melody) { | ||
| 145 | gptStartContinuous(&AUDIO_STATE_TIMER, 64); | ||
| 146 | } | ||
| 147 | } | ||
| 148 | |||
| 149 | void audio_driver_stop(void) { | ||
| 150 | channel_1_stop(); | ||
| 151 | gptStopTimer(&AUDIO_STATE_TIMER); | ||
| 152 | } | ||
| 153 | |||
| 154 | /* a regular timer task, that checks the note to be currently played | ||
| 155 | * and updates the pwm to output that frequency | ||
| 156 | */ | ||
| 157 | static void gpt_callback(GPTDriver *gptp) { | ||
| 158 | float freq; // TODO: freq_alt | ||
| 159 | |||
| 160 | if (audio_update_state()) { | ||
| 161 | freq = audio_get_processed_frequency(0); // freq_alt would be index=1 | ||
| 162 | channel_1_set_frequency(freq); | ||
| 163 | } | ||
| 164 | } | ||
diff --git a/platforms/chibios/drivers/i2c_master.c b/platforms/chibios/drivers/i2c_master.c index fc4bb2ab3..63e85ae87 100644 --- a/platforms/chibios/drivers/i2c_master.c +++ b/platforms/chibios/drivers/i2c_master.c | |||
| @@ -63,16 +63,16 @@ __attribute__((weak)) void i2c_init(void) { | |||
| 63 | is_initialised = true; | 63 | is_initialised = true; |
| 64 | 64 | ||
| 65 | // Try releasing special pins for a short time | 65 | // Try releasing special pins for a short time |
| 66 | palSetPadMode(I2C1_SCL_BANK, I2C1_SCL, PAL_MODE_INPUT); | 66 | palSetLineMode(I2C1_SCL_PIN, PAL_MODE_INPUT); |
| 67 | palSetPadMode(I2C1_SDA_BANK, I2C1_SDA, PAL_MODE_INPUT); | 67 | palSetLineMode(I2C1_SDA_PIN, PAL_MODE_INPUT); |
| 68 | 68 | ||
| 69 | chThdSleepMilliseconds(10); | 69 | chThdSleepMilliseconds(10); |
| 70 | #if defined(USE_GPIOV1) | 70 | #if defined(USE_GPIOV1) |
| 71 | palSetPadMode(I2C1_SCL_BANK, I2C1_SCL, I2C1_SCL_PAL_MODE); | 71 | palSetLineMode(I2C1_SCL_PIN, I2C1_SCL_PAL_MODE); |
| 72 | palSetPadMode(I2C1_SDA_BANK, I2C1_SDA, I2C1_SDA_PAL_MODE); | 72 | palSetLineMode(I2C1_SDA_PIN, I2C1_SDA_PAL_MODE); |
| 73 | #else | 73 | #else |
| 74 | palSetPadMode(I2C1_SCL_BANK, I2C1_SCL, PAL_MODE_ALTERNATE(I2C1_SCL_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN); | 74 | palSetLineMode(I2C1_SCL_PIN, PAL_MODE_ALTERNATE(I2C1_SCL_PAL_MODE) | PAL_OUTPUT_TYPE_OPENDRAIN); |
| 75 | palSetPadMode(I2C1_SDA_BANK, I2C1_SDA, PAL_MODE_ALTERNATE(I2C1_SDA_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN); | 75 | palSetLineMode(I2C1_SDA_PIN, PAL_MODE_ALTERNATE(I2C1_SDA_PAL_MODE) | PAL_OUTPUT_TYPE_OPENDRAIN); |
| 76 | #endif | 76 | #endif |
| 77 | } | 77 | } |
| 78 | } | 78 | } |
| @@ -102,7 +102,7 @@ i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, | |||
| 102 | i2cStart(&I2C_DRIVER, &i2cconfig); | 102 | i2cStart(&I2C_DRIVER, &i2cconfig); |
| 103 | 103 | ||
| 104 | uint8_t complete_packet[length + 1]; | 104 | uint8_t complete_packet[length + 1]; |
| 105 | for (uint8_t i = 0; i < length; i++) { | 105 | for (uint16_t i = 0; i < length; i++) { |
| 106 | complete_packet[i + 1] = data[i]; | 106 | complete_packet[i + 1] = data[i]; |
| 107 | } | 107 | } |
| 108 | complete_packet[0] = regaddr; | 108 | complete_packet[0] = regaddr; |
| @@ -111,6 +111,21 @@ i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, | |||
| 111 | return chibios_to_qmk(&status); | 111 | return chibios_to_qmk(&status); |
| 112 | } | 112 | } |
| 113 | 113 | ||
| 114 | i2c_status_t i2c_writeReg16(uint8_t devaddr, uint16_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout) { | ||
| 115 | i2c_address = devaddr; | ||
| 116 | i2cStart(&I2C_DRIVER, &i2cconfig); | ||
| 117 | |||
| 118 | uint8_t complete_packet[length + 2]; | ||
| 119 | for (uint16_t i = 0; i < length; i++) { | ||
| 120 | complete_packet[i + 2] = data[i]; | ||
| 121 | } | ||
| 122 | complete_packet[0] = regaddr >> 8; | ||
| 123 | complete_packet[1] = regaddr & 0xFF; | ||
| 124 | |||
| 125 | msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), complete_packet, length + 2, 0, 0, TIME_MS2I(timeout)); | ||
| 126 | return chibios_to_qmk(&status); | ||
| 127 | } | ||
| 128 | |||
| 114 | i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) { | 129 | i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) { |
| 115 | i2c_address = devaddr; | 130 | i2c_address = devaddr; |
| 116 | i2cStart(&I2C_DRIVER, &i2cconfig); | 131 | i2cStart(&I2C_DRIVER, &i2cconfig); |
| @@ -118,4 +133,12 @@ i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16 | |||
| 118 | return chibios_to_qmk(&status); | 133 | return chibios_to_qmk(&status); |
| 119 | } | 134 | } |
| 120 | 135 | ||
| 136 | i2c_status_t i2c_readReg16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) { | ||
| 137 | i2c_address = devaddr; | ||
| 138 | i2cStart(&I2C_DRIVER, &i2cconfig); | ||
| 139 | uint8_t register_packet[2] = {regaddr >> 8, regaddr & 0xFF}; | ||
| 140 | msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), register_packet, 2, data, length, TIME_MS2I(timeout)); | ||
| 141 | return chibios_to_qmk(&status); | ||
| 142 | } | ||
| 143 | |||
| 121 | void i2c_stop(void) { i2cStop(&I2C_DRIVER); } | 144 | void i2c_stop(void) { i2cStop(&I2C_DRIVER); } |
diff --git a/platforms/chibios/drivers/i2c_master.h b/platforms/chibios/drivers/i2c_master.h index c68109acb..5f082e9d1 100644 --- a/platforms/chibios/drivers/i2c_master.h +++ b/platforms/chibios/drivers/i2c_master.h | |||
| @@ -27,24 +27,11 @@ | |||
| 27 | #include <ch.h> | 27 | #include <ch.h> |
| 28 | #include <hal.h> | 28 | #include <hal.h> |
| 29 | 29 | ||
| 30 | #ifdef I2C1_BANK | 30 | #ifndef I2C1_SCL_PIN |
| 31 | # define I2C1_SCL_BANK I2C1_BANK | 31 | # define I2C1_SCL_PIN B6 |
| 32 | # define I2C1_SDA_BANK I2C1_BANK | ||
| 33 | #endif | 32 | #endif |
| 34 | 33 | #ifndef I2C1_SDA_PIN | |
| 35 | #ifndef I2C1_SCL_BANK | 34 | # define I2C1_SDA_PIN B7 |
| 36 | # define I2C1_SCL_BANK GPIOB | ||
| 37 | #endif | ||
| 38 | |||
| 39 | #ifndef I2C1_SDA_BANK | ||
| 40 | # define I2C1_SDA_BANK GPIOB | ||
| 41 | #endif | ||
| 42 | |||
| 43 | #ifndef I2C1_SCL | ||
| 44 | # define I2C1_SCL 6 | ||
| 45 | #endif | ||
| 46 | #ifndef I2C1_SDA | ||
| 47 | # define I2C1_SDA 7 | ||
| 48 | #endif | 35 | #endif |
| 49 | 36 | ||
| 50 | #ifdef USE_I2CV1 | 37 | #ifdef USE_I2CV1 |
| @@ -83,10 +70,10 @@ | |||
| 83 | 70 | ||
| 84 | #ifdef USE_GPIOV1 | 71 | #ifdef USE_GPIOV1 |
| 85 | # ifndef I2C1_SCL_PAL_MODE | 72 | # ifndef I2C1_SCL_PAL_MODE |
| 86 | # define I2C1_SCL_PAL_MODE PAL_MODE_STM32_ALTERNATE_OPENDRAIN | 73 | # define I2C1_SCL_PAL_MODE PAL_MODE_ALTERNATE_OPENDRAIN |
| 87 | # endif | 74 | # endif |
| 88 | # ifndef I2C1_SDA_PAL_MODE | 75 | # ifndef I2C1_SDA_PAL_MODE |
| 89 | # define I2C1_SDA_PAL_MODE PAL_MODE_STM32_ALTERNATE_OPENDRAIN | 76 | # define I2C1_SDA_PAL_MODE PAL_MODE_ALTERNATE_OPENDRAIN |
| 90 | # endif | 77 | # endif |
| 91 | #else | 78 | #else |
| 92 | // The default PAL alternate modes are used to signal that the pins are used for I2C | 79 | // The default PAL alternate modes are used to signal that the pins are used for I2C |
| @@ -109,5 +96,7 @@ i2c_status_t i2c_start(uint8_t address); | |||
| 109 | i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout); | 96 | i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout); |
| 110 | i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout); | 97 | i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout); |
| 111 | i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout); | 98 | i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout); |
| 99 | i2c_status_t i2c_writeReg16(uint8_t devaddr, uint16_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout); | ||
| 112 | i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout); | 100 | i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout); |
| 101 | i2c_status_t i2c_readReg16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout); | ||
| 113 | void i2c_stop(void); | 102 | void i2c_stop(void); |
diff --git a/platforms/chibios/drivers/ps2/ps2_io.c b/platforms/chibios/drivers/ps2/ps2_io.c new file mode 100644 index 000000000..906d85d84 --- /dev/null +++ b/platforms/chibios/drivers/ps2/ps2_io.c | |||
| @@ -0,0 +1,55 @@ | |||
| 1 | #include <stdbool.h> | ||
| 2 | #include "ps2_io.h" | ||
| 3 | |||
| 4 | // chibiOS headers | ||
| 5 | #include "ch.h" | ||
| 6 | #include "hal.h" | ||
| 7 | |||
| 8 | /* Check port settings for clock and data line */ | ||
| 9 | #if !(defined(PS2_CLOCK_PIN)) | ||
| 10 | # error "PS/2 clock setting is required in config.h" | ||
| 11 | #endif | ||
| 12 | |||
| 13 | #if !(defined(PS2_DATA_PIN)) | ||
| 14 | # error "PS/2 data setting is required in config.h" | ||
| 15 | #endif | ||
| 16 | |||
| 17 | /* | ||
| 18 | * Clock | ||
| 19 | */ | ||
| 20 | void clock_init(void) {} | ||
| 21 | |||
| 22 | void clock_lo(void) { | ||
| 23 | palSetLineMode(PS2_CLOCK_PIN, PAL_MODE_OUTPUT_OPENDRAIN); | ||
| 24 | palWriteLine(PS2_CLOCK_PIN, PAL_LOW); | ||
| 25 | } | ||
| 26 | |||
| 27 | void clock_hi(void) { | ||
| 28 | palSetLineMode(PS2_CLOCK_PIN, PAL_MODE_OUTPUT_OPENDRAIN); | ||
| 29 | palWriteLine(PS2_CLOCK_PIN, PAL_HIGH); | ||
| 30 | } | ||
| 31 | |||
| 32 | bool clock_in(void) { | ||
| 33 | palSetLineMode(PS2_CLOCK_PIN, PAL_MODE_INPUT); | ||
| 34 | return palReadLine(PS2_CLOCK_PIN); | ||
| 35 | } | ||
| 36 | |||
| 37 | /* | ||
| 38 | * Data | ||
| 39 | */ | ||
| 40 | void data_init(void) {} | ||
| 41 | |||
| 42 | void data_lo(void) { | ||
| 43 | palSetLineMode(PS2_DATA_PIN, PAL_MODE_OUTPUT_OPENDRAIN); | ||
| 44 | palWriteLine(PS2_DATA_PIN, PAL_LOW); | ||
| 45 | } | ||
| 46 | |||
| 47 | void data_hi(void) { | ||
| 48 | palSetLineMode(PS2_DATA_PIN, PAL_MODE_OUTPUT_OPENDRAIN); | ||
| 49 | palWriteLine(PS2_DATA_PIN, PAL_HIGH); | ||
| 50 | } | ||
| 51 | |||
| 52 | bool data_in(void) { | ||
| 53 | palSetLineMode(PS2_DATA_PIN, PAL_MODE_INPUT); | ||
| 54 | return palReadLine(PS2_DATA_PIN); | ||
| 55 | } | ||
diff --git a/platforms/chibios/drivers/serial.c b/platforms/chibios/drivers/serial.c index f54fbcee4..ef6f0aa8d 100644 --- a/platforms/chibios/drivers/serial.c +++ b/platforms/chibios/drivers/serial.c | |||
| @@ -19,7 +19,7 @@ | |||
| 19 | # error "chSysPolledDelayX method not supported on this platform" | 19 | # error "chSysPolledDelayX method not supported on this platform" |
| 20 | #else | 20 | #else |
| 21 | # undef wait_us | 21 | # undef wait_us |
| 22 | # define wait_us(x) chSysPolledDelayX(US2RTC(STM32_SYSCLK, x)) | 22 | # define wait_us(x) chSysPolledDelayX(US2RTC(CPU_CLOCK, x)) |
| 23 | #endif | 23 | #endif |
| 24 | 24 | ||
| 25 | #ifndef SELECT_SOFT_SERIAL_SPEED | 25 | #ifndef SELECT_SOFT_SERIAL_SPEED |
diff --git a/platforms/chibios/drivers/serial_usart.c b/platforms/chibios/drivers/serial_usart.c index ea4473791..124e4be68 100644 --- a/platforms/chibios/drivers/serial_usart.c +++ b/platforms/chibios/drivers/serial_usart.c | |||
| @@ -104,9 +104,9 @@ static inline bool receive(uint8_t* destination, const size_t size) { | |||
| 104 | __attribute__((weak)) void usart_init(void) { | 104 | __attribute__((weak)) void usart_init(void) { |
| 105 | # if defined(MCU_STM32) | 105 | # if defined(MCU_STM32) |
| 106 | # if defined(USE_GPIOV1) | 106 | # if defined(USE_GPIOV1) |
| 107 | palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_STM32_ALTERNATE_OPENDRAIN); | 107 | palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE_OPENDRAIN); |
| 108 | # else | 108 | # else |
| 109 | palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE(SERIAL_USART_TX_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN); | 109 | palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE(SERIAL_USART_TX_PAL_MODE) | PAL_OUTPUT_TYPE_OPENDRAIN); |
| 110 | # endif | 110 | # endif |
| 111 | 111 | ||
| 112 | # if defined(USART_REMAP) | 112 | # if defined(USART_REMAP) |
| @@ -125,11 +125,11 @@ __attribute__((weak)) void usart_init(void) { | |||
| 125 | __attribute__((weak)) void usart_init(void) { | 125 | __attribute__((weak)) void usart_init(void) { |
| 126 | # if defined(MCU_STM32) | 126 | # if defined(MCU_STM32) |
| 127 | # if defined(USE_GPIOV1) | 127 | # if defined(USE_GPIOV1) |
| 128 | palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_STM32_ALTERNATE_PUSHPULL); | 128 | palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE_PUSHPULL); |
| 129 | palSetLineMode(SERIAL_USART_RX_PIN, PAL_MODE_INPUT); | 129 | palSetLineMode(SERIAL_USART_RX_PIN, PAL_MODE_INPUT); |
| 130 | # else | 130 | # else |
| 131 | palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE(SERIAL_USART_TX_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); | 131 | palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE(SERIAL_USART_TX_PAL_MODE) | PAL_OUTPUT_TYPE_PUSHPULL | PAL_OUTPUT_SPEED_HIGHEST); |
| 132 | palSetLineMode(SERIAL_USART_RX_PIN, PAL_MODE_ALTERNATE(SERIAL_USART_RX_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); | 132 | palSetLineMode(SERIAL_USART_RX_PIN, PAL_MODE_ALTERNATE(SERIAL_USART_RX_PAL_MODE) | PAL_OUTPUT_TYPE_PUSHPULL | PAL_OUTPUT_SPEED_HIGHEST); |
| 133 | # endif | 133 | # endif |
| 134 | 134 | ||
| 135 | # if defined(USART_REMAP) | 135 | # if defined(USART_REMAP) |
diff --git a/platforms/chibios/drivers/spi_master.c b/platforms/chibios/drivers/spi_master.c index 28ddcbb2b..c592369dd 100644 --- a/platforms/chibios/drivers/spi_master.c +++ b/platforms/chibios/drivers/spi_master.c | |||
| @@ -42,9 +42,9 @@ __attribute__((weak)) void spi_init(void) { | |||
| 42 | palSetPadMode(PAL_PORT(SPI_MOSI_PIN), PAL_PAD(SPI_MOSI_PIN), SPI_MOSI_PAL_MODE); | 42 | palSetPadMode(PAL_PORT(SPI_MOSI_PIN), PAL_PAD(SPI_MOSI_PIN), SPI_MOSI_PAL_MODE); |
| 43 | palSetPadMode(PAL_PORT(SPI_MISO_PIN), PAL_PAD(SPI_MISO_PIN), SPI_MISO_PAL_MODE); | 43 | palSetPadMode(PAL_PORT(SPI_MISO_PIN), PAL_PAD(SPI_MISO_PIN), SPI_MISO_PAL_MODE); |
| 44 | #else | 44 | #else |
| 45 | palSetPadMode(PAL_PORT(SPI_SCK_PIN), PAL_PAD(SPI_SCK_PIN), PAL_MODE_ALTERNATE(SPI_SCK_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); | 45 | palSetPadMode(PAL_PORT(SPI_SCK_PIN), PAL_PAD(SPI_SCK_PIN), PAL_MODE_ALTERNATE(SPI_SCK_PAL_MODE) | PAL_OUTPUT_TYPE_PUSHPULL | PAL_OUTPUT_SPEED_HIGHEST); |
| 46 | palSetPadMode(PAL_PORT(SPI_MOSI_PIN), PAL_PAD(SPI_MOSI_PIN), PAL_MODE_ALTERNATE(SPI_MOSI_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); | 46 | palSetPadMode(PAL_PORT(SPI_MOSI_PIN), PAL_PAD(SPI_MOSI_PIN), PAL_MODE_ALTERNATE(SPI_MOSI_PAL_MODE) | PAL_OUTPUT_TYPE_PUSHPULL | PAL_OUTPUT_SPEED_HIGHEST); |
| 47 | palSetPadMode(PAL_PORT(SPI_MISO_PIN), PAL_PAD(SPI_MISO_PIN), PAL_MODE_ALTERNATE(SPI_MISO_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL | PAL_STM32_OSPEED_HIGHEST); | 47 | palSetPadMode(PAL_PORT(SPI_MISO_PIN), PAL_PAD(SPI_MISO_PIN), PAL_MODE_ALTERNATE(SPI_MISO_PAL_MODE) | PAL_OUTPUT_TYPE_PUSHPULL | PAL_OUTPUT_SPEED_HIGHEST); |
| 48 | #endif | 48 | #endif |
| 49 | } | 49 | } |
| 50 | } | 50 | } |
| @@ -110,6 +110,31 @@ bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) { | |||
| 110 | spiConfig.tar0 |= SPIx_CTARn_BR(8); | 110 | spiConfig.tar0 |= SPIx_CTARn_BR(8); |
| 111 | break; | 111 | break; |
| 112 | } | 112 | } |
| 113 | |||
| 114 | #elif defined(HT32) | ||
| 115 | spiConfig.cr0 = SPI_CR0_SELOEN; | ||
| 116 | spiConfig.cr1 = SPI_CR1_MODE | 8; // 8 bits and in master mode | ||
| 117 | |||
| 118 | if (lsbFirst) { | ||
| 119 | spiConfig.cr1 |= SPI_CR1_FIRSTBIT; | ||
| 120 | } | ||
| 121 | |||
| 122 | switch (mode) { | ||
| 123 | case 0: | ||
| 124 | spiConfig.cr1 |= SPI_CR1_FORMAT_MODE0; | ||
| 125 | break; | ||
| 126 | case 1: | ||
| 127 | spiConfig.cr1 |= SPI_CR1_FORMAT_MODE1; | ||
| 128 | break; | ||
| 129 | case 2: | ||
| 130 | spiConfig.cr1 |= SPI_CR1_FORMAT_MODE2; | ||
| 131 | break; | ||
| 132 | case 3: | ||
| 133 | spiConfig.cr1 |= SPI_CR1_FORMAT_MODE3; | ||
| 134 | break; | ||
| 135 | } | ||
| 136 | |||
| 137 | spiConfig.cpr = (roundedDivisor - 1) >> 1; | ||
| 113 | #else | 138 | #else |
| 114 | spiConfig.cr1 = 0; | 139 | spiConfig.cr1 = 0; |
| 115 | 140 | ||
diff --git a/platforms/chibios/drivers/spi_master.h b/platforms/chibios/drivers/spi_master.h index b5a6ef143..6a3ce481f 100644 --- a/platforms/chibios/drivers/spi_master.h +++ b/platforms/chibios/drivers/spi_master.h | |||
| @@ -33,7 +33,7 @@ | |||
| 33 | 33 | ||
| 34 | #ifndef SPI_SCK_PAL_MODE | 34 | #ifndef SPI_SCK_PAL_MODE |
| 35 | # if defined(USE_GPIOV1) | 35 | # if defined(USE_GPIOV1) |
| 36 | # define SPI_SCK_PAL_MODE PAL_MODE_STM32_ALTERNATE_PUSHPULL | 36 | # define SPI_SCK_PAL_MODE PAL_MODE_ALTERNATE_PUSHPULL |
| 37 | # else | 37 | # else |
| 38 | # define SPI_SCK_PAL_MODE 5 | 38 | # define SPI_SCK_PAL_MODE 5 |
| 39 | # endif | 39 | # endif |
| @@ -45,7 +45,7 @@ | |||
| 45 | 45 | ||
| 46 | #ifndef SPI_MOSI_PAL_MODE | 46 | #ifndef SPI_MOSI_PAL_MODE |
| 47 | # if defined(USE_GPIOV1) | 47 | # if defined(USE_GPIOV1) |
| 48 | # define SPI_MOSI_PAL_MODE PAL_MODE_STM32_ALTERNATE_PUSHPULL | 48 | # define SPI_MOSI_PAL_MODE PAL_MODE_ALTERNATE_PUSHPULL |
| 49 | # else | 49 | # else |
| 50 | # define SPI_MOSI_PAL_MODE 5 | 50 | # define SPI_MOSI_PAL_MODE 5 |
| 51 | # endif | 51 | # endif |
| @@ -57,7 +57,7 @@ | |||
| 57 | 57 | ||
| 58 | #ifndef SPI_MISO_PAL_MODE | 58 | #ifndef SPI_MISO_PAL_MODE |
| 59 | # if defined(USE_GPIOV1) | 59 | # if defined(USE_GPIOV1) |
| 60 | # define SPI_MISO_PAL_MODE PAL_MODE_STM32_ALTERNATE_PUSHPULL | 60 | # define SPI_MISO_PAL_MODE PAL_MODE_ALTERNATE_PUSHPULL |
| 61 | # else | 61 | # else |
| 62 | # define SPI_MISO_PAL_MODE 5 | 62 | # define SPI_MISO_PAL_MODE 5 |
| 63 | # endif | 63 | # endif |
diff --git a/platforms/chibios/drivers/uart.c b/platforms/chibios/drivers/uart.c index 030335b34..297c1892c 100644 --- a/platforms/chibios/drivers/uart.c +++ b/platforms/chibios/drivers/uart.c | |||
| @@ -29,22 +29,26 @@ void uart_init(uint32_t baud) { | |||
| 29 | serialConfig.speed = baud; | 29 | serialConfig.speed = baud; |
| 30 | 30 | ||
| 31 | #if defined(USE_GPIOV1) | 31 | #if defined(USE_GPIOV1) |
| 32 | palSetLineMode(SD1_TX_PIN, PAL_MODE_STM32_ALTERNATE_OPENDRAIN); | 32 | palSetLineMode(SD1_TX_PIN, PAL_MODE_ALTERNATE_OPENDRAIN); |
| 33 | palSetLineMode(SD1_RX_PIN, PAL_MODE_STM32_ALTERNATE_OPENDRAIN); | 33 | palSetLineMode(SD1_RX_PIN, PAL_MODE_ALTERNATE_OPENDRAIN); |
| 34 | #else | 34 | #else |
| 35 | palSetLineMode(SD1_TX_PIN, PAL_MODE_ALTERNATE(SD1_TX_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN); | 35 | palSetLineMode(SD1_TX_PIN, PAL_MODE_ALTERNATE(SD1_TX_PAL_MODE) | PAL_OUTPUT_TYPE_OPENDRAIN); |
| 36 | palSetLineMode(SD1_RX_PIN, PAL_MODE_ALTERNATE(SD1_RX_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN); | 36 | palSetLineMode(SD1_RX_PIN, PAL_MODE_ALTERNATE(SD1_RX_PAL_MODE) | PAL_OUTPUT_TYPE_OPENDRAIN); |
| 37 | #endif | 37 | #endif |
| 38 | sdStart(&SERIAL_DRIVER, &serialConfig); | 38 | sdStart(&SERIAL_DRIVER, &serialConfig); |
| 39 | } | 39 | } |
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | void uart_putchar(uint8_t c) { sdPut(&SERIAL_DRIVER, c); } | 42 | void uart_write(uint8_t data) { sdPut(&SERIAL_DRIVER, c); } |
| 43 | 43 | ||
| 44 | uint8_t uart_getchar(void) { | 44 | uint8_t uart_read(void) { |
| 45 | msg_t res = sdGet(&SERIAL_DRIVER); | 45 | msg_t res = sdGet(&SERIAL_DRIVER); |
| 46 | 46 | ||
| 47 | return (uint8_t)res; | 47 | return (uint8_t)res; |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | void uart_transmit(const uint8_t *data, uint16_t length) { sdWrite(&SERIAL_DRIVER, data, length); } | ||
| 51 | |||
| 52 | void uart_receive(uint8_t *data, uint16_t length) { sdRead(&SERIAL_DRIVER, data, length); } | ||
| 53 | |||
| 50 | bool uart_available(void) { return !sdGetWouldBlock(&SERIAL_DRIVER); } | 54 | bool uart_available(void) { return !sdGetWouldBlock(&SERIAL_DRIVER); } |
diff --git a/platforms/chibios/drivers/uart.h b/platforms/chibios/drivers/uart.h index b4e20e9fd..5bc487590 100644 --- a/platforms/chibios/drivers/uart.h +++ b/platforms/chibios/drivers/uart.h | |||
| @@ -70,8 +70,12 @@ | |||
| 70 | 70 | ||
| 71 | void uart_init(uint32_t baud); | 71 | void uart_init(uint32_t baud); |
| 72 | 72 | ||
| 73 | void uart_putchar(uint8_t c); | 73 | void uart_write(uint8_t data); |
| 74 | 74 | ||
| 75 | uint8_t uart_getchar(void); | 75 | uint8_t uart_read(void); |
| 76 | |||
| 77 | void uart_transmit(const uint8_t *data, uint16_t length); | ||
| 78 | |||
| 79 | void uart_receive(uint8_t *data, uint16_t length); | ||
| 76 | 80 | ||
| 77 | bool uart_available(void); | 81 | bool uart_available(void); |
diff --git a/platforms/chibios/drivers/ws2812.c b/platforms/chibios/drivers/ws2812.c index 0d12e2fb7..b46c46ae5 100644 --- a/platforms/chibios/drivers/ws2812.c +++ b/platforms/chibios/drivers/ws2812.c | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | /* Adapted from https://github.com/bigjosh/SimpleNeoPixelDemo/ */ | 6 | /* Adapted from https://github.com/bigjosh/SimpleNeoPixelDemo/ */ |
| 7 | 7 | ||
| 8 | #ifndef NOP_FUDGE | 8 | #ifndef NOP_FUDGE |
| 9 | # if defined(STM32F0XX) || defined(STM32F1XX) || defined(STM32F3XX) || defined(STM32F4XX) || defined(STM32L0XX) | 9 | # if defined(STM32F0XX) || defined(STM32F1XX) || defined(GD32VF103) || defined(STM32F3XX) || defined(STM32F4XX) || defined(STM32L0XX) |
| 10 | # define NOP_FUDGE 0.4 | 10 | # define NOP_FUDGE 0.4 |
| 11 | # else | 11 | # else |
| 12 | # error("NOP_FUDGE configuration required") | 12 | # error("NOP_FUDGE configuration required") |
| @@ -23,7 +23,7 @@ | |||
| 23 | #endif | 23 | #endif |
| 24 | 24 | ||
| 25 | #define NUMBER_NOPS 6 | 25 | #define NUMBER_NOPS 6 |
| 26 | #define CYCLES_PER_SEC (STM32_SYSCLK / NUMBER_NOPS * NOP_FUDGE) | 26 | #define CYCLES_PER_SEC (CPU_CLOCK / NUMBER_NOPS * NOP_FUDGE) |
| 27 | #define NS_PER_SEC (1000000000L) // Note that this has to be SIGNED since we want to be able to check for negative values of derivatives | 27 | #define NS_PER_SEC (1000000000L) // Note that this has to be SIGNED since we want to be able to check for negative values of derivatives |
| 28 | #define NS_PER_CYCLE (NS_PER_SEC / CYCLES_PER_SEC) | 28 | #define NS_PER_CYCLE (NS_PER_SEC / CYCLES_PER_SEC) |
| 29 | #define NS_TO_CYCLES(n) ((n) / NS_PER_CYCLE) | 29 | #define NS_TO_CYCLES(n) ((n) / NS_PER_CYCLE) |
diff --git a/platforms/chibios/drivers/ws2812_pwm.c b/platforms/chibios/drivers/ws2812_pwm.c index e6af55b6b..c17b9cd4e 100644 --- a/platforms/chibios/drivers/ws2812_pwm.c +++ b/platforms/chibios/drivers/ws2812_pwm.c | |||
| @@ -5,7 +5,9 @@ | |||
| 5 | /* Adapted from https://github.com/joewa/WS2812-LED-Driver_ChibiOS/ */ | 5 | /* Adapted from https://github.com/joewa/WS2812-LED-Driver_ChibiOS/ */ |
| 6 | 6 | ||
| 7 | #ifdef RGBW | 7 | #ifdef RGBW |
| 8 | # error "RGBW not supported" | 8 | # define WS2812_CHANNELS 4 |
| 9 | #else | ||
| 10 | # define WS2812_CHANNELS 3 | ||
| 9 | #endif | 11 | #endif |
| 10 | 12 | ||
| 11 | #ifndef WS2812_PWM_DRIVER | 13 | #ifndef WS2812_PWM_DRIVER |
| @@ -40,15 +42,15 @@ | |||
| 40 | // Default Push Pull | 42 | // Default Push Pull |
| 41 | #ifndef WS2812_EXTERNAL_PULLUP | 43 | #ifndef WS2812_EXTERNAL_PULLUP |
| 42 | # if defined(USE_GPIOV1) | 44 | # if defined(USE_GPIOV1) |
| 43 | # define WS2812_OUTPUT_MODE PAL_MODE_STM32_ALTERNATE_PUSHPULL | 45 | # define WS2812_OUTPUT_MODE PAL_MODE_ALTERNATE_PUSHPULL |
| 44 | # else | 46 | # else |
| 45 | # define WS2812_OUTPUT_MODE PAL_MODE_ALTERNATE(WS2812_PWM_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL | PAL_STM32_OSPEED_HIGHEST | PAL_STM32_PUPDR_FLOATING | 47 | # define WS2812_OUTPUT_MODE PAL_MODE_ALTERNATE(WS2812_PWM_PAL_MODE) | PAL_OUTPUT_TYPE_PUSHPULL | PAL_OUTPUT_SPEED_HIGHEST | PAL_PUPDR_FLOATING |
| 46 | # endif | 48 | # endif |
| 47 | #else | 49 | #else |
| 48 | # if defined(USE_GPIOV1) | 50 | # if defined(USE_GPIOV1) |
| 49 | # define WS2812_OUTPUT_MODE PAL_MODE_STM32_ALTERNATE_OPENDRAIN | 51 | # define WS2812_OUTPUT_MODE PAL_MODE_ALTERNATE_OPENDRAIN |
| 50 | # else | 52 | # else |
| 51 | # define WS2812_OUTPUT_MODE PAL_MODE_ALTERNATE(WS2812_PWM_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN | PAL_STM32_OSPEED_HIGHEST | PAL_STM32_PUPDR_FLOATING | 53 | # define WS2812_OUTPUT_MODE PAL_MODE_ALTERNATE(WS2812_PWM_PAL_MODE) | PAL_OUTPUT_TYPE_OPENDRAIN | PAL_OUTPUT_SPEED_HIGHEST | PAL_PUPDR_FLOATING |
| 52 | # endif | 54 | # endif |
| 53 | #endif | 55 | #endif |
| 54 | 56 | ||
| @@ -59,7 +61,7 @@ | |||
| 59 | 61 | ||
| 60 | /* --- PRIVATE CONSTANTS ---------------------------------------------------- */ | 62 | /* --- PRIVATE CONSTANTS ---------------------------------------------------- */ |
| 61 | 63 | ||
| 62 | #define WS2812_PWM_FREQUENCY (STM32_SYSCLK / 2) /**< Clock frequency of PWM, must be valid with respect to system clock! */ | 64 | #define WS2812_PWM_FREQUENCY (CPU_CLOCK / 2) /**< Clock frequency of PWM, must be valid with respect to system clock! */ |
| 63 | #define WS2812_PWM_PERIOD (WS2812_PWM_FREQUENCY / WS2812_PWM_TARGET_PERIOD) /**< Clock period in ticks. 1 / 800kHz = 1.25 uS (as per datasheet) */ | 65 | #define WS2812_PWM_PERIOD (WS2812_PWM_FREQUENCY / WS2812_PWM_TARGET_PERIOD) /**< Clock period in ticks. 1 / 800kHz = 1.25 uS (as per datasheet) */ |
| 64 | 66 | ||
| 65 | /** | 67 | /** |
| @@ -68,8 +70,9 @@ | |||
| 68 | * The reset period for each frame is defined in WS2812_TRST_US. | 70 | * The reset period for each frame is defined in WS2812_TRST_US. |
| 69 | * Calculate the number of zeroes to add at the end assuming 1.25 uS/bit: | 71 | * Calculate the number of zeroes to add at the end assuming 1.25 uS/bit: |
| 70 | */ | 72 | */ |
| 73 | #define WS2812_COLOR_BITS (WS2812_CHANNELS * 8) | ||
| 71 | #define WS2812_RESET_BIT_N (1000 * WS2812_TRST_US / 1250) | 74 | #define WS2812_RESET_BIT_N (1000 * WS2812_TRST_US / 1250) |
| 72 | #define WS2812_COLOR_BIT_N (RGBLED_NUM * 24) /**< Number of data bits */ | 75 | #define WS2812_COLOR_BIT_N (RGBLED_NUM * WS2812_COLOR_BITS) /**< Number of data bits */ |
| 73 | #define WS2812_BIT_N (WS2812_COLOR_BIT_N + WS2812_RESET_BIT_N) /**< Total number of bits in a frame */ | 76 | #define WS2812_BIT_N (WS2812_COLOR_BIT_N + WS2812_RESET_BIT_N) /**< Total number of bits in a frame */ |
| 74 | 77 | ||
| 75 | /** | 78 | /** |
| @@ -114,7 +117,7 @@ | |||
| 114 | * | 117 | * |
| 115 | * @return The bit index | 118 | * @return The bit index |
| 116 | */ | 119 | */ |
| 117 | #define WS2812_BIT(led, byte, bit) (24 * (led) + 8 * (byte) + (7 - (bit))) | 120 | #define WS2812_BIT(led, byte, bit) (WS2812_COLOR_BITS * (led) + 8 * (byte) + (7 - (bit))) |
| 118 | 121 | ||
| 119 | #if (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_GRB) | 122 | #if (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_GRB) |
| 120 | /** | 123 | /** |
| @@ -228,6 +231,20 @@ | |||
| 228 | # define WS2812_BLUE_BIT(led, bit) WS2812_BIT((led), 0, (bit)) | 231 | # define WS2812_BLUE_BIT(led, bit) WS2812_BIT((led), 0, (bit)) |
| 229 | #endif | 232 | #endif |
| 230 | 233 | ||
| 234 | #ifdef RGBW | ||
| 235 | /** | ||
| 236 | * @brief Determine the index in @ref ws2812_frame_buffer "the frame buffer" of a given white bit | ||
| 237 | * | ||
| 238 | * @note The white byte is the last byte in the color packet | ||
| 239 | * | ||
| 240 | * @param[in] led: The led index [0, @ref WS2812_LED_N) | ||
| 241 | * @param[in] bit: The bit index [0, 7] | ||
| 242 | * | ||
| 243 | * @return The bit index | ||
| 244 | */ | ||
| 245 | # define WS2812_WHITE_BIT(led, bit) WS2812_BIT((led), 3, (bit)) | ||
| 246 | #endif | ||
| 247 | |||
| 231 | /* --- PRIVATE VARIABLES ---------------------------------------------------- */ | 248 | /* --- PRIVATE VARIABLES ---------------------------------------------------- */ |
| 232 | 249 | ||
| 233 | static uint32_t ws2812_frame_buffer[WS2812_BIT_N + 1]; /**< Buffer for a frame */ | 250 | static uint32_t ws2812_frame_buffer[WS2812_BIT_N + 1]; /**< Buffer for a frame */ |
| @@ -296,6 +313,17 @@ void ws2812_write_led(uint16_t led_number, uint8_t r, uint8_t g, uint8_t b) { | |||
| 296 | ws2812_frame_buffer[WS2812_BLUE_BIT(led_number, bit)] = ((b >> bit) & 0x01) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0; | 313 | ws2812_frame_buffer[WS2812_BLUE_BIT(led_number, bit)] = ((b >> bit) & 0x01) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0; |
| 297 | } | 314 | } |
| 298 | } | 315 | } |
| 316 | void ws2812_write_led_rgbw(uint16_t led_number, uint8_t r, uint8_t g, uint8_t b, uint8_t w) { | ||
| 317 | // Write color to frame buffer | ||
| 318 | for (uint8_t bit = 0; bit < 8; bit++) { | ||
| 319 | ws2812_frame_buffer[WS2812_RED_BIT(led_number, bit)] = ((r >> bit) & 0x01) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0; | ||
| 320 | ws2812_frame_buffer[WS2812_GREEN_BIT(led_number, bit)] = ((g >> bit) & 0x01) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0; | ||
| 321 | ws2812_frame_buffer[WS2812_BLUE_BIT(led_number, bit)] = ((b >> bit) & 0x01) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0; | ||
| 322 | #ifdef RGBW | ||
| 323 | ws2812_frame_buffer[WS2812_WHITE_BIT(led_number, bit)] = ((w >> bit) & 0x01) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0; | ||
| 324 | #endif | ||
| 325 | } | ||
| 326 | } | ||
| 299 | 327 | ||
| 300 | // Setleds for standard RGB | 328 | // Setleds for standard RGB |
| 301 | void ws2812_setleds(LED_TYPE* ledarray, uint16_t leds) { | 329 | void ws2812_setleds(LED_TYPE* ledarray, uint16_t leds) { |
| @@ -306,6 +334,10 @@ void ws2812_setleds(LED_TYPE* ledarray, uint16_t leds) { | |||
| 306 | } | 334 | } |
| 307 | 335 | ||
| 308 | for (uint16_t i = 0; i < leds; i++) { | 336 | for (uint16_t i = 0; i < leds; i++) { |
| 337 | #ifdef RGBW | ||
| 338 | ws2812_write_led_rgbw(i, ledarray[i].r, ledarray[i].g, ledarray[i].b, ledarray[i].w); | ||
| 339 | #else | ||
| 309 | ws2812_write_led(i, ledarray[i].r, ledarray[i].g, ledarray[i].b); | 340 | ws2812_write_led(i, ledarray[i].r, ledarray[i].g, ledarray[i].b); |
| 341 | #endif | ||
| 310 | } | 342 | } |
| 311 | } | 343 | } |
diff --git a/platforms/chibios/drivers/ws2812_spi.c b/platforms/chibios/drivers/ws2812_spi.c index fe14b478a..62722f466 100644 --- a/platforms/chibios/drivers/ws2812_spi.c +++ b/platforms/chibios/drivers/ws2812_spi.c | |||
| @@ -3,10 +3,6 @@ | |||
| 3 | 3 | ||
| 4 | /* Adapted from https://github.com/gamazeps/ws2812b-chibios-SPIDMA/ */ | 4 | /* Adapted from https://github.com/gamazeps/ws2812b-chibios-SPIDMA/ */ |
| 5 | 5 | ||
| 6 | #ifdef RGBW | ||
| 7 | # error "RGBW not supported" | ||
| 8 | #endif | ||
| 9 | |||
| 10 | // Define the spi your LEDs are plugged to here | 6 | // Define the spi your LEDs are plugged to here |
| 11 | #ifndef WS2812_SPI | 7 | #ifndef WS2812_SPI |
| 12 | # define WS2812_SPI SPID1 | 8 | # define WS2812_SPI SPID1 |
| @@ -24,15 +20,15 @@ | |||
| 24 | // Default Push Pull | 20 | // Default Push Pull |
| 25 | #ifndef WS2812_EXTERNAL_PULLUP | 21 | #ifndef WS2812_EXTERNAL_PULLUP |
| 26 | # if defined(USE_GPIOV1) | 22 | # if defined(USE_GPIOV1) |
| 27 | # define WS2812_MOSI_OUTPUT_MODE PAL_MODE_STM32_ALTERNATE_PUSHPULL | 23 | # define WS2812_MOSI_OUTPUT_MODE PAL_MODE_ALTERNATE_PUSHPULL |
| 28 | # else | 24 | # else |
| 29 | # define WS2812_MOSI_OUTPUT_MODE PAL_MODE_ALTERNATE(WS2812_SPI_MOSI_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL | 25 | # define WS2812_MOSI_OUTPUT_MODE PAL_MODE_ALTERNATE(WS2812_SPI_MOSI_PAL_MODE) | PAL_OUTPUT_TYPE_PUSHPULL |
| 30 | # endif | 26 | # endif |
| 31 | #else | 27 | #else |
| 32 | # if defined(USE_GPIOV1) | 28 | # if defined(USE_GPIOV1) |
| 33 | # define WS2812_MOSI_OUTPUT_MODE PAL_MODE_STM32_ALTERNATE_OPENDRAIN | 29 | # define WS2812_MOSI_OUTPUT_MODE PAL_MODE_ALTERNATE_OPENDRAIN |
| 34 | # else | 30 | # else |
| 35 | # define WS2812_MOSI_OUTPUT_MODE PAL_MODE_ALTERNATE(WS2812_SPI_MOSI_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN | 31 | # define WS2812_MOSI_OUTPUT_MODE PAL_MODE_ALTERNATE(WS2812_SPI_MOSI_PAL_MODE) | PAL_OUTPUT_TYPE_OPENDRAIN |
| 36 | # endif | 32 | # endif |
| 37 | #endif | 33 | #endif |
| 38 | 34 | ||
| @@ -68,14 +64,18 @@ | |||
| 68 | #endif | 64 | #endif |
| 69 | 65 | ||
| 70 | #if defined(USE_GPIOV1) | 66 | #if defined(USE_GPIOV1) |
| 71 | # define WS2812_SCK_OUTPUT_MODE PAL_MODE_STM32_ALTERNATE_PUSHPULL | 67 | # define WS2812_SCK_OUTPUT_MODE PAL_MODE_ALTERNATE_PUSHPULL |
| 72 | #else | 68 | #else |
| 73 | # define WS2812_SCK_OUTPUT_MODE PAL_MODE_ALTERNATE(WS2812_SPI_SCK_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL | 69 | # define WS2812_SCK_OUTPUT_MODE PAL_MODE_ALTERNATE(WS2812_SPI_SCK_PAL_MODE) | PAL_OUTPUT_TYPE_PUSHPULL |
| 74 | #endif | 70 | #endif |
| 75 | 71 | ||
| 76 | #define BYTES_FOR_LED_BYTE 4 | 72 | #define BYTES_FOR_LED_BYTE 4 |
| 77 | #define NB_COLORS 3 | 73 | #ifdef RGBW |
| 78 | #define BYTES_FOR_LED (BYTES_FOR_LED_BYTE * NB_COLORS) | 74 | # define WS2812_CHANNELS 4 |
| 75 | #else | ||
| 76 | # define WS2812_CHANNELS 3 | ||
| 77 | #endif | ||
| 78 | #define BYTES_FOR_LED (BYTES_FOR_LED_BYTE * WS2812_CHANNELS) | ||
| 79 | #define DATA_SIZE (BYTES_FOR_LED * RGBLED_NUM) | 79 | #define DATA_SIZE (BYTES_FOR_LED * RGBLED_NUM) |
| 80 | #define RESET_SIZE (1000 * WS2812_TRST_US / (2 * 1250)) | 80 | #define RESET_SIZE (1000 * WS2812_TRST_US / (2 * 1250)) |
| 81 | #define PREAMBLE_SIZE 4 | 81 | #define PREAMBLE_SIZE 4 |
| @@ -116,6 +116,9 @@ static void set_led_color_rgb(LED_TYPE color, int pos) { | |||
| 116 | for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE + j] = get_protocol_eq(color.g, j); | 116 | for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE + j] = get_protocol_eq(color.g, j); |
| 117 | for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE * 2 + j] = get_protocol_eq(color.r, j); | 117 | for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE * 2 + j] = get_protocol_eq(color.r, j); |
| 118 | #endif | 118 | #endif |
| 119 | #ifdef RGBW | ||
| 120 | for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE * 4 + j] = get_protocol_eq(color.w, j); | ||
| 121 | #endif | ||
| 119 | } | 122 | } |
| 120 | 123 | ||
| 121 | void ws2812_init(void) { | 124 | void ws2812_init(void) { |
diff --git a/platforms/chibios/eeprom_stm32.c b/platforms/chibios/eeprom_stm32.c new file mode 100644 index 000000000..acc6a4851 --- /dev/null +++ b/platforms/chibios/eeprom_stm32.c | |||
| @@ -0,0 +1,687 @@ | |||
| 1 | /* | ||
| 2 | * This software is experimental and a work in progress. | ||
| 3 | * Under no circumstances should these files be used in relation to any critical system(s). | ||
| 4 | * Use of these files is at your own risk. | ||
| 5 | * | ||
| 6 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, | ||
| 7 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR | ||
| 8 | * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||
| 9 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
| 10 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
| 11 | * DEALINGS IN THE SOFTWARE. | ||
| 12 | * | ||
| 13 | * This files are free to use from http://engsta.com/stm32-flash-memory-eeprom-emulator/ by | ||
| 14 | * Artur F. | ||
| 15 | * | ||
| 16 | * Modifications for QMK and STM32F303 by Yiancar | ||
| 17 | * Modifications to add flash wear leveling by Ilya Zhuravlev | ||
| 18 | * Modifications to increase flash density by Don Kjer | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <stdio.h> | ||
| 22 | #include <stdbool.h> | ||
| 23 | #include "util.h" | ||
| 24 | #include "debug.h" | ||
| 25 | #include "eeprom_stm32.h" | ||
| 26 | #include "flash_stm32.h" | ||
| 27 | |||
| 28 | /* | ||
| 29 | * We emulate eeprom by writing a snapshot compacted view of eeprom contents, | ||
| 30 | * followed by a write log of any change since that snapshot: | ||
| 31 | * | ||
| 32 | * === SIMULATED EEPROM CONTENTS === | ||
| 33 | * | ||
| 34 | * ┌─ Compacted ┬ Write Log ─┐ | ||
| 35 | * │............│[BYTE][BYTE]│ | ||
| 36 | * │FFFF....FFFF│[WRD0][WRD1]│ | ||
| 37 | * │FFFFFFFFFFFF│[WORD][NEXT]│ | ||
| 38 | * │....FFFFFFFF│[BYTE][WRD0]│ | ||
| 39 | * ├────────────┼────────────┤ | ||
| 40 | * └──PAGE_BASE │ │ | ||
| 41 | * PAGE_LAST─┴─WRITE_BASE │ | ||
| 42 | * WRITE_LAST ┘ | ||
| 43 | * | ||
| 44 | * Compacted contents are the 1's complement of the actual EEPROM contents. | ||
| 45 | * e.g. An 'FFFF' represents a '0000' value. | ||
| 46 | * | ||
| 47 | * The size of the 'compacted' area is equal to the size of the 'emulated' eeprom. | ||
| 48 | * The size of the compacted-area and write log are configurable, and the combined | ||
| 49 | * size of Compacted + WriteLog is a multiple FEE_PAGE_SIZE, which is MCU dependent. | ||
| 50 | * Simulated Eeprom contents are located at the end of available flash space. | ||
| 51 | * | ||
| 52 | * The following configuration defines can be set: | ||
| 53 | * | ||
| 54 | * FEE_PAGE_COUNT # Total number of pages to use for eeprom simulation (Compact + Write log) | ||
| 55 | * FEE_DENSITY_BYTES # Size of simulated eeprom. (Defaults to half the space allocated by FEE_PAGE_COUNT) | ||
| 56 | * NOTE: The current implementation does not include page swapping, | ||
| 57 | * and FEE_DENSITY_BYTES will consume that amount of RAM as a cached view of actual EEPROM contents. | ||
| 58 | * | ||
| 59 | * The maximum size of FEE_DENSITY_BYTES is currently 16384. The write log size equals | ||
| 60 | * FEE_PAGE_COUNT * FEE_PAGE_SIZE - FEE_DENSITY_BYTES. | ||
| 61 | * The larger the write log, the less frequently the compacted area needs to be rewritten. | ||
| 62 | * | ||
| 63 | * | ||
| 64 | * *** General Algorithm *** | ||
| 65 | * | ||
| 66 | * During initialization: | ||
| 67 | * The contents of the Compacted-flash area are loaded and the 1's complement value | ||
| 68 | * is cached into memory (e.g. 0xFFFF in Flash represents 0x0000 in cache). | ||
| 69 | * Write log entries are processed until a 0xFFFF is reached. | ||
| 70 | * Each log entry updates a byte or word in the cache. | ||
| 71 | * | ||
| 72 | * During reads: | ||
| 73 | * EEPROM contents are given back directly from the cache in memory. | ||
| 74 | * | ||
| 75 | * During writes: | ||
| 76 | * The contents of the cache is updated first. | ||
| 77 | * If the Compacted-flash area corresponding to the write address is unprogrammed, the 1's complement of the value is written directly into Compacted-flash | ||
| 78 | * Otherwise: | ||
| 79 | * If the write log is full, erase both the Compacted-flash area and the Write log, then write cached contents to the Compacted-flash area. | ||
| 80 | * Otherwise a Write log entry is constructed and appended to the next free position in the Write log. | ||
| 81 | * | ||
| 82 | * | ||
| 83 | * *** Write Log Structure *** | ||
| 84 | * | ||
| 85 | * Write log entries allow for optimized byte writes to addresses below 128. Writing 0 or 1 words are also optimized when word-aligned. | ||
| 86 | * | ||
| 87 | * === WRITE LOG ENTRY FORMATS === | ||
| 88 | * | ||
| 89 | * ╔═══ Byte-Entry ══╗ | ||
| 90 | * ║0XXXXXXX║YYYYYYYY║ | ||
| 91 | * ║ └──┬──┘║└──┬───┘║ | ||
| 92 | * ║ Address║ Value ║ | ||
| 93 | * ╚════════╩════════╝ | ||
| 94 | * 0 <= Address < 0x80 (128) | ||
| 95 | * | ||
| 96 | * ╔ Word-Encoded 0 ╗ | ||
| 97 | * ║100XXXXXXXXXXXXX║ | ||
| 98 | * ║ │└─────┬─────┘║ | ||
| 99 | * ║ │Address >> 1 ║ | ||
| 100 | * ║ └── Value: 0 ║ | ||
| 101 | * ╚════════════════╝ | ||
| 102 | * 0 <= Address <= 0x3FFE (16382) | ||
| 103 | * | ||
| 104 | * ╔ Word-Encoded 1 ╗ | ||
| 105 | * ║101XXXXXXXXXXXXX║ | ||
| 106 | * ║ │└─────┬─────┘║ | ||
| 107 | * ║ │Address >> 1 ║ | ||
| 108 | * ║ └── Value: 1 ║ | ||
| 109 | * ╚════════════════╝ | ||
| 110 | * 0 <= Address <= 0x3FFE (16382) | ||
| 111 | * | ||
| 112 | * ╔═══ Reserved ═══╗ | ||
| 113 | * ║110XXXXXXXXXXXXX║ | ||
| 114 | * ╚════════════════╝ | ||
| 115 | * | ||
| 116 | * ╔═══════════ Word-Next ═══════════╗ | ||
| 117 | * ║111XXXXXXXXXXXXX║YYYYYYYYYYYYYYYY║ | ||
| 118 | * ║ └─────┬─────┘║└───────┬──────┘║ | ||
| 119 | * ║(Address-128)>>1║ ~Value ║ | ||
| 120 | * ╚════════════════╩════════════════╝ | ||
| 121 | * ( 0 <= Address < 0x0080 (128): Reserved) | ||
| 122 | * 0x80 <= Address <= 0x3FFE (16382) | ||
| 123 | * | ||
| 124 | * Write Log entry ranges: | ||
| 125 | * 0x0000 ... 0x7FFF - Byte-Entry; address is (Entry & 0x7F00) >> 4; value is (Entry & 0xFF) | ||
| 126 | * 0x8000 ... 0x9FFF - Word-Encoded 0; address is (Entry & 0x1FFF) << 1; value is 0 | ||
| 127 | * 0xA000 ... 0xBFFF - Word-Encoded 1; address is (Entry & 0x1FFF) << 1; value is 1 | ||
| 128 | * 0xC000 ... 0xDFFF - Reserved | ||
| 129 | * 0xE000 ... 0xFFBF - Word-Next; address is (Entry & 0x1FFF) << 1 + 0x80; value is ~(Next_Entry) | ||
| 130 | * 0xFFC0 ... 0xFFFE - Reserved | ||
| 131 | * 0xFFFF - Unprogrammed | ||
| 132 | * | ||
| 133 | */ | ||
| 134 | |||
| 135 | #include "eeprom_stm32_defs.h" | ||
| 136 | #if !defined(FEE_PAGE_SIZE) || !defined(FEE_PAGE_COUNT) || !defined(FEE_MCU_FLASH_SIZE) || !defined(FEE_PAGE_BASE_ADDRESS) | ||
| 137 | # error "not implemented." | ||
| 138 | #endif | ||
| 139 | |||
| 140 | /* These bits are used for optimizing encoding of bytes, 0 and 1 */ | ||
| 141 | #define FEE_WORD_ENCODING 0x8000 | ||
| 142 | #define FEE_VALUE_NEXT 0x6000 | ||
| 143 | #define FEE_VALUE_RESERVED 0x4000 | ||
| 144 | #define FEE_VALUE_ENCODED 0x2000 | ||
| 145 | #define FEE_BYTE_RANGE 0x80 | ||
| 146 | |||
| 147 | /* Addressable range 16KByte: 0 <-> (0x1FFF << 1) */ | ||
| 148 | #define FEE_ADDRESS_MAX_SIZE 0x4000 | ||
| 149 | |||
| 150 | /* Flash word value after erase */ | ||
| 151 | #define FEE_EMPTY_WORD ((uint16_t)0xFFFF) | ||
| 152 | |||
| 153 | /* Size of combined compacted eeprom and write log pages */ | ||
| 154 | #define FEE_DENSITY_MAX_SIZE (FEE_PAGE_COUNT * FEE_PAGE_SIZE) | ||
| 155 | |||
| 156 | #ifndef FEE_MCU_FLASH_SIZE_IGNORE_CHECK /* *TODO: Get rid of this check */ | ||
| 157 | # if FEE_DENSITY_MAX_SIZE > (FEE_MCU_FLASH_SIZE * 1024) | ||
| 158 | # pragma message STR(FEE_DENSITY_MAX_SIZE) " > " STR(FEE_MCU_FLASH_SIZE * 1024) | ||
| 159 | # error emulated eeprom: FEE_DENSITY_MAX_SIZE is greater than available flash size | ||
| 160 | # endif | ||
| 161 | #endif | ||
| 162 | |||
| 163 | /* Size of emulated eeprom */ | ||
| 164 | #ifdef FEE_DENSITY_BYTES | ||
| 165 | # if (FEE_DENSITY_BYTES > FEE_DENSITY_MAX_SIZE) | ||
| 166 | # pragma message STR(FEE_DENSITY_BYTES) " > " STR(FEE_DENSITY_MAX_SIZE) | ||
| 167 | # error emulated eeprom: FEE_DENSITY_BYTES exceeds FEE_DENSITY_MAX_SIZE | ||
| 168 | # endif | ||
| 169 | # if (FEE_DENSITY_BYTES == FEE_DENSITY_MAX_SIZE) | ||
| 170 | # pragma message STR(FEE_DENSITY_BYTES) " == " STR(FEE_DENSITY_MAX_SIZE) | ||
| 171 | # warning emulated eeprom: FEE_DENSITY_BYTES leaves no room for a write log. This will greatly increase the flash wear rate! | ||
| 172 | # endif | ||
| 173 | # if FEE_DENSITY_BYTES > FEE_ADDRESS_MAX_SIZE | ||
| 174 | # pragma message STR(FEE_DENSITY_BYTES) " > " STR(FEE_ADDRESS_MAX_SIZE) | ||
| 175 | # error emulated eeprom: FEE_DENSITY_BYTES is greater than FEE_ADDRESS_MAX_SIZE allows | ||
| 176 | # endif | ||
| 177 | # if ((FEE_DENSITY_BYTES) % 2) == 1 | ||
| 178 | # error emulated eeprom: FEE_DENSITY_BYTES must be even | ||
| 179 | # endif | ||
| 180 | #else | ||
| 181 | /* Default to half of allocated space used for emulated eeprom, half for write log */ | ||
| 182 | # define FEE_DENSITY_BYTES (FEE_PAGE_COUNT * FEE_PAGE_SIZE / 2) | ||
| 183 | #endif | ||
| 184 | |||
| 185 | /* Size of write log */ | ||
| 186 | #ifdef FEE_WRITE_LOG_BYTES | ||
| 187 | # if ((FEE_DENSITY_BYTES + FEE_WRITE_LOG_BYTES) > FEE_DENSITY_MAX_SIZE) | ||
| 188 | # pragma message STR(FEE_DENSITY_BYTES) " + " STR(FEE_WRITE_LOG_BYTES) " > " STR(FEE_DENSITY_MAX_SIZE) | ||
| 189 | # error emulated eeprom: FEE_WRITE_LOG_BYTES exceeds remaining FEE_DENSITY_MAX_SIZE | ||
| 190 | # endif | ||
| 191 | # if ((FEE_WRITE_LOG_BYTES) % 2) == 1 | ||
| 192 | # error emulated eeprom: FEE_WRITE_LOG_BYTES must be even | ||
| 193 | # endif | ||
| 194 | #else | ||
| 195 | /* Default to use all remaining space */ | ||
| 196 | # define FEE_WRITE_LOG_BYTES (FEE_PAGE_COUNT * FEE_PAGE_SIZE - FEE_DENSITY_BYTES) | ||
| 197 | #endif | ||
| 198 | |||
| 199 | /* Start of the emulated eeprom compacted flash area */ | ||
| 200 | #define FEE_COMPACTED_BASE_ADDRESS FEE_PAGE_BASE_ADDRESS | ||
| 201 | /* End of the emulated eeprom compacted flash area */ | ||
| 202 | #define FEE_COMPACTED_LAST_ADDRESS (FEE_COMPACTED_BASE_ADDRESS + FEE_DENSITY_BYTES) | ||
| 203 | /* Start of the emulated eeprom write log */ | ||
| 204 | #define FEE_WRITE_LOG_BASE_ADDRESS FEE_COMPACTED_LAST_ADDRESS | ||
| 205 | /* End of the emulated eeprom write log */ | ||
| 206 | #define FEE_WRITE_LOG_LAST_ADDRESS (FEE_WRITE_LOG_BASE_ADDRESS + FEE_WRITE_LOG_BYTES) | ||
| 207 | |||
| 208 | #if defined(DYNAMIC_KEYMAP_EEPROM_MAX_ADDR) && (DYNAMIC_KEYMAP_EEPROM_MAX_ADDR >= FEE_DENSITY_BYTES) | ||
| 209 | # error emulated eeprom: DYNAMIC_KEYMAP_EEPROM_MAX_ADDR is greater than the FEE_DENSITY_BYTES available | ||
| 210 | #endif | ||
| 211 | |||
| 212 | /* In-memory contents of emulated eeprom for faster access */ | ||
| 213 | /* *TODO: Implement page swapping */ | ||
| 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.mk b/platforms/chibios/flash.mk index c0b32c2f2..31f69595d 100644 --- a/platforms/chibios/flash.mk +++ b/platforms/chibios/flash.mk | |||
| @@ -82,6 +82,8 @@ else ifeq ($(strip $(MCU_FAMILY)),MIMXRT1062) | |||
| 82 | $(UNSYNC_OUTPUT_CMD) && $(call EXEC_TEENSY) | 82 | $(UNSYNC_OUTPUT_CMD) && $(call EXEC_TEENSY) |
| 83 | else ifeq ($(strip $(MCU_FAMILY)),STM32) | 83 | else ifeq ($(strip $(MCU_FAMILY)),STM32) |
| 84 | $(UNSYNC_OUTPUT_CMD) && $(call EXEC_DFU_UTIL) | 84 | $(UNSYNC_OUTPUT_CMD) && $(call EXEC_DFU_UTIL) |
| 85 | else ifeq ($(strip $(MCU_FAMILY)),GD32V) | ||
| 86 | $(UNSYNC_OUTPUT_CMD) && $(call EXEC_DFU_UTIL) | ||
| 85 | else | 87 | else |
| 86 | $(PRINT_OK); $(SILENT) || printf "$(MSG_FLASH_BOOTLOADER)" | 88 | $(PRINT_OK); $(SILENT) || printf "$(MSG_FLASH_BOOTLOADER)" |
| 87 | endif | 89 | endif |
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..1c8d43007 --- /dev/null +++ b/platforms/chibios/platform.mk | |||
| @@ -0,0 +1,439 @@ | |||
| 1 | # Hey Emacs, this is a -*- makefile -*- | ||
| 2 | ############################################################################## | ||
| 3 | # Architecture or project specific options | ||
| 4 | # | ||
| 5 | |||
| 6 | # Stack size to be allocated to the Cortex-M process stack. This stack is | ||
| 7 | # the stack used by the main() thread. | ||
| 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 | SHARED_LDSYMBOLS = -Wl,--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,--gc-sections \ | ||
| 331 | -nostartfiles | ||
| 332 | |||
| 333 | ifeq ($(strip $(MCU)), risc-v) | ||
| 334 | # RISC-V toolchain specific configuration | ||
| 335 | # Find suitable GCC compiler | ||
| 336 | ifeq ($(strip $(TOOLCHAIN)),) | ||
| 337 | ifneq ($(shell which riscv32-unknown-elf-gcc 2>/dev/null),) | ||
| 338 | TOOLCHAIN = riscv32-unknown-elf- | ||
| 339 | else | ||
| 340 | ifneq ($(shell which riscv64-unknown-elf-gcc 2>/dev/null),) | ||
| 341 | TOOLCHAIN = riscv64-unknown-elf- | ||
| 342 | else | ||
| 343 | $(error "No RISC-V toolchain found. Can't find riscv32-unknown-elf-gcc or riscv64-unknown-elf-gcc found in your systems PATH variable. Please install a valid toolchain and make it accessible!") | ||
| 344 | endif | ||
| 345 | endif | ||
| 346 | endif | ||
| 347 | |||
| 348 | # Default to compiling with picolibc for RISC-V targets if available, which | ||
| 349 | # is available by default on distributions based on Debian 11+. | ||
| 350 | ifeq ($(shell $(TOOLCHAIN)gcc --specs=picolibc.specs -E - 2>/dev/null >/dev/null </dev/null ; echo $$?),0) | ||
| 351 | # Toolchain specific Compiler flags Note that we still link with our own | ||
| 352 | # linker script by providing it via the -T flag in SHARED_LDFLAGS. | ||
| 353 | TOOLCHAIN_CFLAGS = --specs=picolibc.specs | ||
| 354 | |||
| 355 | # picolibc internally uses __heap_start and __heap_end instead of the | ||
| 356 | # defacto chibios linker script standard __heap_base__ and __heap_end__ | ||
| 357 | # therefore we introduce these symbols as an alias. | ||
| 358 | TOOLCHAIN_LDSYMBOLS = -Wl,--defsym=__heap_start=__heap_base__,--defsym=__heap_end=__heap_end__ | ||
| 359 | |||
| 360 | # Tell QMK that we are compiling with picolibc. | ||
| 361 | OPT_DEFS += -DUSE_PICOLIBC | ||
| 362 | endif | ||
| 363 | |||
| 364 | # MCU architecture flags | ||
| 365 | MCUFLAGS = -march=$(MCU_ARCH) \ | ||
| 366 | -mabi=$(MCU_ABI) \ | ||
| 367 | -mcmodel=$(MCU_CMODEL) \ | ||
| 368 | -mstrict-align | ||
| 369 | else | ||
| 370 | # ARM toolchain specific configuration | ||
| 371 | TOOLCHAIN ?= arm-none-eabi- | ||
| 372 | |||
| 373 | # Toolchain specific Linker flags | ||
| 374 | TOOLCHAIN_LDFLAGS = -Wl,--no-wchar-size-warning \ | ||
| 375 | --specs=nano.specs | ||
| 376 | |||
| 377 | # MCU architecture flags | ||
| 378 | MCUFLAGS = -mcpu=$(MCU) \ | ||
| 379 | -mthumb -DTHUMB_PRESENT \ | ||
| 380 | -mno-thumb-interwork -DTHUMB_NO_INTERWORKING \ | ||
| 381 | -mno-unaligned-access | ||
| 382 | |||
| 383 | # Some ARM cores like the M4 and M7 have floating point units which can be enabled | ||
| 384 | USE_FPU ?= no | ||
| 385 | |||
| 386 | ifneq ($(USE_FPU),no) | ||
| 387 | OPT_DEFS += -DCORTEX_USE_FPU=TRUE | ||
| 388 | |||
| 389 | # Default is single precision floats | ||
| 390 | USE_FPU_OPT ?= -mfloat-abi=hard \ | ||
| 391 | -mfpu=fpv4-sp-d16 \ | ||
| 392 | -fsingle-precision-constant | ||
| 393 | |||
| 394 | MCUFLAGS += $(USE_FPU_OPT) | ||
| 395 | else | ||
| 396 | OPT_DEFS += -DCORTEX_USE_FPU=FALSE | ||
| 397 | endif | ||
| 398 | endif | ||
| 399 | |||
| 400 | # Assembler flags | ||
| 401 | ASFLAGS += $(SHARED_ASFLAGS) $(TOOLCHAIN_ASFLAGS) | ||
| 402 | |||
| 403 | # C Compiler flags | ||
| 404 | CFLAGS += $(SHARED_CFLAGS) $(TOOLCHAIN_CFLAGS) | ||
| 405 | |||
| 406 | # C++ Compiler flags | ||
| 407 | CXXFLAGS += $(CFLAGS) $(SHARED_CXXFLAGS) $(TOOLCHAIN_CXXFLAGS) -fno-rtti | ||
| 408 | |||
| 409 | # Linker flags | ||
| 410 | LDFLAGS += $(SHARED_LDFLAGS) $(SHARED_LDSYMBOLS) $(TOOLCHAIN_LDFLAGS) $(TOOLCHAIN_LDSYMBOLS) $(MCUFLAGS) | ||
| 411 | |||
| 412 | # Tell QMK that we are hosting it on ChibiOS. | ||
| 413 | OPT_DEFS += -DPROTOCOL_CHIBIOS | ||
| 414 | |||
| 415 | # Workaround to stop ChibiOS from complaining about new GCC -- it's been fixed for 7/8/9 already | ||
| 416 | OPT_DEFS += -DPORT_IGNORE_GCC_VERSION_CHECK=1 | ||
| 417 | |||
| 418 | # Construct GCC toolchain | ||
| 419 | CC = $(CC_PREFIX) $(TOOLCHAIN)gcc | ||
| 420 | OBJCOPY = $(TOOLCHAIN)objcopy | ||
| 421 | OBJDUMP = $(TOOLCHAIN)objdump | ||
| 422 | SIZE = $(TOOLCHAIN)size | ||
| 423 | AR = $(TOOLCHAIN)ar | ||
| 424 | NM = $(TOOLCHAIN)nm | ||
| 425 | HEX = $(OBJCOPY) -O $(FORMAT) | ||
| 426 | EEP = | ||
| 427 | BIN = $(OBJCOPY) -O binary | ||
| 428 | |||
| 429 | ############################################################################## | ||
| 430 | # Make targets | ||
| 431 | # | ||
| 432 | |||
| 433 | DEBUG = gdb | ||
| 434 | |||
| 435 | # List any extra directories to look for libraries here. | ||
| 436 | EXTRALIBDIRS = $(RULESPATH)/ld | ||
| 437 | |||
| 438 | bin: $(BUILD_DIR)/$(TARGET).bin sizeafter | ||
| 439 | $(COPY) $(BUILD_DIR)/$(TARGET).bin $(TARGET).bin; | ||
diff --git a/platforms/chibios/platform_deps.h b/platforms/chibios/platform_deps.h new file mode 100644 index 000000000..8243dcec5 --- /dev/null +++ b/platforms/chibios/platform_deps.h | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | /* Copyright 2021 QMK | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 3 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #pragma once | ||
| 17 | |||
| 18 | #include <hal.h> | ||
| 19 | #include "chibios_config.h" | ||
diff --git a/platforms/chibios/sleep_led.c b/platforms/chibios/sleep_led.c new file mode 100644 index 000000000..477056a45 --- /dev/null +++ b/platforms/chibios/sleep_led.c | |||
| @@ -0,0 +1,192 @@ | |||
| 1 | #include <ch.h> | ||
| 2 | #include <hal.h> | ||
| 3 | |||
| 4 | #include "led.h" | ||
| 5 | #include "sleep_led.h" | ||
| 6 | |||
| 7 | /* All right, we go the "software" way: timer, toggle LED in interrupt. | ||
| 8 | * Based on hasu's code for AVRs. | ||
| 9 | * Use LP timer on Kinetises, TIM14 on STM32F0. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #ifndef SLEEP_LED_GPT_DRIVER | ||
| 13 | # if defined(STM32F0XX) | ||
| 14 | # define SLEEP_LED_GPT_DRIVER GPTD14 | ||
| 15 | # endif | ||
| 16 | #endif | ||
| 17 | |||
| 18 | #if defined(KL2x) || defined(K20x) || defined(SLEEP_LED_GPT_DRIVER) /* common parts for timers/interrupts */ | ||
| 19 | |||
| 20 | /* Breathing Sleep LED brighness(PWM On period) table | ||
| 21 | * (64[steps] * 4[duration]) / 64[PWM periods/s] = 4 second breath cycle | ||
| 22 | * | ||
| 23 | * http://www.wolframalpha.com/input/?i=%28sin%28+x%2F64*pi%29**8+*+255%2C+x%3D0+to+63 | ||
| 24 | * (0..63).each {|x| p ((sin(x/64.0*PI)**8)*255).to_i } | ||
| 25 | */ | ||
| 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..7150a4632 --- /dev/null +++ b/platforms/chibios/syscall-fallbacks.c | |||
| @@ -0,0 +1,111 @@ | |||
| 1 | /* Copyright 2021 Nick Brassel, QMK | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 2 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <errno.h> | ||
| 18 | #include <sys/stat.h> | ||
| 19 | #include <sys/types.h> | ||
| 20 | |||
| 21 | /* To compile the ChibiOS syscall stubs with picolibc | ||
| 22 | * the _reent struct has to be defined. */ | ||
| 23 | #if defined(USE_PICOLIBC) | ||
| 24 | struct _reent; | ||
| 25 | struct timeval; | ||
| 26 | #endif | ||
| 27 | |||
| 28 | #pragma GCC diagnostic ignored "-Wmissing-prototypes" | ||
| 29 | |||
| 30 | __attribute__((weak, used)) int _open_r(struct _reent *r, const char *path, int flag, int m) { | ||
| 31 | __errno_r(r) = ENOENT; | ||
| 32 | return -1; | ||
| 33 | } | ||
| 34 | |||
| 35 | __attribute__((weak, used)) int _lseek_r(struct _reent *r, int file, int ptr, int dir) { | ||
| 36 | __errno_r(r) = EBADF; | ||
| 37 | return -1; | ||
| 38 | } | ||
| 39 | |||
| 40 | __attribute__((weak, used)) int _read_r(struct _reent *r, int file, char *ptr, int len) { | ||
| 41 | __errno_r(r) = EBADF; | ||
| 42 | return -1; | ||
| 43 | } | ||
| 44 | |||
| 45 | __attribute__((weak, used)) int _write_r(struct _reent *r, int file, char *ptr, int len) { | ||
| 46 | __errno_r(r) = EBADF; | ||
| 47 | return -1; | ||
| 48 | } | ||
| 49 | |||
| 50 | __attribute__((weak, used)) int _close_r(struct _reent *r, int file) { | ||
| 51 | __errno_r(r) = EBADF; | ||
| 52 | return -1; | ||
| 53 | } | ||
| 54 | |||
| 55 | __attribute__((weak, used)) int _link_r(struct _reent *r, const char *oldpath, const char *newpath) { | ||
| 56 | __errno_r(r) = EPERM; | ||
| 57 | return -1; | ||
| 58 | } | ||
| 59 | |||
| 60 | __attribute__((weak, used)) int _unlink_r(struct _reent *r, const char *path) { | ||
| 61 | __errno_r(r) = EPERM; | ||
| 62 | return -1; | ||
| 63 | } | ||
| 64 | |||
| 65 | __attribute__((weak, used)) clock_t _times_r(struct _reent *r, void *t) { | ||
| 66 | __errno_r(r) = EFAULT; | ||
| 67 | return -1; | ||
| 68 | } | ||
| 69 | |||
| 70 | __attribute__((weak, used)) int _fstat_r(struct _reent *r, int file, struct stat *st) { | ||
| 71 | __errno_r(r) = EBADF; | ||
| 72 | return -1; | ||
| 73 | } | ||
| 74 | |||
| 75 | __attribute__((weak, used)) int _isatty_r(struct _reent *r, int fd) { | ||
| 76 | __errno_r(r) = EBADF; | ||
| 77 | return 0; | ||
| 78 | } | ||
| 79 | |||
| 80 | __attribute__((weak, used)) caddr_t _sbrk_r(struct _reent *r, int incr) { | ||
| 81 | __errno_r(r) = ENOMEM; | ||
| 82 | return (caddr_t)-1; | ||
| 83 | } | ||
| 84 | |||
| 85 | __attribute__((weak, used)) int _kill(int pid, int sig) { | ||
| 86 | errno = EPERM; | ||
| 87 | return -1; | ||
| 88 | } | ||
| 89 | |||
| 90 | __attribute__((weak, used)) pid_t _getpid(void) { return 1; } | ||
| 91 | |||
| 92 | __attribute__((weak, used)) void _fini(void) { return; } | ||
| 93 | |||
| 94 | __attribute__((weak, used, noreturn)) void _exit(int i) { | ||
| 95 | while (1) | ||
| 96 | ; | ||
| 97 | } | ||
| 98 | |||
| 99 | __attribute__((weak, used)) int _gettimeofday_r(struct _reent *r, struct timeval *t, void *tzp) { | ||
| 100 | __errno_r(r) = EPERM; | ||
| 101 | return -1; | ||
| 102 | } | ||
| 103 | |||
| 104 | __attribute__((weak, used)) void *__dso_handle; | ||
| 105 | |||
| 106 | __attribute__((weak, used)) void __cxa_pure_virtual(void) { | ||
| 107 | while (1) | ||
| 108 | ; | ||
| 109 | } | ||
| 110 | |||
| 111 | #pragma GCC diagnostic pop | ||
diff --git a/platforms/chibios/timer.c b/platforms/chibios/timer.c new file mode 100644 index 000000000..9f664e1f7 --- /dev/null +++ b/platforms/chibios/timer.c | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | #include <ch.h> | ||
| 2 | |||
| 3 | #include "timer.h" | ||
| 4 | |||
| 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 | ||
diff --git a/platforms/common.mk b/platforms/common.mk new file mode 100644 index 000000000..f7a0fc702 --- /dev/null +++ b/platforms/common.mk | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | PLATFORM_COMMON_DIR = $(PLATFORM_PATH)/$(PLATFORM_KEY) | ||
| 2 | |||
| 3 | TMK_COMMON_SRC += \ | ||
| 4 | $(PLATFORM_COMMON_DIR)/platform.c \ | ||
| 5 | $(PLATFORM_COMMON_DIR)/suspend.c \ | ||
| 6 | $(PLATFORM_COMMON_DIR)/timer.c \ | ||
| 7 | $(PLATFORM_COMMON_DIR)/bootloader.c \ | ||
| 8 | |||
| 9 | # Search Path | ||
| 10 | VPATH += $(PLATFORM_PATH) | ||
| 11 | VPATH += $(PLATFORM_PATH)/$(PLATFORM_KEY) | ||
| 12 | VPATH += $(PLATFORM_PATH)/$(PLATFORM_KEY)/$(DRIVER_DIR) | ||
diff --git a/platforms/eeprom.h b/platforms/eeprom.h new file mode 100644 index 000000000..f5b3f0ad5 --- /dev/null +++ b/platforms/eeprom.h | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | #pragma once | ||
| 2 | |||
| 3 | #if defined(__AVR__) && !defined(EEPROM_DRIVER) | ||
| 4 | # include <avr/eeprom.h> | ||
| 5 | #else | ||
| 6 | # include <stdint.h> | ||
| 7 | # include <stdlib.h> | ||
| 8 | |||
| 9 | uint8_t eeprom_read_byte(const uint8_t *__p); | ||
| 10 | uint16_t eeprom_read_word(const uint16_t *__p); | ||
| 11 | uint32_t eeprom_read_dword(const uint32_t *__p); | ||
| 12 | void eeprom_read_block(void *__dst, const void *__src, size_t __n); | ||
| 13 | void eeprom_write_byte(uint8_t *__p, uint8_t __value); | ||
| 14 | void eeprom_write_word(uint16_t *__p, uint16_t __value); | ||
| 15 | void eeprom_write_dword(uint32_t *__p, uint32_t __value); | ||
| 16 | void eeprom_write_block(const void *__src, void *__dst, size_t __n); | ||
| 17 | void eeprom_update_byte(uint8_t *__p, uint8_t __value); | ||
| 18 | void eeprom_update_word(uint16_t *__p, uint16_t __value); | ||
| 19 | void eeprom_update_dword(uint32_t *__p, uint32_t __value); | ||
| 20 | void eeprom_update_block(const void *__src, void *__dst, size_t __n); | ||
| 21 | #endif | ||
diff --git a/platforms/gpio.h b/platforms/gpio.h new file mode 100644 index 000000000..b47f6f8e4 --- /dev/null +++ b/platforms/gpio.h | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | /* Copyright 2021 QMK | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 3 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #pragma once | ||
| 17 | |||
| 18 | #include "pin_defs.h" | ||
| 19 | |||
| 20 | #if __has_include_next("gpio.h") | ||
| 21 | # include_next "gpio.h" /* Include the platforms gpio.h */ | ||
| 22 | #endif \ No newline at end of file | ||
diff --git a/platforms/pin_defs.h b/platforms/pin_defs.h new file mode 100644 index 000000000..ea730138f --- /dev/null +++ b/platforms/pin_defs.h | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | /* Copyright 2021 QMK | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 3 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #pragma once | ||
| 17 | |||
| 18 | // useful for direct pin mapping | ||
| 19 | #define NO_PIN (pin_t)(~0) | ||
| 20 | |||
| 21 | #if __has_include_next("pin_defs.h") | ||
| 22 | # include_next "pin_defs.h" /* Include the platforms pin_defs.h */ | ||
| 23 | #endif | ||
diff --git a/platforms/progmem.h b/platforms/progmem.h new file mode 100644 index 000000000..a70d8e299 --- /dev/null +++ b/platforms/progmem.h | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | #pragma once | ||
| 2 | |||
| 3 | #if defined(__AVR__) | ||
| 4 | # include <avr/pgmspace.h> | ||
| 5 | #else | ||
| 6 | # include <string.h> | ||
| 7 | # define PROGMEM | ||
| 8 | # define __flash | ||
| 9 | # define PSTR(x) x | ||
| 10 | # define PGM_P const char* | ||
| 11 | # define memcpy_P(dest, src, n) memcpy(dest, src, n) | ||
| 12 | # define pgm_read_byte(address_short) *((uint8_t*)(address_short)) | ||
| 13 | # define pgm_read_word(address_short) *((uint16_t*)(address_short)) | ||
| 14 | # define pgm_read_dword(address_short) *((uint32_t*)(address_short)) | ||
| 15 | # define pgm_read_ptr(address_short) *((void**)(address_short)) | ||
| 16 | # define strcmp_P(s1, s2) strcmp(s1, s2) | ||
| 17 | # define strcpy_P(dest, src) strcpy(dest, src) | ||
| 18 | # define strlen_P(src) strlen(src) | ||
| 19 | #endif | ||
diff --git a/platforms/sleep_led.h b/platforms/sleep_led.h new file mode 100644 index 000000000..38f80a660 --- /dev/null +++ b/platforms/sleep_led.h | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | #pragma once | ||
| 2 | |||
| 3 | #ifdef SLEEP_LED_ENABLE | ||
| 4 | |||
| 5 | void sleep_led_init(void); | ||
| 6 | void sleep_led_enable(void); | ||
| 7 | void sleep_led_disable(void); | ||
| 8 | void sleep_led_toggle(void); | ||
| 9 | |||
| 10 | #else | ||
| 11 | |||
| 12 | # define sleep_led_init() | ||
| 13 | # define sleep_led_enable() | ||
| 14 | # define sleep_led_disable() | ||
| 15 | # define sleep_led_toggle() | ||
| 16 | |||
| 17 | #endif | ||
diff --git a/platforms/suspend.h b/platforms/suspend.h new file mode 100644 index 000000000..081735f90 --- /dev/null +++ b/platforms/suspend.h | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include <stdint.h> | ||
| 4 | #include <stdbool.h> | ||
| 5 | |||
| 6 | void suspend_idle(uint8_t timeout); | ||
| 7 | void suspend_power_down(void); | ||
| 8 | bool suspend_wakeup_condition(void); | ||
| 9 | void suspend_wakeup_init(void); | ||
| 10 | |||
| 11 | void suspend_wakeup_init_user(void); | ||
| 12 | void suspend_wakeup_init_kb(void); | ||
| 13 | void suspend_wakeup_init_quantum(void); | ||
| 14 | void suspend_power_down_user(void); | ||
| 15 | void suspend_power_down_kb(void); | ||
| 16 | void suspend_power_down_quantum(void); | ||
| 17 | |||
| 18 | #ifndef USB_SUSPEND_WAKEUP_DELAY | ||
| 19 | # define USB_SUSPEND_WAKEUP_DELAY 0 | ||
| 20 | #endif | ||
diff --git a/platforms/test/_wait.h b/platforms/test/_wait.h new file mode 100644 index 000000000..4e22f593b --- /dev/null +++ b/platforms/test/_wait.h | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | /* Copyright 2021 QMK | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 3 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #pragma once | ||
| 17 | |||
| 18 | #include <inttypes.h> | ||
| 19 | |||
| 20 | void wait_ms(uint32_t ms); | ||
| 21 | #define wait_us(us) wait_ms(us / 1000) | ||
| 22 | #define waitInputPinDelay() | ||
diff --git a/platforms/test/bootloader.c b/platforms/test/bootloader.c new file mode 100644 index 000000000..5155d9ff0 --- /dev/null +++ b/platforms/test/bootloader.c | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | /* Copyright 2017 Fred Sundvik | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 2 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include "bootloader.h" | ||
| 18 | |||
| 19 | void bootloader_jump(void) {} | ||
diff --git a/platforms/test/eeprom.c b/platforms/test/eeprom.c new file mode 100644 index 000000000..5c8e69dae --- /dev/null +++ b/platforms/test/eeprom.c | |||
| @@ -0,0 +1,95 @@ | |||
| 1 | /* Copyright 2017 Fred Sundvik | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 2 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include "eeprom.h" | ||
| 18 | |||
| 19 | #define EEPROM_SIZE 32 | ||
| 20 | |||
| 21 | static uint8_t buffer[EEPROM_SIZE]; | ||
| 22 | |||
| 23 | uint8_t eeprom_read_byte(const uint8_t *addr) { | ||
| 24 | uintptr_t offset = (uintptr_t)addr; | ||
| 25 | return buffer[offset]; | ||
| 26 | } | ||
| 27 | |||
| 28 | void eeprom_write_byte(uint8_t *addr, uint8_t value) { | ||
| 29 | uintptr_t offset = (uintptr_t)addr; | ||
| 30 | buffer[offset] = value; | ||
| 31 | } | ||
| 32 | |||
| 33 | uint16_t eeprom_read_word(const uint16_t *addr) { | ||
| 34 | const uint8_t *p = (const uint8_t *)addr; | ||
| 35 | return eeprom_read_byte(p) | (eeprom_read_byte(p + 1) << 8); | ||
| 36 | } | ||
| 37 | |||
| 38 | uint32_t eeprom_read_dword(const uint32_t *addr) { | ||
| 39 | const uint8_t *p = (const uint8_t *)addr; | ||
| 40 | return eeprom_read_byte(p) | (eeprom_read_byte(p + 1) << 8) | (eeprom_read_byte(p + 2) << 16) | (eeprom_read_byte(p + 3) << 24); | ||
| 41 | } | ||
| 42 | |||
| 43 | void eeprom_read_block(void *buf, const void *addr, size_t len) { | ||
| 44 | const uint8_t *p = (const uint8_t *)addr; | ||
| 45 | uint8_t * dest = (uint8_t *)buf; | ||
| 46 | while (len--) { | ||
| 47 | *dest++ = eeprom_read_byte(p++); | ||
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 51 | void eeprom_write_word(uint16_t *addr, uint16_t value) { | ||
| 52 | uint8_t *p = (uint8_t *)addr; | ||
| 53 | eeprom_write_byte(p++, value); | ||
| 54 | eeprom_write_byte(p, value >> 8); | ||
| 55 | } | ||
| 56 | |||
| 57 | void eeprom_write_dword(uint32_t *addr, uint32_t value) { | ||
| 58 | uint8_t *p = (uint8_t *)addr; | ||
| 59 | eeprom_write_byte(p++, value); | ||
| 60 | eeprom_write_byte(p++, value >> 8); | ||
| 61 | eeprom_write_byte(p++, value >> 16); | ||
| 62 | eeprom_write_byte(p, value >> 24); | ||
| 63 | } | ||
| 64 | |||
| 65 | void eeprom_write_block(const void *buf, void *addr, size_t len) { | ||
| 66 | uint8_t * p = (uint8_t *)addr; | ||
| 67 | const uint8_t *src = (const uint8_t *)buf; | ||
| 68 | while (len--) { | ||
| 69 | eeprom_write_byte(p++, *src++); | ||
| 70 | } | ||
| 71 | } | ||
| 72 | |||
| 73 | void eeprom_update_byte(uint8_t *addr, uint8_t value) { eeprom_write_byte(addr, value); } | ||
| 74 | |||
| 75 | void eeprom_update_word(uint16_t *addr, uint16_t value) { | ||
| 76 | uint8_t *p = (uint8_t *)addr; | ||
| 77 | eeprom_write_byte(p++, value); | ||
| 78 | eeprom_write_byte(p, value >> 8); | ||
| 79 | } | ||
| 80 | |||
| 81 | void eeprom_update_dword(uint32_t *addr, uint32_t value) { | ||
| 82 | uint8_t *p = (uint8_t *)addr; | ||
| 83 | eeprom_write_byte(p++, value); | ||
| 84 | eeprom_write_byte(p++, value >> 8); | ||
| 85 | eeprom_write_byte(p++, value >> 16); | ||
| 86 | eeprom_write_byte(p, value >> 24); | ||
| 87 | } | ||
| 88 | |||
| 89 | void eeprom_update_block(const void *buf, void *addr, size_t len) { | ||
| 90 | uint8_t * p = (uint8_t *)addr; | ||
| 91 | const uint8_t *src = (const uint8_t *)buf; | ||
| 92 | while (len--) { | ||
| 93 | eeprom_write_byte(p++, *src++); | ||
| 94 | } | ||
| 95 | } | ||
diff --git a/platforms/test/eeprom_stm32_tests.cpp b/platforms/test/eeprom_stm32_tests.cpp new file mode 100644 index 000000000..5bc8d8790 --- /dev/null +++ b/platforms/test/eeprom_stm32_tests.cpp | |||
| @@ -0,0 +1,438 @@ | |||
| 1 | /* Copyright 2021 by Don Kjer | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 2 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include "gtest/gtest.h" | ||
| 18 | |||
| 19 | extern "C" { | ||
| 20 | #include "flash_stm32.h" | ||
| 21 | #include "eeprom_stm32.h" | ||
| 22 | #include "eeprom.h" | ||
| 23 | } | ||
| 24 | |||
| 25 | /* Mock Flash Parameters: | ||
| 26 | * | ||
| 27 | * === Large Layout === | ||
| 28 | * flash size: 65536 | ||
| 29 | * page size: 2048 | ||
| 30 | * density pages: 16 | ||
| 31 | * Simulated EEPROM size: 16384 | ||
| 32 | * | ||
| 33 | * FlashBuf Layout: | ||
| 34 | * [Unused | Compact | Write Log ] | ||
| 35 | * [0......|32768......|49152......65535] | ||
| 36 | * | ||
| 37 | * === Tiny Layout === | ||
| 38 | * flash size: 1024 | ||
| 39 | * page size: 512 | ||
| 40 | * density pages: 1 | ||
| 41 | * Simulated EEPROM size: 256 | ||
| 42 | * | ||
| 43 | * FlashBuf Layout: | ||
| 44 | * [Unused | Compact | Write Log ] | ||
| 45 | * [0......|512......|768......1023] | ||
| 46 | * | ||
| 47 | */ | ||
| 48 | |||
| 49 | #define EEPROM_SIZE (FEE_PAGE_SIZE * FEE_PAGE_COUNT / 2) | ||
| 50 | #define LOG_SIZE EEPROM_SIZE | ||
| 51 | #define LOG_BASE (MOCK_FLASH_SIZE - LOG_SIZE) | ||
| 52 | #define EEPROM_BASE (LOG_BASE - EEPROM_SIZE) | ||
| 53 | |||
| 54 | /* Log encoding helpers */ | ||
| 55 | #define BYTE_VALUE(addr, value) (((addr) << 8) | (value)) | ||
| 56 | #define WORD_ZERO(addr) (0x8000 | ((addr) >> 1)) | ||
| 57 | #define WORD_ONE(addr) (0xA000 | ((addr) >> 1)) | ||
| 58 | #define WORD_NEXT(addr) (0xE000 | (((addr)-0x80) >> 1)) | ||
| 59 | |||
| 60 | class EepromStm32Test : public testing::Test { | ||
| 61 | public: | ||
| 62 | EepromStm32Test() {} | ||
| 63 | ~EepromStm32Test() {} | ||
| 64 | |||
| 65 | protected: | ||
| 66 | void SetUp() override { EEPROM_Erase(); } | ||
| 67 | |||
| 68 | void TearDown() override { | ||
| 69 | #ifdef EEPROM_DEBUG | ||
| 70 | dumpEepromDataBuf(); | ||
| 71 | #endif | ||
| 72 | } | ||
| 73 | }; | ||
| 74 | |||
| 75 | TEST_F(EepromStm32Test, TestErase) { | ||
| 76 | EEPROM_WriteDataByte(0, 0x42); | ||
| 77 | EEPROM_Erase(); | ||
| 78 | EXPECT_EQ(EEPROM_ReadDataByte(0), 0); | ||
| 79 | EXPECT_EQ(EEPROM_ReadDataByte(1), 0); | ||
| 80 | } | ||
| 81 | |||
| 82 | TEST_F(EepromStm32Test, TestReadGarbage) { | ||
| 83 | uint8_t garbage = 0x3c; | ||
| 84 | for (int i = 0; i < MOCK_FLASH_SIZE; ++i) { | ||
| 85 | garbage ^= 0xa3; | ||
| 86 | garbage += i; | ||
| 87 | FlashBuf[i] = garbage; | ||
| 88 | } | ||
| 89 | EEPROM_Init(); // Just verify we don't crash | ||
| 90 | } | ||
| 91 | |||
| 92 | TEST_F(EepromStm32Test, TestWriteBadAddress) { | ||
| 93 | EXPECT_EQ(EEPROM_WriteDataByte(EEPROM_SIZE, 0x42), FLASH_BAD_ADDRESS); | ||
| 94 | EXPECT_EQ(EEPROM_WriteDataWord(EEPROM_SIZE - 1, 0xbeef), FLASH_BAD_ADDRESS); | ||
| 95 | EXPECT_EQ(EEPROM_WriteDataWord(EEPROM_SIZE, 0xbeef), FLASH_BAD_ADDRESS); | ||
| 96 | } | ||
| 97 | |||
| 98 | TEST_F(EepromStm32Test, TestReadBadAddress) { | ||
| 99 | EXPECT_EQ(EEPROM_ReadDataByte(EEPROM_SIZE), 0xFF); | ||
| 100 | EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE - 1), 0xFFFF); | ||
| 101 | EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE), 0xFFFF); | ||
| 102 | EXPECT_EQ(eeprom_read_dword((uint32_t*)(EEPROM_SIZE - 4)), 0); | ||
| 103 | EXPECT_EQ(eeprom_read_dword((uint32_t*)(EEPROM_SIZE - 3)), 0xFF000000); | ||
| 104 | EXPECT_EQ(eeprom_read_dword((uint32_t*)EEPROM_SIZE), 0xFFFFFFFF); | ||
| 105 | } | ||
| 106 | |||
| 107 | TEST_F(EepromStm32Test, TestReadByte) { | ||
| 108 | /* Direct compacted-area baseline: Address < 0x80 */ | ||
| 109 | FlashBuf[EEPROM_BASE + 2] = ~0xef; | ||
| 110 | FlashBuf[EEPROM_BASE + 3] = ~0xbe; | ||
| 111 | /* Direct compacted-area baseline: Address >= 0x80 */ | ||
| 112 | FlashBuf[EEPROM_BASE + EEPROM_SIZE - 2] = ~0x78; | ||
| 113 | FlashBuf[EEPROM_BASE + EEPROM_SIZE - 1] = ~0x56; | ||
| 114 | /* Check values */ | ||
| 115 | EEPROM_Init(); | ||
| 116 | EXPECT_EQ(EEPROM_ReadDataByte(2), 0xef); | ||
| 117 | EXPECT_EQ(EEPROM_ReadDataByte(3), 0xbe); | ||
| 118 | EXPECT_EQ(EEPROM_ReadDataByte(EEPROM_SIZE - 2), 0x78); | ||
| 119 | EXPECT_EQ(EEPROM_ReadDataByte(EEPROM_SIZE - 1), 0x56); | ||
| 120 | /* Write Log byte value */ | ||
| 121 | FlashBuf[LOG_BASE] = 0x65; | ||
| 122 | FlashBuf[LOG_BASE + 1] = 3; | ||
| 123 | /* Write Log word value */ | ||
| 124 | *(uint16_t*)&FlashBuf[LOG_BASE + 2] = WORD_NEXT(EEPROM_SIZE - 2); | ||
| 125 | *(uint16_t*)&FlashBuf[LOG_BASE + 4] = ~0x9abc; | ||
| 126 | /* Check values */ | ||
| 127 | EEPROM_Init(); | ||
| 128 | EXPECT_EQ(EEPROM_ReadDataByte(2), 0xef); | ||
| 129 | EXPECT_EQ(EEPROM_ReadDataByte(3), 0x65); | ||
| 130 | EXPECT_EQ(EEPROM_ReadDataByte(EEPROM_SIZE - 2), 0xbc); | ||
| 131 | EXPECT_EQ(EEPROM_ReadDataByte(EEPROM_SIZE - 1), 0x9a); | ||
| 132 | } | ||
| 133 | |||
| 134 | TEST_F(EepromStm32Test, TestWriteByte) { | ||
| 135 | /* Direct compacted-area baseline: Address < 0x80 */ | ||
| 136 | EEPROM_WriteDataByte(2, 0xef); | ||
| 137 | EEPROM_WriteDataByte(3, 0xbe); | ||
| 138 | /* Direct compacted-area baseline: Address >= 0x80 */ | ||
| 139 | EEPROM_WriteDataByte(EEPROM_SIZE - 2, 0x78); | ||
| 140 | EEPROM_WriteDataByte(EEPROM_SIZE - 1, 0x56); | ||
| 141 | /* Check values */ | ||
| 142 | /* First write in each aligned word should have been direct */ | ||
| 143 | EXPECT_EQ(FlashBuf[EEPROM_BASE + 2], (uint8_t)~0xef); | ||
| 144 | EXPECT_EQ(FlashBuf[EEPROM_BASE + EEPROM_SIZE - 2], (uint8_t)~0x78); | ||
| 145 | |||
| 146 | /* Second write per aligned word requires a log entry */ | ||
| 147 | EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE], BYTE_VALUE(3, 0xbe)); | ||
| 148 | EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 2], WORD_NEXT(EEPROM_SIZE - 1)); | ||
| 149 | EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 4], (uint16_t)~0x5678); | ||
| 150 | } | ||
| 151 | |||
| 152 | TEST_F(EepromStm32Test, TestByteRoundTrip) { | ||
| 153 | /* Direct compacted-area: Address < 0x80 */ | ||
| 154 | EEPROM_WriteDataWord(0, 0xdead); | ||
| 155 | EEPROM_WriteDataByte(2, 0xef); | ||
| 156 | EEPROM_WriteDataByte(3, 0xbe); | ||
| 157 | /* Direct compacted-area: Address >= 0x80 */ | ||
| 158 | EEPROM_WriteDataByte(EEPROM_SIZE - 2, 0x78); | ||
| 159 | EEPROM_WriteDataByte(EEPROM_SIZE - 1, 0x56); | ||
| 160 | /* Check values */ | ||
| 161 | EEPROM_Init(); | ||
| 162 | EXPECT_EQ(EEPROM_ReadDataByte(0), 0xad); | ||
| 163 | EXPECT_EQ(EEPROM_ReadDataByte(1), 0xde); | ||
| 164 | EXPECT_EQ(EEPROM_ReadDataByte(2), 0xef); | ||
| 165 | EXPECT_EQ(EEPROM_ReadDataByte(3), 0xbe); | ||
| 166 | EXPECT_EQ(EEPROM_ReadDataByte(EEPROM_SIZE - 2), 0x78); | ||
| 167 | EXPECT_EQ(EEPROM_ReadDataByte(EEPROM_SIZE - 1), 0x56); | ||
| 168 | /* Write log entries */ | ||
| 169 | EEPROM_WriteDataByte(2, 0x80); | ||
| 170 | EEPROM_WriteDataByte(EEPROM_SIZE - 2, 0x3c); | ||
| 171 | /* Check values */ | ||
| 172 | EEPROM_Init(); | ||
| 173 | EXPECT_EQ(EEPROM_ReadDataByte(2), 0x80); | ||
| 174 | EXPECT_EQ(EEPROM_ReadDataByte(3), 0xbe); | ||
| 175 | EXPECT_EQ(EEPROM_ReadDataByte(EEPROM_SIZE - 2), 0x3c); | ||
| 176 | EXPECT_EQ(EEPROM_ReadDataByte(EEPROM_SIZE - 1), 0x56); | ||
| 177 | } | ||
| 178 | |||
| 179 | TEST_F(EepromStm32Test, TestReadWord) { | ||
| 180 | /* Direct compacted-area baseline: Address < 0x80 */ | ||
| 181 | FlashBuf[EEPROM_BASE + 0] = ~0xad; | ||
| 182 | FlashBuf[EEPROM_BASE + 1] = ~0xde; | ||
| 183 | /* Direct compacted-area baseline: Address >= 0x80 */ | ||
| 184 | FlashBuf[EEPROM_BASE + 200] = ~0xcd; | ||
| 185 | FlashBuf[EEPROM_BASE + 201] = ~0xab; | ||
| 186 | FlashBuf[EEPROM_BASE + EEPROM_SIZE - 4] = ~0x34; | ||
| 187 | FlashBuf[EEPROM_BASE + EEPROM_SIZE - 3] = ~0x12; | ||
| 188 | FlashBuf[EEPROM_BASE + EEPROM_SIZE - 2] = ~0x78; | ||
| 189 | FlashBuf[EEPROM_BASE + EEPROM_SIZE - 1] = ~0x56; | ||
| 190 | /* Check values */ | ||
| 191 | EEPROM_Init(); | ||
| 192 | EXPECT_EQ(EEPROM_ReadDataWord(0), 0xdead); | ||
| 193 | EXPECT_EQ(EEPROM_ReadDataWord(200), 0xabcd); | ||
| 194 | EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE - 4), 0x1234); | ||
| 195 | EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE - 2), 0x5678); | ||
| 196 | /* Write Log word zero-encoded */ | ||
| 197 | *(uint16_t*)&FlashBuf[LOG_BASE] = WORD_ZERO(200); | ||
| 198 | /* Write Log word one-encoded */ | ||
| 199 | *(uint16_t*)&FlashBuf[LOG_BASE + 2] = WORD_ONE(EEPROM_SIZE - 4); | ||
| 200 | /* Write Log word value */ | ||
| 201 | *(uint16_t*)&FlashBuf[LOG_BASE + 4] = WORD_NEXT(EEPROM_SIZE - 2); | ||
| 202 | *(uint16_t*)&FlashBuf[LOG_BASE + 6] = ~0x9abc; | ||
| 203 | /* Check values */ | ||
| 204 | EEPROM_Init(); | ||
| 205 | EXPECT_EQ(EEPROM_ReadDataWord(200), 0); | ||
| 206 | EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE - 4), 1); | ||
| 207 | EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE - 2), 0x9abc); | ||
| 208 | } | ||
| 209 | |||
| 210 | TEST_F(EepromStm32Test, TestWriteWord) { | ||
| 211 | /* Direct compacted-area: Address < 0x80 */ | ||
| 212 | EEPROM_WriteDataWord(0, 0xdead); // Aligned | ||
| 213 | EEPROM_WriteDataWord(3, 0xbeef); // Unaligned | ||
| 214 | /* Direct compacted-area: Address >= 0x80 */ | ||
| 215 | EEPROM_WriteDataWord(200, 0xabcd); // Aligned | ||
| 216 | EEPROM_WriteDataWord(203, 0x9876); // Unaligned | ||
| 217 | EEPROM_WriteDataWord(EEPROM_SIZE - 4, 0x1234); | ||
| 218 | EEPROM_WriteDataWord(EEPROM_SIZE - 2, 0x5678); | ||
| 219 | /* Write Log word zero-encoded */ | ||
| 220 | EEPROM_WriteDataWord(EEPROM_SIZE - 4, 0); | ||
| 221 | /* Write Log word one-encoded */ | ||
| 222 | EEPROM_WriteDataWord(EEPROM_SIZE - 2, 1); | ||
| 223 | /* Write Log word value aligned */ | ||
| 224 | EEPROM_WriteDataWord(200, 0x4321); // Aligned | ||
| 225 | /* Write Log word value unaligned */ | ||
| 226 | EEPROM_WriteDataByte(202, 0x3c); // Set neighboring byte | ||
| 227 | EEPROM_WriteDataWord(203, 0xcdef); // Unaligned | ||
| 228 | /* Check values */ | ||
| 229 | /* Direct compacted-area */ | ||
| 230 | EXPECT_EQ(*(uint16_t*)&FlashBuf[EEPROM_BASE], (uint16_t)~0xdead); | ||
| 231 | EXPECT_EQ(*(uint16_t*)&FlashBuf[EEPROM_BASE + 3], (uint16_t)~0xbeef); | ||
| 232 | EXPECT_EQ(*(uint16_t*)&FlashBuf[EEPROM_BASE + 200], (uint16_t)~0xabcd); | ||
| 233 | EXPECT_EQ(FlashBuf[EEPROM_BASE + 203], (uint8_t)~0x76); | ||
| 234 | EXPECT_EQ(FlashBuf[EEPROM_BASE + 204], (uint8_t)~0x98); | ||
| 235 | EXPECT_EQ(*(uint16_t*)&FlashBuf[EEPROM_BASE + EEPROM_SIZE - 4], (uint16_t)~0x1234); | ||
| 236 | EXPECT_EQ(*(uint16_t*)&FlashBuf[EEPROM_BASE + EEPROM_SIZE - 2], (uint16_t)~0x5678); | ||
| 237 | /* Write Log word zero-encoded */ | ||
| 238 | EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE], WORD_ZERO(EEPROM_SIZE - 4)); | ||
| 239 | /* Write Log word one-encoded */ | ||
| 240 | EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 2], WORD_ONE(EEPROM_SIZE - 2)); | ||
| 241 | /* Write Log word value aligned */ | ||
| 242 | EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 4], WORD_NEXT(200)); | ||
| 243 | EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 6], (uint16_t)~0x4321); | ||
| 244 | /* Write Log word value unaligned */ | ||
| 245 | EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 8], WORD_NEXT(202)); | ||
| 246 | EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 10], (uint16_t)~0x763c); | ||
| 247 | EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 12], WORD_NEXT(202)); | ||
| 248 | EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 14], (uint16_t)~0xef3c); | ||
| 249 | EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 16], WORD_NEXT(204)); | ||
| 250 | EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 18], (uint16_t)~0x00cd); | ||
| 251 | } | ||
| 252 | |||
| 253 | TEST_F(EepromStm32Test, TestWordRoundTrip) { | ||
| 254 | /* Direct compacted-area: Address < 0x80 */ | ||
| 255 | EEPROM_WriteDataWord(0, 0xdead); // Aligned | ||
| 256 | EEPROM_WriteDataWord(3, 0xbeef); // Unaligned | ||
| 257 | /* Direct compacted-area: Address >= 0x80 */ | ||
| 258 | EEPROM_WriteDataWord(200, 0xabcd); // Aligned | ||
| 259 | EEPROM_WriteDataWord(203, 0x9876); // Unaligned | ||
| 260 | EEPROM_WriteDataWord(EEPROM_SIZE - 4, 0x1234); | ||
| 261 | EEPROM_WriteDataWord(EEPROM_SIZE - 2, 0x5678); | ||
| 262 | /* Check values */ | ||
| 263 | EEPROM_Init(); | ||
| 264 | EXPECT_EQ(EEPROM_ReadDataWord(0), 0xdead); | ||
| 265 | EXPECT_EQ(EEPROM_ReadDataWord(3), 0xbeef); | ||
| 266 | EXPECT_EQ(EEPROM_ReadDataWord(200), 0xabcd); | ||
| 267 | EXPECT_EQ(EEPROM_ReadDataWord(203), 0x9876); | ||
| 268 | EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE - 4), 0x1234); | ||
| 269 | EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE - 2), 0x5678); | ||
| 270 | |||
| 271 | /* Write Log word zero-encoded */ | ||
| 272 | EEPROM_WriteDataWord(EEPROM_SIZE - 4, 0); | ||
| 273 | /* Write Log word one-encoded */ | ||
| 274 | EEPROM_WriteDataWord(EEPROM_SIZE - 2, 1); | ||
| 275 | /* Write Log word value aligned */ | ||
| 276 | EEPROM_WriteDataWord(200, 0x4321); // Aligned | ||
| 277 | /* Write Log word value unaligned */ | ||
| 278 | EEPROM_WriteDataByte(202, 0x3c); // Set neighboring byte | ||
| 279 | EEPROM_WriteDataWord(203, 0xcdef); // Unaligned | ||
| 280 | /* Check values */ | ||
| 281 | EEPROM_Init(); | ||
| 282 | EXPECT_EQ(EEPROM_ReadDataWord(200), 0x4321); | ||
| 283 | EXPECT_EQ(EEPROM_ReadDataByte(202), 0x3c); | ||
| 284 | EXPECT_EQ(EEPROM_ReadDataWord(203), 0xcdef); | ||
| 285 | EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE - 4), 0); | ||
| 286 | EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE - 2), 1); | ||
| 287 | } | ||
| 288 | |||
| 289 | TEST_F(EepromStm32Test, TestByteWordBoundary) { | ||
| 290 | /* Direct compacted-area write */ | ||
| 291 | EEPROM_WriteDataWord(0x7e, 0xdead); | ||
| 292 | EEPROM_WriteDataWord(0x80, 0xbeef); | ||
| 293 | /* Byte log entry */ | ||
| 294 | EEPROM_WriteDataByte(0x7f, 0x3c); | ||
| 295 | /* Word log entry */ | ||
| 296 | EEPROM_WriteDataByte(0x80, 0x18); | ||
| 297 | /* Check values */ | ||
| 298 | EEPROM_Init(); | ||
| 299 | EXPECT_EQ(EEPROM_ReadDataWord(0x7e), 0x3cad); | ||
| 300 | EXPECT_EQ(EEPROM_ReadDataWord(0x80), 0xbe18); | ||
| 301 | EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE], BYTE_VALUE(0x7f, 0x3c)); | ||
| 302 | EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 2], WORD_NEXT(0x80)); | ||
| 303 | EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 4], (uint16_t)~0xbe18); | ||
| 304 | /* Byte log entries */ | ||
| 305 | EEPROM_WriteDataWord(0x7e, 0xcafe); | ||
| 306 | /* Check values */ | ||
| 307 | EEPROM_Init(); | ||
| 308 | EXPECT_EQ(EEPROM_ReadDataWord(0x7e), 0xcafe); | ||
| 309 | EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 6], BYTE_VALUE(0x7e, 0xfe)); | ||
| 310 | EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 8], BYTE_VALUE(0x7f, 0xca)); | ||
| 311 | /* Byte and Word log entries */ | ||
| 312 | EEPROM_WriteDataWord(0x7f, 0xba5e); | ||
| 313 | /* Check values */ | ||
| 314 | EEPROM_Init(); | ||
| 315 | EXPECT_EQ(EEPROM_ReadDataWord(0x7f), 0xba5e); | ||
| 316 | EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 10], BYTE_VALUE(0x7f, 0x5e)); | ||
| 317 | EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 12], WORD_NEXT(0x80)); | ||
| 318 | EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 14], (uint16_t)~0xbeba); | ||
| 319 | /* Word log entry */ | ||
| 320 | EEPROM_WriteDataWord(0x80, 0xf00d); | ||
| 321 | /* Check values */ | ||
| 322 | EEPROM_Init(); | ||
| 323 | EXPECT_EQ(EEPROM_ReadDataWord(0x80), 0xf00d); | ||
| 324 | EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 16], WORD_NEXT(0x80)); | ||
| 325 | EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 18], (uint16_t)~0xf00d); | ||
| 326 | } | ||
| 327 | |||
| 328 | TEST_F(EepromStm32Test, TestDWordRoundTrip) { | ||
| 329 | /* Direct compacted-area: Address < 0x80 */ | ||
| 330 | eeprom_write_dword((uint32_t*)0, 0xdeadbeef); // Aligned | ||
| 331 | eeprom_write_dword((uint32_t*)9, 0x12345678); // Unaligned | ||
| 332 | /* Direct compacted-area: Address >= 0x80 */ | ||
| 333 | eeprom_write_dword((uint32_t*)200, 0xfacef00d); | ||
| 334 | eeprom_write_dword((uint32_t*)(EEPROM_SIZE - 4), 0xba5eba11); // Aligned | ||
| 335 | eeprom_write_dword((uint32_t*)(EEPROM_SIZE - 9), 0xcafed00d); // Unaligned | ||
| 336 | /* Check direct values */ | ||
| 337 | EEPROM_Init(); | ||
| 338 | EXPECT_EQ(eeprom_read_dword((uint32_t*)0), 0xdeadbeef); | ||
| 339 | EXPECT_EQ(eeprom_read_dword((uint32_t*)9), 0x12345678); | ||
| 340 | EXPECT_EQ(eeprom_read_dword((uint32_t*)200), 0xfacef00d); | ||
| 341 | EXPECT_EQ(eeprom_read_dword((uint32_t*)(EEPROM_SIZE - 4)), 0xba5eba11); // Aligned | ||
| 342 | EXPECT_EQ(eeprom_read_dword((uint32_t*)(EEPROM_SIZE - 9)), 0xcafed00d); // Unaligned | ||
| 343 | /* Write Log byte encoded */ | ||
| 344 | eeprom_write_dword((uint32_t*)0, 0xdecafbad); | ||
| 345 | eeprom_write_dword((uint32_t*)9, 0x87654321); | ||
| 346 | /* Write Log word encoded */ | ||
| 347 | eeprom_write_dword((uint32_t*)200, 1); | ||
| 348 | /* Write Log word value aligned */ | ||
| 349 | eeprom_write_dword((uint32_t*)(EEPROM_SIZE - 4), 0xdeadc0de); // Aligned | ||
| 350 | eeprom_write_dword((uint32_t*)(EEPROM_SIZE - 9), 0x6789abcd); // Unaligned | ||
| 351 | /* Check log values */ | ||
| 352 | EEPROM_Init(); | ||
| 353 | EXPECT_EQ(eeprom_read_dword((uint32_t*)0), 0xdecafbad); | ||
| 354 | EXPECT_EQ(eeprom_read_dword((uint32_t*)9), 0x87654321); | ||
| 355 | EXPECT_EQ(eeprom_read_dword((uint32_t*)200), 1); | ||
| 356 | EXPECT_EQ(eeprom_read_dword((uint32_t*)(EEPROM_SIZE - 4)), 0xdeadc0de); // Aligned | ||
| 357 | EXPECT_EQ(eeprom_read_dword((uint32_t*)(EEPROM_SIZE - 9)), 0x6789abcd); // Unaligned | ||
| 358 | } | ||
| 359 | |||
| 360 | TEST_F(EepromStm32Test, TestBlockRoundTrip) { | ||
| 361 | char src0[] = "0123456789abcdef"; | ||
| 362 | void* src1 = (void*)&src0[1]; | ||
| 363 | /* Various alignments of src & dst, Address < 0x80 */ | ||
| 364 | eeprom_write_block(src0, (void*)0, sizeof(src0)); | ||
| 365 | eeprom_write_block(src0, (void*)21, sizeof(src0)); | ||
| 366 | eeprom_write_block(src1, (void*)40, sizeof(src0) - 1); | ||
| 367 | eeprom_write_block(src1, (void*)61, sizeof(src0) - 1); | ||
| 368 | /* Various alignments of src & dst, Address >= 0x80 */ | ||
| 369 | eeprom_write_block(src0, (void*)140, sizeof(src0)); | ||
| 370 | eeprom_write_block(src0, (void*)161, sizeof(src0)); | ||
| 371 | eeprom_write_block(src1, (void*)180, sizeof(src0) - 1); | ||
| 372 | eeprom_write_block(src1, (void*)201, sizeof(src0) - 1); | ||
| 373 | |||
| 374 | /* Check values */ | ||
| 375 | EEPROM_Init(); | ||
| 376 | |||
| 377 | char dstBuf[256] = {0}; | ||
| 378 | char* dst0a = (char*)dstBuf; | ||
| 379 | char* dst0b = (char*)&dstBuf[20]; | ||
| 380 | char* dst1a = (char*)&dstBuf[41]; | ||
| 381 | char* dst1b = (char*)&dstBuf[61]; | ||
| 382 | char* dst0c = (char*)&dstBuf[80]; | ||
| 383 | char* dst0d = (char*)&dstBuf[100]; | ||
| 384 | char* dst1c = (char*)&dstBuf[121]; | ||
| 385 | char* dst1d = (char*)&dstBuf[141]; | ||
| 386 | eeprom_read_block((void*)dst0a, (void*)0, sizeof(src0)); | ||
| 387 | eeprom_read_block((void*)dst0b, (void*)21, sizeof(src0)); | ||
| 388 | eeprom_read_block((void*)dst1a, (void*)40, sizeof(src0) - 1); | ||
| 389 | eeprom_read_block((void*)dst1b, (void*)61, sizeof(src0) - 1); | ||
| 390 | eeprom_read_block((void*)dst0c, (void*)140, sizeof(src0)); | ||
| 391 | eeprom_read_block((void*)dst0d, (void*)161, sizeof(src0)); | ||
| 392 | eeprom_read_block((void*)dst1c, (void*)180, sizeof(src0) - 1); | ||
| 393 | eeprom_read_block((void*)dst1d, (void*)201, sizeof(src0) - 1); | ||
| 394 | EXPECT_EQ(strcmp((char*)src0, dst0a), 0); | ||
| 395 | EXPECT_EQ(strcmp((char*)src0, dst0b), 0); | ||
| 396 | EXPECT_EQ(strcmp((char*)src0, dst0c), 0); | ||
| 397 | EXPECT_EQ(strcmp((char*)src0, dst0d), 0); | ||
| 398 | EXPECT_EQ(strcmp((char*)src1, dst1a), 0); | ||
| 399 | EXPECT_EQ(strcmp((char*)src1, dst1b), 0); | ||
| 400 | EXPECT_EQ(strcmp((char*)src1, dst1c), 0); | ||
| 401 | EXPECT_EQ(strcmp((char*)src1, dst1d), 0); | ||
| 402 | } | ||
| 403 | |||
| 404 | TEST_F(EepromStm32Test, TestCompaction) { | ||
| 405 | /* Direct writes */ | ||
| 406 | eeprom_write_dword((uint32_t*)0, 0xdeadbeef); | ||
| 407 | eeprom_write_byte((uint8_t*)4, 0x3c); | ||
| 408 | eeprom_write_word((uint16_t*)6, 0xd00d); | ||
| 409 | eeprom_write_dword((uint32_t*)150, 0xcafef00d); | ||
| 410 | eeprom_write_dword((uint32_t*)200, 0x12345678); | ||
| 411 | /* Fill write log entries */ | ||
| 412 | uint32_t i; | ||
| 413 | uint32_t val = 0xd8453c6b; | ||
| 414 | for (i = 0; i < (LOG_SIZE / (sizeof(uint32_t) * 2)); i++) { | ||
| 415 | val ^= 0x593ca5b3; | ||
| 416 | val += i; | ||
| 417 | eeprom_write_dword((uint32_t*)200, val); | ||
| 418 | } | ||
| 419 | /* Check values pre-compaction */ | ||
| 420 | EEPROM_Init(); | ||
| 421 | EXPECT_EQ(eeprom_read_dword((uint32_t*)0), 0xdeadbeef); | ||
| 422 | EXPECT_EQ(eeprom_read_byte((uint8_t*)4), 0x3c); | ||
| 423 | EXPECT_EQ(eeprom_read_word((uint16_t*)6), 0xd00d); | ||
| 424 | EXPECT_EQ(eeprom_read_dword((uint32_t*)150), 0xcafef00d); | ||
| 425 | EXPECT_EQ(eeprom_read_dword((uint32_t*)200), val); | ||
| 426 | EXPECT_NE(*(uint16_t*)&FlashBuf[LOG_BASE], 0xFFFF); | ||
| 427 | EXPECT_NE(*(uint16_t*)&FlashBuf[LOG_BASE + LOG_SIZE - 2], 0xFFFF); | ||
| 428 | /* Run compaction */ | ||
| 429 | eeprom_write_byte((uint8_t*)4, 0x1f); | ||
| 430 | EEPROM_Init(); | ||
| 431 | EXPECT_EQ(eeprom_read_dword((uint32_t*)0), 0xdeadbeef); | ||
| 432 | EXPECT_EQ(eeprom_read_byte((uint8_t*)4), 0x1f); | ||
| 433 | EXPECT_EQ(eeprom_read_word((uint16_t*)6), 0xd00d); | ||
| 434 | EXPECT_EQ(eeprom_read_dword((uint32_t*)150), 0xcafef00d); | ||
| 435 | EXPECT_EQ(eeprom_read_dword((uint32_t*)200), val); | ||
| 436 | EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE], 0xFFFF); | ||
| 437 | EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + LOG_SIZE - 2], 0xFFFF); | ||
| 438 | } | ||
diff --git a/platforms/test/flash_stm32_mock.c b/platforms/test/flash_stm32_mock.c new file mode 100644 index 000000000..222a004bc --- /dev/null +++ b/platforms/test/flash_stm32_mock.c | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | /* Copyright 2021 by Don Kjer | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 2 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <string.h> | ||
| 18 | #include <stdbool.h> | ||
| 19 | #include "flash_stm32.h" | ||
| 20 | |||
| 21 | uint8_t FlashBuf[MOCK_FLASH_SIZE] = {0}; | ||
| 22 | |||
| 23 | static bool flash_locked = true; | ||
| 24 | |||
| 25 | FLASH_Status FLASH_ErasePage(uint32_t Page_Address) { | ||
| 26 | if (flash_locked) return FLASH_ERROR_WRP; | ||
| 27 | Page_Address -= (uintptr_t)FlashBuf; | ||
| 28 | Page_Address -= (Page_Address % FEE_PAGE_SIZE); | ||
| 29 | if (Page_Address >= MOCK_FLASH_SIZE) return FLASH_BAD_ADDRESS; | ||
| 30 | memset(&FlashBuf[Page_Address], '\xff', FEE_PAGE_SIZE); | ||
| 31 | return FLASH_COMPLETE; | ||
| 32 | } | ||
| 33 | |||
| 34 | FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data) { | ||
| 35 | if (flash_locked) return FLASH_ERROR_WRP; | ||
| 36 | Address -= (uintptr_t)FlashBuf; | ||
| 37 | if (Address >= MOCK_FLASH_SIZE) return FLASH_BAD_ADDRESS; | ||
| 38 | uint16_t oldData = *(uint16_t*)&FlashBuf[Address]; | ||
| 39 | if (oldData == 0xFFFF || Data == 0) { | ||
| 40 | *(uint16_t*)&FlashBuf[Address] = Data; | ||
| 41 | return FLASH_COMPLETE; | ||
| 42 | } else { | ||
| 43 | return FLASH_ERROR_PG; | ||
| 44 | } | ||
| 45 | } | ||
| 46 | |||
| 47 | FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout) { return FLASH_COMPLETE; } | ||
| 48 | void FLASH_Unlock(void) { flash_locked = false; } | ||
| 49 | void FLASH_Lock(void) { flash_locked = true; } | ||
diff --git a/platforms/test/hal.h b/platforms/test/hal.h new file mode 100644 index 000000000..2d268ad54 --- /dev/null +++ b/platforms/test/hal.h | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | /* Copyright 2021 QMK | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 3 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #pragma once | ||
| 17 | |||
| 18 | // Just here to please eeprom tests | ||
diff --git a/platforms/test/platform.c b/platforms/test/platform.c new file mode 100644 index 000000000..8ddceeda8 --- /dev/null +++ b/platforms/test/platform.c | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | /* Copyright 2021 QMK | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 3 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include "platform_deps.h" | ||
| 18 | |||
| 19 | void platform_setup(void) { | ||
| 20 | // do nothing | ||
| 21 | } \ No newline at end of file | ||
diff --git a/platforms/test/platform.h b/platforms/test/platform.h new file mode 100644 index 000000000..f296d1d53 --- /dev/null +++ b/platforms/test/platform.h | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | /* Copyright 2021 QMK | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 3 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #pragma once | ||
| 17 | |||
| 18 | // here just to please the build | ||
diff --git a/platforms/test/platform.mk b/platforms/test/platform.mk new file mode 100644 index 000000000..eb2424ec5 --- /dev/null +++ b/platforms/test/platform.mk | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | SYSTEM_TYPE := $(shell gcc -dumpmachine) | ||
| 2 | GCC_VERSION := $(shell gcc --version 2>/dev/null) | ||
| 3 | |||
| 4 | CC = $(CC_PREFIX) gcc | ||
| 5 | OBJCOPY = | ||
| 6 | OBJDUMP = | ||
| 7 | SIZE = | ||
| 8 | AR = | ||
| 9 | NM = | ||
| 10 | HEX = | ||
| 11 | EEP = | ||
| 12 | BIN = | ||
| 13 | |||
| 14 | |||
| 15 | COMPILEFLAGS += -funsigned-char | ||
| 16 | ifeq ($(findstring clang, ${GCC_VERSION}),) | ||
| 17 | COMPILEFLAGS += -funsigned-bitfields | ||
| 18 | endif | ||
| 19 | COMPILEFLAGS += -ffunction-sections | ||
| 20 | COMPILEFLAGS += -fdata-sections | ||
| 21 | COMPILEFLAGS += -fshort-enums | ||
| 22 | ifneq ($(findstring mingw, ${SYSTEM_TYPE}),) | ||
| 23 | COMPILEFLAGS += -mno-ms-bitfields | ||
| 24 | endif | ||
| 25 | |||
| 26 | CFLAGS += $(COMPILEFLAGS) | ||
| 27 | ifeq ($(findstring clang, ${GCC_VERSION}),) | ||
| 28 | CFLAGS += -fno-inline-small-functions | ||
| 29 | endif | ||
| 30 | CFLAGS += -fno-strict-aliasing | ||
| 31 | |||
| 32 | CXXFLAGS += $(COMPILEFLAGS) | ||
| 33 | CXXFLAGS += -fno-exceptions | ||
| 34 | CXXFLAGS += -std=gnu++11 | ||
diff --git a/platforms/test/platform_deps.h b/platforms/test/platform_deps.h new file mode 100644 index 000000000..f296d1d53 --- /dev/null +++ b/platforms/test/platform_deps.h | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | /* Copyright 2021 QMK | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 3 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #pragma once | ||
| 17 | |||
| 18 | // here just to please the build | ||
diff --git a/platforms/test/rules.mk b/platforms/test/rules.mk new file mode 100644 index 000000000..66b853d8e --- /dev/null +++ b/platforms/test/rules.mk | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | eeprom_stm32_DEFS := -DFLASH_STM32_MOCKED -DNO_PRINT -DFEE_FLASH_BASE=FlashBuf | ||
| 2 | eeprom_stm32_tiny_DEFS := $(eeprom_stm32_DEFS) \ | ||
| 3 | -DFEE_MCU_FLASH_SIZE=1 \ | ||
| 4 | -DMOCK_FLASH_SIZE=1024 \ | ||
| 5 | -DFEE_PAGE_SIZE=512 \ | ||
| 6 | -DFEE_PAGE_COUNT=1 | ||
| 7 | eeprom_stm32_large_DEFS := $(eeprom_stm32_DEFS) \ | ||
| 8 | -DFEE_MCU_FLASH_SIZE=64 \ | ||
| 9 | -DMOCK_FLASH_SIZE=65536 \ | ||
| 10 | -DFEE_PAGE_SIZE=2048 \ | ||
| 11 | -DFEE_PAGE_COUNT=16 | ||
| 12 | |||
| 13 | eeprom_stm32_INC := \ | ||
| 14 | $(PLATFORM_PATH)/chibios/ | ||
| 15 | eeprom_stm32_tiny_INC := $(eeprom_stm32_INC) | ||
| 16 | eeprom_stm32_large_INC := $(eeprom_stm32_INC) | ||
| 17 | |||
| 18 | eeprom_stm32_SRC := \ | ||
| 19 | $(TOP_DIR)/drivers/eeprom/eeprom_driver.c \ | ||
| 20 | $(PLATFORM_PATH)/$(PLATFORM_KEY)/eeprom_stm32_tests.cpp \ | ||
| 21 | $(PLATFORM_PATH)/$(PLATFORM_KEY)/flash_stm32_mock.c \ | ||
| 22 | $(PLATFORM_PATH)/chibios/eeprom_stm32.c | ||
| 23 | eeprom_stm32_tiny_SRC := $(eeprom_stm32_SRC) | ||
| 24 | eeprom_stm32_large_SRC := $(eeprom_stm32_SRC) | ||
diff --git a/platforms/test/suspend.c b/platforms/test/suspend.c new file mode 100644 index 000000000..76b705967 --- /dev/null +++ b/platforms/test/suspend.c | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | /* Copyright 2017 Fred Sundvik | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 2 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
diff --git a/platforms/test/testlist.mk b/platforms/test/testlist.mk new file mode 100644 index 000000000..51a9638bb --- /dev/null +++ b/platforms/test/testlist.mk | |||
| @@ -0,0 +1 @@ | |||
| TEST_LIST += eeprom_stm32_tiny eeprom_stm32_large | |||
diff --git a/platforms/test/timer.c b/platforms/test/timer.c new file mode 100644 index 000000000..61c3a0020 --- /dev/null +++ b/platforms/test/timer.c | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | /* Copyright 2017 Fred Sundvik | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 2 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include "timer.h" | ||
| 18 | |||
| 19 | static uint32_t current_time = 0; | ||
| 20 | |||
| 21 | void timer_init(void) { current_time = 0; } | ||
| 22 | |||
| 23 | void timer_clear(void) { current_time = 0; } | ||
| 24 | |||
| 25 | uint16_t timer_read(void) { return current_time & 0xFFFF; } | ||
| 26 | uint32_t timer_read32(void) { return current_time; } | ||
| 27 | uint16_t timer_elapsed(uint16_t last) { return TIMER_DIFF_16(timer_read(), last); } | ||
| 28 | uint32_t timer_elapsed32(uint32_t last) { return TIMER_DIFF_32(timer_read32(), last); } | ||
| 29 | |||
| 30 | void set_time(uint32_t t) { current_time = t; } | ||
| 31 | void advance_time(uint32_t ms) { current_time += ms; } | ||
| 32 | |||
| 33 | void wait_ms(uint32_t ms) { advance_time(ms); } | ||
diff --git a/platforms/timer.h b/platforms/timer.h new file mode 100644 index 000000000..02e39e79e --- /dev/null +++ b/platforms/timer.h | |||
| @@ -0,0 +1,67 @@ | |||
| 1 | /* | ||
| 2 | Copyright 2011 Jun Wako <wakojun@gmail.com> | ||
| 3 | Copyright 2021 Simon Arlott | ||
| 4 | |||
| 5 | This program is free software: you can redistribute it and/or modify | ||
| 6 | it under the terms of the GNU General Public License as published by | ||
| 7 | the Free Software Foundation, either version 2 of the License, or | ||
| 8 | (at your option) any later version. | ||
| 9 | |||
| 10 | This program is distributed in the hope that it will be useful, | ||
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | GNU General Public License for more details. | ||
| 14 | |||
| 15 | You should have received a copy of the GNU General Public License | ||
| 16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #pragma once | ||
| 20 | |||
| 21 | #if __has_include_next("_timer.h") | ||
| 22 | # include_next "_timer.h" /* Include the platform's _timer.h */ | ||
| 23 | #endif | ||
| 24 | |||
| 25 | #include <stdint.h> | ||
| 26 | |||
| 27 | #define TIMER_DIFF(a, b, max) ((max == UINT8_MAX) ? ((uint8_t)((a) - (b))) : ((max == UINT16_MAX) ? ((uint16_t)((a) - (b))) : ((max == UINT32_MAX) ? ((uint32_t)((a) - (b))) : ((a) >= (b) ? (a) - (b) : (max) + 1 - (b) + (a))))) | ||
| 28 | #define TIMER_DIFF_8(a, b) TIMER_DIFF(a, b, UINT8_MAX) | ||
| 29 | #define TIMER_DIFF_16(a, b) TIMER_DIFF(a, b, UINT16_MAX) | ||
| 30 | #define TIMER_DIFF_32(a, b) TIMER_DIFF(a, b, UINT32_MAX) | ||
| 31 | #define TIMER_DIFF_RAW(a, b) TIMER_DIFF_8(a, b) | ||
| 32 | |||
| 33 | #ifdef __cplusplus | ||
| 34 | extern "C" { | ||
| 35 | #endif | ||
| 36 | |||
| 37 | extern volatile uint32_t timer_count; | ||
| 38 | |||
| 39 | void timer_init(void); | ||
| 40 | void timer_clear(void); | ||
| 41 | uint16_t timer_read(void); | ||
| 42 | uint32_t timer_read32(void); | ||
| 43 | uint16_t timer_elapsed(uint16_t last); | ||
| 44 | uint32_t timer_elapsed32(uint32_t last); | ||
| 45 | |||
| 46 | // Utility functions to check if a future time has expired & autmatically handle time wrapping if checked / reset frequently (half of max value) | ||
| 47 | #define timer_expired(current, future) ((uint16_t)(current - future) < UINT16_MAX / 2) | ||
| 48 | #define timer_expired32(current, future) ((uint32_t)(current - future) < UINT32_MAX / 2) | ||
| 49 | |||
| 50 | // Use an appropriate timer integer size based on architecture (16-bit will overflow sooner) | ||
| 51 | #if FAST_TIMER_T_SIZE < 32 | ||
| 52 | # define TIMER_DIFF_FAST(a, b) TIMER_DIFF_16(a, b) | ||
| 53 | # define timer_expired_fast(current, future) timer_expired(current, future) | ||
| 54 | typedef uint16_t fast_timer_t; | ||
| 55 | fast_timer_t inline timer_read_fast(void) { return timer_read(); } | ||
| 56 | fast_timer_t inline timer_elapsed_fast(fast_timer_t last) { return timer_elapsed(last); } | ||
| 57 | #else | ||
| 58 | # define TIMER_DIFF_FAST(a, b) TIMER_DIFF_32(a, b) | ||
| 59 | # define timer_expired_fast(current, future) timer_expired32(current, future) | ||
| 60 | typedef uint32_t fast_timer_t; | ||
| 61 | fast_timer_t inline timer_read_fast(void) { return timer_read32(); } | ||
| 62 | fast_timer_t inline timer_elapsed_fast(fast_timer_t last) { return timer_elapsed32(last); } | ||
| 63 | #endif | ||
| 64 | |||
| 65 | #ifdef __cplusplus | ||
| 66 | } | ||
| 67 | #endif | ||
diff --git a/platforms/wait.h b/platforms/wait.h new file mode 100644 index 000000000..cf7180fb0 --- /dev/null +++ b/platforms/wait.h | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | /* Copyright 2021 QMK | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 3 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #pragma once | ||
| 17 | |||
| 18 | #include <inttypes.h> | ||
| 19 | |||
| 20 | #ifdef __cplusplus | ||
| 21 | extern "C" { | ||
| 22 | #endif | ||
| 23 | |||
| 24 | #if __has_include_next("_wait.h") | ||
| 25 | # include_next "_wait.h" /* Include the platforms _wait.h */ | ||
| 26 | #endif | ||
| 27 | |||
| 28 | #ifdef __cplusplus | ||
| 29 | } | ||
| 30 | #endif | ||
