驱动程序开发:多点电容触摸屏

news2024/11/18 1:45:08

驱动程序开发:多点电容触摸屏

  • 一、编写驱动前的知识准备
    • 1、CST340触摸屏芯片寄存器
    • 2、CST340触摸屏的硬件原理图
    • 3、电容触摸屏驱动是由几种linux驱动框架组成的
    • 4、linux多点电容触摸的(Multi-touch,简称 MT)协议
  • 二、驱动程序的编写
    • 1、修改设备树
    • 2、驱动程序编写
    • 3、驱动运行测试
    • 4、将驱动添加到内核中
  • 三、tslib移植

一、编写驱动前的知识准备

  这里我要吐槽一下正点原子的触摸屏了,本人使用的是正点原子的7寸触摸屏,万万没想到的是他们家的7寸触摸屏使用过多款的触摸屏芯片,正是这个“因”,导致我在做触摸屏裸机实验时使用FT5426触摸屏芯片的驱动程序可以完整正确运行,但到了使用FT5426驱动程序时却不能正常的读、写寄存器了,经过多次折腾,终于忍不住请了外援FAE帮忙,它说FT5426驱动可以兼容好几款的7寸触摸屏,但又有一些略微的不同,正因为这略微的不同导致我掉坑里那么久的“果”。
  经过我手机的百倍放大终于看清楚了高温黄油纸下的芯片上的型号字体,其型号是CST340,FAE说这款芯片是兼容FT5426驱动,但是略微不同的是,该芯片不需要进行初始化,也就是说上电就给你自动初始化了,而且CST340芯片的寄存器好像只支持读,而且不是所有都能读,由于和FT5426芯片读触摸点坐标相同位置的寄存器才能读,这是我实验测试出来的,不太准,因为CST340这款芯片网上可以说找不到资料。

1、CST340触摸屏芯片寄存器

FT5426芯片寄存器,如下图所示:


在这里插入图片描述

  注意:FT5426和CST340都是I2C通讯,其I2C设备地址都是0x38,而且其两的触摸点寄存器地址都是相同的,也就是上图红色框框里的,但是不同的是CST340的X和Y坐标的数据存储的寄存器是和FT5426相反过来的。

2、CST340触摸屏的硬件原理图

在这里插入图片描述
上图可以看出,CST340芯片的I2C数据线、时钟线引脚、中断引脚和复位引脚连接到对应的IMX6ULL芯片的引脚。

3、电容触摸屏驱动是由几种linux驱动框架组成的

①、 IIC 设备驱动,因为电容触摸 IC 基本都是 IIC 接口的,因此大框架就是 IIC 设备驱动。
②、通过中断引脚(INT)向 linux 内核上报触摸信息,因此需要用到 linux 中断驱动框架。坐标的上报在中断服务函数中完成。
③、触摸屏的坐标信息、屏幕按下和抬起信息都属于 linux 的 input 子系统,因此向 linux 内核上报触摸屏坐标信息就得使用 input 子系统。只是,我们得按照 linux 内核规定的规则来上报坐标信息。

4、linux多点电容触摸的(Multi-touch,简称 MT)协议

MT 协议被分为两种类型, TypeA 和 TypeB,这两种类型的区别如下:
Type A:适用于触摸点不能被区分或者追踪,此类型的设备上报原始数据(此类型在实际使用中非常少!)。
Type B:适用于有硬件追踪并能区分触摸点的触摸设备,此类型设备通过 slot 更新某一个触摸点的信息, FT5426 就属于此类型,一般的多点电容触摸屏 IC 都有此能力。
 
  其实触摸点的信息通过一系列的 ABS_MT 事件(有的资料也叫消息)上报给 linux 内核,只有ABS_MT 事件是用于多点触摸的, ABS_MT 事件定义在文件 include/uapi/linux/input.h 中,相关事件如下所示:
在这里插入图片描述
  在 上 面 这 些 众 多 的 ABS_MT 事 件 中 , 我 们 最 常 用 的 就 是 ABS_MT_SLOT 、ABS_MT_POSITION_X 、 ABS_MT_POSITION_Y 和 ABS_MT_TRACKING_ID 。 其 中ABS_MT_POSITION_X 和 ABS_MT_POSITION_Y 用来上 报触摸 点的 (X,Y) 坐标 信息 ,ABS_MT_SLOT 用 来 上 报 触 摸 点 ID , 对 于 Type B 类 型 的 设 备 , 需 要 用 到ABS_MT_TRACKING_ID 事件来区分触摸点。
  对于 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 A 类型的设备,发送触摸点信息的时序如下所示,这里以 2 个触摸点为例:

						示例代码 64.1.2.1 Type A 触摸点数据上报时序
