嵌入式linux 电容触摸屏驱动框架

           电容触摸屏驱动其实就是以下几种 linux 驱动框架的组合:    

         1,IIC 设备驱动,因为电容触摸 IC 基本都是 IIC 接口的,因此大框架就是 IIC 设备驱动。

        2,通过中断引脚(INT)linux 内核上报触摸信息,因此需要用到 linux 中断驱动框架。坐标的上报在中断服务函数中完成。

        3,触摸屏的坐标信息、屏幕按下和抬起信息都属于 linux input 子系统,因此向 linux 内核上报触摸屏坐标信息就得使用 input 子系统。只是,我们得按照 linux 内核规定的规则来上报坐标信息。

        我们应该已经了解了IIC驱动,中断驱动还有input子系统,唯一不太清楚的可能就是在input子系统里面如何上报多点电容触摸的信息。这是跟多点触摸协议相关的。

        老版本的linux内核是不支持多点电容触摸的(Multi-Touch),简称MT,是后面的版本新加上去的。MT协议被分为两种类型,TypeA和TypeB,两种类型区别如下:

        TypeA:适用于触摸点不能被区分或者追踪,此类型的设备上报原始数据(实际应用中很少)

        TypeB:适用于有硬件追踪并能区分触摸触摸点的触摸设备,此类型设备通过slot更新某一个触摸点信息,FT5426就属于此类型,一般的多点电容触摸IC都有此能力。

        触摸点信息通过一系列的ABS_MT事件上报给linux内核,只有ABS_MT事件用于多点触摸的,ADS_MT事件如下:

         在上面众多AMS_MT事件中,我们最常用的是AMS_MT_SLOT,AMS_MT_POSITION_X,AMS_MT_POSITION_Y和AMS_MT_TRACKING_ID。其中ABS_MT_POSITION_X 和 ABS_MT_POSITION_Y 用 来 上报 触 摸点 的 (X,Y) 坐 标 信息 , ABS_MT_SLOT 用 来 上 报 触 摸 点 ID ,对于 Type B 类 型 的 设 备 ,需 要 用 到ABS_MT_TRACKING_ID 事件来区分触摸点。

        对于TypeA类型的设备,通过input_mt_sync函数来隔离不同的触摸点数据信息,此函数原型如下所示:

        此函数只有一个参数,类型为input_dev,用于指定具体的input_dev设备,input_mt_sync函数会触发SYN_MT_REPORT事件,此事件会通知接受者获取当前触摸数据,并准备接收下一个触摸点信息。

        对于TypeB类型的设备,上报触摸点信息的时候需要通过input_mt_slot函数区分是哪一个触摸点,函数原型如下:

         第二个参数slot用于指定当前上报的是哪一个触摸点的信息,input_mt_slot函数会触发ABS_MT_SLOT事件,此事件会告诉接收者当前更新的是哪个触摸点(slot)的数据。

         不管那种类型的设备,最终都需要调用input_sync函数来标识多点触摸信息传输完成,告诉接收者处理之前累计的所有信息,并准备好下一次接收。Type B 和 Type A 相比最大的区别就是 Type B 可以区分出触摸点, 因此可以减少发送到用户空间的数据。Type B 使用 slot 协议区分具体的触摸点,slot需要用到AMS_MT_TRACKING_ID消息,这个ID需要硬件提供,或者通过原始数据计算出来。

        Type B 设备驱动需要给每个识别出来的触摸点分配一个 slot,后面使用这个slot来上报触摸点信息。可以通过slot的ABS_MT_TRACKING_ID来新增,替换,或者删除触摸点,一个非负值的ID表示一个有效的触摸点,-1这个ID表示未使用slot。一个以前不存在的ID表示这是一个新增加的触摸点,一个ID如果再也不存在了就表示删除了。

        有些设备识别或追踪的触摸点信息要比他上报的多(跟相应的设备有关),这些设备驱动应该给硬件上报的每个触摸点分配一个 Type B 的 slot。一旦检测到某一个 slot 关联的触摸点 ID 发生了变化,驱动就 应该改变这个 slot 的 ABS_MT_TRACKING_ID,使这个 slot 失效。如果硬件设备追踪到了比他正在上报的还要多的触摸点,那么驱动程序应该发送 BTN_TOOL_*TAP 消息,并且调用input_mt_report_pointer_emulation函数,将此函数的第二个参数 use_count 设置为 false。

