Clifton Laboratories 7236 Clifton Road  Clifton VA 20124 tel: (703) 830 0368 fax: (703) 830 0711

E-mail: Jack.Smith@cliftonlaboratories.com
 

 

To search within the Clifton Laboratories site, enter your search term below.
 

 


Home
Up
Updates
Current Products
Prior Products - no longer available
Documents
Book
Software Updates
Softrock Lite 6.2
Adventures in Electronics and Radio
Elecraft K2 and K3 Transceivers

 
Graphics LCD Driver Module

I've had a request to post the graphics LCD module that I use in the Z90. Here it is. This module is written for the Swordfish BASIC compiler and Crystalfontz's 320x240 "quarter VGA" GLCD, model CFAG320240C, with integrated controller. I understand that Crystalfontz's new displays use the updated S1D13700 controller. A data sheet for the S1D13700 controller is available for download from Crystalfontz at this link.

The earlier display that my GLCD module was developed with uses an S1D13305F controller, a data sheet for which is available for download from Crystalfontz at this link. I believe the S1D13305F is a variant of the SED1335.

I'm still awaiting delivery of displays with the S1D13700 controller for compatibility testing, estimated delivery date is mid-October 2006. I believe the two controllers are broadly compatible but until testing I cannot substantiate that belief.

Unfortunately, until the Z90 project is completed I don't have the time to answer a lot of questions concerning the code or the display module. 

Swordfish's chief software developer tells me that he plans to add support for these quarter VGA GLCD modules in a future Swordfish release, via an "official" Swordfish library, but that there are other modules ahead of it in the priority queue. I've provided a copy of this library to Swordfish with permission to use any of it deemed useful. 

 

'****************************************************************

'* Name : CF320240.BAS *

'* Author : Jack Smith *

'* Notice : Copyright (c) 2006 Jack R. Smith *

'* : All Rights Reserved *

'* Date : 1/31/2006 *

'* Version : 1.0 *

'* Notes : Started 31 Jan 2006 *

'* : *

'****************************************************************

//

// LCD INFORMATION & CONNECTION

// ----------------------------

// Library assumes a CrystalFontz 320x240 graphic LCD is connected to the PIC.

// CFAG320240C Series LCD. Factory-shipped with jumper JM in 6800 compatibility mode. This is OK

//Connections are:

// LCD Pin Fcn PIC Pin LCD Pin Fcn PIC Pin

// 1 GND -- 11 DB4 PortD.4

// 2 +5V -- 12 DB5 PortD.5

// 3 Vo -- 13 DB6 PortD.6

// 4 E PortE.0 14 DB7 PortD.7

// 5 R/W PortE.1 15 CS PortA.5

// 6 A0 PortE.2 16 RES PortA.1

// 7 DB0 PortD.0 17 Vee --

// 8 DB1 PortD.1 18 Frame -- [to ground]

// 9 DB2 PortD.2 19 unused --

// 10 DB3 PortD.3 20 unused --

//

// LCD Pin 3 to wiper of 20k POT. One end off pot to +5V, other end to Vee (pin 17)

// Pot adjusts contrast. Vee outputs ~ -20V from on-board power inverter

//

// Program demonstrates how to initialize the LCD and display text and graphics

// with display screen for panadapter display.

 

'--------------

Module CF320240

'--------------

Include "string.bas"

Include "usart.bas"

Include "globalconst.bas"

Include "utils.bas"

Include "math.bas"

Public Const

GLCD_Width = 320, //dimensions of LCD display

GLCD_Height = 240,

GLCD_CharWidth = 8, //built-in character generator dimensions

GLCD_CharHeight = 8, //ditto

GLCD_TextAdr = $0000, //text memory

GLCD_GrAdr = GLCD_Width * GLCD_Height / 64,

GLCD_GrAdrEnd = GLCD_GrAdr + (GLCD_Width * GLCD_Height),

GLCD_CR = GLCD_Width / 8 - 1,

GLCD_CMD_SYSTEM = $40, // General system settings

GLCD_CMD_SLEEP = $53, // Enter into standy mode

GLCD_CMD_DISP_OFF = $58, // Turn the display off

GLCD_CMD_DISP_ON = $59, // Turn the display on

