【LittlevGL】ARM Linux移植

在前面移植到Ubuntu虚拟机上进行测试过,但是测试程序里面只有显示器驱动,没有输入设备(鼠标、键盘、触摸板)的移植,今天将LittlevGL移植到我的一块Linux板子上去,板子带有一块800*480的屏幕以及电容触摸面板。说不准什么时候可能可以用上,毕竟安卓和QT对系统的性能和资源要求太高,使用LittlevGL这套图形库可能会在某些场景上使用到。

准备使用原来在虚拟机上测试的那套例程进行修改,因为framebuffer的操作都是一样的,直接修改Makefile,将其中的CC改成交叉编译器即可:

CC = /home/tangquan/workspace/docs/Linux-SDK/dragonboard/out/sun8iw5p1/dragonboard/common/buildroot/external-toolchain/bin/arm-linux-gnueabi-gcc

然后直接make编译即可得到开发板上可执行的文件,运行即可,效果和虚拟机上测试是一样的,但是无法触摸。下面进行输入设备的移植工作。

参考文章:https://blog.csdn.net/a694543965/article/details/79935086。

执行命令“cat /proc/bus/input/devices”查看本机的输入设备,找到其中关于触摸屏的信息:

I: Bus=0000 Vendor=0000 Product=0000 Version=0000
N: Name="ft5x_ts"
P: Phys=
S: Sysfs=/devices/virtual/input/input3
U: Uniq=
H: Handlers=ddrfreq_dsm event3 
B: PROP=0
B: EV=b
B: KEY=400 0 0 0 0 0 0 0 0 0 0
B: ABS=2650000 0

信息中的Handlers表示该输入设备的事件处理者,第一个是DDR内存(目的是在点击屏幕的时候调整DDR频率,一段时间不操作则降低DDR频率以节能)。第二个是event3,这个设备在“/dev/input/”中可以看到,我们可以操作event3这个设备来获得触摸屏的输入信息。

在"lv_drivers/indev/"文件夹中创建两个文件touchscreen.c和touchscreen.h,参考并修改参考文章中的内容,得到一个驱动设备:

#include "touchscreen.h"
#include "stdio.h"
#if USE_TOUCHSCREEN

#include 
#include LV_DRV_INDEV_INCLUDE
#include LV_DRV_DELAY_INCLUDE

#include 
#include 
#include 
#include 
#include 
#include 
#include "unistd.h"
#include "pthread.h"
#include 

pthread_t TouchScreenEventHandler_t;
void* TouchScreenEventHandler(void *args);

static bool left_button_down = false;
static int flags = 0;
static int16_t last_x = 0,last_x_tmp = 0;
static int16_t last_y = 0,last_y_tmp = 0;

void ts_init(void)
{
    printf("Initialize touch screen\r\n");
	//int pthread_create(pthread_t * tidp, const pthread_attr_t *attr, void *(*start_rtn)(void *), void *arg);
	pthread_create(&TouchScreenEventHandler_t,NULL,TouchScreenEventHandler,(void*)0);
}

/**
 * Get the current position and state of the touchpad
 * @param data store the read data here
 * @return false: because no ore data to be read
 */
bool ts_read(struct _lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
    /*Store the collected data*/
    data->point.x = last_x;
    data->point.y = last_y;
    data->state = left_button_down ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL;

    return false;
}

/**********************
 *   STATIC FUNCTIONS
 **********************/
