IMX6ULL Linux 驱动开发流程:从环境搭建到系统启动与内核编译

本文基于 NXP i.MX6ULL 嵌入式平台,结合实际开发操作链路,系统梳理嵌入式 Linux 驱动开发的体系,覆盖开发环境标准化搭建、Linux 系统三大件(U-Boot、内核、根文件系统)、完整启动流程、内核编译裁剪、根文件系统制作等环节。

一、嵌入式 Linux 开发体系与硬件基础

嵌入式 Linux 驱动开发的核心,是围绕「硬件平台初始化 - 内核引导 - 系统挂载 - 驱动适配」的完整链路展开,其底层依赖 i.MX6ULL 硬件平台与 Linux 操作系统的分层设计思想。

1. 硬件平台核心参数

本文基于正点原子 i.MX6ULL MINI 核心板,核心硬件配置如下:

  • 主控:NXP i.MX6ULL,Cortex-A7 内核,主频最高 792MHz
  • 内存:512MB DDR3L,用于系统运行、镜像加载与数据缓存
  • 存储:8GB EMMC(核心板板载)+ 最高 32GB TF/SD 卡(底板扩展),用于系统镜像与文件系统固化
  • 外设资源:集成 100M 以太网、RGB LCD 接口、I2C、SPI、CAN、ADC、GPIO、USB OTG 等常用外设,满足工业级开发需求

2. Linux 系统核心三大件

嵌入式 Linux 系统的运行,完全依赖三个核心组件,也是开发过程中需要重点适配、编译与调试的对象:

表格

组件 核心作用 开发产物
U-Boot 通用引导加载程序,完成硬件基础初始化、镜像加载与内核启动参数传递,是系统上电后运行的第一个可定制代码 u-boot.imx
Linux 内核 操作系统核心,负责进程调度、内存管理、硬件驱动、网络协议栈、虚拟文件系统等核心能力 zImage(内核镜像)+ imx6ull-alientek-emmc.dtb(设备树文件)
根文件系统 rootfs 内核启动后挂载的第一个文件系统,存放系统命令、动态库、配置文件、设备节点与用户程序,是用户空间与内核交互的载体 rootfs.tar.bz2(压缩包)或 nfs 共享目录

Linux 内核采用分层设计,核心由进程调度、内存管理、虚拟文件系统 (VFS)、网络接口、进程间通信 5 个子系统构成;而设备驱动则是内核与硬件之间的桥梁,除网络设备外,字符设备、块设备均被映射到文件系统的文件节点,通过 open/read/write/close 等标准接口访问,即 Linux「一切皆是文件」的核心设计思想。

二、开发环境标准化搭建

稳定的开发环境是嵌入式开发的基础,核心目标是实现「Ubuntu 虚拟机既能访问公网下载软件,又能与开发板稳定通信」,同时配套开发所需的工具链与服务。

1. 虚拟机双网卡网络配置

采用「NAT 模式 + 桥接模式」双网卡组网,是嵌入式开发的最优方案,解决单网卡无法同时满足上网与开发板通信的痛点:

  • 网络适配器 1:NAT 模式,负责 Ubuntu 访问公网,IP 网段默认配置为 192.168.78.0/24,自动获取 IP
  • 网络适配器 2:桥接模式,桥接到电脑有线网卡,负责与开发板通信,配置静态 IP 192.168.1.100/24,与开发板 IP 192.168.1.50 同网段

核心配置步骤:

  1. VMware 中添加双网卡,分别配置 NAT 与桥接模式,桥接模式需指定到物理有线网卡,而非自动检测
  2. 修改 Ubuntu 网络配置文件/etc/network/interfaces,NAT 网卡设为 dhcp 自动获取,桥接网卡设为 static 静态 IP
  3. 配置默认路由走 NAT 网卡,确保公网访问正常,通过route命令验证路由表,同时设置开机自启避免重启后配置失效
  4. 连通性验证:ping www.baidu.com验证公网,ping 192.168.1.50验证与开发板的通信

2. 核心开发服务与工具配置

