From da1d294f4de06929ef411a9309f8495ea4ae7430 Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Tue, 3 Dec 2024 21:55:43 +0100 Subject: [PATCH] WIP STM32H5 support --- examples/generic/blinky/project.xml | 3 +- ext/modm-devices | 2 +- repo.lb | 2 +- src/modm/board/nucleo_h503rb/board.hpp | 240 ++++++++++++++++++ src/modm/board/nucleo_h503rb/board.xml | 14 + src/modm/board/nucleo_h503rb/module.lb | 56 ++++ src/modm/board/nucleo_h503rb/startup.cpp | 21 ++ src/modm/platform/clock/stm32/module.lb | 8 +- src/modm/platform/clock/stm32/rcc.cpp.in | 4 +- src/modm/platform/clock/stm32/rcc.hpp.in | 24 +- src/modm/platform/clock/stm32/rcc_impl.hpp.in | 2 +- src/modm/platform/core/stm32/module.lb | 1 + src/modm/platform/gpio/stm32/data.hpp.in | 4 +- src/modm/platform/gpio/stm32/enable.cpp.in | 2 +- 14 files changed, 358 insertions(+), 25 deletions(-) create mode 100644 src/modm/board/nucleo_h503rb/board.hpp create mode 100644 src/modm/board/nucleo_h503rb/board.xml create mode 100644 src/modm/board/nucleo_h503rb/module.lb create mode 100644 src/modm/board/nucleo_h503rb/startup.cpp diff --git a/examples/generic/blinky/project.xml b/examples/generic/blinky/project.xml index ca7b76e203..f85a33566b 100644 --- a/examples/generic/blinky/project.xml +++ b/examples/generic/blinky/project.xml @@ -1,5 +1,6 @@ - modm:nucleo-l476rg + + modm:nucleo-h503rb diff --git a/ext/modm-devices b/ext/modm-devices index 202131e0a3..2c26f65a72 160000 --- a/ext/modm-devices +++ b/ext/modm-devices @@ -1 +1 @@ -Subproject commit 202131e0a30fdd4a05988c7e9c333e5526b663fc +Subproject commit 2c26f65a72eed4d5a982d137b3d6470d0bbfe21e diff --git a/repo.lb b/repo.lb index 95caae6990..9488fc15bb 100644 --- a/repo.lb +++ b/repo.lb @@ -86,7 +86,7 @@ class DevicesCache(dict): supported = ["stm32c0", "stm32f0", "stm32f1", "stm32f2", "stm32f3", "stm32f4", "stm32f7", "stm32g0", "stm32g4", - "stm32h7", + "stm32h5", "stm32h7", "stm32l0", "stm32l1", "stm32l4", "stm32l5", "stm32u5", "at90", "attiny", "atmega", diff --git a/src/modm/board/nucleo_h503rb/board.hpp b/src/modm/board/nucleo_h503rb/board.hpp new file mode 100644 index 0000000000..3c5aa0fd0d --- /dev/null +++ b/src/modm/board/nucleo_h503rb/board.hpp @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2021, Christopher Durand + * Copyright (c) 2021, 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_h503rb +#define MODM_BOARD_HAS_LOGGER + +namespace Board +{ +/// @ingroup modm_board_nucleo_h503rb +/// @{ +using namespace modm::literals; + +/// STM32H503RB running at 250MHz from PLL clock generated from 8 MHz HSE +struct SystemClock +{ + static constexpr uint32_t Hse = 8_MHz; + + // Max 250MHz + static constexpr uint32_t SysClk = 250_MHz; + static constexpr uint32_t Pll1Q = SysClk / 4; + static constexpr uint32_t Pll2Q = 120_MHz; + // Max 250MHz + static constexpr uint32_t Hclk = SysClk / 1; // D1CPRE + static constexpr uint32_t Frequency = Hclk; + // Max 125MHz + static constexpr uint32_t Ahb = Hclk / 2; // HPRE + static constexpr uint32_t Ahb1 = Ahb; + static constexpr uint32_t Ahb2 = Ahb; + static constexpr uint32_t Ahb3 = Ahb; + static constexpr uint32_t Ahb4 = Ahb; + // Max 62.5MHz + static constexpr uint32_t Apb1 = Ahb / 2; // D2PPRE1 + static constexpr uint32_t Apb2 = Ahb / 2; // D2PPRE2 + static constexpr uint32_t Apb3 = Ahb / 2; // D1PPRE + static constexpr uint32_t Apb4 = Ahb / 2; // D3PPRE + + static constexpr uint32_t Adc1 = Ahb1; + static constexpr uint32_t Adc2 = Ahb1; + static constexpr uint32_t Adc3 = Ahb4; + + static constexpr uint32_t Dac1 = Apb1; + + static constexpr uint32_t Spi1 = Pll1Q; + static constexpr uint32_t Spi2 = Pll1Q; + static constexpr uint32_t Spi3 = Pll1Q; + static constexpr uint32_t Spi4 = Apb2; + static constexpr uint32_t Spi5 = Apb2; + static constexpr uint32_t Spi6 = Apb4; + + static constexpr uint32_t Usart1 = Apb2; + 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 Usart6 = Apb2; + static constexpr uint32_t Uart7 = Apb1; + static constexpr uint32_t Uart8 = Apb1; + static constexpr uint32_t Uart9 = Apb2; + static constexpr uint32_t Usart10 = Apb2; + + static constexpr uint32_t LpUart1 = Apb4; + + static constexpr uint32_t Fdcan1 = Pll2Q; + static constexpr uint32_t Fdcan2 = Pll2Q; + static constexpr uint32_t Fdcan3 = Pll2Q; + + static constexpr uint32_t I2c1 = Apb1; + static constexpr uint32_t I2c2 = Apb1; + static constexpr uint32_t I2c3 = Apb1; + static constexpr uint32_t I2c4 = Apb4; + static constexpr uint32_t I2c5 = 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; + 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 Timer12 = Apb1Timer; + static constexpr uint32_t Timer13 = Apb1Timer; + static constexpr uint32_t Timer14 = Apb1Timer; + static constexpr uint32_t Timer15 = Apb2Timer; + static constexpr uint32_t Timer16 = Apb2Timer; + static constexpr uint32_t Timer17 = Apb2Timer; + static constexpr uint32_t Timer23 = Apb1Timer; + static constexpr uint32_t Timer24 = Apb1Timer; + + static constexpr uint32_t Usb = 48_MHz; // From PLL3Q + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; + + static bool inline + enable() + { + // Switch core supply voltage to maximum level + // Required for running at 250 MHz + Rcc::setVoltageScaling(Rcc::VoltageScaling::Scale0); + + Rcc::enableExternalClock(); // 8 MHz + const Rcc::PllFactors pllFactors1{ + .range = Rcc::PllInputRange::MHz1_2, + .pllM = 4, // 8 MHz / 4 = 2 MHz + .pllN = 275, // 2 MHz * 275 = 250 MHz + .pllP = 1, // 250 MHz / 1 = 250 MHz + .pllQ = 4, // 250 MHz / 4 = 137.5 MHz + .pllR = 2, // 250 MHz / 2 = 275 MHz + }; + Rcc::enablePll1(Rcc::PllSource::Hse, pllFactors1); + + // Use PLL2 for FDCAN 120MHz + const Rcc::PllFactors pllFactors2{ + .range = Rcc::PllInputRange::MHz1_2, + .pllM = 4, // 8MHz / M= 2MHz + .pllN = 120, // 2MHz * N= 240MHz + .pllP = 2, // 240MHz / P= 120MHz + .pllQ = 2, // 240MHz / Q= 120MHz + .pllR = 2, // 240MHz / R= 120MHz + }; + Rcc::enablePll2(Rcc::PllSource::ExternalClock, pllFactors2); + Rcc::setCanClockSource(Rcc::CanClockSource::Pll2Q); + + // Use PLL3 for USB 48MHz + const Rcc::PllFactors pllFactors3{ + .range = Rcc::PllInputRange::MHz4_8, + .pllM = 2, // 8MHz / M= 4MHz + .pllN = 60, // 4MHz * N= 240MHz + .pllP = 5, // 240MHz / P= 48MHz + .pllQ = 5, // 240MHz / Q= 48MHz = F_usb + .pllR = 5, // 240MHz / R= 48MHz + }; + Rcc::enablePll3(Rcc::PllSource::ExternalClock, pllFactors3); + Rcc::setFlashLatency(); + + // max. 275MHz + Rcc::setAhbPrescaler(Rcc::AhbPrescaler::Div2); + // max. 137.5MHz on Apb clocks + Rcc::setApb1Prescaler(Rcc::Apb1Prescaler::Div2); + Rcc::setApb2Prescaler(Rcc::Apb2Prescaler::Div2); + Rcc::setApb3Prescaler(Rcc::Apb3Prescaler::Div2); + Rcc::setApb4Prescaler(Rcc::Apb4Prescaler::Div2); + + // update clock frequencies + Rcc::updateCoreFrequency(); + Rcc::enableUsbClockSource(Rcc::UsbClockSource::Pll3Q); + // switch system clock to pll + Rcc::enableSystemClock(Rcc::SystemClockSource::Pll1P); + + return true; + } + +}; + +// Arduino Footprint +#include "nucleo64_arduino.hpp" + +using Button = GpioInputC13; + +using Led = GpioOutputB0; +using Leds = SoftwareGpioPort< Led >; +/// @} + +namespace usb +{ +/// @ingroup modm_board_nucleo_h503rb +/// @{ +using Vbus = GpioA9; +using Id = GpioA10; +using Dm = GpioA11; +using Dp = GpioA12; + +using Overcurrent = GpioInputD2; +using Power = GpioC10; + +using Device = UsbFs; +/// @} +} + +namespace stlink +{ +/// @ingroup modm_board_nucleo_h503rb +/// @{ +using Tx = GpioOutputA4; +using Rx = GpioInputA3; +using Uart = BufferedUart>; +/// @} +} + +/// @ingroup modm_board_nucleo_h503rb +/// @{ +using LoggerDevice = modm::IODeviceWrapper< stlink::Uart, modm::IOBuffer::BlockIfFull >; + +inline void +initialize() +{ + SystemClock::enable(); + SysTickTimer::initialize(); + + stlink::Uart::connect(); + stlink::Uart::initialize(); + + Led::setOutput(modm::Gpio::Low); + + Button::setInput(); +} + +inline void +initializeUsbFs(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_HS->GCCFG |= USB_OTG_GCCFG_VBDEN; +} +/// @} + +} + diff --git a/src/modm/board/nucleo_h503rb/board.xml b/src/modm/board/nucleo_h503rb/board.xml new file mode 100644 index 0000000000..0015ca0d00 --- /dev/null +++ b/src/modm/board/nucleo_h503rb/board.xml @@ -0,0 +1,14 @@ + + + + ../../../../repo.lb + + + + + + + + modm:board:nucleo-h503rb + + diff --git a/src/modm/board/nucleo_h503rb/module.lb b/src/modm/board/nucleo_h503rb/module.lb new file mode 100644 index 0000000000..294f81b52b --- /dev/null +++ b/src/modm/board/nucleo_h503rb/module.lb @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# Copyright (c) 2016-2018, Niklas Hauser +# Copyright (c) 2017, Fabian Greif +# +# 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-h503rb" + module.description = """\ +# NUCLEO-H503RB + +[Nucleo kit for STM32H503RB](https://www.st.com/en/evaluation-tools/nucleo-h503rb.html) + +## TinyUSB + +To use the USB port, you must configure TinyUSB to use the HS port in FS mode: + +```xml + +``` +""" + +def prepare(module, options): + if not options[":target"].partname.startswith("stm32h503rbt"): + return False + + module.depends( + ":debug", + ":architecture:clock", + ":platform:core", + ":platform:gpio", + ":platform:clock", + ":platform:uart:3", + ":platform:usb") + + 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("../nucleo64_arduino.hpp", "nucleo64_arduino.hpp") + env.outbasepath = "modm/openocd/modm/board/" + # env.copy(repopath("tools/openocd/modm/st_nucleo_h503rb.cfg"), "st_nucleo_h503rb.cfg") + # env.collect(":build:openocd.source", "modm/board/st_nucleo_h503rb.cfg") diff --git a/src/modm/board/nucleo_h503rb/startup.cpp b/src/modm/board/nucleo_h503rb/startup.cpp new file mode 100644 index 0000000000..425f1ffc17 --- /dev/null +++ b/src/modm/board/nucleo_h503rb/startup.cpp @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2021, Christopher Durand + * + * 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 modm::platform; + +extern "C" void +modm_initialize_platform(void) +{ + // Configure internal voltage regulator + Rcc::configurePowerSource(Rcc::PowerSource::Ldo); +} diff --git a/src/modm/platform/clock/stm32/module.lb b/src/modm/platform/clock/stm32/module.lb index 31fc0313a1..69857aab70 100644 --- a/src/modm/platform/clock/stm32/module.lb +++ b/src/modm/platform/clock/stm32/module.lb @@ -43,7 +43,7 @@ def build(env): properties["hsi_frequency"] = 8_000_000 properties["lsi_frequency"] = 40_000 properties["boot_frequency"] = properties["hsi_frequency"] - elif target["family"] in ["h7"]: + elif target["family"] in ["h5", "h7"]: properties["hsi_frequency"] = 64_000_000 properties["lsi_frequency"] = 32_000 properties["boot_frequency"] = properties["hsi_frequency"] @@ -89,7 +89,7 @@ def build(env): properties["pllsai_p_usb"] = (target["family"] == "f7") or \ ((target["family"] == "f4") and target["name"] in ["46", "69", "79"]) - if target.family in ["h7"]: + if target.family in ["h5", "h7"]: if target.name in ["a3", "b0", "b3"]: properties["cfgr_prescaler"] = "CDCFGR1" else: @@ -99,7 +99,7 @@ def build(env): else: properties["cfgr_prescaler"] = "CFGR" - if target.family in ["h7"]: + if target.family in ["h5", "h7"]: if target.name in ["a3", "b0", "b3"]: properties["cfgr2"] = "CDCFGR2" else: @@ -109,7 +109,7 @@ def build(env): else: properties["cfgr2"] = "CFGR" - if target.family in ["h7"]: + if target.family in ["h5", "h7"]: if target.name in ["a3", "b0", "b3"]: properties["ccipr1"] = "CDCCIP1R" else: diff --git a/src/modm/platform/clock/stm32/rcc.cpp.in b/src/modm/platform/clock/stm32/rcc.cpp.in index e3c471f357..38347c3af4 100644 --- a/src/modm/platform/clock/stm32/rcc.cpp.in +++ b/src/modm/platform/clock/stm32/rcc.cpp.in @@ -160,7 +160,7 @@ Rcc::enableLowSpeedExternalCrystal(uint32_t waitCycles) bool Rcc::enablePll{{id}}(PllSource source, const PllFactors& pllFactors, uint32_t waitCycles) { -%% if target.family == "h7" +%% if target.family in ["h5", "h7"] // set the PLL{{id}} source and DIVM{{id}} prescaler uint32_t tmp = RCC->PLLCKSELR & ~(RCC_PLLCKSELR_PLLSRC | RCC_PLLCKSELR_DIVM{{id}}); tmp |= uint32_t(source); @@ -504,7 +504,7 @@ Rcc::setVoltageScaling(VoltageScaling voltage, uint32_t waitCycles) if (--waitCycles == 0) return false; return true; } -%% elif target.family == "h7" +%% elif target.family in ["h5", "h7"] bool Rcc::setVoltageScaling(VoltageScaling voltage, uint32_t waitCycles) { diff --git a/src/modm/platform/clock/stm32/rcc.hpp.in b/src/modm/platform/clock/stm32/rcc.hpp.in index 8fc79b21a6..070f381090 100644 --- a/src/modm/platform/clock/stm32/rcc.hpp.in +++ b/src/modm/platform/clock/stm32/rcc.hpp.in @@ -60,7 +60,7 @@ public: enum class PllSource : uint32_t { -%% if target.family == "h7" +%% if target.family in ["h7"] /// High speed internal clock (4-64 MHz) Hsi = RCC_PLLCKSELR_PLLSRC_HSI, InternalClock = Hsi, @@ -110,7 +110,7 @@ public: /// Multi speed internal clock Msi = RCC_PLLCFGR_PLLSRC_0, MultiSpeedInternalClock = Msi, -%% elif target.family in ["u5"] +%% elif target.family in ["h5", "u5"] None = 0b00, MsiS = 0b01, Hsi16 = 0b10, @@ -183,7 +183,7 @@ public: InternalClock = Hsi, ExternalClock = Hse, ExternalCrystal = Hse, -%% if target.family == "h7" +%% if target.family in ["h5", "h7"] Pll1P = RCC_CFGR_SW_PLL1, %% else Pll = RCC_CFGR_SW_PLL, @@ -295,7 +295,7 @@ public: }; %% endif -%% if target.family == "h7" +%% if target.family in ["h5", "h7"] enum class Apb3Prescaler : uint32_t { @@ -405,7 +405,7 @@ public: Pll = RCC_CFGR_MCO2_1 | RCC_CFGR_MCO2_0, }; %% endif -%% elif target.family in ["h7"] +%% elif target.family in ["h5", "h7"] enum class ClockOutput1Source : uint32_t { @@ -478,7 +478,7 @@ public: }; %% endif -%% if target.family in ["g4", "l5", "u5", "h7"] +%% if target.family in ["g4", "l5", "u5", "h5", "h7"] enum class CanClockSource : uint32_t { @@ -492,7 +492,7 @@ public: %% elif target.family in ["u5"] Pll1Q = 0b01 << RCC_{{ccipr1}}_FDCANSEL_Pos, Pll2P = 0b10 << RCC_{{ccipr1}}_FDCANSEL_Pos, -%% elif target.family in ["h7"] +%% elif target.family in ["h5", "h7"] Pll1Q = 0b01 << RCC_{{ccipr1}}_FDCANSEL_Pos, Pll2Q = 0b10 << RCC_{{ccipr1}}_FDCANSEL_Pos, %% endif @@ -651,7 +651,7 @@ public: %% if target.family != "c0" struct PllFactors { -%% if target.family in ["h7"] +%% if target.family in ["h5", "h7"] PllInputRange range; uint8_t pllM; uint16_t pllN; @@ -816,7 +816,7 @@ public: } %% endif -%% if target.family == "h7" +%% if target.family in ["h5", "h7"] enum class UsbClockSource : uint32_t { @@ -852,7 +852,7 @@ public: return true; } %% endif -%% elif target.family in ["h7"] +%% elif target.family in ["h5", "h7"] static inline bool enableClockOutput1(ClockOutput1Source src, uint8_t div) { @@ -941,7 +941,7 @@ public: } %% endif -%% if target.family == "h7" +%% if target.family in ["h5", "h7"] static inline bool setApb3Prescaler(Apb3Prescaler prescaler) { @@ -969,7 +969,7 @@ public: enableOverdriveMode(uint32_t waitCycles = 2048); %% endif -%% if target.family == "h7" +%% if target.family in ["h5", "h7"] enum class VoltageScaling : uint32_t { diff --git a/src/modm/platform/clock/stm32/rcc_impl.hpp.in b/src/modm/platform/clock/stm32/rcc_impl.hpp.in index e1ce1aff37..f2602608b8 100644 --- a/src/modm/platform/clock/stm32/rcc_impl.hpp.in +++ b/src/modm/platform/clock/stm32/rcc_impl.hpp.in @@ -80,7 +80,7 @@ Rcc::setFlashLatency() %% elif target["family"] in ["u5"] // enable flash prefetch acr |= FLASH_ACR_PRFTEN; -%% elif target["family"] not in ["h7", "l5"] +%% elif target["family"] not in ["h5", "h7", "l5"] // enable flash prefetch acr |= FLASH_ACR_PRFTBE; %% endif diff --git a/src/modm/platform/core/stm32/module.lb b/src/modm/platform/core/stm32/module.lb index de7c732d45..86478b8b49 100644 --- a/src/modm/platform/core/stm32/module.lb +++ b/src/modm/platform/core/stm32/module.lb @@ -61,6 +61,7 @@ def build(env): "l0": (3, 4), # CM0+ tested on L031 in RAM "g0": (3, 4), # CM0+ tested on G072 in RAM "f7": (4, 4), # CM7 tested on F767 in ITCM + "h5": (4, 4), # CM7 tested on H503 in ITCM "h7": (4, 4), # CM7 tested on H743 in ITCM "l4": (3, 4), # CM4 tested on L476 in SRAM2 "l5": (3, 4), # CM33 tested on L552 in RAM diff --git a/src/modm/platform/gpio/stm32/data.hpp.in b/src/modm/platform/gpio/stm32/data.hpp.in index 3a31b44795..69f70191e0 100644 --- a/src/modm/platform/gpio/stm32/data.hpp.in +++ b/src/modm/platform/gpio/stm32/data.hpp.in @@ -17,7 +17,7 @@ namespace modm::platform::detail { -%% if target.family in ["h7"] +%% if target.family in ["h5", "h7"] enum class AdcPolarity { @@ -26,7 +26,7 @@ AdcPolarity }; %% endif template struct SignalConnection; -template static constexpr int8_t AdcChannel = -1; +template static constexpr int8_t AdcChannel = -1; template static constexpr int8_t DacChannel = -1; struct DataUnused {}; diff --git a/src/modm/platform/gpio/stm32/enable.cpp.in b/src/modm/platform/gpio/stm32/enable.cpp.in index 68e20eee54..63efcbad21 100644 --- a/src/modm/platform/gpio/stm32/enable.cpp.in +++ b/src/modm/platform/gpio/stm32/enable.cpp.in @@ -26,7 +26,7 @@ modm_gpio_enable(void) %% elif target.family in ["f1"] %% set clock_tree = "APB2" %% set prefix = "IOP" -%% elif target.family in ["l4", "l5", "g4", "u5"] +%% elif target.family in ["l4", "l5", "g4", "h5", "u5"] %% set clock_tree = 'AHB2' %% elif target.family in ["c0", "g0", "l0"] %% set clock_tree = 'IOP'