触摸屏归纳为输入子系统,这里主要是针对电阻屏,其使用过程如下

当用触摸笔按下时,产生中断。
在中断处理函数处理函数中启动ADC转换x,y坐标。
ADC结束,产生ADC中断
在ADC中断处理函数里上报(input_event)启动定时器
再次启动定时器(可以处理滑动、长按)
松开按键
其驱动程序的写法和之前写输入子系统的写法基本上一致。
写出入口函数,出口函数并加以修饰,加入相关头文件,然后开始完善各函数,在入口函数中分配input_dev结构体,设置(能产生哪类事件,能产生这类事件中的哪些事件),注册设备,硬件相关的操作等。出口函数中主要对之前注册、分配的一些资源进行释放。
还应根据2440数据手册ADC转换和触摸屏那一章,对相关寄存器根据实际需要进行设置。

点击(此处)折叠或打开

  1. #include <linux/errno.h>
  2. #include <linux/kernel.h>
  3. #include <linux/module.h>
  4. #include <linux/slab.h>
  5. #include <linux/input.h>
  6. #include <linux/init.h>
  7. #include <linux/serio.h>
  8. #include <linux/delay.h>
  9. #include <linux/platform_device.h>
  10. #include <linux/clk.h>
  11. #include <asm/io.h>
  12. #include <asm/irq.h>
  13. #include <asm/plat-s3c24xx/ts.h>
  14. #include <asm/arch/regs-adc.h>
  15. #include <asm/arch/regs-gpio.h>
  16. struct s3c_ts_regs {                     /* 相关的寄存器 */
  17. unsigned long adccon;
  18. unsigned long adctsc;
  19. unsigned long adcdly;
  20. unsigned long adcdat0;
  21. unsigned long adcdat1;
  22. unsigned long adcupdn;
  23. };
  24. static struct input_dev *s3c_ts_dev;
  25. static volatile struct s3c_ts_regs *s3c_ts_regs;
  26. static struct timer_list ts_timer;
  27. void enter_wait_pen_down_mode(void) /* 进入等待触摸笔按下模式 */
  28. {
  29. s3c_ts_regs->adctsc = 0xd3; /* 进入等待中断模式 bit[8]为0 2440手册P442 */
  30. }
  31. void enter_wait_pen_up_mode(void) /* 进入等待触摸笔松开模式 */
  32. {
  33. s3c_ts_regs->adctsc = 0x1d3; /* 进入等待中断模式 bit[8]为1 2440手册P442 */
  34. }
  35. static void enter_measure_xy_mode(void) /* 进入xy测量模式 */
  36. {
  37. s3c_ts_regs->adctsc = (1<<3) | (1<<2);
  38. }
  39. static void start_adc(void)
  40. {
  41. s3c_ts_regs->adccon |= (1<<0); /* 启动ADC */
  42. }
  43. static int s3c_filter_ts(int x[], int y[]) /* 软件过滤 */
  44. {
  45. #define ERR_LIMIT 10      /* 经验值,容差值 */
  46. int avr_x, avr_y;
  47. int det_x, det_y;
  48. avr_x = (x[0] + x[1])/2;
  49. avr_y = (y[0] + y[1])/2;
  50. det_x = (x[2] > avr_x) ? (x[2] - avr_x) : (avr_x - x[2]);
  51. det_y = (y[2] > avr_y) ? (y[2] - avr_y) : (avr_y - y[2]);
  52. if ((det_x > ERR_LIMIT) || (det_y > ERR_LIMIT))
  53. return 0;
  54. avr_x = (x[1] + x[2])/2;
  55. avr_y = (y[1] + y[2])/2;
  56. det_x = (x[3] > avr_x) ? (x[3] - avr_x) : (avr_x - x[3]);
  57. det_y = (y[3] > avr_y) ? (y[3] - avr_y) : (avr_y - y[3]);
  58. if ((det_x > ERR_LIMIT) || (det_y > ERR_LIMIT))
  59. return 1;
  60. }
  61. static void s3c_ts_timer_functions(unsigned long data)
  62. {
  63. if (s3c_ts->adcdat0 & (1<<15)) /* 假设时间到 */
  64. {
  65. /* 如果触摸已经松开 */
  66. input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0); /* 上报事件,压力值为0 */
  67. input_report_key(s3c_ts_dev, BTN_TOUCH, 0);
  68. input_sync(s3c_ts_dev); /* 上报完后要同步 */
  69. enter_wait_pen_down_mode(); /* 进入触摸等待模式 */
  70. }
  71. else
  72. {
  73. /* 否则测量x,y坐标 */
  74. enter_measure_xy_mode();
  75. start_adc();
  76. }
  77. }
  78. static irqreturn_t pen_down_up_irq(int irq, void *dev id)
  79. {
  80. if (s3c_ts->adcdat0 & (1<<15)) /* 2440手册P447 ADCDAT0寄存器 */
  81. {
  82. printk("pen up\n");
  83. enter_wait_pen_down_mode();
  84. }
  85. else
  86. {
  87. //printk("pen down\n");
  88. //enter_wait_pen_up_mode();
  89. enter_measure_xy_mode();
  90. start_adc();
  91. }
  92. return IRQ_HANDLED;
  93. }
  94. static irqreturn_t adc_irq(int irq, void *dev id)
  95. {
  96. static int cnt = 0;
  97. static int x[4], y[4];
  98. int adcdat0, adcdat1;
  99. /* 优化措施2
  100. * 如果ACD完成时,发现触摸笔已松开,则丢弃此次结果
  101. */
  102. adcdat0 = s3c_ts_regs->adcdat0;
  103. adcdat1 = s3c_ts_regs->adcdat1;
  104. if (s3c_ts->adcdat0 & (1<<15)) /* bit[15]判断是否松开 */
  105. {
  106. /* 如果已经松开则丢弃结果 */
  107. cnt = 0;
  108. input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0); /* 上报事件,压力值为0 */
  109. input_report_key(s3c_ts_dev, BTN_TOUCH, 0);
  110. input_sync(s3c_ts_dev);
  111. enter_wait_pen_up_mode();
  112. }
  113. else
  114. {
  115. /* 如果还是按下,则打印结果并进入等待松开模式 */
  116. //printk("adc_irq cnt = %d,x = %d, y = %d\n", ++cnt, adcdat0 & 0x3ff, adcdat1 & 0x3ff);
  117. /* 优化措施3:
  118. * 多次测量取平均值
  119. */
  120. x[cnt] = adcdat0 & 0x3ff; /* 将测量结果存入静态变量中 */
  121. y[cnt] = adcdat1 & 0x3ff;
  122. ++cnt;
  123. if (cnt == 4)
  124. {
  125. /* 优化措施4
  126. * 软件过滤
  127. */
  128. if (s3c_filter_ts(x, y))
  129. {
  130. //printk("x = %d, y = %d\n", (x[0]+x[1]+x[2]+x[3])/4, (y[0]+y[1]+y[2]+y[3])/4);
  131. input_report_abs(s3c_ts_dev, ABS_X, (x[0]+x[1]+x[2]+x[3])/4);
  132. input_report_abs(s3c_ts_dev, ABS_Y, (y[0]+y[1]+y[2]+y[3])/4);
  133. input_report_abs(s3c_ts_dev, ABS_PRESSURE, 1);
  134. input_report_key(s3c_ts_dev, BTN_TOUCH, 1);
  135. input_sync(s3c_ts_dev);
  136. }
  137. cnt = 0; /* cnt计数清0 */
  138. enter_wait_pen_up_mode(); /* 测量完后要进入等待松开模式,这样才能连续操作 */
  139. /* 启动定时器处理长按/滑动的情况 */
  140. mod_timer(&ts_timer, jiffies + HZ/100); /* 1HZ/100 = 10ms */
  141. }
  142. else /* 否则再测量一次 */
  143. {
  144. enter_measure_xy_mode();
  145. start_adc();
  146. }
  147. }
  148. return IRQ_HANDLED;
  149. }
  150. static int s3c_ts_init(void)
  151. {
  152. struct clk* clk;
  153. /* 1.分配一个input_dev结构体 */
  154. s3c_ts_dev = input_allocate_device();
  155. /* 2.设置 */
  156. /* 2.1 能产生哪类事件 */
  157. set_bit(EV_KEY, s3c_ts_dev->evbit); /* 能够产生按键事件 */
  158. set_bit(EV_ABS, s3c_ts_dev->evbit); /* 能够产生绝对位移事件 */
  159. /* 2.2 能产生这类事件里的哪些事件 */
  160. set_bit(BTN_TOUCH, s3c_ts_dev->evbit); /* 能够产生按键类里面的触摸屏事件 */
  161. input_set_abs_params(s3c_ts_dev, ABS_X, 0, 0x3FF, 0, 0); /* X方向 0xFF是因为触摸屏ADC是10位 */
  162. input_set_abs_params(s3c_ts_dev, ABS_Y, 0, 0x3FF, 0, 0); /* Y方向 */
  163. input_set_abs_params(s3c_ts_dev, ABS_PRESSURE, 0, 1, 0, 0);/* 压力方向 */
  164. /* 3.注册 */
  165. input_register_device(s3c_ts_dev);
  166. /* 4.硬件相关的操作 */
  167. /* 4.1 使能时钟CLKCON[15] (总开关,一般对不用的设备,时钟一般是关闭的) */
  168. clk = clk_get(NULL, "adc");
  169. clk_enable(clk);
  170. /* 4.2 设置S3c2440的ADC/TS寄存器 */
  171. s3c_ts_regs = ioremap(0x58000000, sizeof(struct s3c_ts_regs));
  172. /* ADCCON
  173. * bit[14] : 1 预分频使能
  174. * bit[13:6] : 预分频系数
  175. * 49 ,ADCCLK = PCLK/(49+1) = 50MHz/(49+1)=1MHz
  176. * bit[5:3] : 多路选择
  177. * bit[2] : 省电模式选择
  178. * bit[1] : AD启动方式,通过读来启动
  179. * bit[0] : 启动AD转换,启动后会自动清零
  180. */
  181. s3c_ts_regs->adccon = (1<<14) | (49<<6);
  182. request_irq(IRQ_TC, pen_down_up_irq, IRQF_SAMPLE_RANDOM, "ts_pen", NULL);
  183. request_irq(IRQ_ADC, adc_irq, IRQF_SAMPLE_RANDOM, "adc", NULL);
  184. /* 优化措施1
  185. * 设置ADCDLY为最大值,使得电压稳定后再发出中断IRQ_TC
  186. */
  187. s3c_ts_regs->adcdly = 0xffff;
  188. /* 优化措施5
  189. * 使用定时器,用来解决连按或滑动
  190. */
  191. init_timer(&ts_timer);
  192. ts_timer.function = s3c_ts_timer_function;
  193. add_timer(&ts_timer);
  194. enter_wait_pen_down_mode();
  195. return 0;
  196. }
  197. static void s3c_ts_exit(void)
  198. {
  199. free_irq(IRQ_TC, NULL);
  200. free_irq(IRQ_ADC, NULL);
  201. iounmap(s3c_ts_regs);
  202. input_unregister_device(s3c_ts_dev);
  203. input_free_device(s3c_ts_dev);
  204. del_timer(&ts_timer);
  205. }
  206. module_init(s3c_ts_init);
  207. module_exit(s3c_ts_exit);
  208. MODULE_DESCRIPTION("s3c_ts driver for the s3c2440");
  209. MODULE_LICENSE("GPL");