ABS_MT_POSITION_X x[0]		//通过 ABS_MT_POSITION_X 事件上报第一个触摸点的 X 坐标数据,通过input_report_abs 函数实现,下面同理
ABS_MT_POSITION_Y y[0]		//通过 ABS_MT_POSITION_Y 事件上报第一个触摸点的 Y 坐标数据
SYN_MT_REPORT				//上报 SYN_MT_REPORT 事件,通过调用 input_mt_sync 函数来实现
ABS_MT_POSITION_X x[1]		//通过 ABS_MT_POSITION_X 事件上报第二个触摸点的 X 坐标数据
ABS_MT_POSITION_Y y[1]		//通过 ABS_MT_POSITION_Y 事件上报第二个触摸点的 Y 坐标数据
SYN_MT_REPORT				//上报 SYN_MT_REPORT 事件,通过调用 input_mt_sync 函数来实现
SYN_REPORT					//上报 SYN_REPORT 事件,通过调用 input_sync 函数实现

  以下是某个TypeA类型驱动的代码段案例:
在这里插入图片描述


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

							示例代码 64.1.3.1 Type B 触摸点数据上报时序
ABS_MT_SLOT 0				//报 ABS_MT_SLOT 事件,也就是触摸点对应的 SLOT。每次上报一个触摸点坐标之前要先使用input_mt_slot函数上报当前触摸点SLOT,触摸点的SLOT其实就是触摸点ID,需要由触摸 IC 提供
ABS_MT_TRACKING_ID 45		//根据 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 值
ABS_MT_POSITION_X x[0]		//上报触摸点 0 的 X 轴坐标,使用函数 input_report_abs 来完成
ABS_MT_POSITION_Y y[0]		//上报触摸点 0 的 Y 轴坐标,使用函数 input_report_abs 来完成
ABS_MT_SLOT 1
ABS_MT_TRACKING_ID 46
ABS_MT_POSITION_X x[1]
ABS_MT_POSITION_Y y[1]
SYN_REPORT					//当所有的触摸点坐标都上传完毕以后就得发送 SYN_REPORT 事件,使用 input_sync函数来完成

  以下是某个TypeB类型驱动的代码段案例:
在这里插入图片描述
 
 

二、驱动程序的编写

1、修改设备树

  CST340触摸屏芯片用到了4个IO,一个复位IO、一个中断IO、I2C的SCL和SDA,所以我们需要先在设备树中添加IO相关的信息。(具体电器属性的意思可以看我前面的博客,有介绍怎么查看手册的电器属性设置)
  ①、中断IO,在IOMUXC节点下的imx6ul-evk子节点中添加触摸屏的中断引脚信息:


在这里插入图片描述

  ②、触摸屏复位IO使用的是SNVS_TAMPER9,因此复位引脚信息要添加到iomuxc_snvs节点下的imx6ul-evk子节点中:


在这里插入图片描述

  ③、添加 I2C2 的 SCL 和 SDA 这两个 IO 信息, imx6ull-alientek-emmc.dts 里面默认就已经
添加了 I2C2 的 IO 信息,这是 NXP 官方添加的,所以不需要我们去修改。找到“pinctrl_i2c2”
节点,此节点就是用于描述 I2C2 的 IO 信息,节点内容如下所示:


在这里插入图片描述


最后,一定要检查一下设备树,确保触摸屏所使用的 IO 没有被其他的外设使用,如果有的 话就需要将其屏蔽掉,保证只有触摸屏用到了这四个 IO。

  ④、CST340这个触摸 IC 挂载 I2C2 下,因此需要向 I2C2 节点下添加一个子节点,此子节点用
于描述 CST340,添加完成以后的 I2C2 节点内容如下所示:


在这里插入图片描述

  因为正点原子的触摸芯片CST340和FT5426连接的IO引脚都是相同的,并且I2C的设备地址和触摸点寄存器地址也是相同的.

  从ft5426:ft5426@32依次往下解释:
  第一行设置的节点名称为ft5426,且ft5426器件地址为0x38。
  第二行是兼容属性,是用来在驱动程序中匹配设备树对应的节点使用的,只有匹配成功才会进入probe函数。
  第三行是触摸屏芯片的设备地址,也就是0x38。
  第四行是状态属性,这里设置的是“default”。
  第五行是描述 CST340的复位 IO 和中断 IO 所使用的节点为 pinctrl_tsc
