news 2026/7/24 23:19:33

Linux 工控项目打包、烧录、批量量产部署完整流程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux 工控项目打包、烧录、批量量产部署完整流程

Linux 工控项目打包、烧录、批量量产部署完整流程

从开发板到出厂出货,中间隔着一条完整的量产流水线——这流程搞不定,代码写得再好也只是实验室玩具。

一、工控项目交付物构成

一个完整的Linux工控固件包,通常包含以下组件:

组件文件说明
Bootloaderuboot.img / idbloader.img引导加载器,负责硬件初始化和加载内核
内核kernel.img / zImage / ImageLinux内核镜像
设备树dtb文件硬件描述,告诉内核板子上有什么外设
根文件系统rootfs.img包含所有用户空间程序和库
应用包app.tar.gz / app.ipk你的工控应用程序
配置文件config/默认配置、网络参数等
firmware_v1.0.0/ ├── idbloader.img # Bootloader阶段1 ├── uboot.img # Bootloader阶段2 ├── kernel.img # Linux内核 ├── rk3568-board.dtb # 设备树 ├── rootfs.img # 根文件系统(ext4/squashfs) ├── app/ │ ├── myapp # 主程序 │ ├── lib/ # 依赖库 │ └── config/ # 配置文件 └── version.txt # 版本信息

二、固件打包工具

2.1 mkimage —— U-Boot镜像封装

mkimage是U-Boot自带的镜像打包工具,给内核镜像加上U-Boot识别的头信息:

# 将zImage打包成uImagemkimage-Aarm64-Olinux-Tkernel-Cnone\-a0x80080000-e0x80080000\-n"Linux Kernel"\-darch/arm64/boot/Image uImage# 参数说明:# -A 架构(arm64/x86/mips)# -O 操作系统(linux)# -T 镜像类型(kernel/ramdisk/script)# -C 压缩方式(none/gzip/bzip2)# -a 加载地址# -e 入口地址# -n 镜像名称# -d 输入文件

2.2 genext2fs —— 制作ext2文件系统镜像

# 根据目录生成ext2文件系统镜像genext2fs-b32768-drootfs_dir rootfs.img# -b 块数(每块1KB,32768块=32MB)# -d 源目录

2.3 mksquashfs —— 制作只读压缩文件系统

squashfs是工控设备根文件系统的首选,只读+压缩,掉电不损坏:

# 将rootfs目录打包成squashfs镜像mksquashfs rootfs_dir rootfs.squashfs-compxz -no-xattrs# -comp 压缩算法(xz/gzip/lzo/zstd)# xz压缩率最高,lzo解压最快

2.4 dd —— 磁盘镜像工具

# 将SD卡内容完整导出为镜像ddif=/dev/sdbof=sdcard.imgbs=4Mstatus=progress# 将镜像写入SD卡ddif=sdcard.imgof=/dev/sdbbs=4Mstatus=progressconv=fsync

三、SD卡烧录

3.1 分区方案

典型的SD卡分区布局:

| 分区 | 偏移 | 大小 | 内容 | 文件系统 | |------|------|------|------|----------| | idbloader | 0x40 | 32KB | Bootloader | 无 | | uboot | 0x4000 | 4MB | U-Boot | 无 | | boot | 0x8000 | 64MB | 内核+DTB | FAT32 | | rootfs | 0x88000 | 剩余 | 根文件系统 | ext4 |

3.2 烧录脚本