GLCD_CMD_SCROLL = $44, // Setup text and graphics address regions

GLCD_CMD_CSR_FORM = $5D, // Set cursor size

GLCD_CMD_CSRDIR_RIGHT = $4C, // Cursor moves right after write to display memory

GLCD_CMD_CSRDIR_LEFT = $4D, // Cursor moves left after write to display memory

GLCD_CMD_CSRDIR_UP = $4E, // Cursor moves up after write to display memory

GLCD_CMD_CSRDIR_DN = $4F, // Cursor moves down after write to display memory

GLCD_CMD_CGRAM_ADDR = $5C, // Configure character generator RAM address

GLCD_CMD_HDOT_SCR = $5A, // Set horizontal scroll rate

GLCD_CMD_OVERLAY = $5B, // Configure how layers overlay

GLCD_CMD_SET_CSR_ADDR = $46, // Set the cursor address

GLCD_CMD_GET_CSR_ADDR = $47, // Read the cursor address

GLCD_CMD_DISPLAY_WRITE = $42, // Write to display memory

GLCD_CMD_DISPLAY_READ = $43, // Read from display memory

MemLength = GLCD_Width * GLCD_Height / 8, // memory required for full graphics

// = 9600 bytes

PageAStart = $0960, // start of memory for Graphics Page A

PageAEnd = PageAStart + MemLength - 1,

PageBStart = PageAStart + MemLength, 'memory required for full graphics

PageBEnd = PageBStart + MemLength -1, 'page B end

CheckVal = %10101010, 'for writing to see if have problems

CheckAdr = PageBEnd + 256 'with loss of synchronization

// error check data port, then set default - user option will override...

#if IsOption(CLF_DATA) And Not IsValidPort(CLF_DATA) Or IsOption(CLF_DATA@)

#error CLF_DATA, "Invalid option. DATA must be a valid MCU port name."

#endif

#option CLF_DATA = PORTD

// error check data access, then set default - user option will override...

#if IsOption(CLF_ACCESS) And Not IsValidPortPin(CLF_ACCESS)

#error CLF_ACCESS, "Invalid option. ACCESS must be a valid MCU port pin."

#endif

#option CLF_ACCESS = PORTE.2

// error check RW, then set default - user option will override...

#if IsOption(CLF_RW) And Not IsValidPortPin(CLF_RW)

#error CLF_RW, "Invalid option. RW must be a valid MCU port pin."

#endif

#option CLF_RW = PORTE.1

// error check ENABLE, then set default - user option will override...

#if IsOption(CLF_ENABLE) And Not IsValidPortPin(CLF_ENABLE)

#error CLF_ENABLE, "Invalid option. ENABLE must be a valid MCU port pin."

#endif

#option CLF_ENABLE = PORTE.0

// error check CS, then set default - user option will override...

#if IsOption(CLF_CS) And Not IsValidPortPin(CLF_CS)

#error CLF_CS, "Invalid option. CS must be a valid MCU port pin."

#endif

#option CLF_CS = PORTA.5

// error check RESET, then set default - user option will override...

#if IsOption(CLF_RESET) And Not IsValidPortPin(CLF_RESET)

#error CLF_RESET, "Invalid option. RESET must be a valid MCU port pin."

#endif

#option CLF_RESET = PORTA.1

// port and pin assignments...

Private Dim

DatPort As CLF_DATA, // LCD Data bus (DB0..DB7) is connected to PortD

A0 As CLF_ACCESS.CLF_ACCESS@, // A0 sets data destination. A0=1 control / A0=0 memory

RW As CLF_RW.CLF_RW@, // Read/Write direction. R/W = 0 is write to LCD, R/W=1 read from LCD

E As CLF_ENABLE.CLF_ENABLE@, // E=enable in 6800 mode. Serves as a strobe

CS As CLF_CS.CLF_CS@, // Chip select -- CS=0 is selected CS=1 is disabled

RES As CLF_RESET.CLF_RESET@ // RES = Reset. Normally RES=1 but take it to 0 for initialization

'Subroutine Initialize.

'Purpose: Set up ports for I/O and perform RESET on LCD

'Call Initialize before doing anything to the LCD

'-----------------------

Public Sub Initialize()

'-----------------------

CMCON = %00000111 // must disable comparators to read with PortD

