公司动态

硬件调试三板斧—【万物智能之开源鸿蒙OpenHarmony系统实战开发系列教程】

📅 2026/9/1 17:35:50
硬件调试三板斧—【万物智能之开源鸿蒙OpenHarmony系统实战开发系列教程】
会刷之后日常就三件事。今天把串口、hdc、编译机的职责分开——系统还没起来时hdc 不会有设备只能靠串口。板子黑着USB 线插着你不知道该骂哪一头。Windows 上 DevEco 说hdc list targets空Linux 上./build.sh刚编完串口工具里一片乱码。三件事其实是三条独立的路任何一条都能单独活着没有桌面串口照样能出sh没有串口hdc 照样能推文件没有 hdc整包照样能刷。把它们缠成「插上 USB 就全通」排障会从第一分钟开始猜。这块 RK3568 板上调试控制台是 UART2节点ttyS21500000 8N1。hdc 走 OTG 口上的hdcd。编译在 Ubuntu应用和多数 hdc 操作在 Windows。两台电脑一台板是这套系统最省事的拓扑也是hdc端口被抢、文件不知道在哪台机器上的根源。产品名rk3568_evb。官方 hdc 说明使用指导。1. 三条线三种职责flowchart LR L[Ubuntu 编译机] --|共享盘镜像 / .ko / hap| W[Windows] W --|OTG ROCKUSB / hdc| B[RK3568 板] W --|USB 转串口 1500000| B L -.-|可选同网 nc| B线插哪干什么系统没起来时还在吗USB 转串口底板 UART / DEBUGUART2U-Boot、printk、# 提示符在。BootROM、DDR 训练也走这里USB 数据线底板 **OTG / DEVICE**不是 HostMaskrom 刷 eMMC起来之后 hdcMaskrom 阶段是 ROCKUSB不是 hdc读卡器电脑不插板给 SD 写整包与板是否开机无关Host 口给 U 盘、USB 相机、USB 网卡。OTG 口反过来板当从机。插错的表现电脑毫无反应设备管理器不刷新你却去重装驱动。充电线不能传数据同一症状。换线、换口、认丝印十分钟怀疑芯片十天。串口是 3.3 V TTL。5 V 模块有可能打坏 SoC 脚。GND 对 GNDTX 对板 RXRX 对板 TX。接反的表现是完全没字和波特率错、没供电很难一眼分开。先确认转接芯片在设备管理器里出现再对调 TX/RX 试一次。2. 串口1500000 8N1回车出 sh1500000 不是笔误。芯片 UART 时钟分频在这块板上的常用值U-Boot 和内核约定好了。填 115200电平和连线全对窗口里只是乱码或空白。很多人在这里耗一个晚上。项值填错会怎样设备UART2 / ttyS2Windows 上是 COMx打开失败或打开了没数据波特率**1500000**乱码像板子没起数据位8偶发错字校验None大量错字停止位1错字流控**None**默认 RTS/CTS 时能收几个字然后卡住回车发不出去板子 UART2 没接 RTS/CTS。工具若默认硬件流控TX 等一个永远不来的 CTS看起来像「串口只能看不能敲」。关掉流控。Windows 上 PuTTY、MobaXterm、安全 CRT 都可以。Linux 上# 查看转接芯片 ls -l /dev/ttyUSB* /dev/ttyACM* # picocom sudo picocom -b 1500000 /dev/ttyUSB0 # 退出Ctrl-A Ctrl-X # 或 screen有的发行版 screen 对非标准波特率不友好优先 picocom sudo picocom -b 1500000 --omap crcrlf /dev/ttyUSB0上电后正常顺序DDR ... V1.16 ... U-Boot ... Hit any key to stop autoboot Starting kernel ... [ 0.000000] Booting Linux on physical CPU 0x0000000000 ... ... #内核起来之后init 拉console服务。公版console.cfg常是disabled:1加ondemand:true默认不起。板级必须在init.rk30board.cfg的 boot 段写start console写在init.rk3568.cfg里等于没写。ohos.boot.hardwarerk30boardinit 只 import 这个后缀。写对了敲回车出现#或/ #。# uname -a Linux localhost 5.10.xxx #1 SMP PREEMPT ... aarch64 # param get ohos.boot.hardware rk30board # cat /proc/cmdline consolettyS2,1500000n8 androidboot.hardwarerk30board ...噪声多、刷屏影响看字# echo 1 /proc/sys/kernel/printk排完再改回去或重启恢复。dmesg的 ring 仍在只是不再往控制台喷。串口能看、敲回车没人理按这个顺序排不要先换线流控是否关掉TX/RX 是否接反能看不能敲经常是 TX 没接到板 RX板的 TX 倒是接到了你的 RXps | grep sh有没有 console 拉起的 shellgrep start /vendor/etc/init.rk30board.cfgconsole服务对应/system/bin/sh。SELinux enforcing 时也可能把控制台卡住这块板 bring-up 常用enforcing0。3. 测其它 ttymicrocom别占用调试口UART2 是调试控制台。外设模组挂在 uart0 / uart3 / uart7 / uart8 上对应/dev/ttyS0、ttyS3、ttyS7、ttyS8。在已经有#的那条调试口里用 microcom 打开另一条。板上 toybox 带microcom# ls -l /dev/ttyS0 /dev/ttyS3 /dev/ttyS7 /dev/ttyS8 # cat /proc/tty/driver/serial/proc/tty/driver/serial里没有0:这一行说明 uart0 没 probe节点即便ls看得到也可能是假文件。先把设备树和抢脚处理完再谈收发。原始 8N1、无流控115200# microcom -s 115200 /dev/ttyS79600不少 GPS / LoRa 模组# microcom -s 9600 /dev/ttyS7退出Ctrl-X。有的版本是Ctrl-A Ctrl-X先试前者。不要cat /dev/ttyS7。cat 不设 termios波特率、raw 模式都是默认二进制帧会被 canonical 处理切碎。也不要echo AT /dev/ttyS7当调试手段——echo 不设波特率还可能在节点不存在时建假文件。自己写一个最小收发比 microcom 好留日志。用户态必须 32 位 musl/* uart_raw.c 板上: /data/uart_raw /dev/ttyS7 115200 */ #include fcntl.h #include stdio.h #include stdlib.h #include string.h #include termios.h #include unistd.h static speed_t to_speed(int b) { switch (b) { case 9600: return B9600; case 115200: return B115200; case 1500000: return B1500000; default: return B115200; } } int main(int argc, char **argv) { if (argc 3) { fprintf(stderr, usage: %s /dev/ttySN baud\n, argv[0]); return 1; } int fd open(argv[1], O_RDWR | O_NOCTTY); if (fd 0) { perror(open); return 1; } struct termios t; if (tcgetattr(fd, t) 0) { perror(tcgetattr); /* Not a tty 假文件或没 probe */ return 1; } cfmakeraw(t); speed_t sp to_speed(atoi(argv[2])); cfsetispeed(t, sp); cfsetospeed(t, sp); t.c_cflag | CLOCAL | CREAD; t.c_cc[VMIN] 0; t.c_cc[VTIME] 10; /* 1s */ if (tcsetattr(fd, TCSANOW, t) 0) { perror(tcsetattr); return 1; } char buf[256]; for (;;) { int n read(fd, buf, sizeof buf); if (n 0) write(STDOUT_FILENO, buf, n); } }tcgetattr报Not a ttyls -l看是不是-rw普通文件。是就删掉回头查为什么驱动没建字符设备。调试口自己不要用 microcom 打开/dev/ttyS2。你正在这条口上敲命令再抢它shell 和 microcom 互相吃字符看起来像板子死了。4. hdc设备号、shell、传文件系统进到用户态hdcd起来OTG 插着 Windows或 Linux电脑侧hdc kill hdc start hdc list targets应打出一串十六进制例如ab0122454d41325245135dbd94d6bc00Empty或空白hdcd 没起、线插在 Host、驱动认成了别的设备、两个 hdc server 在抢。板上# ps | grep hdcd # netstat -lptn | grep 8710常用命令官方文档更全下面是每天用的那几个hdc shell hdc shell uname -a hdc shell param get ohos.boot.hardware hdc file send D:\ohos\boot_linux.img /data/local/tmp/boot_linux.img hdc file recv /data/local/tmp/p4.read D:\ohos\p4.read hdc install D:\hap\entry-signed.hap hdc uninstall com.example.foo hdc hilog hdc hilog -x hdc fport ls hdc tmode port hdc target boothdc shell进的是板上的 sh和串口那个 console 不是同一个会话但看到的文件系统是同一份。串口被 printk 刷屏时用 hdc shell 更干净。file send远端用/data/local/tmp/。只读分区 send 过去可能报成功、复位后消失。大文件看大小hdc shell ls -l /data/local/tmp/*.img和主机dir的字节数比不够就重发不要 dd 半截 system.img。Windows 上 hdc.exe 常见路径C:\Users\you\AppData\Local\OpenHarmony\Sdk\11\toolchains\hdc.exeDevEco 也带一份。两份同时跑就是下一节的端口问题。5. hilog 和 dmesg 不是一个桶内核 printk 进dmesg也进串口级别够的话。用户态 SA、HDF host、ArkTS、相机 HAL走hilog。你在dmesg里找HiLog标签、在 hilog 里找gpio-wdt probe都会觉得「驱动没打日志」。# dmesg | tail -50 # dmesg | grep -iE hdmi|vop|gt911|i2c|uart # hilog | grep -i hdf | headhdc 上hdc hilog D:\ohos\hilog.txt hdc shell hilog -x hdc shell hilog -b Ddmesg的 ring 大约几百 KB开机 audit 噪声能把它冲掉。关心 probe 失败时起来之后立刻抓不要先玩十分钟再翻。# dmesg -c /data/local/tmp/boot.dmesg # hdc file recv 之前先在 hdc 里把文件拉走区分口诀你在查用谁驱动 probe、-22、pin already requesteddmesg/sys /dev 节点有没有串口或 hdc shellHDF Bind/Init、HDI、Ability、相机 pipelinehiloginit 挂载、fstab wait串口init 往 console 打 hilog相机预览花屏那类问题内核 uvcvideo 枚举成功只说明 USB 层活着花屏在用户态节点里hilog 才看得到。LED 不亮、uart0 没 tty先 dmesg。6. 两台电脑一台板日常拓扑Ubuntu 源码、./build.sh、pack、增量 make M、sign-file 产物放到共享盘 /mnt/hgfs/share/ 并写 md5 Windows DevEco 编 hap、签名、hdc、串口工具、SDDiskTool、RKDevTool 从共享盘取 sd_image.img / .ko / .hap RK3568 OTG 插 Windows 串口插 Windows 以太网可选给 nc 拉文件为什么不把 hdc 放 Linux、把编译放 Windows标准系统现阶段不在 Windows 上编内核hap 的 IDE、瑞芯微刷机工具、DriverAssistantWindows 更省事。OTG 同时插两台电脑做不到。认这一条板的 USB 调试只属于 Windows。Linux 编出来的.ko要上板Ubuntu --共享盘-- Windows --hdc file send-- /data/xxx.ko --insmod--板和 Ubuntu 同网段、板上有nc时可以跳过 Windows# Ubuntu python3 -m http.server 8000 --bind 0.0.0.0 # 板上没有 wget用 toybox nc 拼 HTTP 很脆ftpget 若在 # ftpget -u user -p pass 192.168.3.10 driver.ko driver.ko多数时候共享盘更稳。源码不要放共享盘上编只丢产物。拷完两端对哈希不对就不要file send# Ubuntu md5sum /mnt/hgfs/share/boot_linux.img /mnt/hgfs/share/resource.img \ /mnt/hgfs/share/vendor.img /mnt/hgfs/share/system.imgcertutil -hashfile D:\ohos\boot_linux.img MD5 certutil -hashfile D:\ohos\resource.img MD5Windows 资源管理器能看见文件不等于字节完整。hgfs 大文件偶发拷残大小对、哈希不对时再拷一遍。Windows 侧hdc shell里管道要引号包死否则 cmd 自己吃掉|hdc shell dmesg | grep uart hdc shell cat /proc/tty/driver/serial少了引号Windows 会本地 grep然后说找不到文件。7. HDC_SERVER_PORT两个 server 抢一台板DevEco 启动时会拉起自己的 hdc server。你在 cmd 里再hdc start默认都听8710。后启动的那个把前一个挤掉或者两个都在、设备挂在你没在看的那一个上。表现DevEco 能装 hapcmd 里hdc list targets空cmd 能 shellDevEco 一直 Connectinglist targets闪一下又 Empty处理同一时刻只留一个 server。命令行要用时先关掉 DevEco 的调试服务或给命令行换端口。REM 只给这份 cmd 用 18710DevEco 继续 8710 set HDC_SERVER_PORT18710 hdc kill hdc start hdc list targets设备只能连一个 server。板插着的时候先hdc list targets看它在哪边再在那边操作。不要两个窗口同时hdc kill。Linux 编译机若也装了 hdc、也插过这根 OTG虚拟机直通 USB会再出现第三个 server。虚拟机 USB 直通一旦勾上这根线Windows 侧设备管理器里板子会消失。调试期不要把 OTG 直通给 Ubuntu除非你决定 hdc 全部改去 Linux。看电脑侧谁在听netstat -ano | findstr 8710PID 对到任务管理器多余的 hdc 进程结束掉。8. 没有 shell 的时候late_initcall 诊断hdc 没起来、console 服务没开、你又不能在板上敲命令——早期 bring-up 或某次 init 崩在一阶段会落到这个状态。诊断不能做成「我发你一个用户态程序」没有进程能跑它。做成内核模块late_initcall在大部分驱动 probe 之后跑pr_err打到串口。串口只收不发时这是唯一的读数手段。骨架板级device/board/rk/rk3568_evb/kernel/diag_i2c.c构建时拷进drivers/misc/#include linux/delay.h #include linux/i2c.h #include linux/module.h #include linux/workqueue.h #define TAG BOARD_DIAG: static void diag_work_fn(struct work_struct *w) { struct i2c_adapter *adap; int addr, ret; u8 b; msleep(3000); /* 等 HDF / i2c 控制器起来 */ adap i2c_get_adapter(2); /* i2c2按你要扫的总线改 */ if (!adap) { pr_err(TAG no i2c-2\n); return; } for (addr 0x08; addr 0x77; addr) { struct i2c_msg msg { .addr addr, .flags I2C_M_RD, .len 1, .buf b, }; ret i2c_transfer(adap, msg, 1); if (ret 1) pr_err(TAG ack 0x%02x val0x%02x\n, addr, b); } pr_err(TAG scan done\n); i2c_put_adapter(adap); } static DECLARE_DELAYED_WORK(diag_work, diag_work_fn); static int __init diag_init(void) { pr_err(TAG scheduled\n); schedule_delayed_work(diag_work, msecs_to_jiffies(4000)); return 0; } late_initcall(diag_init); MODULE_LICENSE(GPL);Kconfig / Makefile 由build_kernel.sh注入CONFIG_BOARD_DIAGy。前缀用固定字符串BOARD_DIAG:串口再乱也能 grep。# 主机侧从串口日志里滤 grep BOARD_DIAG uart.log交付镜像不要留这种模块。它会在每趟开机扫总线拖慢启动也干扰真驱动。调通就删节点、关 CONFIG。gpio / 寄存器同理pr_err打gpiod_get_raw_value或readl。用户态/dev/mem在有 shell 之后更方便没 shell 时不要指望它。有 shell 之后同一件事用现成节点# i2cdetect -y 2 # cat /sys/kernel/debug/gpio # cat /proc/device-tree/serialfdd50000/statusCONFIG_I2C_CHARDEVy才能i2cdetect。debugfs 先挂# mount -t debugfs none /sys/kernel/debug9. 用户态是 32 位 musl内核是 aarch64uname -a打出aarch64。那是内核。.ko、设备树、vmlinux 按 64 位 ARM 走。用户态不是。板上没有 aarch64 的 musl 加载器。有的是/system/lib/ld-musl-arm.so.1没有/system/lib64/ld-musl-aarch64.so.1。/system/bin/sh、toybox、你丢上去的小工具都应当是ELF 32-bit ARM动态链接解释器指到上面那个路径。编错的两种死法报错都不提 arch你编出来的板上表现aarch64 动态No such file or directory。shell 找不到 64 位解释器像路径写错aarch64 静态Signal 11退出码 139armv7 静态 musl也可能段错误或链接期缺符号。这套 musl 静态不作为日常选项armv7 动态没指定解释器主机默认解释器不是 /system/lib/ld-musl-arm.so.1上板仍是 No such file正确的编译器在源码树预编译工具链里不是系统自带的aarch64-linux-gnu-gcc也不是 glibc 的arm-linux-gnueabihf-gccCCprebuilts/clang/ohos/linux-x86_64/llvm/bin/armv7-unknown-linux-ohos-clang SYSROOTprebuilts/ohos-sdk/linux/11/native/sysroot $CC --sysroot$SYSROOT \ -o hello hello.c \ -Wl,--dynamic-linker/system/lib/ld-musl-arm.so.1主机上确认file hello readelf -h hello | grep -E Class|Machine readelf -l hello | grep interpreter期望ELF 32-bit、ARM、interpreter/system/lib/ld-musl-arm.so.1。然后拷到共享目录对 md5Windowsfile send到/data/local/tmp/hellohdc shell ls -l /system/lib/ld-musl-arm.so.1 hdc shell chmod 0755 /data/local/tmp/hello hdc shell /data/local/tmp/hellohdc shell有时会吞掉秒退进程的 stdout。程序自己把结果写/data/local/tmp/hello.log再cat比只靠printf稳。.ko仍然按内核 arch 编ARCHarm64。用户态工具和内核模块不能共用一条 clang 命令。同一块板两种 ABI混了就按上面那张表死。板上不一定有file。把二进制file recv回主机再看或在主机编完立刻file不要等上板。上文uart_raw.c也按这条命令编。这块板的dw-apb-uart对VTIME超时不可靠正式收发用非阻塞加pollUART 总线那篇写。10. 一次最小验收十分钟内能做完板子上电串口开着OTG 插着 Windows。串口回车出现 # 串口uname -a 是 5.10 aarch64 串口param get ohos.boot.hardware rk30board Windowshdc list targets 有设备号 hdc shell echo hdc_ok hdc file send 一个小文本 /data/local/tmp/a.txt hdc shell cat /data/local/tmp/a.txt hdc hilog 能刷出几行 dmesg | head 能看见 Booting Linux全部绿灯三板斧就在你手上。缺串口Maskrom 和 panic 你会瞎缺 hdc单分区和 hap 你会回到整包缺编译机改一行 dts 你只能等别人打镜像。11. 失败判断乱码。波特率。先改 1500000再怀疑线。有字回车没反应。流控TX 没接上console 服务没 start改错了init.rk3568.cfg。完全没字。供电、TX/RX 反、插错口、DDR 训练就停了loader 版本启动链那篇、USB 转串口驱动没装。hdc list targets空串口正常。OTG 口、hdcd、HDC_SERVER_PORT、充电线、虚拟机 USB 直通把设备抢走。DevEco 和 cmd 抢设备。只留一个 server或给 cmd 换HDC_SERVER_PORT。hdc shell dmesg | grep uart在 Windows 上报错。引号没包住cmd 本地执行了 grep。microcom 打开 ttyS2。你把调试口抢了。开 ttyS7。tcgetattr: Not a tty。假文件。ls -l删查 probe。dmesg 没有你加的 printkhilog 也没有。分桶。内核用 dmesg用户态用 hilog。还没有多半没编进这次镜像。late_initcall 里 i2c_get_adapter 返回 NULL。延迟不够控制器还没 probe。msleep加大或对具体platform_device做 defer。不要改成pure_initcall那时总线更不存在。自编工具No such file or directory路径明明在。ls /system/lib/ld-musl-arm.so.1主机file。编成了 aarch64 动态找不到 64 位加载器。自编工具立刻 139。多半是 aarch64 静态。.ko能insmod不代表同目录的用户态 ELF 能跑——模块是 64 位用户态要 32 位。三板斧的验收不是「工具都装了」。验收是串口能敲命令、hdc 能推文件、两台电脑不会抢同一根 OTG。少一条后面改 dts、改驱动、装 hap 都会把时间浪费在通道上而不是浪费在问题上。系列第 10 篇 · 芯片瑞芯微 RK3568 · OpenHarmony 4.1API 11 · Linux 5.10