diff --git a/.circleci/config.yml b/.circleci/config.yml
index 45b19a7f21..1b6502504f 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -105,6 +105,10 @@ jobs:
name: Examples STM32L4 Series
command: |
(cd examples && ../tools/scripts/examples_compile.py stm32l476_discovery nucleo_l476rg nucleo_l432kc)
+ - run:
+ name: Examples STM32G4 Series
+ command: |
+ (cd examples && ../tools/scripts/examples_compile.py nucleo_g474re)
stm32f4-examples:
docker:
@@ -305,6 +309,23 @@ jobs:
path: test/all/log
destination: log
+ stm32g4-compile-all:
+ docker:
+ - image: modm/modm-build:latest
+ steps:
+ - checkout
+ - run:
+ name: Checkout code and update modm tools
+ command: |
+ (git submodule sync && git submodule update --init --jobs 8) & pip3 install --upgrade modm & wait
+ - run:
+ name: Compile HAL for all STM32G4
+ command: |
+ (cd test/all && python3 run_all.py stm32g4)
+ - store_artifacts:
+ path: test/all/log
+ destination: log
+
build-docs:
docker:
- image: modm/modm-build:latest
@@ -405,6 +426,10 @@ workflows:
requires:
- unittests-linux-generic
- stm32-examples
+ - stm32g4-compile-all:
+ requires:
+ - unittests-linux-generic
+ - stm32-examples
- upload-docs:
filters:
branches:
@@ -429,3 +454,4 @@ workflows:
- stm32f2-compile-all
- stm32f3-compile-all
- stm32g0-compile-all
+ - stm32g4-compile-all
diff --git a/README.md b/README.md
index 995c362fe6..12d8fd53b5 100644
--- a/README.md
+++ b/README.md
@@ -70,7 +70,7 @@ git clone --recurse-submodules https://github.com/modm-io/modm.git
## Targets
-modm can generate code for 78 AVR and 1039
+modm can generate code for 78 AVR and 1158
STM32 devices, however, there are different levels of support and testing.
@@ -80,7 +80,7 @@ STM32 devices, however, there are different levels of support and testing.
| AVR | ★★★ | STM32F0 | ★★★★ | STM32F1 | ★★★★ |
| STM32F2 | ★★★★ | STM32F3 | ★★★★★ | STM32F4 | ★★★★★ |
| STM32F7 | ★★★★ | STM32L1 | ★★★★ | STM32L4 | ★★★★ |
-| STM32L4+ | ★★★★ | STM32G0 | ★★★★ |
+| STM32L4+ | ★★★★ | STM32G0 | ★★★★ | STM32G4 | ★★★★ |
@@ -141,10 +141,11 @@ documentation.
NUCLEO-F446RE |
NUCLEO-G071RB |
+NUCLEO-G474RE |
NUCLEO-L152RE |
NUCLEO-L432KC |
-NUCLEO-L476RG |
+NUCLEO-L476RG |
OLIMEXINO-STM32 |
STM32F030F4P6-DEMO |
diff --git a/examples/nucleo_g474re/blink/main.cpp b/examples/nucleo_g474re/blink/main.cpp
new file mode 100644
index 0000000000..4ef69dffc8
--- /dev/null
+++ b/examples/nucleo_g474re/blink/main.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2019, Raphael Lehmann
+ *
+ * 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();
+ LedD13::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);
+
+ while (true)
+ {
+ LedD13::toggle();
+ modm::delayMilliseconds(Button::read() ? 100 : 500);
+
+ MODM_LOG_INFO << "loop: " << counter++ << modm::endl;
+ }
+
+ return 0;
+}
diff --git a/examples/nucleo_g474re/blink/project.xml b/examples/nucleo_g474re/blink/project.xml
new file mode 100644
index 0000000000..4f9e4597ae
--- /dev/null
+++ b/examples/nucleo_g474re/blink/project.xml
@@ -0,0 +1,9 @@
+
+ modm:nucleo-g474re
+
+
+
+
+ modm:build:scons
+
+
diff --git a/repo.lb b/repo.lb
index 7b95af12d8..f3355f35f2 100644
--- a/repo.lb
+++ b/repo.lb
@@ -82,7 +82,7 @@ class DevicesCache(dict):
# roughly filter to supported devices
supported = ["stm32f0", "stm32f1", "stm32f2", "stm32f3", "stm32f4", "stm32f7",
- "stm32g0",
+ "stm32g0", "stm32g4",
"stm32l1", "stm32l4",
"at90", "attiny", "atmega",
"hosted"]
diff --git a/src/modm/board/nucleo_g474re/board.hpp b/src/modm/board/nucleo_g474re/board.hpp
new file mode 100644
index 0000000000..69d6bcd5cb
--- /dev/null
+++ b/src/modm/board/nucleo_g474re/board.hpp
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2019, Raphael Lehmann
+ *
+ * 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/.
+ */
+
+#ifndef MODM_STM32_NUCLEO_G474RE_HPP
+#define MODM_STM32_NUCLEO_G474RE_HPP
+
+#include
+#include
+#include
+/// @ingroup modm_board_nucleo_g474re
+#define MODM_BOARD_HAS_LOGGER
+
+using namespace modm::platform;
+
+/// @ingroup modm_board_nucleo_g474re
+namespace Board
+{
+ using namespace modm::literals;
+
+/// STM32G474RE running at 170MHz generated from the internal 16MHz crystal
+// Dummy clock for devices
+struct SystemClock {
+ static constexpr uint32_t Frequency = 170_MHz;
+ static constexpr uint32_t Ahb1 = Frequency;
+ static constexpr uint32_t Ahb2 = Frequency;
+ static constexpr uint32_t Apb1 = Frequency;
+ static constexpr uint32_t Apb2 = Frequency;
+
+ static constexpr uint32_t Cordic = Ahb1;
+ static constexpr uint32_t Crc = Ahb1;
+ static constexpr uint32_t Dma = Ahb1;
+ static constexpr uint32_t Dma1 = Dma;
+ static constexpr uint32_t Dma2 = Dma;
+ static constexpr uint32_t DmaMux = Dma;
+ static constexpr uint32_t Fmac = Ahb1;
+
+ static constexpr uint32_t Adc = Ahb2;
+ static constexpr uint32_t Adc1 = Adc;
+ static constexpr uint32_t Adc2 = Adc;
+ static constexpr uint32_t Adc3 = Adc;
+ static constexpr uint32_t Adc4 = Adc;
+ static constexpr uint32_t Adc5 = Adc;
+ static constexpr uint32_t Dac = Ahb2;
+ static constexpr uint32_t Dac1 = Dac;
+ static constexpr uint32_t Dac2 = Dac;
+ static constexpr uint32_t Dac3 = Dac;
+ static constexpr uint32_t Dac4 = Dac;
+ static constexpr uint32_t Rng = Ahb2;
+
+ static constexpr uint32_t Can = Apb1;
+ static constexpr uint32_t Fdcan1 = Can;
+ static constexpr uint32_t Fdcan2 = Can;
+ static constexpr uint32_t Fdcan3 = Can;
+ static constexpr uint32_t I2c = Apb1;
+ static constexpr uint32_t I2c1 = I2c;
+ static constexpr uint32_t I2c2 = I2c;
+ static constexpr uint32_t I2c3 = I2c;
+ static constexpr uint32_t I2c4 = I2c;
+ static constexpr uint32_t Lptim = Apb1;
+ static constexpr uint32_t Lpuart = Apb1;
+ static constexpr uint32_t Rtc = Apb1;
+ static constexpr uint32_t Spi2 = Apb1;
+ static constexpr uint32_t Spi3 = Apb1;
+ static constexpr uint32_t Uart4 = Apb1;
+ static constexpr uint32_t Uart5 = Apb1;
+ static constexpr uint32_t Usart2 = Apb1;
+ static constexpr uint32_t Usart3 = Apb1;
+ static constexpr uint32_t Usb = Apb1;
+ static constexpr uint32_t Apb1Timer = Apb1 * 1;
+ 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 Sai1 = Apb2;
+ static constexpr uint32_t Spi1 = Apb2;
+ static constexpr uint32_t Usart1 = Apb2;
+ static constexpr uint32_t Apb2Timer = Apb2 * 1;
+ static constexpr uint32_t Timer1 = Apb2Timer;
+ static constexpr uint32_t Timer8 = Apb2Timer;
+ static constexpr uint32_t Timer15 = Apb2Timer;
+ static constexpr uint32_t Timer16 = Apb2Timer;
+ static constexpr uint32_t Timer17 = Apb2Timer;
+ static constexpr uint32_t Timer20 = Apb2Timer;
+
+ static bool inline
+ enable()
+ {
+ Rcc::enableInternalClock(); // 16MHz
+ Rcc::enablePll(
+ Rcc::PllSource::InternalClock,
+ 4, // 16MHz / N= 4 -> 4MHz
+ 85, // 4MHz * M=85 -> 340MHz
+ 2 // 336MHz / P= 2 -> 170MHz = F_cpu
+ );
+ // set flash latency for 170MHz
+ Rcc::setFlashLatency();
+ // switch system clock to PLL output
+ Rcc::enableSystemClock(Rcc::SystemClockSource::Pll);
+ Rcc::setAhbPrescaler(Rcc::AhbPrescaler::Div1);
+ // APB1 has max. 170MHz
+ Rcc::setApb1Prescaler(Rcc::Apb1Prescaler::Div1);
+ Rcc::setApb2Prescaler(Rcc::Apb2Prescaler::Div1);
+ // update frequencies for busy-wait delay functions
+ Rcc::updateCoreFrequency();
+
+ return true;
+ }
+};
+
+// Arduino Footprint
+#include "nucleo64_arduino.hpp"
+
+using Button = GpioInverted;
+using LedD13 = D13;
+
+using Leds = SoftwareGpioPort< LedD13 >;
+
+
+namespace stlink
+{
+using Rx = GpioInputA3;
+using Tx = GpioOutputA2;
+using Uart = Usart2;
+}
+
+using LoggerDevice = modm::IODeviceWrapper< stlink::Uart, modm::IOBuffer::BlockIfFull >;
+
+
+inline void
+initialize()
+{
+ SystemClock::enable();
+ SysTickTimer::initialize();
+
+ stlink::Uart::connect();
+ stlink::Uart::initialize();
+
+ Button::setInput();
+ Button::setInputTrigger(Gpio::InputTrigger::RisingEdge);
+ Button::enableExternalInterrupt();
+// Button::enableExternalInterruptVector(12);
+}
+
+}
+
+#endif // MODM_STM32_NUCLEO_G474RE_HPP
diff --git a/src/modm/board/nucleo_g474re/board.xml b/src/modm/board/nucleo_g474re/board.xml
new file mode 100644
index 0000000000..769a3a369c
--- /dev/null
+++ b/src/modm/board/nucleo_g474re/board.xml
@@ -0,0 +1,16 @@
+
+
+
+ ../../../../repo.lb
+
+
+
+
+
+
+
+
+
+ modm:board:nucleo-g474re
+
+
diff --git a/src/modm/board/nucleo_g474re/module.lb b/src/modm/board/nucleo_g474re/module.lb
new file mode 100644
index 0000000000..a2f69c154f
--- /dev/null
+++ b/src/modm/board/nucleo_g474re/module.lb
@@ -0,0 +1,38 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2019, Raphael Lehmann
+#
+# 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-g474re"
+ module.description = """\
+# NUCLEO-G474RE
+
+[Nucleo kit for STM32G474RE](https://www.st.com/en/evaluation-tools/nucleo-g474re.html)
+"""
+
+def prepare(module, options):
+ if options[":target"].partname != "stm32g474ret":
+ return False
+
+ module.depends(":platform:core", ":platform:gpio", ":platform:clock", ":platform:uart:2",
+ ":debug", ":architecture:clock")
+ return True
+
+def build(env):
+ env.outbasepath = "modm/src/modm/board"
+ env.substitutions = {"board_has_logger": True}
+ 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_g4.cfg"), "st_nucleo_g4.cfg")
+ env.collect(":build:openocd.source", "modm/board/st_nucleo_g4.cfg")
diff --git a/src/modm/platform/adc/stm32f3/adc.hpp.in b/src/modm/platform/adc/stm32f3/adc.hpp.in
index 6a36299e3d..6161450663 100644
--- a/src/modm/platform/adc/stm32f3/adc.hpp.in
+++ b/src/modm/platform/adc/stm32f3/adc.hpp.in
@@ -55,7 +55,7 @@ public:
BatDiv2 = 17,
InternalReference = 18,
// TODO: Add internal connections
-%% elif target["family"] in ["l4"]
+%% elif target["family"] in ["l4", "g4"]
Temperature = 17,
BatDiv3 = 18,
%% endif
@@ -63,7 +63,7 @@ public:
%% if target["family"] in ["f3"]
Opamp2 = 17,
InternalReference = 18,
-%% elif target["family"] in ["l4"]
+%% elif target["family"] in ["l4", "g4"]
Dac1 = 17,
Dac2 = 18,
%% endif
@@ -72,7 +72,7 @@ public:
Vss = 4, // ADC3_IN4 not bonded and connected to VSS
Opamp3 = 17,
InternalReference = 18,
-%% elif target["family"] in ["l4"]
+%% elif target["family"] in ["l4", "g4"]
Dac1 = 14,
Dac2 = 15,
Vss = 16,
@@ -101,9 +101,21 @@ public:
enum class ClockSource : uint32_t
{
NoClock = 0, // No clock selected.
+%% if target["family"] in ["g4"]
+%% if id in [1, 2]
+ PllSai1 = RCC_CCIPR_ADC12SEL_0, // PLLSAI1 "R" clock (PLLADC1CLK) selected as ADCs clock
+ PllSai2 = RCC_CCIPR_ADC12SEL_1, // PLLSAI2 "R" clock (PLLADC2CLK) selected as ADCs clock
+ SystemClock = RCC_CCIPR_ADC12SEL_1 | RCC_CCIPR_ADC12SEL_0, // System clock selected as ADCs clock
+%% elif id in [3, 4, 5]
+ PllSai1 = RCC_CCIPR_ADC345SEL_0, // PLLSAI1 "R" clock (PLLADC1CLK) selected as ADCs clock
+ PllSai2 = RCC_CCIPR_ADC345SEL_1, // PLLSAI2 "R" clock (PLLADC2CLK) selected as ADCs clock
+ SystemClock = RCC_CCIPR_ADC345SEL_1 | RCC_CCIPR_ADC345SEL_0, // System clock selected as ADCs clock
+%% endif
+%% else
PllSai1 = RCC_CCIPR_ADCSEL_0, // PLLSAI1 "R" clock (PLLADC1CLK) selected as ADCs clock
PllSai2 = RCC_CCIPR_ADCSEL_1, // PLLSAI2 "R" clock (PLLADC2CLK) selected as ADCs clock
SystemClock = RCC_CCIPR_ADCSEL_1 | RCC_CCIPR_ADCSEL_0, // System clock selected as ADCs clock
+%% endif
};
%% endif
@@ -125,7 +137,7 @@ public:
Div128 = RCC_CFGR2_{{ adc_pre }}_DIV128,
Div256 = RCC_CFGR2_{{ adc_pre }}_DIV256,
Div256AllBits = RCC_CFGR2_{{ adc_pre }}, // for bit clear
-%% elif target["family"] in ["l4"]
+%% elif target["family"] in ["l4", "g4"]
Div1 = 0,
Div2 = ADC_CCR_PRESC_0,
Div4 = ADC_CCR_PRESC_1,
@@ -163,7 +175,7 @@ public:
enum class VoltageRegulatorState : uint32_t
{
-%% if target["family"] in ["l4"]
+%% if target["family"] in ["l4", "g4"]
Enabled = ADC_CR_ADVREGEN,
%% elif target["family"] in ["f3"]
// Intermediate state is needed to move from enabled to disabled
@@ -177,16 +189,16 @@ public:
enum class Interrupt : uint32_t
{
Ready = ADC_IER_ADRDYIE,
- EndOfSampling = ADC_IER_EOSMP,
- EndOfRegularConversion = ADC_IER_EOC,
- EndOfRegularSequenceOfConversions = ADC_IER_EOS,
- Overrun = ADC_IER_OVR,
- EndOfInjectedConversion = ADC_IER_JEOC,
- EndOfInjectedSequenceOfConversions = ADC_IER_JEOS,
- AnalogWatchdog1 = ADC_IER_AWD1,
- AnalogWatchdog2 = ADC_IER_AWD2,
- AnalogWatchdog3 = ADC_IER_AWD3,
- InjectedContextQueueOverflow = ADC_IER_JQOVF,
+ EndOfSampling = ADC_IER_EOSMPIE,
+ EndOfRegularConversion = ADC_IER_EOCIE,
+ EndOfRegularSequenceOfConversions = ADC_IER_EOSIE,
+ Overrun = ADC_IER_OVRIE,
+ EndOfInjectedConversion = ADC_IER_JEOCIE,
+ EndOfInjectedSequenceOfConversions = ADC_IER_JEOSIE,
+ AnalogWatchdog1 = ADC_IER_AWD1IE,
+ AnalogWatchdog2 = ADC_IER_AWD2IE,
+ AnalogWatchdog3 = ADC_IER_AWD3IE,
+ InjectedContextQueueOverflow = ADC_IER_JQOVFIE,
};
MODM_FLAGS32(Interrupt);
diff --git a/src/modm/platform/adc/stm32f3/adc_impl.hpp.in b/src/modm/platform/adc/stm32f3/adc_impl.hpp.in
index 9085fcd34d..b7b9b9844a 100644
--- a/src/modm/platform/adc/stm32f3/adc_impl.hpp.in
+++ b/src/modm/platform/adc/stm32f3/adc_impl.hpp.in
@@ -29,8 +29,8 @@ modm::platform::Adc{{ id }}::initialize(const ClockMode clk,
uint32_t tmp = 0;
// enable clock
-%% if target["family"] in ["f3"]
- RCC->AHBENR |= RCC_AHBENR_ADC{{ id_common }}EN;
+%% if target["family"] in ["f3", "g4"]
+ RCC->{{ ahb }}ENR |= RCC_{{ ahb }}ENR_ADC{{ id_common }}EN;
%% elif target["family"] in ["l4"]
Rcc::enable();
%% endif
@@ -40,7 +40,7 @@ modm::platform::Adc{{ id }}::initialize(const ClockMode clk,
RCC->CCIPR |= static_cast(clk_src);
%% endif
-%% if target["family"] in ["l4"]
+%% if target["family"] in ["l4", "g4"]
// Disable deep power down
ADC{{ id }}->CR &= ~ADC_CR_DEEPPWD;
%% endif
@@ -86,8 +86,8 @@ modm::platform::Adc{{ id }}::disable(const bool blocking)
while(ADC{{ id }}->CR & ADC_CR_ADDIS);
}
// disable clock
-%% if target["family"] in ["f3"]
- RCC->AHBENR &= ~RCC_AHBENR_ADC{{ id_common }}EN;
+%% if target["family"] in ["f3", "g4"]
+ RCC->{{ ahb }}ENR &= ~RCC_{{ ahb }}ENR_ADC{{ id_common }}EN;
%% elif target["family"] in ["l4"]
Rcc::disable();
%% endif
@@ -102,7 +102,7 @@ modm::platform::Adc{{ id }}::setPrescaler(const Prescaler pre)
tmp &= ~static_cast(Prescaler::Div256AllBits);
tmp |= static_cast(pre);
RCC->CFGR2 = tmp;
-%% elif target["family"] in ["l4"]
+%% elif target["family"] in ["l4", "g4"]
tmp = ADC{{ id_common_u }}->CCR;
tmp &= ~static_cast(Prescaler::Div256AllBits);
tmp |= static_cast(pre);
@@ -224,9 +224,9 @@ void
modm::platform::Adc{{ id }}::enableInterruptVector(const uint32_t priority,
const bool enable)
{
-%% if id < 3
+%% if id <= 2
const IRQn_Type INTERRUPT_VECTOR = ADC1_2_IRQn;
-%% elif id < 5
+%% elif id <= 5
const IRQn_Type INTERRUPT_VECTOR = ADC{{ id }}_IRQn;
%% endif
diff --git a/src/modm/platform/adc/stm32f3/module.lb b/src/modm/platform/adc/stm32f3/module.lb
index 394bf6cdcc..8831bbd88b 100644
--- a/src/modm/platform/adc/stm32f3/module.lb
+++ b/src/modm/platform/adc/stm32f3/module.lb
@@ -39,6 +39,9 @@ class Instance(Module):
elif target["family"] == "l4":
# ADC1 is connected to 16 external channels + 3 internal channels
channels = range(1,17)
+ elif target["family"] == "g4":
+ # ADC1 is connected to 14 external channels + 4 internal channels
+ channels = range(1,15)
else:
# 11-14 reserved
channels = [1,2,3,4,5,6,7,8,9,10,15,16,17,18]
@@ -46,21 +49,38 @@ class Instance(Module):
if target["family"] == "f3":
# 13-16 reserved
channels = [1,2,3,4,5,6,7,8,9,10,11,12,17,18]
+ elif target["family"] == "g4":
+ # ADC2 is connected to 16 external channels + 2 internal channels
+ channels = range(1,17)
else:
# ADC2 is connected to 16 external channels + 2 internal channels
channels = range(1,17)
elif instance_id == 3:
if target["family"] == "f3":
channels = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18]
+ elif target["family"] == "g4":
+ # ADC3 is connected to 15 external channels + 3 internal channels
+ channels = range(1,16)
else:
# ADC3 is connected to 12 external channels + 4 internal channels
channels = [1,2,3,4,6,7,8,9,10,11,12,13]
elif instance_id == 4:
- # 14-16 reserved
- channels = [1,2,3,4,5,6,7,8,9,10,11,12,13,17,18]
+ if target["family"] == "g4":
+ # ADC4 is connected to 16 external channels + 2 internal channels
+ channels = range(1,17)
+ else:
+ # 14-16 reserved
+ channels = [1,2,3,4,5,6,7,8,9,10,11,12,13,17,18]
+ elif instance_id == 5:
+ if target["family"] == "g4":
+ # ADC5 is connected to 13 external channels + 5 internal channels
+ channels = range(1,14)
+ else:
+ raise NotImplementedError
properties["channels"] = sorted(channels)
if target["family"] == "f3":
+ properties["ahb"] = "AHB"
if len(driver["instance"]) == 1:
properties["adc_ccr"] = "ADC1_CCR"
properties["adc_pre"] = "ADC1PRES"
@@ -77,7 +97,7 @@ class Instance(Module):
properties["id_common"] = "34"
properties["id_common_u"] = "3_4_COMMON"
properties["clock_mux"] = False
- else: # L4
+ elif target["family"] == "l4":
properties["adc_ccr"] = "ADC_CCR"
if len(driver["instance"]) == 1:
properties["id_common"] = "1"
@@ -89,6 +109,18 @@ class Instance(Module):
properties["id_common"] = "123"
properties["id_common_u"] = "123_COMMON"
properties["clock_mux"] = (target["name"] not in ("12", "22"))
+ elif target["family"] == "g4":
+ properties["ahb"] = "AHB2"
+ properties["adc_ccr"] = "ADC_CCR"
+ if instance_id in [1, 2]:
+ properties["id_common"] = "12"
+ properties["id_common_u"] = "12_COMMON"
+ else:
+ properties["id_common"] = "345"
+ properties["id_common_u"] = "345_COMMON"
+ properties["clock_mux"] = True
+ else:
+ raise NotImplementedError
env.substitutions = properties
env.outbasepath = "modm/src/modm/platform/adc"
diff --git a/src/modm/platform/clock/stm32/module.lb b/src/modm/platform/clock/stm32/module.lb
index 8919655e55..c8f96db5ac 100644
--- a/src/modm/platform/clock/stm32/module.lb
+++ b/src/modm/platform/clock/stm32/module.lb
@@ -63,7 +63,7 @@ def build(env):
properties["pllprediv2"] = False # FIXME: not sure what value this should have
properties["hsi48"] = \
target["family"] == "f0" and target["name"] in ["42", "48", "71", "72", "78", "91", "98"]
- properties["pll_p"] = target["family"] == "l4" and target["name"] not in ["12", "22"]
+ properties["pll_p"] = ((target["family"] == "l4" and target["name"] not in ["12", "22"]) or target["family"] == "g4")
flash_latencies = {}
for vcore in device.get_driver("flash")["latency"]:
diff --git a/src/modm/platform/clock/stm32/rcc.cpp.in b/src/modm/platform/clock/stm32/rcc.cpp.in
index afaaa449c9..1415e91c5f 100644
--- a/src/modm/platform/clock/stm32/rcc.cpp.in
+++ b/src/modm/platform/clock/stm32/rcc.cpp.in
@@ -173,7 +173,7 @@ modm::platform::Rcc::enablePll(PllSource source, uint8_t pllM, uint16_t pllN, ui
return tmp;
}
-%% elif target["family"] in ["g0", "l4"]
+%% elif target["family"] in ["g0", "l4", "g4"]
// ----------------------------------------------------------------------------
bool
modm::platform::Rcc::enablePll(PllSource source,
@@ -198,7 +198,7 @@ modm::platform::Rcc::enablePll(PllSource source,
tmp |= (uint32_t(pllN) << RCC_PLLCFGR_PLLN_Pos) & RCC_PLLCFGR_PLLN;
// PLLR divider for CPU frequency
-%% if target["family"] in ["g0"]
+%% if target["family"] in ["g0", "g4"]
tmp |= ((uint32_t(pllR) - 1) << RCC_PLLCFGR_PLLR_Pos) & RCC_PLLCFGR_PLLR;
// PLLP divider for P frequency
// tmp |= ((uint32_t(pllP) - 1) << RCC_PLLCFGR_PLLP_Pos) & RCC_PLLCFGR_PLLP;
diff --git a/src/modm/platform/clock/stm32/rcc.hpp.in b/src/modm/platform/clock/stm32/rcc.hpp.in
index eb40647563..d754ccc3ce 100644
--- a/src/modm/platform/clock/stm32/rcc.hpp.in
+++ b/src/modm/platform/clock/stm32/rcc.hpp.in
@@ -40,7 +40,7 @@ public:
enum class
PllSource : uint32_t
{
-%% if target["family"] in ["f2", "f4", "f7", "l4", "g0"]
+%% if target["family"] in ["f2", "f4", "f7", "l4", "g0", "g4"]
/// High speed internal clock (16 MHz)
Hsi = RCC_PLLCFGR_PLLSRC_HSI,
/// High speed external clock (see HseConfig)
@@ -203,7 +203,7 @@ public:
Pll = RCC_CFGR_MCO2_1 | RCC_CFGR_MCO2_0,
};
%% endif
-%% elif target["family"] in ["l1", "l4", "g0"]
+%% elif target["family"] in ["l1", "l4", "g0", "g4"]
enum class
ClockOutputSource : uint32_t
{
@@ -308,7 +308,7 @@ public:
enableLowSpeedExternalCrystal(uint32_t waitCycles = 2048);
// plls
-%% if target["family"] in ["f2", "f4", "f7", "l4", "g0"]
+%% if target["family"] in ["f2", "f4", "f7", "l4", "g0", "g4"]
/**
* Enable PLL.
*
@@ -340,7 +340,7 @@ public:
*/
static bool
enablePll(PllSource source, uint8_t pllM, uint16_t pllN,
-%% if target["family"] in ["l4", "g0"]
+%% if target["family"] in ["l4", "g0", "g4"]
uint8_t pllR,
%% else
uint8_t pllP,
@@ -401,7 +401,7 @@ public:
return true;
}
%% endif
-%% elif target["family"] in ["l1", "l4", "g0"]
+%% elif target["family"] in ["l1", "l4", "g0", "g4"]
enum class
ClockOutputPrescaler : 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 13ae30e03e..69955ca9dc 100644
--- a/src/modm/platform/clock/stm32/rcc_impl.hpp.in
+++ b/src/modm/platform/clock/stm32/rcc_impl.hpp.in
@@ -62,7 +62,7 @@ Rcc::setFlashLatency()
uint32_t acr = FLASH->ACR & ~FLASH_ACR_LATENCY;
// set flash latency
acr |= fl.latency;
-%% if target["family"] in ["f2", "f4", "l4"]
+%% if target["family"] in ["f2", "f4", "l4", "g4"]
// enable flash prefetch and data and instruction cache
acr |= FLASH_ACR_PRFTEN | FLASH_ACR_DCEN | FLASH_ACR_ICEN;
%% elif target["family"] in ["g0"]
diff --git a/src/modm/platform/comp/stm32/base.hpp.in b/src/modm/platform/comp/stm32/base.hpp.in
index 2b7a70b9f9..46443a8940 100644
--- a/src/modm/platform/comp/stm32/base.hpp.in
+++ b/src/modm/platform/comp/stm32/base.hpp.in
@@ -12,12 +12,14 @@
#ifndef MODM_STM32_COMP_BASE_HPP
#define MODM_STM32_COMP_BASE_HPP
+#include
namespace modm::platform
{
/// @ingroup modm_platform_comp
class CompBase
{
+ {% if driver.type not in ["stm32-tsmc90_g4_rockfish_cube"] -%}
public:
enum class
Mode
@@ -36,6 +38,7 @@ namespace modm::platform
};
protected:
static constexpr uint32_t ModeMask = 0b11 << 2;
+ {% endif -%}
public:
enum class
@@ -47,6 +50,7 @@ namespace modm::platform
protected:
static constexpr uint32_t PolarityMask = 0b1 << 15;
+ {% if driver.type in ["stm32-v1.3", "stm32-tsmc90_cube"] -%}
public:
enum class
Hysteresis
@@ -58,6 +62,28 @@ namespace modm::platform
};
protected:
static constexpr uint32_t HysteresisMask = 0b11 << 16;
+ {% elif "g4" in driver.type -%}
+ public:
+ enum class
+ Hysteresis
+ {
+ NoHysteresis = 0b000 << COMP_CSR_HYST_Pos,
+ Hysteresis10mV = 0b001 << COMP_CSR_HYST_Pos,
+ Hysteresis20mV = 0b010 << COMP_CSR_HYST_Pos,
+ Hysteresis30mV = 0b011 << COMP_CSR_HYST_Pos,
+ Hysteresis40mV = 0b100 << COMP_CSR_HYST_Pos,
+ Hysteresis50mV = 0b101 << COMP_CSR_HYST_Pos,
+ Hysteresis60mV = 0b110 << COMP_CSR_HYST_Pos,
+ Hysteresis70mV = 0b111 << COMP_CSR_HYST_Pos,
+
+ // for compatibility:
+ LowHysteresis = Hysteresis10mV,
+ MediumHysteresis = Hysteresis40mV,
+ HighHysteresis = Hysteresis70mV,
+ };
+ protected:
+ static constexpr uint32_t HysteresisMask = COMP_CSR_HYST_Msk;
+ {% endif -%}
};
}
diff --git a/src/modm/platform/comp/stm32/comp.hpp.in b/src/modm/platform/comp/stm32/comp.hpp.in
index da39b81873..638f838bf1 100644
--- a/src/modm/platform/comp/stm32/comp.hpp.in
+++ b/src/modm/platform/comp/stm32/comp.hpp.in
@@ -53,7 +53,7 @@ namespace modm::platform
Vref1Div4 = (0b000 << 4) | (0b11 << 22),
Vref1Div2 = (0b001 << 4) | (0b11 << 22),
Vref3Div4 = (0b010 << 4) | (0b11 << 22),
- Vref = 0b011 << 4,
+ Vref = (0b011 << 4) | (0b10 << 22),
DacChannel1 = 0b100 << 4,
DacChannel2 = 0b101 << 4,
{% if id == 1 -%}
@@ -67,13 +67,56 @@ namespace modm::platform
{% endif -%}
GpioA4 = (0b111 << 4) | (0b10 << 25),
GpioA5 = (0b111 << 4) | (0b11 << 25),
+ {% elif target.family == "g4" -%}
+ Vref1Div4 = (0b000 << 4) | (0b11 << 22),
+ Vref1Div2 = (0b001 << 4) | (0b11 << 22),
+ Vref3Div4 = (0b010 << 4) | (0b11 << 22),
+ Vref = (0b011 << 4) | (0b10 << 22),
+ {% if id == 1 -%}
+ Dac3Ch1 = 0b100 << 4,
+ Dac1Ch1 = 0b101 << 4,
+ GpioA4 = 0b110 << 4,
+ GpioA0 = 0b111 << 4,
+ {% elif id == 2 -%}
+ Dac3Ch2 = 0b100 << 4,
+ Dac1Ch2 = 0b101 << 4,
+ GpioA5 = 0b110 << 4,
+ GpioA2 = 0b111 << 4,
+ {% elif id == 3 -%}
+ Dac3Ch1 = 0b100 << 4,
+ Dac1Ch1 = 0b101 << 4,
+ GpioF1 = 0b110 << 4,
+ GpioC0 = 0b111 << 4,
+ {% elif id == 4 -%}
+ Dac3Ch2 = 0b100 << 4,
+ Dac1Ch1 = 0b101 << 4,
+ GpioE8 = 0b110 << 4,
+ GpioB2 = 0b111 << 4,
+ {% elif id == 5 -%}
+ Dac4Ch1 = 0b100 << 4,
+ Dac1Ch2 = 0b101 << 4,
+ GpioB10 = 0b110 << 4,
+ GpioD13 = 0b111 << 4,
+ {% elif id == 6 -%}
+ Dac4Ch2 = 0b100 << 4,
+ Dac2Ch1 = 0b101 << 4,
+ GpioD10 = 0b110 << 4,
+ GpioB15 = 0b111 << 4,
+ {% elif id == 7 -%}
+ Dac4Ch1 = 0b100 << 4,
+ Dac2Ch1 = 0b101 << 4,
+ GpioD15 = 0b110 << 4,
+ GpioB12 = 0b111 << 4,
+ {% endif -%}
{% endif -%}
};
protected:
{% if target.family == "f3" -%}
static constexpr uint32_t InvertingInputMask = (0b111 << 4) | (0b1 << 22);
- {% elif target.family == "l4" -%}
+ {% elif target.family in ["l4"] -%}
static constexpr uint32_t InvertingInputMask = (0b111 << 4) | (0b11 << 22) | (0b11 << 25);
+ {% elif target.family in ["g4"] -%}
+ static constexpr uint32_t InvertingInputMask = (0b1111 << 4) | (0b11 << 22);
{% endif -%}
public:
@@ -84,7 +127,7 @@ namespace modm::platform
// TODO: Gpio names (with data from parsed datasheets
BitUnset = 0b0 << 7,
BitSet = 0b1 << 7,
- {% elif target.family == "l4" -%}
+ {% elif target.family in ["l4"] -%}
{% if id == 1 -%}
GpioC5 = 0b00 << 7,
GpioB2 = 0b01 << 7,
@@ -94,12 +137,37 @@ namespace modm::platform
GpioB6 = 0b01 << 7,
GpioA3 = 0b10 << 7,
{% endif -%}
+ {% elif target.family in ["g4"] -%}
+ {% if id == 1 -%}
+ GpioA1 = 0b0 << 8,
+ GpioB1 = 0b1 << 8,
+ {% elif id == 2 -%}
+ GpioA7 = 0b0 << 8,
+ GpioA3 = 0b1 << 8,
+ {% elif id == 3 -%}
+ GpioA0 = 0b0 << 8,
+ GpioC1 = 0b1 << 8,
+ {% elif id == 4 -%}
+ GpioB0 = 0b0 << 8,
+ GpioE7 = 0b1 << 8,
+ {% elif id == 5 -%}
+ GpioB13 = 0b0 << 8,
+ GpioD12 = 0b1 << 8,
+ {% elif id == 6 -%}
+ GpioB11 = 0b0 << 8,
+ GpioD11 = 0b1 << 8,
+ {% elif id == 7 -%}
+ GpioB14 = 0b0 << 8,
+ GpioD14 = 0b1 << 8,
+ {% endif -%}
{% endif -%}
};
protected:
{% if target.family == "f3" -%}
static constexpr uint32_t NonInvertingInputMask = 0b1 << 7;
- {% elif target.family == "l4" -%}
+ {% elif target.family in ["g4"] -%}
+ static constexpr uint32_t NonInvertingInputMask = 0b1 << 8;
+ {% elif target.family in ["l4"] -%}
static constexpr uint32_t NonInvertingInputMask = 0b11 << 7;
{% endif -%}
@@ -137,21 +205,15 @@ namespace modm::platform
BlankingSource
{
NoBlanking = 0b000 << 18,
- {% if target.family == "f3" -%}
- Tim1Oc5 = 0b001 << 18,
- Tim2Oc3 = 0b010 << 18,
- Tim3Oc3 = 0b011 << 18,
- {% elif target.family == "l4" -%}
- {% if id == 1 -%}
- Tim1Oc5 = 0b001 << 18,
- Tim2Oc3 = 0b010 << 18,
- {% elif id == 2 -%}
- Tim15Oc1 = 0b100 << 18,
- {% endif -%}
+
+ {% for k, v in blanking_source.items() -%}
+ {% if k is not none and v is not none -%}
+ {{ v }} = 0{{ k }} << {{ csr }}BLANKING_Pos,
{% endif -%}
+ {% endfor -%}
};
protected:
- static constexpr uint32_t BlankingSourceMask = 0b111 << 18;
+ static constexpr uint32_t BlankingSourceMask = {{ csr }}BLANKING_Msk;
public:
/**
@@ -165,26 +227,30 @@ namespace modm::platform
static inline void
initialize(
InvertingInput n_in,
- {% if (target.family == "f3" and id > 1) or target.family == "l4" -%}
+ {% if (target.family == "f3" and id > 1) or target.family in ["l4", "g4"] -%}
NonInvertingInput p_in,
{% endif -%}
{% if target.family == "f3" -%}
Output out = Output::NoSelection,
{% endif -%}
Hysteresis hyst = Hysteresis::NoHysteresis,
+ {% if driver.type not in ["stm32-tsmc90_g4_rockfish_cube"] -%}
Mode mode = Mode::HighSpeed,
+ {% endif -%}
Polarity pol = Polarity::NonInverted,
bool lock_comp = false)
{
setInvertingInput(n_in);
- {% if (target.family == "f3" and id > 1) or target.family == "l4" -%}
+ {% if (target.family == "f3" and id > 1) or target.family in ["l4", "g4"] -%}
setNonInvertingInput(p_in);
{% endif -%}
{% if target.family == "f3" -%}
setOutputSelection(out);
{% endif -%}
setHysteresis(hyst);
+ {% if driver.type not in ["stm32-tsmc90_g4_rockfish_cube"] -%}
setMode(mode);
+ {% endif -%}
setPolarity(pol);
setEnabled(true); // enable comparator
if(lock_comp) {
@@ -242,6 +308,7 @@ namespace modm::platform
}
{% endif -%}
+ {% if driver.type not in ["stm32-tsmc90_g4_rockfish_cube"] -%}
/**
* \brief Sets the mode that determins speed/power consumption.
*
@@ -263,6 +330,7 @@ namespace modm::platform
{
return static_cast(COMP{{ id }}->CSR & ModeMask);
}
+ {% endif -%}
/**
* \brief Selects what the inverting input is connected to.
@@ -282,7 +350,7 @@ namespace modm::platform
return static_cast(COMP{{ id }}->CSR & InvertingInputMask);
}
- {% if (target.family == "f3" and id > 1) or target.family == "l4" -%}
+ {% if (target.family == "f3" and id > 1) or target.family in ["l4", "g4"] -%}
/**
* \brief Selects what the non-inverting input is connected to.
*/
@@ -308,7 +376,6 @@ namespace modm::platform
{% elif target.family == "l4" -%}
{% set windowmode = "WINMODE" %}
{% endif -%}
-
/**
* \brief Enable/Disable window mode for COMP{{ (id-1) }}/{{ id }}.
*/
@@ -414,7 +481,7 @@ namespace modm::platform
{
{% if target.family == "f3" -%}
return COMP{{ id }}->CSR & {{ csr }}OUT;
- {% elif target.family == "l4" -%}
+ {% elif target.family in ["l4", "g4"] -%}
return COMP{{ id }}->CSR & {{ csr }}VALUE;
{% endif -%}
}
diff --git a/src/modm/platform/comp/stm32/module.lb b/src/modm/platform/comp/stm32/module.lb
index 9e8ddfe0b1..87aee6f45d 100644
--- a/src/modm/platform/comp/stm32/module.lb
+++ b/src/modm/platform/comp/stm32/module.lb
@@ -30,7 +30,27 @@ class Instance(Module):
properties["target"] = device.identifier
instance_id = int(self.instance)
properties["id"] = instance_id
- properties["csr"] = "COMP_CSR_" if device.identifier["family"] in ["l4"] else "COMP_CSR_COMPx"
+ properties["driver"] = driver
+ properties["csr"] = "COMP_CSR_" if device.identifier["family"] in ["l4", "g4"] else "COMP_CSR_COMPx"
+ properties["blanking_source"] = dict()
+ if device.identifier["family"] in ["g4"]:
+ properties["blanking_source"]["b001"] = ["Tim1Oc5", "Tim1Oc5", "Tim1Oc5", "Tim3Oc4", "Tim2Oc3", "Tim8Oc5", "Tim1Oc5"][instance_id - 1]
+ properties["blanking_source"]["b010"] = ["Tim2Oc3", "Tim2Oc3", "Tim3Oc3", "Tim8Oc5", "Tim8Oc5", "Tim2Oc4", "Tim8Oc5"][instance_id - 1]
+ properties["blanking_source"]["b011"] = ["Tim3Oc3", "Tim3Oc3", "Tim2Oc4", "Tim15Oc1_2", "Tim3Oc3", "Tim15Oc2", "Tim3Oc3"][instance_id - 1]
+ properties["blanking_source"]["b100"] = ["Tim8Oc5", "Tim8Oc5", "Tim8Oc5", "Tim1Oc5", "Tim1Oc5", "Tim1Oc5", "Tim15Oc2"][instance_id - 1]
+ properties["blanking_source"]["b101"] = ["Tim20Oc5", "Tim20Oc5", "Tim20Oc5", "Tim20Oc5", "Tim20Oc5", "Tim20Oc5", "Tim20Oc5"][instance_id - 1]
+ properties["blanking_source"]["b110"] = ["Tim15Oc1", "Tim15Oc1", "Tim15Oc1", "Tim15Oc1", "Tim15Oc1", "Tim15Oc1", "Tim15Oc1"][instance_id - 1]
+ properties["blanking_source"]["b111"] = ["Tim4Oc3", "Tim4Oc3", "Tim4Oc3", "Tim4Oc3", "Tim4Oc3", "Tim4Oc3", "Tim4Oc3"][instance_id - 1]
+ elif device.identifier["family"] in ["l4"]:
+ properties["blanking_source"]["b001"] = ["Tim1Oc5", None][instance_id - 1]
+ properties["blanking_source"]["b010"] = ["Tim2Oc3", None][instance_id - 1]
+ properties["blanking_source"]["b100"] = [None, "Tim15Oc1"][instance_id - 1]
+ elif device.identifier["family"] in ["f3"]:
+ properties["blanking_source"]["b001"] = "Tim1Oc5"
+ properties["blanking_source"]["b010"] = "Tim2Oc3"
+ properties["blanking_source"]["b011"] = "Tim3Oc3"
+
+
env.substitutions = properties
env.outbasepath = "modm/src/modm/platform/comp"
@@ -48,7 +68,22 @@ def prepare(module, options):
if not device.has_driver("comp:stm32*"):
return False
- if not device.get_driver("comp")["type"] in ["stm32-v1.3", "stm32-tsmc90_cube"]:
+ """
+ Existing comparator IPs:
+ "stm32-tsmc90_cube"
+ "stm32-tsmc90_dory_cube"
+ "stm32-tsmc90_g4_rockfish_cube"
+ "stm32-tsmc90_h7_cube"
+ "stm32-tsmc90_orca128_cube"
+ "stm32-tsmc90_orca512_cube"
+ "stm32-tsmc90_orcazero_cube"
+ "stm32-v1.0"
+ "stm32-v1.2"
+ "stm32-v1.3"
+ "stm32-v3.4"
+ "stm32-v3.6"
+ """
+ if not device.get_driver("comp")["type"] in ["stm32-v1.3", "stm32-tsmc90_cube", "stm32-tsmc90_g4_rockfish_cube"]:
return False
# Only some STM32F3 and STM32L4
@@ -58,6 +93,8 @@ def prepare(module, options):
elif device.identifier["family"] == "l4":
if not device.identifier["name"] in ["31", "32", "33", "42", "43", "51", "52", "62"]:
return False
+ elif device.identifier["family"] == "g4":
+ pass
else:
return False
@@ -75,7 +112,7 @@ def build(env):
properties = device.properties
properties["target"] = device.identifier
properties["driver"] = driver
- properties["csr"] = "COMP_CSR_" if device.identifier["family"] in ["l4"] else "COMP_CSR_COMPx"
+ properties["csr"] = "COMP_CSR_" if device.identifier["family"] in ["l4", "g4"] else "COMP_CSR_COMPx"
env.substitutions = properties
env.outbasepath = "modm/src/modm/platform/comp"
diff --git a/src/modm/platform/gpio/stm32/enable.cpp.in b/src/modm/platform/gpio/stm32/enable.cpp.in
index 6230cb4610..afe4255984 100644
--- a/src/modm/platform/gpio/stm32/enable.cpp.in
+++ b/src/modm/platform/gpio/stm32/enable.cpp.in
@@ -24,7 +24,7 @@ modm_gpio_enable(void)
%% elif target["family"] in ["f1"]
%% set clock_tree = "APB2"
%% set prefix = "IOP"
-%% elif target["family"] in ["l4"]
+%% elif target["family"] in ["l4", "g4"]
%% set clock_tree = 'AHB2'
%% elif target["family"] in ["g0"]
%% set clock_tree = 'IOP'
diff --git a/src/modm/platform/gpio/stm32/module.lb b/src/modm/platform/gpio/stm32/module.lb
index 3528d4678e..9cdcf90211 100644
--- a/src/modm/platform/gpio/stm32/module.lb
+++ b/src/modm/platform/gpio/stm32/module.lb
@@ -237,11 +237,11 @@ def validate(env):
all_peripherals.extend([get_driver(r) for r in driver["remap"]])
bprops["all_peripherals"] = sorted(list(set(all_peripherals)))
bprops["all_signals"] = sorted(list(set(s["name"] for s in all_signals.values())))
- bprops["pf"] = "1" if device.identifier["family"] in ["l4", "g0"] else ""
+ bprops["pf"] = "1" if device.identifier["family"] in ["l4", "g0", "g4"] else ""
# Check the max number of ADC instances
max_adc_instance = max(map(int, device.get_driver("adc").get("instance", [1])))
- if (max_adc_instance > (3 if device.identifier["family"] == "f1" else 4)):
+ if (max_adc_instance > (3 if device.identifier["family"] == "f1" else 5 if device.identifier["family"] == "g4" else 4)):
raise ValidateException("Too many ADC instances: '{}'".format(max_adc_instance))
def build(env):
diff --git a/tools/openocd/modm/st_nucleo_g4.cfg b/tools/openocd/modm/st_nucleo_g4.cfg
new file mode 100644
index 0000000000..00dabbad44
--- /dev/null
+++ b/tools/openocd/modm/st_nucleo_g4.cfg
@@ -0,0 +1,11 @@
+# Should work with all STM32G4 Nucleo Dev Boards.
+# http://www.st.com/en/evaluation-tools/stm32-mcu-nucleo.html
+
+source [find interface/stlink.cfg]
+
+transport select hla_swd
+
+source [find target/stm32g4x.cfg]
+
+# use hardware reset
+reset_config srst_only srst_nogate
diff --git a/tools/scripts/generate_module_docs.py b/tools/scripts/generate_module_docs.py
index 2b8ab70be0..10c8c13c4e 100755
--- a/tools/scripts/generate_module_docs.py
+++ b/tools/scripts/generate_module_docs.py
@@ -49,7 +49,7 @@ def get_modules(builder, limit=None):
num_options = []
print("Querying for {} targets...".format(len(targets)))
- mtargets = []
+ mfinal = None
for target in targets:
option.value = target
target = option.value._identifier
@@ -107,13 +107,12 @@ def get_modules(builder, limit=None):
qp.setAttribute("type", type(c).__name__)
qp.setAttribute("_description", q._description)
+ if mfinal is None:
+ mfinal = modules["modm"]
+ else:
+ mfinal.merge(modules["modm"])
- mtargets.append(modules["modm"])
- print("Merging module tree...")
- mfinal = mtargets[0]
- for mtarg in mtargets[1:]:
- mfinal.merge(mtarg)
print("Sorting module tree...")
mfinal._sortTree()