使用正点原子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 文件夹下,文件目录如下:
shell
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

编译
shell
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函数里添加打印,输出当前坐标位置,检测是否检测到触摸。
c
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 ;
}
从打印信息里观察到:
shell
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,然后重新编译内核,可以解决此问题,然而这里修改后并未解决。
c
#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_SYN |
0x00 | 同步事件------用来打包一组数据,本身无意义 | SYN_REPORT |
EV_KEY |
0x01 | 按键/开关------键盘、鼠标键、触摸按下/释放 | BTN_TOUCH, KEY_ENTER |
EV_REL |
0x02 | 相对坐标------鼠标、轨迹球 | REL_X, REL_Y, REL_WHEEL |
EV_ABS |
0x03 | 绝对坐标------触摸屏、游戏摇杆 | ABS_X, ABS_Y, ABS_MT_POSITION_X |
EV_MSC |
0x04 | 杂项------无标准含义,驱动私有 | MSC_SCAN, MSC_SERIAL |
EV_SW |
0x05 | 开关------物理滑盖、耳机插入 | SW_LID, SW_HEADPHONE_INSERT |
所以这里只需要关注EV_ABS下的代码:
c
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。
继续添加打印信息:
c
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 ,所以一直不会把按下的状态置起。
修改代码,再次测试:
c
if(in.value == -1)
evdev_button = LV_INDEV_STATE_REL;
else /*if(in.value == 0)*/
evdev_button = LV_INDEV_STATE_PR;
果然,一切正常了,可以愉快的触摸了。

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