多点电容触摸驱动(基于gt911) 您所在的位置:网站首页 天马触摸屏掉电时序 多点电容触摸驱动(基于gt911)

多点电容触摸驱动(基于gt911)

2024-03-12 15:29| 来源: 网络整理| 查看: 265

        多点电容触摸的驱动使用到的知识主要有input子系统、gpio硬件中断、iic子系统,tslib测试等知识点,下面将针对多点电容触摸屏的驱动开发的四个知识点进行展开,以及gt911芯片的知识,官方gt9xx驱动的移植。

一、gt911芯片

        gt911芯片是可以直接使用的,因为出场的时候已经代码已经烧录进去了,上电之后就可以直接检测到芯片的int引脚产生的中断脉冲,配置对应的引脚为中断,就可以观察到中断的触发。gt911芯片使用需要注意的有,芯片地址的脉冲配置,数据判断寄存器,中断清除。

(1)根据reset复位引脚和int中断引脚的脉冲的配置,设置芯片的iic通讯地址,

 

        但是gt911的iic通讯地址,只有低7位有效,所以需要将0xBA/0xBB的地址右移一位,得到iic的通讯地址为:0x5d。

(2)触摸点的数据缓冲区是否有数据,以及触摸点的个数,是一个重要的寄存器进行储存的。

 (3)在中断里将数据读取走之后,需要对“0x814E”寄存器写入0,不然int引脚就会一直产生中断的脉冲。

二、iic子系统

        韦老师的开发板是gt911的芯片通讯的iic是使用的imx6ull的i2c,设备树中gt911的设备结点时挂载到i2c的结点下面的。编写i2c的时候可以先测试与设备树的匹配是否成功,当iic设备与设备树中的结点匹配成功之后,就会调用probe函数,这个可以测试是否匹配成功。在匹配成功之后,就可以写iic的发送和接收函数,这时候可以对gt911的其中一个可以读写的寄存器,先对寄存器写入,然后对寄存器进行读取,观察写入和读出的数据是否相同,相同就说明iic读写是成功的。

        注意iic通讯使用的通讯频率。

三、gpio硬件中断(中断线程化)

        gpio的硬件中断的配置代码前面是已将有了,但是这里并没有使用gpio的硬件中断,因为gt911的工作频率是非常高的,中断上报的频率也是非常频繁的,如果使用硬件中断进行处理的话,由于硬件中断的优先级是最高的,这时候芯片就需要频繁的去处理中断,导致芯片效率变低。就算使用中断的上半部和下半部进行处理的话,中断的下半部使用软件中断也是优先级比普通的任务函数高的,使用任务进行处理,中断的上半部分也是较占资源的,所以这里采用中断线程化来处理这种比较频繁的中断。中断线程化之后,创建的资源是不需要程序员手动释放的,因为普通的任务线程是由系统管理的,在其不使用了之后就会手动释放。

        中断线程化设计到两个函数,使用还是比较简单的,下面将对两个函数的使用给出示例:(中断线程化的函数都是带“devm_”前缀的)。         下面是使用中断线程化函数进行gpio的创建:

