很多同学一上来就想直接写驱动、跑 Qt 界面,结果往往卡在环境搭建、工具链安装和启动链路理解上。真正高效的做法不是先敲代码,而是先把开发主机、交叉编译环境、板卡启动文件的来龙去脉理顺。只要这一步做扎实,后面无论是字符设备驱动、设备树、PetaLinux,还是 Qt 交叉编译和部署,都会顺很多。
本节目标
-
搭好适合嵌入式开发的 Ubuntu 虚拟机环境。
-
完成常用开发工具和交叉编译工具链安装。
-
理解为什么 Linux 系统移植经常要从 Vivado/Vitis 的工程结果出发。
-
建立后续"驱动开发 + Qt 开发"的统一工作流。
一、为什么推荐先用虚拟机
对于 ZYNQ MPSoC 这类平台,Linux 开发并不只是写应用程序,还会涉及交叉编译、内核裁剪、设备树、启动镜像打包、串口调试、文件传输等工作。直接把 Ubuntu 装到物理机当然也能做,但虚拟机有几个明显优势:
-
不影响现有 Windows 开发环境,资料整理、串口工具、下载工具可以同时保留。
-
方便备份、克隆和回滚,环境一旦配好,后面几乎可以一直复用。
-
出问题时恢复成本低,不必频繁重装系统。
-
多套实验环境可以并行存在,适合同时做 Linux 驱动和 Qt 项目。
所以,对初学者来说,虚拟机不是"将就方案",反而是更稳的起步方式。
二、Ubuntu 安装时的几个关键点
这套课程建议统一使用 Ubuntu 18.04。原因很简单:很多板级开发包、交叉编译工具和旧版本依赖,都是围绕这个版本验证过的。如果你一开始就用太新的发行版,经常会遇到依赖冲突、脚本兼容性下降等问题。
安装虚拟机时,建议重点注意下面这些参数:
-
虚拟机镜像文件尽量放到容量更大的磁盘,SSD 优先。
-
虚拟磁盘空间尽量给大一些,后面编译内核、根文件系统、Qt 库都比较占空间。
-
用户名和密码在安装时就要规划好,后续很多操作都要用到 sudo。
-
系统安装完成后第一件事不是立刻装软件,而是先确认网络、分辨率、共享目录和剪贴板是否正常。
如果你只是想尽快开工,也可以直接使用已经配好的 Ubuntu 虚拟机镜像,这样能少踩很多工具链和依赖方面的坑。
三、系统安装后第一时间要做什么
刚装好的 Ubuntu,先别急着下载一堆工具,建议按这个顺序处理:
-
更换软件源,优先选国内稳定镜像。
-
更新软件索引。
-
安装基础构建环境。
-
安装交叉编译工具链。
-
安装调试和文本处理工具。
最常用的一组命令如下:
Code example:
sudo apt-get update
sudo apt-get install build-essential gcc-arm-linux-gnueabi gcc-aarch64-linux-gnu openssl libssl-dev vim
sudo apt-get install cvs automake autoconf libtool bison flex
sudo apt-get install libncurses5-dev
sudo apt-get install binutils-doc cpp-doc gcc-doc glibc-doc stl-manual manpages manpages-dev
这几组命令的意义可以简单理解为:
-
build-essential:提供最基础的编译环境。
-
gcc-arm-linux-gnueabi、gcc-aarch64-linux-gnu:分别对应常见 ARM 交叉编译场景。
-
openssl、libssl-dev:很多源码构建时都会依赖。
-
automake、autoconf、libtool、bison、flex:老项目和内核相关工具经常用到。
-
libncurses5-dev:菜单配置类界面常见依赖,比如内核配置。
如果安装过程中遇到包不存在、下载失败或依赖不匹配,第一反应不是怀疑命令错了,而是先检查软件源是否可用。
四、开发包部署,决定后面效率高不高
嵌入式 Linux 开发最怕的是"工具零散"。一会儿单独编译 U-Boot,一会儿又手工处理设备树和 rootfs,流程容易乱,也难复现。更合理的方式是把常用脚本、源码、启动镜像制作流程统一放进一个开发包目录里管理。
例如把开发包解压到固定目录:
Code example:
tar -xvf uisrc-lab-xlnx20220501.tar.gz
之后你至少要做到两点:
-
统一自己的工程目录结构,不要今天放桌面、明天放下载目录。
-
把"源码、脚本、输出镜像、板卡配置"拆开管理,避免后期找不到版本对应关系。
建议把工作目录规划成下面这样:
Code example:
~/workspace/
boot/
kernel/
rootfs/
tools/
projects/
qt/
只要目录结构清楚,后面不管是 Linux 驱动实验还是 Qt 应用实验,都会容易维护很多。
五、为什么 Linux 二次开发常常从 Vitis 结果开始
很多初学者对这一步最容易困惑:我明明是在做 Linux,为什么还要回到 Vivado、Vitis 这套流程?
答案在于启动链路。
对于 ZYNQ MPSoC,一套完整系统能否启动,不只是内核文件的问题,还涉及这些关键产物:
-
fsbl:第一阶段启动程序,系统上电后的早期初始化离不开它。
-
pmufw.elf:电源管理相关固件。
-
system_wrapper.bit:PL 端逻辑配置文件,同时会影响部分 PS 侧外设配置。
-
设备树相关文件:告诉 Linux 系统板上有哪些外设、地址和中断怎么映射。
也就是说,Linux 想正常起来,前面这几步要先打通。很多板卡移植工作,本质上是把硬件设计结果、启动固件、设备树和 Linux 系统一起串起来,而不是单独"编译一个内核"这么简单。
从这个角度看,Vitis 不是偏离主题,而是 Linux 二次开发的入口之一。
六、从硬件工程过渡到 Linux 系统的思路
如果你已经在 Vivado 中完成了硬件设计,后续一般会经历下面这条主线:
-
在 Vivado 中确认硬件平台配置正确。
-
通过 TCL 脚本快速还原或搭建工程。
-
生成顶层文件和约束文件,确保硬件设计完整。
-
导出硬件平台,进入 Vitis 生成启动相关文件。
-
将启动文件、bit 文件、设备树、内核和根文件系统重新组织,生成可启动镜像。
这里最值得记住的一点是:Linux 与 FPGA 的交互建立在"硬件描述已经确定"的前提上。如果硬件侧没有把 GPIO、中断、总线接口这些内容配置好,光改设备树或者驱动代码通常也救不回来。
七、做 Linux 驱动和 Qt 开发,应该形成什么工作流
很多人把 Linux 驱动开发和 Qt 开发分成两条线,其实它们在实际项目里是前后衔接的:
-
Linux 驱动负责把底层硬件抽象成用户态可访问的接口。
-
Qt 应用负责把这些接口包装成图形化的操作入口。
所以一个更合理的学习路径是:
-
先把 Ubuntu 和交叉编译环境稳定下来。
-
再理解启动链路、镜像打包和设备树。
-
然后进入字符设备、平台驱动、中断、阻塞与非阻塞 IO。
-
最后再用 Qt 去调用这些驱动接口,完成可视化控制和数据展示。
这也是为什么课程第一课不讲花哨界面,而是先把环境和开发链路讲透。
八、本节常用命令清单
Code example:
sudo apt-get update
sudo apt-get install build-essential gcc-arm-linux-gnueabi gcc-aarch64-linux-gnu openssl libssl-dev vim
sudo apt-get install cvs automake autoconf libtool bison flex
sudo apt-get install libncurses5-dev
sudo apt-get install binutils-doc cpp-doc gcc-doc glibc-doc stl-manual manpages manpages-dev
tar -xvf uisrc-lab-xlnx20220501.tar.gz
如果你现在只能先记一件事,那就是先把这些基础命令跑通,并确认交叉编译器真的安装成功。
九、常见问题
- Ubuntu 一定要装在虚拟机里吗
不一定,但对于入门阶段来说,虚拟机最省心,也最适合反复做实验。
- 为什么我能装 Qt Creator,却还是没法做板卡开发
因为桌面 Qt 和板端 Qt 不是一回事。板卡开发还依赖交叉编译链、目标根文件系统和部署流程。
- 为什么改了设备树还是控制不了外设
很可能硬件工程本身就没有把对应外设正确接出来,或者 bit 文件和设备树版本不匹配。
- 开发包一定要跟教程版本一致吗
尽量一致。尤其是入门阶段,版本不一致会带来大量无谓的环境问题。
十、课后练习
-
自己新建一台 Ubuntu 18.04 虚拟机,完整走一遍安装流程。
-
把软件源切换到稳定镜像,并执行 sudo apt-get update。
-
安装交叉编译工具链,确认命令行可以找到相关编译器。
-
画出你理解的 MPSoC 启动链路图,至少包含 fsbl、pmufw、bit、设备树、内核这几个节点。
下一课预告
下一课我们会继续往 Linux 基础能力靠拢,把命令行、编译流程、Makefile 和开发环境使用习惯串起来。等这部分稳定后,再进入真正的驱动开发阶段,效率会高很多。