基于双网卡网络,需配置以下服务与工具,覆盖开发全流程需求:

  1. apt-get 源配置 :替换为阿里云源,执行sudo apt-get autoclean && sudo apt-get update更新源,解决软件下载慢、依赖安装失败的问题
  2. minicom 串口工具 :通过sudo apt-get install minicom安装,配置串口参数为 115200 8N1,关闭硬件流控,用于开发板终端交互与启动日志查看
  3. tftp 服务器 :安装tftpd-hpa服务,指定共享目录/home/linux/tftpboot并赋予 777 权限,用于 U-Boot 阶段下载内核镜像与设备树文件,无需反复烧写存储介质
  4. nfs 服务器 :安装nfs-kernel-server,修改/etc/exports配置共享目录/home/linux/nfs/rootfs,开放读写、同步、无 root 权限限制,用于开发阶段根文件系统的网络挂载
  5. 交叉编译工具链 :采用gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf,将工具链路径添加到系统 PATH 环境变量,通过arm-linux-gnueabihf-gcc -v验证安装,实现 x86 主机编译 ARM 平台可执行程序

三、Linux 系统启动流程解析

1. BotROM 阶段

  1. 设置为 SD 卡启动
  2. 上电
  3. 执行 0x0 地址的代码
  4. imx6ull 芯片内部的 96K 的 BotRAM,使用的 imx6ull 芯片内部的 128k SRAM 空间
  5. 查看启动方式为 SD 卡启动
  6. 从 SD 卡中找 uboot.imx(uboot.bin + DCD 数据头)文件
  7. 从 DCD 数据头中找到时钟配置、DDR 配置信息初始化 DDR
  8. 将 uboot.bin 拷贝到 DDR 中
  9. 跳转执行 uboot.bin

2. uboot 阶段

  1. 重定位异常向量表

  2. 切换工作模式

  3. 关闭 MMU、DCache、看门狗

  4. 初始化串口、网口及相关外设

  5. 将 uboot 代码搬移到高地址

  6. 进入用户交互阶段

  7. 倒计时等待用户输入 Enter

  8. 如果用户不输入 Enter 执行 bootcmd

    setenv bootcmd 'tftp 80800000 zImage;tftp 83000000 imx6ull-alientek-emmc.dtb;bootz 80800000 - 83000000'
    saveenv

  9. 找内核和设备树(tftp 80800000 zImage; tftp 83000000 dtb; bootz)

  10. 将 bootargs 写入到设备树 choosen 节点中

  11. R0(固定值)、R1 (machine ID)、R2 (设备树的地址) 对内核传参

    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

3. 内核阶段

  1. 解析设备树文件
  2. 启动内核
    1. 内存管理
    2. 多任务管理
    3. 进程间通信
    4. 网络通信
    5. 文件系统管理
  3. 根据设备树中的 choosen 节点挂载文件系统
  4. 文件系统使用 nfs 挂载

4. 文件系统

  1. 内核执行 linuxrc
  2. 加载 /etc/inittab 文件设置了开机执行脚本关机执行脚本..
  3. 执行 /etc/init.d/rcS设置环境变量挂载文件系统
  4. 执行 /etc/fstab挂载 sys 和 proc 文件系统
  5. 通过 fork+exec 启动终端
  6. 终端启动 fork+exec 启动 shell
  7. shell 执行用户输入 fork+exec

四、Linux 内核编译与裁剪

Linux 内核是一个高度可裁剪的开源项目,开发过程中需根据硬件平台与功能需求,完成内核的配置、编译与裁剪,仅保留需要的功能,减少镜像体积与启动耗时。

1. 编译前置准备

  1. 安装编译依赖:sudo apt-get install lzop libncurses5-dev,lzop 用于 zImage 镜像压缩,ncurses 用于 menuconfig 图形化配置界面
  2. 获取对应版本内核源码:采用 NXP 官方维护的linux-imx-rel_imx_4.1.15_2.1.0_ga版本,适配 i.MX6ULL 平台

2. 内核编译核心流程

