eMMC 编程器如何把 Boot0 与 Boot1 读写边界做清楚
eMMC 编程器如何把 Boot0 与 Boot1 读写边界做清楚
给平板或开发板移植系统时,最麻烦的往往不是用户区,而是 Boot0 和 Boot1。它们决定启动配置、厂商参数和恢复流程,误把用户区设备节点当成启动分区,轻则读不到目标,重则把现场证据覆盖掉。本文围绕 eMMC-Studio 的 EMMC-Test-Rig_R2 版本,重新核对同一版本的原理图、PCB 顶底面和软件部署说明,整理出一套先识别、再读取、最后才考虑写入的工程边界。
这篇文章是独立技术分析。原项目页面只作为硬件和功能事实来源;没有复制 GitHub 仓库代码,也没有把图片或第三方实现冒称为自研。本文完成了源码结构阅读、同版本 EDA 高清导出和一个只读的设备识别脚本测试,没有接入实物,也没有宣称已经完成真实 eMMC 写入。
先确定项目真正解决了什么
项目页面给出的硬件路径很明确:NanoPi R28S 的 eMMC 以模块形式安装在背面,RK3528 提供原生 eMMC 控制器,转接板把模块引到测试座上。这样做的价值是把难以夹取的模块变成可插拔的测试对象,并让 Linux 内核有机会直接暴露用户区、Boot0 和 Boot1。页面也特别说明,Radxa 的另一种 eMMC 读卡器不是原生控制器,不能读取 Boot0 和 Boot1;“有测试座”并不等于“所有启动分区都能访问”。

图 1 项目页的功能图展示了用户区、Boot0/Boot1、分区管理和十六进制读写等入口。图片来源于项目页,按 CC BY-NC-SA 4.0 归属使用。
项目更新时间为 2026 年 10 月 29 日。本文核对的工程树同时显示 EMMC-Test-Rig_R2、Schematic1_1 和 PCB1_1,原理图标题栏的更新日期为 2026 年 10 月 9 日。软件仓库 eMMC-Studio 使用 React、TypeScript、Vite 前端和 Flask、Waitress 后端,由独立 root 工作进程执行磁盘操作;README 要求 Debian 12/13、Ubuntu 或兼容 Armbian,并提醒先用 lsblk 区分 eMMC、系统盘和 USB 设备。

图 2 成品正面照片只用于说明测试座和转接关系,不能代替本次没有进行的实物通电测试。
原理图先看电源和信号边界
同版本高清原理图里,P1 页面把 eMMC 接口分成三块:用户区数据线 eMMC_D0 到 eMMC_D7、命令和时钟 eMMC_CMD/eMMC_CLK,以及 RSTN、eMMC_DTE 和若干电源网络。U3 的 KLM9G1GETF-B041 符号给出了 DAT0 到 DAT7、CMD、CLK、DataStrobe、RSTN、VDD、VDDI 和 VDDF 等连接。图中没有把 Boot0、Boot1 画成两根独立的“启动线”,它们属于 eMMC 内部地址空间,最终是否出现为 Linux 设备节点要由控制器、内核和器件配置共同决定。

图 3 从嘉立创 EDA 的 Schematic1_1 以 4 倍分辨率导出,标题栏仍标为 EMMC-Test-Rig_R2、P1。图中可核对数据线、CMD/CLK、复位和 VDD/VDDI/VDDF 电源网络。
电源核对时有三个容易被忽略的点:
VDD、VDDI、VDDF是不同的电源语义,不能因为都画成电源符号就当成同一电压;实际电压和上电时序要以 eMMC 型号数据手册与板上电源实现为准。- C1~C6 的去耦值分散在 UFS 接口和 eMMC 电源区域,读图时应先按网络名分组,再沿着 PCB 找回流路径。
- 测试座接触不良会表现为枚举失败、容量读取异常或 Boot 分区消失。此时先检查座子、地回路和供电,不能直接把“没有
/dev/mmcblkXboot0”解释成软件不支持。
用设备节点把 Boot0 和 Boot1 分开
软件层最重要的规则是 永远不要默认 mmcblk0 就是目标 eMMC。系统盘、USB 读卡器和 eMMC 的枚举顺序都可能改变。先读 lsblk 元数据,再看 /sys/block/mmcblkX 下是否存在 mmcblkXboot0 与 mmcblkXboot1,最后检查只读标志、挂载点和容量。
下面的脚本是本文独立编写的只读预检工具。它只调用 lsblk -J 并检查 sysfs 名称,不打开块设备,更不会执行写入。完整文件也放在本文源码目录的 source/emmc_audit.py 中。
#!/usr/bin/env python3
import json
import subprocess
from pathlib import Path
from typing import Iterable
def load_block_devices() -> list[dict]:
result = subprocess.run(
["lsblk", "-J", "-o", "NAME,TYPE,MODEL,RO,SIZE,MOUNTPOINTS"],
check=True,
capture_output=True,
text=True,
)
return json.loads(result.stdout).get("blockdevices", [])
def flatten(nodes: Iterable[dict]) -> Iterable[dict]:
for node in nodes:
yield node
yield from flatten(node.get("children", []))
def e_mmc_nodes(nodes: Iterable[dict]) -> list[dict]:
return [
node for node in flatten(nodes)
if node.get("type") == "disk"
and str(node.get("name", "")).startswith("mmcblk")
]
def boot_nodes(name: str, sys_block: Path = Path("/sys/block")) -> dict[str, bool]:
base = sys_block / name
return {
"boot0": (base / f"{name}boot0").exists(),
"boot1": (base / f"{name}boot1").exists(),
}
def audit(nodes: Iterable[dict], sys_block: Path = Path("/sys/block")) -> list[dict]:
report = []
for node in e_mmc_nodes(nodes):
name = str(node["name"])
report.append({
"name": name,
"model": node.get("model"),
"size": node.get("size"),
"read_only": str(node.get("ro", "0")) == "1",
"boot_nodes": boot_nodes(name, sys_block),
})
return report
if __name__ == "__main__":
print(json.dumps(audit(load_block_devices()), ensure_ascii=False, indent=2))
脚本的关键输出不是“找到一个盘”,而是把三件事同时留下证据:目标名称、只读状态、Boot0/Boot1 节点是否存在。本文用一个包含 mmcblk2boot0 的合成 sysfs 目录运行了回归测试,确认它不会把 sda 或 mmcblk2p1 当成目标磁盘;在 Windows 环境没有伪造 Linux 设备运行结果。

