ESP-IDF Programming Guide

This is the documentation for Espressif IoT Developement Framework (esp-idf). ESP-IDF is the official development framework for the ESP32 chip.

Contents:

Set up of Toolchain for Windows

Step 1: Quick Steps

Windows doesn’t have a built-in “make” environment, so as well as installing the toolchain you will need a GNU-compatible environment. We use the MSYS2 environment to provide.
You don’t need to use this environment all the time (you can use Eclipse or some other front-end), but it runs behind the scenes.

The quick setup is to download the Windows all-in-one toolchain & MSYS zip file from dl.espressif.com:

https://dl.espressif.com/dl/esp32_win32_msys2_environment_and_toolchain-20170111.zip

Unzip the zip file to C:and it will create an “msys32” directory with a pre-prepared environment.

Alternative Step 1: Configure toolchain & environment from scratch

As an alternative to getting a pre-prepared environment, you can set up the environment from scratch:

  • Navigate to the MSYS2 installer page and download the msys2-i686-xxxxxxx.exe installer executable (we only support a 32-bit MSYS environment, it works on both 32-bit and 64-bit Windows.)
  • Run through the installer steps, and accept the “Run MSYS2 now” option at the end. A window will open with a MSYS2 terminal.
  • The ESP-IDF repository on github contains a script in the tools directory titled windows_install_prerequisites.sh. If you haven’t downloaded the ESP-IDF yet, that’s OK - you can just download that one file in Raw format from here. Save it somewhere on your computer.
  • Type the path to the shell script into the MSYS2 terminal window. You can type it as a normal Windows path, but use forward-slashes instead of back-slashes. ie: C:/Users/myuser/Downloads/windows_install_prerequisites.sh. You can read the script beforehand to check what it does.
  • If you use the 201602 MSYS2 installer, the first time you run windows_install_prerequisites.sh it will update the MSYS2 core system. At the end of this update, you will be prompted to close the MSYS2 terminal and re-open. When you re-open after the update, re-run windows_install_prerequisites.sh. The next version of MSYS2 (after 201602) will not need this interim step.
  • The windows_install_prerequisites.sh script will download and install packages for ESP-IDF support, and the ESP32 toolchain.

Note: You may encounter a bug where svchost.exe uses 100% CPU in Windows after setup is finished, resulting in the ESP-IDF building very slowly. Terminating svchost.exe or restarting Windows will solve this problem.

Another Alternative Step 1: Just download a toolchain

If you already have an MSYS2 install or want to do things differently, you can download just the toolchain here:

https://dl.espressif.com/dl/xtensa-esp32-elf-win32-1.22.0-61-gab8375a-5.2.0.zip

If you followed one of the above options for Step 1, you won’t need this download.

Important: Just having this toolchain is not enough to use ESP-IDF on Windows. You will need GNU make, bash, and sed at minimum. The above environments provide all this, plus a host compiler (required for menuconfig support).

Step 2: Getting the esp-idf repository from github

Open an MSYS2 terminal window by running C:\msys32\msys2_shell.cmd. The environment in this window is a bash shell.

Change to the directory you want to clone the SDK into by typing a command like this one: cd "C:/path/to/dir" (note the forward-slashes in the path). Then type git clone --recursive https://github.com/espressif/esp-idf.git

If you’d rather use a Windows UI tool to manage your git repositories, this is also possible. A wide range are available.

NOTE: While cloning submodules, the git clone command may print some output starting ': not a valid identifier.... This is a known issue but the git clone still succeeds without any problems.

Step 3: Starting a project

ESP-IDF by itself does not build a binary to run on the ESP32. The binary “app” comes from a project in a different directory. Multiple projects can share the same ESP-IDF directory on your computer.

The easiest way to start a project is to download the Getting Started project from github.

The process is the same as for checking out the ESP-IDF from github. Change to the parent directory and run git clone https://github.com/espressif/esp-idf-template.git.

IMPORTANT: The esp-idf build system does not support spaces in paths to esp-idf or to projects.

Step 4: Configuring the project

Open an MSYS2 terminal window by running C:\msys32\msys2_shell.cmd. The environment in this window is a bash shell.

Type a command like this to set the path to ESP-IDF directory: export IDF_PATH="C:/path/to/esp-idf" (note the forward-slashes not back-slashes for the path). If you don’t want to run this command every time you open an MSYS2 window, create a new file in C:/msys32/etc/profile.d/ and paste this line in - then it will be run each time you open an MYS2 terminal.

Use cd to change to the project directory (not the ESP-IDF directory.) Type make menuconfig to configure your project, then make to build it, make clean to remove built files, and make flash to flash (use the menuconfig to set the serial port for flashing.)

If you’d like to use the Eclipse IDE instead of running make, check out the Eclipse setup guide in this directory.

Set up of Toolchain for Linux

Step 0: Prerequisites

Install some packages

To compile with ESP-IDF you need to get the following packages:

  • Ubuntu and Debian:

    sudo apt-get install git wget make libncurses-dev flex bison gperf python python-serial
    
  • Arch:

    sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial
    

Step 1: Download binary toolchain for the ESP32

ESP32 toolchain for Linux is available for download from Espressif website:

  • for 64-bit Linux:

    https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-1.22.0-61-gab8375a-5.2.0.tar.gz
    
  • for 32-bit Linux:

    https://dl.espressif.com/dl/xtensa-esp32-elf-linux32-1.22.0-61-gab8375a-5.2.0.tar.gz
    

Download this file, then extract it to the location you prefer, for example:

mkdir -p ~/esp
cd ~/esp
tar -xzf ~/Downloads/xtensa-esp32-elf-linux64-1.22.0-61-gab8375a-5.2.0.tar.gz

The toolchain will be extracted into ~/esp/xtensa-esp32-elf/ directory.

To use it, you will need to update your PATH environment variable in ~/.bash_profile file. To make xtensa-esp32-elf available for all terminal sessions, add the following line to your ~/.bash_profile file:

export PATH=$PATH:$HOME/esp/xtensa-esp32-elf/bin

Alternatively, you may create an alias for the above command. This way you can get the toolchain only when you need it. To do this, add different line to your ~/.bash_profile file:

alias get_esp32="export PATH=$PATH:$HOME/esp/xtensa-esp32-elf/bin"

Then when you need the toolchain you can type get_esp32 on the command line and the toolchain will be added to your PATH.

Arch Linux Users

To run the precompiled gdb (xtensa-esp32-elf-gdb) in Arch Linux requires ncurses 5, but Arch uses ncurses 6. Backwards compatibility libraries are available in AUR for native and lib32 configurations: - https://aur.archlinux.org/packages/ncurses5-compat-libs/ - https://aur.archlinux.org/packages/lib32-ncurses5-compat-libs/

(Alternatively, use crosstool-NG to compile a gdb that links against ncurses 6.)

Alternative Step 1: Compile the toolchain from source using crosstool-NG

Instead of downloading binary toolchain from Espressif website (Step 1 above) you may build the toolchain yourself.

If you can’t think of a reason why you need to build it yourself, then probably it’s better to stick with the binary version. However, here are some of the reasons why you might want to compile it from source:

  • if you want to customize toolchain build configuration
  • if you want to use a different GCC version (such as 4.8.5)
  • if you want to hack gcc or newlib or libstdc++
  • if you are curious and/or have time to spare
  • if you don’t trust binaries downloaded from the Internet

In any case, here are the steps to compile the toolchain yourself.

  • Install dependencies:

    • Ubuntu:

      sudo apt-get install gawk gperf grep gettext libncurses-dev python python-dev automake bison flex texinfo help2man libtool
      
    • Debian:

      TODO
      
    • Arch:

      TODO
      

Download crosstool-NG and build it:

cd ~/esp
git clone -b xtensa-1.22.x https://github.com/espressif/crosstool-NG.git
cd crosstool-NG
./bootstrap && ./configure --prefix=$PWD && make install

Build the toolchain:

./ct-ng xtensa-esp32-elf
./ct-ng build
chmod -R u+w builds/xtensa-esp32-elf

Toolchain will be built in ~/esp/crosstool-NG/builds/xtensa-esp32-elf. Follow instructions given in the previous section to add the toolchain to your PATH.

Step 2: Getting ESP-IDF from github

Open terminal, navigate to the directory you want to clone ESP-IDF and clone it using git clone command:

cd ~/esp
git clone --recursive https://github.com/espressif/esp-idf.git

ESP-IDF will be downloaded into ~/esp/esp-idf.

Note the --recursive option! If you have already cloned ESP-IDF without this option, run another command to get all the submodules:

cd ~/esp/esp-idf
git submodule update --init

IMPORTANT: The esp-idf build system does not support spaces in paths to esp-idf or to projects.

Step 3: Starting a project

ESP-IDF by itself does not build a binary to run on the ESP32. The binary “app” comes from a project in a different directory. Multiple projects can share the same ESP-IDF directory.

The easiest way to start a project is to download the template project from GitHub:

cd ~/esp
git clone https://github.com/espressif/esp-idf-template.git myapp

This will download esp-idf-template project into ~/esp/myapp directory.

Step 4: Building and flashing the application

In terminal, go to the application directory which was obtained on the previous step:

cd ~/esp/myapp

Type a command like this to set the path to ESP-IDF directory:

export IDF_PATH=~/esp/esp-idf

At this point you may configure the serial port to be used for uploading. Run:

make menuconfig

Then navigate to “Serial flasher config” submenu and change value of “Default serial port” to match the serial port you will use. Also take a moment to explore other options which are configurable in menuconfig.

Special note for Arch Linux users: navigate to “SDK tool configuration” and change the name of “Python 2 interpreter” from python to python2.

Now you can build and flash the application. Run:

make flash

This will compile the application and all the ESP-IDF components, generate bootloader, partition table, and application binaries, and flash these binaries to your development board.

Further reading

If you’d like to use the Eclipse IDE instead of running make, check out the Eclipse setup guide in this directory.

Set up of Toolchain for Mac OS

Step 0: Prerequisites

  • install pip:

    sudo easy_install pip
    
  • install pyserial

    sudo pip install pyserial

Step 1: Download binary toolchain for the ESP32

ESP32 toolchain for macOS is available for download from Espressif website:

https://dl.espressif.com/dl/xtensa-esp32-elf-osx-1.22.0-61-gab8375a-5.2.0.tar.gz

Download this file, then extract it to the location you prefer, for example:

mkdir -p ~/esp
cd ~/esp
tar -xzf ~/Downloads/xtensa-esp32-elf-osx-1.22.0-61-gab8375a-5.2.0.tar.gz

The toolchain will be extracted into ~/esp/xtensa-esp32-elf/ directory.

To use it, you will need to update your PATH environment variable in ~/.profile file. To make xtensa-esp32-elf available for all terminal sessions, add the following line to your ~/.profile file:

export PATH=$PATH:$HOME/esp/xtensa-esp32-elf/bin

Alternatively, you may create an alias for the above command. This way you can get the toolchain only when you need it. To do this, add different line to your ~/.profile file:

alias get_esp32="export PATH=$PATH:$HOME/esp/xtensa-esp32-elf/bin"

Then when you need the toolchain you can type get_esp32 on the command line and the toolchain will be added to your PATH.

Alternative Step 1: Compile the toolchain from source using crosstool-NG

Instead of downloading binary toolchain from Espressif website (Step 1 above) you may build the toolchain yourself.

If you can’t think of a reason why you need to build it yourself, then probably it’s better to stick with the binary version. However, here are some of the reasons why you might want to compile it from source:

  • if you want to customize toolchain build configuration
  • if you want to use a different GCC version (such as 4.8.5)
  • if you want to hack gcc or newlib or libstdc++
  • if you are curious and/or have time to spare
  • if you don’t trust binaries downloaded from the Internet

In any case, here are the steps to compile the toolchain yourself.

  • Install dependencies:

    • Install either MacPorts or homebrew package manager. MacPorts needs a full XCode installation, while homebrew only needs XCode command line tools.

    • with MacPorts:

      sudo port install gsed gawk binutils gperf grep gettext wget libtool autoconf automake
      
    • with homebrew:

      brew install gnu-sed gawk binutils gperftools gettext wget help2man libtool autoconf automake
      

Create a case-sensitive filesystem image:

hdiutil create ~/esp/crosstool.dmg -volname "ctng" -size 10g -fs "Case-sensitive HFS+"

Mount it:

hdiutil mount ~/esp/crosstool.dmg

Create a symlink to your work directory:

cd ~/esp
ln -s /Volumes/ctng crosstool-NG

Download crosstool-NG and build it:

cd ~/esp
git clone -b xtensa-1.22.x https://github.com/espressif/crosstool-NG.git
cd crosstool-NG
./bootstrap && ./configure --prefix=$PWD && make install

Build the toolchain:

./ct-ng xtensa-esp32-elf
./ct-ng build
chmod -R u+w builds/xtensa-esp32-elf

Toolchain will be built in ~/esp/crosstool-NG/builds/xtensa-esp32-elf. Follow instructions given in the previous section to add the toolchain to your PATH.

Step 2: Getting ESP-IDF from github

Open Terminal.app, navigate to the directory you want to clone ESP-IDF and clone it using git clone command:

cd ~/esp
git clone --recursive https://github.com/espressif/esp-idf.git

ESP-IDF will be downloaded into ~/esp/esp-idf.

Note the --recursive option! If you have already cloned ESP-IDF without this option, run another command to get all the submodules:

cd ~/esp/esp-idf
git submodule update --init

Step 3: Starting a project

ESP-IDF by itself does not build a binary to run on the ESP32. The binary “app” comes from a project in a different directory. Multiple projects can share the same ESP-IDF directory.

The easiest way to start a project is to download the template project from GitHub:

cd ~/esp
git clone https://github.com/espressif/esp-idf-template.git myapp

This will download esp-idf-template project into ~/esp/myapp directory.

IMPORTANT: The esp-idf build system does not support spaces in paths to esp-idf or to projects.

Step 4: Building and flashing the application

In Terminal.app, go to the application directory which was obtained on the previous step:

cd ~/esp/myapp

Type a command like this to set the path to ESP-IDF directory:

export IDF_PATH=~/esp/esp-idf

At this point you may configure the serial port to be used for uploading. Run:

make menuconfig

Then navigate to “Serial flasher config” submenu and change value of “Default serial port” to match the serial port you will use. Also take a moment to explore other options which are configurable in menuconfig.

If you don’t know device name for the serial port of your development board, run this command two times, first with the board unplugged, then with the board plugged in. The port which appears the second time is the one you need:

ls /dev/tty.*

Now you can build and flash the application. Run:

make flash

This will compile the application and all the ESP-IDF components, generate bootloader, partition table, and application binaries, and flash these binaries to your development board.

Further reading

If you’d like to use the Eclipse IDE instead of running make, check out the Eclipse setup guide in this directory.

Build and Flash with Make

Finding a project

As well as the esp-idf-template project mentioned in the setup guide, esp-idf comes with some example projects on github in the examples directory.

Once you’ve found the project you want to work with, change to its directory and you can configure and build it:

Configuring your project

make menuconfig

Compiling your project

make all

... will compile app, bootloader and generate a partition table based on the config.

Flashing your project

When make all finishes, it will print a command line to use esptool.py to flash the chip. However you can also do this from make by running:

make flash

This will flash the entire project (app, bootloader and partition table) to a new chip. The settings for serial port flashing can be configured with make menuconfig.

You don’t need to run make all before running make flash, make flash will automatically rebuild anything which needs it.

Compiling & Flashing Just the App

After the initial flash, you may just want to build and flash just your app, not the bootloader and partition table:

  • make app - build just the app.
  • make app-flash - flash just the app.

make app-flash will automatically rebuild the app if it needs it.

(There’s no downside to reflashing the bootloader and partition table each time, if they haven’t changed.)

The Partition Table

Once you’ve compiled your project, the “build” directory will contain a binary file with a name like “my_app.bin”. This is an ESP32 image binary that can be loaded by the bootloader.

A single ESP32’s flash can contain multiple apps, as well as many different kinds of data (calibration data, filesystems, parameter storage, etc). For this reason a partition table is flashed to offset 0x4000 in the flash.

Each entry in the partition table has a name (label), type (app, data, or something else), subtype and the offset in flash where the partition is loaded.

The simplest way to use the partition table is to make menuconfig and choose one of the simple predefined partition tables:

  • “Single factory app, no OTA”
  • “Factory app, two OTA definitions”

In both cases the factory app is flashed at offset 0x10000. If you make partition_table then it will print a summary of the partition table.

For more details about partition tables and how to create custom variations, view the documentation.

Build and Flash with Eclipse IDE

Installing Eclipse IDE

The Eclipse IDE gives you a graphical integrated development environment for writing, compiling and debugging ESP-IDF projects.

  • Start by installing the esp-idf for your platform (see files in this directory with steps for Windows, OS X, Linux).
  • Download the Eclipse Installer for your platform from eclipse.org.
  • When running the Eclipse Installer, choose “Eclipse for C/C++ Development” (in other places you’ll see this referred to as CDT.)

Setting up Eclipse

Once your new Eclipse installation launches, follow these steps:

Import New Project

  • Eclipse makes use of the Makefile support in ESP-IDF. This means you need to start by creating an ESP-IDF project. You can use the skeleton project from github.
  • Once Eclipse is running, choose File -> Import...
  • In the dialog that pops up, choose “C/C++” -> “Existing Code as Makefile Project” and click Next.
  • On the next page, enter “Existing Code Location” to be the directory of your IDF project. Don’t specify the path to the ESP-IDF directory itself.
  • On the same page, under “Toolchain for Indexer Settings” choose “Cross GCC”. Then click Finish.

Project Properties

  • The new project will appear under Project Explorer. Right-click the project and choose Properties from the context menu.
  • Click on the “Environment” properties page under “C/C++ Build”. Click “Add...” and enter name V and value 1.
  • Click “Add...” again, and enter name IDF_PATH. The value should be the full path where ESP-IDF is installed. Windows users: Use forward-slashes not backslashes for this path, ie C:/Users/MyUser/Development/esp-idf.

Windows users only, follow these two additional steps:

  • On the same Environment property page, edit the PATH environment variable. Delete the existing value and replace it with C:\msys32\usr\bin;C:\msys32\mingw32\bin;C:\msys32\opt\xtensa-esp32-elf\bin (If you installed msys32 to a different directory then you’ll need to change these paths to match).
  • Click on the “C/C++ Build” top-level properties page then uncheck “Use default build command” and enter this for the custom build command: bash ${IDF_PATH}/tools/windows/eclipse_make.sh.

All users, continue with these steps:

Navigate to “C/C++ General” -> “Preprocessor Include Paths” property page:

  • Click the “Providers” tab
  • In the list of providers, click “CDT Cross GCC Built-in Compiler Settings”. Under “Command to get compiler specs”, replace the text ${COMMAND} at the beginning of the line with xtensa-esp32-elf-gcc. This means the full “Command to get compiler specs” should be xtensa-esp32-elf-gcc ${FLAGS} -E -P -v -dD "${INPUTS}".
  • In the list of providers, click “CDT GCC Build Output Parser” and type xtensa-esp32-elf- at the beginning of the Compiler command pattern. This means the full Compiler command pattern should be xtensa-esp32-elf-(g?cc)|([gc]\+\+)|(clang)
  • Click OK to close the Properties dialog, and choose Project -> Build to build your project.

Flash from Eclipse

You can integrate the “make flash” target into your Eclipse project to flash using esptool.py from the Eclipse UI:

  • Right-click your project in Project Explorer (important to make sure you select the project, not a directory in the project, or Eclipse may find the wrong Makefile.)
  • Select Make Targets -> Create from the context menu.
  • Type “flash” as the target name. Leave the other options as their defaults.
  • Now you can use Project -> Make Target -> Build (Shift+F9) to build the custom flash target, which will compile and flash the project.

Note that you will need to use “make menuconfig” to set the serial port and other config options for flashing. “make menuconfig” still requires a command line terminal (see the instructions for your platform.)

Follow the same steps to add bootloader and partition_table targets, if necessary.

Eclipse Troubleshooting

  • *** Make was invoked from ... However please do not run make from the sdk or a component directory; ... - Eclipse will detect any directory with a Makefile in it as being a possible directory to run “make” in. All component directories also contain a Makefile (the wrong one), so it is important when using Project -> Make Target to always select the top-level project directory in Project Explorer.

General Notes About ESP-IDF Programming

Application startup flow

This note explains various steps which happen before app_main function of an ESP-IDF application is called.

The high level view of startup process is as follows:

  1. First-stage bootloader in ROM loads second-stage bootloader image to RAM (IRAM & DRAM) from flash offset 0x1000.
  2. Second-stage bootloader loads partition table and main app image from flash. Main app incorporates both RAM segments and read-only segments mapped via flash cache.
  3. Main app image executes. At this point the second CPU and RTOS scheduler can be started.

This process is explained in detail in the following sections.

First stage bootloader

After SoC reset, PRO CPU will start running immediately, executing reset vector code, while APP CPU will be held in reset. During startup process, PRO CPU does all the initialization. APP CPU reset is de-asserted in the call_start_cpu0 function of application startup code. Reset vector code is located at address 0x40000400 in the mask ROM of the ESP32 chip and can not be modified.

Startup code called from the reset vector determines the boot mode by checking GPIO_STRAP_REG register for bootstrap pin states. Depending on the reset reason, the following takes place:

  1. Reset from deep sleep: if the value in RTC_CNTL_STORE6_REG is non-zero, and CRC value of RTC memory in RTC_CNTL_STORE7_REG is valid, use RTC_CNTL_STORE6_REG as an entry point address and jump immediately to it. If RTC_CNTL_STORE6_REG is zero, or RTC_CNTL_STORE7_REG contains invalid CRC, or once the code called via RTC_CNTL_STORE6_REG returns, proceed with boot as if it was a power-on reset. Note: to run customized code at this point, a deep sleep stub mechanism is provided. Please see deep sleep documentation for this.
  2. For power-on reset, software SOC reset, and watchdog SOC reset: check the GPIO_STRAP_REG register if UART or SDIO download mode is requested. If this is the case, configure UART or SDIO, and wait for code to be downloaded. Otherwise, proceed with boot as if it was due to software CPU reset.
  3. For software CPU reset and watchdog CPU reset: configure SPI flash based on EFUSE values, and attempt to load the code from flash. This step is described in more detail in the next paragraphs. If loading code from flash fails, unpack BASIC interpreter into the RAM and start it. Note that RTC watchdog is still enabled when this happens, so unless any input is received by the interpreter, watchdog will reset the SOC in a few hundred milliseconds, repeating the whole process. If the interpreter receives any input from the UART, it disables the watchdog.

Application binary image is loaded from flash starting at address 0x1000. First 4kB sector of flash is used to store secure boot IV and signature of the application image. Please check secure boot documentation for details about this.

Second stage bootloader

In ESP-IDF, the binary image which resides at offset 0x1000 in flash is the second stage bootloader. Second stage bootloader source code is available in components/bootloader directory of ESP-IDF. Note that this arrangement is not the only one possible with the ESP32 chip. It is possible to write a fully featured application which would work when flashed to offset 0x1000, but this is out of scope of this document. Second stage bootloader is used in ESP-IDF to add flexibility to flash layout (using partition tables), and allow for various flows associated with flash encryption, secure boot, and over-the-air updates (OTA) to take place.

When the first stage bootloader is finished checking and loading the second stage bootloader, it jumps to the second stage bootloader entry point found in the binary image header.

Second stage bootloader reads the partition table found at offset 0x8000. See partition tables documentation for more information. The bootloader finds factory and OTA partitions, and decides which one to boot based on data found in OTA info partition.

For the selected partition, second stage bootloader copies data and code sections which are mapped into IRAM and DRAM to their load addresses. For sections which have load addresses in DROM and IROM regions, flash MMU is configured to provide the correct mapping. Note that the second stage bootloader configures flash MMU for both PRO and APP CPUs, but it only enables flash MMU for PRO CPU. Reason for this is that second stage bootloader code is loaded into the memory region used by APP CPU cache. The duty of enabling cache for APP CPU is passed on to the application. Once code is loaded and flash MMU is set up, second stage bootloader jumps to the application entry point found in the binary image header.

Currently it is not possible to add application-defined hooks to the bootloader to customize application partition selection logic. This may be required to load different application image depending on a state of a GPIO, for example. Such customization features will be added to ESP-IDF in the future. For now, bootloader can be customized by copying bootloader component into application directory and making necessary changes there. ESP-IDF build system will compile the component in application directory instead of ESP-IDF components directory in this case.

Application startup

ESP-IDF application entry point is call_start_cpu0 function found in components/esp32/cpu_start.c. Two main things this function does are to enable heap allocator and to make APP CPU jump to its entry point, call_start_cpu1. The code on PRO CPU sets the entry point for APP CPU, de-asserts APP CPU reset, and waits for a global flag to be set by the code running on APP CPU, indicating that it has started. Once this is done, PRO CPU jumps to start_cpu0 function, and APP CPU jumps to start_cpu1 function.

Both start_cpu0 and start_cpu1 are weak functions, meaning that they can be overridden in the application, if some application-specific change to initialization sequence is needed. Default implementation of start_cpu0 enables or initializes components depending on choices made in menuconfig. Please see source code of this function in components/esp32/cpu_start.c for an up to date list of steps performed. Note that any C++ global constructors present in the application will be called at this stage. Once all essential components are initialized, main task is created and FreeRTOS scheduler is started.

While PRO CPU does initialization in start_cpu0 function, APP CPU spins in start_cpu1 function, waiting for the scheduler to be started on the PRO CPU. Once the scheduler is started on the PRO CPU, code on the APP CPU starts the scheduler as well.

Main task is the task which runs app_main function. Main task stack size and priority can be configured in menuconfig. Application can use this task for initial application-specific setup, for example to launch other tasks. Application can also use main task for event loops and other general purpose activities. If app_main function returns, main task is deleted.

Application memory layout

ESP32 chip has flexible memory mapping features. This section describes how ESP-IDF uses these features by default.

Application code in ESP-IDF can be placed into one of the following memory regions.

IRAM (instruction RAM)

ESP-IDF allocates part of Internal SRAM0 region (defined in the Technical Reference Manual) for instruction RAM. Except for the first 64 kB block which is used for PRO and APP CPU caches, the rest of this memory range (i.e. from 0x40080000 to 0x400A0000) is used to store parts of application which need to run from RAM.

A few components of ESP-IDF and parts of WiFi stack are placed into this region using the linker script.

If some application code needs to be placed into IRAM, it can be done using IRAM_ATTR define:

#include "esp_attr.h"

void IRAM_ATTR gpio_isr_handler(void* arg)
{
        // ...
}

Here are the cases when parts of application may or should be placed into IRAM.

  • ISR handlers must always be placed into IRAM. Furthermore, ISR handlers may only call functions placed into IRAM or functions present in ROM. Note 1: all FreeRTOS APIs are currently placed into IRAM, so are safe to call from ISR handlers. Note 1: all constant data used by ISR handlers and functions called from ISR handlers (including, but not limited to, const char arrays), must be placed into DRAM using DRAM_ATTR.
  • Some timing critical code may be placed into IRAM to reduce the penalty associated with loading the code from flash. ESP32 reads code and data from flash via a 32 kB cache. In some cases, placing a function into IRAM may reduce delays caused by a cache miss.

IROM (code executed from Flash)

If a function is not explicitly placed into IRAM or RTC memory, it is placed into flash. The mechanism by which Flash MMU is used to allow code execution from flash is described in the Technical Reference Manual. ESP-IDF places the code which should be executed from flash starting from the beginning of 0x400D0000 0x40400000 region. Upon startup, second stage bootloader initializes Flash MMU to map the location in flash where code is located into the beginning of this region. Access to this region is transparently cached using two 32kB blocks in 0x400700000x40080000 range.

Note that the code outside 0x40000000 0x40400000 region may not be reachable with Window ABI CALLx instructions, so special care is required if 0x40400000 0x40800000 or 0x40800000 0x40C00000 regions are used by the application. ESP-IDF doesn’t use these regions by default.

RTC fast memory

The code which has to run after wake-up from deep sleep mode has to be placed into RTC memory. Please check detailed description in deep sleep documentation.

DRAM (data RAM)

Non-constant static data and zero-initialized data is placed by the linker into 200 kB 0x3FFB0000 — 0x3FFF0000 region. Note that this region is reduced by 64kB (by shifting start address to 0x3FFC0000) if Bluetooth stack is used. Length of this region is also reduced by 16 kB or 32kB if trace memory is used. All space which is left in this region after placing static data there is used for the runtime heap.

Constant data may also be placed into DRAM, for example if it is used in an ISR handler (see notes in IRAM section above). To do that, DRAM_ATTR define can be used:

DRAM_ATTR const char[] format_string = "%p %x";
char buffer[64];
sprintf(buffer, format_string, ptr, val);

Needless to say, it is not advised to use printf and other output functions in ISR handlers. For debugging purposes, use ESP_EARLY_LOGx macros when logging from ISR handlers. Make sure that both TAG and format string are placed into DRAM in that case.

DROM (data stored in Flash)

By default, constant data is placed by the linker into a 4 MB region (0x3F400000 — 0x3F800000) which is used to access external flash memory via Flash MMU and cache. Exceptions to this are literal constants which are embedded by the compiler into application code.

RTC slow memory

Global and static variables used by code which runs from RTC memory (i.e. deep sleep stub code) must be placed into RTC slow memory. Please check detailed description in deep sleep documentation.

Partition Tables

Overview

A single ESP32’s flash can contain multiple apps, as well as many different kinds of data (calibration data, filesystems, parameter storage, etc). For this reason a partition table is flashed to offset 0x8000 in the flash.

Partition table length is 0xC00 bytes (maximum 95 partition table entries). If the partition table is signed due to secure boot, the signature is appended after the table data.

Each entry in the partition table has a name (label), type (app, data, or something else), subtype and the offset in flash where the partition is loaded.

The simplest way to use the partition table is to make menuconfig and choose one of the simple predefined partition tables:

  • “Single factory app, no OTA”
  • “Factory app, two OTA definitions”

In both cases the factory app is flashed at offset 0x10000. If you make partition_table then it will print a summary of the partition table.

Built-in Partition Tables

Here is the summary printed for the “Single factory app, no OTA” configuration:

# Espressif ESP32 Partition Table
# Name,   Type, SubType, Offset,  Size
nvs,      data, nvs,     0x9000,  0x6000
phy_init, data, phy,     0xf000,  0x1000
factory,  app,  factory, 0x10000, 1M
  • At a 0x10000 (64KB) offset in the flash is the app labelled “factory”. The bootloader will run this app by default.
  • There are also two data regions defined in the partition table for storing NVS library partition and PHY init data.

Here is the summary printed for the “Factory app, two OTA definitions” configuration:

# Espressif ESP32 Partition Table
# Name,   Type, SubType, Offset,  Size
nvs,      data, nvs,     0x9000,  0x4000
otadata,  data, ota,     0xd000,  0x2000
phy_init, data, phy,     0xf000,  0x1000
factory,  0,    0,       0x10000, 1M
ota_0,    0,    ota_0,   ,        1M
ota_1,    0,    ota_1,   ,        1M
  • There are now three app partition definitions.
  • The type of all three are set as “app”, but the subtype varies between the factory app at 0x10000 and the next two “OTA” apps.
  • There is also a new “ota data” slot, which holds the data for OTA updates. The bootloader consults this data in order to know which app to execute. If “ota data” is empty, it will execute the factory app.

Creating Custom Tables

If you choose “Custom partition table CSV” in menuconfig then you can also enter the name of a CSV file (in the project directory) to use for your partition table. The CSV file can describe any number of definitions for the table you need.

The CSV format is the same format as printed in the summaries shown above. However, not all fields are required in the CSV. For example, here is the “input” CSV for the OTA partition table:

# Name,   Type, SubType, Offset,   Size
nvs,      data, nvs,     0x9000,  0x4000
otadata,  data, ota,     0xd000,  0x2000
phy_init, data, phy,     0xf000,  0x1000
factory,  app,  factory, 0x10000,  1M
ota_0,    app,  ota_0,   ,         1M
ota_1,    app,  ota_1,   ,         1M
  • Whitespace between fields is ignored, and so is any line starting with # (comments).
  • Each non-comment line in the CSV file is a partition definition.
  • Only the offset for the first partition is supplied. The gen_esp32part.py tool fills in each remaining offset to start after the preceding partition.

Name field

Name field can be any meaningful name. It is not significant to the ESP32. Names longer than 16 characters will be truncated.

Type field

