This is the third article in the mini2440 driver analysis series. This article is divided into three parts. The first part talks about hardware knowledge, including the principle of touch screen and how the touch screen on SCC2440 SOC works. The second part analyzes the framework of the input device subsystem and performs corresponding code analysis. The third part uses the above principles to analyze the touch screen driver of mini2440. The fourth part introduces testing and calibration.
1. Hardware knowledge to be prepared
1.1 Working principle of resistive touch screen Principle The
touch screen is attached to the surface of the display and used in conjunction with the display. If the coordinate position of the touch point on the screen can be measured, the intention of the toucher can be obtained based on the display content or icon of the corresponding coordinate point on the display. Touch screens can be divided into five categories according to their technical principles: vector pressure sensing, resistive, capacitive, infrared, and surface acoustic wave. Among them, resistive touch screens are more commonly used in embedded systems. The resistive touch screen is a 4-layer transparent composite film screen, as shown in Figure 2. The bottom is a base layer made of glass or organic glass, the top is a plastic layer with a hardened outer surface that is smooth and scratch-resistant, and in the middle are two metal conductive layers, one on the base layer and the other on the inner surface of the plastic layer. There are many small transparent isolation points between the two conductive layers to separate them. When a finger touches the screen, the two conductive layers touch at the touch point. The
two metal conductive layers of the touch screen are the two working surfaces of the touch screen. A silver glue is coated at both ends of each working surface, which is called a pair of electrodes of the working surface. If a voltage is applied to the electrode pair of a working surface, a uniform and continuous parallel voltage distribution will be formed on the working surface. As shown in Figure 4, when a certain voltage is applied to the electrode pair in the X direction and no voltage is applied to the electrode pair in the Y direction, in the X parallel voltage field, the voltage value at the touch point can be reflected on the Y+ (or Y-) electrode. By measuring the voltage of the Y+ electrode to the ground, the X coordinate value of the touch point can be obtained. Similarly, when voltage is applied to the Y electrode pair and no voltage is applied to the X electrode pair, the Y coordinate of the touch point can be obtained by measuring the voltage of the X+ electrode. There are two types of resistive touch screens: four-wire and five-wire. The X working surface and Y working surface of the four-wire touch screen are added to two conductive layers respectively, and there are four lead wires, which are connected to the X electrode pair and Y electrode pair of the touch screen respectively. The five-wire touch screen adds both the X working surface and the Y working surface to the conductive coating of the glass base layer, but when working, the voltage is still applied in time-sharing, that is, the voltage fields in two directions are allowed to work in time-sharing on the same working surface, and the outer conductive layer is only used as a conductor and voltage measurement electrode. Therefore, the lead wires of the five-wire touch screen need to be 5.
1.2 Touch screen interface in S3C2440
SOC The touch screen interface of S3C2440 is combined with the ADC interface. The block diagram is as follows:
Conversion rate: When PCLK=50MHz, the division frequency is set to 49, then the 10-bit conversion calculation is as follows:
When the GCLK frequency is 50MHz and the prescaler value is 49,
A/D converter freq. = 50MHz/(49+1) = 1MHz
Conversion time = 1/(1MHz / 5cycles) = 1/200KHz = 5 us
This A/D converter was designed to operate at maximum 2.5MHz clock, so the conversion rate can go up to 500 KSPS.
The modes of the touch screen interface are as follows:
normal ADC conversion mode
Independent X/Y position conversion mode
Automatic X/Y position conversion mode
Wait for interrupt mode
We mainly accept the wait for interrupt mode and automatic X/Y position conversion mode of the touch screen interface (used in the driver):
The operation flow of the automatic conversion mode is as follows: The touch screen controller automatically converts the touch position of X and Y. When the conversion is completed, the data is stored in the registers ADCDAT0 and ADCDAT1 respectively. And the INT_ADC interrupt is generated to notify the completion of the conversion.
Waiting for interrupt mode:
Touch Screen Controller generates interrupt (INT_TC) signal when the Stylus is down. Waiting for Interrupt Modesetting value is rADCTSC=0xd3; // XP_PU, XP_Dis, XM_Dis, YP_Dis, YM_En.When
touched, the touch screen controller generates INT_TC interrupt. The four pin settings should be:
Pin XP XM YP YM
Status PULL UP/XP Disable Disable (The initial value is) Disable Enable
Setting 1 0 1 1When
the interrupt is generated, the X/Y position data can be read in independent X/Y position conversion mode and automatic X/Y position conversion mode. To read in automatic X/Y position conversion mode, we need to change the TSC register we have set, on the basis of the original or on S3C2410_ADCTSC_PULL_UP_DISABLE | S3C2410_ADCTSC_AUTO_PST | S3C2410_ADCTSC_XY_PST(0).
After the data conversion is completed, an interrupt will also be generated.
2. Input subsystem model analysis
2.1 Overall framework:
The input subsystem consists of three parts: device driver, input core, and event processor.
The first part is the input device driver connected to each bus. On our SOC, this bus can be a virtual bus platformbus. Their role is to convert the underlying hardware input into a unified event format and report to the input core. The
second part of the input core is as follows:
(1) Call input_register_device() used to add devices, and call input_unregister_device() to remove devices. (This will be discussed in conjunction with the touch screen driver below.)
(2) The corresponding device information is generated under /PROC. The following example is:
/proc/bus/input/devices showing a USB mouse:
I: Bus=0003 Vendor=046d Product=c002 Version=0120
N: Name="Logitech USB-PS/2 Mouse M-BA47"
P: Phys=usb-00:01.2-2.2/input0
H: Handlers=mouse0 event2
B: EV=7
B: KEY=f0000 0 0 0 0 0 0 0
B: REL=103
(3) Notify the event handler to process the event
The third part is the event handler:
the input subsystem includes the large-scale handlers you need, such as mouse, keyboard, joystick, touch screen, and a general handler called event handler (for kernel file evdev.C). It should be noted that as the kernel version develops, the event handler will be used to handle more input events of different hardware. In Linux 2.6.29, the only specific device event handlers left are mouse and joystick. This means that more and more input devices will interact with user space through event handlers. The main function of the event handling layer is to interact with user space. We know that Linux treats all devices as files in user space. In general drivers, fops interfaces are provided, and corresponding device files nod are generated under /dev. In the input subsystem driver, these actions are all completed at the event handler layer. Let's take a look at the relevant code of evdev.C.
static int __init evdev_init(void)
{
return input_register_handler(&evdev_handler);
}
This is the registration procedure of the module and will be called when the system is initialized.
The initialization process is very simple, just one sentence, but all the secrets are hidden in evdev_handler:
static struct input_handler evdev_handler = {
.event = evdev_event,
.connect = evdev_connect,
.disconnect = evdev_disconnect,
.fops = &evdev_fops,
.minor = EVDEV_MINOR_BASE,
.name = "evdev",
.id_table = evdev_ids,
};
First look at the following code in the connect function:
snprintf(evdev->name, sizeof(evdev->name), "event%d", minor);
evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);
evdev->handle.dev = input_get_device(dev);
evdev->handle.name = evdev->name;
dev_set_name(&evdev->dev, evdev->name);
evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);
evdev->dev.class = &input_class;
evdev->dev.parent = &dev->dev;
evdev->dev.release = evdev_free;
device_initialize(&evdev->dev);
error = device_add(&evdev->dev);
Note the black part. This will be generated in the directory /sys/device/viture/input/input0/event0. Under event, there will be a dev attribute file, which stores the device number of the device file. In this way, udev can read
the attribute file to obtain the device number, and then create the device node /dev/event0 in the /dev directory.
Let's look at the evdev_fops member:
static const struct file_operations evdev_fops = {
.owner = THIS_MODULE,
.read = evdev_read,
.write = evdev_write,
.poll = evdev_poll,
.open = evdev_open,
.release = evdev_release,
.unlocked_ioctl = evdev_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = evdev_ioctl_compat,
#endif
.fasync = evdev_fasync,
.flush = evdev_flush
};
Anyone who has seen LDD3 knows that this is the interface provided by the device to user space to provide operations on the device. evdev_ioctl provides many commands. For related commands, please refer to "Using the Input Subsystem, Part II".
3 mini2440 touch screen driver
3.1 Initialization:
static int __init s3c2410ts_init(void)
{
struct input_dev *input_dev;
adc_clock = clk_get(NULL,"adc");
if (!adc_clock) {
printk(KERN_ERR "failed to get adc clock source\n");
return -ENOENT;
}
clk_enable(adc_clock);
//Get the clock. The peripheral devices mounted on the APB BUS require clock control. ADC is such a device.
base_addr=ioremap(S3C2410_PA_ADC,0x20);
I/O memory cannot be accessed directly, it must be mapped, and virtual addresses are assigned to I/O memory. These virtual addresses are described by __iomem, but they cannot be accessed directly. Special functions such as iowrite32 are required
if (base_addr == NULL) {
printk(KERN_ERR "Failed to remap register block\n");
return -ENOMEM;
}
/* Configure GPIOs */
s3c2410_ts_connect();
iowrite32(S3C2410_ADCCON_PRSCEN | S3C2410_ADCCON_PRSCVL(0xFF),\
base_addr+S3C2410_ADCCON); //Enable pre-scaling and set the division coefficient
iowrite32(0xffff, base_addr+S3C2410_ADCDLY);//Set ADC delay, which
indicates the interval time of generating INT_TC in waiting interrupt mode
iowrite32(WAIT4INT(0), base_addr+S3C2410_ADCTSC);
Set TSC in waiting interrupt mode
The next part is to register input device
/* Initialise input stuff */
input_dev = input_allocate_device();
//allocate memory for new input device, used to allocate space for input device and do some common initial settings for input device
if (!input_dev) {
printk(KERN_ERR "Unable to allocate the input device !!\n");
return -ENOMEM;
}
dev = input_dev;
dev->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);
//Set event type
dev->keybit[BITS_TO_LONGS(BTN_TOUCH)] = BIT(BTN_TOUCH);
input_set_abs_params(dev, ABS_X, 0, 0x3FF, 0, 0);
input_set_abs_params(dev, ABS_Y, 0, 0x3FF, 0, 0);
input_set_abs_params(dev, ABS_PRESSURE, 0, 1, 0, 0);
The above four sentences are all about setting the code in the event type. How to understand it? First, explain the event type. The commonly used event types are
EV_KEY, EV_MOSSE, and EV_ABS (used to receive absolute coordinate events such as touch screens), and each event will
have a different type of code, such as ABS_X, ABS_Y, and these codes will have corresponding values
dev->name = s3c2410ts_name;
dev->id.bustype = BUS_RS232;
dev->id.vendor = 0xDEAD;
dev->id.product = 0xBEEF;
dev->id.version = S3C2410TSVERSION;
//The above is the name and id of the input device. This information is the identity information of the input device. How to see it in user space?
cat /proc/bus/input/devices. The following is my screenshot.
/* Get irqs */
if (request_irq(IRQ_ADC, stylus_action, IRQF_SAMPLE_RANDOM,
"s3c2410_action", dev)) {
printk(KERN_ERR "s3c2410_ts.c: Could not allocate ts IRQ_ADC !\n");
iounmap(base_addr);
return -EIO;
}
if (request_irq(IRQ_TC, stylus_updown, IRQF_SAMPLE_RANDOM,
"s3c2410_action", dev)) {
printk(KERN_ERR "s3c2410_ts.c: Could not allocate ts IRQ_TC !\n");
iounmap(base_addr);
return -EIO;
}
printk(KERN_INFO "%s successfully loaded\n", s3c2410ts_name);
/* All went ok, so register to the input system */
input_register_device(dev);
//The basic information and capabilities of the device have been set up before. Everything is ready. Now you can register it.
return 0;
}
Interrupt processing
stylus_action and stylus_updown are two interrupt processing functions. When the pen tip touches, it will enter stylus_updown.
static irqreturn_t stylus_updown(int irq, void *dev_id)
{
unsigned longdata0;
unsigned longdata1;
int updown;
//Note that in the touch screen driver module, the role of this ADC_LOCK is to ensure that only one driver uses the ADC interrupt line at any time, because the ADC is also used in the mini2440adc module. In this way, only with this lock can the ADC be started. Note that although LDD3 says that semaphores are not suitable for use in ISRs because of sleep, down_trylock is an exception and it will not sleep.
if (down_trylock(&ADC_LOCK) == 0) {
OwnADC = 1;
data0 = ioread32(base_addr+S3C2410_ADCDAT0);
data1 = ioread32(base_addr+S3C2410_ADCDAT1);
updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(da ta1 & S3C2410_ADCDAT0_UPDOWN));
if (updown) {//means down
touch_timer_fire(0);//This is a timer function, of course it is called as a normal function here to start ADC
} else {
OwnADC = 0;
up(&ADC_LOCK);//Note that the red part will basically not be executed, unless you touch it at a very fast speed and there is no time to start the ADC. Of course, this fast speed is generally unattainable. When I debugged the program, I found that I could not enter here.
}
}
return IRQ_HANDLED;
}
static void touch_timer_fire(unsigned long data)
{
unsigned long data0;
unsigned long data1;
int updown;
data0 = ioread32(base_addr+S3C2410_ADCDAT0);
data1 = ioread32(base_addr+S3C2410_ADCDAT1);
updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(da ta1 & S3C2410_ADCDAT0_UPDOWN));
if (updown) {//means Down
converts four times and reports the event
if (count != 0) {
long tmp;
tmp = xp;
xp = yp;
yp = tmp;
//The conversion here is because our screen is 240*320, which is equivalent to converting the X and Y axes of the original screen.
Personal understanding is not just whether it is correct
xp >>= 2;
yp >>= 2;
/
input_report_abs(dev, ABS_X, xp);
input_report_abs(dev, ABS_Y, yp);
//Device X, Y value
input_report_key(dev, BTN_TOUCH, 1);
input_report_abs(dev, ABS_PRESSURE, 1);
input_sync(dev);
//This indicates that we have reported a complete touch screen event, which is used to interval the next report
}
xp = 0;
yp = 0;
count = 0;
iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC);
iowrite32(ioread32(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);
If the ADC has not been started or the ACD conversion is completed four times, start the ADC
} else {
If it is in the up state, report it and let the touch screen be in the waiting stage
count = 0;
input_report_key(dev, BTN_TOUCH, 0);
input_report_abs(dev, ABS_PRESSURE, 0);
input_sync(dev);
iowrite32(WAIT4INT(0), base_addr+S3C2410_ADCTSC);
if (OwnADC) {
OwnADC = 0;
up(&ADC_LOCK);
}
}
}
static irqreturn_t stylus_action(int irq, void *dev_id)
{
unsigned long data0;
unsigned long data1;
if (OwnADC) {
data0 = ioread32(base_addr+S3C2410_ADCDAT0);
da ta1 =ioread32(base_addr+S3C2410_ADCDAT1) ;
MASK ;
count++;
read data
if (count < (1<<2)) {if less than four times, restart the conversion
iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC);
iowrite32(ioread32(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);
} else {if more than four times, wait for 1ms before reporting data
mod_timer(&touch_timer, jiffies+1);
iowrite32(WAIT4INT(1), base_addr+S3C2410_ADCTSC);
}
}
return IRQ_HANDLED;
}
Let's describe the conversion process as a whole:
(1) If the touch screen senses a touch, it enters updown ISR, if ADC_LOCK can be obtained, then call touch_timer_fire to start ADC,
(2) ADC conversion, if less than four times, continue conversion, if four times are completed, start a timer of 1 time tick and stop ADC, that is, within this time tick, ADC is stopped,
(3) This can prevent screen jitter.
(4) If the touch screen is still in the touch state after 1 time tick, report the conversion data and restart ADC, repeat (2)
(5) If the touch pen is released, report the release event and reset the touch screen to the waiting interrupt state.
4 Testing and calibration
For application writing, please refer to "Using the Input Subsystem, Part II", which explains the API of the input device.
When calibrating the touch screen, the coordinates of the touch screen are matched with the coordinates of the LCD. This correspondence requires mapping. This mapping process is calibration. We provide a mapping method using a linear algorithm.
Keywords:Mini2440
Reference address:Mini2440 touch screen program analysis
1. Hardware knowledge to be prepared
1.1 Working principle of resistive touch screen Principle The
touch screen is attached to the surface of the display and used in conjunction with the display. If the coordinate position of the touch point on the screen can be measured, the intention of the toucher can be obtained based on the display content or icon of the corresponding coordinate point on the display. Touch screens can be divided into five categories according to their technical principles: vector pressure sensing, resistive, capacitive, infrared, and surface acoustic wave. Among them, resistive touch screens are more commonly used in embedded systems. The resistive touch screen is a 4-layer transparent composite film screen, as shown in Figure 2. The bottom is a base layer made of glass or organic glass, the top is a plastic layer with a hardened outer surface that is smooth and scratch-resistant, and in the middle are two metal conductive layers, one on the base layer and the other on the inner surface of the plastic layer. There are many small transparent isolation points between the two conductive layers to separate them. When a finger touches the screen, the two conductive layers touch at the touch point. The
two metal conductive layers of the touch screen are the two working surfaces of the touch screen. A silver glue is coated at both ends of each working surface, which is called a pair of electrodes of the working surface. If a voltage is applied to the electrode pair of a working surface, a uniform and continuous parallel voltage distribution will be formed on the working surface. As shown in Figure 4, when a certain voltage is applied to the electrode pair in the X direction and no voltage is applied to the electrode pair in the Y direction, in the X parallel voltage field, the voltage value at the touch point can be reflected on the Y+ (or Y-) electrode. By measuring the voltage of the Y+ electrode to the ground, the X coordinate value of the touch point can be obtained. Similarly, when voltage is applied to the Y electrode pair and no voltage is applied to the X electrode pair, the Y coordinate of the touch point can be obtained by measuring the voltage of the X+ electrode. There are two types of resistive touch screens: four-wire and five-wire. The X working surface and Y working surface of the four-wire touch screen are added to two conductive layers respectively, and there are four lead wires, which are connected to the X electrode pair and Y electrode pair of the touch screen respectively. The five-wire touch screen adds both the X working surface and the Y working surface to the conductive coating of the glass base layer, but when working, the voltage is still applied in time-sharing, that is, the voltage fields in two directions are allowed to work in time-sharing on the same working surface, and the outer conductive layer is only used as a conductor and voltage measurement electrode. Therefore, the lead wires of the five-wire touch screen need to be 5.
1.2 Touch screen interface in S3C2440
SOC The touch screen interface of S3C2440 is combined with the ADC interface. The block diagram is as follows:
Conversion rate: When PCLK=50MHz, the division frequency is set to 49, then the 10-bit conversion calculation is as follows:
When the GCLK frequency is 50MHz and the prescaler value is 49,
A/D converter freq. = 50MHz/(49+1) = 1MHz
Conversion time = 1/(1MHz / 5cycles) = 1/200KHz = 5 us
This A/D converter was designed to operate at maximum 2.5MHz clock, so the conversion rate can go up to 500 KSPS.
The modes of the touch screen interface are as follows:
normal ADC conversion mode
Independent X/Y position conversion mode
Automatic X/Y position conversion mode
Wait for interrupt mode
We mainly accept the wait for interrupt mode and automatic X/Y position conversion mode of the touch screen interface (used in the driver):
The operation flow of the automatic conversion mode is as follows: The touch screen controller automatically converts the touch position of X and Y. When the conversion is completed, the data is stored in the registers ADCDAT0 and ADCDAT1 respectively. And the INT_ADC interrupt is generated to notify the completion of the conversion.
Waiting for interrupt mode:
Touch Screen Controller generates interrupt (INT_TC) signal when the Stylus is down. Waiting for Interrupt Modesetting value is rADCTSC=0xd3; // XP_PU, XP_Dis, XM_Dis, YP_Dis, YM_En.When
touched, the touch screen controller generates INT_TC interrupt. The four pin settings should be:
Pin XP XM YP YM
Status PULL UP/XP Disable Disable (The initial value is) Disable Enable
Setting 1 0 1 1When
the interrupt is generated, the X/Y position data can be read in independent X/Y position conversion mode and automatic X/Y position conversion mode. To read in automatic X/Y position conversion mode, we need to change the TSC register we have set, on the basis of the original or on S3C2410_ADCTSC_PULL_UP_DISABLE | S3C2410_ADCTSC_AUTO_PST | S3C2410_ADCTSC_XY_PST(0).
After the data conversion is completed, an interrupt will also be generated.
2. Input subsystem model analysis
2.1 Overall framework:
The input subsystem consists of three parts: device driver, input core, and event processor.
The first part is the input device driver connected to each bus. On our SOC, this bus can be a virtual bus platformbus. Their role is to convert the underlying hardware input into a unified event format and report to the input core. The
second part of the input core is as follows:
(1) Call input_register_device() used to add devices, and call input_unregister_device() to remove devices. (This will be discussed in conjunction with the touch screen driver below.)
(2) The corresponding device information is generated under /PROC. The following example is:
/proc/bus/input/devices showing a USB mouse:
I: Bus=0003 Vendor=046d Product=c002 Version=0120
N: Name="Logitech USB-PS/2 Mouse M-BA47"
P: Phys=usb-00:01.2-2.2/input0
H: Handlers=mouse0 event2
B: EV=7
B: KEY=f0000 0 0 0 0 0 0 0
B: REL=103
(3) Notify the event handler to process the event
The third part is the event handler:
the input subsystem includes the large-scale handlers you need, such as mouse, keyboard, joystick, touch screen, and a general handler called event handler (for kernel file evdev.C). It should be noted that as the kernel version develops, the event handler will be used to handle more input events of different hardware. In Linux 2.6.29, the only specific device event handlers left are mouse and joystick. This means that more and more input devices will interact with user space through event handlers. The main function of the event handling layer is to interact with user space. We know that Linux treats all devices as files in user space. In general drivers, fops interfaces are provided, and corresponding device files nod are generated under /dev. In the input subsystem driver, these actions are all completed at the event handler layer. Let's take a look at the relevant code of evdev.C.
static int __init evdev_init(void)
{
return input_register_handler(&evdev_handler);
}
This is the registration procedure of the module and will be called when the system is initialized.
The initialization process is very simple, just one sentence, but all the secrets are hidden in evdev_handler:
static struct input_handler evdev_handler = {
.event = evdev_event,
.connect = evdev_connect,
.disconnect = evdev_disconnect,
.fops = &evdev_fops,
.minor = EVDEV_MINOR_BASE,
.name = "evdev",
.id_table = evdev_ids,
};
First look at the following code in the connect function:
snprintf(evdev->name, sizeof(evdev->name), "event%d", minor);
evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);
evdev->handle.dev = input_get_device(dev);
evdev->handle.name = evdev->name;
dev_set_name(&evdev->dev, evdev->name);
evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);
evdev->dev.class = &input_class;
evdev->dev.parent = &dev->dev;
evdev->dev.release = evdev_free;
device_initialize(&evdev->dev);
error = device_add(&evdev->dev);
Note the black part. This will be generated in the directory /sys/device/viture/input/input0/event0. Under event, there will be a dev attribute file, which stores the device number of the device file. In this way, udev can read
the attribute file to obtain the device number, and then create the device node /dev/event0 in the /dev directory.
Let's look at the evdev_fops member:
static const struct file_operations evdev_fops = {
.owner = THIS_MODULE,
.read = evdev_read,
.write = evdev_write,
.poll = evdev_poll,
.open = evdev_open,
.release = evdev_release,
.unlocked_ioctl = evdev_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = evdev_ioctl_compat,
#endif
.fasync = evdev_fasync,
.flush = evdev_flush
};
Anyone who has seen LDD3 knows that this is the interface provided by the device to user space to provide operations on the device. evdev_ioctl provides many commands. For related commands, please refer to "Using the Input Subsystem, Part II".
3 mini2440 touch screen driver
3.1 Initialization:
static int __init s3c2410ts_init(void)
{
struct input_dev *input_dev;
adc_clock = clk_get(NULL,"adc");
if (!adc_clock) {
printk(KERN_ERR "failed to get adc clock source\n");
return -ENOENT;
}
clk_enable(adc_clock);
//Get the clock. The peripheral devices mounted on the APB BUS require clock control. ADC is such a device.
base_addr=ioremap(S3C2410_PA_ADC,0x20);
I/O memory cannot be accessed directly, it must be mapped, and virtual addresses are assigned to I/O memory. These virtual addresses are described by __iomem, but they cannot be accessed directly. Special functions such as iowrite32 are required
if (base_addr == NULL) {
printk(KERN_ERR "Failed to remap register block\n");
return -ENOMEM;
}
/* Configure GPIOs */
s3c2410_ts_connect();
iowrite32(S3C2410_ADCCON_PRSCEN | S3C2410_ADCCON_PRSCVL(0xFF),\
base_addr+S3C2410_ADCCON); //Enable pre-scaling and set the division coefficient
iowrite32(0xffff, base_addr+S3C2410_ADCDLY);//Set ADC delay, which
indicates the interval time of generating INT_TC in waiting interrupt mode
iowrite32(WAIT4INT(0), base_addr+S3C2410_ADCTSC);
Set TSC in waiting interrupt mode
The next part is to register input device
/* Initialise input stuff */
input_dev = input_allocate_device();
//allocate memory for new input device, used to allocate space for input device and do some common initial settings for input device
if (!input_dev) {
printk(KERN_ERR "Unable to allocate the input device !!\n");
return -ENOMEM;
}
dev = input_dev;
dev->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);
//Set event type
dev->keybit[BITS_TO_LONGS(BTN_TOUCH)] = BIT(BTN_TOUCH);
input_set_abs_params(dev, ABS_X, 0, 0x3FF, 0, 0);
input_set_abs_params(dev, ABS_Y, 0, 0x3FF, 0, 0);
input_set_abs_params(dev, ABS_PRESSURE, 0, 1, 0, 0);
The above four sentences are all about setting the code in the event type
EV_KEY, EV_MOSSE, and EV_ABS (used to receive absolute coordinate events such as touch screens), and each event will
have a different type of code
dev->name = s3c2410ts_name;
dev->id.bustype = BUS_RS232;
dev->id.vendor = 0xDEAD;
dev->id.product = 0xBEEF;
dev->id.version = S3C2410TSVERSION;
//The above is the name and id of the input device. This information is the identity information of the input device. How to see it in user space?
cat /proc/bus/input/devices. The following is my screenshot.
/* Get irqs */
if (request_irq(IRQ_ADC, stylus_action
"s3c2410_action
printk(KERN_ERR "s3c2410_ts.c: Could not allocate ts IRQ_ADC !\n");
iounmap(base_addr);
return -EIO;
}
if (request_irq(IRQ_TC, stylus_updown, IRQF_SAMPLE_RANDOM,
"s3c2410_action
printk(KERN_ERR "s3c2410_ts.c: Could not allocate ts IRQ_TC !\n");
iounmap(base_addr);
return -EIO;
}
printk(KERN_INFO "%s successfully loaded\n", s3c2410ts_name);
/* All went ok, so register to the input system */
input_register_device(dev);
//The basic information and capabilities of the device have been set up before. Everything is ready. Now you can register it.
return 0;
}
Interrupt processing
stylus_act
static irqreturn_t stylus_updown(int irq, void *dev_id)
{
unsigned long
unsigned long
int updown;
//Note that in the touch screen driver module, the role of this ADC_LOCK is to ensure that only one driver uses the ADC interrupt line at any time, because the ADC is also used in the mini2440adc module. In this way, only with this lock can the ADC be started. Note that although LDD3 says that semaphores are not suitable for use in ISRs because of sleep, down_trylock is an exception and it will not sleep.
if (down_trylock(&ADC_LOCK) == 0) {
OwnADC = 1;
da
da
updown = (!(da
if (updown) {//means down
touch_timer_fire(0);//This is a timer function, of course it is called as a normal function here to start ADC
} else {
OwnADC = 0;
up(&ADC_LOCK);//Note that the red part will basically not be executed, unless you touch it at a very fast speed and there is no time to start the ADC. Of course, this fast speed is generally unattainable. When I debugged the program, I found that I could not enter here.
}
}
return IRQ_HANDLED;
}
static void touch_timer_fire(unsigned long da
{
unsigned long da
unsigned long da
int updown;
da
da
updown = (!(da
if (updown) {//means Down
converts four times and reports the event
if (count != 0) {
long tmp;
tmp = xp;
xp = yp;
yp = tmp;
//The conversion here is because our screen is 240*320, which is equivalent to converting the X and Y axes of the original screen.
Personal understanding is not just whether it is correct
xp >>= 2;
yp >>= 2;
/
input_report_abs(dev, ABS_X, xp);
input_report_abs(dev, ABS_Y, yp);
//Device X, Y value
input_report_key(dev, BTN_TOUCH, 1);
input_report_abs(dev, ABS_PRESSURE, 1);
input_sync(dev);
//This indicates that we have reported a complete touch screen event, which is used to interval the next report
}
xp = 0;
yp = 0;
count = 0;
iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC);
iowrite32(ioread32(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);
If the ADC has not been started or the ACD conversion is completed four times, start the ADC
} else {
If it is in the up state, report it and let the touch screen be in the waiting stage
count = 0;
input_report_key(dev, BTN_TOUCH, 0);
input_report_abs(dev, ABS_PRESSURE, 0);
input_sync(dev);
iowrite32(WAIT4INT(0), base_addr+S3C2410_ADCTSC);
if (OwnADC) {
OwnADC = 0;
up(&ADC_LOCK);
}
}
}
static irqreturn_t stylus_act
{
unsigned long da
unsigned long da
if (OwnADC) {
da
da ta1 =
Previous article:I2C slave mode for LPC2200
Next article:Detailed explanation of S3C2410 startup code (1)
- Popular Resources
- Popular amplifiers
Recommended Content
Latest Microcontroller Articles
He Limin Column
Microcontroller and Embedded Systems Bible
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
MoreSelected Circuit Diagrams
MorePopular Articles
- 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
MoreDaily News
- Huawei's Strategic Department Director Gai Gang: The cumulative installed base of open source Euler operating system exceeds 10 million sets
- Download from the Internet--ARM Getting Started Notes
- Learn ARM development(22)
- Learn ARM development(21)
- Learn ARM development(20)
- Learn ARM development(19)
- Learn ARM development(14)
- Learn ARM development(15)
- Analysis of the application of several common contact parts in high-voltage connectors of new energy vehicles
- Wiring harness durability test and contact voltage drop test method
Guess you like
- Well-known semiconductor manufacturer in Shanghai Zhangjiang recruits FAE and R&D engineers
- Amazing! TI launches smart high-tech clothing to help curb teenage obesity
- EEWORLD University ---- TPS65218D0: User Programming of Multi-Rail Power Management IC (PMIC)
- 【Environmental Expert’s Smart Watch】Part 20: Work Submission
- DAPLink version upgraded to 0254
- The withstand voltage of film capacitors
- Is there an official reference routine for the C6748 PRU?
- [GD32E231 DIY Contest]——09. Proofing, welding and debugging based on V1.0 hardware version
- Thoughts and feelings after experiencing a domestic USB audio chip
- [2022 Digi-Key Innovation Design Competition] [Intelligent Garden Integrated Control System] Data Collection STM32L496G-DISCO