void* TouchScreenEventHandler(void *args)
{
	int fd;
	fd_set rds;
	int ret;
	struct input_event event;
	struct timeval time;
    struct input_absinfo absI;

	fd = open( "/dev/input/event3", O_RDONLY );
	if ( fd < 0 )
	{
		perror( "/dev/input/event3" );
		return NULL;
	}

   //得到X轴的abs信息
    ioctl(fd,EVIOCGABS(ABS_X),&absI);
    printf("x abs lastest value=%d\n",absI.value);
    printf("x abs min=%d\n",absI.minimum);
    printf("x abs max=%d\n",absI.maximum);
   //得到y轴的abs信息
    ioctl(fd,EVIOCGABS(ABS_Y),&absI);
    printf("y abs lastest value=%d\n",absI.value);
    printf("y abs min=%d\n",absI.minimum);
    printf("y abs max=%d\n",absI.maximum);
   //得到按压轴的abs信息
    ioctl(fd,EVIOCGABS(ABS_PRESSURE),&absI);
    printf("pressure abs lastest value=%d\n",absI.value);
    printf("pressure abs min=%d\n",absI.minimum);
    printf("pressure abs max=%d\n",absI.maximum);

	while ( 1 )
	{
		FD_ZERO( &rds );
		FD_SET( fd, &rds );
		/*调用select检查是否能够从/dev/input/event0设备读取数据*/
		ret = select( fd + 1, &rds, NULL, NULL, NULL );
		if ( ret < 0 )
		{
			perror( "select" );
			return NULL;
		}
		/*能够读取到数据*/
		else if ( FD_ISSET( fd, &rds ) )
		{
			ret	= read( fd, &event, sizeof(struct input_event) );
			time	= event.time;
			// printf( "timeS=%d,timeUS=%d,type=%d,code=%.2x,value=%d\n", time.tv_sec, time.tv_usec, event.type, event.code, event.value );
			// printf("%d,%d\r\n",event.type,event.code);
			if(event.type == EV_SYN)
			{
				if(event.code == SYN_REPORT)
				{
					if((flags & 0x03) == 0x03)
					{
						flags = 0x00;
						last_x = last_x_tmp;
						last_y = last_y_tmp;
						if(!left_button_down)
						{
							left_button_down = true;
							// printf("key:%d\r\n",left_button_down);
						}
						// printf("%d,%d\r\n",last_x,last_y);
					}
					else
					{
						left_button_down = false;
						// printf("key:%d\r\n",left_button_down);
					}
				}
			}
			else if(event.type == EV_ABS)
			{
				if(event.code == ABS_MT_POSITION_X)
				{
					last_x_tmp = event.value;
					flags |= 0x01;
					// printf("%d,",last_x);
				}
				else if(event.code == ABS_MT_POSITION_Y)
				{
					last_y_tmp = event.value;
					flags |= 0x02;
					// printf("%d\r\n",last_y);
				}
			}
		}
		else
			printf("a");
		//usleep(100000);
	}
	/*关闭设备文件句柄*/
	close( fd );
}

#endif

程序中创建了一个线程TouchScreenEventHandler用于读取触摸屏的数据,这里需要注意Linux系统的input子系统的输入数据的格式,例如这里的触摸屏应用中,一般是先读取到X轴的数据帧,然后再读取到Y轴的数据帧,然后读取到一个Event types为EV_SYN,Event code为SYN_REPORT的帧作为不同组数据间的分割,如果停止触摸,则在收到最后一组触摸数据以及数据间隔之后会再收到一个EV_SYN | SYN_REPORT帧,表示两次触摸事件间的间隔。程序中使用一个flags变量用于处理上诉的这些事件,并通过触摸事件模拟出按键按下的事件。通过全局变量的方式将TouchScreenEventHandler中的数据传出去,LittlevGL内核调用ts_read函数读取设备输入数据:

/**
 * Get the current position and state of the touchpad
 * @param data store the read data here
 * @return false: because no ore data to be read
 */
bool ts_read(struct _lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
    /*Store the collected data*/
    data->point.x = last_x;
    data->point.y = last_y;
    data->state = left_button_down ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL;

    return false;
}

下面可以创建一个输入设备实体并注册到LittlevGL中去了:

    //Add a touchscreen input device
    ts_init();
    lv_indev_drv_t indev_drv;
    lv_indev_drv_init(&indev_drv);          /*Basic initialization*/
    indev_drv.type = LV_INDEV_TYPE_POINTER;
    indev_drv.read_cb = ts_read;         /*This function will be called periodically (by the library) to get the mouse position and state*/
    lv_indev_drv_register(&indev_drv);

上面这段代码放在创建完显示设备之后即可,将LV_DEMO_SLIDE_SHOW设置为0以关闭自动滑动功能取消。运行之后效果就出来了:

【LittlevGL】ARM Linux移植_第1张图片

流畅性还可以,做一些简单的应用是没有问题的。

注:可以使用tslib作为提供的接口函数创建出来一个输入设备来给LittlevGL使用,tslib的API参考:https://github.com/libts/tslib#the-libts-library。

你可能感兴趣的:(LittlevGL)