OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 613|回复: 0

《ESP32-P4开发指南— V1.0》第二章 初识ESP32-P4

[复制链接]

1207

主题

1221

帖子

2

精华

超级版主

Rank: 8Rank: 8

积分
5201
金钱
5201
注册时间
2019-5-8
在线时间
1307 小时
发表于 5 天前 | 显示全部楼层 |阅读模式
本帖最后由 正点原子运营 于 2025-12-1 10:58 编辑

第二章 初识ESP32-P4

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


2.jpg

3.png

在本章中,我们将深入探索ESP32-P4这款备受瞩目的微控制器。我们将详细阐述其定义、核心资源、功能应用,以及如何选择适合您项目的ESP32-P4型号。通过本章的学习,您将全面了解ESP32-P4,为您的物联网项目选择合适的硬件平台奠定坚实基础。
本章分为如下几个小节:
2.1 ESP32-P4概述
2.2 ESP32-P4资源概述
2.3 ESP32-P4 命名规则
2.4 ESP32-P4 功能概述
2.5 ESP32-P4 启动流程

2.1 ESP32-P4概述
ESP32-P4是一款高性能MCU,支持超大片上内存,具有强大的图像和语音处理能力。该款MCU包含一个高性能(HP)系统和一个低功耗(LP)系统。其中HP系统由RISC-V双核处理器驱动,包含丰富的外设;LP系统由RISC-V单核处理器驱动,其外设针对低功耗应用进行了优化。下图为ESP32-P4芯片的功能框图。

第二章 初识ESP32412.png
图2.1.1 ESP32-P4功能框图

这里,笔者结合《ESP32-P4数据手册》中的“Product Overview”章节和上图的内容,简单归纳为5个部分。
1,架构和性能:ESP32-P4采用RISC-V 32位双核处理器(HP系统,400 MHz)和单核处理器(LP系统,40 MHz),具有高效的处理能力和性能。
2,存储:HP系统配备128 KB ROM和768 KB L2MEM,LP系统配备16 KB ROM和32 KB SRAM,支持8 KB的系统紧密耦合内存(TCM)和多个外部存储器接口。
3,外设:提供55个可编程GPIO和多个高级外设接口,包括JPEG解码器、视频编码器和多种数字接口与模拟接口,增强系统的灵活性和扩展性。
4,通信:同时支持多种通信协议,如USB、以太网、SPI、UART等,适用于物联网设备在智能家居和工业自动化等领域的广泛应用。
5,安全机制:具备安全启动、一次性写入安全性(eFuse OTP)和加密硬件加速器,确保数据和系统的安全性。
ESP32-P4是一款功能强大、性能丰富的物联网芯片,适用于各种物联网和音视频等应用场景。以上信息仅供参考,如需了解更多信息,请访问乐鑫公司官网查询相关资料。

2.2 ESP32-P4资源概述
ESP32-P4芯片为开发者提供了丰富的硬件资源和高灵活度的管脚功能,以适应多种物联网应用需求。本章节将介绍芯片的管脚布局以及各个IO管脚的功能,帮助开发者更好地理解如何高效利用这些资源。

2.2.1 管脚布局概览
下图为ESP32-P4管脚分布图。

第二章 初识ESP321081.png
图2.2.1.1 ESP32-P4管脚布局(俯视图)

上图中,ESP32-P4芯片总共有104个管脚,这些管脚可分为以下几类:
1,IO管脚:上图中的GPIO0~GPIO54,这些IO具有以下预设功能:
1)所有IO管脚均预设了HP IO MUX功能。
2)部分IO管脚预设了LP IO MUX功能。
3)部分IO管脚预设了模拟功能。
关于HP IO MUX、LP IO MUX和模拟功能的详细信息,将在后面的2.4.3小节中进行讲解。
2,专用数字管脚:仅可用于特定外设,如Flash、MIPI DSI、MIPI CSI等。这些管脚在上图中用橙色、红色、黄色和绿色框框标识。
3,特殊模拟管脚:专用于特殊模拟功能。上图78、79、99、100、103号管脚为特殊模拟管脚,这些特殊模拟管脚描述如下表所示。

1.png
图2.2.1.1 模拟管脚

上表展示了ESP32-P4芯片提供的一些特殊模拟管脚,用于特定的电源管理和时钟功能。其中,XTAL_N和XTAL_P需要连接一个40MHz晶振,以启动ESP32-P4芯片。CHIP_PU管脚用于芯片的使能控制,必须进行上拉才能启动芯片。EN_DCDC管脚用于控制同步降压DC-DC转换器。FB_DCDC管脚与内部参考电压进行比较,使控制器能够调整EN_DCDC管脚的占空比,以稳定输出电压。下图为DNESP32P4开发板中的同步降压DC-DC转换原理图。

第二章 初识ESP321946.png
图2.2.1.2 同步降压DC-DC转换

用户可以在其他平台上找到TLV62569 DC-DC电源芯片的数据手册。在手册的第9页中,有一个相关的转换公式,如下图所示。

第二章 初识ESP322032.png
图2.2.1.3 TLV62569 DC-DC电源芯片转换公式

在上图中,R1和R2分别对应原理图中的R9和R12。根据该公式计算,得出Vout为1.2V,从而为HP系统的内核提供所需电压。
4,电源管脚:为芯片和非电源管脚提供供电,如下表所示。

2.png
表2.2.1.2 电源管脚

通过控制VDDPST_1至VDDPST_6管脚,用户可以灵活调整各IO管脚的输出电压,以满足不同外设的电压需求。此外,VFB/VO1至VFB/VO4(图2.2.1.1中用黑色框框标识)管脚可以通过程序调节内部LDO的输出电压。通常情况下,我们将VFB/VO1至VFB/VO4连接到VDDPST_1至VDDPST_6的IO管理电源域,这样可以通过程序控制特定IO管脚的输出电压。为了让读者更好地理解这一功能,我们在DNESP32P4开发板上将VFB/VO3和连接至VDD_MIPI_DPHY以及将VFB/VO4和连接至VDDPST_1,这样便可以通过程序灵活控制MIPI和VDDPST_1电源域中IO的电压了。下图为可调LDO控制电源域原理图。

第二章 初识ESP323268.png
图2.2.1.4 通过VO3来控制MIPI电源域的IO

