05-系统烧写与量产.md 21 KB


title: 系统烧写与量产 tags: [系统烧写, SD卡, 串口, USB, 量产, MfgTool, 嵌入式Linux] created: 2026-09-16 updated: 2026-09-17

pdf_ref: "【正点原子】I.MX6U嵌入式Linux驱动开发指南V2.0.1 - 第三十九章 系统烧写"

系统烧写与量产

关联知识: [[06-系统移植与启动/01-U-Boot基础与命令]] | [[06-系统移植与启动/04-根文件系统构建]] | [[06-系统移植与启动/02-Linux内核编译]]


一、烧写方式概述

系统移植完成后,需要将 U-Boot、Linux Kernel、设备树(.dtb)和根文件系统(rootfs)四个文件烧写到板载 EMMC、NAND Flash 或 QSPI Flash 等存储设备上,使产品脱离网络独立运行。

flowchart LR
    accTitle: Embedded Linux System Flashing Methods
    accDescr: Four main methods for flashing embedded Linux systems: SD card, serial, USB OTG, and network

    sd[💾 SD卡烧写] --> target[🎯 目标存储]
    serial[📡 串口烧写] --> target
    usb[🔌 USB烧写] --> target
    net[🌐 网络烧写] --> target

    classDef method fill:#dbeafe,stroke:#2563eb,stroke-width:2px,color:#1e3a5f
    classDef target fill:#dcfce7,stroke:#16a34a,stroke-width:2px,color:#14532d
    class sd,serial,usb,net method
    class target target
烧写方式 接口 速度 适用场景 工具
SD卡烧写 SD/MMC卡槽 ~10MB/s 开发调试、批量生产 ddmkfs
串口烧写 UART (TTL) ~115KB/s 紧急恢复、无网络环境 U-Boot loadb
USB烧写 USB OTG ~20MB/s 量产首选、NXP推荐 MfgTool / uuu
网络烧写 Ethernet/WiFi ~100MB/s 大文件、远程部署 TFTP + NFS

💡 选择建议: 开发阶段优先用 SD卡 或 USB 烧写;量产环境首选 USB OTG(MfgTool);紧急恢复可用串口;大批量部署用网络。


二、SD卡烧写

2.1 硬件准备

  • 一张 MicroSD 卡(建议 8GB 以上 Class 10)
  • 读卡器连接电脑
  • 开发板支持 SD 卡启动(拨码开关设置)

2.2 格式化 SD 卡

在 Linux 主机上执行,将 SD 卡分为两个分区:

# 查看 SD 卡设备编号(以 /dev/sdb 为例)
lsblk

# 使用 parted 创建分区表
sudo parted /dev/sdb mklabel msdos

# 创建 FAT32 分区(存放 U-Boot、内核、设备树)
sudo parted /dev/sdb mkpart primary fat32 1MiB 128MiB

# 创建 ext4 分区(存放根文件系统)
sudo parted /dev/sdb mkpart primary ext4 128MiB 100%

# 格式化分区
sudo mkfs.vfat -F 32 /dev/sdb1
sudo mkfs.ext4 /dev/sdb2

2.3 烧写 U-Boot 到 SD 卡

U-Boot 需要写入 SD 卡的特定偏移位置(IMX6ULL 为扇区 2,即 1KB 偏移):

# 将 U-Boot 写入 SD 卡(跳过前 1KB)
sudo dd if=u-boot.imx of=/dev/sdb bs=1k seek=2 conv=fsync

# 验证写入
sudo dd if=/dev/sdb bs=1k skip=2 count=100 2>/dev/null | xxd | head -5

2.4 拷贝内核与设备树

将编译好的文件复制到 FAT32 分区:

# 挂载分区
sudo mkdir -p /mnt/sdboot
sudo mount /dev/sdb1 /mnt/sdboot

# 拷贝内核和设备树
sudo cp zImage /mnt/sdboot/
sudo cp imx6ull-alientek-emmc.dtb /mnt/sdboot/

