Skip to content

Commit

Permalink
WIP STM32H5 support
Browse files Browse the repository at this point in the history
  • Loading branch information
salkinium committed Dec 3, 2024
1 parent 9e480a8 commit da1d294
Show file tree
Hide file tree
Showing 14 changed files with 358 additions and 25 deletions.
3 changes: 2 additions & 1 deletion examples/generic/blinky/project.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<library>
<extends>modm:nucleo-l476rg</extends>
<!-- <extends>modm:nucleo-l476rg</extends> -->
<extends>modm:nucleo-h503rb</extends>
<options>
<option name="modm:build:build.path">../../../build/generic/blinky</option>
</options>
Expand Down
2 changes: 1 addition & 1 deletion repo.lb
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
240 changes: 240 additions & 0 deletions src/modm/board/nucleo_h503rb/board.hpp
Original file line number Diff line number Diff line change
@@ -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 <modm/platform.hpp>
#include <modm/architecture.hpp>
#include <modm/debug.hpp>

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<Ahb>();

// 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<Frequency>();
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<UsartHal3, UartTxBuffer<2048>>;
/// @}
}

/// @ingroup modm_board_nucleo_h503rb
/// @{
using LoggerDevice = modm::IODeviceWrapper< stlink::Uart, modm::IOBuffer::BlockIfFull >;

inline void
initialize()
{
SystemClock::enable();
SysTickTimer::initialize<SystemClock>();

stlink::Uart::connect<stlink::Tx::Tx, stlink::Rx::Rx>();
stlink::Uart::initialize<SystemClock, 115200_Bd>();

Led::setOutput(modm::Gpio::Low);

Button::setInput();
}

inline void
initializeUsbFs(uint8_t priority=3)
{
usb::Device::initialize<SystemClock>(priority);
usb::Device::connect<usb::Dm::Dm, usb::Dp::Dp, usb::Id::Id>();

usb::Overcurrent::setInput();
usb::Vbus::setInput();
// Enable VBUS sense (B device) via pin PA9
USB_OTG_HS->GCCFG |= USB_OTG_GCCFG_VBDEN;
}
/// @}

}

14 changes: 14 additions & 0 deletions src/modm/board/nucleo_h503rb/board.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<library>
<repositories>
<repository>
<path>../../../../repo.lb</path>
</repository>
</repositories>

<options>
<option name="modm:target">stm32h503rbt6</option>
</options>
<modules>
<module>modm:board:nucleo-h503rb</module>
</modules>
</library>
56 changes: 56 additions & 0 deletions src/modm/board/nucleo_h503rb/module.lb
Original file line number Diff line number Diff line change
@@ -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
<option name="modm:tinyusb:max-speed">full</option>
```
"""

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")
21 changes: 21 additions & 0 deletions src/modm/board/nucleo_h503rb/startup.cpp
Original file line number Diff line number Diff line change
@@ -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 <modm/platform.hpp>

using namespace modm::platform;

extern "C" void
modm_initialize_platform(void)
{
// Configure internal voltage regulator
Rcc::configurePowerSource(Rcc::PowerSource::Ldo);
}
8 changes: 4 additions & 4 deletions src/modm/platform/clock/stm32/module.lb
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Expand Down Expand Up @@ -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:
Expand All @@ -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:
Expand All @@ -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:
Expand Down
Loading

0 comments on commit da1d294

Please sign in to comment.