Merge branch 'master' into feature/esp32s2beta_update

This commit is contained in:
Angus Gratton
2019-08-08 13:44:24 +10:00
committed by Angus Gratton
2414 changed files with 160787 additions and 45783 deletions

View File

@@ -11,9 +11,9 @@ Overview
Application Example
-------------------
Check :example:`bluetooth` folder in ESP-IDF examples, which contains the following application:
Check :example:`bluetooth/bluedroid/hci` folder in ESP-IDF examples, which contains the following application:
* This is a BLE advertising demo with virtual HCI interface. Send Reset/ADV_PARAM/ADV_DATA/ADV_ENABLE HCI command for BLE advertising - :example:`bluetooth/ble_adv`.
* This is a BLE advertising demo with virtual HCI interface. Send Reset/ADV_PARAM/ADV_DATA/ADV_ENABLE HCI command for BLE advertising - :example:`bluetooth/bluedroid/hci/controller_vhci_ble_adv`.
API Reference
-------------

View File

@@ -11,9 +11,9 @@ Overview
Application Example
-------------------
Check :example:`bluetooth` folder in ESP-IDF examples, which contains the following application:
Check :example:`bluetooth/bluedroid/classic_bt` folder in ESP-IDF examples, which contains the following application:
* This is a A2DP sink client demo. This demo can be discovered and connected by A2DP source device and receive the audio stream from remote device - :example:`bluetooth/a2dp_sink`
* This is a A2DP sink client demo. This demo can be discovered and connected by A2DP source device and receive the audio stream from remote device - :example:`bluetooth/bluedroid/classic_bt/a2dp_sink`
API Reference
-------------

View File

@@ -12,9 +12,9 @@ Use should concern these things:
Application Example
-------------------
Check :example:`bluetooth` folder in ESP-IDF examples, which contains the following application:
Check :example:`bluetooth/bluedroid/ble` folder in ESP-IDF examples, which contains the following application:
* This is a BLUFI demo. This demo can set ESP32's wifi to softap/station/softap&station mode and config wifi connections - :example:`bluetooth/blufi`
* This is the BLUFI demo. This demo can set ESP32's wifi to softap/station/softap&station mode and config wifi connections - :example:`bluetooth/bluedroid/ble/blufi`
API Reference
-------------

View File

@@ -11,17 +11,17 @@ Overview
Application Example
-------------------
Check :example:`bluetooth` folder in ESP-IDF examples, which contains the following demos and their tutorials:
Check :example:`bluetooth/bluedroid/ble` folder in ESP-IDF examples, which contains the following demos and their tutorials:
* This is a SMP security client demo and its tutorial. This demo initiates its security parameters and acts as a GATT client, which can send a security request to the peer device and then complete the encryption procedure.
- :example:`bluetooth/gatt_security_client`
- :example_file:`GATT Security Client Example Walkthrough <bluetooth/gatt_security_client/tutorial/Gatt_Security_Client_Example_Walkthrough.md>`
- :example:`bluetooth/bluedroid/ble/gatt_security_client`
- :example_file:`GATT Security Client Example Walkthrough <bluetooth/bluedroid/ble/gatt_security_client/tutorial/Gatt_Security_Client_Example_Walkthrough.md>`
* This is a SMP security server demo and its tutorial. This demo initiates its security parameters and acts as a GATT server, which can send a pair request to the peer device and then complete the encryption procedure.
- :example:`bluetooth/gatt_security_server`
- :example_file:`GATT Security Server Example Walkthrough <bluetooth/gatt_security_server/tutorial/Gatt_Security_Server_Example_Walkthrough.md>`
- :example:`bluetooth/bluedroid/ble/gatt_security_server`
- :example_file:`GATT Security Server Example Walkthrough <bluetooth/bluedroid/ble/gatt_security_server/tutorial/Gatt_Security_Server_Example_Walkthrough.md>`
API Reference
-------------

View File

@@ -11,21 +11,21 @@ Overview
Application Example
-------------------
Check :example:`bluetooth` folder in ESP-IDF examples, which contains the following demos and their tutorials:
Check :example:`bluetooth/bluedroid/ble` folder in ESP-IDF examples, which contains the following demos and their tutorials:
* This is a GATT client demo and its tutorial. This demo can scan for devices, connect to the GATT server and discover its services.
- :example:`bluetooth/gatt_client`
- :example_file:`GATT Client Example Walkthrough <bluetooth/gatt_client/tutorial/Gatt_Client_Example_Walkthrough.md>`
- :example:`bluetooth/bluedroid/ble/gatt_client`
- :example_file:`GATT Client Example Walkthrough <bluetooth/bluedroid/ble/gatt_client/tutorial/Gatt_Client_Example_Walkthrough.md>`
* This is a multiple connection demo and its tutorial. This demo can connect to multiple GATT server devices and discover their services.
- :example:`bluetooth/gattc_multi_connect`
- :example_file:`GATT Client Multi-connection Example Walkthrough <bluetooth/gattc_multi_connect/tutorial/Gatt_Client_Multi_Connection_Example_Walkthrough.md>`
- :example:`bluetooth/bluedroid/ble/gattc_multi_connect`
- :example_file:`GATT Client Multi-connection Example Walkthrough <bluetooth/bluedroid/ble/gattc_multi_connect/tutorial/Gatt_Client_Multi_Connection_Example_Walkthrough.md>`
* This is a BLE SPP-Like demo. This demo, which acts as a GATT client, can receive data from UART and then send the data to the peer device automatically.
- :example:`bluetooth/ble_spp_client`
- :example:`bluetooth/bluedroid/ble/ble_spp_client`
API Reference
-------------

View File

@@ -11,21 +11,21 @@ Overview
Application Example
-------------------
Check :example:`bluetooth` folder in ESP-IDF examples, which contains the following demos and their tutorials:
Check :example:`bluetooth/bluedroid/ble` folder in ESP-IDF examples, which contains the following demos and their tutorials:
* This is a GATT sever demo and its tutorial. This demo creates a GATT service with an attribute table, which releases the user from adding attributes one by one. This is the recommended method of adding attributes.
- :example:`bluetooth/gatt_server_service_table`
- :example_file:`GATT Server Service Table Example Walkthrough <bluetooth/gatt_server_service_table/tutorial/Gatt_Server_Service_Table_Example_Walkthrough.md>`
- :example:`bluetooth/bluedroid/ble/gatt_server_service_table`
- :example_file:`GATT Server Service Table Example Walkthrough <bluetooth/bluedroid/ble/gatt_server_service_table/tutorial/Gatt_Server_Service_Table_Example_Walkthrough.md>`
* This is a GATT server demo and its tutorial. This demo creates a GATT service by adding attributes one by one as defined by Bluedroid. The recommended method of adding attributes is presented in example above.
- :example:`bluetooth/gatt_server`
- :example_file:`GATT Server Example Walkthrough <bluetooth/gatt_server/tutorial/Gatt_Server_Example_Walkthrough.md>`
- :example:`bluetooth/bluedroid/ble/gatt_server`
- :example_file:`GATT Server Example Walkthrough <bluetooth/bluedroid/ble/gatt_server/tutorial/Gatt_Server_Example_Walkthrough.md>`
* This is a BLE SPP-Like demo. This demo, which acts as a GATT server, can receive data from UART and then send the data to the peer device automatically.
- :example:`bluetooth/ble_spp_server`
- :example:`bluetooth/bluedroid/ble/ble_spp_server`
API Reference
-------------

View File

@@ -11,9 +11,9 @@ Overview
Application Example
-------------------
Check :example:`bluetooth` folder in ESP-IDF examples, which contains the following application:
Check :example:`bluetooth/bluedroid/classic_bt` folder in ESP-IDF examples, which contains the following application:
* This is a SPP demo. This demo can discover the service, connect, send and recive SPP data :example:`bluetooth/bt_spp_acceptor`, :example:`bluetooth/bt_spp_initiator`
* This is a SPP demo. This demo can discover the service, connect, send and recive SPP data :example:`bluetooth/bluedroid/classic_bt/bt_spp_acceptor`, :example:`bluetooth/bluedroid/classic_bt/bt_spp_initiator`
API Reference
-------------

View File

@@ -10,6 +10,11 @@ Bluetooth API
Bluetooth Common <bt_common>
Bluetooth LE <bt_le>
Bluetooth Classic <classic_bt>
NimBLE <nimble/index>
ESP-IDF currently supports two host stacks. The Bluedroid based stack (default) supports classic Bluetooth as well as BLE. On the other hand, Apache NimBLE based stack is BLE only. For users to make a choice:
* For usecases involving classic Bluetooth as well as BLE, Bluedroid should be used.
* For BLE-only usecases, using NimBLE is recommended. It is less demanding in terms of code footprint and runtime memory, making it suitable for such scenarios.
For the overview of the ESP32 Bluetooth stack architecture, follow the links below:
@@ -17,13 +22,13 @@ For the overview of the ESP32 Bluetooth stack architecture, follow the links bel
* `ESP32 Bluetooth Architecture (PDF) [English] <http://espressif.com/sites/default/files/documentation/esp32_bluetooth_architecture_en.pdf>`_
* `ESP32 Bluetooth Architecture (PDF) [中文] <http://espressif.com/sites/default/files/documentation/esp32_bluetooth_architecture_cn.pdf>`_
Code examples for this API section are provided in the :example:`bluetooth` directory of ESP-IDF examples.
Code examples for this API section are provided in the :example:`bluetooth/bluedroid` directory of ESP-IDF examples.
The following examples contain detailed walkthroughs:
* :example_file:`GATT Client Example Walkthrough <bluetooth/gatt_client/tutorial/Gatt_Client_Example_Walkthrough.md>`
* :example_file:`GATT Server Service Table Example Walkthrough <bluetooth/gatt_server_service_table/tutorial/Gatt_Server_Service_Table_Example_Walkthrough.md>`
* :example_file:`GATT Server Example Walkthrough <bluetooth/gatt_server/tutorial/Gatt_Server_Example_Walkthrough.md>`
* :example_file:`GATT Security Client Example Walkthrough <bluetooth/gatt_security_client/tutorial/Gatt_Security_Client_Example_Walkthrough.md>`
* :example_file:`GATT Security Server Example Walkthrough <bluetooth/gatt_security_server/tutorial/Gatt_Security_Server_Example_Walkthrough.md>`
* :example_file:`GATT Client Multi-connection Example Walkthrough <bluetooth/gattc_multi_connect/tutorial/Gatt_Client_Multi_Connection_Example_Walkthrough.md>`
* :example_file:`GATT Client Example Walkthrough <bluetooth/bluedroid/ble/gatt_client/tutorial/Gatt_Client_Example_Walkthrough.md>`
* :example_file:`GATT Server Service Table Example Walkthrough <bluetooth/bluedroid/ble/gatt_server_service_table/tutorial/Gatt_Server_Service_Table_Example_Walkthrough.md>`
* :example_file:`GATT Server Example Walkthrough <bluetooth/bluedroid/ble/gatt_server/tutorial/Gatt_Server_Example_Walkthrough.md>`
* :example_file:`GATT Security Client Example Walkthrough <bluetooth/bluedroid/ble/gatt_security_client/tutorial/Gatt_Security_Client_Example_Walkthrough.md>`
* :example_file:`GATT Security Server Example Walkthrough <bluetooth/bluedroid/ble/gatt_security_server/tutorial/Gatt_Security_Server_Example_Walkthrough.md>`
* :example_file:`GATT Client Multi-connection Example Walkthrough <bluetooth/bluedroid/ble/gattc_multi_connect/tutorial/Gatt_Client_Multi_Connection_Example_Walkthrough.md>`

View File

@@ -0,0 +1,44 @@
NimBLE-based host APIs
**********************
Overview
========
Apache MyNewt NimBLE is a highly configurable and BT SIG qualifiable BLE stack providing both host and controller functionalities. ESP-IDF supports NimBLE host stack which is specifically ported for ESP32 platform and FreeRTOS. The underlying controller is still the same (as in case of Bluedroid) providing VHCI interface. Refer to `NimBLE user guide <http://mynewt.apache.org/latest/network/docs/index.html#>`_ for a complete list of features and additional information on NimBLE stack. Most features of NimBLE including BLE Mesh are supported by ESP-IDF. The porting layer is kept cleaner by maintaining all the existing APIs of NimBLE along with a single ESP-NimBLE API for initialization, making it simpler for the application developers.
Architecture
============
Currently, NimBLE host and controller support different transports such as UART and RAM between them. However, RAM transport cannot be used as is in case of ESP as ESP controller supports VHCI interface and buffering schemes used by NimBLE host is incompatible with that used by ESP controller. Therefore, a new transport between NimBLE host and ESP controller has been added. This is depicted in the figure below. This layer is responsible for maintaining pool of transport buffers and formatting buffers exchanges between host and controller as per the requirements.
.. figure:: ../../../../_static/esp32_nimble_stack.png
:align: center
:alt: ESP NimBLE Stack.
:scale: 50
ESP NimBLE Stack
Threading Model
===============
The NimBLE host can run inside the application thread or can have its own independent thread. This flexibility is inherently provided by NimBLE design. By default, a thread is spawned by the porting function ``nimble_port_freertos_init``. This behavior can be changed by overriding the same function. For BLE Mesh, additional thread (advertising thread) is used which keeps on feeding advertisement events to the main thread.
Programming Sequence
====================
To begin with, make sure that the NimBLE stack is enabled from menuconfig :ref:`choose NimBLE for the Bluetooth host <CONFIG_BT_HOST>`.
Typical programming sequence with NimBLE stack consists of the following steps:
* Initialize NVS flash using :cpp:func:`nvs_flash_init` API. This is because ESP controller uses NVS during initialization.
* Call :cpp:func:`esp_nimble_hci_and_controller_init` to initialize ESP controller as well as transport layer. This will also link the host and controller modules together. Alternatively, if ESP controller is already initialized, then :cpp:func:`esp_nimble_hci_init` can be called for the remaining initialization.
* Initialize the host stack using ``nimble_port_init``.
* Initialize the required NimBLE host configuration parameters and callbacks
* Perform application specific tasks/initialization
* Run the thread for host stack using ``nimble_port_freertos_init``
This documentation does not cover NimBLE APIs. Refer to `NimBLE tutorial <https://mynewt.apache.org/latest/network/docs/index.html#ble-user-guide>`_ for more details on the programming sequence/NimBLE APIs for different scenarios.
API Reference
=============
.. include:: /_build/inc/esp_nimble_hci.inc

View File

@@ -1,19 +1,28 @@
Configuration Options
Project Configuration
*********************
Introduction
============
ESP-IDF uses Kconfig_ system to provide a compile-time configuration mechanism. Kconfig is based around options of several types: integer, string, boolean. Kconfig files specify dependencies between options, default values of the options, the way the options are grouped together, etc.
ESP-IDF uses Kconfig_ system to provide a compile-time project configuration mechanism. Kconfig is based around options of several types: integer, string, boolean. Kconfig files specify dependencies between options, default values of the options, the way the options are grouped together, etc.
Applications developers can use ``make menuconfig`` build target to edit components' configuration. This configuration is saved inside ``sdkconfig`` file in the project root directory. Based on ``sdkconfig``, application build targets will generate ``sdkconfig.h`` file in the build directory, and will make sdkconfig options available to component makefiles.
.. _project-configuration-menu:
Project Configuration Menu
==========================
Application developers can open a terminal-based project configuration menu with the ``idf.py menuconfig`` build target.
After being updated, this configuration is saved inside ``sdkconfig`` file in the project root directory. Based on ``sdkconfig``, application build targets will generate ``sdkconfig.h`` file in the build directory, and will make sdkconfig options available to the project build system and source files.
(For the legacy GNU Make build system, the project configuration menu is opened with ``make menuconfig``.)
Using sdkconfig.defaults
========================
When updating ESP-IDF version, it is not uncommon to find that new Kconfig options are introduced. When this happens, application build targets will offer an interactive prompt to select values for the new options. New values are then written into ``sdkconfig`` file. To supress interactive prompts, applications can either define ``BATCH_BUILD`` environment variable, which will cause all prompts to be suppressed. This is the same effect as that of ``V`` or ``VERBOSE`` variables. Alternatively, ``defconfig`` build target can be used to update configuration for all new variables to the default values.
In some cases, such as when ``sdkconfig`` file is under revision control, the fact that ``sdkconfig`` file gets changed by the build system may be inconvenient. The build system offers a way to avoid this, in the form of ``sdkconfig.defaults`` file. This file is never touched by the build system, and must be created manually. It can contain all the options which matter for the given application. The format is the same as that of the ``sdkconfig`` file. Once ``sdkconfig.defaults`` is created, ``sdkconfig`` can be deleted and added to the ignore list of the revision control system (e.g. ``.gitignore`` file for git). Project build targets will automatically create ``sdkconfig`` file, populated with the settings from ``sdkconfig.defaults`` file, and the rest of the settings will be set to their default values. Note that when ``make defconfig`` is used, settings in sdkconfig will be overriden by the ones in ``sdkconfig.defaults``. For more information, see :ref:`custom-sdkconfig-defaults`.
In some cases, such as when ``sdkconfig`` file is under revision control, the fact that ``sdkconfig`` file gets changed by the build system may be inconvenient. The build system offers a way to avoid this, in the form of ``sdkconfig.defaults`` file. This file is never touched by the build system, and must be created manually. It can contain all the options which matter for the given application. The format is the same as that of the ``sdkconfig`` file. Once ``sdkconfig.defaults`` is created, ``sdkconfig`` can be deleted and added to the ignore list of the revision control system (e.g. ``.gitignore`` file for git). Project build targets will automatically create ``sdkconfig`` file, populated with the settings from ``sdkconfig.defaults`` file, and the rest of the settings will be set to their default values. Note that when ``idf.py defconfig`` is used, settings in sdkconfig will be overriden by the ones in ``sdkconfig.defaults``. For more information, see :ref:`custom-sdkconfig-defaults`.
Kconfig Formatting Rules
========================

View File

@@ -7,48 +7,47 @@ Application Example
- Ethernet basic example: :example:`ethernet/ethernet`.
- Ethernet iperf example: :example:`ethernet/iperf`.
PHY Interfaces
--------------
Ethernet Driver Model
---------------------
The configured PHY model(s) are set in software by configuring the eth_config_t structure for the given PHY.
* :component_file:`esp_eth/include/esp_eth.h`
Headers include a default configuration structure. These default configurations will need some members overriden or re-set before they can be used for a particular PHY hardware configuration. Consult the Ethernet example to see how this is done.
Ethernet Common Interface
-------------------------
* :component_file:`ethernet/include/eth_phy/phy.h` (common)
* :component_file:`ethernet/include/eth_phy/phy_tlk110.h`
* :component_file:`ethernet/include/eth_phy/phy_lan8720.h`
* :component_file:`ethernet/include/eth_phy/phy_ip101.h`
* :component_file:`esp_eth/include/esp_eth_com.h`
PHY Configuration Constants
^^^^^^^^^^^^^^^^^^^^^^^^^^^
Ethernet MAC Interface
----------------------
.. doxygenvariable:: phy_tlk110_default_ethernet_config
.. doxygenvariable:: phy_lan8720_default_ethernet_config
.. doxygenvariable:: phy_ip101_default_ethernet_config
* :component_file:`esp_eth/include/esp_eth_mac.h`
Ethernet PHY Interface
----------------------
API Reference - Ethernet
------------------------
* :component_file:`esp_eth/include/esp_eth_phy.h`
Ethernet PHY Common Registers
-----------------------------
* :component_file:`esp_eth/include/eth_phy_regs_struct.h`
API Reference - Driver Model
----------------------------
.. include:: /_build/inc/esp_eth.inc
API Reference - PHY Common
--------------------------
API Reference - Common Interface
--------------------------------
.. include:: /_build/inc/phy.inc
.. include:: /_build/inc/esp_eth_com.inc
API Reference - PHY TLK110
--------------------------
API Reference - MAC Interface
-----------------------------
.. include:: /_build/inc/phy_tlk110.inc
.. include:: /_build/inc/esp_eth_mac.inc
API Reference - PHY LAN8720
---------------------------
.. include:: /_build/inc/phy_lan8720.inc
API Reference - PHY IP101
-------------------------
.. include:: /_build/inc/phy_ip101.inc
API Reference - PHY Interface
-----------------------------
.. include:: /_build/inc/esp_eth_phy.inc

