Mini2440 touch screen program analysis

Publisher:FreeSpirit123Latest update time:2016-08-14 Source: eefocusKeywords:Mini2440 Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere
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_act ion 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 long data0;
     unsigned long data1;
     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 ta0 = ioread32(base_addr+S3C2410_ADCDAT0);
         da ta1 = ioread32(base_addr+S3C2410_ADCDAT1);

         updown = (!(da ta0 & 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 da ta)
{
       unsigned long da ta0;
       unsigned long da ta1;
     int updown;

       da ta0 = ioread32(base_addr+S3C2410_ADCDAT0);
       da ta1 = ioread32(base_addr+S3C2410_ADCDAT1);

     updown = (!(da ta0 & 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_act ion(int irq, void *dev_id)
{
     unsigned long da ta0;
     unsigned long da ta1;

     if (OwnADC) {
         da ta0 = 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

Previous article:I2C slave mode for LPC2200
Next article:Detailed explanation of S3C2410 startup code (1)

Latest Microcontroller Articles
  • Download from the Internet--ARM Getting Started Notes
    A brief introduction: From today on, the ARM notebook of the rookie is open, and it can be regarded as a place to store these notes. Why publish it? Maybe you are interested in it. In fact, the reason for these notes is ...
  • Learn ARM development(22)
    Turning off and on interrupts Interrupts are an efficient dialogue mechanism, but sometimes you don't want to interrupt the program while it is running. For example, when you are printing something, the program suddenly interrupts and another ...
  • Learn ARM development(21)
    First, declare the task pointer, because it will be used later. Task pointer volatile TASK_TCB* volatile g_pCurrentTask = NULL;volatile TASK_TCB* vol ...
  • Learn ARM development(20)
    With the previous Tick interrupt, the basic task switching conditions are ready. However, this "easterly" is also difficult to understand. Only through continuous practice can we understand it. ...
  • Learn ARM development(19)
    After many days of hard work, I finally got the interrupt working. But in order to allow RTOS to use timer interrupts, what kind of interrupts can be implemented in S3C44B0? There are two methods in S3C44B0. ...
  • Learn ARM development(14)
  • Learn ARM development(15)
  • Learn ARM development(16)
  • Learn ARM development(17)
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号