diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml
index b9f7f41632..f118087086 100644
--- a/.github/workflows/linux.yml
+++ b/.github/workflows/linux.yml
@@ -148,7 +148,7 @@ jobs:
- name: Examples STM32H7 Series
if: always()
run: |
- (cd examples && ../tools/scripts/examples_compile.py nucleo_h743zi nucleo_h723zg stm32h750vbt6_devebox)
+ (cd examples && ../tools/scripts/examples_compile.py nucleo_h743zi nucleo_h723zg stm32h750vbt6_devebox nucleo_h755zi-q)
stm32f4-examples-1:
runs-on: ubuntu-20.04
diff --git a/README.md b/README.md
index 7e0515231e..cebd2ba00b 100644
--- a/README.md
+++ b/README.md
@@ -78,9 +78,9 @@ git clone --recurse-submodules --jobs 8 https://github.com/modm-io/modm.git
## Microcontrollers
-modm can create a HAL for 3287 devices of these vendors:
+modm can create a HAL for 3385 devices of these vendors:
-- STMicroelectronics STM32: 2712 devices.
+- STMicroelectronics STM32: 2810 devices.
- Microchip SAM: 186 devices.
- Microchip AVR: 388 devices.
- Raspberry Pi: 1 device.
@@ -595,26 +595,27 @@ We have out-of-box support for many development boards including documentation.
NUCLEO-H723ZG |
NUCLEO-H743ZI |
+NUCLEO-H755ZI-Q |
NUCLEO-L031K6 |
NUCLEO-L053R8 |
NUCLEO-L152RE |
-NUCLEO-L432KC |
+NUCLEO-L432KC |
NUCLEO-L452RE |
NUCLEO-L476RG |
NUCLEO-L496ZG-P |
-NUCLEO-L552ZE-Q |
+NUCLEO-L552ZE-Q |
OLIMEXINO-STM32 |
Raspberry Pi |
Raspberry Pi Pico |
-SAMD21-MINI |
+SAMD21-MINI |
SAMG55-XPLAINED-PRO |
Smart Response XE |
STM32-F4VE |
-STM32F030-DEMO |
+STM32F030-DEMO |
diff --git a/examples/nucleo_h755zi-q/blink/cm4/main.cpp b/examples/nucleo_h755zi-q/blink/cm4/main.cpp
new file mode 100644
index 0000000000..c0065bca7c
--- /dev/null
+++ b/examples/nucleo_h755zi-q/blink/cm4/main.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2022, 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 Board;
+
+int
+main()
+{
+ Board::initialize();
+
+ while(1)
+ {
+ LedGreen::toggle();
+ modm::delay_ms(1000);
+ }
+ return 0;
+}
diff --git a/examples/nucleo_h755zi-q/blink/cm4/project.xml b/examples/nucleo_h755zi-q/blink/cm4/project.xml
new file mode 100644
index 0000000000..2d9110330e
--- /dev/null
+++ b/examples/nucleo_h755zi-q/blink/cm4/project.xml
@@ -0,0 +1,10 @@
+
+ modm:nucleo-h755zi-q
+
+
+
+
+
+ modm:build:scons
+
+
diff --git a/examples/nucleo_h755zi-q/blink/cm7/main.cpp b/examples/nucleo_h755zi-q/blink/cm7/main.cpp
new file mode 100644
index 0000000000..d0b7aa0b54
--- /dev/null
+++ b/examples/nucleo_h755zi-q/blink/cm7/main.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2022, Christopher Durand
+ * 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();
+ Leds::setOutput();
+
+ // 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);
+
+ LedYellow::set();
+ while (true)
+ {
+ LedYellow::toggle();
+ LedRed::toggle();
+ modm::delay(Button::read() ? 100ms : 500ms);
+
+ MODM_LOG_INFO << "loop: " << counter++ << modm::endl;
+ }
+
+ return 0;
+}
diff --git a/examples/nucleo_h755zi-q/blink/cm7/project.xml b/examples/nucleo_h755zi-q/blink/cm7/project.xml
new file mode 100644
index 0000000000..90022d3ec0
--- /dev/null
+++ b/examples/nucleo_h755zi-q/blink/cm7/project.xml
@@ -0,0 +1,10 @@
+
+ modm:nucleo-h755zi-q
+
+
+
+
+
+ modm:build:scons
+
+
diff --git a/ext/modm-devices b/ext/modm-devices
index c0022f2eaa..0a9ac3529a 160000
--- a/ext/modm-devices
+++ b/ext/modm-devices
@@ -1 +1 @@
-Subproject commit c0022f2eaaf0fb66b18f93e0113bd35264c171e6
+Subproject commit 0a9ac3529a7b2cd58410d01a08201cc52faf5867
diff --git a/ext/st/module.lb b/ext/st/module.lb
index ecb38e4859..8a830ce375 100644
--- a/ext/st/module.lb
+++ b/ext/st/module.lb
@@ -124,6 +124,7 @@ def common_header_file(env):
family_header = folder + ".h"
folder = "stm32/{}/Include".format(folder)
define = None
+ core_define = "CORE_CM{}".format(core) if device.identifier.get("core") else None
content = Path(localpath(folder, family_header)).read_text(encoding="utf-8", errors="replace")
match = re.findall(r"if defined\((?PSTM32[FLGH][\w\d]+)\)", content)
@@ -136,6 +137,7 @@ def common_header_file(env):
headers = {
"define": define,
"family_define": family_define,
+ "core_define": core_define,
"core_header": core_header,
"device_header": device_header,
"family_header": family_header,
@@ -179,7 +181,7 @@ def build(env):
env.substitutions = bprops
env.substitutions.update({
"headers": [bprops["device_header"], bprops["system_header"]],
- "defines": [bprops["define"]],
+ "defines": [bprops["define"]] + ([bprops["core_define"]] if bprops["core_define"] is not None else []),
"target": env[":target"].identifier,
})
env.outbasepath = "modm/src/modm/platform"
diff --git a/src/modm/board/nucleo144_arduino_h745_55.hpp b/src/modm/board/nucleo144_arduino_h745_55.hpp
new file mode 100644
index 0000000000..a78b3308ab
--- /dev/null
+++ b/src/modm/board/nucleo144_arduino_h745_55.hpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2022, Christopher Durand
+ * Copyright (c) 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/.
+ */
+// ----------------------------------------------------------------------------
+
+// Nucleo144 Arduino Header Footprint
+
+#ifndef MODM_STM32_NUCLEO144_ARDUINO_H745_55_HPP
+#define MODM_STM32_NUCLEO144_ARDUINO_H745_55_HPP
+
+// Arduino Footprint
+using A0 = GpioA3;
+using A1 = GpioC0;
+using A2 = GpioC3;
+using A3 = GpioB1;
+using A4 = GpioC2;
+using A5 = GpioF11;
+// Zio Footprint
+using A6 = GpioF6;
+using A7 = GpioF10;
+using A8 = GpioA2; // RMII_MDIO
+
+// Arduino Footprint
+using D0 = GpioB7;
+using D1 = GpioB6;
+using D2 = GpioG14;
+using D3 = GpioE13;
+using D4 = GpioE14;
+using D5 = GpioE11;
+using D6 = GpioA8;
+using D7 = GpioG12; // SMPS PG
+using D8 = GpioG9; // SMPS EN
+using D9 = GpioD15;
+using D10 = GpioD14;
+using D11 = GpioB5;
+using D12 = GpioA6;
+using D13 = GpioA5;
+using D14 = GpioB9;
+using D15 = GpioB8;
+// Zio Footprint
+using D16 = GpioC6;
+using D17 = GpioB15;
+using D18 = GpioB13; // RMII TXD1
+using D19 = GpioB12;
+using D20 = GpioA15;
+using D21 = GpioC7;
+using D22 = GpioB5;
+using D23 = GpioB3; // SWO
+using D24 = GpioA4;
+using D25 = GpioB4;
+using D26 = GpioG6;
+using D27 = GpioB2;
+using D28 = GpioD13;
+using D29 = GpioD12;
+using D30 = GpioD11;
+using D31 = GpioE2;
+using D32 = GpioA0;
+using D33 = GpioB0;
+using D34 = GpioE0;
+using D35 = GpioB11;
+using D36 = GpioB10;
+using D37 = GpioE15;
+using D38 = GpioE6;
+using D39 = GpioE12;
+using D40 = GpioE10;
+using D41 = GpioE7;
+using D42 = GpioE8;
+using D43 = GpioC8;
+using D44 = GpioC9;
+using D45 = GpioC10;
+using D46 = GpioC11;
+using D47 = GpioC12;
+using D48 = GpioD2;
+using D49 = GpioG10; // SMPS_SW
+using D50 = GpioG8; // SMPS V1
+using D51 = GpioD7;
+using D52 = GpioD6;
+using D53 = GpioD5;
+using D54 = GpioD4;
+using D55 = GpioD3;
+using D56 = GpioE2;
+using D57 = GpioE4;
+using D58 = GpioE5;
+using D59 = GpioE6;
+using D60 = GpioE3;
+using D61 = GpioF8;
+using D62 = GpioF7;
+using D63 = GpioF9;
+using D64 = GpioD10; // USB_FS_PWR_EN
+using D65 = GpioB14; // LED RED
+using D66 = GpioD1;
+using D67 = GpioD0;
+using D68 = GpioF15;
+using D69 = GpioF14;
+using D70 = GpioB5;
+using D71 = GpioE9;
+using D72 = GpioB2;
+
+#endif // MODM_STM32_NUCLEO144_ARDUINO_H745_55_HPP
diff --git a/src/modm/board/nucleo_h755zi-q/board.hpp b/src/modm/board/nucleo_h755zi-q/board.hpp
new file mode 100644
index 0000000000..9ec82473f1
--- /dev/null
+++ b/src/modm/board/nucleo_h755zi-q/board.hpp
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2021-2022, 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_h755zi-q
+#define MODM_BOARD_HAS_LOGGER
+
+namespace Board
+{
+/// @ingroup modm_board_nucleo_h755zi-q
+/// @{
+using namespace modm::literals;
+
+/// STM32H755 running at 480MHz from the external 8MHz HSE
+struct SystemClock
+{
+ static constexpr uint32_t SysClk = 480_MHz;
+
+ // Max 480MHz
+ static constexpr uint32_t Hclk = SysClk / 1; // D1CPRE
+ // Max 240MHz
+ static constexpr uint32_t Ahb = Hclk / 2; // HPRE
+
+#ifdef CORE_CM7
+ static constexpr uint32_t Frequency = Hclk;
+#else
+ static constexpr uint32_t Frequency = Ahb;
+#endif
+
+ // Max 240MHz
+ 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 120MHz
+ 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 Dac2 = Apb1;
+
+ static constexpr uint32_t Spi1 = Apb2;
+ static constexpr uint32_t Spi2 = Apb1;
+ static constexpr uint32_t Spi3 = Apb1;
+ 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 LpUart1 = Apb4;
+
+ static constexpr uint32_t Can1 = Apb1;
+ static constexpr uint32_t Can2 = Apb1;
+
+ 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 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 Usb = 48_MHz;
+
+#ifdef CORE_CM7
+ static bool inline
+ enable()
+ {
+ Rcc::enableExternalClock(); // 8 MHz
+ Rcc::setVoltageScaling(Rcc::VoltageScaling::Scale0); // required for 480MHz
+ const Rcc::PllFactors pllFactors {
+ .range = Rcc::PllInputRange::MHz4_8,
+ .pllM = 1, // 8MHz / M= 8MHz
+ .pllN = 120, // 8MHz * N= 960MHz
+ .pllP = 2, // 960MHz / P= 480MHz = F_cpu
+ .pllQ = 20, // 960MHz / Q= 48MHz
+ .pllR = 2, // 960MHz / R= 480MHz
+ };
+ Rcc::enablePll1(Rcc::PllSource::ExternalClock, pllFactors);
+ Rcc::setFlashLatency();
+ // max 240MHz on AHB
+ Rcc::setAhbPrescaler(Rcc::AhbPrescaler::Div2);
+ // max 120MHz on APB
+ 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::Pll1Q);
+ // Switch the main clock source to PLL
+ Rcc::enableSystemClock(Rcc::SystemClockSource::Pll1P);
+ return true;
+ }
+#else
+ static bool inline
+ enable()
+ {
+ Rcc::updateCoreFrequency();
+ return true;
+ }
+#endif
+};
+
+// Arduino Footprint
+#include "nucleo144_arduino_h745_55.hpp"
+
+using Button = GpioInputC13;
+
+using LedGreen = GpioOutputB0;
+using LedYellow = GpioOutputE1;
+using LedRed = GpioOutputB14;
+using Leds = SoftwareGpioPort;
+
+namespace usb
+{
+using Vbus = GpioA9;
+using Id = GpioA10;
+using Dm = GpioA11;
+using Dp = GpioA12;
+
+using Overcurrent = GpioInputG7; // OTG_FS_OverCurrent
+using Power = GpioOutputD10; // OTG_FS_PowerSwitchOn
+
+using Device = UsbFs;
+}
+
+namespace stlink
+{
+using Tx = GpioOutputD8;
+using Rx = GpioInputD9;
+using Uart = Usart3;
+}
+
+#ifdef CORE_CM7
+using LoggerDevice = modm::IODeviceWrapper;
+#endif
+
+inline void
+initialize()
+{
+ SystemClock::enable();
+ SysTickTimer::initialize();
+
+#ifdef CORE_CM7
+ Rcc::bootCortexM4();
+
+ stlink::Uart::connect();
+ stlink::Uart::initialize();
+
+ LedGreen::setOutput(modm::Gpio::Low);
+ LedYellow::setOutput(modm::Gpio::Low);
+ LedRed::setOutput(modm::Gpio::Low);
+
+ Button::setInput();
+#endif
+}
+
+inline void
+initializeUsbFs(uint8_t priority=3)
+{
+ usb::Device::initialize(priority);
+ usb::Device::connect();
+ usb::Id::configure(Gpio::InputType::Floating);
+
+ usb::Overcurrent::setInput();
+ usb::Vbus::setInput();
+ // Enable VBUS sense (B device) via pin PA9
+ USB_OTG_FS->GCCFG |= USB_OTG_GCCFG_VBDEN;
+}
+
+}
+/// @}
+
diff --git a/src/modm/board/nucleo_h755zi-q/board.xml b/src/modm/board/nucleo_h755zi-q/board.xml
new file mode 100644
index 0000000000..8996b6ffd5
--- /dev/null
+++ b/src/modm/board/nucleo_h755zi-q/board.xml
@@ -0,0 +1,18 @@
+
+
+
+ ../../../../repo.lb
+
+
+
+
+
+
+
+
+
+
+
+ modm:board:nucleo-h755zi-q
+
+
diff --git a/src/modm/board/nucleo_h755zi-q/module.lb b/src/modm/board/nucleo_h755zi-q/module.lb
new file mode 100644
index 0000000000..6a7c0b56d8
--- /dev/null
+++ b/src/modm/board/nucleo_h755zi-q/module.lb
@@ -0,0 +1,67 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2022, Christopher Durand
+# 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-h755zi-q"
+ module.description = """\
+# NUCLEO-H755ZI-Q
+
+[Nucleo kit for STM32H755ZI-Q](https://www.st.com/en/evaluation-tools/nucleo-h755zi-q.html)
+
+The "modm:target" has to be configured in `project.xml` to select between the
+Cortex-M7 and Cortex-M4 applications:
+
+```xml
+
+ modm:nucleo-h755zi-q
+
+
+
+
+ …
+
+```
+
+The STLink UART logger is only available from the Cortex-M7 core.
+
+This BSP assumes the default boot addresses are configured in the option bytes
+for both cores.
+
+"""
+
+def prepare(module, options):
+ if not options[":target"].partname.startswith("stm32h755zit"):
+ 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": env[":target"].identifier.core == "m7",
+ "with_assert": env.has_module(":architecture:assert")
+ }
+ env.template("../board.cpp.in", "board.cpp")
+ env.copy('.')
+ env.copy("../nucleo144_arduino_h745_55.hpp", "nucleo144_arduino_h745_55.hpp")
+ env.collect(":build:openocd.source", "board/st_nucleo_h745zi.cfg");
diff --git a/src/modm/board/nucleo_h755zi-q/startup.cpp b/src/modm/board/nucleo_h755zi-q/startup.cpp
new file mode 100644
index 0000000000..3f227009b1
--- /dev/null
+++ b/src/modm/board/nucleo_h755zi-q/startup.cpp
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2022, 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;
+
+#ifdef CORE_CM7
+
+extern "C" void
+modm_initialize_platform(void)
+{
+ // Configure switch mode power supply
+ Rcc::configurePowerSource(Rcc::PowerSource::SmpsDirect);
+}
+
+#endif
diff --git a/src/modm/platform/clock/stm32/rcc.cpp.in b/src/modm/platform/clock/stm32/rcc.cpp.in
index 3e1c73ae44..9a4f096ed2 100644
--- a/src/modm/platform/clock/stm32/rcc.cpp.in
+++ b/src/modm/platform/clock/stm32/rcc.cpp.in
@@ -529,4 +529,22 @@ Rcc::setCanPrescaler(CanPrescaler prescaler)
}
%% endif
+%% if target.family == "h7" and target.name in ["45", "47", "55", "57"] and target.core == "m7"
+void
+Rcc::bootCortexM4()
+{
+ // Enable Cortex-M4 boot in case it is disabled via option bytes
+ RCC->GCR |= RCC_GCR_BOOT_C2;
+
+ // Lock hardware semaphore 0
+ // Cortex-M4 startup code will continue to boot
+ RCC->AHB4ENR |= RCC_AHB4ENR_HSEMEN_Msk;
+ constexpr unsigned CortexM7CoreId{3};
+ HSEM->R[0] = HSEM_R_LOCK | (CortexM7CoreId << HSEM_R_COREID_Pos);
+
+ // Wait for unlock by Cortex-M4 core
+ while((HSEM->R[0] & HSEM_R_LOCK) != 0);
+}
+%% endif
+
}
diff --git a/src/modm/platform/clock/stm32/rcc.hpp.in b/src/modm/platform/clock/stm32/rcc.hpp.in
index b91529ef38..7606e17c88 100644
--- a/src/modm/platform/clock/stm32/rcc.hpp.in
+++ b/src/modm/platform/clock/stm32/rcc.hpp.in
@@ -865,6 +865,17 @@ public:
setVoltageScaling(VoltageScaling voltage, uint32_t waitCycles = 2048);
%% endif
+%% if target.family == "h7" and target.name in ["45", "47", "55", "57"] and target.core == "m7"
+ /**
+ * Release lock in Cortex-M4 startup code to continue boot. Call this function
+ * after system initialization has been completed.
+ *
+ * In case automatic Cortex-M4 boot is disabled in the option bytes, the core will
+ * be enabled.
+ */
+ static void bootCortexM4();
+%% endif
+
public:
/** Set flash latency for CPU frequency and voltage.
* Does nothing if CPU frequency is too high for the available
diff --git a/src/modm/platform/clock/systick/module.lb b/src/modm/platform/clock/systick/module.lb
index cb0681e145..8aacee6b98 100644
--- a/src/modm/platform/clock/systick/module.lb
+++ b/src/modm/platform/clock/systick/module.lb
@@ -36,7 +36,8 @@ def build(env):
# Interrupt Frequency must not overflow the 2^24 SysTick->VAL!
freq = 1000 if "m0" in core else 4
# STM32H7 goes up to 550MHz, so make the Frequency higher
- if target.family == "h7": freq = 100;
+ if target.family == "h7" and target.get("core", "cm7") == "cm7":
+ freq = 100
# SysTick clock prescaler is dynamically chosen as /1 or /8
div = 8
diff --git a/src/modm/platform/core/stm32/module.lb b/src/modm/platform/core/stm32/module.lb
index bc0bfe6518..f244a7afb8 100644
--- a/src/modm/platform/core/stm32/module.lb
+++ b/src/modm/platform/core/stm32/module.lb
@@ -80,6 +80,19 @@ def build(env):
env.template("../cortex/delay_ns.hpp.in", "delay_ns.hpp")
env.template("../cortex/delay_impl.hpp.in", "delay_impl.hpp")
+def _get_memory_by_address(memories, address):
+ for memory in memories:
+ start = memory["start"]
+ end = start + memory["size"]
+ if address >= start and address < end:
+ return memory
+ raise KeyError("No memory found containing address '0x{:x}'".format(address))
+
+def _get_memory_by_name(memories, name):
+ for memory in memories:
+ if memory["name"] == name:
+ return memory
+ raise KeyError("No memory found with name '{}'".format(name))
def post_build(env):
env.substitutions = env.query("::cortex-m:linkerscript")
@@ -89,7 +102,49 @@ def post_build(env):
linkerscript = "../cortex/ram.ld.in"
if env.get(":platform:core:vector_table_location", "rom") == "ram":
linkerscript = "ram_remap_vector_table.ld.in"
- for memory in env.substitutions["memories"]:
+
+ identifier = env[":target"].identifier
+ memories = env.substitutions["memories"]
+
+ # H7 dual-core devices
+ if identifier.family == "h7" and identifier.get("core"):
+ # only use half of flash for each core of H7 dual core devices
+ # TODO: allow non-default configurations with custom boot addresses
+ core = identifier.core
+ if identifier.size == "i":
+ # one contiguous segment of flash organized in two banks
+ # bank 0: 0x0800 0000 - 0x080F FFFF, used for CM7 program
+ # bank 1: 0x0810 0000 - 0x081F FFFF, used for CM4 program
+ flash = _get_memory_by_address(memories, 0x08000000)
+ flash["size"] //= 2
+ if core == "m4":
+ flash["start"] += flash["size"]
+ elif identifier.size == "g":
+ # two discontiguous segments of flash
+ # bank 0: 0x0800 0000 - 0x0807 FFFF, used for CM7 program
+ # bank 1: 0x0810 0000 - 0x0817 FFFF, used for CM4 program
+ flash_bank0 = _get_memory_by_address(memories, 0x08000000)
+ flash_bank1 = _get_memory_by_address(memories, 0x08100000)
+ if core == "m7":
+ # remove flash segment used for CM4
+ memories.remove(flash_bank1)
+ flash_bank0["name"] = "flash"
+ else: # m4
+ # remove flash segment used for CM7
+ memories.remove(flash_bank0)
+ flash_bank1["name"] = "flash"
+ else:
+ raise RuntimeError("H7 dual-core devices with size '{}' are not supported!".format(identifier.size))
+
+ # place CM4 stack in local d2_sram
+ # first memory in list is used as stack
+ # move d2_sram to the beginning of the list
+ if core == "m4":
+ cont_regions = env.substitutions["cont_ram_regions"]
+ d2_sram_index = cont_regions.index(_get_memory_by_name(cont_regions, "d2_sram1"))
+ cont_regions[0], cont_regions[d2_sram_index] = cont_regions[d2_sram_index], cont_regions[0]
+
+ for memory in memories:
if memory["name"] == "ccm":
if "x" in memory["access"]:
# Executable CCM (Instruction Core-Coupled Memory)
diff --git a/src/modm/platform/core/stm32/startup_platform.c.in b/src/modm/platform/core/stm32/startup_platform.c.in
index d55eba4897..fb06a74f7d 100644
--- a/src/modm/platform/core/stm32/startup_platform.c.in
+++ b/src/modm/platform/core/stm32/startup_platform.c.in
@@ -28,6 +28,17 @@
void
__modm_initialize_platform(void)
{
+%% if target.family == "h7" and target.name in ["45", "47", "55", "57"] and target.core == "m4"
+ /* Use hardware semaphore 0 as a spin lock to delay Cortex-M4 boot until
+ * the system has been initialized by the Cortex-M7 core */
+ RCC->AHB4ENR |= RCC_AHB4ENR_HSEMEN_Msk;
+ // wait until hardware semaphore 0 has been locked by Cortex-M7
+ while((HSEM->R[0] & HSEM_R_LOCK) == 0);
+ // unlock hardware semaphore
+ const unsigned CortexM7CoreId = 3;
+ HSEM->CR = HSEM->KEYR | (CortexM7CoreId << HSEM_CR_COREID_Pos);
+%% endif
+
// Enable SYSCFG
%% if target.family == "g0"
RCC->APBENR2 |= RCC_APBENR2_SYSCFGEN;
diff --git a/src/modm/platform/gpio/stm32/enable.cpp.in b/src/modm/platform/gpio/stm32/enable.cpp.in
index ffb014b134..960c2b3258 100644
--- a/src/modm/platform/gpio/stm32/enable.cpp.in
+++ b/src/modm/platform/gpio/stm32/enable.cpp.in
@@ -59,4 +59,6 @@ modm_gpio_enable(void)
%% endfor
}
+%% if not (target.family == "h7" and target.name in ["45", "47", "55", "57"] and target.core == "m4")
MODM_HARDWARE_INIT_ORDER(modm_gpio_enable, 80);
+%% endif
diff --git a/test/all/ignored.txt b/test/all/ignored.txt
index d6ed40b370..58f3a4c51e 100644
--- a/test/all/ignored.txt
+++ b/test/all/ignored.txt
@@ -110,8 +110,3 @@ samd21e16c-uu
stm32g0b0
stm32g0b1
stm32g0c1
-# FIXME: Dual-core devices not supported yet
-stm32h745
-stm32h755
-stm32h747
-stm32h757