本节路线图
|-----------------|---|------------------|---|------------------|
| 为什么先学"恢复出厂" | → | 恢复出厂与固化到eMMC | → | Linux目录结构要先看 |
|-------------------------------------------------------------------------------------|----------------------------------------|
|
| 小猫提醒 这节有分区、烧录或删除类操作,先确认盘符和路径,再按回车。 |
|--------------------------------------------------------------------------------------|-------------------------------------------|
|
| 猫头鹰提示 编译前先对齐目标架构和工具链名字,别让主机程序和板卡程序搞混。 |
第 1 课我们把开发环境和整体链路搭起来了,这一课要把"能进系统"和"能在系统上做事"两件事真正落地。对于 Linux 驱动和 Qt 开发来说,开发板一旦因为误操作导致系统损坏、目录混乱、权限错误或者编译链没装对,后面的实验会变得非常低效。所以本节不追求花哨,而是先把恢复能力、命令行能力和编译能力打牢。
本节路线图(参考原理图)
|---------------------------------------------------|---|----------------------------------|---|-----------------------------------------|---|-------------------------------------|
| 阶段 1:救援准备 下载并整理 sdcard_image 与 emmc_image | → | 阶段 2:SD 卡救援启动 分区、格式化、写入可启动镜像 | → | 阶段 3:eMMC 固化 从 SD 启动后执行烧写脚本并切回 eMMC | → | 阶段 4:编译验收 用 GCC/交叉 GCC 验证开发环境闭环 |
|-------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------|
|
| 小猫提醒: 这一课会碰到 make_parted.sh、deploy_image.sh、rm -rf 这类高风险动作。先核对盘符、挂载点和启动模式,再按回车。 |
|--------------------------------------------------------------------------------------|--------------------------------------------------------------------------|
|
| **猫头鹰提示:**驱动和 Qt 开发最怕"环境坏了却以为是代码错了"。所以本节的重点不是背命令,而是建立"能恢复、能排查、能编译"的完整闭环。 |
本节目标
- 学会在系统损坏或实验失败后恢复出厂,并重新固化到 eMMC。
- 建立对 Linux 目录结构、文件权限和常用文件管理命令的基本认知。
- 理解什么是交叉编译,为什么嵌入式开发离不开它。
- 能在 Linux 环境下完成一次基础的 GCC/交叉 GCC 编译验证。
一、为什么先学"恢复出厂"
很多同学会低估这一节的重要性,觉得"恢复系统"只是售后动作,和开发没关系。实际上恰恰相反,在驱动调试、设备树修改、根文件系统裁剪、Qt 库替换这些工作中,只要某一步出错,就可能让系统无法正常启动。这个时候如果没有一套可复原的流程,整个开发就会被卡住。
恢复出厂流程的核心思路很简单:
- 先把可启动的 SD 卡镜像烧好。
- 再把 eMMC 镜像拷贝到 SD 卡启动后的系统里。
- 从 SD 卡启动进入 Linux。
- 通过串口或 SSH 登录板卡,执行 eMMC 分区和烧写脚本。
- 最后切回 eMMC 启动,确认系统恢复成功。
这意味着 SD 卡不只是"临时启动盘",更像是一张救援卡。只要它准备好,哪怕后面把板卡系统改坏了,也能较快回到可工作的状态。
二、恢复出厂与固化到 eMMC 的实操逻辑
原始资料里的流程比较偏操作截图,这里把它整理成更容易复现的步骤。
0. 恢复出厂闭环参考图
|------------------------|---|------------------|---|--------------------------|---|-----------------------|
| Ubuntu 主机 准备恢复包与脚本 | → | SD 卡 制作救援启动盘 | → | 开发板 从 SD 启动并进入 Linux | → | eMMC 分区、部署、切回固化启动 |
|-------------------------------------------------------------------------------------|--------------------------------------------------------------|
|
| **兔兔建议:**第一次操作时,建议你把"当前盘符""SD 挂载点""拨码开关状态"写在纸上。看起来笨一点,但会非常稳。 |
1. 准备镜像文件
先下载对应板卡型号的恢复镜像压缩包,解压后通常会得到两个目录:
sdcard_imageemmc_image
可以把整个恢复目录先放到 Ubuntu 用户主目录,例如:
cp -r rst_to_factory /home/uisrc/
2. 制作 SD 启动卡
进入 sdcard_image 目录后,先切到 root 权限,再执行分区和镜像部署脚本:
su
./make_parted.sh
./deploy_image.sh
这里有两个常见细节:
- 脚本会要求你输入盘符,常见是
sdb,一定要先确认设备名,避免误格式化主机硬盘。 make_parted.sh负责分区和格式化,deploy_image.sh负责把启动镜像和根文件系统写进去。
3. 把 eMMC 镜像拷贝到 SD 卡系统里
烧好 SD 卡之后,还要把 eMMC 用到的镜像目录拷贝进去,便于开发板启动后直接本地烧写:
cp -r /home/uisrc/rst_to_factory/emmc_image/ /media/uisrc/rootfs/home/uisrc/
如果你的挂载点不是 /media/uisrc/rootfs/,就要根据实际挂载路径调整命令。这里特别能体现 Linux 基础命令的重要性,因为后面你会经常依赖 pwd、ls、cp 来确认路径是否正确。
4. 从 SD 卡启动并烧写 eMMC
把板卡切到 SD 启动模式,上电进入系统后,用串口或 SSH 登录,再执行 eMMC 烧写:
su
cd /home/uisrc/emmc_image
./make_parted.sh
./deploy_image.sh
完成后,切换拨码开关回 eMMC 启动模式,再次上电验证。如果系统能从 eMMC 正常启动,说明恢复流程闭环了。
5. 这一步为什么对后续驱动开发很关键
因为驱动实验里最怕的是"我不知道是代码问题,还是系统环境已经坏了"。有了恢复出厂手段后,你就可以把问题切开:
- 如果恢复后系统正常,说明硬件和基础镜像大概率没问题。
- 如果恢复后还不正常,就要优先查硬件、启动文件或镜像版本。
这会让排障效率高很多。
三、Linux 目录结构要先看懂什么
驱动开发和 Qt 开发虽然看起来一个偏底层、一个偏界面,但它们最终都跑在 Linux 文件系统之上。目录不清楚,后面找驱动节点、库文件、配置文件都会很痛苦。
先记住几个最常用的目录:
/boot:启动相关文件,经常和内核、启动镜像打交道。/dev:设备文件目录,驱动调试时最常去看。/etc:系统配置文件目录。/home:普通用户主目录,平时开发资料通常放这里。/lib:动态库目录,Qt 程序和很多系统程序都依赖它。/media:外部介质挂载点,U 盘、SD 卡、共享目录经常会出现在这里。/proc:进程和内核状态的虚拟文件系统。/sys:设备模型和驱动信息非常重要的虚拟文件系统。/usr:大量应用程序和共享资源所在目录。/var:日志、缓存和运行时数据常放在这里。
对驱动开发来说,最值得形成习惯的是这两个对应关系:
- 看设备节点时,多去
/dev - 看设备枚举、总线和属性时,多去
/sys
后面我们讲字符设备、平台驱动、设备树的时候,这两个目录会反复出现。
目录参考图:遇到问题时先去哪里看
| 目录 | 你通常先看什么 | 驱动 / Qt 开发里常见动作 |
|---|---|---|
/dev |
设备节点有没有出现 | 测试程序打开串口、LED、I2C、SPI 节点 |
/sys |
总线、属性、驱动绑定关系 | 排查设备树、平台驱动、class 信息 |
/lib / /usr/lib |
动态库是否齐全 | Qt 程序运行失败时检查依赖库 |
/boot |
内核、启动镜像、启动参数 | 恢复系统、替换内核、核对启动文件 |
四、权限模型必须先过关
Linux 和 Windows 很不一样的一点,是它天然面向多用户、多权限场景。很多"命令执行失败"其实不是命令错了,而是你没有权限。
一个典型权限串长这样:
-rwxr-xr--
可以把它拆成三组:
- 拥有者权限:
rwx - 用户组权限:
r-x - 其他用户权限:
r--
其中:
r表示可读w表示可写x表示可执行
1. 用数字表示权限
数字权限最常见:
r = 4w = 2x = 1
比如:
755 = rwx r-x r-x644 = rw- r-- r--777 = rwx rwx rwx
2. 三个最常用的权限命令
chgrp users test
chown root:root test
chmod 755 test
你可以把它们理解成:
chgrp:改属组chown:改属主和属组chmod:改读写执行权限
3. 驱动开发里为什么总会碰到权限问题
因为很多设备节点默认只有 root 可访问。如果你的测试程序或 Qt 程序打开 /dev/xxx 失败,除了怀疑驱动逻辑,也要先确认:
- 节点有没有创建成功
- 当前用户有没有访问权限
- 设备节点属主和属组是否合理
所以权限并不是"系统运维知识",而是驱动调试的基础能力。
五、这几个 Linux 命令一定要熟
原始资料里介绍了很多基础命令,这里不求一口气背完,但下面这些是每天都会用到的。
1. ls:看目录和文件
ls
ls -a
ls -l
ls -al
最常用的是 ls -al,它能同时看到隐藏文件和详细属性。很多时候你以为"目录里什么都没有",其实只是漏了隐藏文件。
2. cd 和 pwd:搞清楚你现在在哪
cd /root/test
cd ./test
cd ..
cd ~
pwd
pwd -P
这里最容易出错的不是命令本身,而是相对路径和绝对路径混用。建议初学阶段尽量多用绝对路径,先减少路径判断错误。
3. mkdir 和 rmdir:创建和删除目录
mkdir test
mkdir -p test1/test2/test3
rmdir test
rmdir -p test1/test2/test3
-p 很实用,它能递归创建或递归删除空目录。
4. cp、rm、mv:文件管理三件套
cp ~/test /tmp/test2
cp -r source_dir target_dir
rm -i test2
rm -rf old_dir
mv test mvtest
mv mvtest mvtest2
这里我建议你形成两个习惯:
- 删除前先
ls确认目标 - 初学阶段多用
-i交互确认,减少误删
因为在板卡根文件系统里,一次 rm -rf 用错目录,可能就直接把实验环境删坏了。
六、什么是 GCC 编译,为什么嵌入式里要讲"交叉编译"
对于桌面开发者来说,本地编译是很自然的事情:在自己的电脑上写代码、编译、运行,三个动作都在同一平台完成。
但嵌入式开发不是这样。
我们常见的开发模式是:
- 在 x86 的 Ubuntu 主机上写代码
- 编译出 ARM 或 AArch64 目标程序
- 再把程序放到开发板上运行
这就是交叉编译。
参考原理图:本地编译与交叉编译的分工
|-----------------------------------|---|-----------------------------------------------------------|---|-----------------------------------|
| x86 Ubuntu 主机 写代码、调用 GCC、管理工程 | → | 交叉工具链 arm-linux-gnueabi-gcc aarch64-linux-gnu-gcc | → | ARM / AArch64 开发板 运行目标程序并验证结果 |
|--------------------------------------------------------------------------------------|----------------------------------------------------------------------|
|
| 猫头鹰提示: "能编译"不等于"能在板卡上跑"。一定要再用 file、ldd、实际运行结果去确认目标架构和依赖是否正确。 |
1. 本地编译和交叉编译的区别
- 本地编译:编译平台和运行平台相同
- 交叉编译:编译平台和运行平台不同
比如:
- 在 Windows 上编出
.exe给 Windows 跑,是本地编译 - 在 Ubuntu 上编出 ARM Linux 程序给 MPSoC 板卡跑,是交叉编译
2. 为什么必须交叉编译
嵌入式板卡资源有限,这是最直接的原因。
- 板卡 CPU、内存、存储空间都比 PC 紧张
- 本地安装完整编译环境成本高
- 编译大型项目会很慢
- 真正量产时,不可能给每块板子都装一套开发工具链
所以最合理的做法,是在性能更强的主机上完成编译,再把结果部署到目标板。
七、交叉编译链到底是什么
很多同学会把编译器简单理解成一个 gcc 命令,但严格来说,真正工作的是一整套工具链。
一个 C 程序从源码到可执行文件,通常会经历:
- 预处理
- 编译
- 汇编
- 链接
对应会涉及头文件展开、宏替换、语法检查、汇编生成、目标文件生成和最终链接。也就是说,交叉编译不是"把一个命令改个名字"这么简单,而是一整套面向目标平台的工具集合。
八、怎么理解交叉编译器的命名
资料里提到两个已经安装过的交叉编译器:
gcc-arm-linux-gnueabigcc-aarch64-linux-gnu
你可以先粗略理解它们的差异:
arm-linux-gnueabi:偏 32 位 ARM 目标aarch64-linux-gnu:偏 64 位 ARM 目标
名称里通常会体现几件事:
- 目标架构
- 运行系统
- ABI 或工具链约定
现阶段不用死记所有命名规则,但要建立一个意识:编译器名字不一样,往往就意味着目标平台不一样。你后面编 Qt 程序、驱动测试程序时,一旦工具链选错,最终生成的程序就可能根本不能在板卡上运行。
九、第一次 GCC 编译该怎么做
本节不追求复杂项目,先验证"工具链通不通"。
1. 本机 GCC 验证
先确认 Ubuntu 主机本地 GCC 可用:
gcc --version
再写一个最简单的 hello.c:
#include <stdio.h>
int main(void) {
printf("hello linux\\n");
return 0;
}
编译并运行:
gcc hello.c -o hello
./hello
如果这一步成功,说明本机基础编译环境正常。
2. 交叉 GCC 验证
再确认交叉编译器是否存在:
arm-linux-gnueabi-gcc --version
aarch64-linux-gnu-gcc --version
然后用交叉编译器把同一个 hello.c 编成目标板程序:
arm-linux-gnueabi-gcc hello.c -o hello_arm
aarch64-linux-gnu-gcc hello.c -o hello_aarch64
这两个生成文件通常不能在当前 x86 Ubuntu 主机直接运行,但可以用 file 命令确认它们的目标架构:
file hello
file hello_arm
file hello_aarch64
这一步的意义非常大,因为它相当于把"写代码 -> 编译 -> 得到目标平台程序"的基本通路先打通了。后面不管是写驱动配套的测试程序,还是写 Qt 应用,都离不开这条链路。
十、把这三部分串起来看,才是完整开发思路
这一课看似内容很散,其实正好构成了嵌入式 Linux 开发最常见的三种底层能力:
- 系统坏了,能恢复
- 进系统后,能熟练管理文件和路径
- 写完代码后,能正确编译出目标平台程序
这三件事缺任何一个,后面的驱动和 Qt 实验都会反复卡住。
比如一个很真实的场景:
- 你修改了某个库或脚本,把系统搞乱了
- 用恢复流程把板卡救回来
- 用
cp、mv、chmod重新整理部署文件 - 用交叉 GCC 编译测试程序验证驱动节点是否可用
这才是工程里真正会发生的事情。
常见问题
1. 为什么我能进系统,但还是说不会 Linux 开发
因为"能登录"不等于"能定位问题"。真正开发时,你必须能看路径、改权限、复制文件、判断程序架构、恢复系统,这些都属于基本功。
2. chmod 777 是不是最省事
短期确实省事,但不推荐养成习惯。权限一旦全部放开,后面更难分辨到底是谁能访问、为什么能访问。调试时可以临时使用,正式项目里要更克制。
3. 为什么交叉编译好的程序在 Ubuntu 主机上运行不了
因为它不是为当前主机架构生成的。你在 x86 上编出来的 ARM 程序,应该放到 ARM 板卡上运行。
4. 为什么恢复出厂还要经过 SD 卡
因为很多时候 eMMC 上的系统已经不可依赖了,而 SD 卡更适合作为外部启动和修复介质。
课后练习
- 自己完整走一遍 SD 卡恢复和 eMMC 固化流程,把关键命令抄成操作清单。
- 用
ls -al、pwd、cd、mkdir -p、cp -r、mv、rm -i各做一次练习。 - 新建一个
hello.c,分别用本机 GCC 和交叉 GCC 编译,并用file命令观察产物差异。 - 试着解释
/dev、/sys、/etc、/home四个目录分别在后续驱动开发里会扮演什么角色。
下一课预告
下一课我们会继续往开发基本功推进,开始把 Makefile、编译组织方式和调试习惯串起来。等这部分稳定之后,再进入真正的驱动框架和 Qt 工程实践,整条学习曲线会顺得多。