View File

@@ -51,9 +51,9 @@ An application interfaces with ESP-MESH via **ESP-MESH Events**. Since ESP-MESH
ESP-MESH System Events Delivery
The :cpp:type:`mesh_event_id_t` defines all possible ESP-MESH system events and can indicate events such as the connection/disconnection of parent/child. Before ESP-MESH system events can be used, the application must register a **Mesh Event Callback** via :cpp:func:`esp_mesh_set_config`. The callback is used to receive events from the ESP-MESH stack as well as the LwIP Stack and should contain handlers for each event relevant to the application.
The :cpp:type:`mesh_event_id_t` defines all possible ESP-MESH events and can indicate events such as the connection/disconnection of parent/child. Before ESP-MESH events can be used, the application must register a **Mesh Events handler** via :cpp:func:`esp_event_handler_register` to the default event task. Should contain handlers for each event relevant to the application.
Typical use cases of system events include using events such as :cpp:enumerator:`MESH_EVENT_PARENT_CONNECTED` and :cpp:enumerator:`MESH_EVENT_CHILD_CONNECTED` to indicate when a node can begin transmitting data upstream and downstream respectively. Likewise, :cpp:enumerator:`MESH_EVENT_ROOT_GOT_IP` and :cpp:enumerator:`MESH_EVENT_ROOT_LOST_IP` can be used to indicate when the root node can and cannot transmit data to the external IP network.
Typical use cases of mesh events include using events such as :cpp:enumerator:`MESH_EVENT_PARENT_CONNECTED` and :cpp:enumerator:`MESH_EVENT_CHILD_CONNECTED` to indicate when a node can begin transmitting data upstream and downstream respectively. Likewise, :cpp:enumerator:`IP_EVENT_STA_GOT_IP` and :cpp:enumerator:`IP_EVENT_STA_LOST_IP` can be used to indicate when the root node can and cannot transmit data to the external IP network.
.. warning::
When using ESP-MESH under self-organized mode, users must ensure that no calls to Wi-Fi API are made. This is due to the fact that the self-organizing mode will internally make Wi-Fi API calls to connect/disconnect/scan etc. **Any Wi-Fi calls from the application (including calls from callbacks and handlers of Wi-Fi events) may interfere with ESP-MESH's self-organizing behavior**. Therefore, user's should not call Wi-Fi APIs after :cpp:func:`esp_mesh_start` is called, and before :cpp:func:`esp_mesh_stop` is called.
@@ -81,8 +81,6 @@ The following code snippet demonstrates how to initialize LwIP for ESP-MESH appl
*/
ESP_ERROR_CHECK(tcpip_adapter_dhcps_stop(TCPIP_ADAPTER_IF_AP));
ESP_ERROR_CHECK(tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_STA));
/* do not specify system event callback, use NULL instead. */
ESP_ERROR_CHECK(esp_event_loop_init(NULL, NULL));
.. note::
@@ -108,12 +106,15 @@ The prerequisites for starting ESP-MESH is to initialize LwIP and Wi-Fi, The fol
*/
ESP_ERROR_CHECK(tcpip_adapter_dhcps_stop(TCPIP_ADAPTER_IF_AP));
ESP_ERROR_CHECK(tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_STA));
/* do not specify system event callback, use NULL instead. */
ESP_ERROR_CHECK(esp_event_loop_init(NULL, NULL));
/* event initialization */
ESP_ERROR_CHECK(esp_event_loop_create_default());
/* Wi-Fi initialization */
wifi_init_config_t config = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&config));
/* register IP events handler */
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &ip_event_handler, NULL));
ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_FLASH));
ESP_ERROR_CHECK(esp_wifi_start());
@@ -134,6 +135,8 @@ The following code snippet demonstrates how to initialize ESP-MESH
/* mesh initialization */
ESP_ERROR_CHECK(esp_mesh_init());
/* register mesh events handler */
ESP_ERROR_CHECK(esp_event_handler_register(MESH_EVENT, ESP_EVENT_ANY_ID, &mesh_event_handler, NULL));
.. _mesh-configuring-mesh:
@@ -149,9 +152,6 @@ ESP-MESH is configured via :cpp:func:`esp_mesh_set_config` which receives its ar
+==================+=====================================+
| Channel | Range from 1 to 14 |
+------------------+-------------------------------------+
| Event Callback | Callback for Mesh Events, |
| | see :cpp:type:`mesh_event_cb_t` |
+------------------+-------------------------------------+
| Mesh ID | ID of ESP-MESH Network, |
| | see :cpp:type:`mesh_addr_t` |
+------------------+-------------------------------------+
@@ -173,8 +173,6 @@ The following code snippet demonstrates how to configure ESP-MESH.
mesh_cfg_t cfg = MESH_INIT_CONFIG_DEFAULT();
/* mesh ID */
memcpy((uint8_t *) &cfg.mesh_id, MESH_ID, 6);
/* mesh event callback */
cfg.event_cb = &mesh_event_handler;
/* channel (must match the router's channel) */
cfg.channel = CONFIG_MESH_CHANNEL;
/* router */

View File

@@ -1,5 +1,7 @@
Smart Config
============
SmartConfig
===========
:link_to_translation:`zh_CN:[中文]`
API Reference
-------------

View File

@@ -4,23 +4,23 @@ LED Control
Introduction
------------
The LED control (LEDC) module is primarily designed to control the intensity of LEDs, although it can be used to generate PWM signals for other purposes as well. It has 16 channels which can generate independent waveforms, that can be used to drive e.g. RGB LED devices.
The LED control (LEDC) peripheral is primarily designed to control the intensity of LEDs, although it can also be used to generate PWM signals for other purposes as well. It has 16 channels which can generate independent waveforms that can be used, for example, to drive RGB LED devices.
Half of all LEDC's channels provide high speed mode of operation. This mode offers implemented in hardware, automatic and glitch free change of PWM duty cycle. The other half of channels operate in a low speed mode, where the moment of change depends on the application software. Each group of channels is also able to use different clock sources but this feature is not implemented in the API.
A half of LEDC's channels operate in high speed mode. This mode is implemented in hardware and offers automatic and glitch-free changing of the PWM duty cycle. The other half of channels operate in low speed mode, where the moment of change depends on the application software. Each group of channels is also able to use different clock sources, but this feature is not yet supported in the LEDC driver.
The PWM controller also has the ability to automatically increase or decrease the duty cycle gradually, allowing for fades without any processor interference.
The PWM controller can automatically increase or decrease the duty cycle gradually, allowing for fades without any processor interference.
Functionality Overview
----------------------
Getting LEDC to work on specific channel in either :ref:`high or low speed mode <ledc-api-high_low_speed_mode>` is done in three steps:
Getting LEDC to work on a specific channel in either :ref:`high or low speed mode <ledc-api-high_low_speed_mode>` is done in three steps:
1. :ref:`ledc-api-configure-timer` to determine PWM signal's frequency and the a number (resolution of duty range).
1. :ref:`ledc-api-configure-timer` by specifying the PWM signal's frequency and duty cycle resolution.
2. :ref:`ledc-api-configure-channel` by associating it with the timer and GPIO to output the PWM signal.
3. :ref:`ledc-api-change-pwm-signal` that drives the output to change LED's intensity. This may be done under full control by software or with help of hardware fading functions.
3. :ref:`ledc-api-change-pwm-signal` that drives the output in order to change LED's intensity. This can be done under the full control of software or with hardware fading functions.
In an optional step it is also possible to set up an interrupt on the fade end.
As an optional step, it is also possible to set up an interrupt on the fade end.
.. figure:: ../../../_static/ledc-api-settings.jpg
:align: center
@@ -35,12 +35,14 @@ In an optional step it is also possible to set up an interrupt on the fade end.
Configure Timer
^^^^^^^^^^^^^^^
Setting of the timer is done by calling function :cpp:func:`ledc_timer_config`. This function should be provided with a data structure :cpp:type:`ledc_timer_config_t` that contains the following configuration settings:
Setting the timer is done by calling the function :cpp:func:`ledc_timer_config` and passing to it a data structure :cpp:type:`ledc_timer_config_t` that contains the following configuration settings:
* The timer number :cpp:type:`ledc_timer_t` and a speed mode :cpp:type:`ledc_mode_t`.
* The PWM signal's frequency and resolution of PWM's duty value changes.
- Timer number :cpp:type:`ledc_timer_t`
- Speed mode :cpp:type:`ledc_mode_t`
- PWM signal frequency
- Resolution of PWM duty
The frequency and the duty resolution are interdependent. The higher the PWM frequency, the lower duty resolution is available and vice versa. This relationship may became important, if you are planning to use this API for purposes other that changing intensity of LEDs. Check section :ref:`ledc-api-supported-range-frequency-duty-resolution` for more details.
The frequency and the duty resolution are interdependent. The higher the PWM frequency, the lower duty resolution is available, and vice versa. This relationship might be important if you are planning to use this API for purposes other than changing the intensity of LEDs. For more details, see Section :ref:`ledc-api-supported-range-frequency-duty-resolution`.
.. _ledc-api-configure-channel:
@@ -48,11 +50,11 @@ The frequency and the duty resolution are interdependent. The higher the PWM fre
Configure Channel
^^^^^^^^^^^^^^^^^
Having set up the timer, the next step is to configure selected channel (one out of :cpp:type:`ledc_channel_t`). This is done by calling function :cpp:func:`ledc_channel_config`.
When the timer is set up, configure a selected channel (one out of :cpp:type:`ledc_channel_t`). This is done by calling the function :cpp:func:`ledc_channel_config`.
In similar way, like with the timer configuration, the channel setup function should be provided with specific structure :cpp:type:`ledc_channel_config_t`, that contains channel's configuration parameters.
Similar to the timer configuration, the channel setup function should be passed a structure :cpp:type:`ledc_channel_config_t` that contains the channel's configuration parameters.
At this point channel should became operational and start generating PWM signal of frequency determined by the timer settings and the duty on selected GPIO, as configured in :cpp:type:`ledc_channel_config_t`. The channel operation / the signal generation may be suspended at any time by calling function :cpp:func:`ledc_stop`.
At this point, the channel should start operating and generating the PWM signal on the selected GPIO, as configured in :cpp:type:`ledc_channel_config_t`, with the frequency specified in the timer settings and the given duty cycle. The channel operation (signal generation) can be suspended at any time by calling the function :cpp:func:`ledc_stop`.
.. _ledc-api-change-pwm-signal:
@@ -60,23 +62,25 @@ At this point channel should became operational and start generating PWM signal
Change PWM Signal
^^^^^^^^^^^^^^^^^
Once the channel is operational and generating the PWM signal of constant duty and frequency, there are couple of ways to change this signal. When driving LEDs we are changing primarily the duty to vary the light intensity. See the two section below how to change the duty by software or with hardware fading. If required, we can change signal's frequency as well and this is covered in section :ref:`ledc-api-change-pwm-frequency`.
Once the channel starts operating and generating the PWM signal with the constant duty cycle and frequency, there are a couple of ways to change this signal. When driving LEDs, primarily the duty cycle is changed to vary the light intensity.
The following two sections describe how to change the duty cycle using software and hardware fading. If required, the signal's frequency can also be changed; it is covered in Section :ref:`ledc-api-change-pwm-frequency`.
Change PWM Duty by Software
"""""""""""""""""""""""""""
Setting of the duty is done by first calling dedicated function :cpp:func:`ledc_set_duty` and then calling :cpp:func:`ledc_update_duty` to make the change effective. To check the value currently set, there is a corresponding ``_get_`` function :cpp:func:`ledc_get_duty`.
Another way to set the duty, and some other channel parameters as well, is by calling :cpp:func:`ledc_channel_config` discussed in the previous section.
The range of the duty value entered into functions depends on selected ``duty_resolution`` and should be from 0 to (2 ** duty_resolution) - 1. For example, if selected duty resolution is 10, then the duty range is from 0 to 1023. This provides the resolution of ~0.1%.
Change PWM Duty with Hardware Fading
Change PWM Duty Cycle Using Software
""""""""""""""""""""""""""""""""""""
The LEDC hardware provides the means to gradually fade from one duty value to another. To use this functionality first enable fading with :cpp:func:`ledc_fade_func_install`. Then configure it by calling one of available fading functions:
To set the duty cycle, use the dedicated function :cpp:func:`ledc_set_duty`. After that, call :cpp:func:`ledc_update_duty` to activeate the changes. To check the currently set value, use the corresponding ``_get_`` function :cpp:func:`ledc_get_duty`.
Another way to set the duty cycle, as well as some other channel parameters, is by calling :cpp:func:`ledc_channel_config` covered in Section :ref:`ledc-api-configure-channel`.
The range of the duty cycle values passed to functions depends on selected ``duty_resolution`` and should be from ``0`` to ``(2 ** duty_resolution) - 1``. For example, if the selected duty resolution is 10, then the duty cycle values can range from 0 to 1023. This provides the resolution of ~0.1%.
Change PWM Duty Cycle using Hardware
""""""""""""""""""""""""""""""""""""
The LEDC hardware provides the means to gradually transition from one duty cycle value to another. To use this functionality, enable fading with :cpp:func:`ledc_fade_func_install` and then configure it by calling one of the available fading functions:
* :cpp:func:`ledc_set_fade_with_time`
* :cpp:func:`ledc_set_fade_with_step`
@@ -84,7 +88,7 @@ The LEDC hardware provides the means to gradually fade from one duty value to an
Finally start fading with :cpp:func:`ledc_fade_start`.
If not required anymore, fading and associated interrupt may be disabled with :cpp:func:`ledc_fade_func_uninstall`.
If not required anymore, fading and an associated interrupt can be disabled with :cpp:func:`ledc_fade_func_uninstall`.
.. _ledc-api-change-pwm-frequency:
@@ -92,34 +96,32 @@ If not required anymore, fading and associated interrupt may be disabled with :c
Change PWM Frequency
""""""""""""""""""""
The LEDC API provides several means to change the PWM frequency "on the fly".
The LEDC API provides several ways to change the PWM frequency "on the fly":
* One of options is to call :cpp:func:`ledc_set_freq`. There is a corresponding function :cpp:func:`ledc_get_freq` to check what frequency is currently set.
* Another option to change the frequency, and the duty resolution as well, is by calling :cpp:func:`ledc_bind_channel_timer` to bind other timer to the channel.
* Finally the channel's timer may be changed by calling :cpp:func:`ledc_channel_config`.
* Set the frequency by calling :cpp:func:`ledc_set_freq`. There is a corresponding function :cpp:func:`ledc_get_freq` to check the current frequency.
* Change the frequency and the duty resolution by calling :cpp:func:`ledc_bind_channel_timer` to bind some other timer to the channel.
* Change the channel's timer by calling :cpp:func:`ledc_channel_config`.
More Control Over PWM
"""""""""""""""""""""
There are couple of lower level timer specific functions, that may be used to provide additional means to change the PWM settings:
There are several lower level timer-specific functions that can be used to change PWM settings:
* :cpp:func:`ledc_timer_set`
* :cpp:func:`ledc_timer_rst`
* :cpp:func:`ledc_timer_pause`
* :cpp:func:`ledc_timer_resume`
The first two functions are called "behind the scenes" by :cpp:func:`ledc_channel_config` to provide "clean" start up of a timer after is it configured.
The first two functions are called "behind the scenes" by :cpp:func:`ledc_channel_config` to provide a "clean" startup of a timer after it is configured.
Use Interrupts
^^^^^^^^^^^^^^
When configuring a LEDC channel, one of parameters selected within :cpp:type:`ledc_channel_config_t` is :cpp:type:`ledc_intr_type_t` and allows to enable an interrupt on fade completion.
When configuring an LEDC channel, one of the parameters selected within :cpp:type:`ledc_channel_config_t` is :cpp:type:`ledc_intr_type_t` which triggers an interrupt on fade completion.
Registration of a handler to service this interrupt is done by calling :cpp:func:`ledc_isr_register`.
For registration of a handler to address this interrupt, call :cpp:func:`ledc_isr_register`.
.. _ledc-api-high_low_speed_mode:
@@ -127,39 +129,39 @@ Registration of a handler to service this interrupt is done by calling :cpp:func
LEDC High and Low Speed Mode
----------------------------
Out of the total 8 timers and 16 channels available in the LED PWM Controller, half of them are dedicated to operate in the high speed mode and the other half in the low speed mode. Selection of the low or high speed "capable" timer or the channel is done with parameter :cpp:type:`ledc_mode_t` that is present in applicable function calls.
Of the total 8 timers and 16 channels available in the LED PWM Controller, half of them are dedicated to operation in high speed mode and the other half in low speed mode. Selection of a low or high speed timer or channel is done with the parameter :cpp:type:`ledc_mode_t` that can be found in applicable function calls.
The advantage of the high speed mode is h/w supported, glitch-free changeover of the timer settings. This means that if the timer settings are modified, the changes will be applied automatically after the next overflow interrupt of the timer. In contrast, when updating the low-speed timer, the change of settings should be specifically triggered by software. The LEDC API is doing it "behind the scenes", e.g. when :cpp:func:`ledc_timer_config` or :cpp:func:`ledc_timer_set` is called.
The advantage of high speed mode is hardware-supported, glitch-free changeover of the timer settings. This means that if the timer settings are modified, the changes will be applied automatically on the next overflow interrupt of the timer. In contrast, when updating the low-speed timer, the change of settings should be explicitly triggered by software. The LEDC driver handles it in the background, e.g., when :cpp:func:`ledc_timer_config` or :cpp:func:`ledc_timer_set` is called.
For additional details regarding speed modes please refer to `ESP32 Technical Reference Manual <https://espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf>`_ (PDF). Note that support for ``SLOW_CLOCK`` mentioned in this manual is not implemented in the LEDC API.
For additional details regarding speed modes, refer to `ESP32 Technical Reference Manual <https://espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf>`_ (PDF). Please note that the support for ``SLOW_CLOCK`` mentioned in this manual is not yet supported in the LEDC driver.
.. _ledc-api-supported-range-frequency-duty-resolution:
Supported Range of Frequency and Duty Resolution
------------------------------------------------
Supported Range of Frequency and Duty Resolutions
-------------------------------------------------
The LED PWM Controller is designed primarily to drive LEDs and provides wide resolution of PWM duty settings. For instance for the PWM frequency at 5 kHz, the maximum duty resolution is 13 bits. It means that the duty may be set anywhere from 0 to 100% with resolution of ~0.012% (2 ** 13 = 8192 discrete levels of the LED intensity).
The LED PWM Controller is designed primarily to drive LEDs. It provides a wide resolution for PWM duty cycle settings. For instance, the PWM frequency of 5 kHz can have the maximum duty resolution of 13 bits. It means that the duty can be set anywhere from 0 to 100% with a resolution of ~0.012% (2 ** 13 = 8192 discrete levels of the LED intensity).
The LEDC may be used for providing signals at much higher frequencies to clock other devices, e.g. a digital camera module. In such a case the maximum available frequency is 40 MHz with duty resolution of 1 bit. This means that duty is fixed at 50% and cannot be adjusted.
The LEDC can be used for generating signals at much higher frequencies that are sufficient enough to clock other devices, e.g., a digital camera module. In this case, the maximum available frequency is 40 MHz with duty resolution of 1 bit. This means that the duty cycle is fixed at 50% and cannot be adjusted.
The API is designed to report an error when trying to set a frequency and a duty resolution that is out of the range of LEDC's hardware. For example, an attempt to set the frequency at 20 MHz and the duty resolution of 3 bits will result in the following error reported on a serial monitor:
The LEDC API is designed to report an error when trying to set a frequency and a duty resolution that exceed the range of LEDC's hardware. For example, an attempt to set the frequency to 20 MHz and the duty resolution to 3 bits will result in the following error reported on a serial monitor:
.. highlight:: none
::
E (196) ledc: requested frequency and duty resolution can not be achieved, try reducing freq_hz or duty_resolution. div_param=128
E (196) ledc: requested frequency and duty resolution cannot be achieved, try reducing freq_hz or duty_resolution. div_param=128
In such a case either the duty resolution or the frequency should be reduced. For example setting the duty resolution at 2 will resolve this issue and provide possibility to set the duty with 25% steps, i.e. at 25%, 50% or 75%.
In such a situation, either the duty resolution or the frequency must be reduced. For example, setting the duty resolution to 2 will resolve this issue and will make it possible to set the duty cycle at 25% steps, i.e., at 25%, 50% or 75%.
The LEDC API will also capture and report an attempt to configure frequency / duty resolution combination that is below the supported minimum, e.g.:
The LEDC driver will also capture and report attempts to configure frequency / duty resolution combinations that are below the supported minimum, e.g.:
::
E (196) ledc: requested frequency and duty resolution can not be achieved, try increasing freq_hz or duty_resolution. div_param=128000000
E (196) ledc: requested frequency and duty resolution cannot be achieved, try increasing freq_hz or duty_resolution. div_param=128000000
Setting of the duty resolution is normally done using :cpp:type:`ledc_timer_bit_t`. This enumeration covers the range from 10 to 15 bits. If a smaller duty resolution is required (below 10 down to 1), enter the equivalent numeric values directly.
The duty resolution is normally set using :cpp:type:`ledc_timer_bit_t`. This enumeration covers the range from 10 to 15 bits. If a smaller duty resolution is required (from 10 down to 1), enter the equivalent numeric values directly.
Application Example