# 卸载
sudo umount /mnt/sdboot

2.5 拷贝根文件系统

# 挂载 ext4 分区
sudo mkdir -p /mnt/sdrootfs
sudo mount /dev/sdb2 /mnt/sdrootfs

# 解压根文件系统
sudo tar -xvf rootfs.tar.bz2 -C /mnt/sdrootfs/

# 卸载
sudo umount /mnt/sdrootfs

2.6 U-Boot 启动参数设置

插入 SD 卡后,设置 U-Boot 从 SD 卡启动:

# 在 U-Boot 命令行中设置
setenv bootcmd 'mmc dev 0;fatload mmc 0:1 0x80800000 zImage;fatload mmc 0:1 0x83000000 imx6ull-alientek-emmc.dtb;bootz 0x80800000 - 0x83000000'
setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk0p2 rootwait rw'
saveenv
boot

2.7 启动验证

# 串口终端观察启动日志
# 成功标志:出现 Linux version 和 login 提示

# 登录后验证
uname -a           # 确认内核版本
df -h              # 确认文件系统挂载
ls /               # 确认根文件系统内容

⚠️ 注意: 一旦 SD 卡启动测试通过,建议用 USB OTG(MfgTool)烧写 EMMC 进行最终部署。


三、串口烧写

3.1 适用场景

串口烧写主要用于紧急恢复场景——当 EMMC 中无有效系统、网络不可用、USB 也无法使用时,通过 UART 串口将固件传输到板载 DDR,再由 U-Boot 写入存储。

3.2 工具准备

  • 串口终端软件:SecureCRT、minicom 或 PuTTY
  • 波特率:115200, 8N1
  • 连接线:USB 转 TTL 串口线

3.3 U-Boot Kermit/Ymodem 烧写

在 U-Boot 命令行中使用 loadb 命令配合串口协议传输文件:

# 1. 设置串口波特率(U-Boot 中执行)
setenv baudrate 115200
saveenv

# 2. 使用 loadb 命令接收文件(Ymodem 协议)
loadb 0x80800000

# 3. 在终端软件中选择"发送文件" -> Ymodem 协议
#    选择 zImage 文件进行发送

# 4. 发送完成后,写入 EMMC
mmc dev 1
mmc write 0x80800000 0x800 0x3000

3.4 串口烧写完整流程

# === 阶段一:传输 U-Boot ===
loadb 0x87800000
# 通过 Ymodem 发送 u-boot.imx
mmc dev 1
mmc write 0x87800000 0x2 0x300

# === 阶段二:传输内核 ===
loadb 0x80800000
# 通过 Ymodem 发送 zImage
mmc dev 1
mmc write 0x80800000 0x800 0x3000

# === 阶段三:传输设备树 ===
loadb 0x83000000
# 通过 Ymodem 发送 imx6ull-alientek-emmc.dtb
mmc dev 1
mmc write 0x83000000 0x3800 0x200

# === 阶段四:传输根文件系统 ===
loadb 0x83800000
# 通过 Ymodem 发送 rootfs.tar.bz2
mmc dev 1
mmc write 0x83800000 0x4000 0x40000

3.5 优缺点分析

优点 缺点
不依赖任何外部接口(仅需串口) 速度极慢(115200 bps ≈ 10KB/s)
可恢复任何状态的板子 大文件传输耗时长
工具简单,几乎所有终端都支持 需要人工操作发送协议

💡 实用建议: 串口烧写仅作为最后手段。对于 IMX6ULL 的量产恢复,建议保留一个最小 U-Boot 在 EMMC 中,通过 U-Boot 的 usb烧写 功能恢复系统。


四、USB烧写

4.1 MfgTool 工具简介

MfgTool 是 NXP 官方提供的系统烧写工具,专为 I.MX 系列芯片设计,运行在 Windows 平台。工具路径通常为:

5、开发工具 -> 3、NXP官方原版MFG_TOOL烧写工具 -> L4.1.15_2.0.0-ga_mfg-tools.tar.gz