Type field can be specified as app (0) or data (1). Or it can be a number 0-254 (or as hex 0x00-0xFE). Types 0x00-0x3F are reserved for Espressif. If your application needs to store data, please add a custom partition type in the range 0x40-0xFE.

The bootloader ignores any types other than 0 & 1.

Subtype

When type is “app”, the subtype field can be specified as factory (0), ota_0 (0x10) ... ota_15 (0x1F) and test (0x20). Or it can be any number 0-255 (0x00-0xFF). The bootloader will execute the factory app unless there it sees a partition of type data/ota, in which case it reads this partition to determine which OTA image to boot

When type is “data”, the subtype field can be specified as ota (0), phy (1), nvs (2). Or it can be a number 0x00-0xFF. The bootloader ignores all data subtypes except for ota. Subtypes 0-0x7f are reserved for Espressif use. To create custom data partition subtypes use “data” type, and choose any unused subtype in 0x80-0xFF range. If you are porting a filesystem to the ESP-IDF, consider opening a PR to add the new subtype to esp_partition.h file.

Offset & Size

Only the first offset field is required (we recommend using 0x10000). Partitions with blank offsets will start after the previous partition.

App partitions have to be at offsets aligned to 0x10000 (64K). If you leave the offset field blank, the tool will automatically align the partition. If you specify an unaligned offset for an app partition, the tool will return an error.

Sizes and offsets can be specified as decimal numbers, hex numbers with the prefix 0x, or size multipliers M or K (1024 and 1024*1024 bytes).

NVS data partition has to be at least 0x3000 bytes long, and OTA data parition has to be 0x2000 bytes long. If you are using NVS in your application to store a lot of data, consider using a custom partition table with larger NVS partition.

Generating Binary Partition Table

The partition table which is flashed to the ESP32 is in a binary format, not CSV. The tool bin/gen_esp32part.py is used to convert between CSV and binary formats.

If you configure the partition table CSV name in make menuconfig and then make partition_table, this conversion is done for you.

To convert CSV to Binary manually:

python bin/gen_esp32part.py --verify input_partitions.csv binary_partitions.bin

To convert binary format back to CSV:

python bin/gen_esp32part.py --verify binary_partitions.bin input_partitions.csv