View File

@@ -4,12 +4,12 @@ SDMMC Host Driver
Overview
--------
On the ESP32, SDMMC host peripheral has two slots:
ESP32's SDMMC host peripheral has two slots:
- Slot 0 (:c:macro:`SDMMC_HOST_SLOT_0`) is an 8-bit slot. It uses ``HS1_*`` signals in the PIN MUX.
- Slot 1 (:c:macro:`SDMMC_HOST_SLOT_1`) is a 4-bit slot. It uses ``HS2_*`` signals in the PIN MUX.
Pin mappings of these slots are given in the following table:
Pin mappings of these slots are given in the table below.
+--------+-------------+-------------+
| Signal | Slot 0 | Slot 1 |
@@ -39,44 +39,55 @@ Pin mappings of these slots are given in the following table:
| WP | any input via GPIO matrix |
+--------+---------------------------+
Card Detect and Write Protect signals can be routed to arbitrary pins using GPIO matrix. To use these pins, set ``gpio_cd`` and ``gpio_wp`` members of :cpp:class:`sdmmc_slot_config_t` structure before calling :cpp:func:`sdmmc_host_init_slot`. Note that it is not advised to specify Card Detect pin when working with SDIO cards, because in ESP32 card detect signal can also trigger SDIO slave interrupt.
The Card Detect and Write Protect signals can be routed to arbitrary pins using the GPIO matrix. To reserve the pins, set the ``gpio_cd`` and ``gpio_wp`` members of the :cpp:class:`sdmmc_slot_config_t` structure before calling :cpp:func:`sdmmc_host_init_slot`. Please note that it is not advised to specify a Card Detect pin when working with SDIO cards, because the card detect signal in ESP32 can also trigger SDIO slave interrupt.
.. warning::
Pins used by slot 0 (``HS1_*``) are also used to connect SPI flash chip in ESP-WROOM32 and ESP32-WROVER modules. These pins can not be shared between SD card and SPI flash. If you need to use Slot 0, connect SPI flash to different pins and set Efuses accordingly.
Pins used by Slot 0 (``HS1_*``) are also used to connect the SPI flash chip in ESP32-WROOM and ESP32-WROVER modules. These pins cannot be shared between an SD card and SPI flash. If you need to use Slot 0, connect SPI flash to different pins and set eFuses accordingly.
Supported speed modes
Supported Speed Modes
---------------------
SDMMC Host driver supports the following speed modes:
- Default Speed (20MHz), 4-line/1-line (with SD cards), and 8-line (with 3.3V eMMC).
- High Speed (40MHz), 4-line/1-line (with SD cards), and 8-line (with 3.3V eMMC)
- High Speed DDR (40MHz), 4-line (with 3.3V eMMC)
- Default Speed (20 MHz), 4-line/1-line (with SD cards), and 8-line (with 3.3 V eMMC)
- High Speed (40 MHz), 4-line/1-line (with SD cards), and 8-line (with 3.3 V eMMC)
- High Speed DDR (40 MHz), 4-line (with 3.3 V eMMC)
Not supported at present are:
Speed modes not supported at present:
- High Speed DDR mode, 8-line eMMC
- UHS-I 1.8V modes, 4-line SD cards
- UHS-I 1.8 V modes, 4-line SD cards
Using the SDMMC Host driver
Using the SDMMC Host Driver
---------------------------
Of all the funtions listed below, only :cpp:func:`sdmmc_host_init`, :cpp:func:`sdmmc_host_init_slot`, and :cpp:func:`sdmmc_host_deinit` will be used directly by most applications.
Of all the functions listed below, only the following ones will be used directly by most applications:
Other functions, such as :cpp:func:`sdmmc_host_set_bus_width`, :cpp:func:`sdmmc_host_set_card_clk`, and :cpp:func:`sdmmc_host_do_transaction` will be called by the SD/MMC protocol layer via function pointers in :cpp:class:`sdmmc_host_t` structure.
- :cpp:func:`sdmmc_host_init`
- :cpp:func:`sdmmc_host_init_slot`
- :cpp:func:`sdmmc_host_deinit`
Configuring bus width and frequency
Other functions, such as the ones given below, will be called by the SD/MMC protocol layer via function pointers in the :cpp:class:`sdmmc_host_t` structure:
- :cpp:func:`sdmmc_host_set_bus_width`
- :cpp:func:`sdmmc_host_set_card_clk`
- :cpp:func:`sdmmc_host_do_transaction`
Configuring Bus Width and Frequency
-----------------------------------
With the default initializers for :cpp:class:`sdmmc_host_t` and :cpp:class:`sdmmc_slot_config_t` (:c:macro:`SDMMC_HOST_DEFAULT` and :c:macro:`SDMMC_SLOT_CONFIG_DEFAULT`), SDMMC Host driver will attempt to use widest bus supported by the card (4 lines for SD, 8 lines for eMMC) and 20MHz frequency.
With the default initializers for :cpp:class:`sdmmc_host_t` and :cpp:class:`sdmmc_slot_config_t` (:c:macro:`SDMMC_HOST_DEFAULT` and :c:macro:`SDMMC_SLOT_CONFIG_DEFAULT`), SDMMC Host driver will attempt to use the widest bus supported by the card (4 lines for SD, 8 lines for eMMC) and the frequency of 20 MHz.
In designs where communication at 40MHz frequency can be achieved, it is possible to increase the bus frequency to by changing ``max_freq_khz`` field of :cpp:class:`sdmmc_host_t`::
In the designs where communication at 40 MHz frequency can be achieved, it is possible to increase the bus frequency by changing the ``max_freq_khz`` field of :cpp:class:`sdmmc_host_t`::
sdmmc_host_t host = SDMMC_HOST_DEFAULT();
host.max_freq_khz = SDMMC_FREQ_HIGHSPEED;
To configure bus width, set ``width`` field of :cpp:class:`sdmmc_slot_config_t`. For example, to set 1-line mode::
To configure the bus width, set the ``width`` field of :cpp:class:`sdmmc_slot_config_t`. For example, to set 1-line mode::
sdmmc_slot_config_t slot = SDMMC_SLOT_CONFIG_DEFAULT();
slot.width = 1;
@@ -87,9 +98,10 @@ See also
See :doc:`SD/SDIO/MMC Driver <../storage/sdmmc>` for the higher level driver which implements the protocol layer.
See :doc:`SD SPI Host Driver <sdspi_host>` for a similar driver which uses SPI controller and is limited to SPI mode of SD protocol.
See :doc:`SD SPI Host Driver <sdspi_host>` for a similar driver which uses the SPI controller and is limited to SD protocol's SPI mode.
See :doc:`sd_pullup_requirements` for pullup support and compatibilities of modules and development kits.
See :doc:`sd_pullup_requirements` for pullup support and compatiblities about modules and devkits.
API Reference
-------------

View File

@@ -1,21 +1,21 @@
TIMER
Timer
=====
Introduction
------------
The ESP32 chip contains two hardware timer groups. Each group has two general-purpose hardware timers. They are all 64-bit generic timers based on 16-bit prescalers and 64-bit auto-reload-capable up / down counters.
The ESP32 chip contains two hardware timer groups. Each group has two general-purpose hardware timers. They are all 64-bit generic timers based on 16-bit prescalers and 64-bit up / down counters which are capable of being auto-reloaded.
Functional Overview
-------------------
Typical steps to configure an operate the timer are described in the following sections:
The following sections of this document cover the typical steps to configure and operate a timer:
* :ref:`timer-api-timer-initialization` - what parameters should be set up to get the timer working and what specific functionality is provided depending on the set up.
* :ref:`timer-api-timer-control` - how to read the timer's value, pause / start the timer, and change how it operates.
* :ref:`timer-api-alarms` - setting and using alarms.
* :ref:`timer-api-interrupts`- how to enable and use interrupts.
* :ref:`timer-api-timer-initialization` - covers which parameters should be set up to get the timer working, and also what specific functionality is provided depending on the timer configuration.
* :ref:`timer-api-timer-control` - describes how to read a timer's value, pause or start a timer, and change how it operates.
* :ref:`timer-api-alarms` - shows how to set and use alarms.
* :ref:`timer-api-interrupts`- explains how to enable and use interrupts.
.. _timer-api-timer-initialization:
@@ -23,18 +23,18 @@ Typical steps to configure an operate the timer are described in the following s
Timer Initialization
^^^^^^^^^^^^^^^^^^^^
The two timer groups on-board of the ESP32 are identified using :cpp:type:`timer_group_t`. Individual timers in a group are identified with :cpp:type:`timer_idx_t`. The two groups, each having two timers, provide the total of four individual timers to our disposal.
The two ESP32 timer groups, with two timers in each, provide the total of four individual timers for use. An ESP32 timer group should be identified using :cpp:type:`timer_group_t`. An individual timer in a group should be identified with :cpp:type:`timer_idx_t`.
Before starting the timer, it should be initialized by calling :cpp:func:`timer_init`. This function should be provided with a structure :cpp:type:`timer_config_t` to define how timer should operate. In particular the following timer's parameters may be set:
First of all, the timer should be initialized by calling the function :cpp:func:`timer_init` and passing a structure :cpp:type:`timer_config_t` to it to define how the timer should operate. In particular, the following timer parameters can be set:
* **Divider**: How quickly the timer's counter is "ticking". This depends on the setting of :cpp:member:`divider`, that will be used as divisor of the incoming 80 MHz APB_CLK clock.
* **Mode**: If the the counter is incrementing or decrementing, defined using :cpp:member:`counter_dir` by selecting one of values from :cpp:type:`timer_count_dir_t`.
* **Counter Enable**: If the counter is enabled, then it will start incrementing / decrementing immediately after calling :cpp:func:`timer_init`. This action is set using :cpp:member:`counter_en` by selecting one of vales from :cpp:type:`timer_start_t`.
* **Alarm Enable**: Determined by the setting of :cpp:member:`alarm_en`.
* **Auto Reload**: Whether the counter should :cpp:member:`auto_reload` a specific initial value on the timer's alarm, or continue incrementing or decrementing.
* **Interrupt Type**: Whether an interrupt is triggered on timer's alarm. Set the value defined in :cpp:type:`timer_intr_mode_t`.
* **Divider**: Sets how quickly the timer's counter is "ticking". The setting :cpp:member:`divider` is used as a divisor of the incoming 80 MHz APB_CLK clock.
* **Mode**: Sets if the counter should be incrementing or decrementing. It can be defined using :cpp:member:`counter_dir` by selecting one of the values from :cpp:type:`timer_count_dir_t`.
* **Counter Enable**: If the counter is enabled, it will start incrementing / decrementing immediately after calling :cpp:func:`timer_init`. You can change the behavior with :cpp:member:`counter_en` by selecting one of the values from :cpp:type:`timer_start_t`.
* **Alarm Enable**: Can be set using :cpp:member:`alarm_en`.
* **Auto Reload**: Sets if the counter should :cpp:member:`auto_reload` the initial counter value on the timer's alarm or continue incrementing or decrementing.
* **Interrupt Type**: Select which interrupt type should be triggered on the timer's alarm. Set the value defined in :cpp:type:`timer_intr_mode_t`.
To get the current values of the timers settings, use function :cpp:func:`timer_get_config`.
To get the current values of the timer's settings, use the function :cpp:func:`timer_get_config`.
.. _timer-api-timer-control:
@@ -42,35 +42,40 @@ To get the current values of the timers settings, use function :cpp:func:`timer_
Timer Control
^^^^^^^^^^^^^
Once the timer is configured and enabled, it is already "ticking". To check it's current value call :cpp:func:`timer_get_counter_value` or :cpp:func:`timer_get_counter_time_sec`. To set the timer to specific starting value call :cpp:func:`timer_set_counter_value`.
Once the timer is enabled, its counter starts running. To enable the timer, call the function :cpp:func:`timer_init` with :cpp:member:`counter_en` set to ``true``, or call :cpp:func:`timer_start`. You can specify the timer's initial counter value by calling :cpp:func:`timer_set_counter_value`. To check the timer's current value, call :cpp:func:`timer_get_counter_value` or :cpp:func:`timer_get_counter_time_sec`.
The timer may be paused at any time by calling :cpp:func:`timer_pause`. To start it again call :cpp:func:`timer_start`.
To pause the timer at any time, call :cpp:func:`timer_pause`. To resume it, call :cpp:func:`timer_start`.
To change how the timer operates you can call once more :cpp:func:`timer_init` described in section :ref:`timer-api-timer-initialization`. Another option is to use dedicated functions to change individual settings:
To reconfigure the timer, you can call :cpp:func:`timer_init`. This function is described in Section :ref:`timer-api-timer-initialization`.
* **Divider** value - :cpp:func:`timer_set_divider`. **Note:** the timer should be paused when changing the divider to avoid unpredictable results. If the timer is already running, :cpp:func:`timer_set_divider` will first pause the timer, change the divider, and finally start the timer again.
* **Mode** (whether the counter incrementing or decrementing) - :cpp:func:`timer_set_counter_mode`
* **Auto Reload** counter on alarm - :cpp:func:`timer_set_auto_reload`
You can also reconfigure the timer by using dedicated functions to change individual settings:
============= =================================== ==========================================================================
Setting Dedicated Function Description
============= =================================== ==========================================================================
Divider :cpp:func:`timer_set_divider` Change the rate of ticking. To avoid unpredictable results, the timer should be paused when changing the divider. If the timer is running, :cpp:func:`timer_set_divider` pauses it, change the setting, and start the timer again.
Mode :cpp:func:`timer_set_counter_mode` Set if the counter should be incrementing or decrementing
Auto Reload :cpp:func:`timer_set_auto_reload` Set if the initial counter value should be reloaded on the timer's alarm
============= =================================== ==========================================================================
.. _timer-api-alarms:
Alarms
^^^^^^
To set an alarm, call function :cpp:func:`timer_set_alarm_value` and then enable it with :cpp:func:`timer_set_alarm`. The alarm may be also enabled during the timer initialization stage, when :cpp:func:`timer_init` is called.
To set an alarm, call the function :cpp:func:`timer_set_alarm_value` and then enable the alarm using :cpp:func:`timer_set_alarm`. The alarm can also be enabled during the timer initialization stage, when :cpp:func:`timer_init` is called.
After the alarm is enabled and the timer reaches the alarm value, depending on configuration, the following two actions may happen:
After the alarm is enabled, and the timer reaches the alarm value, the following two actions can occur depending on the configuration:
* An interrupt will be triggered, if previously configured. See section :ref:`timer-api-interrupts` how to configure interrupts.
* When :cpp:member:`auto_reload` is enabled, the timer's counter will be reloaded to start counting from specific initial value. The value to start should be set in advance with :cpp:func:`timer_set_counter_value`.
* An interrupt will be triggered if previously configured. See Section :ref:`timer-api-interrupts` on how to configure interrupts.
* When :cpp:member:`auto_reload` is enabled, the timer's counter will automatically be reloaded to start counting again from a previously configured value. This value should be set in advance with :cpp:func:`timer_set_counter_value`.
.. note::
* The alarm will be triggered immediately, if an alarm value is set and the timer has already passed this value.
* Once triggered the alarm will be disabled automatically and needs to be re-armed to trigger again.
* If an alarm value is set and the timer has already reached this value, the alarm is triggered immediately.
* Once triggered, the alarm is disabled automatically and needs to be re-enabled to trigger again.
To check what alarm value has been set up, call :cpp:func:`timer_get_alarm_value`.
To check the specified alarm value, call :cpp:func:`timer_get_alarm_value`.
.. _timer-api-interrupts:
@@ -78,15 +83,16 @@ To check what alarm value has been set up, call :cpp:func:`timer_get_alarm_value
Interrupts
^^^^^^^^^^
Registration of the interrupt handler for a specific timer group and timer is done be calling :cpp:func:`timer_isr_register`.
Registration of the interrupt handler for a specific timer or a timer group can be done by calling :cpp:func:`timer_isr_register`.
To enable interrupts for a timer group call :cpp:func:`timer_group_intr_enable`. To do it for a specific timer, call :cpp:func:`timer_enable_intr`. Disabling of interrupts is done with corresponding functions :cpp:func:`timer_group_intr_disable` and :cpp:func:`timer_disable_intr`.
To enable interrupts for a timer group, call :cpp:func:`timer_group_intr_enable`, for a specific timer call :cpp:func:`timer_enable_intr`.
To disable interrupts for a timer group, call :cpp:func:`timer_group_intr_disable`, for a specified timer, call :cpp:func:`timer_disable_intr`.
When servicing an interrupt within an ISR, the interrupt need to explicitly cleared. To do so, set the ``TIMERGN.int_clr_timers.tM`` structure defined in :component_file:`soc/esp32/include/soc/timer_group_struct.h`, where N is the timer group number [0, 1] and M is the timer number [0, 1]. For example to clear an interrupt for the timer 1 in the timer group 0, call the following::
When handling an interrupt within an interrupt serivce routine (ISR), the interrupt status bit needs to be explicitly cleared. To do that, set the ``TIMERGN.int_clr_timers.tM`` structure, defined in :component_file:`soc/esp32/include/soc/timer_group_struct.h`. In this structure, ``N`` is the timer group number [0, 1], ``M`` is the timer number [0, 1]. For example, to clear an interrupt status bit for the timer 1 in the timer group 0, call the following::
TIMERG0.int_clr_timers.t1 = 1
See the application example below how to use interrupts.
For more information on how to use interrupts, please see the application example below.
Application Example

View File

