从零上手嵌入式 RTOS:以 Raspberry Pi Pico 2 WH 为例的烧录、定制构建与多系统对比指南
目标读者:第一次上手嵌入式 RTOS、想在真实硬件上做固件验证/代码审计/漏洞复现的安全研究者或嵌入式开发者。
说明:本文覆盖 Zephyr OS、FreeRTOS、RT-Thread 三套主流 RTOS 在 Raspberry Pi Pico 2 W/WH 上的环境搭建、构建与烧录流程,并系统梳理各种连接方式与调试手段。
作者也是小白,文中如有错误欢迎指正。
目录
- 为什么我选 Raspberry Pi Pico 2 WH
- 硬件连接方式全览
- 除了开发板,还需要什么?
- Zephyr OS:环境搭建与构建
- Zephyr OS:Hello World 烧录验证
- Zephyr OS:构建带 LLEXT 的定制固件
- FreeRTOS:环境搭建与烧录
- RT-Thread:环境搭建与烧录
- 三套 RTOS 横向对比
- 多 RTOS 共存与切换烧录策略
- 调试进阶:GDB、OpenOCD、逻辑分析仪
- 固件安全审计:通用技巧
- 常见问题与排查
- 经验总结
- 附录
1. 为什么我选 Raspberry Pi Pico 2 WH(RP2350) {#1}
两个词简述原因:便捷、便宜。
硬件规格速览
| 参数 | 规格 |
|---|---|
| 主控 | RP2350A |
| CPU | 双核 Cortex-M33 @ 150MHz(亦可切换为 RISC-V Hazard3) |
| SRAM | 520KB |
| Flash | 2MB(板载 QSPI) |
| Wi-Fi / BLE | CYW43439(Pico 2 W/WH) |
| GPIO | 26 个可用 GPIO,支持 PWM/I2C/SPI/UART/ADC |
| USB | USB 1.1 设备/主机模式 |
| 安全特性 | TrustZone-M,OTP,安全启动(可选) |
| 价格 | ~ <math xmlns="http://www.w3.org/1998/Math/MathML"> 7 U S D ( W 版), 7 USD(W 版),~ </math>7USD(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)。
css
PC ──[Micro-USB 数据线]── Pico 2 W/WH
工作原理:Pico 2 的 USB 控制器在 BOOTSEL 模式下枚举为 USB 大容量存储设备(MSC),固件运行时可枚举为 CDC-ACM(虚拟串口)、HID、RNDIS 等任意 USB 设备类。
操作步骤:
- 按住 BOOTSEL,插入 USB,电脑弹出
RPI-RP2U 盘。 - 拖入
.uf2文件,板子自动重启运行新固件。 - 固件运行后,设备管理器(Windows)或
ls /dev/ttyACM*(Linux)可见虚拟串口。
连接串口:
bash
# 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 固件下载:
ruby
wget https://github.com/raspberrypi/picoprobe/releases/latest/download/picoprobe.uf2
# 将这个 uf2 烧录到作为调试器的那块 Pico
接线方式(调试器 Pico → 目标 Pico 2 WH) :
| 调试器 Pico | 目标 Pico 2 WH | 说明 |
|---|---|---|
| GP2 | SWDCLK(Pin 24) | 时钟线 |
| GP3 | SWDIO(Pin 25) | 数据线 |
| GND | GND | 共地(必须) |
| GP4(TX) | GP1(UART0 RX) | 可选:转发 UART 日志 |
| GP5(RX) | GP0(UART0 TX) | 可选:转发 UART 日志 |
| VSYS | VSYS | 可选:为目标供电 |
scss
调试器 Pico 目标 Pico 2 WH
GP2 ────────────────────── SWDCLK
GP3 ────────────────────── SWDIO
GND ────────────────────── GND
GP4 ────────────────────── GP1 (UART RX) [可选]
GP5 ────────────────────── GP0 (UART TX) [可选]
安装 OpenOCD(支持 RP2350) :
bash
# 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 连接目标:
bash
openocd -f interface/cmsis-dap.cfg \
-f target/rp2350.cfg \
-c "adapter speed 5000"
看到以下输出说明连接成功:
yaml
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 调试:
bash
# 新开终端连接 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 | 说明 |
|---|---|---|
| TX | GP1(Pin 2,UART0 RX) | 模块发,板子收 |
| RX | GP0(Pin 1,UART0 TX) | 板子发,模块收 |
| GND | GND | 共地(必须) |
| 3.3V | 3.3V(Pin 36) | 可选:为板子供电 |
⚠️ 注意:TX 接 RX,RX 接 TX(交叉连接)。共地是必须的,否则信号参考电平不一致会乱码。
Zephyr 配置(让 console 走 UART0 而非 USB):
ini
CONFIG_UART_CONSOLE=y
CONFIG_CONSOLE=y
Linux 连接:
bash
ls /dev/ttyUSB* # CH340/CP2102 一般是 ttyUSB0
picocom -b 115200 /dev/ttyUSB0
2.4 方案四:USB + UART 并用(日常开发推荐)
同时接 Micro-USB 和 USB-TTL,两者各司其职:
css
PC ──[Micro-USB]── Pico 2 WH ──[UART0: GP0/GP1]──[USB-TTL]── PC
- Micro-USB:供电 + UF2 烧录
- USB-TTL:日志/shell(独立于 USB 设备栈,固件崩溃仍能看到最后日志)
Zephyr 配置:
ini
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 场景测试。
ini
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 系统依赖
go
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
bash
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
bash
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:
bash
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 构建
bash
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 拖拽)
bash
# 按住 BOOTSEL → 插 USB → 弹出 RPI-RP2
cp build-hello-pico2/zephyr/zephyr.uf2 /media/$USER/RPI-RP2/
(ps:真的是非常非常非常方便,特别是和其他对比)
5.3 查看输出
bash
picocom -b 115200 /dev/ttyACM0
# *** Booting Zephyr OS build v4.4.0-... ***
# Hello World! rpi_pico2
5.4 QEMU 模拟运行(无需硬件)
bash
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_64 |
native_sim |
|---|---|---|
| 启动速度 | 较慢(~2s) | 极快(<0.1s) |
| MMU / 用户空间 | 支持 | 不支持 |
| GDB 调试 | 支持 | 支持(直接 gdb) |
| AddressSanitizer | 否 | 是 |
| 适合场景 | 内存安全、系统调用类复现 | 协议/逻辑类复现、ASAN |
6. Zephyr OS:构建带 LLEXT 的定制固件 {#6}
LLEXT(Linkable Loadable Extensions)是 Zephyr 的动态可加载扩展框架,支持运行时加载 ELF 格式模块。
6.1 配置文件
prj.conf:
ini
# 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
sql
west blobs fetch hal_infineon
6.3 一键构建脚本
bash
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 验证
ruby
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
bash
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 双核:
bash
git clone https://github.com/FreeRTOS/FreeRTOS-Kernel.git ~/freertos-kernel
cd ~/freertos-kernel && git checkout V11.1.0
7.3 Hello World 示例
项目结构:
css
freertos-hello/
├── CMakeLists.txt
├── FreeRTOSConfig.h
└── main.c
CMakeLists.txt:
scss
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(最小配置):
arduino
#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:
arduino
#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 构建与烧录
bash
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 查看输出
css
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)
scss
target_link_libraries(freertos_hello
pico_stdlib
pico_cyw43_arch_lwip_freertos # CYW43 + lwIP + FreeRTOS 集成
FreeRTOS-Kernel
FreeRTOS-Kernel-Heap4
)
scss
#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 安装工具链
bash
# 系统依赖
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 主仓库
bash
git clone https://github.com/RT-Thread/rt-thread.git ~/rt-thread
cd ~/rt-thread && git checkout v5.2.0
8.3 进入 BSP 目录
bash
cd ~/rt-thread/bsp/raspberrypi-pico
注意 :截至本文写作时,RT-Thread 对 RP2350 的支持仍在积极开发中。建议先在
raspberrypi-pico(RP2040)BSP 上验证流程,再迁移到 RP2350 BSP。
8.4 配置内核(menuconfig)
css
scons --menuconfig
图形化菜单中可以启用/关闭组件(空格选中,/ 搜索,S 保存,Q 退出)。
或者直接编辑 rtconfig.h(等价于 Zephyr 的 prj.conf):
arduino
#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 构建
bash
export RTT_EXEC_PATH=~/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi/bin
scons -j$(nproc)
构建产物:
python
rtthread.uf2 # 直接拖拽烧录
rtthread.elf # 用于 GDB 调试
rtthread.bin # 二进制镜像
如果 scons 没有自动生成 UF2:
css
pip3 install --user uf2conv
uf2conv rtthread.bin --base 0x10000000 --family RP2350 -o rtthread.uf2
8.6 烧录与验证
bash
cp rtthread.uf2 /media/$USER/RPI-RP2/
RT-Thread 默认走硬件 UART,需要 USB-TTL 模块(接 GP0/GP1):
bash
picocom -b 115200 /dev/ttyUSB0
预期看到:
yaml
\ | /
- RT - Thread Operating System
/ | \ 5.2.0 build ...
2006 - 2024 Copyright by RT-Thread team
msh >
8.7 FinSH 常用命令
bash
msh > help # 所有命令列表
msh > ps # 查看线程列表(类似 Linux ps)
msh > free # 查看内存使用
msh > date # 查看系统时间
msh > reboot # 重启
8.8 RT-Thread Studio(图形化 IDE,可选)
RT-Thread 提供官方 IDE,内置工具链管理、图形化 menuconfig、一键烧录:
arduino
# 从 https://www.rt-thread.org/studio.html 下载 Linux 版
chmod +x rtthread-studio-*.run
./rtthread-studio-*.run
适合不喜欢命令行的初次上手用户。
9. 三套 RTOS 横向对比 {#9}
9.1 基本特性对比
| 维度 | Zephyr OS | FreeRTOS | RT-Thread |
|---|---|---|---|
| 开源协议 | Apache 2.0 | MIT | Apache 2.0 |
| 主要维护方 | Linux Foundation | Amazon AWS | RT-Thread 团队 |
| 构建系统 | west + CMake + Kconfig | CMake / Make | SCons + Kconfig |
| 社区语言 | 英文为主 | 英文为主 | 中文为主 |
| Pico 2 成熟度 | ★★★★★ | ★★★★★ | ★★★☆(RP2350 完善中) |
| 内核大小(最小) | ~20KB | ~6KB | ~8KB |
| 上手难度 | 高(配置复杂) | 低(API 简单) | 中 |
9.2 功能生态对比
| 特性 | Zephyr | FreeRTOS | RT-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 安全研究视角对比
| 攻击面 | Zephyr | FreeRTOS | RT-Thread |
|---|---|---|---|
| 内存隔离 | MPU + 用户空间(目标相关) | MPU(可选) | MPU(可选) |
| 动态加载 | ✅ LLEXT | ❌ | ✅ 模块系统 |
| 网络协议栈 | LwIP(复杂攻击面) | LwIP / FreeRTOS+TCP | LwIP |
| 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 归档目录结构
markdown
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 快速切换脚本
bash
#!/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)
bash
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
bash
# 终端一:启动调试服务器
west debugserver -d build-hello-pico2
# 终端二:连接 GDB
west attach -d build-hello-pico2
11.2 常用 GDB 命令速查
perl
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 配置:
ini
CONFIG_LOG=y
CONFIG_USE_SEGGER_RTT=y
CONFIG_LOG_BACKEND_RTT=y
CONFIG_RTT_CONSOLE=y
通过 OpenOCD + telnet 查看:
shell
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 提取信息
python
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 调试构建保留完整符号,对审计非常有帮助:
bash
# 查找危险函数
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 明文凭据检查
这是嵌入式固件最常见的安全问题:
perl
strings firmware.bin | grep -E ".{8,}"
常见敏感信息:Wi-Fi 密码、MQTT broker 凭据、API Key / Token、硬编码默认密码。
12.4 ASAN + native_sim 发现内存漏洞
ini
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 报网络错误
arduino
export https_proxy=http://127.0.0.1:7890
west blobs fetch hal_infineon
Q2:构建报错 ARCH_HAS_USERSPACE=n
rpi_pico2 不支持 CONFIG_USERSPACE,改用 QEMU:
css
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)
ini
CONFIG_LLEXT_HEAP_SIZE=16 # 减小堆
CONFIG_WIFI_SHELL=n # 关闭不需要的 shell
CONFIG_SIZE_OPTIMIZATIONS=y # 启用尺寸优化
Q6:FreeRTOS 找不到 FreeRTOS_Kernel_import.cmake
bash
ls ~/freertos-kernel/portable/ThirdParty/GCC/RP2350_ARM_NTZ/
# 如果没有 RP2350 目录:
cd ~/freertos-kernel && git pull && git checkout main
Q7:RT-Thread scons 找不到编译器
bash
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 无输出
ini
CONFIG_UART_CONSOLE=y # 确保走 UART 而非 USB CDC
或者改用 native_sim(输出直接到终端):
java
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记录。 - 所有配置进 overlay :
prj.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看一遍)
bash
#!/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 "$@"
工具版本速查
| 工具 | 本文使用版本 |
|---|---|
| Zephyr | v4.4.0 |
| Zephyr SDK | 1.0.1 |
| FreeRTOS-Kernel | V11.1.0 |
| RT-Thread | v5.2.0 |
| OpenOCD | 0.12.0(raspberrypi 分支) |
| Python | 3.12 |
| arm-none-eabi-gcc | 13.3 |