To display the contents of a binary partition table on stdout (this is how the summaries displayed when running make partition_table are generated:

python bin/gen_esp32part.py binary_partitions.bin

gen_esp32part.py takes one optional argument, --verify, which will also verify the partition table during conversion (checking for overlapping partitions, unaligned partitions, etc.)

Flashing the partition table

  • make partition_table-flash: will flash the partition table with esptool.py.
  • make flash: Will flash everything including the partition table.

A manual flashing command is also printed as part of make partition_table.

Note that updating the partition table doesn’t erase data that may have been stored according to the old partition table. You can use make erase_flash (or esptool.py erase_flash) to erase the entire flash contents.

Build System

This document explains the Espressif IoT Development Framework build system and the concept of “components”

Read this document if you want to know how to organise a new ESP-IDF project.

We recommend using the esp-idf-template project as a starting point for your project.

Using the Build System

The esp-idf README file contains a description of how to use the build system to build your project.

Overview

An ESP-IDF project can be seen as an amalgamation of a number of components. For example, for a webserver that shows the current humidity, there could be:

  • The ESP32 base libraries (libc, rom bindings etc)
  • The WiFi drivers
  • A TCP/IP stack
  • The FreeRTOS operating system
  • A webserver
  • A driver for the humidity sensor
  • Main code tying it all together

ESP-IDF makes these components explicit and configurable. To do that, when a project is compiled, the build environment will look up all the components in the ESP-IDF directories, the project directories and (optionally) in additional custom component directories. It then allows the user to configure the ESP-IDF project using a a text-based menu system to customize each component. After the components in the project are configured, the build process will compile the project.

Concepts

  • A “project” is a directory that contains all the files and configuration to build a single “app” (executable), as well as additional supporting output such as a partition table, data/filesystem partitions, and a bootloader.
  • “Project configuration” is held in a single file called sdkconfig in the root directory of the project. This configuration file is modified via make menuconfig to customise the configuration of the project. A single project contains exactly one project configuration.
  • An “app” is an executable which is built by esp-idf. A single project will usually build two apps - a “project app” (the main executable, ie your custom firmware) and a “bootloader app” (the initial bootloader program which launches the project app).
  • “components” are modular pieces of standalone code which are compiled into static libraries (.a files) and linked into an app. Some are provided by esp-idf itself, others may be sourced from other places.

Some things are not part of the project:

  • “ESP-IDF” is not part of the project. Instead it is standalone, and linked to the project via the IDF_PATH environment variable which holds the path of the esp-idf directory. This allows the IDF framework to be decoupled from your project.
  • The toolchain for compilation is not part of the project. The toolchain should be installed in the system command line PATH, or the path to the toolchain can be set as part of the compiler prefix in the project configuration.

Example Project

An example project directory tree might look like this:

- myProject/
             - Makefile
             - sdkconfig
             - components/ - component1/ - component.mk
                                         - Kconfig
                                         - src1.c
                           - component2/ - component.mk
                                         - Kconfig
                                         - src1.c
                                         - include/ - component2.h
             - main/       - src1.c
                           - src2.c
                           - component.mk

             - build/

This example “myProject” contains the following elements:

  • A top-level project Makefile. This Makefile set the PROJECT_NAME variable and (optionally) defines other project-wide make variables. It includes the core $(IDF_PATH)/make/project.mk makefile which implements the rest of the ESP-IDF build system.
  • “sdkconfig” project configuration file. This file is created/updated when “make menuconfig” runs, and holds configuration for all of the components in the project (including esp-idf itself). The “sdkconfig” file may or may not be added to the source control system of the project.
  • Optional “components” directory contains components that are part of the project. A project does not have to contain custom components of this kind, but it can be useful for structuring reusable code or including third party components that aren’t part of ESP-IDF.
  • “main” directory is a special “pseudo-component” that contains source code for the project itself. “main” is a default name, the Makefile variable SRCDIRS defaults to this but can be set to look for pseudo-components in other directories.
  • “build” directory is where build output is created. After the make process is run, this directory will contain interim object files and libraries as well as final binary output files. This directory is usually not added to source control or distributed with the project source code.

Component directories contain a component makefile - component.mk. This may contain variable definitions to control the build process of the component, and its integration into the overall project. See Component Makefiles for more details.

Each component may also include a Kconfig file defining the component configuration options that can be set via the project configuration. Some components may also include Kconfig.projbuild and Makefile.projbuild files, which are special files for overriding parts of the project.

Project Makefiles

Each project has a single Makefile that contains build settings for the entire project. By default, the project Makefile can be quite minimal.

Minimal Example Makefile
PROJECT_NAME := myProject

include $(IDF_PATH)/make/project.mk
Mandatory Project Variables
  • PROJECT_NAME: Name of the project. Binary output files will use this name - ie myProject.bin, myProject.elf.
Optional Project Variables

These variables all have default values that can be overridden for custom behaviour. Look in make/project.mk for all of the implementation details.

  • PROJECT_PATH: Top-level project directory. Defaults to the directory containing the Makefile. Many other project variables are based on this variable. The project path cannot contain spaces.
  • BUILD_DIR_BASE: The build directory for all objects/libraries/binaries. Defaults to $(PROJECT_PATH)/build.
  • COMPONENT_DIRS: Directories to search for components. Defaults to $(IDF_PATH)/components, $(PROJECT_PATH)/components and EXTRA_COMPONENT_DIRS. Override this variable if you don’t want to search for components in the esp-idf & project components directories.
  • EXTRA_COMPONENT_DIRS: Optional list of additional directories to search for components. Components themselves are in sub-directories of these directories, this is a top-level directory containing the component directories.
  • COMPONENTS: A list of component names to build into the project. Defaults to all components found in the COMPONENT_DIRS directories.
  • SRCDIRS: Directories under the main project directory which contain project-specific “pseudo-components”. Defaults to ‘main’. The difference between specifying a directory here and specifying it under EXTRA_COMPONENT_DIRS is that a directory in SRCDIRS is a component itself (contains a file “component.mk”), whereas a directory in EXTRA_COMPONENT_DIRS contains component directories which contain a file “component.mk”. See the Example Project for a concrete case of this.

Component Makefiles

Each project contains one or more components, which can either be part of esp-idf or added from other component directories.

A component is any sub-directory that contains a component.mk file.[#f1]_.

Minimal Component Makefile

The minimal component.mk file is an empty file(!). If the file is empty, the default component behaviour is set:

  • All source files in the same directory as the makefile (*.c, *.cpp, *.S) will be compiled into the component library
  • A sub-directory “include” will be added to the global include search path for all other components.
  • The component library will be linked into the project app.

See example component makefiles for more complete component makefile examples.

Note that there is a different between an empty component.mk file (which invokes default component build behaviour) and no component.mk file (which means no default component build behaviour will occur.) It is possible for a component to have no component.mk file, if it only contains other files which influence the project configuration or build process.

Preset Component Variables

The following component-specific variables are available for use inside component.mk, but should not be modified:

  • COMPONENT_PATH: The component directory. Evaluates to the absolute path of the directory containing component.mk. The component path cannot contain spaces.
  • COMPONENT_NAME: Name of the component. Defaults to the name of the component directory.
  • COMPONENT_BUILD_DIR: The component build directory. Evaluates to the absolute path of a directory inside $(BUILD_DIR_BASE) where this component’s source files are to be built. This is also the Current Working Directory any time the component is being built, so relative paths in make targets, etc. will be relative to this directory.
  • COMPONENT_LIBRARY: Name of the static library file (relative to the component build directory) that will be built for this component. Defaults to $(COMPONENT_NAME).a.

The following variables are set at the project level, but exported for use in the component build:

  • PROJECT_NAME: Name of the project, as set in project Makefile
  • PROJECT_PATH: Absolute path of the project directory containing the project Makefile.
  • COMPONENTS: Name of all components that are included in this build.
  • CONFIG_*: Each value in the project configuration has a corresponding variable available in make. All names begin with CONFIG_.
  • CC, LD, AR, OBJCOPY: Full paths to each tool from the gcc xtensa cross-toolchain.
  • HOSTCC, HOSTLD, HOSTAR: Full names of each tool from the host native toolchain.
  • IDF_VER: Git version of ESP-IDF (produced by git describe)

If you modify any of these variables inside component.mk then this will not prevent other components from building but it may make your component hard to build and/or debug.

Optional Project-Wide Component Variables

The following variables can be set inside component.mk to control build settings across the entire project:

  • COMPONENT_ADD_INCLUDEDIRS: Paths, relative to the component directory, which will be added to the include search path for all components in the project. Defaults to include if not overridden. If an include directory is only needed to compile this specific component, add it to COMPONENT_PRIV_INCLUDEDIRS instead.
  • COMPONENT_ADD_LDFLAGS: Add linker arguments to the LDFLAGS for the app executable. Defaults to -l$(COMPONENT_NAME). If adding pre-compiled libraries to this directory, add them as absolute paths - ie $(COMPONENT_PATH)/libwhatever.a
  • COMPONENT_DEPENDS: Optional list of component names that should be compiled before this component. This is not necessary for link-time dependencies, because all component include directories are available at all times. It is necessary if one component generates an include file which you then want to include in another component. Most components do not need to set this variable.
  • COMPONENT_ADD_LINKER_DEPS: Optional list of component-relative paths to files which should trigger a re-link of the ELF file if they change. Typically used for linker script files and binary libraries. Most components do not need to set this variable.

The following variable only works for components that are part of esp-idf itself:

  • COMPONENT_SUBMODULES: Optional list of git submodule paths (relative to COMPONENT_PATH) used by the component. These will be checked (and initialised if necessary) by the build process. This variable is ignored if the component is outside the IDF_PATH directory.
Optional Component-Specific Variables

The following variables can be set inside component.mk to control the build of that component:

  • COMPONENT_PRIV_INCLUDEDIRS: Directory paths, must be relative to the component directory, which will be added to the include search path for this component’s source files only.
  • COMPONENT_EXTRA_INCLUDES: Any extra include paths used when compiling the component’s source files. These will be prefixed with ‘-I’ and passed as-is to the compiler. Similar to the COMPONENT_PRIV_INCLUDEDIRS variable, except these paths are not expanded relative to the component directory.
  • COMPONENT_SRCDIRS: Directory paths, must be relative to the component directory, which will be searched for source files (*.cpp, *.c, *.S). Defaults to ‘.’, ie the component directory itself. Override this to specify a different list of directories which contain source files.
  • COMPONENT_OBJS: Object files to compile. Default value is a .o file for each source file that is found in COMPONENT_SRCDIRS. Overriding this list allows you to exclude source files in COMPONENT_SRCDIRS that would otherwise be compiled. See Specifying source files
  • COMPONENT_EXTRA_CLEAN: Paths, relative to the component build directory, of any files that are generated using custom make rules in the component.mk file and which need to be removed as part of make clean. See Source Code Generation for an example.
  • COMPONENT_OWNBUILDTARGET & COMPONENT_OWNCLEANTARGET: These targets allow you to fully override the default build behaviour for the component. See Fully Overriding The Component Makefile for more details.
  • CFLAGS: Flags passed to the C compiler. A default set of CFLAGS is defined based on project settings. Component-specific additions can be made via CFLAGS +=. It is also possible (although not recommended) to override this variable completely for a component.
  • CPPFLAGS: Flags passed to the C preprocessor (used for .c, .cpp and .S files). A default set of CPPFLAGS is defined based on project settings. Component-specific additions can be made via CPPFLAGS +=. It is also possible (although not recommended) to override this variable completely for a component.
  • CXXFLAGS: Flags passed to the C++ compiler. A default set of CXXFLAGS is defined based on project settings. Component-specific additions can be made via CXXFLAGS +=. It is also possible (although not recommended) to override this variable completely for a component.

To apply compilation flags to a single source file, you can add a variable override as a target, ie:

apps/dhcpserver.o: CFLAGS += -Wno-unused-variable

This can be useful if there is upstream code that emits warnings.

Component Configuration

Each component can also have a Kconfig file, alongside component.mk. This contains contains configuration settings to add to the “make menuconfig” for this component.

These settings are found under the “Component Settings” menu when menuconfig is run.

To create a component KConfig file, it is easiest to start with one of the KConfig files distributed with esp-idf.

For an example, see Adding conditional configuration.

Preprocessor Definitions

ESP-IDF build systems adds the following C preprocessor definitions on the command line:

  • ESP_PLATFORM — Can be used to detect that build happens within ESP-IDF.
  • IDF_VER — Defined to a git version string. E.g. v2.0 for a tagged release or v1.0-275-g0efaa4f for an arbitrary commit.

Build Process Internals

Top Level: Project Makefile
  • “make” is always run from the project directory and the project makefile, typically named Makefile.
  • The project makefile sets PROJECT_NAME and optionally customises other optional project variables
  • The project makefile includes $(IDF_PATH)/make/project.mk which contains the project-level Make logic.
  • project.mk fills in default project-level make variables and includes make variables from the project configuration. If the generated makefile containing project configuration is out of date, then it is regenerated (via targets in project_config.mk) and then the make process restarts from the top.
  • project.mk builds a list of components to build, based on the default component directories or a custom list of components set in optional project variables.
  • Each component can set some optional project-wide component variables. These are included via generated makefiles named component_project_vars.mk - there is one per component. These generated makefiles are included into project.mk. If any are missing or out of date, they are regenerated (via a recursive make call to the component makefile) and then the make process restarts from the top.
  • Makefile.projbuild files from components are included into the make process, to add extra targets or configuration.
  • By default, the project makefile also generates top-level build & clean targets for each component and sets up app and clean targets to invoke all of these sub-targets.
  • In order to compile each component, a recursive make is performed for the component makefile.

To better understand the project make process, have a read through the project.mk file itself.

Second Level: Component Makefiles
  • Each call to a component makefile goes via the $(IDF_PATH)/make/component_wrapper.mk wrapper makefile.
  • The component_wrapper.mk is called with the current directory set to the component build directory, and the COMPONENT_MAKEFILE variable is set to the absolute path to component.mk.
  • component_wrapper.mk sets default values for all component variables, then includes the component.mk file which can override or modify these.
  • If COMPONENT_OWNBUILDTARGET and COMPONENT_OWNCLEANTARGET are not defined, default build and clean targets are created for the component’s source files and the prerequisite COMPONENT_LIBRARY static library file.
  • The component_project_vars.mk file has its own target in component_wrapper.mk, which is evaluated from project.mk if this file needs to be rebuilt due to changes in the component makefile or the project configuration.

To better understand the component make process, have a read through the component_wrapper.mk file and some of the component.mk files included with esp-idf.

Debugging The Make Process

Some tips for debugging the esp-idf build system:

  • Appending V=1 to the make arguments (or setting it as an environment variable) will cause make to echo all commands executed, and also each directory as it is entered for a sub-make.
  • Running make -w will cause make to echo each directory as it is entered for a sub-make - same as V=1 but without also echoing all commands.
  • Running make --trace (possibly in addition to one of the above arguments) will print out every target as it is built, and the dependency which caused it to be built.
  • Running make -p prints a (very verbose) summary of every generated target in each makefile.

For more debugging tips and general make information, see the GNU Make Manual.

Overriding Parts of the Project

Makefile.projbuild

For components that have build requirements that must be evaluated in the top-level project make pass, you can create a file called Makefile.projbuild in the component directory. This makefile is included when project.mk is evaluated.

For example, if your component needs to add to CFLAGS for the entire project (not just for its own source files) then you can set CFLAGS += in Makefile.projbuild.

Makefile.projbuild files are used heavily inside esp-idf, for defining project-wide build features such as esptool.py command line arguments and the bootloader “special app”.

Note that Makefile.projbuild isn’t necessary for the most common component uses - such as adding include directories to the project, or LDFLAGS to the final linking step. These values can be customised via the component.mk file itself. See Optional Project-Wide Component Variables for details.

Take care when setting variables or targets in this file. As the values are included into the top-level project makefile pass, they can influence or break functionality across all components!

KConfig.projbuild

This is an equivalent to Makefile.projbuild for component configuration KConfig files. If you want to include configuration options at the top-level of menuconfig, rather than inside the “Component Configuration” sub-menu, then these can be defined in the KConfig.projbuild file alongside the component.mk file.

Take care when adding configuration values in this file, as they will be included across the entire project configuration. Where possible, it’s generally better to create a KConfig file for component configuration.

Example Component Makefiles

Because the build environment tries to set reasonable defaults that will work most of the time, component.mk can be very small or even empty (see Minimal Component Makefile). However, overriding component variables is usually required for some functionality.

Here are some more advanced examples of component.mk makefiles:

Adding source directories

By default, sub-directories are ignored. If your project has sources in sub-directories instead of in the root of the component then you can tell that to the build system by setting COMPONENT_SRCDIRS:

COMPONENT_SRCDIRS := src1 src2

This will compile all source files in the src1/ and src2/ sub-directories instead.

Specifying source files

The standard component.mk logic adds all .S and .c files in the source directories as sources to be compiled unconditionally. It is possible to circumvent that logic and hard-code the objects to be compiled by manually setting the COMPONENT_OBJS variable to the name of the objects that need to be generated:

COMPONENT_OBJS := file1.o file2.o thing/filea.o thing/fileb.o anotherthing/main.o
COMPONENT_SRCDIRS := . thing anotherthing

Note that COMPONENT_SRCDIRS must be set as well.

Adding conditional configuration

The configuration system can be used to conditionally compile some files depending on the options selected in make menuconfig:

Kconfig:

config FOO_ENABLE_BAR
    bool "Enable the BAR feature."
    help
        This enables the BAR feature of the FOO component.

component.mk:

COMPONENT_OBJS := foo_a.o foo_b.o

ifdef CONFIG_FOO_BAR
COMPONENT_OBJS += foo_bar.o foo_bar_interface.o
endif

See the GNU Make Manual for conditional syntax that can be used use in makefiles.

Source Code Generation

Some components will have a situation where a source file isn’t supplied with the component itself but has to be generated from another file. Say our component has a header file that consists of the converted binary data of a BMP file, converted using a hypothetical tool called bmp2h. The header file is then included in as C source file called graphics_lib.c:

COMPONENT_EXTRA_CLEAN := logo.h

graphics_lib.o: logo.h

logo.h: $(COMPONENT_PATH)/logo.bmp
    bmp2h -i $^ -o $@

In this example, graphics_lib.o and logo.h will be generated in the current directory (the build directory) while logo.bmp comes with the component and resides under the component path. Because logo.h is a generated file, it needs to be cleaned when make clean is called which why it is added to the COMPONENT_EXTRA_CLEAN variable.

Cosmetic Improvements

Because logo.h is a generated file, it needs to be cleaned when make clean is called which why it is added to the COMPONENT_EXTRA_CLEAN variable.

Adding logo.h to the graphics_lib.o dependencies causes it to be generated before graphics_lib.c is compiled.

If a a source file in another component included logo.h, then this component’s name would have to be added to the other component’s COMPONENT_DEPENDS list to ensure that the components were built in-order.

Embedding Binary Data

Sometimes you have a file with some binary or text data that you’d like to make available to your component - but you don’t want to reformat the file as C source.

You can set a variable COMPONENT_EMBED_FILES in component.mk, giving the names of the files to embed in this way:

COMPONENT_EMBED_FILES := server_root_cert.der

Or if the file is a string, you can use the variable COMPONENT_EMBED_TXTFILES. This will embed the contents of the text file as a null-terminated string:

COMPONENT_EMBED_TXTFILES := server_root_cert.pem

The file’s contents will be added to the .rodata section in flash, and are available via symbol names as follows:

extern const uint8_t server_root_cert_pem_start[] asm("_binary_server_root_cert_pem_start");
extern const uint8_t server_root_cert_pem_end[]   asm("_binary_server_root_cert_pem_end");

The names are generated from the full name of the file, as given in COMPONENT_EMBED_FILES. Characters /, ., etc. are replaced with underscores. The _binary prefix in the symbol name is added by objcopy and is the same for both text and binary files.

For an example of using this technique, see examples/04_https_request - the certificate file contents are loaded from the text .pem file at compile time.

Fully Overriding The Component Makefile

Obviously, there are cases where all these recipes are insufficient for a certain component, for example when the component is basically a wrapper around another third-party component not originally intended to be compiled under this build system. In that case, it’s possible to forego the esp-idf build system entirely by setting COMPONENT_OWNBUILDTARGET and possibly COMPONENT_OWNCLEANTARGET and defining your own targets named build and clean in component.mk target. The build target can do anything as long as it creates $(COMPONENT_LIBRARY) for the project make process to link into the app binary.

(Actually, even this is not strictly necessary - if the COMPONENT_ADD_LDFLAGS variable is set then the component can instruct the linker to link other binaries instead.)

Custom sdkconfig defaults

For example projects or other projects where you don’t want to specify a full sdkconfig configuration, but you do want to override some key values from the esp-idf defaults, it is possible to create a file sdkconfig.defaults in the project directory. This file will be used when running make defconfig, or creating a new config from scratch.

To override the name of this file, set the SDKCONFIG_DEFAULTS environment variable.

Debugging

OpenOCD setup for ESP32

The ESP31 and ESP32 have two powerful Xtensa cores, allowing for a great variety of program architectures. The FreeRTOS OS that comes with ESP-IDF is capable of multi-core pre-emptive multithreading, allowing for an intuitive way of writing software.

The downside of the ease of programming is that debugging without the right tools is harder: figuring out a bug that is caused by two threads, maybe even running simultaneously on two different CPU cores, can take a long time when all you have are printf statements. A better and in many cases quicker way to debug such problems is by using a debugger, connected to the processors over a debug port.

Espressif has ported OpenOCD to support the ESP32 processor and the multicore FreeRTOS that will be the foundation of most ESP32 apps, and has written some tools to help with features OpenOCD does not support natively. These are all available for free, and this document describes how to install and use them.

JTAG adapter hardware

You will need a JTAG adapter that is compatible with both the voltage levels on the ESP32 as well as with the OpenOCD software. The JTAG port on the ESP32 is an industry-standard JTAG port which lacks (and does not need) the TRST pin. The JTAG I/O pins all are powered from the VDD_3P3_RTC pin (which normally would be powered by a 3.3V rail) so the JTAG adapter needs to be able to work with JTAG pins in that voltage range. On the software side, OpenOCD supports a fair amount of JTAG adapters. See http://openocd.org/doc/html/Debug-Adapter-Hardware.html for an (unfortunately slightly incomplete) list of the adapters OpenOCD works with. This page lists SWD-compatible adapters as well; take note that the ESP32 does not support SWD.

At Espressif, we have tested the TIAO USB Multi-protocol Adapter board as well as the Flyswatter2, which are both USB2.0 high-speed devices and give a good throughput. We also tested a J-link-compatible and an EasyOpenJTAG adapter; both worked as well but are somewhat slower.

The minimal signalling to get a working JTAG connection are TDI, TDO, TCK, TMS and Gnd. Some JTAG debuggers also need a connection from the ESP32 power line to a line called e.g. Vtar to set the working voltage. SRST can optionally be connected to the CH_PD of the ESP32, although for now, support in OpenOCD for that line is pretty minimal.

Installing OpenOCD

The sources for the ESP32-enabled variant of OpenOCD are available from Espressifs Github. To download the source, use the following commands:

git clone --recursive https://github.com/espressif/openocd-esp32.git
cd openocd-esp32

For compilation of OpenOCD, please refer to the README, README.OSX and README.Windows file in the openocd-esp32 directory. You can skip the make install step if you want.

Configuring the ESP32 target in OpenOCD

After OpenOCD is compiled (and optionally installed) and the JTAG adapter is connected to the ESP32 board, everything is ready to invoke OpenOCD for the first time. To do this, OpenOCD needs to be told what JTAG adapter to use as well as what type of board and processor the JTAG adapter is connected to. It is the easiest to do both using a configuration file. A template configuration file (esp32.cfg) is included in the same directory as this file. A way to use this would be:

  • Copy esp32.cfg to the openocd-esp32 directory
  • Edit the copied esp32.cfg file. Most importantly, change the source [find interface/ftdi/tumpa.cfg] line to reflect the physical JTAG adapter connected.
  • Open a terminal and cd to the openocd-esp32 directory.
  • Run ./src/openocd -s ./tcl -f ./esp32.cfg to start OpenOCD

You should now see something like this:

user@machine:~/esp32/openocd-esp32$ ./src/openocd -s ./tcl/ -f ../openocd-esp32-tools/esp32.cfg
Open On-Chip Debugger 0.10.0-dev-00446-g6e13a97-dirty (2016-08-23-16:36)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
none separate
adapter speed: 200 kHz
Info : clock speed 200 kHz
Info : JTAG tap: esp32.cpu0 tap/device found: 0x120034e5 (mfg: 0x272 (Tensilica), part: 0x2003, ver: 0x1)
Info : JTAG tap: esp32.cpu1 tap/device found: 0x120034e5 (mfg: 0x272 (Tensilica), part: 0x2003, ver: 0x1)
Info : esp32.cpu0: Debug controller was reset (pwrstat=0x5F, after clear 0x0F).
Info : esp32.cpu0: Core was reset (pwrstat=0x5F, after clear 0x0F).
  • If you see an error indicating permission problems, please see the ‘Permissions delegation’ bit in the OpenOCD README
  • If you see JTAG errors (...all ones/...all zeroes) please check your connections and see if everything is powered on.

Connecting a debugger to OpenOCD

OpenOCD should now be ready to accept gdb connections. If you have compiled the ESP32 toolchain using Crosstool-NG, or if you have downloaded a precompiled toolchain from the Espressif website, you should already have xtensa-esp32-elf-gdb, a version of gdb that can be used for this. First, make sure the project you want to debug is compiled and flashed into the ESP32’s SPI flash. Then, in a different console than OpenOCD is running in, invoke gdb. For example, for the template app, you would do this like such:

cd esp-idf-template
xtensa-esp32-elf-gdb -ex 'target remote localhost:3333' ./build/app-template.elf

This should give you a gdb prompt.

FreeRTOS support

OpenOCD has explicit support for the ESP-IDF FreeRTOS; FreeRTOS detection can be disabled in esp32.conf. When enabled, gdb can see FreeRTOS tasks as threads. Viewing them all can be done using the gdb i threads command, changing to a certain task is done with thread x, with x being the number of the thread. All threads can be switched to except for a thread actually running on the other CPU, please see ESP32 quirks for more information.

ESP32 quirks

Normal gdb breakpoints (b myFunction) can only be set in IRAM, because that memory is writable. Setting these types of breakpoints in code in flash will not work. Instead, use a hardware breakpoint (hb myFunction). The esp32 supports 2 hardware breakpoints. It also supports two watchpoint, so two variables can be watched for change or read by the gdb command watch myVariable.

Connecting gdb to the APP or PRO cpu happens by changing the port gdb connects to. target remote localhost:3333 connects to the PRO CPU, target remote localhost:3334 to the APP CPU. Hardware-wise, when one CPU is halted because of debugging reasons, the other one will be halted as well; resuming also happens simultaneously.

Because gdb only sees the system from the point of view of the selected CPU, only the FreeRTOS tasks that are suspended and the task running on the CPU gdb is connected to, will be shown correctly. The task that was active on the other cpu can be inspected, but its state may be wildly inconsistent.

The ESP-IDF code has the option of compiling in various support options for OpenOCD: it can stop execution when the first thread is started and break the system if a panic or unhandled exception is thrown. Both options are enabled by default but can be disabled using the esp-idf configuration menu. Please see the make menuconfig menu for more details.

Normally, under OpenOCD, a board can be reset by entering ‘mon reset’ or ‘mon reset halt’ into gdb. For the ESP32, these commands work more or less, but have side effects. First of all, an OpenOCD reset only resets the CPU cores, not the peripherals, which may lead to undefined behaviour if software assumes the after-reset state of peripherals. Secondly, ‘mon reset halt’ stops before FreeRTOS is initialized. OpenOCD assumes (in the default configuration, you can change this by editing esp32.cfg) a running FreeRTOS and may get confused.

ESP32 Core Dump

Overview

ESP-IDF provides support to generate core dumps on unrecoverable software errors. This useful technique allows post-mortem analysis of software state at the moment of failure. Upon the crash system enters panic state, prints some information and halts or reboots depending configuration. User can choose to generate core dump in order to analyse the reason of failure on PC later on. Core dump contains snapshots of all tasks in the system at the moment of failure. Snapshots include tasks control blocks (TCB) and stacks. So it is possible to find out what task, at what instruction (line of code) and what callstack of that task lead to the crash. ESP-IDF provides special script espcoredump.py to help users to retrieve and analyse core dumps. This tool provides two commands for core dumps analysis:

  • info_corefile - prints crashed task’s registers, callstack, list of available tasks in the system, memory regions and contents of memory stored in core dump (TCBs and stacks)
  • dbg_corefile - creates core dump ELF file and runs GDB debug session with this file. User can examine memory, variables and tasks states manually. Note that since not all memory is saved in core dump only values of variables allocated on stack will be meaningfull

Configuration

Currently there are three options related to core dump generation which user can choose in configuration menu of the application (make menuconfig):

  • Disable core dump generation
  • Save core dump to flash
  • Print core dump to UART

These options can be choosen in Components -> ESP32-specific config -> Core dump destination menu item.

Save core dump to flash

When this option is selected core dumps are saved to special partition on flash. When using default partition table files which are provided with ESP-IDF it automatically allocates necessary space on flash, But if user wants to use its own layout file together with core dump feature it should define separate partition for core dump as it is shown below:

# Name,   Type, SubType, Offset,  Size
# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
nvs,      data, nvs,     0x9000,  0x6000
phy_init, data, phy,     0xf000,  0x1000
factory,  app,  factory, 0x10000, 1M
coredump, data, coredump,,        64K

There are no special requrements for partition name. It can be choosen according to the user application needs, but partition type should be ‘data’ and sub-type should be ‘coredump’. Also when choosing partition size note that core dump data structure introduces constant overhead of 20 bytes and per-task overhead of 12 bytes. This overhead does not include size of TCB and stack for every task. So partirion size should be at least 20 + max tasks number x (12 + TCB size + max task stack size) bytes.

The example of generic command to analyze core dump from flash is: espcoredump.py -p </path/to/serial/port> info_corefile </path/to/program/elf/file> or espcoredump.py -p </path/to/serial/port> dbg_corefile </path/to/program/elf/file>

Running ‘espcoredump.py’

Generic command syntax:

espcoredump.py [options] command [args]

Script Options:
  • –chip,-c {auto,esp32}. Target chip type. Supported values are auto and esp32.
  • –port,-p PORT. Serial port device.
  • –baud,-b BAUD. Serial port baud rate used when flashing/reading.
Commands:
  • info_corefile. Retrieve core dump and print useful info.
  • dbg_corefile. Retrieve core dump and start GDB session with it.
Command Arguments:
 
  • –gdb,-g GDB. Path to gdb to use for data retrieval.
  • –core,-c CORE. Path to core dump file to use (if skipped core dump will be read from flash).
  • –core-format,-t CORE_FORMAT. Specifies that file passed with “-c” is an ELF (“elf”), dumped raw binary (“raw”) or base64-encoded (“b64”) format.
  • –off,-o OFF. Ofsset of coredump partition in flash (type “make partition_table” to see it).
  • –save-core,-s SAVE_CORE. Save core to file. Othwerwise temporary core file will be deleted. Ignored with “-c”.
  • –print-mem,-m Print memory dump. Used only with “info_corefile”.

Flash Encryption

Flash Encryption is a feature for encrypting the contents of the ESP32’s attached SPI flash. When flash encryption is enabled, physical readout of the SPI flash is not sufficient to recover most flash contents.

Flash Encryption is separate from the Secure Boot feature, and you can use flash encryption without enabling secure boot. However we recommend using both features together for a secure environment.

IMPORTANT: Enabling flash encryption limits your options for further updates of your ESP32. Make sure to read this document (including `Limitations of Flash Encryption` and understand the implications of enabling flash encryption.

Background

  • The contents of the flash are encrypted using AES with a 256 bit key. The flash encryption key is stored in efuse internal to the chip, and is (by default) protected from software access.

  • Flash access is transparent via the flash cache mapping feature of ESP32 - any flash regions which are mapped to the address space will be transparently decrypted when read.

  • Encryption is applied by flashing the ESP32 with plaintext data, and (if encryption is enabled) the bootloader encrypts the data in place on first boot.

  • Not all of the flash is encrypted. The following kinds of flash data are encrypted: - Bootloader - Secure boot bootloader digest (if secure boot is enabled) - Partition Table - All “app” type partitions - Any partition marked with the “encrypt” flag in the partition table

    It may be desirable for some data partitions to remain unencrypted for ease of access, or to use flash-friendly update algorithms that are ineffective if the data is encrypted. “NVS” partitions for non-volatile storage cannot be encrypted.

  • The flash encryption key is stored in efuse key block 1, internal to the ESP32 chip. By default, this key is read- and write-protected so software cannot access it or change it.

  • The flash encryption algorithm is AES-256, where the key is “tweaked” with the offset address of each 32 byte block of flash. This means every 32 byte block (two consecutive 16 byte AES blocks) is encrypted with a unique key derived from the flash encryption key.

  • Although software running on the chip can transparently decrypt flash contents, by default it is made possible for the UART bootloader to decrypt (or encrypt) data when flash encryption is enabled.

Flash Encryption Initialisation

This is the default (and recommended) flash encryption initialisation process. It is possible to customise this process for development or other purposes, see Flash Encryption Advanced Features for details.

IMPORTANT: Once flash encryption is enabled on first boot, the hardware allows a maximum of 3 subsequent flash updates via physical re-flashing. If secure boot is enabled, no physical re-flashes are possible. OTA updates can be used to update flash content without counting towards this limit. When enabling flash encryption in development, use a `precalculated flash encryption key` to allow physically re-flashing an unlimited number of times with pre-encrypted data.

  • The bootloader must be compiled with flash encryption support enabled. In make menuconfig, navigate to “Security Features” and select “Yes” for “Enable flash nencryption on boot”.
  • If enabling Secure Boot at the same time, you can simultaneously select those options now. See the Secure Boot documentation for details.
  • Build and flash the bootloader, partition table and factory app image as normal. These partitions are initially written to the flash unencrypted.
  • On first boot, the bootloader sees FLASH_CRYPT_CNT efuse is set to 0 so it generates a flash encryption key using the hardware random number generator. This key is stored in efuse. The key is read and write protected against further software access.
  • All of the encrypted partitions are then encrypted in-place by the bootloader. Encrypting in-place can take some time (up to a minute for large partitions.)

IMPORTANT: Do not interrupt power to the ESP32 while the first boot encryption pass is running. If power is interrupted, the flash contents will be corrupted and require flashing with unencrypted data again. This re-flash will not count towards the flashing limit, as ``FLASH_CRYPT_CNT`` is only updated after this process finishes.

  • Once flashing is complete. efuses are blown (by default) to disable encrypted flash access while the UART bootloader is running.
  • If not already write-protected, the FLASH_CRYPT_CONFIG efuse is also burned to the maximum value (0xF) to maximise the number of key bits which are tweaked in the flash algorithm. See Setting FLASH_CRYPT_CONFIG for details of this efuse.
  • Finally, the FLASH_CRYPT_CNT efuse is burned with the initial value 1. It is this efuse which activates the transparent flash encryption layer, and limits the number of subsequent reflashes. See the Updating Encrypted Flash section for details about FLASH_CRYPT_CNT.
  • The bootloader resets itself to reboot from the newly encrypted flash.

Encrypted Flash Access

Reading Encrypted Flash

Whenever the FLASH_CRYPT_CNT efuse is set to a value with an odd number of bits set, all flash content which is accessed via the MMU’s flash cache is transparently decrypted. This includes:

  • Executable application code in flash (IROM).
  • All read-only data stored in flash (DROM).
  • Any data accessed via esp_spi_flash_mmap.
  • The software bootloader image when it is read by the ROM bootloader.

IMPORTANT: The MMU flash cache unconditionally decrypts all data. Data which is stored unencrypted in the flash will be “transparently decrypted” via the flash cache and appear to software like random garbage.

To read data without using a flash cache MMU mapping, we recommend using the partition read function esp_partition_read. When using this function, data will only be decrypted when it is read from an encrypted partition. Other partitions will be read unencrypted. In this way, software can access encrypted and non-encrypted flash in the same way.

Data which is read via other SPI read APIs are not decrypted:

  • Data read via esp_spi_flash_read is not decrypted
  • Data read via ROM function SPIRead is not decrypted (this function is not supported in esp-idf apps).
  • Data stored using the Non-Volatile Storage (NVS) API is always stored decrypted.

Writing Encrypted Flash

Where possible, we recommend using the partition write function esp_partition_write. When using this function, data will only be encrypted when writing to encrypted partitions. Data will be written to other partitions unencrypted. In this way, software can access encrypted and non-encrypted flash in the same way.

The esp_spi_flash_write function will write data when the write_encrypted parameter is set to true. Otherwise, data will be written unencrypted.

The ROM function SPI_Encrypt_Write will write encrypted data to flash, the ROM function SPIWrite will write unencrypted to flash. (these function are not supported in esp-idf apps).

The minimum write size for unencrypted data is 4 bytes (and the alignment is 4 bytes). Because data is encrypted in blocks, the minimum write size for encrypted data is 32 bytes (and the alignment is 32 bytes.)

Updating Encrypted Flash

OTA Updates

OTA updates to encrypted partitions will automatically write encrypted, as long as the esp_partition_write function is used.

Serial Flashing

Provided secure boot is not used, the FLASH_CRYPT_CNT registers allow the flash to be updated with new plaintext data via serial flashing (or other physical methods), up to 3 additional times. FLASH_CRYPT_CNT efuse is an 8-bit value, and the flash encryption enables or disables based on the number of bits which are set to “1”:

  • Even number (0-6) bits are set: Transparent reading of encrypted flash is disabled, any encrypted data cannot be decrypted. If the bootloader was built with “Enable flash encryption on boot” then it will see this situation and immediately re-encrypt the flash wherever it finds unencrypted data. Once done, it sets another bit in the efuse to ‘1’ meaning an odd number of bits are now set.
  • Odd number (1-7) bits are set: Transparent reading of encrypted flash is enabled.
  • All 8 bits are set (valuye 0: Transparent reading of encrypted flash is disabled, any encrypted data is inaccessible. Bootloader will normally detect this condition and halt. To avoid use of this state to load unauthorised code, secure boot must be used or FLASH_CRYPT_CNT must be write-protected.

The espefuse.py tool can be used to manually change the number of bits set in FLASH_CRYPT_CNT, via serial bootloader.

Limited Updates

Only 4 physical flash updates (writing plaintext data which is then encrypted) are possible:

  1. On first plaintext boot, bit count has brand new value 0 and bootloader changes to 1 (0x01) following encryption.
  2. On next plaintext flash update, bit count is manually updated to 2 (0x03) and bootloader changes to 4 (0x07) following encryption.
  3. Then bit count is manually updated to 4 (0x0F) and the bootloader changes efuse bit count to 5 (0x1F).
  4. Finally bootloader is manually updated to 6 (0x3F) and bootloader changes efuse bit count to 7 (0x7F).

Cautions With Re-Flashing

  • When reflashing via serial, reflash every partition that was previously written with plaintext (including bootloader). It is possible to skip app partitions which are not the “currently selected” OTA partition (these will not be re-encrypted unless a plaintext app image is found there.) However any partition marked with the “encrypt” flag will be unconditionally re-encrypted, meaning that any already encrypted data will be encrypted twice and corrupted.
  • If secure boot is enabled, you can’t reflash via serial at all unless you used chosen the “Reflashable” option for Secure Boot, pre-generated a key and burned it to the ESP32. In this case you can re-flash a plaintext secure boot digest and bootloader image at offset 0 (see Secure Boot documentation.) In production secure boot configuration, the secure boot digest is stored encrypted - so if FLASH_CRYPT_CNT is set to an even value then the ROM bootloader will read the encrypted digest as-is and therefore will fail to verify any bootloader image as valid.

Re-Flashing Procedure

The steps to update a device with plaintext via UART bootloader, when flash encryption is enabled are:

  • Build the application as usual.
  • Burn the FLASH_CRYPT_CNT efuse by running the command espefuse.py burn_efuse FLASH_CRYPT_CNT. espefuse.py will automatically increment the bit count by 1.
  • Flash the device with plaintext data as usual (make flash or esptool.py commands.) Flash all previously encrypted partitions, including the bootloader. If secure boot is enabled, it must be enabled in “Reflashable” mode and a pre-generated key burned to the ESP32 - flash the bootloader-reflash-digest.bin file at offset 0x0.
  • Reset the device and it will re-encrypt plaintext partitions, burn the FLASH_CRYPT_CNT flag to re-enable encryption.

Disabling Updates

To prevent further plaintext updates via physical access, use espefuse.py to write protect the FLASH_CRYPT_CNT efuse after flash encryption has been enabled (ie after first boot is complete):

espefuse.py write_protect_efuse FLASH_CRYPT_CNT

This prevents any further modifications to disable or re-enable flash encryption.

Limitations of Flash Encryption

Flash Encryption prevents plaintext readout of the encrypted flash, to protect firmware against unauthorised readout and modification. It is important to understand the limitations of the flash encryption system:

  • Flash encryption is only as strong as the key. For this reason, we recommend keys are generated on the device during first boot (default behaviour). If generating keys off-device to burn with esp_efuse.py burn_key, ensure they are generated from a quality random number source, kept secure, and never shared between devices.
  • Not all data is stored encrypted. If storing data on flash, check if the method you are using (library, API, etc.) supports flash encryption.
  • Flash encryption does not prevent an attacker from understanding the high-level layout of the flash. This is because the same AES key is used for every two 16 byte AES blocks. When both adjacent 16 byte blocks contain identical content (such as empty or padding areas), these blocks will encrypt to produce matching pairs of encrypted blocks. This may allow an attacker to make high-level comparisons between encrypted devices (ie to tell if two devices are probably running the same firmware version).
  • For the same reason, an attacker can always guess when two adjacent 16 byte blocks (32 byte aligned) contain identical content. Keep this in mind if storing sensitive data on the flash, design your flash storage so this doesn’t happen (using a counter byte or some other non-identical value every 16 bytes is sufficient).
  • Flash encryption alone may not prevent an attacker from modifying the firmware of the device. Always use flash encryption in combination with Secure Boot.

Flash Encryption Advanced Features

Encrypted Partition Flag

In the partition table description CSV files, there is a field for flags.

Usually left blank, if you write “encrypted” in this field then the partition will be marked as encrypted in the partition table, and data written here will be treated as encrypted (same as an app partition):

# Name,   Type, SubType, Offset,  Size, Flags
nvs,      data, nvs,     0x9000,  0x6000
phy_init, data, phy,     0xf000,  0x1000
factory,  app,  factory, 0x10000, 1M
secret_data, 0x40, 0x01, 0x20000, 256K, encrypted
  • None of the default partition formats have any encrypted data partitions.
  • It is not necessary to mark “app” partitions as encrypted, they are always treated as encrypted.
  • The “encrypted” flag does nothing if flash encryption is not enabled.
  • It is possible to mark the optional phy partition with phy_init data as encrypted, if you wish to protect this data from physical access readout or modification.
  • It is not possible to mark the nvs partition as encrypted.

Precalculated Flash Encryption Key

It is possible to pre-generate a flash encryption key on the host computer and burn it into the ESP32 efuse. This allows data to be per-encrypted on the host and flashed to the ESP32 without needing a plaintext flash update.

This is useful for development, because it removes the 4 flash limit and allows reflashing with secure boot enabled.

IMPORTANT This method is intended to assist with development only, not for production devices. If pre-generating flash encryption for production, ensure the keys are generated from a high quality random number source and do not share the same flash encryption key across multiple devices.

Obtaining Flash Encryption Key

Flash encryption keys are 32 bytes of random data. You can generate a random key with espsecure.py:

espsecure.py generate_flash_encryption_key my_flash_encryption_key.bin

(The randomness of this data is only as good as the OS and it’s Python installation’s random data source.)

Alternatively, if you’re using secure boot and have a secure boot signing key then you can generate a deterministic SHA-256 digest of the secure boot private key to use:

espsecure.py digest_private-key --keyfile secure_boot_signing_key.pem my_flash_encryption_key.bin

The same key is used as the secure boot digest key if you enabled “Reflashable” mode for secure boot.

This means you can always re-calculate the flash encryption key from the secure boot private signing key. This method is not at all suitable for production devices.

Burning Flash Encryption Key

Once you have generated a flash encryption key, you need to burn it to efuse on the device. This must be done before first boot, otherwise the ESP32 will generate a random key that software can’t access.

To burn a key to the device (possible one time only):

espefuse.py burn_key flash_encryption my_flash_encryption_key.bin
First Flash

For the first flash, follow the same steps as for default Flash Encryption Initialisation and flash a plaintext image. The bootloader will enable flash encryption using the pre-burned key and encrypt all partitions.

Reflashing

To reflash an encrypted image requires an additional manual update step, to encrypt the data you wish to flash.

Suppose that this is the normal flashing non-encrypted flashing step:

esptool.py --port /dev/ttyUSB0 --baud 115200 write_flash -z 0x10000 build/my-app.bin

The data needs to be pre-encrypted with knowledge of the address (0x10000) and the binary file name:

espsecure.py encrypt_flash_data --keyfile my_flash_encryption_key.bin --address 0x10000 -o build/my-app-encrypted.bin build/my-app.bin

This step will encrypt my-app.bin using the supplied key, and produce an encrypted file my-app-encrypted.bin. Be sure that the address argument matches the address where you plan to flash the binary.

Then, flash the encrypted binary with esptool.py:

esptool.py --port /dev/ttyUSB0 --baud 115200 write_flash -z 0x10000 build/my-app-encrypted.bin

Enabling UART Bootloader Encryption/Decryption

By default, on first boot the flash encryption process will burn efuses DISABLE_DL_ENCRYPT, DISABLE_DL_DECRYPT and DISABLE_DL_CACHE.

  • DISABLE_DL_ENCRYPT disables the flash encryption operations when running in UART bootloader boot mode.
  • DISABLE_DL_DECRYPT disables transparent flash decryption when running in UART bootloader mode, even if FLASH_CRYPT_CNT is set to enable it in normal operation.
  • DISABLE_DL_CACHE disables the entire MMU flash cache when running in UART bootloader mode.

It is possible to burn only some of these efuses, and write-protect the rest (with unset value 0) before the first boot, in order to preserve them:

espefuse.py burn_efuse DISABLE_DL_DECRYPT
espefuse.py write_protect_efuse DISABLE_DL_ENCRYPT

(Note that all 3 of these efuses are disabled via one write protect bit, so write protecting one will write protect all of them.)

Write protecting these efuses when they are unset (0) is not currently useful, as esptool.py does not support flash encryption functions.

However, note that write protecting DISABLE_DL_DECRYPT when it is unset (0) effectively makes flash encryption useless, as an attacker with physical access can use UART bootloader mode to read out the flash.

Technical Details

Flash Encryption Algorithm

  • AES-256 operates on 16 byte blocks of data. The flash encryption engine encrypts and decrypts data in 32 byte blocks, two AES blocks in series.
  • AES algorithm is used inverted in flash encryption, so the flash encryption “encrypt” operation is AES decrypt and the “decrypt” operation is AES encrypt. This is for performance reasons and does not alter the effectiveness of the algorithm.
  • The main flash encryption key is stored in efuse (BLK2) and by default is protected from further writes or software readout.
  • Each 32 byte block is encrypted with a unique key which is derived from this main flash encryption key XORed with the offset of this block in the flash (a “key tweak”).
  • The specific tweak depends on the setting of FLASH_CRYPT_CONFIG efuse. This is a 4 bit efuse, where each bit enables XORing of a particular range of the key bits: - Bit 1, bits 0-66 of the key are XORed. - Bit 2, bits 67-131 of the key are XORed. - Bit 3, bits 132-194 of the key are XORed. - Bit 4, bits 195-256 of the key are XORed.

It is recommended that FLASH_CRYPT_CONFIG is always left to set the default value 0xF, so that all key bits are XORed with the block offset. See Setting FLASH_CRYPT_CONFIG for details.

  • The high 19 bits of the block offset (bit 5 to bit 23) are XORed with the main flash encryption key. This range is chosen for two reasons: the maximum flash size is 16MB (24 bits), and each block is 32 bytes so the least significant 5 bits are always zero.
  • There is a particular mapping from each of the 19 block offset bits to the 256 bits of the flash encryption key, to determine which bit is XORed with which. See the variable _FLASH_ENCRYPTION_TWEAK_PATTERN in espsecure.py for a list of these.
  • For the full algorithm implemented in Python, see _flash_encryption_operation() in the espsecure.py source code.

Setting FLASH_CRYPT_CONFIG

The FLASH_CRYPT_CONFIG efuse determines the number of bits in the flash encryption key which are “tweaked” with the block offset. See Flash Encryption Algorithm for details.

First boot of the bootloader always sets this value to the maximum 0xF.

It is possible to write these efuse manually, and write protect it before first boot in order to select different tweak values. This is not recommended.

It is strongly recommended to never write protect FLASH_CRYPT_CONFIG when it the value is zero. If this efuse is set to zero, no bits in the flash encryption key are tweaked and the flash encryption algorithm is equivalent to AES ECB mode.

Secure Boot

Secure Boot is a feature for ensuring only your code can run on the chip. Data loaded from flash is verified on each reset.

Secure Boot is separate from the Flash Encryption feature, and you can use secure boot without encrypting the flash contents. However we recommend using both features together for a secure environment.

Background

  • Most data is stored in flash. Flash access does not need to be protected from physical access in order for secure boot to function, because critical data is stored (non-software-accessible) in Efuses internal to the chip.
  • Efuses are used to store the secure bootloader key (in efuse block 2), and also a single Efuse bit (ABS_DONE_0) is burned (written to 1) to permanently enable secure boot on the chip. For more details about efuse, see the (forthcoming) chapter in the Technical Reference Manual.
  • To understand the secure boot process, first familiarise yourself with the standard ESP-IDF boot process.
  • Both stages of the boot process (initial software bootloader load, and subsequent partition & app loading) are verified by the secure boot process, in a “chain of trust” relationship.

Secure Boot Process Overview

This is a high level overview of the secure boot process. Step by step instructions are supplied under How To Enable Secure Boot. Further in-depth details are supplied under Technical Details:

  1. The options to enable secure boot are provided in the make menuconfig hierarchy, under “Secure Boot Configuration”.
  2. Secure Boot defaults to signing images and partition table data during the build process. The “Secure boot private signing key” config item is a file path to a ECDSA public/private key pair in a PEM format file.
  3. The software bootloader image is built by esp-idf with secure boot support enabled and the public key (signature verification) portion of the secure boot signing key compiled in. This software bootloader image is flashed at offset 0x1000.
  4. On first boot, the software bootloader follows the following process to enable secure boot:
    • Hardware secure boot support generates a device secure bootloader key (generated via hardware RNG, then stored read/write protected in efuse), and a secure digest. The digest is derived from the key, an IV, and the bootloader image contents.
    • The secure digest is flashed at offset 0x0 in the flash.
    • Depending on Secure Boot Configuration, efuses are burned to disable JTAG and the ROM BASIC interpreter (it is strongly recommended these options are turned on.)
    • Bootloader permanently enables secure boot by burning the ABS_DONE_0 efuse. The software bootloader then becomes protected (the chip will only boot a bootloader image if the digest matches.)
  5. On subsequent boots the ROM bootloader sees that the secure boot efuse is burned, reads the saved digest at 0x0 and uses hardware secure boot support to compare it with a newly calculated digest. If the digest does not match then booting will not continue. The digest and comparison are performed entirely by hardware, and the calculated digest is not readable by software. For technical details see Hardware Secure Boot Support.
  6. When running in secure boot mode, the software bootloader uses the secure boot signing key (the public key of which is embedded in the bootloader itself, and therefore validated as part of the bootloader) to verify the signature appended to all subsequent partition tables and app images before they are booted.

Keys

The following keys are used by the secure boot process:

  • “secure bootloader key” is a 256-bit AES key that is stored in Efuse block 2. The bootloader can generate this key itself from the internal hardware random number generator, the user does not need to supply it (it is optionally possible to supply this key, see Re-Flashable Software Bootloader). The Efuse holding this key is read & write protected (preventing software access) before secure boot is enabled.
  • “secure boot signing key” is a standard ECDSA public/private key pair (see Image Signing Algorithm) in PEM format.
    • The public key from this key pair (for signature verificaton but not signature creation) is compiled into the software bootloader and used to verify the second stage of booting (partition table, app image) before booting continues. The public key can be freely distributed, it does not need to be kept secret.
    • The private key from this key pair must be securely kept private, as anyone who has this key can authenticate to any bootloader that is configured with secure boot and the matching public key.

How To Enable Secure Boot

  1. Run make menuconfig, navigate to “Secure Boot Configuration” and select the option “One-time Flash”. (To understand the alternative “Reflashable” choice, see Re-Flashable Software Bootloader.)

  2. Select a name for the secure boot signing key. This option will appear after secure boot is enabled. The file can be anywhere on your system. A relative path will be evaluated from the project directory. The file does not need to exist yet.

  3. Set other menuconfig options (as desired). Pay particular attention to the “Bootloader Config” options, as you can only flash the bootloader once. Then exit menuconfig and save your configuration

  4. The first time you run make, if the signing key is not found then an error message will be printed with a command to generate a signing key via espsecure.py generate_signing_key.

    IMPORTANT A signing key generated this way will use the best random number source available to the OS and its Python installation (/dev/urandom on OSX/Linux and CryptGenRandom() on Windows). If this random number source is weak, then the private key will be weak.

    IMPORTANT For production environments, we recommend generating the keypair using openssl or another industry standard encryption program. See Generating Secure Boot Signing Key for more details.

  5. Run make bootloader to build a secure boot enabled bootloader. The output of make will include a prompt for a flashing command, using esptool.py write_flash.

  6. When you’re ready to flash the bootloader, run the specified command (you have to enter it yourself, this step is not performed by make) and then wait for flashing to complete. Remember this is a one time flash, you can’t change the bootloader after this!.

  7. Run make flash to build and flash the partition table and the just-built app image. The app image will be signed using the signing key you generated in step 4.

    NOTE: make flash doesn’t flash the bootloader if secure boot is enabled.

  8. Reset the ESP32 and it will boot the software bootloader you flashed. The software bootloader will enable secure boot on the chip, and then it verifies the app image signature and boots the app. You should watch the serial console output from the ESP32 to verify that secure boot is enabled and no errors have occured due to the build configuration.

NOTE Secure boot won’t be enabled until after a valid partition table and app image have been flashed. This is to prevent accidents before the system is fully configured.

  1. On subsequent boots, the secure boot hardware will verify the software bootloader has not changed (using the secure bootloader key) and then the software bootloader will verify the signed partition table and app image (using the public key portion of the secure boot signing key).

Re-Flashable Software Bootloader

Configuration “Secure Boot: One-Time Flash” is the recommended configuration for production devices. In this mode, each device gets a unique key that is never stored outside the device.

However, an alternative mode “Secure Boot: Reflashable” is also available. This mode allows you to supply a 256-bit key file that is used for the secure bootloader key. As you have the key file, you can generate new bootloader images and secure boot digests for them.

In the esp-idf build process, this 256-bit key file is derived from the app signing key generated during the generate_signing_key step above. The private key’s SHA-256 digest is used as the 256-bit secure bootloader key. This is a convenience so you only need to generate/protect a single private key.

NOTE: Although it’s possible, we strongly recommend not generating one secure boot key and flashing it to every device in a production environment. The “One-Time Flash” option is recommended for production environments.

To enable a reflashable bootloader:

  1. In the make menuconfig step, select “Bootloader Config” -> “Secure Boot” -> “Reflashable”.
  2. Follow the steps shown above to choose a signing key file, and generate the key file.
  3. Run make bootloader. A 256-bit key file will be created, derived from the private key that is used for signing. Two sets of flashing steps will be printed - the first set of steps includes an espefuse.py burn_key command which is used to write the bootloader key to efuse. (Flashing this key is a one-time-only process.) The second set of steps can be used to reflash the bootloader with a pre-calculated digest (generated during the build process).
  4. Resume from Step 6<Secure Boot Process Overview> of the one-time process, to flash the bootloader and enable secure boot. Watch the console log output closely to ensure there were no errors in the secure boot configuration.

Generating Secure Boot Signing Key

The build system will prompt you with a command to generate a new signing key via espsecure.py generate_signing_key. This uses the python-ecdsa library, which in turn uses Python’s os.urandom() as a random number source.

The strength of the signing key is proportional to (a) the random number source of the system, and (b) the correctness of the algorithm used. For production devices, we recommend generating signing keys from a system with a quality entropy source, and using the best available EC key generation utilities.

For example, to generate a signing key using the openssl command line:

` openssl ecparam -name prime256v1 -genkey -noout -out my_secure_boot_signing_key.pem `

Remember that the strength of the secure boot system depends on keeping the signing key private.

Remote Signing of Images

For production builds, it can be good practice to use a remote signing server rather than have the signing key on the build machine (which is the default esp-idf secure boot configuration). The espsecure.py command line program can be used to sign app images & partition table data for secure boot, on a remote system.

To use remote signing, disable the option “Sign binaries during build”. The private signing key does not need to be present on the build system. However, the public (signature verification) key is required because it is compiled into the bootloader (and can be used to verify image signatures during OTA updates.

To extract the public key from the private key:

espsecure.py extract_public_key --keyfile PRIVATE_SIGNING_KEY PUBLIC_VERIFICATION_KEY

The path to the public signature verification key needs to be specified in the menuconfig under “Secure boot public signature verification key” in order to build the secure bootloader.

After the app image and partition table are built, the build system will print signing steps using espsecure.py:

espsecure.py sign_data --keyfile PRIVATE_SIGNING_KEY BINARY_FILE

The above command appends the image signature to the existing binary. You can use the –output argument to place the binary with signature appended into a separate file:

espsecure.py sign_data --keyfile PRIVATE_SIGNING_KEY --output SIGNED_BINARY_FILE BINARY_FILE

Secure Boot Best Practices

  • Generate the signing key on a system with a quality source of entropy.
  • Keep the signing key private at all times. A leak of this key will compromise the secure boot system.
  • Do not allow any third party to observe any aspects of the key generation or signing process using espsecure.py. Both processes are vulnerable to timing or other side-channel attacks.
  • Enable all secure boot options in the Secure Boot Configuration. These include flash encryption, disabling of JTAG, disabling BASIC ROM interpeter, and disabling the UART bootloader encrypted flash access.

Technical Details

The following sections contain low-level descriptions of various technical functions:

Hardware Secure Boot Support

The Secure Boot support hardware can perform three basic operations:

  1. Generate a random sequence of bytes from a hardware random number generator.
  2. Generate a digest from data (usually the bootloader image from flash) using a key stored in Efuse block 2. The key in Efuse can (& should) be read/write protected, which prevents software access. For full details of this algorithm see Secure Bootloader Digest Algorithm. The digest can only be read back by software if Efuse ABS_DONE_0 is not burned (ie still 0).
  3. Generate a digest from data (usually the bootloader image from flash) using the same algorithm as step 2 and compare it to a pre-calculated digest supplied in a buffer (usually read from flash offset 0x0). The hardware returns a true/false comparison without making the digest available to software. This function is available even when Efuse ABS_DONE_0 is burned.

Secure Bootloader Digest Algorithm

Starting with an “image” of binary data as input, this algorithm generates a digest as output. The digest is sometimes referred to as an “abstract” in hardware documentation.

For a Python version of this algorithm, see the espsecure.py tool in the components/esptool_py directory.

Items marked with (^) are to fulfill hardware restrictions, as opposed to cryptographic restrictions.

  1. Prefix the image with a 128 byte randomly generated IV.
  2. If the image length is not modulo 128, pad the image to a 128 byte boundary with 0xFF. (^)
  3. For each 16 byte plaintext block of the input image: - Reverse the byte order of the plaintext input block (^) - Apply AES256 in ECB mode to the plaintext block. - Reverse the byte order of the ciphertext output block. (^) - Append to the overall ciphertext output.
  4. Byte-swap each 4 byte word of the ciphertext (^)
  5. Calculate SHA-512 of the ciphertext.

Output digest is 192 bytes of data: The 128 byte IV, followed by the 64 byte SHA-512 digest.

Image Signing Algorithm

Deterministic ECDSA as specified by RFC6979.

  • Curve is NIST256p (openssl calls this curve “prime256v1”, it is also sometimes called secp256r1).
  • Hash function is SHA256.
  • Key format used for storage is PEM. - In the bootloader, the public key (for signature verification) is flashed as 64 raw bytes.
  • Image signature is 68 bytes - a 4 byte version word (currently zero), followed by a 64 bytes of signature data. These 68 bytes are appended to an app image or partition table data.

Manual Commands

Secure boot is integrated into the esp-idf build system, so make will automatically sign an app image if secure boot is enabled. make bootloader will produce a bootloader digest if menuconfig is configured for it.

However, it is possible to use the espsecure.py tool to make standalone signatures and digests.

To sign a binary image:

espsecure.py sign_data --keyfile ./my_signing_key.pem --output ./image_signed.bin image-unsigned.bin

Keyfile is the PEM file containing an ECDSA private signing key.

To generate a bootloader digest:

espsecure.py digest_secure_bootloader --keyfile ./securebootkey.bin --output ./bootloader-digest.bin build/bootloader/bootloader.bin

Keyfile is the 32 byte raw secure boot key for the device. To flash this digest onto the device:

esptool.py write_flash 0x0 bootloader-digest.bin

ULP coprocessor programming

Warning

ULP coprocessor programming approach described here is experimental. It is probable that once binutils support for ULP is done, this preprocessor-based approach may be deprecated. We welcome discussion about and contributions to ULP programming tools.

ULP coprocessor is a simple FSM which is designed to perform measurements using ADC, temperature sensor, and external I2C sensors, while main processors are in deep sleep mode. ULP coprocessor can access RTC_SLOW_MEM memory region, and registers in RTC_CNTL, RTC_IO, and SARADC peripherals. ULP coprocessor uses fixed-width 32-bit instructions, 32-bit memory addressing, and has 4 general purpose 16-bit registers.

ULP coprocessor doesn’t have a dedicated binutils port yet. Programming ULP coprocessor is possible by embedding assembly-like macros into an ESP32 application. Here is an example how this can be done:

const ulp_insn_t program[] = {
    I_MOVI(R3, 16),         // R3 <- 16
    I_LD(R0, R3, 0),        // R0 <- RTC_SLOW_MEM[R3 + 0]
    I_LD(R1, R3, 1),        // R1 <- RTC_SLOW_MEM[R3 + 1]
    I_ADDR(R2, R0, R1),     // R2 <- R0 + R1
    I_ST(R2, R3, 2),        // R2 -> RTC_SLOW_MEM[R2 + 2]
    I_HALT()
};
size_t load_addr = 0;
size_t size = sizeof(program)/sizeof(ulp_insn_t);
ulp_process_macros_and_load(load_addr, program, &size);
ulp_run(load_addr);

The program array is an array of ulp_insn_t, i.e. ULP coprocessor instructions. Each I_XXX preprocessor define translates into a single 32-bit instruction. Arguments of these preprocessor defines can be register numbers (R0 R3) and literal constants. See ULP coprocessor instruction defines section for descriptions of instructions and arguments they take.

Load and store instructions use addresses expressed in 32-bit words. Address 0 corresponds to the first word of RTC_SLOW_MEM (which is address 0x50000000 as seen by the main CPUs).

To generate branch instructions, special M_ preprocessor defines are used. M_LABEL define can be used to define a branch target. Label identifier is a 16-bit integer. M_Bxxx defines can be used to generate branch instructions with target set to a particular label.

Implementation note: these M_ preprocessor defines will be translated into two ulp_insn_t values: one is a token value which contains label number, and the other is the actual instruction. ulp_process_macros_and_load function resolves the label number to the address, modifies the branch instruction to use the correct address, and removes the the extra ulp_insn_t token which contains the label numer.

Here is an example of using labels and branches:

const ulp_insn_t program[] = {
    I_MOVI(R0, 34),         // R0 <- 34
    M_LABEL(1),             // label_1
    I_MOVI(R1, 32),         // R1 <- 32
    I_LD(R1, R1, 0),        // R1 <- RTC_SLOW_MEM[R1]
    I_MOVI(R2, 33),         // R2 <- 33
    I_LD(R2, R2, 0),        // R2 <- RTC_SLOW_MEM[R2]
    I_SUBR(R3, R1, R2),     // R3 <- R1 - R2
    I_ST(R3, R0, 0),        // R3 -> RTC_SLOW_MEM[R0 + 0]
    I_ADDI(R0, R0, 1),      // R0++
    M_BL(1, 64),            // if (R0 < 64) goto label_1
    I_HALT(),
};
RTC_SLOW_MEM[32] = 42;
RTC_SLOW_MEM[33] = 18;
size_t load_addr = 0;
size_t size = sizeof(program)/sizeof(ulp_insn_t);
ulp_process_macros_and_load(load_addr, program, &size);
ulp_run(load_addr);

Functions

esp_err_t ulp_process_macros_and_load(uint32_t load_addr, const ulp_insn_t *program, size_t *psize)

Resolve all macro references in a program and load it into RTC memory.

Return
  • ESP_OK on success
  • ESP_ERR_NO_MEM if auxiliary temporary structure can not be allocated
  • one of ESP_ERR_ULP_xxx if program is not valid or can not be loaded
Parameters
  • load_addr: address where the program should be loaded, expressed in 32-bit words
  • program: ulp_insn_t array with the program
  • psize: size of the program, expressed in 32-bit words

esp_err_t ulp_run(uint32_t entry_point)

Run the program loaded into RTC memory.

Return
ESP_OK on success
Parameters
  • entry_point: entry point, expressed in 32-bit words

Error codes

ESP_ERR_ULP_BASE

Offset for ULP-related error codes

ESP_ERR_ULP_SIZE_TOO_BIG

Program doesn’t fit into RTC memory reserved for the ULP

ESP_ERR_ULP_INVALID_LOAD_ADDR

Load address is outside of RTC memory reserved for the ULP

ESP_ERR_ULP_DUPLICATE_LABEL

More than one label with the same number was defined

ESP_ERR_ULP_UNDEFINED_LABEL

Branch instructions references an undefined label

ESP_ERR_ULP_BRANCH_OUT_OF_RANGE

Branch target is out of range of B instruction (try replacing with BX)

ULP coprocessor registers

ULP co-processor has 4 16-bit general purpose registers. All registers have same functionality, with one exception. R0 register is used by some of the compare-and-branch instructions as a source register.

These definitions can be used for all instructions which require a register.

R0

general purpose register 0

R1

general purpose register 1

R2

general purpose register 2

R3

general purpose register 3

ULP coprocessor instruction defines

I_DELAY(cycles_)

Delay (nop) for a given number of cycles

I_HALT

Halt the coprocessor

I_END(wake)

End program.

If wake == 1, wake up main CPU.

I_ST(reg_val, reg_addr, offset_)

Store value from register reg_val into RTC memory.

The value is written to an offset calculated by adding value of reg_addr register and offset_ field (this offset is expressed in 32-bit words). 32 bits written to RTC memory are built as follows:

  • 5 MSBs are zero
  • next 11 bits hold the PC of current instruction, expressed in 32-bit words
  • next 16 bits hold the actual value to be written

RTC_SLOW_MEM[addr + offset_] = { 5’b0, insn_PC[10:0], val[15:0] }

I_LD(reg_dest, reg_addr, offset_)

Load value from RTC memory into reg_dest register.

Loads 16 LSBs from RTC memory word given by the sum of value in reg_addr and value of offset_.

I_WR_REG(reg, low_bit, high_bit, val)

Write literal value to a peripheral register

reg[high_bit : low_bit] = val This instruction can access RTC_CNTL_, RTC_IO_, and SENS_ peripheral registers.

I_RD_REG(reg, low_bit, high_bit, val)

Read from peripheral register into R0

R0 = reg[high_bit : low_bit] This instruction can access RTC_CNTL_, RTC_IO_, and SENS_ peripheral registers.

I_BL(pc_offset, imm_value)

Branch relative if R0 less than immediate value.

pc_offset is expressed in words, and can be from -127 to 127 imm_value is a 16-bit value to compare R0 against

I_BGE(pc_offset, imm_value)

Branch relative if R0 greater or equal than immediate value.

pc_offset is expressed in words, and can be from -127 to 127 imm_value is a 16-bit value to compare R0 against

I_BXR(reg_pc)

Unconditional branch to absolute PC, address in register.

reg_pc is the register which contains address to jump to. Address is expressed in 32-bit words.

I_BXI(imm_pc)

Unconditional branch to absolute PC, immediate address.

Address imm_pc is expressed in 32-bit words.

I_BXZR(reg_pc)

Branch to absolute PC if ALU result is zero, address in register.

reg_pc is the register which contains address to jump to. Address is expressed in 32-bit words.

I_BXZI(imm_pc)

Branch to absolute PC if ALU result is zero, immediate address.

Address imm_pc is expressed in 32-bit words.

I_BXFR(reg_pc)

Branch to absolute PC if ALU overflow, address in register

reg_pc is the register which contains address to jump to. Address is expressed in 32-bit words.

I_BXFI(imm_pc)

Branch to absolute PC if ALU overflow, immediate address

Address imm_pc is expressed in 32-bit words.

I_ADDR(reg_dest, reg_src1, reg_src2)

Addition: dest = src1 + src2

I_SUBR(reg_dest, reg_src1, reg_src2)

Subtraction: dest = src1 - src2

I_ANDR(reg_dest, reg_src1, reg_src2)

Logical AND: dest = src1 & src2

I_ORR(reg_dest, reg_src1, reg_src2)

Logical OR: dest = src1 | src2

I_MOVR(reg_dest, reg_src)

Copy: dest = src

I_LSHR(reg_dest, reg_src, reg_shift)

Logical shift left: dest = src << shift

I_RSHR(reg_dest, reg_src, reg_shift)

Logical shift right: dest = src >> shift

I_ADDI(reg_dest, reg_src, imm_)

Add register and an immediate value: dest = src1 + imm

I_SUBI(reg_dest, reg_src, imm_)

Subtract register and an immediate value: dest = src - imm

I_ANDI(reg_dest, reg_src, imm_)

Logical AND register and an immediate value: dest = src & imm

I_ORI(reg_dest, reg_src, imm_)

Logical OR register and an immediate value: dest = src | imm

I_MOVI(reg_dest, imm_)

Copy an immediate value into register: dest = imm

I_LSHI(reg_dest, reg_src, imm_)

Logical shift left register value by an immediate: dest = src << imm

I_RSHI(reg_dest, reg_src, imm_)

Logical shift right register value by an immediate: dest = val >> imm

M_LABEL(label_num)

Define a label with number label_num.

This is a macro which doesn’t generate a real instruction. The token generated by this macro is removed by ulp_process_macros_and_load function. Label defined using this macro can be used in branch macros defined below.

M_BL(label_num, imm_value)

Macro: branch to label label_num if R0 is less than immediate value.

This macro generates two ulp_insn_t values separated by a comma, and should be used when defining contents of ulp_insn_t arrays. First value is not a real instruction; it is a token which is removed by ulp_process_macros_and_load function.

M_BGE(label_num, imm_value)

Macro: branch to label label_num if R0 is greater or equal than immediate value

This macro generates two ulp_insn_t values separated by a comma, and should be used when defining contents of ulp_insn_t arrays. First value is not a real instruction; it is a token which is removed by ulp_process_macros_and_load function.

M_BX(label_num)

Macro: unconditional branch to label

This macro generates two ulp_insn_t values separated by a comma, and should be used when defining contents of ulp_insn_t arrays. First value is not a real instruction; it is a token which is removed by ulp_process_macros_and_load function.

M_BXZ(label_num)

Macro: branch to label if ALU result is zero

This macro generates two ulp_insn_t values separated by a comma, and should be used when defining contents of ulp_insn_t arrays. First value is not a real instruction; it is a token which is removed by ulp_process_macros_and_load function.

M_BXF(label_num)

Macro: branch to label if ALU overflow

This macro generates two ulp_insn_t values separated by a comma, and should be used when defining contents of ulp_insn_t arrays. First value is not a real instruction; it is a token which is removed by ulp_process_macros_and_load function.

Defines

RTC_SLOW_MEM

RTC slow memory, 8k size

Wi-Fi

Overview

Instructions

Application Example

Instructions

API Reference

Instructions

Macros

WIFI_INIT_CONFIG_DEFAULT

Type Definitions

typedef void (*wifi_promiscuous_cb_t)(void *buf, wifi_promiscuous_pkt_type_t type)

The RX callback function in the promiscuous mode. Each time a packet is received, the callback function will be called.

Parameters
  • buf: Data received. Type of data in buffer (wifi_promiscuous_pkt_t or wifi_pkt_rx_ctrl_t) indicated by ‘type’ parameter.
  • type: promiscuous packet type.

typedef void (*esp_vendor_ie_cb_t)(void *ctx, wifi_vendor_ie_type_t type, const uint8_t sa[6], const uint8_t *vnd_ie, int rssi)

Define function pointer for vendor specific element callback.

Parameters
  • ctx: reserved
  • type: information element type
  • sa: source address
  • vnd_ie: pointer to a vendor specific element
  • rssi: received signal strength indication

Functions

esp_err_t esp_wifi_init(wifi_init_config_t *config)

Init WiFi Alloc resource for WiFi driver, such as WiFi control structure, RX/TX buffer, WiFi NVS structure etc, this WiFi also start WiFi task.

Attention
1. This API must be called before all other WiFi API can be called
Attention
2. event_handler field in cfg should be set to a valid event handler function. In most cases, use the WIFI_INIT_CONFIG_DEFAULT macro which sets esp_event_send().
Return
  • ESP_OK: succeed
  • ESP_ERR_WIFI_NO_MEM: out of memory
  • others: refer to error code esp_err.h
Parameters
  • config: provide WiFi init configuration

esp_err_t esp_wifi_deinit(void)

Deinit WiFi Free all resource allocated in esp_wifi_init and stop WiFi task.

Attention
1. This API should be called if you want to remove WiFi driver from the system
Return
ESP_OK: succeed

esp_err_t esp_wifi_set_mode(wifi_mode_t mode)

Set the WiFi operating mode.

Set the WiFi operating mode as station, soft-AP or station+soft-AP, The default mode is soft-AP mode.

Return
  • ESP_OK: succeed
  • ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
  • ESP_ERR_WIFI_ARG: invalid argument
  • others: refer to error code in esp_err.h
Parameters
  • mode: WiFi operating mode

esp_err_t esp_wifi_get_mode(wifi_mode_t *mode)

Get current operating mode of WiFi.

Return
  • ESP_OK: succeed
  • ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
  • ESP_ERR_WIFI_ARG: invalid argument
Parameters
  • mode: store current WiFi mode

esp_err_t esp_wifi_start(void)

Start WiFi according to current configuration If mode is WIFI_MODE_STA, it create station control block and start station If mode is WIFI_MODE_AP, it create soft-AP control block and start soft-AP If mode is WIFI_MODE_APSTA, it create soft-AP and station control block and start soft-AP and station.

Return
  • ESP_OK: succeed
  • ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
  • ESP_ERR_WIFI_ARG: invalid argument
  • ESP_ERR_WIFI_NO_MEM: out of memory
  • ESP_ERR_WIFI_CONN: WiFi internal error, station or soft-AP control block wrong
  • ESP_ERR_WIFI_FAIL: other WiFi internal errors

esp_err_t esp_wifi_stop(void)

Stop WiFi If mode is WIFI_MODE_STA, it stop station and free station control block If mode is WIFI_MODE_AP, it stop soft-AP and free soft-AP control block If mode is WIFI_MODE_APSTA, it stop station/soft-AP and free station/soft-AP control block.

Return
  • ESP_OK: succeed
  • ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init

esp_err_t esp_wifi_connect(void)

Connect the ESP32 WiFi station to the AP.

Attention
1. This API only impact WIFI_MODE_STA or WIFI_MODE_APSTA mode
Attention
2. If the ESP32 is connected to an AP, call esp_wifi_disconnect to disconnect.
Return
  • ESP_OK: succeed
  • ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
  • ESP_ERR_WIFI_NOT_START: WiFi is not started by esp_wifi_start
  • ESP_ERR_WIFI_CONN: WiFi internal error, station or soft-AP control block wrong
  • ESP_ERR_WIFI_SSID: SSID of AP which station connects is invalid

esp_err_t esp_wifi_disconnect(void)

Disconnect the ESP32 WiFi station from the AP.

Return
  • ESP_OK: succeed
  • ESP_ERR_WIFI_NOT_INIT: WiFi was not initialized by eps_wifi_init
  • ESP_ERR_WIFI_NOT_STARTED: WiFi was not started by esp_wifi_start
  • ESP_ERR_WIFI_FAIL: other WiFi internal errors

esp_err_t esp_wifi_clear_fast_connect(void)

Currently this API is just an stub API.

Return
  • ESP_OK: succeed
  • others: fail

esp_err_t esp_wifi_deauth_sta(uint16_t aid)

deauthenticate all stations or associated id equals to aid

Return
  • ESP_OK: succeed
  • ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
  • ESP_ERR_WIFI_NOT_STARTED: WiFi was not started by esp_wifi_start
  • ESP_ERR_WIFI_ARG: invalid argument
  • ESP_ERR_WIFI_MODE: WiFi mode is wrong
Parameters
  • aid: when aid is 0, deauthenticate all stations, otherwise deauthenticate station whose associated id is aid

esp_err_t esp_wifi_scan_start(wifi_scan_config_t *config, bool block)

Scan all available APs.

Attention
If this API is called, the found APs are stored in WiFi driver dynamic allocated memory and the will be freed in esp_wifi_get_ap_list, so generally, call esp_wifi_get_ap_list to cause the memory to be freed once the scan is done
Return
  • ESP_OK: succeed
  • ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
  • ESP_ERR_WIFI_NOT_STARTED: WiFi was not started by esp_wifi_start
  • ESP_ERR_WIFI_TIMEOUT: blocking scan is timeout
  • others: refer to error code in esp_err.h
Parameters
  • config: configuration of scanning
  • block: if block is true, this API will block the caller until the scan is done, otherwise it will return immediately

esp_err_t esp_wifi_scan_stop(void)

Stop the scan in process.

Return
  • ESP_OK: succeed
  • ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
  • ESP_ERR_WIFI_NOT_STARTED: WiFi is not started by esp_wifi_start

esp_err_t esp_wifi_scan_get_ap_num(uint16_t *number)

Get number of APs found in last scan.

Attention
This API can only be called when the scan is completed, otherwise it may get wrong value.
Return
  • ESP_OK: succeed
  • ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
  • ESP_ERR_WIFI_NOT_STARTED: WiFi is not started by esp_wifi_start
  • ESP_ERR_WIFI_ARG: invalid argument
Parameters
  • number: store number of APIs found in last scan

esp_err_t esp_wifi_scan_get_ap_records(uint16_t *number, wifi_ap_record_t *ap_records)

Get AP list found in last scan.

Return
  • ESP_OK: succeed
  • ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
  • ESP_ERR_WIFI_NOT_STARTED: WiFi is not started by esp_wifi_start
  • ESP_ERR_WIFI_ARG: invalid argument
  • ESP_ERR_WIFI_NO_MEM: out of memory
Parameters
  • number: As input param, it stores max AP number ap_records can hold. As output param, it receives the actual AP number this API returns.
  • ap_records: wifi_ap_record_t array to hold the found APs

esp_err_t esp_wifi_sta_get_ap_info(wifi_ap_record_t *ap_info)

Get information of AP which the ESP32 station is associated with.

Return
  • ESP_OK: succeed
  • others: fail
Parameters
  • ap_info: the wifi_ap_record_t to hold AP information

esp_err_t esp_wifi_set_ps(wifi_ps_type_t type)

Set current power save type.

Attention
Default power save type is WIFI_PS_NONE.
Return
ESP_ERR_WIFI_NOT_SUPPORT: not supported yet
Parameters
  • type: power save type

esp_err_t esp_wifi_get_ps(wifi_ps_type_t *type)

Get current power save type.

Attention
Default power save type is WIFI_PS_NONE.
Return
ESP_ERR_WIFI_NOT_SUPPORT: not supported yet
Parameters
  • type: store current power save type

esp_err_t esp_wifi_set_protocol(wifi_interface_t ifx, uint8_t protocol_bitmap)

Set protocol type of specified interface The default protocol is (WIFI_PROTOCOL_11B|WIFI_PROTOCOL_11G|WIFI_PROTOCOL_11N)

Attention
Currently we only support 802.11b or 802.11bg or 802.11bgn mode
Return
  • ESP_OK: succeed
  • ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
  • ESP_ERR_WIFI_IF: invalid interface
  • others: refer to error codes in esp_err.h
Parameters
  • ifx: interfaces
  • protocol_bitmap: WiFi protocol bitmap

esp_err_t esp_wifi_get_protocol(wifi_interface_t ifx, uint8_t *protocol_bitmap)

Get the current protocol bitmap of the specified interface.

Return
  • ESP_OK: succeed
  • ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
  • ESP_ERR_WIFI_IF: invalid interface
  • ESP_ERR_WIFI_ARG: invalid argument
  • others: refer to error codes in esp_err.h
Parameters
  • ifx: interface
  • protocol_bitmap: store current WiFi protocol bitmap of interface ifx

esp_err_t esp_wifi_set_bandwidth(wifi_interface_t ifx, wifi_bandwidth_t bw)

Set the bandwidth of ESP32 specified interface.

Attention
1. API return false if try to configure an interface that is not enabled
Attention
2. WIFI_BW_HT40 is supported only when the interface support 11N
Return
  • ESP_OK: succeed
  • ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
  • ESP_ERR_WIFI_IF: invalid interface
  • ESP_ERR_WIFI_ARG: invalid argument
  • others: refer to error codes in esp_err.h
Parameters
  • ifx: interface to be configured
  • bw: bandwidth

esp_err_t esp_wifi_get_bandwidth(wifi_interface_t ifx, wifi_bandwidth_t *bw)

Get the bandwidth of ESP32 specified interface.

Attention
1. API return false if try to get a interface that is not enable
Return
  • ESP_OK: succeed
  • ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
  • ESP_ERR_WIFI_IF: invalid interface
  • ESP_ERR_WIFI_ARG: invalid argument
Parameters
  • ifx: interface to be configured
  • bw: store bandwidth of interface ifx

esp_err_t esp_wifi_set_channel(uint8_t primary, wifi_second_chan_t second)

Set primary/secondary channel of ESP32.

Attention
1. This is a special API for sniffer
Return
  • ESP_OK: succeed
  • ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
  • ESP_ERR_WIFI_IF: invalid interface
  • ESP_ERR_WIFI_ARG: invalid argument
Parameters
  • primary: for HT20, primary is the channel number, for HT40, primary is the primary channel
  • second: for HT20, second is ignored, for HT40, second is the second channel

esp_err_t esp_wifi_get_channel(uint8_t *primary, wifi_second_chan_t *second)

Get the primary/secondary channel of ESP32.

Attention
1. API return false if try to get a interface that is not enable
Return
  • ESP_OK: succeed
  • ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
  • ESP_ERR_WIFI_ARG: invalid argument
Parameters
  • primary: store current primary channel
  • second: store current second channel

esp_err_t esp_wifi_set_country(wifi_country_t country)

Set country code The default value is WIFI_COUNTRY_CN.

Return
  • ESP_OK: succeed
  • ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
  • ESP_ERR_WIFI_ARG: invalid argument
  • others: refer to error code in esp_err.h
Parameters
  • country: country type

esp_err_t esp_wifi_get_country(wifi_country_t *country)

Get country code.

Return
  • ESP_OK: succeed
  • ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
  • ESP_ERR_WIFI_ARG: invalid argument
Parameters
  • country: store current country

esp_err_t esp_wifi_set_mac(wifi_interface_t ifx, uint8_t mac[6])

Set MAC address of the ESP32 WiFi station or the soft-AP interface.

Attention
1. This API can only be called when the interface is disabled
Attention
2. ESP32 soft-AP and station have different MAC addresses, do not set them to be the same.
Attention
3. The bit 0 of the first byte of ESP32 MAC address can not be 1. For example, the MAC address can set to be “1a:XX:XX:XX:XX:XX”, but can not be “15:XX:XX:XX:XX:XX”.
Return
  • ESP_OK: succeed
  • ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
  • ESP_ERR_WIFI_ARG: invalid argument
  • ESP_ERR_WIFI_IF: invalid interface
  • ESP_ERR_WIFI_MAC: invalid mac address
  • ESP_ERR_WIFI_MODE: WiFi mode is wrong
  • others: refer to error codes in esp_err.h
Parameters
  • ifx: interface
  • mac: the MAC address

esp_err_t esp_wifi_get_mac(wifi_interface_t ifx, uint8_t mac[6])

Get mac of specified interface.

Return
  • ESP_OK: succeed
  • ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
  • ESP_ERR_WIFI_ARG: invalid argument
  • ESP_ERR_WIFI_IF: invalid interface
Parameters
  • ifx: interface
  • mac: store mac of the interface ifx

esp_err_t esp_wifi_set_promiscuous_rx_cb(wifi_promiscuous_cb_t cb)

Register the RX callback function in the promiscuous mode.

Each time a packet is received, the registered callback function will be called.

Return
  • ESP_OK: succeed
  • ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
Parameters
  • cb: callback

esp_err_t esp_wifi_set_promiscuous(bool en)

Enable the promiscuous mode.

Return
  • ESP_OK: succeed
  • ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
Parameters
  • en: false - disable, true - enable

esp_err_t esp_wifi_get_promiscuous(bool *en)

Get the promiscuous mode.

Return
  • ESP_OK: succeed
  • ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
  • ESP_ERR_WIFI_ARG: invalid argument
Parameters
  • en: store the current status of promiscuous mode

esp_err_t esp_wifi_set_config(wifi_interface_t ifx, wifi_config_t *conf)

Set the configuration of the ESP32 STA or AP.

Attention
1. This API can be called only when specified interface is enabled, otherwise, API fail
Attention
2. For station configuration, bssid_set needs to be 0; and it needs to be 1 only when users need to check the MAC address of the AP.
Attention
3. ESP32 is limited to only one channel, so when in the soft-AP+station mode, the soft-AP will adjust its channel automatically to be the same as the channel of the ESP32 station.
Return
  • ESP_OK: succeed
  • ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
  • ESP_ERR_WIFI_ARG: invalid argument
  • ESP_ERR_WIFI_IF: invalid interface
  • ESP_ERR_WIFI_MODE: invalid mode
  • ESP_ERR_WIFI_PASSWORD: invalid password
  • ESP_ERR_WIFI_NVS: WiFi internal NVS error
  • others: refer to the erro code in esp_err.h
Parameters
  • ifx: interface
  • conf: station or soft-AP configuration

esp_err_t esp_wifi_get_config(wifi_interface_t ifx, wifi_config_t *conf)

Get configuration of specified interface.

Return
  • ESP_OK: succeed
  • ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
  • ESP_ERR_WIFI_ARG: invalid argument
  • ESP_ERR_WIFI_IF: invalid interface
Parameters
  • ifx: interface
  • conf: station or soft-AP configuration

esp_err_t esp_wifi_ap_get_sta_list(wifi_sta_list_t *sta)

Get STAs associated with soft-AP.

Attention
SSC only API
Return
  • ESP_OK: succeed
  • ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
  • ESP_ERR_WIFI_ARG: invalid argument
  • ESP_ERR_WIFI_MODE: WiFi mode is wrong
  • ESP_ERR_WIFI_CONN: WiFi internal error, the station/soft-AP control block is invalid
Parameters
  • sta: station list

esp_err_t esp_wifi_set_storage(wifi_storage_t storage)

Set the WiFi API configuration storage type.

Attention
1. The default value is WIFI_STORAGE_FLASH
Return
  • ESP_OK: succeed
  • ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
  • ESP_ERR_WIFI_ARG: invalid argument
Parameters
  • storage: : storage type

esp_err_t esp_wifi_set_auto_connect(bool en)

Set auto connect The default value is true.

Return
  • ESP_OK: succeed
  • ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
  • ESP_ERR_WIFI_MODE: WiFi internal error, the station/soft-AP control block is invalid
  • others: refer to error code in esp_err.h
Parameters
  • en: : true - enable auto connect / false - disable auto connect

esp_err_t esp_wifi_get_auto_connect(bool *en)

Get the auto connect flag.

Return
  • ESP_OK: succeed
  • ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
  • ESP_ERR_WIFI_ARG: invalid argument
Parameters
  • en: store current auto connect configuration

esp_err_t esp_wifi_set_vendor_ie(bool enable, wifi_vendor_ie_type_t type, wifi_vendor_ie_id_t idx, uint8_t *vnd_ie)

Set vendor specific element.

Return
  • ESP_OK: succeed
  • ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
  • ESP_ERR_WIFI_ARG: invalid argument
  • ESP_ERR_WIFI_NO_MEM: out of memory
Parameters
  • enable: enable or not
  • type: information element type
  • idx: information element index
  • vnd_ie: pointer to a vendor specific element

esp_err_t esp_wifi_set_vendor_ie_cb(esp_vendor_ie_cb_t cb, void *ctx)

Set vendor specific element callback.

Return
  • ESP_OK: succeed
  • ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
Parameters
  • cb: callback function
  • ctx: reserved

Smart Config ===

API Reference

Type Definitions

typedef void (*sc_callback_t)(smartconfig_status_t status, void *pdata)

The callback of SmartConfig, executed when smart-config status changed.

Parameters
  • status: Status of SmartConfig:
    • SC_STATUS_GETTING_SSID_PSWD : pdata is a pointer of smartconfig_type_t, means config type.
    • SC_STATUS_LINK : pdata is a pointer of struct station_config.
    • SC_STATUS_LINK_OVER : pdata is a pointer of phone’s IP address(4 bytes) if pdata unequal NULL.
    • otherwise : parameter void *pdata is NULL.
  • pdata: According to the different status have different values.

Functions

const char *esp_smartconfig_get_version(void)

Get the version of SmartConfig.

Return
  • SmartConfig version const char.

esp_err_t esp_smartconfig_start(sc_callback_t cb, ...)

Start SmartConfig, config ESP device to connect AP. You need to broadcast information by phone APP. Device sniffer special packets from the air that containing SSID and password of target AP.

Attention
1. This API can be called in station or softAP-station mode.
Attention
2. Can not call esp_smartconfig_start twice before it finish, please call esp_smartconfig_stop first.
Return
  • ESP_OK: succeed
  • others: fail
Parameters
  • cb: SmartConfig callback function.
  • ...: log 1: UART output logs; 0: UART only outputs the result.

esp_err_t esp_smartconfig_stop(void)

Stop SmartConfig, free the buffer taken by esp_smartconfig_start.

Attention
Whether connect to AP succeed or not, this API should be called to free memory taken by smartconfig_start.
Return
  • ESP_OK: succeed
  • others: fail

esp_err_t esp_esptouch_set_timeout(uint8_t time_s)

Set timeout of SmartConfig process.

Attention
Timing starts from SC_STATUS_FIND_CHANNEL status. SmartConfig will restart if timeout.
Return
  • ESP_OK: succeed
  • others: fail
Parameters
  • time_s: range 15s~255s, offset:45s.

esp_err_t esp_smartconfig_set_type(smartconfig_type_t type)

Set protocol type of SmartConfig.

Attention
If users need to set the SmartConfig type, please set it before calling esp_smartconfig_start.
Return
  • ESP_OK: succeed
  • others: fail
Parameters
  • type: Choose from the smartconfig_type_t.

esp_err_t esp_smartconfig_fast_mode(bool enable)

Set mode of SmartConfig. default normal mode.

Attention
1. Please call it before API esp_smartconfig_start.
Attention
2. Fast mode have corresponding APP(phone).
Attention
3. Two mode is compatible.
Return
  • ESP_OK: succeed
  • others: fail
Parameters
  • enable: false-disable(default); true-enable;

Bluetooth

Controller && VHCI

Overview

Instructions

Application Example

Check /examples folder of espressif/esp-idf repository, that contains the following example:

05_ble_adv

This is a BLE advertising demo with virtual HCI interface. Send Reset/ADV_PARAM/ADV_DATA/ADV_ENABLE HCI command for BLE advertising.

Instructions

API Reference

Header Files
Type Definitions
typedef struct esp_vhci_host_callback esp_vhci_host_callback_t

esp_vhci_host_callback used for vhci call host function to notify what host need to do

Enumerations
Structures
struct esp_vhci_host_callback

esp_vhci_host_callback used for vhci call host function to notify what host need to do

Public Members

void (*notify_host_send_available)(void)

callback used to notify that the host can send packet to controller

int (*notify_host_recv)(uint8_t *data, uint16_t len)

callback used to notify that the controller has a packet to send to the host

Functions
void esp_bt_controller_init(void)

Initialize BT controller.

This function should be called only once, before any other BT functions are called.

bool esp_vhci_host_check_send_available(void)

esp_vhci_host_check_send_available used for check actively if the host can send packet to controller or not.

Return
true for ready to send, false means cannot send packet

void esp_vhci_host_send_packet(uint8_t *data, uint16_t len)

esp_vhci_host_send_packet host send packet to controller

Parameters
  • data: the packet point ,
  • len: the packet length

void esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callback)

esp_vhci_host_register_callback register the vhci referece callback, the call back struct defined by vhci_host_callback structure.

Parameters

BT COMMON

BT GENERIC DEFINES

Overview

Instructions

Application Example

Instructions

API Reference
Macros
ESP_DEFAULT_GATT_IF

Default GATT interface id.

ESP_BLE_CONN_PARAM_UNDEF

Default BLE connection param, if the value doesn’t be overwritten.

ESP_BLE_IS_VALID_PARAM(x, min, max)

Check the param is valid or not.

ESP_UUID_LEN_16
ESP_UUID_LEN_32
ESP_UUID_LEN_128
ESP_BD_ADDR_LEN

Bluetooth address length.

ESP_APP_ID_MIN

Minimum of the application id.

ESP_APP_ID_MAX

Maximum of the application id.

Type Definitions
typedef uint8_t esp_bd_addr_t[ESP_BD_ADDR_LEN]

Bluetooth device address.

Enumerations
enum esp_bt_status_t

Status Return Value.

Values:

ESP_BT_STATUS_SUCCESS = 0
ESP_BT_STATUS_FAILURE = 1
ESP_BT_STATUS_PENDING = 2
ESP_BT_STATUS_BUSY = 3
ESP_BT_STATUS_NO_RESOURCES = 4
ESP_BT_STATUS_WRONG_MODE = 5
enum esp_bt_dev_type_t

Bluetooth device type.

Values:

ESP_BT_DEVICE_TYPE_BREDR = 0x01
ESP_BT_DEVICE_TYPE_BLE = 0x02
ESP_BT_DEVICE_TYPE_DUMO = 0x03
enum esp_bd_addr_type_t

Own BD address source of the device.

Values:

BD_ADDR_PUBLIC

Public Address.

BD_ADDR_PROVIDED_RND

Provided random address.

BD_ADDR_GEN_STATIC_RND

Provided static random address.

BD_ADDR_GEN_RSLV

Generated resolvable private random address.

BD_ADDR_GEN_NON_RSLV

Generated non-resolvable private random address.

BD_ADDR_PROVIDED_RECON

Provided Reconnection address.

enum esp_ble_addr_type_t

BLE device address type.

Values:

BLE_ADDR_TYPE_PUBLIC = 0x00
BLE_ADDR_TYPE_RANDOM = 0x01
BLE_ADDR_TYPE_RPA_PUBLIC = 0x02
BLE_ADDR_TYPE_RPA_RANDOM = 0x03
Structures
Functions

BT MAIN API

Overview

Instructions

Application Example

Instructions

API Reference
Macros
Type Definitions
Enumerations
enum esp_bluedroid_status_t

Bluetooth stack status type, to indicate whether the bluetooth stack is ready.

Values:

ESP_BLUEDROID_STATUS_UNINITIALIZED = 0

Bluetooth not initialized

ESP_BLUEDROID_STATUS_INITIALIZED

Bluetooth initialized but not enabled

ESP_BLUEDROID_STATUS_ENABLED

Bluetooth initialized and enabled

Structures
Functions
esp_bluedroid_status_t esp_bluedroid_get_status(void)

Get bluetooth stack status.

Return
Bluetooth stack status

esp_err_t esp_bluedroid_enable(void)

Enable bluetooth, must after esp_bluedroid_init()

Return
  • ESP_OK : Succeed
  • Other : Failed

esp_err_t esp_bluedroid_disable(void)

Disable bluetooth, must prior to esp_bluedroid_deinit()

Return
  • ESP_OK : Succeed
  • Other : Failed

esp_err_t esp_bluedroid_init(void)

Init and alloc the resource for bluetooth, must be prior to every bluetooth stuff.

Return
  • ESP_OK : Succeed
  • Other : Failed

esp_err_t esp_bluedroid_deinit(void)

Deinit and free the resource for bluetooth, must be after every bluetooth stuff.

Return
  • ESP_OK : Succeed
  • Other : Failed

BT DEVICE APIs

Overview

Bluetooth device reference APIs.

Instructions

Application Example

Instructions

API Reference
Macros
Type Definitions
Enumerations
Structures
Functions
const uint8_t *esp_bt_dev_get_address(void)

Get bluetooth device address. Must use after “esp_bluedroid_enable”.

Return
bluetooth device address (six bytes), or NULL if bluetooth stack is not enabled

BT COMMON

GAP API

Overview

Instructions

Application Example

Check /examples folder of espressif/esp-idf repository, that contains the following example:

14_gatts_demo 15_gattc_demo

The two demos use different gap api, such like advertising, scan, set device name and others.

Instructions

API Reference
Macros
ESP_BLE_ADV_FLAG_LIMIT_DISC

BLE_ADV_DATA_FLAG data flag bit definition used for advertising data flag

ESP_BLE_ADV_FLAG_GEN_DISC
ESP_BLE_ADV_FLAG_BREDR_NOT_SPT
ESP_BLE_ADV_FLAG_DMT_CONTROLLER_SPT
ESP_BLE_ADV_FLAG_DMT_HOST_SPT
ESP_BLE_ADV_FLAG_NON_LIMIT_DISC
ESP_BLE_ADV_DATA_LEN_MAX

Advertising data maximum length.

Type Definitions
typedef void (*esp_gap_ble_cb_t)(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)

GAP callback function type.

Parameters
  • event: : Event type
  • param: : Point to callback parameter, currently is union type

Enumerations
enum esp_gap_ble_cb_event_t

GAP BLE callback event type.

Values:

ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT = 0

When advertising data set complete, the event comes

ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT

When scan response data set complete, the event comes

ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT

When scan parameters set complete, the event comes

ESP_GAP_BLE_SCAN_RESULT_EVT

When one scan result ready, the event comes each time

enum esp_ble_adv_data_type

The type of advertising data(not adv_type)

Values:

ESP_BLE_AD_TYPE_FLAG = 0x01
ESP_BLE_AD_TYPE_16SRV_PART = 0x02
ESP_BLE_AD_TYPE_16SRV_CMPL = 0x03
ESP_BLE_AD_TYPE_32SRV_PART = 0x04
ESP_BLE_AD_TYPE_32SRV_CMPL = 0x05
ESP_BLE_AD_TYPE_128SRV_PART = 0x06
ESP_BLE_AD_TYPE_128SRV_CMPL = 0x07
ESP_BLE_AD_TYPE_NAME_SHORT = 0x08
ESP_BLE_AD_TYPE_NAME_CMPL = 0x09
ESP_BLE_AD_TYPE_TX_PWR = 0x0A
ESP_BLE_AD_TYPE_DEV_CLASS = 0x0D
ESP_BLE_AD_TYPE_SM_TK = 0x10
ESP_BLE_AD_TYPE_SM_OOB_FLAG = 0x11
ESP_BLE_AD_TYPE_INT_RANGE = 0x12
ESP_BLE_AD_TYPE_SOL_SRV_UUID = 0x14
ESP_BLE_AD_TYPE_128SOL_SRV_UUID = 0x15
ESP_BLE_AD_TYPE_SERVICE_DATA = 0x16
ESP_BLE_AD_TYPE_PUBLIC_TARGET = 0x17
ESP_BLE_AD_TYPE_RANDOM_TARGET = 0x18
ESP_BLE_AD_TYPE_APPEARANCE = 0x19
ESP_BLE_AD_TYPE_ADV_INT = 0x1A
ESP_BLE_AD_TYPE_32SOL_SRV_UUID = 0x1B
ESP_BLE_AD_TYPE_32SERVICE_DATA = 0x1C
ESP_BLE_AD_TYPE_128SERVICE_DATA = 0x1D
ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE = 0xFF
enum esp_ble_adv_type_t

Advertising mode.

Values:

ADV_TYPE_IND = 0x00
ADV_TYPE_DIRECT_IND_HIGH = 0x01
ADV_TYPE_SCAN_IND = 0x02
ADV_TYPE_NONCONN_IND = 0x03
ADV_TYPE_DIRECT_IND_LOW = 0x04
enum esp_ble_adv_channel_t

Advertising channel mask.

Values:

ADV_CHNL_37 = 0x01
ADV_CHNL_38 = 0x02
ADV_CHNL_39 = 0x03
ADV_CHNL_ALL = 0x07
enum esp_ble_adv_filter_t

Values:

ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY = 0x00

Allow both scan and connection requests from anyone.

ADV_FILTER_ALLOW_SCAN_WLST_CON_ANY

Allow both scan req from White List devices only and connection req from anyone.

ADV_FILTER_ALLOW_SCAN_ANY_CON_WLST

Allow both scan req from anyone and connection req from White List devices only.

ADV_FILTER_ALLOW_SCAN_WLST_CON_WLST

Allow scan and connection requests from White List devices only.

enum esp_ble_own_addr_src_t

Own BD address source of the device.

Values:

ESP_PUBLIC_ADDR

Public Address.

ESP_PROVIDED_RND_ADDR

Provided random address.

ESP_GEN_STATIC_RND_ADDR

Provided static random address.

ESP_GEN_RSLV_ADDR

Generated resolvable private random address.

ESP_GEN_NON_RSLV_ADDR

Generated non-resolvable private random address.

ESP_PROVIDED_RECON_ADDR

Provided Reconnection address.

enum esp_ble_scan_type_t

Ble scan type.

Values:

BLE_SCAN_TYPE_PASSIVE = 0x0

Passive scan

BLE_SCAN_TYPE_ACTIVE = 0x1

Active scan

enum esp_ble_scan_filter_t

Ble scan filter type.

Values:

BLE_SCAN_FILTER_ALLOW_ALL = 0x0

Accept all :

  1. advertisement packets except directed advertising packets not addressed to this device (default).

BLE_SCAN_FILTER_ALLOW_ONLY_WLST = 0x1

Accept only :

  1. advertisement packets from devices where the advertiser’s address is in the White list.
  2. Directed advertising packets which are not addressed for this device shall be ignored.

BLE_SCAN_FILTER_ALLOW_UND_RPA_DIR = 0x2

Accept all :

  1. undirected advertisement packets, and
  2. directed advertising packets where the initiator address is a resolvable private address, and
  3. directed advertising packets addressed to this device.

BLE_SCAN_FILTER_ALLOW_WLIST_PRA_DIR = 0x3

Accept all :

  1. advertisement packets from devices where the advertiser’s address is in the White list, and
  2. directed advertising packets where the initiator address is a resolvable private address, and
  3. directed advertising packets addressed to this device.

enum esp_gap_search_evt_t

Sub Event of ESP_GAP_BLE_SCAN_RESULT_EVT.

Values:

ESP_GAP_SEARCH_INQ_RES_EVT = 0

Inquiry result for a peer device.

ESP_GAP_SEARCH_INQ_CMPL_EVT = 1

Inquiry complete.

ESP_GAP_SEARCH_DISC_RES_EVT = 2

Discovery result for a peer device.

ESP_GAP_SEARCH_DISC_BLE_RES_EVT = 3

Discovery result for BLE GATT based service on a peer device.

ESP_GAP_SEARCH_DISC_CMPL_EVT = 4

Discovery complete.

ESP_GAP_SEARCH_DI_DISC_CMPL_EVT = 5

Discovery complete.

ESP_GAP_SEARCH_SEARCH_CANCEL_CMPL_EVT = 6

Search cancelled

enum esp_ble_evt_type_t

Ble scan result event type, to indicate the result is scan response or advertising data or other.

Values:

ESP_BLE_EVT_CONN_ADV = 0x00

Connectable undirected advertising (ADV_IND)

ESP_BLE_EVT_CONN_DIR_ADV = 0x01

Connectable directed advertising (ADV_DIRECT_IND)

ESP_BLE_EVT_DISC_ADV = 0x02

Scannable undirected advertising (ADV_SCAN_IND)

ESP_BLE_EVT_NON_CONN_ADV = 0x03

Non connectable undirected advertising (ADV_NONCONN_IND)

ESP_BLE_EVT_SCAN_RSP = 0x04

Scan Response (SCAN_RSP)

Structures
struct esp_ble_adv_params_t

Advertising parameters.

Public Members

uint16_t adv_int_min

Minimum advertising interval for undirected and low duty cycle directed advertising. Range: 0x0020 to 0x4000 Default: N = 0x0800 (1.28 second) Time = N * 0.625 msec Time Range: 20 ms to 10.24 sec

uint16_t adv_int_max

Maximum advertising interval for undirected and low duty cycle directed advertising. Range: 0x0020 to 0x4000 Default: N = 0x0800 (1.28 second) Time = N * 0.625 msec Time Range: 20 ms to 10.24 sec Advertising max interval

esp_ble_adv_type_t adv_type

Advertising type

esp_ble_addr_type_t own_addr_type

Owner bluetooth device address type

esp_bd_addr_t peer_addr

Peer device bluetooth device address

esp_ble_addr_type_t peer_addr_type

Peer device bluetooth device address type

esp_ble_adv_channel_t channel_map

Advertising channel map

esp_ble_adv_filter_t adv_filter_policy

Advertising filter policy

struct esp_ble_adv_data_t

Advertising data content, according to “Supplement to the Bluetooth Core Specification”.

Public Members

bool set_scan_rsp

Set this advertising data as scan response or not

bool include_name

Advertising data include device name or not

bool include_txpower

Advertising data include TX power

int min_interval

Advertising data show advertising min interval

int max_interval

Advertising data show advertising max interval

int appearance

External appearance of device

uint16_t manufacturer_len

Manufacturer data length

uint8_t *p_manufacturer_data

Manufacturer data point

uint16_t service_data_len

Service data length

uint8_t *p_service_data

Service data point

uint16_t service_uuid_len

Service uuid length

uint8_t *p_service_uuid

Service uuid array point

uint8_t flag

Advertising flag of discovery mode, see BLE_ADV_DATA_FLAG detail

struct esp_ble_scan_params_t

Ble scan parameters.

Public Members

esp_ble_scan_type_t scan_type

Scan type

esp_ble_addr_type_t own_addr_type

Owner address type

esp_ble_scan_filter_t scan_filter_policy

Scan filter policy

uint16_t scan_interval

Scan interval. This is defined as the time interval from when the Controller started its last LE scan until it begins the subsequent LE scan. Range: 0x0004 to 0x4000 Default: 0x0010 (10 ms) Time = N * 0.625 msec Time Range: 2.5 msec to 10.24 seconds

uint16_t scan_window

Scan window. The duration of the LE scan. LE_Scan_Window shall be less than or equal to LE_Scan_Interval Range: 0x0004 to 0x4000 Default: 0x0010 (10 ms) Time = N * 0.625 msec Time Range: 2.5 msec to 10240 msec

struct esp_ble_conn_update_params_t

Connection update parameters.

Public Members

esp_bd_addr_t bda

Bluetooth device address

uint16_t min_int

Min connection interval

uint16_t max_int

Max connection interval

uint16_t latency

Slave latency for the connection in number of connection events. Range: 0x0000 to 0x01F3

uint16_t timeout

Supervision timeout for the LE Link. Range: 0x000A to 0x0C80. Mandatory Range: 0x000A to 0x0C80 Time = N * 10 msec Time Range: 100 msec to 32 seconds

Warning

doxygenstruct: Cannot find class “esp_ble_gap_cb_param_t” in doxygen xml output for project “esp32-idf” from directory: xml/

struct esp_ble_gap_cb_param_t::ble_adv_data_cmpl_evt_param

ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT.

Public Members

esp_bt_status_t status

Indicate the set advertising data operation success status

struct esp_ble_gap_cb_param_t::ble_scan_rsp_data_cmpl_evt_param

ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT.

Public Members

esp_bt_status_t status

Indicate the set scan response data operation success status

struct esp_ble_gap_cb_param_t::ble_scan_param_cmpl_evt_param

ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT.

Public Members

esp_bt_status_t status

Indicate the set scan param operation success status

struct esp_ble_gap_cb_param_t::ble_scan_result_evt_param

ESP_GAP_BLE_SCAN_RESULT_EVT.

Public Members

esp_gap_search_evt_t search_evt

Search event type

esp_bd_addr_t bda

Bluetooth device address which has been searched

esp_bt_dev_type_t dev_type

Device type

esp_ble_addr_type_t ble_addr_type

Ble device address type

esp_ble_evt_type_t ble_evt_type

Ble scan result event type

int rssi

Searched device’s RSSI

uint8_t ble_adv[ESP_BLE_ADV_DATA_LEN_MAX+ESP_BLE_SCAN_RSP_DATA_LEN_MAX]

Received EIR

int flag

Advertising data flag bit

int num_resps

Scan result number

Functions
esp_err_t esp_ble_gap_register_callback(esp_gap_ble_cb_t callback)

This function is called to occur gap event, such as scan result.

Return
  • ESP_OK : success
  • other : failed
Parameters
  • callback: callback function

esp_err_t esp_ble_gap_config_adv_data(esp_ble_adv_data_t *adv_data)

This function is called to override the BTA default ADV parameters.

Return
  • ESP_OK : success
  • other : failed
Parameters
  • adv_data: Pointer to User defined ADV data structure. This memory space can not be freed until callback of config_adv_data is received.

esp_err_t esp_ble_gap_set_scan_params(esp_ble_scan_params_t *scan_params)

This function is called to set scan parameters.

Return
  • ESP_OK : success
  • other : failed
Parameters
  • scan_params: Pointer to User defined scan_params data structure. This memory space can not be freed until callback of set_scan_params

esp_err_t esp_ble_gap_start_scanning(uint32_t duration)

This procedure keep the device scanning the peer device which advertising on the air.

Return
  • ESP_OK : success
  • other : failed
Parameters
  • duration: Keeping the scanning time, the unit is second.

esp_err_t esp_ble_gap_stop_scanning(void)

This function call to stop the device scanning the peer device which advertising on the air.

Return
  • ESP_OK : success
    • other : failed

esp_err_t esp_ble_gap_start_advertising(esp_ble_adv_params_t *adv_params)

This function is called to start advertising.

Return
  • ESP_OK : success
  • other : failed
Parameters
  • adv_params: pointer to User defined adv_params data structure.

esp_err_t esp_ble_gap_stop_advertising(void)

This function is called to stop advertising.

Return
  • ESP_OK : success
  • other : failed

esp_err_t esp_ble_gap_update_conn_params(esp_ble_conn_update_params_t *params)

Update connection parameters, can only be used when connection is up.

Return
  • ESP_OK : success
  • other : failed
Parameters
  • params: - connection update parameters

esp_err_t esp_ble_gap_set_pkt_data_len(esp_bd_addr_t remote_device, uint16_t tx_data_length)

This function is to set maximum LE data packet size.

Return
  • ESP_OK : success
  • other : failed

esp_err_t esp_ble_gap_set_rand_addr(esp_bd_addr_t rand_addr)

This function set the random address for the application.

Return
  • ESP_OK : success
  • other : failed
Parameters
  • rand_addr: the random address which should be setting

esp_err_t esp_ble_gap_config_local_privacy(bool privacy_enable)

Enable/disable privacy on the local device.

Return
  • ESP_OK : success
  • other : failed
Parameters
  • privacy_enable: - enable/disable privacy on remote device.

esp_err_t esp_ble_gap_set_device_name(const char *name)

Set device name to the local device.

Return
  • ESP_OK : success
  • other : failed
Parameters
  • name: - device name.

uint8_t *esp_ble_resolve_adv_data(uint8_t *adv_data, uint8_t type, uint8_t *length)

This function is called to get ADV data for a specific type.

Return
- ESP_OK : success
  • other : failed
Parameters
  • adv_data: - pointer of ADV data which to be resolved
  • type: - finding ADV data type
  • length: - return the length of ADV data not including type

GATT DEFINES

Overview

Instructions

Application Example

Instructions

API Reference
Macros
ESP_GATT_UUID_IMMEDIATE_ALERT_SVC

All “ESP_GATT_UUID_xxx” is attribute types

ESP_GATT_UUID_TX_POWER_SVC
ESP_GATT_UUID_CURRENT_TIME_SVC
ESP_GATT_UUID_REF_TIME_UPDATE_SVC
ESP_GATT_UUID_NEXT_DST_CHANGE_SVC
ESP_GATT_UUID_GLUCOSE_SVC
ESP_GATT_UUID_HEALTH_THERMOM_SVC
ESP_GATT_UUID_DEVICE_INFO_SVC
ESP_GATT_UUID_HEART_RATE_SVC
ESP_GATT_UUID_PHONE_ALERT_STATUS_SVC
ESP_GATT_UUID_BATTERY_SERVICE_SVC
ESP_GATT_UUID_BLOOD_PRESSURE_SVC
ESP_GATT_UUID_ALERT_NTF_SVC
ESP_GATT_UUID_HID_SVC
ESP_GATT_UUID_SCAN_PARAMETERS_SVC
ESP_GATT_UUID_RUNNING_SPEED_CADENCE_SVC
ESP_GATT_UUID_CYCLING_SPEED_CADENCE_SVC
ESP_GATT_UUID_CYCLING_POWER_SVC
ESP_GATT_UUID_LOCATION_AND_NAVIGATION_SVC
ESP_GATT_UUID_USER_DATA_SVC
ESP_GATT_UUID_WEIGHT_SCALE_SVC
ESP_GATT_UUID_PRI_SERVICE
ESP_GATT_UUID_SEC_SERVICE
ESP_GATT_UUID_INCLUDE_SERVICE
ESP_GATT_UUID_CHAR_DECLARE
ESP_GATT_UUID_CHAR_EXT_PROP
ESP_GATT_UUID_CHAR_DESCRIPTION
ESP_GATT_UUID_CHAR_CLIENT_CONFIG
ESP_GATT_UUID_CHAR_SRVR_CONFIG
ESP_GATT_UUID_CHAR_PRESENT_FORMAT
ESP_GATT_UUID_CHAR_AGG_FORMAT
ESP_GATT_UUID_CHAR_VALID_RANGE
ESP_GATT_UUID_EXT_RPT_REF_DESCR
ESP_GATT_UUID_RPT_REF_DESCR
ESP_GATT_UUID_GAP_DEVICE_NAME
ESP_GATT_UUID_GAP_ICON
ESP_GATT_UUID_GAP_PREF_CONN_PARAM
ESP_GATT_UUID_GAP_CENTRAL_ADDR_RESOL
ESP_GATT_UUID_GATT_SRV_CHGD
ESP_GATT_UUID_ALERT_LEVEL
ESP_GATT_UUID_TX_POWER_LEVEL
ESP_GATT_UUID_CURRENT_TIME
ESP_GATT_UUID_LOCAL_TIME_INFO
ESP_GATT_UUID_REF_TIME_INFO
ESP_GATT_UUID_NW_STATUS
ESP_GATT_UUID_NW_TRIGGER
ESP_GATT_UUID_ALERT_STATUS
ESP_GATT_UUID_RINGER_CP
ESP_GATT_UUID_RINGER_SETTING
ESP_GATT_UUID_GM_MEASUREMENT
ESP_GATT_UUID_GM_CONTEXT
ESP_GATT_UUID_GM_CONTROL_POINT
ESP_GATT_UUID_GM_FEATURE
ESP_GATT_UUID_SYSTEM_ID
ESP_GATT_UUID_MODEL_NUMBER_STR
ESP_GATT_UUID_SERIAL_NUMBER_STR
ESP_GATT_UUID_FW_VERSION_STR
ESP_GATT_UUID_HW_VERSION_STR
ESP_GATT_UUID_SW_VERSION_STR
ESP_GATT_UUID_MANU_NAME
ESP_GATT_UUID_IEEE_DATA
ESP_GATT_UUID_PNP_ID
ESP_GATT_UUID_HID_INFORMATION
ESP_GATT_UUID_HID_REPORT_MAP
ESP_GATT_UUID_HID_CONTROL_POINT
ESP_GATT_UUID_HID_REPORT
ESP_GATT_UUID_HID_PROTO_MODE
ESP_GATT_UUID_HID_BT_KB_INPUT
ESP_GATT_UUID_HID_BT_KB_OUTPUT
ESP_GATT_UUID_HID_BT_MOUSE_INPUT
ESP_GATT_HEART_RATE_MEAS

Heart Rate Measurement.

ESP_GATT_BODY_SENSOR_LOCATION

Body Sensor Location.

ESP_GATT_HEART_RATE_CNTL_POINT

Heart Rate Control Point.

ESP_GATT_UUID_BATTERY_LEVEL
ESP_GATT_UUID_SC_CONTROL_POINT
ESP_GATT_UUID_SENSOR_LOCATION
ESP_GATT_UUID_RSC_MEASUREMENT
ESP_GATT_UUID_RSC_FEATURE
ESP_GATT_UUID_CSC_MEASUREMENT
ESP_GATT_UUID_CSC_FEATURE
ESP_GATT_UUID_SCAN_INT_WINDOW
ESP_GATT_UUID_SCAN_REFRESH
ESP_GATT_ILLEGAL_UUID

GATT INVALID UUID.

ESP_GATT_ILLEGAL_HANDLE

GATT INVALID HANDLE.

ESP_GATT_ATTR_HANDLE_MAX

GATT attribute max handle.

ESP_GATT_MAX_ATTR_LEN

GATT maximum attribute length.

ESP_GATT_RSP_BY_APP
ESP_GATT_AUTO_RSP
ESP_GATT_IF_NONE

If callback report gattc_if/gatts_if as this macro, means this event is not correspond to any app

Type Definitions
typedef uint8_t esp_gatt_if_t

Gatt interface type, different application on GATT client use different gatt_if

Enumerations
enum esp_gatt_prep_write_type

Attribute write data type from the client.

Values:

ESP_GATT_PREP_WRITE_CANCEL = 0x00

Prepare write cancel

ESP_GATT_PREP_WRITE_EXEC = 0x01

Prepare write execute

enum esp_gatt_status_t

GATT success code and error codes.

Values:

ESP_GATT_OK = 0x0
ESP_GATT_INVALID_HANDLE = 0x01
ESP_GATT_READ_NOT_PERMIT = 0x02
ESP_GATT_WRITE_NOT_PERMIT = 0x03
ESP_GATT_INVALID_PDU = 0x04
ESP_GATT_INSUF_AUTHENTICATION = 0x05
ESP_GATT_REQ_NOT_SUPPORTED = 0x06
ESP_GATT_INVALID_OFFSET = 0x07
ESP_GATT_INSUF_AUTHORIZATION = 0x08
ESP_GATT_PREPARE_Q_FULL = 0x09
ESP_GATT_NOT_FOUND = 0x0a
ESP_GATT_NOT_LONG = 0x0b
ESP_GATT_INSUF_KEY_SIZE = 0x0c
ESP_GATT_INVALID_ATTR_LEN = 0x0d
ESP_GATT_ERR_UNLIKELY = 0x0e
ESP_GATT_INSUF_ENCRYPTION = 0x0f
ESP_GATT_UNSUPPORT_GRP_TYPE = 0x10
ESP_GATT_INSUF_RESOURCE = 0x11
ESP_GATT_NO_RESOURCES = 0x80
ESP_GATT_INTERNAL_ERROR = 0x81
ESP_GATT_WRONG_STATE = 0x82
ESP_GATT_DB_FULL = 0x83
ESP_GATT_BUSY = 0x84
ESP_GATT_ERROR = 0x85
ESP_GATT_CMD_STARTED = 0x86
ESP_GATT_ILLEGAL_PARAMETER = 0x87
ESP_GATT_PENDING = 0x88
ESP_GATT_AUTH_FAIL = 0x89
ESP_GATT_MORE = 0x8a
ESP_GATT_INVALID_CFG = 0x8b
ESP_GATT_SERVICE_STARTED = 0x8c
ESP_GATT_ENCRYPED_MITM = ESP_GATT_OK
ESP_GATT_ENCRYPED_NO_MITM = 0x8d
ESP_GATT_NOT_ENCRYPTED = 0x8e
ESP_GATT_CONGESTED = 0x8f
ESP_GATT_DUP_REG = 0x90
ESP_GATT_ALREADY_OPEN = 0x91
ESP_GATT_CANCEL = 0x92
ESP_GATT_CCC_CFG_ERR = 0xfd
ESP_GATT_PRC_IN_PROGRESS = 0xfe
ESP_GATT_OUT_OF_RANGE = 0xff
enum esp_gatt_conn_reason_t

Gatt Connection reason enum.

Values:

ESP_GATT_CONN_UNKNOWN = 0

Gatt connection unknown

ESP_GATT_CONN_L2C_FAILURE = 1

General L2cap failure

ESP_GATT_CONN_TIMEOUT = 0x08

Connection timeout

ESP_GATT_CONN_TERMINATE_PEER_USER = 0x13

Connection terminate by peer user

ESP_GATT_CONN_TERMINATE_LOCAL_HOST = 0x16

Connectionterminated by local host

ESP_GATT_CONN_FAIL_ESTABLISH = 0x3e

Connection fail to establish

ESP_GATT_CONN_LMP_TIMEOUT = 0x22

Connection fail for LMP response tout

ESP_GATT_CONN_CONN_CANCEL = 0x0100

L2CAP connection cancelled

ESP_GATT_CONN_NONE = 0x0101

No connection to cancel

enum esp_gatt_auth_req_t

Gatt authentication request type.

Values:

ESP_GATT_AUTH_REQ_NONE = 0
ESP_GATT_AUTH_REQ_NO_MITM = 1
ESP_GATT_AUTH_REQ_MITM = 2
ESP_GATT_AUTH_REQ_SIGNED_NO_MITM = 3
ESP_GATT_AUTH_REQ_SIGNED_MITM = 4
enum esp_gatt_perm_t

Attribute permissions.

Values:

ESP_GATT_PERM_READ = (1 << 0)
ESP_GATT_PERM_READ_ENCRYPTED = (1 << 1)
ESP_GATT_PERM_READ_ENC_MITM = (1 << 2)
ESP_GATT_PERM_WRITE = (1 << 4)
ESP_GATT_PERM_WRITE_ENCRYPTED = (1 << 5)
ESP_GATT_PERM_WRITE_ENC_MITM = (1 << 6)
ESP_GATT_PERM_WRITE_SIGNED = (1 << 7)
ESP_GATT_PERM_WRITE_SIGNED_MITM = (1 << 8)
enum esp_gatt_char_prop_t

Values:

ESP_GATT_CHAR_PROP_BIT_BROADCAST = (1 << 0)
ESP_GATT_CHAR_PROP_BIT_READ = (1 << 1)
ESP_GATT_CHAR_PROP_BIT_WRITE_NR = (1 << 2)
ESP_GATT_CHAR_PROP_BIT_WRITE = (1 << 3)
ESP_GATT_CHAR_PROP_BIT_NOTIFY = (1 << 4)
ESP_GATT_CHAR_PROP_BIT_INDICATE = (1 << 5)
ESP_GATT_CHAR_PROP_BIT_AUTH = (1 << 6)
ESP_GATT_CHAR_PROP_BIT_EXT_PROP = (1 << 7)
enum esp_gatt_write_type_t

Gatt write type.

Values:

ESP_GATT_WRITE_TYPE_NO_RSP = 1

Gatt write attribute need no response

ESP_GATT_WRITE_TYPE_RSP

Gatt write attribute need remote response

Structures
struct esp_attr_desc_t

Attribute description (used to create database)

Public Members

uint16_t uuid_length

UUID length

uint8_t *uuid_p

UUID value

uint16_t perm

Attribute permission

uint16_t max_length

Maximum length of the element

uint16_t length

Current length of the element

uint8_t *value

Element value array

struct esp_attr_control_t

attribute auto respose flag

Public Members

uint8_t auto_rsp

need the app response to the client if need_rsp set to 1

struct esp_gatts_attr_db_t

attribute type added to the gatt server database

Public Members

esp_attr_control_t attr_control

The attribue control type

esp_attr_desc_t att_desc

The attribue type

struct esp_attr_value_t

set the attribute value type

Public Members

uint16_t attr_max_len

attribute max value length

uint16_t attr_len

attribute current value length

uint8_t *attr_value

the pointer to attribute value

struct esp_gatts_incl_svc_desc_t

Gatt include service entry element.

Public Members

uint16_t start_hdl

Gatt start handle value of included service

uint16_t end_hdl

Gatt end handle value of included service

uint16_t uuid

Gatt attribute value UUID of included service

struct esp_gatts_incl128_svc_desc_t

Gatt include 128 bit service entry element.

Public Members

uint16_t start_hdl

Gatt start handle value of included 128 bit service

uint16_t end_hdl

Gatt end handle value of included 128 bit service

struct esp_gatt_value_t

Gatt attribute value.

Public Members

uint8_t value[ESP_GATT_MAX_ATTR_LEN]

Gatt attribute value

uint16_t handle

Gatt attribute handle

uint16_t offset

Gatt attribute value offset

uint16_t len

Gatt attribute value length

uint8_t auth_req

Gatt authentication request

Warning

doxygenstruct: Cannot find class “esp_gatt_rsp_t” in doxygen xml output for project “esp32-idf” from directory: xml/

Functions

GATT SERVER API

Overview

Instructions

Application Example

Check /examples folder of espressif/esp-idf repository, that contains the following example:

14_gatts_demo

This is a gatt server demo. Use gatt api to create a gatt server with send advertising. This gatt server can be connected and the service can be discovery.

Instructions

API Reference
Macros
ESP_GATT_PREP_WRITE_CANCEL

Prepare write flag to indicate cancel prepare write

ESP_GATT_PREP_WRITE_EXEC

Prepare write flag to indicate execute prepare write

Type Definitions
typedef void (*esp_gatts_cb_t)(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)

GATT Server callback function type.

Parameters
  • event: : Event type
  • gatts_if: : GATT server access interface, normally different gatts_if correspond to different profile
  • param: : Point to callback parameter, currently is union type

Enumerations
enum esp_gatts_cb_event_t

GATT Server callback function events.

Values:

ESP_GATTS_REG_EVT = 0

When register application id, the event comes

ESP_GATTS_READ_EVT = 1

When gatt client request read operation, the event comes

ESP_GATTS_WRITE_EVT = 2

When gatt client request write operation, the event comes

ESP_GATTS_EXEC_WRITE_EVT = 3

When gatt client request execute write, the event comes

ESP_GATTS_MTU_EVT = 4

When set mtu complete, the event comes

ESP_GATTS_CONF_EVT = 5

When receive confirm, the event comes

ESP_GATTS_UNREG_EVT = 6

When unregister application id, the event comes

ESP_GATTS_CREATE_EVT = 7

When create service complete, the event comes

ESP_GATTS_ADD_INCL_SRVC_EVT = 8

When add included service complete, the event comes

ESP_GATTS_ADD_CHAR_EVT = 9

When add characteristic complete, the event comes

ESP_GATTS_ADD_CHAR_DESCR_EVT = 10

When add descriptor complete, the event comes

ESP_GATTS_DELETE_EVT = 11

When delete service complete, the event comes

ESP_GATTS_START_EVT = 12

When start service complete, the event comes

ESP_GATTS_STOP_EVT = 13

When stop service complete, the event comes

ESP_GATTS_CONNECT_EVT = 14

When gatt client connect, the event comes

ESP_GATTS_DISCONNECT_EVT = 15

When gatt client disconnect, the event comes

ESP_GATTS_OPEN_EVT = 16

When connect to peer, the event comes

ESP_GATTS_CANCEL_OPEN_EVT = 17

When disconnect from peer, the event comes

ESP_GATTS_CLOSE_EVT = 18

When gatt server close, the event comes

ESP_GATTS_LISTEN_EVT = 19

When gatt listen to be connected the event comes

ESP_GATTS_CONGEST_EVT = 20

When congest happen, the event comes

ESP_GATTS_RESPONSE_EVT = 21

When gatt send response complete, the event comes

ESP_GATTS_CREAT_ATTR_TAB_EVT = 22
ESP_GATTS_SET_ATTR_VAL_EVT = 23
Structures

Warning

doxygenstruct: Cannot find class “esp_ble_gatts_cb_param_t” in doxygen xml output for project “esp32-idf” from directory: xml/

struct esp_ble_gatts_cb_param_t::gatts_reg_evt_param

ESP_GATTS_REG_EVT.

Public Members

esp_gatt_status_t status

Operation status

uint16_t app_id

Application id which input in register API

struct esp_ble_gatts_cb_param_t::gatts_read_evt_param

ESP_GATTS_READ_EVT.

Public Members

uint16_t conn_id

Connection id

uint32_t trans_id

Transfer id

esp_bd_addr_t bda

The bluetooth device address which been read

uint16_t handle

The attribute handle

uint16_t offset

Offset of the value, if the value is too long

bool is_long

The value is too long or not

bool need_rsp

The read operation need to do response

struct esp_ble_gatts_cb_param_t::gatts_write_evt_param

ESP_GATTS_WRITE_EVT.

Public Members

uint16_t conn_id

Connection id

uint32_t trans_id

Transfer id

esp_bd_addr_t bda

The bluetooth device address which been written

uint16_t handle

The attribute handle

uint16_t offset

Offset of the value, if the value is too long

bool need_rsp

The write operation need to do response

bool is_prep

This write operation is prepare write

uint16_t len

The write attribute value length

uint8_t *value

The write attribute value

struct esp_ble_gatts_cb_param_t::gatts_exec_write_evt_param

ESP_GATTS_EXEC_WRITE_EVT.

Public Members

uint16_t conn_id

Connection id

uint32_t trans_id

Transfer id

esp_bd_addr_t bda

The bluetooth device address which been written

uint8_t exec_write_flag

Execute write flag

struct esp_ble_gatts_cb_param_t::gatts_mtu_evt_param

ESP_GATTS_MTU_EVT.

Public Members

uint16_t conn_id

Connection id

uint16_t mtu

MTU size

struct esp_ble_gatts_cb_param_t::gatts_conf_evt_param

ESP_GATTS_CONF_EVT.

Public Members

esp_gatt_status_t status

Operation status

uint16_t conn_id

Connection id

struct esp_ble_gatts_cb_param_t::gatts_create_evt_param

ESP_GATTS_UNREG_EVT.

ESP_GATTS_CREATE_EVT

Public Members

esp_gatt_status_t status

Operation status

uint16_t service_handle

Service attribute handle

esp_gatt_srvc_id_t service_id

Service id, include service uuid and other information

struct esp_ble_gatts_cb_param_t::gatts_add_incl_srvc_evt_param

ESP_GATTS_ADD_INCL_SRVC_EVT.

Public Members

esp_gatt_status_t status

Operation status

uint16_t attr_handle

Included service attribute handle

uint16_t service_handle

Service attribute handle

struct esp_ble_gatts_cb_param_t::gatts_add_char_evt_param

ESP_GATTS_ADD_CHAR_EVT.

Public Members

esp_gatt_status_t status

Operation status

uint16_t attr_handle

Characteristic attribute handle

uint16_t service_handle

Service attribute handle

esp_bt_uuid_t char_uuid

Characteristic uuid

struct esp_ble_gatts_cb_param_t::gatts_add_char_descr_evt_param

ESP_GATTS_ADD_CHAR_DESCR_EVT.

Public Members

esp_gatt_status_t status

Operation status

uint16_t attr_handle

Descriptor attribute handle

uint16_t service_handle

Service attribute handle

esp_bt_uuid_t char_uuid

Characteristic uuid

struct esp_ble_gatts_cb_param_t::gatts_delete_evt_param

ESP_GATTS_DELETE_EVT.

Public Members

esp_gatt_status_t status

Operation status

uint16_t service_handle

Service attribute handle

struct esp_ble_gatts_cb_param_t::gatts_start_evt_param

ESP_GATTS_START_EVT.

Public Members

esp_gatt_status_t status

Operation status

uint16_t service_handle

Service attribute handle

struct esp_ble_gatts_cb_param_t::gatts_stop_evt_param

ESP_GATTS_STOP_EVT.

Public Members

esp_gatt_status_t status

Operation status

uint16_t service_handle

Service attribute handle

struct esp_ble_gatts_cb_param_t::gatts_connect_evt_param

ESP_GATTS_CONNECT_EVT.

Public Members

uint16_t conn_id

Connection id

esp_bd_addr_t remote_bda

Remote bluetooth device address

bool is_connected

Indicate it is connected or not

struct esp_ble_gatts_cb_param_t::gatts_disconnect_evt_param

ESP_GATTS_DISCONNECT_EVT.

Public Members

uint16_t conn_id

Connection id

esp_bd_addr_t remote_bda

Remote bluetooth device address

bool is_connected

Indicate it is connected or not

struct esp_ble_gatts_cb_param_t::gatts_congest_evt_param

ESP_GATTS_OPEN_EVT.

ESP_GATTS_CANCEL_OPEN_EVT ESP_GATTS_CLOSE_EVT ESP_GATTS_LISTEN_EVT ESP_GATTS_CONGEST_EVT

Public Members

uint16_t conn_id

Connection id

bool congested

Congested or not

struct esp_ble_gatts_cb_param_t::gatts_rsp_evt_param

ESP_GATTS_RESPONSE_EVT.

Public Members

esp_gatt_status_t status

Operation status

uint16_t handle

Attribute handle which send response

struct esp_ble_gatts_cb_param_t::gatts_add_attr_tab_evt_param

ESP_GATTS_CREAT_ATTR_TAB_EVT.

Public Members

esp_gatt_status_t status

Operation status

esp_bt_uuid_t svc_uuid

Service uuid type

uint16_t num_handle

The number of the attribute handle to be added to the gatts database

uint16_t *handles

The number to the handles

struct esp_ble_gatts_cb_param_t::gatts_set_attr_val_evt_param

ESP_GATTS_SET_ATTR_VAL_EVT.

Public Members

uint16_t srvc_handle

The service handle

uint16_t attr_handle

The attribute handle

esp_gatt_status_t status

Operation status

Functions
esp_err_t esp_ble_gatts_register_callback(esp_gatts_cb_t callback)

This function is called to register application callbacks with BTA GATTS module.

Return
  • ESP_OK : success
  • other : failed

esp_err_t esp_ble_gatts_app_register(uint16_t app_id)

This function is called to register application identifier.

Return
  • ESP_OK : success
  • other : failed

esp_err_t esp_ble_gatts_app_unregister(esp_gatt_if_t gatts_if)

unregister with GATT Server.

Return
  • ESP_OK : success
  • other : failed
Parameters
  • gatts_if: GATT server access interface

esp_err_t esp_ble_gatts_create_service(esp_gatt_if_t gatts_if, esp_gatt_srvc_id_t *service_id, uint16_t num_handle)

Create a service. When service creation is done, a callback event BTA_GATTS_CREATE_SRVC_EVT is called to report status and service ID to the profile. The service ID obtained in the callback function needs to be used when adding included service and characteristics/descriptors into the service.

Return
  • ESP_OK : success
  • other : failed
Parameters
  • gatts_if: GATT server access interface
  • service_id: service ID.
  • num_handle: number of handle requested for this service.

esp_err_t esp_ble_gatts_create_attr_tab(const esp_gatts_attr_db_t *gatts_attr_db, esp_gatt_if_t gatts_if, uint8_t max_nb_attr, uint8_t srvc_inst_id)

Create a service attribute tab.

Return
  • ESP_OK : success
  • other : failed
Parameters
  • gatts_attr_db: the pointer to the service attr tab
  • gatts_if: GATT server access interface
  • max_nb_attr: the number of attribute to be added to the service database.
  • srvc_inst_id: the instance id of the service

esp_err_t esp_ble_gatts_add_included_service(uint16_t service_handle, uint16_t included_service_handle)

This function is called to add an included service. After included service is included, a callback event BTA_GATTS_ADD_INCL_SRVC_EVT is reported the included service ID.

Return
  • ESP_OK : success
  • other : failed
Parameters
  • service_handle: service handle to which this included service is to be added.
  • included_service_handle: the service ID to be included.

esp_err_t esp_ble_gatts_add_char(uint16_t service_handle, esp_bt_uuid_t *char_uuid, esp_gatt_perm_t perm, esp_gatt_char_prop_t property, esp_attr_value_t *char_val, esp_attr_control_t *control)

This function is called to add a characteristic into a service.

Return
  • ESP_OK : success
  • other : failed
Parameters
  • service_handle: service handle to which this included service is to be added.
  • char_uuid: : Characteristic UUID.
  • perm: : Characteristic value declaration attribute permission.
  • property: : Characteristic Properties
  • char_val: : Characteristic value
  • control: : attribute response control byte

esp_err_t esp_ble_gatts_add_char_descr(uint16_t service_handle, esp_bt_uuid_t *descr_uuid, esp_gatt_perm_t perm, esp_attr_value_t *char_descr_val, esp_attr_control_t *control)

This function is called to add characteristic descriptor. When it’s done, a callback event BTA_GATTS_ADD_DESCR_EVT is called to report the status and an ID number for this descriptor.

Return
  • ESP_OK : success
  • other : failed
Parameters
  • service_handle: service handle to which this characteristic descriptor is to be added.
  • perm: descriptor access permission.
  • descr_uuid: descriptor UUID.
  • char_descr_val: : Characteristic descriptor value
  • control: : attribute response control byte

esp_err_t esp_ble_gatts_delete_service(uint16_t service_handle)

This function is called to delete a service. When this is done, a callback event BTA_GATTS_DELETE_EVT is report with the status.

Return
  • ESP_OK : success
  • other : failed
Parameters
  • service_handle: service_handle to be deleted.

esp_err_t esp_ble_gatts_start_service(uint16_t service_handle)

This function is called to start a service.

Return
  • ESP_OK : success
  • other : failed
Parameters
  • service_handle: the service handle to be started.

esp_err_t esp_ble_gatts_stop_service(uint16_t service_handle)

This function is called to stop a service.

Return
  • ESP_OK : success
  • other : failed
Parameters
  • service_handle: - service to be topped.

esp_err_t esp_ble_gatts_send_indicate(esp_gatt_if_t gatts_if, uint16_t conn_id, uint16_t attr_handle, uint16_t value_len, uint8_t *value, bool need_confirm)

Send indicate or notify to GATT client. Set param need_confirm as false will send notification, otherwise indication.

Return
  • ESP_OK : success
  • other : failed
Parameters
  • gatts_if: GATT server access interface
  • conn_id: - connection id to indicate.
  • attr_handle: - attribute handle to indicate.
  • value_len: - indicate value length.
  • value: value to indicate.
  • need_confirm: - if this indication expects a confirmation or not.

esp_err_t esp_ble_gatts_send_response(esp_gatt_if_t gatts_if, uint16_t conn_id, uint32_t trans_id, esp_gatt_status_t status, esp_gatt_rsp_t *rsp)

This function is called to send a response to a request.

Return
  • ESP_OK : success
  • other : failed
Parameters
  • gatts_if: GATT server access interface
  • conn_id: - connection identifier.
  • trans_id: - transfer id
  • status: - response status
  • rsp: - response data.

esp_err_t esp_ble_gatts_set_attr_value(uint16_t attr_handle, uint16_t length, const uint8_t *value)

This function is called to set the attribute value by the application.

Return
  • ESP_OK : success
  • other : failed
Parameters
  • attr_handle: the attribute handle which to be set
  • length: the value length
  • value: the pointer to the attribute value

esp_err_t esp_ble_gatts_get_attr_value(uint16_t attr_handle, uint16_t *length, const uint8_t **value)

Retrieve attribute value.

Return
  • ESP_OK : success
  • other : failed
Parameters
  • attr_handle: Attribute handle.
  • length: pointer to the attribute value length
  • value: Pointer to attribute value payload, the value cannot be modified by user

esp_err_t esp_ble_gatts_open(esp_gatt_if_t gatts_if, esp_bd_addr_t remote_bda, bool is_direct)

Open a direct open connection or add a background auto connection.

Return
  • ESP_OK : success
  • other : failed
Parameters
  • gatts_if: GATT server access interface
  • remote_bda: remote device bluetooth device address.
  • is_direct: direct connection or background auto connection

esp_err_t esp_ble_gatts_close(esp_gatt_if_t gatts_if, uint16_t conn_id)

Close a connection a remote device.

Return
  • ESP_OK : success
  • other : failed
Parameters
  • gatts_if: GATT server access interface
  • conn_id: connection ID to be closed.

GATT CLIENT API

Overview

Instructions

Application Example

Check /examples folder of espressif/esp-idf repository, that contains the following example:

15_gattc_demo

This is a gatt client demo. This demo can scan devices, connect to the gatt server and discover the service.

Instructions

API Reference
Macros
ESP_GATT_DEF_BLE_MTU_SIZE

Maximum Transmission Unit used in GATT.

ESP_GATT_MAX_MTU_SIZE

Maximum Transmission Unit allowed in GATT.

Type Definitions
typedef void (*esp_gattc_cb_t)(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param)

GATT Client callback function type.

Parameters
  • event: : Event type
  • gatts_if: : GATT client access interface, normally different gattc_if correspond to different profile
  • param: : Point to callback parameter, currently is union type

Enumerations
enum esp_gattc_cb_event_t

GATT Client callback function events.

Values:

ESP_GATTC_REG_EVT = 0

When GATT client is registered, the event comes

ESP_GATTC_UNREG_EVT = 1

When GATT client is unregistered, the event comes

ESP_GATTC_OPEN_EVT = 2

When GATT connection is set up, the event comes

ESP_GATTC_READ_CHAR_EVT = 3

When GATT characteristic is read, the event comes

ESP_GATTC_WRITE_CHAR_EVT = 4

When GATT characteristic write operation completes, the event comes

ESP_GATTC_CLOSE_EVT = 5

When GATT connection is closed, the event comes

ESP_GATTC_SEARCH_CMPL_EVT = 6

When GATT service discovery is completed, the event comes

ESP_GATTC_SEARCH_RES_EVT = 7

When GATT service discovery result is got, the event comes

ESP_GATTC_READ_DESCR_EVT = 8

When GATT characteristic descriptor read completes, the event comes

ESP_GATTC_WRITE_DESCR_EVT = 9

When GATT characteristic descriptor write completes, the event comes

ESP_GATTC_NOTIFY_EVT = 10

When GATT notification or indication arrives, the event comes

ESP_GATTC_PREP_WRITE_EVT = 11

When GATT prepare-write operation completes, the event comes

ESP_GATTC_EXEC_EVT = 12

When write execution completes, the event comes

ESP_GATTC_ACL_EVT = 13

When ACL connection is up, the event comes

ESP_GATTC_CANCEL_OPEN_EVT = 14

When GATT client ongoing connection is cancelled, the event comes

ESP_GATTC_SRVC_CHG_EVT = 15

When “service changed” occurs, the event comes

ESP_GATTC_ENC_CMPL_CB_EVT = 17

When encryption procedure completes, the event comes

ESP_GATTC_CFG_MTU_EVT = 18

When configuration of MTU completes, the event comes

ESP_GATTC_ADV_DATA_EVT = 19

When advertising of data, the event comes

ESP_GATTC_MULT_ADV_ENB_EVT = 20

When multi-advertising is enabled, the event comes

ESP_GATTC_MULT_ADV_UPD_EVT = 21

When multi-advertising parameters are updated, the event comes

ESP_GATTC_MULT_ADV_DATA_EVT = 22

When multi-advertising data arrives, the event comes

ESP_GATTC_MULT_ADV_DIS_EVT = 23

When multi-advertising is disabled, the event comes

ESP_GATTC_CONGEST_EVT = 24

When GATT connection congestion comes, the event comes

ESP_GATTC_BTH_SCAN_ENB_EVT = 25

When batch scan is enabled, the event comes

ESP_GATTC_BTH_SCAN_CFG_EVT = 26

When batch scan storage is configured, the event comes

ESP_GATTC_BTH_SCAN_RD_EVT = 27

When Batch scan read event is reported, the event comes

ESP_GATTC_BTH_SCAN_THR_EVT = 28

When Batch scan threshold is set, the event comes

ESP_GATTC_BTH_SCAN_PARAM_EVT = 29

When Batch scan parameters are set, the event comes

ESP_GATTC_BTH_SCAN_DIS_EVT = 30

When Batch scan is disabled, the event comes

ESP_GATTC_SCAN_FLT_CFG_EVT = 31

When Scan filter configuration completes, the event comes

ESP_GATTC_SCAN_FLT_PARAM_EVT = 32

When Scan filter parameters are set, the event comes

ESP_GATTC_SCAN_FLT_STATUS_EVT = 33

When Scan filter status is reported, the event comes

ESP_GATTC_ADV_VSC_EVT = 34

When advertising vendor spec content event is reported, the event comes

ESP_GATTC_GET_CHAR_EVT = 35

When characteristic is got from GATT server, the event comes

ESP_GATTC_GET_DESCR_EVT = 36

When characteristic descriptor is got from GATT server, the event comes

ESP_GATTC_GET_INCL_SRVC_EVT = 37

When included service is got from GATT server, the event comes

ESP_GATTC_REG_FOR_NOTIFY_EVT = 38

When register for notification of a service completes, the event comes

ESP_GATTC_UNREG_FOR_NOTIFY_EVT = 39

When unregister for notification of a service completes, the event comes

Structures

Warning

doxygenstruct: Cannot find class “esp_ble_gattc_cb_param_t” in doxygen xml output for project “esp32-idf” from directory: xml/

struct esp_ble_gattc_cb_param_t::gattc_reg_evt_param

ESP_GATTC_REG_EVT.

Public Members

esp_gatt_status_t status

Operation status

uint16_t app_id

Application id which input in register API

struct esp_ble_gattc_cb_param_t::gattc_open_evt_param

ESP_GATTC_OPEN_EVT.

Public Members

esp_gatt_status_t status

Operation status

uint16_t conn_id

Connection id

esp_bd_addr_t remote_bda

Remote bluetooth device address

uint16_t mtu

MTU size

struct esp_ble_gattc_cb_param_t::gattc_close_evt_param

ESP_GATTC_CLOSE_EVT.

Public Members

esp_gatt_status_t status

Operation status

uint16_t conn_id

Connection id

esp_bd_addr_t remote_bda

Remote bluetooth device address

esp_gatt_conn_reason_t reason

The reason of gatt connection close

struct esp_ble_gattc_cb_param_t::gattc_cfg_mtu_evt_param

ESP_GATTC_CFG_MTU_EVT.

Public Members

esp_gatt_status_t status

Operation status

uint16_t conn_id

Connection id

uint16_t mtu

MTU size

struct esp_ble_gattc_cb_param_t::gattc_search_cmpl_evt_param

ESP_GATTC_SEARCH_CMPL_EVT.

Public Members

esp_gatt_status_t status

Operation status

uint16_t conn_id

Connection id

struct esp_ble_gattc_cb_param_t::gattc_search_res_evt_param

ESP_GATTC_SEARCH_RES_EVT.

Public Members

uint16_t conn_id

Connection id

esp_gatt_srvc_id_t srvc_id

Service id, include service uuid and other information

struct esp_ble_gattc_cb_param_t::gattc_read_char_evt_param

ESP_GATTC_READ_CHAR_EVT, ESP_GATTC_READ_DESCR_EVT.

Public Members

esp_gatt_status_t status

Operation status

uint16_t conn_id

Connection id

esp_gatt_srvc_id_t srvc_id

Service id, include service uuid and other information

esp_gatt_id_t char_id

Characteristic id, include characteristic uuid and other information

esp_gatt_id_t descr_id

Descriptor id, include descriptor uuid and other information

uint8_t *value

Characteristic value

uint16_t value_type

Characteristic value type

uint16_t value_len

Characteristic value length

struct esp_ble_gattc_cb_param_t::gattc_write_evt_param

ESP_GATTC_WRITE_CHAR_EVT, ESP_GATTC_PREP_WRITE_EVT, ESP_GATTC_WRITE_DESCR_EVT.

Public Members

esp_gatt_status_t status

Operation status

uint16_t conn_id

Connection id

esp_gatt_srvc_id_t srvc_id

Service id, include service uuid and other information

esp_gatt_id_t char_id

Characteristic id, include characteristic uuid and other information

esp_gatt_id_t descr_id

Descriptor id, include descriptor uuid and other information

struct esp_ble_gattc_cb_param_t::gattc_exec_cmpl_evt_param

ESP_GATTC_EXEC_EVT.

Public Members

esp_gatt_status_t status

Operation status

uint16_t conn_id

Connection id

struct esp_ble_gattc_cb_param_t::gattc_notify_evt_param

ESP_GATTC_NOTIFY_EVT.

Public Members

uint16_t conn_id

Connection id

esp_bd_addr_t remote_bda

Remote bluetooth device address

esp_gatt_srvc_id_t srvc_id

Service id, include service uuid and other information

esp_gatt_id_t char_id

Characteristic id, include characteristic uuid and other information

esp_gatt_id_t descr_id

Descriptor id, include descriptor uuid and other information

uint16_t value_len

Notify attribute value

uint8_t *value

Notify attribute value

bool is_notify

True means notify, false means indicate

struct esp_ble_gattc_cb_param_t::gattc_srvc_chg_evt_param

ESP_GATTC_SRVC_CHG_EVT.

Public Members

esp_bd_addr_t remote_bda

Remote bluetooth device address

struct esp_ble_gattc_cb_param_t::gattc_congest_evt_param

ESP_GATTC_CONGEST_EVT.

Public Members

uint16_t conn_id

Connection id

bool congested

Congested or not

struct esp_ble_gattc_cb_param_t::gattc_get_char_evt_param

ESP_GATTC_GET_CHAR_EVT.

Public Members

esp_gatt_status_t status

Operation status

uint16_t conn_id

Connection id

esp_gatt_srvc_id_t srvc_id

Service id, include service uuid and other information

esp_gatt_id_t char_id

Characteristic id, include characteristic uuid and other information

esp_gatt_char_prop_t char_prop

Characteristic property

struct esp_ble_gattc_cb_param_t::gattc_get_descr_evt_param

ESP_GATTC_GET_DESCR_EVT.

Public Members

esp_gatt_status_t status

Operation status

uint16_t conn_id

Connection id

esp_gatt_srvc_id_t srvc_id

Service id, include service uuid and other information

esp_gatt_id_t char_id

Characteristic id, include characteristic uuid and other information

esp_gatt_id_t descr_id

Descriptor id, include descriptor uuid and other information

struct esp_ble_gattc_cb_param_t::gattc_get_incl_srvc_evt_param

ESP_GATTC_GET_INCL_SRVC_EVT.

Public Members

esp_gatt_status_t status

Operation status

uint16_t conn_id

Connection id

esp_gatt_srvc_id_t srvc_id

Service id, include service uuid and other information

esp_gatt_srvc_id_t incl_srvc_id

Included service id, include service uuid and other information

struct esp_ble_gattc_cb_param_t::gattc_reg_for_notify_evt_param

ESP_GATTC_REG_FOR_NOTIFY_EVT.

Public Members

esp_gatt_status_t status

Operation status

esp_gatt_srvc_id_t srvc_id

Service id, include service uuid and other information

esp_gatt_id_t char_id

Characteristic id, include characteristic uuid and other information

struct esp_ble_gattc_cb_param_t::gattc_unreg_for_notify_evt_param

ESP_GATTC_UNREG_FOR_NOTIFY_EVT.

Public Members

esp_gatt_status_t status

Operation status

esp_gatt_srvc_id_t srvc_id

Service id, include service uuid and other information

esp_gatt_id_t char_id

Characteristic id, include characteristic uuid and other information

Functions
esp_err_t esp_ble_gattc_register_callback(esp_gattc_cb_t callback)

This function is called to register application callbacks with GATTC module.

Return
  • ESP_OK: success
  • other: failed
Parameters
  • callback: : pointer to the application callback function.

esp_err_t esp_ble_gattc_app_register(uint16_t app_id)

This function is called to register application callbacks with GATTC module.

Return
  • ESP_OK: success
  • other: failed
Parameters
  • app_id: : Application Identify (UUID), for different application

esp_err_t esp_ble_gattc_app_unregister(esp_gatt_if_t gattc_if)

This function is called to unregister an application from GATTC module.

Return
  • ESP_OK: success
  • other: failed
Parameters
  • gattc_if: Gatt client access interface.

esp_err_t esp_ble_gattc_open(esp_gatt_if_t gattc_if, esp_bd_addr_t remote_bda, bool is_direct)

Open a direct connection or add a background auto connection.

Return
  • ESP_OK: success
  • other: failed
Parameters
  • gattc_if: Gatt client access interface.
  • remote_bda: remote device bluetooth device address.
  • is_direct: direct connection or background auto connection

esp_err_t esp_ble_gattc_close(esp_gatt_if_t gattc_if, uint16_t conn_id)

Close a connection to a GATT server.

Return
  • ESP_OK: success
  • other: failed
Parameters
  • gattc_if: Gatt client access interface.
  • conn_id: connection ID to be closed.

esp_err_t esp_ble_gattc_config_mtu(esp_gatt_if_t gattc_if, uint16_t conn_id, uint16_t mtu)

Configure the MTU size in the GATT channel. This can be done only once per connection.

Return
  • ESP_OK: success
  • other: failed
Parameters
  • gattc_if: Gatt client access interface.
  • conn_id: connection ID.
  • mtu: desired MTU size to use.

esp_err_t esp_ble_gattc_search_service(esp_gatt_if_t gattc_if, uint16_t conn_id, esp_bt_uuid_t *filter_uuid)

This function is called to request a GATT service discovery on a GATT server. This function report service search result by a callback event, and followed by a service search complete event.

Return
  • ESP_OK: success
  • other: failed
Parameters
  • gattc_if: Gatt client access interface.
  • conn_id: connection ID.
  • filter_uuid: a UUID of the service application is interested in. If Null, discover for all services.

esp_err_t esp_ble_gattc_get_characteristic(esp_gatt_if_t gattc_if, uint16_t conn_id, esp_gatt_srvc_id_t *srvc_id, esp_gatt_id_t *start_char_id)

This function is called to find the first characteristic of the service on the given server.

Return
  • ESP_OK: success
  • other: failed
Parameters
  • gattc_if: Gatt client access interface.
  • conn_id: connection ID which identify the server.
  • srvc_id: service ID
  • start_char_id: the start characteristic ID

esp_err_t esp_ble_gattc_get_descriptor(esp_gatt_if_t gattc_if, uint16_t conn_id, esp_gatt_srvc_id_t *srvc_id, esp_gatt_id_t *char_id, esp_gatt_id_t *start_descr_id)

This function is called to find the descriptor of the service on the given server.

Return
  • ESP_OK: success
  • other: failed
Parameters
  • gattc_if: Gatt client access interface.
  • conn_id: connection ID which identify the server.
  • srvc_id: the service ID of which the characteristic is belonged to.
  • char_id: Characteristic ID, if NULL find the first available characteristic.
  • start_descr_id: the start descriptor id

esp_err_t esp_ble_gattc_get_included_service(esp_gatt_if_t gattc_if, uint16_t conn_id, esp_gatt_srvc_id_t *srvc_id, esp_gatt_srvc_id_t *start_incl_srvc_id)

This function is called to find the first characteristic of the service on the given server.

Return
  • ESP_OK: success
  • other: failed
Parameters
  • gattc_if: Gatt client access interface.
  • conn_id: connection ID which identify the server.
  • srvc_id: the service ID of which the characteristic is belonged to.
  • start_incl_srvc_id: the start include service id

esp_err_t esp_ble_gattc_read_char(esp_gatt_if_t gattc_if, uint16_t conn_id, esp_gatt_srvc_id_t *srvc_id, esp_gatt_id_t *char_id, esp_gatt_auth_req_t auth_req)

This function is called to read a service’s characteristics of the given characteristic ID.

Return
  • ESP_OK: success
  • other: failed
Parameters
  • gattc_if: Gatt client access interface.
  • conn_id: : connection ID.
  • srvc_id: : service ID.
  • char_id: : characteristic ID to read.
  • auth_req: : authenticate request type

esp_err_t esp_ble_gattc_read_char_descr(esp_gatt_if_t gattc_if, uint16_t conn_id, esp_gatt_srvc_id_t *srvc_id, esp_gatt_id_t *char_id, esp_gatt_id_t *descr_id, esp_gatt_auth_req_t auth_req)

This function is called to read a characteristics descriptor.

Return
  • ESP_OK: success
  • other: failed
Parameters
  • gattc_if: Gatt client access interface.
  • conn_id: : connection ID.
  • srvc_id: : service ID.
  • char_id: : characteristic ID to read.
  • descr_id: : characteristic descriptor ID to read.
  • auth_req: : authenticate request type

esp_err_t esp_ble_gattc_write_char(esp_gatt_if_t gattc_if, uint16_t conn_id, esp_gatt_srvc_id_t *srvc_id, esp_gatt_id_t *char_id, uint16_t value_len, uint8_t *value, esp_gatt_write_type_t write_type, esp_gatt_auth_req_t auth_req)

This function is called to write characteristic value.

Return
  • ESP_OK: success
  • other: failed
Parameters
  • gattc_if: Gatt client access interface.
  • conn_id: : connection ID.
  • srvc_id: : service ID.
  • char_id: : characteristic ID to write.
  • value_len: length of the value to be written.
  • value: : the value to be written.
  • write_type: : the type of attribute write operation.
  • auth_req: : authentication request.

esp_err_t esp_ble_gattc_write_char_descr(esp_gatt_if_t gattc_if, uint16_t conn_id, esp_gatt_srvc_id_t *srvc_id, esp_gatt_id_t *char_id, esp_gatt_id_t *descr_id, uint16_t value_len, uint8_t *value, esp_gatt_write_type_t write_type, esp_gatt_auth_req_t auth_req)

This function is called to write characteristic descriptor value.

Return
  • ESP_OK: success
  • other: failed
Parameters
  • gattc_if: Gatt client access interface.
  • conn_id: : connection ID
  • srvc_id: : service ID.
  • char_id: : characteristic ID.
  • descr_id: : characteristic descriptor ID to write.
  • value_len: length of the value to be written.
  • value: : the value to be written.
  • write_type: : the type of attribute write operation.
  • auth_req: : authentication request.

esp_err_t esp_ble_gattc_prepare_write(esp_gatt_if_t gattc_if, uint16_t conn_id, esp_gatt_srvc_id_t *srvc_id, esp_gatt_id_t *char_id, uint16_t offset, uint16_t value_len, uint8_t *value, esp_gatt_auth_req_t auth_req)

This function is called to prepare write a characteristic value.

Return
  • ESP_OK: success
  • other: failed
Parameters
  • gattc_if: Gatt client access interface.
  • conn_id: : connection ID.
  • srvc_id: : service ID.
  • char_id: : GATT characteristic ID of the service.
  • offset: : offset of the write value.
  • value_len: length of the value to be written.
  • value: : the value to be written.
  • auth_req: : authentication request.

esp_err_t esp_ble_gattc_execute_write(esp_gatt_if_t gattc_if, uint16_t conn_id, bool is_execute)

This function is called to execute write a prepare write sequence.

Return
  • ESP_OK: success
  • other: failed
Parameters
  • gattc_if: Gatt client access interface.
  • conn_id: : connection ID.
  • is_execute: : execute or cancel.

esp_gatt_status_t esp_ble_gattc_register_for_notify(esp_gatt_if_t gattc_if, esp_bd_addr_t server_bda, esp_gatt_srvc_id_t *srvc_id, esp_gatt_id_t *char_id)

This function is called to register for notification of a service.

Return
  • ESP_OK: registration succeeds
  • other: failed
Parameters
  • gattc_if: Gatt client access interface.
  • server_bda: : target GATT server.
  • srvc_id: : pointer to GATT service ID.
  • char_id: : pointer to GATT characteristic ID.

esp_gatt_status_t esp_ble_gattc_unregister_for_notify(esp_gatt_if_t gattc_if, esp_bd_addr_t server_bda, esp_gatt_srvc_id_t *srvc_id, esp_gatt_id_t *char_id)

This function is called to de-register for notification of a service.

Return
  • ESP_OK: unregister succeeds
  • other: failed
Parameters
  • gattc_if: Gatt client access interface.
  • server_bda: : target GATT server.
  • srvc_id: : pointer to GATT service ID.
  • char_id: : pointer to GATT characteristic ID.

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 /examples folder of espressif/esp-idf repository, that contains the following example:

12_blufi

This is a BLUFI demo. This demo can set ESP32’s wifi to softap/station/softap&station mode and config wifi connections.

API Reference
Macros
Type Definitions
typedef void (*esp_blufi_event_cb_t)(esp_blufi_cb_event_t event, esp_blufi_cb_param_t *param)

BLUFI event callback function type.

Parameters
  • event: : Event type
  • param: : Point to callback parameter, currently is union type

typedef void (*esp_blufi_negotiate_data_handler_t)(uint8_t *data, int len, uint8_t **output_data, int *output_len, bool *need_free)

BLUFI negotiate data handler.

Parameters
  • data: : data from phone
  • len: : length of data from phone
  • output_data: : data want to send to phone
  • output_len: : length of data want to send to phone

typedef int (*esp_blufi_encrypt_func_t)(uint8_t iv8, uint8_t *crypt_data, int cyprt_len)

BLUFI encrypt the data after negotiate a share key.

Return
Nonnegative number is encrypted length, if error, return negative number;
Parameters
  • iv8: : initial vector(8bit), normally, blufi core will input packet sequence number
  • crypt_data: : plain text and encrypted data, the encrypt function must support autochthonous encrypt
  • crypt_len: : length of plain text

typedef int (*esp_blufi_decrypt_func_t)(uint8_t iv8, uint8_t *crypt_data, int crypt_len)

BLUFI decrypt the data after negotiate a share key.

Return
Nonnegative number is decrypted length, if error, return negative number;
Parameters
  • iv8: : initial vector(8bit), normally, blufi core will input packet sequence number
  • crypt_data: : encrypted data and plain text, the encrypt function must support autochthonous decrypt
  • crypt_len: : length of encrypted text

typedef uint16_t (*esp_blufi_checksum_func_t)(uint8_t iv8, uint8_t *data, int len)

BLUFI checksum.

Parameters
  • iv8: : initial vector(8bit), normally, blufi core will input packet sequence number
  • data: : data need to checksum
  • len: : length of data

Enumerations
enum esp_blufi_cb_event_t

Values:

ESP_BLUFI_EVENT_INIT_FINISH = 0
ESP_BLUFI_EVENT_DEINIT_FINISH
ESP_BLUFI_EVENT_SET_WIFI_OPMODE
ESP_BLUFI_EVENT_BLE_CONNECT
ESP_BLUFI_EVENT_BLE_DISCONNECT
ESP_BLUFI_EVENT_REQ_CONNECT_TO_AP
ESP_BLUFI_EVENT_REQ_DISCONNECT_FROM_AP
ESP_BLUFI_EVENT_GET_WIFI_STATUS
ESP_BLUFI_EVENT_DEAUTHENTICATE_STA
ESP_BLUFI_EVENT_RECV_STA_BSSID
ESP_BLUFI_EVENT_RECV_STA_SSID
ESP_BLUFI_EVENT_RECV_STA_PASSWD
ESP_BLUFI_EVENT_RECV_SOFTAP_SSID
ESP_BLUFI_EVENT_RECV_SOFTAP_PASSWD
ESP_BLUFI_EVENT_RECV_SOFTAP_MAX_CONN_NUM
ESP_BLUFI_EVENT_RECV_SOFTAP_AUTH_MODE
ESP_BLUFI_EVENT_RECV_SOFTAP_CHANNEL
ESP_BLUFI_EVENT_RECV_USERNAME
ESP_BLUFI_EVENT_RECV_CA_CERT
ESP_BLUFI_EVENT_RECV_CLIENT_CERT
ESP_BLUFI_EVENT_RECV_SERVER_CERT
ESP_BLUFI_EVENT_RECV_CLIENT_PRIV_KEY
ESP_BLUFI_EVENT_RECV_SERVER_PRIV_KEY
enum esp_blufi_sta_conn_state_t

BLUFI config status.

Values:

ESP_BLUFI_STA_CONN_SUCCESS = 0x00
ESP_BLUFI_STA_CONN_FAIL = 0x01
enum esp_blufi_init_state_t

BLUFI init status.

Values:

ESP_BLUFI_INIT_OK = 0
ESP_BLUFI_INIT_FAILED = 0
enum esp_blufi_deinit_state_t

BLUFI deinit status.

Values:

ESP_BLUFI_DEINIT_OK = 0
ESP_BLUFI_DEINIT_FAILED = 0
Structures
struct esp_blufi_extra_info_t

BLUFI extra information structure.

Public Members

uint8_t sta_bssid[6]

BSSID of station interface

bool sta_bssid_set

is BSSID of station interface set

uint8_t *sta_ssid

SSID of station interface

int sta_ssid_len

length of SSID of station interface

uint8_t *sta_passwd

password of station interface

int sta_passwd_len

length of password of station interface

uint8_t *softap_ssid

SSID of softap interface

int softap_ssid_len

length of SSID of softap interface

uint8_t *softap_passwd

password of station interface

int softap_passwd_len

length of password of station interface

uint8_t softap_authmode

authentication mode of softap interface

bool softap_authmode_set

is authentication mode of softap interface set

uint8_t softap_max_conn_num

max connection number of softap interface

bool softap_max_conn_num_set

is max connection number of softap interface set

uint8_t softap_channel

channel of softap interface

bool softap_channel_set

is channel of softap interface set

Warning

doxygenstruct: Cannot find class “esp_blufi_cb_param_t” in doxygen xml output for project “esp32-idf” from directory: xml/

struct esp_blufi_cb_param_t::blufi_init_finish_evt_param

ESP_BLUFI_EVENT_INIT_FINISH.

Public Members

esp_blufi_init_state_t state

Initial status

struct esp_blufi_cb_param_t::blufi_deinit_finish_evt_param

ESP_BLUFI_EVENT_DEINIT_FINISH.

Public Members

esp_blufi_deinit_state_t state

De-initial status

struct esp_blufi_cb_param_t::blufi_set_wifi_mode_evt_param

ESP_BLUFI_EVENT_SET_WIFI_MODE.

Public Members

wifi_mode_t op_mode

Wifi operation mode

struct esp_blufi_cb_param_t::blufi_connect_evt_param

ESP_BLUFI_EVENT_CONNECT.

Public Members

esp_bd_addr_t remote_bda

Blufi Remote bluetooth device address

struct esp_blufi_cb_param_t::blufi_disconnect_evt_param

ESP_BLUFI_EVENT_DISCONNECT.

Public Members

esp_bd_addr_t remote_bda

Blufi Remote bluetooth device address

struct esp_blufi_cb_param_t::blufi_recv_sta_bssid_evt_param

ESP_BLUFI_EVENT_RECV_STA_BSSID.

Public Members

uint8_t bssid[6]

BSSID

struct esp_blufi_cb_param_t::blufi_recv_sta_ssid_evt_param

ESP_BLUFI_EVENT_RECV_STA_SSID.

Public Members

uint8_t *ssid

SSID

int ssid_len

SSID length

struct esp_blufi_cb_param_t::blufi_recv_sta_passwd_evt_param

ESP_BLUFI_EVENT_RECV_STA_PASSWD.

Public Members

uint8_t *passwd

Password

int passwd_len

Password Length

struct esp_blufi_cb_param_t::blufi_recv_softap_ssid_evt_param

ESP_BLUFI_EVENT_RECV_SOFTAP_SSID.

Public Members

uint8_t *ssid

SSID

int ssid_len

SSID length

struct esp_blufi_cb_param_t::blufi_recv_softap_passwd_evt_param

ESP_BLUFI_EVENT_RECV_SOFTAP_PASSWD.

Public Members

uint8_t *passwd

Password

int passwd_len

Password Length

struct esp_blufi_cb_param_t::blufi_recv_softap_max_conn_num_evt_param

ESP_BLUFI_EVENT_RECV_SOFTAP_MAX_CONN_NUM.

Public Members

int max_conn_num

SSID

struct esp_blufi_cb_param_t::blufi_recv_softap_auth_mode_evt_param

ESP_BLUFI_EVENT_RECV_SOFTAP_AUTH_MODE.

Public Members

wifi_auth_mode_t auth_mode

Authentication mode

struct esp_blufi_cb_param_t::blufi_recv_softap_channel_evt_param

ESP_BLUFI_EVENT_RECV_SOFTAP_CHANNEL.

Public Members

uint8_t channel

Authentication mode

struct esp_blufi_cb_param_t::blufi_recv_username_evt_param

ESP_BLUFI_EVENT_RECV_USERNAME.

Public Members

uint8_t *name

Username point

int name_len

Username length

struct esp_blufi_cb_param_t::blufi_recv_ca_evt_param

ESP_BLUFI_EVENT_RECV_CA_CERT.

Public Members

uint8_t *cert

CA certificate point

int cert_len

CA certificate length

struct esp_blufi_cb_param_t::blufi_recv_client_cert_evt_param

ESP_BLUFI_EVENT_RECV_CLIENT_CERT

Public Members

uint8_t *cert

Client certificate point

int cert_len

Client certificate length

struct esp_blufi_cb_param_t::blufi_recv_server_cert_evt_param

ESP_BLUFI_EVENT_RECV_SERVER_CERT

Public Members

uint8_t *cert

Client certificate point

int cert_len

Client certificate length

struct esp_blufi_cb_param_t::blufi_recv_client_pkey_evt_param

ESP_BLUFI_EVENT_RECV_CLIENT_PRIV_KEY

Public Members

uint8_t *pkey

Client Private Key point, if Client certificate not contain Key

int pkey_len

Client Private key length

struct esp_blufi_cb_param_t::blufi_recv_server_pkey_evt_param

ESP_BLUFI_EVENT_RECV_SERVER_PRIV_KEY

Public Members

uint8_t *pkey

Client Private Key point, if Client certificate not contain Key

int pkey_len

Client Private key length

struct esp_blufi_callbacks_t

BLUFI callback functions type.

Public Members

esp_blufi_event_cb_t event_cb

BLUFI event callback

esp_blufi_negotiate_data_handler_t negotiate_data_handler

BLUFI negotiate data function for negotiate share key

esp_blufi_encrypt_func_t encrypt_func

BLUFI encrypt data function with share key generated by negotiate_data_handler

esp_blufi_decrypt_func_t decrypt_func

BLUFI decrypt data function with share key generated by negotiate_data_handler

esp_blufi_checksum_func_t checksum_func

BLUFI check sum function (FCS)

Functions
esp_err_t esp_blufi_register_callbacks(esp_blufi_callbacks_t *callbacks)

This function is called to receive blufi callback event.

Return
ESP_OK - success, other - failed
Parameters
  • callbacks: callback functions

esp_err_t esp_blufi_profile_init(void)

This function is called to initialize blufi_profile.

Return
ESP_OK - success, other - failed

esp_err_t esp_blufi_profile_deinit(void)

This function is called to de-initialize blufi_profile.

Return
ESP_OK - success, other - failed

esp_err_t esp_blufi_send_wifi_conn_report(wifi_mode_t opmode, esp_blufi_sta_conn_state_t sta_conn_state, uint8_t softap_conn_num, esp_blufi_extra_info_t *extra_info)

This function is called to send wifi connection report.

Return
ESP_OK - success, other - failed
Parameters
  • opmode: : wifi opmode
  • sta_conn_state: : station is already in connection or not
  • softap_conn_num: : softap connection number
  • extra_info: : extra information, such as sta_ssid, softap_ssid and etc.

uint16_t esp_blufi_get_version(void)

Get BLUFI profile version.

Return
Most 8bit significant is Great version, Least 8bit is Sub version

Watchdogs

Overview

Esp-idf has support for two types of watchdogs: a task watchdog as well as an interrupt watchdog. Both can be enabled using make menuconfig and selecting the appropriate options.

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

Any tasks can elect to be watched by the task watchdog. If such a task does not feed the watchdog within the time specified by the task watchdog timeout (which is configurable using make menuconfig), the watchdog will print out a warning with information about which processes are running on the ESP32 CPUs and which processes failed to feed the watchdog.

By default, the task watchdog watches the idle tasks. The usual cause of idle tasks not feeding the watchdog is a higher-priority process looping without yielding to the lower-priority processes, and can be an indicator of badly-written code that spinloops on a peripheral or a task that is stuck in an infinite loop.

Other task can elect to be watched by the task watchdog by calling esp_task_wdt_feed(). Calling this routine for the first time will register the task to the task watchdog; calling it subsequent times will feed the watchdog. If a task does not want to be watched anymore (e.g. because it is finished and will call vTaskDelete() on itself), it needs to call esp_task_wdt_delete().

The task watchdog is built around the hardware watchdog in timer group 0. If this watchdog for some reason cannot execute the interrupt handler that prints the task data (e.g. because IRAM is overwritten by garbage or interrupts are disabled entirely) it will hard-reset the SOC.

JTAG and watchdogs

While debugging using OpenOCD, if the CPUs are halted the watchdogs will keep running, eventually resetting the CPU. This makes it very hard to debug code; that is why the OpenOCD config will disable both watchdogs on startup. This does mean that you will not get any warnings or panics from either the task or interrupt watchdog when the ESP32 is connected to OpenOCD via JTAG.

Functions

void esp_int_wdt_init()

Initialize the interrupt watchdog. This is called in the init code if the interrupt watchdog is enabled in menuconfig.

void esp_task_wdt_init()

Initialize the task watchdog. This is called in the init code, if the task watchdog is enabled in menuconfig.

void esp_task_wdt_feed()

Feed the watchdog. After the first feeding session, the watchdog will expect the calling task to keep feeding the watchdog until task_wdt_delete() is called.

void esp_task_wdt_delete()

Delete the watchdog for the current task.

OTA

API Reference

Macros

ESP_ERR_OTA_BASE

base error code for ota_ops api

ESP_ERR_OTA_PARTITION_CONFLICT

want to write or erase current running partition

ESP_ERR_OTA_SELECT_INFO_INVALID

ota data partition info is error

ESP_ERR_OTA_VALIDATE_FAILED

validate ota image failed

Type Definitions

typedef uint32_t esp_ota_handle_t

Opaque handle for application update obtained from app_ops.

Functions

esp_err_t esp_ota_begin(const esp_partition_t *partition, size_t image_size, esp_ota_handle_t *out_handle)

format input partition in flash to 0xFF as input image size, if unkown image size ,pass 0x0 or 0xFFFFFFFF, it will erase all the partition ,Otherwise, erase the required range

Return
:
  • ESP_OK: if format ota image OK
  • ESP_ERR_OTA_PARTITION_CONFLICT: operate current running bin
  • ESP_ERR_OTA_SELECT_INFO_INVALID: ota bin select info invalid
Parameters
  • partition: Pointer to partition structure which need to be updated Must be non-NULL.
  • image_size: size of image need to be updated
  • out_handle: handle which should be used for esp_ota_write or esp_ota_end call

esp_err_t esp_ota_write(esp_ota_handle_t handle, const void *data, size_t size)

Write data to input input partition.

Return
:
  • ESP_OK: if write flash data OK
  • ESP_ERR_OTA_PARTITION_CONFLICT: operate current running bin
  • ESP_ERR_OTA_SELECT_INFO_INVALID: ota bin select info invalid
Parameters
  • handle: Handle obtained from esp_ota_begin
  • data: Pointer to data write to flash
  • size: data size of recieved data

esp_err_t esp_ota_end(esp_ota_handle_t handle)

Finish the update and validate written data.

Return
:
  • ESP_OK: if validate ota image pass
  • ESP_ERR_OTA_VALIDATE_FAILED: validate the ota image is invalid
Parameters
  • handle: Handle obtained from esp_ota_begin

esp_err_t esp_ota_set_boot_partition(const esp_partition_t *partition)

Set next boot partition, call system_restart() will switch to run it.

Note
if you want switch to run a bin file has never been checked before,please validate it’s signature firstly
Return
:
  • ESP_OK: if set next boot partition OK
  • ESP_ERR_OTA_SELECT_INFO_INVALID: ota bin select info invalid
Parameters
  • partition: Pointer to partition structure which need to boot

const esp_partition_t *esp_ota_get_boot_partition(void)

Get partition info of current running image.

Return
pointer to esp_partition_t structure, or NULL if no partition is found or operate flash failed,This pointer is valid for the lifetime of the application.

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.

Application Example

GPIO output and input interrupt example: examples/21_gpio.

API Reference

Macros

GPIO_SEL_0

Pin 0 selected

GPIO_SEL_1

Pin 1 selected

GPIO_SEL_2

Pin 2 selected

GPIO_SEL_3

Pin 3 selected

GPIO_SEL_4

Pin 4 selected

GPIO_SEL_5

Pin 5 selected

GPIO_SEL_6

Pin 6 selected

GPIO_SEL_7

Pin 7 selected

GPIO_SEL_8

Pin 8 selected

GPIO_SEL_9

Pin 9 selected

GPIO_SEL_10

Pin 10 selected

GPIO_SEL_11

Pin 11 selected

GPIO_SEL_12

Pin 12 selected

GPIO_SEL_13

Pin 13 selected

GPIO_SEL_14

Pin 14 selected

GPIO_SEL_15

Pin 15 selected

GPIO_SEL_16

Pin 16 selected

GPIO_SEL_17

Pin 17 selected

GPIO_SEL_18

Pin 18 selected

GPIO_SEL_19

Pin 19 selected

GPIO_SEL_21

Pin 21 selected

GPIO_SEL_22

Pin 22 selected

GPIO_SEL_23

Pin 23 selected

GPIO_SEL_25

Pin 25 selected

GPIO_SEL_26

Pin 26 selected

GPIO_SEL_27

Pin 27 selected

GPIO_SEL_32

Pin 32 selected

GPIO_SEL_33

Pin 33 selected

GPIO_SEL_34

Pin 34 selected

GPIO_SEL_35

Pin 35 selected

GPIO_SEL_36

Pin 36 selected

GPIO_SEL_37

Pin 37 selected

GPIO_SEL_38

Pin 38 selected

GPIO_SEL_39

Pin 39 selected

GPIO_PIN_REG_0
GPIO_PIN_REG_1
GPIO_PIN_REG_2
GPIO_PIN_REG_3
GPIO_PIN_REG_4
GPIO_PIN_REG_5
GPIO_PIN_REG_6
GPIO_PIN_REG_7
GPIO_PIN_REG_8
GPIO_PIN_REG_9
GPIO_PIN_REG_10
GPIO_PIN_REG_11
GPIO_PIN_REG_12
GPIO_PIN_REG_13
GPIO_PIN_REG_14
GPIO_PIN_REG_15
GPIO_PIN_REG_16
GPIO_PIN_REG_17
GPIO_PIN_REG_18
GPIO_PIN_REG_19
GPIO_PIN_REG_20
GPIO_PIN_REG_21
GPIO_PIN_REG_22
GPIO_PIN_REG_23
GPIO_PIN_REG_25
GPIO_PIN_REG_26
GPIO_PIN_REG_27
GPIO_PIN_REG_32
GPIO_PIN_REG_33
GPIO_PIN_REG_34
GPIO_PIN_REG_35
GPIO_PIN_REG_36
GPIO_PIN_REG_37
GPIO_PIN_REG_38
GPIO_PIN_REG_39
GPIO_APP_CPU_INTR_ENA
GPIO_APP_CPU_NMI_INTR_ENA
GPIO_PRO_CPU_INTR_ENA
GPIO_PRO_CPU_NMI_INTR_ENA
GPIO_SDIO_EXT_INTR_ENA
GPIO_MODE_DEF_INPUT
GPIO_MODE_DEF_OUTPUT
GPIO_MODE_DEF_OD
GPIO_PIN_COUNT
GPIO_IS_VALID_GPIO(gpio_num)
GPIO_IS_VALID_OUTPUT_GPIO(gpio_num)

Type Definitions

typedef void (*gpio_isr_t)(void *)
typedef intr_handle_t gpio_isr_handle_t

Enumerations

enum gpio_num_t

Values:

GPIO_NUM_0 = 0

GPIO0, input and output

GPIO_NUM_1 = 1

GPIO1, input and output

GPIO_NUM_2 = 2

GPIO2, input and output

GPIO_NUM_3 = 3

GPIO3, input and output

GPIO_NUM_4 = 4

GPIO4, input and output

GPIO_NUM_5 = 5

GPIO5, input and output

GPIO_NUM_6 = 6

GPIO6, input and output

GPIO_NUM_7 = 7

GPIO7, input and output

GPIO_NUM_8 = 8

GPIO8, input and output

GPIO_NUM_9 = 9

GPIO9, input and output

GPIO_NUM_10 = 10

GPIO10, input and output

GPIO_NUM_11 = 11

GPIO11, input and output

GPIO_NUM_12 = 12

GPIO12, input and output

GPIO_NUM_13 = 13

GPIO13, input and output

GPIO_NUM_14 = 14

GPIO14, input and output

GPIO_NUM_15 = 15

GPIO15, input and output

GPIO_NUM_16 = 16

GPIO16, input and output

GPIO_NUM_17 = 17

GPIO17, input and output

GPIO_NUM_18 = 18

GPIO18, input and output

GPIO_NUM_19 = 19

GPIO19, input and output

GPIO_NUM_21 = 21

GPIO21, input and output

GPIO_NUM_22 = 22

GPIO22, input and output

GPIO_NUM_23 = 23

GPIO23, input and output

GPIO_NUM_25 = 25

GPIO25, input and output

GPIO_NUM_26 = 26

GPIO26, input and output

GPIO_NUM_27 = 27

GPIO27, input and output

GPIO_NUM_32 = 32

GPIO32, input and output

GPIO_NUM_33 = 33

GPIO32, input and output

GPIO_NUM_34 = 34

GPIO34, input mode only

GPIO_NUM_35 = 35

GPIO35, input mode only

GPIO_NUM_36 = 36

GPIO36, input mode only

GPIO_NUM_37 = 37

GPIO37, input mode only

GPIO_NUM_38 = 38

GPIO38, input mode only

GPIO_NUM_39 = 39

GPIO39, input mode only

GPIO_NUM_MAX = 40
enum gpio_int_type_t

Values:

GPIO_INTR_DISABLE = 0

Disable GPIO interrupt

GPIO_INTR_POSEDGE = 1

GPIO interrupt type : rising edge

GPIO_INTR_NEGEDGE = 2

GPIO interrupt type : falling edge

GPIO_INTR_ANYEDGE = 3

GPIO interrupt type : both rising and falling edge

GPIO_INTR_LOW_LEVEL = 4

GPIO interrupt type : input low level trigger

GPIO_INTR_HIGH_LEVEL = 5

GPIO interrupt type : input high level trigger

GPIO_INTR_MAX
enum gpio_mode_t

Values:

GPIO_MODE_INPUT = GPIO_MODE_DEF_INPUT

GPIO mode : input only

GPIO_MODE_OUTPUT = GPIO_MODE_DEF_OUTPUT

GPIO mode : output only mode

GPIO_MODE_OUTPUT_OD = ((GPIO_MODE_DEF_OUTPUT)|(GPIO_MODE_DEF_OD))

GPIO mode : output only with open-drain mode

GPIO_MODE_INPUT_OUTPUT_OD = ((GPIO_MODE_DEF_INPUT)|(GPIO_MODE_DEF_OUTPUT)|(GPIO_MODE_DEF_OD))

GPIO mode : output and input with open-drain mode

GPIO_MODE_INPUT_OUTPUT = ((GPIO_MODE_DEF_INPUT)|(GPIO_MODE_DEF_OUTPUT))

GPIO mode : output and input mode

enum gpio_pullup_t

Values:

GPIO_PULLUP_DISABLE = 0x0

Disable GPIO pull-up resistor

GPIO_PULLUP_ENABLE = 0x1

Enable GPIO pull-up resistor

enum gpio_pulldown_t

Values:

GPIO_PULLDOWN_DISABLE = 0x0

Disable GPIO pull-down resistor

GPIO_PULLDOWN_ENABLE = 0x1

Enable GPIO pull-down resistor

enum gpio_pull_mode_t

Values:

GPIO_PULLUP_ONLY

Pad pull up

GPIO_PULLDOWN_ONLY

Pad pull down

GPIO_PULLUP_PULLDOWN

Pad pull up + pull down

GPIO_FLOATING

Pad floating

Structures

struct gpio_config_t

Configuration parameters of GPIO pad for gpio_config function.

Public Members

uint64_t pin_bit_mask

GPIO pin: set with bit mask, each bit maps to a GPIO

gpio_mode_t mode

GPIO mode: set input/output mode

gpio_pullup_t pull_up_en

GPIO pull-up

gpio_pulldown_t pull_down_en

GPIO pull-down

gpio_int_type_t intr_type

GPIO interrupt type

Functions

esp_err_t gpio_config(gpio_config_t *pGPIOConfig)

GPIO common configuration.

Configure GPIO’s Mode,pull-up,PullDown,IntrType

Return
  • ESP_OK success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • pGPIOConfig: Pointer to GPIO configure struct

esp_err_t gpio_set_intr_type(gpio_num_t gpio_num, gpio_int_type_t intr_type)

GPIO set interrupt trigger type.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • gpio_num: GPIO number. If you want to set the trigger type of e.g. of GPIO16, gpio_num should be GPIO_NUM_16 (16);
  • intr_type: Interrupt type, select from gpio_int_type_t

esp_err_t gpio_intr_enable(gpio_num_t gpio_num)

Enable GPIO module interrupt signal.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • gpio_num: GPIO number. If you want to enable an interrupt on e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16);

esp_err_t gpio_intr_disable(gpio_num_t gpio_num)

Disable GPIO module interrupt signal.

Return
  • ESP_OK success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • gpio_num: GPIO number. If you want to disable the interrupt of e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16);

esp_err_t gpio_set_level(gpio_num_t gpio_num, uint32_t level)

GPIO set output level.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG GPIO number error
Parameters
  • gpio_num: GPIO number. If you want to set the output level of e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16);
  • level: Output level. 0: low ; 1: high

int gpio_get_level(gpio_num_t gpio_num)

GPIO get input level.

Return
  • 0 the GPIO input level is 0
  • 1 the GPIO input level is 1
Parameters
  • gpio_num: GPIO number. If you want to get the logic level of e.g. pin GPIO16, gpio_num should be GPIO_NUM_16 (16);

esp_err_t gpio_set_direction(gpio_num_t gpio_num, gpio_mode_t mode)

GPIO set direction.

Configure GPIO direction,such as output_only,input_only,output_and_input

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG GPIO error
Parameters
  • gpio_num: Configure GPIO pins number, it should be GPIO number. If you want to set direction of e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16);
  • mode: GPIO direction