有些读者可能会有疑问?为什么需要这个功能呢?。其实很多器件不一定用到3.3V电压启动的,就比如我们正点原子的MIPI显示屏,驱动的IO电平必须是1.8V,所以我们可以通过可调LDO来控制这些不同电压驱动IO器件。

2.2.2 IO管脚功能说明
在上小节中,我们了解到ESP32-P4具有55个可编程IO管脚(GPIO0~GPIO54)。这些IO管脚具有三种预设功能,分别为全部IO管脚的IO MUX功能、部分IO管脚的LP IO MUX功能和部分IO管脚的模拟功能。如下表所示。

3.png
表2.2.2.1 部分外设管脚分配

从上表可知,ESP32-P4的IO MUX功能使得所有GPIO管脚能够灵活配置为多种数字信号接口,例如UART、I2S、I2C等,利用ESP32-P4的55个任意IO实现相关通信信号;与此同时,部分IO管脚的LP IO MUX功能专为低功耗应用设计,允许某些管脚在待机状态下保持活跃,以支持LP I2C和LP I2S等通信方式,从而有效节省能耗(如下图为LP系统管理的IO);此外,部分GPIO管脚具备模拟功能(如表中的ADC和TOUCH管脚,其他IO则不具备此功能),能够处理连续信号,直接与传感器和音频设备交互,拓展了ESP32-P4在多样化应用场景中的适用性。

第二章 初识ESP324490.png
图2.2.2.1 LP系统管理的IO

如果LP系统启动时,我们可以利用上图的IO管脚实现I2C、I2S等多种通信,因为这些信号可以灵活地映射到任意的IO管脚上。这种灵活性使得我们能够根据具体需求驱动相应的器件,从而更好地适应不同的应用场景和设计要求。
值得注意的是,某些外设必须使用特定的管脚实现,例如具有调试功能的JTAG、USB串口/JTAG、全速USB 2.0和EMAC等。如果在开发时未使用这些外设,我们可以利用IO MUX功能对特定通信接口进行映射。然而,这些映射可能会影响传输速率,因此笔者建议开发者首先采用ESP32-P4默认的复用功能IO设计原理图,然后再考虑其他IO映射功能,以确保系统性能的稳定性和可靠性。

2.3 ESP32-P4 命名规则
乐鑫P4系列包含两款芯片:ESP32-P4NRW16和ESP32-P4NRW32,它们之间的唯一差异在于PSRAM容量。以下是这两款芯片的命名规则图示。

第二章 初识ESP324901.png
图2.3.1 ESP32-P4 系列芯片命名规则

从上图可以看到, H/N表示FLASH温度(H:高温,N:常温);R表示内置PSRAM;W表示仅持1.8v 16-line PSRAM;x表示内置PSRAM大小(MB);。

2.4 ESP32-P4 功能概述

2.4.1 时钟树
ESP32-P4的时钟主要来源于振荡器(oscillator,OSC)、 RC振荡电路和PLL时钟生成电路。上述时钟源产生的时钟经时钟分频器或时钟选择器等时钟模块的处理,使得大部分功能模块可以根据不同功耗和性能需求来获取及选择对应频率的工作时钟。下图为ESP32-P4系统时钟结构。

7.png
图2.4.1.1 HP和LP系统时钟树

在上图中,十多路时钟源通过分频器或直接连接的方式供给各个外设。这样,各模块可根据功耗和性能需求,选择和获取相应的工作时钟频率。
接下来,笔者根据HP系统和LP系统的应用不同,划分为两个类型的时钟。

1,高速时钟
1)CPLL_CLK:内部400MHz时钟,CPU主频可由该时钟提供。
2)MPPL_CLK:内部500MHz时钟,PSRAM_CLK可由该时钟提供。
3)SPLL_CLK:内部480MHz时钟,FLASH_CLK/PSRAM_CLK可由该时钟提供。

2,慢速时钟
1)XTAL32K_CLK:外部32KHz石英晶振时钟。
2)RC_SLOW_CLK:内部慢速RC振荡器,频率可调,默认150KHz。
3)RC32K_CLK:内部32KHz RC振荡器。
4)XTAL_CLK:40MHz外部石英晶振时钟。
5)RC_FAST_CLK:内部快速RC振荡器,频率可调,默认20MHz。
6)PLL_LP_CLK:内部PLL时钟,默认为8MHz。
其中,高速时钟用于HP系统及其数字/模拟外设,而慢速时钟则用于LP系统以及某些低功耗模式下的外设。由此可见,我们可以将上图2.4.1.1划分为两个部分:上部分(红色区域)为HP系统所需的时钟,下部分(绿色区域)为LP系统所需的时钟。
前面我们已经了解到,ESP32-P4芯片集成了高性能(HP)系统和低功耗(LP)系统。其中,HP系统的主频最高可达400MHz,而LP系统的主频最高则为40MHz。那么,如何配置这两个系统以达到其最高主频呢?接下来,笔者将结合《ESP32-P4技术参考手册》,详细讲解这两个系统的主频配置方法。

1,HP系统时钟配置
由上图红色区域可知,CPU_CLK是HP系统的主频时钟,由XTAL_CLK、CPLL_CLK和RC_FAST_CLK这三个时钟源提供(LP_CLKRST_HP_CLK_CTRL_REG寄存器中的第0~1位(即LP_CLKRST_LP_CLK_SEL字段)来选择时钟源)。若要将HP系统的主频配置为400MHz,则必须选择CPLL_CLK作为时钟源,并将其频率设置为400MHz。此时,分频器(DIV)不进行分频(即1分频,意味着直接传递原频率),从而确保CPU_CLK的频率为400MHz。
MEM_CLK、SYS_CLK和APB_CLK时钟则是由CPU_CLK时钟经过分频得到的。另外,MPLL_CLK和SPLL_CLK也会经过分频器(DIV)进行分频,以产生不同频率的时钟信号。这些时钟信号被提供给HP系统的各个模块,各模块根据自身的功耗和性能需求来选择相应的时钟频率。下图是派生的HP时钟源。

第二章 初识ESP326311.png
图2.4.1.2 派生的HP时钟源

上图中,左边“Source Clock”为原始时钟源,右边“Derived Clock”为派生时钟源(由原始时钟源经过分频得到)。下图为HP系统外设时钟源选择。

第二章 初识ESP326412.png
图2.4.1.2 HP系统外设时钟源选择(部分截图)

关于ESP32-P4的HP系统外设时钟源选择,可以参考《ESP32-P4技术参考手册》中的453页8.2-4和8.2-5表格。

