简介:海思HiTool烧写工具包面向机顶盒、电视机主板及海思芯片方案的硬件调试与量产烧录人员,覆盖从镜像烧写到寄存器读写的完整链路。包内集成HiBurn镜像烧写与上载、HiLoader升级包制作、HiReg图形化寄存器与内存读写、HiDebugger调试信息抓取及码流录制、HiFastplay开机画面与瞬播镜像制作等组件,便于在串口连接环境下完成主板升级与故障排查。资源共1220个文件,以jar程序模块、cfg配置、chip芯片定义、dll动态库、svf边界扫描、xml与tcl脚本、exe可执行程序为主,另有少量图片、日志和说明文档,压缩包约166.47MB,目录按工具与芯片型号组织,检索方便。已有3251人学习下载,适合需要对照官方工具链完成烧录验证、梳理多平台芯片支持的硬件工程师与维修人员参考。
1. HiTool 是什么:板子起不来时最后一条可供尝试的路径
凌晨两点,一块刚贴完片的板子上电只吐出半行乱码,内核停在Waiting for root device。这时候能救场的往往不是示波器,而是 HiTool——一套跑在 Windows 上的烧写工具,直接跟芯片内部的 BootROM 握手,把 fastboot、boot、kernel、rootfs 一个接一个写入 eMMC、NAND 或 SPI Flash。它不属于源码软件那一类,随 SDK 一起分发的闭源二进制,源码改不了,但实验室点板和产线小批量烧片基本绕不开它。适合谁:手里已经有板子、有镜像,却卡在“烧不进去”或者“烧进去起不来”的 BSP、驱动、硬件工程师,以及需要给十几块样机统一灌版本的团队。下面按真实操作顺序拆:连接怎么接、分区表怎么写、失败了看哪里、怎么把三小时的串口烧写压缩到十分钟。
2. 三根线接对之前,别急着点烧写
HiTool 界面上那个“烧写”按钮极其朴素,点了之后弹一句“请给单板上电或复位”,看着毫无门槛。真正卡人的全在按钮之外:串口线是不是交叉的、USB 驱动装没装、网口 IP 是不是同网段、分区表里的偏移量有没有重叠。这一章先把物理层和握手时序讲清楚,再给一个能照着敲的最小流程。
2.1 串口、网口、USB 三条通路的能力边界
三条通路不是随便选一条就行,它们对应的是芯片在不同启动阶段暴露出来的不同接口能力。串口是最底层的保底方式,BootROM 阶段就会往外打印,几乎不可能完全没反应,缺点是慢;网口和 USB 快得多,但依赖 BootROM 或 fastboot 阶段对相应控制器的初始化,板子硬件稍微有点问题就直接不通。
| 通道 | 实测典型速率 | 前置条件 | 适合场景 | 失败表象 |
|---|---|---|---|---|
| 串口 | 9~11 KB/s(115200 8N1) | USB-TTL 线,TX/RX 交叉、共地 | 首次点板、BootROM 无输出时定位 | 日志全黑,或清一色乱码 |
| 网口 | 3~8 MB/s | 板端 MAC/PHY 正常,PC 与单板同网段 | 大 rootfs、反复迭代 | 卡在 TFTP 超时或 IP 冲突 |
| USB | 20~40 MB/s | 驱动装好,线是数据线不是充电线 | 调试期高频烧写 | 设备管理器压根不认新设备 |
新手最容易犯的错是把串口当“备用方案”,实际上它是唯一能在芯片还没跑起任何软件时说话的通道。板子完全没反应的那一刻,先接串口抓日志,看到BootRom字样才说明芯片活着、时钟和 DDR 初始化没崩,后面才有得谈。如果串口一个字都没有,先别怀疑工具,去量供电和复位电平。
网口烧写还有个隐藏前提:单板的 MAC 地址和 PHY 得在 BootROM 阶段就被正确识别。有些板子 PHY 的复位脚接得随意,冷启动时 PHY 还没就绪,BootROM 扫描就落空了,表现就是工具一直提示等待、而串口日志里能看到网络初始化失败的痕迹。这种板子只能先用串口烧一版正常的 fastboot 进去,之后再用网口。
提示:判断该用哪条通道,不看工具支不支持,看板上实际焊了什么。板子只有调试串口引出,就别在网口配置上耗时间。
2.2 上电时序与握手窗口:顺序反了就一定失败
这是被问得最多、也是最不值当的一个坑。HiTool 的工作方式是:点击“烧写”后,工具进入监听状态,通过选定的物理通道周期性向板子发出握手请求;板子复位后,BootROM 在启动流程很早的阶段会短暂检测这个通道上有没有下载请求,有就停下来接收 fastboot,没有就继续走正常启动。
也就是说,正确顺序永远是:先点“烧写”,让工具进入等待,再给板子上电或按复位。反过来先上电再点烧写,板子早就跑过 BootROM 那几毫秒的检测窗口了,工具只能干等到超时。这个窗口在部分平台上短得离谱,按复位的手速都要练一下。
握手成功的第一标志是串口日志里出现 fastboot 的版本行。此时 fastboot 已经被下载到 DDR 里运行,接下来才是真正把镜像一个个写进存储介质。所以“握手失败”和“写入失败”是两类完全不同的问题:前者是物理层和启动介质选择的问题,后者是分区表、容量、介质寿命的问题。分不清这两类,排查就会来回绕。
顺带说一句启动介质的选择。很多板子用电阻或者拨码决定从 eMMC 起还是从 SPI Flash 起,也有用 GPIO 组合的。如果板子被人动过这些配置,BootROM 会去一个空的介质上找东西,串口表现是启动到一半就没声了,工具这边则是握手请求发出去无人应答。改分区表之前,先用万用表确认启动选择脚的电平,比反复点按钮省时间。
2.3 一个可以照抄的最小烧写流程
把下面这套流程走通一遍,后面所有复杂配置都是在这个骨架上加东西。假设串口线已经接好,板子上的调试串口是 3.3V 电平,PC 端是一个 USB 转串口模块。
第一步,先在 PC 上把日志通道占住,确认板子真的在说话。Linux 下不用装任何图形工具:
# 关掉回显和硬件流控,否则 USB-TTL 没接 RTS/CTS 时会吞掉字节 stty -F /dev/ttyUSB0 115200 raw -echo -crtscts # 60 秒窗口留给你给板子上电,日志同时落盘 timeout 60 cat /dev/ttyUSB0 | tee bootrom_$(date +%H%M).lograw关掉行缓冲和特殊字符处理,日志里才不会有莫名其妙的控制字符;-echo防止本机把收到的字节回显回去造成日志重复;-crtscts是重点,绝大多数廉价 USB-TTL 模块的 RTS/CTS 是悬空的,开着硬件流控会随机丢字节,表现就是日志偶尔缺几行,很容易误判成板子的问题。timeout 60只是给一个观察窗口,不影响后续操作。
Windows 上习惯用 Python 直接抓,顺便加时间戳,方便跟工具日志对齐:
import sys, time, serial port = sys.argv[1] if len(sys.argv) > 1 else "COM7" ser = serial.Serial(port, 115200, timeout=0.2) # timeout 让 read 不永久阻塞 t0 = time.time() while time.time() - t0 < 60: data = ser.read(4096) if data: # errors="replace" 保证乱码不会抛异常打断抓取 sys.stdout.write(data.decode("utf-8", errors="replace")) sys.stdout.flush() ser.close()timeout=0.2是读超时,不是连接超时,设太小会频繁空转、设太大会让 Ctrl+C 不灵敏;errors="replace"这一行是关键,波特率没匹配时收到的就是一堆无效字节,硬解码会直接抛UnicodeDecodeError把脚本打死。
第二步,打开 HiTool,在芯片型号下拉框里选与板上丝印完全一致的那一项。这一步选错,后续所有参数都是错的,而且失败现象往往很暧昧——不是立刻报错,而是握手成功但镜像跑不起来。
第三步,加载分区表文件。首次接触这块板子,直接用 SDK 里配套的那份,不要自己从零写。
第四步,在“烧写方式”里选“烧写全部”,让工具把所有勾选的分区按顺序灌一遍。
第五步,设置串口参数:端口号对上刚才能抓到日志的那个口,波特率 115200,校验位无,数据位 8,停止位 1。
第六步,点“烧写”,看到提示后给板子上电。此时工具下方会出现进度条,逐个分区走。
第七步,烧完别急着断电,等工具提示“烧写成功”并且串口日志把内核启动信息吐完,再决定是留在烧写模式还是切回正常启动。
整个流程跑通一次之后,立刻把配置保存下来。HiTool 的配置是跟着目录走的,换个目录打开就是一套空配置,产线上经常因为有人图省事在桌面直接双击 exe,结果配置全丢、误烧成别的板子的镜像。
3. 分区表写不对,前面全白干
分区表是 HiTool 里唯一一个“写错不报错、烧完才暴雷”的东西。它不参与握手,也不影响 fastboot 下载,工具会老老实实按你给的偏移量写下去,然后板子启动时告诉你找不到根文件系统。这一章把 XML 里的字段逐个拆开,再给一个用脚本生成的方案,最后把 bootargs 这条隐形的依赖链讲清楚。
3.1 XML 字段逐项拆解
不同 SDK 版本的分区表字段名会有些出入,但核心就那么几个。下面是常见结构,字段含义比字段拼写更重要:
<Partition_Table> <!-- Name:分区名,必须和内核 blkdevparts 里写的名字一模一样 --> <Partition Name="fastboot" Length="1M" Start="0x0" FileName="fastboot.bin" sel="1"/> <Partition Name="boot" Length="16M" Start="0x100000" FileName="boot.img" sel="1"/> <Partition Name="rootfs" Length="200M" Start="0x1100000" FileName="rootfs.squashfs" sel="1"/> <Partition Name="userdata" Length="0" Start="0xD900000" FileName="" sel="1"/> </Partition_Table>| 字段 | 含义 | 常见误用 |
|---|---|---|
Name | 分区标识 | 用中文或带空格,内核参数里没法引用 |
Length | 分区容量 | 按十进制理解成字节,实际是带单位的字符串 |
Start | 在介质上的字节偏移 | 手算十六进制,改一个分区后面全要改 |
FileName | 对应镜像 | 写绝对路径,换台机器就找不到 |
sel | 是否参与本次烧写 | 调试时忘记置 0,把参数区覆盖掉 |
Start是重灾区。分区必须按介质擦除块对齐,eMMC 上常见是按 512KB 或更大对齐,SPI NAND 一般按 128KB 或 256KB 的块对齐。手动排偏移量,改一次 rootfs 大小就要把后面几个分区全部重算一遍,算出错位的概率极高,而且工具不会拦你——它只会忠实地把镜像写到重叠的区域,把相邻分区的前几个字节盖掉。
Length写 0 在多数版本里表示“吃掉剩余空间”,这个语义在不同版本上不完全一致,稳妥做法是最后一块才用。
FileName建议一律用相对路径,把分区表和所有镜像放在同一个工作目录下,整个目录打包拷给产线。用绝对路径的后果是:换台机器打开,工具提示找不到文件,或者更糟——找到的是另一版同名镜像。
注意:分区表改完之后,务必回头核对内核启动参数里的分区描述,两者不同源是启动失败最常见的原因,且现象极其迷惑。
3.2 用脚本生成分区表,别手改十六进制
既然手动排偏移量必错,那就把这件事交给脚本。思路很简单:维护一份声明式清单,脚本负责对齐和累加,输出 XML。这样做的好处是改一个分区大小之后,成本为零。
#!/usr/bin/env python3 """gen_partition.py —— 由声明式清单生成分区表,避免手算偏移量出错""" import xml.etree.ElementTree as ET # 对齐粒度:eMMC 取 512KB,SPI NAND 一般取 128KB,按实际介质改 ALIGN = 512 * 1024 # size 单位为字节;size=0 表示占用剩余空间,只能出现在最后一项 PARTS = [ {"name": "fastboot", "size": 1 << 20, "file": "fastboot.bin"}, {"name": "boot", "size": 16 << 20, "file": "boot.img"}, {"name": "rootfs", "size": 200 << 20, "file": "rootfs.squashfs"}, {"name": "userdata", "size": 0, "file": ""}, ] def align_up(x, a=ALIGN): """向上对齐到 a 的整数倍,分区起点必须落在擦除块边界""" return (x + a - 1) // a * a def human(n): """把字节数转成工具能识别的 K/M 写法""" for unit in ("K", "M", "G"): n //= 1024 if n < 1024: return f"{n}{unit}" return f"{n}T" root = ET.Element("Partition_Table") cursor = 0 for p in PARTS: start = align_up(cursor) cursor = start + p["size"] if p["size"] else start ET.SubElement(root, "Partition", { "Name": p["name"], "Length": human(p["size"]) if p["size"] else "0", "Start": hex(start), "FileName": p["file"], "sel": "1", }) ET.indent(root) # Python 3.9+ 才有,旧版可换成 minidom 美化 ET.ElementTree(root).write("partition_table.xml", encoding="utf-8") print(f"生成完毕,介质占用止于 {hex(cursor)}")ALIGN是唯一需要按介质调整的参数,改错的表现是:烧写成功,但第一批数据写进去之后,紧接着的分区数据覆盖了前一个分区的尾部,板子跑起来表现为某个配置文件损坏或者内核 paging 异常。align_up用整数除法避免浮点误差,别用math.ceil(x / a) * a,大偏移量下会丢精度。human()之所以要循环除以 1024,是因为工具界面上的Length按 K/M/G 解析,直接塞字节数会被当成 K 处理,分区瞬间变成几万倍大,工具写入时才发现超出介质容量。
最后那行print是留给你和介质容量做对照的,把输出跟cat /sys/block/mmcblk0/size(单位是 512 字节扇区)换算出来的容量比一比,超出就是分区表排得太大了。
3.3 bootargs 与分区表必须同源
这是最容易翻车、也最容易被忽略的一环。板子上的分区信息有两份:一份在 HiTool 的分区表 XML 里,决定数据写到哪儿;另一份在内核启动参数里,告诉内核去哪儿找。两份必须完全一致,包括顺序和名字。
mem=1024M console=ttyAMA0,115200 root=/dev/mmcblk0p3 rootfstype=squashfs ro rootwait blkdevparts=mmcblk0:1M(fastboot),16M(boot),200M(rootfs),-(userdata)blkdevparts里逗号分隔的顺序就是介质上的物理顺序,括号里的名字就是分区名,-表示吃掉剩余空间。内核会按这个描述去解析分区表,/dev/mmcblk0p3就是第三个分区。改了 XML 里 rootfs 的大小却没改blkdevparts,内核算出来的p3起始位置就跟实际写入位置错开,挂载时报VFS: Cannot open root device或者更糟——挂载成功但读出来的是错位数据,跑一会儿随机崩溃。
我一般会在烧写前把这两处并排打印出来对一遍,用脚本自动比对更省事:从 XML 里抽出Name和Length拼成blkdevparts的格式,跟参数文件里的那一行做字符串比对,不一致就拒绝出包。
root=后面的设备名也要跟blkdevparts的顺序对上,很多人是复制了另一块板子的参数文件,设备号差一位,现象就是内核起来了但一路报找不到根文件系统。
4. 烧写失败排查:五种现场与对应解法
这一章按现场出现频率排。每一条都写清楚现象、原因和解决办法,遇到问题直接对号入座,别再从第一页开始翻。
4.1 现象:点了烧写,提示等待上电,串口一个字都没有
原因基本在物理层。USB-TTL 的 TX 和 RX 接反是最常见的,模块上的 TX 要接板子的 RX,很多人凭直觉对接,结果就是双向都不通。其次是没共地,只接了两根信号线,电平参考漂移,表现是偶尔能收到几个乱码字节。第三是电平不对,板子调试口是 1.8V,接了 3.3V 模块,要么收不到,要么长期用会损伤 IO。还有一种隐蔽情况:串口被别的程序占着,Windows 上不报错但数据流去了别处。
解决办法:先短接 USB-TTL 模块自己的 TX 和 RX 做回环测试,能收到自己发的字符说明模块和驱动没问题;再用万用表量板子调试口的空闲电平,确认是 3.3V 还是 1.8V;最后确认设备管理器里没有黄色感叹号,串口助手之类的软件全部关掉。回环测试这一步能省掉一半的排查时间。
4.2 现象:串口有 BootROM 日志,但卡在 Download fastboot,进度 0%
现象是工具握手成功、开始下载 fastboot,然后就一直停在那里,最后超时。原因通常是fastboot.bin与芯片型号或 DDR 容量不匹配。fastboot 是跑在 DDR 里的,它自己要先完成 DDR 初始化,参数对不上就起不来,工具那边只能等到超时。另一种原因是供电不足——USB 口供电的板子在 DDR 全速跑起来的瞬间电流拉高,电压跌落导致复位。
解决办法:确认fastboot.bin的来源,必须与当前芯片和板卡 DDR 配置严格配套,不要从别的项目拷。用独立电源给板子供电,别指望调试口的 5V。如果是自己改过 DDR 参数的板子,先把参数回退到 SDK 默认值验证链路,再逐步改。
4.3 现象:写某个分区写到一半报写入失败或校验错
这一类通常跟介质和容量有关。分区表里Length之和超过了实际介质容量,前面几个分区能写,写到后面就落到不存在的地址上。eMMC 寿命耗尽或者存在坏块也会这样,尤其是被反复擦写过几百次的样机。SPI NAND 还有坏块管理的问题,如果镜像没有经过坏块跳过处理,写到大块边界就会失败。
解决办法:先把分区表生成脚本最后打印的介质占用值,跟芯片实际容量对一遍。怀疑介质问题时,用工具里的“擦除全片”跑一遍再烧,如果擦除也报错,基本可以判定介质有问题。样机阶段别心疼,直接换片,反复抢救一颗快坏的 eMMC 只会浪费更多时间。
4.4 现象:全绿,烧写成功,但上电停在 Waiting for root device
工具告诉你成功,板子告诉你失败。原因在 3.3 节讲过:分区表和blkdevparts不同源,或者是root=指向的设备号错了,还可能是rootfstype跟实际镜像格式不符(squashfs 写成 ext4 是很常见的复制粘贴事故)。
解决办法:在串口日志里找Kernel command line那一行,把实际生效的参数打出来,跟分区表逐项对照。再看内核打印的分区识别结果,通常会列出mmcblk0: p1 p2 p3 p4以及各自的扇区范围,把这些范围换算成字节,跟 XML 里的Start和Length比一比,错位立刻现形。
4.5 现象:USB 或网口烧写识别不到设备,或者速度只有几十 KB/s
USB 方向,八成是驱动没装或者装的是未签名版本,设备管理器里能看到未知设备。也可能是线的问题——现在随手抓一根 Type-C 线大概率是充电线,只有电源引脚没有数据对。网口方向,PC 和单板不在同一网段,或者 PC 上装了虚拟网卡、防火墙把 TFTP 的端口拦了。
速度慢的原因另说。串口 115200 下烧 100MB 的 rootfs 要三个小时,这是物理决定的,不是工具的问题。网口跑到几十 KB/s,先查是不是协商成了 10M 半双工,换根网线试试;再查 PC 侧是不是走了无线网络。USB 慢,多半是插在 USB 2.0 的 Hub 上,直连主板后置口再测。
提示:每次出现“识别不到设备”,先换线、换口、换机器,三步走完再怀疑软件。这条经验在嵌入式调试里几乎没有例外。
5. 把烧写时间压到十分钟以内
烧写速度这件事,很多人第一反应是换通道,实际上换通道的收益有上限,镜像体积的收益没有上限。这一章先算清楚时间花在哪,再讲怎么瘦身,最后给一个多工位并行的做法。
5.1 先算一笔带宽账
串口 115200 8N1,理论上是每秒 115200/10 = 11520 字节,实际因为有协议开销和工具侧的校验,落在 9~11 KB/s。一个 100MB 的 rootfs,光是传输就接近 3 小时,加上擦除和校验,半天就没了。这也是为什么第一次点板用串口可以接受,量产绝对不能用串口。
| 通道 | 有效吞吐 | 100MB rootfs 耗时 | 说明 |
|---|---|---|---|
| 串口 115200 | 约 10 KB/s | 约 2.8 小时 | 协议开销固定,提不动 |
| 串口 921600 | 约 80 KB/s | 约 21 分钟 | 需板端 fastboot 支持改波特率 |
| 百兆网口 | 3~6 MB/s | 20~35 秒 | 受 TFTP 块大小影响 |
| USB 2.0 | 20~40 MB/s | 3~5 秒 | 受驱动和介质写入速度限制 |
串口提波特率是个便宜办法,但有个前提:BootROM 阶段的波特率是固定的,只有等 fastboot 起来之后才能协商切换。工具里改了波特率而板端 fastboot 不支持,表现就是握手成功后立刻失联。这个特性在不同平台上的支持程度差别很大,改之前先翻 SDK 里 fastboot 的配置项。
网口这边,瓶颈往往不是带宽而是 TFTP 的块大小。默认 512 字节一块,每块都要等一个 ACK,往返延迟一叠加,实际吞吐就掉到 3 MB/s 左右。如果用的是外置 TFTP 服务,把块大小调到 1468 或者更大,速度能翻一倍。HiTool 内置的服务不一定开放这个参数,这时候可以先用工具下载 fastboot,再用板端tftp命令手动拉大文件,效果一样。
5.2 镜像瘦身比换通道更有效
一个典型的 rootfs 里,真正跑起来需要的东西可能只占三分之一。先看看空间去哪了:
# 只看两层目录,避免输出刷屏;sort -rh 按人类可读单位倒序 sudo du -h --max-depth=2 rootfs/ 2>/dev/null | sort -rh | head -20这一步能立刻揪出几个常见的体积大户:/usr/share/doc、/usr/lib/debug、交叉编译工具链被误拷进去的副本、以及一堆.a静态库。清完之后体积掉一半很常见。--max-depth=2是刻意的,层级再深就变成一片碎文件,看不出主要矛盾;sudo是因为有些目录普通用户读不了,不加会静默跳过,统计结果偏小,容易误判已经瘦身到位。
第二步是换文件系统格式。ext4 对只读的 rootfs 来说太奢侈,换 squashfs 通常能再压缩掉 50%~70%,而且挂载速度更快:
# -comp xz 压缩率最高,代价是制作慢;产线用 -comp gzip 平衡一下 mksquashfs rootfs/ rootfs.squashfs -comp xz -b 128K -noappend-b 128K是块大小,比默认的 128K 保持一致即可,改小会增大元数据开销,改大对小文件多的场景反而不划算。-noappend必须加,否则重复执行会把新内容追加到已有镜像后面,得到一个体积翻倍、内容重复的怪东西,而且工具不会报错。
瘦身之后记得同步改分区表里的Length和blkdevparts,这又回到 3.3 节那条依赖链上。
5.3 多工位并行与配置固化
单板烧写优化到头也就几分钟,真正吃时间的是“一次要烧二十块板”。HiTool 本身支持多开,但有个前提:每个实例必须用独立的程序目录。因为配置是写在程序目录下的,同一个目录起两个实例,后开的会把先开的配置覆盖掉,表现是两块板子烧成了同一个镜像,或者串口互相抢占。
做法是复制整个工具目录若干份,每份里改好串口端口号,做成批处理脚本双击启动:
# 每个工位一份独立目录,避免配置文件互相覆盖 for i in 1 2 3 4; do mkdir -p "station$i" cp -r HiTool/* "station$i"/ # 用 sed 把默认串口改成各自的端口,具体字段名按实际配置文件调整 sed -i "s/COM[0-9]\+/COM$((i + 2))/" "station$i/config.ini" done这个脚本的价值不在于省了几次点击,而在于保证四个工位用的是同一份分区表和同一批镜像——手工复制最容易出现某台机器上还留着上一版的 boot.img,烧出来的板子行为不一致,排查时能让人怀疑人生。sed那一行的字段名请按实际配置文件里的键名调整,不同版本的配置格式不一样。
工位数量不是越多越好。USB 控制器是共享带宽的,四个工位同时烧大镜像,单个速度会掉下来;串口工位反而无所谓,本来就不是瓶颈。经验值是网口烧写不超过四路,USB 不超过六路,再多就要上独立的控制卡。
6. 烧完不算完:回读校验与模板固化
工具显示“烧写成功”只代表数据发出去了,不代表落在介质上的内容和源文件一致。传输过程有校验,但介质本身、供电波动、DDR 偶发错误都可能让最终写入的内容出现偏差,而且这种偏差往往是随机位置的几个字节,表现为“十块板子里有一块偶尔启动失败”,是最难查的一类问题。
所以我习惯在烧完之后做一次回读比对,用板子自己的dd把分区读出来算摘要:
# 偏移 = fastboot(1M) + boot(16M) = 17M;count 给足分区容量 IMG=rootfs.squashfs SZ=$(stat -c%s "$IMG") # 只比对镜像实际长度,分区尾部填充字节不参与,避免 md5 天然不一致 dd if=/dev/mmcblk0 bs=1M skip=17 count=200 2>/dev/null | head -c "$SZ" | md5sum md5sum "$IMG"skip=17是按 3.2 节脚本生成的偏移量算出来的,改了分区表就要跟着改,这一步没法自动化,除非把校验也写进分区表生成脚本里一起输出。head -c "$SZ"是关键:分区容量 200M 而镜像只有 180M,直接对整个分区做摘要,多出来的填充字节会让结果永远对不上,白折腾。
几个关键观察点整理成一张表,点板阶段按这个顺序看:
| 观察点 | 位置 | 期望结果 |
|---|---|---|
| BootROM 是否启动 | 串口最开头 | 出现 BootRom 版本信息 |
| fastboot 是否跑起来 | 握手成功后 | 打印 fastboot 版本与 DDR 容量 |
| 分区识别 | 内核启动中段 | 打印的分区数与分区表一致 |
| 内核命令行 | 启动中段 | blkdevparts与分区表逐项一致 |
| 根文件系统挂载 | 启动末尾 | 不再出现Waiting for root device |
最后说固化。跑通一次之后,把工具目录、分区表、镜像、参数文件、还有一份写着“这块板子对应哪个芯片型号、哪个分区表、哪个 blkdevparts”的说明文档,一起打成一个包。产线只允许从这个包里取工具,不允许从桌面快捷方式启动。
从那以后我每次改完分区表,都会先把生成的 XML 和blkdevparts那一行并排打印在屏幕上,肉眼过一遍再点烧写——这个动作花十秒,能省掉一晚上。希望帮到你。
本文还有配套的精品资源,点击获取