esp_err_t gpio_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull)

GPIO set pull.

User this Function,configure GPIO pull mode,such as pull-up,pull-down

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG : Parameter error
Parameters
  • gpio_num: GPIO number. If you want to set pull up or down mode for e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16);
  • pull: GPIO pull up/down mode.

esp_err_t gpio_wakeup_enable(gpio_num_t gpio_num, gpio_int_type_t intr_type)

enable GPIO wake-up function.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • gpio_num: GPIO number.
  • intr_type: GPIO wake-up type. Only GPIO_INTR_LOW_LEVEL or GPIO_INTR_HIGH_LEVEL can be used.

esp_err_t gpio_wakeup_disable(gpio_num_t gpio_num)

Disable GPIO wake-up function.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • gpio_num: GPIO number

esp_err_t gpio_isr_register(void (*fn)(void *), void *arg, int intr_alloc_flags, gpio_isr_handle_t *handle, )

register GPIO interrupt handler, the handler is an ISR. The handler will be attached to the same CPU core that this function is running on.

Return
  • ESP_OK Success ;
  • ESP_ERR_INVALID_ARG GPIO error
Parameters
  • fn: Interrupt handler function.
  • intr_alloc_flags: Flags used to allocate the interrupt. One or multiple (ORred) ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info.
  • arg: Parameter for handler function
  • handle: Pointer to return handle. If non-NULL, a handle for the interrupt will be returned here.