4.2 工具目录结构

mfgtools-with-rootfs/mfgtools/
├── MfgTool2.exe              # 烧写主程序
├── mfgtool2-yocto-mx-evk-emmc.vbs   # EMMC烧写脚本
├── mfgtool2-yocto-mx-evk-nand.vbs   # NAND烧写脚本
├── cfg.ini                  # 配置文件
└── Profiles/Linux/OS Firmware/
    ├── ucl2.xml             # 烧写命令脚本
    ├── firmware/            # 第一阶段文件(下载到DDR)
    │   ├── u-boot-imx6ull14x14evk_emmc.imx
    │   ├── zImage
    │   └── zImage-imx6ull-14x14-evk-emmc.dtb
    └── files/               # 第二阶段文件(写入EMMC)
        ├── u-boot-imx6ull14x14evk_emmc.imx
        ├── zImage
        ├── zImage-imx6ull-14x14-evk-emmc.dtb
        └── rootfs_nogpu.tar.bz2

4.3 MfgTool 工作原理

flowchart TD
    accTitle: MfgTool Two-Stage Flashing Process
    accDescr: MfgTool uses a two-stage process: first boot Linux in DDR via USB, then flash full system to EMMC

    connect["🔌 USB OTG连接"] --> bootstrap["📥 阶段一:BootStrap"]
    bootstrap --> ddr["💾 下载firmware到DDR"]
    ddr --> boot["🚀 DDR中启动Linux"]
    boot --> flash["📦 阶段二:烧写"]
    flash --> partition["🗂️ 格式化EMMC分区"]
    partition --> write["✏️ 写入files目录文件"]
    write --> done["✅ 烧写完成"]

    classDef stage1 fill:#dbeafe,stroke:#2563eb,stroke-width:2px,color:#1e3a5f
    classDef stage2 fill:#fef9c3,stroke:#ca8a04,stroke-width:2px,color:#713f12
    classDef done fill:#dcfce7,stroke:#16a34a,stroke-width:2px,color:#14532d
    class bootstrap,ddr,boot stage1
    class flash,partition,write stage2
    class done done

阶段一(BootStrap):将 firmware/ 目录中的 U-Boot、zImage 和设备树通过 USB OTG 下载到 DDR,启动临时 Linux 系统。

阶段二(Updater):利用 DDR 中运行的 Linux 系统,将 files/ 目录中的完整系统(含 rootfs)烧写到 EMMC。

4.4 硬件连接与设置

  1. USB OTG 连接:使用 USB 线连接开发板 USB_OTG1 接口到电脑
  2. 拨码开关:拨到 USB 下载模式
  3. 弹出 TF 卡:如已插入 TF 卡,先弹出,待识别后再插入
  4. 按复位键:进入 USB 模式,电脑识别出 HID 设备

⚠️ V2.4 以上版本底板:USB OTG 口已更换为 Type-C 接口。

4.5 自制系统的文件替换

将自己编译的文件重命名后替换 MfgTool 中的原始文件:

原始文件 重命名目标 所在目录
u-boot.imx u-boot-imx6ull14x14evk_emmc.imx firmware + files
zImage zImage(不改名) firmware + files
imx6ull-alientek-emmc.dtb zImage-imx6ull-14x14-evk-emmc.dtb firmware + files
rootfs.tar.bz2 rootfs_nogpu.tar.bz2 files

4.6 烧写步骤

# 1. 准备根文件系统(在 Ubuntu 中打包)
cd rootfs/
tar -vcjf rootfs.tar.bz2 *

# 2. 将4个文件拷贝到 Windows 的 MfgTool 目录
#    firmware/ 放 3 个文件(u-boot + zImage + dtb)
#    files/ 放 4 个文件(u-boot + zImage + dtb + rootfs)

