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.
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 :
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.
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
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?
@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.
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
@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?
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
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.
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
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!
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.
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...
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.
... 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]
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.
[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
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.
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.
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
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
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
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 ). 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?
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.
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.
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.
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?
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
Comments
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.
Current version is much faster. Fully working?
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.
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
.
*edit*
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.
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
Then try dropping in this startup code.
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.
This could be modified for 8 bit writes if necessary.
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!
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.
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...
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. that's the main object and it's call, the pfw object is what is the RIGHT way to pass this address. I'm lost.
[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 This is CrReader, thanks Kuroneko Then we have propfont_asm
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.
Little slider bars. How cool would it be to make them move when you move your finger along them?!
The call... The method that passes the write And the dat block The faders look something like this These are really buggy right now.
Thanks,
Tyler
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.
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 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.
SD-MMC File Allocation Table Engine
Version: 2.0 - Special
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?
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
and the helpers
propFont, now has passthrough functions...
and my fsrw stuff for good measure
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