Shop OBEX P1 Docs P2 Docs Learn Events
LCD touchscreen, A development thread - Page 3 — Parallax Forums

LCD touchscreen, A development thread

135

Comments

  • average joeaverage joe Posts: 795
    edited 2012-02-24 13:32
    Very nice work! I will have to examine your implementation closer. You seem to have optimized this a bit. I am still fighting ASM. I can't seem to get my dat block working properly.
    DAT                                             'init
                   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                    'enables p0 - p15
                     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 outa, PinsInit                          'set pins to inital state       
                             mov dira, DirsEnabled                     'enables p0 - p15
                             
                             mov LCD_cmd, LCD_Data                    'copy lcd command to lcd data
    
                             and LCD_Data, lowWordMask                'mask off High word of 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
    
    
    
                      
                             mov    pntr, Lcd_cmd
    :wait0                   djnz   pntr, :wait0  
    WrCmd                    mov    outa, #$22
                             mov    pntr, #$f
    :wait0                   djnz   pntr, :wait0                          
                             add    zero, #0                                 wz                      
                             muxz   dira, RSpin                              
                             mov    pntr, #$f
    :wait1                   djnz   pntr, :wait1
                             muxz   dira, WritePin
                             mov    pntr, #$f
    :wait2                   djnz   pntr, :wait2                                                
                             muxnz  dira, WritePin
                             mov    pntr, #$f         
    :wait3                   djnz   pntr, :wait3                         
                             muxnz  dira, RSpin
                             mov    pntr, #$f
    :wait4                   djnz   pntr, :wait4
    
    :WrDataPortion                  
                             mov    outa, LCD_Data
                             mov    pntr, #$f                                    
    :wait5                   djnz   pntr, :wait5  
                             add    zero, #0                   wz
                             muxz   dira, WritePin
                             mov    pntr, #$f                           
    :wait6                   djnz   pntr, :wait6
                             muxnz  dira, WritePin
                             mov    pntr, #$f
    :wait7                   djnz   pntr, :wait7                         '
                             'add   asmColor,#1
                             'max    asmColor, BackgroundColorASM
                             mov    pntr, #$f
    :wait8                   djnz   pntr, :wait8
                             mov    dira, DirsDisabled                 'disables p0 - p15
                             wrlong zero, bufferaddress                        
                      jmp #Get
    
    
    
    zero                              long $0
    lowWordMask                       long $0000_ffff
    
    WritePin                          long   %00000000_00000010_00000000_00000000
    RSPin                             long   %00000000_00000001_00000000_00000000                                          
    PinsInit                          long   %00000000_00000000_00000000_00000000
    DirsDisabled                      long   %00000000_00000000_00000000_00000000
    DirsEnabled                       long   %00000000_00000000_11111111_11111111
    bufferaddress           res 1
    
    LCD_cmd                 res 1
    LCD_data                res 1
    Pntr                    res 1
    
    fit
    
    
    The dat block will print color data, but I'm still trying to get everything working properly. Writes are a bit faster.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2012-02-24 18:35
    Sorry to hijack for a post, but I can't seem to get my screen to do anything but light up the backlight. I have wired up my screen directly to the Prop according to the schematic in post #1 and am using the test code from post #2. The Screen is one of these :

    http://www.ebay.com/itm/2-4-TFT-LCD-Module-Display-Touch-Panel-PCB-adapter-/190477028273?pt=LH_DefaultDomain_0&hash=item2c5950cbb1

    There are 8 connections I do not have connected on the 40 pin connector (An old 40 pin hard drive connector).
    The 8 pins not connected are :
    Pin 3 - Not Used
    Pin 16 - F_CS
    Pin 18 - Not Used
    Pin 20 - Not Used
    Pin 32 - D_BUSY
    Pin 34 - D_Penirq (Not sure what this is)
    Pin 39 - F_WP
    Pin 40 - F_HOLD

    Is there something I am missing? I have the Data IN and Data Out pins shared on pins 24 and 25 on the Prop. No pull up or pull down resistors are in place for the LCD circuitry.
  • average joeaverage joe Posts: 795
    edited 2012-02-24 18:57
    No worries eagle, you need to change the initialization values to match those in the datasheet. They are different for your screen. That should help.
    Current version is much faster. Fully working?
    CON
      _clkmode      = xtal1 + pll16x                        ' use crystal x 16
      _xinfreq      = 5_000_000
      RS                = 16            ''PINS FOR CS - TO KEEP FROM FLOATING 
      LCD_WR            = 17
    
    
      DEV_SD_CLK    = 18
      DEV_SD_DI         = 19
      DEV_SD_DO         = 20    
      DEV_SPI_EN        = 21
      DEV_SPI_ADD0      = 22
      DEV_SPI_ADD1      = 23
      DEV_SPI_ADD_LE    = 24
    
    DEV_SPI_LCD_RES      = 0
    DEV_SPI_SDC_CS       = 1
    DEV_SPI_TSC_CS       = 2
    DEV_SPI_EXT_CS       = 3
      
    DEV_SPI_EXT_POT_CS   = 0
    DEV_SPI_EXT_SW_CS    = 1
      
    ''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                               ''                                          (R4Fh) (POR = 0000h)
    
      FONT_ROM_ADDRESS              = $8000
    
      BGCOLOR                       = $ffff
      TXTCOLOR                      = $0000
      NotPressedBGC                 = $ffff
      NotPressedATC                 = $0000
      PressedBGC                    = $0000
      PressedATC                    = $ffff
      Pressed                       = 1
      NotPressed                    = 0    
    
    VAR
    long BackgroundColor,ActiveColor, ActiveTextColor, InactiveTextColor, Row, Col, RowBorder,ColBorder, WindowX1, WindowX2, WindowY1, WindowY2
    long ScreenBuffer
          long stringptr[65]
            BYTE Fader0[3], Fader1[3], Fader2[3], Fader3[3], faderOrentation, faderpos, faderval, oldfader, ButtonName 'Fader POS, New Fader Value, Old Fader Value, FaderOrentation holds 0 for landscape, portrait not enabled
                word Button0[3], Button1[3], Button2[3], Button3[3], Button4[3], Button5[3], ButtonGroup, ButtonX, ButtonY, ButtonState
    
    obj wait : "timing"
        pst  : "parallax serial terminal"
    PUB BOOT | cr, idxr 'bootstrap
      dirA[DEV_SPI_ADD0]   := 1
      dirA[DEV_SPI_ADD1]   := 1
      dirA[DEV_SPI_EN]     := 1
      OUTA[LCD_WR]         := 0
      OUTA[RS]             := 0
      OUTA[DEV_SPI_EN]     := 1
      OUTA[DEV_SPI_ADD_LE] := 0
       PST_Init
       Init_SSD1289            
       EnableDisplayPins                           
       TristateDisplayPins     
        StartAsm
       pst.newline
       pst.str(string("Starting Asm"))
       pst.newline   
       ClearScreenAsm($ffff)
       helloworld
    deadend
    
    PUB StartAsm                            'Method to load a cog with screen driver
     long[@screenbuffer]          := $ffff                        ''make sure screen buffer does not equal 0
     cognew(@entry,@Long[@screenbuffer])                          ''start write driver and pass it the address of screen buffer
    
    PUB PST_Init  | PstCog                                       ''Starts Parallax Serial Terminal for debugging.
      PstCog := (pst.Start(115200) -1)                             '' returns the cog pst started in
      pst.Str(String("Parallax Serial Terminal started in cog "))  ''  talk to human
      pst.Dec(PstCog)                                              '' displays cog on PST                                                  ''
      wait.pause1s(1)
      
    PUB HelloWorld
        WriteActiveCrAsm(72, 0, 0*16, 0, 0, BGCOLOR, TXTCOLOR)
        WriteNextActiveCrAsm(101)
        WriteNextActiveCrAsm(108)
        WriteNextActiveCrAsm(108)
        WriteNextActiveCrAsm(111)
        WriteNextActiveCrAsm(32)
        WriteNextActiveCrAsm(87)
        WriteNextActiveCrAsm(111)
        WriteNextActiveCrAsm(114)
        WriteNextActiveCrAsm(108)
        WriteNextActiveCrAsm(100)
    
    PUB WriteNextActiveCrAsm(Character) | characterpointer, odd_even, bitpatern[32], idx, pxlidx, lcdidx, pxlidxdcd, x1, y1, x2, y2
      odd_even                      := character & $0001
      characterpointer              := character & $fffe
      characterpointer              >>= 1
      characterpointer              *= 32
       repeat idx from 0 to 31 
         bitpatern[idx] := long[FONT_ROM_ADDRESS][characterpointer + idx]
    
      y1 :=  Col + ColBorder 
      y2 := (Col + 15) - ColBorder
      x1 :=  Row + RowBorder
      x2 := (Row + 31) - RowBorder
      
         SetWindowAsm(x1, y1, x2, y2)
         SetGAddressAsm(x1,y1)
      repeat idx from RowBorder to 31 - RowBorder        
         repeat pxlidx from odd_even + (ColBorder*2) to (odd_even + 30) - (ColBorder*2) step 2
           pxlidxdcd := |< pxlidx   
           if ((bitpatern[idx] & pxlidxdcd) == pxlidxdcd)  
             Lcd_Write_Asm(ActiveTextColor + ($22 << 16))
           else
             Lcd_Write_Asm(BackgroundColor + ($22 << 16))
    
      if (((Col + 16) >  319 ) and  ((Row + 32) > 223))
        Row := 0
        Col := 0
      elseif (((Col + 16) >  319 ) and  ((Row + 32) < 223)) 
        Row := Row + 32
        Col := 0
      else
        Col := Col + 16
             
    ' SetWindow(0, 0, 239, 319)
    PUB WriteActiveCrAsm(Character, PosR, PosC, RBorder, CBorder, BgC, TxC) | characterpointer, odd_even, bitpatern[32], idx, pxlidx, lcdidx, pxlidxdcd, x1, y1, x2, y2
      odd_even                      := character & $0001
      characterpointer              := character & $fffe
      characterpointer              >>= 1
      characterpointer              *= 32
       repeat idx from RBorder to 31 - RBorder 
         bitpatern[idx] := long[FONT_ROM_ADDRESS][characterpointer + idx]
         
       Row              := PosR      
       Col              := PosC
       RowBorder        := RBorder
       ColBorder        := CBorder
       BackgroundColor  := BgC
       ActiveTextColor  := Txc
    
      y1 :=  PosC + CBorder 
      y2 := (PosC + 15) - CBorder
      x1 :=  PosR + RBorder
      x2 := (PosR + 31) - RBorder
         SetWindowAsm(x1, y1, x2, y2)
         SetGAddressAsm(x1,y1)
      repeat idx from RBorder to 31 - RBorder        
         repeat pxlidx from odd_even + (CBorder*2) to (odd_even + 30) - (CBorder*2) step 2
           pxlidxdcd := |< pxlidx   
           if ((bitpatern[idx] & pxlidxdcd) == pxlidxdcd)
             Lcd_Write_Asm(ActiveTextColor + ($22 << 16))
           else        
             Lcd_Write_Asm(BackgroundColor + ($22 << 16))
      if (((Col + 16) >  319 ) and  ((Row + 32) > 223))
        Row := 0
        Col := 0
      elseif (((Col + 16) >  319 ) and  ((Row + 32) < 223)) 
        Row := Row + 32
        Col := 0
      else
        Col := Col + 16
     return
    
    PUB ClearScreenAsm(color) | idxr, idxc
      SetWindowAsm(0, 0, 239, 319)
      SetGAddressAsm(0,0)
      color += ($22 << 16)
      repeat idxr from 0 to 76800           
          Lcd_Write_Asm(Color)
    Row              := 0      
    Col              := 0
    
    PUB SetWindowAsm(x1, y1, x2, y2) | HORIZONTALRAMADDRESSPOS 
     WindowX1 := x1
     WindowX2 := x2
     WindowY1 := y1
     WindowY2 := y2
        HORIZONTALRAMADDRESSPOS := x1 + (x2 << 8)                                                                                                    
           Lcd_Write_Asm ($0044_0000 + HORIZONTALRAMADDRESSPOS)
           Lcd_Write_Asm(y1 + $0045_0000)
           Lcd_Write_Asm(y2 + $0046_0000)
           
    PUB SetGAddressAsm(x,y)
           Lcd_Write_Asm ($004E_0000 + x) ''max %1111_1111, $FF
           Lcd_Write_Asm ($004F_0000 + y) ''max %1_0011_1111, $13f
                                                                                ''                                          (R4Eh) (POR = 0000h)                               
    PUB EnableDisplayPins
        DIRA:=%00000001_11100000_11111111_11111111 ' , Reset, WR, RS and 16 data lines active    
    PUB TristateDisplayPins ' tristate all pins -                                                 
        DIRA:=%00000001_11100000_00000000_00000000 ''
    
    PRI Lcd_Write_Asm(V)                                   'handler for asm writes
         repeat while (screenbuffer <> 0)
      long[@screenbuffer] := V                         'makes screen buffer = v
        
    PRI LCD_Writ_Bus(V) 
        OUTA[15..0]  := V
        WriteLow                                            ' write pin low
        WriteHigh                                           ' toggle write pin
    PRI Lcd_Write_Com(V)
        RSLow
        LCD_Writ_Bus(V)
    PRI Lcd_Write_Data(V)
        RSHigh
        LCD_Writ_Bus(V)  
    PRI RSLow                                        
        dira[RS] := 1
    PRI RSHigh
        dira[RS] := 0                 '
    PRI WriteLow                                    
        dira[LCD_WR] := 1                             ' 
    PRI WriteHigh
        dira[LCD_WR] := 0
    
    pub deadend
    repeat
       wait.pause1s(1)
    PUB Init_SSD1289                                        ''Init Display
        EnableDisplayPins                                   ''enable pins 0 to 15
        ' WriteHigh
        
        'LCD_Reset                                          ''reset screen
        'wait.pause1ms(5)                                      
        'LCD_Reset          ''then init screen
        'wait.pause1ms(5)
        Lcd_Write_Com (REG_DISPLAYCONTROL)                  ''Display Control (R07h) (POR = 0000h) 
        Lcd_Write_Data($0021)                               ''GON = 1 DTE = 0 D[1:0] = 01
        
        Lcd_Write_Com (REG_OSCILLATOR)                      ''Oscillator (R00h) (POR = 0000h)
        Lcd_Write_Data($0001)                               ''Turn on oscillator
        
        Lcd_Write_Com (REG_DISPLAYCONTROL)                  ''Display Control (R07h) (POR = 0000h)
        Lcd_Write_Data($0023)                               ''GON = 1 DTE = 0 D[1:0] = 11
                
        Lcd_Write_Com (REG_SLEEPMODE)                       ''Sleep mode (R10h) (POR = 0001h)
        Lcd_Write_Data($0000)     ''                        ''exit sleep mode
        
        Lcd_Write_Com (REG_DISPLAYCONTROL)                  ''Display Control (R07h) (POR = 0000h)
        Lcd_Write_Data($0033)                               ''GON = 1 DTE = 1 D[1:0] = 11
        
        Lcd_Write_Com (REG_ENTRYMODE)                       ''Entry Mode (R11h) (POR = 6830h)
        Lcd_Write_Data($6838)                               ''
        
        Lcd_Write_Com (REG_LCDDRIVINGWAVFORM)               ''LCD-Driving-Waveform Control (R02h) (POR = 0000h)($1000) 
        Lcd_Write_Data($1000)     ''                        ''
        
        Lcd_Write_Com (REG_GATESCANPOSITION)                ''Gate Scan Position (R0Fh) (POR = 0000h)  ($0000)
        Lcd_Write_Data($0000)     ''                        ''
                                            ''
        Lcd_Write_Com (REG_DRIVEROUTPUTCONTROL)             ''Driver Output Control (R01h) (POR = [0XXXX0X1]3Fh) 433f    ($633F) 
        Lcd_Write_Data($6B3F) ''                            ''
                                        
        Lcd_Write_Com (REG_FRAMECYCLECONTROL)               ''Frame Cycle Control (R0Bh) (POR = 5308h) ($5308)
        Lcd_Write_Data($5308)                               ''
                '
        Lcd_Write_Com (REG_DISPLAYCONTROL)                  ''Display Control (R07h) (POR = 0000h) ($0033)
        Lcd_Write_Data($0033)                               ''GON = 1 DTE = 1 D[1:0] = 11 
    
        'TristateDisplayPins
       'deadend
    
    
    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                    'enables p0 - p15
                     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 outa, PinsInit                          'set pins to inital state       
                             mov dira, DirsEnabled                     'enables p0 - p15
                             
                             mov LCD_cmd, LCD_Data                    'copy lcd command to lcd data
    
                             and LCD_Data, lowWordMask                'mask off High word of 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
                      
                             mov    pntr, #$f                          'set wait period
    :wait0                   djnz   pntr, :wait0                       'and wait
    WrCmd                    mov    outa, LCD_Cmd                  'place LCD_Cmd on write bus
                             mov    pntr, #$f                           '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, #$f                           'set wait period
    :wait1                   djnz   pntr, :wait1                        'and wait 
                             muxz   dira, WritePin                 'make Write Pin low by enabling its DIR REG
                             mov    pntr, #$f                           'set wait period
    :wait2                   djnz   pntr, :wait2                        'and wait               
                             muxnz  dira, WritePin                 'make Write Pin high by disabling its DIR REG
                             mov    pntr, #$f                           'set wait period
    :wait3                   djnz   pntr, :wait3                        'and wait
                             muxnz  dira, RSpin                    'make RS pin high by disabling its DIR REG
                             mov    pntr, #$f                           'set wait period
    :wait4                   djnz   pntr, :wait4                        'and wait
    
    :WrDataPortion                                                 
                             mov    outa, LCD_Data                 'place LCD_Data on write bus
                             mov    pntr, #$f                           '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
                             mov    pntr, #$f                           'set wait period
    :wait6                   djnz   pntr, :wait6                        'and wait
                             muxnz  dira, WritePin                  'make Write Pin high by disabling its DIR REG
                             mov    pntr, #$f                           'set wait period
    :wait7                   djnz   pntr, :wait7                        'and wait
                             mov    pntr, #$f                           'set wait period 
    :wait8                   djnz   pntr, :wait8                        'and wait
                             mov    dira, DirsDisabled                 'disables p0 - p15
                             wrlong zero, bufferaddress                        
                      jmp #Get                              'do it all again
    
    
    
    zero                              long $0
    lowWordMask                       long $0000_ffff
    
    WritePin                          long   %00000000_00000010_00000000_00000000
    RSPin                             long   %00000000_00000001_00000000_00000000                                          
    PinsInit                          long   %00000000_00000000_00000000_00000000
    DirsDisabled                      long   %00000000_00000000_00000000_00000000
    DirsEnabled                       long   %00000000_00000000_11111111_11111111                                                                           ''                                          (R4Fh) (POR = 0000h)
    
    
    bufferaddress           res 1
    
    LCD_cmd                 res 1
    LCD_data                res 1
    Pntr                    res 1
    
    
  • eagletalontimeagletalontim Posts: 1,399
    edited 2012-02-24 19:28
    Would the initialization values be these :
    REG_OSCILLATOR                = $0000                               ''Oscillator                                (R00h) (POR = 0000h)
    REG_DRIVEROUTPUTCONTROL       = $0001                               ''Driver Output Control                     (R01h) (POR = 2B3Fh)
    REG_LCDDRIVINGWAVFORM         = $0002 
    ...
    

    I am terrible at understanding datasheets! Hopefully I can find the right one. I actually bought the screen from here :

    http://iteadstudio.com/store/index.php?main_page=product_info&cPath=57_58&products_id=55

    But..... It is also on Ebay for cheaper. Same screen though.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2012-02-24 19:49
    I think I found the right area to get the information for the initialization, but I don't really know what I am looking at. The code has hex but the datasheet does not have a hex value from what I can see. I have attached the PDF for the screen that I have. On page 55 is the LCD Driving Wave Control (R02h). Where or how do I get the value from this to put in the code you posted above?
  • blittledblittled Posts: 681
    edited 2012-02-24 19:52
    @eagletalontim
    Thanks for the link. There's a lot of good info there and will help me in my design. It is interesting that it says it only handles 8 bit mode. Has anyone had trouble interfacing 16 bit data? Also I was thinking if the problems with the SD cards is because it is expecting 5V rather than 3.3V since it has series resistors.

    Edit : eagletalontim look at http://www.rayslogic.com/Propeller/Products/Psm/psm.htm. You'll find Prop code for initialization of the LCD screen there. Also I have attached an pdf with the c code to run this
  • average joeaverage joe Posts: 795
    edited 2012-02-24 19:58
    I've played with the sd card a bit, and still no luck. Even with an external breakout. I think I have incompatible cards. If you give me a few I'll check into the datasheet. I don't know if you'll have luck using my code if your display is only 8-bit. You might check with Dr. A as I think he has the same screen. I would start with his initialization values. Let me see if I can find them.
    .
    *edit*
     From Dr. Acula's initalization. Format is Command, Data. 
              ' ************* Start Initial Sequence **********
        ILIcmd($00E5,$78F0)                          ' set SRAM internal timing
        ILIcmd($0001,$0100)                        ' set SS and SM bit 0001 0100   portrait
        ILIcmd($0002,$0700)                          ' set 1 line inversion 
        ILIcmd($0003,$1030)                        ' set GRAM write direction and BGR=1. $0003 $1030
        ILIcmd($0004,$0000)                          ' Resize register 
        ILIcmd($0008,$0207)                          ' set the back porch and front porch 
        ILIcmd($0009,$0000)                          ' set non-display area refresh cycle ISC[3:0]  
        ILIcmd($000A,$0000)                          ' FMARK function  
        ILIcmd($000C,$0000)                          ' RGB interface setting   
        ILIcmd($000D,$0000)                          ' Frame marker Position   
        ILIcmd($000F,$0000)                          ' RGB interface polarity  
    '        *************Power On sequence ****************//
        ILIcmd($0010,$0000)                         ' SAP, BT[3:0], AP, DSTB, SLP, STB 
        ILIcmd($0011,$0007)                         ' DC1[2:0], DC0[2:0], VC[2:0] 
        ILIcmd($0012,$0000)                         ' VREG1OUT voltage   
        ILIcmd($0013,$0000)                         ' VDV[4:0] for VCOM amplitude  
        ILIcmd($0007,$0001)   
        wait.pause1ms(50)                                   ' Dis-charge capacitor power voltage
        ILIcmd($0010,$1090)                         ' 1490//SAP, BT[3:0], AP, DSTB, SLP, STB   
        ILIcmd($0011,$0227)                         ' DC1[2:0], DC0[2:0], VC[2:0] 
        wait.pause1ms(50)                                   ' delay
        ILIcmd($0012,$001F)                         ' 001C// Internal reference voltage= Vci;
        wait.pause1ms(50)                                   ' delay   
        ILIcmd($0013,$1500)                         ' $1000//1400   Set VDV[4:0] for VCOM amplitude  1A00  
        ILIcmd($0029,$0027)                         ' $0012 //001a  Set VCM[5:0] for VCOMH  //$0025  0034  
        ILIcmd($002B,$000D)                         ' Set Frame Rate   000C       
        wait.pause1ms(50)                                   ' delay   
        ILIcmd($0020,$0000)                         ' GRAM horizontal Address   
        ILIcmd($0021,$0000)                         ' GRAM Vertical Address    
    '         ----------- Adjust the Gamma Curve ----------//
        ILIcmd($0030,$0000) 
        ILIcmd($0031,$0707)  
        ILIcmd($0032,$0307)  
        ILIcmd($0035,$0200)  
        ILIcmd($0036,$0008)  
        ILIcmd($0037,$0004)  
        ILIcmd($0038,$0000)  
        ILIcmd($0039,$0707)  
        ILIcmd($003C,$0002)  
        ILIcmd($003D,$1D04)  
    '        ------------------ Set GRAM area ---------------//
        ILIcmd($0050,$0000)  ' Horizontal GRAM Start Address
        ILIcmd($0051,$00EF)  ' Horizontal GRAM End Address       
        ILIcmd($0052,$0000) ' Vertical GRAM Start Address    
        ILIcmd($0053,$013F) ' Vertical GRAM Start Address       
        ILIcmd($0060,$A700) ' Gate Scan Line     
        ILIcmd($0061,$0001) ' NDL,VLE, REV    
        ILIcmd($006A,$0000) ' set scrolling line      
    '        -------------- Partial Display Control ---------/
        ILIcmd($0080,$0000)
        ILIcmd($0081,$0000)
        ILIcmd($0082,$0000)
        ILIcmd($0083,$0000)
        ILIcmd($0084,$0000)
        ILIcmd($0085,$0000)
    '        //-------------- Panel Control -------------------//
        ILIcmd($0090,$0010)
        ILIcmd($0092,$0600)
        ILIcmd($0007,$0133)  ' 262K color and display ON
    
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-02-24 20:08
    @eagletalontim - sorry this is not so easy. I have a board on the way which hopefully will be a 'plug and play' affair but until that arrives, average joe and me are not even using the same schematic.

    I don't understand any of the startup code either and I started off with only C code to work with, so I'll document how I got the display working.

    First thing was to just work on the display, so forget about the SD card and the touchscreen.

    5V, 0V, 16 data lines and 5 control lines.

    Of those control lines, I am not sure which ones you can leave out. I'm pretty sure now that /rd is not needed. But I see that average joe has left out /cs and I don't know about that one.

    So let's say 4 control lines, and tie /rd high.

    I then coded some spin code to set each of these high and each of these low. Things like ResetHigh, and ChipSelectLow. 8 PUB routines in total. I then tested each of those with a LED on the appropriate pin. Did the code do what it was supposed to?

    I then worked on the data lines.
    PRI LCD_Writ_Bus(VH,VL) 
        OUTA[7..0]  := VL
        OUTA[15..8] := VH
        WriteLow                                            ' write pin low
        WriteHigh                                           ' toggle write pin
    

    Comment out the writelow and writehigh for the moment and put a "repeat" there instead so the program hangs.

    Now pass some numbers in VH and VL and see if the pins do what they are supposed to. I used Windows Calculator a lot to convert numbers to binary. Pick a random number, work out its binary, send it out and then check with a logic probe the pins are as they are supposed to be.

    Then remove that 'repeat' and put back in the writelow writehigh.

    add this code
    PRI ILIcmd(c,d)  ' instruction in one method
        Lcd_Write_Com(c >> 8,c & 255) ' split a word into two bytes, send command then data
        Lcd_Write_Data(d >> 8,d & 255)
    
    PRI Lcd_Write_Com(VH,VL)
        RSLow
        LCD_Writ_Bus(VH,VL)
    
    PRI Lcd_Write_Data(VH,VL)
        RSHigh
        LCD_Writ_Bus(VH,VL)   
    

    Then try dropping in this startup code.
    PUB Start_ILI9325 ' pass orientation true = portrait, false = landscape
        DisplayPins := %00000000_00000000_00000000_00000000 ' store the status of the display pins
        ResetHigh
        wait.pause1ms(5)
        ResetLow
        wait.pause1ms(5)
        ResetHigh
        ChipSelectHigh
        ReadHigh
        WriteHigh
        wait.pause1ms(5)
        ChipSelectLow
              ' ************* Start Initial Sequence **********
        ILIcmd($00E5,$78F0)                          ' set SRAM internal timing
        ILIcmd($0001,$0100)                        ' set SS and SM bit 0001 0100   portrait
        ILIcmd($0002,$0700)                          ' set 1 line inversion 
        ILIcmd($0003,$1030)                        ' set GRAM write direction and BGR=1. $0003 $1030
        ILIcmd($0004,$0000)                          ' Resize register 
        ILIcmd($0008,$0207)                          ' set the back porch and front porch 
        ILIcmd($0009,$0000)                          ' set non-display area refresh cycle ISC[3:0]  
        ILIcmd($000A,$0000)                          ' FMARK function  
        ILIcmd($000C,$0000)                          ' RGB interface setting   
        ILIcmd($000D,$0000)                          ' Frame marker Position   
        ILIcmd($000F,$0000)                          ' RGB interface polarity  
    '        *************Power On sequence ****************//
        ILIcmd($0010,$0000)                         ' SAP, BT[3:0], AP, DSTB, SLP, STB 
        ILIcmd($0011,$0007)                         ' DC1[2:0], DC0[2:0], VC[2:0] 
        ILIcmd($0012,$0000)                         ' VREG1OUT voltage   
        ILIcmd($0013,$0000)                         ' VDV[4:0] for VCOM amplitude  
        ILIcmd($0007,$0001)   
        wait.pause1ms(50)                                   ' Dis-charge capacitor power voltage
        ILIcmd($0010,$1090)                         ' 1490//SAP, BT[3:0], AP, DSTB, SLP, STB   
        ILIcmd($0011,$0227)                         ' DC1[2:0], DC0[2:0], VC[2:0] 
        wait.pause1ms(50)                                   ' delay
        ILIcmd($0012,$001F)                         ' 001C// Internal reference voltage= Vci;
        wait.pause1ms(50)                                   ' delay   
        ILIcmd($0013,$1500)                         ' $1000//1400   Set VDV[4:0] for VCOM amplitude  1A00  
        ILIcmd($0029,$0027)                         ' $0012 //001a  Set VCM[5:0] for VCOMH  //$0025  0034  
        ILIcmd($002B,$000D)                         ' Set Frame Rate   000C       
        wait.pause1ms(50)                                   ' delay   
        ILIcmd($0020,$0000)                         ' GRAM horizontal Address   
        ILIcmd($0021,$0000)                         ' GRAM Vertical Address    
    '         ----------- Adjust the Gamma Curve ----------//
        ILIcmd($0030,$0000) 
        ILIcmd($0031,$0707)  
        ILIcmd($0032,$0307)  
        ILIcmd($0035,$0200)  
        ILIcmd($0036,$0008)  
        ILIcmd($0037,$0004)  
        ILIcmd($0038,$0000)  
        ILIcmd($0039,$0707)  
        ILIcmd($003C,$0002)  
        ILIcmd($003D,$1D04)  
    '        ------------------ Set GRAM area ---------------//
        ILIcmd($0050,$0000)  ' Horizontal GRAM Start Address
        ILIcmd($0051,$00EF)  ' Horizontal GRAM End Address       
        ILIcmd($0052,$0000) ' Vertical GRAM Start Address    
        ILIcmd($0053,$013F) ' Vertical GRAM Start Address       
        ILIcmd($0060,$A700) ' Gate Scan Line     
        ILIcmd($0061,$0001) ' NDL,VLE, REV    
        ILIcmd($006A,$0000) ' set scrolling line      
    '        -------------- Partial Display Control ---------/
        ILIcmd($0080,$0000)
        ILIcmd($0081,$0000)
        ILIcmd($0082,$0000)
        ILIcmd($0083,$0000)
        ILIcmd($0084,$0000)
        ILIcmd($0085,$0000)
    '        //-------------- Panel Control -------------------//
        ILIcmd($0090,$0010)
        ILIcmd($0092,$0600)
        ILIcmd($0007,$0133)  ' 262K color and display ON
    
  • average joeaverage joe Posts: 795
    edited 2012-02-24 20:13
    For my display, cs is not needed. My module seems to be fine without reset. YMMV. I would like to pick up one the the 2.4"s so I could work on that too. One place I found an optimization * or maybe not* is using 10k pullups on WR and RS lines. In spin it doesn't seem to matter, but in asm, it cuts out a few instructions per write.

    Dr A has a good method to get up and running. I actually used his code to develop a template for mine. I changed the initialization values for the display, and then modified his writing method.
    PRI LCD_Writ_Bus(V) 
        OUTA[15..0]  := V
        WriteLow                                            ' write pin low
        WriteHigh                                           ' toggle write pin
    PRI Lcd_Write_Com(V)
        RSLow
        LCD_Writ_Bus(V)
    PRI Lcd_Write_Data(V)
        RSHigh
        LCD_Writ_Bus(V)  
    PRI RSLow                                               'these are for pullup version, non pullup will be                      
        dira[RS] := 1        'outa[RS] := 0
    PRI RSHigh                                              'these are for pullup version, non pullup will be
        dira[RS] := 0         'outa[RS] := 1       
    PRI WriteLow                                             'these are for pullup version, non pullup will be
        dira[LCD_WR] := 1   'outa[LCD_WR] := 0                          ' 
    PRI WriteHigh                                              'these are for pullup version, non pullup will be
        dira[LCD_WR] := 0     'outa[LCD_WR] := 1
    
    This could be modified for 8 bit writes if necessary.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2012-02-24 21:05
    How far away can the display be from the prop? I have an old HD cable which I cut about 2 inches away from the connector and tinned all the tips to it will plug into my bread board. The pins are connected right at the prop pins. What I would like to do is to add a few more inches for testing purposes to the pins from the header so I can plug them into a different area away from the prop and run single wires to where they need to go for the display. This will help clean my breadboard up so debugging will be easier. Since I am connecting all the display pins directly to the prop, I will have to redo quite a bit of the code Dr_Acula is using since he is using latches. That is the point where I get lost :(
  • average joeaverage joe Posts: 795
    edited 2012-02-24 21:50
    I will be writing compatible drivers for Dr. A's stuff soon. Real soon. I'm not sure what the limit would be, but I'm using an old HD cable *they work as long as they're the 40 pin cables, the 80's don't to my knowledge* and I have about 2" + between the display and my propRPM. I would say you'll be fine.
    I've got ASM running good.

    *Edit*
    Here's version 2! It runs pretty fast and can be optimized further.
    Program: 345 Longs
    Variable: 17 Longs
    not too bad!
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-02-24 22:00
    How far away can the display be from the prop?

    For spin, it could be 50cm or more. Pasm might need shorter distances, but spin is slower so distance should not be a problem. My display is 10cm from the prop.

    Start with the reset line. Write some code to make that line high, then wait 1ms then low, wait 1ms, then high again. Change the delay to 1 second for debugging. Put a led on that pin, and run the code. That should reset the display which should get something to change on the display.
  • average joeaverage joe Posts: 795
    edited 2012-02-24 22:17
    Dr A, have you changed your low level writes yet?
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-02-24 22:24
    Not in pasm, no. In spin, it is standard spin "turn a led on, turn a led off" code for the 4 control lines, and then send out a word on 16 prop pins which is your code.

    For pasm, the code I'm going to be writing for the new board will be very different. The design uses a ram chip and was built to transfer data from the ram chip to the display as fast as possible, with the transfer speed between the prop and ram a secondary consideration. So there is a bus between ram and the display, and there are some isolating 245 buffer chips so that bus is independent of the propeller.

    If it doesn't work - back to the drawing board. If it does work, well I'm getting 10 boards made so some could be available for others to test out...
  • average joeaverage joe Posts: 795
    edited 2012-02-24 23:07
    OK, I will be playing around with some compatibility issues. I am currently trying to figure out the RIGHT way to do this...
    So, I my "terminal" object *MAIN* to create an area in main memory, and pass that address to another object *PFW*, which starts the cog that loads the data from main memory.
    var Screen_Buffer
    pub init
    ...do something
    long[@Screen_Buffer]          := $ffff                        'make sure screen buffer does not equal 0  
       pfw.Start(@Long[@Screen_Buffer])                         'Start Asm Driver, needs to be changed to pass screen buffer from top object
    ....do more
    
    that's the main object and it's call, the pfw object is
    var long screenbufferaddress
    PUB Start(ScreenBufferAdd)             'Method to Init display, then load a cog with screen driver
       screenbufferaddress   := ScreenBufferAdd                'store buffer address in long
     Init_SSD1289
                                               'init screen
      
     result := cognew(@entry,ScreenBufferAdd ])                          'start write driver and pass it the address of screen buffer
    
    PRI Lcd_Write_Asm(V)                                   'handler for asm writes
         repeat while (long[@screenbufferaddress] <> 0)                        'waits for cog to clear screenbuffer
      long[@screenbufferaddress] := V                                        'makes screen buffer = v
    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                    'enables p0 - p15
                     wrlong zero, bufferaddress                   'set par to zero to confirm load done
    
    ...do more
    
    what is the RIGHT way to pass this address. I'm lost.
  • kuronekokuroneko Posts: 3,623
    edited 2012-02-24 23:42
    ... what is the RIGHT way to pass this address. I'm lost.
    There is no right way. See example below. For easier testing I kept the start method in the same file. It can easily be moved to a different object (then you'll have to un-comment the {pfw.} bit). The main program is only allowed to continue (toggling an LED) when the PASM part gets the right value (42).
    VAR
      long  screen
    
    PUB null
    
      screen := 42                                          ' start not equal zero
     [COLOR="orange"]{pfw.}[/COLOR]start(@screen)                                   ' communicate address
      repeat while screen                                   ' wait until it reached PASM
    
      dira[16]~~
      repeat
        !outa[16]
        waitcnt(clkfreq/2 + cnt)
        
    [COLOR="blue"]PUB start(address)
    
      cognew(@entry, address)
    
    DAT             org     0
    
    entry           rdlong  temp, par               ' par == @screen (4n limitation)
    
                    cmp     temp, #42 wz
            if_e    wrlong  zero, par               ' release caller if ID checks out
    
                    waitpeq $, #0                   ' stop
    
    temp            res     1
    
                    fit
    
    CON
      zero = $1F0   ' par
      
    DAT[/COLOR]
    
  • average joeaverage joe Posts: 795
    edited 2012-02-25 05:23
    Thanks! That was a HUGE help. I'm still trying to get the hang of PASM. I have raw data writes being processed in spin, now to implement a buffer and do some other optimizations. I am very happy with the results so far. Offloading writes improved performance quite a bit, even being controlled from spin. Now to push the reading of pixel data into the cog. I think I can eek some more performance from this driver. It is about twice as fast as it was when drawing a blank screen. Text generation is still slow.
  • average joeaverage joe Posts: 795
    edited 2012-02-25 12:49
    *Edit* Added video and fixed code

    [video=youtube_share;_w6VCS-_8X0]
    I got some stuff working, but there may be bugs still. It display characters correctly I think. It's a start, I still need to get fifo's working...
    TOF object
    CON
    {''Hardware version 2.11 - see diagram.
    ''
    }                                 
      DEV_SPI_EN        = 21                               ''SPI Enable enumeration
      DEV_SPI_ADD0      = 22                               ''Device address 0 enumeration
      DEV_SPI_ADD1      = 23                               ''Device address 1 enumeration
      DEV_SPI_LCD_RES   = 0                 ''Device id for LCD reset
      
     _clkmode       = xtal1 + pll16x                        ' use crystal x 16
     _xinfreq       = 5_000_000                             'with 5mhz crystal
    
      BGCOLOR                       = $ffff
      TXTCOLOR                      = $0000
       Pressed                       = 1
      NotPressed                    = 0
    VAR
     long Screen_Buffer, CRbuffer
       long BackgroundColor, ActiveTextColor, stringptr[65]
    
       BYTE Fader0[3], Fader1[3], Fader2[3], Fader3[3], faderOrentation, faderpos, faderval, oldfader 'Fader POS, New Fader Value, Old Fader Value, FaderOrentation holds 0 for landscape, portrait not enabled 
    OBJ pfw :"PropFont_asmDone"
         'wait : "timing"
    
               
    PUB BOOT   | f                       'bootstrap, initalizes pins, then starts pst, init display, start asm, clear screen and display hello world
      dirA[DEV_SPI_ADD0]   := 1             'makes address 0 and 1          
      dirA[DEV_SPI_ADD1]   := 1             'outputs
      dirA[DEV_SPI_EN]     := 1             'and enable an output as well
    OUTA[DEV_SPI_ADD1..DEV_SPI_ADD0] := 3 
      'OUTA[LCD_WR]         := 0            'prime WR pin
      'OUTA[LCD_RS]         := 0            'and RS pin, probably not needed.
      OUTA[DEV_SPI_EN]     := 1             'Disable - Reset Screen
        'wait.pause1s(5)                                 
       ''PST_Init                          'Start Parallax Serial Terminal
    BackgroundColor := $ffe0
    ActiveTextColor := %0000  
     long[@Screen_Buffer]          := $ffff                        'make sure screen buffer does not equal 0  
       pfw.Start(@Long[@Screen_Buffer])                         'Start Asm Driver, needs to be changed to pass screen buffer from top object
       '' pst.newline                                  
       ''pst.str(string("Starting Asm"))             'Talk to human
       ''pst.newline
       dirA[DEV_SPI_EN]     := 1   
        OUTA[DEV_SPI_EN]     := 1             'Disable - Reset Screen 
       pfw.ClearScreen(BackgroundColor)            'Draw White Screen with asm
       helloworld                       'draw hello world
      {Fader.}FaderTest
      '{Button.}ButtonTest
      FaderRun
      deadend                            'hold cog in endless loop
    PUB HelloWorld
        pfw.WriteActiveCr("H", 0, 0*16, 0, 0, BackgroundColor, ActiveTextColor)    
        pfw.WriteNextActiveCr("e")
        pfw.WriteNextActiveCr("l")
        pfw.WriteNextActiveCr("l")
        pfw.WriteNextActiveCr("o")
        pfw.WriteNextActiveCr(" ")
        pfw.WriteNextActiveCr("W")
        pfw.WriteNextActiveCr("o")
        pfw.WriteNextActiveCr("r")
        pfw.WriteNextActiveCr("l")
        pfw.WriteNextActiveCr("d")
    pub deadend                                                               'loop for testing
      repeat                                                                             'endlessly wait
        repeat
         waitcnt(2_000 + cnt)
    
    PUB FaderTest | F , b
    Fader0[0] :=255
    Fader0[1] := 0
    Fader0[2] := 2
    
    Fader1[0] := 0
    Fader1[1] := 0
    Fader1[2] := 54
    
    Fader2[0] := 126
    Fader2[1] := 126
    Fader2[2] := 106
    
    Fader3[0] := 192
    Fader3[1] := 192
    Fader3[2] := 161
    
     REPEAT f from 0 to 3
         SetFader(F)
         DrawFader
    
    
    PUB SetFader(FaderNumber)
     case FaderNumber
        0: faderval :=  Fader0[0]
           oldfader :=  Fader0[1]
           faderpos :=  Fader0[2]
           
        1: faderval :=  Fader1[0]
           oldfader :=  Fader1[1]
           faderpos :=  Fader1[2]
           
        2: faderval :=  Fader2[0]
           oldfader :=  Fader2[1]
           faderpos :=  Fader2[2]
           
        3: faderval :=  Fader3[0]
           oldfader :=  Fader3[1]
           faderpos :=  Fader3[2]
          
    PUB UpdateFader 'layer 2               
      if oldfader<> faderval
        pfw.WriteActiveCr(6, faderpos, 2, 7, 0, BackgroundColor, ActiveTextColor)
        pfw.WriteActiveCr(7, faderpos, 301, 7, 0, BackgroundColor, ActiveTextColor)
      
       pfw.WriteActiveCr(32, faderpos, oldfader + 24, 4, 3, BackgroundColor, ActiveTextColor)
       pfw.WriteActiveCr(14, faderpos, faderval + 24, 4, 3, BackgroundColor, ActiveTextColor)
      
    PUB DrawFader |index                'layer 1
    
      pfw.WriteActiveCr(1, faderpos, 0, 0, 0, BackgroundColor, ActiveTextColor)
      pfw.WriteActiveCr(9, faderpos, 7, 0, 0, BackgroundColor, ActiveTextColor)
       
         REPEAT 18
           pfw.WriteNextActiveCr(13)
        
        pfw.WriteActiveCr(1, faderpos, 297, 0, 0, BackgroundColor, ActiveTextColor)
        pfw.WriteActiveCr(9, faderpos, 304, 0, 0, BackgroundColor, ActiveTextColor)
    
        pfw.WriteActiveCr(6, faderpos, 2, 7, 0, BackgroundColor, ActiveTextColor)
        pfw.WriteActiveCr(7, faderpos, 301, 7, 0, BackgroundColor, ActiveTextColor)
      
        pfw.WriteActiveCr(32, faderpos, oldfader + 24, 4, 2, BackgroundColor, ActiveTextColor)
        pfw.WriteActiveCr(14, faderpos, faderval + 24, 4, 3, BackgroundColor, ActiveTextColor)
    
    
    PUB FaderRun | f
      repeat
         REPEAT f from 0 to 3
           SetFader(F)
           UpdateFader
        Fader0[1] := Fader0[0]
        Fader0[0] -= 1       
    
    This is CrReader, thanks Kuroneko
    CON
      zero = $1F0   ' par
    var
      long  command, cog
      word  font[32]
        
    PUB null
    '' This is not a top level object.
    PUB Start
      result := cog := cognew(@fillchar, @command) + 1        ' start cog     
    PUB GetChar(c) 
      command := $200|c.byte{0}                             ' query bitmap
      repeat                                                ' |
      while command                                         ' wait for completion
      return @font{0}
        
    DAT             org     0
    
    fillchar        mov     addr, par               ' @font[0]
    :idle           rdlong  char, par wz
            if_z    jmp     #$-1
    
                    mov     temp, char              ' where to begin
                    shr     temp, #1                '  2 chars/long
                    shl     temp, #7                ' 32 longs/char
    
                    test    char, #1 wc
                    muxnc   shft, #1                ' even/odd
                    
                    mov     lcnt, #32               ' 32 rows
    
    :loop           rdlong  char, temp              ' read line from ROM
                    shl     char, shft              ' adjust for even/odd
    
                    shl     char, #2 wc
                    rcl     line, #1                ' bit 15
    
                    shl     char, #2 wc
                    rcl     line, #1
    
                    shl     char, #2 wc
                    rcl     line, #1
    
                    shl     char, #2 wc
                    rcl     line, #1                ' bit 12
    
                    shl     char, #2 wc
                    rcl     line, #1
    
                    shl     char, #2 wc
                    rcl     line, #1
    
                    shl     char, #2 wc
                    rcl     line, #1
    
                    shl     char, #2 wc
                    rcl     line, #1                ' bit 8
    
                    shl     char, #2 wc
                    rcl     line, #1
    
                    shl     char, #2 wc
                    rcl     line, #1
    
                    shl     char, #2 wc
                    rcl     line, #1
    
                    shl     char, #2 wc
                    rcl     line, #1                ' bit 4
    
                    shl     char, #2 wc
                    rcl     line, #1
    
                    shl     char, #2 wc
                    rcl     line, #1
    
                    shl     char, #2 wc
                    rcl     line, #1
    
                    shl     char, #2 wc
                    rcl     line, #1                ' bit 0
    
                    wrword  line, addr              ' update hub array
                    add     addr, #2                ' advance dst
                    add     temp, #4                ' advance src
                    
                    djnz    lcnt, #:loop            ' repeat
    
                    
                    
                    wrlong  zero, par
    :chktbl         rdword  line, addr wz             'get font table and
          if_nz      jmp     #:chktbl                    'wait till character is printed
                    sub     addr, #64               ' rewind
                    jmp     #:idle     
    
    ' initialised data and/or presets
    
    addr            long    8
    shft            long    0
    
    ' uninitialised data and/or temporaries
    
    temp            res     1
    char            res     1
    lcnt            res     1
    line            res     1
    
                    fit
    
    
    Then we have propfont_asm

    CON
     ''PINS
      LCD_RS            = 16                               ''LCD RS pin
      LCD_WR            = 17                               ''LCD WR pin
       
    ''LCD REGISTER Enumeration, for SSM1289   
      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                               ''                                          (R4Fh) (POR = 0000h)
    
      FONT_ROM_ADDRESS              = $8000
    
    VAR
    long screenbufferaddress
    long BackgroundColor,ActiveColor, ActiveTextColor, InactiveTextColor, Row, Col, RowBorder,ColBorder, WindowX1, WindowX2, WindowY1, WindowY2
     
     
    
    obj wait : "timing"
        cr   : "crReader"
       'pst  : "parallax serial terminal"  'used for debugging..
    PUB BOOT                         'not a standalone object
      
    
    PUB Start(ScreenBufferAdd)             'Method to Init display, then load a cog with screen driver
       screenbufferaddress   := ScreenBufferAdd                'store buffer address in long
     Init_SSD1289                                                'init screen
     long[@screenbufferaddress]      := $ffff                        'make sure screen buffer does not equal 0
     result := cognew(@entry,@long[@screenbufferaddress])                          'start write driver and pass it the address of screen buffer
     cr.Start
     
    PUB WriteNextActiveCr(Character) | characterpointer, odd_even, bitpatern[32], idx, pxlidx, lcdidx, pxlidxdcd, x1, y1, x2, y2, fontaddress
     fontaddress := Cr.GetChar(Character)
     'odd_even                      := character & $0001
     ' characterpointer              := character & $fffe
      'characterpointer              >>= 1
      'characterpointer              *= 32
       repeat idx from 0 to 31 
         bitpatern[idx] := word[fontaddress][idx]
    
      word[fontaddress] := 0
    
       y1 :=  Col + ColBorder  
       y2:= (Col + 15) - ColBorder 
       x1 :=  Row + RowBorder
       x2:= (Row + 31) - RowBorder
      
         SetWindow(x1, y1, x2, y2)
         SetGAddress(x1,y1)
      repeat idx from RowBorder to 31 - RowBorder        
         repeat pxlidx from ColBorder to  15 - ColBorder 
           pxlidxdcd := |< pxlidx
           if ((bitpatern[idx] & pxlidxdcd) == pxlidxdcd)  
             Lcd_Write_Asm(ActiveTextColor + (REG_RAMDATAWRITE  << 16))
           else
             Lcd_Write_Asm(BackgroundColor + (REG_RAMDATAWRITE  << 16))
         repeat while word[fontaddress] := 0
    
    
      if (((Col + 16) >  319 ) and  ((Row + 32) > 223))
        Row := 0
        Col := 0
      elseif (((Col + 16) >  319 ) and  ((Row + 32) < 223)) 
        Row := Row + 32
        Col := 0
      else
        Col := Col + 16
             
    ' SetWindow(0, 0, 239, 319)
    PUB WriteActiveCr(Character, PosR, PosC, RBorder, CBorder, BgC, TxC) | characterpointer, odd_even, bitpatern[32], idx, pxlidx, lcdidx, pxlidxdcd, x1, y1, x2, y2, fontaddress
     fontaddress := Cr.GetChar(Character) 
       Row              := PosR      
       Col              := PosC
       RowBorder        := RBorder
       ColBorder        := CBorder
       BackgroundColor  := BgC
       ActiveTextColor  := Txc
       
        repeat idx from 0 to 31
         bitpatern[idx] := word[fontaddress][idx]
      word[fontaddress] := 0
          
       y1 :=  Col + ColBorder  
       y2:= (Col + 15) - ColBorder 
       x1 :=  Row + RowBorder   
       x2:= (Row + 31) - RowBorder 
      
         SetWindow(x1, y1, x2, y2)
         SetGAddress(x1,y1)
      repeat idx from RowBorder to 31 - RowBorder         
         repeat pxlidx from ColBorder to  15 - ColBorder 
           pxlidxdcd := |< pxlidx
           if ((bitpatern[idx] & pxlidxdcd) == pxlidxdcd)  
             Lcd_Write_Asm(ActiveTextColor + (REG_RAMDATAWRITE  << 16))
           else
             Lcd_Write_Asm(BackgroundColor + (REG_RAMDATAWRITE  << 16))
         repeat while word[fontaddress] := 0
      if (((Col + 16) >  319 ) and  ((Row + 32) > 223))
        Row := 0
        Col := 0
      elseif (((Col + 16) >  319 ) and  ((Row + 32) < 223)) 
        Row := Row + 32
        Col := 0
      else
        Col := Col + 16
    
    PUB ClearScreen(color) | idxr, idxc
      SetWindow(0, 0, 239, 319)
      SetGAddress(0,0)
      color += (REG_RAMDATAWRITE  << 16)
      repeat idxr from 0 to 76800           
          Lcd_Write_Asm(Color)
    Row              := 0      
    Col              := 0
    PUB SetWindow(x1, y1, x2, y2) | HORIZONTALRAMADDRESSPOS                      'Set window to draw in
     WindowX1 := x1                                                                        'update draw window in main memory
     WindowX2 := x2                                                                        'update draw window in main memory 
     WindowY1 := y1                                                                        'update draw window in main memory 
     WindowY2 := y2                                                                        'update draw window in main memory 
        HORIZONTALRAMADDRESSPOS := x1 + (x2 << 8)                                                      'combine x1 and x2 values                                                                                                  
           Lcd_Write_Asm ((REG_HORIZONTALRAMADDRESSPOS << 16) + HORIZONTALRAMADDRESSPOS)               'and write to display
           Lcd_Write_Asm(y1 + (REG_VERTICALRAMADDRESSSTART << 16))                                     'send v-address start
           Lcd_Write_Asm(y2 + (REG_VERTICALRAMADDRESSEND << 16))                                       'send v-address end
           
    PUB SetGAddress(x,y)                                                         'Set address for gddr writes
           Lcd_Write_Asm ((REG_SETGDDRXADDRESSCOUNTER << 16) + x)      ''max %1111_1111, $FF
           Lcd_Write_Asm ((REG_SETGDDRYADDRESSCOUNTER << 16) + y)      ''max %1_0011_1111, $13f
    
    PRI deadend                                                               'loop for testing
     repeat
      repeat                                                                             'endlessly wait
        wait.pause1s(1)                                                                            ''                                                                    
    PRI EnableDisplayPins                                                    'enable all pins -
        DIRA:=%00000000_00000000_11111111_11111111        ''enable p15 - p0    
    PRI TristateDisplayPins                                                  'tristate all pins -                                                 
        DIRA:=%00000000_00000000_00000000_00000000        ''release p15 - p0
    
    PRI Lcd_Write_Asm(V)                                   'handler for asm writes
         repeat while (long[@screenbufferaddress] <> 0)                        'waits for cog to clear screenbuffer
      long[@screenbufferaddress] := V                                        'makes screen buffer = v
                           
    PRI LCD_Writ_Bus(V)                   'write to display
        OUTA[15..0]  := V                       ' copy V onto pins
        WriteLow                                ' write pin low
        WriteHigh                               ' toggle write pin
    
    PRI Lcd_Write_Com(V)                    'write command to display
        LCD_RSLow                               'Sets command
        LCD_Writ_Bus(V)                         'Do write
    
    PRI LCD_Write_Data(V)                   'write data to display
        LCD_RSHigh                              'Sets data
        LCD_Writ_Bus(V)                         'do write
    
    PRI LCD_RSLow
        outa[LCD_RS] := 0                             'controls RS pin with DIR-A         
        dira[LCD_RS] := 1                       'see hardware revision
    
    PRI LCD_RSHigh                              'controls RS pin with DIR-A
        dira[LCD_RS] := 0                       'see hardware revision   
    
    PRI WriteLow
        outa[LCD_WR] := 0                          'controls WR pin with DIR-A        
        dira[LCD_WR] := 1                        'see hardware revision      ' 
    
    PRI WriteHigh                           'controls WR pin with DIR-A 
        dira[LCD_WR] := 0                        'see hardware revision 
    
    PRI Init_SSD1289                ''Init Display
    
    
     EnableDisplayPins
    
       outa[21] := 1
       dira[21] := 1
        Lcd_Write_Com (REG_DISPLAYCONTROL)                  ''Display Control (R07h) (POR = 0000h) 
        Lcd_Write_Data($0021)                               ''GON = 1 DTE = 0 D[1:0] = 01
        
        Lcd_Write_Com (REG_OSCILLATOR)                      ''Oscillator (R00h) (POR = 0000h)
        Lcd_Write_Data($0001)                               ''Turn on oscillator
        
        Lcd_Write_Com (REG_DISPLAYCONTROL)                  ''Display Control (R07h) (POR = 0000h)
        Lcd_Write_Data($0023)                               ''GON = 1 DTE = 0 D[1:0] = 11
                
        Lcd_Write_Com (REG_SLEEPMODE)                       ''Sleep mode (R10h) (POR = 0001h)
        Lcd_Write_Data($0000)     ''                        ''exit sleep mode
        
        Lcd_Write_Com (REG_DISPLAYCONTROL)                  ''Display Control (R07h) (POR = 0000h)
        Lcd_Write_Data($0033)                               ''GON = 1 DTE = 1 D[1:0] = 11
        
        Lcd_Write_Com (REG_ENTRYMODE)                       ''Entry Mode (R11h) (POR = 6830h)
        Lcd_Write_Data($6838)                               ''
        
        Lcd_Write_Com (REG_LCDDRIVINGWAVFORM)               ''LCD-Driving-Waveform Control (R02h) (POR = 0000h)($1000) 
        Lcd_Write_Data($1000)     ''                        ''
        
        Lcd_Write_Com (REG_GATESCANPOSITION)                ''Gate Scan Position (R0Fh) (POR = 0000h)  ($0000)
        Lcd_Write_Data($0000)     ''                        ''
                                            ''
        Lcd_Write_Com (REG_DRIVEROUTPUTCONTROL)             ''Driver Output Control (R01h) (POR = [0XXXX0X1]3Fh) 433f    ($633F) 
        Lcd_Write_Data($6B3F) ''                            ''
                                        
        Lcd_Write_Com (REG_FRAMECYCLECONTROL)               ''Frame Cycle Control (R0Bh) (POR = 5308h) ($5308)
        Lcd_Write_Data($5308)                               ''
                '
        Lcd_Write_Com (REG_DISPLAYCONTROL)                  ''Display Control (R07h) (POR = 0000h) ($0033)
        Lcd_Write_Data($0033)
        TristateDisplayPins                            ''Release pins
    
    'PUB PST_Init  | PstCog                                       ''Starts Parallax Serial Terminal for debugging.
    '  PstCog := (pst.Start(115200) -1)                             '' returns the cog pst started in
    '  pst.Str(String("Parallax Serial Terminal started in cog "))  ''  talk to human
    '  pst.Dec(PstCog)                                              '' displays cog on PST                                                  ''
    '  wait.pause1s(1)
    PUB HelloWorld
        WriteActiveCr("H", 0, 0*16, 0, 0, $ffff, $0000)    
        WriteNextActiveCr("e")
        WriteNextActiveCr("l")
        WriteNextActiveCr("l")
        WriteNextActiveCr("o")
        WriteNextActiveCr(" ")
        WriteNextActiveCr("W")
        WriteNextActiveCr("o")
        WriteNextActiveCr("r")
        WriteNextActiveCr("l")
        WriteNextActiveCr("d")
    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, #$8                          'set wait period
    :wait0                   djnz   pntr, :wait0                       'and wait
    
    WrCmd                    mov    outa, LCD_Cmd                  'place LCD_Cmd on write bus
    
                             mov    pntr, #$8                           '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, #$8                           '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, #$f                           'set wait period
    :wait2                   djnz   pntr, :wait2                        'and wait
                  
                             muxnz  dira, WritePin                 'make Write Pin high by disabling its DIR REG
                             
                             mov    pntr, #$8                           'set wait period
    :wait3                   djnz   pntr, :wait3                        'and wait
    
                             muxnz  dira, RSpin                    'make RS pin high by disabling its DIR REG
                            
                             mov    pntr, #$8                          '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, #$8                           '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, #$8                          'set wait period
    :wait6                   djnz   pntr, :wait6                        'and wait
    
                             muxnz  dira, WritePin                  'make Write Pin high by disabling its DIR REG
                             
                             mov    pntr, #$8                           'set wait period
    :wait7                   djnz   pntr, :wait7                        'and wait
                             'mov    dira, DirsDisabled                 'disables p0 - p15
                                                   
                      jmp #Get                              'do it all again
    
    
    
                      
    
    zero                              long $0
    lowWordMask                       long $0000_ffff
                                          'pin settings
    WritePin                          long   %00000000_00000010_00000000_00000000
    RSPin                             long   %00000000_00000001_00000000_00000000                                          
    PinsInit                          long   %00000000_00000000_00000000_00000000
    DirsDisabled                      long   %00000000_00000000_00000000_00000000
    DirsEnabled                       long   %00000000_00000000_11111111_11111111                                                                           ''                                          (R4Fh) (POR = 0000h)
    
    
    
    
    bufferaddress           res 1
    LCD_cmd                 res 1
    LCD_data                res 1
    Pntr                    res 1
    
    ForegroundFormat        res 1
    BackgroundFormat        res 1
    ForegroundScreen        res 1
    BackgroundScreen        res 1
    fit                  
    
    
    
                      
    
    zero                              long $0
    lowWordMask                       long $0000_ffff
                                          'pin settings
    WritePin                          long   %00000000_00000010_00000000_00000000
    RSPin                             long   %00000000_00000001_00000000_00000000                                          
    PinsInit                          long   %00000000_00000000_00000000_00000000
    DirsDisabled                      long   %00000000_00000000_00000000_00000000
    DirsEnabled                       long   %00000000_00000000_11111111_11111111                                                                           ''                                          (R4Fh) (POR = 0000h)
    
    
    
    
    bufferaddress           res 1
    LCD_cmd                 res 1
    LCD_data                res 1
    Pntr                    res 1
    
    ForegroundFormat        res 1
    BackgroundFormat        res 1
    ForegroundScreen        res 1
    BackgroundScreen        res 1
    fit                  
    
    writes WAY faster, and still single character? about 5 or 6 seconds to draw full screen? haven't tested much yet. Still no sd card. I think either the cable I attached *about 3'* is too long, those damn pullup resistors or the cards I have are incompat.
    1024 x 716 - 92K
  • average joeaverage joe Posts: 795
    edited 2012-02-25 15:57
    I have large and small fonts working now! Just a small test. Here's the important routines from propfontwriter
    PUB WriteNextActiveCr(Character) | characterpointer, odd_even, bitpatern[32], idx, pxlidx, lcdidx, pxlidxdcd, x1, y1, x2, y2, fontaddress
     fontaddress := Cr.GetChar(Character)
     'odd_even                      := character & $0001
     ' characterpointer              := character & $fffe
      'characterpointer              >>= 1
      'characterpointer              *= 32
       repeat idx from 0 to 31 
         bitpatern[idx] := word[fontaddress][idx]
    
      word[fontaddress] := 0
    
       y1 :=   Col + ColBorder  
       y2 :=  (Col + (15 / fontsize ) - ColBorder)      
       x1 :=   Row + RowBorder
       x2 :=  (Row + (31 / fontsize )  - RowBorder)      
      
         SetWindow(x1, y1, x2, y2)
         SetGAddress(x1,y1)
      repeat idx from RowBorder to 31 - RowBorder  step Fontsize       
         repeat pxlidx from ColBorder to  15 - ColBorder step Fontsize 
           pxlidxdcd := |< pxlidx
           if ((bitpatern[idx] & pxlidxdcd) == pxlidxdcd)  
             Lcd_Write_Asm(ActiveTextColor + (REG_RAMDATAWRITE  << 16))
           else
             Lcd_Write_Asm(BackgroundColor + (REG_RAMDATAWRITE  << 16))
         repeat while word[fontaddress] := 0
    
    
    
    if (((Col + (16 >> (fontsize -1))) >  319 ) and  ((Row + (32 >> (fontsize -1)) > 223)))
        Row := 0
        Col := 0                         
    elseif (((Col + (16 >> (fontsize -1))) >  319 ) and  ((Row + (32 >> (fontsize -1)) < 223))) 
        Row := Row + (32 >> (fontsize -1))
        Col := 0
    else
        Col := Col + (16 >> (fontsize - 1))
             
    ' SetWindow(0, 0, 239, 319)
    PUB WriteActiveCr(Character, PosR, PosC, RBorder, CBorder, BgC, TxC, size) | characterpointer, odd_even, bitpatern[32], idx, pxlidx, lcdidx, pxlidxdcd, x1, y1, x2, y2, fontaddress
     fontaddress := Cr.GetChar(Character) 
       Row              := PosR      
       Col              := PosC
       RowBorder        := RBorder
       ColBorder        := CBorder
       BackgroundColor  := BgC
       ActiveTextColor  := Txc
       Fontsize         := size
       
        repeat idx from 0 to 31
         bitpatern[idx] := word[fontaddress][idx]
      word[fontaddress] := 0
    
       y1 :=   Col + ColBorder  
       y2 :=  (Col + (15 / fontsize ) - ColBorder)      
       x1 :=   Row + RowBorder
       x2 :=  (Row + (31 / fontsize )  - RowBorder)   
      
         SetWindow(x1, y1, x2, y2)
         SetGAddress(x1,y1)
      repeat idx from RowBorder to 31 - RowBorder  step Fontsize        
         repeat pxlidx from ColBorder to  15 - ColBorder step Fontsize
           pxlidxdcd := |< pxlidx
           if ((bitpatern[idx] & pxlidxdcd) == pxlidxdcd)  
             Lcd_Write_Asm(ActiveTextColor + (REG_RAMDATAWRITE  << 16))
           else
             Lcd_Write_Asm(BackgroundColor + (REG_RAMDATAWRITE  << 16))
         repeat while word[fontaddress] := 0
    
      if (((Col + (16 >> fontsize -1)) >  319 ) and  ((Row + (32 >> (fontsize -1)) > 223)))
        Row := 0
        Col := 0
      elseif (((Col + (16 >> (fontsize -1))) >  319 ) and  ((Row + (32 >> (fontsize -1)) < 223))) 
        Row := Row + (32 >> (fontsize -1))
        Col := 0
      else
        Col := Col + (16 >> (fontsize - 1))
    
    and of course pix! And another youtube video as soon as it's uploaded.
    320 x 191 - 7K
  • kuronekokuroneko Posts: 3,623
    edited 2012-02-25 17:24
    var
      long  command, cog
      word  font[32]
        
      ...
                    
    [COLOR="red"]:chktbl         rdword  line, addr wz             'get font table and
          if_nz      jmp     #:chktbl                    'wait till character is printed[/COLOR]
    
                    sub     addr, #64               ' rewind
                    jmp     #:idle
    
    What's the purpose of this? addr points to after the font array so whether you continue or not depends on whoever controls the next two bytes. Besides why do you feel you need the sync op here? The cog only writes to the font array while you're in the GetChar method.
  • average joeaverage joe Posts: 795
    edited 2012-02-25 18:03
    That's an artifact of testing. Sorry, I thought I removed that. I have to admit it's primitive ATM. I'm working on a Character test now. Touchscreen enabled. I will make sure to clean this up. Thank you very much for your example. It streamlines in quite nicely. I am sure I can speed writes up even more, but every time I mess around with the timing, I end up breaking things. LOL
  • average joeaverage joe Posts: 795
    edited 2012-02-26 16:41
    Here's a working copy. I have just a few pictures. I still need to clean all the code up. Current SW version 3.4 and HW 3.5.
    1024 x 716 - 92K
    1024 x 612 - 66K
    1024 x 612 - 47K
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-02-26 16:59
    That looks fun!

    Little slider bars. How cool would it be to make them move when you move your finger along them?!
  • average joeaverage joe Posts: 795
    edited 2012-02-26 17:49
    I have though about it, and will probably do it. But I just put it in the analog hardware and total failure! Clock and Data? are all over the signal. There's also some bugs. I want to turn the faders and buttons into objects, but there's a ton of work there. Including changing orientation and making them hold their own TouchScreen bounds. I've gotta take a second look at the hardware now :(
  • average joeaverage joe Posts: 795
    edited 2012-02-26 18:03
    Here's the method used to send pixels to the screen. Maybe the PASM will help others
    The call...
     Lcd_Write_Asm(ActiveTextColor + (REG_RAMDATAWRITE  << 16))
    
    The method that passes the write
    PRI Lcd_Write_Asm(V)                                   'handler for asm writes
         repeat while (long[@screenbufferaddress] <> 0)                        'waits for cog to clear screenbuffer
      long[@screenbufferaddress] := V                                        'makes screen buffer = v
    
    And the dat block
    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
    
    
    
                      
    
    zero                              long $0
    lowWordMask                       long $0000_ffff
                                          'pin settings
    WritePin                          long   %00000000_00000010_00000000_00000000
    RSPin                             long   %00000000_00000001_00000000_00000000                                          
    PinsInit                          long   %00000000_00000000_00000000_00000000
    DirsDisabled                      long   %00000000_00000000_00000000_00000000
    DirsEnabled                       long   %00000000_00000000_11111111_11111111                                                                           ''                                          (R4Fh) (POR = 0000h)
    
    
    
    
    bufferaddress           res 1
    LCD_cmd                 res 1
    LCD_data                res 1
    Pntr                    res 1
    
    The faders look something like this
    PUB FaderInit | F , b
    Fader0[0] := 1
    Fader0[1] := 1
    Fader0[2] := 2
    
    Fader1[0] := 1
    Fader1[1] := 1
    Fader1[2] := 54
    
    Fader2[0] := 1
    Fader2[1] := 1
    Fader2[2] := 106
    
    Fader3[0] := 1
    Fader3[1] := 1
    Fader3[2] := 161
    
    PUB SetFader(FaderNumber)
      case FaderNumber
        0: Fader0[0]  := NewFaderValue
           Fader0[1]  := OldValue
           Fader0[2]  := faderpos
           
        1: Fader1[0]  := NewFaderValue 
           Fader1[1]  := OldValue
           Fader1[2]  := faderpos
           
        2: Fader2[0]  := NewFaderValue
           Fader2[1]  := OldValue
           Fader2[2]  := faderpos
           
        3: Fader3[0]  := NewFaderValue
           Fader3[1]  :=OldValue
           Fader3[2]  := faderpos
          
    PUB GetFader(FaderNumber)
     case FaderNumber
        0: NewFaderValue :=  Fader0[0]
           OldValue :=  Fader0[1]
           faderpos :=  Fader0[2]
           
        1: NewFaderValue :=  Fader1[0]
           OldValue :=  Fader1[1]
           faderpos :=  Fader1[2]
           
        2: NewFaderValue :=  Fader2[0]
           OldValue :=  Fader2[1]
           faderpos :=  Fader2[2]
           
        3: NewFaderValue :=  Fader3[0]
           OldValue :=  Fader3[1]
           faderpos :=  Fader3[2]
          
    PUB updatefader(f) 'layer 2            
    if OldValue<> NewFaderValue
         SendPot(F,NewFaderValue)
        pfw.WriteActiveCr(6, faderpos, 2,  4, 0, BackgroundColor, ActiveTextColor, 1)
        pfw.WriteActiveCr(7, faderpos, 301, 4, 0, BackgroundColor, ActiveTextColor, 1)
      
       pfw.WriteActiveCr(32, faderpos, OldValue + 24, 4, 3, BackgroundColor, ActiveTextColor, 1)
       pfw.WriteActiveCr(14, faderpos, NewFaderValue + 24, 4, 4, BackgroundColor, ActiveTextColor, 1)
         oldvalue := NewfaderValue
    PUB DrawFader |index                'layer 1
    
      pfw.WriteActiveCr(1, faderpos, 0, 0, 0, BackgroundColor, ActiveTextColor, 1)
      pfw.WriteActiveCr(9, faderpos, 7, 0, 0, BackgroundColor, ActiveTextColor, 1)
       
         REPEAT 18
           pfw.WriteNextActiveCr(13)
        
        pfw.WriteActiveCr(1, faderpos, 297, 0, 0, BackgroundColor, ActiveTextColor, 1)
        pfw.WriteActiveCr(9, faderpos, 304, 0, 0, BackgroundColor, ActiveTextColor, 1)
    
        pfw.WriteActiveCr(6, faderpos, 2, 3, 0, BackgroundColor, ActiveTextColor, 1)
        pfw.WriteActiveCr(7, faderpos, 301, 3, 0, BackgroundColor, ActiveTextColor, 1)
      
        pfw.WriteActiveCr(32, faderpos, OldValue + 24, 5, 4, BackgroundColor, ActiveTextColor, 1)
        pfw.WriteActiveCr(14, faderpos, NewFaderValue + 24, 4, 4, BackgroundColor, ActiveTextColor, 1)
    
    These are really buggy right now.
  • TylerSkylerTylerSkyler Posts: 72
    edited 2012-02-27 10:34
    Wow! The ASM code makes the display much faster. Good work! I was orginally adapting your spin code for the screen for my purposes, but I think i'll see if I can't get ASM to work as you have done. I'm sure it will be a bit of work(i'm hopless a ASM :smile:). Just a quick question is there a way to "Debug" a string to the display from the font in ram(i haven't got my sd card to work yet) instead of havening to put each character to the screen separately and defining it's position separately?


    Thanks,

    Tyler
  • average joeaverage joe Posts: 795
    edited 2012-02-27 12:04
    I was planning a terminal type front end, but I have not got that far yet. The font I'm using is actually in rom. If you look at my calls, I have 2 propfont writers. One is active character, and the other is next character. Writing to the display is pretty simple, just call active character with the parameters for the first character, and then you can call next character with just the character.
    pfw.WriteActiveCr("F", 0, 8, 0, 0, BackgroundColor, ActiveTextColor, 1)
        pfw.WriteNextActiveCr("o")
        pfw.WriteNextActiveCr("n")
        pfw.WriteNextActiveCr("t")
    
    this writes font to the display starting a row 0 column 8, no borders.
    if you want, I can help you with the asm modifications. Should not be too hard.
    *edited*
    I fixed my analog hardware, and now I'm trying to get the HW to bind with the SW values. THIS VERSION IS NOT STABLE!!! I'm working on it ;)
    The HW version has optimizations I really recommend. Those pullup resistors on RS and WR are REALLY cool. I was going to pull all lines up or down for a correct init, but address comes out 0 which is screen reset, with enable floating that holds the screen in reset till the prop takes over.
  • average joeaverage joe Posts: 795
    edited 2012-03-02 18:42
    I have been busy with school so not much time to update code. The analog hardware failure has been a big setback although I was able to find the fault. I am debating repairing this board as I have designed an actual PCB to replace the tangled mess of wire. I have also ordered brand new IC's and am replacing all tl074's with tl082's. Much work to be done.

    What I'm wondering about now is the best way to regain the eeprom pins after startup. I have lcd_reset line that could be used to indicate a reset status as it is active when spi_en and spi_address lines are inputs. So my thought is to use a `244 to connect the pins to the external devices *midi out and midi in.* Do I need to use both sections of the 244, one for midi active, the other for eeprom active, or can I get away with leaving the eeprom in circuit. I've made enough modifications to the PropRPM that I feel sorry for it. I'm totally willing to cut traces if I have to, but would rather not. I also want to replace the eeprom with the largest one I can, and not sure which part to order. I'm looking at the AT24C512, not sure if this is the best choice.

    Another consideration is how to connect my foot controller. I have 18 buttons, 3 digit - 7 segment display, 8 leds and a photo-sensor. I was using my BS2, but would like to free this up so my wife can build the boe-bot. I have a couple of PIC 18F's laying around, but no desire to build a board and develop code for what I consider to be an obsolete and overpriced micro. I will probably end up grabbing a couple more 40pin props and eeproms to match.

    I keep saying I'm going to get the SD card working, but have had nothing but failure. I'm wondering if this is because when I'm starting the sd driver, the enable pin is set as an output by the calling cog. I will be conducting more tests later. Fingers crossed.

    I also plan on turning the fader code into its own object. I'm trying to wrap my head around the process of this. The idea is to declare multiple instances of the fader object something like
    obj
       fader[4] : "faderObject"
    
    Then update each fader instance, which will hold all necessary information for controlling it. Or something like this?
    I also received a 16-bit drivers from another member today so I will be looking at those. Anyway, here's some pictures of the progress so far.
    1024 x 612 - 51K
    1024 x 1712 - 116K
    1024 x 612 - 86K
    1024 x 612 - 63K
    1024 x 612 - 57K
    1024 x 612 - 42K
  • average joeaverage joe Posts: 795
    edited 2012-03-03 18:09
    Once again, I've worked on the sd card and failed. I wired the breakout slot directly to the proprpm. No pin sharing, CS, D0, CK, DI. I did not install resistors yet since no-one else seems to need them. I will add those later to establish that is not the problem. I have tested with the only 2 sd cards I can get my hands on. SanDisk 64m and samsung micro-sd 2g. Both received fresh fat16 formats. I'm stumped as to why I can't get it to work. Pins are set to inputs at start of method. I'm using:

    SD-MMC File Allocation Table Engine
    Version: 2.0 - Special

     pst.dec(fat.FATEngineStart(27,26,25,24,-1,-1, -1, -1,-1)) 
    and 
    pst.dec(fat.FATEngineStart(25,26,27,24,-1,-1, -1, -1,-1))
    
    Both calls return -1
    I have no idea what else to try, other than add the resistors which I will be doing shortly. I will quadruple check my wiring, but doubt that's it. Does anyone have any insight? This is driving me crazy!



    *EDIT*
    I'm working on a new controller. Here's the initial idea.. I plan on using 2x - 18F452 or 18F4620's. I will be using one of each at first. These use the PSP bus and will be programmable via PROP. Once bootstrap is installed, updates will be handled from sd card, *opcode $F*. Instructions will be 4 bit, 2 bit priority, 2 bits reserved. 8 bit address, 8 or 16 bit data. Prop to PIC transfers will be 1 byte, 2 byte, 3 byte or 4 byte. Still working out all the details, but this will give 2 bidirectional USARTs, 3 SPI busses, 2x8 - bit digital pic bus *B, 2x6 10-bit analog bus. The configuration will be left up to user. There are a ton of built in's that will be very handy. I want to add Dr. Acula's Ram chips on. Any thoughts?
    newController.jpg
    1024 x 731 - 120K
  • average joeaverage joe Posts: 795
    edited 2012-03-12 06:12
    I DID IT! The sd card is working, although I've had some interesting results. I was unable to get kye's sd driver going. I spent about 4 hours working on it after I got fsrw1.7 going and gave up. I then spent another 8 hours getting fsrw 2.6 running. The interesting thing is, my micro-sd card worked in fsrw1.7... I THINK. I only have one card that works in fsrw 2.6 and I'm still not sure why. I will do some more debugging later and post the results.
    SO, the next task after getting sd cards working was getting Dr. Acula's fonts working. That took about a week. The code needs a ton of work, but it's a start. I'm kinda put off by how the parallax font looks. That 7 is KILLIN me. I still think it looks better than the rom font at half size. Pix to come.

    Dr. Acula's font test
    CON
    {''Hardware version 3.11 - see diagram.
    ''
    } 
     _clkmode       = xtal1 + pll16x                        ' use crystal x 16
     _xinfreq       = 5_000_000                             'with 5mhz crystal 
          
      DEV_SD_CLK        = 18
      DEV_SD_DI         = 19
      DEV_SD_DO         = 20                                 
      DEV_SPI_EN        = 21                               ''SPI Enable enumeration
      DEV_SPI_ADD0      = 22                               ''Device address 0 enumeration
      DEV_SPI_ADD1      = 23                               ''Device address 1 enumeration
      DEV_SPI_ADD_LE    = 24
      
      DEV_SPI_LCD_RES    = 0                 ''Device id for LCD reset
      SDC     = 1
      TSC     = 2
      EXT     = 3  
     DEV_SPI_EXT_POT_CS  = 0
     DEV_SPI_EXT_SW_CS   = 1
                          
      BGCOLOR                       = $ffff
      TXTCOLOR                      = $0000
       Pressed                       = 1  
       NotPressed                    = 0
    faderUpBtnBound                 = 499     ''y < 499
    faderDnBtnBound                 = 3700    ''y > 3699                  3200, 1600, 320
    fadertouchoffset                = 320         ''3375 < y < 825  range e
    
      cols = 40
      rows = 15
      screensize = cols * rows
      lastrow = screensize - cols
      offset = 8 * 2048 ' the block offset of where we do writes 
    
      RamText   = 169984
      VT100     = 202752
      FontTable = 206080 
    
    
    VAR
     long Screen_Buffer, CRbuffer
    
     
        byte FontHeight                ' size of the current loaded font (pixels = fontsize *.75)
       word BackFontColor           ' the background color in RRRRRGGG GGGBBBBB format
       word curx                    ' current cursor x position in pixels
       word cury                    ' current cursor y position in pixels
       byte Orientation                ' true for portrait, false for landscape
       word ScreenWidth             ' either 240 in portrait or 320 in landscape
       word ScreenHeight            ' 320 in portrait or 240 in landscape
       byte screen[screensize]
       long col,row,flag
      
     
       'byte  font[13312], sdbuffer[512],buffer2[512]                     ' 512 byte buffer for sd card interface
                                     
       'byte tbuf[20]
       'byte bigbuf[8192]
       
       long BackgroundColor, ActiveTextColor, stringptr[32], maxdur,sr ,speedresults 
               
    OBJ pfw :"PropFont_asmDone"
         wait : "timing"  
         'pst : "parallax serial terminal"
         spi : "spi_asm"
         sdfat: "fsrw"
          'block: "safe_spi"
         'ILI9325:"ILI9325_Dracblade"       
    PUB BOOT   | f                       'bootstrap, initalizes pins, then starts pst, init display, start asm, clear screen and display hello world
      WAIT.PAUSE1S(5)
      initPins
    
    
    SetOrientation(false)
      
    BackgroundColor := $ffe0
    ActiveTextColor := %0000  
     long[@Screen_Buffer]          := $ffff                        'make sure screen buffer does not equal 0  
      pfw.Start(@Long[@Screen_Buffer])                          'Start Asm Driver, needs to be changed to pass screen buffer from top object
      pfw.size(1)
      pfw.setChar(0, 8, 0, 0, BackgroundColor, ActiveTextColor)
      spi.start(3,0) 
       'pfw.ClearScreen(BackgroundColor)            'Draw White Screen with asm
      ' DracFont
       'pfw.dec(\SD_speedtest)
       'wait.pause1s(5)
       repeat 
         DracFont
    
    Pub DracFont |c
    'pfw.clearscreen($FFFF)
    pfw.size(2)            
    'pfw.str(string("  setting enable output  "))
      OUTA[DEV_SPI_EN] := 1    
      outa[DEV_SPI_ADD1..DEV_SPI_ADD0] := SDC
      dira[DEV_SPI_EN..DEV_SD_CLK] := 0
      dira[DEV_SPI_ADD1..DEV_SPI_ADD0] := 3
    'pfw.newline    
    'pfw.str(string("  setting enable output ok  "))
    'pfw.newline
    'pfw.str(string("  trying to mount sd card  "))  
      'pfw.newline
      'wait.pause1s(1)               
        if \sdfat.mount(18) < -1
         ' pfw.str(string("Mount Failed"))
          'wait.pause1s(3)
          sdfat.unmount
        else
        'pfw.str(string("  Mounting OK  "))
        \NewFont(string("Par16.ifn"))
        sdfat.unmount
        Text_cls
    
         'tswait
         repeat
            repeat c from 32 to 125
           
              wait.pause1ms(100)
              text_out(c)     '
       
       ' Text_str(string("ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz")) 
        Text_str(string("Basic text display for the ILI9325"))
         
        Text_crlf
        Text_str(string("Print decimal value "))
        Text_dec(100)
        Text_crlf
        text_str(string("Hex value 500 = "))
        Text_hex(500,4)
        text_crlf    
       'wait.pause1s(5)
    
       
    PUB Text_Str(rstringptr)
    '' Print a zero-terminated string
      repeat strsize(rstringptr)
        Text_out(byte[rstringptr++])
    
    PUB Text_out(c) | i, k
    '' Output a character
    ''
    ''     $08 = backspace
    ''     $09 = tab (8 spaces per)
    ''     $01 = set X position (X follows)
    ''     $0B = set Y position (Y follows)
    ''     $0C = set color (color follows)  (not on this simple terminal)
    ''     $0A = line feed
    ''     $0D = carriage return (col = 0)
    ''  others = printable characters
    
      case flag
        $00: case c
               $08: if col        ' not zero so can subtract one
                      col--
                      Text_print(" ")     ' backspace and rubout
                      col--
                      'Text_RedrawLine
               $09: repeat
                      Text_print(" ")
                    while col & 7
               $01: flag := c
                 return
               $0B: flag := c
                 return
               $0C: flag := c
                 return
               $0A: Text_newline ' linefeed/new line     
               $0D: col := 0 ' carriage return
               other: Text_print(c)
        $0A: col := c // cols
        $0B: row := c // rows
        '$0C: color := c & 7
      flag := 0
      
    PRI Text_print(c)         ' private routine from routine above
      screen[row * cols + col] := c  ' store in the screen text buffer
      ILIChar(c,col<<3,row <<4)   ' print on the screen  col*8 and row *16 as this is the font size
      if ++col == cols
        Text_newline       '
       
    PUB Text_hex(value, digits)
      {{ Send value as hexadecimal characters up to digits in length.
      ''
      '' `Parameters:
      ''
      ''     `value: byte, word, or long value to send as hexadecimal characters.
      ''     `digits: number of hexadecimal digits to send.  Will be zero padded if necessary.
      ''
      '' `Return: none.
      ''
      '' `Example: pst.Hex(1234, 5)
      ''
      ''     Output decimal 1234 as five hex digits. Outputs `004D2.
      ''     Next lines, if needed...
      }}
    
      if (digits > 8)
        repeat digits - 8
          Text_out("0")
        digits := 8
      else
        value <<= (8 - digits) << 2
      repeat digits
        Text_out(lookupz((value <-= 4) & $F : "0".."9", "A".."F"))
            
    PUB Text_dec(value) | i
    '' Print a decimal number
      if value < 0
        -value
        Text_out("-")
      i := 1_000_000_000
      repeat 10
        if value => i
          Text_out(value / i + "0")
          value //= i
          result~~
        elseif result or i == 1
          Text_out("0")
        i /= 10
        
    PRI Text_newline | i
      col := 0
      if ++row == rows
        row--
        bytemove(@screen, @screen[cols], lastrow)   'scroll lines
        bytefill(@screen[lastrow], " ", cols)      'clear new line
        Text_RedrawScreen                                   ' all lines shuffle up one so need to redraw all the screen
    
    PUB Text_RedrawScreen | x,y,i
        ClearFontBackground(0,0,screenheight,screenwidth)
        ILIsetcursor(0,0)
        i := 0
        repeat y from 0 to rows -1
          repeat x from 0 to cols -1
            curx := ILIChar(screen[i],curx,cury)
            i++
          curx :=0
          cury +=fontheight
    
    PRI Text_RedrawLine | oldcurx,i ' redraw current row, for backspace
       oldcurx := curx' store
       ClearFontBackground(0,row <<4 ,screenwidth,row <<4 + FontHeight) ' clear background line to the background color ready to draw
       curx := 0
       cury := row <<4 ' times 16
       i := row * cols ' variable row times constant cols
       repeat cols ' do 40x
         curx := ILIChar(screen[i],curx,cury)
         i++
       curx := oldcurx              ' restore curx
       
    PUB ILIChar(ascii,x,y) | jump,size,width,height,ramaddress,xoffset,yoffset,xadvance   ' read out a character from a .ifn file stored in ram
        jump := long[@font + (ascii << 2) +  256]' jump location = ascii *4 plus fonttable + 256
        jump += @font
        size := long[jump]                 ' size precalculated = width x height x 2
        xadvance :=  long[jump][5]     '     ' amount to move to next character offset = 20 which is 5 longs
        if size > 0 and ascii <> 32          ' no need to print anything if size is zero or read more font data
          width :=   long[jump][1]                ' width value of offset is 1 long
          height :=  long[jump][2]            ' height
          xoffset := long[jump][3]          ' xoffset to move
          yoffset := long[jump][4]           ' yoffset to move
          if (x+width -1 + xoffset) > screenwidth
            ILIcrlf ' do a new line if it won't fit
            x :=curx                                           
            y :=cury
          pfw.draw( x+xoffset, y+yoffset, x+width-1+xoffset,y+height-1+yoffset)      ' draw on screen
          pfw.hub(jump+32,size)                                 ' move bytes from ram out to the display   
        return x + xadvance
    
    PUB SetOrientation(e) ' change orientation true = portrait. Changes global variable 'orientation' and also screen width and height
        orientation := e
        pfw.ChangeOrientation(orientation)
        if orientation
          screenwidth :=239
          screenheight :=319
        else
          screenwidth :=319
          screenheight :=239
    
    PUB Text_crlf
       Text_out(13)
       Text_out(10)   
          
    PUB Text_cls
       bytefill(@screen, " ", screensize)
       col := row := 0
       
    PUB ILISetCursor(x,y)            
        curx := x
        cury := y
        
    PUB ILIcrlf
        curx := 0
        cury += FontHeight
        
    PUB NewFont(nstrpointer)
        ILIloadfont(nstrpointer)
        ' only call this routine with the cursor curx at zero
        'pfw.newline
        'pfw.str(string("calling font clear with curx"))
       ' pfw.dec(curx)
        'pfw.newline
        'pfw.str(string("cury"))
       ' pfw.dec(cury)
        'pfw.newline
        'pfw.str(string("screenwitdth"))
        'pfw.dec(screenwidth)
        'pfw.newline
       ' pfw.str(string("screenheight"))
        'pfw.dec(screenheight)
        'pfw.newline
       ''tswait
        'pfw.str(string("go"))
        ClearFontBackground(0,0,screenheight,screenwidth)             ' clear an area the same color as the font background
        'pfw.str(string("cleared?"))
        ILIsetcursor(0,0)
    
    PUB ILILoadFont(nstringptr)| filesize,i   ' hub version
        ' pass file name in stringptr
        ' the variable "i" must start on 0,256,512,768 etc for the block move to work
        i := 0
        'pfw.newline
        'pfw.str(string("Opening file "))
        'pfw.str(nstringptr)
        'pfw.newline                                            
        sdfat.popen(nstringptr,"r")                        ' store at the constant 'fonttable' location 
        'pfw.str(string("Opening file ok "))
        'pfw.newline
        'pfw.str(string("Getting filesize"))
        'pfw.newline
        filesize := sdfat.get_filesize
        'pfw.str(string("Filesize is "))
        'pfw.dec(filesize)
        'pfw.newline
        'pfw.str(string("loading font into hub"))
        'pfw.newline
        repeat (filesize >> 8)                              ' read in this number of 256 byte blocks
          sdfat.pread(@font+i,256)                         ' get 256 bytes from sd card
          i += 256                                         ' add 256
        'pfw.str(string(" read complete "))
        'pfw.newline
        'pfw.str(string(" closing filesystem ")) 
        sdfat.pclose
        'pfw.str(string(" closed "))
        'pfw.newline
        'pfw.str(string("loading font height"))  
       FontHeight := font[251]
       'pfw.dec(FontHeight)
       'pfw.newline
       'pfw.str(string("getting bgcolor"))
       'pfw.newline 
       repeat i from 0 to 2
          sdbuffer[i] := font[35+i]                         ' read the 3 RGB bytes
      'pfw.str(string("bg color is "))
      'repeat i from 0 to 2
      'pfw.dec(sdbuffer[i])
      'pfw.newline 
      'pfw.str(string("converting colors "))
      pfw.convertColors(@sdbuffer,@buffer2,1)
      'pfw.str(string("conversion done"))
      'tswait
      'pfw.clearscreen($4893)
      'pfw.str(string("new colors are"))  
      BackFontColor := word[@buffer2]                  ' background color in ILI two byte format
        'pfw.dec(BackFontColor)
        'pfw.newline
        'pfw.str(string("returing with filesize"))
        'pfw.dec(filesize)
        result := filesize
      ''tswait
    
    PUB ClearFontBackground(x1,y1,x2,y2) | 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) << 1                      ' if not a whole number of 256 pixels
        repeat i from 0 to 510 step 2                         ' move the background font colour to the buffer
          sdbuffer[i] := BackFontColor & 255                  ' and replicate for 256 pixels
          sdbuffer[i+1] := BackFontColor >> 8
        pfw.draw(y1,x1,y2,x2)                           ' set up the area of the screen to draw in
        repeat size >> 8                                    ' 512 byte blocks
          pfw.hub(@sdbuffer,512)                ' 2 = 2 bytes which = one pixel   *was 512
        if remainder <> 0  
          pfw.hub(@sdbuffer,remainder)           ' do the remainder
           
    PUB TSWait  | yval, xval,x,y
      OUTA[DEV_SPI_ADD1..DEV_SPI_ADD0] := TSC        ''Old format was      OUTA[TS_CS] := 0     ' enable the touch screen    '  
      dirA[DEV_SPI_EN] := 1 
      dirA[DEV_SPI_ADD1] :=1
      dirA[DEV_SPI_ADD0] := 1 
       outa[DEV_SPI_EN] := 1   
      wait.pause1ms(100)
       repeat
         OUTA[DEV_SPI_EN] := 0
          SPI.SHIFTOUT(DEV_SD_DI, DEV_SD_CLK, 5, 8 , %1101_0000)  ' reads x from  500 to 3700  (off < 500 )
          xval := SPI.SHIFTIN(DEV_SD_DO, DEV_SD_CLK,2, 12)
          SPI.SHIFTOUT(DEV_SD_DI, DEV_SD_CLK, 5, 8 , %1001_0000)  ' reads y from 400 to 3800 (off > 3800 ) 
          yval := SPI.SHIFTIN(DEV_SD_DO,DEV_SD_CLK,2, 12)
           if xval <>  0
             result := xval + (yval << 16)
             OUTA[DEV_SPI_EN] := 1
             outa[DEV_SPI_ADD1..DEV_SPI_ADD0] := SDC
             RETURN
           ELSE 
             wait.pause1ms(100)
    
    PUB StrobeCS
       OUTA[DEV_SPI_EN] := 0
       wait.pause1ms(10)
       OUTA[DEV_SPI_EN] := 1
    
    pri initPins
      dirA[DEV_SPI_ADD0]   := 1             'makes address 0 and 1          
      dirA[DEV_SPI_ADD1]   := 1             'outputs
      dirA[DEV_SPI_EN]     := 1              'and enable an output as well
      OUTA[DEV_SPI_ADD1..DEV_SPI_ADD0] := 2   'sd_card is default
      OUTA[DEV_SPI_EN]     := 1             'Disable - Reset Screen
          
    'pri SD_speedtest | r, sta, bytes, CHAR                 ''works?
    ' OUTA[DEV_SPI_EN] := 1    
    ' outa[DEV_SPI_ADD1..DEV_SPI_ADD0] := SDC
    ' dira[DEV_SPI_EN..DEV_SD_CLK] := 0
    ' dira[DEV_SPI_ADD1..DEV_SPI_ADD0] := 3
    ' pfw.size(2)
    ' pfw.clearscreen(0)
    ' pfw.setColors($0000,$FFFF)  
    ' pfw.Str(string("Starting SD card"))        ' helpful message if card is out, better than just a blank screen
    ' pfw.newline                          
    ' Pfw.str(string("Mounting."))
     ' pfw.newline   
      ' sdfat.mount(18)
      ' Pfw.str(string("Mounted."))
      ' pfw.newline
      ' wait.Pause1s(1)
      ' Pfw.str(string("Dir:"))
      ' pfw.newline
      ' sdfat.opendir
      ' repeat while 0 == sdfat.nextfile(@tbuf)
      '   Pfw.str(@tbuf)
      '   Pfw.newline     
      ' Pfw.str(string("That's the dir"))     
      ' sta := cnt
      ' r := sdfat.popen(string("speed.txt"), "w")
      ' repeat 256                  
      '   sdfat.pwrite(@bigbuf, 8192)                  
       'r := (cnt - sta) >> 2
      ' sdfat.pclose
       'pfw.newline
       'Pfw.str(string("Writing 2M took "))
      ' pfw.dec(r)
       'Pfw.newline
       'sta := cnt
       'r := sdfat.popen(string("speed.txt"), "r")
       'repeat 256
       '  sdfat.pread(@bigbuf, 8192)
       'r := (cnt - sta) >> 2     
       'sdfat.pclose
       'sdfat.release
       'sdfat.unmount
       'Pfw.str(string("Reading 2M took "))
       'pfw.dec(r)
       'Pfw.newline
       'Pfw.str(string("That's, all, folks! "))
       'pfw.size(1) 
       'tswait    
    'pub deadend                                                               'loop for testing
    ' repeat                                                                             'endlessly wait
    '   repeat
    '    waitcnt(2_000 + cnt)
    
    DAT
    sdbuffer        byte    $0[512]  ' 512 byte buffer for sd card interface
    buffer2         byte    $0[512]  ' 512 general purpose hub buffer
    font            byte    $0[13312]
    

    and the helpers
    propFont, now has passthrough functions...
    CON
     ''PINS
      LCD_RS            = 16                               ''LCD RS pin
      LCD_WR            = 17                               ''LCD WR pin
       
    ''LCD REGISTER Enumeration, for SSM1289   
      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                               ''                                          (R4Fh) (POR = 0000h)
    
      FONT_ROM_ADDRESS              = $8000
    
    VAR
    long screenbufferaddress, Fontsize, pcog
    long BackgroundColor,ActiveColor, ActiveTextColor, InactiveTextColor, Row, Col, RowBorder,ColBorder, WindowX1, WindowX2, WindowY1, WindowY2
    byte orientation
    word entrymode  
    
    obj wait : "timing"
        cr   : "crReader"
       'pst  : "parallax serial terminal"  'used for debugging..
            num : "numbers"
    PUB nul                  'not a standalone object
    
    PUB draw (x1, y1,x2, y2)  'compatibility passthrough for DRAC
    SetWindow( y1,x1, y2,x2 )
    SetGAddress(y1,x1)
    col :=0
    row :=0 
    
    PUB ChangeOrientation(n) ' pass true = portrait or false = landscape, changes global variable orientation in this object
    '    EnableDisplayPins
         orientation := n
    '    if orientation
    '      Lcd_Write_Com($0001,$0100)                        ' set SS and SM bit 0001 0100   portrait
    '      Lcd_Write_Com$0003,$1030)                        ' set GRAM write direction and BGR=1. $0003 $1030  
    '    else
    '     Lcd_Write_Com($0001,$0000)                        ' set SS and SM bit 0001 0000   landscape   
    '     Lcd_Write_Com($0003,$1038)                        ' landscape  $1028 = original but 1038 is correct - not mirror image' 
    
    pub convertColors(inadd, outadd, len )  |red, green, blue, ilihigh, ililow
    
                            ' takes a .raw 3 byte RRRRRRRR GGGGGGGG BBBBBBBB and converts to 2 byte RRRRRGGG GGGBBBBB
                            ' pass hubaddr, ramaddr and len
                            ' hubaddr is source location, len is number of pixels
                            ' ramaddr is destination in hub (messy naming) and length is 2/3 of blocklength
                     repeat len       
                             red := byte[inadd]
                             inadd++
                             green := byte[inadd] 
                             inadd++
                             blue := byte[inadd]
                             inadd++             
                             red >>= 3
                             red <<= 3
                             green >>= 2
                             ilihigh:= green
                             ilihigh >>= 3
                             ilihigh |= red 
                             green &=%00000111
                             green <<= 5
                             ililow := green
                             blue >>= 3
                             ililow |= blue
    
                           word[outadd] := ilihigh +(ililow << 8) 
                            outadd++
    
    PUB hub(address,l)   | p, pl, ph
     repeat l  / 2   
        pl := byte[address++]
        ph := byte[address++]
        p:= ph +(pl << 8)
         
       Lcd_Write_Asm((REG_RAMDATAWRITE  << 16)+ p )
       
    'PUB setEntryModeDefault
     ' setEntryMode(3,1)
    
    pub setEntryMode
    '                                                      5..4    3
    'entry        vs   dfm  trans-  oe    wm   d0..1   ty   id     AM   LG
    'mode        Mode  1..0 parent  def  mode  mode        1..0
    entrymode :=  %0110______1000____0000____1000      ' default $6838
    
    Lcd_Write_Asm((REG_ENTRYMODE  << 16) + entrymode )
    
    pub setDriverOutputControl    | reverse,bgr,tb,rl
    'reverse
    'bgr
    'tb  
    'rl
    
    
    
    
        
    pub pixel(p)                      
      Lcd_Write_Asm((REG_RAMDATAWRITE  << 16)+ p )
                             
         
    pub size(s)
     fontsize := s
     
    PUB Str(ptr) |  cbuf
      cbuf := byte[ptr++]
     WriteActiveCr(cbuf, row, col, 0, 0, BackgroundColor, ActiveTextColor)    
      repeat (strsize(ptr) )
        WriteNextActiveCr(byte[ptr++])
    
    PUB  dec(n) | t, t2, t3, t4, t5, t6, t7, t8, t9, t10, pl, im
    str(num.tostr(n, %000_010_001_0_0_000000_01010))
                     
    pub newline
        Row := Row + (32 >> (fontsize -1))
        Col := 0
        
    pub setRow(PosR )
        Row := PosR
        
    pub setCol(PosC)
        Col := PosC
        
    pub setBorders(RBorder, CBorder)
        RowBorder := RBorder
        ColBorder := CBorder
        
    pub setColors( BgC, TxC)
       BackgroundColor  := BgC
       ActiveTextColor  := Txc
    
    PUB setChar(PosR, PosC, RBorder, CBorder, BgC, TxC) | characterpointer, odd_even, bitpatern[32], idx, pxlidx, lcdidx, pxlidxdcd, x1, y1, x2, y2, fontaddress
     setRow(PosR)
     setCol(PosC)
     setBorders(RBorder, CBorder)
     setColors(BgC, TxC)
    
    PUB Start(ScreenBufferAdd)             'Method to Init display, then load a cog with screen driver
     screenbufferaddress   := ScreenBufferAdd                'store buffer address in long
     Init_SSD1289                                                'init screen
     long[@screenbufferaddress]      := $ffff                        'make sure screen buffer does not equal 0
     result := pcog := cognew(@entry,@long[@screenbufferaddress])                          'start write driver and pass it the address of screen buffer
     cr.Start
      num.init
      
    PUB Stop
        cogstop(pcog)
    PUB Char(c)
    WriteNextActiveCr(c)
    
    PUB WriteNextActiveCr(Character) | characterpointer, odd_even, bitpatern[32], idx, pxlidx, lcdidx, pxlidxdcd, x1, y1, x2, y2, fontaddress
     fontaddress := Cr.GetChar(Character)
       repeat idx from 0 to 31 
         bitpatern[idx] := word[fontaddress][idx]
         
       y1 :=   Col + ColBorder  
       y2 :=  (Col + (15 / fontsize ) - ColBorder)      
       x1 :=   Row + RowBorder
       x2 :=  (Row + (31 / fontsize )  - RowBorder)
       
         SetWindow(x1, y1, x2, y2)
         SetGAddress(x1,y1)
         
      repeat idx from RowBorder to 31 - RowBorder  step Fontsize       
         repeat pxlidx from ColBorder to  15 - ColBorder step Fontsize 
           pxlidxdcd := |< pxlidx
           if ((bitpatern[idx] & pxlidxdcd) == pxlidxdcd)  
             Lcd_Write_Asm(ActiveTextColor + (REG_RAMDATAWRITE  << 16))
           else
             Lcd_Write_Asm(BackgroundColor + (REG_RAMDATAWRITE  << 16))
         repeat while word[fontaddress] := 0
    
    if (((Col + (16 >> (fontsize -1))) >  319 ) and  ((Row + (32 >> (fontsize -1)) > 223)))
        Row := 0
        Col := 0                         
    elseif (((Col + (16 >> (fontsize -1))) >  319 ) and  ((Row + (32 >> (fontsize -1)) < 223))) 
        Row := Row + (32 >> (fontsize -1))
        Col := 0
    else
        Col := Col + (16 >> (fontsize - 1))
    
    PUB WriteActiveCr(Character, PosR, PosC, RBorder, CBorder,  BgC, TxC) | characterpointer, odd_even, bitpatern[32], idx, pxlidx, lcdidx, pxlidxdcd, x1, y1, x2, y2, fontaddress
      setChar(PosR, PosC, RBorder, CBorder,  BgC, TxC)
     WriteNextActiveCr(Character)
    
    PUB ClearScreen(color) | idxr, idxc
      SetWindow(0, 0, 239, 319)
      SetGAddress(0,0)
      color += (REG_RAMDATAWRITE  << 16)
      repeat idxr from 0 to 76800           
          Lcd_Write_Asm(Color)
    Row              := 0      
    Col              := 0
    
       'BackgroundColor := color
       'ActiveTextColor := $ffff
    
    PUB SetWindow(x1, y1, x2, y2) | HORIZONTALRAMADDRESSPOS                      'Set window to draw in
     WindowX1 := x1                                                                        'update draw window in main memory
     WindowX2 := x2                                                                        'update draw window in main memory 
     WindowY1 := y1                                                                        'update draw window in main memory 
     WindowY2 := y2                                                                        'update draw window in main memory 
        HORIZONTALRAMADDRESSPOS := x1 + (x2 << 8)                                                      'combine x1 and x2 values                                                                                                  
           Lcd_Write_Asm ((REG_HORIZONTALRAMADDRESSPOS << 16) + HORIZONTALRAMADDRESSPOS)               'and write to display
           Lcd_Write_Asm(y1 + (REG_VERTICALRAMADDRESSSTART << 16))                                     'send v-address start
           Lcd_Write_Asm(y2 + (REG_VERTICALRAMADDRESSEND << 16))                                       'send v-address end
           
    PUB SetGAddress(x,y)                                                         'Set address for gddr writes
           Lcd_Write_Asm ((REG_SETGDDRXADDRESSCOUNTER << 16) + x)      ''max %1111_1111, $FF
           Lcd_Write_Asm ((REG_SETGDDRYADDRESSCOUNTER << 16) + y)      ''max %1_0011_1111, $13f
                                                                                                   ''                                                                    
    PRI EnableDisplayPins                                                    'enable all pins -
        DIRA:=%00000000_11000000_11111111_11111111        ''enable p15 - p0    
    PRI TristateDisplayPins                                                  'tristate all pins -                                                 
        DIRA:=%00000000_11000000_00000000_00000000        ''release p15 - p0
    
    PRI Lcd_Write_Asm(V)                                   'handler for asm writes
         repeat while (long[@screenbufferaddress] <> 0)                        'waits for cog to clear screenbuffer
      long[@screenbufferaddress] := V                                        'makes screen buffer = v
                           
    PRI LCD_Writ_Bus(V)                   'write to display
        OUTA[15..0]  := V                       ' copy V onto pins
        WriteLow                                ' write pin low
        WriteHigh                               ' toggle write pin
    
    PRI Lcd_Write_Com(V)                    'write command to display
        LCD_RSLow                               'Sets command
        LCD_Writ_Bus(V)                         'Do write
    
    PRI LCD_Write_Data(V)                   'write data to display
        LCD_RSHigh                              'Sets data
        LCD_Writ_Bus(V)                         'do write
    
    PRI LCD_RSLow
        outa[LCD_RS] := 0                             'controls RS pin with DIR-A         
        dira[LCD_RS] := 1                       'see hardware revision
    
    PRI LCD_RSHigh                              'controls RS pin with DIR-A
        dira[LCD_RS] := 0                       'see hardware revision   
    
    PRI WriteLow
        outa[LCD_WR] := 0                          'controls WR pin with DIR-A        
        dira[LCD_WR] := 1                        'see hardware revision      ' 
    
    PRI WriteHigh                           'controls WR pin with DIR-A 
        dira[LCD_WR] := 0                        'see hardware revision 
    
    PRI Init_SSD1289                ''Init Display
     EnableDisplayPins
    
        Lcd_Write_Com (REG_DISPLAYCONTROL)                  ''Display Control (R07h) (POR = 0000h) 
        Lcd_Write_Data($0021)                               ''GON = 1 DTE = 0 D[1:0] = 01
        
        Lcd_Write_Com (REG_OSCILLATOR)                      ''Oscillator (R00h) (POR = 0000h)
        Lcd_Write_Data($0001)                               ''Turn on oscillator
        
        Lcd_Write_Com (REG_DISPLAYCONTROL)                  ''Display Control (R07h) (POR = 0000h)
        Lcd_Write_Data($0023)                               ''GON = 1 DTE = 0 D[1:0] = 11
                
        Lcd_Write_Com (REG_SLEEPMODE)                       ''Sleep mode (R10h) (POR = 0001h)
        Lcd_Write_Data($0000)     ''                        ''exit sleep mode
        
        Lcd_Write_Com (REG_DISPLAYCONTROL)                  ''Display Control (R07h) (POR = 0000h)
        Lcd_Write_Data($0033)                               ''GON = 1 DTE = 1 D[1:0] = 11
        
        Lcd_Write_Com (REG_ENTRYMODE)                       ''Entry Mode (R11h) (POR = 6830h)     6838
        Lcd_Write_Data($6838)                               ''
        
        Lcd_Write_Com (REG_LCDDRIVINGWAVFORM)               ''LCD-Driving-Waveform Control (R02h) (POR = 0000h)($1000) 
        Lcd_Write_Data($1000)     ''                        ''
        
        Lcd_Write_Com (REG_GATESCANPOSITION)                ''Gate Scan Position (R0Fh) (POR = 0000h)  ($0000)
        Lcd_Write_Data($0000)     ''                        ''
                                            ''
        Lcd_Write_Com (REG_DRIVEROUTPUTCONTROL)             ''Driver Output Control (R01h) (POR = [0XXXX0X1]3Fh) 433f ($633F)  6838
        Lcd_Write_Data($6B3F) ''                            '' Bit 14 - Invert Color     bit9-TB
                                        
        Lcd_Write_Com (REG_FRAMECYCLECONTROL)               ''Frame Cycle Control (R0Bh) (POR = 5308h) ($5308)
        Lcd_Write_Data($5308)                               ''
                '
        Lcd_Write_Com (REG_DISPLAYCONTROL)                  ''Display Control (R07h) (POR = 0000h) ($0033)
        Lcd_Write_Data($0033)
        
        TristateDisplayPins                            ''Release pins
        
    PUB HelloWorld
        WriteActiveCr("H", 0, 0*16, 0, 0, $ffff, $0000)       
        WriteNextActiveCr("e")
        WriteNextActiveCr("l")
        WriteNextActiveCr("l")
        WriteNextActiveCr("o")
        WriteNextActiveCr(" ")
        WriteNextActiveCr("W")
        WriteNextActiveCr("o")
        WriteNextActiveCr("r")
        WriteNextActiveCr("l")
        WriteNextActiveCr("d")
    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, #$2                          'set wait period
    :wait4                   djnz   pntr, :wait4                        'and wait
    
    :WrDataPortion                                                 
                             mov    outa, LCD_Data                 'place LCD_Data on write bus
                           
                             
                             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
                              wrlong zero, bufferaddress                       
                      jmp #Get                              'do it all again
    
    
    
    
     
    
    
    
    
    
    
    
    
                      
    
    zero                              long $0
    lowWordMask                       long $0000_ffff
                                          'pin settings
    WritePin                          long   %00000000_00000010_00000000_00000000
    RSPin                             long   %00000000_00000001_00000000_00000000                                          
    PinsInit                          long   %00000000_00000000_00000000_00000000
    DirsDisabled                      long   %00000000_00000000_00000000_00000000
    DirsEnabled                       long   %00000000_00000000_11111111_11111111                                                                           ''                                          (R4Fh) (POR = 0000h)
    
    
    
    
    bufferaddress           res 1
    LCD_cmd                 res 1
    LCD_data                res 1
    Pntr                    res 1
    
    ForegroundFormat        res 1
    BackgroundFormat        res 1
    ForegroundScreen        res 1
    BackgroundScreen        res 1
    fit 
    
    and my fsrw stuff for good measure
    {{
    '   fsrw 2.6 Copyright 2009  Tomas Rokicki and Jonathan Dummer
    '
    '   See end of file for terms of use.
    '
    '   This object provides FAT16/32 file read/write access on a block device.
    '   Only one file open at a time.  Open modes are 'r' (read), 'a' (append),
    '   'w' (write), and 'd' (delete).  Only the root directory is supported.
    '   No long filenames are supported.  We also support traversing the
    '   root directory.
    '
    '   In general, negative return values are errors; positive return
    '   values are success.  Other than -1 on popen when the file does not
    '   exist, all negative return values will be "aborted" rather than
    '   returned.
    '
    '   Changes:
    '       v1.1  28 December 2006  Fixed offset for ctime
    '       v1.2  29 December 2006  Made default block driver be fast one
    '       v1.3  6 January 2007    Added some docs, and a faster asm
    '       v1.4  4 February 2007   Rearranged vars to save memory;
    '                               eliminated need for adjacent pins;
    '                               reduced idle current consumption; added
    '                               sample code with abort code data
    '       v1.5  7 April 2007      Fixed problem when directory is larger
    '                               than a cluster.
    '       v1.6  23 September 2008 Fixed a bug found when mixing pputc
    '                               with pwrite.  Also made the assembly
    '                               routines a bit more cautious.
    '       v2.1  12 July 2009      FAT32, SDHC, multiblock, bug fixes
    '       v2.4  26 September 2009 Added seek support.  Added clustersize.
    '       v2.4a   6 October 2009 modified setdate to explicitly set year/month/etc.
    '       v2.5  13 November 2009 fixed a bug on releasing the pins, added a "release" pass through function
    '       v2.6  11 December 2009: faster transfer hub <=> cog, safe_spi.spin uses 1/2 speed reads, is default
    }}
    '
    '   Constants describing FAT volumes.
    '
    con
       SECTORSIZE = 512
       SECTORSHIFT = 9
       DIRSIZE = 32
       DIRSHIFT = 5
    '
    '   The object that provides the block-level access.
    '
    obj   'sdspi : "sdspiqasm"      ' old?   no release  
        'sdspi: "mb_spi"         nogood
        'sdspi: "mb_rawb_spi"    noope
       'sdspi: "mb_small_spi"   'no work
       sdspi: "safe_spi"
      
    var                                                         
    '
    '
    '   Variables concerning the open file.
    '
       long fclust ' the current cluster number
       long filesize ' the total current size of the file
       long floc ' the seek position of the file
       long frem ' how many bytes remain in this cluster from this file
       long bufat ' where in the buffer our current character is
       long bufend ' the last valid character (read) or free position (write)
       long direntry ' the byte address of the directory entry (if open for write)
       long writelink ' the byte offset of the disk location to store a new cluster
       long fatptr ' the byte address of the most recently written fat entry
       long firstcluster ' the first cluster of this file
    '
    '   Variables used when mounting to describe the FAT layout of the card
    '   (moved to the end of the file in the Spin version).
    '
    '
    '   Variables controlling the caching.
    '
    '
    '  Buffering:  two sector buffers.  These two buffers must be longword
    '  aligned!  To ensure this, make sure they are the first byte variables
    '  defined in this object.
    '
       byte buf[SECTORSIZE] ' main data buffer
    pub release
    '
    '   This is just a pass-through function to allow the block layer
    '   to tristate the I/O pins to the card.
    '
       sdspi.release
    pri writeblock2(n, b)
    '
    '   On metadata writes, if we are updating the FAT region, also update
    '   the second FAT region.
    '
       sdspi.writeblock(n, b)
       if (n => fat1)
         if (n < fat1 + sectorsperfat)
           sdspi.writeblock(n+sectorsperfat, b)
    pri flushifdirty
    '
    '   If the metadata block is dirty, write it out.
    '
       if (dirty)
          writeblock2(lastread, @buf2)
          dirty := 0
    pri readblockc(n)
    '
    '   Read a block into the metadata buffer, if that block is not already
    '   there.
    '
       if (n <> lastread)
          flushifdirty
          sdspi.readblock(n, @buf2)
          lastread := n
    pri brword(b)
    '
    '   Read a byte-reversed word from a (possibly odd) address.
    '
       return (byte[b]) + ((byte[b][1]) << 8)
    pri brlong(b)
    '
    '   Read a byte-reversed long from a (possibly odd) address.
    '
       return brword(b) + (brword(b+2) << 16)
    pri brclust(b)
    '
    '   Read a cluster entry.
    '
      if (filesystem == 1)
        return brword(b)
      else
        return brlong(b)
    pri brwword(w, v)
    '
    '   Write a byte-reversed word to a (possibly odd) address, and
    '   mark the metadata buffer as dirty.
    '
       byte[w++] := v
       byte[w] := v >> 8
       dirty := 1
    pri brwlong(w, v)
    '
    '   Write a byte-reversed long to a (possibly odd) address, and
    '   mark the metadata buffer as dirty.
    '
       brwword(w, v)
       brwword(w+2, v >> 16)
    pri brwclust(w, v)
    '
    '   Write a cluster entry.
       if (filesystem == 1)
         brwword(w, v)
       else
         brwlong(w, v)
    '
    '   This may do more complicated stuff later.
    '
    pub unmount
      pclose
      sdspi.stop
    pri getfstype : r
       if (brlong(@buf+$36) == constant("F" + ("A" << 8) + ("T" << 16) + ("1" << 24)) and buf[$3a]=="6")
         return 1
       if (brlong(@buf+$52) == constant("F" + ("A" << 8) + ("T" << 16) + ("3" << 24)) and buf[$56]=="2")
         return 2
       ' return r (default return)
    pub mount_explicit(DO, CLK, DI, CS) : r | start, sectorspercluster, reserved, rootentries, sectors
    {{
    '   Mount a volume.  The address passed in is passed along to the block
    '   layer; see the currently used block layer for documentation.  If the
    '   volume mounts, a 0 is returned, else abort is called.
    }}
       if (pdate == 0)
          pdate := constant(((2009-1980) << 25) + (1 << 21) + (27 << 16) + (7 << 11))
       unmount
       sdspi.start_explicit(DO, CLK, DI, CS)
       lastread := -1
       dirty := 0
       sdspi.readblock(0, @buf)
       if (getfstype > 0)
         start := 0
       else
         start := brlong(@buf+$1c6)
         sdspi.readblock(start, @buf)
       filesystem := getfstype
       if (filesystem == 0)
          abort(-20) ' not a fat16 or fat32 volume
       if (brword(@buf+$0b) <> SECTORSIZE)
          abort(-21) ' bad bytes per sector
       sectorspercluster := buf[$0d]
       if (sectorspercluster & (sectorspercluster - 1))
          abort(-22) ' bad sectors per cluster
       clustershift := 0
       repeat while (sectorspercluster > 1)
          clustershift++
          sectorspercluster >>= 1
       sectorspercluster := 1 << clustershift
       clustersize := SECTORSIZE << clustershift
       reserved := brword(@buf+$0e)
       if (buf[$10] <> 2)
          abort(-23) ' not two FATs
       sectors := brword(@buf+$13)
       if (sectors == 0)
         sectors := brlong(@buf+$20)
       fat1 := start + reserved
       if (filesystem == 2)
          rootentries := 16 << clustershift
          sectorsperfat := brlong(@buf+$24)
          dataregion := (fat1 + 2 * sectorsperfat) - 2 * sectorspercluster
          rootdir := (dataregion + (brword(@buf+$2c) << clustershift)) << SECTORSHIFT
          rootdirend := rootdir + (rootentries << DIRSHIFT)
          endofchain := $ffffff0
       else
          rootentries := brword(@buf+$11)
          sectorsperfat := brword(@buf+$16)
          rootdir := (fat1 + 2 * sectorsperfat) << SECTORSHIFT
          rootdirend := rootdir + (rootentries << DIRSHIFT)
          dataregion := 1 + ((rootdirend - 1) >> SECTORSHIFT) - 2 * sectorspercluster
          endofchain := $fff0
       if (brword(@buf+$1fe) <> $aa55)
         abort(-24) ' bad FAT signature
       totclusters := ((sectors - dataregion + start) >> clustershift)
       ' return r (default return)
    '
    '   For compatibility, a single pin.
    '
    pub mount(basepin) : r | start, sectorspercluster, reserved, rootentries, sectors
       return mount_explicit(basepin+2, basepin, basepin+1,  basepin+3)
    pri readbytec(byteloc)
    '
    '   Read a byte address from the disk through the metadata buffer and
    '   return a pointer to that location.
    '
       readblockc(byteloc >> SECTORSHIFT)
       return @buf2 + (byteloc & constant(SECTORSIZE - 1))
    pri readfat(clust)
    '
    '   Read a fat location and return a pointer to the location of that
    '   entry.
    '
       fatptr := (fat1 << SECTORSHIFT) + (clust << filesystem)
       return readbytec(fatptr)
    pri followchain : r
    '
    '   Follow the fat chain and update the writelink.
    '
       r := brclust(readfat(fclust))
       writelink := fatptr
       ' return r (default return)
    pri nextcluster : r
    '
    '   Read the next cluster and return it.  Set up writelink to
    '   point to the cluster we just read, for later updating.  If the
    '   cluster number is bad, return a negative number.
    '
       r := followchain
       if (r < 2 or r => totclusters)
          abort(-9) ' bad cluster value
       ' return r (default return)
    pri freeclusters(clust) | bp
    '
    '   Free an entire cluster chain.  Used by remove and by overwrite.
    '   Assumes the pointer has already been cleared/set to end of chain.
    '
       repeat while (clust < endofchain)
          if (clust < 2)
             abort(-26) ' bad cluster number")
          bp := readfat(clust)
          clust := brclust(bp)
          brwclust(bp, 0)
       flushifdirty
    pri datablock
    '
    '   Calculate the block address of the current data location.
    '
       return (fclust << clustershift) + dataregion + ((floc >> SECTORSHIFT) & ((1 << clustershift) - 1))
    pri uc(c)
    '
    '   Compute the upper case version of a character.
    '
       if ("a" =< c and c =< "z")
          return c - 32
       return c
    pri pflushbuf(rcnt, metadata) : r | cluststart, newcluster, count, i
    '
    '   Flush the current buffer, if we are open for write.  This may
    '   allocate a new cluster if needed.  If metadata is true, the
    '   metadata is written through to disk including any FAT cluster
    '   allocations and also the file size in the directory entry.
    '
       if (direntry == 0)
          abort(-27) ' not open for writing
       if (rcnt > 0) ' must *not* allocate cluster if flushing an empty buffer
          if (frem < SECTORSIZE)
             ' find a new clustercould be anywhere!  If possible, stay on the
             ' same page used for the last cluster.
             newcluster := -1
             cluststart := fclust & (!((SECTORSIZE >> filesystem) - 1))
             count := 2
             repeat
                readfat(cluststart)
                repeat i from 0 to SECTORSIZE - 1<<filesystem step 1<<filesystem
                  if (buf2[i] == 0)
                    if (brclust(@buf2+i) == 0)
                       newcluster := cluststart + (i >> filesystem)
                       if (newcluster => totclusters)
                          newcluster := -1
                       quit
                if (newcluster > 1)
                   brwclust(@buf2+i, endofchain+$f)
                   if (writelink == 0)
                      brwword(readbytec(direntry)+$1a, newcluster)
                      writelink := (direntry&(SECTORSIZE-filesystem))
                      brwlong(@buf2+writelink+$1c, floc+bufat)
                      if (filesystem == 2)
                         brwword(@buf2+writelink+$14, newcluster>>16)
                   else
                      brwclust(readbytec(writelink), newcluster)
                   writelink := fatptr + i
                   fclust := newcluster
                   frem := clustersize
                   quit
                else
                   cluststart += (SECTORSIZE >> filesystem)
                   if (cluststart => totclusters)
                      cluststart := 0
                      count--
                      if (rcnt < 0)
                         rcnt := -5 ' No space left on device
                         quit
          if (frem => SECTORSIZE)
             sdspi.writeblock(datablock, @buf)
             if (rcnt == SECTORSIZE) ' full buffer, clear it
                floc += rcnt
                frem -= rcnt
                bufat := 0
                bufend := rcnt
       if (rcnt < 0 or metadata) ' update metadata even if error
          readblockc(direntry >> SECTORSHIFT) ' flushes unwritten FAT too
          brwlong(@buf2+(direntry & (SECTORSIZE-filesystem))+$1c, floc+bufat)
          flushifdirty
       if (rcnt < 0)
          abort(rcnt)
       return rcnt
    pub pflush
    {{
    '   Call flush with the current data buffer location, and the flush
    '   metadata flag set.
    }}
       return pflushbuf(bufat, 1)
    pri pfillbuf : r
    '
    '   Get some data into an empty buffer.  If no more data is available,
    '   return -1.  Otherwise return the number of bytes read into the
    '   buffer.
    '
       if (floc => filesize)
          return -1
       if (frem == 0)
          fclust := nextcluster
          frem := (clustersize) <# (filesize - floc)
       sdspi.readblock(datablock, @buf)
       r := SECTORSIZE
       if (floc + r => filesize)
          r := filesize - floc
       floc += r
       frem -= r
       bufat := 0
       bufend := r
       ' return r (default return)
    pub pclose : r
    {{
    '   Flush and close the currently open file if any.  Also reset the
    '   pointers to valid values.  If there is no error, 0 will be returned.
    }}
       if (direntry)
          r := pflush
       bufat := 0
       bufend := 0
       filesize := 0
       floc := 0
       frem := 0
       writelink := 0
       direntry := 0
       fclust := 0
       firstcluster := 0
       sdspi.release
       ' return r (default return)
    pub setdate(year, month, day, hour, minute, second)
    {{
    '   Set the current date and time, as a long, in the format
    '   required by FAT16.  Various limits are not checked.
    }}
       pdate := ((year-1980) << 25) + (month << 21) + (day << 16)
       pdate += (hour << 11) + (minute << 5) + (second >> 1)
    pub popen(s, mode) : r | i, sentinel, dirptr, freeentry
    {{
    '   Close any currently open file, and open a new one with the given
    '   file name and mode.  Mode can be "r" "w" "a" or "d" (delete).
    '   If the file is opened successfully, 0 will be returned.  If the
    '   file did not exist, and the mode was not "w" or "a", -1 will be
    '   returned.  Otherwise abort will be called with a negative error
    '   code.
    }}
       pclose
       i := 0
       repeat while (i<8 and byte[s] and byte[s] <> ".")
          padname[i++] := uc(byte[s++])
       repeat while (i<8)
          padname[i++] := " "
       repeat while (byte[s] and byte[s] <> ".")
          s++
       if (byte[s] == ".")
          s++
       repeat while (i<11 and byte[s])
          padname[i++] := uc(byte[s++])
       repeat while (i < 11)
          padname[i++] := " "
       sentinel := 0
       freeentry := 0
       repeat dirptr from rootdir to rootdirend - DIRSIZE step DIRSIZE
          s := readbytec(dirptr)
          if (freeentry == 0 and (byte[s] == 0 or byte[s] == $e5))
             freeentry := dirptr
          if (byte[s] == 0)
             sentinel := dirptr
             quit
          repeat i from 0 to 10
             if (padname[i] <> byte[s][i])
                quit
          if (i == 11 and 0 == (byte[s][$0b] & $18)) ' this always returns
             fclust := brword(s+$1a)
             if (filesystem == 2)
                fclust += brword(s+$14) << 16
             firstcluster := fclust
             filesize := brlong(s+$1c)
             if (mode == "r")
                frem := (clustersize) <# (filesize)
                return 0
             if (byte[s][11] & $d9)
                abort(-6) ' no permission to write
             if (mode == "d")
                brwword(s, $e5)
                if (fclust)
                   freeclusters(fclust)
                flushifdirty
                return 0
             if (mode == "w")
                brwword(s+$1a, 0)
                brwword(s+$14, 0)
                brwlong(s+$1c, 0)
                writelink := 0
                direntry := dirptr
                if (fclust)
                   freeclusters(fclust)
                bufend := SECTORSIZE
                fclust := 0
                filesize := 0
                frem := 0
                return 0
             elseif (mode == "a")
    ' this code will eventually be moved to seek
                frem := filesize
                freeentry := clustersize
                if (fclust => endofchain)
                   fclust := 0
                repeat while (frem > freeentry)
                   if (fclust < 2)
                      abort(-7) ' eof repeat while following chain
                   fclust := nextcluster
                   frem -= freeentry
                floc := filesize & constant(!(SECTORSIZE - 1))
                bufend := SECTORSIZE
                bufat := frem & constant(SECTORSIZE - 1)
                writelink := 0
                direntry := dirptr
                if (bufat)
                   sdspi.readblock(datablock, @buf)
                   frem := freeentry - (floc & (freeentry - 1))
                else
                   if (fclust < 2 or frem == freeentry)
                      frem := 0
                   else
                      frem := freeentry - (floc & (freeentry - 1))
                if (fclust => 2)
                   followchain
                return 0
             else
                abort(-3) ' bad argument
       if (mode <> "w" and mode <> "a")
          return -1 ' not found
       direntry := freeentry
       if (direntry == 0)
          abort(-2) ' no empty directory entry
       ' write (or new append): create valid directory entry
       s := readbytec(direntry)
       bytefill(s, 0, DIRSIZE)
       bytemove(s, @padname, 11)
       brwword(s+$1a, 0)
       brwword(s+$14, 0)
       i := pdate
       brwlong(s+$e, i) ' write create time and date
       brwlong(s+$16, i) ' write last modified date and time
       if (direntry == sentinel and direntry + DIRSIZE < rootdirend)
          brwword(readbytec(direntry+DIRSIZE), 0)
       flushifdirty
       writelink := 0
       fclust := 0
       bufend := SECTORSIZE
       ' return r (default return)
    pub get_filesize
       return filesize
    pub pread(ubuf, count) : r | t
    {{
    '   Read count bytes into the buffer ubuf.  Returns the number of bytes
    '   successfully read, or a negative number if there is an error.
    '   The buffer may be as large as you want.
    }}
       repeat while (count > 0)
          if (bufat => bufend)
             t := pfillbuf
             if (t =< 0)
                if (r > 0)
    ' parens below prevent this from being optimized out
                  return (r)
                return t
          t := (bufend - bufat) <# (count)
          if ((t | (ubuf) | bufat) & 3)
             bytemove(ubuf, @buf+bufat, t)
          else
             longmove(ubuf, @buf+bufat, t>>2)
          bufat += t
          r += t
          ubuf += t
          count -= t
       ' return r (default return)
    pub pgetc | t
    {{
    '   Read and return a single character.  If the end of file is
    '   reached, -1 will be returned.  If an error occurs, a negative
    '   number will be returned.
    }}
       if (bufat => bufend)
          t := pfillbuf
          if (t =< 0)
             return -1
       return (buf[bufat++])
    pub pwrite(ubuf, count) : r | t
    {{
    '   Write count bytes from the buffer ubuf.  Returns the number of bytes
    '   successfully written, or a negative number if there is an error.
    '   The buffer may be as large as you want.
    }}
       repeat while (count > 0)
          if (bufat => bufend)
             pflushbuf(bufat, 0)
          t := (bufend - bufat) <# (count)
          if ((t | (ubuf) | bufat) & 3)
             bytemove(@buf+bufat, ubuf, t)
          else
             longmove(@buf+bufat, ubuf, t>>2)
          r += t
          bufat += t
          ubuf += t
          count -= t
       ' return r (default return)
    {{
    '   Write a null-terminated string to the file.
    }}
    pub pputs(b)
      return pwrite(b, strsize(b))
    pub pputc(c) : r
    {{
    '   Write a single character into the file open for write.  Returns
    '   0 if successful, or a negative number if some error occurred.
    }}
       if (bufat == SECTORSIZE)
         if (pflushbuf(SECTORSIZE, 0) < 0)
           return -1
       buf[bufat++] := c
       ' return r (default return)
    {{
    '   Seek.  Right now will only seek within the current cluster.
    '   Added for PrEdit so he can debug; do not use with files larger
    '   than one cluster (and make that cluster size 32K please.)
    '
    '   Returns -1 on failure.  Make sure to check this return code!
    '
    '   We only support reads right now (but writes won"t be too hard to
    '   add).
    }}
    pub seek(pos) | delta
       if (direntry or pos < 0 or pos > filesize)
          return -1
       delta := (floc - bufend) & - clustersize
       if (pos < delta)
          fclust := firstcluster
          frem := (clustersize) <# (filesize)
          floc := 0
          bufat := 0
          bufend := 0
          delta := 0
       repeat while (pos => delta + clustersize)
          fclust := nextcluster
          floc += clustersize
          delta += clustersize
          frem := (clustersize) <# (filesize - floc)
          bufat := 0
          bufend := 0
       if (bufend == 0 or pos < floc - bufend or pos => floc - bufend + SECTORSIZE)
          ' must change buffer
          delta := floc + frem
          floc := pos & - SECTORSIZE
          frem := delta - floc
          pfillbuf
       bufat := pos & (SECTORSIZE - 1)
       return 0
    pub tell
       return floc + bufat - bufend
    pub opendir | off
    {{
    '   Close the currently open file, and set up the read buffer for
    '   calls to nextfile.
    }}
       pclose
       off := rootdir - (dataregion << SECTORSHIFT)
       fclust := off >> (clustershift + SECTORSHIFT)
       floc := off - (fclust << (clustershift + SECTORSHIFT))
       frem := rootdirend - rootdir
       filesize := floc + frem
       return 0
    pub nextfile(fbuf) | i, t, at, lns
    {{
    '   Find the next file in the root directory and extract its
    '   (8.3) name into fbuf.  Fbuf must be sized to hold at least
    '   13 characters (8 + 1 + 3 + 1).  If there is no next file,
    '   -1 will be returned.  If there is, 0 will be returned.
    }}
       repeat
          if (bufat => bufend)
             t := pfillbuf
             if (t < 0)
                return t
             if (((floc >> SECTORSHIFT) & ((1 << clustershift) - 1)) == 0)
                fclust++
          at := @buf + bufat
          if (byte[at] == 0)
             return -1
          bufat += DIRSIZE
          if (byte[at] <> $e5 and (byte[at][$0b] & $18) == 0)
             lns := fbuf
             repeat i from 0 to 10
                byte[fbuf] := byte[at][i]
                fbuf++
                if (byte[at][i] <> " ")
                   lns := fbuf
                if (i == 7 or i == 10)
                   fbuf := lns
                   if (i == 7)
                      byte[fbuf] := "."
                      fbuf++
             byte[fbuf] := 0
             return 0
    {{
    '   Utility routines; may be removed.
    }}
    pub getclustersize
      return clustersize
    pub getclustercount
      return totclusters
    {{
    '  Permission is hereby granted, free of charge, to any person obtaining
    '  a copy of this software and associated documentation files
    '  (the "Software"), to deal in the Software without restriction,
    '  including without limitation the rights to use, copy, modify, merge,
    '  publish, distribute, sublicense, and/or sell copies of the Software,
    '  and to permit persons to whom the Software is furnished to do so,
    '  subject to the following conditions:
    '
    '  The above copyright notice and this permission notice shall be included
    '  in all copies or substantial portions of the Software.
    '
    '  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    '  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    '  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    '  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
    '  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
    '  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    '  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    }}
    DAT
    filesystem  long 0 ' 0 = unmounted, 1 = fat16, 2 = fat32
    rootdir  long 0 ' the byte address of the start of the root directory
    rootdirend  long 0 ' the byte immediately following the root directory.
    dataregion  long 0 ' the start of the data region, offset by two sectors
    clustershift  long 0 ' log base 2 of blocks per cluster
    clustersize  long 0 ' total size of cluster in bytes
    fat1  long 0 ' the block address of the fat1 space
    totclusters  long 0 ' how many clusters in the volume
    sectorsperfat  long 0 ' how many sectors per fat
    endofchain  long 0 ' end of chain marker (with a 0 at the end)
    pdate  long 0 ' current date
    lastread  long 0 ' the block address of the buf2 contents
    dirty  long 0 ' nonzero if buf2 is dirty
    buf2 byte 0[SECTORSIZE]  ' main metadata buffer
    padname byte 0[11]  ' filename buffer
    


    I made small changes to fsrw, made the mount command work *sometimes?*
    The test code I was having problems with is
    [code]
    CON
    {''Hardware version 3.11 - see diagram.
    ''
    }
    _clkmode = xtal1 + pll16x ' use crystal x 16
    _xinfreq = 5_000_000 'with 5mhz crystal

    DEV_SD_CLK = 18
    DEV_SD_DI = 19
    DEV_SD_DO = 20
    DEV_SPI_EN = 21 ''SPI Enable enumeration
    DEV_SPI_ADD0 = 22 ''Device address 0 enumeration
    DEV_SPI_ADD1 = 23 ''Device address 1 enumeration
    DEV_SPI_ADD_LE = 24

    DEV_SPI_LCD_RES = 0 ''Device id for LCD reset
    SDC = 1
    TSC = 2
    EXT = 3
    DEV_SPI_EXT_POT_CS = 0
    DEV_SPI_EXT_SW_CS = 1

    BGCOLOR = $ffff
    TXTCOLOR = $0000
    Pressed = 1
    NotPressed = 0
    faderUpBtnBound = 499 ''y < 499
    faderDnBtnBound = 3700 ''y > 3699 3200, 1600, 320
    fadertouchoffset = 320 ''3375 < y < 825 range e


    offset = 8 * 2048 ' the block offset of where we do writes

    VAR
    long Screen_Buffer, CRbuffer

    byte tbuf[20]
    byte bigbuf[8192]

    long BackgroundColor, ActiveTextColor, stringptr[65], maxdur,sr ,speedresults
    BYTE Fader0[3], Fader1[3], Fader2[3], Fader3[3], FaderPOS, NewFaderValue, OldValue 'FaderOrentation holds 0 for landscape, portrait not enabled
    word Button0[5], Button1[5], Button2[5], Button3[5], Button4[5], Button5[5], ButtonX, ButtonY, ButtonState, OldState
    WORD NotPressedBGC,NotPressedATC,PressedBGC,PressedATC, ButtonName, ButtonReg 'ButtonGroup,oldButtonGroup,faderOrentation,
    OBJ pfw :"PropFont_asmDone"
    wait : "timing"
    'pst : "parallax serial terminal"
    spi : "spi_asm"
    sdfat: "fsrw"
    block: "safe_spi"
    ILI9325:"ILI9325_Dracblade"
    PUB BOOT | f 'bootstrap, initalizes pins, then starts pst, init display, start asm, clear screen and display hello world
    WAIT.PAUSE1S(5)
    initPins
    BackgroundColor := $ffe0
    ActiveTextColor := %0000
    long[@Screen_Buffer] := $ffff
Sign In or Register to comment.