RK3576 调试工具使用指南
目标平台: RK3576 | NPU 算力: 6 TOPS | 文档版本: V1.0
适用板型: C-3576BQ 核心板 + M4-R2 底板
最后更新: 2026-10-23
1. 概述
1.1 功能简介
本指南为基于 RK3576 处理器的 ShimetaPi M4-R2 系统提供全面的调试方法论和工具链参考。本文档覆盖串口调试、GDB 远程调试、内核跟踪(ftrace/perf/strace)、NPU 调试、内存调试、GPIO/I2C/SPI 硬件调试以及崩溃转储(kdump/ramoops)等核心调试场景,帮助开发者快速定位和解决软件及硬件层面的问题。
1.2 应用场景
| 场景 | 说明 |
|---|---|
| 系统启动失败 | 通过串口控制台捕获 bootrom/uboot/kernel 日志,定位启动卡死或 panic 原因 |
| 内核驱动调试 | 使用 ftrace、perf、printk 追踪驱动执行路径、中断延迟和调度行为 |
| 用户态应用崩溃 | 利用 GDB 远程调试、strace、AddressSanitizer 定位段错误和内存越界 |
| NPU 推理异常 | 通过 rknpu debugfs 和 RKNN Toolkit2 profiling 分析 NPU 推理耗时和内存占用 |
| GPIO/I2C/SPI 通信问题 | 借助 debugfs 和 i2cdetect 等工具验证总线状态和信号完整性 |
| 内存泄漏排查 | 使用 valgrind 和 AddressSanitizer 检测堆内存越界和泄漏 |
| 系统崩溃恢复 | 配置 kdump 和 ramoops 在内核 panic 后保留现场信息 |
1.3 工作原理
RK3576 调试体系分为三个层次:
硬件层:通过板载调试串口(USB 转 TTL 3.3V,波特率 1500000)连接调试终端,调试串口对应的设备树节点以实际发布的 RK3576 SDK 为准。
内核层:Linux 6.1 内核提供 ftrace(函数跟踪)、perf(性能计数器)、printk/kmsg(内核日志)、debugfs(调试文件系统)等机制,运行时可动态开关,对系统性能影响可控。
用户层:通过 GDB + gdbserver 实现远程断点调试,通过 strace 跟踪系统调用,通过 valgrind/AddressSanitizer 检测内存错误,通过 RKNN Toolkit2 进行 NPU 模型 profiling。
2. 硬件准备
2.1 硬件清单
| 序号 | 名称 | 型号/规格 | 用途 |
|---|---|---|---|
| 1 | 核心板 | C-3576BQ V1.0 | RK3576 主处理器模块 |
| 2 | 底板 | ShimetaPi M4-R2 V10 | 外设接口扩展与信号转接 |
| 3 | USB 转串口线 | USB 转 TTL 3.3V,支持 1.5Mbps | 连接调试串口 |
| 4 | 调试器(可选) | J-Link / DAP-Link | JTAG 硬件断点调试 |
| 5 | 以太网线 | CAT5e/CAT6 | GDB 网络调试、文件传输 |
| 6 | 电源 | 5V/2A(Type-C 或 6pin) | 系统供电 |
| 7 | TF 卡(可选) | microSD(最大 128GB) | 系统启动与日志存储 |
2.2 调试串口连接
M4-R2 的调试串口为板载调试串口(USB 转 TTL 3.3V,波特率 1500000),具体引脚位置以底板原理图(S-04)为准。
连接步骤:
- 将 USB 转 TTL 模块的 TX 接到底板调试串口 RX 引脚
- 将 USB 转 TTL 模块的 RX 接到底板调试串口 TX 引脚
- 将 GND 连接到共地引脚
- 将 USB 转 TTL 模块插入主机 USB 口
确认串口设备:
# Linux 主机
ls -l /dev/ttyUSB*
# macOS 主机
ls -l /dev/tty.usbserial*
# 打开串口终端(1500000 波特率)
sudo picocom -b 1500000 /dev/ttyUSB02.3 硬件确认
#!/bin/bash
# hardware_check.sh - RK3576 调试硬件确认
echo "===== RK3576 调试硬件检查 ====="
[ -c /dev/ttyUSB0 ] && echo "[OK] /dev/ttyUSB0 存在" || echo "[WARN] 串口未检测到"
lsof /dev/ttyUSB0 2>/dev/null || echo "[OK] 串口未被占用"
ping -c 1 -W 2 <板端IP> &> /dev/null && echo "[OK] 目标板网络可达" || echo "[WARN] 网络不可达"
echo "===== 检查完成 ====="3. 软件准备
3.1 调试工具安装
# Linux 主机(Ubuntu/Debian)
sudo apt-get update && sudo apt-get install -y \
build-essential gcc-aarch64-linux-gnu gdb-multiarch \
minicom picocom screen strace ltrace valgrind \
linux-tools-common linux-tools-$(uname -r) \
trace-cmd kernelshark nmap tcpdump wireshark
# NPU 调试工具(安装方式以实际发布的 RKNN Toolkit2 文档为准)
# pip3 install rknn-toolkit23.2 内核调试配置
确保 Linux 6.1 内核编译时开启以下调试选项(配置项名称以实际发布的 RK3576 SDK 内核为准):
# 内核 .config 关键调试配置项
CONFIG_DEBUG_INFO=y # 生成调试信息
CONFIG_FRAME_POINTER=y # 保留帧指针(便于栈回溯)
CONFIG_KGDB=y # 内核 GDB 调试支持
CONFIG_KGDB_SERIAL_CONSOLE=y # 通过串口进行 KGDB 调试
CONFIG_MAGIC_SYSRQ=y # SysRq 魔术键支持
CONFIG_FTRACE=y # 函数跟踪
CONFIG_FUNCTION_TRACER=y # 函数级跟踪
CONFIG_FUNCTION_GRAPH_TRACER=y # 函数图跟踪
CONFIG_KPROBES=y # 动态探针
CONFIG_PERF_EVENTS=y # 性能事件
CONFIG_SCHED_DEBUG=y # 调度器调试
CONFIG_DEBUG_FS=y # debugfs 文件系统
CONFIG_KDUMP=y # 内核崩溃转储
CONFIG_PSTORE=y # 持久化存储(ramoops)
CONFIG_PSTORE_RAM=y # RAM 中的 pstore验证内核调试配置:
zcat /proc/config.gz | grep -E "CONFIG_(DEBUG_INFO|KGDB|FTRACE|KPROBES|PERF_EVENTS|DEBUG_FS|KDUMP|PSTORE|MAGIC_SYSRQ)"4. 操作步骤
4.1 串口调试
串口是最基础的调试手段,即使内核崩溃也能通过串口获取日志。
# minicom
sudo minicom -D /dev/ttyUSB0 -b 1500000 # Ctrl+A X 退出
# picocom(推荐)
sudo picocom -b 1500000 /dev/ttyUSB0 # Ctrl+A Ctrl+X 退出
# screen
screen /dev/ttyUSB0 1500000 # Ctrl+A K 退出
# 串口日志保存
sudo picocom -b 1500000 /dev/ttyUSB0 | tee serial_$(date +%Y%m%d).txtSysRq 调试技巧:
echo 1 > /proc/sys/kernel/sysrq # 启用 SysRq
echo t > /proc/sysrq-trigger # 打印所有任务状态
echo l > /proc/sysrq-trigger # 显示所有 CPU 调用栈
echo w > /proc/sysrq-trigger # 打印阻塞任务
echo c > /proc/sysrq-trigger # 触发内核 crash(测试 kdump)4.2 GDB 远程调试
用户态程序远程调试:
# === 目标板端 ===
gdbserver 0.0.0.0:1234 /path/to/program
# === 主机端 ===
gdb-multiarch /path/to/program
(gdb) set target-remote <板端IP>:1234
(gdb) set architecture aarch64
(gdb) break main
(gdb) continue
(gdb) info registers # 查看寄存器
(gdb) backtrace # 查看调用栈
(gdb) print variable_name # 打印变量值
(gdb) x/16xg 0xaddr # 查看内存内核 GDB 调试(KGDB):
# 目标板触发 KGDB
echo g > /proc/sysrq-trigger
# 主机端连接
gdb-multiarch vmlinux
(gdb) set target-remote /dev/ttyUSB0
(gdb) set baud 1500000
(gdb) break start_kernel
(gdb) bt4.3 ftrace 函数跟踪
# 挂载 debugfs
mount -t debugfs none /sys/kernel/debug
# 函数图跟踪(显示调用关系和耗时)
echo function_graph > /sys/kernel/debug/tracing/current_tracer
echo "i2c_*" > /sys/kernel/debug/tracing/set_ftrace_filter
echo 1 > /sys/kernel/debug/tracing/tracing_on
tail -f /sys/kernel/debug/tracing/trace_pipe
echo 0 > /sys/kernel/debug/tracing/tracing_on # 停止
# 事件跟踪
echo 1 > /sys/kernel/debug/tracing/events/sched/sched_switch/enable
echo 1 > /sys/kernel/debug/tracing/events/irq/irq_handler_entry/enable
echo 1 > /sys/kernel/debug/tracing/tracing_on
# trace-cmd 工具
trace-cmd record -e sched_switch -e irq_handler_entry sleep 5
trace-cmd report | head -30
# 保存并可视化分析
trace-cmd record -p function_graph -g i2c_transfer -- sleep 10
kernelshark trace.dat4.4 perf 性能分析
# 系统级/进程级统计
perf stat -a sleep 5
perf stat -p <PID> sleep 5
# 函数级热点分析
perf record -a -g sleep 10
perf report
# 事件跟踪
perf record -e sched:sched_switch -a sleep 3
perf stat -e cache-references,cache-misses -a sleep 5
# 火焰图生成
perf script -i perf.data | stackcollapse-perf.pl | flamegraph.pl > flamegraph.svg4.5 strace 系统调用跟踪
strace -p <PID> # 跟踪进程
strace /path/to/program # 跟踪程序启动
strace -e trace=network -p <PID> # 仅跟踪网络调用
strace -e trace=file -p <PID> # 仅跟踪文件调用
strace -tt -T -p <PID> # 带时间戳
strace -f -p <PID> # 多线程跟踪
strace -c -p <PID> # 统计汇总4.6 NPU 调试
# debugfs NPU 调试信息(以实际 SDK 驱动为准)
ls /sys/kernel/debug/rknpu/ 2>/dev/null
cat /sys/kernel/debug/rknpu/info 2>/dev/null
cat /sys/kernel/debug/rknpu/usage 2>/dev/null
cat /sys/kernel/debug/rknpu/mem_info 2>/dev/null
cat /sys/kernel/debug/rknpu/dvfs 2>/dev/null
# NPU devfreq 频率查看
NPU_PATH=$(ls -d /sys/class/devfreq/npu* 2>/dev/null | head -1)
cat $NPU_PATH/cur_freq 2>/dev/null
# RKNN Toolkit2 模型 profiling
python3 << 'EOF'
from rknn.api import RKNN
rknn = RKNN()
rknn.config(mean_values=[[123.675, 116.28, 103.53]],
std_values=[[58.395, 57.12, 57.375]],
target_platform='rk3576')
rknn.load_rknn('model.rknn')
rknn.init_runtime(target=None)
import numpy as np
input_data = np.random.randint(0, 255, [1, 224, 224, 3], dtype=np.uint8)
print(rknn.perf(inputs=[input_data], n=100))
rknn.release()
EOF4.7 内存调试
# AddressSanitizer
aarch64-linux-gnu-gcc -fsanitize=address -g -O1 program.c -o program
LD_PRELOAD=/usr/lib/aarch64-linux-gnu/libasan.so.5 ./program
# Valgrind 内存泄漏检测
valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes ./program
# 内存监控
watch -n 1 'cat /proc/meminfo | grep -E "MemTotal|MemFree|MemAvailable"'
# OOM 调试
dmesg | grep -i "oom\|out of memory\|killed process"4.8 GPIO/I2C/SPI 硬件调试
# GPIO
cat /sys/kernel/debug/gpio
# I2C(总线编号以实际 SDK 为准)
i2cdetect -l # 列出 I2C 总线
i2cdetect -y <bus> # 扫描指定 I2C 总线
i2cget -y <bus> 0x50 0x00 # 读取寄存器
i2cset -y <bus> 0x50 0x00 0x01 # 写入寄存器
# SPI
ls /dev/spidev*
spi-pipe -d /dev/spidev0.0 -s 1000000 -b 8 -c 0 -r 164.9 崩溃转储
# kdump 配置
sudo apt-get install kdump-tools makedumpfile
sudo dpkg-reconfigure kdump-tools
sudo reboot
# ramoops/pstore
ls /sys/fs/pstore/
cat /sys/fs/pstore/console-ramoops-0
# crash dump 分析
crash /usr/lib/debug/boot/vmlinux-$(uname -r) /var/crash/*/vmcore
# crash 常用命令:bt(调用栈) log(日志) ps(进程) kmem(内存)5. 代码详解
5.1 调试方法论
分级调试策略(由简到繁):
第一级:printk + 串口日志
└─ 适用:驱动加载、初始化、基础功能验证
└─ 优点:无额外依赖,内核崩溃也能看到
第二级:strace + 系统调用跟踪
└─ 适用:用户态程序行为分析、文件/网络操作追踪
└─ 优点:无需重编译,运行时挂载
第三级:ftrace + 内核函数跟踪
└─ 适用:内核驱动执行路径、中断延迟、调度行为分析
└─ 优点:性能开销极小,可动态开关
第四级:GDB + 断点调试
└─ 适用:复杂逻辑错误、内存越界、多线程竞态
└─ 优点:精确控制执行流程
第五级:KGDB + 内核调试
└─ 适用:内核级 bug、驱动底层问题
└─ 优点:内核级断点、单步执行5.2 各工具使用场景对比
| 工具 | 层级 | 性能影响 | 信息密度 | 适用场景 | 复杂度 |
|---|---|---|---|---|---|
| printk | 内核 | 极低 | 低 | 启动调试、驱动基础验证 | 低 |
| strace | 用户态 | 中 | 高 | 系统调用追踪、程序行为分析 | 低 |
| ftrace | 内核 | 低 | 高 | 驱动路径分析、调度研究 | 中 |
| perf | 内核+用户 | 低 | 高 | 性能分析、热点函数定位 | 中 |
| GDB | 用户态 | 高 | 极高 | 逻辑错误、内存问题 | 中高 |
| KGDB | 内核 | 极高 | 极高 | 内核级 bug、底层驱动问题 | 高 |
| valgrind | 用户态 | 高 | 高 | 内存泄漏、越界访问 | 中 |
| ASan | 用户态 | 中 | 高 | 内存错误实时检测 | 中 |
5.3 自动化调试信息采集
#!/bin/bash
# rk3576_debug_collect.sh - RK3576 调试信息一键采集
OUT="debug_$(date +%Y%m%d_%H%M%S)"
mkdir -p "$OUT"
uname -a > "$OUT/uname.txt"
cat /proc/meminfo > "$OUT/meminfo.txt"
dmesg > "$OUT/dmesg.txt"
dmesg | grep -iE "error|panic|oops|fail" > "$OUT/errors.txt"
cat /proc/slabinfo > "$OUT/slabinfo.txt"
cat /sys/kernel/debug/gpio > "$OUT/gpio.txt" 2>/dev/null
for bus in $(ls /dev/i2c-* 2>/dev/null | sed 's|/dev/i2c-||'); do
i2cdetect -y $bus >> "$OUT/i2c.txt" 2>/dev/null
done
tar czf "${OUT}.tar.gz" "$OUT" && rm -rf "$OUT"
echo "完成: ${OUT}.tar.gz"6. 常见问题
6.1 串口无输出或乱码
现象: 连接串口后无任何输出,或输出乱码。
排查步骤:
# 1. 确认波特率(M4-R2 调试串口为 1500000,不是常见的 115200)
# 2. 检查 TX/RX 交叉连接(非直连),确认 GND 共地
# 3. 检查 USB 转串口芯片驱动
dmesg | grep -i "tty\|usb\|serial\|cp210\|ch34"
# 4. 尝试降低波特率测试基本通信
# 5. 检查调试串口对应设备树节点是否已启用(以实际 SDK 为准)6.2 GDB 连接超时
现象: 主机 GDB 无法连接到目标板 gdbserver。
解决方案:
# 1. 确认网络连通:ping <板端IP>
# 2. 检查防火墙:sudo iptables -A INPUT -p tcp --dport 1234 -j ACCEPT
# 3. gdbserver 监听地址使用 0.0.0.0(非 127.0.0.1)
# 4. 无网络时使用串口作为 GDB 通道
gdb-multiarch vmlinux
(gdb) set target-remote /dev/ttyUSB0
(gdb) set baud 15000006.3 ftrace 无输出
现象: 启用 ftrace 跟踪后 trace 文件为空。
解决方案:
# 1. 确认内核支持:zcat /proc/config.gz | grep CONFIG_FTRACE
# 2. 检查 filter 名称是否与函数名完全匹配
# 3. 确认 tracing_on 状态为 1
# 4. 清除 filter 重新测试
echo > /sys/kernel/debug/tracing/set_ftrace_filter
echo 1 > /sys/kernel/debug/tracing/tracing_on6.4 NPU 调试信息无法读取
现象: 读取 /sys/kernel/debug/rknpu/ 下的文件报错或为空。
解决方案:
# 1. 确认 debugfs 已挂载
mount -t debugfs none /sys/kernel/debug
# 2. 确认 rknpu 驱动已加载:lsmod | grep rknpu
# 3. 检查初始化日志:dmesg | grep -i rknpu
# 4. 需要 root 权限:sudo cat /sys/kernel/debug/rknpu/info6.5 内核 panic 后无法获取 crash dump
现象: 内核 panic 后重启,无法找到 crash dump。
解决方案:
# 1. 确认 kdump 服务:systemctl status kdump-tools
# 2. 检查 crashkernel 参数:cat /proc/cmdline | grep crashkernel
# 3. 检查 pstore:mount -t pstore none /sys/fs/pstore
# 4. 设置 panic 后等待时间:GRUB_CMDLINE_LINUX="panic=10"6.6 perf 报 "Permission denied"
现象: 运行 perf 命令时提示权限不足。
解决方案:
# 1. 临时允许:sudo sysctl -w kernel.perf_event_paranoid=-1
# 2. 永久生效:echo "kernel.perf_event_paranoid=-1" >> /etc/sysctl.conf
# 3. 或使用 sudo:sudo perf stat -a sleep 57. 相关文档
| 文档名称 | 路径 | 说明 |
|---|---|---|
| 系统启动时间优化 | 系统启动时间优化 | 启动流程与系统级优化 |
| CPU-GPU-NPU 调优 | CPU-GPU-NPU调优 | 多核协同与频率调优 |
| 内存与存储优化 | 内存与存储优化 | 内存带宽与存储优化 |
| 功耗分析与优化 | 功耗分析与优化 | 低功耗设计与功耗管理 |
| 内核配置与裁剪 | 内核配置与裁剪 | 内核裁剪与编译方法 |
| 设备树详解与实践 | 设备树详解与实践 | 设备树配置与调试 |
| 串口调试与基础操作 | 系统启动与基础操作 | 串口登录与基础操作 |
| NPU 性能调优与调试 | NPU性能调优与调试 | NPU 推理性能分析 |
