Zephyr 移植、测试与调试指南
1. 新板级移植的分层
1 | Architecture(通常复用) |
若芯片已有 SoC 支持,新板通常只需:
board.yml;- board
.dts; <board>_defconfig;- 可选 Kconfig、board.cmake、runner;
- pinctrl/connector 描述。
不要把应用策略和大量功能选项塞进 board defconfig;board 默认值应主要描述板上始终存在的硬件能力。
2. Board 移植步骤
- 选择最接近的现有 board;
- 确认 SoC、flash、SRAM 容量;
- 创建
board.yml; - include 正确 SoC/参考板
.dtsi/.dts; - 配置 clocks;
- 配置 console 和 pinctrl;
- 启用必要 GPIO/interrupt controller;
- 添加 aliases/chosen;
- 定义 flash partitions;
- 设置最小 defconfig;
- 编译
samples/hello_world; - 再依次验证 GPIO、UART、I2C/SPI、flash、watchdog;
- 添加 board test/CI allowlist。
3. 新 SoC 移植
除 DTS 外还需:
- SoC Kconfig;
- CMake/runner/toolchain 选择;
- reset/early init;
- clock control;
- interrupt controller;
- system timer;
- pinctrl;
- memory map/linker;
- cache/MPU/MMU;
- reboot、poweroff、SMP;
- HAL module glue。
优先把可复用寄存器操作放入 driver/HAL,把启动时序和 SoC 特有 glue 放入 soc/。
4. Driver 验证层次
- 编译期:无实例/单实例/多实例;
- init:依赖设备和错误返回;
- API 正常路径;
- 参数边界;
- interrupt/callback;
- timeout/abort;
- 并发;
- runtime PM;
- suspend/resume;
- fault injection:bus NACK、DMA error、设备掉线。
能编译不代表 DTS binding、pinctrl 和真实硬件时序正确。
5. Ztest
框架路径:
1 | subsys/testsuite/ztest/ |
典型:
1 | ZTEST_SUITE(suite, NULL, setup, before, after, teardown); |
支持:
- suite/test fixture;
- parameterized/generated tests;
- userspace tests;
- expected fail/skip;
- mock/fake;
- rules 和 test phases。
测试不应依赖执行顺序,fixture 应恢复全局状态。
6. Twister
Twister 读取 testcase.yaml:
1 | tests: |
作用:
- 构建矩阵;
- 运行 native/QEMU/硬件测试;
- 过滤 architecture、toolchain、RAM/flash;
- 解析 harness 输出;
- 生成报告和覆盖率。
常用:
1 | west twister -T tests/path |
对 board/driver 代码至少增加 compile-only 和一个可执行场景。
7. Native simulation 与 QEMU
native_sim:把 Zephyr 编译为 host process,适合内核/协议/单元测试;- QEMU:模拟 CPU、interrupt 和部分外设,更接近目标架构;
- unit testing architecture:隔离编译特定库;
- hardware map:Twister 管理真实板。
硬件相关问题仍需板上测试,尤其是 DMA、cache、flash 掉电和时钟。
8. 调试构建
常用配置:
1 | CONFIG_DEBUG=y |
调试功能会改变 timing、stack 和 image size。最终结论需在接近 release 的配置下复测。
9. GDB
1 | west debug -d build/<name> |
关键检查:
1 | info threads |
优化构建中变量可能被优化掉,必要时仅对问题文件降低优化,而不是长期全局 -O0。
10. 启动问题
无输出时按顺序:
- reset vector 是否到达;
- flash/link address 是否正确;
- clock 是否工作;
z_cstart()是否执行;- console device 是否 status okay;
- UART pinctrl/baud;
- console driver Kconfig;
- init function 返回值;
- logging backend 是否启动。
早期 PRE_KERNEL 问题优先用 GPIO、debugger 或 printk,logging 可能尚不可用。
11. Device init 问题
检查构建产物:
1 | rg '<node-name>|<compatible>' build/zephyr/zephyr.dts |
运行时:
device_is_ready();- init result;
- shell device list;
- dependency handles;
- clock/pinctrl/controller 状态。
12. HardFault/Fatal
记录:
- reason;
- exception stack frame;
- PC/LR/SP;
- current thread name;
- stack bounds;
- fault status registers;
- build ID/firmware version。
地址解析:
1 | addr2line -e build/zephyr/zephyr.elf -f -C <pc> |
必须使用与设备完全一致、未 strip 的 ELF。
13. Stack 分析
方法:
- thread analyzer;
k_thread_stack_space_get();- stack sentinel/canary;
- compiler stack usage 文件;
- map 和静态 call graph;
- 压力场景下 high-water mark。
分别评估:
- main stack;
- ISR stack;
- system workqueue;
- logging;
- shell;
- network RX/TX;
- 每个业务线程。
14. 性能与实时性
测量对象:
- ISR latency;
- ISR-to-thread latency;
- context switch;
- mutex contention;
- workqueue delay;
- timeout jitter;
- flash operation blocking;
- network tail latency。
使用 cycle counter、timing API、tracing/SystemView。避免在被测路径中大量 logging。
15. 内存分析
1 | west build -d build/<name> -t rom_report |
重点:
.text/.rodata;.data/.bss/noinit;- iterable metadata;
- thread stacks;
- heap;
- network buffers;
- logging buffer;
- filesystem cache。
功能关闭后若体积未下降,检查引用、select、always-linked library 和 LTO。
16. 配置归档
发布应保存:
- source commit;
- west manifest revisions;
- toolchain/SDK;
- board/revision;
- build command;
.config;zephyr.dts;- map/ELF;
- signing metadata;
- generated version/build descriptor。
只保存 prj.conf 无法重现完整构建。
17. 安全检查
- userspace/MPU 是否按威胁模型启用;
- stack protection;
- fortify;
- assert 在 release 的策略;
- entropy/CSPRNG;
- management shell/MCUmgr 暴露;
- debug port;
- firmware signing/rollback;
- persistent data 权限;
- network credentials;
- fatal/coredump 是否泄露敏感信息。
18. 常见误区
- 把 board defconfig 当应用配置;
- 手改生成文件;
- 只看
prj.conf不看.config; DEVICE_DT_GET()后不检查 ready;- 在 ISR/workqueue 中做长阻塞;
- 用 heap 解决所有实时对象;
- 认为 logging 不影响时序;
- 忽略 MCUboot header/trailer 对 flash 容量的影响;
- 只测试正常升级,不做掉电和回滚。
正在加载留言…