瑞芯微RK3588应用程序开发全流程记录
Contents
瑞芯微RK3588应用程序开发全流程记录
起因
手头的项目是 AI 视觉识别:摄像头进画面,板上实时跑模型推理,输出检测/分类结果。这类应用对算力的要求远超普通 MCU 和入门级 SoC——CPU 软跑 YOLO 这类模型只有个位数帧率,没有实用价值,必须上 NPU。
RK3588 是国产 SoC 里做端侧 AI 推理的主流选择:6 TOPS NPU、大小核 A76+A55 八核、Mali-G610 GPU、8K 硬编解码,配合 RKNN 工具链(PC 上 rknn-toolkit2 把 ONNX/PyTorch 模型转成 RKNN 格式,板上 rknnrt 运行时执行推理)能把主流视觉模型推到实时帧率,板卡生态和中文资料也最成熟。
但跑通模型只是一半:视觉识别要变成产品,还有一整条工程链——开发环境、内核与设备树定制、烧录、应用固化、开机自启动、启动画面、显示、GPIO、各类输入。本篇把这条嵌入式 Linux 完整生命周期逐环节过一遍,内容以瑞芯微官方 Developer Guide 和 Linux SDK 的公开惯例为准,落地后逐节把"惯例"替换成"实测"。
需求
流水线覆盖嵌入式 Linux 产品的完整生命周期:
- 虚拟机开发环境建设
- SDK 编译体系与编译选项配置修改
- 设备树(dts)配置修改
- 编译与打包
- 烧录固件
- 固化应用(打进固件,而不是每次 adb push)
- 应用自启动
- 修改启动图片与启动声音
- 修改显示驱动相关配置
- GPIO 控制
- 输入设备(USB / SD / KEY)
选型:RK3588 是什么量级
| 模块 | 规格 |
|---|---|
| CPU | 4×A76 @2.4G + 4×A55 @1.8G(大小核) |
| GPU | Mali-G610 MP4 |
| NPU | 6 TOPS,RKNN 工具链(PC 端 rknn-toolkit2 转模型 + 板端 rknnrt 执行) |
| 视频 | 8K 硬编解码(RKMPP),多路 MIPI 摄像头输入 |
| SDK | buildroot / Debian / Yocto 三套,build.sh 驱动 |
| 烧录 | RKDevTool / upgrade_tool / rkdeveloptool |
| 调试串口 | ttyFIQ0,默认 1500000(后面有坑) |
| 显示框架 | DRM/KMS |
| AD 按键 | SARADC + adc-keys |
生态一句话:一个 build.sh 串三套 rootfs 体系(buildroot 精简、Debian 通用、Yocto 严格),工具链标准化程度高;但闭源组件(GPU、NPU、硬件编解码)只随厂商 SDK 发布——用主线内核/Armbian 会失去 Mali、RKNN、RKMPP 这些关键能力,做 AI 视觉产品必须走 Rockchip 原厂 SDK 或板卡厂商配套 SDK,NPU 的 rknnrt 运行库也在这一包里。
板卡生态丰富,常见的:官方 EVB、Firefly(ROC-RK3588S-PC / ITX-3588J)、腾讯 Toybrick TB-RK3588X、野火鲁班猫、Radxa Rock 5B、Orange Pi 5。SDK 优先从 FAE / 板卡厂商处获取配套版本。
虚拟机开发环境建设
- Ubuntu(SDK 推荐 LTS 版本,buildroot 对主机 glibc 有要求;太新的发行版容易在 host 工具上翻车)
- 磁盘 100GB+(kernel + buildroot + 预编译工具链全量解压后 40GB 级,编译输出还会继续膨胀)
- 内存 16GB 起——8 核 SoC 的内核 + buildroot rootfs 并行编译很吃内存,8G 容易 OOM
- 先补齐编译依赖:
sudo apt install build-essential git bc bison flex libncurses5-dev libssl-dev zlib1g-dev gawk gettext ccache
源码经共享目录 /mnt/share 只做中转,编译拷回 ext4 本地进行(hgfs 共享目录不支持符号链接、没有真实权限位,而 buildroot 里全是指向 host 工具的软链,直接在共享目录里编必出玄学错误)。
编译体系与编译选项
build.sh:一个脚本串起全流程
瑞芯微 SDK 的所有操作集中在一个 build.sh 上:
|
|
lunch 选中的是 device/rockchip/rk3588/ 下的板级 defconfig,里面是一组 RK_ 开头的变量——RK_UBOOT_DEFCONFIG、RK_KERNEL_DTS、RK_ROOTFS_SYSTEM(buildroot/debian/yocto 三选一)等。这块板"用哪份 dts、哪套 rootfs"全由它决定,自建板子的第一步就是复制一份最接近的板级 defconfig 改名。
编译选项配置修改
三层配置,各管一段:
内核配置:kernel/arch/arm64/configs/rk3588_linux_defconfig。官方推荐直接改 defconfig,或手动流程:
|
|
注意:改散落的 .config 会被下次构建覆盖,只有落回 defconfig 的改动才持久。
buildroot 配置:buildroot/configs/<板卡>_defconfig 决定 rootfs 里的包(alsa、libgpiod、你的应用),menuconfig 改完同样要 savedefconfig 回写(具体入口以手头 SDK 的 Developer Guide 为准)。
uboot 配置:u-boot/configs/rk3588_defconfig,一般不动,动到的场景多是启动 logo、串口参数这类。
设备树(dts)配置修改
dts 在哪、怎么生效
|
|
由板级 defconfig 的 RK_KERNEL_DTS 变量指定。编译后 dtb 和内核一起打进 boot.img,没有独立 dtb 分区、也不需要单独烧——改了 dts 就要重编内核、重新打包烧写。
运行时验证:
|
|
常改的节点
|
|
引脚引用是瑞芯微风格:<&gpioN RK_Pxy GPIO_ACTIVE_*>,RK_PB5 即 bank B 第 5 脚。pinctrl 子系统的行为:外设驱动 probe 时向它申请引脚,被别的节点占用即失败——引脚不工作先查 status 是否 okay、引脚分配和原理图是否对得上。
编译与打包
./build.sh 完成后产物在 output/firmware/(或 rockdev/,随 SDK 版本):
| 镜像 | 内容 |
|---|---|
uboot.img |
bootloader(含 SPL) |
boot.img |
内核 + dtb |
resource.img |
开机 logo(BMP) |
recovery.img |
恢复系统(做 OTA/恢复才需要) |
rootfs.img |
根文件系统 |
oem.img / userdata.img |
厂商资源分区 / 用户数据分区 |
update.img |
./build.sh updateimg 生成的整包刷机固件 |
分区表在 parameter.txt:一行 mtdparts 风格的布局描述,定义 uboot/boot/rootfs 各分区的起始扇区和大小。rootfs 装不下加东西时,改这里 + 重新打包。
烧录固件
日常主流程不变:选板(build.sh lunch)→ 编译(build.sh)→ 整包(updateimg)→ 烧录测试。
工具选型
| 工具 | 性质 | 说明 |
|---|---|---|
| RKDevTool | 官方,Windows | 图形界面,最常用 |
| upgrade_tool | 官方,Linux | 命令行,官方 Linux 烧写 |
| rkdeveloptool | 开源社区 | 跨平台,命令行脚本化友好,批量烧写首选 |
|
|
Loader 与 MaskRom:两种烧写模式
- Loader 模式:板子上跑着可用的 bootloader,从它进入下载态。进法:uboot 命令行输入
reset(部分板)、系统里adb reboot loader、或按住 RECOVERY/VOL+ 键上电 - MaskRom 模式:BootROM 里固化的一段 USB 下载协议,eMMC 为空、bootloader 损坏也能进,是救砖的最后防线。进法:按住 MASKROM 键上电,或短接 eMMC CLK 测试点
分不清当前在哪个模式:rkdeveloptool ld 会显示 Loader 或 MaskRom。
开发节奏:push 循环优先
按改动层级选更新方式,是整个生命周期里最重要的节奏:
| 改动类型 | 更新方式 | 耗时 |
|---|---|---|
| 应用代码 | adb push app /tmp/ && /tmp/app |
秒级 |
| 资源/配置(logo、音频、脚本) | adb push / 单分区烧写 | 秒~分钟级 |
| 内核、dts、rootfs 布局、分区表 | ./build.sh && ./build.sh updateimg 整包烧录 |
十分钟级 |
RK3588 的 Linux SDK 默认起了 adbd(USB gadget),adb reboot loader 还能把"重启进烧写模式"和 push 迭代串成一条命令流水,全程不用碰按键。
SD 启动卡
官方 SD_Firmware_Tool 把 update.img 写进 SD 卡做成启动卡,板子拨到 SD 启动优先即可——适合不动 eMMC 做验证和批量老化。
固化应用
rootfs 体系不同,固化路径随 RK_ROOTFS_SYSTEM 分岔:
buildroot(产品固件常用):
- 正规做法:buildroot 包——
package/<你的应用>/下放Config.in+Makefile(源码 tar 或 git 拉取,make规则调交叉工具链),buildroot/configs里选中BR2_PACKAGE_你的应用,装进 rootfs - 快速做法:
BR2_ROOTFS_OVERLAY指一个 overlay 目录,二进制和启动脚本直接按目标路径摆进去
Debian(开发/通用场景):走 rootfs 定制脚本(Debian rootfs 是 mk-rootfs 一类脚本在 PC 上 chgroup/debootstrap 出来的),把应用和 systemd 单元写进脚本;也可以 apt 打私有源。
交叉编译器在 prebuilts/ 下(aarch64-buildroot-linux-gnu- 前缀):
|
|
应用自启动
buildroot(busybox init):/etc/init.d/S99app_launcher,序号排最后保证 DRM 设备、声卡、input 都就绪后再起应用:
|
|
Debian(systemd):写 unit:
|
|
systemctl enable 后开机自启。图形应用注意:RK3588 上 /dev/fb0 是 DRM 的 fbcon 兼容层,不是原生 framebuffer,Qt 程序 QT_QPA_PLATFORM=linuxfb 能跑,但正式产品建议直接走 DRM/KMS 或 Wayland,才能吃到多层合成与 GPU——对视觉识别应用来说,视频层 + UI 层 + 检测框叠加正是 DRM 多平面合成的用武之地。
修改启动图片和启动声音
启动画面分三层,瑞芯微的实现机制如下:
1. bootloader logo:resource.img 里的 logo.bmp,uboot 阶段显示。换图:替换 logo.bmp 后重新生成 resource.img 打包;调试期也可以只烧 resource 分区(rkdeveloptool 单分区写入),不必整包。
2. 内核 logo:resource.img 里的 logo_kernel.bmp,由内核 fbcon 显示。产品一般把它做成纯黑,衔接 bootloader logo 和应用首帧,避免闪企鹅/花屏。
3. 开机动画与开机音:SDK 的 bootanimation 组件(动画 zip + 配套音频,放 rootfs 指定目录,具体路径随 SDK 版本);最稳的做法仍然是自启动脚本里 aplay 播开机音后拉起主程序:
|
|
RK3588 音频走 ALSA(codec 挂 I2S,dts 里 rk809-codec/es8388 之类),aplay -l 先确认 card 设备号再写脚本。
修改显示驱动相关配置
RK3588 的显示框架是 DRM/KMS(不是传统 framebuffer):多视频端口 + 多输出控制器 + 多图层合成,对视觉识别产品(视频层叠 UI、检测框)是刚需能力。
dts 侧
RK3588 显示子系统是"4 个视频端口(vp0-vp3)+ 多种输出控制器(2×HDMI、2×MIPI DSI、eDP、LVDS)“的矩阵,dts 里要指定哪个 vp 接哪个控制器、什么时序:
|
|
MIPI 屏则是 dsi 节点 + panel 子节点(panel-init-sequence 一串 DCS 初始化命令,屏厂 datasheet 给多少抄多少)+ backlight PWM。
调试
|
|
dri/0/summary 是 RK 排显示问题的招牌命令——时序对不对、控制器挂没挂、vp 有没有分配,一眼全出来。黑屏排查顺序:summary → 电源/背光量波形 → panel init 序列。
GPIO
用户空间访问 GPIO 用 libgpiod(gpiodetect / gpioinfo / gpioset),编号规则:
- 5 个 bank:
gpiochip0GPIO4),每 bank 32 线gpiochip4(GPIO0 - 组内:A0-A7=0-7,B0-B7=8-15,C=16-23,D=24-31
- 全局线号 = bank×32 + 组内偏移,如
GPIO1_B5= 32+8+5 = 45
|
|
dts 里被 pinctrl 声明占用的脚无法再从用户空间申请(gpioinfo 的 consumer 字段可查占用者);LED/继电器大电流负载一律加三极管或驱动芯片。
输入:USB / SD / KEY
USB
RK3588 的 USB3.1 控制器是 dwc3,host/device 双 role。U 盘热插拔:插上后枚举出 /dev/sda1,mdev/udev 负责自动挂载;adb push 迭代应用。USB3 的读写带宽足够 4K 视频素材直读,视觉产品的素材盘、模型盘都够用。
SD 卡
sdmmc 节点 + cd-gpios 插拔检测,设备 /dev/mmcblk1p1。两个用途:数据卡(模型文件、媒体资源库)和启动卡(SD_Firmware_Tool 制作)。
KEY(按键)
GPIO 直连:dts 配 gpio-keys,内核生成 /dev/input/event*,evtest 验证:
|
|
SARADC 按键(AD 分压按键):一根 AD 脚挂一串不同阻值的分压电阻,一个电压区间对应一个键,省 IO。dts 用 adc-keys 节点 + io-channels = <&saradc> + 毫伏/键值表。
用户空间读法:read() /dev/input/event* 拿 struct input_event,EV_KEY + value 1/0 分按下/抬起。前提是内核开了 Event interface(CONFIG_INPUT_EVDEV),否则连 /dev/input/event* 都不会出现。
踩坑记录与注意事项(预研版)
以下是按公开资料预判的高频坑,落地时逐条验证替换为实测:
- 串口 1500000:RK 默认调试口是
ttyFIQ0@ 1500000,很多 USB 转串口不支持这个波特率——买串口线先确认;连不上串口先怀疑波特率,不是驱动 - 主线内核陷阱:Armbian/主线能点亮系统,但 Mali GPU、RKNN NPU、RKMPP 硬编解是闭源组件,只随厂商 SDK 发布;做产品老老实实用原厂 SDK
- 改
.config不生效:内核/buildroot 配置必须 savedefconfig 落回各自 defconfig,散改会被下次构建覆盖 - 烧不进去分不清状态:
rkdeveloptool ld看是 Loader 还是 MaskRom;两都不是就按住按键重新上电 - uboot 损坏救砖:MaskRom 模式 + 烧 uboot.img(eMMC CLK 测试点短接进法提前在图纸上标好)
- 单分区烧错扇区:
wl的起始扇区必须查parameter.txt对应分区,抄错分区表会互相覆盖 - 黑屏先看 summary:
/sys/kernel/debug/dri/0/summary一条顶十条,先确认 vp/控制器/时序再量硬件 - fb0 语义差异:RK3588 的 fb0 是 DRM 兼容层,不是原生 fb;从其他 fb 平台移植来的应用(DMA 直写、多 buffer)行为可能不同,重活建议迁 DRM
- buildroot 编译机内存不足:8G 内存 -j8 会 OOM,加 swap 或减并发
- 一切启动问题先看串口:1500000 的 log 从 BootROM 一路打到应用,是唯一全链路现场
Author 软件开发大郭
LastMod 2026-09-06