从零上手嵌入式 RTOS:以 Raspberry Pi Pico 2 WH 为例的烧录、定制构建与多系统对比指南

5 阅读13分钟

从零上手嵌入式 RTOS:以 Raspberry Pi Pico 2 WH 为例的烧录、定制构建与多系统对比指南

目标读者:第一次上手嵌入式 RTOS、想在真实硬件上做固件验证/代码审计/漏洞复现的安全研究者或嵌入式开发者。

说明:本文覆盖 Zephyr OS、FreeRTOS、RT-Thread 三套主流 RTOS 在 Raspberry Pi Pico 2 W/WH 上的环境搭建、构建与烧录流程,并系统梳理各种连接方式与调试手段。

作者也是小白,文中如有错误欢迎指正。


目录

  1. 为什么我选 Raspberry Pi Pico 2 WH
  2. 硬件连接方式全览
  3. 除了开发板,还需要什么?
  4. Zephyr OS:环境搭建与构建
  5. Zephyr OS:Hello World 烧录验证
  6. Zephyr OS:构建带 LLEXT 的定制固件
  7. FreeRTOS:环境搭建与烧录
  8. RT-Thread:环境搭建与烧录
  9. 三套 RTOS 横向对比
  10. 多 RTOS 共存与切换烧录策略
  11. 调试进阶:GDB、OpenOCD、逻辑分析仪
  12. 固件安全审计:通用技巧
  13. 常见问题与排查
  14. 经验总结
  15. 附录

1. 为什么我选 Raspberry Pi Pico 2 WH(RP2350) {#1}

两个词简述原因:便捷、便宜。

硬件规格速览

参数规格
主控RP2350A
CPU双核 Cortex-M33 @ 150MHz(亦可切换为 RISC-V Hazard3)
SRAM520KB
Flash2MB(板载 QSPI)
Wi-Fi / BLECYW43439(Pico 2 W/WH)
GPIO26 个可用 GPIO,支持 PWM/I2C/SPI/UART/ADC
USBUSB 1.1 设备/主机模式
安全特性TrustZone-M,OTP,安全启动(可选)
价格~7USDW版), 7 USD(W 版),~8 USD(WH 版,预焊排针)

对 RTOS 研究者的优势

  • 多 RTOS 生态齐全:Zephyr、FreeRTOS、RT-Thread 都有官方或社区维护的 Pico 2 支持,是横向对比研究的理想平台。
  • 烧录无门槛:UF2 拖拽,无需调试器,5 秒完成烧录。
  • 双架构可切换:RP2350 支持 Cortex-M33 和 RISC-V(Hazard3)双架构,可以研究同一 RTOS 在不同架构下的行为差异。
  • 安全特性丰富:TrustZone-M 和 OTP 为研究 TEE 相关攻击面提供了条件。

已知限制

  • CONFIG_USERSPACE(Zephyr 用户空间隔离)在 rpi_pico2 目标上不可用(ARCH_HAS_USERSPACE=n)。需要此特性时请用 qemu_x86_64
  • Wi-Fi 需要专有 blob,构建依赖外网访问。
  • 2MB Flash 在启用 Wi-Fi + LLEXT + Shell 后会比较紧张。

