触摸屏驱动笔记


这是我看韦东山第2期视频触摸屏驱动的一些笔记,记录方便以后学习。

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

当用触摸笔按下时,产生中断。

在中断处理函数处理函数中启动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. 

14. #include <asm/plat-s3c24xx/ts.h>

15. 

16. #include <asm/arch/regs-adc.h>

17. #include <asm/arch/regs-gpio.h>

18. 

19. struct s3c_ts_regs {                     /* 相关的寄存器 */

20.     unsigned long adccon;

21.     unsigned long adctsc;

22.     unsigned long adcdly;

23.     unsigned long adcdat0;

24.     unsigned long adcdat1;

25.     unsigned long adcupdn;

26. };

27. 

28. static struct input_dev *s3c_ts_dev;

29. static volatile struct s3c_ts_regs *s3c_ts_regs;

30. 

31. static struct timer_list ts_timer;

32. 

33. void enter_wait_pen_down_mode(void) /* 进入等待触摸笔按下模式 */

34. {

35.     s3c_ts_regs->adctsc = 0xd3; /* 进入等待中断模式 bit[8]为0 2440手册P442 */

36. }

37. 

38. void enter_wait_pen_up_mode(void) /* 进入等待触摸笔松开模式 */

39. {

40.     s3c_ts_regs->adctsc = 0x1d3; /* 进入等待中断模式 bit[8]为1 2440手册P442 */

41. }

42. 

43. static void enter_measure_xy_mode(void) /* 进入xy测量模式 */

44. {

45.     s3c_ts_regs->adctsc = (1<<3) | (1<<2);

46. }

47. 

48. static void start_adc(void)

49. {

50.     s3c_ts_regs->adccon |= (1<<0); /* 启动ADC */

51. }

52. 

53. static int s3c_filter_ts(int x[], int y[]) /* 软件过滤 */

54. {

55. #define ERR_LIMIT 10      /* 经验值,容差值 */   

56. 

57.     int avr_x, avr_y;

58.     int det_x, det_y;

59.     

60.     avr_x = (x[0] + x[1])/2;

61.     avr_y = (y[0] + y[1])/2;

62. 

63.     det_x = (x[2] > avr_x) ? (x[2] - avr_x) : (avr_x - x[2]);

64.     det_y = (y[2] > avr_y) ? (y[2] - avr_y) : (avr_y - y[2]);

65. 

66.     if ((det_x > ERR_LIMIT) || (det_y > ERR_LIMIT))

67.         return 0;

68.     

69.     avr_x = (x[1] + x[2])/2;

70.     avr_y = (y[1] + y[2])/2;

71. 

72.     det_x = (x[3] > avr_x) ? (x[3] - avr_x) : (avr_x - x[3]);

73.     det_y = (y[3] > avr_y) ? (y[3] - avr_y) : (avr_y - y[3]);

74. 

75.     if ((det_x > ERR_LIMIT) || (det_y > ERR_LIMIT))

76.         return 1;

77. }

78. 

79. static void s3c_ts_timer_functions(unsigned long data)

80. {

81.     if (s3c_ts->adcdat0 & (1<<15)) /* 假设时间到 */ 

82.     {

83.         /* 如果触摸已经松开 */

84.         input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0); /* 上报事件,压力值为0 */

85.         input_report_key(s3c_ts_dev, BTN_TOUCH, 0);

86.         input_sync(s3c_ts_dev); /* 上报完后要同步 */

87.         enter_wait_pen_down_mode(); /* 进入触摸等待模式 */

88.     }

89.     else

90.     {

91.         /* 否则测量x,y坐标 */

92.         enter_measure_xy_mode();

93.         start_adc();

94.     }

95.         

96. }

97. 

98. static irqreturn_t pen_down_up_irq(int irq, void *dev id)

99. {

100.     if (s3c_ts->adcdat0 & (1<<15)) /* 2440手册P447 ADCDAT0寄存器 */

101.     {

102.         printk("pen up\n");

103.         enter_wait_pen_down_mode();

104.     }

105.     else

106.     {

107.         //printk("pen down\n"); 

108.         //enter_wait_pen_up_mode();

109.         enter_measure_xy_mode();

110.         start_adc();

111.     }

112.     return IRQ_HANDLED;

113. }

114. 

115. static irqreturn_t adc_irq(int irq, void *dev id)

116. {

117.     static int cnt = 0;

118.     static int x[4], y[4];

119.     int adcdat0, adcdat1;

120.     /* 优化措施2

121.      * 如果ACD完成时,发现触摸笔已松开,则丢弃此次结果

122.      */

123.     adcdat0 = s3c_ts_regs->adcdat0;

124.     adcdat1 = s3c_ts_regs->adcdat1;

125.     if (s3c_ts->adcdat0 & (1<<15)) /* bit[15]判断是否松开 */

126.     {

127.         /* 如果已经松开则丢弃结果 */

128.         cnt = 0;

129.         input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0); /* 上报事件,压力值为0 */

130.         input_report_key(s3c_ts_dev, BTN_TOUCH, 0);

131.         input_sync(s3c_ts_dev);

132.         enter_wait_pen_up_mode();

133.     }

134.     else

