Calculate STM32 clocks from the roots#1137
Conversation
0752317 to
70fa1ce
Compare
13a306f to
4de3164
Compare
TomSaw
left a comment
There was a problem hiding this comment.
Request for a 1th review @salkinium.
4de3164 to
a22d568
Compare
There was a problem hiding this comment.
You are now empowered to control the clocks from PLL factors and prescalers for blue-pill and f411ve-disco.
Before diving deeper, please confirm my design decisions. Further improvements may be added to the Rcc namespace but let's be happy with pll's and prescalers for now.
Rcc::AhbPrescaler does not behave as expected
When selecting anything but Div1 or Div2 for Rcc::AhbPrescaler, the F103-blue-bill refuses to work. f411-disco keeps working but the Timer frequencies (scoped in hardware) don't scale like expected. I've matched the various intermediate clocks using static_assert with what is shown in CubeMX for the same configuration and seems to be all fine 🤨.
Propably, another side effect enters the scene when going beyond Div1, Div2 with Rcc::AhbPrescaler.
Because all the boards use an uninspired Div1 the glitch shall be tolerated for now.
I'll add a comment at least.
| template<Rcc::Apb1Prescaler Prescaler> | ||
| 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; | ||
| }; | ||
| } |
There was a problem hiding this comment.
To associate prescaler values to their registers, i've borrowed this construct from modm::platform::GeneralPurposeTimer::signalToChannel<...>(...) but using a switch operator.
There was a problem hiding this comment.
Sure, but I'd rather use a normal constexpr function like uint8_t Rcc::Apb1Div(Rcc::Apb1Prescaler pre) {...}, then it can also be used at runtime if necessary.
|
Hm, so what I would want is to move the common pattern of // Enable clock source
Rcc::enableExternalCrystal();
// Enable PLL
Rcc::enablePll(Rcc::PllSource::ExternalCrystal, pllFactors);
Rcc::setFlashLatency<Frequency>();
Rcc::enableSystemClock(Rcc::SystemClockSource::Pll);
// Set Bus Prescaler
Rcc::setAhbPrescaler(Rcc::AhbPrescaler::Div1);
Rcc::setApb1Prescaler(Rcc::Apb1Prescaler::Div2);
Rcc::setApb2Prescaler(Rcc::Apb2Prescaler::Div1);into a helper class defined in modm and configured by the user: template< OneConfigStruct? >
struct BaseSystemClock
{
// Computes the basic frequencies with static_assert < max freq
// Adds all the peripheral frequencies via modm-devices?
// has a basic enable() function that does the above always correctly
};The BSP would then inherit from that for their SystemClock and perhaps overwrite the one of the other thing for customization. // simple case
using SystemClock = BaseSystemClock< ConfigStruct >;
// advances case
struct SystemClock : public BaseSystemClock< ConfigStruct >;
{
// customize
};This would probably cover 90% of use-cases. |
|
That't some good guidiance! You're way more convenient with the STM architecture than me, so i blindly follow your suggestions in this topic. Thats simple and users can opt in to vary their clocks per application. |
There are hardcoded clock constants in each of **/board.hpp althought the required information to calculate the truth is available!