KS0108 Driver/Library Modification - Help!

Coding and general discussion relating to user created compiler modules

Moderators: David Barker, Jerry Messina

Post Reply
xnederlandx
Posts: 33
Joined: Wed Jul 01, 2009 5:55 am

KS0108 Driver/Library Modification - Help!

Post by xnederlandx » Thu Dec 02, 2010 8:23 am

Hi All,

I'm trying to make my own version of the KS0108 driver/library included with swordfish. I've read that storing a copy of what is on the display in the PIC's memory helps to increase the speed at which you can read the data (and therefore draw text, rectangles, etc) to the display.

I took the original driver, and modified some parts of it so that all other functions in the driver called the "WriteByte" and "ReadByte" functions. I then tested this driver, and everything works OK.

I added a 1024 byte array, which will keep a copy of the display's data. (128 x 64 pixels / 8 pixels per byte = 1024 bytes).
I then modified the WriteByte function so that it also writes to this array (index is calculated by "(Pos.y * 128) + Pos.x" ). The readbyte function was modified so that instead of reading data from the display, it would read from the array. The Clear Screen function was also changed so that the entire array is zero'd.

The problem is this:
When I write a string to the display from my main program using "WriteStr", only the first character of that string gets printed on the screen.
I've narrowed down the problem to the modification which I made to the writebyte function. It seems that the line "DisplayData(index) = pvalue" in the WriteByte function is causing the problem.

(whole function below:)

Code: Select all

Public Sub WriteByte(pValue As Byte)
   Dim index As Word
   SetPosition
   SetData(pValue)   
   index = (Pos.y * 128) + Pos.x               
   If (index < 1023) Then
        DisplayData(index) = pvalue
   EndIf
End Sub  
I'm not sure what I'm doing wrong - I'm even checking that the index is not outside the bounds of the array, and have test that this is always the case.

The entire driver's code which is having problems is below:

Code: Select all

{
****************************************************************
*  Name    : KS0108.BAS                                        *
*  Author  : David John Barker                                 *
*  Notice  : Copyright (c) 2006 Mecanique                      *
*          : All Rights Reserved                               *
*  Date    : 02/05/2006                                        *
*  Version : 1.0                                               *
*  Notes   :                                                   *
*          :                                                   *
****************************************************************
}
Module KS0108

// import the graphics module...
#define GLCD_PIXEL_01
#define GLCD_COLOR_01
#define GLCD_XY_08
Include "Graphics.bas"   
Include "system.bas"   

// default module options - user options can override these values...
#option GLCD_DATA = PORTD        // data port
#option GLCD_RS = PORTC.1        // RS pin
#option GLCD_EN = PORTE.0        // EN pin
#option GLCD_RW = PORTC.0        // RW pin
#option GLCD_CS1 = PORTE.1       // chip select
#option GLCD_CS2 = PORTE.2       // chip select
#option GLCD_ASPECT_RATIO = 75   // aspect ratio, smaller number will squeeze y for GLCD circles and box
#option GLCD_INIT_DELAY = 100    // initialisation delay (ms)
#option GLCD_INVERT_CS = false   // invert CS lines... 

// 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 RS pin...
#if IsOption(GLCD_RS) And Not IsValidPortPin(GLCD_RS) 
   #error GLCD_RS, "Invalid option. RS must be a valid port pin."
#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 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 CS1 pin...
#if IsOption(GLCD_CS1) And Not IsValidPortPin(GLCD_CS1) 
   #error GLCD_CS1, "Invalid option. CS1 must be a valid port pin."
#endif

// validate CS2 pin...
#if IsOption(GLCD_CS2) And Not IsValidPortPin(GLCD_CS2) 
   #error GLCD_CS2, "Invalid option. CS2 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 

// validate invert CS...
#if IsOption(GLCD_INVERT_CS)
   #if Not (GLCD_INVERT_CS in (true, false))
      #error GLCD_INVERT_CS, "Invalid option. GLCD invert CS must be true or false."
   #endif
#endif 

// validate RST pin...
#if IsOption(GLCD_RST) And Not IsValidPortPin(GLCD_RST) 
   #error GLCD_RST, "Invalid option. RST must be a valid port pin."
#endif

// now create Data TRIS...
#option _GLCD_DATA_TRIS = GetTRIS(GLCD_DATA)

// GLCD width and height...
Public Const
   GLCDWidth = 128,
   GLCDHeight = 64

// x, y position...
Public Dim
   Pos As TPosition

// KS0108 commands...   
Const
   cmdOn = $3F,
   cmdOff = $3E,
   cmdPage = $B8,
   cmdColumn = $40,
   cmdRam = $C0,
   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
   RS As GLCD_RS.GLCD_RS@,      // RS pin (instruction or data)
   EN As GLCD_EN.GLCD_EN@,      // EN pin
   RW As GLCD_RW.GLCD_RW@,      // RW pin (read or write)
   CS1 As GLCD_CS1.GLCD_CS1@,   // chip1 select
   CS2 As GLCD_CS2.GLCD_CS2@    // chip2 select