TRISD = $00 //all Ports D & E are output

// Must use ADCON1 to set PortA pins to mixed digital/analog

'ADCON1 = %10001111 // A0 is analog input rest of PortA are digitial

// V+ref = AN3 for %1111

ADCON1 = %00011110 'for PIC18F4620 ONLY

TRISE = $00 // Set all PortE pins for output. Also disable D slave

TRISA = %00001001 // Still must set PortA digital pins for Output

// Don't forget AN3 must also be an INPUT

RES = %1 //RST = HIGH for operation

CS = %1 //CS = HIGH - chip is unselected

E = %1 //E = High - exact status unimportant at the moment

RW = %1 //WR = HIGH - also unimportant at the moment

A0 = %0 //A0 = Low - not important now

CS = %0 //Chip select is active LOW - set to 0 to enable LCD

DelayMS(10)

RES = %0 //accomplish reset via low

DelayMS(5) //3 ms minimum, so we'll wait a bit longer for safety

RES = %1 //take high to end reset and restore function to normal

DelayMS(10) //time for reset to take effect

RW = %0 //R/w = 0 to permit writing to the LCD

End Sub // Initialize

 

'Returns the high byte of pValue. pValue can be a constant

'-----------------------------------------

Public Function Hi(pValue As Word) As Byte

'-----------------------------------------

Hi = pValue.Byte1

End Function

 

'Returns the high byte of pValue. pValue can be a constant

'-----------------------------------------

Public Function Lo(pVaLUE As Word) As Byte

'-----------------------------------------

Lo = pValue.Byte0

End Function

 

'Subroutine WriteCtrl writes a control byte to the LCD

'Call with the byte to be written. Assumes E is set low upon entry

'-------------------------------------

Public Sub WriteCtrl(CtrlByte As Byte)

'-------------------------------------

DatPort = CtrlByte //assert data on bus - give it time to settle

ASM

NOP

NOP

End ASM

A0 = %1 //SET A0 -- this determines that the data is intrepreted as control by LCD

ASM

NOP

NOP

End ASM

CS = %0 //CLEAR CS

ASM

NOP

NOP

End ASM

E = %1 //SET E -- data is read on falling edge of E.

ASM // E must be high at least 120ns

NOP

NOP

NOP

End ASM

E = %0 //CLEAR E -- here's the falling edge

ASM // E must be high at least 120ns

NOP

NOP

NOP

End ASM

CS = %1 //SET CS

ASM

NOP

NOP

End ASM

End Sub // WriteCtrl

 

'Subroutine WriteCtrl writes a control byte to the LCD

'Call with the byte to be written. Assumes E is set low upon entry

'Only difference between WriteCtrl and WriteData is value of A0

'Public Inline Sub WriteData(DataByte as Byte)

'-------------------------------------

Public Sub WriteData(DataByte As Byte)

'-------------------------------------

ASM

NOP

NOP

End ASM

DatPort = DataByte //assert data on bus - give it time to settle

ASM

NOP

NOP

End ASM

A0 = %0 //CLEAR A0 -- this determines that the data is intrepreted as data by LCD

ASM

NOP

NOP

End ASM

CS = %0 //CLEAR CS

ASM

NOP

NOP

End ASM

E = %1 //SET E -- data is read on falling edge of E.

ASM // E must be high at least 120ns

NOP

NOP

NOP

End ASM

E = %0 //CLEAR E -- here's the falling edge

ASM // E must be high at least 120ns

NOP

NOP

NOP

End ASM

CS = %1 //SET CS

ASM

NOP

NOP

End ASM

End Sub // WriteData

 

'Function ReadData reads the LCD's databus and returns the byte read. Data

'address is previously set via a set cursor command

'---------------------------------

Public Inline Function ReadData() As Byte

'---------------------------------

PortD = $00

TRISD = $FF // set data port for input

ASM

NOP

NOP

End ASM

E = %0

ASM

NOP

NOP

End ASM

CS = %0 //CLEAR CS to activate chip

ASM

NOP

NOP

End ASM

RW = %1 // Read from LCD

ASM

NOP

NOP

End ASM

A0 = %1

ASM

NOP

NOP

End ASM

E = %1

Result = PortD // use a read as a delay statement