和 pinctrl_tsc_reset。
  第七行interrupt-parent 属性描述中断 IO 对应的 GPIO 组为 GPIO1。
  第八行interrupts 属性描述中断 IO 对应的是 GPIO1 组的 IOI09。
  第九行reset-gpios 属性描述复位 IO 对应的 GPIO 为 GPIO5_IO09。
  第十行interrupt-gpios 属性描述中断 IO 对应的 GPIO 为 GPIO1_IO09。
 

2、驱动程序编写

  这里先再描述驱动程序的编写过程了,程序都有注释和编写顺序。如下:

/* 
 *  根据linux内核的程序查找所使用函数的对应头文件。 
 */  
#include <linux/module.h>       //MODULE_LICENSE,MODULE_AUTHOR  
#include <linux/init.h>         //module_init,module_exit  
#include <linux/kernel.h>       //printk  
#include <linux/fs.h>           //struct file_operations  
#include <linux/slab.h>         //kmalloc, kfree  
#include <linux/uaccess.h>      //copy_to_user,copy_from_user  
#include <linux/io.h>           //ioremap,iounmap  
#include <linux/cdev.h>         //struct cdev,cdev_init,cdev_add,cdev_del  
#include <linux/device.h>       //class  
#include <linux/of.h>           //of_find_node_by_path  
#include <linux/of_gpio.h>      //of_get_named_gpio  
#include <linux/gpio.h>         //gpio_request,gpio_direction_output,gpio_set_number  
#include <linux/atomic.h>       //atomic_t  
#include <linux/of_irq.h>       //irq_of_parse_and_map
#include <linux/interrupt.h>    //request_irq
#include <linux/timer.h>        //timer_list
#include <linux/jiffies.h>      //jiffies
#include <linux/atomic.h>       //atomic_set
#include <linux/input.h>        //input
#include <linux/platform_device.h>  //platform
#include <linux/delay.h>        //mdelay
#include <linux/i2c.h>          //i2c
#include <linux/input/mt.h>     //input multi touch

#define MAX_SUPPORT_POINTS 5 /* 5 点触摸 */
#define TOUCH_EVENT_DOWN 0x00 /* 按下 */
#define TOUCH_EVENT_UP 0x01 /* 抬起 */
#define TOUCH_EVENT_ON 0x02 /* 接触 */
#define TOUCH_EVENT_RESERVED 0x03 /* 保留 */

/* FT5426 寄存器相关宏定义 */
#define ft5426_TD_STATUS_REG 0X02 /* 状态寄存器地址 */
#define ft5426_DEVICE_MODE_REG 0X00 /* 模式寄存器 */
#define FT5426_IDG_MODE_REG 0XA4 /* 中断模式 */
#define ft5426_READLEN 29 /* 要读取的寄存器个数 */

/* 设备结构体 */
struct ft5426_dev {
    struct device_node *nd;     /* 设备节点 */
    int irq_pin, reset_pin;     /* 中断和复位的GPIO号 */
    int irq_num;                /* 中断号 */
    void *private_data;         /* 私有数据 */
    struct i2c_client *client;  /* 保存系统分配的client */
    struct input_dev *input;    /* input_dev结构体成员变量 */
};
static struct ft5426_dev ft5426;  /* 实例ft5426_dev结构体 */

/* 3.1 读取ft5426的N个寄存器值 */
static int ft5426_read_regs(struct ft5426_dev *dev, u8 reg, void *val, int len) {
    struct i2c_client *client = (struct i2c_client *)dev->client;
    /* msg[0]发送从机地址来连接对应的从机   msg[1]发送连接从机设备对应的寄存器 */
    struct i2c_msg msg[2] = {
        [0] = {
            .addr  = client->addr,  //从机地址
            .flags = 0,             //表示发送数据,也就是控制位为写
            .buf   = &reg,          //发送需要读取的寄存器地址
            .len   = 1,             //发送读取的寄存器地址长度为1个字节
        },

        [1] = {
            .addr  = client->addr,  //从机地址
            .flags = I2C_M_RD,      //表示读取数据,控制位为读
            .buf   = val,           //将接收到的数据保存到缓存val中
            .len   = len,           //读取的寄存器数据长度
            
        },
    };  
    if (2 != i2c_transfer(client->adapter, msg, 2)) //判断是否为执行的消息个数
        return -1;
    return 0;
}


