Skip to content

Commit 2d5bb8c

Browse files
committed
WIP STM32H5 support
1 parent da891c6 commit 2d5bb8c

File tree

17 files changed

+516
-41
lines changed

17 files changed

+516
-41
lines changed

.github/workflows/compile-all.yml

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -712,6 +712,58 @@ jobs:
712712
name: stm32g4-compile-all-2
713713
path: test/all/log
714714

715+
stm32h5-compile-all-1:
716+
if: github.event.label.name == 'ci:hal'
717+
runs-on: ubuntu-24.04
718+
container:
719+
image: ghcr.io/modm-ext/modm-build-cortex-m:2025-05-18
720+
steps:
721+
- name: Check out repository
722+
uses: actions/checkout@v4
723+
with:
724+
submodules: 'recursive'
725+
- name: Fix Git permission/ownership problem
726+
run: |
727+
git config --global --add safe.directory /__w/modm/modm
728+
- name: Update lbuild
729+
run: |
730+
pip3 install --upgrade --upgrade-strategy=eager modm
731+
- name: Compile HAL for all STM32H5 Part 1
732+
run: |
733+
(cd test/all && python3 run_all.py stm32h5 --quick-remaining --split 2 --part 0)
734+
- name: Upload log artifacts
735+
if: always()
736+
uses: actions/upload-artifact@v4
737+
with:
738+
name: stm32h5-compile-all-1
739+
path: test/all/log
740+
741+
stm32h5-compile-all-2:
742+
if: github.event.label.name == 'ci:hal'
743+
runs-on: ubuntu-24.04
744+
container:
745+
image: ghcr.io/modm-ext/modm-build-cortex-m:2025-05-18
746+
steps:
747+
- name: Check out repository
748+
uses: actions/checkout@v4
749+
with:
750+
submodules: 'recursive'
751+
- name: Fix Git permission/ownership problem
752+
run: |
753+
git config --global --add safe.directory /__w/modm/modm
754+
- name: Update lbuild
755+
run: |
756+
pip3 install --upgrade --upgrade-strategy=eager modm
757+
- name: Compile HAL for all STM32H5 Part 2
758+
run: |
759+
(cd test/all && python3 run_all.py stm32h5 --quick-remaining --split 2 --part 1)
760+
- name: Upload log artifacts
761+
if: always()
762+
uses: actions/upload-artifact@v4
763+
with:
764+
name: stm32h5-compile-all-2
765+
path: test/all/log
766+
715767
stm32h7-compile-all-1:
716768
if: github.event.label.name == 'ci:hal'
717769
runs-on: ubuntu-24.04

examples/generic/blinky/project.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<library>
2-
<extends>modm:nucleo-l476rg</extends>
2+
<!-- <extends>modm:nucleo-l476rg</extends> -->
3+
<extends>modm:nucleo-h503rb</extends>
34
<options>
45
<option name="modm:build:build.path">../../../build/generic/blinky</option>
56
</options>