Result = PortD

Result = PortD

Result = PortD // delay is required to let LCD bus xfer data

E = %0

ASM

NOP

NOP

End ASM

RW = %0 // Restore data bus direction for writing to LCD

ASM

NOP

NOP

End ASM

A0 = %0

ASM

NOP

NOP

End ASM

TRISD = $00 // reset data port for output

ASM

NOP

NOP

End ASM

PortD = $00

ASM

NOP

NOP

NOP

End ASM

CS = %1 //SET CS

ASM

NOP

NOP

End ASM

End Function

'Returns the current Cursor Address

'-----------------------------------

Public Function GetCursAdr() As Word

'-----------------------------------

WriteCtrl(GLCD_CMD_GET_CSR_ADDR)

Result.Byte0 = ReadData

Result.Byte1 = ReadData

End Function

'sub CursMem moves the cursor to the memory address MemStart. Remember that the cursor is

'the starting LCD memory address for read/write. The cursor auto increments as defined by

'another parameter setting, cursor direction.

'Call with the starting memory address as a WORD variable

'Public Inline sub CursMem(MemStart as Word)

'-----------------------------------

Public Sub CursMem(MemStart As Word) 'positions cursor to MemStart

'-----------------------------------

WriteCtrl(GLCD_CMD_SET_CSR_ADDR) // command - next two bytes are Low/High bytes of memory start

WriteData(MemStart.Byte0) // send in sequence LOW BYTE then

WriteData(MemStart.Byte1) // the HIGH BYTE

{

While MemStart <> GetCursAdr

WriteCtrl(GLCD_CMD_SET_CSR_ADDR) // check for correct cursor start adr

WriteData(MemStart.Byte0)

WriteData(MemStart.Byte1)

WEND

}

End Sub // CursMem

 

'Subroutine ClearTextMem writes blanks (spaces) into all text memory

'------------------------

Public Sub ClearTextMem()

'------------------------

Dim

m As Word // loop counter to go through text memory

CursMem(GLCD_TextAdr) // Position cursor to start of text memory at $0000

WriteCtrl(GLCD_CMD_DISPLAY_WRITE) // Set to write to display memory

For m = 1 To (30 * 40) // Text memory corresponds to 30 rows

WriteData(" ") // of 40 characters per row using built-in

Next 'm // character gen 5 x 7 using 8x8 cells

CursMem(GLCD_TextAdr) // good practice to reset cursor to start

End Sub // subroutine ClearTextMem

 

'Subroutine ClearGraphicMem clears the graphics memory by writing $00 to the

'memory bytes representing one graphics page, starting at Where.

'----------------------------------------

Public Sub ClearGraphicMem(Where As Word)

'----------------------------------------

Dim

m As Word // loop counter to go through text memory

CursMem(Where) // start of graphic memory = .2400 << REV to named constant>>

WriteCtrl(GLCD_CMD_DISPLAY_WRITE) // Set to write to display memory

// Graphics memory set up similarly to

For m = 0 To MemLength-1 // text memory except each row is 1 pixel tall.

WriteData($00) // hence one page is 240 pixels tall * 40 bytes wide

Next 'm // total memory in Crystalfontz LCD is 32 K so clear

// some extra memory while we are at it

CursMem(GLCD_TextAdr) // reset cursor to start of text memory

End Sub // subroutine ClearGraphicMem

 

'Subroutine TextOut writes a text string of maximum

'length 30 at coordinates Row,Col. Used to put the status value report up

'If COl > 40, then program auto-centers the text

'--------------------------------------------------------

Public Sub TextOut(s As String, Col As Byte, Row As Byte)

'--------------------------------------------------------

Dim

MemLoc As Word,

n As Byte

//USART.Write("Into Text Out",13)

//USART.Write("Str Len: ",DecToStr(Length(s)),9,"Str: ",s,13)

// look for auto-centering value

If Col > 39 Then // if Col > 40 then auto-center the string

Col = (40 - Length(s))/2

EndIf

If Row > 29 Then Row = 0 EndIf

// text memory starts at $0000. Organized in

MemLoc = Row * 40 + Col // continous strip with wraparound.

// [0000][0001]...[0039] ROW 0 (top of LCD)