/* 3.2 读取ft5426一个寄存器值 */
static u8 ft5426_read_reg(struct ft5426_dev *dev, u8 reg)
{
    u8 data = 0;
    ft5426_read_regs(dev, reg, &data, 1);
    return data;
}

/* 3.3 向ft5426的N个寄存器写入数值 */
static int ft5426_write_regs(struct ft5426_dev *dev, u8 reg, u8 *buf, int len) {
    u8 send_buf[256];
    struct i2c_client *client = (struct i2c_client *)dev->client;
    /* 构建要发送的数据,也就是寄存器首地址+实际发送的数据 */
    send_buf[0] = reg;  //寄存器地址
    memcpy(&send_buf[1], buf, len); //发送的数据
    struct i2c_msg msg = {
        .addr  = client->addr,  //从机地址
        .flags = 0,             //表示发送数据,也就是控制位为写
        .buf   = send_buf,      //发送的数据,寄存器首地址+实际发送的数据
        .len   = len + 1,       //要发送的数据长度,寄存器长度+实际发送的数据的长度
    }; 
    if (1 != i2c_transfer(client->adapter, &msg, 1)) //判断是否为执行的消息个数
        return -1;
    return 0;   
}

/* 3.4 向ft5426一个寄存器写数据 */
static void ft5426_write_reg(struct ft5426_dev *dev, u8 reg, u8 data) {
    ft5426_write_regs(dev, reg, &data, 1);
}

/* 2.4 FT5426中断处理函数线程 */
static irqreturn_t ft5426_handler(int irq, void *dev_id)
{   
    int i,x,y,touch_id;
    u8 touch_type;  //触摸类型
    struct ft5426_dev *dev = dev_id;    //获取设备结构体
    u8 read_buf[29] = {0};
    int TouchPoint_len = 6; //一个触摸点信息占用6个寄存器
    bool down;

    // printk("\r\nft5426_handler\r\n");
/************************ 5 从FT5426芯片读取触摸点信息 ************************/
    ft5426_read_regs(dev, ft5426_TD_STATUS_REG, read_buf, ft5426_READLEN);
    /* 提取每个触摸点的触摸坐标数据,并以TypeB格式上报 */
    for(i = 0; i < MAX_SUPPORT_POINTS; i++) {
        u8 *buf = &read_buf[i * TouchPoint_len + 1]; //读取每个坐标点的第一个寄存器位置,偏移1位

        /* 以第一个触摸点为例,寄存器 TOUCH1_XH(地址 0X03),各位描述如下:
        * bit7:6 Event flag 0:按下 1:释放 2:接触 3:没有事件
        * bit5:4 保留
        * bit3:0 X 轴触摸点的 11~8 位。
        */
        touch_type = buf[0] >> 6;   //获取触摸类型
        if(touch_type == TOUCH_EVENT_RESERVED)    //如果没有事件,就继续下一个
            continue;

        /* 使用的CST340芯片的X、Y寄存器是反过来的,也就是X寄存器是Y寄存器的 */
        x = ((buf[2] << 8) | buf[3]) & 0x0FFF;  //高位只有4位,低位有8位
        y = ((buf[0] << 8) | buf[1]) & 0x0FFF;

        /* 以第一个触摸点为例,寄存器 TOUCH1_YH(地址 0X05),各位描述如下:
        * bit7:4 Touch ID 触摸 ID,表示是哪个触摸点
        * bit3:0 Y 轴触摸点的 11~8 位。
        */      
        touch_id = (buf[2] >> 4) & 0x0F;    //获取触摸点的ID
        down = touch_type != TOUCH_EVENT_UP;    //触摸按下,先运行后面的touch_type != TOUCH_EVENT_UP;返回真或假
        /* 上报触摸点信息 */
        input_mt_slot(dev->input, touch_id);   //设置input多点触摸槽信息
        input_mt_report_slot_state(dev->input, MT_TOOL_FINGER, down);  //设置上报槽函数的状态,参数2为手指按下工具,参数3为触摸点按下
        if(!down) { //如果按下为假,那么就获取下一个触摸点
            continue;
        }
        input_report_abs(dev->input, ABS_MT_POSITION_X, x); //上报触摸点的绝对坐标值
        input_report_abs(dev->input, ABS_MT_POSITION_Y, y); //上报触摸点的绝对坐标值
    }
    input_mt_report_pointer_emulation(dev->input, true);    //上报指针模拟,相当与模拟触摸板手指计数
    input_sync(dev->input);    //将input输入的数据同步上报
/***************************************************************************/
    return IRQ_HANDLED;
}

