S1D13700
This library supports a 320 x 240 GLCD with the S1D13700 controller. It is intended for use with the standard Swordfish GLCD library (GLCD.bas). This will allow use of proportional fonts, bitmap images and vector graphics.
The library is included below. Use with the GLCD library requires an addition to the GLCD library itself. However, this has already been done for you. You do not need to add the module code shown below to the user library folder. Just do one of the following:
- For licenced users, run the on-line update facility.
- For SE users, download the latest release.
This will update the GLCD library and add the new S1D13700 library.
The library allows use of either 6800 or 8080 addressing mode - use #option GLCD_MODE to determine which mode is used.
Below are two images of the display in use.
Thanks go to Jack Smith for his help with much of the initial code and for testing the library.
S1D13700 Graphics Driver
S1D13700 Module
{ ******************************************************************************** * Name : S1D13700.BAS * * Author : S Wright * * Notice : Copyright (c) 2007 J Smith, S Wright * * : All Rights Reserved * * Date : 27/01/2007 * * Version : 1.0 * * Notes : Library for a 320 x 240 graphic LCD with S1D13700 controller * * : working in 6800 or 8080 mode * ******************************************************************************** } Module S1D13700 // import the graphics module... #define GLCD_PIXEL_08 #define GLCD_COLOR_01 #define GLCD_XY_16 Include "Graphics.bas" Include "System.bas" Include "Utils.bas" // default module options - user options can override these values... #option GLCD_MODE = 8080 // GLCD interface mode - 6800 or 8080 #option GLCD_DATA = PORTD // data port #option GLCD_EN = PORTB.0 // EN pin - 6800 mode #option GLCD_RD = PORTB.0 // RD pin - 8080 mode #option GLCD_RW = PORTB.1 // RW pin - 6800 mode #option GLCD_WR = PORTB.1 // WR pin - 8080 mode #option GLCD_A0 = PORTB.2 // A0 pin #option GLCD_CS = PORTB.3 // chip select #option GLCD_RES = PORTB.5 // reset pin #option GLCD_ASPECT_RATIO = 100 // aspect ratio, smaller number will squeeze y for GLCD circles and box #option GLCD_INIT_DELAY = 100 // initialisation delay (ms) #if Not (GLCD_MODE in (6800, 8080)) #error GLCD_MODE, "Invalid option. GLCD mode not recognized." #endif // validate data port... #if IsOption(GLCD_DATA) #if Not IsValidPort(GLCD_DATA) #error GLCD_DATA, "Invalid option. DATA must be a valid port name." #endif #ifdef GLCD_DATA@ Then #error GLCD_DATA@, "Invalid option. DATA port cannot be a single bit value." #endif #endif // validate EN pin... #if IsOption(GLCD_EN) And Not IsValidPortPin(GLCD_EN) #error GLCD_EN, "Invalid option. EN must be a valid port pin." #endif // validate RD pin... #if IsOption(GLCD_RD) And Not IsValidPortPin(GLCD_RD) #error GLCD_RD, "Invalid option. RD must be a valid port pin." #endif // validate RW pin... #if IsOption(GLCD_RW) And Not IsValidPortPin(GLCD_RW) #error GLCD_RW, "Invalid option. RW must be a valid port pin." #endif // validate WR pin... #if IsOption(GLCD_WR) And Not IsValidPortPin(GLCD_WR) #error GLCD_WR, "Invalid option. WR must be a valid port pin." #endif // validate A0 pin... #if IsOption(GLCD_A0) And Not IsValidPortPin(GLCD_A0) #error GLCD_A0, "Invalid option. A0 must be a valid port pin." #endif // validate CS pin... #if IsOption(GLCD_CS) And Not IsValidPortPin(GLCD_CS) #error GLCD_CS, "Invalid option. CS must be a valid port pin." #endif // validate RES pin... #if IsOption(GLCD_RES) And Not IsValidPortPin(GLCD_RES) #error GLCD_RES, "Invalid option. RES must be a valid port pin." #endif // validate initialisation delay... #if IsOption(GLCD_INIT_DELAY) #if Not (GLCD_INIT_DELAY in (0 to 1000)) #error GLCD_INIT_DELAY, "Invalid option. GLCD initialize delay must be between 0 and 1000 (ms)." #endif #endif // now create Data TRIS... #option _GLCD_DATA_TRIS = GetTRIS(GLCD_DATA) // GLCD width and height... Public Const GLCDWidth = 320, GLCDHeight = 240 // x, y position structure... Public Structure TPositionS1D13700 x As TXY y As Byte End Structure // x, y position... Public Dim Pos As TPositionS1D13700 // S1D13700 commands... Const cmdSystem = $40, // general system settings cmdSleep = $53, // enter into standy mode cmdDisplayOff = $58, // turn the display off cmdDisplayOn = $59, // turn the display on cmdScroll = $44, // setup text and graphics address regions cmdCsrForm = $5D, // set cursor size cmdCsrDirRight = $4C, // cursor moves right after write to display memory cmdCsrDirLeft = $4D, // cursor moves left after write to display memory cmdCsrDirUp = $4E, // cursor moves up after write to display memory cmdCsrDirDown = $4F, // cursor moves down after write to display memory cmdCGRAMAddress = $5C, // configure character generator RAM address cmdHDotScroll = $5A, // set horizontal scroll rate cmdOverlay = $5B, // configure how layers overlay cmdSetCsrAddress = $46, // set the cursor address cmdGetCsrAddress = $47, // read the cursor address cmdDisplayWrite = $42, // write to display memory cmdDisplayRead = $43, // read from display memory GLCDDelay = GLCD_INIT_DELAY // port and pin settings, these are brought into // the program by using the above options... Dim Data As GLCD_DATA, // data in (PORT) TRISData As _GLCD_DATA_TRIS, // data TRIS EN As GLCD_EN.GLCD_EN@, // EN pin - enable (serves as a strobe) - 6800 mode RD As GLCD_RD.GLCD_RD@, // RD pin - read when L - 8080 mode RW As GLCD_RW.GLCD_RW@, // RW pin - read or write (0 = write, 1 = read) - 6800 mode WR As GLCD_WR.GLCD_WR@, // WR pin - write when L - 8080 mode A0 As GLCD_A0.GLCD_A0@, // A0 pin - sets data destination: 1 = command, 0 = data CS As GLCD_CS.GLCD_CS@, // chip select - 0 = selected, 1 = disabled RES As GLCD_RES.GLCD_RES@ // RES pin - normally RES = 1 but pull to 0 for initialization Dim Layers As Byte, // layers 1 - 3 on/off Layer1 As Layers.Booleans(2), Layer2 As Layers.Booleans(4), Layer3 As Layers.Booleans(6), CurrentLayer As Byte, // current drawing layer CurrentLayerMemPos As Word { ******************************************************************************** * Name : SetData (PRIVATE) * * Purpose : Write a data byte to GLCD * ******************************************************************************** } Sub SetData(pData As Byte) #if GLCD_MODE = 6800 A0 = 0 // access display RAM data RW = 0 // write mode TRISData = $00 // set data bus to output Data = pData // write to the bus CS = 0 EN = 1 // write to GLCD DelayUS(1) EN = 0 CS = 1 DelayUS(1) // prevent further write/read immediately #elseif GLCD_MODE = 8080 A0 = 0 // setup for data write RD = 1 // RD high for writing TRISData = $00 // set data bus to output Data = pData // write to the bus CS = 0 WR = 0 // write low starts write sequence DelayUS(1) // keep WR low to allow command to register WR = 1 // de-assert write CS = 1 DelayUS(1) // prevent further write/read immediately #endif End Sub { ******************************************************************************** * Name : GetData (PRIVATE) * * Purpose : Read byte from GLCD * ******************************************************************************** } Function GetData() As Byte #if GLCD_MODE = 6800 A0 = 1 // access display RAM data RW = 1 // read mode TRISData = $FF // set data bus to input CS = 0 EN = 1 // read from GLCD DelayUS(2) Result = Data // read from the bus EN = 0 CS = 1 DelayUS(1) // prevent further write/read immediately #elseif GLCD_MODE = 8080 A0 = 1 // setup for data read WR = 1 // WR high for reading TRISData = $FF // set data bus to input CS = 0 RD = 0 // read low starts read sequence DelayUS(2) // keep RD low to allow data to be read Result = Data // read from the bus RD = 1 // de-assert read CS = 1 DelayUS(1) // prevent further write/read immediately #endif End Function { ******************************************************************************** * Name : Command (PRIVATE) * * Purpose : Write a command byte to GLCD * ******************************************************************************** } Sub Command(pCommand As Byte) #if GLCD_MODE = 6800 A0 = 1 // instruction mode RW = 0 // write mode TRISData = $00 // set data bus to output Data = pCommand // write to the bus CS = 0 EN = 1 // write to GLCD DelayUS(1) EN = 0 CS = 1 DelayUS(1) // prevent further write/read immediately #elseif GLCD_MODE = 8080 A0 = 1 // setup for command RD = 1 // RD high for writing TRISData = $00 // set data bus to output Data = pCommand // write to the bus CS = 0 WR = 0 // write low starts write sequence DelayUS(1) // keep WR low to allow command to register WR = 1 // de-assert write CS = 1 DelayUS(1) // prevent further write/read immediately #endif End Sub { ******************************************************************************** * Name : CsrMemPosition * * Purpose : Positions cursor in graphics memory * ******************************************************************************** } Sub CsrMemPosition(pMemStart As Word) Command(cmdSetCsrAddress) // command - next two bytes are low & high bytes of memory start SetData(pMemStart.Byte0) // low byte SetData(pMemStart.Byte1) // high byte End Sub { ******************************************************************************** * Name : SetPosition (PRIVATE) * * Purpose : Set GLCD x and y positions * ******************************************************************************** } Sub SetPosition() Dim MemPos As Word MemPos = CurrentLayerMemPos + Pos.x + (40 * Pos.y) // find position in graphics // memory (40 bytes across 320 pixel screen) CsrMemPosition(MemPos) End Sub { ******************************************************************************** * Name : WriteByte * * Purpose : Write a byte * ******************************************************************************** } Public Sub WriteByte(pValue As Byte) SetPosition Command(cmdDisplayWrite) SetData(pValue) End Sub { ******************************************************************************** * Name : ReadByte * * Purpose : Read a byte * ******************************************************************************** } Public Function ReadByte() As Byte SetPosition Command(cmdDisplayRead) ReadByte = GetData End Function { ******************************************************************************** * Name : SetPixel * * Purpose : Set pixel at pixel location x,y * ******************************************************************************** } Public Sub SetPixel(pX, pY As TXY) Dim XBit As Byte Dim Pixel As Byte Dim LastPosX As TXY If (pX < GLCDWidth) And (pY < GLCDHeight) Then LastPosX = Pos.x XBit = %10000000 >> (pX Mod 8) Pos.y = pY Pos.x = pX / 8 SetPosition Command(cmdDisplayRead) Pixel = GetData // pen is white... If Pen.Color = 0 Then If Pen.Mode = pmCopy Then XBit = Not XBit Pixel = Pixel And XBit EndIf // pen is black... Else // pen copy or merge... If Pen.Mode <> pmXOR Then Pixel = Pixel Or XBit // pen XOR Else If (Pixel And XBit) = 0 Then Pixel = Pixel Or XBit Else XBit = Not XBit Pixel = Pixel And XBit EndIf EndIf EndIf SetPosition Command(cmdDisplayWrite) SetData(Pixel) Pos.x = LastPosX EndIf End Sub { ******************************************************************************** * Name : GetPixel * * Purpose : Return pixel colour at pixel position x, y * ******************************************************************************** } Public Function GetPixel(pX, pY As TXY) As TColor Dim Pixel As Byte Pos.y = pY Pos.x = pX / 8 SetPosition Command(cmdDisplayRead) Pixel = GetData << (pX Mod 8) Result = Pixel.7 End Function { ******************************************************************************** * Name : Cls * * Purpose : Clear one of the three graphic screens * ******************************************************************************** } Public Sub Cls(pLayer As Byte) Dim MemStart, MemPos As Word MemStart = (pLayer - 1) * 9600 CsrMemPosition(MemStart) // move to start of graphic memory for layer Command(cmdDisplayWrite) // set to write to display memory MemPos = 0 Repeat SetData($00) Inc(MemPos) Until MemPos = 9600 CsrMemPosition(MemStart) // move to start of graphic memory for layer Command(cmdDisplayOn) // command for screen on to remove cursor SetData(Layers) // sets layers 1 - 3, cursor off End Sub { ******************************************************************************** * Name : ApplyLine (PRIVATE) * * Purpose : Applies mask to line * ******************************************************************************** } Private Function ApplyLine(pLine, pMask As Byte) As Byte If Brush.Color = 0 Then // brush is white... ApplyLine = pLine And (Not pMask) Else // brush is black... ApplyLine = pLine Or pMask EndIf End Function { ******************************************************************************** * Name : Fill * * Purpose : Fast fill screen area with brush color. * * : Assumes pX1 < pX2 and pY1 < pY2 * ******************************************************************************** } Public Sub Fill(pX1, pY1, pX2, pY2 As TXY) Dim LastPosX As Word Dim MaskL, MaskR As Byte Dim Line As Byte LastPosX = Pos.x MaskL = $FF >> (pX1 Mod 8) MaskR = $FF << (7 - pX2 Mod 8) Pos.y = pY1 Repeat Pos.x = pX1 / 8 Line = ReadByte() If pX2 / 8 = pX1 / 8 Then // start & end of rectangle in same byte WriteByte(ApplyLine(Line, MaskL And MaskR)) Else WriteByte(ApplyLine(Line, MaskL)) Inc(Pos.x) SetPosition() Command(cmdDisplayWrite) // set to write to display memory While Pos.x < pX2 / 8 If Brush.Color = 0 Then // brush is white... SetData($00) Else // brush is black... SetData($FF) EndIf Inc(Pos.x) Wend Line = ReadByte() // right side of rectangle WriteByte(ApplyLine(Line,MaskR)) EndIf Inc(Pos.y) Until Pos.y > pY2 End Sub { ******************************************************************************** * Name : WriteImageByte (PRIVATE) * * Purpose : Write an image byte to GLCD at pixel position x, y * ******************************************************************************** } #define GLCD_SETIMAGE Sub WriteImageByte(pX As Word, pY As Byte, pValue As Byte) Dim Line, ShiftValue, XBit, XBitReverse As Byte Dim LastPosX As Word LastPosX = Pos.x // save x position XBit = pX Mod 8 // offset XBitReverse = 8 - XBit // reverse offset Pos.x = pX / 8 // align to page Pos.y = pY // save y // get first byte... Line = ReadByte // mask, if needed... If Pen.Mode = pmCopy Then Line = Line >> XBitReverse Line = Line << XBitReverse EndIf // merge then write data... ShiftValue = pValue >> XBit If Pen.Mode = pmXOR Then Line = Line Xor ShiftValue Else Line = Line Or ShiftValue EndIf WriteByte(Line) // get next byte... If XBit <> 0 Then Inc(Pos.x) Line = ReadByte // mask, if needed... If Pen.Mode = pmCopy Then Line = Line << XBit Line = Line >> XBit EndIf // merge then write data... ShiftValue = pValue << XBitReverse If Pen.Mode = pmXOR Then Line = Line Xor ShiftValue Else Line = Line Or ShiftValue EndIf WriteByte(Line) EndIf // restore x position... Pos.x = LastPosX End Sub { ******************************************************************************** * Name : ReadImageByte (PRIVATE) * * Purpose : Read an image byte * ******************************************************************************** } Function ReadImageByte() As Byte ASM- TBLRD *+ movff TABLAT, result End ASM End Function { ******************************************************************************** * Name : SetImage * * Purpose : BitBlit image to GLCD at pixel location x, y. * * : NOTE - This subroutine only supports $01 (monochrome) bitmaps. * * : It requires images drawn with bytes in the x-direction. * ******************************************************************************** } Public Sub SetImage(pX, pY As TXY, pImageAdr As Word, pMode As Byte = cmCopy) Dim Image As TImage Dim x,Width As Word Dim y,Height As Byte Dim Line As Byte Dim LastPen As TPen // get bitmap ID, width and height... TABLEPTR = pImageAdr Image.Header = ReadImageByte Image.Width = ReadImageByte Image.Height = ReadImageByte Inc(TABLEPTR) LastPen = Pen Pen.Mode = pMode // byte aligned bit blit... x = pX Width = Image.Width / 8 While Width > 0 y = pY Height = Image.Height While Height > 0 WriteImageByte(x,y,ReadImageByte) Inc(y) Dec(Height) Wend Inc(x, 8) Dec(Width) Wend // non byte aligned bit blit... pX = x Image.Width = Image.Width Mod 8 If Image.Width > 0 Then y = pY Height = Image.Height While Height > 0 Line = ReadImageByte Width = Image.Width x = pX While Width > 0 Pen.Color = Line.7 SetPixel(x,y) Line = Line << 1 Dec(Width) Inc(x) Wend Dec(Height) Inc(y) Wend EndIf Pen = LastPen End Sub { ******************************************************************************** * Name : SetImage * * Purpose : BitBlit image To GLCD at pixel location x, y. * * : NOTE - This subroutine only supports $01 (monochrome) bitmaps. * * : It requires images drawn with bytes in the x-direction. * ******************************************************************************** } Public Sub SetImage(pX, pY As TXY, ByRefConst pImage() As Byte, pMode As Byte = cmCopy) SetImage(pX, pY, @pImage, pMode) End Sub { ******************************************************************************** * Name : ShowLayer (Public) * * Purpose : Turns on/off graphic layers * ******************************************************************************** } Public Sub ShowLayer(pLayer As Byte, pOn As Boolean) Layers.Bits(2 * pLayer) = Bit(pOn) Command(cmdDisplayOn) // command for screen on SetData(Layers) // sets layers 1 - 3, cursor off End Sub { ******************************************************************************** * Name : SwitchLayer (Public) * * Purpose : Switches current drawing layer * ******************************************************************************** } Public Sub SwitchLayer(pLayer As Byte) CurrentLayer = pLayer CurrentLayerMemPos = 9600 * (CurrentLayer - 1) End Sub { ******************************************************************************** * Name : Initialize * * Purpose : Configure the GLCD before use. * * : Set up ports for I/O and perform RESET on LCD * ******************************************************************************** } Sub Initialize() Dim i As Word SetAllDigital() Pos.x = 0 Pos.y = 0 #if GLCD_MODE = 6800 Output(EN) // enable Output(RW) // read/write #elseif GLCD_MODE = 8080 Output(RD) // read Output(WR) // write #endif Output(A0) // data or instruction Output(CS) // chip select Output(RES) // reset #if GLCD_MODE = 6800 DelayMS(GLCDDelay) // start up delay, allow GLCD to settle RES = 0 // RES = 0 to reset EN = 0 // start with EN = 0 A0 = 0 Data = 0 CS = 0 DelayMS(5) RES = 1 DelayMS(10) // time for reset to finish #elseif GLCD_MODE = 8080 RES = 1 RD = 1 WR = 1 A0 = 0 CS = 1 DelayMS(GLCDDelay) // start up delay, allow GLCD to settle RES = 0 // RST = 0 to reset DelayMS(5) // 1 ms minimum, 5ms for safety RES = 1 DelayMS(5) // 3 ms minimum, 5ms for safety CS = 1 #endif Command(cmdSystem) // execute 'system set' instruction DelayMS(1) SetData($30) // control byte sets internal char gen (see DS) SetData($87) // FX - horizontal char size - 1 (see DS) SetData($07) // FY - vertical char size - 1 SetData($27) // C/R - bytes per line horizintally - 1 SetData($42) // TC/R - provides overscan idle time (see DS) SetData($EF) // LF - height of frame in lines - 1 ($EF = 239) SetData($28) // AP[L] - low byte of AP (horizontal address of virtual screen) SetData($00) // AP[H] - high byte of AP (horizontal address of virtual screen) Command(cmdScroll) // sets scroll address and lines per scroll block SetData($00) // graphics layer 1 start[L] ($0000) SetData($00) // graphics layer 1 start[H] SetData($EF) // graphics layer 1 lines per block - 1 ($EF = 239) SetData($80) // graphics layer 2 start[L] ($2580 = 9600 = 320 x 240 / 8) SetData($25) // graphics layer 2 start[H] SetData($EF) // graphics layer 2 lines per block - 1 ($EF = 239) SetData($00) // graphics layer 3 start[L] ($4B00 = 19200 = 9600 + 320 x 240 / 8) SetData($4B) // graphics layer 3 start[H] SetData($00) // no graphics layer 4 SetData($00) Command(cmdHDotScroll) // allow screen to scroll by pixels SetData($00) // set to zero pixels Command(cmdOverlay) // controls how graphics layers are combined SetData($1C) // set to priority OR L1 > L2 > L3, all graphics layers Command(cmdDisplayOff) // command for screen off... SetData($54) // but sets screens 1 - 3 for turning on later Command(cmdCsrForm) // select cursor size and shape SetData($00) // cursor width - 1 SetData($80) // cursor height - 1 (plus block style) Command(cmdCsrDirRight) // set cursor to increment to right CsrMemPosition(0) // cursor at start of graphics layer 1 Command(cmdDisplayWrite) // set to write to display memory For i = 1 To 28800 // clear layers 1 - 3 of display memory SetData($00) Next CsrMemPosition(0) // cursor at start of graphics layer 1 Command(cmdDisplayOn) // command for screen on... SetData($54) // for screens 1 - 3 Layers = %01010100 // default to all three graphics layers on (1 - 3) SwitchLayer(1) // start with layer 1 as drawing layer End Sub // configure the module Initialize