2,LP系统时钟配置
由上图绿色区域可知,在“active”模式下,LP_FAST_CLK是LP系统(低功耗系统)的主频时钟,它由XTAL_CLK、RC_FAST_CLK和PLL_LP_CLK这三个时钟源提供。我们可以通过操作LP_CLKRST_LP_CLK_CONF_REG寄存器中的第0~1位(即LP_CLKRST_LP_CLK_SEL字段)来选择时钟源。若要将LP系统的主频配置为40MHz,则必须选择XTAL_CLK作为时钟源,并将其频率设置为40MHz。
在‘Light-sleep’或‘Deep-sleep’模式下,一般选择LP_SLOW_CLK作为时钟源,该时钟由RC_SLOW_CLK、XTAL32K_CLK、RC32K_CLK和OSC_SLOW_CLK这四个低频时钟源提供。我们可操作LP_CLKRST_LP_CLK_CONF_REG寄存器中的第0~1位(即LP_CLKRST_SLOW_CLK_SEL字段)来选择时钟源。下图是派生的LP时钟源。

第二章 初识ESP326938.png
图2.4.1.3 派生的LP时钟源

上图中,左边“Source Clock”为原始时钟源,右边“Derived Clock”为派生时钟源(由原始时钟源经过分频得到)。下图为LP系统外设时钟源选择。

第二章 初识ESP327039.png
图2.4.1.4 LP系统外设时钟源选择

关于ESP32-P4的LP系统外设时钟源选择,可以参考《eESP32-P4技术参考手册》中的455页8.2-7表格。

2.4.2 系统与内存
在ESP32-P4芯片中,系统架构设计和内存布局为高效处理和多任务并发提供了基础。前面讲解过,该芯片集成了高性能(HP)和低功耗(LP)两种RISC-V处理器,配合多级内存结构与丰富的外设支持,适用于各种物联网和嵌入式应用场景。
下图展示了ESP32-P4的系统结构和地址映射。ESP32-P4的指令总线和数据总线共享同一地址空间,这意味着所有非保留的地址都可以通过这两条总线进行访问。这种设计提高了系统在执行指令和访问数据时的灵活性。在分析下图之前,我们需要先了解两个关键概念:总线结构与端序,以及数据访问对齐。

1,总线结构与端序
在ESP32-P4中,HP CPU和LP CPU的指令总线和数据总线均采用小端序(little-endian)。其中,HP CPU的数据总线(DBUS)具有128位的数据宽度,而其他总线的数据宽度为32位。

2,数据访问对齐
1)HP CPU:通过数据总线访问数据时,支持单字节(1字节)、双字节(2字节)和4字节对齐。此外,在执行AI指令时,HP CPU的数据对齐需求最高可达16字节,这为高效的AI计算提供了支持。
2)LP CPU:支持单字节、双字节和4字节对齐的数据访问。
这种对齐方式的设计,尤其是HP CPU的多字节对齐支持,使得ESP32-P4在高性能计算和数据处理任务中能够更有效地利用内存带宽和系统资源。

第二章 初识ESP327713.png
图2.4.2.1 ESP32-P4 系统结构与地址映射

上图展示了ESP32-P4的系统结构和地址映射。以下是对该图所示系统结构和地址映射的逐步解剖。

1,处理器结构
ESP32-P4芯片包含以下两种处理器:
1)高性能(HP)CPU:32位RISC-V双核处理器,主频高达400 MHz,采用五级流水线结构。HP CPU适用于计算密集型任务,支持对高速缓存和大容量外部存储的快速访问。
2)低功耗(LP)CPU:32位RISC-V单核处理器,主频40 MHz,采用两级流水线结构。LP CPU功耗较低,适合执行低速率、低功耗任务,通常用于待机或低频应用。
这种双处理器架构允许系统在功耗和性能之间灵活切换,为任务分配和资源管理提供了更高的灵活性。

2,内存结构
ESP32-P4的内存结构由多层次的内部存储器和可外扩的存储器组成,允许高效的数据处理和存储访问。
1)HP CPU内存访问:
HP TCM(紧耦合内存):8 KB,地址范围为0x30100000~0x30101FFF,供HP CPU快速访问,适合存储时间敏感的数据或指令。
①:HP ROM(只读存储器):128 KB,分为两种访问方式,一种是缓存访问地址,通过Cache进行缓存访问(0x4FC00000~0x4FC1FFFF),另一种是直接访问地址(0x8FC00000~0x8FC1FFFF)。HP ROM存储区是用于系统启动代码和初始化程序。
②:HP L2MEM(二级缓存内存):768 KB,分为两种访问方式,一种是缓存访问地址(0x4FF00000~0x4FFBFFFF),另一种是直接访问地址(0x8FF00000~0x8FFBFFFF)。
③:外部存储器:
外部Flash(External flash):最大64 MB,供程序代码和非易失性数据存储,地址范围为:
缓存访问地址:0x40000000~0x43FFFFFF。
直接访问地址:0x80000000~0x83FFFFFF。
外部RAM(External RAM):最大64 MB,适合存储大量数据或临时缓存,地址范围为:
缓存访问地址:0x48000000~0x4BFFFFFF。
直接访问地址:0x88000000~0x8BFFFFFF。
2)LP CPU内存访问:
①:LP ROM:16 KB,地址范围为0x50100000~0x50103FFF,存储启动代码和初始化程序。
②:LP SRAM:32 KB,地址范围为0x50108000~0x5010FFFF,为LP CPU提供的低功耗快速访问存储。
③:共享访问:LP CPU还可以访问HP ROM、HP L2MEM和外部存储器(地址与HP CPU相同),从而增强数据共享和协同处理能力。

3,外设地址映射
ESP32-P4芯片的外设模块具有独立的地址空间,为处理器和外设间的通信提供了便利。
1)HP CPU外设:地址范围为0x3FF00000~0x3FF1FFFF。
2)HP外设:地址范围为0x50000000~0x500FFFFF。
3)LP外设:地址范围为0x50110000~0x5012FFFF。
通过这种独立的地址划分,ESP32-P4的处理器能够高效管理多个外设,减少总线冲突,并优化访问延迟。关于外设地址映射的详细信息,请参考《ESP32-P4技术参考手册》第5章《System and Memory》中的5.3.5小节《Modules/Peripherals Address Mapping》,该小节已详细讲解了各个外设的映射地址。