TypeA触摸点信息上报时序

        对于TypeA类型的设备,发送触摸点信息的时序如下,这里以两个触摸点为例:

         第 1 行, ABS_MT_POSITION_X 事件上报第一个触摸点的 X 坐标数据,通过 input_report_abs 函数实现,下面同理。

        第 2 行,通过 ABS_MT_POSITION_Y 事件上报第一个触摸点的 Y 坐标数据。
        第 3 行,上报 SYN_MT_REPORT 事件,通过调用 input_mt_sync 函数来实现。用来隔离不同的触摸点数据信息。
        第 4 行,通过 ABS_MT_POSITION_X 事件上报第二个触摸点的 X 坐标数据。
        第 5 行,通过 ABS_MT_POSITION_Y 事件上报第二个触摸点的 Y 坐标数据。 
        第 6 行,上报 SYN_MT_REPORT 事件,通过调用 input_mt_sync 函数来实现。 

        第 7 行,上报 SYN_REPORT 事件,通过调用 input_sync 函数实现。这个是上报完每一轮触摸点信息就调用一次,比如上报3个触摸点信息,将3个触摸点信息上报完在调用这个就好。也就是发送一个SYN_REPORT事件。

Type B 触摸点信息上报时序     

        对于Type B 类型的设备,发送触摸点信息的时序如下所示,这里以 2 个触摸点为例:

         第1行,上报ABS_MT_SLOT事件,也就是触摸点对应的SLOT,每次上报一个触摸点坐标之前要先使用input_mt_slot函数上报当前触摸点SLOT,触摸点SLOT其实就是触摸点ID,由硬件提供。

        第2行,根据TypeB的要求,每个SLOT必须关联一个AMS_MT_TRACKING_ID来完成对触摸点的增加,替换,或删除。具体用到的函数就是input_mt_solt_state,如果添加一个新的触摸点,那么此函数的第三个参数active要设置为true,linux 内核会自动分配一个 ABS_MT_TRACKING_ID 值,不需要用户去指定具体的 ABS_MT_TRACKING_ID 值。

        3 行,上报触摸点 0 X 轴坐标,使用函数 input_report_abs 来完成。

        第 4 行,上报触摸点 0 Y 轴坐标,使用函数 input_report_abs 来完成。
        
        第 5~8 行,和第 1~4 行类似,只是换成了上报触摸点 1   (X,Y) 坐标信息  
        第 9 行,当所有的触摸点坐标都上传完毕以后就得发送 SYN_REPORT 事件,使用 input_sync 函数来完成。  

        当一个触摸点移除以后,同样需要通过 SLOT 关联的 ABS_MT_TRACKING_ID 来处理,需要通过ABS_MT_TRACKING_ID事件发送一个-1给内核,方法很简单,同样使用input_mt_report_slot_state函数来完成,只需要将第三个参数active设置为false即可,不需要手动设置为-1,时序如下所示:

