1、搭建基础工程
(1)启动VS Code 并打开命令面板
按下 “Ctrl+Shift+P” 快捷键打开命令面板,并在搜索栏内输入“新建项目”,如下图所示:
(2)配置工程参数
上图回车进入新建工程配置界面,如下图所示:
(3)选择模板工程
配置参数填写完称后,点击上图的 “Choose Template” 选项,将进入选择模板界面。在这个界面上,你会发现许多应用实例可供选择。为了新建工程,你可以采用某个应用示例作为模板,例如,若以乐鑫 Blink 跑马灯实验为模版,那么新创建的工程将具备 LED使用功能。 下面以 sample_project 为模版新建工程(因为此工程是乐鑫官方提供的基本模板,所以我们使用此模板来新建工程),如下图所示:
点击“Create project using template sample_project”选项新建工程,点击完成后在此界面的右下角跳出以下信息,如下所示:
我们点击“Yes”选项即可完成新建工程。此时 VS Code 的资源管理器区域内显示我们的新建工程,如下图所示:
2、基础工程的文件架构解析
(1)文件架构
(2).devcontainer和.vscode文件夹在 VS Code 的使用场景中各自扮演着不同的角色。
- .devcontainer 文件夹通常与 VS Code 的 Remote - Containers 扩展一起使用,用于定义开发容器环境的配置。这个文件夹包含了用于创建和管理容器化开发环境的所有必须文件。
- .vscode 文件夹通常位于项目的根目录下,用于存放 VS Code 的项目级设置和扩展配置。这个文件夹中的文件不会影响其他用户或全局的 VS Code 设置,它们只针对当前项目有效。
在.vscode文件夹中,常见的文件包括:- settings.json。用于定义项目特定的 VS Code 设置 (个性配置和工作环境配置)。
- tasks.json。用于定义任务,这些任务可以在 VS Code 的终端中运行,或者与编辑器中的其他功能(如代码片段)结合使用。
- launch.json。用于配置调试器,包括启动配置和断点等。
- c_cpp_properties.json。这个文件用于定义C和C++项目的编译器路径、包含路径、编译器定义以及其他与IntelliSense相关的设置。
上述文件都是 VSCode自动生成的,不需要人为去编写。但是在某种特殊情况下需要人为介入,如代码调试(需要修改 launch.json)、编译错误(需要修改 c_cpp_properties.json)和个性配置(需要修改 settings.json)等。剩下的文件就是工程的文件结构,如下图所示:
├CMakeLists.txt # 项目的朱CMake文件,定义了项目的基本设置和组件
├main # 主应用程序目录
│ ├CMakeLists.txt # 主应用程序的CMake文件
│ ├main.c # 主应用程序的C源文件,通常包含app_main()入口函数
├README.md # 提供项目的基本信息、使用说明和其他相关信息。
├sdkconfig # 编译后生成,项目的配置文件,记录了menuconfig中的配置选项
3、调试相关工具介绍
在上述中,已经在VS Code环境下新建一个工程,下面介绍VS Code软件提供用户调试相关的工具有哪些,如下所示:
- 选择串口(插头):即连接硬件的下载串口号,VS 会列出当前连接电脑的所有串口让你选择,这个会记录,再新打开 VSCode 不用重新选择,开发过程中尽量不要更换USB线的电脑插口,否则串口号会变。
- 选择目标芯片:对应idf命令 idf.py set-target xxxx。即你当前这个工程是要下载到什么芯片上面,如ESP32 S2,S3,C2,C3等等,工程要与芯片相匹配,这个选择是写入当前工程配置的,一般不用更改,工程下配置文件基本已经选择好的。
- 选择当前工程目录(文件夹):也不用修改,一般打开工程时会默认操作都在这个工程目录下。
- 工程配置菜单(齿轮):对应idf命令 idf.py menuconfig,用来配置当前工程的一些设置,配置项非常多,建议使用到再修改。一般代码工程都是配置好的,且不用修改。
- 清除工程(垃圾桶):清除工程编译文件,一般用于压缩拷贝工程文件时用到,清除后工程目录占用空间会非常小,KB级,编译后为百MB级,还有一些编译过程中奇奇怪怪的问题也可以先清除编译后再编译。
- 编译工程(圆柱体):编译当前工程,只是编译,没有下载功能。
- 选择下载模式(五角星):一般都是选择串口UART方式下载。
- 下载(闪电):下载编译好的固件到设备芯片上,这里只是下载,没有编译功能,修改代码后要先编译再点这个下载,所做的修改才有效。
- 串口监控(小电视):打开与设备连接的串口,打印设备串口信息。
- 编译/下载/监控(一团火):最常用的一个,它将编译下载和打开串口监视器做在了一起,点一次全部搞定。
- 打开命令行:打开命令行窗口,且会定位在当前项目路径下,可以执行idf的一些命令。
- 执行自定义任务:不使用。
- 工程的错误与警告提示。
以上是ESP-IDF插件提供的调试工具。ESP32-S3有两种下载方式。首先是USB串口下载,这种方式主要用于代码下载,但无法用于代码调试。另一种则是JTAG(USB口)下载,它不仅能用于下载代码,还支持代码调试。下面介绍这两种下载方式。
- UART和JTAG来回切换会导致sdkconfig配置项复位。
3.1、串口下载
打开工程,编译通过后可通过串口下载程序。下载流程如下所示。
(1)将板子串口与电脑USB(USB转串口)连接,使得电脑与开发板建立连接。
- 下载电路分析:
论ESP32自动下载电路-CSDN博客
(2)在设备管理器中,查看USB串口的端口号,并在VS Code软件左下角调试区域设置端口号(图标为插头)。
(3)点击“Set Espressif Device Target”选择目标芯片,这里我们选择 ESP32-S3。
网上说如下选项是ESP32-S3相关的编程和调试接口或方法,这里选择什么都能下载,暂时不管。
- via ESP-PROG
- via builtin USB-JTAG
- via ESP USB Bridge
(4)选择“select flash Method” 下载方式(五角星),UART或者JTAG,这里选择UART。
- JTAG
- UART
- DFU:DFU (Device Firmware Update) 是一种在USB设备上进行固件升级的标准模式。
(5)点击 “Full Clean” 擦除工程(垃圾桶)。
(6)点击 “Build Project” 编译工程(圆柱形)。
(7)编译完成后,点击 “ESP-IDF:Flash Device” 下载代码(闪电)。
编译工程成功后, 工程目录下出现 build 文件夹,这个文件夹是由 ESP-IDF 编译器生产的文
件,如 log、固件、 map 等下载和调试文件。 如下图所示:
编译输出文件(部分截图)
编译完成后, VSCode 软件底部的 Build Output 窗口会输出编译信息,如下图所示:
当出现以上信息后便证明工程编译成功,上图中可以查到本次编译的许多信息,这里介绍几个重要信息:
(1)Used static IRAM:为了与 ESP32-S3目标兼容,保留了这些选项,当前读取为 56526 bytes(.text size + . vectors size)
- .text size:文本占用空间大小(55499 bytes)
- .vectors size:矢量大小(1027 bytes)
(2)Used stat D/IRAM:这是内部 RAM 的总使用量,静态 DRAM .data + .bss 的总和,以及
应用程序用于可执行代码的静态 IRAM(指令 RAM)。可用大小是运行时作为堆内存可用的
DRAM 的估计量(由于元数据开销和实现限制,以及 ESP-IDF 在启动期间完成的堆分配,启动
时的实际可用堆将低于此值)。
- .data size:是静态分配的 RAM,在启动时分配给非零值。这在运行时使用 RAM(DRAM),并且还使用二进制文件中的空间。
- .bss size:是静态分配的 RAM,在启动时分配为零。这在运行时使用 RAM(DRAM),
但不使用二进制文件中的任何空间。
(3)Used Flash size:这表示项目在编译后将使用的 Flash 内存的大小,但不包括 DRAM 和
IRAM 的使用量。
- .text:这部分用于表示.text 的 Flash 大小。
- .rodata:这部分用于表示.rodata 的 Flash 大小。
(4)Total image size:是二进制文件的预估总大小。
3.2、JTAG下载与调试
略
4、基础工程配置
在如上工程的编译下载中,并未立刻配置ESP32S3模组的内部资源,例如时钟频率、Flash配置等。这些参数需要自行配置,否则工程只能使用乐鑫的默认配置进行开发,这样模组便无法充分发挥其应有的性能。这里使用的是ESP32-S3-WROOM-1-N16R8:
- Flash:16MB
- PSRAM:8MB
下面,进行基础工程的配置,配置流程如下:
(1)使用VS Code打开工程,并点击左下角的 ESP-IDF: SDK Configurati
on Editor (menuconfig)(齿轮),进入menuconfig(菜单配置)界面,如下图所示:
关于 menuconfig 配置界面的具体内容,后面有时间再看,这里只介绍部分内容。
(2)在上图“Search parameter”搜索框下输入“Flash”进去 flash 配置界面,配置内容如下所示:
上图中的① “Flash SPI mode” 支持四种不同的 SPI flash 访问模式,它们分别为 DIO、DOUT、 QIO 和 QOUT。这几种模式到底有哪些区别,这些模式的对比如下表所示:
Flash SPI mode (可选项) | 模式名称 | 引脚 | 速度 |
---|---|---|---|
QIO | Quad I/O | 地址和数据4pins | 最快 |
QOUT | Quad Output | 数据4pins | 约比qio模式下慢15% |
DIO | Dual I/O | 地址和数据2pins | 约比qio模式下慢45% |
DOUT | Dual Output | 数据2pins | 约比qio模式下慢50% |
从上表可知, QIO 模式的速率为最快,所以我们把工程的 Flash SPI mode 设置为 QIO。
上图中的②“Flash SPI speed”提供了120、80、40和20MHz的配置选项。在选择具体速度
时,我们需要考虑 Flash 和 PSRAM 的 SPI 接口共享情况。为了优化模组性能,我们最好将 flash
和 PSRAM的 SPI速率设置为一致,这样分时访问这两个存储设备时,就不必切换时钟频率了。
鉴于 PSRAM 的 SPI 速率最高可设置为 80MHz,因此我们将 flash 的 SPI 速率也设置为 80MHz,
以确保最佳性能。
上图的③是根据模组挂在的 flash 来确定的,这里我们选择 16MB 大小。
(3)在搜索框中输入“Partition Table”来设置分区表。分区表的主要功能是将 flash划分为多
个功能各异的区域,包括存储启动文件、代码区域和文件系统区域等子分区,以满足不同的应
用需求。下图是基础工程分区表配置参数:
上图中,我们选择“Custom partition table CSV”自定义分区表,然后设置分区表的名称为
partitions-16MB.csv。稍后我们会设置分区表各个子分区的管理大小。
(4)在搜索框中输入“PSRAM”来设置 PSRAM 参数,配置参数如下图所示:
上图的①选项是基于模组内部芯片的选择来确定的。为了正确配置,读者可以查阅
《esp32-s3-wroom-1_wroom-1u_datasheet_cn》数据手册的第三页。在该页中,我们可以看到ESP32-S3-WROOM-1-N16R8 模组所挂载的 PSRAM使用的是 Octal SPI模式。因此,在配置过程
中,我们应该选择“Octal Mode PSRAM”这一选项。
上图的②选项选择最该的速率即可,并且与 Flash SPI 速率一致。
(5)在搜索框中输入“CPU frequency” 来设置CPU的时钟频率,如下图所示:
(6)在搜索框中输入“FreeRTOS”来配置系统节拍时钟(tick clock)的频率。默认情况下,
“configTICK_RATE_HZ” 的 值 为 100, 意 味 着 节 拍 时 钟 的 周 期 为 10ms。 因 此 , 调 用
vTaskDelay(1000)将会导致延时 10 秒。为了提高定时精度和方便性,建议将该值设置为 1000,
这样节拍时钟的周期就变为 1ms,从而使得 vTaskDelay(1000)代表延时 1 秒。如下图所示:
(7)配置分区表各个子分区,我们按下“Ctrl+Shift+P”快捷键打开命令面板,并在搜索栏
内输入“打开分区表编辑器”,按以下图配置各个分区的管理大小。