#!/bin/bash# /opt/scripts/sdcard_burn.sh# SD卡烧录脚本SDCARD_DEV=$1# /dev/sdbFIRMWARE_DIR=$2# firmware_v1.0.0/if[-z"$SDCARD_DEV"]||[-z"$FIRMWARE_DIR"];thenecho"Usage:$0<sdcard_dev> <firmware_dir>"echo" e.g:$0/dev/sdb ./firmware_v1.0.0/"exit1fiecho"========================================"echo" SD Card Burning Tool"echo" Device:$SDCARD_DEV"echo" Firmware:$FIRMWARE_DIR"echo"========================================"# 安全确认echo"WARNING: All data on$SDCARD_DEVwill be erased!"echo"Type 'YES' to continue:"read-rCONFIRMif["$CONFIRM"!="YES"];thenecho"Aborted."exit0fi# 1. 卸载所有已挂载的分区umount${SDCARD_DEV}?*2>/dev/null# 2. 写入Bootloaderecho"[1/5] Writing idbloader..."ddif="${FIRMWARE_DIR}/idbloader.img"of="$SDCARD_DEV"bs=32kseek=1conv=fsyncecho"[2/5] Writing uboot..."ddif="${FIRMWARE_DIR}/uboot.img"of="$SDCARD_DEV"bs=64kseek=128conv=fsync# 3. 创建分区echo"[3/5] Creating partitions..."# 清空分区表ddif=/dev/zeroof="$SDCARD_DEV"bs=512count=2048conv=fsync# 用fdisk或sfdisk创建分区sfdisk"$SDCARD_DEV"<<EOF label: dos${SDCARD_DEV}1 : start=8192, size=131072, type=c, bootable${SDCARD_DEV}2 : start=139264, type=83 EOF# 刷新分区表partprobe"$SDCARD_DEV"2>/dev/nullsleep2# 4. 格式化分区echo"[4/5] Formatting partitions..."mkfs.vfat-F32-nBOOT"${SDCARD_DEV}1"mkfs.ext4-F-Lrootfs"${SDCARD_DEV}2"# 5. 写入内核和根文件系统echo"[5/5] Writing kernel and rootfs..."mkdir-p/tmp/sd_boot /tmp/sd_rootmount"${SDCARD_DEV}1"/tmp/sd_bootmount"${SDCARD_DEV}2"/tmp/sd_root# 拷贝内核和DTB到boot分区cp"${FIRMWARE_DIR}/kernel.img"/tmp/sd_boot/cp"${FIRMWARE_DIR}/"*.dtb /tmp/sd_boot/# 解压rootfs到root分区if[-f"${FIRMWARE_DIR}/rootfs.tar.gz"];thentar-xzf"${FIRMWARE_DIR}/rootfs.tar.gz"-C/tmp/sd_root/elif[-f"${FIRMWARE_DIR}/rootfs.img"];thenddif="${FIRMWARE_DIR}/rootfs.img"of="${SDCARD_DEV}2"bs=4Mconv=fsyncfisyncumount/tmp/sd_boot /tmp/sd_rootecho"========================================"echo" Burning Complete!"echo"========================================"

四、eMMC/NAND烧录

4.1 fastboot(通用Android协议)

# 进入fastboot模式(U-Boot命令行中)=>fastboot0# 主机端烧录fastboot flash loader idbloader.img fastboot flash uboot uboot.img fastboot flash boot_a kernel.img fastboot flash dtbo_a rk3568-board.dtb fastboot flash system_a rootfs.img# 切换启动槽位并重启fastboot set_active a fastbootreboot

4.2 rkflashtool(瑞芯微专用)

# 查看连接的设备rkflashtool p# 读取分区表rkflashtool r 0x0 0x2000 param.img# 烧录各分区rkdeveloptool db RK3568_loader.bin rkdeveloptool wl 0x40 idbloader.img rkdeveloptool wl 0x4000 uboot.img rkdeveloptool wl 0x8000 boot.img rkdeveloptool wl 0x88000 rootfs.img# 重启设备rkdeveloptool rd

4.3 nandwrite(NAND Flash直接写入)

# 先擦除flash_erase /dev/mtd200# 写入镜像nandwrite-p/dev/mtd2 rootfs.ubi# UBI方式(NAND推荐)ubiformat /dev/mtd2-s2048-frootfs.ubi-yubiattach /dev/ubi_ctrl-m2mount-tubifs /dev/ubi0_0 /mnt/rootfs

五、量产烧录自动化

批量烧录场景下,需要自动检测设备插入并触发烧录:

#!/bin/bash# /opt/scripts/mass_burn.sh# 批量SD卡烧录脚本(配合USB Hub多卡同时烧)FIRMWARE_DIR="/opt/firmware/current"LOG_FILE="/var/log/mass_burn.log"BURN_SCRIPT="/opt/scripts/sdcard_burn.sh"echo"$(date)[INFO] Mass burn service started">>"$LOG_FILE"# udev规则:SD卡插入时自动触发# /etc/udev/rules.d/99-sdburn.rules:# ACTION=="add", KERNEL=="sd[b-z]", SUBSYSTEM=="block", \# RUN+="/opt/scripts/mass_burn.sh /dev/%k"DEVICE=$1if[-z"$DEVICE"];thenecho"$(date)[ERROR] No device specified">>"$LOG_FILE"exit1fi# 等待设备稳定sleep3# 检查设备是否存在if[!-b"$DEVICE"];thenecho"$(date)[ERROR] Device$DEVICEnot found">>"$LOG_FILE"exit1fiecho"$(date)[INFO] Start burning$DEVICE">>"$LOG_FILE"# 调用烧录脚本(非交互模式)YES=YES$BURN_SCRIPT"$DEVICE""$FIRMWARE_DIR">>"$LOG_FILE"2>&1if[$?-eq0];thenecho"$(date)[OK]$DEVICEburned successfully">>"$LOG_FILE"# 闪烁指示灯或播放提示音echo1>/sys/class/leds/green/brightnesssleep1echo0>/sys/class/leds/green/brightnesselseecho"$(date)[ERROR]$DEVICEburn failed!">>"$LOG_FILE"echo1>/sys/class/leds/red/brightnessfi