CursMem(MemLoc) // [0040][0041] ...[0079] ROW 1

// ...

// [1160[1161] ... [1199] BOTTOM ROW

// [ ] values are decimal memory addresses

// above code calculates mem address for ROW/COL

// and then sets cursor to that mem address

WriteCtrl(GLCD_CMD_DISPLAY_WRITE) // command to write to LCD memory

If (Length(s) >= 1) And (Length(s) < 41) Then

For n = 0 To Length(s)-1 // only give command 1 time for sequence

WriteData(s(n)) // cursor auto advances

Next 'n // so we write the text one letter at a time

EndIf

//USART.Write("Row ",DecToStr(Row),9,

// "Col ",DecToStr(Col),9,

// "Str Len: ",DecToStr(Length(s)),9,

// "Str: ",s,13)

End Sub 'Subroutine TextOut

 

'Subroutine FastDrawBox draws a 8x10 graticule on the screen at right side

'the box is 240 x 240 pixels. Where defines PageA or PageB memory area

'FastDrawBox is revised to remove conditional tests

'------------------------------------ // Graticule has solid line box

Public Sub FastDrawBox(Where As Word) // with solid dividers at 50%

'------------------------------------ // other dividers are . . . . .

Dim // layout is 8 x 10 divisions

n,l As Byte,

m As Word,

Ind(6) As Byte

Ind(0) = 1

Ind(1) = 2

Ind(2) = 3

Ind(3) = 5

Ind(4) = 6

Ind(5) = 7

//draw vertical lines first

For n = 0 To 10 Step 5 // First put on vertical lines

For l = 0 To 232 // For 10 divisions, need 11 lines

m = Where + 9 + l*40 // Display area is 240 pixels, so lines

m = m + Byte(3*n) // are 24 pixels apart. Memory indexes

WriteCtrl(GLCD_CMD_SET_CSR_ADDR) //jumps by 40 bytes per display line

WriteData(m.Byte0) // see SED1335 data sheet for more info

WriteData(m.Byte1) // setup memory index a/k/a cursor adr

WriteCtrl(GLCD_CMD_DISPLAY_WRITE)

WriteData(%00000001) // write solid lines

Next 'l // each byte, as a byte represents a horizontal line

Next 'n

For n = 1 To 9 // First put on vertical lines

For l = 0 To 232 Step 4 // For 10 divisions, need 11 lines

m = Where + 9 + l*40 // Display area is 240 pixels, so lines

m = m + Byte(3*n) // are 24 pixels apart. Memory indexes

WriteCtrl(GLCD_CMD_SET_CSR_ADDR) //jumps by 40 bytes per display line

WriteData(m.Byte0) // see SED1335 data sheet for more info

WriteData(m.Byte1) // setup memory index a/k/a cursor adr

WriteCtrl(GLCD_CMD_DISPLAY_WRITE)

WriteData(%00000001) // write solid lines

Next 'l // each byte, as a byte represents a horizontal line

Next 'n

// now draw horizontal lines First draw 6 horizontal dotted lines

For l = 0 To 5 'Start of memory is function of X & Y

m = Where + 10 + Word(Ind(l)*1160) '+10 starts at 80 pixesl from left

WriteCtrl(GLCD_CMD_SET_CSR_ADDR) 'point cursor to starting point

WriteData(m.Byte0) 'load starting point

WriteData(m.Byte1) '

'

WriteCtrl(GLCD_CMD_DISPLAY_WRITE) 'lines are 8*(1+(39-10)) pixels wide

For n = 10 To 39 '

WriteData(%10001000) 'these intermediate lines are dotted

Next 'm

Next 'l

For l = 0 To 8 Step 4

m = Where + 10 + Word(l*1160) //need 9 lines for 8 divisions

WriteCtrl(GLCD_CMD_SET_CSR_ADDR)

WriteData(m.Byte0)

WriteData(m.Byte1) //graphics memory starts at 0x960 = .2400

WriteCtrl(GLCD_CMD_DISPLAY_WRITE) // now write the lines

For n = 10 To 39 // others are dotted.

WriteData($FF) // solid line is $FF

Next 'm

Next 'l

End Sub

 

'Initialize and set up various registers in the LCD control board

'Need to go back and replace some hard coding with defined constants

'----------------------