4,地址配置
ESP32-P4内存的地址空间可以通过不同方式进行访问,其中缓存访问和直接访问的分布设计可以满足不同任务的需求:
1)缓存访问:地址以0x4xxx_xxxx开头的区域可以配置为缓存访问,通过处理器的PMU(性能监控单元)进行管理,以提高访问速度。
2)直接访问:地址以0x8xxx_xxxx开头的区域提供直接访问,通常用于调试或需要低延迟访问的场景。
通过这种灵活的访问配置,ESP32-P4芯片支持在不同存储设备和数据类型之间快速切换,提升了数据的读取和写入效率。
至此,ESP32-P4的系统与内存相关知识讲解完毕。如需深入了解更多系统与内存的细节,请参考《ESP32-P4技术参考手册》中的第5章《System and Memory》。

2.4.3 IO MUX和GPIO交换矩阵
GPIO(通用输入输出)引脚作为芯片与外部设备交互的关键接口,为了支持多种外设和应用需求,GPIO引脚需要灵活地连接到不同的外设信号上。ESP32-P4芯片通过高功率(HP)和低功率(LP)两种GPIO矩阵和IO MUX(输入输出复用器)系统,实现了对GPIO引脚的灵活配置,使其可以与多达数百个外设信号相互连接,并且可以支持信号同步、滤波、直连等多种功能。了解IO MUX和GPIO矩阵的架构和功能,有助于开发者灵活配置ESP32-P4的引脚资源,满足不同应用场景的需求。
本章节将详细介绍ESP32-P4中的HP和LP GPIO矩阵以及对应的IO MUX的工作原理、架构以及信号的路由方式,并对其主要特性进行分析。下图为ESP32-P4的IO MUX和GPIO交换矩阵整体框架。

第二章 初识ESP329889.png
图2.4.3.1 IO MUX和GPIO交换矩阵整体框架

上图是ESP32-P4的HP GPIO矩阵、HP IO MUX、LP GPIO矩阵和LP IO MUX的结构,详细描述了信号从引脚到外设以及从外设到引脚的路由方式。下面我们先了解比较重要的模块相关特性,然后再去了解信号从引脚到外设和外设到引脚的路由方式。

1,HP GPIO Matrix特性
图2.4.3.1中的HP GPIO矩阵是用于将HP外设信号与GPIO引脚连接,它具有以下特点:
1)全交换矩阵:支持HP外设信号与GPIO引脚之间的全交换配置,灵活处理输入输出。
2)HP外设输入:可支持222个HP外设输入信号,灵活路由到任意GPIO引脚。这222个HP外设输入信号可查看《ESP32-P4技术参考手册》中的7.12 HP Peripheral Signal List小节内容,如下图所示。

第二章 初识ESP3210272.png
图2.4.3.2 HP外设信号列表

上图中,左侧为HP系统的外设输入信号,而右侧为HP系统的输出信号,这些外设输入输出可使用任意IO来实现。
3)HP外设输出:支持232个HP外设输出信号,能够路由到任意GPIO引脚(请看上图右侧信号)。
4)信号同步:通过同步处理确保输入信号与HP IO MUX的工作时钟一致,稳定性高。
5)输入信号滤波:配有GPIO滤波器进行二次过滤,有效提升信号抗干扰能力。
6)简单输入输出:提供基础的GPIO输入输出功能,支持常规数字输入输出。

2,HP IO MUX特性
图2.4.3.1中的HP IO MUX是负责HP GPIO引脚的配置与管理,主要功能包括:
1)引脚控制:管理55个GPIO引脚(GPIO0 ~ GPIO54),用于HP外设的连接和控制。
2)配置寄存器:每个GPIO引脚配有配置寄存器(IO_MUX_GPIOn_REG),可控制引脚的输入输出模式、上拉/下拉、电流驱动强度及功能选择。
3)高频信号直连:对于高频信号(如SPI、EMAC),可直接通过HP IO MUX连接外设,优化高频性能。
这两部分功能紧密配合,为ESP32-P4提供了灵活的外设信号处理和GPIO管理能力。

3,LP GPIO Matrix特性
图2.4.3.1中的LP GPIO矩阵是用于LP外设信号提供了灵活的信号路由,适用于低功耗场景,具有以下功能:
1)全交换矩阵:支持LP外设输入输出信号与LP GPIO引脚之间的全交换矩阵配置。
2)LP外设输入:支持14个LP外设输入信号,可以通过LP GPIO矩阵路由到任意LP GPIO引脚,这些外设输入信号请看《ESP32-P4技术参考手册》中的7.13 LP Peripheral Signal List小节内容,如下图所示。

第二章 初识ESP3211030.png
图2.4.3.3 LP系统的外设信号列表

上图中,左侧为LP系统的外设输入信号,而右侧为LP系统的输出信号,这些外设输入输出可使用任意IO来实现。
3)LP外设输出:支持14个LP外设输出信号,可以路由至任意LP GPIO引脚输出(请看上图右侧信号)。
4)输入信号滤波:配备GPIO滤波器,用于对输入信号进行简单的滤波处理,提高信号的稳定性。
5)简单输入输出:支持基本的GPIO输入输出功能,满足低功耗设备的输入输出需求。

4,LP IO MUX特性
图2.4.3.1中的LP IO MUX是负责LP GPIO引脚的配置与管理,它的功能包括:
1)引脚控制:管理16个LP GPIO引脚(GPIO0 ~ GPIO15),用于LP外设的连接和控制。
2)配置寄存器:每个LP GPIO引脚配有配置寄存器(LP_IOMUX_PADn_REG),可用于控制引脚的输入输出模式、上拉/下拉、电流驱动强度、功能选择和IO MUX选择。

5,管脚PAD类型
在图2.4.3.1中,ESP32-P4芯片的PAD管脚类型分为两类电源域:VDDPST1和VDDPST2~VDDPST6。VDDPST1电源域负责管理GPIO0~GPIO15号管脚的电源,而VDDPST2~VDDPST6电源域则负责管理GPIO16~GPIO54号管脚的电源。之所以将管脚分为两类电源域,是因为ESP32-P4在不同工作模式下对电源管理有不同的需求。在低功耗(LP)模式下,芯片只能使用由VDDPST1电源域管理的GPIO0~GPIO15管脚,以最大限度减少功耗。而在高性能(HP)模式下,芯片可以使用VDDPST1到VDDPST6电源域管理的管脚,即可使用GPIO0~GPIO54的全部55个可编程I/O管脚,满足更复杂的I/O需求。这种电源域的划分使得ESP32-P4能够根据不同的工作状态灵活地管理功耗,同时提供丰富的I/O资源来支持多种应用。下面为VDDPST1到VDDPST6电源域管理的管脚范围,如下图所示。