//在中断处理函数里面,我们需要将读取到的数据上报,但是需要按照上报时序来完成
//主要看硬件可以是几点触发器,触发就循环多少次
//下面是一个简略的中断处理函数,可以大致看出上报流程
static irqreturn_t ft5x06_handler(int irq, void *dev_id)
{
	/* 读取FT5X06触摸点坐标从0X02寄存器开始,连续读取29个寄存器 */
	ret = ft5x06_read_regs(multidata, FT5X06_TD_STATUS_REG, rdbuf, FT5X06_READLEN);

    /* 上报每一个触摸点坐标 */
	for (i = 0; i < 5; i++) {
		u8 *buf = &rdbuf[i * tplen + offset];

		/* 以第一个触摸点为例,寄存器TOUCH1_XH(地址0X03),各位描述如下:
		 * bit7:6  Event flag  0:按下 1:释放 2:接触 3:没有事件
		 * bit5:4  保留
		 * bit3:0  X轴触摸点的11~8位。
		 */
		type = buf[0] >> 6;     /* 获取触摸类型 */
		if (type == TOUCH_EVENT_RESERVED)
			continue;                    //当硬件得到的信息时没有按下的话就终结本次循环,无需上报
 
		/* 我们所使用的触摸屏和FT5X06是反过来的 */
		x = ((buf[2] << 8) | buf[3]) & 0x0fff;
		y = ((buf[0] << 8) | buf[1]) & 0x0fff;
		
		/* 以第一个触摸点为例,寄存器TOUCH1_YH(地址0X05),各位描述如下:
		 * bit7:4  Touch ID  触摸ID,表示是哪个触摸点
		 * bit3:0  Y轴触摸点的11~8位。
		 */
		id = (buf[2] >> 4) & 0x0f;
		down = type != TOUCH_EVENT_UP;

		input_mt_slot(multidata->input, id);
		input_mt_report_slot_state(multidata->input, MT_TOOL_FINGER, down);

		if (!down)
			continue;

		input_report_abs(multidata->input, ABS_MT_POSITION_X, x);
		input_report_abs(multidata->input, ABS_MT_POSITION_Y, y);
	}
    
    //这个函数就是硬件的追踪的点比上报的多的话就为false,当不是的话就位ture
	input_mt_report_pointer_emulation(multidata->input, true);
    //在5点信息全部上报完的时候,再执行下面的函数,表示本次信息全部上报完成
	input_sync(multidata->input);
}
多点触摸所使用到的 API 函数
        1,input_mt_init_slots函数
        
        input_mt_init_slots函数 用于初始化MT的输入slots,编写MT驱动的是个必须先调用此函数初始化slots,通常也就是在probe函数里面就已经执行了。函数原型如下:

        dev:MT设备对应的input_dev,因为MT设备隶属于input_dev

        num_slots:设备要使用slot数量,也就是触摸点的数量

        flags:其他一些flags信息,可设置如下所示:

         可以采样‘|’运算来同时设置多个flags标识

        返回值:0,成功;负值,失败。

         2,input_mt_slot函数

        此函数用于TypeB类型,此函数用于产生ABS_MT_SLOT事件,告诉内核当前上报的是哪个触摸点的坐标数据。

         dev:MT设备对应的input_dev

        slot:当前发送的是哪个slot的坐标信息,也就是那个触摸点,那就是硬件发送过来的信息ID

        3,input_mt_report_slot_state函数

        此函数用于TypeB类型,用于产生ABS_MT_TRACKING_ID 和 ABS_MT_TOOL_TYPE事件给slot关联一个ABS_MT_TRACKING_ID ,ABS_MT_TOOL_TYPE 事 件 指 定 触 摸 类 型 ( 是 笔 还 是 手 指 等 )。函数原型如下:

         dev:MT设备对应的input_dev。

        tool_type:触摸类型,可以选择MT_TOOL_FINGER(手指)MT_TOOL_PEN()或MT_TOOL_PALM(手掌),对于多点电容触摸屏来说一般都是手指。

        active:ture,连续触摸,input子系统内核汇自动分配一个ABS_MT_TRACKING_ID给slot。false,触摸点抬起。表示某个触摸点无效了,input子系统就会给内核分配一个-1给slot,表示触摸点移除。

        4,input_report_abs函数

        TypeA Type B 类型都使用此函数上报触摸点坐标信息,通过ABS_MT_POSITION_X 和ABS_MT_POSITION_Y 事 件 实 现 X Y 轴 坐 标 信 息 上 报 。函数定义如下:

        dev:mt设备对应的input_dev

        code:要上报的是什么数据,要设置为ABS_MT_POSITION_X或 ABS_MT_POSITION_Y,也就是X轴或者Y轴坐标点数据。

        value:具体的X轴和Y轴坐标点数值

     5,input_mt_report_pointer_emulation函数

        如果追踪到的触摸点数量多于当前上报的数量,驱动程序使用 BTN_TOOL_TAP 事件来通知用户空间当前追踪到的触摸点总数量,然后调用 input_mt_report_pointer_emulation 函数将 use_count 参数设置为 false。否则的话将 use_count 参数设置为 true,表示当前的触摸点数量(此函数会获取到具体的触摸点数量,不需要用户给出)。 

        dev:MT设备对应的input_dev

        use_count:true,有效的触摸点数量;flase,追踪到的触摸点数量多于当前上报的数量

 多点电容触摸驱动框架   

        多点电容需要用到那些框架呢?我们需要注意以下几点:

  1. 多点电容触摸芯片的接口,一般都为I2C接口,因此驱动主框架肯定是I2C   
  2. linux里面一般都是通过中断来上报触摸点坐标信息的,因此需要中断框架
  3. 多点电容触摸属于input子系统,因此还要用到input子系统框架
  4. 在中断处理程序中按照linux的MT协议上报坐标信息

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值