跳过正文

使用 C 和 esp-idf 开发 ESP32 项目

·1747 字
Rust Esp32 Rust Esp32
目录
rust-esp32 - 这篇文章属于一个选集。
§ 2: 本文

参考:ESP-IDF (Espressif IoT Development Framework) 开发者文档

1 构建和运行 hello-world 项目
#

这里以运行官方 esp-idf 仓库中的 examples/get-started/hello_world 项目为例。

使用 esp-idf 前必须先 source 安装路径中的 export.sh:

zj@a:~$ source ~/esp/esp-idf/export.sh

zj@a:~$ cd ~/esp/esp-idf/examples/get-started/hello_world/

zj@a:~/esp/esp-idf/examples/get-started/hello_world$ ls
CMakeLists.txt  README.md  main/  pytest_hello_world.py  sdkconfig.ci

清理项目中已经存在的 sdkconfig 文件和 cmake build cache,生成新的 sdkconfig 文件:

  • 使用 idf.py --list-targets 命令列出支持的 CPU target 列表。
zj@a:~/esp/esp-idf/examples/get-started/hello_world$ idf.py set-target esp32s3

重新配置项目:先读取项目中已有的 sdkconfig 文件,然后将行的配置结果保存到 sdkconfig 文件。

zj@a:~/esp/esp-idf/examples/get-started/hello_world$ idf.py menuconfig

构建项目:在 build 目录下生成 3 个后续烧写到设备 Flash 的 bin 文件:

  1. bootloader:build/bootloader/bootloader.bin
  2. 分区表(默认):build/partition_table/partition-table.bin
  3. 程序固件:build/hello_world.bin
zj@a:~/esp/esp-idf/examples/get-started/hello_world$ idf.py build

[998/1000] Generating binary image from built executable
esptool.py v4.8.dev3
Creating esp32s3 image...
Merged 3 ELF sections
Successfully created esp32s3 image.
Generated /Users/alizj/esp/esp-idf/examples/get-started/hello_world/build/hello_world.bin
[999/1000] cd /Users/alizj/esp/esp-idf/examples/get-started/hello_world/build/esp-idf/esptool_py && /User...table/partition-table.bin /Users/alizj/esp/esp-idf/examples/get-started/hello_world/build/hello_world.bi
hello_world.bin binary size 0x35a00 bytes. Smallest app partition is 0x100000 bytes. 0xca600 bytes (79%) free.

Project build complete. To flash, run:
idf.py flash
or
idf.py -p PORT flash
or
python -m esptool --chip esp32s3 -b 460800 --before default_reset --after hard_reset 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/hello_world.bin
or from the "/Users/alizj/esp/esp-idf/examples/get-started/hello_world/build" directory
python -m esptool --chip esp32s3 -b 460800 --before default_reset --after hard_reset write_flash "@flash_args"

将设备 USB-JTAG 接口连接到电脑,然后确认设备文件路径:

  1. linux 系统: /dev/ttyUSB*
  2. macOS 系统: /dev/tty.usbmodem* 或 /dev/cu.usbmodem*
