12. Touch screen driver

Publisher:sclibinLatest update time:2021-07-20 Source: eefocus Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

The touch screen subsystem is implemented through the input subsystem, corresponding to the device node /dev/input/eventn. After becoming familiar with the routine, focus on writing hardware programs.


1. Simple analysis of the kernel's built-in touch screen driver S3c2410_ts

S3c2410_ts.c (driversinputtouchscreen) The kernel comes with Samsung's touch screen driver

(1) Entry function:


/*Register a platform driver*/static int __init s3c2410ts_init(void){// init_MUTEX(&gADClock); returnplatform_driver_register(&s3c2410ts_driver);}

(2) platform_driver structure


static struct platform_drivers 3c2410ts_driver = { .driver = { .name = "s3c2410-ts", .owner = THIS_MODULE, }, .probe = s3c2410ts_probe, .remove = s3c2410ts_remove,};/*When there is a device with the same name in the kernel, the probe function s3c2410ts_probe will be called*/

(3) What does static int __init s3c2410ts_probe(structplatform_device *pdev) do?


  /*Allocate an input_dev structure*/input_dev = input_allocate_device();

/*Set what events can be generated, key events, absolute position events*/ts.dev = input_dev;ts.dev->evbit[0]= BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);ts.dev->keybit[LONG(BTN_TOUCH)]= BIT(BTN_TOUCH);/*Set the parameters of absolute position*/ input_set_abs_params(ts.dev,ABS_X, 0, 0x3FF, 0, 0);//Absolute displacement direction input_set_abs_params(ts.dev,ABS_Y, 0, 0x3FF, 0, 0); input_set_abs_params(ts.dev,ABS_PRESSURE, 0, 1, 0, 0); ts.dev->private= &ts; ts.dev->name= s3c2410ts_name; ts.dev->id.bustype= BUS_RS232; ts.dev->id.vendor= 0xDEAD; ts.dev->id.product= 0xBEEF; ts.dev->id.version= S3C2410TSVERSION;/*Register*/ input_register_device(ts.dev);

(4) touch_timer_fire reports an event when it occurs


/*Report event*/input_report_abs--》input_event

2. Refer to S3c2410_ts to write S3C2440 touch screen driver from scratch

Touch screen usage process

a. Press to generate an interrupt

b. In the interrupt handler, start ADC to convert coordinates.

c. ADC ends and an ADC interrupt is generated.

d. In the ADC interrupt processing function, report (input_event) and start the timer.

e. Timer time is up (handle long press and slide operations.)

f. Release

The specific principle of measuring coordinates of the touch screen can be found at https://blog.csdn.net/qq_16933601/article/details/102749277


Allocate input_dev structure

static struct input_dev *s3c_ts_dev;/* 1. Allocate an input_dev structure*/

s3c_ts_dev = input_allocate_device();

set up

/* 2. Setting*//* 2.1 What kind of events can be generated*/set_bit(EV_KEY, s3c_ts_dev->evbit);/*Touch screen absolute displacement event*/set_bit(EV_ABS, s3c_ts_dev->evbit);/* 2.2 Which events in this type of event can be generated*/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);

register

/* 3. Register */ input_register_device(s3c_ts_dev);

Hardware related operations

/* 4. Hardware related operations*//* 4.1 Enable clock (CLKCON[15]) *//* When the kernel starts, irrelevant modules will be turned off. CLKCON starts various modules*/

clk = clk_get(NULL, "adc");clk_enable(clk);/* 4.2 Set the ADC/TS register of S3C2440*/

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. Set to 0 first

 */

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);/* Optimization 1: 

 * Set ADCDLY to the maximum value, which will cause the IRQ_TC interrupt to be issued after the voltage stabilizes

 */

s3c_ts_regs->adcdly = 0xffff;/* Optimization measure 5: Use timer to handle long press and sliding

 * 

 */init_timer(&ts_timer);

ts_timer.function = s3c_ts_timer_function;add_timer(&ts_timer);enter_wait_pen_down_mode();return 0;}

Other related sub-functions

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;}static void enter_measure_xy_mode(void){

s3c_ts_regs->adctsc = (1<<3)|(1<<2);}static void start_adc(void){

s3c_ts_regs->adccon |= (1<<0);}static int s3c_filter_ts(int x[], int y[]){#define ERR_LIMIT 10int 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)){/* Already released*/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{/* Measure X/Y coordinates*/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 upn");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 downn");//enter_wait_pen_up_mode();/*Measure xy*/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;/* Optimization measure 2: If the touch pen is released when ADC is completed, the result will be discarded*/

adcdat0 = s3c_ts_regs->adcdat0;

adcdat1 = s3c_ts_regs->adcdat1;if (s3c_ts_regs->adcdat0 & (1<<15)){/* Already released*/

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 = %dn", ++cnt, adcdat0 & 0x3ff, adcdat1 & 0x3ff);/* Optimization measure 3: multiple measurements to find the average value*/

x[cnt] = adcdat0 & 0x3ff;

y[cnt] = adcdat1 & 0x3ff;++cnt;if (cnt == 4){/* Optimization measure 4: software filtering*/if (s3c_filter_ts(x, y)){//printk("x = %d, y = %dn", (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();/* Start the timer to handle long press/slide*/mod_timer(&ts_timer, jiffies + HZ/100);}else{enter_measure_xy_mode();start_adc();}}return IRQ_HANDLED;}

quit

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);}

Register initialization and exit functions

module_init(s3c_ts_init);module_exit(s3c_ts_exit);MODULE_LICENSE("GPL");

test

a. ls /dev/event*

b. insmod s3c_ts.ko

c. ls /dev/event*

d. hexdump /dev/event0

          Seconds Microseconds 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


Compile tslib


export TSLIB_TSDEVICE=/dev/event1 //Which touch screen is itexport TSLIB_CALIBFILE=/etc/pointercal //Verification file location After verification, generate the verification file in /etc/pointercalexport TSLIB_CONFFILE=/etc/ts.conf //Configuration file locationexport TSLIB_PLUGINDIR=/lib/ts //Plug-in locationexport TSLIB_CONSOLEDEVICE=none 

export TSLIB_FBDEVICE=/dev/fb0 //Display screen

At this point the touch screen driver has been successfully transplanted.


Reference address:12. Touch screen driver

Previous article:11. LCD driver
Next article:26.3.4.2 I2C Driver under Kernel (I)

Latest Microcontroller Articles
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号