esp_err_t gpio_pullup_en(gpio_num_t gpio_num)

Enable pull-up on GPIO.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • gpio_num: GPIO number

esp_err_t gpio_pullup_dis(gpio_num_t gpio_num)

Disable pull-up on GPIO.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • gpio_num: GPIO number

esp_err_t gpio_pulldown_en(gpio_num_t gpio_num)

Enable pull-down on GPIO.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • gpio_num: GPIO number

esp_err_t gpio_pulldown_dis(gpio_num_t gpio_num)

Disable pull-down on GPIO.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • gpio_num: GPIO number

esp_err_t gpio_install_isr_service(int intr_alloc_flags)

Install a GPIO ISR service, so we can assign different ISR handler for different pins.

Return
  • ESP_OK Success
  • ESP_FAIL Operation fail
  • ESP_ERR_NO_MEM No memory to install this service
Parameters
  • intr_alloc_flags: Flags used to allocate the interrupt. One or multiple (ORred) ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info.

void gpio_uninstall_isr_service()

Un-install GPIO ISR service, free the resources.

esp_err_t gpio_isr_handler_add(gpio_num_t gpio_num, gpio_isr_t isr_handler, void *args)

Add ISR handler for the corresponding GPIO.

Interrupt handlers no longer need to be declared with IRAM_ATTR, unless you pass the ESP_INTR_FLAG_IRAM flag when allocating the ISR in gpio_install_isr_service(). This ISR handler will be called from an ISR. So there probably is some stack size limit, and this limit is smaller compared to a “raw” interrupt handler due to another level of indirection.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_STATE Wrong state, the ISR service has not been initialized.
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • gpio_num: GPIO number
  • isr_handler: ISR handler function for the corresponding GPIO number.
  • args: parameter for ISR handler.