/* 2.2 FT5426复位引脚初始化 */
static int ft5426_ts_reset(struct i2c_client *client, struct ft5426_dev *dev)
{
    int ret = 0;
    /* 检查IO是否有效 */
    if(gpio_is_valid(dev->reset_pin)) {
        /* 申请复位IO,并且默认输出低电平,devm开头的表示申请资源后不需要手动释放,系统会自动释放 */
        ret = devm_gpio_request_one(&client->dev, dev->reset_pin, GPIOF_OUT_INIT_LOW, "edt-ft5426 reset");
        if(ret) {
            return ret;
        }
        gpio_set_value(dev->reset_pin, 0);  /* 输出低电平,开始复位 */
        msleep(20);
        gpio_set_value(dev->reset_pin, 1);  /* 输出高点平,停止复位 */
        msleep(20);
    }
    return 0;
}

/* 2.3 FT5426中断引脚初始化 */
static int ft5426_ts_irq(struct i2c_client *client, struct ft5426_dev *dev)
{
    int ret = 0;
    /* 申请中断gpio */
    if(gpio_is_valid(dev->irq_pin)) {
        ret = devm_gpio_request_one(&client->dev, dev->irq_pin, GPIOF_IN, "edt-ft5426 irq");
        if(ret) {
            dev_err(&client->dev, "Failed to request GPIO %d, errot %d\r\n", dev->irq_pin, ret);
            return ret;
        }
    }
    /* 申请中断,client->irq就是中断 */
    ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, ft5426_handler, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, client->name, &ft5426);
    if(ret) {
        dev_err(&client->dev, "Unable to request touchscreen IRQ.\r\n");
        return ret;
    }
    return 0;
}

/* 1.2 probe函数 */
static int ft5426_probe(struct i2c_client *client, const struct i2c_device_id *id) {
    int ret = 0;
    printk("ft5426_probe\r\n");

    /* 2.1 */
    ft5426.client = client; //获取系统分配的client
    ft5426.irq_pin = of_get_named_gpio(client->dev.of_node, "interrupt-gpios", 0);   //获取irq的gpio引脚
    ft5426.reset_pin = of_get_named_gpio(client->dev.of_node, "reset-gpios", 0); //获取reset的gpio引脚
    ft5426_ts_reset(client, &ft5426);   //ft5426复位引脚初始化
    ft5426_ts_irq(client, &ft5426);     //ft5426中断引脚初始化

    /* 3.5 初始化FT5426,我使用的是CST340触摸芯片,因此只是兼容触摸点坐标寄存器地址,但无需进行初始化,上电会自动初始化的 */
    ft5426_write_reg(&ft5426, ft5426_DEVICE_MODE_REG, 0); //进入正常模式
    ft5426_write_reg(&ft5426, FT5426_IDG_MODE_REG, 1); //FT5426中断模式

/************************** 4 input子系统框架 **************************/
    ft5426.input = devm_input_allocate_device(&client->dev);    //申请input子系统,参数是属于哪个设备
    if(!ft5426.input) {
        ret = -ENOMEM;
        goto fail;
    }
    ft5426.input->name = client->name;  //设置 input_dev 名字
    ft5426.input->id.bustype = BUS_I2C; //input_id总线类型为BUS_I2C
    ft5426.input->dev.parent = &client->dev; //设置其父设备为client->dev

    __set_bit(EV_SYN, ft5426.input->evbit); //设置同步事件
    __set_bit(EV_KEY, ft5426.input->evbit); //设置产生按键事件
    __set_bit(EV_ABS, ft5426.input->evbit); //设置绝对坐标事件
    __set_bit(BTN_TOUCH, ft5426.input->keybit); //设置产生哪些按键值

    /* 单点触摸 */
    input_set_abs_params(ft5426.input, ABS_X, 0, 1024, 0, 0);
    input_set_abs_params(ft5426.input, ABS_Y, 0, 600, 0, 0);

    /* 多点触摸 */
    input_mt_init_slots(ft5426.input, MAX_SUPPORT_POINTS, 0);   //初始化input多点触摸槽,最大支持5个触摸点
    input_set_abs_params(ft5426.input, ABS_MT_POSITION_X, 0, 1024, 0, 0);
    input_set_abs_params(ft5426.input, ABS_MT_POSITION_Y, 0, 600, 0, 0);
    
    /* 注册input子系统 */
    ret = input_register_device(ft5426.input);
    if (ret)
        goto fail;    
/*********************************************************************/
fail:
    return ret;
}

