diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml
index 5bdfdcd936..38ebb3b45b 100644
--- a/.github/workflows/linux.yml
+++ b/.github/workflows/linux.yml
@@ -151,6 +151,10 @@ jobs:
if: always()
run: |
(cd examples && ../tools/scripts/examples_compile.py stm32f1_discovery nucleo_f103rb olimexino_stm32 blue_pill_f103 black_pill_f103)
+ - name: Examples STM32F2 Series
+ if: always()
+ run: |
+ (cd examples && ../tools/scripts/examples_compile.py nucleo_f207zg)
- name: Examples STM32F3 Series
if: always()
run: |
diff --git a/README.md b/README.md
index a58257de5e..f53cc39320 100644
--- a/README.md
+++ b/README.md
@@ -755,65 +755,66 @@ We have out-of-box support for many development boards including documentation.
NUCLEO-F091RC |
| NUCLEO-F103RB |
+NUCLEO-F207ZG |
NUCLEO-F303K8 |
NUCLEO-F303RE |
-NUCLEO-F334R8 |
+| NUCLEO-F334R8 |
NUCLEO-F401RE |
NUCLEO-F411RE |
NUCLEO-F429ZI |
-NUCLEO-F439ZI |
+| NUCLEO-F439ZI |
NUCLEO-F446RE |
NUCLEO-F446ZE |
NUCLEO-F722ZE |
-NUCLEO-F746ZG |
+| NUCLEO-F746ZG |
NUCLEO-F767ZI |
NUCLEO-G070RB |
NUCLEO-G071RB |
-NUCLEO-G0B1RE |
+| NUCLEO-G0B1RE |
NUCLEO-G431KB |
NUCLEO-G431RB |
NUCLEO-G474RE |
-NUCLEO-H503RB |
+| NUCLEO-H503RB |
NUCLEO-H723ZG |
NUCLEO-H743ZI |
NUCLEO-L031K6 |
-NUCLEO-L053R8 |
+| NUCLEO-L053R8 |
NUCLEO-L152RE |
NUCLEO-L432KC |
NUCLEO-L452RE |
-NUCLEO-L476RG |
+| NUCLEO-L476RG |
NUCLEO-L496ZG-P |
NUCLEO-L552ZE-Q |
NUCLEO-U083RC |
-NUCLEO-U385RG-Q |
+| NUCLEO-U385RG-Q |
NUCLEO-U575ZI-Q |
OLIMEXINO-STM32 |
Raspberry Pi Pico |
-SAMD21-MINI |
+| SAMD21-MINI |
SAMD21-XPLAINED-PRO |
SAME54-XPLAINED-PRO |
SAME70-XPLAINED |
-SAMG55-XPLAINED-PRO |
+| SAMG55-XPLAINED-PRO |
SAMV71-XPLAINED-ULTRA |
Smart Response XE |
STM32-F4VE |
-STM32F030-DEMO |
+| STM32F030-DEMO |
THINGPLUS-RP2040 |
WEACT-C011F6 |
WEACT-G0B1CB |
-WEACT-H503CB |
+| WEACT-H503CB |
WEACT-H562RG |
WEACT-U585CI |
diff --git a/examples/generic/delay/project.xml b/examples/generic/delay/project.xml
index f839f46a81..5e6f2fa0a2 100644
--- a/examples/generic/delay/project.xml
+++ b/examples/generic/delay/project.xml
@@ -5,6 +5,7 @@
+
diff --git a/examples/generic/usb/project.xml b/examples/generic/usb/project.xml
index 5a4dbf05b0..43800ed4ff 100644
--- a/examples/generic/usb/project.xml
+++ b/examples/generic/usb/project.xml
@@ -12,6 +12,7 @@
+
diff --git a/examples/nucleo_f207zg/blink/main.cpp b/examples/nucleo_f207zg/blink/main.cpp
new file mode 100644
index 0000000000..3853e8a0ee
--- /dev/null
+++ b/examples/nucleo_f207zg/blink/main.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2016-2017, 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/.
+ */
+// ----------------------------------------------------------------------------
+
+#include
+
+using namespace Board;
+
+int
+main()
+{
+ Board::initialize();
+
+ // Use the logging streams to print some messages.
+ // Change MODM_LOG_LEVEL above to enable or disable these messages
+ MODM_LOG_DEBUG << "debug" << modm::endl;
+ MODM_LOG_INFO << "info" << modm::endl;
+ MODM_LOG_WARNING << "warning" << modm::endl;
+ MODM_LOG_ERROR << "error" << modm::endl;
+
+ uint32_t counter(0);
+
+ while (true)
+ {
+ Leds::toggle();
+ modm::delay(Button::read() ? 100ms : 500ms);
+
+ MODM_LOG_INFO << "loop: " << counter++ << modm::endl;
+ }
+
+ return 0;
+}
diff --git a/examples/nucleo_f207zg/blink/project.xml b/examples/nucleo_f207zg/blink/project.xml
new file mode 100644
index 0000000000..2e464d3d6c
--- /dev/null
+++ b/examples/nucleo_f207zg/blink/project.xml
@@ -0,0 +1,9 @@
+
+ modm:nucleo-f207zg
+
+
+
+
+ modm:build:scons
+
+
diff --git a/ext/hathach/uart.hpp b/ext/hathach/uart.hpp
index e482f617d1..8e08699018 100644
--- a/ext/hathach/uart.hpp
+++ b/ext/hathach/uart.hpp
@@ -35,12 +35,14 @@ class UsbUart : public modm::Uart
static inline void
flushWriteBuffer()
{
+ if (not tud_cdc_n_ready(ITF)) return;
tud_cdc_n_write_flush(ITF);
}
static inline bool
write(uint8_t c)
{
+ if (not tud_cdc_n_ready(ITF)) return false;
bool rc = tud_cdc_n_write_char(ITF, c);
tud_cdc_n_write_flush(ITF);
return rc;
@@ -49,6 +51,7 @@ class UsbUart : public modm::Uart
static inline std::size_t
write(const uint8_t *data, std::size_t length)
{
+ if (not tud_cdc_n_ready(ITF)) return false;
std::size_t rc = tud_cdc_n_write(ITF, data, length);
tud_cdc_n_write_flush(ITF);
return rc;
diff --git a/src/modm/board/nucleo_f207zg/board.hpp b/src/modm/board/nucleo_f207zg/board.hpp
new file mode 100644
index 0000000000..b50864cbf1
--- /dev/null
+++ b/src/modm/board/nucleo_f207zg/board.hpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2016-2017, Sascha Schade
+ * Copyright (c) 2016-2018, 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
+#include
+
+using namespace modm::platform;
+
+/// @ingroup modm_board_nucleo_f207zg
+#define MODM_BOARD_HAS_LOGGER
+
+namespace Board
+{
+/// @ingroup modm_board_nucleo_f207zg
+/// @{
+using namespace modm::literals;
+
+/// STM32F207ZG running at 120MHz from the ST-LINK 8 MHz MCO
+struct SystemClock
+{
+ static constexpr uint32_t Hse = 8_MHz;
+ static constexpr Rcc::PllConfig pll
+ {
+ .M = 4, // 8 MHz / 4 = 2 MHz
+ .N = 240, // 2 MHz * 240 = 480 MHz
+ .P = 4, // 480 MHz / 4 = 120 MHz = F_cpu
+ .Q = 10, // 480 MHz / 10 = 48 MHz = F_usb
+ };
+ static constexpr uint32_t PllP = Hse / pll.M * pll.N / pll.P;
+ static constexpr uint32_t PllQ = Hse / pll.M * pll.N / pll.Q;
+
+ static constexpr uint32_t Frequency = PllP;
+ static_assert(Frequency == Rcc::MaxFrequency);
+
+ static constexpr uint32_t Ahb = Frequency;
+ static constexpr uint32_t Apb1 = Frequency / 4;
+ static constexpr uint32_t Apb2 = Frequency / 2;
+ static constexpr uint32_t Ahb1 = Ahb;
+ static constexpr uint32_t Ahb2 = Ahb;
+
+ static constexpr uint32_t Crc = Ahb1;
+ static constexpr uint32_t Flash = Ahb1;
+ static constexpr uint32_t Dma1 = Ahb1;
+ static constexpr uint32_t Dma2 = Ahb1;
+ static constexpr uint32_t Eth = Ahb1;
+
+ static constexpr uint32_t Dcmi = Ahb2;
+ static constexpr uint32_t Rng = Ahb2;
+
+ static constexpr uint32_t Spi2 = Apb1;
+ static constexpr uint32_t Spi3 = Apb1;
+ static constexpr uint32_t Usart2 = Apb1;
+ static constexpr uint32_t Usart3 = Apb1;
+ static constexpr uint32_t Uart4 = Apb1;
+ static constexpr uint32_t Uart5 = Apb1;
+ static constexpr uint32_t I2c1 = Apb1;
+ static constexpr uint32_t I2c2 = Apb1;
+ static constexpr uint32_t I2c3 = Apb1;
+ static constexpr uint32_t Can1 = Apb1;
+ static constexpr uint32_t Can2 = Apb1;
+ static constexpr uint32_t Pwr = Apb1;
+ static constexpr uint32_t Dac = Apb1;
+ static constexpr uint32_t Wwdg = Apb1;
+
+ // APB2 domain
+ static constexpr uint32_t Spi1 = Apb2;
+ static constexpr uint32_t Usart1 = Apb2;
+ static constexpr uint32_t Usart6 = Apb2;
+ static constexpr uint32_t Adc = Apb2;
+ static constexpr uint32_t Sdio = Apb2;
+ static constexpr uint32_t Syscfg = Apb2;
+
+ 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;
+ static constexpr uint32_t Timer4 = Apb1Timer;
+ static constexpr uint32_t Timer5 = Apb1Timer;
+ static constexpr uint32_t Timer6 = Apb1Timer;
+ static constexpr uint32_t Timer7 = Apb1Timer;
+ static constexpr uint32_t Timer8 = Apb2Timer;
+ static constexpr uint32_t Timer9 = Apb2Timer;
+ static constexpr uint32_t Timer10 = Apb2Timer;
+ static constexpr uint32_t Timer11 = Apb2Timer;
+ static constexpr uint32_t Timer12 = Apb1Timer;
+ static constexpr uint32_t Timer13 = Apb1Timer;
+ static constexpr uint32_t Timer14 = Apb1Timer;
+
+ static constexpr uint32_t Usb = PllQ;
+ static constexpr uint32_t Iwdg = Rcc::LsiFrequency;
+ static constexpr uint32_t Rtc = 32.768_kHz;
+
+ static bool inline
+ enable()
+ {
+ Rcc::enableLseCrystal();
+ Rcc::enableHseClock();
+
+ Rcc::setFlashLatency();
+ Rcc::updateCoreFrequency();
+
+ Rcc::setAhbPrescaler(Rcc::AhbPrescaler::Div1);
+ Rcc::setApb1Prescaler(Rcc::ApbPrescaler::Div4);
+ Rcc::setApb2Prescaler(Rcc::ApbPrescaler::Div2);
+
+ Rcc::enablePll(Rcc::PllSource::Hse, pll);
+ Rcc::enableSystemClock(Rcc::SystemClockSource::Pll);
+ Rcc::setRealTimeClockSource(Rcc::RealTimeClockSource::Lse);
+
+ return true;
+ }
+};
+
+// Arduino Footprint
+#include "nucleo144_arduino.hpp"
+
+using Button = GpioInputC13;
+
+using LedGreen = GpioOutputB0; // LED1 [Green]
+using LedBlue = GpioOutputB7; // LED2 [Blue]
+using LedRed = GpioOutputB14; // LED3 [Red]
+using Leds = SoftwareGpioPort< LedRed, LedBlue, LedGreen >;
+/// @}
+
+namespace usb
+{
+/// @ingroup modm_board_nucleo_f207zg
+/// @{
+using Vbus = GpioA9;
+using Id = GpioA10;
+using Dm = GpioA11;
+using Dp = GpioA12;
+
+using Overcurrent = GpioInputG7; // OTG_FS_OverCurrent
+using Power = GpioOutputG6; // OTG_FS_PowerSwitchOn
+
+using Device = UsbFs;
+/// @}
+}
+
+namespace stlink
+{
+/// @ingroup modm_board_nucleo_f207zg
+/// @{
+using Tx = GpioOutputD8;
+using Rx = GpioInputD9;
+using Uart = BufferedUart>;
+/// @}
+}
+
+/// @ingroup modm_board_nucleo_f207zg
+/// @{
+using LoggerDevice = modm::IODeviceWrapper< stlink::Uart, modm::IOBuffer::BlockIfFull >;
+
+inline void
+initialize()
+{
+ SystemClock::enable();
+ SysTickTimer::initialize();
+
+ stlink::Uart::connect();
+ stlink::Uart::initialize();
+
+ Leds::setOutput(modm::Gpio::Low);
+
+ Button::setInput();
+}
+
+inline void
+initializeUsb(uint8_t priority=3)
+{
+ usb::Device::initialize(priority);
+ usb::Device::connect();
+
+ usb::Overcurrent::setInput();
+ usb::Vbus::setInput();
+ // // Enable VBUS sense (B device) via pin PA9
+ // USB_OTG_FS->GCCFG &= ~USB_OTG_GCCFG_NOVBUSSENS;
+ // USB_OTG_FS->GCCFG |= USB_OTG_GCCFG_VBUSBSEN;
+}
+/// @}
+
+}
diff --git a/src/modm/board/nucleo_f207zg/board.xml b/src/modm/board/nucleo_f207zg/board.xml
new file mode 100644
index 0000000000..10c4ba35f0
--- /dev/null
+++ b/src/modm/board/nucleo_f207zg/board.xml
@@ -0,0 +1,14 @@
+
+
+
+ ../../../../repo.lb
+
+
+
+
+
+
+
+ modm:board:nucleo-f207zg
+
+
diff --git a/src/modm/board/nucleo_f207zg/module.lb b/src/modm/board/nucleo_f207zg/module.lb
new file mode 100644
index 0000000000..328c01eeeb
--- /dev/null
+++ b/src/modm/board/nucleo_f207zg/module.lb
@@ -0,0 +1,49 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# 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/.
+# -----------------------------------------------------------------------------
+
+def init(module):
+ module.name = ":board:nucleo-f207zg"
+ module.description = """\
+# NUCLEO-F207ZG
+
+[Nucleo kit for STM32F207ZG](https://www.st.com/en/evaluation-tools/nucleo-f207zg.html)
+"""
+
+def prepare(module, options):
+ if not options[":target"].partname.startswith("stm32f207zgt"):
+ return False
+
+ module.depends(
+ ":debug",
+ ":architecture:clock",
+ ":platform:core",
+ ":platform:gpio",
+ ":platform:clock",
+ ":platform:uart:3",
+ ":platform:usb:fs")
+
+ return True
+
+def build(env):
+ env.outbasepath = "modm/src/modm/board"
+ env.substitutions = {
+ "with_logger": True,
+ "with_assert": env.has_module(":architecture:assert")
+ }
+ env.template("../board.cpp.in", "board.cpp")
+ env.copy('.')
+ env.copy("../nucleo144_arduino.hpp", "nucleo144_arduino.hpp")
+
+ env.outbasepath = "modm/openocd/modm/board/"
+ env.template(repopath("tools/openocd/modm/st_nucleo_swd.cfg.in"), "board.cfg",
+ substitutions={"target": "stm32f2x"})
+ env.collect(":build:openocd.source", "modm/board/board.cfg")
diff --git a/src/modm/platform/clock/stm32/module.lb b/src/modm/platform/clock/stm32/module.lb
index 4651653aba..5e83b94566 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", "f1"]:
+ if t.family in ["h5", "u0", "g0", "u3", "c0", "f0", "l0", "f1", "f2"]:
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_f2.hpp.in b/src/modm/platform/clock/stm32/rcc_f2.hpp.in
new file mode 100644
index 0000000000..0d32d4260c
--- /dev/null
+++ b/src/modm/platform/clock/stm32/rcc_f2.hpp.in
@@ -0,0 +1,348 @@
+/*
+ * 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 STM32F2 devices.
+ *
+ * This class abstracts access to clock settings on the STM32F2 family.
+ * 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 = 32'000;
+ static constexpr uint32_t HsiFrequency = 16'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;
+ }
+
+ // PLL configuration
+ enum class
+ PllSource : uint8_t
+ {
+ Hsi = 0,
+ Hse = 1,
+ };
+ struct PllConfig
+ {
+ uint8_t M; ///< PLLM division factor: 2-63
+ uint16_t N; ///< PLLN multiplication factor: 192-432
+ uint8_t P; ///< PLLP division factor: 2,4,6,8
+ uint8_t Q; ///< PLLQ division factor: 2-15 (48 MHz domain)
+ };
+ static inline bool
+ enablePll(PllSource src, PllConfig cfg, uint32_t waitLoops = 0x10000)
+ {
+ if (cfg.Q < 2u or cfg.M < 2u or cfg.N < 192u or 432u < cfg.N or (cfg.P & 1u))
+ return false;
+ RCC->PLLCFGR = (uint32_t(src) << RCC_PLLCFGR_PLLSRC_Pos) |
+ ((uint32_t(cfg.M) << RCC_PLLCFGR_PLLM_Pos) & RCC_PLLCFGR_PLLM) |
+ ((uint32_t(cfg.N) << RCC_PLLCFGR_PLLN_Pos) & RCC_PLLCFGR_PLLN) |
+ ((uint32_t(cfg.P / 2u - 1u) << RCC_PLLCFGR_PLLP_Pos) & RCC_PLLCFGR_PLLP) |
+ ((uint32_t(cfg.Q) << RCC_PLLCFGR_PLLQ_Pos) & RCC_PLLCFGR_PLLQ);
+
+ RCC->CR |= RCC_CR_PLLON;
+ while (not (RCC->CR & RCC_CR_PLLRDY) and --waitLoops) ;
+ return waitLoops;
+ }
+ static inline bool
+ disablePll(uint32_t waitLoops = 0x10000)
+ {
+ RCC->CR &= ~RCC_CR_PLLON;
+ while ((RCC->CR & RCC_CR_PLLRDY) and --waitLoops) ;
+ return waitLoops;
+ }
+
+ struct PllI2sConfig
+ {
+ uint16_t N; ///< PLLI2SN multiplication factor: 192-432
+ uint8_t R; ///< PLLI2SR division factor: 2-7
+ };
+ static inline bool
+ enablePllI2s(PllI2sConfig cfg, uint32_t waitLoops = 0x10000)
+ {
+ RCC->PLLI2SCFGR =
+ ((uint32_t(cfg.N) << RCC_PLLI2SCFGR_PLLI2SN_Pos) & RCC_PLLI2SCFGR_PLLI2SN_Msk) |
+ ((uint32_t(cfg.R) << RCC_PLLI2SCFGR_PLLI2SR_Pos) & RCC_PLLI2SCFGR_PLLI2SR_Msk);
+ RCC->CR |= RCC_CR_PLLI2SON;
+ while (not (RCC->CR & RCC_CR_PLLI2SRDY) and --waitLoops) ;
+ return waitLoops;
+ }
+ static inline bool
+ disablePllI2s(uint32_t waitLoops = 0x10000)
+ {
+ RCC->CR &= ~RCC_CR_PLLI2SON;
+ while ((RCC->CR & RCC_CR_PLLI2SRDY) and --waitLoops) ;
+ return waitLoops;
+ }
+
+ 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 = 0b00,
+ Lse = 0b01,
+ Lsi = 0b10,
+ Hse = 0b11,
+ };
+ static inline void
+ setRealTimeClockSource(RealTimeClockSource src, uint8_t hseDivider = 2)
+ {
+ RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_RTCPRE) | ((uint32_t(hseDivider) << RCC_CFGR_RTCPRE_Pos) & RCC_CFGR_RTCPRE);
+ RCC->BDCR = (RCC->BDCR & ~RCC_BDCR_RTCSEL) | (uint32_t(src) << RCC_BDCR_RTCSEL_Pos) | RCC_BDCR_RTCEN;
+ }
+
+ enum class
+ AdcPrescaler : uint8_t
+ {
+ Div2 = 0b00,
+ Div4 = 0b01,
+ Div6 = 0b10,
+ Div8 = 0b11,
+ };
+ static inline void
+ setAdcPrescaler(AdcPrescaler prescaler)
+ {
+ ADC123_COMMON->CCR = (ADC123_COMMON->CCR & ~ADC_CCR_ADCPRE) | (uint32_t(prescaler) << ADC_CCR_ADCPRE_Pos);
+ }
+
+ enum class
+ I2sClockSource : uint32_t
+ {
+ PllI2s,
+ External,
+ };
+ static inline void
+ setI2sClockSource(I2sClockSource src)
+ {
+ if (src == I2sClockSource::External)
+ RCC->CFGR |= RCC_CFGR_I2SSRC;
+ else
+ RCC->CFGR &= ~RCC_CFGR_I2SSRC;
+ }
+
+ enum class
+ McoPrescaler : uint8_t
+ {
+ Div1 = 0b000,
+ Div2 = 0b100,
+ Div3 = 0b101,
+ Div4 = 0b110,
+ Div5 = 0b111,
+ };
+ enum class
+ Mco1ClockSource : uint8_t
+ {
+ Hsi = 0b00,
+ Lse = 0b01,
+ Hse = 0b10,
+ Pll = 0b11,
+ };
+ static inline void
+ setMco1ClockSource(Mco1ClockSource src, McoPrescaler prescaler = McoPrescaler::Div1)
+ {
+ RCC->CFGR = (RCC->CFGR & ~(RCC_CFGR_MCO1 | RCC_CFGR_MCO1PRE)) |
+ ((uint32_t(src) << RCC_CFGR_MCO1_Pos) & RCC_CFGR_MCO1) |
+ ((uint32_t(prescaler) << RCC_CFGR_MCO1PRE_Pos) & RCC_CFGR_MCO1PRE);
+ }
+
+ enum class
+ Mco2ClockSource : uint8_t
+ {
+ SysClk = 0b00,
+ PllI2s = 0b01,
+ Hse = 0b10,
+ Pll = 0b11,
+ };
+ static inline void
+ setMco2ClockSource(Mco2ClockSource src, McoPrescaler prescaler = McoPrescaler::Div1)
+ {
+ RCC->CFGR = (RCC->CFGR & ~(RCC_CFGR_MCO2 | RCC_CFGR_MCO2PRE)) |
+ ((uint32_t(src) << RCC_CFGR_MCO2_Pos) & RCC_CFGR_MCO2) |
+ ((uint32_t(prescaler) << RCC_CFGR_MCO2PRE_Pos) & RCC_CFGR_MCO2PRE);
+ }
+
+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"
diff --git a/src/modm/platform/core/stm32/module.lb b/src/modm/platform/core/stm32/module.lb
index 6f3f26788b..caf6c405d3 100644
--- a/src/modm/platform/core/stm32/module.lb
+++ b/src/modm/platform/core/stm32/module.lb
@@ -90,7 +90,7 @@ def build(env):
"f0": (4, 4), # CM3 tested on F071 in RAM
"f1": (4, 4), # CM3 tested on F103 in RAM
"f4": (4, 4), # CM4 tested on F401, F411, F446 in RAM
- "f2": (4, 4), # CM3 guessed based on documentation
+ "f2": (4, 4), # CM3 tested on F207 in RAM
}[target.family]
# us_shift is an optimization to limit error via fractional math