
1. 为什么一块2016年的开发板至今还有人学第一次接触RK3399是在一个做边缘计算设备的项目里当时团队要选一颗能跑双屏异显、还要带NPU做轻量推理的主控。翻了一圈市面上的方案全志H6性能够但接口少树莓派4还没出最后锁定在RK3399上。这颗芯片是瑞芯微2016年发布的六核big.LITTLE架构双核Cortex-A72加四核Cortex-A53GPU是Mali-T860MP4放到今天看参数不算亮眼但它的接口丰富程度和资料沉淀让它在工控、商显、教育硬件这些领域一直有生命力。很多人学RK3399是被逼的——公司项目要用或者买了一块板子想跑通某个外设。但学着学着就发现这颗芯片能讲的东西太多了从uboot移植、kernel裁剪、设备树配置到GPU驱动、VPU硬解、NPU调用再到Android和Linux双系统的适配几乎涵盖了嵌入式Linux的完整链路。它不像那些一键烧录就能跑的玩具板你想改点东西就得真正理解启动流程和驱动模型。这篇内容适合三类人一是刚拿到RK3399开发板、不知道从哪下手的新手二是做过其他ARM平台、想迁移到RK3399的工程师三是需要评估RK3399是否适合自己项目的技术选型者。我会从整体思路讲到具体实操把踩过的坑和验证过的方案都摊开说尽量让你少走弯路。2. 学习RK3399之前必须想清楚的几件事2.1 你到底要学哪个层面RK3399的学习路径分叉很早你得先明确目标。如果只是想在板子上跑个应用那学会烧录固件、配置网络、交叉编译就够了一两天能上手。但如果要做板级支持包开发比如换一块屏幕、加一个传感器、改一个电源管理策略那就得深入uboot和kernel。再往上如果要做系统级定制比如裁剪Android、适配新的文件系统、优化启动速度那涉及的面就更广了。我见过不少人一上来就啃TRM技术参考手册两千多页的PDF看到第三章就放弃了。正确的做法是带着问题去查手册而不是通读。比如你要配置一个I2C设备那就去查I2C控制器的寄存器章节和时钟树部分其他章节暂时不用管。2.2 硬件选型的几个关键点市面上的RK3399板子五花八门选板子的时候有几个参数必须看参数项推荐配置原因内存4GB LPDDR42GB跑Android会紧张4GB是甜点存储eMMC 16GB以上比SD卡稳定读写速度快一个量级调试口板载USB转串口省去额外买调试线的麻烦电源支持DC和Type-C供电调试时Type-C方便量产用DC扩展接口40pin排针PCIe方便接外设和做扩展实验有些板子为了压缩成本省掉了调试串口这个对新手很不友好。串口是你看启动日志的唯一窗口没有它你连uboot跑到哪一步都不知道。2.3 开发环境的搭建逻辑RK3399的开发环境分两部分主机端和目标板端。主机端建议用Ubuntu 18.04或20.04太新的版本有些老工具链会出兼容问题。需要装的工具包括sudo apt-get install repo git-core gitk git-gui gcc-arm-linux-gnueabihf \ u-boot-tools device-tree-compiler gcc-aarch64-linux-gnu mtools parted \ libudev-dev libssl-dev python3 python3-pip这里有个细节RK3399是64位芯片但uboot阶段可能用到32位工具链所以两个架构的交叉编译器都要装。另外repo工具是拉取SDK用的瑞芯微的SDK用repo管理多个git仓库手动clone会漏掉依赖。目标板端就是你的开发板本身需要准备一张至少8GB的TF卡做启动盘以及一根USB Type-A转Type-C的数据线用于烧录。有些板子支持Maskrom模式按住恢复键上电就能进入烧录状态这个后面实操部分会细说。3. 从零跑通第一个系统的完整流程3.1 获取SDK与目录结构解读瑞芯微官方SDK通过repo管理拉取命令大致是这样mkdir rk3399-sdk cd rk3399-sdk repo init -u https://github.com/rockchip-linux/manifests -b master repo sync -j8同步完成后你会看到一堆目录新手容易懵。核心目录就几个u-boot/引导程序源码负责初始化DDR、加载kernelkernel/Linux内核源码驱动都在这里buildroot/或debian/根文件系统构建脚本device/rockchip/板级配置包括分区表、打包脚本rkbin/预编译的二进制比如DDR初始化固件、BL31rkbin这个目录特别重要里面是闭源的DDR训练固件和ARM Trusted Firmware。很多人编译报错就是因为rkbin没同步全或者版本和uboot不匹配。3.2 编译uboot的关键配置进入u-boot目录后先选配置make ARCHarm CROSS_COMPILEaarch64-linux-gnu- rk3399_defconfig然后根据你的板子修改configs/rk3399_defconfig常见的改动点包括CONFIG_DEFAULT_DEVICE_TREE指定设备树文件名CONFIG_SYS_MMC_ENV_DEV环境变量存在哪个设备CONFIG_BOOTDELAY启动延时调试时设长一点方便进命令行编译命令make ARCHarm CROSS_COMPILEaarch64-linux-gnu- -j$(nproc)生成的u-boot.bin和u-boot.itb在根目录下。注意RK3399用的是FIT格式的uboot镜像u-boot.itb才是最终烧录的文件u-boot.bin只是中间产物。注意如果你改了DDR频率或者时序必须同步更新rkbin里的DDR初始化固件否则uboot阶段就会挂死串口没有任何输出。3.3 内核编译与设备树修改内核编译相对标准化make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- rockchip_defconfig make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- rk3399-evb.dtb make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- -j$(nproc)设备树文件在arch/arm64/boot/dts/rockchip/下面你的板子对应哪个dtb要看具体型号。改设备树是RK3399开发中最频繁的操作比如要加一个I2C传感器就在对应的i2c节点下添加子节点i2c4 { status okay; clock-frequency 100000; mysensor: mysensor48 { compatible myvendor,mysensor; reg 0x48; interrupt-parent gpio1; interrupts RK_PC5 IRQ_TYPE_LEVEL_LOW; }; };这里clock-frequency设100kHz是保守值长走线或者多设备挂载时建议先用100k调通再往上提。中断引脚要查原理图确认GPIO编号RK_PC5这种宏定义在include/dt-bindings/pinctrl/rockchip.h里。3.4 打包与烧录的实操细节瑞芯微的打包脚本在device/rockchip/rk3399/下面执行./build.sh kernel ./build.sh最终生成rockdev/目录下的update.img这是一个包含uboot、kernel、rootfs的完整固件包。烧录工具有Windows版的RKDevTool和Linux版的upgrade_tool我习惯用Linux版sudo upgrade_tool uf update.img烧录前板子要进入Maskrom模式断开电源按住恢复键插入Type-C线等两秒松开。upgrade_tool ld能列出设备就说明识别成功了。实操心得第一次烧录建议用TF卡启动而不是直接写eMMC。TF卡刷坏了重新写就行eMMC刷坏了可能得拆机短接。等TF卡启动验证没问题了再用dd命令把镜像写到eMMC。4. 外设调试与性能优化的实战经验4.1 GPIO与中断调试的常见陷阱RK3399的GPIO分5组每组32个引脚命名规则是GPIO0到GPIO4。在sysfs里操作GPIOecho 138 /sys/class/gpio/export echo out /sys/class/gpio/gpio138/direction echo 1 /sys/class/gpio/gpio138/value138这个编号怎么来的计算公式是组号*32 组内偏移。比如GPIO4_C6组号是4C6对应偏移是2*8622所以编号是4*3222150。这个计算经常有人搞错尤其是B组和C组的偏移。中断调试更容易出问题。设备树里配了中断但驱动收不到先检查三个地方一是引脚复用有没有配成中断功能二是触发方式上升沿/下降沿/电平和硬件是否匹配三是中断控制器有没有使能。用cat /proc/interrupts能看到中断计数如果数字不涨说明硬件层面就没触发。4.2 双屏异显的配置方法RK3399支持HDMI和DP同时输出也可以HDMI加MIPI DSI。配置双屏要在设备树里把两个显示通道都使能hdmi { status okay; }; dp { status okay; }; vopb { status okay; }; vopl { status okay; };VOPB和VOPL是两个视频输出处理器大分辨率屏建议接VOPB。然后在uboot的cmdline里加videoHDMI-A-1:1920x108060 videoDP-1:1280x80060。如果两个屏分辨率不同要确认带宽是否够4K加2K同时输出可能会丢帧。4.3 NPU调用的入门路径RK3399本身不带NPU但很多板子外挂了RK1808或者通过PCIe接了算力卡。如果只是用CPU跑推理建议用NCNN或者TFLite量化到int8后MobileNet跑一帧大概几十毫秒。要用硬件加速的话瑞芯微提供了RKNN工具链流程是在PC上用RKNN-Toolkit把模型转成.rknn格式把.rknn文件和推理程序放到板子上调用rknn_init、rknn_run、rknn_outputs_get完成推理转换时要注意输入尺寸和归一化参数必须和训练时一致否则精度会掉得厉害。我遇到过一次转换后精度从75%掉到30%查了半天发现是均值方差填反了。5. 问题排查速查与避坑清单5.1 启动失败的分层排查法RK3399启动失败时串口日志是唯一线索。按阶段排查现象可能原因排查方法串口无输出DDR初始化失败检查rkbin版本换DDR固件卡在BL31ATF配置错误确认BL31二进制和芯片版本匹配uboot能进但kernel起不来设备树或cmdline错误对比官方evb的dtskernel起来但挂载rootfs失败分区表或文件系统类型不对检查parameter.txt和mkfs参数系统起来但外设不工作驱动未编译或设备树未使能看dmesg和/sys下的设备节点5.2 编译报错的典型场景repo sync卡住不动多半是网络问题可以加--force-sync重试。编译uboot报dtc版本过低升级device-tree-compiler就行。内核编译报undefined reference通常是defconfig里漏了某个驱动选项用make menuconfig搜一下补上。还有一个坑是Python版本。老版SDK的打包脚本是Python2写的Ubuntu 20.04默认Python3需要手动装Python2或者改脚本。我建议直接改脚本Python2已经停止维护了。5.3 性能调优的几个抓手CPU调频用cpufreq子系统查看当前策略cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor默认是interactive跑计算密集型任务可以改成performance锁最高频。GPU调频在/sys/class/devfreq/下面Mali-T860的可用频率档位有200MHz到800MHz。散热是个容易被忽视的问题。RK3399满载功耗能到5W以上不加散热片跑十分钟就会降频。实测加一个20x20mm的铝散热片持续编译时CPU频率能稳定在1.8GHz不降。避坑提醒改CPU频率前先确认供电能力。有些板子的PMIC余量不足锁最高频会导致系统不稳定甚至重启。用cat /sys/kernel/debug/regulator/regulator_summary能看到各路电源的负载情况。6. 后续可以深入的方向跑通系统只是起点RK3399能玩的东西还很多。想往底层走可以研究uboot的启动流程从BootROM到TPL到SPL再到uboot proper每一级做了什么、怎么传递参数搞清楚了整个ARM启动链路就通了。想往应用走可以研究GStreamer硬编解码RK3399的VPU支持H.264/H.265的4K编解码用mpp库能直接调用硬件单元比软编快一个数量级。我个人在实际操作中的体会是RK3399的学习曲线前陡后平。刚开始配环境、烧固件、调串口会觉得处处是坑但一旦系统跑起来后面加外设、改驱动、做优化都是在这个框架里填内容。关键是别怕看日志串口输出的每一行都有意义看懂了日志就看懂了系统在干什么。另外建议养成记录的习惯每次改了什么配置、报了什么错、怎么解决的记下来。RK3399的坑很多是重复的下次遇到翻记录比重新查快得多。