六、量产部署完整流程

固件版本管理 │ ▼ ┌─────────────┐ │ 1. 编译打包 │ ← CI/CD自动构建,产出固件包 └──────┬──────┘ ▼ ┌─────────────┐ │ 2. 烧录固件 │ ← SD卡/eMMC烧录 └──────┬──────┘ ▼ ┌─────────────┐ │ 3. 首次启动 │ ← 系统初始化、分区扩展 └──────┬──────┘ ▼ ┌─────────────┐ │ 4. 功能验证 │ ← 自动化测试脚本 └──────┬──────┘ ▼ ┌─────────────┐ │ 5. 烧录MAC │ ← 写入唯一MAC/序列号 └──────┬──────┘ ▼ ┌─────────────┐ │ 6. 出库登记 │ ← 记录序列号、版本、日期 └─────────────┘

6.1 固件版本管理

# /etc/version 文件cat/etc/version# FW_VERSION=1.0.3# FW_DATE=2026-07-13# FW_GIT_COMMIT=a1b2c3d# HW_VERSION=V2.1

与git tag关联:

# 发布固件时打taggittag-av1.0.3-m"Release v1.0.3: fix watchdog timeout issue"gitpush origin v1.0.3# 构建脚本读取tag写入版本文件GIT_TAG=$(gitdescribe--tags--always)BUILD_DATE=$(date+%Y-%m-%d)GIT_COMMIT=$(gitrev-parse--shortHEAD)cat>rootfs/etc/version<<EOF FW_VERSION=${GIT_TAG}FW_DATE=${BUILD_DATE}FW_GIT_COMMIT=${GIT_COMMIT}HW_VERSION=V2.1 EOF

6.2 首次启动配置脚本

#!/bin/bash# /opt/scripts/firstboot.sh# 首次启动初始化(通过systemd firstboot服务触发)MARKER="/etc/.firstboot_done"if[-f"$MARKER"];thenexit0# 已执行过fiecho"=== First Boot Initialization ==="# 1. 扩展rootfs分区到整个磁盘ROOT_DEV=$(findmnt /-oSOURCE-n)PART_NUM=$(echo"$ROOT_DEV"|grep-o'[0-9]*$')# resize2fs扩展ext4文件系统resize2fs"$ROOT_DEV"# 2. 生成SSH密钥ssh-keygen-A# 3. 设置时区ln-sf/usr/share/zoneinfo/Asia/Shanghai /etc/localtime# 4. 生成唯一设备IDecho"DEV_ID=$(cat/proc/sys/kernel/random/uuid)">/etc/device_id# 5. 启用核心服务systemctlenablemyapp.service systemctlenablesshd.servicetouch"$MARKER"echo"=== First Boot Done ==="reboot

七、OTA远程升级方案

7.1 A/B分区切换方案

| 分区 | 内容 | 状态 | |------|------|------| | boot_a | 内核槽位A | 当前活跃 | | boot_b | 内核槽位B | 备用 | | system_a | 根文件系统A | 当前活跃 | | system_b | 根文件系统B | 备用 |

升级流程:

#!/bin/bash# /opt/scripts/ota_update.shNEW_FW=$1# 新固件包路径# 1. 确定当前活跃槽位ACTIVE_SLOT=$(bootctl status|grep"Current Slot"|awk'{print $3}')if["$ACTIVE_SLOT"="a"];thenTARGET_SLOT="b"elseTARGET_SLOT="a"fiecho"Active:$ACTIVE_SLOT, Target:$TARGET_SLOT"# 2. 写入新固件到非活跃槽位fastboot flash boot_${TARGET_SLOT}${NEW_FW}/kernel.img fastboot flash system_${TARGET_SLOT}${NEW_FW}/rootfs.img# 3. 设置下次启动使用新槽位bootctl set_active$TARGET_SLOT# 4. 重启,尝试新固件reboot# 5. 如果新固件正常,应用确认(在应用中调用)# bootctl mark_successful# 如果启动失败,bootloader自动回滚到旧槽位

