docs:update CN translation for build-system,ulp,unit-tests,and idf-monitor for v4.1

This commit is contained in:
daiziyan 2021-04-20 20:06:35 +08:00 committed by bot
parent e17a8e1904
commit 9fe035e4f5
8 changed files with 1053 additions and 670 deletions

View File

@ -3,7 +3,7 @@ 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.
@ -11,24 +11,17 @@ This document explains the implementation of the ESP-IDF build system and the co
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
--------
@ -78,6 +71,7 @@ Type ``idf.py --help`` for a list of commands. Here are a summary of the most us
- 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.
@ -105,14 +99,15 @@ The order of multiple ``idf.py`` commands on the same invocation is not importan
idf.py options
^^^^^^^^^^^^^^
To list all available root level options, run ``idf.py --help``. To list options that are specific for a subcommand, run ``idf.py <command> --help``, for example ``idf.py monitor --help``.
Here is a list of some useful options:
To list all available root level options, run ``idf.py --help``. To list options that are specific for a subcommand, run ``idf.py <command> --help``, for example ``idf.py monitor --help``. Here is a list of some useful options:
- ``-C <dir>`` allows overriding the project directory from the default current working directory.
- ``-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.
@ -166,7 +161,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
---------------------
@ -183,8 +177,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.
@ -193,7 +186,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.
@ -237,8 +230,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.
@ -248,8 +240,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`_.
@ -269,7 +260,6 @@ Minimal project::
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(myProject)
.. _project-mandatory-parts:
Mandatory Parts
@ -281,6 +271,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
--------------------------
@ -288,7 +279,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.
@ -300,11 +293,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.
@ -326,13 +315,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:
@ -352,10 +340,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.
@ -397,6 +385,8 @@ from the component CMakeLists.txt:
Other build properties are listed :ref:`here<cmake-build-properties>`.
.. _component_build_control:
Controlling Component Compilation
---------------------------------
@ -422,8 +412,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.
@ -456,8 +445,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.
@ -561,7 +553,6 @@ This means that the ``spark_plug/CMakeLists.txt`` file doesn't need any ``REQUIR
INCLUDE_DIRS ".")
Source File Include Directories
-------------------------------
@ -599,6 +590,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:
@ -620,6 +612,7 @@ 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:
Overriding Parts of the Project
===============================
@ -629,9 +622,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".
@ -646,19 +637,18 @@ 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.
Debugging CMake
===============
@ -686,8 +676,7 @@ If you don't want this behaviour, it can be disabled by passing ``--no-warnings`
Browse the :idf_file:`/tools/cmake/project.cmake` file and supporting functions in :idf_file:`/tools/cmake/idf_functions.cmake` for more details.
.. _gnu-make-to-cmake:
.. _component_cmakelists_example:
Example Component CMakeLists
============================
@ -777,12 +766,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
@ -797,18 +781,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:
@ -822,7 +801,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(...
@ -850,10 +828,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:
@ -862,11 +837,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
@ -880,7 +851,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)
@ -937,6 +907,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/files, the name of target-specific defaults file will be derived from ``SDKCONFIG_DEFAULTS`` value/values using the rule above.
.. _flash_parameters:
Flash arguments
===============
@ -975,7 +946,7 @@ Selecting the Target
ESP-IDF supports multiple targets (chips). The identifiers used for each chip are as follows:
* ``esp32`` — for ESP32-D0WD, ESP32-D2WD, ESP32-S0WD (ESP-SOLO), ESP32-U4WD, ESP32-PICO-D4
* ``esp32`` — for ESP32-D0WD, ESP32-D2WD, ESP32-S0WD (ESP-SOLO), ESP32-U4WDH, ESP32-PICO-D4
* ``esp32s2beta``— for ESP32-S2-beta (engineering samples)
To select the target before building the project, use ``idf.py set-target <target>`` command, for example::
@ -994,12 +965,14 @@ To select the target before building the project, use ``idf.py set-target <targe
2. removing the sdkconfig file (``mv sdkconfig sdkconfig.old``)
3. configuring the project with the new target (``idf.py -DIDF_TARGET=esp32 reconfigure``)
It is also possible to pass the desired ``IDF_TARGET`` as an environement variable (e.g. ``export IDF_TARGET=esp32s2beta``) or as a CMake variable (e.g. ``-DIDF_TARGET=esp32s2beta`` argument to CMake or idf.py). Setting the environment variable is a convenient method if you mostly work with one type of the chip.
It is also possible to pass the desired ``IDF_TARGET`` as an environment variable (e.g. ``export IDF_TARGET=esp32s2beta``) or as a CMake variable (e.g. ``-DIDF_TARGET=esp32s2beta`` argument to CMake or idf.py). Setting the environment variable is a convenient method if you mostly work with one type of the chip.
To specify the _default_ value of ``IDF_TARGET`` for a given project, add ``CONFIG_IDF_TARGET`` value to ``sdkconfig.defaults``. For example, ``CONFIG_IDF_TARGET="esp32s2beta"``. This value will be used if ``IDF_TARGET`` is not specified by other method: using an environment variable, CMake variable, or ``idf.py set-target`` command.
If the target has not been set by any of these methods, the build system will default to ``esp32`` target.
.. _write-pure-component:
Writing Pure CMake Components
=============================
@ -1021,13 +994,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
@ -1046,19 +1016,16 @@ 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.
Using ESP-IDF components from external libraries
------------------------------------------------
The above example assumes that the external library ``foo` (or ``tinyxml`` in the case of the ``import_lib`` example) doesn't need to use any ESP-IDF APIs apart from common APIs such as libc, libstdc++, etc. If the external library needs to use APIs provided by other ESP-IDF components, this needs to be specified in the external CMakeLists.txt file by adding a dependency on the library target ``idf::<componentname>``.
The above example assumes that the external library ``foo`` (or ``tinyxml`` in the case of the ``import_lib`` example) doesn't need to use any ESP-IDF APIs apart from common APIs such as libc, libstdc++, etc. If the external library needs to use APIs provided by other ESP-IDF components, this needs to be specified in the external CMakeLists.txt file by adding a dependency on the library target ``idf::<componentname>``.
For example, in the ``foo/CMakeLists.txt`` file::
@ -1077,8 +1044,7 @@ Using Prebuilt Libraries with Components
Another possibility is that you have a prebuilt static library (``.a`` file), built by some other build process.
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 ...])
@ -1089,18 +1055,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:
@ -1113,7 +1075,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)
@ -1125,10 +1087,11 @@ 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
@ -1141,17 +1104,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
@ -1173,11 +1132,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:
@ -1188,63 +1144,57 @@ The call requires the target chip to be specified with *target* argument. Option
- SDKCONFIG_DEFAULTS - list of files containing default config to use in the build (list must contain full paths); defaults to empty. For each value *filename* in the list, the config from file *filename.target*, if it exists, is also loaded.
- 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 - list of files containing default config to use in the build; 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 - list of files containing default config to use in the build; 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
----------------------
@ -1253,17 +1203,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:
@ -1279,9 +1225,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
@ -1291,8 +1235,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
@ -1301,9 +1244,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
@ -1313,22 +1254,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
@ -1373,6 +1310,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
=====================
@ -1476,7 +1415,8 @@ This section describes the standard ESP-IDF application build process. The build
Initialization
^^^^^^^^^^^^^^
This phase sets up necessary parameters for the build.
This phase sets up necessary parameters for the build.
- Upon inclusion of ``idf.cmake`` in ``project.cmake``, the following steps are performed:
- Set ``IDF_PATH`` from environment variable or inferred from path to ``project.cmake`` included in the top-level CMakeLists.txt.
@ -1501,6 +1441,7 @@ Enumeration
Processing
^^^^^^^^^^
This phase processes the components in the build, and is the second half of ``idf_build_process()``.
- Load project configuration from sdkconfig file and generate an sdkconfig.cmake and sdkconfig.h header. These define configuration variables/macros that are accessible from the build scripts and C/C++ source/header files, respectively.
@ -1514,16 +1455,12 @@ Finalization
- Create executable and link the component libraries to it.
- Generate project metadata files such as project_description.json and display relevant information about the project built.
Browse :idf_file:`/tools/cmake/project.cmake` for more details.
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
-------------------------
@ -1577,7 +1514,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
------------------

View File

@ -8,48 +8,64 @@ 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.
IDF-specific features
=====================
Automatic Address Decoding
~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -95,7 +111,6 @@ To decode each address, IDF Monitor runs the following command in the background
xtensa-esp32-elf-addr2line -pfiaC -e build/PROJECT.elf ADDRESS
Launching GDB with GDBStub
~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -122,40 +137,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 +190,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.

View File

@ -42,11 +42,7 @@ To compile the ULP code as part of the component, the following steps must be ta
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 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.
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`)
@ -147,7 +143,7 @@ Declaration of the entry point symbol comes from the generated header file menti
ULP Program Flow
----------------
The ULP coprocessor is started by a timer. The timer is started once ``ulp_run`` is called. The timer counts the 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 the ``sleep`` instruction.
The 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 the ``sleep`` instruction.
The application can set ULP timer period values (SENS_ULP_CP_SLEEP_CYCx_REG, x = 0..4) using the ``ulp_set_wakeup_period`` function.

