Skip to content

Commit

Permalink
Bazel: stm32cube support
Browse files Browse the repository at this point in the history
Tested by building and flashing the blinky sample project, which uses
stm32cube (with pwrev/177672).

I updated the headings in pw_stm32cube_build/docs.rst to follow the
style guide recommendations. I think docs on how to integrate with
stm32cube would be more discoverable at third_party/stm32cube
(especially because in Bazel we don't even use the pw_stm32cube_build
tooling). But I'll move the docs in a separate followup CL, so that it's
clearer from the diff here what's being added.

Fixed: b/259151566
Fixed: b/261506064
Fixed: b/271032946
Change-Id: Id1f7205ba0dfc3fabfeda60e4126ac76c12bbe29
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/177134
Reviewed-by: Armando Montanez <amontanez@google.com>
Commit-Queue: Ted Pudlik <tpudlik@google.com>
Presubmit-Verified: CQ Bot Account <pigweed-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Kayce Basques <kayce@google.com>
  • Loading branch information
tpudlik authored and CQ Bot Account committed Oct 28, 2023
1 parent a74535c commit 1863631
Show file tree
Hide file tree
Showing 13 changed files with 478 additions and 36 deletions.
18 changes: 18 additions & 0 deletions .bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,24 @@ build:fuzztest \
build:fuzztest \
--@pigweed//targets:pw_unit_test_main=@com_google_fuzztest//fuzztest:fuzztest_gtest_main

# We use non-default labels for the STM32Cube repositories upstream (to reserve
# the option of building for more than one MCU family down the road), so need to
# override the three labels below.
common --//third_party/stm32cube:hal_driver=@stm32f4xx_hal_driver//:hal_driver
common --@stm32f4xx_hal_driver//:cmsis_device=@cmsis_device_f4//:cmsis_device
common --@stm32f4xx_hal_driver//:cmsis_init=@cmsis_device_f4//:default_cmsis_init

# Config for the stm32f429i_disc1_stm32cube platform.
#
# TODO: b/301334234 - Make the platform set the flags below.
build:stm32f429i --platforms=//targets/stm32f429i_disc1_stm32cube:platform
build:stm32f429i --copt="-DSTM32CUBE_HEADER=\"stm32f4xx.h\""
build:stm32f429i --copt="-DSTM32F429xx"
build:stm32f429i --@stm32f4xx_hal_driver//:hal_config=//targets/stm32f429i_disc1_stm32cube:hal_config
build:stm32f429i --//pw_log:backend_impl=@pigweed//pw_log_tokenized:impl
build:stm32f429i --//targets:pw_log_backend=@pigweed//pw_log_tokenized
build:stm32f429i --//targets:pw_log_tokenized_handler_backend=@pigweed//pw_system:log_backend

# Specifies desired output mode for running tests.
# Valid values are
# 'summary' to output only test status summary
Expand Down
24 changes: 24 additions & 0 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -387,3 +387,27 @@ http_archive(
strip_prefix = "FreeRTOS-Kernel-10.5.1",
urls = ["https://github.com/FreeRTOS/FreeRTOS-Kernel/archive/refs/tags/V10.5.1.tar.gz"],
)

http_archive(
name = "stm32f4xx_hal_driver",
build_file = "//third_party/stm32cube:stm32_hal_driver.BUILD.bazel",
sha256 = "c8741e184555abcd153f7bdddc65e4b0103b51470d39ee0056ce2f8296b4e835",
strip_prefix = "stm32f4xx_hal_driver-1.8.0",
urls = ["https://github.com/STMicroelectronics/stm32f4xx_hal_driver/archive/refs/tags/v1.8.0.tar.gz"],
)

http_archive(
name = "cmsis_device_f4",
build_file = "//third_party/stm32cube:cmsis_device.BUILD.bazel",
sha256 = "6390baf3ea44aff09d0327a3c112c6ca44418806bfdfe1c5c2803941c391fdce",
strip_prefix = "cmsis_device_f4-2.6.8",
urls = ["https://github.com/STMicroelectronics/cmsis_device_f4/archive/refs/tags/v2.6.8.tar.gz"],
)