# 3. 双击 mfgtool2-yocto-mx-evk-emmc.vbs
# 4. 确认界面显示"符合 HID 标准的供应商定义设备"
# 5. 点击 Start 开始烧写
# 6. 等待显示 "Done" 后点击 Stop -> Exit
# 7. 拨码开关拨回 EMMC 启动,重启开发板

4.7 网络开机自启动配置

烧写完成后,Linux 内核不会自动打开网卡。在 /etc/init.d/rcS 中添加:

#!/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/lib:/usr/lib
export PATH LD_LIBRARY_PATH runlevel

# 网络开机自启动
ifconfig eth0 up
ifconfig eth0 192.168.1.251 netmask 255.255.255.0
route add default gw 192.168.1.1

五、量产方案

5.1 量产工具对比

工具 平台 速度 适用规模 特点
MfgTool Windows ~20MB/s 小批量 NXP 官方,配置灵活
uuu (Universal Update Utility) 跨平台 ~20MB/s 中批量 NXP 新工具,命令行友好
SD卡量产 任意 ~10MB/s 中批量 无需电脑,可预烧写
OTA远程升级 云端 受限于带宽 大规模 远程部署,需网络
自动化脚本 Linux 可并行 大批量 灵活定制,可多设备并行

5.2 uuu 工具使用

uuu 是 NXP 推荐的新一代跨平台烧写工具,替代 MfgTool:

# 安装 uuu(Linux/Mac/Windows)
# Ubuntu:
sudo apt install uuu

# 编写烧写脚本 uuu.lst
SDPS: boot -f firmware/u-boot-imx6ull14x14evk_emmc.imx
FB: flash -raw2sparse all firmware/image.img
FB: done

# 执行烧写
sudo uuu uuu.lst

5.3 SD卡批量量产流程

适用于需要大量预烧写 SD 卡的生产场景:

#!/bin/bash
# sdcard_flash.sh - SD卡批量烧写脚本

SD_DEV=$1  # 如 /dev/sdb

echo "=== 格式化 SD 卡 ==="
sudo parted ${SD_DEV} mklabel msdos
sudo parted ${SD_DEV} mkpart primary fat32 1MiB 128MiB
sudo parted ${SD_DEV} mkpart primary ext4 128MiB 100%
sudo mkfs.vfat -F 32 ${SD_DEV}1
sudo mkfs.ext4 ${SD_DEV}2

echo "=== 烧写 U-Boot ==="
sudo dd if=u-boot.imx of=${SD_DEV} bs=1k seek=2 conv=fsync

echo "=== 拷贝内核与设备树 ==="
sudo mount ${SD_DEV}1 /mnt/sdboot
sudo cp zImage /mnt/sdboot/
sudo cp imx6ull-alientek-emmc.dtb /mnt/sdboot/
sudo umount /mnt/sdboot

echo "=== 拷贝根文件系统 ==="
sudo mount ${SD_DEV}2 /mnt/sdrootfs
sudo tar -xvf rootfs.tar.bz2 -C /mnt/sdrootfs/
sudo umount /mnt/sdrootfs

echo "=== 烧写完成 ==="

5.4 自动化烧写脚本(USB 多设备并行)

#!/bin/bash
# usb_mass_flash.sh - USB多设备并行烧写

IMAGE_DIR="./firmware"
FLASH_SCRIPT="./uuu.lst"

# 监控新设备接入
watch_usb_device() {
    while true; do
        DEVICE_COUNT=$(lsusb | grep "15a2:0080" | wc -l)
        echo "检测到 ${DEVICE_COUNT} 个待烧写设备"
        sleep 2
    done
}

# 主流程
echo "等待设备连接..."
watch_usb_device &

# 为每个设备启动烧写进程
for dev in $(uuu_list 2>/dev/null); do
    echo "烧写设备: ${dev}"
    sudo uuu -d ${dev} ${FLASH_SCRIPT} &
done

wait
echo "所有设备烧写完成"

5.5 量产质量检查

# 烧写后自动化验证脚本
#!/bin/bash
# verify_flash.sh