@@ -4,19 +4,19 @@ Touch Sensor
Introduction
------------
A touch-sensor system is built on a substrate which carries electrodes and relevant connections under a protective flat surface. When a user touches the surface, the capacitance variation is triggered and a binary signal is generated to indicate whether the touch is valid.
A touch sensor system is built on a substrate which carries electrodes and relevant connections under a protective flat surface. When a user touches the surface, the capacitance variation is used to evaluate if the touch was valid.
ESP32 can provide up to 10 capacitive touch pads / GPIOs. The sensing pads can be arranged in different combinations (e.g. matrix, slider), so that a larger area or more points can be detected. The touch pad sensing process is under the control of a hardware-implemented finite-state machine (FSM) which is initiated by software or a dedicated hardware timer.
ESP32 can handle up to 10 capacitive touch pads / GPIOs. The sensing pads can be arranged in different combinations (e.g., matrix, slider), so that a larger area or more points can be detected. The touch pad sensing process is under the control of a hardware-implemented finite-state machine (FSM) which is initiated by software or a dedicated hardware timer.
Design, operation and control registers of touch sensor are discussed in `ESP32 Technical Reference Manual <https://espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf>`_ (PDF). Please refer to it for additional details how this subsystem works.
Design, operation, and control registers of a touch sensor are discussed in `ESP32 Technical Reference Manual <https://espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf>`_ (PDF). Please refer to this manual for additional details on how this subsystem works.
In depth details of design of touch sensors and firmware development guidelines for the ESP32 are available in `Touch Sensor Application Note <https://github.com/espressif/esp-iot-solution/blob/master/documents/touch_pad_solution/touch_sensor_design_en.md>`_. If you would like to test touch sensors in various configurations without building them on your own, check `Guide for ESP32-Sense Development Kit <https://github.com/espressif/esp-iot-solution/blob/master/documents/evaluation_boards/esp32_sense_kit_guide_en.md>`_.
In-depth design details of touch sensors and firmware development guidelines for ESP32 are available in `Touch Sensor Application Note <https://github.com/espressif/esp-iot-solution/blob/master/documents/touch_pad_solution/touch_sensor_design_en.md>`_. If you want to test touch sensors in various configurations without building them on your own, check the `Guide for ESP32-Sense Development Kit <https://github.com/espressif/esp-iot-solution/blob/master/documents/evaluation_boards/esp32_sense_kit_guide_en.md>`_.
Functionality Overview
----------------------
Description of API is broken down into groups of functions to provide quick overview of features like:
Description of API is broken down into groups of functions to provide a quick overview of the following features:
- Initialization of touch pad driver
- Configuration of touch pad GPIO pins
@@ -25,118 +25,120 @@ Description of API is broken down into groups of functions to provide quick over
- Filtering measurements
- Touch detection methods
- Setting up interrupts to report touch detection
- Waking up from sleep mode on interrupt
- Waking up from Sleep mode on interrupt
For detailed description of particular function please go to section :ref:`touch_pad-api-reference`. Practical implementation of this API is covered in section :ref:`touch_pad-api-examples`.
For detailed description of a particular function, please go to Section :ref:`touch_pad-api-reference`. Practical implementation of this API is covered in Section :ref:`touch_pad-api-examples`.
Initialization
^^^^^^^^^^^^^^
Touch pad driver should be initialized before use by calling function :cpp:func:`touch_pad_init`. This function sets several ``.._DEFAULT`` driver parameters listed in :ref:`touch_pad-api-reference` under "Macros". It also clears information what pads have been touched before (if any) and disables interrupts.
Before using a touch pad, you need to initialize the touch pad driver by calling the function :cpp:func:`touch_pad_init`. This function sets several ``.._DEFAULT`` driver parameters listed in :ref:`touch_pad-api-reference` under *Macros*. It also removes the information about which pads have been touched before, if any, and disables interrupts.
If not required anymore, driver can be disabled by calling :cpp:func:`touch_pad_deinit`.
If the driver is not required anymore, deinitialize it by calling :cpp:func:`touch_pad_deinit`.
Configuration
^^^^^^^^^^^^^
Enabling of touch sensor functionality for particular GPIO is done with :cpp:func:`touch_pad_config`.
Enabling the touch sensor functionality for a particular GPIO is done with :cpp:func:`touch_pad_config`.
The function :cpp:func:`touch_pad_set_fsm_mode` is used to select whether touch pad measurement (operated by FSM) is started automatically by hardware timer, or by software. If software mode is selected, then use :cpp:func:`touch_pad_sw_start` to start of the FSM.
Use the function :cpp:func:`touch_pad_set_fsm_mode` to select if touch pad measurement (operated by FSM) should be started automatically by a hardware timer, or by software. If software mode is selected, use :cpp:func:`touch_pad_sw_start` to start the FSM.
Touch State Measurements
^^^^^^^^^^^^^^^^^^^^^^^^
The following two functions come handy to read raw or filtered measurements from the sensor:
The following two functions come in handy to read raw or filtered measurements from the sensor:
* :cpp:func:`touch_pad_read`
* :cpp:func:`touch_pad_read_filtered`
They may be used to characterize particular touch pad design by checking the range of sensor readings when a pad is touched or released. This information can be then used to establish the touch threshold.
They can also be used, for example, to evaluate a particular touch pad design by checking the range of sensor readings when a pad is touched or released. This information can be then used to establish a touch threshold.
.. note::
Start and configure filter before using :cpp:func:`touch_pad_read_filtered` by calling specific filter functions described down below.
Before using :cpp:func:`touch_pad_read_filtered`, you need to initialize and configure the filter by calling specific filter functions described in Section `Filtering of Measurements`_.
To see how to use both read functions check :example:`peripherals/touch_pad_read` application example.
For the demonstration of how to use both read functions, check the application example :example:`peripherals/touch_pad_read`.
Optimization of Measurements
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Touch sensor has several configurable parameters to match characteristics of particular touch pad design. For instance, to sense smaller capacity changes, it is possible to narrow the reference voltage range within which the touch pads are charged / discharged. The high and low reference voltages are set using function :cpp:func:`touch_pad_set_voltage`. A positive side effect, besides ability to discern smaller capacity changes, will be reduction of power consumption for low power applications. A likely negative effect will be increase of measurement noise. If dynamic rage of obtained readings is still satisfactory, then further reduction of power consumption may be done by lowering the measurement time with :cpp:func:`touch_pad_set_meas_time`.
A touch sensor has several configurable parameters to match the characteristics of a particular touch pad design. For instance, to sense smaller capacity changes, it is possible to narrow down the reference voltage range within which the touch pads are charged / discharged. The high and low reference voltages are set using the function :cpp:func:`touch_pad_set_voltage`.
The following summarizes available measurement parameters and corresponding 'set' functions:
Besides the ability to discern smaller capacity changes, a positive side effect is reduction of power consumption for low power applications. A likely negative effect is an increase in measurement noise. If the dynamic range of obtained readings is still satisfactory, then further reduction of power consumption might be done by reducing the measurement time with :cpp:func:`touch_pad_set_meas_time`.
The following list summarizes available measurement parameters and corresponding 'set' functions:
* Touch pad charge / discharge parameters:
* voltage range: :cpp:func:`touch_pad_set_voltage`
* speed (slope): :cpp:func:`touch_pad_set_cnt_mode`
* Measure time: :cpp:func:`touch_pad_set_meas_time`
* Measurement time: :cpp:func:`touch_pad_set_meas_time`
Relationship between voltage range (high / low reference voltages), speed (slope) and measure time is shown on figure below.
Relationship between the voltage range (high / low reference voltages), speed (slope), and measurement time is shown in the figure below.
.. figure:: ../../../_static/touch_pad-measurement-parameters.jpg
:align: center
:alt: Touch Pad - relationship between measurement parameters
:figclass: align-center
Touch Pad - relationship between measurement parameters
Touch pad - relationship between measurement parameters
The last chart "Output" represents the touch sensor reading, i.e. the count of pulses collected within measure time.
The last chart *Output* represents the touch sensor reading, i.e., the count of pulses collected within the measurement time.
All functions are provided in pairs to 'set' specific parameter and to 'get' the current parameter's value, e.g. :cpp:func:`touch_pad_set_voltage` and :cpp:func:`touch_pad_get_voltage`.
All functions are provided in pairs to *set* a specific parameter and to *get* the current parameter's value, e.g., :cpp:func:`touch_pad_set_voltage` and :cpp:func:`touch_pad_get_voltage`.
.. _touch_pad-api-filtering-of-measurements:
Filtering of Measurements
^^^^^^^^^^^^^^^^^^^^^^^^^
If measurements are noisy, you may filter them with provided API. The filter should be started before first use by calling :cpp:func:`touch_pad_filter_start`.
If measurements are noisy, you can filter them with provided API functions. Before using the filter, please start it by calling :cpp:func:`touch_pad_filter_start`.
The filter type is IIR (Infinite Impulse Response) and it has configurable period that can be set with function :cpp:func:`touch_pad_set_filter_period`.
The filter type is IIR (infinite impulse response), and it has a configurable period that can be set with the function :cpp:func:`touch_pad_set_filter_period`.
You can stop the filter with :cpp:func:`touch_pad_filter_stop`. If not required anymore, the filter may be deleted by invoking :cpp:func:`touch_pad_filter_delete`.
You can stop the filter with :cpp:func:`touch_pad_filter_stop`. If not required anymore, the filter can be deleted by invoking :cpp:func:`touch_pad_filter_delete`.
Touch Detection
^^^^^^^^^^^^^^^
Touch detection is implemented in ESP32's hardware basing on user configured threshold and raw measurements executed by FSM. Use function :cpp:func:`touch_pad_get_status` to check what pads have been touched and :cpp:func:`touch_pad_clear_status` to clear the touch status information.
Touch detection is implemented in ESP32's hardware based on the user-configured threshold and raw measurements executed by FSM. Use the functions :cpp:func:`touch_pad_get_status` to check which pads have been touched and :cpp:func:`touch_pad_clear_status` to clear the touch status information.
Hardware touch detection may be also wired to interrupts and this is described in next section.
Hardware touch detection can also be wired to interrupts. This is described in the next section.
If measurements are noisy and capacity changes small, then hardware touch detection may be not reliable. To resolve this issue, instead of using hardware detection / provided interrupts, implement measurement filtering and perform touch detection in your own application. See :example:`peripherals/touch_pad_interrupt` for sample implementation of both methods of touch detection.
If measurements are noisy and capacity changes are small, hardware touch detection might be unreliable. To resolve this issue, instead of using hardware detection / provided interrupts, implement measurement filtering and perform touch detection in your own application. For sample implementation of both methods of touch detection, see :example:`peripherals/touch_pad_interrupt`.
Touch Triggered Interrupts
^^^^^^^^^^^^^^^^^^^^^^^^^^
Before enabling an interrupt on touch detection, user should establish touch detection threshold. Use functions described above to read and display sensor measurements when pad is touched and released. Apply a filter when measurements are noisy and relative changes are small. Depending on your application and environmental conditions, test the influence of temperature and power supply voltage changes on measured values.
Before enabling an interrupt on a touch detection, you should establish a touch detection threshold. Use the functions described in `Touch State Measurements`_ to read and display sensor measurements when a pad is touched and released. Apply a filter if measurements are noisy and relative capacity changes are small. Depending on your application and environment conditions, test the influence of temperature and power supply voltage changes on measured values.
Once detection threshold is established, it may be set on initialization with :cpp:func:`touch_pad_config` or at the runtime with :cpp:func:`touch_pad_set_thresh`.
Once a detection threshold is established, it can be set during initialization with :cpp:func:`touch_pad_config` or at the runtime with :cpp:func:`touch_pad_set_thresh`.
In next step configure how interrupts are triggered. They may be triggered below or above threshold and this is set with function :cpp:func:`touch_pad_set_trigger_mode`.
In the next step, configure how interrupts are triggered. They can be triggered below or above the threshold, which is set with the function :cpp:func:`touch_pad_set_trigger_mode`.
Finally configure and manage interrupt calls using the following functions:
Finally, configure and manage interrupt calls using the following functions:
* :cpp:func:`touch_pad_isr_register` / :cpp:func:`touch_pad_isr_deregister`
* :cpp:func:`touch_pad_intr_enable` / :cpp:func:`touch_pad_intr_disable`
When interrupts are operational, you can obtain information what particular pad triggered interrupt by invoking :cpp:func:`touch_pad_get_status` and clear pad status with :cpp:func:`touch_pad_clear_status`.
When interrupts are operational, you can obtain the information from which particular pad an interrupt came by invoking :cpp:func:`touch_pad_get_status` and clear the pad status with :cpp:func:`touch_pad_clear_status`.
.. note::
Interrupts on touch detection operate on raw / unfiltered measurements checked against user established threshold and are implemented in hardware. Enabling software filtering API (see :ref:`touch_pad-api-filtering-of-measurements`) does not affect this process.
Interrupts on touch detection operate on raw / unfiltered measurements checked against user established threshold and are implemented in hardware. Enabling the software filtering API (see :ref:`touch_pad-api-filtering-of-measurements`) does not affect this process.
Wakeup from Sleep Mode
^^^^^^^^^^^^^^^^^^^^^^
If touch pad interrupts are used to wakeup the chip from a sleep mode, then user can select certain configuration of pads (SET1 or both SET1 and SET2), that should be touched to trigger the interrupt and cause subsequent wakeup. To do so, use function :cpp:func:`touch_pad_set_trigger_source`.
If touch pad interrupts are used to wake up the chip from a sleep mode, you can select a certain configuration of pads (SET1 or both SET1 and SET2) that should be touched to trigger the interrupt and cause the subsequent wakeup. To do so, use the function :cpp:func:`touch_pad_set_trigger_source`.
Configuration of required bit patterns of pads may be managed for each 'SET' with:
@@ -162,7 +164,7 @@ API Reference
GPIO Lookup Macros
^^^^^^^^^^^^^^^^^^
Some useful macros can be used to specified the GPIO number of a touchpad channel, or vice versa.
Some useful macros can be used to specified the GPIO number of a touch pad channel, or vice versa.
e.g.
1. ``TOUCH_PAD_NUM5_GPIO_NUM`` is the GPIO number of channel 5 (12);

View File

@@ -0,0 +1,206 @@
ESP Local Control
=================
Overview
--------
ESP Local Control (**esp_local_ctrl**) component in ESP-IDF provides capability to control an ESP device over Wi-Fi + HTTPS or BLE. It provides access to application defined **properties** that are available for reading / writing via a set of configurable handlers.
Initialization of the **esp_local_ctrl** service over BLE transport is performed as follows:
.. highlight:: c
::
esp_local_ctrl_config_t config = {
.transport = ESP_LOCAL_CTRL_TRANSPORT_BLE,
.transport_config = {
.ble = & (protocomm_ble_config_t) {
.device_name = SERVICE_NAME,
.service_uuid = {
/* LSB <---------------------------------------
* ---------------------------------------> MSB */
0x21, 0xd5, 0x3b, 0x8d, 0xbd, 0x75, 0x68, 0x8a,
0xb4, 0x42, 0xeb, 0x31, 0x4a, 0x1e, 0x98, 0x3d
}
}
},
.handlers = {
/* User defined handler functions */
.get_prop_values = get_property_values,
.set_prop_values = set_property_values,
.usr_ctx = NULL,
.usr_ctx_free_fn = NULL
},
/* Maximum number of properties that may be set */
.max_properties = 10
};
/* Start esp_local_ctrl service */
ESP_ERROR_CHECK(esp_local_ctrl_start(&config));
Similarly for HTTPS transport:
.. highlight:: c
::
/* Set the configuration */
httpd_ssl_config_t https_conf = HTTPD_SSL_CONFIG_DEFAULT();
/* Load server certificate */
extern const unsigned char cacert_pem_start[] asm("_binary_cacert_pem_start");
extern const unsigned char cacert_pem_end[] asm("_binary_cacert_pem_end");
https_conf.cacert_pem = cacert_pem_start;
https_conf.cacert_len = cacert_pem_end - cacert_pem_start;
/* Load server private key */
extern const unsigned char prvtkey_pem_start[] asm("_binary_prvtkey_pem_start");
extern const unsigned char prvtkey_pem_end[] asm("_binary_prvtkey_pem_end");
https_conf.prvtkey_pem = prvtkey_pem_start;
https_conf.prvtkey_len = prvtkey_pem_end - prvtkey_pem_start;
esp_local_ctrl_config_t config = {
.transport = ESP_LOCAL_CTRL_TRANSPORT_HTTPD,
.transport_config = {
.httpd = &https_conf
},
.handlers = {
/* User defined handler functions */
.get_prop_values = get_property_values,
.set_prop_values = set_property_values,
.usr_ctx = NULL,
.usr_ctx_free_fn = NULL
},
/* Maximum number of properties that may be set */
.max_properties = 10
};
/* Start esp_local_ctrl service */
ESP_ERROR_CHECK(esp_local_ctrl_start(&config));
Creating a property
===================
Now that we know how to start the **esp_local_ctrl** service, let's add a property to it. Each property must have a unique `name` (string), a `type` (e.g. enum), `flags` (bit fields) and `size`.
The `size` is to be kept 0, if we want our property value to be of variable length (e.g. if its a string or bytestream). For fixed length property value data-types, like int, float, etc., setting the `size` field to the right value, helps **esp_local_ctrl** to perform internal checks on arguments received with write requests.
The interpretation of `type` and `flags` fields is totally upto the application, hence they may be used as enumerations, bitfields, or even simple integers. One way is to use `type` values to classify properties, while `flags` to specify characteristics of a property.
Here is an example property which is to function as a timestamp. It is assumed that the application defines `TYPE_TIMESTAMP` and `READONLY`, which are used for setting the `type` and `flags` fields here.
.. highlight:: c
::
/* Create a timestamp property */
esp_local_ctrl_prop_t timestamp = {
.name = "timestamp",
.type = TYPE_TIMESTAMP,
.size = sizeof(int32_t),
.flags = READONLY,
.ctx = func_get_time,
.ctx_free_fn = NULL
};
/* Now register the property */
esp_local_ctrl_add_property(&timestamp);
Also notice that there is a ctx field, which is set to point to some custom `func_get_time()`. This can be used inside the property get / set handlers to retrieve timestamp.
Here is an example of `get_prop_values()` handler, which is used for retrieving the timestamp.
.. highlight:: c
::
static esp_err_t get_property_values(size_t props_count,
const esp_local_ctrl_prop_t *props,
esp_local_ctrl_prop_val_t *prop_values,
void *usr_ctx)
{
for (uint32_t i = 0; i < props_count; i++) {
ESP_LOGI(TAG, "Reading %s", props[i].name);
if (props[i].type == TYPE_TIMESTAMP) {
/* Obtain the timer function from ctx */
int32_t (*func_get_time)(void) = props[i].ctx;
/* Use static variable for saving the value.
* This is essential because the value has to be
* valid even after this function returns.
* Alternative is to use dynamic allocation
* and set the free_fn field */
static int32_t ts = func_get_time();
prop_values[i].data = &ts;
}
}
return ESP_OK;
}
Here is an example of `set_prop_values()` handler. Notice how we restrict from writing to read-only properties.
.. highlight:: c
::
static esp_err_t set_property_values(size_t props_count,
const esp_local_ctrl_prop_t *props,
const esp_local_ctrl_prop_val_t *prop_values,
void *usr_ctx)
{
for (uint32_t i = 0; i < props_count; i++) {
if (props[i].flags & READONLY) {
ESP_LOGE(TAG, "Cannot write to read-only property %s", props[i].name);
return ESP_ERR_INVALID_ARG;
} else {
ESP_LOGI(TAG, "Setting %s", props[i].name);
/* For keeping it simple, lets only log the incoming data */
ESP_LOG_BUFFER_HEX_LEVEL(TAG, prop_values[i].data,
prop_values[i].size, ESP_LOG_INFO);
}
}
return ESP_OK;
}
For complete example see :example:`protocols/esp_local_ctrl`
Client Side Implementation
==========================
The client side implementation will have establish a protocomm session with the device first, over the supported mode of transport, and then send and receive protobuf messages understood by the **esp_local_ctrl** service. The service will translate these messages into requests and then call the appropriate handlers (set / get). Then, the generated response for each handler is again packed into a protobuf message and transmitted back to the client.
See below the various protobuf messages understood by the **esp_local_ctrl** service:
1. `get_prop_count` : This should simply return the total number of properties supported by the service
2. `get_prop_values` : This accepts an array of indices and should return the information (name, type, flags) and values of the properties corresponding to those indices
3. `set_prop_values` : This accepts an array of indices and an array of new values, which are used for setting the values of the properties corresponding to the indices
Note that indices may or may not be the same for a property, across multiple sessions. Therefore, the client must only use the names of the properties to uniquely identify them. So, every time a new session is established, the client should first call `get_prop_count` and then `get_prop_values`, hence form an index to name mapping for all properties. Now when calling `set_prop_values` for a set of properties, it must first convert the names to indexes, using the created mapping. As emphasized earlier, the client must refresh the index to name mapping every time a new session is established with the same device.
The various protocomm endpoints provided by **esp_local_ctrl** are listed below:
.. list-table:: Endpoints provided by ESP Local Control
:widths: 10 25 50
:header-rows: 1
* - Endpoint Name (BLE + GATT Server)
- URI (HTTPS Server + mDNS)
- Description
* - esp_local_ctrl/version
- https://<mdns-hostname>.local/esp_local_ctrl/version
- Endpoint used for retrieving version string
* - esp_local_ctrl/control
- https://<mdns-hostname>.local/esp_local_ctrl/control
- Endpoint used for sending / receiving control messages
API Reference
-------------
.. include:: /_build/inc/esp_local_ctrl.inc

