本文整理了嵌入式Linux驱动学习前两日的完整内容,从最基础的虚拟机双网卡环境搭建,到TFTP/NFS服务配置、交叉编译工具链,再到U-Boot编译烧录、内核裁剪、BusyBox根文件系统构建,最后梳理驱动核心基础知识点。全程结合实操步骤与核心概念,既能跟着步骤复现环境,也能快速回顾核心理论,适合嵌入式入门学习者参考。
文章目录
- 前言
- 一、基础环境搭建:嵌入式开发的"基建"部分
- [1.1 双网卡网络配置:兼顾上网与开发板通信](#1.1 双网卡网络配置:兼顾上网与开发板通信)
- [1.2 apt-get软件源配置](#1.2 apt-get软件源配置)
- [1.3 minicom串口终端配置](#1.3 minicom串口终端配置)
- [1.4 TFTP服务器配置](#1.4 TFTP服务器配置)
- [1.5 NFS服务器配置](#1.5 NFS服务器配置)
- [1.6 交叉编译工具链配置](#1.6 交叉编译工具链配置)
- [二、开发启动方案:SD卡U-Boot + TFTP内核 + NFS根文件系统](#二、开发启动方案:SD卡U-Boot + TFTP内核 + NFS根文件系统)
- [2.1 整体流程](#2.1 整体流程)
- [2.2 U-Boot环境变量配置](#2.2 U-Boot环境变量配置)
- [三、U-Boot 深入理解与实操](#三、U-Boot 深入理解与实操)
- [3.1 U-Boot核心定位](#3.1 U-Boot核心定位)
- [3.2 核心功能](#3.2 核心功能)
- [3.3 U-Boot启动流程(两级架构)](#3.3 U-Boot启动流程(两级架构))
- [3.4 U-Boot编译实操](#3.4 U-Boot编译实操)
- [3.5 常用命令分类](#3.5 常用命令分类)
- [3.6 核心环境变量详解](#3.6 核心环境变量详解)
- 四、Linux内核编译与裁剪
- [4.1 内核概述](#4.1 内核概述)
- [4.2 编译步骤](#4.2 编译步骤)
- [4.3 编译产物与部署](#4.3 编译产物与部署)
- [五、BusyBox 构建根文件系统](#五、BusyBox 构建根文件系统)
- [5.1 根文件系统的作用](#5.1 根文件系统的作用)
- [5.2 BusyBox方案特点](#5.2 BusyBox方案特点)
- [5.3 构建步骤](#5.3 构建步骤)
- [5.4 功能验证](#5.4 功能验证)
- 六、Linux驱动基础核心知识点
- [6.1 驱动本质与三大分类](#6.1 驱动本质与三大分类)
- [6.2 内核模块:驱动的载体](#6.2 内核模块:驱动的载体)
- [6.3 字符设备驱动核心框架](#6.3 字符设备驱动核心框架)
- [6.4 bus-device-driver驱动模型](#6.4 bus-device-driver驱动模型)
- [6.5 设备树(Device Tree)](#6.5 设备树(Device Tree))
- [6.6 中断处理机制](#6.6 中断处理机制)
- [6.7 驱动核心设计思想](#6.7 驱动核心设计思想)
- 总结
一、基础环境搭建:嵌入式开发的"基建"部分
环境搭建是嵌入式开发的第一步,核心目标是让Ubuntu虚拟机同时具备「访问公网下载软件」和「与开发板通信提供服务」的能力,同时配齐开发所需的各类工具。
1.1 双网卡网络配置:兼顾上网与开发板通信
为什么需要双网卡
嵌入式开发中,Ubuntu需要一个网卡直连开发板,提供TFTP文件传输、NFS目录共享服务;同时还需要另一个网卡访问公网,用于下载软件、更新源码。单网卡无法同时满足两个场景,因此采用双网卡方案。
两种虚拟机网络模式对比
| 模式 | 原理 | 优势 | 局限性 | 适用场景 |
|---|---|---|---|---|
| 桥接模式 | Ubuntu作为独立主机存在,拥有真实局域网IP | 可作为服务器被其他设备访问,网络独立 | 拨号网络下可能无法获取公网IP | 与开发板通信、提供服务 |
| NAT模式 | Windows为主机虚拟网卡,Ubuntu共享Windows的网络 | 配置简单,Windows能上网Ubuntu就能上网 | 虚拟IP无法作为服务器被外部访问 | Ubuntu访问公网 |
双网卡组网方案
- 网卡1(NAT模式) :负责Ubuntu访问公网,网段默认
192.168.78.0 - 网卡2(桥接模式) :桥接到电脑有线网卡,负责与开发板直连通信,静态IP设为
192.168.1.100
详细配置步骤
-
虚拟机添加双网卡 VMware中添加两个网络适配器,分别设置为NAT模式、桥接模式(桥接到物理有线网卡)。
-
Ubuntu内配置IP地址 先通过
ifconfig查看两个网卡名称(如ens33为NAT网卡,ens36为桥接网卡),编辑网络配置文件:sudo vim /etc/network/interfaces配置NAT网卡自动获取IP,桥接网卡设置静态IP:
auto ens33 iface ens33 inet dhcp auto ens36 iface ens36 inet static address 192.168.1.100 netmask 255.255.255.0 -
修复默认路由(关键坑点) 默认路由必须指向NAT网卡才能正常上网,桥接网卡仅负责
192.168.1.0网段通信:sudo route delete default sudo route add default gw 192.168.78.2 ens33 -
路由配置开机自启 创建systemd服务实现开机自动配置路由,避免每次重启重复操作:
sudo vim /etc/systemd/system/custom-route.service写入服务配置:
[Unit] Description=Custom Route Configuration After=network.target [Service] Type=oneshot ExecStart=/sbin/route delete default ExecStart=/sbin/route add default gw 192.168.78.2 ens33 RemainAfterExit=yes [Install] WantedBy=multi-user.target启用服务:
sudo systemctl daemon-reload sudo systemctl enable custom-route.service sudo systemctl start custom-route.service -
双网卡转发(可选:开发板上网) 如果需要开发板通过Ubuntu访问公网,开启IP转发并配置MASQUERADE:
sudo echo "1" > /proc/sys/net/ipv4/ip_forward sudo iptables -t nat -A POSTROUTING -o ens33 -j MASQUERADE同样可以写入上述开机自启服务,实现重启生效。
验证测试
# 测试公网连通性
ping www.baidu.com
# 测试开发板连通性
ping 192.168.1.50
1.2 apt-get软件源配置
apt-get是Ubuntu的软件包管理工具,能自动解决软件依赖,配置国内源可大幅提升下载速度。
-
将软件源替换为阿里云镜像源
-
更新软件源:
sudo apt-get autoclean sudo apt-get update sudo apt-get install -f -
常用命令:
- 安装软件:
sudo apt-get install 软件名 - 卸载软件:
sudo apt-get remove 软件名
- 安装软件:
1.3 minicom串口终端配置
嵌入式开发中,通过串口与开发板交互、查看启动日志、输入命令,minicom是Ubuntu下常用的串口终端工具。
-
安装:
sudo apt-get install minicom -
首次配置:
sudo minicom -s选择
Serial port setup,设置串口设备、波特率115200、8N1。 -
常用操作:
- 启动:
sudo minicom - 退出:
Ctrl + A再按Q,选择Yes退出
- 启动:
1.4 TFTP服务器配置
TFTP是嵌入式开发中最常用的网络文件传输工具,开发板可以直接通过网络从Ubuntu下载内核、设备树等文件。
-
安装服务端与客户端:
sudo apt-get install tftpd-hpa tftp -
编辑配置文件,指定共享目录:
sudo vim /etc/default/tftpd-hpa设置
TFTP_DIRECTORY为共享目录路径,如/home/linux/tftpboot。 -
创建共享目录并设置权限:
mkdir /home/linux/tftpboot chmod 0777 /home/linux/tftpboot -
重启服务:
sudo service tftpd-hpa restart -
功能测试:分别测试上传、下载功能,确认服务正常。
1.5 NFS服务器配置
NFS是网络文件共享协议,将Ubuntu的目录共享给开发板挂载,修改代码后编译完成直接放到共享目录,开发板就能立即运行,无需反复烧录,大幅提升开发效率。
-
安装NFS服务:
sudo apt-get install nfs-kernel-server -
编辑配置文件
/etc/exports,添加共享目录配置:/home/linux/nfs/rootfs * rw sync no_subtree_check no_root_squash*:允许所有客户端访问rw:读写权限no_root_squash:客户端root用户拥有服务端root权限
-
创建共享目录并设置权限:
sudo mkdir -p /home/linux/nfs/rootfs sudo chmod 0777 /home/linux/nfs/rootfs -
重启服务:
sudo service nfs-kernel-server restart -
挂载测试:
# 查看可挂载目录 sudo showmount -e # 本地挂载测试 sudo mount -t nfs -o nolock,rw 192.168.1.100:/home/linux/nfs/rootfs /mnt
1.6 交叉编译工具链配置
什么是交叉编译
在x86架构的Ubuntu上,编译出能在ARM架构开发板上运行的程序,这个过程叫交叉编译,对应的工具就是交叉编译工具链。
配置步骤
-
解压工具链到指定目录,如
/home/linux/tools/opt/ -
添加环境变量到
~/.bashrc:export PATH=$PATH:/home/linux/tools/opt/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin -
重启终端或重新加载配置,验证安装:
arm-linux-gnueabihf-gcc -v输出版本号即为配置成功,其中
hf表示支持硬件浮点指令。
二、开发启动方案:SD卡U-Boot + TFTP内核 + NFS根文件系统
这是嵌入式开发阶段的标准启动方案,优势在于修改内核、驱动、应用后,无需烧录到开发板存储,直接在Ubuntu更新文件,开发板重启就能加载最新版本,调试效率极高。
2.1 整体流程
- 开发板从SD卡启动U-Boot,完成硬件初始化
- U-Boot通过TFTP从Ubuntu下载内核镜像
zImage和设备树.dtb到内存 - U-Boot向内核传递启动参数,跳转执行内核
- 内核启动后,通过NFS挂载Ubuntu上的根文件系统
- 进入Linux命令行,完成系统启动
2.2 U-Boot环境变量配置
在U-Boot串口终端依次配置以下参数,saveenv保存到SD卡持久化:
# 网络基础参数
setenv ipaddr 192.168.1.50
setenv ethaddr 00:04:9f:04:d2:35
setenv gatewayip 192.168.1.1
setenv netmask 255.255.255.0
setenv serverip 192.168.1.100
saveenv
自动启动命令:倒计时结束自动下载内核+设备树并启动
setenv bootcmd 'tftp 80800000 zImage;tftp 83000000 imx6ull-alientek-emmc.dtb;bootz 80800000 - 83000000'
saveenv
内核启动参数:指定控制台、根文件系统为NFS、IP配置
setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.1.100:/home/linux/nfs/rootfs,proto=tcp,nfsvers=3 rw ip=192.168.1.50:192.168.1.100:192.168.1.1:255.255.255.0::eth0:off'
saveenv
配置完成后输入boot或重启开发板,即可自动完成从TFTP下载、NFS挂载的完整启动流程。
三、U-Boot 深入理解与实操
3.1 U-Boot核心定位
U-Boot(Universal Boot Loader)是嵌入式领域最主流的开源引导加载程序,是开发板上电后第一个运行的程序,地位等同于PC的「BIOS+启动引导器」。
- 本质:裸机程序,直接运行在硬件之上,不依赖操作系统
- 核心使命:硬件初始化、加载并启动Linux内核、提供底层调试工具
3.2 核心功能
- 硬件底层初始化:初始化CPU时钟、DDR内存、串口、以太网、SD/EMMC控制器等核心外设
- 引导Linux内核:读取内核镜像与设备树到内存,传递启动参数,跳转执行内核
- 环境变量管理:支持配置参数持久化存储,掉电不丢失
- 调试工具集:提供内存读写、网络调试、存储烧录等丰富的串口命令
- 多启动介质支持:支持SD卡、EMMC、网络、USB等多种启动方式
3.3 U-Boot启动流程(两级架构)
- BL1(ROM Boot):芯片出厂固化在ROM中,上电自动执行,加载第二阶段程序到片内RAM
- SPL(BL2):U-Boot精简版,负责初始化DDR内存,再加载完整U-Boot到DDR运行
- U-Boot正文:完整功能版本,完成外设初始化、倒计时等待、命令行交互、引导内核
3.4 U-Boot编译实操
-
安装依赖库:
sudo apt-get install libncurses5-dev -
解压源码并进入目录,执行编译:
# 清理旧编译 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean # 加载板级配置 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_alientek_emmc_defconfig # 编译 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j16 -
编译产物:顶层目录生成
u-boot.imx镜像文件,可烧录到SD卡或EMMC。
3.5 常用命令分类
| 类别 | 常用命令 | 功能 |
|---|---|---|
| 环境变量 | printenv/setenv/saveenv |
查看、修改、保存环境变量 |
| 内存操作 | md/mw/cp/cmp |
内存读取、写入、拷贝、比较 |
| 网络操作 | ping/tftp/nfs |
网络连通测试、TFTP下载、NFS加载 |
| MMC操作 | mmc dev/mmc read/mmc write/mmc part |
切换设备、读写、查看分区 |
| 启动命令 | bootz/bootm/boot/go |
启动zImage/uImage、执行bootcmd、跳转地址 |
3.6 核心环境变量详解
bootcmd:自动启动命令,U-Boot倒计时结束后自动执行,定义了内核加载与启动的完整流程bootargs:传递给Linux内核的启动参数,包含控制台配置、根文件系统类型与路径、网络配置等,是内核启动的关键参数
四、Linux内核编译与裁剪
4.1 内核概述
Linux内核是操作系统的核心,负责进程调度、内存管理、硬件驱动、文件系统、网络协议等核心功能。嵌入式开发中需要根据硬件平台裁剪配置内核,生成适配的镜像文件。
4.2 编译步骤
-
安装依赖工具:
sudo apt-get install lzop -
解压内核源码并进入目录:
# 清理旧编译 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean # 加载板级默认配置 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_alientek_emmc_defconfig # 图形化配置(可选,裁剪功能) make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig # 全量编译 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all -j16
4.3 编译产物与部署
编译完成后生成两个关键文件:
- 内核镜像:
arch/arm/boot/zImage - 设备树文件:
arch/arm/boot/dts/imx6ull-alientek-emmc.dtb
将两个文件拷贝到TFTP共享目录,开发板启动时就会自动下载最新版本:
cp arch/arm/boot/zImage ~/tftpboot/
cp arch/arm/boot/dts/imx6ull-alientek-emmc.dtb ~/tftpboot/
五、BusyBox 构建根文件系统
5.1 根文件系统的作用
根文件系统是Linux内核启动后挂载的第一个文件系统,包含系统命令、库文件、配置文件、设备节点等,是用户空间运行的基础。嵌入式常用BusyBox构建轻量根文件系统,体积小、易定制。
5.2 BusyBox方案特点
BusyBox被称为"嵌入式Linux的瑞士军刀",将大量Linux命令和工具整合到一个二进制文件中,支持静态编译,占用空间极小,非常适合嵌入式场景。
5.3 构建步骤
-
解压BusyBox源码,修改Makefile指定交叉编译器:
CROSS_COMPILE ?= arm-linux-gnueabihf- ARCH ?= arm -
配置BusyBox:
make defconfig make menuconfig关键配置:开启
Build static binary静态编译,避免依赖动态库。 -
编译并安装到指定目录:
make make install CONFIG_PREFIX=/home/linux/nfs/rootfs -
拷贝依赖库文件 将交叉工具链中的libc库、动态库拷贝到根文件系统的
lib和usr/lib目录,确保程序能正常运行。 -
创建必要目录
mkdir dev proc mnt sys tmp root lib/modules -
完善系统配置文件
/etc/init.d/rcS:系统启动脚本,配置环境变量、挂载文件系统、启动mdev/etc/fstab:文件系统挂载表,定义proc、tmpfs、sysfs等特殊文件系统/etc/inittab:init进程配置,定义系统启动、重启、关机对应的动作
5.4 功能验证
将构建好的根文件系统放到NFS共享目录,开发板通过NFS挂载启动,能正常进入命令行、运行程序,即为构建成功。
六、Linux驱动基础核心知识点
6.1 驱动本质与三大分类
驱动是运行在内核态的代码,是硬件与用户程序之间的桥梁,向下管理硬件,向上提供标准操作接口。
- 字符设备:按字节流顺序访问,如串口、LED、按键,是最基础的驱动类型
- 块设备:以数据块为单位随机访问,如SD卡、硬盘,用于存储场景
- 网络设备:面向数据包收发,不对应普通文件节点,如网卡
6.2 内核模块:驱动的载体
内核模块是可以动态加载卸载的代码段,无需重新编译内核,是Linux驱动的标准开发形式。
- 四大要素:
module_init入口、module_exit出口、MODULE_LICENSE许可证、辅助描述信息 - 操作命令:
insmod加载、rmmod卸载、lsmod查看已加载模块 - 进阶特性:模块参数动态传参、
EXPORT_SYMBOL符号导出跨模块调用
6.3 字符设备驱动核心框架
- 两个核心结构体:
struct cdev:内核抽象字符设备的结构体struct file_operations:操作函数表,封装open、read、write、ioctl等接口
- 设备号:主设备号(标识驱动类型)+ 次设备号(标识不同设备实例),支持静态申请和动态分配
- 核心流程:分配设备号 → 初始化cdev并绑定操作函数 → 注册到内核
- 空间交互:通过
copy_from_user和copy_to_user完成内核与用户空间的数据拷贝
6.4 bus-device-driver驱动模型
核心思想是硬件描述与驱动逻辑分离,通过总线统一管理匹配,实现一个驱动适配多个同类硬件。
- 总线(bus):管理者,负责设备与驱动的匹配绑定
- 设备(device):描述硬件资源信息
- 驱动(driver):实现通用驱动逻辑
- Platform平台总线:专为SoC片上外设设计的虚拟总线,是嵌入式最常用的驱动框架
6.5 设备树(Device Tree)
将硬件配置信息从驱动代码中剥离,用独立的.dts树形文件描述硬件,驱动只实现通用逻辑,通过解析设备树获取硬件参数,实现驱动通用化、跨板适配。
- 核心属性:
compatible(匹配标识)、reg(寄存器地址)、interrupts(中断配置)、status(设备状态) - 驱动通过
of_系列函数解析设备树节点属性
6.6 中断处理机制
采用顶半部+底半部分层设计,平衡中断响应速度与处理耗时:
- 顶半部:中断触发后立即执行,只做紧急操作,运行在中断上下文,不可睡眠
- 底半部:延后执行耗时逻辑,主流实现有tasklet(软中断,不可睡眠)和工作队列(内核线程,可睡眠)
6.7 驱动核心设计思想
- 分层思想:通用逻辑向上抽取复用,硬件差异向下适配
- 分离思想:硬件信息与驱动代码分离,一套驱动适配多硬件
- 面向对象思想:用结构体封装属性与方法,模拟面向对象编程
以上就是嵌入式驱动前两日的全部学习内容,从底层环境搭建到系统启动全流程,再到驱动核心理论,形成了完整的入门知识体系。后续会继续深入字符设备驱动、platform总线、设备树驱动等内容的学习与实操。