BOARD_IP=$1

# 1. 启动检测(等待设备上线)
timeout 60 bash -c "until ping -c 1 ${BOARD_IP}; do sleep 2; done"
echo "✅ 设备启动成功"

# 2. 版本验证
VERSION=$(ssh root@${BOARD_IP} "cat /etc/version")
echo "固件版本: ${VERSION}"

# 3. 内存测试
ssh root@${BOARD_IP} "free -m"

# 4. 存储测试
ssh root@${BOARD_IP} "df -h"

# 5. 网络测试
ssh root@${BOARD_IP} "ping -c 3 8.8.8.8"

echo "✅ 验证通过"

六、烧写问题排查

6.1 MfgTool 常见错误

错误现象 可能原因 解决方案
无法识别 HID 设备 USB 线未连接或拨码开关错误 检查 USB 线连接;确认拨码开关在 USB 模式
"No device connected" TF 卡未弹出 弹出 TF 卡后重新插拔 USB
烧写过程中断 USB 供电不足 使用独立供电 USB Hub 或更换 USB 口
"Jumping to OS image" 后卡住 firmware 文件错误 检查 firmware 目录文件是否正确替换
"Done" 但无法启动 设备树或 U-Boot 名称不匹配 确认文件重命名与 ucl2.xml 一致

6.2 内核启动失败排查

现象: 串口输出 "Starting kernel ..." 后无任何信息。

# 在 U-Boot 命令行中检查
mmc dev 1              # 切换到 EMMC
ls mmc 1:1             # 查看分区 1 文件列表
# 确认设备树文件名是否正确

# 检查 bootcmd 中的设备树文件名
printenv bootcmd
# 确保设备树文件名与实际烧写的一致

解决方案

# 方法一:在 U-Boot 中临时修改
setenv bootcmd 'mmc dev 1;fatload mmc 1:1 80800000 zImage;fatload mmc 1:1 83000000 imx6ull-alientek-emmc.dtb;bootz 80800000 - 83000000'
setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw'
saveenv
boot

# 方法二:修改 U-Boot 源码(永久方案)
# 文件:include/configs/mx6ull_alientek_emmc.h
# 修改 findfdt 环境变量,将设备树文件名改为 imx6ull-alientek-emmc.dtb

6.3 调试技巧

# 1. 查看 U-Boot 环境变量
printenv

# 2. 查看 EMMC 分区信息
mmc part

# 3. 手动读取文件验证
mmc dev 1
fatload mmc 1:1 0x80800000 zImage
# 无报错说明文件读取正常

# 4. 查看设备树内容
fdt addr 0x83000000
fdt print /

# 5. 串口日志抓取(SecureCRT)
# 启用日志记录,保存完整启动日志用于分析

七、跨平台对比

7.1 IMX6ULL vs STM32MP1 vs RK3568 烧写差异

特性 IMX6ULL STM32MP1 RK3568
官方工具 MfgTool / uuu STM32CubeProgrammer RKDevTool / upgrade_tool
烧写接口 USB OTG USB DFU / UART USB OTG / SD 卡
启动模式 拨码开关 BOOT0 引脚 按住 Recovery + 上电
分区格式 固定脚本定义 XML 配置文件 parameter.txt + 分区表
设备树支持 .dtb 文件 .dtb 文件 .dtb 文件
量产推荐 uuu 工具 CubeProgrammer 脚本 upgrade_tool 批量
OTA 支持 自行实现 自行实现 A/B 分区原生支持

7.2 烧写流程对比

flowchart LR
    accTitle: Cross-Platform Flashing Workflow Comparison
    accDescr: Comparison of flashing workflows for three popular embedded Linux SoC platforms

    subgraph IMX6ULL
        a1[USB OTG] --> a2[MfgTool/uuu]
        a2 --> a3[DDR运行临时系统]
        a3 --> a4[写入EMMC]
    end

    subgraph STM32MP1
        b1[USB DFU] --> b2[CubeProgrammer]
        b2 --> b3[直接写入Flash]
    end

    subgraph RK3568
        c1[USB OTG] --> c2[RKDevTool]
        c2 --> c3[loader模式写入]
    end