esp_err_t gpio_isr_handler_remove(gpio_num_t gpio_num)

Remove ISR handler for the corresponding GPIO.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_STATE Wrong state, the ISR service has not been initialized.
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • gpio_num: GPIO number

UART

Overview

Instructions

Application Example

Instructions

API Reference

Instructions

Data Structures

struct uart_config_t

UART configuration parameters for uart_param_config function.

Public Members

int baud_rate

UART baudrate

uart_word_length_t data_bits

UART byte size

uart_parity_t parity

UART parity mode

uart_stop_bits_t stop_bits

UART stop bits

uart_hw_flowcontrol_t flow_ctrl

UART HW flow control mode(cts/rts)

uint8_t rx_flow_ctrl_thresh

UART HW RTS threshold

struct uart_intr_config_t

UART interrupt configuration parameters for uart_intr_config function.

Public Members

uint32_t intr_enable_mask

UART interrupt enable mask, choose from UART_XXXX_INT_ENA_M under UART_INT_ENA_REG(i), connect with bit-or operator

uint8_t rx_timeout_thresh

UART timeout interrupt threshold(unit: time of sending one byte)

uint8_t txfifo_empty_intr_thresh

UART TX empty interrupt threshold.

uint8_t rxfifo_full_thresh

UART RX full interrupt threshold.

