Propeller GUI touchscreen and full color display

1101113151624

Comments

  • average joeaverage joe Posts: 795
    edited 2012-05-16 - 19:41:50
    @ Johannes, I just got a chance to listen to the examples and I'm very impressed! Nice work as always!

    I've been stuck on the display end for so long, I forgot all the other cool things that need to be worked on. I need to test a "master-slave" config with 2 boards. Since I have 2 fully built boards and only 1 *QUESTIONABLE* display, I was going to use the second as an expansion board. I've also started to build a multi-prop audio generation circuit on the bread board. The plan is to use 4 props, 8 - R-C DAC's, and a small mixer to allow multi-voice SidCog and TINYsynth patches. More experimenting later tonight.

    Johannes and Doc, keep up the great work.
    *edited*

    Well, I ordered 2 new screens from hong-kong @ $13.00 a piece! Too bad it will be at least a month before they get here!
  • jazzedjazzed Posts: 11,803
    edited 2012-05-16 - 20:37:12
    Dr_Acula wrote: »
    C ultimately will be useful but right now it is stuck with not being able to read and write the SD card. That is my poor understanding of C probably, but even a one line fopen is not working. There is a thread about this in the C forum.

    I thought you had something working. Follow up?
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-05-19 - 21:05:43
    @jazzed - following up in the GCC thread, thanks!

    @averagejoe, I have done a massive rewrite of the code so that the sram acts as a better ramdisk. All the fonts, text files, bitmaps and music files are all treated in the same way, so there are no 'special' areas of the ramdisk. Probably the most obvious advantage is that more than one font can be stored - and I wanted that so I could put time signatures and other notation in the music font. So you can have a basic music font with notes, and then another font with fancy things like portamento.

    This is also in preparation for adding .wav files for sampling.

    I see Ahle2 has updated the synth - so will need to update that as well.

    And glue the music font to the synth player so it can play some music. Should be a simple 256 byte lookup table and maybe some code to handle sharps and flats.

    Addit: new files May21 - added in Kye's .wav player. There are a number of online .mp3 to .wav converters (plus many programs can do this) so it is very easy to have a library of music on the SD card. Need to add a selection box so can select which .wav file to play.
  • average joeaverage joe Posts: 795
    edited 2012-05-20 - 05:31:08
    Very nice work Doc. I've been working on porting the "Chiptune player" over to our hardware. Porting software is always a pain. I will let you know when I finish the port. I have not had a chance to look at the new code, but I will check it out when I get a chance.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-05-20 - 05:44:38
    Cross post, I uploaded a new version just now which has Kye's .wav player see post #364. At the simplest level, this makes the board a music player. I put a few songs on the sd card and they sound really good. The sample is just a tiny piano.wav file as there is no need for huge demo files as a typical .wav for a song is 40Mb or so. At a more complex level I'd like to try to understand Kye's code more and think about polyphonic .wav files playing at once. Somewhere in the code it is working out the volume. The volume is a startup constant but if you could change it on the fly you can mix multiple voices from a polyphonic sample based synth.
  • average joeaverage joe Posts: 795
    edited 2012-05-20 - 07:27:56
    Wonderful news! I'm stuck with the ChipTune player right now. Seems like we have quite a few files in the root directory so I tried playing with directories... The problem comes from getting the number of files. I think I have it fixed...
    PRI getNrOfTunes    | t,i   ''Gets the number of files in "Tunes" directory
      nrOfTunes := -1            'init number
        fat.closefile                'prepare sd card
       propfont_string(fat.changeDirectory(string("tunes")))  'change directory and display current working directory
      
      repeat until strcomp(@Dir2, t)     'cycle through root directory, 
        fat.listEntries("N")                    'get next fat entry
        t := fat.listname                       'copy name address to "t"
        propfont_String(t)                     'and display that name
        
      fat.listEntries("N")                    
      t := fat.listname
      propfont_String(t)
      i := 0
      
      repeat until byte[t][i] == 0 
        firstFile[i] := byte[t] [i]
        propfont_out(".")
        i++
      crlf
      propfont_string(string("FirstFile"))
      propfont_string(@firstFile)
      
      t:= -1
      repeat until strcomp(@firstFile, t)                
        fat.listEntries("N")
        t := fat.listname
        propfont_String(t)
        nrOfTunes++
        
      hex(nrOfTunes,4)
    DAT
    Dir2
            byte "..          ",0 
    
    This is what I've been able to come up with. I'd like to inline the "Dir2" but can't figure out how to get it to work. Seems working with directories is a bit confusing, but could help the "file clutter?"


    *edited*
    I have the chiptune player functioning. Not very pretty right now. But it opens chiptunes, and plays! I have not figured out the directory yet, so I have a copy in the root AND in "tunes" folder. I need to figure how to tack on the directory in file opens. Here's what I have working so far. Not much of a front end, but it works!
    '' ILI9325 driver using the Touchblade161 design for faster ram to display transfers with a hc137 for group select '' Average Joe and James Moxham 2012 ' notes re groupings of pins ' To shut down a group, deselect it by making P22 low. This makes Y0-Y7 from the 137 all high ' To start a group, the initial state is P0-P20 all HiZ and P22 HiZ (P21 and 23 are audio and there is less audio noise if the pins are not next to each other) ' Passing to a cog, P0-P20 and P22 HiZ ie DIRA all as 0 fo these pins. This is to avoid contention between spin and the cog code ' A routine in Spin or Pasm that changes the 137 will also return P0-P20 and P22 as HiZ. ' In general terms, H is inactive and L is active. So changing a pin from HiZ to H will have no effect as pins all have pullups. ' Any handover to cog code must be done in this HiZ state and all pins in a group need to work with this CON ''LCD REGISTERS REG_OSCILLATOR = $0000 ''Oscillator (R00h) (POR = 0000h) REG_DRIVEROUTPUTCONTROL = $0001 ''Driver Output Control (R01h) (POR = 2B3Fh) REG_LCDDRIVINGWAVFORM = $0002 ''LCD-Driving-Waveform Control (R02h) (POR = 0000h) REG_POWERCONTROL1 = $0003 '' (R03H) REG_DISPLAYCONTROL = $0007 ''Display Control (R07h) (POR = 0000h) REG_FRAMECYCLECONTROL = $000B ''Frame Cycle Control (R0Bh) (POR = 5308h)D308 BY DATASHEET REG_POWERCONTROL2 = $000C '' (R0Ch) (POR = 0004) REG_POWERCONTROL3 = $000D '' REG_POWERCONTROL4 = $000E '' REG_GATESCANPOSITION = $000F ''Gate Scan Position (R0Fh) (POR = 0000h) REG_SLEEPMODE = $0010 ''Sleep mode (R10h) (POR = 0001h) REG_ENTRYMODE = $0011 ''Entry Mode (R11h) (POR = 6830h) REG_HPORCH = $0016 '' (R16h) (POR = EF1Ch) REG_VPORCH = $0017 '' (R17h) (POR = 0003h) REG_POWERCONTROL5 = $001E '' REG_RAMDATAWRITE = $0022 '' REG_RAMWRITEDATAMASK1 = $0023 '' (R23h) (POR = 0000h) REG_RAMWRITEDATAMASK2 = $0024 '' (R24h) (POR = 0000h) REG_VERTICALSCROLCONTROL1 = $0041 '' (R41h) (POR = 0000h) REG_VERTICALSCROLCONTROL2 = $0042 '' (R42h) (POR = 0000h) REG_HORIZONTALRAMADDRESSPOS = $0044 '' (R44h) (POR = EF00h) REG_VERTICALRAMADDRESSSTART = $0045 '' (R45h) (POR = 0000h) REG_VERTICALRAMADDRESSEND = $0046 '' (R46h) (POR = 013Fh) REG_FIRSTWINDOWSTART = $0048 '' (R48h) (POR = 0000h) REG_FIRSTWINDOWEND = $0049 '' (R49h) (POR = 013Fh) REG_SECONDWINDOWSTART = $004A '' (R4Ah) (POR = 0000h) REG_SECONDWINDOWEND = $004B '' (R4Bh) (POR = 013Fh) REG_SETGDDRXADDRESSCOUNTER = $004E '' (R4Eh) (POR = 0000h) REG_SETGDDRYADDRESSCOUNTER = $004F '' _clkmode = xtal1 + pll16x ' use crystal x 16 _xinfreq = 5_000_000 _1ms = 1_000_000 / 1_000 ' Divisor for 1 ms ' kye sd numbers _dopin = 24 _clkpin = 25 _dipin = 26 _cspin = 27 _cdpin = -1 ' -1 if unused. _wppin = -1 ' -1 if unused. _rtcres1 = -1 ' -1 always. _rtcres2 = -1 ' -1 always. _rtcres3 = -1 ' -1 always. _statuspin = -1 ' Status LED pin number. ' touchscreen pins Touch_Clock = 0 'Touch_ChipSelect = done with a 137 select Touch_DataIn = 1 Touch_DataOut = 2 ' audio pins _leftChannelVolume = 32 _rightChannelVolume = 32 _leftChannelAudioPin = 21 ' -1 ifnot installed. _rightChannelAudioPin = 23 ' -1 ifnot installed. ' general purpose constants Margin = 4 ' some characters have xoffset of -1 or -2 eg v, and won't display on the extreme left edge ' external ram size of data blocks Ram_Fontsize = 65536 ' 128k for fonts (largest is around 108k) Ram_MaskSize = (64*64*2)/2 ' 64x64 (59x60) bytes divide by 2 for words Ram_IconSize = (64*64*2)/2 ' 2 bytes per pixel converts from .bmp in the routine Ram_TextSize = 32768 ' 64k for text ' external ram locations, if adding more, follow the pattern FontTable = 0 ' address for ram chip (2 bytes per address) Mask = FontTable + Ram_Fontsize ' address for raw mask image Icon = Mask + Ram_MaskSize ' address for icon image Text = Icon + Ram_IconSize ' text buffer for word processing etc RamDiskStart = Text + Ram_TextSize ' ramdisk with searchable bitmap files OBJ 'fat: "SD3.01_FATEngine.spin" ' thanks to Kye - sd card fat: "SD-MMC_FATEngine.spin" ' Kye's latest sd driver and no RTC spi: "SPI_ASM" ' thanks to Beau - spi driver for touch screen str: "ASCII0_STREngine.spin" ' thanks to Kye - string routines ' term: "FullDuplexSerial.spin" ' Thanks to Chip - for debugging if display not working ' synth : "tinysynth" ' ' Thanks Ahle2 http://forums.parallax.com/showthread.php?139724-TinySynth-! VAR long orientation long curx, cury long clkcycles ' for the delay routine word ScreenWidth ' either 240 in portrait or 320 in landscape word ScreenHeight ' 320 in portrait or 240 in landscape byte LineOfText1[20] ' general purpose string buffer byte LineOfText2[20] ' general purpose string buffer byte FontHeight ' size of the current loaded font (pixels = fontsize *.75) word BackFontColor ' the background color in RRRRRGGG GGGBBBBB format long RamDiskPointer ' pointer to current ramdisk location long RamDiskFiles ' number of files in the ramdisk 'byte sdbuffer[512] ' can't put these here, writes to sdbuffer sometimes back overwrite variables above this eg fontheight!! 'byte buffer2[512] ' so put these in a dat section 'word rambuffer[256] long DecRate ' synth settings long SusLevel long PWinit long pwmRate long Filter long Portamento ''*****************Start chiptune Player CON here*********************** CON ENABLE_PAL = false ''****************Start chiptune Player OBJ here************************ OBJ ' WaveZoom : "WaveZoomer" ' OSC : "Oscilloscope" SID : "SIDcog" AY : "AYcog" ' SD : "fsrw" ''***************Start chiptune Player VAR here VAR byte buffer[25] byte filename[18] byte playing byte chipTuneType byte prevChipTuneType byte ffw word playRate long wait long fileNumber long nrOfTunes long scrollSpeed long frameCounter long scrollCounter long textPointer long AY_register PUB Main | i, oldStatus, fin,yval, xval start_ram ' start the external ram / display driver in a cog Change161(0) ' reset all the 161 counters to zero SelectMemGroup ' select group1 Start_ILI9325 ' start the display. Don't clear screen as this uses ram commands and these might not be working yet SetOrientation(true) ' in portrait (true) or landscape mode (false), must be before clearscreen otherwise don't know screensize 'pause1ms(5000) Clearscreen(RGBtoWord(0,0,0)) ' clear screen to black - uses the display driver above propfont_string(String("Mount SD")) fat.fatEngineStart( _dopin, _clkpin, _dipin, _cspin, _wppin, _cdpin, _rtcres1, _rtcres2, _rtcres3) fat.mountPartition(0) ' mount the sd card propfont_string(String("Mounted")) ClearRamdisk ' clear ram disk for pictures not on the desktop ''*Note* Load fonts and bmp's here! LoadBMPtoRamdisk(string("Trans.bmp")) sid.start(_rightChannelAudioPin, _leftChannelAudioPin) propfont_out(".") crlf getNrOfTunes 'pause1ms(5000) Clearscreen(RGBtoWord(0,0,0)) ' clear screen to black - uses the display driver above curx := 0 cury := 0 propfont_string(@message4) 'propfont_out("!") frameCounter := 0 fileNumber := 0 chipTuneType := 1 playRate := 50 scrollSpeed := 2 playing := false ffw := false wait := cnt DrawBMP(string("Trans.bmp"),0,280) openNextFile 'Main loop repeat ' Wait between register updates if (cnt - wait) > 0 if ffw wait := cnt + (clkfreq/(playRate<<2)) else wait := cnt + (clkfreq/playRate) ' Update the PSG if playing case chipTuneType 1: updateSID 2: updateAY ' Check for a change in tv status ' if oldStatus <> tv_status ' oldStatus := tv_status ' ' Check for vbl ' if tv_status == 2 ' scroll ' ' ' Handle user interactions ' if input.getLastState <> input.getCurrentState SelectSPIGroup yval := TouchYPercent ' decode yval 0-100% xval := TouchXPercent ' decode xval 0-100% if (xval <> 255) and (yval <> 255) 'SelectMemGroup 'hex(xval,2) ' if display any debug messages need to restart the SPI cog as it has been stopped by the debug display 'hex(yval,2) if (yval > 89) SelectMemGroup ' Handle previous tune if (xval < 19) handleMuting if fileNumber == 0 fileNumber := nrOfTunes + 1 fileNumber-- openNextFile ' Handle pausing if (xval > 37 and xval < 70) playing := not playing handleMuting ifnot playing setScrollMessage(@message2) else ffw := false setScrollMessage(@songName) ' Handle next tune if (xval > 79 and xval < 99) handleMuting if fileNumber == nrOfTunes fileNumber := -1 fileNumber++ openNextFile ' ' Handle pausing ' if input.getLastState&input#START ' playing := not playing ' handleMuting ' ' ifnot playing ' setScrollMessage(@message2 - @message) ' ' else ' ffw := false ' setScrollMessage(@songName - @message) ' ' scrollSpeed := 8 ' ' ' Handle fast forward ' if playing > 0 and input.getLastState&input#A ' ffw := not ffw ' ' if ffw ' setScrollMessage(@message3 - @message) ' ' else ' setScrollMessage(@songName - @message) ' ' scrollSpeed := 8 ' ' ' Handle next tune ' if input.getLastState&input#RIGHT ' if fileNumber == nrOfTunes ' fileNumber := -1 ' ' fileNumber++ ' openNextFile ' ' ' Handle previous tune ' if input.getLastState&input#LEFT ' if fileNumber == 0 ' fileNumber := nrOfTunes + 1 ' ' fileNumber-- ' openNextFile ' ' ' Handle next page ( += 10 ) ' if input.getLastState&input#DOWN ' fileNumber += 10 ' ' if fileNumber > nrOfTunes ' fileNumber := 0 ' ' openNextFile ' ' ' Handle previous page ( -= 10 ) ' if input.getLastState&input#UP ' fileNumber -= 10 ' ' if fileNumber < 0 ' fileNumber := nrOfTunes ' ' openNextFile PRI openNextFile | i, t, nameP ffw := false playing := true ' Iterate through files and find the file with fileNumber == X fat.closeFile repeat i from 0 to fileNumber fat.listEntries("N") nameP := fat.listname t:=0 repeat until byte [nameP][t] == 0 byte [@filename][t]:= byte[nameP][t] t++ byte[@filename][t] := 0 ' Find out what kind of file type we are dealing with prevChipTuneType := chipTuneType chipTuneType := 0 fat.openFile(@filename, "R") if fat.readData(@buffer, 4) < 0 if byte[nameP - 3] == "D" and byte[nameP - 2] == "M" and byte[nameP - 1] == "P" chipTuneType := 1 if buffer[0] == "S" and buffer[1] == "D" and buffer[2] == "M" and buffer[3] == "P" ' SDMP chipTuneType := 1 elseif buffer[0] == "Y" and buffer[1] == "M" and buffer[2] == "6" and buffer[3] == "!" ' YM6! chipTuneType := 2 else fat.closeFile AY.stop SID.stop setScrollMessage(@message1) return ' Set some standard values in case the header doesn't provide any info playRate := 50 bytefill(@songName + 10, 32, 15) intToString(@songName + 6, fileNumber, 5) repeat i from 0 to 15 if filename[i] byte[@songName + i + 10] := filename[i] else i := 16 ' Init everything, read the header and start the PSG fat.openFile(@filename, "R") if chipTuneType == 1 readHeaderSID initSID elseif chipTuneType == 2 readHeaderAY initAY wait := cnt + 20_000_000 PRI handleMuting case chipTuneType 1: if playing SID.unmute else SID.mute 2: if playing AY.unmute else AY.mute PRI initSID | registers if prevChipTuneType == 2 AY.stop elseif prevChipTuneType == 1 SID.stop registers := SID.start( _rightChannelAudioPin, _leftChannelAudioPin ) SID.resetRegisters ' OSC.stop ' OSC.start( display_base, registers + 28, @tv_status, @scrollSpeed ) chipTuneType := 1 ' setSIDColor PRI initAY | registers if prevChipTuneType == 2 AY.stop elseif prevChipTuneType == 1 SID.stop registers := AY.start(_rightChannelAudioPin, _leftChannelAudioPin, AY_register) AY.resetRegisters ' OSC.stop ' OSC.start( display_base, registers + 16, @tv_status, @scrollSpeed ) chipTuneType := 2 ' setAYColor PRI updateSID if( fat.readData(@buffer, 25) ) < 0 fileNumber++ openNextFile SID.updateRegisters(@buffer) PRI updateAY if( fat.readData(@buffer, 16) ) < 0 fileNumber++ openNextFile AY.updateRegisters(@buffer) PRI readHeaderSID | i, t if( fat.readData(@buffer, 25) ) => 0 if buffer[0] == "S" and buffer[1] == "D" and buffer[2] == "M" and buffer[3] == "P" playRate := buffer[4] | (buffer[5]<<8) repeat i from 0 to 15 t := buffer[ i + 8 ] if t byte[ @songName + i + 10 ] := t else byte[ @songName + i + 10 ] := 32 PRI readHeaderAY | extra, digiDrums, i, t if( fat.readData(@buffer, 12)) => 0 ' 00 - read "YM6!" header ' 04 - read "LeOnArD!" identifier if( fat.readData(@buffer, 4) ) => 0 ' 0c - number of VBL frames (play rate) if( fat.readData(@buffer, 4) ) => 0 ' 10 - attributes if( fat.readData(@buffer, 2) ) => 0 ' 14 - number of digi drum samples digiDrums := buffer[0] | (buffer[1]<<8) if( fat.readData(@buffer, 4) ) => 0 ' 16 - YM2149 external frequency in Hz AY_register := buffer[3] | (buffer[2]<<8) | (buffer[1] << 16) | (buffer[0] << 24) if( fat.readData(@buffer, 2) ) => 0 ' 1a - player frequency in Hz playRate := buffer[1] | (buffer[0]<<8) if( fat.readData(@buffer, 4) ) => 0 ' 1c - frame where looping starts if( fat.readData(@buffer, 2) ) => 0 ' 20 - extra bytes following (should be 0) extra := buffer[0] | (buffer[1]<<8) bytefill(@buffer, 32, 15) if get_string ' read song name repeat i from 0 to 14 t := buffer[i] if t byte[ @songName + i + 10 ] := t else byte[ @songName + i + 10 ] := 32 get_string ' read author name get_string ' read comments / software PRI get_string | n, t repeat n from 0 to 127 if (t := fat.readByte ) =< 0 return n else if n < 25 buffer[n] := t var byte firstFile[18] PRI getNrOfTunes | t,i nrOfTunes := -1 fat.closefile propfont_string(fat.changeDirectory(string("tunes"))) repeat until strcomp(@Dir2, t) fat.listEntries("N") t := fat.listname 'propfont_String(t) fat.listEntries("N") t := fat.listname 'propfont_String(t) i := 0 repeat until byte[t][i] == 0 firstFile[i] := byte[t] [i] ' propfont_out(".") i++ crlf 'propfont_string(string("FirstFile")) 'propfont_string(@firstFile) t:= -1 repeat until strcomp(@firstFile, t) fat.listEntries("N") t := fat.listname ' propfont_String(t) nrOfTunes++ if nrOfTunes < 1 nrOfTunes -= 2 'hex(nrOfTunes,2) 'pause1ms(5000) PRI intToString( position, value, digits ) | i digits += position if value < 0 -value byte[position++] := "-" i := 1_000_000_000 repeat 10 if value => i byte[position++] := value / i + "0" value //= i result~~ elseif result or i == 1 byte[position++] := "0" i /= 10 repeat while position < digits byte[position++] := " " PUB SetScrollMessage(x) curx :=0 cury :=127 propfont_string(x) dat message byte " " songName byte 32, 32, 32, 32, 32, "#", 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 0 message1 byte " Invalid file ", 0 message2 byte "&#8227;&#8227; Paused", 0 message3 byte " &#9654;&#9654; Fast forward ", 0 message4 byte "Propeller chip-tune player by Johannes Ahlebrand Select a tune ", 0 'zero long $80000000 T Dir2 byte ".. ",0 PUB FixGlitch ILIcmd($0000,$0001) 'Turn Oscillator on POR-$0000 ' pause1ms(1) ' ILIcmd($0003,$A8A4) 'Power control (1) POR-$6664 ' pause1ms(1) ' ILIcmd($000C,$0000) 'Power control (2) POR- ? ' pause1ms(1) ' ILIcmd($000D,$080C) 'Power control (3) POR-$0009 ' pause1ms(1) ' ILIcmd($000E,$2B00) 'Power control (4) POR-$3200 ' pause1ms(1) ' ILIcmd($001E,$00B0) 'Power control (5) POR-$0029 ' pause1ms(1) ILIcmd($0001,$6B3F) 'Driver output control, *landscape?? $6B3F* From code??2B3F? POR-$433F ' pause1ms(1) ILIcmd($0002,$0600) 'LCD drive AC control POR-$0400 ' pause1ms(1) ILIcmd($0010,$0000) 'Sleep Mode sleep mode off POR-$0001 ' pause1ms(1) ILIcmd($0011,$6070) 'Entry Mode, *landscape? $4030* POR-$6830 ' pause1ms(1) ILIcmd($0007,$0033) 'Display Control POR-$0000 ''Used 0033 ' pause1ms(1) ILIcmd($0023,$0000) 'RAM write data mask (1) POR-$0000 ' pause1ms(1) ILIcmd($0024,$0000) 'RAM write data mask (2) POR-$0000 ' pause1ms(1) ChangeOrientation(orientation) PUB Deadend repeat waitcnt(cnt) ' *********************************** Driver Routines ******************************* PUB OpenFileRead(stringptr) ' open a file for reading and display a message if it fails result := \fat.openfile(stringptr,"R") if fat.partitionerror <> 0 ' failed to find the file propfont_string(stringptr) ' print the filename propfont_string(result) ' print the error message repeat ' stop the program PRI TouchValue | xval,yval,x,y ' returns % values 0-100% (or 255 for no touch) xval := TouchX yval := TouchY if (xval => 500) and (yval =< 3800) ' both have to be valid for a touch pause1ms(2) ' tiny delay then read again as the first reads may not have the correct value xval := TouchX yval := TouchY if (xval => 500) and (yval =< 3800) ' and if valid again, now more likely this value is correct x := xval - 440 ' scale 0-3360 x /= 32 ' scale 0-100 x <#= 100 ' max 100 x #>=0 ' min 0 x := 100 - x ' so left edge on left y := yval -420 ' scale 0-3180 y /= 32 ' scale 0-100 y <#= 100 ' max 100 y #>=0 ' min 0 y := 100-y ' so 0 is top left result := (y <<8) | x ' return 00000000_00000000_YYYYYYYY_XXXXXXXX if (xval < 500) or (xval >3800) result := $0000FFFF ' invalid number(s) PUB TouchXPercent result := 100 - (TouchValue & 255) ' decode xval 0-100% PUB TouchYPercent result := TouchValue >> 8 ' decode yval 0-100% PUB TouchSwish | xval,oldxval,difference,average ' returns result = +ve or -ve depending on swish direction ' did finger move left or right? SelectSPIGroup ' turn on the spi touchscreen oldxval := 255' for startup average := 0 repeat until (average > 30) or (average < -30) ' possibly add a decay function here for average pause1ms(50) xval := TouchXPercent ' decode xval 0-100% if xval == 255 ' not touched oldxval := 255 ' reset oldxval as well else if oldxval <>255 ' discard the first reading as the screen is touched difference := xval - oldxval 'printdecimal(xval) 'printdecimal(difference) average := average + difference ' 'printdecimal(average) 'crlf oldxval := xval ' store for next time result := average ' return negative or positive value PUB TouchStart SPI.start(3,0) ' delay,state, start clock high PRI TouchX SPI.SHIFTOUT(Touch_DataIn, Touch_Clock, 5, 8 , %1101_0000) ' reads x from 500 to 3700 (off < 500 ) result := SPI.SHIFTIN(Touch_DataOut,Touch_Clock,2, 12) PRI TouchY SPI.SHIFTOUT(Touch_DataIn, Touch_Clock, 5, 8 , %1001_0000) ' reads y from 400 to 3800 (off > 3800 ) result := SPI.SHIFTIN(Touch_DataOut,Touch_Clock,2, 12) PUB SDToDisplay(stringptr) ' bitmap from SD to display Clearscreen(0) ClearRamDiskExcludeDesktop LoadBMPtoRamdisk(stringptr) DrawBMP(stringptr,0,0) PUB FindBMP(stringptr) | i,rampointer,ramcounter,match,searchlen,width,height ' pass the name and the x and y location, searches for this file and if found, displays it rampointer := RamDiskStart searchlen := str.instr(stringptr,".") - 1 ' ignore the .bmp extension repeat ramcounter from 1 to ramdiskfiles docmd("T",@sdbuffer,rampointer,$36) ' get hex $36 bytes from the ramdisk = filenames width := sdbuffer[$12] + sdbuffer[$13] << 8 ' only read in two bytes as never will be >64k wide or high height := sdbuffer[$16] + sdbuffer[$17] << 8 match := true repeat i from 0 to searchlen - 1 if sdbuffer[i] <> byte[stringptr][i] match := false ' any characters not matching, try next one. (case must match too) if match == true quit ' found a match so quit looking for any more files ' get the next rampointer = $36 + width * height rampointer += $36 + (width * height) if match == true ' if found a match return the rampointer result := rampointer else result := -1 ' no match so zero PUB ClearRamdisk ILISetcursor(0,0) ' cursor for debugging to 0,0 RamDiskPointer := RamDiskStart ' set the global ramdisk pointer start RamDiskFiles := 0 PUB ClearRamdiskExcludeDesktop ' exclude the desktop which is the first 76800+36 pixels and also sets ramdiskfiles to 1, not 0 ClearRamdisk RamDiskPointer += $36 + (240 * 320) ' leave room for the desktop RamDiskFiles +=1 ' file counter +1 PUB DrawBMP(stringptr,x,y) | rampointer,width,height ' pass the name and the x and y location, searches for this file and if found, displays it rampointer := FindBMP(stringptr) ' find the file in the list if rampointer <> -1 ' if a match then draw width := sdbuffer[$12] + sdbuffer[$13] << 8 ' only read in two bytes as never will be >64k wide or high height := sdbuffer[$16] + sdbuffer[$17] << 8 Draw(x,y,x+width-1,y+height-1) ' set up the area to draw RamToDisplay(RamPointer + $36,width*height) ' skip the header and display result := (width <<16) | (height & $0000FFFF) ' return the width and height combined into a long PUB TextBoxClear(x1,y1,x2,y2) ' draw the outline of the box ClearRectangle(x1,y1,x2,y2,RGBtoWord(255,255,255)) Drawline(x1-1,y1-1,x2,y1-1,RGBtoWord(64,64,64)) ' gray outline lines - extract values from paint shop pro Drawline(x1-2,y1-2,x2+1,y1-2,RGBtoWord(128,128,128)) ' horizontal upper light gray Drawline(x1-1,y1-1,x1-1,y2,RGBtoWord(64,64,64)) ' vertical left gray Drawline(x1-2,y1-2,x1-2,y2+1,RGBtoWord(128,128,128)) ' vertical left light gray Drawline(x2+2,y1-2,x2+2,y2+2,RGBtoWord(255,255,255)) ' vertical right white Drawline(x1-2,y2+2,x2+2,y2+2,RGBtoWord(255,255,255)) ' horizontal lower white PUB LoadBMPtoRamdisk(stringptr) | width,height,w,i ' load and display a bitmap file ' http://en.wikipedia.org/wiki/BMP_file_format scroll down about 1/3 of the way for the header formats ' get the width, height ' store these as 2 longs at the beginning of the ram file ' the bitmap format starts at the last row and works up so need to reverse the order ' on the ram store a 0x36 byte header - the bitmap header but put in the filename at location 0 ' this becomes a rudimentary file system that can be searched to find pictures 'propfont_out("1") ' for debugging display something while load in pictures ' pause1ms(Debugtimer) fat.openfile(stringptr,"R") OpenFileRead(stringptr) fat.readdata(@sdbuffer,$36) ' get the header 0x36 hex bytes width := sdbuffer[$12] + sdbuffer[$13] << 8 ' only read in two bytes as never will be >64k wide or high height := sdbuffer[$16] + sdbuffer[$17] << 8 w := width * 3 ' this number of bytes per row, and round up to nearest 4 bytes et 327 goes to 328 The size of each row is rounded up to a multiple of 4 bytes (a 32-bit DWORD) by padding. w +=3 ' add 3 and w &= %11111111_11111111_11111111_11111100 ' round down repeat i from 0 to 11 ' add the file name at the beginning of the header sdbuffer[i] := byte[stringptr][i] docmd("S",@sdbuffer,RamDiskPointer,$36) ' store header to ram i := $36 + RamDiskPointer + ((height - 1) * width) ' start + header and on the last row and work back repeat height fat.readdata(@sdbuffer,w) ' read in the first row docmd("F",@sdbuffer,@rambuffer,width) HubToRam(i,width) ' send to ram i -= width ' subtract the width, move up the picture FixGlitch fat.closefile RamDiskPointer += $36 + (width * height) ' increment the ramdiskpointer for next picture RamDiskFiles += 1 ' increment number of entries in the ram disk FixGlitch PUB DrawCheckbox(x,y,Checked,Stringptr) | i ' draw a checkbox if checked DrawBMP(string("Checked.bmp"),x,y) else DrawBMP(string("Uncheckd.bmp"),x,y) curx := x+20 ' add 20 width cury := y ILIPrintString(stringptr) PUB DrawRadioBox(x,y,Checked,Stringptr)| i ' draw a radio box if checked DrawBMP(string("RadioChk.bmp"),x,y) else DrawBMP(string("RadioUnc.bmp"),x,y) curx := x+20 ' add 20 width cury := y ILIPrintString(stringptr) PUB DrawButton(x,y,Stringptr) ' draw a radio box DrawBMP(string("butn8430.bmp"),x,y) curx := x + (84/2)-(str.len(stringptr)*4 / 2) ' centre, avg width 4 per char 84 could be a variable width passed to this routine cury := y + 8 ILIPrintString(stringptr) PUB LoadFile(strpointer) | filesize,i ' reads a text file into external ram OpenFileRead(strpointer) ' open a file filesize := fat.filesize i := Text ' store text here repeat (filesize >>8 ) + 1 ' so works with 256 byte blocks fat.readdata(@sdbuffer,256) ' get 256 bytes from sd card docmd("S",@sdbuffer,i,128) ' send 128 words to external ram i +=128 ' increment counter fat.closefile return filesize PUB NewFont(strpointer) ILIloadfont(strpointer) ' only call this routine with the cursor curx at zero ClearRectangle(curx,cury,screenwidth,cury+FontHeight,BackFontColor) ' clear an area the same color as the font background PUB ILIChar(ascii,x,y) | jump,size,width,height,ramaddress,xoffset,yoffset,xadvance ' read out a character from a .ifn file stored in ram ' pass Fonttable = global ' moves to next line if off the end jump := ReadRamLong(fonttable,(ascii << 2) + 256) ' jump location = ascii *4 plus fonttable + 256 docmd("T",@buffer2,fonttable+jump>>1,20) ' read in the width height as a block = quicker than readramlong size := long[@buffer2][0] ' size in pixels of this character xadvance := long[@buffer2][5] ' amount to move to next character 'if size > 0 and ascii <> 32 ' no need to print anything if size is zero or read more font data width := long[@buffer2][1] ' width height := long[@buffer2][2] ' height xoffset := long[@buffer2][3] ' xoffset to move yoffset := long[@buffer2][4] ' yoffset to move if (x+width -1 + xoffset) > screenwidth ILIcrlf ' do a new line if it won't fit x := curx y := cury if ascii < 32 xadvance := 0 ' add nothing if a non displaying character if ascii == 13 ' carriage return ILIcr x := curx if ascii ==10 ' line feed (new line) ILIlf y := cury if ascii > 32 ' space not displayed Draw(x+xoffset,y+yoffset,x+width-1+xoffset,y+height-1+yoffset) ' draw on screen RamToDisplay(fonttable+((jump+32)>>1),size) ' move bytes from ram out to the display return x + xadvance PUB ILIcrlf ILIcr ILIlf PUB ILIcr ' carriage return, to left margin curx := Margin ' some characters are -1 xoffset so won't display PUB ILIlf ' line feed, move up one cury += FontHeight if cury > screenheight ClearRectangle(0,0,screenwidth,screenheight,BackFontColor) cury := 0 ' if off the bottom of the screen then clear screen start at the top (VT00 does scrolling) ' don't clear background here, do in calling routine 'ClearFontBackground(0,cury,screenwidth,cury + FontHeight) ' clear background line to the background color ready to draw PUB ILIPrintstring(stringptr) 'print at curx,cury '' Print a zero-terminated string repeat strsize(stringptr) curx := ILIChar(byte[stringptr++],curx,cury) PUB ILISetCursor(x,y) curx := x cury := y PUB ReadRamLong(WordStart,Bytevalue) ' easier calculating docmd("T",@result,Wordstart+Bytevalue>>1,2) return result PUB ILILoadFont(stringptr) | filesize,i ' read a .ifn file premade in angelcode bmfont and then the vb.net program ' ' pass file name in stringptr i := fonttable ' store at the constant 'fonttable' location, 2 bytes per address OpenFileRead(stringptr) ' open an image. Size is in the first long and has been rounded up to the next 256 byte block filesize := fat.filesize ' read the file size. This file has been rounded up to the next 256 byte block repeat (filesize >> 8) ' read in this number of 256 byte blocks fat.readdata(@rambuffer,256) ' get 256 bytes from sd card HubToRam(i,128) ' 128 words = 256 bytes i += 128 ' counter for ram location fat.closefile docmd("T",@rambuffer,FontTable,128) ' read first 128 words =256 bytes back FontHeight := byte[@rambuffer][251] ' font height 'hex(fontheight,8) repeat i from 0 to 2 sdbuffer[i] := byte[@rambuffer][35+i] docmd("E",@sdbuffer,@buffer2,1) ' convert to 2 byte .ili format BackFontColor := ( byte[@buffer2][1] << 8) | byte[@buffer2][0] ' correct order 'hex(backfontcolor,4) result := filesize PUB MergeBackgroundIcon(stringptr,x,y) | i,j,k,n ' merge icon and background - if mask =0 then background, else icon (not classic alpha compositing but close enough) ' i is background counter, j is icon counter, k = mask counter LoadBMPtoRamdisk(stringptr) ' load icon into ram i := RamDiskStart + $36 + (y*(screenwidth+1)+x) ' location of picture pixel in ram j := FindBMP(stringptr) + $36 ' location of icon in ram k := FindBMP(string("mask.bmp")) + $36 ' location of mask repeat 60 docmd("T",@sdbuffer,i,59) ' get 59 pixels from background docmd("T",@rambuffer,j,59) ' get 59 icon pixels docmd("T",@buffer2,k,59) ' get words for the mask 'repeat n from 0 to 58 ' if (word[@buffer2][n] & %00000000_00011111) > %10000 ' RGB are the same, so use BBBBB, mask 5 low bits, and if > %10000 ' word[@sdbuffer][n] :=word[@rambuffer][n] ' if >128 then replace with icon pixel docmd("X",@sdbuffer,@rambuffer,@buffer2) ' pasm version of the above 3 lines docmd("S",@sdbuffer,i,59) ' send back modified line to the picture buffer i += screenwidth+1 ' next line in picture j +=59 ' icon next line k +=59 ' next line in mask (bytes) - buffer2 FixGlitch PUB HubToRam(RamAddress,Number) ' send pixels from rambuffer hub to ram docmd("S",@rambuffer,RamAddress,Number) PUB RamToHub(RamAddress,Number) ' send pixels from ram to hub at rambuffer docmd("T",@rambuffer,RamAddress,Number) PUB RamToDisplay(RamAddress,Number) ' send pixels from ram to display docmd("U",0,RamAddress,Number) PUB HubToDisplay(HubAddress,Number) ' send pixels from hub to display docmd("V",HubAddress,0,Number) PUB Change137(group) docmd("Y",group,0,0) ' change the current group PUB Change161(RamAddress) ' pass ramaddress. Returns in group 1 docmd("Z",0,RamAddress,0) PUB Clearscreen(color) ' uses 2 byte ILI color (see below for rgb conversion) wordfill(@rambuffer,color,256) Draw(0,0,screenwidth,screenheight) ' set up the area of the screen to draw in repeat 300 HubToDisplay(@rambuffer,256) PUB RGBtoWord(R,G,B) ' convert RGB to 2 byte ILI color sdbuffer[0] := R sdbuffer[1] := G sdbuffer[2] := B docmd("E",@sdbuffer,@buffer2,1) result := ( byte[@buffer2][1] << 8) | byte[@buffer2][0] ' correct order PUB ClearRectangle(x1,y1,x2,y2,ColorWord) | i,size,remainder ' clears an area of the screen to the current font background color size := (x2-x1+1) * (y2 - y1 +1) ' number of pixels remainder := size & 255 ' if not a whole number of 256 pixels repeat i from 0 to 255 ' move the background font colour to the buffer rambuffer[i] := ColorWord Draw(x1,y1,x2,y2) ' set up the area of the screen to draw in repeat size >> 8 ' 256 pixel blocks docmd("V",@rambuffer,0,256) if remainder <> 0 docmd("V",@rambuffer,0,remainder) ' do the remainder PUB Drawline(x1,y1,x2,y2,ColorWord) ' draws a vertical or horizontal line ClearRectangle(x1,y1,x2,y2,ColorWord) ' same as drawing a rectangle PUB SetOrientation(e) ' change orientation true = portrait. Changes global variable 'orientation' and also screen width and height orientation := e ChangeOrientation(orientation) if orientation screenwidth :=239 screenheight :=319 else screenwidth :=319 screenheight :=239 PUB SelectMemGroup ' select group 2 for memory transfer spi.stop ' and stop any other cogs here too if needed OUTA |= %00000000_00011111_11111111_11111111 ' set P0-P20 high DIRA |= %00000000_00011111_11111111_11111111 ' set P0-P20 as outputs Change137(1) OUTA |= %00000000_00011111_00000000_00000000 ' set P16-P20 high DIRA |= %00000000_00011111_11111111_11111111 ' set P0-P20 as outputs PUB SelectSPIGroup ' select group 0 for the SPI 'SsdInit OUTA |= %00000000_00000000_00000010_00000000 ' keep p9 high so doesn't reset DIRA |= %00000000_00000000_00000010_00000000 ' P0-P2 are used to load the 137 Change137(2) OUTA |= %00000000_00000000_00000010_00000000 ' keep p9 high so doesn't reset DIRA |= %00000000_00000000_00000010_00000000 ' enable these pins for output DIRA &= %11111111_11111111_11111111_11111000 ' so no clashes with the cog using P0-P2 set these as inputs TouchStart ' start the touchscreen cog PUB Propfont_string(stringptr) 'print at curx,cury repeat strsize(stringptr) Propfont_out(byte[stringptr++]) crlf PUB crlf curx := 0 cury += 32 ' new line at end of string if cury >319 ' bottom of screen so new screen curx:=0 cury:=0 PUB Propfont_out(ascii) | address,pixels Draw(curx,cury,curx+15,cury+31) ' location to start drawing address := $8000 + (ascii >> 1) << 7 ' get rom address repeat 32 ' 32 rows per character, split in two parts pixels := long[address] ' get rom font data pixels := pixels >> (ascii & 1) ' shift for odd characters repeat 16 ' 16 columns if pixels & 1 Pixel(%00000111_11100000) ' foreground color RRRRRGGG_GGGBBBBB else Pixel(%00000000_00000000) ' background color pixels := pixels >> 2 ' alternate pixels interleaved so shift 2 address += 4 curx +=16 if curx >239 ' new line crlf PUB ChangeOrientation(n) ' pass true = portrait or false = landscape, changes global variable orientation in this object ' command $0001 '8.2.4. Driver Output Control (R01h) 'R/W RS D15 D14 D13 D12 D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0 'W 1 0 0 0 0 0 SM 0 SS 0 0 0 0 0 0 0 0 'SS: Select the shift direction of outputs from the source driver. 'When SS = 0, the shift direction of outputs is from S1 to S720 'When SS = 1, the shift direction of outputs is from S720 to S1. 'In addition to the shift direction, the settings for both SS and BGR bits are required to change the 'assignment of R, G, B dots to the source driver pins. 'To assign R, G, B dots to the source driver pins from S1 to S720, set SS = 0. 'To assign R, G, B dots to the source driver pins from S720 to S1, set SS = 1. ' command $0003 'R/W RS D15 D14 D13 D12 D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0 'W 1 TRI DFM 0 BGR 0 0 HWM 0 ORG 0 I/D1 I/D0 AM 0 0 0 ' When AM = 0, the address is updated in horizontal writing direction. 'When AM = 1, the address is updated in vertical writing direction. 'I/D[1:0] Control the address counter (AC) to automatically increase or decrease by 1 when update one pixel ' display data. SelectMemGroup ' 137 and appropriate pins orientation := n '_________Start ILI_______________________ ' if orientation ' ' for origin top left and portrait mode ' ILIcmd($0001,%00000001_00000000) ' $0001,$0100 set SS and SM bit 0001 0100 portrait ' ILIcmd($0003,%00010000_00110000) ' $0003,$1030 set GRAM write direction and BGR=1. $0003 $1030 ' else ' ' for origin top right and landscape mode ' ILIcmd($0001,%00000000_00000000) ' set SS and SM bit 0001 0000 landscape ' ILIcmd($0003,%00010000_00111000) ' landscape $1028 = original but 1038 is correct - not mirror image '________END ILI_____________________ '________Start SSD___________________ if orientation ' for origin top left and portrait mode ILIcmd($0001,$2B3F) ' $0001,$0100 set SS and SM bit 0001 0100 portrait ILIcmd($0011,$6070) '6070 ' $0003,$1030 set GRAM write direction and BGR=1. $0003 $1030 else ' for origin top right and landscape mode ILIcmd($0001,$4B3F) ' set SS and SM bit 0001 0000 landscape ILIcmd($0011,$6838) ' landscape $1028 = original but 1038 is correct - not mirror image '_________END SSD____________________ PUB Start_ILI9325 ' pass orientation true = portrait, false = landscape ILI_Reset_High pause1ms(5) ILI_Reset_Low pause1ms(5) ILI_Reset_High ' returns in group 2, ie CS is high Change137(2) ' replaces ILI_CS high - select another group ILI_RD_High ILI_WR_High pause1ms(5) 'ILI_CS_Low SelectMemGroup ' enables correct pins for output and sets CS low 'IliInit SsdInit PRI SsdInit ILIcmd($0000,$0001) 'Turn Oscillator on POR-$0000 pause1ms(1) ILIcmd($0003,$A8A4) 'Power control (1) POR-$6664 pause1ms(1) ILIcmd($000C,$0000) 'Power control (2) POR- ? pause1ms(1) ILIcmd($000D,$080C) 'Power control (3) POR-$0009 pause1ms(1) ILIcmd($000E,$2B00) 'Power control (4) POR-$3200 pause1ms(1) ILIcmd($001E,$00B0) 'Power control (5) POR-$0029 pause1ms(1) ILIcmd($0001,$4B3F) 'Driver output control, *landscape?? $6B3F* POR-$433F pause1ms(1) ILIcmd($0002,$0600) 'LCD drive AC control POR-$0400 pause1ms(1) ILIcmd($0010,$0000) 'Sleep Mode sleep mode off POR-$0001 pause1ms(1) ILIcmd($0011,$6070) 'Entry Mode, *landscape? $4030* POR-$6830 pause1ms(1) ILIcmd($0005,$0000) 'Compare Register (1) POR-$0000 pause1ms(1) ILIcmd($0006,$0000) 'Compare Register (2) POR-$0000 pause1ms(1) ILIcmd($0016,$EF1C) 'Horizontal Porch POR-$EFC1 pause1ms(1) ILIcmd($0017,$0003) 'Vertical Porch POR-$0003 pause1ms(1) ILIcmd($0007,$0033) 'Display Control POR-$0000 pause1ms(1) ILIcmd($000B,$D308) 'Frame cycle Control POR-$D308 pause1ms(1) ILIcmd($000F,$0000) 'Gate Scan start position POR-$0000 pause1ms(1) ILIcmd($0041,$0000) 'Vertical Scroll Control (1) POR-$0000 pause1ms(1) ILIcmd($0042,$0000) 'Vertical Scroll Control (2) POR-$0000 pause1ms(1) ILIcmd($0048,$0000) 'First Window Start POR-$0000 pause1ms(1) ILIcmd($0049,$013F) 'First Window End POR-$013F pause1ms(1) ILIcmd($004A,$0000) 'Second Window Start POR-$0000 pause1ms(1) ILIcmd($004B,$0000) 'Second Window End POR-$013F pause1ms(1) ILIcmd($0044,$EF00) 'Horizontal Ram Address Postion POR-$EF00 pause1ms(1) ILIcmd($0045,$0000) 'Vertical Ram Address Start POR-$0000 pause1ms(1) ILIcmd($0046,$013F) 'Vertical Ram Address End POR-$013F pause1ms(1) ILIcmd($0023,$0000) 'RAM write data mask (1) POR-$0000 pause1ms(1) ILIcmd($0024,$0000) 'RAM write data mask (2) POR-$0000 pause1ms(1) 'ILIcmd($0025,$8000) 'not in datasheet? ' pause1ms(1) ILIcmd($004f,0) 'RAM Y address counter POR-$0000 pause1ms(1) ILIcmd($004e,0) 'RAM X address counter POR-$0000 pause1ms(1) ChangeOrientation(false) ' default to portrait '----------------SSD1289 END---------------------------------------------------------------------- PUB Draw(x1, y1, x2, y2)|HORIZONTALRAMADDRESSPOS ' sets the pixel to x1,y1 and then fills the next (x2-x1)*(y2-y1) pixels SelectMemGroup ' set 137 to correct value ifnot orientation ' landscape mode so swap x and y result :=x1 ' swap x1 and y1 x1 := y1 y1 := result result := x2 ' swap x2 and y2 x2 :=y2 y2 := result HORIZONTALRAMADDRESSPOS := x1 + (x2 << 8) ILIcmd(REG_HORIZONTALRAMADDRESSPOS,HORIZONTALRAMADDRESSPOS) ILIcmd(REG_VERTICALRAMADDRESSSTART,y1) ILIcmd(REG_VERTICALRAMADDRESSEND,y2) ILIcmd(REG_SETGDDRxADDRESSCOUNTER,x1) ILIcmd(REG_SETGDDRyADDRESSCOUNTER,y1) Lcd_Write_Com($0022) 'ILIcmd($0050,x1) 'ILIcmd($0052,y1) 'ILIcmd($0051,x2) 'ILIcmd($0053,y2) 'ILIcmd($0020,x1) 'ILIcmd($0021,y1) 'Lcd_Write_Com($0022) PUB Pixel(pixelcolor) ' send out a pixel Lcd_Write_Data(pixelcolor) PUB pause1ms(period) '' Pause execution for period (in units of 1 ms). clkcycles := ((clkfreq / _1ms * period) - 4296) #> 381 ' Calculate 1 ms time unit waitcnt(clkcycles + cnt) ' Wait for designated time PUB hex(value, digits) ' uses internal prop font and slow pixel drawing (for very basic debugging without an SD font) SelectMemGroup ' reselect 138 for display output for debugging '' Print a hexadecimal number propfont_out("O") propfont_out("x") value <<= (8 - digits) << 2 repeat digits propfont_out(lookupz((value <-= 4) & $F : "0".."9", "A".."F")) crlf PRI ILIcmd(c,d) ' instruction in one method Lcd_Write_Com(c) ' send out a word Lcd_Write_Data(d) PRI Lcd_Write_Com(ILIlong) ILI_RS_low LCD_Writ_Bus(ILIlong) 'docmd("W",ILIlong,0,0) ' try moving to pasm, leaves spin and cog dira as 0 so need to reset both 'SelectMemGroup ' not working though. Not sure if should be ILIlong or @ILIlong. neither work PRI Lcd_Write_Data(ILIlong) ILI_RS_High LCD_Writ_Bus(ILIlong) PRI LCD_Writ_Bus(ILILong) 'ILILong &= %00000000_00000000_11111111_11111111 ' mask to a word. Not needed if care taken always to send a word value OUTA &= %11111111_11111111_00000000_00000000 ' set P0-P15 to zero ready to OR OUTA |= ILILong ' merge with the word to output ILI_WR_Low ' send out the data ILI_WR_High PRI ILI_RS_Low OUTA &= %11111111_11111011_11111111_11111111 ' P18 low PRI ILI_RS_High OUTA |= %00000000_00000100_00000000_00000000 ' P18 high PRI ILI_WR_Low OUTA &= %11111111_11101111_11111111_11111111 ' p20 low PRI ILI_WR_High OUTA |= %00000000_00010000_00000000_00000000 ' p20 high PRI ILI_RD_High ' not used, set high in hardware 'PRI ILI_CS_Low ' Change137(1) ' change to group 1 ' 'PRI ILI_CS_High ' Change137(0) ' change to group 0 (any group other than 1) PRI ILI_RESET_Low ' reset low Change137(2) ' group 2 DIRA |= %00000000_00000000_00000010_00000000 ' set pin 9 as an output OUTA &= %11111111_11111111_11111101_11111111 ' set pin 9 low PRI ILI_RESET_High Change137(2) ' group 2 DIRA |= %00000000_00000000_00000010_00000000 ' set pin 9 as an output OUTA |= %00000000_00000000_00000010_00000000 ' set pin 9 high DAT sdbuffer byte $0[1024] ' 512 byte buffer for sd card interface and also for sending one row 320 x3 = 960 bytes max picture size buffer2 byte $0[512] ' 512 general purpose hub buffer rambuffer word $0[256] ' 512 byte (256 word) buffer easier for using with words PUB start_ram : err_ ' Initialise the Drac Ram driver. No actual changes to ram as the read/write routines handle this command := "I" cog := 1 + cognew(@tbp2_start, @command) if cog == 0 err_ := $FF ' error = no cog else repeat while command ' driver cog sets =0 when done err_ := errx ' driver cog sets =0 if no error, else xx = error code PUB stop_ram if cog cogstop(cog~ - 1) PUB DoCmd(command_, hub_address, ram_address, block_length) : err_| a,b ' Do the command: A-Z (I is reserved for Initialise) 'dira := 0 ' tristate all pins with the spin dira a := dira ' store the state of these and restore at the end b := outa DIRA &= %11111111_10100000_00000000_00000000 ' tristate all common pins that cog can change so no conflicts hubaddrs := hub_address ' hub address start ramaddrs := ram_address ' ram address start blocklen := block_length ' block length command := command_ ' must be last !! ' Wait for command to complete and get status repeat while command ' driver cog sets =0 when done err_ := errx ' driver cog sets =0 if no error, else xx = error code dira := a ' restore dira and outa outa := b CON '' Modified code from Cluso's triblade '' commands to move blocks of data to the ILI9325 touchscreen display ' DoCmd(command_, hub_address, ram_address, block_length) ' I - initialise ' S - Move data from hub to ram ' T - Move data from ram to hub ' U - Move data from ram to display ' V - Hub to display ' W - not working - writecom in pasm ' E - convert from .raw RGB to two byte ILI format RRRRRGGG_GGG_BBBBB ' F - convert from .bmp BGR format to two byte ILI format ' X - merge icon and background based on a mask ' Y - Change 137 output Returns P0-P20 and P22 in HiZ. Pass hubaddrs ' Z - Set 161 pins. Returns in group 1 VAR ' communication params(5) between cog driver code - only "command" and "errx" are modified by the driver long command, hubaddrs, ramaddrs, blocklen, errx, cog ' rendezvous between spin and assembly (can be used cog to cog) ' command = A to Z etc =0 when operation completed by cog ' hubaddrs = hub address for data buffer ' ramaddrs = ram address for data ' blocklen = ram buffer length for data transfer ' errx = returns =0 (false=good), else <>0 (true & error code) ' cog = cog no of driver (set by spin start routine) DAT '' +-----------------------------------------------------------------------------------------------+ '' | Touchblade 161 Ram Driver (with grateful acknowlegements to Cluso and Average Joe) | '' +-----------------------------------------------------------------------------------------------+ org 0 tbp2_start ' setup the pointers to the hub command interface (saves execution time later ' +-- These instructions are overwritten as variables after start comptr mov comptr, par ' -| hub pointer to command hubptr mov hubptr, par ' | hub pointer to hub address ramptr add hubptr, #4 ' | hub pointer to ram address lenptr mov ramptr, par ' | hub pointer to length errptr add ramptr, #8 ' | hub pointer to error status cmd mov lenptr, par ' | command I/R/W/G/P/Q hubaddr add lenptr, #12 ' | hub address ramaddr mov errptr, par ' | ram address len add errptr, #16 ' | length err nop ' -+ error status returned (=0=false=good) ' Initialise hardware tristates everything and read/write set the pins init mov err, #0 ' reset err=false=good 'mov dira,zero ' tristate the pins with the cog dira and dira,maskP0P20P22 ' tristates all the common pins done wrlong err, errptr ' status =0=false=good, else error x wrlong zero, comptr ' command =0 (done) ' wait for a command (pause short time to reduce power) pause ' mov ctr, delay wz ' if =0 no pause ' if_nz add ctr, cnt ' if_nz waitcnt ctr, #0 ' wait for a short time (reduces power) rdlong cmd, comptr wz ' command ? if_z jmp #pause ' not yet ' decode command cmp cmd, #"S" wz ' hub to ram if_z jmp #pasmhubtoram cmp cmd, #"T" wz ' ram to hub if_z jmp #pasmramtohub cmp cmd, #"U" wz ' ram to display if_z jmp #pasmramtodisplay cmp cmd, #"V" wz ' hub to display if_z jmp #pasmhubtodisplay cmp cmd, #"E" wz ' convert 3 byte .raw format to 2 byte .ili format - hub to hub if_z jmp #rawtoiliformat cmp cmd, #"F" wz ' convert 3 byte .bmp format BGR to 2 byte ili format (same as E but order reversed) if_z jmp #bmptoiliformat ' cmp cmd, #"W" wz ' lcdwritecom in pasm, not working ' if_z jmp #pasmlcdwritecom cmp cmd, #"X" wz ' merge icon and background based on a mask if_z jmp #mergeicons cmp cmd, #"Y" wz ' change the 137 output if_z jmp #changegroup cmp cmd, #"Z" wz ' set the 161 counters if_z jmp #set161 cmp cmd, #"I" wz ' init if_z jmp #init mov err, cmd ' error = cmd (unknown command) jmp #done ' ----------------- common routines ------------------------------------- get_values rdlong hubaddr, hubptr ' get hub address rdlong ramaddr, ramptr ' get ram address rdlong len, lenptr ' get length mov err, #5 ' err=5 get_values_ret ret ' Pass pasm_n = 0- 7 come to this with P0-P20 and P22 tristated and returns them as this too set137 or dira,maskP22 ' pin 22 is an output andn outa,maskP22 ' set P22low so Y0-Y7 are all high or dira,maskP0P20 ' pins P0-P20 are outputs and outa,maskP0P2low ' set these 3 pins low or outa,pasm_n ' set the 137 pins or outa,maskP22 ' pin 22 high set137_ret ret ' return load161pasm ' uses ramaddr or outa,maskP0P20 ' set P0-P20 high or dira,maskP0P20 ' output pins 0-20 mov pasm_n,#0 ' group 0 call #set137 ' set the 137 output and outa,maskP0P18low ' pins 0-18 set low or outa,ramaddr ' output addres to 161 chips or outa,maskP19 ' clock high [code]
    '' ILI9325 driver using the Touchblade161 design for faster ram to display transfers with a hc137 for group select
    '' Average Joe and James Moxham 2012

    ' notes re groupings of pins
    ' To shut down a group, deselect it by making P22 low. This makes Y0-Y7 from the 137 all high
    ' To start a group, the initial state is P0-P20 all HiZ and P22 HiZ (P21 and 23 are audio and there is less audio noise if the pins are not next to each other)
    ' Passing to a cog, P0-P20 and P22 HiZ ie DIRA all as 0 fo these pins. This is to avoid contention between spin and the cog code
    ' A routine in Spin or Pasm that changes the 137 will also return P0-P20 and P22 as HiZ.
    ' In general terms, H is inactive and L is active. So changing a pin from HiZ to H will have no effect as pins all have pullups.
    ' Any handover to cog code must be done in this HiZ state and all pins in a group need to work with this



    CON


    ''LCD REGISTERS
    REG_OSCILLATOR = $0000 ''Oscillator (R00h) (POR = 0000h)
    REG_DRIVEROUTPUTCONTROL = $0001 ''Driver Output Control (R01h) (POR = 2B3Fh)
    REG_LCDDRIVINGWAVFORM = $0002 ''LCD-Driving-Waveform Control (R02h) (POR = 0000h)
    REG_POWERCONTROL1 = $0003 '' (R03H)
    REG_DISPLAYCONTROL = $0007 ''Display Control (R07h) (POR = 0000h)
    REG_FRAMECYCLECONTROL = $000B ''Frame Cycle Control (R0Bh) (POR = 5308h)D308 BY DATASHEET
    REG_POWERCONTROL2 = $000C '' (R0Ch) (POR = 0004)
    REG_POWERCONTROL3 = $000D ''
    REG_POWERCONTROL4 = $000E ''
    REG_GATESCANPOSITION = $000F ''Gate Scan Position (R0Fh) (POR = 0000h)
    REG_SLEEPMODE = $0010 ''Sleep mode (R10h) (POR = 0001h)
    REG_ENTRYMODE = $0011 ''Entry Mode (R11h) (POR = 6830h)
    REG_HPORCH = $0016 '' (R16h) (POR = EF1Ch)
    REG_VPORCH = $0017 '' (R17h) (POR = 0003h)
    REG_POWERCONTROL5 = $001E ''
    REG_RAMDATAWRITE = $0022 ''
    REG_RAMWRITEDATAMASK1 = $0023 '' (R23h) (POR = 0000h)
    REG_RAMWRITEDATAMASK2 = $0024 '' (R24h) (POR = 0000h)
    REG_VERTICALSCROLCONTROL1 = $0041 '' (R41h) (POR = 0000h)
    REG_VERTICALSCROLCONTROL2 = $0042 '' (R42h) (POR = 0000h)
    REG_HORIZONTALRAMADDRESSPOS = $0044 '' (R44h) (POR = EF00h)
    REG_VERTICALRAMADDRESSSTART = $0045 '' (R45h) (POR = 0000h)
    REG_VERTICALRAMADDRESSEND = $0046 '' (R46h) (POR = 013Fh)
    REG_FIRSTWINDOWSTART = $0048 '' (R48h) (POR = 0000h)
    REG_FIRSTWINDOWEND = $0049 '' (R49h) (POR = 013Fh)
    REG_SECONDWINDOWSTART = $004A '' (R4Ah) (POR = 0000h)
    REG_SECONDWINDOWEND = $004B '' (R4Bh) (POR = 013Fh)
    REG_SETGDDRXADDRESSCOUNTER = $004E '' (R4Eh) (POR = 0000h)
    REG_SETGDDRYADDRESSCOUNTER = $004F ''

    _clkmode = xtal1 + pll16x ' use crystal x 16
    _xinfreq = 5_000_000

    _1ms = 1_000_000 / 1_000 ' Divisor for 1 ms

    ' kye sd numbers
    _dopin = 24
    _clkpin = 25
    _dipin = 26
    _cspin = 27
    _cdpin = -1 ' -1 if unused.
    _wppin = -1 ' -1 if unused.
    _rtcres1 = -1 ' -1 always.
    _rtcres2 = -1 ' -1 always.
    _rtcres3 = -1 ' -1 always.
    _statuspin = -1 ' Status LED pin number.

    ' touchscreen pins
    Touch_Clock = 0
    'Touch_ChipSelect = done with a 137 select
    Touch_DataIn = 1
    Touch_DataOut = 2

    ' audio pins
    _leftChannelVolume = 32
    _rightChannelVolume = 32
    _leftChannelAudioPin = 21 ' -1 ifnot installed.
    _rightChannelAudioPin = 23 ' -1 ifnot installed.

    ' general purpose constants
    Margin = 4 ' some characters have xoffset of -1 or -2 eg v, and won't display on the extreme left edge
    ' external ram size of data blocks
    Ram_Fontsize = 65536 ' 128k for fonts (largest is around 108k)
    Ram_MaskSize = (64*64*2)/2 ' 64x64 (59x60) bytes divide by 2 for words
    Ram_IconSize = (64*64*2)/2 ' 2 bytes per pixel converts from .bmp in the routine
    Ram_TextSize = 32768 ' 64k for text

    ' external ram locations, if adding more, follow the pattern
    FontTable = 0 ' address for ram chip (2 bytes per address)
    Mask = FontTable + Ram_Fontsize ' address for raw mask image
    Icon = Mask + Ram_MaskSize ' address for icon image
    Text = Icon + Ram_IconSize ' text buffer for word processing etc
    RamDiskStart = Text + Ram_TextSize ' ramdisk with searchable bitmap files


    OBJ

    'fat: "SD3.01_FATEngine.spin" ' thanks to Kye - sd card
    fat: "SD-MMC_FATEngine.spin" ' Kye's latest sd driver and no RTC
    spi: "SPI_ASM" ' thanks to Beau - spi driver for touch screen
    str: "ASCII0_STREngine.spin" ' thanks to Kye - string routines
    ' term: "FullDuplexSerial.spin" ' Thanks to Chip - for debugging if display not working
    ' synth : "tinysynth" ' ' Thanks Ahle2 http://forums.parallax.com/showthread.php?139724-TinySynth-!
    VAR
    long orientation
    long curx, cury
    long clkcycles ' for the delay routine
    word ScreenWidth ' either 240 in portrait or 320 in landscape
    word ScreenHeight ' 320 in portrait or 240 in landscape
    byte LineOfText1[20] ' general purpose string buffer
    byte LineOfText2[20] ' general purpose string buffer
    byte FontHeight ' size of the current loaded font (pixels = fontsize *.75)
    word BackFontColor ' the background color in RRRRRGGG GGGBBBBB format
    long RamDiskPointer ' pointer to current ramdisk location
    long RamDiskFiles ' number of files in the ramdisk

    'byte sdbuffer[512] ' can't put these here, writes to sdbuffer sometimes back overwrite variables above this eg fontheight!!
    'byte buffer2[512] ' so put these in a dat section
    'word rambuffer[256]
    long DecRate ' synth settings
    long SusLevel
    long PWinit
    long pwmRate
    long Filter
    long Portamento



    ''*****************Start chiptune Player CON here***********************
    CON
    ENABLE_PAL = false

    ''****************Start chiptune Player OBJ here************************
    OBJ
    ' WaveZoom : "WaveZoomer"
    ' OSC : "Oscilloscope"
    SID : "SIDcog"
    AY : "AYcog"
    ' SD : "fsrw"

    ''***************Start chiptune Player VAR here
    VAR
    byte buffer[25]
    byte filename[18]
    byte playing
    byte chipTuneType
    byte prevChipTuneType
    byte ffw
    word playRate
    long wait
    long fileNumber
    long nrOfTunes
    long scrollSpeed
    long frameCounter
    long scrollCounter
    long textPointer
    long AY_register


    PUB Main | i, oldStatus, fin,yval, xval
    start_ram ' start the external ram / display driver in a cog
    Change161(0) ' reset all the 161 counters to zero
    SelectMemGroup ' select group1
    Start_ILI9325 ' start the display. Don't clear screen as this uses ram commands and these might not be working yet
    SetOrientation(true) ' in portrait (true) or landscape mode (false), must be before clearscreen otherwise don't know screensize
    'pause1ms(5000)

    Clearscreen(RGBtoWord(0,0,0)) ' clear screen to black - uses the display driver above
    propfont_string(String("Mount SD"))
    fat.fatEngineStart( _dopin, _clkpin, _dipin, _cspin, _wppin, _cdpin, _rtcres1, _rtcres2, _rtcres3)
    fat.mountPartition(0) ' mount the sd card
    propfont_string(String("Mounted"))
    ClearRamdisk ' clear ram disk for pictures not on the desktop
    ''*Note* Load fonts and bmp's here!



    LoadBMPtoRamdisk(string("Trans.bmp"))

    sid.start(_rightChannelAudioPin, _leftChannelAudioPin)
    propfont_out(".")
    crlf

    getNrOfTunes

    'pause1ms(5000)

    Clearscreen(RGBtoWord(0,0,0)) ' clear screen to black - uses the display driver above
    curx := 0
    cury := 0

    propfont_string(@message4)
    'propfont_out("!")

    frameCounter := 0
    fileNumber := 0
    chipTuneType := 1
    playRate := 50
    scrollSpeed := 2
    playing := false
    ffw := false
    wait := cnt

    DrawBMP(string("Trans.bmp"),0,280)
    openNextFile

    'Main loop
    repeat
    ' Wait between register updates
    if (cnt - wait) > 0
    if ffw
    wait := cnt + (clkfreq/(playRate<<2))
    else
    wait := cnt + (clkfreq/playRate)
    ' Update the PSG
    if playing
    case chipTuneType
    1: updateSID
    2: updateAY

    ' Check for a change in tv status
    ' if oldStatus <> tv_status
    ' oldStatus := tv_status

    ' ' Check for vbl
    ' if tv_status == 2
    ' scroll
    '
    ' ' Handle user interactions
    ' if input.getLastState <> input.getCurrentState

    SelectSPIGroup
    yval := TouchYPercent ' decode yval 0-100%
    xval := TouchXPercent ' decode xval 0-100%
    if (xval <> 255) and (yval <> 255)
    'SelectMemGroup
    'hex(xval,2) ' if display any debug messages need to restart the SPI cog as it has been stopped by the debug display
    'hex(yval,2)
    if (yval > 89)
    SelectMemGroup
    ' Handle previous tune
    if (xval < 19)
    handleMuting
    if fileNumber == 0
    fileNumber := nrOfTunes + 1
    fileNumber--
    openNextFile

    ' Handle pausing
    if (xval > 37 and xval < 70)
    playing := not playing
    handleMuting
    ifnot playing
    setScrollMessage(@message2)
    else
    ffw := false
    setScrollMessage(@songName)

    ' Handle next tune
    if (xval > 79 and xval < 99)
    handleMuting
    if fileNumber == nrOfTunes
    fileNumber := -1
    fileNumber++
    openNextFile



    ' ' Handle pausing
    ' if input.getLastState&input#START
    ' playing := not playing
    ' handleMuting
    '
    ' ifnot playing
    ' setScrollMessage(@message2 - @message)
    '
    ' else
    ' ffw := false
    ' setScrollMessage(@songName - @message)
    '
    ' scrollSpeed := 8
    '
    ' ' Handle fast forward
    ' if playing > 0 and input.getLastState&input#A
    ' ffw := not ffw
    '
    ' if ffw
    ' setScrollMessage(@message3 - @message)
    '
    ' else
    ' setScrollMessage(@songName - @message)
    '
    ' scrollSpeed := 8
    '
    ' ' Handle next tune
    ' if input.getLastState&input#RIGHT
    ' if fileNumber == nrOfTunes
    ' fileNumber := -1
    '
    ' fileNumber++
    ' openNextFile
    '
    ' ' Handle previous tune
    ' if input.getLastState&input#LEFT
    ' if fileNumber == 0
    ' fileNumber := nrOfTunes + 1
    '
    ' fileNumber--
    ' openNextFile
    '
    ' ' Handle next page ( += 10 )
    ' if input.getLastState&input#DOWN
    ' fileNumber += 10
    '
    ' if fileNumber > nrOfTunes
    ' fileNumber := 0
    '
    ' openNextFile
    '
    ' ' Handle previous page ( -= 10 )
    ' if input.getLastState&input#UP
    ' fileNumber -= 10
    '
    ' if fileNumber < 0
    ' fileNumber := nrOfTunes
    '
    ' openNextFile

    PRI openNextFile | i, t, nameP
    ffw := false
    playing := true
    ' Iterate through files and find the file with fileNumber == X
    fat.closeFile

    repeat i from 0 to fileNumber
    fat.listEntries("N")
    nameP := fat.listname
    t:=0
    repeat until byte [nameP][t] == 0
    byte [@filename][t]:= byte[nameP][t]
    t++
    byte[@filename][t] := 0

    ' Find out what kind of file type we are dealing with
    prevChipTuneType := chipTuneType
    chipTuneType := 0

    fat.openFile(@filename, "R")

    if fat.readData(@buffer, 4) < 0

    if byte[nameP - 3] == "D" and byte[nameP - 2] == "M" and byte[nameP - 1] == "P"
    chipTuneType := 1

    if buffer[0] == "S" and buffer[1] == "D" and buffer[2] == "M" and buffer[3] == "P" ' SDMP
    chipTuneType := 1

    elseif buffer[0] == "Y" and buffer[1] == "M" and buffer[2] == "6" and buffer[3] == "!" ' YM6!
    chipTuneType := 2

    else
    fat.closeFile
    AY.stop
    SID.stop
    setScrollMessage(@message1)
    return

    ' Set some standard values in case the header doesn't provide any info
    playRate := 50
    bytefill(@songName + 10, 32, 15)
    intToString(@songName + 6, fileNumber, 5)

    repeat i from 0 to 15
    if filename
    byte[@songName + i + 10] := filename

    else
    i := 16

    ' Init everything, read the header and start the PSG
    fat.openFile(@filename, "R")

    if chipTuneType == 1
    readHeaderSID
    initSID

    elseif chipTuneType == 2
    readHeaderAY
    initAY

    wait := cnt + 20_000_000

    PRI handleMuting
    case chipTuneType
    1:
    if playing
    SID.unmute

    else
    SID.mute

    2:
    if playing
    AY.unmute

    else
    AY.mute

    PRI initSID | registers

    if prevChipTuneType == 2
    AY.stop

    elseif prevChipTuneType == 1
    SID.stop

    registers := SID.start( _rightChannelAudioPin, _leftChannelAudioPin )
    SID.resetRegisters
    ' OSC.stop
    ' OSC.start( display_base, registers + 28, @tv_status, @scrollSpeed )
    chipTuneType := 1
    ' setSIDColor

    PRI initAY | registers

    if prevChipTuneType == 2
    AY.stop

    elseif prevChipTuneType == 1
    SID.stop

    registers := AY.start(_rightChannelAudioPin, _leftChannelAudioPin, AY_register)
    AY.resetRegisters
    ' OSC.stop
    ' OSC.start( display_base, registers + 16, @tv_status, @scrollSpeed )
    chipTuneType := 2
    ' setAYColor

    PRI updateSID
    if( fat.readData(@buffer, 25) ) < 0
    fileNumber++
    openNextFile

    SID.updateRegisters(@buffer)

    PRI updateAY
    if( fat.readData(@buffer, 16) ) < 0
    fileNumber++
    openNextFile

    AY.updateRegisters(@buffer)

    PRI readHeaderSID | i, t
    if( fat.readData(@buffer, 25) ) => 0

    if buffer[0] == "S" and buffer[1] == "D" and buffer[2] == "M" and buffer[3] == "P"
    playRate := buffer[4] | (buffer[5]<<8)

    repeat i from 0 to 15
    t := buffer[ i + 8 ]

    if t
    byte[ @songName + i + 10 ] := t

    else
    byte[ @songName + i + 10 ] := 32

    PRI readHeaderAY | extra, digiDrums, i, t

    if( fat.readData(@buffer, 12)) => 0 ' 00 - read "YM6!" header ' 04 - read "LeOnArD!" identifier
    if( fat.readData(@buffer, 4) ) => 0 ' 0c - number of VBL frames (play rate)
    if( fat.readData(@buffer, 4) ) => 0 ' 10 - attributes
    if( fat.readData(@buffer, 2) ) => 0 ' 14 - number of digi drum samples
    digiDrums := buffer[0] | (buffer[1]<<8)

    if( fat.readData(@buffer, 4) ) => 0 ' 16 - YM2149 external frequency in Hz
    AY_register := buffer[3] | (buffer[2]<<8) | (buffer[1] << 16) | (buffer[0] << 24)

    if( fat.readData(@buffer, 2) ) => 0 ' 1a - player frequency in Hz
    playRate := buffer[1] | (buffer[0]<<8)

    if( fat.readData(@buffer, 4) ) => 0 ' 1c - frame where looping starts

    if( fat.readData(@buffer, 2) ) => 0 ' 20 - extra bytes following (should be 0)
    extra := buffer[0] | (buffer[1]<<8)

    bytefill(@buffer, 32, 15)

    if get_string ' read song name
    repeat i from 0 to 14
    t := buffer

    if t
    byte[ @songName + i + 10 ] := t

    else
    byte[ @songName + i + 10 ] := 32

    get_string ' read author name
    get_string ' read comments / software

    PRI get_string | n, t

    repeat n from 0 to 127
    if (t := fat.readByte ) =< 0
    return n
    else
    if n < 25
    buffer[n] := t

    var byte firstFile[18]

    PRI getNrOfTunes | t,i
    nrOfTunes := -1
    fat.closefile
    propfont_string(fat.changeDirectory(string("tunes")))

    repeat until strcomp(@Dir2, t)
    fat.listEntries("N")
    t := fat.listname
    'propfont_String(t)

    fat.listEntries("N")
    t := fat.listname
    'propfont_String(t)
    i := 0

    repeat until byte[t] == 0
    firstFile := byte[t]
    ' propfont_out(".")
    i++
    crlf
    'propfont_string(string("FirstFile"))
    'propfont_string(@firstFile)

    t:= -1
    repeat until strcomp(@firstFile, t)
    fat.listEntries("N")
    t := fat.listname
    ' propfont_String(t)
    nrOfTunes++
    if nrOfTunes < 1
    nrOfTunes -= 2

    'hex(nrOfTunes,2)
    'pause1ms(5000)
    PRI intToString( position, value, digits ) | i
    digits += position

    if value < 0
    -value
    byte[position++] := "-"

    i := 1_000_000_000

    repeat 10
    if value => i
    byte[position++] := value / i + "0"
    value //= i
    result~~

    elseif result or i == 1
    byte[position++] := "0"

    i /= 10

    repeat while position < digits
    byte[position++] := " "


    PUB SetScrollMessage(x)
    curx :=0
    cury :=127

    propfont_string(x)

    dat
    message
    byte " "
    songName
    byte 32, 32, 32, 32, 32, "#", 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 0

    message1
    byte " Invalid file ", 0

    message2
    byte "‣‣ Paused", 0

    message3
    byte " ▶▶ Fast forward ", 0

    message4
    byte "Propeller chip-tune player by Johannes Ahlebrand Select a tune ", 0

    'zero long $80000000 T
    Dir2
    byte ".. ",0

    PUB FixGlitch
    ILIcmd($0000,$0001) 'Turn Oscillator on POR-$0000
    ' pause1ms(1)
    ' ILIcmd($0003,$A8A4) 'Power control (1) POR-$6664
    ' pause1ms(1)
    ' ILIcmd($000C,$0000) 'Power control (2) POR- ?
    ' pause1ms(1)
    ' ILIcmd($000D,$080C) 'Power control (3) POR-$0009
    ' pause1ms(1)
    ' ILIcmd($000E,$2B00) 'Power control (4) POR-$3200
    ' pause1ms(1)
    ' ILIcmd($001E,$00B0) 'Power control (5) POR-$0029
    ' pause1ms(1)
    ILIcmd($0001,$6B3F) 'Driver output control, *landscape?? $6B3F* From code??2B3F? POR-$433F
    ' pause1ms(1)
    ILIcmd($0002,$0600) 'LCD drive AC control POR-$0400
    ' pause1ms(1)
    ILIcmd($0010,$0000) 'Sleep Mode sleep mode off POR-$0001
    ' pause1ms(1)
    ILIcmd($0011,$6070) 'Entry Mode, *landscape? $4030* POR-$6830
    ' pause1ms(1)
    ILIcmd($0007,$0033) 'Display Control POR-$0000 ''Used 0033
    ' pause1ms(1)
    ILIcmd($0023,$0000) 'RAM write data mask (1) POR-$0000
    ' pause1ms(1)
    ILIcmd($0024,$0000) 'RAM write data mask (2) POR-$0000
    ' pause1ms(1)
    ChangeOrientation(orientation)
    PUB Deadend
    repeat
    waitcnt(cnt)


    ' *********************************** Driver Routines *******************************

    PUB OpenFileRead(stringptr) ' open a file for reading and display a message if it fails
    result := \fat.openfile(stringptr,"R")
    if fat.partitionerror <> 0 ' failed to find the file
    propfont_string(stringptr) ' print the filename
    propfont_string(result) ' print the error message
    repeat ' stop the program

    PRI TouchValue | xval,yval,x,y ' returns % values 0-100% (or 255 for no touch)
    xval := TouchX
    yval := TouchY
    if (xval => 500) and (yval =< 3800) ' both have to be valid for a touch
    pause1ms(2) ' tiny delay then read again as the first reads may not have the correct value
    xval := TouchX
    yval := TouchY
    if (xval => 500) and (yval =< 3800) ' and if valid again, now more likely this value is correct
    x := xval - 440 ' scale 0-3360
    x /= 32 ' scale 0-100
    x <#= 100 ' max 100
    x #>=0 ' min 0
    x := 100 - x ' so left edge on left
    y := yval -420 ' scale 0-3180
    y /= 32 ' scale 0-100
    y <#= 100 ' max 100
    y #>=0 ' min 0
    y := 100-y ' so 0 is top left
    result := (y <<8) | x ' return 00000000_00000000_YYYYYYYY_XXXXXXXX
    if (xval < 500) or (xval >3800)
    result := $0000FFFF ' invalid number(s)

    PUB TouchXPercent
    result := 100 - (TouchValue & 255) ' decode xval 0-100%

    PUB TouchYPercent
    result := TouchValue >> 8 ' decode yval 0-100%

    PUB TouchSwish | xval,oldxval,difference,average ' returns result = +ve or -ve depending on swish direction ' did finger move left or right?
    SelectSPIGroup ' turn on the spi touchscreen
    oldxval := 255' for startup
    average := 0
    repeat until (average > 30) or (average < -30)
    ' possibly add a decay function here for average
    pause1ms(50)
    xval := TouchXPercent ' decode xval 0-100%
    if xval == 255 ' not touched
    oldxval := 255 ' reset oldxval as well
    else
    if oldxval <>255 ' discard the first reading as the screen is touched
    difference := xval - oldxval
    'printdecimal(xval)
    'printdecimal(difference)
    average := average + difference '
    'printdecimal(average)
    'crlf
    oldxval := xval ' store for next time
    result := average ' return negative or positive value

    PUB TouchStart
    SPI.start(3,0) ' delay,state, start clock high

    PRI TouchX
    SPI.SHIFTOUT(Touch_DataIn, Touch_Clock, 5, 8 , %1101_0000) ' reads x from 500 to 3700 (off < 500 )
    result := SPI.SHIFTIN(Touch_DataOut,Touch_Clock,2, 12)

    PRI TouchY
    SPI.SHIFTOUT(Touch_DataIn, Touch_Clock, 5, 8 , %1001_0000) ' reads y from 400 to 3800 (off > 3800 )
    result := SPI.SHIFTIN(Touch_DataOut,Touch_Clock,2, 12)


    PUB SDToDisplay(stringptr) ' bitmap from SD to display
    Clearscreen(0)
    ClearRamDiskExcludeDesktop
    LoadBMPtoRamdisk(stringptr)
    DrawBMP(stringptr,0,0)

    PUB FindBMP(stringptr) | i,rampointer,ramcounter,match,searchlen,width,height ' pass the name and the x and y location, searches for this file and if found, displays it
    rampointer := RamDiskStart
    searchlen := str.instr(stringptr,".") - 1 ' ignore the .bmp extension
    repeat ramcounter from 1 to ramdiskfiles
    docmd("T",@sdbuffer,rampointer,$36) ' get hex $36 bytes from the ramdisk = filenames
    width := sdbuffer[$12] + sdbuffer[$13] << 8 ' only read in two bytes as never will be >64k wide or high
    height := sdbuffer[$16] + sdbuffer[$17] << 8
    match := true
    repeat i from 0 to searchlen - 1
    if sdbuffer <> byte[stringptr]
    match := false ' any characters not matching, try next one. (case must match too)
    if match == true
    quit ' found a match so quit looking for any more files
    ' get the next rampointer = $36 + width * height
    rampointer += $36 + (width * height)
    if match == true ' if found a match return the rampointer
    result := rampointer
    else
    result := -1 ' no match so zero

    PUB ClearRamdisk
    ILISetcursor(0,0) ' cursor for debugging to 0,0
    RamDiskPointer := RamDiskStart ' set the global ramdisk pointer start
    RamDiskFiles := 0

    PUB ClearRamdiskExcludeDesktop ' exclude the desktop which is the first 76800+36 pixels and also sets ramdiskfiles to 1, not 0
    ClearRamdisk
    RamDiskPointer += $36 + (240 * 320) ' leave room for the desktop
    RamDiskFiles +=1 ' file counter +1

    PUB DrawBMP(stringptr,x,y) | rampointer,width,height ' pass the name and the x and y location, searches for this file and if found, displays it
    rampointer := FindBMP(stringptr) ' find the file in the list
    if rampointer <> -1 ' if a match then draw
    width := sdbuffer[$12] + sdbuffer[$13] << 8 ' only read in two bytes as never will be >64k wide or high
    height := sdbuffer[$16] + sdbuffer[$17] << 8
    Draw(x,y,x+width-1,y+height-1) ' set up the area to draw
    RamToDisplay(RamPointer + $36,width*height) ' skip the header and display
    result := (width <<16) | (height & $0000FFFF) ' return the width and height combined into a long

    PUB TextBoxClear(x1,y1,x2,y2) ' draw the outline of the box
    ClearRectangle(x1,y1,x2,y2,RGBtoWord(255,255,255))
    Drawline(x1-1,y1-1,x2,y1-1,RGBtoWord(64,64,64)) ' gray outline lines - extract values from paint shop pro
    Drawline(x1-2,y1-2,x2+1,y1-2,RGBtoWord(128,128,128)) ' horizontal upper light gray
    Drawline(x1-1,y1-1,x1-1,y2,RGBtoWord(64,64,64)) ' vertical left gray
    Drawline(x1-2,y1-2,x1-2,y2+1,RGBtoWord(128,128,128)) ' vertical left light gray
    Drawline(x2+2,y1-2,x2+2,y2+2,RGBtoWord(255,255,255)) ' vertical right white
    Drawline(x1-2,y2+2,x2+2,y2+2,RGBtoWord(255,255,255)) ' horizontal lower white

    PUB LoadBMPtoRamdisk(stringptr) | width,height,w,i ' load and display a bitmap file
    ' http://en.wikipedia.org/wiki/BMP_file_format scroll down about 1/3 of the way for the header formats
    ' get the width, height
    ' store these as 2 longs at the beginning of the ram file
    ' the bitmap format starts at the last row and works up so need to reverse the order
    ' on the ram store a 0x36 byte header - the bitmap header but put in the filename at location 0
    ' this becomes a rudimentary file system that can be searched to find pictures
    'propfont_out("1") ' for debugging display something while load in pictures
    ' pause1ms(Debugtimer)
    fat.openfile(stringptr,"R")
    OpenFileRead(stringptr)
    fat.readdata(@sdbuffer,$36) ' get the header 0x36 hex bytes
    width := sdbuffer[$12] + sdbuffer[$13] << 8 ' only read in two bytes as never will be >64k wide or high
    height := sdbuffer[$16] + sdbuffer[$17] << 8
    w := width * 3 ' this number of bytes per row, and round up to nearest 4 bytes et 327 goes to 328 The size of each row is rounded up to a multiple of 4 bytes (a 32-bit DWORD) by padding.
    w +=3 ' add 3 and
    w &= %11111111_11111111_11111111_11111100 ' round down
    repeat i from 0 to 11 ' add the file name at the beginning of the header
    sdbuffer := byte[stringptr]
    docmd("S",@sdbuffer,RamDiskPointer,$36) ' store header to ram
    i := $36 + RamDiskPointer + ((height - 1) * width) ' start + header and on the last row and work back
    repeat height
    fat.readdata(@sdbuffer,w) ' read in the first row
    docmd("F",@sdbuffer,@rambuffer,width)
    HubToRam(i,width) ' send to ram
    i -= width ' subtract the width, move up the picture
    FixGlitch
    fat.closefile
    RamDiskPointer += $36 + (width * height) ' increment the ramdiskpointer for next picture
    RamDiskFiles += 1 ' increment number of entries in the ram disk
    FixGlitch
    PUB DrawCheckbox(x,y,Checked,Stringptr) | i ' draw a checkbox
    if checked
    DrawBMP(string("Checked.bmp"),x,y)
    else
    DrawBMP(string("Uncheckd.bmp"),x,y)
    curx := x+20 ' add 20 width
    cury := y
    ILIPrintString(stringptr)

    PUB DrawRadioBox(x,y,Checked,Stringptr)| i ' draw a radio box
    if checked
    DrawBMP(string("RadioChk.bmp"),x,y)
    else
    DrawBMP(string("RadioUnc.bmp"),x,y)
    curx := x+20 ' add 20 width
    cury := y
    ILIPrintString(stringptr)

    PUB DrawButton(x,y,Stringptr) ' draw a radio box
    DrawBMP(string("butn8430.bmp"),x,y)
    curx := x + (84/2)-(str.len(stringptr)*4 / 2) ' centre, avg width 4 per char 84 could be a variable width passed to this routine
    cury := y + 8
    ILIPrintString(stringptr)


    PUB LoadFile(strpointer) | filesize,i ' reads a text file into external ram
    OpenFileRead(strpointer) ' open a file
    filesize := fat.filesize
    i := Text ' store text here
    repeat (filesize >>8 ) + 1 ' so works with 256 byte blocks
    fat.readdata(@sdbuffer,256) ' get 256 bytes from sd card
    docmd("S",@sdbuffer,i,128) ' send 128 words to external ram
    i +=128 ' increment counter
    fat.closefile
    return filesize

    PUB NewFont(strpointer)
    ILIloadfont(strpointer)
    ' only call this routine with the cursor curx at zero
    ClearRectangle(curx,cury,screenwidth,cury+FontHeight,BackFontColor) ' clear an area the same color as the font background

    PUB ILIChar(ascii,x,y) | jump,size,width,height,ramaddress,xoffset,yoffset,xadvance ' read out a character from a .ifn file stored in ram
    ' pass Fonttable = global
    ' moves to next line if off the end
    jump := ReadRamLong(fonttable,(ascii << 2) + 256) ' jump location = ascii *4 plus fonttable + 256
    docmd("T",@buffer2,fonttable+jump>>1,20) ' read in the width height as a block = quicker than readramlong
    size := long[@buffer2][0] ' size in pixels of this character
    xadvance := long[@buffer2][5] ' amount to move to next character
    'if size > 0 and ascii <> 32 ' no need to print anything if size is zero or read more font data
    width := long[@buffer2][1] ' width
    height := long[@buffer2][2] ' height
    xoffset := long[@buffer2][3] ' xoffset to move
    yoffset := long[@buffer2][4] ' yoffset to move
    if (x+width -1 + xoffset) > screenwidth
    ILIcrlf ' do a new line if it won't fit
    x := curx
    y := cury
    if ascii < 32
    xadvance := 0 ' add nothing if a non displaying character
    if ascii == 13 ' carriage return
    ILIcr
    x := curx
    if ascii ==10 ' line feed (new line)
    ILIlf
    y := cury
    if ascii > 32 ' space not displayed
    Draw(x+xoffset,y+yoffset,x+width-1+xoffset,y+height-1+yoffset) ' draw on screen
    RamToDisplay(fonttable+((jump+32)>>1),size) ' move bytes from ram out to the display
    return x + xadvance

    PUB ILIcrlf
    ILIcr
    ILIlf

    PUB ILIcr ' carriage return, to left margin
    curx := Margin ' some characters are -1 xoffset so won't display

    PUB ILIlf ' line feed, move up one
    cury += FontHeight
    if cury > screenheight
    ClearRectangle(0,0,screenwidth,screenheight,BackFontColor)
    cury := 0 ' if off the bottom of the screen then clear screen start at the top (VT00 does scrolling)
    ' don't clear background here, do in calling routine
    'ClearFontBackground(0,cury,screenwidth,cury + FontHeight) ' clear background line to the background color ready to draw


    PUB ILIPrintstring(stringptr) 'print at curx,cury
    '' Print a zero-terminated string
    repeat strsize(stringptr)
    curx := ILIChar(byte[stringptr++],curx,cury)


    PUB ILISetCursor(x,y)
    curx := x
    cury := y


    PUB ReadRamLong(WordStart,Bytevalue) ' easier calculating
    docmd("T",@result,Wordstart+Bytevalue>>1,2)
    return result


    PUB ILILoadFont(stringptr) | filesize,i ' read a .ifn file premade in angelcode bmfont and then the vb.net program
    ' ' pass file name in stringptr
    i := fonttable ' store at the constant 'fonttable' location, 2 bytes per address
    OpenFileRead(stringptr) ' open an image. Size is in the first long and has been rounded up to the next 256 byte block
    filesize := fat.filesize ' read the file size. This file has been rounded up to the next 256 byte block
    repeat (filesize >> 8) ' read in this number of 256 byte blocks
    fat.readdata(@rambuffer,256) ' get 256 bytes from sd card
    HubToRam(i,128) ' 128 words = 256 bytes
    i += 128 ' counter for ram location
    fat.closefile
    docmd("T",@rambuffer,FontTable,128) ' read first 128 words =256 bytes back
    FontHeight := byte[@rambuffer][251] ' font height
    'hex(fontheight,8)
    repeat i from 0 to 2
    sdbuffer := byte[@rambuffer][35+i]
    docmd("E",@sdbuffer,@buffer2,1) ' convert to 2 byte .ili format
    BackFontColor := ( byte[@buffer2][1] << 8) | byte[@buffer2][0] ' correct order
    'hex(backfontcolor,4)
    result := filesize

    PUB MergeBackgroundIcon(stringptr,x,y) | i,j,k,n ' merge icon and background - if mask =0 then background, else icon (not classic alpha compositing but close enough)
    ' i is background counter, j is icon counter, k = mask counter
    LoadBMPtoRamdisk(stringptr) ' load icon into ram
    i := RamDiskStart + $36 + (y*(screenwidth+1)+x) ' location of picture pixel in ram
    j := FindBMP(stringptr) + $36 ' location of icon in ram
    k := FindBMP(string("mask.bmp")) + $36 ' location of mask
    repeat 60
    docmd("T",@sdbuffer,i,59) ' get 59 pixels from background
    docmd("T",@rambuffer,j,59) ' get 59 icon pixels
    docmd("T",@buffer2,k,59) ' get words for the mask
    'repeat n from 0 to 58
    ' if (word[@buffer2][n] & %00000000_00011111) > %10000 ' RGB are the same, so use BBBBB, mask 5 low bits, and if > %10000
    ' word[@sdbuffer][n] :=word[@rambuffer][n] ' if >128 then replace with icon pixel
    docmd("X",@sdbuffer,@rambuffer,@buffer2) ' pasm version of the above 3 lines
    docmd("S",@sdbuffer,i,59) ' send back modified line to the picture buffer
    i += screenwidth+1 ' next line in picture
    j +=59 ' icon next line
    k +=59 ' next line in mask (bytes) - buffer2
    FixGlitch
    PUB HubToRam(RamAddress,Number) ' send pixels from rambuffer hub to ram
    docmd("S",@rambuffer,RamAddress,Number)

    PUB RamToHub(RamAddress,Number) ' send pixels from ram to hub at rambuffer
    docmd("T",@rambuffer,RamAddress,Number)

    PUB RamToDisplay(RamAddress,Number) ' send pixels from ram to display
    docmd("U",0,RamAddress,Number)

    PUB HubToDisplay(HubAddress,Number) ' send pixels from hub to display
    docmd("V",HubAddress,0,Number)

    PUB Change137(group)
    docmd("Y",group,0,0) ' change the current group

    PUB Change161(RamAddress) ' pass ramaddress. Returns in group 1
    docmd("Z",0,RamAddress,0)


    PUB Clearscreen(color) ' uses 2 byte ILI color (see below for rgb conversion)
    wordfill(@rambuffer,color,256)
    Draw(0,0,screenwidth,screenheight) ' set up the area of the screen to draw in
    repeat 300
    HubToDisplay(@rambuffer,256)

    PUB RGBtoWord(R,G,B) ' convert RGB to 2 byte ILI color
    sdbuffer[0] := R
    sdbuffer[1] := G
    sdbuffer[2] := B
    docmd("E",@sdbuffer,@buffer2,1)
    result := ( byte[@buffer2][1] << 8) | byte[@buffer2][0] ' correct order

    PUB ClearRectangle(x1,y1,x2,y2,ColorWord) | i,size,remainder ' clears an area of the screen to the current font background color
    size := (x2-x1+1) * (y2 - y1 +1) ' number of pixels
    remainder := size & 255 ' if not a whole number of 256 pixels
    repeat i from 0 to 255 ' move the background font colour to the buffer
    rambuffer := ColorWord
    Draw(x1,y1,x2,y2) ' set up the area of the screen to draw in
    repeat size >> 8 ' 256 pixel blocks
    docmd("V",@rambuffer,0,256)
    if remainder <> 0
    docmd("V",@rambuffer,0,remainder) ' do the remainder

    PUB Drawline(x1,y1,x2,y2,ColorWord) ' draws a vertical or horizontal line
    ClearRectangle(x1,y1,x2,y2,ColorWord) ' same as drawing a rectangle

    PUB SetOrientation(e) ' change orientation true = portrait. Changes global variable 'orientation' and also screen width and height
    orientation := e
    ChangeOrientation(orientation)
    if orientation
    screenwidth :=239
    screenheight :=319
    else
    screenwidth :=319
    screenheight :=239



    PUB SelectMemGroup ' select group 2 for memory transfer
    spi.stop ' and stop any other cogs here too if needed

    OUTA |= %00000000_00011111_11111111_11111111 ' set P0-P20 high
    DIRA |= %00000000_00011111_11111111_11111111 ' set P0-P20 as outputs
    Change137(1)
    OUTA |= %00000000_00011111_00000000_00000000 ' set P16-P20 high
    DIRA |= %00000000_00011111_11111111_11111111 ' set P0-P20 as outputs

    PUB SelectSPIGroup ' select group 0 for the SPI
    'SsdInit

    OUTA |= %00000000_00000000_00000010_00000000 ' keep p9 high so doesn't reset
    DIRA |= %00000000_00000000_00000010_00000000 ' P0-P2 are used to load the 137
    Change137(2)
    OUTA |= %00000000_00000000_00000010_00000000 ' keep p9 high so doesn't reset
    DIRA |= %00000000_00000000_00000010_00000000 ' enable these pins for output
    DIRA &= %11111111_11111111_11111111_11111000 ' so no clashes with the cog using P0-P2 set these as inputs
    TouchStart ' start the touchscreen cog

    PUB Propfont_string(stringptr) 'print at curx,cury
    repeat strsize(stringptr)
    Propfont_out(byte[stringptr++])
    crlf

    PUB crlf
    curx := 0
    cury += 32 ' new line at end of string
    if cury >319 ' bottom of screen so new screen
    curx:=0
    cury:=0

    PUB Propfont_out(ascii) | address,pixels
    Draw(curx,cury,curx+15,cury+31) ' location to start drawing
    address := $8000 + (ascii >> 1) << 7 ' get rom address
    repeat 32 ' 32 rows per character, split in two parts
    pixels := long[address] ' get rom font data
    pixels := pixels >> (ascii & 1) ' shift for odd characters
    repeat 16 ' 16 columns
    if pixels & 1
    Pixel(%00000111_11100000) ' foreground color RRRRRGGG_GGGBBBBB
    else
    Pixel(%00000000_00000000) ' background color
    pixels := pixels >> 2 ' alternate pixels interleaved so shift 2
    address += 4
    curx +=16
    if curx >239 ' new line
    crlf


    PUB ChangeOrientation(n) ' pass true = portrait or false = landscape, changes global variable orientation in this object
    ' command $0001
    '8.2.4. Driver Output Control (R01h)
    'R/W RS D15 D14 D13 D12 D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0
    'W 1 0 0 0 0 0 SM 0 SS 0 0 0 0 0 0 0 0
    'SS: Select the shift direction of outputs from the source driver.
    'When SS = 0, the shift direction of outputs is from S1 to S720
    'When SS = 1, the shift direction of outputs is from S720 to S1.
    'In addition to the shift direction, the settings for both SS and BGR bits are required to change the
    'assignment of R, G, B dots to the source driver pins.
    'To assign R, G, B dots to the source driver pins from S1 to S720, set SS = 0.
    'To assign R, G, B dots to the source driver pins from S720 to S1, set SS = 1.

    ' command $0003
    'R/W RS D15 D14 D13 D12 D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0
    'W 1 TRI DFM 0 BGR 0 0 HWM 0 ORG 0 I/D1 I/D0 AM 0 0 0
    ' When AM = 0, the address is updated in horizontal writing direction.
    'When AM = 1, the address is updated in vertical writing direction.
    'I/D[1:0] Control the address counter (AC) to automatically increase or decrease by 1 when update one pixel
    ' display data.
    SelectMemGroup ' 137 and appropriate pins
    orientation := n
    '_________Start ILI_______________________
    ' if orientation
    ' ' for origin top left and portrait mode
    ' ILIcmd($0001,%00000001_00000000) ' $0001,$0100 set SS and SM bit 0001 0100 portrait
    ' ILIcmd($0003,%00010000_00110000) ' $0003,$1030 set GRAM write direction and BGR=1. $0003 $1030
    ' else
    ' ' for origin top right and landscape mode
    ' ILIcmd($0001,%00000000_00000000) ' set SS and SM bit 0001 0000 landscape
    ' ILIcmd($0003,%00010000_00111000) ' landscape $1028 = original but 1038 is correct - not mirror image
    '________END ILI_____________________
    '________Start SSD___________________

    if orientation
    ' for origin top left and portrait mode
    ILIcmd($0001,$2B3F) ' $0001,$0100 set SS and SM bit 0001 0100 portrait
    ILIcmd($0011,$6070) '6070 ' $0003,$1030 set GRAM write direction and BGR=1. $0003 $1030
    else
    ' for origin top right and landscape mode
    ILIcmd($0001,$4B3F) ' set SS and SM bit 0001 0000 landscape
    ILIcmd($0011,$6838) ' landscape $1028 = original but 1038 is correct - not mirror image

    '_________END SSD____________________

    PUB Start_ILI9325 ' pass orientation true = portrait, false = landscape
    ILI_Reset_High
    pause1ms(5)
    ILI_Reset_Low
    pause1ms(5)
    ILI_Reset_High ' returns in group 2, ie CS is high
    Change137(2) ' replaces ILI_CS high - select another group
    ILI_RD_High
    ILI_WR_High
    pause1ms(5)

    'ILI_CS_Low
    SelectMemGroup ' enables correct pins for output and sets CS low
    'IliInit
    SsdInit

    PRI SsdInit
    ILIcmd($0000,$0001) 'Turn Oscillator on POR-$0000
    pause1ms(1)
    ILIcmd($0003,$A8A4) 'Power control (1) POR-$6664
    pause1ms(1)
    ILIcmd($000C,$0000) 'Power control (2) POR- ?
    pause1ms(1)
    ILIcmd($000D,$080C) 'Power control (3) POR-$0009
    pause1ms(1)
    ILIcmd($000E,$2B00) 'Power control (4) POR-$3200
    pause1ms(1)
    ILIcmd($001E,$00B0) 'Power control (5) POR-$0029
    pause1ms(1)
    ILIcmd($0001,$4B3F) 'Driver output control, *landscape?? $6B3F* POR-$433F
    pause1ms(1)
    ILIcmd($0002,$0600) 'LCD drive AC control POR-$0400
    pause1ms(1)
    ILIcmd($0010,$0000) 'Sleep Mode sleep mode off POR-$0001
    pause1ms(1)
    ILIcmd($0011,$6070) 'Entry Mode, *landscape? $4030* POR-$6830
    pause1ms(1)
    ILIcmd($0005,$0000) 'Compare Register (1) POR-$0000
    pause1ms(1)
    ILIcmd($0006,$0000) 'Compare Register (2) POR-$0000
    pause1ms(1)
    ILIcmd($0016,$EF1C) 'Horizontal Porch POR-$EFC1
    pause1ms(1)
    ILIcmd($0017,$0003) 'Vertical Porch POR-$0003
    pause1ms(1)
    ILIcmd($0007,$0033) 'Display Control POR-$0000
    pause1ms(1)
    ILIcmd($000B,$D308) 'Frame cycle Control POR-$D308
    pause1ms(1)
    ILIcmd($000F,$0000) 'Gate Scan start position POR-$0000
    pause1ms(1)
    ILIcmd($0041,$0000) 'Vertical Scroll Control (1) POR-$0000
    pause1ms(1)
    ILIcmd($0042,$0000) 'Vertical Scroll Control (2) POR-$0000
    pause1ms(1)
    ILIcmd($0048,$0000) 'First Window Start POR-$0000
    pause1ms(1)
    ILIcmd($0049,$013F) 'First Window End POR-$013F
    pause1ms(1)
    ILIcmd($004A,$0000) 'Second Window Start POR-$0000
    pause1ms(1)
    ILIcmd($004B,$0000) 'Second Window End POR-$013F
    pause1ms(1)
    ILIcmd($0044,$EF00) 'Horizontal Ram Address Postion POR-$EF00
    pause1ms(1)
    ILIcmd($0045,$0000) 'Vertical Ram Address Start POR-$0000
    pause1ms(1)
    ILIcmd($0046,$013F) 'Vertical Ram Address End POR-$013F
    pause1ms(1)

    ILIcmd($0023,$0000) 'RAM write data mask (1) POR-$0000
    pause1ms(1)
    ILIcmd($0024,$0000) 'RAM write data mask (2) POR-$0000
    pause1ms(1)
    'ILIcmd($0025,$8000) 'not in datasheet?
    ' pause1ms(1)
    ILIcmd($004f,0) 'RAM Y address counter POR-$0000
    pause1ms(1)
    ILIcmd($004e,0) 'RAM X address counter POR-$0000
    pause1ms(1)

    ChangeOrientation(false) ' default to portrait

    '

    SSD1289 END

    PUB Draw(x1, y1, x2, y2)|HORIZONTALRAMADDRESSPOS ' sets the pixel to x1,y1 and then fills the next (x2-x1)*(y2-y1) pixels
    SelectMemGroup ' set 137 to correct value
    ifnot orientation ' landscape mode so swap x and y
    result :=x1 ' swap x1 and y1
    x1 := y1
    y1 := result
    result := x2 ' swap x2 and y2
    x2 :=y2
    y2 := result

    HORIZONTALRAMADDRESSPOS := x1 + (x2 << 8)
    ILIcmd(REG_HORIZONTALRAMADDRESSPOS,HORIZONTALRAMADDRESSPOS)
    ILIcmd(REG_VERTICALRAMADDRESSSTART,y1)
    ILIcmd(REG_VERTICALRAMADDRESSEND,y2)
    ILIcmd(REG_SETGDDRxADDRESSCOUNTER,x1)
    ILIcmd(REG_SETGDDRyADDRESSCOUNTER,y1)
    Lcd_Write_Com($0022)

    'ILIcmd($0050,x1)
    'ILIcmd($0052,y1)
    'ILIcmd($0051,x2)
    'ILIcmd($0053,y2)
    'ILIcmd($0020,x1)
    'ILIcmd($0021,y1)
    'Lcd_Write_Com($0022)


    PUB Pixel(pixelcolor) ' send out a pixel
    Lcd_Write_Data(pixelcolor)

    PUB pause1ms(period)

    '' Pause execution for period (in units of 1 ms).

    clkcycles := ((clkfreq / _1ms * period) - 4296) #> 381 ' Calculate 1 ms time unit
    waitcnt(clkcycles + cnt) ' Wait for designated time

    PUB hex(value, digits) ' uses internal prop font and slow pixel drawing (for very basic debugging without an SD font)
    SelectMemGroup ' reselect 138 for display output for debugging
    '' Print a hexadecimal number
    propfont_out("O")
    propfont_out("x")
    value <<= (8 - digits) << 2
    repeat digits
    propfont_out(lookupz((value <-= 4) & $F : "0".."9", "A".."F"))
    crlf


    PRI ILIcmd(c,d) ' instruction in one method
    Lcd_Write_Com(c) ' send out a word
    Lcd_Write_Data(d)

    PRI Lcd_Write_Com(ILIlong)
    ILI_RS_low
    LCD_Writ_Bus(ILIlong)
    'docmd("W",ILIlong,0,0) ' try moving to pasm, leaves spin and cog dira as 0 so need to reset both
    'SelectMemGroup ' not working though. Not sure if should be ILIlong or @ILIlong. neither work


    PRI Lcd_Write_Data(ILIlong)
    ILI_RS_High
    LCD_Writ_Bus(ILIlong)

    PRI LCD_Writ_Bus(ILILong)
    'ILILong &= %00000000_00000000_11111111_11111111 ' mask to a word. Not needed if care taken always to send a word value
    OUTA &= %11111111_11111111_00000000_00000000 ' set P0-P15 to zero ready to OR
    OUTA |= ILILong ' merge with the word to output
    ILI_WR_Low ' send out the data
    ILI_WR_High

    PRI ILI_RS_Low
    OUTA &= %11111111_11111011_11111111_11111111 ' P18 low

    PRI ILI_RS_High
    OUTA |= %00000000_00000100_00000000_00000000 ' P18 high

    PRI ILI_WR_Low
    OUTA &= %11111111_11101111_11111111_11111111 ' p20 low

    PRI ILI_WR_High
    OUTA |= %00000000_00010000_00000000_00000000 ' p20 high

    PRI ILI_RD_High ' not used, set high in hardware

    'PRI ILI_CS_Low
    ' Change137(1) ' change to group 1
    '
    'PRI ILI_CS_High
    ' Change137(0) ' change to group 0 (any group other than 1)


    PRI ILI_RESET_Low ' reset low
    Change137(2) ' group 2
    DIRA |= %00000000_00000000_00000010_00000000 ' set pin 9 as an output
    OUTA &= %11111111_11111111_11111101_11111111 ' set pin 9 low

    PRI ILI_RESET_High
    Change137(2) ' group 2
    DIRA |= %00000000_00000000_00000010_00000000 ' set pin 9 as an output
    OUTA |= %00000000_00000000_00000010_00000000 ' set pin 9 high

    DAT
    sdbuffer byte $0[1024] ' 512 byte buffer for sd card interface and also for sending one row 320 x3 = 960 bytes max picture size
    buffer2 byte $0[512] ' 512 general purpose hub buffer
    rambuffer word $0[256] ' 512 byte (256 word) buffer easier for using with words

    PUB start_ram : err_
    ' Initialise the Drac Ram driver. No actual changes to ram as the read/write routines handle this
    command := "I"
    cog := 1 + cognew(@tbp2_start, @command)
    if cog == 0
    err_ := $FF ' error = no cog
    else
    repeat while command ' driver cog sets =0 when done
    err_ := errx ' driver cog sets =0 if no error, else xx = error code

    PUB stop_ram
    if cog
    cogstop(cog~ - 1)

    PUB DoCmd(command_, hub_address, ram_address, block_length) : err_| a,b
    ' Do the command: A-Z (I is reserved for Initialise)
    'dira := 0 ' tristate all pins with the spin dira
    a := dira ' store the state of these and restore at the end
    b := outa
    DIRA &= %11111111_10100000_00000000_00000000 ' tristate all common pins that cog can change so no conflicts
    hubaddrs := hub_address ' hub address start
    ramaddrs := ram_address ' ram address start
    blocklen := block_length ' block length
    command := command_ ' must be last !!
    ' Wait for command to complete and get status
    repeat while command ' driver cog sets =0 when done
    err_ := errx ' driver cog sets =0 if no error, else xx = error code
    dira := a ' restore dira and outa
    outa := b

    CON
    '' Modified code from Cluso's triblade
    '' commands to move blocks of data to the ILI9325 touchscreen display
    ' DoCmd(command_, hub_address, ram_address, block_length)
    ' I - initialise
    ' S - Move data from hub to ram
    ' T - Move data from ram to hub
    ' U - Move data from ram to display
    ' V - Hub to display
    ' W - not working - writecom in pasm
    ' E - convert from .raw RGB to two byte ILI format RRRRRGGG_GGG_BBBBB
    ' F - convert from .bmp BGR format to two byte ILI format
    ' X - merge icon and background based on a mask
    ' Y - Change 137 output Returns P0-P20 and P22 in HiZ. Pass hubaddrs
    ' Z - Set 161 pins. Returns in group 1

    VAR

    ' communication params(5) between cog driver code - only "command" and "errx" are modified by the driver
    long command, hubaddrs, ramaddrs, blocklen, errx, cog ' rendezvous between spin and assembly (can be used cog to cog)
    ' command = A to Z etc =0 when operation completed by cog
    ' hubaddrs = hub address for data buffer
    ' ramaddrs = ram address for data
    ' blocklen = ram buffer length for data transfer
    ' errx = returns =0 (false=good), else <>0 (true & error code)
    ' cog = cog no of driver (set by spin start routine)


    DAT
    '' +
    +
    '' | Touchblade 161 Ram Driver (with grateful acknowlegements to Cluso and Average Joe) |
    '' +
    +
    org 0
    tbp2_start ' setup the pointers to the hub command interface (saves execution time later
    ' +-- These instructions are overwritten as variables after start
    comptr mov comptr, par ' -| hub pointer to command
    hubptr mov hubptr, par ' | hub pointer to hub address
    ramptr add hubptr, #4 ' | hub pointer to ram address
    lenptr mov ramptr, par ' | hub pointer to length
    errptr add ramptr, #8 ' | hub pointer to error status
    cmd mov lenptr, par ' | command I/R/W/G/P/Q
    hubaddr add lenptr, #12 ' | hub address
    ramaddr mov errptr, par ' | ram address
    len add errptr, #16 ' | length
    err nop ' -+ error status returned (=0=false=good)


    ' Initialise hardware tristates everything and read/write set the pins
    init mov err, #0 ' reset err=false=good
    'mov dira,zero ' tristate the pins with the cog dira
    and dira,maskP0P20P22 ' tristates all the common pins

    done wrlong err, errptr ' status =0=false=good, else error x
    wrlong zero, comptr ' command =0 (done)
    ' wait for a command (pause short time to reduce power)
    pause
    ' mov ctr, delay wz ' if =0 no pause
    ' if_nz add ctr, cnt
    ' if_nz waitcnt ctr, #0 ' wait for a short time (reduces power)
    rdlong cmd, comptr wz ' command ?
    if_z jmp #pause ' not yet
    ' decode command
    cmp cmd, #"S" wz ' hub to ram
    if_z jmp #pasmhubtoram
    cmp cmd, #"T" wz ' ram to hub
    if_z jmp #pasmramtohub
    cmp cmd, #"U" wz ' ram to display
    if_z jmp #pasmramtodisplay
    cmp cmd, #"V" wz ' hub to display
    if_z jmp #pasmhubtodisplay
    cmp cmd, #"E" wz ' convert 3 byte .raw format to 2 byte .ili format - hub to hub
    if_z jmp #rawtoiliformat
    cmp cmd, #"F" wz ' convert 3 byte .bmp format BGR to 2 byte ili format (same as E but order reversed)
    if_z jmp #bmptoiliformat
    ' cmp cmd, #"W" wz ' lcdwritecom in pasm, not working
    ' if_z jmp #pasmlcdwritecom
    cmp cmd, #"X" wz ' merge icon and background based on a mask
    if_z jmp #mergeicons
    cmp cmd, #"Y" wz ' change the 137 output
    if_z jmp #changegroup
    cmp cmd, #"Z" wz ' set the 161 counters
    if_z jmp #set161
    cmp cmd, #"I" wz ' init
    if_z jmp #init
    mov err, cmd ' error = cmd (unknown command)
    jmp #done

    '
    common routines

    get_values rdlong hubaddr, hubptr ' get hub address
    rdlong ramaddr, ramptr ' get ram address
    rdlong len, lenptr ' get length
    mov err, #5 ' err=5
    get_values_ret ret

    ' Pass pasm_n = 0- 7 come to this with P0-P20 and P22 tristated and returns them as this too
    set137 or dira,maskP22 ' pin 22 is an output
    andn outa,maskP22 ' set P22low so Y0-Y7 are all high
    or dira,maskP0P20 ' pins P0-P20 are outputs
    and outa,maskP0P2low ' set these 3 pins low
    or outa,pasm_n ' set the 137 pins
    or outa,maskP22 ' pin 22 high
    set137_ret ret ' return


    load161pasm ' uses ramaddr
    or outa,maskP0P20 ' set P0-P20 high
    or dira,maskP0P20 ' output pins 0-20
    mov pasm_n,#0 ' group 0
    call #set137 ' set the 137 output
    and outa,maskP0P18low ' pins 0-18 set low
    or outa,ramaddr ' output addres to 161 chips
    or outa,maskP19 ' clock high
  • Ahle2Ahle2 Posts: 1,073
    edited 2012-05-20 - 12:08:23
    There's a huge step from a wav player to a polyfonic sample based synth.
    It's better to do the synth from ground up than hacking Kyes wav player object; In the end almost nothing will be left from the wav player anyway.
    To be able to play samples at an arbitrary frequency, a phase accumulator is the way to go.
    Use X number of the MSBs of the accumulator as an index into the sample in memory.
    32bitAcc += 32freqValue
    outputToDac( sampleInMemory[32bitAcc>>16] )
    

    The example above can play samples of up to 64 kB in size. You can increase sample size by shifting less than 16 bits, but the pitch accuracy will decrease.
    Less than 12 bit pitch accuracy will sound out of tune. (Btw, Pokey used 8 bits... ugh..)

    The rate at wich the sample is played back can be calculated by the formula below.

    samplePlaybackRate = mixingRate * (32bitFreqValue / (2^(32 -
    nrOfMsbsUsedAsSampleIndex) )

    Note
    that samplePlaybackRate isn't the resulting frequency of the sampled instrument itself.. it's just the sample rate.
    mixingRate is the sample rate out to the DAC.


    A wavetable synth can be made by using just a few of the MSBs (like 8 or so) and then letting the 32 bit accumulator wrap over from 0xFFFFFFFF to 0. Each wrap is a period.
    Then just apply a volume envelope and you're done. ;)
  • average joeaverage joe Posts: 795
    edited 2012-05-21 - 09:05:17
    I agree that it's a huge step from sample player to polyphonic sampling synth. You need all the things already pointed out, and I would add LPF12,LPF24,BPF,HPF filters with frequency and resonance. It would also be nice to "patch" modulation sources to the filter frequency and resonance as well as the volume envelope. There's quite a bit to consider and this would be best for C IMO.
    Speaking of C, I think I have it working in XMMC AND LMM. See post here : http://forums.parallax.com/showthread.php?140010-Files&p=1099650&viewfull=1#post1099650 Looks like it's time to work on cache driver?

    I have a bit of work to do before I release the chiptune player. It is functional except fast forward, rewind and GUI screening. I'm REALLY excited now! More later!

    *edit*
    Here's the newest transport BMP!

    Trans2.bmp


    *more edit*
    Here's an ALPHA release of chiptune player. It SHOULD be ready for the ILI but I might have missed something when porting from the SSD. These use OLD *May 13't* drivers.


    Just updated to include the transport files for the SD card!

    Found a bug,
    PUB SetScrollMessage(x)
    Disp.SetCurXY(0,119)
    
    Should be:
    PUB SetScrollMessage(x)
    Disp.SetCurXY(0,127)
    
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-05-21 - 18:38:41
    Well done re getting C working. I'll have to check that out.

    There are some amazing synthesizer threads running at the moment. Lots of possibilities there. Generally, those synths are going to need knobs or sliders. I spent last night coding a multiline text box and a multi select box. Useful for things like a word processor and also for selecting which song to play. I have some rudimentary things working in gray but I am thinking windows95 gray is looking a bit boring and old-school. Maybe need some more funky sliders and buttons and checkboxes eg http://www.dreamstime.com/stock-images-stock-images-scroll-bar.-image14529454.

    I wrote some of the drawing as code drawing individual lines and pixels but it may actually work out faster to use bitmaps. Also if we keep the size of things a common standard (eg a scrollbar is 15 pixels wide) then you can start to think about different 'skins'.

    Oh and I just got an email saying the dual screen boards have been shipped.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-05-23 - 06:06:21
    Thinking more about a more modern looking GUI, I have been looking again at html. I think html could be a more universal language than vb.net etc as you can debug things in a browser. I'm back inside the w3schools tutorials looking at things like frames, buttons, checkboxes and scrollbars. Interestingly, the same html code looks slightly different visually in Firefox, Internet Explorer and Opera. I've gone for the Opera style. It is designed to go on a white background (cf a lot of older windows code which has a gray background). So to start with the html code for a frame
    <!DOCTYPE html>
    <html>
    <body>
    <iframe src="demo_iframe.htm" width="120" height="200"></iframe>
    </body>
    </html>
    

    And then add some scrollbars. In Opera these are gray when inactive and a light purple when active. Scrollbars will have three active touchscreen areas per bar - the top and bottom arrows move up or down one line and the slider goes through an entire text file, or moves around a bigger picture/webpage than can fit on the screen.

    In many ways it is easier to draw bitmaps than to draw pixels and lines, so as much as possible, draw things with bitmaps that have been loaded into the ramdisk.

    Spin code
    PUB HTML ' based on http://www.w3schools.com/html/html_iframe.asp and the Opera browser - text boxes, check boxes, scrollbars etc. Gray for inactive, light purple for active
       Clearscreen($FFFF)                                 ' clear the screen to white
       RamErase1                                          ' erase all but file 0 (desktop)
       SDBMPtoRam(string("arrupgry.bmp"))                 ' file 1 up arrow part of the slider
       SDBMPtoRam(string("arrdngry.bmp"))                 ' file 2 down arrow part of the slider
       SDBMPtoRam(string("scrolcnr.bmp"))                 ' file 3 corner gray part of the slider
       SDBMPtoRam(string("arrlgry.bmp"))                  ' file 4 left gray
       SDBMPtoRam(string("arrrgry.bmp"))                  ' file 5 right gray
       SDBMPtoRam(string("slivegry.bmp"))                 ' file 6 slider vertical gray
       SDBMPtoRam(string("slihogry.bmp"))                 ' file 7 slider horizontal gray      
       iframe(10,10,120,200,50,128)                       ' x1,y1,x2,y2,slider h 0-255, slider w
       repeat
    
    PRI iframe(x1,y1,x2,y2,h,w)         ' see 3schools tutorial
       Drawline(x1-1,y1-1,x2+1,y1-1,RGBtoWord(0,0,0))       ' black line at top 
       Drawline(x1-2,y1-2,x2+2,y1-2,RGBtoWord(0,0,0))       ' black line at top dual line
       Drawline(x1-1,y1-1,x1-1,y2+1,RGBtoWord(0,0,0))       ' left black line
       Drawline(x1-2,y1-2,x1-2,y2+2,RGBtoWord(0,0,0))       ' left double black line
       Drawline(x2+1,y1,x2+1,y2+1,RGBtoWord(128,128,128))   ' right gray line
       Drawline(x2+2,y1-1,x2+2,y2+2,RGBtoWord(128,128,128)) ' right gray line double
       Drawline(x1,y2+1,x2+1,y2+1,RGBtoWord(128,128,128))   ' gray line at bottom
       Drawline(x1-1,y2+2,x2+2,y2+2,RGBtoWord(128,128,128)) ' gray line at bottom dual line
       Drawline(x2-15,y1,x2,y2,RGBtoWord(240,240,240))      ' slider background vertical
       Drawline(x1,y2-15,x2,y2,RGBtoWord(240,240,240))      ' slider background horizontal
       DrawBMPRam(1,x2-15,y1)                               ' draw file 1 up arrow
       DrawBMPRam(2,x2-15,y2-31)                            ' draw file 2 down arrow
       DrawBMPRam(3,x2-15,y2-15)                            ' draw file 3 corner gray
       DrawBMPRam(4,x1,y2-15)                               ' draw file 4 left gray
       DrawBMPRam(5,x2-31,y2-15)                            ' draw file 5 right gray
       DrawBMPRam(6,x2-15,y1+16+(y2-y1-80)*h/255)           ' draw file 6 vertical slider 
       DrawBMPRam(7,x1+16+(x2-x1-80)*w/255,y2-15)           ' draw file 7 horizontal slider     
    
    800 x 600 - 40K
    646 x 320 - 40K
  • average joeaverage joe Posts: 795
    edited 2012-05-23 - 08:03:18
    Wow, you keep blowing me away with your progress. I feel like I've been stuck in reverse for a couple weeks now * and will be for at least another month*.
    I was able to confirm my display is faulty. I returned to my WAY OLD hardware to run some tests and sure enough, it seems as if the /CS line is not properly gating the /WR line. Also, some bits in some registers do not work properly. My new displays are on their way from Hong Kong with a 4-6 week ship time. *My wife rolls her eyes whenever I bring up priority shipping, lol*

    I really, really like the idea of skinning things. Have a text based, *.skn (or whatever you want to call it) that contains the names of the bmps attached to the elements. You could also encode the background color and text color in the file to make it super-simple to skin. Honestly the more I think about it, there's all KINDS of things we could do with skins. Which brings me to an interesting thought:

    There are several different screens and controllers to look at as potential "ports" BUT... The functionality depends on the controller and some have nicer features than others. Your ILI offers resize while my SSD does not. I do like the SSD1289's writeMask 1 and 2. Once I verify operation on my new displays, this method of masking should allow us to "color-mask" in REAL-TIME! The idea is this, with a black background *all 0's* you set the write mask register to the inverse of the color you want. Then draw your Black and White image and the White will appear the color set! It works on blue *WriteMask2*, and I suspect the faulty screen is why red-green don't work properly. *writeMask1* There is also COMPARE settings that I'm not able to decipher the operation of yet and can't trust the results of testing. *My guess is you set the compare registers to a value, and then 3 other bits control the logical function of the compare? Maybe we can use this to make the black part of the image not draw to screen but increment pointer???? at least that's what I hope!
    CPR [5:0], CPG [5:0] CPB [5:0] :
    Set the value for the compare register, of which the data is read out from the GDDRAM or data is written to the GDDRAM by the microcomputer are compared...
     ...CPR [5:0] compares the pins RR[5:0], and CPG [5:0] compares the pins GG[5:0], and CPB [5:0] compares the pins BB[5:0]. 
    Refer to section 14 interface mapping for writing methods in RGB data. 
    
    There is a mention of LG [2:0] ="000" in external mode, but no other explanation of SETTING LG?

    *edit*
    Just found the LG settings in Entry Mode(R$11) IB [0:2]:
    "Write data to the GDDRAM after comparing the write data written to the GDDRAM by the microcomputer with the values in the compare registers (CPR [5:0], CPG [5:0] CPB [5:0]) and performing a logical and arithmetic operation on them."

    That's all I can find on those... Any thoughts?
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-05-23 - 22:48:37
    I got the SSD1289 3.2" displays today.

    Of course they are wider (D'oh) so they won't fit side by side on the dual display board.

    However, I'm having problems getting the display to work. Below is some code. There is a line in the con section
      ILI9325 = true                          
      SSD1289 = false
    

    and so set which one you are using and I think there are 3-4 places in the code that are different.

    I can get it to read off the SD card and display the background correctly. However, the picture then fades away over about 4 second - various colors in the picture spread out and take over the screen until there are just a couple of large squares of color. Interestingly though, if I hit the reset button, while the prop is restarting, all the correct picture plus icons are there. So for a brief moment the display is correct and an awful lot of things would have to have worked to get that picture-plus-icons there.

    In the C code, /CS is kept high once all the data has been sent out. I don't think that is the problem though because when it is waiting for touch input it is in a different group and /CS is high then.

    Also - I picked up these 3.2" displays for $20 but suddenly they are now $50. Hmm.

    So we are close but no cigar.

    So I'm back to using the 2.4" ones for the moment http://www.ebay.com.au/itm/2-4-TFT-LCD-Module-Display-Touch-Panel-PCB-adapter-/190477028273?pt=LH_DefaultDomain_0&hash=item2c5950cbb1 which are $16.87. If the 3.2" ones are going to be $50 then two 2.4" ones will be cheaper.

    c code that we are copying
    #include <reg51.h> /* http://ttmcu.taobao.com [code]
    #include <reg51.h>

    /* http://ttmcu.taobao.com
  • average joeaverage joe Posts: 795
    edited 2012-05-24 - 05:31:18
    Oh no, the problem with the display sounds like my "screen freak" event. If you search through the code and re-enable "FixGlitch" it should start working. I was hoping my display was the issue but I guess I'll have to go back to the drawing board. I noticed my supplier changed prices so I ordered from here : http://cgi.ebay.com/ws/eBayISAPI.dll?ViewItem&item=180871283713&ssPageName=ADME:X:BOCOR:US:1123
    Asking price is $14 a piece, not too shabby.
    I will go through and try to figure out what's going on. I doubt it will help but here's the timings I used to run:
    DAT                                             'init  Display driver
                                                    'designed for optimized hardware, pull-up resistors on RS and WR pins.
                   org 0                             
    entry             mov outa, PinsInit             'set pins to inital state
                      mov dira, DirsEnabled            'enables p0 - p15        
                      mov bufferaddress, par                      'store par in bufferaddress, par is screen buffer address at startup 
                     'mov dira, DirsDisabled                    'disables p0 - p15 if necessary    
                     wrlong zero, bufferaddress                   'set par to zero to confirm load done
                                                   'get write command from buffer, and check if it's 0
                                                                                               
    Get                      rdlong LCD_Data, bufferaddress           'get long from main memory and put it in ldc command, msW = LCD cmd, LSw = LCD data
                             cmp    Lcd_Data, #0                wz    'and check if it's 0
    if_z                     jmp #get                                 'if it is, try again.
                                                   'if not, prepare transfer
                             'mov dira, DirsEnabled                          'set pins if necessary                        
                             mov LCD_cmd, LCD_Data                    'copy lcd command to lcd data
                             
                             shr LCD_cmd, #16                         'move lcd command 16 bit to the right if not gddr write
    '                        cmp LCD_cmd, #22                   wz    'check to see if this is a gddr write  
    'if_nz                   jmp WRcmd         
                                            'optimized write to display, for gddr transfer
                                            
                                                  'enables p0 - p15 
    '                         mov    pntr, #$1                          'set wait period
    ':wait0                   djnz   pntr, :wait0                       'and wait
    
    WrCmd                    mov    outa, LCD_Cmd                  'place LCD_Cmd on write bus
    
    '                         mov    pntr, #$1                           'set wait period
    ':wait0                   djnz   pntr, :wait0                        'and wait
    
                             add    zero, #0               wz   'prime WZ flag                       
                             muxz   dira, RSpin                    'make RS pin low by enabling its DIR REG
                             
     '                        mov    pntr, #$1                           'set wait period
    ':wait1                   djnz   pntr, :wait1                        'and wait
     
                             muxz   dira, WritePin                 'make Write Pin low by enabling its DIR REG
    
                             and LCD_Data, lowWordMask                'mask off High word of Lcd_Data
                             
    '                         mov    pntr, #1                           'set wait period
    ':wait2                   djnz   pntr, :wait2                        'and wait
                  
                             muxnz  dira, WritePin                 'make Write Pin high by disabling its DIR REG
                             
                             mov    pntr, #$1                           'set wait period
    :wait3                   djnz   pntr, :wait3                        'and wait
    
                             muxnz  dira, RSpin                    'make RS pin high by disabling its DIR REG
                            
                             mov    pntr, #$1                          'set wait period
    :wait4                   djnz   pntr, :wait4                        'and wait
    
    :WrDataPortion                                                 
                             mov    outa, LCD_Data                 'place LCD_Data on write bus
                             wrlong zero, bufferaddress     'wz
                             mov    pntr, #$1                           'set wait period  
    :wait5                   djnz   pntr, :wait5                        'and wait
    
                             add    zero, #0               wz    'prime WZ flag
                             muxz   dira, WritePin                  'make Write Pin low by enabling its DIR REG
                            
                              
                              'rdlong LCD_Data, bufferaddress           'get long from main memory and put it in ldc command, msW = LCD cmd, LSw = LCD data 
    
                             mov    pntr, #$2                          'set wait period
    :wait6                   djnz   pntr, :wait6                        'and wait
    
                             muxnz  dira, WritePin                  'make Write Pin high by disabling its DIR REG
                             
                             mov    pntr, #$1                           'set wait period
    :wait7                   djnz   pntr, :wait7                        'and wait
                             'mov    dira, DirsDisabled                 'disables p0 - p15
                                                   
                      jmp #Get                              'do it all again
    
    Of course this is just controlling WR, not CS.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-05-24 - 06:48:07
    I think this one might require some lateral thinking. On my hour drive to work this evening and then back again I let my mind wander a bit and try to think of things that would cause a picture to slowly fade away like a Cheshire cat. And then I did some free association trying to work out why the picture was there when you hit the propeller reset button?

    I think my creative brain hemisphere came up with the answer, but it required some input from the logical hemisphere as well. What happens when you hit reset? One thing is that all the propeller pins go to HiZ.

    I don't have a full answer yet, but I do have some code that works:
    PUB Main | touchtest  ' debug value
      start_ram                                             ' start the external ram / display driver in a cog
      Change161(0)                                          ' reset all the 161 counters to zero
      SelectMemGroup                                        ' select group1
      Start_ILI9325                                         ' start the display. Don't clear screen as this uses ram commands and these might not be working yet
      Text(string("SD"))                         ' string to send, uses internal prop font so can see something if the SD fails to mount   
      SetOrientation(true)                                  '  in portrait (true) or landscape mode (false), must be before clearscreen otherwise don't know screensize   
      fat.fatEngineStart( _dopin, _clkpin, _dipin, _cspin, _wppin, _cdpin, _rtcres1, _rtcres2, _rtcres3)
      fat.mountPartition(0)                                 ' mount the sd card
      Clearscreen(RGBtoWord(0,0,0))                         ' clear screen to black - uses the display driver above
      RamErase                                              ' erase ram chip fat
      LoadDesktop                                           ' a image 240x320 for the desktop. Load first as there is a ramclear routine that does not delete the first entry
      DrawDesktop
    
      dira := 0                                            ' HiZ for debugging the SSD1289
      repeat
      
      LoadIcons                                             ' load the mask and icons onto the screen
      ILISetcursor(0,0)                                     ' cursor for debugging to 0,0
      SelectSPIGroup                                        ' selects this group and starts the cog
      Touchscreen                                           ' wait for input
    

    Patch that into the code I posted above.

    Picture attached is the proof. Put the dira := 0 any further down and it fails.

    Now my theory is that there is a short happening, and that the power supply is collapsing causing the display to fade out. Why a short would happen I do not know. It is as if "input" pins on that 40 pin header are somehow becoming "output" pins and fighting against the propeller pins.

    I do not know which pins yet, but I guess one can go through them one at a time in code and make them outputs and find out.

    The picture has been rock solid now for 20 minutes so that is proof that the setup and driver code is working correctly.

    Can you replicate this?

    Addit: $13.89 for your display? Wow, that is good value.

    One thing I have noticed is the 3.2" display is not as good looking at an oblique angle. I don't think it is as true a "TFT" lcd as the smaller ones. ebay helpfully suggested some more 3.2" TFT touchscreens and some of those say that they have the "standard" 40 pin header. It is encouraging there are multiple suppliers and this 40 pin header is a standard. We could try some different displays and compare them. The code above just needs a couple of lines changed to completely change the display and that will be very handy for swapping in different sized displays. Futurlec sell the 20x2 socket which is also very useful. Once we get these SSD1289 displays working it means we are not so dependent on one supplier.
    800 x 600 - 85K
  • average joeaverage joe Posts: 795
    edited 2012-05-24 - 08:07:34
    Very interesting work doc! I will need to think about it a bit more but it seems my results may have varied a bit? With my testing, I noticed the picture to still be on screen, even after the screen faded. *on reset like you say* I stepped through the code and found that the oscillator was being turned off it seems. From what I can tell, this has SOMETHING to do with HubToRam. I'm still confused as to what is going on, but I will do some more tests. I do know that this will "fix" the display after it glitches:
    PUB FixGlitch
        ILIcmd($0000,$0001)      'Turn Oscillator on                                POR-$0000
        ILIcmd($0001,$6B3F)      'Driver output control,    *landscape?? $6B3F*  From code??2B3F?   POR-$433F
        ILIcmd($0002,$0600)      'LCD drive AC control                              POR-$0400
        ILIcmd($0010,$0000)      'Sleep Mode                sleep mode off          POR-$0001
        ILIcmd($0011,$6070)      'Entry Mode,               *landscape? $4030*      POR-$6830  
        ILIcmd($0007,$0033)      'Display Control                                   POR-$0000   ''Used 0033
        ILIcmd($0023,$0000)      'RAM write data mask (1)                           POR-$0000
        ILIcmd($0024,$0000)      'RAM write data mask (2)                           POR-$0000
        ChangeOrientation(orientation)
    
    I hope we are having the same issues but on the other hand I still think the display is bad. Now that you have the SSD could you try this?
    PUB TestMask(timeout)
      Clearscreen(RGBtoWord(0,0,0))                         ' clear screen to black - uses the display driver above 
      FixGlitch
                                     '  in portrait (true) or landscape mode (false), must be before clearscreen otherwise don't know screensize
      Clearscreen(0)                         ' clear screen to black - uses the display driver above 
    
    ''draw Red         'draws yellow?
        propfont_string(String("RED"))            
        Clearscreen(0)                            'Prepeare screen for mask
      ILIcmd($23,$00FC)                           'setMask Green0-5=1 Mask off green  
      ILIcmd($24,$00FC)                           'setMask Blue0-5=1 Mask off blue   
       Clearscreen($FFFE)                         ' clear screen to black - use mask 
      FixGlitch                                   'fix my display
    
      pause1ms(5_000)                            'wait for a bit
        propfont_string(String("green"))
        Clearscreen(0)                            'Prepeare screen for mask
        ''draw Green     'draws nothing           
      ILIcmd(0023,$FC00)         'setMask Blue0-5=1 Mask off blue                      ' 
      ILIcmd(0024,$00fc)         'setMask RED0-5=1 Mask off RED                      '   
      Clearscreen($FFFE)                          ' clear screen to black - use mask 
        FixGlitch                                 'fix my display
    
                          'update orientation 
      pause1ms(5_000)                             'wait for a bit
      propfont_string(String("blue"))
      Clearscreen(0)                              'Prepeare screen for mask
        ''draw Blue -OK  ' draws blue, works??
      ILIcmd(0023,$fcFc)         'setMask Green0-5=1, Red0-5=1 Mask off green and red                      ' 
      ILIcmd(0024,$0000)         'setMask Blue0-5=0                      ' 
      Clearscreen($FFFE)                          ' clear screen to white - usemask
        FixGlitch                                 'reset display
    
                           'update orientation
      pause1ms(5_000)                             'wait a bit
      deadend       
    
    My fingers are crossed this draws RED, GREEN, then BLUE screens.. Blue works for me. Red and Green are controlled by Red?


    re displays, I do find my screen a bit dull. It would be nice to try some other displays, although I believe setting the gamma and power control properly * I can't quite figure it out* it might look better.

    *edit*

    Tried plugging in your code and sometimes it will load the icons, most of the time it will fail somewhere after mask. From my previous testing it seems to fail in HubToRam as I said. It seems like it only fails in LoadBMP but I'm not sure why.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-05-24 - 16:27:52
    I'll test that when I get home.

    I see in the C code that after many routines, /CS goes high. I don't think the ILI9325 code does that. My assumption with the ILI9325 driver is that even if /CS is low, if /RD and /WR and /RS are all high then no data will go to and from the display. But that may not be true with the SSD1289 display. Maybe /CS needs to be high to truly disable the display. It might explain why glitches happen with HubtoRam because that is going to be toggling lots of the data lines, and possibly sending data somehow to the display.

    /CS at the moment is controlled by the group select but maybe it needs to be controlled by a latch?
  • jmgjmg Posts: 14,540
    edited 2012-05-24 - 16:34:33
    Some of the video chip Data I've looked at, suggest the CS\ needs to cycle every R/W, so it is not quite like SRAM.
    You could try that ?
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-05-24 - 18:42:24
    Well spotted jmg.

    Yes you are right
    void Lcd_Write_Com( int  DH)	 //&#21629;&#20196;
    {	
        LCD_RS=0;
    	LCD_CS =0;	 
    	LCD_DataPortH=DH>>8;	
    	LCD_DataPortL=DH;		
    	LCD_WR=0;
    	LCD_WR=1;
    	LCD_CS =1;	
    }
    void Lcd_Write_DATA(int DH)	//&#25968;&#25454;	
    {
        LCD_RS=1;
    	LCD_CS =0;	  				
    	LCD_DataPortH=DH>>8;	
    	LCD_DataPortL=DH;					
    	LCD_WR=0;
    	LCD_WR=1;
    	LCD_CS =1;	
    }
    

    There is a way we could test that. /CS on our board goes low when that group is selected, so if we deselect all groups between each data transfer that will put /CS high. However, on the board averagejoe and I have, we can't set /CS high when doing hub to ram transfers. We may need a revision on the board design to work around this.
  • average joeaverage joe Posts: 795
    edited 2012-05-24 - 19:16:45
    I've been thinking about trying to strobe /CS after the last transfer to screen. Hopefully this will "deselect" the display? I am just postulating here but I think it's the FIRST transfer to RAM after writing to screen. I have not had a chance to check this yet. If not and /CS must be held high then a fix will be in order.. It may be time to think about a "daughter-board" to hold a latch and another `32? I'm hoping it won't come to that and it can be fixed in software.

    *edit*
    I'm pulling out the trusty HW_v3.4 to verify opperation of the screen. I will need to make some revisions to control /CS. Hopefully I can test a couple things out and see if it's the "last display / load RAM address" /CS
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-05-24 - 20:28:41
    Sounds a plan. At least we know the cause now.

    I'm going to try soldering up one of the dual display boards (they should be in the air to the USA by now). Because each display needs to be selected individually these have a latch on the /CS so this could be an unintended bonus for this board.
    1024 x 768 - 164K
  • average joeaverage joe Posts: 795
    edited 2012-05-25 - 20:02:18
    I am eagerly awaiting the new boards. I'm short on sockets now!
    I was able to coax the XMMC - SRAM driver to life. Now I need to test the actual performance. I'm uploading files to the webpage this evening. I've been looking at your latest code and think it needs to be broken into objects. Almost 2500 lines of code! Breaking things up a bit will make it easier to port to C IMO. Still much work to be done.

    Could you try the colormask when you get a chance? I really want to make sure this works before I invest more time coding for this. I am fairly sure there are a few broken registers in my display.

    Also, I have been unable to replicate the glitch on HW_3.4b.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-05-26 - 16:23:25
    Good news and bad news.

    First the good news. The dual display works fine - see attached photo. So you can have a 480x320 screen if you want, or have a keyboard on one and lots of knobs on the other. That is with these displays http://www.ebay.com.au/itm/2-4-TFT-LCD-Module-Display-Touch-Panel-PCB-adapter-/190477028273?pt=LH_DefaultDomain_0&hash=item2c5950cbb1

    The bad news is the SSD1289. I have tried all sorts of code. I did get some text on the display at one stage, but it was split into two lines and I have seen that error before and it is due to not setting up the draw area correctly.

    The problem is the /CS line. We have run out of free propeller pins and by sending this through a latch it gets complicated because the pins controlling the latch output are also pins shared by the data bus. Because of the lack of spare pins, there never is total control over all the pins in parallel. So a simple thing like replicating this
        LCD_RS=0;
    	LCD_CS =0;	 
    	LCD_DataPortH=DH>>8;	
    	LCD_DataPortL=DH;		
    	LCD_WR=0;
    	LCD_WR=1;
    	LCD_CS =1;	
    

    becomes many more lines of code eg LatchLow
    PRI LatchLow(pin)   
       LatchStart
       Latch &= !(1 << pin)                               ' set this pin low
       LatchSend
    
    PRI LatchStart                                          ' common routine to above 2 routines
       Change137(3)                                         ' group 3 is the latch group
       DIRA |= %00000000_00000000_00000000_11111111         ' P0-P7 are outputs   
    
    PRI LatchSend                                           ' common routine to both above routines
       OUTA := Latch                                        ' send out
       DIRA |= %00000000_01000000_00000000_00000000         ' enable pin 22 as an output
       OUTA |= %00000000_01000000_00000000_00000000         ' set P22 high - this latches the data into the latch
    
    PUB Change137(group)
       docmd("Y",group,0,0)                                 ' change the current group
    
    

    with the change137 going off in pasm and making the propeller pins HiZ (high with pullups) as the group changes. So I don't know if that upsets the display or not.

    Or maybe we just have not got the startup code right.

    There could be a software solution. But take a look at the photo - if you have two of the smaller displays you want them fairly close side by side. And the wider 3.2" display is too wide for the spacing on this board so you can only fit one. This means if you want a dual SSD1289 the spacing needs to be wider. And if the spacing is wider then the ILI9325 boards are further apart. Which means if we want two SSD9325's side by side we need a different board.

    And if there is a different board for the dual SSD1289 displays then it might be better to think of a better design.

    What I am thinking of is that if we need one more pin to do /CS then the only place to get a spare pin is P22 which is controlling the 137. One way you could do this is instead of selecting the group with the 137, use a MCP23008 on the I2C lines. Or even the 16 I/O version. That gives more I/O pins and it means the 374 latch and the 137 could be combined into one. But the main advantage would be that other propeller pins are not going up and down during latch outputs. (eg P0-P2). I think it will make the code simpler.

    Speed will be an issue. The C code for the SSD1289 toggles the /CS line every time data goes out. I don't know if that is necessary and it may not be given I got a full screen picture at one stage and only toggled /CS at the beginning and the end of the entire picture, but if it is necessary, then /CS will be P22. The slower bit can be which screen to select and that can go through the MCP23008 and then some logic gates to select which screen.
    800 x 600 - 102K
  • average joeaverage joe Posts: 795
    edited 2012-05-26 - 18:25:43
    This is very strange with the SSD. I have used the "workaround" and it doesn't seem to slow things down that much. It's still a pain and I can't quite understand why. I've looked for other fourms and posts relating to this controller and have not been able to find anything. I keep hoping to figure something out but I'm at a loss. I will have to order a couple ILI's in the future.

    Note, the screen draws correctly with the ILI code. There's just some error, most likely in the handoff between groups *IMO* I need to get my propalyzer board finished. I'm stuck trying to figure out how to plug everything together but think I'm close to a solution. I will need to pull my rack-mount out and start strippin old hardware. Maybe Jazzed will be kind enough to test some transistions in the load-desktop. I'm mostly interested in the /CS and /WR lines, although the /RS and Data would be interesting to know. Maybe I'll finish up the rebuild next week.
    I'm not too worried about displays being side by side since my dual-screen board will be going in the rackmount with displays in landscape. Ribbon cables are handy for this, but the pin-header must go on the back of the board. Oh well, I'm sure we'll figure something out.

    Keep up the good work and let's not worry too much about the SSD right now until I get all the information.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-05-26 - 18:46:47
    I do have many things working with the SSD - I've had a picture on the screen and some text. I am very convinced now that it is just the fact you have to deselect the display /CS most of the time.

    Take a look at this design. It is backwards compatible with the ILI9325. The display sockets are further apart so two SSD1289 displays fit side by side (and almost cover the whole board so doing this in surface mount is not so important if the display almost fills the board anyway). Replacing the 374 and 137 with a MCP23008 saves a chip. The design is simpler to code and simpler to understand. I also took the opportunity to move the audio closer to the propeller chip and as far from the max3232 as possible as I was worried about the stepup driver in the max3232 causing noise. I also grouped all the max3232 and reset components together because if you use the propplug you can leave that whole group out. And there are pads to bring out the group pins and P0-P15 so you can expand at least another 20 propeller pins to another board.
  • average joeaverage joe Posts: 795
    edited 2012-05-26 - 19:45:09
    This is a very interesting idea, and just might solve the problem? I can see where it could simplify code and should still run pretty fast.
    I REALLY like the audio layout, although I'm wondering about the "backwards compatibility" since the ILI displays will be fairly far apart?
    A 28-bit logic analyzer would tell volumes about what's going on with the current display, and it's simple to build. Connecting things is a bit more difficult since the headers are on the 4 corners. I actually only need 0-22 and /CS /WR and /RS. See the theory I have is that /RS and /WR are low before /CS goes high. OR the timing of the last display write is not fully completing before the tri-state. But I'll need to burn that bridge when I get there.

    The other thing I have been thinking about is this. If we stripped the touchscreen functions, how could we make the old board useful to vga, tv, keyboard and mice guys?

    *edit*

    Okay, I just finished looking at the board. The only suggestion I have is this. There needs to be more room around the gnd screw for the TO-220. I ran into a problem shorting this trace before. There's nothing around it, so I would leave plenty of space around this.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-05-27 - 02:22:42
    I'm wondering about the "backwards compatibility" since the ILI displays will be fairly far apart?

    Yes that is a tricky one. There isn't room for more sockets. Maybe this can be a "feature"?

    It would be a simple matter if the circuit all works to have two boards - one with the sockets closer.
    If we stripped the touchscreen functions, how could we make the old board useful to vga, tv, keyboard and mice guys?

    Not quite sure what you mean but there are lots of boards out there that can do TV and VGA and audio and a keyboard eg the propeller demoboard http://elmicro.com/files/parallax/propdemod_schematic.pdf

    I put a square pad on the underside so there are no tracks near the switcher bolt hole.

    The autorouter was completing very easily so I thought I might add some SPI ports. So there are now three SPI ports and one I2C port so that means you can add an external A to D converter etc.

    Have you got any of the 2.4" touchscreens?
  • average joeaverage joe Posts: 795
    edited 2012-05-27 - 02:33:38
    I'm just postulating at the aesthetics. Two 2.4" displays might look okay with the additional space but we won't know till we see.
    The "stripping" of functions was a reference to the presentation thread. I was thinking of integrating something like Steve's HD shield. I'm sure it would not be too difficult. Not top priority by any means, just something to ponder.

    I don't have any ILI displays right now. Need to order some other parts as well. I'm stuck waiting until I move now since I've reached the cutoff for ordering more stuff.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-05-27 - 06:12:05
    I'm stuck waiting until I move now since I've reached the cutoff for ordering more stuff.

    Ah. We can fix that. Ok, well I just put an order through for you for the parts below - if that goes off now then it will arrive about the same time as the boards and I can post both to you at the same time.

    The catch is... you might have to find some obex driver code - eg for the MCP2302 A to D as I managed to squeeze that onto the board as well. (addit http://obex.parallax.com/objects/625/) So we can play around with some digital audio manipulation. I'm thinking fun things like a digital delay line. I wonder if we can do 16x16 bit multiplies fast enough?

    I've sent off the boards for the MCP23008 driver. The space saved by removing one chip is the space I was able to use for the A to D converter so that makes this a better design now. Still, the one that you will get in a few days is very useful if you have a 2.4" ILI9325 display.
    1N5819 	1N5819 Shottky Barrier Diode 	4 	$0.14 	$0.56
    74HC08 	74HC08 - Quad 2-input AND Gate 	1 	$0.20 	$0.20
    74HC161 	74HC161 - Synch 4-bit Counter 	5 	$0.32 	$1.60
    74HC32 	74HC32 - Quad 2-input OR Gate 	2 	$0.20 	$0.40
    BC549 	BC549 Transistor 	2 	$0.10 	$0.20
    C010UMC 	0.01uF 50V Multilayer Ceramic Capacitor 	10 	$0.05 	$0.50
    C022U16T 	22uF 16V Tantalum Capacitors 	2 	$0.60 	$1.20
    C100UMC 	0.10uF (100nF) 50V Multilayer Ceramic Capacitor 	50 	$0.04 	$2.00
    C470U16E 	470uF 16V Radial Electrolytic Capacitor 	4 	$0.12 	$0.48
    C470U25E 	470uF 25V Radial Electrolytic Capacitor 	2 	$0.25 	$0.50
    CRY5.000 	5.000MHz Crystal 	1 	$0.75 	$0.75
    DCCHM9 	2.1mm DC Power Male PC Mount 	2 	$0.25 	$0.50
    DSUBPCF9 	D-Sub 9 Cont Female PC Mount Connector 	2 	$0.55 	$1.10
    FHEADD40 	40 Pin .100 Straight Female Double Headers 	2 	$0.50 	$1.00
    ICS14 	14 Pin IC Socket 	10 	$0.06 	$0.60
    ICS16 	16 Pin IC Socket 	20 	$0.07 	$1.40
    ICS18 	18 Pin IC Socket 	6 	$0.08 	$0.48
    ICS20 	20 Pin IC Socket 	6 	$0.09 	$0.54
    ICS32 	32 pin IC Socket 	4 	$0.15 	$0.60
    ICS40 	40 pin IC Socket 	4 	$0.15 	$0.60
    ICS8 	8 Pin IC Socket 	10 	$0.04 	$0.40
    LEDBARRED 	10-Led Red Bargraph 	2 	$0.30 	$0.60
    LM2574N-3 	LM2574N-3 - Step-Down 3.3V Regulator 	1 	$1.70 	$1.70
    LM2575T-5 	LM2575T-5 - Step-Down 5-Voltage Regulator 	1 	$1.55 	$1.55
    MAX3232CSE 	MAX3232 RS232 Transceiver 	1 	$1.90 	$1.90
    MCP23008 	MCP23008 8-Bit I/O Expander with I²C Interface 	4 	$1.20 	$4.80
    MCP3202 	MCP3202 Dual 12-Bit A/D Convertor w/SPI 	2 	$3.40 	$6.80
    P035SCK03 	3.5mm Stereo PCB Socket 	2 	$0.40 	$0.80
    PIND330 	330µH 1.1A Power Inductor 	2 	$0.45 	$0.90
    RN100K 	100kohm 9 Resistor Network (10 pins) 	10 	$0.25 	$2.50
    RN10K 	10kohm 9 Resistor Network (10 pins) 	4 	$0.25 	$1.00
    RN1K 	1kohm 9 Resistor Network (10pins) 	4 	$0.25 	$1.00
    STOFFHEX_10MM 	10mm M3 Hexagonal Standoff 	2 	$1.90 	$3.80
    TACT001 	Small Black Tactile Switch 	2 	$0.25 	$0.50
    
  • average joeaverage joe Posts: 795
    edited 2012-05-27 - 16:19:48
    Re parts. Well that's good news then! I should have my new address in the next week.
    The cache driver for the old board using xmm-single is working quite well. I should be able to use xmmc since Steve has it working. I'm playing the NOOB card here. Not too worried since part of my need for xmm is variable AND code space. I have also been working on the "glitch fix" since it's a viable workaround for now.. With 2 SSD's on their way, ordering 2 ILI's will have to wait till I get my deposit back from this apartment :D I will post example of workaround when it's fully working and done. As a note, in the XMM driver :
    load161pasm                                             ' uses vmaddr
                            mov     count, line_size       ' make a copy of line_size AND.
                            mov     ptr, hubaddr            ' hubaddr = hub page address
                           'or      outa,maskP0P20          ' set P0-P20 high - unnecessary - jsd
          
    

    *edit*
    In testing of latest code, using glitchfix I have most things working
    SDtoRam,
    SDBMPtoRam,
    MergeBackgroundIconRam,
    'all get this at the end of method:
     if SSD1289
       fixGlitch
    
    PUB FixGlitch
        ILIcmd($0000,$0001)      'Turn Oscillator on                                POR-$0000
        ILIcmd($0001,$6B3F)      'Driver output control,    *landscape?? $6B3F*  From code??2B3F?   POR-$433F
        ILIcmd($0002,$0600)      'LCD drive AC control                              POR-$0400
        ILIcmd($0010,$0000)      'Sleep Mode                sleep mode off          POR-$0001
        ILIcmd($0011,$6070)      'Entry Mode,               *landscape? $4030*      POR-$6830  
        ILIcmd($0007,$0033)      'Display Control                                   POR-$0000   ''Used 0033
        ILIcmd($0023,$0000)      'RAM write data mask (1)                           POR-$0000
        ILIcmd($0024,$0000)      'RAM write data mask (2)                           POR-$0000
        ChangeOrientation(orientation)
    
    There are still things not working, since I'm missing files on the sd card. Also, buttons demo has broken radio buttons? 2 are selected, 1 is not. Just noticed this.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-05-27 - 16:42:55
    There are still things not working, since I'm missing files on the sd card. Also, buttons demo has broken radio buttons? 2 are selected, 1 is not. Just noticed this.
    Yes I noticed that too. My dodgy code - sorry.

    I'm going to recode that with a white background. Needs a frame so the code only switches radio buttons within a frame.

    I see you have got some cool stuff working over on the GCC forum - well done!
Sign In or Register to comment.