mirror of
https://github.com/espressif/esp-idf.git
synced 2025-07-30 18:57:19 +02:00
Backport CN translation for api-guides for v4.0
This commit is contained in:
committed by
Krzysztof Budzynski
parent
b2bcb609ad
commit
e1a6d45e83
@ -3,32 +3,24 @@ Build System
|
||||
|
||||
:link_to_translation:`zh_CN:[中文]`
|
||||
|
||||
This document explains the implementation of the ESP-IDF build system and the concept of "components". Read this document if you want to know how to organise and build a new ESP-IDF project or component.
|
||||
This document explains the implementation of the ESP-IDF build system and the concept of "components". Read this document if you want to know how to organize and build a new ESP-IDF project or component.
|
||||
|
||||
.. note:: This document describes the CMake-based build system, which is the default since ESP-IDF V4.0. ESP-IDF also supports a :doc:`legacy build system based on GNU Make <build-system-legacy>`, which was the default before ESP-IDF V4.0.
|
||||
|
||||
|
||||
Overview
|
||||
========
|
||||
|
||||
An ESP-IDF project can be seen as an amalgamation of a number of components.
|
||||
For example, for a webserver that shows the current humidity, there could be:
|
||||
An ESP-IDF project can be seen as an amalgamation of a number of components. For example, for a webserver that shows the current humidity, there could be:
|
||||
|
||||
- The ESP32 base libraries (libc, ROM bindings, etc)
|
||||
- The WiFi drivers
|
||||
- The Wi-Fi drivers
|
||||
- A TCP/IP stack
|
||||
- The FreeRTOS operating system
|
||||
- A webserver
|
||||
- A driver for the humidity sensor
|
||||
- Main code tying it all together
|
||||
|
||||
ESP-IDF makes these components explicit and configurable. To do that,
|
||||
when a project is compiled, the build system will look up all the
|
||||
components in the ESP-IDF directories, the project directories and
|
||||
(optionally) in additional custom component directories. It then
|
||||
allows the user to configure the ESP-IDF project using a a text-based
|
||||
menu system to customize each component. After the components in the
|
||||
project are configured, the build system will compile the project.
|
||||
ESP-IDF makes these components explicit and configurable. To do that, when a project is compiled, the build system will look up all the components in the ESP-IDF directories, the project directories and (optionally) in additional custom component directories. It then allows the user to configure the ESP-IDF project using a text-based menu system to customize each component. After the components in the project are configured, the build system will compile the project.
|
||||
|
||||
Concepts
|
||||
--------
|
||||
@ -77,6 +69,7 @@ Type ``idf.py --help`` for a full list of commands. Here are a summary of the mo
|
||||
- Run the main build tool (Ninja_ or `GNU Make`). By default, the build tool is automatically detected but it can be explicitly set by passing the ``-G`` option to ``idf.py``.
|
||||
|
||||
Building is incremental so if no source files or configuration has changed since the last build, nothing will be done.
|
||||
|
||||
- ``idf.py clean`` will "clean" the project by deleting build output files from the build directory, forcing a "full rebuild" the next time the project is built. Cleaning doesn't delete CMake configuration output and some other files.
|
||||
- ``idf.py fullclean`` will delete the entire "build" directory contents. This includes all CMake configuration output. The next time the project is built, CMake will configure it from scratch. Note that this option recursively deletes *all* files in the build directory, so use with care. Project configuration is not deleted.
|
||||
- ``idf.py flash`` will automatically build the project if necessary, and then flash it to an ESP32. The ``-p`` and ``-b`` options can be used to set serial port name and flasher baud rate, respectively.
|
||||
@ -109,7 +102,8 @@ To list all available options, run ``idf.py --help``.
|
||||
- ``-B <dir>`` allows overriding the build directory from the default ``build`` subdirectory of the project directory.
|
||||
- ``--ccache`` flag can be used to enable CCache_ when compiling source files, if the CCache_ tool is installed. This can dramatically reduce some build times.
|
||||
|
||||
Note that some older versions of CCache may exhibit bugs on some platforms, so if files are not rebuilt as expected then try disabling ccache and build again. CCache can be enabled by default by setting the ``IDF_CCACHE_ENABLE`` environment variable to a non-zero value.
|
||||
Note that some older versions of CCache may exhibit bugs on some platforms, so if files are not rebuilt as expected then try disabling CCache and build again. CCache can be enabled by default by setting the ``IDF_CCACHE_ENABLE`` environment variable to a non-zero value.
|
||||
|
||||
- ``-v`` flag causes both ``idf.py`` and the build system to produce verbose build output. This can be useful for debugging build problems.
|
||||
- ``--cmake-warn-uninitialized`` (or ``-w``) will cause CMake to print uninitialized variable warnings inside the project directory (not for directories not found inside the project directory). This only controls CMake variable warnings inside CMake itself, not other types of build warnings. This option can also be set permanently by setting the ``IDF_CMAKE_WARN_UNINITIALIZED`` environment variable to a non-zero value.
|
||||
|
||||
@ -163,7 +157,6 @@ Or::
|
||||
|
||||
.. note:: Providing variables at the end of the command line is ``make`` syntax, and works for ``make`` on all platforms.
|
||||
|
||||
|
||||
Using CMake in an IDE
|
||||
---------------------
|
||||
|
||||
@ -180,8 +173,7 @@ Setting up the Python Interpreter
|
||||
|
||||
ESP-IDF works well with all supported Python versions. It should work out-of-box even if you have a legacy system where the default ``python`` interpreter is still Python 2.7, however, it is advised to switch to Python 3 if possible.
|
||||
|
||||
``idf.py`` and other Python scripts will run with the default Python interpreter, i.e. ``python``. You can switch to a
|
||||
different one like ``python3 $IDF_PATH/tools/idf.py ...``, or you can set up a shell alias or another script to simplify the command.
|
||||
``idf.py`` and other Python scripts will run with the default Python interpreter, i.e. ``python``. You can switch to a different one like ``python3 $IDF_PATH/tools/idf.py ...``, or you can set up a shell alias or another script to simplify the command.
|
||||
|
||||
If using CMake directly, running ``cmake -D PYTHON=python3 ...`` will cause CMake to override the default Python interpreter.
|
||||
|
||||
@ -190,7 +182,7 @@ If using an IDE with CMake, setting the ``PYTHON`` value as a CMake cache overri
|
||||
To manage the Python version more generally via the command line, check out the tools pyenv_ or virtualenv_. These let you change the default Python version.
|
||||
|
||||
Possible issues
|
||||
^^^^^^^^^^^^^^^
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The user of ``idf.py`` may sometimes experience ``ImportError`` described below.
|
||||
|
||||
@ -234,8 +226,7 @@ An example project directory tree might look like this::
|
||||
|
||||
This example "myProject" contains the following elements:
|
||||
|
||||
- A top-level project CMakeLists.txt file. This is the primary file which CMake uses to learn how to build the project; and may set project-wide CMake variables. It includes the file :idf_file:`/tools/cmake/project.cmake` which
|
||||
implements the rest of the build system. Finally, it sets the project name and defines the project.
|
||||
- A top-level project CMakeLists.txt file. This is the primary file which CMake uses to learn how to build the project; and may set project-wide CMake variables. It includes the file :idf_file:`/tools/cmake/project.cmake` which implements the rest of the build system. Finally, it sets the project name and defines the project.
|
||||
|
||||
- "sdkconfig" project configuration file. This file is created/updated when ``idf.py menuconfig`` runs, and holds configuration for all of the components in the project (including ESP-IDF itself). The "sdkconfig" file may or may not be added to the source control system of the project.
|
||||
|
||||
@ -245,8 +236,7 @@ This example "myProject" contains the following elements:
|
||||
|
||||
- "build" directory is where build output is created. This directory is created by ``idf.py`` if it doesn't already exist. CMake configures the project and generates interim build files in this directory. Then, after the main build process is run, this directory will also contain interim object files and libraries as well as final binary output files. This directory is usually not added to source control or distributed with the project source code.
|
||||
|
||||
Component directories each contain a component ``CMakeLists.txt`` file. This file contains variable definitions
|
||||
to control the build process of the component, and its integration into the overall project. See `Component CMakeLists Files`_ for more details.
|
||||
Component directories each contain a component ``CMakeLists.txt`` file. This file contains variable definitions to control the build process of the component, and its integration into the overall project. See `Component CMakeLists Files`_ for more details.
|
||||
|
||||
Each component may also include a ``Kconfig`` file defining the `component configuration`_ options that can be set via ``menuconfig``. Some components may also include ``Kconfig.projbuild`` and ``project_include.cmake`` files, which are special files for `overriding parts of the project`_.
|
||||
|
||||
@ -266,7 +256,6 @@ Minimal project::
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(myProject)
|
||||
|
||||
|
||||
.. _project-mandatory-parts:
|
||||
|
||||
Mandatory Parts
|
||||
@ -278,6 +267,7 @@ The inclusion of these three lines, in the order shown above, is necessary for e
|
||||
- ``include($ENV{IDF_PATH}/tools/cmake/project.cmake)`` pulls in the rest of the CMake functionality to configure the project, discover all the components, etc.
|
||||
- ``project(myProject)`` creates the project itself, and specifies the project name. The project name is used for the final binary output files of the app - ie ``myProject.elf``, ``myProject.bin``. Only one project can be defined per CMakeLists file.
|
||||
|
||||
.. _optional_project_variable:
|
||||
|
||||
Optional Project Variables
|
||||
--------------------------
|
||||
@ -285,7 +275,9 @@ Optional Project Variables
|
||||
These variables all have default values that can be overridden for custom behaviour. Look in :idf_file:`/tools/cmake/project.cmake` for all of the implementation details.
|
||||
|
||||
- ``COMPONENT_DIRS``, ``COMPONENTS_DIRS``: Directories to search for components. Defaults to ``IDF_PATH/components``, ``PROJECT_DIR/components``, and ``EXTRA_COMPONENT_DIRS``. Override this variable if you don't want to search for components in these places.
|
||||
|
||||
- ``EXTRA_COMPONENT_DIRS``, ``EXTRA_COMPONENTS_DIRS``: Optional list of additional directories to search for components. Paths can be relative to the project directory, or absolute.
|
||||
|
||||
- ``COMPONENTS``: A list of component names to build into the project. Defaults to all components found in the ``COMPONENT_DIRS`` directories. Use this variable to "trim down" the project for faster build times. Note that any component which "requires" another component via the REQUIRES or PRIV_REQUIRES arguments on component registration will automatically have it added to this list, so the ``COMPONENTS`` list can be very short.
|
||||
|
||||
Any paths in these variables can be absolute paths, or set relative to the project directory.
|
||||
@ -297,11 +289,7 @@ To set these variables, use the `cmake set command <cmake set_>`_ ie ``set(VARIA
|
||||
Renaming ``main`` component
|
||||
----------------------------
|
||||
|
||||
The build system provides special treatment to the ``main`` component. It is a component that gets automatically added to the build provided
|
||||
that it is in the expected location, PROJECT_DIR/main. All other components in the build are also added as its dependencies,
|
||||
saving the user from hunting down dependencies and providing a build that works right out of the box. Renaming the ``main`` component
|
||||
causes the loss of these behind-the-scences heavy lifting, requiring the user to specify the location of the newly renamed component
|
||||
and manually specifying its dependencies. Specifically, the steps to renaming ``main`` are as follows:
|
||||
The build system provides special treatment to the ``main`` component. It is a component that gets automatically added to the build provided that it is in the expected location, PROJECT_DIR/main. All other components in the build are also added as its dependencies, saving the user from hunting down dependencies and providing a build that works right out of the box. Renaming the ``main`` component causes the loss of these behind-the-scenes heavy lifting, requiring the user to specify the location of the newly renamed component and manually specifying its dependencies. Specifically, the steps to renaming ``main`` are as follows:
|
||||
|
||||
1. Rename ``main`` directory.
|
||||
2. Set ``EXTRA_COMPONENT_DIRS`` in the project CMakeLists.txt to include the renamed ``main`` directory.
|
||||
@ -323,13 +311,12 @@ The list of directories in ``COMPONENT_DIRS`` is searched for the project's comp
|
||||
|
||||
When CMake runs to configure the project, it logs the components included in the build. This list can be useful for debugging the inclusion/exclusion of certain components.
|
||||
|
||||
.. _cmake-components-same-name:
|
||||
|
||||
Multiple components with the same name
|
||||
--------------------------------------
|
||||
|
||||
When ESP-IDF is collecting all the components to compile, it will do this in the order specified by ``COMPONENT_DIRS``; by default, this means ESP-IDF's internal components first, then the project's components, and finally any components set in ``EXTRA_COMPONENT_DIRS``. If two or more of these directories
|
||||
contain component sub-directories with the same name, the component in the last place searched is used. This allows, for example, overriding ESP-IDF components
|
||||
with a modified version by copying that component from the ESP-IDF components directory to the project components directory and then modifying it there.
|
||||
If used in this way, the ESP-IDF directory itself can remain untouched.
|
||||
When ESP-IDF is collecting all the components to compile, it will do this in the order specified by ``COMPONENT_DIRS``; by default, this means ESP-IDF's internal components first, then the project's components, and finally any components set in ``EXTRA_COMPONENT_DIRS``. If two or more of these directories contain component sub-directories with the same name, the component in the last place searched is used. This allows, for example, overriding ESP-IDF components with a modified version by copying that component from the ESP-IDF components directory to the project components directory and then modifying it there. If used in this way, the ESP-IDF directory itself can remain untouched.
|
||||
|
||||
.. _cmake_minimal_component_cmakelists:
|
||||
|
||||
@ -349,10 +336,10 @@ The minimal component ``CMakeLists.txt`` file simply registers the component to
|
||||
- ``REQUIRES`` is not actually required, but it is very often required to declare what other components this component will use. See :ref:`component requirements`.
|
||||
|
||||
A library with the name of the component will be built and linked into the final app.
|
||||
|
||||
Directories are usually specified relative to the ``CMakeLists.txt`` file itself, although they can be absolute.
|
||||
|
||||
There are other arguments that can be passed to ``idf_component_register``. These arguments
|
||||
are discussed :ref:`here<cmake-component-register>`.
|
||||
There are other arguments that can be passed to ``idf_component_register``. These arguments are discussed :ref:`here<cmake-component-register>`.
|
||||
|
||||
See `example component requirements`_ and `example component CMakeLists`_ for more complete component ``CMakeLists.txt`` examples.
|
||||
|
||||
@ -394,6 +381,8 @@ from the component CMakeLists.txt:
|
||||
|
||||
Other build properties are listed :ref:`here<cmake-build-properties>`.
|
||||
|
||||
.. _component_build_control:
|
||||
|
||||
Controlling Component Compilation
|
||||
---------------------------------
|
||||
|
||||
@ -419,8 +408,7 @@ When using these commands, place them after the call to ``idf_component_register
|
||||
Component Configuration
|
||||
=======================
|
||||
|
||||
Each component can also have a ``Kconfig`` file, alongside ``CMakeLists.txt``. This contains
|
||||
configuration settings to add to the configuration menu for this component.
|
||||
Each component can also have a ``Kconfig`` file, alongside ``CMakeLists.txt``. This contains configuration settings to add to the configuration menu for this component.
|
||||
|
||||
These settings are found under the "Component Settings" menu when menuconfig is run.
|
||||
|
||||
@ -453,8 +441,11 @@ When writing a component
|
||||
PRIV_REQUIRES console spiffs)
|
||||
|
||||
- ``REQUIRES`` should be set to all components whose header files are #included from the *public* header files of this component.
|
||||
|
||||
- ``PRIV_REQUIRES`` should be set to all components whose header files are #included from *any source files* in this component, unless already listed in ``REQUIRES``. Also any component which is required to be linked in order for this component to function correctly.
|
||||
|
||||
- The values of ``REQUIRES`` and ``PRIV_REQUIRES`` should not depend on any configuration choices (``CONFIG_xxx`` macros). This is because requirements are expanded before configuration is loaded. Other component variables (like include paths or source files) can depend on configuration choices.
|
||||
|
||||
- Not setting either or both ``REQUIRES`` variables is fine. If the component has no requirements except for the `Common component requirements`_ needed for RTOS, libc, etc.
|
||||
|
||||
If a components only supports some target chips (values of ``IDF_TARGET``) then it can specify ``REQUIRED_IDF_TARGETS`` in the ``idf_component_register`` call to express these requirements. In this case the build system will generate an error if the component is included into the build, but does not support the selected target.
|
||||
@ -558,7 +549,6 @@ This means that the ``spark_plug/CMakeLists.txt`` file doesn't need any ``REQUIR
|
||||
INCLUDE_DIRS ".")
|
||||
|
||||
|
||||
|
||||
Source File Include Directories
|
||||
-------------------------------
|
||||
|
||||
@ -596,6 +586,7 @@ Including components in the build
|
||||
- Components mentioned explicitly in ``COMPONENTS``.
|
||||
- Those components' requirements (evaluated recursively).
|
||||
- The "common" components that every component depends on.
|
||||
|
||||
- Setting ``COMPONENTS`` to the minimal list of required components can significantly reduce compile times.
|
||||
|
||||
.. _component-requirements-implementation:
|
||||
@ -617,6 +608,8 @@ The order of components in the ``BUILD_COMPONENTS`` variable determines other or
|
||||
- Order that :ref:`project_include.cmake` files are included into the project.
|
||||
- Order that the list of header paths is generated for compilation (via ``-I`` argument). (Note that for a given component's source files, only that component's dependency's header paths are passed to the compiler.)
|
||||
|
||||
.. _override_project_config:
|
||||
|
||||
Build Process Internals
|
||||
=======================
|
||||
|
||||
@ -649,7 +642,7 @@ The custom ``project()`` function performs the following steps:
|
||||
Browse the :idf_file:`/tools/cmake/project.cmake` file and supporting functions in :idf_file:`/tools/cmake/idf_functions.cmake` for more details.
|
||||
|
||||
Debugging CMake
|
||||
---------------
|
||||
===============
|
||||
|
||||
Some tips for debugging the ESP-IDF CMake-based build system:
|
||||
|
||||
@ -664,7 +657,7 @@ It also defines an overridden custom version of the built-in CMake_ ``project``
|
||||
.. _warn-undefined-variables:
|
||||
|
||||
Warning On Undefined Variables
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
------------------------------
|
||||
|
||||
By default, ``idf.py`` passes the ``--warn-uninitialized`` flag to CMake_ so it will print a warning if an undefined variable is referenced in the build. This can be very useful to find buggy CMake files.
|
||||
|
||||
@ -680,9 +673,7 @@ Overriding Parts of the Project
|
||||
project_include.cmake
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
For components that have build requirements which must be evaluated before any component CMakeLists
|
||||
files are evaluated, you can create a file called ``project_include.cmake`` in the
|
||||
component directory. This CMake file is included when ``project.cmake`` is evaluating the entire project.
|
||||
For components that have build requirements which must be evaluated before any component CMakeLists files are evaluated, you can create a file called ``project_include.cmake`` in the component directory. This CMake file is included when ``project.cmake`` is evaluating the entire project.
|
||||
|
||||
``project_include.cmake`` files are used inside ESP-IDF, for defining project-wide build features such as ``esptool.py`` command line arguments and the ``bootloader`` "special app".
|
||||
|
||||
@ -697,32 +688,32 @@ Take great care when setting variables or targets in a ``project_include.cmake``
|
||||
KConfig.projbuild
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
This is an equivalent to ``project_include.cmake`` for :ref:`component-configuration` KConfig files. If you want to include
|
||||
configuration options at the top-level of menuconfig, rather than inside the "Component Configuration" sub-menu, then these can be defined in the KConfig.projbuild file alongside the ``CMakeLists.txt`` file.
|
||||
This is an equivalent to ``project_include.cmake`` for :ref:`component-configuration` KConfig files. If you want to include configuration options at the top-level of menuconfig, rather than inside the "Component Configuration" sub-menu, then these can be defined in the KConfig.projbuild file alongside the ``CMakeLists.txt`` file.
|
||||
|
||||
Take care when adding configuration values in this file, as they will be included across the entire project configuration. Where possible, it's generally better to create a KConfig file for :ref:`component-configuration`.
|
||||
|
||||
``project_include.cmake`` files are used inside ESP-IDF, for defining project-wide build features such as ``esptool.py`` command line arguments and the ``bootloader`` "special app".
|
||||
|
||||
.. _config_only_component:
|
||||
|
||||
Configuration-Only Components
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Special components which contain no source files, only ``Kconfig.projbuild`` and ``KConfig``, can have a one-line ``CMakeLists.txt`` file which calls the function ``idf_component_register()`` with no
|
||||
arguments specified. This function will include the component in the project build, but no library will be built *and* no header files will be added to any include paths.
|
||||
Special components which contain no source files, only ``Kconfig.projbuild`` and ``KConfig``, can have a one-line ``CMakeLists.txt`` file which calls the function ``idf_component_register()`` with no arguments specified. This function will include the component in the project build, but no library will be built *and* no header files will be added to any include paths.
|
||||
|
||||
Example Component CMakeLists
|
||||
============================
|
||||
|
||||
Because the build environment tries to set reasonable defaults that will work most
|
||||
of the time, component ``CMakeLists.txt`` can be very small or even empty (see `Minimal Component CMakeLists`_). However, overriding `component variables`_ is usually required for some functionality.
|
||||
Because the build environment tries to set reasonable defaults that will work most of the time, component ``CMakeLists.txt`` can be very small or even empty (see `Minimal Component CMakeLists`_). However, overriding `component variables`_ is usually required for some functionality.
|
||||
|
||||
Here are some more advanced examples of component CMakeLists files.
|
||||
|
||||
.. _add_conditional_config:
|
||||
|
||||
Adding conditional configuration
|
||||
--------------------------------
|
||||
|
||||
The configuration system can be used to conditionally compile some files
|
||||
depending on the options selected in the project configuration.
|
||||
The configuration system can be used to conditionally compile some files depending on the options selected in the project configuration.
|
||||
|
||||
.. highlight:: none
|
||||
|
||||
@ -798,12 +789,7 @@ Note that component dependencies may depend on ``IDF_TARGET`` variable, but not
|
||||
Source Code Generation
|
||||
----------------------
|
||||
|
||||
Some components will have a situation where a source file isn't
|
||||
supplied with the component itself but has to be generated from
|
||||
another file. Say our component has a header file that consists of the
|
||||
converted binary data of a BMP file, converted using a hypothetical
|
||||
tool called bmp2h. The header file is then included in as C source
|
||||
file called graphics_lib.c::
|
||||
Some components will have a situation where a source file isn't supplied with the component itself but has to be generated from another file. Say our component has a header file that consists of the converted binary data of a BMP file, converted using a hypothetical tool called bmp2h. The header file is then included in as C source file called graphics_lib.c::
|
||||
|
||||
add_custom_command(OUTPUT logo.h
|
||||
COMMAND bmp2h -i ${COMPONENT_DIR}/logo.bmp -o log.h
|
||||
@ -818,18 +804,13 @@ file called graphics_lib.c::
|
||||
|
||||
This answer is adapted from the `CMake FAQ entry <cmake faq generated files_>`_, which contains some other examples that will also work with ESP-IDF builds.
|
||||
|
||||
In this example, logo.h will be generated in the
|
||||
current directory (the build directory) while logo.bmp comes with the
|
||||
component and resides under the component path. Because logo.h is a
|
||||
generated file, it should be cleaned when the project is cleaned. For this reason
|
||||
it is added to the `ADDITIONAL_MAKE_CLEAN_FILES`_ property.
|
||||
In this example, logo.h will be generated in the current directory (the build directory) while logo.bmp comes with the component and resides under the component path. Because logo.h is a generated file, it should be cleaned when the project is cleaned. For this reason it is added to the `ADDITIONAL_MAKE_CLEAN_FILES`_ property.
|
||||
|
||||
.. note::
|
||||
|
||||
If generating files as part of the project CMakeLists.txt file, not a component CMakeLists.txt, then use build property ``PROJECT_DIR`` instead of ``${COMPONENT_DIR}`` and ``${PROJECT_NAME}.elf`` instead of ``${COMPONENT_LIB}``.)
|
||||
|
||||
If a a source file from another component included ``logo.h``, then ``add_dependencies`` would need to be called to add a dependency between
|
||||
the two components, to ensure that the component source files were always compiled in the correct order.
|
||||
If a a source file from another component included ``logo.h``, then ``add_dependencies`` would need to be called to add a dependency between the two components, to ensure that the component source files were always compiled in the correct order.
|
||||
|
||||
.. _cmake_embed_data:
|
||||
|
||||
@ -843,7 +824,6 @@ You can specify argument ``EMBED_FILES`` in the component registration, giving s
|
||||
idf_component_register(...
|
||||
EMBED_FILES server_root_cert.der)
|
||||
|
||||
|
||||
Or if the file is a string, you can use the variable ``EMBED_TXTFILES``. This will embed the contents of the text file as a null-terminated string::
|
||||
|
||||
idf_component_register(...
|
||||
@ -871,10 +851,7 @@ For an example of using this technique, see :example:`protocols/https_request` -
|
||||
Code and Data Placements
|
||||
------------------------
|
||||
|
||||
ESP-IDF has a feature called linker script generation that enables components to define where its code and data will be placed in memory through
|
||||
linker fragment files. These files are processed by the build system, and is used to augment the linker script used for linking
|
||||
app binary. See :doc:`Linker Script Generation <linker-script-generation>` for a quick start guide as well as a detailed discussion
|
||||
of the mechanism.
|
||||
ESP-IDF has a feature called linker script generation that enables components to define where its code and data will be placed in memory through linker fragment files. These files are processed by the build system, and is used to augment the linker script used for linking app binary. See :doc:`Linker Script Generation <linker-script-generation>` for a quick start guide as well as a detailed discussion of the mechanism.
|
||||
|
||||
.. _component-build-full-override:
|
||||
|
||||
@ -883,11 +860,7 @@ Fully Overriding The Component Build Process
|
||||
|
||||
.. highlight:: cmake
|
||||
|
||||
Obviously, there are cases where all these recipes are insufficient for a
|
||||
certain component, for example when the component is basically a wrapper
|
||||
around another third-party component not originally intended to be
|
||||
compiled under this build system. In that case, it's possible to forego
|
||||
the ESP-IDF build system entirely by using a CMake feature called ExternalProject_. Example component CMakeLists::
|
||||
Obviously, there are cases where all these recipes are insufficient for a certain component, for example when the component is basically a wrapper around another third-party component not originally intended to be compiled under this build system. In that case, it's possible to forego the ESP-IDF build system entirely by using a CMake feature called ExternalProject_. Example component CMakeLists::
|
||||
|
||||
# External build process for quirc, runs in source dir and
|
||||
# produces libquirc.a
|
||||
@ -901,7 +874,6 @@ the ESP-IDF build system entirely by using a CMake feature called ExternalProjec
|
||||
)
|
||||
|
||||
# Add libquirc.a to the build process
|
||||
#
|
||||
add_library(quirc STATIC IMPORTED GLOBAL)
|
||||
add_dependencies(quirc quirc_build)
|
||||
|
||||
@ -958,6 +930,7 @@ In addition to ``sdkconfig.defaults`` file, build system will also load defaults
|
||||
|
||||
If ``SDKCONFIG_DEFAULTS`` is used to override the name of defaults file, the name of target-specific defaults file will be derived from ``SDKCONFIG_DEFAULTS`` value.
|
||||
|
||||
.. _flash_parameters:
|
||||
|
||||
Flash arguments
|
||||
===============
|
||||
@ -989,15 +962,18 @@ The bootloader is a special "subproject" inside :idf:`/components/bootloader/sub
|
||||
|
||||
The subproject is inserted as an external project from the top-level project, by the file :idf_file:`/components/bootloader/project_include.cmake`. The main build process runs CMake for the subproject, which includes discovering components (a subset of the main components) and generating a bootloader-specific config (derived from the main ``sdkconfig``).
|
||||
|
||||
.. _selecting-idf-target:
|
||||
|
||||
Selecting the Target
|
||||
====================
|
||||
|
||||
Currently ESP-IDF supports one target, ``esp32``. It is used by default by the build system. Developers working on adding multiple target support can change the target as follows::
|
||||
|
||||
rm sdkconfig
|
||||
idf.py -DIDF_TARGET=new_target reconfigure
|
||||
|
||||
|
||||
.. _write-pure-component:
|
||||
|
||||
Writing Pure CMake Components
|
||||
=============================
|
||||
|
||||
@ -1019,13 +995,10 @@ Here is an example minimal "pure CMake" component CMakeLists file for a componen
|
||||
- This file is quite simple as there are not a lot of source files. For components with a large number of files, the globbing behaviour of ESP-IDF's component logic can make the component CMakeLists style simpler.)
|
||||
- Any time a component adds a library target with the component name, the ESP-IDF build system will automatically add this to the build, expose public include directories, etc. If a component wants to add a library target with a different name, dependencies will need to be added manually via CMake commands.
|
||||
|
||||
|
||||
Using Third-Party CMake Projects with Components
|
||||
================================================
|
||||
|
||||
CMake is used for a lot of open-source C and C++ projects — code that users can tap into for their applications. One of the benefits of having a CMake build system
|
||||
is the ability to import these third-party projects, sometimes even without modification! This allows for users to be able to get functionality that may
|
||||
not yet be provided by a component, or use another library for the same functionality.
|
||||
CMake is used for a lot of open-source C and C++ projects — code that users can tap into for their applications. One of the benefits of having a CMake build system is the ability to import these third-party projects, sometimes even without modification! This allows for users to be able to get functionality that may not yet be provided by a component, or use another library for the same functionality.
|
||||
|
||||
.. highlight:: cmake
|
||||
|
||||
@ -1044,12 +1017,9 @@ Importing a library might look like this for a hypothetical library ``foo`` to b
|
||||
# Publicly link `foo` to `main` component
|
||||
target_link_libraries(main PUBLIC foo)
|
||||
|
||||
For an actual example, take a look at :example:`build_system/cmake/import_lib`. Take note that what needs to be done in order to import
|
||||
the library may vary. It is recommended to read up on the library's documentation for instructions on how to
|
||||
import it from other projects. Studying the library's CMakeLists.txt and build structure can also be helpful.
|
||||
For an actual example, take a look at :example:`build_system/cmake/import_lib`. Take note that what needs to be done in order to import the library may vary. It is recommended to read up on the library's documentation for instructions on how to import it from other projects. Studying the library's CMakeLists.txt and build structure can also be helpful.
|
||||
|
||||
It is also possible to wrap a third-party library to be used as a component in this manner. For example, the :component:`mbedtls` component is a wrapper for
|
||||
Espressif's fork of `mbedtls <https://github.com/ARMmbed/mbedtls>`_. See its :component_file:`component CMakeLists.txt <mbedtls/CMakeLists.txt>`.
|
||||
It is also possible to wrap a third-party library to be used as a component in this manner. For example, the :component:`mbedtls` component is a wrapper for Espressif's fork of `mbedtls <https://github.com/ARMmbed/mbedtls>`_. See its :component_file:`component CMakeLists.txt <mbedtls/CMakeLists.txt>`.
|
||||
|
||||
The CMake variable ``ESP_PLATFORM`` is set to 1 whenever the ESP-IDF build system is being used. Tests such as ``if (ESP_PLATFORM)`` can be used in generic CMake code if special IDF-specific logic is required.
|
||||
|
||||
@ -1058,8 +1028,7 @@ Using Prebuilt Libraries with Components
|
||||
|
||||
.. highlight:: cmake
|
||||
|
||||
The ESP-IDF build system provides a utility function ``add_prebuilt_library`` for users to be able to easily import and use
|
||||
prebuilt libraries::
|
||||
The ESP-IDF build system provides a utility function ``add_prebuilt_library`` for users to be able to easily import and use prebuilt libraries::
|
||||
|
||||
add_prebuilt_library(target_name lib_path [REQUIRES req1 req2 ...] [PRIV_REQUIRES req1 req2 ...])
|
||||
|
||||
@ -1070,18 +1039,14 @@ where:
|
||||
|
||||
Optional arguments ``REQUIRES`` and ``PRIV_REQUIRES`` specify dependency on other components. These have the same meaning as the arguments for ``idf_component_register``.
|
||||
|
||||
Take note that the prebuilt library must have been compiled for the same target as the consuming project. Configuration relevant to the prebuilt
|
||||
library must also match. If not paid attention to, these two factors may contribute to subtle bugs in the app.
|
||||
Take note that the prebuilt library must have been compiled for the same target as the consuming project. Configuration relevant to the prebuilt library must also match. If not paid attention to, these two factors may contribute to subtle bugs in the app.
|
||||
|
||||
For an example, take a look at :example:`build_system/cmake/import_prebuilt`.
|
||||
|
||||
|
||||
Using ESP-IDF in Custom CMake Projects
|
||||
======================================
|
||||
|
||||
ESP-IDF provides a template CMake project for easily creating an application. However, in some instances the user might already
|
||||
have an existing CMake project or may want to create a custom one. In these cases it is desirable to be able to consume IDF components
|
||||
as libraries to be linked to the user's targets (libraries/ executables).
|
||||
ESP-IDF provides a template CMake project for easily creating an application. However, in some instances the user might already have an existing CMake project or may want to create a custom one. In these cases it is desirable to be able to consume IDF components as libraries to be linked to the user's targets (libraries/ executables).
|
||||
|
||||
It is possible to do so by using the :ref:`build system APIs provided<cmake_buildsystem_api>` by :idf_file:`tools/cmake/idf.cmake`. For example:
|
||||
|
||||
@ -1094,7 +1059,7 @@ It is possible to do so by using the :ref:`build system APIs provided<cmake_buil
|
||||
include($ENV{IDF_PATH}/tools/cmake/idf.cmake)
|
||||
|
||||
# Include ESP-IDF components in the build, may be thought as an equivalent of
|
||||
# add_subdirectory() but with some additional procesing and magic for ESP-IDF build
|
||||
# add_subdirectory() but with some additional processing and magic for ESP-IDF build
|
||||
# specific build processes.
|
||||
idf_build_process(esp32)
|
||||
|
||||
@ -1106,10 +1071,10 @@ It is possible to do so by using the :ref:`build system APIs provided<cmake_buil
|
||||
# Let the build system know what the project executable is to attach more targets, dependencies, etc.
|
||||
idf_build_executable(${CMAKE_PROJECT_NAME}.elf)
|
||||
|
||||
The example in :example:`build_system/cmake/idf_as_lib` demonstrates the creation of an application equivalent to :example:`hello world application <get-started/hello_world>`
|
||||
using a custom CMake project.
|
||||
The example in :example:`build_system/cmake/idf_as_lib` demonstrates the creation of an application equivalent to :example:`hello world application <get-started/hello_world>` using a custom CMake project.
|
||||
|
||||
.. note:: The IDF build system can only set compiler flags for source files that it builds. When an external CMakeLists.txt file is used and PSRAM is enabled, remember to add ``-mfix-esp32-psram-cache-issue`` to the C compiler arguments. See :ref:`CONFIG_SPIRAM_CACHE_WORKAROUND` for details of this flag.
|
||||
|
||||
.. _cmake_buildsystem_api:
|
||||
|
||||
ESP-IDF CMake Build System API
|
||||
@ -1122,17 +1087,13 @@ idf-build-commands
|
||||
|
||||
idf_build_get_property(var property [GENERATOR_EXPRESSION])
|
||||
|
||||
Retrieve a :ref:`build property<cmake-build-properties>` *property* and store it in *var* accessible from the current scope. Specifying
|
||||
*GENERATOR_EXPRESSION* will retrieve the generator expression string for that property, instead of the actual value, which
|
||||
can be used with CMake commands that support generator expressions.
|
||||
Retrieve a :ref:`build property<cmake-build-properties>` *property* and store it in *var* accessible from the current scope. Specifying *GENERATOR_EXPRESSION* will retrieve the generator expression string for that property, instead of the actual value, which can be used with CMake commands that support generator expressions.
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
idf_build_set_property(property val [APPEND])
|
||||
|
||||
Set a :ref:`build property<cmake-build-properties>` *property* with value *val*. Specifying *APPEND* will append the specified value to the current
|
||||
value of the property. If the property does not previously exist or it is currently empty, the specified value becomes
|
||||
the first element/member instead.
|
||||
Set a :ref:`build property<cmake-build-properties>` *property* with value *val*. Specifying *APPEND* will append the specified value to the current value of the property. If the property does not previously exist or it is currently empty, the specified value becomes the first element/member instead.
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
@ -1154,11 +1115,8 @@ This command does not guarantee that the component will be processed during buil
|
||||
[BUILD_DIR build_dir]
|
||||
[COMPONENTS component1 component2 ...])
|
||||
|
||||
Performs the bulk of the behind-the-scenes magic for including ESP-IDF components such as component configuration, libraries creation,
|
||||
dependency expansion and resolution. Among these functions, perhaps the most important
|
||||
from a user's perspective is the libraries creation by calling each component's ``idf_component_register``. This command creates the libraries for each component, which are accessible using aliases in the form
|
||||
idf::*component_name*. These aliases can be used to link the components to the user's own targets, either libraries
|
||||
or executables.
|
||||
Performs the bulk of the behind-the-scenes magic for including ESP-IDF components such as component configuration, libraries creation, dependency expansion and resolution. Among these functions, perhaps the most important from a user's perspective is the libraries creation by calling each component's ``idf_component_register``. This command creates the libraries for each component, which are accessible using aliases in the form idf::*component_name*.
|
||||
These aliases can be used to link the components to the user's own targets, either libraries or executables.
|
||||
|
||||
The call requires the target chip to be specified with *target* argument. Optional arguments for the call include:
|
||||
|
||||
@ -1169,63 +1127,57 @@ The call requires the target chip to be specified with *target* argument. Option
|
||||
- SDKCONFIG_DEFAULTS - defaults file to use for the build; defaults to empty
|
||||
- BUILD_DIR - directory to place ESP-IDF build-related artifacts, such as generated binaries, text files, components; defaults to CMAKE_BINARY_DIR
|
||||
- COMPONENTS - select components to process among the components known by the build system (added via `idf_build_component`). This argument is used to trim the build.
|
||||
Other components are automatically added if they are required in the dependency chain, i.e.
|
||||
the public and private requirements of the components in this list are automatically added, and in turn the public and private requirements of those requirements,
|
||||
so on and so forth. If not specified, all components known to the build system are processed.
|
||||
Other components are automatically added if they are required in the dependency chain, i.e. the public and private requirements of the components in this list are automatically added, and in turn the public and private requirements of those requirements, so on and so forth. If not specified, all components known to the build system are processed.
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
idf_build_executable(executable)
|
||||
|
||||
Specify the executable *executable* for ESP-IDF build. This attaches additional targets such as dependencies related to
|
||||
flashing, generating additional binary files, etc. Should be called after ``idf_build_process``.
|
||||
Specify the executable *executable* for ESP-IDF build. This attaches additional targets such as dependencies related to flashing, generating additional binary files, etc. Should be called after ``idf_build_process``.
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
idf_build_get_config(var config [GENERATOR_EXPRESSION])
|
||||
|
||||
Get the value of the specified config. Much like build properties, specifying
|
||||
*GENERATOR_EXPRESSION* will retrieve the generator expression string for that config, instead of the actual value, which
|
||||
can be used with CMake commands that support generator expressions. Actual config values are only known after call to `idf_build_process`, however.
|
||||
Get the value of the specified config. Much like build properties, specifying *GENERATOR_EXPRESSION* will retrieve the generator expression string for that config, instead of the actual value, which can be used with CMake commands that support generator expressions. Actual config values are only known after call to ``idf_build_process``, however.
|
||||
|
||||
.. _cmake-build-properties:
|
||||
|
||||
idf-build-properties
|
||||
--------------------
|
||||
|
||||
These are properties that describe the build. Values of build properties can be retrieved by using the build command ``idf_build_get_property``.
|
||||
For example, to get the Python interpreter used for the build:
|
||||
These are properties that describe the build. Values of build properties can be retrieved by using the build command ``idf_build_get_property``. For example, to get the Python interpreter used for the build:
|
||||
|
||||
.. code-block: cmake
|
||||
.. code-block:: cmake
|
||||
|
||||
idf_build_get_property(python PYTHON)
|
||||
message(STATUS "The Python intepreter is: ${python}")
|
||||
|
||||
- BUILD_DIR - build directory; set from ``idf_build_process`` BUILD_DIR argument
|
||||
- BUILD_COMPONENTS - list of components included in the build; set by ``idf_build_process``
|
||||
- BUILD_COMPONENT_ALIASES - list of library alias of components included in the build; set by ``idf_build_process``
|
||||
- C_COMPILE_OPTIONS - compile options applied to all components' C source files
|
||||
- COMPILE_OPTIONS - compile options applied to all components' source files, regardless of it being C or C++
|
||||
- COMPILE_DEFINITIONS - compile definitions applied to all component source files
|
||||
- CXX_COMPILE_OPTIONS - compile options applied to all components' C++ source files
|
||||
- EXECUTABLE - project executable; set by call to ``idf_build_executable``
|
||||
- EXECUTABLE_NAME - name of project executable without extension; set by call to ``idf_build_executable``
|
||||
- IDF_PATH - ESP-IDF path; set from IDF_PATH environment variable, if not, inferred from the location of ``idf.cmake``
|
||||
- IDF_TARGET - target chip for the build; set from the required target argument for ``idf_build_process``
|
||||
- IDF_VER - ESP-IDF version; set from either a version file or the Git revision of the IDF_PATH repository
|
||||
- INCLUDE_DIRECTORIES - include directories for all component source files
|
||||
- KCONFIGS - list of Kconfig files found in components in build; set by ``idf_build_process``
|
||||
- KCONFIG_PROJBUILDS - list of Kconfig.projbuild diles found in components in build; set by ``idf_build_process``
|
||||
- PROJECT_NAME - name of the project; set from ``idf_build_process`` PROJECT_NAME argument
|
||||
- PROJECT_DIR - directory of the project; set from ``idf_build_process`` PROJECT_DIR argument
|
||||
- PROJECT_VER - version of the project; set from ``idf_build_process`` PROJECT_VER argument
|
||||
- PYTHON - Python interpreter used for the build; set from PYTHON environment variable if available, if not "python" is used
|
||||
- SDKCONFIG - full path to output config file; set from ``idf_build_process`` SDKCONFIG argument
|
||||
- SDKCONFIG_DEFAULTS - full path to config defaults file; set from ``idf_build_process`` SDKCONFIG_DEFAULTS argument
|
||||
- SDKCONFIG_HEADER - full path to C/C++ header file containing component configuration; set by ``idf_build_process``
|
||||
- SDKCONFIG_CMAKE - full path to CMake file containing component configuration; set by ``idf_build_process``
|
||||
- SDKCONFIG_JSON - full path to JSON file containing component configuration; set by ``idf_build_process``
|
||||
- SDKCONFIG_JSON_MENUS - full path to JSON file containing config menus; set by ``idf_build_process``
|
||||
- BUILD_DIR - build directory; set from ``idf_build_process`` BUILD_DIR argument
|
||||
- BUILD_COMPONENTS - list of components included in the build; set by ``idf_build_process``
|
||||
- BUILD_COMPONENT_ALIASES - list of library alias of components included in the build; set by ``idf_build_process``
|
||||
- C_COMPILE_OPTIONS - compile options applied to all components' C source files
|
||||
- COMPILE_OPTIONS - compile options applied to all components' source files, regardless of it being C or C++
|
||||
- COMPILE_DEFINITIONS - compile definitions applied to all component source files
|
||||
- CXX_COMPILE_OPTIONS - compile options applied to all components' C++ source files
|
||||
- EXECUTABLE - project executable; set by call to ``idf_build_executable``
|
||||
- EXECUTABLE_NAME - name of project executable without extension; set by call to ``idf_build_executable``
|
||||
- IDF_PATH - ESP-IDF path; set from IDF_PATH environment variable, if not, inferred from the location of ``idf.cmake``
|
||||
- IDF_TARGET - target chip for the build; set from the required target argument for ``idf_build_process``
|
||||
- IDF_VER - ESP-IDF version; set from either a version file or the Git revision of the IDF_PATH repository
|
||||
- INCLUDE_DIRECTORIES - include directories for all component source files
|
||||
- KCONFIGS - list of Kconfig files found in components in build; set by ``idf_build_process``
|
||||
- KCONFIG_PROJBUILDS - list of Kconfig.projbuild files found in components in build; set by ``idf_build_process``
|
||||
- PROJECT_NAME - name of the project; set from ``idf_build_process`` PROJECT_NAME argument
|
||||
- PROJECT_DIR - directory of the project; set from ``idf_build_process`` PROJECT_DIR argument
|
||||
- PROJECT_VER - version of the project; set from ``idf_build_process`` PROJECT_VER argument
|
||||
- PYTHON - Python interpreter used for the build; set from PYTHON environment variable if available, if not "python" is used
|
||||
- SDKCONFIG - full path to output config file; set from ``idf_build_process`` SDKCONFIG argument
|
||||
- SDKCONFIG_DEFAULTS - full path to config defaults file; set from ``idf_build_process`` SDKCONFIG_DEFAULTS argument
|
||||
- SDKCONFIG_HEADER - full path to C/C++ header file containing component configuration; set by ``idf_build_process``
|
||||
- SDKCONFIG_CMAKE - full path to CMake file containing component configuration; set by ``idf_build_process``
|
||||
- SDKCONFIG_JSON - full path to JSON file containing component configuration; set by ``idf_build_process``
|
||||
- SDKCONFIG_JSON_MENUS - full path to JSON file containing config menus; set by ``idf_build_process``
|
||||
|
||||
idf-component-commands
|
||||
----------------------
|
||||
@ -1234,17 +1186,13 @@ idf-component-commands
|
||||
|
||||
idf_component_get_property(var component property [GENERATOR_EXPRESSION])
|
||||
|
||||
Retrieve a specified *component*'s :ref:`component property<cmake-component-properties>`, *property* and store it in *var* accessible from the current scope. Specifying
|
||||
*GENERATOR_EXPRESSION* will retrieve the generator expression string for that property, instead of the actual value, which
|
||||
can be used with CMake commands that support generator expressions.
|
||||
Retrieve a specified *component*'s :ref:`component property<cmake-component-properties>`, *property* and store it in *var* accessible from the current scope. Specifying *GENERATOR_EXPRESSION* will retrieve the generator expression string for that property, instead of the actual value, which can be used with CMake commands that support generator expressions.
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
idf_component_set_property(component property val [APPEND])
|
||||
|
||||
Set a specified *component*'s :ref:`component property<cmake-component-properties>`, *property* with value *val*. Specifying *APPEND* will append the specified value to the current
|
||||
value of the property. If the property does not previously exist or it is currently empty, the specified value becomes
|
||||
the first element/member instead.
|
||||
Set a specified *component*'s :ref:`component property<cmake-component-properties>`, *property* with value *val*. Specifying *APPEND* will append the specified value to the current value of the property. If the property does not previously exist or it is currently empty, the specified value becomes the first element/member instead.
|
||||
|
||||
.. _cmake-component-register:
|
||||
|
||||
@ -1260,9 +1208,7 @@ the first element/member instead.
|
||||
[EMBED_FILES file1 file2 ...]
|
||||
[EMBED_TXTFILES file1 file2 ...])
|
||||
|
||||
Register a component to the build system. Much like the ``project()`` CMake command, this should be called from the component's
|
||||
CMakeLists.txt directly (not through a function or macro) and is recommended to be called before any other command. Here are some
|
||||
guidelines on what commands can **not** be called before ``idf_component_register``:
|
||||
Register a component to the build system. Much like the ``project()`` CMake command, this should be called from the component's CMakeLists.txt directly (not through a function or macro) and is recommended to be called before any other command. Here are some guidelines on what commands can **not** be called before ``idf_component_register``:
|
||||
|
||||
- commands that are not valid in CMake script mode
|
||||
- custom commands defined in project_include.cmake
|
||||
@ -1272,8 +1218,7 @@ Commands that set and operate on variables are generally okay to call before ``i
|
||||
|
||||
The arguments for ``idf_component_register`` include:
|
||||
|
||||
- SRCS - component source files used for creating a static library for the component; if not specified, component is a treated as a
|
||||
config-only component and an interface library is created instead.
|
||||
- SRCS - component source files used for creating a static library for the component; if not specified, component is a treated as a config-only component and an interface library is created instead.
|
||||
- SRC_DIRS, EXCLUDE_SRCS - used to glob source files (.c, .cpp, .S) by specifying directories, instead of specifying source files manually via SRCS. Note that this is subject to the :ref:`limitations of globbing in CMake<cmake-file-globbing>`. Source files specified in EXCLUDE_SRCS are removed from the globbed files.
|
||||
- INCLUDE_DIRS - paths, relative to the component directory, which will be added to the include search path for all other components which require the current component
|
||||
- PRIV_INCLUDE_DIRS - directory paths, must be relative to the component directory, which will be added to the include search path for this component's source files only
|
||||
@ -1282,9 +1227,7 @@ The arguments for ``idf_component_register`` include:
|
||||
- LDFRAGMENTS - component linker fragment files
|
||||
- REQUIRED_IDF_TARGETS - specify the only target the component supports
|
||||
|
||||
The following are used for :ref:`embedding data into the component<cmake_embed_data>`, and is considered as source files
|
||||
when determining if a component is config-only. This means that even if the component does not specify source files, a static library is still
|
||||
created internally for the component if it specifies either:
|
||||
The following are used for :ref:`embedding data into the component<cmake_embed_data>`, and is considered as source files when determining if a component is config-only. This means that even if the component does not specify source files, a static library is still created internally for the component if it specifies either:
|
||||
|
||||
- EMBED_FILES - binary files to be embedded in the component
|
||||
- EMBED_TXTFILES - text files to be embedded in the component
|
||||
@ -1294,22 +1237,18 @@ created internally for the component if it specifies either:
|
||||
idf-component-properties
|
||||
------------------------
|
||||
|
||||
These are properties that describe a component. Values of component properties can be retrieved by using the build command ``idf_component_get_property``.
|
||||
For example, to get the directory of the ``freertos`` component:
|
||||
These are properties that describe a component. Values of component properties can be retrieved by using the build command ``idf_component_get_property``. For example, to get the directory of the ``freertos`` component:
|
||||
|
||||
.. code-block: cmake
|
||||
.. code-block:: cmake
|
||||
|
||||
idf_component_get_property(dir freertos COMPONENT_DIR)
|
||||
message(STATUS "The 'freertos' component directory is: ${dir}")
|
||||
|
||||
- COMPONENT_ALIAS - alias for COMPONENT_LIB used for linking the component to external targets; set by ``idf_build_component`` and alias library itself
|
||||
is created by ``idf_component_register``
|
||||
- COMPONENT_ALIAS - alias for COMPONENT_LIB used for linking the component to external targets; set by ``idf_build_component`` and alias library itself is created by ``idf_component_register``
|
||||
- COMPONENT_DIR - component directory; set by ``idf_build_component``
|
||||
- COMPONENT_LIB - name for created component static/interface library; set by ``idf_build_component`` and library itself
|
||||
is created by ``idf_component_register``
|
||||
- COMPONENT_LIB - name for created component static/interface library; set by ``idf_build_component`` and library itself is created by ``idf_component_register``
|
||||
- COMPONENT_NAME - name of the component; set by ``idf_build_component`` based on the component directory name
|
||||
- COMPONENT_TYPE - type of the component, whether LIBRARY or CONFIG_ONLY. A component is of type LIBRARY if it specifies
|
||||
source files or embeds a file
|
||||
- COMPONENT_TYPE - type of the component, whether LIBRARY or CONFIG_ONLY. A component is of type LIBRARY if it specifies source files or embeds a file
|
||||
- EMBED_FILES - list of files to embed in component; set from ``idf_component_register`` EMBED_FILES argument
|
||||
- EMBED_TXTFILES - list of text files to embed in component; set from ``idf_component_register`` EMBED_TXTFILES argument
|
||||
- INCLUDE_DIRS - list of component include directories; set from ``idf_component_register`` INCLUDE_DIRS argument
|
||||
@ -1354,6 +1293,8 @@ For project components (not part of ESP-IDF), there are a few different options:
|
||||
|
||||
The best option will depend on your particular project and its users.
|
||||
|
||||
.. _build_system_metadata:
|
||||
|
||||
Build System Metadata
|
||||
=====================
|
||||
|
||||
@ -1422,10 +1363,7 @@ Any combination of "load", "set", and "save" can be sent in a single command and
|
||||
Migrating from ESP-IDF GNU Make System
|
||||
======================================
|
||||
|
||||
Some aspects of the CMake-based ESP-IDF build system are very similar to the older GNU Make-based system. The developer needs to provide values
|
||||
the include directories, source files etc. There is a syntactical difference, however, as the developer needs to pass these as arguments
|
||||
to the registration command, `idf_component_register`.
|
||||
|
||||
Some aspects of the CMake-based ESP-IDF build system are very similar to the older GNU Make-based system. The developer needs to provide values the include directories, source files etc. There is a syntactical difference, however, as the developer needs to pass these as arguments to the registration command, ``idf_component_register``.
|
||||
|
||||
Automatic Conversion Tool
|
||||
-------------------------
|
||||
@ -1466,7 +1404,6 @@ Some features are significantly different or removed in the CMake-based system.
|
||||
- ``COMPONENT_CONFIG_ONLY``: Call ``idf_component_register`` without any arguments instead. See `Configuration-Only Components`_.
|
||||
- ``CFLAGS``, ``CPPFLAGS``, ``CXXFLAGS``: Use equivalent CMake commands instead. See `Controlling Component Compilation`_.
|
||||
|
||||
|
||||
No Default Values
|
||||
-----------------
|
||||
|
||||
@ -1480,7 +1417,6 @@ No Longer Necessary
|
||||
|
||||
- In the legacy Make-based build system, it is required to also set ``COMPONENT_SRCDIRS`` if ``COMPONENT_SRCS`` is set. In CMake, the equivalent is not necessary i.e. specifying ``SRC_DIRS`` to ``idf_component_register`` if ``SRCS`` is also specified (in fact, ``SRCS`` is ignored if ``SRC_DIRS`` is specified).
|
||||
|
||||
|
||||
Flashing from make
|
||||
------------------
|
||||
|
||||
|
@ -8,40 +8,57 @@ The IDF monitor tool is mainly a serial terminal program which relays serial dat
|
||||
|
||||
This tool can be launched from an IDF project by running ``idf.py monitor``.
|
||||
|
||||
(For the legacy GNU Make system, run ``make monitor``.)
|
||||
For the legacy GNU Make system, run ``make monitor``.
|
||||
|
||||
|
||||
Keyboard Shortcuts
|
||||
==================
|
||||
|
||||
For easy interaction with IDF Monitor, use the keyboard shortcuts given in the table.
|
||||
|
||||
+-------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Keyboard Shortcut | Action | Description |
|
||||
+===================+========================================================+======================================================================================================================================================================================================================================================+
|
||||
| Ctrl+] | Exit the program | |
|
||||
+-------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Ctrl+T | Menu escape key | Press and follow it by one of the keys given below. |
|
||||
+-------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| - Ctrl+T | Send the menu character itself to remote | |
|
||||
+-------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| - Ctrl+] | Send the exit character itself to remote | |
|
||||
+-------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| - Ctrl+P | Reset target into bootloader to pause app via RTS line | Resets the target, into bootloader via the RTS line (if connected), so that the board runs nothing. Useful when you need to wait for another device to startup. |
|
||||
+-------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| - Ctrl+R | Reset target board via RTS | Resets the target board and re-starts the application via the RTS line (if connected). |
|
||||
+-------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| - Ctrl+F | Build and flash the project | Pauses idf_monitor to run the project ``flash`` target, then resumes idf_monitor. Any changed source files are recompiled and then re-flashed. Target ``encrypted-flash`` is run if idf_monitor was started with argument ``-E``. |
|
||||
+-------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| - Ctrl+A (or A) | Build and flash the app only | Pauses idf_monitor to run the ``app-flash`` target, then resumes idf_monitor. Similar to the ``flash`` target, but only the main app is built and re-flashed. Target ``encrypted-app-flash`` is run if idf_monitor was started with argument ``-E``. |
|
||||
+-------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| - Ctrl+Y | Stop/resume log output printing on screen | Discards all incoming serial data while activated. Allows to quickly pause and examine log output without quitting the monitor. |
|
||||
+-------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| - Ctrl+L | Stop/resume log output saved to file | Creates a file in the project directory and the output is written to that file until this is disabled with the same keyboard shortcut (or IDF Monitor exits). |
|
||||
+-------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| - Ctrl+H (or H) | Display all keyboard shortcuts | |
|
||||
+-------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| - Ctrl+X (or X) | Exit the program | |
|
||||
+-------------------+--------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
:widths: 15 25 55
|
||||
|
||||
* - Keyboard Shortcut
|
||||
- Action
|
||||
- Description
|
||||
* - Ctrl+]
|
||||
- Exit the program
|
||||
-
|
||||
* - Ctrl+T
|
||||
- Menu escape key
|
||||
- Press and follow it by one of the keys given below.
|
||||
* - * Ctrl+T
|
||||
- Send the menu character itself to remote
|
||||
-
|
||||
* - * Ctrl+]
|
||||
- Send the exit character itself to remote
|
||||
-
|
||||
* - * Ctrl+P
|
||||
- Reset target into bootloader to pause app via RTS line
|
||||
- Resets the target, into bootloader via the RTS line (if connected), so that the board runs nothing. Useful when you need to wait for another device to startup.
|
||||
* - * Ctrl+R
|
||||
- Reset target board via RTS
|
||||
- Resets the target board and re-starts the application via the RTS line (if connected).
|
||||
* - * Ctrl+F
|
||||
- Build and flash the project
|
||||
- Pauses idf_monitor to run the project ``flash`` target, then resumes idf_monitor. Any changed source files are recompiled and then re-flashed. Target ``encrypted-flash`` is run if idf_monitor was started with argument ``-E``.
|
||||
* - * Ctrl+A (or A)
|
||||
- Build and flash the app only
|
||||
- Pauses idf_monitor to run the ``app-flash`` target, then resumes idf_monitor. Similar to the ``flash`` target, but only the main app is built and re-flashed. Target ``encrypted-app-flash`` is run if idf_monitor was started with argument ``-E``.
|
||||
* - * Ctrl+Y
|
||||
- Stop/resume log output printing on screen
|
||||
- Discards all incoming serial data while activated. Allows to quickly pause and examine log output without quitting the monitor.
|
||||
* - * Ctrl+L
|
||||
- Stop/resume log output saved to file
|
||||
- Creates a file in the project directory and the output is written to that file until this is disabled with the same keyboard shortcut (or IDF Monitor exits).
|
||||
* - * Ctrl+H (or H)
|
||||
- Display all keyboard shortcuts
|
||||
-
|
||||
* - * Ctrl+X (or X)
|
||||
- Exit the program
|
||||
-
|
||||
|
||||
Any keys pressed, other than ``Ctrl-]`` and ``Ctrl-T``, will be sent through the serial port.
|
||||
|
||||
@ -49,7 +66,6 @@ Any keys pressed, other than ``Ctrl-]`` and ``Ctrl-T``, will be sent through the
|
||||
IDF-specific features
|
||||
=====================
|
||||
|
||||
|
||||
Automatic Address Decoding
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@ -122,40 +138,23 @@ Restrictions on what to print can be specified as a series of ``<tag>:<log_level
|
||||
For example, ``PRINT_FILTER="tag1:W"`` matches and prints only the outputs written with ``ESP_LOGW("tag1", ...)`` or at lower verbosity level, i.e. ``ESP_LOGE("tag1", ...)``. Not specifying a ``<log_level>`` or using ``*`` defaults to Verbose level.
|
||||
|
||||
.. note::
|
||||
Use primary logging to disable at compilation the outputs you do not
|
||||
need through the :doc:`logging library<../../api-reference/system/log>`.
|
||||
Output filtering with IDF monitor is a secondary solution
|
||||
which can be useful for adjusting the filtering options without
|
||||
recompiling the application.
|
||||
Use primary logging to disable at compilation the outputs you do not need through the :doc:`logging library<../../api-reference/system/log>`. Output filtering with IDF monitor is a secondary solution which can be useful for adjusting the filtering options without recompiling the application.
|
||||
|
||||
Your app tags must not contain spaces, asterisks ``*``,
|
||||
and semicolons ``:`` to be compatible with the output filtering feature.
|
||||
Your app tags must not contain spaces, asterisks ``*``, or colons ``:`` to be compatible with the output filtering feature.
|
||||
|
||||
If the last line of the output in your app is not followed by a carriage return, the output filtering might get confused, i.e., the monitor starts to print the line and later finds out that the line should not have been written. This is a known issue and can be avoided by always adding a carriage return (especially when no output follows immediately afterwards).
|
||||
|
||||
Examples Of Filtering Rules:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- ``*`` can be used to match any tags. However, the string
|
||||
``PRINT_FILTER="*:I tag1:E"`` with regards to ``tag1`` prints errors
|
||||
only, because the rule for ``tag1`` has a higher priority over the rule for ``*``.
|
||||
- The default (empty) rule is equivalent to ``*:V`` because matching every tag
|
||||
at the Verbose level or lower means matching everything.
|
||||
- ``"*:N"`` suppresses not only the outputs from logging functions, but also
|
||||
the prints made by ``printf``, etc. To avoid this, use ``*:E`` or a higher verbosity level.
|
||||
- Rules ``"tag1:V"``, ``"tag1:v"``, ``"tag1:"``, ``"tag1:*"``, and ``"tag1"``
|
||||
are equivalent.
|
||||
- Rule ``"tag1:W tag1:E"`` is equivalent to ``"tag1:E"`` because any
|
||||
consequent occurrence of the same tag name overwrites the previous one.
|
||||
- Rule ``"tag1:I tag2:W"`` only prints ``tag1`` at the Info verbosity level or
|
||||
lower and ``tag2`` at the Warning verbosity level or lower.
|
||||
- Rule ``"tag1:I tag2:W tag3:N"`` is essentially equivalent to the previous
|
||||
one because ``tag3:N`` specifies that ``tag3`` should not be printed.
|
||||
- ``tag3:N`` in the rule ``"tag1:I tag2:W tag3:N *:V"`` is more meaningful because
|
||||
without ``tag3:N`` the ``tag3`` messages could have been printed;
|
||||
the errors for ``tag1`` and ``tag2`` will be printed at the specified (or lower)
|
||||
verbosity level and everything else will be printed by default.
|
||||
|
||||
- ``*`` can be used to match any tags. However, the string ``PRINT_FILTER="*:I tag1:E"`` with regards to ``tag1`` prints errors only, because the rule for ``tag1`` has a higher priority over the rule for ``*``.
|
||||
- The default (empty) rule is equivalent to ``*:V`` because matching every tag at the Verbose level or lower means matching everything.
|
||||
- ``"*:N"`` suppresses not only the outputs from logging functions, but also the prints made by ``printf``, etc. To avoid this, use ``*:E`` or a higher verbosity level.
|
||||
- Rules ``"tag1:V"``, ``"tag1:v"``, ``"tag1:"``, ``"tag1:*"``, and ``"tag1"`` are equivalent.
|
||||
- Rule ``"tag1:W tag1:E"`` is equivalent to ``"tag1:E"`` because any consequent occurrence of the same tag name overwrites the previous one.
|
||||
- Rule ``"tag1:I tag2:W"`` only prints ``tag1`` at the Info verbosity level or lower and ``tag2`` at the Warning verbosity level or lower.
|
||||
- Rule ``"tag1:I tag2:W tag3:N"`` is essentially equivalent to the previous one because ``tag3:N`` specifies that ``tag3`` should not be printed.
|
||||
- ``tag3:N`` in the rule ``"tag1:I tag2:W tag3:N *:V"`` is more meaningful because without ``tag3:N`` the ``tag3`` messages could have been printed; the errors for ``tag1`` and ``tag2`` will be printed at the specified (or lower) verbosity level and everything else will be printed by default.
|
||||
|
||||
|
||||
A More Complex Filtering Example
|
||||
@ -192,7 +191,7 @@ Known Issues with IDF Monitor
|
||||
=============================
|
||||
|
||||
Issues Observed on Windows
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- If in the Windows environment you receive the error "winpty: command not found", fix it by running ``pacman -S winpty``.
|
||||
- Arrow keys, as well as some other keys, do not work in GDB due to Windows Console limitations.
|
||||
|
@ -1,4 +1,4 @@
|
||||
ULP coprocessor programming
|
||||
ULP Coprocessor Programming
|
||||
===================================
|
||||
|
||||
:link_to_translation:`zh_CN:[中文]`
|
||||
@ -10,23 +10,23 @@ ULP coprocessor programming
|
||||
Programming using macros (legacy) <ulp_macros>
|
||||
|
||||
|
||||
ULP (Ultra Low Power) coprocessor is a simple FSM which is designed to perform measurements using ADC, temperature sensor, and external I2C sensors, while main processors are in deep sleep mode. ULP coprocessor can access RTC_SLOW_MEM memory region, and registers in RTC_CNTL, RTC_IO, and SARADC peripherals. ULP coprocessor uses fixed-width 32-bit instructions, 32-bit memory addressing, and has 4 general purpose 16-bit registers.
|
||||
The ULP (Ultra Low Power) coprocessor is a simple FSM (Finite State Machine) which is designed to perform measurements using the ADC, temperature sensor, and external I2C sensors, while the main processors are in deep sleep mode. The ULP coprocessor can access the RTC_SLOW_MEM memory region, and registers in RTC_CNTL, RTC_IO, and SARADC peripherals. The ULP coprocessor uses fixed-width 32-bit instructions, 32-bit memory addressing, and has 4 general-purpose 16-bit registers.
|
||||
|
||||
Installing the toolchain
|
||||
Installing the Toolchain
|
||||
------------------------
|
||||
|
||||
ULP coprocessor code is written in assembly and compiled using the `binutils-esp32ulp toolchain`_.
|
||||
The ULP coprocessor code is written in assembly and compiled using the `binutils-esp32ulp toolchain`_.
|
||||
|
||||
If you have already set up ESP-IDF with CMake build system according to the :doc:`Getting Started Guide <../../get-started/index>`, then the ULP toolchain is already installed.
|
||||
If you have already set up ESP-IDF with CMake build system according to the :doc:`Getting Started Guide <../../get-started/index>`, then the ULP toolchain will already be installed.
|
||||
|
||||
If you are using ESP-IDF with the legacy GNU Make based build system, refer to the instructions on this page: :doc:`ulp-legacy`.
|
||||
|
||||
Compiling ULP code
|
||||
------------------
|
||||
Compiling the ULP Code
|
||||
-----------------------
|
||||
|
||||
To compile ULP code as part of a component, the following steps must be taken:
|
||||
To compile the ULP code as part of the component, the following steps must be taken:
|
||||
|
||||
1. ULP code, written in assembly, must be added to one or more files with `.S` extension. These files must be placed into a separate directory inside component directory, for instance `ulp/`.
|
||||
1. The ULP code, written in assembly, must be added to one or more files with `.S` extension. These files must be placed into a separate directory inside the component directory, for instance `ulp/`.
|
||||
|
||||
.. note: When registering the component (via ``idf_component_register``), this directory should not be added to the ``SRC_DIRS`` argument. The logic behind this is that the ESP-IDF build system will compile files found in ``SRC_DIRS`` based on their extensions. For ``.S`` files, ``xtensa-esp32-elf-as`` assembler is used. This is not desirable for ULP assembly files, so the easiest way to achieve the distinction is by placing ULP assembly files into a separate directory. The ULP assembly source files should also **not** be added to ``SRCS`` for the same reason. See the step below for how to properly add ULP assembly source files.
|
||||
|
||||
@ -41,38 +41,34 @@ To compile ULP code as part of a component, the following steps must be taken:
|
||||
|
||||
ulp_embed_binary(${ulp_app_name} "${ulp_s_sources}" "${ulp_exp_dep_srcs}")
|
||||
|
||||
The first argument to ``ulp_embed_binary`` specifies the ULP binary name. The name specified here will also be used other generated artifacts
|
||||
such as the ELF file, map file, header file and linker export file. The second argument specifies the ULP assembly source files.
|
||||
Finally, the third argument specifies the list of component source files which include the header file to be generated.
|
||||
This list is needed to build the dependencies correctly and ensure that the generated header file is created before any of these files are compiled.
|
||||
See section below explaining the concept of generated header files for ULP applications.
|
||||
The first argument to ``ulp_embed_binary`` specifies the ULP binary name. The name specified here will also be used by other generated artifacts such as the ELF file, map file, header file and linker export file. The second argument specifies the ULP assembly source files. Finally, the third argument specifies the list of component source files which include the header file to be generated. This list is needed to build the dependencies correctly and ensure that the generated header file will be created before any of these files are compiled. See section below for the concept of generated header files for ULP applications.
|
||||
|
||||
3. Build the application as usual (e.g. `idf.py app`)
|
||||
|
||||
Inside, the build system will take the following steps to build ULP program:
|
||||
|
||||
1. **Run each assembly file (foo.S) through C preprocessor.** This step generates the preprocessed assembly files (foo.ulp.S) in the component build directory. This step also generates dependency files (foo.ulp.d).
|
||||
1. **Run each assembly file (foo.S) through the C preprocessor.** This step generates the preprocessed assembly files (foo.ulp.S) in the component build directory. This step also generates dependency files (foo.ulp.d).
|
||||
|
||||
2. **Run preprocessed assembly sources through assembler.** This produces objects (foo.ulp.o) and listing (foo.ulp.lst) files. Listing files are generated for debugging purposes and are not used at later stages of build process.
|
||||
2. **Run preprocessed assembly sources through the assembler.** This produces object (foo.ulp.o) and listing (foo.ulp.lst) files. Listing files are generated for debugging purposes and are not used at later stages of the build process.
|
||||
|
||||
3. **Run linker script template through C preprocessor.** The template is located in components/ulp/ld directory.
|
||||
3. **Run the linker script template through the C preprocessor.** The template is located in ``components/ulp/ld`` directory.
|
||||
|
||||
4. **Link object files into an output ELF file** (ulp_app_name.elf). Map file (ulp_app_name.map) generated at this stage may be useful for debugging purposes.
|
||||
4. **Link the object files into an output ELF file** (``ulp_app_name.elf``). The Map file (``ulp_app_name.map``) generated at this stage may be useful for debugging purposes.
|
||||
|
||||
5. **Dump contents of the ELF file into binary** (ulp_app_name.bin) for embedding into the application.
|
||||
5. **Dump the contents of the ELF file into a binary** (``ulp_app_name.bin``) which can then be embedded into the application.
|
||||
|
||||
6. **Generate list of global symbols** (ulp_app_name.sym) in the ELF file using esp32ulp-elf-nm.
|
||||
6. **Generate a list of global symbols** (``ulp_app_name.sym``) in the ELF file using ``esp32ulp-elf-nm``.
|
||||
|
||||
7. **Create LD export script and header file** (ulp_app_name.ld and ulp_app_name.h) containing the symbols from ulp_app_name.sym. This is done using esp32ulp_mapgen.py utility.
|
||||
7. **Create an LD export script and header file** (``ulp_app_name.ld`` and ``ulp_app_name.h``) containing the symbols from ``ulp_app_name.sym``. This is done using the ``esp32ulp_mapgen.py`` utility.
|
||||
|
||||
8. **Add the generated binary to the list of binary files** to be emedded into the application.
|
||||
8. **Add the generated binary to the list of binary files** to be embedded into the application.
|
||||
|
||||
Accessing ULP program variables
|
||||
-------------------------------
|
||||
Accessing the ULP Program Variables
|
||||
-------------------------------------
|
||||
|
||||
Global symbols defined in the ULP program may be used inside the main program.
|
||||
|
||||
For example, ULP program may define a variable ``measurement_count`` which will define the number of ADC measurements the program needs to make before waking up the chip from deep sleep::
|
||||
For example, the ULP program may define a variable ``measurement_count`` which will define the number of ADC measurements the program needs to make before waking up the chip from deep sleep::
|
||||
|
||||
.global measurement_count
|
||||
measurement_count: .long 0
|
||||
@ -81,19 +77,19 @@ For example, ULP program may define a variable ``measurement_count`` which will
|
||||
move r3, measurement_count
|
||||
ld r3, r3, 0
|
||||
|
||||
Main program needs to initialize this variable before ULP program is started. Build system makes this possible by generating a ``${ULP_APP_NAME}.h`` and ``${ULP_APP_NAME}.ld`` files which define global symbols present in the ULP program. This files include each global symbol defined in the ULP program, prefixed with ``ulp_``.
|
||||
The main program needs to initialize this variable before the ULP program is started. The build system makes this possible by generating the ``${ULP_APP_NAME}.h`` and ``${ULP_APP_NAME}.ld`` files which define the global symbols present in the ULP program. This files include each global symbol defined in the ULP program, prefixed with ``ulp_``.
|
||||
|
||||
The header file contains declaration of the symbol::
|
||||
The header file contains the declaration of the symbol::
|
||||
|
||||
extern uint32_t ulp_measurement_count;
|
||||
|
||||
Note that all symbols (variables, arrays, functions) are declared as ``uint32_t``. For functions and arrays, take address of the symbol and cast to the appropriate type.
|
||||
Note that all symbols (variables, arrays, functions) are declared as ``uint32_t``. For functions and arrays, take the address of the symbol and cast it to the appropriate type.
|
||||
|
||||
The generated linker script file defines locations of symbols in RTC_SLOW_MEM::
|
||||
The generated linker script file defines the locations of symbols in RTC_SLOW_MEM::
|
||||
|
||||
PROVIDE ( ulp_measurement_count = 0x50000060 );
|
||||
|
||||
To access ULP program variables from the main program, include the generated header file and use variables as one normally would::
|
||||
To access the ULP program variables from the main program, include the generated header file and use variables as one normally would::
|
||||
|
||||
#include "ulp_app_name.h"
|
||||
|
||||
@ -102,20 +98,20 @@ To access ULP program variables from the main program, include the generated hea
|
||||
ulp_measurement_count = 64;
|
||||
}
|
||||
|
||||
Note that ULP program can only use lower 16 bits of each 32-bit word in RTC memory, because the registers are 16-bit, and there is no instruction to load from high part of the word.
|
||||
Note that the ULP program can only use lower 16 bits of each 32-bit word in RTC memory, because the registers are 16-bit, and there is no instruction to load from the high part of the word.
|
||||
|
||||
Likewise, ULP store instruction writes register value into the lower 16 bit part of the 32-bit word. Upper 16 bits are written with a value which depends on the address of the store instruction, so when reading variables written by the ULP, main application needs to mask upper 16 bits, e.g.::
|
||||
Likewise, the ULP store instruction writes register value into the lower 16 bits part of the 32-bit word. The upper 16 bits are written with a value which depends on the address of the store instruction, thus when reading variables written by the ULP, the main application needs to mask the upper 16 bits, e.g.::
|
||||
|
||||
printf("Last measurement value: %d\n", ulp_last_measurement & UINT16_MAX);
|
||||
|
||||
Starting the ULP program
|
||||
Starting the ULP Program
|
||||
------------------------
|
||||
|
||||
To run a ULP program, main application needs to load the ULP program into RTC memory using ``ulp_load_binary`` function, and then start it using ``ulp_run`` function.
|
||||
To run a ULP program, the main application needs to load the ULP program into RTC memory using the ``ulp_load_binary`` function, and then start it using the ``ulp_run`` function.
|
||||
|
||||
Note that "Enable Ultra Low Power (ULP) Coprocessor" option must be enabled in menuconfig in order to reserve memory for the ULP. "RTC slow memory reserved for coprocessor" option must be set to a value sufficient to store ULP code and data. If the application components contain multiple ULP programs, then the size of the RTC memory must be sufficient to hold the largest one.
|
||||
Note that "Enable Ultra Low Power (ULP) Coprocessor" option must be enabled in menuconfig to reserve memory for the ULP. "RTC slow memory reserved for coprocessor" option must be set to a value sufficient to store ULP code and data. If the application components contain multiple ULP programs, then the size of the RTC memory must be sufficient to hold the largest one.
|
||||
|
||||
Each ULP program is embedded into the ESP-IDF application as a binary blob. Application can reference this blob and load it in the following way (suppose ULP_APP_NAME was defined to ``ulp_app_name``::
|
||||
Each ULP program is embedded into the ESP-IDF application as a binary blob. The application can reference this blob and load it in the following way (suppose ULP_APP_NAME was defined to ``ulp_app_name``)::
|
||||
|
||||
extern const uint8_t bin_start[] asm("_binary_ulp_app_name_bin_start");
|
||||
extern const uint8_t bin_end[] asm("_binary_ulp_app_name_bin_end");
|
||||
@ -129,13 +125,13 @@ Each ULP program is embedded into the ESP-IDF application as a binary blob. Appl
|
||||
|
||||
.. doxygenfunction:: ulp_load_binary
|
||||
|
||||
Once the program is loaded into RTC memory, application can start it, passing the address of the entry point to ``ulp_run`` function::
|
||||
Once the program is loaded into RTC memory, the application can start it, passing the address of the entry point to the ``ulp_run`` function::
|
||||
|
||||
ESP_ERROR_CHECK( ulp_run(&ulp_entry - RTC_SLOW_MEM) );
|
||||
|
||||
.. doxygenfunction:: ulp_run
|
||||
|
||||
Declaration of the entry point symbol comes from the above mentioned generated header file, ``${ULP_APP_NAME}.h``. In assembly source of the ULP application, this symbol must be marked as ``.global``::
|
||||
Declaration of the entry point symbol comes from the generated header file mentioned above, ``${ULP_APP_NAME}.h``. In the assembly source of the ULP application, this symbol must be marked as ``.global``::
|
||||
|
||||
|
||||
.global entry
|
||||
@ -146,7 +142,7 @@ Declaration of the entry point symbol comes from the above mentioned generated h
|
||||
ULP program flow
|
||||
----------------
|
||||
|
||||
ULP coprocessor is started by a timer. The timer is started once ``ulp_run`` is called. The timer counts a number of RTC_SLOW_CLK ticks (by default, produced by an internal 150kHz RC oscillator). The number of ticks is set using ``SENS_ULP_CP_SLEEP_CYCx_REG`` registers (x = 0..4). When starting the ULP for the first time, ``SENS_ULP_CP_SLEEP_CYC0_REG`` will be used to set the number of timer ticks. Later the ULP program can select another ``SENS_ULP_CP_SLEEP_CYCx_REG`` register using ``sleep`` instruction.
|
||||
ULP coprocessor is started by a timer. The timer is started once ``ulp_run`` is called. The timer counts a number of RTC_SLOW_CLK ticks (by default, produced by an internal 150 kHz RC oscillator). The number of ticks is set using ``SENS_ULP_CP_SLEEP_CYCx_REG`` registers (x = 0..4). When starting the ULP for the first time, ``SENS_ULP_CP_SLEEP_CYC0_REG`` will be used to set the number of timer ticks. Later the ULP program can select another ``SENS_ULP_CP_SLEEP_CYCx_REG`` register using ``sleep`` instruction.
|
||||
|
||||
The application can set ULP timer period values (SENS_ULP_CP_SLEEP_CYCx_REG, x = 0..4) using ``ulp_set_wakeup_period`` function.
|
||||
|
||||
@ -158,5 +154,4 @@ The program runs until it encounters a ``halt`` instruction or an illegal instru
|
||||
|
||||
To disable the timer (effectively preventing the ULP program from running again), clear the ``RTC_CNTL_ULP_CP_SLP_TIMER_EN`` bit in the ``RTC_CNTL_STATE0_REG`` register. This can be done both from ULP code and from the main program.
|
||||
|
||||
|
||||
.. _binutils-esp32ulp toolchain: https://github.com/espressif/binutils-esp32ulp
|
||||
|
@ -4,34 +4,31 @@ Unit Testing in ESP32
|
||||
|
||||
ESP-IDF comes with a unit test app based on Unity - unit test framework. Unit tests are integrated in the ESP-IDF repository and are placed in ``test`` subdirectory of each component respectively.
|
||||
|
||||
Add normal test cases
|
||||
Add Mormal Test Cases
|
||||
---------------------
|
||||
|
||||
Unit tests are added in the ``test`` subdirectory of the respective component.
|
||||
Tests are added in C files, a single C file can include multiple test cases.
|
||||
Test files start with the word "test".
|
||||
Unit tests are added in the ``test`` subdirectory of the respective component. Tests are added in C files, a single C file can include multiple test cases. Test files start with the word "test".
|
||||
|
||||
The test file should include unity.h and the header for the C module to be tested.
|
||||
|
||||
Tests are added in a function in the C file as follows::
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
TEST_CASE("test name", "[module name]"
|
||||
{
|
||||
// Add test here
|
||||
}
|
||||
|
||||
First argument is a descriptive name for the test, second argument is an identifier in square brackets.
|
||||
Identifiers are used to group related test, or tests with specific properties.
|
||||
|
||||
There is no need to add a main function with ``UNITY_BEGIN()`` and ``UNITY_END()`` in each test case.
|
||||
``unity_platform.c`` will run ``UNITY_BEGIN()``, run the tests cases, and then call ``UNITY_END()``.
|
||||
- The first argument is a descriptive name for the test.
|
||||
- The second argument is an identifier in square brackets. Identifiers are used to group related test, or tests with specific properties.
|
||||
|
||||
The ``test`` subdirectory should contain a :ref:`component CMakeLists.txt <component-directories>`, since they are themselves,
|
||||
components. ESP-IDF uses the test framework ``unity`` and should be specified as a requirement for the component. Normally, components
|
||||
:ref:`should list their sources manually <cmake-file-globbing>`; for component tests however, this requirement is relaxed and the
|
||||
use of ``SRC_DIRS`` argument to ``idf_component_register`` is advised.
|
||||
There is no need to add a main function with ``UNITY_BEGIN()`` and ``UNITY_END()`` in each test case. ``unity_platform.c`` will run ``UNITY_BEGIN()``, run the tests cases, and then call ``UNITY_END()``.
|
||||
|
||||
Overall, the minimal ``test`` subdirectory CMakeLists.txt file may look like as follows:
|
||||
The ``test`` subdirectory should contain a :ref:`component CMakeLists.txt <component-directories>`, since they are themselves, components. ESP-IDF uses the ``unity`` test framework and should be specified as a requirement for the component. Normally, components :ref:`should list their sources manually <cmake-file-globbing>`; for component tests however, this requirement is relaxed and the use of the ``SRC_DIRS`` argument in ``idf_component_register`` is advised.
|
||||
|
||||
Overall, the minimal ``test`` subdirectory ``CMakeLists.txt`` file should contain the following:
|
||||
|
||||
.. code:: cmake
|
||||
|
||||
@ -42,13 +39,15 @@ Overall, the minimal ``test`` subdirectory CMakeLists.txt file may look like as
|
||||
See http://www.throwtheswitch.org/unity for more information about writing tests in Unity.
|
||||
|
||||
|
||||
Add multiple devices test cases
|
||||
Add Multi-device Test Cases
|
||||
-------------------------------
|
||||
|
||||
The normal test cases will be executed on one DUT (Device Under Test). Components need to communicate with each other (like GPIO, SPI ...) can't be tested with normal test cases.
|
||||
Multiple devices test cases support writing and running test with multiple DUTs.
|
||||
|
||||
Here's an example of multiple devices test case::
|
||||
The following is an example of a multi-device test case:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
void gpio_master_test()
|
||||
{
|
||||
@ -74,13 +73,13 @@ Here's an example of multiple devices test case::
|
||||
|
||||
TEST_CASE_MULTIPLE_DEVICES("gpio multiple devices test example", "[driver]", gpio_master_test, gpio_slave_test);
|
||||
|
||||
The macro ``TEST_CASE_MULTIPLE_DEVICES`` is used to declare a multi-device test case.
|
||||
|
||||
The macro ``TEST_CASE_MULTIPLE_DEVICES`` is used to declare multiple devices test cases.
|
||||
First argument is test case name, second argument is test case description.
|
||||
From the third argument, upto 5 test functions can be defined, each function will be the entry point of tests running on each DUT.
|
||||
- The first argument is test case name.
|
||||
- The second argument is test case description.
|
||||
- From the third argument, up to 5 test functions can be defined, each function will be the entry point of tests running on each DUT.
|
||||
|
||||
Running test cases from different DUTs could require synchronizing between DUTs. We provide ``unity_wait_for_signal`` and ``unity_send_signal`` to support synchronizing with UART.
|
||||
As the secnario in the above example, slave should get GPIO level after master set level. DUT UART console will prompt and requires user interaction:
|
||||
Running test cases from different DUTs could require synchronizing between DUTs. We provide ``unity_wait_for_signal`` and ``unity_send_signal`` to support synchronizing with UART. As the scenario in the above example, the slave should get GPIO level after master set level. DUT UART console will prompt and user interaction is required:
|
||||
|
||||
DUT1 (master) console::
|
||||
|
||||
@ -91,15 +90,13 @@ DUT2 (slave) console::
|
||||
|
||||
Send signal: [output high level]!
|
||||
|
||||
Once the signal is set from DUT2, you need to press "Enter" on DUT1, then DUT1 unblocks from ``unity_wait_for_signal`` and starts to change GPIO level.
|
||||
Once the signal is sent from DUT2, you need to press "Enter" on DUT1, then DUT1 unblocks from ``unity_wait_for_signal`` and starts to change GPIO level.
|
||||
|
||||
|
||||
Add multiple stages test cases
|
||||
Add Multi-stage Test Cases
|
||||
-------------------------------
|
||||
|
||||
The normal test cases are expected to finish without reset (or only need to check if reset happens). Sometimes we want to run some specific test after certain kinds of reset.
|
||||
For example, we want to test if reset reason is correct after wakeup from deep sleep. We need to create deep sleep reset first and then check the reset reason.
|
||||
To support this, we can define multiple stages test case, to group a set of test functions together::
|
||||
The normal test cases are expected to finish without reset (or only need to check if reset happens). Sometimes we expect to run some specific tests after certain kinds of reset. For example, we expect to test if the reset reason is correct after a wakeup from deep sleep. We need to create a deep-sleep reset first and then check the reset reason. To support this, we can define multi-stage test cases, to group a set of test functions::
|
||||
|
||||
static void trigger_deepsleep(void)
|
||||
{
|
||||
@ -118,19 +115,17 @@ To support this, we can define multiple stages test case, to group a set of test
|
||||
Multiple stages test cases present a group of test functions to users. It need user interactions (select case and select different stages) to run the case.
|
||||
|
||||
|
||||
Building unit test app
|
||||
Building Unit Test App
|
||||
----------------------
|
||||
|
||||
Follow the setup instructions in the top-level esp-idf README.
|
||||
Make sure that IDF_PATH environment variable is set to point to the path of esp-idf top-level directory.
|
||||
Follow the setup instructions in the top-level esp-idf README. Make sure that ``IDF_PATH`` environment variable is set to point to the path of esp-idf top-level directory.
|
||||
|
||||
Change into tools/unit-test-app directory to configure and build it:
|
||||
Change into ``tools/unit-test-app`` directory to configure and build it:
|
||||
|
||||
* `idf.py menuconfig` - configure unit test app.
|
||||
|
||||
* `idf.py -T all build` - build unit test app with tests for each component having tests in the ``test`` subdirectory.
|
||||
* `idf.py -T "xxx yyy" build` - build unit test app with tests for some space-separated specific components (For instance: ``idf.py -T heap build`` - build unit tests only for ``heap`` component directory).
|
||||
* `idf.py -T all -E "xxx yyy" build` - build unit test app with all unit tests, except for unit tests of some components (For instance: ``idf.py -T all -E "ulp mbedtls" build`` - build all unit tests exludes ``ulp`` and ``mbedtls`` components).
|
||||
* ``idf.py menuconfig`` - configure unit test app.
|
||||
* ``idf.py -T all build`` - build unit test app with tests for each component having tests in the ``test`` subdirectory.
|
||||
* ``idf.py -T "xxx yyy" build`` - build unit test app with tests for some space-separated specific components (For instance: ``idf.py -T heap build`` - build unit tests only for ``heap`` component directory).
|
||||
* ``idf.py -T all -E "xxx yyy" build`` - build unit test app with all unit tests, except for unit tests of some components (For instance: ``idf.py -T all -E "ulp mbedtls" build`` - build all unit tests exludes ``ulp`` and ``mbedtls`` components).
|
||||
|
||||
When the build finishes, it will print instructions for flashing the chip. You can simply run ``idf.py flash`` to flash all build output.
|
||||
|
||||
@ -138,7 +133,7 @@ You can also run ``idf.py -T all flash`` or ``idf.py -T xxx flash`` to build and
|
||||
|
||||
Use menuconfig to set the serial port for flashing.
|
||||
|
||||
Running unit tests
|
||||
Running Unit Tests
|
||||
------------------
|
||||
|
||||
After flashing reset the ESP32 and it will boot the unit test app.
|
||||
@ -171,7 +166,7 @@ When unit test app is idle, press "Enter" will make it print test menu with all
|
||||
(1) "trigger_deepsleep"
|
||||
(2) "check_deepsleep_reset_reason"
|
||||
|
||||
Normal case will print the case name and description. Master slave cases will also print the sub-menu (the registered test function names).
|
||||
The normal case will print the case name and description. Master-slave cases will also print the sub-menu (the registered test function names).
|
||||
|
||||
Test cases can be run by inputting one of the following:
|
||||
|
||||
@ -183,25 +178,22 @@ Test cases can be run by inputting one of the following:
|
||||
|
||||
- An asterisk to run all test cases
|
||||
|
||||
``[multi_device]`` and ``[multi_stage]`` tags tell the test runner whether a test case is a multiple devices or multiple stages test case.
|
||||
These tags are automatically added by ```TEST_CASE_MULTIPLE_STAGES`` and ``TEST_CASE_MULTIPLE_DEVICES`` macros.
|
||||
``[multi_device]`` and ``[multi_stage]`` tags tell the test runner whether a test case is a multiple devices or multiple stages of test case. These tags are automatically added by ```TEST_CASE_MULTIPLE_STAGES`` and ``TEST_CASE_MULTIPLE_DEVICES`` macros.
|
||||
|
||||
After you select a multiple devices test case, it will print sub menu::
|
||||
After you select a multi-device test case, it will print sub-menu::
|
||||
|
||||
Running gpio master/slave test example...
|
||||
gpio master/slave test example
|
||||
(1) "gpio_master_test"
|
||||
(2) "gpio_slave_test"
|
||||
|
||||
You need to input number to select the test running on the DUT.
|
||||
You need to input a number to select the test running on the DUT.
|
||||
|
||||
Similar to multiple devices test cases, multiple stages test cases will also print sub menu::
|
||||
Similar to multi-device test cases, multi-stage test cases will also print sub-menu::
|
||||
|
||||
Running reset reason check for deepsleep...
|
||||
reset reason check for deepsleep
|
||||
(1) "trigger_deepsleep"
|
||||
(2) "check_deepsleep_reset_reason"
|
||||
|
||||
First time you execute this case, input ``1`` to run first stage (trigger deepsleep).
|
||||
After DUT is rebooted and able to run test cases, select this case again and input ``2`` to run the second stage.
|
||||
The case only passes if the last stage passes and all previous stages trigger reset.
|
||||
First time you execute this case, input ``1`` to run first stage (trigger deepsleep). After DUT is rebooted and able to run test cases, select this case again and input ``2`` to run the second stage. The case only passes if the last stage passes and all previous stages trigger reset.
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -11,36 +11,63 @@ IDF 监视器是一个串行终端程序,用于收发目标设备串口的串
|
||||
- **若使用 CMake 编译系统,则请调用**:``idf.py monitor``
|
||||
- **若使用传统 GNU Make 编译系统,请调用**:``make monitor``
|
||||
|
||||
|
||||
|
||||
操作快捷键
|
||||
==================
|
||||
|
||||
为了方便与 IDF 监视器进行交互,请使用表中给出的快捷键。
|
||||
|
||||
=================== ======================================================================== =======================================================================================================================================================================================
|
||||
快捷键 操作 描述
|
||||
=================== ======================================================================== =======================================================================================================================================================================================
|
||||
Ctrl+] 退出监视器程序
|
||||
Ctrl+T 菜单退出键 按下如下给出的任意键,并按指示操作。
|
||||
- Ctrl+T 将菜单字符发送至远程
|
||||
- Ctrl+] 将 exit 字符发送至远程
|
||||
- Ctrl+P 重置目标设备,进入 Bootloader,通过 RTS 线暂停应用程序 重置目标设备,通过 RTS 线(如已连接)进入 Bootloader,此时开发板不运行任何程序。等待其他设备启动时可以使用此操作。
|
||||
- Ctrl+R 通过 RTS 线重置目标设备 重置设备,并通过 RTS 线(如已连接)重新启动应用程序。
|
||||
- Ctrl+F 编译并烧录此项目 暂停 idf_monitor,运行 ``idf.py flash`` 目标,然后恢复 idf_monitor。任何改动的源文件都会被重新编译,然后重新烧录。
|
||||
- Ctrl+A (A) 仅编译及烧录应用程序 暂停 idf_monitor,运行 ``app-flash`` 目标,然后恢复 idf_monitor。 这与 ``flash`` 类似,但只有主应用程序被编译并被重新烧录。
|
||||
- Ctrl+Y 停止/恢复日志输出在屏幕上打印 激活时,会丢弃所有传入的串行数据。允许在不退出监视器的情况下快速暂停和检查日志输出。
|
||||
- Ctrl+L 停止/恢复向文件写入日志输出 在工程目录下创建一个文件,用于写入日志输出。可使用快捷键停止/恢复该功能(退出 IDF 监视器也会终止该功能)
|
||||
- Ctrl+H (H) 显示所有快捷键
|
||||
=================== ======================================================================== =======================================================================================================================================================================================
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
:widths: 15 25 55
|
||||
|
||||
* - 快捷键
|
||||
- 操作
|
||||
- 描述
|
||||
* - Ctrl+]
|
||||
- 退出监视器程序
|
||||
-
|
||||
* - Ctrl+T
|
||||
- 菜单退出键
|
||||
- 按下如下给出的任意键之一,并按指示操作。
|
||||
* - * Ctrl+T
|
||||
- 将菜单字符发送至远程
|
||||
-
|
||||
* - * Ctrl+]
|
||||
- 将 exit 字符发送至远程
|
||||
-
|
||||
* - * Ctrl+P
|
||||
- 重置目标设备,进入 Bootloader,通过 RTS 线暂停应用程序
|
||||
- 重置目标设备,通过 RTS 线(如已连接)进入 Bootloader,此时开发板不运行任何程序。等待其他设备启动时可以使用此操作。
|
||||
* - * Ctrl+R
|
||||
- 通过 RTS 线重置目标设备
|
||||
- 重置设备,并通过 RTS 线(如已连接)重新启动应用程序。
|
||||
* - * Ctrl+F
|
||||
- 编译并烧录此项目
|
||||
- 暂停 idf_monitor,运行 ``flash`` 目标,然后恢复 idf_monitor。任何改动的源文件都会被重新编译,然后重新烧录。如果 idf_monitor 是以参数 ``-E`` 启动的,则会运行目标 ``encrypted-flash``。
|
||||
* - * Ctrl+A (或者 A)
|
||||
- 仅编译及烧录应用程序
|
||||
- 暂停 idf_monitor,运行 ``app-flash`` 目标,然后恢复 idf_monitor。 这与 ``flash`` 类似,但只有主应用程序被编译并被重新烧录。如果 idf_monitor 是以参数 ``-E`` 启动的,则会运行目标 ``encrypted-flash``。
|
||||
* - * Ctrl+Y
|
||||
- 停止/恢复在屏幕上打印日志输出
|
||||
- 激活时,会丢弃所有传入的串行数据。允许在不退出监视器的情况下快速暂停和检查日志输出。
|
||||
* - * Ctrl+L
|
||||
- 停止/恢复向文件写入日志输出
|
||||
- 在工程目录下创建一个文件,用于写入日志输出。可使用快捷键停止/恢复该功能(退出 IDF 监视器也会终止该功能)
|
||||
* - * Ctrl+H (或者 H)
|
||||
- 显示所有快捷键
|
||||
-
|
||||
* - * Ctrl+X (或者 X)
|
||||
- 退出监视器程序
|
||||
-
|
||||
|
||||
除了 ``Ctrl-]`` 和 ``Ctrl-T``,其他快捷键信号会通过串口发送到目标设备。
|
||||
|
||||
|
||||
兼具 IDF 特性
|
||||
=====================
|
||||
|
||||
自动解码地址
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
ESP-IDF 输出形式为 ``0x4_______`` 的十六进制代码地址后,IDF 监视器将使用 addr2line_ 查找该地址在源代码中的位置和对应的函数名。
|
||||
|
||||
@ -104,30 +131,30 @@ IDF 监控器在后台运行如下命令::
|
||||
输出筛选
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
IDF 监视器有两种启用方式:运行 ``idf.py monitor PRINT_FILTER=""`` (适用于 CMake) 或者 ``make monitor PRINT_FILTER=""`` (适用于传统 GNU Make),其中,``--print-filter`` 是输出筛选的参数。参数默认值为空字符串,可打印任何内容。
|
||||
可以调用 ``idf.py monitor --print-filter="xyz"`` 启动 IDF 监视器,其中,``--print-filter`` 是输出筛选的参数。参数默认值为空字符串,可打印任何内容。
|
||||
|
||||
若需对打印内容设置限制,可指定 ``<tag>:<log_level>`` 等选项,其中 ``<tag>`` 是标签字符串,``<log_level>`` 是 ``{N, E, W, I, D, V, *}`` 集合中的一个字母,指的是 :doc:`日志 <../../api-reference/system/log>` 级别。
|
||||
|
||||
例如,``PRINT_FILTER="tag1:W"`` 只匹配并打印 ``ESP_LOGW("tag1", ...)`` 所写的输出,或者写在较低冗余级别的输出,即 ``ESP_LOGE("tag1", ...)``。请勿指定 ``<log_level>`` 或使用冗余级别默认值 ``*``。
|
||||
例如,``PRINT_FILTER="tag1:W"`` 只匹配并打印 ``ESP_LOGW("tag1", ...)`` 所写的输出,或者写在较低日志详细度级别的输出,即 ``ESP_LOGE("tag1", ...)``。请勿指定 ``<log_level>`` 或使用详细级别默认值 ``*``。
|
||||
|
||||
.. note::
|
||||
编译时,可以使用主日志在 :doc:`日志库 <../../api-reference/system/log>` 中禁用不需要的输出。也可以使用 IDF 监视器筛选输出来调整筛选设置,且无需重新编译应用程序。
|
||||
|
||||
应用程序标签不能包含空格、星号 ``*``、分号 ``:``,以便兼容输出筛选功能。
|
||||
应用程序标签不能包含空格、星号 ``*``、冒号 ``:``,以便兼容输出筛选功能。
|
||||
|
||||
如果应用程序输出的最后一行后面没有回车,可能会影响输出筛选功能,即,监视器开始打印该行,但后来发现该行不应该被写入。这是一个已知问题,可以通过添加回车来避免此问题(特别是在没有输出紧跟其后的情况下)。
|
||||
|
||||
筛选规则示例
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
- ``*`` 可用于匹配任何类型标签。但 ``PRINT_FILTER="*:I tag1:E"`` 打印关于 ``tag1`` 的输出时会报错,这是因为 ``tag1`` 规则比 ``*`` 规则的优先级高。
|
||||
- 默认规则(空)等价于 ``*:V``,因为在冗余级别或更低级别匹配任意标签即意味匹配所有内容。
|
||||
- 默认规则(空)等价于 ``*:V``,因为在详细级别或更低级别匹配任意标签即意味匹配所有内容。
|
||||
- ``"*:N"`` 不仅抑制了日志功能的输出,也抑制了 ``printf`` 的打印输出。为了避免这一问题,请使用 ``*:E`` 或更高的冗余级别。
|
||||
- 规则 ``"tag1:V"``、``"tag1:v"``、``"tag1:"``、``"tag1:*"`` 和 ``"tag1"`` 等同。
|
||||
- 规则 ``"tag1:W tag1:E"`` 等同于 ``"tag1:E"``,这是因为后续出现的具有相同名称的标签会覆盖掉前一个标签。
|
||||
- 规则 ``"tag1:I tag2:W"`` 仅在 Info 冗余级别或更低级别打印 ``tag1``,在 Warning 冗余级别或更低级别打印 ``tag2``。
|
||||
- 规则 ``"tag1:I tag2:W"`` 仅在 Info 详细度级别或更低级别打印 ``tag1``,在 Warning 详细度级别或更低级别打印 ``tag2``。
|
||||
- 规则 ``"tag1:I tag2:W tag3:N"`` 在本质上等同于上一规则,这是因为 ``tag3:N`` 指定 ``tag3`` 不打印。
|
||||
- ``tag3:N`` 在规则 ``"tag1:I tag2:W tag3:N *:V"`` 中更有意义,这是因为如果没有 ``tag3:N``,``tag3`` 信息就可能打印出来了;``tag1`` 和 ``tag2`` 错误信息会打印在指定的冗余级别(或更低级别),并默认打印所有内容。
|
||||
- ``tag3:N`` 在规则 ``"tag1:I tag2:W tag3:N *:V"`` 中更有意义,这是因为如果没有 ``tag3:N``,``tag3`` 信息就可能打印出来了;``tag1`` 和 ``tag2`` 错误信息会打印在指定的详细度级别(或更低级别),并默认打印所有内容。
|
||||
|
||||
|
||||
高级筛选规则示例
|
||||
|
@ -10,7 +10,7 @@ ULP 协处理器编程
|
||||
使用宏进行编程(遗留) <ulp_macros>
|
||||
|
||||
|
||||
ULP(Ultra Low Power 超低功耗)协处理器是一种简单的有限状态机 (FSM),可以在主处理器处于深度睡眠模式时,使用 ADC、温度传感器和外部 I2C 传感器执行测量操作。ULP 协处理器可以访问 RTC_SLOW_MEM 内存区域及 RTC_CNTL、RTC_IO、SARADC 等外设寄存器。ULP 协处理器使用 32 位固定宽度的指令,32 位内存寻址,配备 4 个 16 位通用寄存器。
|
||||
ULP(Ultra Low Power 超低功耗)协处理器是一种简单的有限状态机 (FSM),可以在主处理器处于深度睡眠模式时,使用 ADC、温度传感器和外部 I2C 传感器执行测量操作。ULP 协处理器可以访问 RTC_SLOW_MEM 内存区域及 RTC_CNTL、RTC_IO、SARADC 外设中的寄存器。ULP 协处理器使用 32 位固定宽度的指令,32 位内存寻址,配备 4 个 16 位通用寄存器。
|
||||
|
||||
安装工具链
|
||||
----------
|
||||
@ -19,56 +19,47 @@ ULP 协处理器代码是用汇编语言编写的,并使用 `binutils-esp32ulp
|
||||
|
||||
如果你已经按照 :doc:`快速入门指南 <../../get-started/index>` 中的介绍安装好了 ESP-IDF 及其 CMake 构建系统,那么 ULP 工具链已经被默认安装到了你的开发环境中。
|
||||
|
||||
如果你的 ESP-IDF 仍在使用旧版本的基于 GNU Make 的构建系统,请参考 :doc:`ulp-legacy` 一文中的说明,完成工具链的安装。
|
||||
|
||||
如果你的 ESP-IDF 仍在使用传统的基于 GNU Make 的构建系统,请参考 :doc:`ulp-legacy` 一文中的说明,完成工具链的安装。
|
||||
|
||||
编译 ULP 代码
|
||||
-------------
|
||||
|
||||
若需要将 ULP 代码编译为某组件的一部分,则必须执行以下步骤:
|
||||
|
||||
1. 用汇编语言编写的 ULP 代码必须导入到一个或多个 .S 扩展文件中,且这些文件必须放在组件目录中一个独立的目录中,例如 `ulp/`。
|
||||
1. 用汇编语言编写的 ULP 代码必须导入到一个或多个 `.S` 扩展文件中,且这些文件必须放在组件目录中一个独立的目录中,例如 `ulp/`。
|
||||
|
||||
.. note:
|
||||
该目录不要添加到 ``COMPONENT_SRCDIRS`` 环境变量中。因为 ESP-IDF 构建系统将基于文件扩展名编译在 ``COMPONENT_SRCDIRS`` 中搜索到的文件。对于 ``.S`` 文件,使用的是 ``xtensa-esp32-elf-as`` 汇编器。但这并不适用于 ULP 程序集文件,因此体现这种区别的最简单方法就是将 ULP 程序集文件放到单独的目录中。同样,ULP 程序集源文件也不应该添加到 ``COMPONENT_SRCS`` 中。请参考如下步骤,查看如何正确添加 ULP 程序集源文件。
|
||||
.. note: 在注册组件(通过 ``idf_component_register``)时,不应将该目录添加到 ``SRC_DIRS`` 参数中。因为 ESP-IDF 构建系统将基于文件扩展名编译在 ``SRC_DIRS`` 中搜索到的文件。对于 ``.S`` 文件,使用的是 ``xtensa-esp32-elf-as`` 汇编器。但这并不适用于 ULP 程序集文件,因此体现这种区别最简单的方式就是将 ULP 程序集文件放到单独的目录中。同样,ULP 程序集源文件也 **不应该** 添加到 ``SRCS`` 中。请参考如下步骤,查看如何正确添加 ULP 程序集源文件。
|
||||
|
||||
2. 修改组件 CMakeLists.txt,添加必要的 ULP CMake 定义,示例如下::
|
||||
2. 注册后从组件 CMakeLists.txt 中调用 ``ulp_embed_binary`` 示例如下::
|
||||
|
||||
set(ULP_APP_NAME ulp_${COMPONENT_NAME})
|
||||
set(ULP_S_SOURCES ulp/ulp_assembly_source_file.S)
|
||||
set(ULP_EXP_DEP_SRCS "ulp_c_source_file.c")
|
||||
include(${IDF_PATH}/components/ulp/component_ulp_common.cmake)
|
||||
...
|
||||
idf_component_register()
|
||||
|
||||
代码解释如下:
|
||||
|
||||
``set(ULP_APP_NAME ulp_${COMPONENT_NAME})``
|
||||
为生成的 ULP 应用程序设置名称,不带扩展名。此名称用于 ULP 应用程序的构建输出:ELF 文件、.map 文件、二进制文件、生成的头文件和链接器导出文件。
|
||||
set(ulp_app_name ulp_${COMPONENT_NAME})
|
||||
set(ulp_s_sources ulp/ulp_assembly_source_file.S)
|
||||
set(ulp_exp_dep_srcs "ulp_c_source_file.c")
|
||||
|
||||
ulp_embed_binary(${ulp_app_name} "${ulp_s_sources}" "${ulp_exp_dep_srcs}")
|
||||
|
||||
``set(ULP_EXP_DEP_SRCS "ulp_c_source_file_1.c ulp_c_source_file_2.c")``
|
||||
设置组件中源文件名称的列表。所有包含被生成的头文件的原文件都必须在列表里。此列表建立正确构建依赖项,并确保在构建过程会先生成才编译包含头文件的原文件。请参考下文,查看为 ULP 应用程序生成的头文件等相关概念。此列表需要用空格隔开,路径可以是组件 CMakeLists.txt 文件的相对路径,也可以是绝对路径。
|
||||
|
||||
``include(${IDF_PATH}/components/ulp/component_ulp_common.cmake)``
|
||||
包含 ULP 编译步骤的通用定义。使用 ULP 工具链为 ULP 目标文件、ELF 文件、二进制文件等设置编译规则。
|
||||
``ulp_embed_binary`` 的第一个参数为 ULP 二进制文件命名。指定的此名称也用于生成的其他文件,如:ELF 文件、.map 文件、头文件和链接器导出文件。第二个参数指定 ULP 程序集源文件。最后,第三个参数指定组件源文件列表,其中包括被生成的头文件。此列表用以建立正确的依赖项,并确保在编译这些文件之前先创建生成的头文件。有关 ULP 应用程序生成的头文件等相关概念,请参考下文。
|
||||
|
||||
3. 使用常规方法(例如 `idf.py app`)编译应用程序
|
||||
|
||||
在内部,编译系统将按照以下步骤编译 ULP 程序:
|
||||
在内部,构建系统将按照以下步骤编译 ULP 程序:
|
||||
|
||||
1. **通过 C 预处理器运行每个程序集文件 (foo.S)。** 此步骤在组件编译目录中生成预处理的程序集文件 (foo.ulp.S),同时生成依赖文件 (foo.ulp.d)。
|
||||
|
||||
2. **通过汇编器运行预处理过的汇编源码。** 此步骤会生成目标文件 (foo.ulp.o) 和清单 (foo.ulp.lst)。清单文件仅用于调试,不用于编译进程的后续步骤。
|
||||
|
||||
3. **通过 C 预处理器运行链接器脚本模板。** 模板位于 components/ulp/ld 目录中。
|
||||
3. **通过 C 预处理器运行链接器脚本模板。** 模板位于 ``components/ulp/ld`` 目录中。
|
||||
|
||||
4. **将目标文件链接到 ELF 输出文件** (ulp_app_name.elf)。此步骤生成的.map 文件 (ulp_app_name.map) 默认用于调试。
|
||||
4. **将目标文件链接到 ELF 输出文件** (``ulp_app_name.elf``)。此步骤生成的.map 文件 (``ulp_app_name.map``) 默认用于调试。
|
||||
|
||||
5. **将 ELF 文件中的内容转储为二进制文件** (ulp_app_name.bin),以便嵌入到应用程序中。
|
||||
5. **将 ELF 文件中的内容转储为二进制文件** (``ulp_app_name.bin``),以便嵌入到应用程序中。
|
||||
|
||||
6. **使用 esp32ulp-elf-nm 在 ELF 文件中生成全局符号列表** (ulp_app_name.sym)。
|
||||
6. 使用 ``esp32ulp-elf-nm`` 在 ELF 文件中 **生成全局符号列表** (``ulp_app_name.sym``)。
|
||||
|
||||
7. **创建 LD 导出脚本和头文件** (ulp_app_name.ld 和 ulp_app_name.h),包含来自 ulp_app_name.sym 的符号。此步骤可借助 esp32ulp_mapgen.py 工具来完成。
|
||||
7. **创建 LD 导出脚本和头文件** (``ulp_app_name.ld`` 和 ``ulp_app_name.h``),包含来自 ``ulp_app_name.sym`` 的符号。此步骤可借助 ``esp32ulp_mapgen.py`` 工具来完成。
|
||||
|
||||
8. **将生成的二进制文件添加到要嵌入应用程序的二进制文件列表中。**
|
||||
|
||||
@ -86,7 +77,7 @@ ULP 协处理器代码是用汇编语言编写的,并使用 `binutils-esp32ulp
|
||||
move r3, measurement_count
|
||||
ld r3, r3, 0
|
||||
|
||||
主程序需要在启动 ULP 程序之前初始化 ``measurement_count`` 变量,编译系统生成 ``${ULP_APP_NAME}.h`` 和 ``${ULP_APP_NAME}.ld`` 文件可以实现上述操作,这些文件在 ULP 编程中定义了全局符号,包含了在 ULP 程序中定义的所有全局符号,前缀为 ``ulp_``。
|
||||
主程序需要在启动 ULP 程序之前初始化 ``measurement_count`` 变量,构建系统通过生成定义 ULP 编程中全局符号的 ``${ULP_APP_NAME}.h`` 和 ``${ULP_APP_NAME}.ld`` 文件实现上述操作。这些文件包含了在 ULP 程序中定义的所有全局符号,文件以 ``ulp_`` 开头。
|
||||
|
||||
头文件包含对此类符号的声明::
|
||||
|
||||
@ -120,7 +111,7 @@ ULP 协处理器代码是用汇编语言编写的,并使用 `binutils-esp32ulp
|
||||
|
||||
注意,在 menuconfig 中必须启用 "Enable Ultra Low Power (ULP) Coprocessor" 选项,以便为 ULP 预留内存。"RTC slow memory reserved for coprocessor" 选项设置的值必须足够储存 ULP 代码和数据。如果应用程序组件包含多个 ULP 程序,则 RTC 内存必须足以容纳最大的程序。
|
||||
|
||||
每个 ULP 程序均以二进制 BLOB 的形式嵌入到 ESP-IDF 应用程序中。应用程序可以引用此 BLOB,并以下面的方式加载此 BLOB (假设 ULP_APP_NAME 已被定义为 ``ulp_app_name``)::
|
||||
每个 ULP 程序均以二进制 BLOB 的形式嵌入到 ESP-IDF 应用程序中。应用程序可以引用此 BLOB,并以下面的方式加载此 BLOB(假设 ULP_APP_NAME 已被定义为 ``ulp_app_name``)::
|
||||
|
||||
extern const uint8_t bin_start[] asm("_binary_ulp_app_name_bin_start");
|
||||
extern const uint8_t bin_end[] asm("_binary_ulp_app_name_bin_end");
|
||||
@ -149,19 +140,18 @@ ULP 协处理器代码是用汇编语言编写的,并使用 `binutils-esp32ulp
|
||||
|
||||
|
||||
ULP 程序流
|
||||
----------
|
||||
--------------
|
||||
|
||||
ULP 协处理器由定时器启动,而调用 ``ulp_run`` 则可启动此定时器。定时器为 RTC_SLOW_CLK 的 Tick 事件计数(默认情况下,Tick 由内部 150 KHz 晶振器生成)。使用 ``SENS_ULP_CP_SLEEP_CYCx_REG`` 寄存器 (x = 0..4) 设置 Tick 数值。第一次启动 ULP 时,使用 ``SENS_ULP_CP_SLEEP_CYC0_REG`` 设置定时器 Tick 数值,之后,ULP 程序可以使用 ``sleep`` 指令来另外选择 ``SENS_ULP_CP_SLEEP_CYCx_REG`` 寄存器。
|
||||
ULP 协处理器由定时器启动,而调用 ``ulp_run`` 则可启动此定时器。定时器为 RTC_SLOW_CLK 的 Tick 事件计数(默认情况下,Tick 由内部 150 KHz RC 振荡器生成)。使用 ``SENS_ULP_CP_SLEEP_CYCx_REG`` 寄存器 (x = 0..4) 设置 Tick 数值。第一次启动 ULP 时,使用 ``SENS_ULP_CP_SLEEP_CYC0_REG`` 设置定时器 Tick 数值,之后,ULP 程序可以使用 ``sleep`` 指令来选择另一个 ``SENS_ULP_CP_SLEEP_CYCx_REG`` 寄存器。
|
||||
|
||||
此应用程序可以调用 ``ulp_set_wakeup_period`` 函数来设置 ULP 定时器周期值 (SENS_ULP_CP_SLEEP_CYCx_REG, x = 0..4)。
|
||||
|
||||
.. doxygenfunction:: ulp_set_wakeup_period
|
||||
|
||||
一旦定时器达到在所选的 ``SENS_ULP_CP_SLEEP_CYCx_REG`` 寄存器中设置的数值,ULP 协处理器就会启动,并调用 ``ulp_run`` 的入口点开始运行程序。
|
||||
一旦定时器计数到 ``SENS_ULP_CP_SLEEP_CYCx_REG`` 寄存器设定的 Tick 数值,ULP 协处理器就会启动,并调用 ``ulp_run`` 的入口点开始运行程序。
|
||||
|
||||
程序保持运行,直到遇到 ``halt`` 指令或非法指令。一旦程序停止,ULP 协处理器电源关闭,定时器再次启动。
|
||||
|
||||
如果想禁用定时器(有效防止 ULP 程序再次运行),请清除 ``RTC_CNTL_STATE0_REG`` 寄存器中的 ``RTC_CNTL_ULP_CP_SLP_TIMER_EN`` 位,可在 ULP 代码或主程序中进行以上操作。
|
||||
|
||||
如果想禁用定时器(有效防止 ULP 程序再次运行),可在 ULP 代码或主程序中清除 ``RTC_CNTL_STATE0_REG`` 寄存器中的 ``RTC_CNTL_ULP_CP_SLP_TIMER_EN`` 位。
|
||||
|
||||
.. _binutils-esp32ulp 工具链: https://github.com/espressif/binutils-esp32ulp
|
||||
|
@ -2,18 +2,14 @@ ESP32 中的单元测试
|
||||
==========================
|
||||
:link_to_translation:`en:[English]`
|
||||
|
||||
ESP-IDF
|
||||
中附带了一个基于 ``Unity`` 的单元测试应用程序框架,且所有的单元测试用例分别保存在
|
||||
ESP-IDF 仓库中每个组件的 ``test`` 子目录中。
|
||||
ESP-IDF 中附带了一个基于 ``Unity`` 的单元测试应用程序框架,且所有的单元测试用例分别保存在 ESP-IDF 仓库中每个组件的 ``test`` 子目录中。
|
||||
|
||||
添加常规测试用例
|
||||
----------------
|
||||
|
||||
单元测试被添加在相应组件的 ``test`` 子目录中,测试用例写在 C 文件中,一个
|
||||
C 文件可以包含多个测试用例。测试文件的名字要以 “test” 开头。
|
||||
单元测试被添加在相应组件的 ``test`` 子目录中,测试用例写在 C 文件中,一个 C 文件可以包含多个测试用例。测试文件的名字要以 “test” 开头。
|
||||
|
||||
测试文件需要包含 ``unity.h`` 头文件,此外还需要包含待测试 C
|
||||
模块需要的头文件。
|
||||
测试文件需要包含 ``unity.h`` 头文件,此外还需要包含待测试 C 模块需要的头文件。
|
||||
|
||||
测试用例需要通过 C 文件中特定的函数来添加,如下所示:
|
||||
|
||||
@ -24,43 +20,34 @@ C 文件可以包含多个测试用例。测试文件的名字要以 “test”
|
||||
// 在这里添加测试用例
|
||||
}
|
||||
|
||||
- 第一个参数是字符串,用来描述当前测试。
|
||||
|
||||
- 第二个参数是字符串,用方括号中的标识符来表示,标识符用来对相关测试或具有特定属性的测试进行分组。
|
||||
- 第一个参数是此测试的描述性名称。
|
||||
- 第二个参数用方括号中的标识符来表示,标识符用来对相关测试或具有特定属性的测试进行分组。
|
||||
|
||||
没有必要在每个测试用例中使用 ``UNITY_BEGIN()`` 和 ``UNITY_END()``
|
||||
来声明主函数的区域, ``unity_platform.c`` 会自动调用
|
||||
``UNITY_BEGIN()``\ , 然后运行测试用例,最后调用 ``UNITY_END()``\ 。
|
||||
没有必要在每个测试用例中使用 ``UNITY_BEGIN()`` 和 ``UNITY_END()`` 来声明主函数的区域,``unity_platform.c`` 会自动调用 ``UNITY_BEGIN()``, 然后运行测试用例,最后调用 ``UNITY_END()``。
|
||||
|
||||
``test`` 子目录需要包含 :ref:`组件 CMakeLists.txt <component-directories>`,因为他们本身就是一种组件。ESP-IDF 使用了
|
||||
``unity`` 测试框架,需要将其指定为组件的依赖项。通常,组件
|
||||
:ref:`需要手动指定待编译的源文件 <cmake-file-globbing>`;但是,对于测试组件来说,这个要求被放宽了,仅仅是建议使用 “COMPONENT_SRCDIRS”。
|
||||
``test`` 子目录应包含 :ref: `组件 CMakeLists.txt <component-directories>`,因为他们本身就是一种组件。ESP-IDF 使用了 ``unity`` 测试框架,需要将其指定为组件的依赖项。通常,组件 :ref: `需要手动指定待编译的源文件 <cmake-file-globbing>;但是,对于测试组件来说,这个要求被放宽为仅建议将参数 ``SRC_DIRS`` 用于 ``idf_component_register``。
|
||||
|
||||
总的来说,``test`` 子目录下最简单的 CMakeLists.txt 文件可能如下所示:
|
||||
总的来说,``test`` 子目录下最小的 CMakeLists.txt 文件可能如下所示:
|
||||
|
||||
.. code:: cmake
|
||||
|
||||
set(COMPONENT_SRCDIRS ".")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||
set(COMPONENT_REQUIRES unity)
|
||||
idf_component_register(SRC_DIRS "."
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES unity)
|
||||
|
||||
register_component()
|
||||
|
||||
更多关于如何在 Unity 下编写测试用例的信息,请查阅
|
||||
http://www.throwtheswitch.org/unity 。
|
||||
更多关于如何在 Unity 下编写测试用例的信息,请查阅 http://www.throwtheswitch.org/unity。
|
||||
|
||||
|
||||
添加多设备测试用例
|
||||
------------------
|
||||
-------------------------------
|
||||
|
||||
常规测试用例会在一个 DUT(Device Under
|
||||
Test,在试设备)上执行,那些需要互相通信的组件(比如
|
||||
GPIO,SPI...)不能使用常规测试用例进行测试。多设备测试用例支持使用多个
|
||||
DUT 进行写入和运行测试。
|
||||
常规测试用例会在一个 DUT(Device Under Test,在试设备)上执行,那些需要互相通信的组件(比如 GPIO,SPI...)不能使用常规测试用例进行测试。
|
||||
多设备测试用例支持使用多个 DUT 进行写入和运行测试。
|
||||
|
||||
以下是一个多设备测试用例:
|
||||
|
||||
.. code:: c
|
||||
.. code-block:: c
|
||||
|
||||
void gpio_master_test()
|
||||
{
|
||||
@ -89,41 +76,27 @@ DUT 进行写入和运行测试。
|
||||
宏 ``TEST_CASE_MULTIPLE_DEVICES`` 用来声明多设备测试用例,
|
||||
|
||||
- 第一个参数指定测试用例的名字。
|
||||
|
||||
- 第二个参数是测试用例的描述。
|
||||
- 从第三个参数开始,可以指定最多 5 个测试函数,每个函数都是单独运行在一个 DUT 上的测试入口点。
|
||||
|
||||
- 从第三个参数开始,可以指定最多5个测试函数,每个函数都是单独运行在一个
|
||||
DUT 上的测试入口点。
|
||||
在不同的 DUT 上运行的测试用例,通常会要求它们之间进行同步。我们提供 ``unity_wait_for_signal`` 和 ``unity_send_signal`` 这两个函数来使用 UART 去支持同步操作。如上例中的场景,slave 应该在 master 设置好 GPIO 电平后再去读取 GPIO 电平,DUT 的 UART 终端会打印提示信息,并要求用户进行交互。
|
||||
|
||||
在不同的 DUT 上运行的测试用例,通常会要求它们之间进行同步。我们提供
|
||||
``unity_wait_for_signal`` 和 ``unity_send_signal`` 这两个函数来使用 UART
|
||||
去支持同步操作。如上例中的场景,slave 应该在在 master 设置好 GPIO
|
||||
电平后再去读取 GPIO 电平,DUT 的 UART
|
||||
终端会打印提示信息,并要求用户进行交互。
|
||||
|
||||
DUT1(master)终端:
|
||||
|
||||
.. code:: bash
|
||||
DUT1(master)终端::
|
||||
|
||||
Waiting for signal: [output high level]!
|
||||
Please press "Enter" key once any board send this signal.
|
||||
|
||||
DUT2(slave)终端:
|
||||
|
||||
.. code:: bash
|
||||
DUT2(slave)终端::
|
||||
|
||||
Send signal: [output high level]!
|
||||
|
||||
一旦 DUT2 发送了该信号,您需要在 DUT2 的终端输入回车,然后 DUT1 会从
|
||||
``unity_wait_for_signal`` 函数中解除阻塞,并开始更改 GPIO 的电平。
|
||||
一旦 DUT2 发送了该信号,您需要在 DUT1 的终端按回车键,然后 DUT1 会从 ``unity_wait_for_signal`` 函数中解除阻塞,并开始更改 GPIO 的电平。
|
||||
|
||||
|
||||
添加多阶段测试用例
|
||||
------------------
|
||||
|
||||
常规的测试用例无需重启就会结束(或者仅需要检查是否发生了重启),可有些时候我们想在某些特定类型的重启事件后运行指定的测试代码,例如,我们想在深度睡眠唤醒后检查复位的原因是否正确。首先我们需要出发深度睡眠复位事件,然后检查复位的原因。为了实现这一点,我们可以定义多阶段测试用例来将这些测试函数组合在一起。
|
||||
|
||||
.. code:: c
|
||||
常规的测试用例无需重启就会结束(或者仅需要检查是否发生了重启),可有些时候我们想在某些特定类型的重启事件后运行指定的测试代码,例如,我们想在深度睡眠唤醒后检查复位的原因是否正确。首先我们需要触发深度睡眠复位事件,然后检查复位的原因。为了实现这一点,我们可以定义多阶段测试用例来将这些测试函数组合在一起::
|
||||
|
||||
static void trigger_deepsleep(void)
|
||||
{
|
||||
@ -145,41 +118,27 @@ DUT2(slave)终端:
|
||||
编译单元测试程序
|
||||
----------------
|
||||
|
||||
按照 esp-idf 顶层目录的 README 文件中的说明进行操作,请确保 ``IDF_PATH``
|
||||
环境变量已经被设置指向了 esp-idf 的顶层目录。
|
||||
按照 esp-idf 顶层目录的 README 文件中的说明进行操作,请确保 ``IDF_PATH`` 环境变量已经被设置指向了 esp-idf 的顶层目录。
|
||||
|
||||
切换到 ``tools/unit-test-app`` 目录下进行配置和编译:
|
||||
|
||||
- ``idf.py menuconfig`` - 配置单元测试程序。
|
||||
* ``idf.py menuconfig`` - 配置单元测试程序。
|
||||
* ``idf.py -T all build`` - 编译单元测试程序,测试每个组件 ``test`` 子目录下的用例。
|
||||
* ``idf.py -T "xxx yyy" build`` - 编译单元测试程序,测试指定的组件。(如 ``idf.py -T heap build`` - 仅对 ``heap`` 组件目录下的单元测试程序进行编译)
|
||||
* ``idf.py -T all -E "xxx yyy" build`` - 编译单元测试程序,测试除指定组件之外的所有组件。(例如 ``idf.py -T all -E "ulp mbedtls" build`` - 编译所有的单元测试,不包括 ``ulp`` 和 ``mbedtls`` 组件。)
|
||||
|
||||
- ``idf.py -T all build`` - 编译单元测试程序,测试每个组件 ``test``
|
||||
子目录下的用例。
|
||||
当编译完成时,它会打印出烧写芯片的指令。您只需要运行 ``idf.py flash`` 即可烧写所有编译输出的文件。
|
||||
|
||||
- ``idf.py -T "xxx yyy" build`` - 编译单元测试程序,测试指定的组件。
|
||||
|
||||
- ``idf.py -T all -E "xxx yyy" build`` -
|
||||
编译单元测试程序,测试所有(除开指定)的组件。例如
|
||||
``idf.py -T all -E "ulp mbedtls" build`` -
|
||||
编译所有的单元测试,不包括 ``ulp`` 和 ``mbedtls``\ 组件。
|
||||
|
||||
当编译完成时,它会打印出烧写芯片的指令。您只需要运行 ``idf.py flash``
|
||||
即可烧写所有编译输出的文件。
|
||||
|
||||
您还可以运行 ``idf.py -T all flash`` 或者
|
||||
``idf.py -T xxx flash``
|
||||
来编译并烧写,所有需要的文件都会在烧写之前自动重新编译。
|
||||
您还可以运行 ``idf.py -T all flash`` 或者 ``idf.py -T xxx flash`` 来编译并烧写,所有需要的文件都会在烧写之前自动重新编译。
|
||||
|
||||
使用 ``menuconfig`` 可以设置烧写测试程序所使用的串口。
|
||||
|
||||
|
||||
运行单元测试
|
||||
------------
|
||||
|
||||
烧写完成后重启 ESP32, 它将启动单元测试程序。
|
||||
烧写完成后重启 ESP32,它将启动单元测试程序。
|
||||
|
||||
当单元测试应用程序空闲时,输入回车键,它会打印出测试菜单,其中包含所有的测试项目。
|
||||
|
||||
.. code::
|
||||
当单元测试应用程序空闲时,输入回车键,它会打印出测试菜单,其中包含所有的测试项目::
|
||||
|
||||
Here's the test menu, pick your combo:
|
||||
(1) "esp_ota_begin() verifies arguments" [ota]
|
||||
@ -211,7 +170,7 @@ DUT2(slave)终端:
|
||||
|
||||
可以输入以下任意一项来运行测试用例:
|
||||
|
||||
- 引号中的测试用例的名字,运行单个测试用例。
|
||||
- 引号中写入测试用例的名字,运行单个测试用例。
|
||||
|
||||
- 测试用例的序号,运行单个测试用例。
|
||||
|
||||
@ -219,14 +178,9 @@ DUT2(slave)终端:
|
||||
|
||||
- 星号,运行所有测试用例。
|
||||
|
||||
``[multi_device]`` 和 ``[multi_stage]``
|
||||
标签告诉测试运行者该用例是多设备测试还是多阶段测试。这些标签由
|
||||
``TEST_CASE_MULTIPLE_STAGES`` 和 ``TEST_CASE_MULTIPLE_DEVICES``
|
||||
宏自动生成。
|
||||
``[multi_device]`` 和 ``[multi_stage]``标签告诉测试运行者该用例是多设备测试还是多阶段测试。这些标签由 ``TEST_CASE_MULTIPLE_STAGES`` 和 ``TEST_CASE_MULTIPLE_DEVICES`` 宏自动生成。
|
||||
|
||||
一旦选择了多设备测试用例,它会打印一个子菜单:
|
||||
|
||||
.. code::
|
||||
一旦选择了多设备测试用例,它会打印一个子菜单::
|
||||
|
||||
Running gpio master/slave test example...
|
||||
gpio master/slave test example
|
||||
@ -235,15 +189,11 @@ DUT2(slave)终端:
|
||||
|
||||
您需要输入数字以选择在 DUT 上运行的测试。
|
||||
|
||||
与多设备测试用例相似,多阶段测试用例也会打印子菜单:
|
||||
|
||||
.. code::
|
||||
与多设备测试用例相似,多阶段测试用例也会打印子菜单::
|
||||
|
||||
Running reset reason check for deepsleep...
|
||||
reset reason check for deepsleep
|
||||
(1) "trigger_deepsleep"
|
||||
(2) "check_deepsleep_reset_reason"
|
||||
|
||||
第一次执行此用例时,输入 ``1`` 来运行第一阶段(触发深度睡眠)。在重启
|
||||
DUT 并再次选择运行此用例后,输入 ``2``
|
||||
来运行第二阶段。只有在最后一个阶段通过并且之前所有的阶段都成功触发了复位的情况下,该测试才算通过。
|
||||
第一次执行此用例时,输入 ``1`` 来运行第一阶段(触发深度睡眠)。在重启 DUT 并再次选择运行此用例后,输入 ``2`` 来运行第二阶段。只有在最后一个阶段通过并且之前所有的阶段都成功触发了复位的情况下,该测试才算通过。
|
||||
|
Reference in New Issue
Block a user