Shop OBEX P1 Docs P2 Docs Learn Events
2.4" 320x240 TFT Prop based display module - Page 2 — Parallax Forums

2.4" 320x240 TFT Prop based display module

2»

Comments

  • jmgjmg Posts: 15,173
    edited 2011-12-28 15:28
    Dr_Acula wrote: »
    The code I don't understand is this sort of thing:
    DCLK=1; _nop_();_nop_();_nop_();_nop_();
    DCLK=0; _nop_();_nop_();_nop_();_nop_();
    

    where NOP seems to do nothing, and DCLK is a variable that changes.
    There was code like this in the display driver and I replaced it with spin that did things like change the status of DCLK. But in this code, it seems like in C you change the value of the clock pin, but how do you actually change that to a status change on the pin? Maybe it is a macro?

    And is the _nop_(); function actually doing anything or is it just a delay loop?

    The DCLK is first physically mapped to a pin here
    sbit DCLK = P1^7;

    which will be an 8051 Port P1.7, & once declared as a Boolean like that, then

    DCLK=1; will generate SETB P1.7 and DCLK=0; will generate CLR P1.7 (8051 has Boolean opcodes)

    The _nop_(); are what you suspect, they will compile to NOP opcodes, which are single-cycle-delay 'packers'
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-12-28 21:22
    Thanks jmg and Nick

    I also have got the touch screen working.

    The display has 6 pins but penirq may not be needed; it changes state when you touch the screen but you can detect that by reading the values. Maybe it is useful for powerdown but then again, the touchscreen chip is using only a small amount of power. The other pin not really needed is the busy pin. So now it is a 4 pins standard SPI interface.

    I added a line to enable the /cs pin. This possibly is also a waste of a propeller pin as the touchscreen would usually always be on. But maybe it could be useful for sharing a SPI bus with other SPI devices.

    I also tweaked the code so it reads out -1 if the screen is not being touched.

    The 'origin' is a bit tricky. Old-school says the origin is top left. Graphs and things have the origin at bottom left. This screen has the origin at top right, but then again it comes from a mobile phone screen so it is meant to be used in portrait mode rather than landscape. The code moves it to bottom left in portrait mode, but I am now thinking I'll probably use it more in landscape. Anyway, it is easy to change.
    PRI TouchScreen  | yval, xval
    ' *** note these pins are changing in the next board to DO = 20, CLK =21, DI = 22, CS = 23 (busy and penirq not connected)
    '  Touch_Clock = 23                                       ' clock
    '  Touch_ChipSelect = 22                                  ' chip select needs to be low to enable the touchscreen
    '  Touch_DataIn = 21                                      ' data into the chip = an output from the prop
    '  Touch_Busy = 20                                        ' busy ? not needed - just returns /cs
    '  Touch_DataOut = 19                                     ' data out of the chip = an input to the prop
    '  Touch_Penirq = 18                                      ' pen down (? use for wakeup)
      OUTA[Touch_ChipSelect] := 0                           ' enable the touch screen
      SPI.start(3,0)                                        ' delay,state
      'Shiftout = data,clock,mode,bits,value
      'shiftin = data,clock,mode,bits
      'SPI read S, A2, A1, A0, Mode, SER, PD1, PD0
      '         1  0   0   1    1     0    0    0
      ' MSB first
      ' 001 is X
      ' 101 is Y
        repeat
          SPI.SHIFTOUT(Touch_DataIn, Touch_Clock, 5, 8 , %1101_0000)  ' reads x from  500 to 3700  (off < 500 )
          xval := SPI.SHIFTIN(Touch_DataOut,Touch_Clock,2, 12)
          SPI.SHIFTOUT(Touch_DataIn, Touch_Clock, 5, 8 , %1001_0000)  ' reads y from 400 to 3800 (off > 3800 ) 
          yval := SPI.SHIFTIN(Touch_DataOut,Touch_Clock,2, 12)
          if xval <500                                      ' if less than 500 then not touched, change to -1
            xval := -1                                      ' no touch is -1
          else
            xval := 3700 - xval                             ' move origin bottom right to bottom left
          if yval > 3800                                   ' if >3800 then not touched, change to -1
            yval := -1  
          delay.pause1ms(300)                              ' short delay for the display
          printdecimal(xval)                               ' display the numbers
          printdecimal(yval)
          crlf                                             ' new line
    

    So Nick, you want to do the SPI object in spin rather than pasm. That would make sense because touch screens are read and updated rather slowly (? max 30ms refresh rate). And then you free up a cog. And the free cog will be needed because the spin code to update the display is far too slow and than needs to be changed to pasm.

    So - touchscreen needs to go from pasm to spin, and the display needs to go from spin to pasm!
  • Oldbitcollector (Jeff)Oldbitcollector (Jeff) Posts: 8,091
    edited 2011-12-29 13:56
    Thanks to a combination of code from Dr_A and Nick mine is also now working...

    Thanks!
    CON
      _clkmode = xtal1 + pll16x
      _xinfreq =5_000_000
    
      clockfreq = ((_CLKMODE - XTAL1) >> 6) * _XINFREQ   
      _1mS  = clockfreq /     1_000 'Divisor for  1mS 
    
      Touch_Clock = 23                                       ' clock
      Touch_ChipSelect = 27                                  ' chip select needs to be low to enable the touchscreen
      Touch_DataIn = 22                                      ' data into the chip = an output from the prop
      Touch_DataOut = 21                                     ' data out of the chip = an input to the prop
    
    OBJ
    
      text : "PSM_tv_text"
      spi : "SPI_ASM"
    
    PUB TouchScreen  | yval, xval
    ' *** note these pins are changing in the next board to DO = 20, CLK =21, DI = 22, CS = 23 (busy and penirq not connected)
       text.start 
      OUTA[Touch_ChipSelect] := 0                           ' enable the touch screen
      SPI.start(3,0)                                        ' delay,state
        repeat
          SPI.SHIFTOUT(Touch_DataIn, Touch_Clock, 5, 8 , %1101_0000)  ' reads x from  500 to 3700  (off < 500 )
          xval := SPI.SHIFTIN(Touch_DataOut,Touch_Clock,2, 12)
          SPI.SHIFTOUT(Touch_DataIn, Touch_Clock, 5, 8 , %1001_0000)  ' reads y from 400 to 3800 (off > 3800 ) 
          yval := SPI.SHIFTIN(Touch_DataOut,Touch_Clock,2, 12)
          if xval <500                                      ' if less than 500 then not touched, change to -1
            xval := -1                                      ' no touch is -1
          else
            xval := 3700 - xval                             ' move origin bottom right to bottom left
          if yval > 3800                                   ' if >3800 then not touched, change to -1
            yval := -1  
          ms(300)                              ' short delay for the display
          text.str(string("xval: "))
          text.dec(xval)
          text.str(string(" yval: "))  
          text.dec(yval)
          text.out($0d)
    
    PUB ms(Period)
      if Period                                    '1 mS
        waitcnt(_1mS * Period + cnt)
    
    
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-12-29 14:21
    A thought - do we need /cs connected for the touchscreen? It is using a precious propeller pin and the touchscreen would always be enabled, right? I'm thinking of tying it low permanently. Then the touchscreen would only use three pins.
  • Cluso99Cluso99 Posts: 18,069
    edited 2011-12-29 16:00
    Why not share the 3 SPI pins with the SD card? So for 5 pins, you have 2x -CS, one for SD one for Touch. I understand even the screen has SPI mode, so 6 pins total???
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-12-29 17:25
    Interesting suggestion Cluso. Yes, that would save some pins.

    I need to do some more experiments regarding speed. A full screen is 153k. I'm not sure how fast SD cards can be accessed. If a full screen refresh is fast enough, then pull the data out of the sd card in blocks and send it to the screen.

    [Addit - Kye's driver is 241 kilobytes a second reading an SD card so a screen refresh will take 0.63 seconds].

    If this is not fast enough, buffer the data in a parallel ram, then move it from parallel ram to the display in parallel using 8 lines.

    Now the touch screen is working, next step is to move the display driver from spin to pasm and see how fast it can go.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-12-31 20:27
    Touchscreen and a display working. Blurry video here

    http://youtu.be/Bopkr2PbRWY

    The text on the TV is out of focus, but what it is doing is reading in each icon from SD card into external memory (8k per icon). The delay between each file being loaded is a little too long for a working display, though Kye has recently said he thinks he can speed up the driver if data is being loaded in blocks.

    Then each icon is displayed on the touchscreen when the appropriate area of the screen is touched. The transfer from external memory to the display is done in parallel and the code is pasm so it is as fast as possible.

    All very preliminary but it is a proof of concept.
  • Cluso99Cluso99 Posts: 18,069
    edited 2012-01-01 02:11
    Happy New Year Drac.

    Nice job. BTW Do you know if these displays when in 8 bit mode use DB0-7 or DB8-16 ?
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-01-02 04:46
    Hi Cluso,

    Thankyou for the New Year greetings!

    In answer to your question, I believe the display uses DB 8-16 for 8 bit mode. However, I am not 100% sure how to interface to these displays that bring out 40 pins - the ILI9325 can certainly use all sorts of modes including SPI mode, but the datasheet for the board that has the touchscreen as well seemed to be designed for 16 bit mode so I just added in the latches and talked to it in 16 bit mode.

    I have changed the code a little to support 512 byte block reads from the SD card and this has dramatically improved the speed.

    Also at the core of the driver is Cluso's external ram driver, now with extra pasm added for talking to the ILI9325 display.

    This is an example of how to read a picture off the sd card and onto the display, using Kye's SD driver.
    PUB SDtoHubMemoryBlock                                 ' block move data from sd card to hub then block move to display 
        fat.openfile(string("icons320.ili"),"R")            ' open an image (.ili extension)
        ILI9325.draw(0,0,239,319)                           ' set up the area of the screen to draw in
        repeat 300
          fat.readdata(@sdbuffer,512)                        ' read 512 bytes from sd card to hub ram
          ILI9325.docmd("D",@sdbuffer,0,512)                 ' move 512 bytes = 256 pixels from external ram to the display
        fat.closefile   
    



    Youtube video here http://youtu.be/ZFc6l0Yvobk


    This is a very short video but it is designed to show a comparison of the speed reading data off the external memory vs reading directly off the sd card. My conclusion is they are about the same.

    The first part loads multiple tiles off the external ram and fills (most of) the screen (technically 80% of the screen). The second is a complete screen read from the sd card directly. Given the first one is not filling the screen completely (the tiles are 64x64 which doesn't fit into 240 fully), I think reading off the sd card directly is faster.

    And this results in a very interesting conclusion as it saves a lot of hardware. At the moment my Gadget Gangster stack has a motherboard, keyboard/mouse board, vga/tv board, external memory board, sd board and touchscreen board. That is 6 boards.

    Now consider - with a touchscreen you don't need mouse or keyboard. Nor TV. Nor external memory. Nor SD card board because the touchscreens come with an SD card socket on the back. So... you only need the motherboard (eg a GG USB prop board) and the touchscreen board.

    That is a lot of savings in hardware.

    And I know that the speed can be improved even more, given videos like this http://www.youtube.com/watch?feature=endscreen&v=nhXcYWkc9lI&NR=1

    Next step - taking a variable width font and storing it as a file and then display some text on the screen. If we can do that then the TV/VGA/serial port is not needed for debugging and messages can be displayed directly on the touchscreen board.
  • Oldbitcollector (Jeff)Oldbitcollector (Jeff) Posts: 8,091
    edited 2012-01-04 20:31
    @Dr_A: What is that .ili file format you are using? Something you generated?

    BTW, for anyone else who wants to join the fun on this project, Nick has made is easy.. see here..

    Has anyone done a touchscreen-to-mouse.spin conversion yet? Looks like it would be a snap..

    OBC
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-01-04 23:28
    Nice link to the GG board - this will make interfacing even easier.

    The .ili format is simply two bytes per pixel, raw data, with the bytes containing RRRRRGGG and then GGGBBBBB.

    Today however I did some experiments with icons and transparent overlays. There are vast libraries of icons available in .png format and I discovered that with a few simple lines of vb.net it is possible to pull out 4 bytes per pixel, Red, Green, Blue and "alpha" which is a transparent value from 0 to 255. I've managed to separate these out and so I might end up storing files with 4 bytes per pixel - ARGB, and then do the bitshifts on the fly in pasm.

    What I think should be possible is to store a background image 320x240 and then overlay icons as required, including the transparent layer so that the icons display as they were originally designed. I think it should be possible to greatly simplify the transparancies so that instead of 0-255, there are just 5 values, 0,25%,50%, 75% and 100% and this should give a compromise between speed and smooth edges. Those values should be possible to do with bitshifts rather than byte multiplies which will be faster.

    I'm also thinking that by the time you pull data out of an sd card or a memory chip, a few extra bitshifts won't slow things down much more, so if possible, maybe even store the data as a standard .raw file? Then you don't need to do pre-processing. Or even decode the header for a .bmp file?
  • Jim FouchJim Fouch Posts: 395
    edited 2012-01-05 07:01
    Dr_Acula wrote: »
    Nice link to the GG board - this will make interfacing even easier.

    The .ili format is simply two bytes per pixel, raw data, with the bytes containing RRRRRGGG and then GGGBBBBB.

    Today however I did some experiments with icons and transparent overlays. There are vast libraries of icons available in .png format and I discovered that with a few simple lines of vb.net it is possible to pull out 4 bytes per pixel, Red, Green, Blue and "alpha" which is a transparent value from 0 to 255. I've managed to separate these out and so I might end up storing files with 4 bytes per pixel - ARGB, and then do the bitshifts on the fly in pasm.

    What I think should be possible is to store a background image 320x240 and then overlay icons as required, including the transparent layer so that the icons display as they were originally designed. I think it should be possible to greatly simplify the transparancies so that instead of 0-255, there are just 5 values, 0,25%,50%, 75% and 100% and this should give a compromise between speed and smooth edges. Those values should be possible to do with bitshifts rather than byte multiplies which will be faster.

    I'm also thinking that by the time you pull data out of an sd card or a memory chip, a few extra bitshifts won't slow things down much more, so if possible, maybe even store the data as a standard .raw file? Then you don't need to do pre-processing. Or even decode the header for a .bmp file?

    I have an Icon library of over 200,000 icons. I have them in various sizes from 16x16 upto 256x256. In several formats including BMP, PNG, ICO, and GIF. The idea of converting them to be used on this display sounds awesome. Any chance you woud be willing to share your vb.net conversion code?
  • Oldbitcollector (Jeff)Oldbitcollector (Jeff) Posts: 8,091
    edited 2012-01-05 09:15
    I'd like to second that request!

    OBC
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-01-05 14:30
    Sure, I'll need to tidy it up first and it can all be open source.

    Some thoughts.

    1) For a background you don't need alpha so the format would simply be RGB. I have a feeling that is a .raw format which any graphics program can output. Given the propeller works natively in longs, there may be an advantage to having all files in the same format, ie ARGB = 1 long per pixel, and for a background, just ignore A (or set it to 255).
    2) For icons, the format would be ARGB = 1 long per pixel. Does this need a header as well?

    I was testing out some icons I downloaded and expecting them to be 64x64 but in fact they were 59x60. Of course, with a transparent layer, they display fine as there is a transparent border of 3 pixels or so around the outside. So do we need to change the size to something more standard like 64x64, or do we allow a range of sizes and store the size in a header?

    I was looking around for an equivalent to the .png format but with raw data (.png is compressed I think) - if such a format exists is might be even better to use a standard format.

    But if not, maybe we could just reserve some bytes at the beginning for a header, which might include the size and other things we might think of along the way like byte order, filename and the offset to point to the main data.

    The other thing about drawing icons on a background is that the background will need to be stored somewhere. You could read the entire background off an sd card every time you need to redraw or move an icon, but to speed things up you only need to redraw the part of the background that is underneath the icon. I think for random access like that, an external ram is going to be the easiest. For 320x240x3 that is 230k which will fit in a 512k ram chip, and use the free memory to store some icons and fonts.

    Reading this website http://www.axialis.com/tutorials/tutorial-misc001.html it appears that .bmp files can contain an alpha channel. In an ideal world it would be great to use a standard file format like .bmp. I shall see if I can find out more about the .bmp format with alpha.


    I'm still in two minds about whether to start writing code for reading off an sd card or whether to write it for an external memory.
  • Oldbitcollector (Jeff)Oldbitcollector (Jeff) Posts: 8,091
    edited 2012-01-05 14:45
    If you put the size in the header, then larger images can be loaded using the same method, not just icons..

    two cents....

    OBC
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-01-05 23:29
    Ok, this is a bit of vb.net code. Start up a new vb.net project, put a button on the screen and then double click it and paste in this code. Put two pictureboxes on the screen. Now go through this code and replace picturebox119 with your picturebox1, and picturebox120 with your picturebox2. I think you will need to put an "openfiledialog" on the form from the toolbox (near the bottom in "dialogs")

    This code takes any .bmp or .jgp or .png file and turns it into a ".rgb" file

    For .bmp or .jpg the alpha value is always 255 ie fully opaque.

    For .png files, if there is an alpha layer it separates this out.

    Files are large - for a background 320x240 the file is 300k. I'm going to code this with an external memory driver as I think it might be a bit hard reading data on and off a sd card all the time.
            ' read a .png or a .jpg or a .bmp file and stores ARGB to a file
            ' format is 32 bytes at the beginning then data. 4 bytes per pixel
            ' long 1 = size in bytes
            ' long 2 = width
            ' long 3 = height
            Dim Mycolor As Color
            Dim x, y, t, i As Integer
            Dim sizex, sizey As Integer
            Dim Sizefile As Long
            Dim Filepath, Sourcefile, DestinationFile As String
            Filepath = "C:\Propeller\Icons2" ' directory
            OpenFileDialog1.Multiselect = False
            OpenFileDialog1.InitialDirectory = Filepath
            OpenFileDialog1.FileName = "*.png;*.jpg;*.bmp" ' select .png and .jpg and .bmp icon files
            OpenFileDialog1.ShowDialog() ' open the openfile dialog
            Sourcefile = OpenFileDialog1.FileName ' get the filename
            Sourcefile = Strings.Mid(Sourcefile, Strings.Len(Filepath) + 2) ' strip off directory
            ' load in the picture
            ' this little bit of code replaces new sytem.drawing.bitmap as the latter leaves the file locked eg so paintshop can't save a new file
            Dim img As Image
            Dim fs As New FileStream(Filepath + "\" + Sourcefile, IO.FileMode.Open) ' open the picture
            img = Image.FromStream(fs) ' load in the file
            fs.Close() ' close the picture
            PictureBox119.Image = img ' display the picture
            sizex = PictureBox119.Image.Width - 1 ' get the width minus 1
            sizey = PictureBox119.Image.Height - 1 ' get the height minus 1
            Dim PixelArray(sizex, sizey, 5) As Byte ' define an array to store the pixel values
            PictureBox119.Width = PictureBox119.Image.Width ' set to actual size
            PictureBox119.Height = PictureBox119.Image.Height ' set to actual size
            PictureBox120.Width = PictureBox119.Image.Width ' set alpha display to actual size
            PictureBox120.Height = PictureBox119.Image.Height ' set alpha display to actual size
            ' picture to array
            Dim MyBitmap As New System.Drawing.Bitmap(PictureBox119.Image) 'image from picture box
            For y = 0 To sizey
                For x = 0 To sizex
                    Mycolor = MyBitmap.GetPixel(x, y) ' get the color
                    PixelArray(x, y, 0) = Mycolor.A ' transparency value 0-255 (255 for normal pictures = fully opaque)
                    PixelArray(x, y, 1) = Mycolor.R ' red
                    PixelArray(x, y, 2) = Mycolor.G ' green
                    PixelArray(x, y, 3) = Mycolor.B ' blue
                Next
            Next
            'display alpha on a separate picturebox - usually an outline of the icon with rounded corners
            For y = 0 To sizey
                For x = 0 To sizex
                    Mycolor = Color.FromArgb(255, PixelArray(x, y, 0), PixelArray(x, y, 0), PixelArray(x, y, 0))
                    MyBitmap.SetPixel(x, y, Mycolor) ' set the pixels back to this palette color
                Next x
            Next y
            PictureBox120.Image = MyBitmap ' display the picture after processing
            Sizefile = ((sizex + 1) * (sizey + 1)) * 4 + 32
            Dim OutputArray(Sizefile) As Byte ' 4 bytes per pixel ARGB plus 32 byte header
            OutputArray(0) = Sizefile And 255 ' LSB store little endian LSB first
            OutputArray(1) = (Sizefile >> 8) And 255
            OutputArray(2) = (Sizefile >> 16) And 255
            OutputArray(3) = (Sizefile >> 24) And 255 ' MSB store
            ' now store width as a long
            OutputArray(4) = (sizex + 1) And 255 ' LSB store little endian LSB first
            OutputArray(5) = ((sizex + 1) >> 8) And 255
            OutputArray(6) = ((sizex + 1) >> 16) And 255
            OutputArray(7) = ((sizex + 1) >> 24) And 255 ' MSB store
            ' and store height as a long
            OutputArray(8) = (sizey + 1) And 255 ' LSB store little endian LSB first
            OutputArray(9) = ((sizey + 1) >> 8) And 255
            OutputArray(10) = ((sizey + 1) >> 16) And 255
            OutputArray(11) = ((sizey + 1) >> 24) And 255 ' MSB store
            ' unused header bytes...
            ' put "Data ARGB" in the array so can read this with a hex editor
            OutputArray(24) = Strings.Asc("D")
            OutputArray(25) = Strings.Asc("a")
            OutputArray(26) = Strings.Asc("t")
            OutputArray(27) = Strings.Asc("a")
            OutputArray(28) = Strings.Asc("A")
            OutputArray(29) = Strings.Asc("R")
            OutputArray(30) = Strings.Asc("G")
            OutputArray(31) = Strings.Asc("B")
            t = 32 ' start data here
            For y = 0 To sizey
                For x = 0 To sizex
                    For i = 0 To 3
                        OutputArray(t) = PixelArray(x, y, i)
                        t += 1
                    Next i
                Next
            Next
            DestinationFile = Strings.Left(Sourcefile, Strings.Len(Sourcefile) - 4) + ".rgb" ' use a rgb extension
            Dim OutputILI As New FileStream(Filepath + "\" + DestinationFile, FileMode.Create, FileAccess.Write)
            OutputILI.Write(OutputArray, 0, Sizefile) ' save bytes
            OutputILI.Close()
    
    
  • Reset_VectorReset_Vector Posts: 55
    edited 2012-01-06 01:00
    Dr_Acula,
    Here is the code I use for a ADS7843 touch driver;
    I give it to you the complete code, including the calibration procedure I think you need;
    Use the parts you want, not included is the LCD driver (wich use a ST7781 controller)
    Feel free to ask questions.

    Best regards

    Olivier
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-01-06 03:48
    Hi Reset_Vector

    Is your touchscreen I2C or SPI?

    Mine seems to work with an SPI driver

    spi: "SPI_ASM" ' thanks to Beau
    Set up the pins
      Touch_Clock = 23                                        ' Touch screen pins (shared with VGA and one, penirq, shared with TV)
      Touch_ChipSelect = 22
      Touch_DataIn = 21
      Touch_Busy = 20
      Touch_DataOut = 19
      Touch_Penirq = 18
    
    Then call this routine
    PRI TouchScreen  | yval, xval,x,y
      OUTA[Touch_ChipSelect] := 0                           ' enable the touch screen
      SPI.start(3,0)                                        ' delay,state
        repeat
          SPI.SHIFTOUT(Touch_DataIn, Touch_Clock, 5, 8 , %1101_0000)  ' reads x from  500 to 3700  (off < 500 )
          xval := SPI.SHIFTIN(Touch_DataOut,Touch_Clock,2, 12)
          SPI.SHIFTOUT(Touch_DataIn, Touch_Clock, 5, 8 , %1001_0000)  ' reads y from 400 to 3800 (off > 3800 ) 
          yval := SPI.SHIFTIN(Touch_DataOut,Touch_Clock,2, 12)
    

    What sort of display do you have?
  • Reset_VectorReset_Vector Posts: 55
    edited 2012-01-06 05:08
    Hi, Doc !

    Here is the link to the LCD :

    http://www.xtune.se/product_info.php?cPath=59&products_id=111

    Here is the link to the PropPad (the board I have used with this LCD):

    http://www.xtune.se/product_info.php?cPath=59&products_id=131



    The LCD have a touchscreen built in, but only the resistive panel, no touch driver chip.

    I have made a complete driver (for the ST7781 controller) for this LCD, including the touch driver ( I have used the ADS7843 (it is SPI), mounted on a piece of perfboard.) as the board don't have
    any touch controller chip

    Best regards
  • Oldbitcollector (Jeff)Oldbitcollector (Jeff) Posts: 8,091
    edited 2012-01-06 07:28
    @Dr_A:

    Drawing the colors down to 256, full screens would be around 77k instead of 300k. Most existing windows icons converted would probably look just fine this way. Toss in two bytes in the header to indicate height/width (240/255) (or full screen), then simply read the bytes directly to the screen.

    OBC
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-01-06 15:27
    Hi Reset_Vector, the displays I am using are on post #22 of this thread - cost is less and you get the SPI driver for the touchscreen, and a SD socket as well.

    @OBC - the display uses RRRRRGGGGGGBBBBB so that is two bytes per pixel without any losses = 64k colors which is 153k.

    If you add in an alpha channel that is another byte (though one might only use a few alpha values, I'm thinking of only 5.)

    Once you add in alpha it is 3 bytes per pixel and one may as well go to one long per pixel. For an icon that is, as icons are only 64x64 so that is 4096 pixels, or 16k.

    Backgrounds don't need the alpha channel. This maybe leads to considering two file formats. One for icons that uses one long per pixel, and one for all other files that uses one word per pixel.

    With that VB.net code above, one could easily translate the file produced into a half size file. Ignore alpha, and take RGB and convert to two bytes. This code isn't the most efficient as it stores a value in an array on the way through but it gives the general idea
            For y = 0 To sizey
                For x = 0 To sizex
                    Mycolor = MyBitmap.GetPixel(x, y) ' get the color
                    PixelArray(x, y, 0) = (Int(Mycolor.R) >> 3) << 3 ' red byte 2^5 values
                    PixelArray(x, y, 1) = (Int(Mycolor.G) >> 2) << 2 ' green byte 2^6 values
                    PixelArray(x, y, 2) = (Int(Mycolor.B) >> 3) << 3 ' blue byte 2^5 values
                    ' RRRRRGGGGGGBBBBB
                    R = PixelArray(x, y, 0) >> 3 ' bit shifts
                    G = PixelArray(x, y, 1) >> 2
                    B = PixelArray(x, y, 2) >> 3
                    PixelArray(x, y, 3) = (R << 11) + (G << 5) + B
                    PixelArray(x, y, 4) = PixelArray(x, y, 3) >> 8 ' high byte
                    PixelArray(x, y, 5) = PixelArray(x, y, 3) And 255 ' low byte
                Next
            Next
    

    I was going to do this in pasm and see how fast it was.

    The thing I was thinking was that if you are merging a background and foreground, you have to extract RRRRRRRR GGGGGGGGG BBBBBBBBB for both from RRRRRGGGGGGBBBBB and then do the alpha calculation, and then convert back to RRRRRGGGGGGBBBBB so maybe it was easier to have larger files? I'm still not sure about that.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-01-12 05:33
    Working on some speed tests - a screen is 153600 bytes so it is not possible to store an entire screen in hub ram.

    However, if we store 512 bytes in an array and dump them out (eg store zero for a Clearscreen routine) then the speed to dump out to the display is 0.12 seconds for a full screen. This is useful for a "clearscreen" routine.

    It is a bit slower dumping out the contents of the ram - the speed for a full screen refresh is 0.46 seconds.

    Displaying icons will of course be faster - an icon 64x64 will be 0.46*64x64/(320*240) = 0.024 seconds if displaying from external ram (and even faster if displaying from hub).

    There are some different test routines - one moves data from external ram to hub, then hub to the display, and the other routine moves data directly from external ram to the display. The speeds end up about the same.

    I'm hoping movies might work in a smaller window - 160x120 might be 5 frames a second.

    Next experiment I'd like to do is see if I can print out a .raw file format. That ought to be useful as this is a file format that paint shop and other graphics programs can output, so no pre-processing will be needed.

    Once that is working, it will be time to look at drawing .png files with the transparent layer.


    Addit: Now can read .raw files so no preprocessing required for backgrounds
    PUB RawToILI | ramaddress                         ' convert 3 byte .raw file to 2 byte .ili file
        PrintStringCR(string("Load .raw file"))                 ' message on the TV screen    
        fat.openfile(string("tropical.raw"),"R")                ' open an image
        ramaddress := 0
        repeat 600
          fat.readdata(@sdbuffer,384)                       ' 128 pixels, 3 bytes per pixel
          ILI9325.docmd("E",@sdbuffer,@buffer2,128)         ' convert to 2 byte .ili format, len is number of pixels
          ILI9325.docmd("A",@buffer2,ramaddress,256)        ' move bytes to external ram
          ramaddress := ramaddress + 256                    ' add 256
        fat.closefile
        PrintStringCR(string("Closing file"))
        RamToDisplay                              ' move bytes from ram out to display
    
    PUB RamToDisplay ' clears screen and dumps preloaded ram to display starting address 0
        Clearscreen 
        ILI9325.draw(0,0,239,319)                           ' set up the area of the screen to draw in
        ILI9325.docmd("C",0,0,153600)                       ' move bytes from ram out to the display         
    
    PUB Clearscreen | i
        i := 0
        repeat 512
          sdbuffer[i] := 0                         ' array all to zero
          i := i + 1
        ILI9325.draw(0,0,239,319)                           ' set up the area of the screen to draw in   
        repeat 300
          ILI9325.docmd("D",@sdbuffer,0,512)                       ' move bytes from ram out to the display              
    

    14th Jan - worked out a way to display transparent icons without needing any special image vb.net (or whatever) preprocessing program.

    I'm using an ancient (1996) version of paint shop pro, so if that works then any graphics program *should* be able to do this:

    1) Open a .png icon file
    2) Copy and paste the picture to a new picture and save as a .raw RRRRRRRRGGGGGGGGBBBBBBBB file
    3) View the mask (in PSP there is a Mask on the top menu bar, then Edit).
    4) Masks/Save the file, and rename the extension as .bmp.
    5) Close down all open files in PSP, then File/Open and open the .bmp file above. This should be 256 color grayscale, ie 1 byte per pixel.
    6) Save that file as a .raw file, eg mask.raw
    7) Copy the mask.raw file to the sd card This .raw file has 1 byte per pixel (note different to the picture which is 3 bytes per pixel)

    Given that a group of icons are likely to all be the same size and use the same mask, you should only need to do this once.

    Next step - writing a little pasm program to combine myicon.raw and mask.raw

    Addit - this little bit of spin code creates a "one long per pixel" file with red,green,blue,alpha which means that if you have a graphics program like paint shop pro, that is all the other software you need.
    PUB CreateIcon | iconaddress,maskaddress,i,j
      ' this creates a .icn file which is 4 bytes per pixel, red, green, blue and alpha. Do once when setting up icons
      ' so one long per pixel. All values are 0-255
      ' takes 8 seconds per icon so don't do this every load
      ' to create an icon using paint shop pro or similar
      '1) Open a .png icon file which has a transparancy layer
      '2) Copy and paste the picture to a new picture and save as a .raw RRRRRRRRGGGGGGGGBBBBBBBB file
      '3) View the mask (in PSP there is a Mask on the top menu bar, then Edit).
      '4) Masks/Save the file, and rename the extension as .bmp.
      '5) Close down all open files in PSP, then File/Open and open the .bmp file above. This should be 256 color grayscale, ie 1 byte per pixel.
      '6) Save that file as a .raw file, eg mask.raw
      '7) Copy the mask.raw file to the sd card This .raw file has 1 byte per pixel (note different to the picture which is 3 bytes per pixel)    
    
      ' in a family of icons the mask.raw file is going to be the same for all of them
      ' so on the sd card one might have two files - clock.raw and mask.raw
      ' this function combines these together into an .icn file. It is in spin which is slower but this is only ever run once
      PrintStringCR(string("myfile.raw and mask.raw to myfile.icn"))   
      fat.openfile(string("clock.raw"),"R")                 ' open an icon file which is 59x60 bytes x3 = 10620
      iconaddress := 0 
      repeat 10620                                          ' 
        i := fat.readbyte
        ILI9325.docmd("W",@i,iconaddress,1)                  ' write n to ramaddress
        iconaddress +=1                                     ' increment the counter
      fat.closefile
      fat.openfile(string("mask.raw"),"R")                 ' open an icon file which is 59x60 bytes x3 = 10620
      maskaddress := 16384
      repeat 3540                                           ' one byte per pixel in the mask
        i := fat.readbyte
        ILI9325.docmd("W",@i,maskaddress,1)                  ' write n to ramaddress
        maskaddress += 1                                    ' increment the counter
      fat.closefile
      iconaddress := 0                                      ' reset counters
      maskaddress := 16384
                                                            ' see kyedos for using "stringpointer" instead of text 
      result := \fat.newFile(string("clock.icn"))           ' All aborts traps must have "variable := \function" setup.
      if(fat.partitionError == fat#Entry_Already_Exist)     ' file already exists
         result := \fat.deleteEntry(string("clock.icn"))    ' delete the old file
         result := \fat.newfile(string("clock.icn"))        ' recreate the file
      fat.openfile(string("clock.icn"),"W")
      repeat 3540
        ILI9325.docmd("R",@i,iconaddress,1)                  ' read from ram into i the red byte
        iconaddress += 1
        j := i << 24                                        ' put the red byte into msb place
        ILI9325.docmd("R",@i,iconaddress,1)                 ' read from ram into i the red byte
        iconaddress += 1
        j := j | (i << 16)                                  ' put the green byte into place
        ILI9325.docmd("R",@i,iconaddress,1)                 ' read from ram into i the red byte
        iconaddress += 1
        j := j | (i << 8)                                   ' put the blue byte into place
        ILI9325.docmd("R",@i,maskaddress,1)                 ' read from ram into i the alpha byte
        maskaddress += 1
        j := j | i                                          ' put the alpha byte into lsb place
        fat.writelong(j)                                    ' store to SD card file
      fat.closefile
      PrintStringCR(string("clock.icn created"))  
    

    I'm deep inside the maths of merging icons and the background.

    GUI working now with transparent icons

  • LtechLtech Posts: 380
    edited 2012-03-12 14:26
    I'm able to read from the touchscreen using Beau's SPI object;
    PUB main | yval, xval  
    SPI.start(3,0)
    'SPI read S, A2, A1, A0, Mode, SER, PD1, PD0
    '         1  0   0   1    1     0    0    0
    ' MSB first
    ' 001 is X
    ' 101 is Y
    repeat
      SPI.SHIFTOUT(19, 21, 5, 8 , %1101_0000)  ' reads y from  500 to 3700  (off < 500 )
      yval := SPI.SHIFTIN(17,21,2, 12)
    
      SPI.SHIFTOUT(19, 21, 5, 8 , %1001_0000)  ' reads x from 420 to 3800 (off > 3800 ) 
      xval := SPI.SHIFTIN(17,21,2, 12)
    

    The values seem to correspond to where I'm touching the screen. First bit is a start bit, A2,A1, And A0 set what axis you want to read. Mode is whether you want 8-bit or 12-bit resolution. SER further sets how you want the measurements returned. PD0 and PD1 are for the power down mode.

    Next thing is to roll this into the Spin version of the SPI object - I'd like the touchscreen to be read without needing another cog.

    Values do not work for me ?
    I tried different settings ???
    I just copy your code.
  • skylightskylight Posts: 1,915
    edited 2013-03-17 12:36
    @DrA Found this thread by accident and found it extremely interesting to see the project develop from the start, I'm presuming as this thread ends here the Propeller GUI touchscreen and full color display thread takes over from here?

    Trying to follow that thread was hard having not seen the previous thread, wondering how you'd advanced to such a high level. Wish these relevant threads were all in one place to make it easier for beginners like myself to try and catch up. Not a criticism just wishing there was a structure to keep relevant threads together.
Sign In or Register to comment.