7.2 增量升级

如果只是应用层更新,不需要刷整包,用差分包更高效:

# 生成差分包bsdiff old_app.tar.gz new_app.tar.gz app_patch.diff# 设备端应用差分bspatch old_app.tar.gz new_app.tar.gz app_patch.diff

八、烧录常见问题排查

问题可能原因解决方案
dd写入失败SD卡写保护/损坏检查写保护开关,换卡
设备不启动Bootloader未烧录或地址错误检查偏移地址,确认idbloader写入位置
内核启动后挂死DTB不匹配确认DTB与硬件版本一致
rootfs挂载失败文件系统损坏重新格式化分区,检查镜像完整性
烧录后分区大小不对未做首次扩展执行resize2fs扩展分区
fastboot无法连接USB驱动/线缆换数据线,检查udev规则

8.1 验证镜像完整性

# 生成校验和sha256sum uboot.img kernel.img rootfs.img>checksums.sha256# 设备端校验sha256sum-cchecksums.sha256# uboot.img: OK# kernel.img: OK# rootfs.img: OK

九、量产部署Checklist

序号检查项状态
1固件版本号已更新并打git tag
2所有镜像SHA256校验通过
3SD卡/eMMC烧录成功,无报错
4设备首次启动正常,串口有输出
5首次启动脚本执行完成
6rootfs分区已扩展到完整容量
7网口可通信,IP获取正常
8串口数据收发正常
9看门狗功能验证通过
10应用程序自动启动且运行正常
11MAC地址/序列号已烧录
12重启3次无异常
13出库信息登记(序列号/版本/日期)

量产部署的核心是标准化和可重复。每一步都有明确的检查项,每一台设备都走同样的流程,不依赖人的经验,这样才能保证100台设备100台稳定。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/24 23:18:16

网盘直链下载助手终极指南:免费解锁九大网盘高速下载的完整方案

网盘直链下载助手终极指南&#xff1a;免费解锁九大网盘高速下载的完整方案 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 &#xff0c;支持 百度网盘 / 阿里云盘 / 中国移动云…

作者头像 李华
网站建设 2026/7/24 23:15:11

微服务框架中获取用户信息

从流程可以看出&#xff0c;浏览在访问服务时会携带jwt向微服务发起请求&#xff0c;中间会先经过网关。网关从jwt中获取用户信息并保存到请求中&#xff0c;然后再转发给对应服务。在到达业务层之前会有拦截器将用户信息存入ThreadLocal中。 1.在经过网关过滤器被拦截时将用户…

作者头像 李华
网站建设 2026/7/24 23:13:48

游戏任务系统插件Quests 2核心解析:可视化架构与实战开发指南

1. 项目概述&#xff1a;为什么我们需要一个专业的任务系统插件&#xff1f;在游戏开发中&#xff0c;任务系统&#xff08;Quest System&#xff09;是连接玩家与游戏世界、驱动叙事和引导游戏进程的核心骨架。无论是开放世界中的史诗主线&#xff0c;还是角色扮演游戏里的琐碎…

作者头像 李华
网站建设 2026/7/24 23:13:17

车载手持无线吸尘器选购指南:从核心需求到实际体验全解析

这类车载手持无线吸尘器最值得先看的不是功能列表&#xff0c;而是它到底能不能在真实用车和家用场景里稳定解决清洁问题。巴斯这款吸尘器主打16000Pa吸力、紫外线杀菌和多功能切换&#xff0c;但实际使用时&#xff0c;我更关注的是无线续航、吸力持久性、尘盒清理便利性以及不…

作者头像 李华
网站建设 2026/7/24 23:10:11

新一代 Ai coding 工程进阶系列-前言

前言&#xff1a;绝大多数AI开发者&#xff0c;都卡在「只会用、不会建」做AI应用开发、AI Coding落地的这几年&#xff0c;你是不是一直有这种直观感受&#xff1a;明明模型越来越强&#xff0c;但自己写的AI脚本、项目代码&#xff0c;稳定性、复用性、持续性始终上不去&…

作者头像 李华
网站建设 2026/7/24 23:09:15

如何轻松导出原神抽卡记录:新手也能掌握的完整数据分析指南

如何轻松导出原神抽卡记录&#xff1a;新手也能掌握的完整数据分析指南 【免费下载链接】genshin-wish-export Easily export the Genshin Impact wish record. 项目地址: https://gitcode.com/GitHub_Trending/ge/genshin-wish-export 你是否曾经好奇自己在《原神》中到…

作者头像 李华