
i.MX6ULL 嵌入式 Linux 入门学习文档第一周学习总结一 学习路线和当前进度tip:这是我的学习路径规划基本靠ai学习这条路线不是让你把三本厚书从头背到尾而是先完成四个看得见的任务。每个任务都会产出一个能运行的结果。阶段要完成的事为什么先做它当前状态第一阶段Ubuntu 和开发板联网 搭好 NFS 交叉编译并运行 Hello World先把电脑和板子之间的开发通道修好 后面写的程序才能送过去核心已完成————第二阶段用 C 操作文件 再练 fork 和 pthread学会让 Linux 程序保存数据并同时做多件事下一步流程了解系统移植和文件系统构建跟着教程走一遍知道开发板系统从哪里来 但暂时不钻底层未开始第三阶段用 C 控制 LED 和蜂鸣器让程序开始接触真实硬件未开始第四阶段做 Qt 窗口并部署到开发板让板子运行一个看得见的完整应用未开始六周安排周次本周任务本周交付结果第一周串口 网络 双网卡 NFS 交叉编译 Hello World开发板成功输出 Hello i.MX6ULL 和可复现日志———第二周Linux C 文件的打开 读取 写入 关闭一个能保存和读取文本的 C 程序第三周fork 多进程和 pthread 多线程两个小程序分别展示进程和线程第四周系统移植流程浏览 LED 和蜂鸣器入门知道系统组成并至少控制一个外设第五周Qt 基础和简单窗口Ubuntu 中能运行自己的 Qt 窗口第六周Qt 交叉编译 部署 开机运行 整理总结开发板运行自己的界面程序和总日志为什么按这个顺序1. 先修路。网络和 NFS 不通程序写好了也送不到开发板。2. 再学做事。文件 进程和线程是 Linux 应用最常见的基本能力。3. 然后碰硬件。应用通过驱动提供的接口去控制 LED 和蜂鸣器。4. 最后做界面。Qt 依赖前面的编译 部署和硬件环境放最后最稳。送外卖故事总览把整个开发过程想成送外卖。Ubuntu 是后厨你在里面写菜谱也就是 C 代码。交叉编译器是专门给 ARM 顾客打包的机器。蓝色网线是马路IP 地址是门牌号NFS 是双方都能打开的取餐柜开发板是最后真正执行任务的店员串口是你和店员直接说话的对讲机。记忆图Ubuntu 后厨 - ARM 交叉编译器 - NFS 共享取餐柜 - 蓝色网线 - i.MX6ULL 开发板二 Linux 基础知识命令行和 Shell命令行就是一个可以打字控制电脑的窗口。你输入 ls电脑就列出文件。它像餐厅的点单窗口。Shell 是听懂这些命令并让 Linux 去执行的程序。它像服务员你说一句命令Shell 把要求交给系统。Ubuntu 常见的 Shell 是 Bash。终端是窗口Shell 是窗口里听命令的人命令是你说的话。最常用的文件命令命令人话解释例子pwd我现在在哪个文件夹pwd———ls看看这里有什么lsls -a连隐藏文件也显示ls -acd 路径走进指定文件夹cd ~/nfs_sharecd …返回上一层cd …mkdir新建文件夹mkdir orderstouch新建空文件touch order.txtcat把文件内容显示出来cat order.txtecho显示文字 也能把文字写入文件echo hello test.txtcp复制文件cp order.txt copy.txtmv移动文件或改名mv copy.txt done.txtrm删除文件rm done.txtrmdir删除空文件夹rmdir empty_dirfile看看文件是什么类型file hellorm 删除后通常没有回收站。刚开始不要随便加 -r 或 -f更不要对不确定的路径执行删除。查找和系统查看命令命令人话解释例子find按名字找文件find . -name “order.txt”———grep在文件内容里找文字grep “牛肉面” order.txtman查看命令说明书man lsclear清空终端画面clearuname -a查看系统和内核信息uname -aps查看当前进程pstop实时查看系统运行状态topdf -h查看磁盘还剩多少空间df -hdu -sh查看一个文件夹多大du -sh ~/nfs_shareip addr查看现代 Linux 网卡和 IPip addrifconfig查看或设置旧系统网卡ifconfig eth1ping测试另一台电脑能否联系ping -c 4 192.168.10.20find . -name “order.txt” 里find 是查找点号表示从当前文件夹开始-name 表示按名字找order.txt 是目标名字。四部分缺一不可。正确命令是 gedit不是 gredit。gedit 是图形文本编辑器没有桌面环境时就用 vim。需要知道但不常用的命令命令作用注意sudo 命令临时用管理员权限执行一条命令只给确实需要权限的命令使用———su切换用户初学阶段很少需要sync把还在内存里的数据写入磁盘拔 U 盘或关机前可用reboot重启系统会中断当前工作poweroff关闭系统拼写不是 powerofLinux 目录和路径Linux 的所有文件都从根目录 / 往下长像一棵倒过来的树。路径就是从一个位置走到另一个位置的路线。目录把它想成主要放什么/整栋大楼所有目录的起点———/home普通用户的宿舍个人文件和项目/root管理员宿舍root 用户文件/etc总设置室系统和服务配置/bin 和 /sbin工具房系统命令/usr软件仓库大部分程序和资源/lib公共零件库程序需要的库/dev设备窗口串口 磁盘等设备文件/mnt 和 /media外接物品入口挂载 NFS U 盘 SD 卡/proc 和 /sys系统仪表盘运行状态 内核和设备信息/tmp临时桌面临时文件/var不断变化的记录柜日志 缓存等绝对路径从 / 开始例如 /home/zyy/nfs_share。相对路径从当前位置开始例如当前在 /home/zyy 时nfs_share 就是相对路径。软链接和硬链接inode 可以先理解为文件在 Linux 里的身份证号。系统先找到这个身份证再找到真正的数据。类型生活类比特点命令软链接Windows 快捷方式能链接目录 能跨磁盘 源文件删掉后链接失效ln -s 源文件 链接名————硬链接同一个房间的第二扇门多个名字指向同一份数据 不能跨文件系统 通常不链接目录ln 源文件 新名字嵌入式入门阶段先会用软链接即可。创建软链接时尽量写绝对路径最不容易出错。文件权限Linux 会问三件事谁可以看谁可以改谁可以运行。r 是读w 是写x 是执行。权限分给三类人拥有者 所在组 其他人。怎么读权限-rw-rw-r–│ │ │ └─ 其他人 只读│ │ └──── 同组用户 可读可写│ └─────── 拥有者 可读可写└───────── 普通文件权限数字人话r4可以读———w2可以写x1可以运行常见写法chmod x hello # 给 hello 增加执行权限chmod 755 hello # 拥有者可读写执行 其他人可读执行chown zyy file.txt # 把文件拥有者改成 zyy我们在开发板运行 hello 前执行 chmod x /mnt/nfs/hello就是给程序一张可以上岗的工作证。Vim 最小用法Vim 有三种状态。刚打开时是普通模式按 i 或 A 进入编辑模式按 Esc 回到普通模式再输入冒号命令保存退出。操作作用vim hello.c打开或创建文件——i在光标前开始输入A移动到当前行末尾并开始输入 你记得的 A 完全正确Esc退出编辑 回到普通模式:w保存:q退出:wq保存并退出:q!不保存 强制退出yy 和 p复制当前行 再粘贴dd删除当前行u撤销上一步/文字在文件里搜索文字看到自己不能输入时先按 i 或 A。退出前先按 Esc再输入 :wq。GCC Make 和 MakefileC 源代码是人能读的菜谱CPU 不能直接执行。gcc 是编译器负责把菜谱做成可执行程序。文件少时直接用 gcc文件多时让 make 按 Makefile 的规则自动编译。make 是执行者Makefile 是施工单。没有 Makefilemake 不知道先编什么、怎么编。Makefile 基本格式目标: 依赖文件要执行的命令最小 Makefile 例子app: main.c add.cgcc main.c add.c -o appclean:rm -f app使用方法make # 按规则生成 app./app # 运行 appmake clean # 执行 clean 规则 删除 appMakefile 中命令前必须是键盘 Tab不能用普通空格。文件名通常写 Makefile大小写要一致。Shell 脚本Shell 脚本就是把原来要一条一条输入的终端命令写进一个 .sh 文件让系统从上到下自动执行。像把多张外卖单订成一张流程单。一个能看懂的脚本#!/bin/bashecho “开始处理订单”read foodcount2price15total$((count * price))if [ “$food” “牛肉面” ]; thenecho “找到餐品 总价 $total 元”elseecho “没有这个餐品”fifor number in 1 2 3; doecho “第 $number 次检查订单”done保存后运行chmod x order.sh./order.sh写法作用对照 C 语言#!/bin/bash说明用 Bash 解释这个文件告诉系统使用哪种语言———namevalue保存一个值 等号两边不能有空格变量赋值$name取出变量的值读取变量read name等待用户输入scanf$((ab))整数计算a b[ 条件 ]判断条件 中括号两边必须留空格if 条件前一条成功才执行下一条逻辑与||前一条失败才执行下一条逻辑或if then else fi条件判断if elsecase esac多个固定选项中选择switch casewhile do done条件成立就循环whileuntil do done条件不成立时循环和 while 方向相反for do done按次数或列表循环forfunction name()把一段功能包装起来函数$0 $1 $# $脚本名 第一个参数 参数数量 所有参数main 的命令行参数作为嵌入式初学者先会写 shebang 变量 read 整数计算 if 和 for 就够用其他语法见到时再查。三 第一阶段实战过程先认识四个角色东西它是什么本次负责什么Windows 笔记本真实电脑和总平台运行 VMware 和串口助手———Ubuntu 虚拟机电脑里的另一台 Linux 电脑写代码 安装工具 交叉编译 提供 NFSi.MX6ULL 开发板一台小型 ARM Linux 电脑运行最终程序 控制未来的硬件串口调试助手直接和开发板终端说话的工具输入开发板命令 查看启动和报错i.MX6ULL 开发板可以理解为单板计算机。它有处理器 内存 接口和 Linux 系统只是它更适合连接和控制硬件。串口连接串口像一部对讲机。即使网络还没配置好你仍然可以通过串口看到开发板启动信息并输入命令。设置项本次实际值接口开发板 USB_TTL——串口COM9 USB SERIAL CH34C波特率115200数据位8停止位1校验位None按钮显示 打开串口说明现在还没打开点击后按钮变成 关闭串口才是真的连上。看到 rootATK-IMX6U:~#说明已经进入开发板 Linux。串口里偶尔出现方框或奇怪字符多数是颜色控制码不影响命令执行。网络基础概念生活类比这次实际含义IP 地址门牌号Ubuntu 是 192.168.10.10 开发板是 192.168.10.20———同一网段住在同一个小区两者前三段都是 192.168.10ping敲门并等对方回应测试两台机器能不能互相找到桥接虚拟机直接接上真实网卡ens33 经 VMnet0 接 USB 网卡和开发板NAT借 Windows 的网络上网ens37 负责访问软件源和网页网卡一扇网络大门不同网卡可以走不同道路我们给 Ubuntu 配两块虚拟网卡是因为一条路专门去开发板另一条路专门上网。两条路互不抢工作。本次网络结构Ubuntu ens33 192.168.10.10|VMnet0 桥接到 NX USB2.0 Fast Ethernet Adapter|蓝色网线|i.MX6ULL eth1 192.168.10.20Ubuntu ens37 NAT - 互联网判断网线和网卡在开发板串口输入ls /sys/class/netcat /sys/class/net/eth0/carriercat /sys/class/net/eth1/carrier结果中 eth0 的 carrier 是 0eth1 的 carrier 是 1所以蓝色网线实际接在 eth1。carrier 为 1 就是检测到物理连接。启动早期出现 eth1 link is not ready 不一定是故障。后来又出现 Link is Up 100Mbps Full 和 link becomes ready说明协商成功。设置两边的临时 IP在 Ubuntu 终端输入sudo ip addr add 192.168.10.10/24 dev ens33ip addr show ens33在开发板串口输入ifconfig eth1 192.168.10.20 netmask 255.255.255.0 upifconfig eth1这两个地址是临时设置Ubuntu 或开发板重启后可能消失。现在这样做是为了先把流程跑通之后再学习永久配置。测试双向通信在 Ubuntu 终端输入ping -c 4 192.168.10.20在开发板串口输入ping -c 4 192.168.10.10两边都得到 4 packets transmitted 4 received 0 percent packet loss说明网络双向畅通。-c 4 的意思是只发 4 次避免一直 ping。在 Ubuntu 检查互联网wget --spider --timeout10 https://www.baidu.com看到 200 OK说明 ens37 的 NAT 上网正常。以前 ping 外网失败不一定代表没网有些网络会阻止 ping所以用网页请求再次验证。NFS 共享文件夹NFS 就像 Ubuntu 和开发板共用一个取餐柜。Ubuntu 把程序放进柜子开发板在 /mnt/nfs 打开柜门就能看到。它不是每次手动复制而是两边看见同一份目录内容。TFTP 更像一次送一个包裹NFS 更像一直连着的共享柜。本次选择 NFS所以 TFTP 只安装没有继续配置。第一步 在 Ubuntu 安装工具sudo apt updatesudo apt install -y nfs-kernel-server tftpd-hpa第二步 在 Ubuntu 建共享目录mkdir -p ~/nfs_shareecho “hello from Ubuntu” ~/nfs_share/test.txtcat ~/nfs_share/test.txt第三步 在 Ubuntu 写共享规则sudo mkdir -p /etc/exports.decho “/home/zyy/nfs_share 192.168.10.0/24(rw,sync,no_subtree_check,no_root_squash)” | sudo tee /etc/exports.d/imx6ull.exports配置内容意思/home/zyy/nfs_share要共享的 Ubuntu 文件夹——192.168.10.0/24允许同一网段里的设备访问rw允许读取和写入sync写入时立即同步到磁盘no_subtree_check不做子目录检查 减少兼容问题no_root_squash允许开发板 root 保留写权限 只适合当前隔离实验网第四步 在 Ubuntu 让规则生效并检查sudo exportfs -ravsudo systemctl restart nfs-kernel-servershowmount -e 192.168.10.10第五步 在开发板挂载 NFSmkdir -p /mnt/nfsmount -t nfs -o nolock,vers3 192.168.10.10:/home/zyy/nfs_share /mnt/nfsls /mnt/nfscat /mnt/nfs/test.txtmount 就是把远处的共享柜接到本机的一扇门上。vers3 是为了兼容开发板较老的系统nolock 用来避免文件锁服务不兼容。第六步 在开发板写一个文件echo “hello from board” /mnt/nfs/board.txt回到 Ubuntu 检查cat ~/nfs_share/board.txtUbuntu 成功看到 hello from board说明 NFS 不仅能读还能双向写。交叉编译笔记本通常是 x86 处理器i.MX6ULL 是 ARM 处理器。普通 gcc 做出的程序是给笔记本吃的开发板看不懂。arm-linux-gnueabihf-gcc 是翻译器专门在 Ubuntu 上生成 ARM 能运行的程序。交叉编译就是在 A 机器上制作给 B 机器运行的程序。在 Ubuntu 安装并检查交叉编译器sudo apt install -y gcc-arm-linux-gnueabihfarm-linux-gnueabihf-gcc --version编写和运行 Hello WorldUbuntu 中的 hello.c#include stdio.hint main(void){printf(“Hello i.MX6ULL!\n”);return 0;}在 Ubuntu 编译并检查cd ~/nfs_sharearm-linux-gnueabihf-gcc -static hello.c -o hellofile hello-static 表示把程序需要的大部分库一起装进程序像把餐具调料都装进外卖盒能减少开发板系统库版本不一致的问题。file hello 的实际结果包含 ELF 32-bit ARM 和 statically linked。这证明生成的是 ARM 32 位静态程序不是 Ubuntu 自己的 x86 程序。在开发板运行chmod x /mnt/nfs/hello/mnt/nfs/hello实际输出Hello i.MX6ULL!这一行输出证明整条链路已经跑通写代码 交叉编译 NFS 共享 开发板执行。第一阶段的核心目标已经完成。应用 驱动和硬件的关系应用和驱动不是同一个东西。应用负责你想做什么驱动负责怎么和硬件说话硬件负责真正发光 发声或采集数据。从上到下的关系Qt 或 C 应用 - Linux 提供的文件或设备接口 - 驱动 - LED 蜂鸣器等硬件用送外卖类比应用是顾客下单页面驱动是调度员硬件是骑手和车辆。下单页面不能自己骑车必须通过调度系统。四 我们遇到的错误和解决办法看到的现象真正原因解决办法ens33 显示 NO CARRIERVMware 虚拟网卡没有连接 或桥接的物理网卡不对勾选已连接和启动时连接 VMnet0 桥接到 NX USB2.0 网卡———Destination Host UnreachableUbuntu 有 IP 但找不到开发板的物理链路检查网线 板子 eth1 carrier VMware 桥接对象网络不可达ens33 上没有 192.168.10.10 地址重新执行 sudo ip addr add 命令启动时 link is not ready网口还在协商等待后续 Link is Up 和 link becomes readydhclient command not found系统没有安装 dhclient本实验直接使用静态临时 IP 不需要它curl command not found系统没有安装 curl使用已存在的 wget 检查网页外网 ping 不通网络可能屏蔽 ICMP用 wget spider 看是否得到 200 OK/etc/exports.d 不存在系统未自动建立目录sudo mkdir -p /etc/exports.d找不到交叉编译器gcc-arm-linux-gnueabihf 未安装sudo apt install -y gcc-arm-linux-gnueabihf串口不能输入串口还是关闭状态点击打开串口 按钮变成关闭串口后再输入重启后 IP 消失使用的是临时 IP按恢复清单重新设置错误信息怎么读1. 先看命令是在哪台机器执行的。提示符 zyy… 是 UbunturootATK-IMX6U 是开发板。2. 先读最后一两行。大多数关键原因就在最后例如 command not found 或 No such file or directory。3. 一次只改一个地方再重新测试。否则最后不知道是哪一步起作用。4. 保存成功命令和实际输出形成日志。下次照着恢复不用重猜。重启后的最短恢复清单Ubuntu 终端sudo ip addr add 192.168.10.10/24 dev ens33sudo systemctl restart nfs-kernel-serverping -c 4 192.168.10.20开发板串口ifconfig eth1 192.168.10.20 netmask 255.255.255.0 upmkdir -p /mnt/nfsmount -t nfs -o nolock,vers3 192.168.10.10:/home/zyy/nfs_share /mnt/nfsping -c 4 192.168.10.10ls /mnt/nfs如果 add IP 提示 File exists说明地址可能已经存在先用 ip addr show ens33 检查不要重复添加。五 接下来四个学习任务任务一 已完成的开发通道目标是 Ubuntu 写程序开发板运行程序。现在网络 NFS 交叉编译和 Hello World 已经全部跑通。下一步只需要把临时配置逐渐整理成稳定流程。任务二 Linux C 应用只练两类程序不从书头看到尾。文件操作fopen 打开fread 或 fgets 读取fwrite 或 fprintf 写入fclose 关闭。类比打开笔记本 写字 看字 合上。多进程fork 像把一个店复制成两家店各自继续工作。多线程pthread 像一家店里的多个员工共用同一间厨房同时做不同工作。学习成果应该是三个很小的程序文件读写程序 fork 程序 pthread 程序。系统移植和文件系统构建这一部分像给一套新房安装地基 电路和家具。你只需要跟教程把启动加载器 Linux 内核 设备树 根文件系统的整体流程走一遍知道它们各自负责什么不要求现在会从零修改内核。任务三 控制开发板硬件目标是让 C 程序控制板载 LED 和蜂鸣器。Linux 下通常不直接改寄存器而是打开系统提供的文件或设备接口再读写它。应用通过接口找到驱动驱动再控制硬件。任务四 Qt 图形界面Qt 是用 C 做窗口 按钮 文本和界面的工具。先在 Ubuntu 上做一个最小窗口再交叉编译放到开发板最后让开发板启动后运行自己的界面程序。完成这一步就具备继续做一个完整嵌入式产品界面的基础。暂时不学什么ARM 裸机篇暂时不学。现阶段先把 Linux 路线走通。驱动开发指南不用从第一页啃到最后一页只在做 LED 蜂鸣器和系统流程时查对应章节。Qt 不要一开始追求漂亮界面先让一个窗口成功上板。遇到暂时用不到的细节先知道名字和作用等项目需要时再深挖。六 用送外卖故事复习整条流程现在把所有技术词暂时放下只看一个送外卖故事。读完这个故事再看后面的技术对照你就能知道每一步为什么存在。1. 你在 Ubuntu 后厨写了一张菜谱 hello.c。它现在只是文字还不能直接让开发板干活。2. 普通打包机 gcc 只会打包给 x86 笔记本吃。你换成 ARM 专用打包机 arm-linux-gnueabihf-gcc把菜谱做成开发板能吃的 hello。3. 为了避免开发板缺少餐具和调料你加上 -static把常用库一起装进外卖盒。4. Ubuntu 和开发板先要有一条路。蓝色网线是马路192.168.10.10 和 192.168.10.20 是两边的门牌号ping 是敲门确认。5. NFS 是共享取餐柜。Ubuntu 把 hello 放进 ~/nfs_share开发板从 /mnt/nfs 看见同一个 hello不需要再次手动搬运。6. chmod x 像给 hello 发一张上岗证。最后开发板执行 /mnt/nfs/hello屏幕出现 Hello i.MX6ULL。7. 以后控制 LED 和蜂鸣器时应用负责下单驱动负责调度硬件负责真正发光或发声。技术词和生活类比对照技术词送外卖类比真正作用Ubuntu后厨写代码 安装工具 编译程序———开发板真正干活的店员运行程序并控制硬件串口对讲机直接输入开发板命令并看启动信息网线马路传递网络数据IP门牌号让两台机器找到对方ping敲门检查对方是否能回应交叉编译器ARM 专用打包机把 C 代码变成 ARM 程序NFS共享取餐柜两边访问同一个共享目录mount把取餐柜接到一扇门把远程目录接到开发板 /mnt/nfschmod x发上岗证允许程序执行应用顾客下单页面说明想让系统做什么驱动调度员把应用要求变成硬件动作自我检查□ 我能说出 Windows Ubuntu 虚拟机和开发板分别负责什么□ 我知道串口是对讲机 网络是传文件和通信的道路□ 我知道 IP 是门牌号 ping 是敲门测试□ 我能分清 Ubuntu 命令提示符和开发板命令提示符□ 我能解释桥接和 NAT 的区别□ 我能解释 NFS 为什么像共享文件夹□ 我能解释普通编译和交叉编译的区别□ 我知道 chmod x 是给程序执行权限□ 我能说明第一阶段已经成功输出 Hello i.MX6ULL□ 我知道下一步是文件操作 多进程和多线程最后只记住这条主线第一阶段主线写 C 代码 - 在 Ubuntu 交叉编译 - 放进 NFS 共享目录 - 开发板运行你现在不需要把每条命令背下来。能说清楚每一步为什么存在能照日志重新做一遍并且知道报错时先检查哪一层就已经达到第一阶段的学习目标。