/* 1.3 remove函数 */
static int ft5426_remove(struct i2c_client *client) {
    int ret = 0;
    printk("ft5426_remove\r\n");
    /* 释放 input_dev */
    input_unregister_device(ft5426.input);
    return ret;
}

/* 1.4 传统的匹配表 */
static const struct i2c_device_id ft5426_id[] = {
    {"edt-ft5426",0},
    {}
};

/* 1.5 设备树匹配表 */
static const struct of_device_id ft5426_of_match[] = {
    { .compatible = "edt,edt-ft5426" },
    {}
};

/* 1.1 i2c_driver结构体 */
static struct i2c_driver ft5426_driver = {
    .probe = ft5426_probe,
    .remove = ft5426_remove,
    .driver = {
        .name = "edt_ft5426",
        .owner = THIS_MODULE,
        .of_match_table = of_match_ptr(ft5426_of_match),
    },
    .id_table = ft5426_id,
};

/* 1.6 i2c驱动模块注册和注销 */
module_i2c_driver(ft5426_driver);	  

/* 1.7 许可证和作者 */
MODULE_LICENSE("GPL");  
MODULE_AUTHOR("djw");  

3、驱动运行测试

①使用命令:depmod 和 modprobe ft5426.ko 加载驱动程序
驱动加载成功后会显示下图信息:
在这里插入图片描述
在/dev/input目录下可以看到多出一个没有加载驱动前的事件event2,如下图:
在这里插入图片描述
②使用命令:hexdump /dev/input/event2 可查看到多点触摸屏上报的TypeB类型的原始数据,如下图:
在这里插入图片描述

4、将驱动添加到内核中

①linux 内核里面将触摸屏驱动放到了 drivers/input/touchscreen 目录下,因此我们要将 ft5x06.c 拷贝到此目录下,命令如下:

cp ft5426.c /drivers/input/touchscreen/ -f

②修改 drivers/input/touchscreen 目录下的 Makefile,在最下面添加下面一行,如下图:
在这里插入图片描述
③进入 linux 内核源码目录,输入make menuconfig命令打开图形化配置界面,Touchscreens项要使能能,linux内核才会初始化调用触摸屏功能的驱动。

Location:
 -> Device Drivers
  -> Input device support
   -> Generic input layer (needed for keyboard, mouse, …) (INPUT [=y])
    -> Touchscreens (INPUT_TOUCHSCREEN [=y])

④这时再调用 hexdump /dev/input/event2 命令可能就不行了,因为内核在一开始启动就初始化了ft5426.c触摸屏驱动程序,那么它应该就在event1中了,不过具体还是要看实际的。
 
其重启开机后可以看到加载ft5426.c驱动程序的日志,如下图:
在这里插入图片描述

 
 

三、tslib移植

①获取 tslib 源码,在git 地址为 tslib源码链接,下载解压后,得到名为“tslib-1.21”的目录,此目录下就是 tslib 源码。
②修改 tslib 源码所属用户,命令如下:注意:我的ubuntu登陆用户名是djw

sudo chown djw:djw tslib-1.21 -R

③编译 tslib 的时候需要先在 ubuntu 中安装一些文件,防止编译 tslib 过程中出错,命令如下:

sudo apt-get install autoconf
sudo apt-get install automake
sudo apt-get install libtool

④首先在 ubuntu 中创建一个名为“tslib”的目录存放编译结果,列如我的是/home/djw/linux/IMX6ULL/tool/tslib,输入如下配置命令得到我们想要的tslib相关文件,如下:

cd tslib-1.21/ //进入 tslib 源码目录
./autogen.sh
./configure --host=arm-linux-gnueabihf --prefix=/home/djwi/linux/IMX6ULL/tool/tslib
make //编译
make install //安装

完成以后,tslib目录如下图:


在这里插入图片描述

