ESP-IDF 编程指导(中文版)

本文档是为乐鑫 IoT 开发框架(ESP-IDF)而设计的文档。ESP-IDF 是 ESP32 芯片官方的开发框架。

提示

该中文文档非乐鑫官方文档,而是由个人翻译的,以方便广大初学者。

文档源码位于 https://github.com/tidyjiang8/esp-idf-zh,欢迎大家 Star、参与翻译。

个人的能力、精力都非常有限,如果读者在阅读时发现任何翻译有误的地方,请到 这里 指出,或直接提交PR。

Get Started API Reference H/W Reference
Get Started API Reference H/W Reference
Api Guides Contribute Resources
API Guides Contribute Resources

快速入门

开发 ESP32 应用程序需要准备:

  • 安装有 Windows、Linux 或者 Mac 操作系统的 PC
  • 用于编译 ESP32 应用程序工具链
  • ESP-IDF —— 包含 ESP32 的 API 和用于操作 工具链 的脚本
  • 编写 C 语言程序的文本编辑器,例如 Eclipse
  • ESP32 开发板
Development of applications for ESP32

为 ESP32 开发应用程序

开发环境的准备工作包括以下三部分:

  1. 设置 工具链
  2. 从 GitHub 上面获取 ESP-IDF
  3. 安装和配置 Eclipse

如果你喜欢用其它的编辑器,则可以跳过最后一步。

环境设置好后,你就可以开始开发应用程序了。整个过程可以概括为如下四步:

  1. 配置 工程 并编写代码
  2. 编译 工程 并链接成一个 应用程序
  3. 烧写 应用程序ESP32 上面
  4. 监视/调试 应用程序

请继续阅读下面的指令,它将带你完成这些步骤。

指导

如果你有下面所列举的某块 ESP32 开发板,请点击对应的链接,它会教你如何让你的板子跑起来。

ESP32-DevKitC Getting Started Guide

This user guide shows how to get started with ESP32-DevKitC development board.

What You Need
  • 1 × ESP32-DevKitC board
  • 1 × USB A / mini USB B cable
  • 1 × PC loaded with Windows, Linux or Mac O/S
Overview

ESP32-DevKitC is a small-sized ESP32-based development board produced by Espressif. Most of the I/O pins are broken out to the pin headers on both sides for easy interfacing. Developers can connect these pins to peripherals as needed. Standard headers also make development easy and convenient when using a breadboard.

Functional Description

The following list and figure below describe key components, interfaces and controls of ESP32-DevKitC board.

ESP-WROOM-32
Standard ESP-WROOM-32 module soldered to the ESP32-DevKitC board.
EN
Reset button: pressing this button resets the system.
Boot
Download button: holding down the Boot button and pressing the EN button initiates the firmware download mode. Then user can download firmware through the serial port.
USB
USB interface. It functions as the power supply for the board and the communication interface between PC and ESP-WROOM-32.
I/O
Most of the pins on the ESP-WROOM-32 are broken out to the pin headers on the board. Users can program ESP32 to enable multiple functions such as PWM,ADC, DAC, I2C, I2S, SPI, etc.
ESP32-DevKitC board layout

ESP32-DevKitC board layout

Start Application Development

Before powering up the ESP32-DevKitC, please make sure that the board has been received in good condition with no obvious signs of damage.

To start development of applications, proceed to section 快速入门, that will walk you through the following steps:

  • 设置工具链 in your PC to develop applications for ESP32 in C language
  • 连接 the module to the PC and verify if it is accessible
  • 编译和烧写 an example application to the ESP32
  • 监视器 instantly what the application is doing

ESP-WROVER-KIT Getting Started Guide

This user guide shows how to get started with ESP-WROVER-KIT development board.

What You Need
  • 1 × ESP-WROVER-KIT board
  • 1 × USB A / mini USB B cable
  • 1 × PC loaded with Windows, Linux or Mac O/S
The Board

This section describes functionality of ESP-WROVER-KIT board and configuration options. If you like to start using it now, go directly to section Start Application Development

Overview

The ESP-WROVER-KIT is a development board produced by Espressif built around ESP32. This board is compatible with ESP32 modules, including the ESP-WROOM-32 and ESP32-WROVER. The ESP-WROVER-KIT features support for an LCD and MicroSD card. The I/O pins have been broken out from the ESP32 module for easy extension. The board carries an advanced multi-protocol USB bridge (the FTDI FT2232HL), enabling developers to use JTAG directly to debug the ESP32 through the USB interface. The development board makes secondary development easy and cost-effective.

注解

ESP-WROVER-KIT integrates the ESP-WROOM-32 module by default.

Functionality Overview

Block diagram below presents main components of ESP-WROVER-KIT and interconnections between components.

ESP-WROVER-KIT block diagram

ESP-WROVER-KIT block diagram

Functional Description

The following list and figures below describe key components, interfaces and controls of ESP-WROVER-KIT board.

32.768 kHz
An external precision 32.768 kHz crystal oscillator provides the chip with a clock of low-power consumption during the Deep-sleep mode.
ESP32 Module

ESP-WROVER-KIT is compatible with both ESP-WROOM-32 and ESP32-WROVER. The ESP32-WROVER module features all the functions of ESP-WROOM-32 and integrates an external 32-MBit PSRAM for flexible extended storage and data processing capabilities.

注解

GPIO16 and GPIO17 are used as the CS and clock signal for PSRAM. To ensure reliable performance, the two GPIOs are not broken out.

CTS/RTS
Serial port flow control signals: the pins are not connected to the circuitry by default. To enable them, respective pins of JP14 must be shorted with jumpers.
UART
Serial port: the serial TX/RX signals on FT2232HL and ESP32 are broken out to the two sides of JP11. By default, the two signals are connected with jumpers. To use the ESP32 module serial interface only, the jumpers may be removed and the module can be connected to another external serial device.
SPI
SPI interface: the SPI interface connects to an external flash (PSRAM). To interface another SPI device, an extra CS signal is needed. If an ESP32-WROVER is being used, please note that the electrical level on the flash and SRAM is 1.8V.
JTAG
JTAG interface: the JTAG signals on FT2232HL and ESP32 are broken out to the two sides of JP8. By default, the two signals are disconnected. To enable JTAG, shorting jumpers are required on the signals.
FT2232

FT2232 chip is a multi-protocol USB-to-serial bridge. The FT2232 chip features USB-to-UART and USB-to-JTAG functionalities. Users can control and program the FT2232 chip through the USB interface to establish communication with ESP32.

The embedded FT2232 chip is one of the distinguishing features of the ESPWROVER-KIT. It enhances users’ convenience in terms of application development and debugging. In addition, uses do not need to buy a JTAG debugger separately, which reduces the development cost. The schematics is provided in section Related Documents.

EN
Reset button: pressing this button resets the system.
Boot
Download button: holding down the Boot button and pressing the EN button initiates the firmware download mode. Then user can download firmware through the serial port.
USB
USB interface. It functions as the power supply for the board and the communication interface between PC and ESP32 module.
Power Select
Power supply selection interface: the ESP-WROVER-KIT can be powered through the USB interface or the 5V Input interface. The user can select the power supply with a jumper. More details can be found in section Setup Options, jumper header JP7.
Power Key
Power on/off button: toggling to the right powers the board on; toggling to the left powers the board off.
5V Input
The 5V power supply interface is used as a backup power supply in case of full-load operation.
LDO
NCP1117(1A). 5V-to-3.3V LDO. (There is an alternative pin-compatible LDO — LM317DCY, with an output current of up to 1.5A). NCP1117 can provide a maximum current of 1A. The LDO solutions are available with both fixed output voltage and variable output voltage. For details please refer to ESP-WROVER-KIT schematic.
Camera
Camera interface: a standard OV7670 camera module is supported.
RGB
Red, green and blue (RGB) light emitting diodes (LEDs), which may be controlled by pulse width modulation (PWM).
I/O
All the pins on the ESP32 module are led out to the pin headers on the ESPWROVER-KIT. Users can program ESP32 to enable multiple functions such as PWM, ADC, DAC, I2C, I2S, SPI, etc.
Micro SD Card
Micro SD card slot for data storage: when ESP32 enters the download mode, GPIO2 cannot be held high. However, a pull-up resistor is required on GPIO2 to enable the Micro SD Card. By default, GPIO2 and the pull-up resistor R153 are disconnected. To enable the SD Card, use jumpers on JP1 as shown in section Setup Options.
LCD
ESP-WROVER-KIT supports mounting and interfacing a 3.2” SPI (standard 4-wire Serial Peripheral Interface) LCD, as shown on figure ESP-WROVER-KIT board layout - back.
ESP-WROVER-KIT board layout - front

ESP-WROVER-KIT board layout - front

ESP-WROVER-KIT board layout - back

ESP-WROVER-KIT board layout - back

Setup Options

There are five jumper headers available to set up the board functionality. Typical options to select from are listed in table below.

Header Jumper Setting Description of Functionality
JP1 jp1-sd_io2 Enable pull up for the Micro SD Card
JP1 jp1-both Assert GPIO2 low during each download (by jumping it to GPIO0)
JP7 jp7-ext_5v Power ESP-WROVER-KIT board from an external power supply
JP7 jp7-usb_5v Power ESP-WROVER-KIT board from an USB port
JP8 jp8 Enable JTAG functionality
JP11 jp11-rx-tx Enable UART communication
JP14 jp14 Enable RTS/CTS flow control for serial communication
Start Application Development

Before powering up the ESP-WROVER-KIT, please make sure that the board has been received in good condition with no obvious signs of damage.

Initial Setup

Select the source of power supply for the board by setting jumper JP7. The options are either USB port or an external power supply. For this application selection of USB port is sufficient. Enable UART communication by installing jumpers on JP11. Both selections are shown in table below.

Power up from USB port Enable UART communication
jp7-usb_5v jp11-rx-tx

Do not install any other jumpers.

Now to Development

To start development of applications for ESP32-DevKitC, proceed to section 快速入门, that will walk you through the following steps:

  • 设置工具链 in your PC to develop applications for ESP32 in C language
  • 连接 the module to the PC and verify if it is accessible
  • 编译和烧写 an example application to the ESP32
  • 监视器 instantly what the application is doing

如果你有其它的开发板,请查看下面的内容。

设置工具链

你可以完全遵循标准安装过程或者自定义你的环境,这完全依赖于你个人的经验和喜好。下面的指令用于标准安装。如果要在你自己的系统上进行设置,请移步 工具链的自定义设置

工具链的标准设置

用 ESP32 进行开发最快的方法是安装预编译的工具链。请根据你的操作系选择点击对应的链接,并按照该链接中的指令进行安装。

Windows 平台工具链的标准设置
引言

Windows 没有内置的 “make” 环境,因此如果要安装工具链,你需要一个 GNU-兼容 环境。我们这里使用 MSYS2 来提供该环境。你可能不需要一直使用这个环境(你可以使用 Eclipse 或其它前段工具),但是它在你的屏幕后面隐藏着。

工具链的设置

快速设置的方法是从 dl.espressif.com 下载集成在一起的工具链 & MSYS zip 压缩文件:

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

将 zip 压缩文件解压到 C:\ (或其它路径,但是这里假设解压缩到 C:\),它会使用预先准备的环境创建一个 msys32 目录。

检出

运行 C:\msys32\mingw32.exe 可以打开 MSYS2 的终端窗口。该窗口的环境是一个 bash shell。

MSYS2 terminal window

MSYS2 终端窗口

后续步骤将会使用这个窗口来为 ESP32 设置开发环境。

后续步骤

要继续设置开发环境,请参考 获取 ESP-IDF 一节。

相关文档
Setup Windows Toolchain from Scratch

Setting up the environment gives you some more control over the process, and also provides the information for advanced users to customize the install. The pre-built environment, addressed to less experienced users, has been prepared by following these steps.

To quickly setup the toolchain in standard way, using prebuild environment, proceed to section Windows 平台工具链的标准设置.

Configure Toolchain & Environment from Scratch

This process involves installing MSYS2, then installing the MSYS2 and Python packages which ESP-IDF uses, and finally downloading and installing the Xtensa toolchain.

  • 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.) At time of writing, the latest installer is msys2-i686-20161025.exe.

  • Run through the installer steps. Uncheck the “Run MSYS2 32-bit now” checkbox at the end.

  • Once the installer exits, open Start Menu and find “MSYS2 MinGW 32-bit” to run the terminal.

    (Why launch this different terminal? MSYS2 has the concept of different kinds of environments. The default “MSYS” environment is Cygwin-like and uses a translation layer for all Windows API calls. We need the “MinGW” environment in order to have a native Python which supports COM ports.)

  • The ESP-IDF repository on github contains a script in the tools directory titled windows_install_prerequisites.sh. If you haven’t got a local copy of the ESP-IDF yet, that’s OK - you can just download that one file in Raw format from here: tools/windows/windows_install_prerequisites.sh. 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.

  • The windows_install_prerequisites.sh script will download and install packages for ESP-IDF support, and the ESP32 toolchain.

  • During the initial update step, MSYS may update itself into a state where it can no longer operate. You may see errors like the following:

    *** fatal error - cygheap base mismatch detected - 0x612E5408/0x612E4408. This problem is probably due to using incompatible versions of the cygwin DLL.
    

    If you see errors like this, close the terminal window entirely (terminating the processes running there) and then re-open a new terminal. Re-run windows_install_prerequisites.sh (tip: use the up arrow key to see the last run command). The update process will resume after this step.

MSYS2 Mirrors in China

There are some (unofficial) MSYS2 mirrors inside China, which substantially improves download speeds inside China.

To add these mirrors, edit the following two MSYS2 mirrorlist files before running the setup script. The mirrorlist files can be found in the /etc/pacman.d directory (i.e. c:\msys2\etc\pacman.d).

Add these lines at the top of mirrorlist.mingw32:

Server = http://mirrors.ustc.edu.cn/msys2/mingw/i686/
Server = http://mirror.bit.edu.cn/msys2/REPOS/MINGW/i686

Add these lines at the top of mirrorlist.msys:

Server = http://mirrors.ustc.edu.cn/msys2/msys/$arch
Server = http://mirror.bit.edu.cn/msys2/REPOS/MSYS2/$arch
HTTP Proxy

You can enable an HTTP proxy for MSYS and PIP downloads by setting the http_proxy variable in the terminal before running the setup script:

export http_proxy='http://http.proxy.server:PORT'

Or with credentials:

export http_proxy='http://user:password@http.proxy.server:PORT'

Add this line to /etc/profile in the MSYS directory in order to permanently enable the proxy when using MSYS.

Alternative Setup: 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 instructions Configure Toolchain & Environment from Scratch, you already have the toolchain and you won’t need this download.

重要

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).

Next Steps

要继续设置开发环境,请参考 获取 ESP-IDF 一节。

Linux 平台工具链的标准设置
安装前提

要编译 ESP-IDF,你需要先安装如下的软件包。

  • CentOS 7:

    sudo yum install git wget make ncurses-devel flex bison gperf python pyserial
    
  • 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
    
工具链的设置

Linux 版的 ESP32 工具链可以从 Espressif 的网站下载:

下载完成后,将它解压到 ~/esp 目录

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

工具链将会被解压到 ~/esp/xtensa-esp32-elf/ 目录。

要使用工具链,你还需要在 ~/.bash_profile 文件中更新环境变量 PATH。要使 xtensa-esp32-elf 在所有的终端会话中有效,需要将下面这一行代码添加到你的 ~/.bash_profile 文件中

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

可选地,你也可以给上面的命令创建一个别名。这样的好处是,你只在需要使用它的时候才获取工具链。你只需要将下面这行代码添加到 ~/.bash_profile 文件中即可

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

然后,当你需要使用工具链时,在命令行输入 get_esp32,然后工具链会自动添加到你的 ``PATH``中。

Arch Linux 用户

在 Arch Linux 中运行预编译的 gdb(xtensa-esp32-elf-gdb) 需要 ncurses 5,但是 Arch 使用的是 ncurses 6。

AUR 中有可用于本地和 lib32 配置的后向兼容库:

可选地,你也可以使用 crosstool-NG 编译一个链接 ncurses 6 的 gdb。

后续步骤

要继续设置开发环境,请参考 获取 ESP-IDF 一节。

修改文档
Scratch 设置 Linux 工具链

下列指令是可选的,用于从 Espressif 网站下载二进制工具链。如果需呀快速设置工具链,而不是自己编译,请回到 Linux 平台工具链的标准设置 一节。

安装前提

要编译 ESP-IDF,你需要先安装如下的软件包。

  • 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
    
从源码编译工具链
  • 安装依赖:

    • CentOS 7:

      sudo yum install gawk gperf grep gettext ncurses-devel python python-devel automake bison flex texinfo help2man libtool
      
    • Ubuntu pre-16.04:

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

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

      TODO
      
    • Arch:

      TODO
      

下载 crosstool-NG 并编译

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

编译工具链

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

工具链将会被编译到 ~/esp/crosstool-NG/builds/xtensa-esp32-elf。请参考 标准设置指令 将工具链添加到你的 ``PATH``中。

后续步骤

要继续设置开发环境,请参考 获取 ESP-IDF 一节。

为 Mac OS 设置标准工具链
安装前提
  • install pip:

    sudo easy_install pip
    
  • install pyserial:

    sudo pip install pyserial
    
工具链的设置

macOS 版的 ESP32 工具链可以从 Espressif 的网站下载:

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

下载完成后,将它解压到 ~/esp 目录

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

工具链将会被解压到 ~/esp/xtensa-esp32-elf/ 目录。

要使用工具链,你还需要在 ~/.profile 文件中更新环境变量 PATH。要使 xtensa-esp32-elf 在所有的终端会话中有效,需要将下面这一行代码添加到你的 ~/.profile 文件中

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

可选地,你也可以给上面的命令创建一个别名。这样的好处是,你只在需要使用它的时候才获取工具链。你只需要将下面这行代码添加到 ~/.profile 文件中即可

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

然后,当你需要使用工具链时,在命令行输入 get_esp32,然后工具链会自动添加到你的 ``PATH``中。

后续步骤

要继续设置开发环境,请参考 获取 ESP-IDF 一节。

相关文档
Setup Toolchain for Mac OS from Scratch
Install Prerequisites
  • install pip:

    sudo easy_install pip
    
  • install pyserial:

    sudo pip install pyserial
    
Compile the Toolchain from Source
  • 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 --enable-local && 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 for standard setup to add the toolchain to your PATH.

Next Steps

要继续设置开发环境,请参考 获取 ESP-IDF 一节。

windows-logo linux-logo macos-logo
Windows Linux Mac OS

注解

我们默认使用 ~/esp 目录来安装预编译的工具链、ESP-IDF 和示例程序。你也可以使用其它目录,但是需要注意调整对应的命令。

设置完工具链后,你可以进入 获取 ESP-IDF 一节。

工具链的自定义设置

除了从乐鑫的网站(工具链的标准设置)下载预编译的二进制工具链外,你还可以自己编译工具链。

如果你找不到需要自己编译的理由,那么最好还是使用预编译版本吧。不过,这里可能有一些你希望从源码进行编译的理由:

  • 如果你想自定义工具链的编译配置选项
  • 如果你想使用不同版本的 GCC,例如 4.8.5
  • if you want to hack gcc or newlib or libstdc++
  • 如果你很好奇,和/或你有许多闲暇时间
  • 如果你不信任从互联网上面下载的二进制镜像

无论是因为何种情形,请都按照下面的指令编译你自己的工具链。

获取 ESP-IDF

工具链(包括用于编译和构建应用程序的程序)安装完后,你还需要 ESP32 相关的 API/库。乐鑫已经将它们放到 ESP-IDF 仓库 中了。 要获取这些 API/库,请打开一个控制台终端,进入某个你希望存放 ESP-IDF 的目录,然后克隆代码

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

ESP-IDF 将会被下载到 ~/esp/esp-idf

注解

注意这里还有个 --recursive 选项。如果你克隆 ESP-IDF 时没有带这个选项,你还需要运行额外的命令来获取子模块

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

注解

Windows 平台克隆子模块时,git clone 命令可能会打印一些 ': not a valid identifier... 消息。这是一个 已知问题 ,但实际上 git clone 已经成功了,没有任何问题。

设置 ESP-IDF 路径

工具链程序使用环境变量 IDF_PATH 来访问 ESP-IDF。这个变量应该设置在你的 PC 中,否则工程将不会编译。你可以在每次 PC 重启时手工设置。你也可以通过在 user profile 中定义 IDF_PATH 变量来永久性设置。要永久性设置,请按照 将 IDF_PATH 添加到 User Profile 一节中 Windows 或者 Linux and MacOS 中所指定的指令进行操作。 Linux and MacOS in section 将 IDF_PATH 添加到 User Profile.

开始一个工程

到了这里,你已经完成为 ESP32 编写应用程序的所有准备工作了。为了快速开始,我们这里以 IDF 的 examples 目录下的 get-started/hello_world 工程为例进行说明。

get-started/hello_world 拷贝到 ~/esp 目录:

cd ~/esp
cp -r $IDF_PATH/examples/get-started/hello_world .

你可以在 ESP-IDF 的 examples 目录下面发现一系列的示例工程。你可以按照上面的方法将使用这些例子作为你自己的工程,并在此基础之上进行开发。

重要

esp-idf 构建系统不支持在路径中存在空格。

连接

现在已经差不多了。在继续后续操作前,请现将 ESP32 的板子连接到 PC,然后检查 PC 所识别到的板子的串口号,看看它是否能正常通信。如果你不知道如何操作,请查看 与 ESP32 建立串口连接 中的相关指令。请注意一下端口号,因为我们在下一步中将会用到。

配置

在终端窗口中,输入 cd ~/esp/hello_world 进入 hello_world 所在目录,然后启动刚工程配置工具 menuconfig:

cd ~/esp/hello_world
make menuconfig

如果之前的步骤都正确,则会显示下面的菜单:

Project configuration - Home window

工程配置 - 主窗口

在菜单中,进入 Serial flasher config > Default serial port 来配置串口(工程将会加载到该串口上)。输入回车来确认选择,选择 < Save > 来保存配置,选择 < Exit > 来退出应用程序。

下面是一些使用 menuconfig 的小技巧:

  • 使用 up & down 组合键在菜单中上下移动
  • 使用 Enter 键进入一个子菜单,Escape 键退出子菜单或退出整个菜单
  • 输入 ? 查看帮助信息,Enter 键退出帮助屏幕
  • 使用空格键或 YN 键来使能(Yes) 和禁止 (No) 带有复选框 “[*]” 的配置项
  • 当光标在某个配置项上面高亮时,输入 ? 可以直接查看该项的帮助信息
  • 输入 / 可以来搜索某个配置项

注解

如果你是 Arch Linux 用户,需要进入 SDK tool configurationPython 2 interpreterpython 修改为 python2

编译和烧写

现在你可以编译和烧写应用程序了,输入

make flash

上面的命令会将应用程序、所有的 ESP-IDF 组件、通用的 bootloader、分区表编译成应用程序二进制文件,并将这些应用程序二进制文件烧写到 ESP32 的板子上面。

esptool.py v2.0-beta2
Flashing binaries to serial port /dev/ttyUSB0 (app at offset 0x10000)...
esptool.py v2.0-beta2
Connecting........___
Uploading stub...
Running stub...
Stub running...
Changing baud rate to 921600
Changed.
Attaching SPI flash...
Configuring flash size...
Auto-detected Flash size: 4MB
Flash params set to 0x0220
Compressed 11616 bytes to 6695...
Wrote 11616 bytes (6695 compressed) at 0x00001000 in 0.1 seconds (effective 920.5 kbit/s)...
Hash of data verified.
Compressed 408096 bytes to 171625...
Wrote 408096 bytes (171625 compressed) at 0x00010000 in 3.9 seconds (effective 847.3 kbit/s)...
Hash of data verified.
Compressed 3072 bytes to 82...
Wrote 3072 bytes (82 compressed) at 0x00008000 in 0.0 seconds (effective 8297.4 kbit/s)...
Hash of data verified.

Leaving...
Hard resetting...

如果没有任何问题,在编译过程结束后,你将能看到类似上面的将程序加载到板子上面的消息。最后,板子将会复位,应用程序 “hello_world” 开始启动。

如果你偏向于使用 Eclipse IDE 而不是运行 make,请参考 Eclipse guide

监视器

如果要看 “hello_world” 程序是否真的在运行,输入命令 make monitor。这个命令会启动 IDF Monitor 程序

$ make monitor
MONITOR
--- idf_monitor on /dev/ttyUSB0 115200 ---
--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
ets Jun  8 2016 00:22:57

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
ets Jun  8 2016 00:22:57
...

板子启动后,你就能看到 “Hello world!” 程序所打印的消息:

...
Hello world!
Restarting in 10 seconds...
I (211) cpu_start: Starting scheduler on APP CPU.
Restarting in 9 seconds...
Restarting in 8 seconds...
Restarting in 7 seconds...

要退出监视器,请使用快捷键 Ctrl+] 。如果要在同一个命令中执行 make flashmake monitor,可以直接输入 make flash monitor。关于监视器的更多使用细节请参考 IDF Monitor

相关文档

将 IDF_PATH 添加到 User Profile

要使环境变量 IDF_PATH 在系统重启后依然有效,需要将它添加到用户 profile,具体方法请参考下面的指令。

Windows

用户 profile 脚本位于 C:/msys32/etc/profile.d/ 目录,它会在你每次打开一个新的 MSYS2 窗口时被执行。

  1. C:/msys32/etc/profile.d/ 目录创建一个新的脚本文件,将将其命名为 export_idf_path.sh

  2. 指定 ESP-IDF 目录所在路径。这与你的系统配置相关,比如你的路径可能是 C:\msys32\home\Krzysztof\esp\esp-idf

  3. 向脚本文件中添加 export 命令,例如

    export IDF_PATH="C:/msys32/home/Krzysztof/esp/esp-idf"
    

    记得在原始 Windows 路径中将反斜线替换为斜线。

  4. 保存脚本文件。

  5. 关闭 MSYS2 窗口后重新打开。检查 IDF_PATH 是否被设置了,输入

    printenv IDF_PATH
    

    之前在脚本文件中输入的路劲会被打印出来。

如果你不希望将 IDF_PATH 永久设置到 user profile 中,你需要在每次重新打开 MSYS2 窗口时手工输入下面的命令

export IDF_PATH="C:/msys32/home/Krzysztof/esp/esp-idf"

如果你是从 设置 ESP-IDF 路径 一节中进入本页的,可以直接点击 开始一个工程 跳转回去。

Linux 和 MacOS

直接将下面一行代码添加到 ~/.bash 文件就能设置 IDF_PATH

export IDF_PATH=~/esp/esp-idf

注销并重新登录后,修改将生效。

如果你不希望永久设置 IDF_PATH,你需要在每次重新打开终端窗口后手工输入上面的代码。

运行下面的命令可以检查 IDF_PATH 是否设置正确

printenv IDF_PATH

之前在 ~/.bash 文件中输入(或者手工输入)的路径将会被打印出来。

如果你是从 设置 ESP-IDF 路径 一节中进入本页的,可以直接点击 开始一个工程 跳转回去。

与 ESP32 建立串口连接

本节用于说明如何在 ESP32 和 PC 之间建立串口连接。

将 ESP32 连接到 PC

使用 USB 线将 ESP32 板子和 PC 连接在一起。如果你的设备驱动没有自动安装,请先确认你 ESP32 板子(或者外部转换器 dongle)上面的 USB 转串口芯片的型号,然后在互联网上搜索对应的驱动并将其安装好。

下面的链接包含乐鑫生产的 ESP32 开发板的驱动程序:

在 Windows 上查看端口

在 Windows 设备管理器中查看系统所识别到的 COM 端口。断开 ESP32 并重新连接,看看哪个端口从列表中消失了然后又显示出来了。

下图显示了 ESP32 DevKitC 和 ESP32 WROVER KIT 的串口

USB to UART bridge of ESP32-DevKitC in Windows Device Manager

USB to UART bridge of ESP32-DevKitC in Windows Device Manager

Two USB Serial Ports of ESP-WROVER-KIT in Windows Device Manager

Two USB Serial Ports of ESP-WROVER-KIT in Windows Device Manager

在 Linux 和 MacOS 上查看端口

要查看 ESP32 板子(或外部转换器)上面的串口的设备名,运行下面的命令两次,第一次运行前将板子/dognle断开,第二次运行前再将其插上。第二次出现的端口号就是你需要的:

Linux

ls /dev/tty*

MacOS

ls /dev/tty.*
验证串口通信

验证串口通信是可选的。你可以使用一个串口终端程序完成它。在这个例子中,我们使用的是 PuTTY SSH Client ,它同时支持 Linux 和 Windows。你也可以使用其它串口工具,并设置如下的参数。

运行终端,设置端口号,波特率 115200,数据位 8,停止位 1,奇偶 N。下面分别是在 Windows 和 Linux 下面配置这些传输参数(简单的描述就是 115200-8-1-N)的例子。请一定选择你上面说识别出来的端口号。

Setting Serial Communication in PuTTY on Windows

在 Windows 设置 PuTTY 的串口通信

Setting Serial Communication in PuTTY on Linux

在 Linux 设置 PuTTY 的串口通信

然后在终端中打开串口,并查看是否有 ESP32 的消息打印出来。消息的内容是跟你加载到 ESP32 中的程序有关的,例如:

ets Jun  8 2016 00:22:57

rst:0x5 (DEEPSLEEP_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
ets Jun  8 2016 00:22:57

rst:0x7 (TG0WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0x00
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0008,len:8
load:0x3fff0010,len:3464
load:0x40078000,len:7828
load:0x40080000,len:252
entry 0x40080034
I (44) boot: ESP-IDF v2.0-rc1-401-gf9fba35 2nd stage bootloader
I (45) boot: compile time 18:48:10

...

如果你看到人类可识别的打印消息,表示串口连接工作正常,你可以继续安装并将应用程序下载到 ESP32 中。

注解

验证串口通信后,请先关闭串口终端。在下一步中,我们将会使用另一个应用程序进行下载。当串口打开时,这个应用程序就无法串口。

如果你是从 get-started-connect`跳转到此处的,点击链接 :ref:`get-started-configure 回到之前的章节。

使用 Make 进行编译和烧写

找一个工程

esp-idf-template 工程之外,ESP-IDF 还在 examples 目录下附带了若干示例工程。

找到你想要使用的工程后,进入该目录,然后你就可以对它进行配置、编译。

配置你的工程
make menuconfig
编译你的工程
make all

... 将会编译 app、bootloader 和一个基于配置所产生的分区表。

烧写你的工程

make all 完成后,它会打印一行命令,提示使用 esptool.py 来烧写芯片。不过,你也可以直接运行如下命令来烧写

make flash

该命令将会烧写整个工程(app、bootloader 和分区表)到芯片中。用于烧写程序的串行端口可以使用 make menuconfig 进行配置。

你不需要在运行 make flash 前运行 make all,因为 make flash 会自动重新编译它所需要的任何文件。

仅编译 & 烧写 APP

完成第一次烧写后,你可以只编译和烧写应用程序,而不需要 bootloader 和分区表:

  • make app - 仅编译应用程序
  • make app-flash - 仅烧写应用程序

make app-flash 会自动重新编译它所需要的任何文件。

如果 bootloader 和分区表没有改动,则不需要重新烧写。

分区表

工程编译完成后,”build” 目录下将会产生一个名字类似于 “my_app.bin” 的二进制文件,这是可以被 ESP32 bootloader 加载的二进制镜像。

一片 ESP32 flash 上面可以包含多个 app 和多种数据(校正数据、文件系统、参数存储器等)。因此,一个分区表被烧写到 flash 的地址 0x8000 处。

分区表的每个入口都有一个名字(label)、类型(app、数据或其它一些类型)、子类型和分区表被加载时在 flash 中的偏移。

使用分区表最简单的方法是运行 make menuconfig 并选择一个预定义的分区表:

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

在这两个情况下,工厂 app 都会被烧写到偏移地址 0x10000 处。如果你输入 如果你输入 make partition_table 命令,它将会打印分区表的参数。

关于 分区表 和如何创建自定义变量的更多细节,请参考 此文档

使用 Eclipse IDE 编译和烧写

安装 Eclipse IDE

Eclipse 提供了一个可用于编写、编译和调试 ESP-IDF 工程的图形化集成开发环境。

  • 请先在你的平台上按照好 esp-idf。
  • 我们建议先使用命令行编译一个工程,感受一下整个过程是如何工作的。此外,你也需要使用命令行通过( make menuconfig)来配置你的 esp-idf 工程,因为当前并不支持在 Eclipse 里面进行配置。
  • eclipse.org 下载适合你的平台的安装器(Installer)。
  • 运行 Eclipse 安装器,选择 “Eclipse for C/C++ Development” (在其它某些地方也将它叫做 CDT)。
Windows 用户

在 Windows 上使用 Eclipse 来编译 ESP-IDF 的配置步骤略有不同,请参考 Windows Eclipse IDE 指南.

设置 Eclipse

当你的 Eclipse 安装完成后,你需要完成这些步骤:

导入新工程 Project
  • Eclipse 会借助 ESP-IDF 中的 Makefile。这意味着,你需要先创建一个 ESP-IDF 工程。你可以使用 github 上面的 idf-template 工程,也可以使用在 esp-idf examples 子目录下的工程。
  • Eclipse 启动后,依次选择 File -> Import...
  • 在弹出的对话框中,选择 “C/C++” -> “Existing Code as Makefile Project”,然后点击 Next。
  • 在下一页中,将 “Existing Code Location” 设置为你的 IDF 工程所在路径。这里不要把路径设置为 ESP-IDF 的根目录了(随后会设置)。你所指定的目录中应当包含一个名为 “Makefile” 的文件,即工程 Makefile。
  • 在同一页中,在 “Toolchain for Indexer Settings” 下面选择 “Cross GCC”,然后点击 Finish。
工程属性
  • 工程浏览器(Project Explorer)中将会出现新工程。右击工程,并在弹出的菜单中选择属性(Properties)。
  • 在 “C/C++ Build” 下面点击 “Environment” 属性页。点击 “Add...” ,并输入名字(name)``BATCH_BUILD`` 和值(value)``1``。
  • 再次点击 “Add...”,输入名字(name) IDF_PATH。值(value)应当填写为 ESP-IDF 的完整安装路径。
  • 编辑环境变量 PATH。保持当前值不变,将路径追加到 Xtensa 工具链(something/xtensa-esp32-elf/bin) 后面。
  • On macOS, add a PYTHONPATH environment variable and set it to /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages. This is so that the system Python, which has pyserial installed as part of the setup steps, overrides any built-in Eclipse Python.

点击 “C/C++ General” -> “Preprocessor Include Paths” 属性页:

  • 点击 “Providers” 标签
  • 在 providers 列表中,点击 “CDT Cross GCC Built-in Compiler Settings”。在 “Command to get compiler specs” 下面,用 xtensa-esp32-elf-gcc 将该行开始处的文本 ${COMMAND} 替换到。即完整的 “Command to get compiler specs” 应当是 xtensa-esp32-elf-gcc ${FLAGS} -E -P -v -dD "${INPUTS}"
  • 在 providers 列表中,点击 “CDT GCC Build Output Parser”,在编译器命令行模式(Compiler command pattern)的开始处输入 xtensa-esp32-elf-。即编译器目录模式的完整路径是 xtensa-esp32-elf-(g?cc)|([gc]\+\+)|(clang)
在 Eclipse 中编译

你的工程在第一次编译之前,Eclipse 可能会显示许多关于未定义值的错误和警告,这是因为某些源文件是由 esp-idf 编译过程中自动生成的。当你编译完工程后,这些错误和警告就会消失。

  • 在 Eclipse 中点击 OK 按钮关闭属性对话框。
  • 在 Eclipse 外面,打开一个命令行提示符,进入工程所在目录,运行命令 make menuconfig 来配置你的工程的 esp-idf 设置。目前,这一步必须在 Eclipse 外面运行。
  • 如果你编译之前没有运行配置步骤,esp-idf 会在命令行提示你进行配置,但是 Eclipse 不能处理这样的消息,因此编译过程将会挂起或者失败。
  • 回到 Eclipse,选择 Project -> Build 来编译你的工程。

TIP: 如果你的工程已在 Eclipse 外面编译过,你可能需要执行 Project -> Clean before choosing Project -> Build 操作,这样 Eclipse 就能看到所有源文件的编译器参数。它使用这些参数来判断头文件的包含路径。

从 Eclipse 烧写

你可以将 “make flash” 目标集成到你的 Eclipse 工程中,然后通过 Eclipse UI 调用 esptool.py 来完成烧写操作:

  • 在工程浏览器(Project Explorer)中右键你的工程(一定要确保你选择的是一个工程,而不是工程中的某个目录,否则 Eclipse 不能找到正确的 Makefile 文件)。
  • 从弹出的菜单中选择 Make Targets -> Create 。
  • 在目标名(target name)中输入 “flash”,保持其它选项默认不变。
  • 现在,你可以使用 Project -> Make Target -> Build (Shift+F9) 来编译预定义的自定义 flash 目标,它会编译和烧写工程。

注意,你需要使用 “make menuconfig” 来设置串口和与烧写相关的其它配置项。”make menuconfig” 任然需要在命令行终端中执行,详细相信请参考你的平台所对应的文档。

如果有需要,你可以按照相同的步骤添加 bootloaderpartition_table 目标。

相关文档
在 Windows 上设置 Eclipse IDE

在 Windows 上面配置 Eclipse 需要一些不同的步骤,下面将展示完整的配置步骤。

(对于 OS X 和 Linux 上面的指令,请参考 Eclipse IDE page

安装 Eclipse IDE

请按照 安装 Eclipse IDE 中的步骤安装 Eclipse。

在 Windows 上设置 Eclipse

当你的 Eclipse 安装完成后,你需要完成这些步骤:

导入新工程 Project
  • Eclipse 会借助 ESP-IDF 中的 Makefile。这意味着,你需要先创建一个 ESP-IDF 工程。你可以使用 github 上面的 idf-template 工程,也可以使用在 esp-idf examples 子目录下的工程。
  • Eclipse 启动后,依次选择 File -> Import...
  • 在弹出的对话框中,选择 “C/C++” -> “Existing Code as Makefile Project”,然后点击 Next。
  • 在下一页中,将 “Existing Code Location” 设置为你的 IDF 工程所在路径。这里不要把路径设置为 ESP-IDF 的根目录了(随后会设置)。你所指定的目录中应当包含一个名为 “Makefile” 的文件,即工程 Makefile。
  • 在同一页中,在 “Toolchain for Indexer Settings” 下面取消复选框 “Show only available toolchains that support this platform”。
  • 在出现的扩展列表中,选择 “Cygwin GCC”,然后点击 Finish。

*Note: 你可能会在 UI 上面看到警告“Cygwin GCC Toolchain could not be found”。没关系,我们将会重新配置 Eclipse,让其能够找打工具链。

工程属性
  • 工程浏览器(Project Explorer)中将会出现新工程。右击工程,并在弹出的菜单中选择属性(Properties)。

  • 点击 “C/C++ Build” 属性也(顶层):

    • 取消勾选 “Use default build command”,并输入自定义编译命令: python ${IDF_PATH}/tools/windows/eclipse_make.py
  • 在 “C/C++ Build” 下面点击 “Environment” 属性页:

    • 点击 “Add...”,输入名字(name)``BATCH_BUILD`` 和值(value) 1
    • 再次点击 “Add...”,输入名字(name) IDF_PATH。值(value)应当填写为 ESP-IDF 的完整安装路径。IDF_PATH 路径应当用斜线而不要用反斜线,即使用 C:/Users/MyUser/Development/esp-idf
    • 编辑环境变量 PATH。删除已存在的值,并用 C:\msys32\usr\bin;C:\msys32\mingw32\bin;C:\msys32\opt\xtensa-esp32-elf\bin 替代(如果你将 msys32 安装到其它目录了,则需要修改对应的路径)。
  • 点击 “C/C++ General” -> “Preprocessor Include Paths, Macros, etc.” 属性页:

    • 点击 “Providers” 标签

      • 在 providers 列表中,点击 “CDT GCC Built-in Compiler Settings Cygwin”。在 “Command to get compiler specs” 下面,用 xtensa-esp32-elf-gcc 将该行开始处的文本 ${COMMAND} 替换到。即完整的 “Command to get compiler specs” 应当是 xtensa-esp32-elf-gcc ${FLAGS} -E -P -v -dD "${INPUTS}"
      • 在 providers 列表中,点击 “CDT GCC Build Output Parser”,在编译器命令行模式(Compiler command pattern)的开始处输入 xtensa-esp32-elf-。即编译器目录模式的完整路径是 xtensa-esp32-elf-(g?cc)|([gc]\+\+)|(clang)
在 Eclipse 中编译

请按照 在 Eclipse 中编译 中的步骤进行编译。

技术细节

仅争对 Windows 专家和好奇心比较重的小伙伴

Explanations of the technical reasons for some of these steps. You don’t need to know this to use esp-idf with Eclipse on Windows,
but it may be helpful background knowledge if you plan to do dig into the Eclipse support:
  • The xtensa-esp32-elf-gcc cross-compiler is not a Cygwin toolchain, even though we tell Eclipse that it is one.

This is because msys2 uses Cygwin and supports Cygwin paths (of the type /c/blah instead of c:/blah or c:\\blah). In particular, xtensa-esp32-elf-gcc reports to the Eclipse “built-in compiler settings” function that its built-in include directories are all under /usr/, which is a Unix/Cygwin-style path that Eclipse otherwise can’t resolve. By telling Eclipse the compiler is Cygwin,

it resolves these paths internally using the cygpath utility.
  • The same problem occurs when parsing make output from esp-idf. Eclipse parses this output to find header directories,
but it can’t resolve include directories of the form /c/blah without using cygpath. There is a heuristic that
Eclipse Build Output Parser uses to determine whether it should call cygpath, but for currently unknown reasons the
esp-idf configuration doesn’t trigger it. For this reason, the eclipse_make.py wrapper script is used to call make and then use cygpath to process the output for Eclipse.

IDF Monitor

idf_monitor 是一个用 Python 编写的工具程序。当你在 IDF 中调用 make monitor 目标时,该程序会被执行。

idf_monitor 的主要功能是进行串口通信,将串行数据转发到目标设备的串行端口或者或者获取端口中传递出来的数据。此外,它还有一些其它的与 IDF 相关的功能。

与 idf_monitor 交互
  • Ctrl-] 将退出 monitor。
  • Ctrl-T Ctrl-H 将显示一个带有键盘快捷键的帮助菜单。
  • Ctrl-]Ctrl-T 之外的其它键都会通过串行端口发送出去。
对地址自动解码

在任何时候,只要 esp-idf 打印出类似于 0x4_______ 形式的十六进制代码时,idf_monitor 都会使用 addr2line 来查看源代码的位置和函数名。

当 esp-idf 的应用程序 crash 或者 panic 时,将会产生一个像下面这样的寄存器 dump 和 backtrace

Guru Meditation Error of type StoreProhibited occurred on core  0. Exception was unhandled.
Register dump:
PC      : 0x400f360d  PS      : 0x00060330  A0      : 0x800dbf56  A1      : 0x3ffb7e00
A2      : 0x3ffb136c  A3      : 0x00000005  A4      : 0x00000000  A5      : 0x00000000
A6      : 0x00000000  A7      : 0x00000080  A8      : 0x00000000  A9      : 0x3ffb7dd0
A10     : 0x00000003  A11     : 0x00060f23  A12     : 0x00060f20  A13     : 0x3ffba6d0
A14     : 0x00000047  A15     : 0x0000000f  SAR     : 0x00000019  EXCCAUSE: 0x0000001d
EXCVADDR: 0x00000000  LBEG    : 0x4000c46c  LEND    : 0x4000c477  LCOUNT  : 0x00000000

Backtrace: 0x400f360d:0x3ffb7e00 0x400dbf56:0x3ffb7e20 0x400dbf5e:0x3ffb7e40 0x400dbf82:0x3ffb7e60 0x400d071d:0x3ffb7e90

idf_monitor 将会增加 dump

Guru Meditation Error of type StoreProhibited occurred on core  0. Exception was unhandled.
Register dump:
PC      : 0x400f360d  PS      : 0x00060330  A0      : 0x800dbf56  A1      : 0x3ffb7e00
0x400f360d: do_something_to_crash at /home/gus/esp/32/idf/examples/get-started/hello_world/main/./hello_world_main.c:57
(inlined by) inner_dont_crash at /home/gus/esp/32/idf/examples/get-started/hello_world/main/./hello_world_main.c:52
A2      : 0x3ffb136c  A3      : 0x00000005  A4      : 0x00000000  A5      : 0x00000000
A6      : 0x00000000  A7      : 0x00000080  A8      : 0x00000000  A9      : 0x3ffb7dd0
A10     : 0x00000003  A11     : 0x00060f23  A12     : 0x00060f20  A13     : 0x3ffba6d0
A14     : 0x00000047  A15     : 0x0000000f  SAR     : 0x00000019  EXCCAUSE: 0x0000001d
EXCVADDR: 0x00000000  LBEG    : 0x4000c46c  LEND    : 0x4000c477  LCOUNT  : 0x00000000

Backtrace: 0x400f360d:0x3ffb7e00 0x400dbf56:0x3ffb7e20 0x400dbf5e:0x3ffb7e40 0x400dbf82:0x3ffb7e60 0x400d071d:0x3ffb7e90
0x400f360d: do_something_to_crash at /home/gus/esp/32/idf/examples/get-started/hello_world/main/./hello_world_main.c:57
(inlined by) inner_dont_crash at /home/gus/esp/32/idf/examples/get-started/hello_world/main/./hello_world_main.c:52
0x400dbf56: still_dont_crash at /home/gus/esp/32/idf/examples/get-started/hello_world/main/./hello_world_main.c:47
0x400dbf5e: dont_crash at /home/gus/esp/32/idf/examples/get-started/hello_world/main/./hello_world_main.c:42
0x400dbf82: app_main at /home/gus/esp/32/idf/examples/get-started/hello_world/main/./hello_world_main.c:33
0x400d071d: main_task at /home/gus/esp/32/idf/components/esp32/./cpu_start.c:254

对于上面到结果,idf_monitor 其实在后台运行了下面的命令来对每个地址进行解码的

xtensa-esp32-elf-addr2line -pfia -e build/PROJECT.elf ADDRESS
为 GDBStub 加载 GDB

默认情况下,如果 esp-idf 应用程序崩溃(crash)了,panic handler 会打印像上面展示的寄存器和栈 dump 消息,然后复位。

可选地,panic handler 可以被配置为去运行一个串行 “gdb stub”。“gdb stub” 可以与 gdb 调试程序通信,从而对内存进行读取,对变量和栈帧进行检查等等。这种功能虽然不如 JTAG 那样强大,但是不需要额外的硬件即可完成。

要使能 gdbstub,请运行 make menuconfig 并进入 Component config -> ESP32-specific -> Panic handler behaviour,然后将其设为 Invoke GDBStub

如果该选项被使能且 idf_monitor 能看到 gdb stub,则它会暂停监视串口并使用正确的参数运行 GDB。当 GDB 退出后,板子会通过 RST 串行线复位(如果连接了该线)。

在这北湖,idf_monitor 运行了如下目录

xtensa-esp32-elf-gdb -ex "set serial baud BAUD" -ex "target remote PORT" -ex interrupt build/PROJECT.elf
快速编译和烧写

键盘快捷键 Ctrl-T Ctrl-F 会暂停 idf_monitor 并运行 make flash 目标,然后恢复 idf_monitor。任何有改动的源文件都会在重新烧写前被重新编译。

键盘快捷键 Ctrl-T Ctrl-A 会暂停 idf-monitor 鳖你个运行 make app-flash 目标,然后恢复 idf_monitor。.这与 make flash 很相似,但是只会编译和重新烧写 main app。

快速复位

键盘快捷键 Ctrl-T Ctrl-R 会通过 RTS 线对开发板进行复位(如果连接了该线)。

Simple Monitor

早期版本的 ESP-IDF 使用 pySerial 命令行程序 miniterm 作为串口控制台程序。

这个程序选择任然可以运行,通过 make simple_monitor 命令。

idf_monitor 是基于 miniterm 的,它共享了相同的键盘快捷键。

idf_monitor 的已知问题
在 Windows 上看到的问题
  • 如果你在使用 Windows 环境且接收到了错误 “winpty: command not found”,需要运行 pacman -S winpty 来修复该错误。
  • 方向键或者一些其它的特殊键在 gdb 中不工作,这是又有 Windows 控制台的限制。
  • 有时候,当 “make” 退出时,它可能最高暂停 30 秒才能恢复 idf_monitor。
  • 有时候,当 “gdb” 运行时,它可能会暂停一会儿才能与 gdbstub 通信。

API 参考手册

Wi-Fi API

Wi-Fi

应用程序示例

示例代码 esp-idf-template 展示了如何将 ESP32 模块连接到 AP。

API 参考手册
WIFI_INIT_CONFIG_DEFAULT
类型定义
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

函数
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. Always use WIFI_INIT_CONFIG_DEFAULT macro to init the config to default values, this can guarantee all the fields got correct value when more fields are added into wifi_init_config_t in future release. If you want to set your owner initial values, overwrite the default values which are set by WIFI_INIT_CONFIG_DEFAULT, please be notified that the field ‘magic’ of wifi_init_config_t should always be WIFI_INIT_CONFIG_MAGIC!
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
Attention
The values of maximum active scan time and passive scan time per channel are limited to 1500 milliseconds. Values above 1500ms may cause station to disconnect from AP and are not recommended.
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
Attention
2. This API should be called after esp_wifi_start() or esp_wifi_set_promiscuous()
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

智能配置

API 参考手册
类型定义
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.

函数
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;

关于本节 API 的示例代码请参考 ESP-IDF 示例中的 wifi 目录。

蓝牙 API

控制器 && VHCI

应用程序示例

请检查 ESP-IDF 示例中的 bluetooth 文件夹,它包含如下示例:

bluetooth/ble_adv

这是一个带有虚拟 HCI 接口的 BLE 广播 demo。BLE 广播时发送 Reset/ADV_PARAM/ADV_DATA/ADV_ENABLE HCI 命令。
API 参考手册
头文件
类型定义
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

枚举
enum esp_bt_mode_t

Bluetooth mode for controller enable/disable.

Values:

ESP_BT_MODE_IDLE = 0x00

Bluetooth is not running

ESP_BT_MODE_BLE = 0x01

Run BLE mode

ESP_BT_MODE_CLASSIC_BT = 0x02

Run Classic BT mode

ESP_BT_MODE_BTDM = 0x03

Run dual mode

结构体
struct esp_bt_controller_config_t

Controller config options, depend on config mask. Config mask indicate which functions enabled, this means some options or parameters of some functions enabled by config mask.

Public Members

uint8_t hci_uart_no

If use UART1/2 as HCI IO interface, indicate UART number

uint32_t hci_uart_baudrate

If use UART1/2 as HCI IO interface, indicate UART baudrate

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

函数
esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg)

Initialize BT controller to allocate task and other resource.

Return
ESP_OK - success, other - failed
Parameters
  • cfg: Initial configuration of BT controller. This function should be called only once, before any other BT functions are called.

void esp_bt_controller_deinit(void)

De-initialize BT controller to free resource and delete task.

This function should be called only once, after any other BT functions are called. This function is not whole completed, esp_bt_controller_init cannot called after this function.

esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode)

Enable BT controller.

Return
ESP_OK - success, other - failed
Parameters
  • mode: : the mode(BLE/BT/BTDM) to enable. Now only support BTDM.

esp_err_t esp_bt_controller_disable(esp_bt_mode_t mode)

Disable BT controller.

Return
ESP_OK - success, other - failed
Parameters
  • mode: : the mode(BLE/BT/BTDM) to disable. Now only support BTDM.

esp_bt_controller_status_t esp_bt_controller_get_status(void)

Get BT controller is initialised/de-initialised/enabled/disabled.

Return
status value

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 通用说明

BT GENERIC DEFINES
应用程序示例

Instructions

API 参考手册
ESP_BT_OCTET16_LEN
ESP_BT_OCTET8_LEN
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.

ESP_BD_ADDR_STR
ESP_BD_ADDR_HEX(addr)
类型定义
typedef uint8_t esp_bt_octet16_t[ESP_BT_OCTET16_LEN]
typedef uint8_t esp_bt_octet8_t[ESP_BT_OCTET8_LEN]
typedef uint8_t esp_bd_addr_t[ESP_BD_ADDR_LEN]

Bluetooth device address.

枚举
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
结构体
函数
BT MAIN API
应用程序示例

Instructions

API 参考手册
类型定义
枚举
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

结构体
函数
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 设备 API
概述

蓝牙设备参考 API。

Instructions

应用程序示例

Instructions

API 参考手册
类型定义
枚举
结构体
函数
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

esp_err_t esp_bt_dev_set_device_name(const char *name)

Set bluetooth device name. This function should be called after esp_bluedroid_enable() completes successfully.

Return
  • ESP_OK : Succeed
  • ESP_ERR_INVALID_ARG : if name is NULL pointer or empty, or string length out of limit
  • ESP_INVALID_STATE : if bluetooth stack is not yet enabled
  • ESP_FAIL : others
Parameters
  • name: : device name to be set

低功耗蓝牙

GAP API
应用程序示例

请检查 ESP-IDF 示例中的 bluetooth 文件夹,它包含如下示例:

bluetooth/gatt_server, bluetooth/gatt_client

这两个 demos 使用不同的 GAP API,例如广播、扫描、设置设备名等。
API 参考手册
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_LE_KEY_NONE
ESP_LE_KEY_PENC

encryption key, encryption information of peer device

ESP_LE_KEY_PID

identity key of the peer device

ESP_LE_KEY_PCSRK

peer SRK

ESP_LE_KEY_PLK

Link key

ESP_LE_KEY_LLK
ESP_LE_KEY_LENC

master role security information:div

ESP_LE_KEY_LID

master device ID key

ESP_LE_KEY_LCSRK

local CSRK has been deliver to peer

ESP_LE_AUTH_NO_BOND

0

ESP_LE_AUTH_BOND

1 << 0

ESP_LE_AUTH_REQ_MITM

1 << 2

ESP_LE_AUTH_REQ_SC_ONLY

1 << 3

ESP_LE_AUTH_REQ_SC_BOND

1001

ESP_LE_AUTH_REQ_SC_MITM

1100

ESP_LE_AUTH_REQ_SC_MITM_BOND

1101

ESP_IO_CAP_OUT

DisplayOnly

ESP_IO_CAP_IO

DisplayYesNo

ESP_IO_CAP_IN

KeyboardOnly

ESP_IO_CAP_NONE

NoInputNoOutput

ESP_IO_CAP_KBDISP

Keyboard display

ESP_BLE_ADV_DATA_LEN_MAX

Advertising data maximum length.

ESP_BLE_SCAN_RSP_DATA_LEN_MAX

Scan response data maximum length.

类型定义
typedef uint8_t esp_ble_key_type_t
typedef uint8_t esp_ble_auth_req_t

combination of the above bit pattern

typedef uint8_t esp_ble_io_cap_t

combination of the io capability

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

枚举
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

ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT

When raw advertising data set complete, the event comes

ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT

When raw advertising data set complete, the event comes

ESP_GAP_BLE_ADV_START_COMPLETE_EVT

When start advertising complete, the event comes

ESP_GAP_BLE_SCAN_START_COMPLETE_EVT

When start scan complete, the event comes

ESP_GAP_BLE_AUTH_CMPL_EVT
ESP_GAP_BLE_KEY_EVT
ESP_GAP_BLE_SEC_REQ_EVT
ESP_GAP_BLE_PASSKEY_NOTIF_EVT
ESP_GAP_BLE_PASSKEY_REQ_EVT
ESP_GAP_BLE_OOB_REQ_EVT
ESP_GAP_BLE_LOCAL_IR_EVT
ESP_GAP_BLE_LOCAL_ER_EVT
ESP_GAP_BLE_NC_REQ_EVT
ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT

When stop adv complete, the event comes

ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT

When stop scan complete, the event comes

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 = 0x04
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_sec_act_t

Values:

ESP_BLE_SEC_NONE
ESP_BLE_SEC_ENCRYPT
ESP_BLE_SEC_ENCRYPT_NO_MITM
ESP_BLE_SEC_ENCRYPT_MITM
enum esp_ble_sm_param_t

Values:

ESP_BLE_SM_PASSKEY
ESP_BLE_SM_AUTHEN_REQ_MODE
ESP_BLE_SM_IOCAP_MODE
ESP_BLE_SM_SET_INIT_KEY
ESP_BLE_SM_SET_RSP_KEK
ESP_BLE_SM_MAX_KEY_SIZE
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)

结构体
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

struct esp_ble_penc_keys_t

BLE encryption keys.

Public Members

esp_bt_octet16_t ltk

The long term key

esp_bt_octet8_t rand

The random number

uint16_t ediv

The ediv value

uint8_t sec_level

The security level of the security link

uint8_t key_size

The key size(7~16) of the security link

struct esp_ble_pcsrk_keys_t

BLE CSRK keys.

Public Members

uint32_t counter

The counter

esp_bt_octet16_t csrk

The csrk key

uint8_t sec_level

The security level

struct esp_ble_pid_keys_t

BLE pid keys.

Public Members

esp_bt_octet16_t irk

The irk value

esp_bd_addr_type_t addr_type

The address type

esp_bd_addr_t static_addr

The static address

struct esp_ble_lenc_keys_t

BLE Encryption reproduction keys.

Public Members

esp_bt_octet16_t ltk

The long term key

uint16_t div

The div value

uint8_t key_size

The key size of the security link

uint8_t sec_level

The security level of the security link

struct esp_ble_lcsrk_keys

BLE SRK keys.

Public Members

uint32_t counter

The counter value

uint16_t div

The div value

uint8_t sec_level

The security level of the security link

esp_bt_octet16_t csrk

The csrk key value

struct esp_ble_sec_key_notif_t

Structure associated with ESP_KEY_NOTIF_EVT.

Public Members

esp_bd_addr_t bd_addr

peer address

uint32_t passkey

the numeric value for comparison. If just_works, do not show this number to UI

struct esp_ble_sec_req_t

Structure of the security request.

Public Members

esp_bd_addr_t bd_addr

peer address

警告

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

struct esp_ble_key_t

union type of the security key value

Public Members

esp_bd_addr_t bd_addr

peer address

esp_ble_key_type_t key_type

key type of the security link

esp_ble_key_value_t p_key_value

the pointer to the key value

struct esp_ble_local_id_keys_t

structure type of the ble local id keys value

Public Members

esp_bt_octet16_t ir

the 16 bits of the ir value

esp_bt_octet16_t irk

the 16 bits of the ir key value

esp_bt_octet16_t dhk

the 16 bits of the dh key value

struct esp_ble_auth_cmpl_t

Structure associated with ESP_AUTH_CMPL_EVT.

Public Members

esp_bd_addr_t bd_addr

BD address peer device.

bool key_present

Valid link key value in key element

esp_link_key key

Link key associated with peer device.

uint8_t key_type

The type of Link Key

bool success

TRUE of authentication succeeded, FALSE if failed.

uint8_t fail_reason

The HCI reason/error code for when success=FALSE

esp_bd_addr_type_t addr_type

Peer device address type

esp_bt_dev_type_t dev_type

Device type

警告

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

警告

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

uint8_t adv_data_len

Adv data length

uint8_t scan_rsp_len

Scan response length

struct esp_ble_gap_cb_param_t::ble_adv_data_raw_cmpl_evt_param

ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT.

Public Members

esp_bt_status_t status

Indicate the set raw advertising data operation success status

struct esp_ble_gap_cb_param_t::ble_scan_rsp_data_raw_cmpl_evt_param

ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT.

Public Members

esp_bt_status_t status

Indicate the set raw advertising data operation success status

struct esp_ble_gap_cb_param_t::ble_adv_start_cmpl_evt_param

ESP_GAP_BLE_ADV_START_COMPLETE_EVT.

Public Members

esp_bt_status_t status

Indicate advertising start operation success status

struct esp_ble_gap_cb_param_t::ble_scan_start_cmpl_evt_param

ESP_GAP_BLE_SCAN_START_COMPLETE_EVT.

Public Members

esp_bt_status_t status

Indicate scan start operation success status

函数
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

esp_err_t esp_ble_gap_config_adv_data_raw(uint8_t *raw_data, uint32_t raw_data_len)

This function is called to set raw advertising data. User need to fill ADV data by self.

Return
  • ESP_OK : success
  • other : failed
Parameters
  • raw_data: : raw advertising data
  • raw_data_len: : raw advertising data length , less than 31 bytes

esp_err_t esp_ble_gap_config_scan_rsp_data_raw(uint8_t *raw_data, uint32_t raw_data_len)

This function is called to set raw scan response data. User need to fill scan response data by self.

Return
  • ESP_OK : success
  • other : failed
Parameters
  • raw_data: : raw scan response data
  • raw_data_len: : raw scan response data length , less than 31 bytes

esp_err_t esp_ble_gap_set_security_param(esp_ble_sm_param_t param_type, void *value, uint8_t len)

Set a GAP security parameter value. Overrides the default value.

Return
- ESP_OK : success
  • other : failed
Parameters
  • param_type: :L the type of the param which to be set
  • value: : the param value
  • len: : the length of the param value

esp_err_t esp_ble_gap_security_rsp(esp_bd_addr_t bd_addr, bool accept)

Grant security request access.

Return
- ESP_OK : success
  • other : failed
Parameters
  • bd_addr: : BD address of the peer
  • accept: : accept the security request or not

esp_err_t esp_ble_set_encryption(esp_bd_addr_t bd_addr, esp_ble_sec_act_t sec_act)

Set a gap parameter value. Use this function to change the default GAP parameter values.

Return
- ESP_OK : success
  • other : failed
Parameters
  • bd_addr: : the address of the peer device need to encryption
  • sec_act: : This is the security action to indicate what kind of BLE security level is required for the BLE link if the BLE is supported

esp_err_t esp_ble_passkey_reply(esp_bd_addr_t bd_addr, bool accept, uint32_t passkey)

Reply the key value to the peer device in the lagecy connection stage.

Return
- ESP_OK : success
  • other : failed
Parameters
  • bd_addr: : BD address of the peer
  • accept: : passkey entry sucessful or declined.
  • passkey: : passkey value, must be a 6 digit number, can be lead by 0.

esp_err_t esp_ble_confirm_reply(esp_bd_addr_t bd_addr, bool accept)

Reply the comfirm value to the peer device in the lagecy connection stage.

Return
- ESP_OK : success
  • other : failed
Parameters
  • bd_addr: : BD address of the peer device
  • accept: : numbers to compare are the same or different.

GATT DEFINES
应用程序示例

Instructions

API 参考手册
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

类型定义
typedef uint8_t esp_gatt_if_t

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

枚举
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

结构体
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

警告

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

函数
GATT SERVER API
应用程序示例

请检查 ESP-IDF 示例中的 bluetooth 文件夹,它包含如下示例:

bluetooth/gatt_server

这是一个 GATT 服务器 demo。使用 GATT API 创建一个发送广播 GATT 服务器。这个 GATT 服务器可以被连接,服务可以被发现。
API 参考手册
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

类型定义
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

枚举
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
结构体

警告

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

函数
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: - Whether a confirmation is required. false sends a GATT notification, true sends a GATT indication.

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
应用程序示例

请检查 ESP-IDF 示例中的 bluetooth 文件夹,它包含如下示例:

bluetooth/gatt_client

这是一个 GATT 客户端 demo。这个 demo 可以扫描设备、连接到 GATT 服务端以及发下服务。
API 参考手册
ESP_GATT_DEF_BLE_MTU_SIZE

Maximum Transmission Unit used in GATT.

ESP_GATT_MAX_MTU_SIZE

Maximum Transmission Unit allowed in GATT.

类型定义
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

枚举
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

结构体

警告

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

函数
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
Over概述view

BLUFI 是一个基于 GATT 的属性,用于配置 ESP32 WIFI 与 AP 的连接/断开连接,或者设置 softap 等。在使用时应当关注如下两点:

  1. 从 profile 发送的事件。你需要根据事件的指示完成某些工作。
  2. 安全引用。你可以自己写安全函数,例如对称加密/解密、校验和等函数。你甚至可以定义 “Key Exchange/Negotiation” 过程。
应用程序示例

请检查 ESP-IDF 示例中的 bluetooth 文件夹,它包含如下示例:

bluetooth/blufi

这是一个 BLUFI demo。该 demo 可以设置 ESP32 的 wifi 为 softap/station/softap&station 模式,并且可以配置 wifi 连接。
API 参考手册
类型定义
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

枚举
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
结构体
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

警告

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)

函数
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

经典蓝牙

经典蓝牙 GAP API
应用程序示例

Instructions

API 参考手册
类型定义
枚举
enum esp_bt_scan_mode_t

Discoverability and Connectability mode.

Values:

ESP_BT_SCAN_MODE_NONE = 0

Neither discoverable nor connectable

ESP_BT_SCAN_MODE_CONNECTABLE

Connectable but not discoverable

ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE

both discoverable and connectaable

结构体
函数
esp_err_t esp_bt_gap_set_scan_mode(esp_bt_scan_mode_t mode)

Set discoverability and connectability mode for legacy bluetooth. This function should be called after esp_bluedroid_enable() completes successfully.

Return
  • ESP_OK : Succeed
  • ESP_ERR_INVALID_ARG: if argument invalid
  • ESP_INVALID_STATE: if bluetooth stack is not yet enabled
  • ESP_FAIL: others
Parameters
  • mode: : one of the enums of bt_scan_mode_t

Bluetooth A2DP API
应用程序示例

请检查 ESP-IDF 示例中的 bluetooth 文件夹,它包含如下示例:

bluetooth/a2dp_sink

这是一个 A2DP sink 客户端 demo。该 demo 可以被 A2DP 设备发现和连接,从远程设备接收音频数据。
API 参考手册
ESP_A2D_MCT_SBC

Media codec types supported by A2DP.

SBC

ESP_A2D_MCT_M12

MPEG-1, 2 Audio

ESP_A2D_MCT_M24

MPEG-2, 4 AAC

ESP_A2D_MCT_ATRAC

ATRAC family

ESP_A2D_MCT_NON_A2DP
ESP_A2D_CIE_LEN_SBC
ESP_A2D_CIE_LEN_M12
ESP_A2D_CIE_LEN_M24
ESP_A2D_CIE_LEN_ATRAC
类型定义
typedef uint8_t esp_a2d_mct_t
typedef void (*esp_a2d_cb_t)(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param)

A2DP profile callback function type.

Parameters
  • event: : Event type
  • param: : Pointer to callback parameter

typedef void (*esp_a2d_data_cb_t)(const uint8_t *buf, uint32_t len)

A2DP profile data callback function.

Parameters
  • buf: : data received from A2DP source device and is PCM format decoder from SBC decoder; buf references to a static memory block and can be overwritten by upcoming data
  • len: : size(in bytes) in buf

枚举
enum esp_a2d_connection_state_t

Bluetooth A2DP connection states.

Values:

ESP_A2D_CONNECTION_STATE_DISCONNECTED = 0

connection released

ESP_A2D_CONNECTION_STATE_CONNECTING

connecting remote device

ESP_A2D_CONNECTION_STATE_CONNECTED

connection established

ESP_A2D_CONNECTION_STATE_DISCONNECTING

disconnecting remote device

enum esp_a2d_disc_rsn_t

Bluetooth A2DP disconnection reason.

Values:

ESP_A2D_DISC_RSN_NORMAL = 0

Finished disconnection that is initiated by local or remote device

ESP_A2D_DISC_RSN_ABNORMAL

Abnormal disconnection caused by signal loss

enum esp_a2d_audio_state_t

Bluetooth A2DP datapath states.

Values:

ESP_A2D_AUDIO_STATE_REMOTE_SUSPEND = 0

audio stream datapath suspended by remote device

ESP_A2D_AUDIO_STATE_STOPPED

audio stream datapath stopped

ESP_A2D_AUDIO_STATE_STARTED

audio stream datapath started

enum esp_a2d_cb_event_t

A2DP callback events.

Values:

ESP_A2D_CONNECTION_STATE_EVT = 0

connection state changed event

ESP_A2D_AUDIO_STATE_EVT = 1

audio stream transmission state changed event

ESP_A2D_AUDIO_CFG_EVT = 2

audio codec is configured

结构体

警告

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

struct esp_a2d_cb_param_t::a2d_conn_stat_param

ESP_A2D_CONNECTION_STATE_EVT.

Public Members

esp_a2d_connection_state_t state

one of values from esp_a2d_connection_state_t

esp_bd_addr_t remote_bda

remote bluetooth device address

esp_a2d_disc_rsn_t disc_rsn

reason of disconnection for “DISCONNECTED”

struct esp_a2d_cb_param_t::a2d_audio_stat_param

ESP_A2D_AUDIO_STATE_EVT.

Public Members

esp_a2d_audio_state_t state

one of the values from esp_a2d_audio_state_t

esp_bd_addr_t remote_bda

remote bluetooth device address

struct esp_a2d_cb_param_t::a2d_audio_cfg_param

ESP_A2D_AUDIO_CFG_EVT.

Public Members

esp_bd_addr_t remote_bda

remote bluetooth device address

esp_a2d_mcc_t mcc

A2DP media codec capability information

函数
esp_err_t esp_a2d_register_callback(esp_a2d_cb_t callback)

Register application callback function to A2DP module. This function should be called only after esp_bluedroid_enable() completes successfully.

Return
  • ESP_OK: success
  • ESP_INVALID_STATE: if bluetooth stack is not yet enabled
  • ESP_FAIL: if callback is a NULL function pointer
Parameters
  • callback: A2DP sink event callback function

esp_err_t esp_a2d_register_data_callback(esp_a2d_data_cb_t callback)

Register A2DP sink data output function; For now the output is PCM data stream decoded from SBC format. This function should be called only after esp_bluedroid_enable() completes successfully.

Return
  • ESP_OK: success
  • ESP_INVALID_STATE: if bluetooth stack is not yet enabled
  • ESP_FAIL: if callback is a NULL function pointer
Parameters
  • callback: A2DP data callback function

esp_err_t esp_a2d_sink_init(void)

Initialize the bluetooth A2DP sink module. This function should be called after esp_bluedroid_enable() completes successfully.

Return
  • ESP_OK: if the initialization request is sent successfully
  • ESP_INVALID_STATE: if bluetooth stack is not yet enabled
  • ESP_FAIL: others

esp_err_t esp_a2d_sink_deinit(void)

De-initialize for A2DP sink module. This function should be called only after esp_bluedroid_enable() completes successfully.

Return
  • ESP_OK: success
  • ESP_INVALID_STATE: if bluetooth stack is not yet enabled
  • ESP_FAIL: others

esp_err_t esp_a2d_sink_connect(esp_bd_addr_t remote_bda)

Connect the remote bluetooth device bluetooth, must after esp_a2d_sink_init()

Return
  • ESP_OK: connect request is sent to lower layer
  • ESP_INVALID_STATE: if bluetooth stack is not yet enabled
  • ESP_FAIL: others
Parameters
  • remote_bda: remote bluetooth device address

esp_err_t esp_a2d_sink_disconnect(esp_bd_addr_t remote_bda)

Disconnect the remote bluetooth device.

Return
  • ESP_OK: disconnect request is sent to lower layer
  • ESP_INVALID_STATE: if bluetooth stack is not yet enabled
  • ESP_FAIL: others
Parameters
  • remote_bda: remote bluetooth device address

BT AVRCP API
概述

蓝牙 AVRCP 参考 API。

Instructions

应用程序示例

Instructions

API 参考手册
类型定义
typedef void (*esp_avrc_ct_cb_t)(esp_avrc_ct_cb_event_t event, esp_avrc_ct_cb_param_t *param)

AVRCP controller callback function type.

Parameters
  • event: : Event type
  • param: : Pointer to callback parameter union

枚举
enum esp_avrc_features_t

AVRC feature bit mask.

Values:

ESP_AVRC_FEAT_RCTG = 0x0001

remote control target

ESP_AVRC_FEAT_RCCT = 0x0002

remote control controller

ESP_AVRC_FEAT_VENDOR = 0x0008

remote control vendor dependent commands

ESP_AVRC_FEAT_BROWSE = 0x0010

use browsing channel

ESP_AVRC_FEAT_META_DATA = 0x0040

remote control metadata transfer command/response

ESP_AVRC_FEAT_ADV_CTRL = 0x0200

remote control advanced control commmand/response

enum esp_avrc_pt_cmd_t

AVRC passthrough command code.

Values:

ESP_AVRC_PT_CMD_PLAY = 0x44

play

ESP_AVRC_PT_CMD_STOP = 0x45

stop

ESP_AVRC_PT_CMD_PAUSE = 0x46

pause

ESP_AVRC_PT_CMD_FORWARD = 0x4B

forward

ESP_AVRC_PT_CMD_BACKWARD = 0x4C

backward

enum esp_avrc_pt_cmd_state_t

AVRC passthrough command state.

Values:

ESP_AVRC_PT_CMD_STATE_PRESSED = 0

key pressed

ESP_AVRC_PT_CMD_STATE_RELEASED = 1

key released

enum esp_avrc_ct_cb_event_t

AVRC Controller callback events.

Values:

ESP_AVRC_CT_CONNECTION_STATE_EVT = 0

connection state changed event

ESP_AVRC_CT_PASSTHROUGH_RSP_EVT = 1

passthrough response event

ESP_AVRC_CT_MAX_EVT
结构体

警告

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

struct esp_avrc_ct_cb_param_t::avrc_ct_conn_stat_param

ESP_AVRC_CT_CONNECTION_STATE_EVT.

Public Members

bool connected

whether AVRC connection is set up

uint32_t feat_mask

AVRC feature mask of remote device

esp_bd_addr_t remote_bda

remote bluetooth device address

struct esp_avrc_ct_cb_param_t::avrc_ct_psth_rsp_param

ESP_AVRC_CT_PASSTHROUGH_RSP_EVT.

Public Members

uint8_t tl

transaction label, 0 to 15

uint8_t key_code

passthrough command code

uint8_t key_state

0 for PRESSED, 1 for RELEASED

函数
esp_err_t esp_avrc_ct_register_callback(esp_avrc_ct_cb_t callback)

Register application callbacks to AVRCP module; for now only AVRCP Controller role is supported. This function should be called after esp_bluedroid_enable() completes successfully.

Return
  • ESP_OK: success
  • ESP_INVALID_STATE: if bluetooth stack is not yet enabled
  • ESP_FAIL: others
Parameters
  • callback: AVRCP controller callback function

esp_err_t esp_avrc_ct_init(void)

Initialize the bluetooth AVRCP controller module, This function should be called after esp_bluedroid_enable() completes successfully.

Return
  • ESP_OK: success
  • ESP_INVALID_STATE: if bluetooth stack is not yet enabled
  • ESP_FAIL: others

esp_err_t esp_avrc_ct_deinit(void)

De-initialize AVRCP controller module. This function should be called after after esp_bluedroid_enable() completes successfully.

Return
  • ESP_OK: success
  • ESP_INVALID_STATE: if bluetooth stack is not yet enabled
  • ESP_FAIL: others

esp_err_t esp_avrc_ct_send_passthrough_cmd(uint8_t tl, uint8_t key_code, uint8_t key_state)

Send passthrough command to AVRCP target, This function should be called after ESP_AVRC_CT_CONNECTION_STATE_EVT is received and AVRCP connection is established.

Return
  • ESP_OK: success
  • ESP_INVALID_STATE: if bluetooth stack is not yet enabled
  • ESP_FAIL: others
Parameters
  • tl: : transaction label, 0 to 15, consecutive commands should use different values.
  • key_code: : passthrough command code, e.g. ESP_AVRC_PT_CMD_PLAY, ESP_AVRC_PT_CMD_STOP, etc.
  • key_state: : passthrough command key state, ESP_AVRC_PT_CMD_STATE_PRESSED or ESP_AVRC_PT_CMD_STATE_PRESSED

关于本节 API 的示例代码请参考 ESP-IDF 示例中的 bluetooth 目录。

以太网 API

以太网

应用程序示例

以太网示例 ethernet/ethernet.

API 参考手册
PHY 接口

PHY 模块通过配置所给 PHY 的结构体 eth_config_t 进行配置。

头部包含一个默认的配置结构体。这些默认配置中的某些成员在被用于一个特殊的 PHY 硬件配置之前需要被覆盖或重置。查看以太网的示例代码可以了解这是如何完成的。

类型定义
typedef void (*eth_phy_check_init_func)(void)
typedef eth_speed_mode_t (*eth_phy_get_speed_mode_func)(void)
typedef eth_duplex_mode_t (*eth_phy_get_duplex_mode_func)(void)
typedef void (*eth_phy_func)(void)
typedef esp_err_t (*eth_tcpip_input_func)(void *buffer, uint16_t len, void *eb)
typedef void (*eth_gpio_config_func)(void)
typedef bool (*eth_phy_get_partner_pause_enable_func)(void)
枚举
enum eth_mode_t

Values:

ETH_MODE_RMII = 0
ETH_MODE_MII
enum eth_speed_mode_t

Values:

ETH_SPEED_MODE_10M = 0
ETH_SPEED_MODE_100M
enum eth_duplex_mode_t

Values:

ETH_MODE_HALFDUPLEX = 0
ETH_MODE_FULLDUPLEX
enum eth_phy_base_t

Values:

PHY0 = 0
PHY1
PHY2
PHY3
PHY4
PHY5
PHY6
PHY7
PHY8
PHY9
PHY10
PHY11
PHY12
PHY13
PHY14
PHY15
PHY16
PHY17
PHY18
PHY19
PHY20
PHY21
PHY22
PHY23
PHY24
PHY25
PHY26
PHY27
PHY28
PHY29
PHY30
PHY31
结构体
struct eth_config_t

ethernet configuration

Public Members

eth_phy_base_t phy_addr

phy base addr (0~31)

eth_mode_t mac_mode

mac mode only support RMII now

eth_tcpip_input_func tcpip_input

tcpip input func

eth_phy_func phy_init

phy init func

eth_phy_check_link_func phy_check_link

phy check link func

eth_phy_check_init_func phy_check_init

phy check init func

eth_phy_get_speed_mode_func phy_get_speed_mode

phy check init func

eth_phy_get_duplex_mode_func phy_get_duplex_mode

phy check init func

eth_gpio_config_func gpio_config

gpio config func

bool flow_ctrl_enable

flag of flow ctrl enable

eth_phy_get_partner_pause_enable_func phy_get_partner_pause_enable

get partner pause enable

eth_phy_power_enable_func phy_power_enable

enable or disable phy power

函数
esp_err_t esp_eth_init(eth_config_t *config)

Init ethernet mac.

Note
config can not be NULL,and phy chip must be suitable to phy init func.
Return
  • ESP_OK
  • ESP_FAIL
Parameters
  • config: mac init data.

esp_err_t esp_eth_tx(uint8_t *buf, uint16_t size)

Send packet from tcp/ip to mac.

Note
buf can not be NULL,size must be less than 1580
Return
  • ESP_OK
  • ESP_FAIL
Parameters
  • buf: start address of packet data.
  • size: size (byte) of packet data.

esp_err_t esp_eth_enable(void)

Enable ethernet interface.

Note
Shout be called after esp_eth_init
Return
  • ESP_OK
  • ESP_FAIL

esp_err_t esp_eth_disable(void)

Disable ethernet interface.

Note
Shout be called after esp_eth_init
Return
  • ESP_OK
  • ESP_FAIL

void esp_eth_get_mac(uint8_t mac[6])

Get mac addr.

Note
mac addr must be a valid unicast address
Parameters
  • mac: start address of mac address.

void esp_eth_smi_write(uint32_t reg_num, uint16_t value)

Read phy reg with smi interface.

Note
phy base addr must be right.
Parameters
  • reg_num: phy reg num.
  • value: value which write to phy reg.

uint16_t esp_eth_smi_read(uint32_t reg_num)

Read phy reg with smi interface.

Note
phy base addr must be right.
Return
value what read from phy reg
Parameters
  • reg_num: phy reg num.

esp_err_t esp_eth_smi_wait_value(uint32_t reg_num, uint16_t value, uint16_t value_mask, int timeout_ms)

Continuously read a PHY register over SMI interface, wait until the register has the desired value.

Note
PHY base address must be right.
Return
ESP_OK if desired value matches, ESP_ERR_TIMEOUT if timed out.
Parameters
  • reg_num: PHY register number
  • value: Value to wait for (masked with value_mask)
  • value_mask: Mask of bits to match in the register.
  • timeout_ms: Timeout to wait for this value (milliseconds). 0 means never timeout.

static esp_err_t esp_eth_smi_wait_set(uint32_t reg_num, uint16_t value_mask, int timeout_ms)

Continuously read a PHY register over SMI interface, wait until the register has all bits in a mask set.

Note
PHY base address must be right.
Return
ESP_OK if desired value matches, ESP_ERR_TIMEOUT if timed out.
Parameters
  • reg_num: PHY register number
  • value_mask: Value mask to wait for (all bits in this mask must be set)
  • timeout_ms: Timeout to wait for this value (milliseconds). 0 means never timeout.

void esp_eth_free_rx_buf(void *buf)

Free emac rx buf.

Note
buf can not be null,and it is tcpip input buf.
Parameters
  • buf: start address of recevie packet data.

PHY 配置常量

警告

doxygenvariable: Cannot find variable “phy_tlk110_default_ethernet_config” in doxygen xml output for project “esp32-idf” from directory: xml/

警告

doxygenvariable: Cannot find variable “phy_lan8720_default_ethernet_config” in doxygen xml output for project “esp32-idf” from directory: xml/

关于本节 API 的示例代码请参考 ESP-IDF 示例中的 ethernet 目录。

外设 API

Analog to Digital Converter

概述

ESP32 integrates two 12-bit SAR (“Successive Approximation Register”) ADCs (Analog to Digital Converters) and supports measurements on 18 channels (analog enabled pins). Some of these pins can be used to build a programmable gain amplifier which is used for the measurement of small analog signals.

The ADC driver API currently only supports ADC1 (9 channels, attached to GPIOs 32-39).

Taking an ADC reading involves configuring the ADC with the desired precision and attentuation settings, and then calling adc1_get_voltage() to read the channel.

It is also possible to read the internal hall effect sensor via ADC1.

应用程序示例

Reading voltage on ADC1 channel 0 (GPIO 36):

#include <driver/adc.h>

...

    adc1_config_width(ADC_WIDTH_12Bit);
    adc1_config_channel_atten(ADC1_CHANNEL_0,ADC_ATTEN_0db);
    int val = adc1_get_voltage(ADC1_CHANNEL_0);

Reading the internal hall effect sensor:

#include <driver/adc.h>

...

    adc1_config_width(ADC_WIDTH_12Bit);
    int val = hall_sensor_read();

The value read in both these examples is 12 bits wide (range 0-4095).

API 参考手册
头文件
  • components/driver/include/driver/adc.h
枚举
enum adc1_channel_t

Values:

ADC1_CHANNEL_0 = 0

ADC1 channel 0 is GPIO36

ADC1_CHANNEL_1

ADC1 channel 1 is GPIO37

ADC1_CHANNEL_2

ADC1 channel 2 is GPIO38

ADC1_CHANNEL_3

ADC1 channel 3 is GPIO39

ADC1_CHANNEL_4

ADC1 channel 4 is GPIO32

ADC1_CHANNEL_5

ADC1 channel 5 is GPIO33

ADC1_CHANNEL_6

ADC1 channel 6 is GPIO34

ADC1_CHANNEL_7

ADC1 channel 7 is GPIO35

ADC1_CHANNEL_MAX
enum adc_atten_t

Values:

ADC_ATTEN_0db = 0

The input voltage of ADC will be reduced to about 1/1

ADC_ATTEN_2_5db = 1

The input voltage of ADC will be reduced to about 1/1.34

ADC_ATTEN_6db = 2

The input voltage of ADC will be reduced to about 1/2

ADC_ATTEN_11db = 3

The input voltage of ADC will be reduced to about 1/3.6

enum adc_bits_width_t

Values:

ADC_WIDTH_9Bit = 0

ADC capture width is 9Bit

ADC_WIDTH_10Bit = 1

ADC capture width is 10Bit

ADC_WIDTH_11Bit = 2

ADC capture width is 11Bit

ADC_WIDTH_12Bit = 3

ADC capture width is 12Bit

函数
esp_err_t adc1_config_width(adc_bits_width_t width_bit)

Configure ADC1 capture width.

The configuration is for all channels of ADC1

Return
  • ESP_OK success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • width_bit: Bit capture width for ADC1

esp_err_t adc1_config_channel_atten(adc1_channel_t channel, adc_atten_t atten)

Configure the ADC1 channel, including setting attenuation.

The default ADC full-scale voltage is 1.1V. To read higher voltages (up to the pin maximum voltage, usually 3.3V) requires setting >0dB signal attenuation for that ADC channel.

Note
This function also configures the input GPIO pin mux to connect it to the ADC1 channel. It must be called before calling adc1_get_voltage() for this channel.

When VDD_A is 3.3V:

  • 0dB attenuaton (ADC_ATTEN_0db) gives full-scale voltage 1.1V
  • 2.5dB attenuation (ADC_ATTEN_2_5db) gives full-scale voltage 1.5V
  • 6dB attenuation (ADC_ATTEN_6db) gives full-scale voltage 2.2V
  • 11dB attenuation (ADC_ATTEN_11db) gives full-scale voltage 3.9V (see note below)

Note
The full-scale voltage is the voltage corresponding to a maximum reading (depending on ADC1 configured bit width, this value is: 4095 for 12-bits, 2047 for 11-bits, 1023 for 10-bits, 511 for 9 bits.)
Note
At 11dB attenuation the maximum voltage is limited by VDD_A, not the full scale voltage.
Return
  • ESP_OK success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • channel: ADC1 channel to configure
  • atten: Attenuation level

int adc1_get_voltage(adc1_channel_t channel)

Take an ADC1 reading on a single channel.

Note
Call adc1_config_width() before the first time this function is called.
Note
For a given channel, adc1_config_channel_atten(channel) must be called before the first time this function is called.
Return
  • -1: Parameter error
  • Other: ADC1 channel reading.
Parameters
  • channel: ADC1 channel to read

int hall_sensor_read()

Read Hall Sensor.

Note
The Hall Sensor uses channels 0 and 3 of ADC1. Do not configure these channels for use as ADC channels.
Note
The ADC1 module must be enabled by calling adc1_config_width() before calling hall_sensor_read(). ADC1 should be configured for 12 bit readings, as the hall sensor readings are low values and do not cover the full range of the ADC.
Return
The hall sensor reading.

Digital To Analog Converter

概述

ESP32 has two 8-bit DAC (digital to analog converter) channels, connected to GPIO25 (Channel 1) and GPIO26 (Channel 2).

The DAC driver allows these channels to be set to arbitrary voltages.

The DAC channels can also be driven with DMA-style written sample data, via the I2S driver when using the “built-in DAC mode”.

For other analog output options, see the Sigma-delta Modulation module and the LED Control module. Both these modules produce high frequency PWM output, which can be hardware low-pass filtered in order to generate a lower frequency analog output.

应用程序示例

Setting DAC channel 1 (GPIO 25) voltage to approx 0.78 of VDD_A voltage (VDD * 200 / 255). For VDD_A 3.3V, this is 2.59V:

#include <driver/dac.h>

...

    dac_out_voltage(DAC_CHANNEL_1, 200);
API 参考手册
头文件
  • components/driver/include/driver/dac.h
枚举
enum dac_channel_t

Values:

DAC_CHANNEL_1 = 1

DAC channel 1 is GPIO25

DAC_CHANNEL_2

DAC channel 2 is GPIO26

DAC_CHANNEL_MAX
函数
esp_err_t dac_out_voltage(dac_channel_t channel, uint8_t dac_value)

Set DAC output voltage.

DAC output is 8-bit. Maximum (255) corresponds to VDD.

Note
When this function is called, function for the DAC channel’s GPIO pin is reconfigured for RTC DAC function.
Return
  • ESP_OK success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • channel: DAC channel
  • dac_value: DAC output value

GPIO & RTC GPIO

概述

The ESP32 chip features 40 physical GPIO pads. Some GPIO pads cannot be used or do not have the corresponding pin on the chip package(refer to technical reference manual). Each pad can be used as a general purpose I/O or can be connected to an internal peripheral signal.

  • Note that GPIO6-11 are usually used for SPI flash.
  • GPIO34-39 can only be set as input mode and do not have software pullup or pulldown functions.

There is also separate “RTC GPIO” support, which functions when GPIOs are routed to the “RTC” low-power and analog subsystem. These pin functions can be used when in deep sleep, when the Ultra Low Power co-processor is running, or when analog functions such as ADC/DAC/etc are in use.

应用程序示例

GPIO output and input interrupt example: peripherals/gpio.

API 参考手册
Normal GPIO
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)
类型定义
Normal GPIO
typedef void (*gpio_isr_t)(void *)
typedef intr_handle_t gpio_isr_handle_t
枚举
Normal GPIO
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

RTC GPIO
enum rtc_gpio_mode_t

Values:

RTC_GPIO_MODE_INPUT_ONLY

Pad output

RTC_GPIO_MODE_OUTPUT_ONLY

Pad input

RTC_GPIO_MODE_INPUT_OUTUT

Pad pull output + input

RTC_GPIO_MODE_DISABLED

Pad (output + input) disable

结构体
Normal GPIO
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

函数
Normal GPIO
esp_err_t gpio_config(const 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)

Configure GPIO pull-up/pull-down resistors.

Only pins that support both input & output have integrated pull-up and pull-down resistors. Input-only GPIOs 34-39 do not.

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.

This ISR function is called whenever any GPIO interrupt occurs. See the alternative gpio_install_isr_service() and gpio_isr_handler_add() API in order to have the driver support per-GPIO ISRs.

To disable or remove the ISR, pass the returned handle to the interrupt allocation functions.

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.

Return
  • ESP_OK Success ;
  • ESP_ERR_INVALID_ARG GPIO error

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 the driver’s GPIO ISR handler service, which allows per-pin GPIO interrupt handlers.

This function is incompatible with gpio_isr_register() - if that function is used, a single global ISR is registered for all GPIO interrupts. If this function is used, the ISR service provides a global GPIO ISR and individual pin handlers are registered via the gpio_isr_register() function.

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()

Uninstall the driver’s GPIO ISR service, freeing related 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 pin.

Call this function after using gpio_install_isr_service() to install the driver’s GPIO ISR handler service.

The pin ISR 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 is a stack size limit (configurable as “ISR stack size” in menuconfig). This limit is smaller compared to a global GPIO interrupt handler due to the additional 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 pin.

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

RTC GPIO
static bool rtc_gpio_is_valid_gpio(gpio_num_t gpio_num)

Determine if the specified GPIO is a valid RTC GPIO.

Return
true if GPIO is valid for RTC GPIO use. talse otherwise.
Parameters
  • gpio_num: GPIO number

esp_err_t rtc_gpio_init(gpio_num_t gpio_num)

Init a GPIO as RTC GPIO.

This function must be called when initializing a pad for an analog function.

Return
  • ESP_OK success
  • ESP_ERR_INVALID_ARG GPIO is not an RTC IO
Parameters
  • gpio_num: GPIO number (e.g. GPIO_NUM_12)

esp_err_t rtc_gpio_deinit(gpio_num_t gpio_num)

Init a GPIO as digital GPIO.

Return
  • ESP_OK success
  • ESP_ERR_INVALID_ARG GPIO is not an RTC IO
Parameters
  • gpio_num: GPIO number (e.g. GPIO_NUM_12)

uint32_t rtc_gpio_get_level(gpio_num_t gpio_num)

Get the RTC IO input level.

Return
  • 1 High level
  • 0 Low level
  • ESP_ERR_INVALID_ARG GPIO is not an RTC IO
Parameters
  • gpio_num: GPIO number (e.g. GPIO_NUM_12)

esp_err_t rtc_gpio_set_level(gpio_num_t gpio_num, uint32_t level)

Set the RTC IO output level.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG GPIO is not an RTC IO
Parameters
  • gpio_num: GPIO number (e.g. GPIO_NUM_12)
  • level: output level

esp_err_t rtc_gpio_set_direction(gpio_num_t gpio_num, rtc_gpio_mode_t mode)

RTC GPIO set direction.

Configure RTC GPIO direction, such as output only, input only, output and input.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG GPIO is not an RTC IO
Parameters
  • gpio_num: GPIO number (e.g. GPIO_NUM_12)
  • mode: GPIO direction

esp_err_t rtc_gpio_pullup_en(gpio_num_t gpio_num)

RTC GPIO pullup enable.

This function only works for RTC IOs. In general, call gpio_pullup_en, which will work both for normal GPIOs and RTC IOs.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG GPIO is not an RTC IO
Parameters
  • gpio_num: GPIO number (e.g. GPIO_NUM_12)

esp_err_t rtc_gpio_pulldown_en(gpio_num_t gpio_num)

RTC GPIO pulldown enable.

This function only works for RTC IOs. In general, call gpio_pulldown_en, which will work both for normal GPIOs and RTC IOs.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG GPIO is not an RTC IO
Parameters
  • gpio_num: GPIO number (e.g. GPIO_NUM_12)

esp_err_t rtc_gpio_pullup_dis(gpio_num_t gpio_num)

RTC GPIO pullup disable.

This function only works for RTC IOs. In general, call gpio_pullup_dis, which will work both for normal GPIOs and RTC IOs.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG GPIO is not an RTC IO
Parameters
  • gpio_num: GPIO number (e.g. GPIO_NUM_12)

esp_err_t rtc_gpio_pulldown_dis(gpio_num_t gpio_num)

RTC GPIO pulldown disable.

This function only works for RTC IOs. In general, call gpio_pulldown_dis, which will work both for normal GPIOs and RTC IOs.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG GPIO is not an RTC IO
Parameters
  • gpio_num: GPIO number (e.g. GPIO_NUM_12)

警告

doxygenfunction: Cannot find function “rtc_gpio_unhold_all” in doxygen xml output for project “esp32-idf” from directory: xml/

I2C

概述

ESP32 has two I2C controllers which can be set as master mode or slave mode.

应用程序示例

I2C master and slave example: peripherals/i2c.

API 参考手册
I2C_APB_CLK_FREQ

I2C source clock is APB clock, 80MHz

I2C_FIFO_LEN

I2C hardware fifo length

类型定义
typedef void *i2c_cmd_handle_t

I2C command handle

枚举
enum i2c_mode_t

Values:

I2C_MODE_SLAVE = 0

I2C slave mode

I2C_MODE_MASTER

I2C master mode

I2C_MODE_MAX
enum i2c_rw_t

Values:

I2C_MASTER_WRITE = 0

I2C write data

I2C_MASTER_READ

I2C read data

enum i2c_trans_mode_t

Values:

I2C_DATA_MODE_MSB_FIRST = 0

I2C data msb first

I2C_DATA_MODE_LSB_FIRST = 1

I2C data lsb first

I2C_DATA_MODE_MAX
enum i2c_opmode_t

Values:

I2C_CMD_RESTART = 0

I2C restart command

I2C_CMD_WRITE

I2C write command

I2C_CMD_READ

I2C read command

I2C_CMD_STOP

I2C stop command

I2C_CMD_END

I2C end command

enum i2c_port_t

Values:

I2C_NUM_0 = 0

I2C port 0

I2C_NUM_1

I2C port 1

I2C_NUM_MAX
enum i2c_addr_mode_t

Values:

I2C_ADDR_BIT_7 = 0

I2C 7bit address for slave mode

I2C_ADDR_BIT_10

I2C 10bit address for slave mode

I2C_ADDR_BIT_MAX
结构体
struct i2c_config_t

I2C initialization parameters.

Public Members

i2c_mode_t mode

I2C mode

gpio_num_t sda_io_num

GPIO number for I2C sda signal

gpio_pullup_t sda_pullup_en

Internal GPIO pull mode for I2C sda signal

gpio_num_t scl_io_num

GPIO number for I2C scl signal

gpio_pullup_t scl_pullup_en

Internal GPIO pull mode for I2C scl signal

uint32_t clk_speed

I2C clock frequency for master mode, (no higher than 1MHz for now)

uint8_t addr_10bit_en

I2C 10bit address mode enable for slave mode

uint16_t slave_addr

I2C address for slave mode

函数
esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_buf_len, size_t slv_tx_buf_len, int intr_alloc_flags)

I2C driver install.

Note
Only slave mode will use this value, driver will ignore this value in master mode.
Note
Only slave mode will use this value, driver will ignore this value in master mode.
Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_FAIL Driver install error
Parameters
  • i2c_num: I2C port number
  • mode: I2C mode( master or slave )
  • slv_rx_buf_len: receiving buffer size for slave mode
Parameters
  • slv_tx_buf_len: sending buffer size for slave mode
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.

esp_err_t i2c_driver_delete(i2c_port_t i2c_num)

I2C driver delete.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • i2c_num: I2C port number

esp_err_t i2c_param_config(i2c_port_t i2c_num, const i2c_config_t *i2c_conf)

I2C parameter initialization.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • i2c_num: I2C port number
  • i2c_conf: pointer to I2C parameter settings

esp_err_t i2c_reset_tx_fifo(i2c_port_t i2c_num)

reset I2C tx hardware fifo

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • i2c_num: I2C port number

esp_err_t i2c_reset_rx_fifo(i2c_port_t i2c_num)

reset I2C rx fifo

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • i2c_num: I2C port number

esp_err_t i2c_isr_register(i2c_port_t i2c_num, void (*fn)(void *), void *arg, int intr_alloc_flags, intr_handle_t *handle, )

I2C isr handler register.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • i2c_num: I2C port number
  • fn: isr handler function
  • arg: parameter for isr 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: handle return from esp_intr_alloc.

esp_err_t i2c_isr_free(intr_handle_t handle)

to delete and free I2C isr.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • handle: handle of isr.

esp_err_t i2c_set_pin(i2c_port_t i2c_num, gpio_num_t sda_io_num, gpio_num_t scl_io_num, gpio_pullup_t sda_pullup_en, gpio_pullup_t scl_pullup_en, i2c_mode_t mode)

Configure GPIO signal for I2C sck and sda.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • i2c_num: I2C port number
  • sda_io_num: GPIO number for I2C sda signal
  • scl_io_num: GPIO number for I2C scl signal
  • sda_pullup_en: Whether to enable the internal pullup for sda pin
  • scl_pullup_en: Whether to enable the internal pullup for scl pin
  • mode: I2C mode

esp_err_t i2c_master_start(i2c_cmd_handle_t cmd_handle)

Queue command for I2C master to generate a start signal.

Note
Only call this function in I2C master mode Call i2c_master_cmd_begin() to send all queued commands
Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • cmd_handle: I2C cmd link

esp_err_t i2c_master_write_byte(i2c_cmd_handle_t cmd_handle, uint8_t data, bool ack_en)

Queue command for I2C master to write one byte to I2C bus.

Note
Only call this function in I2C master mode Call i2c_master_cmd_begin() to send all queued commands
Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • cmd_handle: I2C cmd link
  • data: I2C one byte command to write to bus
  • ack_en: enable ack check for master

esp_err_t i2c_master_write(i2c_cmd_handle_t cmd_handle, uint8_t *data, size_t data_len, bool ack_en)

Queue command for I2C master to write buffer to I2C bus.

Note
Only call this function in I2C master mode Call i2c_master_cmd_begin() to send all queued commands
Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • cmd_handle: I2C cmd link
  • data: data to send
  • data_len: data length
  • ack_en: enable ack check for master

esp_err_t i2c_master_read_byte(i2c_cmd_handle_t cmd_handle, uint8_t *data, int ack)

Queue command for I2C master to read one byte from I2C bus.

Note
Only call this function in I2C master mode Call i2c_master_cmd_begin() to send all queued commands
Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • cmd_handle: I2C cmd link
  • data: pointer accept the data byte
  • ack: ack value for read command

esp_err_t i2c_master_read(i2c_cmd_handle_t cmd_handle, uint8_t *data, size_t data_len, int ack)

Queue command for I2C master to read data from I2C bus.

Note
Only call this function in I2C master mode Call i2c_master_cmd_begin() to send all queued commands
Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • cmd_handle: I2C cmd link
  • data: data buffer to accept the data from bus
  • data_len: read data length
  • ack: ack value for read command

esp_err_t i2c_master_stop(i2c_cmd_handle_t cmd_handle)

Queue command for I2C master to generate a stop signal.

Note
Only call this function in I2C master mode Call i2c_master_cmd_begin() to send all queued commands
Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • cmd_handle: I2C cmd link

esp_err_t i2c_master_cmd_begin(i2c_port_t i2c_num, i2c_cmd_handle_t cmd_handle, portBASE_TYPE ticks_to_wait)

I2C master send queued commands. This function will trigger sending all queued commands. The task will be blocked until all the commands have been sent out. The I2C APIs are not thread-safe, if you want to use one I2C port in different tasks, you need to take care of the multi-thread issue.

Note
Only call this function in I2C master mode
Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_FAIL Sending command error, slave doesn’t ACK the transfer.
  • ESP_ERR_INVALID_STATE I2C driver not installed or not in master mode.
  • ESP_ERR_TIMEOUT Operation timeout because the bus is busy.
Parameters
  • i2c_num: I2C port number
  • cmd_handle: I2C command handler
  • ticks_to_wait: maximum wait ticks.

int i2c_slave_write_buffer(i2c_port_t i2c_num, uint8_t *data, int size, portBASE_TYPE ticks_to_wait)

I2C slave write data to internal ringbuffer, when tx fifo empty, isr will fill the hardware fifo from the internal ringbuffer.

Note
Only call this function in I2C slave mode
Return
  • ESP_FAIL(-1) Parameter error
  • Others(>=0) The number of data bytes that pushed to the I2C slave buffer.
Parameters
  • i2c_num: I2C port number
  • data: data pointer to write into internal buffer
  • size: data size
  • ticks_to_wait: Maximum waiting ticks

警告

doxygenfunction: Cannot find function “i2c_slave_read” in doxygen xml output for project “esp32-idf” from directory: xml/

esp_err_t i2c_set_period(i2c_port_t i2c_num, int high_period, int low_period)

set I2C master clock period

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • i2c_num: I2C port number
  • high_period: clock cycle number during SCL is high level, high_period is a 14 bit value
  • low_period: clock cycle number during SCL is low level, low_period is a 14 bit value

esp_err_t i2c_get_period(i2c_port_t i2c_num, int *high_period, int *low_period)

get I2C master clock period

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • i2c_num: I2C port number
  • high_period: pointer to get clock cycle number during SCL is high level, will get a 14 bit value
  • low_period: pointer to get clock cycle number during SCL is low level, will get a 14 bit value

esp_err_t i2c_set_start_timing(i2c_port_t i2c_num, int setup_time, int hold_time)

set I2C master start signal timing

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • i2c_num: I2C port number
  • setup_time: clock number between the falling-edge of SDA and rising-edge of SCL for start mark, it’s a 10-bit value.
  • hold_time: clock num between the falling-edge of SDA and falling-edge of SCL for start mark, it’s a 10-bit value.

esp_err_t i2c_get_start_timing(i2c_port_t i2c_num, int *setup_time, int *hold_time)

get I2C master start signal timing

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • i2c_num: I2C port number
  • setup_time: pointer to get setup time
  • hold_time: pointer to get hold time

esp_err_t i2c_set_stop_timing(i2c_port_t i2c_num, int setup_time, int hold_time)

set I2C master stop signal timing

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • i2c_num: I2C port number
  • setup_time: clock num between the rising-edge of SCL and the rising-edge of SDA, it’s a 10-bit value.
  • hold_time: clock number after the STOP bit’s rising-edge, it’s a 14-bit value.

esp_err_t i2c_get_stop_timing(i2c_port_t i2c_num, int *setup_time, int *hold_time)

get I2C master stop signal timing

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • i2c_num: I2C port number
  • setup_time: pointer to get setup time.
  • hold_time: pointer to get hold time.

esp_err_t i2c_set_data_timing(i2c_port_t i2c_num, int sample_time, int hold_time)

set I2C data signal timing

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • i2c_num: I2C port number
  • sample_time: clock number I2C used to sample data on SDA after the rising-edge of SCL, it’s a 10-bit value
  • hold_time: clock number I2C used to hold the data after the falling-edge of SCL, it’s a 10-bit value

esp_err_t i2c_get_data_timing(i2c_port_t i2c_num, int *sample_time, int *hold_time)

get I2C data signal timing

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • i2c_num: I2C port number
  • sample_time: pointer to get sample time
  • hold_time: pointer to get hold time

esp_err_t i2c_set_data_mode(i2c_port_t i2c_num, i2c_trans_mode_t tx_trans_mode, i2c_trans_mode_t rx_trans_mode)

set I2C data transfer mode

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • i2c_num: I2C port number
  • tx_trans_mode: I2C sending data mode
  • rx_trans_mode: I2C receving data mode

esp_err_t i2c_get_data_mode(i2c_port_t i2c_num, i2c_trans_mode_t *tx_trans_mode, i2c_trans_mode_t *rx_trans_mode)

get I2C data transfer mode

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • i2c_num: I2C port number
  • tx_trans_mode: pointer to get I2C sending data mode
  • rx_trans_mode: pointer to get I2C receiving data mode

Create and init I2C command link.

Note
Before we build I2C command link, we need to call i2c_cmd_link_create() to create a command link. After we finish sending the commands, we need to call i2c_cmd_link_delete() to release and return the resources.
Return
i2c command link handler

Free I2C command link.

Note
Before we build I2C command link, we need to call i2c_cmd_link_create() to create a command link. After we finish sending the commands, we need to call i2c_cmd_link_delete() to release and return the resources.
Parameters
  • cmd_handle: I2C command handle

I2S

概述

ESP32 contains two I2S peripherals. These peripherals can be configured to input and output sample data via the I2S driver.

The I2S peripheral supports DMA meaning it can stream sample data without requiring each sample to be read or written by the CPU.

I2S output can also be routed directly to the Digital/Analog Converter output channels (GPIO 25 & GPIO 26) to produce analog output directly, rather than via an external I2S codec.

应用程序示例

A full I2S example is available in esp-idf: peripherals/i2s.

Short example of I2S configuration:

#include "driver/i2s.h"
#include "freertos/queue.h"

static const int i2s_num = 0; // i2s port number

static const i2s_config_t i2s_config = {
     .mode = I2S_MODE_MASTER | I2S_MODE_TX,
     .sample_rate = 44100,
     .bits_per_sample = 16,
     .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
     .communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB,
     .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // high interrupt priority
     .dma_buf_count = 8,
     .dma_buf_len = 64
};

static const i2s_pin_config_t pin_config = {
    .bck_io_num = 26,
    .ws_io_num = 25,
    .data_out_num = 22,
    .data_in_num = I2S_PIN_NO_CHANGE
};

...

    i2s_driver_install(i2s_num, &i2s_config, 0, NULL);   //install and start i2s driver

    i2s_set_pin(i2s_num, &pin_config);

    i2s_set_sample_rates(i2s_num, 22050); //set sample rates

    i2s_driver_uninstall(i2s_num); //stop & destroy i2s driver

Short example configuring I2S to use internal DAC for analog output:

#include "driver/i2s.h"
#include "freertos/queue.h"

static const int i2s_num = 0; // i2s port number

static const i2s_config_t i2s_config = {
     .mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN,
     .sample_rate = 44100,
     .bits_per_sample = 8, /* must be 8 for built-in DAC */
     .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
     .communication_format = I2S_COMM_FORMAT_I2S_MSB,
     .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // high interrupt priority
     .dma_buf_count = 8,
     .dma_buf_len = 64
};

...

    i2s_driver_install(i2s_num, &i2s_config, 0, NULL);   //install and start i2s driver

    i2s_set_pin(i2s_num, NULL); //for internal DAC

    i2s_set_sample_rates(i2s_num, 22050); //set sample rates

    i2s_driver_uninstall(i2s_num); //stop & destroy i2s driver
API 参考手册
头文件
  • components/driver/include/driver/i2s.h
Data 结构体
struct i2s_config_t

I2S configuration parameters for i2s_param_config function.

Public Members

i2s_mode_t mode

I2S work mode

int sample_rate

I2S sample rate

i2s_bits_per_sample_t bits_per_sample

I2S bits per sample

i2s_channel_fmt_t channel_format

I2S channel format

i2s_comm_format_t communication_format

I2S communication format

int 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

int dma_buf_count

I2S DMA Buffer Count

int dma_buf_len

I2S DMA Buffer Length

struct i2s_event_t

Event structure used in I2S event queue.

Public Members

i2s_event_type_t type

I2S event type

size_t size

I2S data size for I2S_DATA event

struct i2s_pin_config_t

I2S pin number for i2s_set_pin.

Public Members

int bck_io_num

BCK in out pin

int ws_io_num

WS in out pin

int data_out_num

DATA out pin

int data_in_num

DATA in pin

I2S_PIN_NO_CHANGE

Use in i2s_pin_config_t for pins which should not be changed

枚举
enum i2s_bits_per_sample_t

I2S bit width per sample.

Values:

I2S_BITS_PER_SAMPLE_8BIT = 8

I2S bits per sample: 8-bits

I2S_BITS_PER_SAMPLE_16BIT = 16

I2S bits per sample: 16-bits

I2S_BITS_PER_SAMPLE_24BIT = 24

I2S bits per sample: 24-bits

I2S_BITS_PER_SAMPLE_32BIT = 32

I2S bits per sample: 32-bits

enum i2s_comm_format_t

I2S communication standard format.

Values:

I2S_COMM_FORMAT_I2S = 0x01

I2S communication format I2S

I2S_COMM_FORMAT_I2S_MSB = 0x02

I2S format MSB

I2S_COMM_FORMAT_I2S_LSB = 0x04

I2S format LSB

I2S_COMM_FORMAT_PCM = 0x08

I2S communication format PCM

I2S_COMM_FORMAT_PCM_SHORT = 0x10

PCM Short

I2S_COMM_FORMAT_PCM_LONG = 0x20

PCM Long

enum i2s_channel_fmt_t

I2S channel format type.

Values:

I2S_CHANNEL_FMT_RIGHT_LEFT = 0x00
I2S_CHANNEL_FMT_ALL_RIGHT
I2S_CHANNEL_FMT_ALL_LEFT
I2S_CHANNEL_FMT_ONLY_RIGHT
I2S_CHANNEL_FMT_ONLY_LEFT
enum pdm_sample_rate_ratio_t

PDM sample rate ratio, measured in Hz.

Values:

PDM_SAMPLE_RATE_RATIO_64
PDM_SAMPLE_RATE_RATIO_128
enum pdm_pcm_conv_t

PDM PCM convter enable/disable.

Values:

PDM_PCM_CONV_ENABLE
PDM_PCM_CONV_DISABLE
enum i2s_port_t

I2S Peripheral, 0 & 1.

Values:

I2S_NUM_0 = 0x0

I2S 0

I2S_NUM_1 = 0x1

I2S 1

I2S_NUM_MAX
enum i2s_mode_t

I2S Mode, defaut is I2S_MODE_MASTER | I2S_MODE_TX.

Values:

I2S_MODE_MASTER = 1
I2S_MODE_SLAVE = 2
I2S_MODE_TX = 4
I2S_MODE_RX = 8
I2S_MODE_DAC_BUILT_IN = 16
enum i2s_event_type_t

I2S event types.

Values:

I2S_EVENT_DMA_ERROR
I2S_EVENT_TX_DONE

I2S DMA finish sent 1 buffer

I2S_EVENT_RX_DONE

I2S DMA finish received 1 buffer

I2S_EVENT_MAX

I2S event max index

函数
esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin)

Set I2S pin number.

Inside the pin configuration structure, set I2S_PIN_NO_CHANGE for any pin where the current configuration should not be changed.

Note
The I2S peripheral output signals can be connected to multiple GPIO pads. However, the I2S peripheral input signal can only be connected to one GPIO pad.
Parameters
  • i2s_num: I2S_NUM_0 or I2S_NUM_1
  • pin: I2S Pin structure, or NULL to set 2-channel 8-bit internal DAC pin configuration (GPIO25 & GPIO26)

Return
  • ESP_OK Success
  • ESP_FAIL Parameter error

esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, int queue_size, void *i2s_queue)

Install and start I2S driver.

This function must be called before any I2S driver read/write operations.

Parameters
  • i2s_num: I2S_NUM_0, I2S_NUM_1
  • i2s_config: I2S configurations - see i2s_config_t struct
  • queue_size: I2S event queue size/depth.
  • i2s_queue: I2S event queue handle, if set NULL, driver will not use an event queue.

Return
  • ESP_OK Success
  • ESP_FAIL Parameter error

esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num)

Uninstall I2S driver.

Return
  • ESP_OK Success
  • ESP_FAIL Parameter error
Parameters
  • i2s_num: I2S_NUM_0, I2S_NUM_1

int i2s_write_bytes(i2s_port_t i2s_num, const char *src, size_t size, TickType_t ticks_to_wait)

Write data to I2S DMA transmit buffer.

Format of the data in source buffer is determined by the I2S configuration (see i2s_config_t).

Parameters
  • i2s_num: I2S_NUM_0, I2S_NUM_1
  • src: Source address to write from
  • size: Size of data in bytes
  • ticks_to_wait: TX buffer wait timeout in RTOS ticks. If this many ticks pass without space becoming available in the DMA transmit buffer, then the function will return (note that if the data is written to the DMA buffer in pieces, the overall operation may still take longer than this timeout.) Pass portMAX_DELAY for no timeout.

Return
Number of bytes written, or ESP_FAIL (-1) for parameter error. If a timeout occurred, bytes written will be less than total size.

int i2s_read_bytes(i2s_port_t i2s_num, char *dest, size_t size, TickType_t ticks_to_wait)

Read data from I2S DMA receive buffer.

Format of the data in source buffer is determined by the I2S configuration (see i2s_config_t).

Parameters
  • i2s_num: I2S_NUM_0, I2S_NUM_1
  • dest: Destination address to read into
  • size: Size of data in bytes
  • ticks_to_wait: RX buffer wait timeout in RTOS ticks. If this many ticks pass without bytes becoming available in the DMA receive buffer, then the function will return (note that if data is read from the DMA buffer in pieces, the overall operation may still take longer than this timeout.) Pass portMAX_DELAY for no timeout.

Return
Number of bytes read, or ESP_FAIL (-1) for parameter error. If a timeout occurred, bytes read will be less than total size.

int i2s_push_sample(i2s_port_t i2s_num, const char *sample, TickType_t ticks_to_wait)

Push (write) a single sample to the I2S DMA TX buffer.

Size of the sample is determined by the channel_format (mono or stereo)) & bits_per_sample configuration (see i2s_config_t).

Return
Number of bytes successfully pushed to DMA buffer, or ESP_FAIL (-1) for parameter error. Will be either zero or the size of configured sample buffer.
Parameters
  • i2s_num: I2S_NUM_0, I2S_NUM_1
  • sample: Pointer to buffer containing sample to write. Size of buffer (in bytes) = (number of channels) * bits_per_sample / 8.
  • ticks_to_wait: Push timeout in RTOS ticks. If space is not available in the DMA TX buffer within this period, no data is written and function returns 0.

int i2s_pop_sample(i2s_port_t i2s_num, char *sample, TickType_t ticks_to_wait)

Pop (read) a single sample from the I2S DMA RX buffer.

Size of the sample is determined by the channel_format (mono or stereo)) & bits_per_sample configuration (see i2s_config_t).

Return
Number of bytes successfully read from DMA buffer, or ESP_FAIL (-1) for parameter error. Byte count will be either zero or the size of the configured sample buffer.
Parameters
  • i2s_num: I2S_NUM_0, I2S_NUM_1
  • sample: Buffer sample data will be read into. Size of buffer (in bytes) = (number of channels) * bits_per_sample / 8.
  • ticks_to_wait: Pop timeout in RTOS ticks. If a sample is not available in the DMA buffer within this period, no data is read and function returns zero.

esp_err_t i2s_set_sample_rates(i2s_port_t i2s_num, uint32_t rate)

Set sample rate used for I2S RX and TX.

The bit clock rate is determined by the sample rate and i2s_config_t configuration parameters (number of channels, bits_per_sample).

bit_clock = rate * (number of channels) * bits_per_sample

Return
  • ESP_OK Success
  • ESP_FAIL Parameter error
Parameters
  • i2s_num: I2S_NUM_0, I2S_NUM_1
  • rate: I2S sample rate (ex: 8000, 44100...)

esp_err_t i2s_start(i2s_port_t i2s_num)

Start I2S driver.

It is not necessary to call this function after i2s_driver_install() (it is started automatically), however it is necessary to call it after i2s_stop().

Return
  • ESP_OK Success
  • ESP_FAIL Parameter error
Parameters
  • i2s_num: I2S_NUM_0, I2S_NUM_1

esp_err_t i2s_stop(i2s_port_t i2s_num)

Stop I2S driver.

Disables I2S TX/RX, until i2s_start() is called.

Return
  • ESP_OK Success
  • ESP_FAIL Parameter error
Parameters
  • i2s_num: I2S_NUM_0, I2S_NUM_1

esp_err_t i2s_zero_dma_buffer(i2s_port_t i2s_num)

Zero the contents of the TX DMA buffer.

Pushes zero-byte samples into the TX DMA buffer, until it is full.

Return
  • ESP_OK Success
  • ESP_FAIL Parameter error
Parameters
  • i2s_num: I2S_NUM_0, I2S_NUM_1

LED Control

概述

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.

应用程序示例

LEDC change duty cycle and fading control example: peripherals/ledc.

API 参考手册
LEDC_APB_CLK_HZ
LEDC_REF_CLK_HZ
类型定义
typedef intr_handle_t ledc_isr_handle_t
枚举
enum ledc_mode_t

Values:

LEDC_HIGH_SPEED_MODE = 0

LEDC high speed speed_mode

LEDC_LOW_SPEED_MODE

LEDC low 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

结构体
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)

函数
esp_err_t ledc_channel_config(const 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(const 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,
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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.
  • ESP_FAIL Fade function init error
Parameters
  • speed_mode: Select the LEDC speed_mode, high-speed mode and low-speed mode,
  • 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.
  • ESP_FAIL Fade function init error
Parameters
  • speed_mode: Select the LEDC speed_mode, high-speed mode and low-speed mode,
  • 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_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_mode_t speed_mode, 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
  • speed_mode: Select the LEDC speed_mode, high-speed mode and low-speed mode
  • channel: LEDC channel number
  • wait_done: Whether to block until fading done.

Pulse Counter

概述

The PCNT (Pulse Counter) module is designed to count the number of rising and/or falling edges of an input signal. Each pulse counter unit has a 16-bit signed counter register and two channels that can be configured to either increment or decrement the counter. Each channel has a signal input that accepts signal edges to be detected, as well as a control input that can be used to enable or disable the signal input. The inputs have optional filters that can be used to discard unwanted glitches in the signal.

应用程序示例

Pulse counter with control signal and event interrupt example: peripherals/pcnt.

API 参考手册
类型定义
枚举
enum pcnt_ctrl_mode_t

Values:

PCNT_MODE_KEEP = 0

Control mode: won’t change counter mode

PCNT_MODE_REVERSE = 1

Control mode: invert counter mode(increase -> decrease, decrease -> increase);

PCNT_MODE_DISABLE = 2

Control mode: Inhibit counter(counter value will not change in this condition)

PCNT_MODE_MAX
enum pcnt_count_mode_t

Values:

PCNT_COUNT_DIS = 0

Counter mode: Inhibit counter(counter value will not change in this condition)

PCNT_COUNT_INC = 1

Counter mode: Increase counter value

PCNT_COUNT_DEC = 2

Counter mode: Decrease counter value

PCNT_COUNT_MAX
enum pcnt_unit_t

Values:

PCNT_UNIT_0 = 0

PCNT unit0

PCNT_UNIT_1 = 1

PCNT unit1

PCNT_UNIT_2 = 2

PCNT unit2

PCNT_UNIT_3 = 3

PCNT unit3

PCNT_UNIT_4 = 4

PCNT unit4

PCNT_UNIT_5 = 5

PCNT unit5

PCNT_UNIT_6 = 6

PCNT unit6

PCNT_UNIT_7 = 7

PCNT unit7

PCNT_UNIT_MAX
enum pcnt_channel_t

Values:

PCNT_CHANNEL_0 = 0x00

PCNT channel0

PCNT_CHANNEL_1 = 0x01

PCNT channel1

PCNT_CHANNEL_MAX
enum pcnt_evt_type_t

Values:

PCNT_EVT_L_LIM = 0

PCNT watch point event: Minimum counter value

PCNT_EVT_H_LIM = 1

PCNT watch point event: Maximum counter value

PCNT_EVT_THRES_0 = 2

PCNT watch point event: threshold0 value event

PCNT_EVT_THRES_1 = 3

PCNT watch point event: threshold1 value event

PCNT_EVT_ZERO = 4

PCNT watch point event: counter value zero event

PCNT_EVT_MAX
结构体
struct pcnt_config_t

Pulse Counter configure struct.

函数
esp_err_t pcnt_unit_config(const pcnt_config_t *pcnt_config)

Configure Pulse Counter unit.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • pcnt_config: Pointer of Pulse Counter unit configure parameter

esp_err_t pcnt_get_counter_value(pcnt_unit_t pcnt_unit, int16_t *count)

Get pulse counter value.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • pcnt_unit: Pulse Counter unit number
  • count: Pointer to accept counter value

esp_err_t pcnt_counter_pause(pcnt_unit_t pcnt_unit)

Pause PCNT counter of PCNT unit.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • pcnt_unit: PCNT unit number

esp_err_t pcnt_counter_resume(pcnt_unit_t pcnt_unit)

Resume counting for PCNT counter.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • pcnt_unit: PCNT unit number, select from pcnt_unit_t

esp_err_t pcnt_counter_clear(pcnt_unit_t pcnt_unit)

Clear and reset PCNT counter value to zero.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • pcnt_unit: PCNT unit number, select from pcnt_unit_t

esp_err_t pcnt_intr_enable(pcnt_unit_t pcnt_unit)

Enable PCNT interrupt for PCNT unit.

Note
Each Pulse counter unit has five watch point events that share the same interrupt. Configure events with pcnt_event_enable() and pcnt_event_disable()
Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • pcnt_unit: PCNT unit number

esp_err_t pcnt_intr_disable(pcnt_unit_t pcnt_unit)

Disable PCNT interrupt for PCNT uint.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • pcnt_unit: PCNT unit number

esp_err_t pcnt_event_enable(pcnt_unit_t unit, pcnt_evt_type_t evt_type)

Enable PCNT event of PCNT unit.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • unit: PCNT unit number
  • evt_type: Watch point event type. All enabled events share the same interrupt (one interrupt per pulse counter unit).

esp_err_t pcnt_event_disable(pcnt_unit_t unit, pcnt_evt_type_t evt_type)

Disable PCNT event of PCNT unit.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • unit: PCNT unit number
  • evt_type: Watch point event type. All enabled events share the same interrupt (one interrupt per pulse counter unit).

esp_err_t pcnt_set_event_value(pcnt_unit_t unit, pcnt_evt_type_t evt_type, int16_t value)

Set PCNT event value of PCNT unit.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • unit: PCNT unit number
  • evt_type: Watch point event type. All enabled events share the same interrupt (one interrupt per pulse counter unit).
  • value: Counter value for PCNT event

esp_err_t pcnt_get_event_value(pcnt_unit_t unit, pcnt_evt_type_t evt_type, int16_t *value)

Get PCNT event value of PCNT unit.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • unit: PCNT unit number
  • evt_type: Watch point event type. All enabled events share the same interrupt (one interrupt per pulse counter unit).
  • value: Pointer to accept counter value for PCNT event

esp_err_t pcnt_isr_register(void (*fn)(void *), void *arg, int intr_alloc_flags, pcnt_isr_handle_t *handle, )

Register PCNT 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: 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 pcnt_set_pin(pcnt_unit_t unit, pcnt_channel_t channel, int pulse_io, int ctrl_io)

Configure PCNT pulse signal input pin and control input pin.

Note
Set to PCNT_PIN_NOT_USED if unused.
Note
Set to PCNT_PIN_NOT_USED if unused.
Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • unit: PCNT unit number
  • channel: PCNT channel number
  • pulse_io: Pulse signal input GPIO
Parameters
  • ctrl_io: Control signal input GPIO

esp_err_t pcnt_filter_enable(pcnt_unit_t unit)

Enable PCNT input filter.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • unit: PCNT unit number

esp_err_t pcnt_filter_disable(pcnt_unit_t unit)

Disable PCNT input filter.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • unit: PCNT unit number

esp_err_t pcnt_set_filter_value(pcnt_unit_t unit, uint16_t filter_val)

Set PCNT filter value.

Note
filter_val is a 10-bit value, so the maximum filter_val should be limited to 1023.
Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • unit: PCNT unit number
  • filter_val: PCNT signal filter value, counter in APB_CLK cycles. Any pulses lasting shorter than this will be ignored when the filter is enabled.

esp_err_t pcnt_get_filter_value(pcnt_unit_t unit, uint16_t *filter_val)

Get PCNT filter value.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • unit: PCNT unit number
  • filter_val: Pointer to accept PCNT filter value.

esp_err_t pcnt_set_mode(pcnt_unit_t unit, pcnt_channel_t channel, pcnt_count_mode_t pos_mode, pcnt_count_mode_t neg_mode, pcnt_ctrl_mode_t hctrl_mode, pcnt_ctrl_mode_t lctrl_mode)

Set PCNT counter mode.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • unit: PCNT unit number
  • channel: PCNT channel number
  • pos_mode: Counter mode when detecting positive edge
  • neg_mode: Counter mode when detecting negative edge
  • hctrl_mode: Counter mode when control signal is high level
  • lctrl_mode: Counter mode when control signal is low level

SDMMC Host Peripheral

概述

SDMMC peripheral supports SD and MMC memory cards and SDIO cards. SDMMC software builds on top of SDMMC driver and consists of the following parts:

  1. SDMMC host driver (driver/sdmmc_host.h) — this driver provides APIs to send commands to the slave device(s), send and receive data, and handling error conditions on the bus.
  2. SDMMC protocol layer (sdmmc_cmd.h) — this component handles specifics of SD protocol such as card initialization and data transfer commands. Despite the name, only SD (SDSC/SDHC/SDXC) cards are supported at the moment. Support for MCC/eMMC cards can be added in the future.

Protocol layer works with the host via sdmmc_host_t structure. This structure contains pointers to various functions of the host. This design makes it possible to implement an SD host using SPI interface later.

应用程序示例

An example which combines SDMMC driver with FATFS library is provided in examples/storage/sd_card directory. This example initializes the card, writes and reads data from it using POSIX and C library APIs. See README.md file in the example directory for more information.

Protocol layer APIs

Protocol layer is given sdmmc_host_t structure which describes the SD/MMC host driver, lists its capabilites, and provides pointers to functions of the driver. Protocol layer stores card-specific information in sdmmc_card_t structure. When sending commands to the SD/MMC host driver, protocol layer uses sdmmc_command_t structure to describe the command, argument, expected return value, and data to transfer, if any.

Normal usage of the protocol layer is as follows:

  1. Call the host driver functions to initialize the host (e.g. sdmmc_host_init, sdmmc_host_init_slot).
  2. Call sdmmc_card_init to initialize the card, passing it host driver information (host) and a pointer to sdmmc_card_t structure which will be filled in (card).
  3. To read and write sectors of the card, use sdmmc_read_sectors and sdmmc_write_sectors, passing the pointer to card information structure (card).
  4. When card is not used anymore, call the host driver function to disable SDMMC host peripheral and free resources allocated by the driver (e.g. sdmmc_host_deinit).

Most applications need to use the protocol layer only in one task; therefore the protocol layer doesn’t implement any kind of locking on the sdmmc_card_t structure, or when accessing SDMMC host driver. Such locking has to be implemented in the higher layer, if necessary (e.g. in the filesystem driver).

struct sdmmc_host_t

SD/MMC Host description

This structure defines properties of SD/MMC host and functions of SD/MMC host which can be used by upper layers.

Public Members

uint32_t flags

flags defining host properties

int slot

slot number, to be passed to host functions

int max_freq_khz

max frequency supported by the host

float io_voltage

I/O voltage used by the controller (voltage switching is not supported)

esp_err_t (*init)(void)

Host function to initialize the driver

esp_err_t (*set_bus_width)(int slot, size_t width)

host function to set bus width

esp_err_t (*set_card_clk)(int slot, uint32_t freq_khz)

host function to set card clock frequency

esp_err_t (*do_transaction)(int slot, sdmmc_command_t *cmdinfo)

host function to do a transaction

esp_err_t (*deinit)(void)

host function to deinitialize the driver

SDMMC_HOST_FLAG_1BIT

host supports 1-line SD and MMC protocol

SDMMC_HOST_FLAG_4BIT

host supports 4-line SD and MMC protocol

SDMMC_HOST_FLAG_8BIT

host supports 8-line MMC protocol

SDMMC_HOST_FLAG_SPI

host supports SPI protocol

SDMMC_FREQ_DEFAULT

SD/MMC Default speed (limited by clock divider)

SDMMC_FREQ_HIGHSPEED

SD High speed (limited by clock divider)

SDMMC_FREQ_PROBING

SD/MMC probing speed

struct sdmmc_command_t

SD/MMC command information

Public Members

uint32_t opcode

SD or MMC command index

uint32_t arg

SD/MMC command argument

sdmmc_response_t response

response buffer

void *data

buffer to send or read into

size_t datalen

length of data buffer

size_t blklen

block length

int flags

see below

esp_err_t error

error returned from transfer

struct sdmmc_card_t

SD/MMC card information structure

Public Members

sdmmc_host_t host

Host with which the card is associated

uint32_t ocr

OCR (Operation Conditions Register) value

sdmmc_cid_t cid

decoded CID (Card IDentification) register value

sdmmc_csd_t csd

decoded CSD (Card-Specific Data) register value

sdmmc_scr_t scr

decoded SCR (SD card Configuration Register) value

uint16_t rca

RCA (Relative Card Address)

struct sdmmc_csd_t

Decoded values from SD card Card Specific Data register

Public Members

int csd_ver

CSD structure format

int mmc_ver

MMC version (for CID format)

int capacity

total number of sectors

int sector_size

sector size in bytes

int read_block_len

block length for reads

int card_command_class

Card Command Class for SD

int tr_speed

Max transfer speed

struct sdmmc_cid_t

Decoded values from SD card Card IDentification register

Public Members

int mfg_id

manufacturer identification number

int oem_id

OEM/product identification number

char name[8]

product name (MMC v1 has the longest)

int revision

product revision

int serial

product serial number

int date

manufacturing date

struct sdmmc_scr_t

Decoded values from SD Configuration Register

Public Members

int sd_spec

SD Physical layer specification version, reported by card

int bus_width

bus widths supported by card: BIT(0) — 1-bit bus, BIT(2) — 4-bit bus

esp_err_t sdmmc_card_init(const sdmmc_host_t *host, sdmmc_card_t *out_card)

Probe and initialize SD/MMC card using given host

Note
Only SD cards (SDSC and SDHC/SDXC) are supported now. Support for MMC/eMMC cards will be added later.
Return
  • ESP_OK on success
  • One of the error codes from SDMMC host controller
Parameters
  • host: pointer to structure defining host controller
  • out_card: pointer to structure which will receive information about the card when the function completes

esp_err_t sdmmc_write_sectors(sdmmc_card_t *card, const void *src, size_t start_sector, size_t sector_count)

Write given number of sectors to SD/MMC card

Return
  • ESP_OK on success
  • One of the error codes from SDMMC host controller
Parameters
  • card: pointer to card information structure previously initialized using sdmmc_card_init
  • src: pointer to data buffer to read data from; data size must be equal to sector_count * card->csd.sector_size
  • start_sector: sector where to start writing
  • sector_count: number of sectors to write

esp_err_t sdmmc_read_sectors(sdmmc_card_t *card, void *dst, size_t start_sector, size_t sector_count)

Write given number of sectors to SD/MMC card

Return
  • ESP_OK on success
  • One of the error codes from SDMMC host controller
Parameters
  • card: pointer to card information structure previously initialized using sdmmc_card_init
  • dst: pointer to data buffer to write into; buffer size must be at least sector_count * card->csd.sector_size
  • start_sector: sector where to start reading
  • sector_count: number of sectors to read

SDMMC host driver APIs

On the ESP32, SDMMC host peripheral has two slots:

  • Slot 0 (SDMMC_HOST_SLOT_0) is an 8-bit slot. It uses HS1_* signals in the PIN MUX.
  • Slot 1 (SDMMC_HOST_SLOT_1) is a 4-bit slot. It uses HS2_* signals in the PIN MUX.

Card Detect and Write Protect signals can be routed to arbitrary pins using GPIO matrix. To use these pins, set gpio_cd and gpio_wp members of sdmmc_slot_config_t structure when calling sdmmc_host_init_slot.

Of all the funtions listed below, only sdmmc_host_init, sdmmc_host_init_slot, and sdmmc_host_deinit will be used directly by most applications. Other functions, such as sdmmc_host_set_bus_width, sdmmc_host_set_card_clk, and sdmmc_host_do_transaction will be called by the SD/MMC protocol layer via function pointers in sdmmc_host_t structure.

esp_err_t sdmmc_host_init()

Initialize SDMMC host peripheral.

Note
This function is not thread safe
Return
  • ESP_OK on success
  • ESP_ERR_INVALID_STATE if sdmmc_host_init was already called
  • ESP_ERR_NO_MEM if memory can not be allocated

SDMMC_HOST_SLOT_0

SDMMC slot 0.

SDMMC_HOST_SLOT_1

SDMMC slot 1.

SDMMC_HOST_DEFAULT

Default sdmmc_host_t structure initializer for SDMMC peripheral.

Uses SDMMC peripheral, with 4-bit mode enabled, and max frequency set to 20MHz

SDMMC_SLOT_WIDTH_DEFAULT

use the default width for the slot (8 for slot 0, 4 for slot 1)

esp_err_t sdmmc_host_init_slot(int slot, const sdmmc_slot_config_t *slot_config)

Initialize given slot of SDMMC peripheral.

On the ESP32, SDMMC peripheral has two slots:

  • Slot 0: 8-bit wide, maps to HS1_* signals in PIN MUX
  • Slot 1: 4-bit wide, maps to HS2_* signals in PIN MUX

Card detect and write protect signals can be routed to arbitrary GPIOs using GPIO matrix.

Note
This function is not thread safe
Return
  • ESP_OK on success
  • ESP_ERR_INVALID_STATE if host has not been initialized using sdmmc_host_init
Parameters
  • slot: slot number (SDMMC_HOST_SLOT_0 or SDMMC_HOST_SLOT_1)
  • slot_config: additional configuration for the slot

struct sdmmc_slot_config_t

Extra configuration for SDMMC peripheral slot

Public Members

gpio_num_t gpio_cd

GPIO number of card detect signal.

gpio_num_t gpio_wp

GPIO number of write protect signal.

uint8_t width

Bus width used by the slot (might be less than the max width supported)

SDMMC_SLOT_NO_CD

indicates that card detect line is not used

SDMMC_SLOT_NO_WP

indicates that write protect line is not used

SDMMC_SLOT_CONFIG_DEFAULT

Macro defining default configuration of SDMMC host slot

esp_err_t sdmmc_host_set_bus_width(int slot, size_t width)

Select bus width to be used for data transfer.

SD/MMC card must be initialized prior to this command, and a command to set bus width has to be sent to the card (e.g. SD_APP_SET_BUS_WIDTH)

Note
This function is not thread safe
Return
  • ESP_OK on success
  • ESP_ERR_INVALID_ARG if slot number or width is not valid
Parameters
  • slot: slot number (SDMMC_HOST_SLOT_0 or SDMMC_HOST_SLOT_1)
  • width: bus width (1, 4, or 8 for slot 0; 1 or 4 for slot 1)

esp_err_t sdmmc_host_set_card_clk(int slot, uint32_t freq_khz)

Set card clock frequency.

Currently only integer fractions of 40MHz clock can be used. For High Speed cards, 40MHz can be used. For Default Speed cards, 20MHz can be used.

Note
This function is not thread safe
Return
  • ESP_OK on success
  • other error codes may be returned in the future
Parameters
  • slot: slot number (SDMMC_HOST_SLOT_0 or SDMMC_HOST_SLOT_1)
  • freq_khz: card clock frequency, in kHz

esp_err_t sdmmc_host_do_transaction(int slot, sdmmc_command_t *cmdinfo)

Send command to the card and get response.

This function returns when command is sent and response is received, or data is transferred, or timeout occurs.

Note
This function is not thread safe w.r.t. init/deinit functions, and bus width/clock speed configuration functions. Multiple tasks can call sdmmc_host_do_transaction as long as other sdmmc_host_* functions are not called.
Return
  • ESP_OK on success
  • ESP_ERR_TIMEOUT if response or data transfer has timed out
  • ESP_ERR_INVALID_CRC if response or data transfer CRC check has failed
  • ESP_ERR_INVALID_RESPONSE if the card has sent an invalid response
Parameters
  • slot: slot number (SDMMC_HOST_SLOT_0 or SDMMC_HOST_SLOT_1)
  • cmdinfo: pointer to structure describing command and data to transfer

esp_err_t sdmmc_host_deinit()

Disable SDMMC host and release allocated resources.

Note
This function is not thread safe
Return
  • ESP_OK on success
  • ESP_ERR_INVALID_STATE if sdmmc_host_init function has not been called

Sigma-delta Modulation

概述

ESP32 has a second-order sigma-delta modulation module. This driver configures the channels of the sigma-delta module.

应用程序示例

Sigma-delta Modulation example: peripherals/sigmadelta.

API 参考手册
类型定义
枚举
enum sigmadelta_channel_t

Sigma-delta channel list.

Values:

SIGMADELTA_CHANNEL_0 = 0

Sigma-delta channel0

SIGMADELTA_CHANNEL_1 = 1

Sigma-delta channel1

SIGMADELTA_CHANNEL_2 = 2

Sigma-delta channel2

SIGMADELTA_CHANNEL_3 = 3

Sigma-delta channel3

SIGMADELTA_CHANNEL_4 = 4

Sigma-delta channel4

SIGMADELTA_CHANNEL_5 = 5

Sigma-delta channel5

SIGMADELTA_CHANNEL_6 = 6

Sigma-delta channel6

SIGMADELTA_CHANNEL_7 = 7

Sigma-delta channel7

SIGMADELTA_CHANNEL_MAX
结构体
struct sigmadelta_config_t

Sigma-delta configure struct.

Public Members

sigmadelta_channel_t channel

Sigma-delta channel number

int8_t sigmadelta_duty

Sigma-delta duty, duty ranges from -128 to 127.

uint8_t sigmadelta_prescale

Sigma-delta prescale, prescale ranges from 0 to 255.

uint8_t sigmadelta_gpio

Sigma-delta output io number, refer to gpio.h for more details.

函数
esp_err_t sigmadelta_config(const sigmadelta_config_t *config)

Configure Sigma-delta channel.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • config: Pointer of Sigma-delta channel configuration struct

esp_err_t sigmadelta_set_duty(sigmadelta_channel_t channel, int8_t duty)

Set Sigma-delta channel duty.

This function is used to set Sigma-delta channel duty, If you add a capacitor between the output pin and ground, the average output voltage Vdc = VDDIO / 256 * duty + VDDIO/2, VDDIO is power supply voltage.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • channel: Sigma-delta channel number
  • duty: Sigma-delta duty of one channel, the value ranges from -128 to 127, recommended range is -90 ~ 90. The waveform is more like a random one in this range.

esp_err_t sigmadelta_set_prescale(sigmadelta_channel_t channel, uint8_t prescale)

Set Sigma-delta channel’s clock pre-scale value. The source clock is APP_CLK, 80MHz. The clock frequency of the sigma-delta channel is APP_CLK / pre_scale.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • channel: Sigma-delta channel number
  • prescale: The divider of source clock, ranges from 0 to 255

esp_err_t sigmadelta_set_pin(sigmadelta_channel_t channel, gpio_num_t gpio_num)

Set Sigma-delta signal output pin.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • channel: Sigma-delta channel number
  • gpio_num: GPIO number of output pin.

SPI Master driver

概述

The ESP32 has four SPI peripheral devices, called SPI0, SPI1, HSPI and VSPI. SPI0 is entirely dedicated to the flash cache the ESP32 uses to map the SPI flash device it is connected to into memory. SPI1 is connected to the same hardware lines as SPI0 and is used to write to the flash chip. HSPI and VSPI are free to use. SPI1, HSPI and VSPI all have three chip select lines, allowing them to drive up to three SPI devices each as a master.

The spi_master driver

The spi_master driver allows easy communicating with SPI slave devices, even in a multithreaded environment. It fully transparently handles DMA transfers to read and write data and automatically takes care of multiplexing between different SPI slaves on the same master

Terminology

The spi_master driver uses the following terms:

  • Host: The SPI peripheral inside the ESP32 initiating the SPI transmissions. One of SPI, HSPI or VSPI. (For now, only HSPI or VSPI are actually supported in the driver; it will support all 3 peripherals somewhere in the future.)
  • Bus: The SPI bus, common to all SPI devices connected to one host. In general the bus consists of the miso, mosi, sclk and optionally quadwp and quadhd signals. The SPI slaves are connected to these signals in parallel.
    • miso - Also known as q, this is the input of the serial stream into the ESP32
    • mosi - Also known as d, this is the output of the serial stream from the ESP32
    • sclk - Clock signal. Each data bit is clocked out or in on the positive or negative edge of this signal
    • quadwp - Write Protect signal. Only used for 4-bit (qio/qout) transactions.
    • quadhd - Hold signal. Only used for 4-bit (qio/qout) transactions.
  • Device: A SPI slave. Each SPI slave has its own chip select (CS) line, which is made active when a transmission to/from the SPI slave occurs.
  • Transaction: One instance of CS going active, data transfer from and/or to a device happening, and CS going inactive again. Transactions are atomic, as in they will never be interrupted by another transaction.
SPI transactions

A transaction on the SPI bus consists of five phases, any of which may be skipped:

  • The command phase. In this phase, a command (0-16 bit) is clocked out.
  • The address phase. In this phase, an address (0-64 bit) is clocked out.
  • The read phase. The slave sends data to the master.
  • The write phase. The master sends data to the slave.

In full duplex, the read and write phases are combined, causing the SPI host to read and write data simultaneously.

The command and address phase are optional in that not every SPI device will need to be sent a command and/or address. Tis is reflected in the device configuration: when the command_bits or data_bits fields are set to zero, no command or address phase is done.

Something similar is true for the read and write phase: not every transaction needs both data to be written as well as data to be read. When rx_buffer is NULL (and SPI_USE_RXDATA) is not set) the read phase is skipped. When tx_buffer is NULL (and SPI_USE_TXDATA) is not set) the write phase is skipped.

Using the spi_master driver
  • Initialize a SPI bus by calling spi_bus_initialize. Make sure to set the correct IO pins in the bus_config struct. Take care to set signals that are not needed to -1.
  • Tell the driver about a SPI slave device connected to the bus by calling spi_bus_add_device. Make sure to configure any timing requirements the device has in the dev_config structure. You should now have a handle for the device, to be used when sending it a transaction.
  • To interact with the device, fill one or more spi_transaction_t structure with any transaction parameters you need. Either queue all transactions by calling spi_device_queue_trans, later quering the result using spi_device_get_trans_result, or handle all requests synchroneously by feeding them into spi_device_transmit.
  • Optional: to unload the driver for a device, call spi_bus_remove_device with the device handle as an argument
  • Optional: to remove the driver for a bus, make sure no more drivers are attached and call spi_bus_free.
Transaction data

Normally, data to be transferred to or from a device will be read from or written to a chunk of memory indicated by the rx_buffer and tx_buffer members of the transaction structure. The SPI driver may decide to use DMA for transfers, so these buffers should be allocated in DMA-capable memory using pvPortMallocCaps(size, MALLOC_CAP_DMA).

Sometimes, the amount of data is very small making it less than optimal allocating a separate buffer for it. If the data to be transferred is 32 bits or less, it can be stored in the transaction struct itself. For transmitted data, use the tx_data member for this and set the SPI_USE_TXDATA flag on the transmission. For received data, use rx_data and set SPI_USE_RXDATA. In both cases, do not touch the tx_buffer or rx_buffer members, because they use the same memory locations as tx_data and rx_data.

应用程序示例

Display graphics on the ILI9341-based 320x240 LCD: peripherals/spi_master.

API 参考手册
SPI_DEVICE_TXBIT_LSBFIRST

Transmit command/address/data LSB first instead of the default MSB first.

SPI_DEVICE_RXBIT_LSBFIRST

Receive data LSB first instead of the default MSB first.

SPI_DEVICE_BIT_LSBFIRST

Transmit and receive LSB first.

SPI_DEVICE_3WIRE

Use MOSI (=spid) for both sending and receiving data.

SPI_DEVICE_POSITIVE_CS

Make CS positive during a transaction instead of negative.

SPI_DEVICE_HALFDUPLEX

Transmit data before receiving it, instead of simultaneously.

SPI_DEVICE_CLK_AS_CS

Output clock on CS line if CS is active.

SPI_TRANS_MODE_DIO

Transmit/receive data in 2-bit mode.

SPI_TRANS_MODE_QIO

Transmit/receive data in 4-bit mode.

SPI_TRANS_MODE_DIOQIO_ADDR

Also transmit address in mode selected by SPI_MODE_DIO/SPI_MODE_QIO.

SPI_TRANS_USE_RXDATA

Receive into rx_data member of spi_transaction_t instead into memory at rx_buffer.

SPI_TRANS_USE_TXDATA

Transmit tx_data member of spi_transaction_t instead of data at tx_buffer. Do not set tx_buffer when using this.

类型定义
typedef struct spi_device_t *spi_device_handle_t

Handle for a device on a SPI bus.

枚举
enum spi_host_device_t

Enum with the three SPI peripherals that are software-accessible in it.

Values:

SPI_HOST =0

SPI1, SPI.

HSPI_HOST =1

SPI2, HSPI.

VSPI_HOST =2

SPI3, VSPI.

结构体
struct spi_transaction_t

This structure describes one SPI transaction

Public Members

uint32_t flags

Bitwise OR of SPI_TRANS_* flags.

uint16_t command

Command data. Specific length was given when device was added to the bus.

uint64_t address

Address. Specific length was given when device was added to the bus.

size_t length

Total data length, in bits.

size_t rxlength

Total data length received, if different from length. (0 defaults this to the value of length)

void *user

User-defined variable. Can be used to store eg transaction ID.

const void *tx_buffer

Pointer to transmit buffer, or NULL for no MOSI phase.

uint8_t tx_data[4]

If SPI_USE_TXDATA is set, data set here is sent directly from this variable.

void *rx_buffer

Pointer to receive buffer, or NULL for no MISO phase.

uint8_t rx_data[4]

If SPI_USE_RXDATA is set, data is received directly to this variable.

struct spi_bus_config_t

This is a configuration structure for a SPI bus.

You can use this structure to specify the GPIO pins of the bus. Normally, the driver will use the GPIO matrix to route the signals. An exception is made when all signals either can be routed through the IO_MUX or are -1. In that case, the IO_MUX is used, allowing for >40MHz speeds.

Public Members

int mosi_io_num

GPIO pin for Master Out Slave In (=spi_d) signal, or -1 if not used.

int miso_io_num

GPIO pin for Master In Slave Out (=spi_q) signal, or -1 if not used.

int sclk_io_num

GPIO pin for Spi CLocK signal, or -1 if not used.

int quadwp_io_num

GPIO pin for WP (Write Protect) signal which is used as D2 in 4-bit communication modes, or -1 if not used.

int quadhd_io_num

GPIO pin for HD (HolD) signal which is used as D3 in 4-bit communication modes, or -1 if not used.

int max_transfer_sz

Maximum transfer size, in bytes. Defaults to 4094 if 0.

struct spi_device_interface_config_t

This is a configuration for a SPI slave device that is connected to one of the SPI buses.

Public Members

uint8_t command_bits

Amount of bits in command phase (0-16)

uint8_t address_bits

Amount of bits in address phase (0-64)

uint8_t dummy_bits

Amount of dummy bits to insert between address and data phase.

uint8_t mode

SPI mode (0-3)

uint8_t duty_cycle_pos

Duty cycle of positive clock, in 1/256th increments (128 = 50%/50% duty). Setting this to 0 (=not setting it) is equivalent to setting this to 128.

uint8_t cs_ena_pretrans

Amount of SPI bit-cycles the cs should be activated before the transmission (0-16). This only works on half-duplex transactions.

uint8_t cs_ena_posttrans

Amount of SPI bit-cycles the cs should stay active after the transmission (0-16)

int clock_speed_hz

Clock speed, in Hz.

int spics_io_num

CS GPIO pin for this device, or -1 if not used.

uint32_t flags

Bitwise OR of SPI_DEVICE_* flags.

int queue_size

Transaction queue size. This sets how many transactions can be ‘in the air’ (queued using spi_device_queue_trans but not yet finished using spi_device_get_trans_result) at the same time.

transaction_cb_t pre_cb

Callback to be called before a transmission is started. This callback is called within interrupt context.

transaction_cb_t post_cb

Callback to be called after a transmission has completed. This callback is called within interrupt context.

函数
esp_err_t spi_bus_initialize(spi_host_device_t host, const spi_bus_config_t *bus_config, int dma_chan)

Initialize a SPI bus.

Warning
For now, only supports HSPI and VSPI.
Return
  • ESP_ERR_INVALID_ARG if configuration is invalid
  • ESP_ERR_INVALID_STATE if host already is in use
  • ESP_ERR_NO_MEM if out of memory
  • ESP_OK on success
Parameters
  • host: SPI peripheral that controls this bus
  • bus_config: Pointer to a spi_bus_config_t struct specifying how the host should be initialized
  • dma_chan: Either channel 1 or 2, or 0 in the case when no DMA is required. Selecting a DMA channel for a SPI bus allows transfers on the bus to have sizes only limited by the amount of internal memory. Selecting no DMA channel (by passing the value 0) limits the amount of bytes transfered to a maximum of 32.

esp_err_t spi_bus_free(spi_host_device_t host)

Free a SPI bus.

Warning
In order for this to succeed, all devices have to be removed first.
Return
  • ESP_ERR_INVALID_ARG if parameter is invalid
  • ESP_ERR_INVALID_STATE if not all devices on the bus are freed
  • ESP_OK on success
Parameters
  • host: SPI peripheral to free

esp_err_t spi_bus_add_device(spi_host_device_t host, spi_device_interface_config_t *dev_config, spi_device_handle_t *handle)

Allocate a device on a SPI bus.

This initializes the internal structures for a device, plus allocates a CS pin on the indicated SPI master peripheral and routes it to the indicated GPIO. All SPI master devices have three CS pins and can thus control up to three devices.

Note
While in general, speeds up to 80MHz on the dedicated SPI pins and 40MHz on GPIO-matrix-routed pins are supported, full-duplex transfers routed over the GPIO matrix only support speeds up to 26MHz.
Return
  • ESP_ERR_INVALID_ARG if parameter is invalid
  • ESP_ERR_NOT_FOUND if host doesn’t have any free CS slots
  • ESP_ERR_NO_MEM if out of memory
  • ESP_OK on success
Parameters
  • host: SPI peripheral to allocate device on
  • dev_config: SPI interface protocol config for the device
  • handle: Pointer to variable to hold the device handle

esp_err_t spi_bus_remove_device(spi_device_handle_t handle)

Remove a device from the SPI bus.

Return
  • ESP_ERR_INVALID_ARG if parameter is invalid
  • ESP_ERR_INVALID_STATE if device already is freed
  • ESP_OK on success
Parameters
  • handle: Device handle to free

esp_err_t spi_device_queue_trans(spi_device_handle_t handle, spi_transaction_t *trans_desc, TickType_t ticks_to_wait)

Queue a SPI transaction for execution.

Return
  • ESP_ERR_INVALID_ARG if parameter is invalid
  • ESP_OK on success
Parameters
  • handle: Device handle obtained using spi_host_add_dev
  • trans_desc: Description of transaction to execute
  • ticks_to_wait: Ticks to wait until there’s room in the queue; use portMAX_DELAY to never time out.

esp_err_t spi_device_get_trans_result(spi_device_handle_t handle, spi_transaction_t **trans_desc, TickType_t ticks_to_wait)

Get the result of a SPI transaction queued earlier.

This routine will wait until a transaction to the given device (queued earlier with spi_device_queue_trans) has succesfully completed. It will then return the description of the completed transaction so software can inspect the result and e.g. free the memory or re-use the buffers.

Return
  • ESP_ERR_INVALID_ARG if parameter is invalid
  • ESP_OK on success
Parameters
  • handle: Device handle obtained using spi_host_add_dev
  • trans_desc: Pointer to variable able to contain a pointer to the description of the transaction that is executed
  • ticks_to_wait: Ticks to wait until there’s a returned item; use portMAX_DELAY to never time out.

esp_err_t spi_device_transmit(spi_device_handle_t handle, spi_transaction_t *trans_desc)

Do a SPI transaction.

Essentially does the same as spi_device_queue_trans followed by spi_device_get_trans_result. Do not use this when there is still a transaction queued that hasn’t been finalized using spi_device_get_trans_result.

Return
  • ESP_ERR_INVALID_ARG if parameter is invalid
  • ESP_OK on success
Parameters
  • handle: Device handle obtained using spi_host_add_dev
  • trans_desc: Pointer to variable able to contain a pointer to the description of the transaction that is executed

SPI Slave driver

概述

The ESP32 has four SPI peripheral devices, called SPI0, SPI1, HSPI and VSPI. SPI0 is entirely dedicated to the flash cache the ESP32 uses to map the SPI flash device it is connected to into memory. SPI1 is connected to the same hardware lines as SPI0 and is used to write to the flash chip. HSPI and VSPI are free to use, and with the spi_slave driver, these can be used as a SPI slave, driven from a connected SPI master.

The spi_slave driver

The spi_slave driver allows using the HSPI and/or VSPI peripheral as a full-duplex SPI slave. It can make use of DMA to send/receive transactions of arbitrary length.

Terminology

The spi_slave driver uses the following terms:

  • Host: The SPI peripheral inside the ESP32 initiating the SPI transmissions. One of HSPI or VSPI.
  • Bus: The SPI bus, common to all SPI devices connected to a master. In general the bus consists of the miso, mosi, sclk and optionally quadwp and quadhd signals. The SPI slaves are connected to these signals in parallel. Each SPI slave is also connected to one CS signal.
    • miso - Also known as q, this is the output of the serial stream from the ESP32 to the SPI master
    • mosi - Also known as d, this is the output of the serial stream from the SPI master to the ESP32
    • sclk - Clock signal. Each data bit is clocked out or in on the positive or negative edge of this signal
    • cs - Chip Select. An active Chip Select delineates a single transaction to/from a slave.
  • Transaction: One instance of CS going active, data transfer from and to a master happening, and CS going inactive again. Transactions are atomic, as in they will never be interrupted by another transaction.
SPI transactions

A full-duplex SPI transaction starts with the master pulling CS low. After this happens, the master starts sending out clock pulses on the CLK line: every clock pulse causes a data bit to be shifted from the master to the slave on the MOSI line and vice versa on the MISO line. At the end of the transaction, the master makes CS high again.

Using the spi_slave driver
  • Initialize a SPI peripheral as a slave by calling spi_slave_initialize. Make sure to set the correct IO pins in the bus_config struct. Take care to set signals that are not needed to -1. A DMA channel (either 1 or 2) must be given if transactions will be larger than 32 bytes, if not the dma_chan parameter may be 0.
  • To set up a transaction, fill one or more spi_transaction_t structure with any transaction parameters you need. Either queue all transactions by calling spi_slave_queue_trans, later quering the result using spi_slave_get_trans_result, or handle all requests synchroneously by feeding them into spi_slave_transmit. The latter two functions will block until the master has initiated and finished a transaction, causing the queued data to be sent and received.
  • Optional: to unload the SPI slave driver, call spi_slave_free.
Transaction data and master/slave length mismatches

Normally, data to be transferred to or from a device will be read from or written to a chunk of memory indicated by the rx_buffer and tx_buffer members of the transaction structure. The SPI driver may decide to use DMA for transfers, so these buffers should be allocated in DMA-capable memory using pvPortMallocCaps(size, MALLOC_CAP_DMA).

The amount of data written to the buffers is limited by the length member of the transaction structure: the driver will never read/write more data than indicated there. The length cannot define the actual length of the SPI transaction; this is determined by the master as it drives the clock and CS lines. In case the length of the transmission is larger than the buffer length, only the start of the transmission will be sent and received. In case the transmission length is shorter than the buffer length, only data up to the length of the buffer will be exchanged.

Warning: Due to a design peculiarity in the ESP32, if the amount of bytes sent by the master or the length of the transmission queues in the slave driver, in bytes, is not both larger than eight and dividable by four, the SPI hardware can fail to write the last one to seven bytes to the receive buffer.

应用程序示例

Slave/master communication: peripherals/spi_slave.

API 参考手册
SPI_SLAVE_TXBIT_LSBFIRST

Transmit command/address/data LSB first instead of the default MSB first.

SPI_SLAVE_RXBIT_LSBFIRST

Receive data LSB first instead of the default MSB first.

SPI_SLAVE_BIT_LSBFIRST

Transmit and receive LSB first.

警告

doxygendefine: Cannot find define “SPI_SLAVE_POSITIVE_CS” in doxygen xml output for project “esp32-idf” from directory: xml/

枚举
enum spi_host_device_t

Enum with the three SPI peripherals that are software-accessible in it.

Values:

SPI_HOST =0

SPI1, SPI.

HSPI_HOST =1

SPI2, HSPI.

VSPI_HOST =2

SPI3, VSPI.

类型定义
结构体
struct spi_slave_transaction_t

This structure describes one SPI transaction

Public Members

size_t length

Total data length, in bits.

const void *tx_buffer

Pointer to transmit buffer, or NULL for no MOSI phase.

void *rx_buffer

Pointer to receive buffer, or NULL for no MISO phase.

void *user

User-defined variable. Can be used to store eg transaction ID.

struct spi_slave_interface_config_t

This is a configuration for a SPI host acting as a slave device.

Public Members

int spics_io_num

CS GPIO pin for this device.

uint32_t flags

Bitwise OR of SPI_SLAVE_* flags.

int queue_size

Transaction queue size. This sets how many transactions can be ‘in the air’ (queued using spi_slave_queue_trans but not yet finished using spi_slave_get_trans_result) at the same time.

uint8_t mode

SPI mode (0-3)

slave_transaction_cb_t post_setup_cb

Callback called after the SPI registers are loaded with new data.

slave_transaction_cb_t post_trans_cb

Callback called after a transaction is done.

struct spi_bus_config_t

This is a configuration structure for a SPI bus.

You can use this structure to specify the GPIO pins of the bus. Normally, the driver will use the GPIO matrix to route the signals. An exception is made when all signals either can be routed through the IO_MUX or are -1. In that case, the IO_MUX is used, allowing for >40MHz speeds.

Public Members

int mosi_io_num

GPIO pin for Master Out Slave In (=spi_d) signal, or -1 if not used.

int miso_io_num

GPIO pin for Master In Slave Out (=spi_q) signal, or -1 if not used.

int sclk_io_num

GPIO pin for Spi CLocK signal, or -1 if not used.

int quadwp_io_num

GPIO pin for WP (Write Protect) signal which is used as D2 in 4-bit communication modes, or -1 if not used.

int quadhd_io_num

GPIO pin for HD (HolD) signal which is used as D3 in 4-bit communication modes, or -1 if not used.

int max_transfer_sz

Maximum transfer size, in bytes. Defaults to 4094 if 0.

Be advised that the slave driver does not use the quadwp/quadhd lines and fields in spi_bus_config_t refering to these lines will be ignored and can thus safely be left uninitialized.

函数
esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *bus_config, const spi_slave_interface_config_t *slave_config, int dma_chan)

Initialize a SPI bus as a slave interface.

Warning
For now, only supports HSPI and VSPI.
Return
  • ESP_ERR_INVALID_ARG if configuration is invalid
  • ESP_ERR_INVALID_STATE if host already is in use
  • ESP_ERR_NO_MEM if out of memory
  • ESP_OK on success
Parameters
  • host: SPI peripheral to use as a SPI slave interface
  • bus_config: Pointer to a spi_bus_config_t struct specifying how the host should be initialized
  • slave_config: Pointer to a spi_slave_interface_config_t struct specifying the details for the slave interface
  • dma_chan: Either 1 or 2. A SPI bus used by this driver must have a DMA channel associated with it. The SPI hardware has two DMA channels to share. This parameter indicates which one to use.

esp_err_t spi_slave_free(spi_host_device_t host)

Free a SPI bus claimed as a SPI slave interface.

Return
  • ESP_ERR_INVALID_ARG if parameter is invalid
  • ESP_ERR_INVALID_STATE if not all devices on the bus are freed
  • ESP_OK on success
Parameters
  • host: SPI peripheral to free

esp_err_t spi_slave_queue_trans(spi_host_device_t host, const spi_slave_transaction_t *trans_desc, TickType_t ticks_to_wait)

Queue a SPI transaction for execution.

Queues a SPI transaction to be executed by this slave device. (The transaction queue size was specified when the slave device was initialised via spi_slave_initialize.) This function may block if the queue is full (depending on the ticks_to_wait parameter). No SPI operation is directly initiated by this function, the next queued transaction will happen when the master initiates a SPI transaction by pulling down CS and sending out clock signals.

This function hands over ownership of the buffers in trans_desc to the SPI slave driver; the application is not to access this memory until spi_slave_queue_trans is called to hand ownership back to the application.

Return
  • ESP_ERR_INVALID_ARG if parameter is invalid
  • ESP_OK on success
Parameters
  • host: SPI peripheral that is acting as a slave
  • trans_desc: Description of transaction to execute. Not const because we may want to write status back into the transaction description.
  • ticks_to_wait: Ticks to wait until there’s room in the queue; use portMAX_DELAY to never time out.

esp_err_t spi_slave_get_trans_result(spi_host_device_t host, spi_slave_transaction_t **trans_desc, TickType_t ticks_to_wait)

Get the result of a SPI transaction queued earlier.

This routine will wait until a transaction to the given device (queued earlier with spi_slave_queue_trans) has succesfully completed. It will then return the description of the completed transaction so software can inspect the result and e.g. free the memory or re-use the buffers.

It is mandatory to eventually use this function for any transaction queued by spi_slave_queue_trans.

Return
  • ESP_ERR_INVALID_ARG if parameter is invalid
  • ESP_OK on success
Parameters
  • host: SPI peripheral to that is acting as a slave
  • trans_desc: Pointer to variable able to contain a pointer to the description of the transaction that is executed
  • ticks_to_wait: Ticks to wait until there’s a returned item; use portMAX_DELAY to never time out.

esp_err_t spi_slave_transmit(spi_host_device_t host, spi_slave_transaction_t *trans_desc, TickType_t ticks_to_wait)

Do a SPI transaction.

Essentially does the same as spi_slave_queue_trans followed by spi_slave_get_trans_result. Do not use this when there is still a transaction queued that hasn’t been finalized using spi_slave_get_trans_result.

Return
  • ESP_ERR_INVALID_ARG if parameter is invalid
  • ESP_OK on success
Parameters
  • host: SPI peripheral to that is acting as a slave
  • trans_desc: Pointer to variable able to contain a pointer to the description of the transaction that is executed. Not const because we may want to write status back into the transaction description.
  • ticks_to_wait: Ticks to wait until there’s a returned item; use portMAX_DELAY to never time out.

RMT

概述

The RMT (Remote Control) module driver can be used to send and receive infrared remote control signals. Due to flexibility of RMT module, the driver can also be used to generate many other types of signals.

应用程序示例

NEC remote control TX and RX example: peripherals/rmt_nec_tx_rx.

API 参考手册
RMT_MEM_BLOCK_BYTE_NUM
RMT_MEM_ITEM_NUM
枚举
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
结构体
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

uint8_t filter_ticks_thresh

RMT filter tick number

uint16_t idle_threshold

RMT RX idle threshold

struct rmt_config_t

Data struct of RMT configure parameters.

Public Members

rmt_mode_t rmt_mode

RMT mode: transmitter or receiver

rmt_channel_t channel

RMT channel

uint8_t clk_div

RMT channel counter divider

gpio_num_t gpio_num

RMT GPIO number

uint8_t mem_block_num

RMT memory block number

rmt_tx_config_t tx_config

RMT TX parameter

rmt_rx_config_t rx_config

RMT RX parameter

函数
esp_err_t rmt_set_clk_div(rmt_channel_t channel, uint8_t div_cnt)

Set RMT clock divider, channel clock is divided from source clock.

Return
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
Parameters
  • channel: RMT channel (0-7)
  • div_cnt: RMT counter clock divider

esp_err_t rmt_get_clk_div(rmt_channel_t channel, uint8_t *div_cnt)

Get RMT clock divider, channel clock is divided from source clock.

Return
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
Parameters
  • channel: RMT channel (0-7)
  • div_cnt: pointer to accept RMT counter divider

esp_err_t rmt_set_rx_idle_thresh(rmt_channel_t channel, uint16_t thresh)

Set RMT RX idle threshold value.

In receive mode, when no edge is detected on the input signal for longer than idle_thres channel clock cycles, the receive process is finished.

Return
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
Parameters
  • channel: RMT channel (0-7)
  • thresh: RMT RX idle threshold

esp_err_t rmt_get_rx_idle_thresh(rmt_channel_t channel, uint16_t *thresh)

Get RMT idle threshold value.

In receive mode, when no edge is detected on the input signal for longer than idle_thres channel clock cycles, the receive process is finished.

Return
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
Parameters
  • channel: RMT channel (0-7)
  • thresh: pointer to accept RMT RX idle threshold value

esp_err_t rmt_set_mem_block_num(rmt_channel_t channel, uint8_t rmt_mem_num)

Set RMT memory block number for RMT channel.

This function is used to configure the amount of memory blocks allocated to channel n The 8 channels share a 512x32-bit RAM block which can be read and written by the processor cores over the APB bus, as well as read by the transmitters and written by the receivers. The RAM address range for channel n is start_addr_CHn to end_addr_CHn, which are defined by: Memory block start address is RMT_CHANNEL_MEM(n) (in soc/rmt_reg.h), that is, start_addr_chn = RMT base address + 0x800 + 64 ∗ 4 ∗ n, and end_addr_chn = RMT base address + 0x800 + 64 ∗ 4 ∗ n + 64 ∗ 4 ∗ RMT_MEM_SIZE_CHn mod 512 ∗ 4

Note
If memory block number of one channel is set to a value greater than 1, this channel will occupy the memory block of the next channel. Channel0 can use at most 8 blocks of memory, accordingly channel7 can only use one memory block.
Return
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
Parameters
  • channel: RMT channel (0-7)
  • rmt_mem_num: RMT RX memory block number, one block has 64 * 32 bits.

esp_err_t rmt_get_mem_block_num(rmt_channel_t channel, uint8_t *rmt_mem_num)

Get RMT memory block number.

Return
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
Parameters
  • channel: RMT channel (0-7)
  • rmt_mem_num: Pointer to accept RMT RX memory block number

esp_err_t rmt_set_tx_carrier(rmt_channel_t channel, bool carrier_en, uint16_t high_level, uint16_t low_level, rmt_carrier_level_t carrier_level)

Configure RMT carrier for TX signal.

Set different values for carrier_high and carrier_low to set different frequency of carrier. The unit of carrier_high/low is the source clock tick, not the divided channel counter clock.

Return
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
Parameters
  • channel: RMT channel (0-7)
  • carrier_en: Whether to enable output carrier.
  • high_level: High level duration of carrier
  • low_level: Low level duration of carrier.
  • carrier_level: Configure the way carrier wave is modulated for channel0-7.
                     1'b1:transmit on low output level
    
                     1'b0:transmit on high output level
    

esp_err_t rmt_set_mem_pd(rmt_channel_t channel, bool pd_en)

Set RMT memory in low power mode.

Reduce power consumed by memory. 1:memory is in low power state.

Return
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
Parameters
  • channel: RMT channel (0-7)
  • pd_en: RMT memory low power enable.

esp_err_t rmt_get_mem_pd(rmt_channel_t channel, bool *pd_en)

Get RMT memory low power mode.

Return
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
Parameters
  • channel: RMT channel (0-7)
  • pd_en: Pointer to accept RMT memory low power mode.

esp_err_t rmt_tx_start(rmt_channel_t channel, bool tx_idx_rst)

Set RMT start sending data from memory.

Return
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
Parameters
  • channel: RMT channel (0-7)
  • tx_idx_rst: Set true to reset memory index for TX. Otherwise, transmitter will continue sending from the last index in memory.

esp_err_t rmt_tx_stop(rmt_channel_t channel)

Set RMT stop sending.

Return
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
Parameters
  • channel: RMT channel (0-7)

esp_err_t rmt_rx_start(rmt_channel_t channel, bool rx_idx_rst)

Set RMT start receiving data.

Return
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
Parameters
  • channel: RMT channel (0-7)
  • rx_idx_rst: Set true to reset memory index for receiver. Otherwise, receiver will continue receiving data to the last index in memory.

esp_err_t rmt_rx_stop(rmt_channel_t channel)

Set RMT stop receiving data.

Return
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
Parameters
  • channel: RMT channel (0-7)

esp_err_t rmt_memory_rw_rst(rmt_channel_t channel)

Reset RMT TX/RX memory index.

Return
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
Parameters
  • channel: RMT channel (0-7)

esp_err_t rmt_set_memory_owner(rmt_channel_t channel, rmt_mem_owner_t owner)

Set RMT memory owner.

Return
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
Parameters
  • channel: RMT channel (0-7)
  • owner: To set when the transmitter or receiver can process the memory of channel.

esp_err_t rmt_get_memory_owner(rmt_channel_t channel, rmt_mem_owner_t *owner)

Get RMT memory owner.

Return
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
Parameters
  • channel: RMT channel (0-7)
  • owner: Pointer to get memory owner.

esp_err_t rmt_set_tx_loop_mode(rmt_channel_t channel, bool loop_en)

Set RMT tx loop mode.

Return
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
Parameters
  • channel: RMT channel (0-7)
  • loop_en: To enable RMT transmitter loop sending mode.
               If set true, transmitter will continue sending from the first data
               to the last data in channel0-7 again and again.
    

esp_err_t rmt_get_tx_loop_mode(rmt_channel_t channel, bool *loop_en)

Get RMT tx loop mode.

Return
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
Parameters
  • channel: RMT channel (0-7)
  • loop_en: Pointer to accept RMT transmitter loop sending mode.

esp_err_t rmt_set_rx_filter(rmt_channel_t channel, bool rx_filter_en, uint8_t thresh)

Set RMT RX filter.

In receive mode, channel0-7 will ignore input pulse when the pulse width is smaller than threshold. Counted in source clock, not divided counter clock.

Return
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
Parameters
  • channel: RMT channel (0-7)
  • rx_filter_en: To enable RMT receiver filter.
  • thresh: Threshold of pulse width for receiver.

esp_err_t rmt_set_source_clk(rmt_channel_t channel, rmt_source_clk_t base_clk)

Set RMT source clock.

RMT module has two source clock:

  1. APB clock which is 80Mhz
  2. REF tick clock, which would be 1Mhz( not supported in this version).

Return
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
Parameters
  • channel: RMT channel (0-7)
  • base_clk: To choose source clock for RMT module.

esp_err_t rmt_get_source_clk(rmt_channel_t channel, rmt_source_clk_t *src_clk)

Get RMT source clock.

RMT module has two source clock:

  1. APB clock which is 80Mhz
  2. REF tick clock, which would be 1Mhz( not supported in this version).

Return
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
Parameters
  • channel: RMT channel (0-7)
  • src_clk: Pointer to accept source clock for RMT module.

esp_err_t rmt_set_idle_level(rmt_channel_t channel, bool idle_out_en, rmt_idle_level_t level)

Set RMT idle output level for transmitter.

Return
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
Parameters
  • channel: RMT channel (0-7)
  • idle_out_en: To enable idle level output.
  • level: To set the output signal’s level for channel0-7 in idle state.

esp_err_t rmt_get_status(rmt_channel_t channel, uint32_t *status)

Get RMT status.

Return
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
Parameters
  • channel: RMT channel (0-7)
  • status: Pointer to accept channel status.

void rmt_set_intr_enable_mask(uint32_t mask)

Set mask value to RMT interrupt enable register.

Parameters
  • mask: Bit mask to set to the register

void rmt_clr_intr_enable_mask(uint32_t mask)

Clear mask value to RMT interrupt enable register.

Parameters
  • mask: Bit mask to clear the register

esp_err_t rmt_set_rx_intr_en(rmt_channel_t channel, bool en)

Set RMT RX interrupt enable.

Return
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
Parameters
  • channel: RMT channel (0 - 7)
  • en: enable or disable RX interrupt.

esp_err_t rmt_set_err_intr_en(rmt_channel_t channel, bool en)

Set RMT RX error interrupt enable.

Return
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
Parameters
  • channel: RMT channel (0 - 7)
  • en: enable or disable RX err interrupt.

esp_err_t rmt_set_tx_intr_en(rmt_channel_t channel, bool en)

Set RMT TX interrupt enable.

Return
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
Parameters
  • channel: RMT channel (0 - 7)
  • en: enable or disable TX interrupt.

警告

doxygenfunction: Cannot find function “rmt_set_evt_intr_en” in doxygen xml output for project “esp32-idf” from directory: xml/

esp_err_t rmt_set_pin(rmt_channel_t channel, rmt_mode_t mode, gpio_num_t gpio_num)

Set RMT pins.

Return
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
Parameters
  • channel: RMT channel (0 - 7)
  • mode: TX or RX mode for RMT
  • gpio_num: GPIO number to transmit or receive the signal.

esp_err_t rmt_config(const rmt_config_t *rmt_param)

Configure RMT parameters.

Return
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
Parameters
  • rmt_param: RMT parameter structor

esp_err_t rmt_isr_register(void (*fn)(void *), void *arg, int intr_alloc_flags, rmt_isr_handle_t *handle, )

register RMT interrupt handler, the handler is an ISR.

The handler will be attached to the same CPU core that this function is running on.

Note
If you already called rmt_driver_install to use system RMT driver, please do not register ISR handler again.
Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Function pointer error.
  • ESP_FAIL System driver installed, can not register ISR handler for RMT
Parameters
  • 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: If non-zero, a handle to later clean up the ISR gets stored here.

esp_err_t rmt_fill_tx_items(rmt_channel_t channel, const rmt_item32_t *item, uint16_t item_num, uint16_t mem_offset)

Fill memory data of channel with given RMT items.

Return
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
Parameters
  • channel: RMT channel (0 - 7)
  • item: Pointer of items.
  • item_num: RMT sending items number.
  • mem_offset: Index offset of memory.

esp_err_t rmt_driver_install(rmt_channel_t channel, size_t rx_buf_size, int intr_alloc_flags)

Initialize RMT driver.

Return
  • ESP_ERR_INVALID_STATE Driver is already installed, call rmt_driver_uninstall first.
  • ESP_ERR_NO_MEM Memory allocation failure
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
Parameters
  • channel: RMT channel (0 - 7)
  • rx_buf_size: Size of RMT RX ringbuffer. Can be 0 if the RX ringbuffer is not used.
  • intr_alloc_flags: Flags for the RMT driver interrupt handler. Pass 0 for default flags. See esp_intr_alloc.h for details.

esp_err_t rmt_driver_uninstall(rmt_channel_t channel)

Uninstall RMT driver.

Return
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
Parameters
  • channel: RMT channel (0 - 7)

esp_err_t rmt_write_items(rmt_channel_t channel, const rmt_item32_t *rmt_item, int item_num, bool wait_tx_done)

RMT send waveform from rmt_item array.

This API allows user to send waveform with any length.

Return
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
Parameters
  • channel: RMT channel (0 - 7)
  • rmt_item: head point of RMT items array.
  • item_num: RMT data item number.
  • wait_tx_done: If set 1, it will block the task and wait for sending done.
                    If set 0, it will not wait and return immediately.
    
                    @note
                    This function will not copy data, instead, it will point to the original items,
                    and send the waveform items.
                    If wait_tx_done is set to true, this function will block and will not return until
                    all items have been sent out.
                    If wait_tx_done is set to false, this function will return immediately, and the driver
                    interrupt will continue sending the items. We must make sure the item data will not be
                    damaged when the driver is still sending items in driver interrupt.
    

esp_err_t rmt_wait_tx_done(rmt_channel_t channel)

Wait RMT TX finished.

Return
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
Parameters
  • channel: RMT channel (0 - 7)

esp_err_t rmt_get_ringbuf_handler(rmt_channel_t channel, RingbufHandle_t *buf_handler)

Get ringbuffer from UART.

Users can get the RMT RX ringbuffer handler, and process the RX data.

Return
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_OK Success
Parameters
  • channel: RMT channel (0 - 7)
  • buf_handler: Pointer to buffer handler to accept RX ringbuffer handler.

TIMER

概述

ESP32 chip contains two hardware timer groups, each containing two general-purpose hardware timers.

They are all 64-bit generic timers based on 16-bit prescalers and 64-bit auto-reload-capable up/down counters.

应用程序示例

64-bit hardware timer example: peripherals/timer_group.

API 参考手册
TIMER_BASE_CLK
类型定义
枚举
enum timer_group_t

Selects a Timer-Group out of 2 available groups.

Values:

TIMER_GROUP_0 = 0

Hw timer group 0

TIMER_GROUP_1 = 1

Hw timer group 1

TIMER_GROUP_MAX
enum timer_idx_t

Select a hardware timer from timer groups.

Values:

TIMER_0 = 0

Select timer0 of GROUPx

TIMER_1 = 1

Select timer1 of GROUPx

TIMER_MAX
enum timer_count_dir_t

Decides the direction of counter.

Values:

TIMER_COUNT_DOWN = 0

Descending Count from cnt.high|cnt.low

TIMER_COUNT_UP = 1

Ascending Count from Zero

TIMER_COUNT_MAX
enum timer_start_t

Decides whether timer is on or paused.

Values:

TIMER_PAUSE = 0

Pause timer counter

TIMER_START = 1

Start timer counter

enum timer_alarm_t

Decides whether to enable alarm mode.

Values:

TIMER_ALARM_DIS = 0

Disable timer alarm

TIMER_ALARM_EN = 1

Enable timer alarm

TIMER_ALARM_MAX
enum timer_intr_mode_t

Select interrupt type if running in alarm mode.

Values:

TIMER_INTR_LEVEL = 0

Interrupt mode: level mode

TIMER_INTR_MAX
enum timer_autoreload_t

Select if Alarm needs to be loaded by software or automatically reload by hardware.

Values:

TIMER_AUTORELOAD_DIS = 0

Disable auto-reload: hardware will not load counter value after an alarm event

TIMER_AUTORELOAD_EN = 1

Enable auto-reload: hardware will load counter value after an alarm event

TIMER_AUTORELOAD_MAX
结构体
struct timer_config_t

timer configure struct

Public Members

bool alarm_en

Timer alarm enable

bool counter_en

Counter enable

timer_intr_mode_t intr_type

Interrupt mode

timer_count_dir_t counter_dir

Counter direction

bool auto_reload

Timer auto-reload

uint16_t divider

Counter clock divider

函数
esp_err_t timer_get_counter_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t *timer_val)

Read the counter value of hardware timer.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • group_num: Timer group, 0 for TIMERG0 or 1 for TIMERG1
  • timer_num: Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
  • timer_val: Pointer to accept timer counter value.

esp_err_t timer_get_counter_time_sec(timer_group_t group_num, timer_idx_t timer_num, double *time)

Read the counter value of hardware timer, in unit of a given scale.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • group_num: Timer group, 0 for TIMERG0 or 1 for TIMERG1
  • timer_num: Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
  • time: Pointer, type of double*, to accept timer counter value, in seconds.

esp_err_t timer_set_counter_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t load_val)

Set counter value to hardware timer.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • group_num: Timer group, 0 for TIMERG0 or 1 for TIMERG1
  • timer_num: Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
  • load_val: Counter value to write to the hardware timer.

esp_err_t timer_start(timer_group_t group_num, timer_idx_t timer_num)

Start the counter of hardware timer.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • group_num: Timer group number, 0 for TIMERG0 or 1 for TIMERG1
  • timer_num: Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]

esp_err_t timer_pause(timer_group_t group_num, timer_idx_t timer_num)

Pause the counter of hardware timer.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • group_num: Timer group number, 0 for TIMERG0 or 1 for TIMERG1
  • timer_num: Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]

esp_err_t timer_set_counter_mode(timer_group_t group_num, timer_idx_t timer_num, timer_count_dir_t counter_dir)

Set counting mode for hardware timer.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • group_num: Timer group number, 0 for TIMERG0 or 1 for TIMERG1
  • timer_num: Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
  • counter_dir: Counting direction of timer, count-up or count-down

esp_err_t timer_set_auto_reload(timer_group_t group_num, timer_idx_t timer_num, timer_autoreload_t reload)

Enable or disable counter reload function when alarm event occurs.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • group_num: Timer group number, 0 for TIMERG0 or 1 for TIMERG1
  • timer_num: Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
  • reload: Counter reload mode.

esp_err_t timer_set_divider(timer_group_t group_num, timer_idx_t timer_num, uint16_t divider)

Set hardware timer source clock divider. Timer groups clock are divider from APB clock.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • group_num: Timer group number, 0 for TIMERG0 or 1 for TIMERG1
  • timer_num: Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
  • divider: Timer clock divider value.

esp_err_t timer_set_alarm_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t alarm_value)

Set timer alarm value.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • group_num: Timer group, 0 for TIMERG0 or 1 for TIMERG1
  • timer_num: Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
  • alarm_value: A 64-bit value to set the alarm value.

esp_err_t timer_get_alarm_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t *alarm_value)

Get timer alarm value.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • group_num: Timer group, 0 for TIMERG0 or 1 for TIMERG1
  • timer_num: Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
  • alarm_value: Pointer of A 64-bit value to accept the alarm value.

esp_err_t timer_set_alarm(timer_group_t group_num, timer_idx_t timer_num, timer_alarm_t alarm_en)

Get timer alarm value.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • group_num: Timer group, 0 for TIMERG0 or 1 for TIMERG1
  • timer_num: Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
  • alarm_en: To enable or disable timer alarm function.

esp_err_t timer_isr_register(timer_group_t group_num, timer_idx_t timer_num, void (*fn)(void *), void *arg, int intr_alloc_flags, timer_isr_handle_t *handle, )

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

Note
In case the this is called with the INIRAM flag, code inside the handler function can only call functions in IRAM, so it cannot call other timer APIs. Use direct register access to access timers from inside the ISR in this case.
Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Function pointer error.
Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • group_num: Timer group number
  • timer_num: Timer index of timer group
  • fn: Interrupt handler function.
Parameters
  • 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 timer_init(timer_group_t group_num, timer_idx_t timer_num, const timer_config_t *config)

Initializes and configure the timer.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • group_num: Timer group number, 0 for TIMERG0 or 1 for TIMERG1
  • timer_num: Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
  • config: Pointer to timer initialization parameters.

esp_err_t timer_get_config(timer_group_t group_num, timer_idx_t timer_num, timer_config_t *config)

Get timer configure value.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • group_num: Timer group number, 0 for TIMERG0 or 1 for TIMERG1
  • timer_num: Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
  • config: Pointer of struct to accept timer parameters.

esp_err_t timer_group_intr_enable(timer_group_t group_num, uint32_t en_mask)

Enable timer group interrupt, by enable mask.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • group_num: Timer group number, 0 for TIMERG0 or 1 for TIMERG1
  • en_mask: Timer interrupt enable mask. Use TIMG_T0_INT_ENA_M to enable t0 interrupt Use TIMG_T1_INT_ENA_M to enable t1 interrupt

esp_err_t timer_group_intr_disable(timer_group_t group_num, uint32_t disable_mask)

Disable timer group interrupt, by disable mask.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • group_num: Timer group number, 0 for TIMERG0 or 1 for TIMERG1
  • disable_mask: Timer interrupt disable mask. Use TIMG_T0_INT_ENA_M to disable t0 interrupt Use TIMG_T1_INT_ENA_M to disable t1 interrupt

esp_err_t timer_enable_intr(timer_group_t group_num, timer_idx_t timer_num)

Enable timer interrupt.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • group_num: Timer group number, 0 for TIMERG0 or 1 for TIMERG1
  • timer_num: Timer index.

esp_err_t timer_disable_intr(timer_group_t group_num, timer_idx_t timer_num)

Disable timer interrupt.

Return
  • ESP_OK Success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • group_num: Timer group number, 0 for TIMERG0 or 1 for TIMERG1
  • timer_num: Timer index.

UART

应用程序示例

Configure uart settings and install uart driver to read/write using UART0 and UART1 interfaces: peripherals/uart.

API 参考手册
Data 结构体
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

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

枚举
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

函数
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.

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. Do not set ESP_INTR_FLAG_IRAM here (the driver’s ISR handler is not located in IRAM)

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.

关于本节 API 的示例代码请参考 ESP-IDF 示例中的 peripherals 目录。

系统 API

内存(Memory)分配

提示

译注:本节以及后面 深度睡眠 一节中的 Memory 都翻译为内存的,但是实际情况可能是指的存储器,其中细节请自己体会。

概述

ESP32 有多种 RAM。本质上,它包含 IRAM、DRAM 和可以同时用于这两者的 RAM。此外,还可以将外部 SPI flash 连接到 ESP32;可以使用 flash cache 将它的内存集成到 ESP32 的内存映射中。

为了利用这些所有的内存,esp-idf 包含了一个内存分配器。基本上,如果你想要内存具有某一属性(例如,DMA-capable、被某个特定的 PID 访问、或者执行代码的能力),你可以创建一个所需功能 OR 掩码并将它传递给 pvPortMallocCaps。例如,内部分配内存的常规 malloc 代码使用 `pvPortMallocCaps(size, MALLOC_CAP_8BIT)`,这样就可以以字节为单位获取内存数据。

因为 malloc 也是使用的这个分配系统,所以使用 pvPortMallocCaps 分配的内存也可以通过调用标准函数 `free()` 进行释放。

本质上,这个分配器被分为两部分。FreeRTOS 目录中的分配器可以从标记的(tagged)区域分配内存:一个标记(tag)是一个整数值,空闲内存的每个区域都有一个标记。esp32 相关的代码使用一些特殊的标记来初始化这些区域,并且包含一些逻辑,这些逻辑可以根据用户所给的功能选择对应功能的标记。尽管这些 API 是公共的,但是还这些标记只能用于这两部分直接通信,而不能直接使用。

Special Uses

如果某个内存结构只能以 32 比特为单位进行访问(例如整数数组或指针数组),则在分配是可以使用 MALLOC_CAP_32BIT 标志。这允许分配器分发 IRAM 内存;一些在常规 malloc() 中不能做的事儿会被调用。这样有助于是哟个 ESP32 中的所有有效内存。

API 参考手册
MALLOC_CAP_EXEC

Flags to indicate the capabilities of the various memory systems.

Memory must be able to run executable code

MALLOC_CAP_32BIT

Memory must allow for aligned 32-bit data accesses.

MALLOC_CAP_8BIT

Memory must allow for 8/16/...-bit data accesses.

MALLOC_CAP_DMA

Memory must be able to accessed by DMA.

MALLOC_CAP_PID2

Memory must be mapped to PID2 memory space.

MALLOC_CAP_PID3

Memory must be mapped to PID3 memory space.

MALLOC_CAP_PID4

Memory must be mapped to PID4 memory space.

MALLOC_CAP_PID5

Memory must be mapped to PID5 memory space.

MALLOC_CAP_PID6

Memory must be mapped to PID6 memory space.

MALLOC_CAP_PID7

Memory must be mapped to PID7 memory space.

MALLOC_CAP_SPISRAM

Memory must be in SPI SRAM.

MALLOC_CAP_INVALID

Memory can’t be used / list end marker.

类型定义
typedef struct HeapRegionTagged HeapRegionTagged_t

Structure to define a memory region.

函数
void heap_alloc_caps_init()

Initialize the capability-aware heap allocator.

For the ESP32, this is called once in the startup code.

void *pvPortMallocCaps(size_t xWantedSize, uint32_t caps)

Allocate a chunk of memory which has the given capabilities.

Return
A pointer to the memory allocated on success, NULL on failure
Parameters
  • xWantedSize: Size, in bytes, of the amount of memory to allocate
  • caps: Bitwise OR of MALLOC_CAP_* flags indicating the type of memory to be returned

size_t xPortGetFreeHeapSizeCaps(uint32_t caps)

Get the total free size of all the regions that have the given capabilities.

This function takes all regions capable of having the given capabilities allocated in them and adds up the free space they have.

Return
Amount of free bytes in the regions
Parameters
  • caps: Bitwise OR of MALLOC_CAP_* flags indicating the type of memory

size_t xPortGetMinimumEverFreeHeapSizeCaps(uint32_t caps)

Get the total minimum free memory of all regions with the given capabilities.

This adds all the lowmarks of the regions capable of delivering the memory with the given capabilities

Return
Amount of free bytes in the regions
Parameters
  • caps: Bitwise OR of MALLOC_CAP_* flags indicating the type of memory

void vPortDefineHeapRegionsTagged(const HeapRegionTagged_t *const pxHeapRegions)

Initialize the heap allocator by feeding it the usable memory regions and their tags.

This takes an array of heapRegionTagged_t structs, the last entry of which is a dummy entry which has pucStartAddress set to NULL. It will initialize the heap allocator to serve memory from these ranges.

Parameters
  • pxHeapRegions: Array of region definitions

void *pvPortMallocTagged(size_t xWantedSize, BaseType_t tag)

Allocate memory from a region with a certain tag.

Like pvPortMalloc, this returns an allocated chunk of memory. This function, however, forces the allocator to allocate from a region specified by a specific tag.

Return
Pointer to allocated memory if succesful. NULL if unsuccesful.
Parameters
  • xWantedSize: Size needed, in bytes
  • tag: Tag of the memory region the allocation has to be from

void vPortFreeTagged(void *pv)

Free memory allocated with pvPortMallocTagged.

This is basically an implementation of free().

Parameters
  • pv: Pointer to region allocated by pvPortMallocTagged

size_t xPortGetMinimumEverFreeHeapSizeTagged(BaseType_t tag)

Get the lowest amount of memory free for a certain tag.

This function allows the user to see what the least amount of free memory for a certain tag is.

Return
Minimum amount of free bytes available in the runtime of the program
Parameters
  • tag: Tag of the memory region

size_t xPortGetFreeHeapSizeTagged(BaseType_t tag)

Get the amount of free bytes in a certain tagged region.

Works like xPortGetFreeHeapSize but allows the user to specify a specific tag

Return
Remaining amount of free bytes in region
Parameters
  • tag: Tag of the memory region

中断分配

概述

ESP32 有两个核(core),每个核有 32 个中断。每个中断有一个确定的优先级,大多数(而非全部)中断被连接到中断复用矩阵中。由于中断源的数量大于中断的数量,因此在必要时可以在多个驱动程序中共享同一个中断。ESP-IDF 中提供了一个 esp_intr_alloc 抽象,它的作用就是隐藏这些实现细节。

驱动程序可以调用 esp_intr_alloc(或 esp_intr_alloc_sintrstatus)为某个外设分配一个中断。它可以通过一个传递给该函数的标志设置所分配中断的类型,指明指定的等级或者触发方法。然后中断分配代码会知道一个可用的中断,使用中断复用矩阵将它与外设挂在一起,并安装驱动程序传递给它的中断 hander 和 ISR。

该代码有两种处理方式不同的中断:共享中断和非共享中断。二者中最简单的是非共享中断:一个独立的中断会在调用 esp_intr_alloc 时被分配,且该中断仅能用于附着到它上面的外设,仅由一个 ISR 会被调用。共享中断可以被多个外设触发,当附着到它上面的某一个外设发送中断信号时,多个 ISR 都会被调用。因此,共享中断的 ISR 应当检查它们所服务的外设的中断状态,以查看是否需要执行任何动作。

非共享中断即可以由电平触发,也可以是边沿触发。共享中断仅能被电平触发(因为使用边沿触发时可能错过中断)。(它内部的逻辑是这样的:设备 A 和设备 B 共享一个中断。设备 B 发出一个中断信号。中断线为高。ISR handler 调用设备 A 的代码 -> 什么也不做。ISR handler 调用设备 B 的代码,但是在此期间,设备 A 发送了一个信号。设备 B 完成处理,清除设备 B 的中断,退出中断代码。现在,设备 A 的中断处于 pending 状态,但是由于中断线没有变为低(即使设备 B 的中断被清除了,设备 A 仍然保持为高),中断永远不会被服务)

多核问题

可以产生中断的外设可以被分为两类:

  • 外部外设,在 ESP32 上面但是在 Xtensa 核外面。大多数 ESP32 外设都是这种类型。
  • 内部外设,属于 Xtensa CPU 核自身的设备。

这两种外设的中断处理有一点点区别。

内部外设中断

每个 Xtensa CPU 核都有六个内部外设:

  • 三个 timer 比较器(comparator)
  • 一个性能监视器(monitor)
  • 两个软件中断

内部中断源在 esp_intr_alloc.h 中定义为 ETS_INTERNAL_*_INTR_SOURCE

这些外设只能由它们所关联的核进行配置。当产生中断时,中断是通过硬连线(hard-wire)连接到它所关联的核;一个核中的中断源(例如内部 timer 比较器)不能在另一个核中产生中断。这就是为什么只能被运行在该核上面的某个任务管理。内部中断源仍然是使用 esp_intr_alloc 进行分配的,但是它们不能进行共享,且总是具有一个固定的中断等级。

外部外设中断

剩下的中断源来自外部设备,它们在 soc/soc.h 中定义为 ETS_*_INTR_SOURCE

两个 CPU 核的非内部中断槽被连接到一个中断复用器上面。中断复用器可以将任何外部中断源引导到它上面的任意中断槽。

  • 分配外部中断时总是会将它分配到对它进行分配的那个核上面。
  • 释放外部中断时必须发送在它所分配的同一个核上面。
  • 可以从另一个核使能/禁止外部中断。
  • 多个外部中断源可以通过将 ESP_INTR_FLAG_SHARED 作为标志参数传递给 esp_intr_alloc() 来共享一个中断槽。

从某个没有固定到一个具体核的任务中调用 esp_intr_alloc() 将不会有效果。在任务切换期时,这些任务可能会在两个核之间迁移。因此,它不能辨别中断被分配到哪个 CPU 上了,从而导致很难释放中断处理,且可能让调试变得更加困难。建议在创建需要分配中断的任务时,使用 xTaskCreatePinnedToCore() 函数,且指定一个参数 CoreID。在内部中断源的时候,这也是需要的。

IRAM-Safe 中断 Handler

使用 ESP_INTR_FLAG_IRAM 标志注册的中断 handler 将移植在 IRAM 中运行(从 DRAM 中读取它的所有数据),因此不需要在 flash

这对于那些需要保证最小执行延迟的中断来说是非常有用的,因为 falsh 的写和擦除操作可能比较慢(擦除可能哟啊花几十或几百微秒才能完成)。

如果中断 handler 的调用非常频繁,可以将它放到 IRAM 中,从而避免 flash cache 的遗漏。

更多细节请cake SPI flash API 文档

应用程序示例
API 参考手册
ESP_INTR_FLAG_LEVEL1

Interrupt allocation flags.

These flags can be used to specify which interrupt qualities the code calling esp_intr_alloc* needs.Accept a Level 1 interrupt vector

ESP_INTR_FLAG_LEVEL2

Accept a Level 2 interrupt vector.

ESP_INTR_FLAG_LEVEL3

Accept a Level 3 interrupt vector.

ESP_INTR_FLAG_LEVEL4

Accept a Level 4 interrupt vector.

ESP_INTR_FLAG_LEVEL5

Accept a Level 5 interrupt vector.

ESP_INTR_FLAG_LEVEL6

Accept a Level 6 interrupt vector.

ESP_INTR_FLAG_NMI

Accept a Level 7 interrupt vector.

ESP_INTR_FLAG_LOWMED

Low and medium prio interrupts. These can be handled in C.

ESP_INTR_FLAG_HIGH

High level interrupts. Need to be handled in assembly.

ESP_INTR_FLAG_SHARED

Interrupt can be shared between ISRs.

ESP_INTR_FLAG_EDGE

Edge-triggered interrupt.

ESP_INTR_FLAG_IRAM

ISR can be called if cache is disabled.

ESP_INTR_FLAG_INTRDISABLED

Return with this interrupt disabled.

函数
esp_err_t esp_intr_mark_shared(int intno, int cpu, bool is_in_iram)

Mark an interrupt as a shared interrupt.

This will mark a certain interrupt on the specified CPU as an interrupt that can be used to hook shared interrupt handlers to.

Return
ESP_ERR_INVALID_ARG if cpu or intno is invalid ESP_OK otherwise
Parameters
  • intno: The number of the interrupt (0-31)
  • cpu: CPU on which the interrupt should be marked as shared (0 or 1)
  • is_in_iram: Shared interrupt is for handlers that reside in IRAM and the int can be left enabled while the flash cache is disabled.

esp_err_t esp_intr_reserve(int intno, int cpu)

Reserve an interrupt to be used outside of this framewoek.

This will mark a certain interrupt on the specified CPU as reserved, not to be allocated for any reason.

Return
ESP_ERR_INVALID_ARG if cpu or intno is invalid ESP_OK otherwise
Parameters
  • intno: The number of the interrupt (0-31)
  • cpu: CPU on which the interrupt should be marked as shared (0 or 1)

esp_err_t esp_intr_alloc(int source, int flags, intr_handler_t handler, void *arg, intr_handle_t *ret_handle)

Allocate an interrupt with the given parameters.

This finds an interrupt that matches the restrictions as given in the flags parameter, maps the given interrupt source to it and hooks up the given interrupt handler (with optional argument) as well. If needed, it can return a handle for the interrupt as well.

The interrupt will always be allocated on the core that runs this function.

If ESP_INTR_FLAG_IRAM flag is used, and handler address is not in IRAM or RTC_FAST_MEM, then ESP_ERR_INVALID_ARG is returned.

Return
ESP_ERR_INVALID_ARG if the combination of arguments is invalid. ESP_ERR_NOT_FOUND No free interrupt found with the specified flags ESP_OK otherwise
Parameters
  • source: The interrupt source. One of the ETS_*_INTR_SOURCE interrupt mux sources, as defined in soc/soc.h, or one of the internal ETS_INTERNAL_*_INTR_SOURCE sources as defined in this header.
  • flags: An ORred mask of the ESP_INTR_FLAG_* defines. These restrict the choice of interrupts that this routine can choose from. If this value is 0, it will default to allocating a non-shared interrupt of level 1, 2 or 3. If this is ESP_INTR_FLAG_SHARED, it will allocate a shared interrupt of level 1. Setting ESP_INTR_FLAG_INTRDISABLED will return from this function with the interrupt disabled.
  • handler: The interrupt handler. Must be NULL when an interrupt of level >3 is requested, because these types of interrupts aren’t C-callable.
  • arg: Optional argument for passed to the interrupt handler
  • ret_handle: Pointer to an intr_handle_t to store a handle that can later be used to request details or free the interrupt. Can be NULL if no handle is required.

esp_err_t esp_intr_alloc_intrstatus(int source, int flags, uint32_t intrstatusreg, uint32_t intrstatusmask, intr_handler_t handler, void *arg, intr_handle_t *ret_handle)

Allocate an interrupt with the given parameters.

This essentially does the same as esp_intr_alloc, but allows specifying a register and mask combo. For shared interrupts, the handler is only called if a read from the specified register, ANDed with the mask, returns non-zero. By passing an interrupt status register address and a fitting mask, this can be used to accelerate interrupt handling in the case a shared interrupt is triggered; by checking the interrupt statuses first, the code can decide which ISRs can be skipped

Return
ESP_ERR_INVALID_ARG if the combination of arguments is invalid. ESP_ERR_NOT_FOUND No free interrupt found with the specified flags ESP_OK otherwise
Parameters
  • source: The interrupt source. One of the ETS_*_INTR_SOURCE interrupt mux sources, as defined in soc/soc.h, or one of the internal ETS_INTERNAL_*_INTR_SOURCE sources as defined in this header.
  • flags: An ORred mask of the ESP_INTR_FLAG_* defines. These restrict the choice of interrupts that this routine can choose from. If this value is 0, it will default to allocating a non-shared interrupt of level 1, 2 or 3. If this is ESP_INTR_FLAG_SHARED, it will allocate a shared interrupt of level 1. Setting ESP_INTR_FLAG_INTRDISABLED will return from this function with the interrupt disabled.
  • intrstatusreg: The address of an interrupt status register
  • intrstatusmask: A mask. If a read of address intrstatusreg has any of the bits that are 1 in the mask set, the ISR will be called. If not, it will be skipped.
  • handler: The interrupt handler. Must be NULL when an interrupt of level >3 is requested, because these types of interrupts aren’t C-callable.
  • arg: Optional argument for passed to the interrupt handler
  • ret_handle: Pointer to an intr_handle_t to store a handle that can later be used to request details or free the interrupt. Can be NULL if no handle is required.

esp_err_t esp_intr_free(intr_handle_t handle)

Disable and free an interrupt.

Use an interrupt handle to disable the interrupt and release the resources associated with it.

Return
ESP_ERR_INVALID_ARG if handle is invalid, or esp_intr_free runs on another core than where the interrupt is allocated on. ESP_OK otherwise
Parameters
  • handle: The handle, as obtained by esp_intr_alloc or esp_intr_alloc_intrstatus

int esp_intr_get_cpu(intr_handle_t handle)

Get CPU number an interrupt is tied to.

Return
The core number where the interrupt is allocated
Parameters
  • handle: The handle, as obtained by esp_intr_alloc or esp_intr_alloc_intrstatus

int esp_intr_get_intno(intr_handle_t handle)

Get the allocated interrupt for a certain handle.

Return
The interrupt number
Parameters
  • handle: The handle, as obtained by esp_intr_alloc or esp_intr_alloc_intrstatus

esp_err_t esp_intr_disable(intr_handle_t handle)

Disable the interrupt associated with the handle.

Note
For local interrupts (ESP_INTERNAL_* sources), this function has to be called on the CPU the interrupt is allocated on. Other interrupts have no such restriction.
Return
ESP_ERR_INVALID_ARG if the combination of arguments is invalid. ESP_OK otherwise
Parameters
  • handle: The handle, as obtained by esp_intr_alloc or esp_intr_alloc_intrstatus

esp_err_t esp_intr_enable(intr_handle_t handle)

Ensable the interrupt associated with the handle.

Note
For local interrupts (ESP_INTERNAL_* sources), this function has to be called on the CPU the interrupt is allocated on. Other interrupts have no such restriction.
Return
ESP_ERR_INVALID_ARG if the combination of arguments is invalid. ESP_OK otherwise
Parameters
  • handle: The handle, as obtained by esp_intr_alloc or esp_intr_alloc_intrstatus

void esp_intr_noniram_disable()

Disable interrupts that aren’t specifically marked as running from IRAM.

void esp_intr_noniram_enable()

Re-enable interrupts disabled by esp_intr_noniram_disable.

看门狗

概述

Esp-idf 支持两种类型的看门狗:任务看门狗和中断看门狗。二者都可以通过使用 make menuconfig 进行配置和选择恰当的选项。

中断看门狗

中断看门狗可以确保 FreeRTOS 任务切换中断不会被阻塞太长时间。否则这是非常糟糕的,因为没有其它任务(包括相当重要的任务,比如 WiFi 任务和空转任务)能够获取到任何 CPU 时间。如果在中断被禁止时,程序运行到了无线循环,或者程序在中断中被挂起,则任务切换将会阻塞。

中断看门狗的默认行为是调用 panic handler。产生寄存器 dump 可以帮助程序员(使用 OpenOCD 或者 gdbstub)查看代码的问题。也可以通过配置 panic handler,让它直接对 CPU 进行复位,这更适合于实际产品环境。

中断看门狗被编译到定时器组 1 的赢硬件看门狗中。如果该看门狗由于某些原因例如 IRAM 被垃圾数据覆盖)不能执行调用 panic handler 的 NMI handler,它它将对 SoC 进行硬复位。

任务看门狗

任何任务都可以被任务看门狗看守。如果这个任务没有在任务看门狗所指定的超时时间(可以通过 make menuconfig 配置)内喂狗,看门狗将会打印警告消息 —— 哪些任务正在 ESP32 CPU 上面运行,哪些任务没有喂狗。

默认情况下,任务看门狗会看守空转(idle)任务。空转任务没有喂狗的原因通常是某个高优先级任务在处理循环,没有退出到低优先级任务,这可以作为有害代码(外设的 spinloop 或者陷入无线循环的任务)的指示器。

其它任务可以通过调用 esp_task_wdt_feed() 让该任务别任务看门狗看守。第一次调用这个函数时会将该任务注册到任务看门狗中;后续的调用会喂狗。如果任务不想再被看守(例如任务完成了,即将调用 vTaskDelete()),则可以调用 esp_task_wdt_delete()

看门狗任务被编译到定时器组 0 的赢硬件看门狗中。如果这个看门狗由于某些原因(例如 IRAM 被垃圾数据覆盖、中断被完全禁止等)不能执行用于打印任务数据的中断 handler,它将对 SoC 进行硬复位。

JTAG 和看门狗

在使用 OpenOCD 进行调试时,如果 CPU 被挂起,看门狗会继续运行,最终会复位 CPU。这导致调试代码变得非常困难;这也是为什么 OpenOCD 配置会在启动时禁止所有看门狗的原因。也就是说,当 ESP32 通过 JTAG 连接到 OpenOCD 时,你不会看到由任务看门狗或中断看门狗打印的如何警告和 panic。

函数
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)

OTA 过程概述

OTA 升级机制允许常规固件在运行时基于它所接收的数据对设备进行升级(通过 WiFI 或者蓝牙)。

OTA 需要配置设备的 Partition Table,且至少需要两个 “OTA app” 分区(即 ota_0ota_1)和一个 “OTA 数据分区”。

OTA 会将新的 app 固件镜像写到当前未用于启动程序的那个 OTA app 分区。当镜像校验完成后,OTA 数据分区会被更新,表示下一次启动时将使用该镜像。

OTA 数据分区

使用 OTA 功能的产品必须在 Partition Table 中包含一个 OTA 数据分区。

对于工厂启动设置,OTA 数据分区应当不包含数据(所有的字节被擦除为 0xFF)。在这种情况下,如果分区表中存在工厂 app,esp-idf 软件的 bootloader 会启动工厂 app。如果分区表中不存在工厂 app,则会启动第一个有效的 OTA 分区(通常是 ota_0)。

当第一次 OTA 更新后,OTA 数据分区将会被更新,表示表示下一次启动时将使用哪个 OTA app 分区。

OTA 数据分期是两个 flash 扇区(0x2000 字节),以消除正在写时供电失败的问题。如果没有计数字段表明哪个扇区在最近被写过,则两个扇区会被独立擦除并写入匹配的数据。

应用程序示例

端到端的 OTA 固件升级流程请你参考: system/ota

API 参考手册
ESP_ERR_OTA_BASE

Base error code for ota_ops api

ESP_ERR_OTA_PARTITION_CONFLICT

Error if request was to write or erase the current running partition

ESP_ERR_OTA_SELECT_INFO_INVALID

Error if OTA data partition contains invalid content

ESP_ERR_OTA_VALIDATE_FAILED

Error if OTA app image is invalid

OTA_SIZE_UNKNOWN

Used for esp_ota_begin() if new image size is unknown

类型定义
typedef uint32_t esp_ota_handle_t

Opaque handle for an application OTA update.

esp_ota_begin() returns a handle which is then used for subsequent calls to esp_ota_write() and esp_ota_end().

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

Commence an OTA update writing to the specified partition.

The specified partition is erased to the specified image size.

If image size is not yet known, pass OTA_SIZE_UNKNOWN which will cause the entire partition to be erased.

On success, this function allocates memory that remains in use until esp_ota_end() is called with the returned handle.

Return
  • ESP_OK: OTA operation commenced successfully.
  • ESP_ERR_INVALID_ARG: partition or out_handle arguments were NULL, or partition doesn’t point to an OTA app partition.
  • ESP_ERR_NO_MEM: Cannot allocate memory for OTA operation.
  • ESP_ERR_OTA_PARTITION_CONFLICT: Partition holds the currently running firmware, cannot update in place.
  • ESP_ERR_NOT_FOUND: Partition argument not found in partition table.
  • ESP_ERR_OTA_SELECT_INFO_INVALID: The OTA data partition contains invalid data.
  • ESP_ERR_INVALID_SIZE: Partition doesn’t fit in configured flash size.
  • ESP_ERR_FLASH_OP_TIMEOUT or ESP_ERR_FLASH_OP_FAIL: Flash write failed.
Parameters
  • partition: Pointer to info for partition which will receive the OTA update. Required.
  • image_size: Size of new OTA app image. Partition will be erased in order to receive this size of image. If 0 or OTA_SIZE_UNKNOWN, the entire partition is erased.
  • out_handle: On success, returns a handle which should be used for subsequent esp_ota_write() and esp_ota_end() calls.

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

Write OTA update data to partition.

This function can be called multiple times as data is received during the OTA operation. Data is written sequentially to the partition.

Return
  • ESP_OK: Data was written to flash successfully.
  • ESP_ERR_INVALID_ARG: handle is invalid.
  • ESP_ERR_OTA_VALIDATE_FAILED: First byte of image contains invalid app image magic byte.
  • ESP_ERR_FLASH_OP_TIMEOUT or ESP_ERR_FLASH_OP_FAIL: Flash write failed.
  • ESP_ERR_OTA_SELECT_INFO_INVALID: OTA data partition has invalid contents
Parameters
  • handle: Handle obtained from esp_ota_begin
  • data: Data buffer to write
  • size: Size of data buffer in bytes.

esp_err_t esp_ota_end(esp_ota_handle_t handle)

Finish OTA update and validate newly written app image.

Note
After calling esp_ota_end(), the handle is no longer valid and any memory associated with it is freed (regardless of result).
Return
  • ESP_OK: Newly written OTA app image is valid.
  • ESP_ERR_NOT_FOUND: OTA handle was not found.
  • ESP_ERR_INVALID_ARG: Handle was never written to.
  • ESP_ERR_OTA_VALIDATE_FAILED: OTA image is invalid (either not a valid app image, or - if secure boot is enabled - signature failed to verify.)
  • ESP_ERR_INVALID_STATE: If flash encryption is enabled, this result indicates an internal error writing the final encrypted bytes to flash.
Parameters
  • handle: Handle obtained from esp_ota_begin().

const esp_partition_t *esp_ota_get_running_partition(void)

Get partition info of currently running app.

This function is different to esp_ota_get_boot_partition() in that it ignores any change of selected boot partition caused by esp_ota_set_boot_partition(). Only the app whose code is currently running will have its partition information returned.

Return
Pointer to info for partition structure, or NULL if no partition is found or flash read operation failed. Returned pointer is valid for the lifetime of the application.

esp_err_t esp_ota_set_boot_partition(const esp_partition_t *partition)

Configure OTA data for a new boot partition.

Note
If this function returns ESP_OK, calling esp_restart() will boot the newly configured app partition.
Return
  • ESP_OK: OTA data updated, next reboot will use specified partition.
  • ESP_ERR_INVALID_ARG: partition argument was NULL or didn’t point to a valid OTA partition of type “app”.
  • ESP_ERR_OTA_VALIDATE_FAILED: Partition contained invalid app image. Also returned if secure boot is enabled and signature validation failed.
  • ESP_ERR_NOT_FOUND: OTA data partition not found.
  • ESP_ERR_FLASH_OP_TIMEOUT or ESP_ERR_FLASH_OP_FAIL: Flash erase or write failed.
Parameters
  • partition: Pointer to info for partition containing app image to boot.

const esp_partition_t *esp_ota_get_boot_partition(void)

Get partition info of currently configured boot app.

If esp_ota_set_boot_partition() has been called, the partition which was set by that function will be returned.

If esp_ota_set_boot_partition() has not been called, the result is equivalent to esp_ota_get_running_partition().

Return
Pointer to info for partition structure, or NULL if no partition is found or flash read operation failed. Returned pointer is valid for the lifetime of the application.

const esp_partition_t *esp_ota_get_next_update_partition(const esp_partition_t *start_from)

Return the next OTA app partition which should be written with a new firmware.

Call this function to find an OTA app partition which can be passed to esp_ota_begin().

Finds next partition round-robin, starting from the current running partition.

Return
Pointer to info for partition which should be updated next. NULL result indicates invalid OTA data partition, or that no eligible OTA app slot partition was found.
Parameters
  • start_from: If set, treat this partition info as describing the current running partition. Can be NULL, in which case esp_ota_get_running_partition() is used to find the currently running partition. The result of this function is never the same as this argument.

深度睡眠

概述

ESP32 具有深度睡眠节电功能。在这种模式下,CPU、大多数的 RAM 和所有的由时钟 APB_CLK 驱动的数字外设都会被断电。芯片中还继续处于供电状态的部分包括:RTC 控制器、RTC 外设(包括 ULP 协处理器)、RTC 内存(低速和快速)。

从深度睡眠中唤醒可以使用几种源。这些源可以组合在一起,此时,任何一种源都可以触发唤醒。可以通过 API esp_deep_sleep_enable_X_wakeup 来使能唤醒源。下一节将描述这些 API 的细节。你可以在系统进入深度睡眠前的任何时刻配置唤醒源。

此外,应用程序可以使用 API esp_deep_sleep_pd_config 让 RTC 外设和 RTC 内存强制断电。

唤醒源被配置后,应用程序可以使用 API esp_deep_sleep_start 进入深度睡眠。从这一点看,硬件将会根据所请求的唤醒源来配置,RTC 控制器将给 CPU 和数字外设断电。

唤醒源
定时器

RTC 控制器中有一个内置的定时器,可用于在预定义的时间到达后唤醒芯片。时间的精度是微秒,但是实际的分辨率依赖于为 RTC SLOW_CLK 所选择的时钟源。关于 RTC 时钟选项的更多细节请参考 ESP32 技术参考手册的 “Reset and Clock” 一章。

这种唤醒模式不需要 RTC 外设或内存在深度睡眠器件供电。

下面的函数可以用于使能使用定时器深度睡眠唤醒。

esp_err_t esp_deep_sleep_enable_timer_wakeup(uint64_t time_in_us)

Enable wakeup by timer.

Return
  • ESP_OK on success
  • ESP_ERR_INVALID_ARG if value is out of range (TBD)
Parameters
  • time_in_us: time before wakeup, in microseconds

触摸板

RTC IO 模块中包含这样一个逻辑:当发生触摸传感器中断时触发唤醒。你需要在芯片进入深度睡眠前配置触摸屏的中断。

ESP32 的修订版 0 和 1 仅在 RTC 外设没有被强制供电时支持该唤醒(即 ESP_PD_DOMAIN_RTC_PERIPH 被设置为 ESP_PD_OPTION_AUTO)。

esp_err_t esp_deep_sleep_enable_touchpad_wakeup()

Enable wakeup by touch sensor.

Note
In revisions 0 and 1 of the ESP32, touch wakeup source can not be used when RTC_PERIPH power domain is forced to be powered on (ESP_PD_OPTION_ON) or when ext0 wakeup source is used.
Return
  • ESP_OK on success
  • ESP_ERR_INVALID_STATE if wakeup triggers conflict

外部唤醒(ext0)

RTC IO 模块中包含这样一个逻辑,当某个 RTC GPIO 被设置为预定义的逻辑值时触发唤醒。RTC IO 是 RTC 外设电源域的一部分,因此如果该唤醒源被请求的话,RTC 外设将在深度睡眠期间保持供电。

因为 RTC IO 模块在这个模式被使能,因此也可以使用内部上拉或下拉电阻。它们需要应用程序在调用 esp_deep_sleep_start 前使用先调用函数 rtc_gpio_pullup_enrtc_gpio_pulldown_en

在 ESP32 的修订版 0 和 1 中,这个唤醒源与 ULP 和触摸唤醒源都不兼容。

警告

从深度睡眠中唤醒后,用于唤醒的 IO Pad 将被配置为 RTC IO,因此在将该 pad 用作数字 IO 前,需要使用函数 rtc_gpio_deinit(gpio_num) 对它进行重新配置。

esp_err_t esp_deep_sleep_enable_ext0_wakeup(gpio_num_t gpio_num, int level)

Enable wakeup using a pin.

This function uses external wakeup feature of RTC_IO peripheral. It will work only if RTC peripherals are kept on during deep sleep.

This feature can monitor any pin which is an RTC IO. Once the pin transitions into the state given by level argument, the chip will be woken up.

Note
This function does not modify pin configuration. The pin is configured in esp_deep_sleep_start, immediately before entering deep sleep.
Note
In revisions 0 and 1 of the ESP32, ext0 wakeup source can not be used together with touch or ULP wakeup sources.
Return
  • ESP_OK on success
  • ESP_ERR_INVALID_ARG if the selected GPIO is not an RTC GPIO, or the mode is invalid
  • ESP_ERR_INVALID_STATE if wakeup triggers conflict
Parameters
  • gpio_num: GPIO number used as wakeup source. Only GPIOs which are have RTC functionality can be used: 0,2,4,12-15,25-27,32-39.
  • level: input level which will trigger wakeup (0=low, 1=high)

外部唤醒(ext1)

RTC 控制器包含使用多个 RTC GPIO 触发唤醒的逻辑。下面其中一个逻辑功能可以用于触发唤醒:

  • 当任意一个所选引脚为高电平时唤醒 (ESP_EXT1_WAKEUP_ANY_HIGH)
  • 当所有所选引脚为低电平时唤醒 (ESP_EXT1_WAKEUP_ALL_LOW)

这个唤醒源由 RTC 控制器实现。这种模式下的 RTC 外设和 RTC 内存可以被断电。不过,如果 RTC 外设被断电,内部上拉和下拉电阻将被禁止。为了使用内部上拉和下拉电阻,需要 RTC 外设电源域在睡眠期间保持开启,并在进入深度睡眠前使用函数 rtc_gpio_ 配置上拉/下拉电阻

esp_deep_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
gpio_pullup_dis(gpio_num);
gpio_pulldown_en(gpio_num);

警告

从深度睡眠中唤醒后,用于唤醒的 IO Pad 将被配置为 RTC IO,因此在将该 pad 用作数字 IO 前,需要使用函数 rtc_gpio_deinit(gpio_num) 对它进行重新配置。

下列函数可以用于使能这个唤醒模式:

esp_err_t esp_deep_sleep_enable_ext1_wakeup(uint64_t mask, esp_ext1_wakeup_mode_t mode)

Enable wakeup using multiple pins.

This function uses external wakeup feature of RTC controller. It will work even if RTC peripherals are shut down during deep sleep.

This feature can monitor any number of pins which are in RTC IOs. Once any of the selected pins goes into the state given by mode argument, the chip will be woken up.

Note
This function does not modify pin configuration. The pins are configured in esp_deep_sleep_start, immediately before entering deep sleep.
Note
internal pullups and pulldowns don’t work when RTC peripherals are shut down. In this case, external resistors need to be added. Alternatively, RTC peripherals (and pullups/pulldowns) may be kept enabled using esp_deep_sleep_pd_config function.
Return
  • ESP_OK on success
  • ESP_ERR_INVALID_ARG if any of the selected GPIOs is not an RTC GPIO, or mode is invalid
Parameters
  • mask: bit mask of GPIO numbers which will cause wakeup. Only GPIOs which are have RTC functionality can be used in this bit map: 0,2,4,12-15,25-27,32-39.
  • mode: select logic function used to determine wakeup condition:
    • ESP_EXT1_WAKEUP_ALL_LOW: wake up when all selected GPIOs are low
    • ESP_EXT1_WAKEUP_ANY_HIGH: wake up when any of the selected GPIOs is high

enum esp_ext1_wakeup_mode_t

Logic function used for EXT1 wakeup mode.

Values:

ESP_EXT1_WAKEUP_ALL_LOW = 0

Wake the chip when all selected GPIOs go low.

ESP_EXT1_WAKEUP_ANY_HIGH = 1

Wake the chip when any of the selected GPIOs go high.

ULP 协处理器唤醒

当芯片处于深度睡眠时,ULP 协处理器能够运行,可以用于轮询传感器、监视器 ADC 或者触摸板传感器的值,并在检查到某个特殊事件时唤醒芯片。ULP 协处理器是 RTC 外设电源域的一部分,它运行存储在 RTC 低速内存中的程序。如果请求了这种唤醒模式,则 RTC 低速内存将会在深度睡眠期间保持供电状态。RTC 外设会在 ULP 协处理器开始运行程序前自动上电;一旦程序停止运行,RTC 外设会再次自动断电。

ESP32 的修订版 0 和 1 仅在 RTC 外设没有被强制供电时支持该唤醒(即 ESP_PD_DOMAIN_RTC_PERIPH 被设置为 ESP_PD_OPTION_AUTO)。

下列函数可以用于使能这个唤醒模式:

esp_err_t esp_deep_sleep_enable_ulp_wakeup()

Enable wakeup by ULP coprocessor.

Note
In revisions 0 and 1 of the ESP32, ULP wakeup source can not be used when RTC_PERIPH power domain is forced to be powered on (ESP_PD_OPTION_ON) or when ext0 wakeup source is used.
Return
  • ESP_OK on success
  • ESP_ERR_INVALID_STATE if ULP co-processor is not enabled or if wakeup triggers conflict

RTC 外设和内存断电

默认情况下,函数 esp_deep_sleep_start 将会关掉被使能的唤醒源不需要的所有 RTC 电源域。如果向修改这个默认行为,可以使用下面的函数:

Note: 在 ESP32 的修订版 1 中,RTC 快速内存在深度睡眠期间将总是保持使能,因此深度睡眠桩(stub)可以在复位后运行。如果应用程序在深度睡眠后不需要清除复位行为,也可以对其进行修改。

如果程序中的某些值被if昂懂啊 RTC 低速内存中(例如,使用 RTC_DATA_ATTR 属性),RTC 低速内存将默认保持供电。如果有需要,也可以使用函数 esp_deep_sleep_pd_config 对其进行修改。

esp_err_t esp_deep_sleep_pd_config(esp_deep_sleep_pd_domain_t domain, esp_deep_sleep_pd_option_t option)

Set power down mode for an RTC power domain in deep sleep.

If not set set using this API, all power domains default to ESP_PD_OPTION_AUTO.

Return
  • ESP_OK on success
  • ESP_ERR_INVALID_ARG if either of the arguments is out of range
Parameters
  • domain: power domain to configure
  • option: power down option (ESP_PD_OPTION_OFF, ESP_PD_OPTION_ON, or ESP_PD_OPTION_AUTO)

enum esp_deep_sleep_pd_domain_t

Power domains which can be powered down in deep sleep.

Values:

ESP_PD_DOMAIN_RTC_PERIPH

RTC IO, sensors and ULP co-processor.

ESP_PD_DOMAIN_RTC_SLOW_MEM

RTC slow memory.

ESP_PD_DOMAIN_RTC_FAST_MEM

RTC fast memory.

ESP_PD_DOMAIN_MAX

Number of domains.

enum esp_deep_sleep_pd_option_t

Power down options.

Values:

ESP_PD_OPTION_OFF

Power down the power domain in deep sleep.

ESP_PD_OPTION_ON

Keep power domain enabled during deep sleep.

ESP_PD_OPTION_AUTO

Keep power domain enabled in deep sleep, if it is needed by one of the wakeup options. Otherwise power it down.

进入深度睡眠

唤醒源配置后,下面函数可以用于进入深度睡眠。在没有配置唤醒源时也可以进入深度睡眠,在这种情形下,芯片将确切地处于深度睡眠模式,知道接收到外部复位。

void esp_deep_sleep_start()

Enter deep sleep with the configured wakeup options.

This function does not return.

检查深度睡眠唤醒原因

下面的函数可用于检测是何种唤醒源在深度睡眠期间被触发了。对于触摸板和 ext1 唤醒源,可以确定造成唤醒的引脚或触摸 pad。

esp_deep_sleep_wakeup_cause_t esp_deep_sleep_get_wakeup_cause()

Get the source which caused deep sleep wakeup.

Return
wakeup cause, or ESP_DEEP_SLEEP_WAKEUP_UNDEFINED if reset reason is other than deep sleep reset.

enum esp_deep_sleep_wakeup_cause_t

Deep sleep wakeup cause.

Values:

ESP_DEEP_SLEEP_WAKEUP_UNDEFINED
ESP_DEEP_SLEEP_WAKEUP_EXT0

Wakeup was not caused by deep sleep.

ESP_DEEP_SLEEP_WAKEUP_EXT1

Wakeup caused by external signal using RTC_IO.

ESP_DEEP_SLEEP_WAKEUP_TIMER

Wakeup caused by external signal using RTC_CNTL.

ESP_DEEP_SLEEP_WAKEUP_TOUCHPAD

Wakeup caused by timer.

ESP_DEEP_SLEEP_WAKEUP_ULP

Wakeup caused by touchpad.

touch_pad_t esp_deep_sleep_get_touchpad_wakeup_status()

Get the touch pad which caused wakeup.

If wakeup was caused by another source, this function will return TOUCH_PAD_MAX;

Return
touch pad which caused wakeup

uint64_t esp_deep_sleep_get_ext1_wakeup_status()

Get the bit mask of GPIOs which caused wakeup (ext1)

If wakeup was caused by another source, this function will return 0.

Return
bit mask, if GPIOn caused wakeup, BIT(n) will be set

应用程序示例

深度睡眠的基本示例程序是 protocols/sntp,它会让 ESP 模块周期性地唤醒,以从 NTP 服务器获取时间。

更多扩展示例请参考 system/deep_sleep,它描述了各种深度睡眠触发器和 ULP 协处理器编程的方法。

日志库

概述

日志库有两种方式管理日志的可见性:编译时和运行时。编译时是通过配置菜单实现的;运行时是通过函数 esp_log_level_set 实现的。

在编译时,日志的过滤是通过配置菜单的宏 CONFIG_LOG_DEFAULT_LEVEL 完成的。所有日志级别大于 CONFIG_LOG_DEFAULT_LEVEL 的语句都会被预处理器移除。

在运行时,级别在 CONFIG_LOG_DEFAULT_LEVEL 以下的日志默认都被使能。函数 esp_log_level_set 可以用于设置每个模块的日志级别。模块通过它们的标签(tags)进行标识。标签是人类可识别的以 ‘0’ 作为结尾的字符串。

如何使用日志库

在每个需要使用日志功能的 C 源文件中,按照类似下面的这种方式定义 TAG 变量:

static const char* TAG = "MyModule";

然后使用以下其中一个宏来产生输出,例如:

ESP_LOGW(TAG, "Baud rate error %.1f%%. Requested: %d baud, actual: %d baud", error * 100, baud_req, baud_real);

下面的几个宏可用于输出不同的日志级别:

  • ESP_LOGE - 错误/error
  • ESP_LOGW - 警告/warning
  • ESP_LOGI - 信息/info
  • ESP_LOGD - 调试/debug
  • ESP_LOGV - 啰嗦/verbose

此外,上面的每一种宏还存在一种 _EARLY_ 变种,例如 ESP_EARLY_LOGE。这些变种可以运行在启动代码中,在堆分配器和 syscall 被初始化之前。在编译 bootloader 时,常规的宏 ESP_LOGx 将会退化为对应的宏 ESP_EARLY_LOGx。因此,需要明确使用 ESP_EARLY_LOGx 的地方是早起的启动代码,例如堆分配器的初始化代码。

(注意,如果我们在 ROM 中有 ets_vprintf 函数,则不需要进行这样的区分,可以直接将 _EARLY_ 版的宏切换为普通版的宏。不幸的是,ROM 中的 ets_vprintf 会被编译器内链为 ets_printf,因此在外部不可访问)

如果想在文件或者组件内覆盖默认的可视级别,可以在文件或组件内定义一个 LOG_LOCAL_LEVEL 宏。如果是在文件内,该宏的定义需要在包含头文件 esp_log.h 之前,例如:

#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE
#include "esp_log.h"

如果是在组件内,则需要在组件的 makefile 中定义:

CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_DEBUG

如果需要在运行时为每个模块配置日志输出,则直接调用函数 esp_log_level_set

esp_log_level_set("*", ESP_LOG_ERROR);        // set all components to ERROR level
esp_log_level_set("wifi", ESP_LOG_WARN);      // enable WARN logs from WiFi stack
esp_log_level_set("dhcpc", ESP_LOG_INFO);     // enable INFO logs from DHCP client
通过 JTAG 将日志输出到主机

默认情况下,日志库会使用类 vprintf 函数将格式化消息输出到专用的 UART 中。通常,这会涉及到以下步骤:

  1. 解释格式化字符串,以获取每个参数的类型。
  2. 根据每个参数的类型,将其转换成字符串形式。
  3. 格式化字符串和转换后的参数被发送到 UART。

尽管类 vprintf 函数的实现可以被优化到一定的级别,但是在所有情形下都需要执行上面到步骤,且每个步骤(尤其是第三项)都需要花一定的时间。 So it is frequent situation when addition of extra logging to the program to diagnose some problem changes its behaviour and problem dissapears。或者在最差的情形,程序最终可能会发送错误以致完全不能工作,甚至直接挂起。克服这个问题的可用的办法是使用一个更快的 UART 波特率(或者使用另一个更快的接口)和/或将将字符串格式化过程转移到主机上。ESP IDF 有一个 应用程序跟踪(Application Tracing) 功能,它允许通过 JTAG 将任意的应用程序数据发送到主机。这个功能也可哟通过使用函数 esp_apptrace_vprintf 将日志信息传输到主机。这个函数不会对格式化字符串和参数执行完整的解释,相反,它仅仅计算传递的参数的数量,并将其与格式话字符串的地址一起发送到主机。在主机上,日志数据会被一个特俗的 Python 脚本处理并打印。

配置选项和依赖

使用这个功能依赖于两个组件:

1.主机侧: 应用程序跟踪是由 JTAG 完成的,所以需要在主机上配置并运行 OpenOCD。关于如何配置的指令,请阅读 为 ESP32 设置 OpenOCD 一节。NOTE: 为了达到更高的数据速率,你需要在 OpenOCD 的配置文件中修改 JTAG 适配器的工作频率。经测试,最大的稳定速度是 26MHz,因此你需要在你的配置文件中使用 adapter_khz 26000 替换默认的 adapter_khz 200JTAG 的实际的最大稳定频率依赖于主机系统的配置。 2. 目标侧:应用程序跟踪功能可以在配置菜单中通过宏 CONFIG_ESP32_APPTRACE_ENABLE 进行使能。该选项会使能该模块,并让 esp_apptrace_vprintf 对所有用户有效。

限制

当前,通过 JTAG 打印日志消息有如下几点限制:

  1. 不支持对 ESP_EARLY_LOGx 宏的跟踪。
  2. 不支持参数(例如 doubleuint64_t)超过 4 个字节的 printf。
  3. 仅支持 .rodata 段中的字符串用过格式化字符串和参数。
  4. printf 参数的最大数量是 256。
如何使用

要使用 JTAG 输出日志,你需要执行以下步骤:

  1. 在目标侧,需要安装特定的类 vprintf 函数。正如之前提到的,这个函数是 esp_apptrace_vprintf。它会通过 JTAG 向主机发送日志数据。示例代码如下:
#include "esp_app_trace.h"
...
void app_main()
{
    // set log vprintf handler
    esp_log_set_vprintf(esp_apptrace_vprintf);
    ...
    // user code using ESP_LOGx starts here
    // all data passed to ESP_LOGx are sent to host
    ...
    // restore log vprintf handler
    esp_log_set_vprintf(vprintf);
    // flush last data to host
    esp_apptrace_flush(ESP_APPTRACE_DEST_TRAX, 100000 /*tmo in us*/);
    ESP_LOGI(TAG, "Tracing is finished."); // this will be printed out to UART
    while (1);
}
  1. 按照 Developing With the ESP-IDF 一节中的方法编译应用程序镜像并将其下载到目标板中。
  2. 运行 OpenOCD (参考 OpenOCD setup for ESP32 一节)。
  3. 连接到 OpenOCD telnet 服务器。在 Linux 上,你可以在终端中使用命令 telnet <oocd_host> 4444。如果运行 telnet 会话的主机就是你运行 OpenOCD 的同一个主机,你可以在该命令中直接使用 localhost 作为 <oocd_host>
  4. 在 OpenOCD telnet 会话中运行如下命令: esp108 apptrace start /path/to/trace/file -1 -1 0 0 1。这个命令会等待板子复位,并以最高的速率传输跟踪数据。
  5. 将开发板复位。日志会自动发送到主机。
  6. 使用上面参数的命令 esp108 apptrace 永远不会返回(参考下面的命令选项),因此你必须手动停止,可以通过复位开发板或者在 OpenOCD 窗口(不是运行 telnet 会话的窗口)按下 CTRL+C。
  7. 当调试完成后(例如对于上面的示例代码,指的是当 “Tracing is finished.” 出现在 UART 后),将开发板复位,或者在 OpenOCD 窗口不是运行 telnet 会话的窗口)按下 CTRL+C。
  8. 如果要打印所采集的日志记录,在终端中运行如下命令: $IDF_PATH/tools/esp_app_trace/logtrace_proc.py /path/to/trace/file /path/to/program/elf/file
OpenOCD 应用程序跟踪命令的选项

命令的用法: esp108 apptrace [start <outfile> [options] | [stop] | [status] | [dump <outfile>]

子命令:
  • start. 启动跟踪 (continuous streaming).
  • stop. 停止跟踪
  • status. 获取跟踪状态
  • dump. Dump 尽量多的数据,不需要等待跟踪内存块切换 (post-mortem dump).
启动命令的语法:
start <outfile> [trace_size [stop_tmo [skip_size [poll_period [wait4halt]]]]]
日志跟踪处理命令的选项

命令的用法: logtrace_proc.py [-h] [--no-errors] <trace_file> <elf_file>

必选参数:

参数 描述
trace_file 日志跟踪文件的路径
elf_file 程序 ELF 文件的路径

可选参数:

参数 描述
-h, –help 显示本帮助信息并退出
–no-errors, -n 不打印错误
应用程序示例

大多数 esp-idf 组件和例程都使用了日志(Log)库。日志功能的演示请参考 espressif/esp-idf 仓库的 examples 目录,建议可以参考这些示例:

API 参考手册
LOG_COLOR_E
LOG_COLOR_W
LOG_COLOR_I
LOG_COLOR_D
LOG_COLOR_V
LOG_RESET_COLOR
LOG_FORMAT(letter, format)
LOG_LOCAL_LEVEL
ESP_EARLY_LOGE(tag, format, ...)
ESP_EARLY_LOGW(tag, format, ...)
ESP_EARLY_LOGI(tag, format, ...)
ESP_EARLY_LOGD(tag, format, ...)
ESP_EARLY_LOGV(tag, format, ...)
ESP_LOGE(tag, format, ...)
ESP_LOGW(tag, format, ...)
ESP_LOGI(tag, format, ...)
ESP_LOGD(tag, format, ...)
ESP_LOGV(tag, format, ...)
类型定义
typedef int (*vprintf_like_t)(const char *, va_list)
枚举
enum esp_log_level_t

Log level.

Values:

ESP_LOG_NONE

No log output

ESP_LOG_ERROR

Critical errors, software module can not recover on its own

ESP_LOG_WARN

Error conditions from which recovery measures have been taken

ESP_LOG_INFO

Information messages which describe normal flow of events

ESP_LOG_DEBUG

Extra information which is not necessary for normal use (values, pointers, sizes, etc).

ESP_LOG_VERBOSE

Bigger chunks of debugging information, or frequent messages which can potentially flood the output.

函数
void esp_log_level_set(const char *tag, esp_log_level_t level)

Set log level for given tag.

If logging for given component has already been enabled, changes previous setting.

Parameters
  • tag: Tag of the log entries to enable. Must be a non-NULL zero terminated string. Value “*” resets log level for all tags to the given value.
  • level: Selects log level to enable. Only logs at this and lower levels will be shown.

void esp_log_set_vprintf(vprintf_like_t func)

Set function used to output log entries.

By default, log output goes to UART0. This function can be used to redirect log output to some other destination, such as file or network.

Parameters
  • func: Function used for output. Must have same signature as vprintf.

uint32_t esp_log_timestamp(void)

Function which returns timestamp to be used in log output.

This function is used in expansion of ESP_LOGx macros. In the 2nd stage bootloader, and at early application startup stage this function uses CPU cycle counter as time source. Later when FreeRTOS scheduler start running, it switches to FreeRTOS tick count.

For now, we ignore millisecond counter overflow.

Return
timestamp, in milliseconds

void esp_log_write(esp_log_level_t level, const char *tag, const char *format, ...)

Write message into the log.

This function is not intended to be used directly. Instead, use one of ESP_LOGE, ESP_LOGW, ESP_LOGI, ESP_LOGD, ESP_LOGV macros.

This function or these macros should not be used from an interrupt.

关于本节 API 的示例代码请参考 ESP-IDF 示例中的 system 目录。

存储器 API

SPI Flash APIs

Overview

The spi_flash component contains APIs related to reading, writing, erasing, memory mapping data in the external SPI flash. It also has higher-level APIs which work with partitions defined in the partition table.

Note that all the functionality is limited to the “main” SPI flash chip, the same SPI flash chip from which program runs. For spi_flash_* functions, this is a software limitation. The underlying ROM functions which work with SPI flash do not have provisions for working with flash chips attached to SPI peripherals other than SPI0.

SPI flash access APIs

This is the set of APIs for working with data in flash:

  • spi_flash_read used to read data from flash to RAM
  • spi_flash_write used to write data from RAM to flash
  • spi_flash_erase_sector used to erase individual sectors of flash
  • spi_flash_erase_range used to erase range of addresses in flash
  • spi_flash_get_chip_size returns flash chip size, in bytes, as configured in menuconfig

Generally, try to avoid using the raw SPI flash functions in favour of partition-specific functions.

SPI Flash Size

The SPI flash size is configured by writing a field in the software bootloader image header, flashed at offset 0x1000.

By default, the SPI flash size is detected by esptool.py when this bootloader is written to flash, and the header is updated with the correct size. Alternatively, it is possible to generate a fixed flash size by disabling detection in make menuconfig (under Serial Flasher Config).

If it is necessary to override the configured flash size at runtime, is is possible to set the chip_size member of g_rom_flashchip structure. This size is used by spi_flash_* functions (in both software & ROM) for bounds checking.

Concurrency Constraints

Because the SPI flash is also used for firmware execution (via the instruction & data caches), these caches much be disabled while reading/writing/erasing. This means that both CPUs must be running code from IRAM and only reading data from DRAM while flash write operations occur.

Refer to the application memory layout documentation for an explanation of the differences between IRAM, DRAM and flash cache.

To avoid reading flash cache accidentally, when one CPU commences a flash write or erase operation the other CPU is put into a blocked state and all non-IRAM-safe interrupts are disabled on both CPUs, until the flash operation completes.

IRAM-Safe Interrupt Handlers

If you have an interrupt handler that you want to execute even when a flash operation is in progress (for example, for low latency operations), set the ESP_INTR_FLAG_IRAM flag when the interrupt handler is registered.

You must ensure all data and functions accessed by these interrupt handlers are located in IRAM or DRAM. This includes any functions that the handler calls.

Use the IRAM_ATTR attribute for functions:

#include "esp_attr.h"

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

Use the DRAM_ATTR and DRAM_STR attributes for constant data:

void IRAM_ATTR gpio_isr_handler(void* arg)
{
   const static DRAM_ATTR uint8_t INDEX_DATA[] = { 45, 33, 12, 0 };
   const static char *MSG = DRAM_STR("I am a string stored in RAM");
}

Note that knowing which data should be marked with DRAM_ATTR can be hard, the compiler will sometimes recognise that a variable or expression is constant (even if it is not marked const) and optimise it into flash, unless it is marked with DRAM_ATTR.

If a function or symbol is not correctly put into IRAM/DRAM and the interrupt handler reads from the flash cache during a flash operation, it will cause a crash due to Illegal Instruction exception (for code which should be in IRAM) or garbage data to be read (for constant data which should be in DRAM).

Partition table APIs

ESP-IDF projects use a partition table to maintain information about various regions of SPI flash memory (bootloader, various application binaries, data, filesystems). More information about partition tables can be found here.

This component provides APIs to enumerate partitions found in the partition table and perform operations on them. These functions are declared in esp_partition.h:

  • esp_partition_find used to search partition table for entries with specific type, returns an opaque iterator
  • esp_partition_get returns a structure describing the partition, for the given iterator
  • esp_partition_next advances iterator to the next partition found
  • esp_partition_iterator_release releases iterator returned by esp_partition_find
  • esp_partition_find_first is a convenience function which returns structure describing the first partition found by esp_partition_find
  • esp_partition_read, esp_partition_write, esp_partition_erase_range are equivalent to spi_flash_read, spi_flash_write, spi_flash_erase_range, but operate within partition boundaries

Most application code should use esp_partition_* APIs instead of lower level spi_flash_* APIs. Partition APIs do bounds checking and calculate correct offsets in flash based on data stored in partition table.

SPI Flash Encryption

It is possible to encrypt SPI flash contents, and have it transparenlty decrypted by hardware.

Refer to the Flash Encryption documentation for more details.

Memory mapping APIs

ESP32 features memory hardware which allows regions of flash memory to be mapped into instruction and data address spaces. This mapping works only for read operations, it is not possible to modify contents of flash memory by writing to mapped memory region. Mapping happens in 64KB pages. Memory mapping hardware can map up to 4 megabytes of flash into data address space, and up to 16 megabytes of flash into instruction address space. See the technical reference manual for more details about memory mapping hardware.

Note that some number of 64KB pages is used to map the application itself into memory, so the actual number of available 64KB pages may be less.

Reading data from flash using a memory mapped region is the only way to decrypt contents of flash when flash encryption is enabled. Decryption is performed at hardware level.

Memory mapping APIs are declared in esp_spi_flash.h and esp_partition.h:

  • spi_flash_mmap maps a region of physical flash addresses into instruction space or data space of the CPU
  • spi_flash_munmap unmaps previously mapped region
  • esp_partition_mmap maps part of a partition into the instruction space or data space of the CPU

Differences between spi_flash_mmap and esp_partition_mmap are as follows:

  • spi_flash_mmap must be given a 64KB aligned physical address
  • esp_partition_mmap may be given an arbitrary offset within the partition, it will adjust returned pointer to mapped memory as necessary

Note that because memory mapping happens in 64KB blocks, it may be possible to read data outside of the partition provided to esp_partition_mmap.

其它
API 参考手册
ESP_ERR_FLASH_BASE
ESP_ERR_FLASH_OP_FAIL
ESP_ERR_FLASH_OP_TIMEOUT
SPI_FLASH_SEC_SIZE

SPI Flash sector size

SPI_FLASH_MMU_PAGE_SIZE

Flash cache MMU mapping page size

ESP_PARTITION_SUBTYPE_OTA(i)

Convenience macro to get esp_partition_subtype_t value for the i-th OTA partition.

SPI_FLASH_CACHE2PHYS_FAIL
类型定义
typedef uint32_t spi_flash_mmap_handle_t

Opaque handle for memory region obtained from spi_flash_mmap.

typedef struct esp_partition_iterator_opaque_ *esp_partition_iterator_t

Opaque partition iterator type.

枚举
enum spi_flash_mmap_memory_t

Enumeration which specifies memory space requested in an mmap call.

Values:

SPI_FLASH_MMAP_DATA

map to data memory (Vaddr0), allows byte-aligned access, 4 MB total

SPI_FLASH_MMAP_INST

map to instruction memory (Vaddr1-3), allows only 4-byte-aligned access, 11 MB total

enum esp_partition_type_t

Partition type.

Note
Keep this enum in sync with PartitionDefinition class gen_esp32part.py

Values:

ESP_PARTITION_TYPE_APP = 0x00

Application partition type.

ESP_PARTITION_TYPE_DATA = 0x01

Data partition type.

enum esp_partition_subtype_t

Partition subtype.

Note
Keep this enum in sync with PartitionDefinition class gen_esp32part.py

Values:

ESP_PARTITION_SUBTYPE_APP_FACTORY = 0x00

Factory application partition.

ESP_PARTITION_SUBTYPE_APP_OTA_MIN = 0x10

Base for OTA partition subtypes.

ESP_PARTITION_SUBTYPE_APP_OTA_0 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 0

OTA partition 0.

ESP_PARTITION_SUBTYPE_APP_OTA_1 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 1

OTA partition 1.

ESP_PARTITION_SUBTYPE_APP_OTA_2 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 2

OTA partition 2.

ESP_PARTITION_SUBTYPE_APP_OTA_3 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 3

OTA partition 3.

ESP_PARTITION_SUBTYPE_APP_OTA_4 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 4

OTA partition 4.

ESP_PARTITION_SUBTYPE_APP_OTA_5 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 5

OTA partition 5.

ESP_PARTITION_SUBTYPE_APP_OTA_6 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 6

OTA partition 6.

ESP_PARTITION_SUBTYPE_APP_OTA_7 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 7

OTA partition 7.

ESP_PARTITION_SUBTYPE_APP_OTA_8 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 8

OTA partition 8.

ESP_PARTITION_SUBTYPE_APP_OTA_9 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 9

OTA partition 9.

ESP_PARTITION_SUBTYPE_APP_OTA_10 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 10

OTA partition 10.

ESP_PARTITION_SUBTYPE_APP_OTA_11 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 11

OTA partition 11.

ESP_PARTITION_SUBTYPE_APP_OTA_12 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 12

OTA partition 12.

ESP_PARTITION_SUBTYPE_APP_OTA_13 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 13

OTA partition 13.

ESP_PARTITION_SUBTYPE_APP_OTA_14 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 14

OTA partition 14.

ESP_PARTITION_SUBTYPE_APP_OTA_15 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 15

OTA partition 15.

ESP_PARTITION_SUBTYPE_APP_OTA_MAX = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 16

Max subtype of OTA partition.

ESP_PARTITION_SUBTYPE_APP_TEST = 0x20

Test application partition.

ESP_PARTITION_SUBTYPE_DATA_OTA = 0x00

OTA selection partition.

ESP_PARTITION_SUBTYPE_DATA_PHY = 0x01

PHY init data partition.

ESP_PARTITION_SUBTYPE_DATA_NVS = 0x02

NVS partition.

ESP_PARTITION_SUBTYPE_DATA_COREDUMP = 0x03

COREDUMP partition.

ESP_PARTITION_SUBTYPE_DATA_ESPHTTPD = 0x80

ESPHTTPD partition.

ESP_PARTITION_SUBTYPE_DATA_FAT = 0x81

FAT partition.

ESP_PARTITION_SUBTYPE_DATA_SPIFFS = 0x82

SPIFFS partition.

ESP_PARTITION_SUBTYPE_ANY = 0xff

Used to search for partitions with any subtype.

结构体
struct esp_partition_t

partition information structure

This is not the format in flash, that format is esp_partition_info_t.

However, this is the format used by this API.

函数
void spi_flash_init()

Initialize SPI flash access driver.

This function must be called exactly once, before any other spi_flash_* functions are called. Currently this function is called from startup code. There is no need to call it from application code.

size_t spi_flash_get_chip_size()

Get flash chip size, as set in binary image header.

Note
This value does not necessarily match real flash size.
Return
size of flash chip, in bytes

esp_err_t spi_flash_erase_sector(size_t sector)

Erase the Flash sector.

Return
esp_err_t
Parameters
  • sector: Sector number, the count starts at sector 0, 4KB per sector.

esp_err_t spi_flash_erase_range(size_t start_address, size_t size)

Erase a range of flash sectors.

Return
esp_err_t
Parameters
  • start_address: Address where erase operation has to start. Must be 4kB-aligned
  • size: Size of erased range, in bytes. Must be divisible by 4kB.

esp_err_t spi_flash_write(size_t dest_addr, const void *src, size_t size)

Write data to Flash.

Note
If source address is in DROM, this function will return ESP_ERR_INVALID_ARG.
Return
esp_err_t
Parameters
  • dest_addr: destination address in Flash. Must be a multiple of 4 bytes.
  • src: pointer to the source buffer.
  • size: length of data, in bytes. Must be a multiple of 4 bytes.

esp_err_t spi_flash_write_encrypted(size_t dest_addr, const void *src, size_t size)

Write data encrypted to Flash.

Note
Flash encryption must be enabled for this function to work.
Note
Flash encryption must be enabled when calling this function. If flash encryption is disabled, the function returns ESP_ERR_INVALID_STATE. Use esp_flash_encryption_enabled() function to determine if flash encryption is enabled.
Note
Both dest_addr and size must be multiples of 16 bytes. For absolute best performance, both dest_addr and size arguments should be multiples of 32 bytes.
Return
esp_err_t
Parameters
  • dest_addr: destination address in Flash. Must be a multiple of 16 bytes.
  • src: pointer to the source buffer.
  • size: length of data, in bytes. Must be a multiple of 16 bytes.

esp_err_t spi_flash_read(size_t src_addr, void *dest, size_t size)

Read data from Flash.

Return
esp_err_t
Parameters
  • src_addr: source address of the data in Flash.
  • dest: pointer to the destination buffer
  • size: length of data

esp_err_t spi_flash_read_encrypted(size_t src, void *dest, size_t size)

Read data from Encrypted Flash.

If flash encryption is enabled, this function will transparently decrypt data as it is read. If flash encryption is not enabled, this function behaves the same as spi_flash_read().

See esp_flash_encryption_enabled() for a function to check if flash encryption is enabled.

Return
esp_err_t
Parameters
  • src: source address of the data in Flash.
  • dest: pointer to the destination buffer
  • size: length of data

esp_err_t spi_flash_mmap(size_t src_addr, size_t size, spi_flash_mmap_memory_t memory, const void **out_ptr, spi_flash_mmap_handle_t *out_handle)

Map region of flash memory into data or instruction address space.

This function allocates sufficient number of 64k MMU pages and configures them to map request region of flash memory into data address space or into instruction address space. It may reuse MMU pages which already provide required mapping. As with any allocator, there is possibility of fragmentation of address space if mmap/munmap are heavily used. To troubleshoot issues with page allocation, use spi_flash_mmap_dump function.

Return
ESP_OK on success, ESP_ERR_NO_MEM if pages can not be allocated
Parameters
  • src_addr: Physical address in flash where requested region starts. This address must be aligned to 64kB boundary (SPI_FLASH_MMU_PAGE_SIZE).
  • size: Size of region which has to be mapped. This size will be rounded up to a 64k boundary.
  • memory: Memory space where the region should be mapped
  • out_ptr: Output, pointer to the mapped memory region
  • out_handle: Output, handle which should be used for spi_flash_munmap call

void spi_flash_munmap(spi_flash_mmap_handle_t handle)

Release region previously obtained using spi_flash_mmap.

Note
Calling this function will not necessarily unmap memory region. Region will only be unmapped when there are no other handles which reference this region. In case of partially overlapping regions it is possible that memory will be unmapped partially.
Parameters
  • handle: Handle obtained from spi_flash_mmap

void spi_flash_mmap_dump()

Display information about mapped regions.

This function lists handles obtained using spi_flash_mmap, along with range of pages allocated to each handle. It also lists all non-zero entries of MMU table and corresponding reference counts.

size_t spi_flash_cache2phys(const void *cached)

Given a memory address where flash is mapped, return the corresponding physical flash offset.

Cache address does not have have been assigned via spi_flash_mmap(), any address in flash map space can be looked up.

Return
  • SPI_FLASH_CACHE2PHYS_FAIL If cache address is outside flash cache region, or the address is not mapped.
  • Otherwise, returns physical offset in flash
Parameters
  • cached: Pointer to flashed cached memory.

const void *spi_flash_phys2cache(size_t phys_offs, spi_flash_mmap_memory_t memory)

Given a physical offset in flash, return the address where it is mapped in the memory space.

Physical address does not have to have been assigned via spi_flash_mmap(), any address in flash can be looked up.

Note
Only the first matching cache address is returned. If MMU flash cache table is configured so multiple entries point to the same physical address, there may be more than one cache address corresponding to that physical address. It is also possible for a single physical address to be mapped to both the IROM and DROM regions.
Note
This function doesn’t impose any alignment constraints, but if memory argument is SPI_FLASH_MMAP_INST and phys_offs is not 4-byte aligned, then reading from the returned pointer will result in a crash.
Return
  • NULL if the physical address is invalid or not mapped to flash cache of the specified memory type.
  • Cached memory address (in IROM or DROM space) corresponding to phys_offs.
Parameters
  • phys_offs: Physical offset in flash memory to look up.
  • memory: Memory type to look up a flash cache address mapping for (IROM or DROM)

bool spi_flash_cache_enabled()

Check at runtime if flash cache is enabled on both CPUs.

Return
true if both CPUs have flash cache enabled, false otherwise.

esp_partition_iterator_t esp_partition_find(esp_partition_type_t type, esp_partition_subtype_t subtype, const char *label)

Find partition based on one or more parameters.

Return
iterator which can be used to enumerate all the partitions found, or NULL if no partitions were found. Iterator obtained through this function has to be released using esp_partition_iterator_release when not used any more.
Parameters
  • type: Partition type, one of esp_partition_type_t values
  • subtype: Partition subtype, one of esp_partition_subtype_t values. To find all partitions of given type, use ESP_PARTITION_SUBTYPE_ANY.
  • label: (optional) Partition label. Set this value if looking for partition with a specific name. Pass NULL otherwise.

const esp_partition_t *esp_partition_find_first(esp_partition_type_t type, esp_partition_subtype_t subtype, const char *label)

Find first partition based on one or more parameters.

Return
pointer to esp_partition_t structure, or NULL if no partition is found. This pointer is valid for the lifetime of the application.
Parameters
  • type: Partition type, one of esp_partition_type_t values
  • subtype: Partition subtype, one of esp_partition_subtype_t values. To find all partitions of given type, use ESP_PARTITION_SUBTYPE_ANY.
  • label: (optional) Partition label. Set this value if looking for partition with a specific name. Pass NULL otherwise.

const esp_partition_t *esp_partition_get(esp_partition_iterator_t iterator)

Get esp_partition_t structure for given partition.

Return
pointer to esp_partition_t structure. This pointer is valid for the lifetime of the application.
Parameters
  • iterator: Iterator obtained using esp_partition_find. Must be non-NULL.

esp_partition_iterator_t esp_partition_next(esp_partition_iterator_t iterator)

Move partition iterator to the next partition found.

Any copies of the iterator will be invalid after this call.

Return
NULL if no partition was found, valid esp_partition_iterator_t otherwise.
Parameters
  • iterator: Iterator obtained using esp_partition_find. Must be non-NULL.

void esp_partition_iterator_release(esp_partition_iterator_t iterator)

Release partition iterator.

Parameters
  • iterator: Iterator obtained using esp_partition_find. Must be non-NULL.

esp_err_t esp_partition_read(const esp_partition_t *partition, size_t src_offset, void *dst, size_t size)

Read data from the partition.

Return
ESP_OK, if data was read successfully; ESP_ERR_INVALID_ARG, if src_offset exceeds partition size; ESP_ERR_INVALID_SIZE, if read would go out of bounds of the partition; or one of error codes from lower-level flash driver.
Parameters
  • partition: Pointer to partition structure obtained using esp_partition_find_first or esp_partition_get. Must be non-NULL.
  • dst: Pointer to the buffer where data should be stored. Pointer must be non-NULL and buffer must be at least ‘size’ bytes long.
  • src_offset: Address of the data to be read, relative to the beginning of the partition.
  • size: Size of data to be read, in bytes.

esp_err_t esp_partition_write(const esp_partition_t *partition, size_t dst_offset, const void *src, size_t size)

Write data to the partition.

Before writing data to flash, corresponding region of flash needs to be erased. This can be done using esp_partition_erase_range function.

Partitions marked with an encryption flag will automatically be written via the spi_flash_write_encrypted() function. If writing to an encrypted partition, all write offsets and lengths must be multiples of 16 bytes. See the spi_flash_write_encrypted() function for more details. Unencrypted partitions do not have this restriction.

Note
Prior to writing to flash memory, make sure it has been erased with esp_partition_erase_range call.
Return
ESP_OK, if data was written successfully; ESP_ERR_INVALID_ARG, if dst_offset exceeds partition size; ESP_ERR_INVALID_SIZE, if write would go out of bounds of the partition; or one of error codes from lower-level flash driver.
Parameters
  • partition: Pointer to partition structure obtained using esp_partition_find_first or esp_partition_get. Must be non-NULL.
  • dst_offset: Address where the data should be written, relative to the beginning of the partition.
  • src: Pointer to the source buffer. Pointer must be non-NULL and buffer must be at least ‘size’ bytes long.
  • size: Size of data to be written, in bytes.

esp_err_t esp_partition_erase_range(const esp_partition_t *partition, uint32_t start_addr, uint32_t size)

Erase part of the partition.

Return
ESP_OK, if the range was erased successfully; ESP_ERR_INVALID_ARG, if iterator or dst are NULL; ESP_ERR_INVALID_SIZE, if erase would go out of bounds of the partition; or one of error codes from lower-level flash driver.
Parameters
  • partition: Pointer to partition structure obtained using esp_partition_find_first or esp_partition_get. Must be non-NULL.
  • start_addr: Address where erase operation should start. Must be aligned to 4 kilobytes.
  • size: Size of the range which should be erased, in bytes. Must be divisible by 4 kilobytes.

esp_err_t esp_partition_mmap(const esp_partition_t *partition, uint32_t offset, uint32_t size, spi_flash_mmap_memory_t memory, const void **out_ptr, spi_flash_mmap_handle_t *out_handle)

Configure MMU to map partition into data memory.

Unlike spi_flash_mmap function, which requires a 64kB aligned base address, this function doesn’t impose such a requirement. If offset results in a flash address which is not aligned to 64kB boundary, address will be rounded to the lower 64kB boundary, so that mapped region includes requested range. Pointer returned via out_ptr argument will be adjusted to point to the requested offset (not necessarily to the beginning of mmap-ed region).

To release mapped memory, pass handle returned via out_handle argument to spi_flash_munmap function.

Return
ESP_OK, if successful
Parameters
  • partition: Pointer to partition structure obtained using esp_partition_find_first or esp_partition_get. Must be non-NULL.
  • offset: Offset from the beginning of partition where mapping should start.
  • size: Size of the area to be mapped.
  • memory: Memory space where the region should be mapped
  • out_ptr: Output, pointer to the mapped memory region
  • out_handle: Output, handle which should be used for spi_flash_munmap call

static bool esp_flash_encryption_enabled(void)

Is flash encryption currently enabled in hardware?

Flash encryption is enabled if the FLASH_CRYPT_CNT efuse has an odd number of bits set.

Return
true if flash encryption is enabled.

实现细节

为了执行某些 flash 操作,我们需要确保两个 CPU 在 flash 操作期间都没有从 flash 运行任何代码。在单核中,这非常简单:禁止中断/调度器,然后执行 flash 操作。在双核中,所谓有点复杂。我们需要确保其它 CPU 没有从 flash 上面运行任何代码。

当 SPI flahs API 在 CPU A(可以是 PRO 或者 APP)上被调用,我们使用 API esp_ipc_call 在 CPU B 上启动函数 spi_flash_op_block_func。这个 API 会唤醒 CPU B 上的高优先级任务,告诉它取执行所给函数,即 spi_flash_op_block_func。该函数子啊 CPU B 上 When SPI flash API is called on CPU A (can be PRO or APP), we start spi_flash_op_block_func function on CPU B using esp_ipc_call API. This API wakes up high priority task on CPU B and tells it to execute given function, in this case spi_flash_op_block_func. This function disables cache on CPU B and signals that cache is disabled by setting s_flash_op_can_start flag. Then the task on CPU A disables cache as well, and proceeds to execute flash operation.

While flash operation is running, interrupts can still run on CPUs A and B. We assume that all interrupt code is placed into RAM. Once interrupt allocation API is added, we should add a flag to request interrupt to be disabled for the duration of flash operations.

Once flash operation is complete, function on CPU A sets another flag, s_flash_op_complete, to let the task on CPU B know that it can re-enable cache and release the CPU. Then the function on CPU A re-enables the cache on CPU A as well and returns control to the calling code.

Additionally, all API functions are protected with a mutex (s_flash_op_mutex).

In a single core environment (CONFIG_FREERTOS_UNICORE enabled), we simply disable both caches, no inter-CPU communication takes place.

非易失性存储器(NVS)库

简介

非易失性存储器(Non-volatile storage,NVS)库被设计用于在 flash 中存储键值对。本节介绍一些在 NVS 中所使用的概念。

Underlying storage

当前,NVS 通过 spi_flash_{read|write|erase} API 使用了一部分主 flash 存储器。该库使用第一个分区 —— 其类型是 data,子类型是 nvs

该库将来可能会添加其它的存储器后端,让数据可以保存在另一个 flash(I2C 或者 SPI)芯片、RTC、FRAM 等中。

注解

如果 NVS 分区被截断了(例如分区表布局文件被修改),它上面的内容必修被擦除。ESP-IDF 构建系统提供了一个 make erase_flash 目标来擦除 flash 芯片上的所有内容。

键和值

NVS 操作的对象是键值对。键是 ASCII 字符串,当前的最大键长度是 15 个字符。值可以是下面某一种类型:

  • 整数值 uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t
  • 以零结尾的字符串
  • 长度可变的二进制数据 (blob)

在今后也可能支持其它类型,例如 floatdouble

键必须是唯一的。向一个已存在的键写值时的行为如下:

  • 如果新值与就指类型相同,则将值更新
  • 如果新值与就指类型相同,则返回一个错误

读取值时会执行能够数据类型检查。如果读操作的数据类型与值的数据类型不匹配,则返回一个错误。

命名空间

为了减小不同组件间命令冲突的可能性,NVS 将每个键值对分配到一个命名空间中。命名空间的名字与键名的规则相同,即最长 15 个字符。命名空间的名字在执行 nvs_open 调用时指定。这个调用会返回一个不透明的句柄,这个句柄在随后调用函数 nvs_read_*`nvs_write_*nvs_commit 时使用。这样,句柄与命名空间相关联,键名就不会与其它组件具有相同名字的键冲突。

安全、篡改和鲁棒性

NVS 库没有实现篡改预防策略。任何可以在物理上访问芯片的代码都可以更改、擦除或添加新的键值对。

NVS 与 ESP32 的 flash 加密系统是兼容的,它可以以加密形式存储键值对。一些元数据,例如页状态、私立入口(individual entries)的写/擦除标志,不能被加密,因为因为它们表示为有效访问和操作 flash 存储器的比特。Flash 加密可以阻止某些形式的修改:

  • 使用任意值替换键或值
  • 改变值的数据类型

下列形式的修改即使在使用了 flash 加密依然可以:

  • 完整地擦除页,移除该页中擦除的所有键值对
  • 破坏(corrupting)页中的数据,发生这种情况将会造成页被自动擦除
  • 回滚 flash 存储器的状态到某个早期快照
  • 合并 flash 存储器的两个快照,回滚一些键值对到某个早起状态(即使当前的设计还不支持 — TODO)

当 flash 存储器处于非一致性状态时,库会尝试取从这些条件中恢复。特别的,你可以在任何时间、任何点将设备断电再上电,除了新键值对(即该键值对正在写时断电了),这一般不会造成数据丢失。库能够能够使用 flash 存储器中的任何随机数进行恰当地初始化。

内部
键值对的记录

NVS 按顺序存储键值对,新的键值对被添加到末尾。当任意所给键的值被更新时,新的键值对别添加到记录(log)的默认,旧的键值对被标记未已擦除。

页和条目

NVS 库在操作时主要使用了两种实体:页(page)和条目(entry)。页是一个存储整个记录中一部分内容的逻辑结构。逻辑页对应一个 flash 存储器的扇区。正在使用的页有一个与之绑定咋一起的 序列号(sequence number)。序列号反映了也的顺序。序列号越大表示页创建的时间越晚。每个页可以处于下列的某种状态:

空/未初始化(Empty/uninitialized)
页的 flash 存储器是空的,即所有的字节都是``0xff``。在这种状态时,页不能用于存储任何数据,也没有序列号。
有效(Active)
Flash 存储器被初始化了,页的头部被写到 flash 中,且页有一个序列号。页有一些可以被写入的空的条目和数据。大多数时候,页都处于这种状态。
满(Full)
Flash 存储器处于一个一致性转台,且被写满了键值对。向该页新写的键值对将失败。此时仍然可以将某些键值对标记为已擦除。
擦除中(Erasing)
未被标记未已擦除的键值对正在被移动到另一页,然后该也就可以被擦除。这是一个临时状态,即当任何 API 调用返回时页都不会处于该状态。如果遇到突然断电,移动-擦除操作将在下一次上电后继续。
被破坏(Corrupted)
页的头部包含无效的数据,对页数据的解析将会取消。之前写入该页的任何数据都不可访问。相应的 flash 扇区不会立即擦除,将会保持为 未初始化 状态,以供今后使用。这有助于进行调试。

从 flash 扇区到逻辑页的映射没有任何特殊的顺序。库将会检查每个 flash 扇区中的页序列号,然后基于这些数字将页按照形成一个链表。

+--------+     +--------+     +--------+     +--------+
| Page 1 |     | Page 2 |     | Page 3 |     | Page 4 |
| Full   +---> | Full   +---> | Active |     | Empty  |   <- states
| #11    |     | #12    |     | #14    |     |        |   <- sequence numbers
+---+----+     +----+---+     +----+---+     +---+----+
    |               |              |             |
    |               |              |             |
    |               |              |             |
+---v------+  +-----v----+  +------v---+  +------v---+
| Sector 3 |  | Sector 0 |  | Sector 2 |  | Sector 1 |    <- physical sectors
+----------+  +----------+  +----------+  +----------+
页的结构

现在我们假设 flash 扇区的大小是 4096 字节,且 ESP32 的 flash 加密硬件是以 32 字节块为单位进行操作的。为了适应扇区大小不相同的 flash 芯片,可以在编译时(例如通过配置菜单)引入一些可配置的设置(尽管不清楚系统其它组件,例如 SPI flash 驱动和 SPI flash cache,是否可以支持其它的大小)。

页由三部分组成:头部、条目状态位映射(bitmap)和条目自身。为了与 ESP32 的 flash 加密兼容,条目的大小是 32 字节。对于整数类型,条目拥有一个键值对。对于字符串和块(blob),条目拥有部分键值对(更多的在条目的结构体描述符中)。

下列框图描述了页的结构。原括号中的数字表示每部分的大小(以字节为单位)。

+-----------+--------------+-------------+-----------+
| State (4) | Seq. no. (4) | Unused (20) | CRC32 (4) | Header (32)
+-----------+--------------+-------------+-----------+
|                Entry state bitmap (32)             |
+----------------------------------------------------+
|                       Entry 0 (32)                 |
+----------------------------------------------------+
|                       Entry 1 (32)                 |
+----------------------------------------------------+
/                                                    /
/                                                    /
+----------------------------------------------------+
|                       Entry 125 (32)               |
+----------------------------------------------------+

页的头部和条目状态位映射通常被写到 flash 的未加密部分。如果使用了 ESP32 的 flash 加密功能,条目会被加密。

页的状态是这样定义的:向某些比特写 0 可以改变状态。因此,一般没有必要通过擦除页来改变页的状态,除非要改变的状态是 已擦除 状态。

头部中计算的 CRC32 值不包括状态值(底 4 ~ 28 字节)。未使用部分当前使用 0xff 填充。今后的库可能会在这里存储格式化版本。

下面的章节描述了条目状态位映射和条目自身的结构。

条目和条目状态位映射

每个条目可以处于一下三个状态之一。每个状态都由条目状态位映射中的两个比特表示。位映射中的最后四个比特(256 - 2 * 126)未被使用。

空 Empty (2’b11)
所指定的条目还没有写入任何东西。这是一个未初始化状态(所有的字节都是 0xff)。
已写入 Written (2’b10)
一个键值对(或者跨越多个条目的键值对的一部分)已被写入到条目。
已擦除 Erased (2’b00)
该条目中的键值对被丢弃。该条目中的内容将不会被解析。
条目的结构

For values of primitive types (currently integers from 1 to 8 bytes long), entry holds one key-value pair. For string and blob types, entry holds part of the whole key-value pair. In case when a key-value pair spans multiple entries, all entries are stored in the same page.

+--------+----------+----------+---------+-----------+---------------+----------+
| NS (1) | Type (1) | Span (1) | Rsv (1) | CRC32 (4) |    Key (16)   | Data (8) |
+--------+----------+----------+---------+-----------+---------------+----------+

                                               +--------------------------------+
                         +->    Fixed length:  | Data (8)                       |
                         |                     +--------------------------------+
          Data format ---+
                         |                     +----------+---------+-----------+
                         +-> Variable length:  | Size (2) | Rsv (2) | CRC32 (4) |
                                               +----------+---------+-----------+

Individual fields in entry structure have the following meanings:

NS
Namespace index for this entry. See section on namespaces implementation for explanation of this value.
Type
One byte indicating data type of value. See ItemType enumeration in nvs_types.h for possible values.
Span
Number of entries used by this key-value pair. For integer types, this is equal to 1. For strings and blobs this depends on value length.
Rsv
Unused field, should be 0xff.
CRC32
Checksum calculated over all the bytes in this entry, except for the CRC32 field itself.
Key
Zero-terminated ASCII string containing key name. Maximum string length is 15 bytes, excluding zero terminator.
Data
For integer types, this field contains the value itself. If the value itself is shorter than 8 bytes it is padded to the right, with unused bytes filled with 0xff. For string and blob values, these 8 bytes hold additional data about the value, described next:
Size
(Only for strings and blobs.) Size, in bytes, of actual data. For strings, this includes zero terminator.
CRC32
(Only for strings and blobs.) Checksum calculated over all bytes of data.

Variable length values (strings and blobs) are written into subsequent entries, 32 bytes per entry. Span field of the first entry indicates how many entries are used.

命名空间

As mentioned above, each key-value pair belongs to one of the namespaces. Namespaces identifiers (strings) are stored as keys of key-value pairs in namespace with index 0. Values corresponding to these keys are indexes of these namespaces.

+-------------------------------------------+
| NS=0 Type=uint8_t Key="wifi" Value=1      |   Entry describing namespace "wifi"
+-------------------------------------------+
| NS=1 Type=uint32_t Key="channel" Value=6  |   Key "channel" in namespace "wifi"
+-------------------------------------------+
| NS=0 Type=uint8_t Key="pwm" Value=2       |   Entry describing namespace "pwm"
+-------------------------------------------+
| NS=2 Type=uint16_t Key="channel" Value=20 |   Key "channel" in namespace "pwm"
+-------------------------------------------+
Item 哈希链表

To reduce the number of reads performed from flash memory, each member of Page class maintains a list of pairs: (item index; item hash). This list makes searches much quicker. Instead of iterating over all entries, reading them from flash one at a time, Page::findItem first performs search for item hash in the hash list. This gives the item index within the page, if such an item exists. Due to a hash collision it is possible that a different item will be found. This is handled by falling back to iteration over items in flash.

Each node in hash list contains a 24-bit hash and 8-bit item index. Hash is calculated based on item namespace and key name. CRC32 is used for calculation, result is truncated to 24 bits. To reduce overhead of storing 32-bit entries in a linked list, list is implemented as a doubly-linked list of arrays. Each array holds 29 entries, for the total size of 128 bytes, together with linked list pointers and 32-bit count field. Minimal amount of extra RAM useage per page is therefore 128 bytes, maximum is 640 bytes.

应用程序示例

下面这两个示例是在 ESP-IDF 示例的 storage 目录提供的:

storage/nvs_rw_value

演示了如何使用 NVS 读写一个整数值。

该值记录了 ESP32 模块重启的次数。由于它是写到 NVS 中的,因此重启后该值还保留着。

示例还演示了如何检查读/写操作是否成功,或者某个值在 NVS 中是否被初始化了。 提供的诊断消息可用于帮助跟踪程序流、采集问题。

storage/nvs_rw_blob

演示了如何使用 NVS 读/写一个整数值和一块数据(二进制大对象,blob),让它们在 ESP32 模块重启后依然保存着。

  • 值 - 跟踪 ESP32 模块软件/硬件重启的次数.
  • 块(blob) - 包含一个记录模块运行时间的表格。程序会将表格由 NVS 读取到动态分配的 RAM。每次手工触发软件复位时,新的运行时间被添加到表格中,并被写回 NVS。触发是通过下拉 GPIO0 完成的。

示例还演示了如何检查读/写操作是否成功。

API 参考手册
ESP_ERR_NVS_BASE

Starting number of error codes

ESP_ERR_NVS_NOT_INITIALIZED

The storage driver is not initialized

ESP_ERR_NVS_NOT_FOUND

Id namespace doesn’t exist yet and mode is NVS_READONLY

ESP_ERR_NVS_TYPE_MISMATCH

The type of set or get operation doesn’t match the type of value stored in NVS

ESP_ERR_NVS_READ_ONLY

Storage handle was opened as read only

ESP_ERR_NVS_NOT_ENOUGH_SPACE

There is not enough space in the underlying storage to save the value

ESP_ERR_NVS_INVALID_NAME

Namespace name doesn’t satisfy constraints

ESP_ERR_NVS_INVALID_HANDLE

Handle has been closed or is NULL

ESP_ERR_NVS_REMOVE_FAILED

The value wasn’t updated because flash write operation has failed. The value was written however, and update will be finished after re-initialization of nvs, provided that flash operation doesn’t fail again.

ESP_ERR_NVS_KEY_TOO_LONG

Key name is too long

ESP_ERR_NVS_PAGE_FULL

Internal error; never returned by nvs_ API functions

ESP_ERR_NVS_INVALID_STATE

NVS is in an inconsistent state due to a previous error. Call nvs_flash_init and nvs_open again, then retry.

ESP_ERR_NVS_INVALID_LENGTH

String or blob length is not sufficient to store data

ESP_ERR_NVS_NO_FREE_PAGES

NVS partition doesn’t contain any empty pages. This may happen if NVS partition was truncated. Erase the whole partition and call nvs_flash_init again.

类型定义
typedef uint32_t nvs_handle

Opaque pointer type representing non-volatile storage handle

枚举
enum nvs_open_mode

Mode of opening the non-volatile storage.

Values:

NVS_READONLY

Read only

NVS_READWRITE

Read and write

函数
esp_err_t nvs_flash_init(void)

Initialize NVS flash storage with layout given in the partition table.

Return
  • ESP_OK if storage was successfully initialized.
  • ESP_ERR_NVS_NO_FREE_PAGES if the NVS storage contains no empty pages (which may happen if NVS partition was truncated)
  • one of the error codes from the underlying flash storage driver

esp_err_t nvs_open(const char *name, nvs_open_mode open_mode, nvs_handle *out_handle)

Open non-volatile storage with a given namespace.

Multiple internal ESP-IDF and third party application modules can store their key-value pairs in the NVS module. In order to reduce possible conflicts on key names, each module can use its own namespace.

Return
  • ESP_OK if storage handle was opened successfully
  • ESP_ERR_NVS_NOT_INITIALIZED if the storage driver is not initialized
  • ESP_ERR_NVS_NOT_FOUND id namespace doesn’t exist yet and mode is NVS_READONLY
  • ESP_ERR_NVS_INVALID_NAME if namespace name doesn’t satisfy constraints
  • other error codes from the underlying storage driver
Parameters
  • name: Namespace name. Maximal length is determined by the underlying implementation, but is guaranteed to be at least 16 characters. Shouldn’t be empty.
  • open_mode: NVS_READWRITE or NVS_READONLY. If NVS_READONLY, will open a handle for reading only. All write requests will be rejected for this handle.
  • out_handle: If successful (return code is zero), handle will be returned in this argument.

esp_err_t nvs_set_i8(nvs_handle handle, const char *key, int8_t value)

set value for given key

This family of functions set value for the key, given its name. Note that actual storage will not be updated until nvs_commit function is called.

Return
  • ESP_OK if value was set successfully
  • ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL
  • ESP_ERR_NVS_READ_ONLY if storage handle was opened as read only
  • ESP_ERR_NVS_INVALID_NAME if key name doesn’t satisfy constraints
  • ESP_ERR_NVS_NOT_ENOUGH_SPACE if there is not enough space in the underlying storage to save the value
  • ESP_ERR_NVS_REMOVE_FAILED if the value wasn’t updated because flash write operation has failed. The value was written however, and update will be finished after re-initialization of nvs, provided that flash operation doesn’t fail again.
Parameters
  • handle: Handle obtained from nvs_open function. Handles that were opened read only cannot be used.
  • key: Key name. Maximal length is determined by the underlying implementation, but is guaranteed to be at least 16 characters. Shouldn’t be empty.
  • value: The value to set.

esp_err_t nvs_set_u8(nvs_handle handle, const char *key, uint8_t value)
esp_err_t nvs_set_i16(nvs_handle handle, const char *key, int16_t value)
esp_err_t nvs_set_u16(nvs_handle handle, const char *key, uint16_t value)
esp_err_t nvs_set_i32(nvs_handle handle, const char *key, int32_t value)
esp_err_t nvs_set_u32(nvs_handle handle, const char *key, uint32_t value)
esp_err_t nvs_set_i64(nvs_handle handle, const char *key, int64_t value)
esp_err_t nvs_set_u64(nvs_handle handle, const char *key, uint64_t value)
esp_err_t nvs_set_str(nvs_handle handle, const char *key, const char *value)
esp_err_t nvs_set_blob(nvs_handle handle, const char *key, const void *value, size_t length)

set variable length binary value for given key

This family of functions set value for the key, given its name. Note that actual storage will not be updated until nvs_commit function is called.

Return
  • ESP_OK if value was set successfully
  • ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL
  • ESP_ERR_NVS_READ_ONLY if storage handle was opened as read only
  • ESP_ERR_NVS_INVALID_NAME if key name doesn’t satisfy constraints
  • ESP_ERR_NVS_NOT_ENOUGH_SPACE if there is not enough space in the underlying storage to save the value
  • ESP_ERR_NVS_REMOVE_FAILED if the value wasn’t updated because flash write operation has failed. The value was written however, and update will be finished after re-initialization of nvs, provided that flash operation doesn’t fail again.
Parameters
  • handle: Handle obtained from nvs_open function. Handles that were opened read only cannot be used.
  • key: Key name. Maximal length is determined by the underlying implementation, but is guaranteed to be at least 16 characters. Shouldn’t be empty.
  • value: The value to set.
  • length: length of binary value to set, in bytes.

esp_err_t nvs_get_i8(nvs_handle handle, const char *key, int8_t *out_value)

get value for given key

These functions retrieve value for the key, given its name. If key does not exist, or the requested variable type doesn’t match the type which was used when setting a value, an error is returned.

In case of any error, out_value is not modified.

All functions expect out_value to be a pointer to an already allocated variable of the given type.

// Example of using nvs_get_i32:
int32_t max_buffer_size = 4096; // default value
esp_err_t err = nvs_get_i32(my_handle, "max_buffer_size", &max_buffer_size);
assert(err == ESP_OK || err == ESP_ERR_NVS_NOT_FOUND);
// if ESP_ERR_NVS_NOT_FOUND was returned, max_buffer_size will still
// have its default value.

Return
  • ESP_OK if the value was retrieved successfully
  • ESP_ERR_NVS_NOT_FOUND if the requested key doesn’t exist
  • ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL
  • ESP_ERR_NVS_INVALID_NAME if key name doesn’t satisfy constraints
  • ESP_ERR_NVS_INVALID_LENGTH if length is not sufficient to store data
Parameters
  • handle: Handle obtained from nvs_open function.
  • key: Key name. Maximal length is determined by the underlying implementation, but is guaranteed to be at least 16 characters. Shouldn’t be empty.
  • out_value: Pointer to the output value. May be NULL for nvs_get_str and nvs_get_blob, in this case required length will be returned in length argument.

esp_err_t nvs_get_u8(nvs_handle handle, const char *key, uint8_t *out_value)
esp_err_t nvs_get_i16(nvs_handle handle, const char *key, int16_t *out_value)
esp_err_t nvs_get_u16(nvs_handle handle, const char *key, uint16_t *out_value)
esp_err_t nvs_get_i32(nvs_handle handle, const char *key, int32_t *out_value)
esp_err_t nvs_get_u32(nvs_handle handle, const char *key, uint32_t *out_value)
esp_err_t nvs_get_i64(nvs_handle handle, const char *key, int64_t *out_value)
esp_err_t nvs_get_u64(nvs_handle handle, const char *key, uint64_t *out_value)
esp_err_t nvs_get_str(nvs_handle handle, const char *key, char *out_value, size_t *length)

get value for given key

These functions retrieve value for the key, given its name. If key does not exist, or the requested variable type doesn’t match the type which was used when setting a value, an error is returned.

In case of any error, out_value is not modified.

All functions expect out_value to be a pointer to an already allocated variable of the given type.

nvs_get_str and nvs_get_blob functions support WinAPI-style length queries. To get the size necessary to store the value, call nvs_get_str or nvs_get_blob with zero out_value and non-zero pointer to length. Variable pointed to by length argument will be set to the required length. For nvs_get_str, this length includes the zero terminator. When calling nvs_get_str and nvs_get_blob with non-zero out_value, length has to be non-zero and has to point to the length available in out_value. It is suggested that nvs_get/set_str is used for zero-terminated C strings, and nvs_get/set_blob used for arbitrary data structures.

// Example (without error checking) of using nvs_get_str to get a string into dynamic array:
size_t required_size;
nvs_get_str(my_handle, "server_name", NULL, &required_size);
char* server_name = malloc(required_size);
nvs_get_str(my_handle, "server_name", server_name, &required_size);

// Example (without error checking) of using nvs_get_blob to get a binary data
into a static array:
uint8_t mac_addr[6];
size_t size = sizeof(mac_addr);
nvs_get_blob(my_handle, "dst_mac_addr", mac_addr, &size);

Return
  • ESP_OK if the value was retrieved successfully
  • ESP_ERR_NVS_NOT_FOUND if the requested key doesn’t exist
  • ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL
  • ESP_ERR_NVS_INVALID_NAME if key name doesn’t satisfy constraints
  • ESP_ERR_NVS_INVALID_LENGTH if length is not sufficient to store data
Parameters
  • handle: Handle obtained from nvs_open function.
  • key: Key name. Maximal length is determined by the underlying implementation, but is guaranteed to be at least 16 characters. Shouldn’t be empty.
  • out_value: Pointer to the output value. May be NULL for nvs_get_str and nvs_get_blob, in this case required length will be returned in length argument.
  • length: A non-zero pointer to the variable holding the length of out_value. In case out_value a zero, will be set to the length required to hold the value. In case out_value is not zero, will be set to the actual length of the value written. For nvs_get_str this includes zero terminator.

esp_err_t nvs_get_blob(nvs_handle handle, const char *key, void *out_value, size_t *length)
esp_err_t nvs_erase_key(nvs_handle handle, const char *key)

Erase key-value pair with given key name.

Note that actual storage may not be updated until nvs_commit function is called.

Return
  • ESP_OK if erase operation was successful
  • ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL
  • ESP_ERR_NVS_READ_ONLY if handle was opened as read only
  • ESP_ERR_NVS_NOT_FOUND if the requested key doesn’t exist
  • other error codes from the underlying storage driver
Parameters
  • handle: Storage handle obtained with nvs_open. Handles that were opened read only cannot be used.
  • key: Key name. Maximal length is determined by the underlying implementation, but is guaranteed to be at least 16 characters. Shouldn’t be empty.

esp_err_t nvs_erase_all(nvs_handle handle)

Erase all key-value pairs in a namespace.

Note that actual storage may not be updated until nvs_commit function is called.

Return
  • ESP_OK if erase operation was successful
  • ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL
  • ESP_ERR_NVS_READ_ONLY if handle was opened as read only
  • other error codes from the underlying storage driver
Parameters
  • handle: Storage handle obtained with nvs_open. Handles that were opened read only cannot be used.

esp_err_t nvs_commit(nvs_handle handle)

Write any pending changes to non-volatile storage.

After setting any values, nvs_commit() must be called to ensure changes are written to non-volatile storage. Individual implementations may write to storage at other times, but this is not guaranteed.

Return
  • ESP_OK if the changes have been written successfully
  • ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL
  • other error codes from the underlying storage driver
Parameters
  • handle: Storage handle obtained with nvs_open. Handles that were opened read only cannot be used.

void nvs_close(nvs_handle handle)

Close the storage handle and free any allocated resources.

This function should be called for each handle opened with nvs_open once the handle is not in use any more. Closing the handle may not automatically write the changes to nonvolatile storage. This has to be done explicitly using nvs_commit function. Once this function is called on a handle, the handle should no longer be used.

Parameters
  • handle: Storage handle to close

虚拟文件系统(VFS)组件

概述

虚拟文件系统(VFS)组件为驱动程序提供了统一的接口,可以执行类似文件对象的操作。这既可以是一个真实文件系统(FAT、SPIFFS 等),也可以是暴露了类似文件接口的设备驱动程序。

该组件允许 C 库函数(例如 fopen、fprintf)与文件系统驱动程序一起工作。在顶层,每个文件系统驱动程序都关联了某些路径前缀。当某个 C 库函数需要打开文件时,VFS 组件会查找与文件的路径相关的文件系统驱动,然后将调用转给那个驱动。

例如,你可以通过前缀 /fat 注册一个 FAT 文件系统,然后调用 fopen("/fat/file.txt", "w")。VFS 组件将会调用 FAT 驱动 open 函数,并将参数 /file.txt (以及一些 mode 标志)传递给它。随后对返回的 FILE* 文件流进行调用的 C 库函数也会被转给 FAT 驱动。

FS 注册

要注册一个 FS 驱动,应用程序需要定义一个 esp_vfs_t 结构体的实例,并初始化它里面的函数指针

esp_vfs_t myfs = {
    .fd_offset = 0,
    .flags = ESP_VFS_FLAG_DEFAULT,
    .write = &myfs_write,
    .open = &myfs_open,
    .fstat = &myfs_fstat,
    .close = &myfs_close,
    .read = &myfs_read,
};

ESP_ERROR_CHECK(esp_vfs_register("/data", &myfs, NULL));

你可以使用的 API 依赖于 FS 驱动程序申明 API 的方式,例如 read, write, 等, 或 read_p, ``write_p``等。

情形 1: API 函数定义时没有额外的上下文指针 (FS driver is a singleton):

size_t myfs_write(int fd, const void * data, size_t size);

// In definition of esp_vfs_t:
    .flags = ESP_VFS_FLAG_DEFAULT,
    .write = &myfs_write,
// ... other members initialized

// 当注册 FS 时,上下文指针(第三个参数)是 NULL:
ESP_ERROR_CHECK(esp_vfs_register("/data", &myfs, NULL));

情形 2: API 函数定义时有额外的上下文指针 (FS 驱动支持多个实例):

size_t myfs_write(myfs_t* fs, int fd, const void * data, size_t size);

// In definition of esp_vfs_t:
    .flags = ESP_VFS_FLAG_CONTEXT_PTR,
    .write_p = &myfs_write,
// ... other members initialized

// 当注册 FS 时,FS 上下文指针传递给了第三个参数
// (hypothetical myfs_mount function is used for illustrative purposes)
myfs_t* myfs_inst1 = myfs_mount(partition1->offset, partition1->size);
ESP_ERROR_CHECK(esp_vfs_register("/data1", &myfs, myfs_inst1));

// 可以注册另外的实例
myfs_t* myfs_inst2 = myfs_mount(partition2->offset, partition2->size);
ESP_ERROR_CHECK(esp_vfs_register("/data2", &myfs, myfs_inst2));
路径

每个注册的 FS 都有一个相关的前缀。这个前缀可以被看成是一个该分区的“挂载点”。

在已有的挂载点上注册另一个挂载点是不被支持的,其结果是未定义的。例如,下面是正确、支持的:

  • FS 1 on /data/fs1
  • FS 2 on /data/fs2

下面这种方法 不会正确工作

  • FS 1 on /data
  • FS 2 on /data/fs2

打开文件时,FS 驱动只会收到文件的相对路径,例如:

  • myfs 注册时的路径前缀是 /data
  • 应用程序调用 fopen("/data/config.json", ...)
  • 然后 VFS 组件将调用 myfs_open("/config.json", ...)
  • myfs 驱动将打开文件 /config.json

VFS 不会限制文件路径的总长度,但是会限制文件路径前缀的长度,即最多为 ESP_VFS_PATH_MAX 个字符。另外,FS 驱动可能自己会对文件名长度有限制。

文件描述符

建议在文件系统驱动中使用一个小的正整数作为文件描述符。VFS 组件假设用 CONFIG_MAX_FD_BITS 比特(默认值 12)就足够表示文件描述符。

如果文件系统配置了一个文件描述符偏移选项(一个常数值),该值应当被传递到结构体 esp_vfs_t 中的 fd_offset 字段。在处理指定的文件系统的 FS 时,VFS 组件会移除这个偏移量,使其处于小的正整数的范围。

尽管由 VFS 返回给 newlib 库的文件描述符通常对应用程序不可见,但是理解下面的这些细节有助于调试。由 VFS 组件返回的文件描述符由两部分组成:FS 驱动 ID 和实际的文件描述符。由于 newlib 用 16 比特的整数来存储文件描述符,VFS 组件在存储这两部分时也受到 16 比特的限制。

较低的 CONFIG_MAX_FD_BITS 比特被用于存储基于零(zero-based)的文件描述符。如果 FS 驱动有一个非零 fd_offset 字段, 则这个 fd_offset 会减去一个在文件系统的 open 调用时获取到的 FD,然后其结果存储到 FD 的低比特。高比特用于保存该 FS 在已注册的文件系统构成的内部表格中的索引。

当 VFS 组件从 newlib 接收到一个带有文件描述符的调用时,该文件描述符会被转换成文件系统相关的文件描述符。首先,FD 的高比特用于标识文件系统。然后,FS 的 fd_offset 字段与 fd 较低的 CONFIG_MAX_FD_BITS 比特相加,然后将其相加结果传递给文件系统的驱动。

   FD as seen by newlib                                    FD as seen by FS driver
                                              +-----+
+-------+---------------+                     |     |    +------------------------+
| FS id | Zero—based FD |     +---------------> sum +---->                        |
+---+---+------+--------+     |               |     |    +------------------------+
    |          |              |               +--^--+
    |          +--------------+                  |
    |                                            |
    |       +-------------+                      |
    |       | Table of    |                      |
    |       | registered  |                      |
    |       | filesystems |                      |
    |       +-------------+    +-------------+   |
    +------->  entry      +----> esp_vfs_t   |   |
    index   +-------------+    | structure   |   |
            |             |    |             |   |
            |             |    | + fd_offset +---+
            +-------------+    |             |
                               +-------------+
标准 IO 流 (stdin, stdout, stderr)

如果菜单配置选项 “UART for console output” 没有设置为 “None”,则 stdinstdoutstderr 会被配置成从 UART 中读写。UART0 或 UART1 均可以用作标准 IO。默认情况下使用的是 UART0,波特率是 115200,TX 引脚是 GPIO1,RX 引脚是 GPIO3。这些参数可以在配置菜单中修改。

stdoutstderr 中写时会发送字符到 UART 的传输 FIFO。从 stdin 中读会从 UART 的接收 FIFO 中取数据。

注意,向 stdoutstderr 中写时会阻塞,直到所有的字符都被放到 FIFO 中;从 stdin 中读是非阻塞的。从 UART 中读的函数会获取到 FIFO 中的所有存在的字符。例如,fscanf("%d\n", &var); 可能不会产生预期的结果。这个限制是临时的,且会在将 fcntl 添加到 VFS 接口后移除。

标准流和 FreeRTOS 任务

stdinstdoutstderrFILE 对象在所有的 FreeRTOS 任务中是共享的,但是执行这些对象的指针是存储在每个任务的 struct _reent 中的。下面的代码

fprintf(stderr, "42\n");

实际上会被(由预处理器)转换成:

fprintf(__getreent()->_stderr, “42n”);

其中,函数 __getreent() 返回一个指向 struct _reent (newlib/include/sys/reent.h#L370-L417>) 的指针。这个结构体分配在每个任务的 TCB 上。当任务被初始化时,struct _reent` 的成员 stdinstdoutstderr 的值被设置为 _GLOBAL_REENT``(FreeRTOS 启动前的一个结构体) ``_stdin_stdout_stderr

这样设计的结果:

  • 通过执行 stdin = fopen("/dev/uart/1", "r") 可以为任何所给任务设置 stdin````stdoutstderr
  • 使用 fclose 可以默认的 stdinstdoutstderr 将关闭 FILE 流对象 — 这会影响其它所有任务。
  • 如果要为新任务改变默认的 stdinstdoutstderr 流,则在创建任务前修改 _GLOBAL_REENT->_stdin (_stdout, _stderr)。
应用程序示例

Instructions

API 参考手册
ESP_VFS_PATH_MAX

Maximum length of path prefix (not including zero terminator)

ESP_VFS_FLAG_DEFAULT

Default value of flags member in esp_vfs_t structure.

ESP_VFS_FLAG_CONTEXT_PTR

Flag which indicates that FS needs extra context pointer in syscalls.

结构体
struct esp_vfs_t

VFS definition structure.

This structure should be filled with pointers to corresponding FS driver functions.

If the FS implementation has an option to use certain offset for all file descriptors, this value should be passed into fd_offset field. Otherwise VFS component will translate all FDs to start at zero offset.

Some FS implementations expect some state (e.g. pointer to some structure) to be passed in as a first argument. For these implementations, populate the members of this structure which have _p suffix, set flags member to ESP_VFS_FLAG_CONTEXT_PTR and provide the context pointer to esp_vfs_register function. If the implementation doesn’t use this extra argument, populate the members without _p suffix and set flags member to ESP_VFS_FLAG_DEFAULT.

If the FS driver doesn’t provide some of the functions, set corresponding members to NULL.

Public Members

int fd_offset

file descriptor offset, determined by the FS driver

int flags

ESP_VFS_FLAG_CONTEXT_PTR or ESP_VFS_FLAG_DEFAULT

函数
esp_err_t esp_vfs_register(const char *base_path, const esp_vfs_t *vfs, void *ctx)

Register a virtual filesystem for given path prefix.

Return
ESP_OK if successful, ESP_ERR_NO_MEM if too many VFSes are registered.
Parameters
  • base_path: file path prefix associated with the filesystem. Must be a zero-terminated C string, up to ESP_VFS_PATH_MAX characters long, and at least 2 characters long. Name must start with a “/” and must not end with “/”. For example, “/data” or “/dev/spi” are valid. These VFSes would then be called to handle file paths such as “/data/myfile.txt” or “/dev/spi/0”.
  • vfs: Pointer to esp_vfs_t, a structure which maps syscalls to the filesystem driver functions. VFS component doesn’t assume ownership of this pointer.
  • ctx: If vfs->flags has ESP_VFS_FLAG_CONTEXT_PTR set, a pointer which should be passed to VFS functions. Otherwise, NULL.

esp_err_t esp_vfs_unregister(const char *base_path)

Unregister a virtual filesystem for given path prefix

Return
ESP_OK if successful, ESP_ERR_INVALID_STATE if VFS for given prefix hasn’t been registered
Parameters
  • base_path: file prefix previously used in esp_vfs_register call

ssize_t esp_vfs_write(struct _reent *r, int fd, const void *data, size_t size)

These functions are to be used in newlib syscall table. They will be called by newlib when it needs to use any of the syscalls.

off_t esp_vfs_lseek(struct _reent *r, int fd, off_t size, int mode)
ssize_t esp_vfs_read(struct _reent *r, int fd, void *dst, size_t size)
int esp_vfs_open(struct _reent *r, const char *path, int flags, int mode)
int esp_vfs_close(struct _reent *r, int fd)
int esp_vfs_fstat(struct _reent *r, int fd, struct stat *st)
int esp_vfs_stat(struct _reent *r, const char *path, struct stat *st)
int esp_vfs_link(struct _reent *r, const char *n1, const char *n2)
int esp_vfs_unlink(struct _reent *r, const char *path)
int esp_vfs_rename(struct _reent *r, const char *src, const char *dst)
void esp_vfs_dev_uart_register()

add /dev/uart virtual filesystem driver

This function is called from startup code to enable serial output

FAT 文件系统的支持

ESP-IDF 使用 FatFs 库作为 FAT 文件系统。FatFs 库位于 fatfs 组件内。尽管它可以被直接访问,它的许多功能都可以通过 VFS 访问,即使用标准 C 库和 POSIX API。

此外,FatFs 已被修改,支持运行时可插拔磁盘 IO 层。这能让 FatFs 在运行时映射为物理磁盘。

FatFs with VFS

头文件 esp_vfs_fat.h 中定义的函数可以将 FatFs 与 VFS 连接起来。函数 esp_vfs_fat_register 分配了一个 FATFS 结构,并在 VSF 中注册了一个所给路径前缀。随后对以这个前缀作为开始的文件的操作将会被转发给 FatFs 的 API。函数 esp_vfs_fat_unregister_path 用于删除

function deletes the registration with VFS, and frees the FATFS structure.

Most applications will use the following flow when working with esp_vfs_fat_ functions:

  1. Call esp_vfs_fat_register, specifying path prefix where the filesystem has to be mounted (e.g. "/sdcard", "/spiflash"), FatFs drive number, and a variable which will receive a pointer to FATFS structure.
  2. Call ff_diskio_register function to register disk IO driver for the drive number used in step 1.
  3. Call f_mount function (and optionally f_fdisk, f_mkfs) to mount the filesystem using the same drive number which was passed to esp_vfs_fat_register. See FatFs documentation for more details.
  4. Call POSIX and C standard library functions to open, read, write, erase, copy files, etc. Use paths starting with the prefix passed to esp_vfs_register (such as "/sdcard/hello.txt").
  5. Optionally, call FatFs library functions directly. Use paths without a VFS prefix in this case ("/hello.txt").
  6. Close all open files.
  7. Call f_mount function for the same drive number, with NULL FATFS* argument, to unmount the filesystem.
  8. Call ff_diskio_register with NULL ff_diskio_impl_t* argument and the same drive number.
  9. Call esp_vfs_fat_unregister_path with the path where the file system is mounted to remove FatFs from VFS, and free the FATFS structure allocated on step 1.

Convenience functions, esp_vfs_fat_sdmmc_mount and esp_vfs_fat_sdmmc_unmount, which wrap these steps and also handle SD card initialization, are described in the next section.

esp_err_t esp_vfs_fat_register(const char *base_path, const char *fat_drive, size_t max_files, FATFS **out_fs)

Register FATFS with VFS component.

This function registers given FAT drive in VFS, at the specified base path. If only one drive is used, fat_drive argument can be an empty string. Refer to FATFS library documentation on how to specify FAT drive. This function also allocates FATFS structure which should be used for f_mount call.

Note
This function doesn’t mount the drive into FATFS, it just connects POSIX and C standard library IO function with FATFS. You need to mount desired drive into FATFS separately.
Return
  • ESP_OK on success
  • ESP_ERR_INVALID_STATE if esp_vfs_fat_register was already called
  • ESP_ERR_NO_MEM if not enough memory or too many VFSes already registered
Parameters
  • base_path: path prefix where FATFS should be registered
  • fat_drive: FATFS drive specification; if only one drive is used, can be an empty string
  • max_files: maximum number of files which can be open at the same time
  • out_fs: pointer to FATFS structure which can be used for FATFS f_mount call is returned via this argument.

esp_err_t esp_vfs_fat_unregister_path(const char *base_path)

Un-register FATFS from VFS.

Note
FATFS structure returned by esp_vfs_fat_register is destroyed after this call. Make sure to call f_mount function to unmount it before calling esp_vfs_fat_unregister_ctx. Difference between this function and the one above is that this one will release the correct drive, while the one above will release the last registered one
Return
  • ESP_OK on success
  • ESP_ERR_INVALID_STATE if FATFS is not registered in VFS
Parameters
  • base_path: path prefix where FATFS is registered. This is the same used when esp_vfs_fat_register was called

Using FatFs with VFS and SD cards

esp_vfs_fat.h header file also provides a convenience function to perform steps 1–3 and 7–9, and also handle SD card initialization: esp_vfs_fat_sdmmc_mount. This function does only limited error handling. Developers are encouraged to look at its source code and incorporate more advanced versions into production applications. esp_vfs_fat_sdmmc_unmount function unmounts the filesystem and releases resources acquired by esp_vfs_fat_sdmmc_mount.

esp_err_t esp_vfs_fat_sdmmc_mount(const char *base_path, const sdmmc_host_t *host_config, const sdmmc_slot_config_t *slot_config, const esp_vfs_fat_mount_config_t *mount_config, sdmmc_card_t **out_card)

Convenience function to get FAT filesystem on SD card registered in VFS.

This is an all-in-one function which does the following:

  • initializes SD/MMC peripheral with configuration in host_config
  • initializes SD/MMC card with configuration in slot_config
  • mounts FAT partition on SD/MMC card using FATFS library, with configuration in mount_config
  • registers FATFS library with VFS, with prefix given by base_prefix variable

This function is intended to make example code more compact. For real world applications, developers should implement the logic of probing SD card, locating and mounting partition, and registering FATFS in VFS, with proper error checking and handling of exceptional conditions.

Return
  • ESP_OK on success
  • ESP_ERR_INVALID_STATE if esp_vfs_fat_sdmmc_mount was already called
  • ESP_ERR_NO_MEM if memory can not be allocated
  • ESP_FAIL if partition can not be mounted
  • other error codes from SDMMC host, SDMMC protocol, or FATFS drivers
Parameters
  • base_path: path where partition should be registered (e.g. “/sdcard”)
  • host_config: pointer to structure describing SDMMC host
  • slot_config: pointer to structure with extra SDMMC slot configuration
  • mount_config: pointer to structure with extra parameters for mounting FATFS
  • out_card: if not NULL, pointer to the card information structure will be returned via this argument

struct esp_vfs_fat_mount_config_t

Configuration arguments for esp_vfs_fat_sdmmc_mount and esp_vfs_fat_spiflash_mount functions.

Public Members

bool format_if_mount_failed

If FAT partition can not be mounted, and this parameter is true, create partition table and format the filesystem.

int max_files

Max number of open files.

esp_err_t esp_vfs_fat_sdmmc_unmount()

Unmount FAT filesystem and release resources acquired using esp_vfs_fat_sdmmc_mount.

Return
  • ESP_OK on success
  • ESP_ERR_INVALID_STATE if esp_vfs_fat_sdmmc_mount hasn’t been called

FatFS disk IO layer

FatFs has been extended with an API to register disk IO driver at runtime.

Implementation of disk IO functions for SD/MMC cards is provided. It can be registered for the given FatFs drive number using ff_diskio_register_sdmmc function.

void ff_diskio_register(BYTE pdrv, const ff_diskio_impl_t *discio_impl)

Register or unregister diskio driver for given drive number.

When FATFS library calls one of disk_xxx functions for driver number pdrv, corresponding function in discio_impl for given pdrv will be called.

Parameters
  • pdrv: drive number
  • discio_impl: pointer to ff_diskio_impl_t structure with diskio functions or NULL to unregister and free previously registered drive

struct ff_diskio_impl_t

Structure of pointers to disk IO driver functions.

See FatFs documentation for details about these functions

Public Members

DSTATUS (*init)(BYTE pdrv)

disk initialization function

DSTATUS (*status)(BYTE pdrv)

disk status check function

DRESULT (*read)(BYTE pdrv, BYTE *buff, DWORD sector, UINT count)

sector read function

DRESULT (*write)(BYTE pdrv, const BYTE *buff, DWORD sector, UINT count)

sector write function

DRESULT (*ioctl)(BYTE pdrv, BYTE cmd, void *buff)

function to get info about disk and do some misc operations

void ff_diskio_register_sdmmc(BYTE pdrv, sdmmc_card_t *card)

Register SD/MMC diskio driver

Parameters
  • pdrv: drive number
  • card: pointer to sdmmc_card_t structure describing a card; card should be initialized before calling f_mount.

Wear Levelling APIs

Overview

Most of the flash devices and specially SPI flash devices that are used in ESP32 have sector based organization and have limited amount of erase/modification cycles per memory sector. To avoid situation when one sector reach the limit of erases when other sectors was used not often, we have made a component that avoid this situation. The wear levelling component share the amount of erases between all sectors in the memory without user interaction. The wear_levelling component contains APIs related to reading, writing, erasing, memory mapping data in the external SPI flash through the partition component. It also has higher-level APIs which work with FAT filesystem defined in the FAT filesystem.

The wear levelling component does not cache data in RAM. Write and erase functions modify flash directly, and flash contents is consistent when the function returns.

Wear Levelling access APIs

This is the set of APIs for working with data in flash:

  • wl_mount mount wear levelling module for defined partition
  • wl_unmount used to unmount levelling module
  • wl_erase_range used to erase range of addresses in flash
  • wl_write used to write data to the partition
  • wl_read used to read data from the partition
  • wl_size return size of avalible memory in bytes
  • wl_sector_size returns size of one sector

Generally, try to avoid using the raw wear levelling functions in favor of filesystem-specific functions.

Memory Size

The memory size calculated in the wear Levelling module based on parameters of partition. The module use few sectors of flash for internal data.

应用程序示例

An example which combines wear levelling driver with FATFS library is provided in examples/storage/wear_levelling directory. This example initializes the wear levelling driver, mounts FATFS partition, and writes and reads data from it using POSIX and C library APIs. See README.md file in the example directory for more information.

High level API 参考手册
函数
esp_err_t esp_vfs_fat_spiflash_mount(const char *base_path, const char *partition_label, const esp_vfs_fat_mount_config_t *mount_config, wl_handle_t *wl_handle)

Convenience function to initialize FAT filesystem in SPI flash and register it in VFS.

This is an all-in-one function which does the following:

  • finds the partition with defined partition_label. Partition label should be configured in the partition table.
  • initializes flash wear levelling library on top of the given partition
  • mounts FAT partition using FATFS library on top of flash wear levelling library
  • registers FATFS library with VFS, with prefix given by base_prefix variable

This function is intended to make example code more compact.

Return
  • ESP_OK on success
  • ESP_ERR_NOT_FOUND if the partition table does not contain FATFS partition with given label
  • ESP_ERR_INVALID_STATE if esp_vfs_fat_spiflash_mount was already called
  • ESP_ERR_NO_MEM if memory can not be allocated
  • ESP_FAIL if partition can not be mounted
  • other error codes from wear levelling library, SPI flash driver, or FATFS drivers
Parameters
  • base_path: path where FATFS partition should be mounted (e.g. “/spiflash”)
  • partition_label: label of the partition which should be used
  • mount_config: pointer to structure with extra parameters for mounting FATFS
  • wl_handle: wear levelling driver handle

struct esp_vfs_fat_mount_config_t

Configuration arguments for esp_vfs_fat_sdmmc_mount and esp_vfs_fat_spiflash_mount functions.

Public Members

bool format_if_mount_failed

If FAT partition can not be mounted, and this parameter is true, create partition table and format the filesystem.

int max_files

Max number of open files.

esp_err_t esp_vfs_fat_spiflash_unmount(const char *base_path, wl_handle_t wl_handle)

Unmount FAT filesystem and release resources acquired using esp_vfs_fat_spiflash_mount.

Return
  • ESP_OK on success
  • ESP_ERR_INVALID_STATE if esp_vfs_fat_spiflash_mount hasn’t been called
Parameters
  • base_path: path where partition should be registered (e.g. “/spiflash”)
  • wl_handle: wear levelling driver handle returned by esp_vfs_fat_spiflash_mount

Mid level API 参考手册
函数
esp_err_t wl_mount(const esp_partition_t *partition, wl_handle_t *out_handle)

Mount WL for defined partition.

Return
  • ESP_OK, if the allocation was successfully;
  • ESP_ERR_INVALID_ARG, if WL allocation was unsuccessful;
  • ESP_ERR_NO_MEM, if there was no memory to allocate WL components;
Parameters
  • partition: that will be used for access
  • out_handle: handle of the WL instance

esp_err_t wl_unmount(wl_handle_t handle)

Unmount WL for defined partition.

Return
  • ESP_OK, if the operation completed successfully;
  • or one of error codes from lower-level flash driver.
Parameters
  • handle: WL partition handle

esp_err_t wl_erase_range(wl_handle_t handle, size_t start_addr, size_t size)

Erase part of the WL storage.

Return
  • ESP_OK, if the range was erased successfully;
  • ESP_ERR_INVALID_ARG, if iterator or dst are NULL;
  • ESP_ERR_INVALID_SIZE, if erase would go out of bounds of the partition;
  • or one of error codes from lower-level flash driver.
Parameters
  • handle: WL handle that are related to the partition
  • start_addr: Address where erase operation should start. Must be aligned to the result of function wl_sector_size(...).
  • size: Size of the range which should be erased, in bytes. Must be divisible by result of function wl_sector_size(...)..

esp_err_t wl_write(wl_handle_t handle, size_t dest_addr, const void *src, size_t size)

Write data to the WL storage.

Before writing data to flash, corresponding region of flash needs to be erased. This can be done using wl_erase_range function.

Note
Prior to writing to WL storage, make sure it has been erased with wl_erase_range call.
Return
  • ESP_OK, if data was written successfully;
  • ESP_ERR_INVALID_ARG, if dst_offset exceeds partition size;
  • ESP_ERR_INVALID_SIZE, if write would go out of bounds of the partition;
  • or one of error codes from lower-level flash driver.
Parameters
  • handle: WL handle that are related to the partition
  • dest_addr: Address where the data should be written, relative to the beginning of the partition.
  • src: Pointer to the source buffer. Pointer must be non-NULL and buffer must be at least ‘size’ bytes long.
  • size: Size of data to be written, in bytes.

esp_err_t wl_read(wl_handle_t handle, size_t src_addr, void *dest, size_t size)

Read data from the WL storage.

Return
  • ESP_OK, if data was read successfully;
  • ESP_ERR_INVALID_ARG, if src_offset exceeds partition size;
  • ESP_ERR_INVALID_SIZE, if read would go out of bounds of the partition;
  • or one of error codes from lower-level flash driver.
Parameters
  • handle: WL module instance that was initialized before
  • dest: Pointer to the buffer where data should be stored. Pointer must be non-NULL and buffer must be at least ‘size’ bytes long.
  • src_addr: Address of the data to be read, relative to the beginning of the partition.
  • size: Size of data to be read, in bytes.

size_t wl_size(wl_handle_t handle)

Get size of the WL storage.

Return
usable size, in bytes
Parameters
  • handle: WL module handle that was initialized before

size_t wl_sector_size(wl_handle_t handle)

Get sector size of the WL instance.

Return
sector size, in bytes
Parameters
  • handle: WL module handle that was initialized before

关于本节 API 的示例代码请参考 ESP-IDF 示例中的 storage 目录。

协议 API

mDNS 服务

概述

mDNS 是一个多播 UDP 服务,它用于提供本地网络服务和发现主机。

mDNS 在大多数操作系统中都已默认安装,或者可以用于独立的软件包。在 Mac OS 上面,它默认已被安装,且被叫做 Bonjour。苹果发布了一个 Windows 的安装器,可以在 on Apple’s support page 上面找到。在 Linux 上,mDNS 由 avahi 提供,且通常都已默认安装。

mDNS 属性
  • 主机名(hostname): 设备将要相应的主机名。如果没设置,主机名 将会从接口中读取。例如: my-esp32 会被解析为 my-esp32.local
  • 默认实例(default_instance): 设备的友好名字,例如 Jhon's ESP32 Thing。如果未被设置,默认使用 主机名

为 STA 接口启动 mDNS 并设置 hostnamedefault_instance 的示例:

mdns_server_t * mdns = NULL;

void start_mdns_service()
{
    //initialize mDNS service on STA interface
    esp_err_t err = mdns_init(TCPIP_ADAPTER_IF_STA, &mdns);
    if (err) {
        printf("MDNS Init failed: %d\n", err);
        return;
    }

    //set hostname
    mdns_set_hostname(mdns, "my-esp32");
    //set default instance
    mdns_set_instance(mdns, "Jhon's ESP32 Thing");
}
mDNS 服务

mDNS 可以广播你的设备所提供给的网络服务。每个服务通过一些属性定义。

  • 服务(service): 所需的服务类型,使用下划线作为前缀。一些通过类型可以在 这里 找到。
  • 协议(proto): 服务运行所需的协议,以下划线作为前缀,例如: _tcp 或者 _udp
  • 端口(port): 服务运行所需的端口。
  • 实例(instance): 服务的友好名字,例如 Jhon's ESP32 Web Server。如果未定义,则使用 默认实例
  • 文本(txt): var=val 类型的字符串数组,用于为你的服务定义属性。

添加服务和不同属性的示例:

void add_mdns_services()
{
    //add our services
    mdns_service_add(mdns, "_http", "_tcp", 80);
    mdns_service_add(mdns, "_arduino", "_tcp", 3232);
    mdns_service_add(mdns, "_myservice", "_udp", 1234);

    //NOTE: services must be added before their properties can be set
    //use custom instance for the web server
    mdns_service_instance_set(mdns, "_http", "_tcp", "Jhon's ESP32 Web Server");

    const char * arduTxtData[4] = {
            "board=esp32",
            "tcp_check=no",
            "ssh_upload=no",
            "auth_upload=no"
    };
    //set txt data for service (will free and replace current data)
    mdns_service_txt_set(mdns, "_arduino", "_tcp", 4, arduTxtData);

    //change service port
    mdns_service_port_set(mdns, "_myservice", "_udp", 4321);
}
mDNS 查询

mDNS 提供了浏览服务和解析主机 IP/IPv6 地址的方法。

结果用过一个链表对象 mdns_result_t 返回。如果结果是来自主机查询,则只包含 addr``addrv6``(如果找到)。服务查询将存在于所找到的结构的所有字段。

解析主机 IP 的示例:

void resolve_mdns_host(const char * hostname)
{
    printf("mDNS Host Lookup: %s.local\n", hostname);
    //run search for 1000 ms
    if (mdns_query(mdns, hostname, NULL, 1000)) {
        //results were found
        const mdns_result_t * results = mdns_result_get(mdns, 0);
        //itterate through all results
        size_t i = 1;
        while(results) {
            //print result information
            printf("  %u: IP:" IPSTR ", IPv6:" IPV6STR "\n", i++
                IP2STR(&results->addr), IPV62STR(results->addrv6));
            //load next result. Will be NULL if this was the last one
            results = results->next;
        }
        //free the results from memory
        mdns_result_free(mdns);
    } else {
        //host was not found
        printf("  Host Not Found\n");
    }
}

解析本地服务的示例:

void find_mdns_service(const char * service, const char * proto)
{
    printf("mDNS Service Lookup: %s.%s\n", service, proto);
    //run search for 1000 ms
    if (mdns_query(mdns, service, proto, 1000)) {
        //results were found
        const mdns_result_t * results = mdns_result_get(mdns, 0);
        //itterate through all results
        size_t i = 1;
        while(results) {
            //print result information
            printf("  %u: hostname:%s, instance:\"%s\", IP:" IPSTR ", IPv6:" IPV6STR ", port:%u, txt:%s\n", i++,
                (results->host)?results->host:"NULL", (results->instance)?results->instance:"NULL",
                IP2STR(&results->addr), IPV62STR(results->addrv6),
                results->port, (results->txt)?results->txt:"\r");
            //load next result. Will be NULL if this was the last one
            results = results->next;
        }
        //free the results from memory
        mdns_result_free(mdns);
    } else {
        //service was not found
        printf("  Service Not Found\n");
    }
}

使用上面的方法的示例:

void my_app_some_method(){
    //search for esp32-mdns.local
    resolve_mdns_host("esp32-mdns");

    //search for HTTP servers
    find_mdns_service("_http", "_tcp");
    //or file servers
    find_mdns_service("_smb", "_tcp"); //windows sharing
    find_mdns_service("_afpovertcp", "_tcp"); //apple sharing
    find_mdns_service("_nfs", "_tcp"); //NFS server
    find_mdns_service("_ftp", "_tcp"); //FTP server
    //or networked printer
    find_mdns_service("_printer", "_tcp");
    find_mdns_service("_ipp", "_tcp");
}
应用程序示例

mDNS 的服务器/扫描示例程序: protocols/mdns.

API 参考手册
类型定义
typedef struct mdns_server_s mdns_server_t
typedef struct mdns_result_s mdns_result_t

mDNS query result structure

枚举
结构体
struct mdns_result_s

mDNS query result structure

Public Members

const char *host

hostname

const char *instance

instance

const char *txt

txt data

uint16_t priority

service priority

uint16_t weight

service weight

uint16_t port

service port

struct ip4_addr addr

ip4 address

struct ip6_addr addrv6

ip6 address

const struct mdns_result_s *next

next result, or NULL for the last result in the list

函数
esp_err_t mdns_init(tcpip_adapter_if_t tcpip_if, mdns_server_t **server)

Initialize mDNS on given interface.

Return
  • ESP_OK on success
  • ESP_ERR_INVALID_ARG when bad tcpip_if is given
  • ESP_ERR_INVALID_STATE when the network returned error
  • ESP_ERR_NO_MEM on memory error
  • ESP_ERR_WIFI_NOT_INIT when WiFi is not initialized by eps_wifi_init
Parameters
  • tcpip_if: Interface that the server will listen on
  • server: Server pointer to populate on success

void mdns_free(mdns_server_t *server)

Stop and free mDNS server.

Parameters
  • server: mDNS Server to free

esp_err_t mdns_set_hostname(mdns_server_t *server, const char *hostname)

Set the hostname for mDNS server.

Return
  • ESP_OK success
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_ERR_NO_MEM memory error
Parameters
  • server: mDNS Server
  • hostname: Hostname to set

esp_err_t mdns_set_instance(mdns_server_t *server, const char *instance)

Set the default instance name for mDNS server.

Return
  • ESP_OK success
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_ERR_NO_MEM memory error
Parameters
  • server: mDNS Server
  • instance: Instance name to set

esp_err_t mdns_service_add(mdns_server_t *server, const char *service, const char *proto, uint16_t port)

Add service to mDNS server.

Return
  • ESP_OK success
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_ERR_NO_MEM memory error
Parameters
  • server: mDNS Server
  • service: service type (_http, _ftp, etc)
  • proto: service protocol (_tcp, _udp)
  • port: service port

esp_err_t mdns_service_remove(mdns_server_t *server, const char *service, const char *proto)

Remove service from mDNS server.

Return
  • ESP_OK success
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_ERR_NOT_FOUND Service not found
  • ESP_FAIL unknown error
Parameters
  • server: mDNS Server
  • service: service type (_http, _ftp, etc)
  • proto: service protocol (_tcp, _udp)

esp_err_t mdns_service_instance_set(mdns_server_t *server, const char *service, const char *proto, const char *instance)

Set instance name for service.

Return
  • ESP_OK success
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_ERR_NOT_FOUND Service not found
  • ESP_ERR_NO_MEM memory error
Parameters
  • server: mDNS Server
  • service: service type (_http, _ftp, etc)
  • proto: service protocol (_tcp, _udp)
  • instance: instance name to set

esp_err_t mdns_service_txt_set(mdns_server_t *server, const char *service, const char *proto, uint8_t num_items, const char **txt)

Set TXT data for service.

Return
  • ESP_OK success
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_ERR_NOT_FOUND Service not found
  • ESP_ERR_NO_MEM memory error
Parameters
  • server: mDNS Server
  • service: service type (_http, _ftp, etc)
  • proto: service protocol (_tcp, _udp)
  • num_items: number of items in TXT data
  • txt: string array of TXT data (eg. {“var=val”,”other=2”})

esp_err_t mdns_service_port_set(mdns_server_t *server, const char *service, const char *proto, uint16_t port)

Set service port.

Return
  • ESP_OK success
  • ESP_ERR_INVALID_ARG Parameter error
  • ESP_ERR_NOT_FOUND Service not found
Parameters
  • server: mDNS Server
  • service: service type (_http, _ftp, etc)
  • proto: service protocol (_tcp, _udp)
  • port: service port

esp_err_t mdns_service_remove_all(mdns_server_t *server)

Remove and free all services from mDNS server.

Return
  • ESP_OK success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • server: mDNS Server

size_t mdns_query(mdns_server_t *server, const char *service, const char *proto, uint32_t timeout)

Query mDNS for host or service.

Return
the number of results found
Parameters
  • server: mDNS Server
  • service: service type or host name
  • proto: service protocol or NULL if searching for host
  • timeout: time to wait for answers. If 0, mdns_query_end MUST be called to end the search

size_t mdns_query_end(mdns_server_t *server)

Stop mDNS Query started with timeout = 0.

Return
the number of results found
Parameters
  • server: mDNS Server

size_t mdns_result_get_count(mdns_server_t *server)

get the number of results currently in memoty

Return
the number of results
Parameters
  • server: mDNS Server

const mdns_result_t *mdns_result_get(mdns_server_t *server, size_t num)

Get mDNS Search result with given index.

Return
the result or NULL if error
Parameters
  • server: mDNS Server
  • num: the index of the result

esp_err_t mdns_result_free(mdns_server_t *server)

Remove and free all search results from mDNS server.

Return
  • ESP_OK success
  • ESP_ERR_INVALID_ARG Parameter error
Parameters
  • server: mDNS Server

关于本节 API 的示例代码请参考 ESP-IDF 示例中的 protocols 目录。

Hardware Reference

ESP32 Modules and Boards

Espressif designed and manufactured several development modules and boards to help users evaluate functionality of ESP32 chip. Development boards, depending on intended functionality, have exposed GPIO pins headers, provide USB programming interface, JTAG interface as well as peripherals like touch pads, LCD screen, SD card slot, camera module header, etc.

For details please refer to documentation below, provided together with description of particular boards.

ESP-WROOM-32

The smallest module intended for installation in final products. Can be also used for evaluation after adding extra components like programming interface, boot strapping resistors and break out headers.

ESP-WROOM-32 module (front and back)

ESP32 Core Board V2 / ESP32 DevKitC

Small and convenient development board with break out pin headers and minimum additional components. Includes USB to serial programming interface, that also provides power supply for the board. Has press buttons to reset the board and put it in upload mode.

ESP32 Core Board V2 / ESP32 DevKitC board

ESP32 Demo Board V2

One of first feature rich evaluation boards that contains several pin headers, dip switches, USB to serial programming interface, reset and boot mode press buttons, power switch, 10 touch pads and separate header to connect LCD screen.

ESP32 Demo Board V2 board

ESP32 WROVER KIT V1 / ESP32 DevKitJ V1

Development board that has dual port USB to serial converter for programming and JTAG interface for debugging. Power supply is provided by USB interface or from standard 5 mm power supply jack. Power supply selection is done with a jumper and may be put on/off with a separate switch. Has SD card slot, 3.2” SPI LCD screen and dedicated header to connect a camera. Provides RGB diode for diagnostics. Also, includes 32.768 kHz XTAL for internal RTC to operate it in low power modes.

ESP32 WROVER KIT V1 / ESP32 DevKitJ V1 board

ESP32 WROVER KIT V2

This is an updated version of ESP32 DevKitJ V1 described above with design improvements identified when DevKitJ was in use. Both V1 and V2 versions of this board are ready to accommodate existing ESP-WROOM-32 or the new ESP32-WROVER module.

ESP32 WROVER KIT V2 board

API 指导

关于 ESP-IDF 编程的通用说明

应用程序启动流程

本文档解释了在 ESP-IDF 应用程序的 app_main 被调用前的各个步骤。

启动过程的顶层视图如下:

  1. 在 ROM 中的第一阶段的 bootloader 从 flash 偏移地址 0x1000 处加载第二阶段的 bootloader 到 RAM 中。
  2. 第二阶段的 bootloader 从 flash 上面加载分区表和主应用程序镜像。主应用程序包含 RAM 段和通过 flash cacha 映射的只读段。
  3. 主应用程序镜像开始执行。此时,第二个 CPU 以及 RTOS 调度器开始启动。

下面将详细介绍这个过程。

第一阶段的 bootloader

SoC 复位后,PRO CPU 将会立即运行,并执行复位向量代码;此时 APP CPU 将会保持在复位状态。在启动过程中,PRO CPU 将会完成所有的初始化工作。APP CPU 由应用程序启动代码中的函数 call_start_cpu0 解除复位。复位向量表位于 ESP32 芯片的 mask ROM 中的地址 0x40000400 处,且不能被修改。

启动代码会被复位代码调用,然后通过检查寄存器 ``GPIO_STRAP_REG``(bootstrap 引脚状态)来判断启动模式。根据复位原因的不同,可能会发生如下的行为:

  1. 从深度睡眠中复位:如果在 RTC_CNTL_STORE6_REG 中的值非零,且在 RTC_CNTL_STORE7_REG 中的 RTC 内存中的 CRC 值是有效的,则使用 RTC_CNTL_STORE6_REG 作为入口点地址,并立即跳转到该地址。如果 RTC_CNTL_STORE6_REG 是零,或者 RTC_CNTL_STORE7_REG 包含无效的 CRC,或者通过 RTC_CNTL_STORE6_REG 调用的代码立即返回了,则将这次启动作为上电复位启动。Note: 如果要在此时运行自定义的代码,可以使用所提供的深度睡眠桩机制。具体细节请参考文档 深度睡眠
  2. 对于上电复位,软件 SoC 复位,以及看门狗 SoC 复位:如果请求了 UART 或 SDIO 下载模式,则检查寄存器 GPIO_STRAP_REG。对于这种情形,会配置 UART 或者 SDIO,并等待下载代码。否则,将这次启动作为软件 CPU 复位。
  3. 对于软件 CPU 复位和看门狗 CPU 复位:基于 EFUSE 的值配置 SPI,并尝试从 flash 中加载代码。这一步的更多细节将在下一段中进行描述。如果从 flash 中加载代码失败,则将基本的解释器解压缩到 RAM 中并启动它。注意,此时 RTC 看门狗依然是使能的,所以除非从解释器中接收到输入,否则看门狗将会在几百毫秒后复位 SoC,然后重复整个过程。如果解释器从 UART 接收到了输入,则它会禁止看门狗。

应用程序镜像被加载到 flash 的地址 0x10000 处。flash 的前 4 KB 扇区用于存储安全启动 IV 和应用程序镜像签名。更多细节请参考安全启动文档。

第二阶段的 bootloader

在 ESP-IDF 中,flash 的地址 0x1000 处存储的二进制镜像就是第二阶段的 bootloader。第二阶段的 bootloader 源代码位于 ESP-IDF 的 components/bootloader 目录下。注意,这种做法只是 ESP32 芯片的一种实现方法,你也可以直接将一个具有完整功能的应用程序镜像烧写到地址 0x1000 处,不过这超出了本文当的讨论范围。ESP-IDF 使用第二阶段的 bootloader 的好处是可以实现灵活地添加 flash 布局(使用分区表),允许实现与 flash 加密相关的各种流程、安全启动以及空中升级(OTA)。

当第一阶段的 bootloader 完成后,ESP32 会检查并加载第二阶段的 bootloader,跳转到在二进制镜像头部中找到的第二阶段 bootloader 的入口点。

第二阶段的 bootloader 会阅读位于偏移量 0x8000 处的分区表。更多信息请参考 分区表。bootloader 会找到工厂分区和 OTA 分区,然后基于 OTA info 分区中的信息判断启动哪个分区。

对于所选择的分区,第二阶段的 bootloader 会将数据段和映射到 IRAM/DRAM 中的代码段拷贝到它们对应的加载地址。对于加载地址在 IRAM/DROM 范围内的段,ESP32 会通过所提供的正确的映射来配置 flash MMU。需要注意的是,第二阶段的 bootloader 会同时为 PRO CPU 和 APP CPU 同时配置 flash MMU,但是只会使能 PRO CPU 的 flash MMU。这样做的原因是第二阶段的 bootloader 代码被加载到了由 APP CPU cache 所使用的内存范围内了。使能 APP CPU cache 的任务被移交给应用程序了。当代码被加载、flash MMU 被设置后,第二阶段的 bootloader 会跳转到由二进制镜像头部中指定的应用程序入口点。

当前不能向 bootloader 中添加由应用程序指定的钩子,因此不能自定义应用程序的分区选择逻辑。但是这可能是需要的,例如,根据某个 GPIO 的状态来加载不同的应用程序镜像。今后会将这种自定义功能添加到 ESP-IDF 中。目前为止,如果你需要自定义 bootloader,可以将 bootloader 组件拷贝懂啊应用程序目录,然后做相应的修改。对于这种情况,ESP-IDF 的编译系统会在应用程序目录编译该组件,而不会在 ESP-IDF 的组件目录中编译它。

应用程序启动

ESP-IDF 应用程序的入口点是 components/esp32/cpu_start.c 中的函数 call_start_cpu0。该函数主要做了两件事儿:使能堆分配器以及让 APP CPU 跳转到它的入口点 call_start_cpu1。在 PRO CPU 上面的代码会设置 APP CPU 的入口点,激活 APP CPU 的复位,并等待由 APP CPU 中的代码设置一个表示它已启动的全局标志。完成后,PRO CPU 会跳转到函数 start_cpu0,APP CPU 会跳转到函数 start_cpu1

start_cpu0start_cpu1 都是虚函数。这意味着,如果应用程序需要改变初始化序列,可以直接在应用程序中覆盖这两个函数。start_cpu0 默认会根据 menuconfig 中的选项使能/初始化对应的组件。具体请在 components/esp32/cpu_start.c 中参考该函数的实现。注意,应用程序中的所有 C++ 全局构造器都会在这个阶段被调用。当所有必要组件都初始化后,会创建 主任务(main task) 并启动 FreeRTOS 的调度器。

当 PRO CPU 在函数 start_cpu0 中执行初始化时,APP CPU 会在函数 start_cpu1 中自旋,等待 PRO CPU 启动调度器。当 PRO CPU 启动调度器后,在 APP CPU 上面的代码也会启动调度器。

主任务就是运行函数 app_main 的任务。主任务的栈大小和优先级都可以通过 menuconfig 配置。应用程序可以利用这个任务做一些应用程序相关的初始化,例如启动其它任务。应用程序也可以使用主任务做事件循环以及其它的通过工作。如果函数 app_main 返回了,主任务会被删除。

应用程序内存布局

ESP32 芯片具有灵活的内存映射功能。本节描述 ESP-IDF 在默认情况下是如何使用这些功能的。

在 ESP-IDF 中的应用程序代码可以放到下列的内存区域内。

IRAM (指令 RAM)

ESP-IDF 从 Internal SRAM0`(在技术参考手册中定义的) 中分配了部分区域作为指令 RAM。除前 64 kB 块用于 PRO 和 APP CPU cache 之外,这段内存的剩余部分(即从 ``0x40080000`0x400A0000)用于存储需要直接从 RAM 中运行的应用程序。

ESP-IDF 中的少量组件和部分 WiFi 协议栈就是通过链接脚本放置到这个区域的。

如果某些应用程序的代码需要放置到 IRAM,可以使用 IRAM_ATTR 进行定义

#include "esp_attr.h"

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

下面是一些应用程序可能需要放置到 IRAM 中的例子。

  • ISR handler 必须被放置到 IRAM。更进一步说,ISR handler 智只能调用放到 IRAM 中的函数和 ROM 中的函数。 Note 1: 当前所有的 FreeRTOS API 都是放置到 IRAM 中的,所以可以被 ISR handler 安全调用。Note 2: ISR handler 所使用的常量数据(包括但不限于 const char)以及被 ISR 调用的函数都必须通过 DRAM_ATTR 放到 DRAM 中。
  • 某些对时间敏感的代码需要放知道 IRAM 中,这样可以减小从 flash 加载代码的时间。ESP32 通过一个 32 kB 的 cache 读取代码和数据。在某些情况下,将函数放到 IRAM 中可以减小 cache 缺失所造成的延迟。
IROM (从 Flash 执行的代码)

如果函数没有被明确指明需要放到 IRAM 或者 RTC 内存中,则它会被默认放到 flash 中。 关于使用 flash MMU 来允许从 flash 中执行代码的机制请查阅技术参考手册。ESP-IDF 将需要从 flash 中执行的代码放到 0x400D0000 0x40400000 范围内。启动的时候,第二阶段的 bootloader 会初始化 flash MMU,将 flahs 中代码所处的位置映射到这段区域的起始处。对这段范围的访问将会被显示地缓存到 0x400700000x40080000 范围内的两个 32kB 块。

注意,位于 0x40000000 0x40400000 范围之外的代码不可由 Window ABI CALLx 指令获得,因此,如果应用程序使用了 0x40400000 0x408000000x40800000 0x40C00000 范围,需要特别注意。ESP-IDF 默认不会使用这些区域。

RTC 快速内存

需要在从深度睡眠唤醒时执行的代码必须被放置到 RTC 内存中,具体细节请参考文档 深度睡眠

DRAM (数据 RAM)

非常量静态数据和以 0 初始化的数据别链接器放到一个 256 kB 的范围 0x3FFB0000 — 0x3FFF0000 内。注意,如果使用了蓝牙协议栈,则则个范围会被缩减到 64 kB(通过将起始位置移位到 0x3FFC0000),如果使用了内存跟踪技术,这个范围的长度会被进一步缩减到 16 kB 或者 32 kB。放置静态数据后所剩余的所有空间将被用于运行时的堆空间。

常量数据也可以被放置到 DRAM 中,例如如果它用于 ISR handler 中(参考上面的 IRAM 章节)。要达到此目的,需要使用 DRAM_ATTR 进行定义

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

不言而喻的是,不用在 ISR handler 中使用 printf 和其它输出函数。如果需要调试,可以在 ISR 中使用宏 ESP_EARLY_LOGx 来记录日志。在这种情况下,请确保将 TAG 和格式化字符串都放入 DRAM 中。

DROM (存储在 Flash 中的数据)

默认情况下,常量数据会被链接器放到一个 4 MB(0x3F400000 — 0x3F800000) 的范围内,ESP32 通过 Flash MMU 和 cache 在该范围内访问外部 flash。字面量常数是一个例外,它们会被编译器内嵌到应用程序的代码中。

RTC 低速内存

在 RTC 内存中运行的代码的全局和静态变量必须放到 RTC 慢速内存中,具体细节请查阅文档 深度睡眠

构建系统

本节阐释了乐鑫 IoT 开发框架的编译系统以及 “组件(components)” 的概念。

如果你想知道如何组织已给新的 ESP-IDF 工程的话,请继续阅读本文档。

我们推荐你使用 esp-idf-template 工程作为你的工程的起点。

使用构建系统

esp-idf 的 README 文件包含了如何使用构建系统构建你自己的工程的描述。

概述

ESP-IDF 工程可以看做大量组件构成的集合。例如,一个显示当前空气湿度的 webserver 可能包括:

  • ESP32 基本库(libc,rom bindings 等)
  • WiFi drivers
  • TCP/IP 协议栈
  • FreeRTOS 操作系统
  • webserver
  • 湿度传感器
  • 将它们集成到一个的主代码

ESP-IDF 中组件的概念非常清晰明确,且是可配置的。当编译工程时,构建环境将查找 ESP-IDF 目录下面的所有组件、工程目录以及额外自定义的目录(可选)。它允许用户通过一个基于文本 的菜单系统对 ESP-IDF 工程进行配置,以自定义每个组件。当工程中的组件被配置后,构建过程将会编译工程。

概念
  • “工程(project)” 是一个目录,它包含需要编译成 “app”(以及一些额外支持的输出,例如分区表,数据/文件系统分区,bootloader)的所有文件和配置。
  • “工程配置(Project configuration)” 是一个位于工程根目录的叫做 sdkconfig 的文件。这个配置文件可以通过 make menuconfig 来自定义工程的配置项。单个工程确切地包含一个工程配置。
  • “应用程序(app)” 是一个由 esp-idf 编译成的可执行文件。单个工程通常会被编译成两个 app - 一个 “工程 app” (主可执行文件,即你的自定义固件)和一个 “bootloader app”(加载工程 app 的初始化 bootloader 程序)。
  • “组件(component)” 是由相对独立的代码构成的模块,它们会被编译乘静态库(.a 文件)并被链接到 app 中。某些组件是由 esp-idf 自身提供的,另外一些组件可能在其它地方。

下面这些东西不属于工程的内容:

  • “ESP-IDF” 不是工程的一部分,而是一个相对独立的代码,通过环境变量 IDF_PATH 链接到工程。这能减小 IED 框架与工程直接的耦合性。
  • 用于编译的工具链不是工程的一部分。工具链应当安装在系统命令行的 PATH 中,或者工程配置中所配置的工具链前缀所对应的路径中。
示例工程

一个示例工程目录大概如下

- 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/

这个示例 “myProject” 包含如下元素:

  • 一个顶层工程 Makefile。这个 Makefile 设置变量 PROJECT_NAME,并(可选)定义项目范围内的其它 make 变量。 它包含了核心 makefile $(IDF_PATH)/make/project.mk,这个核心 makefile 实现了 ESP-IDF 构建系统的余下部分。
  • “sdkconfig” 工程配置文件。这个文件会在运行 “make menuconfig” 时被创建/更新,它包含了工程中的所有组件(包括 esp-idf 自身)。”sdkconfig” 可以被添加到工程的源码控制系统中,也可以不添加到工程的源码控制系统中。
  • 可选的 “组件(components)” 目录包含了一些组件,这些组件属于工程的一部分。工程并非必须包含这种自定义的组件,但是这通常有利于构架可充用的代码或者包含不属于 ESP-IDF 的第三方组件。
  • “main” 目录是一个特殊的 “虚拟组件”,它包含工程自身的源代码。”main” 是一个特殊的名字,Makefile 变量 SRCDIRS 默认就是这个值。用于也可以通过设置该变量让构建系统在其它目录来查找这个虚拟组件。
  • “build” 是构架系统所创建的构建输出目录。运行 make 命令后,这个变量将包含临时目标文件、库文件和最中国的二进制输出文件。该目录通常不会添加到源代码控制系统中,或者不会随着工程源代码一起发布。

组件目录包含一个组件 makefile - component.mk。它里面可能包含用于控制组件编译过程的变量定义,被集成到整个工程。更多细节请参考 Component Makefiles

每个组件可以包含一个 Kconfig 文件,用于定义可以通过工程配置进行设置的 组件配置 选项。 一些组件可能还包括 Kconfig.projbuildMakefile.projbuild —— 用于 覆盖构成的某一部分 的特殊文件。

工程 Makefile

每个工程都有一个包含整个工程构建设置的 Makefile。默认情况下,工程的 Makefile 非常简单。

最小的 Makefile 示例
PROJECT_NAME := myProject

include $(IDF_PATH)/make/project.mk
强制的工程变量
  • PROJECT_NAME: 工程的名字。二进制输出文件会使用这个名字 - 即 myProject.bin, myProject.elf。
可选的工程变量

下面的这些变量都有一个默认值,但是你可以覆盖它们来实现一些自定义的行为。具体的实现细节请查看 make/project.mk

  • 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.
组件的 Makefile

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 [1].

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 difference 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.

Running Make Non-Interactively

When running make in a situation where you don’t want interactive prompts (for example: inside an IDE or an automated build system) append BATCH_BUILD=1 to the make arguments (or set it as an environment variable).

Setting BATCH_BUILD implies the following:

  • Verbose output (same as V=1, see below). If you don’t want verbose output, also set V=0.
  • If the project configuration is missing new configuration items (from new components or esp-idf updates) then the project use the default values, instead of prompting the user for each item.
  • If the build system needs to invoke menuconfig, an error is printed and the build fails.
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 protocols/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.)

[1]Actually, some components in esp-idf are “pure configuration” components that don’t have a component.mk file, only a Makefile.projbuild and/or Kconfig.projbuild file. However, these components are unusual and most components have a component.mk file.
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.

调试

为 ESP32 设置 OpenOCD

ESP321 和 ESP32 带有两个功能强劲的 Xtensa 核,支持大量的程序架构。ESP-IDF 中的 FreeRTOS 具有多核抢占式多线程功能,支持以最直观的方式编写代码。

当然这也带来一个弊端,即当没有合适的工具时,程序的调试变得更加艰难:如果一个 bug 是由两个线程引起的,这两个线程可能会同时运行在两个 CPU 核上,如果你所仅能使用 printf 语句,则调试过程可能会花费你的大量时间。调试这种问题的更好的以及更快速(大多数情形下)的方法是使用一个调试器,将它连接到处理器的调试端口。

乐鑫已经将 OpenOCD 和多核 FreeRTOS 移植到 ESP32 处理器上,并添加了一些 OpenOCD 原生并未支持的有用功能。这些都是免费的,本文档就是用于描述如何安装并使用它们。

JTAG 适配器硬件

你需要一个电压值既兼容 ESP32 又兼容 OpenOCD 软件的 JTAG 适配器。ESP32 上面的 JTAG 端口是一个工业级的没有(也不需要)TRST 引脚的 JTAG 端口。JTAG 的 I/O 引脚都通过 VDD_3P3_RTC 引脚进行供电(通常是 3.3 V),因此 JTAG 适配器和 JTAG 引脚应该能在该电压范围内正常工作。在软件方面,OpenOCD 支持大量的 JTAG 适配器,具体的适配器列表(不是太完整)请查阅 http://openocd.org/doc/html/Debug-Adapter-Hardware.html。 该页面也列举了 SWD 兼容的适配器;需要说明的是,ESP32 不支持 SWD。

在乐鑫,我们已经测试了 TIAO USB Multi-protocol 适配器电路板以及 Flyswatter2,这二者都是 USB2.0 的高速设备,具有良好的吞吐量。我们还测试了 J-Link 兼容的适配器以及 EasyOpenJTAG 适配器,它们都能正常工作,不过速度有点慢。

JTAG 工作所需要的最少信号线包括 TDI、TDO、TCK、TMS 和 Gnd。某些 JTAG 适配器还需要将 ESP32 的电源线连接到一根叫做 Vtar 的信号线上,以提供工作电压。另外,还可以将 SRST 可选地连接到 ESP32 的 CH_PD 引脚,OpenOCD 中很少使用该信号线。

安装 OpenOCD

ESP32 的变体版 OpenOCD 的源码位于 Espressifs Github,你可以使用下面的命令下载该源码

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

具体的编译步骤请参考 openocd-esp32 目录下的 README、README.OSX 和 README.Windows。当然,你也可以跳过 make install 这一步。

在 OpenOCD 中配置 ESP32 目标

当 OpenOCD 编译(以及可选地安装)完,JTAG 适配器连接到 ESP32 开发板后,使用 OpenOCD 就以及基本准备就绪了。此外,OpenOCD 还需要知道使用的是什么 JTAG 适配器,以及适配器所连接的是什么开发板和处理器。实现该目的的最简单的方式是使用一个配置文件。在本文档的同一目录下包含一个配置文件模板,你可以这样使用它:

  • 将 esp32.cfg 拷贝到 openocd-esp32 目录。
  • 编辑所拷贝的文件 esp32.cfg。最重要的是修改 source [find interface/ftdi/tumpa.cfg] 这一行,它用于说明所连接的物理 JTAG 适配器。
  • 打开一个终端,cd 到 openocd-esp32 目录。
  • 运行 ./src/openocd -s ./tcl -f ./esp32.cfg 启动 OpenOCD。

然后你将看到类似下面的输出

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).
  • 如果你碰到了关于权限的问题,请查阅 OpenOCD README 文档中的 ‘Permissions delegation’。
  • 如果你碰到了错误 (...all ones/...all zeroes),请检查你的连线,并确实是否已上电。

将调试器连接到 OpenOCD

OpenOCD 现在已经准备接受 gdb 连接了。如果你使用 Crosstool-NG 编译好了 ESP32 的工具链,或者从乐鑫官方下载了预编译的工具链,则该工具链中已包含 xtensa-esp32-elf-gdb,你可以直接用该 gdb 进行调试。首先,确保你的想要调试的工程已经被编译并烧写到 ESP32 的 SPI flahs 中了。然后,在另一个控制台(而非运行 OpenOCD 的控制台)中运行 gdb。例如,对于 template app

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

然后它应该会显示 gdb 提示符。

FreeRTOS 的支持

OpenOCD 已经明确地支持 ESP-IDF FreeRTOS 了;可以在 esp32.conf 中禁止 FreeRTOS 检测。如果使能了 FreeRTOS 检测,gdb 则会将 FreeRTOS 任务当做线程处理。查看这些线程可以使用 gdb 命令 i threads,切换到某个线程可以使用命令 thread x,其中 x 是线程的数字。可以切换到除了正在另一个 CPU 上运行的线程之前的其它所有线程,更多信息请参考 ESP32 quirks

ESP32 quirks

常规的 gdb 断点(b myFunction)只能设置在 IRAM 中,因为这段内存是可写的。在 flash 中的代码中设置这种类型的代码是无效的。它还可以支持两个观察点,因此可以使用 gdb 命令 watch myVariable 来观察/读取两个变量的改动。

你可以通过改变端口号将 gdb 连接到 APP CPU 或者 PRO CPU。target remote localhost:3333 可以连接到 PRO CPU,target remote localhost:3334 可以连接到 APP CPU。硬件方面,当某个 CPU 由于调试原因被挂起时,另一个 CPU 也会被挂起;恢复也是同时发生的。

由于 gdb 只能看到以所选 CPU 的视角所对应的系统,只有挂起的任务和正在 gdb 所连接的 CPU 上面运行的任务会被正确地显示。另一个 cpu 上面的活动的任务也可以被查看,不过它的状态可能非常不连续。

ESP-IDF 针对 OpenOCD 的各种功能提供了对应的编译选项:可以在第一个线程启动后停止执行执行;当抛出 panic 或者未处理异常后打断系统。这两个选项默认都是使能的,但是可以使用 esp-idf 配置选项对其进行禁止,更多细节请参考 make menuconfig 菜单。

正常情况下,在 OpenOCD 下面,可以通过向 ddb 中输入 ‘mon reset’ 或 ‘mon reset halt’ 对开发板进行复位。对于 ESP32,这些功能基本都能工作,但是有一些负面影响。首先,OpenoCD 复位只会复位 CPU 核,不会复位外设,因此如果软件依赖了外设复位后的状态,则可能导致产生未定的行为。其次,’mon reset halt’ 会在 freeRTOS 初始化前停止,而 OpenOCD 会假设 FreeRTOS 正在运行(默认情况,你也可以编辑 esp32.cfg 进行修改),然后它会变得混淆。

ESP32 的 Core Dump

ESP-IDF 支持在遇到不可恢复的软件错误时产生 core dump。这项有用的技术允许发生错误后再分析软件的状态。程序一旦崩溃,系统将进入 panic 状态,打印一些信息并挂起或者重启系统(依赖于配置)。用户可以选择产生 core dump 文件,从而可以在随后在 PC 上分析失败的原因。Core dump 中包含失败的那一刻系统中所有任务的快照。快照包括导致系统崩溃的线程的调用栈(callstack)。 ESP-IDF 提供了一个特殊的脚本 espcoredump.py 用于帮助用户恢复和分析 core dump。该工具提供了两个用于分析 core dump 的命令:

  • info_corefile - 打印崩溃任务的寄存器、调用栈、系统有效任务列、内存区域以及存储在 core dump 中的内存中的内容(任务控制块 TCB 和栈)。
  • dbg_corefile - 创建 core dump ELF 文件,并使用这个文件运行 GDB 调试会话。用户可以人工检查内存、变量和任务状态。需要注意的是,由于不是所有的内容都存放在 cour dump 中,只有分配到栈上的变量值才有意义。

配置

存在许多与 core dump 相关的配置选项,用户可以在应用程序的配置菜单中进行选择(make menuconfig)。

  1. Core dump 数据目的地 (Components -> ESP32-specific config -> Core dump destination):
  • 禁止产生 core dump
  • 将 core dump 保存到 flash
  • 将 core dump 打印到 UART
  1. core dump 模块的日志级别 (Components -> ESP32-specific config -> Core dump module logging level)。该值是一个从 0(无输出)到 5(最多输出)之间的一个数字。
  2. 将 core dump 打印到 UART 之前的延迟 (Components -> ESP32-specific config -> Core dump print to UART delay)。该值以 ms 为单位。

保存 core dump 到 flash

当该值被选择时,core dump 会被保存到 flash 上面的某个特殊分区。当使用 ESP-IDF 提供的默认分区表文件时,它将在 flash 上面自动分配所需空间。但是如果用户希望使用自己的带有 core dump 功能的布局文件,则应当像下面这样定义独立的分区表

# 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

分区表名没有特殊的需求,它可以根据用户应用程序的需要进行选择,但是分区表类型应当选择为 ‘data’,子类型应当选择为 ‘coredump’。此外,选择分区表大小的时候需要注意,core dump 的数据结构会引进一些额外的开销,包括固定 20 字节加上每个任务 12 字节。这个开销不包括每个任务的 TCB 大小和栈空间。因此,分区表的大小应当至少为 20 + 最大任务数量 x (12 + TCB 大小 + 任务最大栈大小) 字节。

从 flash 上面分析 core dump 的常用命令是: espcoredump.py -p </path/to/serial/port> info_corefile </path/to/program/elf/file> 或者 espcoredump.py -p </path/to/serial/port> dbg_corefile </path/to/program/elf/file>

打印 core dump 到 UART

当该选项被选择时,系统 panic 时会将按照 base64 编码的 core dump 打印到 UART 上。在这种情况下,用户需要手工将这些 core dump 文本的 body 保存到某个文件中,然后运行如下的目录: espcoredump.py info_corefile -t b64 -c </path/to/saved/base64/text> </path/to/program/elf/file> 或者 espcoredump.py dbg_corefile -t b64 -c </path/to/saved/base64/text> </path/to/program/elf/file>

按照 base64 编码的 core dump 的 body 位于下面的头部和尾部之间

================= CORE DUMP START =================
<body of base64-encoded core dump, save it to file on disk>
================= CORE DUMP END ===================

运行 ‘espcoredump.py’

命令的常用语法:

espcoredump.py [options] command [args]

Script Options:
  • –chip,-c {auto,esp32}. 目标芯片类型。支持的值包括 autoesp32
  • –port,-p PORT. 串口设备。
  • –baud,-b BAUD. 当 flashing/reading 时的串口波特率。
Commands:
  • info_corefile. 恢复 core dump 并打印有用的信息。
  • dbg_corefile. 恢复 core dump 并使用它启动 GDB 会话。
Command Arguments:
 
  • –gdb,-g GDB. 用于恢复数据的 gdb 的路径。
  • –core,-c CORE. 待使用的 core dump 文件的路径(如果省略,则会从 flash 上面读取 core dmup)。
  • –core-format,-t CORE_FORMAT. 指定通过 “-c” 参数传递的文件是 ELF (“elf”) 格式,还是 dump 原始二进制格式 (“raw”),还是按照 base64 编码的(“b64”) 格式。
  • –off,-o OFF. coredump 分区在 flash 中的偏移(输入 “make partition_table” 可以直接查看)。
  • –save-core,-s SAVE_CORE. 将 core 保存到文件中,否则临时的 core 文件将会被删除。Ignored with “-c”.
  • –print-mem,-m 打印内存 dump。值在 “info_corefile” 时有用。

分区表

概述

单个 ESP32 flash 可以包含多个应用程序,以及多种数据(校验数据、文件系统、参数存储器等)。基于这个原因,在 flash 的偏移地址 0x8000 处烧写了一个分区比表。

分区表的长度是 0xC00 字节(最多 95 个分区表条目)。如果分区表由于 安全启动 被签名,则签名会追加到表格的数据后面。

分区表的每个条目都包含名字(标签)、类型(app、data 等)、子类型以及在 flash 中的偏移量(分区表被加载的地址)。

使用分区表最简单的方法是使用 make menuconfig,然后选择一个简单的预定义的分区表:

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

在这两种情况下,工厂应用程序都会被烧写到偏移量 0x10000 处。如果你运行 make partition_table,控制台则会打印出分配表的情况。

内置分区表

下面是配置 “Single factory app, no OTA” 所打印出的信息

# 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
  • flash 的偏移地址 0x10000 (64KB) 处是标记为 “factory” 的应用程序。bootloader 默认会运行这里的应用程序。
  • 分区表中还定义了连个数据区域,用于存储 NVS 库分区和 PHY 初始化数据。

下面是配置 “Factory app, two OTA definitions” 所打印出的信息

# 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
  • 存在三个应用程序分区的定义。
  • 这三个的类型都是 “app”,但是子类型不同,工厂 app 位于 0x10000 处,剩余两个是 “OTA” app。
  • 这里还有一个新的 “ota data”,它用于保存 OTA 更新的一些信息。bootloader 会使用这些数据来判断指定哪个应用程序。如果 “ota data” 是空的,它会执行工厂应用程序。

创建自定义分区表

如果你在配置菜单中选择 “Custom partition table CSV”,你需要输入用于保存你的分区表的 CSV 文件的名字(在工程目录中)。CSV 可以根据你的需要描述任意数量的定义。

CVS 的格式与上面所打印的信息的格式是类似的。不过,不是所有的字段都需要。例如,这是一个 OTA 分区表的 “input” CSV

# 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
  • 字段间的空格会被忽略,以 # 开始的行(注释)也会被忽略。
  • CSV 文件的每个非注释行都是一个分区定义。
  • 只提供了第一个分区的偏移量。工具 gen_esp32part.py 会自动根据前一个分区的参数来填充偏移量。
名字(Name)字段

名字字段可以是任意有意义的名字。这对 ESP32 是无关紧要的。长度大于 16 个字符的名字将会被截断。

Type 字段

分区类型字段可以指定为 app(0)或者 data(1)。它也可以是 0-254(0x00-0xFE)之间的数字。类型 0x00-0x3F 被保留用于 esp-idf 的核心功能。

如果你的应用程序需要存储数据,请添加一个类型在 0x40-0xFE 范围的自定义分区。

bootloader 会忽略所有类型不是 app(0) & data(1) 的分区。

子类型

8 比特的子类型字段与所给的分区类型相关。

esp-idf 当前只指定了 “app” 和 “data” 分区的子类型字段。

App 子类型

当类型是 “app” 时,子类型可以是 factory (0), ota_0 (0x10) ... ota_15 (0x1F) 或 test (0x20)。

  • factory (0) 是默认的 app 分区。如果这里没有 data/ota 类型的分区,它会默认执行工厂 app,否则会读取该分区来判断启动哪个 OTA 镜像。
    • OTA 永远不会更新工厂分区。
    • 如果你想在 OTA 工程中保护 flash 的使用,你可以移除工厂分区并使用 ota_0 代替。
  • ota_0 (0x10) ... ota_15 (0x1F) 是 OTA 应用程序插槽(slot)。更多细节请参考 OTA 文档,然后使用 OTA 数据分区来配置让给 bootloader 启动哪个插槽。如果使用 OTA,应用程序应当至少包括两个 OTA 应用程序插槽(ota_0 & ota_1)。更多细节请参考 OTA 文档
  • test (0x2) 是用于工厂测试过程的保留子类型。esp-idf bootloader 当前不支持这种子类型。
Data 子类型

当类型是 “data”时,子类型可以是 ota (0), phy (1), nvs (2)。

  • ota (0) 是 OTA 数据分区,用于存储当前所选择的 OTA 应用程序的信息。这个分区的大小固定为 0x2000 字节。更多细节请参考 OTA 文档
  • phy (1) 用于存储 PHY 初始化数据。这样可以为每个设备(而不是在固件中)配置 PHY。
    • 在默认的配置中,phy partition 未被使用,PHY 初始化数据被编译到应用程序自身中。对于这种过情况,可以将这个分区从分区表中移除,以节约空间。
    • 要从这个分区表中加载 PHY 数据,运行 make menuconfig 并使能 “Component Config” -> “PHY” -> “Use a partition to store PHY init data”。你还需要给你的设备烧写 phy 初始化数据,因为 esp-idf 的编译系统默认不会自动完成该操作。
  • nvs (2) 用于 非易失性存储器 (NVS) API
    • NVS 用于存储每个设备的 PHY 校验数据(与初始化数据不同)。
    • NVS 用于存储 Wifi 数据(如果使用了 esp_wifi_set_storage(WIFI_STORAGE_FLASH) 初始函数)。
    • NVS 也可以用于其它应用程序数据。
    • 强烈建议在你的工程中包含一个大于 0x3000 字节的 NVS 分区。
    • 如果想要使用 NVS API 来存储大量数据,请增加 NVS 分区表的大小(默认是 0x6000 字节)。

其它数据子类型保留。

偏移量 & 大小

只有第一个偏移字段是需要的(我们推荐使用 0x10000)。偏移量为空白的分区将会自动跟在前一个分区的后面。

应用程序分区必须对齐到 0x10000 (64K)。如果它的偏移量字段为空白,工具将会自动让给分区对齐。如果你指定了一个未对齐的偏移量,工具将会返回一个错误。

大小和偏移量可以以十进制形式指定,也可以以 0x 为前缀的十六进制形式指定,或者以 K 或 M 作为单位指定(分别是 1024 和 1024*1024 字节)。

产生二进制分区表

烧写到 ESP32 中的分区表是二进制格式的,而不是 CSV。工具 partition_table/gen_esp32part.py 可用于将分区表在 CSV 和二进制格式之间进行转化。

如果你在``make menuconfig`` 中配置了 CSV 名字,然后 make partition_table,则在编译过程会自动进行转化。

手工将 CSV 转化为二进制格式

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

将二进制转换回 CSV

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

如果需要在标志输出中显示二进制分区表的内容(这就是运行 make partition_table 时所产生的信息)

python gen_esp32part.py binary_partitions.bin

gen_esp32part.py 有一个可选参数 --verify,它会在转化期间校验分区表(检查重叠分区、为对齐分区等)。

烧写分区表

  • make partition_table-flash: 将会使用 esptool.py 烧写分区表。
  • make flash: 将会烧写包括分区表在内的所有东西。

make partition_table 时也会打印手工烧写命令。

注意,更新分区表不会擦除老的分区表所存储的数据。你可以使用命令 make erase_flash (或 esptool.py erase_flash) 擦除整个 flash 的内容。

Flash 加密

Flash 加密功能可用于加密 ESP32 所连接的 SPI flash 上面的内容。当 flash 加密被使能后,从 SPI flash 上面读出的数据不足以用于恢复 flash 上面所存储的大多数内容。

Falsh 加密是与 安全启动 相独立的另一个功能,你可以在不使能安全加密的情况下单独使用 flash 加密功能。不过,为了有一个更加安全的环境,我们推荐同时使用这两种技术。

**IMPORTANT: 使能 flash 加密将会限制你今后可以对 ESP32 进行更新的次数。请确保仔细阅读本文档(包括 Flash 加密的限制)并充分理解使能 flash 加密的含义。 **

背景

  • flash 的内容使用秘钥长度为 256 比特的 AES 进行加密。flash 的加密密钥存储在芯片内部的 efuse 中,且(默认)被保护,以免软件访问呢。
  • 通过 ESP32 的 flash cache 映射功能对 flash 的访问是透明的 - 读取时,所有被映射到这段地址空间的 flash 区域都会被透明地解密。
  • 加密是通过给 ESP32 烧写明码文本数据、然后由 bootloader 在第一次启动准备就绪后对这些数据进行加密完成的(如果加密被使能)。
  • 不是所有的 flash 都会被加密。下列 flash 数据不会被加密:
    • Bootloader
    • 安全启动 bootloader digest (如果安全启动被使能)
    • 分区表
    • 所有的 “app” 类型的分区
    • 在分区表中所有标记了 “encrypt” 的分区

为了易于访问,或者为了使用 flash 友好的更新算法(数据加密后对算法有影响),有时候需要某些数据分区不被加密。非易失型存储器的 “NVS” 分区不能被加密。

  • flash 的加密秘钥存储在 ESP32 芯片内部的 efuse 密钥块 1 中。默认情况下,这个密钥是读/写保护的,因此软件不能访问或者修改它。
  • flash 加密算法 使用的是 AES-256,其密钥是通过 flash 的 32 字节的块的偏移地址进行调整的。这意味着,每 32 字节的块(两个连续的 16 字节 AES 块)是通过由 flash 加密密钥推断出来的唯一的密钥(unique key)进行加密的。
  • 尽管运行在芯片上的软件可以透明地对 flash 上面的内容进行解密,但是当 falsh 加密被使能后,UART bootloader(默认)不能对数据进行加密/解密。
  • 如果 flash 加密被使能,当程序员在 使用加密的 flash 写代码时必须进行更加周详的考虑。

Flash 加密的初始化

这里描述的是 flash 加密初始化的默认(且推荐)过程。如果需要实现特殊的功能,也可以自定义该过程,具体细节请参考 Flash 加密高级功能

IMPORTANT: 一旦在某次启动时使能 flash 加密后,随后通过串口对 flash 重新烧写最多只有三次机会。 且需要执行特殊的步骤(参考文档 串口烧写)才能进行烧写。

  • 如果安全启动被使用,则再也不能在物理上进行重新烧写。
  • OTA 可以用于更新 flash 上面的内容,没有受到这种限制。
  • 当在开发过程中使能 flash 加密时,使用 预生成的 flash 加密密钥 可以在物理上对预加密的数据进行无数次的重新烧写。**

使能 flash 加密的过程:

  • bootloader 在被编译时必须使能 flash 加密功能。在 ``make menuconfig``中,进入 “Security Features” 并给 “Enable flash encryption on boot” 选择 “Yes”。
  • 如果同时还使能了安全启动,最好同时也选上这些选项。请先参考文档 安全启动
  • 像常规方法一样编译和烧写 bootloader、分区表和工厂 app。这些分区在初次被写入 flash 时是未被加密的。
  • 第一次启动时,bootloader 将会看到 FLASH_CRYPT_CNT efuse 被设置为 0(工厂默认),然后它会使用硬件随机数发生器生成一个 falsh 加密密钥。这个密钥会被存储在 efuse 中,且具有软件读/写保护的功能。
  • 所有的加密分区然后被 bootloader 加密。加密需要一段时间(大分区最多会需要一分钟)。

IMPORTANT: 当第一次启动在进行加密时,不要中断对 ESP32 的供电。如果供电被中断,flash 中的内容将会被破坏,然后需要使用未加密的数据进行重新烧写。这种重新烧写不会影响烧写次数限制。

  • 当烧写完成后,efuses 会在 UART bootloader 运行期间禁止对加密 flash 的访问。请查看 使能 UART Bootloader 加密/解密 以了解高级特性。
  • efuse FLASH_CRYPT_CONFIG 被烧写为最大值(0xF),以得到一个位数最大的密钥(在 flash 算法中被调整)。请查看 ref:setting-flash-crypt-config 以了解高级特性。
  • 最后,FLASH_CRYPT_CNT efuse 被烧写为一个初始值 1。就是这个 efuse 激活了 flash 透明加密层并限制了随后可重新烧写的次数。关于 FLASH_CRYPT_CNT efuse 的更多细节请参考章节 更新加密的 Flash
  • bootloader 自身复位,并从新的被加密的 flash 重启。

使用加密的 Flash

ESP32 应用程序代码可以通过调用 esp_flash_encryption_enabled() 来检查当前是否使能了 flash 加密功能。

当 flash 加密被使能后, 从代码中访问 flash 上面的内容时需要考虑一些额外的东西。

Flash 加密的范围

无论什么时候,只要 FLASH_CRYPT_CNT efuse 被设置了一个新的奇数比特位,所有通过 MMU cache 访问的 flash 内容都会被透明地解密。这包括:

  • flash 上面的应用程序可执行代码(IROM)
  • 存储在 flash 中的所有只读数据(DROM)
  • 所有通过 esp_spi_flash_mmap() 访问的数据
  • 正在被 ROM bootloader 读取的软件 bootloader 镜像

IMPORTANT: MMU flash cache 会无条件地解码所有数据。在 flash 中存储的未加密数据会通过 flash cache 被透明地解密,然后对软件来说就是垃圾数据。

读取加密的 Flash

如果要在读取数据时不使用 flash cache MMU 映射,我们推荐使用分区读取函数 esp_partition_read()。当使用这个函数时,只有从加密分区中读取的数据会被解密,其它分区读取的数据不会被解密。通过这种方法,软件可以以同一种方法访问加密和未加密的 falsh。

以其它 SPI 读 API 所读取的数据不会被解密:

  • 通过 esp_spi_flash_read() 读取的数据不被解密。
  • 通过 ROM 函数 SPIRead() 读取的数据不被解密(该函数不支持 esp-idf 应用程序)。
  • 使用非易失性存储器 (NVS) API 存储的数据总是以解密形式进行存储/读取。
写加密的 Flash

只要可能,我们都推荐使用分区写函数 esp_partition_write。当使用该函数时,只有往加密分区中写的数据会被加密,往其它分区写的数据不会被加密。通过这种方法,软件可以以同一种方法访问加密和未加密的 falsh。

当参数 write_encrypted 设置为 true 时,函数 esp_spi_flash_write 将以加密的形式写数据,否则则会以未加密的形式写数据。

ROM 函数 esp_rom_spiflash_write_encrypted 将会写加密数据到 flash,ROM 函数 SPIWrite 将会写未加密数据到 flash 中(这些函数不支持 esp-idf 应用程序)。

未加密数据的最小写尺寸是 4 字节(且是 4 字节对齐的)。由于数据加密是以块为单位的,加密数据的最小写尺寸是 16 字节(且是以 16 字节对齐的)。

更新加密的 Flash

OTA 更新

对加密分区进行 OTA 更新时,只要使用的函数是 esp_partition_write,该分区就会被自动以加密的形式进行写。

串口烧写

如果没有使用安全启动,FLASH_CRYPT_CNT efuse 允许通过串口烧写的方式(或其它物理方式)对 flash 进行更新,但最多有三次额外的机会。

该过程涉及烧写明码文本数据、更改(bump):ref:FLASH_CRYPT_CNT 的值,从而引起 bootloader 对该数据进行重新加密。

有限的更新

这种情况下只有 4 次串口烧写机会,其中还包括初始加密 flash 在内的那次机会。

当第四次加密被禁止后,FLASH_CRYPT_CNT efuse 将拥有一个最大值 0xFF,加密被永久禁止。

使用 OTA 更新通过预生成的 Flash 加密密钥重新烧写 可以绕过这种限制。

串口烧写的注意事项
  • 当使用串口重新烧写时,需要重新烧写所有使用明码文本初始化的分区(包括 bootloader),但是可以跳过非 “当前所选择” 的那个 OTA 分区(除非在上面发现了明码文本应用程序镜像,否则不会待其进行重新加密)。不过,所有有 “加密” 标记的分区会被无条件地重新加密,这也意味着已被加密的数据会被再次加密而被破坏。
    • 使用 make flash 会烧写所有需要烧写的分区。
  • 如果安全启动被使能,除非你的安全启动使用了 “重新烧写” 选项并烧写了预生成的密钥(参考 Secure Boot 文档),否则你不能使用串口进行串行烧写。在这种情况下,你可以在偏移地址 0x0 处重新烧写一个明码文本的安全启动 digest 和 bootloader 镜像。在烧写其它明码文本数据之前,必须要先烧写这个 digest。
串口重新烧写的过程
  • 像平常一样编译应用程序。
  • 像平常一样给设备烧写明码文本数据(make flashesptool.py 命令),烧写之前的所有加密分区(包括 bootloader)。
  • 此时,设备将不能启动(提示消息 flash read err, 1000),这是因为它期望看到的是一个加密的 bootloader,而实际上却是一个明码文本。
  • 使用命令 espefuse.py burn_efuse FLASH_CRYPT_CNT 烧写 FLASH_CRYPT_CNT efuse。espefuse.py 会自动给计数比特加 1,并禁止加密。
  • 复位设备,然后设备会重新加密明码文本分区,然后再次烧写 FLASH_CRYPT_CNT efuse 以重新使能加密功能。
禁止串口更新

如果需要阻止今后使用串口更新明码文本,可以在 flash 加密被使能后(即第一次启动完成后)使用 espefuse.py 写保护 FLASH_CRYPT_CNT efuse

espefuse.py --port PORT write_protect_efuse FLASH_CRYPT_CNT

这将会禁止今后做任何改动,以禁止/重新使能 flash 加密。

通过预生成的 Flash 加密密钥重新烧写

你也可以在 PC 上面预生成一个 flash 加密密钥,然后将它烧写到 ESP32 的 efuse 密钥块中。这样做的好处是可以在主机对数据预加密,然后将加密后的数据烧写到 ESP32 上面,从而不需要明码文本烧写更新。

这在开发过程中是很有用的,因为它没有 4 次重烧的限制。此外,即使安全启动被使能,也可以无限次地重新烧写,因为 bootloader 不需要每次都被烧写。

IMPORTANT 这种方法只是为了方便开发,不要用于实际的产品设备。如果要为产品生成 flash 加密数据,请确保使用一个高质量的随机数源产生加密密钥,且不要在多个设备之间共享同一个 flash 加密密钥。

预生成 Flash 加密密钥

Flash 加密密钥是一个 32 字节的随机数。你可以使用 espsecure.py 生成一个随机密钥

espsecure.py generate_flash_encryption_key my_flash_encryption_key.bin

(随机数的质量与 OS 以及 Python 所安装的随机数源相关。)

另外,如果你正在使用 安全启动,且有一个安全启动签名密钥,你可以生成一个安全启动私有签名密钥的 SHA-256 digest,并使用它作为 flash 加密密钥

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

(如果你在安全启动中使能了 可重新烧写模式,则这 32 字节的数据还将作为安全启动 digest 密钥。)

通过这种从全球启动签名密钥生成 flash 加密密钥的方式意味着你只需要存储一个密钥文件。不过,这种方法 完全不适用于 实际产品中的设备。

烧写 Flash 加密密钥

生成 flash 加密密钥后,你还需要将它烧写到 ESP32 的 efuse 密钥块中。这必须在加密启动前完成,否则 ESP32 将会产生一个随机密钥,导致软件不能访问/修改 flash 上的内容。

将密钥烧写到设备(只需要一次)

espefuse.py --port PORT burn_key flash_encryption my_flash_encryption_key.bin
使用预生成的密钥第一次烧写

烧写完密钥后,按照默认 Flash 加密的初始化 步骤进行操作,并为第一次启动烧写一个明码文本镜像。bootloader将会使用预先烧写的密钥使能 flash 加密并加密所有分区。

使用预生成的密钥重新烧写

当第一次启动使能加密后,重新烧写加密的镜像需要一步额外的手工步骤,即预加密我们需要烧写到 flash 中的数据。

假设这是你用于烧写明码文本数据的命令

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

二进制应用程序镜像 build/my-app.bin 被烧写到偏移地址 0x10000 处。这里的文件名和偏移地址要用于加密数据

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

上面这条命令会使用所提供的密钥加密 my-app.bin,并产生一个加密文件 my-app-encrypted.bin。请确保这里的地址参数与你将要烧写二进制镜像的地址相匹配。

然后,使用 esptool.py 烧写加密后的二进制文件

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

至此,已经不需要其它的步骤了,因为数据已经被加密并烧写完成了。

禁止 Flash 加密

如果你由于某些原因意外地把 flash 加密功能使能了, the next flash of plaintext data will soft-brick the ESP32 (设备将会连续重启,并打印错误 flash read err, 1000)。

你可以通过写 FLASH_CRYPT_CNT efuse 再次禁止 flash 加密:

  • 首先,运行 make menuconfig 并取消 “Security Features” 下面的复选框 “Enable flash encryption boot”。
  • 退出配置菜单并保存新的配置。
  • 再次运行 make menuconfig ,再次检查是否真的禁止了该选项!如果该选项被使能,bootloader 启动时会立即再次重新加密
  • 运行 make flash to 编译并烧写 flash 加密未被使能的 bootloader 和应用程序。
  • 运行 espefuse.py (在 components/esptool_py/esptool 下面) 禁止 FLASH_CRYPT_CNT efuse)::
    espefuse.py burn_efuse FLASH_CRYPT_CNT

给 ESP32 复位,此时 flash 加密功能会被禁止,bootloader 会像平常一样启动。

Flash 加密的限制

Flash 加密功能可以阻止读取加密的 flash 的内容,保护固件,使其不会在未授权时被读取和修改。如果打算使用 flash 加密系统,则非常有必要理解它的限制:

  • Flash 加密的安全性完全由密钥决定。因此,我们推荐在设备第一次启动时由设备产生密钥(这是默认的行为)。如果密钥是在设备外产生的,请确保其过程的正确性。
  • 不是所有的数据都会被加密存储。如果需要在 flash 上存储数据,请先检查你所使用的方法(库、API 等)是否支持 flash 加密。
  • Flash 加密不能阻止知道 flash 顶层布局的攻击者。这是因为每一对相邻的 16 字节 AES 块使用的是同样的 AES 密钥。当这些相邻的 16 字节块包含相同的内容(例如空区域或填充(pading)区域)时,这些块将会加密生成匹配的加密块对,攻击者可以在加密设备间进行顶层比较(例如判断两个设备运行的固件是否是同一版本)。
  • 同样的理由,攻击者还可以判断两个相连的 16 字节块(32 字节对齐的)是否包含相同的内容。因此一定要记住,如果你想在 flash 上面存储敏感的数据,需要对你的存储方法进行进行一定的设计,确保不会发生这样的事(每 16 个字节使用一个字节的计数器或者其它某些不同的值是足够的)。
  • 仅使用 Flash 加密功能不能阻止攻击者修改设备的固件。如果要阻止设备运行未被授权的固件,需要结合使用 flash 加密功能和 安全启动 功能。

Flash 加密高级功能

下列信息用于描述 flash 加密的高级功能:

加密分区标志

某些分区默认被加密。否则,可以将任何分区标记为需要加密:

在描述 分区表 的 CSV 文件中,存在一个标志字段。该字段通常是空的。如果你在这个字段中写上 “encrypted”,则这个分区将会在分区表中被标记为”加密的”,写到这里的数据也被当当做加密的(与应用程序分区相同):

# 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
  • 默认的分区表不包含任何加密数据分区。
  • “app” 分区不需要被标记为 “encrypted”,因为它们总是被当做加密的。
  • 如果 flash 加密功能未被使能,则 “encrypted” 标志不会起任何作用。
  • 如果你希望从物理上阻止访问/修改带有 phy_init 数据的 phy 分区,你也可以将该分区标记为 “encrypted”。
  • nvs 分区不能被标记为 “encrypted”。
使能 UART Bootloader 加密/解密

默认情况下,在第一次启动时,flash 加密过程会烧写 efuses DISABLE_DL_ENCRYPTDISABLE_DL_DECRYPTDISABLE_DL_CACHE:

  • DISABLE_DL_ENCRYPT,当运行在 UART bootloader 模式时,禁止 flash 加密功能。
  • DISABLE_DL_DECRYPT,当运行在 UART bootloader 模式时,即使 FLASH_CRYPT_CNT efuse 被设置为以正常操作使能 flash 透明解密,也禁止 flash 透明解密。
  • DISABLE_DL_CACHE,当运行在 UART bootloader 模式时,禁止整个 MMU flash cache。

可以只烧写其中一部分 efuses,让其它 efuses 在第一次启动前写保护(将其值复原为 0),例如

espefuse.py --port PORT burn_efuse DISABLE_DL_DECRYPT
espefuse.py --port PORT write_protect_efuse DISABLE_DL_ENCRYPT

(注意,通过一次写保护,这三个 efuses 都会被禁止。因此,有必要在写保护前设置所有的比特。)

IMPORTANT: 当前,对这些 efuses 写保护使其复原不是很有用,因为 esptool.py 不支持读/写加密的 flash。

IMPORTANT: 如果 DISABLE_DL_DECRYPT 被复原(0),这会使 flash 加密不起作用,因为进行物理访问的攻击者可以使用 UART bootloader 模式(使用自定义的桩代码)读出 flash 中的内容。

设置 FLASH_CRYPT_CONFIG

efuse FLASH_CRYPT_CONFIG 用于判断 flash 加密密钥的比特数,具体细节请参考 Flash 加密算法

bootloader 在第一次启动时总是会将这个值设为最大值 0xF

可以在第一次启动前对该 efuse 进行手工写,使其写保护,以选择不同的调整值。不过不推荐这样做。

强烈推荐当 FLASH_CRYPT_CONFIG 的值被设置为零时不要使其写保护。如果它被设置零,flash 加密密钥中没有比特会被调整,flash 加密算法与 AES ECB 模式相同。

技术细节

下面的章节将介绍 flash 加密操作的一些参考信息。

FLASH_CRYPT_CNT efuse

FLASH_CRYPT_CNT 是一个 8 比特的字段,用于控制 flash 加密。Flash 加密的使能/禁止就是基于该 efuse 中被设置为 “1” 的比特的数量。

  • 当偶数比特(0,2,4,6,8)被设置时:Flash 加密被禁止,所有加密的数据将不能被解密。
    • 如果在编译 bootloader 时选择了 “Enable flash encryption on boot”,则 bootloader 遇到的就是这种情形,它会立即对所找都的所有为加密数据进行加密,将 efuse 中的其它比特设置为 ‘1’,表示当前奇数比特被设置了。
      1. 第一次明码文本启动时,比特计数值是 0,bootloader 会将其修改为 1(值 0x1)。
      2. 在下一次明码文本更新后,比特计数值被手工设置 2(值 0x3)。重新加密后,bootloader 会将比特计数值改为 3(值 0x7)。
      3. 在下一次明码文本更新后,比特计数值被手工设置 4(值 0x0F)。重新加密后,bootloader 会将比特计数值改为 5(值 0x1F)。
      4. 在下一次明码文本更新后,比特计数值被手工设置 6(值 0x3F)。重新加密后,bootloader 会将比特计数值改为 7(值 0x7F)。
  • 当奇数比特(1,3,5,7)被设置时:透明读取加密 flash 被使能。
  • 当所有的 8 比特(efuse 值 0xFF)被设置后:透明地读加密 flash 被禁止,所有的加密数据将永久不可访问。bootloader 会检测到这个条件,然后挂起。如果要绕过这种状态来加载为授权的代码,必须使用安全启动或 FLASH_CRYPT_CNT efuse 被写保护。
Flash 加密算法
  • AES-256 操作在数据的 16 字节块之上。flash 加密引擎以 32 字节块(两个 AES 块)加密/解密数据。
  • AES 算法被用于逆向 falsh 加密,因此 flash 加密的加密操作就是 AES 的解密,解密操作就是 AES 加密。这样做是性能的原因,且不会改变算法的性能。
  • 主 flash 加密密钥存储在 efuse (BLK2) 中,且默认具有写保护和软件读保护。
  • 每 32 字节块(两个相连的 16 字节 AES 块)使用一个唯一的密钥进行加密。该密钥由 efuse 中的主 flash 加密密钥推断(与 flash 中该块的偏移量异或,这个偏移量又叫做 “密钥调整值”)而来。
  • 还需要根据 efuse FLASH_CRYPT_CONFIG 的值进行特殊调整。这是一个 4 比特的 efuse,其中每个比特都需要与密钥的某个范围内的比特进行异或:。
    • 比特 1 与密钥的比特 0-66 进行异或。
    • 比特 2 与密钥的比特 67-131 进行异或。
    • 比特 3 与密钥的比特 132-194 进行异或。
    • 比特 4 与密钥的比特 195-256 进行异或。

推荐将 FLASH_CRYPT_CONFIG 保持为默认值 0xF,这样所有的比特都是直接与块的偏移量进行异或的。具体细节请查看 设置 FLASH_CRYPT_CONFIG

  • 块偏移量的高 19 比特(比特 5 ~ 比特 23)被用于与主 flash 加密密钥进行异或。选择这个比特范围有两个原因: flash 的最大容量是 16 MB(24 个比特);每个块是 32 字节的,因此最低 5 比特总是零。
  • 19 比特的块偏移量与 flash 加密密钥之间存在一个特殊的映射,用于判断哪个比特是用于异或的。关于完整的映射关系,请查看 espsecure.py 源文件中的变量 _FLASH_ENCRYPTION_TWEAK_PATTERN
  • 如果想要查看用 Python 语言写的完整的 flash 加密算法,请参考 espsecure.py 源文件中的函数 _flash_encryption_operation()

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.

重要

Enabling secure boot limits your options for further updates of your ESP32. Make sure to read this document throughly and understand the implications of enabling secure boot.

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 Secure Boot Hardware 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.

  1. 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!.

  2. 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.

  3. 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 of the one-time flashing 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 write the signed binary to 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.
  • Use secure boot in combination with flash encryption to prevent local readout of the flash contents.

Technical Details

The following sections contain low-level reference descriptions of various secure boot elements:

Secure Boot Hardware Support

The first stage of secure boot verification (checking the software bootloader) is done via hardware. The ESP32’s 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 (specifically, the digest_secure_bootloader command).

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 RFC 6979.

  • 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

深度睡眠唤醒桩

ESP32 支持从深度睡眠中醒来后运行 “深度睡眠唤醒桩(stub)”,该函数会在芯片唤醒后立即执行 —— 在运行其它任何常规初始化、bootloader、ESP-IDF 代码之前。唤醒桩运行完成后,SoC 可以重新深度睡眠,或者继续正确启动 ESP-IDF。

深度睡眠唤醒桩的代码被加载到 “RTC 快速内存中”,它所使用的所有数据都必须被加载到 RTC 内存中。RTC 内存区域会在深度睡眠期间保留其内容。

唤醒桩的规则

编写唤醒桩代码时必须非常小心:

  • 由于 SoC 才刚刚从睡眠中唤醒,大多数外设都处于复位状态。SPI flash 也未被映射。
  • 唤醒桩代码只能调用在 ROM 中实现的函数或者被加载到 RTC 快速内存中的函数。
  • 唤醒桩代码只能访问加载到 RTC 内存中的数据。其它的所有 RAM 都是未初始化的,其内容是随机的。唤醒桩可以使用其它 RAM 作为临时存储,但是其内容会在 SoC 重新睡眠或者启动 ESP-IDF 后被覆盖。
  • RTC 内存必须包含桩所使用的所有只读数据(.rodata)。
  • RTC 内存中的数据会在除从深度睡眠唤醒之外的其它所有 SoC 重启的时候被初始化。从深度睡眠唤醒时,之前存在的值在深度睡眠期间会继续保持不变。
  • 唤醒桩代码是主 esp-idf 应用程序的一部分。在运行 esp-idf 期间,函数可以向常规程序一样调用唤醒桩函数/访问 RTC 内存。

桩的实现

Esp-idf 中的桩叫做 esp_wake_deep_sleep()。SoC 每次从深度睡眠唤醒后都会运行该函数。esp-idf 默认实现了该函数,但是这个默认函数是一个虚链接函数,因此如果你的应用层中包含一个叫做 esp_wake_deep_sleep() 的函数的话,它将会覆盖这个默认函数。

如果要实现一个自定义的唤醒桩,需要做的第一件事应当是调用 esp_default_wake_deep_sleep()

如果只是为了实现深度睡眠,你不需要在你的应用程序中实现 esp_wake_deep_sleep()。只有当你希望在唤醒后立即做一些特殊行为时才有需要。

如果你希望运行时交换两个不同的深度睡眠桩,你可以调用函数 esp_set_deep_sleep_wake_stub()。如果你只使用了默认的 esp_wake_deep_sleep() 函数,则不需要。

上面这些函数定义在组件 components/esp32 的头文件 esp_deepsleep.h 中。

将代码加到 RTC 内存

唤醒桩代码必须位于 RTC 快速内存中。这可以通过两种方法实现。

第一种方法是使用属性 RTC_IRAM_ATTR 将一个函数放到 RTC 内存中

void RTC_IRAM_ATTR esp_wake_deep_sleep(void) {
    esp_default_wake_deep_sleep();
    // Add additional functionality here
}

第二种方法是将函数放到任意的名字以 rtc_wake_stub 开始的源代码中。以 rtc_wake_stub* 为名字的文件中的内容会被链接器自动放到 RTC 内存中。

第一种方法适用于非常简短的代码或者你想混合使用 “常规” 代码和 “RTC” 代码的源文件。第二种方法适用于比较长的 RTC 代码。

将数据加载到 RTC 内存

桩代码使用的数据必须存放到 RTC 慢速内存中。该内存也会被 ULP 使用。

指定这种数据也有两种方法:

第一种方法是是使用 RTC_DATA_ATTRRTC_RODATA_ATTR 来指定需要加载到 RTC 慢速内存中的数据(分别对应于可写、只读数据)

RTC_DATA_ATTR int wake_count;

void RTC_IRAM_ATTR esp_wake_deep_sleep(void) {
    esp_default_wake_deep_sleep();
    static RTC_RODATA_ATTR const char fmt_str[] = "Wake count %d\n";
    ets_printf(fmt_str, wake_count++);
}

不幸的是,按这种方法使用的字符串常量必须被申明为数组,且使用 RTC_RODATA_ATTR 进行标记,正如上面的例子中展示的那样。

第二种方法是将数据放到任意的以 rtc_wake_stub 开始的源代码中。

例如,同一个例子在 rtc_wake_stub_counter.c 中则是

int wake_count;

void RTC_IRAM_ATTR esp_wake_deep_sleep(void) {
    esp_default_wake_deep_sleep();
    ets_printf("Wake count %d\n", wake_count++);
}

如果你想要使用字符串或者写一些复杂的代码,推荐使用第二种方法。

ULP coprocessor programming

ULP coprocessor instruction set

This document provides details about the instructions used by ESP32 ULP coprocessor assembler.

ULP coprocessor has 4 16-bit general purpose registers, labeled R0, R1, R2, R3. It also has an 8-bit counter register (stage_cnt) which can be used to implement loops. Stage count regiter is accessed using special instructions.

ULP coprocessor can access 8k bytes of RTC_SLOW_MEM memory region. Memory is addressed in 32-bit word units. It can also access peripheral registers in RTC_CNTL, RTC_IO, and SENS peripherals.

All instructions are 32-bit. Jump instructions, ALU instructions, peripheral register and memory access instructions are executed in 1 cycle. Instructions which work with peripherals (TSENS, ADC, I2C) take variable number of cycles, depending on peripheral operation.

The instruction syntax is case insensitive. Upper and lower case letters can be used and intermixed arbitrarily. This is true both for register names and instruction names.

Note about addressing

ESP32 ULP coprocessor’s JUMP, ST, LD instructions which take register as an argument (jump address, store/load base address) expect the argument to be expressed in 32-bit words.

Consider the following example program:

entry:
        NOP
        NOP
        NOP
        NOP
loop:
        MOVE R1, loop
        JUMP R1

When this program is assembled and linked, address of label loop will be equal to 16 (expressed in bytes). However JUMP instruction expects the address stored in register to be expressed in 32-bit words. To account for this common use case, assembler will convert the address of label loop from bytes to words, when generating MOVE instruction, so the code generated code will be equivalent to:

0000    NOP
0004    NOP
0008    NOP
000c    NOP
0010    MOVE R1, 4
0014    JUMP R1

The other case is when the argument of MOVE instruction is not a label but a constant. In this case assembler will use the value as is, without any conversion:

.set        val, 0x10
MOVE        R1, val

In this case, value loaded into R1 will be 0x10.

Similar considerations apply to LD and ST instructions. Consider the following code:

        .global array
array:  .long 0
        .long 0
        .long 0
        .long 0

        MOVE R1, array
        MOVE R2, 0x1234
        ST R2, R1, 0      // write value of R2 into the first array element,
                          // i.e. array[0]

        ST R2, R1, 4      // write value of R2 into the second array element
                          // (4 byte offset), i.e. array[1]

        ADD R1, R1, 2     // this increments address by 2 words (8 bytes)
        ST R2, R1, 0      // write value of R2 into the third array element,
                          // i.e. array[2]
NOP - no operation
Syntax:
NOP
Operands:
None
Description:
No operation is performed. Only the PC is incremented.

Example:

1:    NOP
ADD - Add to register
Syntax:

ADD Rdst, Rsrc1, Rsrc2

ADD Rdst, Rsrc1, imm

Operands:
  • Rdst - Register R[0..3]
  • Rsrc1 - Register R[0..3]
  • Rsrc2 - Register R[0..3]
  • Imm - 16-bit signed value
Description:
The instruction adds source register to another source register or to a 16-bit signed value and stores result to the destination register.

Examples:

1:    ADD R1, R2, R3        //R1 = R2 + R3

2:    Add R1, R2, 0x1234    //R1 = R2 + 0x1234

3:    .set value1, 0x03     //constant value1=0x03
      Add R1, R2, value1    //R1 = R2 + value1


4:    .global label         //declaration of variable label
      Add R1, R2, label     //R1 = R2 + label
        ...
      label: nop            //definition of variable label
SUB - Subtract from register
Syntax:

SUB Rdst, Rsrc1, Rsrc2

SUB Rdst, Rsrc1, imm

Operands:
  • Rdst - Register R[0..3]
  • Rsrc1 - Register R[0..3]
  • Rsrc2 - Register R[0..3]
  • Imm - 16-bit signed value
Description:
The instruction subtracts the source register from another source register or subtracts 16-bit signed value from a source register, and stores result to the destination register.

Examples::

1:         SUB R1, R2, R3             //R1 = R2 - R3

2:         sub R1, R2, 0x1234         //R1 = R2 - 0x1234

3:         .set value1, 0x03          //constant value1=0x03
           SUB R1, R2, value1         //R1 = R2 - value1
4:         .global label              //declaration of variable label
           SUB R1, R2, label          //R1 = R2 - label
             ....
  label:   nop                        //definition of variable label
AND - Logical AND of two operands
Syntax:

AND Rdst, Rsrc1, Rsrc2

AND Rdst, Rsrc1, imm

Operands:
  • Rdst - Register R[0..3]
  • Rsrc1 - Register R[0..3]
  • Rsrc2 - Register R[0..3]
  • Imm - 16-bit signed value
Description:
The instruction does logical AND of a source register and another source register or 16-bit signed value and stores result to the destination register.

Example:

1:        AND R1, R2, R3          //R1 = R2 & R3

2:        AND R1, R2, 0x1234      //R1 = R2 & 0x1234

3:        .set value1, 0x03       //constant value1=0x03
          AND R1, R2, value1      //R1 = R2 & value1

4:        .global label           //declaration of variable label
          AND R1, R2, label       //R1 = R2 & label
              ...
  label:  nop                     //definition of variable label
OR - Logical OR of two operands
Syntax

OR Rdst, Rsrc1, Rsrc2

OR Rdst, Rsrc1, imm

Operands
  • Rdst - Register R[0..3]
  • Rsrc1 - Register R[0..3]
  • Rsrc2 - Register R[0..3]
  • Imm - 16-bit signed value
Description
The instruction does logical OR of a source register and another source register or 16-bit signed value and stores result to the destination register.

Examples:

1:       OR R1, R2, R3           //R1 = R2 \| R3

2:       OR R1, R2, 0x1234       //R1 = R2 \| 0x1234

3:       .set value1, 0x03       //constant value1=0x03
         OR R1, R2, value1       //R1 = R2 \| value1

4:       .global label           //declaration of variable label
         OR R1, R2, label        //R1 = R2 \|label
         ...
  label: nop                     //definition of variable label
LSH - Logical Shift Left
Syntax

LSH Rdst, Rsrc1, Rsrc2

LSH Rdst, Rsrc1, imm

Operands
  • Rdst - Register R[0..3]
  • Rsrc1 - Register R[0..3]
  • Rsrc2 - Register R[0..3]
  • Imm - 16-bit signed value
Description
The instruction does logical shift to left of source register to number of bits from another source register or 16-bit signed value and store result to the destination register.

Examples:

1:       LSH R1, R2, R3            //R1 = R2 << R3

2:       LSH R1, R2, 0x03          //R1 = R2 << 0x03

3:       .set value1, 0x03         //constant value1=0x03
         LSH R1, R2, value1        //R1 = R2 << value1

4:       .global label             //declaration of variable label
         LSH R1, R2, label         //R1 = R2 << label
         ...
  label:  nop                       //definition of variable label
RSH - Logical Shift Right
Syntax

RSH Rdst, Rsrc1, Rsrc2

RSH Rdst, Rsrc1, imm

Operands
Rdst - Register R[0..3] Rsrc1 - Register R[0..3] Rsrc2 - Register R[0..3] Imm - 16-bit signed value
Description
The instruction does logical shift to right of source register to number of bits from another source register or 16-bit signed value and store result to the destination register.

Examples:

1:        RSH R1, R2, R3              //R1 = R2 >> R3

2:        RSH R1, R2, 0x03            //R1 = R2 >> 0x03

3:        .set value1, 0x03           //constant value1=0x03
          RSH R1, R2, value1          //R1 = R2 >> value1

4:        .global label               //declaration of variable label
          RSH R1, R2, label           //R1 = R2 >> label
  label:  nop                         //definition of variable label
MOVE – Move to register
Syntax

MOVE Rdst, Rsrc

MOVE Rdst, imm

Operands
  • Rdst – Register R[0..3]
  • Rsrc – Register R[0..3]
  • Imm – 16-bit signed value
Description

The instruction move to destination register value from source register or 16-bit signed value.

Note that when a label is used as an immediate, the address of the label will be converted from bytes to words. This is because LD, ST, and JUMP instructions expect the address register value to be expressed in words rather than bytes. To avoid using an extra instruction

Examples:

1:        MOVE       R1, R2            //R1 = R2 >> R3

2:        MOVE       R1, 0x03          //R1 = R2 >> 0x03

3:        .set       value1, 0x03      //constant value1=0x03
          MOVE       R1, value1        //R1 = value1

4:        .global     label            //declaration of label
          MOVE        R1, label        //R1 = address_of(label) / 4
          ...
  label:  nop                          //definition of label
ST – Store data to the memory
Syntax
ST Rsrc, Rdst, offset
Operands
  • Rsrc – Register R[0..3], holds the 16-bit value to store
  • Rdst – Register R[0..3], address of the destination, in 32-bit words
  • Offset – 10-bit signed value, offset in bytes
Description

The instruction stores the 16-bit value of Rsrc to the lower half-word of memory with address Rdst+offset. The upper half-word is written with the current program counter (PC), expressed in words, shifted left by 5 bits:

Mem[Rdst + offset / 4]{31:0} = {PC[10:0], 5'b0, Rsrc[15:0]}

The application can use higher 16 bits to determine which instruction in the ULP program has written any particular word into memory.

Examples:

1:        ST  R1, R2, 0x12        //MEM[R2+0x12] = R1

2:        .data                   //Data section definition
  Addr1:  .word     123           // Define label Addr1 16 bit
          .set      offs, 0x00    // Define constant offs
          .text                   //Text section definition
          MOVE      R1, 1         // R1 = 1
          MOVE      R2, Addr1     // R2 = Addr1
          ST        R1, R2, offs  // MEM[R2 +  0] = R1
                                  // MEM[Addr1 + 0] will be 32'h600001
LD – Load data from the memory
Syntax
LD Rdst, Rsrc, offset
Operands

Rdst – Register R[0..3], destination

Rsrc – Register R[0..3], holds address of destination, in 32-bit words

Offset – 10-bit signed value, offset in bytes

Description

The instruction loads lower 16-bit half-word from memory with address Rsrc+offset into the destination register Rdst:

Rdst[15:0] = Mem[Rsrc + offset / 4][15:0]

Examples:

1:        LD  R1, R2, 0x12            //R1 = MEM[R2+0x12]

2:        .data                       //Data section definition
  Addr1:  .word     123               // Define label Addr1 16 bit
          .set      offs, 0x00        // Define constant offs
          .text                       //Text section definition
          MOVE      R1, 1             // R1 = 1
          MOVE      R2, Addr1         // R2 = Addr1 / 4 (address of label is converted into words)
          LD        R1, R2, offs      // R1 = MEM[R2 +  0]
                                      // R1 will be 123
JUMP – Jump to an absolute address
Syntax

JUMP Rdst

JUMP ImmAddr

JUMP Rdst, Condition

JUMP ImmAddr, Condition

Operands
  • Rdst – Register R[0..3] containing address to jump to (expressed in 32-bit words)
  • ImmAddr – 13 bits address (expressed in bytes), aligned to 4 bytes
  • Condition:
    • EQ – jump if last ALU operation result was zero
    • OV – jump if last ALU has set overflow flag
Description
The instruction makes jump to the specified address. Jump can be either unconditional or based on an ALU flag.

Examples:

1:        JUMP       R1            // Jump to address in R1 (address in R1 is in 32-bit words)

2:        JUMP       0x120, EQ     // Jump to address 0x120 (in bytes) if ALU result is zero

3:        JUMP       label         // Jump to label
          ...
  label:  nop                      // Definition of label

4:        .global    label         // Declaration of global label

          MOVE       R1, label     // R1 = label (value loaded into R1 is in words)
          JUMP       R1            // Jump to label
          ...
  label:  nop                      // Definition of label
JUMPR – Jump to a relative offset (condition based on R0)
Syntax
JUMPR Step, Threshold, Condition
Operands
  • Step – relative shift from current position, in bytes
  • Threshold – threshold value for branch condition
  • Condition:
    • GE (greater or equal) – jump if value in R0 >= threshold
    • LT (less than) – jump if value in R0 < threshold
Description
The instruction makes a jump to a relative address if condition is true. Condition is the result of comparison of R0 register value and the threshold value.

Examples:

1:pos:    JUMPR       16, 20, GE   // Jump to address (position + 16 bytes) if value in R0 >= 20

2:        // Down counting loop using R0 register
          MOVE        R0, 16       // load 16 into R0
  label:  SUB         R0, R0, 1    // R0--
          NOP                      // do something
          JUMPR       label, 1, GE // jump to label if R0 >= 1
JUMPS – Jump to a relative address (condition based on stage count)
Syntax
JUMPS Step, Threshold, Condition
Operands
  • Step – relative shift from current position, in bytes
  • Threshold – threshold value for branch condition
  • Condition:
    • EQ (equal) – jump if value in stage_cnt == threshold
    • LT (less than) – jump if value in stage_cnt < threshold
    • GT (greater than) – jump if value in stage_cnt > threshold
Description
The instruction makes a jump to a relative address if condition is true. Condition is the result of comparison of count register value and threshold value.

Examples:

1:pos:    JUMPS     16, 20, EQ     // Jump to (position + 16 bytes) if stage_cnt == 20

2:        // Up counting loop using stage count register
          STAGE_RST                  // set stage_cnt to 0
  label:  STAGE_INC  1               // stage_cnt++
          NOP                        // do something
          JUMPS       label, 16, LT  // jump to label if stage_cnt < 16
STAGE_RST – Reset stage count register
Syntax
STAGE_RST
Operands
No operands
Description
The instruction sets the stage count register to 0

Examples:

1:       STAGE_RST      // Reset stage count register
STAGE_INC – Increment stage count register
Syntax
STAGE_INC Value
Operands
  • Value – 8 bits value
Description
The instruction increments stage count register by given value.

Examples:

1:        STAGE_INC      10          // stage_cnt += 10

2:        // Up counting loop example:
          STAGE_RST                  // set stage_cnt to 0
  label:  STAGE_INC  1               // stage_cnt++
          NOP                        // do something
          JUMPS      label, 16, LT   // jump to label if stage_cnt < 16
STAGE_DEC – Decrement stage count register
Syntax
STAGE_DEC Value
Operands
  • Value – 8 bits value
Description
The instruction decrements stage count register by given value.

Examples:

1:        STAGE_DEC      10        // stage_cnt -= 10;

2:        // Down counting loop exaple
          STAGE_RST                // set stage_cnt to 0
          STAGE_INC  16            // increment stage_cnt to 16
  label:  STAGE_DEC  1             // stage_cnt--;
          NOP                      // do something
          JUMPS      label, 0, GT  // jump to label if stage_cnt > 0
HALT – End the program
Syntax
HALT
Operands
No operands
Description
The instruction halt the processor to the power down mode

Examples:

1:       HALT      // Move chip to powerdown
WAKE – wakeup the chip
Syntax
WAKE
Operands
No operands
Description

The instruction sends an interrupt from ULP to RTC controller.

  • If the SoC is in deep sleep mode, and ULP wakeup is enabled, this causes the SoC to wake up.
  • If the SoC is not in deep sleep mode, and ULP interrupt bit (RTC_CNTL_ULP_CP_INT_ENA) is set in RTC_CNTL_INT_ENA_REG register, RTC interrupt will be triggered.

Examples:

1:        WAKE                      // Trigger wake up
          REG_WR 0x006, 24, 24, 0   // Stop ULP timer (clear RTC_CNTL_ULP_CP_SLP_TIMER_EN)
          HALT                      // Stop the ULP program
          // After these instructions, SoC will wake up,
          // and ULP will not run again until started by the main program.
SLEEP – set ULP wakeup timer period
Syntax
SLEEP sleep_reg
Operands
  • sleep_reg – 0..4, selects one of SENS_ULP_CP_SLEEP_CYCx_REG registers.
Description
The instruction selects which of the SENS_ULP_CP_SLEEP_CYCx_REG (x = 0..4) register values is to be used by the ULP wakeup timer as wakeup period. By default, the value from SENS_ULP_CP_SLEEP_CYC0_REG is used.

Examples:

1:        SLEEP     1         // Use period set in SENS_ULP_CP_SLEEP_CYC1_REG

2:        .set sleep_reg, 4   // Set constant
          SLEEP  sleep_reg    // Use period set in SENS_ULP_CP_SLEEP_CYC4_REG
WAIT – wait some number of cycles
Syntax
WAIT Cycles
Operands
  • Cycles – number of cycles for wait
Description
The instruction delays for given number of cycles.

Examples:

1:        WAIT     10         // Do nothing for 10 cycles

2:        .set  wait_cnt, 10  // Set a constant
          WAIT  wait_cnt      // wait for 10 cycles
TSENS – do measurement with temperature sensor
Syntax
  • TSENS Rdst, Wait_Delay
Operands
  • Rdst – Destination Register R[0..3], result will be stored to this register
  • Wait_Delay – number of cycles used to perform the measurement
Description
The instruction performs measurement using TSENS and stores the result into a general purpose register.

Examples:

1:        TSENS     R1, 1000     // Measure temperature sensor for 1000 cycles,
                                 // and store result to R1
ADC – do measurement with ADC
Syntax
ADC Rdst, Sar_sel, Mux, Cycles
Operands
  • Rdst – Destination Register R[0..3], result will be stored to this register
  • Sar_sel – selected ADC : 0=SARADC0, 1=SARADC1
  • Mux - selected PAD, SARADC Pad[Mux+1] is enabled
  • Cycle – number of cycles used to perform measurement
Description
The instruction makes measurements from ADC.

Examples:

1:        ADC      R1, 0, 1, 100 // Measure value using ADC1 pad 2,
                                 // for 100 cycles and move result to R1
REG_RD – read from peripheral register
Syntax
REG_RD Addr, High, Low
Operands
  • Addr – register address, in 32-bit words
  • High – High part of R0
  • Low – Low part of R0
Description

The instruction reads up to 16 bits from a peripheral register into a general purpose register: R0 = REG[Addr][High:Low].

This instruction can access registers in RTC_CNTL, RTC_IO, and SENS peripherals. Address of the the register, as seen from the ULP, can be calculated from the address of the same register on the DPORT bus as follows:

addr_ulp = (addr_dport - DR_REG_RTCCNTL_BASE) / 4

Examples:

1:        REG_RD      0x120, 2, 0     // load 4 bits: R0 = {12'b0, REG[0x120][7:4]}
REG_WR – write to peripheral register
Syntax
REG_WR Addr, High, Low, Data
Operands
  • Addr – register address, in 32-bit words.
  • High – High part of R0
  • Low – Low part of R0
  • Data – value to write, 8 bits
Description

The instruction writes up to 8 bits from a general purpose register into a peripheral register. REG[Addr][High:Low] = data

This instruction can access registers in RTC_CNTL, RTC_IO, and SENS peripherals. Address of the the register, as seen from the ULP, can be calculated from the address of the same register on the DPORT bus as follows:

addr_ulp = (addr_dport - DR_REG_RTCCNTL_BASE) / 4

Examples:

1:        REG_WR      0x120, 7, 0, 0x10   // set 8 bits: REG[0x120][7:0] = 0x10
Convenience macros for peripheral registers access

ULP source files are passed through C preprocessor before the assembler. This allows certain macros to be used to facilitate access to peripheral registers.

Some existing macros are defined in soc/soc_ulp.h header file. These macros allow access to the fields of peripheral registers by their names. Peripheral registers names which can be used with these macros are the ones defined in soc/rtc_cntl_reg.h, soc/rtc_io_reg.h, and soc/sens_reg.h.

READ_RTC_REG(rtc_reg, low_bit, bit_width)

Read up to 16 bits from rtc_reg[low_bit + bit_width - 1 : low_bit] into R0. For example:

#include "soc/soc_ulp.h"
#include "soc/rtc_cntl_reg.h"

/* Read 16 lower bits of RTC_CNTL_TIME0_REG into R0 */
READ_RTC_REG(RTC_CNTL_TIME0_REG, 0, 16)
READ_RTC_FIELD(rtc_reg, field)

Read from a field in rtc_reg into R0, up to 16 bits. For example:

#include "soc/soc_ulp.h"
#include "soc/sens_reg.h"

/* Read 8-bit SENS_TSENS_OUT field of SENS_SAR_SLAVE_ADDR3_REG into R0 */
READ_RTC_REG(SENS_SAR_SLAVE_ADDR3_REG, SENS_TSENS_OUT)
WRITE_RTC_REG(rtc_reg, low_bit, bit_width, value)

Write immediate value into rtc_reg[low_bit + bit_width - 1 : low_bit], bit_width <= 8. For example:

#include "soc/soc_ulp.h"
#include "soc/rtc_io_reg.h"

/* Set BIT(2) of RTC_GPIO_OUT_DATA_W1TS field in RTC_GPIO_OUT_W1TS_REG */
WRITE_RTC_REG(RTC_GPIO_OUT_W1TS_REG, RTC_GPIO_OUT_DATA_W1TS_S + 2, 1, 1)
WRITE_RTC_FIELD(rtc_reg, field, value)

Write immediate value into a field in rtc_reg, up to 8 bits. For example:

#include "soc/soc_ulp.h"
#include "soc/rtc_cntl_reg.h"

/* Set RTC_CNTL_ULP_CP_SLP_TIMER_EN field of RTC_CNTL_STATE0_REG to 0 */
READ_RTC_REG(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN, 0)

Programming ULP coprocessor using C macros

In addition to the existing binutils port for the ESP32 ULP coprocessor, it is possible to generate programs for the ULP 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.

This instruction halts the coprocessor, but keeps ULP timer active. As such, ULP program will be restarted again by timer. To stop the program and prevent the timer from restarting the program, use I_END(0) instruction.

I_END

Stop ULP program timer.

This is a convenience macro which disables the ULP program timer. Once this instruction is used, ULP program will not be restarted anymore until ulp_run function is called.

ULP program will continue running after this instruction. To stop the currently running program, use I_HALT().

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:

  • bits [31:21] hold the PC of current instruction, expressed in 32-bit words
  • bits [20:16] = 5’b1
  • bits [15:0] are assigned the contents of reg_val

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)

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

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

Installing the toolchain

ULP coprocessor code is written in assembly and compiled using the binutils-esp32ulp toolchain.

1. Download the toolchain using the links listed on this page: https://github.com/espressif/binutils-esp32ulp/wiki#downloads

  1. Extract the toolchain into a directory, and add the path to the bin/ directory of the toolchain to the PATH environment variable.

Compiling ULP code

To compile ULP code as part of a component, the following steps must be taken:

  1. ULP code, written in assembly, must be added to one or more files with .S extension. These files must be placed into a separate directory inside component directory, for instance ulp/.
  1. Modify the component makefile, adding the following:

    ULP_APP_NAME ?= ulp_$(COMPONENT_NAME)
    ULP_S_SOURCES = $(COMPONENT_PATH)/ulp/ulp_source_file.S
    ULP_EXP_DEP_OBJECTS := main.o
    include $(IDF_PATH)/components/ulp/component_ulp_common.mk
    

    Here is each line explained:

    ULP_APP_NAME

    Name of the generated ULP application, without an extension. This name is used for build products of the ULP application: ELF file, map file, binary file, generated header file, and generated linker export file.

    ULP_S_SOURCES

    List of assembly files to be passed to the ULP assembler. These must be absolute paths, i.e. start with $(COMPONENT_PATH). Consider using $(addprefix) function if more than one file needs to be listed. Paths are relative to component build directory, so prefixing them is not necessary.

    ULP_EXP_DEP_OBJECTS

    List of object files names within the component which include the generated header file. This list is needed to build the dependencies correctly and ensure that the generated header file is created before any of these files are compiled. See section below explaining the concept of generated header files for ULP applications.

    include $(IDF_PATH)/components/ulp/component_ulp_common.mk

    Includes common definitions of ULP build steps. Defines build targets for ULP object files, ELF file, binary file, etc.

  2. Build the application as usual (e.g. make app)

    Inside, the build system will take the following steps to build ULP program:

    1. Run each assembly file (foo.S) through C preprocessor. This step generates the preprocessed assembly files (foo.ulp.pS) in the component build directory. This step also generates dependency files (foo.ulp.d).
    2. Run preprocessed assembly sources through assembler. This produces objects (foo.ulp.o) and listing (foo.ulp.lst) files. Listing files are generated for debugging purposes and are not used at later stages of build process.
    3. Run linker script template through C preprocessor. The template is located in components/ulp/ld directory.
    4. Link object files into an output ELF file (ulp_app_name.elf). Map file (ulp_app_name.map) generated at this stage may be useful for debugging purposes.
    5. Dump contents of the ELF file into binary (ulp_app_name.bin) for embedding into the application.
    6. Generate list of global symbols (ulp_app_name.sym) in the ELF file using esp32ulp-elf-nm.
    7. Create LD export script and header file (ulp_app_name.ld and ulp_app_name.h) containing the symbols from ulp_app_name.sym. This is done using esp32ulp_mapgen.py utility.
    8. Add the generated binary to the list of binary files to be emedded into the application.

Accessing ULP program variables

Global symbols defined in the ULP program may be used inside the main program.

For example, ULP program may define a variable measurement_count which will define the number of ADC measurements the program needs to make before waking up the chip from deep sleep:

                        .global measurement_count
measurement_count:      .long 0

                        /* later, use measurement_count */
                        move r3, measurement_count
                        ld r3, r3, 0

Main program needs to initialize this variable before ULP program is started. Build system makes this possible by generating a $(ULP_APP_NAME).h and $(ULP_APP_NAME).ld files which define global symbols present in the ULP program. This files include each global symbol defined in the ULP program, prefixed with ulp_.

The header file contains declaration of the symbol:

extern uint32_t ulp_measurement_count;

Note that all symbols (variables, arrays, functions) are declared as uint32_t. For functions and arrays, take address of the symbol and cast to the appropriate type.

The generated linker script file defines locations of symbols in RTC_SLOW_MEM:

PROVIDE ( ulp_measurement_count = 0x50000060 );

To access ULP program variables from the main program, include the generated header file and use variables as one normally would:

#include "ulp_app_name.h"

// later
void init_ulp_vars() {
    ulp_measurement_count = 64;
}

Note that ULP program can only use lower 16 bits of each 32-bit word in RTC memory, because the registers are 16-bit, and there is no instruction to load from high part of the word.

Likewise, ULP store instruction writes register value into the lower 16 bit part of the 32-bit word. Upper 16 bits are written with a value which depends on the address of the store instruction, so when reading variables written by the ULP, main application needs to mask upper 16 bits, e.g.:

printf("Last measurement value: %d\n", ulp_last_measurement & UINT16_MAX);

Starting the ULP program

To run a ULP program, main application needs to load the ULP program into RTC memory using ulp_load_binary function, and then start it using ulp_run function.

Note that “Enable Ultra Low Power (ULP) Coprocessor” option must be enabled in menuconfig in order to reserve memory for the ULP. “RTC slow memory reserved for coprocessor” option must be set to a value sufficient to store ULP code and data. If the application components contain multiple ULP programs, then the size of the RTC memory must be sufficient to hold the largest one.

Each ULP program is embedded into the ESP-IDF application as a binary blob. Application can reference this blob and load it in the following way (suppose ULP_APP_NAME was defined to ulp_app_name:

extern const uint8_t bin_start[] asm("_binary_ulp_app_name_bin_start");
extern const uint8_t bin_end[]   asm("_binary_ulp_app_name_bin_end");

void start_ulp_program() {
    ESP_ERROR_CHECK( ulp_load_binary(
        0 /* load address, set to 0 when using default linker scripts */,
        bin_start,
        (bin_end - bin_start) / sizeof(uint32_t)) );
}
esp_err_t ulp_load_binary(uint32_t load_addr, const uint8_t *program_binary, size_t program_size)

Load ULP program binary into RTC memory.

ULP program binary should have the following format (all values little-endian):

  1. MAGIC, (value 0x00706c75, 4 bytes)
  2. TEXT_OFFSET, offset of .text section from binary start (2 bytes)
  3. TEXT_SIZE, size of .text section (2 bytes)
  4. DATA_SIZE, size of .data section (2 bytes)
  5. BSS_SIZE, size of .bss section (2 bytes)
  6. (TEXT_OFFSET - 16) bytes of arbitrary data (will not be loaded into RTC memory)
  7. .text section
  8. .data section

Linker script in components/ulp/ld/esp32.ulp.ld produces ELF files which correspond to this format. This linker script produces binaries with load_addr == 0.

Return
  • ESP_OK on success
  • ESP_ERR_INVALID_ARG if load_addr is out of range
  • ESP_ERR_INVALID_SIZE if program_size doesn’t match (TEXT_OFFSET + TEXT_SIZE + DATA_SIZE)
  • ESP_ERR_NOT_SUPPORTED if the magic number is incorrect
Parameters
  • load_addr: address where the program should be loaded, expressed in 32-bit words
  • program_binary: pointer to program binary
  • program_size: size of the program binary

Once the program is loaded into RTC memory, application can start it, passing the address of the entry point to ulp_run function:

ESP_ERROR_CHECK( ulp_run((&ulp_entry - RTC_SLOW_MEM) / sizeof(uint32_t)) );
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

Declaration of the entry point symbol comes from the above mentioned generated header file, $(ULP_APP_NAME).h. In assembly source of the ULP application, this symbol must be marked as .global:

        .global entry
entry:
        /* code starts here */

ULP program flow

ULP coprocessor is started by a timer. The timer is started once ulp_run is called. The timer counts a number of RTC_SLOW_CLK ticks (by default, produced by an internal 150kHz RC oscillator). The number of ticks is set using SENS_ULP_CP_SLEEP_CYCx_REG registers (x = 0..4). When starting the ULP for the first time, SENS_ULP_CP_SLEEP_CYC0_REG will be used to obtain the number of timer ticks. Later the ULP program can select another SENS_ULP_CP_SLEEP_CYCx_REG register using sleep instruction.

Once the timer counts the number of ticks set by the selected SENS_ULP_CP_SLEEP_CYCx_REG register, ULP coprocessor powers up and starts running the program from the entry point set in the call to ulp_run.

The program runs until it encounters a halt instruction or an illegal instruction. Once the program halts, ULP coprocessor powers down, and the timer is started again.

To disable the timer (effectively preventing the ULP program from running again), clear the RTC_CNTL_ULP_CP_SLP_TIMER_EN bit in the RTC_CNTL_STATE0_REG register. This can be done both from ULP code and from the main program.

Unit Testing in ESP32

ESP-IDF comes with a unit test app based on Unity - unit test framework. Unit tests are integrated in the ESP-IDF repository and are placed in test subdirectory of each component respectively.

Adding unit tests

Unit tests are added in the test subdirectory of the respective component. Tests are added in C files, a single C file can include multiple test cases. Test files start with the word “test”.

The test file should include unity.h and the header for the C module to be tested.

Tests are added in a function in the C file as follows:

TEST_CASE("test name", "[module name]"
{
        // Add test here
}

First argument is a descriptive name for the test, second argument is an identifier in square brackets. Identifiers are used to group related test, or tests with specific properties.

There is no need to add a main function with UNITY_BEGIN() and ​UNITY_END() in each test case. unity_platform.c will run UNITY_BEGIN(), run the tests cases, and then call ​UNITY_END().

Each test subdirectory needs to include component.mk file with at least the following line of code:

COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive

See http://www.throwtheswitch.org/unity for more information about writing tests in Unity.

Building unit test app

Follow the setup instructions in the top-level esp-idf README. Make sure that IDF_PATH environment variable is set to point to the path of esp-idf top-level directory.

Change into tools/unit-test-app directory to configure and build it:

  • make menuconfig - configure unit test app.
  • make TESTS_ALL=1 - build unit test app with tests for each component having tests in the test subdirectory.
  • make TEST_COMPONENTS=’xxx’ - build unit test app with tests for specific components.

When the build finishes, it will print instructions for flashing the chip. You can simply run make flash to flash all build output.

You can also run make flash TESTS_ALL=1 or make TEST_COMPONENTS='xxx' to build and flash. Everything needed will be rebuilt automatically before flashing.

Use menuconfig to set the serial port for flashing.

Running unit tests

After flashing reset the ESP32 and it will boot the unit test app.

Unit test app prints a test menu with all available tests.

Test cases can be run by inputting one of the following:

  • Test case name in quotation marks to run a single test case
  • Test case index to run a single test case
  • Module name in square brackets to run all test cases for a specific module
  • An asterisk to run all test cases

资源

Copyrights and Licenses

Software Copyrights

All original source code in this repository is Copyright (C) 2015-2016 Espressif Systems. This source code is licensed under the Apache License 2.0 as described in the file LICENSE.

Additional third party copyrighted code is included under the following licenses:

  • Newlib (components/newlib) is licensed under the BSD License and is Copyright of various parties, as described in the file components/newlib/COPYING.NEWLIB.
  • Xtensa header files (components/esp32/include/xtensa) are Copyright (C) 2013 Tensilica Inc and are licensed under the MIT License as reproduce in the individual header files.
  • esptool.py (components/esptool_py/esptool) is Copyright (C) 2014-2016 Fredrik Ahlberg, Angus Gratton and is licensed under the GNU General Public License v2, as described in the file components/esptool_py/LICENSE.
  • Original parts of FreeRTOS (components/freertos) are Copyright (C) 2015 Real Time Engineers Ltd and is licensed under the GNU General Public License V2 with the FreeRTOS Linking Exception, as described in the file components/freertos/license.txt.
  • Original parts of LWIP (components/lwip) are Copyright (C) 2001, 2002 Swedish Institute of Computer Science and are licensed under the BSD License as described in the file components/lwip/COPYING.
  • KConfig (tools/kconfig) is Copyright (C) 2002 Roman Zippel and others, and is licensed under the GNU General Public License V2.
  • wpa_supplicant Copyright (c) 2003-2005 Jouni Malinen and licensed under the BSD license.
  • FreeBSD net80211 Copyright (c) 2004-2008 Sam Leffler, Errno Consulting and licensed under the BSD license.
  • JSMN JSON Parser (components/jsmn) Copyright (c) 2010 Serge A. Zaitsev and licensed under the MIT license.

Where source code headers specify Copyright & License information, this information takes precedence over the summaries made here.

ROM Source Code Copyrights

ESP32 mask ROM hardware includes binaries compiled from portions of the following third party software:

  • Newlib, as licensed under the BSD License and Copyright of various parties, as described in the file components/newlib/COPYING.NEWLIB.
  • Xtensa libhal, Copyright (c) Tensilica Inc and licensed under the MIT license (see below).
  • TinyBasic Plus, Copyright Mike Field & Scott Lawrence and licensed under the MIT license (see below).
  • miniz, by Rich Geldreich - placed into the public domain.
  • wpa_supplicant Copyright (c) 2003-2005 Jouni Malinen and licensed under the BSD license.
  • TJpgDec Copyright (C) 2011, ChaN, all right reserved. See below for license.

Xtensa libhal MIT License

Copyright (c) 2003, 2006, 2010 Tensilica Inc.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

TinyBasic Plus MIT License

Copyright (c) 2012-2013

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

TJpgDec License

TJpgDec - Tiny JPEG Decompressor R0.01 (C)ChaN, 2011 The TJpgDec is a generic JPEG decompressor module for tiny embedded systems. This is a free software that opened for education, research and commercial developments under license policy of following terms.

Copyright (C) 2011, ChaN, all right reserved.

  • The TJpgDec module is a free software and there is NO WARRANTY.
  • No restriction on use. You can use, modify and redistribute it for personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.
  • Redistributions of source code must retain the above copyright notice.

About

This is documentation of ESP-IDF, the framework to develop applications for ESP32 chip by Espressif.

The ESP32 is 2.4 GHz Wi-Fi and Bluetooth combo, 32 bit dual core chip with 600 DMIPS processing power.

Espressif IoT Integrated Development Framework

Espressif IoT Integrated Development Framework

The ESP-IDF, Espressif IoT Integrated Development Framework, provides toolchain, API, components and workflows to develop applications for ESP32 using Windows, Linux and Mac OS operating systems.