第二章 初识ESP3211876.png
图2.4.3.4 电源域管理的GPIO(部分截图)

上图的列表摘自《ESP32-P4数据手册》中的2.2 Pin Overview小节,表格详细阐述了各个电源域管理的GPIO管脚。通过控制这些电源域的电压,我们可以相应地控制它们所管理的GPIO的输入输出电压。具体来说,VDDPST1电源域管理的GPIO(GPIO0~GPIO15)和VDDPST2~VDDPST6电源域管理的GPIO(GPIO16~GPIO54)在工作时可根据不同电源域的电压调节来控制相应管脚的电平状态,从而实现精确的电压控制与信号处理。
至此,我们已了解了ESP32-P4的IO MUX和GPIO交换矩阵各个模块的功能与特性,接下来我们将介绍如何配置GPIO管脚为输入或输出,并将其分别与输入信号和输出信号进行绑定。

6,管脚的输入输出配置
从上述内容可以看出,配置ESP32-P4的55个可编程I/O管脚的输入输出模式,需要通过配置IO_MUX_GPIOx_REG和LP_IOMUX_PADx_REG寄存器来实现。其中,IO_MUX_GPIOx_REG寄存器用于配置HP系统中所有55个可编程I/O管脚的电气特性,而LP_IOMUX_PADx_REG寄存器仅能用于配置GPIO0~GPIO15号管脚的I/O功能,适用于低功耗模式下的配置。接下来,笔者将以HP系统为例,介绍如何配置这些管脚。
下图为管脚PAD内部结构,如下图所示。

第二章 初识ESP3212481.png
图2.4.3.4 GPIO0~GPIO54的PAD内部结构

上图展示了PAD焊盘内部结构的输入/输出、上拉/下拉等配置,这些配置可以通过IO_MUX_GPIOx_REG(x:0~54)寄存器来实现。该寄存器用于设置与GPIO相关的电气属性,如输入输出模式、上拉或下拉电阻等。具体的寄存器描述和配置细节如下图所示。

第二章 初识ESP3212640.png
图2.4.3.5 配置GPIO输入配置

上图中,WPD和WPU字段用于配置GPIO的上下拉使能;IE和DRV字段用于配置GPIO的输入使能与驱动能力;SEL和EN字段用于配置GPIO功能和是否启动滤波器。输出配置是由GPIO_ENABLE_REG寄存器配置的,大家可参看《ESP32-P4技术参考手册》中的7.12 HP Peripheral Signal List小节内容。

7,管脚路由至内部外设信号
从图2.4.3.1中可以看出,若GPIO由VDDPST2~VDDPST6电源域管理,则该GPIO的输入信号会流经两个方向:一条是HP IO MUX,另一条是HP GPIO matrix交换矩阵。而若GPIO由VDDPST1电源域管理,则该GPIO的输入信号可流经四个方向:首先是HP IO MUX,其次是HP GPIO matrix交换矩阵,另外在系统处于低功耗模式(即LP系统)时,信号还将流入LP IO MUX和LP GPIO matrix交换矩阵。这些信号流向的方向可参考图2.4.3.1中的红色(③)箭头。
接下来,笔者以VDDPST2~VDDPST6电源域管理的GPIO为例进行说明。
1)若输入信号被选择输入到HP IO MUX,则必须首先选择该GPIO的功能,并将其直接连接至CPU内部外设信号。下图展示了可供选择的GPIO功能,这些功能可以通过配置IO_MUX_GPIOn_REG寄存器来实现。

第二章 初识ESP3213251.png
图2.4.3.6 IO MUX的GPIO选择功能(部分截图)

上图摘自《ESP32-P4数据手册》中的2.3.1 IO MUX Functions小节内容。上图中,若我们把GPIO28号管脚配置为Function3功能,则该GPIO通过IO MUX直接连接至SPI2_CS_PAD内部外设信号(请看图2.4.3.1中的⑥和①)。
2)当输入信号被选择进入高性能(HP)GPIO矩阵时,该信号会依次经过信号滤波和毛刺滤波处理,然后通过GPIO_EXT_GLITCH_FILTER_CHn_REG寄存器配置特定的GPIO输入。此寄存器用于选择对哪个GPIO信号应用毛刺滤波,以去除可能存在的短时噪声信号或毛刺信号,从而提升信号的稳定性和可靠性。经过滤波处理的信号还会进行时钟同步(GPIO SYNC),确保信号与系统时钟保持一致性,减少由于时钟不匹配可能引入的延迟或不稳定因素。同步处理完成后,信号将进入内部信号绑定模块,用于后续的逻辑控制或输出。如下图所示,通过GPIO_EXT_GLITCH_FILTER_CHn_REG(n:0~7)寄存器配置哪个GPIO输入字段描述。

第二章 初识ESP3213739.png
图2.4.3.7 配置哪个GPIO输入信号

3)通过GPIO_FUNCn_IN_SEL配置输入信号时,可参考图2.4.3.1中的步骤②。例如,若要将UART0的RXD输入信号(信号索引为10)连接到GPIO7,请按以下步骤配置。
设置GPIO_FUNC10_IN_SEL_CFG_REG寄存器(n表示图2.4.3.2中的索引号,对应uart0_rxd_pad_in输入信号)中的GPIO_SIG10_IN_SEL位,以通过HP GPIO矩阵启用外设输入。这样可以通过矩阵将信号索引10(即UART0的RXD输入)路由到一个GPIO上。然后在GPIO_FUNC10_IN_SEL_CFG_REG寄存器中,将GPIO_FUNC10_IN_SEL字段设置为7,指定GPIO7作为UART0 RXD信号的输入源,最后配置IO_MUX_GPIO7_REG寄存器中的IO_MUX_GPIO7_FUN_IE位(具体描述见图2.4.3.5中左则的外部信号),以启用GPIO7的引脚输入。此设置允许引脚从HP GPIO矩阵接收输入信号。上述用到的寄存器的字段描述如下所示。

第二章 初识ESP3214219.png
图2.4.3.8 配置GPIO映射到内部输入信号

至此,GPIO路由至内部输入信号的流程已讲解完成。对于LP系统,流程与HP系统类似,只是配置的寄存器不同。

8,内部外设信号路由至管脚
接下来,笔者将以HP系统的内部外设信号输出为例进行说明。如图2.4.3.1所示,HP系统中的232个外设信号可以通过HP GPIO matrix 和HP IO MUX输出。如果选择通过HP GPIO matrix输出外设信号(请看图2.4.3.1中的⑧),则必须配置对应的寄存器,即GPIO_FUNCn_OUT_SEL_CFG_REG寄存器,其中n表示图2.4.3.2右侧列出的外部信号编号,共有232个外部输出信号。以下是GPIO_FUNCn_OUT_SEL_CFG_REG寄存器的字段描述。

第二章 初识ESP3214562.png
图2.4.3.9 内部外设输出信号绑定GPIO

如果选择直接输出外设信号,则信号会通过HP IO MUX的直接映射功能输出。这些映射功能我们已经在图2.4.3.6中进行了详细说明。要实现直接输出的配置,只需设置对应的IO_MUX_GPIOn_REG寄存器,即可完成信号的输出。
至此,内部输出信号路由至GPIO的流程已讲解完成。对于LP系统,流程与HP系统类似,也 是配置的寄存器不同。

2.4.4 芯片Boot控制
芯片在上电或硬件复位时,会通过某些管脚的上下拉(Strapping Pins)和eFuse bits(是一种可编程电子保险丝,是一种用于存储信息和保护芯片的非易失性存储器件)来确定其启动过程和一些功能,无需微处理器的参与。这些设置可以决定以下功能:
1)芯片启动模式:确定芯片以何种模式启动。
2)ROM消息打印的启动和禁用:决定是否在启动时打印ROM中的消息。
3)JTAG信号源:决定JTAG信号的来源。

1,芯片启动模式。
在电源上电或复位过程中,芯片会采集Strapping管脚(GPIO35、GPIO36、GPIO37、GPIO38)的电平状态,存储在锁存器中并保持至断电。下表是芯片启动模式控制。

4.png
表2.4.4.1 芯片启动模式控制

ESP32-P4芯片的启动模式由GPIO35至GPIO38的电平决定。默认情况下,若GPIO35为高电平,则芯片进入“SPI Boot”模式;若GPIO35为低电平且GPIO36为高电平,则进入“Joint Download Boot”模式,支持“USB”、“UART”和“SPI Slave”三种下载方式;若GPIO35至GPIO37均为低电平且GPIO38为高电平,则芯片进入“SPI Download Boot”模式;若GPIO35至GPIO38均为低电平,则芯片进入“Invalid Combination”无效模式。下图为Strapping管脚默认电平。

第二章 初识ESP3215531.png
图2.4.4.1 Strapping管脚默认电平

根据上图所示,ESP32-P4芯片的GPIO35管脚在默认情况下内部连接有一个上拉电阻,这种配置使得芯片进入“SPI Boot”模式。若GPIO35管脚未连接或连接到外部高阻抗电路,那么内部的弱上拉电阻将确定该管脚的默认输入电平,进而决定芯片的默认启动模式。下图是芯片启动流程。

第二章 初识ESP3215698.png
图2.4.4.2 ESP32-P4芯片启动流程

注意:上图中的“x1”和“01”表示GPIO35和GPIO36组合值,芯片根据这两个管脚组合值进入不同的启动模式。
小知识:
1)Strapping管脚是芯片每次上电或复位时,都需要一些初始配置参数,如加载芯片的启动模式、flash存储器的电压等。这些参数通过strapping管脚控制。芯片读取Strapping管脚上电时的状态来配置芯片的初始化的参数,复位释放后, strapping管脚和普通IO管脚功能相同。
2)在SPI Boot模式下,ROM引导加载程序通过从SPI flash中读取程序来启动系统。在这个模式下,我们还可以进一步分类如下:
①:Normal flash Boot:ROM引导加载程序通过从SPI Flash加载至L2MEM中启动。
②:Direct Boot:程序从Flash运行。如果要启动此模式,请确保下载的bin文件前两个字为0xaedb041d。
3)在Joint Download Boot模式下,用户可通过USB或UART0接口将二进制文件下载至flash,或者下载至L2MEM中直接运行‌。
4)在SPI Download Boot模式下,用户可通过SPI接口将二进制文件下载至Flash,或者下载至L2MEM中直接运行。

2,ROM消息打印的启动和禁用
系统启动过程中,ROM代码log可打印至如下控制器。
1)UART0和USB Serial/JTAG控制器(默认)
2)USB Serial/JTAG控制器
3)UART0
EFUSE_UART_PRINT_CONTROL(eFuse 位)和GPIO36控制ROM消息打印到UART0,如下图所示。

第二章 初识ESP3216424.png
图2.4.4.3 UART0 ROM 日志打印控制

EFUSE_DIS_USB_SERIAL_JTAG_ROM_PRINT(eFuse 位)用于控制 ROM 日志是否打印到 USB Serial/JTAG 控制器。当该位为 1 时,禁止将日志打印到 UART Serial/JTAG 控制器。当该位为 0 时,如果通过 EFUSE_DIS_USB_SERIAL_JTAG 启用 USB Serial/JTAG 控制器,则 ROM 消息将打印到 USB 串口/JTAG 控制器。具体情况如下图所示。

第二章 初识ESP3216675.png
图2.4.4.4 USB 串口/JTAG ROM 日志打印控制

默认情况下,EFUSE_UART_PRINT_CONTROL(eFuse 位)和 EFUSE_DIS_USB_SERIAL_JTAG_ROM_PRINT(eFuse 位)均配置为 0,表示启用 UART0 和 USB Serial/JTAG ROM 日志打印功能。请注意,如果 EFUSE_DIS_USB_SERIAL_JTAG_ROM_PRINT 设置为 0 以打印到 USB,但 USB Serial/JTAG 控制器已禁用,则 ROM 消息将不会打印到 USB Serial/JTAG 控制器。
有关 eFuse 控制器的详细信息,请参阅《ESP32-P4 Technical Reference Manual》中的第 292 页“eFuse Controller”章节,该章节提供了关于 eFuse 控制器的技术规格和功能说明。