⑤将tslib目录下的文件拷贝到开发板的跟文件系统中,命令如下:

sudo cp * -rf /home/djw/linux/nfs/rootfs

⑥开启开发板,打开/etc/ts.conf文件,如下图,该行不能屏蔽:

命令:vi /etc/ts.conf

在这里插入图片描述
⑦配置tslib,打开/etc/profile文件,没有的可以自己创建一个,添加如下图内容:
在这里插入图片描述
加好后的profile文件,如下图:


在这里插入图片描述

⑧配置好上面的步骤,就可以对tslib工具进行测试了,先重启开发板,然后输入 ts_test_mt命令即可在开发板触摸屏上看到触摸测试界面了,如下图:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/148470.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring AOP【AOP的基本实现与动态代理JDK Proxy 和 CGLIB区别】

Spring AOP【AOP的基本实现与动态代理JDK Proxy 和 CGLIB区别】&#x1f34e;一. Spring AOP&#x1f352;1.1 什么是Spring AOP&#x1f352;1.2 Spring AOP的作用&#x1f352;1.3 AOP的组成&#x1f349;1.3.1 切面&#xff08;Aspect&#xff09;&#x1f349;1.3.2 连接点…

大数据NiFi(十一):NiFi入门案例一

文章目录 NiFi入门案例一 一、配置“GetFile”处理器

Elastic-Job分布式任务调度

一.什么是任务调度 **任务调度&#xff1a;**是指系统为了自动完成特点任务&#xff0c;在约定的特定时刻去执行任务的过程。有了任务调度就不需要人力去实现&#xff0c;系统可以在某个时间自动执行任务。 二&#xff0c;任务调度的实现方式&#xff1a; 1.**多线程方式实现…

【博客579】netfilter network flow 和 routing decision的网络流处理交互关系

netfilter网络流转&#xff08;network flow&#xff09;与路由决策&#xff08;routing decision&#xff09;的网络流处理交互关系 1、场景&#xff1a; 我们可以通过iptables来基于netfilter机制下发我们的hook处理函数&#xff0c;那么我们平时iptables的四表五链与报文的…

JDBC简介

大家好&#xff0c;今天给大家分享jdbc 首先我们要知道什么是jdbc JDBC(Java DataBase Connectivity) &#xff1a;Java数据库连接技术&#xff1a;具体讲就是通过Java连接广泛的数据库&#xff0c;并对表中数据执行增、删、改、查等操作的技术 看它的架构图 或者看这个图…

flowable工作流架构分析

flowable工作流目录概述需求&#xff1a;设计思路实现思路分析1.复杂的状态的或者状态的维度增加的状的条件极为复杂2.工作流3.BPMN2.0协议4.协议的元素5.互斥网关包容性网关&#xff08;Inclusive Gateway&#xff09;参考资料和推荐阅读Survive by day and develop by night.…

车载以太网 - DoIP诊断消息处理逻辑 - 05

前面我们已经介绍了DoIP信息头部处理逻辑和路由激活处理,那根据DoIP报文的顺序,在路由激活处理完成后,接下来我们就需要发送真正的DoIP诊断信息了,那今天我们就来介绍下DoIP诊断消息的处理逻辑。 诊断消息处理逻辑 DoIP诊断报文结构: 上面表格对于DoIP诊断报文的…

Android 11 SystemUI(状态/导航栏)-图标按键的深浅色

概述 自 Android 5.0 版本&#xff0c;Android 带来了沉浸式系统 bar&#xff08;状态栏和导航栏&#xff09;&#xff0c;Android 的视觉效果进一步提高&#xff0c;各大 app 厂商也在大多数场景上使用沉浸式效果。6.0开始提供了View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR标志位&a…

MVC架构模式 | 使用银行转账的功能实现引出MVC架构模式

一、银行转账的功能实现数据库表的准备创建数据库表&#xff0c;主要包括三个字段&#xff1a;自增的id、账户名、账户余额不使用MVC架构模式完成账户转账首先写一个页面&#xff0c;写入转账的账户和金额&#xff1b;并发送post请求<% page contentType"text/html;cha…

【JavaEE】进入Web开发的世界-HTML

目录 一、HTML 1.1概念篇 1.2工具篇 1.2.1文本类型的标签 1.2.2多媒体标签 1.2.3超链接 1.2.4target 1.2.5表格相关的标签 1.2.6 列表标签 1.2.7表单标签 进入Web开发的世界&#xff0c;了解html、css、JavaScript的使用。 Web开发的核心&#xff1a;准备各式各样的资…

元壤:国内首家免费的数字藏品、DAO数字化营销SaaS平台

元壤&#xff1a;国内首家免费的数字藏品、DAO数字化营销SaaS平台 元壤是 Web3.0 时代 NFT 数字藏品与用户服务的数字化工具。元壤是中国企业数字资产化及数字藏品营销解决方案提供商。元壤致力于通过产品和服务,助力企业资产数字化,数字营销化,通过科技驱动数字商业变革,让数…

如何仿真MOS电容的电压-电容曲线?

一、原理 电容的阻抗为&#xff1a; 假设在电容两端施加频率为 f 的小信号电压 v &#xff0c;电容上流过的小信号电流为 i &#xff0c;那么三者有如下关系&#xff1a; 二、仿真 设置频率为1/2pi&#xff0c;这样算出来斜率即为1/C。设置f为0.159155 斜率就是1/C&#xff0c…

你问我答|DDR5对企业用户意味着什么?

自从2014年DDR4内存在市场推出以来,时间已经过去了八年,这对日新月异的计算机行业来说,无疑是相当长的一段时间了。这期间,更快的CPU和存储介质等产品的技术进步,促进了对更大容量的内存、更高内存带宽和更快速率的需求,服务器市场尤其如此。      而在2023年,我们终于迎来…

Sentinel 初始化监控以及流控规则简介

Sentinel 初始化监控 第一步&#xff1a;创建8401微服务 cloudalibaba-sentinel-service 并引入依赖 .yml 配置文件 server:port: 8401spring:application:name: cloudalibaba-sentinel-servicecloud:nacos:server-addr: localhost:8848 #Nacos服务注册中心地址sentinel:trans…

抖音搜索里的百科词条如何创建?

头条系的两大拳头产品&#xff0c;一个是抖音&#xff0c;一个是今日头条。现在头条系的运营重心向抖音倾斜&#xff0c;而抖音搜索里也存在一个固定的位置给快懂百科&#xff0c;这个位置不是像短视频一样滚动更新&#xff0c;做抖音搜索优化的话&#xff0c;小马识途营销顾问…

gateway网关的使用

今天与大家分享gateway网关的使用 1. gateway简介 1.1 是什么 SpringCloud Gateway 作为 Spring Cloud 生态系统中的网关&#xff0c;目标是替代 Zuul&#xff0c;在Spring Cloud 2.0以上版本中&#xff0c;没有对新版本的Zuul 2.0以上最新高性能版本进行集成&#xff0c;仍…

Java设计模式中外观模式是什么/外观模式有什么用,如何实现

继续整理记录这段时间来的收获&#xff0c;详细代码可在我的Gitee仓库SpringBoot克隆下载学习使用&#xff01; 5.6 外观模式 5.6.1 概述 又称门面模式&#xff0c;通过为多个子系统提供一个一致接口&#xff0c;而使这些子系统更加容易被访问的模式对外有一个统一接口&…

SAP工作流规则

代理人规则获取部分&#xff0c;灵活工作流和传统工作流一致 1. 事务代码&#xff1a;PFAC&#xff0c;用来创建规则 2. 规则用来确定代理&#xff0c;可通过如下下拉框中多种方式确定代理人 责任可在事务代码OOCU_RESP中配置代理人&#xff0c;可用来代替配置表确定代理人的…

Python蓝桥杯训练:数组和字符串 Ⅴ

Python蓝桥杯训练&#xff1a;数组和字符串 Ⅴ 文章目录Python蓝桥杯训练&#xff1a;数组和字符串 Ⅴ一、找到数组的中间位置二、使用最小花费爬楼梯一、找到数组的中间位置 给你一个下标从 0 开始的整数数组 nums &#xff0c;请你找到 最左边 的中间位置 middleIndex &#…

推荐系统实战5——EasyRec 在DSSM召回模型中添加负采样构建CTR点击平台

推荐系统实战5——EasyRec 在DSSM召回模型中添加负采样构建CTR点击平台学习前言EasyRec仓库地址DSSM实现思路一、DSSM整体结构解析二、网络结构解析1、Embedding层的构建2、网络层的构建3、相似度计算三、训练部分解析训练自己的DSSM模型一、数据集的准备二、Config配置文件的设…