RGB 屏幕
LuckFox Pico Ultra 和 LuckFox Pico Ultra W 现在支持RGB
屏幕,采用并行的RGB LCD
接口。图像数据以RGB666
格式传输,每个像素占用 6 位。目前只适配 720x720
和 480x480
分辨率。提供的镜像默认支持 720x720
分辨率。如果用户使用的是 480x480
分辨率的屏幕,可以在开发板开机后,按一下开发板的 BOOT按键进行分辨率切换。为了帮助大家的理解工作原理,本节会从应用层到驱动层进行介绍,由于屏幕种类繁多,其它分辨率屏幕适配还需要自行研究。
兼容平台
型号 | 操作系统 | LF40-720720-ARK | LF40-480480-ARK |
---|---|---|---|
Luckfox Pico Ultra | Buildroot/Ubuntu | 支持 | 支持 |
Luckfox Pico Ultra W | Buildroot/Ubuntu | 支持 | 支持 |
注意:当前开发板Ubuntu22.04
和buildroot
系统都适配了屏幕的驱动,但是lvgl
示例程序当前仅支持buildroot
系统。
1. 示例程序
LVGL示例程序源码获取(在虚拟机或者Ubuntu主机上进行)。
git clone https://github.com/luckfox-eng29/luckfox_lvgl.git
交叉编译示例程序。
# 编译环境:WSL2 Ubuntu 22.02
mkdir build
cd build
export LUCKFOX_SDK_PATH=<Luckfox Pico SDK 的绝对地址>
cmake ..
make -j- 最终编译生成的可执行文件:
luckfox_lvgl_demo
- 最终编译生成的可执行文件:
硬件连接
- Luckfox Pico Ultra:如果接入 LP40-720720-ARK 需要检查以下位置是否有焊接电阻,如果有,需将其拆除。LP40-480480-ARK 不需要检查此电阻是否有焊接。(从2024年7月5日之后发货的版本,此位置的电阻默认将不焊接)
- 屏幕未连接FFC线,具体连接步骤如下:
①将转接板处的黑色卡扣向上撬起。
②将FFC排线的金属面朝下插入转接板。
③锁住卡扣。
注意:屏幕不能正常显示(例如出现波纹),检查FFC线连接是否良好,可能需要重新插拔以确保接触良好。 - 屏幕:Luckfox Pico Ultra 按图示接入屏幕
注意: 接入屏幕时请断电操作,在上电前请再次检查是否接入正常,错误的连接会导致屏幕或者 Luckfox Pico Ultra 损坏。
天线:LVGL 的示例程序可以进行 WIFI 连接(仅限 Luckfox Pico Ultra W),需要接入WIFI天线才能正常使用。
喇叭:LVGL 的示例程序可以进行音乐播放,需要接入喇叭才能正常播放。
可执行文件的上传运行
- Luckfox Pico Ultra:如果接入 LP40-720720-ARK 需要检查以下位置是否有焊接电阻,如果有,需将其拆除。LP40-480480-ARK 不需要检查此电阻是否有焊接。(从2024年7月5日之后发货的版本,此位置的电阻默认将不焊接)
使用
adb
或者scp
命令将文件上传到 Luckfox Pico Ultra 上,如果需要播放音乐请将准备播放的.mp3
音频文件统一放置到/music
文件夹中(如果没有该文件夹使用 mkdir 命令创建,缺少文件夹或者文件夹中没有.mp3
文件都无法正常运行音乐播放功能)。由于开机默认运行的RKIPC
程序会占用音频的使用,需要进行强制关闭后才可以执行测试程序。RkLunch-stop.sh
chmod a+x ./luckfox_lvgl_demo
./luckfox_lvgl_demo- Luckfox Pico Ultra LVGL 示例程序主界面。
- Luckfox Pico Ultra LVGL 示例程序主界面。
2. MIPI DPI 接口
RGB 接口也被称为 DPI(Display Pixel Interface) 接口,采用普通的同步、时钟、信号线来传输特定数据,采用 IIC 等控制线完成命令控制,DPI接口信号线:
- DPIVSYNC (Vertical Sync): 垂直同步信号,用于指示一帧图像的开始。
- DPIHSYNC (Horizontal Sync): 水平同步信号,用于指示一行像素的开始。
- DPIDE (Data Enable): 数据有效信号,用于指示当前传输的数据是有效的像素数据。
- DPICK (Clock): 像素时钟信号,用于同步数据传输。
- 数据线: 多条并行数据线(如DPI_DATA0, DPI_DATA1, ...),用于传输像素数据。
3. Rockchip 平台显示子系统(DSS)
显示子系统是Rockchip
平台显示输出相关软硬件系统的统称,linux
内核采用component
框架来构建显示子系统,一个显示子系统由显示处理器(vop
,video output processor
)、接口控制器(mipi
,lvds
,hdmi
、edp
、dp
、rgb
、BT1120
、BT656
、I8080
(MCU
显示接口)等)、液晶背光,电源等多个独立的功能模块构成。将在内存中的图像数据,转化为电信号送到显示设备称为显示控制器,比如早期的LCDC
;后面进行了拓展,可以处理一些简单的图像,比如缩放、旋转、合成等,如瑞芯微的vop
和博通的VideoCore
都称为显示处理器。RV1106 采用的VOP1.0 ,整个显示系统的硬件框架如下图所示:
4. FBDEV 介绍
Linux 内核中常用的两类图形显示设备驱动框架分别是 DRM(Direct Rendering Manager)和 FBDEV(Framebuffer Device)。在 Framebuffer 驱动框架下,用户可以通过 /dev/fbX
接口直接操作显示设备的显存,进行标准文件操作(如 read
, write
, ioctl
)。用户空间程序可以通过这些设备节点和 ioctl
调用来控制帧缓冲设备。Framebuffer 提供基本的 2D 图形操作,如点、线、矩形的绘制,支持多种像素格式和分辨率。缺点是它不支持现代图形硬件的高级功能,如硬件加速和 3D 渲染。
5. DRM 介绍
DRM 全称是 Direct Rendering Manager,进行显示输出管理、buffer 分配、帧缓冲。对应的 userspace 库为 libdrm,libdrm 库提供 了一系列友好的控制封装,使用户可以方便的进行显示的控制和 buffer 申请。DRM 的设备节点为 "/dev/dri/cardX", X 为 0-15 的数 值,默认使用的是 /dev/dri/card0。 Rockchip 平台从 Linux 4.4 内核开始,显示驱动全部切到 DRM 显示框架。
5.1 DRM 与 framebuffer 的区别
下图是 FBDEV 和 DRM 连接到设备端最终显示过程对比:
6. DRM 基本概念
为了方便管理显示通路上的各种硬件模块,DRM 定义了以下几个概念:
基本概念 | 说明 |
---|---|
CRTC | 显示控制器;RGB timing的产生,以及显示数据的更新,都需要访问Dislay Controller硬件寄存器,因此放在Display Controller驱动中 在Rockchip平台里对应SoC内部的vop模块 |
Plane | 图层,在 rockchip 平台是 SOC 内部 VOP(LCDC)模块 win 图层的抽象 |
Encoder | 输出转换器,指 RGB、LVDS、DSI、eDP、DP、HDMI、CVBS、VGA 等显示接口 |
Connector | 连接器,指 encoder 和 panel 之间交互的接口部分 |
Bridge | 桥接设备,一般用于注册 encoder 后面另外再接的转换芯片,如 DSI2HDMI 转换芯片 |
Panel | 泛指屏,各种 LCD 显示设备的抽象 |
GEM | DRM 下 buffer 管理和分配,类似 ION、DMA BUFFER |
7. DRM 框架介绍
DRM 驱动和 libdrm 的交互过程:
7.1 Libdrm
在 DRM 框架中,libdrm(Direct Rendering Manager library)是一个用户空间库。,提供了DRM
驱动的用户空间接口;对底层接口进行封装,向上层应用程序提供通用的API
接口,本质上是对各种ioctl
接口进行封装。
7.2 KMS
KMS(Kernel Mode Setting)使内核直接管理显示模式和分辨率,提高了系统的稳定性和性能。KMS 包含 CRTC(Cathode Ray Tube Controller),用于控制显示扫描;Plane,用于管理图形数据层;Encoder,将图形数据转换为适当的输出信号;以及 Connector,连接显示设备,如显示器或电视。
7.3 GEM
GEM(Graphics Execution Manager)负责显存的分配和管理,提供高效的显存操作机制。它与 DRM 的其他组件,如 Plane、CRTC 和 Panel 协同工作,以确保图形数据在显存中的高效传输和渲染,支持硬件加速和现代图形硬件的高级功能。
7.4 drm_panel
drm_panel
是 DRM(Direct Rendering Manager)框架中的一个重要概念,尽管它不像 drm_crtc
、drm_connector
、drm_plane
等直接被认为是对象,但它的存在降低了LCD
驱动与encoder
驱动之间的耦合度。drm_panel
它是一堆回调函数的集合,这些回调函数允许显示驱动程序和其他部分(如 encoder 驱动程序)与显示面板进行交互。
8. 驱动模块路径
linux
内核将DRM
驱动相关的代码都放在drivers/gpu/drm
目录下,驱动部分内容作为了解即可。
驱动 | 文件位置 |
---|---|
core | drivers/gpu/drm/rockchip/rockchip_drm_drv.c |
framebuffer | drivers/gpu/drm/rockchip/rockchip_drm_fb.c |
vop | drivers/gpu/drm/rockchip/rockchip_drm_vop.c drivers/gpu/drm/rockchip/rockchip_vop_reg.c drivers/gpu/drm/rockchip/rockchip_drm_vop2.c<br/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c |
rgb | drivers/gpu/drm/rockchip/rockchip_rgb.c |
panel | drivers/gpu/drm/panel/panel-simple.c |
drivers/gpu/drm/drm_panel.c |
9. DRM 驱动入口
平台驱动(Platform Driver) 和设备的匹配,这里是直接比较驱动和设备的字段,看看是否相同。通过
compatible
属性,内核会将simple-panel
驱动与设备树中的panel
节点进行匹配。static struct platform_driver panel_simple_platform_driver = {
.driver = {
.name = "panel-simple",
.of_match_table = platform_of_match,
},
.probe = panel_simple_platform_probe,
.remove = panel_simple_platform_remove,
.shutdown = panel_simple_platform_shutdown,
};驱动的
probe
函数会检查display-timings
节点,并解析其中的时序参数。根据解析得到的时序参数,驱动会配置显示控制器,以确保面板能够正确显示。static int panel_simple_of_get_desc_data(struct device *dev,
struct panel_desc *desc)
{
struct device_node *np = dev->of_node;
u32 bus_flags;
const void *data;
int len;
int err;
if (of_child_node_is_present(np, "display-timings")) {
struct drm_display_mode *mode;
mode = devm_kzalloc(dev, sizeof(*mode), GFP_KERNEL);
if (!mode)
return -ENOMEM;
if (!of_get_drm_display_mode(np, mode, &bus_flags,
OF_USE_NATIVE_MODE)) {
desc->modes = mode;
desc->num_modes = 1;
desc->bus_flags = bus_flags;
}设备树中定义的面板节点会被
panel-simple
驱动探测到,panel_simple_platform_probe
函数会读取设备树中的面板描述信息,并通过panel_simple_probe
函数进行面板初始化和注册。static int panel_simple_platform_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
const struct of_device_id *id;
const struct panel_desc *desc;
struct panel_desc *d;
int err;
id = of_match_node(platform_of_match, pdev->dev.of_node);
if (!id)
return -ENODEV;
if (!id->data) {
d = devm_kzalloc(dev, sizeof(*d), GFP_KERNEL);
if (!d)
return -ENOMEM;
err = panel_simple_of_get_desc_data(dev, d);
if (err) {
dev_err(dev, "failed to get desc data: %d\n", err);
return err;
}
}
desc = id->data ? id->data : d;
return panel_simple_probe(&pdev->dev, desc);
}注册过程中,
drm_panel_init
和drm_panel_add
函数会将面板初始化并注册到 DRM 框架中,使其成为 DRM 子系统的一部分,供其他 DRM 组件使用。void drm_panel_init(struct drm_panel *panel, struct device *dev,
const struct drm_panel_funcs *funcs, int connector_type)
{
INIT_LIST_HEAD(&panel->list);
panel->dev = dev;
panel->funcs = funcs;
panel->connector_type = connector_type;
}
EXPORT_SYMBOL(drm_panel_init);
/**
* drm_panel_add - add a panel to the global registry
* @panel: panel to add
*
* Add a panel to the global registry so that it can be looked up by display
* drivers.
*/
void drm_panel_add(struct drm_panel *panel)
{
mutex_lock(&panel_lock);
list_add_tail(&panel->list, &panel_list);
mutex_unlock(&panel_lock);
}
EXPORT_SYMBOL(drm_panel_add);DRM 驱动模块入口函数为
rockchip_drm_init
,位于drivers/gpu/drm/rockchip/rockchip_drm_drv.c
:#define ADD_ROCKCHIP_SUB_DRIVER(drv, cond) { \
if (IS_ENABLED(cond) && \
!WARN_ON(num_rockchip_sub_drivers >= MAX_ROCKCHIP_SUB_DRIVERS)) \
rockchip_sub_drivers[num_rockchip_sub_drivers++] = &drv; \
}
static int __init rockchip_drm_init(void)
{
int ret;
num_rockchip_sub_drivers = 0;
#if IS_ENABLED(CONFIG_DRM_ROCKCHIP_VVOP)
ADD_ROCKCHIP_SUB_DRIVER(vvop_platform_driver, CONFIG_DRM_ROCKCHIP_VVOP);
#else
ADD_ROCKCHIP_SUB_DRIVER(vop_platform_driver, CONFIG_ROCKCHIP_VOP);
...
ADD_ROCKCHIP_SUB_DRIVER(rockchip_rgb_driver, CONFIG_ROCKCHIP_RGB);
...
#endif
ret = platform_register_drivers(rockchip_sub_drivers,
num_rockchip_sub_drivers);
if (ret)
return ret;
ret = platform_driver_register(&rockchip_drm_platform_driver);
if (ret)
goto err_unreg_drivers;
rockchip_gem_get_ddr_info();
return 0;
err_unreg_drivers:
platform_unregister_drivers(rockchip_sub_drivers,
num_rockchip_sub_drivers);
return ret;
}- 在前面的内核配置中我们已经打开
CONFIG_ROCKCHIP_VOP
和CONFIG_ROCKCHIP_RGB
,所以此步将vop_platform_driver
和rockchip_rgb_driver
驱动添加到数组rockchip_sub_drivers
中 - 通过
platform_register_drivers
注册多个驱动和注册rockchip_drm_platform_driver
- 在前面的内核配置中我们已经打开
平台驱动(Platform Driver) 和设备的匹配,这里是直接比较驱动和设备的字段,看看是否相同。
rockchip-drm
平台驱动rockchip-drm
是一个针对 Rockchip 芯片的 DRM 驱动,它主要用于管理和控制显示子系统。static struct platform_driver rockchip_drm_platform_driver = {
.probe = rockchip_drm_platform_probe,
.remove = rockchip_drm_platform_remove,
.shutdown = rockchip_drm_platform_shutdown,
.driver = {
.name = "rockchip-drm", //此字段为device和driver匹配的最后一种方式
.of_match_table = rockchip_drm_dt_ids,
.pm = &rockchip_drm_pm_ops,
},
};of_match_table
用于设备树匹配,匹配设备树中compatible = "rockchip,display-subsystem"
的设备节点:static const struct of_device_id rockchip_drm_dt_ids[] = {
{ .compatible = "rockchip,display-subsystem", },
{ /* sentinel */ },
};在第二步内核中有
platform
设备和platform
驱动匹配,会调用到platform_driver
里的成员.probe
,在这里就是rockchip_drm_platform_probe
函数:static int rockchip_drm_platform_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct component_match *match = NULL;
int ret;
ret = rockchip_drm_platform_of_probe(dev);
#if !IS_ENABLED(CONFIG_DRM_ROCKCHIP_VVOP)
if (ret)
return ret;
#endif
match = rockchip_drm_match_add(dev);
if (IS_ERR(match))
return PTR_ERR(match);
ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(64));
if (ret)
goto err;
ret = component_master_add_with_match(dev, &rockchip_drm_ops, match);
if (ret < 0)
goto err;
return 0;
err:
rockchip_drm_match_remove(dev);
return ret;
}ret = rockchip_drm_platform_of_probe(dev);
: 校验display-subsystem设备节点的属性ports是否有效match = rockchip_drm_match_add(dev);
:构建一个带release函数的component_matchret = component_master_add_with_match(dev, &rockchip_drm_ops, match);
:向系统注册一个aggregate_device,触发执行rockchip_drm_ops.bind,即rockchip_drm_bind,该函数用于绑定设备并初始化DRM
驱动
总结:
- 设备树匹配:设备树中定义的面板节点通过设备树匹配机制与
panel-simple
驱动关联。内核启动时,rockchip-drm
平台驱动也会匹配设备树节点。驱动查找并解析设备树中的ports
和iommus
节点,以获取显示管道和内存管理单元的信息。 - 面板驱动初始化:
panel_simple_platform_probe
函数读取设备树中的面板描述信息,并通过panel_simple_probe
函数进行面板初始化和注册。在此过程中,调用drm_panel_init
和drm_panel_add
函数将面板初始化并注册到 DRM 框架中,使其成为 DRM 子系统的一部分,供其他 DRM 组件使用。 - 注册组件:
rockchip-drm
使用component_master_add_with_match
函数将其注册到组件框架中。通过设置rockchip_drm_ops
,定义了bind
和unbind
操作,这些操作将在组件初始化和注销时调用。 - 添加子组件:各个子组件(例如 VOP、HDMI、MIPI DSI 等)使用
component_add
函数添加到组件框架中。每个子组件都有对应的component_ops
结构体,定义其自身的bind
和unbind
操作。 - 绑定组件:当 master 组件(即
rockchip-drm
)匹配到所有子组件后,会调用其bind
回调函数。在bind
回调函数中,执行各个子组件的初始化和配置。 - 注册到 DRM 核心:
rockchip-drm
驱动在内核模块加载时通过drm_dev_register
函数注册 DRM 设备。在此过程中,drm_dev_register
会调用drm_minor_register
注册字符设备。drm_minor_register
函数负责创建字符设备并添加到/dev/dri
目录下,最终创建设备节点,如/dev/dri/card0
。
想了解更多具体内容,需自己进入源码目录(drivers/gpu/drm
)阅读理解。
10. RGB 屏幕系统配置
10.1 内核配置
Luckfox Pico Ultra 驱动 RGB 需要在内核设置中打开 VOP 驱动支持和 RGB 驱动支持(默认打开)。
在 luckfox-pico SDk 根目录下打开 kernel 的 menuconfig 配置页面。
# Buildroot 系统
./build.sh kernelconfig
# Ubuntu 系统
sudo ./build.sh kernelconfig输入 “/” 搜索
CONFIG_DRM_ROCKCHIP
选择第一项。配置 DRM Support for Rockchip ,输入 “y” 打开
Rockchip VOP driver
和Rockchip RGB support
。Device Drivers --->
Graphics support --->
<*> Direct Rendering Manager (XFree86 4.1.0 and higher DRI support) --->
<*> DRM Support for Rockchip (DRM_ROCKCHIP [=y])
[ ] Support 3D cubic LUT
[ ] Rockchip DRM debug
[ ] Rockchip DRM direct show
[*] Rockchip VOP driver
[ ] Rockchip VOP2 driver
[ ] Rockchip specific extensions for Analogix DP driver
[ ] Rockchip cdn DP
[ ] Rockchip TVE support
[ ] Rockchip specific extensions for Synopsys DW HDMI
[ ] Rockchip specific extensions for Synopsys DW MIPI DSI
[ ] Rockchip specific extensions for Synopsys DW DPTX
[ ] Rockchip specific extensions for Innosilicon HDMI
[ ] Rockchip LVDS support
[*] Rockchip RGB support
[ ] Rockchip specific extensions for RK3066 HDMI
[ ] Rockchip Virtual connector driver for HDMI/DP/DSI
[ ] Rockchip virtual VOP drm driver< > Synopsis Designware HDCP2 interface
在 luckfox-pico Sdk 根目录下执行命令编译生成
boot.img
。# Buildroot 系统
./build.sh kernel
# Ubuntu 系统
sudo ./build.sh kernel注意: 建议在修改好 RGB 屏幕和电容触摸屏的设备树后再编译烧录
boot.img
。
10.2 设备树设置
RGB 和 VOP 配置
在 Luckfox Pico Ultra 上与 RGB 显示的相关设备树设置已经在
<Luckfox Pico Sdk Path>/sysdrv/source/kernel/arch/arm/boot/dts/rv1106-luckfox-pico-ultra-ipc.dtsi
中默认打开。&display_subsystem {
status = "okay";
logo-memory-region = <&drm_logo>;
};
&rgb {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&lcd_pins>;
ports {
rgb_out: port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
rgb_out_panel: endpoint@0 {
reg = <0>;
remote-endpoint = <&panel_in_rgb>;
};
};
};
};
&rgb_in_vop {
status = "okay";
};
&route_rgb {
status = "okay";
};
&vop {
status = "okay";
};注意: 如果需要取消 RGB 屏幕的使用,可以将
&rgb
节点的 status 修改为 “disabled”,防止打算使用的外设引脚被复用为 lcd 引脚。在使能 RGB 屏幕时,请不要将相关引脚复用为其它功能或接入其它外设。CMA 配置
使用
LF40-720720-ARK
时由于默认分配的 CMA 大小不够,需要额外申请10MB
内存作为 CMA 才能正常显示图像。CMA 是从内存中申请的,会导致可使用的内存大小减少,在不需要使用LF40-720720-ARK
时可以将<luckfox-pico SDK>/ sysdrv/source/kernel/arch/arm/boot/dts/rv1106-luckfox-pico-ultra-ipc.dtsi
下的reserved-memory/linux,cma
节点注释掉,释放内存资源。reserved-memory {
#address-cells = <1>;
#size-cells = <1>;
ranges;
drm_logo: drm-logo@00000000 {
compatible = "rockchip,drm-logo";
reg = <0x0 0x0>;
};
//linux,cma {
// compatible = "shared-dma-pool";
// inactive;
// reusable;
// size = <0xA00000>;
// linux,cma-default;
//};
};panel 配置 除了默认的设备树配置,需要额外配置主要是屏幕的 panel 节点。
在最新的 luckfox-pico SDK 中,最上层的
dts
文件已经软链接到 luckfox-pico SDK 根目录下的config/dts_config
中,只需要对其进行修改就能覆盖dtsi
中的设置,根据型号在config/dts_config
中添加相应内容就可以完成设备树的配置。
LF40-720720-ARK
设备树配置/**********RGB**********/
&panel {
status = "okay";
reset {
status = "okay";
};
enable {
status = "disabled";
};
display-timings {
timing0: timing0 {
clock-frequency = <30000000>;
hactive = <720>;
vactive = <720>;
hback-porch = <44>;
hfront-porch = <46>;
vback-porch = <18>;
vfront-porch = <16>;
hsync-len = <2>;
vsync-len = <2>;
hsync-active = <0>;
vsync-active = <0>;
de-active = <0>;
pixelclk-active = <0>;
};
};
};LF40-480480-ARK
设备树配置/**********RGB**********/
&panel {
status = "okay";
reset {
status = "okay";
};
enable {
status = "disabled";
};
display-timings {
timing0: timing0 {
clock-frequency = <16500000>;
hactive = <480>;
vactive = <480>;
hback-porch = <10>;
hfront-porch = <50>;
vback-porch = <8>;
vfront-porch = <8>;
hsync-len = <4>;
vsync-len = <10>;
hsync-active = <0>;
vsync-active = <0>;
de-active = <0>;
pixelclk-active = <1>;
};
};
};
10.2 DRM 测试
RGB 屏幕可以使用 Framebuffer 框架或 DRM 框架进行控制。使用 buildroot 系统自带的 modetest 工具可以获取 DRM 的 Connectors ID
和 CRTCS ID
用于显示测试。
Luckfox Pico Ultra 使用 Ubuntu 系统需要安装 modetest 工具(buildroot系统默认已安装)
# 确保 Luckfox Pico Ultra 成功连接网络
sudo apt-get update
sudo apt-get install libdrm-dev
sudo apt-get install libdrm-testsmodetest 获取
Connector ID
modetest 获取
CRTCS ID
执行测试程序显示色块
modetest -M rockchip -s <Connector ID>@<CRTCS ID>:<显示分辨率>
示例:
LF40-480480-ARK
modetest -M rockchip -s 70@66:720x720
LF40-720720-ARK
modetest -M rockchip -s 70@66:480x480
11. 电容触摸屏系统配置
LF40-720720-ARK
和 LF40-480480-ARK
都贴合了GT911电容触摸屏,使用 I2C 进行控制。
11.1 内核配置
Luckfox Pico Ultra 在控制触摸屏时会将 I2C 连接的 GT911 触摸屏设置为 input 设备,需要在内核中打开对应的驱动。
在 luckfox-pico Sdk 根目录下执行命令进入 kernel 的 menuconfig 界面。
# Buildroot 系统
./build.sh kernelconfig
# Ubuntu 系统
sudo ./build.sh kernelconfig使用 “/” 进行搜索, 搜索
TOUCHSCREEN_GOODIX
选择第一项选中
Goodix I2C touchscreen
按下 “y” 键选中后保存退出在 luckfox-pico Sdk 根目录下执行命令编译生成
boot.img
。# Buildroot 系统
./build.sh kernel
# Ubuntu 系统
sudo ./build.sh kernel注意: 建议在修改好 RGB 屏幕和电容触摸屏的设备树后再编译烧录
boot.img
。
11.2 设备树设置
GT911 触摸会根据上电时序配置不同的 I2C 地址,驱动加载成功后会与 GT911 通讯获取到电容触摸屏的分辨率数据,所以 LF40-720720-ARK
和 LF40-480480-ARK
的设备树配置一致。
GT911 设备树配置
/**********TouchScreen**********/
&i2c3 {
status="okay";
clock-frequency = <100000>;
pinctrl-names = "default";
pinctrl-0 = <&i2c3m2_xfer &tp_rst &tp_irq>;
GT911:touchscreen {
compatible = "goodix,gt911";
reg = <0x14>;
interrupt-parent = <&gpio0>;
interrupts = <RK_PA3 IRQ_TYPE_EDGE_FALLING>;
reset-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>;
};
};
&pinctrl {
Touchscreen{
tp_rst:tp-rst {
rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>;
};
tp_irq:tp-irq {
rockchip,pins = <0 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
};注意: GT911 触摸屏会占用
I2C3M2
,请确保 I2C3 的其它组没有被使用。
11.3 触摸屏测试
11.3.1 i2c 测试
如果上电时序正确,那么 GT911 触摸屏会在 I2C3 的 0x14
地址上被识别到,GT911 的驱动会占用该地址。
使用 i2cdetect 命令查看 I2C3 的设备挂载情况。
i2cdetect -y 3
可以观察到 I2C3 的
0x14
地址会被标记 "UU"。注意: 如果 I2C3 的
0x14
地址没有被识别到,可能是上电时序错误或接触不良,需要检查 FPC 软排线是否安装稳定。
11.3.2 hexdump 测试
GT911 触摸屏驱动在加载过程中会在 /dev/input 下创建 event 节点用于传递触摸信息,在 Luckfox Pico Ultra 上没有添加其它 input 设备的话, GT911 触摸屏对应节点通常是 /dev/input/event0
。
Luckfox Pico Ultra 使用 ubuntu 系统需要安装 hexdump 工具(buildroot系统默认已安装)
# 确保 Luckfox Pico Ultra 成功连接网络
sudo apt-get update
sudo apt-get install bsdmainutils使用 hexdump 命令获取 GT911 传输信息。
hexdump /dev/input/event0
用手指触摸屏幕触发中断,此时打印的信息是 GT911 传递到 input 子系统的初始信息,需要通过整理才能获取到实际的坐标值。
注意: Luckfox Pico Ultra 上的 adc-key (对应 BOOT 按键) 也被注册为 event 节点,如果 GT911 触摸屏驱动没有成功加载, 那么
/dev/input/event0
节点对应的是 adc-key ; 如果有其它 input 设备的加载顺序较早,那么 GT911 触摸屏可能被加载到/dev/input/event1
或其它节点上。
11.3.3 evtest 测试
如果需要观察触摸实际坐标数据和 input 设备更详细的信息可以通过在 buildroot 中添加 evtest 工具来进行测试,方便在有多个 input 设备时进行区分。
Luckfox Pico Ultra 系统自带 evtest 工具,可以跳过 2 ~ 6 步。
在 luckfox-pico SDK 根目录下执行命令进入 buildroot 的 menuconfig 界面。
./build.sh buildrootconfig
使用 “/” 进行搜索, 搜索
BR2_PACKAGE_EVTEST
选择第一项使用 “y” 将
evtest
打开后保存退出。执行命令重新编译生成
rootfs.img
。# Buildroot 系统
./build.sh rootfs
./build.sh firmware将新生成的
rootfs.img
烧写入 Luckfox Pico Ultra 中就可以使用 evtest 来测试 input 设备。其中的
Goodix Capacitive TouchScreen
对应的就是 GT911 触摸屏,选中 0 回车就可以看到 GT911 触摸屏设备的相关信息,触摸屏幕就可以观察到触发的事件信息和坐标数据( ABS_X 和 ABS_Y )。