内核编译通过 Makefile 管理,严格遵循「清理 - 加载默认配置 - 自定义裁剪 - 编译 - 产物部署」的流程,所有操作均在源码顶层目录执行:

  1. 清理历史编译文件

    bash

    运行

    复制代码
    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean

    ARCH 指定目标架构为 arm,CROSS_COMPILE 指定交叉编译工具链前缀,distclean 清除所有历史配置与编译产物,确保编译环境纯净。

  2. 加载板级默认配置

    bash

    运行

    复制代码
    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_alientek_emmc_defconfig

    该命令将开发板厂商提供的板级默认配置文件,写入内核顶层目录的.config 文件,.config 是内核编译的核心配置文件,所有功能的开启 / 关闭均由该文件定义。

  3. 图形化功能裁剪

    bash

    运行

    复制代码
    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig

    打开图形化配置界面,按需开启 / 关闭内核功能,常用配置项包括:GPIO 子系统、I2C/SPI 总线驱动、CAN 总线、IIO ADC 驱动、LCD / 触摸屏驱动、摄像头 V4L2 驱动、网络协议栈等,无需的功能直接关闭,减少内核体积。

  4. 全量编译

    bash

    运行

    复制代码
    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all -j16

    -j16 指定编译线程数,根据主机 CPU 核心数调整,提升编译速度。编译完成后,核心产物为:

    • 内核镜像:arch/arm/boot/zImage
    • 设备树二进制文件:arch/arm/boot/dts/imx6ull-alientek-emmc.dtb
  5. 产物部署 将编译生成的 zImage 与 dtb 文件,拷贝到 tftp 服务器的共享目录/home/linux/tftpboot,U-Boot 即可通过 tftp 下载最新的内核与设备树,无需烧写存储介质。

3. 内核模块的加载方式

内核功能与驱动分为两种加载方式,适配不同的开发场景:

  1. 静态加载:将驱动代码编译进内核镜像,随内核启动自动执行初始化,适用于系统核心功能与必须开机加载的驱动
  2. 动态加载 :将驱动代码编译为独立的.ko 内核模块,内核启动后,通过insmod命令加载、rmmod命令卸载,无需重新编译内核,是外设驱动开发的主要方式,大幅提升调试效率

五、根文件系统制作与配置

根文件系统是 Linux 系统运行的基础,内核启动后必须挂载根文件系统才能进入用户空间,嵌入式平台通常采用 busybox 制作极简根文件系统,占用空间小、易于移植。

1. 根文件系统核心目录结构

根文件系统遵循 Linux FHS 标准,核心目录与作用如下:

表格

目录 核心作用
/bin 存放系统基础命令(ls、cd、cat 等),由 busybox 生成
/sbin 存放系统管理员命令(ifconfig、mount、insmod 等)
/lib 存放交叉编译工具链的动态链接库,为应用程序与系统命令提供运行依赖
/dev 存放设备节点文件,由内核与 mdev 自动生成,是用户空间访问硬件的入口
/etc 存放系统配置文件,包括启动脚本、环境变量、文件系统挂载配置等
/proc、/sys 虚拟文件系统挂载点,proc 存放内核进程与系统信息,sys 存放设备与驱动的属性信息
/mnt 临时挂载目录,用于 nfs、U 盘、SD 卡等存储介质的挂载
/root root 用户的家目录

2. 基于 busybox 的根文件系统制作流程

  1. 源码准备与工具链配置解压 busybox-1.29.0 源码,修改顶层 Makefile,指定 ARCH=arm,CROSS_COMPILE=arm-linux-gnueabihf-,匹配交叉编译工具链。

  2. busybox 功能配置

    bash

    运行

    复制代码
    make defconfig  # 加载默认配置
    make menuconfig # 图形化配置

    核心配置项:关闭静态编译(避免 DNS 解析异常)、开启 vi-style 行编辑、开启 mdev 功能与子目录支持,其余功能按需开启。

  3. 编译与安装

    bash

    运行

    复制代码
    make
    make install CONFIG_PREFIX=/home/linux/nfs/rootfs

    将编译生成的命令与基础目录,安装到指定的 rootfs 目录。

  4. 动态库移植拷贝交叉编译工具链中的 libc 库、动态链接库到 rootfs 的 /lib 与 /usr/lib 目录,包括所有.so 动态库文件与.a 静态库文件,确保系统命令与应用程序能够正常运行。

  5. 必备目录与配置文件完善

    1. 创建 dev、proc、sys、tmp、mnt、root 等必备目录
    2. 编写 /etc/init.d/rcS 启动脚本,配置环境变量、挂载文件系统、启动 mdev
    3. 编写 /etc/fstab 文件,定义开机自动挂载的虚拟文件系统
    4. 编写 /etc/inittab 文件,配置 init 进程的启动动作与控制台交互

