TechBlog
首页分类标签搜索关于

© 2025 TechBlog. All rights reserved.

正点原子imx6ull移植lvgl-v8.3及触摸屏调试

11/22/2025
未分类#驱动开发#触摸屏#Lvgl#Linux#Imx

正点原子imx6ull移植lvgl v8.3及触摸屏调试

使用正点原子imx6ull移植lvgl 8.3及触摸屏调试过程。

硬件

  • 开发板:ALPHA I.MX6ULL
  • 屏幕:ALIENTEK 7’ RGB TFTLCD 1024*600

软件

已烧录带framebuffer的zImage(cat /dev/fb0可以打开)
如果带触摸,需要确认已存在触摸节点(ls /dev/input/event*),使用hexdump /dev/input/event*可以检测到触摸

lvgl源码下载、修改、编译

  • 创建文件夹mkdir lvgl_imx6ull && cd lvgl_imx6ull
  • 克隆源代码
git clone -b release/v8.3 https://github.com/lvgl/lv_port_linux_frame_buffer.git
git clone -b release/v8.3 https://github.com/lvgl/lvgl.git
git clone -b release/v8.3 https://github.com/lvgl/lv_drivers.git

将lvgl、lv_drivers文件夹复制到lv_port_frame_buffer 文件夹下,文件目录如下:

lv_port_linux_frame_buffer$ tree -L 1
├── LICENSE
├── lv_conf.h
├── lv_drivers
├── lv_drv_conf.h
├── lvgl
├── main.c
├── Makefile
├── mouse_cursor_icon.c
└── README.md

修改Makefile

修改工具链:CC = arm-linux-gnueabihf-gcc
由于驱动教程安装的工具链版本较低,所以后续编译会报错,这里直接为了解决编译错误,直接修改Makefile的CFLAGS:

  • 添加-std=gnu99
  • 删除编译选项-Wshift-negative-value

修改lv_drv_conf.h

1. USE_FBDEV

在这里插入图片描述

2. USE_EVDEV

在这里插入图片描述

修改lv_conf.h

1. LV_MEM_CUSTOM

在这里插入图片描述

2. 可选

在这里插入图片描述

修改main.c

在这里插入图片描述

编译

lvgl_imx/lv_port_linux_frame_buffer$ make -j16

编译完后生成可执行文件demo,拷贝至开发板后使用./demo运行即可。

运行效果

在这里插入图片描述

触摸调试

这里是使用的Linux内核自带的驱动,edt-ft5x06.c也是使用的正点原子修改过的,理论上不需要再次修改。
使用hexdump /dev/input/event1命令可以确认触摸硬件及驱动都是正常工作的。

evdev_read

在main.c已经注册了输入的回调函数,调试的第一步选择在evdev_read函数里添加打印,输出当前坐标位置,检测是否检测到触摸。

void evdev_read(lv_indev_drv_t * drv, lv_indev_data_t * data)
{
	  ...
	  
	data->state = evdev_button;
	printf("state = %d\n", evdev_button);
	
	if(data->point.x < 0)
	  data->point.x = 0;
	if(data->point.y < 0)
	  data->point.y = 0;
	if(data->point.x >= drv->disp->driver->hor_res)
	  data->point.x = drv->disp->driver->hor_res - 1;
	if(data->point.y >= drv->disp->driver->ver_res)
	  data->point.y = drv->disp->driver->ver_res - 1;
	  
	printf("point.x = %d, point.y = %d\n", data->point.x, data->point.y);
	
	return ;
}

从打印信息里观察到:

state = 0
point.x = 930, point.y = 61
state = 0
point.x = 930, point.y = 61
state = 0
point.x = 930, point.y = 61
...
state = 0
point.x = 593, point.y = 28
state = 0
point.x = 593, point.y = 28
state = 0
point.x = 593, point.y = 28

按下的状态一直为0,但是实际坐标是实时更新的,所以还是这个data->state的问题。

修改驱动文件MAX_SUPPORT_POINTS

看到其他博客中有提到这款屏幕只支持单点触摸,可以把此宏修改为1,然后重新编译内核,可以解决此问题,然而这里修改后并未解决。

