diff --git a/src/modm/board/blue_pill_f103/board.hpp b/src/modm/board/blue_pill_f103/board.hpp index dcd053c20c..020738696d 100644 --- a/src/modm/board/blue_pill_f103/board.hpp +++ b/src/modm/board/blue_pill_f103/board.hpp @@ -10,12 +10,13 @@ */ // ---------------------------------------------------------------------------- -#ifndef MODM_STM32_F103C8T6_BLUE_PILL_HPP -#define MODM_STM32_F103C8T6_BLUE_PILL_HPP +#pragma once #include #include +#include "rcc_prototype.hpp" + using namespace modm::platform; namespace Board @@ -24,13 +25,44 @@ namespace Board /// @{ 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 Ahb = Frequency; - static constexpr uint32_t Apb1 = Frequency / 2; - static constexpr uint32_t Apb2 = Frequency; + // static constexpr uint32_t ExternalLSEclock = ; + static constexpr uint32_t ExternalHSEclock = 8_MHz; + + static constexpr Rcc::PllFactors pllFactors{ + .pllMul = 9, + .usbPrediv = Rcc::UsbPrescaler::Div1_5 + }; + static constexpr Rcc::AhbPrescaler Ahb_prescaler = Rcc::AhbPrescaler::Div1; + static constexpr Rcc::Apb1Prescaler Apb1_prescaler = Rcc::Apb1Prescaler::Div2; + static constexpr Rcc::Apb2Prescaler Apb2_prescaler = Rcc::Apb2Prescaler::Div1; + + // ------------------------------------------ + + static constexpr int HsePredivision = 1; + static constexpr int PllClock = ExternalHSEclock / HsePredivision * pllFactors.pllMul; // 72 Mhz + + // System Clock MUX + static constexpr uint32_t Clock = PllClock; + static_assert(Clock <= 72_MHz, "Clock has max. 72MHz!"); + + static constexpr uint32_t Ahb = Clock / RccProto::prescalerToValue(); + static_assert(Ahb <= 72_MHz, "Ahb has max. 72MHz!"); + + static constexpr uint32_t Apb1 = Ahb / RccProto::prescalerToValue(); + static_assert(Apb1 <= 36_MHz, "Apb1 has max. 36MHz!"); + + static constexpr uint32_t Apb2 = Ahb / RccProto::prescalerToValue(); + static_assert(Apb2 <= 72_MHz, "Apb2 has max. 72MHz!"); + + // @todo is this correct? + static constexpr uint32_t Apb1Timer = Apb1 * (RccProto::prescalerToValue() == 1 ? 1 : 2); + static constexpr uint32_t Apb2Timer = Apb2 * (RccProto::prescalerToValue() == 1 ? 1 : 2); + + // ------------------------------------------ + + static constexpr uint32_t Frequency = Ahb; static constexpr uint32_t Adc = Apb2; @@ -49,26 +81,18 @@ struct SystemClock static constexpr uint32_t I2c1 = Apb1; static constexpr uint32_t I2c2 = Apb1; - static constexpr uint32_t Apb1Timer = Apb1 * 2; - static constexpr uint32_t Apb2Timer = Apb2 * 1; static constexpr uint32_t Timer1 = Apb2Timer; static constexpr uint32_t Timer2 = Apb1Timer; 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 / RccProto::prescalerToValue(); // 48 MHz! static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() { 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); // set flash latency for 72MHz @@ -76,15 +100,9 @@ struct SystemClock // switch system clock to PLL output Rcc::enableSystemClock(Rcc::SystemClockSource::Pll); - - // AHB has max 72MHz - Rcc::setAhbPrescaler(Rcc::AhbPrescaler::Div1); - - // APB1 has max. 36MHz - Rcc::setApb1Prescaler(Rcc::Apb1Prescaler::Div2); - - // APB2 has max. 72MHz - Rcc::setApb2Prescaler(Rcc::Apb2Prescaler::Div1); + Rcc::setAhbPrescaler(Ahb_prescaler); + Rcc::setApb1Prescaler(Apb1_prescaler); + Rcc::setApb2Prescaler(Apb2_prescaler); // update frequencies for busy-wait delay functions Rcc::updateCoreFrequency(); @@ -129,5 +147,3 @@ initializeUsbFs(uint8_t priority=3) /// @} } // Board namespace - -#endif // MODM_STM32_F103C8T6_BLUE_PILL_HPP diff --git a/src/modm/board/blue_pill_f103/rcc_prototype.hpp b/src/modm/board/blue_pill_f103/rcc_prototype.hpp new file mode 100644 index 0000000000..fea31c8a08 --- /dev/null +++ b/src/modm/board/blue_pill_f103/rcc_prototype.hpp @@ -0,0 +1,70 @@ +#pragma once + +#include + +namespace modm::platform +{ + +// @todo integrate with /platform/clock/stm32/rcc.hpp.in +class RccProto +{ +public: + template + static consteval int + prescalerToValue() + { + switch (Prescaler) + { + case Rcc::AhbPrescaler::Div1: return 1; + case Rcc::AhbPrescaler::Div2: return 2; + case Rcc::AhbPrescaler::Div4: return 4; + case Rcc::AhbPrescaler::Div8: return 8; + case Rcc::AhbPrescaler::Div16: return 16; + case Rcc::AhbPrescaler::Div64: return 64; + case Rcc::AhbPrescaler::Div128: return 128; + case Rcc::AhbPrescaler::Div256: return 256; + case Rcc::AhbPrescaler::Div512: return 512; + }; + } + + template + static consteval int + prescalerToValue() + { + switch (Prescaler) + { + case Rcc::Apb1Prescaler::Div1: return 1; + case Rcc::Apb1Prescaler::Div2: return 2; + case Rcc::Apb1Prescaler::Div4: return 4; + case Rcc::Apb1Prescaler::Div8: return 8; + case Rcc::Apb1Prescaler::Div16: return 16; + }; + } + + template + static consteval int + prescalerToValue() + { + switch (Prescaler) + { + case Rcc::Apb2Prescaler::Div1: return 1; + case Rcc::Apb2Prescaler::Div2: return 2; + case Rcc::Apb2Prescaler::Div4: return 4; + case Rcc::Apb2Prescaler::Div8: return 8; + case Rcc::Apb2Prescaler::Div16: return 16; + } + } + + template + static consteval float + prescalerToValue() + { + switch (Prescaler) + { + case Rcc::UsbPrescaler::Div1: return 1; + case Rcc::UsbPrescaler::Div1_5: return 1.5; + } + } +}; + +} // namespace modm::platform diff --git a/src/modm/board/disco_f411ve/board.hpp b/src/modm/board/disco_f411ve/board.hpp index 0e4b470a2b..50bfeead33 100644 --- a/src/modm/board/disco_f411ve/board.hpp +++ b/src/modm/board/disco_f411ve/board.hpp @@ -14,6 +14,8 @@ #include #include +#include "rcc_prototype.hpp" + using namespace modm::platform; namespace Board @@ -22,13 +24,53 @@ namespace Board /// @{ using namespace modm::literals; -/// STM32F411 running at 96MHz generated from the external 8MHz crystal + struct SystemClock { - static constexpr uint32_t Frequency = 96_MHz; - static constexpr uint32_t Ahb = Frequency; - static constexpr uint32_t Apb1 = Frequency / 2; - static constexpr uint32_t Apb2 = Frequency; + // static constexpr uint32_t ExternalLSEclock = ; + static constexpr uint32_t ExternalHSEclock = 8_MHz; + + static constexpr Rcc::PllFactors pllFactors{ + .pllM = 8, + .pllN = 336, + .pllP = 4, + .pllQ = 7, + }; + static constexpr Rcc::AhbPrescaler Ahb_prescaler = Rcc::AhbPrescaler::Div1; + static constexpr Rcc::Apb1Prescaler Apb1_prescaler = Rcc::Apb1Prescaler::Div2; + static constexpr Rcc::Apb2Prescaler Apb2_prescaler = Rcc::Apb2Prescaler::Div1; + + // ------------------------------------------ + + static constexpr int HsePredivision = 1; + static constexpr uint32_t PllClock = ExternalHSEclock / HsePredivision / pllFactors.pllM * pllFactors.pllN; + + static constexpr uint32_t Clock = PllClock / pllFactors.pllP; // 96_Mhz + static_assert(Clock <= 100_MHz, "Clock has max. 100MHz!"); + + static constexpr uint32_t Ahb = Clock / RccProto::prescalerToValue(); + static_assert(Ahb <= 100_MHz, "Ahb has max. 100MHz!"); + + static constexpr uint32_t Apb1 = Ahb / RccProto::prescalerToValue(); + static_assert(Apb1 <= 50_MHz, "Apb1 has max. 50MHz!"); + + static constexpr uint32_t Apb2 = Ahb / RccProto::prescalerToValue(); + static_assert(Apb2 <= 100_MHz, "Apb2 has max. 100MHz!"); + + // @todo is this correct? + // prescaler is one ? -> multiply by one, otherwise multiply by two + static constexpr uint32_t Apb1Timer = Apb1 * (RccProto::prescalerToValue() == 1 ? 1 : 2); + static constexpr uint32_t Apb2Timer = Apb2 * (RccProto::prescalerToValue() == 1 ? 1 : 2); + + // static_assert(Ahb == 84_MHz, "Wrong"); + // static_assert(Apb1 == 42_MHz, "Wrong"); + // static_assert(Apb2 == 84_MHz, "Wrong"); + // static_assert(Apb1Timer == 84_MHz, "Wrong"); + // static_assert(Apb2Timer == 84_MHz, "Wrong"); + + // ------------------------------------------ + + static constexpr uint32_t Frequency = Ahb; static constexpr uint32_t Adc = Apb2; @@ -51,8 +93,6 @@ struct SystemClock static constexpr uint32_t I2c2 = Apb1; static constexpr uint32_t I2c3 = Apb1; - static constexpr uint32_t Apb1Timer = Apb1 * 2; - static constexpr uint32_t Apb2Timer = Apb2 * 2; static constexpr uint32_t Timer1 = Apb2Timer; static constexpr uint32_t Timer2 = Apb1Timer; static constexpr uint32_t Timer3 = Apb1Timer; @@ -62,27 +102,20 @@ struct SystemClock static constexpr uint32_t Timer10 = Apb2Timer; static constexpr uint32_t Timer11 = Apb2Timer; - static constexpr uint32_t Usb = 48_MHz; + static constexpr uint32_t Usb = PllClock / pllFactors.pllQ; // 48_Mhz static bool inline enable() { - Rcc::enableExternalCrystal(); // 8MHz - const Rcc::PllFactors pllFactors{ - .pllM = 7, // 8MHz / M=7 -> ~1.14MHz - .pllN = 336, // 1.14MHz * N=336 -> 384MHz - .pllP = 4, // 384MHz / P=4 -> 96MHz = F_cpu - .pllQ = 8, // 384MHz / P=8 -> 48MHz = F_usb - }; + /// STM32F411 running at 84MHz generated from the external 8MHz crystal + Rcc::enableExternalCrystal(); Rcc::enablePll(Rcc::PllSource::ExternalCrystal, pllFactors); // set flash latency for 100MHz Rcc::setFlashLatency(); // switch system clock to PLL output Rcc::enableSystemClock(Rcc::SystemClockSource::Pll); - Rcc::setAhbPrescaler(Rcc::AhbPrescaler::Div1); - // APB1 has max. 50MHz - // APB2 has max. 100MHz - Rcc::setApb1Prescaler(Rcc::Apb1Prescaler::Div2); - Rcc::setApb2Prescaler(Rcc::Apb2Prescaler::Div1); + Rcc::setAhbPrescaler(Ahb_prescaler); + Rcc::setApb1Prescaler(Apb1_prescaler); + Rcc::setApb2Prescaler(Apb2_prescaler); // update frequencies for busy-wait delay functions Rcc::updateCoreFrequency(); diff --git a/src/modm/board/disco_f411ve/rcc_prototype.hpp b/src/modm/board/disco_f411ve/rcc_prototype.hpp new file mode 100644 index 0000000000..ea99320ac4 --- /dev/null +++ b/src/modm/board/disco_f411ve/rcc_prototype.hpp @@ -0,0 +1,58 @@ +#pragma once + +#include + +namespace modm::platform +{ + +// @todo integrate with /platform/clock/stm32/rcc.hpp.in +class RccProto +{ +public: + template + static consteval int + prescalerToValue() + { + switch (Prescaler) + { + case Rcc::AhbPrescaler::Div1: return 1; + case Rcc::AhbPrescaler::Div2: return 2; + case Rcc::AhbPrescaler::Div4: return 4; + case Rcc::AhbPrescaler::Div8: return 8; + case Rcc::AhbPrescaler::Div16: return 16; + case Rcc::AhbPrescaler::Div64: return 64; + case Rcc::AhbPrescaler::Div128: return 128; + case Rcc::AhbPrescaler::Div256: return 256; + case Rcc::AhbPrescaler::Div512: return 512; + }; + } + + template + static consteval int + prescalerToValue() + { + switch (Prescaler) + { + case Rcc::Apb1Prescaler::Div1: return 1; + case Rcc::Apb1Prescaler::Div2: return 2; + case Rcc::Apb1Prescaler::Div4: return 4; + case Rcc::Apb1Prescaler::Div8: return 8; + case Rcc::Apb1Prescaler::Div16: return 16; + }; + } + + template + static consteval int + prescalerToValue() + { + switch (Prescaler) + { + case Rcc::Apb2Prescaler::Div1: return 1; + case Rcc::Apb2Prescaler::Div2: return 2; + case Rcc::Apb2Prescaler::Div4: return 4; + case Rcc::Apb2Prescaler::Div8: return 8; + case Rcc::Apb2Prescaler::Div16: return 16; + } + } +}; +} // namespace modm::platform \ No newline at end of file