触摸屏使用过程
1.按下,产生中断pen_down_up_irq
2.在中断处理程序里面启动ADC,转换坐标(x,y)
3.ADC结束之后,产生ADC中断
4.在ADC中断处理函数里面上报事件(input_event),启动定时器。
5.定时器时间到(处理长按、滑动)
5.1如果触摸笔松开,进入等待按下模式
5.2否则,再次再一次测量x,y,再次启动ADC
初始化函数
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);
/* 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); //按下触摸屏,产生中断,pen_down_up_irq:中断处理函数
request_irq(IRQ_ADC, adc_irq, IRQF_SAMPLE_RANDOM, "adc", NULL); //ADC完成之后产生的中断,adc_irq:中断处理函数
/* 优化措施1:
* 设置ADCDLY为最大值, 这使得电压稳定后再发出IRQ_TC中断
*/
s3c_ts_regs->adcdly = 0xffff;
/* 优化措施5: 使用定时器处理长按,滑动的情况
*
*/
init_timer(&ts_timer); //初始化,传入定时器地址&ts_timer
ts_timer.function = s3c_ts_timer_function; //超时函数
add_timer(&ts_timer); //把定时器告诉内核,当超时后,s3c_ts_timer_function被调用
enter_wait_pen_down_mode(); //设置等待触摸笔按下模式,让寄存器ADCTSC=0xd3,进入等待中断模式Waiting for Interrupt Mode
return 0;
}
按键按下后,产生的中断函数
pen_down_up_irq()
static irqreturn_t pen_down_up_irq(int irq, void *dev_id)
{
/*如何判断按下还是松开? ADCDAT0的bit[15],0表示按下,1表示松开
松开的时候进入等待按下模式enter_wait_pen_down_mode(),这样他就继续处理下一次。
*/
if (s3c_ts_regs->adcdat0 & (1<<15)) //松开
{
//printk("pen up\n");
input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0); //上报事件,ABS_PRESSURE压力值为0
input_report_key(s3c_ts_dev, BTN_TOUCH, 0); //BTN_TOUCH表示按键类事件,没有按下按键
input_sync(s3c_ts_dev);
enter_wait_pen_down_mode(); //触摸笔按下模式
}
else //按下
{
//printk("pen down\n");
//enter_wait_pen_up_mode();
enter_measure_xy_mode(); //测量x,y坐标模式
start_adc(); //启动ADC
}
return IRQ_HANDLED;
}
进入测量x,y坐标模式
static void enter_measure_xy_mode(void)
{
s3c_ts_regs->adctsc = (1<<3)|(1<<2); //bit[3]=1 禁止上拉使能,上拉电阻要断开,bit[2]=1设置模式3自动(连续)的x/y坐标转换模式
}
启动ADC
static void start_adc(void)
{
s3c_ts_regs->adccon |= (1<<0); //设置启动ADCCON寄存器bit[0]=1,就启动ADC
}
ADC结束,产生ADC中断
static irqreturn_t adc_irq(int irq, void *dev_id) //ADC 完成之后,产生一个中断
{
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,