zj@a:~$ ls -l /dev/*.usbmodem*
crw-rw-rw- 1 root 9, 11  5 10 21:38 /dev/cu.usbmodem2101
crw-rw-rw- 1 root 9, 10  5 10 20:16 /dev/tty.usbmodem2101

烧写 3 个 bin 文件到设备 Flash 指定地址:

# 一条命令完成 build/flash/monitor
idf.py -p /dev/cu.usbmodem2101 flash monitor

# idf.py flash 命令自动 build 和 flash
$ idf.py -p /dev/cu.usbmodem2101 flash

# 监控串口输出
$ idf.py -p /dev/cu.usbmodem2101 monitor
Running idf_monitor in directory [...]/esp/hello_world/build
Executing "python [...]/esp-idf/tools/idf_monitor.py -b 115200 [...]/esp/hello_world/build/hello_world.elf"...
--- idf_monitor on <PORT> 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
...


# 上面的 idf.py flash 命令实际是调用 esptool module 实现了,等效为如下命令。
#
# 烧写了三个 bin 文件, 并分别指定了它们在 flash 中的起始地址,这些地址在项目根目录下的
# partitions.csv 文件配置,或使用默认的分区表配置。
python -m esptool \
       --chip esp32s3 \
       -b 460800 \
       --before default_reset \
       --after hard_reset 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/hello_world.bin

2 为项目添加 component 依赖
#

IDF Component 是 esp-idf 项目依赖的 cmake 组件模块, 构建时 cmake 自动从 git repo 或 component ESP-IDF component registry 下载安装到项目中。

参考: idf-component-manager

项目的 idf_component.yml 指定了该 Component 依赖的其它 Component, 可以使用 idf.py create-manifest 命令创建该文件, 当该文件发生变更时需要运行 idf.py reconfigure 命令来更新。

更新依赖: idf.py update-dependencies

自动为项目添加 Component 依赖:

# idf.py add-dependency DEPENDENCY
idf.py add-dependency "espressif/esp_jpeg^1.0.5~2"

# 为项目添加 esp-box BSP,BSP 为开发版提供了高层的抽象封装和初始化, 仓库:
# https://github.com/espressif/esp-bsp;
idf.py add-dependency esp-box

# 或者从指定 Componet 创建一个本地 component
idf.py create-project-from-example "espressif/esp_jpeg^1.0.5~2:get_started"

手动在项目 main component 的 idf_component.yml 文件中添加依赖,可以是:

  1. Registry;
  2. git 仓库;
  3. 本地目录的组件;
# https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-component-manager.html
dependencies:

  # Define a dependency from the registry (https://components.espressif.com/component/example/cmp)
  example/cmp: ">=1.0.0"

  # Define a dependency from a Git repository
  test_component:
    path: test_component
    git: ssh://[email protected]/user/components.git

 # Define local dependency with relative path
  some_local_component:
    path: ../../projects/component

可以从 registry 将 Component 手动下载到本地。以 espressif_esp_jpeg_1.0.5_2 为例,目录结构如下:

  1. idf_component.yml 为 component 元数据文件,包含版本和它的依赖;
  2. CMakeLists.txt 为构建该 component 的配置文件,指定了源文件和头文件;
  3. Kconfig 是该 component 的配置参数文件;
zj@a:~/Downloads/espressif_esp_jpeg_1.0.5_2$ ls -l
total 40K
-rw-r--r-- 1 alizj  270 11 28 13:09 CMakeLists.txt
-rw-r--r-- 1 alizj 2.3K 11 28 13:09 Kconfig
-rw-r--r-- 1 alizj 4.5K 11 28 13:09 README.md
drwxr-xr-x 3 alizj   96 11 28 13:10 examples/
-rw-r--r-- 1 alizj  173 11 28 13:10 idf_component.yml
drwxr-xr-x 3 alizj   96 11 28 13:10 include/
-rw-r--r-- 1 alizj 7.5K 11 28 13:09 jpeg_decoder.c
-rw-r--r-- 1 alizj  12K 11 28 13:09 license.txt
drwxr-xr-x 7 alizj  224 11 28 13:10 test/
drwxr-xr-x 5 alizj  160 11 28 13:10 tjpgd/

# idf_component.yml 为 component 元数据文件,包含版本和它的依赖
zj@a:~/Downloads/espressif_esp_jpeg_1.0.5_2$ cat idf_component.yml
dependencies:
  idf:
    version: '>=4.4'
description: 'JPEG Decoder: TJpgDec'
url: https://github.com/espressif/idf-extra-components/tree/master/esp_jpeg/
version: 1.0.5~2

# CMakeLists.txt 为构建该 component 的配置文件,指定了源文件和头文件
zj@a:~/Downloads/espressif_esp_jpeg_1.0.5_2$ cat CMakeLists.txt
set(sources "jpeg_decoder.c")
set(includes "include")

# Compile only when cannot use ROM code
if(NOT CONFIG_JD_USE_ROM)
    list(APPEND sources "tjpgd/tjpgd.c")
    list(APPEND includes "tjpgd")
endif()

idf_component_register(SRCS ${sources} INCLUDE_DIRS ${includes})

# Kconfig 是该 component 的配置参数文件
zj@a:~/Downloads/espressif_esp_jpeg_1.0.5_2$ cat Kconfig
menu "JPEG Decoder"

    config JD_USE_ROM
        bool "Use TinyJPG Decoder from ROM"
        depends on IDF_TARGET_ESP32 || IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C6 || IDF_TARGET_ESP32S3
        default y
        help
            By default, Espressif SoCs use TJpg decoder implemented in ROM code.
            If this feature is disabled, new configuration of TJpg decoder can be used.
            Refer to REAME.md for more details.

    config JD_SZBUF
        int "Size of stream input buffer"
        depends on !JD_USE_ROM
        default 512

    config JD_FORMAT
        int
        depends on !JD_USE_ROM
        default 0 if JD_FORMAT_RGB888
        default 1 if JD_FORMAT_RGB565

        choice
            prompt "Output pixel format"
            depends on !JD_USE_ROM
            default JD_FORMAT_RGB888
            help
                Output format is selected at runtime.

        config JD_FORMAT_RGB888
            bool "Support RGB565 and RGB888 output (16-bit/pix and 24-bit/pix)"
        config JD_FORMAT_RGB565
            bool "Support RGB565 output (16-bit/pix)"
        endchoice

    config JD_USE_SCALE
        bool "Enable descaling"
        depends on !JD_USE_ROM
        default y
        help
            If scaling is enabled, size of output image can be lowered during decoding.

    config JD_TBLCLIP
        bool "Use table conversion for saturation arithmetic"
        depends on !JD_USE_ROM
        default y
        help
            Use table conversion for saturation arithmetic. A bit faster, but increases 1 KB of code size.

    config JD_FASTDECODE
        int
        depends on !JD_USE_ROM
        default 0 if JD_FASTDECODE_BASIC
        default 1 if JD_FASTDECODE_32BIT
        default 2 if JD_FASTDECODE_TABLE

        choice
            prompt "Optimization level"
            depends on !JD_USE_ROM
            default JD_FASTDECODE_32BIT

        config JD_FASTDECODE_BASIC
            bool "Basic optimization. Suitable for 8/16-bit MCUs"
        config JD_FASTDECODE_32BIT
            bool "+ 32-bit barrel shifter. Suitable for 32-bit MCUs"
        config JD_FASTDECODE_TABLE
            bool "+ Table conversion for huffman decoding (wants 6 << HUFF_BIT bytes of RAM)"
        endchoice
endmenu
zj@a:~/Downloads/espressif_esp_jpeg_1.0.5_2$

3 项目 sdkconfig 配置
#

esp-idf-kconfig 使用 kconfig provides a compile-time project configuration mechanism and offers configuration options of several types. Kconfig files specify dependencies between options, default values of options, the way options are grouped together, etc.

使用命令 idf.py menuconfig 来对项目 kconfig 进行配置, 它读取和写入配置到项目根目录的 sdkconfig 文件中, 然后 esp-idf 构建系统会将这些参数写入 build/sdkconfig.h 头文件中, 这样项目其他位置就可以读取到它们。

开发者也可以定义 sdkconfig.defaults 文件, 然后手动维护其中的配置, esp-idf 构建系统不会修改该文件 (构建系统只会管理 sdkconfig 文件), 这样可以将该文件纳入版本管理:

  • 使用 idf.py save-defconfig 命令来创建 sdkconfig.defaults 文件.
  • 在 main component 的 CMakeLists.txt 文件中通过 SDKCONFIG_DEFAULTS 变量来指定多个分号分割的 sdkconfig.defaults 文件路径;
  • Target 相关的 defaults 配置: sdkconfig.defaults.TARGET_NAME, 如 sdkconfig.defaults.esp32s3;

一旦有了 sdkconfig.defaults 文件, 构建系统就会忽略 sdkconfig 文件, 而是根据 sdkconfig.defaults 文件的配置创建出 sdkconfig 文件.

sdkconfig 配置参数列表: Configuration Options Reference

各种 Componet Config:

rust-esp32 - 这篇文章属于一个选集。
§ 2: 本文

相关文章

Rust 驱动 Audio - 播放和录音
·6323 字
Rust Esp32 Rust Esp32
Rust 驱动 Camera - 采集和播放
·7304 字
Rust Esp32 Rust Esp32
Rust 驱动 LCD - 显示中英文
·818 字
Rust Esp32 Rust Esp32
Rust 驱动 LCD - 显示图片
·4232 字
Rust Esp32 Rust Esp32