乐鑫ESP32系列芯片是性价比非常高的嵌入式平台,不仅外设接口丰富,有较多的存储空间,还支持WIFI/BT等无线连接,同时也支持加密和权限管理等安全功能,这大大拓展了芯片的应用领域;当然,最重要的是该系列芯片的价格并不贵。个人是很看好ESP32系列芯片的前景,故此准备几篇文章来解析该芯片平台的功能,并为以后的开发做技术储备。
初次接触乐鑫ESP32,是从乐鑫的ESP-IDF开发环境开始的,这也是乐鑫主推的开发套件;另外也有Arduino开发套件,暂无涉及。IDF采用CMAKE编译系统,较晦涩复杂,本文不作解析,仅从使用IDF的角度出发。
IDF编译app固件按乐鑫官网的编程指南,安装好IDF开发环境,并复制examples\get-started\blink\作为测试用例,按下述命令编译测试:
>:?idf.py set-target esp32c3? ? #配置目标芯片
>: idf.py menuconfig? ? ? ? ? ? ? ?#图像化配置功能宏,这里修改宏CONFIG_BLINK_GPIO为13
>: idf.py build? ? ? ? ? ? ? ? ? ? ? ? ? #编译blink测试用例
? ? 以下是整个编译过程的主要日志,可以看出涉及到哪些代码,以及编译结果。
Executing action: all (aliases: build)
Running ninja in directory G:\workspace\espressif\blink\build
Executing "ninja all"...
[0/1] Re-running CMake...
-- Building ESP-IDF components for target esp32c3
Processing 2 dependencies: #项目依赖的组件来源
[1/2] espressif/led_strip (2.5.2) #项目目录下的组件:\blink\managed_components\espressif__led_strip
[2/2] idf (5.1.2) #ESP-IDF目录components\下的组件
######编译器添加ESP32C3内部ROM的链接资源以及相关的组件代码路径,准备编译app(blink.bin)
-- Project sdkconfig file G:/workspace/espressif/blink/sdkconfig
-- App "blink" version: 1
-- Adding linker script G:/workspace/espressif/blink/build/esp-idf/esp_system/ld/memory.ld
-- Adding linker script G:/Program/Espressif/frameworks/esp-idf-v5.1.2/components/esp_system/ld/esp32c3/sections.ld.in
-- Adding linker script G:/Program/Espressif/frameworks/esp-idf-v5.1.2/components/esp_rom/esp32c3/ld/esp32c3.rom.ld
-- Adding linker script G:/Program/Espressif/frameworks/esp-idf-v5.1.2/components/esp_rom/esp32c3/ld/esp32c3.rom.api.ld
-- Adding linker script G:/Program/Espressif/frameworks/esp-idf-v5.1.2/components/esp_rom/esp32c3/ld/esp32c3.rom.libgcc.ld
-- Adding linker script G:/Program/Espressif/frameworks/esp-idf-v5.1.2/components/esp_rom/esp32c3/ld/esp32c3.rom.newlib.ld
-- Adding linker script G:/Program/Espressif/frameworks/esp-idf-v5.1.2/components/esp_rom/esp32c3/ld/esp32c3.rom.version.ld
-- Adding linker script G:/Program/Espressif/frameworks/esp-idf-v5.1.2/components/esp_rom/esp32c3/ld/esp32c3.rom.eco3.ld
-- Adding linker script G:/Program/Espressif/frameworks/esp-idf-v5.1.2/components/soc/esp32c3/ld/esp32c3.peripherals.ld
-- Components: app_trace app_update bootloader bootloader_support bt cmock console cxx driver efuse esp-tls esp_adc esp_app_format esp_coex esp_common esp_eth esp_event esp_gdbstub esp_hid esp_http_client esp_http_server esp_https_ota esp_https_server esp_hw_support esp_lcd esp_local_ctrl esp_mm esp_netif esp_netif_stack esp_partition esp_phy esp_pm esp_psram esp_ringbuf esp_rom esp_system esp_timer esp_wifi espcoredump espressif__led_strip esptool_py fatfs freertos hal heap http_parser idf_test ieee802154 json log lwip main mbedtls mqtt newlib nvs_flash openthread partition_table protobuf-c protocomm pthread riscv sdmmc soc spi_flash spiffs tcp_transport ulp unity usb vfs wear_levelling wifi_provisioning wpa_supplicant
-- Component paths: #上面的组件列表不止来源于ESP-IDF组件目录,还包含了项目目录(..../blink/)下的组件
... ... ... (略)
[1/875] Generating project_elf_src_esp32c3.c
[2/875] Generating ../../partition_table/partition-table.bin #生成分区表镜像文件partition-table.bin
Partition table binary generated. Contents:
*******************************************************************************
# ESP-IDF Partition Table
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 24K, #非易失性存储,储存工厂校准数据和配置数据
phy_init,data, phy, 0xf000, 4K, #以太网PHY初始化数据
factory, app, factory, 0x10000, 1M, #系统分区,例如工厂的生产固件,默认运行分区
*******************************************************************************
[3/875] Generating memory.ld linker script...
... ... ... (略) #编译组件的代码
######编译器添加ESP32C3内部ROM的链接资源以及相关的组件代码路径,准备编译bootloader.bin
-- Adding linker script G:/Program/Espressif/frameworks/esp-idf-v5.1.2/components/soc/esp32c3/ld/esp32c3.peripherals.ld
-- App "bootloader" version: 1
-- Adding linker script G:/Program/Espressif/frameworks/esp-idf-v5.1.2/components/esp_rom/esp32c3/ld/esp32c3.rom.ld
-- Adding linker script G:/Program/Espressif/frameworks/esp-idf-v5.1.2/components/esp_rom/esp32c3/ld/esp32c3.rom.api.ld
-- Adding linker script G:/Program/Espressif/frameworks/esp-idf-v5.1.2/components/esp_rom/esp32c3/ld/esp32c3.rom.libgcc.ld
-- Adding linker script G:/Program/Espressif/frameworks/esp-idf-v5.1.2/components/esp_rom/esp32c3/ld/esp32c3.rom.newlib.ld
-- Adding linker script G:/Program/Espressif/frameworks/esp-idf-v5.1.2/components/bootloader/subproject/main/ld/esp32c3/bootloader.ld
-- Adding linker script G:/Program/Espressif/frameworks/esp-idf-v5.1.2/components/bootloader/subproject/main/ld/esp32c3/bootloader.rom.ld
-- Components: bootloader bootloader_support efuse esp_app_format esp_common esp_hw_support esp_rom esp_system esptool_py freertos hal log main micro-ecc newlib partition_table riscv soc spi_flash
-- Component paths: ... ... ...
[668/875] Performing build step for 'bootloader'
... ... ... (略) #编译bootloader组件的代码
Successfully created esp32c3 image.
Generated G:/workspace/espressif/blink/build/bootloader/bootloader.bin #生成引导镜像文件bootloader.bin
[96/96] cmd.exe /C "cd /D G:\workspace\espressif\blink\build\bootloader\esp-idf\esptool_py && G:\Program\Espressif\python_env\idf5.1_py3.11_env\Scripts\python.exe G:/Program/Espressif/frameworks/esp-idf-v5.1.2/components/partition_table/check_sizes.py --offset 0x8000 bootloader 0x0 G:/workspace/espressif/blink/build/bootloader/bootloader.bin"
Bootloader binary size 0x5070 bytes. 0x2f90 bytes (37%) free.
[669/875] No install step for 'bootloader'
[670/875] Completed 'bootloader'
[671/875] Generating x509_crt_bundle
[672/875] Generating ../../x509_crt_bundle.S
... ... ... (略)#继续编译app的关联代码
[873/875] Linking CXX executable blink.elf
[874/875] Generating binary image from built executable
esptool.py v4.7.0
Creating esp32c3 image...
Merged 1 ELF section
Successfully created esp32c3 image.
Generated G:/workspace/espressif/blink/build/blink.bin #生成APP镜像文件blink.bin
[875/875] cmd.exe /C "cd /D G:\workspace\espressif\blink\build\esp-idf\esptool_py && G:\Program\Espressif\python_env\idf5.1_py3.11_env\Scripts\python.exe G:/Program/Espressif/frameworks/esp-idf-v5.1.2/components/partition_table/check_sizes.py --offset 0x8000 partition --type app G:/workspace/espressif/blink/build/partition_table/partition-table.bin G:/workspace/espressif/blink/build/blink.bin"
blink.bin binary size 0x2ec20 bytes. Smallest app partition is 0x100000 bytes. 0xd13e0 bytes (82%) free.
######编译完成
Project build complete. To flash, run this command: #下载命令行:烧录所有镜像到ESP32C3开发板
G:\Program\Espressif\python_env\idf5.1_py3.11_env\Scripts\python.exe ..\..\..\Program\Espressif\frameworks\esp-idf-v5.1.2\components\esptool_py\esptool\esptool.py -p (PORT) -b 460800 --before default_reset --after hard_reset --chip esp32c3 write_flash --flash_mode dio --flash_size 2MB --flash_freq 80m 0x0 build\bootloader\bootloader.bin 0x8000 build\partition_table\partition-table.bin 0x10000 build\blink.bin
or run 'idf.py -p (PORT) flash'
?从代码的组成部分来看,一个测试用例,会涉及4个方面:
从编译结果来看,测试固件分3个部分:
最后的下载命令行用于烧录固件到ESP32C3开发板:
>: idf.py -p COM5? flash? #板子串口COM5
上述命令会烧录全部的固件,烧录地址和镜像文件的关系,如下
????????0x00000?build\bootloader\bootloader.bin
????????0x08000 build\partition_table\partition-table.bin
????????0x10000 build\blink.bin
注意,烧录位置,并不在ESP32C3内部,而是SPI接口的外部flash存储芯片,下一小节讲述芯片的存储结构。
烧录地址并不是固定的,与分区表相关;分区表允许修改或重新指定配置文件,具体见IDF组件目录:components\partition_table\,默认分区表为partitions_singleapp.csv,分区信息见上面的编译日志。
当前的Flash分区存储结构如下:
?Bootloader? ? ?-?起始必须是0x00000,大小等于CONFIG_PARTITION_TABLE_OFFSET?
?PartitionTable - 起始为CONFIG_PARTITION_TABLE_OFFSET (0x8000),固定大小4KB
?nvs数据分区? ?- 紧挨上个分区结尾并4KB对齐:0x9000,大小24KB
?phy数据分区? ?-?紧挨上个分区结尾并4KB对齐:0xF000,大小4KB
?factory? ? ? ? ? ? -?紧挨上个分区结尾并4KB对齐:0x10000,大小1024KB
另,其他编译和烧录命令:
idf.py app #单独编译APP,比如blink.bin
idf.py size #查看APP占用RAM+ROM的情况
idf.py app-flash #单独烧录app分区,比如将blink.bin烧录到默认app分区:factory
idf.py encrypted-app-flash #加密并烧录APP
idf.py bootloader #单独编译引导镜像
idf.py bootloader-flash #单独烧录引导镜像
idf.py partition-table #单独生成分区表镜像
idf.py partition-table-flash #单独烧录分区表镜像
idf.py erase-flash #擦除整块FLASH芯片,慎重!请先备份工厂的数据分区
idf.py erase-otadata #擦除OTA数据分区
idf.py read-otadata #读取OTA数据分区
分区工具parttool.py的用法举例:
# 擦除名为'storage' 的分区
parttool.py --port "/dev/ttyUSB1" erase_partition --partition-name=storage
# 读取类型为'data'、子类型为'spiffs' 的分区, 保存到'spiffs.bin' 文件
parttool.py --port "/dev/ttyUSB1" read_partition --partition-type=data --partition-subtype=spiffs --output "spiffs.bin"
# 将'factory.bin' 文件中的内容写入到'factory' 分区
parttool.py --port "/dev/ttyUSB1" write_partition --partition-name=factory --input "factory.bin"
# 打印默认启动分区的大小
parttool.py --port "/dev/ttyUSB1" get_partition_info --partition-boot-default --info size
# 显示子命令的描述
parttool.py [subcommand] --help