http_archive(
name = "cmsis_core",
build_file = "//third_party/stm32cube:cmsis_core.BUILD.bazel",
sha256 = "f711074a546bce04426c35e681446d69bc177435cd8f2f1395a52db64f52d100",
strip_prefix = "cmsis_core-5.4.0_cm4",
urls = ["https://github.com/STMicroelectronics/cmsis_core/archive/refs/tags/v5.4.0_cm4.tar.gz"],
)
8 changes: 8 additions & 0 deletions pw_presubmit/py/pw_presubmit/pigweed_presubmit.py
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,14 @@ def bazel_build(ctx: PresubmitContext) -> None:
'//pw_cpu_exception/...',
)

# Build the pw_system example for the Discovery board using STM32Cube.
build.bazel(
ctx,
'build',
'--config=stm32f429i',
'//pw_system:system_example',
)


def pw_transfer_integration_test(ctx: PresubmitContext) -> None:
"""Runs the pw_transfer cross-language integration test only.
Expand Down
194 changes: 166 additions & 28 deletions pw_stm32cube_build/docs.rst
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
.. _module-pw_stm32cube_build:

------------------
==================
pw_stm32cube_build
------------------

==================
The ``pw_stm32cube_build`` module provides helper utilities for building a
target with the stm32cube HAL and/or the stm32cube initialization code.

Expand All @@ -12,13 +11,29 @@ are documented here. The rationale for keeping the build files in `third_party`
is that code depending on stm32cube can clearly see that their dependency is on
third party, not pigweed code.

STM32Cube directory setup
=========================
.. _module-pw_stm32cube_build-components:

------------------------
STM32Cube MCU Components
------------------------
Each stm32 product family (ex. F4, L5, etc.) has its own stm32cube libraries.
This integration depends on ST's 3 core `MCU Components`_ instead of their
monolithic `MCU Package`. The components are the hal_driver, cmsis_core, and
cmsis_device. All of these repos exist on `ST's GitHub page`_. Compatible
version tags are specified on the ``README.md`` of each MCU component.

To use Pigweed's STM32Cube integration, you will need to acquire the three
components. The details are build-system dependent.

--------
GN build
--------
The primary ``pw_source_set`` for this integration is
``$dir_pw_third_party/stm32cube:stm32cube``. This source set includes all of
the HAL, init code, and templates, depending on the value of the `GN args`_.

Directory setup
===============
Within a single directory, the following directory/file names are required.

=============== =============================================
Expand All @@ -40,26 +55,20 @@ generate the ``files.txt``.
pw package install stm32cube_{family}
GN build
========
The primary ``pw_source_set`` for this integration is
``$dir_pw_third_party/stm32cube:stm32cube``. This source set includes all of
the HAL, init code, and templates, depending on value of the `GN args`_.

Headers
-------
=======
``$dir_pw_third_party/stm32cube:stm32cube`` contains the following primary
headers that external targets / applications would care about.

``{family}.h``
^^^^^^^^^^^^^^
--------------
ex. ``stm32f4xx.h``, ``stm32l5xx.h``

This is the primary HAL header provided by stm32cube. It includes the entire
HAL and all product specific defines.

``stm32cube/stm32cube.h``
^^^^^^^^^^^^^^^^^^^^^^^^^
-------------------------
This is a convenience define provided by this integration. It simply includes
``{family}.h``.

Expand All @@ -70,7 +79,7 @@ header allows for stm32 family agnostic modules (ex. ``pw_sys_io_stm32``, which
could work with most, if not all families).

``stm32cube/init.h``
^^^^^^^^^^^^^^^^^^^^
--------------------
As described in the inject_init_ section, if you decide to use the built in
init functionality, a pre main init function call, ``pw_stm32cube_Init()``, is
injected into ST's startup scripts.
Expand All @@ -79,18 +88,18 @@ This header contains the ``pw_stm32cube_Init()`` function declaration. It
should be included and implemented by target init code.

GN args
-------
=======
The stm32cube GN build arguments are defined in
``$dir_pw_third_party/stm32cube/stm32cube.gni``.

``dir_pw_third_party_stm32cube_xx``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-----------------------------------
These should be set to point to the stm32cube directory for each family that
you need to build for. These are optional to set and are only provided for
convenience if you need to build for multiple families in the same project.

``dir_pw_third_party_stm32cube``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-----------------------------------
This needs to point to the stm32cube directory for the current build.

For multi target projects, the standard practice to set this for each target:
Expand All @@ -101,35 +110,36 @@ For multi target projects, the standard practice to set this for each target:
``pw_third_party_stm32cube_PRODUCT``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
------------------------------------
The product specified in as much detail as possible.
ex. ``stm32f429zit``, ``stm32l552ze``, ``stm32f207zg``, etc.

``pw_third_party_stm32cube_CONFIG``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
------------------------------------
The pw_source_set that provides ``stm32{family}xx_hal_conf.h``. The default
uses the in-tree ``stm32{family}xx_hal_conf_template.h``.

``pw_third_party_stm32cube_TIMEBASE``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-------------------------------------
The pw_source_set containing the timebase. The default uses the in-tree
``stm32{family}xx_hal_timebase_tim_template.c``.

``pw_third_party_stm32cube_CMSIS_INIT``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
---------------------------------------
The pw_source_set containing the cmsis init logic. The default uses the in-tree
``system_stm32{family}xx.c``.

``pw_third_party_stm32cube_CORE_INIT``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
--------------------------------------
pw_source_set containing the core initialization logic. This normally includes
a ``startup_stm32{...}.s`` + a dependent ``pw_linker_script``. The default
``core_init_template`` uses the upstream startup and linker script matching
``pw_third_party_stm32cube_PRODUCT``. If set to "", you must provide your own
linker/startup logic somewhere else in the build.

-----------------
stm32cube_builder
=================
-----------------
``stm32cube_builder`` is utility that contains the backend scripts used by
``pw_package/stm32cube`` and the GN build scripts in ``third_party/stm32cube``
to interact with the stm32cube repos. You should only need to interact with
Expand All @@ -138,7 +148,7 @@ using git submodules instead of pw_package, forking the stm32cube libraries,
interfacing with a different build system, or using your own init.

gen_file_list
-------------
=============
Build systems like GN are unable to depend on arbitrary directories. Instead,
they must have dependencies on specific files. The HAL for each stm32 product
family has different filenames, so ``files.txt`` was created as a workaround.
Expand All @@ -154,7 +164,7 @@ directories.
stm32cube_builder gen_file_list /path/to/stm32cube_dir
find_files
----------
==========
Within each stm32 family, there are specific products. Although most of the
HAL is common between products, the init code is almost always different.
``find_files`` looks for all of the files relevant to a particular product
Expand All @@ -179,7 +189,7 @@ The following variables are output: ``family``, ``product_define``,
stm32cube_builder find_files /path/to/stm32cube_dir stm32{family}{product} [--init]
inject_init
-----------
=============
ST provides init assembly files for every product in ``cmsis_device``. This is
helpful for getting up and running quickly, but they directly call into
``main()`` before initializing the hardware / peripherals. This is because they
Expand All @@ -200,7 +210,7 @@ the pre main init call. The output is printed to stdout, or to the specified
stm32cube_builder inject_init /path/to/startup.s [--out-startup-path /path/to/new_startup.s]
icf_to_ld
---------
=========
Pigweed primarily uses GCC for its Cortex-M builds. However, ST only provides
IAR linker scripts in ``cmsis_device`` for most product families. This script
converts from ST's IAR linker script format (.icf) to a basic GCC linker
Expand All @@ -217,3 +227,131 @@ stdout or the specified ``--ld-path``.
.. _`MCU Components`: https://github.com/STMicroelectronics/STM32Cube_MCU_Overall_Offer#stm32cube-mcu-components
.. _`ST's GitHub page`: https://github.com/STMicroelectronics

.. _module-pw_stm32cube_build-bazel:

-----------
Bazel build
-----------

External dependencies
=====================
As discussed above in :ref:`module-pw_stm32cube_build-components`, you need the
three STM32Cube Components for your MCU family to use Pigweed's STM32Cube
integration. You need to add the following git repositories to your workspace:

* ``stm32{family}xx_hal_driver`` (e.g., `HAL driver repo for the F4 family
<https://github.com/STMicroelectronics/stm32f4xx_hal_driver/>`_). We provide
a Bazel build file which works for any family at
``@pigweed//third_party/stm32cube/stm32_hal_driver.BUILD.bazel``. By default,
we assume this repository will be named ``@hal_driver``, but this can be
overriden with a label flag (discussed below).
* ``cmsis_device_{family}`` (e.g., `CMSIS device repo for the F4 family
<https://github.com/STMicroelectronics/cmsis_device_f4>`_). We provide a
Bazel build file which works for any family at
``@pigweed//third_party/stm32cube/cmsis_device.BUILD.bazel``. By default, we
assume this repository will be named ``@cmsis_device``, but this can be
overriden with a label flag (discussed below).
* ``cmsis_core``, at https://github.com/STMicroelectronics/cmsis_core. We
provide a Bazel build file for it at
``@pigweed//third_party/stm32cube/cmsis_core.BUILD.bazel``. By
default, we assume this repository will be named ``@cmsis_core``, but this
can be overriden with a label flag (discussed below).

.. _module-pw_stm32cube_build-bazel-multifamily:

Building for more than one MCU family
-------------------------------------
Different MCU families require different HAL driver and CMSIS device packages
from STM. So, if your project builds firmware for more than one MCU family, you
will need to configure separate sets of the three [#]_ STM repositories for each MCU
family. To do so,

1. Add the appropriate repositories to your WORKSPACE under different names,
eg. ``@stm32f4xx_hal_driver`` and ``@stm32h7xx_hal_driver``.
2. Set the corresponding :ref:`module-pw_stm32cube_build-bazel-label-flags` as
part of the platform configuration for your embedded target platforms.
Currently, the best way to do this is via a `bazelrc config
<https://bazel.build/run/bazelrc#config>`_, which would look like this:

.. code-block::
build:stm32f429i --platforms=//targets/stm32f429i_disc1_stm32cube:platform
build:stm32f429i --@pigweed//third_party/stm32cube:stm32_hal_driver=@stm32f4xx_hal_driver//:hal_driver
build:stm32f429i --@stm32f4xx_hal_driver//:cmsis_device=@cmsis_device_f4//:cmsis_device
build:stm32f429i --@stm32f4xx_hal_driver//:cmsis_init=@cmsis_device_f4//:default_cmsis_init
However, once `platform-based flags
<https://github.com/bazelbuild/proposals/blob/main/designs/2023-06-08-platform-based-flags.md>`_
are implemented in Bazel, it will be possible to set these flags directly
in the platform definition.

.. [#] Although CMSIS core is shared by all MCU families, different CMSIS
device repositories may not be compatible with the same version of CMSIS
core. In this case, you may need to use separate versions of CMSIS core,
too.
Defines
=======

``STM32CUBE_HEADER``
--------------------
Upstream Pigweed modules that depend on the STM32Cube HAL, like
:ref:`module-pw_sys_io_stm32cube`, include the HAL through the family-agnostic
header ``stm32cube/stm32cube.h``. This header expects the family to be set
through a define of ``STM32CUBE_HEADER``. So, to use these Pigweed modules, you
need to set that define to the correct value (e.g., ``\"stm32f4xx.h\"``; note
the backslashes) as part of your build. This is most conveniently done through
``copts`` associated with the target platform.

.. _module-pw_stm32cube_build-bazel-label-flags:

Label flags
===========
Required
--------
``@hal_driver//:hal_config``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Points to the ``cc_library`` target providing a header with the HAL
configuration. Note that this header needs an appropriate, family-specific name
(e.g., ``stm32f4xx_hal_conf.h`` for the F4 family).

Optional
--------
These label flags can be used to further customize the behavior of STM32Cube.

``//third_party/stm32cube:stm32_hal_driver``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This label_flag introduces a layer of indirection useful when building a
project that requires more than one STM32Cube package (see
:ref:`module-pw_stm32cube_build-bazel-multifamily`). It should point to the
repository containing the HAL driver.

The default value is ``@hal_driver``.

``@cmsis_device//:cmsis_core``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This label flag should point to the repository containing the CMSIS core build
target.

The default value is ``@cmsis_core``.

``@hal_driver//:cmsis_device``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This label flag should point to the repository containing the CMSIS device
build target.

The default value is ``@cmsis_device``.

``@hal_driver//:cmsis_init``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This label flag should point to the CMSIS initialization code. By default it
points to the ``system_{family}.c`` template provided in the CMSIS device
repository.

``@hal_driver//:timebase``
^^^^^^^^^^^^^^^^^^^^^^^^^^
This label flag should point to a ``cc_library`` providing a timebase
implementation. By default it points to the template included with STM's HAL
repository.

5 changes: 3 additions & 2 deletions pw_sys_io_stm32cube/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ pw_cc_library(
"sys_io.cc",
],
hdrs = ["public/pw_sys_io_stm32cube/init.h"],
# TODO: b/259151566 - Get this to build.
tags = ["manual"],
copts = ["-Wno-unused-parameter"],
includes = ["public"],
target_compatible_with = [":backend"],
deps = [
"//pw_preprocessor",
"//pw_status",
Expand Down
Loading

0 comments on commit 1863631

Please sign in to comment.