1. 课程导学与开发环境搭建

各位同学好,我是老吴。做嵌入式Linux显示驱动这块,掐指一算也有十来年了。今天咱们开始第一讲,先把整个显示子系统的大框架理清楚,再把开发环境搭起来。别小看环境搭建,我见过太多人卡在这一步,一卡就是好几天。

1.1 显示子系统全景概览

嵌入式Linux的显示子系统,说白了就是一条数据流水线。应用程序把图像数据扔给内核,内核经过层层处理,最终送到屏幕上点亮像素。这条流水线上有三个关键角色:

  • 应用层:Qt、LVGL、Wayland等GUI框架,负责生成图像内容
  • 内核层:DRM/KMS框架、GPU驱动、显示控制器驱动,负责管理和调度
  • 硬件层:LCD屏、MIPI DSI/LVDS/RGB接口、显示控制器、GPU/DPU

我个人习惯把显示子系统比作一个「显示管道」。数据从应用层流下来,经过内核的调度,最终在屏幕上呈现。你想想看,如果管道里任何一个环节堵了,画面就会出问题——撕裂、闪烁、黑屏,啥毛病都有。

核心要点:显示驱动开发,本质上就是打通这条管道,让数据顺畅地从应用流到屏幕。

嵌入式Linux显示子系统数据流 应用层 Qt / LVGL / Wayland 内核层 DRM/KMS + GPU驱动 硬件层 LCD / MIPI / LVDS 内核显示子系统内部结构 DRM Core KMS Framebuffer V4L2 DRM/KMS是当前主流框架 FBDEV已逐渐被淘汰

1.2 硬件平台介绍

本课程选用两块主流开发板:IMX6ULL 和 STM32MP157。为什么选它们?因为这两款芯片在工业产品里用得最多,资料也最全。

特性 IMX6ULL STM32MP157
CPU核心 单核 Cortex-A7 @800MHz 双核 Cortex-A7 @650MHz + M4
显示控制器 eLCDIF (并行RGB/8位串行) LTDC (并行RGB) + DSI主机
最大分辨率 1366×768 @60fps 1080p @60fps
GPU 无 (2D加速由PXP完成) 内置 Vivante GCNano
显示接口 RGB / LVDS (需外接转换) RGB / MIPI DSI
典型应用 工业HMI、车载仪表 智能家居、医疗设备

选型建议:如果你的项目只需要简单的UI显示,IMX6ULL性价比更高;如果需要跑复杂的GUI动画,STM32MP157带GPU会省力很多。

1.3 Ubuntu与交叉编译环境配置

开发环境我推荐用 Ubuntu 20.04 LTS 或 22.04 LTS。别问我为什么不用最新版——稳定第一。我曾经在Ubuntu 24.04上踩过工具链兼容性的坑,折腾了两天才发现是glibc版本问题。

1.3.1 基础软件包安装

# 更新软件源
sudo apt update && sudo apt upgrade -y

# 安装基础开发工具
sudo apt install -y build-essential git vim cmake
sudo apt install -y libncurses5-dev bison flex
sudo apt install -y libssl-dev libelf-dev

# 安装设备树编译工具
sudo apt install -y device-tree-compiler

# 安装TFTP/NFS服务(调试用)
sudo apt install -y tftpd-hpa nfs-kernel-server

1.3.2 交叉编译工具链

IMX6ULL和STM32MP157都是ARM Cortex-A7核心,但工具链略有不同。我个人习惯把工具链放在 /opt/toolchains/ 目录下,方便管理。

平台 工具链名称 下载方式
IMX6ULL arm-linux-gnueabihf- 从NXP官网或Linaro下载
STM32MP157 arm-ostl-linux-gnueabi- 从ST官网下载SDK
# 以IMX6ULL为例,解压工具链
sudo mkdir -p /opt/toolchains
cd /opt/toolchains
sudo tar xvf ~/gcc-arm-10.3-2021.07-x86_64-arm-linux-gnueabihf.tar.xz

# 配置环境变量(建议写入 ~/.bashrc)
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-
export PATH=$PATH:/opt/toolchains/gcc-arm-10.3-2021.07-x86_64-arm-linux-gnueabihf/bin

注意:工具链版本一定要和内核版本匹配。比如Linux 5.10以上内核,建议用gcc 10.x以上版本。版本不匹配会导致编译报错,而且错误信息往往很隐晦。

1.4 内核源码获取与编译

内核源码获取有两种方式:从官方仓库克隆,或者下载厂商提供的BSP包。我建议初学者先用厂商BSP,因为配置已经调好了,省去很多麻烦。

1.4.1 获取内核源码

# 方式一:从官方主线仓库克隆(适合IMX6ULL)
git clone https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
cd linux
git checkout v5.10.100

# 方式二:从NXP官方仓库克隆(带IMX补丁)
git clone https://github.com/nxp-imx/linux-imx.git
cd linux-imx
git checkout lf-5.10.y

1.4.2 配置与编译

配置内核是门学问。我刚开始做的时候,经常配错选项,编译出来的内核要么缺驱动,要么启动就挂。后来我总结了一套流程:

  1. 加载默认配置:厂商提供的defconfig文件
  2. 微调配置:用menuconfig添加或删除功能
  3. 编译内核:make zImage(或make Image)
  4. 编译设备树:make dtbs
  5. 编译模块:make modules
# IMX6ULL 配置示例
make imx_v7_defconfig
make menuconfig  # 手动调整显示相关选项
make -j$(nproc) zImage
make -j$(nproc) dtbs
make -j$(nproc) modules

# 编译完成后,生成的文件在 arch/arm/boot/ 下
ls arch/arm/boot/zImage
ls arch/arm/boot/dts/imx6ull-14x14-evk.dtb

关键配置项:显示驱动相关的内核选项集中在 Device Drivers → Graphics support 下。记得开启 DRM 和对应的 LCDIF 或 LTDC 驱动。

1.4.3 常见编译错误与解决

这里列几个我踩过的坑:

错误现象 原因 解决方法
undefined reference to `__aeabi_uidiv' 工具链缺少除法库 添加 -lgcc 链接选项
fatal error: linux/compiler-gcc.h 工具链版本与内核不匹配 升级或降级工具链
multiple definition of `yylloc' flex/bison版本问题 安装 flex-old 或降级flex

调试技巧:编译出错时,先看第一行错误信息,别急着翻到最后。很多时候第一个错误才是根因,后面的都是连锁反应。

1.5 本章小结

这一章我们走完了显示子系统的全景,认识了IMX6ULL和STM32MP157两块板子,也把开发环境搭好了。嗯,环境搭建这一步虽然枯燥,但基础打牢了,后面写驱动、调参数才能顺风顺水。

我记得第一次给IMX6ULL移植显示驱动时,光环境就折腾了三天。工具链版本不对、内核配置漏项、设备树写错——各种问题轮番上阵。但熬过去之后,看到屏幕上出现那只小企鹅,那种成就感,值得。