From 26b12a658bb33489399e16e2b9ef5987cd01298a Mon Sep 17 00:00:00 2001 From: Eric Callahan Date: Mon, 11 Apr 2022 19:59:56 -0400 Subject: [PATCH] src: update stm32 source Bring in the latest changes from Klipper. The STM32F4 variants are still unsupported at this time. Signed-off-by: Eric Callahan --- src/Kconfig | 2 +- src/stm32/Kconfig | 59 ++++++---- src/stm32/Makefile | 5 +- src/stm32/can.c | 103 +++++++++-------- src/stm32/clockline.c | 32 ++++++ src/stm32/gpioperiph.c | 38 ++++++ src/stm32/internal.h | 22 +++- src/stm32/stm32f0.c | 82 +++---------- src/stm32/stm32f1.c | 256 ++++++++++++++++++++++++----------------- src/stm32/stm32f4.c | 137 +++++++--------------- 10 files changed, 397 insertions(+), 339 deletions(-) create mode 100644 src/stm32/clockline.c create mode 100644 src/stm32/gpioperiph.c diff --git a/src/Kconfig b/src/Kconfig index ade4fb7..638bca4 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -12,7 +12,7 @@ config CANSERIAL bool default y -config CANBUS_BAUD +config CONFIG_CANBUS_FREQUENCY int "CAN bus speed" default 500000 diff --git a/src/stm32/Kconfig b/src/stm32/Kconfig index 2d28890..42f8e95 100644 --- a/src/stm32/Kconfig +++ b/src/stm32/Kconfig @@ -17,18 +17,27 @@ choice config MACH_STM32F405 bool "STM32F405" select MACH_STM32F4 + select MACH_STM32F4x5 config MACH_STM32F407 bool "STM32F407" select MACH_STM32F4 + select MACH_STM32F4x5 + config MACH_STM32F429 + bool "STM32F429" + select MACH_STM32F4 + select MACH_STM32F4x5 config MACH_STM32F446 bool "STM32F446" select MACH_STM32F4 config MACH_STM32F042 bool "STM32F042" select MACH_STM32F0 - config MACH_STM32F070 - bool "STM32F070" + select MACH_STM32F0x2 + config MACH_STM32F072 + bool "STM32F072" select MACH_STM32F0 + select MACH_STM32F0x2 + endchoice config MACH_STM32F0 @@ -43,11 +52,12 @@ config MACH_STM32F4 config MCU string default "stm32f042x6" if MACH_STM32F042 - default "stm32f070xb" if MACH_STM32F070 + default "stm32f072xb" if MACH_STM32F072 default "stm32f103xe" if MACH_STM32F103 default "stm32f207xx" if MACH_STM32F207 default "stm32f405xx" if MACH_STM32F405 default "stm32f407xx" if MACH_STM32F407 + default "stm32f429xx" if MACH_STM32F429 default "stm32f446xx" if MACH_STM32F446 config CLOCK_FREQ @@ -56,13 +66,13 @@ config CLOCK_FREQ default 64000000 if MACH_STM32F103 && STM32_CLOCK_REF_INTERNAL default 72000000 if MACH_STM32F103 default 120000000 if MACH_STM32F207 - default 168000000 if MACH_STM32F405 || MACH_STM32F407 + default 168000000 if MACH_STM32F4x5 default 180000000 if MACH_STM32F446 config FLASH_SIZE hex default 0x8000 if MACH_STM32F042 - default 0x20000 if MACH_STM32F070 + default 0x20000 if MACH_STM32F072 default 0x10000 if MACH_STM32F103 # Flash size of stm32f103x8 (64KiB) default 0x40000 if MACH_STM32F2 default 0x80000 if MACH_STM32F4 @@ -74,7 +84,7 @@ config RAM_START config RAM_SIZE hex default 0x1800 if MACH_STM32F042 - default 0x4000 if MACH_STM32F070 + default 0x4000 if MACH_STM32F072 default 0x5000 if MACH_STM32F103 # Ram size of stm32f103x8 (20KiB) default 0x20000 if MACH_STM32F207 default 0x20000 if MACH_STM32F4 @@ -97,6 +107,16 @@ config ARMCM_RAM_VECTORTABLE default y if MACH_STM32F0 && FLASH_START != 0x8000000 default n +config STM32F103GD_DISABLE_SWD + bool "Disable SWD at startup (for GigaDevice stm32f103 clones)" + depends on MACH_STM32F103 + default n + help + The GigaDevice clone of the STM32F103 may not be able to + reliably disable SWD at run-time. This can prevent the PA13 + and PA14 pins from being available. Selecting this option + disables SWD at startup and thus makes these pins available. + choice prompt "Clock Reference" config STM32_CLOCK_REF_8M @@ -105,11 +125,14 @@ choice bool "12 MHz crystal" config STM32_CLOCK_REF_16M bool "16 MHz crystal" + config STM32_CLOCK_REF_25M + bool "25 MHz crystal" config STM32_CLOCK_REF_INTERNAL bool "Internal clock" endchoice config CLOCK_REF_FREQ int + default 25000000 if STM32_CLOCK_REF_25M default 16000000 if STM32_CLOCK_REF_16M default 12000000 if STM32_CLOCK_REF_12M default 1 if STM32_CLOCK_REF_INTERNAL @@ -117,16 +140,20 @@ config CLOCK_REF_FREQ choice prompt "CAN pins" - config CAN_PINS_PA11_PA12 + config STM32_CANBUS_PA11_PA12 bool "Pins PA11(rx) and PA12(tx)" - config CAN_PINS_PB8_PB9 + config STM32_CANBUS_PA11_PA12_REMAP + bool "Pins on PA9(rx) and PA10(tx)" if MACH_STM32F042 + config STM32_CANBUS_PB8_PB9 bool "Pins PB8(rx) and PB9(tx)" - config CAN_PINS_PI8_PH13 - bool "Pins PI8(rx) and PH13(tx)" if MACH_STM32F4 - config CAN_PINS_PB5_PB6 + config STM32_CANBUS_PI9_PH13 + bool "Pins PI9(rx) and PH13(tx)" if MACH_STM32F4 + config STM32_CANBUS_PB5_PB6 bool "Pins PB5(rx) and PB6(tx)" if MACH_STM32F4 - config CAN_PINS_PB12_PB13 + config STM32_CANBUS_PB12_PB13 bool "Pins PB12(rx) and PB13(tx)" if MACH_STM32F4 + config STM32_CANBUS_PD0_PD1 + bool "Pins PD0(rx) and PD1(tx)" endchoice config STM32F0_TRIM @@ -138,14 +165,6 @@ config STM32F0_TRIM Default is 16 (use factory default). Each increment increases the clock rate by ~240KHz. -config STM32F042_PIN_SWAP - bool "Use PA9/PA10 for USB or CAN" if MACH_STM32F042 - depends on MACH_STM32F042 - default y if MACH_STM32F042 - default n - help - Remaps logical pins PA11/PA12 to physical PA9/PA10 on low pincount F042 devices. - choice depends on MACH_STM32F103 prompt "Flash Page Size" diff --git a/src/stm32/Makefile b/src/stm32/Makefile index 24a4aa8..159c02a 100644 --- a/src/stm32/Makefile +++ b/src/stm32/Makefile @@ -24,19 +24,22 @@ CFLAGS_canboot.elf += -T $(OUT)src/generic/armcm_link.ld $(OUT)canboot.elf: $(OUT)src/generic/armcm_link.ld # Add source files -src-y += stm32/gpio.c stm32/flash.c +src-y += stm32/gpio.c stm32/flash.c stm32/clockline.c src-y += generic/armcm_boot.c generic/armcm_irq.c src-$(CONFIG_MACH_STM32F0) += ../lib/stm32f0/system_stm32f0xx.c src-$(CONFIG_MACH_STM32F0) += stm32/stm32f0.c stm32/stm32f0_timer.c +src-$(CONFIG_MACH_STM32F0) += stm32/gpioperiph.c src-$(CONFIG_MACH_STM32F1) += ../lib/stm32f1/system_stm32f1xx.c src-$(CONFIG_MACH_STM32F1) += stm32/stm32f1.c generic/armcm_timer.c src-$(CONFIG_MACH_STM32F2) += ../lib/stm32f2/system_stm32f2xx.c src-$(CONFIG_MACH_STM32F2) += stm32/stm32f4.c generic/armcm_timer.c +src-$(CONFIG_MACH_STM32F2) += stm32/gpioperiph.c src-$(CONFIG_MACH_STM32F4) += ../lib/stm32f4/system_stm32f4xx.c src-$(CONFIG_MACH_STM32F4) += stm32/stm32f4.c generic/armcm_timer.c +src-$(CONFIG_MACH_STM32F4) += stm32/gpioperiph.c can-src-$(CONFIG_CANSERIAL) += stm32/can.c ../lib/fast-hash/fasthash.c src-$(CONFIG_CANSERIAL) += $(can-src-y) generic/canbus.c diff --git a/src/stm32/can.c b/src/stm32/can.c index fa85bfc..2533f24 100644 --- a/src/stm32/can.c +++ b/src/stm32/can.c @@ -15,31 +15,36 @@ #include "internal.h" // enable_pclock #include "ctr.h" // DECL_CONSTANT_STR -#if CONFIG_CAN_PINS_PA11_PA12 +#if CONFIG_STM32_CANBUS_PA11_PA12 || CONFIG_STM32_CANBUS_PA11_PA12_REMAP DECL_CONSTANT_STR("RESERVE_PINS_CAN", "PA11,PA12"); #define GPIO_Rx GPIO('A', 11) #define GPIO_Tx GPIO('A', 12) #endif -#if CONFIG_CAN_PINS_PB8_PB9 +#if CONFIG_STM32_CANBUS_PB8_PB9 DECL_CONSTANT_STR("RESERVE_PINS_CAN", "PB8,PB9"); #define GPIO_Rx GPIO('B', 8) #define GPIO_Tx GPIO('B', 9) #endif -#if CONFIG_CAN_PINS_PI8_PH13 - DECL_CONSTANT_STR("RESERVE_PINS_CAN", "PI8,PH13"); - #define GPIO_Rx GPIO('I', 8) +#if CONFIG_STM32_CANBUS_PI9_PH13 + DECL_CONSTANT_STR("RESERVE_PINS_CAN", "PI9,PH13"); + #define GPIO_Rx GPIO('I', 9) #define GPIO_Tx GPIO('H', 13) #endif -#if CONFIG_CAN_PINS_PB5_PB6 +#if CONFIG_STM32_CANBUS_PB5_PB6 DECL_CONSTANT_STR("RESERVE_PINS_CAN", "PB5,PB6"); #define GPIO_Rx GPIO('B', 5) #define GPIO_Tx GPIO('B', 6) #endif -#if CONFIG_CAN_PINS_PB12_PB13 +#if CONFIG_STM32_CANBUS_PB12_PB13 DECL_CONSTANT_STR("RESERVE_PINS_CAN", "PB12,PB13"); #define GPIO_Rx GPIO('B', 12) #define GPIO_Tx GPIO('B', 13) #endif +#if CONFIG_STM32_CANBUS_PD0_PD1 + DECL_CONSTANT_STR("RESERVE_PINS_CAN", "PD0,PD1"); + #define GPIO_Rx GPIO('D', 0) + #define GPIO_Tx GPIO('D', 1) +#endif #if CONFIG_MACH_STM32F0 #define SOC_CAN CAN @@ -61,14 +66,14 @@ #if CONFIG_MACH_STM32F4 #warning CAN on STM32F4 is untested - #if (CONFIG_CAN_PINS_PA11_PA12 || CONFIG_CAN_PINS_PB8_PB9 \ - || CONFIG_CAN_PINS_PI8_PH13) + #if (CONFIG_STM32_CANBUS_PA11_PA12 || CONFIG_STM32_CANBUS_PB8_PB9 \ + || CONFIG_STM32_CANBUS_PD0_PD1 || CONFIG_STM32_CANBUS_PI9_PH13) #define SOC_CAN CAN1 #define CAN_RX0_IRQn CAN1_RX0_IRQn #define CAN_RX1_IRQn CAN1_RX1_IRQn #define CAN_TX_IRQn CAN1_TX_IRQn #define CAN_SCE_IRQn CAN1_SCE_IRQn - #elif CONFIG_CAN_PINS_PB5_PB6 || CONFIG_CAN_PINS_PB12_PB13 + #elif CONFIG_STM32_CANBUS_PB5_PB6 || CONFIG_STM32_CANBUS_PB12_PB13 #define SOC_CAN CAN2 #define CAN_RX0_IRQn CAN2_RX0_IRQn #define CAN_RX1_IRQn CAN2_RX1_IRQn @@ -152,62 +157,64 @@ canbus_send(uint32_t id, uint32_t len, uint8_t *data) return len; } -#define CAN_FILTER_NUMBER 0 - // Setup the receive packet filter -static void -can_set_filter(uint32_t id1, uint32_t id2) +void +canbus_set_filter(uint32_t id) { - uint32_t filternbrbitpos = 1 << CAN_FILTER_NUMBER; - /* Select the start slave bank */ SOC_CAN->FMR |= CAN_FMR_FINIT; /* Initialisation mode for the filter */ SOC_CAN->FA1R = 0; - SOC_CAN->sFilterRegister[CAN_FILTER_NUMBER].FR1 = id1 << (5 + 16); - SOC_CAN->sFilterRegister[CAN_FILTER_NUMBER].FR2 = id2 << (5 + 16); + uint32_t mask = CAN_RI0R_STID | CAN_TI0R_IDE | CAN_TI0R_RTR; + SOC_CAN->sFilterRegister[0].FR1 = CANBUS_ID_ADMIN << CAN_RI0R_STID_Pos; + SOC_CAN->sFilterRegister[0].FR2 = mask; + SOC_CAN->sFilterRegister[1].FR1 = (id + 1) << CAN_RI0R_STID_Pos; + SOC_CAN->sFilterRegister[1].FR2 = mask; + SOC_CAN->sFilterRegister[2].FR1 = id << CAN_RI0R_STID_Pos; + SOC_CAN->sFilterRegister[2].FR2 = mask; - /* Identifier list mode for the filter */ - SOC_CAN->FM1R = filternbrbitpos; /* 32-bit scale for the filter */ - SOC_CAN->FS1R = filternbrbitpos; + SOC_CAN->FS1R = (1<<0) | (1<<1) | (1<<2); - /* FIFO 0 assigned for the filter */ - SOC_CAN->FFA1R = 0; + /* FIFO 1 assigned to 'id' */ + SOC_CAN->FFA1R = (1<<2); /* Filter activation */ - SOC_CAN->FA1R = filternbrbitpos; + SOC_CAN->FA1R = (1<<0) | (id ? (1<<1) | (1<<2) : 0); /* Leave the initialisation mode for the filter */ SOC_CAN->FMR &= ~CAN_FMR_FINIT; } -void -canbus_set_dataport(uint32_t id) -{ - can_set_filter(CANBUS_ID_UUID, id); -} - -void -canbus_reboot(void) -{ - NVIC_SystemReset(); -} - // This function handles CAN global interrupts void CAN_IRQHandler(void) { - if (SOC_CAN->RF0R & CAN_RF0R_FMP0) { - // Rx - SOC_CAN->IER &= ~CAN_IER_FMPIE0; - canbus_notify_rx(); + if (SOC_CAN->RF1R & CAN_RF1R_FMP1) { + // Read and ack data packet + CAN_FIFOMailBox_TypeDef *mb = &SOC_CAN->sFIFOMailBox[1]; + uint32_t rir_id = (mb->RIR >> CAN_RI0R_STID_Pos) & 0x7FF; + uint32_t dlc = mb->RDTR & CAN_RDT0R_DLC; + uint32_t rdlr = mb->RDLR, rdhr = mb->RDHR; + SOC_CAN->RF1R = CAN_RF1R_RFOM1; + + // Process packet + union { + struct { uint32_t rdlr, rdhr; }; + uint8_t data[8]; + } rdata = { .rdlr = rdlr, .rdhr = rdhr }; + canbus_process_data(rir_id, dlc, rdata.data); } uint32_t ier = SOC_CAN->IER; + if (ier & CAN_IER_FMPIE0 && SOC_CAN->RF0R & CAN_RF0R_FMP0) { + // Admin Rx + SOC_CAN->IER = ier = ier & ~CAN_IER_FMPIE0; + canbus_notify_rx(); + } if (ier & CAN_IER_TMEIE && SOC_CAN->TSR & (CAN_TSR_RQCP0|CAN_TSR_RQCP1|CAN_TSR_RQCP2)) { // Tx - SOC_CAN->IER &= ~CAN_IER_TMEIE; + SOC_CAN->IER = ier & ~CAN_IER_TMEIE; canbus_notify_tx(); } } @@ -260,6 +267,12 @@ compute_btr(uint32_t pclock, uint32_t bitrate) return make_btr(sjw, time_seg1, time_seg2, brp); } +void +canbus_reboot(void) +{ + NVIC_SystemReset(); +} + void can_init(void) { @@ -270,7 +283,7 @@ can_init(void) uint32_t pclock = get_pclock_frequency((uint32_t)SOC_CAN); - uint32_t btr = compute_btr(pclock, CONFIG_CANBUS_BAUD); + uint32_t btr = compute_btr(pclock, CONFIG_CANBUS_FREQUENCY); /*##-1- Configure the CAN #######################################*/ @@ -290,17 +303,15 @@ can_init(void) ; /*##-2- Configure the CAN Filter #######################################*/ - can_set_filter(CANBUS_ID_UUID, CANBUS_ID_SET); + canbus_set_filter(0); /*##-3- Configure Interrupts #################################*/ - - SOC_CAN->IER = CAN_IER_FMPIE0; // RX mailbox IRQ - armcm_enable_irq(CAN_IRQHandler, CAN_RX0_IRQn, 0); if (CAN_RX0_IRQn != CAN_RX1_IRQn) armcm_enable_irq(CAN_IRQHandler, CAN_RX1_IRQn, 0); if (CAN_RX0_IRQn != CAN_TX_IRQn) armcm_enable_irq(CAN_IRQHandler, CAN_TX_IRQn, 0); + SOC_CAN->IER = CAN_IER_FMPIE1; // Convert unique 96-bit chip id into 48 bit representation uint64_t hash = fasthash64((uint8_t*)UID_BASE, 12, 0xA16231A7); diff --git a/src/stm32/clockline.c b/src/stm32/clockline.c new file mode 100644 index 0000000..970ce9d --- /dev/null +++ b/src/stm32/clockline.c @@ -0,0 +1,32 @@ +// Code to enable clock lines on stm32 +// +// Copyright (C) 2021 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "board/irq.h" // irq_save +#include "internal.h" // struct cline + +// Enable a peripheral clock +void +enable_pclock(uint32_t periph_base) +{ + struct cline cl = lookup_clock_line(periph_base); + irqstatus_t flag = irq_save(); + *cl.en |= cl.bit; + *cl.en; // Pause 2 cycles to ensure peripheral is enabled + if (cl.rst) { + // Reset peripheral + *cl.rst = cl.bit; + *cl.rst = 0; + } + irq_restore(flag); +} + +// Check if a peripheral clock has been enabled +int +is_enabled_pclock(uint32_t periph_base) +{ + struct cline cl = lookup_clock_line(periph_base); + return *cl.en & cl.bit; +} diff --git a/src/stm32/gpioperiph.c b/src/stm32/gpioperiph.c new file mode 100644 index 0000000..06cdaa0 --- /dev/null +++ b/src/stm32/gpioperiph.c @@ -0,0 +1,38 @@ +// Code to setup gpio on stm32 chip (except for stm32f1) +// +// Copyright (C) 2019-2021 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "internal.h" // gpio_peripheral + +// Set the mode and extended function of a pin +void +gpio_peripheral(uint32_t gpio, uint32_t mode, int pullup) +{ + GPIO_TypeDef *regs = digital_regs[GPIO2PORT(gpio)]; + + // Enable GPIO clock + gpio_clock_enable(regs); + + // Configure GPIO + uint32_t mode_bits = mode & 0xf, func = (mode >> 4) & 0xf, od = mode >> 8; + uint32_t pup = pullup ? (pullup > 0 ? 1 : 2) : 0; + uint32_t pos = gpio % 16, af_reg = pos / 8; + uint32_t af_shift = (pos % 8) * 4, af_msk = 0x0f << af_shift; + uint32_t m_shift = pos * 2, m_msk = 0x03 << m_shift; + + regs->AFR[af_reg] = (regs->AFR[af_reg] & ~af_msk) | (func << af_shift); + regs->MODER = (regs->MODER & ~m_msk) | (mode_bits << m_shift); + regs->PUPDR = (regs->PUPDR & ~m_msk) | (pup << m_shift); + regs->OTYPER = (regs->OTYPER & ~(1 << pos)) | (od << pos); + + // Setup OSPEEDR: + // stm32f0 is ~10Mhz at 50pF + // stm32f2 is ~25Mhz at 40pF + // stm32f4 is ~50Mhz at 40pF + // stm32g0 is ~30Mhz at 50pF + // stm32h7 is ~85Mhz at 50pF + uint32_t ospeed = CONFIG_MACH_STM32F0 ? 0x01 : 0x02; + regs->OSPEEDR = (regs->OSPEEDR & ~m_msk) | (ospeed << m_shift); +} diff --git a/src/stm32/internal.h b/src/stm32/internal.h index 2538bba..f0535ab 100644 --- a/src/stm32/internal.h +++ b/src/stm32/internal.h @@ -12,24 +12,34 @@ #include "stm32f2xx.h" #elif CONFIG_MACH_STM32F4 #include "stm32f4xx.h" +#elif CONFIG_MACH_STM32G0 +#include "stm32g0xx.h" +#elif CONFIG_MACH_STM32H7 +#include "stm32h7xx.h" #endif +// gpio.c extern GPIO_TypeDef * const digital_regs[]; - #define GPIO(PORT, NUM) (((PORT)-'A') * 16 + (NUM)) #define GPIO2PORT(PIN) ((PIN) / 16) #define GPIO2BIT(PIN) (1<<((PIN) % 16)) +// gpioperiph.c #define GPIO_INPUT 0 #define GPIO_OUTPUT 1 #define GPIO_OPEN_DRAIN 0x100 #define GPIO_FUNCTION(fn) (2 | ((fn) << 4)) #define GPIO_ANALOG 3 - -void enable_pclock(uint32_t periph_base); -int is_enabled_pclock(uint32_t periph_base); -uint32_t get_pclock_frequency(uint32_t periph_base); -void gpio_clock_enable(GPIO_TypeDef *regs); void gpio_peripheral(uint32_t gpio, uint32_t mode, int pullup); +// clockline.c +void enable_pclock(uint32_t periph_base); +int is_enabled_pclock(uint32_t periph_base); + +// stm32??.c +struct cline { volatile uint32_t *en, *rst; uint32_t bit; }; +struct cline lookup_clock_line(uint32_t periph_base); +uint32_t get_pclock_frequency(uint32_t periph_base); +void gpio_clock_enable(GPIO_TypeDef *regs); + #endif // internal.h diff --git a/src/stm32/stm32f0.c b/src/stm32/stm32f0.c index c963679..42b5a70 100644 --- a/src/stm32/stm32f0.c +++ b/src/stm32/stm32f0.c @@ -1,6 +1,6 @@ -// Code to setup clocks and gpio on stm32f0 +// Code to setup clocks on stm32f0 // -// Copyright (C) 2019 Kevin O'Connor +// Copyright (C) 2019-2021 Kevin O'Connor // // This file may be distributed under the terms of the GNU GPLv3 license. @@ -13,38 +13,19 @@ #define FREQ_PERIPH 48000000 -// Enable a peripheral clock -void -enable_pclock(uint32_t periph_base) +// Map a peripheral address to its enable bits +struct cline +lookup_clock_line(uint32_t periph_base) { - if (periph_base < SYSCFG_BASE) { - uint32_t pos = (periph_base - APBPERIPH_BASE) / 0x400; - RCC->APB1ENR |= 1 << pos; - RCC->APB1ENR; - } else if (periph_base < AHBPERIPH_BASE) { - uint32_t pos = (periph_base - SYSCFG_BASE) / 0x400; - RCC->APB2ENR |= 1 << pos; - RCC->APB2ENR; + if (periph_base >= AHB2PERIPH_BASE) { + uint32_t bit = 1 << ((periph_base - AHB2PERIPH_BASE) / 0x400 + 17); + return (struct cline){.en=&RCC->AHBENR, .rst=&RCC->AHBRSTR, .bit=bit}; + } else if (periph_base >= SYSCFG_BASE) { + uint32_t bit = 1 << ((periph_base - SYSCFG_BASE) / 0x400); + return (struct cline){.en=&RCC->APB2ENR, .rst=&RCC->APB2RSTR, .bit=bit}; } else { - uint32_t pos = (periph_base - AHB2PERIPH_BASE) / 0x400; - RCC->AHBENR |= 1 << (pos + 17); - RCC->AHBENR; - } -} - -// Check if a peripheral clock has been enabled -int -is_enabled_pclock(uint32_t periph_base) -{ - if (periph_base < SYSCFG_BASE) { - uint32_t pos = (periph_base - APBPERIPH_BASE) / 0x400; - return RCC->APB1ENR & (1 << pos); - } else if (periph_base < AHBPERIPH_BASE) { - uint32_t pos = (periph_base - SYSCFG_BASE) / 0x400; - return RCC->APB2ENR & (1 << pos); - } else { - uint32_t pos = (periph_base - AHB2PERIPH_BASE) / 0x400; - return RCC->AHBENR & (1 << (pos + 17)); + uint32_t bit = 1 << ((periph_base - APBPERIPH_BASE) / 0x400); + return (struct cline){.en=&RCC->APB1ENR, .rst=&RCC->APB1RSTR, .bit=bit}; } } @@ -64,41 +45,6 @@ gpio_clock_enable(GPIO_TypeDef *regs) RCC->AHBENR; } -// Set the mode and extended function of a pin -void -gpio_peripheral(uint32_t gpio, uint32_t mode, int pullup) -{ - GPIO_TypeDef *regs = digital_regs[GPIO2PORT(gpio)]; - - // Enable GPIO clock - gpio_clock_enable(regs); - - // Configure GPIO - uint32_t mode_bits = mode & 0xf, func = (mode >> 4) & 0xf, od = mode >> 8; - uint32_t pup = pullup ? (pullup > 0 ? 1 : 2) : 0; - uint32_t pos = gpio % 16, af_reg = pos / 8; - uint32_t af_shift = (pos % 8) * 4, af_msk = 0x0f << af_shift; - uint32_t m_shift = pos * 2, m_msk = 0x03 << m_shift; - - regs->AFR[af_reg] = (regs->AFR[af_reg] & ~af_msk) | (func << af_shift); - regs->MODER = (regs->MODER & ~m_msk) | (mode_bits << m_shift); - regs->PUPDR = (regs->PUPDR & ~m_msk) | (pup << m_shift); - regs->OTYPER = (regs->OTYPER & ~(1 << pos)) | (od << pos); - regs->OSPEEDR = (regs->OSPEEDR & ~m_msk) | (0x02 << m_shift); -} - -#define USB_BOOT_FLAG_ADDR (CONFIG_RAM_START + CONFIG_RAM_SIZE - 1024) -#define USB_BOOT_FLAG 0x55534220424f4f54 // "USB BOOT" - -// Handle USB reboot requests -void -usb_request_bootloader(void) -{ - irq_disable(); - *(uint64_t*)USB_BOOT_FLAG_ADDR = USB_BOOT_FLAG; - NVIC_SystemReset(); -} - // Configure and enable the PLL as clock source static void pll_setup(void) @@ -160,7 +106,7 @@ armcm_main(void) // Support pin remapping USB/CAN pins on low pinout stm32f042 #ifdef SYSCFG_CFGR1_PA11_PA12_RMP - if (CONFIG_STM32F042_PIN_SWAP) { + if (CONFIG_STM32_CANBUS_PA11_PA12_REMAP) { enable_pclock(SYSCFG_BASE); SYSCFG->CFGR1 |= SYSCFG_CFGR1_PA11_PA12_RMP; } diff --git a/src/stm32/stm32f1.c b/src/stm32/stm32f1.c index b7ea170..be6387d 100644 --- a/src/stm32/stm32f1.c +++ b/src/stm32/stm32f1.c @@ -1,6 +1,6 @@ // Code to setup clocks and gpio on stm32f1 // -// Copyright (C) 2019 Kevin O'Connor +// Copyright (C) 2019-2021 Kevin O'Connor // // This file may be distributed under the terms of the GNU GPLv3 license. @@ -13,38 +13,19 @@ #define FREQ_PERIPH (CONFIG_CLOCK_FREQ / 2) -// Enable a peripheral clock -void -enable_pclock(uint32_t periph_base) +// Map a peripheral address to its enable bits +struct cline +lookup_clock_line(uint32_t periph_base) { - if (periph_base < APB2PERIPH_BASE) { - uint32_t pos = (periph_base - APB1PERIPH_BASE) / 0x400; - RCC->APB1ENR |= (1<APB1ENR; - } else if (periph_base < AHBPERIPH_BASE) { - uint32_t pos = (periph_base - APB2PERIPH_BASE) / 0x400; - RCC->APB2ENR |= (1<APB2ENR; + if (periph_base >= AHBPERIPH_BASE) { + uint32_t bit = 1 << ((periph_base - AHBPERIPH_BASE) / 0x400); + return (struct cline){.en=&RCC->AHBENR, .bit=bit}; + } else if (periph_base >= APB2PERIPH_BASE) { + uint32_t bit = 1 << ((periph_base - APB2PERIPH_BASE) / 0x400); + return (struct cline){.en=&RCC->APB2ENR, .rst=&RCC->APB2RSTR, .bit=bit}; } else { - uint32_t pos = (periph_base - AHBPERIPH_BASE) / 0x400; - RCC->AHBENR |= (1<AHBENR; - } -} - -// Check if a peripheral clock has been enabled -int -is_enabled_pclock(uint32_t periph_base) -{ - if (periph_base < APB2PERIPH_BASE) { - uint32_t pos = (periph_base - APB1PERIPH_BASE) / 0x400; - return RCC->APB1ENR & (1<APB2ENR & (1<AHBENR & (1<APB1ENR, .rst=&RCC->APB1RSTR, .bit=bit}; } } @@ -64,74 +45,6 @@ gpio_clock_enable(GPIO_TypeDef *regs) RCC->APB2ENR; } - -static void stm32f1_alternative_remap(uint32_t mapr_mask, uint32_t mapr_value) -{ - // The MAPR register is a mix of write only and r/w bits - // We have to save the written values in a global variable - static uint32_t mapr = 0; - - mapr &= ~mapr_mask; - mapr |= mapr_value; - AFIO->MAPR = mapr; -} - -// Set the mode and extended function of a pin -void -gpio_peripheral(uint32_t gpio, uint32_t mode, int pullup) -{ - GPIO_TypeDef *regs = digital_regs[GPIO2PORT(gpio)]; - - // Enable GPIO clock - gpio_clock_enable(regs); - - // Configure GPIO - uint32_t pos = gpio % 16, shift = (pos % 8) * 4, msk = 0xf << shift, cfg; - if (mode == GPIO_INPUT) { - cfg = pullup ? 0x8 : 0x4; - } else if (mode == GPIO_OUTPUT) { - cfg = 0x1; - } else if (mode == (GPIO_OUTPUT | GPIO_OPEN_DRAIN)) { - cfg = 0x5; - } else if (mode == GPIO_ANALOG) { - cfg = 0x0; - } else { - if (mode & GPIO_OPEN_DRAIN) - // Alternate function with open-drain mode - cfg = 0xd; - else if (pullup > 0) - // Alternate function input pins use GPIO_INPUT mode on the stm32f1 - cfg = 0x8; - else - cfg = 0x9; - } - if (pos & 0x8) - regs->CRH = (regs->CRH & ~msk) | (cfg << shift); - else - regs->CRL = (regs->CRL & ~msk) | (cfg << shift); - - if (pullup > 0) - regs->BSRR = 1 << pos; - else if (pullup < 0) - regs->BSRR = 1 << (pos + 16); - - if (gpio == GPIO('A', 13) || gpio == GPIO('A', 14)) - // Disable SWD to free PA13, PA14 - stm32f1_alternative_remap(AFIO_MAPR_SWJ_CFG_Msk, - AFIO_MAPR_SWJ_CFG_DISABLE); - - // STM32F1 remaps functions to pins in a very different - // way from other STM32s. - // Code below is emulating a few mappings to work like an STM32F4 - uint32_t func = (mode >> 4) & 0xf; - if(( gpio == GPIO('B', 8) || gpio == GPIO('B', 9)) && - func == 9) { // CAN - stm32f1_alternative_remap(AFIO_MAPR_CAN_REMAP_Msk, - AFIO_MAPR_CAN_REMAP_REMAP2); - } - // Add more as needed -} - // Main clock setup called at chip startup static void clock_setup(void) @@ -140,9 +53,14 @@ clock_setup(void) uint32_t cfgr; if (!CONFIG_STM32_CLOCK_REF_INTERNAL) { // Configure 72Mhz PLL from external crystal (HSE) - uint32_t div = CONFIG_CLOCK_FREQ / CONFIG_CLOCK_REF_FREQ; RCC->CR |= RCC_CR_HSEON; - cfgr = (1 << RCC_CFGR_PLLSRC_Pos) | ((div - 2) << RCC_CFGR_PLLMULL_Pos); + uint32_t div = CONFIG_CLOCK_FREQ / (CONFIG_CLOCK_REF_FREQ / 2); + cfgr = 1 << RCC_CFGR_PLLSRC_Pos; + if ((div & 1) && div <= 16) + cfgr |= RCC_CFGR_PLLXTPRE_HSE_DIV2; + else + div /= 2; + cfgr |= (div - 2) << RCC_CFGR_PLLMULL_Pos; } else { // Configure 72Mhz PLL from internal 8Mhz oscillator (HSI) uint32_t div2 = (CONFIG_CLOCK_FREQ / 8000000) * 2; @@ -166,6 +84,131 @@ clock_setup(void) ; } + +/**************************************************************** + * GPIO setup + ****************************************************************/ + +static void +stm32f1_alternative_remap(uint32_t mapr_mask, uint32_t mapr_value) +{ + // The MAPR register is a mix of write only and r/w bits + // We have to save the written values in a global variable + static uint32_t mapr = 0; + + mapr &= ~mapr_mask; + mapr |= mapr_value; + AFIO->MAPR = mapr; +} + +#define STM_OSPEED 0x1 // ~10Mhz at 50pF + +// Set the mode and extended function of a pin +void +gpio_peripheral(uint32_t gpio, uint32_t mode, int pullup) +{ + GPIO_TypeDef *regs = digital_regs[GPIO2PORT(gpio)]; + + // Enable GPIO clock + gpio_clock_enable(regs); + + // Configure GPIO + uint32_t pos = gpio % 16, shift = (pos % 8) * 4, msk = 0xf << shift, cfg; + if (mode == GPIO_INPUT) { + cfg = pullup ? 0x8 : 0x4; + } else if (mode == GPIO_OUTPUT) { + cfg = STM_OSPEED; + } else if (mode == (GPIO_OUTPUT | GPIO_OPEN_DRAIN)) { + cfg = 0x4 | STM_OSPEED; + } else if (mode == GPIO_ANALOG) { + cfg = 0x0; + } else { + if (mode & GPIO_OPEN_DRAIN) + // Alternate function with open-drain mode + cfg = 0xc | STM_OSPEED; + else if (pullup > 0) + // Alternate function input pins use GPIO_INPUT mode on the stm32f1 + cfg = 0x8; + else + cfg = 0x8 | STM_OSPEED; + } + if (pos & 0x8) + regs->CRH = (regs->CRH & ~msk) | (cfg << shift); + else + regs->CRL = (regs->CRL & ~msk) | (cfg << shift); + + if (pullup > 0) + regs->BSRR = 1 << pos; + else if (pullup < 0) + regs->BSRR = 1 << (pos + 16); + + if (gpio == GPIO('A', 13) || gpio == GPIO('A', 14)) + // Disable SWD to free PA13, PA14 + stm32f1_alternative_remap(AFIO_MAPR_SWJ_CFG_Msk, + AFIO_MAPR_SWJ_CFG_DISABLE); + + // STM32F1 remaps functions to pins in a very different + // way from other STM32s. + // Code below is emulating a few mappings to work like an STM32F4 + uint32_t func = (mode >> 4) & 0xf; + if (func == 1) { + // TIM2 + if (gpio == GPIO('A', 15) || gpio == GPIO('B', 3)) + stm32f1_alternative_remap(AFIO_MAPR_TIM2_REMAP_Msk, + AFIO_MAPR_TIM2_REMAP_PARTIALREMAP1); + else if (gpio == GPIO('B', 10) || gpio == GPIO('B', 11)) + stm32f1_alternative_remap(AFIO_MAPR_TIM2_REMAP_Msk, + AFIO_MAPR_TIM2_REMAP_PARTIALREMAP2); + } else if (func == 2) { + // TIM3 and TIM4 + if (gpio == GPIO('B', 4) || gpio == GPIO('B', 5)) + stm32f1_alternative_remap(AFIO_MAPR_TIM3_REMAP_Msk, + AFIO_MAPR_TIM3_REMAP_PARTIALREMAP); + else if (gpio == GPIO('C', 6) || gpio == GPIO('C', 7) + || gpio == GPIO('C', 8) || gpio == GPIO('C', 9)) + stm32f1_alternative_remap(AFIO_MAPR_TIM3_REMAP_Msk, + AFIO_MAPR_TIM3_REMAP_FULLREMAP); + else if (gpio == GPIO('D', 12) || gpio == GPIO('D', 13) + || gpio == GPIO('D', 14) || gpio == GPIO('D', 15)) + stm32f1_alternative_remap(AFIO_MAPR_TIM4_REMAP_Msk, + AFIO_MAPR_TIM4_REMAP); + } else if (func == 4) { + // I2C + if (gpio == GPIO('B', 8) || gpio == GPIO('B', 9)) + stm32f1_alternative_remap(AFIO_MAPR_I2C1_REMAP_Msk, + AFIO_MAPR_I2C1_REMAP); + } else if (func == 5) { + // SPI + if (gpio == GPIO('B', 3) || gpio == GPIO('B', 4) + || gpio == GPIO('B', 5)) + stm32f1_alternative_remap(AFIO_MAPR_SPI1_REMAP_Msk, + AFIO_MAPR_SPI1_REMAP); + } else if (func == 7) { + // USART + if (gpio == GPIO('B', 6) || gpio == GPIO('B', 7)) + stm32f1_alternative_remap(AFIO_MAPR_USART1_REMAP_Msk, + AFIO_MAPR_USART1_REMAP); + else if (gpio == GPIO('D', 5) || gpio == GPIO('D', 6)) + stm32f1_alternative_remap(AFIO_MAPR_USART2_REMAP_Msk, + AFIO_MAPR_USART2_REMAP); + else if (gpio == GPIO('D', 8) || gpio == GPIO('D', 9)) + stm32f1_alternative_remap(AFIO_MAPR_USART3_REMAP_Msk, + AFIO_MAPR_USART3_REMAP_FULLREMAP); + } else if (func == 9) { + // CAN + if (gpio == GPIO('B', 8) || gpio == GPIO('B', 9)) + stm32f1_alternative_remap(AFIO_MAPR_CAN_REMAP_Msk, + AFIO_MAPR_CAN_REMAP_REMAP2); + if (gpio == GPIO('D', 0) || gpio == GPIO('D', 1)) + stm32f1_alternative_remap(AFIO_MAPR_CAN_REMAP_Msk, + AFIO_MAPR_CAN_REMAP_REMAP3); + } +} + +/**************************************************************** + * Startup + ****************************************************************/ + // Main entry point - called from armcm_boot.c:ResetHandler() void armcm_main(void) @@ -174,7 +217,7 @@ armcm_main(void) SystemInit(); SCB->VTOR = (uint32_t)VectorTable; - // Reset peripheral clocks + // Reset peripheral clocks (for some bootloaders that don't) RCC->AHBENR = 0x14; RCC->APB1ENR = 0; RCC->APB2ENR = 0; @@ -184,8 +227,13 @@ armcm_main(void) // Disable JTAG to free PA15, PB3, PB4 enable_pclock(AFIO_BASE); - stm32f1_alternative_remap(AFIO_MAPR_SWJ_CFG_Msk, - AFIO_MAPR_SWJ_CFG_JTAGDISABLE); + if (CONFIG_STM32F103GD_DISABLE_SWD) + // GigaDevice clone can't enable PA13/PA14 at runtime - enable here + stm32f1_alternative_remap(AFIO_MAPR_SWJ_CFG_Msk, + AFIO_MAPR_SWJ_CFG_DISABLE); + else + stm32f1_alternative_remap(AFIO_MAPR_SWJ_CFG_Msk, + AFIO_MAPR_SWJ_CFG_JTAGDISABLE); canboot_main(); } diff --git a/src/stm32/stm32f4.c b/src/stm32/stm32f4.c index 6efd32c..0a0da35 100644 --- a/src/stm32/stm32f4.c +++ b/src/stm32/stm32f4.c @@ -1,6 +1,6 @@ -// Code to setup clocks and gpio on stm32f2/stm32f4 +// Code to setup clocks on stm32f2/stm32f4 // -// Copyright (C) 2019 Kevin O'Connor +// Copyright (C) 2019-2021 Kevin O'Connor // // This file may be distributed under the terms of the GNU GPLv3 license. @@ -11,45 +11,34 @@ #include "internal.h" // enable_pclock #include "canboot_main.h" // sched_main -#define FREQ_PERIPH (CONFIG_CLOCK_FREQ / 4) + +/**************************************************************** + * Clock setup + ****************************************************************/ + +#define FREQ_PERIPH_DIV (CONFIG_MACH_STM32F401 ? 2 : 4) +#define FREQ_PERIPH (CONFIG_CLOCK_FREQ / FREQ_PERIPH_DIV) #define FREQ_USB 48000000 -// Enable a peripheral clock -void -enable_pclock(uint32_t periph_base) +// Map a peripheral address to its enable bits +struct cline +lookup_clock_line(uint32_t periph_base) { - if (periph_base < APB2PERIPH_BASE) { - uint32_t pos = (periph_base - APB1PERIPH_BASE) / 0x400; - RCC->APB1ENR |= (1<APB1ENR; - } else if (periph_base < AHB1PERIPH_BASE) { - uint32_t pos = (periph_base - APB2PERIPH_BASE) / 0x400; - RCC->APB2ENR |= (1<APB2ENR; - } else if (periph_base < AHB2PERIPH_BASE) { - uint32_t pos = (periph_base - AHB1PERIPH_BASE) / 0x400; - RCC->AHB1ENR |= (1<AHB1ENR; + if (periph_base >= AHB1PERIPH_BASE) { + uint32_t bit = 1 << ((periph_base - AHB1PERIPH_BASE) / 0x400); + return (struct cline){.en=&RCC->AHB1ENR, .rst=&RCC->AHB1RSTR, .bit=bit}; + } else if (periph_base >= APB2PERIPH_BASE) { + uint32_t bit = 1 << ((periph_base - APB2PERIPH_BASE) / 0x400); + if (bit & 0x700) + // Skip ADC peripheral reset as they share a bit + return (struct cline){.en=&RCC->APB2ENR, .bit=bit}; + return (struct cline){.en=&RCC->APB2ENR, .rst=&RCC->APB2RSTR, .bit=bit}; + } else { + uint32_t bit = 1 << ((periph_base - APB1PERIPH_BASE) / 0x400); + return (struct cline){.en=&RCC->APB1ENR, .rst=&RCC->APB1RSTR, .bit=bit}; } } -// Check if a peripheral clock has been enabled -int -is_enabled_pclock(uint32_t periph_base) -{ - if (periph_base < APB2PERIPH_BASE) { - uint32_t pos = (periph_base - APB1PERIPH_BASE) / 0x400; - return RCC->APB1ENR & (1<APB2ENR & (1<AHB1ENR & (1<AHB1ENR; } -// Set the mode and extended function of a pin -void -gpio_peripheral(uint32_t gpio, uint32_t mode, int pullup) -{ - GPIO_TypeDef *regs = digital_regs[GPIO2PORT(gpio)]; - - // Enable GPIO clock - gpio_clock_enable(regs); - - // Configure GPIO - uint32_t mode_bits = mode & 0xf, func = (mode >> 4) & 0xf, od = mode >> 8; - uint32_t pup = pullup ? (pullup > 0 ? 1 : 2) : 0; - uint32_t pos = gpio % 16, af_reg = pos / 8; - uint32_t af_shift = (pos % 8) * 4, af_msk = 0x0f << af_shift; - uint32_t m_shift = pos * 2, m_msk = 0x03 << m_shift; - - regs->AFR[af_reg] = (regs->AFR[af_reg] & ~af_msk) | (func << af_shift); - regs->MODER = (regs->MODER & ~m_msk) | (mode_bits << m_shift); - regs->PUPDR = (regs->PUPDR & ~m_msk) | (pup << m_shift); - regs->OTYPER = (regs->OTYPER & ~(1 << pos)) | (od << pos); - regs->OSPEEDR = (regs->OSPEEDR & ~m_msk) | (0x02 << m_shift); -} - -#define USB_BOOT_FLAG_ADDR (CONFIG_RAM_START + CONFIG_RAM_SIZE - 4096) -#define USB_BOOT_FLAG 0x55534220424f4f54 // "USB BOOT" - -// Handle USB reboot requests -void -usb_request_bootloader(void) -{ - irq_disable(); - if (CONFIG_STM32_FLASH_START_4000) { - // HID Bootloader - RCC->APB1ENR |= RCC_APB1ENR_PWREN; - RCC->APB1ENR; - PWR->CR |= PWR_CR_DBP; - // HID Bootloader magic key - RTC->BKP4R = 0x424C; - PWR->CR &= ~PWR_CR_DBP; - } else { - // System DFU Bootloader - *(uint64_t*)USB_BOOT_FLAG_ADDR = USB_BOOT_FLAG; - } - NVIC_SystemReset(); -} - // Clock configuration static void enable_clock_stm32f20x(void) @@ -138,8 +81,10 @@ enable_clock_stm32f20x(void) static void enable_clock_stm32f40x(void) { -#if CONFIG_MACH_STM32F405 || CONFIG_MACH_STM32F407 - uint32_t pll_base = 2000000, pll_freq = CONFIG_CLOCK_FREQ * 2, pllcfgr; +#if CONFIG_MACH_STM32F401 || CONFIG_MACH_STM32F4x5 + uint32_t pll_base = (CONFIG_STM32_CLOCK_REF_25M) ? 1000000 : 2000000; + uint32_t pllp = (CONFIG_MACH_STM32F401) ? 4 : 2; + uint32_t pll_freq = CONFIG_CLOCK_FREQ * pllp, pllcfgr; if (!CONFIG_STM32_CLOCK_REF_INTERNAL) { // Configure 168Mhz PLL from external crystal (HSE) uint32_t div = CONFIG_CLOCK_REF_FREQ / pll_base; @@ -151,7 +96,7 @@ enable_clock_stm32f40x(void) pllcfgr = RCC_PLLCFGR_PLLSRC_HSI | (div << RCC_PLLCFGR_PLLM_Pos); } RCC->PLLCFGR = (pllcfgr | ((pll_freq/pll_base) << RCC_PLLCFGR_PLLN_Pos) - | (0 << RCC_PLLCFGR_PLLP_Pos) + | (((pllp >> 1) - 1) << RCC_PLLCFGR_PLLP_Pos) | ((pll_freq/FREQ_USB) << RCC_PLLCFGR_PLLQ_Pos)); RCC->CR |= RCC_CR_PLLON; #endif @@ -213,7 +158,7 @@ clock_setup(void) // Configure and enable PLL if (CONFIG_MACH_STM32F207) enable_clock_stm32f20x(); - else if (CONFIG_MACH_STM32F405 || CONFIG_MACH_STM32F407) + else if (CONFIG_MACH_STM32F4x5) enable_clock_stm32f40x(); else enable_clock_stm32f446(); @@ -227,26 +172,32 @@ clock_setup(void) ; // Switch system clock to PLL - RCC->CFGR = RCC_CFGR_PPRE1_DIV4 | RCC_CFGR_PPRE2_DIV4 | RCC_CFGR_SW_PLL; + if (FREQ_PERIPH_DIV == 2) + RCC->CFGR = RCC_CFGR_PPRE1_DIV2 | RCC_CFGR_PPRE2_DIV2 | RCC_CFGR_SW_PLL; + else + RCC->CFGR = RCC_CFGR_PPRE1_DIV4 | RCC_CFGR_PPRE2_DIV4 | RCC_CFGR_SW_PLL; while ((RCC->CFGR & RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_PLL) ; } +/**************************************************************** + * Startup + ****************************************************************/ + // Main entry point - called from armcm_boot.c:ResetHandler() void armcm_main(void) { - if (CONFIG_USBSERIAL && *(uint64_t*)USB_BOOT_FLAG_ADDR == USB_BOOT_FLAG) { - *(uint64_t*)USB_BOOT_FLAG_ADDR = 0; - uint32_t *sysbase = (uint32_t*)0x1fff0000; - asm volatile("mov sp, %0\n bx %1" - : : "r"(sysbase[0]), "r"(sysbase[1])); - } - // Run SystemInit() and then restore VTOR SystemInit(); SCB->VTOR = (uint32_t)VectorTable; + // Reset peripheral clocks (for some bootloaders that don't) + RCC->AHB1ENR = 0x38000; + RCC->AHB2ENR = 0; + RCC->APB1ENR = 0; + RCC->APB2ENR = 0; + clock_setup(); sched_main();