You are reading a single comment by @allObjects and its replies. Click here to read the full conversation.
  • In many previous projects I used a 2.8" TFT 262K Color LCD display with resistive touchscreen. Since the display had no touchscreen controller, I implemented one on Espruino (Resistive Touchscreen directly (no touch controller)). Recently I wanted to use the display again, but for whatever reason it turned out to be dead not only like a possum, but really really dead. So I ordered some cheaper once of 2.2" size, since needed them just to verify code for the ILI9341 display controller.

    The cheap 2.4" display showed though up with a XPT2046 touchscreen controller from XPTEK TECHNOLOGY CO., LTD, SHENZHEN. After consulting the data sheet it seems that the XPT2046 is functionally about equal to Burr-Brown's / TI's ADS7843 and thus Espruino's ADS7843 module works... at least, it returns coordinates... dodged that bullet... easily...

    But from there on in went tricky to say the least... and unfortunately ended with the conclusion: module useless (from the point of usable values,.. and more), because the user's touch accuracy is about +- 2..3 pixels... but the module error is up to 32... just not useful for a touch UI.

    Why?

    Below code and and attached shot show. The code sets up the display and the touch screen, then draws calibration markers in all corners and the center and then logs values for calibration.

    // TFT24TRCportraitCalibr.js
    //
    //  2.4" 240x320 262K Color TFT LCD ILI9341 on SPI1 with 
    //  Resistive Touch Screen Controller XPT2046 on SPI2
    //  using out of box ILI9341 and ADS7843 modules.
    //
    // Wiring:
    //  2.4"
    //  DSP                  PICO [<---USB
    //   1   VCC      red     3   3.3            shared
    //   2   GND      blk     1   GND            shared
    //   3   CS       blu     7   B6   CS        LCD
    //   4   RST      brn     9   A8   reset RST LCD
    //   5   D/C      grn     8   B7   D/C       LCD
    //   6   MOSI     ylw     6   B5   SPI1 MOSI LCD
    //   7   SCK      wht     4   B3   SPI1 SCK  LCD
    //   8   LED      org    18   A5   LED       LCD
    //   9   MISO     grn     5   B4   SPI1 MISO LCD
    //  10   T_CLK    wht    23   B13  SPI2 SCK  Touch
    //  11   T_CS     ylw    22   B10  CS        Touch
    //  12   T_MOSI   grn    25   B15  SPI2 MOSI Touch
    //  13   T_MISO   blu    24   B14  SPI2 MISO Touch
    //  14   T_IRQ    blk    21   B1   IRQ       Touch
    
    var dW = 240, dH = 320, dsp, dMod = require("ILI9341"),
        tSPI=SPI2, tCs = B10, tIrq = B1, 
        touch, tMod = require("ADS7843");
    
    // marker specs (lik dice face 5; top left to bottom right)
    var mrks =
        [{i:1, label:"topLeft"    , x: 20, y: 20, xOff: 14, yOff:-6}
        ,{i:2, label:"topRight"   , x:220, y: 20, xOff:-66, yOff:-6}
        ,{i:3, label:"center"     , x:120, y:160, xOff:-29, yOff:14}
        ,{i:4, label:"bottomLeft" , x: 20, y:300, xOff: 14, yOff:-6}
        ,{i:5, label:"bottomRight", x:220, y:300, xOff:-74, yOff:-6}
        ];
    var mSiz = 9; // half of marker size, (0.7 of font size)
    
    // print marker at x/y of size s with x/y label
    function mrkr(d,x,y,s,xOff,yOff) {
      dsp.setColor(1,1,1);
      dsp.drawRect(x-s,y-s,x+s,y+s);
      dsp.drawLine(x-s,y,x+s,y);
      dsp.drawLine(x,y-s,x,y+s);
      dsp.setFontVector(s / 0.7);
      dsp.drawString(x + " / " + y, x+xOff, y+yOff);
    }
    
    function average(arry) { // return avarage of array values
      return arry.reduce(
        function(p,c) { return p + c; },0) / arry.length; }
    
    function logAverage(seq,xs,ys) { // log x / y average
      var x = Math.round(average(xs)), 
          y = Math.round(average(ys));
      console.log(
          seq + 1
        , mrks[seq].label
        , mrks[seq].x, mrks[seq].y
        , x ,"(" + (x - mrks[seq].x) + ")"
        , y ,"(" + (y - mrks[seq].y) + ")"
        );
    }
    
    function onInit() {
      A5.set();
      SPI1.setup({sck:B3, miso:B4, mosi:B5, baud: 1000000});
                       // spi, dc, cs, rst, callback
      dsp = dMod.connect(SPI1, B7, B6, A8, function() {
          dsp.clear();
          // print markers like dice face of 5
          mrks.forEach(function(m) {
            mrkr(dsp, m.x, m.y, mSiz, m.xOff, m.yOff); });
          // setup touchscreen with callback averaging
          // x and y sequence for calibration of 
          // touchscreen to lcd display.
          SPI2.setup({sck:B13, miso:B14, mosi:B15, baud: 2000000});
          var seq = 0, xs = [], ys = [], x, y;
          touch = tMod.connect(
                // spi, cs, irq, offsetx, offsety, w, h, callback // landscape
                SPI2, B10, B1,   -15,   6, dH, dW, function(yt, xt) {  // portrait
              if (yt !== undefined) {
                // collect x and y for averaging
                xs.push(dW - xt); ys.push(yt);
              } else {
                // log x and y avarages in console 
                logAverage(seq, xs, ys);
                xs = []; ys = []; seq   = (seq +1) % 5;
              }
          });
      });
    }
    
    onInit();
    

    The issues are:

    • ILI9341 initializes in portrait with x=0..239 - 240 pixels wide - and y=0...319 - 320 pixels high - and 0 / 0 top left (see shot).

    • XPT2046 controller is wired portrait, but not in a twisted way... not just rotated by 90 degrees... It could be fixed with the some additional calculation: with or hight - coordinate touch value.

    • it is not good enough to have an x and y offset for the controller function to calculate the actual x and y for a given display size. The offset helps with the touch screen not aligning with the display, but it messes up the scaling: if the low value is ok, the high value is too much off and vice versa. This can be seen in the output generated by above code when touching the calibration points from top left to bottom right.

    Because many touch screens are larger than the display because they show fixed, printed buttons in the overhang area. For touching in the overhang, proper calculation returns values beyond the screen coordinates.

    Produced output (aligned and with headings added):

     1v86 Copyright 2016 G.Williams
    >echo(0);
    =undefined
            expected x / y   effective (deviation)
    1 topLeft       20  20      21 (  1)  21 (  1)
    2 topRight     220  20     201 (-19)  22 (  2)
    3 center       120 160     110 (-10) 144 (-16)
    4 bottomLeft    20 300      19 ( -1) 271 (-29)
    5 bottomRight  220 300     203 (-17) 268 (-32)
    > 
    

    Looking at x coordinate, the low value is about correct, but the deviation for higher values goes linearly up by about 10 per 120 pixels (half screen width). The 'balconies' or 'porches'
    (screen vs display sizes and alignments) impact the calculation beyond what an offset can handle.

    Same can be said for the y coordinate: after adjusting with an offset, the error is even worse.

    Since the issues are hardware - wiring, size and alignment dependent, a module has to provide an option to pass a calculation function that takes minimum AND maximum touch values into account to scale properly with the display size. I'll take a stab at it and will publish in a next post.


    2 Attachments

About

Avatar for allObjects @allObjects started