3. 根文件系统的两种使用方式

  1. 固化模式:将 rootfs 打包为 rootfs.tar.bz2,通过 mfgtool 工具烧写到 EMMC/SD 卡,设备上电后自动从本地存储挂载根文件系统,适用于量产与设备独立运行场景
  2. 开发模式:将 rootfs 目录配置为 nfs 共享目录,内核通过 bootargs 参数指定 nfs 挂载,修改文件系统中的配置、应用程序、驱动模块后,重启开发板即可生效,无需重新烧写,是开发调试阶段的最优选择

六、开发模式选择与实操建议

针对不同的开发阶段,需选择对应的系统部署与启动模式,兼顾开发效率与设备运行稳定性。

1. 三种主流开发模式对比

表格

模式 部署方式 适用场景 优势
模式一 全系统烧写到 SD 卡 量产多设备部署、系统刷机恢复 设备可独立运行,系统固化稳定
模式二 全系统烧写到 EMMC 产品最终交付、设备独立运行 板载存储启动,无需外接 SD 卡,稳定性高
模式三 U-Boot 烧写到 SD 卡 + zImage 通过 tftp 下载 + rootfs 通过 nfs 挂载 驱动开发、内核调试、应用程序开发 代码修改后无需烧写,重启即可生效,开发效率最高

2. 开发阶段核心建议

  1. 驱动与内核开发阶段,优先采用模式三,减少反复烧写存储介质的耗时,同时便于通过 nfs 直接修改文件系统中的驱动模块与测试程序
  2. 内核功能裁剪完成后,先通过 tftp 下载验证启动正常,再固化到 EMMC/SD 卡,避免启动失败导致设备变砖
  3. 外设驱动开发优先采用动态加载的.ko 模块方式,无需重新编译内核,快速迭代调试
  4. 系统启动失败时,优先通过串口日志定位问题阶段:无串口日志排查 U-Boot 与硬件;U-Boot 启动正常但内核不启动,排查设备树与内核配置;内核启动后挂载根文件系统失败,排查 bootargs 参数、nfs 服务配置与库文件完整性

七、总结

嵌入式 Linux 驱动开发的核心,是建立「硬件平台 - 引导程序 - 内核 - 根文件系统 - 用户程序」的完整链路认知,本文覆盖的环境搭建、系统启动流程、内核编译、根文件系统制作,是所有外设驱动开发的基础。

相关推荐
格林威2 小时前
AI视觉项目部署:Docker 部署视觉服务可行性分析
linux·运维·人工智能·数码相机·docker·容器·工业相机
江湖有缘2 小时前
极简部署Radicale:Docker快速搭建自托管日历 / 联系人服务
运维·docker·容器
huanmieyaoseng10032 小时前
Linux安装达梦数据库DM8
linux·运维·数据库
没bug怎么跑2 小时前
rsync全网备份全流程
linux·运维·github
TechMasterPlus2 小时前
Linux 驱动开发深度解析:从内核模块到设备驱动
linux·运维·驱动开发
念恒123062 小时前
Linux权限
linux·c语言
TechMasterPlus2 小时前
浏览器自动化工具深度对比:Playwright、Chrome DevTools 与 Agent Browser
运维·自动化·chrome devtools
落羽的落羽3 小时前
【算法札记】练习 | Week1
linux·服务器·c++·人工智能·python·算法·机器学习
炸炸鱼.3 小时前
LVS 负载均衡群集实战指南
运维·负载均衡·lvs