RK平台调试工具与量产测试系统化:串口、JTAG、软件测试、PCBA
调试手段按「从软到硬」排:串口日志是最常用的一层,串口失效再上 JTAG;测试则分软件功能/压测和量产 PCBA 两级。本文把这四块串成一套完整的调试与验收方法。

开发期先用串口把日志调通,调不通再上 JTAG;验证阶段用 rockchip-test 做功能与压力,量产用 PCBA 测试逐模块体检。
一、串口只有几行日志就没了?console 与 loglevel 调起来
"串口就打印几行就停了"通常是两个原因:console 没从 earlycon 切换到正式 console,或日志级别太低把后面的输出滤掉了。把这两处调对,日志就源源不断了。
串口日志的输出链路是:earlycon(早期)→ console=ttyFIQ0(正式)→ init 后用户态。只看到几行的常见根因:①console 参数没生效/波特率不对(后面的日志走不到串口);②日志级别(loglevel)太低,把 INFO 以下的打印滤掉了;③卡在内核早期(见 01.05,那是真问题)。
1、console 从哪来:earlycon → 正式 console
本 SDK bootargs(rk3576-linux.dtsi):earlycon=uart8250,mmio32,0x2ad40000 console=ttyFIQ0;
console=ttyFIQ0 是 RK 的 FIQ 调试口,内核编了 CONFIG_SERIAL_8250_CONSOLE=y 才能把 console 挂到串口;
波特率必须与 U-Boot 一致 ,否则正式 console 一接管就"断流"(这经常被误读成"卡住了")。
2、printk 与 loglevel
日志能不能上串口,由内核 printk 级别决定。运行时看/改 /proc/sys/kernel/printk(四个数字):
| 位置 | 含义 |
|---|---|
| 值 1:console_loglevel | 能打到 console 的最高级别(7=debug 全开;4=只到 err 级)——想让串口多打就调它 |
| 值 2:default_message_loglevel | 没有显式级别的 printk 默认级别 |
| 值 3:minimum_console_loglevel | console 级别能设的最小值(下界) |
| 值 4:default_console_loglevel | 默认 console 级别 |
启动时用内核命令行 loglevel=8(或 ignore_loglevel)能从一开始就全量输出;运行时用 echo "7 4 1 7" > /proc/sys/kernel/printk 临时调。
3、常见问题对照表
| 现象 | 根因 | 处理 |
|---|---|---|
| 只有 earlycon 那几行,之后无输出 | console 未接管(波特率/console 参数/driver 未注册) | 确认 console=ttyFIQ0 在 bootargs 里、波特率与 U-Boot 一致、CONFIG_SERIAL_8250_CONSOLE=y |
| 有输出但"缺中间一大段" | loglevel 太低,INFO/DEBUG 被滤掉 | 启动参数加 loglevel=8 或调 /proc/sys/kernel/printk |
| 乱码 / 波特率错 | 串口工具波特率与内核不一致 | 核对 U-Boot/内核/工具三处波特率一致 |
| 用户态日志看不到(systemd 的) | console 被占或 journald 未接到 console | 确认 console 设备存在(ls /dev/ttyFIQ0),必要时 journald 配 ForwardToConsole |
4、实操
# 1. 运行时把日志级别开到最大(临时)echo"7 4 1 7"> /proc/sys/kernel/printk# 2. 确认 console 设备与注册ls/dev/ttyFIQ* ; dmesg | grep -i"console"# 3. 启动参数带 loglevel 全量输出(改 dts bootargs,见 02.03 后重烧)# bootargs += "loglevel=8"# 4. 串口抓取minicom -D /dev/ttyUSB0 -b 1500000 # 波特率与内核一致
串口"只有几行"先分清:是 console 没接管(波特率/console 参数/CONFIG),还是 loglevel 太低(滤掉了)。前者查 console=ttyFIQ0 与波特率,后者 loglevel=8 或改 /proc/sys/kernel/printk。两处都对了,日志自然源源不断。
二、板子死在第一行代码之前?用 JTAG 掀开盖板看寄存器
串口没输出、内核起不来,往往是"太早期就死了"。这时候 JTAG 是唯一能"掀开盖板看寄存器"的手段——OpenOCD + GDB 可以停住 CPU、看 PC/寄存器/内存。
JTAG/OpenOCD 是串口失效时的兜底调试手段:它可以停住 CPU(halt)、读PC/寄存器/内存、设断点,定位"死在第一条指令之前"的问题(如 DDR 初始化失败、时钟/电源没起来导致 CPU 卡死)。代价是需要JTAG 调试器 + 目标配置文件,且早期阶段很多外设还没初始化。它定位的是"硬件/极早期初始化"问题,而不是驱动逻辑。
边界说明:官方文档 Common/DEBUG/..._GNU_MCU_Eclipse_OpenOCD_CN.pdf 侧重 MCU(RTOS/AMP)核调试;本文只讲主系统(A 核)早期崩溃的 JTAG 思路。
1、什么时候需要它
| 场景 | 串口能否帮忙 | JTAG 的价值 |
|---|---|---|
| DDR 初始化失败,CPU 跑不动 | 完全没输出 | halt 后读 PC/看 DDR 寄存器 |
| 内核极早期 panic / 死锁 | 可能只有几行 | 断点 + 单步看死在哪个函数 |
| 怀疑硬件/上电时序 | 不可靠 | 确认 CPU 是否真的在跑(PC 变化?) |
2、OpenOCD 从哪来
SDK 把它做成了buildroot 包:buildroot/package/openocd/(openocd.mk),需要时在 Buildroot 里勾选打进系统;
官方调试文档:docs/cn/Common/DEBUG/Rockchip_Developer_Guide_GNU_MCU_Eclipse_OpenOCD_CN.pdf;
另外 RK 还提供 GPIO 级调试工具PinDebug(tools/linux/PinDebug,Windows 版 tools/windows/pin_debug_tool_v1.17_...),用来查引脚/电平,和 JTAG 互补。
3、基本工作流
# 1. 准备好 JTAG 调试器(如 J-Link/ST-Link 等)+ 目标板 JTAG 接口# 2. 启动 OpenOCD,加载目标配置文件openocd-finterface/jlink.cfg-ftarget/.cfg# —— 监听 localhost:3333 (gdb)# 3. GDB 连上去aarch64-linux-gnu-gdb (gdb) target remote :3333(gdb) halt # 停住 CPU(gdb) info registe rs # 看 PC/SP/通用寄存器(gdb) x/16i$pc # 反 汇编当前指令(gdb)breakfunc tion_name(gdb)continue
4、能力边界与提示
需要硬件 :JTAG 调试器 + 板上 JTAG 引脚(是否引出、复用到哪一组,见板级原理图/调试文档);
需要匹配的目标配置 :目标板的 core、DAP/AP 地址等,SDK 没现成 RK3576 配置时需按 OpenOCD 模板适配(标注"推断");
早期段调试要连 <符号> 用带符号的 vmlinux/u-boot elf,配合 CONFIG_DEBUG_INFO_DWARF4=y(本 SDK 已开)看源码行。 符号>
串口都救不了的"极早期/硬件"问题,用 JTAG + OpenOCD:halt 停 CPU → 看 PC/寄存器 → 断点/单步 → 对带符号的 vmlinux。它是调试链的最后一道手段,配合 buildroot 的 openocd 包与官方 OpenOCD 文档上手;引脚级问题用 RK 的 PinDebug 工具。
三、怎么系统化地测一个功能?软件测试用例与压测
"手点一遍"不算测试。SDK 自带一套 rockchip-test 软件测试框架,把 CPU/DDR/GPU/Flash/音频/相机/网络/压力测试都做成了可复跑的用例。用框架 + 压力测试,功能才算真正验证过。
SDK 的软件测试框架在 external/rockchip-test/:主脚本 rockchip_test.sh 提供交互式菜单,每个模块一个目录(cpu/ddr/gpu/npu2/flash_test/audio/camera/video/wifibt/pcie/benchmark/auto_reboot…,注意 NPU 目录是npu2、Flash 是flash_test)。做法:先跑功能用例验证行为,再跑压力测试验证稳定(压测通过才算数)。
1、框架长什么样
external/rockchip-test/rockchip_test.sh(V2.4)启动后打印菜单,模块号与用例(源码里直接可见):
| 模块号 | 用例 | 适合场景 |
|---|---|---|
| 1 / 2 / 3 / 4 | ddr / cpu / gpu / npu stress | 计算与存储压力,长时间跑稳定性 |
| 6 / 7 | auto reboot / power lost | 反复重启/断电,查异常重启 |
| 8 | flash stress | Flash/eMMC 读写压力 |
| 10 / 11 / 12 | audio / camera / video | 多媒体功能回归(见篇章四/五) |
| 13 / 14 / 15 / 16 / 17 | bt / wifi / wifibt config / pcie / chromium | 无线、高速接口、浏览器压测 |
| 18 | benchmark(unixbench、glmark2…) | 性能基准(配合 09.01) |
注:菜单里的 9 为 recovery wipe(recovery 擦除)测试,属 recovery 范畴,本系列不展开。
2、怎么用
# 交互式(菜单选择)cdexternal/rockchip-test && ./rockchip_test.sh# 直接跑某个模块的脚本(看模块目录)lsexternal/rockchip-test/cpu external/rockchip-test/benchmark./external/rockchip-test/cpu/*stress*.sh # 例:cpu 压测脚本
注意:菜单里含 suspend_resume 等模块,休眠/唤醒相关内容不在本系列范围(见 uboot-series 07.05)。
3、测试方法论:功能用例 + 压测 + 记录
功能用例 :逐项验证行为正确(音频出声、相机出图、网络连通…),人工或脚本断言通过/失败;
压力测试 :对改动过的模块做长时间/高频压测(如 ddr/cpu/flash stress 过夜),记录 dmesg 是否有 error/panic;
记录与判定 :每次测试留档(日志/时间/通过数),对照官方 Linux_Software_Test_CN.pdf 的测试规范组织用例与验收标准。
系统化测试 =rockchip_test.sh 菜单跑功能用例 → 对改动模块跑压力测试 → 全程留 dmesg 日志 → 按官方测试规范判定。压测能复现的崩溃,按 call trace 分析直接定位到驱动。
四、量产板子功能正常吗?PCBA 测试搭起来
量产阶段每一块板都要过"体检":CPU、DDR、eMMC、SD、摄像头、音频、按键、LED、RTC、USB……SDK 自带的 rk_pcba_test 把每个模块做成独立用例,一个服务端统一调度、回报 PASS/FAIL。本文拆开这个框架,讲清楚怎么搭、怎么看结果。
PCBA 测试 = 量产产线上的"功能体检"。external/rk_pcba_test/ 是官方实现:一个服务端(echo_pcbatest_server)统一调度,每个硬件模块一个独立用例(echo_ <模块> _test.c),用例回报 PASS/FAIL/VERIFY/PRESS 模块>,结果可存盘(默认 /tmp)。量产时:编好镜像 → 逐模块跑用例 → 全部 PASS 才放行。
1、框架组成
整个测试程序位于 external/rk_pcba_test/,核心三块:
| 部件 | 作用 |
|---|---|
| echo_pcbatest_server.c + pcbatest_server.h | 服务端:socket 监听 → fork 子进程跑用例 → 收结果(源码里 PARENT_EXIT/CHILD_EXIT/FORK_FAIL 分工) |
| echo_ <模块> _test.c(一模块一文件) 模块> | 独立测试用例:cpu / ddr / emmc / sdcard / camera / audio(play/record/linein) / bt / ir / key / led / rtc / usbhost / touchpad / rotary / ringmic / wlan 等 |
| common.h + cJSON/ | 结果协议与状态定义、JSON 序列化(服务端与 PC 测试端通信) |
辅助件:pcba_minui(板上迷你 UI)、tinyalsa(音频测试)、echo_auto_test.c(一键全测)、echo_discovery.c(设备发现)。构建目标在 CMakeLists.txt:echo_pcbatest_server、pcba-core、各 echo_xxx_test。
2、结果状态与错误码(源码直读)
common.h 里定义了回报给产线的结果:
| 状态宏 | 含义 |
|---|---|
| TESTING | 测试进行中 |
| PASS | 通过 |
| FAIL | 失败(配合错误码定位) |
| VERIFY | 需人工确认(如音视频感官项) |
| PRESS | 等待按键/物理动作(如按键测试要人按) |
错误码也是负值编号,例如 KEY_OPEN_FAIL=-40、IR_OPEN_FAIL=-130、SDCARD_MOUNT_FAIL=4 等(详见 common.h)。FAIL 时按错误码查原因,比只看"失败"高效得多。结果默认存 /tmp(TEST_RESULT_SAVE_PATH)。
3、覆盖哪些测试模块
从目录里的用例文件即可看出能测哪些硬件(每项对应一个 echo_ <模块> _test.c): 模块>
| 类别 | 用例文件 |
|---|---|
| 计算/存储 | echo_cpu_test.c、echo_ddr_test.c、echo_emmc_test.c、echo_sdcard_test.c |
| 音视频 | echo_audio_test.c、echo_audio_play/record/linein_test.c、echo_camera_test.c、echo_ringmic_test.c |
| 输入/外设 | echo_key_test.c、echo_ir_test.c、echo_led_test.c、echo_touchpad_test.c、echo_rotary_test.c、echo_rtc_test.c |
| 连接/无线 | echo_usbhost_test.c、echo_bt_test.c、echo_wlan_test.c |
4、怎么搭起来
框架用 CMake 组织(external/rk_pcba_test/CMakeLists.txt),产线镜像里把服务端/用例打进去:
# 1. 交叉编译(在 SDK 内,工具链见 01.01/01.02)cdexternal/rk_pcba_test &&mkdirbuild &&cdbuildcmake .. && make # 产物: echo_pcbatest_server / pcba-core / echo_xxx_test# 2. 部署到板子并启动服务端adb push echo_pcbatest_server /userdata/ && adb shellchmod+x /userdata/echo_pcbatest_server && /userdata/echo_pcbatest_server &# 3. 跑单个用例(以 eMMC 为例)./echo_emmc_test # 返回 PASS / 打印错误码
产线可把"逐模块跑 + 解析 PASS/FAIL"写成脚本,或直接跑 echo_auto_test.c 一键全测;带 UI 的产线用 pcba_minui 展示结果。
5、结果判定与量产集成
自动项 (CPU/DDR/eMMC/USB…):直接看 PASS/FAIL + 错误码;
人工项 (音视频感官):状态 VERIFY,由产线操作员确认;
FAIL 定位 :按 common.h 的错误码找到对应打开/查询失败的环节(如 KEY_OPEN_FAIL = 按键节点打不开,先查设备树/驱动);
产线合格判据:全部模块 PASS/VERIFY 通过才烧正式固件放行;结果落 /tmp(可改 TEST_RESULT_SAVE_PATH 存持久化分区)。
PCBA 量产测试 =编译 rk_pcba_test → 产线镜像里带服务端与用例 → 逐模块跑(或 auto 全测)→ 按 PASS/FAIL/VERIFY + 错误码判定 → 全过才放行。框架的每个模块都是独立用例、源码可读可改,需要覆盖更多项时可仿照已有文件自行扩展用例(如新增一个 echo_xxx_test.c)。
五、RK3576 板端实测记录
以下在 RK3576 + Debian Bookworm 上通过 adb 直连执行(串口一节命令全部可用):
| 验证项 | 命令(adb shell …) | 实测结果 |
|---|---|---|
| printk 级别 | cat /proc/sys/kernel/printk | 7 4 1 7(console_loglevel=7 全开) |
| FIQ 串口 | ls /dev/ttyFIQ0;dmesg | grep console | /dev/ttyFIQ0 存在,日志见 console [ttyFIQ0] enabled |
| rockchip-test | ls /userdata/rockchip-test /usr/bin/rockchip* | 未预装(SDK 侧框架,需按 01.02 部署到板) |
| PCBA 服务端 | ls /userdata/echo_pcbatest_server | 未预装(需 cmake 交叉编译后 push,见本节省 4) |
官方文档依据:
docs/cn/Common/UART/Rockchip_Developer_Guide_UART_CN.pdfdocs/cn/Common/UART/Rockchip_Developer_Guide_UART_FAQ_CN.pdf(串口与FAQ)
SDK 源码依据:
kernel-6.1/arch/arm64/boot/dts/rockchip/rk3576-linux.dtsi(earlycon/console bootargs)kernel-6.1/arch/arm64/configs/rockchip_linux_rk3576_defconfig(CONFIG_SERIAL_8250_CONSOLE=y、CONFIG_SERIAL_8250_DW=y、CONFIG_PRINTK_TIME=y)kernel-6.1/arch/arm64/boot/dts/rockchip/rk3576.dtsi(uart2 节点)
审核编辑 黄宇









