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'
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!
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)
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.
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???
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.
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.
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
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.
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.
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?
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?
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.
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()
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.
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
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.
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.
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.
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.
@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 displaythread 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.
Comments
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'
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.
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!
Thanks!
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.
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.
Nice job. BTW Do you know if these displays when in 8 bit mode use DB0-7 or DB8-16 ?
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.
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.
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
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?
OBC
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.
two cents....
OBC
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.
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
Is your touchscreen I2C or SPI?
Mine seems to work with an SPI driver
spi: "SPI_ASM" ' thanks to Beau Then call this routine
What sort of display do you have?
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
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
@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
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.
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
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.
I'm deep inside the maths of merging icons and the background.
GUI working now with transparent icons
Values do not work for me ?
I tried different settings ???
I just copy your code.
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.