首先我们按下“Add New Row”选项添加子分区条目,然后设置条目的类型、子类型、偏移和大小,最后点击“Save”选项保存退出。
至此,我们已经完成了工程配置,确保其与 ESP32 模组的内部资源相匹配。
5、配置后工程架构
(1)架构说明
├CMakeLists.txt
├main
│ ├CMakeLists.txt
│ ├main.c
├partitions-16Mb.csv
├README.md
├sdkconfig
├sdkconfig.old
- sdkconfig.old是之前的基础工程所使用的旧版系统配置文件,用于记录之前的配置信息。
- sdkconfig是系统最新生成的系统配置文件,包含最新的配置设置。
- partitons-1MB.csv是系统配置保存后自动生成的分区表文件,该文件可供用户查看,以便了解当前的分区表配置情况。
(2)打印模组内部资源信息
在 app_main 函数中编写如下代码,以获取 ESP32模组的内部资源信息。这些信息包括CPU内核数、 flash 大小以及 PSRAM 大小等。具体的代码实现如下所示:
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "nvs_flash.h"
#include "esp_system.h"
#include "esp_chip_info.h"
#include "esp_psram.h"
#include "esp_flash.h"
/**
* @brief 程序入口
* @param 无
* @retval 无
*/
void app_main(void)
{
esp_err_t ret;
uint32_t flash_size; /* 存储Flash大小,M字节 */
esp_chip_info_t chip_info; /* 定义芯片信息结构体变量 */
ret = nvs_flash_init(); /* 初始化 NVS */
if (ret == ESP_ERR_NVS_NO_FREE_PAGES
|| ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
{
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
/* 获取 CPU 内核数并显示 */
esp_chip_info(&chip_info);
printf("内核: cup 数量%d\n",chip_info.cores);
/* 获取 FLASH 大小并显示 */
esp_flash_get_size(NULL, &flash_size);
printf("FLASH size:%ld MB flash\n",flash_size / (1024 * 1024));
/* 获取 PARAM 大小并显示 */
printf("PSRAM size: %d bytes\n", esp_psram_get_size());
while(1)
{
printf("Hello-ESP32\r\n");
vTaskDelay(1000);
}
}
上述代码是获取 ESP32 模组的内部资源信息,并打印到监控器上。首先我们编译基础工程,然后下载至开发板中,最后打开监控器查看串口打印内容,如下图所示: