RK平台调试工具与量产测试系统化:串口、JTAG、软件测试、PCBA

教育资讯 土里土气 2026-09-26 06:21 6201 0

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

wKgZO2q0XqKABm-bAAC5V8OvtkY979.png

开发期先用串口把日志调通,调不通再上 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 节点)

审核编辑 黄宇