您的位置 首页 元件

触摸屏驱动程序(输入子系统)

includelinuxerrnohincludelinuxkernelhincludelinuxmodulehincludelinuxslabhincludelinuxinputhincludeli

#include “linux/errno.h”

#include“linux/kernel.h”
#include“linux/module.h”
#include“linux/slab.h”
#include“linux/input.h”
#include“linux/init.h”
#include“linux/serio.h”
#include“linux/delay.h”
#include“linux/platform_device.h”
#include“linux/clk.h”
#include“asm/io.h”
#include“asm/irq.h”
#include“asm/plat-s3c24xx/ts.h”
#include“asm/arch/regs-adc.h”
#include“asm/arch/regs-gpio.h”
struct s3c_ts_regs {
unsigned long adccon;
unsigned long adctsc;
unsigned long adcdly;
unsigned long adcdat0;
unsigned long adcdat1;
unsigned long adcupdn;
};
static struct input_dev *s3c_ts_dev;
static volatile struct s3c_ts_regs *s3c_ts_regs;
static struct timer_list ts_timer;
//比及触控笔按下形式
static void enter_wait_pen_down_mode(void)
{
s3c_ts_regs->adctsc = 0xd3;
}
//比及触控笔松开形式
static void enter_wait_pen_up_mode(void)
{
s3c_ts_regs->adctsc = 0x1d3;
}
//进入X/Y方向ADC一起转化形式
static void enter_measure_xy_mode(void)
{
s3c_ts_regs->adctsc = (1<<3)|(1<<2);
}
//发动ADC转化
static void start_adc(void)
{
s3c_ts_regs->adccon |= (1<<0);
}
static int s3c_filter_ts(int x[], int y[])
{
#define ERR_LIMIT 10
int avr_x, avr_y;
int det_x, det_y;
avr_x = (x[0] + x[1])/2;
avr_y = (y[0] + y[1])/2;
det_x = (x[2] > avr_x) ? (x[2] – avr_x) : (avr_x – x[2]);
det_y = (y[2] > avr_y) ? (y[2] – avr_y) : (avr_y – y[2]);
if ((det_x > ERR_LIMIT) || (det_y > ERR_LIMIT))
return 0;
avr_x = (x[1] + x[2])/2;
avr_y = (y[1] + y[2])/2;
det_x = (x[3] > avr_x) ? (x[3] – avr_x) : (avr_x – x[3]);
det_y = (y[3] > avr_y) ? (y[3] – avr_y) : (avr_y – y[3]);
if ((det_x > ERR_LIMIT) || (det_y > ERR_LIMIT))
return 0;
return 1;
}
static void s3c_ts_timer_function(unsigned long data)
{
if (s3c_ts_regs->adcdat0 & (1<<15))
{
// 现已松开
input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0);
input_report_key(s3c_ts_dev, BTN_TOUCH, 0);
input_sync(s3c_ts_dev);
enter_wait_pen_down_mode();
}
else
{
// 丈量X/Y坐标
enter_measure_xy_mode();
start_adc();
}
}
//触控笔按下、抬起中止服务函数
static irqreturn_t pen_down_up_irq(int irq, void *dev_id)
{
if (s3c_ts_regs->adcdat0 & (1<<15))
{
//printk(“pen up\n”);
input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0);
input_report_key(s3c_ts_dev, BTN_TOUCH, 0);
input_sync(s3c_ts_dev);
enter_wait_pen_down_mode();
}
else
{
//printk(“pen down\n”);
//enter_wait_pen_up_mode();
enter_measure_xy_mode();
start_adc();
}
return IRQ_HANDLED;
}
static irqreturn_t adc_irq(int irq, void *dev_id)
{
static int cnt = 0;
static int x[4], y[4];
int adcdat0, adcdat1;
// 优化办法2: 假如ADC完结时, 发现接触笔现已松开, 则丢掉此次成果
adcdat0 = s3c_ts_regs->adcdat0;
adcdat1 = s3c_ts_regs->adcdat1;
if (s3c_ts_regs->adcdat0 & (1<<15))
{
// 现已松开
cnt = 0;
input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0);
input_report_key(s3c_ts_dev, BTN_TOUCH, 0);
input_sync(s3c_ts_dev);
enter_wait_pen_down_mode();
}
else
{
// printk(“adc_irq cnt = %d, x = %d, y = %d\n”, ++cnt, adcdat0 & 0x3ff, adcdat1 & 0x3ff);
// 优化办法3: 屡次丈量求平均值
x[cnt] = adcdat0 & 0x3ff;
y[cnt] = adcdat1 & 0x3ff;
++cnt;
if (cnt == 4)
{
// 优化办法4: 软件过滤
if (s3c_filter_ts(x, y))
{
//printk(“x = %d, y = %d\n”, (x[0]+x[1]+x[2]+x[3])/4, (y[0]+y[1]+y[2]+y[3])/4);
input_report_abs(s3c_ts_dev, ABS_X, (x[0]+x[1]+x[2]+x[3])/4);
input_report_abs(s3c_ts_dev, ABS_Y, (y[0]+y[1]+y[2]+y[3])/4);
input_report_abs(s3c_ts_dev, ABS_PRESSURE, 1);
input_report_key(s3c_ts_dev, BTN_TOUCH, 1);
input_sync(s3c_ts_dev);
}
cnt = 0;
enter_wait_pen_up_mode();
// 发动守时器处理长按/滑动的状况
mod_timer(&ts_timer, jiffies + HZ/100);
}
else
{
enter_measure_xy_mode();
start_adc();
}
}
return IRQ_HANDLED;
}
static int s3c_ts_init(void)
{
struct clk* clk;
// 1. 分配一个input_dev结构体
s3c_ts_dev = input_allocate_device();
// 2. 设置
// 2.1 能发生哪类事情
set_bit(EV_KEY, s3c_ts_dev->evbit); //按键类事情
set_bit(EV_ABS, s3c_ts_dev->evbit); //肯定位移类事情
// 2.2 能发生这类事情里的哪些事情
set_bit(BTN_TOUCH, s3c_ts_dev->keybit);
input_set_abs_params(s3c_ts_dev, ABS_X, 0, 0x3FF, 0, 0);
input_set_abs_params(s3c_ts_dev, ABS_Y, 0, 0x3FF, 0, 0);
input_set_abs_params(s3c_ts_dev, ABS_PRESSURE, 0, 1, 0, 0);//按压力度:1表明按下、0松开
// 3. 注册
input_register_device(s3c_ts_dev);
// 4. 硬件相关的操作
//4.1 使能时钟(CLKCON[15])
clk = clk_get(NULL, “adc”);
clk_enable(clk);
// 4.2 设置S3C2440的ADC/TS寄存器
s3c_ts_regs = ioremap(0x58000000, sizeof(struct s3c_ts_regs));
//bit[14] : 1-A/D converter prescaler enable
* bit[13:6]: A/D converter prescaler value,
* 49, ADCCLK=PCLK/(49+1)=50MHz/(49+1)=1MHz
* bit[0]: A/D conversion starts by enable. 先设为0
//
s3c_ts_regs->adccon = (1<<14)|(49<<6);
request_irq(IRQ_TC, pen_down_up_irq, IRQF_SAMPLE_RANDOM, “ts_pen”, NULL);
request_irq(IRQ_ADC, adc_irq, IRQF_SAMPLE_RANDOM, “adc”, NULL);
// 优化办法1:
// 设置ADCDLY为最大值, 这使得电压安稳后再宣布IRQ_TC中止
s3c_ts_regs->adcdly = 0xffff;
//优化办法5: 运用守时器处理长按,滑动的状况
init_timer(&ts_timer);
ts_timer.function = s3c_ts_timer_function;
add_timer(&ts_timer);
enter_wait_pen_down_mode();
return 0;
}
static void s3c_ts_exit(void)
{
free_irq(IRQ_TC, NULL);
free_irq(IRQ_ADC, NULL);
iounmap(s3c_ts_regs);
input_unregister_device(s3c_ts_dev);
input_free_device(s3c_ts_dev);
del_timer(&ts_timer);
}
module_init(s3c_ts_init);
module_exit(s3c_ts_exit);
MODULE_LICENSE(“GPL”);
================================================================
解析:
加载驱动今后运转s3c_ts_init函数,程序进入等候触控笔按下形式enter_wait_pen_down_mode(),当有触控笔按下时进入按下中止服务函数中运转,即pen_down_up_irq中,进入中止服务函数后当即判别触控笔是否仍然按下,假如这个时分触控笔现已松开则上报事情;若此刻触控笔仍然按下则进入X/Y双方向一起进行ADC转化形式,并发动ADC转化。当ADC转化完结今后进入ADC中止服务程序,从adcdat0、adcdat1获取到x方向、y方向的ADC数据,再判别触控笔是否脱离,假如现已脱离则进行上报数据;不然保存此次ADC转化数据再判别ADC收集到的数据有没有到4次,假如累计到4次则进行软件滤波后上报事情,进入等候触控笔脱离形式enter_wait_pen_up_mode,一起发动守时器开端计时处理接连按压事情;假如不行4次则再次进入X/Y双方向一起进行ADC转化形式,并发动ADC转化。当守时时刻到了今后进入守时中止服务函数里,判别触控笔是否脱离,假如触控笔松开则上报事情,进入等候触控笔按下形式,不然再次进入X/Y双方向一起进行ADC转化形式,并发动ADC转化。顺次!
测验2th~7th:
1. make menuconfig 去掉本来的接触屏驱动程序
-> Device Drivers
-> Input device support
-> Generic input layer
-> Touchscreens
<> S3C2410/S3C2440 touchscreens
make uImage
运用新内核发动
2. insmod s3c_ts.ko
按下/松开接触笔
测验2th~7th:
1. ls /dev/event*
2. insmod s3c_ts.ko
3. ls /dev/event*
4. hexdump /dev/event0
微秒 type code value
0000000 29a4 0000 8625 0008 0003 0000 0172 0000
0000010 29a4 0000 8631 0008 0003 0001 027c 0000
0000020 29a4 0000 8634 0008 0003 0018 0001 0000
0000030 29a4 0000 8638 0008 0001 014a 0001 0000
0000040 29a4 0000 863c 0008 0000 0000 0000 0000
0000050 29a4 0000 c85e 0008 0003 0000 0171 0000
0000060 29a4 0000 c874 0008 0003 0001 027d 0000
0000070 29a4 0000 c87b 0008 0000 0000 0000 0000
0000080 29a4 0000 ed37 0008 0003 0018 0000 0000
0000090 29a4 0000 ed48 0008 0001 014a 0000 0000
00000a0 29a4 0000 ed4a 0008 0000 0000 0000 0000
lcd和接触屏联合运用参阅”tslib编译运用方法“
//暂时疏忽下面三行指令
//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 //装置到tmp目录
装置:
cd tmp
再把tmp目录下的4个文件全都拷贝到开发板的根目录下
cp * /home/book/workspace/JZ2440_TestFile/system/first_fs-rfd
(选用网络文件体系发动时开发板的根目录,可是此刻并没有拷贝到开发板的flash上面,假如要拷贝到开发板的flash上面能够不必网络文件体系发动,选用手动挂载的方法把文件体系挂载到开发板的mnt目录下,在从mnt目录下把tmp里的文件拷贝到开发板的根目录下面,这样就算真实的在开发板的flash上面了。)
运用:
先装置s3c_ts.ko, lcd.ko
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

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/xinpin/yuanjian/263380.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部