repo.lb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ class DevicesCache(dict):
7878
"stm32c0",
7979
"stm32f0", "stm32f1", "stm32f2", "stm32f3", "stm32f4", "stm32f7",
8080
"stm32g0", "stm32g4",
81-
"stm32h7",
81+
"stm32h5", "stm32h7",
8282
"stm32l0", "stm32l1", "stm32l4", "stm32l5",
8383
"stm32u5",
8484
)
Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
/*
2+
* Copyright (c) 2021, Christopher Durand
3+
* Copyright (c) 2021, Niklas Hauser
4+
*
5+
* This file is part of the modm project.
6+
*
7+
* This Source Code Form is subject to the terms of the Mozilla Public
8+
* License, v. 2.0. If a copy of the MPL was not distributed with this
9+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
10+
*/
11+
// ----------------------------------------------------------------------------
12+
13+
#pragma once
14+
15+
#include <modm/platform.hpp>
16+
#include <modm/architecture.hpp>
17+
#include <modm/debug.hpp>
18+
19+
using namespace modm::platform;
20+
21+
/// @ingroup modm_board_nucleo_h503rb
22+
#define MODM_BOARD_HAS_LOGGER
23+
24+
namespace Board
25+
{
26+
/// @ingroup modm_board_nucleo_h503rb
27+
/// @{
28+
using namespace modm::literals;
29+
30+
/// STM32H503RB running at 250MHz from PLL clock generated from 8 MHz HSE
31+
struct SystemClock
32+
{
33+
static constexpr uint32_t Hse = 8_MHz;
34+
35+
// Max 250MHz
36+
static constexpr uint32_t SysClk = 250_MHz;
37+
static constexpr uint32_t Pll1Q = SysClk / 4;
38+
static constexpr uint32_t Pll2Q = 120_MHz;
39+
// Max 250MHz
40+
static constexpr uint32_t Hclk = SysClk / 1; // D1CPRE
41+
static constexpr uint32_t Frequency = Hclk;
42+
// Max 125MHz
43+
static constexpr uint32_t Ahb = Hclk / 2; // HPRE
44+
static constexpr uint32_t Ahb1 = Ahb;
45+
static constexpr uint32_t Ahb2 = Ahb;
46+
static constexpr uint32_t Ahb3 = Ahb;
47+
static constexpr uint32_t Ahb4 = Ahb;
48+
// Max 62.5MHz
49+
static constexpr uint32_t Apb1 = Ahb / 2; // D2PPRE1
50+
static constexpr uint32_t Apb2 = Ahb / 2; // D2PPRE2
51+
static constexpr uint32_t Apb3 = Ahb / 2; // D1PPRE
52+
static constexpr uint32_t Apb4 = Ahb / 2; // D3PPRE
53+
54+
static constexpr uint32_t Adc1 = Ahb1;
55+
static constexpr uint32_t Adc2 = Ahb1;
56+
static constexpr uint32_t Adc3 = Ahb4;
57+
58+
static constexpr uint32_t Dac1 = Apb1;
59+
60+
static constexpr uint32_t Spi1 = Pll1Q;
61+
static constexpr uint32_t Spi2 = Pll1Q;
62+
static constexpr uint32_t Spi3 = Pll1Q;
63+
static constexpr uint32_t Spi4 = Apb2;
64+
static constexpr uint32_t Spi5 = Apb2;
65+
static constexpr uint32_t Spi6 = Apb4;
66+
67+
static constexpr uint32_t Usart1 = Apb2;
68+
static constexpr uint32_t Usart2 = Apb1;
69+
static constexpr uint32_t Usart3 = Apb1;
70+
static constexpr uint32_t Uart4 = Apb1;
71+
static constexpr uint32_t Uart5 = Apb1;
72+
static constexpr uint32_t Usart6 = Apb2;
73+
static constexpr uint32_t Uart7 = Apb1;
74+
static constexpr uint32_t Uart8 = Apb1;
75+
static constexpr uint32_t Uart9 = Apb2;
76+
static constexpr uint32_t Usart10 = Apb2;
77+
78+
static constexpr uint32_t LpUart1 = Apb4;
79+
80+
static constexpr uint32_t Fdcan1 = Pll2Q;
81+
static constexpr uint32_t Fdcan2 = Pll2Q;
82+
static constexpr uint32_t Fdcan3 = Pll2Q;
83+
84+
static constexpr uint32_t I2c1 = Apb1;
85+
static constexpr uint32_t I2c2 = Apb1;
86+
static constexpr uint32_t I2c3 = Apb1;
87+
static constexpr uint32_t I2c4 = Apb4;
88+
static constexpr uint32_t I2c5 = Apb1;
89+
90+
static constexpr uint32_t Apb1Timer = Apb1 * 2;
91+
static constexpr uint32_t Apb2Timer = Apb2 * 2;
92+
static constexpr uint32_t Timer1 = Apb2Timer;
93+
static constexpr uint32_t Timer2 = Apb1Timer;
94+
static constexpr uint32_t Timer3 = Apb1Timer;
95+
static constexpr uint32_t Timer4 = Apb1Timer;
96+
static constexpr uint32_t Timer5 = Apb1Timer;
97+
static constexpr uint32_t Timer6 = Apb1Timer;
98+
static constexpr uint32_t Timer7 = Apb1Timer;
99+
static constexpr uint32_t Timer8 = Apb2Timer;
100+
static constexpr uint32_t Timer12 = Apb1Timer;
101+
static constexpr uint32_t Timer13 = Apb1Timer;
102+
static constexpr uint32_t Timer14 = Apb1Timer;
103+
static constexpr uint32_t Timer15 = Apb2Timer;
104+
static constexpr uint32_t Timer16 = Apb2Timer;
105+
static constexpr uint32_t Timer17 = Apb2Timer;
106+
static constexpr uint32_t Timer23 = Apb1Timer;
107+
static constexpr uint32_t Timer24 = Apb1Timer;
108+
109+
static constexpr uint32_t Usb = 48_MHz; // From PLL3Q
110+
static constexpr uint32_t Iwdg = Rcc::LsiFrequency;
111+
112+
static bool inline
113+
enable()
114+
{
115+
// Switch core supply voltage to maximum level
116+
// Required for running at 250 MHz
117+
Rcc::setVoltageScaling(Rcc::VoltageScaling::Scale0);
118+
119+
Rcc::enableExternalClock(); // 8 MHz
120+
const Rcc::PllFactors pllFactors1{
121+
.range = Rcc::PllInputRange::MHz1_2,
122+
.pllM = 4, // 8 MHz / 4 = 2 MHz
123+
.pllN = 275, // 2 MHz * 275 = 250 MHz
124+
.pllP = 1, // 250 MHz / 1 = 250 MHz
125+
.pllQ = 4, // 250 MHz / 4 = 137.5 MHz
126+
.pllR = 2, // 250 MHz / 2 = 275 MHz
127+
};
128+
Rcc::enablePll1(Rcc::PllSource::Hse, pllFactors1);
129+
130+
// Use PLL2 for FDCAN 120MHz
131+
const Rcc::PllFactors pllFactors2{
132+
.range = Rcc::PllInputRange::MHz1_2,
133+
.pllM = 4, // 8MHz / M= 2MHz
134+
.pllN = 120, // 2MHz * N= 240MHz
135+
.pllP = 2, // 240MHz / P= 120MHz
136+
.pllQ = 2, // 240MHz / Q= 120MHz
137+
.pllR = 2, // 240MHz / R= 120MHz
138+
};
139+
Rcc::enablePll2(Rcc::PllSource::ExternalClock, pllFactors2);
140+
Rcc::setCanClockSource(Rcc::CanClockSource::Pll2Q);
141+
142+
// Use PLL3 for USB 48MHz
143+
const Rcc::PllFactors pllFactors3{
144+
.range = Rcc::PllInputRange::MHz4_8,
145+
.pllM = 2, // 8MHz / M= 4MHz
146+
.pllN = 60, // 4MHz * N= 240MHz
147+
.pllP = 5, // 240MHz / P= 48MHz
148+
.pllQ = 5, // 240MHz / Q= 48MHz = F_usb
149+
.pllR = 5, // 240MHz / R= 48MHz
150+
};
151+
Rcc::enablePll3(Rcc::PllSource::ExternalClock, pllFactors3);
152+
Rcc::setFlashLatency<Ahb>();
153+
154+
// max. 275MHz
155+
Rcc::setAhbPrescaler(Rcc::AhbPrescaler::Div2);
156+
// max. 137.5MHz on Apb clocks
157+
Rcc::setApb1Prescaler(Rcc::Apb1Prescaler::Div2);
158+
Rcc::setApb2Prescaler(Rcc::Apb2Prescaler::Div2);
159+
Rcc::setApb3Prescaler(Rcc::Apb3Prescaler::Div2);
160+
Rcc::setApb4Prescaler(Rcc::Apb4Prescaler::Div2);
161+
162+
// update clock frequencies
163+
Rcc::updateCoreFrequency<Frequency>();
164+
Rcc::enableUsbClockSource(Rcc::UsbClockSource::Pll3Q);
165+
// switch system clock to pll
166+
Rcc::enableSystemClock(Rcc::SystemClockSource::Pll1P);
167+
168+
return true;
169+
}
170+
171+
};
172+
173+
// Arduino Footprint
174+
#include "nucleo64_arduino.hpp"
175+
176+
using Button = GpioInputC13;
177+
178+
using Led = GpioOutputB0;
179+
using Leds = SoftwareGpioPort< Led >;
180+
/// @}
181+
182+
namespace usb
183+
{
184+
/// @ingroup modm_board_nucleo_h503rb
185+
/// @{
186+
using Vbus = GpioA9;
187+
using Id = GpioA10;
188+
using Dm = GpioA11;
189+
using Dp = GpioA12;
190+
191+
using Overcurrent = GpioInputD2;
192+
using Power = GpioC10;
193+
194+
using Device = UsbFs;
195+
/// @}
196+
}
197+
198+
namespace stlink
199+
{
200+
/// @ingroup modm_board_nucleo_h503rb
201+
/// @{
202+
using Tx = GpioOutputA4;
203+
using Rx = GpioInputA3;
204+
using Uart = BufferedUart<UsartHal3, UartTxBuffer<2048>>;
205+
/// @}
206+
}
207+
208+
/// @ingroup modm_board_nucleo_h503rb
209+
/// @{
210+
using LoggerDevice = modm::IODeviceWrapper< stlink::Uart, modm::IOBuffer::BlockIfFull >;
211+
212+
inline void
213+
initialize()
214+
{
215+
SystemClock::enable();
216+
SysTickTimer::initialize<SystemClock>();
217+
218+
stlink::Uart::connect<stlink::Tx::Tx, stlink::Rx::Rx>();
219+
stlink::Uart::initialize<SystemClock, 115200_Bd>();
220+
221+
Led::setOutput(modm::Gpio::Low);
222+
223+
Button::setInput();
224+
}
225+
226+
inline void
227+
initializeUsbFs(uint8_t priority=3)
228+
{
229+
usb::Device::initialize<SystemClock>(priority);
230+
usb::Device::connect<usb::Dm::Dm, usb::Dp::Dp, usb::Id::Id>();
231+
232+
usb::Overcurrent::setInput();
233+
usb::Vbus::setInput();
234+
// Enable VBUS sense (B device) via pin PA9
235+
USB_OTG_HS->GCCFG |= USB_OTG_GCCFG_VBDEN;
236+
}
237+
/// @}
238+
239+
}
240+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<library>
2+
<repositories>
3+
<repository>
4+
<path>../../../../repo.lb</path>
5+
</repository>
6+
</repositories>
7+
8+
<options>
9+
<option name="modm:target">stm32h503rbt6</option>
10+
</options>
11+
<modules>
12+
<module>modm:board:nucleo-h503rb</module>
13+
</modules>
14+
</library>
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
#
4+
# Copyright (c) 2016-2018, Niklas Hauser
5+
# Copyright (c) 2017, Fabian Greif
6+
#
7+
# This file is part of the modm project.
8+
#
9+
# This Source Code Form is subject to the terms of the Mozilla Public
10+
# License, v. 2.0. If a copy of the MPL was not distributed with this
11+
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
12+
# -----------------------------------------------------------------------------
13+
14+
def init(module):
15+
module.name = ":board:nucleo-h503rb"
16+
module.description = """\
17+
# NUCLEO-H503RB
18+
19+
[Nucleo kit for STM32H503RB](https://www.st.com/en/evaluation-tools/nucleo-h503rb.html)
20+
21+
## TinyUSB
22+
23+
To use the USB port, you must configure TinyUSB to use the HS port in FS mode:
24+
25+
```xml
26+
<option name="modm:tinyusb:max-speed">full</option>
27+
```
28+
"""
29+
30+
def prepare(module, options):
31+
if not options[":target"].partname.startswith("stm32h503rbt"):
32+
return False
33+
34+
module.depends(
35+
":debug",
36+
":architecture:clock",
37+
":platform:core",
38+
":platform:gpio",
39+
":platform:clock",
40+
":platform:uart:3",
41+
":platform:usb")
42+
43+
return True
44+
45+
def build(env):
46+
env.outbasepath = "modm/src/modm/board"
47+
env.substitutions = {
48+
"with_logger": True,
49+
"with_assert": env.has_module(":architecture:assert")
50+
}
51+
env.template("../board.cpp.in", "board.cpp")
52+
env.copy('.')
53+
env.copy("../nucleo64_arduino.hpp", "nucleo64_arduino.hpp")
54+
env.outbasepath = "modm/openocd/modm/board/"
55+
# env.copy(repopath("tools/openocd/modm/st_nucleo_h503rb.cfg"), "st_nucleo_h503rb.cfg")
56+
# env.collect(":build:openocd.source", "modm/board/st_nucleo_h503rb.cfg")

0 commit comments

Comments
 (0)