#define MAX_SUPPORT_POINTS		1			/* 5点触摸 	*/

此时有些无语了,搞了大半天了。。。

继续跟踪evdev_read

data->state一直为0,说明问题还是出在evdev_read前面的代码里,未满足条件,所以未进行赋值,data->state一直未得到更新。
in.type 是 input 子系统 的事件大类,定义在 <linux/input-event-codes.h>。
常见 6 种(全部枚举不足 10 种):

宏数值含义典型事件码
EV_SYN0x00同步事件——用来打包一组数据,本身无意义SYN_REPORT
EV_KEY0x01按键/开关——键盘、鼠标键、触摸按下/释放BTN_TOUCH, KEY_ENTER
EV_REL0x02相对坐标——鼠标、轨迹球REL_X, REL_Y, REL_WHEEL
EV_ABS0x03绝对坐标——触摸屏、游戏摇杆ABS_X, ABS_Y, ABS_MT_POSITION_X
EV_MSC0x04杂项——无标准含义,驱动私有MSC_SCAN, MSC_SERIAL
EV_SW0x05开关——物理滑盖、耳机插入SW_LID, SW_HEADPHONE_INSERT

所以这里只需要关注EV_ABS下的代码:

void evdev_read(lv_indev_drv_t * drv, lv_indev_data_t * data)
{
    struct input_event in;
    
    while(read(evdev_fd, &in, sizeof(struct input_event)) > 0) {
        printf("read evdev_fd, in.type = %d, in.code = %d\n", in.type, in.code);
        if(in.type == EV_REL) {
			...
        } else if(in.type == EV_ABS) {
            if(in.code == ABS_X)
				#if EVDEV_SWAP_AXES
					evdev_root_y = in.value;
				#else
					evdev_root_x = in.value;
				#endif
            else if(in.code == ABS_Y)
				#if EVDEV_SWAP_AXES
					evdev_root_x = in.value;
				#else
					evdev_root_y = in.value;
				#endif
            else if(in.code == ABS_MT_POSITION_X)
                                #if EVDEV_SWAP_AXES
                                        evdev_root_y = in.value;
                                #else
                                        evdev_root_x = in.value;
                                #endif
            else if(in.code == ABS_MT_POSITION_Y)
                                #if EVDEV_SWAP_AXES
                                        evdev_root_x = in.value;
                                #else
                                        evdev_root_y = in.value;
                                #endif
            else if(in.code == ABS_MT_TRACKING_ID) {
                                if(in.value == -1)
                                    evdev_button = LV_INDEV_STATE_REL;
                                else if(in.value == 0)
                                    evdev_button = LV_INDEV_STATE_PR;
            }
        } else if(in.type == EV_KEY) {
           ...
        }
    }
    ...
}

上述代码里只有in.code==ABS_MT_TRACKING_ID时才会更新evdev_button ,后续再赋值给data->state。
继续添加打印信息:

in.code = ABS_MT_TRACKING_ID
in.value = 132
in.code = ABS_MT_POSITION_X
in.value = 606
in.code = ABS_MT_POSITION_Y
in.value = 21
in.code = ABS_X
in.value = 606
in.code = ABS_Y
in.value = 21
state = 1
point.x = 606, point.y = 21
state = 1
point.x = 606, point.y = 21
state = 1
point.x = 606, point.y = 21
in.code = ABS_MT_TRACKING_ID
in.value = -1

从打印信息中基本可以确认问题所在了。可以看到,in.value的值并不是只有-1和0两种情况,当触摸释放时in.value=-1,但是当按下时会有具体的数值,但不是0 ,所以一直不会把按下的状态置起。
修改代码,再次测试:

 if(in.value == -1)
     evdev_button = LV_INDEV_STATE_REL;
 else /*if(in.value == 0)*/
     evdev_button = LV_INDEV_STATE_PR;

果然,一切正常了,可以愉快的触摸了。
在这里插入图片描述


由于使用的是现成的驱动程序,所以并未从驱动角度深入调试分析,按理说修改驱动应该才是正确方法,但是既然传入的in.value可以是更大范围的数值,那修改lvgl的代码应该也是合理的,如果大家有更好的修改方法也可评论区交流。