struct uart_event_t

Event structure used in UART event queue.

Public Members

uart_event_type_t type

UART event type

size_t size

UART data size for UART_DATA event

Macros

UART_FIFO_LEN

Length of the hardware FIFO buffers

UART_INTR_MASK

mask of all UART interrupts

UART_LINE_INV_MASK

TBD

UART_BITRATE_MAX

Max bit rate supported by UART

UART_PIN_NO_CHANGE

Constant for uart_set_pin function which indicates that UART pin should not be changed

UART_INVERSE_DISABLE

Disable UART signal inverse

UART_INVERSE_RXD

UART RXD input inverse

UART_INVERSE_CTS

UART CTS input inverse

UART_INVERSE_TXD

UART TXD output inverse

UART_INVERSE_RTS

UART RTS output inverse

Enumerations

enum uart_word_length_t

UART word length constants.

Values:

UART_DATA_5_BITS = 0x0

word length: 5bits

UART_DATA_6_BITS = 0x1

word length: 6bits

UART_DATA_7_BITS = 0x2

word length: 7bits

UART_DATA_8_BITS = 0x3

word length: 8bits

UART_DATA_BITS_MAX = 0X4
enum uart_stop_bits_t

UART stop bits number.

Values:

UART_STOP_BITS_1 = 0x1