八、面试精选

题目 1:嵌入式系统烧写的核心流程是什么?

考察点: 系统烧写原理理解

参考答案:

嵌入式 Linux 系统烧写通常分为两个阶段:

  1. 引导阶段:通过 USB/串口等方式将最小引导系统(U-Boot + 内核 + 设备树)下载到 DDR 中并运行,建立一个临时的 Linux 运行环境
  2. 烧写阶段:利用临时系统对目标存储(EMMC/NAND)进行分区、格式化,然后将完整系统(含 rootfs)写入存储

这种"借鸡生蛋"的设计思路使得烧写工具不需要直接操作存储芯片的底层驱动,而是利用 Linux 内核已有的文件系统和块设备驱动来完成写入操作。

题目 2:MfgTool 中 ucl2.xml 的作用是什么?如何自定义?

考察点: 工具配置能力

参考答案:

ucl2.xml 是 MfgTool 的核心配置文件,负责:

  • 芯片识别:通过 <CFG> 段定义各芯片的 VID/PID,自动识别处理器型号
  • 烧写命令:通过 <LIST> 段定义不同存储介质(EMMC/NAND/SD)的烧写命令序列
  • 文件映射:定义 firmware 和 files 目录中文件与目标芯片的对应关系

自定义时需修改三个地方:新建 .vbs 启动脚本、修改 ucl2.xml 中的烧写命令、替换 firmware/files 中的文件。关键是确保文件命名与 ucl2.xml 中的路径一致。

题目 3:SD 卡烧写和 USB OTG 烧写的主要区别?

考察点: 烧写方式选型

参考答案:

维度 SD卡烧写 USB OTG 烧写
原理 直接 dd 写入块设备 通过 USB 传输到 DDR,再烧写
速度 ~10MB/s(取决于卡速) ~20MB/s
依赖 需要读卡器 + 主机 仅需 USB 线
量产性 可并行多卡 通常单设备烧写
灵活性 每次需物理插拔 可远程/脚本控制
恢复能力 可修复任何状态的板子 需要 ROM 中有 USB 启动代码

题目 4:量产中如何保证烧写的一致性和可靠性?

考察点: 量产工程能力

参考答案:

  1. 固件版本管理:每次烧写使用确定版本的固件包,建立版本号与 MD5 校验的映射表
  2. 烧写后验证:自动检查关键文件(U-Boot、内核、设备树)的完整性,运行基本功能测试
  3. 日志记录:记录每台设备的烧写时间、固件版本、校验结果,便于追溯
  4. A/B 分区:对 OTA 场景,采用 A/B 分区方案,支持回滚
  5. 自动化脚本:减少人工操作,批量烧写 + 批量验证
  6. 环境隔离:烧写主机与生产网络隔离,防止固件被篡改

题目 5:Linux 内核启动后输出 "Starting kernel ..." 卡住,如何排查?

考察点: 调试能力

参考答案:

这种现象说明 U-Boot 已正常工作,但 Linux 内核启动失败。排查步骤:

  1. 设备树检查:在 U-Boot 中 ls mmc 1:1 确认设备树文件是否存在且名称正确
  2. 启动参数检查printenv bootargs 确认 console 参数(串口号和波特率)与硬件一致
  3. 内核调试输出:在 bootargs 中添加 earlyconignore_loglevel 获取更多日志
  4. 设备树调试:在 U-Boot 中 fdt addr + fdt print 验证设备树内容
  5. DDR 检查:确认内核加载地址和设备树地址没有重叠

    # 增强调试的 bootargs 示例
    setenv bootargs 'console=ttymxc0,115200 earlycon=imxuart,0x02020000,115200 ignore_loglevel root=/dev/mmcblk1p2 rootwait rw'
    

最后更新: 2026-09-17