005如何使用ESP32双核
以下为作者本人关于esp32的FreeRtos学习笔记,供自己学习参考。
平台:Ubuntu 20.04 LTS + Arduino IDE
window平台上的代码完全一致,因为我自己电脑上的win11系统arduino编译速度过于缓慢(无法忍受(* ̄︿ ̄)),遂转到ubuntu。
今天的任务比较轻松,故笔记比较简陋,但是看懂应该不成问题(๑•̀ㅂ•́)و✧
首先来看一段废话(bushi)稍微了解一下它的双核
ESP32是一款功能强大的微控制器,其最大的特点之一是采用了双核处理器架构。这种架构使得ESP32能够同时执行多个任务,从而提高了系统的整体性能和效率。
-
一、双核架构概述
ESP32的双核处理器基于Tensilica LX6微处理器架构,由两个独立的32位核心组成:主核(Pro-CPU)和应用核(App-CPU)。 -
二、主核(Pro-CPU)
主核是ESP32的高性能核心,基于RISC-V指令集架构。它具有较高的时钟频率和强大的计算能力,适合执行复杂和计算密集型的任务。在操作系统中,主核通常负责运行主线程、管理内存和处理器资源,以及执行那些需要高性能的任务。 -
三、应用核(App-CPU)
应用核是ESP32的低功耗核心,同样基于RISC-V指令集架构。相比于主核,应用核的时钟频率较低,但功耗也相应地减少,使其非常适合执行轻量级和实时性要求较高的任务。应用核常用于运行应用程序的次要线程、处理中断和实时事件,以及执行一些低功耗模式下的任务。 -
四、核心间的通信与协作
ESP32的两个核心之间通过共享内存和中断机制进行通信和协作。它们可以共同访问同一块内存空间,从而方便数据在两个核心之间的传输和共享。此外,ESP32的中断控制器允许一个核心向另一个核心发送中断信号,以便及时通知和响应特定的事件或任务。 -
五、操作系统的调度与任务分配
ESP32通常搭载FreeRTOS等实时操作系统,操作系统的调度器负责在两个核心之间进行任务的分配和调度。它会根据任务的重要性和优先级,将任务分配给最适合执行的核心。这种灵活的调度机制使得ESP32能够同时处理多个任务,提高系统的整体性能和效率。 -
六、总结
ESP32的双核处理器架构为其在物联网、智能家居、智能城市等领域中的广泛应用提供了强大的支持。无论是需要高性能的计算任务,还是要求实时响应的轻量级任务,ESP32都能够通过其双核处理器实现高效的处理和执行。通过合理利用主核和应用核的特点和优势,以及操作系统的任务调度机制,开发者可以充分发挥ESP32双核处理器的潜力,创造出更多创新的应用。
/*
程序: 多核多任务
API
xPortGetCoreID() 获取当前任务运行的核心
xTaskCreate() 由系统选择运行核心,优先选择0
xTaskCreatePinnedToCore() 指派任何给指定核心
*/
void taskA(void *ptParam) {
while (1) {
Serial.println(xPortGetCoreID());
}
}
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
xTaskCreatePinnedToCore(taskA, "Task A", 1024 * 4, NULL, 1, NULL,0);
}
void loop() {
Serial.println(xPortGetCoreID());
}
这段代码是一个简单的FreeRTOS任务示例,它使用Arduino平台。下面是对代码的详细解读和笔记:
taskA函数
功能: 这是一个FreeRTOS任务,它的功能是不断地通过串行端口打印当前运行的核心ID。
void taskA(void *ptParam) {
while (1) {
Serial.println(xPortGetCoreID());
}
}
细节分析:
void taskA(void *ptParam)
: 这是FreeRTOS任务的函数定义,ptParam
是一个指向传递给任务的参数的指针,但在这个例子中,参数没有被使用。while (1)
: 这是一个无限循环,确保任务不断地运行。Serial.println(xPortGetCoreID())
: 这行代码打印当前运行的核心ID。xPortGetCoreID()
是FreeRTOS的API,用于获取当前执行代码的核心ID。
setup函数
功能: setup
函数在Arduino程序中仅执行一次,用于初始化设置。
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
xTaskCreatePinnedToCore(taskA, "Task A", 1024 * 4, NULL, 1, NULL, 0);
}
细节分析:
Serial.begin(115200)
: 初始化串行通信,设置波特率为115200。xTaskCreatePinnedToCore(taskA, "Task A", 1024 * 4, NULL, 1, NULL, 0)
: 创建一个新的FreeRTOS任务,并将其绑定到特定的核心上。taskA
: 要执行的任务函数。"Task A"
: 任务的名称。1024 * 4
: 任务堆栈的大小,这里是4KB。NULL
: 任务传递给任务的参数,这里没有传递参数。1
: 任务的优先级。NULL
: 任务句柄,如果不需要后续管理任务,可以设置为NULL。0
: 任务的绑定核心ID,0通常表示第一个核心。
loop函数
功能: 在Arduino中,loop
函数在setup
函数执行后反复执行,用于主循环代码。
void loop()
{
Serial.println(xPortGetCoreID());
}
细节分析:
Serial.println(xPortGetCoreID())
: 在主循环中,代码同样打印当前运行的核心ID。这意味着,如果taskA
任务也在相同的核心上执行,那么loop
函数和taskA
任务可能会交替执行,并交替打印核心ID。
总结
- 代码展示了如何在Arduino平台上使用FreeRTOS创建并运行一个简单的任务。
- 通过串行端口,可以观察到任务是在哪个核心上执行的。
- 需要注意的是,
xPortGetCoreID()
返回的核心ID取决于FreeRTOS的配置和硬件平台,所以具体的ID值可能会有所不同。本例中使用ESP32S3的为双核,但是如果使用ESP32C系列就只有一个核心,不支持本节的操作。 - 实际效果可能受到硬件和FreeRTOS配置的影响。
笔记参考B站大佬 孤独的二进制 的视频教程ESP32 FreeRTOS