1. 课程导入
各位好,我是老赵。做嵌入式图形驱动有些年头了,瑞萨R-Car平台也折腾了好几个项目。今天咱们聊聊R-Car系列,特别是它的图形显示子系统。嗯,这部分内容,说白了就是整个移植工作的地基——地基没打好,后面全是坑。
1.1 R-Car系列芯片:你该选哪一颗?
R-Car是瑞萨面向汽车电子推出的SoC家族。覆盖从入门仪表到高端座舱的全场景。我个人习惯把R-Car分成三代:
| 系列 | 典型型号 | 图形能力 | 典型场景 |
|---|---|---|---|
| R-Car Gen2 | H2, M2, E2 | SGX544MP2 (PowerVR) | 入门仪表、AVM |
| R-Car Gen3 | H3, M3, E3, D3 | GX6650 / GX6250 (PowerVR) | 中高端座舱、全景环视 |
| R-Car Gen4 | S4, V4H, V3U | AXR8G (Imagination) + 专用NPU | 自动驾驶、超高清仪表 |
关键点: 如果你做的是图形显示驱动移植,Gen3是目前最成熟的平台。H3/M3的文档和社区支持最全。Gen4虽然性能强,但很多驱动接口还在迭代,我建议新手从Gen3入手。
为什么会这样?因为Gen3的图形显示子系统架构已经非常稳定。我在2018年做过一个H3的项目,当时被它的显示通道数量吓了一跳——最多支持8路独立显示输出。你想想看,一个芯片同时驱动仪表、中控、HUD、后排娱乐,这得有多强的显示控制器。
1.2 图形显示子系统架构:别被框图吓到
第一次看R-Car的显示子系统框图,你可能会觉得眼花缭乱。其实核心就三个模块:
- DU (Display Unit) —— 显示控制器,负责合成图层、生成时序
- VSP (Video Signal Processor) —— 视频处理管线,做缩放、旋转、色彩转换
- LIF (LVDS/eDP/HDMI Interface) —— 物理输出接口
它们的关系是这样的:
我的经验: 移植驱动时,90%的问题出在VSP和DU的时钟配置上。我曾经花了两天时间调试一个显示偏移问题,最后发现是VSP的时钟分频设错了。所以,拿到开发板第一件事——确认时钟树。
1.3 开发环境搭建:别在第一步就卡住
搭建开发环境这件事,说简单也简单,说复杂也复杂。我见过太多人在这一步浪费一整天。咱们按步骤来:
- 获取SDK —— 从瑞萨官网下载R-Car SDK (Yocto BSP)。注意选对芯片型号和版本。我个人习惯用LTS版本,稳定。
- 安装依赖 —— Ubuntu 20.04/22.04 都行。需要安装的工具链:gcc-arm-linux-gnueabihf、cmake、python3、device-tree-compiler。
- 配置Yocto环境 —— 运行
source poky/oe-init-build-env。然后修改local.conf,指定MACHINE为你的板子型号。 - 编译最小系统 ——
bitbake core-image-minimal。第一次编译会下载大量源码,建议用代理或提前准备好本地sstate缓存。 - 烧录与启动 —— 生成SD卡镜像,用
dd命令写入。上电后通过串口观察启动日志。
注意: 瑞萨的BSP对网络要求很高。如果你在公司内网,记得配置好代理。我曾经因为代理没配好,编译到一半卡在git clone上,白白浪费了3个小时。
1.4 SDK安装:图形显示相关的组件
SDK装好之后,你还需要确认图形显示相关的组件是否齐全。我建议你检查以下几个关键包:
- kernel-module-du —— DU显示控制器驱动
- kernel-module-vsp —— VSP视频处理驱动
- libdrm-rcar —— DRM/KMS用户态库
- mesa-pvr —— PowerVR GPU的用户态驱动
- wayland/weston —— 显示合成器(如果你用Wayland)
你可以用 bitbake -s | grep rcar 来列出所有R-Car相关的包。嗯,这里要注意:有些包名可能带版本号后缀,比如 libdrm-rcar-2.4.100,别搞混了。
快速验证: 系统启动后,执行 ls /dev/dri/。如果看到 card0 和 controlD64,说明DRM驱动加载成功。再执行 modetest,如果能显示输出信息,恭喜你,图形显示子系统已经跑起来了。
1.5 第一个测试:点亮屏幕
环境搭好了,咱们来点个灯。写一个最简单的DRM程序,在屏幕上显示纯色:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <drm/drm.h>
#include <drm/drm_mode.h>
int main() {
int fd = open("/dev/dri/card0", O_RDWR);
if (fd < 0) {
perror("open card0 failed");
return -1;
}
// 获取资源
drmModeRes *res = drmModeGetResources(fd);
if (!res) {
perror("get resources failed");
close(fd);
return -1;
}
printf("Connectors: %d, Encoders: %d, CRTCs: %d\n",
res->count_connectors, res->count_encoders, res->count_crtcs);
drmModeFreeResources(res);
close(fd);
return 0;
}
编译命令:
arm-linux-gnueabihf-gcc -o drm_test drm_test.c -ldrm
把这个程序放到开发板上运行。如果输出类似 Connectors: 2, Encoders: 2, CRTCs: 3,说明你的DRM接口已经打通了。
小技巧: 如果 modetest 没有输出,先检查 dmesg | grep du 和 dmesg | grep vsp。我遇到过好几次,驱动加载成功了但显示没输出,最后发现是设备树里DU的时钟频率写错了。