Public Sub InitDisplay()

'----------------------

WriteCtrl(GLCD_CMD_SYSTEM) // Execute System Set Instruction

WriteData($30) // Control byte sets internal char gen. See 8.2.1 of DS

WriteData($87) // FX -- horizontal char size. See 8.2.1.7

WriteData($07) // FY -- vertical char size - 1

WriteData($27) // C/R. Bytes per line horizintally - 1. 320/8 = .40 = $28

WriteData($42) // TC/R. Complicated - provides overscan idle time see DS

WriteData(GLCD_Height-1) // LF -- height of frame in lines -1. $EF = 239

WriteData($28) // APL -- low byte of AP. AP = horizontal address of virtual

WriteData($00) // screen. APH is high byte. See Fig 8 in DS

WriteCtrl(GLCD_CMD_SCROLL) // sets scroll address and lines per scroll block

WriteData($00) // SAD 1 Low - start of text memory

WriteData($00) // SAD 1 High

WriteData(GLCD_Height-1) // SL 1 $EF=.239

WriteData(Lo(PageAStart)) // SAD 2 Low - start of graphic memory

WriteData(Hi(PageAStart)) // SAD 2 High - start at $0960 = 2400

WriteData(GLCD_Height-1) // SL 2 $EF=.239

WriteData(Lo(PageBStart)) // SAD 3 Low

WriteData(Hi(PageBStart)) // SAD 3 High

WriteData(00) // SAD 4 Low

WriteData(00) // SAD 4 High

WriteCtrl(GLCD_CMD_HDOT_SCR) // allow screen to scroll by pixels

WriteData($00) // set to zero pixels for now

WriteCtrl(GLCD_CMD_OVERLAY) // how text and graphics layers are combined

WriteData($00) // set to Priority OR L1 > L2 > L3 $03

WriteCtrl(GLCD_CMD_DISP_OFF) // command for screen on/off

WriteData($14) // turns screen off

WriteCtrl(GLCD_CMD_CSR_FORM) // select cursor size and shape

WriteData($07) // cursor width = 8 pixels (7+1)

WriteData($87) // cursor height is 8 pixels & block style

WriteCtrl(GLCD_CMD_DISP_ON) // command for screen on/off

WriteData($14) // turn screen on, layers 1 & 2 ON

WriteCtrl(GLCD_CMD_CSRDIR_RIGHT) // set cursor to increment to right

CursMem(GLCD_TextAdr) // tidy up with cursor at start of text

// ClearGraphicMem(PageAStart) // clear the graphics memory

// ClearGraphicMem(PageBStart) // both dispay pages

// ClearTextMem //clear text memory

End Sub // Subroutine InitDisplay

 

 

'RefreshRegs re-writes the minimum set of registers necessary to

'fix the register trashing observed

'----------------------

Public Sub RefreshRegs(WhereA, WhereB As Word)

'----------------------

WriteCtrl(GLCD_CMD_SYSTEM) // Execute System Set Instruction

WriteData($30) // Control byte sets internal char gen. See 8.2.1 of DS

WriteData($87) // FX -- horizontal char size. See 8.2.1.7

WriteData($07) // FY -- vertical char size - 1

WriteData($27) // C/R. Bytes per line horizintally - 1. 320/8 = .40 = $28

WriteData($42) // TC/R. Complicated - provides overscan idle time see DS

WriteData(GLCD_Height-1) // LF -- height of frame in lines -1. $EF = 239

WriteData($28) // APL -- low byte of AP. AP = horizontal address of virtual

WriteData($00) // screen. APH is high byte. See Fig 8 in DS

WriteCtrl(GLCD_CMD_SCROLL) // sets scroll address and lines per scroll block

WriteData($00) // SAD 1 Low - start of text memory

WriteData($00) // SAD 1 High

WriteData(GLCD_Height-1) // SL 1 $EF=.239

WriteData(WhereA.Byte0) // SAD 2 Low - start of graphic memory

WriteData(WhereA.Byte1) // SAD 2 Low - start of graphic memory

WriteData(GLCD_Height-1) // SL 2 $EF=.239

WriteData(WhereB.Byte0) // SAD 2 Low - start of graphic memory

WriteData(WhereB.Byte1) // SAD 2 Low - start of graphic memory

