3、开发环境搭建:硬件平台选择、交叉编译工具链、调试工具
好,咱们正式开始动手了。这一章我带你搭环境。说实话,很多初学者觉得搭环境是浪费时间,恨不得直接写代码。但我跟你说,环境没搭好,后面全是坑。我在项目里见过太多人,代码写得挺漂亮,结果一调试发现工具链版本不对,或者OpenOCD死活连不上板子,一查就是配置文件写错了。嗯,咱们别走弯路。
3.1 硬件平台选择:为什么是Cortex-A53双核?
先说说硬件。我选Cortex-A53双核,不是随便挑的。你想想看,现在市面上主流的嵌入式多核芯片,A53几乎是个标配。树莓派3B、全志H3、瑞芯微RK3328,用的都是它。而且A53支持ARMv8-A架构,既能跑32位也能跑64位,灵活性很高。
我个人习惯,做FreeRTOS多核移植,首选双核起步。为什么?因为单核太简单,四核又太复杂,双核刚刚好。你能体会到核间通信、共享资源保护这些核心概念,又不会被调度器的复杂度搞晕。
硬件选型建议:
- 入门推荐:树莓派3B(BCM2837,四核A53,但你可以只用其中两个核)
- 工业级推荐:全志H3(四核A53,价格便宜,资料多)
- 学习板推荐:友善之臂NanoPi NEO2(全志H5,双核A53,小巧)
我这里以树莓派3B为例来讲。为什么?因为它的文档最全,社区最活跃。你遇到问题,Google一搜一大把答案。我曾经用树莓派3B做过一个工业数据采集项目,跑了三个FreeRTOS任务加一个Linux,稳得很。
小提示:如果你手头没有树莓派,用QEMU模拟器也能跑。我后面会专门讲怎么用QEMU调试多核FreeRTOS。但说实话,模拟器跟真板子还是有差距的,尤其是中断延迟和缓存一致性这些,模拟器模拟不出来。
3.2 交叉编译工具链:aarch64-linux-gnu-gcc
好,硬件选好了,接下来是工具链。Cortex-A53是ARMv8-A架构,64位。所以我们需要一个能生成aarch64代码的交叉编译器。
我推荐用aarch64-linux-gnu-gcc。这是Linaro维护的版本,稳定,更新也及时。你可以在Linaro官网下载,或者直接用apt安装:
sudo apt-get install gcc-aarch64-linux-gnu binutils-aarch64-linux-gnu
装完之后,验证一下:
aarch64-linux-gnu-gcc --version
你应该能看到类似这样的输出:
aarch64-linux-gnu-gcc (Linaro GCC 7.5-2019.12) 7.5.0
嗯,版本号不重要,7.x以上都行。但有一点要注意:不要用太新的版本。我记得有一次,我用GCC 10编译FreeRTOS,结果链接的时候报了一堆莫名其妙的错误,查了半天发现是GCC 10默认启用了LTO(链接时优化),跟FreeRTOS的某些内联汇编冲突了。后来换回GCC 7,一切正常。
避坑指南:我曾经因为工具链版本不对,浪费了整整两天。建议你固定使用Linaro GCC 7.5或8.3版本。这两个版本经过大量项目验证,最稳定。
除了编译器,你还需要一个链接脚本。FreeRTOS多核启动时,每个核需要知道自己从哪里开始执行。这个链接脚本定义了各个段的加载地址。我一般这样写:
/* memory.ld */
MEMORY
{
RAM (rwx) : ORIGIN = 0x80000000, LENGTH = 0x10000000
}
SECTIONS
{
.text : {
*(.text*)
} > RAM
.data : {
*(.data*)
} > RAM
.bss : {
*(.bss*)
} > RAM
}
这个脚本很简单,把所有代码和数据都放在0x80000000开始的256MB内存里。实际项目中,你可能需要更精细的内存布局,比如把中断向量表放在固定地址。但刚开始,够用了。
3.3 调试工具:OpenOCD + GDB
环境搭好了,代码写好了,怎么调试?用printf?别闹了。多核系统里,printf会打乱时序,而且你根本不知道哪个核在打印。我强烈建议你学会用OpenOCD + GDB。
OpenOCD负责跟硬件通信,GDB负责调试。它们俩配合,你可以做到:
- 单步执行任意一个核的代码
- 查看所有核的寄存器状态
- 设置硬件断点(不依赖软件)
- 查看共享内存的内容
安装OpenOCD:
sudo apt-get install openocd
然后你需要一个配置文件。树莓派3B的调试接口是JTAG,但默认没开启。你需要先修改/boot/config.txt,加上:
enable_jtag_gpio=1
gpio=22-27=a2
重启后,用一根杜邦线连接树莓派的GPIO引脚到JTAG调试器(比如J-Link或FT2232)。具体的引脚对应关系,我建议你查树莓派的官方文档,不同版本略有差异。
启动OpenOCD:
openocd -f interface/jlink.cfg -f target/rpi3.cfg
如果一切正常,你会看到类似这样的输出:
Info : Listening on port 3333 for gdb connections
好,OpenOCD跑起来了。现在打开另一个终端,启动GDB:
aarch64-linux-gnu-gdb your_elf_file.elf
(gdb) target remote localhost:3333
(gdb) monitor reset halt
(gdb) info registers
你应该能看到所有核的寄存器状态。嗯,到这里,你的调试环境就搭好了。
调试技巧:多核调试时,GDB默认只连接CPU0。要切换到其他核,用monitor mww 0x40000000 1这样的命令。具体命令取决于你的芯片。我一般会在代码里加一个全局变量,每个核写一个不同的值,然后通过查看这个变量来判断哪个核在运行。
3.4 验证环境:跑一个Hello World
环境搭好了,咱们跑个简单的程序验证一下。写一个最简单的FreeRTOS程序,让两个核各自打印一句话:
#include "FreeRTOS.h"
#include "task.h"
void vTask1(void *pvParameters) {
while(1) {
/* 在UART上打印 */
uart_send_string("Hello from Core 0\n");
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
void vTask2(void *pvParameters) {
while(1) {
uart_send_string("Hello from Core 1\n");
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
int main(void) {
/* 初始化硬件 */
uart_init();
/* 创建任务 */
xTaskCreate(vTask1, "Task1", 1024, NULL, 1, NULL);
xTaskCreate(vTask2, "Task2", 1024, NULL, 1, NULL);
/* 启动调度器 */
vTaskStartScheduler();
return 0;
}
编译:
aarch64-linux-gnu-gcc -c main.c -o main.o
aarch64-linux-gnu-ld -T memory.ld main.o -o freertos.elf
然后用OpenOCD + GDB下载并运行。如果一切顺利,你应该能在UART上看到两个核交替打印。嗯,到这里,你的开发环境就彻底搭好了。
总结一下:
- 硬件:Cortex-A53双核(树莓派3B或类似板子)
- 工具链:aarch64-linux-gnu-gcc 7.5或8.3
- 调试:OpenOCD + GDB,通过JTAG连接
- 验证:跑一个双核Hello World
下一章,咱们开始真正移植FreeRTOS到多核系统。我会带你一步步修改启动代码、配置中断控制器、实现核间通信。说实话,那才是真正有意思的部分。准备好了吗?