From 45f068502df821fc6c280471e459c7c2409b252d Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Sun, 25 Jan 2026 11:38:34 +0100 Subject: [PATCH 1/2] [rcc] Move STM32F1 RCC to new API --- src/modm/board/black_pill_f103/board.hpp | 41 +- src/modm/board/blue_pill_f103/board.hpp | 41 +- src/modm/board/disco_f100rb/board.hpp | 35 +- src/modm/board/nucleo_f103rb/board.hpp | 34 +- src/modm/board/olimexino_stm32/board.hpp | 34 +- src/modm/platform/clock/stm32/module.lb | 2 +- src/modm/platform/clock/stm32/rcc_f1.hpp.in | 440 ++++++++++++++++++++ 7 files changed, 520 insertions(+), 107 deletions(-) create mode 100644 src/modm/platform/clock/stm32/rcc_f1.hpp.in diff --git a/src/modm/board/black_pill_f103/board.hpp b/src/modm/board/black_pill_f103/board.hpp index 63fd50037e..152496288a 100644 --- a/src/modm/board/black_pill_f103/board.hpp +++ b/src/modm/board/black_pill_f103/board.hpp @@ -27,7 +27,12 @@ using namespace modm::literals; /// STM32F103 running at 72MHz generated from the external 8MHz crystal struct SystemClock { - static constexpr uint32_t Frequency = 72_MHz; + static constexpr uint32_t Hse = 8_MHz; + static constexpr Rcc::PllConfig pll{.mul = 9, .usbdiv = Rcc::UsbPrescaler::Div1_5}; + static constexpr uint32_t Pll = Hse * pll.mul; + static constexpr uint32_t Frequency = Pll; + static_assert(Frequency == Rcc::MaxFrequency); + static constexpr uint32_t Ahb = Frequency; static constexpr uint32_t Apb1 = Frequency / 2; static constexpr uint32_t Apb2 = Frequency; @@ -56,42 +61,26 @@ struct SystemClock static constexpr uint32_t Timer3 = Apb1Timer; static constexpr uint32_t Timer4 = Apb1Timer; - static constexpr uint32_t Usb = Ahb / 1.5; + static constexpr uint32_t Usb = Ahb * 2 / 3; static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static constexpr uint32_t Rtc = 32.768_kHz; static bool inline enable() { - Rcc::enableLowSpeedExternalCrystal(); - Rcc::enableRealTimeClock(Rcc::RealTimeClockSource::LowSpeedExternalCrystal); - - Rcc::enableExternalCrystal(); - - // external clock * 9 = 72MHz, => 72/1.5 = 48 => good for USB - const Rcc::PllFactors pllFactors{ - .pllMul = 9, - .usbPrediv = Rcc::UsbPrescaler::Div1_5 - }; - Rcc::enablePll(Rcc::PllSource::ExternalCrystal, pllFactors); + Rcc::enableLseCrystal(); + Rcc::enableHseClock(); - // set flash latency for 72MHz Rcc::setFlashLatency(); + Rcc::updateCoreFrequency(); - // switch system clock to PLL output - Rcc::enableSystemClock(Rcc::SystemClockSource::Pll); - - // AHB has max 72MHz Rcc::setAhbPrescaler(Rcc::AhbPrescaler::Div1); + Rcc::setApb1Prescaler(Rcc::ApbPrescaler::Div2); + Rcc::setApb2Prescaler(Rcc::ApbPrescaler::Div1); - // APB1 has max. 36MHz - Rcc::setApb1Prescaler(Rcc::Apb1Prescaler::Div2); - - // APB2 has max. 72MHz - Rcc::setApb2Prescaler(Rcc::Apb2Prescaler::Div1); - - // update frequencies for busy-wait delay functions - Rcc::updateCoreFrequency(); + Rcc::enablePll(Rcc::PllSource::Hse, pll); + Rcc::enableSystemClock(Rcc::SystemClockSource::Pll); + Rcc::setRealTimeClockSource(Rcc::RealTimeClockSource::Lse); return true; } diff --git a/src/modm/board/blue_pill_f103/board.hpp b/src/modm/board/blue_pill_f103/board.hpp index 23636a3ecc..3912eb0284 100644 --- a/src/modm/board/blue_pill_f103/board.hpp +++ b/src/modm/board/blue_pill_f103/board.hpp @@ -31,7 +31,12 @@ using namespace modm::literals; /// STM32F103 running at 72MHz generated from the external 8MHz crystal struct SystemClock { - static constexpr uint32_t Frequency = 72_MHz; + static constexpr uint32_t Hse = 8_MHz; + static constexpr Rcc::PllConfig pll{.mul = 9, .usbdiv = Rcc::UsbPrescaler::Div1_5}; + static constexpr uint32_t Pll = Hse * pll.mul; + static constexpr uint32_t Frequency = Pll; + static_assert(Frequency == Rcc::MaxFrequency); + static constexpr uint32_t Ahb = Frequency; static constexpr uint32_t Apb1 = Frequency / 2; static constexpr uint32_t Apb2 = Frequency; @@ -60,42 +65,26 @@ struct SystemClock static constexpr uint32_t Timer3 = Apb1Timer; static constexpr uint32_t Timer4 = Apb1Timer; - static constexpr uint32_t Usb = Ahb / 1.5; + static constexpr uint32_t Usb = Ahb * 2 / 3; static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static constexpr uint32_t Rtc = 32.768_kHz; static bool inline enable() { - Rcc::enableLowSpeedExternalCrystal(); - Rcc::enableRealTimeClock(Rcc::RealTimeClockSource::LowSpeedExternalCrystal); - - Rcc::enableExternalCrystal(); - - // external clock * 9 = 72MHz, => 72/1.5 = 48 => good for USB - const Rcc::PllFactors pllFactors{ - .pllMul = 9, - .usbPrediv = Rcc::UsbPrescaler::Div1_5 - }; - Rcc::enablePll(Rcc::PllSource::ExternalCrystal, pllFactors); + Rcc::enableLseCrystal(); + Rcc::enableHseClock(); - // set flash latency for 72MHz Rcc::setFlashLatency(); + Rcc::updateCoreFrequency(); - // switch system clock to PLL output - Rcc::enableSystemClock(Rcc::SystemClockSource::Pll); - - // AHB has max 72MHz Rcc::setAhbPrescaler(Rcc::AhbPrescaler::Div1); + Rcc::setApb1Prescaler(Rcc::ApbPrescaler::Div2); + Rcc::setApb2Prescaler(Rcc::ApbPrescaler::Div1); - // APB1 has max. 36MHz - Rcc::setApb1Prescaler(Rcc::Apb1Prescaler::Div2); - - // APB2 has max. 72MHz - Rcc::setApb2Prescaler(Rcc::Apb2Prescaler::Div1); - - // update frequencies for busy-wait delay functions - Rcc::updateCoreFrequency(); + Rcc::enablePll(Rcc::PllSource::Hse, pll); + Rcc::enableSystemClock(Rcc::SystemClockSource::Pll); + Rcc::setRealTimeClockSource(Rcc::RealTimeClockSource::Lse); return true; } diff --git a/src/modm/board/disco_f100rb/board.hpp b/src/modm/board/disco_f100rb/board.hpp index 60decf626a..3d728a64d1 100644 --- a/src/modm/board/disco_f100rb/board.hpp +++ b/src/modm/board/disco_f100rb/board.hpp @@ -32,7 +32,12 @@ using namespace modm::literals; /// supplied by the on-board st-link struct SystemClock { - static constexpr uint32_t Frequency = 24_MHz; + static constexpr uint32_t Hse = 8_MHz; + static constexpr Rcc::PllConfig pll{.mul = 3}; + static constexpr uint32_t Pll = Hse * pll.mul / pll.prediv1; + static constexpr uint32_t Frequency = Pll; + static_assert(Frequency == Rcc::MaxFrequency); + static constexpr uint32_t Ahb = Frequency; static constexpr uint32_t Apb1 = Frequency; static constexpr uint32_t Apb2 = Frequency; @@ -77,26 +82,20 @@ struct SystemClock static bool inline enable() { - Rcc::enableLowSpeedExternalCrystal(); - Rcc::enableRealTimeClock(Rcc::RealTimeClockSource::LowSpeedExternalCrystal); - - Rcc::enableExternalCrystal(); // 8MHz - const Rcc::PllFactors pllFactors{ - .pllMul = 3, - .pllPrediv = 1 - }; - Rcc::enablePll(Rcc::PllSource::ExternalCrystal, pllFactors); - // set flash latency for 24MHz + Rcc::enableLseCrystal(); + Rcc::enableHseClock(); + Rcc::setFlashLatency(); - // switch system clock to PLL output - Rcc::enableSystemClock(Rcc::SystemClockSource::Pll); - Rcc::setAhbPrescaler(Rcc::AhbPrescaler::Div1); - // APB1 has max. 24MHz - Rcc::setApb1Prescaler(Rcc::Apb1Prescaler::Div1); - Rcc::setApb2Prescaler(Rcc::Apb2Prescaler::Div1); - // update frequencies for busy-wait delay functions Rcc::updateCoreFrequency(); + Rcc::setAhbPrescaler(Rcc::AhbPrescaler::Div1); + Rcc::setApb1Prescaler(Rcc::ApbPrescaler::Div1); + Rcc::setApb2Prescaler(Rcc::ApbPrescaler::Div1); + + Rcc::enablePll(Rcc::PllSource::Hse, pll); + Rcc::enableSystemClock(Rcc::SystemClockSource::Pll); + Rcc::setRealTimeClockSource(Rcc::RealTimeClockSource::Lse); + return true; } }; diff --git a/src/modm/board/nucleo_f103rb/board.hpp b/src/modm/board/nucleo_f103rb/board.hpp index ed73766f07..8529a777d3 100644 --- a/src/modm/board/nucleo_f103rb/board.hpp +++ b/src/modm/board/nucleo_f103rb/board.hpp @@ -30,7 +30,11 @@ using namespace modm::literals; /// STM32F103RB running at 64MHz generated from the internal 8MHz crystal struct SystemClock { - static constexpr uint32_t Frequency = 64_MHz; + static constexpr Rcc::PllConfig pll{.mul = 16}; + static constexpr uint32_t Pll = (Rcc::HsiFrequency / 2) * pll.mul; + static_assert(Pll == 64_MHz); + static constexpr uint32_t Frequency = Pll; + static constexpr uint32_t Ahb = Frequency; static constexpr uint32_t Apb1 = Frequency / 2; static constexpr uint32_t Apb2 = Frequency; @@ -68,26 +72,20 @@ struct SystemClock static bool inline enable() { - Rcc::enableLowSpeedInternalClock(); - Rcc::enableRealTimeClock(Rcc::RealTimeClockSource::Lsi); - - Rcc::enableInternalClock(); // 8MHz - // internal clock / 2 * 16 = 64MHz, => 64/1.5 = 42.6 => bad for USB - const Rcc::PllFactors pllFactors{ - .pllMul = 16, - }; - Rcc::enablePll(Rcc::PllSource::InternalClock, pllFactors); - // set flash latency for 64MHz + Rcc::enableLsiClock(); + Rcc::enableHsiClock(); + Rcc::setFlashLatency(); - // switch system clock to PLL output - Rcc::enableSystemClock(Rcc::SystemClockSource::Pll); - Rcc::setAhbPrescaler(Rcc::AhbPrescaler::Div1); - // APB1 has max. 36MHz - Rcc::setApb1Prescaler(Rcc::Apb1Prescaler::Div2); - Rcc::setApb2Prescaler(Rcc::Apb2Prescaler::Div1); - // update frequencies for busy-wait delay functions Rcc::updateCoreFrequency(); + Rcc::setAhbPrescaler(Rcc::AhbPrescaler::Div1); + Rcc::setApb1Prescaler(Rcc::ApbPrescaler::Div2); + Rcc::setApb2Prescaler(Rcc::ApbPrescaler::Div1); + + Rcc::enablePll(Rcc::PllSource::HsiDiv2, pll); + Rcc::enableSystemClock(Rcc::SystemClockSource::Pll); + Rcc::setRealTimeClockSource(Rcc::RealTimeClockSource::Lsi); + return true; } }; diff --git a/src/modm/board/olimexino_stm32/board.hpp b/src/modm/board/olimexino_stm32/board.hpp index 5397cec539..df83d91ff8 100644 --- a/src/modm/board/olimexino_stm32/board.hpp +++ b/src/modm/board/olimexino_stm32/board.hpp @@ -28,7 +28,11 @@ using namespace modm::literals; /// STM32F103RB running at 64MHz generated from the internal 8MHz crystal struct SystemClock { - static constexpr uint32_t Frequency = 64_MHz; + static constexpr Rcc::PllConfig pll{.mul = 16}; + static constexpr uint32_t Pll = (Rcc::HsiFrequency / 2) * pll.mul; + static_assert(Pll == 64_MHz); + static constexpr uint32_t Frequency = Pll; + static constexpr uint32_t Ahb = Frequency; static constexpr uint32_t Apb1 = Frequency / 2; static constexpr uint32_t Apb2 = Frequency; @@ -68,26 +72,20 @@ struct SystemClock static bool inline enable() { - Rcc::enableLowSpeedExternalCrystal(); - Rcc::enableRealTimeClock(Rcc::RealTimeClockSource::LowSpeedExternalCrystal); - - Rcc::enableInternalClock(); // 8MHz - // internal clock / 2 * 16 = 64MHz, => 64/1.5 = 42.6 => bad for USB - const Rcc::PllFactors pllFactors{ - .pllMul = 16, - }; - Rcc::enablePll(Rcc::PllSource::InternalClock, pllFactors); - // set flash latency for 64MHz + Rcc::enableLseCrystal(); + Rcc::enableHsiClock(); + Rcc::setFlashLatency(); - // switch system clock to PLL output - Rcc::enableSystemClock(Rcc::SystemClockSource::Pll); - Rcc::setAhbPrescaler(Rcc::AhbPrescaler::Div1); - // APB1 has max. 36MHz - Rcc::setApb1Prescaler(Rcc::Apb1Prescaler::Div2); - Rcc::setApb2Prescaler(Rcc::Apb2Prescaler::Div1); - // update frequencies for busy-wait delay functions Rcc::updateCoreFrequency(); + Rcc::setAhbPrescaler(Rcc::AhbPrescaler::Div1); + Rcc::setApb1Prescaler(Rcc::ApbPrescaler::Div2); + Rcc::setApb2Prescaler(Rcc::ApbPrescaler::Div1); + + Rcc::enablePll(Rcc::PllSource::HsiDiv2, pll); + Rcc::enableSystemClock(Rcc::SystemClockSource::Pll); + Rcc::setRealTimeClockSource(Rcc::RealTimeClockSource::Lse); + return true; } }; diff --git a/src/modm/platform/clock/stm32/module.lb b/src/modm/platform/clock/stm32/module.lb index 2cd0e99064..4651653aba 100644 --- a/src/modm/platform/clock/stm32/module.lb +++ b/src/modm/platform/clock/stm32/module.lb @@ -146,7 +146,7 @@ def build(env): ids += device.get_driver(driver)["instance"] return list(map(int, ids)) - if t.family in ["h5", "u0", "g0", "u3", "c0", "f0", "l0"]: + if t.family in ["h5", "u0", "g0", "u3", "c0", "f0", "l0", "f1"]: p["uart_ids"] = instances("usart", "uart") p["lpuart_ids"] = instances("lpuart") p["spi_ids"] = instances("spi") diff --git a/src/modm/platform/clock/stm32/rcc_f1.hpp.in b/src/modm/platform/clock/stm32/rcc_f1.hpp.in new file mode 100644 index 0000000000..eb1ade1ca7 --- /dev/null +++ b/src/modm/platform/clock/stm32/rcc_f1.hpp.in @@ -0,0 +1,440 @@ +/* + * Copyright (c) 2026, Niklas Hauser + * + * This file is part of the modm project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +// ---------------------------------------------------------------------------- + +#pragma once + +#include +#include "../device.hpp" +#include +#include +#include + +namespace modm::platform +{ + +/** + * Reset and Clock Control for STM32F1 devices. + * + * This class abstracts access to clock settings on the STM32. + * You need to use this class to enable internal and external clock + * sources & outputs, set PLL parameters and AHB & APB prescalers. + * Don't forget to set the flash latencies. + * + * @author Niklas Hauser + * @ingroup modm_platform_rcc + */ +class Rcc +{ +public: + static constexpr uint32_t LsiFrequency = 40'000; + static constexpr uint32_t HsiFrequency = 8'000'000; + static constexpr uint32_t BootFrequency = HsiFrequency; + static constexpr uint32_t MaxFrequency = {{ max_frequency | modm.digsep }}; + + /// Connect GPIO signals like MCO to the clock tree + template< class... Signals > + static void + connect() + { + using Connector = GpioConnector; + Connector::connect(); + } + + /// Enable the clock for a peripheral + template< Peripheral peripheral > + static void + enable(); + + /// Check if a peripheral clock is enabled + template< Peripheral peripheral > + static bool + isEnabled(); + + /// Disable the clock for a peripheral + template< Peripheral peripheral > + static void + disable(); + + +public: + /** Set flash latency for CPU frequency and voltage. + * Does nothing if CPU frequency is too high for the available + * voltage. + * + * @returns maximum CPU frequency for voltage. + * @retval <=CPU_Frequency flash latency has been set correctly. + * @retval >CPU_Frequency requested frequency too high for voltage. + */ + template< uint32_t Core_Hz, uint16_t Core_mV = 3300> + static uint32_t + setFlashLatency(); + + /// Update the SystemCoreClock and delay variables. + template< uint32_t Core_Hz > + static void + updateCoreFrequency(); + + +public: + // clock sources + static inline bool + enableHsiClock(uint32_t waitLoops = 0x10000) + { + RCC->CR |= RCC_CR_HSION; + while (not (RCC->CR & RCC_CR_HSIRDY) and --waitLoops) ; + return waitLoops; + } + static inline bool + enableHseClock(uint32_t waitLoops = 0x10000) + { + RCC->CR |= RCC_CR_HSEBYP | RCC_CR_HSEON; + while (not (RCC->CR & RCC_CR_HSERDY) and --waitLoops) ; + return waitLoops; + } + + static inline bool + enableHseCrystal(uint32_t waitLoops = 0x10000) + { + RCC->CR = (RCC->CR & ~RCC_CR_HSEBYP) | RCC_CR_HSEON; + while (not (RCC->CR & RCC_CR_HSERDY) and --waitLoops) ; + return waitLoops; + } + + static inline bool + enableLsiClock(uint32_t waitLoops = 0x10000) + { + RCC->CSR |= RCC_CSR_LSION; + while (not (RCC->CSR & RCC_CSR_LSIRDY) and --waitLoops) ; + return waitLoops; + } + + static inline bool + enableLseClock(uint32_t waitLoops = 0x10000) + { + RCC->BDCR |= RCC_BDCR_LSEBYP | RCC_BDCR_LSEON; + while (not (RCC->BDCR & RCC_BDCR_LSERDY) and --waitLoops) ; + return waitLoops; + } + + static inline bool + enableLseCrystal(uint32_t waitLoops = 0x10000) + { + RCC->BDCR = (RCC->BDCR & ~RCC_BDCR_LSEBYP) | RCC_BDCR_LSEON; + while (not (RCC->BDCR & RCC_BDCR_LSERDY) and --waitLoops) ; + return waitLoops; + } + + // clock modifiers +%% set with_connectivity = target.name in ["05", "07"] +%% if with_connectivity + enum class + PllMultiplier : uint8_t + { + Mul4 = 2, + Mul5 = 3, + Mul6 = 4, + Mul6_5 = 13, + Mul7 = 5, + Mul8 = 6, + Mul9 = 7, + }; +%% endif + enum class + PllSource : uint32_t + { + HsiDiv2 = 0, + Hse = RCC_CFGR_PLLSRC, + HseDiv2 = RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE, +%% if with_connectivity + Pll2 = RCC_CFGR_PLLSRC | 1, +%% endif + }; +%% set with_usb = target.name in ["02", "03"] +%% if with_usb + enum class + UsbPrescaler : uint8_t + { + Div1_5, + Div1, + }; +%% elif with_connectivity + enum class + UsbPrescaler : uint8_t + { + Div3, + Div2, + }; +%% endif + struct PllConfig + { +%% set with_prediv1 = target.name in ["00", "05", "07"] +%% if with_prediv1 + uint8_t prediv1 = 1; ///< PREDIV1 division factor: 1-16 +%% endif +%% if with_connectivity + PllMultiplier mul; ///< Multiplication factor 4-9 +%% else + uint8_t mul; ///< Multiplication factor 2-16 +%% endif +%% if with_usb + UsbPrescaler usbdiv = UsbPrescaler::Div1_5; +%% elif with_connectivity + UsbPrescaler usbdiv = UsbPrescaler::Div3; +%% endif + }; + /// Configure and enable the PLL + static inline bool + enablePll(PllSource src, const PllConfig& cfg, uint32_t waitLoops = 0x10000) + { +%% if with_usb + RCC->CFGR = (RCC->CFGR & ~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL | RCC_CFGR_USBPRE)) | + ((cfg.usbdiv == UsbPrescaler::Div1) ? RCC_CFGR_USBPRE : 0) | +%% elif with_connectivity + RCC->CFGR = (RCC->CFGR & ~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL | RCC_CFGR_OTGFSPRE)) | + ((cfg.usbdiv == UsbPrescaler::Div2) ? RCC_CFGR_OTGFSPRE : 0) | +%% else + RCC->CFGR = (RCC->CFGR & ~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL)) | +%% endif +%% if with_connectivity + ((uint32_t(cfg.mul) << RCC_CFGR_PLLMULL_Pos) & RCC_CFGR_PLLMULL) | +%% else + (((cfg.mul - 2) << RCC_CFGR_PLLMULL_Pos) & RCC_CFGR_PLLMULL) | +%% endif + (uint32_t(src) & (RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE)); +%% if with_connectivity + RCC->CFGR2 = (RCC->CFGR2 & ~(RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC)) | + (uint32_t(cfg.prediv1 - 1) & RCC_CFGR2_PREDIV1_Msk) | + ((src == PllSource::Pll2) ? RCC_CFGR2_PREDIV1SRC : 0); +%% elif with_prediv1 + RCC->CFGR2 = (RCC->CFGR2 & ~RCC_CFGR2_PREDIV1) | (uint32_t(cfg.prediv1 - 1) & RCC_CFGR2_PREDIV1_Msk); +%% endif +%# + RCC->CR |= RCC_CR_PLLON; + while (not (RCC->CR & RCC_CR_PLLRDY) and --waitLoops) ; + return waitLoops; + } + /// Disable PLL + static inline bool + disablePll(uint32_t waitLoops = 0x10000) + { + RCC->CR &= ~RCC_CR_PLLON; + while ((RCC->CR & RCC_CR_PLLRDY) and --waitLoops) ; + return waitLoops; + } +%% set with_connectivity = target.name in ["05", "07"] +%% if with_connectivity +%# + enum class + Pll23Multiplier : uint8_t + { + Disabled = 0, + Mul8 = 6, + Mul9 = 7, + Mul10 = 8, + Mul11 = 9, + Mul12 = 10, + Mul13 = 11, + Mul14 = 12, + Mul16 = 14, + Mul20 = 15, + }; + static constexpr uint8_t + value(Pll23Multiplier mul) + { + if (mul == Pll23Multiplier::Disabled) return 0u; + if (mul == Pll23Multiplier::Mul20) return 20u; + return static_cast(mul) + 2u; + } + struct Pll23Config + { + uint8_t prediv2 = 1; ///< PREDIV2 division factor: 1-16 (value line and connectivity line) + Pll23Multiplier mul2 = Pll23Multiplier::Disabled; ///< Multiplication factor 8-20 + Pll23Multiplier mul3 = Pll23Multiplier::Disabled; ///< Multiplication factor 8-20 + }; + /// Configure and enable PLL2 and PLL3 + static inline bool + enablePll23(const Pll23Config &cfg, uint32_t waitLoops = 0x10000) + { + RCC->CFGR2 = (RCC->CFGR2 & ~(RCC_CFGR2_PLL2MUL | RCC_CFGR2_PLL3MUL | RCC_CFGR2_PREDIV2)) | + ((uint32_t(cfg.mul2) << RCC_CFGR2_PLL2MUL_Pos) & RCC_CFGR2_PLL2MUL) | + ((uint32_t(cfg.mul3) << RCC_CFGR2_PLL3MUL_Pos) & RCC_CFGR2_PLL3MUL) | + (((cfg.prediv2 - 1) << RCC_CFGR2_PREDIV2_Pos) & RCC_CFGR2_PREDIV2); + + uint32_t cr{}; + if (cfg.mul2 != Pll23Multiplier::Disabled) cr |= RCC_CR_PLL2ON; + if (cfg.mul3 != Pll23Multiplier::Disabled) cr |= RCC_CR_PLL3ON; + RCC->CR = (RCC->CR & ~cr) | cr; + cr <<= 1; // shift to PLLxRDY position + while (((RCC->CR & cr) != cr) and --waitLoops) ; + return waitLoops; + } + static inline bool + disablePll2(uint32_t waitLoops = 0x10000) + { + RCC->CR &= ~RCC_CR_PLL2ON; + while ((RCC->CR & RCC_CR_PLL2RDY) and --waitLoops) ; + return waitLoops; + } + static inline bool + disablePll3(uint32_t waitLoops = 0x10000) + { + RCC->CR &= ~RCC_CR_PLL3ON; + while ((RCC->CR & RCC_CR_PLL3RDY) and --waitLoops) ; + return waitLoops; + } +%% endif +%# + enum class + AhbPrescaler : uint8_t + { + Div1 = 0b0000, + Div2 = 0b1000, + Div4 = 0b1001, + Div8 = 0b1010, + Div16 = 0b1011, + Div64 = 0b1100, + Div128 = 0b1101, + Div256 = 0b1110, + Div512 = 0b1111, + }; + static inline void + setAhbPrescaler(AhbPrescaler prescaler) + { + RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_HPRE) | (uint32_t(prescaler) << RCC_CFGR_HPRE_Pos); + } + + enum class + ApbPrescaler : uint8_t + { + Div1 = 0b000, + Div2 = 0b100, + Div4 = 0b101, + Div8 = 0b110, + Div16 = 0b111 + }; + static inline void + setApb1Prescaler(ApbPrescaler prescaler) + { + RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_PPRE1) | (uint32_t(prescaler) << RCC_CFGR_PPRE1_Pos); + } + static inline void + setApb2Prescaler(ApbPrescaler prescaler) + { + RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_PPRE2) | (uint32_t(prescaler) << RCC_CFGR_PPRE2_Pos); + } + + // clock sinks + enum class + SystemClockSource : uint32_t + { + Hsi = 0b00, + Hse = 0b01, + Pll = 0b10, + }; + static inline bool + enableSystemClock(SystemClockSource src, uint32_t waitLoops = 0x10000) + { + RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_SW) | uint32_t(src); + // Wait till the main clock source is switched + while ((RCC->CFGR & RCC_CFGR_SWS) != (uint32_t(src) << RCC_CFGR_SWS_Pos) and --waitLoops) ; + return waitLoops; + } + + enum class + RealTimeClockSource : uint8_t + { + Disabled = 0, + Lse = 0b01, + Lsi = 0b10, + Hse = 0b11, + }; + static inline void + setRealTimeClockSource(RealTimeClockSource src) + { + RCC->BDCR = (RCC->BDCR & ~RCC_BDCR_RTCSEL) | RCC_BDCR_RTCEN | (uint32_t(src) << RCC_BDCR_RTCSEL_Pos); + } + + // ADC prescaler + enum class + AdcPrescaler : uint8_t + { + Div2 = 0b00, + Div4 = 0b01, + Div6 = 0b10, + Div8 = 0b11, + }; + static inline void + setAdcPrescaler(AdcPrescaler prescaler) + { + RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_ADCPRE) | (uint32_t(prescaler) << RCC_CFGR_ADCPRE_Pos); + } +%% if with_connectivity +%# + // I2S clock sources (connectivity line) + enum class + I2s2ClockSource : uint8_t + { + SysClk, ///< System clock + Pll3, ///< PLL3 VCO + }; + static inline void + setI2s2ClockSource(I2s2ClockSource src) + { + if (src == I2s2ClockSource::Pll3) + RCC->CFGR2 |= RCC_CFGR2_I2S2SRC; + else + RCC->CFGR2 &= ~RCC_CFGR2_I2S2SRC; + } + + enum class + I2s3ClockSource : uint8_t + { + SysClk, ///< System clock + Pll3, ///< PLL3 VCO + }; + static inline void + setI2s3ClockSource(I2s3ClockSource src) + { + if (src == I2s3ClockSource::Pll3) + RCC->CFGR2 |= RCC_CFGR2_I2S3SRC; + else + RCC->CFGR2 &= ~RCC_CFGR2_I2S3SRC; + } +%% endif +%# + enum class + McoClockSource : uint8_t + { + Disabled = 0b000, + SysClk = 0b100, + Hsi = 0b101, + Hse = 0b110, + PllDiv2 = 0b111, + }; + static inline void + setMcoClockSource(McoClockSource src) + { + RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_MCO) | (uint32_t(src) << RCC_CFGR_MCO_Pos); + } + +private: + struct flash_latency + { + uint32_t latency; + uint32_t max_frequency; + }; + static constexpr flash_latency + computeFlashLatency(uint32_t Core_Hz, uint16_t Core_mV); +}; + +} // namespace modm::platform + +#include "rcc_impl.hpp" From 18781ebe50118c633e023ef4b3b54113507aea5e Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Sun, 25 Jan 2026 15:45:14 +0100 Subject: [PATCH 2/2] [ci] Fix Windows CI ARM GCC download --- .github/workflows/windows.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 86f14b48d6..9f16481978 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -47,13 +47,14 @@ jobs: # Invoke-WebRequest -OutFile gcc-win64.zip https://github.com/brechtsanders/winlibs_mingw/releases/download/14.2.0posix-19.1.7-12.0.0-msvcrt-r3/winlibs-x86_64-posix-seh-gcc-14.2.0-mingw-w64msvcrt-12.0.0-r3.zip # [System.IO.Compression.ZipFile]::ExtractToDirectory("gcc-win64.zip", "C:\") # } + # We had to cache the ARM GCC zip file in an unrelated release due to the download servers blocking us from time to time - name: Download and Unzip GCCs shell: powershell run: | $ProgressPreference = 'SilentlyContinue' Start-Job { Set-Location $using:PWD - Invoke-WebRequest -OutFile gcc-arm-none-eabi-win64-14.zip https://developer.arm.com/-/media/Files/downloads/gnu/14.2.rel1/binrel/arm-gnu-toolchain-14.2.rel1-mingw-w64-x86_64-arm-none-eabi.zip + Invoke-WebRequest -OutFile gcc-arm-none-eabi-win64-14.zip https://github.com/modm-io/avr-gcc/releases/download/v14.2.0/arm-gnu-toolchain-14.2.rel1-mingw-w64-x86_64-arm-none-eabi.zip New-Item -Path "C:\" -Name "arm-none-eabi-14" -ItemType "Directory" Expand-Archive -Path gcc-arm-none-eabi-win64-14.zip -DestinationPath C:\arm-none-eabi-14 -Force Remove-Item gcc-arm-none-eabi-win64-14.zip