This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

AM335x resistive touch screen driver rework

Other Parts Discussed in Thread: TSC2007

Rework of AM335x Linux driver for resistive touchscreens

The existing driver for resistive touchscreens (in Linux 3.2.0) has several
limitations and weaknesses, so I had to enhance quality and performance.

Items covered:

1) The touch pressure was using the resistance of the foil as an input parameter.
However, since the output value do not need to be scaled to the resistance, this
parameter is not neccessary and was removed.

2) The interrupt function was triggered from the wrong interrupt source, so at
the time of execution, the last ADC sample was not ready. So the programmer has
inserted a udelay(315) inside the interrupt function (argh!). Using the EOS
interrupt removes this eating of CPU power.

3) "Pen Up" Events were not filtered in the driver. So, every spurious Pen Up
was sent to user space, which will interrupt gesture recognition.
A kernel timer with a default timeout of 100ms was used to filter such Pen Up
spikes.

4) Scaling from ADC to screen coordinates was implemented inside the touch
driver, in order to do calibration-on-the-fly, without having to reboot android.

5) The ADC state machine was running at full speed (24MHz), which would generate
MANY touch events and eating up CPU power. Use the CLKDIV register to reduce
clock by a factor of 20.

6) The filtering of the ADC samples was far from perfect. Spikes from the LCD
produced a position error of +/- 2mm. There was a constant jitter on the position.
Using a sorted array removed this problem. Position is stable now.

7) A simple filter was implemented to avoid sending events which do not differ
from previous events in X, Y, and Pressure data. This will free CPU power.

8) The Pen Up detection was not reliable, because of using the current state
machine value, and not the interrupt flag register. Pen Up events are missed
in user space, leading to missing action execution. This bug was fixed by
using the correct interrupt flag for "Pen Up".

These modifications lead to some improvements in android gui experience:

- Enhanced position precision == better usability of the virtual keyboard.
- Less CPU power == faster reaction on touch inputs.
- Big improvement in gesture recognition == better srolling of lists.

Driver source files appended.