#if IsOption(GLCD_RST)
Dim
   RST As GLCD_RST.GLCD_RST@    // RST pin
#endif

Dim DisplayData(1024) As Byte

{
****************************************************************************
* Name    : CheckPage (PRIVATE)                                            *
* Purpose : Toggles between left and right half of GLCD                    *
****************************************************************************
}     
Sub CheckPage()
   #if GLCD_INVERT_CS
   If Pos.x < 64 Then
      CS1 = 1
      CS2 = 0	
   Else
      CS1 = 0
      CS2 = 1
   EndIf
   #else
   If Pos.x < 64 Then
      CS1 = 0
      CS2 = 1	
   Else
      CS1 = 1
      CS2 = 0
   EndIf
   #endif
End Sub
{
****************************************************************************
* Name    : StrobeEN (PRIVATE)                                             *
* Purpose : Strobe the GLCD EN pin                                         *
****************************************************************************
}    
Inline Sub StrobeEN()
   EN = 1
   DelayUS(1)
   EN = 0 
End Sub
{
****************************************************************************
* Name    : GLCDData (PRIVATE)                                             *
* Purpose : Switch to GLCD data mode                                       *
****************************************************************************
}    
Inline Sub GLCDData()
   RS = 1
End Sub
{
****************************************************************************
* Name    : GLCDInst (PRIVATE)                                             *
* Purpose : Switch to GLCD instruction mode                                *
****************************************************************************
}    
Inline Sub GLCDInst()
   RS = 0	 
End Sub
{
****************************************************************************
* Name    : GLCDRead (PRIVATE)                                             *
* Purpose : Set GLCD to read mode                                          *
****************************************************************************
}    
Inline Sub GLCDRead()
   RW = 1
End Sub
{
****************************************************************************
* Name    : GLCDWrite (PRIVATE)                                            *
* Purpose : Set GLCD to write mode                                         *
****************************************************************************
}    
Inline Sub GLCDWrite()
   RW = 0	 
End Sub
{
****************************************************************************
* Name    : WaitForIdle (PRIVATE)                                          *
* Purpose : Block further GLCD access until signalled ready.               *
****************************************************************************
}     
Sub WaitForIdle()
   Dim Timeout As Byte
   Timeout = $FF 
   GLCDInst	          // instruction data
   GLCDRead           // read mode
   TRISData = $FF     // set data bus to input
   Repeat
      ClrWDT
      StrobeEN        
      Dec(Timeout)
   Until (DATA.7 = 0) Or (Timeout = 0)
End Sub 
{
****************************************************************************
* Name    : SetData (PRIVATE)                                              *
* Purpose : Write a data byte to GLCD                                      *
****************************************************************************
}     
Sub SetData(pData As Byte) 
   WaitForIdle      // block until not busy
   GLCDData         // access display RAM data
   GLCDWrite        // write mode
   TRISData = $00   // set data bus to output
   DATA = pData     // write to the bus
   StrobeEN         // write to GLCD
End Sub
{
****************************************************************************
* Name    : GetData (PRIVATE)                                              *
* Purpose : Read byte from GLCD                                            *
****************************************************************************
}     
Function GetData() As Byte
   WaitForIdle      // block until not busy
   TRISData = $FF   // set data bus to input
   GLCDData         // access display RAM data
   GLCDRead         // read mode
   StrobeEN         // latch data
   Result = DATA    // get the data
End Function  
{
****************************************************************************
* Name    : Command (PRIVATE)                                              *
* Purpose : Write a command byte to GLCD                                   *
****************************************************************************
}     
Sub Command(pCommand As Byte) 
   WaitForIdle          // block until not busy
   GLCDInst             // instruction mode
   GLCDWrite            // write mode
   TRISData = $00       // set data bus to output
   DATA = pCommand      // write to the bus
   StrobeEN             // write to GLCD
End Sub
{
****************************************************************************
* Name    : SetPosition (PRIVATE)                                          *
* Purpose : Set GLCD x and y positions                                     *
****************************************************************************
}     
Sub SetPosition()
   CheckPage                   // set correct page
   Command(cmdColumn Or Pos.x) // set x position	
   Command(cmdPage Or Pos.y)   // set y position
End Sub

{
****************************************************************************
* Name    : WriteByte                                                      *
* Purpose : Write a byte at x, page                                        *
****************************************************************************
} 
Public Sub WriteByte(pValue As Byte)
   Dim index As Word
   SetPosition
   SetData(pValue)   
   index = (Pos.y * 128) + Pos.x               
   If (index < 1023) Then
        DisplayData(index) = pvalue
   EndIf
