From 2de70e6f2d5c7217ec0a0f318e999a0644d9db0d Mon Sep 17 00:00:00 2001 From: Dasky <32983009+daskygit@users.noreply.github.com> Date: Mon, 30 May 2022 23:04:50 +0100 Subject: Add uf2-split-* make targets. (#17257) --- platforms/chibios/flash.mk | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'platforms') diff --git a/platforms/chibios/flash.mk b/platforms/chibios/flash.mk index a91ef2cf35..86bbc22943 100644 --- a/platforms/chibios/flash.mk +++ b/platforms/chibios/flash.mk @@ -54,11 +54,11 @@ endef # TODO: Remove once ARM has a way to configure EECONFIG_HANDEDNESS # within the emulated eeprom via dfu-util or another tool -ifneq (,$(filter $(MAKECMDGOALS),dfu-util-split-left)) +ifneq (,$(filter $(MAKECMDGOALS), dfu-util-split-left uf2-split-left)) OPT_DEFS += -DINIT_EE_HANDS_LEFT endif -ifneq (,$(filter $(MAKECMDGOALS),dfu-util-split-right)) +ifneq (,$(filter $(MAKECMDGOALS), dfu-util-split-right uf2-split-right)) OPT_DEFS += -DINIT_EE_HANDS_RIGHT endif @@ -66,6 +66,10 @@ dfu-util-split-left: dfu-util dfu-util-split-right: dfu-util +uf2-split-left: flash + +uf2-split-right: flash + ST_LINK_CLI ?= st-link_cli ST_LINK_ARGS ?= -- cgit v1.2.3 From ecce9900c9cecfb095a9eb041af32eab26b44c1e Mon Sep 17 00:00:00 2001 From: Andrew Dunai Date: Tue, 31 May 2022 09:15:17 +0300 Subject: Improve PS/2 mouse performance (#17111) --- platforms/avr/drivers/ps2/ps2_usart.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'platforms') diff --git a/platforms/avr/drivers/ps2/ps2_usart.c b/platforms/avr/drivers/ps2/ps2_usart.c index 39ec930d4a..581badac64 100644 --- a/platforms/avr/drivers/ps2/ps2_usart.c +++ b/platforms/avr/drivers/ps2/ps2_usart.c @@ -72,8 +72,8 @@ uint8_t ps2_error = PS2_ERR_NONE; static inline uint8_t pbuf_dequeue(void); static inline void pbuf_enqueue(uint8_t data); -static inline bool pbuf_has_data(void); static inline void pbuf_clear(void); +bool pbuf_has_data(void); void ps2_host_init(void) { idle(); // without this many USART errors occur when cable is disconnected @@ -212,7 +212,7 @@ static inline uint8_t pbuf_dequeue(void) { return val; } -static inline bool pbuf_has_data(void) { +bool pbuf_has_data(void) { uint8_t sreg = SREG; cli(); bool has_data = (pbuf_head != pbuf_tail); -- cgit v1.2.3 From bbab8eb993c7015a53a51e88da9c1fce6736cffa Mon Sep 17 00:00:00 2001 From: Thomas Preisner Date: Tue, 31 May 2022 08:20:10 +0200 Subject: Make bootloader_jump for dualbank STM32 respect STM32_BOOTLOADER_DUAL_BANK_DELAY (#17178) --- platforms/chibios/bootloaders/stm32_dfu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'platforms') diff --git a/platforms/chibios/bootloaders/stm32_dfu.c b/platforms/chibios/bootloaders/stm32_dfu.c index ff866bd2bc..7b4ab86033 100644 --- a/platforms/chibios/bootloaders/stm32_dfu.c +++ b/platforms/chibios/bootloaders/stm32_dfu.c @@ -38,7 +38,7 @@ extern uint32_t __ram0_end__; # endif # ifndef STM32_BOOTLOADER_DUAL_BANK_DELAY -# define STM32_BOOTLOADER_DUAL_BANK_DELAY 100000 +# define STM32_BOOTLOADER_DUAL_BANK_DELAY 100 # endif __attribute__((weak)) void bootloader_jump(void) { @@ -55,7 +55,7 @@ __attribute__((weak)) void bootloader_jump(void) { # endif // Wait for a while for the capacitor to charge - wait_ms(100); + wait_ms(STM32_BOOTLOADER_DUAL_BANK_DELAY); // Issue a system reset to get the ROM bootloader to execute, with BOOT0 high NVIC_SystemReset(); -- cgit v1.2.3 From e89478eb0fe582d1a30a882e278927e31c9cdcc7 Mon Sep 17 00:00:00 2001 From: Stefan Kerkmann Date: Mon, 6 Jun 2022 00:47:22 +0200 Subject: [Core] Update C standard to GNU11, C++ to GNU++14 (#17114) --- platforms/arm_atsam/platform.mk | 2 +- platforms/avr/platform.mk | 2 +- platforms/test/platform.mk | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'platforms') diff --git a/platforms/arm_atsam/platform.mk b/platforms/arm_atsam/platform.mk index b49bf764d7..9618838dc3 100644 --- a/platforms/arm_atsam/platform.mk +++ b/platforms/arm_atsam/platform.mk @@ -30,7 +30,7 @@ COMPILEFLAGS += -mthumb CFLAGS += $(COMPILEFLAGS) CXXFLAGS += $(COMPILEFLAGS) -CXXFLAGS += -fno-exceptions -std=c++11 +CXXFLAGS += -fno-exceptions $(CXXSTANDARD) LDFLAGS +=-Wl,--gc-sections LDFLAGS += -Wl,-Map="%OUT%%PROJ_NAME%.map" diff --git a/platforms/avr/platform.mk b/platforms/avr/platform.mk index 978199b385..b51a94c93a 100644 --- a/platforms/avr/platform.mk +++ b/platforms/avr/platform.mk @@ -38,7 +38,7 @@ CFLAGS += -fno-inline-small-functions CFLAGS += -fno-strict-aliasing CXXFLAGS += $(COMPILEFLAGS) -CXXFLAGS += -fno-exceptions -std=c++11 +CXXFLAGS += -fno-exceptions $(CXXSTANDARD) LDFLAGS += -Wl,--gc-sections diff --git a/platforms/test/platform.mk b/platforms/test/platform.mk index eb2424ec5c..f07c863e69 100644 --- a/platforms/test/platform.mk +++ b/platforms/test/platform.mk @@ -31,4 +31,4 @@ CFLAGS += -fno-strict-aliasing CXXFLAGS += $(COMPILEFLAGS) CXXFLAGS += -fno-exceptions -CXXFLAGS += -std=gnu++11 +CXXFLAGS += $(CXXSTANDARD) -- cgit v1.2.3 From 1085500e894d9d31c4e97e7f1b74091bb9043a91 Mon Sep 17 00:00:00 2001 From: Nick Brassel Date: Wed, 8 Jun 2022 09:42:35 +1000 Subject: Rework paths for eeprom locations. (#17326) * Rework paths for eeprom locations. * File relocation. * Wrong file move. * Fixup test paths. --- platforms/chibios/drivers/eeprom/eeprom_stm32.c | 629 +++++++++++++++++++++ platforms/chibios/drivers/eeprom/eeprom_stm32.h | 33 ++ .../chibios/drivers/eeprom/eeprom_stm32_defs.h | 136 +++++ platforms/chibios/drivers/eeprom/eeprom_teensy.c | 546 ++++++++++++++++++ platforms/chibios/drivers/eeprom/eeprom_teensy.h | 25 + platforms/chibios/drivers/flash/flash_stm32.c | 208 +++++++ platforms/chibios/drivers/flash/flash_stm32.h | 44 ++ platforms/chibios/eeprom_stm32.c | 629 --------------------- platforms/chibios/eeprom_stm32.h | 33 -- platforms/chibios/eeprom_stm32_defs.h | 136 ----- platforms/chibios/eeprom_teensy.c | 546 ------------------ platforms/chibios/eeprom_teensy.h | 25 - platforms/chibios/flash_stm32.c | 208 ------- platforms/chibios/flash_stm32.h | 44 -- platforms/test/rules.mk | 5 +- 15 files changed, 1624 insertions(+), 1623 deletions(-) create mode 100644 platforms/chibios/drivers/eeprom/eeprom_stm32.c create mode 100644 platforms/chibios/drivers/eeprom/eeprom_stm32.h create mode 100644 platforms/chibios/drivers/eeprom/eeprom_stm32_defs.h create mode 100644 platforms/chibios/drivers/eeprom/eeprom_teensy.c create mode 100755 platforms/chibios/drivers/eeprom/eeprom_teensy.h create mode 100644 platforms/chibios/drivers/flash/flash_stm32.c create mode 100644 platforms/chibios/drivers/flash/flash_stm32.h delete mode 100644 platforms/chibios/eeprom_stm32.c delete mode 100644 platforms/chibios/eeprom_stm32.h delete mode 100644 platforms/chibios/eeprom_stm32_defs.h delete mode 100644 platforms/chibios/eeprom_teensy.c delete mode 100755 platforms/chibios/eeprom_teensy.h delete mode 100644 platforms/chibios/flash_stm32.c delete mode 100644 platforms/chibios/flash_stm32.h (limited to 'platforms') diff --git a/platforms/chibios/drivers/eeprom/eeprom_stm32.c b/platforms/chibios/drivers/eeprom/eeprom_stm32.c new file mode 100644 index 0000000000..a15bfe09ed --- /dev/null +++ b/platforms/chibios/drivers/eeprom/eeprom_stm32.c @@ -0,0 +1,629 @@ +/* + * This software is experimental and a work in progress. + * Under no circumstances should these files be used in relation to any critical system(s). + * Use of these files is at your own risk. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * This files are free to use from http://engsta.com/stm32-flash-memory-eeprom-emulator/ by + * Artur F. + * + * Modifications for QMK and STM32F303 by Yiancar + * Modifications to add flash wear leveling by Ilya Zhuravlev + * Modifications to increase flash density by Don Kjer + */ + +#include +#include +#include "util.h" +#include "debug.h" +#include "eeprom_stm32.h" +#include "flash_stm32.h" + +/* + * We emulate eeprom by writing a snapshot compacted view of eeprom contents, + * followed by a write log of any change since that snapshot: + * + * === SIMULATED EEPROM CONTENTS === + * + * ┌─ Compacted ┬ Write Log ─┐ + * │............│[BYTE][BYTE]│ + * │FFFF....FFFF│[WRD0][WRD1]│ + * │FFFFFFFFFFFF│[WORD][NEXT]│ + * │....FFFFFFFF│[BYTE][WRD0]│ + * ├────────────┼────────────┤ + * └──PAGE_BASE │ │ + * PAGE_LAST─┴─WRITE_BASE │ + * WRITE_LAST ┘ + * + * Compacted contents are the 1's complement of the actual EEPROM contents. + * e.g. An 'FFFF' represents a '0000' value. + * + * The size of the 'compacted' area is equal to the size of the 'emulated' eeprom. + * The size of the compacted-area and write log are configurable, and the combined + * size of Compacted + WriteLog is a multiple FEE_PAGE_SIZE, which is MCU dependent. + * Simulated Eeprom contents are located at the end of available flash space. + * + * The following configuration defines can be set: + * + * FEE_PAGE_COUNT # Total number of pages to use for eeprom simulation (Compact + Write log) + * FEE_DENSITY_BYTES # Size of simulated eeprom. (Defaults to half the space allocated by FEE_PAGE_COUNT) + * NOTE: The current implementation does not include page swapping, + * and FEE_DENSITY_BYTES will consume that amount of RAM as a cached view of actual EEPROM contents. + * + * The maximum size of FEE_DENSITY_BYTES is currently 16384. The write log size equals + * FEE_PAGE_COUNT * FEE_PAGE_SIZE - FEE_DENSITY_BYTES. + * The larger the write log, the less frequently the compacted area needs to be rewritten. + * + * + * *** General Algorithm *** + * + * During initialization: + * The contents of the Compacted-flash area are loaded and the 1's complement value + * is cached into memory (e.g. 0xFFFF in Flash represents 0x0000 in cache). + * Write log entries are processed until a 0xFFFF is reached. + * Each log entry updates a byte or word in the cache. + * + * During reads: + * EEPROM contents are given back directly from the cache in memory. + * + * During writes: + * The contents of the cache is updated first. + * 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 + * Otherwise: + * 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. + * Otherwise a Write log entry is constructed and appended to the next free position in the Write log. + * + * + * *** Write Log Structure *** + * + * Write log entries allow for optimized byte writes to addresses below 128. Writing 0 or 1 words are also optimized when word-aligned. + * + * === WRITE LOG ENTRY FORMATS === + * + * ╔═══ Byte-Entry ══╗ + * ║0XXXXXXX║YYYYYYYY║ + * ║ └──┬──┘║└──┬───┘║ + * ║ Address║ Value ║ + * ╚════════╩════════╝ + * 0 <= Address < 0x80 (128) + * + * ╔ Word-Encoded 0 ╗ + * ║100XXXXXXXXXXXXX║ + * ║ │└─────┬─────┘║ + * ║ │Address >> 1 ║ + * ║ └── Value: 0 ║ + * ╚════════════════╝ + * 0 <= Address <= 0x3FFE (16382) + * + * ╔ Word-Encoded 1 ╗ + * ║101XXXXXXXXXXXXX║ + * ║ │└─────┬─────┘║ + * ║ │Address >> 1 ║ + * ║ └── Value: 1 ║ + * ╚════════════════╝ + * 0 <= Address <= 0x3FFE (16382) + * + * ╔═══ Reserved ═══╗ + * ║110XXXXXXXXXXXXX║ + * ╚════════════════╝ + * + * ╔═══════════ Word-Next ═══════════╗ + * ║111XXXXXXXXXXXXX║YYYYYYYYYYYYYYYY║ + * ║ └─────┬─────┘║└───────┬──────┘║ + * ║(Address-128)>>1║ ~Value ║ + * ╚════════════════╩════════════════╝ + * ( 0 <= Address < 0x0080 (128): Reserved) + * 0x80 <= Address <= 0x3FFE (16382) + * + * Write Log entry ranges: + * 0x0000 ... 0x7FFF - Byte-Entry; address is (Entry & 0x7F00) >> 4; value is (Entry & 0xFF) + * 0x8000 ... 0x9FFF - Word-Encoded 0; address is (Entry & 0x1FFF) << 1; value is 0 + * 0xA000 ... 0xBFFF - Word-Encoded 1; address is (Entry & 0x1FFF) << 1; value is 1 + * 0xC000 ... 0xDFFF - Reserved + * 0xE000 ... 0xFFBF - Word-Next; address is (Entry & 0x1FFF) << 1 + 0x80; value is ~(Next_Entry) + * 0xFFC0 ... 0xFFFE - Reserved + * 0xFFFF - Unprogrammed + * + */ + +#include "eeprom_stm32_defs.h" +/* These bits are used for optimizing encoding of bytes, 0 and 1 */ +#define FEE_WORD_ENCODING 0x8000 +#define FEE_VALUE_NEXT 0x6000 +#define FEE_VALUE_RESERVED 0x4000 +#define FEE_VALUE_ENCODED 0x2000 +#define FEE_BYTE_RANGE 0x80 + +/* Flash word value after erase */ +#define FEE_EMPTY_WORD ((uint16_t)0xFFFF) + +#if !defined(FEE_PAGE_SIZE) || !defined(FEE_PAGE_COUNT) || !defined(FEE_MCU_FLASH_SIZE) || !defined(FEE_PAGE_BASE_ADDRESS) +# error "not implemented." +#endif + +/* In-memory contents of emulated eeprom for faster access */ +/* *TODO: Implement page swapping */ +static uint16_t WordBuf[FEE_DENSITY_BYTES / 2]; +static uint8_t *DataBuf = (uint8_t *)WordBuf; + +/* Pointer to the first available slot within the write log */ +static uint16_t *empty_slot; + +// #define DEBUG_EEPROM_OUTPUT + +/* + * Debug print utils + */ + +#if defined(DEBUG_EEPROM_OUTPUT) + +# define debug_eeprom debug_enable +# define eeprom_println(s) println(s) +# define eeprom_printf(fmt, ...) xprintf(fmt, ##__VA_ARGS__); + +#else /* NO_DEBUG */ + +# define debug_eeprom false +# define eeprom_println(s) +# define eeprom_printf(fmt, ...) + +#endif /* NO_DEBUG */ + +void print_eeprom(void) { +#ifndef NO_DEBUG + int empty_rows = 0; + for (uint16_t i = 0; i < FEE_DENSITY_BYTES; i++) { + if (i % 16 == 0) { + if (i >= FEE_DENSITY_BYTES - 16) { + /* Make sure we display the last row */ + empty_rows = 0; + } + /* Check if this row is uninitialized */ + ++empty_rows; + for (uint16_t j = 0; j < 16; j++) { + if (DataBuf[i + j]) { + empty_rows = 0; + break; + } + } + if (empty_rows > 1) { + /* Repeat empty row */ + if (empty_rows == 2) { + /* Only display the first repeat empty row */ + println("*"); + } + i += 15; + continue; + } + xprintf("%04x", i); + } + if (i % 8 == 0) print(" "); + + xprintf(" %02x", DataBuf[i]); + if ((i + 1) % 16 == 0) { + println(""); + } + } +#endif +} + +uint16_t EEPROM_Init(void) { + /* Load emulated eeprom contents from compacted flash into memory */ + uint16_t *src = (uint16_t *)FEE_COMPACTED_BASE_ADDRESS; + uint16_t *dest = (uint16_t *)DataBuf; + for (; src < (uint16_t *)FEE_COMPACTED_LAST_ADDRESS; ++src, ++dest) { + *dest = ~*src; + } + + if (debug_eeprom) { + println("EEPROM_Init Compacted Pages:"); + print_eeprom(); + println("EEPROM_Init Write Log:"); + } + + /* Replay write log */ + uint16_t *log_addr; + for (log_addr = (uint16_t *)FEE_WRITE_LOG_BASE_ADDRESS; log_addr < (uint16_t *)FEE_WRITE_LOG_LAST_ADDRESS; ++log_addr) { + uint16_t address = *log_addr; + if (address == FEE_EMPTY_WORD) { + break; + } + /* Check for lowest 128-bytes optimization */ + if (!(address & FEE_WORD_ENCODING)) { + uint8_t bvalue = (uint8_t)address; + address >>= 8; + DataBuf[address] = bvalue; + eeprom_printf("DataBuf[0x%02x] = 0x%02x;\n", address, bvalue); + } else { + uint16_t wvalue; + /* Check if value is in next word */ + if ((address & FEE_VALUE_NEXT) == FEE_VALUE_NEXT) { + /* Read value from next word */ + if (++log_addr >= (uint16_t *)FEE_WRITE_LOG_LAST_ADDRESS) { + break; + } + wvalue = ~*log_addr; + if (!wvalue) { + eeprom_printf("Incomplete write at log_addr: 0x%04x;\n", (uint32_t)log_addr); + /* Possibly incomplete write. Ignore and continue */ + continue; + } + address &= 0x1FFF; + address <<= 1; + /* Writes to addresses less than 128 are byte log entries */ + address += FEE_BYTE_RANGE; + } else { + /* Reserved for future use */ + if (address & FEE_VALUE_RESERVED) { + eeprom_printf("Reserved encoded value at log_addr: 0x%04x;\n", (uint32_t)log_addr); + continue; + } + /* Optimization for 0 or 1 values. */ + wvalue = (address & FEE_VALUE_ENCODED) >> 13; + address &= 0x1FFF; + address <<= 1; + } + if (address < FEE_DENSITY_BYTES) { + eeprom_printf("DataBuf[0x%04x] = 0x%04x;\n", address, wvalue); + *(uint16_t *)(&DataBuf[address]) = wvalue; + } else { + eeprom_printf("DataBuf[0x%04x] cannot be set to 0x%04x [BAD ADDRESS]\n", address, wvalue); + } + } + } + + empty_slot = log_addr; + + if (debug_eeprom) { + println("EEPROM_Init Final DataBuf:"); + print_eeprom(); + } + + return FEE_DENSITY_BYTES; +} + +/* Clear flash contents (doesn't touch in-memory DataBuf) */ +static void eeprom_clear(void) { + FLASH_Unlock(); + + for (uint16_t page_num = 0; page_num < FEE_PAGE_COUNT; ++page_num) { + eeprom_printf("FLASH_ErasePage(0x%04x)\n", (uint32_t)(FEE_PAGE_BASE_ADDRESS + (page_num * FEE_PAGE_SIZE))); + FLASH_ErasePage(FEE_PAGE_BASE_ADDRESS + (page_num * FEE_PAGE_SIZE)); + } + + FLASH_Lock(); + + empty_slot = (uint16_t *)FEE_WRITE_LOG_BASE_ADDRESS; + eeprom_printf("eeprom_clear empty_slot: 0x%08x\n", (uint32_t)empty_slot); +} + +/* Erase emulated eeprom */ +void EEPROM_Erase(void) { + eeprom_println("EEPROM_Erase"); + /* Erase compacted pages and write log */ + eeprom_clear(); + /* re-initialize to reset DataBuf */ + EEPROM_Init(); +} + +/* Compact write log */ +static uint8_t eeprom_compact(void) { + /* Erase compacted pages and write log */ + eeprom_clear(); + + FLASH_Unlock(); + + FLASH_Status final_status = FLASH_COMPLETE; + + /* Write emulated eeprom contents from memory to compacted flash */ + uint16_t *src = (uint16_t *)DataBuf; + uintptr_t dest = FEE_COMPACTED_BASE_ADDRESS; + uint16_t value; + for (; dest < FEE_COMPACTED_LAST_ADDRESS; ++src, dest += 2) { + value = *src; + if (value) { + eeprom_printf("FLASH_ProgramHalfWord(0x%04x, 0x%04x)\n", (uint32_t)dest, ~value); + FLASH_Status status = FLASH_ProgramHalfWord(dest, ~value); + if (status != FLASH_COMPLETE) final_status = status; + } + } + + FLASH_Lock(); + + if (debug_eeprom) { + println("eeprom_compacted:"); + print_eeprom(); + } + + return final_status; +} + +static uint8_t eeprom_write_direct_entry(uint16_t Address) { + /* Check if we can just write this directly to the compacted flash area */ + uintptr_t directAddress = FEE_COMPACTED_BASE_ADDRESS + (Address & 0xFFFE); + if (*(uint16_t *)directAddress == FEE_EMPTY_WORD) { + /* Write the value directly to the compacted area without a log entry */ + uint16_t value = ~*(uint16_t *)(&DataBuf[Address & 0xFFFE]); + /* Early exit if a write isn't needed */ + if (value == FEE_EMPTY_WORD) return FLASH_COMPLETE; + + FLASH_Unlock(); + + eeprom_printf("FLASH_ProgramHalfWord(0x%08x, 0x%04x) [DIRECT]\n", (uint32_t)directAddress, value); + FLASH_Status status = FLASH_ProgramHalfWord(directAddress, value); + + FLASH_Lock(); + return status; + } + return 0; +} + +static uint8_t eeprom_write_log_word_entry(uint16_t Address) { + FLASH_Status final_status = FLASH_COMPLETE; + + uint16_t value = *(uint16_t *)(&DataBuf[Address]); + eeprom_printf("eeprom_write_log_word_entry(0x%04x): 0x%04x\n", Address, value); + + /* MSB signifies the lowest 128-byte optimization is not in effect */ + uint16_t encoding = FEE_WORD_ENCODING; + uint8_t entry_size; + if (value <= 1) { + encoding |= value << 13; + entry_size = 2; + } else { + encoding |= FEE_VALUE_NEXT; + entry_size = 4; + /* Writes to addresses less than 128 are byte log entries */ + Address -= FEE_BYTE_RANGE; + } + + /* if we can't find an empty spot, we must compact emulated eeprom */ + if (empty_slot > (uint16_t *)(FEE_WRITE_LOG_LAST_ADDRESS - entry_size)) { + /* compact the write log into the compacted flash area */ + return eeprom_compact(); + } + + /* Word log writes should be word-aligned. Take back a bit */ + Address >>= 1; + Address |= encoding; + + /* ok we found a place let's write our data */ + FLASH_Unlock(); + + /* address */ + eeprom_printf("FLASH_ProgramHalfWord(0x%08x, 0x%04x)\n", (uint32_t)empty_slot, Address); + final_status = FLASH_ProgramHalfWord((uintptr_t)empty_slot++, Address); + + /* value */ + if (encoding == (FEE_WORD_ENCODING | FEE_VALUE_NEXT)) { + eeprom_printf("FLASH_ProgramHalfWord(0x%08x, 0x%04x)\n", (uint32_t)empty_slot, ~value); + FLASH_Status status = FLASH_ProgramHalfWord((uintptr_t)empty_slot++, ~value); + if (status != FLASH_COMPLETE) final_status = status; + } + + FLASH_Lock(); + + return final_status; +} + +static uint8_t eeprom_write_log_byte_entry(uint16_t Address) { + eeprom_printf("eeprom_write_log_byte_entry(0x%04x): 0x%02x\n", Address, DataBuf[Address]); + + /* if couldn't find an empty spot, we must compact emulated eeprom */ + if (empty_slot >= (uint16_t *)FEE_WRITE_LOG_LAST_ADDRESS) { + /* compact the write log into the compacted flash area */ + return eeprom_compact(); + } + + /* ok we found a place let's write our data */ + FLASH_Unlock(); + + /* Pack address and value into the same word */ + uint16_t value = (Address << 8) | DataBuf[Address]; + + /* write to flash */ + eeprom_printf("FLASH_ProgramHalfWord(0x%08x, 0x%04x)\n", (uint32_t)empty_slot, value); + FLASH_Status status = FLASH_ProgramHalfWord((uintptr_t)empty_slot++, value); + + FLASH_Lock(); + + return status; +} + +uint8_t EEPROM_WriteDataByte(uint16_t Address, uint8_t DataByte) { + /* if the address is out-of-bounds, do nothing */ + if (Address >= FEE_DENSITY_BYTES) { + eeprom_printf("EEPROM_WriteDataByte(0x%04x, 0x%02x) [BAD ADDRESS]\n", Address, DataByte); + return FLASH_BAD_ADDRESS; + } + + /* if the value is the same, don't bother writing it */ + if (DataBuf[Address] == DataByte) { + eeprom_printf("EEPROM_WriteDataByte(0x%04x, 0x%02x) [SKIP SAME]\n", Address, DataByte); + return 0; + } + + /* keep DataBuf cache in sync */ + DataBuf[Address] = DataByte; + eeprom_printf("EEPROM_WriteDataByte DataBuf[0x%04x] = 0x%02x\n", Address, DataBuf[Address]); + + /* perform the write into flash memory */ + /* First, attempt to write directly into the compacted flash area */ + FLASH_Status status = eeprom_write_direct_entry(Address); + if (!status) { + /* Otherwise append to the write log */ + if (Address < FEE_BYTE_RANGE) { + status = eeprom_write_log_byte_entry(Address); + } else { + status = eeprom_write_log_word_entry(Address & 0xFFFE); + } + } + if (status != 0 && status != FLASH_COMPLETE) { + eeprom_printf("EEPROM_WriteDataByte [STATUS == %d]\n", status); + } + return status; +} + +uint8_t EEPROM_WriteDataWord(uint16_t Address, uint16_t DataWord) { + /* if the address is out-of-bounds, do nothing */ + if (Address >= FEE_DENSITY_BYTES) { + eeprom_printf("EEPROM_WriteDataWord(0x%04x, 0x%04x) [BAD ADDRESS]\n", Address, DataWord); + return FLASH_BAD_ADDRESS; + } + + /* Check for word alignment */ + FLASH_Status final_status = FLASH_COMPLETE; + if (Address % 2) { + final_status = EEPROM_WriteDataByte(Address, DataWord); + FLASH_Status status = EEPROM_WriteDataByte(Address + 1, DataWord >> 8); + if (status != FLASH_COMPLETE) final_status = status; + if (final_status != 0 && final_status != FLASH_COMPLETE) { + eeprom_printf("EEPROM_WriteDataWord [STATUS == %d]\n", final_status); + } + return final_status; + } + + /* if the value is the same, don't bother writing it */ + uint16_t oldValue = *(uint16_t *)(&DataBuf[Address]); + if (oldValue == DataWord) { + eeprom_printf("EEPROM_WriteDataWord(0x%04x, 0x%04x) [SKIP SAME]\n", Address, DataWord); + return 0; + } + + /* keep DataBuf cache in sync */ + *(uint16_t *)(&DataBuf[Address]) = DataWord; + eeprom_printf("EEPROM_WriteDataWord DataBuf[0x%04x] = 0x%04x\n", Address, *(uint16_t *)(&DataBuf[Address])); + + /* perform the write into flash memory */ + /* First, attempt to write directly into the compacted flash area */ + final_status = eeprom_write_direct_entry(Address); + if (!final_status) { + /* Otherwise append to the write log */ + /* Check if we need to fall back to byte write */ + if (Address < FEE_BYTE_RANGE) { + final_status = FLASH_COMPLETE; + /* Only write a byte if it has changed */ + if ((uint8_t)oldValue != (uint8_t)DataWord) { + final_status = eeprom_write_log_byte_entry(Address); + } + FLASH_Status status = FLASH_COMPLETE; + /* Only write a byte if it has changed */ + if ((oldValue >> 8) != (DataWord >> 8)) { + status = eeprom_write_log_byte_entry(Address + 1); + } + if (status != FLASH_COMPLETE) final_status = status; + } else { + final_status = eeprom_write_log_word_entry(Address); + } + } + if (final_status != 0 && final_status != FLASH_COMPLETE) { + eeprom_printf("EEPROM_WriteDataWord [STATUS == %d]\n", final_status); + } + return final_status; +} + +uint8_t EEPROM_ReadDataByte(uint16_t Address) { + uint8_t DataByte = 0xFF; + + if (Address < FEE_DENSITY_BYTES) { + DataByte = DataBuf[Address]; + } + + eeprom_printf("EEPROM_ReadDataByte(0x%04x): 0x%02x\n", Address, DataByte); + + return DataByte; +} + +uint16_t EEPROM_ReadDataWord(uint16_t Address) { + uint16_t DataWord = 0xFFFF; + + if (Address < FEE_DENSITY_BYTES - 1) { + /* Check word alignment */ + if (Address % 2) { + DataWord = DataBuf[Address] | (DataBuf[Address + 1] << 8); + } else { + DataWord = *(uint16_t *)(&DataBuf[Address]); + } + } + + eeprom_printf("EEPROM_ReadDataWord(0x%04x): 0x%04x\n", Address, DataWord); + + return DataWord; +} + +/***************************************************************************** + * Bind to eeprom_driver.c + *******************************************************************************/ +void eeprom_driver_init(void) { + EEPROM_Init(); +} + +void eeprom_driver_erase(void) { + EEPROM_Erase(); +} + +void eeprom_read_block(void *buf, const void *addr, size_t len) { + const uint8_t *src = (const uint8_t *)addr; + uint8_t * dest = (uint8_t *)buf; + + /* Check word alignment */ + if (len && (uintptr_t)src % 2) { + /* Read the unaligned first byte */ + *dest++ = EEPROM_ReadDataByte((const uintptr_t)src++); + --len; + } + + uint16_t value; + bool aligned = ((uintptr_t)dest % 2 == 0); + while (len > 1) { + value = EEPROM_ReadDataWord((const uintptr_t)((uint16_t *)src)); + if (aligned) { + *(uint16_t *)dest = value; + dest += 2; + } else { + *dest++ = value; + *dest++ = value >> 8; + } + src += 2; + len -= 2; + } + if (len) { + *dest = EEPROM_ReadDataByte((const uintptr_t)src); + } +} + +void eeprom_write_block(const void *buf, void *addr, size_t len) { + uint8_t * dest = (uint8_t *)addr; + const uint8_t *src = (const uint8_t *)buf; + + /* Check word alignment */ + if (len && (uintptr_t)dest % 2) { + /* Write the unaligned first byte */ + EEPROM_WriteDataByte((uintptr_t)dest++, *src++); + --len; + } + + uint16_t value; + bool aligned = ((uintptr_t)src % 2 == 0); + while (len > 1) { + if (aligned) { + value = *(uint16_t *)src; + } else { + value = *(uint8_t *)src | (*(uint8_t *)(src + 1) << 8); + } + EEPROM_WriteDataWord((uintptr_t)((uint16_t *)dest), value); + dest += 2; + src += 2; + len -= 2; + } + + if (len) { + EEPROM_WriteDataByte((uintptr_t)dest, *src); + } +} diff --git a/platforms/chibios/drivers/eeprom/eeprom_stm32.h b/platforms/chibios/drivers/eeprom/eeprom_stm32.h new file mode 100644 index 0000000000..8fcfb556b8 --- /dev/null +++ b/platforms/chibios/drivers/eeprom/eeprom_stm32.h @@ -0,0 +1,33 @@ +/* + * This software is experimental and a work in progress. + * Under no circumstances should these files be used in relation to any critical system(s). + * Use of these files is at your own risk. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * This files are free to use from http://engsta.com/stm32-flash-memory-eeprom-emulator/ by + * Artur F. + * + * Modifications for QMK and STM32F303 by Yiancar + * + * This library assumes 8-bit data locations. To add a new MCU, please provide the flash + * page size and the total flash size in Kb. The number of available pages must be a multiple + * of 2. Only half of the pages account for the total EEPROM size. + * This library also assumes that the pages are not used by the firmware. + */ + +#pragma once + +uint16_t EEPROM_Init(void); +void EEPROM_Erase(void); +uint8_t EEPROM_WriteDataByte(uint16_t Address, uint8_t DataByte); +uint8_t EEPROM_WriteDataWord(uint16_t Address, uint16_t DataWord); +uint8_t EEPROM_ReadDataByte(uint16_t Address); +uint16_t EEPROM_ReadDataWord(uint16_t Address); + +void print_eeprom(void); diff --git a/platforms/chibios/drivers/eeprom/eeprom_stm32_defs.h b/platforms/chibios/drivers/eeprom/eeprom_stm32_defs.h new file mode 100644 index 0000000000..57d0440330 --- /dev/null +++ b/platforms/chibios/drivers/eeprom/eeprom_stm32_defs.h @@ -0,0 +1,136 @@ +/* Copyright 2021 QMK + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +#include + +#if !defined(FEE_PAGE_SIZE) || !defined(FEE_PAGE_COUNT) +# if defined(STM32F103xB) || defined(STM32F042x6) || defined(GD32VF103C8) || defined(GD32VF103CB) +# ifndef FEE_PAGE_SIZE +# define FEE_PAGE_SIZE 0x400 // Page size = 1KByte +# endif +# ifndef FEE_PAGE_COUNT +# define FEE_PAGE_COUNT 2 // How many pages are used +# endif +# elif defined(STM32F103xE) || defined(STM32F303xC) || defined(STM32F303xE) || defined(STM32F072xB) || defined(STM32F070xB) +# ifndef FEE_PAGE_SIZE +# define FEE_PAGE_SIZE 0x800 // Page size = 2KByte +# endif +# ifndef FEE_PAGE_COUNT +# define FEE_PAGE_COUNT 4 // How many pages are used +# endif +# elif defined(STM32F401xC) || defined(STM32F401xE) || defined(STM32F405xG) || defined(STM32F411xE) +# ifndef FEE_PAGE_SIZE +# define FEE_PAGE_SIZE 0x4000 // Page size = 16KByte +# endif +# ifndef FEE_PAGE_COUNT +# define FEE_PAGE_COUNT 1 // How many pages are used +# endif +# endif +#endif + +#if !defined(FEE_MCU_FLASH_SIZE) +# if defined(STM32F042x6) +# define FEE_MCU_FLASH_SIZE 32 // Size in Kb +# elif defined(GD32VF103C8) +# define FEE_MCU_FLASH_SIZE 64 // Size in Kb +# elif defined(STM32F103xB) || defined(STM32F072xB) || defined(STM32F070xB) || defined(GD32VF103CB) +# define FEE_MCU_FLASH_SIZE 128 // Size in Kb +# elif defined(STM32F303xC) || defined(STM32F401xC) +# define FEE_MCU_FLASH_SIZE 256 // Size in Kb +# elif defined(STM32F103xE) || defined(STM32F303xE) || defined(STM32F401xE) || defined(STM32F411xE) +# define FEE_MCU_FLASH_SIZE 512 // Size in Kb +# elif defined(STM32F405xG) +# define FEE_MCU_FLASH_SIZE 1024 // Size in Kb +# endif +#endif + +/* Start of the emulated eeprom */ +#if !defined(FEE_PAGE_BASE_ADDRESS) +# if defined(STM32F401xC) || defined(STM32F401xE) || defined(STM32F405xG) || defined(STM32F411xE) +# ifndef FEE_PAGE_BASE_ADDRESS +# define FEE_PAGE_BASE_ADDRESS 0x08004000 // bodge to force 2nd 16k page +# endif +# else +# ifndef FEE_FLASH_BASE +# define FEE_FLASH_BASE 0x8000000 +# endif +/* Default to end of flash */ +# define FEE_PAGE_BASE_ADDRESS ((uintptr_t)(FEE_FLASH_BASE) + FEE_MCU_FLASH_SIZE * 1024 - (FEE_PAGE_COUNT * FEE_PAGE_SIZE)) +# endif +#endif + +/* Addressable range 16KByte: 0 <-> (0x1FFF << 1) */ +#define FEE_ADDRESS_MAX_SIZE 0x4000 + +/* Size of combined compacted eeprom and write log pages */ +#define FEE_DENSITY_MAX_SIZE (FEE_PAGE_COUNT * FEE_PAGE_SIZE) + +#ifndef FEE_MCU_FLASH_SIZE_IGNORE_CHECK /* *TODO: Get rid of this check */ +# if FEE_DENSITY_MAX_SIZE > (FEE_MCU_FLASH_SIZE * 1024) +# pragma message STR(FEE_DENSITY_MAX_SIZE) " > " STR(FEE_MCU_FLASH_SIZE * 1024) +# error emulated eeprom: FEE_DENSITY_MAX_SIZE is greater than available flash size +# endif +#endif + +/* Size of emulated eeprom */ +#ifdef FEE_DENSITY_BYTES +# if (FEE_DENSITY_BYTES > FEE_DENSITY_MAX_SIZE) +# pragma message STR(FEE_DENSITY_BYTES) " > " STR(FEE_DENSITY_MAX_SIZE) +# error emulated eeprom: FEE_DENSITY_BYTES exceeds FEE_DENSITY_MAX_SIZE +# endif +# if (FEE_DENSITY_BYTES == FEE_DENSITY_MAX_SIZE) +# pragma message STR(FEE_DENSITY_BYTES) " == " STR(FEE_DENSITY_MAX_SIZE) +# warning emulated eeprom: FEE_DENSITY_BYTES leaves no room for a write log. This will greatly increase the flash wear rate! +# endif +# if FEE_DENSITY_BYTES > FEE_ADDRESS_MAX_SIZE +# pragma message STR(FEE_DENSITY_BYTES) " > " STR(FEE_ADDRESS_MAX_SIZE) +# error emulated eeprom: FEE_DENSITY_BYTES is greater than FEE_ADDRESS_MAX_SIZE allows +# endif +# if ((FEE_DENSITY_BYTES) % 2) == 1 +# error emulated eeprom: FEE_DENSITY_BYTES must be even +# endif +#else +/* Default to half of allocated space used for emulated eeprom, half for write log */ +# define FEE_DENSITY_BYTES (FEE_PAGE_COUNT * FEE_PAGE_SIZE / 2) +#endif + +/* Size of write log */ +#ifdef FEE_WRITE_LOG_BYTES +# if ((FEE_DENSITY_BYTES + FEE_WRITE_LOG_BYTES) > FEE_DENSITY_MAX_SIZE) +# pragma message STR(FEE_DENSITY_BYTES) " + " STR(FEE_WRITE_LOG_BYTES) " > " STR(FEE_DENSITY_MAX_SIZE) +# error emulated eeprom: FEE_WRITE_LOG_BYTES exceeds remaining FEE_DENSITY_MAX_SIZE +# endif +# if ((FEE_WRITE_LOG_BYTES) % 2) == 1 +# error emulated eeprom: FEE_WRITE_LOG_BYTES must be even +# endif +#else +/* Default to use all remaining space */ +# define FEE_WRITE_LOG_BYTES (FEE_PAGE_COUNT * FEE_PAGE_SIZE - FEE_DENSITY_BYTES) +#endif + +/* Start of the emulated eeprom compacted flash area */ +#define FEE_COMPACTED_BASE_ADDRESS FEE_PAGE_BASE_ADDRESS +/* End of the emulated eeprom compacted flash area */ +#define FEE_COMPACTED_LAST_ADDRESS (FEE_COMPACTED_BASE_ADDRESS + FEE_DENSITY_BYTES) +/* Start of the emulated eeprom write log */ +#define FEE_WRITE_LOG_BASE_ADDRESS FEE_COMPACTED_LAST_ADDRESS +/* End of the emulated eeprom write log */ +#define FEE_WRITE_LOG_LAST_ADDRESS (FEE_WRITE_LOG_BASE_ADDRESS + FEE_WRITE_LOG_BYTES) + +#if defined(DYNAMIC_KEYMAP_EEPROM_MAX_ADDR) && (DYNAMIC_KEYMAP_EEPROM_MAX_ADDR >= FEE_DENSITY_BYTES) +# error emulated eeprom: DYNAMIC_KEYMAP_EEPROM_MAX_ADDR is greater than the FEE_DENSITY_BYTES available +#endif diff --git a/platforms/chibios/drivers/eeprom/eeprom_teensy.c b/platforms/chibios/drivers/eeprom/eeprom_teensy.c new file mode 100644 index 0000000000..c8777febde --- /dev/null +++ b/platforms/chibios/drivers/eeprom/eeprom_teensy.c @@ -0,0 +1,546 @@ +#include +#include + +#include "eeprom_teensy.h" +#include "eeconfig.h" + +/*************************************/ +/* Hardware backend */ +/* */ +/* Code from PJRC/Teensyduino */ +/*************************************/ + +/* Teensyduino Core Library + * http://www.pjrc.com/teensy/ + * Copyright (c) 2013 PJRC.COM, LLC. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * 1. The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 2. If the Software is incorporated into a build system that allows + * selection among a list of target devices, then similar target + * devices manufactured by PJRC.COM must be included in the list of + * target devices and selectable in the same manner. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if defined(K20x) /* chip selection */ +/* Teensy 3.0, 3.1, 3.2; mchck; infinity keyboard */ + +/* + ^^^ Here be dragons: + NXP AppNote AN4282 section 3.1 states that partitioning must only be done once. + Once EEPROM partitioning is done, the size is locked to this initial configuration. + Attempts to modify the EEPROM_SIZE setting may brick your board. +*/ + +// Writing unaligned 16 or 32 bit data is handled automatically when +// this is defined, but at a cost of extra code size. Without this, +// any unaligned write will cause a hard fault exception! If you're +// absolutely sure all 16 and 32 bit writes will be aligned, you can +// remove the extra unnecessary code. +// +# define HANDLE_UNALIGNED_WRITES + +// Minimum EEPROM Endurance +// ------------------------ +# if (EEPROM_SIZE == 2048) // 35000 writes/byte or 70000 writes/word +# define EEESIZE 0x33 +# elif (EEPROM_SIZE == 1024) // 75000 writes/byte or 150000 writes/word +# define EEESIZE 0x34 +# elif (EEPROM_SIZE == 512) // 155000 writes/byte or 310000 writes/word +# define EEESIZE 0x35 +# elif (EEPROM_SIZE == 256) // 315000 writes/byte or 630000 writes/word +# define EEESIZE 0x36 +# elif (EEPROM_SIZE == 128) // 635000 writes/byte or 1270000 writes/word +# define EEESIZE 0x37 +# elif (EEPROM_SIZE == 64) // 1275000 writes/byte or 2550000 writes/word +# define EEESIZE 0x38 +# elif (EEPROM_SIZE == 32) // 2555000 writes/byte or 5110000 writes/word +# define EEESIZE 0x39 +# endif + +/** \brief eeprom initialization + * + * FIXME: needs doc + */ +void eeprom_initialize(void) { + uint32_t count = 0; + uint16_t do_flash_cmd[] = {0xf06f, 0x037f, 0x7003, 0x7803, 0xf013, 0x0f80, 0xd0fb, 0x4770}; + uint8_t status; + + if (FTFL->FCNFG & FTFL_FCNFG_RAMRDY) { + // FlexRAM is configured as traditional RAM + // We need to reconfigure for EEPROM usage + FTFL->FCCOB0 = 0x80; // PGMPART = Program Partition Command + FTFL->FCCOB4 = EEESIZE; // EEPROM Size + FTFL->FCCOB5 = 0x03; // 0K for Dataflash, 32K for EEPROM backup + __disable_irq(); + // do_flash_cmd() must execute from RAM. Luckily the C syntax is simple... + (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&(FTFL->FSTAT)); + __enable_irq(); + status = FTFL->FSTAT; + if (status & (FTFL_FSTAT_RDCOLERR | FTFL_FSTAT_ACCERR | FTFL_FSTAT_FPVIOL)) { + FTFL->FSTAT = (status & (FTFL_FSTAT_RDCOLERR | FTFL_FSTAT_ACCERR | FTFL_FSTAT_FPVIOL)); + return; // error + } + } + // wait for eeprom to become ready (is this really necessary?) + while (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) { + if (++count > 20000) break; + } +} + +# define FlexRAM ((uint8_t *)0x14000000) + +/** \brief eeprom read byte + * + * FIXME: needs doc + */ +uint8_t eeprom_read_byte(const uint8_t *addr) { + uint32_t offset = (uint32_t)addr; + if (offset >= EEPROM_SIZE) return 0; + if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize(); + return FlexRAM[offset]; +} + +/** \brief eeprom read word + * + * FIXME: needs doc + */ +uint16_t eeprom_read_word(const uint16_t *addr) { + uint32_t offset = (uint32_t)addr; + if (offset >= EEPROM_SIZE - 1) return 0; + if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize(); + return *(uint16_t *)(&FlexRAM[offset]); +} + +/** \brief eeprom read dword + * + * FIXME: needs doc + */ +uint32_t eeprom_read_dword(const uint32_t *addr) { + uint32_t offset = (uint32_t)addr; + if (offset >= EEPROM_SIZE - 3) return 0; + if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize(); + return *(uint32_t *)(&FlexRAM[offset]); +} + +/** \brief eeprom read block + * + * FIXME: needs doc + */ +void eeprom_read_block(void *buf, const void *addr, uint32_t len) { + uint32_t offset = (uint32_t)addr; + uint8_t *dest = (uint8_t *)buf; + uint32_t end = offset + len; + + if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize(); + if (end > EEPROM_SIZE) end = EEPROM_SIZE; + while (offset < end) { + *dest++ = FlexRAM[offset++]; + } +} + +/** \brief eeprom is ready + * + * FIXME: needs doc + */ +int eeprom_is_ready(void) { + return (FTFL->FCNFG & FTFL_FCNFG_EEERDY) ? 1 : 0; +} + +/** \brief flexram wait + * + * FIXME: needs doc + */ +static void flexram_wait(void) { + while (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) { + // TODO: timeout + } +} + +/** \brief eeprom_write_byte + * + * FIXME: needs doc + */ +void eeprom_write_byte(uint8_t *addr, uint8_t value) { + uint32_t offset = (uint32_t)addr; + + if (offset >= EEPROM_SIZE) return; + if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize(); + if (FlexRAM[offset] != value) { + FlexRAM[offset] = value; + flexram_wait(); + } +} + +/** \brief eeprom write word + * + * FIXME: needs doc + */ +void eeprom_write_word(uint16_t *addr, uint16_t value) { + uint32_t offset = (uint32_t)addr; + + if (offset >= EEPROM_SIZE - 1) return; + if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize(); +# ifdef HANDLE_UNALIGNED_WRITES + if ((offset & 1) == 0) { +# endif + if (*(uint16_t *)(&FlexRAM[offset]) != value) { + *(uint16_t *)(&FlexRAM[offset]) = value; + flexram_wait(); + } +# ifdef HANDLE_UNALIGNED_WRITES + } else { + if (FlexRAM[offset] != value) { + FlexRAM[offset] = value; + flexram_wait(); + } + if (FlexRAM[offset + 1] != (value >> 8)) { + FlexRAM[offset + 1] = value >> 8; + flexram_wait(); + } + } +# endif +} + +/** \brief eeprom write dword + * + * FIXME: needs doc + */ +void eeprom_write_dword(uint32_t *addr, uint32_t value) { + uint32_t offset = (uint32_t)addr; + + if (offset >= EEPROM_SIZE - 3) return; + if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize(); +# ifdef HANDLE_UNALIGNED_WRITES + switch (offset & 3) { + case 0: +# endif + if (*(uint32_t *)(&FlexRAM[offset]) != value) { + *(uint32_t *)(&FlexRAM[offset]) = value; + flexram_wait(); + } + return; +# ifdef HANDLE_UNALIGNED_WRITES + case 2: + if (*(uint16_t *)(&FlexRAM[offset]) != value) { + *(uint16_t *)(&FlexRAM[offset]) = value; + flexram_wait(); + } + if (*(uint16_t *)(&FlexRAM[offset + 2]) != (value >> 16)) { + *(uint16_t *)(&FlexRAM[offset + 2]) = value >> 16; + flexram_wait(); + } + return; + default: + if (FlexRAM[offset] != value) { + FlexRAM[offset] = value; + flexram_wait(); + } + if (*(uint16_t *)(&FlexRAM[offset + 1]) != (value >> 8)) { + *(uint16_t *)(&FlexRAM[offset + 1]) = value >> 8; + flexram_wait(); + } + if (FlexRAM[offset + 3] != (value >> 24)) { + FlexRAM[offset + 3] = value >> 24; + flexram_wait(); + } + } +# endif +} + +/** \brief eeprom write block + * + * FIXME: needs doc + */ +void eeprom_write_block(const void *buf, void *addr, uint32_t len) { + uint32_t offset = (uint32_t)addr; + const uint8_t *src = (const uint8_t *)buf; + + if (offset >= EEPROM_SIZE) return; + if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize(); + if (len >= EEPROM_SIZE) len = EEPROM_SIZE; + if (offset + len >= EEPROM_SIZE) len = EEPROM_SIZE - offset; + while (len > 0) { + uint32_t lsb = offset & 3; + if (lsb == 0 && len >= 4) { + // write aligned 32 bits + uint32_t val32; + val32 = *src++; + val32 |= (*src++ << 8); + val32 |= (*src++ << 16); + val32 |= (*src++ << 24); + if (*(uint32_t *)(&FlexRAM[offset]) != val32) { + *(uint32_t *)(&FlexRAM[offset]) = val32; + flexram_wait(); + } + offset += 4; + len -= 4; + } else if ((lsb == 0 || lsb == 2) && len >= 2) { + // write aligned 16 bits + uint16_t val16; + val16 = *src++; + val16 |= (*src++ << 8); + if (*(uint16_t *)(&FlexRAM[offset]) != val16) { + *(uint16_t *)(&FlexRAM[offset]) = val16; + flexram_wait(); + } + offset += 2; + len -= 2; + } else { + // write 8 bits + uint8_t val8 = *src++; + if (FlexRAM[offset] != val8) { + FlexRAM[offset] = val8; + flexram_wait(); + } + offset++; + len--; + } + } +} + +/* +void do_flash_cmd(volatile uint8_t *fstat) +{ + *fstat = 0x80; + while ((*fstat & 0x80) == 0) ; // wait +} +00000000 : + 0: f06f 037f mvn.w r3, #127 ; 0x7f + 4: 7003 strb r3, [r0, #0] + 6: 7803 ldrb r3, [r0, #0] + 8: f013 0f80 tst.w r3, #128 ; 0x80 + c: d0fb beq.n 6 + e: 4770 bx lr +*/ + +#elif defined(KL2x) /* chip selection */ +/* Teensy LC (emulated) */ + +# define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0)) + +extern uint32_t __eeprom_workarea_start__; +extern uint32_t __eeprom_workarea_end__; + +static uint32_t flashend = 0; + +void eeprom_initialize(void) { + const uint16_t *p = (uint16_t *)SYMVAL(__eeprom_workarea_start__); + + do { + if (*p++ == 0xFFFF) { + flashend = (uint32_t)(p - 2); + return; + } + } while (p < (uint16_t *)SYMVAL(__eeprom_workarea_end__)); + flashend = (uint32_t)(p - 1); +} + +uint8_t eeprom_read_byte(const uint8_t *addr) { + uint32_t offset = (uint32_t)addr; + const uint16_t *p = (uint16_t *)SYMVAL(__eeprom_workarea_start__); + const uint16_t *end = (const uint16_t *)((uint32_t)flashend); + uint16_t val; + uint8_t data = 0xFF; + + if (!end) { + eeprom_initialize(); + end = (const uint16_t *)((uint32_t)flashend); + } + if (offset < EEPROM_SIZE) { + while (p <= end) { + val = *p++; + if ((val & 255) == offset) data = val >> 8; + } + } + return data; +} + +static void flash_write(const uint16_t *code, uint32_t addr, uint32_t data) { + // with great power comes great responsibility.... + uint32_t stat; + *(uint32_t *)&(FTFA->FCCOB3) = 0x06000000 | (addr & 0x00FFFFFC); + *(uint32_t *)&(FTFA->FCCOB7) = data; + __disable_irq(); + (*((void (*)(volatile uint8_t *))((uint32_t)code | 1)))(&(FTFA->FSTAT)); + __enable_irq(); + stat = FTFA->FSTAT & (FTFA_FSTAT_RDCOLERR | FTFA_FSTAT_ACCERR | FTFA_FSTAT_FPVIOL); + if (stat) { + FTFA->FSTAT = stat; + } + MCM->PLACR |= MCM_PLACR_CFCC; +} + +void eeprom_write_byte(uint8_t *addr, uint8_t data) { + uint32_t offset = (uint32_t)addr; + const uint16_t *p, *end = (const uint16_t *)((uint32_t)flashend); + uint32_t i, val, flashaddr; + uint16_t do_flash_cmd[] = {0x2380, 0x7003, 0x7803, 0xb25b, 0x2b00, 0xdafb, 0x4770}; + uint8_t buf[EEPROM_SIZE]; + + if (offset >= EEPROM_SIZE) return; + if (!end) { + eeprom_initialize(); + end = (const uint16_t *)((uint32_t)flashend); + } + if (++end < (uint16_t *)SYMVAL(__eeprom_workarea_end__)) { + val = (data << 8) | offset; + flashaddr = (uint32_t)end; + flashend = flashaddr; + if ((flashaddr & 2) == 0) { + val |= 0xFFFF0000; + } else { + val <<= 16; + val |= 0x0000FFFF; + } + flash_write(do_flash_cmd, flashaddr, val); + } else { + for (i = 0; i < EEPROM_SIZE; i++) { + buf[i] = 0xFF; + } + val = 0; + for (p = (uint16_t *)SYMVAL(__eeprom_workarea_start__); p < (uint16_t *)SYMVAL(__eeprom_workarea_end__); p++) { + val = *p; + if ((val & 255) < EEPROM_SIZE) { + buf[val & 255] = val >> 8; + } + } + buf[offset] = data; + for (flashaddr = (uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__); flashaddr < (uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_end__); flashaddr += 1024) { + *(uint32_t *)&(FTFA->FCCOB3) = 0x09000000 | flashaddr; + __disable_irq(); + (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&(FTFA->FSTAT)); + __enable_irq(); + val = FTFA->FSTAT & (FTFA_FSTAT_RDCOLERR | FTFA_FSTAT_ACCERR | FTFA_FSTAT_FPVIOL); + ; + if (val) FTFA->FSTAT = val; + MCM->PLACR |= MCM_PLACR_CFCC; + } + flashaddr = (uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__); + for (i = 0; i < EEPROM_SIZE; i++) { + if (buf[i] == 0xFF) continue; + if ((flashaddr & 2) == 0) { + val = (buf[i] << 8) | i; + } else { + val = val | (buf[i] << 24) | (i << 16); + flash_write(do_flash_cmd, flashaddr, val); + } + flashaddr += 2; + } + flashend = flashaddr; + if ((flashaddr & 2)) { + val |= 0xFFFF0000; + flash_write(do_flash_cmd, flashaddr, val); + } + } +} + +/* +void do_flash_cmd(volatile uint8_t *fstat) +{ + *fstat = 0x80; + while ((*fstat & 0x80) == 0) ; // wait +} +00000000 : + 0: 2380 movs r3, #128 ; 0x80 + 2: 7003 strb r3, [r0, #0] + 4: 7803 ldrb r3, [r0, #0] + 6: b25b sxtb r3, r3 + 8: 2b00 cmp r3, #0 + a: dafb bge.n 4 + c: 4770 bx lr +*/ + +uint16_t eeprom_read_word(const uint16_t *addr) { + const uint8_t *p = (const uint8_t *)addr; + return eeprom_read_byte(p) | (eeprom_read_byte(p + 1) << 8); +} + +uint32_t eeprom_read_dword(const uint32_t *addr) { + const uint8_t *p = (const uint8_t *)addr; + return eeprom_read_byte(p) | (eeprom_read_byte(p + 1) << 8) | (eeprom_read_byte(p + 2) << 16) | (eeprom_read_byte(p + 3) << 24); +} + +void eeprom_read_block(void *buf, const void *addr, uint32_t len) { + const uint8_t *p = (const uint8_t *)addr; + uint8_t * dest = (uint8_t *)buf; + while (len--) { + *dest++ = eeprom_read_byte(p++); + } +} + +int eeprom_is_ready(void) { + return 1; +} + +void eeprom_write_word(uint16_t *addr, uint16_t value) { + uint8_t *p = (uint8_t *)addr; + eeprom_write_byte(p++, value); + eeprom_write_byte(p, value >> 8); +} + +void eeprom_write_dword(uint32_t *addr, uint32_t value) { + uint8_t *p = (uint8_t *)addr; + eeprom_write_byte(p++, value); + eeprom_write_byte(p++, value >> 8); + eeprom_write_byte(p++, value >> 16); + eeprom_write_byte(p, value >> 24); +} + +void eeprom_write_block(const void *buf, void *addr, uint32_t len) { + uint8_t * p = (uint8_t *)addr; + const uint8_t *src = (const uint8_t *)buf; + while (len--) { + eeprom_write_byte(p++, *src++); + } +} + +#else +# error Unsupported Teensy EEPROM. +#endif /* chip selection */ +// The update functions just calls write for now, but could probably be optimized + +void eeprom_update_byte(uint8_t *addr, uint8_t value) { + eeprom_write_byte(addr, value); +} + +void eeprom_update_word(uint16_t *addr, uint16_t value) { + uint8_t *p = (uint8_t *)addr; + eeprom_write_byte(p++, value); + eeprom_write_byte(p, value >> 8); +} + +void eeprom_update_dword(uint32_t *addr, uint32_t value) { + uint8_t *p = (uint8_t *)addr; + eeprom_write_byte(p++, value); + eeprom_write_byte(p++, value >> 8); + eeprom_write_byte(p++, value >> 16); + eeprom_write_byte(p, value >> 24); +} + +void eeprom_update_block(const void *buf, void *addr, size_t len) { + uint8_t * p = (uint8_t *)addr; + const uint8_t *src = (const uint8_t *)buf; + while (len--) { + eeprom_write_byte(p++, *src++); + } +} diff --git a/platforms/chibios/drivers/eeprom/eeprom_teensy.h b/platforms/chibios/drivers/eeprom/eeprom_teensy.h new file mode 100755 index 0000000000..9a14a1fa79 --- /dev/null +++ b/platforms/chibios/drivers/eeprom/eeprom_teensy.h @@ -0,0 +1,25 @@ +// Copyright 2022 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#pragma once + +#include +#include + +#if defined(K20x) +/* Teensy 3.0, 3.1, 3.2; mchck; infinity keyboard */ +// The EEPROM is really RAM with a hardware-based backup system to +// flash memory. Selecting a smaller size EEPROM allows more wear +// leveling, for higher write endurance. If you edit this file, +// set this to the smallest size your application can use. Also, +// due to Freescale's implementation, writing 16 or 32 bit words +// (aligned to 2 or 4 byte boundaries) has twice the endurance +// compared to writing 8 bit bytes. +// +# ifndef EEPROM_SIZE +# define EEPROM_SIZE 32 +# endif +#elif defined(KL2x) /* Teensy LC (emulated) */ +# define EEPROM_SIZE 128 +#else +# error Unsupported Teensy EEPROM. +#endif diff --git a/platforms/chibios/drivers/flash/flash_stm32.c b/platforms/chibios/drivers/flash/flash_stm32.c new file mode 100644 index 0000000000..72c41b8b78 --- /dev/null +++ b/platforms/chibios/drivers/flash/flash_stm32.c @@ -0,0 +1,208 @@ +/* + * This software is experimental and a work in progress. + * Under no circumstances should these files be used in relation to any critical system(s). + * Use of these files is at your own risk. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * This files are free to use from https://github.com/rogerclarkmelbourne/Arduino_STM32 and + * https://github.com/leaflabs/libmaple + * + * Modifications for QMK and STM32F303 by Yiancar + */ + +#include +#include "flash_stm32.h" + +#if defined(STM32F1XX) +# define FLASH_SR_WRPERR FLASH_SR_WRPRTERR +#endif + +#if defined(MCU_GD32V) +/* GigaDevice GD32VF103 is a STM32F103 clone at heart. */ +# include "gd32v_compatibility.h" +#endif + +#if defined(STM32F4XX) +# define FLASH_SR_PGERR (FLASH_SR_PGSERR | FLASH_SR_PGPERR | FLASH_SR_PGAERR) + +# define FLASH_KEY1 0x45670123U +# define FLASH_KEY2 0xCDEF89ABU + +static uint8_t ADDR2PAGE(uint32_t Page_Address) { + switch (Page_Address) { + case 0x08000000 ... 0x08003FFF: + return 0; + case 0x08004000 ... 0x08007FFF: + return 1; + case 0x08008000 ... 0x0800BFFF: + return 2; + case 0x0800C000 ... 0x0800FFFF: + return 3; + } + + // TODO: bad times... + return 7; +} +#endif + +/* Delay definition */ +#define EraseTimeout ((uint32_t)0x00000FFF) +#define ProgramTimeout ((uint32_t)0x0000001F) + +#define ASSERT(exp) (void)((0)) + +/** + * @brief Inserts a time delay. + * @param None + * @retval None + */ +static void delay(void) { + __IO uint32_t i = 0; + for (i = 0xFF; i != 0; i--) { + } +} + +/** + * @brief Returns the FLASH Status. + * @param None + * @retval FLASH Status: The returned value can be: FLASH_BUSY, FLASH_ERROR_PG, + * FLASH_ERROR_WRP or FLASH_COMPLETE + */ +FLASH_Status FLASH_GetStatus(void) { + if ((FLASH->SR & FLASH_SR_BSY) == FLASH_SR_BSY) return FLASH_BUSY; + + if ((FLASH->SR & FLASH_SR_PGERR) != 0) return FLASH_ERROR_PG; + + if ((FLASH->SR & FLASH_SR_WRPERR) != 0) return FLASH_ERROR_WRP; + +#if defined(FLASH_OBR_OPTERR) + if ((FLASH->SR & FLASH_OBR_OPTERR) != 0) return FLASH_ERROR_OPT; +#endif + + return FLASH_COMPLETE; +} + +/** + * @brief Waits for a Flash operation to complete or a TIMEOUT to occur. + * @param Timeout: FLASH progamming Timeout + * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG, + * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. + */ +FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout) { + FLASH_Status status; + + /* Check for the Flash Status */ + status = FLASH_GetStatus(); + /* Wait for a Flash operation to complete or a TIMEOUT to occur */ + while ((status == FLASH_BUSY) && (Timeout != 0x00)) { + delay(); + status = FLASH_GetStatus(); + Timeout--; + } + if (Timeout == 0) status = FLASH_TIMEOUT; + /* Return the operation status */ + return status; +} + +/** + * @brief Erases a specified FLASH page. + * @param Page_Address: The page address to be erased. + * @retval FLASH Status: The returned value can be: FLASH_BUSY, FLASH_ERROR_PG, + * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. + */ +FLASH_Status FLASH_ErasePage(uint32_t Page_Address) { + FLASH_Status status = FLASH_COMPLETE; + /* Check the parameters */ + ASSERT(IS_FLASH_ADDRESS(Page_Address)); + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(EraseTimeout); + + if (status == FLASH_COMPLETE) { + /* if the previous operation is completed, proceed to erase the page */ +#if defined(FLASH_CR_SNB) + FLASH->CR &= ~FLASH_CR_SNB; + FLASH->CR |= FLASH_CR_SER | (ADDR2PAGE(Page_Address) << FLASH_CR_SNB_Pos); +#else + FLASH->CR |= FLASH_CR_PER; + FLASH->AR = Page_Address; +#endif + FLASH->CR |= FLASH_CR_STRT; + + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(EraseTimeout); + if (status != FLASH_TIMEOUT) { + /* if the erase operation is completed, disable the configured Bits */ +#if defined(FLASH_CR_SNB) + FLASH->CR &= ~(FLASH_CR_SER | FLASH_CR_SNB); +#else + FLASH->CR &= ~FLASH_CR_PER; +#endif + } + FLASH->SR = (FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPERR); + } + /* Return the Erase Status */ + return status; +} + +/** + * @brief Programs a half word at a specified address. + * @param Address: specifies the address to be programmed. + * @param Data: specifies the data to be programmed. + * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG, + * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. + */ +FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data) { + FLASH_Status status = FLASH_BAD_ADDRESS; + + if (IS_FLASH_ADDRESS(Address)) { + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(ProgramTimeout); + if (status == FLASH_COMPLETE) { + /* if the previous operation is completed, proceed to program the new data */ + +#if defined(FLASH_CR_PSIZE) + FLASH->CR &= ~FLASH_CR_PSIZE; + FLASH->CR |= FLASH_CR_PSIZE_0; +#endif + FLASH->CR |= FLASH_CR_PG; + *(__IO uint16_t*)Address = Data; + /* Wait for last operation to be completed */ + status = FLASH_WaitForLastOperation(ProgramTimeout); + if (status != FLASH_TIMEOUT) { + /* if the program operation is completed, disable the PG Bit */ + FLASH->CR &= ~FLASH_CR_PG; + } + FLASH->SR = (FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPERR); + } + } + return status; +} + +/** + * @brief Unlocks the FLASH Program Erase Controller. + * @param None + * @retval None + */ +void FLASH_Unlock(void) { + if (FLASH->CR & FLASH_CR_LOCK) { + /* Authorize the FPEC Access */ + FLASH->KEYR = FLASH_KEY1; + FLASH->KEYR = FLASH_KEY2; + } +} + +/** + * @brief Locks the FLASH Program Erase Controller. + * @param None + * @retval None + */ +void FLASH_Lock(void) { + /* Set the Lock Bit to lock the FPEC and the FCR */ + FLASH->CR |= FLASH_CR_LOCK; +} diff --git a/platforms/chibios/drivers/flash/flash_stm32.h b/platforms/chibios/drivers/flash/flash_stm32.h new file mode 100644 index 0000000000..6c66642ec5 --- /dev/null +++ b/platforms/chibios/drivers/flash/flash_stm32.h @@ -0,0 +1,44 @@ +/* + * This software is experimental and a work in progress. + * Under no circumstances should these files be used in relation to any critical system(s). + * Use of these files is at your own risk. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * This files are free to use from https://github.com/rogerclarkmelbourne/Arduino_STM32 and + * https://github.com/leaflabs/libmaple + * + * Modifications for QMK and STM32F303 by Yiancar + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifdef FLASH_STM32_MOCKED +extern uint8_t FlashBuf[MOCK_FLASH_SIZE]; +#endif + +typedef enum { FLASH_BUSY = 1, FLASH_ERROR_PG, FLASH_ERROR_WRP, FLASH_ERROR_OPT, FLASH_COMPLETE, FLASH_TIMEOUT, FLASH_BAD_ADDRESS } FLASH_Status; + +#define IS_FLASH_ADDRESS(ADDRESS) (((ADDRESS) >= 0x08000000) && ((ADDRESS) < 0x0807FFFF)) + +FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout); +FLASH_Status FLASH_ErasePage(uint32_t Page_Address); +FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data); + +void FLASH_Unlock(void); +void FLASH_Lock(void); + +#ifdef __cplusplus +} +#endif diff --git a/platforms/chibios/eeprom_stm32.c b/platforms/chibios/eeprom_stm32.c deleted file mode 100644 index a15bfe09ed..0000000000 --- a/platforms/chibios/eeprom_stm32.c +++ /dev/null @@ -1,629 +0,0 @@ -/* - * This software is experimental and a work in progress. - * Under no circumstances should these files be used in relation to any critical system(s). - * Use of these files is at your own risk. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR - * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * This files are free to use from http://engsta.com/stm32-flash-memory-eeprom-emulator/ by - * Artur F. - * - * Modifications for QMK and STM32F303 by Yiancar - * Modifications to add flash wear leveling by Ilya Zhuravlev - * Modifications to increase flash density by Don Kjer - */ - -#include -#include -#include "util.h" -#include "debug.h" -#include "eeprom_stm32.h" -#include "flash_stm32.h" - -/* - * We emulate eeprom by writing a snapshot compacted view of eeprom contents, - * followed by a write log of any change since that snapshot: - * - * === SIMULATED EEPROM CONTENTS === - * - * ┌─ Compacted ┬ Write Log ─┐ - * │............│[BYTE][BYTE]│ - * │FFFF....FFFF│[WRD0][WRD1]│ - * │FFFFFFFFFFFF│[WORD][NEXT]│ - * │....FFFFFFFF│[BYTE][WRD0]│ - * ├────────────┼────────────┤ - * └──PAGE_BASE │ │ - * PAGE_LAST─┴─WRITE_BASE │ - * WRITE_LAST ┘ - * - * Compacted contents are the 1's complement of the actual EEPROM contents. - * e.g. An 'FFFF' represents a '0000' value. - * - * The size of the 'compacted' area is equal to the size of the 'emulated' eeprom. - * The size of the compacted-area and write log are configurable, and the combined - * size of Compacted + WriteLog is a multiple FEE_PAGE_SIZE, which is MCU dependent. - * Simulated Eeprom contents are located at the end of available flash space. - * - * The following configuration defines can be set: - * - * FEE_PAGE_COUNT # Total number of pages to use for eeprom simulation (Compact + Write log) - * FEE_DENSITY_BYTES # Size of simulated eeprom. (Defaults to half the space allocated by FEE_PAGE_COUNT) - * NOTE: The current implementation does not include page swapping, - * and FEE_DENSITY_BYTES will consume that amount of RAM as a cached view of actual EEPROM contents. - * - * The maximum size of FEE_DENSITY_BYTES is currently 16384. The write log size equals - * FEE_PAGE_COUNT * FEE_PAGE_SIZE - FEE_DENSITY_BYTES. - * The larger the write log, the less frequently the compacted area needs to be rewritten. - * - * - * *** General Algorithm *** - * - * During initialization: - * The contents of the Compacted-flash area are loaded and the 1's complement value - * is cached into memory (e.g. 0xFFFF in Flash represents 0x0000 in cache). - * Write log entries are processed until a 0xFFFF is reached. - * Each log entry updates a byte or word in the cache. - * - * During reads: - * EEPROM contents are given back directly from the cache in memory. - * - * During writes: - * The contents of the cache is updated first. - * 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 - * Otherwise: - * 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. - * Otherwise a Write log entry is constructed and appended to the next free position in the Write log. - * - * - * *** Write Log Structure *** - * - * Write log entries allow for optimized byte writes to addresses below 128. Writing 0 or 1 words are also optimized when word-aligned. - * - * === WRITE LOG ENTRY FORMATS === - * - * ╔═══ Byte-Entry ══╗ - * ║0XXXXXXX║YYYYYYYY║ - * ║ └──┬──┘║└──┬───┘║ - * ║ Address║ Value ║ - * ╚════════╩════════╝ - * 0 <= Address < 0x80 (128) - * - * ╔ Word-Encoded 0 ╗ - * ║100XXXXXXXXXXXXX║ - * ║ │└─────┬─────┘║ - * ║ │Address >> 1 ║ - * ║ └── Value: 0 ║ - * ╚════════════════╝ - * 0 <= Address <= 0x3FFE (16382) - * - * ╔ Word-Encoded 1 ╗ - * ║101XXXXXXXXXXXXX║ - * ║ │└─────┬─────┘║ - * ║ │Address >> 1 ║ - * ║ └── Value: 1 ║ - * ╚════════════════╝ - * 0 <= Address <= 0x3FFE (16382) - * - * ╔═══ Reserved ═══╗ - * ║110XXXXXXXXXXXXX║ - * ╚════════════════╝ - * - * ╔═══════════ Word-Next ═══════════╗ - * ║111XXXXXXXXXXXXX║YYYYYYYYYYYYYYYY║ - * ║ └─────┬─────┘║└───────┬──────┘║ - * ║(Address-128)>>1║ ~Value ║ - * ╚════════════════╩════════════════╝ - * ( 0 <= Address < 0x0080 (128): Reserved) - * 0x80 <= Address <= 0x3FFE (16382) - * - * Write Log entry ranges: - * 0x0000 ... 0x7FFF - Byte-Entry; address is (Entry & 0x7F00) >> 4; value is (Entry & 0xFF) - * 0x8000 ... 0x9FFF - Word-Encoded 0; address is (Entry & 0x1FFF) << 1; value is 0 - * 0xA000 ... 0xBFFF - Word-Encoded 1; address is (Entry & 0x1FFF) << 1; value is 1 - * 0xC000 ... 0xDFFF - Reserved - * 0xE000 ... 0xFFBF - Word-Next; address is (Entry & 0x1FFF) << 1 + 0x80; value is ~(Next_Entry) - * 0xFFC0 ... 0xFFFE - Reserved - * 0xFFFF - Unprogrammed - * - */ - -#include "eeprom_stm32_defs.h" -/* These bits are used for optimizing encoding of bytes, 0 and 1 */ -#define FEE_WORD_ENCODING 0x8000 -#define FEE_VALUE_NEXT 0x6000 -#define FEE_VALUE_RESERVED 0x4000 -#define FEE_VALUE_ENCODED 0x2000 -#define FEE_BYTE_RANGE 0x80 - -/* Flash word value after erase */ -#define FEE_EMPTY_WORD ((uint16_t)0xFFFF) - -#if !defined(FEE_PAGE_SIZE) || !defined(FEE_PAGE_COUNT) || !defined(FEE_MCU_FLASH_SIZE) || !defined(FEE_PAGE_BASE_ADDRESS) -# error "not implemented." -#endif - -/* In-memory contents of emulated eeprom for faster access */ -/* *TODO: Implement page swapping */ -static uint16_t WordBuf[FEE_DENSITY_BYTES / 2]; -static uint8_t *DataBuf = (uint8_t *)WordBuf; - -/* Pointer to the first available slot within the write log */ -static uint16_t *empty_slot; - -// #define DEBUG_EEPROM_OUTPUT - -/* - * Debug print utils - */ - -#if defined(DEBUG_EEPROM_OUTPUT) - -# define debug_eeprom debug_enable -# define eeprom_println(s) println(s) -# define eeprom_printf(fmt, ...) xprintf(fmt, ##__VA_ARGS__); - -#else /* NO_DEBUG */ - -# define debug_eeprom false -# define eeprom_println(s) -# define eeprom_printf(fmt, ...) - -#endif /* NO_DEBUG */ - -void print_eeprom(void) { -#ifndef NO_DEBUG - int empty_rows = 0; - for (uint16_t i = 0; i < FEE_DENSITY_BYTES; i++) { - if (i % 16 == 0) { - if (i >= FEE_DENSITY_BYTES - 16) { - /* Make sure we display the last row */ - empty_rows = 0; - } - /* Check if this row is uninitialized */ - ++empty_rows; - for (uint16_t j = 0; j < 16; j++) { - if (DataBuf[i + j]) { - empty_rows = 0; - break; - } - } - if (empty_rows > 1) { - /* Repeat empty row */ - if (empty_rows == 2) { - /* Only display the first repeat empty row */ - println("*"); - } - i += 15; - continue; - } - xprintf("%04x", i); - } - if (i % 8 == 0) print(" "); - - xprintf(" %02x", DataBuf[i]); - if ((i + 1) % 16 == 0) { - println(""); - } - } -#endif -} - -uint16_t EEPROM_Init(void) { - /* Load emulated eeprom contents from compacted flash into memory */ - uint16_t *src = (uint16_t *)FEE_COMPACTED_BASE_ADDRESS; - uint16_t *dest = (uint16_t *)DataBuf; - for (; src < (uint16_t *)FEE_COMPACTED_LAST_ADDRESS; ++src, ++dest) { - *dest = ~*src; - } - - if (debug_eeprom) { - println("EEPROM_Init Compacted Pages:"); - print_eeprom(); - println("EEPROM_Init Write Log:"); - } - - /* Replay write log */ - uint16_t *log_addr; - for (log_addr = (uint16_t *)FEE_WRITE_LOG_BASE_ADDRESS; log_addr < (uint16_t *)FEE_WRITE_LOG_LAST_ADDRESS; ++log_addr) { - uint16_t address = *log_addr; - if (address == FEE_EMPTY_WORD) { - break; - } - /* Check for lowest 128-bytes optimization */ - if (!(address & FEE_WORD_ENCODING)) { - uint8_t bvalue = (uint8_t)address; - address >>= 8; - DataBuf[address] = bvalue; - eeprom_printf("DataBuf[0x%02x] = 0x%02x;\n", address, bvalue); - } else { - uint16_t wvalue; - /* Check if value is in next word */ - if ((address & FEE_VALUE_NEXT) == FEE_VALUE_NEXT) { - /* Read value from next word */ - if (++log_addr >= (uint16_t *)FEE_WRITE_LOG_LAST_ADDRESS) { - break; - } - wvalue = ~*log_addr; - if (!wvalue) { - eeprom_printf("Incomplete write at log_addr: 0x%04x;\n", (uint32_t)log_addr); - /* Possibly incomplete write. Ignore and continue */ - continue; - } - address &= 0x1FFF; - address <<= 1; - /* Writes to addresses less than 128 are byte log entries */ - address += FEE_BYTE_RANGE; - } else { - /* Reserved for future use */ - if (address & FEE_VALUE_RESERVED) { - eeprom_printf("Reserved encoded value at log_addr: 0x%04x;\n", (uint32_t)log_addr); - continue; - } - /* Optimization for 0 or 1 values. */ - wvalue = (address & FEE_VALUE_ENCODED) >> 13; - address &= 0x1FFF; - address <<= 1; - } - if (address < FEE_DENSITY_BYTES) { - eeprom_printf("DataBuf[0x%04x] = 0x%04x;\n", address, wvalue); - *(uint16_t *)(&DataBuf[address]) = wvalue; - } else { - eeprom_printf("DataBuf[0x%04x] cannot be set to 0x%04x [BAD ADDRESS]\n", address, wvalue); - } - } - } - - empty_slot = log_addr; - - if (debug_eeprom) { - println("EEPROM_Init Final DataBuf:"); - print_eeprom(); - } - - return FEE_DENSITY_BYTES; -} - -/* Clear flash contents (doesn't touch in-memory DataBuf) */ -static void eeprom_clear(void) { - FLASH_Unlock(); - - for (uint16_t page_num = 0; page_num < FEE_PAGE_COUNT; ++page_num) { - eeprom_printf("FLASH_ErasePage(0x%04x)\n", (uint32_t)(FEE_PAGE_BASE_ADDRESS + (page_num * FEE_PAGE_SIZE))); - FLASH_ErasePage(FEE_PAGE_BASE_ADDRESS + (page_num * FEE_PAGE_SIZE)); - } - - FLASH_Lock(); - - empty_slot = (uint16_t *)FEE_WRITE_LOG_BASE_ADDRESS; - eeprom_printf("eeprom_clear empty_slot: 0x%08x\n", (uint32_t)empty_slot); -} - -/* Erase emulated eeprom */ -void EEPROM_Erase(void) { - eeprom_println("EEPROM_Erase"); - /* Erase compacted pages and write log */ - eeprom_clear(); - /* re-initialize to reset DataBuf */ - EEPROM_Init(); -} - -/* Compact write log */ -static uint8_t eeprom_compact(void) { - /* Erase compacted pages and write log */ - eeprom_clear(); - - FLASH_Unlock(); - - FLASH_Status final_status = FLASH_COMPLETE; - - /* Write emulated eeprom contents from memory to compacted flash */ - uint16_t *src = (uint16_t *)DataBuf; - uintptr_t dest = FEE_COMPACTED_BASE_ADDRESS; - uint16_t value; - for (; dest < FEE_COMPACTED_LAST_ADDRESS; ++src, dest += 2) { - value = *src; - if (value) { - eeprom_printf("FLASH_ProgramHalfWord(0x%04x, 0x%04x)\n", (uint32_t)dest, ~value); - FLASH_Status status = FLASH_ProgramHalfWord(dest, ~value); - if (status != FLASH_COMPLETE) final_status = status; - } - } - - FLASH_Lock(); - - if (debug_eeprom) { - println("eeprom_compacted:"); - print_eeprom(); - } - - return final_status; -} - -static uint8_t eeprom_write_direct_entry(uint16_t Address) { - /* Check if we can just write this directly to the compacted flash area */ - uintptr_t directAddress = FEE_COMPACTED_BASE_ADDRESS + (Address & 0xFFFE); - if (*(uint16_t *)directAddress == FEE_EMPTY_WORD) { - /* Write the value directly to the compacted area without a log entry */ - uint16_t value = ~*(uint16_t *)(&DataBuf[Address & 0xFFFE]); - /* Early exit if a write isn't needed */ - if (value == FEE_EMPTY_WORD) return FLASH_COMPLETE; - - FLASH_Unlock(); - - eeprom_printf("FLASH_ProgramHalfWord(0x%08x, 0x%04x) [DIRECT]\n", (uint32_t)directAddress, value); - FLASH_Status status = FLASH_ProgramHalfWord(directAddress, value); - - FLASH_Lock(); - return status; - } - return 0; -} - -static uint8_t eeprom_write_log_word_entry(uint16_t Address) { - FLASH_Status final_status = FLASH_COMPLETE; - - uint16_t value = *(uint16_t *)(&DataBuf[Address]); - eeprom_printf("eeprom_write_log_word_entry(0x%04x): 0x%04x\n", Address, value); - - /* MSB signifies the lowest 128-byte optimization is not in effect */ - uint16_t encoding = FEE_WORD_ENCODING; - uint8_t entry_size; - if (value <= 1) { - encoding |= value << 13; - entry_size = 2; - } else { - encoding |= FEE_VALUE_NEXT; - entry_size = 4; - /* Writes to addresses less than 128 are byte log entries */ - Address -= FEE_BYTE_RANGE; - } - - /* if we can't find an empty spot, we must compact emulated eeprom */ - if (empty_slot > (uint16_t *)(FEE_WRITE_LOG_LAST_ADDRESS - entry_size)) { - /* compact the write log into the compacted flash area */ - return eeprom_compact(); - } - - /* Word log writes should be word-aligned. Take back a bit */ - Address >>= 1; - Address |= encoding; - - /* ok we found a place let's write our data */ - FLASH_Unlock(); - - /* address */ - eeprom_printf("FLASH_ProgramHalfWord(0x%08x, 0x%04x)\n", (uint32_t)empty_slot, Address); - final_status = FLASH_ProgramHalfWord((uintptr_t)empty_slot++, Address); - - /* value */ - if (encoding == (FEE_WORD_ENCODING | FEE_VALUE_NEXT)) { - eeprom_printf("FLASH_ProgramHalfWord(0x%08x, 0x%04x)\n", (uint32_t)empty_slot, ~value); - FLASH_Status status = FLASH_ProgramHalfWord((uintptr_t)empty_slot++, ~value); - if (status != FLASH_COMPLETE) final_status = status; - } - - FLASH_Lock(); - - return final_status; -} - -static uint8_t eeprom_write_log_byte_entry(uint16_t Address) { - eeprom_printf("eeprom_write_log_byte_entry(0x%04x): 0x%02x\n", Address, DataBuf[Address]); - - /* if couldn't find an empty spot, we must compact emulated eeprom */ - if (empty_slot >= (uint16_t *)FEE_WRITE_LOG_LAST_ADDRESS) { - /* compact the write log into the compacted flash area */ - return eeprom_compact(); - } - - /* ok we found a place let's write our data */ - FLASH_Unlock(); - - /* Pack address and value into the same word */ - uint16_t value = (Address << 8) | DataBuf[Address]; - - /* write to flash */ - eeprom_printf("FLASH_ProgramHalfWord(0x%08x, 0x%04x)\n", (uint32_t)empty_slot, value); - FLASH_Status status = FLASH_ProgramHalfWord((uintptr_t)empty_slot++, value); - - FLASH_Lock(); - - return status; -} - -uint8_t EEPROM_WriteDataByte(uint16_t Address, uint8_t DataByte) { - /* if the address is out-of-bounds, do nothing */ - if (Address >= FEE_DENSITY_BYTES) { - eeprom_printf("EEPROM_WriteDataByte(0x%04x, 0x%02x) [BAD ADDRESS]\n", Address, DataByte); - return FLASH_BAD_ADDRESS; - } - - /* if the value is the same, don't bother writing it */ - if (DataBuf[Address] == DataByte) { - eeprom_printf("EEPROM_WriteDataByte(0x%04x, 0x%02x) [SKIP SAME]\n", Address, DataByte); - return 0; - } - - /* keep DataBuf cache in sync */ - DataBuf[Address] = DataByte; - eeprom_printf("EEPROM_WriteDataByte DataBuf[0x%04x] = 0x%02x\n", Address, DataBuf[Address]); - - /* perform the write into flash memory */ - /* First, attempt to write directly into the compacted flash area */ - FLASH_Status status = eeprom_write_direct_entry(Address); - if (!status) { - /* Otherwise append to the write log */ - if (Address < FEE_BYTE_RANGE) { - status = eeprom_write_log_byte_entry(Address); - } else { - status = eeprom_write_log_word_entry(Address & 0xFFFE); - } - } - if (status != 0 && status != FLASH_COMPLETE) { - eeprom_printf("EEPROM_WriteDataByte [STATUS == %d]\n", status); - } - return status; -} - -uint8_t EEPROM_WriteDataWord(uint16_t Address, uint16_t DataWord) { - /* if the address is out-of-bounds, do nothing */ - if (Address >= FEE_DENSITY_BYTES) { - eeprom_printf("EEPROM_WriteDataWord(0x%04x, 0x%04x) [BAD ADDRESS]\n", Address, DataWord); - return FLASH_BAD_ADDRESS; - } - - /* Check for word alignment */ - FLASH_Status final_status = FLASH_COMPLETE; - if (Address % 2) { - final_status = EEPROM_WriteDataByte(Address, DataWord); - FLASH_Status status = EEPROM_WriteDataByte(Address + 1, DataWord >> 8); - if (status != FLASH_COMPLETE) final_status = status; - if (final_status != 0 && final_status != FLASH_COMPLETE) { - eeprom_printf("EEPROM_WriteDataWord [STATUS == %d]\n", final_status); - } - return final_status; - } - - /* if the value is the same, don't bother writing it */ - uint16_t oldValue = *(uint16_t *)(&DataBuf[Address]); - if (oldValue == DataWord) { - eeprom_printf("EEPROM_WriteDataWord(0x%04x, 0x%04x) [SKIP SAME]\n", Address, DataWord); - return 0; - } - - /* keep DataBuf cache in sync */ - *(uint16_t *)(&DataBuf[Address]) = DataWord; - eeprom_printf("EEPROM_WriteDataWord DataBuf[0x%04x] = 0x%04x\n", Address, *(uint16_t *)(&DataBuf[Address])); - - /* perform the write into flash memory */ - /* First, attempt to write directly into the compacted flash area */ - final_status = eeprom_write_direct_entry(Address); - if (!final_status) { - /* Otherwise append to the write log */ - /* Check if we need to fall back to byte write */ - if (Address < FEE_BYTE_RANGE) { - final_status = FLASH_COMPLETE; - /* Only write a byte if it has changed */ - if ((uint8_t)oldValue != (uint8_t)DataWord) { - final_status = eeprom_write_log_byte_entry(Address); - } - FLASH_Status status = FLASH_COMPLETE; - /* Only write a byte if it has changed */ - if ((oldValue >> 8) != (DataWord >> 8)) { - status = eeprom_write_log_byte_entry(Address + 1); - } - if (status != FLASH_COMPLETE) final_status = status; - } else { - final_status = eeprom_write_log_word_entry(Address); - } - } - if (final_status != 0 && final_status != FLASH_COMPLETE) { - eeprom_printf("EEPROM_WriteDataWord [STATUS == %d]\n", final_status); - } - return final_status; -} - -uint8_t EEPROM_ReadDataByte(uint16_t Address) { - uint8_t DataByte = 0xFF; - - if (Address < FEE_DENSITY_BYTES) { - DataByte = DataBuf[Address]; - } - - eeprom_printf("EEPROM_ReadDataByte(0x%04x): 0x%02x\n", Address, DataByte); - - return DataByte; -} - -uint16_t EEPROM_ReadDataWord(uint16_t Address) { - uint16_t DataWord = 0xFFFF; - - if (Address < FEE_DENSITY_BYTES - 1) { - /* Check word alignment */ - if (Address % 2) { - DataWord = DataBuf[Address] | (DataBuf[Address + 1] << 8); - } else { - DataWord = *(uint16_t *)(&DataBuf[Address]); - } - } - - eeprom_printf("EEPROM_ReadDataWord(0x%04x): 0x%04x\n", Address, DataWord); - - return DataWord; -} - -/***************************************************************************** - * Bind to eeprom_driver.c - *******************************************************************************/ -void eeprom_driver_init(void) { - EEPROM_Init(); -} - -void eeprom_driver_erase(void) { - EEPROM_Erase(); -} - -void eeprom_read_block(void *buf, const void *addr, size_t len) { - const uint8_t *src = (const uint8_t *)addr; - uint8_t * dest = (uint8_t *)buf; - - /* Check word alignment */ - if (len && (uintptr_t)src % 2) { - /* Read the unaligned first byte */ - *dest++ = EEPROM_ReadDataByte((const uintptr_t)src++); - --len; - } - - uint16_t value; - bool aligned = ((uintptr_t)dest % 2 == 0); - while (len > 1) { - value = EEPROM_ReadDataWord((const uintptr_t)((uint16_t *)src)); - if (aligned) { - *(uint16_t *)dest = value; - dest += 2; - } else { - *dest++ = value; - *dest++ = value >> 8; - } - src += 2; - len -= 2; - } - if (len) { - *dest = EEPROM_ReadDataByte((const uintptr_t)src); - } -} - -void eeprom_write_block(const void *buf, void *addr, size_t len) { - uint8_t * dest = (uint8_t *)addr; - const uint8_t *src = (const uint8_t *)buf; - - /* Check word alignment */ - if (len && (uintptr_t)dest % 2) { - /* Write the unaligned first byte */ - EEPROM_WriteDataByte((uintptr_t)dest++, *src++); - --len; - } - - uint16_t value; - bool aligned = ((uintptr_t)src % 2 == 0); - while (len > 1) { - if (aligned) { - value = *(uint16_t *)src; - } else { - value = *(uint8_t *)src | (*(uint8_t *)(src + 1) << 8); - } - EEPROM_WriteDataWord((uintptr_t)((uint16_t *)dest), value); - dest += 2; - src += 2; - len -= 2; - } - - if (len) { - EEPROM_WriteDataByte((uintptr_t)dest, *src); - } -} diff --git a/platforms/chibios/eeprom_stm32.h b/platforms/chibios/eeprom_stm32.h deleted file mode 100644 index 8fcfb556b8..0000000000 --- a/platforms/chibios/eeprom_stm32.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * This software is experimental and a work in progress. - * Under no circumstances should these files be used in relation to any critical system(s). - * Use of these files is at your own risk. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR - * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * This files are free to use from http://engsta.com/stm32-flash-memory-eeprom-emulator/ by - * Artur F. - * - * Modifications for QMK and STM32F303 by Yiancar - * - * This library assumes 8-bit data locations. To add a new MCU, please provide the flash - * page size and the total flash size in Kb. The number of available pages must be a multiple - * of 2. Only half of the pages account for the total EEPROM size. - * This library also assumes that the pages are not used by the firmware. - */ - -#pragma once - -uint16_t EEPROM_Init(void); -void EEPROM_Erase(void); -uint8_t EEPROM_WriteDataByte(uint16_t Address, uint8_t DataByte); -uint8_t EEPROM_WriteDataWord(uint16_t Address, uint16_t DataWord); -uint8_t EEPROM_ReadDataByte(uint16_t Address); -uint16_t EEPROM_ReadDataWord(uint16_t Address); - -void print_eeprom(void); diff --git a/platforms/chibios/eeprom_stm32_defs.h b/platforms/chibios/eeprom_stm32_defs.h deleted file mode 100644 index 57d0440330..0000000000 --- a/platforms/chibios/eeprom_stm32_defs.h +++ /dev/null @@ -1,136 +0,0 @@ -/* Copyright 2021 QMK - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#pragma once - -#include - -#if !defined(FEE_PAGE_SIZE) || !defined(FEE_PAGE_COUNT) -# if defined(STM32F103xB) || defined(STM32F042x6) || defined(GD32VF103C8) || defined(GD32VF103CB) -# ifndef FEE_PAGE_SIZE -# define FEE_PAGE_SIZE 0x400 // Page size = 1KByte -# endif -# ifndef FEE_PAGE_COUNT -# define FEE_PAGE_COUNT 2 // How many pages are used -# endif -# elif defined(STM32F103xE) || defined(STM32F303xC) || defined(STM32F303xE) || defined(STM32F072xB) || defined(STM32F070xB) -# ifndef FEE_PAGE_SIZE -# define FEE_PAGE_SIZE 0x800 // Page size = 2KByte -# endif -# ifndef FEE_PAGE_COUNT -# define FEE_PAGE_COUNT 4 // How many pages are used -# endif -# elif defined(STM32F401xC) || defined(STM32F401xE) || defined(STM32F405xG) || defined(STM32F411xE) -# ifndef FEE_PAGE_SIZE -# define FEE_PAGE_SIZE 0x4000 // Page size = 16KByte -# endif -# ifndef FEE_PAGE_COUNT -# define FEE_PAGE_COUNT 1 // How many pages are used -# endif -# endif -#endif - -#if !defined(FEE_MCU_FLASH_SIZE) -# if defined(STM32F042x6) -# define FEE_MCU_FLASH_SIZE 32 // Size in Kb -# elif defined(GD32VF103C8) -# define FEE_MCU_FLASH_SIZE 64 // Size in Kb -# elif defined(STM32F103xB) || defined(STM32F072xB) || defined(STM32F070xB) || defined(GD32VF103CB) -# define FEE_MCU_FLASH_SIZE 128 // Size in Kb -# elif defined(STM32F303xC) || defined(STM32F401xC) -# define FEE_MCU_FLASH_SIZE 256 // Size in Kb -# elif defined(STM32F103xE) || defined(STM32F303xE) || defined(STM32F401xE) || defined(STM32F411xE) -# define FEE_MCU_FLASH_SIZE 512 // Size in Kb -# elif defined(STM32F405xG) -# define FEE_MCU_FLASH_SIZE 1024 // Size in Kb -# endif -#endif - -/* Start of the emulated eeprom */ -#if !defined(FEE_PAGE_BASE_ADDRESS) -# if defined(STM32F401xC) || defined(STM32F401xE) || defined(STM32F405xG) || defined(STM32F411xE) -# ifndef FEE_PAGE_BASE_ADDRESS -# define FEE_PAGE_BASE_ADDRESS 0x08004000 // bodge to force 2nd 16k page -# endif -# else -# ifndef FEE_FLASH_BASE -# define FEE_FLASH_BASE 0x8000000 -# endif -/* Default to end of flash */ -# define FEE_PAGE_BASE_ADDRESS ((uintptr_t)(FEE_FLASH_BASE) + FEE_MCU_FLASH_SIZE * 1024 - (FEE_PAGE_COUNT * FEE_PAGE_SIZE)) -# endif -#endif - -/* Addressable range 16KByte: 0 <-> (0x1FFF << 1) */ -#define FEE_ADDRESS_MAX_SIZE 0x4000 - -/* Size of combined compacted eeprom and write log pages */ -#define FEE_DENSITY_MAX_SIZE (FEE_PAGE_COUNT * FEE_PAGE_SIZE) - -#ifndef FEE_MCU_FLASH_SIZE_IGNORE_CHECK /* *TODO: Get rid of this check */ -# if FEE_DENSITY_MAX_SIZE > (FEE_MCU_FLASH_SIZE * 1024) -# pragma message STR(FEE_DENSITY_MAX_SIZE) " > " STR(FEE_MCU_FLASH_SIZE * 1024) -# error emulated eeprom: FEE_DENSITY_MAX_SIZE is greater than available flash size -# endif -#endif - -/* Size of emulated eeprom */ -#ifdef FEE_DENSITY_BYTES -# if (FEE_DENSITY_BYTES > FEE_DENSITY_MAX_SIZE) -# pragma message STR(FEE_DENSITY_BYTES) " > " STR(FEE_DENSITY_MAX_SIZE) -# error emulated eeprom: FEE_DENSITY_BYTES exceeds FEE_DENSITY_MAX_SIZE -# endif -# if (FEE_DENSITY_BYTES == FEE_DENSITY_MAX_SIZE) -# pragma message STR(FEE_DENSITY_BYTES) " == " STR(FEE_DENSITY_MAX_SIZE) -# warning emulated eeprom: FEE_DENSITY_BYTES leaves no room for a write log. This will greatly increase the flash wear rate! -# endif -# if FEE_DENSITY_BYTES > FEE_ADDRESS_MAX_SIZE -# pragma message STR(FEE_DENSITY_BYTES) " > " STR(FEE_ADDRESS_MAX_SIZE) -# error emulated eeprom: FEE_DENSITY_BYTES is greater than FEE_ADDRESS_MAX_SIZE allows -# endif -# if ((FEE_DENSITY_BYTES) % 2) == 1 -# error emulated eeprom: FEE_DENSITY_BYTES must be even -# endif -#else -/* Default to half of allocated space used for emulated eeprom, half for write log */ -# define FEE_DENSITY_BYTES (FEE_PAGE_COUNT * FEE_PAGE_SIZE / 2) -#endif - -/* Size of write log */ -#ifdef FEE_WRITE_LOG_BYTES -# if ((FEE_DENSITY_BYTES + FEE_WRITE_LOG_BYTES) > FEE_DENSITY_MAX_SIZE) -# pragma message STR(FEE_DENSITY_BYTES) " + " STR(FEE_WRITE_LOG_BYTES) " > " STR(FEE_DENSITY_MAX_SIZE) -# error emulated eeprom: FEE_WRITE_LOG_BYTES exceeds remaining FEE_DENSITY_MAX_SIZE -# endif -# if ((FEE_WRITE_LOG_BYTES) % 2) == 1 -# error emulated eeprom: FEE_WRITE_LOG_BYTES must be even -# endif -#else -/* Default to use all remaining space */ -# define FEE_WRITE_LOG_BYTES (FEE_PAGE_COUNT * FEE_PAGE_SIZE - FEE_DENSITY_BYTES) -#endif - -/* Start of the emulated eeprom compacted flash area */ -#define FEE_COMPACTED_BASE_ADDRESS FEE_PAGE_BASE_ADDRESS -/* End of the emulated eeprom compacted flash area */ -#define FEE_COMPACTED_LAST_ADDRESS (FEE_COMPACTED_BASE_ADDRESS + FEE_DENSITY_BYTES) -/* Start of the emulated eeprom write log */ -#define FEE_WRITE_LOG_BASE_ADDRESS FEE_COMPACTED_LAST_ADDRESS -/* End of the emulated eeprom write log */ -#define FEE_WRITE_LOG_LAST_ADDRESS (FEE_WRITE_LOG_BASE_ADDRESS + FEE_WRITE_LOG_BYTES) - -#if defined(DYNAMIC_KEYMAP_EEPROM_MAX_ADDR) && (DYNAMIC_KEYMAP_EEPROM_MAX_ADDR >= FEE_DENSITY_BYTES) -# error emulated eeprom: DYNAMIC_KEYMAP_EEPROM_MAX_ADDR is greater than the FEE_DENSITY_BYTES available -#endif diff --git a/platforms/chibios/eeprom_teensy.c b/platforms/chibios/eeprom_teensy.c deleted file mode 100644 index c8777febde..0000000000 --- a/platforms/chibios/eeprom_teensy.c +++ /dev/null @@ -1,546 +0,0 @@ -#include -#include - -#include "eeprom_teensy.h" -#include "eeconfig.h" - -/*************************************/ -/* Hardware backend */ -/* */ -/* Code from PJRC/Teensyduino */ -/*************************************/ - -/* Teensyduino Core Library - * http://www.pjrc.com/teensy/ - * Copyright (c) 2013 PJRC.COM, LLC. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * 1. The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * 2. If the Software is incorporated into a build system that allows - * selection among a list of target devices, then similar target - * devices manufactured by PJRC.COM must be included in the list of - * target devices and selectable in the same manner. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#if defined(K20x) /* chip selection */ -/* Teensy 3.0, 3.1, 3.2; mchck; infinity keyboard */ - -/* - ^^^ Here be dragons: - NXP AppNote AN4282 section 3.1 states that partitioning must only be done once. - Once EEPROM partitioning is done, the size is locked to this initial configuration. - Attempts to modify the EEPROM_SIZE setting may brick your board. -*/ - -// Writing unaligned 16 or 32 bit data is handled automatically when -// this is defined, but at a cost of extra code size. Without this, -// any unaligned write will cause a hard fault exception! If you're -// absolutely sure all 16 and 32 bit writes will be aligned, you can -// remove the extra unnecessary code. -// -# define HANDLE_UNALIGNED_WRITES - -// Minimum EEPROM Endurance -// ------------------------ -# if (EEPROM_SIZE == 2048) // 35000 writes/byte or 70000 writes/word -# define EEESIZE 0x33 -# elif (EEPROM_SIZE == 1024) // 75000 writes/byte or 150000 writes/word -# define EEESIZE 0x34 -# elif (EEPROM_SIZE == 512) // 155000 writes/byte or 310000 writes/word -# define EEESIZE 0x35 -# elif (EEPROM_SIZE == 256) // 315000 writes/byte or 630000 writes/word -# define EEESIZE 0x36 -# elif (EEPROM_SIZE == 128) // 635000 writes/byte or 1270000 writes/word -# define EEESIZE 0x37 -# elif (EEPROM_SIZE == 64) // 1275000 writes/byte or 2550000 writes/word -# define EEESIZE 0x38 -# elif (EEPROM_SIZE == 32) // 2555000 writes/byte or 5110000 writes/word -# define EEESIZE 0x39 -# endif - -/** \brief eeprom initialization - * - * FIXME: needs doc - */ -void eeprom_initialize(void) { - uint32_t count = 0; - uint16_t do_flash_cmd[] = {0xf06f, 0x037f, 0x7003, 0x7803, 0xf013, 0x0f80, 0xd0fb, 0x4770}; - uint8_t status; - - if (FTFL->FCNFG & FTFL_FCNFG_RAMRDY) { - // FlexRAM is configured as traditional RAM - // We need to reconfigure for EEPROM usage - FTFL->FCCOB0 = 0x80; // PGMPART = Program Partition Command - FTFL->FCCOB4 = EEESIZE; // EEPROM Size - FTFL->FCCOB5 = 0x03; // 0K for Dataflash, 32K for EEPROM backup - __disable_irq(); - // do_flash_cmd() must execute from RAM. Luckily the C syntax is simple... - (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&(FTFL->FSTAT)); - __enable_irq(); - status = FTFL->FSTAT; - if (status & (FTFL_FSTAT_RDCOLERR | FTFL_FSTAT_ACCERR | FTFL_FSTAT_FPVIOL)) { - FTFL->FSTAT = (status & (FTFL_FSTAT_RDCOLERR | FTFL_FSTAT_ACCERR | FTFL_FSTAT_FPVIOL)); - return; // error - } - } - // wait for eeprom to become ready (is this really necessary?) - while (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) { - if (++count > 20000) break; - } -} - -# define FlexRAM ((uint8_t *)0x14000000) - -/** \brief eeprom read byte - * - * FIXME: needs doc - */ -uint8_t eeprom_read_byte(const uint8_t *addr) { - uint32_t offset = (uint32_t)addr; - if (offset >= EEPROM_SIZE) return 0; - if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize(); - return FlexRAM[offset]; -} - -/** \brief eeprom read word - * - * FIXME: needs doc - */ -uint16_t eeprom_read_word(const uint16_t *addr) { - uint32_t offset = (uint32_t)addr; - if (offset >= EEPROM_SIZE - 1) return 0; - if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize(); - return *(uint16_t *)(&FlexRAM[offset]); -} - -/** \brief eeprom read dword - * - * FIXME: needs doc - */ -uint32_t eeprom_read_dword(const uint32_t *addr) { - uint32_t offset = (uint32_t)addr; - if (offset >= EEPROM_SIZE - 3) return 0; - if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize(); - return *(uint32_t *)(&FlexRAM[offset]); -} - -/** \brief eeprom read block - * - * FIXME: needs doc - */ -void eeprom_read_block(void *buf, const void *addr, uint32_t len) { - uint32_t offset = (uint32_t)addr; - uint8_t *dest = (uint8_t *)buf; - uint32_t end = offset + len; - - if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize(); - if (end > EEPROM_SIZE) end = EEPROM_SIZE; - while (offset < end) { - *dest++ = FlexRAM[offset++]; - } -} - -/** \brief eeprom is ready - * - * FIXME: needs doc - */ -int eeprom_is_ready(void) { - return (FTFL->FCNFG & FTFL_FCNFG_EEERDY) ? 1 : 0; -} - -/** \brief flexram wait - * - * FIXME: needs doc - */ -static void flexram_wait(void) { - while (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) { - // TODO: timeout - } -} - -/** \brief eeprom_write_byte - * - * FIXME: needs doc - */ -void eeprom_write_byte(uint8_t *addr, uint8_t value) { - uint32_t offset = (uint32_t)addr; - - if (offset >= EEPROM_SIZE) return; - if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize(); - if (FlexRAM[offset] != value) { - FlexRAM[offset] = value; - flexram_wait(); - } -} - -/** \brief eeprom write word - * - * FIXME: needs doc - */ -void eeprom_write_word(uint16_t *addr, uint16_t value) { - uint32_t offset = (uint32_t)addr; - - if (offset >= EEPROM_SIZE - 1) return; - if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize(); -# ifdef HANDLE_UNALIGNED_WRITES - if ((offset & 1) == 0) { -# endif - if (*(uint16_t *)(&FlexRAM[offset]) != value) { - *(uint16_t *)(&FlexRAM[offset]) = value; - flexram_wait(); - } -# ifdef HANDLE_UNALIGNED_WRITES - } else { - if (FlexRAM[offset] != value) { - FlexRAM[offset] = value; - flexram_wait(); - } - if (FlexRAM[offset + 1] != (value >> 8)) { - FlexRAM[offset + 1] = value >> 8; - flexram_wait(); - } - } -# endif -} - -/** \brief eeprom write dword - * - * FIXME: needs doc - */ -void eeprom_write_dword(uint32_t *addr, uint32_t value) { - uint32_t offset = (uint32_t)addr; - - if (offset >= EEPROM_SIZE - 3) return; - if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize(); -# ifdef HANDLE_UNALIGNED_WRITES - switch (offset & 3) { - case 0: -# endif - if (*(uint32_t *)(&FlexRAM[offset]) != value) { - *(uint32_t *)(&FlexRAM[offset]) = value; - flexram_wait(); - } - return; -# ifdef HANDLE_UNALIGNED_WRITES - case 2: - if (*(uint16_t *)(&FlexRAM[offset]) != value) { - *(uint16_t *)(&FlexRAM[offset]) = value; - flexram_wait(); - } - if (*(uint16_t *)(&FlexRAM[offset + 2]) != (value >> 16)) { - *(uint16_t *)(&FlexRAM[offset + 2]) = value >> 16; - flexram_wait(); - } - return; - default: - if (FlexRAM[offset] != value) { - FlexRAM[offset] = value; - flexram_wait(); - } - if (*(uint16_t *)(&FlexRAM[offset + 1]) != (value >> 8)) { - *(uint16_t *)(&FlexRAM[offset + 1]) = value >> 8; - flexram_wait(); - } - if (FlexRAM[offset + 3] != (value >> 24)) { - FlexRAM[offset + 3] = value >> 24; - flexram_wait(); - } - } -# endif -} - -/** \brief eeprom write block - * - * FIXME: needs doc - */ -void eeprom_write_block(const void *buf, void *addr, uint32_t len) { - uint32_t offset = (uint32_t)addr; - const uint8_t *src = (const uint8_t *)buf; - - if (offset >= EEPROM_SIZE) return; - if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize(); - if (len >= EEPROM_SIZE) len = EEPROM_SIZE; - if (offset + len >= EEPROM_SIZE) len = EEPROM_SIZE - offset; - while (len > 0) { - uint32_t lsb = offset & 3; - if (lsb == 0 && len >= 4) { - // write aligned 32 bits - uint32_t val32; - val32 = *src++; - val32 |= (*src++ << 8); - val32 |= (*src++ << 16); - val32 |= (*src++ << 24); - if (*(uint32_t *)(&FlexRAM[offset]) != val32) { - *(uint32_t *)(&FlexRAM[offset]) = val32; - flexram_wait(); - } - offset += 4; - len -= 4; - } else if ((lsb == 0 || lsb == 2) && len >= 2) { - // write aligned 16 bits - uint16_t val16; - val16 = *src++; - val16 |= (*src++ << 8); - if (*(uint16_t *)(&FlexRAM[offset]) != val16) { - *(uint16_t *)(&FlexRAM[offset]) = val16; - flexram_wait(); - } - offset += 2; - len -= 2; - } else { - // write 8 bits - uint8_t val8 = *src++; - if (FlexRAM[offset] != val8) { - FlexRAM[offset] = val8; - flexram_wait(); - } - offset++; - len--; - } - } -} - -/* -void do_flash_cmd(volatile uint8_t *fstat) -{ - *fstat = 0x80; - while ((*fstat & 0x80) == 0) ; // wait -} -00000000 : - 0: f06f 037f mvn.w r3, #127 ; 0x7f - 4: 7003 strb r3, [r0, #0] - 6: 7803 ldrb r3, [r0, #0] - 8: f013 0f80 tst.w r3, #128 ; 0x80 - c: d0fb beq.n 6 - e: 4770 bx lr -*/ - -#elif defined(KL2x) /* chip selection */ -/* Teensy LC (emulated) */ - -# define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0)) - -extern uint32_t __eeprom_workarea_start__; -extern uint32_t __eeprom_workarea_end__; - -static uint32_t flashend = 0; - -void eeprom_initialize(void) { - const uint16_t *p = (uint16_t *)SYMVAL(__eeprom_workarea_start__); - - do { - if (*p++ == 0xFFFF) { - flashend = (uint32_t)(p - 2); - return; - } - } while (p < (uint16_t *)SYMVAL(__eeprom_workarea_end__)); - flashend = (uint32_t)(p - 1); -} - -uint8_t eeprom_read_byte(const uint8_t *addr) { - uint32_t offset = (uint32_t)addr; - const uint16_t *p = (uint16_t *)SYMVAL(__eeprom_workarea_start__); - const uint16_t *end = (const uint16_t *)((uint32_t)flashend); - uint16_t val; - uint8_t data = 0xFF; - - if (!end) { - eeprom_initialize(); - end = (const uint16_t *)((uint32_t)flashend); - } - if (offset < EEPROM_SIZE) { - while (p <= end) { - val = *p++; - if ((val & 255) == offset) data = val >> 8; - } - } - return data; -} - -static void flash_write(const uint16_t *code, uint32_t addr, uint32_t data) { - // with great power comes great responsibility.... - uint32_t stat; - *(uint32_t *)&(FTFA->FCCOB3) = 0x06000000 | (addr & 0x00FFFFFC); - *(uint32_t *)&(FTFA->FCCOB7) = data; - __disable_irq(); - (*((void (*)(volatile uint8_t *))((uint32_t)code | 1)))(&(FTFA->FSTAT)); - __enable_irq(); - stat = FTFA->FSTAT & (FTFA_FSTAT_RDCOLERR | FTFA_FSTAT_ACCERR | FTFA_FSTAT_FPVIOL); - if (stat) { - FTFA->FSTAT = stat; - } - MCM->PLACR |= MCM_PLACR_CFCC; -} - -void eeprom_write_byte(uint8_t *addr, uint8_t data) { - uint32_t offset = (uint32_t)addr; - const uint16_t *p, *end = (const uint16_t *)((uint32_t)flashend); - uint32_t i, val, flashaddr; - uint16_t do_flash_cmd[] = {0x2380, 0x7003, 0x7803, 0xb25b, 0x2b00, 0xdafb, 0x4770}; - uint8_t buf[EEPROM_SIZE]; - - if (offset >= EEPROM_SIZE) return; - if (!end) { - eeprom_initialize(); - end = (const uint16_t *)((uint32_t)flashend); - } - if (++end < (uint16_t *)SYMVAL(__eeprom_workarea_end__)) { - val = (data << 8) | offset; - flashaddr = (uint32_t)end; - flashend = flashaddr; - if ((flashaddr & 2) == 0) { - val |= 0xFFFF0000; - } else { - val <<= 16; - val |= 0x0000FFFF; - } - flash_write(do_flash_cmd, flashaddr, val); - } else { - for (i = 0; i < EEPROM_SIZE; i++) { - buf[i] = 0xFF; - } - val = 0; - for (p = (uint16_t *)SYMVAL(__eeprom_workarea_start__); p < (uint16_t *)SYMVAL(__eeprom_workarea_end__); p++) { - val = *p; - if ((val & 255) < EEPROM_SIZE) { - buf[val & 255] = val >> 8; - } - } - buf[offset] = data; - for (flashaddr = (uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__); flashaddr < (uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_end__); flashaddr += 1024) { - *(uint32_t *)&(FTFA->FCCOB3) = 0x09000000 | flashaddr; - __disable_irq(); - (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&(FTFA->FSTAT)); - __enable_irq(); - val = FTFA->FSTAT & (FTFA_FSTAT_RDCOLERR | FTFA_FSTAT_ACCERR | FTFA_FSTAT_FPVIOL); - ; - if (val) FTFA->FSTAT = val; - MCM->PLACR |= MCM_PLACR_CFCC; - } - flashaddr = (uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__); - for (i = 0; i < EEPROM_SIZE; i++) { - if (buf[i] == 0xFF) continue; - if ((flashaddr & 2) == 0) { - val = (buf[i] << 8) | i; - } else { - val = val | (buf[i] << 24) | (i << 16); - flash_write(do_flash_cmd, flashaddr, val); - } - flashaddr += 2; - } - flashend = flashaddr; - if ((flashaddr & 2)) { - val |= 0xFFFF0000; - flash_write(do_flash_cmd, flashaddr, val); - } - } -} - -/* -void do_flash_cmd(volatile uint8_t *fstat) -{ - *fstat = 0x80; - while ((*fstat & 0x80) == 0) ; // wait -} -00000000 : - 0: 2380 movs r3, #128 ; 0x80 - 2: 7003 strb r3, [r0, #0] - 4: 7803 ldrb r3, [r0, #0] - 6: b25b sxtb r3, r3 - 8: 2b00 cmp r3, #0 - a: dafb bge.n 4 - c: 4770 bx lr -*/ - -uint16_t eeprom_read_word(const uint16_t *addr) { - const uint8_t *p = (const uint8_t *)addr; - return eeprom_read_byte(p) | (eeprom_read_byte(p + 1) << 8); -} - -uint32_t eeprom_read_dword(const uint32_t *addr) { - const uint8_t *p = (const uint8_t *)addr; - return eeprom_read_byte(p) | (eeprom_read_byte(p + 1) << 8) | (eeprom_read_byte(p + 2) << 16) | (eeprom_read_byte(p + 3) << 24); -} - -void eeprom_read_block(void *buf, const void *addr, uint32_t len) { - const uint8_t *p = (const uint8_t *)addr; - uint8_t * dest = (uint8_t *)buf; - while (len--) { - *dest++ = eeprom_read_byte(p++); - } -} - -int eeprom_is_ready(void) { - return 1; -} - -void eeprom_write_word(uint16_t *addr, uint16_t value) { - uint8_t *p = (uint8_t *)addr; - eeprom_write_byte(p++, value); - eeprom_write_byte(p, value >> 8); -} - -void eeprom_write_dword(uint32_t *addr, uint32_t value) { - uint8_t *p = (uint8_t *)addr; - eeprom_write_byte(p++, value); - eeprom_write_byte(p++, value >> 8); - eeprom_write_byte(p++, value >> 16); - eeprom_write_byte(p, value >> 24); -} - -void eeprom_write_block(const void *buf, void *addr, uint32_t len) { - uint8_t * p = (uint8_t *)addr; - const uint8_t *src = (const uint8_t *)buf; - while (len--) { - eeprom_write_byte(p++, *src++); - } -} - -#else -# error Unsupported Teensy EEPROM. -#endif /* chip selection */ -// The update functions just calls write for now, but could probably be optimized - -void eeprom_update_byte(uint8_t *addr, uint8_t value) { - eeprom_write_byte(addr, value); -} - -void eeprom_update_word(uint16_t *addr, uint16_t value) { - uint8_t *p = (uint8_t *)addr; - eeprom_write_byte(p++, value); - eeprom_write_byte(p, value >> 8); -} - -void eeprom_update_dword(uint32_t *addr, uint32_t value) { - uint8_t *p = (uint8_t *)addr; - eeprom_write_byte(p++, value); - eeprom_write_byte(p++, value >> 8); - eeprom_write_byte(p++, value >> 16); - eeprom_write_byte(p, value >> 24); -} - -void eeprom_update_block(const void *buf, void *addr, size_t len) { - uint8_t * p = (uint8_t *)addr; - const uint8_t *src = (const uint8_t *)buf; - while (len--) { - eeprom_write_byte(p++, *src++); - } -} diff --git a/platforms/chibios/eeprom_teensy.h b/platforms/chibios/eeprom_teensy.h deleted file mode 100755 index 9a14a1fa79..0000000000 --- a/platforms/chibios/eeprom_teensy.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2022 Nick Brassel (@tzarc) -// SPDX-License-Identifier: GPL-2.0-or-later -#pragma once - -#include -#include - -#if defined(K20x) -/* Teensy 3.0, 3.1, 3.2; mchck; infinity keyboard */ -// The EEPROM is really RAM with a hardware-based backup system to -// flash memory. Selecting a smaller size EEPROM allows more wear -// leveling, for higher write endurance. If you edit this file, -// set this to the smallest size your application can use. Also, -// due to Freescale's implementation, writing 16 or 32 bit words -// (aligned to 2 or 4 byte boundaries) has twice the endurance -// compared to writing 8 bit bytes. -// -# ifndef EEPROM_SIZE -# define EEPROM_SIZE 32 -# endif -#elif defined(KL2x) /* Teensy LC (emulated) */ -# define EEPROM_SIZE 128 -#else -# error Unsupported Teensy EEPROM. -#endif diff --git a/platforms/chibios/flash_stm32.c b/platforms/chibios/flash_stm32.c deleted file mode 100644 index 72c41b8b78..0000000000 --- a/platforms/chibios/flash_stm32.c +++ /dev/null @@ -1,208 +0,0 @@ -/* - * This software is experimental and a work in progress. - * Under no circumstances should these files be used in relation to any critical system(s). - * Use of these files is at your own risk. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR - * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * This files are free to use from https://github.com/rogerclarkmelbourne/Arduino_STM32 and - * https://github.com/leaflabs/libmaple - * - * Modifications for QMK and STM32F303 by Yiancar - */ - -#include -#include "flash_stm32.h" - -#if defined(STM32F1XX) -# define FLASH_SR_WRPERR FLASH_SR_WRPRTERR -#endif - -#if defined(MCU_GD32V) -/* GigaDevice GD32VF103 is a STM32F103 clone at heart. */ -# include "gd32v_compatibility.h" -#endif - -#if defined(STM32F4XX) -# define FLASH_SR_PGERR (FLASH_SR_PGSERR | FLASH_SR_PGPERR | FLASH_SR_PGAERR) - -# define FLASH_KEY1 0x45670123U -# define FLASH_KEY2 0xCDEF89ABU - -static uint8_t ADDR2PAGE(uint32_t Page_Address) { - switch (Page_Address) { - case 0x08000000 ... 0x08003FFF: - return 0; - case 0x08004000 ... 0x08007FFF: - return 1; - case 0x08008000 ... 0x0800BFFF: - return 2; - case 0x0800C000 ... 0x0800FFFF: - return 3; - } - - // TODO: bad times... - return 7; -} -#endif - -/* Delay definition */ -#define EraseTimeout ((uint32_t)0x00000FFF) -#define ProgramTimeout ((uint32_t)0x0000001F) - -#define ASSERT(exp) (void)((0)) - -/** - * @brief Inserts a time delay. - * @param None - * @retval None - */ -static void delay(void) { - __IO uint32_t i = 0; - for (i = 0xFF; i != 0; i--) { - } -} - -/** - * @brief Returns the FLASH Status. - * @param None - * @retval FLASH Status: The returned value can be: FLASH_BUSY, FLASH_ERROR_PG, - * FLASH_ERROR_WRP or FLASH_COMPLETE - */ -FLASH_Status FLASH_GetStatus(void) { - if ((FLASH->SR & FLASH_SR_BSY) == FLASH_SR_BSY) return FLASH_BUSY; - - if ((FLASH->SR & FLASH_SR_PGERR) != 0) return FLASH_ERROR_PG; - - if ((FLASH->SR & FLASH_SR_WRPERR) != 0) return FLASH_ERROR_WRP; - -#if defined(FLASH_OBR_OPTERR) - if ((FLASH->SR & FLASH_OBR_OPTERR) != 0) return FLASH_ERROR_OPT; -#endif - - return FLASH_COMPLETE; -} - -/** - * @brief Waits for a Flash operation to complete or a TIMEOUT to occur. - * @param Timeout: FLASH progamming Timeout - * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG, - * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. - */ -FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout) { - FLASH_Status status; - - /* Check for the Flash Status */ - status = FLASH_GetStatus(); - /* Wait for a Flash operation to complete or a TIMEOUT to occur */ - while ((status == FLASH_BUSY) && (Timeout != 0x00)) { - delay(); - status = FLASH_GetStatus(); - Timeout--; - } - if (Timeout == 0) status = FLASH_TIMEOUT; - /* Return the operation status */ - return status; -} - -/** - * @brief Erases a specified FLASH page. - * @param Page_Address: The page address to be erased. - * @retval FLASH Status: The returned value can be: FLASH_BUSY, FLASH_ERROR_PG, - * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. - */ -FLASH_Status FLASH_ErasePage(uint32_t Page_Address) { - FLASH_Status status = FLASH_COMPLETE; - /* Check the parameters */ - ASSERT(IS_FLASH_ADDRESS(Page_Address)); - /* Wait for last operation to be completed */ - status = FLASH_WaitForLastOperation(EraseTimeout); - - if (status == FLASH_COMPLETE) { - /* if the previous operation is completed, proceed to erase the page */ -#if defined(FLASH_CR_SNB) - FLASH->CR &= ~FLASH_CR_SNB; - FLASH->CR |= FLASH_CR_SER | (ADDR2PAGE(Page_Address) << FLASH_CR_SNB_Pos); -#else - FLASH->CR |= FLASH_CR_PER; - FLASH->AR = Page_Address; -#endif - FLASH->CR |= FLASH_CR_STRT; - - /* Wait for last operation to be completed */ - status = FLASH_WaitForLastOperation(EraseTimeout); - if (status != FLASH_TIMEOUT) { - /* if the erase operation is completed, disable the configured Bits */ -#if defined(FLASH_CR_SNB) - FLASH->CR &= ~(FLASH_CR_SER | FLASH_CR_SNB); -#else - FLASH->CR &= ~FLASH_CR_PER; -#endif - } - FLASH->SR = (FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPERR); - } - /* Return the Erase Status */ - return status; -} - -/** - * @brief Programs a half word at a specified address. - * @param Address: specifies the address to be programmed. - * @param Data: specifies the data to be programmed. - * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG, - * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. - */ -FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data) { - FLASH_Status status = FLASH_BAD_ADDRESS; - - if (IS_FLASH_ADDRESS(Address)) { - /* Wait for last operation to be completed */ - status = FLASH_WaitForLastOperation(ProgramTimeout); - if (status == FLASH_COMPLETE) { - /* if the previous operation is completed, proceed to program the new data */ - -#if defined(FLASH_CR_PSIZE) - FLASH->CR &= ~FLASH_CR_PSIZE; - FLASH->CR |= FLASH_CR_PSIZE_0; -#endif - FLASH->CR |= FLASH_CR_PG; - *(__IO uint16_t*)Address = Data; - /* Wait for last operation to be completed */ - status = FLASH_WaitForLastOperation(ProgramTimeout); - if (status != FLASH_TIMEOUT) { - /* if the program operation is completed, disable the PG Bit */ - FLASH->CR &= ~FLASH_CR_PG; - } - FLASH->SR = (FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPERR); - } - } - return status; -} - -/** - * @brief Unlocks the FLASH Program Erase Controller. - * @param None - * @retval None - */ -void FLASH_Unlock(void) { - if (FLASH->CR & FLASH_CR_LOCK) { - /* Authorize the FPEC Access */ - FLASH->KEYR = FLASH_KEY1; - FLASH->KEYR = FLASH_KEY2; - } -} - -/** - * @brief Locks the FLASH Program Erase Controller. - * @param None - * @retval None - */ -void FLASH_Lock(void) { - /* Set the Lock Bit to lock the FPEC and the FCR */ - FLASH->CR |= FLASH_CR_LOCK; -} diff --git a/platforms/chibios/flash_stm32.h b/platforms/chibios/flash_stm32.h deleted file mode 100644 index 6c66642ec5..0000000000 --- a/platforms/chibios/flash_stm32.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * This software is experimental and a work in progress. - * Under no circumstances should these files be used in relation to any critical system(s). - * Use of these files is at your own risk. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR - * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * This files are free to use from https://github.com/rogerclarkmelbourne/Arduino_STM32 and - * https://github.com/leaflabs/libmaple - * - * Modifications for QMK and STM32F303 by Yiancar - */ - -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -#ifdef FLASH_STM32_MOCKED -extern uint8_t FlashBuf[MOCK_FLASH_SIZE]; -#endif - -typedef enum { FLASH_BUSY = 1, FLASH_ERROR_PG, FLASH_ERROR_WRP, FLASH_ERROR_OPT, FLASH_COMPLETE, FLASH_TIMEOUT, FLASH_BAD_ADDRESS } FLASH_Status; - -#define IS_FLASH_ADDRESS(ADDRESS) (((ADDRESS) >= 0x08000000) && ((ADDRESS) < 0x0807FFFF)) - -FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout); -FLASH_Status FLASH_ErasePage(uint32_t Page_Address); -FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data); - -void FLASH_Unlock(void); -void FLASH_Lock(void); - -#ifdef __cplusplus -} -#endif diff --git a/platforms/test/rules.mk b/platforms/test/rules.mk index 55512c7392..a2baa283d0 100644 --- a/platforms/test/rules.mk +++ b/platforms/test/rules.mk @@ -11,7 +11,8 @@ eeprom_stm32_large_DEFS := $(eeprom_stm32_DEFS) \ -DFEE_PAGE_COUNT=16 eeprom_stm32_INC := \ - $(PLATFORM_PATH)/chibios/ + $(PLATFORM_PATH)/chibios/drivers/eeprom/ \ + $(PLATFORM_PATH)/chibios/drivers/flash/ eeprom_stm32_tiny_INC := $(eeprom_stm32_INC) eeprom_stm32_large_INC := $(eeprom_stm32_INC) @@ -19,6 +20,6 @@ eeprom_stm32_SRC := \ $(TOP_DIR)/drivers/eeprom/eeprom_driver.c \ $(PLATFORM_PATH)/$(PLATFORM_KEY)/eeprom_stm32_tests.cpp \ $(PLATFORM_PATH)/$(PLATFORM_KEY)/flash_stm32_mock.c \ - $(PLATFORM_PATH)/chibios/eeprom_stm32.c + $(PLATFORM_PATH)/chibios/drivers/eeprom/eeprom_stm32.c eeprom_stm32_tiny_SRC := $(eeprom_stm32_SRC) eeprom_stm32_large_SRC := $(eeprom_stm32_SRC) -- cgit v1.2.3 From 6d67e9df4be6981de05517626c1a504da31abf16 Mon Sep 17 00:00:00 2001 From: Stefan Kerkmann Date: Fri, 17 Jun 2022 22:06:44 +0200 Subject: [Core] Allow usage of ChibiOS's SIO driver for split keyboards (#15907) --- platforms/chibios/drivers/serial_usart.c | 173 +++++++++++++++++++++++-------- platforms/chibios/drivers/serial_usart.h | 39 +++---- 2 files changed, 150 insertions(+), 62 deletions(-) (limited to 'platforms') diff --git a/platforms/chibios/drivers/serial_usart.c b/platforms/chibios/drivers/serial_usart.c index e9fa4af7a3..7ea25d005b 100644 --- a/platforms/chibios/drivers/serial_usart.c +++ b/platforms/chibios/drivers/serial_usart.c @@ -1,44 +1,47 @@ -/* Copyright 2021 QMK - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ +// Copyright 2021 QMK +// Copyright 2022 Stefan Kerkmann +// SPDX-License-Identifier: GPL-2.0-or-later #include "serial_usart.h" #include "synchronization_util.h" #if defined(SERIAL_USART_CONFIG) -static SerialConfig serial_config = SERIAL_USART_CONFIG; +static QMKSerialConfig serial_config = SERIAL_USART_CONFIG; #else -static SerialConfig serial_config = { - .speed = (SERIAL_USART_SPEED), /* speed - mandatory */ +static QMKSerialConfig serial_config = { +# if HAL_USE_SERIAL + .speed = (SERIAL_USART_SPEED), /* baudrate - mandatory */ +# else + .baud = (SERIAL_USART_SPEED), /* baudrate - mandatory */ +# endif .cr1 = (SERIAL_USART_CR1), .cr2 = (SERIAL_USART_CR2), # if !defined(SERIAL_USART_FULL_DUPLEX) .cr3 = ((SERIAL_USART_CR3) | USART_CR3_HDSEL) /* activate half-duplex mode */ # else - .cr3 = (SERIAL_USART_CR3) + .cr3 = (SERIAL_USART_CR3) # endif }; #endif -static SerialDriver* serial_driver = &SERIAL_USART_DRIVER; +static QMKSerialDriver* serial_driver = (QMKSerialDriver*)&SERIAL_USART_DRIVER; static inline bool react_to_transactions(void); static inline bool __attribute__((nonnull)) receive(uint8_t* destination, const size_t size); +static inline bool __attribute__((nonnull)) receive_blocking(uint8_t* destination, const size_t size); static inline bool __attribute__((nonnull)) send(const uint8_t* source, const size_t size); static inline bool initiate_transaction(uint8_t sstd_index); static inline void usart_clear(void); +static inline void usart_driver_start(void); + +#if HAL_USE_SERIAL + +/** + * @brief SERIAL Driver startup routine. + */ +static inline void usart_driver_start(void) { + sdStart(serial_driver, &serial_config); +} /** * @brief Clear the receive input queue. @@ -64,6 +67,45 @@ static inline void usart_clear(void) { } } +#elif HAL_USE_SIO + +void clear_rx_evt_cb(SIODriver* siop) { + osalSysLockFromISR(); + /* If errors occured during transactions this callback is invoked. We just + * clear the error sources and move on. We rely on the fact that we check + * for the success of the transaction by comparing the received/send bytes + * with the actual received/send bytes in the send/receive functions. */ + sioGetAndClearEventsI(serial_driver); + osalSysUnlockFromISR(); +} + +static const SIOOperation serial_usart_operation = {.rx_cb = NULL, .rx_idle_cb = NULL, .tx_cb = NULL, .tx_end_cb = NULL, .rx_evt_cb = &clear_rx_evt_cb}; + +/** + * @brief SIO Driver startup routine. + */ +static inline void usart_driver_start(void) { + sioStart(serial_driver, &serial_config); + sioStartOperation(serial_driver, &serial_usart_operation); +} + +/** + * @brief Clear the receive input queue, as some MCUs have built-in hardware FIFOs. + */ +static inline void usart_clear(void) { + osalSysLock(); + while (!sioIsRXEmptyX(serial_driver)) { + (void)sioGetX(serial_driver); + } + osalSysUnlock(); +} + +#else + +# error Either the SERIAL or SIO driver has to be activated to use the usart driver for split keyboards. + +#endif + /** * @brief Blocking send of buffer with timeout. * @@ -71,15 +113,46 @@ static inline void usart_clear(void) { * @return false Send failed. */ static inline bool send(const uint8_t* source, const size_t size) { - bool success = (size_t)sdWriteTimeout(serial_driver, source, size, TIME_MS2I(SERIAL_USART_TIMEOUT)) == size; + bool success = (size_t)chnWriteTimeout(serial_driver, source, size, TIME_MS2I(SERIAL_USART_TIMEOUT)) == size; #if !defined(SERIAL_USART_FULL_DUPLEX) - if (success) { - /* Half duplex fills the input queue with the data we wrote - just throw it away. - Under the right circumstances (e.g. bad cables paired with high baud rates) - less bytes can be present in the input queue, therefore a timeout is needed. */ - uint8_t dump[size]; - return receive(dump, size); + /* Half duplex fills the input queue with the data we wrote - just throw it away. */ + if (likely(success)) { + size_t bytes_left = size; +# if HAL_USE_SERIAL + /* The SERIAL driver uses large soft FIFOs that are filled from an IRQ + * context, so there is a delay between receiving the data and it + * becoming actually available, therefore we have to apply a timeout + * mechanism. Under the right circumstances (e.g. bad cables paired with + * high baud rates) less bytes can be present in the input queue as + * well. */ + uint8_t dump[64]; + + while (unlikely(bytes_left >= 64)) { + if (unlikely(!receive(dump, 64))) { + return false; + } + bytes_left -= 64; + } + + return receive(dump, bytes_left); +# else + /* The SIO driver directly accesses the hardware FIFOs of the USART + * peripheral. As these are limited in depth, the RX FIFO might have been + * overflowed by a large that we just send. Therefore we attempt to read + * back all the data we send or until the FIFO runs empty in case it + * overflowed and data was truncated. */ + if (unlikely(sioSynchronizeTXEnd(serial_driver, TIME_MS2I(SERIAL_USART_TIMEOUT)) < MSG_OK)) { + return false; + } + + osalSysLock(); + while (bytes_left > 0 && !sioIsRXEmptyX(serial_driver)) { + (void)sioGetX(serial_driver); + bytes_left--; + } + osalSysUnlock(); +# endif } #endif @@ -90,10 +163,21 @@ static inline bool send(const uint8_t* source, const size_t size) { * @brief Blocking receive of size * bytes with timeout. * * @return true Receive success. - * @return false Receive failed. + * @return false Receive failed, e.g. by timeout. */ static inline bool receive(uint8_t* destination, const size_t size) { - bool success = (size_t)sdReadTimeout(serial_driver, destination, size, TIME_MS2I(SERIAL_USART_TIMEOUT)) == size; + bool success = (size_t)chnReadTimeout(serial_driver, destination, size, TIME_MS2I(SERIAL_USART_TIMEOUT)) == size; + return success; +} + +/** + * @brief Blocking receive of size * bytes. + * + * @return true Receive success. + * @return false Receive failed. + */ +static inline bool receive_blocking(uint8_t* destination, const size_t size) { + bool success = (size_t)chnRead(serial_driver, destination, size) == size; return success; } @@ -146,7 +230,7 @@ __attribute__((weak)) void usart_init(void) { /** * @brief Overridable master specific initializations. */ -__attribute__((weak, nonnull)) void usart_master_init(SerialDriver** driver) { +__attribute__((weak, nonnull)) void usart_master_init(QMKSerialDriver** driver) { (void)driver; usart_init(); } @@ -154,7 +238,7 @@ __attribute__((weak, nonnull)) void usart_master_init(SerialDriver** driver) { /** * @brief Overridable slave specific initializations. */ -__attribute__((weak, nonnull)) void usart_slave_init(SerialDriver** driver) { +__attribute__((weak, nonnull)) void usart_slave_init(QMKSerialDriver** driver) { (void)driver; usart_init(); } @@ -169,7 +253,7 @@ static THD_FUNCTION(SlaveThread, arg) { chRegSetThreadName("usart_tx_rx"); while (true) { - if (!react_to_transactions()) { + if (unlikely(!react_to_transactions())) { /* Clear the receive queue, to start with a clean slate. * Parts of failed transactions or spurious bytes could still be in it. */ usart_clear(); @@ -184,7 +268,7 @@ static THD_FUNCTION(SlaveThread, arg) { void soft_serial_target_init(void) { usart_slave_init(&serial_driver); - sdStart(serial_driver, &serial_config); + usart_driver_start(); /* Start transport thread. */ chThdCreateStatic(waSlaveThread, sizeof(waSlaveThread), HIGHPRIO, SlaveThread, NULL); @@ -195,10 +279,11 @@ void soft_serial_target_init(void) { */ static inline bool react_to_transactions(void) { /* Wait until there is a transaction for us. */ - uint8_t sstd_index = (uint8_t)sdGet(serial_driver); + uint8_t sstd_index = 0; + receive_blocking(&sstd_index, sizeof(sstd_index)); /* Sanity check that we are actually responding to a valid transaction. */ - if (sstd_index >= NUM_TOTAL_TRANSACTIONS) { + if (unlikely(sstd_index >= NUM_TOTAL_TRANSACTIONS)) { return false; } @@ -208,13 +293,13 @@ static inline bool react_to_transactions(void) { /* Send back the handshake which is XORed as a simple checksum, to signal that the slave is ready to receive possible transaction buffers */ sstd_index ^= HANDSHAKE_MAGIC; - if (!send(&sstd_index, sizeof(sstd_index))) { + if (unlikely(!send(&sstd_index, sizeof(sstd_index)))) { return false; } /* Receive transaction buffer from the master. If this transaction requires it.*/ if (trans->initiator2target_buffer_size) { - if (!receive(split_trans_initiator2target_buffer(trans), trans->initiator2target_buffer_size)) { + if (unlikely(!receive(split_trans_initiator2target_buffer(trans), trans->initiator2target_buffer_size))) { return false; } } @@ -226,7 +311,7 @@ static inline bool react_to_transactions(void) { /* Send transaction buffer to the master. If this transaction requires it. */ if (trans->target2initiator_buffer_size) { - if (!send(split_trans_target2initiator_buffer(trans), trans->target2initiator_buffer_size)) { + if (unlikely(!send(split_trans_target2initiator_buffer(trans), trans->target2initiator_buffer_size))) { return false; } } @@ -244,7 +329,7 @@ void soft_serial_initiator_init(void) { serial_config.cr2 |= USART_CR2_SWAP; // master has swapped TX/RX pins #endif - sdStart(serial_driver, &serial_config); + usart_driver_start(); } /** @@ -270,7 +355,7 @@ bool soft_serial_transaction(int index) { */ static inline bool initiate_transaction(uint8_t sstd_index) { /* Sanity check that we are actually starting a valid transaction. */ - if (sstd_index >= NUM_TOTAL_TRANSACTIONS) { + if (unlikely(sstd_index >= NUM_TOTAL_TRANSACTIONS)) { dprintln("USART: Illegal transaction Id."); return false; } @@ -278,7 +363,7 @@ static inline bool initiate_transaction(uint8_t sstd_index) { split_transaction_desc_t* trans = &split_transaction_table[sstd_index]; /* Send transaction table index to the slave, which doubles as basic handshake token. */ - if (!send(&sstd_index, sizeof(sstd_index))) { + if (unlikely(!send(&sstd_index, sizeof(sstd_index)))) { dprintln("USART: Send Handshake failed."); return false; } @@ -289,14 +374,14 @@ static inline bool initiate_transaction(uint8_t sstd_index) { * - due to the half duplex limitations on return codes, we always have to read *something*. * - without the read, write only transactions *always* succeed, even during the boot process where the slave is not ready. */ - if (!receive(&sstd_index_shake, sizeof(sstd_index_shake)) || (sstd_index_shake != (sstd_index ^ HANDSHAKE_MAGIC))) { + if (unlikely(!receive(&sstd_index_shake, sizeof(sstd_index_shake)) || (sstd_index_shake != (sstd_index ^ HANDSHAKE_MAGIC)))) { dprintln("USART: Handshake failed."); return false; } /* Send transaction buffer to the slave. If this transaction requires it. */ if (trans->initiator2target_buffer_size) { - if (!send(split_trans_initiator2target_buffer(trans), trans->initiator2target_buffer_size)) { + if (unlikely(!send(split_trans_initiator2target_buffer(trans), trans->initiator2target_buffer_size))) { dprintln("USART: Send failed."); return false; } @@ -304,7 +389,7 @@ static inline bool initiate_transaction(uint8_t sstd_index) { /* Receive transaction buffer from the slave. If this transaction requires it. */ if (trans->target2initiator_buffer_size) { - if (!receive(split_trans_target2initiator_buffer(trans), trans->target2initiator_buffer_size)) { + if (unlikely(!receive(split_trans_target2initiator_buffer(trans), trans->target2initiator_buffer_size))) { dprintln("USART: Receive failed."); return false; } diff --git a/platforms/chibios/drivers/serial_usart.h b/platforms/chibios/drivers/serial_usart.h index 81fe9e0113..98c634dac0 100644 --- a/platforms/chibios/drivers/serial_usart.h +++ b/platforms/chibios/drivers/serial_usart.h @@ -1,18 +1,5 @@ -/* Copyright 2021 QMK - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ +// Copyright 2021 QMK +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -23,8 +10,24 @@ #include #include -#if !defined(SERIAL_USART_DRIVER) -# define SERIAL_USART_DRIVER SD1 +#if HAL_USE_SERIAL + +typedef SerialDriver QMKSerialDriver; +typedef SerialConfig QMKSerialConfig; + +# if !defined(SERIAL_USART_DRIVER) +# define SERIAL_USART_DRIVER SD1 +# endif + +#elif HAL_USE_SIO + +typedef SIODriver QMKSerialDriver; +typedef SIOConfig QMKSerialConfig; + +# if !defined(SERIAL_USART_DRIVER) +# define SERIAL_USART_DRIVER SIOD1 +# endif + #endif #if !defined(USE_GPIOV1) @@ -113,4 +116,4 @@ # define SERIAL_USART_TIMEOUT 20 #endif -#define HANDSHAKE_MAGIC 7 +#define HANDSHAKE_MAGIC 7U -- cgit v1.2.3 From fe680a8568d275732738b07166b8f8a950d1e282 Mon Sep 17 00:00:00 2001 From: Stefan Kerkmann Date: Sat, 18 Jun 2022 00:04:17 +0200 Subject: [Core] Split ChibiOS usart split driver in protocol and hardware driver part (#16669) --- platforms/chibios/drivers/serial.c | 4 +- platforms/chibios/drivers/serial_protocol.c | 164 ++++++++++++++++++++++++ platforms/chibios/drivers/serial_protocol.h | 49 +++++++ platforms/chibios/drivers/serial_usart.c | 191 ++-------------------------- platforms/chibios/drivers/serial_usart.h | 81 ++++++------ 5 files changed, 263 insertions(+), 226 deletions(-) create mode 100644 platforms/chibios/drivers/serial_protocol.c create mode 100644 platforms/chibios/drivers/serial_protocol.h (limited to 'platforms') diff --git a/platforms/chibios/drivers/serial.c b/platforms/chibios/drivers/serial.c index 0cff057d1d..e5f346ba33 100644 --- a/platforms/chibios/drivers/serial.c +++ b/platforms/chibios/drivers/serial.c @@ -233,7 +233,7 @@ static inline bool initiate_transaction(uint8_t sstd_index) { // check if the slave is present if (serial_read_pin()) { // slave failed to pull the line low, assume not present - dprintf("serial::NO_RESPONSE\n"); + serial_dprintf("serial::NO_RESPONSE\n"); chSysUnlock(); return false; } @@ -269,7 +269,7 @@ static inline bool initiate_transaction(uint8_t sstd_index) { serial_delay(); if ((checksum_computed) != (checksum_received)) { - dprintf("serial::FAIL[%u,%u,%u]\n", checksum_computed, checksum_received, sstd_index); + serial_dprintf("serial::FAIL[%u,%u,%u]\n", checksum_computed, checksum_received, sstd_index); serial_output(); serial_high(); diff --git a/platforms/chibios/drivers/serial_protocol.c b/platforms/chibios/drivers/serial_protocol.c new file mode 100644 index 0000000000..3e160e0c5c --- /dev/null +++ b/platforms/chibios/drivers/serial_protocol.c @@ -0,0 +1,164 @@ +// Copyright 2022 Stefan Kerkmann +// SPDX-License-Identifier: GPL-2.0-or-later + +#include + +#include "quantum.h" +#include "serial.h" +#include "serial_protocol.h" +#include "printf.h" +#include "synchronization_util.h" + +static inline bool initiate_transaction(uint8_t transaction_id); +static inline bool react_to_transaction(void); + +/** + * @brief This thread runs on the slave and responds to transactions initiated + * by the master. + */ +static THD_WORKING_AREA(waSlaveThread, 1024); +static THD_FUNCTION(SlaveThread, arg) { + (void)arg; + chRegSetThreadName("split_protocol_tx_rx"); + + while (true) { + split_shared_memory_lock(); + if (unlikely(!react_to_transaction())) { + /* Clear the receive queue, to start with a clean slate. + * Parts of failed transactions or spurious bytes could still be in it. */ + serial_transport_driver_clear(); + } + split_shared_memory_unlock(); + } +} + +/** + * @brief Slave specific initializations. + */ +void soft_serial_target_init(void) { + serial_transport_driver_slave_init(); + + /* Start transport thread. */ + chThdCreateStatic(waSlaveThread, sizeof(waSlaveThread), HIGHPRIO, SlaveThread, NULL); +} + +/** + * @brief Master specific initializations. + */ +void soft_serial_initiator_init(void) { + serial_transport_driver_master_init(); +} + +/** + * @brief React to transactions started by the master. + */ +static inline bool react_to_transaction(void) { + uint8_t transaction_id = 0; + /* Wait until there is a transaction for us. */ + if (unlikely(!serial_transport_receive_blocking(&transaction_id, sizeof(transaction_id)))) { + return false; + } + + /* Sanity check that we are actually responding to a valid transaction. */ + if (unlikely(transaction_id >= NUM_TOTAL_TRANSACTIONS)) { + return false; + } + + split_transaction_desc_t* transaction = &split_transaction_table[transaction_id]; + + /* Send back the handshake which is XORed as a simple checksum, + to signal that the slave is ready to receive possible transaction buffers */ + transaction_id ^= NUM_TOTAL_TRANSACTIONS; + if (unlikely(!serial_transport_send(&transaction_id, sizeof(transaction_id)))) { + return false; + } + + /* Receive transaction buffer from the master. If this transaction requires it.*/ + if (transaction->initiator2target_buffer_size) { + if (unlikely(!serial_transport_receive(split_trans_initiator2target_buffer(transaction), transaction->initiator2target_buffer_size))) { + return false; + } + } + + /* Allow any slave processing to occur. */ + if (transaction->slave_callback) { + transaction->slave_callback(transaction->initiator2target_buffer_size, split_trans_initiator2target_buffer(transaction), transaction->initiator2target_buffer_size, split_trans_target2initiator_buffer(transaction)); + } + + /* Send transaction buffer to the master. If this transaction requires it. */ + if (transaction->target2initiator_buffer_size) { + if (unlikely(!serial_transport_send(split_trans_target2initiator_buffer(transaction), transaction->target2initiator_buffer_size))) { + return false; + } + } + + return true; +} + +/** + * @brief Start transaction from the master half to the slave half. + * + * @param index Transaction Table index of the transaction to start. + * @return bool Indicates success of transaction. + */ +bool soft_serial_transaction(int index) { + split_shared_memory_lock(); + bool result = initiate_transaction((uint8_t)index); + split_shared_memory_unlock(); + + if (unlikely(!result)) { + /* Clear the receive queue, to start with a clean slate. + * Parts of failed transactions or spurious bytes could still be in it. */ + serial_transport_driver_clear(); + } + + return result; +} + +/** + * @brief Initiate transaction to slave half. + */ +static inline bool initiate_transaction(uint8_t transaction_id) { + /* Sanity check that we are actually starting a valid transaction. */ + if (unlikely(transaction_id >= NUM_TOTAL_TRANSACTIONS)) { + serial_dprintf("SPLIT: illegal transaction id\n"); + return false; + } + + split_transaction_desc_t* transaction = &split_transaction_table[transaction_id]; + + /* Send transaction table index to the slave, which doubles as basic handshake token. */ + if (unlikely(!serial_transport_send(&transaction_id, sizeof(transaction_id)))) { + serial_dprintf("SPLIT: sending handshake failed\n"); + return false; + } + + uint8_t transaction_id_shake = 0xFF; + + /* Which we always read back first so that we can error out correctly. + * - due to the half duplex limitations on return codes, we always have to read *something*. + * - without the read, write only transactions *always* succeed, even during the boot process where the slave is not ready. + */ + if (unlikely(!serial_transport_receive(&transaction_id_shake, sizeof(transaction_id_shake)) || (transaction_id_shake != (transaction_id ^ NUM_TOTAL_TRANSACTIONS)))) { + serial_dprintf("SPLIT: receiving handshake failed\n"); + return false; + } + + /* Send transaction buffer to the slave. If this transaction requires it. */ + if (transaction->initiator2target_buffer_size) { + if (unlikely(!serial_transport_send(split_trans_initiator2target_buffer(transaction), transaction->initiator2target_buffer_size))) { + serial_dprintf("SPLIT: sending buffer failed\n"); + return false; + } + } + + /* Receive transaction buffer from the slave. If this transaction requires it. */ + if (transaction->target2initiator_buffer_size) { + if (unlikely(!serial_transport_receive(split_trans_target2initiator_buffer(transaction), transaction->target2initiator_buffer_size))) { + serial_dprintf("SPLIT: receiving buffer failed\n"); + return false; + } + } + + return true; +} diff --git a/platforms/chibios/drivers/serial_protocol.h b/platforms/chibios/drivers/serial_protocol.h new file mode 100644 index 0000000000..4275a7f8d8 --- /dev/null +++ b/platforms/chibios/drivers/serial_protocol.h @@ -0,0 +1,49 @@ +// Copyright 2022 Stefan Kerkmann +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include +#include + +#pragma once + +/** + * @brief Clears any intermediate sending or receiving state of the driver to a known good + * state. This happens after errors in the middle of transactions, to start with + * a clean slate. + */ +void serial_transport_driver_clear(void); + +/** + * @brief Driver specific initialization on the slave half. + */ +void serial_transport_driver_slave_init(void); + +/** + * @brief Driver specific specific initialization on the master half. + */ +void serial_transport_driver_master_init(void); + +/** + * @brief Blocking receive of size * bytes. + * + * @return true Receive success. + * @return false Receive failed, e.g. by bit errors. + */ +bool __attribute__((nonnull, hot)) serial_transport_receive(uint8_t* destination, const size_t size); + +/** + * @brief Blocking receive of size * bytes with an implicitly defined timeout. + * + * @return true Receive success. + * @return false Receive failed, e.g. by timeout or bit errors. + */ +bool __attribute__((nonnull, hot)) serial_transport_receive_blocking(uint8_t* destination, const size_t size); + +/** + * @brief Blocking send of buffer with timeout. + * + * @return true Send success. + * @return false Send failed, e.g. by timeout or bit errors. + */ +bool __attribute__((nonnull, hot)) serial_transport_send(const uint8_t* source, const size_t size); diff --git a/platforms/chibios/drivers/serial_usart.c b/platforms/chibios/drivers/serial_usart.c index 7ea25d005b..f76afb5db4 100644 --- a/platforms/chibios/drivers/serial_usart.c +++ b/platforms/chibios/drivers/serial_usart.c @@ -3,6 +3,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "serial_usart.h" +#include "serial_protocol.h" #include "synchronization_util.h" #if defined(SERIAL_USART_CONFIG) @@ -26,14 +27,6 @@ static QMKSerialConfig serial_config = { static QMKSerialDriver* serial_driver = (QMKSerialDriver*)&SERIAL_USART_DRIVER; -static inline bool react_to_transactions(void); -static inline bool __attribute__((nonnull)) receive(uint8_t* destination, const size_t size); -static inline bool __attribute__((nonnull)) receive_blocking(uint8_t* destination, const size_t size); -static inline bool __attribute__((nonnull)) send(const uint8_t* source, const size_t size); -static inline bool initiate_transaction(uint8_t sstd_index); -static inline void usart_clear(void); -static inline void usart_driver_start(void); - #if HAL_USE_SERIAL /** @@ -43,10 +36,7 @@ static inline void usart_driver_start(void) { sdStart(serial_driver, &serial_config); } -/** - * @brief Clear the receive input queue. - */ -static inline void usart_clear(void) { +inline void serial_transport_driver_clear(void) { osalSysLock(); bool volatile queue_not_empty = !iqIsEmptyI(&serial_driver->iqueue); osalSysUnlock(); @@ -89,10 +79,7 @@ static inline void usart_driver_start(void) { sioStartOperation(serial_driver, &serial_usart_operation); } -/** - * @brief Clear the receive input queue, as some MCUs have built-in hardware FIFOs. - */ -static inline void usart_clear(void) { +inline void serial_transport_driver_clear(void) { osalSysLock(); while (!sioIsRXEmptyX(serial_driver)) { (void)sioGetX(serial_driver); @@ -106,13 +93,7 @@ static inline void usart_clear(void) { #endif -/** - * @brief Blocking send of buffer with timeout. - * - * @return true Send success. - * @return false Send failed. - */ -static inline bool send(const uint8_t* source, const size_t size) { +inline bool serial_transport_send(const uint8_t* source, const size_t size) { bool success = (size_t)chnWriteTimeout(serial_driver, source, size, TIME_MS2I(SERIAL_USART_TIMEOUT)) == size; #if !defined(SERIAL_USART_FULL_DUPLEX) @@ -129,13 +110,13 @@ static inline bool send(const uint8_t* source, const size_t size) { uint8_t dump[64]; while (unlikely(bytes_left >= 64)) { - if (unlikely(!receive(dump, 64))) { + if (unlikely(!serial_transport_receive(dump, 64))) { return false; } bytes_left -= 64; } - return receive(dump, bytes_left); + return serial_transport_receive(dump, bytes_left); # else /* The SIO driver directly accesses the hardware FIFOs of the USART * peripheral. As these are limited in depth, the RX FIFO might have been @@ -159,24 +140,12 @@ static inline bool send(const uint8_t* source, const size_t size) { return success; } -/** - * @brief Blocking receive of size * bytes with timeout. - * - * @return true Receive success. - * @return false Receive failed, e.g. by timeout. - */ -static inline bool receive(uint8_t* destination, const size_t size) { +inline bool serial_transport_receive(uint8_t* destination, const size_t size) { bool success = (size_t)chnReadTimeout(serial_driver, destination, size, TIME_MS2I(SERIAL_USART_TIMEOUT)) == size; return success; } -/** - * @brief Blocking receive of size * bytes. - * - * @return true Receive success. - * @return false Receive failed. - */ -static inline bool receive_blocking(uint8_t* destination, const size_t size) { +inline bool serial_transport_receive_blocking(uint8_t* destination, const size_t size) { bool success = (size_t)chnRead(serial_driver, destination, size) == size; return success; } @@ -243,86 +212,12 @@ __attribute__((weak, nonnull)) void usart_slave_init(QMKSerialDriver** driver) { usart_init(); } -/** - * @brief This thread runs on the slave and responds to transactions initiated - * by the master. - */ -static THD_WORKING_AREA(waSlaveThread, 1024); -static THD_FUNCTION(SlaveThread, arg) { - (void)arg; - chRegSetThreadName("usart_tx_rx"); - - while (true) { - if (unlikely(!react_to_transactions())) { - /* Clear the receive queue, to start with a clean slate. - * Parts of failed transactions or spurious bytes could still be in it. */ - usart_clear(); - } - split_shared_memory_unlock(); - } -} - -/** - * @brief Slave specific initializations. - */ -void soft_serial_target_init(void) { +void serial_transport_driver_slave_init(void) { usart_slave_init(&serial_driver); - usart_driver_start(); - - /* Start transport thread. */ - chThdCreateStatic(waSlaveThread, sizeof(waSlaveThread), HIGHPRIO, SlaveThread, NULL); -} - -/** - * @brief React to transactions started by the master. - */ -static inline bool react_to_transactions(void) { - /* Wait until there is a transaction for us. */ - uint8_t sstd_index = 0; - receive_blocking(&sstd_index, sizeof(sstd_index)); - - /* Sanity check that we are actually responding to a valid transaction. */ - if (unlikely(sstd_index >= NUM_TOTAL_TRANSACTIONS)) { - return false; - } - - split_shared_memory_lock(); - split_transaction_desc_t* trans = &split_transaction_table[sstd_index]; - - /* Send back the handshake which is XORed as a simple checksum, - to signal that the slave is ready to receive possible transaction buffers */ - sstd_index ^= HANDSHAKE_MAGIC; - if (unlikely(!send(&sstd_index, sizeof(sstd_index)))) { - return false; - } - - /* Receive transaction buffer from the master. If this transaction requires it.*/ - if (trans->initiator2target_buffer_size) { - if (unlikely(!receive(split_trans_initiator2target_buffer(trans), trans->initiator2target_buffer_size))) { - return false; - } - } - - /* Allow any slave processing to occur. */ - if (trans->slave_callback) { - trans->slave_callback(trans->initiator2target_buffer_size, split_trans_initiator2target_buffer(trans), trans->initiator2target_buffer_size, split_trans_target2initiator_buffer(trans)); - } - - /* Send transaction buffer to the master. If this transaction requires it. */ - if (trans->target2initiator_buffer_size) { - if (unlikely(!send(split_trans_target2initiator_buffer(trans), trans->target2initiator_buffer_size))) { - return false; - } - } - - return true; } -/** - * @brief Master specific initializations. - */ -void soft_serial_initiator_init(void) { +void serial_transport_driver_master_init(void) { usart_master_init(&serial_driver); #if defined(MCU_STM32) && defined(SERIAL_USART_PIN_SWAP) @@ -331,69 +226,3 @@ void soft_serial_initiator_init(void) { usart_driver_start(); } - -/** - * @brief Start transaction from the master half to the slave half. - * - * @param index Transaction Table index of the transaction to start. - * @return bool Indicates success of transaction. - */ -bool soft_serial_transaction(int index) { - /* Clear the receive queue, to start with a clean slate. - * Parts of failed transactions or spurious bytes could still be in it. */ - usart_clear(); - - split_shared_memory_lock(); - bool result = initiate_transaction((uint8_t)index); - split_shared_memory_unlock(); - - return result; -} - -/** - * @brief Initiate transaction to slave half. - */ -static inline bool initiate_transaction(uint8_t sstd_index) { - /* Sanity check that we are actually starting a valid transaction. */ - if (unlikely(sstd_index >= NUM_TOTAL_TRANSACTIONS)) { - dprintln("USART: Illegal transaction Id."); - return false; - } - - split_transaction_desc_t* trans = &split_transaction_table[sstd_index]; - - /* Send transaction table index to the slave, which doubles as basic handshake token. */ - if (unlikely(!send(&sstd_index, sizeof(sstd_index)))) { - dprintln("USART: Send Handshake failed."); - return false; - } - - uint8_t sstd_index_shake = 0xFF; - - /* Which we always read back first so that we can error out correctly. - * - due to the half duplex limitations on return codes, we always have to read *something*. - * - without the read, write only transactions *always* succeed, even during the boot process where the slave is not ready. - */ - if (unlikely(!receive(&sstd_index_shake, sizeof(sstd_index_shake)) || (sstd_index_shake != (sstd_index ^ HANDSHAKE_MAGIC)))) { - dprintln("USART: Handshake failed."); - return false; - } - - /* Send transaction buffer to the slave. If this transaction requires it. */ - if (trans->initiator2target_buffer_size) { - if (unlikely(!send(split_trans_initiator2target_buffer(trans), trans->initiator2target_buffer_size))) { - dprintln("USART: Send failed."); - return false; - } - } - - /* Receive transaction buffer from the slave. If this transaction requires it. */ - if (trans->target2initiator_buffer_size) { - if (unlikely(!receive(split_trans_target2initiator_buffer(trans), trans->target2initiator_buffer_size))) { - dprintln("USART: Receive failed."); - return false; - } - } - - return true; -} diff --git a/platforms/chibios/drivers/serial_usart.h b/platforms/chibios/drivers/serial_usart.h index 98c634dac0..fa062cd736 100644 --- a/platforms/chibios/drivers/serial_usart.h +++ b/platforms/chibios/drivers/serial_usart.h @@ -5,11 +5,46 @@ #include "quantum.h" #include "serial.h" -#include "printf.h" - -#include #include +#if defined(SOFT_SERIAL_PIN) +# define SERIAL_USART_TX_PIN SOFT_SERIAL_PIN +#endif + +#if !defined(SERIAL_USART_TX_PIN) +# define SERIAL_USART_TX_PIN A9 +#endif + +#if !defined(SERIAL_USART_RX_PIN) +# define SERIAL_USART_RX_PIN A10 +#endif + +#if !defined(SELECT_SOFT_SERIAL_SPEED) +# define SELECT_SOFT_SERIAL_SPEED 1 +#endif + +#if defined(SERIAL_USART_SPEED) +// Allow advanced users to directly set SERIAL_USART_SPEED +#elif SELECT_SOFT_SERIAL_SPEED == 0 +# define SERIAL_USART_SPEED 460800 +#elif SELECT_SOFT_SERIAL_SPEED == 1 +# define SERIAL_USART_SPEED 230400 +#elif SELECT_SOFT_SERIAL_SPEED == 2 +# define SERIAL_USART_SPEED 115200 +#elif SELECT_SOFT_SERIAL_SPEED == 3 +# define SERIAL_USART_SPEED 57600 +#elif SELECT_SOFT_SERIAL_SPEED == 4 +# define SERIAL_USART_SPEED 38400 +#elif SELECT_SOFT_SERIAL_SPEED == 5 +# define SERIAL_USART_SPEED 19200 +#else +# error invalid SELECT_SOFT_SERIAL_SPEED value +#endif + +#if !defined(SERIAL_USART_TIMEOUT) +# define SERIAL_USART_TIMEOUT 20 +#endif + #if HAL_USE_SERIAL typedef SerialDriver QMKSerialDriver; @@ -40,18 +75,6 @@ typedef SIOConfig QMKSerialConfig; # endif #endif -#if defined(SOFT_SERIAL_PIN) -# define SERIAL_USART_TX_PIN SOFT_SERIAL_PIN -#endif - -#if !defined(SERIAL_USART_TX_PIN) -# define SERIAL_USART_TX_PIN A9 -#endif - -#if !defined(SERIAL_USART_RX_PIN) -# define SERIAL_USART_RX_PIN A10 -#endif - #if !defined(USART_CR1_M0) # define USART_CR1_M0 USART_CR1_M // some platforms (f1xx) dont have this so #endif @@ -89,31 +112,3 @@ typedef SIOConfig QMKSerialConfig; (AFIO->MAPR |= AFIO_MAPR_USART3_REMAP_FULLREMAP); \ } while (0) #endif - -#if !defined(SELECT_SOFT_SERIAL_SPEED) -# define SELECT_SOFT_SERIAL_SPEED 1 -#endif - -#if defined(SERIAL_USART_SPEED) -// Allow advanced users to directly set SERIAL_USART_SPEED -#elif SELECT_SOFT_SERIAL_SPEED == 0 -# define SERIAL_USART_SPEED 460800 -#elif SELECT_SOFT_SERIAL_SPEED == 1 -# define SERIAL_USART_SPEED 230400 -#elif SELECT_SOFT_SERIAL_SPEED == 2 -# define SERIAL_USART_SPEED 115200 -#elif SELECT_SOFT_SERIAL_SPEED == 3 -# define SERIAL_USART_SPEED 57600 -#elif SELECT_SOFT_SERIAL_SPEED == 4 -# define SERIAL_USART_SPEED 38400 -#elif SELECT_SOFT_SERIAL_SPEED == 5 -# define SERIAL_USART_SPEED 19200 -#else -# error invalid SELECT_SOFT_SERIAL_SPEED value -#endif - -#if !defined(SERIAL_USART_TIMEOUT) -# define SERIAL_USART_TIMEOUT 20 -#endif - -#define HANDSHAKE_MAGIC 7U -- cgit v1.2.3 From 2703ecc9e98819ab4d13bdb6da6e0d02ee840d86 Mon Sep 17 00:00:00 2001 From: Stefan Kerkmann Date: Tue, 21 Jun 2022 00:24:53 +0200 Subject: [BUG] Fix deadlocks on disconnected secondary half (#17423) --- platforms/chibios/drivers/serial.c | 11 ++++------- platforms/chibios/drivers/serial_protocol.c | 8 ++++---- platforms/synchronization_util.h | 30 +++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 11 deletions(-) (limited to 'platforms') diff --git a/platforms/chibios/drivers/serial.c b/platforms/chibios/drivers/serial.c index e5f346ba33..3fae5cd3a4 100644 --- a/platforms/chibios/drivers/serial.c +++ b/platforms/chibios/drivers/serial.c @@ -87,10 +87,7 @@ static THD_FUNCTION(Thread1, arg) { chRegSetThreadName("blinker"); while (true) { palWaitLineTimeout(SOFT_SERIAL_PIN, TIME_INFINITE); - - split_shared_memory_lock(); interrupt_handler(NULL); - split_shared_memory_unlock(); } } @@ -155,6 +152,7 @@ static void __attribute__((noinline)) serial_write_byte(uint8_t data) { // interrupt handle to be used by the slave device void interrupt_handler(void *arg) { + split_shared_memory_lock_autounlock(); chSysLockFromISR(); sync_send(); @@ -212,6 +210,8 @@ void interrupt_handler(void *arg) { static inline bool initiate_transaction(uint8_t sstd_index) { if (sstd_index > NUM_TOTAL_TRANSACTIONS) return false; + split_shared_memory_lock_autounlock(); + split_transaction_desc_t *trans = &split_transaction_table[sstd_index]; // TODO: remove extra delay between transactions @@ -292,8 +292,5 @@ static inline bool initiate_transaction(uint8_t sstd_index) { // // this code is very time dependent, so we need to disable interrupts bool soft_serial_transaction(int sstd_index) { - split_shared_memory_lock(); - bool result = initiate_transaction((uint8_t)sstd_index); - split_shared_memory_unlock(); - return result; + return initiate_transaction((uint8_t)sstd_index); } diff --git a/platforms/chibios/drivers/serial_protocol.c b/platforms/chibios/drivers/serial_protocol.c index 3e160e0c5c..c95aed9885 100644 --- a/platforms/chibios/drivers/serial_protocol.c +++ b/platforms/chibios/drivers/serial_protocol.c @@ -22,13 +22,11 @@ static THD_FUNCTION(SlaveThread, arg) { chRegSetThreadName("split_protocol_tx_rx"); while (true) { - split_shared_memory_lock(); if (unlikely(!react_to_transaction())) { /* Clear the receive queue, to start with a clean slate. * Parts of failed transactions or spurious bytes could still be in it. */ serial_transport_driver_clear(); } - split_shared_memory_unlock(); } } @@ -64,6 +62,8 @@ static inline bool react_to_transaction(void) { return false; } + split_shared_memory_lock_autounlock(); + split_transaction_desc_t* transaction = &split_transaction_table[transaction_id]; /* Send back the handshake which is XORed as a simple checksum, @@ -102,9 +102,7 @@ static inline bool react_to_transaction(void) { * @return bool Indicates success of transaction. */ bool soft_serial_transaction(int index) { - split_shared_memory_lock(); bool result = initiate_transaction((uint8_t)index); - split_shared_memory_unlock(); if (unlikely(!result)) { /* Clear the receive queue, to start with a clean slate. @@ -125,6 +123,8 @@ static inline bool initiate_transaction(uint8_t transaction_id) { return false; } + split_shared_memory_lock_autounlock(); + split_transaction_desc_t* transaction = &split_transaction_table[transaction_id]; /* Send transaction table index to the slave, which doubles as basic handshake token. */ diff --git a/platforms/synchronization_util.h b/platforms/synchronization_util.h index 3730f271db..81ce074cac 100644 --- a/platforms/synchronization_util.h +++ b/platforms/synchronization_util.h @@ -12,3 +12,33 @@ void split_shared_memory_unlock(void); inline void split_shared_memory_lock(void){}; inline void split_shared_memory_unlock(void){}; #endif + +/* GCCs cleanup attribute expects a function with one parameter, which is a + * pointer to a type compatible with the variable. As we don't want to expose + * the platforms internal mutex type this workaround with auto generated adapter + * function is defined */ +#define QMK_DECLARE_AUTOUNLOCK_HELPERS(prefix) \ + inline unsigned prefix##_autounlock_lock_helper(void) { \ + prefix##_lock(); \ + return 0; \ + } \ + \ + inline void prefix##_autounlock_unlock_helper(unsigned* unused_guard) { \ + prefix##_unlock(); \ + } + +/* Convinience macro the automatically generate the correct RAII-style + * lock_autounlock function macro */ +#define QMK_DECLARE_AUTOUNLOCK_CALL(prefix) unsigned prefix##_guard __attribute__((unused, cleanup(prefix##_autounlock_unlock_helper))) = prefix##_autounlock_lock_helper + +QMK_DECLARE_AUTOUNLOCK_HELPERS(split_shared_memory) + +/** + * @brief Acquire exclusive access to the split keyboard shared memory, by + * calling the platforms `split_shared_memory_lock()` function. The lock is + * automatically released by calling the platforms `split_shared_memory_unlock()` + * function. This happens when the block where + * `split_shared_memory_lock_autounlock()` is called in goes out of scope i.e. + * when the enclosing function returns. + */ +#define split_shared_memory_lock_autounlock QMK_DECLARE_AUTOUNLOCK_CALL(split_shared_memory) -- cgit v1.2.3 From 6a81cb44f2ec10472fd58496ad18f812798cc275 Mon Sep 17 00:00:00 2001 From: Stefan Kerkmann Date: Tue, 21 Jun 2022 01:31:20 +0200 Subject: [Fix] Fix compilation warning for non-split keebs after #17423 (#17439) --- platforms/synchronization_util.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'platforms') diff --git a/platforms/synchronization_util.h b/platforms/synchronization_util.h index 81ce074cac..59933945c3 100644 --- a/platforms/synchronization_util.h +++ b/platforms/synchronization_util.h @@ -9,8 +9,10 @@ void split_shared_memory_lock(void); void split_shared_memory_unlock(void); # endif #else +# if defined(SPLIT_KEYBOARD) inline void split_shared_memory_lock(void){}; inline void split_shared_memory_unlock(void){}; +# endif #endif /* GCCs cleanup attribute expects a function with one parameter, which is a @@ -31,6 +33,7 @@ inline void split_shared_memory_unlock(void){}; * lock_autounlock function macro */ #define QMK_DECLARE_AUTOUNLOCK_CALL(prefix) unsigned prefix##_guard __attribute__((unused, cleanup(prefix##_autounlock_unlock_helper))) = prefix##_autounlock_lock_helper +#if defined(SPLIT_KEYBOARD) QMK_DECLARE_AUTOUNLOCK_HELPERS(split_shared_memory) /** @@ -41,4 +44,5 @@ QMK_DECLARE_AUTOUNLOCK_HELPERS(split_shared_memory) * `split_shared_memory_lock_autounlock()` is called in goes out of scope i.e. * when the enclosing function returns. */ -#define split_shared_memory_lock_autounlock QMK_DECLARE_AUTOUNLOCK_CALL(split_shared_memory) +# define split_shared_memory_lock_autounlock QMK_DECLARE_AUTOUNLOCK_CALL(split_shared_memory) +#endif -- cgit v1.2.3 From 608404f8742f01d1821a74c5a107e0c62b046423 Mon Sep 17 00:00:00 2001 From: Daniel Kao Date: Tue, 21 Jun 2022 15:00:04 -0700 Subject: Fix AVR I2C master 1ms timeout (#17174) * avr i2c_master: Fix 1ms timeout i2c_start() produces a minimum time_slice of 1ms for use as timeout value. The timer granularity is 1ms, it is entirely possible for timer_count to tick up immediately after the last timer read and falsely trigger timeout with a '>= 1' comparison. * avr/drivers/i2c_master: Use timer_elapsed() --- platforms/avr/drivers/i2c_master.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'platforms') diff --git a/platforms/avr/drivers/i2c_master.c b/platforms/avr/drivers/i2c_master.c index c1a7b5f72d..524494c99d 100644 --- a/platforms/avr/drivers/i2c_master.c +++ b/platforms/avr/drivers/i2c_master.c @@ -64,7 +64,7 @@ static i2c_status_t i2c_start_impl(uint8_t address, uint16_t timeout) { uint16_t timeout_timer = timer_read(); while (!(TWCR & (1 << TWINT))) { - if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) { + if ((timeout != I2C_TIMEOUT_INFINITE) && (timer_elapsed(timeout_timer) > timeout)) { return I2C_STATUS_TIMEOUT; } } @@ -81,7 +81,7 @@ static i2c_status_t i2c_start_impl(uint8_t address, uint16_t timeout) { timeout_timer = timer_read(); while (!(TWCR & (1 << TWINT))) { - if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) { + if ((timeout != I2C_TIMEOUT_INFINITE) && (timer_elapsed(timeout_timer) > timeout)) { return I2C_STATUS_TIMEOUT; } } @@ -102,7 +102,7 @@ i2c_status_t i2c_start(uint8_t address, uint16_t timeout) { i2c_status_t status; do { status = i2c_start_impl(address, time_slice); - } while ((status < 0) && ((timeout == I2C_TIMEOUT_INFINITE) || (timer_elapsed(timeout_timer) < timeout))); + } while ((status < 0) && ((timeout == I2C_TIMEOUT_INFINITE) || (timer_elapsed(timeout_timer) <= timeout))); return status; } @@ -114,7 +114,7 @@ i2c_status_t i2c_write(uint8_t data, uint16_t timeout) { uint16_t timeout_timer = timer_read(); while (!(TWCR & (1 << TWINT))) { - if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) { + if ((timeout != I2C_TIMEOUT_INFINITE) && (timer_elapsed(timeout_timer) > timeout)) { return I2C_STATUS_TIMEOUT; } } @@ -132,7 +132,7 @@ int16_t i2c_read_ack(uint16_t timeout) { uint16_t timeout_timer = timer_read(); while (!(TWCR & (1 << TWINT))) { - if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) { + if ((timeout != I2C_TIMEOUT_INFINITE) && (timer_elapsed(timeout_timer) > timeout)) { return I2C_STATUS_TIMEOUT; } } @@ -147,7 +147,7 @@ int16_t i2c_read_nack(uint16_t timeout) { uint16_t timeout_timer = timer_read(); while (!(TWCR & (1 << TWINT))) { - if ((timeout != I2C_TIMEOUT_INFINITE) && ((timer_read() - timeout_timer) >= timeout)) { + if ((timeout != I2C_TIMEOUT_INFINITE) && (timer_elapsed(timeout_timer) > timeout)) { return I2C_STATUS_TIMEOUT; } } -- cgit v1.2.3 From 9aa9155e880da4d408a4da19ff56007046a0d3b9 Mon Sep 17 00:00:00 2001 From: Stefan Kerkmann Date: Thu, 23 Jun 2022 00:37:40 +0200 Subject: [Core] Mark GD32VF103 as ChibiOS-Contrib (#17444) --- platforms/chibios/platform.mk | 1 + 1 file changed, 1 insertion(+) (limited to 'platforms') diff --git a/platforms/chibios/platform.mk b/platforms/chibios/platform.mk index 21751f23fd..a30ca62bf5 100644 --- a/platforms/chibios/platform.mk +++ b/platforms/chibios/platform.mk @@ -36,6 +36,7 @@ ifeq ($(strip $(MCU)), risc-v) # RISC-V Support # As of 7.4.2021 there is only one supported RISC-V platform in Chibios-Contrib, # therefore all required settings are hard-coded + USE_CHIBIOS_CONTRIB = yes STARTUP_MK = $(CHIBIOS_CONTRIB)/os/common/startup/RISCV-ECLIC/compilers/GCC/mk/startup_$(MCU_STARTUP).mk PORT_V = $(CHIBIOS_CONTRIB)/os/common/ports/RISCV-ECLIC/compilers/GCC/mk/port.mk RULESPATH = $(CHIBIOS_CONTRIB)/os/common/startup/RISCV-ECLIC/compilers/GCC -- cgit v1.2.3 From 7fd3d76faa92dd3291228e77533859793470683f Mon Sep 17 00:00:00 2001 From: Drashna Jaelre Date: Sat, 25 Jun 2022 12:34:40 -0700 Subject: [Split] Ensure SOFT_SERIAL_PIN is defined if USE_I2C isn't defined (#17466) --- platforms/avr/drivers/serial.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'platforms') diff --git a/platforms/avr/drivers/serial.c b/platforms/avr/drivers/serial.c index 6a36aa5f7f..730d9b7a01 100644 --- a/platforms/avr/drivers/serial.c +++ b/platforms/avr/drivers/serial.c @@ -498,6 +498,10 @@ bool soft_serial_transaction(int sstd_index) { sei(); return true; } +#else +# ifndef USE_I2C +# error SOFT_SERIAL_PIN or USE_I2C is required but has not been defined. +# endif #endif // Helix serial.c history -- cgit v1.2.3 From 34e244cecf62afb30ee5a4362867f24b03675691 Mon Sep 17 00:00:00 2001 From: Nick Brassel Date: Thu, 30 Jun 2022 07:42:23 +1000 Subject: Wear-leveling EEPROM drivers: `embedded_flash`, `spi_flash`, `legacy` (#17376) --- .../drivers/wear_leveling/wear_leveling_efl.c | 140 +++++++++++++++++++++ .../wear_leveling/wear_leveling_efl_config.h | 50 ++++++++ .../drivers/wear_leveling/wear_leveling_legacy.c | 59 +++++++++ .../wear_leveling/wear_leveling_legacy_config.h | 67 ++++++++++ platforms/chibios/platform.mk | 5 + platforms/eeprom.h | 2 + 6 files changed, 323 insertions(+) create mode 100644 platforms/chibios/drivers/wear_leveling/wear_leveling_efl.c create mode 100644 platforms/chibios/drivers/wear_leveling/wear_leveling_efl_config.h create mode 100644 platforms/chibios/drivers/wear_leveling/wear_leveling_legacy.c create mode 100644 platforms/chibios/drivers/wear_leveling/wear_leveling_legacy_config.h (limited to 'platforms') diff --git a/platforms/chibios/drivers/wear_leveling/wear_leveling_efl.c b/platforms/chibios/drivers/wear_leveling/wear_leveling_efl.c new file mode 100644 index 0000000000..4b5639ee4a --- /dev/null +++ b/platforms/chibios/drivers/wear_leveling/wear_leveling_efl.c @@ -0,0 +1,140 @@ +// Copyright 2022 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#include +#include +#include "timer.h" +#include "wear_leveling.h" +#include "wear_leveling_internal.h" + +static flash_offset_t base_offset = UINT32_MAX; + +#if defined(WEAR_LEVELING_EFL_FIRST_SECTOR) +static flash_sector_t first_sector = WEAR_LEVELING_EFL_FIRST_SECTOR; +#else // defined(WEAR_LEVELING_EFL_FIRST_SECTOR) +static flash_sector_t first_sector = UINT16_MAX; +#endif // defined(WEAR_LEVELING_EFL_FIRST_SECTOR) + +static flash_sector_t sector_count = UINT16_MAX; +static BaseFlash * flash; + +#ifndef WEAR_LEVELING_EFL_FIRST_SECTOR +// "Automatic" detection of the flash size -- ideally ChibiOS would have this already, but alas, it doesn't. +static inline uint32_t detect_flash_size(void) { +# if defined(WEAR_LEVELING_EFL_FLASH_SIZE) + return WEAR_LEVELING_EFL_FLASH_SIZE; +# elif defined(FLASH_BANK_SIZE) + return FLASH_BANK_SIZE; +# elif defined(FLASH_SIZE) + return FLASH_SIZE; +# elif defined(FLASHSIZE_BASE) +# if defined(QMK_MCU_SERIES_STM32F0XX) || defined(QMK_MCU_SERIES_STM32F1XX) || defined(QMK_MCU_SERIES_STM32F3XX) || defined(QMK_MCU_SERIES_STM32F4XX) || defined(QMK_MCU_SERIES_STM32G4XX) || defined(QMK_MCU_SERIES_STM32L0XX) || defined(QMK_MCU_SERIES_STM32L4XX) || defined(QMK_MCU_SERIES_GD32VF103) + return ((*(uint32_t *)FLASHSIZE_BASE) & 0xFFFFU) << 10U; // this register has the flash size in kB, so we convert it to bytes +# elif defined(QMK_MCU_SERIES_STM32L1XX) +# error This MCU family has an uncommon flash size register definition and has not been implemented. Perhaps try using the true EEPROM on the MCU instead? +# endif +# else +# error Unknown flash size definition. + return 0; +# endif +} +#endif // WEAR_LEVELING_EFL_FIRST_SECTOR + +bool backing_store_init(void) { + bs_dprintf("Init\n"); + flash = (BaseFlash *)&EFLD1; + + const flash_descriptor_t *desc = flashGetDescriptor(flash); + uint32_t counter = 0; + +#if defined(WEAR_LEVELING_EFL_FIRST_SECTOR) + + // Work out how many sectors we want to use, working forwards from the first sector specified + for (flash_sector_t i = 0; i < desc->sectors_count - first_sector; ++i) { + counter += flashGetSectorSize(flash, first_sector + i); + if (counter >= (WEAR_LEVELING_BACKING_SIZE)) { + sector_count = i + 1; + base_offset = flashGetSectorOffset(flash, first_sector); + break; + } + } + if (sector_count == UINT16_MAX || base_offset >= flash_size) { + // We didn't get the required number of sectors. Can't do anything here. Fault. + chSysHalt("Invalid sector count intended to be used with wear_leveling"); + } + +#else // defined(WEAR_LEVELING_EFL_FIRST_SECTOR) + + // Work out how many sectors we want to use, working backwards from the end of the flash + uint32_t flash_size = detect_flash_size(); + flash_sector_t last_sector = desc->sectors_count; + for (flash_sector_t i = 0; i < desc->sectors_count; ++i) { + first_sector = desc->sectors_count - i - 1; + if (flashGetSectorOffset(flash, first_sector) >= flash_size) { + last_sector = first_sector; + continue; + } + counter += flashGetSectorSize(flash, first_sector); + if (counter >= (WEAR_LEVELING_BACKING_SIZE)) { + sector_count = last_sector - first_sector; + base_offset = flashGetSectorOffset(flash, first_sector); + break; + } + } + +#endif // defined(WEAR_LEVELING_EFL_FIRST_SECTOR) + + return true; +} + +bool backing_store_unlock(void) { + bs_dprintf("Unlock\n"); + return eflStart(&EFLD1, NULL) == HAL_RET_SUCCESS; +} + +bool backing_store_erase(void) { +#ifdef WEAR_LEVELING_DEBUG_OUTPUT + uint32_t start = timer_read32(); +#endif + + bool ret = true; + flash_error_t status; + for (int i = 0; i < sector_count; ++i) { + // Kick off the sector erase + status = flashStartEraseSector(flash, first_sector + i); + if (status != FLASH_NO_ERROR && status != FLASH_BUSY_ERASING) { + ret = false; + } + + // Wait for the erase to complete + status = flashWaitErase(flash); + if (status != FLASH_NO_ERROR && status != FLASH_BUSY_ERASING) { + ret = false; + } + } + + bs_dprintf("Backing store erase took %ldms to complete\n", ((long)(timer_read32() - start))); + return ret; +} + +bool backing_store_write(uint32_t address, backing_store_int_t value) { + uint32_t offset = (base_offset + address); + bs_dprintf("Write "); + wl_dump(offset, &value, sizeof(value)); + value = ~value; + return flashProgram(flash, offset, sizeof(value), (const uint8_t *)&value) == FLASH_NO_ERROR; +} + +bool backing_store_lock(void) { + bs_dprintf("Lock \n"); + eflStop(&EFLD1); + return true; +} + +bool backing_store_read(uint32_t address, backing_store_int_t *value) { + uint32_t offset = (base_offset + address); + backing_store_int_t *loc = (backing_store_int_t *)offset; + *value = ~(*loc); + bs_dprintf("Read "); + wl_dump(offset, value, sizeof(backing_store_int_t)); + return true; +} diff --git a/platforms/chibios/drivers/wear_leveling/wear_leveling_efl_config.h b/platforms/chibios/drivers/wear_leveling/wear_leveling_efl_config.h new file mode 100644 index 0000000000..9e38c2965d --- /dev/null +++ b/platforms/chibios/drivers/wear_leveling/wear_leveling_efl_config.h @@ -0,0 +1,50 @@ +// Copyright 2022 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#pragma once + +#ifndef __ASSEMBLER__ +# include +#endif + +// Work out how many bytes per write to internal flash +#ifndef BACKING_STORE_WRITE_SIZE +// These need to match EFL's XXXXXX_FLASH_LINE_SIZE, see associated code in `lib/chibios/os/hal/ports/**/hal_efl_lld.c`, +// or associated `stm32_registry.h` for the MCU in question (or equivalent for the family). +# if defined(QMK_MCU_SERIES_GD32VF103) +# define BACKING_STORE_WRITE_SIZE 2 // from hal_efl_lld.c +# elif defined(QMK_MCU_FAMILY_NUC123) +# define BACKING_STORE_WRITE_SIZE 4 // from hal_efl_lld.c +# elif defined(QMK_MCU_FAMILY_STM32) +# if defined(STM32_FLASH_LINE_SIZE) // from some family's stm32_registry.h file +# define BACKING_STORE_WRITE_SIZE (STM32_FLASH_LINE_SIZE) +# else +# if defined(QMK_MCU_SERIES_STM32F1XX) +# define BACKING_STORE_WRITE_SIZE 2 // from hal_efl_lld.c +# elif defined(QMK_MCU_SERIES_STM32F3XX) +# define BACKING_STORE_WRITE_SIZE 2 // from hal_efl_lld.c +# elif defined(QMK_MCU_SERIES_STM32F4XX) +# define BACKING_STORE_WRITE_SIZE (1 << STM32_FLASH_PSIZE) // from hal_efl_lld.c +# elif defined(QMK_MCU_SERIES_STM32L4XX) +# define BACKING_STORE_WRITE_SIZE 8 // from hal_efl_lld.c +# elif defined(QMK_MCU_SERIES_STM32G0XX) +# define BACKING_STORE_WRITE_SIZE 8 // from hal_efl_lld.c +# elif defined(QMK_MCU_SERIES_STM32G4XX) +# define BACKING_STORE_WRITE_SIZE 8 // from hal_efl_lld.c +# else +# error "ChibiOS hasn't defined STM32_FLASH_LINE_SIZE, and could not automatically determine BACKING_STORE_WRITE_SIZE" // normally defined in stm32_registry.h, should be set by STM32_FLASH_LINE_SIZE +# endif +# endif +# else +# error "Could not automatically determine BACKING_STORE_WRITE_SIZE" +# endif +#endif + +// 2kB backing space allocated +#ifndef WEAR_LEVELING_BACKING_SIZE +# define WEAR_LEVELING_BACKING_SIZE 2048 +#endif // WEAR_LEVELING_BACKING_SIZE + +// 1kB logical EEPROM +#ifndef WEAR_LEVELING_LOGICAL_SIZE +# define WEAR_LEVELING_LOGICAL_SIZE 1024 +#endif // WEAR_LEVELING_LOGICAL_SIZE diff --git a/platforms/chibios/drivers/wear_leveling/wear_leveling_legacy.c b/platforms/chibios/drivers/wear_leveling/wear_leveling_legacy.c new file mode 100644 index 0000000000..87126c4467 --- /dev/null +++ b/platforms/chibios/drivers/wear_leveling/wear_leveling_legacy.c @@ -0,0 +1,59 @@ +// Copyright 2022 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#include +#include +#include "timer.h" +#include "wear_leveling.h" +#include "wear_leveling_internal.h" +#include "flash_stm32.h" + +bool backing_store_init(void) { + bs_dprintf("Init\n"); + return true; +} + +bool backing_store_unlock(void) { + bs_dprintf("Unlock\n"); + FLASH_Unlock(); + return true; +} + +bool backing_store_erase(void) { +#ifdef WEAR_LEVELING_DEBUG_OUTPUT + uint32_t start = timer_read32(); +#endif + + bool ret = true; + FLASH_Status status; + for (int i = 0; i < (WEAR_LEVELING_LEGACY_EMULATION_PAGE_COUNT); ++i) { + status = FLASH_ErasePage(WEAR_LEVELING_LEGACY_EMULATION_BASE_PAGE_ADDRESS + (i * (WEAR_LEVELING_LEGACY_EMULATION_PAGE_SIZE))); + if (status != FLASH_COMPLETE) { + ret = false; + } + } + + bs_dprintf("Backing store erase took %ldms to complete\n", ((long)(timer_read32() - start))); + return ret; +} + +bool backing_store_write(uint32_t address, backing_store_int_t value) { + uint32_t offset = ((WEAR_LEVELING_LEGACY_EMULATION_BASE_PAGE_ADDRESS) + address); + bs_dprintf("Write "); + wl_dump(offset, &value, sizeof(backing_store_int_t)); + return FLASH_ProgramHalfWord(offset, ~value) == FLASH_COMPLETE; +} + +bool backing_store_lock(void) { + bs_dprintf("Lock \n"); + FLASH_Lock(); + return true; +} + +bool backing_store_read(uint32_t address, backing_store_int_t* value) { + uint32_t offset = ((WEAR_LEVELING_LEGACY_EMULATION_BASE_PAGE_ADDRESS) + address); + backing_store_int_t* loc = (backing_store_int_t*)offset; + *value = ~(*loc); + bs_dprintf("Read "); + wl_dump(offset, loc, sizeof(backing_store_int_t)); + return true; +} diff --git a/platforms/chibios/drivers/wear_leveling/wear_leveling_legacy_config.h b/platforms/chibios/drivers/wear_leveling/wear_leveling_legacy_config.h new file mode 100644 index 0000000000..1e4691a6c0 --- /dev/null +++ b/platforms/chibios/drivers/wear_leveling/wear_leveling_legacy_config.h @@ -0,0 +1,67 @@ +// Copyright 2022 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#pragma once + +// Work out the page size to use +#ifndef WEAR_LEVELING_LEGACY_EMULATION_PAGE_SIZE +# if defined(QMK_MCU_STM32F042) +# define WEAR_LEVELING_LEGACY_EMULATION_PAGE_SIZE 1024 +# elif defined(QMK_MCU_STM32F070) || defined(QMK_MCU_STM32F072) +# define WEAR_LEVELING_LEGACY_EMULATION_PAGE_SIZE 2048 +# elif defined(QMK_MCU_STM32F401) || defined(QMK_MCU_STM32F411) +# define WEAR_LEVELING_LEGACY_EMULATION_PAGE_SIZE 16384 +# endif +#endif + +// Work out how much flash space we have +#ifndef WEAR_LEVELING_LEGACY_EMULATION_FLASH_SIZE +# define WEAR_LEVELING_LEGACY_EMULATION_FLASH_SIZE ((*(uint32_t *)FLASHSIZE_BASE) & 0xFFFFU) // in kB +#endif + +// The base location of program memory +#ifndef WEAR_LEVELING_LEGACY_EMULATION_FLASH_BASE +# define WEAR_LEVELING_LEGACY_EMULATION_FLASH_BASE 0x08000000 +#endif + +// The number of pages to use +#ifndef WEAR_LEVELING_LEGACY_EMULATION_PAGE_COUNT +# if defined(QMK_MCU_STM32F042) +# define WEAR_LEVELING_LEGACY_EMULATION_PAGE_COUNT 2 +# elif defined(QMK_MCU_STM32F070) || defined(QMK_MCU_STM32F072) +# define WEAR_LEVELING_LEGACY_EMULATION_PAGE_COUNT 1 +# elif defined(QMK_MCU_STM32F401) || defined(QMK_MCU_STM32F411) +# define WEAR_LEVELING_LEGACY_EMULATION_PAGE_COUNT 1 +# endif +#endif + +// The origin of the emulated eeprom +#ifndef WEAR_LEVELING_LEGACY_EMULATION_BASE_PAGE_ADDRESS +# if defined(QMK_MCU_STM32F042) || defined(QMK_MCU_STM32F070) || defined(QMK_MCU_STM32F072) +# define WEAR_LEVELING_LEGACY_EMULATION_BASE_PAGE_ADDRESS ((uintptr_t)(WEAR_LEVELING_LEGACY_EMULATION_FLASH_BASE) + WEAR_LEVELING_LEGACY_EMULATION_FLASH_SIZE * 1024 - (WEAR_LEVELING_LEGACY_EMULATION_PAGE_COUNT * WEAR_LEVELING_LEGACY_EMULATION_PAGE_SIZE)) +# elif defined(QMK_MCU_STM32F401) || defined(QMK_MCU_STM32F411) +# if defined(BOOTLOADER_STM32) +# define WEAR_LEVELING_LEGACY_EMULATION_BASE_PAGE_ADDRESS (WEAR_LEVELING_LEGACY_EMULATION_FLASH_BASE + (1 * (WEAR_LEVELING_LEGACY_EMULATION_PAGE_SIZE))) // +16k +# elif defined(BOOTLOADER_TINYUF2) +# define WEAR_LEVELING_LEGACY_EMULATION_BASE_PAGE_ADDRESS (WEAR_LEVELING_LEGACY_EMULATION_FLASH_BASE + (3 * (WEAR_LEVELING_LEGACY_EMULATION_PAGE_SIZE))) // +48k +# endif +# endif +#endif + +// 2-byte writes +#ifndef BACKING_STORE_WRITE_SIZE +# define BACKING_STORE_WRITE_SIZE 2 +#endif + +// The amount of space to use for the entire set of emulation +#ifndef WEAR_LEVELING_BACKING_SIZE +# if defined(QMK_MCU_STM32F042) || defined(QMK_MCU_STM32F070) || defined(QMK_MCU_STM32F072) +# define WEAR_LEVELING_BACKING_SIZE 2048 +# elif defined(QMK_MCU_STM32F401) || defined(QMK_MCU_STM32F411) +# define WEAR_LEVELING_BACKING_SIZE 16384 +# endif +#endif + +// The logical amount of eeprom available +#ifndef WEAR_LEVELING_LOGICAL_SIZE +# define WEAR_LEVELING_LOGICAL_SIZE 1024 +#endif diff --git a/platforms/chibios/platform.mk b/platforms/chibios/platform.mk index a30ca62bf5..72428a762f 100644 --- a/platforms/chibios/platform.mk +++ b/platforms/chibios/platform.mk @@ -94,6 +94,11 @@ ifeq ("$(wildcard $(PLATFORM_MK))","") endif endif +# If no MCU architecture specified, use the MCU instead (allows for mcu_selection.mk to swap to cortex-m0 etc.) +ifeq ("$(MCU_ARCH)","") + MCU_ARCH = $(MCU) +endif + include $(STARTUP_MK) include $(PORT_V) include $(PLATFORM_MK) diff --git a/platforms/eeprom.h b/platforms/eeprom.h index 091e6e4400..8cb7e342dc 100644 --- a/platforms/eeprom.h +++ b/platforms/eeprom.h @@ -27,6 +27,8 @@ void eeprom_update_block(const void *__src, void *__dst, size_t __n); # error EEPROM_SIZE has not been defined for custom driver. # endif # define TOTAL_EEPROM_BYTE_COUNT (EEPROM_SIZE) +#elif defined(EEPROM_WEAR_LEVELING) +# define TOTAL_EEPROM_BYTE_COUNT (WEAR_LEVELING_LOGICAL_SIZE) #elif defined(EEPROM_TRANSIENT) # include "eeprom_transient.h" # define TOTAL_EEPROM_BYTE_COUNT (TRANSIENT_EEPROM_SIZE) -- cgit v1.2.3 From d7173967087e022d20d1f9c812b1b668e9d3f71b Mon Sep 17 00:00:00 2001 From: Stefan Kerkmann Date: Thu, 30 Jun 2022 13:19:27 +0200 Subject: [Core] Add Raspberry Pi RP2040 support (#14877) * Disable RESET keycode because of naming conflicts * Add Pico SDK as submodule * Add RP2040 build support to QMK * Adjust USB endpoint structs for RP2040 * Add RP2040 bootloader and double-tap reset routine * Add generic and pro micro RP2040 boards * Add RP2040 onekey keyboard * Add WS2812 PIO DMA enabled driver and documentation Supports regular and open-drain output configuration. RP2040 GPIOs are sadly not 5V tolerant, so this is a bit use-less or needs extra hardware or you take the risk to fry your hardware. * Adjust SIO Driver for RP2040 * Adjust I2C Driver for RP2040 * Adjust SPI Driver for RP2040 * Add PIO serial driver and documentation * Add general RP2040 documentation * Apply suggestions from code review Co-authored-by: Nick Brassel Co-authored-by: Nick Brassel --- platforms/chibios/_pin_defs.h | 5 + .../boards/GENERIC_PROMICRO_RP2040/board/board.mk | 9 + .../boards/GENERIC_PROMICRO_RP2040/configs/board.h | 12 + .../GENERIC_PROMICRO_RP2040/configs/chconf.h | 13 + .../GENERIC_PROMICRO_RP2040/configs/config.h | 62 +++ .../GENERIC_PROMICRO_RP2040/configs/mcuconf.h | 98 +++++ .../boards/GENERIC_RP_RP2040/board/board.mk | 9 + .../boards/GENERIC_RP_RP2040/configs/board.h | 12 + .../boards/GENERIC_RP_RP2040/configs/chconf.h | 13 + .../boards/GENERIC_RP_RP2040/configs/mcuconf.h | 98 +++++ platforms/chibios/bootloaders/rp2040.c | 57 +++ platforms/chibios/chibios_config.h | 21 + platforms/chibios/drivers/serial_usart.c | 28 +- platforms/chibios/drivers/spi_master.c | 31 +- .../drivers/vendor/RP/RP2040/serial_vendor.c | 457 +++++++++++++++++++++ .../drivers/vendor/RP/RP2040/ws2812_vendor.c | 189 +++++++++ platforms/chibios/flash.mk | 2 + platforms/chibios/platform.mk | 15 +- platforms/chibios/vendors/RP/RP2040.mk | 285 +++++++++++++ platforms/chibios/vendors/RP/_pin_defs.h | 37 ++ platforms/chibios/vendors/RP/pico_sdk_shims.c | 9 + platforms/chibios/vendors/RP/stage2_bootloaders.c | 174 ++++++++ 22 files changed, 1628 insertions(+), 8 deletions(-) create mode 100644 platforms/chibios/boards/GENERIC_PROMICRO_RP2040/board/board.mk create mode 100644 platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/board.h create mode 100644 platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/chconf.h create mode 100644 platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/config.h create mode 100644 platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/mcuconf.h create mode 100644 platforms/chibios/boards/GENERIC_RP_RP2040/board/board.mk create mode 100644 platforms/chibios/boards/GENERIC_RP_RP2040/configs/board.h create mode 100644 platforms/chibios/boards/GENERIC_RP_RP2040/configs/chconf.h create mode 100644 platforms/chibios/boards/GENERIC_RP_RP2040/configs/mcuconf.h create mode 100644 platforms/chibios/bootloaders/rp2040.c create mode 100644 platforms/chibios/drivers/vendor/RP/RP2040/serial_vendor.c create mode 100644 platforms/chibios/drivers/vendor/RP/RP2040/ws2812_vendor.c create mode 100644 platforms/chibios/vendors/RP/RP2040.mk create mode 100644 platforms/chibios/vendors/RP/_pin_defs.h create mode 100644 platforms/chibios/vendors/RP/pico_sdk_shims.c create mode 100644 platforms/chibios/vendors/RP/stage2_bootloaders.c (limited to 'platforms') diff --git a/platforms/chibios/_pin_defs.h b/platforms/chibios/_pin_defs.h index 0d96e2fc3b..414c9e3d11 100644 --- a/platforms/chibios/_pin_defs.h +++ b/platforms/chibios/_pin_defs.h @@ -21,6 +21,11 @@ # include #endif +/* Include the vendor specific pin defs */ +#if __has_include_next("_pin_defs.h") +# include_next "_pin_defs.h" +#endif + #define A0 PAL_LINE(GPIOA, 0) #define A1 PAL_LINE(GPIOA, 1) #define A2 PAL_LINE(GPIOA, 2) diff --git a/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/board/board.mk b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/board/board.mk new file mode 100644 index 0000000000..911cc5a058 --- /dev/null +++ b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/board/board.mk @@ -0,0 +1,9 @@ +# List of all the board related files. +BOARDSRC = $(CHIBIOS)/os/hal/boards/RP_PICO_RP2040/board.c + +# Required include directories +BOARDINC = $(CHIBIOS)/os/hal/boards/RP_PICO_RP2040 + +# Shared variables +ALLCSRC += $(BOARDSRC) +ALLINC += $(BOARDINC) diff --git a/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/board.h b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/board.h new file mode 100644 index 0000000000..b4363595d0 --- /dev/null +++ b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/board.h @@ -0,0 +1,12 @@ +// Copyright 2022 Stefan Kerkmann +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include_next "board.h" + +#undef BOARD_RP_PICO_RP2040 +#define BOARD_GENERIC_PROMICRO_RP2040 + +#undef BOARD_NAME +#define BOARD_NAME "Pro Micro RP2040" diff --git a/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/chconf.h b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/chconf.h new file mode 100644 index 0000000000..d53f57edd9 --- /dev/null +++ b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/chconf.h @@ -0,0 +1,13 @@ +// Copyright 2022 Stefan Kerkmann +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#define CH_CFG_SMP_MODE TRUE +#define CH_CFG_ST_RESOLUTION 32 +#define CH_CFG_ST_FREQUENCY 1000000 +#define CH_CFG_INTERVALS_SIZE 32 +#define CH_CFG_TIME_TYPES_SIZE 32 +#define CH_CFG_ST_TIMEDELTA 20 + +#include_next diff --git a/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/config.h b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/config.h new file mode 100644 index 0000000000..7fe9b654e1 --- /dev/null +++ b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/config.h @@ -0,0 +1,62 @@ +// Copyright 2022 Stefan Kerkmann +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +/**====================== + ** I2C Driver + *========================**/ + +#if !defined(I2C_DRIVER) +# define I2C_DRIVER I2CD2 +#endif + +#if !defined(I2C1_SDA_PIN) +# define I2C1_SDA_PIN GP2 +#endif + +#if !defined(I2C1_SCL_PIN) +# define I2C1_SCL_PIN GP3 +#endif + +/**====================== + ** SPI Driver + *========================**/ + +#if !defined(SPI_DRIVER) +# define SPI_DRIVER SPID0 +#endif + +#if !defined(SPI_SCK_PIN) +# define SPI_SCK_PIN GP18 +#endif + +#if !defined(SPI_MISO_PIN) +# define SPI_MISO_PIN GP20 +#endif + +#if !defined(SPI_MOSI_PIN) +# define SPI_MOSI_PIN GP19 +#endif + +/**====================== + ** SERIAL Driver + *========================**/ + +#if !defined(SERIAL_USART_DRIVER) +# define SERIAL_USART_DRIVER SIOD0 +#endif + +#if !defined(SERIAL_USART_TX_PIN) && !defined(SOFT_SERIAL_PIN) +# define SERIAL_USART_TX_PIN GP0 +#endif + +#if !defined(SERIAL_USART_RX_PIN) +# define SERIAL_USART_RX_PIN GP1 +#endif + +/**====================== + ** Double-tap + *========================**/ + +#define RP2040_BOOTLOADER_DOUBLE_TAP_RESET diff --git a/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/mcuconf.h b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/mcuconf.h new file mode 100644 index 0000000000..8348e5312f --- /dev/null +++ b/platforms/chibios/boards/GENERIC_PROMICRO_RP2040/configs/mcuconf.h @@ -0,0 +1,98 @@ +/* + ChibiOS - Copyright (C) 2006..2021 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#ifndef MCUCONF_H +#define MCUCONF_H + +/* + * RP2040_MCUCONF drivers configuration. + * + * IRQ priorities: + * 3...0 Lowest...Highest. + * + * DMA priorities: + * 0...1 Lowest...Highest. + */ + +#define RP2040_MCUCONF + +/* + * HAL driver system settings. + */ +#define RP_NO_INIT FALSE +#define RP_CORE1_START FALSE +#define RP_CORE1_VECTORS_TABLE _vectors +#define RP_CORE1_ENTRY_POINT _crt0_c1_entry +#define RP_CORE1_STACK_END __c1_main_stack_end__ + +/* + * IRQ system settings. + */ +#define RP_IRQ_SYSTICK_PRIORITY 2 +#define RP_IRQ_TIMER_ALARM0_PRIORITY 2 +#define RP_IRQ_TIMER_ALARM1_PRIORITY 2 +#define RP_IRQ_TIMER_ALARM2_PRIORITY 2 +#define RP_IRQ_TIMER_ALARM3_PRIORITY 2 +#define RP_IRQ_UART0_PRIORITY 3 +#define RP_IRQ_UART1_PRIORITY 3 +#define RP_IRQ_SPI0_PRIORITY 2 +#define RP_IRQ_SPI1_PRIORITY 2 +#define RP_IRQ_USB0_PRIORITY 3 +#define RP_IRQ_I2C0_PRIORITY 2 +#define RP_IRQ_I2C1_PRIORITY 2 + +/* + * ADC driver system settings. + */ +#define RP_ADC_USE_ADC1 FALSE + +/* + * SIO driver system settings. + */ +#define RP_SIO_USE_UART0 TRUE +#define RP_SIO_USE_UART1 FALSE + +/* + * SPI driver system settings. + */ +#define RP_SPI_USE_SPI0 TRUE +#define RP_SPI_USE_SPI1 FALSE +#define RP_SPI_SPI0_RX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY +#define RP_SPI_SPI0_TX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY +#define RP_SPI_SPI1_RX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY +#define RP_SPI_SPI1_TX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY +#define RP_SPI_SPI0_DMA_PRIORITY 1 +#define RP_SPI_SPI1_DMA_PRIORITY 1 +#define RP_SPI_DMA_ERROR_HOOK(spip) + +/* + * I2C driver system settings. + */ +#define RP_I2C_USE_I2C0 FALSE +#define RP_I2C_USE_I2C1 TRUE +#define RP_I2C_BUSY_TIMEOUT 50 +#define RP_I2C_ADDRESS_MODE_10BIT FALSE + +/* + * USB driver system settings. + */ +#define RP_USB_USE_USBD0 TRUE +#define RP_USB_FORCE_VBUS_DETECT TRUE +#define RP_USE_EXTERNAL_VBUS_DETECT FALSE +#define RP_USB_USE_SOF_INTR TRUE +#define RP_USB_USE_ERROR_DATA_SEQ_INTR FALSE + +#endif /* MCUCONF_H */ diff --git a/platforms/chibios/boards/GENERIC_RP_RP2040/board/board.mk b/platforms/chibios/boards/GENERIC_RP_RP2040/board/board.mk new file mode 100644 index 0000000000..911cc5a058 --- /dev/null +++ b/platforms/chibios/boards/GENERIC_RP_RP2040/board/board.mk @@ -0,0 +1,9 @@ +# List of all the board related files. +BOARDSRC = $(CHIBIOS)/os/hal/boards/RP_PICO_RP2040/board.c + +# Required include directories +BOARDINC = $(CHIBIOS)/os/hal/boards/RP_PICO_RP2040 + +# Shared variables +ALLCSRC += $(BOARDSRC) +ALLINC += $(BOARDINC) diff --git a/platforms/chibios/boards/GENERIC_RP_RP2040/configs/board.h b/platforms/chibios/boards/GENERIC_RP_RP2040/configs/board.h new file mode 100644 index 0000000000..052050c944 --- /dev/null +++ b/platforms/chibios/boards/GENERIC_RP_RP2040/configs/board.h @@ -0,0 +1,12 @@ +// Copyright 2022 Stefan Kerkmann +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include_next "board.h" + +#undef BOARD_RP_PICO_RP2040 +#define BOARD_GENERIC_RP2040 + +#undef BOARD_NAME +#define BOARD_NAME "Generic Raspberry Pi RP2040" diff --git a/platforms/chibios/boards/GENERIC_RP_RP2040/configs/chconf.h b/platforms/chibios/boards/GENERIC_RP_RP2040/configs/chconf.h new file mode 100644 index 0000000000..d53f57edd9 --- /dev/null +++ b/platforms/chibios/boards/GENERIC_RP_RP2040/configs/chconf.h @@ -0,0 +1,13 @@ +// Copyright 2022 Stefan Kerkmann +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#define CH_CFG_SMP_MODE TRUE +#define CH_CFG_ST_RESOLUTION 32 +#define CH_CFG_ST_FREQUENCY 1000000 +#define CH_CFG_INTERVALS_SIZE 32 +#define CH_CFG_TIME_TYPES_SIZE 32 +#define CH_CFG_ST_TIMEDELTA 20 + +#include_next diff --git a/platforms/chibios/boards/GENERIC_RP_RP2040/configs/mcuconf.h b/platforms/chibios/boards/GENERIC_RP_RP2040/configs/mcuconf.h new file mode 100644 index 0000000000..9d8dc61aac --- /dev/null +++ b/platforms/chibios/boards/GENERIC_RP_RP2040/configs/mcuconf.h @@ -0,0 +1,98 @@ +/* + ChibiOS - Copyright (C) 2006..2021 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#ifndef MCUCONF_H +#define MCUCONF_H + +/* + * RP2040_MCUCONF drivers configuration. + * + * IRQ priorities: + * 3...0 Lowest...Highest. + * + * DMA priorities: + * 0...1 Lowest...Highest. + */ + +#define RP2040_MCUCONF + +/* + * HAL driver system settings. + */ +#define RP_NO_INIT FALSE +#define RP_CORE1_START FALSE +#define RP_CORE1_VECTORS_TABLE _vectors +#define RP_CORE1_ENTRY_POINT _crt0_c1_entry +#define RP_CORE1_STACK_END __c1_main_stack_end__ + +/* + * IRQ system settings. + */ +#define RP_IRQ_SYSTICK_PRIORITY 2 +#define RP_IRQ_TIMER_ALARM0_PRIORITY 2 +#define RP_IRQ_TIMER_ALARM1_PRIORITY 2 +#define RP_IRQ_TIMER_ALARM2_PRIORITY 2 +#define RP_IRQ_TIMER_ALARM3_PRIORITY 2 +#define RP_IRQ_UART0_PRIORITY 3 +#define RP_IRQ_UART1_PRIORITY 3 +#define RP_IRQ_SPI0_PRIORITY 2 +#define RP_IRQ_SPI1_PRIORITY 2 +#define RP_IRQ_USB0_PRIORITY 3 +#define RP_IRQ_I2C0_PRIORITY 2 +#define RP_IRQ_I2C1_PRIORITY 2 + +/* + * ADC driver system settings. + */ +#define RP_ADC_USE_ADC1 FALSE + +/* + * SIO driver system settings. + */ +#define RP_SIO_USE_UART0 FALSE +#define RP_SIO_USE_UART1 FALSE + +/* + * SPI driver system settings. + */ +#define RP_SPI_USE_SPI0 FALSE +#define RP_SPI_USE_SPI1 FALSE +#define RP_SPI_SPI0_RX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY +#define RP_SPI_SPI0_TX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY +#define RP_SPI_SPI1_RX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY +#define RP_SPI_SPI1_TX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY +#define RP_SPI_SPI0_DMA_PRIORITY 1 +#define RP_SPI_SPI1_DMA_PRIORITY 1 +#define RP_SPI_DMA_ERROR_HOOK(spip) + +/* + * I2C driver system settings. + */ +#define RP_I2C_USE_I2C0 FALSE +#define RP_I2C_USE_I2C1 FALSE +#define RP_I2C_BUSY_TIMEOUT 50 +#define RP_I2C_ADDRESS_MODE_10BIT FALSE + +/* + * USB driver system settings. + */ +#define RP_USB_USE_USBD0 TRUE +#define RP_USB_FORCE_VBUS_DETECT TRUE +#define RP_USE_EXTERNAL_VBUS_DETECT FALSE +#define RP_USB_USE_SOF_INTR TRUE +#define RP_USB_USE_ERROR_DATA_SEQ_INTR FALSE + +#endif /* MCUCONF_H */ diff --git a/platforms/chibios/bootloaders/rp2040.c b/platforms/chibios/bootloaders/rp2040.c new file mode 100644 index 0000000000..13a54036ef --- /dev/null +++ b/platforms/chibios/bootloaders/rp2040.c @@ -0,0 +1,57 @@ +// Copyright 2022 Stefan Kerkmann +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "quantum.h" +#include "hal.h" +#include "bootloader.h" +#include "pico/bootrom.h" + +#if !defined(RP2040_BOOTLOADER_DOUBLE_TAP_RESET_LED) +# define RP2040_BOOTLOADER_DOUBLE_TAP_RESET_LED_MASK 0U +#else +# define RP2040_BOOTLOADER_DOUBLE_TAP_RESET_LED_MASK (1U << RP2040_BOOTLOADER_DOUBLE_TAP_RESET_LED) +#endif + +__attribute__((weak)) void mcu_reset(void) { + NVIC_SystemReset(); +} +void bootloader_jump(void) { + reset_usb_boot(RP2040_BOOTLOADER_DOUBLE_TAP_RESET_LED_MASK, 0U); +} + +void enter_bootloader_mode_if_requested(void) {} + +#if defined(RP2040_BOOTLOADER_DOUBLE_TAP_RESET) +# if !defined(RP2040_BOOTLOADER_DOUBLE_TAP_RESET_TIMEOUT) +# define RP2040_BOOTLOADER_DOUBLE_TAP_RESET_TIMEOUT 200U +# endif + +// Needs to be located in a RAM section that is never initialized on boot to +// preserve its value on reset +static volatile uint32_t __attribute__((section(".ram0.bootloader_magic"))) magic_location; +const uint32_t magic_token = 0xCAFEB0BA; + +// We can not use the __early_init / enter_bootloader_mode_if_requested hook as +// we depend on an already initialized system with usable memory regions and +// populated function pointer tables to the optimized math functions in the +// bootrom. This function is called just prior to main. +void __late_init(void) { + // All clocks have to be enabled before jumping to the bootloader function, + // otherwise the bootrom will be stuck infinitely. + clocks_init(); + + if (magic_location != magic_token) { + magic_location = magic_token; + // ChibiOS is not initialized at this point, so sleeping is only + // possible via busy waiting. The internal timer peripheral is running + // at this point with a precision of 1us. + chSysPolledDelayX(MS2RTC(1 * MHZ, RP2040_BOOTLOADER_DOUBLE_TAP_RESET_TIMEOUT)); + magic_location = 0; + return; + } + + magic_location = 0; + reset_usb_boot(RP2040_BOOTLOADER_DOUBLE_TAP_RESET_LED_MASK, 0U); +} + +#endif diff --git a/platforms/chibios/chibios_config.h b/platforms/chibios/chibios_config.h index a7098f2713..1571bd5cd3 100644 --- a/platforms/chibios/chibios_config.h +++ b/platforms/chibios/chibios_config.h @@ -19,6 +19,27 @@ # define SPLIT_USB_DETECT // Force this on when dedicated pin is not used #endif +#if defined(MCU_RP) +# define CPU_CLOCK RP_CORE_CLK + +# define USE_GPIOV1 +# define PAL_OUTPUT_TYPE_OPENDRAIN _Static_assert(0, "RP2040 has no Open Drain GPIO configuration, setting this is not possible"); + +# define usb_lld_endpoint_fields + +# define I2C1_SCL_PAL_MODE (PAL_MODE_ALTERNATE_I2C | PAL_RP_PAD_SLEWFAST | PAL_RP_PAD_PUE | PAL_RP_PAD_DRIVE4) +# define I2C1_SDA_PAL_MODE I2C1_SCL_PAL_MODE + +# define USE_I2CV1_CONTRIB +# if !defined(I2C1_CLOCK_SPEED) +# define I2C1_CLOCK_SPEED 400000 +# endif + +# define SPI_SCK_PAL_MODE (PAL_MODE_ALTERNATE_SPI | PAL_RP_PAD_SLEWFAST | PAL_RP_PAD_DRIVE4) +# define SPI_MOSI_PAL_MODE SPI_SCK_PAL_MODE +# define SPI_MISO_PAL_MODE SPI_SCK_PAL_MODE +#endif + // STM32 compatibility #if defined(MCU_STM32) # define CPU_CLOCK STM32_SYSCLK diff --git a/platforms/chibios/drivers/serial_usart.c b/platforms/chibios/drivers/serial_usart.c index f76afb5db4..6581a5b6e9 100644 --- a/platforms/chibios/drivers/serial_usart.c +++ b/platforms/chibios/drivers/serial_usart.c @@ -8,12 +8,12 @@ #if defined(SERIAL_USART_CONFIG) static QMKSerialConfig serial_config = SERIAL_USART_CONFIG; -#else +#elif defined(MCU_STM32) /* STM32 MCUs */ static QMKSerialConfig serial_config = { # if HAL_USE_SERIAL - .speed = (SERIAL_USART_SPEED), /* baudrate - mandatory */ + .speed = (SERIAL_USART_SPEED), # else - .baud = (SERIAL_USART_SPEED), /* baudrate - mandatory */ + .baud = (SERIAL_USART_SPEED), # endif .cr1 = (SERIAL_USART_CR1), .cr2 = (SERIAL_USART_CR2), @@ -23,6 +23,19 @@ static QMKSerialConfig serial_config = { .cr3 = (SERIAL_USART_CR3) # endif }; +#elif defined(MCU_RP) /* Raspberry Pi MCUs */ +/* USART in 8E2 config with RX and TX FIFOs enabled. */ +// clang-format off +static QMKSerialConfig serial_config = { + .baud = (SERIAL_USART_SPEED), + .UARTLCR_H = UART_UARTLCR_H_WLEN_8BITS | UART_UARTLCR_H_PEN | UART_UARTLCR_H_STP2 | UART_UARTLCR_H_FEN, + .UARTCR = 0U, + .UARTIFLS = UART_UARTIFLS_RXIFLSEL_1_8F | UART_UARTIFLS_TXIFLSEL_1_8E, + .UARTDMACR = 0U +}; +// clang-format on +#else +# error MCU Familiy not supported by default, supply your own serial_config by defining SERIAL_USART_CONFIG in your keyboard files. #endif static QMKSerialDriver* serial_driver = (QMKSerialDriver*)&SERIAL_USART_DRIVER; @@ -156,7 +169,7 @@ inline bool serial_transport_receive_blocking(uint8_t* destination, const size_t * @brief Initiate pins for USART peripheral. Half-duplex configuration. */ __attribute__((weak)) void usart_init(void) { -# if defined(MCU_STM32) +# if defined(MCU_STM32) /* STM32 MCUs */ # if defined(USE_GPIOV1) palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE_OPENDRAIN); # else @@ -166,6 +179,8 @@ __attribute__((weak)) void usart_init(void) { # if defined(USART_REMAP) USART_REMAP; # endif +# elif defined(MCU_RP) /* Raspberry Pi MCUs */ +# error Half-duplex with the SIO driver is not supported due to hardware limitations on the RP2040, switch to the PIO driver which has half-duplex support. # else # pragma message "usart_init: MCU Familiy not supported by default, please supply your own init code by implementing usart_init() in your keyboard files." # endif @@ -177,7 +192,7 @@ __attribute__((weak)) void usart_init(void) { * @brief Initiate pins for USART peripheral. Full-duplex configuration. */ __attribute__((weak)) void usart_init(void) { -# if defined(MCU_STM32) +# if defined(MCU_STM32) /* STM32 MCUs */ # if defined(USE_GPIOV1) palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE_PUSHPULL); palSetLineMode(SERIAL_USART_RX_PIN, PAL_MODE_INPUT); @@ -189,6 +204,9 @@ __attribute__((weak)) void usart_init(void) { # if defined(USART_REMAP) USART_REMAP; # endif +# elif defined(MCU_RP) /* Raspberry Pi MCUs */ + palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE_UART); + palSetLineMode(SERIAL_USART_RX_PIN, PAL_MODE_ALTERNATE_UART); # else # pragma message "usart_init: MCU Familiy not supported by default, please supply your own init code by implementing usart_init() in your keyboard files." # endif diff --git a/platforms/chibios/drivers/spi_master.c b/platforms/chibios/drivers/spi_master.c index ce69e7f0ac..f9974d9f6b 100644 --- a/platforms/chibios/drivers/spi_master.c +++ b/platforms/chibios/drivers/spi_master.c @@ -20,7 +20,7 @@ static pin_t currentSlavePin = NO_PIN; -#if defined(K20x) || defined(KL2x) +#if defined(K20x) || defined(KL2x) || defined(RP2040) static SPIConfig spiConfig = {NULL, 0, 0, 0}; #else static SPIConfig spiConfig = {false, NULL, 0, 0, 0, 0}; @@ -167,7 +167,36 @@ bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) { spiConfig.SPI_CPOL = SPI_CPOL_High; break; } +#elif defined(MCU_RP) + if (lsbFirst) { + osalDbgAssert(lsbFirst == false, "RP2040s PrimeCell SPI implementation does not support sending LSB first."); + } + + // Motorola frame format and 8bit transfer data size. + spiConfig.SSPCR0 = SPI_SSPCR0_FRF_MOTOROLA | SPI_SSPCR0_DSS_8BIT; + // Serial output clock = (ck_sys or ck_peri) / (SSPCPSR->CPSDVSR * (1 + + // SSPCR0->SCR)). SCR is always set to zero, as QMK SPI API expects the + // passed divisor to be the only value to divide the input clock by. + spiConfig.SSPCPSR = roundedDivisor; // Even number from 2 to 254 + switch (mode) { + case 0: + spiConfig.SSPCR0 &= ~SPI_SSPCR0_SPO; // Clock polarity: low + spiConfig.SSPCR0 &= ~SPI_SSPCR0_SPH; // Clock phase: sample on first edge + break; + case 1: + spiConfig.SSPCR0 &= ~SPI_SSPCR0_SPO; // Clock polarity: low + spiConfig.SSPCR0 |= SPI_SSPCR0_SPH; // Clock phase: sample on second edge transition + break; + case 2: + spiConfig.SSPCR0 |= SPI_SSPCR0_SPO; // Clock polarity: high + spiConfig.SSPCR0 &= ~SPI_SSPCR0_SPH; // Clock phase: sample on first edge + break; + case 3: + spiConfig.SSPCR0 |= SPI_SSPCR0_SPO; // Clock polarity: high + spiConfig.SSPCR0 |= SPI_SSPCR0_SPH; // Clock phase: sample on second edge transition + break; + } #else spiConfig.cr1 = 0; diff --git a/platforms/chibios/drivers/vendor/RP/RP2040/serial_vendor.c b/platforms/chibios/drivers/vendor/RP/RP2040/serial_vendor.c new file mode 100644 index 0000000000..949fc6dd93 --- /dev/null +++ b/platforms/chibios/drivers/vendor/RP/RP2040/serial_vendor.c @@ -0,0 +1,457 @@ +// Copyright 2022 Stefan Kerkmann +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "quantum.h" +#include "serial_usart.h" +#include "serial_protocol.h" +#include "hardware/pio.h" +#include "hardware/clocks.h" + +#if !defined(MCU_RP) +# error PIO Driver is only available for Raspberry Pi 2040 MCUs! +#endif + +static inline bool receive_impl(uint8_t* destination, const size_t size, sysinterval_t timeout); +static inline bool send_impl(const uint8_t* source, const size_t size); +static inline void pio_serve_interrupt(void); + +#define MSG_PIO_ERROR ((msg_t)(-3)) + +#if defined(SERIAL_PIO_USE_PIO1) +static const PIO pio = pio1; + +OSAL_IRQ_HANDLER(RP_PIO1_IRQ_0_HANDLER) { + OSAL_IRQ_PROLOGUE(); + pio_serve_interrupt(); + OSAL_IRQ_EPILOGUE(); +} +#else +static const PIO pio = pio0; + +OSAL_IRQ_HANDLER(RP_PIO0_IRQ_0_HANDLER) { + OSAL_IRQ_PROLOGUE(); + pio_serve_interrupt(); + OSAL_IRQ_EPILOGUE(); +} +#endif + +#define UART_TX_WRAP_TARGET 0 +#define UART_TX_WRAP 3 + +// clang-format off +#if defined(SERIAL_USART_FULL_DUPLEX) +static const uint16_t uart_tx_program_instructions[] = { + // .wrap_target + 0x9fa0, // 0: pull block side 1 [7] + 0xf727, // 1: set x, 7 side 0 [7] + 0x6001, // 2: out pins, 1 + 0x0642, // 3: jmp x--, 2 [6] + // .wrap +}; +#else +static const uint16_t uart_tx_program_instructions[] = { + // .wrap_target + 0x9fa0, // 0: pull block side 1 [7] + 0xf727, // 1: set x, 7 side 0 [7] + 0x6081, // 2: out pindirs, 1 + 0x0642, // 3: jmp x--, 2 [6] + // .wrap +}; +#endif +// clang-format on + +static const pio_program_t uart_tx_program = { + .instructions = uart_tx_program_instructions, + .length = 4, + .origin = -1, +}; + +#define UART_RX_WRAP_TARGET 0 +#define UART_RX_WRAP 8 + +// clang-format off +static const uint16_t uart_rx_program_instructions[] = { + // .wrap_target + 0x2020, // 0: wait 0 pin, 0 + 0xea27, // 1: set x, 7 [10] + 0x4001, // 2: in pins, 1 + 0x0642, // 3: jmp x--, 2 [6] + 0x00c8, // 4: jmp pin, 8 + 0xc020, // 5: irq wait 0 + 0x20a0, // 6: wait 1 pin, 0 + 0x0000, // 7: jmp 0 + 0x8020, // 8: push block + // .wrap +}; +// clang-format on + +static const pio_program_t uart_rx_program = { + .instructions = uart_rx_program_instructions, + .length = 9, + .origin = -1, +}; + +thread_reference_t rx_thread = NULL; +static int rx_state_machine = -1; + +thread_reference_t tx_thread = NULL; +static int tx_state_machine = -1; + +void pio_serve_interrupt(void) { + uint32_t irqs = pio->ints0; + + // The RX FIFO is not empty any more, therefore wake any sleeping rx thread + if (irqs & (PIO_IRQ0_INTF_SM0_RXNEMPTY_BITS << rx_state_machine)) { + // Disable rx not empty interrupt + pio_set_irq0_source_enabled(pio, pis_sm0_rx_fifo_not_empty + rx_state_machine, false); + + osalSysLockFromISR(); + osalThreadResumeI(&rx_thread, MSG_OK); + osalSysUnlockFromISR(); + } + + // The TX FIFO is not full any more, therefore wake any sleeping tx thread + if (irqs & (PIO_IRQ0_INTF_SM0_TXNFULL_BITS << tx_state_machine)) { + // Disable tx not full interrupt + pio_set_irq0_source_enabled(pio, pis_sm0_tx_fifo_not_full + tx_state_machine, false); + osalSysLockFromISR(); + osalThreadResumeI(&tx_thread, MSG_OK); + osalSysUnlockFromISR(); + } + + // IRQ 0 is set on framing or break errors by the rx state machine + if (pio_interrupt_get(pio, 0UL)) { + pio_interrupt_clear(pio, 0UL); + + osalSysLockFromISR(); + osalThreadResumeI(&rx_thread, MSG_PIO_ERROR); + osalSysUnlockFromISR(); + } +} + +#if !defined(SERIAL_USART_FULL_DUPLEX) +// The internal pull-ups of the RP2040 are rather weakish with a range of 50k to +// 80k, which in turn do not provide enough current to guarantee fast signal rise +// times with a parasitic capacitance of greater than 100pf. In real world +// applications, like split keyboards which might have vias in the signal path +// or long PCB traces, this prevents a successful communication. The solution +// is to temporarily augment the weak pull ups from the receiving side by +// driving the tx pin high. On the receiving side the lowest possible drive +// strength is chosen because the transmitting side must still be able to drive +// the signal low. With this configuration the rise times are fast enough and +// the generated low level with 360mV will generate a logical zero. +static inline void enter_rx_state(void) { + osalSysLock(); + // Wait for the transmitting state machines FIFO to run empty. At this point + // the last byte has been pulled from the transmitting state machines FIFO + // into the output shift register. We have to wait a tiny bit more until + // this byte is transmitted, before we can turn on the receiving state + // machine again. + while (!pio_sm_is_tx_fifo_empty(pio, tx_state_machine)) { + } + // Wait for ~11 bits, 1 start bit + 8 data bits + 1 stop bit + 1 bit + // headroom. + chSysPolledDelayX(US2RTC(1 * MHZ, (1000000U * 11 / SERIAL_USART_SPEED))); + // Disable tx state machine to not interfere with our tx pin manipulation + pio_sm_set_enabled(pio, tx_state_machine, false); + gpio_set_drive_strength(SERIAL_USART_TX_PIN, GPIO_DRIVE_STRENGTH_2MA); + pio_sm_set_pins_with_mask(pio, tx_state_machine, 1U << SERIAL_USART_TX_PIN, 1U << SERIAL_USART_TX_PIN); + pio_sm_set_consecutive_pindirs(pio, tx_state_machine, SERIAL_USART_TX_PIN, 1U, false); + pio_sm_set_enabled(pio, rx_state_machine, true); + osalSysUnlock(); +} + +static inline void leave_rx_state(void) { + osalSysLock(); + // In Half-duplex operation the tx pin dual-functions as sender and + // receiver. To not receive the data we will send, we disable the receiving + // state machine. + pio_sm_set_enabled(pio, rx_state_machine, false); + pio_sm_set_consecutive_pindirs(pio, tx_state_machine, SERIAL_USART_TX_PIN, 1U, true); + pio_sm_set_pins_with_mask(pio, tx_state_machine, 0U, 1U << SERIAL_USART_TX_PIN); + gpio_set_drive_strength(SERIAL_USART_TX_PIN, GPIO_DRIVE_STRENGTH_12MA); + pio_sm_restart(pio, tx_state_machine); + pio_sm_set_enabled(pio, tx_state_machine, true); + osalSysUnlock(); +} +#else +// All this trickery is gladly not necessary for full-duplex. +static inline void enter_rx_state(void) {} +static inline void leave_rx_state(void) {} +#endif + +/** + * @brief Clear the RX and TX hardware FIFOs of the state machines. + */ +inline void serial_transport_driver_clear(void) { + osalSysLock(); + pio_sm_clear_fifos(pio, rx_state_machine); + pio_sm_clear_fifos(pio, tx_state_machine); + osalSysUnlock(); +} + +static inline msg_t sync_tx(sysinterval_t timeout) { + msg_t msg = MSG_OK; + osalSysLock(); + while (pio_sm_is_tx_fifo_full(pio, tx_state_machine)) { + pio_set_irq0_source_enabled(pio, pis_sm0_tx_fifo_not_full + tx_state_machine, true); + msg = osalThreadSuspendTimeoutS(&tx_thread, timeout); + if (msg < MSG_OK) { + break; + } + } + osalSysUnlock(); + return msg; +} + +static inline bool send_impl(const uint8_t* source, const size_t size) { + size_t send = 0; + msg_t msg; + while (send < size) { + msg = sync_tx(TIME_MS2I(SERIAL_USART_TIMEOUT)); + if (msg < MSG_OK) { + return false; + } + + osalSysLock(); + while (send < size) { + if (pio_sm_is_tx_fifo_full(pio, tx_state_machine)) { + break; + } + if (send >= size) { + break; + } + pio_sm_put(pio, tx_state_machine, (uint32_t)(*source)); + source++; + send++; + } + osalSysUnlock(); + } + + return send == size; +} + +/** + * @brief Blocking send of buffer with timeout. + * + * @return true Send success. + * @return false Send failed. + */ +inline bool serial_transport_send(const uint8_t* source, const size_t size) { + leave_rx_state(); + bool result = send_impl(source, size); + enter_rx_state(); + + return result; +} + +static inline msg_t sync_rx(sysinterval_t timeout) { + msg_t msg = MSG_OK; + osalSysLock(); + while (pio_sm_is_rx_fifo_empty(pio, rx_state_machine)) { + pio_set_irq0_source_enabled(pio, pis_sm0_rx_fifo_not_empty + rx_state_machine, true); + msg = osalThreadSuspendTimeoutS(&rx_thread, timeout); + if (msg < MSG_OK) { + break; + } + } + osalSysUnlock(); + return msg; +} + +static inline bool receive_impl(uint8_t* destination, const size_t size, sysinterval_t timeout) { + size_t read = 0U; + + while (read < size) { + msg_t msg = sync_rx(timeout); + if (msg < MSG_OK) { + return false; + } + osalSysLock(); + while (true) { + if (pio_sm_is_rx_fifo_empty(pio, rx_state_machine)) { + break; + } + if (read >= size) { + break; + } + *destination++ = *((uint8_t*)&pio->rxf[rx_state_machine] + 3U); + read++; + } + osalSysUnlock(); + } + + return read == size; +} + +/** + * @brief Blocking receive of size * bytes with timeout. + * + * @return true Receive success. + * @return false Receive failed, e.g. by timeout. + */ +inline bool serial_transport_receive(uint8_t* destination, const size_t size) { + return receive_impl(destination, size, TIME_MS2I(SERIAL_USART_TIMEOUT)); +} + +/** + * @brief Blocking receive of size * bytes. + * + * @return true Receive success. + * @return false Receive failed. + */ +inline bool serial_transport_receive_blocking(uint8_t* destination, const size_t size) { + return receive_impl(destination, size, TIME_INFINITE); +} + +static inline void pio_tx_init(pin_t tx_pin) { + uint pio_idx = pio_get_index(pio); + uint offset = pio_add_program(pio, &uart_tx_program); + +#if defined(SERIAL_USART_FULL_DUPLEX) + // clang-format off + iomode_t tx_pin_mode = PAL_RP_GPIO_OE | + PAL_RP_PAD_SLEWFAST | + PAL_RP_PAD_DRIVE4 | + (pio_idx == 0 ? PAL_MODE_ALTERNATE_PIO0 : PAL_MODE_ALTERNATE_PIO1); + // clang-format on + pio_sm_set_pins_with_mask(pio, tx_state_machine, 1U << tx_pin, 1U << tx_pin); + pio_sm_set_consecutive_pindirs(pio, tx_state_machine, tx_pin, 1U, true); +#else + // clang-format off + iomode_t tx_pin_mode = PAL_RP_PAD_IE | + PAL_RP_GPIO_OE | + PAL_RP_PAD_SCHMITT | + PAL_RP_PAD_PUE | + PAL_RP_PAD_SLEWFAST | + PAL_RP_PAD_DRIVE12 | + PAL_RP_IOCTRL_OEOVER_DRVINVPERI | + (pio_idx == 0 ? PAL_MODE_ALTERNATE_PIO0 : PAL_MODE_ALTERNATE_PIO1); + // clang-format on + pio_sm_set_pins_with_mask(pio, tx_state_machine, 0U << tx_pin, 1U << tx_pin); + pio_sm_set_consecutive_pindirs(pio, tx_state_machine, tx_pin, 1U, true); +#endif + + palSetLineMode(tx_pin, tx_pin_mode); + + pio_sm_config config = pio_get_default_sm_config(); + sm_config_set_wrap(&config, offset + UART_TX_WRAP_TARGET, offset + UART_TX_WRAP); +#if defined(SERIAL_USART_FULL_DUPLEX) + sm_config_set_sideset(&config, 2, true, false); +#else + sm_config_set_sideset(&config, 2, true, true); +#endif + // OUT shifts to right, no autopull + sm_config_set_out_shift(&config, true, false, 32); + // We are mapping both OUT and side-set to the same pin, because sometimes + // we need to assert user data onto the pin (with OUT) and sometimes + // assert constant values (start/stop bit) + sm_config_set_out_pins(&config, tx_pin, 1); + sm_config_set_sideset_pins(&config, tx_pin); + // We only need TX, so get an 8-deep FIFO! + sm_config_set_fifo_join(&config, PIO_FIFO_JOIN_TX); + // SM transmits 1 bit per 8 execution cycles. + float div = (float)clock_get_hz(clk_sys) / (8 * SERIAL_USART_SPEED); + sm_config_set_clkdiv(&config, div); + pio_sm_init(pio, tx_state_machine, offset, &config); + pio_sm_set_enabled(pio, tx_state_machine, true); +} + +static inline void pio_rx_init(pin_t rx_pin) { + uint offset = pio_add_program(pio, &uart_rx_program); + +#if defined(SERIAL_USART_FULL_DUPLEX) + uint pio_idx = pio_get_index(pio); + pio_sm_set_consecutive_pindirs(pio, rx_state_machine, rx_pin, 1, false); + // clang-format off + iomode_t rx_pin_mode = PAL_RP_PAD_IE | + PAL_RP_PAD_SCHMITT | + PAL_RP_PAD_PUE | + (pio_idx == 0 ? PAL_MODE_ALTERNATE_PIO0 : PAL_MODE_ALTERNATE_PIO1); + // clang-format on + palSetLineMode(rx_pin, rx_pin_mode); +#endif + + pio_sm_config config = pio_get_default_sm_config(); + sm_config_set_wrap(&config, offset + UART_RX_WRAP_TARGET, offset + UART_RX_WRAP); + sm_config_set_in_pins(&config, rx_pin); // for WAIT, IN + sm_config_set_jmp_pin(&config, rx_pin); // for JMP + // Shift to right, autopush disabled + sm_config_set_in_shift(&config, true, false, 32); + // Deeper FIFO as we're not doing any TX + sm_config_set_fifo_join(&config, PIO_FIFO_JOIN_RX); + // SM transmits 1 bit per 8 execution cycles. + float div = (float)clock_get_hz(clk_sys) / (8 * SERIAL_USART_SPEED); + sm_config_set_clkdiv(&config, div); + pio_sm_init(pio, rx_state_machine, offset, &config); + pio_sm_set_enabled(pio, rx_state_machine, true); +} + +static inline void pio_init(pin_t tx_pin, pin_t rx_pin) { + uint pio_idx = pio_get_index(pio); + + /* Get PIOx peripheral out of reset state. */ + hal_lld_peripheral_unreset(pio_idx == 0 ? RESETS_ALLREG_PIO0 : RESETS_ALLREG_PIO1); + + tx_state_machine = pio_claim_unused_sm(pio, true); + if (tx_state_machine < 0) { + dprintln("ERROR: Failed to acquire state machine for serial transmission!"); + return; + } + pio_tx_init(tx_pin); + + rx_state_machine = pio_claim_unused_sm(pio, true); + if (rx_state_machine < 0) { + dprintln("ERROR: Failed to acquire state machine for serial reception!"); + return; + } + pio_rx_init(rx_pin); + + // Enable error flag IRQ source for rx state machine + pio_set_irq0_source_enabled(pio, pis_sm0_rx_fifo_not_empty + rx_state_machine, true); + pio_set_irq0_source_enabled(pio, pis_sm0_tx_fifo_not_full + tx_state_machine, true); + pio_set_irq0_source_enabled(pio, pis_interrupt0, true); + + // Enable PIO specific interrupt vector +#if defined(SERIAL_PIO_USE_PIO1) + nvicEnableVector(RP_PIO1_IRQ_0_NUMBER, RP_IRQ_UART0_PRIORITY); +#else + nvicEnableVector(RP_PIO0_IRQ_0_NUMBER, RP_IRQ_UART0_PRIORITY); +#endif + + enter_rx_state(); +} + +/** + * @brief PIO driver specific initialization function for the master side. + */ +void serial_transport_driver_master_init(void) { +#if defined(SERIAL_USART_FULL_DUPLEX) + pin_t tx_pin = SERIAL_USART_TX_PIN; + pin_t rx_pin = SERIAL_USART_RX_PIN; +#else + pin_t tx_pin = SERIAL_USART_TX_PIN; + pin_t rx_pin = SERIAL_USART_TX_PIN; +#endif + +#if defined(SERIAL_USART_PIN_SWAP) + pio_init(rx_pin, tx_pin); +#else + pio_init(tx_pin, rx_pin); +#endif +} + +/** + * @brief PIO driver specific initialization function for the slave side. + */ +void serial_transport_driver_slave_init(void) { +#if defined(SERIAL_USART_FULL_DUPLEX) + pin_t tx_pin = SERIAL_USART_TX_PIN; + pin_t rx_pin = SERIAL_USART_RX_PIN; +#else + pin_t tx_pin = SERIAL_USART_TX_PIN; + pin_t rx_pin = SERIAL_USART_TX_PIN; +#endif + + pio_init(tx_pin, rx_pin); +} diff --git a/platforms/chibios/drivers/vendor/RP/RP2040/ws2812_vendor.c b/platforms/chibios/drivers/vendor/RP/RP2040/ws2812_vendor.c new file mode 100644 index 0000000000..bc34eded14 --- /dev/null +++ b/platforms/chibios/drivers/vendor/RP/RP2040/ws2812_vendor.c @@ -0,0 +1,189 @@ +// Copyright 2022 Stefan Kerkmann +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "quantum.h" +#include "ws2812.h" +#include "hardware/pio.h" +#include "hardware/clocks.h" + +#if !defined(MCU_RP) +# error PIO Driver is only available for Raspberry Pi 2040 MCUs! +#endif + +#if defined(WS2812_PIO_USE_PIO1) +static const PIO pio = pio1; +#else +static const PIO pio = pio0; +#endif + +#if !defined(RP_DMA_PRIORITY_WS2812) +# define RP_DMA_PRIORITY_WS2812 12 +#endif + +static int state_machine = -1; + +#define WS2812_WRAP_TARGET 0 +#define WS2812_WRAP 3 + +#define WS2812_T1 2 +#define WS2812_T2 5 +#define WS2812_T3 3 + +#if defined(WS2812_EXTERNAL_PULLUP) + +# pragma message "The GPIOs of the RP2040 are NOT 5V tolerant! Make sure to NOT apply any voltage over 3.3V to the RGB data pin." + +// clang-format off +static const uint16_t ws2812_program_instructions[] = { + // .wrap_target + 0x7221, // 0: out x, 1 side 1 [2] + 0x0123, // 1: jmp !x, 3 side 0 [1] + 0x0400, // 2: jmp 0 side 0 [4] + 0xb442, // 3: nop side 1 [4] + // .wrap +}; + +#else + +static const uint16_t ws2812_program_instructions[] = { + // .wrap_target + 0x6221, // 0: out x, 1 side 0 [2] + 0x1123, // 1: jmp !x, 3 side 1 [1] + 0x1400, // 2: jmp 0 side 1 [4] + 0xa442, // 3: nop side 0 [4] + // .wrap +}; +// clang-format on +#endif + +static const pio_program_t ws2812_program = { + .instructions = ws2812_program_instructions, + .length = 4, + .origin = -1, +}; + +static uint32_t WS2812_BUFFER[RGBLED_NUM]; +static const rp_dma_channel_t* WS2812_DMA_CHANNEL; + +bool ws2812_init(void) { + uint pio_idx = pio_get_index(pio); + /* Get PIOx peripheral out of reset state. */ + hal_lld_peripheral_unreset(pio_idx == 0 ? RESETS_ALLREG_PIO0 : RESETS_ALLREG_PIO1); + + // clang-format off + iomode_t rgb_pin_mode = PAL_RP_PAD_SLEWFAST | + PAL_RP_GPIO_OE | + (pio_idx == 0 ? PAL_MODE_ALTERNATE_PIO0 : PAL_MODE_ALTERNATE_PIO1); + // clang-format on + + palSetLineMode(RGB_DI_PIN, rgb_pin_mode); + + state_machine = pio_claim_unused_sm(pio, true); + if (state_machine < 0) { + dprintln("ERROR: Failed to acquire state machine for WS2812 output!"); + return false; + } + + uint offset = pio_add_program(pio, &ws2812_program); + + pio_sm_set_consecutive_pindirs(pio, state_machine, RGB_DI_PIN, 1, true); + + pio_sm_config config = pio_get_default_sm_config(); + sm_config_set_wrap(&config, offset + WS2812_WRAP_TARGET, offset + WS2812_WRAP); + sm_config_set_sideset_pins(&config, RGB_DI_PIN); + sm_config_set_fifo_join(&config, PIO_FIFO_JOIN_TX); + +#if defined(WS2812_EXTERNAL_PULLUP) + /* Instruct side-set to change the pin-directions instead of outputting + * a logic level. We generate our levels the following way: + * + * 1: Set RGB data pin to high impedance input and let the pull-up drive the + * signal high. + * + * 0: Set RGB data pin to low impedance output and drive the pin low. + */ + sm_config_set_sideset(&config, 1, false, true); +#else + sm_config_set_sideset(&config, 1, false, false); +#endif + +#if defined(RGBW) + sm_config_set_out_shift(&config, false, true, 32); +#else + sm_config_set_out_shift(&config, false, true, 24); +#endif + + int cycles_per_bit = WS2812_T1 + WS2812_T2 + WS2812_T3; + float div = clock_get_hz(clk_sys) / (800.0f * KHZ * cycles_per_bit); + sm_config_set_clkdiv(&config, div); + + pio_sm_init(pio, state_machine, offset, &config); + pio_sm_set_enabled(pio, state_machine, true); + + WS2812_DMA_CHANNEL = dmaChannelAlloc(RP_DMA_CHANNEL_ID_ANY, RP_DMA_PRIORITY_WS2812, NULL, NULL); + + // clang-format off + uint32_t mode = DMA_CTRL_TRIG_INCR_READ | + DMA_CTRL_TRIG_DATA_SIZE_WORD | + DMA_CTRL_TRIG_IRQ_QUIET | + DMA_CTRL_TRIG_TREQ_SEL(pio_idx == 0 ? state_machine : state_machine + 8); + // clang-format on + + dmaChannelSetModeX(WS2812_DMA_CHANNEL, mode); + dmaChannelSetDestinationX(WS2812_DMA_CHANNEL, (uint32_t)&pio->txf[state_machine]); + return true; +} + +/** + * @brief Convert RGBW value into WS2812 compatible 32-bit data word. + */ +__always_inline static uint32_t rgbw8888_to_u32(uint8_t red, uint8_t green, uint8_t blue, uint8_t white) { +#if (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_GRB) + return ((uint32_t)green << 24) | ((uint32_t)red << 16) | ((uint32_t)blue << 8) | ((uint32_t)white); +#elif (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_RGB) + return ((uint32_t)red << 24) | ((uint32_t)green << 16) | ((uint32_t)blue << 8) | ((uint32_t)white); +#elif (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_BGR) + return ((uint32_t)blue << 24) | ((uint32_t)green << 16) | ((uint32_t)red << 8) | ((uint32_t)white); +#endif +} + +static inline void sync_ws2812_transfer(void) { + if (unlikely(dmaChannelIsBusyX(WS2812_DMA_CHANNEL) || !pio_sm_is_tx_fifo_empty(pio, state_machine))) { + fast_timer_t start = timer_read_fast(); + do { + // Abort the synchronization if we have to wait longer than the total + // count of LEDs in millisecounds. This is safely much longer than it + // would take to push all the data out. + if (unlikely(timer_elapsed_fast(start) > RGBLED_NUM)) { + dprintln("ERROR: WS2812 DMA transfer has stalled, aborting!"); + dmaChannelDisableX(WS2812_DMA_CHANNEL); + return; + } + + } while (dmaChannelIsBusyX(WS2812_DMA_CHANNEL) || !pio_sm_is_tx_fifo_empty(pio, state_machine)); + // We wait for the WS2812 chain to reset after all data has been pushed + // out. + wait_us(WS2812_TRST_US); + } +} + +void ws2812_setleds(LED_TYPE* ledarray, uint16_t leds) { + static bool is_initialized = false; + if (unlikely(!is_initialized)) { + is_initialized = ws2812_init(); + } + + sync_ws2812_transfer(); + + for (int i = 0; i < leds; i++) { +#if defined(RGBW) + WS2812_BUFFER[i] = rgbw8888_to_u32(ledarray[i].r, ledarray[i].g, ledarray[i].b, ledarray[i].w); +#else + WS2812_BUFFER[i] = rgbw8888_to_u32(ledarray[i].r, ledarray[i].g, ledarray[i].b, 0); +#endif + } + + dmaChannelSetSourceX(WS2812_DMA_CHANNEL, (uint32_t)WS2812_BUFFER); + dmaChannelSetCounterX(WS2812_DMA_CHANNEL, leds); + dmaChannelEnableX(WS2812_DMA_CHANNEL); +} diff --git a/platforms/chibios/flash.mk b/platforms/chibios/flash.mk index 86bbc22943..790c4f3316 100644 --- a/platforms/chibios/flash.mk +++ b/platforms/chibios/flash.mk @@ -108,6 +108,8 @@ else ifeq ($(strip $(BOOTLOADER)),kiibohd) $(UNSYNC_OUTPUT_CMD) && $(call EXEC_DFU_UTIL) else ifeq ($(strip $(BOOTLOADER)),tinyuf2) $(UNSYNC_OUTPUT_CMD) && $(call EXEC_UF2_UTIL_DEPLOY) +else ifeq ($(strip $(BOOTLOADER)),rp2040) + $(UNSYNC_OUTPUT_CMD) && $(call EXEC_UF2_UTIL_DEPLOY) else ifeq ($(strip $(MCU_FAMILY)),KINETIS) $(UNSYNC_OUTPUT_CMD) && $(call EXEC_TEENSY) else ifeq ($(strip $(MCU_FAMILY)),MIMXRT1062) diff --git a/platforms/chibios/platform.mk b/platforms/chibios/platform.mk index 72428a762f..32b8c5a946 100644 --- a/platforms/chibios/platform.mk +++ b/platforms/chibios/platform.mk @@ -88,9 +88,9 @@ ifeq ("$(MCU_PORT_NAME)","") endif ifeq ("$(wildcard $(PLATFORM_MK))","") - PLATFORM_MK = $(CHIBIOS)/os/hal/ports/$(MCU_PORT_NAME)/$(MCU_SERIES)/$(PLATFORM_NAME).mk + PLATFORM_MK = $(CHIBIOS_CONTRIB)/os/hal/ports/$(MCU_PORT_NAME)/$(MCU_SERIES)/$(PLATFORM_NAME).mk ifeq ("$(wildcard $(PLATFORM_MK))","") - PLATFORM_MK = $(CHIBIOS_CONTRIB)/os/hal/ports/$(MCU_PORT_NAME)/$(MCU_SERIES)/$(PLATFORM_NAME).mk + PLATFORM_MK = $(CHIBIOS)/os/hal/ports/$(MCU_PORT_NAME)/$(MCU_SERIES)/$(PLATFORM_NAME).mk endif endif @@ -287,6 +287,17 @@ EXTRAINCDIRS += $(CHIBIOS)/os/license $(CHIBIOS)/os/oslib/include \ $(HALINC) $(PLATFORMINC) $(BOARDINC) $(TESTINC) \ $(STREAMSINC) $(CHIBIOS)/os/various $(COMMON_VPATH) +# +# QMK specific MCU family support selection. +############################################################################## +ifneq ("$(wildcard $(PLATFORM_PATH)/$(PLATFORM_KEY)/vendors/$(MCU_FAMILY)/$(MCU_SERIES).mk)","") + # Either by MCU series e.g. STM32/STM32F1xx.mk or... + include $(PLATFORM_PATH)/$(PLATFORM_KEY)/vendors/$(MCU_FAMILY)/$(MCU_SERIES).mk +else ifneq ("$(wildcard $(PLATFORM_PATH)/$(PLATFORM_KEY)/vendors/$(MCU_FAMILY)/$(MCU_FAMILY).mk)","") + # By MCU family e.g. STM32/STM32.mk + include $(PLATFORM_PATH)/$(PLATFORM_KEY)/vendors/$(MCU_FAMILY)/$(MCU_FAMILY).mk +endif + # # ChibiOS-Contrib ############################################################################## diff --git a/platforms/chibios/vendors/RP/RP2040.mk b/platforms/chibios/vendors/RP/RP2040.mk new file mode 100644 index 0000000000..1aa925cb15 --- /dev/null +++ b/platforms/chibios/vendors/RP/RP2040.mk @@ -0,0 +1,285 @@ +# +# Raspberry Pi RP2040 specific drivers +############################################################################## +COMMON_VPATH += $(PLATFORM_PATH)/$(PLATFORM_KEY)/$(DRIVER_DIR)/vendor/$(MCU_FAMILY)/$(MCU_SERIES) + +ifeq ($(strip $(WS2812_DRIVER)), vendor) + OPT_DEFS += -DRP_DMA_REQUIRED=TRUE +endif + +# +# Raspberry Pi Pico SDK Support +############################################################################## +ADEFS += -DCRT0_VTOR_INIT=1 \ + -DCRT0_EXTRA_CORES_NUMBER=0 + +CFLAGS += -DPICO_NO_FPGA_CHECK \ + -DNDEBUG + +# +# Pico SDK source and header files needed by QMK and ChibiOS +############################################################################## +PICOSDKROOT := $(TOP_DIR)/lib/pico-sdk + +PICOSDKSRC = $(PICOSDKROOT)/src/rp2_common/hardware_clocks/clocks.c \ + $(PICOSDKROOT)/src/rp2_common/hardware_pll/pll.c \ + $(PICOSDKROOT)/src/rp2_common/hardware_pio/pio.c \ + $(PICOSDKROOT)/src/rp2_common/hardware_gpio/gpio.c \ + $(PICOSDKROOT)/src/rp2_common/hardware_claim/claim.c \ + $(PICOSDKROOT)/src/rp2_common/hardware_watchdog/watchdog.c \ + $(PICOSDKROOT)/src/rp2_common/hardware_xosc/xosc.c \ + $(PICOSDKROOT)/src/rp2_common/pico_bootrom/bootrom.c + +PICOSDKINC = $(CHIBIOS)//os/various/pico_bindings/dumb/include \ + $(PICOSDKROOT)/src/common/pico_base/include \ + $(PICOSDKROOT)/src/rp2_common/pico_platform/include \ + $(PICOSDKROOT)/src/rp2_common/hardware_base/include \ + $(PICOSDKROOT)/src/rp2_common/hardware_clocks/include \ + $(PICOSDKROOT)/src/rp2_common/hardware_claim/include \ + $(PICOSDKROOT)/src/rp2_common/hardware_gpio/include \ + $(PICOSDKROOT)/src/rp2_common/hardware_irq/include \ + $(PICOSDKROOT)/src/rp2_common/hardware_pll/include \ + $(PICOSDKROOT)/src/rp2_common/hardware_pio/include \ + $(PICOSDKROOT)/src/rp2_common/hardware_sync/include \ + $(PICOSDKROOT)/src/rp2_common/hardware_resets/include \ + $(PICOSDKROOT)/src/rp2_common/hardware_watchdog/include \ + $(PICOSDKROOT)/src/rp2_common/hardware_xosc/include \ + $(PICOSDKROOT)/src/rp2040/hardware_regs/include \ + $(PICOSDKROOT)/src/rp2040/hardware_structs/include \ + $(PICOSDKROOT)/src/boards/include \ + $(PICOSDKROOT)/src/rp2_common/pico_bootrom/include + +PLATFORM_SRC += $(PICOSDKSRC) +EXTRAINCDIRS += $(PICOSDKINC) + +PLATFORM_RP2040_PATH := $(PLATFORM_PATH)/$(PLATFORM_KEY)/vendors/$(MCU_FAMILY) + +PLATFORM_SRC += $(PLATFORM_RP2040_PATH)/stage2_bootloaders.c \ + $(PLATFORM_RP2040_PATH)/pico_sdk_shims.c + +EXTRAINCDIRS += $(PLATFORM_RP2040_PATH) + +# +# RP2040 optimized compiler intrinsics +############################################################################## + +# Enables optimized Compiler intrinsics which are located in the RP2040 +# bootrom. This needs startup code and linker script support from ChibiOS, +# which is WIP. Therefore disabled by default for now. +RP2040_INTRINSICS_ENABLED ?= no +ifeq ($(strip $(RP2040_INTRINSICS_ENABLED)), yes) + PICOSDKINTRINSICSSRC = $(PICOSDKROOT)/src/rp2_common/pico_float/float_aeabi.S \ + $(PICOSDKROOT)/src/rp2_common/pico_float/float_math.c \ + $(PICOSDKROOT)/src/rp2_common/pico_float/float_init_rom.c \ + $(PICOSDKROOT)/src/rp2_common/pico_float/float_v1_rom_shim.S \ + $(PICOSDKROOT)/src/rp2_common/pico_double/double_aeabi.S \ + $(PICOSDKROOT)/src/rp2_common/pico_double/double_math.c \ + $(PICOSDKROOT)/src/rp2_common/pico_double/double_init_rom.c \ + $(PICOSDKROOT)/src/rp2_common/pico_double/double_v1_rom_shim.S \ + $(PICOSDKROOT)/src/rp2_common/pico_divider/divider.S \ + $(PICOSDKROOT)/src/rp2_common/pico_int64_ops/pico_int64_ops_aeabi.S \ + $(PICOSDKROOT)/src/rp2_common/pico_mem_ops/mem_ops_aeabi.S \ + $(PICOSDKROOT)/src/rp2_common/pico_malloc/pico_malloc.c \ + $(PICOSDKROOT)/src/rp2_common/pico_bit_ops/bit_ops_aeabi.S + + PICOSDKINTRINSICSINC = $(PICOSDKROOT)/src/common/pico_base/include \ + $(PICOSDKROOT)/src/rp2_common/pico_platfrom/include \ + $(PICOSDKROOT)/src/rp2_common/pico_bootrom/include \ + $(PICOSDKROOT)/src/rp2_common/hardware_divider/include \ + $(PICOSDKROOT)/src/rp2_common/pico_float/include \ + $(PICOSDKROOT)/src/rp2_common/pico_double/include \ + $(PICOSDKROOT)/src/rp2_common/pico_malloc/include + + OPT_DEFS += -DPICO_FLOAT_SUPPORT_ROM_V1=0 -DPICO_DOUBLE_SUPPORT_ROM_V1=0 + + CFLAGS += -Wl,--defsym=__StackLimit=__heap_end__ + CFLAGS += -Wl,--defsym=__unhandled_user_irq=_unhandled_exception + CFLAGS += -Wl,--build-id=none + + # single precision floating point intrinsics + OPT_DEFS += -DPICO_FLOAT_IN_RAM=1 + OPT_DEFS += -DPICO_FLOAT_PROPAGATE_NANS=0 + + CFLAGS += -Wl,--wrap=__aeabi_fdiv + CFLAGS += -Wl,--wrap=__aeabi_fmul + CFLAGS += -Wl,--wrap=__aeabi_frsub + CFLAGS += -Wl,--wrap=__aeabi_fsub + CFLAGS += -Wl,--wrap=__aeabi_cfcmpeq + CFLAGS += -Wl,--wrap=__aeabi_cfrcmple + CFLAGS += -Wl,--wrap=__aeabi_cfcmple + CFLAGS += -Wl,--wrap=__aeabi_fcmpeq + CFLAGS += -Wl,--wrap=__aeabi_fcmplt + CFLAGS += -Wl,--wrap=__aeabi_fcmple + CFLAGS += -Wl,--wrap=__aeabi_fcmpge + CFLAGS += -Wl,--wrap=__aeabi_fcmpgt + CFLAGS += -Wl,--wrap=__aeabi_fcmpun + CFLAGS += -Wl,--wrap=__aeabi_i2f + CFLAGS += -Wl,--wrap=__aeabi_l2f + CFLAGS += -Wl,--wrap=__aeabi_ui2f + CFLAGS += -Wl,--wrap=__aeabi_ul2f + CFLAGS += -Wl,--wrap=__aeabi_i2f + CFLAGS += -Wl,--wrap=__aeabi_f2iz + CFLAGS += -Wl,--wrap=__aeabi_f2lz + CFLAGS += -Wl,--wrap=__aeabi_f2uiz + CFLAGS += -Wl,--wrap=__aeabi_f2ulz + CFLAGS += -Wl,--wrap=__aeabi_f2d + CFLAGS += -Wl,--wrap=sqrtf + CFLAGS += -Wl,--wrap=cosf + CFLAGS += -Wl,--wrap=sinf + CFLAGS += -Wl,--wrap=tanf + CFLAGS += -Wl,--wrap=atan2f + CFLAGS += -Wl,--wrap=expf + CFLAGS += -Wl,--wrap=logf + CFLAGS += -Wl,--wrap=ldexpf + CFLAGS += -Wl,--wrap=copysignf + CFLAGS += -Wl,--wrap=truncf + CFLAGS += -Wl,--wrap=floorf + CFLAGS += -Wl,--wrap=ceilf + CFLAGS += -Wl,--wrap=roundf + CFLAGS += -Wl,--wrap=sincosf + CFLAGS += -Wl,--wrap=asinf + CFLAGS += -Wl,--wrap=acosf + CFLAGS += -Wl,--wrap=atanf + CFLAGS += -Wl,--wrap=sinhf + CFLAGS += -Wl,--wrap=coshf + CFLAGS += -Wl,--wrap=tanhf + CFLAGS += -Wl,--wrap=asinhf + CFLAGS += -Wl,--wrap=acoshf + CFLAGS += -Wl,--wrap=atanhf + CFLAGS += -Wl,--wrap=exp2f + CFLAGS += -Wl,--wrap=log2f + CFLAGS += -Wl,--wrap=exp10f + CFLAGS += -Wl,--wrap=log10f + CFLAGS += -Wl,--wrap=powf + CFLAGS += -Wl,--wrap=powintf + CFLAGS += -Wl,--wrap=hypotf + CFLAGS += -Wl,--wrap=cbrtf + CFLAGS += -Wl,--wrap=fmodf + CFLAGS += -Wl,--wrap=dremf + CFLAGS += -Wl,--wrap=remainderf + CFLAGS += -Wl,--wrap=remquof + CFLAGS += -Wl,--wrap=expm1f + CFLAGS += -Wl,--wrap=log1pf + CFLAGS += -Wl,--wrap=fmaf + + # double precision floating point intrinsics + OPT_DEFS += -DPICO_DOUBLE_IN_RAM=1 + OPT_DEFS += -DPICO_DOUBLE_PROPAGATE_NANS=0 + + CFLAGS += -Wl,--wrap=__aeabi_dadd + CFLAGS += -Wl,--wrap=__aeabi_ddiv + CFLAGS += -Wl,--wrap=__aeabi_dmul + CFLAGS += -Wl,--wrap=__aeabi_drsub + CFLAGS += -Wl,--wrap=__aeabi_dsub + CFLAGS += -Wl,--wrap=__aeabi_cdcmpeq + CFLAGS += -Wl,--wrap=__aeabi_cdrcmple + CFLAGS += -Wl,--wrap=__aeabi_cdcmple + CFLAGS += -Wl,--wrap=__aeabi_dcmpeq + CFLAGS += -Wl,--wrap=__aeabi_dcmplt + CFLAGS += -Wl,--wrap=__aeabi_dcmple + CFLAGS += -Wl,--wrap=__aeabi_dcmpge + CFLAGS += -Wl,--wrap=__aeabi_dcmpgt + CFLAGS += -Wl,--wrap=__aeabi_dcmpun + CFLAGS += -Wl,--wrap=__aeabi_i2d + CFLAGS += -Wl,--wrap=__aeabi_l2d + CFLAGS += -Wl,--wrap=__aeabi_ui2d + CFLAGS += -Wl,--wrap=__aeabi_ul2d + CFLAGS += -Wl,--wrap=__aeabi_d2iz + CFLAGS += -Wl,--wrap=__aeabi_d2lz + CFLAGS += -Wl,--wrap=__aeabi_d2uiz + CFLAGS += -Wl,--wrap=__aeabi_d2ulz + CFLAGS += -Wl,--wrap=__aeabi_d2f + CFLAGS += -Wl,--wrap=sqrt + CFLAGS += -Wl,--wrap=cos + CFLAGS += -Wl,--wrap=sin + CFLAGS += -Wl,--wrap=tan + CFLAGS += -Wl,--wrap=atan2 + CFLAGS += -Wl,--wrap=exp + CFLAGS += -Wl,--wrap=log + CFLAGS += -Wl,--wrap=ldexp + CFLAGS += -Wl,--wrap=copysign + CFLAGS += -Wl,--wrap=trunc + CFLAGS += -Wl,--wrap=floor + CFLAGS += -Wl,--wrap=ceil + CFLAGS += -Wl,--wrap=round + CFLAGS += -Wl,--wrap=sincos + CFLAGS += -Wl,--wrap=asin + CFLAGS += -Wl,--wrap=acos + CFLAGS += -Wl,--wrap=atan + CFLAGS += -Wl,--wrap=sinh + CFLAGS += -Wl,--wrap=cosh + CFLAGS += -Wl,--wrap=tanh + CFLAGS += -Wl,--wrap=asinh + CFLAGS += -Wl,--wrap=acosh + CFLAGS += -Wl,--wrap=atanh + CFLAGS += -Wl,--wrap=exp2 + CFLAGS += -Wl,--wrap=log2 + CFLAGS += -Wl,--wrap=exp10 + CFLAGS += -Wl,--wrap=log10 + CFLAGS += -Wl,--wrap=pow + CFLAGS += -Wl,--wrap=powint + CFLAGS += -Wl,--wrap=hypot + CFLAGS += -Wl,--wrap=cbrt + CFLAGS += -Wl,--wrap=fmod + CFLAGS += -Wl,--wrap=drem + CFLAGS += -Wl,--wrap=remainder + CFLAGS += -Wl,--wrap=remquo + CFLAGS += -Wl,--wrap=expm1 + CFLAGS += -Wl,--wrap=log1p + CFLAGS += -Wl,--wrap=fma + + # bit operation intrinsics + OPT_DEFS += -DPICO_BITS_IN_RAM=1 + + CFLAGS += -Wl,--wrap=__clzsi2 + CFLAGS += -Wl,--wrap=__clzsi2 + CFLAGS += -Wl,--wrap=__clzdi2 + CFLAGS += -Wl,--wrap=__ctzsi2 + CFLAGS += -Wl,--wrap=__ctzdi2 + CFLAGS += -Wl,--wrap=__popcountsi2 + CFLAGS += -Wl,--wrap=__popcountdi2 + CFLAGS += -Wl,--wrap=__clz + CFLAGS += -Wl,--wrap=__clzl + CFLAGS += -Wl,--wrap=__clzsi2 + CFLAGS += -Wl,--wrap=__clzll + + # integer division intrinsics + OPT_DEFS += -DPICO_DIVIDER_IN_RAM=1 + OPT_DEFS += -DPICO_DIVIDER_DISABLE_INTERRUPTS=1 + + CFLAGS += -Wl,--wrap=__aeabi_idiv + CFLAGS += -Wl,--wrap=__aeabi_idivmod + CFLAGS += -Wl,--wrap=__aeabi_ldivmod + CFLAGS += -Wl,--wrap=__aeabi_uidiv + CFLAGS += -Wl,--wrap=__aeabi_uidivmod + CFLAGS += -Wl,--wrap=__aeabi_uldivmod + + # 64bit integer intrinsics + OPT_DEFS += -DPICO_INT64_OPS_IN_RAM=1 + + CFLAGS += -Wl,--wrap=__aeabi_lmul + + # malloc and friends functions + OPT_DEFS += -DPICO_USE_MALLOC_MUTEX=0 + OPT_DEFS += -DPICO_DEBUG_MALLOC=0 + OPT_DEFS ?= -DPICO_MALLOC_PANIC=0 + + CFLAGS += -Wl,--wrap=malloc + CFLAGS += -Wl,--wrap=calloc + CFLAGS += -Wl,--wrap=free + + # memory operation intrinsics + OPT_DEFS += -DPICO_MEM_IN_RAM=1 + + CFLAGS += -Wl,--wrap=memcpy + CFLAGS += -Wl,--wrap=memset + CFLAGS += -Wl,--wrap=__aeabi_memcpy + CFLAGS += -Wl,--wrap=__aeabi_memset + CFLAGS += -Wl,--wrap=__aeabi_memcpy4 + CFLAGS += -Wl,--wrap=__aeabi_memset4 + CFLAGS += -Wl,--wrap=__aeabi_memcpy8 + CFLAGS += -Wl,--wrap=__aeabi_memset8 + + PLATFORM_SRC += $(PICOSDKINTRINSICSSRC) + EXTRAINCDIRS += $(PICOSDKINTRINSICSINC) +endif diff --git a/platforms/chibios/vendors/RP/_pin_defs.h b/platforms/chibios/vendors/RP/_pin_defs.h new file mode 100644 index 0000000000..4241845369 --- /dev/null +++ b/platforms/chibios/vendors/RP/_pin_defs.h @@ -0,0 +1,37 @@ +// Copyright 2022 Stefan Kerkmann +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +/* RP2040 GPIO Numbering */ +#define GP0 0U +#define GP1 1U +#define GP2 2U +#define GP3 3U +#define GP4 4U +#define GP5 5U +#define GP6 6U +#define GP7 7U +#define GP8 8U +#define GP9 9U +#define GP10 10U +#define GP11 11U +#define GP12 12U +#define GP13 13U +#define GP14 14U +#define GP15 15U +#define GP16 16U +#define GP17 17U +#define GP18 18U +#define GP19 19U +#define GP20 20U +#define GP21 21U +#define GP22 22U +#define GP23 23U +#define GP24 24U +#define GP25 25U +#define GP26 26U +#define GP27 27U +#define GP28 28U +#define GP29 29U +#define GP30 30U diff --git a/platforms/chibios/vendors/RP/pico_sdk_shims.c b/platforms/chibios/vendors/RP/pico_sdk_shims.c new file mode 100644 index 0000000000..f6e3943928 --- /dev/null +++ b/platforms/chibios/vendors/RP/pico_sdk_shims.c @@ -0,0 +1,9 @@ +// Copyright 2022 Stefan Kerkmann +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include + +void panic(const char *fmt, ...) { + chSysHalt(fmt); +} diff --git a/platforms/chibios/vendors/RP/stage2_bootloaders.c b/platforms/chibios/vendors/RP/stage2_bootloaders.c new file mode 100644 index 0000000000..f22112fca9 --- /dev/null +++ b/platforms/chibios/vendors/RP/stage2_bootloaders.c @@ -0,0 +1,174 @@ +// ---------------------------------------------------------------------------- +// Pre-compiled second stage boot code for RP2040. +// +// Copyright (c) 2019-2021 Raspberry Pi (Trading) Ltd. +// SPDX-License-Identifier: BSD-3-Clause +// ---------------------------------------------------------------------------- + +#include + +#define BOOTLOADER_SECTION __attribute__ ((used, section (".boot2"))) + +#if defined(RP2040_FLASH_AT25SF128A) + +uint8_t BOOTLOADER_SECTION BOOT2_AT25SF128A[256] = { + 0x00, 0xb5, 0x31, 0x4b, 0x21, 0x20, 0x58, 0x60, 0x98, 0x68, 0x02, 0x21, + 0x88, 0x43, 0x98, 0x60, 0xd8, 0x60, 0x18, 0x61, 0x58, 0x61, 0x2d, 0x4b, + 0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61, 0x01, 0x21, 0xf0, 0x22, + 0x99, 0x50, 0x2a, 0x49, 0x19, 0x60, 0x01, 0x21, 0x99, 0x60, 0x35, 0x20, + 0x00, 0xf0, 0x42, 0xf8, 0x02, 0x22, 0x90, 0x42, 0x12, 0xd0, 0x06, 0x21, + 0x19, 0x66, 0x00, 0xf0, 0x32, 0xf8, 0x19, 0x6e, 0x31, 0x21, 0x19, 0x66, + 0x1a, 0x66, 0x00, 0xf0, 0x2c, 0xf8, 0x19, 0x6e, 0x19, 0x6e, 0x19, 0x6e, + 0x05, 0x20, 0x00, 0xf0, 0x2f, 0xf8, 0x01, 0x21, 0x08, 0x42, 0xf9, 0xd1, + 0x00, 0x21, 0x99, 0x60, 0x1b, 0x49, 0x19, 0x60, 0x00, 0x21, 0x59, 0x60, + 0x1a, 0x49, 0x1b, 0x48, 0x01, 0x60, 0x01, 0x21, 0x99, 0x60, 0xeb, 0x21, + 0x19, 0x66, 0x20, 0x21, 0x19, 0x66, 0x00, 0xf0, 0x12, 0xf8, 0x00, 0x21, + 0x99, 0x60, 0x16, 0x49, 0x14, 0x48, 0x01, 0x60, 0x01, 0x21, 0x99, 0x60, + 0x01, 0xbc, 0x00, 0x28, 0x00, 0xd0, 0x00, 0x47, 0x12, 0x48, 0x13, 0x49, + 0x08, 0x60, 0x03, 0xc8, 0x80, 0xf3, 0x08, 0x88, 0x08, 0x47, 0x03, 0xb5, + 0x99, 0x6a, 0x04, 0x20, 0x01, 0x42, 0xfb, 0xd0, 0x01, 0x20, 0x01, 0x42, + 0xf8, 0xd1, 0x03, 0xbd, 0x02, 0xb5, 0x18, 0x66, 0x18, 0x66, 0xff, 0xf7, + 0xf2, 0xff, 0x18, 0x6e, 0x18, 0x6e, 0x02, 0xbd, 0x00, 0x00, 0x02, 0x40, + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x00, 0x00, 0x03, 0x5f, 0x00, + 0x21, 0x22, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x18, 0x22, 0x20, 0x00, 0x20, + 0x00, 0x01, 0x00, 0x10, 0x08, 0xed, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0xdd, 0xc0, 0xb5 +}; + +#elif defined(RP2040_FLASH_GD25Q64CS) + +uint8_t BOOTLOADER_SECTION BOOT2_GD25Q64CS[256] = { + 0x00, 0xb5, 0x31, 0x4b, 0x21, 0x20, 0x58, 0x60, 0x98, 0x68, 0x02, 0x21, + 0x88, 0x43, 0x98, 0x60, 0xd8, 0x60, 0x18, 0x61, 0x58, 0x61, 0x2d, 0x4b, + 0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61, 0x01, 0x21, 0xf0, 0x22, + 0x99, 0x50, 0x2a, 0x49, 0x19, 0x60, 0x01, 0x21, 0x99, 0x60, 0x35, 0x20, + 0x00, 0xf0, 0x42, 0xf8, 0x02, 0x22, 0x90, 0x42, 0x12, 0xd0, 0x06, 0x21, + 0x19, 0x66, 0x00, 0xf0, 0x32, 0xf8, 0x19, 0x6e, 0x31, 0x21, 0x19, 0x66, + 0x1a, 0x66, 0x00, 0xf0, 0x2c, 0xf8, 0x19, 0x6e, 0x19, 0x6e, 0x19, 0x6e, + 0x05, 0x20, 0x00, 0xf0, 0x2f, 0xf8, 0x01, 0x21, 0x08, 0x42, 0xf9, 0xd1, + 0x00, 0x21, 0x99, 0x60, 0x1b, 0x49, 0x19, 0x60, 0x00, 0x21, 0x59, 0x60, + 0x1a, 0x49, 0x1b, 0x48, 0x01, 0x60, 0x01, 0x21, 0x99, 0x60, 0xe7, 0x21, + 0x19, 0x66, 0xa0, 0x21, 0x19, 0x66, 0x00, 0xf0, 0x12, 0xf8, 0x00, 0x21, + 0x99, 0x60, 0x16, 0x49, 0x14, 0x48, 0x01, 0x60, 0x01, 0x21, 0x99, 0x60, + 0x01, 0xbc, 0x00, 0x28, 0x00, 0xd0, 0x00, 0x47, 0x12, 0x48, 0x13, 0x49, + 0x08, 0x60, 0x03, 0xc8, 0x80, 0xf3, 0x08, 0x88, 0x08, 0x47, 0x03, 0xb5, + 0x99, 0x6a, 0x04, 0x20, 0x01, 0x42, 0xfb, 0xd0, 0x01, 0x20, 0x01, 0x42, + 0xf8, 0xd1, 0x03, 0xbd, 0x02, 0xb5, 0x18, 0x66, 0x18, 0x66, 0xff, 0xf7, + 0xf2, 0xff, 0x18, 0x6e, 0x18, 0x6e, 0x02, 0xbd, 0x00, 0x00, 0x02, 0x40, + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x00, 0x00, 0x03, 0x5f, 0x00, + 0x21, 0x12, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x18, 0x22, 0x10, 0x00, 0xa0, + 0x00, 0x01, 0x00, 0x10, 0x08, 0xed, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe2, 0xd9, 0xa2, 0xb5 +}; + +#elif defined(RP2040_FLASH_W25X10CL) + +uint8_t BOOTLOADER_SECTION BOOT2_W25X10CL[256] = { + 0x00, 0xb5, 0x14, 0x4b, 0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61, + 0x12, 0x49, 0x19, 0x60, 0x00, 0x21, 0x59, 0x60, 0x11, 0x49, 0x12, 0x48, + 0x01, 0x60, 0x01, 0x21, 0x99, 0x60, 0xbb, 0x21, 0x19, 0x66, 0x02, 0x21, + 0x19, 0x66, 0x08, 0x21, 0x98, 0x6a, 0x08, 0x42, 0xfc, 0xd0, 0x00, 0x21, + 0x99, 0x60, 0x0c, 0x49, 0x0a, 0x48, 0x01, 0x60, 0x01, 0x21, 0x99, 0x60, + 0x01, 0xbc, 0x00, 0x28, 0x00, 0xd0, 0x00, 0x47, 0x08, 0x48, 0x09, 0x49, + 0x08, 0x60, 0x03, 0xc8, 0x80, 0xf3, 0x08, 0x88, 0x08, 0x47, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x00, 0x03, 0x3f, 0x00, 0x1d, 0x12, 0x00, 0x00, + 0xf4, 0x00, 0x00, 0x18, 0x1e, 0x10, 0x00, 0x20, 0x00, 0x01, 0x00, 0x10, + 0x08, 0xed, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7c, 0x81, 0x53, 0x9a +}; + +#elif defined(RP2040_FLASH_IS25LP080) + +uint8_t BOOTLOADER_SECTION BOOT2_IS25LP080[256] = { + 0x00, 0xb5, 0x2b, 0x4b, 0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61, + 0x29, 0x49, 0x19, 0x60, 0x01, 0x21, 0x99, 0x60, 0x28, 0x48, 0x00, 0xf0, + 0x42, 0xf8, 0x28, 0x4a, 0x90, 0x42, 0x12, 0xd0, 0x06, 0x21, 0x19, 0x66, + 0x00, 0xf0, 0x32, 0xf8, 0x19, 0x6e, 0x01, 0x21, 0x19, 0x66, 0x00, 0x20, + 0x1a, 0x66, 0x00, 0xf0, 0x2b, 0xf8, 0x19, 0x6e, 0x19, 0x6e, 0x1f, 0x48, + 0x00, 0xf0, 0x2f, 0xf8, 0x01, 0x21, 0x08, 0x42, 0xf9, 0xd1, 0x00, 0x21, + 0x99, 0x60, 0x1d, 0x49, 0x19, 0x60, 0x00, 0x21, 0x59, 0x60, 0x1c, 0x49, + 0x1c, 0x48, 0x01, 0x60, 0x01, 0x21, 0x99, 0x60, 0xeb, 0x21, 0x19, 0x66, + 0xa0, 0x21, 0x19, 0x66, 0x00, 0xf0, 0x12, 0xf8, 0x00, 0x21, 0x99, 0x60, + 0x17, 0x49, 0x16, 0x48, 0x01, 0x60, 0x01, 0x21, 0x99, 0x60, 0x01, 0xbc, + 0x00, 0x28, 0x00, 0xd0, 0x00, 0x47, 0x14, 0x48, 0x14, 0x49, 0x08, 0x60, + 0x03, 0xc8, 0x80, 0xf3, 0x08, 0x88, 0x08, 0x47, 0x03, 0xb5, 0x99, 0x6a, + 0x04, 0x20, 0x01, 0x42, 0xfb, 0xd0, 0x01, 0x20, 0x01, 0x42, 0xf8, 0xd1, + 0x03, 0xbd, 0x02, 0xb5, 0x18, 0x66, 0x18, 0x66, 0xff, 0xf7, 0xf2, 0xff, + 0x18, 0x6e, 0x18, 0x6e, 0x02, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, + 0x00, 0x00, 0x07, 0x00, 0x05, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x5f, 0x00, 0x21, 0x22, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x18, + 0x22, 0x20, 0x00, 0xa0, 0x00, 0x01, 0x00, 0x10, 0x08, 0xed, 0x00, 0xe0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x33, 0x43, 0xb2 +}; + +#elif defined(RP2040_FLASH_GENERIC_03H) + +uint8_t BOOTLOADER_SECTION BOOT2_GENERIC_03H[256] = { + 0x00, 0xb5, 0x0c, 0x4b, 0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61, + 0x0a, 0x49, 0x19, 0x60, 0x0a, 0x49, 0x0b, 0x48, 0x01, 0x60, 0x00, 0x21, + 0x59, 0x60, 0x01, 0x21, 0x99, 0x60, 0x01, 0xbc, 0x00, 0x28, 0x00, 0xd0, + 0x00, 0x47, 0x07, 0x48, 0x07, 0x49, 0x08, 0x60, 0x03, 0xc8, 0x80, 0xf3, + 0x08, 0x88, 0x08, 0x47, 0x00, 0x00, 0x00, 0x18, 0x00, 0x03, 0x1f, 0x00, + 0x18, 0x02, 0x00, 0x03, 0xf4, 0x00, 0x00, 0x18, 0x00, 0x01, 0x00, 0x10, + 0x08, 0xed, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2c, 0xec, 0x21, 0x0d +}; + +#else + +uint8_t BOOTLOADER_SECTION BOOT2_W25Q080[256] = { + 0x00, 0xb5, 0x32, 0x4b, 0x21, 0x20, 0x58, 0x60, 0x98, 0x68, 0x02, 0x21, + 0x88, 0x43, 0x98, 0x60, 0xd8, 0x60, 0x18, 0x61, 0x58, 0x61, 0x2e, 0x4b, + 0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61, 0x01, 0x21, 0xf0, 0x22, + 0x99, 0x50, 0x2b, 0x49, 0x19, 0x60, 0x01, 0x21, 0x99, 0x60, 0x35, 0x20, + 0x00, 0xf0, 0x44, 0xf8, 0x02, 0x22, 0x90, 0x42, 0x14, 0xd0, 0x06, 0x21, + 0x19, 0x66, 0x00, 0xf0, 0x34, 0xf8, 0x19, 0x6e, 0x01, 0x21, 0x19, 0x66, + 0x00, 0x20, 0x18, 0x66, 0x1a, 0x66, 0x00, 0xf0, 0x2c, 0xf8, 0x19, 0x6e, + 0x19, 0x6e, 0x19, 0x6e, 0x05, 0x20, 0x00, 0xf0, 0x2f, 0xf8, 0x01, 0x21, + 0x08, 0x42, 0xf9, 0xd1, 0x00, 0x21, 0x99, 0x60, 0x1b, 0x49, 0x19, 0x60, + 0x00, 0x21, 0x59, 0x60, 0x1a, 0x49, 0x1b, 0x48, 0x01, 0x60, 0x01, 0x21, + 0x99, 0x60, 0xeb, 0x21, 0x19, 0x66, 0xa0, 0x21, 0x19, 0x66, 0x00, 0xf0, + 0x12, 0xf8, 0x00, 0x21, 0x99, 0x60, 0x16, 0x49, 0x14, 0x48, 0x01, 0x60, + 0x01, 0x21, 0x99, 0x60, 0x01, 0xbc, 0x00, 0x28, 0x00, 0xd0, 0x00, 0x47, + 0x12, 0x48, 0x13, 0x49, 0x08, 0x60, 0x03, 0xc8, 0x80, 0xf3, 0x08, 0x88, + 0x08, 0x47, 0x03, 0xb5, 0x99, 0x6a, 0x04, 0x20, 0x01, 0x42, 0xfb, 0xd0, + 0x01, 0x20, 0x01, 0x42, 0xf8, 0xd1, 0x03, 0xbd, 0x02, 0xb5, 0x18, 0x66, + 0x18, 0x66, 0xff, 0xf7, 0xf2, 0xff, 0x18, 0x6e, 0x18, 0x6e, 0x02, 0xbd, + 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x00, + 0x00, 0x03, 0x5f, 0x00, 0x21, 0x22, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x18, + 0x22, 0x20, 0x00, 0xa0, 0x00, 0x01, 0x00, 0x10, 0x08, 0xed, 0x00, 0xe0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x0b, 0x8f, 0xd5 +}; + +#endif -- cgit v1.2.3 From 77d960cce3a10296fcdad2324f17eff4a2f0835f Mon Sep 17 00:00:00 2001 From: Stefan Kerkmann Date: Thu, 30 Jun 2022 21:07:54 +0200 Subject: Disable clang-format for stage2_bootloaders (#17516) --- platforms/chibios/vendors/RP/stage2_bootloaders.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'platforms') diff --git a/platforms/chibios/vendors/RP/stage2_bootloaders.c b/platforms/chibios/vendors/RP/stage2_bootloaders.c index f22112fca9..af679a0dc7 100644 --- a/platforms/chibios/vendors/RP/stage2_bootloaders.c +++ b/platforms/chibios/vendors/RP/stage2_bootloaders.c @@ -7,7 +7,9 @@ #include -#define BOOTLOADER_SECTION __attribute__ ((used, section (".boot2"))) +#define BOOTLOADER_SECTION __attribute__((used, section(".boot2"))) + +// clang-format off #if defined(RP2040_FLASH_AT25SF128A) @@ -172,3 +174,5 @@ uint8_t BOOTLOADER_SECTION BOOT2_W25Q080[256] = { }; #endif + +// clang-format on -- cgit v1.2.3 From 5846b40f7444af96b0d8ddf3af9b558193c2475d Mon Sep 17 00:00:00 2001 From: Nick Brassel Date: Sat, 2 Jul 2022 15:18:50 +1000 Subject: RP2040 emulated EEPROM. (#17519) --- .../boards/common/ld/RP2040_FLASH_TIMECRIT.ld | 117 +++++++++++ .../common/ld/RP2040_rules_data_with_timecrit.ld | 46 +++++ .../wear_leveling/wear_leveling_rp2040_flash.c | 221 +++++++++++++++++++++ .../wear_leveling_rp2040_flash_config.h | 32 +++ platforms/chibios/platform.mk | 3 + platforms/chibios/vendors/RP/RP2040.mk | 2 + platforms/chibios/vendors/RP/pico_sdk_shims.c | 4 + platforms/chibios/vendors/RP/stage2_bootloaders.c | 12 +- 8 files changed, 431 insertions(+), 6 deletions(-) create mode 100644 platforms/chibios/boards/common/ld/RP2040_FLASH_TIMECRIT.ld create mode 100644 platforms/chibios/boards/common/ld/RP2040_rules_data_with_timecrit.ld create mode 100644 platforms/chibios/drivers/wear_leveling/wear_leveling_rp2040_flash.c create mode 100644 platforms/chibios/drivers/wear_leveling/wear_leveling_rp2040_flash_config.h (limited to 'platforms') diff --git a/platforms/chibios/boards/common/ld/RP2040_FLASH_TIMECRIT.ld b/platforms/chibios/boards/common/ld/RP2040_FLASH_TIMECRIT.ld new file mode 100644 index 0000000000..66ed4ce086 --- /dev/null +++ b/platforms/chibios/boards/common/ld/RP2040_FLASH_TIMECRIT.ld @@ -0,0 +1,117 @@ +/* + ChibiOS - Copyright (C) 2006..2021 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* + * RP2040 memory setup. + */ +MEMORY +{ + flash0 (rx) : org = 0x00000000, len = 16k /* ROM */ + flash1 (rx) : org = 0x10000000, len = DEFINED(FLASH_LEN) ? FLASH_LEN : 2048k /* XIP */ + flash2 (rx) : org = 0x00000000, len = 0 + flash3 (rx) : org = 0x00000000, len = 0 + flash4 (rx) : org = 0x00000000, len = 0 + flash5 (rx) : org = 0x00000000, len = 0 + flash6 (rx) : org = 0x00000000, len = 0 + flash7 (rx) : org = 0x00000000, len = 0 + ram0 (wx) : org = 0x20000000, len = 256k /* SRAM0 striped */ + ram1 (wx) : org = 0x00000000, len = 256k /* SRAM0 non striped */ + ram2 (wx) : org = 0x00000000, len = 0 + ram3 (wx) : org = 0x00000000, len = 0 + ram4 (wx) : org = 0x20040000, len = 4k /* SRAM4 */ + ram5 (wx) : org = 0x20041000, len = 4k /* SRAM5 */ + ram6 (wx) : org = 0x00000000, len = 0 + ram7 (wx) : org = 0x20041f00, len = 256 /* SRAM5 boot */ +} + +/* For each data/text section two region are defined, a virtual region + and a load region (_LMA suffix).*/ + +/* Flash region to be used for exception vectors.*/ +REGION_ALIAS("VECTORS_FLASH", flash1); +REGION_ALIAS("VECTORS_FLASH_LMA", flash1); + +/* Flash region to be used for constructors and destructors.*/ +REGION_ALIAS("XTORS_FLASH", flash1); +REGION_ALIAS("XTORS_FLASH_LMA", flash1); + +/* Flash region to be used for code text.*/ +REGION_ALIAS("TEXT_FLASH", flash1); +REGION_ALIAS("TEXT_FLASH_LMA", flash1); + +/* Flash region to be used for read only data.*/ +REGION_ALIAS("RODATA_FLASH", flash1); +REGION_ALIAS("RODATA_FLASH_LMA", flash1); + +/* Flash region to be used for various.*/ +REGION_ALIAS("VARIOUS_FLASH", flash1); +REGION_ALIAS("VARIOUS_FLASH_LMA", flash1); + +/* Flash region to be used for RAM(n) initialization data.*/ +REGION_ALIAS("RAM_INIT_FLASH_LMA", flash1); + +/* RAM region to be used for Main stack. This stack accommodates the processing + of all exceptions and interrupts.*/ +REGION_ALIAS("MAIN_STACK_RAM", ram4); + +/* RAM region to be used for the process stack. This is the stack used by + the main() function.*/ +REGION_ALIAS("PROCESS_STACK_RAM", ram4); + +/* RAM region to be used for Main stack. This stack accommodates the processing + of all exceptions and interrupts.*/ +REGION_ALIAS("C1_MAIN_STACK_RAM", ram5); + +/* RAM region to be used for the process stack. This is the stack used by + the main() function.*/ +REGION_ALIAS("C1_PROCESS_STACK_RAM", ram5); + +/* RAM region to be used for data segment.*/ +REGION_ALIAS("DATA_RAM", ram0); +REGION_ALIAS("DATA_RAM_LMA", flash1); + +/* RAM region to be used for BSS segment.*/ +REGION_ALIAS("BSS_RAM", ram0); + +/* RAM region to be used for the default heap.*/ +REGION_ALIAS("HEAP_RAM", ram0); + +SECTIONS +{ + .flash_begin : { + __flash_binary_start = .; + } > flash1 + + .boot2 : { + __boot2_start__ = .; + KEEP (*(.boot2)) + __boot2_end__ = .; + } > flash1 +} + +/* Generic rules inclusion.*/ +INCLUDE rules_stacks.ld +INCLUDE rules_stacks_c1.ld +INCLUDE RP2040_rules_code_with_boot2.ld +INCLUDE RP2040_rules_data_with_timecrit.ld +INCLUDE rules_memory.ld + +SECTIONS +{ + .flash_end : { + __flash_binary_end = .; + } > flash1 +} diff --git a/platforms/chibios/boards/common/ld/RP2040_rules_data_with_timecrit.ld b/platforms/chibios/boards/common/ld/RP2040_rules_data_with_timecrit.ld new file mode 100644 index 0000000000..a9a47be983 --- /dev/null +++ b/platforms/chibios/boards/common/ld/RP2040_rules_data_with_timecrit.ld @@ -0,0 +1,46 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +SECTIONS +{ + .data : ALIGN(4) + { + PROVIDE(_textdata = LOADADDR(.data)); + PROVIDE(_data = .); + __textdata_base__ = LOADADDR(.data); + __data_base__ = .; + *(vtable) + *(.time_critical*) + . = ALIGN(4); + *(.data) + *(.data.*) + *(.ramtext) + . = ALIGN(4); + PROVIDE(_edata = .); + __data_end__ = .; + } > DATA_RAM AT > DATA_RAM_LMA + + .bss (NOLOAD) : ALIGN(4) + { + __bss_base__ = .; + *(.bss) + *(.bss.*) + *(COMMON) + . = ALIGN(4); + __bss_end__ = .; + PROVIDE(end = .); + } > BSS_RAM +} diff --git a/platforms/chibios/drivers/wear_leveling/wear_leveling_rp2040_flash.c b/platforms/chibios/drivers/wear_leveling/wear_leveling_rp2040_flash.c new file mode 100644 index 0000000000..640628e1e9 --- /dev/null +++ b/platforms/chibios/drivers/wear_leveling/wear_leveling_rp2040_flash.c @@ -0,0 +1,221 @@ +/** + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * Copyright (c) 2022 Nick Brassel (@tzarc) + * Copyright (c) 2022 Stefan Kerkmann (@KarlK90) + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "pico/bootrom.h" +#include "hardware/flash.h" +#include "hardware/sync.h" +#include "hardware/structs/ssi.h" +#include "hardware/structs/ioqspi.h" + +#include +#include "timer.h" +#include "wear_leveling.h" +#include "wear_leveling_internal.h" + +#ifndef WEAR_LEVELING_RP2040_FLASH_BULK_COUNT +# define WEAR_LEVELING_RP2040_FLASH_BULK_COUNT 64 +#endif // WEAR_LEVELING_RP2040_FLASH_BULK_COUNT + +#define FLASHCMD_PAGE_PROGRAM 0x02 +#define FLASHCMD_READ_STATUS 0x05 +#define FLASHCMD_WRITE_ENABLE 0x06 + +extern uint8_t BOOT2_ROM[256]; +static uint32_t BOOT2_ROM_RAM[64]; + +static ssi_hw_t *const ssi = (ssi_hw_t *)XIP_SSI_BASE; + +// Sanity check +check_hw_layout(ssi_hw_t, ssienr, SSI_SSIENR_OFFSET); +check_hw_layout(ssi_hw_t, spi_ctrlr0, SSI_SPI_CTRLR0_OFFSET); + +static void __no_inline_not_in_flash_func(flash_enable_xip_via_boot2)(void) { + ((void (*)(void))BOOT2_ROM_RAM + 1)(); +} + +// Bitbanging the chip select using IO overrides, in case RAM-resident IRQs +// are still running, and the FIFO bottoms out. (the bootrom does the same) +static void __no_inline_not_in_flash_func(flash_cs_force)(bool high) { + uint32_t field_val = high ? IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_VALUE_HIGH : IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_VALUE_LOW; + hw_write_masked(&ioqspi_hw->io[1].ctrl, field_val << IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_LSB, IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_BITS); +} + +// Also allow any unbounded loops to check whether the above abort condition +// was asserted, and terminate early +static int __no_inline_not_in_flash_func(flash_was_aborted)(void) { + return *(io_rw_32 *)(IO_QSPI_BASE + IO_QSPI_GPIO_QSPI_SD1_CTRL_OFFSET) & IO_QSPI_GPIO_QSPI_SD1_CTRL_INOVER_BITS; +} + +// Put bytes from one buffer, and get bytes into another buffer. +// These can be the same buffer. +// If tx is NULL then send zeroes. +// If rx is NULL then all read data will be dropped. +// +// If rx_skip is nonzero, this many bytes will first be consumed from the FIFO, +// before reading a further count bytes into *rx. +// E.g. if you have written a command+address just before calling this function. +static void __no_inline_not_in_flash_func(flash_put_get)(const uint8_t *tx, uint8_t *rx, size_t count, size_t rx_skip) { + // Make sure there is never more data in flight than the depth of the RX + // FIFO. Otherwise, when we are interrupted for long periods, hardware + // will overflow the RX FIFO. + const uint max_in_flight = 16 - 2; // account for data internal to SSI + size_t tx_count = count; + size_t rx_count = count; + while (tx_count || rx_skip || rx_count) { + // NB order of reads, for pessimism rather than optimism + uint32_t tx_level = ssi_hw->txflr; + uint32_t rx_level = ssi_hw->rxflr; + bool did_something = false; // Expect this to be folded into control flow, not register + if (tx_count && tx_level + rx_level < max_in_flight) { + ssi->dr0 = (uint32_t)(tx ? *tx++ : 0); + --tx_count; + did_something = true; + } + if (rx_level) { + uint8_t rxbyte = ssi->dr0; + did_something = true; + if (rx_skip) { + --rx_skip; + } else { + if (rx) *rx++ = rxbyte; + --rx_count; + } + } + // APB load costs 4 cycles, so only do it on idle loops (our budget is + // 48 cyc/byte) + if (!did_something && __builtin_expect(flash_was_aborted(), 0)) break; + } + flash_cs_force(1); +} + +// Convenience wrapper for above +// (And it's hard for the debug host to get the tight timing between +// cmd DR0 write and the remaining data) +static void __no_inline_not_in_flash_func(_flash_do_cmd)(uint8_t cmd, const uint8_t *tx, uint8_t *rx, size_t count) { + flash_cs_force(0); + ssi->dr0 = cmd; + flash_put_get(tx, rx, count, 1); +} + +// Timing of this one is critical, so do not expose the symbol to debugger etc +static void __no_inline_not_in_flash_func(flash_put_cmd_addr)(uint8_t cmd, uint32_t addr) { + flash_cs_force(0); + addr |= cmd << 24; + for (int i = 0; i < 4; ++i) { + ssi->dr0 = addr >> 24; + addr <<= 8; + } +} + +// Poll the flash status register until the busy bit (LSB) clears +static void __no_inline_not_in_flash_func(flash_wait_ready)(void) { + uint8_t stat; + do { + _flash_do_cmd(FLASHCMD_READ_STATUS, NULL, &stat, 1); + } while (stat & 0x1 && !flash_was_aborted()); +} + +// Set the WEL bit (needed before any program/erase operation) +static void __no_inline_not_in_flash_func(flash_enable_write)(void) { + _flash_do_cmd(FLASHCMD_WRITE_ENABLE, NULL, NULL, 0); +} + +static void __no_inline_not_in_flash_func(pico_program_bulk)(uint32_t flash_address, backing_store_int_t *values, size_t item_count) { + rom_connect_internal_flash_fn connect_internal_flash = (rom_connect_internal_flash_fn)rom_func_lookup_inline(ROM_FUNC_CONNECT_INTERNAL_FLASH); + rom_flash_exit_xip_fn flash_exit_xip = (rom_flash_exit_xip_fn)rom_func_lookup_inline(ROM_FUNC_FLASH_EXIT_XIP); + rom_flash_flush_cache_fn flash_flush_cache = (rom_flash_flush_cache_fn)rom_func_lookup_inline(ROM_FUNC_FLASH_FLUSH_CACHE); + assert(connect_internal_flash && flash_exit_xip && flash_flush_cache); + + static backing_store_int_t bulk_write_buffer[WEAR_LEVELING_RP2040_FLASH_BULK_COUNT]; + + while (item_count) { + size_t batch_size = MIN(item_count, WEAR_LEVELING_RP2040_FLASH_BULK_COUNT); + for (size_t i = 0; i < batch_size; i++, values++, item_count--) { + bulk_write_buffer[i] = ~(*values); + } + __compiler_memory_barrier(); + + connect_internal_flash(); + flash_exit_xip(); + flash_enable_write(); + + flash_put_cmd_addr(FLASHCMD_PAGE_PROGRAM, flash_address); + flash_put_get((uint8_t *)bulk_write_buffer, NULL, batch_size * sizeof(backing_store_int_t), 4); + flash_wait_ready(); + flash_address += batch_size * sizeof(backing_store_int_t); + + flash_flush_cache(); + flash_enable_xip_via_boot2(); + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// QMK Wear-Leveling Backing Store implementation + +static int interrupts; + +bool backing_store_init(void) { + bs_dprintf("Init\n"); + memcpy(BOOT2_ROM_RAM, BOOT2_ROM, sizeof(BOOT2_ROM)); + __compiler_memory_barrier(); + return true; +} + +bool backing_store_unlock(void) { + bs_dprintf("Unlock\n"); + return true; +} + +bool backing_store_erase(void) { +#ifdef WEAR_LEVELING_DEBUG_OUTPUT + uint32_t start = timer_read32(); +#endif + + // Ensure the backing size can be cleanly subtracted from the flash size without alignment issues. + _Static_assert((WEAR_LEVELING_BACKING_SIZE) % (FLASH_SECTOR_SIZE) == 0, "Backing size must be a multiple of FLASH_SECTOR_SIZE"); + + interrupts = save_and_disable_interrupts(); + flash_range_erase((WEAR_LEVELING_RP2040_FLASH_BASE), (WEAR_LEVELING_BACKING_SIZE)); + restore_interrupts(interrupts); + + bs_dprintf("Backing store erase took %ldms to complete\n", ((long)(timer_read32() - start))); + return true; +} + +bool backing_store_write(uint32_t address, backing_store_int_t value) { + return backing_store_write_bulk(address, &value, 1); +} + +bool backing_store_write_bulk(uint32_t address, backing_store_int_t *values, size_t item_count) { + uint32_t offset = (WEAR_LEVELING_RP2040_FLASH_BASE) + address; + bs_dprintf("Write "); + wl_dump(offset, values, sizeof(backing_store_int_t) * item_count); + interrupts = save_and_disable_interrupts(); + pico_program_bulk(offset, values, item_count); + restore_interrupts(interrupts); + return true; +} + +bool backing_store_lock(void) { + return true; +} + +bool backing_store_read(uint32_t address, backing_store_int_t *value) { + return backing_store_read_bulk(address, value, 1); +} + +bool backing_store_read_bulk(uint32_t address, backing_store_int_t *values, size_t item_count) { + uint32_t offset = (WEAR_LEVELING_RP2040_FLASH_BASE) + address; + backing_store_int_t *loc = (backing_store_int_t *)((XIP_BASE) + offset); + for (size_t i = 0; i < item_count; ++i) { + values[i] = ~loc[i]; + } + bs_dprintf("Read "); + wl_dump(offset, values, item_count * sizeof(backing_store_int_t)); + return true; +} diff --git a/platforms/chibios/drivers/wear_leveling/wear_leveling_rp2040_flash_config.h b/platforms/chibios/drivers/wear_leveling/wear_leveling_rp2040_flash_config.h new file mode 100644 index 0000000000..93a9aa0372 --- /dev/null +++ b/platforms/chibios/drivers/wear_leveling/wear_leveling_rp2040_flash_config.h @@ -0,0 +1,32 @@ +// Copyright 2022 Nick Brassel (@tzarc) +// SPDX-License-Identifier: GPL-2.0-or-later +#pragma once + +#ifndef __ASSEMBLER__ +# include "hardware/flash.h" +#endif + +// 2-byte writes +#ifndef BACKING_STORE_WRITE_SIZE +# define BACKING_STORE_WRITE_SIZE 2 +#endif + +// 64kB backing space allocated +#ifndef WEAR_LEVELING_BACKING_SIZE +# define WEAR_LEVELING_BACKING_SIZE 8192 +#endif // WEAR_LEVELING_BACKING_SIZE + +// 32kB logical EEPROM +#ifndef WEAR_LEVELING_LOGICAL_SIZE +# define WEAR_LEVELING_LOGICAL_SIZE 4096 +#endif // WEAR_LEVELING_LOGICAL_SIZE + +// Define how much flash space we have (defaults to lib/pico-sdk/src/boards/include/boards/***) +#ifndef WEAR_LEVELING_RP2040_FLASH_SIZE +# define WEAR_LEVELING_RP2040_FLASH_SIZE (PICO_FLASH_SIZE_BYTES) +#endif + +// Define the location of emulated EEPROM +#ifndef WEAR_LEVELING_RP2040_FLASH_BASE +# define WEAR_LEVELING_RP2040_FLASH_BASE ((WEAR_LEVELING_RP2040_FLASH_SIZE) - (WEAR_LEVELING_BACKING_SIZE)) +#endif diff --git a/platforms/chibios/platform.mk b/platforms/chibios/platform.mk index 32b8c5a946..63cc1a4b33 100644 --- a/platforms/chibios/platform.mk +++ b/platforms/chibios/platform.mk @@ -351,8 +351,11 @@ SHARED_CFLAGS = -fomit-frame-pointer \ -fno-common \ -fshort-wchar +LDSCRIPT_PATH := $(shell dirname "$(LDSCRIPT)") + # Shared Linker flags for all toolchains SHARED_LDFLAGS = -T $(LDSCRIPT) \ + -L $(LDSCRIPT_PATH) \ -Wl,--gc-sections \ -nostartfiles diff --git a/platforms/chibios/vendors/RP/RP2040.mk b/platforms/chibios/vendors/RP/RP2040.mk index 1aa925cb15..de426c9c40 100644 --- a/platforms/chibios/vendors/RP/RP2040.mk +++ b/platforms/chibios/vendors/RP/RP2040.mk @@ -24,6 +24,7 @@ PICOSDKROOT := $(TOP_DIR)/lib/pico-sdk PICOSDKSRC = $(PICOSDKROOT)/src/rp2_common/hardware_clocks/clocks.c \ $(PICOSDKROOT)/src/rp2_common/hardware_pll/pll.c \ $(PICOSDKROOT)/src/rp2_common/hardware_pio/pio.c \ + $(PICOSDKROOT)/src/rp2_common/hardware_flash/flash.c \ $(PICOSDKROOT)/src/rp2_common/hardware_gpio/gpio.c \ $(PICOSDKROOT)/src/rp2_common/hardware_claim/claim.c \ $(PICOSDKROOT)/src/rp2_common/hardware_watchdog/watchdog.c \ @@ -36,6 +37,7 @@ PICOSDKINC = $(CHIBIOS)//os/various/pico_bindings/dumb/include \ $(PICOSDKROOT)/src/rp2_common/hardware_base/include \ $(PICOSDKROOT)/src/rp2_common/hardware_clocks/include \ $(PICOSDKROOT)/src/rp2_common/hardware_claim/include \ + $(PICOSDKROOT)/src/rp2_common/hardware_flash/include \ $(PICOSDKROOT)/src/rp2_common/hardware_gpio/include \ $(PICOSDKROOT)/src/rp2_common/hardware_irq/include \ $(PICOSDKROOT)/src/rp2_common/hardware_pll/include \ diff --git a/platforms/chibios/vendors/RP/pico_sdk_shims.c b/platforms/chibios/vendors/RP/pico_sdk_shims.c index f6e3943928..239155c086 100644 --- a/platforms/chibios/vendors/RP/pico_sdk_shims.c +++ b/platforms/chibios/vendors/RP/pico_sdk_shims.c @@ -7,3 +7,7 @@ void panic(const char *fmt, ...) { chSysHalt(fmt); } + +void hard_assertion_failure(void) { + panic("hard assert"); +} diff --git a/platforms/chibios/vendors/RP/stage2_bootloaders.c b/platforms/chibios/vendors/RP/stage2_bootloaders.c index af679a0dc7..e65b0a5802 100644 --- a/platforms/chibios/vendors/RP/stage2_bootloaders.c +++ b/platforms/chibios/vendors/RP/stage2_bootloaders.c @@ -13,7 +13,7 @@ #if defined(RP2040_FLASH_AT25SF128A) -uint8_t BOOTLOADER_SECTION BOOT2_AT25SF128A[256] = { +uint8_t BOOTLOADER_SECTION BOOT2_ROM[256] = { 0x00, 0xb5, 0x31, 0x4b, 0x21, 0x20, 0x58, 0x60, 0x98, 0x68, 0x02, 0x21, 0x88, 0x43, 0x98, 0x60, 0xd8, 0x60, 0x18, 0x61, 0x58, 0x61, 0x2d, 0x4b, 0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61, 0x01, 0x21, 0xf0, 0x22, @@ -40,7 +40,7 @@ uint8_t BOOTLOADER_SECTION BOOT2_AT25SF128A[256] = { #elif defined(RP2040_FLASH_GD25Q64CS) -uint8_t BOOTLOADER_SECTION BOOT2_GD25Q64CS[256] = { +uint8_t BOOTLOADER_SECTION BOOT2_ROM[256] = { 0x00, 0xb5, 0x31, 0x4b, 0x21, 0x20, 0x58, 0x60, 0x98, 0x68, 0x02, 0x21, 0x88, 0x43, 0x98, 0x60, 0xd8, 0x60, 0x18, 0x61, 0x58, 0x61, 0x2d, 0x4b, 0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61, 0x01, 0x21, 0xf0, 0x22, @@ -67,7 +67,7 @@ uint8_t BOOTLOADER_SECTION BOOT2_GD25Q64CS[256] = { #elif defined(RP2040_FLASH_W25X10CL) -uint8_t BOOTLOADER_SECTION BOOT2_W25X10CL[256] = { +uint8_t BOOTLOADER_SECTION BOOT2_ROM[256] = { 0x00, 0xb5, 0x14, 0x4b, 0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61, 0x12, 0x49, 0x19, 0x60, 0x00, 0x21, 0x59, 0x60, 0x11, 0x49, 0x12, 0x48, 0x01, 0x60, 0x01, 0x21, 0x99, 0x60, 0xbb, 0x21, 0x19, 0x66, 0x02, 0x21, @@ -94,7 +94,7 @@ uint8_t BOOTLOADER_SECTION BOOT2_W25X10CL[256] = { #elif defined(RP2040_FLASH_IS25LP080) -uint8_t BOOTLOADER_SECTION BOOT2_IS25LP080[256] = { +uint8_t BOOTLOADER_SECTION BOOT2_ROM[256] = { 0x00, 0xb5, 0x2b, 0x4b, 0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61, 0x29, 0x49, 0x19, 0x60, 0x01, 0x21, 0x99, 0x60, 0x28, 0x48, 0x00, 0xf0, 0x42, 0xf8, 0x28, 0x4a, 0x90, 0x42, 0x12, 0xd0, 0x06, 0x21, 0x19, 0x66, @@ -121,7 +121,7 @@ uint8_t BOOTLOADER_SECTION BOOT2_IS25LP080[256] = { #elif defined(RP2040_FLASH_GENERIC_03H) -uint8_t BOOTLOADER_SECTION BOOT2_GENERIC_03H[256] = { +uint8_t BOOTLOADER_SECTION BOOT2_ROM[256] = { 0x00, 0xb5, 0x0c, 0x4b, 0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61, 0x0a, 0x49, 0x19, 0x60, 0x0a, 0x49, 0x0b, 0x48, 0x01, 0x60, 0x00, 0x21, 0x59, 0x60, 0x01, 0x21, 0x99, 0x60, 0x01, 0xbc, 0x00, 0x28, 0x00, 0xd0, @@ -148,7 +148,7 @@ uint8_t BOOTLOADER_SECTION BOOT2_GENERIC_03H[256] = { #else -uint8_t BOOTLOADER_SECTION BOOT2_W25Q080[256] = { +uint8_t BOOTLOADER_SECTION BOOT2_ROM[256] = { 0x00, 0xb5, 0x32, 0x4b, 0x21, 0x20, 0x58, 0x60, 0x98, 0x68, 0x02, 0x21, 0x88, 0x43, 0x98, 0x60, 0xd8, 0x60, 0x18, 0x61, 0x58, 0x61, 0x2e, 0x4b, 0x00, 0x21, 0x99, 0x60, 0x04, 0x21, 0x59, 0x61, 0x01, 0x21, 0xf0, 0x22, -- cgit v1.2.3 From ac5e6b6a3bfad12ab7d9786a18fcc90f8bf4caf7 Mon Sep 17 00:00:00 2001 From: Ryan Date: Sun, 3 Jul 2022 00:12:45 +1000 Subject: Tentative Teensy 3.5 support (#14420) * Tentative Teensy 3.5 support * Set firmware format to .hex for ARM Teensys * Got to "device descriptor failed" by comparing with Teensy 3.6 code * Drop down to 96MHz... * Bump back up to 120MHz --- platforms/chibios/chibios_config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'platforms') diff --git a/platforms/chibios/chibios_config.h b/platforms/chibios/chibios_config.h index 1571bd5cd3..e5aa8e3d05 100644 --- a/platforms/chibios/chibios_config.h +++ b/platforms/chibios/chibios_config.h @@ -95,7 +95,7 @@ #if defined(MCU_KINETIS) # define CPU_CLOCK KINETIS_SYSCLK_FREQUENCY -# if defined(K20x) || defined(KL2x) +# if defined(K20x) || defined(K60x) || defined(KL2x) # define USE_I2CV1 # define USE_I2CV1_CONTRIB // for some reason a bunch of ChibiOS-Contrib boards only have clock_speed # define USE_GPIOV1 -- cgit v1.2.3 From 29a2bac4691dae81a613af31e5e99660e61edc3d Mon Sep 17 00:00:00 2001 From: Nick Brassel Date: Wed, 6 Jul 2022 06:41:35 +1000 Subject: Fixup SPI. (#17534) --- platforms/chibios/drivers/spi_master.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'platforms') diff --git a/platforms/chibios/drivers/spi_master.c b/platforms/chibios/drivers/spi_master.c index f9974d9f6b..223d8a403e 100644 --- a/platforms/chibios/drivers/spi_master.c +++ b/platforms/chibios/drivers/spi_master.c @@ -46,6 +46,9 @@ __attribute__((weak)) void spi_init(void) { 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); 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); #endif + spiUnselect(&SPI_DRIVER); + spiStop(&SPI_DRIVER); + currentSlavePin = NO_PIN; } } -- cgit v1.2.3 From 744af003befb3f5cf6dc6b6f3e581f288d598f96 Mon Sep 17 00:00:00 2001 From: Joel Challis Date: Wed, 6 Jul 2022 19:27:15 +0100 Subject: Add kb2040 and sparkfun rp2040 converters (#17514) --- platforms/chibios/boards/QMK_PM2040/board/board.mk | 9 ++ .../chibios/boards/QMK_PM2040/configs/board.h | 12 +++ .../chibios/boards/QMK_PM2040/configs/chconf.h | 13 +++ .../chibios/boards/QMK_PM2040/configs/config.h | 21 +++++ .../chibios/boards/QMK_PM2040/configs/halconf.h | 9 ++ .../chibios/boards/QMK_PM2040/configs/mcuconf.h | 98 ++++++++++++++++++++++ .../converters/promicro_to_kb2040/_pin_defs.h | 36 ++++++++ .../converters/promicro_to_kb2040/converter.mk | 9 ++ .../promicro_to_promicro_rp2040/_pin_defs.h | 36 ++++++++ .../promicro_to_promicro_rp2040/converter.mk | 9 ++ 10 files changed, 252 insertions(+) create mode 100644 platforms/chibios/boards/QMK_PM2040/board/board.mk create mode 100644 platforms/chibios/boards/QMK_PM2040/configs/board.h create mode 100644 platforms/chibios/boards/QMK_PM2040/configs/chconf.h create mode 100644 platforms/chibios/boards/QMK_PM2040/configs/config.h create mode 100644 platforms/chibios/boards/QMK_PM2040/configs/halconf.h create mode 100644 platforms/chibios/boards/QMK_PM2040/configs/mcuconf.h create mode 100644 platforms/chibios/converters/promicro_to_kb2040/_pin_defs.h create mode 100644 platforms/chibios/converters/promicro_to_kb2040/converter.mk create mode 100644 platforms/chibios/converters/promicro_to_promicro_rp2040/_pin_defs.h create mode 100644 platforms/chibios/converters/promicro_to_promicro_rp2040/converter.mk (limited to 'platforms') diff --git a/platforms/chibios/boards/QMK_PM2040/board/board.mk b/platforms/chibios/boards/QMK_PM2040/board/board.mk new file mode 100644 index 0000000000..911cc5a058 --- /dev/null +++ b/platforms/chibios/boards/QMK_PM2040/board/board.mk @@ -0,0 +1,9 @@ +# List of all the board related files. +BOARDSRC = $(CHIBIOS)/os/hal/boards/RP_PICO_RP2040/board.c + +# Required include directories +BOARDINC = $(CHIBIOS)/os/hal/boards/RP_PICO_RP2040 + +# Shared variables +ALLCSRC += $(BOARDSRC) +ALLINC += $(BOARDINC) diff --git a/platforms/chibios/boards/QMK_PM2040/configs/board.h b/platforms/chibios/boards/QMK_PM2040/configs/board.h new file mode 100644 index 0000000000..433e1c527f --- /dev/null +++ b/platforms/chibios/boards/QMK_PM2040/configs/board.h @@ -0,0 +1,12 @@ +// Copyright 2022 QMK +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include_next "board.h" + +#undef BOARD_RP_PICO_RP2040 +#define BOARD_PM2040 + +#undef BOARD_NAME +#define BOARD_NAME "Pro Micro RP2040" diff --git a/platforms/chibios/boards/QMK_PM2040/configs/chconf.h b/platforms/chibios/boards/QMK_PM2040/configs/chconf.h new file mode 100644 index 0000000000..d53f57edd9 --- /dev/null +++ b/platforms/chibios/boards/QMK_PM2040/configs/chconf.h @@ -0,0 +1,13 @@ +// Copyright 2022 Stefan Kerkmann +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#define CH_CFG_SMP_MODE TRUE +#define CH_CFG_ST_RESOLUTION 32 +#define CH_CFG_ST_FREQUENCY 1000000 +#define CH_CFG_INTERVALS_SIZE 32 +#define CH_CFG_TIME_TYPES_SIZE 32 +#define CH_CFG_ST_TIMEDELTA 20 + +#include_next diff --git a/platforms/chibios/boards/QMK_PM2040/configs/config.h b/platforms/chibios/boards/QMK_PM2040/configs/config.h new file mode 100644 index 0000000000..6b1dcca938 --- /dev/null +++ b/platforms/chibios/boards/QMK_PM2040/configs/config.h @@ -0,0 +1,21 @@ +// Copyright 2022 QMK +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#ifndef I2C_DRIVER +# define I2C_DRIVER I2CD2 +#endif +#ifndef I2C1_SDA_PIN +# define I2C1_SDA_PIN D2 +#endif +#ifndef I2C1_SCL_PIN +# define I2C1_SCL_PIN D3 +#endif + +#ifndef RP2040_BOOTLOADER_DOUBLE_TAP_RESET +# define RP2040_BOOTLOADER_DOUBLE_TAP_RESET +#endif +#ifndef RP2040_BOOTLOADER_DOUBLE_TAP_RESET_TIMEOUT +# define RP2040_BOOTLOADER_DOUBLE_TAP_RESET_TIMEOUT 500U +#endif diff --git a/platforms/chibios/boards/QMK_PM2040/configs/halconf.h b/platforms/chibios/boards/QMK_PM2040/configs/halconf.h new file mode 100644 index 0000000000..d7a58f0ea6 --- /dev/null +++ b/platforms/chibios/boards/QMK_PM2040/configs/halconf.h @@ -0,0 +1,9 @@ +// Copyright 2022 QMK +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#define HAL_USE_I2C TRUE +#define HAL_USE_SPI TRUE + +#include_next diff --git a/platforms/chibios/boards/QMK_PM2040/configs/mcuconf.h b/platforms/chibios/boards/QMK_PM2040/configs/mcuconf.h new file mode 100644 index 0000000000..a737b36c1c --- /dev/null +++ b/platforms/chibios/boards/QMK_PM2040/configs/mcuconf.h @@ -0,0 +1,98 @@ +/* + ChibiOS - Copyright (C) 2006..2021 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#ifndef MCUCONF_H +#define MCUCONF_H + +/* + * RP2040_MCUCONF drivers configuration. + * + * IRQ priorities: + * 3...0 Lowest...Highest. + * + * DMA priorities: + * 0...1 Lowest...Highest. + */ + +#define RP2040_MCUCONF + +/* + * HAL driver system settings. + */ +#define RP_NO_INIT FALSE +#define RP_CORE1_START FALSE +#define RP_CORE1_VECTORS_TABLE _vectors +#define RP_CORE1_ENTRY_POINT _crt0_c1_entry +#define RP_CORE1_STACK_END __c1_main_stack_end__ + +/* + * IRQ system settings. + */ +#define RP_IRQ_SYSTICK_PRIORITY 2 +#define RP_IRQ_TIMER_ALARM0_PRIORITY 2 +#define RP_IRQ_TIMER_ALARM1_PRIORITY 2 +#define RP_IRQ_TIMER_ALARM2_PRIORITY 2 +#define RP_IRQ_TIMER_ALARM3_PRIORITY 2 +#define RP_IRQ_UART0_PRIORITY 3 +#define RP_IRQ_UART1_PRIORITY 3 +#define RP_IRQ_SPI0_PRIORITY 2 +#define RP_IRQ_SPI1_PRIORITY 2 +#define RP_IRQ_USB0_PRIORITY 3 +#define RP_IRQ_I2C0_PRIORITY 2 +#define RP_IRQ_I2C1_PRIORITY 2 + +/* + * ADC driver system settings. + */ +#define RP_ADC_USE_ADC1 FALSE + +/* + * SIO driver system settings. + */ +#define RP_SIO_USE_UART0 FALSE +#define RP_SIO_USE_UART1 FALSE + +/* + * SPI driver system settings. + */ +#define RP_SPI_USE_SPI0 TRUE +#define RP_SPI_USE_SPI1 FALSE +#define RP_SPI_SPI0_RX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY +#define RP_SPI_SPI0_TX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY +#define RP_SPI_SPI1_RX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY +#define RP_SPI_SPI1_TX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY +#define RP_SPI_SPI0_DMA_PRIORITY 1 +#define RP_SPI_SPI1_DMA_PRIORITY 1 +#define RP_SPI_DMA_ERROR_HOOK(spip) + +/* + * I2C driver system settings. + */ +#define RP_I2C_USE_I2C0 FALSE +#define RP_I2C_USE_I2C1 TRUE +#define RP_I2C_BUSY_TIMEOUT 50 +#define RP_I2C_ADDRESS_MODE_10BIT FALSE + +/* + * USB driver system settings. + */ +#define RP_USB_USE_USBD0 TRUE +#define RP_USB_FORCE_VBUS_DETECT TRUE +#define RP_USE_EXTERNAL_VBUS_DETECT FALSE +#define RP_USB_USE_SOF_INTR TRUE +#define RP_USB_USE_ERROR_DATA_SEQ_INTR FALSE + +#endif /* MCUCONF_H */ diff --git a/platforms/chibios/converters/promicro_to_kb2040/_pin_defs.h b/platforms/chibios/converters/promicro_to_kb2040/_pin_defs.h new file mode 100644 index 0000000000..0a3110890b --- /dev/null +++ b/platforms/chibios/converters/promicro_to_kb2040/_pin_defs.h @@ -0,0 +1,36 @@ +// Copyright 2022 QMK +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +// Left side (front) +#define D3 0U +#define D2 1U +// GND +// GND +#define D1 2U +#define D0 3U +#define D4 4U +#define C6 5U +#define D7 6U +#define E6 7U +#define B4 8U +#define B5 9U + +// Right side (front) +// RAW +// GND +// RESET +// VCC +#define F4 29U +#define F5 28U +#define F6 27U +#define F7 26U +#define B1 18U +#define B3 20U +#define B2 19U +#define B6 10U + +// LEDs (Mapped to QT connector to avoid collisions with button/neopixel) +#define D5 12U +#define B0 13U diff --git a/platforms/chibios/converters/promicro_to_kb2040/converter.mk b/platforms/chibios/converters/promicro_to_kb2040/converter.mk new file mode 100644 index 0000000000..6ffee357b3 --- /dev/null +++ b/platforms/chibios/converters/promicro_to_kb2040/converter.mk @@ -0,0 +1,9 @@ +# Adafruit KB2040 MCU settings for converting AVR projects +MCU := RP2040 +BOARD := QMK_PM2040 +BOOTLOADER := rp2040 + +# These are defaults based on what has been implemented for RP2040 boards +SERIAL_DRIVER ?= vendor +WS2812_DRIVER ?= vendor +BACKLIGHT_DRIVER ?= software diff --git a/platforms/chibios/converters/promicro_to_promicro_rp2040/_pin_defs.h b/platforms/chibios/converters/promicro_to_promicro_rp2040/_pin_defs.h new file mode 100644 index 0000000000..0a1f4112a3 --- /dev/null +++ b/platforms/chibios/converters/promicro_to_promicro_rp2040/_pin_defs.h @@ -0,0 +1,36 @@ +// Copyright 2022 QMK +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +// Left side (front) +#define D3 0U +#define D2 1U +// GND +// GND +#define D1 2U +#define D0 3U +#define D4 4U +#define C6 5U +#define D7 6U +#define E6 7U +#define B4 8U +#define B5 9U + +// Right side (front) +// RAW +// GND +// RESET +// VCC +#define F4 29U +#define F5 28U +#define F6 27U +#define F7 26U +#define B1 22U +#define B3 20U +#define B2 23U +#define B6 21U + +// LEDs (Mapped to QT connector to avoid collisions with button/neopixel) +#define D5 17U +#define B0 16U diff --git a/platforms/chibios/converters/promicro_to_promicro_rp2040/converter.mk b/platforms/chibios/converters/promicro_to_promicro_rp2040/converter.mk new file mode 100644 index 0000000000..03863eeb02 --- /dev/null +++ b/platforms/chibios/converters/promicro_to_promicro_rp2040/converter.mk @@ -0,0 +1,9 @@ +# Sparkfun Pro Micro RP2040 MCU settings for converting AVR projects +MCU := RP2040 +BOARD := QMK_PM2040 +BOOTLOADER := rp2040 + +# These are defaults based on what has been implemented for RP2040 boards +SERIAL_DRIVER ?= vendor +WS2812_DRIVER ?= vendor +BACKLIGHT_DRIVER ?= software -- cgit v1.2.3 From d9bb189e25f14578ca74d6a3aa9f9a467f6f6595 Mon Sep 17 00:00:00 2001 From: Stefan Kerkmann Date: Thu, 7 Jul 2022 09:27:50 +0200 Subject: [Core] Update mpaland/printf to eyalroz/printf fork (#16163) mpaland printf implementation was abandoned in ~2019 and the fork by eyalroz is now regarded to be the goto replacement of it. So this commit incoporates the changes needed to use this fork in QMK. Note that pointer ptrdiff_t is always supported since commit 51c90f93a97fdaef895783ecbe24569be0db7cb8 --- platforms/arm_atsam/platform.mk | 1 + platforms/avr/platform.mk | 1 + platforms/chibios/platform.mk | 3 ++- 3 files changed, 4 insertions(+), 1 deletion(-) (limited to 'platforms') diff --git a/platforms/arm_atsam/platform.mk b/platforms/arm_atsam/platform.mk index 9618838dc3..9462f517ae 100644 --- a/platforms/arm_atsam/platform.mk +++ b/platforms/arm_atsam/platform.mk @@ -24,6 +24,7 @@ COMPILEFLAGS += -fno-strict-aliasing COMPILEFLAGS += -mfloat-abi=hard COMPILEFLAGS += -mfpu=fpv4-sp-d16 COMPILEFLAGS += -mthumb +COMPILEFLAGS += -fno-builtin-printf #ALLOW_WARNINGS = yes diff --git a/platforms/avr/platform.mk b/platforms/avr/platform.mk index b51a94c93a..39a11b28e4 100644 --- a/platforms/avr/platform.mk +++ b/platforms/avr/platform.mk @@ -24,6 +24,7 @@ COMPILEFLAGS += -fdata-sections COMPILEFLAGS += -fpack-struct COMPILEFLAGS += -fshort-enums COMPILEFLAGS += -mcall-prologues +COMPILEFLAGS += -fno-builtin-printf # Linker relaxation is only possible if # link time optimizations are not enabled. diff --git a/platforms/chibios/platform.mk b/platforms/chibios/platform.mk index 63cc1a4b33..b2a8ec89e1 100644 --- a/platforms/chibios/platform.mk +++ b/platforms/chibios/platform.mk @@ -349,7 +349,8 @@ SHARED_CFLAGS = -fomit-frame-pointer \ -ffunction-sections \ -fdata-sections \ -fno-common \ - -fshort-wchar + -fshort-wchar \ + -fno-builtin-printf LDSCRIPT_PATH := $(shell dirname "$(LDSCRIPT)") -- cgit v1.2.3 From cca5d3532128a9d1aa2ab39405d935fc132c752d Mon Sep 17 00:00:00 2001 From: Albert Y <76888457+filterpaper@users.noreply.github.com> Date: Thu, 7 Jul 2022 15:33:11 +0800 Subject: Update PM2040 I2C pins (#17578) --- platforms/chibios/boards/QMK_PM2040/configs/config.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'platforms') diff --git a/platforms/chibios/boards/QMK_PM2040/configs/config.h b/platforms/chibios/boards/QMK_PM2040/configs/config.h index 6b1dcca938..9dfe86f12e 100644 --- a/platforms/chibios/boards/QMK_PM2040/configs/config.h +++ b/platforms/chibios/boards/QMK_PM2040/configs/config.h @@ -7,10 +7,10 @@ # define I2C_DRIVER I2CD2 #endif #ifndef I2C1_SDA_PIN -# define I2C1_SDA_PIN D2 +# define I2C1_SDA_PIN 2U #endif #ifndef I2C1_SCL_PIN -# define I2C1_SCL_PIN D3 +# define I2C1_SCL_PIN 3U #endif #ifndef RP2040_BOOTLOADER_DOUBLE_TAP_RESET -- cgit v1.2.3 From 0348071810d30fc362e8ec8fda6764431f7939e2 Mon Sep 17 00:00:00 2001 From: Stefan Kerkmann Date: Mon, 11 Jul 2022 13:05:04 +0200 Subject: Stabilize Half-duplex PIO split comms (#17612) --- .../chibios/drivers/vendor/RP/RP2040/serial_vendor.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'platforms') diff --git a/platforms/chibios/drivers/vendor/RP/RP2040/serial_vendor.c b/platforms/chibios/drivers/vendor/RP/RP2040/serial_vendor.c index 949fc6dd93..d933dc1f5d 100644 --- a/platforms/chibios/drivers/vendor/RP/RP2040/serial_vendor.c +++ b/platforms/chibios/drivers/vendor/RP/RP2040/serial_vendor.c @@ -142,6 +142,7 @@ void pio_serve_interrupt(void) { // the generated low level with 360mV will generate a logical zero. static inline void enter_rx_state(void) { osalSysLock(); + nvicEnableVector(RP_USBCTRL_IRQ_NUMBER, RP_IRQ_USB0_PRIORITY); // Wait for the transmitting state machines FIFO to run empty. At this point // the last byte has been pulled from the transmitting state machines FIFO // into the output shift register. We have to wait a tiny bit more until @@ -163,6 +164,9 @@ static inline void enter_rx_state(void) { static inline void leave_rx_state(void) { osalSysLock(); + // We don't want to be interrupted by frequent (1KHz) USB interrupts while + // doing our timing critical sending operation. + nvicDisableVector(RP_USBCTRL_IRQ_NUMBER); // In Half-duplex operation the tx pin dual-functions as sender and // receiver. To not receive the data we will send, we disable the receiving // state machine. @@ -194,12 +198,21 @@ static inline msg_t sync_tx(sysinterval_t timeout) { msg_t msg = MSG_OK; osalSysLock(); while (pio_sm_is_tx_fifo_full(pio, tx_state_machine)) { +#if !defined(SERIAL_USART_FULL_DUPLEX) + // Enable USB interrupts again, because we might sleep for a long time + // here and don't want to be disconnected from the host. + nvicEnableVector(RP_USBCTRL_IRQ_NUMBER, RP_IRQ_USB0_PRIORITY); +#endif pio_set_irq0_source_enabled(pio, pis_sm0_tx_fifo_not_full + tx_state_machine, true); msg = osalThreadSuspendTimeoutS(&tx_thread, timeout); if (msg < MSG_OK) { break; } } +#if !defined(SERIAL_USART_FULL_DUPLEX) + // Entering timing critical territory again. + nvicDisableVector(RP_USBCTRL_IRQ_NUMBER); +#endif osalSysUnlock(); return msg; } @@ -412,11 +425,12 @@ static inline void pio_init(pin_t tx_pin, pin_t rx_pin) { pio_set_irq0_source_enabled(pio, pis_sm0_tx_fifo_not_full + tx_state_machine, true); pio_set_irq0_source_enabled(pio, pis_interrupt0, true); - // Enable PIO specific interrupt vector + // Enable PIO specific interrupt vector, as the pio implementation is timing + // critical we use the highest possible priority. #if defined(SERIAL_PIO_USE_PIO1) - nvicEnableVector(RP_PIO1_IRQ_0_NUMBER, RP_IRQ_UART0_PRIORITY); + nvicEnableVector(RP_PIO1_IRQ_0_NUMBER, CORTEX_MAX_KERNEL_PRIORITY); #else - nvicEnableVector(RP_PIO0_IRQ_0_NUMBER, RP_IRQ_UART0_PRIORITY); + nvicEnableVector(RP_PIO0_IRQ_0_NUMBER, CORTEX_MAX_KERNEL_PRIORITY); #endif enter_rx_state(); -- cgit v1.2.3 From 3f5dc472965e6a5b8efe60e33c7b6c2d18d92008 Mon Sep 17 00:00:00 2001 From: Stefan Kerkmann Date: Mon, 11 Jul 2022 15:17:05 +0200 Subject: [Core] Use polled waiting on ChibiOS platforms that support it (#17607) * Use polled waiting on platforms that support it Due to context switching overhead waiting a very short amount of time on a sleeping thread is often not accurate and in fact not usable for timing critical usage i.e. in a driver. Thus we use polled waiting for ranges in the us range on platforms that support it instead. The fallback is the thread sleeping mechanism. This includes: * ARM platforms with CYCCNT register (ARMv7, ARMv8) this is incremented at CPU clock frequency * GD32VF103 RISC-V port with CSR_MCYCLE register this is incremented at CPU clock frequency * RP2040 ARMv6 port which uses the integrated timer peripheral which is incremented with a fixed 1MHz frequency * Use wait_us() instead of chSysPolledDelayX ...as it is powered by busy waiting now. * Add chibios waiting methods test bench --- platforms/chibios/_wait.h | 5 +++++ platforms/chibios/bootloaders/rp2040.c | 5 ++--- platforms/chibios/chibios_config.h | 12 ++++++++++++ platforms/chibios/drivers/serial.c | 3 ++- platforms/chibios/drivers/vendor/RP/RP2040/serial_vendor.c | 2 +- 5 files changed, 22 insertions(+), 5 deletions(-) (limited to 'platforms') diff --git a/platforms/chibios/_wait.h b/platforms/chibios/_wait.h index 2f36c64a2e..21cdffe11a 100644 --- a/platforms/chibios/_wait.h +++ b/platforms/chibios/_wait.h @@ -30,6 +30,11 @@ #ifdef WAIT_US_TIMER void wait_us(uint16_t duration); +#elif PORT_SUPPORTS_RT == TRUE +# define wait_us(us) \ + do { \ + chSysPolledDelayX(US2RTC(REALTIME_COUNTER_CLOCK, us)); \ + } while (0) #else # define wait_us(us) \ do { \ diff --git a/platforms/chibios/bootloaders/rp2040.c b/platforms/chibios/bootloaders/rp2040.c index 13a54036ef..bedc00f32e 100644 --- a/platforms/chibios/bootloaders/rp2040.c +++ b/platforms/chibios/bootloaders/rp2040.c @@ -43,9 +43,8 @@ void __late_init(void) { if (magic_location != magic_token) { magic_location = magic_token; // ChibiOS is not initialized at this point, so sleeping is only - // possible via busy waiting. The internal timer peripheral is running - // at this point with a precision of 1us. - chSysPolledDelayX(MS2RTC(1 * MHZ, RP2040_BOOTLOADER_DOUBLE_TAP_RESET_TIMEOUT)); + // possible via busy waiting. + wait_us(RP2040_BOOTLOADER_DOUBLE_TAP_RESET_TIMEOUT * 1000U); magic_location = 0; return; } diff --git a/platforms/chibios/chibios_config.h b/platforms/chibios/chibios_config.h index e5aa8e3d05..c7a3a98fb0 100644 --- a/platforms/chibios/chibios_config.h +++ b/platforms/chibios/chibios_config.h @@ -21,6 +21,9 @@ #if defined(MCU_RP) # define CPU_CLOCK RP_CORE_CLK +// ChibiOS uses the RP2040 timer peripheral as its real time counter, this timer +// is monotonic and running at 1MHz. +# define REALTIME_COUNTER_CLOCK 1000000 # define USE_GPIOV1 # define PAL_OUTPUT_TYPE_OPENDRAIN _Static_assert(0, "RP2040 has no Open Drain GPIO configuration, setting this is not possible"); @@ -102,6 +105,11 @@ # endif #endif +#if defined(MCU_MIMXRT1062) +# include "clock_config.h" +# define CPU_CLOCK BOARD_BOOTCLOCKRUN_CORE_CLOCK +#endif + #if defined(HT32) # define CPU_CLOCK HT32_CK_SYS_FREQUENCY # define PAL_MODE_ALTERNATE PAL_HT32_MODE_AF @@ -109,3 +117,7 @@ # define PAL_OUTPUT_TYPE_PUSHPULL PAL_HT32_MODE_DIR # define PAL_OUTPUT_SPEED_HIGHEST 0 #endif + +#if !defined(REALTIME_COUNTER_CLOCK) +# define REALTIME_COUNTER_CLOCK CPU_CLOCK +#endif diff --git a/platforms/chibios/drivers/serial.c b/platforms/chibios/drivers/serial.c index 3fae5cd3a4..0dd8e71ae8 100644 --- a/platforms/chibios/drivers/serial.c +++ b/platforms/chibios/drivers/serial.c @@ -20,7 +20,8 @@ # error "chSysPolledDelayX method not supported on this platform" #else # undef wait_us -# define wait_us(x) chSysPolledDelayX(US2RTC(CPU_CLOCK, x)) +// Force usage of polled waiting - in case WAIT_US_TIMER is activated +# define wait_us(us) chSysPolledDelayX(US2RTC(REALTIME_COUNTER_CLOCK, us)) #endif #ifndef SELECT_SOFT_SERIAL_SPEED diff --git a/platforms/chibios/drivers/vendor/RP/RP2040/serial_vendor.c b/platforms/chibios/drivers/vendor/RP/RP2040/serial_vendor.c index d933dc1f5d..338146dadd 100644 --- a/platforms/chibios/drivers/vendor/RP/RP2040/serial_vendor.c +++ b/platforms/chibios/drivers/vendor/RP/RP2040/serial_vendor.c @@ -152,7 +152,7 @@ static inline void enter_rx_state(void) { } // Wait for ~11 bits, 1 start bit + 8 data bits + 1 stop bit + 1 bit // headroom. - chSysPolledDelayX(US2RTC(1 * MHZ, (1000000U * 11 / SERIAL_USART_SPEED))); + wait_us(1000000U * 11U / SERIAL_USART_SPEED); // Disable tx state machine to not interfere with our tx pin manipulation pio_sm_set_enabled(pio, tx_state_machine, false); gpio_set_drive_strength(SERIAL_USART_TX_PIN, GPIO_DRIVE_STRENGTH_2MA); -- cgit v1.2.3 From 45ffe42f1a26d14e372ff8e0a35441fd968e1494 Mon Sep 17 00:00:00 2001 From: Stefan Kerkmann Date: Tue, 12 Jul 2022 21:54:33 +0200 Subject: [Fix] Make ChibiOS `_wait.h` independent of `quantum.h` (#17645) --- platforms/chibios/_wait.h | 1 + 1 file changed, 1 insertion(+) (limited to 'platforms') diff --git a/platforms/chibios/_wait.h b/platforms/chibios/_wait.h index 21cdffe11a..c0ccbc5569 100644 --- a/platforms/chibios/_wait.h +++ b/platforms/chibios/_wait.h @@ -17,6 +17,7 @@ #include #include +#include "chibios_config.h" /* chThdSleepX of zero maps to infinite - so we map to a tiny delay to still yield */ #define wait_ms(ms) \ -- cgit v1.2.3 From ffb34fc0825e4a715842e93dbfdbe843759fec05 Mon Sep 17 00:00:00 2001 From: jack <0x6A73@pm.me> Date: Tue, 12 Jul 2022 13:55:19 -0600 Subject: Include stdint.h in avr/i2c_master.h (#17639) --- platforms/avr/drivers/i2c_master.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'platforms') diff --git a/platforms/avr/drivers/i2c_master.h b/platforms/avr/drivers/i2c_master.h index 2d95846db5..04ef126c80 100644 --- a/platforms/avr/drivers/i2c_master.h +++ b/platforms/avr/drivers/i2c_master.h @@ -19,6 +19,8 @@ #pragma once +#include + #define I2C_READ 0x01 #define I2C_WRITE 0x00 -- cgit v1.2.3 From dfff040433a2cabd4a1047bbeb9eb72b736bba2e Mon Sep 17 00:00:00 2001 From: Nick Brassel Date: Wed, 13 Jul 2022 14:42:24 +1000 Subject: Allow MCU-specific overrides for SPI flags. (#17650) --- platforms/chibios/chibios_config.h | 15 +++++++++++++++ platforms/chibios/drivers/spi_master.c | 6 +++--- 2 files changed, 18 insertions(+), 3 deletions(-) (limited to 'platforms') diff --git a/platforms/chibios/chibios_config.h b/platforms/chibios/chibios_config.h index c7a3a98fb0..8dcc23727f 100644 --- a/platforms/chibios/chibios_config.h +++ b/platforms/chibios/chibios_config.h @@ -84,6 +84,8 @@ # define PAL_OUTPUT_TYPE_PUSHPULL PAL_WB32_OTYPE_PUSHPULL # define PAL_OUTPUT_SPEED_HIGHEST PAL_WB32_OSPEED_HIGH # define PAL_PUPDR_FLOATING PAL_WB32_PUPDR_FLOATING + +# define SPI_SCK_FLAGS PAL_MODE_ALTERNATE(SPI_SCK_PAL_MODE) | PAL_OUTPUT_TYPE_PUSHPULL | PAL_OUTPUT_SPEED_HIGHEST | PAL_WB32_CURRENT_LEVEL3 # endif #endif @@ -121,3 +123,16 @@ #if !defined(REALTIME_COUNTER_CLOCK) # define REALTIME_COUNTER_CLOCK CPU_CLOCK #endif + +// SPI Fallbacks +#ifndef SPI_SCK_FLAGS +# define SPI_SCK_FLAGS PAL_MODE_ALTERNATE(SPI_SCK_PAL_MODE) | PAL_OUTPUT_TYPE_PUSHPULL | PAL_OUTPUT_SPEED_HIGHEST +#endif + +#ifndef SPI_MOSI_FLAGS +# define SPI_MOSI_FLAGS PAL_MODE_ALTERNATE(SPI_MOSI_PAL_MODE) | PAL_OUTPUT_TYPE_PUSHPULL | PAL_OUTPUT_SPEED_HIGHEST +#endif + +#ifndef SPI_MISO_FLAGS +# define SPI_MISO_FLAGS PAL_MODE_ALTERNATE(SPI_MISO_PAL_MODE) | PAL_OUTPUT_TYPE_PUSHPULL | PAL_OUTPUT_SPEED_HIGHEST +#endif diff --git a/platforms/chibios/drivers/spi_master.c b/platforms/chibios/drivers/spi_master.c index 223d8a403e..de308229ef 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) { palSetPadMode(PAL_PORT(SPI_MOSI_PIN), PAL_PAD(SPI_MOSI_PIN), SPI_MOSI_PAL_MODE); palSetPadMode(PAL_PORT(SPI_MISO_PIN), PAL_PAD(SPI_MISO_PIN), SPI_MISO_PAL_MODE); #else - 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); - 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); - 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); + palSetPadMode(PAL_PORT(SPI_SCK_PIN), PAL_PAD(SPI_SCK_PIN), SPI_SCK_FLAGS); + palSetPadMode(PAL_PORT(SPI_MOSI_PIN), PAL_PAD(SPI_MOSI_PIN), SPI_MOSI_FLAGS); + palSetPadMode(PAL_PORT(SPI_MISO_PIN), PAL_PAD(SPI_MISO_PIN), SPI_MISO_FLAGS); #endif spiUnselect(&SPI_DRIVER); spiStop(&SPI_DRIVER); -- cgit v1.2.3 From dc70ba612a929fdd365275d412e68c61836ed5b8 Mon Sep 17 00:00:00 2001 From: Nick Brassel Date: Thu, 14 Jul 2022 00:41:08 +1000 Subject: Post-bootloader EFL/SPI fixes. (#17661) * Fixup read address for EFL driver. * Fixup sequencing of SPI. * Lock during init of EFL backing store. --- platforms/chibios/drivers/spi_master.c | 1 - platforms/chibios/drivers/wear_leveling/wear_leveling_efl.c | 5 ++++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'platforms') diff --git a/platforms/chibios/drivers/spi_master.c b/platforms/chibios/drivers/spi_master.c index de308229ef..c3ab0623f0 100644 --- a/platforms/chibios/drivers/spi_master.c +++ b/platforms/chibios/drivers/spi_master.c @@ -46,7 +46,6 @@ __attribute__((weak)) void spi_init(void) { palSetPadMode(PAL_PORT(SPI_MOSI_PIN), PAL_PAD(SPI_MOSI_PIN), SPI_MOSI_FLAGS); palSetPadMode(PAL_PORT(SPI_MISO_PIN), PAL_PAD(SPI_MISO_PIN), SPI_MISO_FLAGS); #endif - spiUnselect(&SPI_DRIVER); spiStop(&SPI_DRIVER); currentSlavePin = NO_PIN; } diff --git a/platforms/chibios/drivers/wear_leveling/wear_leveling_efl.c b/platforms/chibios/drivers/wear_leveling/wear_leveling_efl.c index 4b5639ee4a..cdd1e26a7d 100644 --- a/platforms/chibios/drivers/wear_leveling/wear_leveling_efl.c +++ b/platforms/chibios/drivers/wear_leveling/wear_leveling_efl.c @@ -43,6 +43,9 @@ bool backing_store_init(void) { bs_dprintf("Init\n"); flash = (BaseFlash *)&EFLD1; + // Need to re-lock the EFL, as if we've just had the bootloader executing it'll already be unlocked. + backing_store_lock(); + const flash_descriptor_t *desc = flashGetDescriptor(flash); uint32_t counter = 0; @@ -132,7 +135,7 @@ bool backing_store_lock(void) { bool backing_store_read(uint32_t address, backing_store_int_t *value) { uint32_t offset = (base_offset + address); - backing_store_int_t *loc = (backing_store_int_t *)offset; + backing_store_int_t *loc = (backing_store_int_t *)flashGetOffsetAddress(flash, offset); *value = ~(*loc); bs_dprintf("Read "); wl_dump(offset, value, sizeof(backing_store_int_t)); -- cgit v1.2.3 From 05f30f0787aaea63f83e4c889891255d379abb6d Mon Sep 17 00:00:00 2001 From: Albert Y <76888457+filterpaper@users.noreply.github.com> Date: Thu, 21 Jul 2022 01:24:34 +0800 Subject: Use Pro Micro pinout for SDA/SCL (#17595) --- platforms/chibios/boards/QMK_PM2040/configs/config.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'platforms') diff --git a/platforms/chibios/boards/QMK_PM2040/configs/config.h b/platforms/chibios/boards/QMK_PM2040/configs/config.h index 9dfe86f12e..8c773f8b19 100644 --- a/platforms/chibios/boards/QMK_PM2040/configs/config.h +++ b/platforms/chibios/boards/QMK_PM2040/configs/config.h @@ -7,10 +7,10 @@ # define I2C_DRIVER I2CD2 #endif #ifndef I2C1_SDA_PIN -# define I2C1_SDA_PIN 2U +# define I2C1_SDA_PIN D1 #endif #ifndef I2C1_SCL_PIN -# define I2C1_SCL_PIN 3U +# define I2C1_SCL_PIN D0 #endif #ifndef RP2040_BOOTLOADER_DOUBLE_TAP_RESET -- cgit v1.2.3 From d510e80b89b5de54d60ff1a3dc1cca0307161fad Mon Sep 17 00:00:00 2001 From: Albert Y <76888457+filterpaper@users.noreply.github.com> Date: Thu, 21 Jul 2022 07:54:05 +0800 Subject: Add Blok 2040 conversion (#17603) --- .../converters/promicro_to_blok/_pin_defs.h | 36 ++++++++++++++++++++++ .../converters/promicro_to_blok/converter.mk | 9 ++++++ 2 files changed, 45 insertions(+) create mode 100644 platforms/chibios/converters/promicro_to_blok/_pin_defs.h create mode 100644 platforms/chibios/converters/promicro_to_blok/converter.mk (limited to 'platforms') diff --git a/platforms/chibios/converters/promicro_to_blok/_pin_defs.h b/platforms/chibios/converters/promicro_to_blok/_pin_defs.h new file mode 100644 index 0000000000..957b84e1a6 --- /dev/null +++ b/platforms/chibios/converters/promicro_to_blok/_pin_defs.h @@ -0,0 +1,36 @@ +// Copyright 2022 QMK +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +// Left side (front) +#define D3 0U +#define D2 1U +// GND +// GND +#define D1 16U +#define D0 17U +#define D4 4U +#define C6 5U +#define D7 6U +#define E6 7U +#define B4 8U +#define B5 9U + +// Right side (front) +// RAW +// GND +// RESET +// VCC +#define F4 29U +#define F5 28U +#define F6 27U +#define F7 26U +#define B1 22U +#define B3 20U +#define B2 23U +#define B6 21U + +// LEDs (Mapped to unused pins to avoid collisions) +#define D5 12U +#define B0 13U diff --git a/platforms/chibios/converters/promicro_to_blok/converter.mk b/platforms/chibios/converters/promicro_to_blok/converter.mk new file mode 100644 index 0000000000..5106e411f4 --- /dev/null +++ b/platforms/chibios/converters/promicro_to_blok/converter.mk @@ -0,0 +1,9 @@ +# Boardsource Blok MCU settings for converting AVR projects +MCU := RP2040 +BOARD := QMK_PM2040 +BOOTLOADER := rp2040 + +# These are defaults based on what has been implemented for RP2040 boards +SERIAL_DRIVER ?= vendor +WS2812_DRIVER ?= vendor +BACKLIGHT_DRIVER ?= software -- cgit v1.2.3 From 083b42068a284765c5dd18c2f04ed542d157ffc9 Mon Sep 17 00:00:00 2001 From: Stefan Kerkmann Date: Tue, 26 Jul 2022 21:40:14 +0200 Subject: Chibios: Stop I2C peripheral on transaction error (#17798) From the ChibiOS HAL I2C driver pages: After a timeout the driver must be stopped and restarted because the bus is in an uncertain state. This commit does that stopping explicitly on any error that occurred, not only timeouts. As all the i2c functions restart the peripheral if necessary it is safe to do so. Co-authored-by: Dasky <32983009+daskygit@users.noreply.github.com> Co-authored-by: Dasky <32983009+daskygit@users.noreply.github.com> --- platforms/chibios/drivers/i2c_master.c | 39 +++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 15 deletions(-) (limited to 'platforms') diff --git a/platforms/chibios/drivers/i2c_master.c b/platforms/chibios/drivers/i2c_master.c index 21e064b1dc..bf8f1ee236 100644 --- a/platforms/chibios/drivers/i2c_master.c +++ b/platforms/chibios/drivers/i2c_master.c @@ -107,16 +107,25 @@ static const I2CConfig i2cconfig = { #endif }; -static i2c_status_t chibios_to_qmk(const msg_t* status) { - switch (*status) { - case I2C_NO_ERROR: - return I2C_STATUS_SUCCESS; - case I2C_TIMEOUT: - return I2C_STATUS_TIMEOUT; - // I2C_BUS_ERROR, I2C_ARBITRATION_LOST, I2C_ACK_FAILURE, I2C_OVERRUN, I2C_PEC_ERROR, I2C_SMB_ALERT - default: - return I2C_STATUS_ERROR; +/** + * @brief Handles any I2C error condition by stopping the I2C peripheral and + * aborting any ongoing transactions. Furthermore ChibiOS status codes are + * converted into QMK codes. + * + * @param status ChibiOS specific I2C status code + * @return i2c_status_t QMK specific I2C status code + */ +static i2c_status_t i2c_epilogue(const msg_t status) { + if (status == I2C_NO_ERROR) { + return I2C_STATUS_SUCCESS; } + + // From ChibiOS HAL: "After a timeout the driver must be stopped and + // restarted because the bus is in an uncertain state." We also issue that + // hard stop in case of any error. + i2c_stop(); + + return status == I2C_TIMEOUT ? I2C_STATUS_TIMEOUT : I2C_STATUS_ERROR; } __attribute__((weak)) void i2c_init(void) { @@ -149,14 +158,14 @@ i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, i2c_address = address; i2cStart(&I2C_DRIVER, &i2cconfig); msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), data, length, 0, 0, TIME_MS2I(timeout)); - return chibios_to_qmk(&status); + return i2c_epilogue(status); } i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout) { i2c_address = address; i2cStart(&I2C_DRIVER, &i2cconfig); msg_t status = i2cMasterReceiveTimeout(&I2C_DRIVER, (i2c_address >> 1), data, length, TIME_MS2I(timeout)); - return chibios_to_qmk(&status); + return i2c_epilogue(status); } i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout) { @@ -170,7 +179,7 @@ i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, complete_packet[0] = regaddr; msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), complete_packet, length + 1, 0, 0, TIME_MS2I(timeout)); - return chibios_to_qmk(&status); + return i2c_epilogue(status); } i2c_status_t i2c_writeReg16(uint8_t devaddr, uint16_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout) { @@ -185,14 +194,14 @@ i2c_status_t i2c_writeReg16(uint8_t devaddr, uint16_t regaddr, const uint8_t* da complete_packet[1] = regaddr & 0xFF; msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), complete_packet, length + 2, 0, 0, TIME_MS2I(timeout)); - return chibios_to_qmk(&status); + return i2c_epilogue(status); } i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) { i2c_address = devaddr; i2cStart(&I2C_DRIVER, &i2cconfig); msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), ®addr, 1, data, length, TIME_MS2I(timeout)); - return chibios_to_qmk(&status); + return i2c_epilogue(status); } i2c_status_t i2c_readReg16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout) { @@ -200,7 +209,7 @@ i2c_status_t i2c_readReg16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uin i2cStart(&I2C_DRIVER, &i2cconfig); uint8_t register_packet[2] = {regaddr >> 8, regaddr & 0xFF}; msg_t status = i2cMasterTransmitTimeout(&I2C_DRIVER, (i2c_address >> 1), register_packet, 2, data, length, TIME_MS2I(timeout)); - return chibios_to_qmk(&status); + return i2c_epilogue(status); } void i2c_stop(void) { -- cgit v1.2.3 From 157ea964117de382b52229db87a55340830839c9 Mon Sep 17 00:00:00 2001 From: Stefan Kerkmann Date: Thu, 28 Jul 2022 03:02:10 +0200 Subject: ChibiOS: use correct status codes in i2c_master.c (#17808) msg_t is MSG_OK in the success case and either MSG_RESET or MSG_TIMEOUT in case of errors. So actually use them in the comparison. --- platforms/chibios/drivers/i2c_master.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'platforms') diff --git a/platforms/chibios/drivers/i2c_master.c b/platforms/chibios/drivers/i2c_master.c index bf8f1ee236..4c7a5daa17 100644 --- a/platforms/chibios/drivers/i2c_master.c +++ b/platforms/chibios/drivers/i2c_master.c @@ -116,7 +116,7 @@ static const I2CConfig i2cconfig = { * @return i2c_status_t QMK specific I2C status code */ static i2c_status_t i2c_epilogue(const msg_t status) { - if (status == I2C_NO_ERROR) { + if (status == MSG_OK) { return I2C_STATUS_SUCCESS; } @@ -125,7 +125,7 @@ static i2c_status_t i2c_epilogue(const msg_t status) { // hard stop in case of any error. i2c_stop(); - return status == I2C_TIMEOUT ? I2C_STATUS_TIMEOUT : I2C_STATUS_ERROR; + return status == MSG_TIMEOUT ? I2C_STATUS_TIMEOUT : I2C_STATUS_ERROR; } __attribute__((weak)) void i2c_init(void) { -- cgit v1.2.3 From a204523bbb22d45e2968d1ded64d499b9777f37f Mon Sep 17 00:00:00 2001 From: Stefan Kerkmann Date: Fri, 29 Jul 2022 20:13:16 +0200 Subject: [Core] RP2040 disable PIO IRQs on serial timeout (#17839) --- platforms/chibios/drivers/vendor/RP/RP2040/serial_vendor.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'platforms') diff --git a/platforms/chibios/drivers/vendor/RP/RP2040/serial_vendor.c b/platforms/chibios/drivers/vendor/RP/RP2040/serial_vendor.c index 338146dadd..764764b3f9 100644 --- a/platforms/chibios/drivers/vendor/RP/RP2040/serial_vendor.c +++ b/platforms/chibios/drivers/vendor/RP/RP2040/serial_vendor.c @@ -206,6 +206,7 @@ static inline msg_t sync_tx(sysinterval_t timeout) { pio_set_irq0_source_enabled(pio, pis_sm0_tx_fifo_not_full + tx_state_machine, true); msg = osalThreadSuspendTimeoutS(&tx_thread, timeout); if (msg < MSG_OK) { + pio_set_irq0_source_enabled(pio, pis_sm0_tx_fifo_not_full + tx_state_machine, false); break; } } @@ -265,6 +266,7 @@ static inline msg_t sync_rx(sysinterval_t timeout) { pio_set_irq0_source_enabled(pio, pis_sm0_rx_fifo_not_empty + rx_state_machine, true); msg = osalThreadSuspendTimeoutS(&rx_thread, timeout); if (msg < MSG_OK) { + pio_set_irq0_source_enabled(pio, pis_sm0_rx_fifo_not_empty + rx_state_machine, false); break; } } -- cgit v1.2.3 From 98d5c77521961fa19d0ff81e941e78997d96dfb0 Mon Sep 17 00:00:00 2001 From: Joel Challis Date: Sun, 31 Jul 2022 22:15:01 +0100 Subject: Remove legacy AVR ssd1306 driver (#17864) --- platforms/avr/drivers/ssd1306.c | 329 ---------------------------------------- platforms/avr/drivers/ssd1306.h | 87 ----------- 2 files changed, 416 deletions(-) delete mode 100644 platforms/avr/drivers/ssd1306.c delete mode 100644 platforms/avr/drivers/ssd1306.h (limited to 'platforms') diff --git a/platforms/avr/drivers/ssd1306.c b/platforms/avr/drivers/ssd1306.c deleted file mode 100644 index 7afbc09f00..0000000000 --- a/platforms/avr/drivers/ssd1306.c +++ /dev/null @@ -1,329 +0,0 @@ -#ifdef SSD1306OLED - -# include "ssd1306.h" -# include "i2c.h" -# include -# include "print.h" -# include "glcdfont.c" -# ifdef PROTOCOL_LUFA -# include "lufa.h" -# endif -# include "sendchar.h" -# include "timer.h" - -struct CharacterMatrix display; - -// Set this to 1 to help diagnose early startup problems -// when testing power-on with ble. Turn it off otherwise, -// as the latency of printing most of the debug info messes -// with the matrix scan, causing keys to drop. -# define DEBUG_TO_SCREEN 0 - -// static uint16_t last_battery_update; -// static uint32_t vbat; -//#define BatteryUpdateInterval 10000 /* milliseconds */ -# define ScreenOffInterval 300000 /* milliseconds */ -# if DEBUG_TO_SCREEN -static uint8_t displaying; -# endif -static uint16_t last_flush; - -// Write command sequence. -// Returns true on success. -static inline bool _send_cmd1(uint8_t cmd) { - bool res = false; - - if (i2c_start_write(SSD1306_ADDRESS)) { - xprintf("failed to start write to %d\n", SSD1306_ADDRESS); - goto done; - } - - if (i2c_master_write(0x0 /* command byte follows */)) { - print("failed to write control byte\n"); - - goto done; - } - - if (i2c_master_write(cmd)) { - xprintf("failed to write command %d\n", cmd); - goto done; - } - res = true; -done: - i2c_master_stop(); - return res; -} - -// Write 2-byte command sequence. -// Returns true on success -static inline bool _send_cmd2(uint8_t cmd, uint8_t opr) { - if (!_send_cmd1(cmd)) { - return false; - } - return _send_cmd1(opr); -} - -// Write 3-byte command sequence. -// Returns true on success -static inline bool _send_cmd3(uint8_t cmd, uint8_t opr1, uint8_t opr2) { - if (!_send_cmd1(cmd)) { - return false; - } - if (!_send_cmd1(opr1)) { - return false; - } - return _send_cmd1(opr2); -} - -# define send_cmd1(c) \ - if (!_send_cmd1(c)) { \ - goto done; \ - } -# define send_cmd2(c, o) \ - if (!_send_cmd2(c, o)) { \ - goto done; \ - } -# define send_cmd3(c, o1, o2) \ - if (!_send_cmd3(c, o1, o2)) { \ - goto done; \ - } - -static void clear_display(void) { - matrix_clear(&display); - - // Clear all of the display bits (there can be random noise - // in the RAM on startup) - send_cmd3(PageAddr, 0, (DisplayHeight / 8) - 1); - send_cmd3(ColumnAddr, 0, DisplayWidth - 1); - - if (i2c_start_write(SSD1306_ADDRESS)) { - goto done; - } - if (i2c_master_write(0x40)) { - // Data mode - goto done; - } - for (uint8_t row = 0; row < MatrixRows; ++row) { - for (uint8_t col = 0; col < DisplayWidth; ++col) { - i2c_master_write(0); - } - } - - display.dirty = false; - -done: - i2c_master_stop(); -} - -# if DEBUG_TO_SCREEN -# undef sendchar -static int8_t capture_sendchar(uint8_t c) { - sendchar(c); - iota_gfx_write_char(c); - - if (!displaying) { - iota_gfx_flush(); - } - return 0; -} -# endif - -bool iota_gfx_init(void) { - bool success = false; - - send_cmd1(DisplayOff); - send_cmd2(SetDisplayClockDiv, 0x80); - send_cmd2(SetMultiPlex, DisplayHeight - 1); - - send_cmd2(SetDisplayOffset, 0); - - send_cmd1(SetStartLine | 0x0); - send_cmd2(SetChargePump, 0x14 /* Enable */); - send_cmd2(SetMemoryMode, 0 /* horizontal addressing */); - -# ifdef OLED_ROTATE180 - // the following Flip the display orientation 180 degrees - send_cmd1(SegRemap); - send_cmd1(ComScanInc); -# endif -# ifndef OLED_ROTATE180 - // Flips the display orientation 0 degrees - send_cmd1(SegRemap | 0x1); - send_cmd1(ComScanDec); -# endif - - send_cmd2(SetComPins, 0x2); - send_cmd2(SetContrast, 0x8f); - send_cmd2(SetPreCharge, 0xf1); - send_cmd2(SetVComDetect, 0x40); - send_cmd1(DisplayAllOnResume); - send_cmd1(NormalDisplay); - send_cmd1(DeActivateScroll); - send_cmd1(DisplayOn); - - send_cmd2(SetContrast, 0); // Dim - - clear_display(); - - success = true; - - iota_gfx_flush(); - -# if DEBUG_TO_SCREEN - print_set_sendchar(capture_sendchar); -# endif - -done: - return success; -} - -bool iota_gfx_off(void) { - bool success = false; - - send_cmd1(DisplayOff); - success = true; - -done: - return success; -} - -bool iota_gfx_on(void) { - bool success = false; - - send_cmd1(DisplayOn); - success = true; - -done: - return success; -} - -void matrix_write_char_inner(struct CharacterMatrix *matrix, uint8_t c) { - *matrix->cursor = c; - ++matrix->cursor; - - if (matrix->cursor - &matrix->display[0][0] == sizeof(matrix->display)) { - // We went off the end; scroll the display upwards by one line - memmove(&matrix->display[0], &matrix->display[1], MatrixCols * (MatrixRows - 1)); - matrix->cursor = &matrix->display[MatrixRows - 1][0]; - memset(matrix->cursor, ' ', MatrixCols); - } -} - -void matrix_write_char(struct CharacterMatrix *matrix, uint8_t c) { - matrix->dirty = true; - - if (c == '\n') { - // Clear to end of line from the cursor and then move to the - // start of the next line - uint8_t cursor_col = (matrix->cursor - &matrix->display[0][0]) % MatrixCols; - - while (cursor_col++ < MatrixCols) { - matrix_write_char_inner(matrix, ' '); - } - return; - } - - matrix_write_char_inner(matrix, c); -} - -void iota_gfx_write_char(uint8_t c) { - matrix_write_char(&display, c); -} - -void matrix_write(struct CharacterMatrix *matrix, const char *data) { - const char *end = data + strlen(data); - while (data < end) { - matrix_write_char(matrix, *data); - ++data; - } -} - -void iota_gfx_write(const char *data) { - matrix_write(&display, data); -} - -void matrix_write_P(struct CharacterMatrix *matrix, const char *data) { - while (true) { - uint8_t c = pgm_read_byte(data); - if (c == 0) { - return; - } - matrix_write_char(matrix, c); - ++data; - } -} - -void iota_gfx_write_P(const char *data) { - matrix_write_P(&display, data); -} - -void matrix_clear(struct CharacterMatrix *matrix) { - memset(matrix->display, ' ', sizeof(matrix->display)); - matrix->cursor = &matrix->display[0][0]; - matrix->dirty = true; -} - -void iota_gfx_clear_screen(void) { - matrix_clear(&display); -} - -void matrix_render(struct CharacterMatrix *matrix) { - last_flush = timer_read(); - iota_gfx_on(); -# if DEBUG_TO_SCREEN - ++displaying; -# endif - - // Move to the home position - send_cmd3(PageAddr, 0, MatrixRows - 1); - send_cmd3(ColumnAddr, 0, (MatrixCols * FontWidth) - 1); - - if (i2c_start_write(SSD1306_ADDRESS)) { - goto done; - } - if (i2c_master_write(0x40)) { - // Data mode - goto done; - } - - for (uint8_t row = 0; row < MatrixRows; ++row) { - for (uint8_t col = 0; col < MatrixCols; ++col) { - const uint8_t *glyph = font + (matrix->display[row][col] * (FontWidth - 1)); - - for (uint8_t glyphCol = 0; glyphCol < FontWidth - 1; ++glyphCol) { - uint8_t colBits = pgm_read_byte(glyph + glyphCol); - i2c_master_write(colBits); - } - - // 1 column of space between chars (it's not included in the glyph) - i2c_master_write(0); - } - } - - matrix->dirty = false; - -done: - i2c_master_stop(); -# if DEBUG_TO_SCREEN - --displaying; -# endif -} - -void iota_gfx_flush(void) { - matrix_render(&display); -} - -__attribute__((weak)) void iota_gfx_task_user(void) {} - -void iota_gfx_task(void) { - iota_gfx_task_user(); - - if (display.dirty) { - iota_gfx_flush(); - } - - if (timer_elapsed(last_flush) > ScreenOffInterval) { - iota_gfx_off(); - } -} -#endif diff --git a/platforms/avr/drivers/ssd1306.h b/platforms/avr/drivers/ssd1306.h deleted file mode 100644 index 6eecdcfaa4..0000000000 --- a/platforms/avr/drivers/ssd1306.h +++ /dev/null @@ -1,87 +0,0 @@ -#pragma once - -#include -#include -#include "config.h" - -enum ssd1306_cmds { - DisplayOff = 0xAE, - DisplayOn = 0xAF, - - SetContrast = 0x81, - DisplayAllOnResume = 0xA4, - - DisplayAllOn = 0xA5, - NormalDisplay = 0xA6, - InvertDisplay = 0xA7, - SetDisplayOffset = 0xD3, - SetComPins = 0xda, - SetVComDetect = 0xdb, - SetDisplayClockDiv = 0xD5, - SetPreCharge = 0xd9, - SetMultiPlex = 0xa8, - SetLowColumn = 0x00, - SetHighColumn = 0x10, - SetStartLine = 0x40, - - SetMemoryMode = 0x20, - ColumnAddr = 0x21, - PageAddr = 0x22, - - ComScanInc = 0xc0, - ComScanDec = 0xc8, - SegRemap = 0xa0, - SetChargePump = 0x8d, - ExternalVcc = 0x01, - SwitchCapVcc = 0x02, - - ActivateScroll = 0x2f, - DeActivateScroll = 0x2e, - SetVerticalScrollArea = 0xa3, - RightHorizontalScroll = 0x26, - LeftHorizontalScroll = 0x27, - VerticalAndRightHorizontalScroll = 0x29, - VerticalAndLeftHorizontalScroll = 0x2a, -}; - -// Controls the SSD1306 128x32 OLED display via i2c - -#ifndef SSD1306_ADDRESS -# define SSD1306_ADDRESS 0x3C -#endif - -#define DisplayHeight 32 -#define DisplayWidth 128 - -#define FontHeight 8 -#define FontWidth 6 - -#define MatrixRows (DisplayHeight / FontHeight) -#define MatrixCols (DisplayWidth / FontWidth) - -struct CharacterMatrix { - uint8_t display[MatrixRows][MatrixCols]; - uint8_t *cursor; - bool dirty; -}; - -extern struct CharacterMatrix display; - -bool iota_gfx_init(void); -void iota_gfx_task(void); -bool iota_gfx_off(void); -bool iota_gfx_on(void); -void iota_gfx_flush(void); -void iota_gfx_write_char(uint8_t c); -void iota_gfx_write(const char *data); -void iota_gfx_write_P(const char *data); -void iota_gfx_clear_screen(void); - -void iota_gfx_task_user(void); - -void matrix_clear(struct CharacterMatrix *matrix); -void matrix_write_char_inner(struct CharacterMatrix *matrix, uint8_t c); -void matrix_write_char(struct CharacterMatrix *matrix, uint8_t c); -void matrix_write(struct CharacterMatrix *matrix, const char *data); -void matrix_write_P(struct CharacterMatrix *matrix, const char *data); -void matrix_render(struct CharacterMatrix *matrix); -- cgit v1.2.3 From 543f54a483842474d2333581597dd4691bb77fac Mon Sep 17 00:00:00 2001 From: Nick Brassel Date: Thu, 4 Aug 2022 21:05:16 +1000 Subject: [Core] `STM32_USB_USE_OTG1` => `USB_ENDPOINTS_ARE_REORDERABLE` (#17647) --- platforms/chibios/boards/GENERIC_WB32_F3G71XX/configs/config.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'platforms') diff --git a/platforms/chibios/boards/GENERIC_WB32_F3G71XX/configs/config.h b/platforms/chibios/boards/GENERIC_WB32_F3G71XX/configs/config.h index 9fdc825669..437a8e4df2 100644 --- a/platforms/chibios/boards/GENERIC_WB32_F3G71XX/configs/config.h +++ b/platforms/chibios/boards/GENERIC_WB32_F3G71XX/configs/config.h @@ -18,3 +18,5 @@ #ifndef EARLY_INIT_PERFORM_BOOTLOADER_JUMP # define EARLY_INIT_PERFORM_BOOTLOADER_JUMP TRUE #endif + +#define USB_ENDPOINTS_ARE_REORDERABLE -- cgit v1.2.3 From 94e8701b3e62647866e52b9e1086017aab4be2f9 Mon Sep 17 00:00:00 2001 From: Nick Brassel Date: Thu, 4 Aug 2022 21:44:56 +1000 Subject: Fixup compilation of printf-like functions with uint32_t args. (#17904) --- platforms/chibios/drivers/eeprom/eeprom_stm32.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'platforms') diff --git a/platforms/chibios/drivers/eeprom/eeprom_stm32.c b/platforms/chibios/drivers/eeprom/eeprom_stm32.c index a15bfe09ed..25733fb336 100644 --- a/platforms/chibios/drivers/eeprom/eeprom_stm32.c +++ b/platforms/chibios/drivers/eeprom/eeprom_stm32.c @@ -250,7 +250,7 @@ uint16_t EEPROM_Init(void) { } wvalue = ~*log_addr; if (!wvalue) { - eeprom_printf("Incomplete write at log_addr: 0x%04x;\n", (uint32_t)log_addr); + eeprom_printf("Incomplete write at log_addr: 0x%04lx;\n", (uint32_t)log_addr); /* Possibly incomplete write. Ignore and continue */ continue; } @@ -261,7 +261,7 @@ uint16_t EEPROM_Init(void) { } else { /* Reserved for future use */ if (address & FEE_VALUE_RESERVED) { - eeprom_printf("Reserved encoded value at log_addr: 0x%04x;\n", (uint32_t)log_addr); + eeprom_printf("Reserved encoded value at log_addr: 0x%04lx;\n", (uint32_t)log_addr); continue; } /* Optimization for 0 or 1 values. */ @@ -273,7 +273,7 @@ uint16_t EEPROM_Init(void) { eeprom_printf("DataBuf[0x%04x] = 0x%04x;\n", address, wvalue); *(uint16_t *)(&DataBuf[address]) = wvalue; } else { - eeprom_printf("DataBuf[0x%04x] cannot be set to 0x%04x [BAD ADDRESS]\n", address, wvalue); + eeprom_printf("DataBuf[0x%04x] cannot be set to 0x%04lx [BAD ADDRESS]\n", address, wvalue); } } } @@ -293,14 +293,14 @@ static void eeprom_clear(void) { FLASH_Unlock(); for (uint16_t page_num = 0; page_num < FEE_PAGE_COUNT; ++page_num) { - eeprom_printf("FLASH_ErasePage(0x%04x)\n", (uint32_t)(FEE_PAGE_BASE_ADDRESS + (page_num * FEE_PAGE_SIZE))); + eeprom_printf("FLASH_ErasePage(0x%04lx)\n", (uint32_t)(FEE_PAGE_BASE_ADDRESS + (page_num * FEE_PAGE_SIZE))); FLASH_ErasePage(FEE_PAGE_BASE_ADDRESS + (page_num * FEE_PAGE_SIZE)); } FLASH_Lock(); empty_slot = (uint16_t *)FEE_WRITE_LOG_BASE_ADDRESS; - eeprom_printf("eeprom_clear empty_slot: 0x%08x\n", (uint32_t)empty_slot); + eeprom_printf("eeprom_clear empty_slot: 0x%08lx\n", (uint32_t)empty_slot); } /* Erase emulated eeprom */ @@ -328,7 +328,7 @@ static uint8_t eeprom_compact(void) { for (; dest < FEE_COMPACTED_LAST_ADDRESS; ++src, dest += 2) { value = *src; if (value) { - eeprom_printf("FLASH_ProgramHalfWord(0x%04x, 0x%04x)\n", (uint32_t)dest, ~value); + eeprom_printf("FLASH_ProgramHalfWord(0x%04lx, 0x%04x)\n", (uint32_t)dest, ~value); FLASH_Status status = FLASH_ProgramHalfWord(dest, ~value); if (status != FLASH_COMPLETE) final_status = status; } @@ -355,7 +355,7 @@ static uint8_t eeprom_write_direct_entry(uint16_t Address) { FLASH_Unlock(); - eeprom_printf("FLASH_ProgramHalfWord(0x%08x, 0x%04x) [DIRECT]\n", (uint32_t)directAddress, value); + eeprom_printf("FLASH_ProgramHalfWord(0x%08lx, 0x%04x) [DIRECT]\n", (uint32_t)directAddress, value); FLASH_Status status = FLASH_ProgramHalfWord(directAddress, value); FLASH_Lock(); @@ -397,12 +397,12 @@ static uint8_t eeprom_write_log_word_entry(uint16_t Address) { FLASH_Unlock(); /* address */ - eeprom_printf("FLASH_ProgramHalfWord(0x%08x, 0x%04x)\n", (uint32_t)empty_slot, Address); + eeprom_printf("FLASH_ProgramHalfWord(0x%08lx, 0x%04x)\n", (uint32_t)empty_slot, Address); final_status = FLASH_ProgramHalfWord((uintptr_t)empty_slot++, Address); /* value */ if (encoding == (FEE_WORD_ENCODING | FEE_VALUE_NEXT)) { - eeprom_printf("FLASH_ProgramHalfWord(0x%08x, 0x%04x)\n", (uint32_t)empty_slot, ~value); + eeprom_printf("FLASH_ProgramHalfWord(0x%08lx, 0x%04x)\n", (uint32_t)empty_slot, ~value); FLASH_Status status = FLASH_ProgramHalfWord((uintptr_t)empty_slot++, ~value); if (status != FLASH_COMPLETE) final_status = status; } @@ -428,7 +428,7 @@ static uint8_t eeprom_write_log_byte_entry(uint16_t Address) { uint16_t value = (Address << 8) | DataBuf[Address]; /* write to flash */ - eeprom_printf("FLASH_ProgramHalfWord(0x%08x, 0x%04x)\n", (uint32_t)empty_slot, value); + eeprom_printf("FLASH_ProgramHalfWord(0x%08lx, 0x%04x)\n", (uint32_t)empty_slot, value); FLASH_Status status = FLASH_ProgramHalfWord((uintptr_t)empty_slot++, value); FLASH_Lock(); -- cgit v1.2.3 From d9eb152a90da0bedb0047b67e4f5ebb53e64b422 Mon Sep 17 00:00:00 2001 From: Nick Brassel Date: Thu, 4 Aug 2022 22:15:42 +1000 Subject: Fix issue with #17904. (#17905) --- platforms/chibios/drivers/eeprom/eeprom_stm32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'platforms') diff --git a/platforms/chibios/drivers/eeprom/eeprom_stm32.c b/platforms/chibios/drivers/eeprom/eeprom_stm32.c index 25733fb336..1a354dc213 100644 --- a/platforms/chibios/drivers/eeprom/eeprom_stm32.c +++ b/platforms/chibios/drivers/eeprom/eeprom_stm32.c @@ -273,7 +273,7 @@ uint16_t EEPROM_Init(void) { eeprom_printf("DataBuf[0x%04x] = 0x%04x;\n", address, wvalue); *(uint16_t *)(&DataBuf[address]) = wvalue; } else { - eeprom_printf("DataBuf[0x%04x] cannot be set to 0x%04lx [BAD ADDRESS]\n", address, wvalue); + eeprom_printf("DataBuf[0x%04x] cannot be set to 0x%04x [BAD ADDRESS]\n", address, wvalue); } } } -- cgit v1.2.3 From 9e443621796a150b244d49a784b77c744ea04d94 Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Fri, 12 Aug 2022 00:37:41 +0300 Subject: Add minimal STM32F103C6 support (#17853) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unfortunately, the crippled versions of “Bluepill” boards with STM32F103C6xx chips instead of STM32F103C8xx are now sold all over the place, sometimes advertised in a confusing way to make the difference not noticeable until too late. Add minimal support for these MCUs in the common “Bluepill with stm32duino” configuration, so that it could be possible to make something useful from those boards (although fitting QMK into the available 24 KiB of flash may be rather hard). (In fact, I'm not sure whether the “STM32” part of the chip name is actually correct for those boards of uncertain origin, so the onekey board name is `bluepill_f103c6`; another reason for that name is to match the existing `blackpill_f401` and `blackpill_f411`.) The EEPROM emulation support is not included on purpose, because enabling it without having a working firmware size check would be irresponsible with such flash size (the chance that someone would build a firmware where the EEPROM backing store ends up overlapping some firmware code is really high). Other than that, enabling the EEPROM emulation code is mostly trivial (the `wear_leveling` driver with the `embedded_flash` backing store even works without any custom configuration, although its code is significantly larger than the `vendor` driver, which may also be important for such flash size). --- .../boards/STM32_F103_STM32DUINO/board/board.c | 2 ++ .../ld/STM32F103x6_stm32duino_bootloader.ld | 23 ++++++++++++++++++++++ .../ld/STM32F103x8_stm32duino_bootloader.ld | 1 + .../ld/STM32F103xB_stm32duino_bootloader.ld | 1 + .../ld/stm32duino_bootloader_common.ld | 2 +- 5 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 platforms/chibios/boards/STM32_F103_STM32DUINO/ld/STM32F103x6_stm32duino_bootloader.ld (limited to 'platforms') diff --git a/platforms/chibios/boards/STM32_F103_STM32DUINO/board/board.c b/platforms/chibios/boards/STM32_F103_STM32DUINO/board/board.c index cba977da77..e82e1d37ce 100644 --- a/platforms/chibios/boards/STM32_F103_STM32DUINO/board/board.c +++ b/platforms/chibios/boards/STM32_F103_STM32DUINO/board/board.c @@ -28,7 +28,9 @@ const PALConfig pal_default_config = {VAL_GPIOBODR, VAL_GPIOBCRL, VAL_GPIOBCRH}, {VAL_GPIOCODR, VAL_GPIOCCRL, VAL_GPIOCCRH}, {VAL_GPIODODR, VAL_GPIODCRL, VAL_GPIODCRH}, +# if STM32_HAS_GPIOE {VAL_GPIOEODR, VAL_GPIOECRL, VAL_GPIOECRH}, +# endif }; #endif diff --git a/platforms/chibios/boards/STM32_F103_STM32DUINO/ld/STM32F103x6_stm32duino_bootloader.ld b/platforms/chibios/boards/STM32_F103_STM32DUINO/ld/STM32F103x6_stm32duino_bootloader.ld new file mode 100644 index 0000000000..18aaff2a23 --- /dev/null +++ b/platforms/chibios/boards/STM32_F103_STM32DUINO/ld/STM32F103x6_stm32duino_bootloader.ld @@ -0,0 +1,23 @@ +/* + ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* + * STM32F103x6 memory setup for use with the STM32Duino bootloader. + */ +f103_flash_size = 32k; +f103_ram_size = 10k; + +INCLUDE stm32duino_bootloader_common.ld diff --git a/platforms/chibios/boards/STM32_F103_STM32DUINO/ld/STM32F103x8_stm32duino_bootloader.ld b/platforms/chibios/boards/STM32_F103_STM32DUINO/ld/STM32F103x8_stm32duino_bootloader.ld index a4bd566b59..465af12cab 100644 --- a/platforms/chibios/boards/STM32_F103_STM32DUINO/ld/STM32F103x8_stm32duino_bootloader.ld +++ b/platforms/chibios/boards/STM32_F103_STM32DUINO/ld/STM32F103x8_stm32duino_bootloader.ld @@ -18,5 +18,6 @@ * STM32F103x8 memory setup for use with the STM32Duino bootloader. */ f103_flash_size = 64k; +f103_ram_size = 20k; INCLUDE stm32duino_bootloader_common.ld diff --git a/platforms/chibios/boards/STM32_F103_STM32DUINO/ld/STM32F103xB_stm32duino_bootloader.ld b/platforms/chibios/boards/STM32_F103_STM32DUINO/ld/STM32F103xB_stm32duino_bootloader.ld index dc47400dc5..3a47a33156 100644 --- a/platforms/chibios/boards/STM32_F103_STM32DUINO/ld/STM32F103xB_stm32duino_bootloader.ld +++ b/platforms/chibios/boards/STM32_F103_STM32DUINO/ld/STM32F103xB_stm32duino_bootloader.ld @@ -18,5 +18,6 @@ * STM32F103xB memory setup for use with the STM32Duino bootloader. */ f103_flash_size = 128k; +f103_ram_size = 20k; INCLUDE stm32duino_bootloader_common.ld diff --git a/platforms/chibios/boards/STM32_F103_STM32DUINO/ld/stm32duino_bootloader_common.ld b/platforms/chibios/boards/STM32_F103_STM32DUINO/ld/stm32duino_bootloader_common.ld index 76cd3153be..1466ae7ed2 100644 --- a/platforms/chibios/boards/STM32_F103_STM32DUINO/ld/stm32duino_bootloader_common.ld +++ b/platforms/chibios/boards/STM32_F103_STM32DUINO/ld/stm32duino_bootloader_common.ld @@ -27,7 +27,7 @@ MEMORY flash5 : org = 0x00000000, len = 0 flash6 : org = 0x00000000, len = 0 flash7 : org = 0x00000000, len = 0 - ram0 : org = 0x20000000, len = 20k + ram0 : org = 0x20000000, len = f103_ram_size ram1 : org = 0x00000000, len = 0 ram2 : org = 0x00000000, len = 0 ram3 : org = 0x00000000, len = 0 -- cgit v1.2.3 From 19ce1418badbf04b0b675c2e81a184e93b14141f Mon Sep 17 00:00:00 2001 From: Joy Lee Date: Sat, 13 Aug 2022 09:14:33 +0800 Subject: Added implementation of WB32 MCU wear_leveling_efl. (#17579) --- platforms/chibios/drivers/wear_leveling/wear_leveling_efl_config.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'platforms') diff --git a/platforms/chibios/drivers/wear_leveling/wear_leveling_efl_config.h b/platforms/chibios/drivers/wear_leveling/wear_leveling_efl_config.h index 9e38c2965d..244c87cb7f 100644 --- a/platforms/chibios/drivers/wear_leveling/wear_leveling_efl_config.h +++ b/platforms/chibios/drivers/wear_leveling/wear_leveling_efl_config.h @@ -14,6 +14,8 @@ # define BACKING_STORE_WRITE_SIZE 2 // from hal_efl_lld.c # elif defined(QMK_MCU_FAMILY_NUC123) # define BACKING_STORE_WRITE_SIZE 4 // from hal_efl_lld.c +# elif defined(QMK_MCU_FAMILY_WB32) +# define BACKING_STORE_WRITE_SIZE 8 // from hal_efl_lld.c # elif defined(QMK_MCU_FAMILY_STM32) # if defined(STM32_FLASH_LINE_SIZE) // from some family's stm32_registry.h file # define BACKING_STORE_WRITE_SIZE (STM32_FLASH_LINE_SIZE) -- cgit v1.2.3 From 4eeafbebabfac04eada98f75dedbecdbbd16298c Mon Sep 17 00:00:00 2001 From: Jay Greco Date: Sat, 13 Aug 2022 06:48:30 -0700 Subject: Add Bit-C PRO converter (#17827) --- .../converters/promicro_to_bit_c_pro/_pin_defs.h | 39 ++++++++++++++++++++++ .../converters/promicro_to_bit_c_pro/converter.mk | 12 +++++++ 2 files changed, 51 insertions(+) create mode 100644 platforms/chibios/converters/promicro_to_bit_c_pro/_pin_defs.h create mode 100644 platforms/chibios/converters/promicro_to_bit_c_pro/converter.mk (limited to 'platforms') diff --git a/platforms/chibios/converters/promicro_to_bit_c_pro/_pin_defs.h b/platforms/chibios/converters/promicro_to_bit_c_pro/_pin_defs.h new file mode 100644 index 0000000000..92e8fbfa1a --- /dev/null +++ b/platforms/chibios/converters/promicro_to_bit_c_pro/_pin_defs.h @@ -0,0 +1,39 @@ +// Copyright 2022 QMK +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +// Left side (front) +#define D3 0U +#define D2 1U +// GND +// GND +#define D1 2U +#define D0 3U +#define D4 4U +#define C6 5U +#define D7 6U +#define E6 7U +#define B4 8U +#define B5 9U + +// Right side (front) +// RAW +// GND +// RESET +// VCC +#define F4 29U +#define F5 28U +#define F6 27U +#define F7 26U +#define B1 22U +#define B3 20U +#define B2 23U +#define B6 21U + +// LEDs (Mapped to R and G channel of the Bit-C PRO's RGB led) +#define D5 16U +#define B0 17U + +// Bit-C LED (mapped to B channel of the Bit-C PRO's RGB led) +#define F0 18U diff --git a/platforms/chibios/converters/promicro_to_bit_c_pro/converter.mk b/platforms/chibios/converters/promicro_to_bit_c_pro/converter.mk new file mode 100644 index 0000000000..c0eaee8593 --- /dev/null +++ b/platforms/chibios/converters/promicro_to_bit_c_pro/converter.mk @@ -0,0 +1,12 @@ +# nullbits Bit-C PRO MCU settings for converting AVR projects +MCU := RP2040 +BOARD := QMK_PM2040 +BOOTLOADER := rp2040 + +# These are defaults based on what has been implemented for RP2040 boards +SERIAL_DRIVER ?= vendor +WS2812_DRIVER ?= vendor +BACKLIGHT_DRIVER ?= software + +# Tell QMK to use the correct 2nd stage bootloader +OPT_DEFS += -DRP2040_FLASH_W25X10CL -- cgit v1.2.3 From a83afb3fcd741d0de391f21196ea79066fe88076 Mon Sep 17 00:00:00 2001 From: Takeshi ISHII <2170248+mtei@users.noreply.github.com> Date: Sun, 14 Aug 2022 08:04:03 +0900 Subject: Improve avr wait_us() (#16879) --- platforms/avr/_wait.h | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) (limited to 'platforms') diff --git a/platforms/avr/_wait.h b/platforms/avr/_wait.h index 683db6ae57..c1a598a428 100644 --- a/platforms/avr/_wait.h +++ b/platforms/avr/_wait.h @@ -17,6 +17,26 @@ #include +// http://ww1.microchip.com/downloads/en/devicedoc/atmel-0856-avr-instruction-set-manual.pdf +// page 22: Table 4-2. Arithmetic and Logic Instructions +/* + for (uint16_t i = times; i > 0; i--) { + __builtin_avr_delay_cycles(1); + } + + .L3: sbiw r24,0 // loop step 1 + brne .L4 // loop step 2 + ret + .L4: nop // __builtin_avr_delay_cycles(1); + sbiw r24,1 // loop step 3 + rjmp .L3 // loop step 4 +*/ + +#define AVR_sbiw_clocks 2 +#define AVR_rjmp_clocks 2 +#define AVR_brne_clocks 2 +#define AVR_WAIT_LOOP_OVERHEAD (AVR_sbiw_clocks + AVR_brne_clocks + AVR_sbiw_clocks + AVR_rjmp_clocks) + #define wait_ms(ms) \ do { \ if (__builtin_constant_p(ms)) { \ @@ -27,15 +47,15 @@ } \ } \ } while (0) -#define wait_us(us) \ - do { \ - if (__builtin_constant_p(us)) { \ - _delay_us(us); \ - } else { \ - for (uint16_t i = us; i > 0; i--) { \ - _delay_us(1); \ - } \ - } \ +#define wait_us(us) \ + do { \ + if (__builtin_constant_p(us)) { \ + _delay_us(us); \ + } else { \ + for (uint16_t i = us; i > 0; i--) { \ + __builtin_avr_delay_cycles((F_CPU / 1000000) - AVR_WAIT_LOOP_OVERHEAD); \ + } \ + } \ } while (0) #define wait_cpuclock(n) __builtin_avr_delay_cycles(n) #define CPU_CLOCK F_CPU -- cgit v1.2.3 From 6b1c7d20aadf40655585df465c4680eca5eca7ae Mon Sep 17 00:00:00 2001 From: Joy Lee Date: Sun, 14 Aug 2022 09:09:57 +0800 Subject: Added ws2812_spi support for WB32 MCU (#17143) Co-authored-by: Joy --- platforms/chibios/drivers/ws2812.c | 2 +- platforms/chibios/drivers/ws2812_spi.c | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) (limited to 'platforms') diff --git a/platforms/chibios/drivers/ws2812.c b/platforms/chibios/drivers/ws2812.c index 1b3bb59842..55ac333b1e 100644 --- a/platforms/chibios/drivers/ws2812.c +++ b/platforms/chibios/drivers/ws2812.c @@ -6,7 +6,7 @@ /* Adapted from https://github.com/bigjosh/SimpleNeoPixelDemo/ */ #ifndef NOP_FUDGE -# if defined(STM32F0XX) || defined(STM32F1XX) || defined(GD32VF103) || defined(STM32F3XX) || defined(STM32F4XX) || defined(STM32L0XX) +# if defined(STM32F0XX) || defined(STM32F1XX) || defined(GD32VF103) || defined(STM32F3XX) || defined(STM32F4XX) || defined(STM32L0XX) || defined(WB32F3G71xx) || defined(WB32FQ95xx) # define NOP_FUDGE 0.4 # else # error("NOP_FUDGE configuration required") diff --git a/platforms/chibios/drivers/ws2812_spi.c b/platforms/chibios/drivers/ws2812_spi.c index 01d8148875..9ee552b187 100644 --- a/platforms/chibios/drivers/ws2812_spi.c +++ b/platforms/chibios/drivers/ws2812_spi.c @@ -5,7 +5,11 @@ // Define the spi your LEDs are plugged to here #ifndef WS2812_SPI -# define WS2812_SPI SPID1 +# if defined(WB32F3G71xx) || defined(WB32FQ95xx) +# define WS2812_SPI SPIDQ +# else +# define WS2812_SPI SPID1 +# endif #endif #ifndef WS2812_SPI_MOSI_PAL_MODE @@ -54,6 +58,7 @@ # define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_2 | SPI_CR1_BR_1 | SPI_CR1_BR_0) #else # define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_1 | SPI_CR1_BR_0) // default +# define WS2812_SPI_DIVISOR 16 #endif // Use SPI circular buffer @@ -148,8 +153,14 @@ void ws2812_init(void) { NULL, // end_cb PAL_PORT(RGB_DI_PIN), PAL_PAD(RGB_DI_PIN), +# if defined(WB32F3G71xx) || defined(WB32FQ95xx) + 0, + 0, + WS2812_SPI_DIVISOR +# else WS2812_SPI_DIVISOR_CR1_BR_X, 0 +# endif #else // HAL_SPI_V2 # if SPI_SUPPORTS_CIRCULAR == TRUE -- cgit v1.2.3 From c02d7ae86f5bc24f7f6201eccf09acec3d2879cf Mon Sep 17 00:00:00 2001 From: Joy Lee Date: Sun, 14 Aug 2022 09:21:46 +0800 Subject: Added ws2812_pwm support for WB32 MCU. (#17142) Co-authored-by: Joy --- platforms/chibios/drivers/ws2812_pwm.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) (limited to 'platforms') diff --git a/platforms/chibios/drivers/ws2812_pwm.c b/platforms/chibios/drivers/ws2812_pwm.c index 57187676d7..37c613049f 100644 --- a/platforms/chibios/drivers/ws2812_pwm.c +++ b/platforms/chibios/drivers/ws2812_pwm.c @@ -17,13 +17,25 @@ # define WS2812_PWM_CHANNEL 2 // Channel #endif #ifndef WS2812_PWM_PAL_MODE -# define WS2812_PWM_PAL_MODE 2 // DI Pin's alternate function value +# if defined(WB32F3G71xx) || defined(WB32FQ95xx) +# define WS2812_PWM_PAL_MODE 1 // DI Pin's alternate function value +# else +# define WS2812_PWM_PAL_MODE 2 // DI Pin's alternate function value +# endif #endif #ifndef WS2812_DMA_STREAM -# define WS2812_DMA_STREAM STM32_DMA1_STREAM2 // DMA Stream for TIMx_UP +# if defined(WB32F3G71xx) || defined(WB32FQ95xx) +# define WS2812_DMA_STREAM WB32_DMA1_STREAM1 // DMA Stream for TIMx_UP +# else +# define WS2812_DMA_STREAM STM32_DMA1_STREAM2 // DMA Stream for TIMx_UP +# endif #endif #ifndef WS2812_DMA_CHANNEL -# define WS2812_DMA_CHANNEL 2 // DMA Channel for TIMx_UP +# if defined(WB32F3G71xx) || defined(WB32FQ95xx) +# define WS2812_DMA_CHANNEL WB32_DMAC_HWHIF_TIM2_UP // DMA Channel for TIM2_UP +# else +# define WS2812_DMA_CHANNEL 2 // DMA Channel for TIMx_UP +# endif #endif #if (STM32_DMA_SUPPORTS_DMAMUX == TRUE) && !defined(WS2812_DMAMUX_ID) # error "please consult your MCU's datasheet and specify in your config.h: #define WS2812_DMAMUX_ID STM32_DMAMUX1_TIM?_UP" @@ -284,11 +296,18 @@ void ws2812_init(void) { // Configure DMA // dmaInit(); // Joe added this +#if defined(WB32F3G71xx) || defined(WB32FQ95xx) + dmaStreamAlloc(WS2812_DMA_STREAM - WB32_DMA_STREAM(0), 10, NULL, NULL); + dmaStreamSetSource(WS2812_DMA_STREAM, ws2812_frame_buffer); + dmaStreamSetDestination(WS2812_DMA_STREAM, &(WS2812_PWM_DRIVER.tim->CCR[WS2812_PWM_CHANNEL - 1])); // Ziel ist der An-Zeit im Cap-Comp-Register + dmaStreamSetMode(WS2812_DMA_STREAM, WB32_DMA_CHCFG_HWHIF(WS2812_DMA_CHANNEL) | WB32_DMA_CHCFG_DIR_M2P | WB32_DMA_CHCFG_PSIZE_WORD | WB32_DMA_CHCFG_MSIZE_WORD | WB32_DMA_CHCFG_MINC | WB32_DMA_CHCFG_CIRC | WB32_DMA_CHCFG_TCIE | WB32_DMA_CHCFG_PL(3)); +#else dmaStreamAlloc(WS2812_DMA_STREAM - STM32_DMA_STREAM(0), 10, NULL, NULL); dmaStreamSetPeripheral(WS2812_DMA_STREAM, &(WS2812_PWM_DRIVER.tim->CCR[WS2812_PWM_CHANNEL - 1])); // Ziel ist der An-Zeit im Cap-Comp-Register dmaStreamSetMemory0(WS2812_DMA_STREAM, ws2812_frame_buffer); - dmaStreamSetTransactionSize(WS2812_DMA_STREAM, WS2812_BIT_N); dmaStreamSetMode(WS2812_DMA_STREAM, STM32_DMA_CR_CHSEL(WS2812_DMA_CHANNEL) | STM32_DMA_CR_DIR_M2P | STM32_DMA_CR_PSIZE_WORD | STM32_DMA_CR_MSIZE_WORD | STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_PL(3)); +#endif + dmaStreamSetTransactionSize(WS2812_DMA_STREAM, WS2812_BIT_N); // M2P: Memory 2 Periph; PL: Priority Level #if (STM32_DMA_SUPPORTS_DMAMUX == TRUE) -- cgit v1.2.3 From dfc92d8f7b669af403c5be0121bbb678e5be8611 Mon Sep 17 00:00:00 2001 From: yiancar Date: Sun, 14 Aug 2022 02:36:34 +0100 Subject: Fix buffer size for WS2812 PWM driver (#17046) Co-authored-by: Drashna Jaelre Co-authored-by: Sergey Vlasov Co-authored-by: yiancar --- platforms/chibios/drivers/ws2812_pwm.c | 52 +++++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 4 deletions(-) (limited to 'platforms') diff --git a/platforms/chibios/drivers/ws2812_pwm.c b/platforms/chibios/drivers/ws2812_pwm.c index 37c613049f..8c0259fb91 100644 --- a/platforms/chibios/drivers/ws2812_pwm.c +++ b/platforms/chibios/drivers/ws2812_pwm.c @@ -41,6 +41,22 @@ # error "please consult your MCU's datasheet and specify in your config.h: #define WS2812_DMAMUX_ID STM32_DMAMUX1_TIM?_UP" #endif +/* Summarize https://www.st.com/resource/en/application_note/an4013-stm32-crossseries-timer-overview-stmicroelectronics.pdf to + * figure out if we are using a 32bit timer. This is needed to setup the DMA controller correctly. + * Ignore STM32H7XX and STM32U5XX as they are not supported by ChibiOS. + */ +#if !defined(STM32F1XX) && !defined(STM32L0XX) && !defined(STM32L1XX) +# define WS2812_PWM_TIMER_32BIT_PWMD2 1 +#endif +#if !defined(STM32F1XX) +# define WS2812_PWM_TIMER_32BIT_PWMD5 1 +#endif +#define WS2812_CONCAT1(a, b) a##b +#define WS2812_CONCAT(a, b) WS2812_CONCAT1(a, b) +#if WS2812_CONCAT(WS2812_PWM_TIMER_32BIT_, WS2812_PWM_DRIVER) +# define WS2812_PWM_TIMER_32BIT +#endif + #ifndef WS2812_PWM_COMPLEMENTARY_OUTPUT # define WS2812_PWM_OUTPUT_MODE PWM_OUTPUT_ACTIVE_HIGH #else @@ -101,6 +117,9 @@ * The duty cycle is calculated for a high period of 350 nS. */ #define WS2812_DUTYCYCLE_0 (WS2812_PWM_FREQUENCY / (1000000000 / 350)) +#if (WS2812_DUTYCYCLE_0 > 255) +# error WS2812 PWM driver: High period for a 0 is more than a byte +#endif /** * @brief High period for a one, in ticks @@ -117,6 +136,9 @@ * This is in the middle of the specifications of the WS2812 and WS2812B. */ #define WS2812_DUTYCYCLE_1 (WS2812_PWM_FREQUENCY / (1000000000 / 800)) +#if (WS2812_DUTYCYCLE_1 > 255) +# error WS2812 PWM driver: High period for a 1 is more than a byte +#endif /* --- PRIVATE MACROS ------------------------------------------------------- */ @@ -259,13 +281,35 @@ /* --- PRIVATE VARIABLES ---------------------------------------------------- */ -static uint32_t ws2812_frame_buffer[WS2812_BIT_N + 1]; /**< Buffer for a frame */ +// STM32F2XX, STM32F4XX and STM32F7XX do NOT zero pad DMA transfers of unequal data width. Buffer width must match TIMx CCR. +// For all other STM32 DMA transfer will automatically zero pad. We only need to set the right peripheral width. +#if defined(STM32F2XX) || defined(STM32F4XX) || defined(STM32F7XX) +# if defined(WS2812_PWM_TIMER_32BIT) +# define WS2812_DMA_MEMORY_WIDTH STM32_DMA_CR_MSIZE_WORD +# define WS2812_DMA_PERIPHERAL_WIDTH STM32_DMA_CR_PSIZE_WORD +typedef uint32_t ws2812_buffer_t; +# else +# define WS2812_DMA_MEMORY_WIDTH STM32_DMA_CR_MSIZE_HWORD +# define WS2812_DMA_PERIPHERAL_WIDTH STM32_DMA_CR_PSIZE_HWORD +typedef uint16_t ws2812_buffer_t; +# endif +#else +# define WS2812_DMA_MEMORY_WIDTH STM32_DMA_CR_MSIZE_BYTE +# if defined(WS2812_PWM_TIMER_32BIT) +# define WS2812_DMA_PERIPHERAL_WIDTH STM32_DMA_CR_PSIZE_WORD +# else +# define WS2812_DMA_PERIPHERAL_WIDTH STM32_DMA_CR_PSIZE_HWORD +# endif +typedef uint8_t ws2812_buffer_t; +#endif + +static ws2812_buffer_t ws2812_frame_buffer[WS2812_BIT_N + 1]; /**< Buffer for a frame */ /* --- PUBLIC FUNCTIONS ----------------------------------------------------- */ /* * Gedanke: Double-buffer type transactions: double buffer transfers using two memory pointers for -the memory (while the DMA is reading/writing from/to a buffer, the application can -write/read to/from the other buffer). + * the memory (while the DMA is reading/writing from/to a buffer, the application can + * write/read to/from the other buffer). */ void ws2812_init(void) { @@ -305,7 +349,7 @@ void ws2812_init(void) { dmaStreamAlloc(WS2812_DMA_STREAM - STM32_DMA_STREAM(0), 10, NULL, NULL); dmaStreamSetPeripheral(WS2812_DMA_STREAM, &(WS2812_PWM_DRIVER.tim->CCR[WS2812_PWM_CHANNEL - 1])); // Ziel ist der An-Zeit im Cap-Comp-Register dmaStreamSetMemory0(WS2812_DMA_STREAM, ws2812_frame_buffer); - dmaStreamSetMode(WS2812_DMA_STREAM, STM32_DMA_CR_CHSEL(WS2812_DMA_CHANNEL) | STM32_DMA_CR_DIR_M2P | STM32_DMA_CR_PSIZE_WORD | STM32_DMA_CR_MSIZE_WORD | STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_PL(3)); + dmaStreamSetMode(WS2812_DMA_STREAM, STM32_DMA_CR_CHSEL(WS2812_DMA_CHANNEL) | STM32_DMA_CR_DIR_M2P | WS2812_DMA_PERIPHERAL_WIDTH | WS2812_DMA_MEMORY_WIDTH | STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_PL(3)); #endif dmaStreamSetTransactionSize(WS2812_DMA_STREAM, WS2812_BIT_N); // M2P: Memory 2 Periph; PL: Priority Level -- cgit v1.2.3 From fce99f38757d7ddbcaada0f5f0157ca24b6162b7 Mon Sep 17 00:00:00 2001 From: Mega Mind <68985133+megamind4089@users.noreply.github.com> Date: Sun, 14 Aug 2022 19:27:26 +0800 Subject: [Controller] Added board config for custom controller STeMCell (#16287) Co-authored-by: Mariappan Ramasamy <947300+Mariappan@users.noreply.github.com> Co-authored-by: Mariappan Ramasamy Co-authored-by: Sadek Baroudi --- platforms/chibios/boards/STEMCELL/board/board.mk | 15 ++ platforms/chibios/boards/STEMCELL/configs/board.h | 8 + platforms/chibios/boards/STEMCELL/configs/chconf.h | 9 + platforms/chibios/boards/STEMCELL/configs/config.h | 29 +++ .../chibios/boards/STEMCELL/configs/halconf.h | 11 + .../chibios/boards/STEMCELL/configs/mcuconf.h | 231 +++++++++++++++++++++ .../converters/promicro_to_stemcell/_pin_defs.h | 57 +++++ .../converters/promicro_to_stemcell/converter.mk | 22 ++ 8 files changed, 382 insertions(+) create mode 100644 platforms/chibios/boards/STEMCELL/board/board.mk create mode 100644 platforms/chibios/boards/STEMCELL/configs/board.h create mode 100644 platforms/chibios/boards/STEMCELL/configs/chconf.h create mode 100644 platforms/chibios/boards/STEMCELL/configs/config.h create mode 100644 platforms/chibios/boards/STEMCELL/configs/halconf.h create mode 100644 platforms/chibios/boards/STEMCELL/configs/mcuconf.h create mode 100644 platforms/chibios/converters/promicro_to_stemcell/_pin_defs.h create mode 100644 platforms/chibios/converters/promicro_to_stemcell/converter.mk (limited to 'platforms') diff --git a/platforms/chibios/boards/STEMCELL/board/board.mk b/platforms/chibios/boards/STEMCELL/board/board.mk new file mode 100644 index 0000000000..b0d1c3c404 --- /dev/null +++ b/platforms/chibios/boards/STEMCELL/board/board.mk @@ -0,0 +1,15 @@ +# Copyright 2022 Mega Mind (@megamind4089) +# SPDX-License-Identifier: GPL-2.0-or-later + +# Default pin config of nucleo64_411re has most pins in input pull up mode + +# List of all the board related files. +BOARDSRC = $(CHIBIOS)/os/hal/boards/ST_NUCLEO64_F411RE/board.c + +# Required include directories +BOARDINC = $(CHIBIOS)/os/hal/boards/ST_NUCLEO64_F411RE + + +# Shared variables +ALLCSRC += $(BOARDSRC) +ALLINC += $(BOARDINC) diff --git a/platforms/chibios/boards/STEMCELL/configs/board.h b/platforms/chibios/boards/STEMCELL/configs/board.h new file mode 100644 index 0000000000..39cf79ab09 --- /dev/null +++ b/platforms/chibios/boards/STEMCELL/configs/board.h @@ -0,0 +1,8 @@ +// Copyright 2022 Mega Mind (@megamind4089) +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include_next "board.h" + +#undef STM32_HSE_BYPASS diff --git a/platforms/chibios/boards/STEMCELL/configs/chconf.h b/platforms/chibios/boards/STEMCELL/configs/chconf.h new file mode 100644 index 0000000000..d25bea0d17 --- /dev/null +++ b/platforms/chibios/boards/STEMCELL/configs/chconf.h @@ -0,0 +1,9 @@ +// Copyright 2022 Mega Mind (@megamind4089) +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#define CH_CFG_ST_RESOLUTION 16 +#define CH_CFG_ST_FREQUENCY 10000 + +#include_next diff --git a/platforms/chibios/boards/STEMCELL/configs/config.h b/platforms/chibios/boards/STEMCELL/configs/config.h new file mode 100644 index 0000000000..82f6c63636 --- /dev/null +++ b/platforms/chibios/boards/STEMCELL/configs/config.h @@ -0,0 +1,29 @@ +// Copyright 2022 Mega Mind(@megamind4089) +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#ifndef EARLY_INIT_PERFORM_BOOTLOADER_JUMP +# define EARLY_INIT_PERFORM_BOOTLOADER_JUMP TRUE +#endif + +/**====================== + ** I2C Driver + *========================**/ + +#if !defined(I2C1_SDA_PIN) +# define I2C1_SDA_PIN D0 +#endif + +#if !defined(I2C1_SCL_PIN) +# define I2C1_SCL_PIN D1 +#endif + +/**====================== + ** SERIAL Driver + *========================**/ + +#if !defined(SERIAL_USART_DRIVER) +# define SERIAL_USART_DRIVER SD2 +#endif + diff --git a/platforms/chibios/boards/STEMCELL/configs/halconf.h b/platforms/chibios/boards/STEMCELL/configs/halconf.h new file mode 100644 index 0000000000..f38949e626 --- /dev/null +++ b/platforms/chibios/boards/STEMCELL/configs/halconf.h @@ -0,0 +1,11 @@ +// Copyright 2022 Mega Mind (@megamind4089) +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#define PAL_USE_WAIT TRUE +#define PAL_USE_CALLBACKS TRUE +#define HAL_USE_I2C TRUE +#define HAL_USE_SERIAL TRUE + +#include_next diff --git a/platforms/chibios/boards/STEMCELL/configs/mcuconf.h b/platforms/chibios/boards/STEMCELL/configs/mcuconf.h new file mode 100644 index 0000000000..621d3fcace --- /dev/null +++ b/platforms/chibios/boards/STEMCELL/configs/mcuconf.h @@ -0,0 +1,231 @@ +// Copyright 2022 Mega Mind (@megamind4089) +// SPDX-License-Identifier: GPL-2.0-or-later + +#ifndef MCUCONF_H +#define MCUCONF_H + +/* + * STM32F4xx drivers configuration. + * The following settings override the default settings present in + * the various device driver implementation headers. + * Note that the settings for each driver only have effect if the whole + * driver is enabled in halconf.h. + * + * IRQ priorities: + * 15...0 Lowest...Highest. + * + * DMA priorities: + * 0...3 Lowest...Highest. + */ + +#define STM32F4xx_MCUCONF +#define STM32F411_MCUCONF + +/* + * HAL driver system settings. + */ +#define STM32_NO_INIT FALSE +#define STM32_PVD_ENABLE FALSE +#define STM32_PLS STM32_PLS_LEV0 +#define STM32_BKPRAM_ENABLE FALSE +#define STM32_HSI_ENABLED TRUE +#define STM32_LSI_ENABLED TRUE +#define STM32_HSE_ENABLED TRUE +#define STM32_LSE_ENABLED FALSE +#define STM32_CLOCK48_REQUIRED TRUE +#define STM32_SW STM32_SW_PLL +#define STM32_PLLSRC STM32_PLLSRC_HSE +#define STM32_PLLM_VALUE 8 +#define STM32_PLLN_VALUE 336 +#define STM32_PLLP_VALUE 4 +#define STM32_PLLQ_VALUE 7 +#define STM32_HPRE STM32_HPRE_DIV1 +#define STM32_PPRE1 STM32_PPRE1_DIV2 +#define STM32_PPRE2 STM32_PPRE2_DIV1 +#define STM32_RTCSEL STM32_RTCSEL_LSI +#define STM32_RTCPRE_VALUE 8 +#define STM32_MCO1SEL STM32_MCO1SEL_HSI +#define STM32_MCO1PRE STM32_MCO1PRE_DIV1 +#define STM32_MCO2SEL STM32_MCO2SEL_SYSCLK +#define STM32_MCO2PRE STM32_MCO2PRE_DIV5 +#define STM32_I2SSRC STM32_I2SSRC_CKIN +#define STM32_PLLI2SN_VALUE 192 +#define STM32_PLLI2SR_VALUE 5 + +/* + * IRQ system settings. + */ +#define STM32_IRQ_EXTI0_PRIORITY 6 +#define STM32_IRQ_EXTI1_PRIORITY 6 +#define STM32_IRQ_EXTI2_PRIORITY 6 +#define STM32_IRQ_EXTI3_PRIORITY 6 +#define STM32_IRQ_EXTI4_PRIORITY 6 +#define STM32_IRQ_EXTI5_9_PRIORITY 6 +#define STM32_IRQ_EXTI10_15_PRIORITY 6 +#define STM32_IRQ_EXTI16_PRIORITY 6 +#define STM32_IRQ_EXTI17_PRIORITY 15 +#define STM32_IRQ_EXTI18_PRIORITY 6 +#define STM32_IRQ_EXTI19_PRIORITY 6 +#define STM32_IRQ_EXTI20_PRIORITY 6 +#define STM32_IRQ_EXTI21_PRIORITY 15 +#define STM32_IRQ_EXTI22_PRIORITY 15 + +#define STM32_IRQ_TIM1_BRK_TIM9_PRIORITY 7 +#define STM32_IRQ_TIM1_UP_TIM10_PRIORITY 7 +#define STM32_IRQ_TIM1_TRGCO_TIM11_PRIORITY 7 +#define STM32_IRQ_TIM1_CC_PRIORITY 7 +#define STM32_IRQ_TIM2_PRIORITY 7 +#define STM32_IRQ_TIM3_PRIORITY 7 +#define STM32_IRQ_TIM4_PRIORITY 7 +#define STM32_IRQ_TIM5_PRIORITY 7 + +#define STM32_IRQ_USART1_PRIORITY 12 +#define STM32_IRQ_USART2_PRIORITY 12 +#define STM32_IRQ_USART6_PRIORITY 12 + +/* + * ADC driver system settings. + */ +#define STM32_ADC_ADCPRE ADC_CCR_ADCPRE_DIV4 +#define STM32_ADC_USE_ADC1 FALSE +#define STM32_ADC_ADC1_DMA_STREAM STM32_DMA_STREAM_ID(2, 4) +#define STM32_ADC_ADC1_DMA_PRIORITY 2 +#define STM32_ADC_IRQ_PRIORITY 6 +#define STM32_ADC_ADC1_DMA_IRQ_PRIORITY 6 + +/* + * GPT driver system settings. + */ +#define STM32_GPT_USE_TIM1 FALSE +#define STM32_GPT_USE_TIM2 FALSE +#define STM32_GPT_USE_TIM3 FALSE +#define STM32_GPT_USE_TIM4 FALSE +#define STM32_GPT_USE_TIM5 FALSE +#define STM32_GPT_USE_TIM9 FALSE +#define STM32_GPT_USE_TIM10 FALSE +#define STM32_GPT_USE_TIM11 FALSE + +/* + * I2C driver system settings. + */ +#define STM32_I2C_USE_I2C1 TRUE +#define STM32_I2C_USE_I2C2 FALSE +#define STM32_I2C_USE_I2C3 FALSE +#define STM32_I2C_BUSY_TIMEOUT 50 +#define STM32_I2C_I2C1_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0) +#define STM32_I2C_I2C1_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6) +#define STM32_I2C_I2C2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2) +#define STM32_I2C_I2C2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7) +#define STM32_I2C_I2C3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2) +#define STM32_I2C_I2C3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4) +#define STM32_I2C_I2C1_IRQ_PRIORITY 5 +#define STM32_I2C_I2C2_IRQ_PRIORITY 5 +#define STM32_I2C_I2C3_IRQ_PRIORITY 5 +#define STM32_I2C_I2C1_DMA_PRIORITY 3 +#define STM32_I2C_I2C2_DMA_PRIORITY 3 +#define STM32_I2C_I2C3_DMA_PRIORITY 3 +#define STM32_I2C_DMA_ERROR_HOOK(i2cp) osalSysHalt("DMA failure") + +/* + * I2S driver system settings. + */ +#define STM32_I2S_USE_SPI2 FALSE +#define STM32_I2S_USE_SPI3 FALSE +#define STM32_I2S_SPI2_IRQ_PRIORITY 10 +#define STM32_I2S_SPI3_IRQ_PRIORITY 10 +#define STM32_I2S_SPI2_DMA_PRIORITY 1 +#define STM32_I2S_SPI3_DMA_PRIORITY 1 +#define STM32_I2S_SPI2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 3) +#define STM32_I2S_SPI2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4) +#define STM32_I2S_SPI3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0) +#define STM32_I2S_SPI3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7) +#define STM32_I2S_DMA_ERROR_HOOK(i2sp) osalSysHalt("DMA failure") + +/* + * ICU driver system settings. + */ +#define STM32_ICU_USE_TIM1 FALSE +#define STM32_ICU_USE_TIM2 FALSE +#define STM32_ICU_USE_TIM3 FALSE +#define STM32_ICU_USE_TIM4 FALSE +#define STM32_ICU_USE_TIM5 FALSE +#define STM32_ICU_USE_TIM9 FALSE +#define STM32_ICU_USE_TIM10 FALSE +#define STM32_ICU_USE_TIM11 FALSE + +/* + * PWM driver system settings. + */ +#define STM32_PWM_USE_TIM1 FALSE +#define STM32_PWM_USE_TIM2 FALSE +#define STM32_PWM_USE_TIM3 FALSE +#define STM32_PWM_USE_TIM4 FALSE +#define STM32_PWM_USE_TIM5 FALSE +#define STM32_PWM_USE_TIM9 FALSE +#define STM32_PWM_USE_TIM10 FALSE +#define STM32_PWM_USE_TIM11 FALSE + +/* + * SERIAL driver system settings. + */ +#define STM32_SERIAL_USE_USART1 TRUE +#define STM32_SERIAL_USE_USART2 TRUE +#define STM32_SERIAL_USE_USART6 FALSE + +/* + * SPI driver system settings. + */ +#define STM32_SPI_USE_SPI1 FALSE +#define STM32_SPI_USE_SPI2 FALSE +#define STM32_SPI_USE_SPI3 FALSE +#define STM32_SPI_SPI1_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 0) +#define STM32_SPI_SPI1_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 3) +#define STM32_SPI_SPI2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 3) +#define STM32_SPI_SPI2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4) +#define STM32_SPI_SPI3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0) +#define STM32_SPI_SPI3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7) +#define STM32_SPI_SPI1_DMA_PRIORITY 1 +#define STM32_SPI_SPI2_DMA_PRIORITY 1 +#define STM32_SPI_SPI3_DMA_PRIORITY 1 +#define STM32_SPI_SPI1_IRQ_PRIORITY 10 +#define STM32_SPI_SPI2_IRQ_PRIORITY 10 +#define STM32_SPI_SPI3_IRQ_PRIORITY 10 +#define STM32_SPI_DMA_ERROR_HOOK(spip) osalSysHalt("DMA failure") + +/* + * ST driver system settings. + */ +#define STM32_ST_IRQ_PRIORITY 8 +#define STM32_ST_USE_TIMER 2 + +/* + * UART driver system settings. + */ +#define STM32_UART_USE_USART1 FALSE +#define STM32_UART_USE_USART2 FALSE +#define STM32_UART_USE_USART6 FALSE +#define STM32_UART_USART1_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 5) +#define STM32_UART_USART1_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 7) +#define STM32_UART_USART2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 5) +#define STM32_UART_USART2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6) +#define STM32_UART_USART6_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 2) +#define STM32_UART_USART6_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 7) +#define STM32_UART_USART1_DMA_PRIORITY 0 +#define STM32_UART_USART2_DMA_PRIORITY 0 +#define STM32_UART_USART6_DMA_PRIORITY 0 +#define STM32_UART_DMA_ERROR_HOOK(uartp) osalSysHalt("DMA failure") + +/* + * USB driver system settings. + */ +#define STM32_USB_USE_OTG1 TRUE +#define STM32_USB_OTG1_IRQ_PRIORITY 14 +#define STM32_USB_OTG1_RX_FIFO_SIZE 512 +#define STM32_USB_HOST_WAKEUP_DURATION 2 + +/* + * WDG driver system settings. + */ +#define STM32_WDG_USE_IWDG FALSE + +#endif /* MCUCONF_H */ diff --git a/platforms/chibios/converters/promicro_to_stemcell/_pin_defs.h b/platforms/chibios/converters/promicro_to_stemcell/_pin_defs.h new file mode 100644 index 0000000000..f5dd55905d --- /dev/null +++ b/platforms/chibios/converters/promicro_to_stemcell/_pin_defs.h @@ -0,0 +1,57 @@ +// Copyright 2022 Mega Mind (@megamind4089) +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +// Pindefs for v2.0.0 +// https://megamind4089.github.io/STeMCell/pinout/ + +// Left side (front) +#ifdef STEMCELL_UART_SWAP +# define D3 PAL_LINE(GPIOA, 3) +# define D2 PAL_LINE(GPIOA, 2) +#else +# define D3 PAL_LINE(GPIOA, 2) +# define D2 PAL_LINE(GPIOA, 3) +#endif +// GND +// GND +#ifdef STEMCELL_I2C_SWAP +# define D1 PAL_LINE(GPIOB, 6) +# define D0 PAL_LINE(GPIOB, 7) +#else +# define D1 PAL_LINE(GPIOB, 7) +# define D0 PAL_LINE(GPIOB, 6) +#endif + +#define D4 PAL_LINE(GPIOA, 15) +#define C6 PAL_LINE(GPIOB, 3) +#define D7 PAL_LINE(GPIOB, 4) +#define E6 PAL_LINE(GPIOB, 5) +#define B4 PAL_LINE(GPIOB, 8) +#define B5 PAL_LINE(GPIOB, 9) + +// Right side (front) +// RAW +// GND +// RESET +// VCC +#define F4 PAL_LINE(GPIOB, 10) +#define F5 PAL_LINE(GPIOB, 2) +#define F6 PAL_LINE(GPIOB, 1) +#define F7 PAL_LINE(GPIOB, 0) + +#define B1 PAL_LINE(GPIOA, 5) +#define B3 PAL_LINE(GPIOA, 6) +#define B2 PAL_LINE(GPIOA, 7) +#define B6 PAL_LINE(GPIOA, 4) + +// Extra elite-c compatible pinout +#define B7 PAL_LINE(GPIOC, 13) +#define D5 PAL_LINE(GPIOC, 14) +#define C7 PAL_LINE(GPIOC, 15) +#define F1 PAL_LINE(GPIOA, 0) +#define F0 PAL_LINE(GPIOA, 1) + +// TX/RX pins of promicro +#define B0 PAL_LINE(GPIOA, 9) // unconnected pin diff --git a/platforms/chibios/converters/promicro_to_stemcell/converter.mk b/platforms/chibios/converters/promicro_to_stemcell/converter.mk new file mode 100644 index 0000000000..525492f96c --- /dev/null +++ b/platforms/chibios/converters/promicro_to_stemcell/converter.mk @@ -0,0 +1,22 @@ +# Copyright 2022 Mega Mind (@megamind4089) +# SPDX-License-Identifier: GPL-2.0-or-later + +MCU := STM32F411 +BOARD := STEMCELL +BOOTLOADER := tinyuf2 + +SERIAL_DRIVER ?= usart +WS2812_DRIVER ?= bitbang + +EEPROM_DRIVER = wear_leveling +WEAR_LEVELING_DRIVER = legacy + + +ifeq ($(strip $(STMC_US)), yes) + OPT_DEFS += -DSTEMCELL_UART_SWAP +endif + +ifeq ($(strip $(STMC_IS)), yes) + OPT_DEFS += -DSTEMCELL_I2C_SWAP +endif + -- cgit v1.2.3 From 463fb72d29e6638f9a28f751e6a1f2a7f9e0bcf8 Mon Sep 17 00:00:00 2001 From: Joel Challis Date: Sun, 14 Aug 2022 20:48:44 +0100 Subject: Partially revert some WB32 specific changes (#18038) --- platforms/chibios/drivers/ws2812_pwm.c | 18 +++--------------- platforms/chibios/drivers/ws2812_spi.c | 15 +++++++-------- 2 files changed, 10 insertions(+), 23 deletions(-) (limited to 'platforms') diff --git a/platforms/chibios/drivers/ws2812_pwm.c b/platforms/chibios/drivers/ws2812_pwm.c index 8c0259fb91..792de85ce9 100644 --- a/platforms/chibios/drivers/ws2812_pwm.c +++ b/platforms/chibios/drivers/ws2812_pwm.c @@ -17,25 +17,13 @@ # define WS2812_PWM_CHANNEL 2 // Channel #endif #ifndef WS2812_PWM_PAL_MODE -# if defined(WB32F3G71xx) || defined(WB32FQ95xx) -# define WS2812_PWM_PAL_MODE 1 // DI Pin's alternate function value -# else -# define WS2812_PWM_PAL_MODE 2 // DI Pin's alternate function value -# endif +# define WS2812_PWM_PAL_MODE 2 // DI Pin's alternate function value #endif #ifndef WS2812_DMA_STREAM -# if defined(WB32F3G71xx) || defined(WB32FQ95xx) -# define WS2812_DMA_STREAM WB32_DMA1_STREAM1 // DMA Stream for TIMx_UP -# else -# define WS2812_DMA_STREAM STM32_DMA1_STREAM2 // DMA Stream for TIMx_UP -# endif +# define WS2812_DMA_STREAM STM32_DMA1_STREAM2 // DMA Stream for TIMx_UP #endif #ifndef WS2812_DMA_CHANNEL -# if defined(WB32F3G71xx) || defined(WB32FQ95xx) -# define WS2812_DMA_CHANNEL WB32_DMAC_HWHIF_TIM2_UP // DMA Channel for TIM2_UP -# else -# define WS2812_DMA_CHANNEL 2 // DMA Channel for TIMx_UP -# endif +# define WS2812_DMA_CHANNEL 2 // DMA Channel for TIMx_UP #endif #if (STM32_DMA_SUPPORTS_DMAMUX == TRUE) && !defined(WS2812_DMAMUX_ID) # error "please consult your MCU's datasheet and specify in your config.h: #define WS2812_DMAMUX_ID STM32_DMAMUX1_TIM?_UP" diff --git a/platforms/chibios/drivers/ws2812_spi.c b/platforms/chibios/drivers/ws2812_spi.c index 9ee552b187..a73eb69720 100644 --- a/platforms/chibios/drivers/ws2812_spi.c +++ b/platforms/chibios/drivers/ws2812_spi.c @@ -5,11 +5,7 @@ // Define the spi your LEDs are plugged to here #ifndef WS2812_SPI -# if defined(WB32F3G71xx) || defined(WB32FQ95xx) -# define WS2812_SPI SPIDQ -# else -# define WS2812_SPI SPID1 -# endif +# define WS2812_SPI SPID1 #endif #ifndef WS2812_SPI_MOSI_PAL_MODE @@ -20,6 +16,10 @@ # define WS2812_SPI_SCK_PAL_MODE 5 #endif +#ifndef WS2812_SPI_DIVISOR +# define WS2812_SPI_DIVISOR 16 +#endif + // Push Pull or Open Drain Configuration // Default Push Pull #ifndef WS2812_EXTERNAL_PULLUP @@ -46,7 +46,7 @@ # define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_0) #elif WS2812_SPI_DIVISOR == 8 # define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_1) -#elif WS2812_SPI_DIVISOR == 16 // same as default +#elif WS2812_SPI_DIVISOR == 16 // default # define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_1 | SPI_CR1_BR_0) #elif WS2812_SPI_DIVISOR == 32 # define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_2) @@ -57,8 +57,7 @@ #elif WS2812_SPI_DIVISOR == 256 # define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_2 | SPI_CR1_BR_1 | SPI_CR1_BR_0) #else -# define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_1 | SPI_CR1_BR_0) // default -# define WS2812_SPI_DIVISOR 16 +# error "Configured WS2812_SPI_DIVISOR value is not supported at this time." #endif // Use SPI circular buffer -- cgit v1.2.3 From f74ed5fc5331b6131538b347dd001e0e6acd23e0 Mon Sep 17 00:00:00 2001 From: Stefan Kerkmann Date: Mon, 15 Aug 2022 19:00:22 +0200 Subject: Fix GD32VF103 WS2812 PWM driver (#18067) ...by adding the missing STM32 DMA defines. --- platforms/chibios/gd32v_compatibility.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'platforms') diff --git a/platforms/chibios/gd32v_compatibility.h b/platforms/chibios/gd32v_compatibility.h index a3148fb6d2..d01c3d00a2 100644 --- a/platforms/chibios/gd32v_compatibility.h +++ b/platforms/chibios/gd32v_compatibility.h @@ -35,7 +35,9 @@ #define STM32_DMA_STREAM_ID(peripheral, channel) GD32_DMA_STREAM_ID(peripheral - 1, channel - 1) #define STM32_DMA_CR_DIR_M2P GD32_DMA_CTL_DIR_M2P #define STM32_DMA_CR_PSIZE_WORD GD32_DMA_CTL_PWIDTH_WORD +#define STM32_DMA_CR_PSIZE_HWORD GD32_DMA_CTL_PWIDTH_HWORD #define STM32_DMA_CR_MSIZE_WORD GD32_DMA_CTL_MWIDTH_WORD +#define STM32_DMA_CR_MSIZE_BYTE GD32_DMA_CTL_MWIDTH_BYTE #define STM32_DMA_CR_MINC GD32_DMA_CTL_MNAGA #define STM32_DMA_CR_CIRC GD32_DMA_CTL_CMEN #define STM32_DMA_CR_PL GD32_DMA_CTL_PRIO -- cgit v1.2.3 From a645301c827705b04c8f19182153a1962c5c7bcb Mon Sep 17 00:00:00 2001 From: David Hoelscher Date: Wed, 17 Aug 2022 19:01:54 -0500 Subject: Add Bonsai C4 converter (#17711) --- .../converters/promicro_to_bonsai_c4/_pin_defs.h | 40 ++++++++++++++++++++++ .../converters/promicro_to_bonsai_c4/converter.mk | 4 +++ 2 files changed, 44 insertions(+) create mode 100644 platforms/chibios/converters/promicro_to_bonsai_c4/_pin_defs.h create mode 100644 platforms/chibios/converters/promicro_to_bonsai_c4/converter.mk (limited to 'platforms') diff --git a/platforms/chibios/converters/promicro_to_bonsai_c4/_pin_defs.h b/platforms/chibios/converters/promicro_to_bonsai_c4/_pin_defs.h new file mode 100644 index 0000000000..7e6b8ddaf2 --- /dev/null +++ b/platforms/chibios/converters/promicro_to_bonsai_c4/_pin_defs.h @@ -0,0 +1,40 @@ +// Copyright 2022 customMK +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +// Left side (front) +#define D3 PAL_LINE(GPIOB, 7) +#define D2 PAL_LINE(GPIOA, 15) +// GND +// GND +#define D1 PAL_LINE(GPIOB, 9) +#define D0 PAL_LINE(GPIOB, 6) +#define D4 PAL_LINE(GPIOA, 4) +#define C6 PAL_LINE(GPIOB, 8) +#define D7 PAL_LINE(GPIOA, 3) +#define E6 PAL_LINE(GPIOB, 10) +#define B4 PAL_LINE(GPIOA, 8) +#define B5 PAL_LINE(GPIOB, 0) + +// Right side (front) +// RAW +// GND +// RESET +// VCC +#define F4 PAL_LINE(GPIOA, 7) +#define F5 PAL_LINE(GPIOA, 6) +#define F6 PAL_LINE(GPIOA, 5) +#define F7 PAL_LINE(GPIOA, 1) +#define B1 PAL_LINE(GPIOB, 13) +#define B3 PAL_LINE(GPIOB, 14) +#define B2 PAL_LINE(GPIOB, 15) +#define B6 PAL_LINE(GPIOB, 1) + +// LEDs (only D5/B2 uses an actual LED) +// Setting both RX and TX LEDs to the same pin as there +// is only one LED availble +// If this is undesirable, either B0 or B5 can be redefined by +// using #undef and #define to change its assignment +#define B0 PAL_LINE(GPIOB, 2) +#define D5 PAL_LINE(GPIOB, 2) \ No newline at end of file diff --git a/platforms/chibios/converters/promicro_to_bonsai_c4/converter.mk b/platforms/chibios/converters/promicro_to_bonsai_c4/converter.mk new file mode 100644 index 0000000000..7410209b67 --- /dev/null +++ b/platforms/chibios/converters/promicro_to_bonsai_c4/converter.mk @@ -0,0 +1,4 @@ +# Proton C MCU settings for converting AVR projects +MCU := STM32F411 +BOARD := GENERIC_STM32_F411XE +BOOTLOADER := stm32-dfu \ No newline at end of file -- cgit v1.2.3 From 1eac095c0c200990c41966944c2b65e633d361f8 Mon Sep 17 00:00:00 2001 From: Nick Brassel Date: Fri, 19 Aug 2022 14:20:44 +1000 Subject: Use the correct bootloader definition. (#18102) --- platforms/chibios/drivers/wear_leveling/wear_leveling_legacy_config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'platforms') diff --git a/platforms/chibios/drivers/wear_leveling/wear_leveling_legacy_config.h b/platforms/chibios/drivers/wear_leveling/wear_leveling_legacy_config.h index 1e4691a6c0..e64cab87d1 100644 --- a/platforms/chibios/drivers/wear_leveling/wear_leveling_legacy_config.h +++ b/platforms/chibios/drivers/wear_leveling/wear_leveling_legacy_config.h @@ -39,7 +39,7 @@ # if defined(QMK_MCU_STM32F042) || defined(QMK_MCU_STM32F070) || defined(QMK_MCU_STM32F072) # define WEAR_LEVELING_LEGACY_EMULATION_BASE_PAGE_ADDRESS ((uintptr_t)(WEAR_LEVELING_LEGACY_EMULATION_FLASH_BASE) + WEAR_LEVELING_LEGACY_EMULATION_FLASH_SIZE * 1024 - (WEAR_LEVELING_LEGACY_EMULATION_PAGE_COUNT * WEAR_LEVELING_LEGACY_EMULATION_PAGE_SIZE)) # elif defined(QMK_MCU_STM32F401) || defined(QMK_MCU_STM32F411) -# if defined(BOOTLOADER_STM32) +# if defined(BOOTLOADER_STM32_DFU) # define WEAR_LEVELING_LEGACY_EMULATION_BASE_PAGE_ADDRESS (WEAR_LEVELING_LEGACY_EMULATION_FLASH_BASE + (1 * (WEAR_LEVELING_LEGACY_EMULATION_PAGE_SIZE))) // +16k # elif defined(BOOTLOADER_TINYUF2) # define WEAR_LEVELING_LEGACY_EMULATION_BASE_PAGE_ADDRESS (WEAR_LEVELING_LEGACY_EMULATION_FLASH_BASE + (3 * (WEAR_LEVELING_LEGACY_EMULATION_PAGE_SIZE))) // +48k -- cgit v1.2.3 From 43fd6471305d3ebd9e6cb537d4d39c71e480922e Mon Sep 17 00:00:00 2001 From: Joel Challis Date: Thu, 25 Aug 2022 12:17:41 +0100 Subject: Add eeprom defaults for tinyuf2 bootloader (#18042) --- platforms/chibios/converters/promicro_to_stemcell/converter.mk | 4 ---- 1 file changed, 4 deletions(-) (limited to 'platforms') diff --git a/platforms/chibios/converters/promicro_to_stemcell/converter.mk b/platforms/chibios/converters/promicro_to_stemcell/converter.mk index 525492f96c..1bbe9bf09e 100644 --- a/platforms/chibios/converters/promicro_to_stemcell/converter.mk +++ b/platforms/chibios/converters/promicro_to_stemcell/converter.mk @@ -8,10 +8,6 @@ BOOTLOADER := tinyuf2 SERIAL_DRIVER ?= usart WS2812_DRIVER ?= bitbang -EEPROM_DRIVER = wear_leveling -WEAR_LEVELING_DRIVER = legacy - - ifeq ($(strip $(STMC_US)), yes) OPT_DEFS += -DSTEMCELL_UART_SWAP endif -- cgit v1.2.3 From 7adef85fa4178109998674c1ea9b6166e3dbc7bf Mon Sep 17 00:00:00 2001 From: Joel Challis Date: Thu, 1 Sep 2022 23:38:52 +0100 Subject: Remove non promicro pins from converters (#18239) --- platforms/chibios/converters/promicro_to_bit_c_pro/_pin_defs.h | 3 --- platforms/chibios/converters/promicro_to_stemcell/_pin_defs.h | 10 ++-------- 2 files changed, 2 insertions(+), 11 deletions(-) (limited to 'platforms') diff --git a/platforms/chibios/converters/promicro_to_bit_c_pro/_pin_defs.h b/platforms/chibios/converters/promicro_to_bit_c_pro/_pin_defs.h index 92e8fbfa1a..a693e33011 100644 --- a/platforms/chibios/converters/promicro_to_bit_c_pro/_pin_defs.h +++ b/platforms/chibios/converters/promicro_to_bit_c_pro/_pin_defs.h @@ -34,6 +34,3 @@ // LEDs (Mapped to R and G channel of the Bit-C PRO's RGB led) #define D5 16U #define B0 17U - -// Bit-C LED (mapped to B channel of the Bit-C PRO's RGB led) -#define F0 18U diff --git a/platforms/chibios/converters/promicro_to_stemcell/_pin_defs.h b/platforms/chibios/converters/promicro_to_stemcell/_pin_defs.h index f5dd55905d..a7b709f837 100644 --- a/platforms/chibios/converters/promicro_to_stemcell/_pin_defs.h +++ b/platforms/chibios/converters/promicro_to_stemcell/_pin_defs.h @@ -46,12 +46,6 @@ #define B2 PAL_LINE(GPIOA, 7) #define B6 PAL_LINE(GPIOA, 4) -// Extra elite-c compatible pinout -#define B7 PAL_LINE(GPIOC, 13) -#define D5 PAL_LINE(GPIOC, 14) -#define C7 PAL_LINE(GPIOC, 15) -#define F1 PAL_LINE(GPIOA, 0) -#define F0 PAL_LINE(GPIOA, 1) - -// TX/RX pins of promicro +// LEDs +#define D5 PAL_LINE(GPIOA, 8) // User LED #define B0 PAL_LINE(GPIOA, 9) // unconnected pin -- cgit v1.2.3 From cc1565f2a3e46f6f364f872962ced35aef5ddae8 Mon Sep 17 00:00:00 2001 From: Ryan Date: Mon, 3 Oct 2022 12:26:04 +1100 Subject: `:flash`: print bootloader (#18569) --- platforms/arm_atsam/flash.mk | 1 + platforms/avr/flash.mk | 3 ++- platforms/chibios/flash.mk | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) (limited to 'platforms') diff --git a/platforms/arm_atsam/flash.mk b/platforms/arm_atsam/flash.mk index 8152610ceb..8068c08d57 100644 --- a/platforms/arm_atsam/flash.mk +++ b/platforms/arm_atsam/flash.mk @@ -13,6 +13,7 @@ mdloader: bin $(call EXEC_MDLOADER) flash: bin + $(SILENT) || printf "Flashing for bootloader: $(BLUE)$(BOOTLOADER)$(NO_COLOR)\n" ifneq ($(strip $(PROGRAM_CMD)),) $(UNSYNC_OUTPUT_CMD) && $(PROGRAM_CMD) else ifeq ($(strip $(ARM_ATSAM)),SAMD51J18A) diff --git a/platforms/avr/flash.mk b/platforms/avr/flash.mk index 6d50e72534..c104f730b3 100644 --- a/platforms/avr/flash.mk +++ b/platforms/avr/flash.mk @@ -168,7 +168,8 @@ endef hid_bootloader: $(BUILD_DIR)/$(TARGET).hex check-size cpfirmware $(call EXEC_HID_LUFA) -flash: $(BUILD_DIR)/$(TARGET).hex check-size cpfirmware +flash: $(BUILD_DIR)/$(TARGET).hex check-size cpfirmware + $(SILENT) || printf "Flashing for bootloader: $(BLUE)$(BOOTLOADER)$(NO_COLOR)\n" ifneq ($(strip $(PROGRAM_CMD)),) $(UNSYNC_OUTPUT_CMD) && $(PROGRAM_CMD) else ifeq ($(strip $(BOOTLOADER)), caterina) diff --git a/platforms/chibios/flash.mk b/platforms/chibios/flash.mk index 790c4f3316..023da34bb5 100644 --- a/platforms/chibios/flash.mk +++ b/platforms/chibios/flash.mk @@ -100,8 +100,8 @@ endef teensy: $(BUILD_DIR)/$(TARGET).hex cpfirmware sizeafter $(call EXEC_TEENSY) - flash: $(BUILD_DIR)/$(TARGET).bin cpfirmware sizeafter + $(SILENT) || printf "Flashing for bootloader: $(BLUE)$(BOOTLOADER)$(NO_COLOR)\n" ifneq ($(strip $(PROGRAM_CMD)),) $(UNSYNC_OUTPUT_CMD) && $(PROGRAM_CMD) else ifeq ($(strip $(BOOTLOADER)),kiibohd) -- cgit v1.2.3 From f731e2789fdd225be1c5b0322c6ba882adf47c8d Mon Sep 17 00:00:00 2001 From: Nick Brassel Date: Mon, 17 Oct 2022 07:30:49 +1100 Subject: Allow Fedora to update ChibiOS configs. (#18698) --- .../boards/GENERIC_STM32_F401XC/configs/mcuconf.h | 4 ++-- .../chibios/boards/STEMCELL/configs/mcuconf.h | 25 ++++++++++++++++++++-- 2 files changed, 25 insertions(+), 4 deletions(-) (limited to 'platforms') diff --git a/platforms/chibios/boards/GENERIC_STM32_F401XC/configs/mcuconf.h b/platforms/chibios/boards/GENERIC_STM32_F401XC/configs/mcuconf.h index 24cec7137d..1208563aa1 100644 --- a/platforms/chibios/boards/GENERIC_STM32_F401XC/configs/mcuconf.h +++ b/platforms/chibios/boards/GENERIC_STM32_F401XC/configs/mcuconf.h @@ -53,8 +53,8 @@ #define STM32_PLLP_VALUE 4 #define STM32_PLLQ_VALUE 7 #define STM32_HPRE STM32_HPRE_DIV1 -#define STM32_PPRE1 STM32_PPRE1_DIV2 -#define STM32_PPRE2 STM32_PPRE2_DIV1 +#define STM32_PPRE1 STM32_PPRE1_DIV2 +#define STM32_PPRE2 STM32_PPRE2_DIV1 #define STM32_RTCSEL STM32_RTCSEL_LSI #define STM32_RTCPRE_VALUE 8 #define STM32_MCO1SEL STM32_MCO1SEL_HSI diff --git a/platforms/chibios/boards/STEMCELL/configs/mcuconf.h b/platforms/chibios/boards/STEMCELL/configs/mcuconf.h index 621d3fcace..db239854aa 100644 --- a/platforms/chibios/boards/STEMCELL/configs/mcuconf.h +++ b/platforms/chibios/boards/STEMCELL/configs/mcuconf.h @@ -1,5 +1,18 @@ -// Copyright 2022 Mega Mind (@megamind4089) -// SPDX-License-Identifier: GPL-2.0-or-later +/* + ChibiOS - Copyright (C) 2006..2020 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ #ifndef MCUCONF_H #define MCUCONF_H @@ -165,6 +178,14 @@ #define STM32_PWM_USE_TIM10 FALSE #define STM32_PWM_USE_TIM11 FALSE +/* + * RTC driver system settings. + */ +#define STM32_RTC_PRESA_VALUE 32 +#define STM32_RTC_PRESS_VALUE 1024 +#define STM32_RTC_CR_INIT 0 +#define STM32_RTC_TAMPCR_INIT 0 + /* * SERIAL driver system settings. */ -- cgit v1.2.3 From 96c48a5f4aa461ed31fd4ee61151ac206e16fb5f Mon Sep 17 00:00:00 2001 From: Joel Challis Date: Mon, 31 Oct 2022 20:16:43 +0000 Subject: Refactor to avoid deprecated wmic execution (#18122) * wmic deprecated? * Update platforms/avr/flash.mk * Update platforms/avr/flash.mk --- platforms/avr/flash.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'platforms') diff --git a/platforms/avr/flash.mk b/platforms/avr/flash.mk index c104f730b3..e058e8d296 100644 --- a/platforms/avr/flash.mk +++ b/platforms/avr/flash.mk @@ -78,7 +78,7 @@ AVRDUDE_PROGRAMMER ?= avrdude define EXEC_AVRDUDE list_devices() { \ if $(GREP) -q -s icrosoft /proc/version; then \ - wmic.exe path Win32_SerialPort get DeviceID 2>/dev/null | LANG=C perl -pne 's/COM(\d+)/COM.($$1-1)/e' | sed 's!COM!/dev/ttyS!' | xargs echo -n | sort; \ + powershell.exe 'Get-CimInstance -Class Win32_SerialPort | Select -ExpandProperty "DeviceID"' 2>/dev/null | sed -e "s/\r//g" | LANG=C perl -pne 's/COM(\d+)/COM.($$1-1)/e' | sed 's!COM!/dev/ttyS!' | sort; \ elif [ "`uname`" = "FreeBSD" ]; then \ ls /dev/tty* | grep -v '\.lock$$' | grep -v '\.init$$'; \ else \ -- cgit v1.2.3