首页
/
行业洞察
/
正文
INDUSTRY INSIGHT · 深度
瑞芯微SDK镜像生成与烧录全流程解析:从U-Boot到update.img
📅 2026/9/21 0:52:04
✍️ 爱科研究院
👁 阅读 3,247
做嵌入式开发这些年瑞芯微平台一直是我手里的主力从RK3288、RK3399到现在的RK3568、RK3588前前后后折腾过不少板子。很多人拿到瑞芯微官方SDK之后第一步不是看代码而是想搞清楚一件事这一堆源码到底怎么变成能烧进板子里的镜像。这个问题听起来挺基础但真做起来会发现里面牵扯到U-Boot、Kernel、Rootfs三套完全不同的构建体系还夹着Loader模式、parameter分区表、update.img整包制作这些概念。这篇文章就把瑞芯微SDK里镜像生成与烧录这条链路完整拆开讲清楚每个镜像从哪里来、怎么编出来、又该怎么烧进去。文章面向的是正在用或准备用瑞芯微平台做产品的开发者不管你是做BSP、驱动还是整机集成只要需要自己编译SDK并且把固件刷到板子上这篇文章都能给你一条很明确的主线。我会尽量按实际操作顺序来讲顺便把那些容易踩的坑标出来省得大家再走一遍我走过的弯路。1. 先搞清楚SDK目录与镜像产物的对应关系1.1 SDK顶层结构与编译入口瑞芯微官方发布的Linux SDK拿到手解压之后第一眼会觉得很乱目录很多但你只要抓住几个关键路径心里就有底了。顶层目录里最重要的几个分别是u-boot、kernel、buildroot、debian、app、device、docs另外还有几个脚本文件build.sh、mkimage.sh和envsetup.sh。build.sh是整个SDK的编译入口很多刚接触的人会直接执行./build.sh结果发现在没有指定参数的情况下它会把U-Boot、Kernel、Rootfs从头到尾编一遍耗时极长。实际上日常开发中更多用的是./build.sh uboot、./build.sh kernel、./build.sh rootfs这样带子命令的编译分区编译完再统一打包。device/rockchip目录下存放的是不同芯片平台和板型的配置文件比如rk3568、rk3588、rv1126这些子目录里面又有BoardConfig*.mk和Rockchip*.mk两种文件。前者定义了板级配置比如RK_UBOOT_DEFCONFIG、RK_KERNEL_DEFCONFIG、RK_ROOTFS_TYPE等变量后者更像是引用关系告诉构建脚本在当前平台上该用哪份配置。mkimage.sh是最后一环的打包脚本它会把前面编译出来的U-Boot、Kernel、Rootfs各自处理成最终固件格式然后存放到rockdev/目录。这个脚本就是“镜像生成”的核心后面我会专门讲它的执行逻辑。1.2 一次完整编译会生成哪些镜像在瑞芯微平台上一套完整的固件通常不是单一文件而是按分区拆开的多个镜像。编译完之后rockdev/目录下你会看到这些文件镜像文件对应分区主要来源作用uboot.imgubootU-Boot编译产物U-Boot主体trust.imgtrust安全启动相关ATF、OP-TEE启动信任链与运行时可执行环境boot.imgbootKernel、dtb、ramdiskLinux内核启动镜像rootfs.imgrootfsBuildroot/Debian根文件系统oem.imgoem板厂私有分区预装应用或无关紧要数据userdata.imguserdata初始数据用户数据分区parameter.txt分区表配置文件定义Flash分区布局update.img整包上述所有镜像打包用于整包升级这里最容易搞混的是uboot.img和trust.img的区别。在瑞芯微新平台的启动流程中芯片上电后先运行BootROMBootROM加载的是U-Boot SPL或者DDR初始化代码而trust.img装的是ARM可信固件ATF和OP-TEE它负责在U-Boot之前或与U-Boot配合完成DDR初始化、切换到安全世界、拉起U-Boot主程序。所以单独烧uboot.img而不烧trust.img板子大概率起不来这两者必须配套。parameter.txt也容易被忽略它虽然不是可执行镜像但烧录时必须先写进去因为升级工具要靠它来识别每个分区在Flash中的偏移和大小。如果分区间错位了轻则文件系统挂不上重则直接变砖返厂。2. 从U-Boot到Kernel两个Boot阶段的分工与编译细节2.1 U-Boot侧到底在干什么U-Boot在瑞芯微平台上承担的任务比一般嵌入式Linux项目要重一些。它不只是引导内核还要负责DDR初始化、时钟初始化、存储设备驱动加载、显示初始化、启动logo显示等。这也是为什么RK平台的U-Boot编译出来会有多个二进制文件而且它们的组织方式跟主线U-Boot不太一样。在SDK里编译U-Boot其实特别简单执行./build.sh uboot脚本会自动读取BoardConfig*.mk里指定的RK_UBOOT_DEFCONFIG然后进入u-boot/目录用这个配置去做编译。你在命令行里看到它执行了make rk3568_defconfig之类的动作实际上就是在用平台默认配置生成.config接着就是常规的make -j16。编译结束之后u-boot/目录里会得到很多文件但最关键的是uboot.img和trust.img。这两个镜像不是U-Boot直接编出来的而是通过瑞芯微提供的打包工具把U-Boot二进制、ATF、DDR初始化代码、Miniloader等部件组合到一起。所以你如果在u-boot/目录里找不到一个叫作uboot.img的文件别着急它生成在rockdev/目录下。有一个实际开发中经常遇到的需求是给U-Boot阶段加上开机动画或者自定义logo。瑞芯微平台在这方面做得比较友好它支持在U-Boot阶段就显示logo然后无缝过渡到Kernel减少切换闪烁。具体做法是在U-Boot里配置CONFIG_LOGO相关选项然后把图片放到u-boot/logo/目录下注意图片格式和分辨率要匹配不然编译能过但显示不出来。编译U-Boot时最典型的坑是交叉编译工具链问题。SDK通常会自带一套工具链放在prebuilts/gcc/linux-x86/目录下但如果你用了自己安装的交叉编译器版本太新反而会报错。我实测过用GCC 9、GCC 8编译RK3568的U-Boot都能过但用GCC 10以上就会出现某些结构体对齐相关的警告个别的还会直接编译失败。所以能不动SDK自带的工具链就尽量别动。2.2 Kernel侧的关键产物与dtb匹配Kernel的编译用的是./build.sh kernel这个命令做的事情就是读取RK_KERNEL_DEFCONFIG对应的配置进入kernel/目录执行编译然后把boot.img生成出来。如果你只是改了驱动源码而没动配置也可以用./build.sh kernel直接把boot.img编出来不需要重新配置内核。这里有个关键点很多人没注意boot.img里面包含的不只是Image或zImage还有一个叫resource.img的概念。在比较旧的SDK版本里resource.img包含了多个dtb文件和logo图片而在新版本SDK里dtb文件已经直接打到boot.img里面去了。所以你在检查Kernel编译产物时不要光找kernel.img要看最终生成的boot.img是否包含了正确的dtb。dtb匹配问题是我见过最多的启动失败原因。Kernel编译默认会把该平台所有dts都编译成dtb然后在U-Boot阶段通过读取分区或环境变量来选择加载哪一个。如果你板子的网口、屏幕或者SD卡驱动不对先不要怀疑内核驱动代码先去确认boot.img里的dtb是不是跟你的板子匹配。最简单的确认方法是解包boot.img或者用mkimage工具查看dtb列表。瑞芯微SDK里Kernel还有一个特殊目录叫kernel/arch/arm64/boot/dts/rockchip/板型对应的dts文件都放在这里。如果你自己画了板子最常规的做法是复制一份官方相近板型的dts比如rk3568-evb.dts改好之后在Makefile里添加编译目标。路径和依赖关系只要加对./build.sh kernel就能自动把它编成dtb并打包到boot.img。内核启动参数中consolettyFIQ0是瑞芯微平台的默认配置很多人想用ttyS0或者ttyAMA0改了内核cmdline之后发现串口没输出。原因在于瑞芯微使用了FIQ debugger机制串口输出经过FIQ处理直接指定普通串口设备不一定能拿到打印信息。如果你只是想看完整启动日志不要折腾参数直接用SDK默认的console配置就行。3. Rootfs的组装与update.img打包流程3.1 Rootfs的两种主流方案Rootfs在瑞芯微SDK中有两种主流选择Buildroot和Debian。Buildroot适合做体积小、功能固定的量产镜像SDK里通过buildroot/目录维护Debian适合做功能丰富、方便调试的开发镜像SDK里通过debian/目录维护。在BoardConfig*.mk里用RK_ROOTFS_TYPE来指定用哪一个。常见写法有RK_ROOTFS_TYPEbuildroot和RK_ROOTFS_TYPEdebian。如果你改了这个变量最好执行一下./build.sh cleanall再重新编译因为两种Rootfs的构建系统差异太大共存时的残留文件会导致一些奇怪的编译报错。Buildroot的构建过程是先把工具链、busybox、第三方库全部编译一遍然后打包成rootfs镜像。第一次执行./build.sh rootfs时会非常久我试过在8核16线程的机器上编一个功能完整的Buildroot也要一个多小时。这里要注意磁盘空间Buildroot构建过程会产生大量临时文件buildroot/output/目录轻松吃掉几十GB。建议给SDK所在的磁盘预留至少100GB空闲空间否则编到一半磁盘满了会出各种令人崩溃的诡异问题。Debian的Rootfs思路不一样它不是从源码编译整个系统而是用debootstrap从一个基础软件包集合开始安装一个最小的Debian根文件系统然后根据需要装上各种应用。这种方式在开发调试阶段更省心因为直接用apt就能装软件。但是要注意SDK里带的Debian根文件系统是预置好的你没法直接往里面加apt源之外的包想改就得用chroot进rootfs手动操作。我先说Buildroot因为它更容易出现“表面成功编译但实际跑不起来”的情况。很多人改完Buildroot配置重新编译rootfs后发现rootfs.img体积一点没变烧进板子也看不到自己的改动原因就很可能是没执行./build.sh cleanall而只执行了./build.sh rootfs。Buildroot有缓存机制某些配置项改动后不会触发对应软件包的重编所以需要先把旧的编译产物清掉再重新编。3.2 mkimage.sh与update.img的生成逻辑编译完各个分区的镜像之后最后一步就是打包update.img。这个过程由mkimage.sh控制它在SDK顶层目录下执行把rockdev/目录里各个分区镜像以及parameter分区表都打包成一个统一固件文件。mkimage.sh的核心动作其实就两件事一是根据parameter.txt把各个镜像放到正确的偏移位置二是生成一个带校验信息的升级头让烧录工具能识别并校验。瑞芯微的升级工具在烧录update.img时会先解析升级头然后按里面的分区信息逐个烧录。很多人会有个疑问既然有了单独的uboot.img、boot.img、rootfs.img为什么还要打一个update.img原因有两方面一方面update.img里包含完整的分区表和校验信息用RKDevTool的“升级固件”功能一键烧录不用手动选择每个分区文件另一方面update.img在生产烧录和售后升级时更方便一个文件搞定所有分区不容易漏掉或选错。在实际量产时我通常不会让产线用update.img整包升级而是用一个叫upgrade_tool的命令行工具配合单独的镜像文件做分区烧录。这样可以省去整包校验和解析的时间也更方便定制烧录流程。比如只烧uboot.img和trust.img来更新Bootloader或者只烧boot.img来更新内核不用每次都带一个几百MB的rootfs。这里要注意一个细节update.img的打包参数RK_UPDATE_INI在Rockchip*.mk里配置默认指向device/rockchip/rk3568/rockimg/rk3568.ini。如果你自己加了一个分区就得同步修改这个ini文件把分区镜像路径加进去否则打包出来的update.img会缺少这个分区烧录后系统依然能启动但那个分区的数据是空的。打包完成的update.img在rockdev/目录下它的体积通常跟rootfs大小直接相关。Debug版本的Debian rootfs解压后可能超过2GB整包固件也会跟着膨胀。如果发现update.img体积异常大先检查rootfs是否包含了一些不该有的日志缓存和临时文件。4. 烧录实操从Loader模式到升级工具使用4.1 进入Loader模式的几种方法瑞芯微芯片内部有一个BootROM程序它上电会检测USB或者SD卡设备如果外部触发条件满足就进入下载模式。这个模式在RKDevTool里显示为“Loader模式”是烧录的前提。进入Loader模式最可靠的方法是按住板子上的RECOVERY键有些板子叫UPDATE或MASKROM键再上电。注意动作顺序很关键先把RECOVERY键按住不松然后再接USB线和电源。上电之后BootROM检测到RECOVERY引脚被拉低就会停留在下载模式等待PC端工具连接。如果你的板子没有实体按键也可以飞线短接对应的测试点原理一样。还有一种是软件层面的方式就是在已经能启动的U-Boot或Linux里执行reboot loader命令。这条命令会让芯片直接进入Loader模式适合远程维护场景。不过要注意U-Boot环境里执行reboot loader和Linux系统里执行reboot loader最终效果都是一样的但前提是内核或U-Boot里对应驱动没有被动过。我遇到过不少烧录失败的情况最后排查出来都是USB连接问题。瑞芯微Loader模式依赖于USB枚举PC端必须识别到一个Rockchip设备才算成功进入Loader模式。如果你插上USB线后设备管理器里没有任何变化先确认RECOVERY引脚是否真的拉低了再检查USB线是否支持数据通信这个坑特别常见很多USB线只能充电插上去完全没反应。4.2 RKDevTool与upgrade_tool两种烧录方式PC端烧录工具常用的有两款Windows下面用RKDevToolLinux环境下用upgrade_tool。Windows版RKDevTool会把驱动和工具一起装好图形界面操作直观适合开发阶段单板调试。Linux下则更依赖命令行适合产线和自动化集成。RKDevTool的使用逻辑很简单。连接板子进入Loader模式后工具界面上会显示一个“发现一个Loader设备”。此时有两个选择如果你有update.img整包就直接切到“升级固件”页点击“升级固件”按钮选择文件然后点“升级”如果你只想单独刷某个分区就切到“分区表”页对照parameter的分区名分别给每个分区指定镜像路径再点“执行”。upgrade_tool命令行工具在Linux下的用法更直接# 查看当前识别到的设备 sudo upgrade_tool ld # 烧录整包固件 sudo upgrade_tool uf update.img # 单独烧录分区镜像 sudo upgrade_tool di -b boot.img sudo upgrade_tool di -u uboot.img sudo upgrade_tool di -t trust.img # 烧录parameter分区表 sudo upgrade_tool di -p parameter.txt这里di参数表示download image后面跟着分区标识符-b对应boot-u对应uboot-t对应trust-p对应parameter。分区标识符跟parameter.txt里定义的名字必须一致所以在执行之前先cat parameter.txt确认分区名称是个好习惯。烧录顺序上如果是从空板或异常状态救砖我建议严格按照“parameter → loader/uboot → trust → boot → rootfs → 其他分区”的顺序来。先烧parameter是为了让工具正确识别分区的物理布局然后再烧uboot和trust这两个是启动关键顺序对了之后板子就能正常进入U-Boot之后再烧kernel和rootfs才有意义。如果你跳过parameter直接烧boot工具不知道往Flash哪个地址写结果就是烧完重启什么都没变。还有一个需要提醒的点就是Linux下用upgrade_tool需要设备权限。默认情况下普通用户访问USB设备会提示权限不足所以要么用sudo执行所有命令要么给设备创建一个udev规则。如果不想每次输密码我在/etc/udev/rules.d/下放了一个规则把VID为2207的设备权限改成0666插上就能直接操作。4.3 分区表parameter.txt的调整思路parameter.txt是烧录时最容易拖后腿但也最关键的文件。它定义了Flash芯片上每个分区的名字、起始偏移和大小格式类似下面这样FIRMWARE_VER: 1.0 MACHINE_MODEL: RK3568 MACHINE_ID: 007 MANUFACTURER: Rockchip CMDLINE: mtdpartsrnand0:0x000020000x00004000(uboot),0x000020000x00006000(trust),...这里每个分区的偏移和大小都是用十六进制表示的单位是扇区一个扇区512字节。比如0x00002000就是8192个扇区对应4MB空间。如果你要调整rootfs大小就得数清楚后面的偏移地址保证前一个分区结束的扇区号正好是后一个分区的起始扇区号不能有重叠也不能有缝隙否则后面分区数据会被错误覆盖。修改parameter.txt之后一定要重新打包update.img而不是只把parameter单独烧进去。原因很简单update.img内部还会记录一份分区表信息单独烧parameter只是改了Flash上的分区布局但整包里的分区信息还是旧的下次再用整包升级时又会把布局改回去。所以规范做法是先改device/rockchip/rk3568/目录下的parameter文件然后重新执行./build.sh updateimg生成新的update.img。我吃过一次亏当时为了给用户数据区腾空间把userdata分区扩大了一倍只改了parameter烧进去没重新打包整包。后来产线用整包升级分区布局瞬间又被重置了用户数据全部丢失。那次之后我只要是动了分区表一定会连同整包一起重新生成并且做一次完整的升级验证。5. 常见问题速查与避坑经验5.1 编译阶段的高频报错编译阶段最常见的报错主要有三类磁盘空间不足、依赖库缺失、工具链不匹配。磁盘空间不足通常出现在编Buildroot和Debian rootfs时报错信息五花八门一会儿是No space left on device一会儿又是cmake编译中段。建议在编译前先用df -h检查一下空间。依赖库缺失主要出现在Ubuntu宿主机的编译环境里。SDK编译某些组件需要libssl-dev、libncurses5-dev、python2等不同Ubuntu版本带的包名还不一样。我常备的一行安装命令是sudo apt-get install -y libssl-dev libncurses5-dev git gnupg flex bison gperf build-essential zip curl liblz4-tool zlib1g-dev libc6-dev-i386 x11proto-core-dev libx11-dev lib32z1-dev libgl1-mesa-dev libxml2-utils xsltproc unzip fontconfig基本覆盖大多数SDK的依赖需求。工具链不匹配这个坑在新手手里出现频率极高尤其是那些之前在别的项目里装过交叉编译器的开发者。SDK在build.sh里会主动使用prebuilts/gcc/linux-x86/下自带的工具链但如果你在~/.bashrc里自定义了PATH而且自定义的路径排在SDK工具链之前就可能用错编译器导致U-Boot编译报Error: unknown pseudo-op: .arch这样的汇编错误。解决办法是编译前检查which aarch64-linux-gnu-gcc确认用的确实是SDK自带的那个。5.2 烧录与启动阶段的排查实录烧录阶段最典型的失败现象是RKDevTool一直提示“等待设备”或者“设备连接失败”。遇到这个现象我通常按以下顺序排查第一确认板子是否真的成功进入Loader模式第二换一个USB端口和USB线第三重新安装驱动程序Windows下尤其常见驱动被安全软件拦截的情况第四确认是否使用了USB Hub我遇到过几次是USB Hub供电不稳导致设备枚举失败直连主板USB口就正常了。启动阶段的问题就更多了而且需要结合串口日志来判断。串口输出里如果卡在DDR V1.09这样的信息上说明U-Boot的DDR初始化没过要么是DDR频率配置不对要么是硬件上DDR颗粒型号和参数对不上。如果卡在Loading firmware...之后没有输出多半是trust.img和uboot.img版本不匹配或者ATF找不到对应平台的BL31参数。有一个经常被忽略的检查项是电源时序。RK3568、RK3588这些平台有多路电源轨上电顺序有严格要求。如果你自研板卡烧录一切正常但上电后就是起不来先拿示波器抓一下各路电源的上电时序是否正确。我调试过一块板子现象是偶尔能启动偶尔死机折腾了好多天最后发现是某个DC-DC的使能引脚时序慢了十几毫秒导致DDR初始化时供电还没稳定。Kernel阶段起不来的话优先看dtb匹配和console输出。我在RK平台遇到过最多次的现象是内核打印到Starting kernel ...之后就没下文了。这种情况八成是dtb里的内存配置、串口配置跟实际硬件不符。你可以把boot.img里的dtb解包出来用fdtdump对比一下chosen、memory和serial节点基本能定位问题。最后再分享一个实用习惯每次编译新固件之前先把rockdev/目录备份一下。瑞芯微SDK在编译过程中会覆盖rockdev/下的文件如果你上一个版本能正常工作但新版本编译后想回退没有备份就得重新编译旧代码浪费时间不说有时候旧分支可能已经被你改了。我现在都习惯在每次出固件之前执行一次tar czf rockdev_$(date %Y%m%d).tar.gz rockdev/一个命令却能省掉很多不必要的麻烦。
📌 标签:
工业官网
设计趋势
AI 建站
SEO
获取完整报告 →
RELATED ARTICLES
推荐阅读
2026/9/21 0:52:04
不必要的 RT 切换与 Resolve:手机 GPU 最贵的那笔隐形账单
2026/9/21 0:47:03
LM Studio本地部署Qwen3.6-27B实战:硬件门槛、量化选型与性能调优
2026/9/21 0:47:03
天气预测与可视化:从时间序列分析到交互看板的毕设实践
2026/9/21 2:47:15
Roc 语言 `if` 表达式缺失 `else` 分支的编译诊断深度解析:基于 `expr_if_missing_else` 快照测试
2026/9/21 2:47:15
Boss直聘岗位数据抓取实战:requests+代理IP池搭建与反爬应对
2026/9/21 2:47:15
伺服电机通信协议选型指南:Modbus、CANopen与EtherCAT对比
2026/9/21 2:47:15
VitePress 部署完全指南:从本地构建、Base 路径到各平台生产发布
2026/9/21 2:47:15
K8s环境下GPU虚拟化切分与算力调度实践指南
2026/9/21 2:42:15
react-admin 生态全景指南:官方包、Enterprise Edition 与第三方扩展组件导航
2026/9/21 0:02:00
Unity ML-Agents 工具包完整安装指南:从 Unity 2022.3 到 Python 训练环境的逐步搭建
2026/9/21 0:02:00
OneUptime 自定义探针(Custom Probe)部署实战:私网监控、代理配置与断连排障全指南
2026/9/21 0:02:00
大众TL52625前端框架材料要求详解:从性能测试到落地执行
2026/9/21 1:46:28
深入解析Transformer多头注意力机制与工程优化
2026/9/21 1:46:31
OpenClaw 的 Skills 跑学习任务,模型通道改到 TaoToken 通道行不行?
2026/9/21 1:46:33
ChatGPT报错Oops, an error occurred! 全链路排查指南