锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

138.多点电容触摸协议基本概念

时间:2023-01-02 19:00:00 y系列电容8合1电容笔

文章目录

    • 1. 硬件接口
    • 2.多点触摸(Multi-touch) 协议
    • 3. 多触摸事件
    • 4.TypeB上报时序
    • 5.使用到的API函数
      • 1.input_mt_init_slots
      • 2.input_mt_slot 函数
      • 3.input_mt_report_slot_state 函数
      • 4.input_report_abs 函数
      • 5.报告时序案例
    • 6.多点电容触摸屏驱动编写
      • 1.I2C驱动框架
      • 2. probe函数
      • 3.报告坐标信息

1. 硬件接口

所以Linux下电容触摸屏驱动框架为:i2c驱动框架,中断机制,input多点触摸协议子系统

2.多点触摸(Multi-touch) 协议

在Linux多点电容触摸协议的文件介绍了多点电容触摸协议,位于Documentation/input/multitouch-protocol.txt ,多点触摸协议也简称MT协议,MT协议又分为TypeA,TypeB

  • TypeA:触摸点无法区分,即使两次相同的触摸信息,也会报告,这种类型使用较少

  • TypeB:硬件跟踪可以区分触摸点。两次相同的触摸数据不报告,而是缓存slot并通过对象slot更新触摸点的信息

本文只讨论TypeB协议,对于TypeAg感兴趣的朋友可以查看相关博客

3. 多触摸事件

触摸点的信息是通过一系列ABS_MT事件上报给Linux内核,只有ABS_MT事件用于多点触摸,ABS_MT 在文件中定义事件 include/uapi/linux/input.h 中,相关定义为

#define ABS_RESERVED  0x2e  #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 */ #define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */ #define ABS_MT_PRESSURE  0x3a /* Pressure on contact area */ #define ABS_MT_DISTANCE  0x3b /* Contact hover distance */ #define ABS_MT_TOOL_X  0x3c /* Center X tool position */ #define ABS_MT_TOOL_Y  0x3d /* Center Y tool position */ 
  • ABS_MT_SLOT:上报触点ID
  • ABS_MT_TRACKING_ID:分配触点ID,用于跟踪轨迹
  • ABS_MT_POSITION_X:报告触摸点X轴坐标信息
  • ABS_MT_POSITION_Y:报告触摸点Y轴坐标信息
  • ABS_MT_TOUCH_MAJOR:上报触摸区长轴信息(触点椭圆形)
  • ABS_MT_WIDTH_MAJOR:上报触摸区短轴信息(触点椭圆形)

4.TypeB上报时序

ABS_MT_SLOT 0    //报告触摸点序号 ABS_MT_TRACKING_ID 45  //分配触点ID ABS_MT_POSITION_X x[0]  ///报告触摸点X轴坐标信息 ABS_MT_POSITION_Y y[0]  ///报告触摸点Y轴坐标信息 ABS_MT_SLOT 1    //以下同上 ABS_MT_TRACKING_ID 46   ABS_MT_POSITION_X x[1] ABS_MT_POSITION_Y y[1] SYN_REPORT     //同步事件 
  1. 使用input_mt_slot函数 上报ABS_MT_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轴坐标和Y轴坐标 input_report_abs 来完成

    关注微信官方账号扫描二维码,回复:13297592查看本文章

  4. 和第 1~4 类似的行,只是换成了报告触摸点 1 的(X,Y)坐标信息

  5. 当所有触摸点坐标上传后,必须发送 SYN_REPORT 事件,使用 input_sync
    函数来完成

5.使用到的API函数

1.input_mt_init_slots

在编写MT驱动必须首先调用此函数的初始化slots,input_mt_init_slots()函数,原型为:

int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots,unsigned int flags) 
  • dev:具体输入设备

  • num_slots:触摸点的数量由触摸芯片决定

  • flags:接触输入设备flags信息

    #define INPUT_MT_POINTER 0x0001 /* pointer device, e.g. trackpad */触控板 #define INPUT_MT_DIRECT 0x0002 /* direct device, e.g. touchscreen */触摸屏 #define INPUT_MT_DROP_UNUSED0x0004 /* drop contacts not seen in frame */ #define INPUT_MT_TRACK 0x0008 /* use in-kernel tracking */ #define INPUT_MT_SEMI_MT 0x0010 /* semi-mt device, finger count handled manually */ 

    可以采用‘|同时设置多个操作 flags 标识

返回值:

  • 成功:0

  • 失败:负数

2.input_mt_slot 函数

该函数用于生成ABS_MT_SLOT事件告诉核心哪个触摸点的坐标数据,即触摸点的序号

static inline void input_mt_slot(struct input_dev *dev, int slot) {            input_event(dev, EV_ABS, ABS_MT_SLOT, slot); } 

参数:

  • dev : 具体输入设备
  • slot:slot对象的序号,也就是哪个触摸点

返回值:

  • 成功:0
  • 失败:负数

3.input_mt_report_slot_state 函数

用于产生 ABS_MT_TRACKING_ID 和 ABS_MT_TOOL_TYPE事 件 , 给触摸点分配ID,ABS_MT_TRACKING_ID 事 件 给 slot 关 联 一 个 ABS_MT_TRACKING_ID ,ABS_MT_TOOL_TYPE 事 件 指 定 触 摸 类 型 ( 是 笔 还 是 手 指 等 )。 此 函 数 定 义 在 文 件drivers/input/input-mt.c 中,此函数原型如下所示:

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

参数:

  • dev : 具体输入设备

  • tool_type:触摸类型

    • MT_TOOL_FINGER:手指
    • MT_TOOL_PEN:笔
    • MT_TOOL_PALM:手掌
  • active:

    • true:连续触摸,动态分配id
    • false:触摸点离开,表示触摸点无效,id为-1

4.input_report_abs 函数

Type A 和 Type B 类型都使用此函数上报触摸点坐标信息,通过 ABS_MT_POSITION_X 和ABS_MT_POSITION_Y 事 件 实 现 X 和 Y 轴 坐 标 信 息 上 报 。 此 函 数 定 义 在 文 件include/linux/input.h 中,函数原型如下所示:

static inline 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 轴坐标数据值

5.上报时序案例

drivers/input/touchscreen/ili210x.c

static void ili210x_report_events(struct input_dev *input,
const struct touchdata *touchdata)
{
    
    
	int i;
	bool touch;
	unsigned int x, y;
	const struct finger *finger;

	for (i = 0; i < MAX_TOUCHES; i++) {
    
    
		input_mt_slot(input, i);

		finger = &touchdata->finger[i];

		touch = touchdata->status & (1 << i);
		input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
		if (touch) {
    
    
			x = finger->x_low | (finger->x_high << 8);
			y = finger->y_low | (finger->y_high << 8);

			input_report_abs(input, ABS_MT_POSITION_X, x);
			input_report_abs(input, ABS_MT_POSITION_Y, y);
		}
	}

	input_mt_report_pointer_emulation(input, false);
	input_sync(input);
 }

使用 for 循环实现上报所有的触摸点坐标,调用 input_mt_slot 函数上 报 ABS_MT_SLOT 事 件 。 用input_mt_report_slot_state 函 数 上 报ABS_MT_TRACKING_ID 事件,也就是给 SLOT 关联一个ABS_MT_TRACKING_ID。使用 input_report_abs 函数上报触摸点对应的(X,Y)坐标值。使用 input_sync 函数上报 SYN_REPORT 事件

6.多点电容触摸屏驱动编写

主要用到以下知识点

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

根据上面的分析,多点电容触摸驱动的框架编写以及步骤为:

1.I2C驱动框架

 /* 传统匹配表 */
static const struct i2c_device_id xxx_ts_id[] = {
    
    
 	{
    
     "xxx", 0, },
 	{
    
     /* sentinel */ }
 };

/* 设备树匹配表 */
 static const struct of_device_id xxx_of_match[] = {
    
    
	{
    
     .compatible = "xxx", },
	 {
    
     /* sentinel */ }
 };

/* i2c设备驱动*/
static struct i2c_driver ft5x06_ts_driver = {
    
    
	.driver = {
    
    
	.owner = THIS_MODULE,
	.name = "xxx",
	.of_match_table = of_match_ptr(xxx_of_match),
},
    .id_table = xxx_ts_id,
	.probe = yyy_probe,
	.remove = zzz_remove,
};
/* 模块入口函数 */
static int __init xxx_init(void)
{
    
    
	int ret = 0;
	
	ret = i2c_add_driver(&xxx_ts_driver);

	return ret;
}

2. probe函数

初始化触摸芯片,外部中断,input子系统

static int yyy_probe(struct i2c_client *client, const struct
i2c_device_id *id)
{
    
    
	struct input_dev *input;
	//初始化触摸芯片,iic配置相关寄存器
	...
	//申请中断
	devm_request_threaded_irq(&client->dev, client->irq, NULL,
	zzz_handler, IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
	client->name, &XXX);
	
	//分配外部输入设备并初步初始化
	input = devm_input_allocate_device(&client->dev);
	
	ts->input_dev->name = "Goodix Capacitive TouchScreen";
	ts->input_dev->phys = "input/ts";
	ts->input_dev->id.bustype = BUS_I2C;
    input->dev.parent = &client->dev;
	
	//配置输入设备的事件类型
	/* 4,初始化 input 和 MT */
    //config
	__set_bit(EV_ABS, input->evbit);
	__set_bit(BTN_TOUCH, input->keybit);

    //单指触摸
	input_set_abs_params(input, ABS_X, 0, width, 0, 0);
	input_set_abs_params(input, ABS_Y, 0, height, 0, 0);
    //多指触摸
	input_set_abs_params(input, ABS_MT_POSITION_X,0, width, 0, 0);
	input_set_abs_params(input, ABS_MT_POSITION_Y,0, height, 0, 0);
	input_mt_init_slots(input, MAX_SUPPORT_POINTS,INPUT_MT_DIRECT);
	
	//初始化所有触摸点slot对象
	input_mt_init_slots(input, MAX_SUPPORT_POINTS, 0);
	
	//注册输入设备
	input_register_device(input);
	...
}
  • 设置 input_dev 需要上报的事件为 EV_ABS 和 BTN_TOUCH,因为多点电容屏的触摸坐标为绝对值,因此需要上报 EV_ABS 事件。触摸屏有按下和抬起之分,因此需要上报 BTN_TOUCH 按键。

  • 调用 input_set_abs_params 函数设置 EV_ABS 事件需要上报 ABS_X、ABS_Y、
    ABS_MT_POSITION_X 和 ABS_MT_POSITION_Y。单点触摸需要上报 ABS_X 和 ABS_Y,对于多点触摸需要上报 ABS_MT_POSITION_X 和 ABS_MT_POSITION_Y

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

3.上报坐标信息

在中断服务程序中上报读取到的坐标信息

static irqreturn_t xxx_handler(int irq, void *dev_id)
{
    
    

	int num; /* 触摸点数量 */
	int x[n], y[n]; /* 保存坐标值 */

	/* 1、从触摸芯片获取各个触摸点坐标值 */
	......

	/* 2、上报每一个触摸点坐标 */
	for (i = 0; i < num; i++) {
    
    
		input_mt_slot(input, id);
		input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
		input_report_abs(input, ABS_MT_POSITION_X, x[i]);
		input_report_abs(input, ABS_MT_POSITION_Y, y[i]);
	}
	......
	
	input_sync(input);
	......

	return IRQ_HANDLED;
 }
  • 进入中断处理程序之后先从触摸IC中读取触摸坐标以及触摸点数量,假设触摸点数量保存到 num 变量,触摸点坐标存放到 x, y 数组里面。

  • 循环上报某一个触摸点的信息,按照typeB类型的时序进行上报

  • 每一轮触摸点坐标上报完毕以后就调用一次 input_sync 函数发送一个
    SYN_REPORT 事件

猜你喜欢

转载自blog.csdn.net/weixin_43824344/article/details/119866157

 

锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章