RK3588 + OpenHarmony 6.1 RKNN2 NPU 验证指南

适用场景 :拿到一块新的 RK3588 + OpenHarmony 6.1 开发板,快速验证 NPU 推理是否可用。 验证结果:通过 (api 2.3.2 / drv 0.9.8 / mobilenet_v1 RK3588 版推理成功 → ALL TESTS PASSED)


0. 前置条件

项目 说明
开发板 RK3588 + OpenHarmony 6.1 标准系统(厂商镜像,基于 rockchip BSP 内核)
调试工具 hdc (HarmonyOS Device Connector),能 hdc shell
PC 编译环境 WSL2 (Ubuntu-22.04) + GCC linaro 7.5.0 aarch64 交叉编译器
RKNN2 SDK rknpu2/runtime/Linux/ 目录(含 librknnrt.sorknn_api.h
测试模型 rknpu2/examples/rknn_api_demo/model/RK3588/mobilenet_v1.rknn必须 RK3588 版,见 10.1

GCC linaro 路径(参考):

makefile 复制代码
D:\Projects\RKNN3\gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu\gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu

RKNN2 SDK 路径(参考):

makefile 复制代码
D:\Projects\rknn-toolkit2\rknpu2

1. 板端 NPU 驱动检查

通过 hdc shell 连上板子,依次执行:

bash 复制代码
hdc shell
bash 复制代码
# 1.1 NPU 驱动版本
cat /sys/kernel/debug/rknpu/version

实际输出RKNPU driver: v0.9.8 ✅(与 RK3576 完全一致,均为 rockchip BSP 内核自带)

bash 复制代码
# 1.2 NPU 设备节点
ls -la /dev/dri/renderD128

实际输出crw-rw-rw- 1 root graphics 226, 128 ... ✅(DRM GEM 方式)

bash 复制代码
# 1.3 板端 libc 类型确认
ls /lib/ld-musl* /lib/ld-linux* 2>/dev/null

实际输出/lib/ld-musl-aarch64.so.1 ✅(OH 6.1 使用 musl libc,这是后续需要 glibc 兼容层的原因)

1.4 关于 dmesg(本次实测为空输出,属正常)

bash 复制代码
dmesg | grep -i rknpu

实际输出 :空。不是驱动没加载 (1.1 的 version 节点已证明驱动在工作),而是 OH 6.1 设置了 kernel.dmesg_restrict=1,hdc shell 默认非 root 读不了 dmesg。若确需查看驱动加载日志:

bash 复制代码
hdc shell su 0 "dmesg | grep -i rknpu"

结论:此项是兜底检查,非必须,空输出不影响后续流程。

如果驱动未加载

检查内核配置:

bash 复制代码
dmesg | grep -i rknpu
zcat /proc/config.gz | grep RKNPU 2>/dev/null

若 NPU 驱动未编译进内核,需要重新编译 OH 内核并启用 RKNPU 驱动(参考 GitHub rockchip-linux/kernel develop-6.1/drivers/rknpu,RK3588 官方支持零改动,compatible = "rockchip,rk3588-rknpu")。


2. 在板端搭建 glibc 兼容环境

由于 librknnrt.so 用 GCC linaro 编译、依赖 glibc,而 OH 6.1 使用 musl,需要自带 glibc 运行时。

2.1 从 GCC 工具链提取 glibc 文件

⚠️ 实测重要经验 :hdc 连续快速 file send(间隔 1-3 秒)会把 USB 通道打挂(USBBulkCallback1 failed),与调用方式(PowerShell/cmd/Bash)无关。推送多个文件务必逐条执行、间隔 ≥5 秒、每条推完先验证大小再推下一条。最稳妥的方式是让用户在 cmd 窗口手动逐条推送(本次实测手动逐条全部成功)。详见 7.5。

在板端创建目录:

bash 复制代码
hdc shell "mkdir -p /data/glibc"

在 cmd 窗口(Win+R → 输入 cmd 回车),进入 glibc 库目录后逐条推送(每次等输出 FileTransfer finish 再执行下一条):

cmd 复制代码
cd /d D:\Projects\RKNN3\gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu\gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu\aarch64-linux-gnu\libc\lib

D:\hdc\hdc.exe file send ld-2.25.so /data/glibc/ld-2.25.so
D:\hdc\hdc.exe file send libc-2.25.so /data/glibc/libc-2.25.so
D:\hdc\hdc.exe file send libm-2.25.so /data/glibc/libm-2.25.so
D:\hdc\hdc.exe file send libdl-2.25.so /data/glibc/libdl-2.25.so
D:\hdc\hdc.exe file send libpthread-2.25.so /data/glibc/libpthread-2.25.so
D:\hdc\hdc.exe file send libstdc++.so.6.0.24 /data/glibc/libstdc++.so.6.0.24
D:\hdc\hdc.exe file send libgcc_s.so.1 /data/glibc/libgcc_s.so.1
D:\hdc\hdc.exe file send librt-2.25.so /data/glibc/librt-2.25.so

注意 :部分板子出厂 /data/glibc 可能已带 ld-2.25.solibc-2.25.so(本次实测出厂就有),推送前先 hdc shell "ls -la /data/glibc/" 查缺,避免重复。

2.2 创建 SONAME 符号链接 + 修复 ld 执行权限

⚠️ 本次实测新坑(RK3576 文档未记录) :本板出厂 ld-2.25.so 权限为 644(无执行位) ,若不修复,运行时动态链接器报 Permission denied。务必先执行 2.2 节第 1 条 chmod

在板端 shell 中:

bash 复制代码
# ★ 先修权限(本次实测必须,否则第 5 节报 Permission denied)
chmod 755 /data/glibc/ld-2.25.so

# 创建 7 个 SONAME 符号链接(libgcc_s.so.1 本身就是 SONAME,不用建)
cd /data/glibc
ln -sf ld-2.25.so               ld-linux-aarch64.so.1
ln -sf libc-2.25.so             libc.so.6
ln -sf libm-2.25.so             libm.so.6
ln -sf libdl-2.25.so            libdl.so.2
ln -sf libpthread-2.25.so       libpthread.so.0
ln -sf libstdc++.so.6.0.24      libstdc++.so.6
ln -sf librt-2.25.so            librt.so.1

2.3 验证 glibc 环境

bash 复制代码
ls -la /data/glibc/

期望 :看到 8 个 *-2.25.so 文件(全部 >0 字节)+ 7 个 *.so.* 符号链接,ld-2.25.so 权限为 755。


3. 编译推理测试程序

3.1 源文件

源文件位于 rknpu2/rknn_oh_test.c,可以作为模板直接使用。核心调用链: rknn_init()rknn_query()rknn_inputs_set()rknn_run()rknn_outputs_get()rknn_destroy()

3.2 在 WSL 中用 GCC linaro 编译

编译脚本 build_oh_test.sh 位于 rknpu2/ 目录,在 WSL 中执行:

bash 复制代码
wsl bash /mnt/d/Projects/rknn-toolkit2/rknpu2/build_oh_test.sh

实际输出 :编译成功,生成 rknpu2/rknn_oh_test(aarch64 ELF)。

编译脚本做了什么

  1. 修复 LTO plugin 符号链接缺失
  2. 在 sysroot 中用 cp 创建 SONAME 别名(DrvFS 不支持 symlink)
  3. 编译命令关键参数:
    • -Wl,-rpath-link,"$LIBC_LIB" --- 链接时找到 glibc 库
    • -Wl,--dynamic-linker=/data/glibc/ld-linux-aarch64.so.1 --- 运行时使用板端的 glibc ld
    • -Wl,-rpath='$ORIGIN:/data/glibc:/data/local/tmp' --- 运行时库搜索路径

验证编译产物:

bash 复制代码
wsl bash -c "file /mnt/d/Projects/rknn-toolkit2/rknpu2/rknn_oh_test"
wsl bash -c "readelf -l /mnt/d/Projects/rknn-toolkit2/rknpu2/rknn_oh_test | grep interpreter"

期望ELF 64-bit LSB executable, ARM aarch64 + Requesting program interpreter: /data/glibc/ld-linux-aarch64.so.1

3.3 编译常见问题

错误 原因 解决
fatal error: liblto_plugin.so not found GCC 工具链 LTO plugin 文件名不对 ln -sf liblto_plugin.so.0.0.0 liblto_plugin.so
cannot find -lpthread sysroot 缺少 SONAME 符号链接 cp libpthread-2.25.so libpthread.so.0
cannot find -lstdc++ 同上 cp libstdc++.so.6.0.24 libstdc++.so.6
cannot find -lgcc_s 同上 cp libgcc_s.so.1 libgcc_s.so

4. 推送二进制和模型到板端

4.1 推送文件

⚠️ 同 2.1 节经验:逐条推送、间隔 ≥5 秒、每条推完验证大小 。批量连续推必断线,宁可手动逐条。三条命令务必分开执行,中间用 hdc shell "ls -la ..." 验证上一条结果。

在 cmd 窗口逐条执行(每次等 FileTransfer finish 再下一条):

cmd 复制代码
D:\hdc\hdc.exe file send D:\Projects\rknn-toolkit2\rknpu2\rknn_oh_test /data/local/tmp/rknn_oh_test

D:\hdc\hdc.exe file send D:\Projects\rknn-toolkit2\rknpu2\examples\rknn_api_demo\model\RK3588\mobilenet_v1.rknn /data/local/tmp/mobilenet_v1.rknn

D:\hdc\hdc.exe file send D:\Projects\rknn-toolkit2\rknpu2\runtime\Linux\librknn_api\aarch64\librknnrt.so /data/local/tmp/librknnrt.so

注意

  • 模型必须是 model/RK3588/mobilenet_v1.rknn(本次实测 SDK 自带现成,不用 PC 端转换;RK3576 的模型在此不可用,见 10.1)
  • 若推送中断,板端会残留 0 字节 文件,重推即可

4.2 设置权限 + 验证文件就位

bash 复制代码
hdc shell "chmod 755 /data/local/tmp/rknn_oh_test /data/local/tmp/librknnrt.so"
hdc shell "ls -la /data/local/tmp/rknn_oh_test /data/local/tmp/mobilenet_v1.rknn /data/local/tmp/librknnrt.so"

实际输出(参考大小):

  • rknn_oh_test:19128 字节
  • mobilenet_v1.rknn:4693865 字节
  • librknnrt.so:7726232 字节 全部非 0 字节即就位。

5. 运行推理测试

bash 复制代码
hdc shell
bash 复制代码
cd /data/local/tmp
/data/glibc/ld-linux-aarch64.so.1 \
  --library-path /data/glibc:/data/local/tmp \
  ./rknn_oh_test mobilenet_v1.rknn

实际输出(2026-08-13 RK3588 实测)

ini 复制代码
=== RKNN OH6.1 Test ===

[1] Loading model: mobilenet_v1.rknn
    model size: 4693865 bytes

[2] rknn_init()...
    OK, ctx=366611633648

[3] Query SDK version...
    api: 2.3.2
    drv: 0.9.8

[4] Query I/O count...
    inputs: 1, outputs: 1

[5] Input tensor(s):
    [0] input: INT8 NHWC dims=[1,224,224,3] n_elems=150528 size=150528

[6] Output tensor(s):
    [0] MobilenetV1/Predictions/Reshape_1: FP16 NHWC dims=[1,1001] n_elems=1001 size=2002

[7] Running inference...
    rknn_run OK
    rknn_outputs_get OK
    output[0] first 5: 0.0001 0.0003 0.0011 0.0000 0.0000

[8] Cleanup...
    done.

=== ALL TESTS PASSED ===

6. 一键快速验证清单

按以下顺序逐项确认,全部 OK 即可判定 NPU 可用:

# 检查项 命令 通过标准
1 NPU 驱动 cat /sys/kernel/debug/rknpu/version 输出 v0.9.x
2 设备节点 ls -la /dev/dri/renderD128 存在且权限正确
3 glibc 环境 ls -la /data/glibc/ld-2.25.so 存在且有执行权限(755)
4 librknnrt.so ls -la /data/local/tmp/librknnrt.so 文件存在且 >0 字节
5 测试程序 ls -la /data/local/tmp/rknn_oh_test 文件存在且可执行
6 测试模型 ls -la /data/local/tmp/mobilenet_v1.rknn 文件存在(RK3588 版)
7 推理运行 执行第 5 节命令 ALL TESTS PASSED

7. 常见问题排查

7.1 "No such file or directory"(即使文件确实存在)

原因 :动态链接器不匹配。OH 使用 /lib/ld-musl-aarch64.so.1,而程序编译时指定了 glibc 的 ld。

确认

bash 复制代码
readelf -l ./rknn_oh_test | grep interpreter
# 应输出: [Requesting program interpreter: /data/glibc/ld-linux-aarch64.so.1]

解决:必须用 glibc 的 ld 启动:

bash 复制代码
/data/glibc/ld-linux-aarch64.so.1 --library-path /data/glibc:/data/local/tmp ./rknn_oh_test

7.2 "can't execute: Permission denied"(本次实测新坑)

现象 :执行第 5 节命令时报 /bin/sh: /data/glibc/ld-linux-aarch64.so.1: can't execute: Permission denied

原因 :本板出厂 ld-2.25.so(符号链接 ld-linux-aarch64.so.1 指向的真实文件)权限为 644,无执行位。

解决

bash 复制代码
chmod 755 /data/glibc/ld-2.25.so

排查 :先看 ls -la /data/glibc/ld-2.25.so,确认权限位是否含 x

7.3 rknn_init 返回错误

  • -1 (RKNN_ERR_FAIL):检查模型文件完整性、检查 /dev/dri/renderD128 权限
  • -4 (RKNN_ERR_DEVICE_UNAVAILABLE):NPU 驱动未加载
  • -6 (RKNN_ERR_MODEL_INVALID):模型与 SDK 版本不匹配,确认使用对应 RK3588 的模型(RK3576 模型不兼容)

7.4 rknn_server "Address already in use"

原因/dev/usb-ffs/ 被 hdc 占用,rknn_server 的 NPUTransfer 组件无法绑定 USB 通道。

结论 :rknn_server 是给 PC↔板端 USB 通信用的,RK3588 内部 NPU 推理不需要 rknn_server,直接调用 librknnrt.so 即可。

7.5 hdc 连续推送断线(本次实测新坑)

现象 :连续快速 hdc file send(间隔 1-3 秒)推到中途卡死,hdc list targets 出现 Connect server failed,hdc 日志报 USBBulkCallback1 failed, ret:2/3 循环。

根因 :连续快速 file send 会把 USB 通道打挂,与调用方式无关(PowerShell、cmd.exe、Bash 均复现;用户手动逐条推送间隔几十秒全部成功)。

预防

  1. 每条 hdc 命令间隔 ≥5 秒
  2. 每次 file send 后先验证板端文件大小,再发下一条
  3. 批量推送让用户手动逐条执行(最可靠)
  4. 推送中断后板端残留 0 字节文件,重推该文件即可,不用全重推

恢复连接(设备断电重插后):

cmd 复制代码
taskkill /F /IM hdc.exe
D:\hdc\hdc.exe start
D:\hdc\hdc.exe list targets

若端口 8710 被僵尸进程占用:netstat -ano | findstr 8710taskkill /F /PID <pid>

7.6 程序段错误 (SEGV)

可能是 --library-path 路径不完整,检查:

bash 复制代码
echo $LD_LIBRARY_PATH
# 确认 /data/glibc 和 /data/local/tmp 都在搜索路径中

8. 相关文件索引

文件 路径 用途
推理测试源码 rknpu2/rknn_oh_test.c 最小 RKNN 推理验证程序
编译脚本 rknpu2/build_oh_test.sh WSL + GCC linaro 编译
RKNN API 头文件 rknpu2/runtime/Linux/librknn_api/include/rknn_api.h 完整 C API 定义
运行时库 rknpu2/runtime/Linux/librknn_api/aarch64/librknnrt.so 7.7MB,板端部署
RK3588 模型 rknpu2/examples/rknn_api_demo/model/RK3588/mobilenet_v1.rknn 分类模型测试(RK3588 专用
YOLOv5 模型 rknpu2/examples/rknn_yolov5_demo/model/RK3588/yolov5s-640-640.rknn 检测模型测试(如有)
RKNN 驱动源码 GitHub rockchip-linux/kernel develop-6.1 分支 drivers/rknpu 内核驱动(v0.9.8,厂商镜像已带)
Reusable Skill ~/.workbuddy/skills/rknn2-oh-cross-compile/ 可复用的 AI 辅助 skill(含本指南全部新坑)

9. 架构要点备忘

scss 复制代码
┌─────────────────────────────────────────────────────┐
│  ArkTS App (OH 6.1 / LLVM+musl)                     │
│         │ 未来通过 IPC/NAPI 调用                      │
│         ▼                                            │
│  rknn_oh_test (GCC linaro / glibc)                  │
│         │ 直接链接                                    │
│         ▼                                            │
│  librknnrt.so (GCC linaro / glibc)                  │
│         │ ioctl                                      │
│         ▼                                            │
│  /dev/dri/renderD128 → NPU 驱动 v0.9.8               │
│         │                                            │
│         ▼                                            │
│  RK3588 三核 NPU (3×2 TOPS = 6 TOPS)                 │
└─────────────────────────────────────────────────────┘
  • 不要用 rknn_server:它依赖 USB-FFS,在 OH 上被 hdc 占用
  • GCC linaro 编译:所有直接调 RKNN API 的代码必须用 GCC 编译
  • 自带 glibc/data/glibc/ 是运行时基础,每块新板子都要先搭好(含 ld 权限修复)
  • RK3588 三核 :多模型并行/加速可通过 rknn_set_core_mask(ctx, RKNN_NPU_CORE_0_1_2) 启用三核

相关推荐
贾伟康1 小时前
【中国方言题库|11】HarmonyOS ArkTS 学习统计实战:计算地区学习进度与收藏数量
harmonyos·arkts·arkui·数据统计·多设备适配
m0_749690232 小时前
【寻迹校园 HarmonyOS NEXT 实战 35】先写全页面 Design Spec 再写 ArkUI:一个比赛项目的设计稿门禁实践
harmonyos·响应式设计·设计规范·arkui·ui设计
Magic-ZYJ3 小时前
HarmonyOS 日记类 App 的日期设计:本地自然日、月历与夏令时边界
华为·harmonyos·arkts·arkui·问题排查·移动端开发·独立开发者
贾伟康3 小时前
【中国方言题库|12】HarmonyOS ArkTS 题库列表组件实战:减少多地区页面重复并保证点击反馈
harmonyos·arkts·arkui·组件化·多设备适配
梦想不只是梦与想3 小时前
鸿蒙 AGC:华为开放能力管理(四)
harmonyos·agc·开发能力
大锅盖13 小时前
ArkUI声明式范式下的暗夜紫调沉浸式剧本杀组局社区:迷雾粒子双层特效与四套差异化弹框的工程化实践
华为·harmonyos
见山是山-见水是水12 小时前
鸿蒙Divider 分割线组件完全指南:内容分组、视觉分区与自定义样式
华为·harmonyos
贾伟康13 小时前
【知律|18】HarmonyOS ArkTS 权限与隐私实战:让 module.json5、功能说明和拒绝路径一致
harmonyos·arkts·隐私合规·appgallery·应用权限