135.     {

136.         /* 如果还是按下,则打印结果并进入等待松开模式 */

137.         //printk("adc_irq cnt = %d,x = %d, y = %d\n", ++cnt, adcdat0 & 0x3ff, adcdat1 & 0x3ff);

138.         

139.         /* 优化措施3:

140.          * 多次测量取平均值

141.          */

142.         x[cnt] = adcdat0 & 0x3ff; /* 将测量结果存入静态变量中 */

143.         y[cnt] = adcdat1 & 0x3ff;

144.         ++cnt;

145.         if (cnt == 4)

146.         {

147.             /* 优化措施4

148.              * 软件过滤

149.              */

150.              if (s3c_filter_ts(x, y))

151.             {

152.                 //printk("x = %d, y = %d\n", (x[0]+x[1]+x[2]+x[3])/4, (y[0]+y[1]+y[2]+y[3])/4); 

153.                 input_report_abs(s3c_ts_dev, ABS_X, (x[0]+x[1]+x[2]+x[3])/4);

154.                 input_report_abs(s3c_ts_dev, ABS_Y, (y[0]+y[1]+y[2]+y[3])/4);

155.                 input_report_abs(s3c_ts_dev, ABS_PRESSURE, 1);

156.                 input_report_key(s3c_ts_dev, BTN_TOUCH, 1);

157.                 input_sync(s3c_ts_dev);

158.             }

159.             cnt = 0; /* cnt计数清0 */

160.             enter_wait_pen_up_mode(); /* 测量完后要进入等待松开模式,这样才能连续操作 */

161. 

162.             /* 启动定时器处理长按/滑动的情况 */

163.             mod_timer(&ts_timer, jiffies + HZ/100); /* 1HZ/100 = 10ms */

164.         }

165.         else /* 否则再测量一次 */

166.         {

167.             enter_measure_xy_mode();

168.             start_adc();

169.         } 

170.     }

171.         return IRQ_HANDLED;

172. }

173. 

174. static int s3c_ts_init(void)

175. {

176.     struct clk* clk;

177.     /* 1.分配一个input_dev结构体 */

178.     s3c_ts_dev = input_allocate_device();

179.     /* 2.设置 */

180.     /* 2.1 能产生哪类事件 */

181.     set_bit(EV_KEY, s3c_ts_dev->evbit); /* 能够产生按键事件 */

182.     set_bit(EV_ABS, s3c_ts_dev->evbit); /* 能够产生绝对位移事件 */

183.     

184.     /* 2.2 能产生这类事件里的哪些事件 */

185.     set_bit(BTN_TOUCH, s3c_ts_dev->evbit); /* 能够产生按键类里面的触摸屏事件 */

186. 

187.     input_set_abs_params(s3c_ts_dev, ABS_X, 0, 0x3FF, 0, 0); /* X方向 0xFF是因为触摸屏ADC是10位 */

188.     input_set_abs_params(s3c_ts_dev, ABS_Y, 0, 0x3FF, 0, 0); /* Y方向 */

189.     input_set_abs_params(s3c_ts_dev, ABS_PRESSURE, 0, 1, 0, 0);/* 压力方向 */

190.     

191.     /* 3.注册 */

192.     

193.     input_register_device(s3c_ts_dev);

194.     

195.     /* 4.硬件相关的操作 */

196.     /* 4.1 使能时钟CLKCON[15] (总开关,一般对不用的设备,时钟一般是关闭的) */

197.     clk = clk_get(NULL, "adc");

198.     clk_enable(clk);

199.     

200.     /* 4.2 设置S3c2440的ADC/TS寄存器 */

201.     s3c_ts_regs = ioremap(0x58000000, sizeof(struct s3c_ts_regs));

202.     /* ADCCON

203.      * bit[14] : 1 预分频使能

204.      * bit[13:6] : 预分频系数

205.      * 49 ,ADCCLK = PCLK/(49+1) = 50MHz/(49+1)=1MHz

206.      * bit[5:3] : 多路选择

207.      * bit[2] : 省电模式选择

208.      * bit[1] : AD启动方式,通过读来启动

209.      * bit[0] : 启动AD转换,启动后会自动清零

210.      */

211.     s3c_ts_regs->adccon = (1<<14) | (49<<6);

212.     request_irq(IRQ_TC, pen_down_up_irq, IRQF_SAMPLE_RANDOM, "ts_pen", NULL);

213.     request_irq(IRQ_ADC, adc_irq, IRQF_SAMPLE_RANDOM, "adc", NULL);

214.     

215.     /* 优化措施1 

216.      * 设置ADCDLY为最大值,使得电压稳定后再发出中断IRQ_TC

217.      */

218.     s3c_ts_regs->adcdly = 0xffff;

219. 

220.     /* 优化措施5

221.      * 使用定时器,用来解决连按或滑动

222.      */

223.     init_timer(&ts_timer);

224.     ts_timer.function = s3c_ts_timer_function;

225.     add_timer(&ts_timer);

226.     

227.     enter_wait_pen_down_mode();

228.     return 0;

229. }

230. 

231. static void s3c_ts_exit(void)

232. {

233.     free_irq(IRQ_TC, NULL);

234.     free_irq(IRQ_ADC, NULL);

235.     iounmap(s3c_ts_regs);

236.     input_unregister_device(s3c_ts_dev);

237.     input_free_device(s3c_ts_dev);

238.     del_timer(&ts_timer);

239. }

240. 

241. 

242. module_init(s3c_ts_init);

243. module_exit(s3c_ts_exit);

244. 

245. MODULE_DESCRIPTION("s3c_ts driver for the s3c2440");

246. 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

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值