WriteData(00) // SAD 4 Low

WriteData(00) // SAD 4 High

WriteCtrl(GLCD_CMD_HDOT_SCR) // allow screen to scroll by pixels

WriteData($00) // set to zero pixels for now

'needed

WriteCtrl(GLCD_CMD_OVERLAY) // how text and graphics layers are combined

WriteData($00) // set to Priority OR L1 > L2 > L3 $03

WriteCtrl(GLCD_CMD_DISP_OFF) // command for screen on/off

WriteData($14) // turns screen off

WriteCtrl(GLCD_CMD_CSR_FORM) // select cursor size and shape

WriteData($07) // cursor width = 8 pixels (7+1)

WriteData($87) // cursor height is 8 pixels & block style

WriteCtrl(GLCD_CMD_DISP_ON) // command for screen on/off

WriteData($14) // turn screen on, layers 1 & 2 ON

WriteCtrl(GLCD_CMD_CSRDIR_RIGHT) // set cursor to increment to right

End Sub // Subroutine RefreshRegs

 

'Write a pixel to the LCD at location X,Y. If mode = true then clear

'------------------------------------------------------------------------

Public Sub PutPixel(x As Word, y As Word, Mode As Boolean, Where As Word)

'------------------------------------------------------------------------

Dim

MemAdr As Word,

Offset As Byte,

temp As Byte

If x > 319 Then x = 319 EndIf

//If y > 239 Then y = 239 EndIf

If y > 239 Then y = 0 EndIf

MemAdr = Where + y * 40 + x/8

Offset = x - ((x/8) * 8)

WriteCtrl(GLCD_CMD_SET_CSR_ADDR)

WriteData(MemAdr.Byte0)

WriteData(MemAdr.Byte1)

WriteCtrl(GLCD_CMD_DISPLAY_READ)

temp = ReadData()

If Mode Then

temp = temp Or (%10000000 >> Offset)

Else

temp = temp And (%01111111 >> Offset)

EndIf

WriteCtrl(GLCD_CMD_SET_CSR_ADDR)

WriteData(MemAdr.Byte0)

WriteData(MemAdr.Byte1)

WriteCtrl(GLCD_CMD_DISPLAY_WRITE)

WriteData(temp) // fix

End Sub

'Subroutine VLine draws a vertical line at X position X, between Ystart and

'Yend. Mode defines line or erase line. True = line, false = erase line

'-------------------------------------------------------------------------

Public Sub VLine(x As Word, ystart As Byte, yend As Byte,

Mode As Boolean, Where As Word)

'-------------------------------------------------------------------------

Dim

i, istart,iend As Byte 'used in indexing

If yend > ystart Then 'need to determine direction to write data

istart = ystart

iend = yend 'this code sets istart to the lower of

Else 'ystart and yend. iend is then set to the

istart = yend 'greatere of ystart and yend

iend = ystart

EndIf

For i = istart To iend 'to draw the vertical line, just write the

PutPixel(x,i,Mode, Where) 'pixels to the screen

Next

End Sub

'Subroutine HLine draws a horizontal line at position X, between X and

'Xend. Mode defines line or erase line. True = line, false = erase line

'-------------------------------------------------------------------------

Public Sub HLine(xstart As Word, y As Word, xend As Word,

Mode As Boolean, Where As Word)

'-------------------------------------------------------------------------

Dim

i, istart,iend As Word 'used in indexing

If xend > xstart Then 'need to determine direction to write data

istart = xstart

iend = xend 'this code sets istart to the lower of

Else 'ystart and yend. iend is then set to the

istart = xend 'greater of xstart and xend

iend = xstart

EndIf

For i = istart To iend

PutPixel(i,y,Mode, Where)

Next 'i

End Sub

 

'-----------------------------------------

Public Sub Box(x1,y1,x2,y2 As Word,

Mode As Boolean,

Where As Word)

'-----------------------------------------

HLine(x1,y1,x2,Mode,Where)

HLine(x1,y2,x2,Mode,Where)

VLine(x1,y1,y2,Mode,Where)

VLine(x2,y1,y2,Mode,Where)

End Sub

 

'Checkerboard writes a block checkerboard to graphics memory page 2

'-------------------------------------------------------

