OpenHarmony调试三板斧:RK3568串口、HDC与内核日志

OpenHarmony调试三板斧:RK3568串口、HDC与内核日志 1. 从“选不对设备树”说起RK3568调试前夜的真实战场很多刚接触OpenHarmony硬件开发的朋友第一个崩溃点往往不是编译报错而是拿到一块RK3568开发板之后面对源码里那一堆dts/dtsi文件完全不知道选哪个。我见过不少人在社区里问“openharmony的rk3568有许多设备树到底咋选”这个问题背后其实藏着一个更本质的困惑OpenHarmony的设备树和Linux内核的设备树到底是不是一回事先说结论机制上同源使用上完全不同。OpenHarmony在RK3568上的设备树继承自Linux内核的device tree语法但它的加载流程、节点含义、board级配置方式都做了大量定制。最典型的是OpenHarmony源码里你会看到device/board/hihope/rk3568/这类目录里面通常放着hihope-rk3568.dts、rk3568-evb1-ddr4-v10.dts这类文件型号后缀五花八门。有些是官方评估板的配置有些是第三方定制的底板还有的是内部调试用的临时配置。你选错了轻则某个外设不工作重则系统起不来串口打印卡在某个地方一动不动。我的建议是拿到一块板子先别急着编译烧录花十分钟确认三件事。第一板子上主控芯片的具体型号后缀比如RK3568J和RK3568在温度等级、封装上都有差异设备树里对应的电源域和时钟配置可能不同。第二DDR颗粒的型号和容量设备树里的内存配置、DDR频率参数都跟这个强相关。第三底板原理图里有没有特殊的外设映射比如某个GPIO被复用成了调试串口还是LED这在dts里必须有对应修改。提示以瑞芯微官方RK3568 EVB1开发板为例默认配置是双核A55四核A55的八核架构DDR4颗粒板载千兆网口、USB3.0、HDMI、MIPI-DSI等接口。源码里arch/arm64/boot/dts/rockchip/目录下以rk3568-evb开头的dts文件对应官方评估板rk3568-iotest、rk3568-nvr这类则对应瑞芯微内部测试或特定行业方案。如果你用的是第三方核心板优先找厂家提供的bsp补丁包别自己硬选。选对设备树只是第一步真正决定你调试效率的是接下来要分享的这套三板斧。我从实际项目中总结出来的经验是OpenHarmony硬件调试最常用的三个手段——串口日志、HDC命令交互、内核日志分析。这三件事搞定绝大多数启动失败、外设异常、系统崩溃问题都能定位到根因。下面逐个拆开讲。2. 第一板斧串口日志——OpenHarmony的“心跳监视器”串口在OpenHarmony开发里是调试的生命线。为什么这么说因为OpenHarmony从uboot阶段到内核启动再到init进程拉起、用户态服务注册整个链路都会往串口输出日志。系统起不来的时候网口、USB、HDMI这些统统不可用只有串口还在说真话。2.1 连接与配置的坑串口连接本身不难USB转TTL模块接开发板的调试串口一般三根线TX、RX、GND注意交叉连接——开发板TX接模块RX开发板RX接模块TX。但有几个细节很容易翻车。第一电平匹配。RK3568的调试串口通常是3.3V TTL电平但有些底板设计成了1.8V电平尤其是用RK3568J做工业级产品的板子。你拿一个3.3V的USB转TTL模块直接怼上去可能能收到乱码或者完全没输出严重的还会烧坏串口引脚。稳妥的做法是查底板原理图确认串口电平或者用带电平转换的调试模块。第二波特率。RK3568平台的OpenHarmony默认调试串口波特率一般是1500000也就是1.5Mbps。这不是我们熟悉的115200很多新手在这里卡半天屏幕上一片乱码还以为是硬件问题。如果你拿到一片乱码先把波特率调对再说。使用minicom的话minicom -s进去配置串口参数选好设备节点比如/dev/ttyUSB0把波特率设成1500000关掉硬件流控。2.2 hilogOpenHarmony的日志门户系统起来之后串口上会持续输出海量日志这时候直接在串口终端里看信息太杂翻屏太快根本看不过来。正确做法是串口只用来观察启动早期阶段的日志系统起来之后用hilog工具做精细化的日志过滤。hilog是OpenHarmony的日志系统对标Linux的logcat。它有一套独立的日志分类体系每个日志条目带domain领域、tag标签、level级别、pid/uid等元信息。调试时的基本操作# 查看所有日志 hilog # 按标签过滤 hilog | grep HDF # 按级别过滤只输出warning及以上 hilog -L WARN # 带时间戳持久化到文件 hilog -w start -f /data/log/hilog.log这里有个非常实用的场景外设驱动注册失败。比如你的I2C触摸屏没反应先不急着改代码用hilog | grep -i i2c看看内核态HDFHardware Driver Foundation驱动的注册日志里面通常会直接告诉你failed to get i2c bus或者device not found这类关键信息。我在RK3568上调一个MIPI屏的时候就是用这招发现是dsi-gpio的复位引脚在dts里配错了。注意hilog的日志量在系统刚启动时会非常大建议用hilog -G 10M把buffer调大一点避免日志丢失。另外hilog -w start会持续写文件长时间跑测试的时候记得关掉否则日志文件会撑满/data分区。2.3 串口日志的“读心术”拿到一串串口日志怎么快速定位问题我的习惯是抓三个关键阶段。第一阶段看uboot日志开头是否正常输出U-Boot 2017.09之类字样DDR初始化是否通过如果卡在DDR training阶段基本是内存参数配置问题跟你的dts没多大关系优先查uboot里的ddr配置。第二阶段看内核早期Starting kernel ...之后关注设备树是否成功加载会打印OF: fdt:Machine model: XXX这个Machine model字段对应设备树里的model ...属性。如果这里显示的不是你预期的板型说明uboot传递给内核的dtb选错了回头检查uboot环境变量或打包脚本。第三阶段看init进程内核跑完会挂载根文件系统拉起/initOpenHarmony的init会逐步启动各个服务单元日志里会逐行打印服务启动状态。卡在某个服务通常是该服务的依赖服务没起来或者对应驱动初始化阻塞了。串口日志篇幅很长建议配合serial-grab这类串口记录工具把日志完整保存下来方便事后搜索定位。直接看终端滚动十有八九会漏关键信息。3. 第二板斧HDC——比ADB更对味的调试中枢系统能从串口看到init阶段说明OpenHarmony基础系统已经跑起来了。从这时候开始串口的效率就远不如HDC了。HDC全称是HarmonyOS Device Connector是OpenHarmony官方的设备调试工具定位类似Android的ADB但机制和命令细节有差异。很多人第一次用会下意识敲adb devices发现没有反应然后开始怀疑驱动装错了——实际上OpenHarmony根本不用ADB你要用的是hdc。3.1 连接方式和版本匹配HDC支持USB和网络两种连接方式。USB连接最简单开发板插上USB线PC端执行hdc list targets能看到设备序列号就说明连接成功。连接不上时优先排查驱动是否正确安装Windows端需要装对应驱动、USB线是否支持数据传输有些线只能充电、开发板USB口是否配置成了device模式RK3568需要在dts里把usb口配成otg且默认device。网络连接是USB连接的补充在开发板系统起来后确保设备与PC在同一局域网执行hdc tconn 192.168.1.100:5555 hdc list targets端口5555是HDC默认的TCP端口。网络连接的典型场景是USB口被占用、设备部署在远程机房、或者调试过程中USB驱动崩溃了。我在实际项目里还遇到过一种情况设备跑了几天后USB枚举失败重启USB栈不如直接切到网络HDC来得快。这里有一个常被忽略的点PC端的hdc版本必须和开发板里的hdcd服务版本匹配。OpenHarmony版本迭代很快API Level不同的镜像hdcd的协议可能会有变化。用旧版hdc连新版设备经常出现连上了但执行命令超时的诡异现象。建议从源码编译或从对应版本的官方toolchain里拿hdc不要随手去网上找个版本就用。3.2 高频命令清单与实战场景HDC的功能覆盖文件传输、命令执行、日志抓取、能力枚举下面这些命令是我日常反复用的# 进入设备shell hdc shell # 查看设备信息 hdc shell param get const.product.model # 传输文件PC - 设备 hdc file send ./test_script.sh /data/local/tmp/ # 传输文件设备 - PC hdc file recv /data/log/hilog.log ./hilog_backup.log # 抓取hilog到本地 hdc hilog hilog_dump.log # 安装hap应用 hdc install entry-default-signed.hap # 卸载hap应用 hdc uninstall com.example.myappHDC还有一个大家知道得多、但用得少的功能是hdc shell power-shell系列可以模拟断电、关机、休眠、唤醒等电源事件。在调试低功耗场景时非常有用比如验证某个外设在suspend/resume之后是否还能正常工作。拿一个实际排查过程举例。一次客户反馈RK3568设备偶发死机屏幕定格系统无响应。串口上看不到panic信息CPU可能还在跑但用户态的窗口系统卡死了。我的排查路径先用hdc shell hilog -w start把日志持续写到设备本地让客户复现问题。问题复现后用hdc file recv /data/log/hilog.log把日志拿到PC上重点搜ERROR和FATAL级别日志再结合崩溃时的上下文最终定位到是graphic模块在某个特定场景下发生了死锁。这个过程如果只用串口日志根本抓不全因为串口打印会丢数据而且hilog到串口是异步的时间戳对不上。3.3 HDC的连接疑难杂症速查HDC连接问题太常见了我把碰到过的几类情况整理成一张表供参考现象可能原因处理方向[E][:]...连接失败版本不匹配更新hdc客户端版本list targets列表为空USB未枚举成功换线/换USB口/查dts otg配置网络tconn超时防火墙拦截关闭PC端防火墙或放行端口执行命令卡死无返回hdcd服务异常设备端执行killall hdcd重启服务文件传输中途断开USB信号不稳改用网络连接传输大文件hdc shell报permission denied用户态权限不足确认账号或使用root镜像调试4. 第三板斧内核日志与崩溃现场——从dmesg到调用栈串口日志和HDC能解决大多数“软件逻辑”层面的问题但OpenHarmony开发里还有一种更棘手的场景内核崩溃、驱动panic、硬件访问异常。这时候你看hilog根本看不到有效信息因为日志框架本身可能已经挂掉了。真正有价值的是内核自身的日志输出——dmesg。4.1 dmesg的读取与过滤OpenHarmony基于Linux内核dmesg命令依然是可用的。系统还在正常运行但行为异常时先用它看内核日志# 查看内核环形缓冲区日志 dmesg # 只看最近的新增日志 dmesg -c # 按关键字过滤 dmesg | grep -i error dmesg | grep -i fail dmesg | grep -i irq # 带时间戳 dmesg -Tdmesg的日志量在启动阶段会非常大尤其是打开了CONFIG_DEBUG_DRIVER等调试开关的镜像驱动探测过程会打印大量信息。建议第一轮排查先用dmesg | grep -i error把明显异常的信息筛出来。如果没看到error再逐步放宽范围。这里有个经验很多驱动初始化失败只是打印probe fail不会打error级别日志所以fail关键字也值得重点搜。RK3568平台比较常见的一类问题是DMA内存分配失败。现象是某个多媒体服务启动时报错dmesg里会出现failed to allocate dma buffer之类的打印。这类问题通常和CMAContiguous Memory Allocator区域配置有关在内核dts的reserved-memory节点里调整CMA大小。你直接改应用代码没用得从内存布局层面解决。4.2 崩溃现场的调用栈分析最让人头疼的莫过于kernel panic或者Oops。OpenHarmony在RK3568上跑出这种问题串口上会打印一大段调用栈。很多人看到panic就慌其实调用栈恰恰是问题最集中的线索。调用栈的分析逻辑并不复杂从栈的最底层第一个被调用的函数往上看找到最后一个能确认是你自己代码的函数问题大概率出在那里。举个例子一次我调的RK3568网络驱动在内核启动时panic调用栈显示rk_gmac_open - phy_start - genphy_update_link问题定位到PHY驱动层我回到底板原理图一查发现PHY芯片的复位引脚和另一个外设冲突了导致PHY上电时序不对。这种问题你不看调用栈单靠读代码很难想到是硬件上的引脚冲突。遇到panic日志第一件事是完整保存现场。串口工具一般有日志记录功能直接存文件。没记录功能的至少用手机拍屏但要尽量拍全别只拍最后几行。完整的调用栈通常有几十行后面还跟着寄存器状态、异常类型这些信息。寄存器状态也很关键尤其是pc指针指向的地址范围可以从System.map或vmlinux符号表里反推是哪个函数。4.3 内核日志持久化让崩溃现场“留证”有个常见困惑是内核panic后文件系统不一定还可用日志存不下来怎么办两个思路。第一用Kernel Crash机制在内核启动参数里加上crashkernelXXM并开启pstore/ramoops# 在uboot或grub的bootargs里追加 crashkernel8M这样的话panic信息会被保存在内存的保留区域中重启后内核从/sys/fs/pstore/目录下把上次的崩溃日志恢复出来hdc shell cat /sys/fs/pstore/console-ramoops第二连接串口服务器或一台专门的日志PC长期把串口输出重定向到文件。这种方法适合需要跑长时间压力测试复现偶发问题的场景。脚本也不复杂# 循环重连串口防止设备重启导致串口断开 while true; do timeout 86400 cat /dev/ttyUSB0 /data/serial_$(date %Y%m%d).log sleep 1 done注意RK3568平台在OpenHarmony中打开pstore支持需要在内核config里加上CONFIG_PSTOREy、CONFIG_PSTORE_RAMy、CONFIG_PSTORE_CONSOLEy。默认的用户态镜像里有些是关着的可以自己编一版带pstore的内核镜像。4.4 内核态和用户态的“灰色地带”实际调试里最花时间的其实是这一类问题界面卡死、服务重启、内存持续上涨。你说内核panic了吗没有。你说完全没异常用户态的行为已经不正常了。这种问题的排查逻辑是“两头夹击”。从内核侧看重点查中断是否有堆积、内存碎片是否严重、某个线程是不是在内核态死循环。用cat /proc/interrupts看中断次数变化趋势用cat /proc/meminfo对照内存使用增长用top -H看线程CPU占用。从用户态看hidumper是OpenHarmony自带的信息抓取工具能列出当前所有进程、线程、内存使用、CPU占用等关键数据# 查看所有进程 hidumper -s # 系统整体CPU和内存 hidumper --cpuusage # 指定进程的内存详情 hidumper -p 1234我记得有一次排查系统卡顿内核侧CPU占用正常内存也不缺但界面就是掉帧。用hidumper --cpuusage一看渲染线程的CPU占用特别高追下去发现是某个特效动画的shader编译逻辑有性能缺陷。这个问题的根因完全在应用层但发现路径是从内核侧的系统负载入手再切到用户态工具精确定位。三板斧之间不是孤立的组合起来威力更大。5. 三板斧联动一次真实系统启动异常的完整排查链路单独讲完三个工具很多人还是会觉得抽象。我复盘一个真实案例把串口、HDC、内核日志结合起来走一遍完整的排查链路让大家感受一下实战中这些工具是怎么配合的。5.1 现象与初步判断项目是某款基于RK3568的工业HMI设备OpenHarmony版本是3.2 Release客户反馈有约5%的机器在冷启动时黑屏无显示但系统似乎没死因为部分机器的网络还能ping通。重启一次后大多能恢复。这种“偶发启动失败”的问题最讨厌因为它不稳定复现而且看起来跟硬件批次有关。接手后我的第一步不是去量电压、查时序而是把问题现象分类。黑屏但不死机说明内核大概率起来了Rootfs也应该挂载成功了问题可能在显示链路初始化环节。但“网络能ping通”又提示系统主要服务已经运行。所以目标缩小到显示链路初始化在这个特定硬件批次上为什么偶发失败。5.2 串口抓启动全量日志先抓一份完整启动日志。连接串口配置好1.5M波特率加时间戳保存到文件连续冷启动十次复现出一次失败。把失败日志和正常日志并排对比在显示初始化相关的位置找差异。对比发现失败时内核日志里多了这么一句dwhdmi-i2s: failed to get clk ref这个dwhdmi-i2s是HDMI的音频时钟驱动它拿不到时钟引用导致后续的HDMI初始化没有完整执行。正常启动的日志里没有这句话。5.3 HDC定位用户态状态串口日志给了方向时钟获取失败。但为什么失败需要进一步确认。此时系统已经起了一半串口上能看到init已经跑起来USB网络也能用。通过HDC网络连接进系统确认显示服务状态hdc tconn 192.168.1.123:5555 hdc shell hidumper -s # 找到显示服务进程的状态 ps -ef | grep render显示相关服务还在但处于等待状态。再用hidumper --cpuusage看负载发现有个hdmi_audio线程在反复重试CPU占用一直在跳动。5.4 内核日志补齐关键拼图继续往下追用dmesg看内核侧完整的时钟管理日志dmesg | grep -i clk dmesg | grep -i hdmi发现HDMI的audio clk在dts里配的parent clock依赖一个外部晶振而该晶振的使能GPIO恰好由另一个GPIO控制该GPIO在冷启动时高概率处于错误电平状态正常情况下uboot阶段应该拉高偶发情况下没拉起来。这个问题在正常日志里看不到因为正常时uboot已经把电平设好了内核侧的clk框架不会重新去碰这个GPIO——内核认为它已经是使能状态。而在失败场景uboot的某个操作和GPIO初始化产生了竞争导致电平没被正确设置。最后方案在uboot阶段增加对这颗晶振GPIO的显式配置确保上电就是正确电平同时内核dts里在HDMI的iommu节点附近补上该GPIO的pinctrl初始状态双保险。5.5 复盘总结这个案例如果只用串口能看到失败现象但很难定位到时钟树和GPIO的竞态问题如果只用HDC系统起一半的时候网络时通时断操作不稳定只用dmesg也看不到uboot阶段的时序。三板斧各自提供了一段信息拼接起来才还原了完整的因果链。6. 三板斧之外的沉淀把调试经验变成调试体系写完三板斧最后再说点个人层面更深的体会。工具是练出来的不是看出来的。三板斧的每一板都需要在一个又一个实际问题上打磨手感。我见过不少工程师工具背得滚瓜烂熟但遇到问题还是手忙脚乱本质上是缺少一套系统化的调试思路。我自己的调试方法论可以浓缩成四句话先复现后分析先外设后内核先日志后代码先怀疑自己再怀疑编译器。这个顺序帮我少走了很多弯路。调试观念上我觉得最重要的一点是日志意识要前置不要等出了bug再回头补日志。在OpenHarmony上写驱动或应用时从第一版代码就把关键路径的hilog打上标签统一、级别合理。等到出问题的时候你手上的日志质量直接决定你定位问题的速度。很多坑很难复现错过的日志窗口就是永远错过的线索。另外建议每个项目从第一天就建立一份《调试备忘》记录设备树选型依据、串口波特率、HDC连接命令、镜像版本号、常见启动日志特征。这东西不花多少时间但价值极大。团队成员交接、远程协作、版本回退都能在这份备忘录里快速找到答案。对RK3568平台还有一个非常实际的建议把几套典型场景的镜像都备好。一个全量用户态镜像、一个rootfs可写的调试镜像、一个带内核调试符号的镜像分别对应功能验证、深度调试、崩溃分析三种场景。切换成本远低于临时现编尤其是调试符号版本能让你在分析调用栈时直接看到函数名而不需要对着地址查符号表。这个细节能省下大把时间。OpenHarmony的生态还在快速演进板卡种类越来越多设备树选择、内核版本、工具链版本都在变化。但底层这套调试哲学是稳定的从启动的第一条日志看到业务的最后一行报错用最直接的手段逼近问题的物理本质。把串口、HDC、内核日志这三板斧用熟了无论是RK3568还是未来新的芯片平台你都能快速上手。毕竟换了平台只是换了一套命令参数调试的思路和手感才是真正值钱的东西。