/* 申请复位IO */ if (gpio_is_valid(dev->reset_pin)) /* gpio_is_valid判断gpio的pin是否存在 */ { /* 申请复位IO,并且默认输出高电平 */ ret = devm_gpio_request_one(&dev->i2cdrv->dev, //设备 dev->reset_pin, //gpio GPIOF_OUT_INIT_HIGH, //默认输出高电平 "gt9147 reset"); //gpio1的名字 if (ret) { return ret; } } /* 申请中断IO*/ if (gpio_is_valid(dev->irq_pin)) { /* 申请复位IO,并且默认输出高电平 */ ret = devm_gpio_request_one(&dev->i2cdrv->dev, dev->irq_pin, GPIOF_OUT_INIT_HIGH, "gt9147 int"); if (ret) { return ret; } }

        下面是对应gpio的中断的申请:

/* 中断的出发需要在硬件初始化之后 */ static int gt911_ts_irq(g_ptI2cDev dev) { int ret = 0; memset(dev->irq_name, 0, 20); strcpy(dev->irq_name, "gt911_irq"); /* 2,申请中断,client->irq就是IO中断, */ ret = devm_request_threaded_irq(&dev->i2cdrv->dev, //设备 dev->i2cdrv->irq, //中断号 NULL, //默认 gt911_handler, //终端函数 IRQ_TYPE_EDGE_FALLING | IRQF_ONESHOT, //下降沿出发|不允许中断嵌套,本次结束才能处理下一个 dev->irq_name, //终端的名字 dev); //给中断函数传入的 if (ret) { dev_err(&dev->i2cdrv->dev, "Unable to request touchscreen IRQ.\n"); return ret; } return 0; }

        下面是对应的中断线程化的线程中断函数:

static irqreturn_t gt911_handler(int irq, void *dev_id) { return IRQ_HANDLED; }

        不需要手动释放。

四、input子系统

            多点电容的触摸屏的input上报是这里新的知识点,前面没有学习过的,分为多触点形式的上报和单触点形式的上报,需要有屏幕按下和抬起的两种情况的上报,两种情况缺少一种,在下面tslib的测试过程中就会有问题。下面将从input上报的重要函数,input初始化和上报的流程案例进行讲解。

        前面已经有input子系统上报的相关知识,这里只进行新的知识的记录。

1、input上报的重要函数和数据 (1)MT的两种协议 Type A :适用于触摸点不能被区分或者追踪,此类型的设备上报原始数据 ( 此类型在实际使 用中非常少! ) 。 Type B :适用于有硬件追踪并能区分触摸点的触摸设备,此类型设备通过 slot 更新某一个 触摸点的信息, FT5426 就属于此类型,一般的多点电容触摸屏 IC 都有此能力。 852 #define ABS_MT_SLOT 0x2f /* MT slot being modified */ 853 #define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */ 854 #define ABS_MT_TOUCH_MINOR 0x31 /* Minor axis (omit if circular) */ 855 #define ABS_MT_WIDTH_MAJOR 0x32 /* Major axis of approaching ellipse */ 856 #define ABS_MT_WIDTH_MINOR 0x33 /* Minor axis (omit if circular) */ 857 #define ABS_MT_ORIENTATION 0x34 /* Ellipse orientation */ 858 #define ABS_MT_POSITION_X 0x35 /* Center X touch position */ 859 #define ABS_MT_POSITION_Y 0x36 /* Center Y touch position */ 860 #define ABS_MT_TOOL_TYPE 0x37 /* Type of touching device */ 861 #define ABS_MT_BLOB_ID 0x38 /* Group a set of packets as a blob */ 862 #define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */ 863 #define ABS_MT_PRESSURE 0x3a /* Pressure on contact area */ 864 #define ABS_MT_DISTANCE 0x3b /* Contact hover distance */ 865 #define ABS_MT_TOOL_X 0x3c /* Center X tool position */ 866 #define ABS_MT_TOOL_Y 0x3d /* Center Y tool position */ (2)上传时间的间隔函数         对于 Type A 类型的设备,通过 input_mt_sync() 函数来隔离不同的触摸点数据信息,此函数 原型如下所示: void input_mt_sync(struct input_dev *dev)         此函数只要一个参数,类型为 input_dev ,用于指定具体的 input_dev 设备。 input_mt_sync() 函数会触发 SYN_MT_REPORT 事件,此事件会通知接收者获取当前触摸数据,并且准备接收 下一个触摸点数据。          对于 Type B 类型的设备,上报触摸点信息的时候需要通过 input_mt_slot()函数区分是哪一 个触摸点, input_mt_slot() 函数原型如下所示: void input_mt_slot(struct input_dev *dev, int slot)         此函数有两个参数,第一个参数是 input_dev 设备,第二个参数 slot 用于指定当前上报的是 哪个触摸点信息。 input_mt_slot() 函数会触发 ABS_MT_SLOT 事件,此事件会告诉接收者当前 正在更新的是哪个触摸点 (slot) 的数据。         Type B 设备驱动需要给每个识别出来的触摸点分配一个 slot ,后面使用这个 slot 来上报触 摸点信息。可以通过 slot 的 ABS_MT_TRACKING_ID 来新增、替换或删除触摸点。一个非负数 的 ID 表示一个有效的触摸点, -1 这个 ID 表示未使用 slot 。一个以前不存在的 ID 表示这是一个 新加的触摸点,一个 ID 如果再也不存在了就表示删除了。 (3)Type A 上报时序 1 ABS_MT_POSITION_X x[0] 2 ABS_MT_POSITION_Y y[0] 3 SYN_MT_REPORT 4 ABS_MT_POSITION_X x[1] 5 ABS_MT_POSITION_Y y[1] 6 SYN_MT_REPORT 7 SYN_REPORT 第 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 函数实现。 116 for (i = 0; i < MAX_FINGERS; i++) { 117 if (!finger[i].is_valid) 118 continue; 119 120 input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, finger[i].t); 121 input_report_abs(input_dev, ABS_MT_POSITION_X, finger[i].x); 122 input_report_abs(input_dev, ABS_MT_POSITION_Y, finger[i].y); 123 input_mt_sync(input_dev); 124 count++; 125 } ...... 140 141 /* SYN_REPORT */ 142 input_sync(input_dev); (4)Type B上报时序 1 ABS_MT_SLOT 0 2 ABS_MT_TRACKING_ID 45 3 ABS_MT_POSITION_X x[0] 4 ABS_MT_POSITION_Y y[0] 5 ABS_MT_SLOT 1 6 ABS_MT_TRACKING_ID 46 7 ABS_MT_POSITION_X x[1] 8 ABS_MT_POSITION_Y y[1] 9 SYN_REPORT 第 1 行,上报 ABS_MT_SLOT 事件,也就是触摸点对应的 SLOT 。每次上报一个触摸点坐 标之前要先使用 input_mt_slot 函数上报当前触摸点 SLOT ,触摸点的 SLOT 其实就是触摸点 ID , 需要由触摸 IC 提供。 第 2 行,根据 Type B 的要求,每个 SLOT 必须关联一个 ABS_MT_TRACKING_ID ,通过 修改 SLOT 关联的 ABS_MT_TRACKING_ID 来完成对触摸点的添加、替换或删除。具体用到 的函数就是 input_mt_report_slot_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 行类似,只是换成了上报触摸点 0 的 (X,Y) 坐标信息 第 9 行,当所有的触摸点坐标都上传完毕以后就得发送 SYN_REPORT 事件,使用 input_sync 函数来完成。 当一个触摸点移除以后,同样需要通过 SLOT 关联的 ABS_MT_TRACKING_ID 来处理, 时序如下所示: 1 ABS_MT_TRACKING_ID -1 2 SYN_REPORT 第 1 行,当一个触摸点 (SLOT) 移除以后,需要通过 ABS_MT_TRACKING_ID 事件发送一 个 -1 给内核。方法很简单,同样使用 input_mt_report_slot_state 函数来完成,只需要将此函数的 第三个参数 active 设置为 false 即可,不需要用户手动去设置 -1 。 第 2 行,当所有的触摸点坐标都上传完毕以后就得发送 SYN_REPORT 事件。 86 for (i = 0; i < MAX_TOUCHES; i++) { 87 input_mt_slot(input, i); 88 89 finger = &touchdata->finger[i]; 90 91 touch = touchdata->status & (1 x_low | (finger->x_high y_low | (finger->y_high dev); if (!I2c.input) { printk("devm_input_allocate_device is error\r\n"); ret = -ENOMEM; } memset(I2c.input_name, 0, 20); strcpy(I2c.input_name, "gt911_input"); /* input子系统参数配置 */ I2c.input->name = I2c.input_name; I2c.input->id.bustype = BUS_I2C; I2c.input->dev.parent = &I2c.i2cdrv->dev; __set_bit(EV_KEY, I2c.input->evbit); /* 支持单点触摸 */ __set_bit(EV_ABS, I2c.input->evbit); /* 支持多点触摸 */ __set_bit(BTN_TOUCH, I2c.input->keybit); /* 对应的事件为触摸按键touch事件 */ I2c.max_x = TOUCH_MAP_MAX_X; /* lcd分辨率的x轴最大值 */ I2c.max_y = TOUCH_MAP_MAX_Y; /* lcd分辨率的y轴最大值 */ /* 单点 */ //input_set_abs_params(I2c.input, ABS_X, 0, I2c.max_x, 0, 0); //input_set_abs_params(I2c.input, ABS_Y, 0, I2c.max_y, 0, 0); /* 多点 */ input_set_abs_params(I2c.input, ABS_MT_POSITION_X,0, I2c.max_x, 0, 0); input_set_abs_params(I2c.input, ABS_MT_POSITION_Y,0, I2c.max_y, 0, 0); ret = input_mt_init_slots(I2c.input, MAX_SUPPORT_POINTS, 0); /* 支持的最多的触摸点数 */ if (ret) { printk(" input_mt_init_slots is error\r\n"); return ret; } ret = input_register_device(I2c.input); /* 进行注册 */ if (ret) { printk("input_register_device is error\r\n"); return ret; } return 0; } static void Input_Exit(void) { input_unregister_device(I2c.input); /* 设备的注销 */ } (2)input的上报代码: /* 有触摸点时候进行上报 */ input_mt_slot(dev->input, slot_id); input_mt_report_slot_state(dev->input, MT_TOOL_FINGER, true); input_report_abs(dev->input, ABS_MT_TRACKING_ID, slot_id); input_report_abs(dev->input, ABS_MT_POSITION_X, input_x); input_report_abs(dev->input, ABS_MT_POSITION_Y, input_y); input_sync(dev->input); /* 没有触摸点或者触摸点松开时候的上报 */ input_mt_slot(dev->input, slot_id); input_mt_report_slot_state(dev->input, MT_TOOL_FINGER, true); input_report_abs(dev->input, ABS_MT_TRACKING_ID, -1); input_sync(dev->input); /* 中断退出之前,要对寄存器0x814E写入0,不然会持续触发中断 */ dt911_flage = 0x00; gt911_write_regs(dev, GT_GSTID_REG, &dt911_flage, 1); 五、tslib测试

        tslib的测试,前面已经将过,这里就注意触摸的input对应那些事件就好了。在文件“/etc/profile”文件中。

六、官方的驱动使用

        由于gt911没有硬件检测触摸的按下和松开,所以需要软件上进行处理,这里我写的驱动不知道如何解决次问题,所以可以采用gt911官方的驱动代码和设备树,韦东山也是用的官方的设备树和驱动,后面会将这部分整理的代码发到自己的gitee,方便后面自己使用。

七、将自己的触摸驱动加入到内核系统中

        (1)首先要验证自己的驱动是否可以使用,是否完成了所有的功能,当所有都验证之后,就可以进行下面的操作。

        (2)将自己写的驱动c文件拷贝到下面的文件夹:

/home/book/100ask_imx6ull-sdk/Linux-4.9.88/drivers/input

         (3)修改当前文件夹下的“Makefile”

              将自己的驱动文件添加进去。

         (4)修改完成以后重新编译 linux 内核,然后用新的 zImage 启动开发板。如果驱动添加成功的话系统启动的时候就会输出如图 64.4.3.2 所示的信息:

注意:这时候触摸input对应的event可能会变,tslib测试的时候需要注意。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有