1. 项目概述与痛点分析
在嵌入式产品的量产环节,烧录效率往往是决定产线吞吐量和生产成本的关键瓶颈。最近在基于瑞萨RZ/G2L微处理器开发一款工业HMI设备时,我们就深刻体会到了这一点。RZ/G2L这颗芯片本身素质不错,Cortex-A55核心跑在1.2GHz,搭配Mali-G31 GPU和丰富的接口,非常适合我们这种需要显示和基础视频处理功能的工控场景。然而,在进入小批量试产阶段时,传统的eMMC烧录方式让我们吃了大亏——单块板子从空白芯片到系统可启动,平均耗时竟然要5分半钟。想象一下,如果一天要烧录几百片,产线工人大部分时间都在等待,这种效率显然无法接受。
问题的核心在于传统烧录流程的串行性。通常的做法是,通过JTAG或者专用的烧录器,将引导程序(U-Boot)、内核、设备树、文件系统等所有镜像,按顺序、完整地写入eMMC存储。这个过程数据量大,且是严格的“一对一”操作,烧录器写完一块板子才能接下一块。RZ/G2L的启动流程又涉及BL2、FIP等多个阶段,进一步拉长了单次操作时间。我们意识到,必须打破这种串行模式,引入并行处理思维,才能把生产效率提上去。这就是我们设计这套“双阶段混合烧录方案”的初衷:它不是一个简单的工具替换,而是一次针对量产流程的架构优化。
2. 双阶段混合烧录方案核心思路
面对效率瓶颈,我们并没有去寻找一个更快的“超级烧录器”,而是重新审视了整个烧录过程的本质。烧录其实可以拆解为两个性质不同的任务:一是写入底层的、固化的引导程序;二是写入上层的、可频繁更换的系统镜像。基于这个洞察,我们设计了“SCIF + Fastboot”的双阶段混合架构。
2.1 第一阶段:SCIF并行烧录Bootloader
第一阶段的目标是高效、可靠地为多块主板写入相同的引导程序(包括BL2和FIP)。我们选择了瑞萨芯片内置的SCIF(Serial Communication Interface with FIFO)接口。你可以把它理解为一个高度优化的串口,但它直接与芯片的Boot ROM协作,是芯片上电后最早能响应的通信接口之一。它的最大优势在于“一对多”的并行能力。
具体操作时,我们使用瑞萨官方提供的Flash Writer工具。这个工具通过SCIF接口,可以直接与处于下载模式的RZ/G2L芯片通信。在生产线上,我们可以通过一个简单的USB Hub,将多块主板的SCIF调试口(通常是某个UART引脚复用)连接到同一台PC。Flash Writer支持脚本化操作,我们可以编写一个脚本,循环对所有检测到的SCIF端口执行相同的烧录命令,将bl2_bp_pmic.srec和fip_pmic.srec这两个引导文件批量写入各自主板的eMMC。由于SCIF通信速率高且指令精简,写入这少量但关键的引导代码非常快,更重要的是,多块板子的这个阶段是真正并行的,耗时几乎不随板子数量增加而线性增长。
注意:SCIF烧录需要主板硬件支持相应的启动模式跳线(通常是将Boot Mode引脚设置为特定电平,使芯片上电后进入Serial Download模式)。在设计和制作测试工装时,务必确保能方便地将主板切入此模式。
2.2 第二阶段:Fastboot over USB并行烧录系统
一旦Bootloader就位,主板就可以正常启动到U-Boot命令行。这时,我们切换战场,利用U-Boot的Fastboot功能和USB接口来完成第二阶段的系统镜像烧录。Fastboot是Android生态中广泛使用的刷机协议,其优点是协议简单、传输效率高,且支持丰富的分区操作命令。
我们的策略是,在U-Boot中使能Fastboot over USB功能。当主板启动到U-Boot后,执行一条命令即可使其进入Fastboot服务模式,等待PC主机连接。在PC端,我们使用标准的fastboot命令行工具。由于每块主板通过独立的USB线连接到PC,操作系统会为其分配独立的设备ID。这样,我们就可以在PC上打开多个终端窗口,每个窗口针对一个特定的设备ID(通过fastboot -s <序列号>指定)执行烧录命令,实现多个系统镜像的并发烧录。
这个阶段烧录的数据量最大(内核、文件系统等),但得益于USB 2.0的带宽和Fastboot协议的高效,速度已经比传统方式快很多。而并发的实现,使得多块板子的烧录总时间,从“串行时间的总和”缩短为“最慢那块板子的时间”,效率提升是指数级的。
3. 详细配置与实操步骤拆解
理论清晰后,落地到每一步操作才是关键。下面我把整个方案的配置和操作拆解开,你会看到从源码编译到批量烧录的完整路径。
3.1 U-Boot配置与编译:启用Fastboot引擎
要让U-Boot支持Fastboot over USB,必须在编译前进行正确的配置。我们的开发板基于RZ/G2L的SMARC板型,因此主要修改u-boot/git/configs/smarc-rzg2l_defconfig这个配置文件。
# 启用Fastboot功能核心选项 CONFIG_USB_FUNCTION_FASTBOOT=y CONFIG_FASTBOOT_BUF_ADDR=0x4D000000 # 指定Fastboot数据传输的内存缓冲区地址 CONFIG_FASTBOOT_BUF_SIZE=0x8000000 # 缓冲区大小,这里为128MB CONFIG_FASTBOOT_USB_DEV=28 # USB设备控制器编号,需参考具体硬件设计 CONFIG_FASTBOOT_FLASH=y # 启用对Flash(如eMMC)的烧写支持 CONFIG_FASTBOOT_FLASH_MMC_DEV=0 # 指定MMC设备号为0(通常是eMMC) CONFIG_CMD_FASTBOOT=y # 启用fastboot命令行命令 # 启用USB Gadget(设备)功能,使开发板能作为USB设备被PC识别 CONFIG_USB=y CONFIG_USB_XHCI_HCD=y # 启用xHCI USB主机控制器驱动(现代USB3.0/2.0) CONFIG_USB_EHCI_HCD=y # 启用EHCI USB主机控制器驱动(USB2.0) CONFIG_USB_GADGET=y CONFIG_USB_GADGET_MANUFACTURER="Renesas" CONFIG_USB_GADGET_VENDOR_NUM=0x18D1 # USB厂商ID,这里使用了Google的测试ID CONFIG_USB_GADGET_PRODUCT_NUM=0x4E23 # USB产品ID这里有几个关键点需要注意:
CONFIG_FASTBOOT_BUF_ADDR:这个地址必须是一段未被系统其他部分使用的安全内存区域。你需要参考RZ/G2L的内存映射图,选择一个合适的地址。设置错误会导致数据传输失败或系统崩溃。CONFIG_FASTBOOT_USB_DEV:这个值(28)对应RZ/G2L内部USB控制器的一个特定实例。这个值强烈依赖于你的具体硬件设计和芯片版本,最准确的方法是查阅你所用板级的设备树(DTS)文件中USB节点的定义。- USB ID:示例中使用了Google的测试ID。对于正式产品,建议向USB-IF申请自己的厂商ID(VID)和产品ID(PID),以避免驱动冲突。
配置完成后,执行编译命令(如make smarc-rzg2l_defconfig && make),得到最终的U-Boot镜像。对于RZ/G2L,我们通常需要的是打包进FIP中的U-Boot镜像。编译产出物中,我们关注fip_pmic.srec和bl2_bp_pmic.srec,它们将通过SCIF被烧录。
3.2 第一阶段实操:使用Flash Writer通过SCIF烧录Bootloader
- 硬件准备:将目标板的Boot Mode引脚设置为SCIF下载模式(具体电平请参考硬件手册)。通过USB转UART工具(如FTDI芯片的模块),将板子的SCIF调试串口(通常是某个UART TX/RX)连接到PC。注意,SCIF接口可能需要特定的电压(如1.8V或3.3V),确保你的转接工具电平匹配。
- 启动Flash Writer:从瑞萨官网下载并运行RZ/G2L对应的Flash Writer工具(例如
flash_writer_{board}.mot)。这个工具本身也是一个可执行文件,它通过串口与板卡通信。 - 建立连接:给目标板上电。在Flash Writer软件界面选择正确的COM端口和波特率(通常是115200),执行连接操作。如果硬件和模式设置正确,软件会显示连接成功,并识别出芯片型号。
- 执行烧录脚本:Flash Writer支持命令行或脚本。我们可以编写一个简单的脚本(或直接使用其GUI的批量操作功能),依次执行以下命令:
> xls2:初始化DDR内存。> download:选择并下载bl2_bp_pmic.srec文件到指定内存地址。> write:将内存中的BL2镜像写入eMMC的特定扇区(地址需根据Boot ROM规范确定)。- 重复
download和write步骤,烧录fip_pmic.srec。 - 对连接在同一个PC上的其他板卡,重复上述操作。可以手动切换串口,也可以用脚本循环控制多个端口。
这个过程非常快,因为写入的数据量很小(两个srec文件通常只有几百KB),且SCIF通信稳定。这是实现“一对多”并行的基础。
3.3 第二阶段实操:配置与使用Fastboot烧录系统
Bootloader烧录完成后,将主板Boot Mode改回从eMMC启动,上电后应能进入U-Boot命令行。
设备端(开发板)操作:在U-Boot命令行中,我们需要做两件事:一是设置一个唯一标识符以便PC区分多设备,二是启动Fastboot服务。
# 设置一个唯一的序列号,例如‘Renesas_001‘。这个值在批量操作中至关重要。 setenv serial# ‘Renesas_001‘ saveenv # 启动USB Fastboot服务。参数‘0‘通常指第一个USB控制器。 fastboot usb 0执行fastboot usb 0后,U-Boot会打印类似starting fastboot USB的信息,并等待PC连接。此时用USB线将板子的USB Device口(通常是某个USB-A或Micro-USB口,具体看原理图)连接到PC。
PC端操作:
- 验证连接:打开终端,输入
fastboot devices。如果一切正常,你会看到类似Renesas_001 fastboot的输出,表明设备已被识别。 - 准备分区表(MBR):我们需要先为eMMC创建分区表。创建一个名为
part.mbr的文件,内容定义了两个分区:一个500MB的FAT32启动分区(存放内核和DTB),一个3.5GB的EXT4根文件系统分区。可以使用fdisk或parted工具生成,也可以直接用一个包含MBR数据的二进制文件。然后烧录它:
这个命令会擦除eMMC上的旧分区表并写入新的。fastboot flash mbr part.mbr - 创建并烧录启动分区(boot.img):
# 创建一个256MB大小的空文件(实际我们分区是500MB,这里先创建镜像文件) dd if=/dev/zero of=boot.img bs=1M count=256 # 将其格式化为FAT32文件系统 sudo mkfs.vfat -F 32 boot.img # 挂载这个镜像文件 sudo mount boot.img /mnt # 将编译好的内核镜像(如Image-smarc-rzg2l.bin)和设备树文件(.dtb)复制进去 cp /path/to/Image-smarc-rzg2l.bin /mnt/ cp /path/to/Image-r9a07g044l2-smarc.dtb /mnt/ sudo umount /mnt # 烧录启动分区到eMMC的第一个分区(分区索引0:1) fastboot flash 0:1 boot.img - 烧录根文件系统分区:如果你的根文件系统已经构建好了一个EXT4格式的镜像文件(例如
core-image-minimal-smarc-rzg2l.ext4),直接烧录即可:
如果镜像文件是稀疏格式(sparse image),fastboot flash 0:2 core-image-minimal-smarc-rzg2l.ext4fastboot工具会自动识别并进行高效烧写,这在烧录日志中可以看到Flashing sparse image的提示。 - 重启设备:
设备将重启,并尝试从我们刚刚烧录好的eMMC分区启动。fastboot reboot
3.4 关键一步:配置U-Boot启动参数
烧录完成后,系统可能还无法正确启动,因为U-Boot不知道去哪里找内核和如何挂载根文件系统。我们需要在U-Boot中设置正确的环境变量。
再次让板子进入U-Boot命令行(可以在启动时按任意键中断自动启动),设置以下参数:
# 设置内核启动参数:读写模式,指定根文件系统在第二个分区 setenv bootargs ‘rw rootwait earlycon root=/dev/mmcblk0p2‘ # 设置自动启动命令:从eMMC设备0的第一个分区加载内核和设备树到内存,然后启动 setenv bootcmd ‘mmc dev 0; fatload mmc 0:1 0x48080000 Image-smarc-rzg2l.bin; fatload mmc 0:1 0x48000000 Image-r9a07g044l2-smarc.dtb; booti 0x48080000 - 0x48000000‘ # 保存环境变量到eMMC saveenvroot=/dev/mmcblk0p2:指定根文件系统位于eMMC块设备的第二个分区。fatload mmc 0:1 ...:从MMC设备0的第一个分区(即我们烧录的FAT32启动分区)加载文件到内存指定地址。booti:启动ARM64内核镜像。后面两个参数分别是内核加载地址和设备树加载地址。
设置并保存后,执行boot命令或直接重启,系统就应该能从eMMC正常启动了。
4. 多设备并行烧录的实战编排
单设备操作只是基础,批量并行才是这个方案的威力所在。其核心在于利用Fastboot工具通过-s参数指定设备序列号的能力。
准备工作:
- 将N块已完成第一阶段SCIF烧录的主板,通过USB线连接到同一台PC。
- 依次给每块主板上电,并在U-Boot中为每块板设置唯一的
serial#环境变量,然后执行fastboot usb 0。例如:- 板子1:
setenv serial# ‘Device_001‘; saveenv; fastboot usb 0 - 板子2:
setenv serial# ‘Device_002‘; saveenv; fastboot usb 0 - ... 以此类推。
- 板子1:
PC端并行操作:在PC上,打开多个终端窗口(如Terminal 1, Terminal 2, ... Terminal N)。在每个终端中,针对特定的设备序列号执行完整的烧录流程。命令几乎一样,只是增加了-s <序列号>参数。
终端1(操作Device_001):
# 查看设备,确认Device_001在线 fastboot devices # 烧录分区表 fastboot -s Device_001 flash mbr part.mbr # 烧录启动分区 fastboot -s Device_001 flash 0:1 boot.img # 烧录根文件系统 fastboot -s Device_001 flash 0:2 core-image-minimal-smarc-rzg2l.ext4 # 重启 fastboot -s Device_001 reboot终端2(操作Device_002):
fastboot -s Device_002 flash mbr part.mbr fastboot -s Device_002 flash 0:1 boot.img fastboot -s Device_002 flash 0:2 core-image-minimal-smarc-rzg2l.ext4 fastboot -s Device_002 reboot效率分析:假设烧录boot.img需12秒,烧录根文件系统需67秒(如示例日志)。在单线程串行下,烧录2块板子总耗时约为 (12+67)*2 = 158秒。采用双终端并行后,总耗时接近于最慢的那个环节的耗时,即约12+67=79秒。理论上,只要PC的USB带宽和CPU处理能力足够,你可以同时操作更多设备(比如4个、8个),将批量烧录的总时间压缩到接近单块板子的烧录时间,效率提升非常可观。
5. 常见问题、避坑指南与实战心得
在实际部署这套方案的过程中,我们踩过不少坑,也积累了一些宝贵的经验。
5.1 编译与配置相关坑点
- U-Boot无法进入Fastboot模式:最常见的原因是
CONFIG_FASTBOOT_USB_DEV配置错误。务必核对你的硬件原理图,确认USB控制器编号。另一个可能是USB PHY的时钟或电源没有正确初始化,需要检查U-Boot板级初始化代码中关于USB的部分。 - PC端
fastboot devices找不到设备:首先检查USB线是否连接正确(是Device口,不是Host口)。在Linux下,检查lsusb命令输出,看是否有类似Google, Inc.或你配置的厂商ID的设备。如果没有,可能是Windows/Linux缺少对应的USB驱动(WinUSB或libusb)。在Windows上,可能需要使用Zadig工具为设备安装WinUSB驱动。在Linux下,确保当前用户有USB设备访问权限(通常需要将用户加入plugdev组)。 fastboot flash命令报权限错误或传输中断:可能是PC端USB端口供电不足,尤其是同时连接多块开发板时。建议使用带外部供电的USB Hub。此外,USB线质量差也会导致数据传输不稳定。
5.2 烧录过程与启动问题
- 烧录MBR后,U-Boot无法识别分区(示例log中出现的
Bad partition specification):这是正常现象。U-Boot在烧录MBR后,需要重新扫描或初始化MMC设备才能识别新分区表。在执行fastboot flash mbr后,U-Boot的Fastboot服务内部会处理这个问题,后续烧录分区就能成功。这些警告信息可以忽略,只要最终烧录成功即可。 - 系统启动时卡住或内核恐慌(Kernel Panic):首先检查
bootargs环境变量是否正确,特别是root=参数指向的分区是否正确(是/dev/mmcblk0p2而不是/dev/mmcblk0p3)。其次,检查烧录的文件系统镜像是否完整且格式正确。可以尝试在PC上挂载boot.img和根文件系统镜像,检查内核和设备树文件是否存在、版本是否匹配。 - 多设备并行时命令串扰:务必确保为每块板子设置了全局唯一的
serial#。如果序列号重复,fastboot -s命令可能会同时操作到两个设备,导致不可预知的结果。建议将序列号与生产批号、MAC地址后几位或流水号关联。
5.3 生产环境优化建议
- 自动化脚本:对于产线,绝不能依赖手动输入命令。应该编写完整的Shell脚本或Python脚本,自动检测连接的Fastboot设备,读取其序列号,然后为每个设备启动一个后台进程,执行完整的烧录流程。脚本还应包含超时重试、错误日志记录和结果汇报功能。
- 镜像管理与校验:建立集中的镜像服务器。烧录脚本应从服务器拉取指定版本的镜像文件,并在烧录完成后,可选地回读eMMC关键扇区进行校验,确保烧录数据的完整性。
- 工装设计:设计专用的烧录治具,将SCIF接口和USB接口通过探针或夹具与主板连接,实现“一键切换”启动模式和一键连接。这能极大减少操作员的手动操作,降低出错率,提升一致性。
- 环境变量固化:对于量产板,
bootargs和bootcmd这类环境变量一旦确定就不应再改变。可以考虑在编译U-Boot时,直接将这些变量设置为默认值(修改include/configs/smarc-rzg2l.h中的CONFIG_EXTRA_ENV_SETTINGS),避免每次烧录后都需要手动设置。
这套“SCIF + Fastboot”双阶段混合烧录方案,在我们实际的生产测试中,将单板烧录总时间从5分30秒降低到了约2分钟(其中SCIF阶段约20秒,Fastboot阶段约1分40秒),并且实现了4块板子的并行烧录,整体效率提升了超过10倍。它特别适合硬件版本固定但软件需要频繁迭代的开发验证阶段,以及小批量、多配置的定制化生产订单。当然,如果产品硬件完全没有预留USB Device调试口,那么这个方案的第二阶段就无法实施,需要回归到寻找更高效的纯烧录器方案。但对于大多数基于RZ/G2L这类现代MPU的开发板而言,USB口几乎是标配,充分利用它来提升生产效率,是一个非常值得投入的优化方向。