mirror of
https://github.com/espressif/esp-idf.git
synced 2026-05-04 03:52:01 +02:00
Moved files into separate folders per 'en' and 'zh_CN' language version and linked 'zh_CN' files back to 'en' files if translation is not yet available
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
BT COMMON
|
||||
=========
|
||||
|
||||
.. toctree::
|
||||
:caption: Bluetooth Common Defines and APIs
|
||||
|
||||
Bluetooth DEFINE <esp_bt_defs>
|
||||
Bluetooth MAIN <esp_bt_main>
|
||||
Bluetooth DEVICE <esp_bt_device>
|
||||
@@ -0,0 +1,11 @@
|
||||
BT LE
|
||||
=========
|
||||
|
||||
.. toctree::
|
||||
:caption: Bluetooth LE
|
||||
|
||||
BLE GAP <esp_gap_ble>
|
||||
BLE GATT DEFINE <esp_gatt_defs>
|
||||
BLE GATT SERVER <esp_gatts>
|
||||
BLE GATT CLIENT <esp_gattc>
|
||||
BLE BLUFI <esp_blufi>
|
||||
@@ -0,0 +1,10 @@
|
||||
CLASSIC BT
|
||||
==========
|
||||
|
||||
.. toctree::
|
||||
:caption: Classic BT
|
||||
|
||||
BT GAP <esp_gap_bt>
|
||||
BT A2DP <esp_a2dp>
|
||||
BT AVRC <esp_avrc>
|
||||
BT SPP <esp_spp>
|
||||
@@ -0,0 +1,21 @@
|
||||
Controller && VHCI
|
||||
==================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
`Instructions`_
|
||||
|
||||
.. _Instructions: ../template.html
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
|
||||
Check :example:`bluetooth` 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`.
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/bt.inc
|
||||
@@ -0,0 +1,22 @@
|
||||
Bluetooth A2DP API
|
||||
==================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
`Instructions`_
|
||||
|
||||
.. _Instructions: ../template.html
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
|
||||
Check :example:`bluetooth` 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`
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/esp_a2dp_api.inc
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
BT AVRCP APIs
|
||||
=============
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
Bluetooth AVRCP reference APIs.
|
||||
|
||||
`Instructions`_
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
|
||||
`Instructions`_
|
||||
|
||||
.. _Instructions: ../template.html
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/esp_avrc_api.inc
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
BLUFI API
|
||||
=========
|
||||
|
||||
Overview
|
||||
--------
|
||||
BLUFI is a profile based GATT to config ESP32 WIFI to connect/disconnect AP or setup a softap and etc.
|
||||
Use should concern these things:
|
||||
|
||||
1. The event sent from profile. Then you need to do something as the event indicate.
|
||||
2. Security reference. You can write your own Security functions such as symmetrical encryption/decryption and checksum functions. Even you can define the "Key Exchange/Negotiation" procedure.
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
|
||||
Check :example:`bluetooth` 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`
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/esp_blufi_api.inc
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
BT GENERIC DEFINES
|
||||
==================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
`Instructions`_
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
|
||||
`Instructions`_
|
||||
|
||||
.. _Instructions: ../template.html
|
||||
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/esp_bt_defs.inc
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
BT DEVICE APIs
|
||||
===============
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
Bluetooth device reference APIs.
|
||||
|
||||
`Instructions`_
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
|
||||
`Instructions`_
|
||||
|
||||
.. _Instructions: ../template.html
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/esp_bt_device.inc
|
||||
@@ -0,0 +1,22 @@
|
||||
BT MAIN API
|
||||
===========
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
`Instructions`_
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
|
||||
`Instructions`_
|
||||
|
||||
.. _Instructions: ../template.html
|
||||
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/esp_bt_main.inc
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
GAP API
|
||||
=======
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
`Instructions`_
|
||||
|
||||
.. _Instructions: ../template.html
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
|
||||
Check :example:`bluetooth` 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>`
|
||||
|
||||
* 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>`
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/esp_gap_ble_api.inc
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
CLASSIC BLUETOOTH GAP API
|
||||
=========================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
`Instructions`_
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
|
||||
`Instructions`_
|
||||
|
||||
.. _Instructions: ../template.html
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/esp_gap_bt_api.inc
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
GATT DEFINES
|
||||
============
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
`Instructions`_
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
|
||||
`Instructions`_
|
||||
|
||||
.. _Instructions: ../template.html
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/esp_gatt_defs.inc
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
GATT CLIENT API
|
||||
===============
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
`Instructions`_
|
||||
|
||||
.. _Instructions: ../template.html
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
|
||||
Check :example:`bluetooth` 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>`
|
||||
|
||||
* 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>`
|
||||
|
||||
* 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`
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/esp_gattc_api.inc
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
GATT SERVER API
|
||||
===============
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
`Instructions`_
|
||||
|
||||
.. _Instructions: ../template.html
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
|
||||
Check :example:`bluetooth` 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>`
|
||||
|
||||
* 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>`
|
||||
|
||||
* 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`
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/esp_gatts_api.inc
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
SPP API
|
||||
===============
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
`Instructions`_
|
||||
|
||||
.. _Instructions: ../template.html
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
|
||||
Check :example:`bluetooth` 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`
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/esp_spp_api.inc
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
Bluetooth API
|
||||
*************
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
Bluetooth Controller && VHCI <controller_vhci>
|
||||
Bluetooth Common <bt_common>
|
||||
Bluetooth LE <bt_le>
|
||||
Bluetooth Classic <classic_bt>
|
||||
|
||||
|
||||
To see the overview of the ESP32 Bluetooth stack architecture, follow links below:
|
||||
|
||||
* `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>`_
|
||||
|
||||
Example code for this API section is provided in :example:`bluetooth` directory of ESP-IDF examples.
|
||||
|
||||
Several examples contain detailed description. To see them please follow links below:
|
||||
|
||||
* :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>`
|
||||
@@ -0,0 +1,47 @@
|
||||
ETHERNET
|
||||
========
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
|
||||
Ethernet example: :example:`ethernet/ethernet`.
|
||||
|
||||
PHY Interfaces
|
||||
--------------
|
||||
|
||||
The configured PHY model(s) are set in software by configuring the eth_config_t structure for the given PHY.
|
||||
|
||||
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.
|
||||
|
||||
* :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`
|
||||
|
||||
PHY Configuration Constants
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. doxygenvariable:: phy_tlk110_default_ethernet_config
|
||||
.. doxygenvariable:: phy_lan8720_default_ethernet_config
|
||||
|
||||
|
||||
API Reference - Ethernet
|
||||
------------------------
|
||||
|
||||
.. include:: /_build/inc/esp_eth.inc
|
||||
|
||||
API Reference - PHY Common
|
||||
--------------------------
|
||||
|
||||
.. include:: /_build/inc/phy.inc
|
||||
|
||||
API Reference - PHY TLK110
|
||||
--------------------------
|
||||
|
||||
.. include:: /_build/inc/phy_tlk110.inc
|
||||
|
||||
API Reference - PHY LAN8720
|
||||
---------------------------
|
||||
|
||||
.. include:: /_build/inc/phy_lan8720.inc
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
Ethernet API
|
||||
************
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
Ethernet <esp_eth>
|
||||
|
||||
|
||||
Example code for this API section is provided in :example:`ethernet` directory of ESP-IDF examples.
|
||||
@@ -0,0 +1,16 @@
|
||||
*************
|
||||
API Reference
|
||||
*************
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
Wi-Fi <wifi/index>
|
||||
Bluetooth <bluetooth/index>
|
||||
Ethernet <ethernet/index>
|
||||
Peripherals <peripherals/index>
|
||||
Protocols <protocols/index>
|
||||
Storage <storage/index>
|
||||
System <system/index>
|
||||
Configuration Options <kconfig>
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
Configuration Options
|
||||
*********************
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
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`.
|
||||
|
||||
Configuration Options Reference
|
||||
===============================
|
||||
|
||||
Subsequent sections contain the list of available ESP-IDF options, automatically generated from Kconfig files. Note that depending on the options selected, some options listed here may not be visible by default in the interface of menuconfig.
|
||||
|
||||
By convention, all option names are upper case with underscores. When Kconfig generates sdkconfig and sdkconfig.h files, option names are prefixed with ``CONFIG_``. So if an option ``ENABLE_FOO`` is defined in a Kconfig file and selected in menuconfig, then sdkconfig and sdkconfig.h files will have ``CONFIG_ENABLE_FOO`` defined. In this reference, option names are also prefixed with ``CONFIG_``, same as in the source code.
|
||||
|
||||
|
||||
.. include:: /_build/inc/kconfig.inc
|
||||
|
||||
Customisations
|
||||
==============
|
||||
|
||||
Because IDF builds by default with :ref:`warn-undefined-variables`, when the Kconfig tool generates Makefiles (the ``auto.conf`` file) its behaviour has been customised. In normal Kconfig, a variable which is set to "no" is undefined. In IDF's version of Kconfig, this variable is defined in the Makefile but has an empty value.
|
||||
|
||||
(Note that ``ifdef`` and ``ifndef`` can still be used in Makefiles, because they test if a variable is defined *and has a non-empty value*.)
|
||||
|
||||
When generating header files for C & C++, the behaviour is not customised - so ``#ifdef`` can be used to test if a boolean config item is set or not.
|
||||
|
||||
.. _Kconfig: https://www.kernel.org/doc/Documentation/kbuild/kconfig-language.txt
|
||||
@@ -0,0 +1,207 @@
|
||||
Analog to Digital Converter
|
||||
===========================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
ESP32 integrates two 12-bit SAR (`Successive Approximation Register <https://en.wikipedia.org/wiki/Successive_approximation_ADC>`_) ADCs (Analog to Digital Converters) and supports measurements on 18 channels (analog enabled pins). Some of these pins can be used to build a programmable gain amplifier which is used for the measurement of small analog signals.
|
||||
|
||||
The ADC driver API supports ADC1 (8 channels, attached to GPIOs 32 - 39), and ADC2 (10 channels, attached to GPIOs 0, 2, 4, 12 - 15 and 25 - 27).
|
||||
However, there're some restrictions for the application to use ADC2:
|
||||
|
||||
1. The application can use ADC2 only when Wi-Fi driver is not started, since the ADC is also used by the Wi-Fi driver, which has higher priority.
|
||||
2. Some of the ADC2 pins are used as strapping pins (GPIO 0, 2, 15), so they cannot be used freely. For examples, for official Develop Kits:
|
||||
|
||||
- `ESP32 Core Board V2 / ESP32 DevKitC <http://esp-idf.readthedocs.io/en/latest/hw-reference/modules-and-boards.html#esp32-core-board-v2-esp32-devkitc>`_: GPIO 0 cannot be used due to external auto program circuits.
|
||||
- `ESP-WROVER-KIT V3 <http://esp-idf.readthedocs.io/en/latest/hw-reference/modules-and-boards.html#esp-wrover-kit-v3>`_: GPIO 0, 2, 4 and 15 cannot be used due to external connections for different purposes.
|
||||
|
||||
Configuration and Reading ADC
|
||||
-----------------------------
|
||||
|
||||
The ADC should be configured before reading is taken.
|
||||
|
||||
- For ADC1, configure desired precision and attenuation by calling functions :cpp:func:`adc1_config_width` and :cpp:func:`adc1_config_channel_atten`.
|
||||
- For ADC2, configure the attenuation by :cpp:func:`adc2_config_channel_atten`. The reading width of ADC2 is configured every time you take the reading.
|
||||
|
||||
Attenuation configuration is done per channel, see :cpp:type:`adc1_channel_t` and :cpp:type:`adc2_channel_t`, set as a parameter of above functions.
|
||||
|
||||
Then it is possible to read ADC conversion result with :cpp:func:`adc1_get_raw` and :cpp:func:`adc2_get_raw`. Reading width of ADC2 should be set as a parameter of :cpp:func:`adc2_get_raw` instead of in the configuration functions.
|
||||
|
||||
.. note:: Since the ADC2 is shared with the WIFI module, which has higher priority, reading operation of :cpp:func:`adc2_get_raw` will fail between :cpp:func:`esp_wifi_start()` and :cpp:func:`esp_wifi_stop()`. Use the return code to see whether the reading is successful.
|
||||
|
||||
It is also possible to read the internal hall effect sensor via ADC1 by calling dedicated function :cpp:func:`hall_sensor_read`. Note that even the hall sensor is internal to ESP32, reading from it uses channels 0 and 3 of ADC1 (GPIO 36 and 39). Do not connect anything else to these pins and do not change their configuration. Otherwise it may affect the measurement of low value signal from the sesnor.
|
||||
|
||||
This API provides convenient way to configure ADC1 for reading from :doc:`ULP <../../api-guides/ulp>`. To do so, call function :cpp:func:`adc1_ulp_enable` and then set precision and attenuation as discussed above.
|
||||
|
||||
There is another specific function :cpp:func:`adc2_vref_to_gpio` used to route internal reference voltage to a GPIO pin. It comes handy to calibrate ADC reading and this is discussed in section :ref:`adc-api-adc-calibration`.
|
||||
|
||||
Application Examples
|
||||
--------------------
|
||||
|
||||
Reading voltage on ADC1 channel 0 (GPIO 36)::
|
||||
|
||||
#include <driver/adc.h>
|
||||
|
||||
...
|
||||
|
||||
adc1_config_width(ADC_WIDTH_BIT_12);
|
||||
adc1_config_channel_atten(ADC1_CHANNEL_0,ADC_ATTEN_DB_0);
|
||||
int val = adc1_get_raw(ADC1_CHANNEL_0);
|
||||
|
||||
The input voltage in above example is from 0 to 1.1V (0 dB attenuation). The input range can be extended by setting higher attenuation, see :cpp:type:`adc_atten_t`.
|
||||
An example using the ADC driver including calibration (discussed below) is available in esp-idf: :example:`peripherals/adc`
|
||||
|
||||
Reading voltage on ADC2 channel 7 (GPIO 27)::
|
||||
|
||||
#include <driver/adc.h>
|
||||
|
||||
...
|
||||
|
||||
int read_raw;
|
||||
adc2_config_channel_atten( ADC2_CHANNEL_7, ADC_ATTEN_0db );
|
||||
|
||||
esp_err_t r = adc2_get_raw( ADC2_CHANNEL_7, ADC_WIDTH_12Bit, &read_raw);
|
||||
if ( r == ESP_OK ) {
|
||||
printf("%d\n", read_raw );
|
||||
} else if ( r == ESP_ERR_TIMEOUT ) {
|
||||
printf("ADC2 used by Wi-Fi.\n");
|
||||
}
|
||||
|
||||
The reading may fail due to collision with Wi-Fi, should check it.
|
||||
An example using the ADC2 driver to read the output of DAC is available in esp-idf: :example:`peripherals/adc2`
|
||||
|
||||
Reading the internal hall effect sensor::
|
||||
|
||||
#include <driver/adc.h>
|
||||
|
||||
...
|
||||
|
||||
adc1_config_width(ADC_WIDTH_BIT_12);
|
||||
int val = hall_sensor_read();
|
||||
|
||||
|
||||
|
||||
The value read in both these examples is 12 bits wide (range 0-4095).
|
||||
|
||||
.. _adc-api-adc-calibration:
|
||||
|
||||
Minimizing Noise
|
||||
----------------
|
||||
|
||||
The ESP32 ADC can be sensitive to noise leading to large discrepancies in ADC readings. To minimize noise, users may connect a 0.1uF capacitor to the ADC input pad in use. Multisampling may also be used to further mitigate the effects of noise.
|
||||
|
||||
.. figure:: ../../_static/adc-noise-graph.jpg
|
||||
:align: center
|
||||
:alt: ADC noise mitigation
|
||||
|
||||
Graph illustrating noise mitigation using capacitor and multisampling of 64 samples.
|
||||
|
||||
ADC Calibration
|
||||
---------------
|
||||
|
||||
The :component_file:`esp_adc_cal/include/esp_adc_cal.h` API provides functions to correct for differences in measured voltages caused by variation of ADC reference voltages (Vref) between chips. Per design the ADC reference voltage is 1100mV, however the true reference voltage can range from 1000mV to 1200mV amongst different ESP32s.
|
||||
|
||||
.. figure:: ../../_static/adc-vref-graph.jpg
|
||||
:align: center
|
||||
:alt: ADC reference voltage comparison
|
||||
|
||||
Graph illustrating effect of differing reference voltages on the ADC voltage curve.
|
||||
|
||||
Correcting ADC readings using this API involves characterizing one of the ADCs at a given attenuation to obtain a characteristics curve (ADC-Voltage curve) that takes into account the difference in ADC reference voltage. The characteristics curve is in the form of ``y = coeff_a * x + coeff_b`` and is used to convert ADC readings to voltages in mV. Calculation of the characteristics curve is based on calibration values which can be stored in eFuse or provided by the user.
|
||||
|
||||
Calibration Values
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Calibration values are used to generate characteristic curves that account for the unique ADC reference voltage of a particular ESP32. There are currently three sources of calibration values. The availability of these calibration values will depend on the type and production date of the ESP32 chip/module.
|
||||
|
||||
**Two Point** values represent each of the ADCs’ readings at 150mV and 850mV. These values are measured and burned into eFuse ``BLOCK3`` during factory calibration.
|
||||
|
||||
**eFuse Vref** represents the true ADC reference voltage. This value is measured and burned into eFuse ``BLOCK0`` during factory calibration.
|
||||
|
||||
**Default Vref** is an estimate of the ADC reference voltage provided by the user as a parameter during characterization. If Two Point or eFuse Vref values are unavailable, **Default Vref** will be used.
|
||||
|
||||
Application Example
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
For a full example see esp-idf: :example:`peripherals/adc`
|
||||
|
||||
Characterizing an ADC at a particular attenuation::
|
||||
|
||||
#include "driver/adc.h"
|
||||
#include "esp_adc_cal.h"
|
||||
|
||||
...
|
||||
|
||||
//Characterize ADC at particular atten
|
||||
esp_adc_cal_characteristics_t *adc_chars = calloc(1, sizeof(esp_adc_cal_characteristics_t));
|
||||
esp_adc_cal_value_t val_type = esp_adc_cal_characterize(unit, atten, ADC_WIDTH_BIT_12, DEFAULT_VREF, adc_chars);
|
||||
//Check type of calibration value used to characterize ADC
|
||||
if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) {
|
||||
printf("eFuse Vref");
|
||||
} else if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP) {
|
||||
printf("Two Point");
|
||||
} else {
|
||||
printf("Default");
|
||||
}
|
||||
|
||||
Reading an ADC then converting the reading to a voltage::
|
||||
|
||||
#include "driver/adc.h"
|
||||
#include "esp_adc_cal.h"
|
||||
|
||||
...
|
||||
uint32_t reading = adc1_get_raw(ADC1_CHANNEL_5);
|
||||
uint32_t voltage = esp_adc_cal_raw_to_voltage(reading, adc_chars);
|
||||
|
||||
Routing ADC reference voltage to GPIO, so it can be manually measured (for **Default Vref**)::
|
||||
|
||||
#include "driver/adc.h"
|
||||
|
||||
...
|
||||
|
||||
esp_err_t status = adc2_vref_to_gpio(GPIO_NUM_25);
|
||||
if (status == ESP_OK) {
|
||||
printf("v_ref routed to GPIO\n");
|
||||
} else {
|
||||
printf("failed to route v_ref\n");
|
||||
}
|
||||
|
||||
GPIO Lookup Macros
|
||||
------------------
|
||||
|
||||
There are macros available to specify the GPIO number of a ADC channel, or vice versa.
|
||||
e.g.
|
||||
|
||||
1. ``ADC1_CHANNEL_0_GPIO_NUM`` is the GPIO number of ADC1 channel 0 (36);
|
||||
2. ``ADC1_GPIO32_CHANNEL`` is the ADC1 channel number of GPIO 32 (ADC1 channel 4).
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
This reference covers three components:
|
||||
|
||||
* :ref:`adc-api-reference-adc-driver`
|
||||
* :ref:`adc-api-reference-adc-calibration`
|
||||
* :ref:`adc-api-reference-gpio-lookup-macros`
|
||||
|
||||
|
||||
.. _adc-api-reference-adc-driver:
|
||||
|
||||
ADC driver
|
||||
^^^^^^^^^^
|
||||
|
||||
.. include:: /_build/inc/adc.inc
|
||||
|
||||
.. _adc-api-reference-adc-calibration:
|
||||
|
||||
ADC Calibration
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
.. include:: /_build/inc/esp_adc_cal.inc
|
||||
|
||||
.. _adc-api-reference-gpio-lookup-macros:
|
||||
|
||||
GPIO Lookup Macros
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. include:: /_build/inc/adc_channel.inc
|
||||
@@ -0,0 +1,41 @@
|
||||
Digital To Analog Converter
|
||||
===========================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
ESP32 has two 8-bit DAC (digital to analog converter) channels, connected to GPIO25 (Channel 1) and GPIO26 (Channel 2).
|
||||
|
||||
The DAC driver allows these channels to be set to arbitrary voltages.
|
||||
|
||||
The DAC channels can also be driven with DMA-style written sample data, via the :doc:`I2S driver <i2s>` when using the "built-in DAC mode".
|
||||
|
||||
For other analog output options, see the :doc:`Sigma-delta Modulation module <sigmadelta>` and the :doc:`LED Control module <ledc>`. Both these modules produce high frequency PWM output, which can be hardware low-pass filtered in order to generate a lower frequency analog output.
|
||||
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
|
||||
Setting DAC channel 1 (GPIO 25) voltage to approx 0.78 of VDD_A voltage (VDD * 200 / 255). For VDD_A 3.3V, this is 2.59V::
|
||||
|
||||
#include <driver/dac.h>
|
||||
|
||||
...
|
||||
|
||||
dac_output_enable(DAC_CHANNEL_1);
|
||||
dac_output_voltage(DAC_CHANNEL_1, 200);
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/dac.inc
|
||||
|
||||
GPIO Lookup Macros
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
Some useful macros can be used to specified the GPIO number of a DAC channel, or vice versa.
|
||||
e.g.
|
||||
|
||||
1. ``DAC_CHANNEL_1_GPIO_NUM`` is the GPIO number of channel 1 (25);
|
||||
2. ``DAC_GPIO26_CHANNEL`` is the channel number of GPIO 26 (channel 2).
|
||||
|
||||
.. include:: /_build/inc/dac_channel.inc
|
||||
@@ -0,0 +1,28 @@
|
||||
GPIO & RTC GPIO
|
||||
===============
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
The ESP32 chip features 40 physical GPIO pads. Some GPIO pads cannot be used or do not have the corresponding pin on the chip package(refer to technical reference manual). Each pad can be used as a general purpose I/O or can be connected to an internal peripheral signal.
|
||||
|
||||
- Note that GPIO6-11 are usually used for SPI flash.
|
||||
- GPIO34-39 can only be set as input mode and do not have software pullup or pulldown functions.
|
||||
|
||||
There is also separate "RTC GPIO" support, which functions when GPIOs are routed to the "RTC" low-power and analog subsystem. These pin functions can be used when in deep sleep, when the :doc:`Ultra Low Power co-processor <../../api-guides/ulp>` is running, or when analog functions such as ADC/DAC/etc are in use.
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
|
||||
GPIO output and input interrupt example: :example:`peripherals/gpio`.
|
||||
|
||||
API Reference - Normal GPIO
|
||||
---------------------------
|
||||
|
||||
.. include:: /_build/inc/gpio.inc
|
||||
|
||||
API Reference - RTC GPIO
|
||||
------------------------
|
||||
|
||||
.. include:: /_build/inc/rtc_io.inc
|
||||
|
||||
@@ -0,0 +1,337 @@
|
||||
I2C
|
||||
===
|
||||
|
||||
An I2C (Inter-Integrated Circuit) bus can be used for communication with several external devices connected to the same bus as ESP32. There are two I2C controllers on board of the ESP32, each of which can be set to master mode or slave mode.
|
||||
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
The following sections will walk you through typical steps to configure and operate the I2C driver:
|
||||
|
||||
1. :ref:`i2c-api-configure-driver` - select driver's parameters like master or slave mode, set specific GPIO pins to act as SDA and SCL, set the clock speed, etc.
|
||||
2. :ref:`i2c-api-install-driver`- activate driver in master or slave mode to operate on one of the two I2C controllers available on ESP32.
|
||||
3. :ref:`i2c-api-run-communication`:
|
||||
|
||||
a) :ref:`i2c-api-master-mode` - run communication acting as a master
|
||||
b) :ref:`i2c-api-slave-mode` - get slave responding to messages from the master
|
||||
|
||||
4. :ref:`i2c-api-interrupt-handling` - configure and service I2C interrupts.
|
||||
5. :ref:`i2c-api-going-beyond-defaults` - adjust timing, pin configuration and other parameters of the I2C communication.
|
||||
6. :ref:`i2c-api-error-handling` - how to recognize and handle driver configuration and communication errors.
|
||||
7. :ref:`i2c-api-delete-driver`- on communication end to free resources used by the I2C driver.
|
||||
|
||||
The top level identification of an I2C driver is one of the two port numbers selected from :cpp:type:`i2c_port_t`. The mode of operation for a given port is provided during driver configuration by selecting either "master" or "slave" from :cpp:type:`i2c_mode_t`.
|
||||
|
||||
|
||||
.. _i2c-api-configure-driver:
|
||||
|
||||
Configure Driver
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
The first step to establishing I2C communication is to configure the driver. This is done by setting several parameters contained in :cpp:type:`i2c_config_t` structure:
|
||||
|
||||
* I2C **operation mode** - select either slave or master from :cpp:type:`i2c_opmode_t`
|
||||
* Settings of the **communication pins**:
|
||||
|
||||
* GPIO pin numbers assigned to the SDA and SCL signals
|
||||
* Whether to enable ESP32's internal pull up for respective pins
|
||||
|
||||
* I2C **clock speed**, if this configuration concerns the master mode
|
||||
* If this configuration concerns the slave mode:
|
||||
|
||||
* Whether **10 bit address mode** should be enabled
|
||||
* The **slave address**
|
||||
|
||||
Then, to initialize configuration for a given I2C port, call function :cpp:func:`i2c_param_config` with the port number and :cpp:type:`i2c_config_t` structure as the function call parameters.
|
||||
|
||||
At this stage :cpp:func:`i2c_param_config` also sets "behind the scenes" couple of other I2C configuration parameters to commonly used default values. To check what are the values and how to change them, see :ref:`i2c-api-going-beyond-defaults`.
|
||||
|
||||
|
||||
.. _i2c-api-install-driver:
|
||||
|
||||
Install Driver
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
Having the configuration initialized, the next step is to install the I2C driver by calling :cpp:func:`i2c_driver_install`. This function call requires the following parameters:
|
||||
|
||||
* The port number, one of the two ports available, selected from :cpp:type:`i2c_port_t`
|
||||
* The operation mode, slave or master selected from :cpp:type:`i2c_opmode_t`
|
||||
* Sizes of buffers that will be allocated for sending and receiving data **in the slave mode**
|
||||
* Flags used to allocate the interrupt
|
||||
|
||||
|
||||
.. _i2c-api-run-communication:
|
||||
|
||||
Run Communication
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
With the I2C driver installed, ESP32 is ready to communicate with other I2C devices. Programming of communication depends on whether selected I2C port operates in a master or a slave mode.
|
||||
|
||||
|
||||
.. _i2c-api-master-mode:
|
||||
|
||||
Master Mode
|
||||
"""""""""""
|
||||
|
||||
ESP32's I2C port working in the master made is responsible for establishing communication with slave I2C devices and sending commands to trigger actions by slaves, like doing a measurement and sending back a result.
|
||||
|
||||
To organize this process the driver provides a container, called a "command link", that should be populated with a sequence of commands and then passed to the I2C controller for execution.
|
||||
|
||||
**Master Write**
|
||||
|
||||
An example of building a commend link for I2C master sending n bytes to slave is shown below:
|
||||
|
||||
.. blockdiag::
|
||||
:scale: 75
|
||||
:caption: I2C command link - master write example
|
||||
:align: center
|
||||
|
||||
blockdiag i2c-command-link-master-write {
|
||||
# global properties
|
||||
span_width = 5;
|
||||
span_height = 5;
|
||||
node_height = 25;
|
||||
default_group_color = lightgrey;
|
||||
class spacer [shape=none, width=10];
|
||||
class cmdlink [colwidth=2, width=180];
|
||||
class cjoint [shape=none, width=40];
|
||||
|
||||
# all the rows
|
||||
0 -- a0 -- f0 [style=none];
|
||||
1 -- a1 -- b1 -- c1 -- d1 -- e1 -- f1 -- g1 -- h1 [style=none];
|
||||
2 -- a2 -- b2 -- c2 -- d2 -- e2 -- f2 -- g2 [style=none];
|
||||
3 -- a3 -- d3 -- f3 [style=none];
|
||||
4 -- a4 [style=none];
|
||||
5 -- a5 [style=none];
|
||||
6 -- a6 -- c6 [style=none];
|
||||
7 -- a7 -- c7 -- d7 [style=none];
|
||||
8 -- a8 -- c8 -- f8 [style=none];
|
||||
9 -- a9 -- c9 -- h9 [style=none];
|
||||
10 -- a10 [style=none];
|
||||
11 -- a11 [style=none];
|
||||
|
||||
# separator row
|
||||
3, a3, d3, f3 [shape=none, height=5];
|
||||
|
||||
# tuning node properties and connections
|
||||
0 [class=spacer]; a0 [shape=none, colwidth=5]; f0 [shape=note, colwidth=2];
|
||||
1 [class=spacer]; a1 [shape=none]; b1; c1 [width=40]; e1 [shape=none, width=30]; g1 [shape=none, width=30]; h1 [width=40];
|
||||
2 [class=spacer]; a2 [shape=none]; b2; c2 [class=cjoint]; d2 [shape=none]; e2 [width=30]; f2 [shape=none]; g2 [width=30];
|
||||
3 [class=spacer]; a3 [shape=none, colwidth=3]; d3 [colwidth=2]; f3 [colwidth=2];
|
||||
4 [class=spacer]; a4 [class=cmdlink]
|
||||
5 [class=spacer]; a5 [class=cmdlink];
|
||||
6 [class=spacer]; a6 [class=cmdlink]; c6 [class=cjoint]; a6 -- c6 [style=solid]; c6 -- c2 -> c1 [folded];
|
||||
7 [class=spacer]; a7 [class=cmdlink]; c7 [class=cjoint]; d7 [shape=none, colwidth=2]; a7 -- c7 -- d7 [style=solid]; d7 -> d3 [folded];
|
||||
8 [class=spacer]; a8 [class=cmdlink]; c8 [class=cjoint, colwidth=3]; f8 [shape=none, colwidth=2]; a8 -- c8 -- f8 [style=solid]; f8 -> f3 [folded];
|
||||
9 [class=spacer]; a9 [class=cmdlink]; c9 [class=cjoint, colwidth=5]; h9 [shape=none, width=40]; a9 -- c9 -- h9 [style=solid]; h9 -> h1 [folded];
|
||||
10 [class=spacer]; a10 [class=cmdlink];
|
||||
11 [class=spacer]; a11 [class=cmdlink];
|
||||
|
||||
# labels
|
||||
f0 [label="Data n times", shape=note, color=yellow];
|
||||
b1 [label=Master, shape=note, color=lightyellow]; c1 [label=START]; d1 [label="Slave Address"]; f1 [label=Data]; h1 [label=STOP];
|
||||
b2 [label=Slave, shape=note, color=lightyellow]; e2 [label=ACK]; g2 [label=ACK];
|
||||
a4 [shape=note, label=Commands, color=yellow];
|
||||
a5 [label="cmd = i2c_cmd_link_create()", numbered = 1];
|
||||
a6 [label="i2c_master_start(cmd)", numbered = 2];
|
||||
a7 [label="i2c_master_write_byte(cmd, Address, ACK)", numbered = 3];
|
||||
a8 [label="i2c_master_write(Data, n, ACK)", numbered = 4];
|
||||
a9 [label="i2c_master_stop(cmd)", numbered = 5];
|
||||
a10 [label="i2c_master_cmd_begin(I2c_port, cmd, wait)", numbered = 6];
|
||||
a11 [label="i2c_cmd_link_delete(cmd)", numbered = 7];
|
||||
|
||||
# Slave Address
|
||||
group { d1; e1; }
|
||||
group { d2; e2; d3; }
|
||||
|
||||
# Data x n times
|
||||
group { f1; g1;}
|
||||
group { f2; g2; f3; }
|
||||
}
|
||||
|
||||
The following describes how the command link for a "master write" is set up and what comes inside:
|
||||
|
||||
1. The first step is to create a command link with :cpp:func:`i2c_cmd_link_create`.
|
||||
|
||||
Then the command link is populated with series of data to be sent to the slave:
|
||||
|
||||
2. **Start bit** - :cpp:func:`i2c_master_start`
|
||||
3. Single byte **slave address** - :cpp:func:`i2c_master_write_byte`. The address is provided as an argument of this function call.
|
||||
4. One or more bytes of **data** as an argument of :cpp:func:`i2c_master_write`.
|
||||
5. **Stop bit** - :cpp:func:`i2c_master_stop`
|
||||
|
||||
Both :cpp:func:`i2c_master_write_byte` and :cpp:func:`i2c_master_write` commands have additional argument defining whether slave should **acknowledge** received data or not.
|
||||
|
||||
6. Execution of command link by I2C controller is triggered by calling :cpp:func:`i2c_master_cmd_begin`.
|
||||
7. As the last step, after sending of the commands is finished, the resources used by the command link are released by calling :cpp:func:`i2c_cmd_link_delete`.
|
||||
|
||||
**Master Read**
|
||||
|
||||
There is a similar sequence of steps for the master to read the data from a slave.
|
||||
|
||||
.. blockdiag::
|
||||
:scale: 100
|
||||
:caption: I2C command link - master read example
|
||||
:align: center
|
||||
|
||||
blockdiag i2c-command-link-master-read {
|
||||
# global properties
|
||||
span_width = 5;
|
||||
span_height = 5;
|
||||
node_height = 25;
|
||||
default_group_color = lightgrey;
|
||||
class spacer [shape=none, width=10];
|
||||
class cmdlink [colwidth=2, width=180];
|
||||
class cjoint [shape=none, width=40];
|
||||
|
||||
# all the rows
|
||||
0 -- a0 -- f0 [style=none];
|
||||
1 -- a1 -- b1 -- c1 -- d1 -- e1 -- f1 -- g1 -- h1 -- i1 -- j1 [style=none];
|
||||
2 -- a2 -- b2 -- c2 -- d2 -- e2 -- f2 -- g2 -- h2 -- i2 [style=none];
|
||||
3 -- a3 -- d3 -- f3 -- h3 [style=none];
|
||||
4 -- a4 [style=none];
|
||||
5 -- a5 [style=none];
|
||||
6 -- a6 -- c6 [style=none];
|
||||
7 -- a7 -- c7 -- d7 [style=none];
|
||||
8 -- a8 -- c8 -- f8 [style=none];
|
||||
9 -- a9 -- c9 -- h9 [style=none];
|
||||
10 -- a10 -- c10 -- j10 [style=none];
|
||||
11 -- a11 [style=none];
|
||||
12 -- a12 [style=none];
|
||||
|
||||
# separator row
|
||||
3, a3, d3, f3, h3 [shape=none, height=5];
|
||||
|
||||
# tuning node properties and connections
|
||||
0 [class=spacer]; a0 [shape=none, colwidth=5]; f0 [shape=note, colwidth=2];
|
||||
1 [class=spacer]; a1 [shape=none]; b1; c1 [width=40]; e1 [shape=none, width=30]; f1 [shape=none]; g1 [width=30]; h1 [shape=none]; i1 [width=30]; j1 [width=40];
|
||||
2 [class=spacer]; a2 [shape=none]; b2; c2 [class=cjoint]; d2 [shape=none]; e2 [width=30]; g2 [shape=none, width=30]; i2 [shape=none, width=30];
|
||||
3 [class=spacer]; a3 [shape=none, colwidth=3]; d3 [colwidth=2]; f3 [colwidth=2]; h3 [colwidth=2];
|
||||
4 [class=spacer]; a4 [class=cmdlink]
|
||||
5 [class=spacer]; a5 [class=cmdlink];
|
||||
6 [class=spacer]; a6 [class=cmdlink]; c6 [class=cjoint]; a6 -- c6 [style=solid]; c6 -- c2 -> c1 [folded];
|
||||
7 [class=spacer]; a7 [class=cmdlink]; c7 [class=cjoint]; d7 [shape=none, colwidth=2]; a7 -- c7 -- d7 [style=solid]; d7 -> d3 [folded];
|
||||
8 [class=spacer]; a8 [class=cmdlink]; c8 [class=cjoint, colwidth=3]; f8 [shape=none, colwidth=2]; a8 -- c8 -- f8 [style=solid]; f8 -> f3 [folded];
|
||||
9 [class=spacer]; a9 [class=cmdlink]; c9 [class=cjoint, colwidth=5]; h9 [shape=none, colwidth=2]; a9 -- c9 -- h9 [style=solid]; h9 -> h3 [folded];
|
||||
10 [class=spacer]; a10 [class=cmdlink]; c10 [class=cjoint, colwidth=7]; j10 [shape=none, width=40]; a10 -- c10 -- j10 [style=solid]; j10 -> j1 [folded];
|
||||
11 [class=spacer]; a11 [class=cmdlink];
|
||||
12 [class=spacer]; a12 [class=cmdlink];
|
||||
|
||||
# labels
|
||||
f0 [label="Data (n-1) times", shape=note, color=yellow];
|
||||
b1 [label=Master, shape=note, color=lightyellow]; c1 [label=START]; d1 [label="Slave Address"]; g1 [label=ACK]; i1 [label=NAK]; j1 [label=STOP];
|
||||
b2 [label=Slave, shape=note, color=lightyellow]; e2 [label=ACK]; f2 [label=Data]; h2 [label=Data];
|
||||
a4 [shape=note, label=Commands, color=yellow];
|
||||
a5 [label="cmd = i2c_cmd_link_create()", numbered = 1];
|
||||
a6 [label="i2c_master_start(cmd)", numbered = 2];
|
||||
a7 [label="i2c_master_write_byte(cmd, Address, ACK)", numbered = 3];
|
||||
a8 [label="i2c_master_read(Data, n-1, ACK)", numbered = 4];
|
||||
a9 [label="i2c_master_read(Data, 1, NAK)", numbered = 5];
|
||||
a10 [label="i2c_master_stop(cmd)", numbered = 6];
|
||||
a11 [label="i2c_master_cmd_begin(I2c_port, cmd, wait)", numbered = 7];
|
||||
a12 [label="i2c_cmd_link_delete(cmd)", numbered = 8];
|
||||
|
||||
# Slave Address
|
||||
group { d1; e1; }
|
||||
group { d2; e2; d3; }
|
||||
|
||||
# Data x (n - 1) times
|
||||
group { f1; g1;}
|
||||
group { f2; g2; f3; }
|
||||
|
||||
# Data
|
||||
group { h1; i1; }
|
||||
group { h2; i2; h3; }
|
||||
}
|
||||
|
||||
When reading the data, instead of "i2c_master_read...", the command link is populated with :cpp:func:`i2c_master_read_byte` and / or :cpp:func:`i2c_master_read`. Also, the last read is configured for not providing an acknowledge by the master.
|
||||
|
||||
**Master Write or Read?**
|
||||
|
||||
After sending a slave's address, see step 3 on pictures above, the master either writes to or reads from the slave. The information what the master will actually do is hidden in the least significant bit of the slave's address.
|
||||
|
||||
Therefore the command link instructing the slave that the master will write the data contains the address like ``(ESP_SLAVE_ADDR << 1) | I2C_MASTER_WRITE`` and looks as follows::
|
||||
|
||||
i2c_master_write_byte(cmd, (ESP_SLAVE_ADDR << 1) | I2C_MASTER_WRITE, ACK_CHECK_EN)
|
||||
|
||||
By similar token the command link to read from the slave looks as follows::
|
||||
|
||||
i2c_master_write_byte(cmd, (ESP_SLAVE_ADDR << 1) | I2C_MASTER_READ, ACK_CHECK_EN)
|
||||
|
||||
|
||||
.. _i2c-api-slave-mode:
|
||||
|
||||
Slave Mode
|
||||
""""""""""
|
||||
|
||||
The API provides functions to read and write data by the slave - * :cpp:func:`i2c_slave_read_buffer` and :cpp:func:`i2c_slave_write_buffer`. An example of using these functions is provided in :example:`peripherals/i2c`.
|
||||
|
||||
|
||||
.. _i2c-api-interrupt-handling:
|
||||
|
||||
Interrupt Handling
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
To register an interrupt handler, call function :cpp:func:`i2c_isr_register`, to delete the handler call :cpp:func:`i2c_isr_free`. Description of interrupts triggered by I2C controller is provided in the `ESP32 Technical Reference Manual (PDF) <https://espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf>`_.
|
||||
|
||||
|
||||
.. _i2c-api-going-beyond-defaults:
|
||||
|
||||
Going Beyond Defaults
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
There are couple of I2C communication parameters setup during driver configuration (when calling :cpp:func:`i2c_param_config`, see :ref:`i2c-api-configure-driver`), to some default commonly used values. Some parameters are also already configured in registers of the I2C controller. These parameters can be changed to user defined values by calling dedicated functions:
|
||||
|
||||
* Period of SCL pulses being high and low - :cpp:func:`i2c_set_period`
|
||||
* SCL and SDA signal timing used during generation of start / stop signals - :cpp:func:`i2c_set_start_timing` / :cpp:func:`i2c_set_stop_timing`
|
||||
* Timing relationship between SCL and SDA signals when sampling by slave, as well as when transmitting by master - :cpp:func:`i2c_set_data_timing`
|
||||
* I2C timeout - :cpp:func:`i2c_set_timeout`
|
||||
|
||||
.. note::
|
||||
|
||||
The timing values are defined in APB clock cycles. The frequency of APB is specified in :cpp:type:`I2C_APB_CLK_FREQ`.
|
||||
|
||||
* What bit, LSB or MSB, is transmitted / received first - :cpp:func:`i2c_set_data_mode` selectable out of modes defined in :cpp:type:`i2c_trans_mode_t`
|
||||
|
||||
Each one of the above functions has a *_get_* counterpart to check the currently set value.
|
||||
|
||||
To see the default values of parameters setup during driver configuration, please refer to file :component_file:`driver/i2c.c` looking up defines with ``_DEFAULT`` suffix.
|
||||
|
||||
With function :cpp:func:`i2c_set_pin` it is also possible to select different SDA and SCL pins and alter configuration of pull ups, changing what has been already entered with :cpp:func:`i2c_param_config`.
|
||||
|
||||
.. note::
|
||||
|
||||
ESP32's internal pull ups are in the range of some tens of kOhm, and as such in most cases insufficient for use as I2C pull ups by themselves. We suggest to add external pull ups as well, with values as described in the I2C standard.
|
||||
|
||||
|
||||
.. _i2c-api-error-handling:
|
||||
|
||||
Error Handling
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
Most of driver's function return the ``ESP_OK`` on successful completion or a specific error code on a failure. It is a good practice to always check the returned values and implement the error handling. The driver is also printing out log messages, when e.g. checking the correctness of entered configuration, that contain explanation of errors. For details please refer to file :component_file:`driver/i2c.c` looking up defines with ``_ERR_STR`` suffix.
|
||||
|
||||
Use dedicated interrupts to capture communication failures. For instance there is ``I2C_TIME_OUT_INT`` interrupt triggered when I2C takes too long to receive data. See :ref:`i2c-api-interrupt-handling` for related information.
|
||||
|
||||
To reset internal hardware buffers in case of communication failure, you can use :cpp:func:`i2c_reset_tx_fifo` and :cpp:func:`i2c_reset_rx_fifo`.
|
||||
|
||||
|
||||
.. _i2c-api-delete-driver:
|
||||
|
||||
Delete Driver
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
If the I2C communication is established with :cpp:func:`i2c_driver_install` for some specific period of time and then not required, the driver may be removed to free allocated resources by calling :cpp:func:`i2c_driver_delete`.
|
||||
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
|
||||
I2C master and slave example: :example:`peripherals/i2c`.
|
||||
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/i2c.inc
|
||||
@@ -0,0 +1,98 @@
|
||||
I2S
|
||||
===
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
ESP32 contains two I2S peripherals. These peripherals can be configured to input and output sample data via the I2S driver.
|
||||
|
||||
The I2S peripheral supports DMA meaning it can stream sample data without requiring each sample to be read or written by the CPU.
|
||||
|
||||
I2S output can also be routed directly to the Digital/Analog Converter output channels (GPIO 25 & GPIO 26) to produce analog output directly, rather than via an external I2S codec.
|
||||
|
||||
.. note:: For high accuracy clock applications, APLL clock source can be used with `.use_apll = true` and ESP32 will automatically calculate APLL parameter.
|
||||
|
||||
.. note:: If `use_apll = true` and `fixed_mclk > 0`, then the Master clock output for I2S is fixed and equal to the fixed_mclk value. The audio clock rate (LRCK) is always the MCLK divisor and 0 < MCLK/LRCK/channels/bits_per_sample < 64
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
|
||||
A full I2S example is available in esp-idf: :example:`peripherals/i2s`.
|
||||
|
||||
Short example of I2S configuration:
|
||||
|
||||
.. highlight:: c
|
||||
|
||||
::
|
||||
|
||||
#include "driver/i2s.h"
|
||||
#include "freertos/queue.h"
|
||||
|
||||
static const int i2s_num = 0; // i2s port number
|
||||
|
||||
static const i2s_config_t i2s_config = {
|
||||
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
|
||||
.sample_rate = 44100,
|
||||
.bits_per_sample = 16,
|
||||
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
|
||||
.communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB,
|
||||
.intr_alloc_flags = 0, // default interrupt priority
|
||||
.dma_buf_count = 8,
|
||||
.dma_buf_len = 64,
|
||||
.use_apll = false
|
||||
};
|
||||
|
||||
static const i2s_pin_config_t pin_config = {
|
||||
.bck_io_num = 26,
|
||||
.ws_io_num = 25,
|
||||
.data_out_num = 22,
|
||||
.data_in_num = I2S_PIN_NO_CHANGE
|
||||
};
|
||||
|
||||
...
|
||||
|
||||
i2s_driver_install(i2s_num, &i2s_config, 0, NULL); //install and start i2s driver
|
||||
|
||||
i2s_set_pin(i2s_num, &pin_config);
|
||||
|
||||
i2s_set_sample_rates(i2s_num, 22050); //set sample rates
|
||||
|
||||
i2s_driver_uninstall(i2s_num); //stop & destroy i2s driver
|
||||
|
||||
Short example configuring I2S to use internal DAC for analog output::
|
||||
|
||||
#include "driver/i2s.h"
|
||||
#include "freertos/queue.h"
|
||||
|
||||
static const int i2s_num = 0; // i2s port number
|
||||
|
||||
static const i2s_config_t i2s_config = {
|
||||
.mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN,
|
||||
.sample_rate = 44100,
|
||||
.bits_per_sample = 16, /* the DAC module will only take the 8bits from MSB */
|
||||
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
|
||||
.communication_format = I2S_COMM_FORMAT_I2S_MSB,
|
||||
.intr_alloc_flags = 0, // default interrupt priority
|
||||
.dma_buf_count = 8,
|
||||
.dma_buf_len = 64,
|
||||
.use_apll = false
|
||||
};
|
||||
|
||||
...
|
||||
|
||||
i2s_driver_install(i2s_num, &i2s_config, 0, NULL); //install and start i2s driver
|
||||
|
||||
i2s_set_pin(i2s_num, NULL); //for internal DAC, this will enable both of the internal channels
|
||||
|
||||
//You can call i2s_set_dac_mode to set built-in DAC output mode.
|
||||
//i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN);
|
||||
|
||||
i2s_set_sample_rates(i2s_num, 22050); //set sample rates
|
||||
|
||||
i2s_driver_uninstall(i2s_num); //stop & destroy i2s driver
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/i2s.inc
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
Peripherals API
|
||||
***************
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
ADC <adc>
|
||||
DAC <dac>
|
||||
GPIO (including RTC low power I/O) <gpio>
|
||||
I2C <i2c>
|
||||
I2S <i2s>
|
||||
LED Control <ledc>
|
||||
MCPWM <mcpwm>
|
||||
Pulse Counter <pcnt>
|
||||
Remote Control <rmt>
|
||||
SD/MMC Card Host <../storage/sdmmc>
|
||||
Sigma-delta Modulation <sigmadelta>
|
||||
SPI Master <spi_master>
|
||||
SPI Slave <spi_slave>
|
||||
Timer <timer>
|
||||
Touch Sensor <touch_pad>
|
||||
UART <uart>
|
||||
|
||||
Example code for this API section is provided in :example:`peripherals` directory of ESP-IDF examples.
|
||||
@@ -0,0 +1,175 @@
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
The PWM controller also has the ability to 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:
|
||||
|
||||
1. :ref:`ledc-api-configure-timer` to determine PWM signal's frequency and the a number (resolution of duty range).
|
||||
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.
|
||||
|
||||
In an optional step it is also possible to set up an interrupt on the fade end.
|
||||
|
||||
.. figure:: ../../_static/ledc-api-settings.jpg
|
||||
:align: center
|
||||
:alt: Key Settings of LED PWM Controller's API
|
||||
:figclass: align-center
|
||||
|
||||
Key Settings of LED PWM Controller's API
|
||||
|
||||
|
||||
.. _ledc-api-configure-timer:
|
||||
|
||||
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:
|
||||
|
||||
* 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.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
.. _ledc-api-configure-channel:
|
||||
|
||||
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`.
|
||||
|
||||
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.
|
||||
|
||||
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`.
|
||||
|
||||
|
||||
.. _ledc-api-change-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`.
|
||||
|
||||
|
||||
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
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
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:
|
||||
|
||||
* :cpp:func:`ledc_set_fade_with_time`
|
||||
* :cpp:func:`ledc_set_fade_with_step`
|
||||
* :cpp:func:`ledc_set_fade`
|
||||
|
||||
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`.
|
||||
|
||||
|
||||
.. _ledc-api-change-pwm-frequency:
|
||||
|
||||
Change PWM Frequency
|
||||
""""""""""""""""""""
|
||||
|
||||
The LEDC API provides several means 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`.
|
||||
|
||||
|
||||
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:
|
||||
|
||||
* :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.
|
||||
|
||||
|
||||
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.
|
||||
|
||||
Registration of a handler to service this interrupt is done by calling :cpp:func:`ledc_isr_register`.
|
||||
|
||||
|
||||
.. _ledc-api-high_low_speed_mode:
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
.. _ledc-api-supported-range-frequency-duty-resolution:
|
||||
|
||||
Supported Range of Frequency and Duty Resolution
|
||||
------------------------------------------------
|
||||
|
||||
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% (13 ** 2 = 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 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:
|
||||
|
||||
.. highlight:: none
|
||||
|
||||
::
|
||||
|
||||
E (196) ledc: requested frequency and duty resolution can not 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%.
|
||||
|
||||
The LEDC API will also capture and report an attempt to configure frequency / duty resolution combination that is 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
|
||||
|
||||
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.
|
||||
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
|
||||
The LEDC change duty cycle and fading control example: :example:`peripherals/ledc`.
|
||||
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/ledc.inc
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
MCPWM
|
||||
=====
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
ESP32 has two MCPWM units which can be used to control different motors.
|
||||
|
||||
Block Diagram
|
||||
-------------
|
||||
|
||||
The block diagram of MCPWM unit is as shown.
|
||||
|
||||
::
|
||||
|
||||
__________________________________________________________________________
|
||||
| SYNCSIG FAULT SIG CAPTURE SIG |
|
||||
| 0 1 2 0 1 2 0 1 2 |
|
||||
|___________________________________________________________________ G |
|
||||
INTERRUPTS<-----+ | | | | | | | | | | P |
|
||||
| | | | | | | | | | | I |
|
||||
________|_|___|___|_____________|___|___|_________|___|___|_________ | O |
|
||||
| | | | | | | | | | | | |
|
||||
| | | | | | | | | | | | M |
|
||||
| | | | __v___v___v__ __v___v___v__ | | A |
|
||||
| | | | | | | | | | T |
|
||||
| | | | | FAULT | | CAPTURE | | | R |
|
||||
| | | | | HANDLER | | | | | I |
|
||||
| | | | | | |___________| | | X |
|
||||
| | | | |___________| | | |
|
||||
| | | | | | |
|
||||
| ____v___v___v____ ____________________ | | |
|
||||
| | +---------+ | | +------------+ |--------->|PWM0A|
|
||||
| | | Timer 0 | | | | Operator 0 | | | | |
|
||||
| | +---------+ | | +------------+ |--------->|PWM0B|
|
||||
| | | | | | | |
|
||||
| | +---------+ | | +------------+ |--------->|PWM1A|
|
||||
| | | Timer 1 | |------------------->| | Operator 1 | | | | |
|
||||
| | +---------+ | | +------------+ |--------->|PWM1B|
|
||||
| | | | | | | |
|
||||
| | +---------+ | | +------------+ |--------->|PWM2A|
|
||||
| | | Timer 2 | | | | Operator 2 | | | | |
|
||||
| | +---------+ | | +------------+ |--------->|PWM2B|
|
||||
| |_______________| |__________________| | |_____|
|
||||
| |
|
||||
| MCPWM-UNIT 0/1 |
|
||||
|___________________________________________________________________|
|
||||
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
|
||||
Examples of using MCPWM for motor control: :example:`peripherals/mcpwm`.
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/mcpwm.inc
|
||||
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
Pulse Counter
|
||||
=============
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
The PCNT (Pulse Counter) module is designed to count the number of rising and/or falling edges of an input signal. Each pulse counter unit has a 16-bit signed counter register and two channels that can be configured to either increment or decrement the counter. Each channel has a signal input that accepts signal edges to be detected, as well as a control input that can be used to enable or disable the signal input. The inputs have optional filters that can be used to discard unwanted glitches in the signal.
|
||||
|
||||
|
||||
Functionality Overview
|
||||
----------------------
|
||||
|
||||
Description of functionality of this API has been broken down into four sections:
|
||||
|
||||
* :ref:`pcnt-api-configuration` - describes counter's configuration parameters and how to setup the counter.
|
||||
* :ref:`pcnt-api-operating-the-counter` - provides information on control functions to pause, measure and clear the counter.
|
||||
* :ref:`pcnt-api-filtering-pulses` - describes options to filtering pulses and the counter control signals.
|
||||
* :ref:`pcnt-api-using-interrupts` - presents how to trigger interrupts on specific states of the counter.
|
||||
|
||||
|
||||
.. _pcnt-api-configuration:
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
The PCNT module has eight independent counting "units" numbered from 0 to 7. In the API they are referred to using :cpp:type:`pcnt_unit_t`. Each unit has two independent channels numbered as 0 and 1 and specified with :cpp:type:`pcnt_channel_t`.
|
||||
|
||||
The configuration is provided separately per unit's channel using :cpp:type:`pcnt_config_t` and covers:
|
||||
|
||||
* The unit and the channel number this configuration refers to.
|
||||
* GPIO numbers of the pulse input and the pulse gate input.
|
||||
* Two pairs of parameters: :cpp:type:`pcnt_ctrl_mode_t` and :cpp:type:`pcnt_count_mode_t` to define how the counter reacts depending on the the status of control signal and how counting is done positive / negative edge of the pulses.
|
||||
* Two limit values (minimum / maximum) that are used to establish watchpoints and trigger interrupts when the pulse count is meeting particular limit.
|
||||
|
||||
Setting up of particular channel is then done by calling a function :cpp:func:`pcnt_unit_config` with above :cpp:type:`pcnt_config_t` as the input parameter.
|
||||
|
||||
To disable the pulse or the control input pin in configuration, provide :cpp:type:`PCNT_PIN_NOT_USED` instead of the GPIO number.
|
||||
|
||||
|
||||
.. _pcnt-api-operating-the-counter:
|
||||
|
||||
Operating the Counter
|
||||
---------------------
|
||||
|
||||
After doing setup with :cpp:func:`pcnt_unit_config`, the counter immediately starts to operate. The accumulated pulse count can be checked by calling :cpp:func:`pcnt_get_counter_value`.
|
||||
|
||||
There are couple of functions that allow to control the counter's operation: :cpp:func:`pcnt_counter_pause`, :cpp:func:`pcnt_counter_resume` and :cpp:func:`pcnt_counter_clear`
|
||||
|
||||
It is also possible to dynamically change the previously set up counter modes with :cpp:func:`pcnt_unit_config` by calling :cpp:func:`pcnt_set_mode`.
|
||||
|
||||
If desired, the pulse input pin and the control input pin may be changed "on the fly" using :cpp:func:`pcnt_set_pin`. To disable particular input provide as a function parameter :cpp:type:`PCNT_PIN_NOT_USED` instead of the GPIO number.
|
||||
|
||||
.. note::
|
||||
|
||||
For the counter not to miss any pulses, the pulse duration should be longer than one APB_CLK cycle (12.5 ns). The pulses are sampled on the edges of the APB_CLK clock and may be missed, if fall between the edges. This applies to counter operation with or without a :ref:`filer <pcnt-api-filtering-pulses>`.
|
||||
|
||||
|
||||
.. _pcnt-api-filtering-pulses:
|
||||
|
||||
Filtering Pulses
|
||||
----------------
|
||||
|
||||
The PCNT unit features filters on each of the pulse and control inputs, adding the option to ignore short glitches in the signals.
|
||||
|
||||
The length of ignored pulses is provided in APB_CLK clock cycles by calling :cpp:func:`pcnt_set_filter_value`. The current filter setting may be checked with :cpp:func:`pcnt_get_filter_value`. The APB_CLK clock is running at 80 MHz.
|
||||
|
||||
The filter is put into operation / suspended by calling :cpp:func:`pcnt_filter_enable` / :cpp:func:`pcnt_filter_disable`.
|
||||
|
||||
|
||||
.. _pcnt-api-using-interrupts:
|
||||
|
||||
Using Interrupts
|
||||
----------------
|
||||
|
||||
There are five counter state watch events, defined in :cpp:type:`pcnt_evt_type_t`, that are able to trigger an interrupt. The event happens on the pulse counter reaching specific values:
|
||||
|
||||
* Minimum or maximum count values: :cpp:member:`counter_l_lim` or :cpp:member:`counter_h_lim` provided in :cpp:type:`pcnt_config_t` as discussed in :ref:`pcnt-api-configuration`
|
||||
* Threshold 0 or Threshold 1 values set using function :cpp:func:`pcnt_set_event_value`.
|
||||
* Pulse count = 0
|
||||
|
||||
To register, enable or disable an interrupt to service the above events, call :cpp:func:`pcnt_isr_register`, :cpp:func:`pcnt_intr_enable`. and :cpp:func:`pcnt_intr_disable`. To enable or disable events on reaching threshold values, you will also need to call functions :cpp:func:`pcnt_event_enable` and :cpp:func:`pcnt_event_disable`.
|
||||
|
||||
In order to check what are the threshold values currently set, use function :cpp:func:`pcnt_get_event_value`.
|
||||
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
|
||||
Pulse counter with control signal and event interrupt example: :example:`peripherals/pcnt`.
|
||||
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/pcnt.inc
|
||||
|
||||
@@ -0,0 +1,267 @@
|
||||
RMT
|
||||
===
|
||||
|
||||
The RMT (Remote Control) module driver can be used to send and receive infrared remote control signals. Due to flexibility of RMT module, the driver can also be used to generate or receive many other types of signals.
|
||||
|
||||
The signal, which consists of a series of pulses, is generated by RMT's transmitter based on a list of values. The values define the pulse duration and a binary level, see below. The transmitter can also provide a carrier and modulate it with provided pulses.
|
||||
|
||||
.. blockdiag::
|
||||
:scale: 100
|
||||
:caption: RMT Transmitter Overview
|
||||
:align: center
|
||||
|
||||
blockdiag rmt_tx {
|
||||
|
||||
node_width = 80;
|
||||
node_height = 60;
|
||||
default_group_color = lightgrey;
|
||||
|
||||
a -> b -> c -> d;
|
||||
e -> f -> g -- h;
|
||||
d -> o [label=GPIO];
|
||||
h -> d [folded];
|
||||
|
||||
a [style=none, width=100, label="{11,high,7,low},\n{5,high,5,low},\n..."]
|
||||
b [label="Waveform\nGenerator"]
|
||||
c [style=none, label="", background="_static/rmt-waveform.png"]
|
||||
d [shape=beginpoint, label="mod"]
|
||||
e [style=none, width=60, height=40, label="Carrier\nenable"]
|
||||
f [label="Carrier\nGenerator"]
|
||||
g [style=none, label="", background="_static/rmt-carrier.png"]
|
||||
h [shape=none]
|
||||
o [style=none, label="", background="_static/rmt-waveform-modulated.png"]
|
||||
|
||||
group {
|
||||
label = Input
|
||||
a,e;
|
||||
}
|
||||
group {
|
||||
label = "RMT Transmitter"
|
||||
b,f,c,g,d,h;
|
||||
}
|
||||
group {
|
||||
label = Output
|
||||
o;
|
||||
}
|
||||
}
|
||||
|
||||
The reverse operation is performed by the receiver, where a series of pulses is decoded into a list of values containing the pulse duration and binary level. A filter may be applied to remove high frequency noise from the input signal.
|
||||
|
||||
.. blockdiag::
|
||||
:scale: 90
|
||||
:caption: RMT Receiver Overview
|
||||
:align: center
|
||||
|
||||
blockdiag rmt_rx {
|
||||
|
||||
node_width = 80;
|
||||
node_height = 60;
|
||||
default_group_color = lightgrey;
|
||||
|
||||
a -> b [label=GPIO];
|
||||
b -> c -> d;
|
||||
e -- f;
|
||||
f -> b [folded];
|
||||
|
||||
a [style=none, label="", background="_static/rmt-waveform.png"]
|
||||
b [label=Filter]
|
||||
c [label="Edge\nDetect"]
|
||||
d [style=none, width=100, label="{11,high,7,low},\n{5,high,5,low},\n..."]
|
||||
e [style=none, width=60, height=40, label="Filter\nenable"]
|
||||
f [shape=none, label=""]
|
||||
|
||||
group {
|
||||
label = Input
|
||||
a,e;
|
||||
}
|
||||
group {
|
||||
label = "RMT Receiver"
|
||||
b,c;
|
||||
}
|
||||
group {
|
||||
label = Output
|
||||
d;
|
||||
}
|
||||
}
|
||||
|
||||
There couple of typical steps to setup and operate the RMT and they are discussed in the following sections:
|
||||
|
||||
1. `Configure Driver`_
|
||||
2. `Transmit Data`_ or `Receive Data`_
|
||||
3. `Change Operation Parameters`_
|
||||
4. `Use Interrupts`_
|
||||
|
||||
The RMT has eight channels numbered from zero to seven. Each channel is able to independently transmit or receive data. They are referred to using indexes defined in structure :cpp:type:`rmt_channel_t`.
|
||||
|
||||
|
||||
Configure Driver
|
||||
----------------
|
||||
|
||||
There are several parameters that define how particular channel operates. Most of these parameters are configured by setting specific members of :cpp:type:`rmt_config_t` structure. Some of the parameters are common to both transmit or receive mode, and some are mode specific. They are all discussed below.
|
||||
|
||||
|
||||
Common Parameters
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
* The **channel** to be configured, select one from the :cpp:type:`rmt_channel_t` enumerator.
|
||||
* The RMT **operation mode** - whether this channel is used to transmit or receive data, selected by setting a **rmt_mode** members to one of the values from :cpp:type:`rmt_mode_t`.
|
||||
* What is the **pin number** to transmit or receive RMT signals, selected by setting **gpio_num**.
|
||||
* How many **memory blocks** will be used by the channel, set with **mem_block_num**.
|
||||
* A **clock divider**, that will determine the range of pulse length generated by the RMT transmitter or discriminated by the receiver. Selected by setting **clk_div** to a value within [1 .. 255] range. The RMT source clock is typically APB CLK, 80Mhz by default.
|
||||
|
||||
.. note::
|
||||
|
||||
The period of a square wave after the clock divider is called a 'tick'. The length of the pulses generated by the RMT transmitter or discriminated by the receiver is configured in number of 'ticks'.
|
||||
|
||||
There are also couple of specific parameters that should be set up depending if selected channel is configured in `Transmit Mode`_ or `Receive Mode`_:
|
||||
|
||||
|
||||
Transmit Mode
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
When configuring channel in transmit mode, set **tx_config** and the following members of :cpp:type:`rmt_tx_config_t`:
|
||||
|
||||
* Transmit the currently configured data items in a loop - **loop_en**
|
||||
* Enable the RMT carrier signal - **carrier_en**
|
||||
* Frequency of the carrier in Hz - **carrier_freq_hz**
|
||||
* Duty cycle of the carrier signal in percent (%) - **carrier_duty_percent**
|
||||
* Level of the RMT output, when the carrier is applied - **carrier_level**
|
||||
* Enable the RMT output if idle - **idle_output_en**
|
||||
* Set the signal level on the RMT output if idle - **idle_level**
|
||||
|
||||
|
||||
Receive Mode
|
||||
^^^^^^^^^^^^
|
||||
|
||||
In receive mode, set **rx_config** and the following members of :cpp:type:`rmt_rx_config_t`:
|
||||
|
||||
* Enable a filter on the input of the RMT receiver - **filter_en**
|
||||
* A threshold of the filter, set in the number of ticks - **filter_ticks_thresh**. Pulses shorter than this setting will be filtered out. Note, that the range of entered tick values is [0..255].
|
||||
* A pulse length threshold that will turn the RMT receiver idle, set in number of ticks - **idle_threshold**. The receiver will ignore pulses longer than this setting.
|
||||
|
||||
|
||||
Finalize Configuration
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Once the :cpp:type:`rmt_config_t` structure is populated with parameters, it should be then invoked with :cpp:func:`rmt_config` to make the configuration effective.
|
||||
|
||||
The last configuration step is installation of the driver in memory by calling :cpp:func:`rmt_driver_install`. If :cpp:type:`rx_buf_size` parameter of this function is > 0, then a ring buffer for incoming data will be allocated. A default ISR handler will be installed, see a note in `Use Interrupts`_.
|
||||
|
||||
Now, depending on how the channel is configured, we are ready to either `Transmit Data`_ or `Receive Data`_. This is described in next two sections.
|
||||
|
||||
|
||||
Transmit Data
|
||||
-------------
|
||||
|
||||
Before being able to transmit some RMT pulses, we need to define the pulse pattern. The minimum pattern recognized by the RMT controller, later called an 'item', is provided in a structure :cpp:type:`rmt_item32_t`, see :component_file:`soc/esp32/include/soc/rmt_struct.h`. Each item consists of two pairs of two values. The first value in a pair describes the signal duration in ticks and is 15 bits long, the second provides the signal level (high or low) and is contained in a single bit. A block of couple of items and the structure of an item is presented below.
|
||||
|
||||
.. packetdiag::
|
||||
:caption: Structure of RMT items (L - signal level)
|
||||
:align: center
|
||||
|
||||
packetdiag rmt_items {
|
||||
colwidth = 32
|
||||
node_width = 10
|
||||
node_height = 24
|
||||
default_fontsize = 12
|
||||
|
||||
0-14: Period (15)
|
||||
15: L
|
||||
16-30: Period (15)
|
||||
31: L
|
||||
32-95: ... [colheight=2]
|
||||
96-110: Period (15)
|
||||
111: L
|
||||
112-126: Period (15)
|
||||
127: L
|
||||
}
|
||||
|
||||
For a simple example how to define a block of items see :example:`peripherals/rmt_tx`.
|
||||
|
||||
The items are provided to the RMT controller by calling function :cpp:func:`rmt_write_items`. This function also automatically triggers start of transmission. It may be called to wait for transmission completion or exit just after transmission start. In such case you can wait for the transmission end by calling :cpp:func:`rmt_wait_tx_done`. This function does not limit the number of data items to transmit. It is using an interrupt to successively copy the new data chunks to RMT's internal memory as previously provided data are sent out.
|
||||
|
||||
Another way to provide data for transmission is by calling :cpp:func:`rmt_fill_tx_items`. In this case transmission is not started automatically. To control the transmission process use :cpp:func:`rmt_tx_start` and :cpp:func:`rmt_tx_stop`. The number of items to sent is restricted by the size of memory blocks allocated in the RMT controller's internal memory, see :cpp:func:`rmt_set_mem_block_num`.
|
||||
|
||||
|
||||
Receive Data
|
||||
------------
|
||||
|
||||
Before starting the receiver we need some storage for incoming items. The RMT controller has 512 x 32-bits of internal RAM shared between all eight channels. In typical scenarios it is not enough as an ultimate storage for all incoming (and outgoing) items. Therefore this API supports retrieval of incoming items on the fly to save them in a ring buffer of a size defined by the user. The size is provided when calling :cpp:func:`rmt_driver_install` discussed above. To get a handle to this buffer call :cpp:func:`rmt_get_ringbuf_handle`.
|
||||
|
||||
With the above steps complete we can start the receiver by calling :cpp:func:`rmt_rx_start` and then move to checking what's inside the buffer. To do so, you can use common FreeRTOS functions that interact with the ring buffer. Please see an example how to do it in :example:`peripherals/rmt_nec_tx_rx`.
|
||||
|
||||
To stop the receiver, call :cpp:func:`rmt_rx_stop`.
|
||||
|
||||
|
||||
Change Operation Parameters
|
||||
---------------------------
|
||||
|
||||
Previously described function :cpp:func:`rmt_config` provides a convenient way to set several configuration parameters in one shot. This is usually done on application start. Then, when the application is running, the API provides an alternate way to update individual parameters by calling dedicated functions. Each function refers to the specific RMT channel provided as the first input parameter. Most of the functions have `_get_` counterpart to read back the currently configured value.
|
||||
|
||||
|
||||
Parameters Common to Transmit and Receive Mode
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
* Selection of a GPIO pin number on the input or output of the RMT - :cpp:func:`rmt_set_pin`
|
||||
* Number of memory blocks allocated for the incoming or outgoing data - :cpp:func:`rmt_set_mem_pd`
|
||||
* Setting of the clock divider - :cpp:func:`rmt_set_clk_div`
|
||||
* Selection of the clock source, note that currently one clock source is supported, the APB clock which is 80Mhz - :cpp:func:`rmt_set_source_clk`
|
||||
|
||||
|
||||
Transmit Mode Parameters
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
* Enable or disable the loop back mode for the transmitter - :cpp:func:`rmt_set_tx_loop_mode`
|
||||
* Binary level on the output to apply the carrier - :cpp:func:`rmt_set_tx_carrier`, selected from :cpp:type:`rmt_carrier_level_t`
|
||||
* Determines the binary level on the output when transmitter is idle - :cpp:func:`rmt_set_idle_level()`, selected from :cpp:type:`rmt_idle_level_t`
|
||||
|
||||
|
||||
Receive Mode Parameters
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
* The filter setting - :cpp:func:`rmt_set_rx_filter`
|
||||
* The receiver threshold setting - :cpp:func:`rmt_set_rx_idle_thresh`
|
||||
* Whether the transmitter or receiver is entitled to access RMT's memory - :cpp:func:`rmt_set_memory_owner`, selection is from :cpp:type:`rmt_mem_owner_t`.
|
||||
|
||||
|
||||
Use Interrupts
|
||||
--------------
|
||||
|
||||
Registering of an interrupt handler for the RMT controller is done be calling :cpp:func:`rmt_isr_register`.
|
||||
|
||||
.. note::
|
||||
|
||||
When calling :cpp:func:`rmt_driver_install` to use the system RMT driver, a default ISR is being installed. In such a case you cannot register a generic ISR handler with :cpp:func:`rmt_isr_register`.
|
||||
|
||||
The RMT controller triggers interrupts on four specific events describes below. To enable interrupts on these events, the following functions are provided:
|
||||
|
||||
* The RMT receiver has finished receiving a signal - :cpp:func:`rmt_set_rx_intr_en`
|
||||
* The RMT transmitter has finished transmitting the signal - :cpp:func:`rmt_set_tx_intr_en`
|
||||
* The number of events the transmitter has sent matches a threshold value :cpp:func:`rmt_set_tx_thr_intr_en`
|
||||
* Ownership to the RMT memory block has been violated - :cpp:func:`rmt_set_err_intr_en`
|
||||
|
||||
Setting or clearing an interrupt enable mask for specific channels and events may be also done by calling :cpp:func:`rmt_set_intr_enable_mask` or :cpp:func:`rmt_clr_intr_enable_mask`.
|
||||
|
||||
When servicing an interrupt within an ISR, the interrupt need to explicitly cleared. To do so, set specific bits described as ``RMT.int_clr.val.chN_event_name`` and defined as a ``volatile struct`` in :component_file:`soc/esp32/include/soc/rmt_struct.h`, where N is the RMT channel number [0, 7] and the ``event_name`` is one of four events described above.
|
||||
|
||||
If you do not need an ISR anymore, you can deregister it by calling a function :cpp:func:`rmt_isr_deregister`.
|
||||
|
||||
|
||||
Uninstall Driver
|
||||
----------------
|
||||
|
||||
If the RMT driver has been installed with :cpp:func:`rmt_driver_install` for some specific period of time and then not required, the driver may be removed to free allocated resources by calling :cpp:func:`rmt_driver_uninstall`.
|
||||
|
||||
|
||||
Application Examples
|
||||
--------------------
|
||||
|
||||
* A simple RMT TX example: :example:`peripherals/rmt_tx`.
|
||||
* NEC remote control TX and RX example: :example:`peripherals/rmt_nec_tx_rx`.
|
||||
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/rmt.inc
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
Sigma-delta Modulation
|
||||
======================
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
ESP32 has a second-order sigma-delta modulation module. This driver configures the channels of the sigma-delta module.
|
||||
|
||||
Functionality Overview
|
||||
----------------------
|
||||
|
||||
There are eight independent sigma-delta modulation channels identified with :cpp:type:`sigmadelta_channel_t`. Each channel is capable to output the binary, hardware generated signal with the sigma-delta modulation.
|
||||
|
||||
Selected channel should be set up by providing configuration parameters in :cpp:type:`sigmadelta_config_t` and then applying this configuration with :cpp:func:`sigmadelta_config`.
|
||||
|
||||
Another option is to call individual functions, that will configure all required parameters one by one:
|
||||
|
||||
* **Prescaler** of the sigma-delta generator - :cpp:func:`sigmadelta_set_prescale`
|
||||
* **Duty** of the output signal - :cpp:func:`sigmadelta_set_duty`
|
||||
* **GPIO pin** to output modulated signal - :cpp:func:`sigmadelta_set_pin`
|
||||
|
||||
The range of the 'duty' input parameter of :cpp:func:`sigmadelta_set_duty` is from -128 to 127 (eight bit signed integer). If zero value is set, then the output signal's duty will be about 50%, see description of :cpp:func:`sigmadelta_set_duty`.
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
|
||||
Sigma-delta Modulation example: :example:`peripherals/sigmadelta`.
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/sigmadelta.inc
|
||||
@@ -0,0 +1,159 @@
|
||||
SPI Master driver
|
||||
=================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
The ESP32 has four SPI peripheral devices, called SPI0, SPI1, HSPI and VSPI. SPI0 is entirely dedicated to
|
||||
the flash cache the ESP32 uses to map the SPI flash device it is connected to into memory. SPI1 is
|
||||
connected to the same hardware lines as SPI0 and is used to write to the flash chip. HSPI and VSPI
|
||||
are free to use. SPI1, HSPI and VSPI all have three chip select lines, allowing them to drive up to
|
||||
three SPI devices each as a master.
|
||||
|
||||
The spi_master driver
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The spi_master driver allows easy communicating with SPI slave devices, even in a multithreaded environment.
|
||||
It fully transparently handles DMA transfers to read and write data and automatically takes care of
|
||||
multiplexing between different SPI slaves on the same master
|
||||
|
||||
Terminology
|
||||
^^^^^^^^^^^
|
||||
|
||||
The spi_master driver uses the following terms:
|
||||
|
||||
* Host: The SPI peripheral inside the ESP32 initiating the SPI transmissions. One of SPI, HSPI or VSPI. (For
|
||||
now, only HSPI or VSPI are actually supported in the driver; it will support all 3 peripherals
|
||||
somewhere in the future.)
|
||||
* Bus: The SPI bus, common to all SPI devices connected to one host. In general the bus consists of the
|
||||
miso, mosi, sclk and optionally quadwp and quadhd signals. The SPI slaves are connected to these
|
||||
signals in parallel.
|
||||
|
||||
- miso - Also known as q, this is the input of the serial stream into the ESP32
|
||||
|
||||
- mosi - Also known as d, this is the output of the serial stream from the ESP32
|
||||
|
||||
- sclk - Clock signal. Each data bit is clocked out or in on the positive or negative edge of this signal
|
||||
|
||||
- quadwp - Write Protect signal. Only used for 4-bit (qio/qout) transactions.
|
||||
|
||||
- quadhd - Hold signal. Only used for 4-bit (qio/qout) transactions.
|
||||
|
||||
* Device: A SPI slave. Each SPI slave has its own chip select (CS) line, which is made active when
|
||||
a transmission to/from the SPI slave occurs.
|
||||
* Transaction: One instance of CS going active, data transfer from and/or to a device happening, and
|
||||
CS going inactive again. Transactions are atomic, as in they will never be interrupted by another
|
||||
transaction.
|
||||
|
||||
|
||||
SPI transactions
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
A transaction on the SPI bus consists of five phases, any of which may be skipped:
|
||||
|
||||
* The command phase. In this phase, a command (0-16 bit) is clocked out.
|
||||
* The address phase. In this phase, an address (0-64 bit) is clocked out.
|
||||
* The write phase. The master sends data to the slave.
|
||||
* The dummy phase. The phase is configurable, used to meet the timing requirements.
|
||||
* The read phase. The slave sends data to the master.
|
||||
|
||||
In full duplex, the read and write phases are combined, causing the SPI host to read and
|
||||
write data simultaneously. The total transaction length is decided by
|
||||
``command_bits + address_bits + trans_conf.length``, while the ``trans_conf.rx_length``
|
||||
only determins length of data received into the buffer.
|
||||
|
||||
In half duplex, the length of write phase and read phase are decided by ``trans_conf.length`` and
|
||||
``trans_conf.rx_length`` respectively. ** Note that a half duplex transaction with both a read and
|
||||
write phase is not supported when using DMA. ** If such transaction is needed, you have to use one
|
||||
of the alternative solutions:
|
||||
|
||||
1. use full-duplex mode instead.
|
||||
2. disable the DMA by set the last parameter to 0 in bus initialization function just as belows:
|
||||
``ret=spi_bus_initialize(VSPI_HOST, &buscfg, 0);``
|
||||
|
||||
this may prohibit you from transmitting and receiving data longer than 32 bytes.
|
||||
3. try to use command and address field to replace the write phase.
|
||||
|
||||
The command and address phase are optional in that not every SPI device will need to be sent a command
|
||||
and/or address. This is reflected in the device configuration: when the ``command_bits`` or ``address_bits``
|
||||
fields are set to zero, no command or address phase is done.
|
||||
|
||||
Something similar is true for the read and write phase: not every transaction needs both data to be written
|
||||
as well as data to be read. When ``rx_buffer`` is NULL (and SPI_USE_RXDATA) is not set) the read phase
|
||||
is skipped. When ``tx_buffer`` is NULL (and SPI_USE_TXDATA) is not set) the write phase is skipped.
|
||||
|
||||
Using the spi_master driver
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- Initialize a SPI bus by calling ``spi_bus_initialize``. Make sure to set the correct IO pins in
|
||||
the ``bus_config`` struct. Take care to set signals that are not needed to -1.
|
||||
|
||||
- Tell the driver about a SPI slave device connected to the bus by calling spi_bus_add_device.
|
||||
Make sure to configure any timing requirements the device has in the ``dev_config`` structure.
|
||||
You should now have a handle for the device, to be used when sending it a transaction.
|
||||
|
||||
- To interact with the device, fill one or more spi_transaction_t structure with any transaction
|
||||
parameters you need. Either queue all transactions by calling ``spi_device_queue_trans``, later
|
||||
quering the result using ``spi_device_get_trans_result``, or handle all requests synchroneously
|
||||
by feeding them into ``spi_device_transmit``.
|
||||
|
||||
- Optional: to unload the driver for a device, call ``spi_bus_remove_device`` with the device
|
||||
handle as an argument
|
||||
|
||||
- Optional: to remove the driver for a bus, make sure no more drivers are attached and call
|
||||
``spi_bus_free``.
|
||||
|
||||
Command and address phases
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
During the command and address phases, ``cmd`` and ``addr`` field in the
|
||||
``spi_transaction_t`` struct are sent to the bus, while nothing is read at the
|
||||
same time. The default length of command and address phase are set in the
|
||||
``spi_device_interface_config_t`` and by ``spi_bus_add_device``. When the the
|
||||
flag ``SPI_TRANS_VARIABLE_CMD`` and ``SPI_TRANS_VARIABLE_ADDR`` are not set in
|
||||
the ``spi_transaction_t``,the driver automatically set the length of these
|
||||
phases to the default value as set when the device is initialized respectively.
|
||||
|
||||
If the length of command and address phases needs to be variable, declare a
|
||||
``spi_transaction_ext_t`` descriptor, set the flag ``SPI_TRANS_VARIABLE_CMD``
|
||||
or/and ``SPI_TRANS_VARIABLE_ADDR`` in the ``flags`` of ``base`` member and
|
||||
configure the rest part of ``base`` as usual. Then the length of each phases
|
||||
will be ``command_bits`` and ``address_bits`` set in the ``spi_transaction_ext_t``.
|
||||
|
||||
Write and read phases
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Normally, data to be transferred to or from a device will be read from or written to a chunk of memory
|
||||
indicated by the ``rx_buffer`` and ``tx_buffer`` members of the transaction structure.
|
||||
When DMA is enabled for transfers, these buffers are highly recommended to meet the requirements as belows:
|
||||
|
||||
1. allocated in DMA-capable memory using ``pvPortMallocCaps(size, MALLOC_CAP_DMA)``;
|
||||
2. 32-bit aligned (start from the boundary and have length of multiples of 4 bytes).
|
||||
|
||||
If these requirements are not satisfied, efficiency of the transaction will suffer due to the allocation and
|
||||
memcpy of temporary buffers.
|
||||
|
||||
Sometimes, the amount of data is very small making it less than optimal allocating a separate buffer
|
||||
for it. If the data to be transferred is 32 bits or less, it can be stored in the transaction struct
|
||||
itself. For transmitted data, use the ``tx_data`` member for this and set the ``SPI_USE_TXDATA`` flag
|
||||
on the transmission. For received data, use ``rx_data`` and set ``SPI_USE_RXDATA``. In both cases, do
|
||||
not touch the ``tx_buffer`` or ``rx_buffer`` members, because they use the same memory locations
|
||||
as ``tx_data`` and ``rx_data``.
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
|
||||
Display graphics on the 320x240 LCD of WROVER-Kits: :example:`peripherals/spi_master`.
|
||||
|
||||
|
||||
API Reference - SPI Common
|
||||
--------------------------
|
||||
|
||||
.. include:: /_build/inc/spi_common.inc
|
||||
|
||||
|
||||
API Reference - SPI Master
|
||||
--------------------------
|
||||
|
||||
.. include:: /_build/inc/spi_master.inc
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
SPI Slave driver
|
||||
=================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
The ESP32 has four SPI peripheral devices, called SPI0, SPI1, HSPI and VSPI. SPI0 is entirely dedicated to
|
||||
the flash cache the ESP32 uses to map the SPI flash device it is connected to into memory. SPI1 is
|
||||
connected to the same hardware lines as SPI0 and is used to write to the flash chip. HSPI and VSPI
|
||||
are free to use, and with the spi_slave driver, these can be used as a SPI slave, driven from a
|
||||
connected SPI master.
|
||||
|
||||
The spi_slave driver
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The spi_slave driver allows using the HSPI and/or VSPI peripheral as a full-duplex SPI slave. It can make
|
||||
use of DMA to send/receive transactions of arbitrary length.
|
||||
|
||||
Terminology
|
||||
^^^^^^^^^^^
|
||||
|
||||
The spi_slave driver uses the following terms:
|
||||
|
||||
* Host: The SPI peripheral inside the ESP32 initiating the SPI transmissions. One of HSPI or VSPI.
|
||||
* Bus: The SPI bus, common to all SPI devices connected to a master. In general the bus consists of the
|
||||
miso, mosi, sclk and optionally quadwp and quadhd signals. The SPI slaves are connected to these
|
||||
signals in parallel. Each SPI slave is also connected to one CS signal.
|
||||
|
||||
- miso - Also known as q, this is the output of the serial stream from the ESP32 to the SPI master
|
||||
|
||||
- mosi - Also known as d, this is the output of the serial stream from the SPI master to the ESP32
|
||||
|
||||
- sclk - Clock signal. Each data bit is clocked out or in on the positive or negative edge of this signal
|
||||
|
||||
- cs - Chip Select. An active Chip Select delineates a single transaction to/from a slave.
|
||||
|
||||
* Transaction: One instance of CS going active, data transfer from and to a master happening, and
|
||||
CS going inactive again. Transactions are atomic, as in they will never be interrupted by another
|
||||
transaction.
|
||||
|
||||
|
||||
SPI transactions
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
A full-duplex SPI transaction starts with the master pulling CS low. After this happens, the master
|
||||
starts sending out clock pulses on the CLK line: every clock pulse causes a data bit to be shifted from
|
||||
the master to the slave on the MOSI line and vice versa on the MISO line. At the end of the transaction,
|
||||
the master makes CS high again.
|
||||
|
||||
Using the spi_slave driver
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- Initialize a SPI peripheral as a slave by calling ``spi_slave_initialize``. Make sure to set the
|
||||
correct IO pins in the ``bus_config`` struct. Take care to set signals that are not needed to -1.
|
||||
A DMA channel (either 1 or 2) must be given if transactions will be larger than 32 bytes, if not
|
||||
the dma_chan parameter may be 0.
|
||||
|
||||
- To set up a transaction, fill one or more spi_transaction_t structure with any transaction
|
||||
parameters you need. Either queue all transactions by calling ``spi_slave_queue_trans``, later
|
||||
quering the result using ``spi_slave_get_trans_result``, or handle all requests synchroneously
|
||||
by feeding them into ``spi_slave_transmit``. The latter two functions will block until the
|
||||
master has initiated and finished a transaction, causing the queued data to be sent and received.
|
||||
|
||||
- Optional: to unload the SPI slave driver, call ``spi_slave_free``.
|
||||
|
||||
|
||||
Transaction data and master/slave length mismatches
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Normally, data to be transferred to or from a device will be read from or written to a chunk of memory
|
||||
indicated by the ``rx_buffer`` and ``tx_buffer`` members of the transaction structure. The SPI driver
|
||||
may decide to use DMA for transfers, so these buffers should be allocated in DMA-capable memory using
|
||||
``pvPortMallocCaps(size, MALLOC_CAP_DMA)``.
|
||||
|
||||
The amount of data written to the buffers is limited by the ``length`` member of the transaction structure:
|
||||
the driver will never read/write more data than indicated there. The ``length`` cannot define the actual
|
||||
length of the SPI transaction; this is determined by the master as it drives the clock and CS lines. The actual length
|
||||
transferred can be read from the ``trans_len`` member of the ``spi_slave_transaction_t`` structure after transaction.
|
||||
In case the length of the transmission is larger than the buffer length, only the start of the transmission
|
||||
will be sent and received, and the ``trans_len`` is set to ``length`` instead of the actual length. It's recommended to
|
||||
set ``length`` longer than the maximum length expected if the ``trans_len`` is required. In case the transmission
|
||||
length is shorter than the buffer length, only data up to the length of the buffer will be exchanged.
|
||||
|
||||
Warning: Due to a design peculiarity in the ESP32, if the amount of bytes sent by the master or the length
|
||||
of the transmission queues in the slave driver, in bytes, is not both larger than eight and dividable by
|
||||
four, the SPI hardware can fail to write the last one to seven bytes to the receive buffer.
|
||||
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
|
||||
Slave/master communication: :example:`peripherals/spi_slave`.
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/spi_slave.inc
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
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.
|
||||
|
||||
|
||||
Functional Overview
|
||||
-------------------
|
||||
|
||||
Typical steps to configure an operate the timer are described in the following sections:
|
||||
|
||||
* :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.
|
||||
|
||||
|
||||
.. _timer-api-timer-initialization:
|
||||
|
||||
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.
|
||||
|
||||
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:
|
||||
|
||||
* **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`.
|
||||
|
||||
To get the current values of the timers settings, use function :cpp:func:`timer_get_config`.
|
||||
|
||||
|
||||
.. _timer-api-timer-control:
|
||||
|
||||
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`.
|
||||
|
||||
The timer may be paused at any time by calling :cpp:func:`timer_pause`. To start it again 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:
|
||||
|
||||
* **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`
|
||||
|
||||
|
||||
.. _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.
|
||||
|
||||
After the alarm is enabled and the timer reaches the alarm value, depending on configuration, the following two actions may happen:
|
||||
|
||||
* 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`.
|
||||
|
||||
.. note::
|
||||
|
||||
The alarm will be triggered immediately, if an alarm value is set and the timer has already passed this value.
|
||||
|
||||
To check what alarm value has been set up, call :cpp:func:`timer_get_alarm_value`.
|
||||
|
||||
|
||||
.. _timer-api-interrupts:
|
||||
|
||||
Interrupts
|
||||
^^^^^^^^^^
|
||||
|
||||
Registration of the interrupt handler for a specific timer group and timer is done be 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`.
|
||||
|
||||
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::
|
||||
|
||||
TIMERG0.int_clr_timers.t1 = 1
|
||||
|
||||
See the application example below how to use interrupts.
|
||||
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
|
||||
The 64-bit hardware timer example: :example:`peripherals/timer_group`.
|
||||
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/timer.inc
|
||||
@@ -0,0 +1,170 @@
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
Functionality Overview
|
||||
----------------------
|
||||
|
||||
Description of API is broken down into groups of functions to provide quick overview of features like:
|
||||
|
||||
- Initialization of touch pad driver
|
||||
- Configuration of touch pad GPIO pins
|
||||
- Taking measurements
|
||||
- Adjusting parameters of measurements
|
||||
- Filtering measurements
|
||||
- Touch detection methods
|
||||
- Setting up interrupts to report touch detection
|
||||
- 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`.
|
||||
|
||||
|
||||
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.
|
||||
|
||||
If not required anymore, driver can be disabled by calling :cpp:func:`touch_pad_deinit`.
|
||||
|
||||
|
||||
Configuration
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
Enabling of touch sensor functionality for 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.
|
||||
|
||||
|
||||
Touch State Measurements
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The following two functions come 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.
|
||||
|
||||
.. note::
|
||||
|
||||
Start and configure filter before using :cpp:func:`touch_pad_read_filtered` by calling specific filter functions described down below.
|
||||
|
||||
To see how to use both read functions check :example:`peripherals/touch_pad_read` application example.
|
||||
|
||||
|
||||
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`.
|
||||
|
||||
The following 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`
|
||||
|
||||
Relationship between voltage range (high / low reference voltages), speed (slope) and measure time is shown on 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
|
||||
|
||||
The last chart "Output" represents the touch sensor reading, i.e. the count of pulses collected within measure 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`.
|
||||
|
||||
.. _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`.
|
||||
|
||||
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`.
|
||||
|
||||
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`.
|
||||
|
||||
|
||||
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.
|
||||
|
||||
Hardware touch detection may be also wired to interrupts and this is described in 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.
|
||||
|
||||
|
||||
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.
|
||||
|
||||
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`.
|
||||
|
||||
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`.
|
||||
|
||||
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`.
|
||||
|
||||
.. 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.
|
||||
|
||||
|
||||
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`.
|
||||
|
||||
Configuration of required bit patterns of pads may be managed for each 'SET' with:
|
||||
|
||||
* :cpp:func:`touch_pad_set_group_mask` / :cpp:func:`touch_pad_get_group_mask`
|
||||
* :cpp:func:`touch_pad_clear_group_mask`
|
||||
|
||||
|
||||
.. _touch_pad-api-examples:
|
||||
|
||||
Application Examples
|
||||
--------------------
|
||||
|
||||
- Touch sensor read example: :example:`peripherals/touch_pad_read`.
|
||||
- Touch sensor interrupt example: :example:`peripherals/touch_pad_interrupt`.
|
||||
|
||||
|
||||
.. _touch_pad-api-reference:
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/touch_pad.inc
|
||||
|
||||
GPIO Lookup Macros
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
Some useful macros can be used to specified the GPIO number of a touchpad channel, or vice versa.
|
||||
e.g.
|
||||
|
||||
1. ``TOUCH_PAD_NUM5_GPIO_NUM`` is the GPIO number of channel 5 (12);
|
||||
2. ``TOUCH_PAD_GPIO4_CHANNEL`` is the channel number of GPIO 4 (channel 0).
|
||||
|
||||
.. include:: /_build/inc/touch_channel.inc
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
UART
|
||||
====
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
An Universal Asynchronous Receiver/Transmitter (UART) is a component known to handle the timing requirements for a variety of widely-adapted protocols (RS232, RS485, RS422, ...). An UART provides a widely adopted and cheap method to realize full-duplex data exchange among different devices.
|
||||
|
||||
There are three UART controllers available on the ESP32 chip. They are compatible with UART-enabled devices from various manufacturers. All UART controllers integrated in the ESP32 feature an identical set of registers for ease of programming and flexibility. In this documentation, these controllers are referred to as UART0, UART1, and UART2.
|
||||
|
||||
|
||||
Functional Overview
|
||||
-------------------
|
||||
|
||||
The following overview describes functions and data types used to establish communication between ESP32 and some other UART device. The overview reflects a typical workflow when programming ESP32's UART driver and is broken down into the following sections:
|
||||
|
||||
1. :ref:`uart-api-setting-communication-parameters` - baud rate, data bits, stop bits, etc,
|
||||
2. :ref:`uart-api-setting-communication-pins` - pins the other UART is connected to
|
||||
3. :ref:`uart-api-driver-installation` - allocate ESP32's resources for the UART driver
|
||||
4. :ref:`uart-api-running-uart-communication` - send / receive the data
|
||||
5. :ref:`uart-api-using-interrupts` - trigger interrupts on specific communication events
|
||||
6. :ref:`uart-api-deleting-driver` - release ESP32's resources, if UART communication is not required anymore
|
||||
|
||||
The minimum to make the UART working is to complete the first four steps, the last two steps are optional.
|
||||
|
||||
The driver is identified by :cpp:type:`uart_port_t`, that corresponds to one of the tree UART controllers. Such identification is present in all the following function calls.
|
||||
|
||||
|
||||
.. _uart-api-setting-communication-parameters:
|
||||
|
||||
Setting Communication Parameters
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
There are two ways to set the communications parameters for UART. One is to do it in one shot by calling :cpp:func:`uart_param_config` provided with configuration parameters in :cpp:type:`uart_config_t` structure.
|
||||
|
||||
The alternate way is to configure specific parameters individually by calling dedicated functions:
|
||||
|
||||
* Baud rate - :cpp:func:`uart_set_baudrate`
|
||||
* Number of transmitted bits - :cpp:func:`uart_set_word_length` selected out of :cpp:type:`uart_word_length_t`
|
||||
* Parity control - :cpp:func:`uart_set_parity` selected out of :cpp:type:`uart_parity_t`
|
||||
* Number of stop bits - :cpp:func:`uart_set_stop_bits` selected out of :cpp:type:`uart_stop_bits_t`
|
||||
* Hardware flow control mode - :cpp:func:`uart_set_hw_flow_ctrl` selected out of `uart_hw_flowcontrol_t`
|
||||
|
||||
All the above functions have a ``_get_`` equivalent to retrieve the current setting, e.g. :cpp:func:`uart_get_baudrate`.
|
||||
|
||||
|
||||
.. _uart-api-setting-communication-pins:
|
||||
|
||||
Setting Communication Pins
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
In next step, after configuring communication parameters, we are setting physical GPIO pin numbers the other UART will be connected to. This is done in a single step by calling function :cpp:func:`uart_set_pin` and providing it with GPIO numbers, that driver should use for the Tx, Rx, RTS and CTS signals.
|
||||
|
||||
Instead of GPIO pin number we can enter a macro :cpp:type:`UART_PIN_NO_CHANGE` and the currently allocated pin will not be changed. The same macro should be entered if certain pin will not be used.
|
||||
|
||||
|
||||
.. _uart-api-driver-installation:
|
||||
|
||||
Driver Installation
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Once configuration of driver is complete, we can install it by calling :cpp:func:`uart_driver_install`. As result several resources required by the UART will be allocated. The type / size of resources are specified as function call parameters and concern:
|
||||
|
||||
* size of the send buffer
|
||||
* size of the receive buffer
|
||||
* the event queue handle and size
|
||||
* flags to allocate an interrupt
|
||||
|
||||
If all above steps have been complete, we are ready to connect the other UART device and check the communication.
|
||||
|
||||
|
||||
.. _uart-api-running-uart-communication:
|
||||
|
||||
Running UART Communication
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The processes of serial communication are under control of UART's hardware FSM. The data to be sent should be put into Tx FIFO buffer, FSM will serialize them and sent out. A similar process, but in reverse order, is done to receive the data. Incoming serial stream is processed by FSM and moved to the Rx FIFO buffer. Therefore the task of API's communication functions is limited to writing and reading the data to / from the respective buffer. This is reflected in some function names, e.g.: :cpp:func:`uart_write_bytes` to transmit the data out, or :cpp:func:`uart_read_bytes` to read the incoming data.
|
||||
|
||||
|
||||
Transmitting
|
||||
""""""""""""
|
||||
|
||||
The basic API function to write the data to Tx FIFO buffer is :cpp:func:`uart_tx_chars`. If the buffer contains not sent characters, this function will write what fits into the empty space and exit reporting the number of bytes actually written.
|
||||
|
||||
There is a 'companion' function :cpp:func:`uart_wait_tx_done` that waits until all the data are transmitted out and the Tx FIFO is empty.
|
||||
|
||||
An easier to work with function is :cpp:func:`uart_write_bytes`. It sets up an intermediate ring buffer and exits after copying the data to this buffer. When there is an empty space in the FIFO, the data are moved from the ring buffer to the FIFO in the background by an ISR.
|
||||
|
||||
There is a similar function as above that adds a serial break signal after sending the data - :cpp:func:`uart_write_bytes_with_break`. The 'serial break signal' means holding TX line low for period longer than one data frame.
|
||||
|
||||
|
||||
Receiving
|
||||
"""""""""
|
||||
|
||||
To retrieve the data received by UART and saved in Rx FIFO, use function :cpp:func:`uart_read_bytes`. You can check in advance what is the number of bytes available in Rx FIFO by calling :cpp:func:`uart_get_buffered_data_len`.
|
||||
|
||||
If the data in Rx FIFO is not required and should be discarded, call :cpp:func:`uart_flush`.
|
||||
|
||||
|
||||
Software Flow Control
|
||||
"""""""""""""""""""""
|
||||
|
||||
When the hardware flow control is disabled, then use :cpp:func:`uart_set_rts` and :cpp:func:`uart_set_dtr` to manually set the levels of the RTS and DTR signals.
|
||||
|
||||
|
||||
.. _uart-api-using-interrupts:
|
||||
|
||||
Using Interrupts
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
There are nineteen interrupts reported on specific states of UART or on detected errors. The full list of available interrupts is described in `ESP32 Technical Reference Manual <https://espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf>`_ (PDF). To enable specific interrupts call :cpp:func:`uart_enable_intr_mask`, to disable call :cpp:func:`uart_disable_intr_mask`. The mask of all interrupts is available as :cpp:type:`UART_INTR_MASK`. Registration of an handler to service interrupts is done with :cpp:func:`uart_isr_register`, freeing the handler with :cpp:func:`uart_isr_free`. To clear the interrupt status bits once the handler is called use :cpp:func:`uart_clear_intr_status`.
|
||||
|
||||
The API provides a convenient way to handle specific interrupts discussed above by wrapping them into dedicated functions:
|
||||
|
||||
* **Event detection** - there are several events defined in :cpp:type:`uart_event_type_t` that may be reported to user application using FreeRTOS queue functionality. You can enable this functionality when calling :cpp:func:`uart_driver_install` described in :ref:`uart-api-driver-installation`. Example how to use it is covered in :example:`peripherals/uart_events`.
|
||||
|
||||
* **FIFO space threshold or transmission timeout reached** - the interrupts on TX or Rx FIFO buffer being filled with specific number of characters or on a timeout of sending or receiving data. To use these interrupts, first configure respective threshold values of the buffer length and the timeout by entering them in :cpp:type:`uart_intr_config_t` structure and calling :cpp:func:`uart_intr_config`. Then enable interrupts with functions :cpp:func:`uart_enable_rx_intr` and :cpp:func:`uart_enable_tx_intr`. To disable these interrupts there are corresponding functions :cpp:func:`uart_disable_rx_intr` or :cpp:func:`uart_disable_tx_intr`.
|
||||
|
||||
* **Pattern detection** - an interrupt triggered on detecting a 'pattern' of the same character being sent number of times. The functions that allow to configure, enable and disable this interrupt are :cpp:func:`uart_enable_pattern_det_intr` and cpp:func:`uart_disable_pattern_det_intr`.
|
||||
|
||||
|
||||
Macros
|
||||
^^^^^^
|
||||
|
||||
The API provides several macros to define configuration parameters, e.g. :cpp:type:`UART_FIFO_LEN` to define the length of the hardware FIFO buffers, :cpp:type:`UART_BITRATE_MAX` that gives the maximum baud rate supported by UART, etc.
|
||||
|
||||
|
||||
.. _uart-api-deleting-driver:
|
||||
|
||||
Deleting Driver
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
If communication is established with :cpp:func:`uart_driver_install` for some specific period of time and then not required, the driver may be removed to free allocated resources by calling :cpp:func:`uart_driver_delete`.
|
||||
|
||||
|
||||
Application Examples
|
||||
--------------------
|
||||
|
||||
Configure UART settings and install UART driver to read/write using UART1 interface: :example:`peripherals/uart_echo`.
|
||||
|
||||
Demonstration of how to report various communication events and how to use patern detection interrupts: :example:`peripherals/uart_events`.
|
||||
|
||||
Transmitting and receiveing with the same UART in two separate FreeRTOS tasks: :example:`peripherals/uart_async_rxtxtasks`.
|
||||
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/uart.inc
|
||||
|
||||
|
||||
GPIO Lookup Macros
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
You can use macros to specify the **direct** GPIO (UART module connected to pads through direct IO mux without the GPIO mux) number of a UART channel, or vice versa. The pin name can be omitted if the channel of a GPIO number is specified, e.g.:
|
||||
|
||||
1. ``UART_NUM_2_TXD_DIRECT_GPIO_NUM`` is the GPIO number of UART channel 2 TXD pin (17);
|
||||
2. ``UART_GPIO19_DIRECT_CHANNEL`` is the UART channel number of GPIO 19 (channel 0);
|
||||
3. ``UART_CTS_GPIO19_DIRECT_CHANNEL`` is the UART channel number of GPIO 19, and GPIO 19 must be a CTS pin (channel 0).
|
||||
|
||||
.. include:: /_build/inc/uart_channel.inc
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
Protocols API
|
||||
*************
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
mDNS <mdns>
|
||||
|
||||
|
||||
Example code for this API section is provided in :example:`protocols` directory of ESP-IDF examples.
|
||||
@@ -0,0 +1,188 @@
|
||||
mDNS Service
|
||||
============
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
mDNS is a multicast UDP service that is used to provide local network service and host discovery.
|
||||
|
||||
mDNS is installed by default on most operating systems or is available as separate package. On ``Mac OS`` it is installed by default and is called ``Bonjour``. Apple releases an installer for ``Windows`` that can be found `on Apple's support page <https://support.apple.com/downloads/bonjour%2520for%2520windows>`_. On ``Linux``, mDNS is provided by `avahi <https://github.com/lathiat/avahi>`_ and is usually installed by default.
|
||||
|
||||
mDNS Properties
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
* ``hostname``: the hostname that the device will respond to. If not set, the ``hostname`` will be read from the interface. Example: ``my-esp32`` will resolve to ``my-esp32.local``
|
||||
* ``default_instance``: friendly name for your device, like ``Jhon's ESP32 Thing``. If not set, ``hostname`` will be used.
|
||||
|
||||
Example method to start mDNS for the STA interface and set ``hostname`` and ``default_instance``:
|
||||
|
||||
.. highlight:: c
|
||||
|
||||
::
|
||||
|
||||
void start_mdns_service()
|
||||
{
|
||||
//initialize mDNS service
|
||||
esp_err_t err = mdns_init();
|
||||
if (err) {
|
||||
printf("MDNS Init failed: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
//set hostname
|
||||
mdns_hostname_set("my-esp32");
|
||||
//set default instance
|
||||
mdns_instance_name_set("Jhon's ESP32 Thing");
|
||||
}
|
||||
|
||||
mDNS Services
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
mDNS can advertise information about network services that your device offers. Each service is defined by a few properties.
|
||||
|
||||
* ``instance_name``: friendly name for your service, like ``Jhon's ESP32 Web Server``. If not defined, ``default_instance`` will be used.
|
||||
* ``service_type``: (required) service type, prepended with underscore. Some common types can be found `here <http://www.dns-sd.org/serviceTypes.html>`_.
|
||||
* ``proto``: (required) protocol that the service runs on, prepended with underscore. Example: ``_tcp`` or ``_udp``
|
||||
* ``port``: (required) network port that the service runs on
|
||||
* ``txt``: ``{var, val}`` array of strings, used to define properties for your service
|
||||
|
||||
Example method to add a few services and different properties::
|
||||
|
||||
void add_mdns_services()
|
||||
{
|
||||
//add our services
|
||||
mdns_service_add(NULL, "_http", "_tcp", 80, NULL, 0);
|
||||
mdns_service_add(NULL, "_arduino", "_tcp", 3232, NULL, 0);
|
||||
mdns_service_add(NULL, "_myservice", "_udp", 1234, NULL, 0);
|
||||
|
||||
//NOTE: services must be added before their properties can be set
|
||||
//use custom instance for the web server
|
||||
mdns_service_instance_name_set("_http", "_tcp", "Jhon's ESP32 Web Server");
|
||||
|
||||
mdns_txt_item_t serviceTxtData[3] = {
|
||||
{"board","esp32"},
|
||||
{"u","user"},
|
||||
{"p","password"}
|
||||
};
|
||||
//set txt data for service (will free and replace current data)
|
||||
mdns_service_txt_set("_http", "_tcp", serviceTxtData, 3);
|
||||
|
||||
//change service port
|
||||
mdns_service_port_set("_myservice", "_udp", 4321);
|
||||
}
|
||||
|
||||
mDNS Query
|
||||
^^^^^^^^^^
|
||||
|
||||
mDNS provides methods for browsing for services and resolving host's IP/IPv6 addresses.
|
||||
|
||||
Results for services are returned as a linked list of ``mdns_result_t`` objects.
|
||||
|
||||
Example method to resolve host IPs::
|
||||
|
||||
void resolve_mdns_host(const char * host_name)
|
||||
{
|
||||
printf("Query A: %s.local", host_name);
|
||||
|
||||
struct ip4_addr addr;
|
||||
addr.addr = 0;
|
||||
|
||||
esp_err_t err = mdns_query_a(host_name, 2000, &addr);
|
||||
if(err){
|
||||
if(err == ESP_ERR_NOT_FOUND){
|
||||
printf("Host was not found!");
|
||||
return;
|
||||
}
|
||||
printf("Query Failed");
|
||||
return;
|
||||
}
|
||||
|
||||
printf(IPSTR, IP2STR(&addr));
|
||||
}
|
||||
|
||||
Example method to resolve local services::
|
||||
|
||||
static const char * if_str[] = {"STA", "AP", "ETH", "MAX"};
|
||||
static const char * ip_protocol_str[] = {"V4", "V6", "MAX"};
|
||||
|
||||
void mdns_print_results(mdns_result_t * results){
|
||||
mdns_result_t * r = results;
|
||||
mdns_ip_addr_t * a = NULL;
|
||||
int i = 1, t;
|
||||
while(r){
|
||||
printf("%d: Interface: %s, Type: %s\n", i++, if_str[r->tcpip_if], ip_protocol_str[r->ip_protocol]);
|
||||
if(r->instance_name){
|
||||
printf(" PTR : %s\n", r->instance_name);
|
||||
}
|
||||
if(r->hostname){
|
||||
printf(" SRV : %s.local:%u\n", r->hostname, r->port);
|
||||
}
|
||||
if(r->txt_count){
|
||||
printf(" TXT : [%u] ", r->txt_count);
|
||||
for(t=0; t<r->txt_count; t++){
|
||||
printf("%s=%s; ", r->txt[t].key, r->txt[t].value);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
a = r->addr;
|
||||
while(a){
|
||||
if(a->addr.type == MDNS_IP_PROTOCOL_V6){
|
||||
printf(" AAAA: " IPV6STR "\n", IPV62STR(a->addr.u_addr.ip6));
|
||||
} else {
|
||||
printf(" A : " IPSTR "\n", IP2STR(&(a->addr.u_addr.ip4)));
|
||||
}
|
||||
a = a->next;
|
||||
}
|
||||
r = r->next;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void find_mdns_service(const char * service_name, const char * proto)
|
||||
{
|
||||
ESP_LOGI(TAG, "Query PTR: %s.%s.local", service_name, proto);
|
||||
|
||||
mdns_result_t * results = NULL;
|
||||
esp_err_t err = mdns_query_ptr(service_name, proto, 3000, 20, &results);
|
||||
if(err){
|
||||
ESP_LOGE(TAG, "Query Failed");
|
||||
return;
|
||||
}
|
||||
if(!results){
|
||||
ESP_LOGW(TAG, "No results found!");
|
||||
return;
|
||||
}
|
||||
|
||||
mdns_print_results(results);
|
||||
mdns_query_results_free(results);
|
||||
}
|
||||
|
||||
Example of using the methods above::
|
||||
|
||||
void my_app_some_method(){
|
||||
//search for esp32-mdns.local
|
||||
resolve_mdns_host("esp32-mdns");
|
||||
|
||||
//search for HTTP servers
|
||||
find_mdns_service("_http", "_tcp");
|
||||
//or file servers
|
||||
find_mdns_service("_smb", "_tcp"); //windows sharing
|
||||
find_mdns_service("_afpovertcp", "_tcp"); //apple sharing
|
||||
find_mdns_service("_nfs", "_tcp"); //NFS server
|
||||
find_mdns_service("_ftp", "_tcp"); //FTP server
|
||||
//or networked printer
|
||||
find_mdns_service("_printer", "_tcp");
|
||||
find_mdns_service("_ipp", "_tcp");
|
||||
}
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
|
||||
mDNS server/scanner example: :example:`protocols/mdns`.
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/mdns.inc
|
||||
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
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.
|
||||
|
||||
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
|
||||
--------------------
|
||||
|
||||
``esp_vfs_fat.h`` header file defines functions to connect FatFs with VFS. ``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. ``esp_vfs_fat_unregister_path`` function deletes the registration with VFS, and frees the ``FATFS`` structure.
|
||||
|
||||
Most applications will use the following flow when working with ``esp_vfs_fat_`` functions:
|
||||
|
||||
1. Call ``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.
|
||||
|
||||
2. Call ``ff_diskio_register`` function to register disk IO driver for the drive number used in step 1.
|
||||
|
||||
3. Call ``f_mount`` function (and optionally ``f_fdisk``, ``f_mkfs``) to mount the filesystem using the same drive number which was passed to ``esp_vfs_fat_register``. See FatFs documentation for more details.
|
||||
|
||||
4. Call POSIX and C standard library functions to open, read, write, erase, copy files, etc. Use paths starting with the prefix passed to ``esp_vfs_register`` (such as ``"/sdcard/hello.txt"``).
|
||||
|
||||
5. Optionally, call FatFs library functions directly. Use paths without a VFS prefix in this case (``"/hello.txt"``).
|
||||
|
||||
6. Close all open files.
|
||||
|
||||
7. Call ``f_mount`` function for the same drive number, with NULL ``FATFS*`` argument, to unmount the filesystem.
|
||||
|
||||
8. Call ``ff_diskio_register`` with NULL ``ff_diskio_impl_t*`` argument and the same drive number.
|
||||
|
||||
9. Call ``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.
|
||||
|
||||
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.
|
||||
|
||||
.. doxygenfunction:: esp_vfs_fat_register
|
||||
.. doxygenfunction:: esp_vfs_fat_unregister_path
|
||||
|
||||
|
||||
Using FatFs with VFS and SD cards
|
||||
---------------------------------
|
||||
|
||||
``esp_vfs_fat.h`` header file also provides a convenience function to perform steps 1–3 and 7–9, and also handle SD card initialization: ``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. ``esp_vfs_fat_sdmmc_unmount`` function unmounts the filesystem and releases resources acquired by ``esp_vfs_fat_sdmmc_mount``.
|
||||
|
||||
.. doxygenfunction:: esp_vfs_fat_sdmmc_mount
|
||||
.. doxygenstruct:: esp_vfs_fat_mount_config_t
|
||||
:members:
|
||||
.. doxygenfunction:: esp_vfs_fat_sdmmc_unmount
|
||||
|
||||
FatFS disk IO layer
|
||||
-------------------
|
||||
|
||||
FatFs has been extended with an API to register disk IO 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 ``ff_diskio_register_sdmmc`` function.
|
||||
|
||||
.. doxygenfunction:: ff_diskio_register
|
||||
.. doxygenstruct:: ff_diskio_impl_t
|
||||
:members:
|
||||
.. doxygenfunction:: ff_diskio_register_sdmmc
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
Storage API
|
||||
***********
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
SPI Flash and Partition APIs <spi_flash>
|
||||
SD/MMC Card Host <sdmmc>
|
||||
Non-Volatile Storage <nvs_flash>
|
||||
Virtual Filesystem <vfs>
|
||||
FAT Filesystem <fatfs>
|
||||
Wear Levelling <wear-levelling>
|
||||
SPIFFS Filesystem <spiffs>
|
||||
|
||||
|
||||
Example code for this API section is provided in :example:`storage` directory of ESP-IDF examples.
|
||||
@@ -0,0 +1,33 @@
|
||||
.. include:: ../../../../components/nvs_flash/README.rst
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
|
||||
Two examples are provided in :example:`storage` directory of ESP-IDF examples:
|
||||
|
||||
:example:`storage/nvs_rw_value`
|
||||
|
||||
Demonstrates how to read and write a single integer value using NVS.
|
||||
|
||||
The value holds the number of ESP32 module restarts. Since it is written to NVS, the value is preserved between restarts.
|
||||
|
||||
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.
|
||||
|
||||
: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.
|
||||
|
||||
* 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.
|
||||
|
||||
Example also shows how to implement diagnostics if read / write operation was successful.
|
||||
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/nvs_flash.inc
|
||||
|
||||
.. include:: /_build/inc/nvs.inc
|
||||
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
SDMMC Host Peripheral
|
||||
=====================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
SDMMC peripheral supports SD and MMC memory cards and SDIO cards. SDMMC software builds on top of SDMMC driver and consists of the following parts:
|
||||
|
||||
1. SDMMC host driver (``driver/sdmmc_host.h``) — this driver provides APIs to send commands to the slave device(s), send and receive data, and handling error conditions on the bus.
|
||||
|
||||
2. SDMMC protocol layer (``sdmmc_cmd.h``) — this component handles specifics of SD protocol such as card initialization and data transfer commands. Despite the name, only SD (SDSC/SDHC/SDXC) cards are supported at the moment. Support for MCC/eMMC cards can be added in the future.
|
||||
|
||||
Protocol layer works with the host via ``sdmmc_host_t`` structure. This structure contains pointers to various functions of the host.
|
||||
|
||||
In addition to SDMMC Host peripheral, ESP32 has SPI peripherals which can also be used to work with SD cards. This is supported using a variant of the host driver, ``driver/sdspi_host.h``. This driver has the same interface as SDMMC host driver, and the protocol layer can use either of two.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
Protocol layer APIs
|
||||
-------------------
|
||||
|
||||
Protocol layer is given ``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 ``sdmmc_card_t`` structure. When sending commands to the SD/MMC host driver, protocol layer uses ``sdmmc_command_t`` structure to describe the command, argument, expected return value, and data to transfer, if any.
|
||||
|
||||
Normal usage of the protocol layer is as follows:
|
||||
|
||||
1. Call the host driver functions to initialize the host (e.g. ``sdmmc_host_init``, ``sdmmc_host_init_slot``).
|
||||
2. Call ``sdmmc_card_init`` to initialize the card, passing it host driver information (``host``) and a pointer to ``sdmmc_card_t`` structure which will be filled in (``card``).
|
||||
3. To read and write sectors of the card, use ``sdmmc_read_sectors`` and ``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 SDMMC host peripheral and free resources allocated by the driver (e.g. ``sdmmc_host_deinit``).
|
||||
|
||||
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 ``sdmmc_card_t`` structure, or when accessing SDMMC host driver. Such locking has to be implemented in the higher layer, if necessary (e.g. in the filesystem driver).
|
||||
|
||||
.. doxygenstruct:: sdmmc_host_t
|
||||
:members:
|
||||
|
||||
.. doxygendefine:: SDMMC_HOST_FLAG_1BIT
|
||||
.. doxygendefine:: SDMMC_HOST_FLAG_4BIT
|
||||
.. doxygendefine:: SDMMC_HOST_FLAG_8BIT
|
||||
.. doxygendefine:: SDMMC_HOST_FLAG_SPI
|
||||
.. doxygendefine:: SDMMC_FREQ_DEFAULT
|
||||
.. doxygendefine:: SDMMC_FREQ_HIGHSPEED
|
||||
.. doxygendefine:: SDMMC_FREQ_PROBING
|
||||
|
||||
.. doxygenstruct:: sdmmc_command_t
|
||||
:members:
|
||||
|
||||
.. doxygenstruct:: sdmmc_card_t
|
||||
:members:
|
||||
|
||||
.. doxygenstruct:: sdmmc_csd_t
|
||||
:members:
|
||||
|
||||
.. doxygenstruct:: sdmmc_cid_t
|
||||
:members:
|
||||
|
||||
.. doxygenstruct:: sdmmc_scr_t
|
||||
:members:
|
||||
|
||||
.. doxygenfunction:: sdmmc_card_init
|
||||
.. doxygenfunction:: sdmmc_write_sectors
|
||||
.. doxygenfunction:: sdmmc_read_sectors
|
||||
|
||||
SDMMC host driver APIs
|
||||
----------------------
|
||||
|
||||
On the ESP32, SDMMC host peripheral has two slots:
|
||||
|
||||
- Slot 0 (``SDMMC_HOST_SLOT_0``) is an 8-bit slot. It uses ``HS1_*`` signals in the PIN MUX.
|
||||
- Slot 1 (``SDMMC_HOST_SLOT_1``) is a 4-bit slot. It uses ``HS2_*`` signals in the PIN MUX.
|
||||
|
||||
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 ``sdmmc_slot_config_t`` structure when calling ``sdmmc_host_init_slot``.
|
||||
|
||||
Of all the funtions listed below, only ``sdmmc_host_init``, ``sdmmc_host_init_slot``, and ``sdmmc_host_deinit`` will be used directly by most applications. Other functions, such as ``sdmmc_host_set_bus_width``, ``sdmmc_host_set_card_clk``, and ``sdmmc_host_do_transaction`` will be called by the SD/MMC protocol layer via function pointers in ``sdmmc_host_t`` structure.
|
||||
|
||||
.. doxygenfunction:: sdmmc_host_init
|
||||
|
||||
.. doxygendefine:: SDMMC_HOST_SLOT_0
|
||||
.. doxygendefine:: SDMMC_HOST_SLOT_1
|
||||
.. doxygendefine:: SDMMC_HOST_DEFAULT
|
||||
.. doxygendefine:: SDMMC_SLOT_WIDTH_DEFAULT
|
||||
|
||||
.. doxygenfunction:: sdmmc_host_init_slot
|
||||
|
||||
.. doxygenstruct:: sdmmc_slot_config_t
|
||||
:members:
|
||||
|
||||
.. doxygendefine:: SDMMC_SLOT_NO_CD
|
||||
.. doxygendefine:: SDMMC_SLOT_NO_WP
|
||||
.. doxygendefine:: SDMMC_SLOT_CONFIG_DEFAULT
|
||||
|
||||
.. doxygenfunction:: sdmmc_host_set_bus_width
|
||||
.. doxygenfunction:: sdmmc_host_set_card_clk
|
||||
.. doxygenfunction:: sdmmc_host_do_transaction
|
||||
.. doxygenfunction:: sdmmc_host_deinit
|
||||
|
||||
SD SPI driver APIs
|
||||
------------------
|
||||
|
||||
SPI controllers accessible via spi_master driver (HSPI, VSPI) can be used to work with SD cards. In SPI mode, SD driver has lower throughput than in 1-line SD mode. However SPI mode makes pin selection more flexible, as SPI peripheral can be connected to any ESP32 pins using GPIO Matrix. SD SPI driver uses software controlled CS signal. Currently SD SPI driver assumes that it can use the SPI controller exclusively, so applications which need to share SPI bus between SD cards and other peripherals need to make sure that SD card and other devices are not used at the same time from different tasks.
|
||||
|
||||
SD SPI driver is represented using an ``sdmmc_host_t`` structure initialized using ``SDSPI_HOST_DEFAULT`` macro. For slot initialization, ``SDSPI_SLOT_CONFIG_DEFAULT`` can be used to fill in default pin mapping, which is the same as the pin mapping in SD mode.
|
||||
|
||||
SD SPI driver APIs are very similar to SDMMC host APIs. As with the SDMMC host driver, only ``sdspi_host_init``, ``sdspi_host_init_slot``, and ``sdspi_host_deinit`` functions are normally used by the applications. Other functions are called by the protocol level driver via function pointers in ``sdmmc_host_t`` structure.
|
||||
|
||||
.. note:
|
||||
|
||||
SD over SPI does not support speeds above SDMMC_FREQ_DEFAULT due to a limitation of SPI driver.
|
||||
|
||||
|
||||
.. doxygenfunction:: sdspi_host_init
|
||||
|
||||
.. doxygendefine:: SDSPI_HOST_DEFAULT
|
||||
|
||||
.. doxygenfunction:: sdspi_host_init_slot
|
||||
|
||||
.. doxygenstruct:: sdspi_slot_config_t
|
||||
:members:
|
||||
|
||||
.. doxygendefine:: SDSPI_SLOT_NO_CD
|
||||
.. doxygendefine:: SDSPI_SLOT_NO_WP
|
||||
.. doxygendefine:: SDSPI_SLOT_CONFIG_DEFAULT
|
||||
|
||||
.. doxygenfunction:: sdspi_host_set_card_clk
|
||||
.. doxygenfunction:: sdspi_host_do_transaction
|
||||
.. doxygenfunction:: sdspi_host_deinit
|
||||
@@ -0,0 +1,61 @@
|
||||
.. include:: ../../../../components/spi_flash/README.rst
|
||||
|
||||
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.
|
||||
|
||||
|
||||
.. _spi-flash-implementation-details:
|
||||
|
||||
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.
|
||||
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
API Reference - SPI Flash
|
||||
-------------------------
|
||||
|
||||
.. include:: /_build/inc/esp_spi_flash.inc
|
||||
|
||||
API Reference - Partition Table
|
||||
-------------------------------
|
||||
|
||||
.. include:: /_build/inc/esp_partition.inc
|
||||
|
||||
API Reference - Flash Encrypt
|
||||
-----------------------------
|
||||
|
||||
.. include:: /_build/inc/esp_flash_encrypt.inc
|
||||
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
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.
|
||||
|
||||
Notes
|
||||
-----
|
||||
|
||||
- Presently, spiffs does not support directories. It produces a flat structure. If SPIFFS is mounted under ``/spiffs`` 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.
|
||||
- Presently, it does not detect or handle bad blocks.
|
||||
|
||||
Tools
|
||||
-----
|
||||
|
||||
Host-Side tools for creating SPIFS partition images exist and one such tool is `mkspiffs <https://github.com/igrr/mkspiffs>`_.
|
||||
You can use it to create image from a given folder and then flash that image with ``esptool.py``
|
||||
|
||||
To do that you need to obtain some 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)
|
||||
|
||||
To pack a folder into 1 Megabyte image::
|
||||
|
||||
mkspiffs -c [src_folder] -b 4096 -p 256 -s 0x100000 spiffs.bin
|
||||
|
||||
To flash the image to ESP32 at offset 0x110000::
|
||||
|
||||
python esptool.py --chip esp32 --port [port] --baud [baud] write_flash -z 0x110000 spiffs.bin
|
||||
|
||||
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.
|
||||
|
||||
High level API Reference
|
||||
------------------------
|
||||
|
||||
* :component_file:`spiffs/include/esp_spiffs.h`
|
||||
|
||||
.. include:: /_build/inc/esp_spiffs.inc
|
||||
@@ -0,0 +1,16 @@
|
||||
.. include:: ../../../../components/vfs/README.rst
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
|
||||
`Instructions`_
|
||||
|
||||
.. _Instructions: ../../template.html
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/esp_vfs.inc
|
||||
|
||||
.. include:: /_build/inc/esp_vfs_dev.inc
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
.. include:: ../../../../components/wear_levelling/README.rst
|
||||
|
||||
See also
|
||||
--------
|
||||
|
||||
- :doc:`FAT Filesystem <./fatfs>`
|
||||
- :doc:`Partition Table documentation <../../api-guides/partition-tables>`
|
||||
|
||||
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.
|
||||
|
||||
High level API Reference
|
||||
------------------------
|
||||
|
||||
Header Files
|
||||
^^^^^^^^^^^^
|
||||
|
||||
* :component_file:`fatfs/src/esp_vfs_fat.h`
|
||||
|
||||
Functions
|
||||
^^^^^^^^^
|
||||
|
||||
.. doxygenfunction:: esp_vfs_fat_spiflash_mount
|
||||
.. doxygenstruct:: esp_vfs_fat_mount_config_t
|
||||
:members:
|
||||
.. doxygenfunction:: esp_vfs_fat_spiflash_unmount
|
||||
|
||||
Mid level API Reference
|
||||
-----------------------
|
||||
|
||||
.. include:: /_build/inc/wear_levelling.inc
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
Application Level Tracing
|
||||
=========================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
IDF provides useful feature for program behaviour analysis: application level tracing. It is implemented in the corresponding library and can be enabled via menuconfig. This feature allows to transfer arbitrary data between host and ESP32 via JTAG interface with small overhead on program execution.
|
||||
Developers can use this library to send application specific state of execution to the host and receive commands or other type of info in the opposite direction at runtime. The main use cases of this library are:
|
||||
|
||||
1. Collecting application specific data, see :ref:`app_trace-application-specific-tracing`
|
||||
2. Lightweight logging to the host, see :ref:`app_trace-logging-to-host`
|
||||
3. System behaviour analysis, see :ref:`app_trace-system-behaviour-analysis-with-segger-systemview`
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/esp_app_trace.inc
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
Base MAC address
|
||||
================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
Serveral MAC addresses (universally administered by IEEE) are uniquely assigned to the networking interfaces (WiFi/BT/Ethernet).
|
||||
The final octet of each universally administered MAC address increases by one. Only the first one which is called base MAC address
|
||||
of them is stored in EFUSE or external storage, the others are generated from it. Here, 'generate' means adding 0, 1, 2 and 3
|
||||
(respectively) to the final octet of the base MAC address.
|
||||
|
||||
If the universally administered MAC addresses are not enough for all of the networking interfaces. Local administered MAC addresses
|
||||
which are derived from universally administered MAC addresses are assigned to the reset of networking interfaces.
|
||||
|
||||
A `definition of local vs universal MAC address can be found on Wikipedia <https://en.wikipedia.org/wiki/MAC_address#Universal_vs._local>`_.
|
||||
|
||||
The number of universally administered MAC address can be configured using ``make menuconfig``.
|
||||
|
||||
Base MAC address
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
If using the default base MAC address factory programmed by Espressif in BLK0 of EFUSE, nothing needs to be done.
|
||||
|
||||
If using a custom base MAC address stored in BLK3 of EFUSE, call API ``esp_efuse_mac_get_custom()`` to get the base MAC address
|
||||
which is stored in BLK3 of EFUSE. If correct MAC address is returned, then call ``esp_base_mac_addr_set()`` to set the base MAC
|
||||
address for system to generate the MAC addresses used by the networking interfaces(WiFi/BT/Ethernet).
|
||||
There are 192 bits storage spaces for custom to store base MAC address in BLK3 of EFUSE. They are EFUSE_BLK3_RDATA0,
|
||||
EFUSE_BLK3_RDATA1, EFUSE_BLK3_RDATA2, EFUSE_BLK3_RDATA3, EFUSE_BLK3_RDATA4 and EFUSE_BLK3_RDATA5, each of them is 32 bits
|
||||
register. The format of the 192 bits storage spaces is:
|
||||
|
||||
.. highlight:: none
|
||||
|
||||
::
|
||||
|
||||
------------------------------------------------------
|
||||
Field |Bits |Range |Description
|
||||
------------------------------------------------------
|
||||
version |8 |[191:184] |1: useful. 0: useless
|
||||
------------------------------------------------------
|
||||
reserve |112 |[183:72] |reserved
|
||||
------------------------------------------------------
|
||||
mac address |64 |[71:8] |base MAC address
|
||||
------------------------------------------------------
|
||||
mac crc |8 |[7:0] |crc of base MAC address
|
||||
------------------------------------------------------
|
||||
|
||||
If using base MAC address stored in external storage, firstly get the base MAC address stored in external storage, then call
|
||||
API ``esp_base_mac_addr_set()`` to set the base MAC address for system to generate the MAC addresses used by the networking
|
||||
interfaces(WiFi/BT/Ethernet).
|
||||
|
||||
All of the steps must be done before initializing the networking interfaces(WiFi/BT/Ethernet). It is recommended to do it in
|
||||
``app_main()`` which can be referenced in :example:`system/base_mac_address`.
|
||||
|
||||
Number of universally administered MAC address
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
If the number of universal MAC addresses is two, only two interfaces (WiFi station and Bluetooth) receive a universally
|
||||
administered MAC address. These are generated sequentially by adding 0 and 1 (respectively) to the base MAC address.
|
||||
The remaining two interfaces (WiFi softap and Ethernet) receive local MAC addresses. These are derived from the universal
|
||||
WiFi station and Bluetooth MAC addresses, respectively.
|
||||
|
||||
If the number of universal MAC addresses is four, all four interfaces (WiFi station, WiFi softap, Bluetooth and Ethernet)
|
||||
receive a universally administered MAC address. These are generated sequentially by adding 0, 1, 2 and 3 (respectively)
|
||||
to the final octet of the base MAC address.
|
||||
|
||||
When using the default (Espressif-assigned) base MAC address, either setting can be used. When using a custom universal MAC
|
||||
address range, the correct setting will depend on the allocation of MAC addresses in this range (either 2 or 4 per device.)
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
Header Files
|
||||
^^^^^^^^^^^^
|
||||
|
||||
* :component_file:`esp32/include/esp_system.h`
|
||||
|
||||
|
||||
Functions
|
||||
---------
|
||||
|
||||
.. doxygenfunction:: esp_base_mac_addr_set
|
||||
.. doxygenfunction:: esp_efuse_mac_get_custom
|
||||
@@ -0,0 +1,52 @@
|
||||
High Resolution Timer
|
||||
=====================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
Although FreeRTOS provides software timers, these timers have a few limitations:
|
||||
|
||||
- Maximum resolution is equal to RTOS tick period
|
||||
- Timer callbacks are dispatched from a low-priority task
|
||||
|
||||
Hardware timers are free from both of the limitations, but often they are less convenient to use. For example, application components may need timer events to fire at certain times in the future, but the hardware timer only contains one "compare" value used for interrupt generation. This means that some facility needs to be built on top of the hardware timer to manage the list of pending events can dispatch the callbacks for these events as corresponding hardware interrupts happen.
|
||||
|
||||
``esp_timer`` set of APIs provide such facility. Internally, ``esp_timer`` uses a 32-bit hardware timer (FRC1, "legacy" timer). ``esp_timer`` provides one-shot and periodic timers, microsecond time resolution, and 64-bit range.
|
||||
|
||||
Timer callbacks are dispatched from a high-priority ``esp_timer`` task. Because all the callbacks are dispatched from the same task, it is recommended to only do the minimal possible amount of work from the callback itself, posting an event to a lower priority task using a queue instead.
|
||||
|
||||
.. note: Provisions are made to dispatch some simple callbacks directly from the interrupt handler, if needed. However this option is not implemented at the moment.
|
||||
|
||||
Using ``esp_timer`` APIs
|
||||
------------------------
|
||||
|
||||
Single timer is represented by :cpp:type:`esp_timer_handle_t` type. Timer has a callback function associated with it. This callback function is called from the ``esp_timer`` task each time the timer elapses.
|
||||
|
||||
- To create a timer, call :cpp:func:`esp_timer_create`.
|
||||
- To delete the timer when it is no longer needed, call :cpp:func:`esp_timer_delete`.
|
||||
|
||||
The timer can be started in one-shot mode or in periodic mode.
|
||||
|
||||
- To start the timer in one-shot mode, call :cpp:func:`esp_timer_start_once`, passing the time interval after which the callback should be called. When the callback gets called, the timer is considered to be stopped.
|
||||
|
||||
- To start the timer in periodic mode, call :cpp:func:`esp_timer_start_periodic`, passing the period with which the callback should be called. The timer keeps running until :cpp:func:`esp_timer_stop` is called.
|
||||
|
||||
Note that the timer must not be running when :cpp:func:`esp_timer_start_once` or :cpp:func:`esp_timer_start_periodic` is called. To restart a running timer, call :cpp:func:`esp_timer_stop` first, then call one of the start functions.
|
||||
|
||||
Obtaining Current Time
|
||||
----------------------
|
||||
|
||||
``esp_timer`` also provides a convenience function to obtain the time passed since start-up, with microsecond precision: :cpp:func:`esp_timer_get_time`. This function returns the number of microseconds since ``esp_timer`` was initialized, which usually happens shortly before ``app_main`` function is called.
|
||||
|
||||
Unlike `gettimeofday` function, values returned by :cpp:func:`esp_timer_get_time`:
|
||||
|
||||
- Start from zero after the chip wakes up from deep sleep
|
||||
- Do not have timezone or DST adjustments applied
|
||||
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/esp_timer.inc
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
FreeRTOS
|
||||
========
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
This section contains documentation of FreeRTOS types, functions, and macros. It is automatically generated from FreeRTOS header files.
|
||||
|
||||
For more information about FreeRTOS features specific to ESP-IDF, see :doc:`ESP-IDF FreeRTOS SMP Changes<../../api-guides/freertos-smp>`.
|
||||
|
||||
|
||||
Task API
|
||||
--------
|
||||
|
||||
.. include:: /_build/inc/task.inc
|
||||
|
||||
Queue API
|
||||
---------
|
||||
|
||||
.. include:: /_build/inc/queue.inc
|
||||
|
||||
Semaphore API
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/semphr.inc
|
||||
|
||||
Timer API
|
||||
---------
|
||||
|
||||
.. include:: /_build/inc/timers.inc
|
||||
|
||||
|
||||
Event Group API
|
||||
---------------
|
||||
|
||||
.. include:: /_build/inc/event_groups.inc
|
||||
|
||||
Ringbuffer API
|
||||
--------------
|
||||
|
||||
.. include:: /_build/inc/ringbuf.inc
|
||||
|
||||
@@ -0,0 +1,245 @@
|
||||
Heap Memory Debugging
|
||||
=====================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
ESP-IDF integrates tools for requesting `heap information`_, `detecting heap corruption <heap corruption detection>`_, and `tracing memory leaks <heap tracing>`_. These can help track down memory-related bugs.
|
||||
|
||||
For general information about the heap memory allocator, see the :doc:`Heap Memory Allocation </api-reference/system/mem_alloc>` page.
|
||||
|
||||
.. _heap-information:
|
||||
|
||||
Heap Information
|
||||
----------------
|
||||
|
||||
To obtain information about the state of the heap:
|
||||
|
||||
- :cpp:func:`xPortGetFreeHeapSize` is a FreeRTOS function which returns the number of free bytes in the (data memory) heap. This is equivalent to calling ``heap_caps_get_free_size(MALLOC_CAP_8BIT)``.
|
||||
- :cpp:func:`heap_caps_get_free_size` can also be used to return the current free memory for different memory capabilities.
|
||||
- :cpp:func:`heap_caps_get_largest_free_block` can be used to return the largest free block in the heap. This is the largest single allocation which is currently possible. Tracking this value and comparing to total free heap allows you to detect heap fragmentation.
|
||||
- :cpp:func:`xPortGetMinimumEverFreeHeapSize` and the related :cpp:func:`heap_caps_get_minimum_free_size` can be used to track the heap "low water mark" since boot.
|
||||
- :cpp:func:`heap_caps_get_info` returns a :cpp:class:`multi_heap_info_t` structure which contains the information from the above functions, plus some additional heap-specific data (number of allocations, etc.).
|
||||
- :cpp:func:`heap_caps_print_heap_info` prints a summary to stdout of the information returned by :cpp:func:`heap_caps_get_info`.
|
||||
- :cpp:func:`heap_caps_dump` and :cpp:func:`heap_caps_dump_all` will output detailed information about the structure of each block in the heap. Note that this can be large amount of output.
|
||||
|
||||
|
||||
.. _heap-corruption:
|
||||
|
||||
Heap Corruption Detection
|
||||
-------------------------
|
||||
|
||||
Heap corruption detection allows you to detect various types of heap memory errors:
|
||||
|
||||
- Out of bounds writes & buffer overflow.
|
||||
- Writes to freed memory.
|
||||
- Reads from freed or uninitialized memory,
|
||||
|
||||
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``.
|
||||
|
||||
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.
|
||||
|
||||
It's also possible to manually check heap integrity by calling :cpp:func:`heap_caps_check_integrity_all` or related functions. This function checks all of requested heap memory for integrity, and can be used even if assertions are disabled. If the integrity check prints an error, it will also contain the address(es) of corrupt heap structures.
|
||||
|
||||
Finding Heap Corruption
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Memory corruption can be one of the hardest classes of bugs to find and fix, as one area of memory can be corrupted from a totally different place. Some tips:
|
||||
|
||||
- A crash with a ``CORRUPT HEAP:`` message will usually include a stack trace, but this stack trace is rarely useful. The crash is the symptom of memory corruption when the system realises the heap is corrupt, but usually the corruption happened elsewhere and earlier in time.
|
||||
- Increasing the Heap memory debugging `Configuration`_ level to "Light impact" or "Comprehensive" can give you a more accurate message with the first corrupt memory address.
|
||||
- Adding regular calls to :cpp:func:`heap_caps_check_integrity_all` or :cpp:func:`heap_caps_check_integrity_addr` in your code will help you pin down the exact time that the corruption happened. You can move these checks around to "close in on" the section of code that corrupted the heap.
|
||||
- Based on the memory address which is being corrupted, you can use :ref:`JTAG debugging <jtag-debugging-introduction>` to set a watchpoint on this address and have the CPU halt when it is written to.
|
||||
- If you don't have JTAG, but you do know roughly when the corruption happens, then you can set a watchpoint in software just beforehand via :cpp:func:`esp_set_watchpoint`. A fatal exception will occur when the watchpoint triggers. For example ``esp_set_watchpoint(0, (void *)addr, 4, ESP_WATCHPOINT_STORE``. Note that watchpoints are per-CPU and are set on the current running CPU only, so if you don't know which CPU is corrupting memory then you will need to call this function on both CPUs.
|
||||
- For buffer overflows, `heap tracing`_ in ``HEAP_TRACE_ALL`` mode lets you see which callers are allocating which addresses from the heap. See `Heap Tracing To Find Heap Corruption`_ for more details. If you can find the function which allocates memory with an address immediately before the address which is corrupted, this will probably be the function which overflows the buffer.
|
||||
- Calling :cpp:func:`heap_caps_dump` or :cpp:func:`heap_caps_dump_all` can give an indication of what heap blocks are surrounding the corrupted region and may have overflowed/underflowed/etc.
|
||||
|
||||
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:
|
||||
|
||||
Basic (no poisoning)
|
||||
++++++++++++++++++++
|
||||
|
||||
This is the default level. No special heap corruption features are enabled, but provided assertions are enabled (the default configuration) then a heap corruption error will be printed if any of the heap's internal data structures appear overwritten or corrupted. This usually indicates a buffer overrun or out of bounds write.
|
||||
|
||||
If assertions are enabled, an assertion will also trigger if a double-free occurs (the same memory is freed twice).
|
||||
|
||||
Calling :cpp:func:`heap_caps_check_integrity` in Basic mode will check the integrity of all heap structures, and print errors if any appear to be corrupted.
|
||||
|
||||
Light Impact
|
||||
++++++++++++
|
||||
|
||||
At this level, heap memory is additionally "poisoned" with head and tail "canary bytes" before and after each block which is allocated. If an application writes outside the bounds of allocated buffers, the canary bytes will be corrupted and the integrity check will fail.
|
||||
|
||||
The head canary word is 0xABBA1234 (3412BAAB in byte order), and the tail canary word is 0xBAAD5678 (7856ADBA in byte order).
|
||||
|
||||
"Basic" heap corruption checks can also detect most out of bounds writes, but this setting is more precise as even a single byte overrun can be detected. With Basic heap checks, the number of overrun bytes before a failure is detected will depend on the properties of the heap.
|
||||
|
||||
Enabling "Light Impact" checking increases memory usage, each individual allocation will use 9 to 12 additional bytes of memory (depending on alignment).
|
||||
|
||||
Each time ``free()`` is called in Light Impact mode, the head and tail canary bytes of the buffer being freed are checked against the expected values.
|
||||
|
||||
When :cpp:func:`heap_caps_check_integrity` is called, all allocated blocks of heap memory have their canary bytes checked against the expected values.
|
||||
|
||||
In both cases, the check is that the first 4 bytes of an allocated block (before the buffer returned to the user) should be the word 0xABBA1234. Then the last 4 bytes of the allocated block (after the buffer returned to the user) should be the word 0xBAAD5678.
|
||||
|
||||
Different values usually indicate buffer underrun or overrun, respectively.
|
||||
|
||||
|
||||
Comprehensive
|
||||
+++++++++++++
|
||||
|
||||
This level incorporates the "light impact" detection features plus additional checks for uninitialised-access and use-after-free bugs. In this mode, all freshly allocated memory is filled with the pattern 0xCE, and all freed memory is filled with the pattern 0xFE.
|
||||
|
||||
Enabling "Comprehensive" detection has a substantial runtime performance impact (as all memory needs to be set to the allocation patterns each time a malloc/free completes, and the memory also needs to be checked each time.) However it allows easier detection of memory corruption bugs which are much more subtle to find otherwise. It is recommended to only enable this mode when debugging, not in production.
|
||||
|
||||
Crashes in Comprehensive Mode
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If an application crashes reading/writing an address related to 0xCECECECE in Comprehensive mode, this indicates it has read uninitialized memory. The application should be changed to either use calloc() (which zeroes memory), or initialize the memory before using it. The value 0xCECECECE may also be seen in stack-allocated automatic variables, because in IDF most task stacks are originally allocated from the heap and in C stack memory is uninitialized by default.
|
||||
|
||||
If an application crashes and the exception register dump indicates that some addresses or values were 0xFEFEFEFE, this indicates it is reading heap memory after it has been freed (a "use after free bug".) The application should be changed to not access heap memory after it has been freed.
|
||||
|
||||
If a call to malloc() or realloc() causes a crash because it expected to find the pattern 0xFEFEFEFE in free memory and a different pattern was found, then this indicates the app has a use-after-free bug where it is writing to memory which has already been freed.
|
||||
|
||||
Manual Heap Checks in Comprehensive Mode
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Calls to :cpp:func:`heap_caps_check_integrity` may print errors relating to 0xFEFEFEFE, 0xABBA1234 or 0xBAAD5678. In each case the checker is expecting to find a given pattern, and will error out if this is not found:
|
||||
|
||||
- For free heap blocks, the checker expects to find all bytes set to 0xFE. Any other values indicate a use-after-free bug where free memory has been incorrectly overwritten.
|
||||
- For allocated heap blocks, the behaviour is the same as for `Light Impact` mode. The canary bytes 0xABBA1234 and 0xBAAD5678 are checked at the head and tail of each allocated buffer, and any variation indicates a buffer overrun/underrun.
|
||||
|
||||
.. _heap-tracing:
|
||||
|
||||
Heap Tracing
|
||||
------------
|
||||
|
||||
Heap Tracing allows tracing of code which allocates/frees memory.
|
||||
|
||||
.. note::
|
||||
|
||||
Heap tracing "standalone" mode is currently implemented, meaning that tracing does not require any external hardware but uses internal memory to hold trace data. Heap tracing via JTAG trace port is also planned.
|
||||
|
||||
Heap tracing can perform two functions:
|
||||
|
||||
- Leak checking: find memory which is allocated and never freed.
|
||||
- Heap use analysis: show all functions that are allocating/freeing memory while the trace is running.
|
||||
|
||||
How To Diagnose Memory Leaks
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
If you suspect a memory leak, the first step is to figure out which part of the program is leaking memory. Use the :cpp:func:`xPortGetFreeHeapSize`, :cpp:func:`heap_caps_get_free`, and related functions to track memory use over the life of the application. Try to narrow the leak down to a single function or sequence of functions where free memory always decreases and never recovers.
|
||||
|
||||
Once you've identified the code which you think is leaking:
|
||||
|
||||
- Under ``make menuconfig``, navigate to ``Component settings`` -> ``Heap Memory Debugging`` and set :ref:`CONFIG_HEAP_TRACING`.
|
||||
- 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.
|
||||
- Call the function :cpp:func:`heap_trace_dump` to dump the results of the heap trace.
|
||||
|
||||
An example::
|
||||
|
||||
#include "esp_heap_trace.h"
|
||||
|
||||
#define NUM_RECORDS 100
|
||||
static heap_trace_record_t trace_record[NUM_RECORDS]; // This buffer must be in internal RAM
|
||||
|
||||
...
|
||||
|
||||
void app_main()
|
||||
{
|
||||
...
|
||||
ESP_ERROR_CHECK( heap_trace_init_standalone(trace_record, NUM_RECORDS) );
|
||||
...
|
||||
}
|
||||
|
||||
void some_function()
|
||||
{
|
||||
ESP_ERROR_CHECK( heap_trace_start(HEAP_TRACE_LEAKS) );
|
||||
|
||||
do_something_you_suspect_is_leaking();
|
||||
|
||||
ESP_ERROR_CHECK( heap_trace_stop() );
|
||||
heap_trace_dump();
|
||||
...
|
||||
}
|
||||
|
||||
The output from the heap trace will look something like this::
|
||||
|
||||
2 allocations trace (100 entry buffer)
|
||||
32 bytes (@ 0x3ffaf214) allocated CPU 0 ccount 0x2e9b7384 caller 0x400d276d:0x400d27c1
|
||||
0x400d276d: leak_some_memory at /path/to/idf/examples/get-started/blink/main/./blink.c:27
|
||||
|
||||
0x400d27c1: blink_task at /path/to/idf/examples/get-started/blink/main/./blink.c:52
|
||||
|
||||
8 bytes (@ 0x3ffaf804) allocated CPU 0 ccount 0x2e9b79c0 caller 0x400d2776:0x400d27c1
|
||||
0x400d2776: leak_some_memory at /path/to/idf/examples/get-started/blink/main/./blink.c:29
|
||||
|
||||
0x400d27c1: blink_task at /path/to/idf/examples/get-started/blink/main/./blink.c:52
|
||||
|
||||
40 bytes 'leaked' in trace (2 allocations)
|
||||
total allocations 2 total frees 0
|
||||
|
||||
(Above example output is using :doc:`IDF Monitor </get-started/idf-monitor>` to automatically decode PC addresses to their source files & line number.)
|
||||
|
||||
The first line indicates how many allocation entries are in the buffer, compared to its total size.
|
||||
|
||||
In ``HEAP_TRACE_LEAKS`` mode, for each traced memory allocation which has not already been freed a line is printed with:
|
||||
|
||||
- ``XX bytes`` is number of bytes allocated
|
||||
- ``@ 0x...`` is the heap address returned from malloc/calloc.
|
||||
- ``CPU x`` is the CPU (0 or 1) running when the allocation was made.
|
||||
- ``ccount 0x...`` is the CCOUNT (CPU cycle count) register value when the allocation was mode. Is different for CPU 0 vs CPU 1.
|
||||
- ``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.
|
||||
|
||||
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.
|
||||
|
||||
A warning will be printed if the trace buffer was not large enough to hold all the allocations which happened. If you see this warning, consider either shortening the tracing period or increasing the number of records in the trace buffer.
|
||||
|
||||
Heap Tracing To Find Heap Corruption
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
When a region in heap is corrupted, it may be from some other part of the program which allocated memory at a nearby address.
|
||||
|
||||
If you have some idea at what time the corruption occured, enabling heap tracing in ``HEAP_TRACE_ALL`` mode allows you to record all of the functions which allocated memory, and the addresses where they were corrupted.
|
||||
|
||||
Using heap tracing in this way is very similar to memory leak detection as described above. For memory which is allocated and not freed, the output
|
||||
|
||||
Heap tracing can also be used to help track down heap corruption. By using
|
||||
|
||||
Performance Impact
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Enabling heap tracing in menuconfig increases the code size of your program, and has a very small negative impact on performance of heap allocation/free operations even when heap tracing is not running.
|
||||
|
||||
When heap tracing is running, heap allocation/free operations are substantially slower than when heap tracing is stopped. Increasing the depth of stack frames recorded for each allocation (see above) will also increase this performance impact.
|
||||
|
||||
False-Positive Memory Leaks
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Not everything printed by :cpp:func:`heap_trace_dump` is necessarily a memory leak. Among things which may show up here, but are not memory leaks:
|
||||
|
||||
- Any memory which is allocated after :cpp:func:`heap_trace_start` but then freed after :cpp:func:`heap_trace_stop` will appear in the leak dump.
|
||||
- Allocations may be made by other tasks in the system. Depending on the timing of these tasks, it's quite possible this memory is freed after :cpp:func:`heap_trace_stop` is called.
|
||||
- The first time a task uses stdio - for example, when it calls ``printf()`` - a lock (RTOS mutex semaphore) is allocated by the libc. This allocation lasts until the task is deleted.
|
||||
- The Bluetooth, WiFi, and TCP/IP libraries will allocate heap memory buffers to handle incoming or outgoing data. These memory buffers are usually short lived, but some may be shown in the heap leak trace if the data was received/transmitted by the lower levels of the network while the leak trace was running.
|
||||
- TCP connections will continue to use some memory after they are closed, because of the ``TIME_WAIT`` state. After the ``TIME_WAIT`` period has completed, this memory will be freed.
|
||||
|
||||
One way to differentiate between "real" and "false positive" memory leaks is to call the suspect code multiple times while tracing is running, and look for patterns (multiple matching allocations) in the heap trace output.
|
||||
|
||||
API Reference - Heap Tracing
|
||||
----------------------------
|
||||
|
||||
.. include:: /_build/inc/esp_heap_trace.inc
|
||||
@@ -0,0 +1,51 @@
|
||||
.. _hooks_api_reference:
|
||||
|
||||
FreeRTOS Hooks
|
||||
==============
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
FreeRTOS consists of Idle Hooks and Tick Hooks which allow for application
|
||||
specific funtiionality to be added to the Idle Task and Tick Interrupt. The
|
||||
ESP32 is dual core in nature, hence the ESP-IDF provides its own Idle and Tick
|
||||
Hooks that are dual core compatible in addition to the hooks provided by Vanilla
|
||||
FreeRTOS.
|
||||
|
||||
Vanilla FreeRTOS Hooks
|
||||
----------------------
|
||||
|
||||
Idle and Tick Hooks in vanilla FreeRTOS are implemented by defining
|
||||
implementations for the functions ``vApplicationIdleHook`` and
|
||||
``vApplicationTickHook`` respectively somewhere in the application. Vanilla
|
||||
FreeRTOS will run the user defined Idle Hook every iteration of the Idle Task,
|
||||
whereas the user defined Tick Hook will run once per tick interrupt (given that
|
||||
there are no pended ticks).
|
||||
|
||||
Due to vanilla FreeRTOS being designed for single core, ``vApplicationIdleHook``
|
||||
and ``vApplicationTickHook`` will be run in both cores on the ESP32. In
|
||||
other words, the same Idle Hook and Tick Hook are used for both cores.
|
||||
|
||||
To enable the vanilla FreeRTOS hooks in ESP-IDF, :ref:`CONFIG_FREERTOS_LEGACY_HOOKS`
|
||||
must be enabled in ``make menuconfig``. :ref:`CONFIG_FREERTOS_LEGACY_IDLE_HOOK`
|
||||
and :ref:`CONFIG_FREERTOS_LEGACY_TICK_HOOK` should also be enabled.
|
||||
|
||||
ESP-IDF Idle and Tick Hooks
|
||||
---------------------------
|
||||
|
||||
Due to the dual core nature of the ESP32, it may be necessary for some
|
||||
applications to have seperate Idle Hooks for each core. Furthermore, it may
|
||||
be necessary for Idle and Tick Hooks to have execute multiple functionalities
|
||||
that are configurable at run time. Therefore the ESP-IDF provides it's own Idle
|
||||
and Tick Hooks in addition to the hooks provided by Vanilla FreeRTOS.
|
||||
|
||||
The ESP-IDF Hooks do not operate in the same way as Vanilla FreeRTOS Hooks
|
||||
where users provide a definition for each of the hooks. Instead, the ESP-IDF
|
||||
Hooks are predefined to call a list of user registered callbacks specific to
|
||||
each core. Users can register and deregister callbacks which are run on the
|
||||
Idle or Tick Hook of a specific core.
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/esp_freertos_hooks.inc
|
||||
@@ -0,0 +1,23 @@
|
||||
System API
|
||||
**********
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
FreeRTOS <freertos>
|
||||
FreeRTOS Hooks <hooks>
|
||||
Heap Memory Allocation <mem_alloc>
|
||||
Heap Memory Debugging <heap_debug>
|
||||
Interrupt Allocation <intr_alloc>
|
||||
Watchdogs <wdts>
|
||||
Inter-Processor Call <ipc>
|
||||
High Resolution Timer <esp_timer>
|
||||
Logging <log>
|
||||
Application Level Tracing <app_trace>
|
||||
Power Management <power_management>
|
||||
Sleep Modes <sleep_modes>
|
||||
Base MAC address <base_mac_address>
|
||||
Over The Air Updates (OTA) <ota>
|
||||
|
||||
|
||||
Example code for this API section is provided in :example:`system` directory of ESP-IDF examples.
|
||||
@@ -0,0 +1,106 @@
|
||||
Interrupt allocation
|
||||
====================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
The ESP32 has two cores, with 32 interrupts each. Each interrupt has a certain priority level, most (but not all) interrupts are connected
|
||||
to the interrupt mux. Because there are more interrupt sources than interrupts, sometimes it makes sense to share an interrupt in
|
||||
multiple drivers. The esp_intr_alloc abstraction exists to hide all these implementation details.
|
||||
|
||||
A driver can allocate an interrupt for a certain peripheral by calling esp_intr_alloc (or esp_intr_alloc_sintrstatus). It can use
|
||||
the flags passed to this function to set the type of interrupt allocated, specifying a specific level or trigger method. The
|
||||
interrupt allocation code will then find an applicable interrupt, use the interrupt mux to hook it up to the peripheral, and
|
||||
install the given interrupt handler and ISR to it.
|
||||
|
||||
This code has two different types of interrupts it handles differently: Shared interrupts and non-shared interrupts. The simplest
|
||||
of the two are non-shared interrupts: a separate interrupt is allocated per esp_intr_alloc call and this interrupt is solely used for
|
||||
the peripheral attached to it, with only one ISR that will get called. Shared interrupts can have multiple peripherals triggering
|
||||
it, with multiple ISRs being called when one of the peripherals attached signals an interrupt. Thus, ISRs that are intended for shared
|
||||
interrupts should check the interrupt status of the peripheral they service in order to see if any action is required.
|
||||
|
||||
Non-shared interrupts can be either level- or edge-triggered. Shared interrupts can
|
||||
only be level interrupts (because of the chance of missed interrupts when edge interrupts are
|
||||
used.)
|
||||
(The logic behind this: DevA and DevB share an int. DevB signals an int. Int line goes high. ISR handler
|
||||
calls code for DevA -> does nothing. ISR handler calls code for DevB, but while doing that,
|
||||
DevA signals an int. ISR DevB is done, clears int for DevB, exits interrupt code. Now an
|
||||
interrupt for DevA is still pending, but because the int line never went low (DevA kept it high
|
||||
even when the int for DevB was cleared) the interrupt is never serviced.)
|
||||
|
||||
|
||||
Multicore issues
|
||||
----------------
|
||||
|
||||
Peripherals that can generate interrupts can be divided in two types:
|
||||
|
||||
- External peripherals, within the ESP32 but outside the Xtensa cores themselves. Most ESP32 peripherals are of this type.
|
||||
- Internal peripherals, part of the Xtensa CPU cores themselves.
|
||||
|
||||
Interrupt handling differs slightly between these two types of peripherals.
|
||||
|
||||
Internal peripheral interrupts
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Each Xtensa CPU core has its own set of six internal peripherals:
|
||||
|
||||
- Three timer comparators
|
||||
- A performance monitor
|
||||
- Two software interrupts.
|
||||
|
||||
Internal interrupt sources are defined in esp_intr_alloc.h as ``ETS_INTERNAL_*_INTR_SOURCE``.
|
||||
|
||||
These peripherals can only be configured from the core they are associated with. When generating an interrupt,
|
||||
the interrupt they generate is hard-wired to their associated core; it's not possible to have e.g. an internal
|
||||
timer comparator of one core generate an interrupt on another core. That is why these sources can only be managed
|
||||
using a task running on that specific core. Internal interrupt sources are still allocatable using esp_intr_alloc
|
||||
as normal, but they cannot be shared and will always have a fixed interrupt level (namely, the one associated in
|
||||
hardware with the peripheral).
|
||||
|
||||
External Peripheral Interrupts
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The remaining interrupt sources are from external peripherals. These are defined in soc/soc.h as ``ETS_*_INTR_SOURCE``.
|
||||
|
||||
Non-internal interrupt slots in both CPU cores are wired to an interrupt multiplexer, which can be used to
|
||||
route any external interrupt source to any of these interrupt slots.
|
||||
|
||||
- Allocating an external interrupt will always allocate it on the core that does the allocation.
|
||||
- Freeing an external interrupt must always happen on the same core it was allocated on.
|
||||
- Disabling and enabling external interrupts from another core is allowed.
|
||||
- Multiple external interrupt sources can share an interrupt slot by passing ``ESP_INTR_FLAG_SHARED`` as a flag to esp_intr_alloc().
|
||||
|
||||
Care should be taken when calling esp_intr_alloc() from a task which is not pinned to a core. During task switching, these tasks can migrate between cores. Therefore it is impossible to tell which CPU the interrupt is allocated on, which makes it difficult to free the interrupt handle and may also cause debugging difficulties. It is advised to use xTaskCreatePinnedToCore() with a specific CoreID argument to create tasks that will allocate interrupts. In the case of internal interrupt sources, this is required.
|
||||
|
||||
IRAM-Safe Interrupt Handlers
|
||||
----------------------------
|
||||
|
||||
The ``ESP_INTR_FLAG_IRAM`` flag registers an interrupt handler that always runs from IRAM (and reads all its data from DRAM), and therefore does not need to be disabled during flash erase and write operations.
|
||||
|
||||
This is useful for interrupts which need a guaranteed minimum execution latency, as flash write and erase operations can be slow (erases can take tens or hundreds of milliseconds to complete).
|
||||
|
||||
It can also be useful to keep an interrupt handler in IRAM if it is called very frequently, to avoid flash cache misses.
|
||||
|
||||
Refer to the :ref:`SPI flash API documentation <iram-safe-interrupt-handlers>` for more details.
|
||||
|
||||
Multiple Handlers Sharing A Source
|
||||
----------------------------------
|
||||
|
||||
Several handlers can be assigned to a same source, given that all handlers are allocated using the ``ESP_INTR_FLAG_SHARED`` flag.
|
||||
They'll be all allocated to the interrupt, which the source is attached to, and called sequentially when the source is active.
|
||||
The handlers can be disabled and freed individually. The source is attached to the interrupt (enabled), if one or more handlers are enabled, otherwise detached.
|
||||
A handler will never be called when disabled, while **its source may still be triggered** if any one of its handler enabled.
|
||||
|
||||
Sources attached to non-shared interrupt do not support this feature.
|
||||
|
||||
Though the framework support this feature, you have to use it *very carefully*. There usually exist 2 ways to stop a interrupt from being triggered: *disable the sourse* or *mask peripheral interrupt status*.
|
||||
IDF only handles the enabling and disabling of the source itself, leaving status and mask bits to be handled by users. **Status bits should always be masked before the handler responsible for it is disabled,
|
||||
or the status should be handled in other enabled interrupt properly**. You may leave some status bits unhandled if you just disable one of all the handlers without mask the status bits, which causes the interrupt being triggered infinitely,
|
||||
and finally a system crash.
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/esp_intr_alloc.inc
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
Inter-Processor Call
|
||||
====================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
Due to the dual core nature of the ESP32, there are instances where a certain
|
||||
function must be run in the context of a particular core (e.g. allocating
|
||||
ISR to an interrupt source of a particular core). The IPC (Inter-Processor
|
||||
Call) feature allows for the execution of functions on a particular CPU.
|
||||
|
||||
A given function can be executed on a particular core by calling
|
||||
:cpp:func:`esp_ipc_call` or :cpp:func:`esp_ipc_call_blocking`. IPC is
|
||||
implemented via two high priority FreeRTOS tasks pinned to each CPU known as
|
||||
the IPC Tasks. The two IPC Tasks remain inactive (blocked) until
|
||||
:cpp:func:`esp_ipc_call` or :cpp:func:`esp_ipc_call_blocking` is called. When
|
||||
an IPC Task of a particular core is unblocked, it will preempt the current
|
||||
running task on that core and execute a given function.
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
:cpp:func:`esp_ipc_call` unblocks the IPC task on a particular core to execute
|
||||
a given function. The task that calls :cpp:func:`esp_ipc_call` will be blocked
|
||||
until the IPC Task begins execution of the given function.
|
||||
:cpp:func:`esp_ipc_call_blocking` is similar but will block the calling task
|
||||
until the IPC Task has completed execution of the given function.
|
||||
|
||||
Functions executed by IPCs must be functions of type
|
||||
`void func(void *arg)`. To run more complex functions which require a larger
|
||||
stack, the IPC tasks' stack size can be configured by modifying
|
||||
:ref:`CONFIG_IPC_TASK_STACK_SIZE` in `menuconfig`. The IPC API is protected by a
|
||||
mutex hence simultaneous IPC calls are not possible.
|
||||
|
||||
Care should taken to avoid deadlock when writing functions to be executed by
|
||||
IPC, especially when attempting to take a mutex within the function.
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/esp_ipc.inc
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
.. include:: ../../../../components/log/README.rst
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
|
||||
Log library is commonly used by most of esp-idf components and examples. For demonstration of log functionality check :idf:`examples` folder of `espressif/esp-idf <https://github.com/espressif/esp-idf>`_ repository, that among others, contains the following examples:
|
||||
|
||||
* :example:`system/ota`
|
||||
* :example:`storage/sd_card`
|
||||
* :example:`protocols/https_request`
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/esp_log.inc
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
Heap Memory Allocation
|
||||
======================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
The ESP32 has multiple types of RAM. Internally, there's IRAM, DRAM as well as RAM that can be used as both. It's also
|
||||
possible to connect external SPI RAM to the ESP32 - external RAM can be integrated into the ESP32's memory map using
|
||||
the flash cache.
|
||||
|
||||
For most purposes, the standard libc ``malloc()`` and ``free()`` functions can be used for heap allocation without any
|
||||
issues.
|
||||
|
||||
However, in order to fully make use of all of the memory types and their characteristics, esp-idf also has a
|
||||
capabilities-based heap memory allocator. If you want to have memory with certain properties (for example, DMA-capable
|
||||
memory, or executable memory), you can create an OR-mask of the required capabilities and pass that to
|
||||
:cpp:func:`heap_caps_malloc`. For instance, the standard ``malloc()`` implementation internally allocates memory via
|
||||
``heap_caps_malloc(size, MALLOC_CAP_8BIT)`` in order to get data memory that is byte-addressable.
|
||||
|
||||
Because malloc uses this allocation system as well, memory allocated using :cpp:func:`heap_caps_malloc` can be freed by calling
|
||||
the standard ``free()`` function.
|
||||
|
||||
The "soc" component contains a list of memory regions for the chip, along with the type of each memory (aka its tag) and the associated capabilities for that memory type. On startup, a separate heap is initialised for each contiguous memory region. The capabilities-based allocator chooses the best heap for each allocation, based on the requested capabilities.
|
||||
|
||||
Special Uses
|
||||
------------
|
||||
|
||||
DMA-Capable Memory
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Use the MALLOC_CAP_DMA flag to allocate memory which is suitable for use with hardware DMA engines (for example SPI and I2S). This capability flag excludes any external PSRAM.
|
||||
|
||||
32-Bit Accessible Memory
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
If a certain memory structure is only addressed in 32-bit units, for example an array of ints or pointers, it can be
|
||||
useful to allocate it with the MALLOC_CAP_32BIT flag. This also allows the allocator to give out IRAM memory; something
|
||||
which it can't do for a normal malloc() call. This can help to use all the available memory in the ESP32.
|
||||
|
||||
Memory allocated with MALLOC_CAP_32BIT can *only* be accessed via 32-bit reads and writes, any other type of access will
|
||||
generate a fatal LoadStoreError exception.
|
||||
|
||||
API Reference - Heap Allocation
|
||||
-------------------------------
|
||||
|
||||
.. include:: /_build/inc/esp_heap_caps.inc
|
||||
|
||||
Heap Tracing & Debugging
|
||||
------------------------
|
||||
|
||||
The following features are documented on the :doc:`Heap Memory Debugging </api-reference/system/heap_debug>` page:
|
||||
|
||||
- :ref:`Heap Information <heap-information>` (free space, etc.)
|
||||
- :ref:`Heap Corruption Detection <heap-corruption>`
|
||||
- :ref:`Heap Tracing <heap-tracing>` (memory leak detection, monitoring, etc.)
|
||||
|
||||
API Reference - Initialisation
|
||||
------------------------------
|
||||
|
||||
.. include:: /_build/inc/esp_heap_caps_init.inc
|
||||
|
||||
Implementation Notes
|
||||
--------------------
|
||||
|
||||
Knowledge about the regions of memory in the chip comes from the "soc" component, which contains memory layout information for the chip.
|
||||
|
||||
Each contiguous region of memory contains its own memory heap. The heaps are created using the `multi_heap <API Reference - Multi Heap API>`_ functionality. multi_heap allows any contiguous region of memory to be used as a heap.
|
||||
|
||||
The heap capabilities allocator uses knowledge of the memory regions to initialize each individual heap. When you call a function in the heap capabilities API, it will find the most appropriate heap for the allocation (based on desired capabilities, available space, and preferences for each region's use) and then call the multi_heap function to use the heap situation in that particular region.
|
||||
|
||||
API Reference - Multi Heap API
|
||||
------------------------------
|
||||
|
||||
(Note: The multi heap API is used internally by the heap capabilities allocator. Most IDF programs will never need to call this API directly.)
|
||||
|
||||
.. include:: /_build/inc/multi_heap.inc
|
||||
@@ -0,0 +1,52 @@
|
||||
Over The Air Updates (OTA)
|
||||
==========================
|
||||
|
||||
OTA Process Overview
|
||||
--------------------
|
||||
|
||||
The OTA update mechanism allows a device to update itself based on data received while the normal firmware is running
|
||||
(for example, over WiFi or Bluetooth.)
|
||||
|
||||
OTA requires configuring the :doc:`Partition Table <../../api-guides/partition-tables>` of the device with at least two "OTA app slot"
|
||||
partitions (ie `ota_0` and `ota_1`) and an "OTA Data Partition".
|
||||
|
||||
The OTA operation functions write a new app firmware image to whichever OTA app slot is not currently being used for
|
||||
booting. Once the image is verified, the OTA Data partition is updated to specify that this image should be used for the
|
||||
next boot.
|
||||
|
||||
.. _ota_data_partition:
|
||||
|
||||
OTA Data Partition
|
||||
------------------
|
||||
|
||||
An OTA data partition (type ``data``, subtype ``ota``) must be included in the :doc:`Partition Table <../../api-guides/partition-tables>`
|
||||
of any project which uses the OTA functions.
|
||||
|
||||
For factory boot settings, the OTA data partition should contain no data (all bytes erased to 0xFF). In this case the
|
||||
esp-idf software bootloader will boot the factory app if it is present in the the partition table. If no factory app is
|
||||
included in the partition table, the first available OTA slot (usually ``ota_0``) is booted.
|
||||
|
||||
After the first OTA update, the OTA data partition is updated to specify which OTA app slot partition should be booted next.
|
||||
|
||||
The OTA data partition is two flash sectors (0x2000 bytes) in size, to prevent problems if there is a power failure
|
||||
while it is being written. Sectors are independently erased and written with matching data, and if they disagree a
|
||||
counter field is used to determine which sector was written more recently.
|
||||
|
||||
See also
|
||||
--------
|
||||
|
||||
* :doc:`Partition Table documentation <../../api-guides/partition-tables>`
|
||||
* :doc:`Lower-Level SPI Flash/Partition API <../storage/spi_flash>`
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
|
||||
End-to-end example of OTA firmware update workflow: :example:`system/ota`.
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/esp_ota_ops.inc
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
Power Management
|
||||
================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
Power management algorithm included in ESP-IDF can adjust APB frequency, CPU frequency, and put the chip into light sleep mode to run the application
|
||||
at smallest possible power consumption, given the requirements of application components.
|
||||
|
||||
Application components can express their requirements by creating and acquiring power management locks.
|
||||
|
||||
For instance, a driver for a peripheral clocked from APB can request the APB frequency to be set to 80 MHz, for the duration while the peripheral is used. Another example is that the RTOS will request the CPU to run at the highest configured frequency while there are tasks ready to run. Yet another example is a peripheral driver which needs interrupts to be enabled. Such driver can request light sleep to be disabled.
|
||||
|
||||
Naturally, requesting higher APB or CPU frequency or disabling light sleep causes higher current consumption. Components should try to limit usage of power management locks to the shortest amount of time possible.
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
Power management can be enabled at compile time, using :ref:`CONFIG_PM_ENABLE` option.
|
||||
|
||||
Enabling power management features comes at the cost of increased interrupt latency. Extra latency depends on a number of factors, among which are CPU frequency, single/dual core mode, whether frequency switch needs to be performed or not. Minimal extra latency is 0.2us (when CPU frequency is 240MHz, and frequency scaling is not enabled), maximum extra latency is 40us (when frequency scaling is enabled, and a switch from 40MHz to 80MHz is performed on interrupt entry).
|
||||
|
||||
Dynamic frequency scaling (DFS) can be enabled in the application by calling :cpp:func:`esp_pm_configure` function. Its argument is a structure defining frequency scaling settings (for ESP32, minimum and maximum CPU frequencies). Alternatively, :ref:`CONFIG_PM_DFS_INIT_AUTO` option can be enabled in menuconfig. If enabled, maximal CPU frequency is determined by :ref:`CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ` setting, and minimal CPU frequency is set to the XTAL frequency.
|
||||
|
||||
.. note::
|
||||
|
||||
:cpp:func:`esp_pm_configure` function also has provisions for enabling automatic light sleep mode. However this feature is not fully supported yet, so `esp_pm_configure` will return an `ESP_ERR_NOT_SUPPORTED` if automatic light sleep is requested.
|
||||
|
||||
Power Management Locks
|
||||
----------------------
|
||||
|
||||
As mentioned in the overview, applications can acquire/release locks to control the power management algorithm. When application takes a lock, power management algorithm operation is restricted in a way described below, for each lock. When the lock is released, such restriction is removed.
|
||||
|
||||
Different parts of the application can take the same lock. In this case, lock mush be released the same number of times as it was acquired, in order for power managment algorithm to resume.
|
||||
|
||||
In ESP32, three types of locks are supported:
|
||||
|
||||
``ESP_PM_CPU_FREQ_MAX``
|
||||
Requests CPU frequency to be at the maximal value set via :cpp:func:`esp_pm_configure`. For ESP32, this value can be set to 80, 160, or 240MHz.
|
||||
|
||||
``ESP_PM_APB_FREQ_MAX``
|
||||
Requests APB frequency to be at the maximal supported value. For ESP32, this is 80 MHz.
|
||||
|
||||
``ESP_PM_NO_LIGHT_SLEEP``
|
||||
Prevents automatic light sleep from being used. Note: currently taking this lock has no effect, as automatic light sleep is never used.
|
||||
|
||||
|
||||
Power Management Algorithm for the ESP32
|
||||
----------------------------------------
|
||||
|
||||
When dynamic frequency scaling is enabled, CPU frequency will be switched as follows:
|
||||
|
||||
- If maximal CPU frequency (set using :cpp:func:`esp_pm_configure` or :ref:`CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ`) is 240 MHz:
|
||||
|
||||
1. When ``ESP_PM_CPU_FREQ_MAX`` or ``ESP_PM_APB_FREQ_MAX`` locks are acquired, CPU frequency will be 240 MHz, and APB frequency will be 80 MHz.
|
||||
|
||||
2. Otherwise, frequency will be switched to the minimal value set using :cpp:func:`esp_pm_configure` (usually, XTAL).
|
||||
|
||||
- If maximal CPU frequency is 160 MHz:
|
||||
|
||||
1. When ``ESP_PM_CPU_FREQ_MAX`` is acquired, CPU frequency is set to 160 MHz, and APB frequency to 80 MHz.
|
||||
|
||||
2. When ``ESP_PM_CPU_FREQ_MAX`` is not acquired, but ``ESP_PM_APB_FREQ_MAX`` is, CPU and APB frequencies are set to 80 MHz.
|
||||
|
||||
3. Otherwise, frequency will be switched to the minimal value set using :cpp:func:`esp_pm_configure` (usually, XTAL).
|
||||
|
||||
- If maximal CPU frequency is 80 MHz:
|
||||
|
||||
1. When ``ESP_PM_CPU_FREQ_MAX`` or ``ESP_PM_APB_FREQ_MAX`` locks are acquired, CPU and APB frequencies will be 80 MHz.
|
||||
|
||||
2. Otherwise, frequency will be switched to the minimal value set using :cpp:func:`esp_pm_configure` (usually, XTAL).
|
||||
|
||||
|
||||
Dynamic Frequency Scaling and Peripheral Drivers
|
||||
------------------------------------------------
|
||||
|
||||
When DFS is enabled, APB frequency can be changed several times within a single RTOS tick. Some peripherals can work normally even when APB frequency changes; some can not.
|
||||
|
||||
The following peripherals can work even when APB frequency is changing:
|
||||
|
||||
- UART: if REF_TICK is used as clock source (see `use_ref_tick` member of `uart_config_t`).
|
||||
|
||||
- LEDC: if REF_TICK is used as clock source (see :cpp:func:`ledc_timer_config` function).
|
||||
|
||||
- RMT: if REF_TICK is used as clock source. Currently the driver does not support REF_TICK, but it can be enabled by clearing ``RMT_REF_ALWAYS_ON_CHx`` bit for the respective channel.
|
||||
|
||||
Currently, the following peripheral drivers are aware of DFS and will use ``ESP_PM_APB_FREQ_MAX`` lock for the duration of the transaction:
|
||||
|
||||
- SPI master
|
||||
|
||||
- SDMMC
|
||||
|
||||
The following drivers will hold ``ESP_PM_APB_FREQ_MAX`` lock while the driver is enabled:
|
||||
|
||||
- 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, lock will be released for thte periods of time when radio is disabled.
|
||||
|
||||
- Bluetooth — between calls to :cpp:func:`esp_bt_controller_enable` and :cpp:func:`esp_bt_controller_disable`.
|
||||
|
||||
The following peripheral drivers are not aware of DFS yet. Applications need to acquire/release locks when necessary:
|
||||
|
||||
- I2C
|
||||
|
||||
- I2S
|
||||
|
||||
- MCPWM
|
||||
|
||||
- PCNT
|
||||
|
||||
- Sigma-delta
|
||||
|
||||
- Timer group
|
||||
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/esp_pm.inc
|
||||
.. include:: /_build/inc/pm.inc
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
Sleep Modes
|
||||
===========
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
ESP32 is capable of light sleep and deep sleep power saving modes.
|
||||
|
||||
In light sleep mode, digital peripherals, most of the RAM, and CPUs are clock-gated, and supply voltage is reduced. Upon exit from light sleep, peripherals and CPUs resume operation, their internal state is preserved.
|
||||
|
||||
In deep sleep mode, CPUs, most of the RAM, and all the digital peripherals which are clocked from APB_CLK are powered off. The only parts of the chip which can still be powered on are: RTC controller, RTC peripherals (including ULP coprocessor), and RTC memories (slow and fast).
|
||||
|
||||
Wakeup from deep and light sleep modes can be done using several sources. These sources can be combined, in this case the chip will wake up when any one of the sources is triggered. Wakeup sources can be enabled using ``esp_sleep_enable_X_wakeup`` APIs. Next section describes these APIs in detail. Wakeup sources can be configured at any moment before entering light or deep sleep mode.
|
||||
|
||||
Additionally, the application can force specific powerdown modes for the RTC peripherals and RTC memories using ``esp_sleep_pd_config`` API.
|
||||
|
||||
Once wakeup sources are configured, application can enter sleep mode using ``esp_light_sleep_start`` or ``esp_deep_sleep_start`` APIs. At this point the hardware will be configured according to the requested wakeup sources, and RTC controller will either power down or power off the CPUs and digital peripherals.
|
||||
|
||||
WiFi/BT and sleep modes
|
||||
-----------------------
|
||||
|
||||
In deep sleep mode, wireless peripherals are powered down. Before entering sleep mode, applications must disable WiFi and BT using appropriate calls ( ``esp_bluedroid_disable``, ``esp_bt_controller_disable``, ``esp_wifi_stop``).
|
||||
|
||||
WiFi can coexist with light sleep mode, allowing the chip to go into light sleep mode when there is no network activity, and waking up the chip from light sleep mode when required. However **APIs described in this section can not be used for that purpose**. ``esp_light_sleep_start`` forces the chip to enter light sleep mode, regardless of whether WiFi is active or not. Automatic entry into light sleep mode, coordinated with WiFi driver, will be supported using a separate set of APIs.
|
||||
|
||||
Wakeup sources
|
||||
--------------
|
||||
|
||||
Timer
|
||||
^^^^^
|
||||
|
||||
RTC controller has a built in timer which can be used to wake up the chip after a predefined amount of time. Time is specified at microsecond precision, but the actual resolution depends on the clock source selected for RTC SLOW_CLK. See chapter "Reset and Clock" of the ESP32 Technical Reference Manual for details about RTC clock options.
|
||||
|
||||
This wakeup mode doesn't require RTC peripherals or RTC memories to be powered on during sleep.
|
||||
|
||||
The following function can be used to enable deep sleep wakeup using a timer.
|
||||
|
||||
.. doxygenfunction:: esp_sleep_enable_timer_wakeup
|
||||
|
||||
Touch pad
|
||||
^^^^^^^^^
|
||||
|
||||
RTC IO module contains logic to trigger wakeup when a touch sensor interrupt occurs. You need to configure the touch pad interrupt before the chip starts deep sleep.
|
||||
|
||||
Revisions 0 and 1 of the ESP32 only support this wakeup mode when RTC peripherals are not forced to be powered on (i.e. ESP_PD_DOMAIN_RTC_PERIPH should be set to ESP_PD_OPTION_AUTO).
|
||||
|
||||
.. doxygenfunction:: esp_sleep_enable_touchpad_wakeup
|
||||
|
||||
|
||||
External wakeup (ext0)
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
RTC IO module contains logic to trigger wakeup when one of RTC GPIOs is set to a predefined logic level. RTC IO is part of RTC peripherals power domain, so RTC peripherals will be kept powered on during deep sleep if this wakeup source is requested.
|
||||
|
||||
Because RTC IO module is enabled in this mode, internal pullup or pulldown resistors can also be used. They need to be configured by the application using ``rtc_gpio_pullup_en`` and ``rtc_gpio_pulldown_en`` functions, before calling ``esp_sleep_start``.
|
||||
|
||||
In revisions 0 and 1 of the ESP32, this wakeup source is incompatible with ULP and touch wakeup sources.
|
||||
|
||||
.. warning:: After wake up from sleep, IO pad used for wakeup will be configured as RTC IO. Before using this pad as digital GPIO, reconfigure it using ``rtc_gpio_deinit(gpio_num)`` function.
|
||||
|
||||
.. doxygenfunction:: esp_sleep_enable_ext0_wakeup
|
||||
|
||||
External wakeup (ext1)
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
RTC controller contains logic to trigger wakeup using multiple RTC GPIOs. One of the two logic functions can be used to trigger wakeup:
|
||||
|
||||
- wake up if any of the selected pins is high (``ESP_EXT1_WAKEUP_ANY_HIGH``)
|
||||
- wake up if all the selected pins are low (``ESP_EXT1_WAKEUP_ALL_LOW``)
|
||||
|
||||
This wakeup source is implemented by the RTC controller. As such, RTC peripherals and RTC memories can be powered down in this mode. However, if RTC peripherals are powered down, internal pullup and pulldown resistors will be disabled. To use internal pullup or pulldown resistors, request RTC peripherals power domain to be kept on during sleep, and configure pullup/pulldown resistors using ``rtc_gpio_`` functions, before entering sleep::
|
||||
|
||||
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
||||
gpio_pullup_dis(gpio_num);
|
||||
gpio_pulldown_en(gpio_num);
|
||||
|
||||
.. warning:: After wake up from sleep, IO pad(s) used for wakeup will be configured as RTC IO. Before using these pads as digital GPIOs, reconfigure them using ``rtc_gpio_deinit(gpio_num)`` function.
|
||||
|
||||
The following function can be used to enable this wakeup mode:
|
||||
|
||||
.. doxygenfunction:: esp_sleep_enable_ext1_wakeup
|
||||
|
||||
.. doxygenenum:: esp_sleep_ext1_wakeup_mode_t
|
||||
|
||||
|
||||
ULP coprocessor wakeup
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
ULP coprocessor can run while the chip is in sleep mode, and may be used to poll sensors, monitor ADC or touch sensor values, and wake up the chip when a specific event is detected. ULP coprocessor is part of RTC peripherals power domain, and it runs the program stored in RTC slow memeory. RTC slow memory will be powered on during sleep if this wakeup mode is requested. RTC peripherals will be automatically powered on before ULP coprocessor starts running the program; once the program stops running, RTC peripherals are automatically powered down again.
|
||||
|
||||
Revisions 0 and 1 of the ESP32 only support this wakeup mode when RTC peripherals are not forced to be powered on (i.e. ESP_PD_DOMAIN_RTC_PERIPH should be set to ESP_PD_OPTION_AUTO).
|
||||
|
||||
The following function can be used to enable this wakeup mode:
|
||||
|
||||
.. doxygenfunction:: esp_sleep_enable_ulp_wakeup
|
||||
|
||||
Power-down of RTC peripherals and memories
|
||||
------------------------------------------
|
||||
|
||||
By default, ``esp_deep_sleep_start`` and ``esp_light_sleep_start`` functions will power down all RTC power domains which are not needed by the enabled wakeup sources. To override this behaviour, ``esp_sleep_pd_config`` function is provided.
|
||||
|
||||
Note: in revision 0 of the ESP32, RTC fast memory will always be kept enabled in deep sleep, so that the deep sleep stub can run after reset. This can be overriden, if the application doesn't need clean reset behaviour after deep sleep.
|
||||
|
||||
If some variables in the program are placed into RTC slow memory (for example, using ``RTC_DATA_ATTR`` attribute), RTC slow memory will be kept powered on by default. This can be overriden using ``esp_sleep_pd_config`` function, if desired.
|
||||
|
||||
.. doxygenfunction:: esp_sleep_pd_config
|
||||
.. doxygenenum:: esp_sleep_pd_domain_t
|
||||
.. doxygenenum:: esp_sleep_pd_option_t
|
||||
|
||||
|
||||
Entering light sleep
|
||||
--------------------
|
||||
|
||||
The following function can be used to enter light sleep once wakeup sources are configured. It is also possible to go into light sleep with no wakeup sources configured, in this case the chip will be in light sleep mode indefinetly, until external reset is applied.
|
||||
|
||||
.. doxygenfunction:: esp_light_sleep_start
|
||||
|
||||
Entering deep sleep
|
||||
-------------------
|
||||
|
||||
The following function can be used to enter deep sleep once wakeup sources are configured. It is also possible to go into deep sleep with no wakeup sources configured, in this case the chip will be in deep sleep mode indefinetly, until external reset is applied.
|
||||
|
||||
.. doxygenfunction:: esp_deep_sleep_start
|
||||
|
||||
Configuring IOs
|
||||
---------------
|
||||
|
||||
Some ESP32 IOs have internal pullups or pulldowns, which are enabled by default. If an external circuit drives this pin in deep sleep mode, current consumption may increase due to current flowing through these pullups and pulldowns.
|
||||
|
||||
To isolate a pin, preventing extra current draw, call :cpp:func:`rtc_gpio_isolate` function.
|
||||
|
||||
For example, on ESP32-WROVER module, GPIO12 is pulled up externally. GPIO12 also has an internal pulldown in the ESP32 chip. This means that in deep sleep, some current will flow through these external and internal resistors, increasing deep sleep current above the minimal possible value.
|
||||
Add the following code before :cpp:func:`esp_deep_sleep_start` to remove this extra current:
|
||||
|
||||
```c++
|
||||
rtc_gpio_isolate(GPIO_NUM_12);
|
||||
```
|
||||
|
||||
Checking sleep wakeup cause
|
||||
---------------------------
|
||||
|
||||
The following function can be used to check which wakeup source has triggered wakeup from sleep mode. For touch pad and ext1 wakeup sources, it is possible to identify pin or touch pad which has caused wakeup.
|
||||
|
||||
.. doxygenfunction:: esp_sleep_get_wakeup_cause
|
||||
.. doxygenenum:: esp_sleep_wakeup_cause_t
|
||||
.. doxygenfunction:: esp_sleep_get_touchpad_wakeup_status
|
||||
.. doxygenfunction:: esp_sleep_get_ext1_wakeup_status
|
||||
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
|
||||
Implementation of basic functionality of deep sleep is shown in :example:`protocols/sntp` example, where ESP module is periodically waken up to retrive time from NTP server.
|
||||
|
||||
More extensive example in :example:`system/deep_sleep` illustrates usage of various deep sleep wakeup triggers and ULP coprocessor programming.
|
||||
@@ -0,0 +1,103 @@
|
||||
Watchdogs
|
||||
=========
|
||||
|
||||
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
|
||||
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
|
||||
yielding for a prolonged period.
|
||||
|
||||
Interrupt watchdog
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The interrupt watchdog makes sure the FreeRTOS task switching interrupt isn't blocked for a long time. This
|
||||
is bad because no other tasks, including potentially important ones like the WiFi task and the idle task,
|
||||
can't get any CPU runtime. A blocked task switching interrupt can happen because a program runs into an
|
||||
infinite loop with interrupts disabled or hangs in an interrupt.
|
||||
|
||||
The default action of the interrupt watchdog is to invoke the panic handler. causing a register dump and an opportunity
|
||||
for the programmer to find out, using either OpenOCD or gdbstub, what bit of code is stuck with interrupts
|
||||
disabled. Depending on the configuration of the panic handler, it can also blindly reset the CPU, which may be
|
||||
preferred in a production environment.
|
||||
|
||||
The interrupt watchdog is built around the hardware watchdog in timer group 1. If this watchdog for some reason
|
||||
cannot execute the NMI handler that invokes the panic handler (e.g. because IRAM is overwritten by garbage),
|
||||
it will hard-reset the SOC.
|
||||
|
||||
Task Watchdog Timer
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The Task Watchdog Timer (TWDT) is responsible for detecting instances of tasks
|
||||
running for a prolonged period of time without yielding. This is a symptom of
|
||||
CPU starvation and is usually caused by a higher priority task looping without
|
||||
yielding to a lower-priority task thus starving the lower priority task from
|
||||
CPU time. This can be an indicator of poorly written code that spinloops on a
|
||||
peripheral, or a task that is stuck in an infinite loop.
|
||||
|
||||
By default the TWDT will watch the Idle Tasks of each CPU, however any task can
|
||||
elect to be watched by the TWDT. Each watched task must 'reset' the TWDT
|
||||
periodically to indicate that they have been allocated CPU time. If a task does
|
||||
not reset within the TWDT timeout period, a warning will be printed with
|
||||
information about which tasks failed to reset the TWDT in time and which
|
||||
tasks are currently running on the ESP32 CPUs and.
|
||||
|
||||
The TWDT is built around the Hardware Watchdog Timer in Timer Group 0. The TWDT
|
||||
can be initialized by calling :cpp:func:`esp_task_wdt_init` which will configure
|
||||
the hardware timer. A task can then subscribe to the TWDT using
|
||||
:cpp:func:`esp_task_wdt_add` in order to be watched. Each subscribed task must
|
||||
periodically call :cpp:func:`esp_task_wdt_reset` to reset the TWDT. Failure by
|
||||
any subscribed tasks to periodically call :cpp:func:`esp_task_wdt_reset`
|
||||
indicates that one or more tasks have been starved of CPU time or are stuck in a
|
||||
loop somewhere.
|
||||
|
||||
A watched task can be unsubscribed from the TWDT using
|
||||
:cpp:func:`esp_task_wdt_delete()`. A task that has been unsubscribed should no
|
||||
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_TASK_WDT` in ``make menuconfig`` will be enabled causing
|
||||
the TWDT to be initialized automatically during startup. Likewise
|
||||
:ref:`CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0` and
|
||||
:ref:`CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1` are also enabled by default causing
|
||||
the two Idle Tasks to be subscribed to the TWDT during startup.
|
||||
|
||||
JTAG and watchdogs
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
While debugging using OpenOCD, the CPUs will be halted every time a breakpoint
|
||||
is reached. However if the watchdog timers continue to run when a breakpoint is
|
||||
encountered, they will eventually trigger a reset making it very difficult to
|
||||
debug code. Therefore OpenOCD will disable the hardware timers of both the
|
||||
interrupt and task watchdogs at every breakpoint. Moreover, OpenOCD will not
|
||||
reenable them upon leaving the breakpoint. This means that interrupt watchdog
|
||||
and task watchdog functionality will essentially be disabled. No warnings or
|
||||
panics from either watchdogs will be generated when the ESP32 is connected to
|
||||
OpenOCD via JTAG.
|
||||
|
||||
|
||||
Interrupt Watchdog API Reference
|
||||
--------------------------------
|
||||
|
||||
Header File
|
||||
^^^^^^^^^^^
|
||||
|
||||
* :component_file:`esp32/include/esp_int_wdt.h`
|
||||
|
||||
|
||||
Functions
|
||||
---------
|
||||
|
||||
.. doxygenfunction:: esp_int_wdt_init
|
||||
|
||||
Task Watchdog API Reference
|
||||
----------------------------
|
||||
|
||||
A full example using the Task Watchdog is available in esp-idf: :example:`system/task_watchdog`
|
||||
|
||||
.. include:: /_build/inc/esp_task_wdt.inc
|
||||
@@ -0,0 +1,105 @@
|
||||
API Documentation Template
|
||||
==========================
|
||||
|
||||
.. note::
|
||||
|
||||
*INSTRUCTIONS*
|
||||
|
||||
|
||||
|
||||
1. Use this file (:idf_file:`docs/api-reference/template.rst`) as a template to document API.
|
||||
2. Change the file name to the name of the header file that represents documented API.
|
||||
3. Include respective files with descriptions from the API folder using ``..include::``
|
||||
|
||||
* README.rst
|
||||
* example.rst
|
||||
* ...
|
||||
|
||||
4. Optionally provide description right in this file.
|
||||
5. Once done, remove all instructions like this one and any superfluous headers.
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
.. note::
|
||||
|
||||
*INSTRUCTIONS*
|
||||
|
||||
1. Provide overview where and how this API may be used.
|
||||
2. Where applicable include code snippets to illustrate functionality of particular functions.
|
||||
3. To distinguish between sections, use the following `heading levels <http://www.sphinx-doc.org/en/stable/rest.html#sections>`_:
|
||||
|
||||
* ``#`` with overline, for parts
|
||||
* ``*`` with overline, for chapters
|
||||
* ``=``, for sections
|
||||
* ``-``, for subsections
|
||||
* ``^``, for subsubsections
|
||||
* ``"``, for paragraphs
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
|
||||
.. note::
|
||||
|
||||
*INSTRUCTIONS*
|
||||
|
||||
1. Prepare one or more practical examples to demonstrate functionality of this API.
|
||||
2. Each example should follow pattern of projects located in ``esp-idf/examples/`` folder.
|
||||
3. Place example in this folder complete with ``README.md`` file.
|
||||
4. Provide overview of demonstrated functionality in ``README.md``.
|
||||
5. With good overview reader should be able to understand what example does without opening the source code.
|
||||
6. Depending on complexity of example, break down description of code into parts and provide overview of functionality of each part.
|
||||
7. Include flow diagram and screenshots of application output if applicable.
|
||||
8. Finally add in this section synopsis of each example together with link to respective folder in ``esp-idf/examples/``.
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. highlight:: none
|
||||
|
||||
.. note::
|
||||
|
||||
*INSTRUCTIONS*
|
||||
|
||||
1. This repository provides for automatic update of API reference documentation using :doc:`code markup retrieved by Doxygen from header files <../contribute/documenting-code>`.
|
||||
|
||||
2. Update is done on each documentation build by invoking script :idf_file:`docs/gen-dxd.py` for all header files listed in the ``INPUT`` statement of :idf_file:`docs/Doxyfile`.
|
||||
|
||||
3. Each line of the ``INPUT`` statement (other than a comment that begins with ``##``) contains a path to header file ``*.h`` that will be used to generate corresponding ``*.inc`` files::
|
||||
|
||||
##
|
||||
## Wi-Fi - API Reference
|
||||
##
|
||||
../components/esp32/include/esp_wifi.h \
|
||||
../components/esp32/include/esp_smartconfig.h \
|
||||
|
||||
4. The ``*.inc`` files contain formatted reference of API members generated automatically on each documentation build. All ``*.inc`` files are placed in Sphinx ``_build`` directory. To see directives generated for e.g. ``esp_wifi.h``, run ``python gen-dxd.py esp32/include/esp_wifi.h``.
|
||||
|
||||
5. To show contents of ``*.inc`` file in documentation, include it as follows::
|
||||
|
||||
.. include:: /_build/inc/esp_wifi.inc
|
||||
|
||||
For example see :idf_file:`docs/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/api-reference/system/deep_sleep.rst` for example.
|
||||
|
||||
Below is the list of common ``.. doxygen...::`` directives:
|
||||
|
||||
* Functions - ``.. doxygenfunction:: name_of_function``
|
||||
* Unions -``.. doxygenunion:: name_of_union``
|
||||
* Structures -``.. doxygenstruct:: name_of_structure`` together with ``:members:``
|
||||
* Macros - ``.. doxygendefine:: name_of_define``
|
||||
* Type Definitions - ``.. doxygentypedef:: name_of_type``
|
||||
* Enumerations - ``.. doxygenenum:: name_of_enumeration``
|
||||
|
||||
See `Breathe documentation <https://breathe.readthedocs.io/en/latest/directives.html>`_ for additional information.
|
||||
|
||||
To provide a link to header file, use the :ref:`link custom role <link-custom-roles>` as follows::
|
||||
|
||||
* :component_file:`path_to/header_file.h`
|
||||
|
||||
7. In any case, to generate API reference, the file :idf_file:`docs/Doxyfile` should be updated with paths to ``*.h`` headers that are being documented.
|
||||
|
||||
8. When changes are committed and documentation is build, check how this section has been rendered. :doc:`Correct annotations <../contribute/documenting-code>` in respective header files, if required.
|
||||
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
ESP-NOW
|
||||
=======
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
ESP-NOW is a kind of connectionless WiFi communication protocol which is defined by Espressif. In ESP-NOW, application data is
|
||||
encapsulated in vendor-specific action frame and then transmitted from one WiFi device to another without connection.
|
||||
CTR with CBC-MAC Protocol(CCMP) is used to protect the action frame for security. ESP-NOW is widely used in smart light, remote
|
||||
controlling, sensor, etc.
|
||||
|
||||
Frame Format
|
||||
------------
|
||||
|
||||
ESP-NOW uses vendor-specific action frame to transmit ESP-NOW data. The format of vendor-specific action frame is as follows:
|
||||
|
||||
.. highlight:: none
|
||||
|
||||
::
|
||||
|
||||
----------------------------------------------------------------------------------------
|
||||
| MAC Header | Category Code | Organization Identifier | Vendor Specific Content | FCS |
|
||||
----------------------------------------------------------------------------------------
|
||||
1 byte 3 bytes 7~255 bytes
|
||||
|
||||
- Category Code: The Category field is set to the value(127) indicating the vendor-specific category.
|
||||
- Organization Identifier: The Organization Identifier contains a unique identifier(0x18fe34) which is the first three bytes
|
||||
of MAC address applied by Espressif.
|
||||
- Vendor Specific Content: The Vendor Specific Content contains vendor-specific field as follows:
|
||||
|
||||
.. highlight:: none
|
||||
|
||||
::
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
| Element ID | Length | Organization Identifier | Type | Version | Body |
|
||||
-------------------------------------------------------------------------------
|
||||
1 byte 1 byte 3 bytes 1 byte 1 byte 0~250 bytes
|
||||
|
||||
- Element ID: The Element ID field is set to the value(221) indicating the vendor-specific element.
|
||||
- Length: The length is the total length of Organization Identifier, Type, Version and Body.
|
||||
- Organization Identifier: The Organization Identifier contains a unique identifier(0x18fe34) which is the first three bytes
|
||||
of MAC address applied by Espressif.
|
||||
- Type: The Type field is set to the value(4) indicating ESP-NOW.
|
||||
- Version: The Version field is set to the version of ESP-NOW.
|
||||
- Body: The Body contains the ESP-NOW data.
|
||||
|
||||
As ESP-NOW is connectionless, the MAC header is a little different from that of standard frames. The FromDS and ToDS bits of
|
||||
FrameControl field are both 0. The first address field is set to the destination address. The second address field is set to
|
||||
the source address. The third address field is set to broadcast address(0xff:0xff:0xff:0xff:0xff:0xff).
|
||||
|
||||
Security
|
||||
--------
|
||||
|
||||
ESP-NOW use CCMP method which can be referenced in IEEE Std. 802.11-2012 to protect the vendor-specific action frame. The WiFi
|
||||
device maintains a Primary Master Key(PMK) and several Local Master Keys(LMK). The lengths of them are 16 bytes. PMK is used
|
||||
to encrypt LMK with AES-128 algorithm. Call ``esp_now_set_pmk()`` to set PMK. If PMK is not set, a default PMK will be used.
|
||||
If LMK of the paired device is set, it will be used to encrypt the vendor-specific action frame with CCMP method. The maximum
|
||||
number of different LMKs is six. Do not support encrypting multicast vendor-specific action frame.
|
||||
|
||||
Initialization and De-initialization
|
||||
------------------------------------
|
||||
|
||||
Call ``esp_now_init()`` to initialize ESP-NOW and ``esp_now_deinit()`` to de-initialize ESP-NOW. ESP-NOW data must be transmitted
|
||||
after WiFi is started, so it is recommended to start WiFi before initializing ESP-NOW and stop WiFi after de-initializing ESP-NOW.
|
||||
When ``esp_now_deinit()`` is called, all of the information of paired devices will be deleted.
|
||||
|
||||
Add Paired Device
|
||||
-----------------
|
||||
|
||||
Before sending data to other device, call ``esp_now_add_peer()`` to add it to the paired device list first. The maximum number of
|
||||
paired devices is twenty. If security is enabled, the LMK must be set. ESP-NOW data can be sent from station or softap interface.
|
||||
Make sure that the interface is enabled before sending ESP-NOW data. A device with broadcast MAC address must be added before
|
||||
sending broadcast data. The range of the channel of paired device is from 0 to 14. If the channel is set to 0, data will be sent
|
||||
on the current channel. Otherwise, the channel must be set as the channel that the local device is on.
|
||||
|
||||
Send ESP-NOW Data
|
||||
-----------------
|
||||
|
||||
Call ``esp_now_send()`` to send ESP-NOW data and ``esp_now_register_send_cb`` to register sending callback function. It will return
|
||||
`ESP_NOW_SEND_SUCCESS` in sending callback function if the data is received successfully on MAC layer. Otherwise, it will return
|
||||
`ESP_NOW_SEND_FAIL`. There are several reasons failing to send ESP-NOW data, for example, the destination device doesn't exist, the
|
||||
channels of the devices are not the same, the action frame is lost when transmiting on the air, etc. It is not guaranteed that
|
||||
application layer can receive the data. If necessary, send back ack data when receiving ESP-NOW data. If receiving ack data timeout
|
||||
happens, retransmit the ESP-NOW data. A sequence number can also be assigned to ESP-NOW data to drop the duplicated data.
|
||||
|
||||
If there is a lot of ESP-NOW data to send, call ``esp_now_send()`` to send less than or equal to 250 bytes of data once a time.
|
||||
Note that too short interval between sending two ESP-NOW datas may lead to disorder of sending callback function. So, it is
|
||||
recommended that sending the next ESP-NOW data after the sending callback function of previous sending has returned. The sending
|
||||
callback function runs from a high-priority WiFi task. So, do not do lengthy operations in the callback function. Instead, post
|
||||
necessary data to a queue and handle it from a lower priority task.
|
||||
|
||||
Receiving ESP-NOW Data
|
||||
----------------------
|
||||
|
||||
Call ``esp_now_register_recv_cb`` to register receiving callback function. When receiving ESP-NOW data, receiving callback function
|
||||
is called. The receiving callback function also runs from WiFi task. So, do not do lengthy operations in the callback function.
|
||||
Instead, post necessary data to a queue and handle it from a lower priority task.
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/esp_now.inc
|
||||
@@ -0,0 +1,7 @@
|
||||
Smart Config
|
||||
============
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/esp_smartconfig.inc
|
||||
@@ -0,0 +1,33 @@
|
||||
Wi-Fi
|
||||
=====
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
The WiFi libraries provide support for configuring and monitoring the ESP32 WiFi networking functionality. This includes configuration for:
|
||||
|
||||
- Station mode (aka STA mode or WiFi client mode). ESP32 connects to an access point.
|
||||
- AP mode (aka Soft-AP mode or Access Point mode). Stations connect to the ESP32.
|
||||
- Combined AP-STA mode (ESP32 is concurrently an access point and a station connected to another access point).
|
||||
|
||||
- Various security modes for the above (WPA, WPA2, WEP, etc.)
|
||||
- Scanning for access points (active & passive scanning).
|
||||
- Promiscuous mode monitoring of IEEE802.11 WiFi packets.
|
||||
|
||||
Application Examples
|
||||
--------------------
|
||||
|
||||
See :example:`wifi` directory of ESP-IDF examples that contains the following applications:
|
||||
|
||||
* Simple application showing how to connect ESP32 module to an Access Point - `esp-idf-template <https://github.com/espressif/esp-idf-template>`_.
|
||||
|
||||
* Using power save mode of Wi-Fi - :example:`wifi/power_save`.
|
||||
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/esp_wifi.inc
|
||||
.. include:: /_build/inc/esp_wifi_types.inc
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
Wi-Fi API
|
||||
*********
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
Wi-Fi <esp_wifi>
|
||||
Smart Config <esp_smartconfig>
|
||||
ESPNOW <esp_now>
|
||||
|
||||
|
||||
Example code for this API section is provided in :example:`wifi` directory of ESP-IDF examples.
|
||||
Reference in New Issue
Block a user