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