Add STM32F769I-DISC0 targets
Add build targets for the STM32F769I-DISC0(1). This device has a
display, but this change does not add a display driver so
blinky and strings are the only applications currently built
for this target.
(1) https://www.st.com/en/evaluation-tools/32f769idiscovery.html
Change-Id: Ib4e93171164d546449a4615066aeb35273b3f006
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/experimental/+/118550
Reviewed-by: Anthony DiGirolamo <tonymd@google.com>
Commit-Queue: Chris Mumford <cmumford@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index 0663b34..424339c 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -93,6 +93,16 @@
]
}
+# stm32f769i_disc0 specific targets.
+group("stm32f769i_disc0") {
+ _default_toolchain = "//targets/stm32f769i_disc0:stm32f769i_disc0_debug"
+ _testing_toolchain = "${_default_toolchain}_tests"
+ deps = [
+ # ":app(${_default_toolchain})",
+ ":tests(${_testing_toolchain})",
+ ]
+}
+
# This group is built during bootstrap to setup the interactive Python
# environment.
pw_python_group("python") {
@@ -114,6 +124,7 @@
"$dir_pw_env_setup:core_pigweed_python_packages",
"$dir_pigweed/targets/lm3s6965evb_qemu/py",
"$dir_pigweed/targets/stm32f429i_disc1/py",
+ "//targets/stm32f769i_disc0/py",
]
_all_python_packages =
@@ -211,6 +222,14 @@
"//applications/strings:all(//targets/stm32f429i_disc1:stm32f429i_disc1_debug)",
]
+ # STMicroelectronics STM32F769I-DISC0 applications steps.
+ deps += [
+ ":applications_tests(//targets/stm32f769i_disc0:stm32f769i_disc0_debug_tests)",
+ "//applications/blinky:blinky(//targets/stm32f769i_disc0:stm32f769i_disc0_debug)",
+ "//applications/rpc:all(//targets/stm32f769i_disc0:stm32f769i_disc0_debug)",
+ "//applications/strings:all(//targets/stm32f769i_disc0:stm32f769i_disc0_debug)",
+ ]
+
if (dir_pw_third_party_stm32cube_f4 != "") {
# STMicroelectronics STM32F429I-DISC1 STM32Cube applications steps.
deps += [
@@ -230,6 +249,14 @@
deps += [ "//applications/blinky:blinky(//targets/stm32f207zg-nucleo:stm32f207zg_nucleo_debug)" ]
}
+ if (dir_pw_third_party_stm32cube_f4 != "") {
+ # STMicroelectronics STM32F769I-DISC0 STM32Cube applications steps.
+ deps += [
+ ":applications_tests(//targets/stm32f769i_disc0_stm32cube:stm32f769i_disc0_stm32cube_debug)",
+ "//applications/blinky:blinky(//targets/stm32f769i_disc0_stm32cube:stm32f769i_disc0_stm32cube_debug)",
+ ]
+ }
+
if (dir_pw_third_party_stm32cube_l5 != "") {
deps += [ "//applications/blinky:blinky(//targets/stm32l552ze-nucleo:stm32l552ze_nucleo_debug)" ]
}
diff --git a/README.md b/README.md
index a62e396..3088382 100644
--- a/README.md
+++ b/README.md
@@ -57,6 +57,29 @@
openocd -f third_party/pigweed/targets/stm32f429i_disc1/py/stm32f429i_disc1_utils/openocd_stm32f4xx.cfg -c "program out/stm32f429i_disc1_stm32cube_debug/obj/applications/terminal_display/bin/terminal_demo.elf verify reset exit"
```
+#### **[STM32F769-DISC0](https://www.st.com/en/evaluation-tools/32f769idiscovery.html)**
+
+**First time setup:**
+```
+pw package install stm32cube_f7
+```
+
+**Compile:**
+
+```sh
+gn gen out --export-compile-commands --args="
+ dir_pw_third_party_stm32cube_f7=\"//environment/packages/stm32cube_f7\"
+"
+ninja -C out
+```
+
+**Flash:**
+
+```
+openocd -f targets/stm32f769i_disc0/py/stm32f769i_disc0_utils/openocd_stm32f7xx.cfg \
+ -c "program out/stm32f769i_disc0_debug/obj/applications/blinky/bin/blinky.elf verify reset exit"
+```
+
#### **Linux, Windows or Mac**
**Compile:**
diff --git a/build_overrides/pigweed.gni b/build_overrides/pigweed.gni
index 9b9cb9f..03cc222 100644
--- a/build_overrides/pigweed.gni
+++ b/build_overrides/pigweed.gni
@@ -40,6 +40,9 @@
dir_pw_board_led_stm32f429i_disc1 =
get_path_info("$dir_pigweed_experimental/pw_board_led_stm32f429i_disc1",
"abspath")
+ dir_pw_board_led_stm32f769i_disc0 =
+ get_path_info("$dir_pigweed_experimental/pw_board_led_stm32f769i_disc0",
+ "abspath")
dir_pw_board_led_stm32cube =
get_path_info("$dir_pigweed_experimental/pw_board_led_stm32cube",
"abspath")
@@ -119,6 +122,12 @@
dir_pw_spin_delay_stm32cube =
get_path_info("$dir_pigweed_experimental/pw_spin_delay_stm32cube",
"abspath")
+ dir_pw_spin_delay_stm32f769i_disc0 =
+ get_path_info("$dir_pigweed_experimental/pw_spin_delay_stm32f769i_disc0",
+ "abspath")
+ dir_pw_sys_io_baremetal_stm32f769 =
+ get_path_info("$dir_pigweed_experimental/pw_sys_io_baremetal_stm32f769",
+ "abspath")
dir_pw_touchscreen =
get_path_info("$dir_pigweed_experimental/pw_graphics/pw_touchscreen",
"abspath")
diff --git a/pw_board_led_stm32f769i_disc0/BUILD.gn b/pw_board_led_stm32f769i_disc0/BUILD.gn
new file mode 100644
index 0000000..1d31ea4
--- /dev/null
+++ b/pw_board_led_stm32f769i_disc0/BUILD.gn
@@ -0,0 +1,25 @@
+# Copyright 2023 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+import("//build_overrides/pigweed.gni")
+
+import("$dir_pw_build/target_types.gni")
+
+pw_source_set("pw_board_led_stm32f769i_disc0") {
+ deps = [
+ "$dir_pw_board_led:pw_board_led.facade",
+ dir_pw_preprocessor,
+ ]
+ sources = [ "led.cc" ]
+}
diff --git a/pw_board_led_stm32f769i_disc0/led.cc b/pw_board_led_stm32f769i_disc0/led.cc
new file mode 100644
index 0000000..47658fb
--- /dev/null
+++ b/pw_board_led_stm32f769i_disc0/led.cc
@@ -0,0 +1,108 @@
+// Copyright 2023 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#include "pw_board_led/led.h"
+
+#include <cinttypes>
+
+#include "pw_preprocessor/compiler.h"
+
+namespace pw::board_led {
+namespace {
+
+// Base address for everything peripheral-related on the STM32F7xx.
+constexpr uint32_t kPeripheralBaseAddr = 0x40000000u;
+// Base address for everything AHB1-related on the STM32F7xx.
+constexpr uint32_t kAhb1PeripheralBase = kPeripheralBaseAddr + 0x00020000u;
+
+constexpr uint32_t RCC_AHB1ENR_GPIOJEN_Pos = 9;
+
+// Reset/clock configuration block (RCC).
+// `reserved` fields are unimplemented features, and are present to ensure
+// proper alignment of registers that are in use.
+PW_PACKED(struct) RccBlock {
+ uint32_t reserved1[12];
+ uint32_t ahb1_config;
+ uint32_t reserved2[4];
+ uint32_t apb2_config;
+};
+
+// GPIO register block definition.
+PW_PACKED(struct) GpioBlock {
+ uint32_t modes;
+ uint32_t out_type;
+ uint32_t out_speed;
+ uint32_t pull_up_down;
+ uint32_t input_data;
+ uint32_t output_data;
+ uint32_t gpio_bit_set;
+ uint32_t port_config_lock;
+ uint32_t alt_low;
+ uint32_t alt_high;
+};
+
+// Constants related to GPIO mode register masks.
+constexpr uint32_t kGpioPortModeMask = 0x3u;
+constexpr uint32_t kGpio13PortModePos = 26;
+constexpr uint32_t kGpioPortModeOutput = 1;
+
+// Constants related to GPIO output mode register masks.
+constexpr uint32_t kGpioOutputModeMask = 0x1u;
+constexpr uint32_t kGpio13OutputModePos = 13;
+constexpr uint32_t kGpioOutputModePushPull = 0;
+
+constexpr uint32_t kGpio13BitSetHigh = 0x1u << 13;
+constexpr uint32_t kGpio13BitSetLow = kGpio13BitSetHigh << 16;
+
+// Mask for ahb1_config (AHB1ENR) to enable the "J" GPIO pins.
+constexpr uint32_t kGpioJEnable = 0x1u << RCC_AHB1ENR_GPIOJEN_Pos;
+
+// Declare a reference to the memory mapped RCC block.
+volatile RccBlock& platform_rcc =
+ *reinterpret_cast<volatile RccBlock*>(kAhb1PeripheralBase + 0x3800U);
+
+// Declare a reference to the 'J' GPIO memory mapped block.
+volatile GpioBlock& gpio_j =
+ *reinterpret_cast<volatile GpioBlock*>(kAhb1PeripheralBase + 0x2400U);
+
+} // namespace
+
+void Init() {
+ // Enable 'J' GIPO clocks.
+ platform_rcc.ahb1_config |= kGpioJEnable;
+
+ // Enable Pin 13 in output mode.
+ gpio_j.modes = (gpio_j.modes & ~(kGpioPortModeMask << kGpio13PortModePos)) |
+ (kGpioPortModeOutput << kGpio13PortModePos);
+
+ // Enable Pin 13 in output mode "push pull"
+ gpio_j.out_type =
+ (gpio_j.out_type & ~(kGpioOutputModeMask << kGpio13OutputModePos)) |
+ (kGpioOutputModePushPull << kGpio13OutputModePos);
+}
+
+void TurnOff() { gpio_j.gpio_bit_set = kGpio13BitSetLow; }
+
+void TurnOn() { gpio_j.gpio_bit_set = kGpio13BitSetHigh; }
+
+void Toggle() {
+ // Check if the LED is on. If so, turn it off.
+ if (gpio_j.output_data & kGpio13BitSetHigh) {
+ TurnOff();
+ } else {
+ TurnOn();
+ }
+}
+
+} // namespace pw::board_led
diff --git a/pw_spin_delay_stm32f769i_disc0/BUILD.gn b/pw_spin_delay_stm32f769i_disc0/BUILD.gn
new file mode 100644
index 0000000..2daffab
--- /dev/null
+++ b/pw_spin_delay_stm32f769i_disc0/BUILD.gn
@@ -0,0 +1,25 @@
+# Copyright 2023 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+import("//build_overrides/pigweed.gni")
+
+import("$dir_pw_build/target_types.gni")
+
+pw_source_set("pw_spin_delay_stm32f769i_disc0") {
+ deps = [
+ "$dir_pw_spin_delay:pw_spin_delay.facade",
+ dir_pw_preprocessor,
+ ]
+ sources = [ "delay.cc" ]
+}
diff --git a/pw_spin_delay_stm32f769i_disc0/delay.cc b/pw_spin_delay_stm32f769i_disc0/delay.cc
new file mode 100644
index 0000000..365070b
--- /dev/null
+++ b/pw_spin_delay_stm32f769i_disc0/delay.cc
@@ -0,0 +1,57 @@
+// Copyright 2023 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#include "pw_spin_delay/delay.h"
+
+#include <cstddef>
+#include <cstdint>
+
+namespace pw::spin_delay {
+
+// !!!WARNING!!!: This delay is not truly accurate! It's mostly just a rough
+// estimate! Also, it only works in a baremetal context with no interrupts
+// getting in the way or threads getting CPU time.
+//
+// TODO(amontanez): Replace this implementation with a loop checking a
+// pw_chrono clock.
+void WaitMillis(size_t delay_ms) {
+ // Default core clock. This is technically not a constant, but since Pigweed
+ // doesn't change the system clock a constant will suffice.
+ constexpr uint32_t kSystemCoreClock = 16000000;
+ constexpr uint32_t kCyclesPerMs = kSystemCoreClock / 1000;
+
+ // This is not totally accurate, but is close enough.
+ for (size_t i = 0; i < delay_ms; i++) {
+ // Do a 4 instruction loop enough times to be running for a millisecond.
+ // This is set up with assembly rather than a regular loop to make the
+ // instruction count predictable (no compiler variation).
+ uint32_t cycles = kCyclesPerMs;
+ asm volatile(
+ " mov r0, %[cycles] \n"
+ " mov r1, #0 \n"
+ "loop: \n"
+ " cmp r1, r0 \n"
+ " itt lt \n"
+ " addlt r1, r1, #4 \n"
+ " blt loop \n"
+ // clang-format off
+ : /*output=*/
+ : /*input=*/[cycles]"r"(cycles)
+ : /*clobbers=*/"r0", "r1"
+ // clang-format on
+ );
+ }
+}
+
+} // namespace pw::spin_delay
diff --git a/pw_sys_io_baremetal_stm32f769/BUILD.bazel b/pw_sys_io_baremetal_stm32f769/BUILD.bazel
new file mode 100644
index 0000000..e1f4fed
--- /dev/null
+++ b/pw_sys_io_baremetal_stm32f769/BUILD.bazel
@@ -0,0 +1,38 @@
+# Copyright 2023 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+load(
+ "//pw_build:pigweed.bzl",
+ "pw_cc_library",
+)
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"])
+
+pw_cc_library(
+ name = "pw_sys_io_baremetal_stm32f769",
+ srcs = ["sys_io_baremetal.cc"],
+ hdrs = ["public/pw_sys_io_baremetal_stm32f769/init.h"],
+ includes = ["public"],
+ target_compatible_with = [
+ "//pw_build/constraints/chipset:stm32f769",
+ "@platforms//os:none",
+ ],
+ deps = [
+ "//pw_preprocessor",
+ "//pw_sys_io:default_putget_bytes",
+ "//pw_sys_io:facade",
+ ],
+)
diff --git a/pw_sys_io_baremetal_stm32f769/BUILD.gn b/pw_sys_io_baremetal_stm32f769/BUILD.gn
new file mode 100644
index 0000000..9dc27ee
--- /dev/null
+++ b/pw_sys_io_baremetal_stm32f769/BUILD.gn
@@ -0,0 +1,44 @@
+# Copyright 2023 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+import("//build_overrides/pigweed.gni")
+
+import("$dir_pw_build/target_types.gni")
+import("$dir_pw_docgen/docs.gni")
+import("$dir_pw_unit_test/test.gni")
+
+config("default_config") {
+ include_dirs = [ "public" ]
+}
+
+pw_source_set("pw_sys_io_baremetal_stm32f769") {
+ public_configs = [ ":default_config" ]
+ public = [ "public/pw_sys_io_baremetal_stm32f769/init.h" ]
+ public_deps = [
+ "$dir_pw_boot_cortex_m:armv7m",
+ "$dir_pw_preprocessor",
+ ]
+ deps = [
+ "$dir_pw_sys_io:default_putget_bytes",
+ "$dir_pw_sys_io:facade",
+ ]
+ sources = [ "sys_io_baremetal.cc" ]
+}
+
+pw_doc_group("docs") {
+ sources = [ "docs.rst" ]
+}
+
+pw_test_group("tests") {
+}
diff --git a/pw_sys_io_baremetal_stm32f769/OWNERS b/pw_sys_io_baremetal_stm32f769/OWNERS
new file mode 100644
index 0000000..61bb96c
--- /dev/null
+++ b/pw_sys_io_baremetal_stm32f769/OWNERS
@@ -0,0 +1 @@
+cmumford@google.com
diff --git a/pw_sys_io_baremetal_stm32f769/docs.rst b/pw_sys_io_baremetal_stm32f769/docs.rst
new file mode 100644
index 0000000..40a57cd
--- /dev/null
+++ b/pw_sys_io_baremetal_stm32f769/docs.rst
@@ -0,0 +1,61 @@
+.. _module-pw_sys_io_baremetal_stm32f769:
+
+-----------------------------
+pw_sys_io_baremetal_stm32f769
+-----------------------------
+
+``pw_sys_io_baremetal_stm32f769`` implements the ``pw_sys_io`` facade over
+UART.
+
+The STM32F769 baremetal sys IO backend provides device startup code and a UART
+driver layer that allows applications built against the ``pw_sys_io`` interface
+to run on a STM32F769 chip and do simple input/output via UART. The code is
+optimized for the STM32F769I-DISC0, using USART1 (which is connected to the
+virtual COM port on the embedded ST-LINKv2 chip). However, this should work with
+all STM32F769 variations (and even some STM32F7xx chips).
+
+This backend has no configuration options. The point of it is to provide bare-
+minimum platform code needed to do UART reads/writes.
+
+Setup
+=====
+This module requires relatively minimal setup:
+
+ 1. Write code against the ``pw_sys_io`` facade.
+ 2. Specify the ``dir_pw_sys_io_backend`` GN global variable to point to this
+ backend.
+ 3. Build an executable with a main() function using a toolchain that
+ supports Cortex-M4.
+
+.. note::
+ This module provides early firmware init and a linker script, so it will
+ conflict with other modules that do any early device init or provide a linker
+ script.
+
+Module usage
+============
+After building an executable that utilizes this backend, flash the
+produced .elf binary to the development board. Then, using a serial
+communication terminal like minicom/screen (Linux/Mac) or TeraTerm (Windows),
+connect to the device at a baud rate of 115200 (8N1). If you're not using a
+STM32F769I-DISC0 development board, manually connect a USB-to-serial TTL adapter
+to pins ``PA9`` (MCU TX) and ``PA10`` (MCU RX), making sure to match logic
+levels (e.g. 3.3V versus 1.8V).
+
+Sample connection diagram
+-------------------------
+
+.. code-block:: text
+
+ --USB Serial--+ +-----STM32F769 MCU-----
+ | |
+ TX o--->o PA10/USART1_RX
+ | |
+ RX o<---o PA9/USART1_TX
+ | |
+ --------------+ +-----------------------
+
+Dependencies
+============
+ * ``pw_sys_io`` facade
+ * ``pw_preprocessor`` module
diff --git a/pw_sys_io_baremetal_stm32f769/public/pw_sys_io_baremetal_stm32f769/init.h b/pw_sys_io_baremetal_stm32f769/public/pw_sys_io_baremetal_stm32f769/init.h
new file mode 100644
index 0000000..6c3ba73
--- /dev/null
+++ b/pw_sys_io_baremetal_stm32f769/public/pw_sys_io_baremetal_stm32f769/init.h
@@ -0,0 +1,23 @@
+// Copyright 2023 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+#pragma once
+
+#include "pw_preprocessor/util.h"
+
+PW_EXTERN_C_START
+
+// The actual implementation of PreMainInit() in sys_io_BACKEND.
+void pw_sys_io_stm32f769_Init();
+
+PW_EXTERN_C_END
diff --git a/pw_sys_io_baremetal_stm32f769/sys_io_baremetal.cc b/pw_sys_io_baremetal_stm32f769/sys_io_baremetal.cc
new file mode 100644
index 0000000..dc6c1e2
--- /dev/null
+++ b/pw_sys_io_baremetal_stm32f769/sys_io_baremetal.cc
@@ -0,0 +1,217 @@
+// Copyright 2023 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#include <cinttypes>
+
+#include "pw_preprocessor/compiler.h"
+#include "pw_sys_io/sys_io.h"
+
+namespace {
+
+// Default core clock. This is technically not a constant, but since this app
+// doesn't change the system clock a constant will suffice.
+constexpr uint32_t kSystemCoreClock = 16000000;
+
+// Base address for everything peripheral-related on the STM32F7xx.
+constexpr uint32_t kPeripheralBaseAddr = 0x40000000u;
+// Base address for everything AHB1-related on the STM32F7xx.
+constexpr uint32_t kAhb1PeripheralBase = kPeripheralBaseAddr + 0x00020000u;
+// Base address for everything APB2-related on the STM32F7xx.
+constexpr uint32_t kApb2PeripheralBase = kPeripheralBaseAddr + 0x00010000u;
+
+// Reset/clock configuration block (RCC).
+// `reserved` fields are unimplemented features, and are present to ensure
+// proper alignment of registers that are in use.
+PW_PACKED(struct) RccBlock {
+ uint32_t reserved1[12];
+ uint32_t ahb1_config;
+ uint32_t reserved2[4];
+ uint32_t apb2_config;
+};
+
+// Mask for ahb1_config (AHB1ENR) to enable the "A" GPIO pins.
+constexpr uint32_t kGpioAEnable = 0x1u;
+
+// Mask for apb2_config (APB2ENR) to enable USART1.
+constexpr uint32_t kUsart1Enable = 0x1u << 4;
+
+// GPIO register block definition.
+PW_PACKED(struct) GpioBlock {
+ uint32_t modes;
+ uint32_t out_type;
+ uint32_t out_speed;
+ uint32_t pull_up_down;
+ uint32_t input_data;
+ uint32_t output_data;
+ uint32_t gpio_bit_set;
+ uint32_t port_config_lock;
+ uint32_t alt_low;
+ uint32_t alt_high;
+};
+
+// Constants related to GPIO mode register masks.
+constexpr uint32_t kTxPortModePos = 18;
+constexpr uint32_t kRxPortModePos = 20;
+constexpr uint32_t kGpioPortModeAlternate = 2;
+
+// Constants related to GPIO port speed register masks.
+constexpr uint32_t kTxPortSpeedPos = 18;
+constexpr uint32_t kRxPortSpeedPos = 20;
+constexpr uint32_t kGpioSpeedVeryHigh = 3;
+
+// Constants related to GPIO pull up/down resistor type masks.
+constexpr uint32_t kTxPullTypePos = 18;
+constexpr uint32_t kRxPullTypePos = 20;
+constexpr uint32_t kPullTypePullUp = 1;
+
+// Constants related to GPIO port speed register masks.
+constexpr uint32_t kTxAltModeHighPos = 4;
+constexpr uint32_t kRxAltModeHighPos = 8;
+
+// Alternate function for pins PA9(TX) and PA10(RX) that enable USART1.
+constexpr uint8_t kGpioAlternateFunctionUsart1 = 0x07u;
+
+// USART configuration flags for control1 register.
+// Note: a large number of configuration flags have been omitted as they default
+// to reasonable values and we don't need to change them.
+constexpr uint32_t kReceiveEnable = 0x1 << 2;
+constexpr uint32_t kTransmitEnable = 0x1 << 3;
+constexpr uint32_t kEnableUsart = 0x1 << 0;
+// USART configuration flags for interrupt_and_status register.
+constexpr uint32_t kReadDataReady = 0x1 << 5;
+constexpr uint32_t kTxRegisterEmpty = 0x1 << 7;
+
+// Layout of memory mapped registers for USART blocks.
+PW_PACKED(struct) UsartBlock {
+ uint32_t control1;
+ uint32_t control2;
+ uint32_t control3;
+ uint32_t baud_rate;
+ uint32_t guard_time_and_prescalar;
+ uint32_t receiver_timeout;
+ uint32_t request;
+ uint32_t interrupt_and_status;
+ uint32_t interrupt_flag_clear;
+ uint32_t receive_data;
+ uint32_t transmit_data;
+};
+
+// Sets the UART baud register using the peripheral clock and target baud rate.
+// These calculations are specific to the default oversample by 16 mode.
+uint32_t CalcBaudRegister(uint32_t clock, uint32_t target_baud) {
+ uint32_t div_fac = (clock * 25) / (4 * target_baud);
+ uint32_t mantissa = div_fac / 100;
+ uint32_t fraction = ((div_fac - mantissa * 100) * 16 + 50) / 100;
+
+ return (mantissa << 4) + (fraction & 0xFFu);
+}
+
+// Declare a reference to the memory mapped RCC block.
+volatile RccBlock& platform_rcc =
+ *reinterpret_cast<volatile RccBlock*>(kAhb1PeripheralBase + 0x3800U);
+
+// Declare a reference to the 'A' GPIO memory mapped block.
+volatile GpioBlock& gpio_a =
+ *reinterpret_cast<volatile GpioBlock*>(kAhb1PeripheralBase + 0x0000U);
+
+// Declare a reference to the memory mapped block for USART1.
+volatile UsartBlock& usart1 =
+ *reinterpret_cast<volatile UsartBlock*>(kApb2PeripheralBase + 0x1000U);
+
+} // namespace
+
+extern "C" void pw_sys_io_stm32f769_Init() {
+ // Enable 'A' GIPO clocks.
+ platform_rcc.ahb1_config |= kGpioAEnable;
+
+ // Enable Uart TX pin.
+ // Output type defaults to push-pull (rather than open/drain).
+ gpio_a.modes |= kGpioPortModeAlternate << kTxPortModePos;
+ gpio_a.out_speed |= kGpioSpeedVeryHigh << kTxPortSpeedPos;
+ gpio_a.pull_up_down |= kPullTypePullUp << kTxPullTypePos;
+ gpio_a.alt_high |= kGpioAlternateFunctionUsart1 << kTxAltModeHighPos;
+
+ // Enable Uart RX pin.
+ // Output type defaults to push-pull (rather than open/drain).
+ gpio_a.modes |= kGpioPortModeAlternate << kRxPortModePos;
+ gpio_a.out_speed |= kGpioSpeedVeryHigh << kRxPortSpeedPos;
+ gpio_a.pull_up_down |= kPullTypePullUp << kRxPullTypePos;
+ gpio_a.alt_high |= kGpioAlternateFunctionUsart1 << kRxAltModeHighPos;
+
+ // Initialize USART1. Initialized to 8N1 at the specified baud rate.
+ platform_rcc.apb2_config |= kUsart1Enable;
+
+ // Warning: Normally the baud rate register calculation is based off
+ // peripheral 2 clock. For this code, the peripheral clock defaults to
+ // the system core clock so it can be used directly.
+ usart1.baud_rate = CalcBaudRegister(kSystemCoreClock, /*target_baud=*/115200);
+
+ usart1.control1 = kEnableUsart | kReceiveEnable | kTransmitEnable;
+}
+
+namespace pw::sys_io {
+
+// Wait for a byte to read on USART1. This blocks until a byte is read. This is
+// extremely inefficient as it requires the target to burn CPU cycles polling to
+// see if a byte is ready yet.
+Status ReadByte(std::byte* dest) {
+ while (true) {
+ if (TryReadByte(dest).ok()) {
+ return OkStatus();
+ }
+ }
+}
+
+// Wait for a byte to read on USART1. This blocks until a byte is read. This is
+// extremely inefficient as it requires the target to burn CPU cycles polling to
+// see if a byte is ready yet.
+Status TryReadByte(std::byte* dest) {
+ if (!(usart1.interrupt_and_status & kReadDataReady)) {
+ return Status::Unavailable();
+ }
+ *dest = static_cast<std::byte>(usart1.receive_data);
+ usart1.interrupt_flag_clear &= ~kReadDataReady;
+ return OkStatus();
+}
+
+// Send a byte over USART1. Since this blocks on every byte, it's rather
+// inefficient. At the default baud rate of 115200, one byte blocks the CPU for
+// ~87 micro seconds. This means it takes only 10 bytes to block the CPU for
+// 1ms!
+Status WriteByte(std::byte b) {
+ // Wait for TX buffer to be empty. When the buffer is empty, we can write
+ // a value to be dumped out of UART.
+ while (!(usart1.interrupt_and_status & kTxRegisterEmpty)) {
+ }
+ usart1.transmit_data = static_cast<uint32_t>(b);
+ return OkStatus();
+}
+
+// Writes a string using pw::sys_io, and add newline characters at the EOL.
+StatusWithSize WriteLine(const std::string_view& s) {
+ size_t chars_written = 0;
+ StatusWithSize result = WriteBytes(as_bytes(span(s)));
+ if (!result.ok()) {
+ return result;
+ }
+ chars_written += result.size();
+
+ // Write trailing EOL characters.
+ result = WriteBytes(as_bytes(span("\r\n", 2)));
+ chars_written += result.size();
+
+ return StatusWithSize(result.status(), chars_written);
+}
+
+} // namespace pw::sys_io
diff --git a/targets/stm32f429i_disc1_stm32cube/boot.cc b/targets/stm32f429i_disc1_stm32cube/boot.cc
index 1dccb42..f192e87 100644
--- a/targets/stm32f429i_disc1_stm32cube/boot.cc
+++ b/targets/stm32f429i_disc1_stm32cube/boot.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Pigweed Authors
+// Copyright 2023 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
diff --git a/targets/stm32f769i_disc0/BUILD.gn b/targets/stm32f769i_disc0/BUILD.gn
new file mode 100644
index 0000000..539b59a
--- /dev/null
+++ b/targets/stm32f769i_disc0/BUILD.gn
@@ -0,0 +1,49 @@
+# Copyright 2023 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+import("//build_overrides/pigweed.gni")
+
+import("$dir_pw_build/target_types.gni")
+import("$dir_pw_malloc/backend.gni")
+import("$dir_pw_toolchain/generate_toolchain.gni")
+import("target_toolchains.gni")
+
+generate_toolchains("toolchains") {
+ toolchains = toolchains_list
+}
+
+config("pw_malloc_active") {
+ if (pw_malloc_BACKEND != "") {
+ defines = [ "PW_MALLOC_ACTIVE=1" ]
+ }
+}
+
+if (current_toolchain != default_toolchain) {
+ pw_source_set("pre_init") {
+ configs = [ ":pw_malloc_active" ]
+ public_deps = [
+ "$dir_pw_boot",
+ "$dir_pw_boot_cortex_m",
+ "$dir_pw_sys_io_baremetal_stm32f769",
+ ]
+ deps = [
+ "$dir_pw_malloc",
+ "$dir_pw_preprocessor",
+ ]
+ sources = [
+ "boot.cc",
+ "vector_table.c",
+ ]
+ }
+}
diff --git a/targets/stm32f769i_disc0/boot.cc b/targets/stm32f769i_disc0/boot.cc
new file mode 100644
index 0000000..9ff552f
--- /dev/null
+++ b/targets/stm32f769i_disc0/boot.cc
@@ -0,0 +1,68 @@
+// Copyright 2023 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#include "pw_boot/boot.h"
+
+#include "pw_boot_cortex_m/boot.h"
+#include "pw_malloc/malloc.h"
+#include "pw_preprocessor/compiler.h"
+#include "pw_sys_io_baremetal_stm32f769/init.h"
+
+// Note that constexpr is used inside of this function instead of using a static
+// constexpr or declaring it outside of this function in an anonymous namespace,
+// because constexpr makes it available for the compiler to evaluate during
+// compile time but does NOT require it to be evaluated at compile time and we
+// have to be incredibly careful that this does not end up in the .data section.
+void pw_boot_PreStaticMemoryInit() {
+ // TODO(pwbug/17): Optionally enable Replace when Pigweed config system is
+ // added.
+#if PW_ARMV7M_ENABLE_FPU
+ // Enable FPU if built using hardware FPU instructions.
+ // CPCAR mask that enables FPU. (ARMv7-M Section B3.2.20)
+ constexpr uint32_t kFpuEnableMask = (0xFu << 20);
+
+ // Memory mapped register to enable FPU. (ARMv7-M Section B3.2.2, Table B3-4)
+ volatile uint32_t& arm_v7m_cpacr =
+ *reinterpret_cast<volatile uint32_t*>(0xE000ED88u);
+ arm_v7m_cpacr |= kFpuEnableMask;
+
+ // Ensure the FPU configuration is committed and enabled before continuing and
+ // potentially executing any FPU instructions, however rare that may be during
+ // startup.
+ asm volatile(
+ " dsb \n"
+ " isb \n"
+ // clang-format off
+ : /*output=*/
+ : /*input=*/
+ : /*clobbers=*/"memory"
+ // clang-format on
+ );
+#endif // PW_ARMV7M_ENABLE_FPU
+}
+
+void pw_boot_PreStaticConstructorInit() {
+#if PW_MALLOC_ACTIVE
+ pw_MallocInit(&pw_boot_heap_low_addr, &pw_boot_heap_high_addr);
+#endif // PW_MALLOC_ACTIVE
+}
+
+void pw_boot_PreMainInit() { pw_sys_io_stm32f769_Init(); }
+
+PW_NO_RETURN void pw_boot_PostMain() {
+ // In case main() returns, just sit here until the device is reset.
+ while (true) {
+ }
+ PW_UNREACHABLE;
+}
diff --git a/targets/stm32f769i_disc0/pw_target_toolchains.gni b/targets/stm32f769i_disc0/pw_target_toolchains.gni
new file mode 100644
index 0000000..9080da1
--- /dev/null
+++ b/targets/stm32f769i_disc0/pw_target_toolchains.gni
@@ -0,0 +1,156 @@
+# Copyright 2023 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+import("//build_overrides/pigweed.gni")
+
+import("$dir_pw_compilation_testing/negative_compilation_test.gni")
+import("$dir_pw_rpc/system_server/backend.gni")
+import("$dir_pw_sys_io/backend.gni")
+import("$dir_pw_toolchain/arm_gcc/toolchains.gni")
+
+# declare_args() {
+# # Enable the pw_target_runner for on-device testing.
+# pw_use_test_server = false
+# }
+
+_target_config = {
+ # TODO(b/241565082): Enable NC testing in GN Windows when it is fixed.
+ pw_compilation_testing_NEGATIVE_COMPILATION_ENABLED = host_os != "win"
+
+ # Use the logging main.
+ pw_unit_test_MAIN = "$dir_pw_unit_test:logging_main"
+
+ # Configuration options for Pigweed executable targets.
+ pw_build_EXECUTABLE_TARGET_TYPE = "stm32f769i_executable"
+
+ pw_build_EXECUTABLE_TARGET_TYPE_FILE =
+ get_path_info("stm32f769i_executable.gni", "abspath")
+
+ # Path to the bloaty config file for the output binaries.
+ pw_bloat_BLOATY_CONFIG = "$dir_pw_boot_cortex_m/bloaty_config.bloaty"
+
+ # TODO: Fix test server: likely have to fork stm32cube-disc1 implementation
+ # if (pw_use_test_server) {
+ # _test_runner_script = "py/stm32f769i_disc0_utils/unit_test_client.py"
+ # pw_unit_test_AUTOMATIC_RUNNER =
+ # get_path_info(_test_runner_script, "abspath")
+ # }
+
+ # Facade backends
+ pw_assert_BACKEND = dir_pw_assert_basic
+ pw_boot_BACKEND = "$dir_pw_boot_cortex_m"
+ pw_cpu_exception_ENTRY_BACKEND =
+ "$dir_pw_cpu_exception_cortex_m:cpu_exception"
+ pw_cpu_exception_HANDLER_BACKEND = "$dir_pw_cpu_exception:basic_handler"
+ pw_cpu_exception_SUPPORT_BACKEND = "$dir_pw_cpu_exception_cortex_m:support"
+ pw_sync_INTERRUPT_SPIN_LOCK_BACKEND =
+ "$dir_pw_sync_baremetal:interrupt_spin_lock"
+ pw_sync_MUTEX_BACKEND = "$dir_pw_sync_baremetal:mutex"
+ pw_log_BACKEND = dir_pw_log_basic
+ pw_sys_io_BACKEND = dir_pw_sys_io_baremetal_stm32f769
+ pw_rpc_system_server_BACKEND = "$dir_pw_hdlc:hdlc_sys_io_system_server"
+ pw_malloc_BACKEND = dir_pw_malloc_freelist
+
+ pw_boot_cortex_m_LINK_CONFIG_DEFINES = [
+ "PW_BOOT_FLASH_BEGIN=0x08000400",
+ "PW_BOOT_FLASH_SIZE=2048K",
+
+ # TODO(b/235348465): Currently "pw_tokenizer/detokenize_test" requires at
+ # least 6K bytes in heap when using pw_malloc_freelist. The heap size
+ # required for tests should be investigated.
+ #
+ # TLS realted tests such as $dir_pw_third_party/boringssl:tests require
+ # much larger heap for dynamic allocation. The current number is an
+ # estimated requirement. The acutal required size will be further investigated
+ # when all TLS tests are in place.
+ "PW_BOOT_HEAP_SIZE=366K",
+ "PW_BOOT_MIN_STACK_SIZE=1K",
+ "PW_BOOT_RAM_BEGIN=0x20020000",
+ "PW_BOOT_RAM_SIZE=384K",
+ "PW_BOOT_VECTOR_TABLE_BEGIN=0x08000000",
+ "PW_BOOT_VECTOR_TABLE_SIZE=1024",
+ ]
+
+ pw_build_LINK_DEPS = []
+ pw_build_LINK_DEPS = [
+ "$dir_pw_assert:impl",
+ "$dir_pw_cpu_exception:entry_impl",
+ "$dir_pw_log:impl",
+ "$dir_pw_toolchain/arm_gcc:arm_none_eabi_gcc_support",
+ ]
+
+ current_cpu = "arm"
+ current_os = ""
+}
+
+_toolchain_properties = {
+ final_binary_extension = ".elf"
+}
+
+_target_default_configs = [
+ "$dir_pw_build:extra_strict_warnings",
+ "$dir_pw_toolchain/arm_gcc:enable_float_printf",
+]
+
+pw_target_toolchain_stm32f769i_disc0 = {
+ _excluded_members = [
+ "defaults",
+ "name",
+ ]
+
+ debug = {
+ name = "stm32f769i_disc0_debug"
+ _toolchain_base = pw_toolchain_arm_gcc.cortex_m7f_debug
+ forward_variables_from(_toolchain_base, "*", _excluded_members)
+ forward_variables_from(_toolchain_properties, "*")
+ defaults = {
+ forward_variables_from(_toolchain_base.defaults, "*")
+ forward_variables_from(_target_config, "*")
+ default_configs += _target_default_configs
+ }
+ }
+
+ speed_optimized = {
+ name = "stm32f769i_disc0_speed_optimized"
+ _toolchain_base = pw_toolchain_arm_gcc.cortex_m7f_speed_optimized
+ forward_variables_from(_toolchain_base, "*", _excluded_members)
+ forward_variables_from(_toolchain_properties, "*")
+ defaults = {
+ forward_variables_from(_toolchain_base.defaults, "*")
+ forward_variables_from(_target_config, "*")
+ default_configs += _target_default_configs
+ }
+ }
+
+ size_optimized = {
+ name = "stm32f769i_disc0_size_optimized"
+ _toolchain_base = pw_toolchain_arm_gcc.cortex_m7f_size_optimized
+ forward_variables_from(_toolchain_base, "*", _excluded_members)
+ forward_variables_from(_toolchain_properties, "*")
+ defaults = {
+ forward_variables_from(_toolchain_base.defaults, "*")
+ forward_variables_from(_target_config, "*")
+ default_configs += _target_default_configs
+ }
+ }
+}
+
+# This list just contains the members of the above scope for convenience to make
+# it trivial to generate all the toolchains in this file via a
+# `generate_toolchains` target.
+pw_target_toolchain_stm32f769i_disc0_list = [
+ pw_target_toolchain_stm32f769i_disc0.debug,
+ pw_target_toolchain_stm32f769i_disc0.speed_optimized,
+ pw_target_toolchain_stm32f769i_disc0.size_optimized,
+]
diff --git a/targets/stm32f769i_disc0/py/BUILD.gn b/targets/stm32f769i_disc0/py/BUILD.gn
new file mode 100644
index 0000000..e95a6da
--- /dev/null
+++ b/targets/stm32f769i_disc0/py/BUILD.gn
@@ -0,0 +1,35 @@
+# Copyright 2023 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+import("//build_overrides/pigweed.gni")
+
+import("$dir_pw_build/python.gni")
+
+pw_python_package("py") {
+ setup = [
+ "pyproject.toml",
+ "setup.cfg",
+ "setup.py",
+ ]
+ sources = [
+ "stm32f769i_disc0_utils/__init__.py",
+ "stm32f769i_disc0_utils/stm32f769i_detector.py",
+ "stm32f769i_disc0_utils/unit_test_client.py",
+ "stm32f769i_disc0_utils/unit_test_runner.py",
+ "stm32f769i_disc0_utils/unit_test_server.py",
+ ]
+ pylintrc = "$dir_pigweed/.pylintrc"
+ mypy_ini = "$dir_pigweed/.mypy.ini"
+ python_deps = [ "$dir_pw_cli/py" ]
+}
diff --git a/targets/stm32f769i_disc0/py/pyproject.toml b/targets/stm32f769i_disc0/py/pyproject.toml
new file mode 100644
index 0000000..78668a7
--- /dev/null
+++ b/targets/stm32f769i_disc0/py/pyproject.toml
@@ -0,0 +1,16 @@
+# Copyright 2023 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+[build-system]
+requires = ['setuptools', 'wheel']
+build-backend = 'setuptools.build_meta'
diff --git a/targets/stm32f769i_disc0/py/setup.cfg b/targets/stm32f769i_disc0/py/setup.cfg
new file mode 100644
index 0000000..a5d9848
--- /dev/null
+++ b/targets/stm32f769i_disc0/py/setup.cfg
@@ -0,0 +1,36 @@
+# Copyright 2023 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+[metadata]
+name = stm32f769i_disc0_utils
+version = 0.0.1
+author = Pigweed Authors
+author_email = pigweed-developers@googlegroups.com
+description = Target-specific python scripts for the stm32f769i-disc0 target
+
+[options]
+packages = find:
+zip_safe = False
+install_requires =
+ pyserial>=3.5,<4.0
+ coloredlogs
+
+[options.entry_points]
+console_scripts =
+ stm32f769i_disc0_unit_test_runner = stm32f769i_disc0_utils.unit_test_runner:main
+ stm32f769i_disc0_detector = stm32f769i_disc0_utils.stm32f769i_detector:main
+ stm32f769i_disc0_test_server = stm32f769i_disc0_utils.unit_test_server:main
+ stm32f769i_disc0_test_client = stm32f769i_disc0_utils.unit_test_client:main
+
+[options.package_data]
+stm32f769i_disc0_utils = py.typed
diff --git a/targets/stm32f769i_disc0/py/setup.py b/targets/stm32f769i_disc0/py/setup.py
new file mode 100644
index 0000000..b7024fa
--- /dev/null
+++ b/targets/stm32f769i_disc0/py/setup.py
@@ -0,0 +1,18 @@
+# Copyright 2023 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+"""stm32f769i_disc0_utils"""
+
+import setuptools # type: ignore
+
+setuptools.setup() # Package definition in setup.cfg
diff --git a/targets/stm32f769i_disc0/py/stm32f769i_disc0_utils/BUILD.bazel b/targets/stm32f769i_disc0/py/stm32f769i_disc0_utils/BUILD.bazel
new file mode 100644
index 0000000..2ee2e17
--- /dev/null
+++ b/targets/stm32f769i_disc0/py/stm32f769i_disc0_utils/BUILD.bazel
@@ -0,0 +1,18 @@
+# Copyright 2023 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+package(default_visibility = ["//visibility:public"])
+
+# Allow other packages to use this configuration file.
+exports_files(["openocd_stm32f7xx.cfg"])
diff --git a/targets/stm32f769i_disc0/py/stm32f769i_disc0_utils/__init__.py b/targets/stm32f769i_disc0/py/stm32f769i_disc0_utils/__init__.py
new file mode 100644
index 0000000..4ce3458
--- /dev/null
+++ b/targets/stm32f769i_disc0/py/stm32f769i_disc0_utils/__init__.py
@@ -0,0 +1,19 @@
+# Copyright 2023 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+"""This package provides tooling specific to the stm32f769i-disc0 target."""
+
+from stm32f769i_disc0_utils.unit_test_runner import TestingFailure
+from stm32f769i_disc0_utils.unit_test_runner import flash_device
+from stm32f769i_disc0_utils.unit_test_runner import run_device_test
+from stm32f769i_disc0_utils.stm32f769i_detector import detect_boards
diff --git a/targets/stm32f769i_disc0/py/stm32f769i_disc0_utils/openocd_stm32f7xx.cfg b/targets/stm32f769i_disc0/py/stm32f769i_disc0_utils/openocd_stm32f7xx.cfg
new file mode 100644
index 0000000..08a606c
--- /dev/null
+++ b/targets/stm32f769i_disc0/py/stm32f769i_disc0_utils/openocd_stm32f7xx.cfg
@@ -0,0 +1,37 @@
+# Copyright 2023 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+# This openocd configuration is compatible with all STM32F7xx cores.
+
+interface hla
+hla_layout stlink
+hla_device_desc "ST-LINK/V2-1"
+hla_vid_pid 0x0483 0x374b
+
+# If PW_STLINK_SERIAL is specified, use that device.
+if { [info exists ::env(PW_STLINK_SERIAL)] } {
+ hla_serial $::env(PW_STLINK_SERIAL)
+}
+
+# If PW_GDB_PORT is specified, use that port.
+if { [info exists ::env(PW_GDB_PORT)] } {
+ gdb_port $::env(PW_GDB_PORT)
+}
+
+transport select hla_swd
+
+source [find target/stm32f7x.cfg]
+
+# Use hardware reset.
+reset_config srst_only srst_nogate
diff --git a/targets/stm32f769i_disc0/py/stm32f769i_disc0_utils/py.typed b/targets/stm32f769i_disc0/py/stm32f769i_disc0_utils/py.typed
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/targets/stm32f769i_disc0/py/stm32f769i_disc0_utils/py.typed
diff --git a/targets/stm32f769i_disc0/py/stm32f769i_disc0_utils/stm32f769i_detector.py b/targets/stm32f769i_disc0/py/stm32f769i_disc0_utils/stm32f769i_detector.py
new file mode 100644
index 0000000..54195d5
--- /dev/null
+++ b/targets/stm32f769i_disc0/py/stm32f769i_disc0_utils/stm32f769i_detector.py
@@ -0,0 +1,78 @@
+#!/usr/bin/env python3
+# Copyright 2023 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+"""Detects attached stm32f769i-disc0 boards connected via mini usb."""
+
+import logging
+import typing
+
+import coloredlogs # type: ignore
+import serial.tools.list_ports # type: ignore
+
+# Vendor/device ID to search for in USB devices.
+# Note the STM32F429I-DISC1 and the STM32F769I-DISC0 have the same vendor/model.
+_ST_VENDOR_ID = 0x0483
+_DISCOVERY_MODEL_ID = 0x374b
+
+_LOG = logging.getLogger('stm32f769i_detector')
+
+
+class BoardInfo(typing.NamedTuple):
+ """Information about a connected dev board."""
+ dev_name: str
+ serial_number: str
+
+
+def detect_boards() -> list:
+ """Detect attached boards, returning a list of Board objects."""
+ boards = []
+ all_devs = serial.tools.list_ports.comports()
+ for dev in all_devs:
+ if dev.vid == _ST_VENDOR_ID and dev.pid == _DISCOVERY_MODEL_ID:
+ boards.append(
+ BoardInfo(dev_name=dev.device,
+ serial_number=dev.serial_number))
+ return boards
+
+
+def main():
+ """This detects and then displays all attached discovery boards."""
+
+ # Try to use pw_cli logs, else default to something reasonable.
+ try:
+ import pw_cli.log # pylint: disable=import-outside-toplevel
+ pw_cli.log.install()
+ except ImportError:
+ coloredlogs.install(level='INFO',
+ level_styles={
+ 'debug': {
+ 'color': 244
+ },
+ 'error': {
+ 'color': 'red'
+ }
+ },
+ fmt='%(asctime)s %(levelname)s | %(message)s')
+
+ boards = detect_boards()
+ if not boards:
+ _LOG.info('No attached boards detected')
+ for idx, board in enumerate(boards):
+ _LOG.info('Board %d:', idx)
+ _LOG.info(' - Port: %s', board.dev_name)
+ _LOG.info(' - Serial #: %s', board.serial_number)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/targets/stm32f769i_disc0/py/stm32f769i_disc0_utils/unit_test_client.py b/targets/stm32f769i_disc0/py/stm32f769i_disc0_utils/unit_test_client.py
new file mode 100755
index 0000000..e10b8c8
--- /dev/null
+++ b/targets/stm32f769i_disc0/py/stm32f769i_disc0_utils/unit_test_client.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python3
+# Copyright 2023 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+"""Launch a pw_target_runner client that sends a test request."""
+
+import argparse
+import subprocess
+import sys
+from typing import Optional
+
+_TARGET_CLIENT_COMMAND = 'pw_target_runner_client'
+
+
+def parse_args():
+ """Parses command-line arguments."""
+
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument('binary', help='The target test binary to run')
+ parser.add_argument('--server-port',
+ type=int,
+ help='Port the test server is located on')
+
+ return parser.parse_args()
+
+
+def launch_client(binary: str, server_port: Optional[int]) -> int:
+ """Sends a test request to the specified server port."""
+ cmd = [_TARGET_CLIENT_COMMAND, '-binary', binary]
+
+ if server_port is not None:
+ cmd.extend(['-port', str(server_port)])
+
+ return subprocess.call(cmd)
+
+
+def main() -> int:
+ """Launch a test by sending a request to a pw_target_runner_server."""
+ args = parse_args()
+ return launch_client(args.binary, args.server_port)
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/targets/stm32f769i_disc0/py/stm32f769i_disc0_utils/unit_test_runner.py b/targets/stm32f769i_disc0/py/stm32f769i_disc0_utils/unit_test_runner.py
new file mode 100755
index 0000000..c9b1c50
--- /dev/null
+++ b/targets/stm32f769i_disc0/py/stm32f769i_disc0_utils/unit_test_runner.py
@@ -0,0 +1,312 @@
+#!/usr/bin/env python3
+# Copyright 2023 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+"""This script flashes and runs unit tests on stm32f769i-disc0 boards."""
+
+import argparse
+import logging
+import os
+import subprocess
+import sys
+import threading
+from typing import List
+
+import coloredlogs # type: ignore
+import serial # type: ignore
+from stm32f769i_disc0_utils import stm32f769i_detector
+
+# Path used to access non-python resources in this python module.
+_DIR = os.path.dirname(__file__)
+
+# Path to default openocd configuration file.
+_OPENOCD_CONFIG = os.path.join(_DIR, 'openocd_stm32f7xx.cfg')
+
+# Path to scripts provided by openocd.
+_OPENOCD_SCRIPTS_DIR = os.path.join(
+ os.getenv('PW_PIGWEED_CIPD_INSTALL_DIR', ''), 'share', 'openocd',
+ 'scripts')
+
+_LOG = logging.getLogger('unit_test_runner')
+
+# Verification of test pass/failure depends on these strings. If the formatting
+# or output of the simple_printing_event_handler changes, this may need to be
+# updated.
+_TESTS_STARTING_STRING = b'[==========] Running all tests.'
+_TESTS_DONE_STRING = b'[==========] Done running all tests.'
+_TEST_FAILURE_STRING = b'[ FAILED ]'
+
+# How long to wait for the first byte of a test to be emitted. This is longer
+# than the user-configurable timeout as there's a delay while the device is
+# flashed.
+_FLASH_TIMEOUT = 5.0
+
+
+class TestingFailure(Exception):
+ """A simple exception to be raised when a testing step fails."""
+
+
+class DeviceNotFound(Exception):
+ """A simple exception to be raised when unable to connect to a device."""
+
+
+def parse_args():
+ """Parses command-line arguments."""
+
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument('binary', help='The target test binary to run')
+ parser.add_argument('--openocd-config',
+ default=_OPENOCD_CONFIG,
+ help='Path to openocd configuration file')
+ parser.add_argument('--stlink-serial',
+ default=None,
+ help='The serial number of the stlink to use when '
+ 'flashing the target device')
+ parser.add_argument('--port',
+ default=None,
+ help='The name of the serial port to connect to when '
+ 'running tests')
+ parser.add_argument('--baud',
+ type=int,
+ default=115200,
+ help='Target baud rate to use for serial communication'
+ ' with target device')
+ parser.add_argument('--test-timeout',
+ type=float,
+ default=5.0,
+ help='Maximum communication delay in seconds before a '
+ 'test is considered unresponsive and aborted')
+ parser.add_argument('--verbose',
+ '-v',
+ dest='verbose',
+ action="store_true",
+ help='Output additional logs as the script runs')
+
+ return parser.parse_args()
+
+
+def log_subprocess_output(level, output):
+ """Logs subprocess output line-by-line."""
+
+ lines = output.decode('utf-8', errors='replace').splitlines()
+ for line in lines:
+ _LOG.log(level, line)
+
+
+def reset_device(openocd_config, stlink_serial):
+ """Uses openocd to reset the attached device."""
+
+ # Name/path of openocd.
+ default_flasher = 'openocd'
+ flash_tool = os.getenv('OPENOCD_PATH', default_flasher)
+
+ cmd = [
+ flash_tool, '-s', _OPENOCD_SCRIPTS_DIR, '-f', openocd_config, '-c',
+ 'init', '-c', 'reset run', '-c', 'exit'
+ ]
+ _LOG.debug('Resetting device')
+
+ env = os.environ.copy()
+ if stlink_serial:
+ env['PW_STLINK_SERIAL'] = stlink_serial
+
+ # Disable GDB port to support multi-device testing.
+ env['PW_GDB_PORT'] = 'disabled'
+ process = subprocess.run(cmd,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ env=env)
+ if process.returncode:
+ log_subprocess_output(logging.ERROR, process.stdout)
+ raise TestingFailure('Failed to reset target device')
+
+ log_subprocess_output(logging.DEBUG, process.stdout)
+
+ _LOG.debug('Successfully reset device')
+
+
+def read_serial(port, baud_rate, test_timeout) -> bytes:
+ """Reads lines from a serial port until a line read times out.
+
+ Returns bytes object containing the read serial data.
+ """
+
+ serial_data = bytearray()
+ device = serial.Serial(baudrate=baud_rate,
+ port=port,
+ timeout=_FLASH_TIMEOUT)
+ if not device.is_open:
+ raise TestingFailure('Failed to open device')
+
+ # Flush input buffer and reset the device to begin the test.
+ device.reset_input_buffer()
+
+ # Block and wait for the first byte.
+ serial_data += device.read()
+ if not serial_data:
+ raise TestingFailure('Device not producing output')
+
+ device.timeout = test_timeout
+
+ # Read with a reasonable timeout until we stop getting characters.
+ while True:
+ bytes_read = device.readline()
+ if not bytes_read:
+ break
+ serial_data += bytes_read
+ if serial_data.rfind(_TESTS_DONE_STRING) != -1:
+ # Set to much more aggressive timeout since the last one or two
+ # lines should print out immediately. (one line if all fails or all
+ # passes, two lines if mixed.)
+ device.timeout = 0.01
+
+ # Remove carriage returns.
+ serial_data = serial_data.replace(b'\r', b'')
+
+ # Try to trim captured results to only contain most recent test run.
+ test_start_index = serial_data.rfind(_TESTS_STARTING_STRING)
+ return serial_data if test_start_index == -1 else serial_data[
+ test_start_index:]
+
+
+def flash_device(binary, openocd_config, stlink_serial):
+ """Flash binary to a connected device using the provided configuration."""
+
+ # Name/path of openocd.
+ default_flasher = 'openocd'
+ flash_tool = os.getenv('OPENOCD_PATH', default_flasher)
+
+ openocd_command = ' '.join(['program', binary, 'reset', 'exit'])
+ cmd = [
+ flash_tool, '-s', _OPENOCD_SCRIPTS_DIR, '-f', openocd_config, '-c',
+ openocd_command
+ ]
+ _LOG.info('Flashing firmware to device')
+
+ env = os.environ.copy()
+ if stlink_serial:
+ env['PW_STLINK_SERIAL'] = stlink_serial
+
+ # Disable GDB port to support multi-device testing.
+ env['PW_GDB_PORT'] = 'disabled'
+ process = subprocess.run(cmd,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ env=env)
+ if process.returncode:
+ log_subprocess_output(logging.ERROR, process.stdout)
+ raise TestingFailure('Failed to flash target device')
+
+ log_subprocess_output(logging.DEBUG, process.stdout)
+
+ _LOG.debug('Successfully flashed firmware to device')
+
+
+def handle_test_results(test_output):
+ """Parses test output to determine whether tests passed or failed."""
+
+ if test_output.find(_TESTS_STARTING_STRING) == -1:
+ raise TestingFailure('Failed to find test start')
+
+ if test_output.rfind(_TESTS_DONE_STRING) == -1:
+ log_subprocess_output(logging.INFO, test_output)
+ raise TestingFailure('Tests did not complete')
+
+ if test_output.rfind(_TEST_FAILURE_STRING) != -1:
+ log_subprocess_output(logging.INFO, test_output)
+ raise TestingFailure('Test suite had one or more failures')
+
+ log_subprocess_output(logging.DEBUG, test_output)
+
+ _LOG.info('Test passed!')
+
+
+def _threaded_test_reader(dest, port, baud_rate, test_timeout):
+ """Parses test output to the mutable "dest" passed to this function."""
+ dest.append(read_serial(port, baud_rate, test_timeout))
+
+
+def run_device_test(binary,
+ test_timeout,
+ openocd_config,
+ baud,
+ stlink_serial=None,
+ port=None) -> bool:
+ """Flashes, runs, and checks an on-device test binary.
+
+ Returns true on test pass.
+ """
+
+ if stlink_serial is None and port is None:
+ _LOG.debug('Attempting to automatically detect dev board')
+ boards = stm32f769i_detector.detect_boards()
+ if not boards:
+ error = 'Could not find an attached device'
+ _LOG.error(error)
+ raise DeviceNotFound(error)
+ stlink_serial = boards[0].serial_number
+ port = boards[0].dev_name
+
+ _LOG.debug('Launching test binary %s', binary)
+ try:
+ # Begin capturing test output via another thread BEFORE flashing the
+ # device since the test will automatically run after the image is
+ # flashed. This reduces flake since there isn't a need to time a reset
+ # correctly relative to the start of capturing device output.
+ result: List[bytes] = []
+ threaded_reader_args = (result, port, baud, test_timeout)
+ read_thread = threading.Thread(target=_threaded_test_reader,
+ args=threaded_reader_args)
+ read_thread.start()
+ _LOG.info('Running test')
+ flash_device(binary, openocd_config, stlink_serial)
+ read_thread.join()
+ if result:
+ handle_test_results(result[0])
+ except TestingFailure as err:
+ _LOG.error(err)
+ return False
+
+ return True
+
+
+def main():
+ """Set up runner, and then flash/run device test."""
+ args = parse_args()
+
+ # Try to use pw_cli logs, else default to something reasonable.
+ try:
+ import pw_cli.log # pylint: disable=import-outside-toplevel
+ log_level = logging.DEBUG if args.verbose else logging.INFO
+ pw_cli.log.install(level=log_level)
+ except ImportError:
+ coloredlogs.install(level='DEBUG' if args.verbose else 'INFO',
+ level_styles={
+ 'debug': {
+ 'color': 244
+ },
+ 'error': {
+ 'color': 'red'
+ }
+ },
+ fmt='%(asctime)s %(levelname)s | %(message)s')
+
+ if run_device_test(args.binary, args.test_timeout, args.openocd_config,
+ args.baud, args.stlink_serial, args.port):
+ sys.exit(0)
+ else:
+ sys.exit(1)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/targets/stm32f769i_disc0/py/stm32f769i_disc0_utils/unit_test_server.py b/targets/stm32f769i_disc0/py/stm32f769i_disc0_utils/unit_test_server.py
new file mode 100644
index 0000000..4fa8d31
--- /dev/null
+++ b/targets/stm32f769i_disc0/py/stm32f769i_disc0_utils/unit_test_server.py
@@ -0,0 +1,116 @@
+#!/usr/bin/env python3
+# Copyright 2023 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+"""Launch a pw_target_runner server to use for multi-device testing."""
+
+import argparse
+import logging
+import sys
+import tempfile
+from typing import IO, List, Optional
+
+import pw_cli.process
+import pw_cli.log
+
+from stm32f769i_disc0_utils import stm32f769i_detector
+
+_LOG = logging.getLogger('unit_test_server')
+
+_TEST_RUNNER_COMMAND = 'stm32f769i_disc0_unit_test_runner'
+
+_TEST_SERVER_COMMAND = 'pw_target_runner_server'
+
+
+def parse_args():
+ """Parses command-line arguments."""
+
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument('--server-port',
+ type=int,
+ default=8080,
+ help='Port to launch the pw_target_runner_server on')
+ parser.add_argument('--server-config',
+ type=argparse.FileType('r'),
+ help='Path to server config file')
+ parser.add_argument('--verbose',
+ '-v',
+ dest='verbose',
+ action="store_true",
+ help='Output additional logs as the script runs')
+
+ return parser.parse_args()
+
+
+def generate_runner(command: str, arguments: List[str]) -> str:
+ """Generates a text-proto style pw_target_runner_server configuration."""
+ # TODO(amontanez): Use a real proto library to generate this when we have
+ # one set up.
+ for i, arg in enumerate(arguments):
+ arguments[i] = f' args: "{arg}"'
+ runner = ['runner {', f' command:"{command}"']
+ runner.extend(arguments)
+ runner.append('}\n')
+ return '\n'.join(runner)
+
+
+def generate_server_config() -> IO[bytes]:
+ """Returns a temporary generated file for use as the server config."""
+ boards = stm32f769i_detector.detect_boards()
+ if not boards:
+ _LOG.critical('No attached boards detected')
+ sys.exit(1)
+ config_file = tempfile.NamedTemporaryFile()
+ _LOG.debug('Generating test server config at %s', config_file.name)
+ _LOG.debug('Found %d attached devices', len(boards))
+ for board in boards:
+ test_runner_args = [
+ '--stlink-serial', board.serial_number, '--port', board.dev_name
+ ]
+ config_file.write(
+ generate_runner(_TEST_RUNNER_COMMAND,
+ test_runner_args).encode('utf-8'))
+ config_file.flush()
+ return config_file
+
+
+def launch_server(server_config: Optional[IO[bytes]],
+ server_port: Optional[int]) -> int:
+ """Launch a device test server with the provided arguments."""
+ if server_config is None:
+ # Auto-detect attached boards if no config is provided.
+ server_config = generate_server_config()
+
+ cmd = [_TEST_SERVER_COMMAND, '-config', server_config.name]
+
+ if server_port is not None:
+ cmd.extend(['-port', str(server_port)])
+
+ return pw_cli.process.run(*cmd, log_output=True).returncode
+
+
+def main():
+ """Launch a device test server with the provided arguments."""
+ args = parse_args()
+
+ # Try to use pw_cli logs, else default to something reasonable.
+ pw_cli.log.install()
+ if args.verbose:
+ _LOG.setLevel(logging.DEBUG)
+
+ exit_code = launch_server(args.server_config, args.server_port)
+ sys.exit(exit_code)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/targets/stm32f769i_disc0/stm32f769i_executable.gni b/targets/stm32f769i_disc0/stm32f769i_executable.gni
new file mode 100644
index 0000000..9ce30ce
--- /dev/null
+++ b/targets/stm32f769i_disc0/stm32f769i_executable.gni
@@ -0,0 +1,33 @@
+# Copyright 2023 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+import("//build_overrides/pigweed.gni")
+import("$dir_pw_malloc/backend.gni")
+
+# Executable wrapper that includes some baremetal startup code.
+template("stm32f769i_executable") {
+ target("executable", target_name) {
+ forward_variables_from(invoker, "*")
+ if (!defined(deps)) {
+ deps = []
+ }
+ deps += [ "//targets/stm32f769i_disc0:pre_init" ]
+ if (pw_malloc_BACKEND != "") {
+ if (!defined(configs)) {
+ configs = []
+ }
+ configs += [ "$dir_pw_malloc:pw_malloc_wrapper_config" ]
+ }
+ }
+}
diff --git a/targets/stm32f769i_disc0/target_toolchains.gni b/targets/stm32f769i_disc0/target_toolchains.gni
new file mode 100644
index 0000000..87a90c0
--- /dev/null
+++ b/targets/stm32f769i_disc0/target_toolchains.gni
@@ -0,0 +1,64 @@
+# Copyright 2023 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+import("//build_overrides/pigweed.gni")
+
+import("//targets/common_backends.gni")
+import("$dir_pw_protobuf_compiler/proto.gni")
+import("$dir_pw_third_party/nanopb/nanopb.gni")
+import("pw_target_toolchains.gni")
+
+target_toolchain_stm32f769i_disc0 = {
+ _excluded_members = [
+ "defaults",
+ "name",
+ ]
+ _excluded_defaults = [
+ "pw_cpu_exception_ENTRY_BACKEND",
+ "pw_cpu_exception_HANDLER_BACKEND",
+ "pw_cpu_exception_SUPPORT_BACKEND",
+ ]
+
+ debug = {
+ name = "stm32f769i_disc0_debug"
+ _toolchain_base = pw_target_toolchain_stm32f769i_disc0.debug
+ forward_variables_from(_toolchain_base, "*", _excluded_members)
+ defaults = {
+ forward_variables_from(_toolchain_base.defaults, "*", _excluded_defaults)
+ forward_variables_from(toolchain_overrides, "*")
+ pw_board_led_BACKEND = "$dir_pw_board_led_stm32f769i_disc0"
+ pw_spin_delay_BACKEND = "$dir_pw_spin_delay_stm32f769i_disc0"
+ }
+ }
+
+ # Toolchain for tests only.
+ debug_tests = {
+ name = "stm32f769i_disc0_debug_tests"
+ _toolchain_base = pw_target_toolchain_stm32f769i_disc0.debug
+ forward_variables_from(_toolchain_base, "*", _excluded_members)
+ defaults = {
+ forward_variables_from(_toolchain_base.defaults, "*", _excluded_defaults)
+ forward_variables_from(toolchain_overrides, "*")
+
+ # Force tests to use basic log backend to avoid generating and loading its
+ # own tokenized database.
+ pw_log_BACKEND = dir_pw_log_basic
+ }
+ }
+}
+
+toolchains_list = [
+ target_toolchain_stm32f769i_disc0.debug,
+ target_toolchain_stm32f769i_disc0.debug_tests,
+]
diff --git a/targets/stm32f769i_disc0/vector_table.c b/targets/stm32f769i_disc0/vector_table.c
new file mode 100644
index 0000000..184bfe6
--- /dev/null
+++ b/targets/stm32f769i_disc0/vector_table.c
@@ -0,0 +1,58 @@
+// Copyright 2023 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#include <stdbool.h>
+
+#include "pw_boot/boot.h"
+#include "pw_boot_cortex_m/boot.h"
+
+// Default handler to insert into the ARMv7-M vector table (below).
+// This function exists for convenience. If a device isn't doing what you
+// expect, it might have hit a fault and ended up here.
+static void DefaultFaultHandler(void) {
+ while (true) {
+ // Wait for debugger to attach.
+ }
+}
+
+// This is the device's interrupt vector table. It's not referenced in any
+// code because the platform (STM32F7xx) expects this table to be present at the
+// beginning of flash. The exact address is specified in the pw_boot_cortex_m
+// configuration as part of the target config.
+//
+// For more information, see ARMv7-M Architecture Reference Manual DDI 0403E.b
+// section B1.5.3.
+
+// This typedef is for convenience when building the vector table. With the
+// exception of SP_main (0th entry in the vector table), all the entries of the
+// vector table are function pointers.
+typedef void (*InterruptHandler)(void);
+
+PW_KEEP_IN_SECTION(".vector_table")
+const InterruptHandler vector_table[] = {
+ // The starting location of the stack pointer.
+ // This address is NOT an interrupt handler/function pointer, it is simply
+ // the address that the main stack pointer should be initialized to. The
+ // value is reinterpret casted because it needs to be in the vector table.
+ [0] = (InterruptHandler)(&pw_boot_stack_high_addr),
+
+ // Reset handler, dictates how to handle reset interrupt. This is the
+ // address that the Program Counter (PC) is initialized to at boot.
+ [1] = pw_boot_Entry,
+
+ // NMI handler.
+ [2] = DefaultFaultHandler,
+ // HardFault handler.
+ [3] = DefaultFaultHandler,
+};
diff --git a/targets/stm32f769i_disc0_stm32cube/BUILD.gn b/targets/stm32f769i_disc0_stm32cube/BUILD.gn
new file mode 100644
index 0000000..ce81104
--- /dev/null
+++ b/targets/stm32f769i_disc0_stm32cube/BUILD.gn
@@ -0,0 +1,84 @@
+# Copyright 2023 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+import("//build_overrides/pigweed.gni")
+
+import("$dir_pw_build/target_types.gni")
+import("$dir_pw_docgen/docs.gni")
+import("$dir_pw_malloc/backend.gni")
+import("$dir_pw_toolchain/generate_toolchain.gni")
+import("target_toolchains.gni")
+
+generate_toolchains("target_toolchains") {
+ toolchains = pw_target_toolchain_stm32f769i_disc0_list
+}
+
+config("module_config_options") {
+ cflags = [
+ "-include",
+ rebase_path("module_config_overrides.h", root_build_dir),
+ ]
+}
+
+pw_source_set("module_config_overrides") {
+ public_configs = [ ":module_config_options" ]
+ sources = [ "module_config_overrides.h" ]
+}
+
+config("pw_malloc_active") {
+ if (pw_malloc_BACKEND != "") {
+ defines = [ "PW_MALLOC_ACTIVE=1" ]
+ }
+}
+
+if (current_toolchain != default_toolchain) {
+ pw_source_set("pre_init") {
+ configs = [ ":pw_malloc_active" ]
+ public_deps = [
+ "$dir_pw_boot",
+ "$dir_pw_boot_cortex_m:armv7m",
+ "$dir_pw_sys_io_stm32cube",
+ ]
+ deps = [
+ "$dir_pw_malloc",
+ "$dir_pw_preprocessor",
+ "$dir_pw_string",
+ "$dir_pw_third_party/freertos",
+ "$dir_pw_third_party/stm32cube",
+ ]
+ sources = [
+ "boot.cc",
+ "vector_table.c",
+ ]
+ }
+
+ config("config_includes") {
+ include_dirs = [ "config" ]
+ }
+
+ pw_source_set("stm32f7xx_hal_config") {
+ public_configs = [ ":config_includes" ]
+ public = [ "config/stm32f7xx_hal_conf.h" ]
+ }
+
+ pw_source_set("stm32f7xx_freertos_config") {
+ public_configs = [ ":config_includes" ]
+ public_deps = [ "$dir_pw_third_party/freertos:config_assert" ]
+ public = [ "config/FreeRTOSConfig.h" ]
+ }
+}
+
+pw_doc_group("target_docs") {
+ sources = [ "target_docs.rst" ]
+}
diff --git a/targets/stm32f769i_disc0_stm32cube/README.md b/targets/stm32f769i_disc0_stm32cube/README.md
new file mode 100644
index 0000000..2c56ac3
--- /dev/null
+++ b/targets/stm32f769i_disc0_stm32cube/README.md
@@ -0,0 +1,18 @@
+##Building
+In order to build this target, the submodules in `//third_party/stm32cubef7`
+need to be checked out and the following flag needs to be added to your
+gn args (gn args out)
+
+```
+pw_third_party_stm32cubef7_enabled = "yes"
+```
+
+##Flashing
+
+Images can be flashed using the same scripts as the in-tree variant.
+
+This command can be used to flash the blinky example:
+
+```
+openocd -s ${PW_PIGWEED_CIPD_INSTALL_DIR}/share/openocd/scripts -f ${PW_ROOT}/targets/stm32f769i_disc0/py/stm32f769i_disc0_utils/openocd_stm32f7xx.cfg -c "program out/stm32f769i_disc0_stm32cube_debug/obj/applications/blinky/bin/blinky.elf reset exit"
+```
diff --git a/targets/stm32f769i_disc0_stm32cube/boot.cc b/targets/stm32f769i_disc0_stm32cube/boot.cc
new file mode 100644
index 0000000..b975653
--- /dev/null
+++ b/targets/stm32f769i_disc0_stm32cube/boot.cc
@@ -0,0 +1,193 @@
+// Copyright 2023 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#include "pw_boot/boot.h"
+
+#include <array>
+
+#include "FreeRTOS.h"
+#include "pw_boot_cortex_m/boot.h"
+#include "pw_malloc/malloc.h"
+#include "pw_preprocessor/compiler.h"
+#include "pw_string/util.h"
+#include "pw_sys_io_stm32cube/init.h"
+#include "stm32f7xx.h"
+#include "task.h"
+
+namespace {
+
+// TODO(cmumford): Remove hard-coded hack. At present this cache is here, which
+// is used for vApplicationGetIdleTaskMemory, and the application has its own
+// stack. Determine if both are needed.
+std::array<StackType_t, 100 /*configMINIMAL_STACK_SIZE*/> freertos_idle_stack;
+StaticTask_t freertos_idle_tcb;
+
+std::array<StackType_t, configTIMER_TASK_STACK_DEPTH> freertos_timer_stack;
+StaticTask_t freertos_timer_tcb;
+
+std::array<char, configMAX_TASK_NAME_LEN> temp_thread_name_buffer;
+
+RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {
+ .PeriphClockSelection = RCC_PERIPHCLK_CLK48,
+ .PLLI2S = {},
+ .PLLSAI =
+ {
+ .PLLSAIN = 192,
+ .PLLSAIQ = 4,
+ .PLLSAIR = 0,
+ .PLLSAIP = RCC_PLLSAIP_DIV4,
+ },
+ .PLLI2SDivQ = 0,
+ .PLLSAIDivQ = 0,
+ .PLLSAIDivR = 0,
+ .RTCClockSelection = 0,
+ .I2sClockSelection = 0,
+ .TIMPresSelection = 0,
+ .Sai1ClockSelection = 0,
+ .Sai2ClockSelection = 0,
+ .Usart1ClockSelection = 0,
+ .Usart2ClockSelection = 0,
+ .Usart3ClockSelection = 0,
+ .Uart4ClockSelection = 0,
+ .Uart5ClockSelection = 0,
+ .Usart6ClockSelection = 0,
+ .Uart7ClockSelection = 0,
+ .Uart8ClockSelection = 0,
+ .I2c1ClockSelection = 0,
+ .I2c2ClockSelection = 0,
+ .I2c3ClockSelection = 0,
+ .I2c4ClockSelection = 0,
+ .Lptim1ClockSelection = 0,
+ .CecClockSelection = 0,
+ .Clk48ClockSelection = RCC_CLK48SOURCE_PLLSAIP,
+ .Sdmmc1ClockSelection = 0,
+ .Sdmmc2ClockSelection = 0,
+ .Dfsdm1ClockSelection = 0,
+ .Dfsdm1AudioClockSelection = 0,
+};
+
+} // namespace
+
+extern "C" {
+
+// Initializes clock to its max, 180Mhz. Note that this naming follows CubeMX's
+// naming out of convention. It's not required that this target provides a
+// symbol named SystemClock_Config. This function shares the same purpose as
+// the symbol of the same name that is generated by CubeMX.
+void SystemClock_Config() {
+ __HAL_RCC_PWR_CLK_ENABLE();
+ __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
+
+ RCC_OscInitTypeDef RCC_OscInitStruct = {
+ .OscillatorType = RCC_OSCILLATORTYPE_HSE,
+ .HSEState = RCC_HSE_ON,
+ .LSEState = RCC_LSE_OFF,
+ .HSIState = RCC_HSI_OFF,
+ .HSICalibrationValue = 0x0,
+ .LSIState = RCC_LSI_OFF,
+ .PLL =
+ {
+ .PLLState = RCC_PLL_ON,
+ .PLLSource = RCC_PLLSOURCE_HSE,
+ .PLLM = 25,
+ .PLLN = 400,
+ .PLLP = RCC_PLLP_DIV2,
+ .PLLQ = 8,
+ .PLLR = 7,
+ },
+ };
+
+ if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
+ pw_boot_PostMain();
+ }
+
+ // OverDrive required for operation > 168Mhz
+ if (HAL_PWREx_EnableOverDrive() != HAL_OK) {
+ pw_boot_PostMain();
+ }
+
+ if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) {
+ pw_boot_PostMain();
+ }
+
+ RCC_ClkInitTypeDef RCC_ClkInitStruct = {
+ .ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK |
+ RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2),
+ .SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK,
+ .AHBCLKDivider = RCC_SYSCLK_DIV1,
+ .APB1CLKDivider = RCC_HCLK_DIV4,
+ .APB2CLKDivider = RCC_HCLK_DIV2,
+ };
+
+ if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_6) != HAL_OK) {
+ pw_boot_PostMain();
+ }
+}
+
+// Functions needed when configGENERATE_RUN_TIME_STATS is on.
+void configureTimerForRunTimeStats(void) {}
+unsigned long getRunTimeCounterValue(void) { return uwTick; }
+
+// Required for configCHECK_FOR_STACK_OVERFLOW.
+void vApplicationStackOverflowHook(TaskHandle_t, char* pcTaskName) {
+ pw::string::Copy(pcTaskName, temp_thread_name_buffer);
+ PW_CRASH("Stack OVF for task %s", temp_thread_name_buffer.data());
+}
+
+// Required for configUSE_TIMERS.
+void vApplicationGetTimerTaskMemory(StaticTask_t** ppxTimerTaskTCBBuffer,
+ StackType_t** ppxTimerTaskStackBuffer,
+ uint32_t* pulTimerTaskStackSize) {
+ *ppxTimerTaskTCBBuffer = &freertos_timer_tcb;
+ *ppxTimerTaskStackBuffer = freertos_timer_stack.data();
+ *pulTimerTaskStackSize = freertos_timer_stack.size();
+}
+
+void vApplicationGetIdleTaskMemory(StaticTask_t** ppxIdleTaskTCBBuffer,
+ StackType_t** ppxIdleTaskStackBuffer,
+ uint32_t* pulIdleTaskStackSize) {
+ *ppxIdleTaskTCBBuffer = &freertos_idle_tcb;
+ *ppxIdleTaskStackBuffer = freertos_idle_stack.data();
+ *pulIdleTaskStackSize = freertos_idle_stack.size();
+}
+
+void pw_boot_PreStaticMemoryInit() {}
+
+void pw_boot_PreStaticConstructorInit() {
+ // Provided by STMicroelectronics SDK. Can be configured to be provided
+ // elsewhere by changing pw_third_party_stm32cube_CMSIS_INIT.
+ SystemInit();
+
+ // Provided by the STMicroelectronics SDK.
+ HAL_Init();
+
+ // Typically provided by CubeMX codegen, SystemClock_Config() is instead
+ // provided as part of this target.
+ SystemClock_Config();
+
+#if PW_MALLOC_ACTIVE
+ pw_MallocInit(&pw_boot_heap_low_addr, &pw_boot_heap_high_addr);
+#endif // PW_MALLOC_ACTIVE
+}
+
+void pw_boot_PreMainInit() { pw_sys_io_Init(); }
+
+PW_NO_RETURN void pw_boot_PostMain() {
+ // In case main() returns, just sit here until the device is reset.
+ while (true) {
+ }
+ PW_UNREACHABLE;
+}
+
+} // extern "C"
diff --git a/targets/stm32f769i_disc0_stm32cube/config/FreeRTOSConfig.h b/targets/stm32f769i_disc0_stm32cube/config/FreeRTOSConfig.h
new file mode 100644
index 0000000..159b64a
--- /dev/null
+++ b/targets/stm32f769i_disc0_stm32cube/config/FreeRTOSConfig.h
@@ -0,0 +1,89 @@
+// Copyright 2023 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+#pragma once
+
+#include <stdint.h>
+
+// Disable formatting to make it easier to compare with other config files.
+// clang-format off
+
+// Externally defined variables that must be forward-declared for FreeRTOS to
+// use them.
+extern uint32_t SystemCoreClock;
+extern void configureTimerForRunTimeStats(void);
+extern unsigned long getRunTimeCounterValue(void);
+
+#define configUSE_16_BIT_TICKS 0
+#define configUSE_CO_ROUTINES 0
+#define configUSE_IDLE_HOOK 0
+#define configUSE_MALLOC_FAILED_HOOK 0
+#define configUSE_MUTEXES 1
+#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
+#define configUSE_PREEMPTION 1
+#define configUSE_TICK_HOOK 0
+#define configUSE_TIMERS 1
+#define configUSE_TRACE_FACILITY 1
+
+#define configGENERATE_RUN_TIME_STATS 1
+#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS configureTimerForRunTimeStats
+#define portGET_RUN_TIME_COUNTER_VALUE getRunTimeCounterValue
+
+#define configCHECK_FOR_STACK_OVERFLOW 2
+#define configCPU_CLOCK_HZ (SystemCoreClock)
+#define configENABLE_BACKWARD_COMPATIBILITY 0
+#define configMAX_CO_ROUTINE_PRIORITIES (2)
+#define configMAX_PRIORITIES (7)
+#define configMAX_TASK_NAME_LEN (16)
+#define configMESSAGE_BUFFER_LENGTH_TYPE size_t
+#define configMINIMAL_STACK_SIZE ((uint16_t)(4 * 1024))
+#define configQUEUE_REGISTRY_SIZE 8
+#define configRECORD_STACK_HIGH_ADDRESS 1
+#define configTICK_RATE_HZ ((TickType_t)1000)
+#define configTIMER_QUEUE_LENGTH 10
+#define configTIMER_TASK_PRIORITY (6)
+#define configTIMER_TASK_STACK_DEPTH 512
+
+/* Memory allocation related definitions. */
+#define configSUPPORT_STATIC_ALLOCATION 1
+#define configSUPPORT_DYNAMIC_ALLOCATION 1
+#define configTOTAL_HEAP_SIZE ((size_t)(1 * 1024))
+#define configAPPLICATION_ALLOCATED_HEAP 0
+
+/* __NVIC_PRIO_BITS in CMSIS */
+#define configPRIO_BITS 4
+
+#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15
+#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
+#define configKERNEL_INTERRUPT_PRIORITY \
+ (configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS))
+#define configMAX_SYSCALL_INTERRUPT_PRIORITY \
+ (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS))
+
+#define INCLUDE_uxTaskPriorityGet 1
+#define INCLUDE_vTaskCleanUpResources 0
+#define INCLUDE_vTaskDelay 1
+#define INCLUDE_vTaskDelayUntil 0
+#define INCLUDE_vTaskDelete 1
+#define INCLUDE_vTaskPrioritySet 1
+#define INCLUDE_vTaskSuspend 1
+#define INCLUDE_xTaskGetSchedulerState 1
+#define INCLUDE_uxTaskGetStackHighWaterMark 1
+
+// Instead of defining configASSERT(), include a header that provides a
+// definition that redirects to pw_assert.
+#include "pw_third_party/freertos/config_assert.h"
+
+#define vPortSVCHandler SVC_Handler
+#define xPortPendSVHandler PendSV_Handler
+#define xPortSysTickHandler SysTick_Handler
diff --git a/targets/stm32f769i_disc0_stm32cube/config/stm32f7xx_hal_conf.h b/targets/stm32f769i_disc0_stm32cube/config/stm32f7xx_hal_conf.h
new file mode 100644
index 0000000..0fe8986
--- /dev/null
+++ b/targets/stm32f769i_disc0_stm32cube/config/stm32f7xx_hal_conf.h
@@ -0,0 +1,266 @@
+// Copyright 2023 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#pragma once
+
+/* Clock setup */
+#define HSI_VALUE 16000000U
+#define LSI_VALUE 32000U
+
+// The F429-disc has an 8Mhz external crystal
+#define HSE_VALUE 8000000U
+#define HSE_STARTUP_TIMEOUT 100U
+
+// The F429-disc has no LSE
+#define LSE_VALUE 0U
+#define LSE_STARTUP_TIMEOUT 5000U
+
+#define EXTERNAL_CLOCK_VALUE 0U
+
+/* HAL Config */
+#define TICK_INT_PRIORITY 0x0FU
+#define USE_RTOS 0U
+#define PREFETCH_ENABLE 1U
+#define INSTRUCTION_CACHE_ENABLE 1U
+#define DATA_CACHE_ENABLE 1U
+
+#define assert_param(expr) ((void)0U)
+
+/* Ethernet driver buffers size + count
+ * (also used by FreeRTOS_Plus_TCP's stm32 driver) */
+#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE
+#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE
+#define ETH_RXBUFNB 4U
+#define ETH_TXBUFNB 4U
+
+/* Ethernet PHY Defines (unused by FreeRTOS_Plus_TCP's driver) */
+#define PHY_RESET_DELAY 0x000000FFU
+#define PHY_CONFIG_DELAY 0x00000FFFU
+
+#define PHY_READ_TO 0x0000FFFFU
+#define PHY_WRITE_TO 0x0000FFFFU
+
+/* Common PHY Registers */
+#define PHY_BCR ((uint16_t)0x0000)
+#define PHY_BSR ((uint16_t)0x0001)
+
+#define PHY_RESET ((uint16_t)0x8000)
+#define PHY_LOOPBACK ((uint16_t)0x4000)
+#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100)
+#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000)
+#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100)
+#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000)
+#define PHY_AUTONEGOTIATION ((uint16_t)0x1000)
+#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200)
+#define PHY_POWERDOWN ((uint16_t)0x0800)
+#define PHY_ISOLATE ((uint16_t)0x0400)
+
+#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020)
+#define PHY_LINKED_STATUS ((uint16_t)0x0004)
+#define PHY_JABBER_DETECTION ((uint16_t)0x0002)
+
+/* Extended PHY Registers */
+#define PHY_SR ((uint16_t)0x0010)
+#define PHY_MICR ((uint16_t)0x0011)
+#define PHY_MISR ((uint16_t)0x0012)
+
+#define PHY_LINK_STATUS ((uint16_t)0x0001)
+#define PHY_SPEED_STATUS ((uint16_t)0x0002)
+#define PHY_DUPLEX_STATUS ((uint16_t)0x0004)
+
+#define PHY_MICR_INT_EN ((uint16_t)0x0002)
+#define PHY_MICR_INT_OE ((uint16_t)0x0001)
+
+#define PHY_MISR_LINK_INT_EN ((uint16_t)0x0020)
+#define PHY_LINK_INTERRUPT ((uint16_t)0x2000)
+
+// SPI config
+#define USE_SPI_CRC 1U
+
+/** HAL Headers: comment out defines + include to remove **/
+/* primary HAL headers */
+#define HAL_CORTEX_MODULE_ENABLED
+#include "stm32f7xx_hal_cortex.h"
+
+#define HAL_DMA_MODULE_ENABLED
+#include "stm32f7xx_hal_dma.h"
+
+#define HAL_EXTI_MODULE_ENABLED
+#include "stm32f7xx_hal_exti.h"
+
+#define HAL_GPIO_MODULE_ENABLED
+#include "stm32f7xx_hal_gpio.h"
+
+#define HAL_RCC_MODULE_ENABLED
+#include "stm32f7xx_hal_rcc.h"
+
+/* remaining headers (can be commented out if desired) */
+#define HAL_ADC_MODULE_ENABLED
+#define USE_HAL_ADC_REGISTER_CALLBACKS 0U
+#include "stm32f7xx_hal_adc.h"
+
+#define HAL_CAN_MODULE_ENABLED
+#define USE_HAL_CAN_REGISTER_CALLBACKS 0U
+#include "stm32f7xx_hal_can.h"
+
+// #define HAL_CAN_LEGACY_MODULE_ENABLED
+// #include "stm32f7xx_hal_can_legacy.h"
+
+#define HAL_CEC_MODULE_ENABLED
+#define USE_HAL_CEC_REGISTER_CALLBACKS 0U
+#include "stm32f7xx_hal_cec.h"
+
+#define HAL_CRC_MODULE_ENABLED
+#include "stm32f7xx_hal_crc.h"
+
+#define HAL_CRYP_MODULE_ENABLED
+#define USE_HAL_CRYP_REGISTER_CALLBACKS 0U
+#include "stm32f7xx_hal_cryp.h"
+
+#define HAL_DAC_MODULE_ENABLED
+#define USE_HAL_DAC_REGISTER_CALLBACKS 0U
+#include "stm32f7xx_hal_dac.h"
+
+#define HAL_DCMI_MODULE_ENABLED
+#define USE_HAL_DCMI_REGISTER_CALLBACKS 0U
+#include "stm32f7xx_hal_dcmi.h"
+
+#define HAL_DMA2D_MODULE_ENABLED
+#define USE_HAL_DMA2D_REGISTER_CALLBACKS 0U
+#include "stm32f7xx_hal_dma2d.h"
+
+#define HAL_DFSDM_MODULE_ENABLED
+#define USE_HAL_DFSDM_REGISTER_CALLBACKS 0U
+#include "stm32f7xx_hal_dfsdm.h"
+
+#define HAL_DSI_MODULE_ENABLED
+#define USE_HAL_DSI_REGISTER_CALLBACKS 0U
+#include "stm32f7xx_hal_dsi.h"
+
+#define HAL_ETH_MODULE_ENABLED
+#define USE_HAL_ETH_REGISTER_CALLBACKS 0U
+#include "stm32f7xx_hal_eth.h"
+
+#define HAL_FLASH_MODULE_ENABLED
+#include "stm32f7xx_hal_flash.h"
+
+#define HAL_HASH_MODULE_ENABLED
+#define USE_HAL_HASH_REGISTER_CALLBACKS 0U
+#include "stm32f7xx_hal_hash.h"
+
+#define HAL_HCD_MODULE_ENABLED
+#define USE_HAL_HCD_REGISTER_CALLBACKS 0U
+#include "stm32f7xx_hal_hcd.h"
+
+#define HAL_I2C_MODULE_ENABLED
+#define USE_HAL_I2C_REGISTER_CALLBACKS 0U
+#include "stm32f7xx_hal_i2c.h"
+
+#define HAL_I2S_MODULE_ENABLED
+#define USE_HAL_I2S_REGISTER_CALLBACKS 0U
+#include "stm32f7xx_hal_i2s.h"
+
+#define HAL_IRDA_MODULE_ENABLED
+#define USE_HAL_IRDA_REGISTER_CALLBACKS 0U
+#include "stm32f7xx_hal_irda.h"
+
+#define HAL_IWDG_MODULE_ENABLED
+#include "stm32f7xx_hal_iwdg.h"
+
+#define HAL_LPTIM_MODULE_ENABLED
+#define USE_HAL_LPTIM_REGISTER_CALLBACKS 0U
+#include "stm32f7xx_hal_lptim.h"
+
+#define HAL_LTDC_MODULE_ENABLED
+#define USE_HAL_LTDC_REGISTER_CALLBACKS 0U
+#include "stm32f7xx_hal_ltdc.h"
+
+#define HAL_MMC_MODULE_ENABLED
+#define USE_HAL_MMC_REGISTER_CALLBACKS 0U
+#include "stm32f7xx_hal_mmc.h"
+
+#define HAL_NAND_MODULE_ENABLED
+#define USE_HAL_NAND_REGISTER_CALLBACKS 0U
+#include "stm32f7xx_hal_nand.h"
+
+#define HAL_NOR_MODULE_ENABLED
+#define USE_HAL_NOR_REGISTER_CALLBACKS 0U
+#include "stm32f7xx_hal_nor.h"
+
+#define HAL_PCD_MODULE_ENABLED
+#define USE_HAL_PCD_REGISTER_CALLBACKS 0U
+#include "stm32f7xx_hal_pcd.h"
+
+#define HAL_PWR_MODULE_ENABLED
+#include "stm32f7xx_hal_pwr.h"
+
+#define HAL_QSPI_MODULE_ENABLED
+#define USE_HAL_QSPI_REGISTER_CALLBACKS 0U
+#include "stm32f7xx_hal_qspi.h"
+
+#define HAL_RNG_MODULE_ENABLED
+#define USE_HAL_RNG_REGISTER_CALLBACKS 0U
+#include "stm32f7xx_hal_rng.h"
+
+#define HAL_RTC_MODULE_ENABLED
+#define USE_HAL_RTC_REGISTER_CALLBACKS 0U
+#include "stm32f7xx_hal_rtc.h"
+
+#define HAL_SAI_MODULE_ENABLED
+#define USE_HAL_SAI_REGISTER_CALLBACKS 0U
+#include "stm32f7xx_hal_sai.h"
+
+#define HAL_SD_MODULE_ENABLED
+#define USE_HAL_SD_REGISTER_CALLBACKS 0U
+#include "stm32f7xx_hal_sd.h"
+
+#define HAL_SDRAM_MODULE_ENABLED
+#define USE_HAL_SDRAM_REGISTER_CALLBACKS 0U
+#include "stm32f7xx_hal_sdram.h"
+
+#define HAL_SMARTCARD_MODULE_ENABLED
+#define USE_HAL_SMARTCARD_REGISTER_CALLBACKS 0U
+#include "stm32f7xx_hal_smartcard.h"
+
+#define HAL_SMBUS_MODULE_ENABLED
+#define USE_HAL_SMBUS_REGISTER_CALLBACKS 0U
+#include "stm32f7xx_hal_smbus.h"
+
+#define HAL_SPDIFRX_MODULE_ENABLED
+#define USE_HAL_SPDIFRX_REGISTER_CALLBACKS 0U
+#include "stm32f7xx_hal_spdifrx.h"
+
+#define HAL_SPI_MODULE_ENABLED
+#define USE_HAL_SPI_REGISTER_CALLBACKS 0U
+#include "stm32f7xx_hal_spi.h"
+
+#define HAL_SRAM_MODULE_ENABLED
+#define USE_HAL_SRAM_REGISTER_CALLBACKS 0U
+#include "stm32f7xx_hal_sram.h"
+
+#define HAL_TIM_MODULE_ENABLED
+#define USE_HAL_TIM_REGISTER_CALLBACKS 0U
+#include "stm32f7xx_hal_tim.h"
+
+#define HAL_UART_MODULE_ENABLED
+#define USE_HAL_UART_REGISTER_CALLBACKS 0U
+#include "stm32f7xx_hal_uart.h"
+
+#define HAL_USART_MODULE_ENABLED
+#define USE_HAL_USART_REGISTER_CALLBACKS 0U
+#include "stm32f7xx_hal_usart.h"
+
+#define HAL_WWDG_MODULE_ENABLED
+#define USE_HAL_WWDG_REGISTER_CALLBACKS 0U
+#include "stm32f7xx_hal_wwdg.h"
diff --git a/targets/stm32f769i_disc0_stm32cube/module_config_overrides.h b/targets/stm32f769i_disc0_stm32cube/module_config_overrides.h
new file mode 100644
index 0000000..c67d1ee
--- /dev/null
+++ b/targets/stm32f769i_disc0_stm32cube/module_config_overrides.h
@@ -0,0 +1,20 @@
+// Copyright 2023 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+#pragma once
+
+// Configure the UART for pw_sys_io_stm32cube.
+#define PW_SYS_IO_STM32CUBE_USART_NUM 1
+#define PW_SYS_IO_STM32CUBE_GPIO_PORT A
+#define PW_SYS_IO_STM32CUBE_GPIO_TX_PIN 9
+#define PW_SYS_IO_STM32CUBE_GPIO_RX_PIN 10
diff --git a/targets/stm32f769i_disc0_stm32cube/stm32f769i_executable.gni b/targets/stm32f769i_disc0_stm32cube/stm32f769i_executable.gni
new file mode 100644
index 0000000..ce54079
--- /dev/null
+++ b/targets/stm32f769i_disc0_stm32cube/stm32f769i_executable.gni
@@ -0,0 +1,35 @@
+# Copyright 2023 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+import("//build_overrides/pigweed.gni")
+import("$dir_pw_malloc/backend.gni")
+
+# Executable wrapper that includes some baremetal startup code.
+template("stm32f769i_executable") {
+ target("executable", target_name) {
+ forward_variables_from(invoker, "*")
+ if (!defined(deps)) {
+ deps = []
+ }
+ deps += [
+ "$dir_pigweed_experimental/targets/stm32f769i_disc0_stm32cube:pre_init",
+ ]
+ if (pw_malloc_BACKEND != "") {
+ if (!defined(configs)) {
+ configs = []
+ }
+ configs += [ "$dir_pw_malloc:pw_malloc_wrapper_config" ]
+ }
+ }
+}
diff --git a/targets/stm32f769i_disc0_stm32cube/target_toolchains.gni b/targets/stm32f769i_disc0_stm32cube/target_toolchains.gni
new file mode 100644
index 0000000..039c98c
--- /dev/null
+++ b/targets/stm32f769i_disc0_stm32cube/target_toolchains.gni
@@ -0,0 +1,175 @@
+# Copyright 2023 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+import("//build_overrides/pigweed.gni")
+
+import("$dir_pw_rpc/system_server/backend.gni")
+import("$dir_pw_sys_io/backend.gni")
+import("$dir_pw_third_party/stm32cube/stm32cube.gni")
+import("$dir_pw_toolchain/arm_gcc/toolchains.gni")
+
+_target_config = {
+ # Use the logging main.
+ pw_unit_test_MAIN = "$dir_pw_unit_test:logging_main"
+
+ # Configuration options for Pigweed executable targets.
+ pw_build_EXECUTABLE_TARGET_TYPE = "stm32f769i_executable"
+
+ pw_build_EXECUTABLE_TARGET_TYPE_FILE =
+ get_path_info("stm32f769i_executable.gni", "abspath")
+
+ # Path to the bloaty config file for the output binaries.
+ pw_bloat_BLOATY_CONFIG = "$dir_pw_boot_cortex_m/bloaty_config.bloaty"
+
+ #TODO: Fix test server: likely have to fork stm32f769i-disc0 implementation
+ # if (pw_use_test_server) {
+ # _test_runner_script = "py/stm32f769i_disc0_utils/unit_test_client.py"
+ # pw_unit_test_AUTOMATIC_RUNNER =
+ # get_path_info(_test_runner_script, "abspath")
+ # }
+
+ # Facade backends
+ pw_assert_BACKEND = dir_pw_assert_basic
+ pw_boot_BACKEND = "$dir_pw_boot_cortex_m:armv7m"
+
+ # TODO(cmumford): Review backend - adding to allow compile.
+ pw_sync_MUTEX_BACKEND = "$dir_pw_sync_baremetal:mutex"
+
+ ### pw_cpu_exception not yet used
+ # pw_cpu_exception_ENTRY_BACKEND =
+ # "$dir_pw_cpu_exception_cortex_m:cpu_exception_armv7m"
+ # pw_cpu_exception_HANDLER_BACKEND = "$dir_pw_cpu_exception:basic_handler"
+ # pw_cpu_exception_SUPPORT_BACKEND =
+ # "$dir_pw_cpu_exception_cortex_m:support_armv7m"
+ pw_sync_INTERRUPT_SPIN_LOCK_BACKEND =
+ "$dir_pw_sync_baremetal:interrupt_spin_lock"
+ pw_log_BACKEND = dir_pw_log_basic
+ pw_sys_io_BACKEND = dir_pw_sys_io_stm32cube
+ pw_sys_io_stm32cube_CONFIG = "$dir_pigweed_experimental/targets/stm32f769i_disc0_stm32cube:module_config_overrides"
+
+ pw_third_party_freertos_CONFIG = "$dir_pigweed_experimental/targets/stm32f769i_disc0_stm32cube:stm32f7xx_freertos_config"
+ pw_third_party_freertos_PORT =
+ "$dir_pigweed_experimental/third_party/freertos:arm_cm7_freertos_port"
+
+ #TODO: remove dependency on stm32f769i-disc0 rpc server.
+ pw_rpc_system_server_BACKEND =
+ "$dir_pigweed/targets/stm32f769i_disc0:system_rpc_server"
+ pw_malloc_BACKEND = dir_pw_malloc_freelist
+
+ pw_boot_cortex_m_LINK_CONFIG_DEFINES = [
+ "PW_BOOT_FLASH_BEGIN=0x08000400",
+ "PW_BOOT_FLASH_SIZE=2048K",
+
+ # TODO(b/235348465): Currently "pw_tokenizer/detokenize_test" requires at
+ # least 6K bytes in heap when using pw_malloc_freelist. The heap size
+ # required for tests should be investigated.
+ "PW_BOOT_HEAP_SIZE=7K",
+ "PW_BOOT_MIN_STACK_SIZE=8K",
+ "PW_BOOT_RAM_BEGIN=0x20000000",
+ "PW_BOOT_RAM_SIZE=512K",
+ "PW_BOOT_VECTOR_TABLE_BEGIN=0x08000000",
+ "PW_BOOT_VECTOR_TABLE_SIZE=0x400",
+ ]
+
+ pw_build_LINK_DEPS = [
+ "$dir_pw_assert:impl",
+ "$dir_pw_log:impl",
+ ]
+
+ current_cpu = "arm"
+ current_os = ""
+
+ pw_board_led_BACKEND = dir_pw_board_led_stm32cube
+ pw_board_led_stm32cube_gpio_port = "J"
+ pw_board_led_stm32cube_gpio_pin = "13"
+ app_common_BACKEND = "//applications/app_common_impl:stm32cube"
+ pw_lcd_width = "320"
+ pw_lcd_height = "240"
+ pw_lcd_cs_port_char = "C"
+ pw_lcd_cs_pin_num = "2"
+ pw_lcd_dc_port_char = "D"
+ pw_lcd_dc_pin_num = "13"
+ pw_lcd_rst_pin_num = "-1"
+
+ pw_spin_delay_BACKEND = dir_pw_spin_delay_stm32cube
+
+ # Configure backend for pw_touchscreen
+ pw_touchscreen_BACKEND = "$dir_pw_touchscreen_null"
+
+ dir_pw_third_party_stm32cube = dir_pw_third_party_stm32cube_f7
+ pw_third_party_stm32cube_PRODUCT = "STM32F769xx"
+ pw_third_party_stm32cube_CONFIG = "$dir_pigweed_experimental/targets/stm32f769i_disc0_stm32cube:stm32f7xx_hal_config"
+ pw_third_party_stm32cube_CORE_INIT = ""
+}
+
+_toolchain_properties = {
+ final_binary_extension = ".elf"
+}
+
+_target_default_configs = [
+ "$dir_pw_build:extra_strict_warnings",
+ "$dir_pw_toolchain/arm_gcc:enable_float_printf",
+]
+
+pw_target_toolchain_stm32f769i_disc0 = {
+ _excluded_members = [
+ "defaults",
+ "name",
+ ]
+
+ debug = {
+ name = "stm32f769i_disc0_stm32cube_debug"
+ _toolchain_base = pw_toolchain_arm_gcc.cortex_m7f_debug
+ forward_variables_from(_toolchain_base, "*", _excluded_members)
+ forward_variables_from(_toolchain_properties, "*")
+ defaults = {
+ forward_variables_from(_toolchain_base.defaults, "*")
+ forward_variables_from(_target_config, "*")
+ default_configs += _target_default_configs
+ }
+ }
+
+ speed_optimized = {
+ name = "stm32f769i_disc0_stm32cube_speed_optimized"
+ _toolchain_base = pw_toolchain_arm_gcc.cortex_m7f_speed_optimized
+ forward_variables_from(_toolchain_base, "*", _excluded_members)
+ forward_variables_from(_toolchain_properties, "*")
+ defaults = {
+ forward_variables_from(_toolchain_base.defaults, "*")
+ forward_variables_from(_target_config, "*")
+ default_configs += _target_default_configs
+ }
+ }
+
+ size_optimized = {
+ name = "stm32f769i_disc0_stm32cube_size_optimized"
+ _toolchain_base = pw_toolchain_arm_gcc.cortex_m7f_size_optimized
+ forward_variables_from(_toolchain_base, "*", _excluded_members)
+ forward_variables_from(_toolchain_properties, "*")
+ defaults = {
+ forward_variables_from(_toolchain_base.defaults, "*")
+ forward_variables_from(_target_config, "*")
+ default_configs += _target_default_configs
+ }
+ }
+}
+
+# This list just contains the members of the above scope for convenience to make
+# it trivial to generate all the toolchains in this file via a
+# `generate_toolchains` target.
+pw_target_toolchain_stm32f769i_disc0_list = [
+ pw_target_toolchain_stm32f769i_disc0.debug,
+ pw_target_toolchain_stm32f769i_disc0.speed_optimized,
+ pw_target_toolchain_stm32f769i_disc0.size_optimized,
+]
diff --git a/targets/stm32f769i_disc0_stm32cube/vector_table.c b/targets/stm32f769i_disc0_stm32cube/vector_table.c
new file mode 100644
index 0000000..ea2a340
--- /dev/null
+++ b/targets/stm32f769i_disc0_stm32cube/vector_table.c
@@ -0,0 +1,81 @@
+// Copyright 2023 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#include <stdbool.h>
+
+#include "pw_boot/boot.h"
+#include "pw_boot_cortex_m/boot.h"
+#include "stm32f7xx.h"
+
+// Default handler to insert into the ARMv7-M vector table (below).
+// This function exists for convenience. If a device isn't doing what you
+// expect, it might have hit a fault and ended up here.
+static void DefaultFaultHandler(void) {
+ while (true) {
+ // Wait for debugger to attach.
+ }
+}
+
+// This is the device's interrupt vector table. It's not referenced in any
+// code because the platform (STM32F7xx) expects this table to be present at the
+// beginning of flash. The exact address is specified in the pw_boot_armv7m
+// configuration as part of the target config.
+//
+// For more information, see ARMv7-M Architecture Reference Manual DDI 0403E.b
+// section B1.5.3.
+
+// This typedef is for convenience when building the vector table. With the
+// exception of SP_main (0th entry in the vector table), all the entries of the
+// vector table are function pointers.
+typedef void (*InterruptHandler)(void);
+
+// This is the timer interrupt handler implemented by the stm32cubef7 timer
+// template.
+void TIM6_DAC_IRQHandler(void);
+
+// Interrupt handlers critical for OS operation.
+void SVC_Handler(void);
+void PendSV_Handler(void);
+void SysTick_Handler(void);
+
+PW_KEEP_IN_SECTION(".vector_table")
+const InterruptHandler vector_table[] = {
+ // The starting location of the stack pointer.
+ // This address is NOT an interrupt handler/function pointer, it is simply
+ // the address that the main stack pointer should be initialized to. The
+ // value is reinterpret casted because it needs to be in the vector table.
+ [0] = (InterruptHandler)(&pw_boot_stack_high_addr),
+
+ // Reset handler, dictates how to handle reset interrupt. This is the
+ // address that the Program Counter (PC) is initialized to at boot.
+ [1] = pw_boot_Entry,
+
+ // NMI handler.
+ [2] = DefaultFaultHandler,
+ // HardFault handler.
+ [3] = DefaultFaultHandler,
+ // 4-6: Specialized fault handlers.
+ // 7-10: Reserved.
+ // SVCall handler.
+ [11] = SVC_Handler,
+ // DebugMon handler.
+ [12] = DefaultFaultHandler,
+ // 13: Reserved.
+ // PendSV handler.
+ [14] = PendSV_Handler,
+ // SysTick handler.
+ [15] = SysTick_Handler,
+ // stm32f7xx_hal sys-tick handler.
+ [TIM6_DAC_IRQn + 16] = TIM6_DAC_IRQHandler,
+};
diff --git a/third_party/freertos/BUILD.gn b/third_party/freertos/BUILD.gn
index 564656a..d4be44c 100644
--- a/third_party/freertos/BUILD.gn
+++ b/third_party/freertos/BUILD.gn
@@ -37,6 +37,15 @@
visibility = [ ":*" ]
}
+config("cm7_public_config") {
+ include_dirs = [
+ "$dir_freertos/include",
+ "$dir_freertos/portable/GCC/ARM_CM7/r0p1",
+ ]
+ cflags = [ "-Wno-cast-qual" ]
+ visibility = [ ":*" ]
+}
+
config("cm33_public_config") {
include_dirs = [
"$dir_freertos/include",
@@ -79,6 +88,16 @@
]
}
+pw_source_set("arm_cm7_freertos_port") {
+ public_configs = [ ":cm7_public_config" ]
+ deps = [ "$pw_third_party_freertos_CONFIG" ]
+ public = []
+ sources = [
+ "$dir_freertos/portable/GCC/ARM_CM7/r0p1/port.c",
+ "$dir_freertos/portable/MemMang/heap_4.c",
+ ]
+}
+
pw_source_set("arm_cm33_ntz_freertos_port") {
public_configs = [
":cm33_public_config",