3,JTAG信号源
在系统启动的早期,GPIO34可用于控制JTAG信号源。该引脚没有内部上下拉电阻,因此strapping的值必须由不处于高阻抗状态的外部电路控制。如下表所示,GPIO34与EFUSE_DIS_PAD_JTAG、EFUSE_DIS_USB_JTAG和EFUSE_JTAG_SEL_ENABLE共同控制JTAG信号源。

5.png
图2.4.4.2 JTAG信号源控制

上图中的 eFuse 1、eFuse 2 和 eFuse 3 分别代表 eFuse 位的 EFUSE_DIS_PAD_JTAG、EFUSE_DIS_USB_JTAG 和 EFUSE_JTAG_SEL_ENABLE。这里的 x 代表任意值,可以忽略。

2.4.5 中断矩阵
ESP32-P4 拥有多达 126个外设中断源,需要通过中断矩阵将这些中断信号映射到 32个HP CPU0中断 或 32个HP CPU1中断。若没有中断矩阵,这样大规模的中断源管理将极具复杂性。而通过中断矩阵,不仅能有效地将中断源分配到不同的CPU核,还可以根据应用需求将同一中断源路由至多个CPU中断输入,从而实现灵活的中断处理和多任务并行操作。通过这种结构设计,ESP32-P4的中断矩阵确保了复杂的外设中断管理变得高效、灵活且可扩展,为开发者提供了更多的系统配置选项,优化了系统性能和响应能力。
关于ESP32-P4的这126个外设中断源的详细信息,可以参考 《ESP32-P4技术参考手册》中的593页,其中的表10.4-1 描述了 CPU外设中断源映射/状态寄存器和外设中断源,为开发者提供了详细的中断源配置和映射方式。

1,中断矩阵概述
中断矩阵是一种灵活的硬件机制,用于管理和分配系统中断信号,使得多个外设的中断请求能够灵活地映射到不同的CPU中断输入上。在ESP32-P4芯片中,中断矩阵允许通过软件配置,将不同外设或GPIO引脚的中断源动态连接到特定的CPU中断控制器(Interrupt Controller)。
中断矩阵的主要功能在于其高度灵活性和可配置性,具体包括:
1)动态路由中断源:中断矩阵可以将不同的外设或GPIO中断信号连接到任意CPU核心的中断通道上,支持跨核中断分配。
2)优先级管理:矩阵允许对不同的中断源设置优先级,以确保高优先级中断能够抢占低优先级中断,提高系统的实时性。
3)中断源隔离:它支持通过矩阵的配置隔离不同的中断源,避免多个中断源竞争同一中断通道,从而提升系统的稳定性和鲁棒性。
4)可查询当前外设中断源的中断状态。
5)多个中断源可映射到单个HP CPU0或HP CPU1中断,我们称之为共享中断。
下图为ESP32-P4芯片中断矩阵结构。

第二章 初识ESP3218356.png
图2.4.5.1 中断矩阵结构

上图中的蓝色框表示中断矩阵,它负责接收来自外设的中断信号,包括低功耗外设(LP Peripheral Interrupt Sources)和高性能外设(HP Peripheral Interrupt Sources)。当中断矩阵接收到这些外设中断信号后,用户可以通过配置红色框标识的 Core0 Interrupt Reg 或 Core1 Interrupt Reg 寄存器,来选择将外设中断源路由到 HP CPU0 或 HP CPU1。
红色框中的 Core0 Interrupt Reg 和Core1 Interrupt Reg寄存器具有两个主要功能:
1)上图中的①,通过配置端口(Config Port) 动态地将中断信号路由到特定核心的中断控制器,允许用户灵活配置中断路由。
2)上图中的②,通过状态端口(Status Port) 查询当前外设中断源的状态,帮助用户监控和调试中断的处理情况。
上图中的绿色框标识表示 Core0 Interrupt Ctrl 和Core1 Interrupt Ctrl中断控制器,它负责处理路由到该核心的中断信号。这些控制器可以根据中断优先级、信号来源等条件,决定是否处理中断。最终,当CPU接收到外部中断信号时,会调用与该中断相关联的中断服务程序(上图的橙色框标识),处理完毕后,恢复正常操作。

2,中断矩阵的操作流程
1)中断信号生成:当某个外设或GPIO产生中断事件时,信号传递至中断矩阵。
2)信号路由:中断矩阵根据预设的路由配置,将中断信号映射至目标CPU的中断输入端。
3)CPU中断处理:CPU接收到中断信号后,根据中断优先级判定是否处理该中断。当中断处理完成后,CPU通过清除相应标志位或通过软件控制的中断服务恢复正常执行流程。
下图为中断处理流程图。


第二章 初识ESP3219131.png
图2.4.5.1 中断处理流程

在 ESP32-P4 中,外设模块可以生成多达126个内部中断源,这些中断源对应于不同的外设事件或状态变化,如计时器溢出、串口数据接收完成、GPIO信号变化等。这些中断源首先通过硬件生成 126条中断信号(Interrupt Signals)。
接下来,这些外设中断信号被发送到中断矩阵(Interrupt Matrix),一个用于灵活管理和分配中断信号的硬件结构。中断矩阵将外设的中断信号转化为 中断源(Interrupt Sources),并根据系统配置将其路由到适当的CPU核上的中断控制器。
上图中的中断控制器的任务是根据系统设计和开发者的配置,将这 126个外设中断源路由到 32条CPU中断通道,这些通道分别与ESP32-P4的不同CPU核(CPU0和CPU1)相对应。当中断矩阵将中断源映射到相应的CPU中断信号时,信号最终会进入 HP CPU中断控制器。该控制器负责进一步管理和处理来自中断矩阵的信号,并根据中断的优先级做出处理决策。当中断控制器决定处理某个中断时,CPU会暂停当前任务,执行与中断相关的中断服务例程(ISR)。中断处理完成后,系统将恢复正常任务执行,并清除中断标志,确保系统顺利运行。
下图为中断矩阵管理的CPU外设中断源映射和状态寄存器。


第二章 初识ESP3219687.png
图2.4.5.2 CPU外设中断源映射和状态寄存器(部分截图)

读者可在《ESP32-P4技术参考手册》中的“Interrupt Matrix”章节中,参考表10.4.1,找到关于CPU外设中断源映射和状态寄存器的详细内容。该表格列出了所有可用的中断源及其映射关系,有助于理解中断系统的工作机制和配置方法。

