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

E-mail: Jack.Smith@cliftonlaboratories.com


 

Home
Updates
Prior Products - no longer available
Documents
Book
Modulation
Loads
Lattice Crystal Filter
IMD Measurements
Using LP100 Coupler
Prototyping
Software Updates
K2 Measurements
Oscillator Noise Measurements
Bypassing
Capacitor Voltage Change
K2 Freq Stability
Cohn Crystal Filter
Receiver AGC Curves
K2 RX Sensitivity
Canned Osc Phase Noise
K2 Interface
K2 Filter
Surface Mount Assembly
TL750L Low Dropout Regulator
Swordfish DDS
Swordfish GLCD Module
Bessel Nulls
AM Modulation
Z10000 with FT-920
Z100 Tuning Aid
Dayton 2007
Softrock Lite 6.2
Header Adapter
Carbon Composition Resistors
Thermometers
Hakko FT-800 Thermal Wire Stripper
Heat Sinks
Diode Turn-On Time
Bill Hewlett and his Magic Lamp
Tektronix P6022 Current Probe
1N400x Diode Family Forward Voltage
Temperature Chamber
Diode Vf vs If
Ferrite Transformers
6 dB Hybrid Combiner
Type 43 Ferrite B-H Curve
K3 IF Bandpass Filter
Estimating Q of Ferrite Cores
Z10000 Buffer Amp
Z10010 Bandpass Filter
Using Softrock as a Panadapter for the K2
Signal Generator Phase Noise & Elecraft K2
Audio Transformer Data and Modeling
Measuring 60 Hz Frequency
Compact Fluorescent Lamp
Z10000-U Buffer Amp and FT-1000MP
WJ-8617B Receiver Impressions
Weather in Clifton VA
Radio Intelligence Example
Diodes for RF Probes
PIC Development Boards and Programmers
Elecraft K3 and Panadapters
Elecraft K3 AGC and S-Meter
Elecraft K3 Noise Blanker and Crystal/DSP Filtering
Jackson Harbor Press VLF Converter
Elecraft K3 Receive Audio
Headphone Impedance

 
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