stop bit: 1bit

UART_STOP_BITS_1_5 = 0x2

stop bit: 1.5bits

UART_STOP_BITS_2 = 0x3

stop bit: 2bits

UART_STOP_BITS_MAX = 0x4
enum uart_port_t

UART peripheral number.

Values:

UART_NUM_0 = 0x0

UART base address 0x3ff40000

UART_NUM_1 = 0x1

UART base address 0x3ff50000

UART_NUM_2 = 0x2

UART base address 0x3ff6E000

UART_NUM_MAX
enum uart_parity_t

UART parity constants.

Values:

UART_PARITY_DISABLE = 0x0

Disable UART parity

UART_PARITY_EVEN = 0x2

Enable UART even parity

UART_PARITY_ODD = 0x3

Enable UART odd parity

enum uart_hw_flowcontrol_t

UART hardware flow control modes.

Values:

UART_HW_FLOWCTRL_DISABLE = 0x0

disable hardware flow control

UART_HW_FLOWCTRL_RTS = 0x1

enable RX hardware flow control (rts)

UART_HW_FLOWCTRL_CTS = 0x2

enable TX hardware flow control (cts)

UART_HW_FLOWCTRL_CTS_RTS = 0x3

enable hardware flow control

UART_HW_FLOWCTRL_MAX = 0x4
enum uart_event_type_t

UART event types used in the ringbuffer.

Values:

UART_DATA

UART data event

UART_BREAK

UART break event

UART_BUFFER_FULL

UART RX buffer full event

UART_FIFO_OVF

UART FIFO overflow event

UART_FRAME_ERR

UART RX frame error event

UART_PARITY_ERR

UART RX parity event

UART_DATA_BREAK

UART TX data and break event

UART_EVENT_MAX

UART event max index

UART_PATTERN_DET

UART pattern detected

Functions

esp_err_t uart_set_word_length(uart_port_t uart_num, uart_word_length_t data_bit)

Set UART data bits.

Return
  • ESP_OK Success
  • ESP_FAIL Parameter error
Parameters
  • uart_num: UART_NUM_0, UART_NUM_1 or UART_NUM_2
  • data_bit: UART data bits

esp_err_t uart_get_word_length(uart_port_t uart_num, uart_word_length_t *data_bit)

Get UART data bits.

Return
  • ESP_FAIL Parameter error
  • ESP_OK Success, result will be put in (*data_bit)
Parameters
  • uart_num: UART_NUM_0, UART_NUM_1 or UART_NUM_2
  • data_bit: Pointer to accept value of UART data bits.

esp_err_t uart_set_stop_bits(uart_port_t uart_num, uart_stop_bits_t stop_bits)

Set UART stop bits.

Return
  • ESP_OK Success
  • ESP_FAIL Fail
Parameters
  • uart_num: UART_NUM_0, UART_NUM_1 or UART_NUM_2
  • stop_bits: UART stop bits

esp_err_t uart_get_stop_bits(uart_port_t uart_num, uart_stop_bits_t *stop_bits)

Set UART stop bits.

Return
  • ESP_FAIL Parameter error
  • ESP_OK Success, result will be put in (*stop_bit)
Parameters
  • uart_num: UART_NUM_0, UART_NUM_1 or UART_NUM_2
  • stop_bits: Pointer to accept value of UART stop bits.

esp_err_t uart_set_parity(uart_port_t uart_num, uart_parity_t parity_mode)

Set UART parity.

Return
  • ESP_FAIL Parameter error
  • ESP_OK Success
Parameters
  • uart_num: UART_NUM_0, UART_NUM_1 or UART_NUM_2
  • parity_mode: the enum of uart parity configuration

esp_err_t uart_get_parity(uart_port_t uart_num, uart_parity_t *parity_mode)

Get UART parity mode.

Return
  • ESP_FAIL Parameter error
  • ESP_OK Success, result will be put in (*parity_mode)
Parameters
  • uart_num: UART_NUM_0, UART_NUM_1 or UART_NUM_2
  • parity_mode: Pointer to accept value of UART parity mode.

esp_err_t uart_set_baudrate(uart_port_t uart_num, uint32_t baudrate)

Set UART baud rate.

Return
  • ESP_FAIL Parameter error
  • ESP_OK Success
Parameters
  • uart_num: UART_NUM_0, UART_NUM_1 or UART_NUM_2
  • baudrate: UART baud rate.

esp_err_t uart_get_baudrate(uart_port_t uart_num, uint32_t *baudrate)

Get UART bit-rate.

Return
  • ESP_FAIL Parameter error
  • ESP_OK Success, result will be put in (*baudrate)
Parameters
  • uart_num: UART_NUM_0, UART_NUM_1 or UART_NUM_2
  • baudrate: Pointer to accept value of UART baud rate

esp_err_t uart_set_line_inverse(uart_port_t uart_num, uint32_t inverse_mask)

Set UART line inverse mode.

Return
  • ESP_OK Success
  • ESP_FAIL Parameter error
Parameters
  • uart_num: UART_NUM_0, UART_NUM_1 or UART_NUM_2
  • inverse_mask: Choose the wires that need to be inverted. Inverse_mask should be chosen from UART_INVERSE_RXD/UART_INVERSE_TXD/UART_INVERSE_RTS/UART_INVERSE_CTS, combine with OR operation.

esp_err_t uart_set_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t flow_ctrl, uint8_t rx_thresh)

Set hardware flow control.

Return
  • ESP_OK Success
  • ESP_FAIL Parameter error
Parameters
  • uart_num: UART_NUM_0, UART_NUM_1 or UART_NUM_2
  • flow_ctrl: Hardware flow control mode
  • rx_thresh: Threshold of Hardware RX flow control(0 ~ UART_FIFO_LEN). Only when UART_HW_FLOWCTRL_RTS is set, will the rx_thresh value be set.

esp_err_t uart_get_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t *flow_ctrl)

Get hardware flow control mode.

Return
  • ESP_FAIL Parameter error
  • ESP_OK Success, result will be put in (*flow_ctrl)
Parameters
  • uart_num: UART_NUM_0, UART_NUM_1 or UART_NUM_2
  • flow_ctrl: Option for different flow control mode.

esp_err_t uart_clear_intr_status(uart_port_t uart_num, uint32_t clr_mask)

Clear UART interrupt status.

Return
  • ESP_OK Success
  • ESP_FAIL Parameter error
Parameters
  • uart_num: UART_NUM_0, UART_NUM_1 or UART_NUM_2
  • clr_mask: Bit mask of the status that to be cleared. enable_mask should be chosen from the fields of register UART_INT_CLR_REG.

esp_err_t uart_enable_intr_mask(uart_port_t uart_num, uint32_t enable_mask)

Set UART interrupt enable.

Return
  • ESP_OK Success
  • ESP_FAIL Parameter error
Parameters
  • uart_num: UART_NUM_0, UART_NUM_1 or UART_NUM_2
  • enable_mask: Bit mask of the enable bits. enable_mask should be chosen from the fields of register UART_INT_ENA_REG.

esp_err_t uart_disable_intr_mask(uart_port_t uart_num, uint32_t disable_mask)

Clear UART interrupt enable bits.

Return
  • ESP_OK Success
  • ESP_FAIL Parameter error
Parameters
  • uart_num: UART_NUM_0, UART_NUM_1 or UART_NUM_2
  • disable_mask: Bit mask of the disable bits. disable_mask should be chosen from the fields of register UART_INT_ENA_REG.

esp_err_t uart_enable_rx_intr(uart_port_t uart_num)

Enable UART RX interrupt(RX_FULL & RX_TIMEOUT INTERRUPT)

Return
  • ESP_OK Success
  • ESP_FAIL Parameter error
Parameters
  • uart_num: UART_NUM_0, UART_NUM_1 or UART_NUM_2

esp_err_t uart_disable_rx_intr(uart_port_t uart_num)

Disable UART RX interrupt(RX_FULL & RX_TIMEOUT INTERRUPT)

Return
  • ESP_OK Success
  • ESP_FAIL Parameter error
Parameters
  • uart_num: UART_NUM_0, UART_NUM_1 or UART_NUM_2

esp_err_t uart_disable_tx_intr(uart_port_t uart_num)

Disable UART TX interrupt(RX_FULL & RX_TIMEOUT INTERRUPT)

Return
  • ESP_OK Success
  • ESP_FAIL Parameter error
Parameters
  • uart_num: UART_NUM_0, UART_NUM_1 or UART_NUM_2

esp_err_t uart_enable_tx_intr(uart_port_t uart_num, int enable, int thresh)

Enable UART TX interrupt(RX_FULL & RX_TIMEOUT INTERRUPT)

Return
  • ESP_OK Success
  • ESP_FAIL Parameter error
Parameters
  • uart_num: UART_NUM_0, UART_NUM_1 or UART_NUM_2
  • enable: 1: enable; 0: disable
  • thresh: Threshold of TX interrupt, 0 ~ UART_FIFO_LEN

esp_err_t uart_isr_register(uart_port_t uart_num, void (*fn)(void *), void *arg, int intr_alloc_flags, uart_isr_handle_t *handle, )

register UART interrupt handler(ISR).

Note
UART ISR handler will be attached to the same CPU core that this function is running on.
Return
  • ESP_OK Success
  • ESP_FAIL Parameter error
Parameters
  • uart_num: UART_NUM_0, UART_NUM_1 or UART_NUM_2
  • fn: Interrupt handler function.
  • arg: parameter for handler function
  • intr_alloc_flags: Flags used to allocate the interrupt. One or multiple (ORred) ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info.
  • handle: Pointer to return handle. If non-NULL, a handle for the interrupt will be returned here.

esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int rts_io_num, int cts_io_num)

Set UART pin number.

Note
Internal signal can be output to multiple GPIO pads. Only one GPIO pad can connect with input signal.
Return
  • ESP_OK Success
  • ESP_FAIL Parameter error
Parameters
  • uart_num: UART_NUM_0, UART_NUM_1 or UART_NUM_2
  • tx_io_num: UART TX pin GPIO number, if set to UART_PIN_NO_CHANGE, use the current pin.
  • rx_io_num: UART RX pin GPIO number, if set to UART_PIN_NO_CHANGE, use the current pin.
  • rts_io_num: UART RTS pin GPIO number, if set to UART_PIN_NO_CHANGE, use the current pin.
  • cts_io_num: UART CTS pin GPIO number, if set to UART_PIN_NO_CHANGE, use the current pin.

esp_err_t uart_set_rts(uart_port_t uart_num, int level)

UART set RTS level (before inverse) UART rx hardware flow control should not be set.

Return
  • ESP_OK Success
  • ESP_FAIL Parameter error
Parameters
  • uart_num: UART_NUM_0, UART_NUM_1 or UART_NUM_2
  • level: 1: RTS output low(active); 0: RTS output high(block)

esp_err_t uart_set_dtr(uart_port_t uart_num, int level)

UART set DTR level (before inverse)

Return
  • ESP_OK Success
  • ESP_FAIL Parameter error
Parameters
  • uart_num: UART_NUM_0, UART_NUM_1 or UART_NUM_2
  • level: 1: DTR output low; 0: DTR output high

esp_err_t uart_param_config(uart_port_t uart_num, const uart_config_t *uart_config)

UART parameter configure.

Return
  • ESP_OK Success
  • ESP_FAIL Parameter error
Parameters
  • uart_num: UART_NUM_0, UART_NUM_1 or UART_NUM_2
  • uart_config: UART parameter settings

esp_err_t uart_intr_config(uart_port_t uart_num, const uart_intr_config_t *intr_conf)

UART interrupt configure.

Return
  • ESP_OK Success
  • ESP_FAIL Parameter error
Parameters
  • uart_num: UART_NUM_0, UART_NUM_1 or UART_NUM_2
  • intr_conf: UART interrupt settings

esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_buffer_size, int queue_size, QueueHandle_t *uart_queue, int intr_alloc_flags)

Install UART driver.

UART ISR handler will be attached to the same CPU core that this function is running on. Users should know that which CPU is running and then pick a INUM that is not used by system. We can find the information of INUM and interrupt level in soc.h.

Return
  • ESP_OK Success
  • ESP_FAIL Parameter error
Parameters
  • uart_num: UART_NUM_0, UART_NUM_1 or UART_NUM_2
  • rx_buffer_size: UART RX ring buffer size, rx_buffer_size should be greater than UART_FIFO_LEN.
  • tx_buffer_size: UART TX ring buffer size. If set to zero, driver will not use TX buffer, TX function will block task until all data have been sent out..
  • queue_size: UART event queue size/depth.
  • uart_queue: UART event queue handle (out param). On success, a new queue handle is written here to provide access to UART events. If set to NULL, driver will not use an event queue.
  • intr_alloc_flags: Flags used to allocate the interrupt. One or multiple (ORred) ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info.

esp_err_t uart_driver_delete(uart_port_t uart_num)

Uninstall UART driver.

Return
  • ESP_OK Success
  • ESP_FAIL Parameter error
Parameters
  • uart_num: UART_NUM_0, UART_NUM_1 or UART_NUM_2

esp_err_t uart_wait_tx_done(uart_port_t uart_num, TickType_t ticks_to_wait)

Wait UART TX FIFO empty.

Return
  • ESP_OK Success
  • ESP_FAIL Parameter error
  • ESP_ERR_TIMEOUT Timeout
Parameters
  • uart_num: UART_NUM_0, UART_NUM_1 or UART_NUM_2
  • ticks_to_wait: Timeout, count in RTOS ticks

int uart_tx_chars(uart_port_t uart_num, const char *buffer, uint32_t len)

Send data to the UART port from a given buffer and length.

This function will not wait for the space in TX FIFO, just fill the TX FIFO and return when the FIFO is full.

Note
This function should only be used when UART TX buffer is not enabled.
Return
  • (-1) Parameter error
  • OTHERS(>=0) The number of data that pushed to the TX FIFO
Parameters
  • uart_num: UART_NUM_0, UART_NUM_1 or UART_NUM_2
  • buffer: data buffer address
  • len: data length to send

int uart_write_bytes(uart_port_t uart_num, const char *src, size_t size)

Send data to the UART port from a given buffer and length,.

If parameter tx_buffer_size is set to zero: This function will not return until all the data have been sent out, or at least pushed into TX FIFO.

Otherwise, if tx_buffer_size > 0, this function will return after copying all the data to tx ringbuffer, then, UART ISR will move data from ring buffer to TX FIFO gradually.

Return
  • (-1) Parameter error
  • OTHERS(>=0) The number of data that pushed to the TX FIFO
Parameters
  • uart_num: UART_NUM_0, UART_NUM_1 or UART_NUM_2
  • src: data buffer address
  • size: data length to send

int uart_write_bytes_with_break(uart_port_t uart_num, const char *src, size_t size, int brk_len)

Send data to the UART port from a given buffer and length,.

If parameter tx_buffer_size is set to zero: This function will not return until all the data and the break signal have been sent out. After all data send out, send a break signal.

Otherwise, if tx_buffer_size > 0, this function will return after copying all the data to tx ringbuffer, then, UART ISR will move data from ring buffer to TX FIFO gradually. After all data send out, send a break signal.

Return
  • (-1) Parameter error
  • OTHERS(>=0) The number of data that pushed to the TX FIFO
Parameters
  • uart_num: UART_NUM_0, UART_NUM_1 or UART_NUM_2
  • src: data buffer address
  • size: data length to send
  • brk_len: break signal length (unit: time of one data bit at current_baudrate)

int uart_read_bytes(uart_port_t uart_num, uint8_t *buf, uint32_t length, TickType_t ticks_to_wait)

UART read bytes from UART buffer.

Return
  • (-1) Error
  • Others return a char data from uart fifo.
Parameters
  • uart_num: UART_NUM_0, UART_NUM_1 or UART_NUM_2
  • buf: pointer to the buffer.
  • length: data length
  • ticks_to_wait: sTimeout, count in RTOS ticks

esp_err_t uart_flush(uart_port_t uart_num)

UART ring buffer flush.

Return
  • ESP_OK Success
  • ESP_FAIL Parameter error
Parameters
  • uart_num: UART_NUM_0, UART_NUM_1 or UART_NUM_2

esp_err_t uart_get_buffered_data_len(uart_port_t uart_num, size_t *size)

UART get RX ring buffer cached data length.

Return
  • ESP_OK Success
  • ESP_FAIL Parameter error
Parameters
  • uart_num: UART port number.
  • size: Pointer of size_t to accept cached data length

esp_err_t uart_disable_pattern_det_intr(uart_port_t uart_num)

UART disable pattern detect function. Designed for applications like ‘AT commands’. When the hardware detect a series of one same character, the interrupt will be triggered.

Return
  • ESP_OK Success
  • ESP_FAIL Parameter error
Parameters
  • uart_num: UART port number.

esp_err_t uart_enable_pattern_det_intr(uart_port_t uart_num, char pattern_chr, uint8_t chr_num, int chr_tout, int post_idle, int pre_idle)

UART enable pattern detect function. Designed for applications like ‘AT commands’. When the hardware detect a series of one same character, the interrupt will be triggered.

Return
  • ESP_OK Success
  • ESP_FAIL Parameter error
Parameters
  • uart_num: UART port number.
  • pattern_chr: character of the pattern
  • chr_num: number of the character, 8bit value.
  • chr_tout: timeout of the interval between each pattern characters, 24bit value, unit is APB(80Mhz) clock cycle.
  • post_idle: idle time after the last pattern character, 24bit value, unit is APB(80Mhz) clock cycle.
  • pre_idle: idle time before the first pattern character, 24bit value, unit is APB(80Mhz) clock cycle.

LED Control

Overview

The LED control 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. For maximum flexibility, the high-speed as well as the low-speed channels can be driven from one of four high-speed/low-speed timers. The PWM controller also has the ability to automatically increase or decrease the duty cycle gradually, allowing for fades without any processor interference.

Application Example

LEDC change duty cycle and fading control example: examples/29_ledc.

API Reference

Macros

LEDC_APB_CLK_HZ
LEDC_REF_CLK_HZ

Type Definitions

typedef intr_handle_t ledc_isr_handle_t

Enumerations

enum ledc_mode_t

Values:

LEDC_HIGH_SPEED_MODE = 0

LEDC high speed speed_mode

LEDC_SPEED_MODE_MAX

LEDC speed limit

enum ledc_intr_type_t

Values:

LEDC_INTR_DISABLE = 0

Disable LEDC interrupt

LEDC_INTR_FADE_END

Enable LEDC interrupt

enum ledc_duty_direction_t

Values:

LEDC_DUTY_DIR_DECREASE = 0

LEDC duty decrease direction

LEDC_DUTY_DIR_INCREASE = 1

LEDC duty increase direction

enum ledc_clk_src_t

Values:

LEDC_REF_TICK = 0

LEDC timer clock divided from reference tick(1Mhz)

LEDC_APB_CLK

LEDC timer clock divided from APB clock(80Mhz)

enum ledc_timer_t

Values:

LEDC_TIMER_0 = 0

LEDC source timer TIMER0

LEDC_TIMER_1

LEDC source timer TIMER1

LEDC_TIMER_2

LEDC source timer TIMER2

LEDC_TIMER_3

LEDC source timer TIMER3

enum ledc_channel_t

Values:

LEDC_CHANNEL_0 = 0

LEDC channel 0

LEDC_CHANNEL_1

LEDC channel 1

LEDC_CHANNEL_2

LEDC channel 2

LEDC_CHANNEL_3

LEDC channel 3

LEDC_CHANNEL_4

LEDC channel 4

LEDC_CHANNEL_5

LEDC channel 5

LEDC_CHANNEL_6

LEDC channel 6

LEDC_CHANNEL_7

LEDC channel 7

LEDC_CHANNEL_MAX
enum ledc_timer_bit_t

Values:

LEDC_TIMER_10_BIT = 10

LEDC PWM depth 10Bit

LEDC_TIMER_11_BIT = 11

LEDC PWM depth 11Bit

LEDC_TIMER_12_BIT = 12

LEDC PWM depth 12Bit

LEDC_TIMER_13_BIT = 13

LEDC PWM depth 13Bit

LEDC_TIMER_14_BIT = 14

LEDC PWM depth 14Bit

LEDC_TIMER_15_BIT = 15

LEDC PWM depth 15Bit

Structures

struct ledc_channel_config_t

Configuration parameters of LEDC channel for ledc_channel_config function.

Public Members

int gpio_num

the LEDC output gpio_num, if you want to use gpio16, gpio_num = 16

ledc_mode_t speed_mode

LEDC speed speed_mode, high-speed mode or low-speed mode

ledc_channel_t channel

LEDC channel(0 - 7)

ledc_intr_type_t intr_type

configure interrupt, Fade interrupt enable or Fade interrupt disable

ledc_timer_t timer_sel

Select the timer source of channel (0 - 3)

uint32_t duty

LEDC channel duty, the duty range is [0, (2**bit_num) - 1],

struct ledc_timer_config_t

Configuration parameters of LEDC Timer timer for ledc_timer_config function.

Public Members

ledc_mode_t speed_mode

LEDC speed speed_mode, high-speed mode or low-speed mode

ledc_timer_bit_t bit_num

LEDC channel duty depth

ledc_timer_t timer_num

The timer source of channel (0 - 3)

uint32_t freq_hz

LEDC timer frequency(Hz)

Functions

esp_err_t ledc_channel_config(ledc_channel_config_t *ledc_conf)

LEDC channel configuration Configure LEDC channel with the given channel/output gpio_num/interrupt/source timer/frequency(Hz)/LEDC depth.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • ledc_conf: Pointer of LEDC channel configure struct

esp_err_t ledc_timer_config(ledc_timer_config_t *timer_conf)

LEDC timer configuration Configure LEDC timer with the given source timer/frequency(Hz)/bit_num.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_FAIL Can not find a proper pre-divider number base on the given frequency and the current bit_num.
Parameters
  • timer_conf: Pointer of LEDC timer configure struct

esp_err_t ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t channel)

LEDC update channel parameters Call this function to activate the LEDC updated parameters. After ledc_set_duty, ledc_set_fade, we need to call this function to update the settings.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • speed_mode: Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
  • channel: LEDC channel(0-7), select from ledc_channel_t

esp_err_t ledc_stop(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t idle_level)

LEDC stop. Disable LEDC output, and set idle level.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • speed_mode: Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
  • channel: LEDC channel(0-7), select from ledc_channel_t
  • idle_level: Set output idle level after LEDC stops.

esp_err_t ledc_set_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num, uint32_t freq_hz)

LEDC set channel frequency(Hz)

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_FAIL Can not find a proper pre-divider number base on the given frequency and the current bit_num.
Parameters
  • speed_mode: Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
  • timer_num: LEDC timer index(0-3), select from ledc_timer_t
  • freq_hz: Set the LEDC frequency

uint32_t ledc_get_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num)

LEDC get channel frequency(Hz)

Return
  • 0 error
  • Others Current LEDC frequency
Parameters
  • speed_mode: Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
  • timer_num: LEDC timer index(0-3), select from ledc_timer_t

esp_err_t ledc_set_duty(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t duty)

LEDC set duty Only after calling ledc_update_duty will the duty update.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • speed_mode: Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
  • channel: LEDC channel(0-7), select from ledc_channel_t
  • duty: Set the LEDC duty, the duty range is [0, (2**bit_num) - 1]

int ledc_get_duty(ledc_mode_t speed_mode, ledc_channel_t channel)

LEDC get duty.

Return
  • (-1) parameter error
  • Others Current LEDC duty
Parameters
  • speed_mode: Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
  • channel: LEDC channel(0-7), select from ledc_channel_t

esp_err_t ledc_set_fade(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t duty, ledc_duty_direction_t gradule_direction, uint32_t step_num, uint32_t duty_cyle_num, uint32_t duty_scale)

LEDC set gradient Set LEDC gradient, After the function calls the ledc_update_duty function, the function can take effect.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • speed_mode: Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
  • channel: LEDC channel(0-7), select from ledc_channel_t
  • duty: Set the start of the gradient duty, the duty range is [0, (2**bit_num) - 1]
  • gradule_direction: Set the direction of the gradient
  • step_num: Set the number of the gradient
  • duty_cyle_num: Set how many LEDC tick each time the gradient lasts
  • duty_scale: Set gradient change amplitude

esp_err_t ledc_isr_register(void (*fn)(void *), void *arg, int intr_alloc_flags, ledc_isr_handle_t *handle, )

Register LEDC interrupt handler, the handler is an ISR. The handler will be attached to the same CPU core that this function is running on.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Function pointer error.
Parameters
  • fn: Interrupt handler function.
  • arg: User-supplied argument passed to the handler function.
  • intr_alloc_flags: Flags used to allocate the interrupt. One or multiple (ORred) ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info.
  • arg: Parameter for handler function
  • handle: Pointer to return handle. If non-NULL, a handle for the interrupt will be returned here.

esp_err_t ledc_timer_set(ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_t div_num, uint32_t bit_num, ledc_clk_src_t clk_src)

Configure LEDC settings.

Return
  • (-1) Parameter error
  • Other Current LEDC duty
Parameters
  • speed_mode: Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
  • timer_sel: Timer index(0-3), there are 4 timers in LEDC module
  • div_num: Timer clock divide number, the timer clock is divided from the selected clock source
  • bit_num: The count number of one period, counter range is 0 ~ ((2 ** bit_num) - 1)
  • clk_src: Select LEDC source clock.

esp_err_t ledc_timer_rst(ledc_mode_t speed_mode, uint32_t timer_sel)

Reset LEDC timer.

Return
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
Parameters
  • speed_mode: Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
  • timer_sel: LEDC timer index(0-3), select from ledc_timer_t

esp_err_t ledc_timer_pause(ledc_mode_t speed_mode, uint32_t timer_sel)

Pause LEDC timer counter.

Return
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
Parameters
  • speed_mode: Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
  • timer_sel: LEDC timer index(0-3), select from ledc_timer_t

esp_err_t ledc_timer_resume(ledc_mode_t speed_mode, uint32_t timer_sel)

Resume LEDC timer.

Return
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
Parameters
  • speed_mode: Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
  • timer_sel: LEDC timer index(0-3), select from ledc_timer_t

esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, uint32_t channel, uint32_t timer_idx)

Bind LEDC channel with the selected timer.

Return
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
Parameters
  • speed_mode: Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
  • channel: LEDC channel index(0-7), select from ledc_channel_t
  • timer_idx: LEDC timer index(0-3), select from ledc_timer_t

esp_err_t ledc_set_fade_with_step(ledc_mode_t speed_mode, ledc_channel_t channel, int target_duty, int scale, int cycle_num)

Set LEDC fade function. Should call ledc_fade_func_install() before calling this function. Call ledc_fade_start() after this to start fading.

Return
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
  • ESP_ERR_INVALID_STATE Fade function not installed.
Parameters
  • speed_mode: Select the LEDC speed_mode, high-speed mode and low-speed mode, For now we only support high-speed mode. We will access low-speed mode soon.
  • channel: LEDC channel index(0-7), select from ledc_channel_t
  • target_duty: Target duty of fading.( 0 - (2 ** bit_num - 1)))
  • scale: Controls the increase or decrease step scale.
  • cycle_num: increase or decrease the duty every cycle_num cycles

esp_err_t ledc_set_fade_with_time(ledc_mode_t speed_mode, ledc_channel_t channel, int target_duty, int max_fade_time_ms)

Set LEDC fade function, with a limited time. Should call ledc_fade_func_install() before calling this function. Call ledc_fade_start() after this to start fading.

Return
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
  • ESP_ERR_INVALID_STATE Fade function not installed.
Parameters
  • speed_mode: Select the LEDC speed_mode, high-speed mode and low-speed mode, For now we only support high-speed mode. We will access low-speed mode soon.
  • channel: LEDC channel index(0-7), select from ledc_channel_t
  • target_duty: Target duty of fading.( 0 - (2 ** bit_num - 1)))
  • max_fade_time_ms: The maximum time of the fading ( ms ).

esp_err_t ledc_fade_func_install(int intr_alloc_flags)

Install ledc fade function. This function will occupy interrupt of LEDC module.

Return
  • ESP_ERR_NO_MEM No enough memory
  • ESP_OK Success
  • ESP_ERR_INVALID_STATE Fade function already installed.
Parameters
  • intr_alloc_flags: Flags used to allocate the interrupt. One or multiple (ORred) ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info.

void ledc_fade_func_uninstall()

Uninstall LEDC fade function.

esp_err_t ledc_fade_start(ledc_channel_t channel, ledc_fade_mode_t wait_done)

Start LEDC fading.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_STATE Fade function not installed.
  • ESP_ERR_INVALID_ARG Parameter error.
Parameters
  • channel: LEDC channel number
  • wait_done: Whether to block until fading done.

RMT

Overview

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 many other types of signals.

Application Example

NEC remote control TX and RX example: examples/11_rmt_nec_tx_rx.

API Reference

Header Files

Macros

RMT_MEM_BLOCK_BYTE_NUM
RMT_MEM_ITEM_NUM

Enumerations

enum rmt_channel_t

Values:

RMT_CHANNEL_0 =0

RMT Channel0

RMT_CHANNEL_1

RMT Channel1

RMT_CHANNEL_2

RMT Channel2

RMT_CHANNEL_3

RMT Channel3

RMT_CHANNEL_4

RMT Channel4

RMT_CHANNEL_5

RMT Channel5

RMT_CHANNEL_6

RMT Channel6

RMT_CHANNEL_7

RMT Channel7

RMT_CHANNEL_MAX
enum rmt_mem_owner_t

Values:

RMT_MEM_OWNER_TX = 0

RMT RX mode, RMT transmitter owns the memory block

RMT_MEM_OWNER_RX = 1

RMT RX mode, RMT receiver owns the memory block

RMT_MEM_OWNER_MAX
enum rmt_source_clk_t

Values:

RMT_BASECLK_REF = 0

RMT source clock system reference tick, 1MHz by default(Not supported in this version)

RMT_BASECLK_APB

RMT source clock is APB CLK, 80Mhz by default

RMT_BASECLK_MAX
enum rmt_data_mode_t

Values:

RMT_DATA_MODE_FIFO = 0
RMT_DATA_MODE_MEM = 1
RMT_DATA_MODE_MAX
enum rmt_mode_t

Values:

RMT_MODE_TX =0

RMT TX mode

RMT_MODE_RX

RMT RX mode

RMT_MODE_MAX
enum rmt_idle_level_t

Values:

RMT_IDLE_LEVEL_LOW =0

RMT TX idle level: low Level

RMT_IDLE_LEVEL_HIGH

RMT TX idle level: high Level

RMT_IDLE_LEVEL_MAX
enum rmt_carrier_level_t

Values:

RMT_CARRIER_LEVEL_LOW =0

RMT carrier wave is modulated for low Level output

RMT_CARRIER_LEVEL_HIGH

RMT carrier wave is modulated for high Level output

RMT_CARRIER_LEVEL_MAX

Structures

struct rmt_tx_config_t

Data struct of RMT TX configure parameters.

Public Members

bool loop_en

RMT loop output mode

uint32_t carrier_freq_hz

RMT carrier frequency

uint8_t carrier_duty_percent

RMT carrier duty (%)

rmt_carrier_level_t carrier_level

RMT carrier level

bool carrier_en

RMT carrier enable

rmt_idle_level_t idle_level

RMT idle level

bool idle_output_en

RMT idle level output enable

struct rmt_rx_config_t

Data struct of RMT RX configure parameters.

Public Members

bool filter_en

RMT receiver filer enable