测试方法主要是检测上报事件是否正常,要想更好的测试,需要移植ts_lib这方面的资料网上都可以找到。
以tslib-1.4.tar.gz为例
sudo apt-get install autoconf
sudo apt-get install automake
sudo apt-get install libtool
编译:
tar xzf tslib-1.4.tar.gz
cd tslib
./autogen.sh 
mkdir tmp      // 安装目录
echo "ac_cv_func_malloc_0_nonnull=yes" >arm-linux.cache
./configure --host=arm-linux --cache-file=arm-linux.cache --prefix=$(pwd)/tmp
make
make install
安装:
cd tmp
cp * -rf /nfsroot    //  /nfsroot可根据实际情况来定
使用:
先安装s3c_ts.ko, lcd.ko     // lcd.ko是之前编译好的LCD驱动,如果后面编译s3c_ts时改过配置,直接装载之前编译好的lcd.ko可能会出现段错误,重新编译一下lcd驱动就可以了。
1.
修改 /etc/ts.conf第1行(去掉#号和第一个空格):
# module_raw input
改为:
module_raw input
2.
export TSLIB_TSDEVICE=/dev/event0
export TSLIB_CALIBFILE=/etc/pointercal
export TSLIB_CONFFILE=/etc/ts.conf
export TSLIB_PLUGINDIR=/lib/ts
export TSLIB_CONSOLEDEVICE=none
export TSLIB_FBDEVICE=/dev/fb0
ts_calibrate
ts_test

<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>

阅读(167) | 评论(0) | 转发(0) |

0

上一篇:H.264技术在视频监控领域的应用前景

下一篇:关于系统调用 (初学者可以看下)

相关热门文章
  • Win7重装打印机驱动
  • 欢迎回收笔记本在ChinaUnix博...
  • 欢迎云算笔记在ChinaUnix博客...
  • Linux TTY设备驱动
  • linux中的块设备和字符设备 (...
  • A sample .exrc file for vi e...
  • IBM System p5 服务器 HACMP ...
  • 游标的特征
  • busybox的httpd使用CGI脚本(Bu...
  • Solaris PowerTOP 1.0 发布
给主人留下些什么吧!~~
评论热议

Linux驱动学习笔记之触摸屏驱动相关推荐

  1. Linux驱动开发学习笔记-电容触摸屏驱动

    <电容触摸屏驱动框架> 电容触摸屏驱动其实是以下几种 linux 驱动框架的组合: ① IIC 设备驱动,因为电容触摸 IC 基本都是 IIC 接口的,因此大框架就是 IIC 设备驱动. ...

  2. linux 驱动学习笔记-ALSA声卡驱动(二)

    前言 ASoC是建立在标准ALSA驱动层上 ,对底层的alsa框架封装了一层,为了更好的支持嵌入式cpu和音频解码器设备的一套软件体系 在ASOC出现之前 解码器驱动和平台CPU驱动联系过于紧密,导致 ...

  3. linux2.6驱动学习笔记之字符驱动

    1.字符驱动组成 1.1字符驱动的模块加载与卸载 //设备结构体模板 struct xxx_dev_t { struct cdev cdev; ...... }xxx_dev; 在字符驱动模块加载函数 ...

  4. Linux内核学习笔记之网卡驱动的详细分析:RTL8139

    学习应该是一个先把问题简单化,在把问题复杂化的过程.一开始就着手处理复杂的问题,难免让 人有心惊胆颤,捉襟见肘的感觉.读Linux网卡驱动也是一样.那长长的源码夹杂着那些我们陌生的变量和符号,望而生畏 ...

  5. linux 驱动学习笔记-ALSA声卡驱动(一)

    概述 ALSA作为Liunx现在主流的音频体系结构,提供了内核的驱动框架,也提供了应用层的alsa-lib库,应用层主要调用alsa-lib的API函数就可以实现对声卡的控制.ALSA也提供了alsa ...

  6. 【嵌入式环境下linux内核及驱动学习笔记-(16)linux总线、设备、驱动模型之input框架】

    目录 1.Linux内核输入子系统概念导入 1.1 输入设备工作机制 1.2 运行框架 1.3 分层思想 2.驱动开发步骤 2.1 在init()或probe()函数中 2.2 在exit()或rem ...

  7. Linux驱动学习笔记

    驱动学习笔记 1.字符设备驱动 Linux 驱动有两种运行方式 第一种就是将驱动编译进 Linux 内核中,这样当 Linux 内核启 动的时候就会自动运行驱动程序. 第二种就是将驱动编译成模块(Li ...

  8. 【嵌入式环境下linux内核及驱动学习笔记-(15-1)例程】

    目录 1.在APP直接调用标准文件IO操作I2C(针对学习笔记-15的15.3节) 1.1 mail.c 1.2 mpu6050.h 1.3 mpu6050.c 1.4 Makefile 2.以外称i ...

  9. Linux 驱动学习笔记 - beep(九)

    Linux 驱动学习笔记 - beep(九) 本系列均为正点原子 Linux 驱动的学习笔记, 以便加深笔者记忆.如读者想进一步学习,可以到正点原子官网中下载资料进行学习. 添加 pinctrl 节点 ...

最新文章

  1. Mysql提示缺少表的别名报错_mysql对sql中别名引起的Column not found问题
  2. 【Leetcode】100. 相同的树
  3. Codemirror-开源在线代码编辑器
  4. Exchange2003表单和OWA选项中更改密码设置
  5. Russ Miles:被忽略的架构师和混沌工程
  6. 数据结构:希尔排序(shell sort)
  7. mysql 插入数据 自增长_MySQL ------ 插入数据(INSERT和insert select)(二十)
  8. python中的ideavim有什么作用_Pycharm和Idea支持的vim插件的方法
  9. Redis:安装、配置、操作和简单代码实例(C语言Client端)[转]
  10. 基础拾遗------泛型详解
  11. Windows Mobile开发资源相关下载收录
  12. php找不到phpmyadmin,phpMyAdmin 安装配置方法和问题解决
  13. jq 修改swal的标题_js-jquery-SweetAlert2【一】使用
  14. poj 3279 poj 1753
  15. 江苏大学矩阵论、数理统计期末考试复习
  16. python学习笔记第六节(函数,装饰器)
  17. Android可收缩伸展的Expandable分组RecyclerView
  18. C#多线程和线程池 【转】
  19. 悉尼大学计算机专业本科2019,2019申请悉尼大学读本科有哪些要求
  20. 数字未来,NFT未来,Game Farmer创始人胡烜峰在IGS上讲述FoxNFT和他的故事

热门文章

  1. su切换特别慢 linux,秋明 | 系统su切换用户时间非常长
  2. 云管边端架构图_新通信行业:阿里云构建云管边端物联网布局
  3. 检索报告计算机类,计算机类的检索报告.docx
  4. AC算法的高效C++实现
  5. 攻防世界 MISC新手练习区 刷12道题题所得的思路和方法
  6. 微信机器人-定制消息
  7. O2O常见的结算模式是什么 O2O线上线下营销策略有哪些?
  8. 快过年了,用五种不同的JS特效带你看烟花
  9. 网络原理:TCP/UDP
  10. c语言电话本程序代码,C语言程序设计之电话簿