Public Sub Checkerboard(Where As Word, pDispMode As Bit)

'-------------------------------------------------------

Dim

i,j,k As Word,

Fore,Back As Byte

If pDispMode = %1 Then

Fore = $FF

Back = $00

Else

Fore = $00

Back = $FF

EndIf

CursMem(Where)

WriteCtrl(GLCD_CMD_DISPLAY_WRITE)

For i = 0 To GLCD_Height-1

For j = 0 To (GLCD_Width / 8) -1

If (i.bit3 = %0) And (j Mod 2 = 0) Then WriteData(Fore)

ElseIf (i.bit3 = %1) And(j Mod 2 = 1) Then WriteData(Fore)

Else WriteData(Back)

EndIf

Next 'j

Next 'i

End Sub

'Draws a box or erases a box around text string of length Len with the

'text written at positions x & y. Mode is true/false for write/erase

'where defines the display page. Since box has margins from text, won't work

'at extreme edges of the display

'------------------------------------------------------------------

Public Sub TextBox(x,y,Len As Word, Mode As Boolean, Where As Word)

'------------------------------------------------------------------

Dim

x1,x2,y1,y2 As Word ' coordinates of box to be drawn

x1 = 8*x - 2 ' Apply border of 2 pixels around

x2 = x1 + 8*len + 2 ' the text on all sides

y1 = 8*y - 2 ' must leave blanks to avoid over printing

y2 = y1 + 10 ' also can't be at screen edge on any side

Box(x1,y1,x2,y2,Mode,Where)

End Sub

'----------------------------------------

Public Sub SetDisplayPage(pValue As Word)

'----------------------------------------

WriteCtrl(GLCD_CMD_SCROLL) // sets scroll address and lines per scroll block

WriteData($00) // SAD 1 Low - start of text memory

WriteData($00) // SAD 1 High

WriteData(GLCD_Height-1) // SL 1 $EF=.239

WriteData(pValue.Byte0) // SAD 2 Low - start of graphic memory

WriteData(pValue.Byte1) // SAD 2 High - start at $0960 = 2400

WriteData(GLCD_Height-1) // SL 2 $EF=.239

WriteData($00) // SAD 3 Low

WriteData($00) // SAD 3 High

WriteData($00) // SAD 4 Low

WriteData($00) // SAD 4 High

End Sub

 

'exchanges values of X & Y

'-------------------------------------

Private Sub Swap(ByRef x,y As Integer)

'-------------------------------------

If x <> y Then

x = x Xor y

y = x Xor y

x = x Xor y

EndIf

End Sub

 

 

'-----------------------------------------------------------------------

Public Sub Line(x0,y0,x1,y1 As Integer,pMode As Boolean, pWhere As Word)

'-----------------------------------------------------------------------

'Based on Bresenham's algoritm

Dim

Steep As Boolean,

DeltaX,DeltaY As Integer,

Error,DeltaErr As Integer,

x,y,ystep As Integer

{

'fudge to get 1 pixel shift

If x0 > 1 Then x0 = x0-1 EndIf

If x1 > 1 Then x1 = x1-1 EndIf

}

Steep = abs(y1-y0) > abs(x1-x0)

If Steep Then

Swap(x0,y0)

Swap(x1,y1)

EndIf

If x0 > x1 Then

Swap(x0,x1)

Swap(y0,y1)

EndIf

DeltaX = x1-x0

DeltaY = abs(y1-y0)

Error = 0

DeltaErr = DeltaY

y = y0

If y0 < y1 Then ystep = 1 Else ystep = -1 EndIf

For x = x0 To x1

If Steep Then

PutPixel(y,x,pMode,pWhere)

Else

PutPixel(x,y,pMode,pWhere)

EndIf

Error = Error + DeltaErr

If 2*Error >= DeltaErr Then

y = y + yStep

Error = Error - DeltaX

EndIf

Next

End Sub

'-------------------

Public Sub StartUp()

'-------------------

Initialize // set up ports and reset the LCD

DelayMS(500) // Take it slow at the start.

InitDisplay // Initialize registers in LCD control board

ClearGraphicMem(PageAStart)

ClearGraphicMem(PageBStart)

ClearTextMem // clear text memory to make room for new messages

End Sub

End