很多刚接触开源鸿蒙OpenHarmony开发的朋友,拿到一块RK3568开发板之后,第一反应往往是:烧录完了,然后呢?屏幕不亮、系统起不来、外设没反应——面对一堆日志,不知道从哪里下手。我自己是从传统嵌入式Linux转过来的,刚上手OpenHarmony时也经历过一段“板子到手如同砖头”的日子。后来摸透了串口、hdc和日志这三个工具,才算是真正找到了硬件调试的抓手。
这篇文章是“万物智能之OpenHarmony系统实战开发系列教程”里专门讲硬件调试的一篇,我会把这三板斧拆开揉碎,从接线、配置、命令到实际定位案例,完整走一遍。适合刚接触OpenHarmony开发板的工程师、正在做RK3568方案验证的学生,以及从Android或LinuxBSP转过来、但对OpenHarmony调试体系还不熟的开发者。看完之后,你应该能独立完成一次从“开不了机”到“定位外设问题”的完整排查。
1. 为什么硬件调试图腾是“三板斧”:从一次起不来机的排查说起
先讲一个我实际遇到的场景。有块RK3568板子,烧录完固件之后,HDMI屏幕始终没信号,板子上的电源指示灯倒是亮的。新手遇到这种情况,大概率会先怀疑屏、怀疑固件、怀疑烧录工具,然后陷入盲目的反复重烧。但我当时做的第一件事,是找一根USB转串口线,把调试串口接上,打开终端看日志。
这一看,问题立刻浮出水面——内核日志里明确打印了DDR初始化失败,系统在bootloader阶段就停了,根本没走到内核,更谈不上屏幕驱动。这时候你就算重烧一百遍固件,问题也解决不了,因为这是硬件相关的初始化问题。反过来,如果你只看屏幕有没有亮,不去看串口日志,那就等于蒙着眼睛修车。
这件事让我彻底认同一个结论:OpenHarmony硬件调试,无论平台是RK3568还是其他芯片,核心手段都可以收敛到三样东西——串口终端、hdc通道和系统日志。我给它们起了个名字叫“三板斧”。
| 板斧 | 工具 | 能看到的层次 | 典型用途 |
|---|---|---|---|
| 第一板斧 | 串口终端 | bootloader、DDR、内核早期启动 | 起不来机、内核crash、底层初始化 |
| 第二板斧 | hdc | 用户态shell、文件系统、系统服务 | 进系统后的操作、文件推送、命令控制 |
| 第三板斧 | hilog/dmesg | 业务日志、内核驱动日志 | 服务崩溃、外设驱动、运行期异常 |
这三板斧不是互相替代的关系,而是层层递进的关系:串口负责“能不能到用户态”,hdc负责“到了用户态能不能操作”,日志负责“出问题到底是谁的锅”。下面我按使用顺序逐个展开。
2. 第一板斧:串口终端——整机启动全流程的唯一“上帝视角”
2.1 接线别接错:调试串口的硬件连接
每一块开发板都会引出调试串口,在板子上一般丝印为Debug、UART或直接标出TX、RX、GND。RK3568的开发板,比如润和的DAYU200、香橙派的OrangePi 3B,调试串口基本都是3.3V电平的UART,引脚间距通常是2.54mm排针。
你需要准备一个USB转TTL模块,市面上常见的CH340、CP2102、FT232都行。接线规则一句话:板子的TX接模块的RX,板子的RX接模块的TX,GND必须共地。这里有两个高频翻车点:一个是TX和RX接反了,表现为终端完全无输出或者输出乱码,另一个是忘记接GND,导致电平参考不一致,同样会出现乱码或者不稳定输出。
还有一点要特别注意:不要直接给串口模块的VCC接板子的3.3V。有些板子的调试串口引脚旁边就有一个3.3V电源脚,新手一看“供电”就顺手接上了。这时候如果模块和板子各自供电,一旦共地再供电,可能形成环路电流,严重时会烧掉串口芯片。我自己的习惯是:给USB转TTL模块单独供电(由USB提供),只连接TX、RX、GND三根线。
2.2 终端工具的配置与参数
硬件接好之后,需要确认USB转TTL模块在电脑上枚举成了哪个设备。在Linux环境下通常是/dev/ttyUSB0或/dev/ttyACM0,Windows下则是一个COM口,可以在设备管理器里查看。
OpenHarmony的调试串口参数,RK平台默认是波特率115200,数据位8,停止位1,无校验,无流控。在终端里我常用picocom,因为它轻量、退出方便:
sudo picocom -b 115200 /dev/ttyUSB0如果习惯用minicom,配置好后启动即可:
sudo minicom -D /dev/ttyUSB0 -b 115200Windows下推荐MobaXterm或者Xshell,新建Serial会话,选对COM口号和波特率就行。这里有个小经验:如果打开串口后敲键盘没反应,先检查串口工具是否勾选了“流控”(Flow Control),OpenHarmony调试串口默认不开流控,RTS/CTS一旦勾上,输入输出都会异常。
2.3 从串口日志看出“卡在哪里”
串口日志最大的价值,是把整个启动流程按时间顺序摊在你眼前。RK3568上电后大致会经历这么几个阶段:BootROM → DDR初始化 → U-Boot → Kernel → init进程 → 系统服务启动。每个阶段卡住,日志的特征都不一样。
- BootROM阶段:如果串口一点输出都没有,先查硬件连接,再看供电和启动介质,这个阶段基本没有软件可干预的空间。
- DDR初始化失败:经常会打印类似“DDR training failed”或者回车不断重试的信息。这时候优先查硬件,比如内存颗粒焊接、电源纹波,也可能是板子的DDR配置和固件不匹配。
- U-Boot阶段卡住:能看到U-Boot的LOGO和版本信息,但光标停在某个命令之后不再往后走。常见原因是启动参数错误、找不到启动分区、设备树选择错误。
- Kernel早期卡住:能看到内核版本和若干[ 0.000000]开头的日志,但没有后续的输出。这时候优先怀疑fdt(设备树)有问题,比如外设时钟配错、中断冲突在启动早期就触发了panic。
- init阶段卡住:内核已经跑起来了,系统进入用户态后异常,串口上往往伴随服务的反复重启日志。
判断“卡在哪里”的核心思路是:找到串口日志中最后一条有意义的输出,然后问自己,这个输出对应的模块是哪个,它之后应该发生什么。比如说,如果你看到内核已经挂载了根文件系统,之后却没有init进程的打印,那就需要查init配置和启动参数。
2.4 串口调试的几个典型坑
第一个坑是“固件关掉了串口打印”。部分商用固件为了安全或性能,默认关闭了串口控制台,只保留必要的错误输出,甚至完全静默。这时候不要怀疑串口线坏了,先看看固件配置里CONFIG_SERIAL_*相关的选项,或者拿一个官方已知正常的固件做交叉验证。
第二个坑是乱码。除了前面说的TX/RX接反和没共地之外,还有一种可能是波特率不匹配。有些板子会把调试串口配置成1500000(1.5Mbps),如果你按115200去读,大概率是乱码。遇到乱码时,先把波特率挨个试一遍,从115200、57600、1500000这几个最常用的开始。
第三个坑是日志缓冲区太小。U-Boot和内核早期日志可能因为串口速度慢导致丢日志,尤其是全量编译后第一次启动,打印量特别大,串口工具如果开了“自动换行”或者缓冲区太小,可能只看到后半段。建议在串口工具里把日志保存到文件,再从文件里搜索关键信息,不要只在屏幕上看。
3. 第二板斧:hdc通道——进入系统后的“手术刀”
3.1 hdc和ADB是什么关系
很多从Android转过来的开发者,拿到OpenHarmony板子后习惯性地敲adb shell,结果发现提示command not found。原因在于OpenHarmony的设备调试通道是hdc(HarmonyOS Device Connector),全称OpenHarmony Device Connector,功能和ADB高度相似——也是基于客户端-服务端-守护进程的架构,也能执行shell命令、推拉文件、转发端口,但命令名和部分参数并不相同。
所以正确的思路是:把你在Android上对adb的认知迁移到hdc,但具体命令要以hdc的帮助为准。在宿主机上,hdc工具通常随着DevEco Studio安装,或者从OpenHarmony官方SDK里单独获取。我习惯单独下载一个hdc_std,放到系统PATH里,因为它小巧、不依赖IDE环境。
执行hdc list targets,能看到当前连接的设备序列号,类似这样:
[Empty]如果显示Empty,先别急,大概率是设备没有开启hdc服务,或者USB枚举有问题。
3.2 两种连接方式:USB与网络
USB方式是最直观的。在OpenHarmony系统里,需要确保设备的“开发者模式”已开启,并且授权了这台电脑。设备首次连接USB时,屏幕上可能会弹出授权对话框,需要用鼠标点击允许。如果你手里的板子没有屏幕,这条路径就走不通,这时候网络hdc就派上用场了。
网络hdc的核心命令是hdc tconn,它和adb connect在概念上类似,但OpenHarmony的网络hdc需要设备端开启对应的服务端口,默认是5555。连接方式:
hdc tconn 192.168.1.100:5555 hdc list targets只要设备已经进入系统并且网络可用,不需要屏幕和USB线,就能通过网络建立hdc会话。这个能力在调试头less设备时尤其重要——毕竟很多OpenHarmony设备的最终形态是没有显示的物联网终端。
3.3 我最常用的hdc命令组合
日常调试里,我的hdc命令主要集中在下面这几类。
第一类是基本控制:
hdc shell ps # 查看进程列表 hdc shell pidof test_demo # 查看某进程的PID hdc reboot # 重启设备 hdc shell param get | grep -i version # 查看系统版本参数第二类是文件交互:
hdc file send ./local_file /data/test hdc file recv /data/log.txt ./log.txt这两个命令在替换配置文件、抓取日志时非常顺手。我以前定位问题,经常把修改好的配置文件直接推送到设备的/data目录,再通过hdc shell cp覆盖到目标位置,省去了重新烧录整个固件的漫长时间。
第三类是日志抓取,这块我放在下一节单独展开,但hdc hilog这个命令本身值得记住——它在宿主机上直接拉取设备日志,效果相当于Android里的adb logcat。
第四类是服务与状态查询:
hdc shell cat /proc/cmdline # 查看内核启动参数 hdc shell cat /proc/meminfo hdc shell dmesg | head -50 # 内核日志 hdc shell mount # 查看挂载情况尤其cat /proc/cmdline这一条,在做设备树选型和启动参数核实的时候几乎是必查项,后面第五节会再回到它。
3.4 无屏幕场景下的hdc价值
我记得有一次做带屏设备,屏幕驱动本身有问题,HDMI无输出,系统也没法通过屏幕提示状态。正常情况下你根本不知道系统到底起来没有,但hdc network方式解决了这个问题:只要板子通过网线(或Wi-Fi)连到了局域网,就算屏幕不亮,照样可以hdc tconn连进去,看系统的进程、日志和网络状态。
这件事给了我一个很重要的习惯:每拿到一块新板子,我都会第一时间把它的IP地址固定下来,并确认系统里hdc服务是正常工作的。因为串口能覆盖启动早期,但进入系统之后的调试,hdc的效率和能力上限要高得多。
4. 第三板斧:系统日志——在hilog与dmesg之间定位问题归属
4.1 OpenHarmony的日志体系分层
OpenHarmony的日志大体上分成两层:内核日志和用户态日志。内核日志由Linux内核产生,包括驱动初始化、内存管理、电源管理等信息,用dmesg查看。用户态日志由系统服务、App进程产生,统一走hilog,用hilog命令查看。
很多开发者拿到一台设备,只盯着hilog看,结果发现某个外设没有任何日志输出,误以为驱动没跑,实际上内核驱动早就probe失败了,报错在dmesg里。反过来,有些应用层服务频繁崩溃,进程反复重启,在dmesg里几乎看不到有效信息,真正的异常堆栈在hilog里。所以排查的第一步永远是先确认问题是内核态还是用户态。
或者说一个更直观的类比:dmesg是房东的眼睛,负责关注房子本身的问题——水电、墙体、地基;hilog是房客的聊天记录,负责反映住在里面的人,也就是各种服务和应用的状态。两个人鸡同鸭讲的时候,问题自然很难定位。
4.2 hilog实战:过滤、追踪与缓冲区
hilog命令的用法在各个版本上略有差异,但核心操作是通用的。我最常做的几个操作如下。
带时间戳和进程信息的全量输出:
hilog -x按关键字过滤,适合盯一个具体服务:
hilog -e "wifi_hal"按日志级别过滤,只看错误和警告:
hilog -L E # 只看error hilog -L W # 只看warning按PID过滤,适合某个进程反复崩溃的场景:
hilog -p 1234这里的难点是:日志量一旦大起来,漂屏速度极快,肉眼根本来不及看。我的做法是先把日志重定向到文件,再慢慢分析:
hilog -x > /data/hilog_all.log在hdc shell里执行完之后,再用hdc file recv把日志文件拖回宿主机分析。如果你希望实时跟踪某个模块,可以配合grep使用:
hilog -x | grep -A 20 "faultlog"4.3 一个定位案例:开机动画卡住
有次我遇到一个问题,系统开机到动画阶段就卡死,触摸屏幕没有任何响应。用串口看内核日志,发现一切正常,说明问题发生在用户态。于是通过hdc shell进入系统,执行ps发现systemui进程的PID一直在变,说明它在反复崩溃重启。
接着用hilog -p指定那个稳定崩溃的PID,配合grep过滤,看到了关键信息——某个.so库加载失败,提示缺少符号。顺着这个线索查,发现是前一天编译系统时,某模块的版本没有对齐,导致新编译出的systemui依赖了旧的动态库接口。重新编译该模块并推送镜像之后,问题解决,全程没有碰过任何硬件。
这个案例说明了日志体系的穿透力:从“现象在外设”(屏幕卡住)到“根因在软件”(动态库版本不匹配),中间隔着一整层系统服务,如果不靠hilog追到进程级日志,这种问题基本无从下手。
4.4 内核日志dmesg与驱动定位
dmesg主要面向内核驱动。在OpenHarmony上,外设驱动如果初始化失败,通常会在这类位置留下记录:
dmesg | grep -i "fail\|err" dmesg | grep -i "wlan\|sdio\|i2c\|pinctrl" dmesg | tail -100比如Wi-Fi模组无法识别,dmesg里可能出现类似“sdio: sdio_bus_probe fails”的记录;屏幕不亮,则可能看到“hdmi: failed to read edid”这类信息。这些日志虽然看起来简陋,但已经把问题方向指得很明确了:总线枚举失败,还是协议通信异常,还是EDID解析失败。
4.5 日志量过大与环形缓冲
内核的dmesg是环形缓冲,用户态hilog同样有缓冲区大小限制。调试过程如果长时间打印大量日志,早期日志可能被覆盖,导致“没看到关键信息”。
处理办法有两个:一是提前加大缓冲区,比如hilog -G 8M把日志缓冲区扩展到8MB;二是尽早开启实时抓取,把日志落盘到文件。我在做Wi-Fi吞吐相关的长时间测试时,基本固定使用后台抓日志:
hilog -x > /data/longtest.log &然后跑测试,跑完再收文件。这里有一个细节:如果设备在测试过程中突然重启,数据可能会丢失,所以重要的日志文件尽量即时回传到宿主机,不要指望设备断电后还能保留。
5. 设备树怎么选:RK3568多设备树的判断与三板斧联动
5.1 RK3568设备树现状:一个平台,N套dts
最近热搜上有个问题特别典型:“RK3568有许多设备树到底咋选”。这确实是让新手非常困惑的点。RK3568这颗芯片被非常多的开发板采用——润和DAYU200、香橙派3B、触觉智能的RK3568系列板卡、各种商业核心板——不同板卡的硬件设计不一样,外设接口、GPIO复用、供电时序都有差异,所以内核源码里为它们各自准备了一套设备树文件。
在OpenHarmony内核源码中,这些设备树文件通常在类似这样的目录下:
kernel/linux/linux-5.10/kernel/arch/arm64/boot/dts/rockchip/命名规律很直观,一般就是芯片型号加板卡名,比如rk3568-dayu200.dts、rk3568-evb.dtsi等。一个型号开发板对应一个最终的dts文件,dts会include多个dtsi公共文件。
那怎么知道你的板子该选哪一个?最重要的判断依据是板卡的硬件原理图,其次就是设备树里的配置是否和外设匹配。比如屏幕模组是MIPI DSI还是RGB屏,Wi-Fi模组是走的SDIO 3.0还是SDIO 2.0,这些信息在dts里都有体现。你手上的板子硬件长什么样,就应该手动确认dts里对应的节点。
5.2 选错设备树,日志长什么样
选错设备树通常不会导致完全不开机,因为RK3568这颗芯片的内核启动本身对设备树并不那么敏感,但外设会大面积异常。典型的症状组合是:
- 屏幕不亮,HDMI无输出或分辨率异常
- Wi-Fi/蓝牙搜不到设备
- 触摸无响应
- 以太网口速率不对
- 串口继电器之类的GPIO方向全乱
在日志层面的表现,往往是dmesg里能看到一些具体的错误。比如Wi-Fi模组识别不出来,会有“mmc1: error -110”这样的SDIO错误;屏幕不亮,会有“hdmi: failed to get edid”等打印。
最关键的是确认当前系统实际加载的设备树是哪一个。在OpenHarmony上,开机后可以这样查:
hdc shell dmesg | grep -i "machine"或者查看:
hdc shell cat /proc/device-tree/model这会打印出板卡型号字符串。比如DAYU200会显示类似“Rockchip RK3568 DAYU200 Evaluation Board”的字样。看到这个字符串,你就知道固件里选的是哪个设备树了,这比翻文档、猜配置要准确得多。
5.3 联动排查案例:Wi-Fi搜不到热点
我把三板斧串起来,还原一次完整的排查流程。
环境是:一块RK3568开发板,烧录了某个通用固件,打开设置里的Wi-Fi,始终搜不到任何热点。串口已经连上,hdc网络也通了。
第一步,用串口观察启动日志。串口输出里没有发现mmc相关错误,Wi-Fi模组供电的regulator也没有异常打印,说明从整个启动流程来看,底层硬件初始化阶段没有明显问题。这个结论很重要,它把排查重心从“内核启动阶段”推向“驱动与配置阶段”。
第二步,通过hdc shell查看网络状态:
hdc shell ifconfig -a hdc shell iw dev结果发现系统里根本没有wlan0这个网络接口,这意味着Wi-Fi驱动确实没有把设备成功注册到网络子系统。
第三步,看内核日志里和Wi-Fi相关的内容:
hdc shell dmesg | grep -i "wlan\|sdio\|mmc1"日志里出现了“mmc1: failed to send tune request”这类信息。指示SDIO总线的信号质量问题。结合开发板硬件设计想到一个问题:板子上的Wi-Fi模组电源域是1.8V还是3.3V,以及对应的IO域配置是否正确。
第四步,回到设备树,检查Wi-Fi模组的节点配置。最终发现dtsi里某个SDIO引脚的IO域配置只适用于某个特定的板卡硬件版本,而当前的硬件版本用的是1.8V。修改设备树中对应io-domains节点后重编内核,固件重新烧录,Wi-Fi正常搜到热点。
回头看,这次排查的核心路径是:先通过串口排除启动阶段的底层问题,再通过hdc确认系统层面缺失了什么,再通过dmesg锁定驱动错误,最后追溯到设备树的配置缺陷。三板斧缺一不可。
5.4 对多设备树场景的实操建议
基于上面的经验,我给刚接触RK3568和OpenHarmony的开发者几个建议。
第一,拿到板子先确认硬件版本。开发板可能有v1.0、v2.0这样的硬件版本差异,同一家板卡不同版本,设备树也可能有差异。dts最后一行的model字符串,或者板卡丝印的版本号,都要先核对清楚。
第二,自己编译固件时,产品配置和设备树是对应的。OpenHarmony的编译体系里,hb set选定产品后,产品定义文件(如rk3568.json)会指向特定的board和device配置,最终决定编译时加载哪个设备树。改产品定义或者改dts,都会影响最终固件。
第三,烧录现场验证时,不要只测一个外设。换一个设备树之后,把屏幕、Wi-Fi、蓝牙、以太网、触摸、音频等外设全过一遍,因为一个dts配置错误可能只影响某个未测试的模块,等到量产阶段才暴露就麻烦了。
第四,善用“系统实际加载板型”的检查手段,也就是前面提到的/proc/device-tree/model和dmesg里的machine字样。拿到任何第三方固件,都可以用这两个手段判断里面的设备树版本,再决定要不要拿来做开发。
6. 最后分享一点我在硬件调试上的习惯
三板斧讲完之后,再谈点个人体会。我做OpenHarmony调试这几年,最大的感受是:调试效率的高低,不取决于你会多少个工具,而是取决于你面对问题时,用什么样的顺序去推理。串口、hdc、日志,这套组合之所以叫“三板斧”,是因为它覆盖了从硬件初始化到应用服务的完整链路。
我自己的排查顺序通常是这样:先看串口日志确认系统是否到了用户态,再用hdc连进去确认系统可操作性,最后用hilog和dmesg并行定位问题归属。每走一步,都要在笔记本上记下当前的结论,比如“串口已确认内核启动正常”、“hdc已确认服务无崩溃”,避免在同一个层次反复打转。
还想提醒一个容易被忽视的习惯:日志一定要落盘。无论串口日志还是hilog,屏幕显示永远是流动的,只有保存成文件才能支持后续的搜索和对比。我经常同时开三个日志文件:一个存串口启动日志,一个存hilog业务日志,一个存dmesg内核日志,排查完问题再统一整理归档。这些日志不只是当时排查的素材,更是后续复现问题、验证修改的重要依据。
如果你刚接触OpenHarmony硬件开发,建议先把手里的板子完整走一遍“串口看启动、hdc连系统、日志查异常”的流程,哪怕没有故障,也要主动制造一个故障来练手,比如故意改错设备树里的屏幕节点,再通过日志去定位。只有亲手走通这个闭环,你才算真正过了硬件调试这一关。