touch.tar.gz
  • Thank you for sharing your work.

    Best regards,
    Miroslav

  • I have brought this to the attention of the factory team.

  • Hi,

    we have also problems with a touchdisplay, so I wan't to give this a trial. But when I look at my sources there is only a driver called ti_tscadc.c. We are on the linux-3.2.0-psp04.06.00.08.sdk. Is it also applicable here?


    Best Regards,

    Manfred

  • ti_tscadc seem to be an older version of the same driver.

    I am using ti_tsc.c on Linux 3.2.0.

    regards

    Wolfgang

  • So, I can copy the touch.tar.gz over my sources and change the configuration from

    CONFIG_TOUCHSCREEN_TI_TSCADC=y

    to

    CONFIG_TOUCHSCREEN_TI_TSCADC=n

    CONFIG_TOUCHSCREEN_TI_TSC=y

    Is it that simple or have I to do some other task?

    Regards,

    Manfred

  • Hi Wolfgang,


    I have now enabled modular support for the driver in linux-3.2.0-psp04.06.00.08.sdk. The module is build without errors.

    But then on loading the driver it fails.

    May  5 13:14:56 SIE user.alert kernel: [  176.334106] Unable to handle kernel NULL pointer dereference at virtual address 0000004c
    May  5 13:14:56 SIE user.alert kernel: [  176.342620] pgd = de548000
    May  5 13:14:56 SIE user.alert kernel: [  176.345428] [0000004c] *pgd=9ee56831, *pte=00000000, *ppte=00000000
    May  5 13:14:56 SIE user.emerg kernel: [  176.351989] Internal error: Oops: 17 [#1]
    May  5 13:14:56 SIE user.warn kernel: [  176.356170] Modules linked in: ti_tsc(+) af_packet usbhid(F) omap_wdt(F)
    May  5 13:14:56 SIE user.warn kernel: [  176.363159] CPU: 0    Tainted: GF             (3.2.0.SIE #1)
    May  5 13:14:56 SIE user.warn kernel: [  176.369079] PC is at tscadc_probe+0x1c/0x43c [ti_tsc]
    May  5 13:14:56 SIE user.warn kernel: [  176.374328] LR is at platform_drv_probe+0x20/0x24
    May  5 13:14:56 SIE user.warn kernel: [  176.379241] pc : [<bf016af0>]    lr : [<c01a0308>]    psr: a0000013
    May  5 13:14:56 SIE user.warn kernel: [  176.379241] sp : dedfbd58  ip : dedfbd90  fp : dedfbd8c
    May  5 13:14:56 SIE user.warn kernel: [  176.391204] r10: bf019000  r9 : 00000415  r8 : df862400
    May  5 13:14:56 SIE user.warn kernel: [  176.396636] r7 : bf017120  r6 : df86243c  r5 : df865e80  r4 : df862408
    May  5 13:14:56 SIE user.warn kernel: [  176.403411] r3 : bf016ad4  r2 : 00000000  r1 : 00000001  r0 : 00000004
    May  5 13:14:56 SIE user.warn kernel: [  176.410217] Flags: NzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment user
    May  5 13:14:56 SIE user.warn kernel: [  176.417663] Control: 10c5387d  Table: 9e548019  DAC: 00000015
    May  5 13:14:56 SIE user.emerg kernel: [  176.423645] Process modprobe (pid: 1662, stack limit = 0xdedfa2f0)
    May  5 13:14:56 SIE user.emerg kernel: [  176.430053] Stack: (0xdedfbd58 to 0xdedfc000)
    May  5 13:14:56 SIE user.emerg kernel: [  176.434600] bd40:                                                       ded72b00 bf019000
    May  5 13:14:56 SIE user.emerg kernel: [  176.443115] bd60: dedfbd7c df862408 c047c430 df86243c bf017120 ded72b00 00000415 bf019000
    May  5 13:14:56 SIE user.emerg kernel: [  176.451629] bd80: dedfbd9c dedfbd90 c01a0308 bf016ae0 dedfbdc4 dedfbda0 c019ef3c c01a02f4
    May  5 13:14:56 SIE user.emerg kernel: [  176.460144] bda0: 00000000 df862408 bf017120 df86243c 00000000 ded72b00 dedfbde4 dedfbdc8
    May  5 13:14:56 SIE user.emerg kernel: [  176.468658] bdc0: c019f0e0 c019eea4 c019f04c bf017120 c019f04c 00000000 dedfbe0c dedfbde8
    May  5 13:14:56 SIE user.emerg kernel: [  176.477203] bde0: c019e068 c019f058 df806ef8 df845170 c0148af0 bf017120 c0454d88 de45e5c0
    May  5 13:14:56 SIE user.emerg kernel: [  176.485717] be00: dedfbe1c dedfbe10 c019ebd8 c019e01c dedfbe4c dedfbe20 c019e7b0 c019ebc0
    May  5 13:14:56 SIE user.emerg kernel: [  176.494232] be20: bf017040 dedfbe30 bf017120 bf01715c dedfa000 00000000 ded72b00 bf019000
    May  5 13:14:56 SIE user.emerg kernel: [  176.502746] be40: dedfbe74 dedfbe50 c019f660 c019e710 00000000 c0462ac0 bf01715c dedfa000
    May  5 13:14:56 SIE user.emerg kernel: [  176.511260] be60: 00000000 ded72b00 dedfbe84 dedfbe78 c01a07d8 c019f5ec dedfbe94 dedfbe88
    May  5 13:14:56 SIE user.emerg kernel: [  176.519775] be80: bf019014 c01a0788 dedfbeec dedfbe98 c0008704 bf01900c dedfbebc dedfbea8
    May  5 13:14:56 SIE user.emerg kernel: [  176.528289] bea0: 00000002 00000003 dedd3940 00000000 dedfbedc dedfbec0 bf0171a4 bf01715c
    May  5 13:14:56 SIE user.emerg kernel: [  176.536834] bec0: 00000001 bf0171a4 bf01715c 00000001 0000001c ded72b00 00000415 00000001
    May  5 13:14:56 SIE user.emerg kernel: [  176.545349] bee0: dedfbfa4 dedfbef0 c005f454 c00086d4 bf017168 dedfbf00 c00083a4 00000000
    May  5 13:14:56 SIE user.emerg kernel: [  176.553863] bf00: 0001b048 e0a7b2ec e0a7b2ec dedfa000 bf01727c bf01715c 00000003 e0a7a000
    May  5 13:14:56 SIE user.emerg kernel: [  176.562377] bf20: 00002969 e0a7b4ec e0a7b3f9 e0a7c554 dee82e00 00001290 000013d0 00000000
    May  5 13:14:56 SIE user.emerg kernel: [  176.570892] bf40: 00000000 00000018 00000019 00000010 00000000 0000000c 00000000 00000000
    May  5 13:14:56 SIE user.emerg kernel: [  176.579406] bf60: 00000000 00000000 00000000 00000000 00000000 0000000f 00000000 beda5b94
    May  5 13:14:56 SIE user.emerg kernel: [  176.587921] bf80: 00000000 0001b038 00000080 c000e3c4 dedfa000 00000000 00000000 dedfbfa8
    May  5 13:14:56 SIE user.emerg kernel: [  176.596435] bfa0: c000e240 c005f368 beda5b94 00000000 4002c000 00002969 0001b048 00000000
    May  5 13:14:56 SIE user.emerg kernel: [  176.604949] bfc0: beda5b94 00000000 0001b038 00000080 00000000 0001b070 0001b038 0001b058
    May  5 13:14:56 SIE user.emerg kernel: [  176.613494] bfe0: 0001b048 beda589c 0000bdd0 40185684 60000010 4002c000 9fffe821 9fffec21
    May  5 13:14:56 SIE user.warn kernel: [  176.621978] Backtrace:
    May  5 13:14:56 SIE user.warn kernel: [  176.624542] [<bf016ad4>] (tscadc_probe+0x0/0x43c [ti_tsc]) from [<c01a0308>] (platform_drv_probe+0x20/0x24)
    May  5 13:14:56 SIE user.warn kernel: [  176.634704] [<c01a02e8>] (platform_drv_probe+0x0/0x24) from [<c019ef3c>] (driver_probe_device+0xa4/0x1b4)
    May  5 13:14:56 SIE user.warn kernel: [  176.644683] [<c019ee98>] (driver_probe_device+0x0/0x1b4) from [<c019f0e0>] (__driver_attach+0x94/0x98)
    May  5 13:14:56 SIE user.warn kernel: [  176.654357]  r8:ded72b00 r7:00000000 r6:df86243c r5:bf017120 r4:df862408
    May  5 13:14:56 SIE user.warn kernel: [  176.661163] r3:00000000
    May  5 13:14:56 SIE user.warn kernel: [  176.663909] [<c019f04c>] (__driver_attach+0x0/0x98) from [<c019e068>] (bus_for_each_dev+0x58/0x84)
    May  5 13:14:56 SIE user.warn kernel: [  176.673217]  r6:00000000 r5:c019f04c r4:bf017120 r3:c019f04c
    May  5 13:14:56 SIE user.warn kernel: [  176.679138] [<c019e010>] (bus_for_each_dev+0x0/0x84) from [<c019ebd8>] (driver_attach+0x24/0x28)
    May  5 13:14:56 SIE user.warn kernel: [  176.688293]  r6:de45e5c0 r5:c0454d88 r4:bf017120
    May  5 13:14:56 SIE user.warn kernel: [  176.693115] [<c019ebb4>] (driver_attach+0x0/0x28) from [<c019e7b0>] (bus_add_driver+0xac/0x244)
    May  5 13:14:56 SIE user.warn kernel: [  176.702178] [<c019e704>] (bus_add_driver+0x0/0x244) from [<c019f660>] (driver_register+0x80/0x138)
    May  5 13:14:56 SIE user.warn kernel: [  176.711517] [<c019f5e0>] (driver_register+0x0/0x138) from [<c01a07d8>] (platform_driver_register+0x5c/0x60)
    May  5 13:14:56 SIE user.warn kernel: [  176.721649]  r8:ded72b00 r7:00000000 r6:dedfa000 r5:bf01715c r4:c0462ac0
    May  5 13:14:56 SIE user.warn kernel: [  176.728454] r3:00000000
    May  5 13:14:56 SIE user.warn kernel: [  176.731201] [<c01a077c>] (platform_driver_register+0x0/0x60) from [<bf019014>] (ti_tsc_init+0x14/0x1c [ti_tsc])
    May  5 13:14:56 SIE user.warn kernel: [  176.741729] [<bf019000>] (ti_tsc_init+0x0/0x1c [ti_tsc]) from [<c0008704>] (do_one_initcall+0x3c/0x180)
    May  5 13:14:56 SIE user.warn kernel: [  176.751495] [<c00086c8>] (do_one_initcall+0x0/0x180) from [<c005f454>] (sys_init_module+0xf8/0x19b8)
    May  5 13:14:56 SIE user.warn kernel: [  176.761016] [<c005f35c>] (sys_init_module+0x0/0x19b8) from [<c000e240>] (ret_fast_syscall+0x0/0x30)
    May  5 13:14:56 SIE user.emerg kernel: [  176.770446] Code: e24dd00c e5905050 e1a08000 e5950000 (e5906048)
    May  5 13:14:56 SIE user.warn kernel: [  176.776977] ---[ end trace 16131b05c2c47ffe ]---

    Are there some other things that have to changed?


    Regards

    Manfred

  • Hi,

    Have some in the reworked items been applied to latest Linux SDK which is version 07.00.00? If so which items have been applied?

    Our customer uses the latest SDK on EVM and has issue that the pointer jumps to unexpected place after pen-up on the touchscreen.

    Best regards,

    Daisuke

     

  • Wolfgang,

    Thanks so much for sharing your results with the community.  You made several excellent finds!

    Can you tell me what you were using as your starting point for your software development?  Did you clone a tree somewhere (kernel.org, arago-project.org, etc.)?  If so, can you point me to what tree/branch/commit you started from?  I would like to be able to look very closely at the changes you made, but need to know the appropriate starting point.

    I think if I can see more of a "diff" view of what you did it will be easier for me to try and pull that code into a newer kernel.

    Thanks again for your efforts.  Hopefully some of us can get that forward ported so that your work does not wither on the vine.

    Brad

  • Brad,


    the starting point of my work is rowboat-jb-am335x-4.1.2.

    (commit 996686459db1181a5deaf5d493681ecb5bf43ad7)

    Attached is the diff of my work.

    regards

    Wolfgang

  • Sorry, the first attached file was wrong, covering not all items of my work.

    Please use the diff attached to THIS post.

    regards

    Wolfgang

  • Wolfgang,

    Thanks a lot for posting all the details.  Great info!  For starters I was trying to get rid of the udelay in SDK 7.00 by utilizing the other interrupts, though things were not working right.  I'm going to go back to the exact version of code you were using to make sure I can reproduce the work you already did.  I can dump some registers in that environment and compare with the SDK 7.00 environment.

    Cheers,
    Brad

  • In case anyone decides to go on this journey:

    1. I cloned the git tree from https://gitorious.org/rowboat/kernel, i.e. git clone git://gitorious.org/rowboat/kernel.git
    2. cd kernel
    3. git checkout -b touchscreen-improvements 996686459db1181a5deaf5d493681ecb5bf43ad7
    4. Here's where we may diverge a bit...  I want to get this running on the am335x EVM with SDK 6.00, so I'm currently building the am335x_evm_defconfig.  I see there's an Android defconfig there as well.  I assume that's probably what you were using for Jelly Bean, though hopefully this has no effect on the end result...

    I'm going to make sure I can get things running with no changes, and then apply your patches and run it again.  Hopefully being able to have a fully functioning "good" driver will help me in being able to patch the driver in the newer kernel versions.

  • I was getting a build error before I even applyed your patches!  I've attached patches.zip which contains:

    1. A patch to resolve the initial build error.
    2. The patch I applied that came from Wolfgang.  (Should be the same -- had a few white space warnings, but otherwise applied cleanly.)
    3. The patch I need to get Wolfgang's code to buid cleanly.  In short the board-am335x-evm.c still had some references to x_plate_resistance that I needed to switch to penfilterms.

    Question: What do you (Wolfgang) consider an appropriate value to set penfilterms to?

    The behavior I'm seeing is not very good.  If I run the ts_test routine and do some drawing things start out ok when I push my finger in the middle of the screen but as I slide upward the mouse gets further and further from my finger.  It's as if it's being scaled oddly.  I re-ran the calibration routine but it didn't seem to fix it.

    I may try doing the Android build (am335x_evm_android_defconfig) to see if it behaves better.  I would try that in an Android environment, not the Linux SDK...

    patches.zip
  • I tried this from an Android environment as well.  First I downloaded the AM335x JB 4.1.2 binaries.  That seemed to work reasonably well on my EVM (though with room for improvement!).  Then I rebuilt my kernel for the am335x_evm_android_defconfig and replaced the uImage.  I was having trouble even unlocking the unit in that scenario.

    Perhaps all my trouble goes back to an incorrect value for penfilterms in board-am335x-evm.c.  Please let me know if I messed that up or if there's anything else you think I'm missing! 

  • If you do not set penfilterms, it defaults to 100ms. I do NOT think that this is the cause of your problems.

    Please look into touchscreen calibration.

    In my board file, initialisation of TS data is:

    static struct tsc_data touchscreen_data = {
            .wires = 4,
            .x = {
                    .min = 0,
                    .max = 480,
                    .inverted = 1,
            },
            .y = {
                    .min = 0,
                    .max = 272,
                    .inverted = 1,
            },
            .penfilterms = 100,
            .steps_to_configure = 5,
    };
    
    struct mfd_tscadc_board tscadc = {
    	.tsc_init = &touchscreen_data,
    };
    
    static void __init mfd_tscadc_init(void)
    {
            int err;
    
            err = am33xx_register_mfd_tscadc(&tscadc);
            if (err)
                    pr_err("failed to register touchscreen device\n");
    }
    

  • I appreciate all your responses though I cannot get this to work on my EVM.  I may refer back to this post for some ideas (there were many good ones!) though as of now I am not going to attempt to directly port these patches to SDK 7.00 (kernel 3.12).

    If I find anything useful in terms of improving touchscreen on SDK 7.00 I'll try to report the changes back here.

  • I have attached a preliminary patch set which applies to the SDK 7.00 Linux Kernel.  Rather extensive changes were made in order to do a better job of working around Advisory 1.0.31 "TSC_ADC: False Pen-Up Interrupts".  The previous method utilized a 275 microsecond udelay inside the ISR in order to detect the pen-up condition.  The new code has completely changed around the configuration in order to have the necessary delays handled in hardware.

    Please note that the patches span both the TSC driver and the ADC driver.  The ADC driver is built as a module in SDK 7.00 so please be sure to rebuild both the kernel and modules and copy both to the file system.

    Other notes:

    • If using ts_test for the purpose of performance testing be sure to pipe the output to /dev/null.
    • When pressure is light the ADC samples can be "glitchy".  This is especially common when drawing with your finger since the broad surface of your finger tip results in substantially lower pressure than a stylus.
    • For drawing purposes a stylus works great and is very responsive and smooth.
    • For "finger based operation" I would NOT recommend using a mouse, i.e. you have a much better user experience "pushing buttons".
    • The TS_CHARGE_CONFIG register is the "hardware knob" which relates closely to the pen-up detection.  I believe this is set at a reasonable number based on testing on several EVMs.  However, if you are seeing a lot of "false pen-ups" you can increase this number.  The down side to increasing the number is that it reduces your sampling rate, so you want to trade off carefully.
    • We had a patch that did some rudimentary event filtering at the kernel level.  However, after reading several threads related to people implementing various plugins for tslib, I decided that was not the right thing to do.  Many users complained about kernel-level filtering because it was limiting the visibility of tslib, i.e. better filtering algorithms are often implemented as plugins.

    I hope to get these patches merged into the TI mainline kernel.  That will likely be for a later kernel version so I wanted to have a set that applies to SDK 7.00 directly.

    sdk-7_0-touchscreen-patches-prelim.zip
  • Hello Brad,

    Thanks for posting the patches to the Touchscreen driver. I am working on a design that uses 4-wire touch and the other 4 channels as sensor (Analog). These sensors are read every 10 secs - and we found 2 problems with it:


    1. Reading the ADC channels causes the Touch driver to stop working and cannot recover unless there is power cycle.

    2. The ADC values show an error of +/-20 LSB counts and it's not consistent, every ADC reading is random.

    I looked through the patch, it doesn't seem to fundamentally change the way the ADC is sampled. Have you run across this issue? Do you have any inputs on how I can solve this?

    Thank you

    Regards

    Santhosh

  • Santhosh Ramani said:
    1. Reading the ADC channels causes the Touch driver to stop working and cannot recover unless there is power cycle.

    Does this happen only on your own hardware?  I don't experience that issue on the EVM.  There was one minor bug I stumbled across related to the channel mapping.  That might possibly be your issue if your hardware has a different channel mapping than the EVM.  It worked fine with the default build but broke as soon as I changed anything.  Here's the portion of the patch that corrected it:

    diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c
    index 95b43e9..87b2547 100644
    --- a/drivers/iio/adc/ti_am335x_adc.c
    +++ b/drivers/iio/adc/ti_am335x_adc.c
    @@ -179,7 +180,14 @@ static int tiadc_read_raw(struct iio_dev *indio_dev,
                            return -EAGAIN;
                    }
            }
    -       map_val = chan->channel + TOTAL_CHANNELS;
    +
    +       /* Get the mapping of channel to stepid */
    +       for (i=0; i<sizeof(adc_dev->channel_line); i++) {
    +               if (chan->channel == adc_dev->channel_line[i]) {
    +                       map_val = adc_dev->channel_step[i];
    +                       break;
    +               }
    +       }
     
            /*
             * When the sub-system is first enabled,

    Santhosh Ramani said:
    2. The ADC values show an error of +/-20 LSB counts and it's not consistent, every ADC reading is random.

    I don't see that issue occurring either.

    root@am335x-evm:~# cat /sys/bus/iio/devices/iio\:device0/in_voltage4_raw
    589
    root@am335x-evm:~# cat /sys/bus/iio/devices/iio\:device0/in_voltage4_raw
    587
    root@am335x-evm:~# cat /sys/bus/iio/devices/iio\:device0/in_voltage4_raw
    583
    root@am335x-evm:~# cat /sys/bus/iio/devices/iio\:device0/in_voltage4_raw
    584
    root@am335x-evm:~# cat /sys/bus/iio/devices/iio\:device0/in_voltage4_raw
    586
    root@am335x-evm:~# cat /sys/bus/iio/devices/iio\:device0/in_voltage4_raw
    567

  • Santhosh Ramani said:
    it doesn't seem to fundamentally change the way the ADC is sampled. Have you run across this issue? Do you have any inputs on how I can solve this?

    You could tweak the tiadc_step_config value to try and improve this.  Currently when the STEPDELAY register is programmed only the OpenDelay is being used.  If you want to fundamentally change the way the sampling is occuring you need to adjust the SampleDelay (i.e. upper 8 bits of the register).  You might try increasing the SampleDelay to see if that yields a better result.

  • I'm attaching some updated patches.  The only difference with these patches is that you can now apply:

    • Patch 1 only
    • Patches 1 and 2
    • Patches 1, 2, 3

    In my original patch set if you attempted to apply patch 1 only then things would break.  This should make things a bit cleaner for anyone experimenting with the affect of various changes.  For completeness here's a copy of my original notes that I posted.  As well as one additional item which I highlighted.

    Rather extensive changes were made in order to do a better job of working around Advisory 1.0.31 "TSC_ADC: False Pen-Up Interrupts".  The previous method utilized a 275 microsecond udelay inside the ISR in order to detect the pen-up condition.  The new code has completely changed around the configuration in order to have the necessary delays handled in hardware.

    Please note that the patches span both the TSC driver and the ADC driver.  The ADC driver is built as a module in SDK 7.00 so please be sure to rebuild both the kernel and modules and copy both to the file system.

    Other notes:

    • If using ts_test for the purpose of performance testing be sure to pipe the output to /dev/null.
    • When pressure is light the ADC samples can be "glitchy".  This is especially common when drawing with your finger since the broad surface of your finger tip results in substantially lower pressure than a stylus.  I found that editing /etc/ts.conf in the EVM's file system to make pmin=150 improves this behavior substantially.
    • For drawing purposes a stylus works great and is very responsive and smooth.
    • For "finger based operation" I would NOT recommend using a mouse, i.e. you have a much better user experience "pushing buttons".
    • The TS_CHARGE_CONFIG register is the "hardware knob" which relates closely to the pen-up detection.  I believe this is set at a reasonable number based on testing on several EVMs.  However, if you are seeing a lot of "false pen-ups" you can increase this number.  The down side to increasing the number is that it reduces your sampling rate, so you want to trade off carefully.
    • We had a patch that did some rudimentary event filtering at the kernel level.  However, after reading several threads related to people implementing various plugins for tslib, I decided that was not the right thing to do.  Many users complained about kernel-level filtering because it was limiting the visibility of tslib, i.e. better filtering algorithms are often implemented as plugins.

    I hope to get these patches merged into the TI mainline kernel.  That will likely be for a later kernel version so I wanted to have a set that applies to SDK 7.00 directly.

    sdk-7-0-touchscreen-patches-v2.zip
  • Dear Brad,

         I get some issue while test with 10.4"touch screen.

    before patch, the calibration no response.

    patched sdk7.0 with 1-3, then calibration touch screen,

    top left is ok every time, while others no response, the response zone is only a little on the screen. 

    will you please help confirm where is the root cause? 

    thank you very much for your kindly help

  • Did you set pmin=150? If you're finding the screen no longer responsive in areas then you probably have too high of a pmin. You'll need to try out a few values to find a value small enough that the whole screen is operational, but large enough to give you good results (e.g. accurate lines, etc.)
  • Dear Brad,
    Thank you very much for your kindly help;
    It's appreciate that you can provide the file include the pmin, I am trying to find out the file but not get it now. I will carefull check out it before you feedback; thank you very much.
    Please let me know if you have one better method to resovled my issue, thank you.
    Best regards,
    liang
  • It's in the filesystem (for the AM335x) and it ships as part of the SDK 7.00 binaries. It's located at /etc/ts.conf. If you don't know where it's at then I assume you've not modified that value and that's likely not your issue!
  • Dear Brad,
    Thank you very much for your kindly help.
    My 10.4" resistive touch screen isn't work fine now. when I use the SDK5.07, the functional is ok; as the SDK5.07 is base on board file; the sdk7.00.00 base on device tree, we want use the sdk7.00 implement our project while the resistive touch screen has issue.
    I follow up your patch, and short the wiring-4 length, through the calibrition no ok as before description, but after calibrition the whole screen touch has data return by ts_print_raw, and the mouse also move. when I replace the sdcard pointcal file by sdk5.07 calibration pointcal the mouse has rotate 90 degree; and app icon no response.
    Then i will check the /etc/ts.conf and test again, thank you very much. I am not modified it yet; if this not my issue then how should i do to resolved?

    Best Regards,
    Liang
  • Hi Brad,
    my /etc/ts.conf comment:
    *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    # Uncomment if you wish to use the linux input layer event interface
    module_raw input

    # Uncomment if you're using a Sharp Zaurus SL-5500/SL-5000d
    # module_raw collie

    # Uncomment if you're using a Sharp Zaurus SL-C700/C750/C760/C860
    # module_raw corgi

    # Uncomment if you're using a device with a UCB1200/1300/1400 TS interface
    # module_raw ucb1x00

    # Uncomment if you're using an HP iPaq h3600 or similar
    # module_raw h3600

    # Uncomment if you're using a Hitachi Webpad
    # module_raw mk712

    # Uncomment if you're using an IBM Arctic II
    # module_raw arctic2

    module pthres pmin=1
    module variance delta=30
    module dejitter delta=100
    module linear
    *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    so the parameters maybe at other file;

    Best Regards,
    Liang
  • Hi Brad,
    I am only update the pmin = 150 and test, no other items need update?
    thank you very much for your kindly help.

    Best Regards,
    Liang
  • Hi, Manfred:

    Did you solve the problem? I got the same information when using TI-SDK7.0.

    Regards.

    Wang Jianghui

  • Hi, Wang,


    no we didn't fix it in that way. I increased a delay in the old driver and fixed the process of production of the touches to a capacity that is under 10pF between the two ITO Layers.

    We are now starting to develop a new Linux version for our Board and there I think we will use the new driver. But at the moment I have no solution for you. Sorry.


    Regards

    Manfred

  • I have had a very hard time this week.

    The displays in the current mass production have some induced EMI from the LCD to the touchscreen, and I have found that the hardware pen down/up detection in the AFE is very sensible to spikes coming into the touch foils. The touch is not usable in 80% of all devices.


    So I have rewritten the touchscreen driver to avoid the hardware pen detection and do that in software. IMO the hardware pen detection should not be used in production devices.

    If anybody needs it, I have attached the driver here.

    Sorry, this version is only for 4-wire-touches. I do not have 5/8-wire-touches available, and not the time to play around.

    regards

    Wolfgang

    ti_tsc.c
    /*
     * TI Touch Screen driver
     *
     * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
     *
     * This program is free software; you can redistribute it and/or
     * modify it under the terms of the GNU General Public License as
     * published by the Free Software Foundation version 2.
     *
     * This program is distributed "as is" WITHOUT ANY WARRANTY of any
     * kind, whether express or implied; without even the implied warranty
     * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     * GNU General Public License for more details.
     *
     * Some major rework done by Wolfgang Muees <wolfgang.muees@auerswald.de>
     * because of severe problems with the pen up/down detection in hardware
     * (not reliable in the presence of spikes).
     */
    
    #include <linux/init.h>
    #include <linux/kernel.h>
    #include <linux/err.h>
    #include <linux/module.h>
    #include <linux/input.h>
    #include <linux/slab.h>
    #include <linux/interrupt.h>
    #include <linux/clk.h>
    #include <linux/platform_device.h>
    #include <linux/io.h>
    #include <linux/input/ti_tsc.h>
    #include <linux/delay.h>
    #include <linux/sort.h>
    #include <linux/timer.h>
    #include <linux/mfd/ti_tscadc.h>
    
    #define MAX_12BIT                    ((1 << 12) - 1)
    #define PEN_DETECT_LEVEL		(MAX_12BIT / 8)
    
    #define PENFILTER_DEFAULT            100  /* ms for filtering pen up events */
    
    #define TSC_MOVE_DIFF                5   /* Report Move if diff >= n */
    #define TSC_MOVE_DIFF2 		(TSC_MOVE_DIFF * TSC_MOVE_DIFF)
    #define TSC_Z_FACT                   4   /* Report Pressure Change if factor >= n */
    #define TSC_CLKDIV                   10  /* ADC Clock Divider */
    
    #define TSCADC_STEPCONFIG_MODE_SW_ONE	 TSCADC_STEPCONFIG_MODE(0)
    #define TSCADC_STEPENB_USED		TSCADC_STEPENB(0x01FE)	 // Steps 1-8, no Charge
    #define TSCADC_STEPDELAY_USED		TSCADC_STEPDELAY_OPEN(1000)
    
    #define SORT_SAMPLES			8
    #define PEN_OFF			4
    
    struct tscadc {
    	struct input_dev	*input;
    	struct ti_tscadc_dev	*mfd_tscadc;
    	int			wires;
    	struct tsc_axis	x;
    	struct tsc_axis	y;
    	int			penfilterjiffies;
    	int			irq;
    	int			steps_to_config;
    	int 			pen;
    	struct timer_list penfiltertimer;
    	int			old_sx;
    	int 			old_sy;
    	unsigned int 		old_z;
    	unsigned int 		x_index;
    	unsigned int 		y_index;
    	unsigned short x_values[SORT_SAMPLES];
    	unsigned short y_values[SORT_SAMPLES];
    };
    
    static ssize_t show_param(struct device *dev, struct device_attribute *attr,
    	char *buf)
    {
    	struct platform_device *pdev =  to_platform_device(dev);
            struct tscadc *ts_dev  = (struct tscadc *) platform_get_drvdata(pdev);
    	struct tsc_axis *axis;
    	
    	if (attr->attr.name[0] == 'x') {
    		axis = &(ts_dev->x);
    	} else {
    		axis = &(ts_dev->y);
    	}
    
    	if (attr->attr.name[1] == 'i') {
    		return sprintf(buf, "%u\n", axis->inverted);
    	} else if (attr->attr.name[1] == 's') {
    		int range = axis->max - axis->min + 1;
    		return sprintf(buf, "%u (%u.%03u)\n", axis->scale, axis->scale / range,
    			(axis->scale % range) * 1000 / range);
    	} else if (attr->attr.name[1] == 'o') {
    		return sprintf(buf, "%u\n", axis->offset);
    	} else if (attr->attr.name[2] == 'a') {
    		return sprintf(buf, "%u\n", axis->max);
    	} else {
    		return sprintf(buf, "%u\n", axis->min);
    	}
    }
    
    static ssize_t store_param(struct device *dev, struct device_attribute *attr,
    	 const char *buf, size_t count)
    {
    	struct platform_device *pdev =  to_platform_device(dev);
            struct tscadc *ts_dev  = (struct tscadc *) platform_get_drvdata(pdev);
    	struct tsc_axis *axis;
    	int val;
    
    
    	if (attr->attr.name[0] == 'x') {
    		axis = &(ts_dev->x);
    	} else {
    		axis = &(ts_dev->y);
    	}
    
            if (sscanf(buf, "%u", &val) != 1)
           	        return -EINVAL;
    	if (attr->attr.name[1] == 'i') {
    	        if ((val != 1) && (val != 0))
            	        return -EINVAL;
    		axis->inverted = val;
    	} else {
    	        if ((val < 0) || (val > MAX_12BIT))
            	        return -EINVAL;
    		if (attr->attr.name[2] == 'a') {
    			axis->max = val;
    		} else if (attr->attr.name[1] == 's') {
    			axis->scale = val;
    		} else if (attr->attr.name[1] == 'o') {
    			axis->offset = val;
    		} else {
    			axis->min = val;
    		}
    	}
    
    	if (axis == &(ts_dev->x)) {
    		input_set_abs_params(ts_dev->input, ABS_X,
    			ts_dev->x.min ? : 0,
    			ts_dev->x.max ? : MAX_12BIT,
    			0, 0);
    	} else {
    		input_set_abs_params(ts_dev->input, ABS_Y,
    			ts_dev->y.min ? : 0,
    			ts_dev->y.max ? : MAX_12BIT,
    			0, 0);
    	}
    
            return strnlen(buf, count);
    }
    
    DEVICE_ATTR(xmin, S_IRUGO | S_IWUSR, show_param, store_param);
    DEVICE_ATTR(ymin, S_IRUGO | S_IWUSR, show_param, store_param);
    DEVICE_ATTR(xmax, S_IRUGO | S_IWUSR, show_param, store_param);
    DEVICE_ATTR(ymax, S_IRUGO | S_IWUSR, show_param, store_param);
    DEVICE_ATTR(xinvert, S_IRUGO | S_IWUSR, show_param, store_param);
    DEVICE_ATTR(yinvert, S_IRUGO | S_IWUSR, show_param, store_param);
    DEVICE_ATTR(xscale, S_IRUGO | S_IWUSR, show_param, store_param);
    DEVICE_ATTR(yscale, S_IRUGO | S_IWUSR, show_param, store_param);
    DEVICE_ATTR(xoffset, S_IRUGO | S_IWUSR, show_param, store_param);
    DEVICE_ATTR(yoffset, S_IRUGO | S_IWUSR, show_param, store_param);
    
    static inline unsigned int tscadc_readl(struct tscadc *ts, unsigned int reg)
    {
    	return readl(ts->mfd_tscadc->tscadc_base + reg);
    }
    
    static inline void tscadc_writel(struct tscadc *tsc, unsigned int reg,
    					unsigned int val)
    {
    	writel(val, tsc->mfd_tscadc->tscadc_base + reg);
    }
    
    static void tsc_step_config(struct tscadc *ts_dev)
    {
    	unsigned int stepconfig;
    	unsigned int step = 1;
    
    	// NOTE: only support for 4-wire touchscreen at this time.
    	
    	// =============== Pen Up/Down Detection ====================
    	// Step 1: Drive X and Y foils in opp. directions, X = high
    	//         Y-Foil = low via strong pulldown
    	//         X-Foil = high via strong pullup
    	//         Analog Sample in FIFO0 not used
    	// No Open Delay, no Sample Delay, no Averaging
    	stepconfig = TSCADC_STEPCONFIG_XPP | TSCADC_STEPCONFIG_YNN;
    	tscadc_writel(ts_dev, TSCADC_REG_STEPCONFIG(step), stepconfig);
    	tscadc_writel(ts_dev, TSCADC_REG_STEPDELAY(step), 0);
    	step++;
    	
    	// Step 2: Measure on X Foil. Must be LOW for contact.
    	//         Y-Foil = low via strong pulldown;
    	//         X-Foil = open
    	//         Analog Sample from AIN0 in FIFO1
    	// Open Delay = 1000(us), no Sample Delay, 16 Averaging
    	stepconfig = TSCADC_STEPCONFIG_YNN | TSCADC_STEPCONFIG_AVG_16
    	           | TSCADC_STEPCONFIG_FIFO1 | TSCADC_STEPCONFIG_MODE_SW_ONE;
    	tscadc_writel(ts_dev, TSCADC_REG_STEPCONFIG(step), stepconfig);
    	tscadc_writel(ts_dev, TSCADC_REG_STEPDELAY(step),TSCADC_STEPDELAY_USED);
    	step++;
    
    	// Step 3: Drive X and Y foils in opp. directions, Y = high
    	//         Y-Foil = high via strong pullup
    	//         X-Foil = low via strong pulldown
    	//         Analog Sample in FIFO0 not used
    	// No Open Delay, no Sample Delay, no Averaging
    	stepconfig = TSCADC_STEPCONFIG_YPP | TSCADC_STEPCONFIG_XNN;
    	tscadc_writel(ts_dev, TSCADC_REG_STEPCONFIG(step), stepconfig);
    	tscadc_writel(ts_dev, TSCADC_REG_STEPDELAY(step), 0);
    	step++;
    
    	// Step 4: Measure on Y Foil. Must be LOW for contact.
    	//         Y-Foil = open
    	//         X-Foil = low via strong pulldown
    	//         Analog Sample from AIN2 in FIFO1
    	// Open Delay = 1000(us), no Sample Delay, 16 Averaging
    	stepconfig = TSCADC_STEPCONFIG_XNN | TSCADC_STEPCONFIG_AVG_16
    	           | TSCADC_STEPCONFIG_FIFO1 | TSCADC_STEPCONFIG_MODE_SW_ONE
    	           | TSCADC_STEPCONFIG_INP_AN2;
    	tscadc_writel(ts_dev, TSCADC_REG_STEPCONFIG(step), stepconfig);
    	tscadc_writel(ts_dev, TSCADC_REG_STEPDELAY(step), TSCADC_STEPDELAY_USED);
    	step++;
    
    	// ================= Position Detection ====================
    	// Step 5: Measure the Value on X Foil.
    	//         Y-Foil = open
    	//         X-Foil = linear voltage
    	//         Analog Sample from AIN2 to FIFO0
    	// Open Delay = 1000(us), no Sample Delay, 16 Averaging
    	stepconfig = TSCADC_STEPCONFIG_XPP | TSCADC_STEPCONFIG_XNN
    		   | TSCADC_STEPCONFIG_MODE_SW_ONE | TSCADC_STEPCONFIG_INP_AN2
    		   | TSCADC_STEPCONFIG_AVG_16;
    	tscadc_writel(ts_dev, TSCADC_REG_STEPCONFIG(step), stepconfig);
    	tscadc_writel(ts_dev, TSCADC_REG_STEPDELAY(step), TSCADC_STEPDELAY_USED);
    	step++;
    
    	// Step 6: Measure the Value on Y Foil.
    	//         Y-Foil = linear voltage
    	//         X-Foil = open
    	//         Analog Sample from AIN0 to FIFO1
    	// Open Delay = 1000(us), no Sample Delay, 16 Averaging
    	stepconfig = TSCADC_STEPCONFIG_YPP | TSCADC_STEPCONFIG_YNN
    	           | TSCADC_STEPCONFIG_MODE_SW_ONE | TSCADC_STEPCONFIG_AVG_16
    	           | TSCADC_STEPCONFIG_FIFO1;
    	tscadc_writel(ts_dev, TSCADC_REG_STEPCONFIG(step), stepconfig);
    	tscadc_writel(ts_dev, TSCADC_REG_STEPDELAY(step), TSCADC_STEPDELAY_USED);
    	step++;
    
    	// ================= Pressure Detection ====================
    	// Step 7: Measure for Pressure Calculation
    	//         Y-Foil = low on AIN2
    	//         X-Foil = high on AIN1
    	//         Analog Sample from AIN0 to FIFO0
    	// Open Delay = 1000(us), no Sample Delay, 16 Averaging
    	stepconfig = TSCADC_STEPCONFIG_XNP | TSCADC_STEPCONFIG_YPN
    	           | TSCADC_STEPCONFIG_MODE_SW_ONE | TSCADC_STEPCONFIG_AVG_16;
    	tscadc_writel(ts_dev, TSCADC_REG_STEPCONFIG(step), stepconfig);
    	tscadc_writel(ts_dev, TSCADC_REG_STEPDELAY(step), TSCADC_STEPDELAY_USED);
    	step++;
    
    	// Step 8: Measure for Pressure Calculation
    	//         Y-Foil = low on AIN2
    	//         X-Foil = high on AIN1
    	//         Analog Sample from AIN3 to FIFO1
    	// Open Delay = 1000(us), no Sample Delay, 16 Averaging
    	stepconfig = TSCADC_STEPCONFIG_XNP | TSCADC_STEPCONFIG_YPN
    	           | TSCADC_STEPCONFIG_MODE_SW_ONE | TSCADC_STEPCONFIG_AVG_16
    	           | TSCADC_STEPCONFIG_INP_AN3 | TSCADC_STEPCONFIG_FIFO1;
    	tscadc_writel(ts_dev, TSCADC_REG_STEPCONFIG(step), stepconfig);
    	tscadc_writel(ts_dev, TSCADC_REG_STEPDELAY(step), TSCADC_STEPDELAY_USED);
    	step++;
    
    	// Number of Steps
    	tscadc_writel(ts_dev, TSCADC_REG_SE, TSCADC_STEPENB_USED);
    }
    
    static void swap_samples(void *a, void *b, int size)
    {
    	unsigned short t = *(unsigned short *)a;
    	*(unsigned short *)a = *(unsigned short *)b;
    	*(unsigned short *)b = t;
    }
    
    static int comp_samples(const void *a, const void *b)
    {
    	return *(unsigned short *)a - *(unsigned short *)b;
    }
    
    static irqreturn_t tscadc_interrupt(int irq, void *dev)
    {
    	struct tscadc		*ts_dev = (struct tscadc *)dev;
    	struct input_dev	*input_dev = ts_dev->input;
    	unsigned int		status, irqclr = 0;
    
    	status = tscadc_readl(ts_dev, TSCADC_REG_IRQSTATUS);
    
    	if (status & TSCADC_IRQENB_EOS) {
    		unsigned int sample_x;
    		unsigned int sample_y;
    		unsigned int z1;
    		unsigned int z2;
    		unsigned int z;
    		int val_x;
    		int val_y;
    		
    		// FIFO0: discard first 2 Samples
    		tscadc_readl(ts_dev, TSCADC_REG_FIFO0);
    		tscadc_readl(ts_dev, TSCADC_REG_FIFO0);
    
    		// FIFO1: read samples 1 and 2
    		sample_x = tscadc_readl(ts_dev, TSCADC_REG_FIFO1);
    		sample_y = tscadc_readl(ts_dev, TSCADC_REG_FIFO1);
    		
    		// printk(KERN_ERR "Pendetectx = %d, Pendetecty = %d\n", sample_x, sample_y);
    
    		// Detect Pen UP/Down
    		if ((sample_x < PEN_DETECT_LEVEL) && (sample_y < PEN_DETECT_LEVEL)) {
    			// Pen down
    			if (ts_dev->pen > 0) {
    				ts_dev->pen--;
    				if (ts_dev->pen == 0)
    					del_timer(&ts_dev->penfiltertimer);
    			}
    		} else {
    			// Pen up
    			if (ts_dev->pen < PEN_OFF) {
    				ts_dev->pen++;
    				if (ts_dev->pen == PEN_OFF)
    					// Retrigger filter timer for pen up
    					mod_timer(&ts_dev->penfiltertimer, jiffies + ts_dev->penfilterjiffies);
    			}
    		}
    
    		// Get Samples for X and Y Position
    		sample_x = tscadc_readl(ts_dev, TSCADC_REG_FIFO0) & 0xfff;
    		sample_y = tscadc_readl(ts_dev, TSCADC_REG_FIFO1) & 0xfff;
    
    		// Get Samples for Pressure Calculation
    		z1 = tscadc_readl(ts_dev, TSCADC_REG_FIFO0) & 0xfff;
    		z2 = tscadc_readl(ts_dev, TSCADC_REG_FIFO1) & 0xfff;
    
    		// Empty the FIFO from garbage
    		z = tscadc_readl(ts_dev, TSCADC_REG_FIFO0CNT);
    		for ( ; z; z--)
    			tscadc_readl(ts_dev, TSCADC_REG_FIFO0);
    		z = tscadc_readl(ts_dev, TSCADC_REG_FIFO1CNT);
    		for ( ; z; z--)
    			tscadc_readl(ts_dev, TSCADC_REG_FIFO1);
    		
    		// Use Samples if pen down
    		if (ts_dev->pen == 0) {
    
    			// Invert samples
    			if (ts_dev->x.inverted)
    				sample_x = MAX_12BIT - sample_x;
    			if (ts_dev->y.inverted)
    				sample_y = MAX_12BIT - sample_y;
    			// printk(KERN_ERR "X = %d, Y = %d, Z1 = %d, Z2 = %d\n", sample_x, sample_y, z1, z2);
    
    			// Store samples
    			if (ts_dev->x_index < SORT_SAMPLES)
    				ts_dev->x_values[ts_dev->x_index++] = sample_x;
    			if (ts_dev->y_index < SORT_SAMPLES)
    				ts_dev->y_values[ts_dev->y_index++] = sample_y;
    			
    			if ((z1 != 0) && (z2 != 0) && (ts_dev->x_index >= SORT_SAMPLES) && (ts_dev->y_index >= SORT_SAMPLES)) {
    				unsigned short *sp;
    				int diff_sx;
    				int diff_sy;
    				unsigned int fact_z;
    				/* sort samples */
    				sort(ts_dev->x_values, SORT_SAMPLES, sizeof(ts_dev->x_values[0]), comp_samples, swap_samples);
    				sort(ts_dev->y_values, SORT_SAMPLES, sizeof(ts_dev->y_values[0]), comp_samples, swap_samples);
    				/* calculate mean values */
    				sp = &ts_dev->x_values[(SORT_SAMPLES / 2) - 2];
    				val_x = *sp++;
    				val_x += *sp++;
    				val_x += *sp++;
    				val_x += *sp;
    				val_x >>= 2;
    				sp = &ts_dev->y_values[(SORT_SAMPLES / 2) - 2];
    				val_y = *sp++;
    				val_y += *sp++;
    				val_y += *sp++;
    				val_y += *sp;
    				val_y >>= 2;
    
    				/* z = resistance of pressure (0..MAX_12BIT) */
    				z = (z1 - z2) * (MAX_12BIT - val_x);
    				z = z / (MAX_12BIT + 1 - z1);
    				if (z >= MAX_12BIT)
    					z = MAX_12BIT - 1;
    				/* z = pressure */
    				z = MAX_12BIT - z;
    
    				/* calculate screen coordinates */
    				val_x = ((val_x - ts_dev->x.offset) * ts_dev->x.scale) >> 12;
    				val_y = ((val_y - ts_dev->y.offset) * ts_dev->y.scale) >> 12;
    
    				/* Check for under/overflow */
    				if (val_x < ts_dev->x.min)
    					val_x = ts_dev->x.min;
    				else if (val_x > ts_dev->x.max)
    					val_x = ts_dev->x.max;
    				if (val_y < ts_dev->y.min)
    					val_y = ts_dev->y.min;
    				else if (val_y > ts_dev->y.max)
    					val_y = ts_dev->y.max;
    
    				/* Do not send the same coordinates twice.
    				(This will prevent CPU load in user space). */
    				diff_sx = val_x - ts_dev->old_sx;
    				if (diff_sx < 0)
    					diff_sx = -diff_sx;
    				diff_sy = val_y - ts_dev->old_sy;
    				if (diff_sy < 0)
    					diff_sy = -diff_sy;
    
    				fact_z = TSC_Z_FACT;
    				if (z && ts_dev->old_z) {
    					if (z >= ts_dev->old_z)
    						fact_z = z / ts_dev->old_z;
    					else
    						fact_z = ts_dev->old_z / z;
    				}
    
    				/* calculate sqr(move) */
    				diff_sx = (diff_sx * diff_sx) + (diff_sy * diff_sy);
    
    				/* Check for significant move & pressure change */
    				if ((diff_sx >= TSC_MOVE_DIFF2) || (fact_z >= TSC_Z_FACT)) {
    					ts_dev->old_sx = val_x;
    					ts_dev->old_sy = val_y;
    					ts_dev->old_z = z;
    					// printk(KERN_ERR "Touch at X= %d, Y= %d, P = %d\n", val_x, val_y, z);
    					input_report_key(input_dev, BTN_TOUCH, 1);
    					input_report_abs(input_dev, ABS_X, val_x);
    					input_report_abs(input_dev, ABS_Y, val_y);
    					input_report_abs(input_dev, ABS_PRESSURE, z);
    					input_sync(input_dev);
    				}
    				/* Clear sample buffer */
    				ts_dev->x_index = 0;
    				ts_dev->y_index = 0;
    			}
    		}
    		
    		irqclr |= TSCADC_IRQENB_EOS;
    		/* start next transfer */
    		tscadc_writel(ts_dev, TSCADC_REG_SE, TSCADC_STEPENB_USED);
    	}
    
    	tscadc_writel(ts_dev, TSCADC_REG_IRQSTATUS, irqclr);
    
    	return IRQ_HANDLED;
    }
    
    /*
     * Timer function for sending the pen up event.
     */
    static void pentimer_timeout(unsigned long context)
    {
        struct tscadc       *ts_dev = (struct tscadc *)context;
        struct input_dev    *input_dev = ts_dev->input;
    
        ts_dev->old_sx = -1000;
        ts_dev->old_sy = -1000;
        ts_dev->old_z = 0;
        ts_dev->x_index = 0;
        ts_dev->y_index = 0;
        
        // printk(KERN_ERR "Touch End\n");
        input_report_key(input_dev, BTN_TOUCH, 0);
        input_report_abs(input_dev, ABS_PRESSURE, 0);
        input_sync(input_dev);
    }
    
    
    /*
    * The functions for inserting/removing driver as a module.
    */
    
    static	int __devinit tscadc_probe(struct platform_device *pdev)
    {
    	struct tscadc			*ts_dev;
    	struct input_dev		*input_dev;
    	int				err;
    	int				irqenable;
    	struct ti_tscadc_dev		*tscadc_dev = pdev->dev.platform_data;
    	struct mfd_tscadc_board	*pdata;
    	unsigned int 			ctrl;
    
    
    	pdata = (struct mfd_tscadc_board *)tscadc_dev->dev->platform_data;
    	if (!pdata) {
    		dev_err(tscadc_dev->dev, "Could not find platform data\n");
    		return -EINVAL;
    	}
    
    	/* Allocate memory for device */
    	ts_dev = kzalloc(sizeof(struct tscadc), GFP_KERNEL);
    	if (!ts_dev) {
    		dev_err(&pdev->dev, "failed to allocate memory.\n");
    		return -ENOMEM;
    	}
    
    	tscadc_dev->tsc = ts_dev;
    	ts_dev->mfd_tscadc = tscadc_dev;
    
    	input_dev = input_allocate_device();
    	if (!input_dev) {
    		dev_err(&pdev->dev, "failed to allocate input device.\n");
    		err = -ENOMEM;
    		goto err_free_mem;
    	}
    	ts_dev->input = input_dev;
    
    	ts_dev->irq = tscadc_dev->irq;
    	err = request_irq(ts_dev->irq, tscadc_interrupt, IRQF_DISABLED,
    				pdev->dev.driver->name, ts_dev);
    	if (err) {
    		dev_err(&pdev->dev, "failed to allocate irq.\n");
    		goto err_fail;
    	}
    
    	ts_dev->wires = pdata->tsc_init->wires;
    	err = pdata->tsc_init->penfilterms;
    	if (!err)
    	    err = PENFILTER_DEFAULT;
    	ts_dev->penfilterjiffies = msecs_to_jiffies(err);
    	ts_dev->steps_to_config = pdata->tsc_init->steps_to_configure;
    	ts_dev->x.min = pdata->tsc_init->x.min;
    	ts_dev->x.max = pdata->tsc_init->x.max;
    	ts_dev->x.inverted = pdata->tsc_init->x.inverted;
    	ts_dev->y.min = pdata->tsc_init->y.min;
    	ts_dev->y.max = pdata->tsc_init->y.max;
    	ts_dev->y.inverted = pdata->tsc_init->y.inverted;
    	ts_dev->x.scale = (ts_dev->x.max - ts_dev->x.min) + 1;
    	ts_dev->y.scale = (ts_dev->y.max - ts_dev->y.min) + 1;
    	init_timer(&ts_dev->penfiltertimer);
    	ts_dev->penfiltertimer.function = pentimer_timeout;
    	ts_dev->penfiltertimer.data = (unsigned long) ts_dev;
    	ts_dev->x_index = 0;
    	ts_dev->y_index = 0;
    	ts_dev->pen = PEN_OFF;
    
    	// Set control register
    	ctrl = TSCADC_CNTRLREG_STEPCONFIGWRT | TSCADC_CNTRLREG_TSCENB;
    	tscadc_writel(ts_dev, TSCADC_REG_CTRL, ctrl);
    	
    	/* Clock divider (avoid CPU load) */
    	tscadc_writel(ts_dev, TSCADC_REG_CLKDIV, TSC_CLKDIV - 1);
        
    	tsc_step_config(ts_dev);
    
    	tscadc_writel(ts_dev, TSCADC_REG_FIFO1THR, ts_dev->steps_to_config);
    
    	input_dev->name = "ti-tsc";
    	input_dev->dev.parent = &pdev->dev;
    
    	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
    	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
    
    	input_set_abs_params(input_dev, ABS_X,
    			ts_dev->x.min ? : 0,
    			ts_dev->x.max ? : MAX_12BIT,
    			0, 0);
    	input_set_abs_params(input_dev, ABS_Y,
    			ts_dev->y.min ? : 0,
    			ts_dev->y.max ? : MAX_12BIT,
    			0, 0);
    	input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0);
    
    	/* register to the input system */
    	err = input_register_device(input_dev);
    	if (err)
    		goto err_free_irq;
    
    	platform_set_drvdata(pdev, ts_dev);
    
            err = device_create_file(&pdev->dev, &dev_attr_xmin);
            if (err < 0)
                    goto err_register_input;
    
            err = device_create_file(&pdev->dev, &dev_attr_xmax);
            if (err < 0)
                    goto err_xmin;
    
            err = device_create_file(&pdev->dev, &dev_attr_ymin);
            if (err < 0)
                    goto err_xmax;
    
            err = device_create_file(&pdev->dev, &dev_attr_ymax);
            if (err < 0)
                    goto err_ymin;
    
            err = device_create_file(&pdev->dev, &dev_attr_xinvert);
            if (err < 0)
                    goto err_ymax;
    
            err = device_create_file(&pdev->dev, &dev_attr_yinvert);
            if (err < 0)
                    goto err_xinvert;
    
            err = device_create_file(&pdev->dev, &dev_attr_xscale);
            if (err < 0)
                    goto err_yinvert;
    
            err = device_create_file(&pdev->dev, &dev_attr_yscale);
            if (err < 0)
                    goto err_xscale;
    
            err = device_create_file(&pdev->dev, &dev_attr_xoffset);
            if (err < 0)
                    goto err_yscale;
    
            err = device_create_file(&pdev->dev, &dev_attr_yoffset);
            if (err < 0)
                    goto err_xoffset;
    
    	/* IRQ Enable */
    	irqenable = TSCADC_IRQENB_EOS /*| TSCADC_IRQENB_PENUP | TSCADC_IRQENB_HW_PEN_SYNC*/;
    	tscadc_writel(ts_dev, TSCADC_REG_IRQENABLE, irqenable);
    
    	// Start
    	ctrl |=  TSCADC_CNTRLREG_TSCSSENB;
    	tscadc_writel(ts_dev, TSCADC_REG_CTRL, ctrl);
    	
    	return 0;
    
    
    err_xoffset:
    	device_remove_file(&pdev->dev, &dev_attr_xoffset);
    err_yscale:
    	device_remove_file(&pdev->dev, &dev_attr_yscale);
    err_xscale:
    	device_remove_file(&pdev->dev, &dev_attr_xscale);
    err_yinvert:
    	device_remove_file(&pdev->dev, &dev_attr_yinvert);
    err_xinvert:
    	device_remove_file(&pdev->dev, &dev_attr_xinvert);
    err_ymax:
    	device_remove_file(&pdev->dev, &dev_attr_ymax);
    err_ymin:
    	device_remove_file(&pdev->dev, &dev_attr_ymin);
    err_xmax:
    	device_remove_file(&pdev->dev, &dev_attr_xmax);
    err_xmin:
    	device_remove_file(&pdev->dev, &dev_attr_xmin);
    err_register_input:
    	input_unregister_device(input_dev);
    err_free_irq:
    	free_irq(ts_dev->irq, ts_dev);
    	del_timer_sync(&ts_dev->penfiltertimer);
    err_fail:
    	input_free_device(ts_dev->input);
    err_free_mem:
    	platform_set_drvdata(pdev, NULL);
    	kfree(ts_dev);
    	return err;
    }
    
    static int __devexit tscadc_remove(struct platform_device *pdev)
    {
    	struct ti_tscadc_dev	*tscadc_dev = pdev->dev.platform_data;
    	struct tscadc		*ts_dev = tscadc_dev->tsc;
    
    	free_irq(ts_dev->irq, ts_dev);
    	del_timer_sync(&ts_dev->penfiltertimer);
    
    	input_unregister_device(ts_dev->input);
    	device_remove_file(&pdev->dev, &dev_attr_yoffset);
    	device_remove_file(&pdev->dev, &dev_attr_xoffset);
    	device_remove_file(&pdev->dev, &dev_attr_yscale);
    	device_remove_file(&pdev->dev, &dev_attr_xscale);
    	device_remove_file(&pdev->dev, &dev_attr_yinvert);
    	device_remove_file(&pdev->dev, &dev_attr_xinvert);
    	device_remove_file(&pdev->dev, &dev_attr_ymax);
    	device_remove_file(&pdev->dev, &dev_attr_ymin);
    	device_remove_file(&pdev->dev, &dev_attr_xmax);
    	device_remove_file(&pdev->dev, &dev_attr_xmin);
    	kfree(ts_dev);
    	platform_set_drvdata(pdev, NULL);
    
    	return 0;
    }
    
    static int tsc_suspend(struct platform_device *pdev, pm_message_t state)
    {
    	struct ti_tscadc_dev	*tscadc_dev = pdev->dev.platform_data;
    	struct tscadc		*ts_dev = tscadc_dev->tsc;
    	unsigned int idle;
    
    	if (device_may_wakeup(tscadc_dev->dev)) {
    		idle = tscadc_readl(ts_dev, TSCADC_REG_IRQENABLE);
    		tscadc_writel(ts_dev, TSCADC_REG_IRQENABLE,
    				(idle | TSCADC_IRQENB_HW_PEN));
    		tscadc_writel(ts_dev, TSCADC_REG_IRQWAKEUP,
    				TSCADC_IRQWKUP_ENB);
    	}
    	return 0;
    }
    
    static int tsc_resume(struct platform_device *pdev)
    {
    	struct ti_tscadc_dev	*tscadc_dev = pdev->dev.platform_data;
    	struct tscadc		*ts_dev = tscadc_dev->tsc;
    
    	if (device_may_wakeup(tscadc_dev->dev)) {
    		tscadc_writel(ts_dev, TSCADC_REG_IRQWAKEUP,
    				0x00);
    		tscadc_writel(ts_dev, TSCADC_REG_IRQCLR,
    				TSCADC_IRQENB_HW_PEN);
    	}
    	tsc_step_config(ts_dev);
    	tscadc_writel(ts_dev, TSCADC_REG_FIFO1THR,
    			ts_dev->steps_to_config);
    	return 0;
    }
    
    static struct platform_driver ti_tsc_driver = {
    	.probe	  = tscadc_probe,
    	.remove	 = __devexit_p(tscadc_remove),
    	.driver	 = {
    		.name   = "tsc",
    		.owner  = THIS_MODULE,
    	},
    	.suspend = tsc_suspend,
    	.resume = tsc_resume,
    };
    
    static int __init ti_tsc_init(void)
    {
    	return platform_driver_register(&ti_tsc_driver);
    }
    module_init(ti_tsc_init);
    
    static void __exit ti_tsc_exit(void)
    {
    	platform_driver_unregister(&ti_tsc_driver);
    }
    module_exit(ti_tsc_exit);
    
    MODULE_DESCRIPTION("TI touchscreen controller driver");
    MODULE_AUTHOR("Rachna Patil <rachna@ti.com>");
    MODULE_LICENSE("GPL");
    

  • Hi Santhosh,

    Did you find any solution for this problem?

    Santhosh Ramani said:

    1. Reading the ADC channels causes the Touch driver to stop working and cannot recover unless there is power cycle.

    Thanks

    Victor

  • Hello Victor,


    Unfortunately I was not able to find a good solution for this problem. The way I solved it is as follows:

    1. Re-write the ADC driver to suit my needs (increased sampling, increased sample and hold etc.)

    2. Removed the TI touch driver from my kernel

    3. Added external touch IC TSC2007 on an I2C bus

    4. Modified the driver for the TSC2007 to work with device tree (this might be fixed on the SDK 8.0 but wasn't part of SDK 7.0)

    If you'd like, I can send you the modified ADC driver and the TSC2007 driver. Hope this helps.

    Thank you

    Regards

    Santhosh

  • Try this:

    commit a447dab91a7ac5bb1397160436c6855e95556f7f
    Author: Brad Griffis <bgriffis@ti.com>
    Date:   Mon Nov 17 20:12:58 2014 -0600

        Avoid misalignment of TSC FIFO

    diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscre
    index 64d15f6..ea3e8c6 100644
    --- a/drivers/input/touchscreen/ti_am335x_tsc.c
    +++ b/drivers/input/touchscreen/ti_am335x_tsc.c
    @@ -215,7 +215,6 @@ static void titsc_step_config(struct titsc *ts_dev)
     static void titsc_read_coordinates(struct titsc *ts_dev,
                    u32 *x, u32 *y, u32 *z1, u32 *z2)
     {
    -       unsigned int fifocount = titsc_readl(ts_dev, REG_FIFO0CNT);
            unsigned int min_x, max_x, x_vals[7], x_cnt=0, x_sum=0;
            unsigned int min_y, max_y, y_vals[7], y_cnt=0, y_sum=0;
     
    @@ -223,8 +222,13 @@ static void titsc_read_coordinates(struct titsc *ts_dev,
            unsigned int creads = ts_dev->coordinate_readouts;
     
            *z1 = *z2 = 0;
    -       if (fifocount % (creads * 2 + 2))
    -               fifocount -= fifocount % (creads * 2 + 2);
    +
    +       while (titsc_readl(ts_dev, REG_FIFO0CNT) > (creads * 2 + 2)) {
    +               read = titsc_readl(ts_dev, REG_FIFO0);
    +       }
     
            /* Read 1st Y coordinate */
            read = titsc_readl(ts_dev, REG_FIFO0);

  • Hi Brad,

    I'm currently using a 3.2.42 kernel. There is no ti_am335x_tsc.c but ti_tscadc.c.
    I couldn't find similar pieces of code like these above.

    Thank you.
  • This was a minor fix-up to my patch-set for 3.12. Sorry, the 3.2 drivers are completely different.
  • Hi Santhosh! I didn't see your message on friday because you guys replied at the exactly same time. Your message didn't load when I saw the thread.

    I think I'm not gonna be able to do such modification on my hardware, but just in case, I'll appreciate if you provide the modified TSC2007 driver.

    Thank you very much!

  • Hi Brad,

    What is the plan for your patch? Is it being included in a new release of TI's SDK?

    Also, we have tried your patch and it has improved our touch screen operationg (we are using a 4-wire resistive touch screen) but we are noticed that when we are using our finger, the responses is not great when trying to do 'swipe' operationg. We have to press relatively hard on the screen.

    Is there a way I can adjust the sensitivity? For example for the device tree or ts.conf?

    Peter M.
  • Peter M said:

    What is the plan for your patch? Is it being included in a new release of TI's SDK?

    It was integrated into SDK 8.00 and also upstreamed to the mainline kernel (3.19?).

    Peter M said:
    Also, we have tried your patch and it has improved our touch screen operationg (we are using a 4-wire resistive touch screen) but we are noticed that when we are using our finger, the responses is not great when trying to do 'swipe' operationg. We have to press relatively hard on the screen.

    There's no way to adjust the sensitivity.  From my experience it is normal that you need to push fairly hard when you are using a finger (as opposed to a stylus).  When you are using your finger the pressure is being distributed over a much larger area.  If you use a stylus, or even the tip of your finger, you will see a significant improvement because the force gets concentrated into a smaller area (i.e. larger force at any given point).

  • Hey Brad,
    I wanted to share some info on this touch screen driver issue and then ask you a few quick questions.
    I am using linux kernel v3.12 and have verified that your patches are applied to my ti's tsc files.

    1. Using the ts_test & ts_print_raw programs, I have observed that a drop in 'touch' pressure when drawing a straight line will create a drastic jitters across the screen in the (x) coordinate direction. This jitter can have unwanted effects if, for example, a user is dragging a 'GUI scroll-bar' on the display. See results below. The columns are (x coordinates), (y coordinates), and (pressure).
                                                (x)    (y)    (pressure)
    1455655154.272601:    161    181    254
    1455655154.288827:    159    187    256
    1455655154.305037:    158    194    258
    1455655154.321250:    591    297    112
    1455655154.337468:    153    214    261
    1455655154.353670:    151    216    262
    1455655154.369877:    151    220    263
    1455655154.386081:    150    223    265
    1455655154.402293:    150    228    266
    1455655154.418513:    149    233    267
    1455655154.434731:    148    238    269
    1455655154.450937:    147    243    269
    1455655154.467156:    147    248    271
    1455655154.483377:    146    254    272
    1455655154.499594:    145    259    272
    1455655154.515814:    447    351    151
    1455655154.532091:    140    277    275
    1455655154.548332:    139    281    277

    When pressure dropped to 112 & 151, the x coordinates spiked to 591 and 447 respectively.

    Wolfgang Muees1 mentioned in his last post that there was electromagnetic interference with the 'pen down/up' detection in the analog front-end coming into the touch foils. Is this why the jitters/spikes are always in the +X direction?

    2. The min/max pressure in my touch screen is different in opposite corners. In the top right-hand corner of my screen, the max pressure is ~210. In the bottom left-hand corner, pmax is ~440. In /etc/ts.conf, setting a pmin to 150 will only eliminate the jitters the closer you get to the top-right hand corner.   

    3. After reviewing a ti_am335x_tsc patch for the linux 3.8 kernel designed by RobertC Nelson, I was able to piece together some code to apply on top of your 3.12 kernel changes to eliminate the jitters from the touch screen. Would you mind reviewing?
    https://github.com/EricZaluzec/ti_am335x_tsc/blob/master/remove-pressure-jitter.patch
    (see also attached.)
    For best results I modified the variance under /etc/ts.conf to '10'.

    This patch will eliminate most touch screen jitters, but a new (less critical) problem was introduced. It seems that any quick touches applied to the touch screen are not outputted by the raw tsc drivers. But a touch (using any pressure) that is held onto the screen for a couple of milliseconds will be picked up by the drivers. It feels like the driver is now waiting for a certain amount of samples to be taken before outputting any touch coordinates.
    Would you be able to point me in the right direction of where to modify the touchscreen driver to output touch point coordinates with less samples being taken?

    4. Moving forward with other kernels past 3.19, has there been any reports of same or improvements with the ti_am335x-tsc drivers?

    Thanks for all your work done on this issue.
    Any input would be very helpful.
    Regards,
    -Eric Zaluzec
    Eric.Zaluzec@Emerson.com

    remove-pressure-jitter.patch.txt
    diff -Nurd orig.kernel-source/drivers/input/touchscreen/ti_am335x_tsc.c mods.kernel-source/drivers/input/touchscreen/ti_am335x_tsc.c
    --- orig.kernel-source/drivers/input/touchscreen/ti_am335x_tsc.c	2016-02-25 15:19:45.424955522 -0500
    +++ mods.kernel-source/drivers/input/touchscreen/ti_am335x_tsc.c	2016-02-25 15:40:41.000000000 -0500
    @@ -52,6 +52,7 @@
     	u32			config_inp[4];
     	u32			bit_xp, bit_xn, bit_yp, bit_yn;
     	u32			inp_xp, inp_xn, inp_yp, inp_yn;
    +	unsigned int 		prevZ;
     };
     
     static unsigned int titsc_readl(struct titsc *ts, unsigned int reg)
    @@ -309,6 +310,7 @@
     	unsigned int status, irqclr = 0;
     	unsigned int x = 0, y = 0;
     	unsigned int z1, z2, z;
    +	int deltaZ;
     
     	status = titsc_readl(ts_dev, REG_RAWIRQSTATUS);
     
    @@ -347,7 +349,13 @@
     			z /= z2;
     			z = (z + 2047) >> 12;
     
    -			if (z <= MAX_12BIT) {
    +			// calculate the deltaZ :
    +			deltaZ= z - ts_dev->prevZ;
    +			// save the last z calculated :
    +			ts_dev->prevZ=z;
    +			pr_debug("x %d y %d deltaZ %d\n", x, y, deltaZ);
    +
    +			if (z <= MAX_12BIT && deltaZ>=0  && deltaZ<=10 ) {
     				input_report_abs(input_dev, ABS_X, x);
     				input_report_abs(input_dev, ABS_Y, y);
     				input_report_abs(input_dev, ABS_PRESSURE, z);
    @@ -466,6 +474,9 @@
     	input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0);
     	input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0);
     
    +	/*init prev Z*/
    +	ts_dev->prevZ=0;
    +		
     	/* register to the input system */
     	err = input_register_device(input_dev);
     	if (err)
    

  • Eric Zaluzec said:
    Wolfgang Muees1 mentioned in his last post that there was electromagnetic interference with the 'pen down/up' detection in the analog front-end coming into the touch foils. Is this why the jitters/spikes are always in the +X direction?

    I've really not spent much time looking at this from a noise perspective.  About my closest data point is the fact that I've had multiple customers relate "glitch behavior" to grounding issues.

    Eric Zaluzec said:
    3. After reviewing a ti_am335x_tsc patch for the linux 3.8 kernel designed by RobertC Nelson, I was able to piece together some code to apply on top of your 3.12 kernel changes to eliminate the jitters from the touch screen. Would you mind reviewing?
    https://github.com/EricZaluzec/ti_am335x_tsc/blob/master/remove-pressure-jitter.patch
    (see also attached.)
    For best results I modified the variance under /etc/ts.conf to '10'.

    This patch will eliminate most touch screen jitters, but a new (less critical) problem was introduced. It seems that any quick touches applied to the touch screen are not outputted by the raw tsc drivers. But a touch (using any pressure) that is held onto the screen for a couple of milliseconds will be picked up by the drivers.

    Interesting patch.  I hadn't considered this type of filtering with the Z coordinate.  That's kind of an extension of increasing pmin.  Be sure and have a number of users test your patch across different boards.  One thing I discovered in my original testing, is that there tends to be more variation across devices then I care for!  It takes a lot of effort and testing to find changes that really consistently improve the touch experience across all boards.

    Probably "the real test" will be for some other users with different hardware to try that same patch on their own boards.  If we consistently get an improvement, you might consider submitting upstream.

    Eric Zaluzec said:
    It feels like the driver is now waiting for a certain amount of samples to be taken before outputting any touch coordinates.
    Would you be able to point me in the right direction of where to modify the touchscreen driver to output touch point coordinates with less samples being taken?

    The "waiting for samples" is being done by your delta filter in that it only reports samples if they're within the specified threshold.

    Eric Zaluzec said:
    4. Moving forward with other kernels past 3.19, has there been any reports of same or improvements with the ti_am335x-tsc drivers?

    Just a patch related to using the touchscreen as a wakeup source for DeepSleep0:

    git.ti.com/.../0fd703378efe35ab1107af87399bd1479044b69e

  • Regarding jitter in resistive touch screens:


    a) every resistive touch screen has the problem that there are EMI spikes from the TFT.

    b) these spikes inject a small amount of charge into the touch foils.

    c) This charge causes an error in the X or Y measurement.

    d) Averaging the samples will make the error smaler, but the magnitude of the spike charge can be so high,

    that it is hopeless to eliminate the error by averaging.

    The only reliable solution to this problem is:

    1) make ADC measurements without much averaging.

    2) put the ADC samples into a buffer.

    3) sort the buffer in ascending order.

    4) make an average over the samples in the middle of the buffer, disregarding all samples with spike energy (which will be at the start and the end of the buffer).

    I have done this in my driver, and it works well. It will give a stable position. I have done this in another embedded environment too.

    Note that the linux kernel has a sort function.

    regards

    Wolfgang