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.
Previous article:11. LCD driver
Next article:26.3.4.2 I2C Driver under Kernel (I)
- Popular Resources
- Popular amplifiers
- Learn ARM development(16)
- Learn ARM development(17)
- Learn ARM development(18)
- Embedded system debugging simulation tool
- A small question that has been bothering me recently has finally been solved~~
- Learn ARM development (1)
- Learn ARM development (2)
- Learn ARM development (4)
- Learn ARM development (6)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
- Detailed explanation of intelligent car body perception system
- How to solve the problem that the servo drive is not enabled
- Why does the servo drive not power on?
- What point should I connect to when the servo is turned on?
- How to turn on the internal enable of Panasonic servo drive?
- What is the rigidity setting of Panasonic servo drive?
- How to change the inertia ratio of Panasonic servo drive
- What is the inertia ratio of the servo motor?
- Is it better for the motor to have a large or small moment of inertia?
- What is the difference between low inertia and high inertia of servo motors?
- [Silicon Labs BG22-EK4108A Bluetooth Development Evaluation] Part 2: First Experience with the Development Environment
- MCU application architecture arrangement
- Application of power amplifier in electrostatic suspension system
- Inexpensive fiber optic transceiver
- Design of wireless network sensor based on Bluetooth protocol
- Design and implementation of a fast and effective broadband power amplifier matching circuit
- SparkRoad-V thermal imaging data acquisition and display
- GD32VF103 modified firmware library for Gigabit RISC-V core
- [Silicon Labs BG22-EK4108A Bluetooth Development Evaluation] 1. Unboxing and Evaluation
- Raspberry Pi MCU RP2040 is now on sale, priced at $1. Do you want to stock up?