diff --git a/src/modm/board/blue_pill_f103/board.hpp b/src/modm/board/blue_pill_f103/board.hpp index dcd053c20c..9d509f4cd4 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,38 @@ 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 ExternalCrystalClock = 8_MHz; + + static constexpr Rcc::PllFactors pllFactors{ + .pllMul = 9, + .usbPrediv = Rcc::UsbPrescaler::Div1_5 + }; + static constexpr Rcc::AhbPrescaler Ahb_pre = Rcc::AhbPrescaler::Div1; + static constexpr Rcc::Apb1Prescaler Apb1_pre = Rcc::Apb1Prescaler::Div2; + static constexpr Rcc::Apb2Prescaler Apb2_pre = Rcc::Apb2Prescaler::Div1; + + // ------------------------------------------ + + static constexpr uint32_t MainPllClock = ExternalCrystalClock * pllFactors.pllMul; // 72 Mhz + + static constexpr uint32_t Ahb = MainPllClock / RccProto::prescalerToValue(); + static constexpr uint32_t Apb1 = Ahb / RccProto::prescalerToValue(); + static constexpr uint32_t Apb2 = Ahb / RccProto::prescalerToValue(); + + // @todo find a nice home for these assert's + static_assert(Ahb <= 72_MHz, "Apb1 has max. 72MHz!"); + static_assert(Apb1 <= 36_MHz, "Apb1 has max. 36MHz!"); + 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 +75,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 +94,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_pre); + Rcc::setApb1Prescaler(Apb1_pre); + Rcc::setApb2Prescaler(Apb2_pre); // update frequencies for busy-wait delay functions Rcc::updateCoreFrequency(); @@ -129,5 +141,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..da87d33839 --- /dev/null +++ b/src/modm/board/blue_pill_f103/rcc_prototype.hpp @@ -0,0 +1,64 @@ +#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; + } + } + }; + +} \ No newline at end of file diff --git a/src/modm/board/disco_f411ve/board.hpp b/src/modm/board/disco_f411ve/board.hpp index ffb5286710..1f83e02a94 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,49 @@ 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 ExternalCrystalClock = 8_MHz; + + static constexpr Rcc::PllFactors pllFactors{ + .pllM = 8, + .pllN = 336, + .pllP = 4, + .pllQ = 7, + }; + static constexpr Rcc::AhbPrescaler Ahb_pre = Rcc::AhbPrescaler::Div1; + static constexpr Rcc::Apb1Prescaler Apb1_pre = Rcc::Apb1Prescaler::Div2; + static constexpr Rcc::Apb2Prescaler Apb2_pre = Rcc::Apb2Prescaler::Div1; + + // ------------------------------------------ + + static constexpr uint32_t MainPllClock = ExternalCrystalClock / pllFactors.pllM * pllFactors.pllN; + static constexpr uint32_t SystemFrequency = MainPllClock / pllFactors.pllP; // 96_Mhz + + static constexpr uint32_t Ahb = SystemFrequency / RccProto::prescalerToValue(); + static constexpr uint32_t Apb1 = Ahb / RccProto::prescalerToValue(); + static constexpr uint32_t Apb2 = Ahb / RccProto::prescalerToValue(); + + // @todo find a nice home for these + static_assert(SystemFrequency <= 100_MHz, "SystemFrequency has max. 100MHz!"); + static_assert(Apb1 <= 50_MHz, "Apb1 has max. 50MHz!"); + 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 +89,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 +98,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 = MainPllClock / 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_pre); + Rcc::setApb1Prescaler(Apb1_pre); + Rcc::setApb2Prescaler(Apb2_pre); // update frequencies for busy-wait delay functions Rcc::updateCoreFrequency(); @@ -188,7 +217,7 @@ initializeLis3() lis3::Cs::setOutput(modm::Gpio::High); lis3::SpiMaster::connect(); - lis3::SpiMaster::initialize(); + lis3::SpiMaster::initialize(); lis3::SpiMaster::setDataMode(lis3::SpiMaster::DataMode::Mode3); } 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..c48f60711c --- /dev/null +++ b/src/modm/board/disco_f411ve/rcc_prototype.hpp @@ -0,0 +1,54 @@ +#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; + } + } + }; + +} \ No newline at end of file