2.5 ESP32-P4 启动流程
本文将会介绍ESP32-P4从上电到运行app_main函数中间所经历的步骤(即启动流程)。从宏观上,该启动流程可分为如下三个步骤。
1)一级引导程序,它被固化在ESP32-P4内部的ROM中,它会从flash的0x2000处地址加载二级引导程序至RAM(IRAM & DRAM)中。
2)二级引导程序从flash中加载分区表和主程序镜像至内存中,主程序中包含了RAM段和通过flash高速缓存映射的只读段。
3)应用程序启动阶段运行,这时第二个CPU和freeRTOS的调度器启动,接着运行main_task任务函数,从而进入app_main函数执行用户代码。
下面作者根据IDF库相关的代码来讲解这三个引导流程,如下:

1,一级引导程序
该部分程序是直接存储在ESP32-P4内部ROM中,所以普通开发者无法直接查看,它主要是做一些前期的准备工作(复位向量代码),然后从flash 0x2000偏移地址中读取二级引导程序文件头中的配置信息,并使用这些信息来加载剩余的二级引导程序。

2,二级引导程序
该程序是可以查看且可被修改,在搭建ESP-IDF环境完成后,可在esp-idf\components\bootloader/subproject/main/路径下找到bootloader_start.c文件,此文件就是二级引导程序启动处。首先我们克隆ESP-IDF库,克隆过程如下所示。

第二章 初识ESP3220457.png
图2.6.1 克隆ESP-IDF库

克隆完成后,使用VSCode打开ESP-IDF库,接着找到bootloader_start.c,如下图所示。

第二章 初识ESP3220532.png
图2.6.2 bootloader_start.c文件路径

在这个文件下,找到call_start_cpu0函数,此函数是bootloader程序,如下是bootloader程序的部分代码。
  1. /*
  2. ROM引导加载程序完成从闪存加载第二阶段引导加载程序之后到达这里
  3. */
  4. void __attribute__((noreturn)) call_start_cpu0(void)
  5. {
  6.     if (bootloader_before_init) {
  7.         bootloader_before_init();
  8.     }

  9. /* 1. 硬件初始化:初始化内存、启用超级看门狗自动喂养、配置时钟、清除bss段、开启cache和
  10. 复位mmu等操作。
  11. bootloader_support/src/ esp32-p4/bootloader_esp32p4.c */
  12.     if (bootloader_init() != ESP_OK) {
  13.         bootloader_reset();
  14.     }

  15.     if (bootloader_after_init) {
  16.         bootloader_after_init();
  17.     }

  18.     /* 2. 选择启动分区的数量:加载分区表,选择boot分区 */
  19.     bootloader_state_t bs = {0};
  20.     int boot_index = select_partition_number(&bs);
  21.    
  22.     if (boot_index == INVALID_INDEX){
  23.         bootloader_reset();
  24.     }

  25. /* 3. 加载应用程序映像并启动
  26. bootloader_support/src/esp32-p4/bootloader_utility.c */
  27.     bootloader_utility_load_boot_image(&bs, boot_index);
  28. }
复制代码
ESP-IDF使用二级引导程序可以增加FLASH分区的灵活性(使用分区表),并且方便实现FLASH加密,安全引导和空中升级(OTA)等功能。主要的作用是从flash的0x8000处加载分区表(请看在线ESP-IDF编程指南分区表章节)。根据分区表运行应用程序。

3,三级引导程序
应用程序的入口是在esp-idf/components/esp_system/port/路径下的cpu_star.c文件,在此文件下找到call_start_cpu0函数(端口层初始化函数)。这个函数由二级引导加载程序执行,并且从不返回。因此你看不到是哪个函数调用了它,它是从汇编的最底层直接调用的(components\esp_system\ld\esp32p4\sections.ld.in汇编文件)。
这个函数会初始化基本的C运行环境(“CRT”),并对SOC的内部硬件进行了初始配置。执行call_start_cpu0函数完成之后,在components\esp_system\startup.c文件下调用start_cpu0(在36行中,弱关联start_cpu0_default函数)系统层初始化函数,如下start_cpu0_default函数的部分代码。
  1. static void start_cpu0_default(void)
  2. {
  3.     /* 初始化核心组件和服务 */
  4.     do_core_init();

  5.     /* 执行构造函数 */
  6.     do_global_ctors();

  7.     /* 执行其他组件的init函数 */
  8. do_secondary_init();

  9. #if SOC_CPU_CORES_NUM > 1 && !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
  10.     s_system_full_inited = true;
  11. #endif

  12.     /* 开启APP程序 */
  13.     esp_startup_start_app();
  14.     while (1);
  15. }
复制代码
到了这里,就完成了二级程序引导,并调用esp_startup_start_app函数进入三级引导程序,该函数的源码如下:
  1. /* components/freertos/app_startup.c */
  2. /* 开启APP程序 */
  3. void esp_startup_start_app(void)
  4. {
  5.     /* 省略部分代码 */

  6.     /* 新建main任务函数 */
  7.     BaseType_t res = xTaskCreatePinnedToCore(main_task, "main",
  8.                                              ESP_TASK_MAIN_STACK, NULL,
  9.                                              ESP_TASK_MAIN_PRIO, NULL,
  10.                                              ESP_TASK_MAIN_CORE);
  11.     assert(res == pdTRUE);
  12.     (void)res;

  13.     void __attribute__((weak)) port_start_app_hook(void);
  14.     if (port_start_app_hook != NULL) {
  15.         port_start_app_hook();
  16.     }

  17.     ESP_EARLY_LOGD(APP_START_TAG, "Starting scheduler on CPU0");
  18.     /* 开启FreeRTOS任务调度 */
  19.     vTaskStartScheduler();
  20. }

  21. /* main任务函数 */
  22. static void main_task(void* args)
  23. {   /* 省略部分代码 */
  24.     /* 执行app_main函数 */
  25.     ESP_LOGI(MAIN_TAG, "Calling app_main()");
  26.     extern void app_main(void);
  27.     app_main();
  28.     ESP_LOGI(MAIN_TAG, "Returned from app_main()");
  29.     vTaskDelete(NULL);
  30. }
复制代码
从上述源码可知,首先在xTaskCreatePinnedToCore函数创建main_task任务,然后开启freeRTOS任务调度器,最后在main_task任务下调用app_main函数(此函数在创建工程时,在main.c下定义的)。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则


关闭

原子哥极力推荐上一条 /1 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-12-6 11:00

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表