超级版主
 
- 积分
- 5201
- 金钱
- 5201
- 注册时间
- 2019-5-8
- 在线时间
- 1307 小时
|
本帖最后由 正点原子运营 于 2025-12-4 09:41 编辑
第五章 工程的新建与配置
1)实验平台:正点原子DNESP32P4开发板
2)章节摘自【正点原子】ESP32-P4开发指南— V1.0
3)购买链接:https://detail.tmall.com/item.htm?id=873309579825
4)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/esp32/ATK-DNESP32P4.html
5)正点原子官方B站:https://space.bilibili.com/394620890
6)正点原子DNESP32S3开发板技术交流群:132780729
在前面的章节中,我们已经简要介绍了ESP32-P4的基础知识和ESP-IDF的基本概念,并完成了VS Code IDE环境的搭建和Espressif插件的安装。现在,基于这些前期准备,我们将在本章搭建一个ESP-IDF项目工程。之后的例程将以此基础工程为模版进行编写和扩展。
本章将分为如下几个小节:
5.1 新建项目工程
5.2 工程文件架构解析
5.3 工程文件架构整理
5.4 项目工程配置
5.5 ESP-IDF插件的下载与调试工具
5.1 新建项目工程
在VS Code中新建ESP32工程是非常简单的操作,接下来笔者将手把手教大家如何一步步创建ESP32项目工程。通过以下步骤,读者可以快速上手并建立自己的ESP32开发环境。
1,打开所有命令面板
按下“Ctrl+Shift+P”快捷键打开所有命令面板,并在搜索栏内输入“新项目”或者“New Project”内容,如下图所示。
图5.1.1 搜索创建项目命令
2,配置项目工程参数
上图回车后,我们根据需求配置项目工程名称、项目保存路径、选择目标芯片、端口号等配置,如下图所示。
图5.1.2 新建工程配置参数
3,选择工程模板新建项目工程
配置参数填写完成后,点击上图中的“Choose Template”选项,将进入选择模版界面。在这个界面上,您会发现许多应用实例可供选择(这些示例可以在路径D:\Soft_APP\Espressif\frameworks\esp-idf\examples下找到)。为了新建工程,您可以采用某个应用示例作为模版,例如,若以乐鑫Blink跑马灯实验为模版,那么新创建的工程将具备LED使用功能。下面笔者以sample_project为模版新建工程(因为此工程是乐鑫官方提供的基本模板,所以我们使用此模板来新建工程),如下图所示:
图5.1.3 以sample_project为模版新建工程
点击上图的“Create project using template sample_project”新建工程,点击完成后在此界面的右下角跳出以下信息,如下所示。
图5.1.4 是否使用新窗口打开工程
我们点击“Yes”选项在新的窗口打开工程,此时系统弹出VS Code新窗口,如下图所示。
图5.1.5 打开00_basic工程
注意:在上图5.1.2中创建工程时选择了“ESP32-P4 chip (via built-in USB-JTAG)”作为目标芯片,但在新建工程完成后,VS Code 左下角显示的目标芯片仍然是 ESP32,这可能是由于当前 ESP-IDF 插件存在某些功能上的不完善或更新问题。
在上图中,我们将目标芯片设置为esp32p4,然后点击“ESP32-P4 chip (via built-in USB-JTAG)”下载类型,如下图所示。
图5.1.6 设置Espressif设备目标
00_BASIC工程与乐鑫官方提供的sample_project示例的内容和工程结构完全相同,读者可以通过对比这两个工程来更好地理解项目的基本框架和文件布局。在接下来的小节中,作者将详细讲解00_BASIC工程中每个文件的作用,以帮助读者更深入地了解其功能和在开发过程中的重要性。
注意:正点原子ESP32-P4的所有工程默认会设置自动编码文件格式。如果VSCode的默认文件编码为UTF-8,其他编码格式的文件可能会显示乱码。为避免此问题,正点原子在每个工程的settings.json文件中添加了以下内容。
- "files.autoGuessEncoding": true,
复制代码
5.2 工程文件架构解析
在上小节中,我们已经成功在VS Code上新建了一个ESP-IDF工程。接下来,笔者将重点讲解这个基础工程的文件架构。该基础工程的文件架构(即00_BASIC工程)如下图所示。
图5.2.1 基础工程文件架构
在ESP32工程的基础架构中,每个文件和文件夹都有特定的作用。以下是对每个文件及文件夹的解析:
1,CMakeLists.txt(顶层CMake):
作用:顶层项目的CMakeLists.txt文件是CMake用于构建项目的主要配置文件。在此文件中,可以设置项目的全局CMake变量。该文件会导入位于IDF_PATH/tools/cmake/project.cmake的文件,由后者负责实现构建系统的其余部分。最终,该文件将设置项目名称并定义项目的基本信息。以下是CMakeLists.txt文件的内容。
- # 以下模板代码必须按此顺序出现在项目的CMakeLists.txt文件中,以确保CMake正常工作
- cmake_minimum_required(VERSION 3.16) # 指定所需的最低CMake版本
- include($ENV{IDF_PATH}/tools/cmake/project.cmake) # 包含ESP-IDF供的项目构建文件
- project(00_basic) # 定义项目名称为00_basic
复制代码
2,README.md:
作用:这是一个常见的文档文件,通常用于提供项目的介绍和基本使用说明。开发者可以在此处写明项目的描述、运行步骤、依赖关系等信息,方便他人快速了解该项目。
3,main文件夹:
作用:“main”目录是一个特殊的组件,专门用于包含项目的源代码。它是CMake的默认名称,且 CMake 变量COMPONENT_DIRS默认包含此组件。你可以根据需要修改此变量以适应项目结构。如果项目中源文件较多,建议将源文件组织成多个组件,而不是将所有文件都放在“main”目录中。这种做法有助于提升代码的可维护性和可读性。
注意:“main”目录会自动添加到构建系统中。其他组件也会作为其依赖项一并添加,这样可以免去用户处理依赖关系的麻烦,并提供即时可用的构建功能。简单来说,在“main”文件夹中定义的应用文件可以直接调用其他组件(如PPA、LVGL等API),而无需在main/CMakeLists.txt文件中声明它们的依赖关系。
1)main/CMakeLists.txt:
作用:定义 main 文件夹内代码的构建规则,特别是与主程序相关的文件编译和链接细节。这个文件用于告诉 CMake 如何处理 main.c 等源文件,并将其编译到最终的可执行程序中。以下是main/CMakeLists.txt文件的内容。
- idf_component_register(SRCS "main.c" # 指定组件的源文件列表,当前包含 main.c
- INCLUDE_DIRS ".") # 定义头文件的包含目录,"." 表示当前目录
复制代码 如果我们在main文件夹下新建APP文件夹来保存自己编写的应用程序源文件,那么CMakeLists.txt文件的内容的内容可以这样编写:
- idf_component_register(
- SRC_DIRS # 指定源文件的目录列表
- "." # 当前目录
- "APP" # "APP" 目录,包含其他源文件
- INCLUDE_DIRS # 指定头文件的包含目录列表
- "." # 当前目录
- "APP" # "APP" 目录,包含相关头文件
- )
复制代码 2)main/main.c:
作用:项目的主源文件,包含实际的应用程序代码。在这个文件中,通常会定义程序的入口函数(app_main()),并编写项目的核心逻辑和实现。
4,sdkconfig
作用:“sdkconfig”是项目的配置文件,在执行idf.py menuconfig时创建或更新。该文件保存了项目中所有组件(包括ESP-IDF本身)的配置信息。根据项目需求,sdkconfig文件可以选择是否添加到源码管理系统中。
5.3 工程文件架构整理
在讲解正点原子ESP32工程架构之前,我们先了解一下乐鑫ESP32的工程架构。乐鑫ESP32的工程架构为整个开发流程奠定了基础,是理解如何进行开发和调试的关键。
图5.3.1 乐鑫官方的ESP32项目工程架构
从上图可以清楚地看到,除了components文件夹外,该工程架构与我们在5.2小节中创建的基本架构一致。components文件夹主要用于存放第三方组件,无论是支持ESP Component Registry的组件,还是未支持的组件,或是开发者自定义的驱动库,都可以放在该文件夹中。然而,随着项目规模的扩大,采用标准的乐鑫 ESP32 工程架构可能会导致架构变得复杂,难以维护。为了解决这一问题,正点原子提出了不同的组织方式:开发者编写的驱动文件被整理到components文件夹下的BSP(板级支持包)子文件夹中;而ESP Component Registry支持的组件(如裸机移植)或其他第三方组件则被整理到components文件夹下的Middlewares子文件夹中。这种做法使硬件相关的驱动文件得到更好的管理,增强了工程的模块化和层次结构。
此外,我们简化了CMakeLists.txt文件的管理。通过仅保留一个主CMakeLists.txt文件来加载多个驱动库,减少了繁琐的配置步骤,从而提高了工程的整洁性和可维护性。这种优化方式不仅减轻了开发者的管理负担,还提高了项目的开发效率和扩展性。
下图为正点原子ESP32工程文件架构。
图5.3.2 正点原子ESP32工程结构
从上图可以清楚地看到,正点原子将所有开发者编写的程序驱动(如LED、KEY、LCD 等)统一放置在BSP文件夹下,而Middlewares文件夹则用于存放第三方组件。这些组件包括 ESP Component Registry 支持的组件、自定义的第三方组件,以及其他开发者编写的组件。每个组件都包含一个CMakeLists.txt文件,用于将该组件添加到构建系统中。
为了高效管理BSP文件夹下的程序驱动,我们引入了一个统一的CMakeLists.txt文件。它的优势在于,创建新的驱动文件时,不再需要像乐鑫ESP32工程那样为每个驱动单独创建CMakeLists.txt文件。相反,只需一个CMakeLists.txt文件即可完成所有驱动库的管理,从而简化了开发流程,提升了效率。
接下来,我们将详细介绍 BSP 文件夹下的 CMakeLists.txt 文件的具体实现,代码如下:
- ①源文件路径,指本目录下的所有代码驱动
- set(src_dirs
- KEY
- LCD
- LED
- SDMMC)
- ②头文件路径,指本目录下的所有代码驱动
- set(include_dirs
- KEY
- LCD
- LED
- SDMMC)
- ③设置依赖库
- set(requires
- driver
- esp_lcd
- esp_common
- fatfs)
- ④注册组件到构建系统的函数
- idf_component_register(SRC_DIRS ${src_dirs} INCLUDE_DIRS
- ${include_dirs} REQUIRES ${requires})
- ⑤设置特定组件编译选项的函数
- component_compile_options(-ffast-math -O3 -Wno-error=format=-Wno-format)
- -ffast-math: 允许编译器进行某些可能减少数学运算精度的优化,以提高性能。
- -O3: 这是一个优化级别选项,指示编译器尽可能地进行高级优化以生成更高效的代码。
- -Wno-error=format: 这将编译器关于格式字符串不匹配的警告从错误降级为警告。
- -Wno-format: 这将完全禁用关于格式字符串的警告。
复制代码 在开发过程中,设定项④和⑤是固定不变的。而设定项①和②则根据项目所需的驱动文件数量而变化。如果当前目录下缺少某个特定的驱动文件(例如LED驱动文件),但在CMakeLists.txt文件中仍然指定了该文件需要编译,那么在系统编译时将会遇到如下错误:
图5.3.3 未发现LED驱动文件
此时,需要我们添加LED驱动文件至BSP文件夹下,并且全部清除编译工程文件才能再一次编译工程。
③表示驱动程序需要依赖的库,例如LCD驱动程序,它依赖的是esp_lcd等这些ESP-IDF(SDK)核心组件实现的。下图是CMakeLists.txt未添加依赖库的错误提示。
图5.3.4 未添加依赖库的提示错误(LCD驱动程序未添加依赖库)
在components文件夹下,无论是驱动还是第三方组件的CMakeLists.txt文件,都必须根据实际需求添加所需的依赖库。如果某个驱动或组件未正确添加依赖库,系统在编译时可能会提示未找到某个函数或头文件的错误。
注意:main组件无需添加依赖库,这是我们之前已讲解过的知识点,此处无需重复说明。如果Middlewares文件夹下的某个第三方组件调用了BSP文件夹中的驱动,那么必须在其CMakeLists.txt文件中添加对BSP的依赖。例如,在5.2.2小节中的TEXT汉字显示组件,它调用了ESP-IDF(SDK)核心组件的分区表API、spi_flash 组件API、fatfs 组件API 以及BSP文件夹下的驱动API。因此,CMakeLists.txt文件的编写内容应如下:
- list(APPEND srcs fonts.c
- text.c) #TEXT组件的源文件
- idf_component_register( SRCS "${srcs}" #指向哪些源文件
- INCLUDE_DIRS "." #指向当前组件根目录的.h头文件
- REQUIRES esp_partition #依赖核心组件分区表API
- spi_flash #依赖核心组件SPIFLASH API
- fatfs #依赖核心组件文件系统fatfs API
- BSP) #依赖驱动 API
复制代码 至此,本书籍提供的项目工程文件结构介绍完毕,请读者认真了解该项目工程结构。
5.4 项目工程配置
在第二章中,我们了解到乐鑫ESP32-P4芯片有两个型号:ESP32-P4NRW16和ESP32-P4NRW32,分别内置16M和32M PSRAM。使用这两个型号的芯片设计板子时,必须挂载外部FLASH,因为内部的ROM仅用于存储P4启动固件,是只读且不可编程的,无法存储用户程序。因此,设计板子时必须项目需求挂载外部FLASH容量以存储用户程序,我们正点原子DNESP32P4开发板使用的是16MB的Flash,所以在项目工程中,必须在menuconfig配置为16MB Flash容量等相关配置。
在本章节中,笔者将重点讲解如何让前面创建的工程匹配我们设计的系统资源(如FLASH 大小、主频、OS节拍等)。如果不进行这些参数配置,项目程序将无法充分发挥P4芯片的全部功能。接下来,笔者将通过00_basic项目工程,逐步介绍项目的配置,具体步骤如下。
1,打开00_basic项目工程
在VS Code中,按下“Ctrl + Shift + P”快捷键进入 “显示所有命令” 页面。在此页面的搜索栏中输入“SDK Configuration Editor (Menuconfig)” 并按回车键进入配置界面。如图所示。
图5.4.1 menuconfig菜单(部分截图)
关于menuconfig配置界面的具体内容,作者将在后续的章节中进行详细讲解。目前,我们的主要目标是配置项目工程与DNESP32P4开发板相匹配的资源。
2,在上图“Search parameter”搜索框下输入“Flash”进去flash配置界面,如下所示。
图5.4.2 配置Flash资源
上图中的①“Flash SPI mode”支持四种不同的 SPI flash 访问模式,它们分别为DIO、DOUT、QIO 和 QOUT。下面我们来看一下这几种模式到底有哪些区别,这些模式的对比如下表所示。
表5.4.1 四种SPI模式的对比
从上表可以看出,QIO模式的速率最快,因此我们将基础工程的Flash SPI模式设置为QIO。上图中的②“Flash SPI speed” 提供了80MHz、40MHz和20MHz的配置选项。鉴于PSRAM的 SPI 速率最高可设置为80MHz,为了确保系统的最佳性能,我们同样将Flash的SPI速率设置为80MHz。上图的③是根据模组挂载的flash来确定的,这里笔者选择16MB大小,是毫无争议的。
3,在搜索框中输入“Partition Table”来设置分区表。分区表的主要功能是将flash划分为多个功能各异的区域,包括存储启动文件、代码区域和文件系统区域等子分区,以满足不同的应用需求。后续章节将详细解释分区表的作用和配置方法。下图是基础工程分区表配置参数。
图5.4.3 配置分区表
上图中,笔者选择“Custom partition table CSV”自定义分区表,然后设置分区表的名称为partitions-16MiB.csv。稍后我们会设置分区表各个子分区的管理大小。
4,在搜索框中输入“PSRAM”来设置PSRAM参数,配置参数如下图所示。
图5.4.4 设置PSRAM
在上图中,笔者首先勾选了①“Support for external PSRAM”以表示支持挂载PSRAM。接着,取消了②选项以关闭PSRAM测试。如果不关闭PSRAM测试,系统启动会变得非常缓慢。
如果读者遇到屏幕闪烁或图像漂移的问题,可以开启上图中的“XiP”模式。在此模式下,Flash中的固件(包括指令和数据)将在启动时移动到PSRAM中,固件代码将直接从PSRAM执行。这种配置可以有效解决屏幕闪烁或图像漂移等问题。
注意:在上图中,“PSRAM clock speed”的时钟最高为20MHz。如果读者希望配置到最高时钟,可以启用P4的实验特性。在搜索框中输入 “Make experimental features visible”并启用该选项,这样PSRAM的时钟可设置为20MHz。一般在使用MIPI屏幕时,必须开启此功能。因此,本书籍提供的例程通常都会启用该选项,并同时开启“XiP” 功能。
5,在搜索框中输入“CPU frequency”来设置CPU的时钟频率,如下图所示:
图5.4.5 配置CPU主频
这里,笔者将主频设置为400MHz,也是ESP32-P4芯片最高的主频了。
6,在搜索框中输入“FreeRTOS” 以配置系统节拍时钟(tick clock)的频率。默认情况下configTICK_RATE_HZ的值为100,表示节拍时钟的周期为10ms。因此,调用vTaskDelay(1000) 会导致延迟10秒。为了提高定时精度和方便性,建议将该值设置为1000,这样节拍时钟的周期就变为1ms,从而使vTaskDelay(1000) 代表延迟1秒。具体操作如图所示
5.4.6 配置系统节拍时钟(tick clock)的频率
至此,保存menuconfig配置并退出。
7,配置分区表各个子分区,我们按下“Ctrl+Shift+P”快捷键打开命令面板,并在搜索栏内输入“Open Partition Table Editor UI”,按以下图配置各个分区的管理大小。
图5.4.7 设置分区表
首先,我们按下“Add New Row”选项以添加子分区条目,然后设置条目的类型、偏移和大小,最后点击“Save”选项保存并退出。
至此,我们已完成工程配置,确保其与ESP32-P4NRW32的内部资源相匹配。现在,我们可以利用这个工程在DNESP32P4开发板上进行开发工作。接下来,我们来看一下当前的工程架构,如下图所示。
图5.4.8 配置完的工程架构
上图中的sdkconfig.old是之前基础工程所使用的旧版系统配置文件,用于记录之前的配置信息。而当前的sdkconfig则是系统最新生成的配置文件,包含了最新的设置。此外,partitions-16MiB.csv是系统配置保存后自动生成的分区表文件,供用户查看当前的分区配置情况。这些文件共同构成了ESP32开发环境的配置体系。
接下来,作者在项目工程的app_main函数中编写了代码,以获取ESP32-P4NRW32的内部资源信息。这些信息包括时钟频率、flash大小以及PSRAM大小等。具体的代码实现如下所示:
- void app_main(void)
- {
- esp_err_t ret;
- uint32_t flash_size;
- 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());
- ESP_ERROR_CHECK(nvs_flash_init());
- }
- /* 获取flash大小 */
- ESP_ERROR_CHECK(esp_flash_get_size(NULL, &flash_size));
- /* 芯片信息 */
- esp_chip_info(&chip_info);
- ESP_LOGI(TAG, "| %-12s | %-10s |", "describe", "explain");
- ESP_LOGI(TAG, "|--------------|------------|");
- if (chip_info.model == CHIP_ESP32P4)
- {
- ESP_LOGI(TAG, "| %-12s | %-10s |", "model", "ESP32P4");/* 芯片型号 */
- }
- /* 获取芯片的内核数量 */
- ESP_LOGI(TAG, "| %-12s | %-d |", "cores", chip_info.cores);
- /* 获取芯片的内核数量 */
- ESP_LOGI(TAG, "| %-12s | %-d |", "revision", chip_info.revision);
- /* 获取FLASH大小(MB) */
- ESP_LOGI(TAG, "| %-12s | %-ld |", "FLASH size", \
- flash_size / (1024 * 1024));
- /* 获取PSRAM的大小(MB) */
- ESP_LOGI(TAG, "| %-12s | %-2d |", "PSRAM size", \
- esp_psram_get_size() / (1024 * 1024));
- ESP_LOGI(TAG, "|--------------|------------|");
- while(1)
- {
- ESP_LOGI(TAG, "Hello-ESP32P4");
- vTaskDelay(pdMS_TO_TICKS(1000)); /* 延时1s */
- }
- }
复制代码 上述代码是获取ESP32-P4NRW32的内部资源信息,并打印到监控器上。首先我们编译基础工程,然后下载至开发板中,最后打开监控器查看串口打印内容,如下图所示:
图5.4.9 打印内部资源信息
在以后的例程中,我们是以这个基础工程来延申扩展,所以本章节的内容非常重要,望读者好好理解。
5.5 ESP-IDF插件的下载与调试工具
ESP-IDF提供了集成的调试工具,特别是VS Code中通过插件形式,可以为开发者提供方便的调试环境。以下图是ESP-IDF插件调试工具的一些关键功能和使用。
图5.5.1 ESP-IDF插件的下载与调试工具
(1)选择SDK模板(猪头图标):通过该图标选择不同的SDK版本编译工程。
(2)选择串口号(插头图标):选择连接开发板的下载串口号,VS Code会列出当前电脑连接的所有串口供选择。串口选择会被记录,下次打开VS Code无需重新选择。在开发过程中,尽量不要更换USB线或更换电脑的插口,否则串口号会发生变化。
(3)设置Espressif设备目标(芯片图标):对应IDF命令idf.py set-target xxxx。此选项用于设置当前工程要下载到的目标芯片型号(如ESP32 S2、S3、C2、C3和P4 等)。该设置会写入当前工程配置文件,默认情况下工程配置目标芯片为ESP32。
(4)查看当前工程位置(文件夹图标):查看当前项目工程路径。
(5)SDK配置编辑器(齿轮图标):对应IDF命令 idf.py menuconfig,用于配置当前工程的系统设置。配置项非常多,建议在需要时再修改。
(6)清除全部构建文件(垃圾桶图标):用于清除编译生成的文件,常用于在压缩或拷贝工程文件时减少占用空间。如果编译过程中出现问题,也可以尝试清除后再重新编译。
(7)构建项目(扳手图标):编译当前项目工程。此操作仅编译功能,不包含下载固件。
(8)选择烧录方式(五角星图标):可选择UART、JTAG和DFU下载,通常选择串口 UART 方式下载。
(9)烧录设备(闪电图标):将编译好的固件下载到设备芯片中。此操作仅下载固件,不包含编译功能。如果修改了代码,需要先编译再点击下载,所做的修改才会生效。
(10)监控设备(电视机图标):用于查看设备的串口信息输出(UART和JTAG均可打开)。
(11)调试(小爬虫图标):此操作仅用于JTAG接口进行调试。
(12)构建、下载与监控(一团火图标):最常用的功能之一,一次性完成编译、下载和打开串口监控的所有操作。
(13)打开ESP-IDF终端(命令图标):打开命令行窗口,定位到当前项目路径下,可以执行ESP-IDF相关命令。
(14)工程的错误与警告提示(错误和警告图标):显示当前工程中出现的错误和警告,便于快速定位和解决问题。
从上述可以看到,ESP-IDF插件工具栏提供了集成的功能,简化了开发、调试和下载固件的流程,使开发者可以专注于代码逻辑的实现。通过这些功能,工程管理更加高效便捷。
下面笔者将简单介绍ESP32-P4的两种下载方式:UART下载 和JTAG下载。其中,UART下载仅支持固件下载,适用于基础开发和固件更新。而JTAG下载不仅支持固件下载,还具备强大的调试功能,可以进行代码级调试,如设置断点、查看寄存器等,适合更复杂的开发场景。
5.5.1 串口下载方式
下面,笔者以5.1小节新建工程(00_BASIC)为例,简单讲解一下工程的下载流程,如下流程所示。
(1)使用USB线的Type-C接口连接DNESP32P4开发板的USB串口,并USB A口连接到电脑,使得电脑与开发板建立连接。
(2)在设备管理器中,查看USB串口的端口号,并在VS Code软件左下角调试区域设置端口号(插头图标)。
(3)点击“设置Espressif设备目标”(芯片图标)选择目标芯片,这里笔者选择ESP32-P4.
(4)选择“烧录方式”(五角星图标),如UART或者JTAG
(5)点击“清除构建”(垃圾桶图标)清除工程。
(6)点击“构建项目”(扳手图标)编译工程。
(7)编译完成后,点击“烧录设备”(闪电图标)下载代码。
编译工程成功后,工程目录下出现build文件夹,这个文件夹是由ESP-IDF Tools生产的文件,如log、固件、map等下载和调试文件。如下图所示:
图5.5.1.1 编译输出文件(部分截图)
编译完成后,VSCode软件底部的“终端”窗口会输出编译信息,如下图所示:
图5.5.1.2 编译00_BASIC工程
上图显示了一个 内存类型使用总结 的输出结果,详细列出了微控制器不同内存区域的使用情况。以下是各部分的描述:
1,Flash 存储:
1)已使用:152832字节,占用总Flash内存的0.23%。
2)详细分配:
①:.text:109424字节。用来存储用户程序,运行时,加载至RAM中执行。
②:.rodata:42904字节。存储只读数据,例如常量和不可修改的字符串。
③:.appdesc:256字节。存储应用描述符信息,如程序的版本信息、编译时间等元数据。
④:.init_array:248字节。存储全局和静态对象的构造函数指针。
2,DIRAM(数据指令 RAM):
1)已使用:80864字节,占用总DIRAM的14.03%。
2)详细分配:
①:.text:65482字节。关键代码存储在DIRAM,用于加快执行速度。
②:.data:9229字节。初始化的全局或静态变量存储在DIRAM中。
③:.bss:6092字节。在程序中声明但未初始化的全局或静态变量,运行时被初始化为0并存储在DIRAM中,可在程序运行过程中动态更新。
3,LP RAM(低功耗 RAM):
1)已使用:128字节,占用总LP RAM的0.39%。
2)详细分配:
.rtc_reserved:24字节。
4,HP 核心 RAM (高性能 RAM):
1)已使用:90字节,占用总HP核心RAM的1.1%。
2)详细分配:
①:.data:60字节。一些高频访问的初始化数据变量存储在高性能 RAM 中。
②:.text:30字节。存储快速执行的极少量核心代码。
总镜像大小:227385字节(可能会在 .bin 文件中填充更多)。
编译成功后,点击图5.6.1中的“设备烧录”(闪电图标)就可以把编译出来的可执行文件烧录至DNESP32P4开发板上。
5.5.2 JTAG下载与调试
本小节参考乐鑫ESP-IDF编程指南的JTAG调试章节,介绍了ESP32-P4的调试功能。
ESP32-P4内置JTAG电路,因此无需额外的芯片即可实现调试。通过将USB线连接到D+/D-引脚,开发人员可以方便地进行下载和调试。利用JTAG接口,开发者可以通过开源工具OpenOCD对ESP32-P4进行调试。OpenOCD是一款专为嵌入式系统设计的工具,支持通过JTAG或SWD接口执行调试、固件烧写等任务。
根据乐鑫官方资料,ESP32-P4支持两种JTAG调试方式:
1)内置JTAG调试:直接利用ESP32-P4内置的JTAG电路进行调试,无需额外硬件。
2)使用ESP-PROG调试器:ESP-PROG是一款官方调试器,集成了自动下载固件、串口通信和JTAG在线调试等功能,进一步提升了开发效率。
在VS Code中安装OpenOCD时,环境会自动配置,开发者可以直接使用内置JTAG电路与VS Code中的OpenOCD进行调试和下载操作,从而简化了开发流程。下面笔者带读者了解一下JTAG下载与调试流程,如下所示。
1,新建launch.json文件
在VS Code中,点击“运行与调试”或使用快捷键“Ctrl + Shift + D”进入调试界面,选择“创建launch.json”文件,然后选择“ESP-IDF”调试器进行配置,如下图所示。
图5.5.2.1 新建ESP-IDF调试文件
在上图中,我们按照图示的①②③顺序操作,即可完成调试器的配置。完成这些步骤后,在生成的launch.json文件中添加所需的调试信息。具体的调试信息及配置内容,笔者将在后续章节中详细讲解。
2,添加launch.json文件调试信息
关于launch.json文件的调试信息,乐鑫官方提供了详细的VS Code调试配置文件launch.json的指导说明,您可以参考乐鑫官网提供的调试配置页面。在该页面中,会详细介绍如何根据您使用的调试器(如JTAG调试器或VS Code内置调试工具)来修改launch.json的内容。由于我们选择使用VS Code进行调试,则选择“Use Microsoft C/C++ Extension to Debug”的launch.json文件内容,如下代码所示:
- {
- "configurations": [
- {
- "name": "GDB",
- "type": "cppdbg",
- "request": "launch",
- "MIMode": "gdb",
- "miDebuggerPath": "${command:espIdf.getToolchainGdb}",
- "program": "${workspaceFolder}/build/${command:espIdf.getProjectName}.elf",
- "windows": {
- "program": "${workspaceFolder}\\build\\${command:espIdf.getProjectName}.elf"
- },
- "cwd": "${workspaceFolder}",
- "setupCommands": [
- { "text": "target remote :3333" }, # 必须添加这一段
- { "text": "set remotetimeout 20" },
- ],
- "postRemoteConnectCommands": [
- { "text": "mon reset halt" },
- { "text": "maintenance flush register-cache"},
- ],
- "externalConsole": false,
- "logging": {
- "engineLogging": true
- }
- }
- ]
- }
复制代码 从上述代码可以看到,我们必须在launch.json文件中添加 { "text": "target remote :3333" } 这一行,否则可能会导致调试错误。完成这一步后,将配置内容完整拷贝到刚刚创建的launch.json文件中,这样就完成了launch.json文件的全部配置。
3,JTAG下载程序流程
使用USB线的Type-C接口连接DNESP32P4开发板的USB 串口/ JTAG,并USB A口连接到电脑,使得电脑与开发板建立连接。
1)点击“选择烧录方法”(五角星图标),这里我们选择JTAG下载。
2)点击“选择要使用的端口”(插头图标),根据电脑识别选择端口号。
3)点击“清除构建”(垃圾桶图标)擦除工程。
4)点击“构建项目”(扳手图标)编译工程。
编译成功后,点击“烧录设备”下载程序至开发板中,此时,VS Code提示是否运行OpenOCD,如下图所示。
图5.5.2.2 运行OpenOCD
下载成功后,VS Code右下角提示如下信息。
图5.5.2.3 提示下载成功
4,JTAG调试流程
JTAG调试过程非常简单。首先,将代码下载至开发板。然后,在VS Code中点击“运行与调试,或者使用快捷键“F5”启动调试。如下图所示,操作十分直观,开发人员可以轻松进行调试。此时,系统执行到app_main函数中的第一行代码,如下图所示。
图5.5.2.4 调试效果
在上图中,右上角提供了一系列用于调试代码的选项。由于这些功能在学习MDK开发环境时已有详细介绍,并且是开发中经常使用的工具,因此作者在此不再对这些调试选项进行过多讲解。开发者可以直接使用这些熟悉的功能,进行代码调试和问题排查。
5,JTAG调试方法
接下来,作者将简要介绍一些在VS Code中使用JTAG调试的操作,包括如何加载变量到监视窗口,以及如何打开反汇编视图等实用功能。
1)变量监控: 在调试时,选择一个变量,右键点击并选择“添加到监视”。这样,该变量就会出现在监视窗口中,方便实时查看其值的变化,如下图所示。
图5.5.2.5 变量添加到监视器中
此时,在运行与调试界面中,监视窗口将实时显示该变量的当前值,如下图所示。
图5.5.2.6 监视变量和监视CPU寄存器
除了简单的变量,您还可以监控 函数、结构体 等复合类型。只需在代码中选择对应的对象并添加到监视窗口中,您可以实时监控这些元素的变化。
2)调用堆栈:调用堆栈用于显示当前程序的执行路径,帮助开发者追踪函数调用顺序,尤其在发生异常时可以快速定位问题,如下图所示。
图5.5.2.7 显示当前程序的执行路径
上图右侧“已暂停”提示表示程序暂停,下一次运行时将不会继续执行该位置的代码。如果显示文件名和行号,则表明程序当前运行到该文件的指定行。
3)断点监控:允许开发者在程序执行到特定位置时暂停程序并检查系统状态。断点监控不仅可以帮助开发者定位代码错误,还可以用来监控特定的变量、寄存器或硬件状态。在 VS Code 中,设置断点非常简单。您只需在代码的某一行上点击左侧的行号即可设置断点。执行到该行时,程序会暂停。如下图所示。
图5.5.2.8 设置断点
在断点监控区域可看到我们设置的当前位置和删除断点,如下图所示。
图5.5.2.9 断点监控
4)反汇编视图:反汇编视图显示程序的机器码指令,并将其转换为汇编语言,便于开发者分析底层代码的执行过程。通过此视图,开发者可以查看程序的控制流、数据处理以及硬件资源的使用情况。通过下图操作就可以打开ESP32-P4项目工程的反汇编视图了。
图5.5.2.10 打开反汇编视图
至此,JTAG调试方法的讲解到此结束。如需了解更多JTAG调试的使用方法,建议查阅乐鑫官方提供的《ESP-IDF Extension for VSCode》在线文档(https://docs.espressif.com/projects/vscode-esp-idf-extension/zh_CN/latest/index.html),获取更详尽的指导。 |
|