View File

@@ -0,0 +1,70 @@
ESP WebSocket Client
====================
Overview
--------
The ESP WebSocket client is an implementation of `WebSocket protocol client <https://tools.ietf.org/html/rfc6455>`_ for ESP32
Features
--------
* supports WebSocket over TCP, SSL with mbedtls
* Easy to setup with URI
* Multiple instances (Multiple clients in one application)
Configuration
-------------
URI
^^^
- Supports ``ws``, ``wss`` schemes
- WebSocket samples:
- ``ws://websocket.org``: WebSocket over TCP, default port 80
- ``wss://websocket.org``: WebSocket over SSL, default port 443
- Minimal configurations:
.. code:: c
const esp_websocket_client_config_t ws_cfg = {
.uri = "ws://websocket.org",
};
- If there are any options related to the URI in
``esp_websocket_client_config_t``, the option defined by the URI will be
overridden. Sample:
.. code:: c
const esp_websocket_client_config_t ws_cfg = {
.uri = "ws://websocket.org:123",
.port = 4567,
};
//WebSocket client will connect to websocket.org using port 4567
SSL
^^^
- Get certificate from server, example: ``websocket.org``
``openssl s_client -showcerts -connect websocket.org:443 </dev/null 2>/dev/null|openssl x509 -outform PEM >websocket_org.pem``
- Configuration:
.. code:: cpp
const esp_websocket_client_config_t ws_cfg = {
.uri = "wss://websocket.org",
.cert_pem = (const char *)websocket_org_pem_start,
};
For more options on ``esp_websocket_client_config_t``, please refer to API reference below
Application Example
-------------------
Simple WebSocket example that uses esp_websocket_client to establish a websocket connection and send/receive data with the `websocket.org <https://websocket.org>`_ Server: :example:`protocols/websocket`.
API Reference
-------------
.. include:: /_build/inc/esp_websocket_client.inc

View File

@@ -8,11 +8,13 @@ Application Protocols
mDNS <mdns>
ESP-TLS <esp_tls>
HTTP Client <esp_http_client>
Websocket Client <esp_websocket_client>
HTTP Server <esp_http_server>
HTTPS Server <esp_https_server>
ASIO <asio>
ESP-MQTT <mqtt>
Modbus <modbus>
Local Control <esp_local_ctrl>
Code examples for this API section are provided in the :example:`protocols` directory of ESP-IDF examples.

View File

@@ -94,12 +94,12 @@ SSL
For more options on ``esp_mqtt_client_config_t``, please refer to API reference below
Change settings in ``menuconfig``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Change settings in Project Configuration Menu
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
::
make menuconfig
-> Component config -> ESP-MQTT Configuration
idf.py menuconfig
-> Component config -> ESP-MQTT Configuration
- :ref:`CONFIG_MQTT_PROTOCOL_311`: Enables 3.1.1 version of MQTT protocol

View File