2. 硬件连接方式全览 {#2}

这是很多教程忽略的部分,但连接方式直接影响调试效率。Pico 2 WH 支持多种连接和调试方式,根据你的需求选择合适的方案。

2.1 方案一:Micro-USB(最简单,推荐入门)

适合场景:快速烧录、USB 串口 shell、USB 网络(RNDIS/ECM)。

PC ──[Micro-USB 数据线]── Pico 2 W/WH

工作原理:Pico 2 的 USB 控制器在 BOOTSEL 模式下枚举为 USB 大容量存储设备(MSC),固件运行时可枚举为 CDC-ACM(虚拟串口)、HID、RNDIS 等任意 USB 设备类。

操作步骤

  1. 按住 BOOTSEL,插入 USB,电脑弹出 RPI-RP2 U 盘。
  2. 拖入 .uf2 文件,板子自动重启运行新固件。
  3. 固件运行后,设备管理器(Windows)或 ls /dev/ttyACM*(Linux)可见虚拟串口。

连接串口

# Linux
picocom -b 115200 /dev/ttyACM0

# Windows(命令行)
plink -serial COM7 -sercfg 115200,8,n,1,N

局限性

  • 无法在固件运行时直接 GDB 调试(需配合 SWD 或 USB 调试适配器)。
  • cmd.exe + plink 下方向键/历史记录体验差,建议用 PuTTY GUI 或 Windows Terminal。

2.2 方案二:SWD + PicoProbe(推荐调试)

适合场景:GDB 单步调试、读写寄存器、不中断运行的日志输出(RTT)、无需进入 BOOTSEL 的在线烧录。

SWD(Serial Wire Debug)是 ARM Cortex-M 系列的标准调试接口,只需 3 根线(SWDIO、SWDCLK、GND)。

你需要准备

  • 另一块 Raspberry Pi Pico(普通 Pico 即可)刷成 PicoProbe 固件作为调试适配器。
  • 3 根杜邦线。

PicoProbe 固件下载

wget https://github.com/raspberrypi/picoprobe/releases/latest/download/picoprobe.uf2
# 将这个 uf2 烧录到作为调试器的那块 Pico

接线方式(调试器 Pico → 目标 Pico 2 WH)

调试器 Pico目标 Pico 2 WH说明
GP2SWDCLK(Pin 24)时钟线
GP3SWDIO(Pin 25)数据线
GNDGND共地(必须)
GP4(TX)GP1(UART0 RX)可选:转发 UART 日志
GP5(RX)GP0(UART0 TX)可选:转发 UART 日志
VSYSVSYS可选:为目标供电
调试器 Pico                目标 Pico 2 WH
  GP2 ────────────────────── SWDCLK
  GP3 ────────────────────── SWDIO
  GND ────────────────────── GND
  GP4 ────────────────────── GP1 (UART RX)  [可选]
  GP5 ────────────────────── GP0 (UART TX)  [可选]

安装 OpenOCD(支持 RP2350)

# Ubuntu 22.04 包管理器版(可能略旧)
sudo apt install openocd

# 推荐:从 Raspberry Pi 官方分支编译
git clone https://github.com/raspberrypi/openocd.git --branch rp2040 --depth=1
cd openocd
./bootstrap
./configure --enable-picoprobe --enable-cmsis-dap
make -j$(nproc)
sudo make install

OpenOCD 连接目标

openocd -f interface/cmsis-dap.cfg \
        -f target/rp2350.cfg \
        -c "adapter speed 5000"

看到以下输出说明连接成功:

Info : SWCLK/TCK = 1 SWDIO/TMS = 1 TDI = 0 TDO = 0 nTRST = 0 nSRST = 1
Info : SWD DPIDR 0x0bc12477
Info : rp2350.cpu0: hardware has 4 breakpoints, 2 watchpoints

GDB 调试

# 新开终端连接 OpenOCD
arm-none-eabi-gdb build/zephyr/zephyr.elf

(gdb) target remote :3333
(gdb) monitor reset halt
(gdb) load            # 烧录固件
(gdb) break main
(gdb) continue

2.3 方案三:UART(硬串口,最稳定的日志输出)

(ps:我没USB-TTL 串口模块所以没有尝试)

适合场景:USB 设备栈出问题时的备用日志通道、需要在 USB 枚举之前就看日志(早期启动日志)、稳定性要求高的长时间测试。

你需要准备

  • USB-TTL 串口模块(CH340、CP2102、FT232 均可),3.3V 电平(RP2350 IO 为 3.3V,不能接 5V TTL)。
  • 3 根杜邦线。

接线

USB-TTL 模块Pico 2 WH说明
TXGP1(Pin 2,UART0 RX)模块发,板子收
RXGP0(Pin 1,UART0 TX)板子发,模块收
GNDGND共地(必须)
3.3V3.3V(Pin 36)可选:为板子供电

⚠️ 注意:TX 接 RX,RX 接 TX(交叉连接)。共地是必须的,否则信号参考电平不一致会乱码。

Zephyr 配置(让 console 走 UART0 而非 USB):

CONFIG_UART_CONSOLE=y
CONFIG_CONSOLE=y

Linux 连接

ls /dev/ttyUSB*          # CH340/CP2102 一般是 ttyUSB0
picocom -b 115200 /dev/ttyUSB0

2.4 方案四:USB + UART 并用(日常开发推荐)

同时接 Micro-USB 和 USB-TTL,两者各司其职:

PC ──[Micro-USB]── Pico 2 WH ──[UART0: GP0/GP1]──[USB-TTL]── PC
  • Micro-USB:供电 + UF2 烧录
  • USB-TTL:日志/shell(独立于 USB 设备栈,固件崩溃仍能看到最后日志)

Zephyr 配置:

CONFIG_UART_CONSOLE=y       # 日志走 UART0
CONFIG_USB_DEVICE_STACK=y   # USB 仍然可用(HID、网络等)
CONFIG_USB_CDC_ACM=n        # 但不用 USB 做 console
CONFIG_SHELL=y
CONFIG_SHELL_BACKEND_SERIAL=y

2.5 方案五:Wi-Fi + TCP Shell(无线调试)

适合场景:板子已上电运行,不方便插线;远程日志采集;IoT 场景测试。

CONFIG_WIFI=y
CONFIG_NET_TCP=y
CONFIG_NET_IPV4=y
CONFIG_NET_DHCPV4=y
CONFIG_SHELL_BACKEND_TELNET=y

启动后通过 telnet 连接板子 IP 的 23 端口即可获得 shell。局限性:Wi-Fi 连接建立之前的早期日志不可见;网络异常时断开 shell;延迟高于 UART。


2.6 连接方式对比速查

方式成本额外硬件GDB 调试日志稳定性推荐场景
Micro-USB(CDC-ACM)入门、快速验证
SWD + PicoProbe低(多一块 Pico)单步调试、在线烧录
UART + USB-TTL低(~$3)最高稳定日志、早期启动
USB + UART 并用日常开发推荐
Wi-Fi TCP Shell零(软件)远程/无线场景

3. 除了开发板,还需要什么? {#3}

必选:

  • 质量靠谱的 Micro-USB 数据线:强调"数据线",充电线内部缺数据引脚。辨别方法:能传文件的线就能用。

强烈推荐:

  • 第二块 Pico(普通版即可) :刷成 PicoProbe 做 SWD 调试适配器,解锁 GDB 调试能力。约 $4,性价比极高。
  • USB-TTL 串口模块(3.3V,如 CP2102 或 CH340) :$2~3,提供最稳定的日志通道。
  • 面包板 + 杜邦线:接 SWD 和 UART 时用,不需要焊接。

可选:

  • USB Hub:避免电脑 USB 口电流不稳导致反复掉线。
  • 逻辑分析仪(如国产 LA2016 或 Saleae Logic) :分析 UART/SPI/I2C 信号,排查物理层问题。
  • 万用表:确认电压电平、检查接线正确性。

4. Zephyr OS:环境搭建与构建 {#4}

由于作者用的是Raspberry Pi Pico 2 WH,如果没有特别说明,后文操作默认是在Raspberry Pi Pico 2 WH,可能有些在其他板子上无法原样照做。

4.1 系统依赖

sudo apt update
sudo apt install -y git cmake ninja-build gperf ccache dfu-util \
  device-tree-compiler wget python3-pip python3-setuptools \
  python3-wheel xz-utils file make gcc gcc-multilib g++-multilib \
  libsdl2-dev libmagic1

4.2 安装 west 与初始化 workspace

pip3 install --user west
echo 'export PATH=$HOME/.local/bin:$PATH' >> ~/.bashrc
source ~/.bashrc

west init ~/zephyrproject --mr v4.4.0
cd ~/zephyrproject
west update
west zephyr-export
pip3 install --user -r zephyr/scripts/requirements.txt

4.3 安装 Zephyr SDK 1.0.1

cd ~
wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v1.0.1/zephyr-sdk-1.0.1_linux-x86_64.tar.xz
tar xf zephyr-sdk-1.0.1_linux-x86_64.tar.xz
cd zephyr-sdk-1.0.1
./setup.sh -t arm-zephyr-eabi -h -c

4.4 环境变量

建议写入项目专用的 env.sh

cat > ~/zephyrproject/env.sh << 'EOF'
export ZEPHYR_TOOLCHAIN_VARIANT=zephyr
export ZEPHYR_SDK_INSTALL_DIR=~/zephyr-sdk-1.0.1
export WEST_PYTHON=/usr/bin/python3.12
export PATH=$HOME/.local/bin:$PATH
EOF

source ~/zephyrproject/env.sh

提示:多项目切换时用 env.sh 隔离版本,比写死到 ~/.bashrc 更灵活。


5. Zephyr OS:Hello World 烧录验证 {#5}

5.1 构建

cd ~/zephyrproject && source env.sh

west build \
  -b rpi_pico2/rp2350a/m33/w \
  -s zephyr/samples/hello_world \
  -d build-hello-pico2 \
  -p auto

5.2 烧录(UF2 拖拽)

# 按住 BOOTSEL → 插 USB → 弹出 RPI-RP2
cp build-hello-pico2/zephyr/zephyr.uf2 /media/$USER/RPI-RP2/

(ps:真的是非常非常非常方便,特别是和其他对比)

5.3 查看输出

picocom -b 115200 /dev/ttyACM0
# *** Booting Zephyr OS build v4.4.0-... ***
# Hello World! rpi_pico2

5.4 QEMU 模拟运行(无需硬件)

west build -b qemu_x86_64 -s zephyr/samples/hello_world -d build-qemu -p auto
west build -d build-qemu -t run
# Hello World! qemu_x86_64
# Ctrl+A, X 退出 QEMU

5.5 QEMU vs native_sim 选哪个?

特性qemu_x86_64native_sim
启动速度较慢(~2s)极快(<0.1s)
MMU / 用户空间支持不支持
GDB 调试支持支持(直接 gdb)
AddressSanitizer
适合场景内存安全、系统调用类复现协议/逻辑类复现、ASAN

6. Zephyr OS:构建带 LLEXT 的定制固件 {#6}

LLEXT(Linkable Loadable Extensions)是 Zephyr 的动态可加载扩展框架,支持运行时加载 ELF 格式模块。

6.1 配置文件

prj.conf

# USB CDC ACM console/shell
CONFIG_USB_DEVICE_STACK=y
CONFIG_USB_CDC_ACM=y
CONFIG_UART_LINE_CTRL=y

# Shell + 日志
CONFIG_SHELL=y
CONFIG_SHELL_BACKEND_SERIAL=y
CONFIG_LOG=y
CONFIG_LOG_DEFAULT_LEVEL=3

# LLEXT
CONFIG_LLEXT=y
CONFIG_LLEXT_SHELL=y
CONFIG_LLEXT_HEAP_SIZE=32

# Wi-Fi
CONFIG_WIFI=y
CONFIG_WIFI_SHELL=y
CONFIG_NET_L2_WIFI_MGMT=y
CONFIG_NET_IPV4=y
CONFIG_NET_DHCPV4=y

6.2 拉取 Wi-Fi blobs

west blobs fetch hal_infineon

6.3 一键构建脚本

cd /home/zyf/zafl/pico2
WIFI_SSID='your_ssid' WIFI_PSK='your_psk' ./build_pico2wh_wifi_llext_uf2.sh

脚本自动完成:初始化 workspace → 下载 SDK → west update → fetch blobs → 写 overlay → 构建 UF2。

6.4 验证

picocom -b 115200 /dev/ttyACM0

uart:~$ wifi connect -s "your_ssid" -p "your_psk" -k 1
uart:~$ wifi status      # 看到 DHCP IP + COMPLETED 状态
uart:~$ llext help       # 看到 llext 命令组
uart:~$ llext list

⚠️ 安全提示:Wi-Fi 凭据会明文嵌入 Flash,可被 strings firmware.bin 直接提取。生产环境请勿使用此方式。


7. FreeRTOS:环境搭建与烧录 {#7}

FreeRTOS 是嵌入式领域使用最广泛的 RTOS。与 Zephyr 的构建体系不同,FreeRTOS 的 Pico 支持通过 Pico SDK + CMake 提供。

7.1 安装 Pico SDK

sudo apt install -y cmake gcc-arm-none-eabi libnewlib-arm-none-eabi \
  build-essential libstdc++-arm-none-eabi-newlib

git clone https://github.com/raspberrypi/pico-sdk.git ~/pico-sdk
cd ~/pico-sdk && git submodule update --init

echo 'export PICO_SDK_PATH=~/pico-sdk' >> ~/.bashrc
source ~/.bashrc

7.2 获取 FreeRTOS Kernel

FreeRTOS-Kernel 的 SMP 分支支持 RP2350 双核:

git clone https://github.com/FreeRTOS/FreeRTOS-Kernel.git ~/freertos-kernel
cd ~/freertos-kernel && git checkout V11.1.0

7.3 Hello World 示例

项目结构:

freertos-hello/
├── CMakeLists.txt
├── FreeRTOSConfig.h
└── main.c

CMakeLists.txt

cmake_minimum_required(VERSION 3.13)

include($ENV{PICO_SDK_PATH}/external/pico_sdk_import.cmake)

set(FREERTOS_KERNEL_PATH $ENV{HOME}/freertos-kernel)
include(${FREERTOS_KERNEL_PATH}/portable/ThirdParty/GCC/RP2350_ARM_NTZ/FreeRTOS_Kernel_import.cmake)

project(freertos_hello C CXX ASM)
set(CMAKE_C_STANDARD 11)
pico_sdk_init()

add_executable(freertos_hello main.c)

target_link_libraries(freertos_hello
    pico_stdlib
    FreeRTOS-Kernel
    FreeRTOS-Kernel-Heap4
)

pico_enable_stdio_usb(freertos_hello 1)
pico_enable_stdio_uart(freertos_hello 0)
pico_add_extra_outputs(freertos_hello)

FreeRTOSConfig.h(最小配置):

#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H

#define configUSE_PREEMPTION                    1
#define configCPU_CLOCK_HZ                      150000000
#define configTICK_RATE_HZ                      1000
#define configMAX_PRIORITIES                    5
#define configMINIMAL_STACK_SIZE                128
#define configTOTAL_HEAP_SIZE                   (128 * 1024)
#define configMAX_TASK_NAME_LEN                 16
#define configUSE_16_BIT_TICKS                  0
#define configIDLE_SHOULD_YIELD                 1
#define configUSE_MUTEXES                       1
#define configUSE_SEMAPHORES                    1
#define configUSE_TIMERS                        1
#define configTIMER_TASK_PRIORITY               (configMAX_PRIORITIES - 1)
#define configTIMER_QUEUE_LENGTH                10
#define configTIMER_TASK_STACK_DEPTH            256
#define configSUPPORT_DYNAMIC_ALLOCATION        1
#define configNUM_CORES                         2   /* RP2350 双核 SMP */

/* 调试:栈溢出检测 */
#define configCHECK_FOR_STACK_OVERFLOW          2
#define configUSE_MALLOC_FAILED_HOOK            1

#include <assert.h>
#define configASSERT(x) assert(x)

#define INCLUDE_vTaskDelay                      1
#define INCLUDE_vTaskDelete                     1
#define INCLUDE_xTaskGetCurrentTaskHandle       1

#endif

main.c

#include <stdio.h>
#include "pico/stdlib.h"
#include "FreeRTOS.h"
#include "task.h"

void task_hello(void *params) {
    (void)params;
    uint32_t count = 0;
    while (1) {
        printf("[Core %u] Hello from FreeRTOS! count=%lu\n",
               get_core_num(), count++);
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

void task_ping(void *params) {
    (void)params;
    while (1) {
        printf("[Core %u] Ping\n", get_core_num());
        vTaskDelay(pdMS_TO_TICKS(500));
    }
}

int main(void) {
    stdio_init_all();
    sleep_ms(2000);  /* 等待 USB CDC 枚举完成 */
    printf("FreeRTOS on Pico 2 WH (RP2350) starting...\n");

    xTaskCreate(task_hello, "Hello", 256, NULL, 1, NULL);
    xTaskCreate(task_ping,  "Ping",  256, NULL, 1, NULL);

    vTaskStartScheduler();
    for (;;) {}
}

7.4 构建与烧录

mkdir -p ~/freertos-hello/build && cd ~/freertos-hello/build
cmake .. -DPICO_BOARD=pico2_w
make -j$(nproc)

# BOOTSEL 模式烧录
cp freertos_hello.uf2 /media/$USER/RPI-RP2/

7.5 查看输出

picocom -b 115200 /dev/ttyACM0
# FreeRTOS on Pico 2 WH (RP2350) starting...
# [Core 0] Hello from FreeRTOS! count=0
# [Core 0] Ping
# [Core 0] Hello from FreeRTOS! count=1

7.6 FreeRTOS + Wi-Fi(CYW43)

target_link_libraries(freertos_hello
    pico_stdlib
    pico_cyw43_arch_lwip_freertos   # CYW43 + lwIP + FreeRTOS 集成
    FreeRTOS-Kernel
    FreeRTOS-Kernel-Heap4
)
#include "pico/cyw43_arch.h"

cyw43_arch_init();
cyw43_arch_enable_sta_mode();
cyw43_arch_wifi_connect_timeout_ms("SSID", "PSK",
    CYW43_AUTH_WPA2_AES_PSK, 30000);
printf("IP: %s\n", ip4addr_ntoa(netif_ip4_addr(netif_default)));

8. RT-Thread:环境搭建与烧录 {#8}

RT-Thread 是国内主流 RTOS,文档和社区资源中文为主,对 RP2040 有完整支持,RP2350 支持也在持续完善中。

8.1 安装工具链

# 系统依赖
sudo apt install -y python3-pip scons
pip3 install --user kconfiglib

# ARM 工具链(推荐从 ARM 官网下载最新版)
wget "https://developer.arm.com/-/media/Files/downloads/gnu/13.3.rel1/binrel/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi.tar.xz"
tar xf arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi.tar.xz -C ~/
echo 'export PATH=~/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi/bin:$PATH' >> ~/.bashrc
source ~/.bashrc

8.2 克隆 RT-Thread 主仓库

git clone https://github.com/RT-Thread/rt-thread.git ~/rt-thread
cd ~/rt-thread && git checkout v5.2.0

8.3 进入 BSP 目录

cd ~/rt-thread/bsp/raspberrypi-pico

注意:截至本文写作时,RT-Thread 对 RP2350 的支持仍在积极开发中。建议先在 raspberrypi-pico(RP2040)BSP 上验证流程,再迁移到 RP2350 BSP。

8.4 配置内核(menuconfig)

scons --menuconfig

图形化菜单中可以启用/关闭组件(空格选中,/ 搜索,S 保存,Q 退出)。

或者直接编辑 rtconfig.h(等价于 Zephyr 的 prj.conf):

#define RT_NAME_MAX          8
#define RT_ALIGN_SIZE        4
#define RT_THREAD_PRIORITY_MAX 32
#define RT_TICK_PER_SECOND   1000
#define RT_USING_OVERFLOW_CHECK       /* 栈溢出检测 */
#define RT_USING_CONSOLE
#define RT_CONSOLEBUF_SIZE   128
#define RT_CONSOLE_DEVICE_NAME "uart0"
#define RT_USING_FINSH                /* 启用 FinSH shell */
#define FINSH_THREAD_STACK_SIZE 4096

8.5 构建

export RTT_EXEC_PATH=~/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi/bin
scons -j$(nproc)

构建产物:

rtthread.uf2   # 直接拖拽烧录
rtthread.elf   # 用于 GDB 调试
rtthread.bin   # 二进制镜像

如果 scons 没有自动生成 UF2:

pip3 install --user uf2conv
uf2conv rtthread.bin --base 0x10000000 --family RP2350 -o rtthread.uf2

8.6 烧录与验证

cp rtthread.uf2 /media/$USER/RPI-RP2/

RT-Thread 默认走硬件 UART,需要 USB-TTL 模块(接 GP0/GP1):

picocom -b 115200 /dev/ttyUSB0

预期看到:

 \ | /
- RT -     Thread Operating System
 / | \     5.2.0 build ...
 2006 - 2024 Copyright by RT-Thread team
msh >

8.7 FinSH 常用命令

msh > help       # 所有命令列表
msh > ps         # 查看线程列表(类似 Linux ps)
msh > free       # 查看内存使用
msh > date       # 查看系统时间
msh > reboot     # 重启

8.8 RT-Thread Studio(图形化 IDE,可选)

RT-Thread 提供官方 IDE,内置工具链管理、图形化 menuconfig、一键烧录:

# 从 https://www.rt-thread.org/studio.html 下载 Linux 版
chmod +x rtthread-studio-*.run
./rtthread-studio-*.run

适合不喜欢命令行的初次上手用户。


9. 三套 RTOS 横向对比 {#9}

9.1 基本特性对比

维度Zephyr OSFreeRTOSRT-Thread
开源协议Apache 2.0MITApache 2.0
主要维护方Linux FoundationAmazon AWSRT-Thread 团队
构建系统west + CMake + KconfigCMake / MakeSCons + Kconfig
社区语言英文为主英文为主中文为主
Pico 2 成熟度★★★★★★★★★★★★★☆(RP2350 完善中)
内核大小(最小)~20KB~6KB~8KB
上手难度高(配置复杂)低(API 简单)

9.2 功能生态对比

特性ZephyrFreeRTOSRT-Thread
USB 设备栈✅ TinyUSB✅ TinyUSB✅ CherryUSB
TCP/IP 协议栈✅ LwIP / 原生✅ LwIP / FreeRTOS+TCP✅ LwIP
Wi-Fi(CYW43)✅(west blobs)✅(Pico SDK 内置)⚠️ 需手动移植
动态加载✅ LLEXT✅ 模块系统
TrustZone 支持⚠️ 有限⚠️ 通过 TF-M⚠️ 实验性
Shell✅ Zephyr Shell⚠️ 需第三方✅ FinSH
OTA 支持✅ MCUboot✅ MCUboot✅ OTA 框架

9.3 安全研究视角对比

攻击面ZephyrFreeRTOSRT-Thread
内存隔离MPU + 用户空间(目标相关)MPU(可选)MPU(可选)
动态加载✅ LLEXT✅ 模块系统
网络协议栈LwIP(复杂攻击面)LwIP / FreeRTOS+TCPLwIP
CVE 历史数量较多(功能复杂)中等较少(曝光度低)
PoC 资料丰富度最丰富丰富较少

9.4 如何选择?

  • 做安全研究/漏洞复现:优先 Zephyr,CVE 多、PoC 资料丰富、LLEXT 动态加载是独特攻击面。
  • 快速验证嵌入式逻辑:选 FreeRTOS,API 简单、文档清晰、Pico SDK 集成完善。
  • 中文资料/国内场景/IoT 设备逆向:选 RT-Thread,中文文档完整、FinSH 好用、国内 IoT 设备大量使用。

10. 多 RTOS 共存与切换烧录策略 {#10}

同一块 Pico 2 随时可以切换 RTOS,关键在于管理好 UF2 文件。

10.1 归档目录结构

firmware/
├── zephyr/
│   ├── hello_world_v4.4.0.uf2
│   ├── llext_poc_4f2e635.uf2
│   └── wifi_shell_latest.uf2
├── freertos/
│   ├── hello_v11.1.0.uf2
│   └── wifi_demo.uf2
└── rtthread/
    ├── hello_v5.2.0.uf2
    └── finsh_demo.uf2

10.2 快速切换脚本

#!/bin/bash
# flash.sh - 快速烧录指定 UF2
# 用法: ./flash.sh firmware/zephyr/hello_world_v4.4.0.uf2

UF2=$1
MOUNT_POINT="/media/$USER/RPI-RP2"

[ -z "$UF2" ] && echo "用法: $0 <path-to-uf2>" && exit 1

echo "等待 RPI-RP2 挂载(请按住 BOOTSEL 并重新插 USB)..."
while [ ! -d "$MOUNT_POINT" ]; do sleep 0.5; done

echo "正在烧录 $UF2 ..."
cp "$UF2" "$MOUNT_POINT/" && echo "完成,等待重启..." && sleep 2

10.3 使用 OpenOCD 在线烧录(无需 BOOTSEL)

openocd -f interface/cmsis-dap.cfg \
        -f target/rp2350.cfg \
        -c "adapter speed 5000" \
        -c "program build/zephyr/zephyr.bin verify reset exit 0x10000000"

优势:无需拔插 USB;速度比 UF2 拖拽快;可在 CI/CD pipeline 中自动化。


11. 调试进阶:GDB、OpenOCD、逻辑分析仪 {#11}

11.1 Zephyr + west debug

# 终端一:启动调试服务器
west debugserver -d build-hello-pico2

# 终端二:连接 GDB
west attach -d build-hello-pico2

11.2 常用 GDB 命令速查

info threads              # 查看所有线程(Zephyr 任务)
thread 2                  # 切换到线程 2
bt                        # 打印调用栈
info registers            # 查看寄存器
x/16xb 0x20000000         # 以 hex 查看内存

break ext2_fetch_direntry # 函数断点
break fs.c:123            # 行断点
watch *0x20001234         # 硬件观察点(内存写触发)
rwatch *0x20001234        # 读观察点

continue / step / next / finish

11.3 RTT(Real-Time Transfer)日志

RTT 通过 SWD 传输日志,不占用 UART 或 USB,延迟极低。

Zephyr 配置:

CONFIG_LOG=y
CONFIG_USE_SEGGER_RTT=y
CONFIG_LOG_BACKEND_RTT=y
CONFIG_RTT_CONSOLE=y

通过 OpenOCD + telnet 查看:

telnet localhost 4444
> rtt setup 0x20000000 0x10000 "SEGGER RTT"
> rtt start
> rtt server start 1234 0
# 新终端:nc localhost 1234

11.4 逻辑分析仪排查物理层问题

当怀疑 UART/SPI/I2C 信号有问题时,逻辑分析仪是最直接的工具。

推荐工具:

  • 国产 LA2016(~$30,配合 PulseView 使用,性价比高)
  • Saleae Logic(贵但体验好,Logic 2 软件免费)
  • PicoProbe 本身(支持 sigrok 协议,可当简单逻辑分析仪用)

典型应用场景:

  • 验证 UART 波特率是否正确
  • 排查 SPI CS 信号是否正常拉低
  • 确认 CYW43 SPI 总线通信是否正常

12. 固件安全审计:通用技巧 {#12}

12.1 从 UF2/BIN 提取信息

pip3 install uf2conv binwalk

# UF2 转 BIN
uf2conv -c -o firmware.bin firmware.uf2

# 基本信息 + 敏感字符串搜索
file firmware.bin
strings firmware.bin | grep -Ei "(ssid|psk|password|key|token|secret)"

# binwalk 分析
binwalk -e firmware.bin   # 提取嵌入文件系统
binwalk -A firmware.bin   # 识别 CPU 架构
binwalk -W firmware.bin   # 熵分析(高熵 = 加密/压缩)

12.2 符号表与危险函数定位

Zephyr 调试构建保留完整符号,对审计非常有帮助:

# 查找危险函数
arm-none-eabi-nm build/zephyr/zephyr.elf | grep -E "(strcpy|sprintf|gets|memcpy)"

# 反汇编特定函数
arm-none-eabi-objdump -d build/zephyr/zephyr.elf | grep -A 40 "<ext2_fetch_direntry>"

# 查看内存布局
arm-none-eabi-objdump -h build/zephyr/zephyr.elf
arm-none-eabi-size build/zephyr/zephyr.elf

12.3 Flash 明文凭据检查

这是嵌入式固件最常见的安全问题:

strings firmware.bin | grep -E ".{8,}"

常见敏感信息:Wi-Fi 密码、MQTT broker 凭据、API Key / Token、硬编码默认密码。

12.4 ASAN + native_sim 发现内存漏洞

west build -b native_sim -s <poc_dir> -d build-asan -- \
  -DCONFIG_ASAN=y

./build-asan/zephyr/zephyr.exe
# ASAN 在 OOB 读写时立即报告,无需硬件

13. 常见问题与排查 {#13}

Q1:west blobs fetch 报网络错误

export https_proxy=http://127.0.0.1:7890
west blobs fetch hal_infineon

Q2:构建报错 ARCH_HAS_USERSPACE=n

rpi_pico2 不支持 CONFIG_USERSPACE,改用 QEMU:

west build -b qemu_x86_64 -s <poc_dir> -d build-qemu

Q3:烧录后 Windows 没有弹出 COM 口

确认是数据线(非充电线);检查 CONFIG_USB_CDC_ACM=y;设备管理器查看是否有感叹号(缺驱动)。

Q4:plink 方向键乱码

改用 PuTTY GUI(Serial 模式,115200, 8-N-1)。

Q5:Flash 溢出(region FLASH overflowed

CONFIG_LLEXT_HEAP_SIZE=16    # 减小堆
CONFIG_WIFI_SHELL=n          # 关闭不需要的 shell
CONFIG_SIZE_OPTIMIZATIONS=y  # 启用尺寸优化

Q6:FreeRTOS 找不到 FreeRTOS_Kernel_import.cmake

ls ~/freertos-kernel/portable/ThirdParty/GCC/RP2350_ARM_NTZ/
# 如果没有 RP2350 目录:
cd ~/freertos-kernel && git pull && git checkout main

Q7:RT-Thread scons 找不到编译器

which arm-none-eabi-gcc   # 确认在 PATH 里
export RTT_EXEC_PATH=/usr/bin
scons -j$(nproc)

Q8:SWD 连接失败(SWDIO/TMS = 0

检查:接线正确性(SWDIO→SWDIO,SWDCLK→SWDCLK);是否共地;目标板是否上电;尝试降低 SWD 速率 -c "adapter speed 1000"

Q9:QEMU 运行 Zephyr 无输出

CONFIG_UART_CONSOLE=y   # 确保走 UART 而非 USB CDC

或者改用 native_sim(输出直接到终端):

west build -b native_sim -s <poc_dir> -d build-native
./build-native/zephyr/zephyr.exe

14. 经验总结 {#14}

关于工作流:

  • QEMU/native_sim 优先,硬件只做最终验证。native_sim 启动最快,qemu_x86_64 支持 MPU/用户空间,两者各有适用场景。
  • 固定全部版本:Python、west、SDK、RTOS revision 四者一旦固定,跨机器复现性大幅提升。用 env.sh + README 记录。
  • 所有配置进 overlayprj.conf + overlay.conf,不要用临时 -D 参数。git commit 一个配置就能复现完整构建。

关于连接方式:

  • 日常开发推荐:Micro-USB + USB-TTL 并用。USB 烧录,UART 日志。UART 独立于 USB 设备栈,固件崩溃仍能看到最后日志。
  • 做 GDB 调试一定要配 PicoProbe。多花一块 Pico 的成本(~$4),换来单步调试能力,性价比极高。

关于安全审计:

  • Flash 明文检查是第一步strings firmware.bin 往往直接找到密码、密钥、URL。
  • 保留符号表做静态分析nm + objdump 快速定位危险函数调用链。
  • ASAN + native_sim 是发现内存漏洞的利器:比在硬件上反复刷固件高效得多。

关于 Windows 体验:

  • 推荐 PuTTY GUI:方向键、历史记录、粘贴体验远好于 plink
  • 日志抓取推荐 MobaXterm:支持同时管理多个串口连接,可自动保存日志到文件。

15. 附录 {#15}

一键构建脚本(Zephyr)(可能部分是针对我的环境的,复用前最好自己看一遍或者让AI看一遍)

#!/usr/bin/env bash
#
# Build Zephyr UF2 for Raspberry Pi Pico 2 W/WH (rpi_pico2/rp2350a/m33/w)
# Features: WiFi (CYW43 / AIROC), LLEXT + LLEXT shell, USB CDC ACM shell/console.
#
# This script is intended to be copy-pasted to a fresh Linux environment.
# It performs:
#  - dependency checks (optionally installs via apt if available)
#  - west init/update
#  - Zephyr SDK download (v1.0.1) + toolchain setup
#  - required Infineon blobs fetch
#  - small Zephyr CMake patch for WEST_PYTHON environment propagation
#  - builds a UF2 under zephyrproject/build-pico2wh-usb-wifi-llext/zephyr/zephyr.uf2
#
# Usage:
#   WIFI_SSID="..." WIFI_PSK="..." ./build_pico2wh_wifi_llext_uf2.sh
#
# Notes:
#  - Zephyr in this workspace requires Python >= 3.12.
#  - WiFi credentials are embedded in the build output via an overlay file.
#
set -euo pipefail

ROOT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
WORK_DIR="${ROOT_DIR}/zephyrproject"
SDK_VER="1.0.1"
SDK_DIR="${ROOT_DIR}/zephyr-sdk-${SDK_VER}"
SDK_TARBALL="${ROOT_DIR}/zephyr-sdk-${SDK_VER}_linux-x86_64_gnu.tar.xz"
SDK_URL="https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v${SDK_VER}/zephyr-sdk-${SDK_VER}_linux-x86_64_gnu.tar.xz"

BOARD="rpi_pico2/rp2350a/m33/w"
APP_REL="zephyr/samples/net/wifi/shell"
BUILD_DIR="${WORK_DIR}/build-pico2wh-usb-wifi-llext"

ZEPHYR_REV_DEFAULT="808a0d08c68917c4ed7692e7e528daba180e375b"
# Desired Zephyr revision (commit SHA, tag, or branch). We always `west init`
# from a branch and then checkout this revision explicitly to support SHA pins.
ZEPHYR_REV="${ZEPHYR_REV:-${ZEPHYR_REV_DEFAULT}}"
ZEPHYR_INIT_REF="${ZEPHYR_INIT_REF:-main}"

OVERLAYS_DIR="${WORK_DIR}/overlays"
OVERLAY_WIFI_LLEXT="${OVERLAYS_DIR}/pico2wh_wifi_llext.conf"
OVERLAY_WIFI_SECRETS="${OVERLAYS_DIR}/pico2wh_wifi_secrets.conf"
OVERLAY_USB_SHELL="${OVERLAYS_DIR}/pico2wh_usb_shell.conf"
OVERLAY_USB_DTS="${OVERLAYS_DIR}/pico2wh_usb_cdc_acm.overlay"

PYTHON_BIN="${PYTHON_BIN:-python3.12}"
WEST_BIN="${WEST_BIN:-west}"

WIFI_SSID="${WIFI_SSID:-}"
WIFI_PSK="${WIFI_PSK:-}"
INSTALL_DEPS="${INSTALL_DEPS:-0}"
USE_VENV="${USE_VENV:-1}"

log() { printf '[%s] %s\n' "$(date -u +'%Y-%m-%dT%H:%M:%SZ')" "$*" >&2; }
die() { log "ERROR: $*"; exit 1; }

acquire_lock() {
  # Prevent accidental concurrent runs in the same workspace, which can leave
  # .git/index.lock files behind during `west update`.
  local lock_dir="${ROOT_DIR}/.build-lock"
  mkdir -p "${lock_dir}"
  local lock_file="${lock_dir}/pico2wh.lock"

  if command -v flock >/dev/null 2>&1; then
    # Hold an exclusive lock for the lifetime of this process.
    exec 9>"${lock_file}"
    flock -n 9 || die "Another build is running (lock: ${lock_file})"
  else
    # Best-effort fallback if flock isn't available.
    if ( set -o noclobber; : >"${lock_file}" ) 2>/dev/null; then
      trap 'rm -f "${lock_file}"' EXIT
    else
      die "Another build is running (lock: ${lock_file})"
    fi
  fi
}

need_cmd() {
  command -v "$1" >/dev/null 2>&1 || die "Missing command: $1"
}

maybe_install_deps_apt() {
  if [[ "${INSTALL_DEPS}" != "1" ]]; then
    log "INSTALL_DEPS!=1; skipping apt dependency installation."
    return 0
  fi

  if command -v apt-get >/dev/null 2>&1; then
    log "apt-get detected; installing build dependencies (requires sudo)..."
    sudo apt-get update
    sudo apt-get install -y \
      git cmake ninja-build gperf wget xz-utils file \
      python3-pip python3-venv \
      libsdl2-dev \
      device-tree-compiler
  else
    log "apt-get not found; skipping dependency installation."
    log "You need: git cmake ninja gperf wget xz dtc + Python>=3.12 + pip."
  fi
}

ensure_python() {
  command -v "${PYTHON_BIN}" >/dev/null 2>&1 || die "Python >= 3.12 required; set PYTHON_BIN or install python3.12"
  "${PYTHON_BIN}" - <<'PY' || die "Python version check failed"
import sys
maj, min = sys.version_info[:2]
assert (maj, min) >= (3, 12), sys.version
print(sys.version)
PY
}

maybe_setup_venv() {
  if [[ "${USE_VENV}" != "1" ]]; then
    log "USE_VENV!=1; using system/user python environment."
    return 0
  fi

  local venv_dir="${WORK_DIR}/.venv"
  if [[ ! -d "${venv_dir}" ]]; then
    log "Creating venv: ${venv_dir}"
    mkdir -p "${WORK_DIR}"
    "${PYTHON_BIN}" -m venv "${venv_dir}"
  fi

  # shellcheck disable=SC1090
  source "${venv_dir}/bin/activate"
  log "Using venv python: $(python -c 'import sys; print(sys.executable)')"
}

ensure_west() {
  if ! command -v "${WEST_BIN}" >/dev/null 2>&1; then
    log "west not found; installing to user site via pip..."
    python -m pip install -U west
  fi
  "${WEST_BIN}" --version
}

ensure_zephyr_checkout() {
  if [[ -d "${WORK_DIR}/.west" ]]; then
    log "Zephyr workspace already exists: ${WORK_DIR}"
    return 0
  fi

  log "Initializing Zephyr workspace with west..."
  mkdir -p "${WORK_DIR}"
  cd "${WORK_DIR}"
  log "west init from ref: ${ZEPHYR_INIT_REF}"
  "${WEST_BIN}" init -m https://github.com/zephyrproject-rtos/zephyr --mr "${ZEPHYR_INIT_REF}" .
}

west_update_and_requirements() {
  cd "${WORK_DIR}"

  # Pin Zephyr manifest repo (zephyr/) to requested revision before `west update`
  # so the manifest (west.yml) matches the exact checkout.
  log "Checking out Zephyr revision: ${ZEPHYR_REV}"
  git -C zephyr fetch --tags --force origin
  git -C zephyr checkout --detach "${ZEPHYR_REV}"

  if find modules tools bootloader zephyr -path '*/.git/index.lock' -print -quit 2>/dev/null | grep -q .; then
    die "Found a stale .git/index.lock (likely from an interrupted west update). Remove it and re-run."
  fi

  log "west update (this can take a while)..."
  "${WEST_BIN}" update

  log "Installing Zephyr Python requirements..."
  python -m pip install -U pip
  python -m pip install -r zephyr/scripts/requirements.txt
}

ensure_sdk() {
  if [[ -d "${SDK_DIR}" ]]; then
    log "Zephyr SDK already present: ${SDK_DIR}"
    return 0
  fi

  log "Downloading Zephyr SDK v${SDK_VER}..."
  if [[ ! -f "${SDK_TARBALL}" ]]; then
    wget -O "${SDK_TARBALL}" "${SDK_URL}"
  fi

  log "Extracting Zephyr SDK..."
  tar -xf "${SDK_TARBALL}" -C "${ROOT_DIR}"
  [[ -d "${SDK_DIR}" ]] || die "SDK extraction failed; expected ${SDK_DIR}"
}

patch_zephyr_python_cmake() {
  # Zephyr's cmake -P scripts don't always receive WEST_PYTHON as a CMake var.
  # This patch makes python.cmake also honor environment variable WEST_PYTHON.
  local f="${WORK_DIR}/zephyr/cmake/modules/python.cmake"
  [[ -f "${f}" ]] || die "Missing file: ${f}"

  if grep -q 'ENV{WEST_PYTHON}' "${f}"; then
    log "python.cmake already patched."
    return 0
  fi

  log "Patching: ${f}"
  PY_CMAKE_FILE="${f}" "${PYTHON_BIN}" - <<'PY'
from pathlib import Path
import os
path = Path(os.environ["PY_CMAKE_FILE"])
txt = path.read_text()
needle = 'if(NOT DEFINED Python3_EXECUTABLE AND DEFINED WEST_PYTHON)\\n  set(Python3_EXECUTABLE \"${WEST_PYTHON}\")\\nendif()\\n'
if needle not in txt:
    raise SystemExit("Unexpected python.cmake contents; patch refused")
insert = needle + '\\nif(NOT DEFINED Python3_EXECUTABLE AND DEFINED ENV{WEST_PYTHON})\\n  set(Python3_EXECUTABLE \"\$ENV{WEST_PYTHON}\")\\nendif()\\n'
txt = txt.replace(needle, insert)
path.write_text(txt)
print("patched ok")
PY
}

write_overlays() {
  mkdir -p "${OVERLAYS_DIR}"

  log "Writing overlays..."

  cat >"${OVERLAY_WIFI_LLEXT}" <<'EOF'
# WiFi shell sample + LLEXT shell commands (Pico 2 W/WH)
CONFIG_WIFI_CREDENTIALS=y

CONFIG_LLEXT=y
CONFIG_LLEXT_SHELL=y
CONFIG_LLEXT_IMPORT_ALL_GLOBALS=y
CONFIG_LLEXT_HEAP_SIZE=32
EOF

  if [[ -z "${WIFI_SSID}" || -z "${WIFI_PSK}" ]]; then
    die "Set WIFI_SSID and WIFI_PSK env vars before running (they are embedded into the build)."
  fi

  # Secrets overlay is intentionally separate.
  cat >"${OVERLAY_WIFI_SECRETS}" <<EOF
# WiFi credentials (static) - PLAINTEXT
CONFIG_WIFI_CREDENTIALS_STATIC=y
CONFIG_WIFI_CREDENTIALS_STATIC_SSID="${WIFI_SSID}"
CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="${WIFI_PSK}"
CONFIG_WIFI_CREDENTIALS_STATIC_TYPE_PSK=y
EOF

  cat >"${OVERLAY_USB_SHELL}" <<'EOF'
# Use USB CDC ACM (virtual COM port) for console/shell.
CONFIG_USB_DEVICE_STACK=y
CONFIG_USB_CDC_ACM=y
CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=y

# Avoid early banner prints before USB enumeration.
# CONFIG_BOOT_BANNER is not set
CONFIG_BOOT_DELAY=2000
EOF

  cat >"${OVERLAY_USB_DTS}" <<'EOF'
/ {
	chosen {
		zephyr,console = &cdc_acm_uart0;
		zephyr,shell-uart = &cdc_acm_uart0;
	};
};

&zephyr_udc0 {
	cdc_acm_uart0: cdc_acm_uart0 {
		compatible = "zephyr,cdc-acm-uart";
		label = "CDC_ACM_0";
	};
};
EOF
}

fetch_blobs() {
  # Required for the CYW43 WiFi firmware/CLM blobs (hal_infineon).
  cd "${WORK_DIR}"
  log "Fetching required blobs (hal_infineon)..."
  "${WEST_BIN}" blobs fetch hal_infineon || "${WEST_BIN}" blobs fetch
}

build_uf2() {
  cd "${WORK_DIR}"

  export ZEPHYR_SDK_INSTALL_DIR="${SDK_DIR}"
  export WEST_PYTHON="$(python -c 'import sys; print(sys.executable)')"

  # Ensure Zephyr env is set (ZEPHYR_BASE, etc.)
  # shellcheck disable=SC1091
  source zephyr/zephyr-env.sh

  log "Building UF2..."
  "${WEST_BIN}" build \
    -b "${BOARD}" \
    -d "${BUILD_DIR}" \
    "${APP_REL}" \
    -p always \
    -DOVERLAY_CONFIG="${OVERLAY_WIFI_LLEXT};${OVERLAY_WIFI_SECRETS};${OVERLAY_USB_SHELL}" \
    -DDTC_OVERLAY_FILE="${OVERLAY_USB_DTS}"

  [[ -f "${BUILD_DIR}/zephyr/zephyr.uf2" ]] || die "UF2 not found: ${BUILD_DIR}/zephyr/zephyr.uf2"
  log "UF2 ready: ${BUILD_DIR}/zephyr/zephyr.uf2"
}

main() {
  log "Root: ${ROOT_DIR}"
  acquire_lock

  need_cmd git
  need_cmd cmake
  need_cmd ninja
  need_cmd wget
  need_cmd tar
  need_cmd bash

  ensure_python
  maybe_setup_venv
  ensure_west

  maybe_install_deps_apt

  ensure_zephyr_checkout
  west_update_and_requirements
  ensure_sdk

  patch_zephyr_python_cmake
  write_overlays
  fetch_blobs
  build_uf2
}

main "$@"

工具版本速查

工具本文使用版本
Zephyrv4.4.0
Zephyr SDK1.0.1
FreeRTOS-KernelV11.1.0
RT-Threadv5.2.0
OpenOCD0.12.0(raspberrypi 分支)
Python3.12
arm-none-eabi-gcc13.3

参考资源