ESP32
模组分类 (选型)
系列 | 内核 | 主频 | 功能 | 数据手册 | 参考手册 |
---|---|---|---|---|---|
ESP32-S2 | Xtensa 单核 | 240 MHz | 2.4 GHz Wi-Fi | ESP32-S2 DataSheet | ESP32-S2 reference_manual |
ESP32-S3 | Xtensa 双核 | 240 MHz | 2.4 GHz Wi-Fi Bluetooth 5 (LE) |
ESP32-S3 DataSheet | ESP32-S3 reference_manual |
ESP32-C2 | RISC-V 单核 | 120 MHz | 2.4 GHz Wi-Fi Bluetooth 5 (LE) |
||
ESP32-C3 | RISC-V 单核 | 160 MHz | 2.4 GHz Wi-Fi Bluetooth 5 (LE) |
ESP32-C3 DataSheet | ESP32-C3 reference_manual |
ESP32-C6 | RISC-V 单核 | 160 MHz | 2.4 GHz Wi-Fi 6 Bluetooth 5 (LE) Zigbee 3.0 Thread |
ESP32-C6 DataSheet | ESP32-C6 reference_manual |
ESP32-H2 | RISC-V 单核 | 96 MHz | Bluetooth 5 (LE) Zigbee 3.0 |
ESP32-H2 DataSheet | ESP32-h2 reference_manual |
ESP32 | Xtensa 单/双核 | 80 MHz ~ 240 MHz | 2.4 GHz Wi-Fi Bluetooth/Bluetooth LE |
ESP32 DataSheet | ESP32 reference_manual |
搭建开发环境
- 安装软件包
sudo apt-get install git wget flex bison gperf python3 python3-pip python3-venv cmake ninja-build ccache libffi-dev libssl-dev dfu-util libusb-1.0-0
- 获取 ESP-IDF
mkdir -p ~/esp
cd ~/esp
git clone --recursive https://github.com/espressif/esp-idf.git
- 设置工具
cd ~/esp/esp-idf
./install.sh esp32s3
- 设置环境变量
. $HOME/esp/esp-idf/export.sh
注意,命令开始的 “.” 与路径之间应有一个空格!
- 配置工程
进入工程目录,设置目标芯片,运行工程配置工具 menuconfig。
cd ~/esp/project
idf.py set-target esp32s3
idf.py menuconfig
- 编译工程
idf.py build
- 擦除 Flash
idf.py -p PORT erase-flash
- 烧录到设备
idf.py -p PORT [-b BAUD] flash
默认波特率:460800
- 查看IRAM使用情况
idf.py size-components
CMake
在ESP32开发中,CMakeLists.txt文件是一个重要的构建脚本,它用于定义和配置项目的构建规则。
作用
- 项目源文件和库的配置:在CMakeLists.txt中,可以列出项目中的源文件和依赖库,并将它们与目标(可执行文件、静态库或动态库)关联起来。
- 编译选项和标志的设置:可以在CMakeLists.txt中设置编译器选项(如编译标准、语言特性等)以及编译标志(如优化级别、警告级别等)。
- 外部依赖项的引入:通过CMakeLists.txt中的指令,可以引入外部依赖项,例如ESP-IDF(ESP32开发框架)的组件或其他库。
- 构建目标的定义:可以定义不同的构建目标,例如可执行文件、静态库或动态库,并指定它们的源文件、依赖项和目标属性等。
编写规则
- CMake最低版本:在CMakeLists.txt文件的开头,通常需要指定CMake的最低版本要求。使用 cmake_minimum_required 命令来指定所需的CMake版本。
- 项目名称:使用 project 命令来设置项目的名称。
- 添加源文件和库:使用 add_executable 、 add_library 等命令来添加源文件和库。将源文件与目标进行关联,定义目标的属性和编译选项。
- 引入外部依赖项:使用 target_link_libraries 命令来引入外部依赖项。这可以包括ESP-IDF的组件、其他第三方库等。
- 设置编译选项和标志:使用 target_compile_options 命令来设置编译器选项和标志。
- 添加其他路径文件:向ESP32的CMakeLists.txt文件中添加文件路径到工程中,可以使用 target_sources 命令。
- 其他设置:根据需要,可以添加其他设置,如设置输出路径、添加编译定义等。
示例
在ESP32项目中,CMakeLists.txt文件分布在不同的目录中,并且每个目录的CMakeLists.txt文件可能有不同的内容。以下是ESP32项目常见目录中CMakeLists.txt文件的示例:
- 顶层目录(项目根目录)的CMakeLists.txt:
cmake_minimum_required(VERSION 3.5)
set(EXTRA_COMPONENT_DIRS "components")
include($$ENV{IDF_PATH}/tools/cmake/project.cmake)
project(my_esp32_project)
- 组件目录的CMakeLists.txt:
idf_component_register(SRCS "component1.c" "component2.c"
INCLUDE_DIRS "include")
- 组件内部子目录下的CMakeLists.txt:
set(COMPONENT_SRCS "subdir/component3.c"
"subdir/component4.c")
set(COMPONENT_ADD_INCLUDEDIRS "subdir/include")
register_component()
- 主应用程序目录的CMakeLists.txt:
idf_component_register(SRCS "main.c"
INCLUDE_DIRS "")
Bootloader Mode
ESP32 内部有45k欧姆的内部上拉电阻,如果要进入下载模式,则需要串个10k左右的电阻到地。
GPIO0 | GPIO2 | |
---|---|---|
serial bootloader | 低电平 | 浮空/低电平 |
Automatic Bootloader | ||
运行模式 | 高电平 | - |
GPIO12 | GPIO15 | |
---|---|---|
默认状态 | 有内部上拉 | 有内部上拉 |
高电平 | VDD_SDIO = 1.8V | 打印启动信息 |
低电平 | VDD_SDIO = 3.3V | 不打印启动信息 |
WiFi
接入阿里云 MQTT
通过wss方式连接阿里云 MQTT,需要 pem 证书
- 生成 pem 证书(前提先安装好
openssl
和sed
)
echo "" | openssl s_client -showcerts -connect mqtt.eclipseprojects.io:443 | sed -n "1,/Root/d; /BEGIN/,/END/p" | openssl x509 -outform PEM >mqtt_eclipse_org.pem
mqtt.eclipseprojects.io替换对应的 MQTT 主机
- 在工程目录下的CMakeLists.txt文件中添加工程的 elf 文件和 pem 证书:
target_add_binary_data(PROJECT.elf "path/to/mqtt_eclipseprojects_io.pem" TEXT)
- 在对应.c文件中声明外部变量并使用
extern const uint8_t mqtt_eclipseprojects_io_pem_start[] asm("_binary_mqtt_eclipseprojects_io_pem_start");
extern const uint8_t mqtt_eclipseprojects_io_pem_end[] asm("_binary_mqtt_eclipseprojects_io_pem_end");
阿里云 MQTT OTA
- 修改分区表
因为选用的 ESP32 的 flash 只有4M,编译文件将近1.4M,如果使用factory APP + 双OTA_x 方式,储存空间明显不够,发现文章有人不用factory分区也可以正常运行
# Name, Type, SubType, Offset, Size, Flags
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
nvs, data, nvs, , 0x4000,
otadata, data, ota, , 0x2000,
phy_init, data, phy, , 0x1000,
# factory, app, factory, , 2M,
ota_0, app, ota_0, , 1600K,
ota_1, app, ota_1, , 1600K,
-
将升级程序上传到阿里云物联网平台
打开阿里云物联网平台,在 “物联网平台/监控运维/OTA 升级 ”中 ,点击 “添加升级包”,
上传完成后,点击“批量升级” -
因为阿里云物联网平台使用的是https协议,所以需要TLS证书,点击下载
将下载的.crt文件添加到工程中,在对应的CMakeLists.txt中添加.crt文件
idf_component_register(
...
EMBED_TXTFILES path/root.crt
)
- 在对应.c文件中声明外部变量并使用
extern const uint8_t server_cert_pem_start[] asm("_binary_root_crt_start");
extern const uint8_t server_cert_pem_end[] asm("_binary_root_crt_end");
参考:https://blog.csdn.net/qq_42900996/article/details/118357518
蓝牙
低功耗蓝牙(BLE)
BLE 服务UUID(Universally Unique Identifier)是一个用于标识BLE设备支持的不同服务的唯一标识符。UUID通常是128位的。
-
前32位(前8个字符):这部分通常是一个16进制的数字,表示UUID的公司或组织标识符。这个部分通常来自Bluetooth SIG(Bluetooth Special Interest Group)分配给各个公司的特定标识符。每个公司都有自己的一组UUID,以便定义其特定的BLE服务。
-
后96位(后24个字符):这部分用于定义具体的BLE服务。这一部分的设计取决于各个公司或组织,以确保其服务UUID的唯一性。
BT 与 BLE 共存
注:程序通过esp_bt_controller_enable(esp_bt_mode_t mode)开启的蓝牙模式要与 SDK 配置的蓝牙控制器的模式一致,否则会报错
低功耗
参考:https://blog.csdn.net/Marchtwentytwo/article/details/128344949
报错和问题
Backtrace回溯
ESP-IDF 应用程序发生 crash 和 panic 事件时,将产生一些寄存器转储和回溯
Backtrace: 0x40375a32:0x3fca6a90 0x4037caf1:0x3fca6ab0 0x4037f876:0x3fca6ad0 0x4037e19f:0x3fca6b50 0x4037f9c4:0x3fca6b70 0x4037f9ba:0x3fca6b90 0x00060820:0x3fca78b4 |<-CORRUPTED
0x40375a32: panic_abort at /home/mo/Esp/esp-idf-v5.1.1/components/esp_system/panic.c:452
0x4037caf1: esp_system_abort at /home/mo/Esp/esp-idf-v5.1.1/components/esp_system/port/esp_system_chip.c:84
0x4037f876: vApplicationStackOverflowHook at /home/mo/Esp/esp-idf-v5.1.1/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c:581
0x4037e19f: vTaskSwitchContext at /home/mo/Esp/esp-idf-v5.1.1/components/freertos/FreeRTOS-Kernel/tasks.c:3728
0x4037f9c4: _frxt_dispatch at /home/mo/Esp/esp-idf-v5.1.1/components/freertos/FreeRTOS-Kernel/portable/xtensa/portasm.S:450
0x4037f9ba: _frxt_int_exit at /home/mo/Esp/esp-idf-v5.1.1/components/freertos/FreeRTOS-Kernel/portable/xtensa/portasm.S:245
解码地址命令
xtensa-esp32s3-elf-addr2line -pfiaC -e build/PROJECT.elf ADDRESS
查看各个任务运行信息
-
menuconfig -> Component config -> FreeRTOS,勾选相关配置
-
调用相关接口
#define CPU_INFO_LEN 512 // 保存CPU运行数据的大小
char cpu_run_info[CPU_INFO_LEN];
memset(cpu_run_info, 0, CPU_INFO_LEN);
vTaskList(cpu_run_info); // 获取任务运行信息
printf("--------------------------------------------------\r\n");
printf("name status priority stack total id\r\n");
printf("%s", cpu_run_info);
printf("--------------------------------------------------\r\n");
堆内存调试(Heap Memory Debugging)
配置Heap Trace:
在 menuconfig 中 Component config
-> Heap Memory Debugging
选项进行配置:
- Heap corruption detection(堆损坏检测级别)
- Base(No poisoning):基本模式(无污染),此为默认级别,默认情况下,不会启用任何特殊的堆内存损坏检测功能。但会启用提供的断言。
- Light impact:轻微影响模式,在此级别下,每个分配的内存块都会在头尾加入“canary 字节”进行“污染”。
- Comprehensive:全面检测模式,此级别包含了轻微影响模式的检测功能,此外还会检查未初始化访问和使用已释放内存产生的错误。
- Heap tracing(堆内存跟踪)
- Standalong:独立模式,确定存在泄漏的代码后,请执行以下步骤:
- 启用 CONFIG_HEAP_TRACING_DEST 选项。
- 在程序早期调用函数 heap_trace_init_standalone() 注册一个可用于记录内存跟踪的缓冲区。
- 在有内存泄漏之嫌的代码块前,调用函数 heap_trace_start() 记录系统中的所有内存分配和释放操作。
- 在有内存泄露之嫌的代码块后,调用函数 heap_trace_stop() 停止跟踪。
- 调用函数 heap_trace_dump() 导出内存跟踪结果。
示例代码
#include "esp_heap_trace.h" #define NUM_RECORDS 100 static heap_trace_record_t trace_record[NUM_RECORDS]; // 该缓冲区必须在内部 RAM 中 ... void app_main() { ... ESP_ERROR_CHECK( heap_trace_init_standalone(trace_record, NUM_RECORDS) ); ... } void some_function() { ESP_ERROR_CHECK( heap_trace_start(HEAP_TRACE_LEAKS) ); do_something_you_suspect_is_leaking(); ESP_ERROR_CHECK( heap_trace_stop() ); heap_trace_dump(); ... }
- Standalong:独立模式,确定存在泄漏的代码后,请执行以下步骤:
fatal error: nvs_flash.h: No such file or directory
在官方 expamle 示例中编译没问题,但移植过去会报找不到头文件错误。
原因:编译时没有把这个组件加入到编译环境中
解决:在使用此组件的文件目录下的 CMakelists.txt 中添加 REQUIRES xxx
参考:
- https://blog.csdn.net/weixin_45499326/article/details/127739659
- https://blog.csdn.net/bluesadman/article/details/121802571
当编译文件过大报错
原因:编译生成的程序是存放在factory区,而factory默认大小为1M,当编译文件大于1MB时,则报以下错误:
FAILED: esp-idf/esptool_py/CMakeFiles/app_check_size /home/mo/esp32/build/esp-idf/esptool_py/CMakeFiles/app_check_size
cd /home/mo/esp32/build/esp-idf/esptool_py && /home/mo/.espressif/python_env/idf5.1_py3.8_env/bin/python /home/mo/Esp/esp-idf-v5.1.1/components/partition_table/check_sizes.py --offset 0x8000 partition --type app /home/mo/esp32/build/partition_table/partition-table.bin /home/mo/esp32/build/esp32.bin
Error: All app partitions are too small for binary esp32.bin size 0x1488d0:
- Part 'factory' 0/0 @ 0x10000 size 0x100000 (overflow 0x488d0)
- Part 'ota_0' 0/16 @ 0x110000 size 0x100000 (overflow 0x488d0)
- Part 'ota_1' 0/17 @ 0x210000 size 0x100000 (overflow 0x488d0)
解决:
- 终端输入 idf.py menuconfig, 先在 Serial flasher config-->flash size 中查看 flash 大小,设置的 flash 的大小需大于所设分区大小
- 在 ESP-IDF 目录下的 components/partition_table/ 选择所需的分区表的模板,拷贝到工程目录下
- 修改 factory 分区大小
# Name, Type, SubType, Offset, Size, Flags
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
nvs, data, nvs, , 0x4000,
otadata, data, ota, , 0x2000,
phy_init, data, phy, , 0x1000,
factory, app, factory, , 2M,
ota_0, app, ota_0, , 2M,
ota_1, app, ota_1, , 2M,
Ali MQTT OTA 报错:
- 报错 1
E (531279) esp-tls: read error :-76
E (531279) TRANS_SSL: esp_tls_conn_read error, errno=No more processes
原因:网络质量差,或者任务栈分配太少
解决:在HTTP客户端配置中添加timeout_ms配置,增大超时时间,或者增加任务栈空间
esp_http_client_config_t config = {
.timeout_ms = 20000,
};
- 报错 2
esp-tls-mbedtls: mbedtls_ssl_handshake returned -0x6C00
原因:ESP-IDF v5.1.2 版本还不支持使用 TLS v1.3
解决:连接 TLS v1.3 服务器,需基于 ESP-IDF v5.2-beta1 及以上版本 SDK 进行测试
配置蓝牙模式时报错:
E (1158) BT_AV: user_bt_init enable controller failed: ESP_ERR_INVALID_ARG
原因:程序通过esp_bt_controller_enable(esp_bt_mode_t mode)开启的蓝牙模式与 SDK 配置的蓝牙控制器的模式不一致
解决:
配置 menuconfig 中Component config
> Bluetooth
> Controller Options
> Bluetooth controller mode (BR/EDR/BLE/DUALMODE)
,选择对应的模式
与华为云物联网平台断开连接
报错1:transport_base: poll_read select error 104, errno = Connection reset by peer, fd = 53
报错2:transport_base: Poll timeout or error, errno=Connection already in progress, fd=-1, timeout_ms=10000
MQTT客户ID冲突
transport_base: tcp_read error, errno=Socket is not connected
mqtt_client: esp_mqtt_handle_transport_read_error: transport_read() error: errno=128
原因:多个设备同时使用同一个客户端ID登录
解决:使用不同的客户端ID进行登录MQTT