View File

@ -7,9 +7,7 @@ ESP-IDF comes with a unit test application that is based on the Unity - unit tes
Normal Test Cases
------------------
Unit tests are located in the ``test`` subdirectory of a component.
Tests are written in C, and a single C source file can contain multiple test cases.
Test files start with the word "test".
Unit tests are located in the ``test`` subdirectory of a component. Tests are written in C, and a single C source file can contain multiple test cases. Test files start with the word "test".
Each test file should include the ``unity.h`` header and the header for the C module to be tested.
@ -22,8 +20,8 @@ Tests are added in a function in the C file as follows:
// Add test here
}
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 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.
.. note::
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()`` autonomously, and run the test cases, then call ``UNITY_END()``.
@ -44,8 +42,7 @@ See http://www.throwtheswitch.org/unity for more information about writing tests
Multi-device Test Cases
-------------------------
The normal test cases will be executed on one DUT (Device Under Test). However, components that require some form of communication (e.g., GPIO, SPI) require another device to communicate with, thus cannot be tested normal test cases.
Multi-device test cases involve writing multiple test functions, and running them on multiple DUTs.
The normal test cases will be executed on one DUT (Device Under Test). However, components that require some form of communication (e.g., GPIO, SPI) require another device to communicate with, thus cannot be tested normal test cases. Multi-device test cases involve writing multiple test functions, and running them on multiple DUTs.
The following is an example of a multi-device test case:
@ -75,13 +72,13 @@ The following is an example of a multi-device 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 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 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:
- 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 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::
@ -98,9 +95,7 @@ Once the signal is sent from DUT2, you need to press "Enter" on DUT1, then DUT1
Multi-stage Test Cases
-----------------------
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::
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,20 +113,17 @@ To support this, we can define multi-stage test cases, to group a set of test fu
Multi-stage test cases present a group of test functions to users. It needs user interactions (select cases and select different stages) to run the case.
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:
* ``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 excluding ``ulp`` and ``mbedtls`` components).
* ``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.
@ -184,8 +176,7 @@ 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 of 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 multi-device test case, it will print sub-menu::
@ -203,10 +194,7 @@ Similar to multi-device test cases, multi-stage test cases will also print sub-m
(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.
Timing Code with Cache Compensated Timer
@ -218,13 +206,9 @@ However, if the instruction or data is not in cache, it needs to be fetched from
Code and data placements can vary between builds, and some arrangements may be more favorable with regards to cache access (i.e., minimizing cache misses). This can technically affect execution speed, however these factors are usually irrelevant as their effect 'average out' over the device's operation.
The effect of the cache on execution speed, however, can be relevant in benchmarking scenarios (espcially microbenchmarks). There might be some variability in measured time
between runs and between different builds. A technique for eliminating for some of the
variability is to place code and data in instruction or data RAM (IRAM/DRAM), respectively. The CPU can access IRAM and DRAM directly, eliminating the cache out of the equation.
However, this might not always be viable as the size of IRAM and DRAM is limited.
The effect of the cache on execution speed, however, can be relevant in benchmarking scenarios (espcially microbenchmarks). There might be some variability in measured time between runs and between different builds. A technique for eliminating for some of the variability is to place code and data in instruction or data RAM (IRAM/DRAM), respectively. The CPU can access IRAM and DRAM directly, eliminating the cache out of the equation. However, this might not always be viable as the size of IRAM and DRAM is limited.
The cache compensated timer is an alternative to placing the code/data to be benchmarked in IRAM/DRAM. This timer uses the processor's internal event counters in order to determine the amount
of time spent on waiting for code/data in case of a cache miss, then subtract that from the recorded wall time.
The cache compensated timer is an alternative to placing the code/data to be benchmarked in IRAM/DRAM. This timer uses the processor's internal event counters in order to determine the amount of time spent on waiting for code/data in case of a cache miss, then subtract that from the recorded wall time.
.. code-block:: c
@ -240,5 +224,3 @@ of time spent on waiting for code/data in case of a cache miss, then subtract th
One limitation of the cache compensated timer is that the task that benchmarked functions should be pinned to a core. This is due to each core having its own event counters that are independent of each other. For example, if ``ccomp_timer_start`` gets called on one core, put to sleep by the scheduler, wakes up, and gets rescheduled on the other core, then the corresponding ``ccomp_timer_stop`` will be invalid.
invalid.

File diff suppressed because it is too large Load Diff

View File

@ -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_ 查找该地址在源代码中的位置和对应的函数名。
@ -84,7 +111,6 @@ IDF 监视器在后台运行以下命令,解码各地址::
xtensa-esp32-elf-addr2line -pfiaC -e build/PROJECT.elf ADDRESS
配置 GDBStub 以启用 GDB
~~~~~~~~~~~~~~~~~~~~~~~~~
@ -104,30 +130,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`` 错误信息会打印在指定的详细度级别(或更低级别),并默认打印所有内容。
高级筛选规则示例

View File

@ -6,23 +6,22 @@ ULP 协处理器编程
.. toctree::
:maxdepth: 1
ESP32 指令集参考 <ulp_instruction_set>
ESP32-S2 指令集参考 <ulps2_instruction_set>
ESP32 ULP 指令集参考 <ulp_instruction_set>
ESP32-S2 ULP 指令集参考 <ulps2_instruction_set>
使用宏进行编程(遗留) <ulp_macros>
ULPUltra Low Power 超低功耗)协处理器是一种简单的有限状态机 (FSM),可以在主处理器处于深度睡眠模式时,使用 ADC、温度传感器和外部 I2C 传感器执行测量操作。ULP 协处理器可以访问 RTC_SLOW_MEM 内存区域及 RTC_CNTL、RTC_IO、SARADC 外设寄存器。ULP 协处理器使用 32 位固定宽度的指令32 位内存寻址,配备 4 个 16 位通用寄存器。
ULPUltra Low Power 超低功耗)协处理器是一种简单的有限状态机 (FSM),可以在主处理器处于深度睡眠模式时,使用 ADC、温度传感器和外部 I2C 传感器执行测量操作。ULP 协处理器可以访问 RTC_SLOW_MEM 内存区域及 RTC_CNTL、RTC_IO、SARADC 外设中的寄存器。ULP 协处理器使用 32 位固定宽度的指令32 位内存寻址,配备 4 个 16 位通用寄存器。
安装工具链
----------
ULP 协处理器代码是用汇编语言编写的,并使用 `binutils-esp32ulp 工具链` 进行编译。
ULP 协处理器代码是用汇编语言编写的,并使用 `binutils-esp32ulp 工具链`_ 进行编译。
如果你已经按照 :doc:`快速入门指南 <../../get-started/index>` 中的介绍安装好了 ESP-IDF 及其 CMake 构建系统,那么 ULP 工具链已经被默认安装到了你的开发环境中。
如果你的 ESP-IDF 仍在使用传统的基于 GNU Make 的构建系统,请参考 :doc:`ulp-legacy` 一文中的说明,完成工具链的安装。
编译 ULP 代码
-------------
@ -32,7 +31,6 @@ ULP 协处理器代码是用汇编语言编写的,并使用 `binutils-esp32ulp
.. note: 在注册组件(通过 ``idf_component_register``)时,不应将该目录添加到 ``SRC_DIRS`` 参数中。因为 ESP-IDF 构建系统将基于文件扩展名编译在 ``SRC_DIRS`` 中搜索到的文件。对于 ``.S`` 文件,使用的是 ``xtensa-esp32-elf-as`` 汇编器。但这并不适用于 ULP 程序集文件,因此体现这种区别最简单的方式就是将 ULP 程序集文件放到单独的目录中。同样ULP 程序集源文件也 **不应该** 添加到 ``SRCS`` 中。请参考如下步骤,查看如何正确添加 ULP 程序集源文件。
2. 注册后从组件 CMakeLists.txt 中调用 ``ulp_embed_binary`` 示例如下::
...
@ -44,16 +42,16 @@ ULP 协处理器代码是用汇编语言编写的,并使用 `binutils-esp32ulp
ulp_embed_binary(${ulp_app_name} "${ulp_s_sources}" "${ulp_exp_dep_srcs}")
上述第一个参数到 ``ulp_embed_binary`` 为 ULP 二进制文件命名。此名称也用于生成的其他文件ELF 文件、.map 文件、头文件和链接器导出文件。第二个参数设置 ULP 程序集源文件。最后,第三个参数设置组件源文件列表,其中包括被生成的头文件。此列表用以建立正确的依赖项,并确保在构建过程会先生成再编译包含头文件的源文件。请参考下文,查看为 ULP 应用程序生成的头文件等相关概念。
``ulp_embed_binary`` 的第一个参数为 ULP 二进制文件命名。指定的此名称也用于生成的其他文件ELF 文件、.map 文件、头文件和链接器导出文件。第二个参数指定 ULP 程序集源文件。最后,第三个参数指定组件源文件列表,其中包括被生成的头文件。此列表用以建立正确的依赖项,并确保在编译这些文件之前先创建生成的头文件。有关 ULP 应用程序生成的头文件等相关概念,请参考下文
3. 使用常规方法(例如 `idf.py app`)编译应用程序
在内部,构建系统将按照以下步骤编译 ULP 程序:
1. **通过 C 预处理器运行每个程序集文件 (foo.S)。** 此步骤在组件编译目录中生成预处理的程序集文件 (foo.ulp.S),同时生成依赖文件 (foo.ulp.d)。
2. **通过汇编器运行预处理过的汇编源码。** 此步骤会生成目标文件 (foo.ulp.o) 和清单 (foo.ulp.lst)。清单文件仅用于调试,不用于编译进程的后续步骤。
3. **通过 C 预处理器运行链接器脚本模板。** 模板位于 ``components/ulp/ld`` 目录中。
4. **将目标文件链接到 ELF 输出文件** (``ulp_app_name.elf``)。此步骤生成的.map 文件 (``ulp_app_name.map``) 默认用于调试。
@ -80,7 +78,7 @@ ULP 协处理器代码是用汇编语言编写的,并使用 `binutils-esp32ulp
move r3, measurement_count
ld r3, r3, 0
主程序需要在启动 ULP 程序之前初始化 ``measurement_count`` 变量,构建系统生成定义 ULP 编程中全局符号的 ``${ULP_APP_NAME}.h````${ULP_APP_NAME}.ld`` 文件,可以实现上述操作,这些文件包含在 ULP 程序中定义的所有全局符号,文件以 ``ulp_`` 开头。
主程序需要在启动 ULP 程序之前初始化 ``measurement_count`` 变量,构建系统通过生成定义 ULP 编程中全局符号的 ``${ULP_APP_NAME}.h````${ULP_APP_NAME}.ld`` 文件实现上述操作。这些文件包含了在 ULP 程序中定义的所有全局符号,文件以 ``ulp_`` 开头。
头文件包含对此类符号的声明::
@ -114,7 +112,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");

View File

@ -2,39 +2,31 @@ 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 文件中特定的函数来添加,如下所示:
.. code-block:: c
TEST_CASE("test name", "[module name]"
TEST_CASE("test name", "[module name]")
{
// 在这里添加测试用例
}
- 第一个参数是字符串,用来描述当前测试。
- 第二个参数是字符串,用方括号中的标识符来表示,标识符用来对相关测试或具有特定属性的测试进行分组。
- 第一个参数是此测试的描述性名称。
- 第二个参数用方括号中的标识符来表示,标识符用来对相关测试或具有特定属性的测试进行分组。
.. note::
没有必要在每个测试用例中使用 ``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>`;但是,对于测试组件来说,这个要求被放宽为仅建议将参数 ``SRC_DIRS`` 用于 ``idf_component_register``
``test`` 子目录应包含 :ref: `组件 CMakeLists.txt <component-directories>`因为他们本身就是一种组件。ESP-IDF 使用了 ``unity`` 测试框架,需要将其指定为组件的依赖项。通常,组件 :ref: `需要手动指定待编译的源文件 <cmake-file-globbing>;但是,对于测试组件来说,这个要求被放宽为仅建议将参数 ``SRC_DIRS`` 用于 ``idf_component_register``。
总的来说,``test`` 子目录下最小的 CMakeLists.txt 文件可能如下所示:
@ -44,82 +36,66 @@ C 文件可以包含多个测试用例。测试文件的名字要以 “test”
INCLUDE_DIRS "."
REQUIRES unity)
更多关于如何在 Unity 下编写测试用例的信息,请查阅
http://www.throwtheswitch.org/unity 。
更多关于如何在 Unity 下编写测试用例的信息,请查阅 http://www.throwtheswitch.org/unity。
添加多设备测试用例
------------------
常规测试用例会在一个 DUTDevice Under Test在试设备上执行.但是,那些需要互相通信的组件(比如
GPIO、SPI需要与其通信的其他设备因此不能使用常规测试用例进行测试。多设备测试用例包括写入多个测试函数并在多个 DUT 进行运行测试。
常规测试用例会在一个 DUTDevice Under Test在试设备上执行。但是那些需要互相通信的组件比如 GPIO、SPI需要其他设备与其通信因此不能使用常规测试用例进行测试。多设备测试用例包括写入多个测试函数并在多个 DUT 进行运行测试。
以下是一个多设备测试用例:
.. code:: c
.. code-block:: c
void gpio_master_test()
{
gpio_config_t slave_config = {
.pin_bit_mask = 1 << MASTER_GPIO_PIN,
.mode = GPIO_MODE_INPUT,
};
gpio_config(&slave_config);
unity_wait_for_signal("output high level");
TEST_ASSERT(gpio_get_level(MASTER_GPIO_PIN) == 1);
}
void gpio_master_test()
{
gpio_config_t slave_config = {
.pin_bit_mask = 1 << MASTER_GPIO_PIN,
.mode = GPIO_MODE_INPUT,
};
gpio_config(&slave_config);
unity_wait_for_signal("output high level");
TEST_ASSERT(gpio_get_level(MASTER_GPIO_PIN) == 1);
}
void gpio_slave_test()
{
gpio_config_t master_config = {
.pin_bit_mask = 1 << SLAVE_GPIO_PIN,
.mode = GPIO_MODE_OUTPUT,
};
gpio_config(&master_config);
gpio_set_level(SLAVE_GPIO_PIN, 1);
unity_send_signal("output high level");
}
void gpio_slave_test()
{
gpio_config_t master_config = {
.pin_bit_mask = 1 << SLAVE_GPIO_PIN,
.mode = GPIO_MODE_OUTPUT,
};
gpio_config(&master_config);
gpio_set_level(SLAVE_GPIO_PIN, 1);
unity_send_signal("output high level");
}
TEST_CASE_MULTIPLE_DEVICES("gpio multiple devices test example", "[driver]", gpio_master_test, gpio_slave_test);
TEST_CASE_MULTIPLE_DEVICES("gpio multiple devices test example", "[driver]", gpio_master_test, gpio_slave_test);
``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
终端会打印提示信息,并要求用户进行交互。
DUT1master终端
.. code:: bash
DUT1master终端::
Waiting for signal: [output high level]!
Please press "Enter" key once any board send this signal.
DUT2slave终端
.. code:: bash
DUT2slave终端::
Send signal: [output high level]!
一旦 DUT2 发送了该信号,您需要在 DUT1 的终端按回车键,然后 DUT1 会从
``unity_wait_for_signal`` 函数中解除阻塞,并开始更改 GPIO 的电平。
一旦 DUT2 发送了该信号,您需要在 DUT1 的终端按回车键,然后 DUT1 会从 ``unity_wait_for_signal`` 函数中解除阻塞,并开始更改 GPIO 的电平。
添加多阶段测试用例
------------------
常规的测试用例无需重启就会结束(或者仅需要检查是否发生了重启),可有些时候我们想在某些特定类型的重启事件后运行指定的测试代码,例如,我们想在深度睡眠唤醒后检查复位的原因是否正确。首先我们需要出发深度睡眠复位事件,然后检查复位的原因。为了实现这一点,我们可以定义多阶段测试用例来将这些测试函数组合在一起。
.. code:: c
常规的测试用例无需重启就会结束(或者仅需要检查是否发生了重启),可有些时候我们想在某些特定类型的重启事件后运行指定的测试代码,例如,我们想在深度睡眠唤醒后检查复位的原因是否正确。首先我们需要触发深度睡眠复位事件,然后检查复位的原因。为了实现这一点,我们可以定义多阶段测试用例来将这些测试函数组合在一起::
static void trigger_deepsleep(void)
{
@ -133,81 +109,66 @@ DUT2slave终端
TEST_ASSERT(reason == DEEPSLEEP_RESET);
}
TEST_CASE_MULTIPLE_STAGES("reset reason check for deepsleep", "[esp32]", trigger_deepsleep, check_deepsleep_reset_reason);
TEST_CASE_MULTIPLE_STAGES("reset reason check for deepsleep", "[esp32]", trigger_deepsleep, check_deepsleep_reset_reason);
多阶段测试用例向用户呈现了一组测试函数,它需要用户进行交互(选择用例并选择不同的阶段)来运行。
编译单元测试程序
----------------
按照 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 flash`` 即可烧写所有编译输出的文件。
- ``idf.py -T all build`` - 编译单元测试程序,测试每个组件 ``test``
子目录下的用例。
- ``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 它将启动单元测试程序。
当单元测试应用程序空闲时,输入回车键,它会打印出测试菜单,其中包含所有的测试项目
当单元测试应用程序空闲时,输入回车键,它会打印出测试菜单,其中包含所有的测试项目::
.. code::
Here's the test menu, pick your combo:
(1) "esp_ota_begin() verifies arguments" [ota]
(2) "esp_ota_get_next_update_partition logic" [ota]
(3) "Verify bootloader image in flash" [bootloader_support]
(4) "Verify unit test app image" [bootloader_support]
(5) "can use new and delete" [cxx]
(6) "can call virtual functions" [cxx]
(7) "can use static initializers for non-POD types" [cxx]
(8) "can use std::vector" [cxx]
(9) "static initialization guards work as expected" [cxx]
(10) "global initializers run in the correct order" [cxx]
(11) "before scheduler has started, static initializers work correctly" [cxx]
(12) "adc2 work with wifi" [adc]
(13) "gpio master/slave test example" [ignore][misc][test_env=UT_T2_1][multi_device]
(1) "gpio_master_test"
(2) "gpio_slave_test"
(14) "SPI Master clockdiv calculation routines" [spi]
(15) "SPI Master test" [spi][ignore]
(16) "SPI Master test, interaction of multiple devs" [spi][ignore]
(17) "SPI Master no response when switch from host1 (HSPI) to host2 (VSPI)" [spi]
(18) "SPI Master DMA test, TX and RX in different regions" [spi]
(19) "SPI Master DMA test: length, start, not aligned" [spi]
(20) "reset reason check for deepsleep" [esp32][test_env=UT_T2_1][multi_stage]
(1) "trigger_deepsleep"
(2) "check_deepsleep_reset_reason"
Here's the test menu, pick your combo:
(1) "esp_ota_begin() verifies arguments" [ota]
(2) "esp_ota_get_next_update_partition logic" [ota]
(3) "Verify bootloader image in flash" [bootloader_support]
(4) "Verify unit test app image" [bootloader_support]
(5) "can use new and delete" [cxx]
(6) "can call virtual functions" [cxx]
(7) "can use static initializers for non-POD types" [cxx]
(8) "can use std::vector" [cxx]
(9) "static initialization guards work as expected" [cxx]
(10) "global initializers run in the correct order" [cxx]
(11) "before scheduler has started, static initializers work correctly" [cxx]
(12) "adc2 work with wifi" [adc]
(13) "gpio master/slave test example" [ignore][misc][test_env=UT_T2_1][multi_device]
(1) "gpio_master_test"
(2) "gpio_slave_test"
(14) "SPI Master clockdiv calculation routines" [spi]
(15) "SPI Master test" [spi][ignore]
(16) "SPI Master test, interaction of multiple devs" [spi][ignore]
(17) "SPI Master no response when switch from host1 (HSPI) to host2 (VSPI)" [spi]
(18) "SPI Master DMA test, TX and RX in different regions" [spi]
(19) "SPI Master DMA test: length, start, not aligned" [spi]
(20) "reset reason check for deepsleep" [esp32][test_env=UT_T2_1][multi_stage]
(1) "trigger_deepsleep"
(2) "check_deepsleep_reset_reason"
常规测试用例会打印用例名字和描述,主从测试用例还会打印子菜单(已注册的测试函数的名字)。
可以输入以下任意一项来运行测试用例:
- 引号中测试用例的名字,运行单个测试用例。
- 引号中写入测试用例的名字,运行单个测试用例。
- 测试用例的序号,运行单个测试用例。
@ -215,31 +176,51 @@ DUT2slave终端
- 星号,运行所有测试用例。
``[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
(1) "gpio_master_test"
(2) "gpio_slave_test"
Running gpio master/slave test example...
gpio master/slave test example
(1) "gpio_master_test"
(2) "gpio_slave_test"
您需要输入数字以选择在 DUT 上运行的测试。
与多设备测试用例相似,多阶段测试用例也会打印子菜单
与多设备测试用例相似,多阶段测试用例也会打印子菜单::
.. code::
Running reset reason check for deepsleep...
reset reason check for deepsleep
(1) "trigger_deepsleep"
(2) "check_deepsleep_reset_reason"
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``
来运行第二阶段。只有在最后一个阶段通过并且之前所有的阶段都成功触发了复位的情况下,该测试才算通过。
带缓存补偿定时器的定时代码
-----------------------------------------
存储在外部存储器(如 SPI Flash 和 SPI RAM中的指令和数据是通过 CPU 的统一指令和数据缓存来访问的。当代码或数据在缓存中时,访问速度会非常快(即缓存命中)。
然而,如果指令或数据不在缓存中,则需要从外部内存中获取(即缓存缺失)。访问外部存储器的速度明显较慢,因为 CPU 在等待从外部存储器获取指令或数据时会陷入停滞。这导致整体代码执行速度会依据缓存命中或缓存缺失的次数而变化。
在不同的编译中,代码和数据的位置可能会有所不同,一些可能会更有利于缓存访问(即,最大限度地减少缓存缺失)。理论上说这会影响执行速度,但这些因素通常却是无关紧要,因为它们的影响会在设备的运行过程中“平均化”。
然而,高速缓存对执行速度的影响可能与基准测试场景(尤其是微基准测试)有关。每次运行和构建时的测量时间可能会有所差异,消除部分差异的方法之一是将代码和数据分别放在指令或数据 RAMIRAM/DRAM中。CPU 可以直接访问 IRAM 和 DRAM从而消除了高速缓存的影响因素。然而由于 IRAM 和 DRAM 容量有限,该方法并不总是可行。
缓存补偿定时器是将要基准测试的代码/数据放置在 IRAM/DRAM 中的替代方法,该计时器使用处理器的内部事件计数器来确定在发生高速缓存未命中时等待代码/数据所花费的时间,然后从记录的实时时间中减去该时间。
.. code-block:: c
// Start the timer
ccomp_timer_start();
// Function to time
func_code_to_time();
// Stop the timer, and return the elapsed time in microseconds relative to
// ccomp_timer_start
int64_t t = ccomp_timer_stop();
缓存补偿定时器的限制之一是基准功能必须固定在一个内核上。这是由于每个内核都有自己的事件计数器,这些事件计数器彼此独立。例如,如果在一个内核上调用 ``ccomp_timer_start``,使调度器进入睡眠状态,唤醒并在在另一个内核上重新调度,那么对应的 ``ccomp_timer_stop`` 将无效。