End Sub 
{
****************************************************************************
* Name    : ReadByte                                                       *
* Purpose : Read a byte at x, page                                         *
****************************************************************************
} 
Public Function ReadByte() As Byte
    SetPosition
    GetData
    Result = GetData
    //Result = DisplayData((Pos.y * 128) + Pos.x)
End Function
{
****************************************************************************
* Name    : SetPixel                                                       *
* Purpose : Set pixel at pixel location x,y                                *
****************************************************************************
} 
Public Sub SetPixel(pX, pY As Byte)
   Dim YBit As Byte
   Dim Pixel As Byte
   
   If (pX < GLCDWidth) And (pY < GLCDHeight) Then

      YBit = 1 << (pY Mod 8)
      Pos.y = pY / 8
      Pos.x = pX
   
      //SetPosition
      //GetData
      Pixel = ReadByte() //GetData  

           
      // pen is white...
      If Pen.Color = 0 Then
         If Pen.Mode = pmCopy Then
            yBit = Not yBit
            Pixel = Pixel And YBit
         EndIf
   
      // pen is black...
      Else

         // pen copy or merge...
         If Pen.Mode <> pmXOR Then
            Pixel = Pixel Or yBit
      
         // pen XOR
         Else
            If (Pixel And YBit) = 0 Then
               Pixel = Pixel Or yBit
            Else
               yBit = Not yBit
               Pixel = Pixel And YBit
            EndIf      
         EndIf
      EndIf

      WriteByte(pixel)
   EndIf
End Sub
{
****************************************************************************
* Name    : GetPixel                                                       *
* Purpose : Return pixel colour at pixel position x, y                     *
****************************************************************************
}
Public Function GetPixel(pX, pY As Byte) As TColor
   Dim Pixel As Byte
   Pos.y = pY / 8
   Pos.x = pX
   //SetPosition
   //GetData
   Pixel = ReadByte() >> (pY Mod 8) 
   Result = Pixel.0  
End Function
{
****************************************************************************
* Name    : Cls                                                            *
* Purpose : Clear the GLCD screen                                          *
****************************************************************************
} 
Public Sub Cls()
   Dim x, y As Byte
   Dim index As Word
   // enable both displays...
   #if GLCD_INVERT_CS 
   CS1 = 1 
   CS2 = 1
   #else
   CS1 = 0 
   CS2 = 0
   #endif	
   Command(cmdOff) 
   y = 0
   Repeat	
	  Command(cmdPage Or y)
	  x = 0
      Repeat	
		 Command(cmdColumn Or x)	
         SetData($00)
         Inc(x)
      Until x > 63
	  Inc(y)
   Until y > 7	
   Command(cmdRam)
   Command(cmdOn)  
   For index = 0 To Bound(DisplayData)
        DisplayData(index) = $00
   Next          
End Sub 
{
****************************************************************************
* Name    : Initialize                                                     *
* Purpose : Configure the GLCD before use                                  *
****************************************************************************
} 
Sub Initialize()
#if IsOption(GLCD_RST) 
   Output(RST)
   RST = 1
#endif
   Pos.x = 0
   Pos.y = 0  
   DelayMS(GLCDDelay) // start up delay, allow GLCD to settle
   Output(EN)         // enable is low
   Output(RS)         // data or instruction is low (command mode)
   Output(RW)         // read/write is low
   Output(CS1)        // screen (1)
   Output(CS2)        // screen (2)
   Command(cmdRam)
   Command(cmdOn) 
End Sub 

// configure the module
Initialize

Jerry Messina
Swordfish Developer
Posts: 1473
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Post by Jerry Messina » Thu Dec 02, 2010 11:36 am

I don't have one of these to try out, but it looks like the new code in WriteByte to access the data array is trashing FSR0, which is used by GLCD.WriteItem(pStr As String)

glcd.bas

Code: Select all

Sub WriteItem(pStr As String)
   FSR0 = @pStr
   While INDF0 <> 0
      WriteFontChar(POSTINC0)
      If Font.IsVariable And INDF0 <> 0 Then
         WriteFontSpace
      EndIf   
   Wend
End Sub
You would need to change WriteByte to preserve FSR0

Code: Select all

Public Sub WriteByte(pValue As Byte)
   Dim index As Word
   Dim save_fsr0 As Word
	
   SetPosition
   SetData(pValue)

   save_fsr0 = FSR0
   index = (Pos.y * 128) + Pos.x               
   If (index < 1023) Then
        DisplayData(index) = pvalue
   EndIf
   FSR0 = save_fsr0
End Sub
There are much better optimizations that could be done to do this, but that should get you started I think.

xnederlandx
Posts: 33
Joined: Wed Jul 01, 2009 5:55 am

Post by xnederlandx » Thu Dec 02, 2010 8:40 pm

Thank you very much!

It is working great now!

I've tested the new driver and the old driver (included in swordfish), and this seems to provide an overall speed increase (when writing test) of 42% (I.E. what used to take 20 seconds now takes 14).

Post Reply