@@ -19,11 +19,7 @@ Initialization
wifi_prov_mgr_config_t config = {
.scheme = wifi_prov_scheme_ble,
.scheme_event_handler = WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BTDM,
.app_event_handler = {
.event_cb = prov_event_handler,
.user_data = NULL
}
.scheme_event_handler = WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BTDM
};
ESP_ERR_CHECK( wifi_prov_mgr_init(config) );
@@ -44,53 +40,51 @@ The configuration structure ``wifi_prov_mgr_config_t`` has a few fields to speci
* ``WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BT`` - Free only classic BT. Used when main application requires BLE. In this case freeing happens right when the manager is initialized.
* ``WIFI_PROV_EVENT_HANDLER_NONE`` - Don't use any scheme specific handler. Used when provisioning scheme is not BLE (i.e. SoftAP or Console), or when main application wants to handle the memory reclaiming on its own, or needs both BLE and classic BT to function.
* `app_event_handler` : Application specific event handler which can be used to execute specific calls depending on the state of the provisioning service. This is to be set to a function of the form ``void app_event_handler(void *user_data, wifi_prov_cb_event_t event, void *event_data)`` along with any user data to be made available at the time of handling. This can also be set to ``WIFI_PROV_EVENT_HANDLER_NONE`` if not used. See definition of ``wifi_prov_cb_event_t`` for the list of events that are generated by the provisioning service. Following is a snippet showing a typical application specific provisioning event handler along with usage of the ``event_data`` parameter :
* `app_event_handler` (Deprecated) : It is now recommended to catch ``WIFI_PROV_EVENT``s that are emitted to the default event loop handler. See definition of ``wifi_prov_cb_event_t`` for the list of events that are generated by the provisioning service. Here is an excerpt showing some of the provisioning events:
.. highlight:: c
::
void prov_event_handler(void *user_data,
wifi_prov_cb_event_t event,
void *event_data)
static void event_handler(void* arg, esp_event_base_t event_base,
int event_id, void* event_data)
{
switch (event) {
case WIFI_PROV_INIT:
ESP_LOGI(TAG, "Manager initialized");
break;
case WIFI_PROV_START:
ESP_LOGI(TAG, "Provisioning started");
break;
case WIFI_PROV_CRED_RECV: {
wifi_sta_config_t *wifi_sta_cfg = (wifi_sta_config_t *)event_data;
ESP_LOGI(TAG, "Received Wi-Fi credentials"
"\n\tSSID : %s\n\tPassword : %s",
(const char *) wifi_sta_cfg->ssid,
(const char *) wifi_sta_cfg->password);
break;
if (event_base == WIFI_PROV_EVENT) {
switch (event_id) {
case WIFI_PROV_START:
ESP_LOGI(TAG, "Provisioning started");
break;
case WIFI_PROV_CRED_RECV: {
wifi_sta_config_t *wifi_sta_cfg = (wifi_sta_config_t *)event_data;
ESP_LOGI(TAG, "Received Wi-Fi credentials"
"\n\tSSID : %s\n\tPassword : %s",
(const char *) wifi_sta_cfg->ssid,
(const char *) wifi_sta_cfg->password);
break;
}
case WIFI_PROV_CRED_FAIL: {
wifi_prov_sta_fail_reason_t *reason = (wifi_prov_sta_fail_reason_t *)event_data;
ESP_LOGE(TAG, "Provisioning failed!\n\tReason : %s"
"\n\tPlease reset to factory and retry provisioning",
(*reason == WIFI_PROV_STA_AUTH_ERROR) ?
"Wi-Fi station authentication failed" : "Wi-Fi access-point not found");
break;
}
case WIFI_PROV_CRED_SUCCESS:
ESP_LOGI(TAG, "Provisioning successful");
break;
case WIFI_PROV_END:
/* De-initialize manager once provisioning is finished */
wifi_prov_mgr_deinit();
break;
default:
break;
}
case WIFI_PROV_CRED_FAIL: {
wifi_prov_sta_fail_reason_t *reason = (wifi_prov_sta_fail_reason_t *)event_data;
ESP_LOGE(TAG, "Provisioning failed : %s",
(*reason == WIFI_PROV_STA_AUTH_ERROR) ?
"Wi-Fi AP password incorrect" :
"Wi-Fi AP not found");
break;
}
case WIFI_PROV_CRED_SUCCESS:
ESP_LOGI(TAG, "Provisioning successful");
break;
case WIFI_PROV_END:
ESP_LOGI(TAG, "Provisioning stopped");
break;
case WIFI_PROV_DEINIT:
ESP_LOGI(TAG, "Manager de-initialized");
break;
default:
break;
}
}
The manager can be de-initialized at any moment by making a call to :cpp:func:`wifi_prov_mgr_deinit()`.
.. _wifi-prov-check-state:
Check Provisioning State
@@ -114,30 +108,6 @@ If provisioning state needs to be reset, any of the following approaches may be
ESP_ERR_CHECK( wifi_prov_mgr_is_provisioned(&provisioned) );
Event Loop Handling
^^^^^^^^^^^^^^^^^^^
Presently Wi-Fi provisioning manager cannot directly catch external system events, hence it is necessary to explicitly call :cpp:func:`wifi_prov_mgr_event_handler()` from inside the global event loop handler. See the following snippet :
.. highlight:: c
::
static esp_err_t global_event_loop_handler(void *ctx, system_event_t *event)
{
/* Pass event information to provisioning manager so that it can
* maintain its internal state depending upon the system event */
wifi_prov_mgr_event_handler(ctx, event);
/* Event handling logic for main application */
switch (event->event_id) {
.....
.....
.....
}
return ESP_OK;
}
Start Provisioning Service
^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -194,21 +164,18 @@ There are two ways for making this possible. The simpler way is to use a blockin
wifi_prov_mgr_deinit();
The other way is to use the application specific event handler which is to be configured during initialization, as explained above in :ref:`wifi-prov-mgr-init`.
The other way is to use the default event loop handler to catch ``WIFI_PROV_EVENT``s and call :cpp:func:`wifi_prov_mgr_deinit()` when event ID is ``WIFI_PROV_END``:
.. highlight:: c
::
void prov_event_handler(void *user_data, wifi_prov_cb_event_t event, void *event_data)
static void event_handler(void* arg, esp_event_base_t event_base,
int event_id, void* event_data)
{
switch (event) {
case WIFI_PROV_END:
// De-initialize manager once provisioning is finished
wifi_prov_mgr_deinit();
break;
default:
break;
if (event_base == WIFI_PROV_EVENT && event_id == WIFI_PROV_END) {
/* De-initialize manager once provisioning is finished */
wifi_prov_mgr_deinit();
}
}
@@ -234,6 +201,9 @@ Once connected to the device, the provisioning related protocomm endpoints can b
* - prov-session
- http://<mdns-hostname>.local/prov-session
- Security endpoint used for session establishment
* - prov-scan
- http://wifi-prov.local/prov-scan
- Endpoint used for starting Wi-Fi scan and receiving scan results
* - prov-config
- http://<mdns-hostname>.local/prov-config
- Endpoint used for configuring Wi-Fi credentials on device
@@ -245,14 +215,31 @@ Immediately after connecting, the client application may fetch the version / cap
User side applications need to implement the signature handshaking required for establishing and authenticating secure protocomm sessions as per the security scheme configured for use (this is not needed when manager is configured to use protocomm security 0).
See Unified Provisioning for more details about the secure handshake and encryption used. Applications must use the `.proto` files found under `components/protocomm/proto <https://github.com/espressif/esp-idf/components/protocomm/proto>`_, which define the Protobuf message structures supported by `prov-session` endpoint.
See Unified Provisioning for more details about the secure handshake and encryption used. Applications must use the `.proto` files found under :component:`protocomm/proto`, which define the Protobuf message structures supported by `prov-session` endpoint.
Once a session is established, Wi-Fi credentials are configured using the following set of commands, serialized as Protobuf messages (the corresponding `.proto` files can be found under `components/wifi_provisioning/proto <https://github.com/espressif/esp-idf/components/wifi_provisioning/proto>`_) :
Once a session is established, Wi-Fi credentials are configured using the following set of `wifi_config` commands, serialized as Protobuf messages (the corresponding `.proto` files can be found under :component:`wifi_provisioning/proto`) :
* `get_status` - For querying the Wi-Fi connection status. The device will respond with a status which will be one of connecting / connected / disconnected. If status is disconnected, a disconnection reason will also be included in the status response.
* `set_config` - For setting the Wi-Fi connection credentials
* `apply_config` - For applying the credentials saved during `set_config` and start the Wi-Fi station
After session establishment, client can also request Wi-Fi scan results from the device. The results returned is a list of AP SSIDs, sorted in descending order of signal strength. This allows client applications to display APs nearby to the device at the time of provisioning, and users can select one of the SSIDs and provide the password which is then sent using the `wifi_config` commands described above. The `wifi_scan` endpoint supports the following protobuf commands :
* `scan_start` - For starting Wi-Fi scan with various options :
* `blocking` (input) - If true, the command returns only when the scanning is finished
* `passive` (input) - If true scan is started in passive mode (this may be slower) instead of active mode
* `group_channels` (input) - This specifies whether to scan all channels in one go (when zero) or perform scanning of channels in groups, with 120ms delay between scanning of consecutive groups, and the value of this parameter sets the number of channels in each group. This is useful when transport mode is SoftAP, where scanning all channels in one go may not give the Wi-Fi driver enough time to send out beacons, and hence may cause disconnection with any connected stations. When scanning in groups, the manager will wait for atleast 120ms after completing scan on a group of channels, and thus allow the driver to send out the beacons. For example, given that the total number of Wi-Fi channels is 14, then setting group_channels to 4, will create 5 groups, with each group having 3 channels, except the last one which will have 14 % 3 = 2 channels. So, when scan is started, the first 3 channels will be scanned, followed by a 120ms delay, and then the next 3 channels, and so on, until all the 14 channels have been scanned. One may need to adjust this parameter as having only few channels in a group may slow down the overall scan time, while having too many may again cause disconnection. Usually a value of 4 should work for most cases. Note that for any other mode of transport, e.g. BLE, this can be safely set to 0, and hence achieve the fastest overall scanning time.
* `period_ms` (input) - Scan parameter specifying how long to wait on each channel
* `scan_status` - Gives the status of scanning process :
* `scan_finished` (output) - When scan has finished this returns true
* `result_count` (output) - This gives the total number of results obtained till now. If scan is yet happening this number will keep on updating
* `scan_result` - For fetching scan results. This can be called even if scan is still on going
* `start_index` (input) - Starting index from where to fetch the entries from the results list
* `count` (input) - Number of entries to fetch from the starting index
* `entries` (output) - List of entries returned. Each entry consists of `ssid`, `channel` and `rssi` information
Additional Endpoints
^^^^^^^^^^^^^^^^^^^^

View File

@@ -1,36 +1,43 @@
FAT Filesystem Support
======================
ESP-IDF uses `FatFs <http://elm-chan.org/fsw/ff/00index_e.html>`_ library to work with FAT filesystems. FatFs library resides in ``fatfs`` component. Although it can be used directly, many of its features can be accessed via VFS using C standard library and POSIX APIs.
ESP-IDF uses the `FatFs <http://elm-chan.org/fsw/ff/00index_e.html>`_ library to work with FAT filesystems. FatFs resides in the ``fatfs`` component. Although the library can be used directly, many of its features can be accessed via VFS, using the C standard library and POSIX API functions.
Additionally, FatFs has been modified to support the runtime pluggable disk I/O layer. This allows mapping of FatFs drives to physical disks at runtime.
Additionally, FatFs has been modified to support run-time pluggable disk IO layer. This allows mapping of FatFs drives to physical disks at run-time.
Using FatFs with VFS
--------------------
:component_file:`fatfs/src/esp_vfs_fat.h` header file defines functions to connect FatFs with VFS. :cpp:func:`esp_vfs_fat_register` function allocates a ``FATFS`` structure, and registers a given path prefix in VFS. Subsequent operations on files starting with this prefix are forwarded to FatFs APIs. :cpp:func:`esp_vfs_fat_unregister_path` function deletes the registration with VFS, and frees the ``FATFS`` structure.
The header file :component_file:`fatfs/vfs/esp_vfs_fat.h` defines the functions for connecting FatFs and VFS.
Most applications will use the following flow when working with ``esp_vfs_fat_`` functions:
The function :cpp:func:`esp_vfs_fat_register` allocates a ``FATFS`` structure and registers a given path prefix in VFS. Subsequent operations on files starting with this prefix are forwarded to FatFs APIs.
The function :cpp:func:`esp_vfs_fat_unregister_path` deletes the registration with VFS, and frees the ``FATFS`` structure.
1. Call :cpp:func:`esp_vfs_fat_register`, specifying path prefix where the filesystem has to be mounted (e.g. ``"/sdcard"``, ``"/spiflash"``), FatFs drive number, and a variable which will receive a pointer to ``FATFS`` structure.
Most applications use the following workflow when working with ``esp_vfs_fat_`` functions:
2. Call :cpp:func:`ff_diskio_register` function to register disk IO driver for the drive number used in step 1.
1. Call :cpp:func:`esp_vfs_fat_register` to specify:
- Path prefix where to mount the filesystem (e.g. ``"/sdcard"``, ``"/spiflash"``)
- FatFs drive number
- A variable which will receive the pointer to the ``FATFS`` structure
3. Call FatFs ``f_mount`` function (and optionally ``f_fdisk``, ``f_mkfs``) to mount the filesystem using the same drive number which was passed to :cpp:func:`esp_vfs_fat_register`. See `FatFs documentation for more details <http://www.elm-chan.org/fsw/ff/doc/mount.html>`.
2. Call :cpp:func:`ff_diskio_register` to register the disk I/O driver for the drive number used in Step 1.
4. Call POSIX and C standard library functions to open, read, write, erase, copy files, etc. Use paths starting with the prefix passed to :cpp:func:`esp_vfs_register` (such as ``"/sdcard/hello.txt"``).
3. Call the FatFs function ``f_mount``, and optionally ``f_fdisk``, ``f_mkfs``, to mount the filesystem using the same drive number which was passed to :cpp:func:`esp_vfs_fat_register`. For more information, see `FatFs documentation <http://www.elm-chan.org/fsw/ff/doc/mount.html>`.
5. Optionally, call FatFs library functions directly. Use paths without a VFS prefix in this case (``"/hello.txt"``).
4. Call the C standard library and POSIX API functions to perform such actions on files as open, read, write, erase, copy, etc. Use paths starting with the path prefix passed to :cpp:func:`esp_vfs_register` (for example, ``"/sdcard/hello.txt"``).
5. Optionally, call the FatFs library functions directly. In this case, use paths without a VFS prefix (for example, ``"/hello.txt"``).
6. Close all open files.
7. Call FatFs ``f_mount`` function for the same drive number, with NULL ``FATFS*`` argument, to unmount the filesystem.
7. Call the FatFs function ``f_mount`` for the same drive number, with NULL ``FATFS*`` argument, to unmount the filesystem.
8. Call FatFs :cpp:func:`ff_diskio_register` with NULL ``ff_diskio_impl_t*`` argument and the same drive number.
8. Call the FatFs function :cpp:func:`ff_diskio_register` with NULL ``ff_diskio_impl_t*`` argument and the same drive number to unregister the disk I/O driver.
9. Call :cpp:func:`esp_vfs_fat_unregister_path` with the path where the file system is mounted to remove FatFs from VFS, and free the ``FATFS`` structure allocated on step 1.
9. Call :cpp:func:`esp_vfs_fat_unregister_path` with the path where the file system is mounted to remove FatFs from VFS, and free the ``FATFS`` structure allocated in Step 1.
Convenience functions, ``esp_vfs_fat_sdmmc_mount`` and ``esp_vfs_fat_sdmmc_unmount``, which wrap these steps and also handle SD card initialization, are described in the next section.
The convenience functions ``esp_vfs_fat_sdmmc_mount`` and ``esp_vfs_fat_sdmmc_unmount`` wrap the steps described above and also handle SD card initialization. These two functions are described in the next section.
.. doxygenfunction:: esp_vfs_fat_register
.. doxygenfunction:: esp_vfs_fat_unregister_path
@@ -39,7 +46,9 @@ Convenience functions, ``esp_vfs_fat_sdmmc_mount`` and ``esp_vfs_fat_sdmmc_unmou
Using FatFs with VFS and SD cards
---------------------------------
:component_file:`fatfs/src/esp_vfs_fat.h` header file also provides a convenience function to perform steps 13 and 79, and also handle SD card initialization: :cpp:func:`esp_vfs_fat_sdmmc_mount`. This function does only limited error handling. Developers are encouraged to look at its source code and incorporate more advanced versions into production applications. :cpp:func:`esp_vfs_fat_sdmmc_unmount` function unmounts the filesystem and releases resources acquired by :cpp:func:`esp_vfs_fat_sdmmc_mount`.
The header file :component_file:`fatfs/vfs/esp_vfs_fat.h` defines convenience functions :cpp:func:`esp_vfs_fat_sdmmc_mount` and :cpp:func:`esp_vfs_fat_sdmmc_unmount`. These function perform Steps 13 and 79 respectively and handle SD card initialization, but provide only limited error handling. Developers are encouraged to check its source code and incorporate more advanced features into production applications.
The convenience function :cpp:func:`esp_vfs_fat_sdmmc_unmount` unmounts the filesystem and releases the resources acquired by :cpp:func:`esp_vfs_fat_sdmmc_mount`.
.. doxygenfunction:: esp_vfs_fat_sdmmc_mount
.. doxygenstruct:: esp_vfs_fat_mount_config_t
@@ -50,20 +59,24 @@ Using FatFs with VFS and SD cards
Using FatFs with VFS in read-only mode
--------------------------------------
Convenience functions, :cpp:func:`esp_vfs_fat_rawflash_mount` and :cpp:func:`esp_vfs_fat_rawflash_unmount`, are provided by :component_file:`fatfs/src/esp_vfs_fat.h` header file in order to perform steps 1-3 and 7-9 for read-only FAT partitions. These are particularly helpful for data partitions written only once during factory provisioning and need not be changed by production application throughout the lifetime.
The header file :component_file:`fatfs/vfs/esp_vfs_fat.h` also defines the convenience functions :cpp:func:`esp_vfs_fat_rawflash_mount` and :cpp:func:`esp_vfs_fat_rawflash_unmount`. These functions perform Steps 1-3 and 7-9 respectively for read-only FAT partitions. These are particularly helpful for data partitions written only once during factory provisioning which will not be changed by production application throughout the lifetime of the hardware.
.. doxygenfunction:: esp_vfs_fat_rawflash_mount
.. doxygenfunction:: esp_vfs_fat_rawflash_unmount
FatFS disk IO layer
-------------------
FatFs has been extended with an API to register disk IO driver at runtime.
FatFs has been extended with API functions that register the disk I/O driver at runtime.
Implementation of disk IO functions for SD/MMC cards is provided. It can be registered for the given FatFs drive number using :cpp:func:`ff_diskio_register_sdmmc` function.
They provide implementation of disk I/O functions for SD/MMC cards and can be registered for the given FatFs drive number using the function :cpp:func:`ff_diskio_register_sdmmc`.
.. doxygenfunction:: ff_diskio_register
.. doxygenstruct:: ff_diskio_impl_t
:members:
.. doxygenfunction:: ff_diskio_register_sdmmc
.. doxygenfunction:: ff_diskio_register_wl_partition
.. doxygenfunction:: ff_diskio_register_raw_partition

View File

@@ -15,4 +15,4 @@ Storage API
Mass Manufacturing Utility <mass_mfg.rst>
Example code for this API section is provided in :example:`storage` directory of ESP-IDF examples.
Code examples for this API section are provided in the :example:`storage` directory of ESP-IDF examples.

View File

@@ -3,29 +3,29 @@
NVS Partition Generator Utility
-------------------------------
This utility helps in generating NVS-esque partition binary file which can be flashed separately on a dedicated partition via a flashing utility. Key-value pairs to be flashed onto the partition can be provided via a CSV file. Refer to :doc:`NVS Partition Generator Utility <nvs_partition_gen>` for more details.
This utility helps generate NVS partition binary files which can be flashed separately on a dedicated partition via a flashing utility. Key-value pairs to be flashed onto the partition can be provided via a CSV file. For more details, please refer to :doc:`NVS Partition Generator Utility <nvs_partition_gen>`.
Application Example
-------------------
Two examples are provided in :example:`storage` directory of ESP-IDF examples:
You can find two code examples in the :example:`storage` directory of ESP-IDF examples:
:example:`storage/nvs_rw_value`
Demonstrates how to read and write a single integer value using NVS.
Demonstrates how to read a single integer value from, and write it to NVS.
The value holds the number of ESP32 module restarts. Since it is written to NVS, the value is preserved between restarts.
The value checked in this example holds the number of the ESP32 module restarts. The value's function as a counter is only possible due to its storing in NVS.
Example also shows how to check if read / write operation was successful, or certain value is not initialized in NVS. Diagnostic is provided in plain text to help track program flow and capture any issues on the way.
The example also shows how to check if a read / write operation was successful, or if a certain value has not been initialized in NVS. The diagnostic procedure is provided in plain text to help you track the program flow and capture any issues on the way.
:example:`storage/nvs_rw_blob`
Demonstrates how to read and write a single integer value and a blob (binary large object) using NVS to preserve them between ESP32 module restarts.
Demonstrates how to read a single integer value and a blob (binary large object), and write them to NVS to preserve this value between ESP32 module restarts.
* value - tracks number of ESP32 module soft and hard restarts.
* blob - contains a table with module run times. The table is read from NVS to dynamically allocated RAM. New run time is added to the table on each manually triggered soft restart and written back to NVS. Triggering is done by pulling down GPIO0.
* value - tracks the number of the ESP32 module soft and hard restarts.
* blob - contains a table with module run times. The table is read from NVS to dynamically allocated RAM. A new run time is added to the table on each manually triggered soft restart, and then the added run time is written to NVS. Triggering is done by pulling down GPIO0.
Example also shows how to implement diagnostics if read / write operation was successful.
The example also shows how to implement the diagnostic procedure to check if the read / write operation was successful.
API Reference

View File

@@ -4,77 +4,93 @@ SD/SDIO/MMC Driver
Overview
--------
SD/SDIO/MMC driver currently supports SD memory, SDIO cards, and eMMC chips. This protocol level driver builds on top of SDMMC and SD SPI host drivers.
The SD/SDIO/MMC driver currently supports SD memory, SDIO cards, and eMMC chips. This is a protocol level driver built on top of SDMMC and SD SPI host drivers.
SDMMC and SD SPI host drivers (``driver/sdmmc_host.h``) provide APIs to send commands to the slave device(s), send and receive data, and handle error conditions on the bus.
- See :doc:`SDMMC Host API <../peripherals/sdmmc_host>` for functions used to initialize and configure SDMMC host.
- See :doc:`SD SPI Host API <../peripherals/sdspi_host>` for functions used to initialize and configure SD SPI host.
SDMMC and SD SPI host drivers (:component:`driver/include/driver/sdmmc_host.h`) provide API functions for:
SDMMC protocol layer (``sdmmc_cmd.h``), described in this document, handles specifics of SD protocol such as card initialization and data transfer commands.
- Sending commands to slave devices
- Sending and receiving data
- Handling error conditions within the bus
For functions used to initialize and configure:
- SDMMC host, see :doc:`SDMMC Host API <../peripherals/sdmmc_host>`
- SD SPI host, see :doc:`SD SPI Host API <../peripherals/sdspi_host>`
The SDMMC protocol layer described in this document handles the specifics of the SD protocol, such as the card initialization and data transfer commands.
The protocol layer works with the host via the :cpp:class:`sdmmc_host_t` structure. This structure contains pointers to various functions of the host.
Protocol layer works with the host via :cpp:class:`sdmmc_host_t` structure. This structure contains pointers to various functions of the host.
Application Example
-------------------
An example which combines SDMMC driver with FATFS library is provided in ``examples/storage/sd_card`` directory. This example initializes the card, writes and reads data from it using POSIX and C library APIs. See README.md file in the example directory for more information.
An example which combines the SDMMC driver with the FATFS library is provided in the :example:`storage/sd_card` directory of ESP-IDF examples. This example initializes the card, then writes and reads data from it using POSIX and C library APIs. See README.md file in the example directory for more information.
Protocol layer APIs
-------------------
Protocol layer is given :cpp:class:`sdmmc_host_t` structure which describes the SD/MMC host driver, lists its capabilites, and provides pointers to functions of the driver. Protocol layer stores card-specific information in :cpp:class:`sdmmc_card_t` structure. When sending commands to the SD/MMC host driver, protocol layer uses :cpp:class:`sdmmc_command_t` structure to describe the command, argument, expected return value, and data to transfer, if any.
Protocol layer API
------------------
Usage with SD memory cards
^^^^^^^^^^^^^^^^^^^^^^^^^^
1. Call the host driver functions to initialize the host (e.g. :cpp:func:`sdmmc_host_init`, :cpp:func:`sdmmc_host_init_slot`).
2. Call :cpp:func:`sdmmc_card_init` to initialize the card, passing it host driver information (``host``) and a pointer to :cpp:class:`sdmmc_card_t` structure which will be filled in (``card``).
3. To read and write sectors of the card, use :cpp:func:`sdmmc_read_sectors` and :cpp:func:`sdmmc_write_sectors`, passing the pointer to card information structure (``card``).
4. When card is not used anymore, call the host driver function to disable the host peripheral and free resources allocated by the driver (e.g. :cpp:func:`sdmmc_host_deinit`).
Usage with eMMC chips
^^^^^^^^^^^^^^^^^^^^^
From the perspective of the protocol layer, eMMC memory chips behave the same way as SD memory cards. Because of similarity of the protocol, even though eMMC are chips don't have the "card" form factor, same terminology is used as for SD cards (`sdmmc_card_t`, `sdmmc_card_init`). Note that eMMC chips can not be used over SPI, therefore are incompatible with SD SPI host driver.
To initialize eMMC memory and do read/write operations, follow the steps listed above for SD cards.
The protocol layer is given the :cpp:class:`sdmmc_host_t` structure. This structure describes the SD/MMC host driver, lists its capabilities, and provides pointers to functions of the driver. The protocol layer stores card-specific information in the :cpp:class:`sdmmc_card_t` structure. When sending commands to the SD/MMC host driver, the protocol layer uses the :cpp:class:`sdmmc_command_t` structure to describe the command, arguments, expected return values, and data to transfer if there is any.
Usage with SDIO cards
^^^^^^^^^^^^^^^^^^^^^
Using API with SD memory cards
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Initialization an probing process is the same as with SD memory cards. Only data transfer commands differ in SDIO mode.
1. To initialize the host, call the host driver functions, e.g., :cpp:func:`sdmmc_host_init`, :cpp:func:`sdmmc_host_init_slot`.
2. To initialize the card, call :cpp:func:`sdmmc_card_init` and pass to it the parameters ``host`` - the host driver information, and ``card`` - a pointer to the structure :cpp:class:`sdmmc_card_t` which will be filled with information about the card when the function completes.
3. To read and write sectors of the card, use :cpp:func:`sdmmc_read_sectors` and :cpp:func:`sdmmc_write_sectors` respectively and pass to it the parameter ``card`` - a pointer to the card information structure.
4. If the card is not used anymore, call the host driver function - e.g., :cpp:func:`sdmmc_host_deinit` - to disable the host peripheral and free the resources allocated by the driver.
During probing and card initialization (done by :cpp:func:`sdmmc_card_init`), the driver only configures the following registers of the IO card:
1. The IO portion of the card is reset by setting RES bit in "I/O Abort" (0x06) register.
2. If 4-line mode is enalbed in host and slot configuration, driver attempts to set "Bus width" field in "Bus Interface Control" (0x07) register. If that succeeds (which means that slave supports 4-line mode), host is also switched to 4-line mode.
3. If high-speed mode is enabled in host configuration, SHS bit is set in "High Speed" (0x13) register.
Using API with eMMC chips
^^^^^^^^^^^^^^^^^^^^^^^^^
In particular, the driver does not set any of the bits in I/O Enable, Int Enable registers, IO block sizes, etc. Applications can set these by calling :cpp:func:`sdmmc_io_write_byte`.
From the protocol layer's perspective, eMMC memory chips behave exactly like SD memory cards. Even though eMMCs are chips and do not have a card form factor, the terminology for SD cards can still be applied to eMMC due to the similarity of the protocol (`sdmmc_card_t`, `sdmmc_card_init`). Note that eMMC chips cannot be used over SPI, which makes them incompatible with the SD SPI host driver.
For card configuration and data transfer, use one of the following functions:
To initialize eMMC memory and perform read/write operations, follow the steps listed for SD cards in the previous section.
- :cpp:func:`sdmmc_io_read_byte`, :cpp:func:`sdmmc_io_write_byte` — read and write single byte using IO_RW_DIRECT (CMD52).
- :cpp:func:`sdmmc_io_read_bytes`, :cpp:func:`sdmmc_io_write_bytes` — read and write multiple bytes using IO_RW_EXTENDED (CMD53), in byte mode.
- :cpp:func:`sdmmc_io_read_blocks`, :cpp:func:`sdmmc_io_write_blocks` — read and write blocks of data using IO_RW_EXTENDED (CMD53), in block mode.
SDIO interrupts can be enabled by the application using :cpp:func:`sdmmc_io_enable_int` function. When using SDIO in 1-line mode, D1 line also needs to be connected to use SDIO interrupts.
Using API with SDIO cards
^^^^^^^^^^^^^^^^^^^^^^^^^
Initialization and the probing process is the same as with SD memory cards. The only difference is in data transfer commands in SDIO mode.
During the card initialization and probing, performed with :cpp:func:`sdmmc_card_init`, the driver only configures the following registers of the IO card:
1. The IO portion of the card is reset by setting RES bit in the I/O Abort (0x06) register.
2. If 4-line mode is enabled in host and slot configuration, the driver attempts to set the Bus width field in the Bus Interface Control (0x07) register. If setting the filed is successful, which means that the slave supports 4-line mode, the host is also switched to 4-line mode.
3. If high-speed mode is enabled in the host configuration, the SHS bit is set in the High Speed (0x13) register.
In particular, the driver does not set any bits in (1) I/O Enable and Int Enable registers, (2) I/O block sizes, etc. Applications can set them by calling :cpp:func:`sdmmc_io_write_byte`.
For card configuration and data transfer, choose the pair of functions relevant to your case from the table below.
========================================================================= ================================= =================================
Action Read Function Write Function
========================================================================= ================================= =================================
Read and write a single byte using IO_RW_DIRECT (CMD52) :cpp:func:`sdmmc_io_read_byte` :cpp:func:`sdmmc_io_write_byte`
Read and write multiple bytes using IO_RW_EXTENDED (CMD53) in byte mode :cpp:func:`sdmmc_io_read_bytes` :cpp:func:`sdmmc_io_write_bytes`
Read and write blocks of data using IO_RW_EXTENDED (CMD53) in block mode :cpp:func:`sdmmc_io_read_blocks` :cpp:func:`sdmmc_io_write_blocks`
========================================================================= ================================= =================================
SDIO interrupts can be enabled by the application using the function :cpp:func:`sdmmc_io_enable_int`. When using SDIO in 1-line mode, the D1 line also needs to be connected to use SDIO interrupts.
If you want the application to wait until the SDIO interrupt occurs, use :cpp:func:`sdmmc_io_wait_int`.
The application can wait for SDIO interrupt to occur using :cpp:func:`sdmmc_io_wait_int`.
Combo (memory + IO) cards
^^^^^^^^^^^^^^^^^^^^^^^^^
The driver does not support SD combo cards. Combo cards will be treated as IO cards.
The driver does not support SD combo cards. Combo cards are treated as IO cards.
Thread safety
^^^^^^^^^^^^^
Most applications need to use the protocol layer only in one task; therefore the protocol layer doesn't implement any kind of locking on the :cpp:class:`sdmmc_card_t` structure, or when accessing SDMMC or SD SPI host drivers. Such locking is usually implemented in the higher layer (e.g. in the filesystem driver).
Most applications need to use the protocol layer only in one task. For this reason, the protocol layer does not implement any kind of locking on the :cpp:class:`sdmmc_card_t` structure, or when accessing SDMMC or SD SPI host drivers. Such locking is usually implemented on a higher layer, e.g., in the filesystem driver.
API Reference

View File

@@ -5,7 +5,7 @@ See also
- :doc:`Partition Table documentation <../../api-guides/partition-tables>`
- :doc:`Over The Air Update (OTA) API <../system/ota>` provides high-level API for updating app firmware stored in flash.
- :doc:`Non-Volatile Storage (NVS) API <nvs_flash>` provides a structured API for storing small items of data in SPI flash.
- :doc:`Non-Volatile Storage (NVS) API <nvs_flash>` provides a structured API for storing small pieces of data in SPI flash.
.. _spi-flash-implementation-details:
@@ -13,40 +13,27 @@ See also
Implementation details
----------------------
In order to perform some flash operations, we need to make sure both CPUs
are not running any code from flash for the duration of the flash operation.
In a single-core setup this is easy: we disable interrupts/scheduler and do
the flash operation. In the dual-core setup this is slightly more complicated.
We need to make sure that the other CPU doesn't run any code from flash.
In order to perform some flash operations, it is necessary to make sure that both CPUs are not running any code from flash for the duration of the flash operation:
- In a single-core setup, the SDK does it by disabling interrupts/scheduler before performing the flash operation.
- In a dual-core setup, this is slightly more complicated as the SDK needs to make sure that the other CPU is not running any code from flash.
When SPI flash API is called on CPU A (can be PRO or APP), we start
spi_flash_op_block_func function on CPU B using esp_ipc_call API. This API
wakes up high priority task on CPU B and tells it to execute given function,
in this case spi_flash_op_block_func. This function disables cache on CPU B and
signals that cache is disabled by setting s_flash_op_can_start flag.
Then the task on CPU A disables cache as well, and proceeds to execute flash
operation.
When SPI flash API is called on CPU A (can be PRO or APP), start the spi_flash_op_block_func function on CPU B using the esp_ipc_call API. This API wakes up a high priority task on CPU B and tells it to execute a given function, in this case, spi_flash_op_block_func. This function disables cache on CPU B and signals that the cache is disabled by setting the s_flash_op_can_start flag. Then the task on CPU A disables cache as well and proceeds to execute flash operation.
While flash operation is running, interrupts can still run on CPUs A and B.
We assume that all interrupt code is placed into RAM. Once interrupt allocation
API is added, we should add a flag to request interrupt to be disabled for
the duration of flash operations.
While a flash operation is running, interrupts can still run on CPUs A and B. It is assumed that all interrupt code is placed into RAM. Once the interrupt allocation API is added, a flag should be added to request the interrupt to be disabled for the duration of a flash operations.
Once flash operation is complete, function on CPU A sets another flag,
s_flash_op_complete, to let the task on CPU B know that it can re-enable
cache and release the CPU. Then the function on CPU A re-enables the cache on
CPU A as well and returns control to the calling code.
Once the flash operation is complete, the function on CPU A sets another flag, s_flash_op_complete, to let the task on CPU B know that it can re-enable cache and release the CPU. Then the function on CPU A re-enables the cache on CPU A as well and returns control to the calling code.
Additionally, all API functions are protected with a mutex (s_flash_op_mutex).
In a single core environment (:ref:`CONFIG_FREERTOS_UNICORE` enabled), we simply
disable both caches, no inter-CPU communication takes place.
In a single core environment (:ref:`CONFIG_FREERTOS_UNICORE` enabled), you need to disable both caches, so that no inter-CPU communication can take place.
API Reference - SPI Flash
-------------------------
.. include:: /_build/inc/esp_spi_flash.inc
.. include:: /_build/inc/esp_flash_spi_init.inc
.. include:: /_build/inc/esp_flash.inc
.. include:: /_build/inc/spi_flash_types.inc
API Reference - Partition Table
-------------------------------

View File

@@ -4,15 +4,16 @@ SPIFFS Filesystem
Overview
--------
SPIFFS is a file system intended for SPI NOR flash devices on embedded targets.
It supports wear leveling, file system consistency checks and more.
SPIFFS is a file system intended for SPI NOR flash devices on embedded targets. It supports wear levelling, file system consistency checks, and more.
Notes
-----
- Currently, SPIFFS does not support directories. It produces a flat structure. If SPIFFS is mounted under ``/spiffs``, then creating a file with path ``/spiffs/tmp/myfile.txt`` will create a file called ``/tmp/myfile.txt`` in SPIFFS, instead of ``myfile.txt`` under directory ``/spiffs/tmp``.
- It is not a realtime stack. One write operation might last much longer than another.
- Currently, it does not detect or handle bad blocks.
- Currently, SPIFFS does not support directories, it produces a flat structure. If SPIFFS is mounted under ``/spiffs``, then creating a file with the path ``/spiffs/tmp/myfile.txt`` will create a file called ``/tmp/myfile.txt`` in SPIFFS, instead of ``myfile.txt`` in the directory ``/spiffs/tmp``.
- It is not a real-time stack. One write operation might take much longer than another.
- For now, it does not detect or handle bad blocks.
Tools
-----
@@ -21,76 +22,94 @@ spiffsgen.py
^^^^^^^^^^^^
:component_file:`spiffsgen.py<spiffs/spiffsgen.py>` is a write-only Python SPIFFS implementation used to create filesystem
images from the contents of a host folder. To use ``spiffsgen.py``, simply invoke it from your favorite terminal::
images from the contents of a host folder. To use ``spiffsgen.py``, open Terminal and run::
python spiffsgen.py <image_size> <base_dir> <output_file>
- image_size: size of the partition on which the created SPIFFS image will be flashed to
- base_dir: directory to create the SPIFFS image of
- output_file: SPIFFS image output file
The required arguments are as follows:
Besides the three required arguments: *image_size*, *base_dir* and *output_file*, there are other arguments
that control image generation. Documentation on these arguments exist in the tool's help::
- **image_size**: size of the partition onto which the created SPIFFS image will be flashed.
- **base_dir**: directory for which the SPIFFS image needs to be created.
- **output_file**: SPIFFS image output file.
There are also other arguments that control image generation. Documentation on these arguments can be found in the tool's help::
python spiffsgen.py --help
These optional arguments correspond to possible SPIFFS build configuration.
User should make sure that the image is generated with the same arguments/configuration as
SPIFFS was built with, else the user ends up with an invalid image. As a guide, the help output indicates the SPIFFS
build configuration the argument corresponds to. In cases when these arguments
are not specified, the default values shown in the help output are used.
These optional arguments correspond to a possible SPIFFS build configuration. To generate the right image, please make sure that you use the same arguments/configuration as were used to build SPIFFS. As a guide, the help output indicates the SPIFFS build configuration to which the argument corresponds. In cases when these arguments are not specified, the default values shown in the help output will be used.
Once the image has been created, it can be flashed using ``esptool.py`` or ``parttool.py``.
When the image is created, it can be flashed using ``esptool.py`` or ``parttool.py``.
Aside from invoking ``spiffsgen.py`` standalone, it is also possible to use it directly from the build system by calling
``spiffs_create_partition_image``.
Aside from invoking the ``spiffsgen.py`` standalone by manually running it from the command line or a script, it is also possible to invoke ``spiffsgen.py`` directly from the build system by calling ``spiffs_create_partition_image``.
Make::
$(eval $(call spiffs_create_partition_image,<partition>,<base_dir>,[FLASH_IN_PROJECT]))
SPIFFS_IMAGE_FLASH_IN_PROJECT := ...
SPIFFS_IMAGE_DEPENDS := ...
$(eval $(call spiffs_create_partition_image,<partition>,<base_dir>))
CMake::
spiffs_create_partition_image(<partition> <base_dir> [FLASH_IN_PROJECT])
spiffs_create_partition_image(<partition> <base_dir> [FLASH_IN_PROJECT] [DEPENDS dep dep dep...])
This is more convenient as the build configuration is automatically passed to the tool,
ensuring that the image generated is valid for that build. An example of this is while the *image_size* is required
for the standalone invocation, only the *partition* name is required when using ``spiffs_create_partition_image`` --
the image size is automatically obtained from the project's partition table.
It is important to note that due to the differences in structure between the two build systems,
when using Make, ``spiffs_create_partition_image`` must be called from the project Makefile;
for CMake, it should be called from one of the component CMakeLists.txt. For both build systems, the image will be created in the build directory
with filename *partition*.bin.
This is more convenient as the build configuration is automatically passed to the tool, ensuring that the generated image is valid for that build. An example of this is while the *image_size* is required for the standalone invocation, only the *partition* name is required when using ``spiffs_create_partition_image`` -- the image size is automatically obtained from the project's partition table.
Due to the differences in structure between Make and CMake, it is important to note that:
- for Make ``spiffs_create_partition_image`` must be called from the project Makefile
- for CMake ``spiffs_create_partition_image`` must be called from one of the component CMakeLists.txt files
Optionally, user can opt to have the image automatically flashed together with the app binaries, partition tables, etc. on
``idf.py flash`` or ``make flash`` by specifying ``FLASH_IN_PROJECT``. For example::
``idf.py flash`` or ``make flash`` by specifying ``FLASH_IN_PROJECT``. For example,
in Make::
SPIFFS_IMAGE_FLASH_IN_PROJECT := 1
$(eval $(call spiffs_create_partition_image,<partition>,<base_dir>))
in CMake::
spiffs_create_partition_image(my_spiffs_partition my_folder FLASH_IN_PROJECT)
If FLASH_IN_PROJECT is not specified, the image is still generated,
but user has to flash it manually using ``esptool.py``, ``parttool.py`` or a custom build system target.
If FLASH_IN_PROJECT/SPIFFS_IMAGE_FLASH_IN_PROJECT is not specified, the image will still be generated, but you will have to flash it manually using ``esptool.py``, ``parttool.py``, or a custom build system target.
For an example, see :example:`examples/storage/spiffsgen>`.
There are cases where the contents of the base directory itself is generated at build time. Users can use DEPENDS/SPIFFS_IMAGE_DEPENDS to specify targets
that should be executed before generating the image.
in Make::
dep:
...
SPIFFS_IMAGE_DEPENDS := dep
$(eval $(call spiffs_create_partition_image,<partition>,<base_dir>))
in CMake::
add_custom_target(dep COMMAND ...)
spiffs_create_partition_image(my_spiffs_partition my_folder DEPENDS dep)
+For an example, see :example:`examples/storage/spiffsgen>`.
mkspiffs
^^^^^^^^
Another tool for creating SPIFS partition images is `mkspiffs <https://github.com/igrr/mkspiffs>`_.
Like ``spiffsgen.py``, it can be used to create image from a given folder and then flash that image with ``esptool.py``
Another tool for creating SPIFFS partition images is `mkspiffs <https://github.com/igrr/mkspiffs>`_.
Similar to ``spiffsgen.py``, it can be used to create an image from a given folder and then flash that image using ``esptool.py``
To do that you need to obtain some parameters:
For that, you need to obtain the following parameters:
- Block Size: 4096 (standard for SPI Flash)
- Page Size: 256 (standard for SPI Flash)
- Image Size: Size of the partition in bytes (can be obtained from partition table)
- Partition Offset: Starting address of the partition (can be obtained from partition table)
- **Block Size**: 4096 (standard for SPI Flash)
- **Page Size**: 256 (standard for SPI Flash)
- **Image Size**: Size of the partition in bytes (can be obtained from a partition table)
- **Partition Offset**: Starting address of the partition (can be obtained from a partition table)
To pack a folder into 1 Megabyte image::
To pack a folder into a 1-Megabyte image, run::
mkspiffs -c [src_folder] -b 4096 -p 256 -s 0x100000 spiffs.bin
To flash the image to ESP32 at offset 0x110000::
To flash the image onto ESP32 at offset 0x110000, run::
python esptool.py --chip esp32 --port [port] --baud [baud] write_flash -z 0x110000 spiffs.bin
@@ -98,21 +117,15 @@ To flash the image to ESP32 at offset 0x110000::
Notes on which SPIFFS tool to use
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The two tools presented above offer very similar functionality. There are, however, reasons to prefer one
over the other depending on the use case.
The two tools presented above offer very similar functionality. However, there are reasons to prefer one over the other, depending on the use case.
If the intent is to simply generate a SPIFFS image during build, ``spiffsgen.py`` makes it very convenient
by providing functions/commands from the build system itself. This makes it easy to generate SPIFFS images
that match the build configuration and can be flashed together with the application.
Another case for choosing ``spiffsgen.py`` is when the host has no C/C++ compiler available, since ``mkspiffs``
requires compilation.
Use ``spiffsgen.py`` in the following cases:
1. If you want to simply generate a SPIFFS image during the build. ``spiffsgen.py`` makes it very convenient by providing functions/commands from the build system itself.
2. If the host has no C/C++ compiler available, because ``spiffsgen.py`` does not require compilation.
On the other hand, ``mkspiffs`` offers unpacking SPIFFS images in addition to image generation. This is not
possible with ``spiffsgen.py``, at least not yet. There might also be environments where a Python interpreter
is not available, but a host compiler is or a pre-compiled ``mkspiffs`` binary
can do the job. However, there is no build system integration for ``mkspiffs`` and the user has to
do the corresponding work: compiling ``mkspiffs`` during build (if a pre-compiled binary is not used), creating build rules/targets
for the output files, passing proper parameters to the tool, etc.
Use ``mkspiffs`` in the following cases:
1. If you need to unpack SPIFFS images in addition to image generation. For now, it is not possible with ``spiffsgen.py``.
2. If you have an environment where a Python interpreter is not available, but a host compiler is available. Otherwise, a pre-compiled ``mkspiffs`` binary can do the job. However, there is no build system integration for ``mkspiffs`` and the user has to do the corresponding work: compiling ``mkspiffs`` during build (if a pre-compiled binary is not used), creating build rules/targets for the output files, passing proper parameters to the tool, etc.
See also
@@ -120,14 +133,14 @@ See also
- :doc:`Partition Table documentation <../../api-guides/partition-tables>`
Application Example
-------------------
An example for using SPIFFS is provided in :example:`storage/spiffs` directory. This example initializes and mounts SPIFFS partition, and writes and reads data from it using POSIX and C library APIs. See README.md file in the example directory for more information.
An example of using SPIFFS is provided in the :example:`storage/spiffs` directory. This example initializes and mounts a SPIFFS partition, then writes and reads data from it using POSIX and C library APIs. See the README.md file in the example directory for more information.
High level API Reference
High-level API Reference
------------------------
* :component_file:`spiffs/include/esp_spiffs.h`
.. include:: /_build/inc/esp_spiffs.inc

View File

@@ -9,7 +9,7 @@ See also
Application Example
-------------------
An example which combines wear levelling driver with FATFS library is provided in ``examples/storage/wear_levelling`` directory. This example initializes the wear levelling driver, mounts FATFS partition, and writes and reads data from it using POSIX and C library APIs. See README.md file in the example directory for more information.
An example which combines the wear levelling driver with the FATFS library is provided in the :example:`storage/wear_levelling` directory. This example initializes the wear levelling driver, mounts FATFS partition, as well as writes and reads data from it using POSIX and C library APIs. See the :example:`storage/wear_levelling/README.md` file for more information.
High level API Reference
------------------------

View File

@@ -0,0 +1,108 @@
App Image Format
================
An application image consists of the following structures:
1. The :cpp:type:`esp_image_header_t` structure describes the mode of SPI flash and the count of memory segments.
2. The :cpp:type:`esp_image_segment_header_t` structure describes each segment, its length, and its location in ESP32's memory, followed by the data with a length of ``data_len``. The data offset for each segment in the image is calculated in the following way:
* offset for 0 Segment = sizeof(:cpp:type:`esp_image_header_t`) + sizeof(:cpp:type:`esp_image_segment_header_t`).
* offset for 1 Segment = offset for 0 Segment + length of 0 Segment + sizeof(:cpp:type:`esp_image_segment_header_t`).
* offset for 2 Segment = offset for 1 Segment + length of 1 Segment + sizeof(:cpp:type:`esp_image_segment_header_t`).
* ...
The count of each segment is defined in the ``segment_count`` field that is stored in :cpp:type:`esp_image_header_t`. The count cannot be more than :cpp:type:`ESP_IMAGE_MAX_SEGMENTS`.
To get the list of your image segments, please run the following command:
::
esptool.py --chip esp32 image_info build/app.bin
::
esptool.py v2.3.1
Image version: 1
Entry point: 40080ea4
13 segments
Segment 1: len 0x13ce0 load 0x3f400020 file_offs 0x00000018 SOC_DROM
Segment 2: len 0x00000 load 0x3ff80000 file_offs 0x00013d00 SOC_RTC_DRAM
Segment 3: len 0x00000 load 0x3ff80000 file_offs 0x00013d08 SOC_RTC_DRAM
Segment 4: len 0x028e0 load 0x3ffb0000 file_offs 0x00013d10 DRAM
Segment 5: len 0x00000 load 0x3ffb28e0 file_offs 0x000165f8 DRAM
Segment 6: len 0x00400 load 0x40080000 file_offs 0x00016600 SOC_IRAM
Segment 7: len 0x09600 load 0x40080400 file_offs 0x00016a08 SOC_IRAM
Segment 8: len 0x62e4c load 0x400d0018 file_offs 0x00020010 SOC_IROM
Segment 9: len 0x06cec load 0x40089a00 file_offs 0x00082e64 SOC_IROM
Segment 10: len 0x00000 load 0x400c0000 file_offs 0x00089b58 SOC_RTC_IRAM
Segment 11: len 0x00004 load 0x50000000 file_offs 0x00089b60 SOC_RTC_DATA
Segment 12: len 0x00000 load 0x50000004 file_offs 0x00089b6c SOC_RTC_DATA
Segment 13: len 0x00000 load 0x50000004 file_offs 0x00089b74 SOC_RTC_DATA
Checksum: e8 (valid)Validation Hash: 407089ca0eae2bbf83b4120979d3354b1c938a49cb7a0c997f240474ef2ec76b (valid)
You can also see the information on segments in the IDF logs while your application is booting:
::
I (443) esp_image: segment 0: paddr=0x00020020 vaddr=0x3f400020 size=0x13ce0 ( 81120) map
I (489) esp_image: segment 1: paddr=0x00033d08 vaddr=0x3ff80000 size=0x00000 ( 0) load
I (530) esp_image: segment 2: paddr=0x00033d10 vaddr=0x3ff80000 size=0x00000 ( 0) load
I (571) esp_image: segment 3: paddr=0x00033d18 vaddr=0x3ffb0000 size=0x028e0 ( 10464) load
I (612) esp_image: segment 4: paddr=0x00036600 vaddr=0x3ffb28e0 size=0x00000 ( 0) load
I (654) esp_image: segment 5: paddr=0x00036608 vaddr=0x40080000 size=0x00400 ( 1024) load
I (695) esp_image: segment 6: paddr=0x00036a10 vaddr=0x40080400 size=0x09600 ( 38400) load
I (737) esp_image: segment 7: paddr=0x00040018 vaddr=0x400d0018 size=0x62e4c (405068) map
I (847) esp_image: segment 8: paddr=0x000a2e6c vaddr=0x40089a00 size=0x06cec ( 27884) load
I (888) esp_image: segment 9: paddr=0x000a9b60 vaddr=0x400c0000 size=0x00000 ( 0) load
I (929) esp_image: segment 10: paddr=0x000a9b68 vaddr=0x50000000 size=0x00004 ( 4) load
I (971) esp_image: segment 11: paddr=0x000a9b74 vaddr=0x50000004 size=0x00000 ( 0) load
I (1012) esp_image: segment 12: paddr=0x000a9b7c vaddr=0x50000004 size=0x00000 ( 0) load
For more details on the type of memory segments and their address ranges, see the ESP32 Technical Reference Manual, Section 1.3.2 *Embedded Memory*.
3. The image has a single checksum byte after the last segment. This byte is written on a sixteen byte padded boundary, so the application image might need padding.
4. If the ``hash_appended`` field from :cpp:type:`esp_image_header_t` is set then a SHA256 checksum will be appended. The value of SHA256 is calculated on the range from first byte and up to this field. The length of this field is 32 bytes.
5. If the options :ref:`CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT` or :ref:`CONFIG_SECURE_BOOT_ENABLED` are enabled then the application image will have additional 68 bytes for an ECDSA signature, which includes:
* version word (4 bytes),
* signature data (64 bytes).
Application Description
-----------------------
The ``DROM`` segment starts with the :cpp:type:`esp_app_desc_t` structure which carries specific fields describing the application:
* ``secure_version`` - see :doc:`Anti-rollback</api-reference/system/ota>`.
* ``version`` - see :doc:`App version</api-reference/system/system>`. ``*``
* ``project_name`` is filled from ``PROJECT_NAME``. ``*``
* ``time`` and ``date`` - compile time and date.
* ``idf_ver`` - version of ESP-IDF. ``*``
* ``app_elf_sha256`` - contains sha256 for the elf application file.
``*`` - The maximum length is 32 characters, including null-termination character. For example, if the length of ``PROJECT_NAME`` exceeds 32 characters, the excess characters will be disregarded.
This structure is useful for identification of images uploaded OTA because it has a fixed offset = sizeof(:cpp:type:`esp_image_header_t`) + sizeof(:cpp:type:`esp_image_segment_header_t`). As soon as a device receives the first fragment containing this structure, it has all the information to determine whether the update should be continued or not.
Adding a Custom Structure to an Application
-------------------------------------------
Customer also has the opportunity to have similar structure with a fixed offset relative to the beginning of the image.
The following pattern can be used to add a custom structure to your image:
::
const __attribute__((section(".rodata_custom_desc"))) esp_custom_app_desc_t custom_app_desc = { ... }
Offset for custom structure is sizeof(:cpp:type:`esp_image_header_t`) + sizeof(:cpp:type:`esp_image_segment_header_t`) + sizeof(:cpp:type:`esp_app_desc_t`).
To guarantee that the custom structure is located in the image even if it is not used, you need to add:
* For Make: add ``COMPONENT_ADD_LDFLAGS += -u custom_app_desc`` into ``component.mk``
* For Cmake: add ``target_link_libraries(${COMPONENT_TARGET} "-u custom_app_desc")`` into ``CMakeLists.txt``
API Reference
-------------
.. include:: /_build/inc/esp_app_format.inc

View File

@@ -31,8 +31,8 @@ The component has API functions for reading and writing fields. Access to the fi
CSV files:
* common (`esp_efuse_table.csv`) - contains eFuse fields which are used inside the IDF. C-source generation should be done manually when changing this file (run command 'make efuse_common_table' or `idf.py efuse_common_table`). Note that changes in this file can lead to incorrect operation.
* custom - (optional and can be enabled by :envvar:`CONFIG_EFUSE_CUSTOM_TABLE`) contains eFuse fields that are used by the user in their application. C-source generation should be done manually when changing this file (run command 'make efuse_custom_table' or `idf.py efuse_custom_table`).
* common (`esp_efuse_table.csv`) - contains eFuse fields which are used inside the IDF. C-source generation should be done manually when changing this file (run command ``idf.py efuse_common_table``). Note that changes in this file can lead to incorrect operation.
* custom - (optional and can be enabled by :envvar:`CONFIG_EFUSE_CUSTOM_TABLE`) contains eFuse fields that are used by the user in their application. C-source generation should be done manually when changing this file and running ``idf.py efuse_custom_table``.
Description CSV file
@@ -84,7 +84,7 @@ efuse_table_gen.py tool
The tool is designed to generate C-source files from CSV file and validate fields. First of all, the check is carried out on the uniqueness of the names and overlaps of the field bits. If an additional `custom` file is used, it will be checked with the existing `common` file (esp_efuse_table.csv). In case of errors, a message will be displayed and the string that caused the error. C-source files contain structures of type `esp_efuse_desc_t`.
To generate a `common` files, use the following command 'make efuse_common_table' or `idf.py efuse_common_table` or:
To generate a `common` files, use the following command ``idf.py efuse_common_table`` or:
::
@@ -96,7 +96,7 @@ After generation in the folder `esp32` create:
* `esp_efuse_table.c` file.
* In `include` folder `esp_efuse_table.c` file.
To generate a `custom` files, use the following command 'make efuse_custom_table' or `idf.py efuse_custom_table` or:
To generate a `custom` files, use the following command ``idf.py efuse_custom_table`` or:
::
@@ -170,7 +170,7 @@ For frequently used fields, special functions are made, like this :cpp:func:`esp
How add a new field
-------------------
1. Find a free bits for field. Show `esp_efuse_table.csv` file or run ``make show_efuse_table`` or ``idf.py show_efuse_table`` or the next command:
1. Find a free bits for field. Show `esp_efuse_table.csv` file or run ``idf.py show_efuse_table`` or the next command:
::

View File

@@ -323,6 +323,51 @@ The following example demonstrates queue set usage with ring buffers.
...
}
Ring Buffers with Static Allocation
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The :cpp:func:`xRingbufferCreateStatic` can be used to create ring buffers with specific memory requirements (such as a ring buffer being allocated in external RAM). All blocks of memory used by a ring buffer must be manually allocated beforehand then passed to the :cpp:func:`xRingbufferCreateStatic` to be initialized as a ring buffer. These blocks include the following:
- The ring buffer's data structure of type :cpp:type:`StaticRingbuffer_t`
- The ring buffer's storage area of size ``xBufferSize``. Note that ``xBufferSize`` must be 32-bit aligned for no-split/allow-split buffers.
The manner in which these blocks are allocated will depend on the users requirements (e.g. all blocks being statically declared, or dynamically allocated with specific capabilities such as external RAM).
.. note::
The :ref:`CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION` option must be enabled in `menuconfig` for statically allocated ring buffers to be available.
.. note::
When deleting a ring buffer created via :cpp:func:`xRingbufferCreateStatic`,
the function :cpp:func:`vRingbufferDelete` will not free any of the memory blocks. This must be done manually by the user after :cpp:func:`vRingbufferDelete` is called.
The code snippet below demonstrates a ring buffer being allocated entirely in external RAM.
.. code-block:: c
#include "freertos/ringbuf.h"
#include "freertos/semphr.h"
#include "esp_heap_caps.h"
#define BUFFER_SIZE 400 //32-bit aligned size
#define BUFFER_TYPE RINGBUF_TYPE_NOSPLIT
...
//Allocate ring buffer data structure and storage area into external RAM
StaticRingbuffer_t *buffer_struct = (StaticRingbuffer_t *)heap_caps_malloc(sizeof(StaticRingbuffer_t), MALLOC_CAP_SPIRAM);
uint8_t *buffer_storage = (uint8_t *)heap_caps_malloc(sizeof(uint8_t)*BUFFER_SIZE, MALLOC_CAP_SPIRAM);
//Create a ring buffer with manually allocated memory
RingbufHandle_t handle = xRingbufferCreateStatic(BUFFER_SIZE, BUFFER_TYPE, buffer_storage, buffer_struct);
...
//Delete the ring buffer after used
vRingbufferDelete(handle);
//Manually free all blocks of memory
free(buffer_struct);
free(buffer_storage);
Ring Buffer API Reference
-------------------------
@@ -375,7 +420,7 @@ Interrupt respectively.
Vanilla FreeRTOS hooks are referred to as **Legacy Hooks** in ESP-IDF FreeRTOS.
To enable legacy hooks, :ref:`CONFIG_FREERTOS_LEGACY_HOOKS` should be enabled
in ``make menuconfig``.
in :doc:`project configuration menu </api-reference/kconfig>`.
Due to vanilla FreeRTOS being designed for single core, ``vApplicationIdleHook()``
and ``vApplicationTickHook()`` can only be defined once. However, the ESP32 is dual core

View File

@@ -38,7 +38,7 @@ Heap corruption detection allows you to detect various types of heap memory erro
Assertions
^^^^^^^^^^
The heap implementation (``multi_heap.c``, etc.) includes a lot of assertions which will fail if the heap memory is corrupted. To detect heap corruption most effectively, ensure that assertions are enabled in ``make menuconfig`` under ``Compiler options``.
The heap implementation (``multi_heap.c``, etc.) includes a lot of assertions which will fail if the heap memory is corrupted. To detect heap corruption most effectively, ensure that assertions are enabled in the project configuration menu under ``Compiler options`` -> :ref:`CONFIG_COMPILER_OPTIMIZATION_ASSERTION_LEVEL`.
If a heap integrity assertion fails, a line will be printed like ``CORRUPT HEAP: multi_heap.c:225 detected at 0x3ffbb71c``. The memory address which is printed is the address of the heap structure which has corrupt content.
@@ -62,7 +62,7 @@ Configuration
Temporarily increasing the heap corruption detection level can give more detailed information about heap corruption errors.
In ``make menuconfig``, under ``Component config`` there is a menu ``Heap memory debugging``. The setting :ref:`CONFIG_HEAP_CORRUPTION_DETECTION` can be set to one of three levels:
In the project configuration menu, under ``Component config`` there is a menu ``Heap memory debugging``. The setting :ref:`CONFIG_HEAP_CORRUPTION_DETECTION` can be set to one of three levels:
Basic (no poisoning)
++++++++++++++++++++
@@ -143,7 +143,7 @@ Standalone Mode
Once you've identified the code which you think is leaking:
- Under ``make menuconfig``, navigate to ``Component settings`` -> ``Heap Memory Debugging`` -> ``Heap tracing`` and select ``Standalone`` option (see :ref:`CONFIG_HEAP_TRACING_DEST`).
- In the project configuration menu, navigate to ``Component settings`` -> ``Heap Memory Debugging`` -> ``Heap tracing`` and select ``Standalone`` option (see :ref:`CONFIG_HEAP_TRACING_DEST`).
- Call the function :cpp:func:`heap_trace_init_standalone` early in the program, to register a buffer which can be used to record the memory trace.
- Call the function :cpp:func:`heap_trace_start` to begin recording all mallocs/frees in the system. Call this immediately before the piece of code which you suspect is leaking memory.
- Call the function :cpp:func:`heap_trace_stop` to stop the trace once the suspect piece of code has finished executing.
@@ -205,7 +205,7 @@ In ``HEAP_TRACE_LEAKS`` mode, for each traced memory allocation which has not al
- ``caller 0x...`` gives the call stack of the call to malloc()/free(), as a list of PC addresses.
These can be decoded to source files and line numbers, as shown above.
The depth of the call stack recorded for each trace entry can be configured in ``make menuconfig``, under ``Heap Memory Debugging`` -> ``Enable heap tracing`` -> ``Heap tracing stack depth``. Up to 10 stack frames can be recorded for each allocation (the default is 2). Each additional stack frame increases the memory usage of each ``heap_trace_record_t`` record by eight bytes.
The depth of the call stack recorded for each trace entry can be configured in the project configuration menu, under ``Heap Memory Debugging`` -> ``Enable heap tracing`` -> ``Heap tracing stack depth``. Up to 10 stack frames can be recorded for each allocation (the default is 2). Each additional stack frame increases the memory usage of each ``heap_trace_record_t`` record by eight bytes.
Finally, the total number of 'leaked' bytes (bytes allocated but not freed while trace was running) is printed, and the total number of allocations this represents.
@@ -217,9 +217,9 @@ Host-Based Mode
Once you've identified the code which you think is leaking:
- Under ``make menuconfig``, navigate to ``Component settings`` -> ``Heap Memory Debugging`` -> ``Heap tracing`` and select ``Host-Based`` option (see :ref:`CONFIG_HEAP_TRACING_DEST`).
- Under ``make menuconfig``, navigate to ``Component settings`` -> ``Application Level Tracing`` -> ``Data Destination`` and select ``Trace memory``.
- Under ``make menuconfig``, navigate to ``Component settings`` -> ``Application Level Tracing`` -> ``FreeRTOS SystemView Tracing`` and check ``SystemView Tracing Enable``.
- In the project configuration menu, navigate to ``Component settings`` -> ``Heap Memory Debugging`` -> :ref:`CONFIG_HEAP_TRACING_DEST` and select ``Host-Based``.
- In the project configuration menu, navigate to ``Component settings`` -> ``Application Level Tracing`` -> :ref:`CONFIG_ESP32_APPTRACE_DESTINATION` and select ``Trace memory``.
- In the project configuration menu, navigate to ``Component settings`` -> ``Application Level Tracing`` -> ``FreeRTOS SystemView Tracing`` and enable :ref:`CONFIG_SYSVIEW_ENABLE`.
- Call the function :cpp:func:`heap_trace_init_tohost` early in the program, to initialize JTAG heap tracing module.
- Call the function :cpp:func:`heap_trace_start` to begin recording all mallocs/frees in the system. Call this immediately before the piece of code which you suspect is leaking memory.
In host-based mode argument to this function is ignored and heap tracing module behaves like ``HEAP_TRACE_ALL`` was passed: all allocations and deallocations are sent to the host.
@@ -250,7 +250,7 @@ An example::
To gather and analyse heap trace do the following on the host:
1. Build the program and download it to the target as described in :doc:`Build and Flash </get-started/make-project>`.
1. Build the program and download it to the target as described in :ref:`Getting Started Guide <get-started-build>`.
2. Run OpenOCD (see :doc:`JTAG Debugging </api-guides/jtag-debugging/index>`).

View File

@@ -23,6 +23,7 @@ System API
ESP HTTPS OTA <esp_https_ota>
ESP pthread <esp_pthread>
Error Codes and Helper Functions <esp_err>
App image format <app_image_format>
Miscellaneous System APIs <system>

View File

@@ -41,7 +41,7 @@ DRAM
At startup, the DRAM heap contains all data memory which is not statically allocated by the app. Reducing statically allocated buffers will increase the amount of available free heap.
To find the amount of statically allocated memory, use the :ref:`make size <make-size>` or :ref:`idf.py size <idf.py-size>` (for CMake) command.
To find the amount of statically allocated memory, use the :ref:`idf.py size <idf.py-size>` command.
.. note:: Due to a technical limitation, the maximum statically allocated DRAM usage is 160KB. The remaining 160KB (for a total of 320KB of DRAM) can only be allocated at runtime as heap.
@@ -52,7 +52,7 @@ IRAM
At startup, the IRAM heap contains all instruction memory which is not used by the app executable code.
The :ref:`make size <make-size>` and :ref:`idf.py size <idf.py-size>` commands can be used to find the amount of IRAM used by the app.
The :ref:`idf.py size <idf.py-size>` command can be used to find the amount of IRAM used by the app.
D/IRAM
^^^^^^
@@ -113,6 +113,13 @@ API Reference - Heap Allocation
.. include:: /_build/inc/esp_heap_caps.inc
Thread Safety
^^^^^^^^^^^^^
Heap functions are thread safe, meaning they can be called from different tasks simultaneously without any limitations.
It is technically possible to call ``malloc``, ``free``, and related functions from interrupt handler (ISR) context. However this is not recommended, as heap function calls may delay other interrupts. It is strongly recommended to refactor applications so that any buffers used by an ISR are pre-allocated outside of the ISR. Support for calling heap functions from ISRs may be removed in a future update.
Heap Tracing & Debugging
------------------------

View File

@@ -188,8 +188,7 @@ Restrictions:
``security_version``:
- In application image it is stored in ``esp_app_desc`` structure. The number is set
:ref:`CONFIG_BOOTLOADER_APP_SECURE_VERSION`.
- In application image it is stored in ``esp_app_desc`` structure. The number is set :ref:`CONFIG_BOOTLOADER_APP_SECURE_VERSION`.
- In ESP32 it is stored in efuse ``EFUSE_BLK3_RDATA4_REG``. (when a eFuse bit is programmed to 1, it can never be reverted to 0). The number of bits set in this register is the ``security_version`` from app.
.. _secure-ota-updates:
@@ -199,6 +198,104 @@ Secure OTA Updates Without Secure boot
The verification of signed OTA updates can be performed even without enabling hardware secure boot. For doing so, refer :ref:`signed-app-verify`
OTA Tool (otatool.py)
---------------------
The component `app_update` provides a tool :component_file:`otatool.py<app_update/otatool.py>` for performing OTA partition-related operations on a target device. The following operations can be performed using the tool:
- read contents of otadata partition (read_otadata)
- erase otadata partition, effectively resetting device to factory app (erase_otadata)
- switch OTA partitions (switch_ota_partition)
- erasing OTA partition (erase_ota_partition)
- write to OTA partition (write_ota_partition)
- read contents of OTA partition (read_ota_partition)
The tool can either be imported and used from another Python script or invoked from shell script for users wanting to perform operation programmatically. This is facilitated by the tool's Python API
and command-line interface, respectively.
Python API
^^^^^^^^^^
Before anything else, make sure that the `otatool` module is imported.
.. code-block:: python
import sys
import os
idf_path = os.environ["IDF_PATH"] # get value of IDF_PATH from environment
otatool_dir = os.path.join(idf_path, "components", "app_update") # otatool.py lives in $IDF_PATH/components/app_update
sys.path.append(otatool_dir) # this enables Python to find otatool module
from otatool import * # import all names inside otatool module
The starting point for using the tool's Python API to do is create a `OtatoolTarget` object:
.. code-block:: python
# Create a partool.py target device connected on serial port /dev/ttyUSB1
target = OtatoolTarget("/dev/ttyUSB1")
The created object can now be used to perform operations on the target device:
.. code-block:: python
# Erase otadata, reseting the device to factory app
target.erase_otadata()
# Erase contents of OTA app slot 0
target.erase_ota_partition(0)
# Switch boot partition to that of app slot 1
target.switch_ota_partition(1)
# Read OTA partition 'ota_3' and save contents to a file named 'ota_3.bin'
target.read_ota_partition("ota_3", "ota_3.bin")
The OTA partition to operate on is specified using either the app slot number or the partition name.
More information on the Python API is available in the docstrings for the tool.
Command-line Interface
^^^^^^^^^^^^^^^^^^^^^^
The command-line interface of `otatool.py` has the following structure:
.. code-block:: bash
otatool.py [command-args] [subcommand] [subcommand-args]
- command-args - these are arguments that are needed for executing the main command (parttool.py), mostly pertaining to the target device
- subcommand - this is the operation to be performed
- subcommand-args - these are arguments that are specific to the chosen operation
.. code-block:: bash
# Erase otadata, resetting the device to factory app
otatool.py --port "/dev/ttyUSB1" erase_otadata
# Erase contents of OTA app slot 0
otatool.py --port "/dev/ttyUSB1" erase_ota_partition --slot 0
# Switch boot partition to that of app slot 1
otatool.py --port "/dev/ttyUSB1" switch_ota_partition --slot 1
# Read OTA partition 'ota_3' and save contents to a file named 'ota_3.bin'
otatool.py --port "/dev/ttyUSB1" read_ota_partition --name=ota_3
More information can be obtained by specifying `--help` as argument:
.. code-block:: bash
# Display possible subcommands and show main command argument descriptions
otatool.py --help
# Show descriptions for specific subcommand arguments
otatool.py [subcommand] --help
See also
--------

View File

@@ -1,6 +1,8 @@
Power Management
================
:link_to_translation:`zh_CN:[中文]`
Overview
--------
@@ -125,7 +127,7 @@ The following drivers will hold the ``ESP_PM_APB_FREQ_MAX`` lock while the drive
- **SPI slave**: between calls to :cpp:func:`spi_slave_initialize` and :cpp:func:`spi_slave_free`.
- **Ethernet**: between calls to :cpp:func:`esp_eth_enable` and :cpp:func:`esp_eth_disable`.
- **WiFi**: between calls to :cpp:func:`esp_wifi_start` and :cpp:func:`esp_wifi_stop`. If modem sleep is enabled, the lock will be released for the periods of time when radio is disabled.
- **Bluetooth**: between calls to :cpp:func:`esp_bt_controller_enable` and :cpp:func:`esp_bt_controller_disable`. If Bluetooth modem sleep is enabled, the ``ESP_PM_APB_FREQ_MAX`` lock will be released for the periods of time when radio is disabled. However the ``ESP_PM_NO_LIGHT_SLEEP`` lock will still be held.
- **Bluetooth**: between calls to :cpp:func:`esp_bt_controller_enable` and :cpp:func:`esp_bt_controller_disable`. If Bluetooth modem sleep is enabled, the ``ESP_PM_APB_FREQ_MAX`` lock will be released for the periods of time when radio is disabled. However the ``ESP_PM_NO_LIGHT_SLEEP`` lock will still be held, unless :ref:`CONFIG_BTDM_LOW_POWER_CLOCK` option is set to "External 32kHz crystal".
- **CAN**: between calls to :cpp:func:`can_driver_install` and :cpp:func:`can_driver_uninstall`.
The following peripheral drivers are not aware of DFS yet. Applications need to acquire/release locks themselves, when necessary:

View File

@@ -109,21 +109,38 @@ SDK version
:cpp:func:`esp_get_idf_version` returns a string describing the IDF version which was used to compile the application. This is the same value as the one available through ``IDF_VER`` variable of the build system. The version string generally has the format of ``git describe`` output.
To get the version at build time, additional version macros are provided. They can be used to enable or disable parts of the program depending on IDF version.
* :c:macro:`ESP_IDF_VERSION_MAJOR`, :c:macro:`ESP_IDF_VERSION_MINOR`, :c:macro:`ESP_IDF_VERSION_PATCH` are defined to integers representing major, minor, and patch version.
* :c:macro:`ESP_IDF_VERSION_VAL` and :c:macro:`ESP_IDF_VERSION` can be used when implementing version checks:
.. code-block:: c
#include "esp_idf_version.h"
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0)
// enable functionality present in IDF v4.0
#endif
App version
-----------
Application version is stored in :cpp:class:`esp_app_desc_t` structure. It is located in DROM sector and has a fixed offset from the beginning of the binary file.
The structure is located after :cpp:class:`esp_image_header_t` and :cpp:class:`esp_image_segment_header_t` structures. The field version has string type and max length 32 chars.
To set version in your project manually you need to set ``PROJECT_VER`` variable in your project Makefile/CMakeLists.txt:
To set version in your project manually you need to set ``PROJECT_VER`` variable in your project CMakeLists.txt/Makefile:
* For Make build system: in application Makefile put ``PROJECT_VER = "0.1.0.1"`` before including project.mk
* For Cmake build system: in application CMakeLists.txt put ``set(PROJECT_VER "0.1.0.1")`` before including project.cmake.
* In application CMakeLists.txt put ``set(PROJECT_VER "0.1.0.1")`` before including ``project.cmake``.
If ``PROJECT_VER`` variable is not set in project Makefile/CMakeLists.txt then it will be retrieved from either ``$(PROJECT_PATH)/version.txt`` file (if present) else using git command ``git describe``. If neither is available then ``PROJECT_VER`` will be set to "1". Application can make use of this by calling :cpp:func:`esp_ota_get_app_description` or :cpp:func:`esp_ota_get_partition_description` functions.
(For legacy GNU Make build system: in application Makefile put ``PROJECT_VER = "0.1.0.1"`` before including ``project.mk``.)
If ``PROJECT_VER`` variable is not set in the project then it will be retrieved from either ``$(PROJECT_PATH)/version.txt`` file (if present) else using git command ``git describe``. If neither is available then ``PROJECT_VER`` will be set to "1". Application can make use of this by calling :cpp:func:`esp_ota_get_app_description` or :cpp:func:`esp_ota_get_partition_description` functions.
API Reference
-------------
.. include:: /_build/inc/esp_system.inc
.. include:: /_build/inc/esp_idf_version.inc

View File

@@ -6,7 +6,7 @@ Overview
The ESP-IDF has support for two types of watchdogs: The Interrupt Watchdog Timer
and the Task Watchdog Timer (TWDT). The Interrupt Watchdog Timer and the TWDT
can both be enabled using ``make menuconfig``, however the TWDT can also be
can both be enabled using :ref:`project-configuration-menu`, however the TWDT can also be
enabled during runtime. The Interrupt Watchdog is responsible for detecting
instances where FreeRTOS task switching is blocked for a prolonged period of
time. The TWDT is responsible for detecting instances of tasks running without
@@ -63,7 +63,7 @@ longer call :cpp:func:`esp_task_wdt_reset`. Once all tasks have unsubscribed
form the TWDT, the TWDT can be deinitialized by calling
:cpp:func:`esp_task_wdt_deinit()`.
By default :ref:`CONFIG_ESP_TASK_WDT` in ``make menuconfig`` will be enabled causing
By default :ref:`CONFIG_ESP_TASK_WDT` in :ref:`project-configuration-menu` be enabled causing
the TWDT to be initialized automatically during startup. Likewise
:ref:`CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0` and
:ref:`CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1` are also enabled by default causing

View File

@@ -79,7 +79,7 @@ API Reference
For example see :idf_file:`docs/en/api-reference/wifi/esp_wifi.rst`
6. Optionally, rather that using ``*.inc`` files, you may want to describe API in you own way. See :idf_file:`docs/en/api-guides/ulp-cmake.rst` for example.
6. Optionally, rather that using ``*.inc`` files, you may want to describe API in you own way. See :idf_file:`docs/en/api-guides/ulp.rst` for example.
Below is the list of common ``.. doxygen...::`` directives: