基于I2C的嵌入式多点触摸屏幕驱动设计

发布者:创意火舞最新更新时间:2013-02-25 来源: dzsc关键字:I2C  多点触摸屏  S3C6410X 手机看文章 扫描二维码
随时随地手机看文章

  引言

  随着嵌入式设备的开发和推广,触摸屏作为新式输入设备已经随处可见,手机、PDA、MID以及ATM机等设备都已经用到了触摸屏。而科技在不断发展,触摸屏也由一开始的4线式单点电阻触摸屏发展到今天的各种多点式电容触摸屏。本文通过对以Cypress 7958为代表的I2C总线接口电容式多点触摸屏的研究,设计了针对Linux操作系统的多点触摸的屏幕驱动,以及不运行操作系统前提下的单片机对触摸屏的驱动,取得了良好的效果。

  1  研究平台介绍

  1.1  ARM11处理器S3C6410X

  S3C6410X是基于ARM1176JZFS核的用于手持、移动等终端设备的通用处理器。S3C6410X是一款低功率、高性价比、高性能的用于移动电话和通用处理RSIC处理器。为2.5G和3G通信服务提供了优化的硬件性能,采用 64/32位的内部总线架构,融合了AXI、AHB、APB总线。还有很多强大的硬件加速器,包括运动视频处理、音频处理、2D加速、显示处理和缩放。

  1.2  电容式多点触摸屏

  电容式触摸屏在触摸屏4边均镀上狭长的电极,在导电体内形成一个低电压交流电场。在触摸屏幕时,由于人体电场,手指与导体层间会形成一个耦合电容,4边电极发出的电流会流向触点,而电流强度与手指到电极的距离成正比,位于触摸屏幕后的控制器会计算电流的比例及强弱,准确算出触摸点的位置。电容触摸屏的双玻璃不但能保护导体及感应器,更有效地防止外在环境因素对触摸屏造成影响,就算屏幕沾有污秽、尘埃或油渍,电容式触摸屏依然能准确算出触摸位置。与电阻触摸屏相对比,电容式触摸屏就是支持多点触摸的人机交互方式,普通电阻式触摸屏只能进行单一点的触控。

  1.3  ARM工具链

  本文针对ARM核的单片机使用了armnonelinuxgnueabi4.3.2交叉编译链,实现对ARM支持的二进制文件编译,用以成功编译ARMLinux 2.6.28内核。

  1.4  移植条件

  对于本文所述内容,所有支持Linux操作系统运行的处理器(包括嵌入式处理器)都可以运行,而所有支持I2C总线协议的单片机也可以在不使用操作系统的前提下将触摸屏作为一种普通输入设备进行使用。

  2  研究过程

  图1显示了本文中针对嵌入式Linux平台下的驱动软硬件结构体系。

驱动软硬件结构体系

图1  驱动软硬件结构体系

  2.1  I2C设备在平台部分声明

  Cypress 7958多点触摸屏的I2C地址为0x20,在使用前需要在平台设备处进行I2C设备声明,这样才可以使Linux驱动找到其对应的I2C地址进行操作。首先要声明该I2C设备结构体,代码如下:

  static struct i2c_board_info i2c_devs1[] __initdata={

  {I2C_BOARD_INFO("cypress7958", 0x20), }, /*cypress7958 touch pannel controller*/

  };

  然后在static void __init smdk6410_machine_init(void)函数中声明该I2C设备:

  i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1));

  2.2  Cypress 7958驱动部分设计

  2.2.1  注册和注销模块

  首先建立I2C驱动结构体,cypress_7958_driver,代码如下:

  static struct i2c_driver cypress_7958_driver={

  .probe=cypress_7958_probe,

  .remove=cypress_7958_remove,

  .id_table=cypress_7958_id,

  .driver={

  .name=CYPRESS_7958_NAME,

  },

  };[page]

  然后建立_INIT初始化函数与_EXIT注销设备函数:static int __devinit cypress_7958_ts_init(void),static void __exit cypress_7958_exit(void),通过i2c_add_driver与i2c_del_driver函数进行I2C设备的注册与注销。

  2.2.2  触摸屏驱动入口函数的设计

  由上节中声明的I2C结构体得知,在设备被检查到的时候进入static int synaptics_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)函数,在该函数中需要进行触摸屏工作模式的初始化,对作为输入设备的触摸屏驱动在Linux平台下的设备名注册,同时初始化触摸事件触发时引起的中断操作。

  (1) Cypress 7958模式初始化

  作为多点触摸屏幕,Cypress 7958有很多相关的配置寄存器,本文中不再赘述,初始化部分仅需对屏幕是否工作在正常工作模式下进行检查,通过读取0x28地址的寄存器,如果值为0x07,则屏幕工作正常,否则返回错误值。

  ret=i2c_smbus_read_byte_data(ts>client, 0x28);

  if(ret!=0x07){

  printk(KERN_ERR,"Cypress Detect Errorn");

  return ret;

  }

  (2) 输入设备名注册

  创建struct input_dev结构体,通过input_allocate_device()函数进行设备名的创建,然后通过set_bit函数进行输入设备功能声明。因为是多点触摸屏,可以产生EV_SYN,EV_KEY,BTN_TOUCH,BTN_2(多点触摸),EV_ABS等功能,故对之进行声明:

  set_bit(EV_SYN, ts>input_dev>evbit);

  set_bit(EV_KEY, ts>input_dev>evbit);

  set_bit(BTN_TOUCH, ts>input_dev>keybit);

  set_bit(BTN_2, ts>input_dev>keybit);

  set_bit(EV_ABS, ts>input_dev>evbit);

  然后完成对事件的具体配置:

  input_set_abs_params(ts>input_dev, ABS_X, 0, max_y, 0, 0);

  input_set_abs_params(ts>input_dev, ABS_Y, 0, max_x, 0, 0);

  input_set_abs_params(ts>input_dev, ABS_PRESSURE, 0, 255, 0, 0);

  input_set_abs_params(ts>input_dev, ABS_TOOL_WIDTH, 0, 15, 0, 0);

  input_set_abs_params(ts>input_dev, ABS_HAT0X, 0, max_y, 0, 0);

  input_set_abs_params(ts>input_dev, ABS_HAT0Y, 0, max_x, 0, 0);

  input_set_abs_params(ts>input_dev, ABS_MT_POSITION_X, 0, max_y, 0, 0);

  input_set_abs_params(ts>input_dev, ABS_MT_POSITION_Y, 0, max_x, 0, 0);

  input_set_abs_params(ts>input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);

  input_set_abs_params(ts>input_dev, ABS_MT_WIDTH_MAJOR, 0, 15, 0, 0);

  最后通过input_register_device(ts>input_dev)函数完成对该设备名的注册。

  (3) 驱动事件产生中断函数初始化

  Cypress 7958触摸屏在触摸事件产生时会在IRQ引脚产生一个低电平信号,将该引脚连接到GPN(15)引脚上,同时创建GPIO中断函数:

  s3c_gpio_cfgpin(S3C64XX_GPN(15),S3C_GPIO_SFN(2));

  client>irq=gpio_to_irq(S3C64XX_GPN(15));

  irqflags=IRQF_TRIGGER_LOW;

  然后通过ret=request_irq(client>irq, cypress_7958_irq_handler, irqflags, client>name, ts)进行中断函数申请。创建cypress_7958_irq_handler函数:

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

  struct synaptics_ts_data *ts=dev_id;

  //int ret=gpio_get_value(S3C64XX_GPN(15));

  //printk("%s:ret=%dn",__func__,ret);

  disable_irq_nosync(ts>client>irq);

  queue_work(cypress_7958_wq, &ts>work);

  return IRQ_HANDLED;

  }[page]

  当驱动事件被触发之后通过queue_work函数进入驱动工作区cypress_7958_wq,进行驱动层对应用层的信息上报。

  2.2.3  触摸屏工作区函数设计

  触摸屏工作区函数需要完成事件信息获取以及驱动层对应用层的信息上报功能,通过INIT_WORK(&ts>work, cypress_7958_work_func)函数完成驱动工作区函数的初始化声明,在驱动事件中断产生之后进入工作区函数cypress_7958_work_func。

  (1) 触摸屏事件信息获取

  Cypress 7958的事件触发信息存储在寄存器中,只需要通过 i2c_smbus_read_byte_data函数对其寄存器信息进行读取即可完成其事件信息的获取,也可以通过i2c_transfer完成对其寄存器信息的批量读取:

  buf[0]=i2c_smbus_read_byte_data(ts>client, 0x12);

  buf[1]=i2c_smbus_read_byte_data(ts>client, 0x13);

  buf[2]=i2c_smbus_read_byte_data(ts>client, 0x14);

  buf[3]=i2c_smbus_read_byte_data(ts>client, 0x15);

  buf[4]=i2c_smbus_read_byte_data(ts>client, 0x16);

  buf[5]=i2c_smbus_read_byte_data(ts>client, 0x17);

  buf[6]=i2c_smbus_read_byte_data(ts>client, 0x18);

  buf[7]=i2c_smbus_read_byte_data(ts>client, 0x19);

  buf[8]=i2c_smbus_read_byte_data(ts>client, 0x1a);

  buf[9]=i2c_smbus_read_byte_data(ts>client, 0x1b);

  buf[10]=i2c_smbus_read_byte_data(ts>client, 0x1c);

  buf[11]=i2c_smbus_read_byte_data(ts>client, 0x1d);

  buf[12]=i2c_smbus_read_byte_data(ts>client, 0x1e);

  buf[13]=i2c_smbus_read_byte_data(ts>client, 0x1f);

  (2) 触摸屏事件信息上报

  通过对buf数组的分析,获取当前事件具体信息,然后通过input_report系列函数进行事件信息的应用层上报:

  if(fingermark==2){

  input_report_key(ts>input_dev,ABS_MT_TRACKING_ID,0);

  input_report_abs(ts>input_dev, ABS_MT_TOUCH_MAJOR, f1z);

  input_report_abs(ts>input_dev, ABS_MT_POSITION_X, f1x);

  input_report_abs(ts>input_dev, ABS_MT_POSITION_Y, f1y);

  input_mt_sync(ts>input_dev);

  input_report_key(ts>input_dev,ABS_MT_TRACKING_ID,1);

  input_report_abs(ts>input_dev, ABS_MT_TOUCH_MAJOR, f2z);

  input_report_abs(ts>input_dev, ABS_MT_POSITION_X, f2x);

  input_report_abs(ts>input_dev, ABS_MT_POSITION_Y, f2y);

  input_mt_sync(ts>input_dev)

  input_sync(ts>input_dev);

  }

  else if(fingermark==1){

  input_report_key(ts>input_dev,ABS_MT_TRACKING_ID,0);

  input_report_abs(ts>input_dev, ABS_MT_TOUCH_MAJOR, f1z);

  input_report_abs(ts>input_dev, ABS_MT_POSITION_X, f1x);

  input_report_abs(ts>input_dev, ABS_MT_POSITION_Y, f1y);

  input_mt_sync(ts>input_dev);

  input_sync(ts>input_dev);

  }

  else{

  input_report_abs(ts>input_dev, ABS_MT_TOUCH_MAJOR, 0);

  input_mt_sync(ts>input_dev);

  input_sync(ts>input_dev);

  }

  2.3  Cypress 7958驱动在内核中的移植

  通过改写Makefile与KCONFIG完成Cypress 7985在内核中的移植,以帮助GCC工具链实现对内核的编译。

  2.3.1  Kconfig的修改

  在/driver/input/touchscreen/Kconfig中添加如下语句:

  config TOUCHSCREEN_CYPRESS

  tristate "CYPRESS 7958 touchscreens"

  help

  Say Y here if you have a CYPRESS 7958 touchscreen connected to your system.

  If unsure, say N.

  以实现将文件编译选项添加到MAKE MENUCONFIG中。由于触摸屏驱动属于系统基本输入设备驱动,本身调用了I/O中断,不能实现模块编译,只能完全编译进内核。在后续的研发中发现可以使用时钟中断将其模块化编译进内核,但由于时钟中断影响UCLINUX时间片的运行,故弃之不用。

  2.3.2  Makefile的修改

  然后在/driver/input/touchscreen/Makefile中添加对应编译信息:

  obj$(CONFIG_TOUCHSCREEN_CYPRESS) +=touchscreen_cypress.o

  最终在编译选项中将/MAKEFILE中的ARCH选项设置为S3C6410,在make menuconfig命令之后的选项中选择TOUCHSREEN_CYPRESS选项并选择编译进内核。

  结语

  本设计以I2C方式对多点触摸屏进行驱动,通过嵌入式Linux将多点触摸输入方式应用到嵌入式应用系统中,丰富了单一的键盘输入与单点输入方式, 减小了系统尺寸,提高了系统的可靠性。使得嵌入式系统的输入方式简单易行,同时也增强了嵌入式系统与人之间的通信能力,简化了繁琐的调试。采用三星公司的S3C6410 ARM11处理器,加快了实验的操作步骤。实践证明,该设计驱动多点触摸屏幕的速度以及稳定性满足调试要求。该设计只需对底层驱动进行简单修改,就可直接应用于单片机以及其他全部可以运行Linux的嵌入式系统中。

参考文献:

[1]. MID datasheet http://www.dzsc.com/datasheet/MID_2043364.html.
[2]. help datasheet http://www.dzsc.com/datasheet/help_1082360.html.

关键字:I2C  多点触摸屏  S3C6410X 引用地址:基于I2C的嵌入式多点触摸屏幕驱动设计

上一篇:对51转到ARM的新人的一些建议
下一篇:SHT15在嵌入式系统中的应用方案

推荐阅读最新更新时间:2024-03-16 13:19

STM8 中I2C读写函数
void I2C_write(u8 Addr, u8 *WriteData, u8 length) { /* Send STRAT condition */ I2C_GenerateSTART(ENABLE); /* Test on EV5 and clear it */ while(!I2C_CheckEvent(I2C_EVENT_MASTER_START_SENT)); /* Send EEPROM address for write */ I2C_Send7bitAddress(Addr, I2C_DIRECTION_TX); /* Test on EV6 and clear it */ while(!
[单片机]
STM32F10x_硬件I2C读写EEPROM(标准外设库版本)
Ⅰ、写在前面 上一篇文章是“STM32F10x_模拟I2C读写EEPROM”,讲述使用IO口模拟I2C总线通信,对EEPROM(AT24Xxx)进行读写操作的过程。 上一篇文章主要内容:I2C协议、模拟I2C底层驱动、EEPROM(AT24Xxx)单字节读写操作。 本文主要内容:STM32硬件I2C详细配置、EEPROM(AT24Xxx)多字节读写操作、ST官方I2C存在问题。 实例实验效果: 1、多字节读写:任意地址(66), 写入任意长度(129)、读取并打印出来 2、单字节读写:任意地址(0),写入1字节数据、 读取并打印出来 实验说明: 1.多字节读写 实验为什么是从66地址写? 为什么
[单片机]
STM32F10x_硬件<font color='red'>I2C</font>读写EEPROM(标准外设库版本)
STM32F051 I2C slave mode
用STM32F051的I2C从模式做某模块的控制接口,通过主机读状态和写控制命令。 Eclips 环境,gcc编译器,相关源码如下: #ifdef DEBUG_I2C_EN #define DEBUG_I2C(...) printf(__VA_ARGS__) #else #define DEBUG_I2C(...) #endif void I2C_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; I2C_InitTypeDef I2C_InitStructure; NVIC_InitTypeDef NVIC_InitStructure;
[单片机]
C51IO口模拟I2C总线驱动AT24C16 (EEPROM部分)
/* 名称:C51IO口模拟I2C总线驱动AT24C16 说明:关于EEPROM,即这里的AT24C16是一个特殊形式的FLASH存储器,不过其容量一般较少。比较适合于存储少量的数据。 AT24C16的通信接口是标准的I2C通信,即我们需要根据I2C通信协议来操纵EEPROM设备。 关于AT24C16的的各种操作,这里就不细讲了,简单介绍一下。 (1)、主机向AT24C16写一个字节:首先需要发送设备地址,然后发送需要访问的存储器地址。然后在发送要写入的数据。这里省略了开始、结束和确认等信号的产生。 (2)、指定页写入n个字节:和(1)的基本操作很类似。不同的是可以连续写入n个数据。这里要小注意一点的就是,写入的数
[单片机]
S5PV210开发 -- I2C 你知道多少?(二)
上一篇主要是介绍了下芯片手册 I2C 部分,都应该看些什么,以及上拉电阻取值和传输速率模式选择。 这一篇该来点程序了,首先以 AT24C02 (EEPROM)为基础介绍一下I2C设备驱动编程,然后以 MT9P031 为基础介绍 LINUX 下内核配置。 最后是 MPU6050 为基础的单片机下 I2C 通信程序。 一、I2C设备驱动编程 该部分我会以嵌入式Linux软硬件开发详解第 12 章,和Linux设备驱动开发详解第 15 章为参考来展开。 (1)I2C 设备驱动程序结构 1. I2C设备驱动层次结构 从系统的角度来看,Linux中 I2C 设备程序所处的位置如下图所示。 I2C设备驱动程序包含总线驱动层和
[单片机]
S5PV210开发 -- <font color='red'>I2C</font> 你知道多少?(二)
I2C总线的基本操作
  I2C总线上只具有SOL(时钟)和SDA(数据)2根信号线。如果是单纯的串行传输,一旦因为某种原因造成引脚的偏差,则可能会造成不能区分总线上传输的是数据还是地址信息的后果。解决上述问题的简单办法就是附加独立于总线的Reset(复位)信号,由主机控制该信号。因为I2C至少利用2根线进行所有的操作,因此在数据传输时,通常当SCL为低电平时,设置下一个数据;当SDA变化后,SCI为高电平,这可以解释为一连串操作的开始/结束。 1. 起始条件 始条件表示一系列操作的开始。图1表示起始条件以及随后数据传输的开始操作。在I2C总线的空闲状态下,SDA及SCL通过上拉电阻都为高电平。在这样的状态下,如果SCL仍保持高电平,而
[嵌入式]
基于嵌入式Linux 的I2C设备驱动程序的分析
  0 引言   由于I2C总线的通用性,Linux作为一款优秀的嵌入式操作系统,也必须要对其要有很好的支持。在Linux内核源码中对I2C总线的驱动是基于总线设备驱动模型的,其驱动程序用到了特殊的几个数据结构,对I2C总线协议进行了更抽象更通用的定义,极大的增加了设备驱动的可移植性。要编写出自己的I2C 设备驱动程序,必须对这种内核I2C总线驱动的架构有深刻的理解。   1 I2C总线的硬件构成   I2C 总线协议只有两条总线线路,一条是串行数据线(SDA),一条是串行时钟线(SCL)。SDA 负责数据的传输,SCL 负责数据传输的时钟同步。I2C 设备通过这两条总线连接到处理器的I2C总线控制器上,不同设备之间通过7
[单片机]
基于嵌入式Linux 的<font color='red'>I2C</font>设备驱动程序的分析
基于I2C总线的处理器的联网设计方案
    随着微控制器的价格越来越低,功能越来越强大,电气设计人员发现在单板和多板系统中都使用多个小型控制器是一种更加经济高效的方法。这种辅助处理器能够减轻主处理器在耗时任务上面的处理开销,例如扫描键盘、显示控制器和电机控制。这些控制器也可以配置为各种各样的专用外设。   最近,我接受了一项任务:开发一种能够方便地适用于多种应用的接口(软/硬件),且要符合嵌入式处理器中常用的行业标准。在分析了一些典型应用之后,我们列出了一些针对该硬件接口的设计需求:常用于32位和8位处理器;能够得到常用外设器件的支持;外设接口代码量低于0.5kB;引脚数量少;数据带宽可达10kBps;RAM用量少;一条总线上支持多种外设;方便使用API;不需要外部
[嵌入式]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved