Skip to content

Commit

Permalink
proto for board/blue_pill_f103 and board/disco_f411ve
Browse files Browse the repository at this point in the history
  • Loading branch information
TomSaw committed Mar 8, 2024
1 parent 54dd9df commit 13a306f
Show file tree
Hide file tree
Showing 4 changed files with 205 additions and 48 deletions.
64 changes: 37 additions & 27 deletions src/modm/board/blue_pill_f103/board.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@
*/
// ----------------------------------------------------------------------------

#ifndef MODM_STM32_F103C8T6_BLUE_PILL_HPP
#define MODM_STM32_F103C8T6_BLUE_PILL_HPP
#pragma once

#include <modm/platform.hpp>
#include <modm/architecture/interface/clock.hpp>

#include "rcc_prototype.hpp"

using namespace modm::platform;

namespace Board
Expand All @@ -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<Ahb_pre>();
static constexpr uint32_t Apb1 = Ahb / RccProto::prescalerToValue<Apb1_pre>();
static constexpr uint32_t Apb2 = Ahb / RccProto::prescalerToValue<Apb2_pre>();

// @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<Apb1_pre>() == 1 ? 1 : 2);
static constexpr uint32_t Apb2Timer = Apb2 * (RccProto::prescalerToValue<Apb2_pre>() == 1 ? 1 : 2);

// ------------------------------------------

static constexpr uint32_t Frequency = Ahb;

static constexpr uint32_t Adc = Apb2;

Expand All @@ -49,42 +75,28 @@ 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<pllFactors.usbPrediv>(); // 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
Rcc::setFlashLatency<Frequency>();

// 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<Frequency>();
Expand Down Expand Up @@ -129,5 +141,3 @@ initializeUsbFs(uint8_t priority=3)
/// @}

} // Board namespace

#endif // MODM_STM32_F103C8T6_BLUE_PILL_HPP
64 changes: 64 additions & 0 deletions src/modm/board/blue_pill_f103/rcc_prototype.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#pragma once

#include <modm/architecture/interface/clock.hpp>

namespace modm::platform {

// @todo integrate with /platform/clock/stm32/rcc.hpp.in
class RccProto {
public:
template<Rcc::AhbPrescaler Prescaler>
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<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;
};
}

template<Rcc::Apb2Prescaler Prescaler>
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<Rcc::UsbPrescaler Prescaler>
static consteval float
prescalerToValue()
{
switch(Prescaler) {
case Rcc::UsbPrescaler::Div1: return 1;
case Rcc::UsbPrescaler::Div1_5: return 1.5;
}
}
};

}
71 changes: 50 additions & 21 deletions src/modm/board/disco_f411ve/board.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
#include <modm/driver/inertial/lis3dsh.hpp>
#include <modm/platform.hpp>

#include "rcc_prototype.hpp"

using namespace modm::platform;

namespace Board
Expand All @@ -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<Ahb_pre>();
static constexpr uint32_t Apb1 = Ahb / RccProto::prescalerToValue<Apb1_pre>();
static constexpr uint32_t Apb2 = Ahb / RccProto::prescalerToValue<Apb2_pre>();

// @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<Apb1_pre>() == 1 ? 1 : 2);
static constexpr uint32_t Apb2Timer = Apb2 * (RccProto::prescalerToValue<Apb2_pre>() == 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;

Expand All @@ -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;
Expand All @@ -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<Frequency>();
// 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<Frequency>();

Expand Down Expand Up @@ -188,7 +217,7 @@ initializeLis3()
lis3::Cs::setOutput(modm::Gpio::High);

lis3::SpiMaster::connect<lis3::Sck::Sck, lis3::Mosi::Mosi, lis3::Miso::Miso>();
lis3::SpiMaster::initialize<SystemClock, 6_MHz>();
lis3::SpiMaster::initialize<SystemClock, 5.25_MHz>();
lis3::SpiMaster::setDataMode(lis3::SpiMaster::DataMode::Mode3);
}

Expand Down
54 changes: 54 additions & 0 deletions src/modm/board/disco_f411ve/rcc_prototype.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#pragma once

#include <modm/architecture/interface/clock.hpp>

namespace modm::platform {

// @todo integrate with /platform/clock/stm32/rcc.hpp.in
class RccProto {
public:
template<Rcc::AhbPrescaler Prescaler>
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<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;
};
}

template<Rcc::Apb2Prescaler Prescaler>
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;
}
}
};

}

0 comments on commit 13a306f

Please sign in to comment.