Shop OBEX P1 Docs P2 Docs Learn Events
Propeller GUI touchscreen and full color display - Page 23 — Parallax Forums

Propeller GUI touchscreen and full color display

11819202123

Comments

  • average joeaverage joe Posts: 795
    edited 2013-10-27 20:24
    When I had things on the breadboard, with the CPLD it looked like it was going to work. Never had a chance to get past that point. I have a couple things I wanted to change but ran out of time.

    I've been using http://forums.parallax.com/showthread.php/134641-DEMO-High-Speed-Multi-Prop-to-Prop-Communication?highlight=beau%27s+high+speed
    It works great. Only requires 2 dedicated lines.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2013-10-27 21:38
    I know this is a little off topic, but has anyone been able to run this display with just a single 8 bit shift register? Would that be slower than connecting this display in 8 bit mode directly to the prop? Or... is 16 bit actually faster? I don't have the money to build an entire board, but am interested in using one of my 4 displays I have. I bought some of these about a year ago and never did anything except run one in 16 bit mode directly from the prop. Changing the screen color took 8 seconds which was WAY too slow for me.... I would be interested to simply draw some boxes, fill them with text and add a few buttons here and there :)
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2013-10-30 04:14
    Yes, you can run these displays with a latch. In fact, you can even run them with no TTL logic at all. 12 pins - 4 control and 8 data. The 8 seconds to refresh a screen would be the speed in Spin - you can get that down to about 30ms if you then recode it in pasm. The main reason for using external memory is so you can load bitmap fonts as these don't fit in the propeller memory.

    Attached is a board I am getting made.

    Going off on a slight tangent, I keep finding I need to put so many of the same components on new boards, and to save money I am constantly unsoldering components from other boards. So I have designed a "standard" motherboard - 10x10cm, VGA, TV, Keyboard, Analog IO, I2C header, SD card, eeprom, several different types of regulators and a MCP23017 for another 16 "slow" I/O pins. Then bring pins out to a 50 pin header. The schematic for the header is as shown on this attached schematic.

    Then additional boards are smaller and just need a short length of ribbon cable. This board for instance will cost $27 including shipping to get 5 made, so that makes prototyping easier.

    I don't know if the "50 pin header" standard will take off or not. I have tried other designs, including the arduino "stackable" system and using lots of smaller headers, but the 50 pin design seems to be working well for me :)
  • cavelambcavelamb Posts: 720
    edited 2013-10-30 11:08
    Dr_Acula wrote: »
    ...

    Actually, if we did build something with 4 bit serial sram chips, some preprocessing of images might be needed anyway. eg - to conserve precious propeller pins, have the concept of 'fast' prop pins which are real pins, and 'slow' pins which are on the I2C bus and a MCP23017 or two. So you would logically use fast pins to do things like clock the ram chip, and to clock the /wr pin on the display. But things like changing ram chips, ie the /cs pins could be slow pins. So for dumping data from a bitmap on an SD card out to the ram chips, it might make more sense to send all the data in blocks, first to one ram chip, then do the next one. So maybe you read a few kilobytes of a bitmap into hub ram off the SD card, then have a little bit of pasm code to mask out each nibble and send it out to the ram chips in the most time efficient way.

    ...
    The original propeller demo board has 8 pins for VGA, so many of my boards have 8 prop pins devoted to the display, whether it is TV or VGA.

    So maybe there is a cunning solution that can talk to a touchscreen using just 8 propeller pins (and then some slow I2C pins as needed).
    Something like 4 pins for data, one for the /wr pin on the touchscreen, one for the sram clock (join all the clocks together), and that is 6 pins so 2 spare for whatever is the most efficient solution.

    Things like the sram /cs pins, the touchscreen reset pin, the control pins for the 4052 chips and maybe the touchscreen RS pin are all slow pins off the MCP23017. In software, setup is slow, but dumping data is fast, and that is what you want for updating text and for moving sprites around.

    Back of an envelope design and count down from prop pin 31 - 2 pins for programming, 2 for I2C, 2 for audio, 2 for keyboard, 8 for display (combo touchscreen, VGA and TV), 4 for SD card, and 4 to run the finger sensor SPI on the display. That leaves 8 propeller pins free and free propeller pins are always a Good Thing :)

    So the chips would be propeller, eeprom, MCP23017 I2C expander, 4 sram chips, two 4052 chips.

    Need to read the sram chip data sheet more - can you set up a sram chip ready for burst mode, then deselect it by making its /cs pin high, then talk to other chips on the same 4 pins bus to set them all up for burst mode, then select all /cs pins low and start clocking?

    The more I think about this, the more I think we have to give it a try!

    Got a link to the data sheets you are using here?

    Because this all looks pretty solid...
  • average joeaverage joe Posts: 795
    edited 2013-10-30 23:15
    Nice work James! Looks like a winner to me. Let me know how this works out.

    I think this could be used with the FLASH chips I have as well. I was working on getting them running and never got around to finishing my PASM SPI driver. Things were slightly different since I had the 4 chips written and read in parallel. The commands were paralleled to the 4 chips and then data was sent 16 bits at a time. I'll be revisiting this before the end of the year. I was even working on a file system for the drive but once again never finished. If I can find a copy of the SPI driver I was working on I'd be willing to post here for S&G.

    The benefit of SRAM + FLASH would be common GUI elements could be placed on FLASH saving SRAM for stuff that changes more frequently. This would be a huge help for the 7" screen since loading a background image to SRAM took almost 5 seconds and used over half the memory. I even had an idea to create application "packages" that could be installed on FLASH. I was thinking about it in a computer sense, where FLASH is the hard drive (?SSD?) SD is the CD ROM and SRAM is the RAM :P
  • Igor_RastIgor_Rast Posts: 357
    edited 2014-02-04 13:35
    Its been some time , but I am thinking of picking op this project again and giving it some time .

    im in the process of setting up a small pcb etch station and lichgtbox to help me with make proto boards faster .

    My question is :
    Which of the 2 designs would you guy would you guys say will give us the best end result (Superior?)

    the CLPD design

    of the 23LC1024 quad design ,

    trying to start a new schematic for me to etch cause my last all wire approach suffered from all sorts of noise problems
    so im trying to go with a home made pcb , have almost all the parts already to build it . so ill be making a start in a few days i hope

    would love to hear how you guys going on with it these days

    Igor
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2014-02-04 14:33
    I haven't tested the CPLD or the 23LC1024 designs. I have the board for the latter but haven't soldered it up. So if you do either of these, you would need to write the software drivers. Shouldn't be too hard.
  • Igor_RastIgor_Rast Posts: 357
    edited 2014-02-04 14:50
    i was afraid so , but that wont stop me trying for that matter,
    the CPLD is what worried me a bit , cause i never worked with one before , but it does look like a slick solution.
    so maybe im gonna dive deep indeed , the 1024 looks more trait ahead from where i left it last ,

    also on discused was using the is62wv51216bll as ram , wich i now have here .

    so its kinda 2 questions

    1. with or withou CLPD to replace all the lose ic on the board.

    2. Memory

    a single is62wv51216bll
    or dual AS6C4008-55ZIN
    or quad 23LC1024

    igor
  • jmgjmg Posts: 15,140
    edited 2014-02-04 16:57
    Igor_Rast wrote: »
    so its kinda 2 questions

    1. with or withou CLPD to replace all the lose ic on the board.

    CPLD is always going to be more flexible, and have higher performance.
    A good ready to go PLD board, is the LCMXO2-7000HE-B-EVN ($26.23)
    That may mean you can skip special PCBs in the prelim stages.
    It is a quite large PLD, so you get RAM as well

    Or, if you want to do a own-PCB layout, you can still get PLCC PLDs eg ATF1508ASV-15JU84
    - not as much logic as Lattice and no RAM, but easy to work with in CUPL.
  • Igor_RastIgor_Rast Posts: 357
    edited 2014-02-04 17:14
    i have bought the xllinx xc2c64a on the guys here advice , havent used it yet cause i have only the bare ic , have to build the schematic yet

    And yes im plannning to build my own pcb , already have most, if not all parts , smd package . .
    including these,
    xllinx xc2c64a
    the is62wv51216bll wich should work best then i guess . gotta find that out. but for now looks like the startpoint

    but have to build the hole thing from scrath (never worked with CLPD before , but shoulded be too much of a trouble , i hope), so these gonna be some kicad around to get that working +


    CUPL ?? ok so know im confused :p
  • jmgjmg Posts: 15,140
    edited 2014-02-04 17:27
    Igor_Rast wrote: »
    CUPL ?? ok so know im confused :p

    CUPL is the language for ATF1508, think of it as Assembler for PLDs
    Easier to use than Verilog, very fast to compile and fit, but less suited to large designs.

    I think Xilinx still have a flow for ABEL syntax (Their version of CUPL), but last I looked they translated to HDL, so the compile speed was not so quick.

    xc2c64a is smallish, but will do simple counters/latches fine.
  • average joeaverage joe Posts: 795
    edited 2014-02-04 21:43
    There is a bit of learning curve to the ISE suite from Xilinx but once you get it, it's an awesome tool. I've refined the design and there is quite a bit of free space. There are also some free pins. Not sure what to do with them. IMHO it's an overkill solution. Have not had a chance to work on the design in a while.

    The 23LC1024 seem like a very slick design and would be my recommendation.
  • Igor_RastIgor_Rast Posts: 357
    edited 2014-02-05 02:54
    Thanks for the great tips guys

    an overkill leaves me room to do other things so that would be fine (second prop , wiznet )
    The 23LC1024 seem like a very slick design and would be my recommendation.

    that was what i was thinking too. guess ill have to dig into the Xilinx then
    ill try to post a schematic in a few days

    igor
  • jmgjmg Posts: 15,140
    edited 2014-02-05 11:24
    There is a bit of learning curve to the ISE suite from Xilinx but once you get it, it's an awesome tool. I've refined the design and there is quite a bit of free space. There are also some free pins. Not sure what to do with them. IMHO it's an overkill solution. Have not had a chance to work on the design in a while.

    The 23LC1024 seem like a very slick design and would be my recommendation.

    The LCD displays seem to be moving to the SSD1963 - I can find now 7", 5" and 4.3" and looking at the other LCD drivers, they seem to have the BUS setting locked in via pins (NOT user accessible) , whilst the SSD1963 allows register choice of Bus

    On most modules, they bring out 16b, so that gives a choice of 3x8/2x9/2x12/16/3x16 write modes in 1963

    A reasonable PLD would allow a 2x9 bus on Prop, saving pins, and running the LCD bus faster - but I think that choice is only there on SSD1963 modules ?.

    I also like the idea of a 4 bit SPI_Quad interface to the PLD, as that should upgrade to P2 with minimal LCD-side module hardware changes. Might allow a 10 pin ribbon connect ?
  • average joeaverage joe Posts: 795
    edited 2014-02-05 12:29
    jmg wrote: »
    The LCD displays seem to be moving to the SSD1963 - I can find now 7", 5" and 4.3" and looking at the other LCD drivers, they seem to have the BUS setting locked in via pins (NOT user accessible) , whilst the SSD1963 allows register choice of Bus

    On most modules, they bring out 16b, so that gives a choice of 3x8/2x9/2x12/16/3x16 write modes in 1963

    A reasonable PLD would allow a 2x9 bus on Prop, saving pins, and running the LCD bus faster - but I think that choice is only there on SSD1963 modules ?.

    I also like the idea of a 4 bit SPI_Quad interface to the PLD, as that should upgrade to P2 with minimal LCD-side module hardware changes. Might allow a 10 pin ribbon connect ?

    I use SSD1963 and SSD1289 displays. Both allow BUS settings so configuration is fairly flexible.

    I've already got a p2 board designed, just waiting for a working chip before I send to FAB. The P1 version is done, other than layout (that I can never seem to find time to complete)
  • jmgjmg Posts: 15,140
    edited 2014-02-05 12:45
    I use SSD1963 and SSD1289 displays. Both allow BUS settings so configuration is fairly flexible.

    Do you mean pin-set, or SW set ?

    In SSD1963, there is set_pixel_data_interface (Command 0xF0) that allows SW choice of Pixels, but inSSD1289 I can see only
    pin-choice control for pixel-writes ? (and I've not seen Chinese modules that think to allow user pin-set )
  • Igor_RastIgor_Rast Posts: 357
    edited 2014-02-05 13:28
    I've already got a p2 board designed, just waiting for a working chip before I send to FAB. The P1 version is done, other than layout (that I can never seem to find time to complete)

    I guess you made a jump to the emulated p2 to make it work right ? , i though i wait for the real thing but that is taking some time also ,

    and how do the end result look like on a p2 , lcd much much better(faster), or just a bit , makes me curious

    im into building my own pcb , so i would love to see your done with p1 schematic , the layout ill have to tackle on my own anyway
  • average joeaverage joe Posts: 795
    edited 2014-02-05 13:55
    Igor_Rast wrote: »
    I guess you made a jump to the emulated p2 to make it work right ? , i though i wait for the real thing but that is taking some time also ,

    and how do the end result look like on a p2 , lcd much much better(faster), or just a bit , makes me curious

    im into building my own pcb , so i would love to see your done with p1 schematic , the layout ill have to tackle on my own anyway

    Have not gone as far as emulation yet. I'll dig up those schematics when I get a chance. I've been so busy with everything else on my plate I've hardly had a chance to work on the project. From my projections, it won't be THAT much faster on p2. RAM2Display is already pushing the display's fmax. The biggest improvement will be the number of pins as well as cogs left over.
  • Igor_RastIgor_Rast Posts: 357
    edited 2014-02-05 14:03
    Copy that , hopefully i get some time for it too , well thats what i planed for now ,

    well see what will happen in the mean time, was very busy too , finalizing my last year as building engineer now ( imagine the combination with out hobby)
    give or take 5 months to go, Time was all out , hopefully i get some now , wount be all i want anyway . more scool stuff also to get that done bye the summer .
    than its all out .

    Gotta keep my hacking mind happy too :smile:
    but ill be working on it again and wondering around here on the forms

    cheers
  • average joeaverage joe Posts: 795
    edited 2014-11-10 00:20
    Had some spare time (and motivation) to get the 7" display working again. After spending a day trying to get the driver build working again, I had a background image. Then to get the touchscreen reading again.. And then the coding. I know I'm still doing something wrong with the calibration, but I'm not sure what. Here's what the calibration looks like:
    '*********************************************
    '* Spin code generated by cspin version 0.82 *
    '*********************************************
    {
     *   Copyright (c) 2001, Carlos E. Vidales. All rights reserved.
     *    This sample program was written matrixd put in the public domain by Carlos E. Vidales.  The program is provided "as is" without warrmatrixty of matrixy kind,
     *    either expressed or implied. If you choose to use the program within your own products you do so at your own risk, matrixd assume the responsibility
     *    for servicing, repairing or correcting the program should it prove defective in matrixy mmatrixner. You may copy matrixd distribute the program's source code
     *    in matrixy  medium, provided that you also include in each copy matrix appropriate copyright notice matrixd disclaimer of warrmatrixty. You may also modify this
     *    program matrixd distribute copies of it provided that you include prominent notices stating that you chmatrixged the file(s) matrixd the date of matrixy chmatrixge,
     *    matrixd that you do not charge matrixy royalties or licenses for its use.
    
      NOTE: Even though the validity of the calibration/trmatrixslation method proposed has been verified with empirical data from several actual touch screen
      enabled displays, for the convenience of this exercise, the raw matrixd expected data used matrixd presented below are artificial.  When used with actual data
      the functions presented yield results that may be off by a larger but still small percentage (~1-3%) due to electrical noise matrixd hummatrix error (i.e., the
      hmatrixd touching a screen target matrixd missing by a small amount.) The array of input points.  The first three are used for calibration. These set of points
      assume that the touchscreen has vertical matrixd horizontal resolutions of 1024 pixels (10-bit digitizer.)
     *  From the article text, recall that the matrix coefficients are resolved to be the following: 
     *
     *      Divider =  (Xs0 - Xs2)*(Ys1 - Ys2) - (Xs1 - Xs2)*(Ys0 - Ys2)
     *
     *
     *
     *                 (Xd0 - Xd2)*(Ys1 - Ys2) - (Xd1 - Xd2)*(Ys0 - Ys2)
     *            A = ---------------------------------------------------
     *                                   Divider
     *
     *
     *                 (Xs0 - Xs2)*(Xd1 - Xd2) - (Xd0 - Xd2)*(Xs1 - Xs2)
     *            B = ---------------------------------------------------
     *                                   Divider
     *
     *
     *                 Ys0*(Xs2*Xd1 - Xs1*Xd2) + 
     *                             Ys1*(Xs0*Xd2 - Xs2*Xd0) + 
     *                                           Ys2*(Xs1*Xd0 - Xs0*Xd1)
     *            C = ---------------------------------------------------
     *                                   Divider
     *
     *
     *                 (Yd0 - Yd2)*(Ys1 - Ys2) - (Yd1 - Yd2)*(Ys0 - Ys2)
     *            D = ---------------------------------------------------
     *                                   Divider
     *
     *
     *                 (Xs0 - Xs2)*(Yd1 - Yd2) - (Yd0 - Yd2)*(Xs1 - Xs2)
     *            E = ---------------------------------------------------
     *                                   Divider
     *
     *
     *                 Ys0*(Xs2*Yd1 - Xs1*Yd2) + 
     *                             Ys1*(Xs0*Yd2 - Xs2*Yd0) + 
     *                                           Ys2*(Xs1*Yd0 - Xs0*Yd1)
     *            F = ---------------------------------------------------
     *                                   Divider
     *
     }
    
    CON
      MAX_SAMPLES =   3
      An          =   0
      Bn          =   1
      Cn          =   2
      Dn          =   3
      En          =   4
      Fn          =   5
      Divider     =   6
    
    DAT      
    {{
      The array of input points. The first three are used for calibration. These set of points assume that the touchscreen has vertical and horizontal
      resolutions of 1024 pixels (10-bit digitizer.)
      screenXSample long 073, 891, 512
      screenYSample long 154, 516, 939
      The array of expected "right answers." The values selected assume a vertical and horizontal display resolution of 240 pixels.(Actual display is 480*800)           
      displayXSample long 060, 420, 240
      displayYSample long 100, 400, 700
      An array of perfect input screen points used to obtain a first pass calibration matrix good enough to collect calibration samples.
    }}
      perfectXScreenSample long  100, 900, 500
      perfectYScreenSample long  100, 500, 900
    {{
      An array of perfect display points used to obtain a first pass calibration matrix good enough to collect calibration samples.
    }}
      perfectXDisplaySample long 100, 900, 500
      perfectYDisplaySample long 100, 500, 900    
    
    DAT matrix long 0[7]
    
    PUB init
     result := setCalibrationMatrix(@perfectXDisplaySample, @perfectYDisplaySample, @perfectXScreenSample, @perfectYScreenSample)
    
    PUB GetMatrixAddress
      result := @matrix
    
    PUB setCalibrationMatrix(displayXPtr, displayYPtr, screenXPtr, screenYPtr)
    {{
     *  Function: setCalibrationMatrix()
     *  Description: Calling this function with valid input data in the display matrixd screen input arguments causes the calibration factors between the screen
     *    matrixd display points to be calculated, matrixd the output argument - matrixPtr - to be populated. This function needs to be called only when new
     *    calibration factors are desired.
     *  
     *  Argument(s): displayPtr (input) - Pointer to matrix array of three sample, reference points.
     *               screenPtr (input) - Pointer to the array of touch screen points corresponding to the reference display points.
     *               matrixPtr (output) - Pointer to the calibration matrix computed for the set of points being provided.
    }}
        result := false    
      long[@matrix][Divider] := ((long[screenXPtr][0] - long[screenXPtr][2]) * (long[screenYPtr][1] - long[screenYPtr][2])) - {{
                              }}((long[screenXPtr][1] - long[screenXPtr][2]) * (long[screenYPtr][0] - long[screenYPtr][2]))
        if(long[@matrix][6] == 0 )
          return false      
      long[@matrix][An] := ((long[displayXPtr][0] - long[displayXPtr][2])  * (long[screenYPtr] [1] -  long[screenYPtr] [2])) - {{
                         }}((long[displayXPtr][1] - long[displayXPtr][2])  * (long[screenYPtr] [0] -  long[screenYPtr] [2]))                                            
      long[@matrix][Bn] := ((long[screenXPtr] [0] - long[screenXPtr] [2] ) * (long[displayXPtr][1] -  long[displayXPtr][2])) - {{
                         }}((long[displayXPtr][0] - long[displayXPtr][2])  * (long[screenXPtr] [1] -  long[screenXPtr] [2]))
      long[@matrix][Cn] :=  (long[screenXPtr] [2] * long[displayXPtr][1]   - long[screenXPtr]  [1] *  long[displayXPtr][2])  * long[screenYPtr][0] + {{
                          }}(long[screenXPtr] [0] * long[displayXPtr][2]   - long[screenXPtr]  [2] *  long[displayXPtr][0])  * long[screenYPtr][1] + {{
                          }}(long[screenXPtr] [1] * long[displayXPtr][0]   - long[screenXPtr]  [0] *  long[displayXPtr][1])  * long[screenYPtr][2] 
      long[@matrix][Dn] := ((long[displayYPtr][0] - long[displayYPtr][2])  * (long[screenYPtr] [1] -  long[screenYPtr] [2])) - {{
                         }}((long[displayYPtr][1] - long[displayYPtr][2])  * (long[screenYPtr] [0] -  long[screenYPtr] [2]))                  
      long[@matrix][En] := ((long[screenXPtr] [0] - long[screenXPtr] [2])  * (long[displayYPtr][1] -  long[displayYPtr][2])) -  {{
                         }}((long[displayYPtr][0] - long[displayYPtr][2])  * (long[screenXPtr] [1]  - long[screenXPtr] [2]))                      
      long[@matrix][Fn] :=  (long[screenXPtr] [2] * long[displayYPtr][1]   -  long[screenXPtr] [1]  * long[displayYPtr][2])  * long[screenYPtr] [0] + {{
                          }}(long[screenXPtr] [0] * long[displayYPtr][2]   -  long[screenXPtr] [2]  * long[displayYPtr][0])  * long[screenYPtr] [1] + {{
                          }}(long[screenXPtr] [1] * long[displayYPtr][0]   -  long[screenXPtr] [0]  * long[displayYPtr][1])  * long[screenYPtr] [2]
                     
      return true
       
    PUB getXDisplayPoint(x,y)    
    {{
     *  Function   : getDisplayPoint()
     *  Description: Given a valid set of calibration factors matrixd a point value reported by the touch screen, this function calculates matrixd returns the true
     *  (or closest to true) display point below the spot where the touch screen was touched.   
     * 
     *  Argument(s): screen (input) - The reported touch screen point.
     *               matrixPtr (input) - Pointer to calibration factors matrix previously calculated from a call to setCalibrationMatrix() 
    }}
        result := ((long[@matrix][An] * x) + (long[@matrix][Bn] * y) + long[@matrix][Cn]) / long[@matrix][Divider]        ' x 
    
    
      
    PUB getYDisplayPoint(x,y)    | t
    {{
     *  Function   : getDisplayPoint()
     *  Description: Given a valid set of calibration factors matrixd a point value reported by the touch screen, this function calculates matrixd returns the true
     *  (or closest to true) display point below the spot where the touch screen was touched.   
     * 
     *  Argument(s): screen (input) - The reported touch screen point.
     *               matrixPtr (input) - Pointer to calibration factors matrix previously calculated from a call to setCalibrationMatrix()
    }}
                                                                                       
      result := (((long[@matrix][Dn] * x) + (long[@matrix][En] * y) + long[@matrix][Fn]) / long[@matrix][Divider]) 
    
                  
    

    Then the code that interfaces with this:
    PRI RunCal |  n,  error 
    
      error := \fat.openfile(String("Cal.cal"),"R")
      if  fat.partitionerror     '? ifnot ?                    ' failed to find the file
        text(error)
        fat.newFile(String("Cal.cal"))
      else
         fat.fileSeek(0)
        repeat n from 0 to 6
          long[cal.GetMatrixAddress][n] := fat.readLong
    '    return
      fat.closeFile
    
      sysfont := LoadFont(string("sysfont.ifn"))
      clearscreen($FFFe)
      SetCursor(0,0)
      TextT(sysfont,string(13,10,13,10,13,10,13,10,"          Touch the X on the next screens")) 
      TextT(sysfont,string(13,10,13,10,13,10,13,10,"          Touch Screen to continue")) 
    
      repeat while RawTouch  == $FFFF
    
      cal.init
      GetScreenSample   
      cal.setCalibrationMatrix(@displayXSample, @displayYSample, @screenXSample, @screenYSample)
    
      fat.openFile(String("Cal.cal"), "W") 
        repeat n from 0 to 6
          fat.writeLong(long[cal.GetMatrixAddress][n])    
        fat.closeFile
    
    
    PRI GetScreenSample  | n, x, y
        
      repeat n from 0 to cal#MAX_SAMPLES - 1
        SetCursor(long[@displayXSample][n],long[@displayYSample][n])
        SelectMemGroup
        clearscreen($FFFe)   
        TextT(sysfont,string("X"))
        pause1ms(2000) 
          repeat 10_000
              repeat while (result := TouchValue) == $FFFF
              x += result & $FFFF
              y += (result >> 16) & $FFFF
              x /= 2
              y /= 2
        long[@screenXSample][n] := x
        long[@screenYSample][n] := y        
        clearscreen($FFFe)
        SetCursor(200,400)
        TextT(sysfont,string("DONE"))
        pause1ms(2000)
    
    Pri RawTouch | xval,yval
        SelectSPIGroup    
        xval := TouchX >>2 
        yval := TouchY >>2
        if xval <> 0 and yval <> 0                    ' both have to be valid for a touch
          xval := TouchX >>2
          yval := TouchY >>2
          if xval <> 0 and yval <> 0                    ' both have to be valid for a touch
        result := (yval << 16) + (xval)
        if xval == 0 or yval == 0 
            result := $0000FFFF                             ' invalid number(s)
              
    PRI TouchValue | xval,yval,x,y ' returns % values 0-100% (or 65535 for no touch)
      result := RawTouch
      if result == $FFFF
        return
      x := result & $FFFF
      y := (result >> 16)& $FFFF
      xval := cal.getXDisplayPoint(x,y)
      yval := cal.getYDisplayPoint(x,y)
      result := xval + (yval  << 16)
    
    PRI TouchY                                                 '  S A0-A2  mode  S/D   PD1-PD '' should be compatible!!
          SPI.SHIFTOUT(PIN#Touch_DataIn, PIN#Touch_Clock, 5, 8 , %1__101____0_____0____00) ' reads x from 500 to 3700 (off < 500 )
          result := SPI.SHIFTIN(PIN#Touch_DataOut,PIN#Touch_Clock,2, 12)
    
    
    PRI TouchX      
          SPI.SHIFTOUT(PIN#Touch_DataIn, PIN#Touch_Clock, 5, 8 , %1_001_0_0_00) ' reads y from 400 to 3800 (off > 3800 )
          result := $fff - SPI.SHIFTIN(PIN#Touch_DataOut,PIN#Touch_Clock,2, 12)
    
    
    

    It still doesn't calibrate quite right. Not sure what the problem is really. I'll be writing a "log file" on my next few tests that will hopefully track the problem down. Here's a standalone version of the calibrate program.
    '*********************************************
    '* Spin code generated by cspin version 0.82 *
    '*********************************************
    {
     *   Copyright (c) 2001, Carlos E. Vidales. All rights reserved.
     *    This sample program was written and put in the public domain by Carlos E. Vidales.  The program is provided "as is" without warranty of any kind,
     *    either expressed or implied. If you choose to use the program within your own products you do so at your own risk, and assume the responsibility
     *    for servicing, repairing or correcting the program should it prove defective in any manner. You may copy and distribute the program's source code
     *    in any  medium, provided that you also include in each copy an appropriate copyright notice and disclaimer of warranty. You may also modify this
     *    program and distribute copies of it provided that you include prominent notices stating that you changed the file(s) and the date of any change,
     *    and that you do not charge any royalties or licenses for its use.
    
      NOTE: Even though the validity of the calibration/translation method proposed has been verified with empirical data from several actual touch screen
      enabled displays, for the convenience of this exercise, the raw and expected data used and presented below are artificial.  When used with actual data
      the functions presented yield results that may be off by a larger but still small percentage (~1-3%) due to electrical noise and human error (i.e., the
      hand touching a screen target and missing by a small amount.) The array of input points.  The first three are used for calibration. These set of points
      assume that the touchscreen has vertical and horizontal resolutions of 1024 pixels (10-bit digitizer.)
    
                    NOTE!    NOTE!    NOTE!                                                              
      setCalibrationMatrix() and getDisplayPoint() will do fine for you as they are, provided that your digitizer resolution does not exceed 10 bits
     (1024 values). Higher resolutions may cause the integer operations to overflow and return incorrect values. If you wish to use these functions with
     digitizer resolutions of 12 bits (4096 values) you will either have to a) use 64-bit signed integer variables and math, or b) judiciously modify the
     operations to scale results by a factor of 2 or even 4.
     
     *  From the article text, recall that the matrix coefficients are resolved to be the following:
     *
     *      Divider =  (Xs0 - Xs2)*(Ys1 - Ys2) - (Xs1 - Xs2)*(Ys0 - Ys2)
     *
     *
     *
     *                 (Xd0 - Xd2)*(Ys1 - Ys2) - (Xd1 - Xd2)*(Ys0 - Ys2)
     *            A = ---------------------------------------------------
     *                                   Divider
     *
     *
     *                 (Xs0 - Xs2)*(Xd1 - Xd2) - (Xd0 - Xd2)*(Xs1 - Xs2)
     *            B = ---------------------------------------------------
     *                                   Divider
     *
     *
     *                 Ys0*(Xs2*Xd1 - Xs1*Xd2) + 
     *                             Ys1*(Xs0*Xd2 - Xs2*Xd0) + 
     *                                           Ys2*(Xs1*Xd0 - Xs0*Xd1)
     *            C = ---------------------------------------------------
     *                                   Divider
     *
     *
     *                 (Yd0 - Yd2)*(Ys1 - Ys2) - (Yd1 - Yd2)*(Ys0 - Ys2)
     *            D = ---------------------------------------------------
     *                                   Divider
     *
     *
     *                 (Xs0 - Xs2)*(Yd1 - Yd2) - (Yd0 - Yd2)*(Xs1 - Xs2)
     *            E = ---------------------------------------------------
     *                                   Divider
     *
     *
     *                 Ys0*(Xs2*Yd1 - Xs1*Yd2) + 
     *                             Ys1*(Xs0*Yd2 - Xs2*Yd0) + 
     *                                           Ys2*(Xs1*Yd0 - Xs0*Yd1)
     *            F = ---------------------------------------------------
     *                                   Divider
     *
     }
    CON                                              
      _clkmode      = xtal1 + pll16x                        ' use crystal x 16
      _xinfreq      = 6_250_000                             ' 5Mhz crystal
    
    
    VAR
      byte font  
    
    OBJ
            cal : "cal.spin"
            tch : "Touch_v1_0_1963a.spin"
    
    DAT      
    {{
      The array of input points. The first three are used for calibration. These set of points assume that the touchscreen has vertical and horizontal
      resolutions of 1024 pixels (10-bit digitizer.)
    }}
      screenXSample long 073, 891, 512
      screenYSample long 154, 516, 939
    {{
      The array of expected "right answers." The values selected assume a vertical and horizontal display resolution of 240 pixels.(Actual display is 480*800)
    }}           
      displayXSample long 060, 420, 240
      displayYSample long 100, 400, 700
    {{
      An array of perfect input screen points used to obtain a first pass calibration matrix good enough to collect calibration samples.
    }}
      perfectXScreenSample long  100, 900, 500
      perfectYScreenSample long  100, 500, 900
    {{
      An array of perfect display points used to obtain a first pass calibration matrix good enough to collect calibration samples.
    }}
      perfectXDisplaySample long 100, 900, 500
      perfectYDisplaySample long 100, 500, 900  
    
    PUB main |  n, m, x, y 
    {*********************************************************************
     *  Function   : main()
     *  Description: Entry point into console version of sample
     *                program that exercises the calibration 
     *                functions. 
     *  Argument(s): argCount - the number of arguments provided
     *               argValue - pointer to the list of char strings 
     *                           representing the command line arguments. 
    }
    
      tch.BeginDesktop("7")               
      font := tch.LoadFont(string("sysfont.ifn"))
      tch.Clearscreen($FFFe)  
      tch.SetCursor(0,0)
      tch.TextT(font, string("Touch Screen Calibration Sample Code,",13,10))
      tch.TextT(font, string("by Carlos E. Vidales, Copyright 2001.",13,10))
      tch.TextT(font, string(13,10))
            
    {{
      The following call calculates the translation matrix that results when the three consecutive points in the sample set are used. Such points are assumed
      to be properly spaced within the screen surface. Note that we call the function twice as we would normally do within a calibration routine. The first
      time we call it using a perfect set of display and screen arguments. Such a call is made to obtain a calibration matrix that is just good enough to
      collect samples to do the real calibration.
      Look at the matrix values when we use a perfect sample set. The result is a unity matrix.
    }}
    
      if cal.setCalibrationMatrix(@perfectXDisplaySample, @perfectYDisplaySample, @perfectXScreenSample, @perfectYScreenSample)
        n := cal.getMatrixAddress                                                                                              
        tch.TextT(font,string(13,10,"Look at the unity matrix:",13,10,13,10))
        tch.TextT(font,string("An=             Bn=             Cn=      ",13,10 ))
        tch.TextT(font,string("Dn=             En=             Fn=      ",13,10))
        tch.TextT(font,string("          Divider =      ",13,10))
        tch.SetCursor(38,120)  
        tch.TextDec(font,long[n][0])
        tch.SetCursor(200,120)
        tch.TextDec(font,long[n][1])
        tch.SetCursor(360,120)
        tch.TextDec(font,long[n][2])
        tch.SetCursor(38,140)  
        tch.TextDec(font,long[n][3])
        tch.SetCursor(200,140)  
        tch.TextDec(font,long[n][4])
        tch.SetCursor(360,140)  
        tch.TextDec(font,long[n][5])
        tch.SetCursor(200,160)  
        tch.TextDec(font,long[n][6]) 
      else
        tch.TextT(font,string(13,10,"Calibration Failed",13,10,13,10))
        
    {{
      Now is when we need to do the work to collect a real set of calibration data. Draw three targets on your display. Drawing one at time is probably a
      simpler implementation. These targets should be widely separated but also avoid the areas too near the edges where digitizer output tends to become
      non-linear. The recommended set of points is (in display resolution percentages):       
                         ( 15, 15)                                    
                         ( 50, 85)                                 
                         ( 85, 50)                                                                
      Each time save the display and screen set (returned by the digitizer when the user touches each calibration target into the corresponding array).
      Since you normalized your calibration matrix above, you should be able to use touch screen data as it would be provided by the digitizer driver.
      When the matrix equals unity, getDisplayPoint() returns the same raw input data as output. Call the function once more to obtain the calibration factors
      you will use until you calibrate again.
      Let's see the matrix values for no particular reason.
    }}
      
      if cal.setCalibrationMatrix(@displayXSample, @displayYSample, @screenXSample, @screenYSample)     
        n := cal.getMatrixAddress
        tch.SelectMemGroup 
        tch.TextT(font,string(13,10,13,10,"This is the actual calibration matrix that we",13,10))
        tch.TextT(font,string("will use for all points",13,10))
        tch.TextT(font,string("(until we calibrate again):",13,10))
        tch.TextT(font,string("An=             Bn=             Cn=      ",13,10 ))
        tch.TextT(font,string("Dn=             En=             Fn=      ",13,10))
        tch.TextT(font,string("          Divider =      ",13,10))
        tch.SetCursor(38,260)  
        tch.TextDec(font,long[n][0])
        tch.SetCursor(200,260)
        tch.TextDec(font,long[n][1])
        tch.SetCursor(360,260)
        tch.TextDec(font,long[n][2])
        tch.SetCursor(38,280)  
        tch.TextDec(font,long[n][3])
        tch.SetCursor(200,280)  
        tch.TextDec(font,long[n][4])
        tch.SetCursor(360,280)  
        tch.TextDec(font,long[n][5])
        tch.SetCursor(200,300)  
        tch.TextDec(font,long[n][6])
      else
        tch.TextT(font,string(13,10,"Calibration Failed",13,10,13,10))
    
    {{
      Now, lets use the complete set of screen samples to verify that the calculated calibration matrix does its job as expected.
      In a real application, your digitizer driver interrupt would probably do the following:
             1) collect raw digitizer data,                         
             2) filter the raw data which would probably contain position jitter                                                
             3) filter out repeated values (a touch screen controller normally continues causing interrupts and collecting data as long as the user is pressing
                on the screen), and                                
             4) call the function getDisplayPoint() to obtain the display coordinates that the user meant to input as he touched the screen.                                                                          
      This code sample, of course, only uses sample data. So we simply run through all the available sample points
    }}
    
      tch.SelectMemGroup
      tch.TextT(font,string(13,10,13,10,"Show the results of our work:",13,10,13,10))
      tch.TextT(font,string("Screen Sample  Translated Sample  Display Sample"))
    
      n := cal.getMatrixAddress
      repeat m from 0 to cal#MAX_SAMPLES - 1
        tch.TextT(font,string(13,10,13,10)) 
        tch.TextT(font,string("   X =  ")) 
        tch.TextDec(font,long[@screenXSample][m])
        tch.TextT(font,string("          "))
        tch.TextDec(font,cal.getXDisplayPoint(long[@screenXSample][m],long[@screenYSample][m]))
        tch.TextT(font,string("          "))
        tch.TextDec(font,long[@displayXSample][m])
    
        tch.TextT(font,string(13,10))
        tch.TextT(font,string("   Y =  ")) 
        tch.TextDec(font,long[@screenYSample][m])
        tch.TextT(font,string("          ")) 
        tch.TextDec(font,cal.getYDisplayPoint(long[@screenXSample][m], long[@screenYSample][m]))
        tch.TextT(font,string("          "))  
        tch.TextDec(font,long[@displayYSample][m])
    
      tch.TextT(font,string(13,10,13,10,13,10,13,10,"          Touch Screen to continue")) 
      repeat while tch.TouchValue  == $FFFF
    
      '' now we do an actual calibration
    
      tch.clearscreen($FFFe)                                                   
      tch.SetCursor(0,0)
      tch.TextT(font,string(13,10,"Now lets try an actual calibration",13,10))
      tch.TextT(font,string(13,10,"First reset the matrix to unity values",13,10))
      
        if cal.setCalibrationMatrix(@perfectXDisplaySample, @perfectYDisplaySample, @perfectXScreenSample, @perfectYScreenSample)
          n := cal.getMatrixAddress
          tch.TextT(font,string("Look at the unity matrix:",13,10,13,10))
          tch.TextT(font,string("An=             Bn=             Cn=      ",13,10 ))
          tch.TextT(font,string("Dn=             En=             Fn=      ",13,10))
          tch.TextT(font,string("          Divider =      ",13,10))
          tch.SetCursor(38,120)  
          tch.TextDec(font,long[n][0])
          tch.SetCursor(200,120)
          tch.TextDec(font,long[n][1])
          tch.SetCursor(360,120)
          tch.TextDec(font,long[n][2])
          tch.SetCursor(38,140)  
          tch.TextDec(font,long[n][3])
          tch.SetCursor(200,140)  
          tch.TextDec(font,long[n][4])
          tch.SetCursor(360,140)  
          tch.TextDec(font,long[n][5])
          tch.SetCursor(200,160)  
          tch.TextDec(font,long[n][6]) 
        else
          tch.TextT(font,string(13,10,"Calibration Failed",13,10,13,10))
    
      tch.TextT(font,string(13,10,13,10,13,10,13,10,"          Touch the X on the next screens")) 
      tch.TextT(font,string(13,10,13,10,13,10,13,10,"          Touch Screen to continue")) 
      repeat while tch.TouchValue  == $FFFF
    
      repeat n from 0 to cal#MAX_SAMPLES - 1
        tch.SetCursor(long[@displayXSample][n],long[@displayYSample][n])
        tch.SelectMemGroup
        tch.clearscreen($FFFe)   
        tch.TextT(font,string("X"))
          repeat while (result := tch.TouchValue) == $FFFF
          x := result & $FFFF
          y := (result >> 16) & $FFFF
            repeat 1_000
              repeat while (result := tch.TouchValue) == $FFFF
              x += result & $FFFF
              y += (result >> 16) & $FFFF
              x /= 2
              y /= 2
        long[@screenXSample][n] := x
        long[@screenYSample][n] := y        
        tch.clearscreen($FFFe)
        tch.SetCursor(200,400)
        tch.TextT(font,string("DONE"))
        tch.pause1ms(2000)
    
      tch.SetCursor(0,0)
      if cal.setCalibrationMatrix(@displayXSample, @displayYSample, @screenXSample, @screenYSample)     
        n := cal.getMatrixAddress
        tch.SelectMemGroup
        tch.clearscreen($FFFe)    
        tch.TextT(font,string(13,10,13,10,"  This is the actual calibration matrix",13,10))
        tch.TextT(font,string("  from the points we collected",13,10))
        tch.TextT(font,string(13,10,13,10))
        tch.TextT(font,string("An=             Bn=             Cn=      ",13,10 ))
        tch.TextT(font,string("Dn=             En=             Fn=      ",13,10))
        tch.TextT(font,string("          Divider =      ",13,10))
        tch.SetCursor(38,120)  
        tch.TextDec(font,long[n][0])
        tch.SetCursor(200,120)
        tch.TextDec(font,long[n][1])
        tch.SetCursor(360,120)
        tch.TextDec(font,long[n][2])
        tch.SetCursor(38,140)  
        tch.TextDec(font,long[n][3])
        tch.SetCursor(200,140)  
        tch.TextDec(font,long[n][4])
        tch.SetCursor(360,140)  
        tch.TextDec(font,long[n][5])
        tch.SetCursor(200,160)  
        tch.TextDec(font,long[n][6])
      else
        tch.TextT(font,string(13,10,"Calibration Failed",13,10,13,10))
        
      tch.TextT(font,string(13,10,13,10,13,10,13,10,"          Touch Screen to continue"))           
      repeat while tch.TouchValue  == $FFFF
      
      tch.SelectMemGroup
      tch.clearscreen($FFFe)                                                   
      tch.SetCursor(0,0)
      tch.TextT(font,string(13,10,13,10,"Show the results of our work:",13,10,13,10))
      tch.TextT(font,string("Screen Sample  Translated Sample  Display Sample"))
    
      n := cal.getMatrixAddress
      repeat m from 0 to cal#MAX_SAMPLES - 1
    
        tch.TextT(font,string(13,10,13,10)) 
        tch.TextT(font,string("   X =  ")) 
        tch.TextDec(font,long[@screenXSample][m])
        tch.TextT(font,string("          "))
        tch.TextDec(font,cal.getXDisplayPoint(long[@screenXSample][m],long[@screenYSample][m]))
        tch.TextT(font,string("          "))
        tch.TextDec(font,long[@displayXSample][m])
    
        tch.TextT(font,string(13,10))
        tch.TextT(font,string("   Y =  ")) 
        tch.TextDec(font,long[@screenYSample][m])
        tch.TextT(font,string("          ")) 
        tch.TextDec(font,cal.getYDisplayPoint(long[@screenXSample][m], long[@screenYSample][m]))
        tch.TextT(font,string("          "))  
        tch.TextDec(font,long[@displayYSample][m])
    
      tch.TextT(font,string(13,10,13,10,13,10,13,10,"          Touch Screen to continue")) 
      repeat while tch.TouchValue  == $FFFF
    
    
      repeat 
        result := tch.TouchValue
        ifnot result == $FFFF
          x := result & $FFFF
          y := (result >> 16)& $FFFF
          tch.clearscreen(0)
          tch.ClearRectangle(x-10,y-10,x+10,y+10,$FFFe)
          tch.pause1ms(500) 
      
    
    
    '*********************************************
    '* Spin code generated by cspin version 0.82 *
    '*********************************************
    {
     *   Copyright (c) 2001, Carlos E. Vidales. All rights reserved.
     *    This sample program was written and put in the public domain by Carlos E. Vidales.  The program is provided "as is" without warranty of any kind,
     *    either expressed or implied. If you choose to use the program within your own products you do so at your own risk, and assume the responsibility
     *    for servicing, repairing or correcting the program should it prove defective in any manner. You may copy and distribute the program's source code
     *    in any  medium, provided that you also include in each copy an appropriate copyright notice and disclaimer of warranty. You may also modify this
     *    program and distribute copies of it provided that you include prominent notices stating that you changed the file(s) and the date of any change,
     *    and that you do not charge any royalties or licenses for its use.
    
      NOTE: Even though the validity of the calibration/translation method proposed has been verified with empirical data from several actual touch screen
      enabled displays, for the convenience of this exercise, the raw and expected data used and presented below are artificial.  When used with actual data
      the functions presented yield results that may be off by a larger but still small percentage (~1-3%) due to electrical noise and human error (i.e., the
      hand touching a screen target and missing by a small amount.) The array of input points.  The first three are used for calibration. These set of points
      assume that the touchscreen has vertical and horizontal resolutions of 1024 pixels (10-bit digitizer.)
     }
    
    
    

    Here's the latest RunCal method, it now creates a log file:
    PRI RunCal |  n,  error 
    
      error := \fat.openfile(String("Cal.cal"),"R")
      if  fat.partitionerror     '? ifnot ?                    ' failed to find the file
        text(error)
        fat.newFile(String("Cal.cal"))
      else
         fat.fileSeek(0)
        repeat n from 0 to 6
          long[cal.GetMatrixAddress][n] := fat.readLong
    '    return
      fat.closeFile
    
      sysfont := LoadFont(string("sysfont.ifn"))
      clearscreen($FFFe)
      SetCursor(0,0)
      TextT(sysfont,string(13,10,13,10,13,10,13,10,"          Touch the X on the next screens")) 
      TextT(sysfont,string(13,10,13,10,13,10,13,10,"          Touch Screen to continue")) 
    
      repeat while RawTouch  == $FFFF
    
      cal.init
      GetScreenSample   
      cal.setCalibrationMatrix(@displayXSample, @displayYSample, @screenXSample, @screenYSample)
    
      SetCursor(0,0)
      error := \fat.openfile(String("Cal.log"),"W")
      if  fat.partitionerror     '? ifnot ?                    ' failed to find the file
        text(error)
        fat.newFile (String("Cal.log"))
        fat.openfile(String("Cal.log"),"W")
        
      fat.fileSeek(0)               
      StringDim(12)
       
      repeat n from 0 to cal#MAX_SAMPLES - 1 
        StringStr(n + (cal#MAX_SAMPLES * 0),long[@displayXSample][n])
      repeat n from 0 to cal#MAX_SAMPLES - 1 
        StringStr(n + (cal#MAX_SAMPLES * 1),long[@displayYSample][n])
      repeat n from 0 to cal#MAX_SAMPLES - 1 
        StringStr(n + (cal#MAX_SAMPLES * 2),long[@screenXSample][n])
      repeat n from 0 to cal#MAX_SAMPLES - 1 
        StringStr(n + (cal#MAX_SAMPLES * 3),long[@screenYSample][n])
      
      fat.writeString(string("Calibration Log 1v0",13,10))
      fat.writeString(string("  Display Sample   "))
      fat.writeString(string("  Screen  Sample   ", 13,10))
          
      fat.writeString(String(" x1 = "))  
      fat.writeString(StringRamBuffer(0))
      fat.writeString(String("              "))       
      fat.writeString(StringRamBuffer(6))
      fat.writeString(string(13,10))
      fat.writeString(String(" y1 = "))  
      fat.writeString(StringRamBuffer(3))
      fat.writeString(String("              "))     
      fat.writeString(StringRamBuffer(9))
      fat.writeString(string(13,10,13,10))
      fat.writeString(String(" x2 = "))  
      fat.writeString(StringRamBuffer(1))
      fat.writeString(String("              "))       
      fat.writeString(StringRamBuffer(7))
      fat.writeString(string(13,10))
      fat.writeString(String(" y2 = "))  
      fat.writeString(StringRamBuffer(4))
      fat.writeString(String("              "))      
      fat.writeString(StringRamBuffer(10))
      fat.writeString(string(13,10,13,10))
      fat.writeString(String(" x3 = "))  
      fat.writeString(StringRamBuffer(2))
      fat.writeString(String("              "))      
      fat.writeString(StringRamBuffer(8))
      fat.writeString(string(13,10))
      fat.writeString(String(" y3 = "))  
      fat.writeString(StringRamBuffer(5))
      fat.writeString(String("              "))       
      fat.writeString(StringRamBuffer(11))
      fat.writeString(string(13,10,13,10))
    
      repeat n from 0 to 6
        StringStr(n ,long[cal.getMatrixAddress][n]) 
      
      fat.writeString(string(13,10,13,10,13,10,13,10,"The calibration matrix:",13,10,13,10))
      fat.writeString(string("   An   = "))
      fat.writeString(StringRamBuffer(0))
      fat.writeString(string(13,10))
      fat.writeString(string("   Bn   = "))
      fat.writeString(StringRamBuffer(1))
      fat.writeString(string(13,10))
      fat.writeString(string("   Cn   = "))
      fat.writeString(StringRamBuffer(2))
      fat.writeString(string(13,10))
      fat.writeString(string("   Dn   = "))
      fat.writeString(StringRamBuffer(3))
      fat.writeString(string(13,10))
      fat.writeString(string("   En   = "))
      fat.writeString(StringRamBuffer(4))
      fat.writeString(string(13,10))
      fat.writeString(string("   Fn   = "))
      fat.writeString(StringRamBuffer(5))
      fat.writeString(string(13,10))
      fat.writeString(string("Divider = "))
      fat.writeString(StringRamBuffer(6))
    
      fat.closeFile
      fat.openFile(String("Cal.cal"), "W") 
        repeat n from 0 to 6
          fat.writeLong(long[cal.GetMatrixAddress][n])    
        fat.closeFile
    

    And this is what the log file looks like :
    Calibration Log 1v0
      Display Sample     Screen  Sample   
     x1 =  60               186
     y1 =  100               148
    
     x2 =  420               861
     y2 =  400               508
    
     x3 =  240               509
     y3 =  700               877
    
    
    
    
    
    The calibration matrix:
    
       An   =  197640
       Bn   =  5220
       Cn   = -14985900
       Dn   =  2700
       En   =  308100
       Fn   = -8521500
    Divider =  375795
    

    It is fairly accuate, the only problem is on the extremities of the display, there's a little bit of lag getting to final point. A few samples. Have not been able to make this disapear yet...
  • average joeaverage joe Posts: 795
    edited 2014-11-10 13:58
    10806367_10155008312595001_4461420992709652322_n.jpg
    10730849_10155006735125001_470575185400394375_n.jpg
    10731190_10155008312545001_3598361776494157286_n.jpg



    I just finished some major housekeeping but much more needs to be done before this can be considered final release. The archive also contains an updated desktop with optimizations for the larger screen. I doubled the number of icons to 40 and I'm thinking about using the icon x-y stored in ram to locate the entry, as opposed to reserved pointers.

    The calibration method checks the SD card for a Cal.cal file. If it exists, it loads the calibration matrix from into propeller memory where it belongs. Otherwise it calls a calibration. This is also accounted for in WarmCold boot, although I'm not sure it works properly yet.

    The calibration method should work with the 3.2" display, as well. I can guarantee the included version won't work on the smaller screen. There are resolution descriptions hard-coded in still. Other small details need to be accounted for when changing displays. This is just a proof of concept at this point. Hopefully, it will help someone in the future.

    calibrate_V10_tb_1963.zip
  • average joeaverage joe Posts: 795
    edited 2014-12-13 04:26
    HI guys,

    Took a break from the grind to work on this project again and made some very positive progress. I have a PCB that "mates" to the 7" display. It has 2x 8M (512K x 16) SRAM chips (AS6C8016), 4x 64M (8M x 8) FLASH (W25Q64FV) and uses a CPLD for all the glue logic. (XC2C128-TQ100) Of course, we can't forget the P8X32A!

    This design is nowhere near complete. The finished version will have MANY additional features!!!

    The idea behind this was... You folks complained there were no free propeller pins. So, you can run in 16 bit mode for speed, or 8 bit mode and have 8 free propeller pins. 8 Bit mode won't suffer that much of a performance hit, I have some tricks up my sleeve. Of course, this is when I get the time to finish the design. This dev sesh has focused on 16 bit implementation. 8 bit mode will incur significant logic but should be very fast considering. Oh yea, there's a lot more going on this board but I decided to work on the logic section first. (Also, it's unlikely I will release the ENTIRE board, due to the development involved in some of the specialized circuitry.)

    So, here's the START of the MIT release.


    4x W25Q64FV (64M (8M x 8)) QSPI FLASH
    2x AS6C8016 (8M (512K x 16)) SRAM
    1x SC2C128-100-VQFP CPLD
    1x P8X32A
    1x SSD1963 display (like this)
    More to come!

    IN_LOG.bmp
    C_LOG2.bmp
    BUS_LOG.bmp
    New Bitmap Image2.bmp
    F_CS.bmp
    COUNT.bmp
    IN_LOG.bmp
    FF_SEC.bmp
    C_LOG1.bmp
    ADD_MUX.bmp
  • average joeaverage joe Posts: 795
    edited 2014-12-13 04:28
    And the actual sources
  • Igor_RastIgor_Rast Posts: 357
    edited 2015-02-18 05:11
    Nice work average joe.

    Quick question , im trying to connect a similar lcd to a bbb . also having an PCA9685 wich can PWM
    can we pwm the led pin for a software defined backlight ? . or is this something done on the lcd board itself . im kinda out of the material for some time:p
    basic connection schematic for driving it then ?

    Thanks
    Igor
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2015-03-11 03:42
    Time to take a look at this again - would it be possible to replace the 74xx support chips with a second propeller?

    Let's add up the pins. 16 data bus, 19 address, 3 ram control, 4 SPI for finger position, 4 SD card, 2 audio, 2 on each propeller for I2C, 2 on each propeller for interprop comms, 2 on each propeller for programming. Hmm, that adds up to 64. This might just work!

    Next step, what is the best way to assign pins. It is not possible to have the ram address and data on the same propeller chip as that is 16+19 which is more than 32. So - data bus on one propeller and address bus on the other propeller. Attached is a schematic. Propeller A is data, SD, finger SPI and audio. Propeller B is address, ram control and display control.

    So - playing music - SD to audio, that needs to be fast and propeller A can do that as this is all on prop A.

    Dumping data from ram to the display. That needs to be fast and it is all on propeller B, so we can send a command to dump 100K of data to the screen in one go.

    Moving data between prop A and B. That can be done with a 2 pin data link and there are a few possibilities - at the simplest level it can be a serial link but I think there are Objects that can do it faster - eg you could send a serial command that converts the default bidirectional serial link into a one directional data+clock link and then the transfer rate may well be able to match the SD transfer rate. So data goes from the SD card to this fast link and then propeller B sends it to the ram chip.

    Not shown on the schematic are some I/O pins, there are some great digital and analog I/O chips for the I2C bus and there should be room on the board for a few of these.

    Thoughts and comments would be most appreciated!
  • average joeaverage joe Posts: 795
    edited 2015-03-11 11:40
    Dr_Acula wrote: »
    Time to take a look at this again - would it be possible to replace the 74xx support chips with a second propeller?

    Let's add up the pins. 16 data bus, 19 address, 3 ram control, 4 SPI for finger position, 4 SD card, 2 audio, 2 on each propeller for I2C, 2 on each propeller for interprop comms, 2 on each propeller for programming. Hmm, that adds up to 64. This might just work!

    Next step, what is the best way to assign pins. It is not possible to have the ram address and data on the same propeller chip as that is 16+19 which is more than 32. So - data bus on one propeller and address bus on the other propeller. Attached is a schematic. Propeller A is data, SD, finger SPI and audio. Propeller B is address, ram control and display control.

    So - playing music - SD to audio, that needs to be fast and propeller A can do that as this is all on prop A.

    Dumping data from ram to the display. That needs to be fast and it is all on propeller B, so we can send a command to dump 100K of data to the screen in one go.

    Moving data between prop A and B. That can be done with a 2 pin data link and there are a few possibilities - at the simplest level it can be a serial link but I think there are Objects that can do it faster - eg you could send a serial command that converts the default bidirectional serial link into a one directional data+clock link and then the transfer rate may well be able to match the SD transfer rate. So data goes from the SD card to this fast link and then propeller B sends it to the ram chip.

    Not shown on the schematic are some I/O pins, there are some great digital and analog I/O chips for the I2C bus and there should be room on the board for a few of these.

    Thoughts and comments would be most appreciated!



    I like it! Maybe this would work for the prop to prop communication?

    http://forums.parallax.com/showthread.php/134641-DEMO-High-Speed-Multi-Prop-to-Prop-Communication

    *edit*

    Here's a render of the current layout of my cpld design.

    finished-OS.JPG


    The "accessory" section is redacted, for the moment. I hope to build this at some point but the main board is expensive to fab, due to size (30 sq in). Then, the paste stencils add another $100, so total initial cost is approaching $300. That gets 3 of each board, stencils and parts for the first board. I still like the design for larger displays (greater than 320x240 px) and it also allows 8 free prop pins!!! Once the design is proven, the cpld could be put on the same board and a breakout for all usable pins could be added (I'm thinking a 2x16 pin header for prop and a separate header for the couple cpld pins.)
    1018 x 609 - 98K
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2015-03-12 16:53
    Yes, that would be perfect for the interprop comms - super fast so can send the data SD to prop 1, then prop 1 to prop 2, then prop 2 to ram and that can all be happening in parallel.

    I think I can get the board down to 10x10cm and that is with DIP parts too. Has 4 analog inputs, one analog output and 8 digital I/O. One clever trick - run the analog and digitial I/O from either 3V or 5V and then you have either 3V or 5V compatible I/O.

    The board is about the same size as the larger touchscreens - maybe a fraction wider.

    Build cost - 10x10cm at Seeed is a good price - maybe $7ea including shipping.
    816 x 798 - 276K
  • Cluso99Cluso99 Posts: 18,066
    edited 2015-03-12 18:59
    Drac,
    Why don't you standardise on using an AV4 socket?
    http://www.4uconnector.com/online/object/4udrawing/18899.pdf

    That way not only can you use it for Stereo, but you can add TV (composite video) too if required. Breakout 3.5mm AV to RCA are cheap on eBay.
    Also usable as separate connector with TV only on tip.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2015-03-13 00:54
    That looks interesting Cluso.

    BTW this was inspired by your original "three propeller" board :)
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2015-04-18 01:36
    It is quite a fun challenge to come up with simpler designs that uses less parts. Attached is the latest incarnation using dual propeller chips.

    I have this crazy notion that with an ESP8266 wifi module, and some code to parse html (partially written) and a full color display with some code to display .jpg files, maybe it might be possible to build a simple internet browser.

    64 pins to use with prop [A] and prop
    4 for downloads (2x2) [A&B]
    4 for I2C (2x2) [A&B]
    2 for audio [A]
    3 for ESP8266 wifi module [A=1 pin, B=2 pins]
    4 for SD card [A]
    4 for SPI interface to detect finger position [A]
    2 for interprop comms {A&B]
    16 for a data bus [A]
    19 for address
    4 to control the touchscreen display
    2 to control the ram chip

    Next challenge - how to divide them up between each propeller. The major determinant of speed is moving data from ram to the display - that needs to be a 16 bit transfer with a tight pasm loop:
    toggle display /wr, increment ram address, repeat n times.

    The next speed bottleneck is moving data from the SD card into the ram chips. What I've done there is put the data bus on prop A, and the ram control on prop B. The SD card is on prop A, so move data in blocks from the SD card to prop A hub ram. Then set up a message protocol via the 1 wire interprop comms link with a command that says the next n toggles on that line are going to be some data coming through. Then prop A puts 16 bits on the data bus, puts the interprop comms line low, prop B recognises this and toggles the ram /WR line low then high, then prop A puts the interprop comms line high, then repeat n times. This allows transfer two bytes at a time, which should easily be faster than the SD card is reading.

    It is a bit complicated because fundamentally the problem is that the data bus (16 bits) and the address bus (19 bits) add up to too many pins for one propeller chip.

    I think this schematic should work. It uses very few additional components apart from the propeller, ram and eeprom. There is room on the board for a few more things - I have a feeling for instance that writing a .jpg decoder in spin might be a bit tricky, but copying an existing one from C should be easier, so might need an I2C ram chip so can store larger C programs.

    A fun little puzzle to work on :)
Sign In or Register to comment.