图 4 项目页的设备信息界面可用于核对容量、协议和寿命字段,但截图本身不能替代目标设备的 lsblk 与 sysfs 证据。
实际读取时建议按下面的顺序操作:
lsblk -o NAME,TYPE,MODEL,RO,SIZE,MOUNTPOINTS
sudo blockdev --getro /dev/mmcblkX
ls -l /sys/block/mmcblkX/mmcblkXboot0 /sys/block/mmcblkX/mmcblkXboot1
其中 X 必须替换成预检脚本确认过的设备号。需要保存现场时,只做从设备到文件的读取,例如对确认过的 Boot0 生成校验副本,再把文件大小和 SHA-256 写入记录。不要把 if= 和 of= 的方向写反,也不要在仍有挂载点时尝试写入。
PCB 顶底面要一起看
PCB1_1 以 3000 像素宽重新导出顶面和底面,两个文件分别为 PCB_PCB1_1_top_3000px.png 与 PCB_PCB1_1_bottom_3000px.png。顶层图可以看到中央测试座、周围的去耦与数据扇出,底层图则能检查座子下方和边缘的回流、过孔和固定孔。导出时保留了 EDA 的图层语义,因此复杂区域仍需放大查看,不能把渲染颜色直接当成电压或阻抗结论。

图 5 PCB1_1 顶面高清导出,中心为测试座和主要器件区域。

图 6 同一版本的底面高清导出,用于检查底层走线、回流和固定孔附近的连续性。
从图上能验证的是器件位置、座子区域和走线层次;走线阻抗、接触电阻、眼图和温升仍需要板厂数据或实测。没有这些数据时,文章只讨论“如何审计”,不把截图写成“已经通过高速信号测试”。
软件能力和硬件能力要分层
eMMC-Studio README 给出的部署方式是下载 GitHub Actions 构建包,目标系统运行 Web、磁盘工作进程和升级服务。首次登录后还要在磁盘详情里核对型号、容量、CID、系统保护和 BOOT 状态。这个分层很重要:网页可以提供分区管理、备份和克隆入口,但是否能安全读写 Boot0/Boot1,仍取决于内核是否识别设备、控制器是否支持、目标是否被挂载以及管理员是否明确选择了正确的节点。
因此,建议把发布前的验收记录拆成四行:
- 硬件事实:
EMMC-Test-Rig_R2、Schematic1_1、PCB1_1和 CC BY-NC-SA 4.0 已在 EDA 与项目页核对。 - 软件事实:README 的 Linux 依赖、构建命令和服务划分已核对;仓库没有单独软件许可证,本文不复制仓库代码。
- 只读验证:设备识别脚本通过合成 sysfs 测试,命令顺序和风险边界可复现。
- 未完成项:没有实体通电、真实 eMMC 读写、ERC/DRC、眼图、温升或寿命测试,不能把这些结果写成已通过。

图 7 分区管理界面说明软件入口的范围。真正执行写入前,仍需回到设备节点、挂载状态和备份校验。
结语
这个项目的工程价值不在于“又做了一个 eMMC 转接板”,而在于把模块化 eMMC、原生控制器、测试座和网页工作台串成了一条可检查的路径。对使用者来说,最值得迁移的方法有三点:先用硬件版本和 EDA 版本锁定对象,再用设备节点证明 Boot0/Boot1 是否存在,最后把读写动作和现场备份分开。这样即使更换 NanoPi、Radxa 或不同容量的 eMMC,也不会因为枚举顺序或页面按钮而误操作。
项目来源:https://oshwhub.com/jasonyang17/radxa-test-rig
硬件许可:CC BY-NC-SA 4.0,复用项目图像需保留来源、署名并遵守相同方式共享。
软件资料:https://github.com/JasonYANG170/eMMC-Studio 。仓库未提供独立软件许可证,本文仅引用公开部署事实,不复制仓库代码。
本文图片处理范围:项目页原图按许可保留,EDA 原理图和 PCB 顶底面从 EMMC-Test-Rig_R2 的 Schematic1_1、PCB1_1 重新导出;未进行实体读写测试。
技术交流,欢迎关注微信公众号:美男子玩编程。



