XuSenfeng

个人站

复读了,更新随缘,有的文件不全或者图片缺失具体看我的笔记库(https://github.com/XuSenfeng/note)


触摸屏

目录

触摸屏

就是上报多点触摸信息, 通过触摸芯片, 多点电容触摸屏本质就是I2C驱动, 通过中断读取, 得到信息之后Linux使用INPUT进行输入

Linux有触摸屏上报的流程

Document/input/multi-touch-protocol.txt

有两种协议, 大多数使用的是Type B, Type A比较简单, 没有轨迹追踪, 会上报所有的数据, Type使用于有硬件追踪的数据

上报触摸信息时候, 通过上报事件进行上报, include/uapi/linux/input.h中

#define ABS_MT_SLOT		0x2f	/* MT slot being modified */
#define ABS_MT_TOUCH_MAJOR	0x30	/* Major axis of touching ellipse */
#define ABS_MT_TOUCH_MINOR	0x31	/* Minor axis (omit if circular) */
#define ABS_MT_WIDTH_MAJOR	0x32	/* Major axis of approaching ellipse */
#define ABS_MT_WIDTH_MINOR	0x33	/* Minor axis (omit if circular) */
#define ABS_MT_ORIENTATION	0x34	/* Ellipse orientation */
#define ABS_MT_POSITION_X	0x35	/* Center X touch position */
#define ABS_MT_POSITION_Y	0x36	/* Center Y touch position */
#define ABS_MT_TOOL_TYPE	0x37	/* Type of touching device */
#define ABS_MT_BLOB_ID		0x38	/* Group a set of packets as a blob */
......

最常用的事件就是, ABS_MT_POSITION_X, ABS_MT_POSITION_Y和ABS_MT_BLOB_ID, 分别上报对应的坐标以及区分坐标点, 一般先上报点的横坐标, 纵坐标, 点和点之间使用ABS_MT_BLOB_ID隔离

void input_mt_sync(struct input_dev *dev)

对于TypeA类型的设备,通过input_mt_sync()函数来隔离不同的触摸点数据信息, 实际是上报SYN_MT_REPORT信息, 通知接收者获取当前触摸数据,并且准备接收下一个触摸点数据

static inline void input_sync(struct input_dev *dev)

所有上报结束之后使用的函数, SYN_REPORT事件

void input_mt_report_slot_state(struct input_dev *dev, unsigned 								int tool_type, bool active);

用来上报一个点的, 如果是添加一个新的触摸点,那么此函数的第三个参数active要设置为true,linux内核会自动分配一个ABS_MT_TRACKING_ID值, 产生ABS_MT_TRACKING_ID和ABS_MT_TOOL_TYPE事件, ABS_MT_TOOL_TYPE事 件 指 定 触 摸 类 型 ( 是 笔 还 是 手 指 等 )

dev:MT设备对应的input_dev。tool_type:触摸类型,可以选择MT_TOOL_FINGER(手指)、MT_TOOL_PEN(笔)或MT_TOOL_PALM(手掌),对于多点电容触摸屏来说一般都是手指。active:true,连续触摸,input子系统内核会自动分配一个ABS_MT_TRACKING_ID给slot。false,触摸点抬起,表示某个触摸点无效了,input子系统内核会分配一个-1给slot,表示触摸点溢出

void input_mt_slot(struct input_dev *dev, int slot)

此函数用于产生ABS_MT_SLOT事件,告诉内核当前上报的是哪个触摸点的坐标数据, dev:MT设备对应的input_dev。slot:当前发送的是哪个slot的坐标信息,也就是哪个触摸点

int input_mt_init_slots(struct input_dev *dev, unsigned int 							num_slots,unsigned int flags)

用于初始化MT的输入slots,编写MT驱动的时候必须先调用此函数初始化slots, dev:MT设备对应的input_dev,因为MT设备隶属于input_dev。num_slots:设备要使用的SLOT数量,也就是触摸点的数量。flags:其他一些flags信息

void input_report_abs(struct input_dev *dev, unsigned int code, 						int value)

dev:MT设备对应的input_dev。code:要上报的是什么数据,可以设置为ABS_MT_POSITION_X或ABS_MT_POSITION_Y,也就是X轴或者Y轴坐标数据。value:具体的X轴或Y轴坐标数据值

void input_mt_report_pointer_emulation(struct input_dev *dev, 				bool use_count)

dev:MT设备对应的input_dev。use_count:true,有效的触摸点数量;false,追踪到的触摸点数量多于当前上报的数量。返回值:无。

实际流程

  • Type A
   ABS_MT_POSITION_X x[0]
   ABS_MT_POSITION_Y y[0]
   SYN_MT_REPORT
   ABS_MT_POSITION_X x[1]
   ABS_MT_POSITION_Y y[1]
   SYN_MT_REPORT
   SYN_REPORT
  • Type B
	ABS_MT_SLOT 0			//input_mt_slot
    ABS_MT_TRACKING_ID 45	//input_mt_report_slot_state
    ABS_MT_POSITION_X x[0]	//input_report_abs
    ABS_MT_POSITION_Y y[0]
    ABS_MT_SLOT 1
    ABS_MT_TRACKING_ID 46
    ABS_MT_POSITION_X x[1]
    ABS_MT_POSITION_Y y[1]
    SYN_REPORT

TypeB设备驱动需要给每个识别出来的触摸点分配一个slot,后面使用这个slot来上报触摸点信息。可以通过slot的ABS_MT_TRACKING_ID来新增、替换或删除触摸点

一个非负数的ID表示一个有效的触摸点,-1这个ID表示未使用slot。一个以前不存在的ID表示这是一个新加的触摸点

中断线程化

驱动的主框架就是i2c, 需要使用中断处理, 中断处理函数中上报, 要使用到INPUT子系统框架

devm_request_threaded_irq函数==> 中断进程化, 用于申请中断,作用和request_irq函数类似, 中断线程化以后中断将作为内核线程运行,而且也可以被赋予不同的优先级,任务的优先级可能比中断线程的优先级高,这样做的目的就是保证高优先级的任务能被优先处理

下半部可以被延迟处理,但是依旧先于线程执行,中断线程化可以让这些比较耗时的下半部与进程进行公平竞争

devm

“devm_“前缀, 使用“devm_”前缀的函数申请到的资源可以由系统自动释放,不需要我们手动处理。

实现

ft5426: ft5426@38 {
    compatible = "edt,edt-ft5426";
    reg = <0x38>;
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_tsc
    &pinctrl_tsc_reset>;
    interrupt-parent = <&gpio1>;
    interrupts = <9 0>;
    reset-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>;
    interrupt-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>;
    status = "okay";
};

.proc/device-tree/soc/aps-bus@2100000/i2c@021a40000

  1. 搭建框架

  2. 初始化引脚

使用函数devm_gpio_request_one一次性初始化引脚

  1. 初始化中断

  2. 初始化ft5426

  3. 读取坐标上报

    if(touch_num) {         /* 单点触摸按下 */
        gt9147_read_regs(dev, GT_TP1_REG, touch_data, 5);
        id = touch_data[0] & 0x0F;
        if(id == 0) {
            input_x  = touch_data[1] | (touch_data[2] << 8);
            input_y  = touch_data[3] | (touch_data[4] << 8);

            input_mt_slot(dev->input, id);
		    input_mt_report_slot_state(dev->input, MT_TOOL_FINGER, true);		//为连续触摸
		    input_report_abs(dev->input, ABS_MT_POSITION_X, input_x);
		    input_report_abs(dev->input, ABS_MT_POSITION_Y, input_y);
        }
    } else if(touch_num == 0){                /* 单点触摸释放 */
        input_mt_slot(dev->input, id);
        input_mt_report_slot_state(dev->input, MT_TOOL_FINGER, false);		//不是连续触摸
    }

测试

tslib, 用于测试触摸屏

  1. 安装
sudo apt-get install autoconf
sudo apt-get install automake
sudo apt-get install libtool
  1. 编译
./autogen.sh
./configure --host=arm-linux-gnueabihf --prefix=/home/zuozhongkai/linux/IMX6ULL/tool/tslib 
make//编译
make install//安装
  1. 复制到根文件

  2. et/profile加入

export TSLIB_TSDEVICE=/dev/input/event2	//使用的设备
export TSLIB_CALIBFILE=/etc/pointercal //校准文件
export TSLIB_CONFFILE=/etc/ts.conf     //触摸配置文件
export TSLIB_PLUGINDIR=/lib/ts        //插件目录
export TSLIB_CONSOLEDEVICE=none   	//
export TSLIB_FBDEVICE=/dev/fb0		//关联的目录
  1. 使用
ts_calibrate 			//校准,不满意删除文件/etc/pointercal
ts_test_mt				//测试

设置驱动为内核

打开Linux,

jiao@jiao-virtual-machine:~/linux/IMX6ULL/Bord_Drivers/23_multitouch$ cp gt9147. /home/jiao/linux/IMX6ULL/linux/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek/drivers/input/touchscreen/

之后在这个文件夹最后加上obj-y += gt9147.o