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