4. 开发环境搭建
嵌入式显示子系统的开发与通用Linux应用开发有本质区别:目标硬件资源受限,无法直接在开发板上运行完整的编译工具链。因此,交叉编译是嵌入式开发的基石。本章将系统讲解从工具链配置、内核源码管理到设备树显示节点定制的完整流程,为后续驱动开发与多屏扩展打下坚实的工程基础。
开发环境全景:本课程采用 Host(x86_64 Ubuntu 22.04) + Target(ARM Cortex-A72 架构开发板) 的典型组合。所有编译工作均在Host侧完成,生成的可执行文件与内核镜像通过TFTP/NFS或USB烧录至Target侧运行。
4.1 交叉编译工具链配置
交叉编译工具链是一套运行在Host平台、生成Target平台机器码的编译器、链接器、调试器及库文件的集合。配置不当将直接导致内核编译失败或驱动模块无法加载。
4.1.1 工具链选择与安装
针对ARM64(AArch64)架构,推荐使用以下两种工具链:
| 工具链类型 | 适用场景 | 安装方式 | 前缀 |
|---|---|---|---|
| Linaro GCC | 通用嵌入式Linux开发,社区支持广泛 | 下载预编译包并解压至 /opt/toolchains/ |
aarch64-linux-gnu- |
| ARM GNU Toolchain | 官方发布,与ARM架构同步更新 | apt安装或下载官方tar包 | aarch64-none-linux-gnu- |
安装步骤(以Linaro GCC 7.5为例):
- 下载工具链:
wget https://releases.linaro.org/components/toolchain/binaries/7.5-2019.12/aarch64-linux-gnu/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu.tar.xz - 解压至指定目录:
sudo tar -xvf gcc-linaro-*.tar.xz -C /opt/toolchains/ - 添加环境变量(写入
~/.bashrc):
export PATH=/opt/toolchains/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin:$PATH
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
- 验证安装:
aarch64-linux-gnu-gcc --version
4.1.2 工具链验证与测试
编写一个简单的C程序,使用交叉编译器编译,并通过 file 命令确认生成的是ARM64可执行文件:
// hello_display.c
#include <stdio.h>
int main(void) {
printf("Display Subsystem Ready!\n");
return 0;
}
# 交叉编译
aarch64-linux-gnu-gcc -o hello_display hello_display.c
# 检查文件类型
file hello_display
# 输出应包含:ELF 64-bit LSB executable, ARM aarch64
常见陷阱:
1. 环境变量未生效时,内核编译会调用Host的本地gcc,导致生成x86_64架构的vmlinux,无法在ARM板上启动。
2. 工具链版本与内核版本不匹配(如使用过老的GCC编译新内核)会触发编译错误,建议使用内核源码
1. 环境变量未生效时,内核编译会调用Host的本地gcc,导致生成x86_64架构的vmlinux,无法在ARM板上启动。
2. 工具链版本与内核版本不匹配(如使用过老的GCC编译新内核)会触发编译错误,建议使用内核源码
Documentation/process/changes.rst 中推荐的GCC版本。
4.2 Linux内核源码获取与编译
显示驱动紧密耦合于内核框架(DRM/KMS),因此必须从源码编译内核,并确保配置选项正确开启。
4.2.1 获取内核源码
推荐从 Linux Kernel官方仓库 或 芯片厂商(如Rockchip、NXP)提供的BSP 获取:
# 方法一:从kernel.org获取主线内核(版本5.10 LTS)
wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.10.210.tar.xz
tar -xvf linux-5.10.210.tar.xz
cd linux-5.10.210
# 方法二:从芯片厂商BSP仓库克隆(以Rockchip为例)
git clone -b rk3588-linux https://github.com/rockchip-linux/kernel.git
4.2.2 内核配置与编译
显示子系统依赖的关键配置项必须手动确认:
| 配置项 | 说明 | 推荐值 |
|---|---|---|
CONFIG_DRM |
Direct Rendering Manager 核心框架 | y |
CONFIG_DRM_KMS_HELPER |
Kernel Mode Setting 辅助层 | y |
CONFIG_DRM_PANEL_SIMPLE |
简单显示面板驱动(MIPI DSI/EDP) | y 或 m |
CONFIG_DRM_BRIDGE |
显示桥接芯片驱动框架(HDMI转DP等) | y |
CONFIG_FB |
传统Framebuffer子系统(与DRM互斥时关闭) | n |
编译命令序列:
# 使用厂商默认配置作为起点(假设为rk3588_defconfig)
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- rk3588_defconfig
# 进入菜单配置界面,检查DRM相关选项
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- menuconfig
# 编译内核镜像与设备树
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- Image dtbs -j$(nproc)
# 编译内核模块(可选)
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- modules -j$(nproc)
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- INSTALL_MOD_PATH=./modules modules_install
编译产物说明:
arch/arm64/boot/Image —— 内核镜像,用于引导系统。arch/arm64/boot/dts/rockchip/ —— 编译后的设备树文件(.dtb),包含显示节点配置。
4.3 设备树(DTS)基础与显示节点配置
设备树(Device Tree)是一种描述硬件资源的数据结构,用于将板级硬件信息从内核源码中解耦。在显示子系统中,显示控制器、接口(HDMI/DP/MIPI DSI)、面板、背光、桥接芯片等均通过设备树节点描述。
4.3.1 设备树语法速览
一个典型的设备树节点包含:节点名、地址单元、属性(reg、interrupts、clocks、pinctrl等)。
/dts-v1/;
#include <dt-bindings/display/drm_mipi_dsi.h>
/ {
model = "Embedded Display Board v1.0";
compatible = "vendor,board";
chosen {
stdout-path = &uart2;
};
/* 显示控制器节点 */
display_subsystem: display-subsystem {
compatible = "rockchip,display-subsystem";
ports = <&vopb_out>, <&vopl_out>;
status = "okay";
};
/* MIPI DSI 显示面板节点 */
panel: panel@0 {
compatible = "boe,tv080wum-nl0";
reg = <0>;
enable-gpios = <&gpio1 RK_PB0 GPIO_ACTIVE_HIGH>;
backlight = <&backlight>;
port {
panel_in_dsi: endpoint {
remote-endpoint = <&dsi_out_panel>;
};
};
};
};
4.3.2 显示节点关键属性解析
| 属性 | 作用 | 示例值 |
|---|---|---|
compatible |
驱动匹配标识,内核通过该字符串查找对应驱动 | "rockchip,rk3588-vop" |
reg |
寄存器地址范围,描述硬件控制器的基地址与大小 | <0x0 0xfdd90000 0x0 0x1000> |
interrupts |
中断号,用于显示控制器VSYNC等事件通知 | <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH> |
clocks |
时钟源,指定显示控制器所需的像素时钟、AHB时钟等 | <&cru ACLK_VOP>, <&cru HCLK_VOP> |
ports |
显示输出端口,连接至HDMI/DP/MIPI DSI等接口 | <&vop_out_dsi> |
status |
节点使能状态,okay 启用,disabled 禁用 |
"okay" |
4.3.3 显示节点配置实战:添加HDMI输出
以下示例展示如何在RK3588设备树中启用HDMI显示输出,并配置对应的时钟与引脚复用:
&hdmi0 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&hdmi0m0_hpd &hdmi0m0_ddc_scl &hdmi0m0_ddc_sda>;
clocks = <&cru PCLK_HDMI0>, <&cru CLK_HDMI0>;
clock-names = "pclk", "hclk";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
hdmi0_in_vp0: endpoint {
remote-endpoint = <&vp0_out_hdmi0>;
};
};
};
};
&hdptxphy0 {
status = "okay";
};
调试技巧:编译设备树后,使用
dtc -I dtb -O dts -o decompiled.dts arch/arm64/boot/dts/rockchip/rk3588-evb1.dtb 反编译确认节点是否生效。若显示节点未出现,检查 #include 路径与 & 标签引用是否正确。
4.4 显示子系统设备树架构图
下图展示了从显示控制器(VOP)到物理接口(HDMI/DP/MIPI DSI)再到面板的设备树节点连接关系:
4.5 开发环境验证清单
完成上述配置后,建议按以下清单逐项验证,确保环境无误:
| 验证项 | 验证方法 | 预期结果 |
|---|---|---|
| 交叉编译器可用 | aarch64-linux-gnu-gcc -v |
显示版本信息,无“command not found” |
| 内核编译成功 | make Image -j4 无错误退出 |
生成 arch/arm64/boot/Image |
| 设备树编译成功 | make dtbs 无错误退出 |
生成对应 .dtb 文件 |
| DRM配置已开启 | grep CONFIG_DRM .config |
CONFIG_DRM=y |
| 显示节点存在 | dtc -I dtb -O dts xxx.dtb | grep display |
输出包含 display-subsystem 及相关子节点 |