Anyone working on an SSD1339 based OLED (132x132) module?
Moderators: David Barker, Jerry Messina
Anyone working on an SSD1339 based OLED (132x132) module?
Hello,
I've switched over to SF from Proton and have been working on a module for an organic LED display that uses the Solomon SSD1339 chip for about a week now. I'm implementing it using the 8-bit 6800-type interface configuration. Is anyone more experienced with SF working on this type of OLED or interested in collaborating on it?
I've switched over to SF from Proton and have been working on a module for an organic LED display that uses the Solomon SSD1339 chip for about a week now. I'm implementing it using the 8-bit 6800-type interface configuration. Is anyone more experienced with SF working on this type of OLED or interested in collaborating on it?
Sure, I have lots of documentation. I am writing a hardware module and also have it going in Proton Plus. However, the Proton code is a kluge, it has a lot of extra small functions since it can't do overloaded subroutines, modules, etc. Which is why I switched to SF.
Note that the SSD1339 has a few unique features. It has built-in functions for drawing lines, circles and rectangles. I use the line drawing feature to put pixels on the screen, just start/stop at the same location. The colour definition is also two bytes, vs. the one byte used by the GLCDs I've seen in the libraries, so I use TColor (which is a byte in graphics.bas) and a second byte for colour, $55 just to fill in the requirement for putting in 2 bytes for colour.
I am using port D for the parallel interface, and B and E for the signals, as noted in the top of the hardware module. I started with the library module for the S1D15G00 by David Barker and made modifications from there.
I have not successfully written directly to RAM in the SSD1339, I'm trying it in the graphic image routine "SetImage", nothing happens.
There's a few manufacturers using the Solomon SSD1339, (they mount the chip on thier own OLED display) including Newtec and Densitron. Densitron has product support, Newtec does not. If you need to see the datasheet for the SSD1339, there's one at:
http://www.densitron.com/Displays/OLED_ ... erica.aspx
You have to register to download the datasheet but it's worth it because it will be the latest version. Or I could email it to you if you like via private message.
So, here is the calling program, the hardware code (SSD1339.bas) module and the top few lines of GLCD.bas module.
I can draw graphics such as squares and circles but the font text comes out as a solid block. Graphic images don't put anything on the screen.
Here is the testing function that calls out the code:
Device = 18F66J16
Clock = 8
Include "GLCD.bas"
Include "Arial.bas"
Config Fosc = intosc
GLCD.SetFont(ArialBold)
GLCD.WriteAt(40,80,"Arial Font")
DelayMS(500)
Rectangle(0,0,120,120)
GLCD.SSD1339.Rectangle(0,0,100,90,119,190,130,9)
Circle(40,40,20)
GLCD.SetImage(49,51,BtnOK)
GLCD.SetImage(89,51,BtnCancel)
GLCD.SetImage(4,2,BatteryImage)
SSD1339.bas:
GLCD.bas top lines:
Note that the SSD1339 has a few unique features. It has built-in functions for drawing lines, circles and rectangles. I use the line drawing feature to put pixels on the screen, just start/stop at the same location. The colour definition is also two bytes, vs. the one byte used by the GLCDs I've seen in the libraries, so I use TColor (which is a byte in graphics.bas) and a second byte for colour, $55 just to fill in the requirement for putting in 2 bytes for colour.
I am using port D for the parallel interface, and B and E for the signals, as noted in the top of the hardware module. I started with the library module for the S1D15G00 by David Barker and made modifications from there.
I have not successfully written directly to RAM in the SSD1339, I'm trying it in the graphic image routine "SetImage", nothing happens.
There's a few manufacturers using the Solomon SSD1339, (they mount the chip on thier own OLED display) including Newtec and Densitron. Densitron has product support, Newtec does not. If you need to see the datasheet for the SSD1339, there's one at:
http://www.densitron.com/Displays/OLED_ ... erica.aspx
You have to register to download the datasheet but it's worth it because it will be the latest version. Or I could email it to you if you like via private message.
So, here is the calling program, the hardware code (SSD1339.bas) module and the top few lines of GLCD.bas module.
I can draw graphics such as squares and circles but the font text comes out as a solid block. Graphic images don't put anything on the screen.
Here is the testing function that calls out the code:
Device = 18F66J16
Clock = 8
Include "GLCD.bas"
Include "Arial.bas"
Config Fosc = intosc
GLCD.SetFont(ArialBold)
GLCD.WriteAt(40,80,"Arial Font")
DelayMS(500)
Rectangle(0,0,120,120)
GLCD.SSD1339.Rectangle(0,0,100,90,119,190,130,9)
Circle(40,40,20)
GLCD.SetImage(49,51,BtnOK)
GLCD.SetImage(89,51,BtnCancel)
GLCD.SetImage(4,2,BatteryImage)
SSD1339.bas:
Code: Select all
Module SSD1339
#define GLCD_PIXEL_08
#define GLCD_COLOR_08
#define GLCD_XY_08
Include "Graphics.bas"
Include "system.bas"
// default module options - user options can override these values...
// this code uses the 6800 format 8-bit parallel interface
// 6800 8-bit configuration used: BS0 low, BS1 low, BS2 high, BS3 low
// This display is 132x132. The RGB interpretation for 8 bit colour is the same
// as for the S1D15G00 - RRRGGGBB.
#option GLCD_RESET = PORTE.5 // reset pin, active low-like S1D15G00
#option GLCD_DATA = PORTD // data port
#option GLCD_DC = PORTE.6 // Data or Command pin, data when high
#option GLCD_CS = PORTE.7 // Chip Select pin, MCU comms enabled when low-like S1D15G00
#option GLCD_E = PORTB.2 // Enable pin, R/W data latched when pulled high-like S1D15G00
#option GLCD_RW = PORTB.3 // Read-Write pin, write mode when low-like S1D15G00
#option GLCD_ASPECT_RATIO = 100 // aspect ratio
#option GLCD_INIT_DELAY = 100 // initialisation delay (ms)
//#option GLCD_SPI = SW // use software SPI
// validate Reset pin...
#if IsOption(GLCD_RESET) And Not IsValidPortPin(GLCD_RESET)
#error GLCD_RESET, "Invalid option. RESET must be a valid port pin."
#endif
// validate DATA port...
#if IsOption(GLCD_DATA) And Not IsValidPort(GLCD_DATA)
#error GLCD_DATA, "Invalid option. DATA must be a valid port."
#endif
// validate DC pin...
#if IsOption(GLCD_DC) And Not IsValidPortPin(GLCD_DC)
#error GLCD_DC, "Invalid option. DC 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 E pin...
#if IsOption(GLCD_E) And Not IsValidPortPin(GLCD_E)
#error GLCD_E, "Invalid option. E 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 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
// SSD1339 commands...
Const
cmdDisCtl = $CA, //Display Control
cmdNOP = $E3, //NOP - $25 in S1D15G00
cmdDisOn = $AF, //Display On, out of sleep
cmdDisOff = $AE, //Display Off, in sleep mode
cmdBlank = $A4, //Sets diplay mode to All Off-all pixels have GS0 (grayscale level 0), minimum brightness
cmdAllOn = $A5, //Sets diplay mode to All On-all pixels have GS63 (grayscale level 63), maximum brightness
cmdDisNor = $A6, //Sets display mode to Display Normal
cmdDisInv = $A7, //Sets display mode to Display Invert-gray levels swapped-GS0 is GS63, GS7 is GS56, etc
cmdPaSet = $75, //Page Address Set
cmdCaSet = $15, //Column Address Set
cmdRamWr = $5C, //Writing to Memory
cmdCtrst = $C7, //Master contrast control
cmdRemap = $A0, //$A0 then $34, normal; $A0 then $26 - flips display 180 degrees
cmdStLin = $A1, //sets starting line
cmdVScrl = $A2, //set vertical scroll by row from 0-131
cmdMastC = $AD, //master configuration, int/ext VCC suppply and int/ext pre-charge V supply
cmdPwrSa = $B0, //power save mode, sets int/ext VSL and power save on/off
cmdResPr = $B1, //et reset (phase 1) & pre-charge (2) period adjustments-1 is discharge time,2 is charge time
cmdOscDv = $B3, //front clock divider and int oscillator freq set
cmdPreCV = $BB, //set the pre-charge colour voltage of each colour
cmdVCOMH = $BE, //set VCOMH - should be irrelevant since use ext supply but manuals say set it...
cmdCoCol = $C1, //Contrast currents for each colour A, B, C (RGB)
cmdMuxRa = $CA, //mux ratio - number of display lines turned on - start & end depends on A2 cmd setting
cmdDLine = $83, //draw line
cmdDRect = $84, //draw rectangle
cmdDcirc = $86, //draw circle
cmdCopy = $8A, //Copy area
cmdDimWi = $8C, //Dim Window
cmdClWin = $8E, //Clear Window
cmdFilED = $92, //Fill Enable/Disable
cmdHorSc = $96, //Horizontal Scroll
cmdSpHor = $9E, //Stop horizontal scroll
cmdStHor = $9F, //Start horizontal scroll moving
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 port
TRISData As TRISD, // Data TRIS
E As GLCD_E.GLCD_E@, // clk pin
CS As GLCD_CS.GLCD_CS@, // CS pin
DC As GLCD_DC.GLCD_DC@, // DC pin
RW As GLCD_RW.GLCD_RW@, //RW pin
Reset As GLCD_RESET.GLCD_RESET@ // reset pin
// GLCD width and height...
Public Const
GLCDWidth = 130,
GLCDHeight = 130
// x, y position...
Public Dim
Pos As TPosition
'Contrast As FContrast
{
****************************************************************************
* Name : StrobeEN (Private) *
* Purpose : Strobe the GLCD EN pin *
****************************************************************************
}
Inline Sub StrobeEN()
CS = 0
E = 1
DelayUS(1)
CS = 1
End Sub
{
****************************************************************************
* Name : GLCDData (PRIVATE) *
* Purpose : Switch To GLCD Data mode *
* Modified For KS0713 *
****************************************************************************
}
Inline Sub GLCDData()
DC = 1
End Sub
{
****************************************************************************
* Name : GLCDInst (PRIVATE) *
* Purpose : Switch To GLCD instruction mode *
* Modified For KS0713 *
****************************************************************************
}
Inline Sub GLCDInst()
DC = 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 : SetData (PRIVATE) *
* Purpose : Write a Data Byte To GLCD *
****************************************************************************
}
Sub SetData(pData As Byte)
TRISData = $00 // Set Data bus To Output
GLCDData // access display RAM Data
GLCDWrite // write mode
Data = pData // write To the bus
StrobeEN // write To GLCD
End Sub
{
****************************************************************************
* Name : WriteData (PRIVATE) *
* Purpose : Write a series of data bytes to GLCD *
****************************************************************************
}
Compound Sub WriteData(SetData)
{
****************************************************************************
* Name : GetData (PRIVATE) *
* Purpose : Read Byte from GLCD *
****************************************************************************
}
Function GetData() As Byte
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 *
****************************************************************************
}
Public Sub Command(pCommand As Byte)
TRISData = $00 // Set Data bus To Output
GLCDInst // instruction mode
GLCDWrite // write mode
Data = pCommand // write To the bus
StrobeEN // write To GLCD
End Sub
{
****************************************************************************
* Name : CommandWithData (PRIVATE) *
* Purpose : Write a command plus extra Data Byte To GLCD *
****************************************************************************
}
Sub CommandWithData(pCommand,pData As Byte)
TRISData = $00 // Set Data bus To Output
GLCDInst // instruction mode
GLCDWrite // write mode
Data = pCommand // write To the bus
StrobeEN // write To GLCD
Data = pData
GLCDData // instruction mode
GLCDWrite // write mode
StrobeEN
End Sub
{
****************************************************************************
* Name : WriteCommnad (PRIVATE) *
* Purpose : Use to write a series of command bytes to GLCD when there is *
* more than one data byte to write after the command mnemonic *
****************************************************************************
}
Compound Sub WriteCommands(Command,SetData)
{
****************************************************************************
* Name : MoveTo (PRIVATE) *
* Purpose : Move to position x,y on the GLCD *
****************************************************************************
}
Sub MoveTo(pX, pY As Byte)
//X position start address,X position end address,Y position start address,
//Y position end address,write to RAM
WriteCommands(cmdCaSet,pX,GLCDWidth - 1,cmdCaSet,pY + 2,GLCDHeight + 1,cmdRamWr)
End Sub
{
****************************************************************************
* Name : SetPixel *
* Purpose : Set pixel at pixel location x,y *
****************************************************************************
}
Public Sub SetPixel(pX, pY As Byte)
'MoveTo(pX, pY)
'WriteData(Pen.Color,$55)
WriteCommands(cmdDLine,pX,pY,pX,pY,Pen.Color,$55)
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 TColor
Pos.y = pY
Pos.x = pX
WriteCommands(cmdCaSet,Pos.x,Pos.x)
WriteCommands(cmdPaSet,Pos.y,Pos.y)
GetData
'Pixel = GetData >> (pY Mod 8)
'Result = Pixel.0
End Function
{
****************************************************************************
* Name : SetContrast *
* Purpose : Set the GLCD contrast *
****************************************************************************
}
Public Sub SetContrast(pContrast As Byte)
WriteCommands(cmdCtrst,pContrast)
End Sub
{
****************************************************************************
* Name : Cls *
* Purpose : Clear the GLCD screen *
****************************************************************************
}
Public Sub Cls(pX,pY,pEndX,pEndY As Byte)
WriteCommands(cmdClWin,pX,pY,pEndX,pEndY)
End Sub
{
****************************************************************************
* Name : MakeColor *
* Purpose : The S1D15G00 8 bit color scheme maps 3 bit R, G values and *
* : a 2 bit B value onto a 12 bit RGB. This routine allows you *
* : to create a color by specifying RGB values in the range 0..255 *
****************************************************************************
}
Public Function MakeColor(pR, pG, pB As Byte) As TColor
'result = (pR / 32 << 5) Or (pG / 32 << 2) Or (pB / 64)
End Function
{
****************************************************************************
* Name : PowerOLED *
* Purpose : Configure the GLCD before Vcc is applied - run this whenever *
* the 3.3V bus is started so the display is ready for the high *
* voltage Vcc. *
****************************************************************************
}
Public Sub PowerOLED()
Command(cmdDisOff) //turn off display
Cls(0,0,132,132) //clear screen
DelayMS(GLCDDelay) //Must be at least 100 mS between this cmd and Vcc
End Sub
{
****************************************************************************
* Name : Initialize *
* Purpose : Configure the GLCD before use. *
****************************************************************************
}
Public Sub Initialize() //first section same as PowerOLED
Command(cmdDisOff) //turn off display
Cls(0,0,132,132) //clear screen
DelayMS(GLCDDelay)
// set display clock divide ratio and oscillator frequency
WriteCommands(cmdOscDv,$F0)
//set display offset, = 132 - dummy lines from common 0
WriteCommands(cmdVScrl,$00) //setting to $01 starts the line off the display
//set multiplex ratio
WriteCommands(cmdMuxRa, $84) //use 131 lines on the display
//set master configuration
WriteCommands(cmdMastC, $8F) //use external Vcc & external pre-charge V source ($8E in Densitron manual)
//set display start line
CommandWithData(cmdStLin, $00) //set start line at 0
//set segment re-map & data format
CommandWithData(cmdRemap, $60) //$34 sets to normal display, $26 flips display 180 degrees
//$6 = 65K colours (x1xx), and prevent skipping every second row (xx1x)
//set master contrast current control, user may have to adjust...
SetContrast(158)
//set contrast control for colours A,B,C (RGB)
WriteCommands(cmdCoCol,$80,$80,$80) //confirmed reset values, may change later
//set pre-charge voltage of colours A,B,C (RGB)
WriteCommands(cmdPreCV,$1C,$1C,$1C) //confirmed reset values, may change later
//set VCOMH
CommandWithData(cmdVCOMH, $1F) //use ext VCOMH so should be irrelevant but manuals say to set it...
//Set reset (phase 1) & pre-charge (2) period adjustments-1 is discharge time,2 is charge time -higher
// capacitance displays need more time and thus a higher value
CommandWithData(cmdResPr, $47) //used $47 out of FF as per defaults-old code used $11
//set power saving mode
CommandWithData(cmdPwrSa, $1A) //Power saving with external VSL, as per manual
//set display mode - turn display on
Command(cmdDisOn)
End Sub
{
****************************************************************************
* Name : SetRegion (PRIVATE) *
* Purpose : Sets the GLCD display boundary setting region *
****************************************************************************
}
Sub SetRegion(pX, pY, pWidth, pHeight As Byte)
WriteCommands(cmdCaSet,pX,pX + pWidth - 1)
WriteCommands(cmdPaSet,pY + 2,pY + pHeight + 1)
End Sub
{
****************************************************************************
* Name : Line *
* Purpose : Draw Line *
* : write start col/row, end col/row,line colour byte 1&2 *
****************************************************************************
}
Public Sub Line(pX1, pY1, pX2, pY2 As TXY,pColor,pColor2 As Byte)
WriteCommands(cmdDLine,pX1, pY1, pX2, pY2,pColor,pColor2)
End Sub
{
****************************************************************************
* Name : Rectangle *
* Purpose : Draw Rectangle *
* : write start col/row, end col/row,line colour byte 1 & 2,fill *
* colour bytes 1 & 2 *
****************************************************************************
}
Public Sub Rectangle(pX1, pY1, pX2, pY2 As TXY,pColor,pColor2,pFColor,pFColor2 As Byte)
WriteCommands(cmdDRect,pX1, pY1, pX2, pY2,pColor,pColor2,pFColor,pFColor2)
End Sub
{
****************************************************************************
* Name : Circle *
* Purpose : Draw circle *
* : write col/row address of center, radius,line colour byte 1&2, *
* fill colour bytes 1 & 2 *
****************************************************************************
}
Public Sub Circle(pX1, pY1, pRadius, pColor,pColor2,pFColor,pFColor2 As Byte)
WriteCommands(cmdDcirc,pX1, pY1, pRadius, pColor,pColor2,pFColor,pFColor2)
End Sub
{
****************************************************************************
* Name : Copy *
* Purpose : Copy one area of the screen to another *
* : Define col/row to start, col/row to end, col/row of new start *
****************************************************************************
}
Public Sub Rectangle(pX1, pY1, pX2, pY2 As TXY,CopyCol, RowCol As Byte)
//write start col/row, end col/row,line colour byte 1&2, fill colour byte 1&2
WriteCommands(cmdCopy,pX1, pY1, pX2, pY2,CopyCol, RowCol)
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 (OVERLOAD) *
* Purpose : Overrides the GLCD library native SetImage call with this *
* : routine which is better suited for rendering to the S1D15G00 *
* : pImageAdr is the address of the image to render *
****************************************************************************
}
#endif // GLCD_PIXEL_01
#endif // GLCD_SETIMAGE
#define GLCD_SETIMAGE // override GLCD SetImage
Public Sub SetImage(pX, pY As TXY, pImageAdr As Word)
Dim x, xRange As TXY
Dim TransColor As TColor
Dim ImageByte1, ImageByte2, ImageByte3 As Byte//for 12 bit colour
Dim Index, Range As Word
Dim RLENum As Byte
Dim LastPenColor As TColor
Dim Image As TImage
Dim Ignore As Boolean
// get bitmap ID, width and height...
TABLEPTR = pImageAdr
Image.Header = ReadImageByte
Image.Width = ReadImageByte
Image.Height = ReadImageByte
Inc(TABLEPTR)
// last pen color to restore pen, index starts
// at 4 to account for header size...
LastPenColor = Pen.Color
Index = 0
// 8 bit color is used only to save ROM space...
If Image.Is8Bit Then
Range = Image.Height * Image.Width
// is it a transparent image...
If Image.IsTransparent Then
Ignore = false
MoveTo(pX,pY)
x = pX
xRange = pX + Image.Width
// read the transparent pixel...
If Image.IsRLE Then
Inc(TABLEPTR)
EndIf
TransColor = ReadImageByte
TABLEPTR = pImageAdr + 4
// repeat for all the pixels in the image...
Repeat
RLENum = 1
If Image.IsRLE Then
RLENum = ReadImageByte
EndIf
Pen.Color = ReadImageByte
Repeat
// if it's a transparent pixel, skip...
If Pen.Color = TransColor Then
Ignore = true
Else
// we have hit a non transparent pixel, so reset x, y
If Ignore Then
WriteCommands(cmdCaSet,x,pX + Image.Width)
Command(cmdRamWr)
Ignore = false
EndIf
WriteData(Pen.Color,$55)
EndIf
// inc x, if greater than image width then reset
// x and move to next y
Inc(x)
If x >= xRange Then
x = pX
Inc(pY)
MoveTo(pX,pY)
EndIf
Inc(Index)
Dec(RLENum)
Until RLENum = 0
Until Index >= Range
// image is not transparent, fast bit blit...
Else
SetRegion(pX, pY, Image.Width, Image.Height)
Repeat
RLENum = 1
If Image.IsRLE Then
RLENum = ReadImageByte
EndIf
Pen.Color = ReadImageByte
Repeat
WriteData(Pen.Color,$55)
Inc(Index)
Dec(RLENum)
Until RLENum = 0
Until Index >= Range
EndIf
// 12 bit, fast bit blit - note that 12 bit images must fall on an even x...
ElseIf Image.Is12Bit Then
Nop
EndIf
Pen.Color = LastPenColor
End Sub
{
****************************************************************************
* Name : SetImage (OVERLOAD) *
* Purpose : Overrides the GLCD library native SetImage call with this *
* : routine which is better suited for rendering to the S1D15G00 *
* : pImage is a constant array holding the image data to render *
****************************************************************************
}
Public Sub SetImage(pX, pY As TXY, ByRefConst pImage() As Byte)
SetImage(pX, pY, @pImage)
End Sub
{
****************************************************************************
* Name : WriteChar *
* Purpose : Overrides the GLCD library native WriteChar call with this *
* : routine which is better suited for rendering to the S1D15G00 *
* : This routine will only handle xFonts (that is, font files with *
* : the scan line in the x direction) *
****************************************************************************
}
{
#define GLCD_WRITECHAR // override GLCD WriteChar
#define GLCD_XFONT // force the use of x scanned font
Public Sub WriteChar()
Dim FontByte As Byte
Dim x, y, xRange, yRange As Byte
Dim PenColor As TColor
Dim Range, Index As Word
Dim Ignore As Boolean
PenColor = Pen.Color
Index = 0
// is the brush style clear...
If Brush.Style = bsClear Then
Ignore = false
yRange = Pos.y + Font.Height
y = Pos.y
While y < yRange
MoveTo(Pos.x,y)
xRange = Pos.x + Font.Width
x = Pos.x
While x < xRange
FontByte = ReadFontByte
Index = 8
Repeat
// write a font pixel with pen color...
If FontByte.7 = 1 Then
If Ignore Then
'WriteCommands(cmdCaSet,x,Pos.x + Font.Width)
'Command(cmdRamWr)
Ignore = false
EndIf
'WriteData(Pen.Color.CB,Pen.Color.BA)
'WriteCommands(cmdDLine,x+index,y,x+index,y,Pen.Color.CB,Pen.Color.BA)
WriteCommands(cmdDLine,x+Index,y,x+Index,y,56,98)
// skip transparent pixel...
Else
Ignore = true
EndIf
FontByte = FontByte << 1
Dec(Index)
Inc(x)
Until Index = 0
Wend
Inc(y)
Wend
// brush style is not clear, fast bit blit...
Else
x = 0
SetRegion(Pos.x, Pos.y, Font.Width, Font.Height)
Range = Font.Height * Font.Width
Repeat
// grab a font byte...
If x >= Font.Width Then
FontByte = ReadFontByte
x = 0
ElseIf x Mod 8 = 0 Then
FontByte = ReadFontByte
EndIf
Inc(x)
// set either font color or background color...
If FontByte.7 = 1 Then
Pen.Color = PenColor
Else
Pen.Color = Brush.Color
EndIf
'WriteData(Pen.Color.CB,Pen.Color.BA)
WriteCommands(cmdDLine,x+Index+20,y,x+Index+20,y,$56,$98)
FontByte = FontByte << 1
Inc(Index)
Until Index >= Range
EndIf
Pen.Color = PenColor
Inc(Pos.x,Font.Width)
End Sub
}
// configure the module
Initialize
Code: Select all
#option GLCD_MODEL = SSD1339
#if Not (GLCD_MODEL in (SSD1339, KS0108, S1D10605, S1D15G00, SED1520, S1D13700))
#error GLCD_MODEL, "Invalid option. GLCD model not recognized."
#endif
// import SSD1339 driver...
#if GLCD_MODEL = SSD1339
Include "SSD1339.bas"
Public Dim
Pos As SSD1339.Pos,
Cls As SSD1339.Cls,
SetPixel As SSD1339.SetPixel,
WriteByte As SSD1339.SetData,
ReadByte As SSD1339.GetData,
SetImage As SSD1339.SetImage,
GetPixel As SSD1339.GetPixel
#endif
Code: Select all
Code: Select all
Code: Select all
Hello,
I've created a module for use with the Solomon SSD0323 (128 x 64 4-bit greyscale). Looking at the specs, the SSD1339 at least shares common command instructions and data writing structures. My code isn't perfect, and is mostly a modification of the S1D15G00 code, but if you like I could polish it up a bit and release it here for you to at least have a look at.
In fact your task would be easier as the SSD0323 has 4-bit pixel data on a 8 bit bus, whereas the SSD1339 has 3-byte transfers in 262k colour mode. I have to do all sorts of read back crap to make sure that when I change 1 pixel, the adjacent one isn't changed. None of that for you!
The graphics acceleration features look pretty handy too!
Any chance you could point me in the direction of the module you are using btw? I am evaluating other OLED options since the one I originally wrote the module for has now been discontinued.
Regards,
Nathan
I've created a module for use with the Solomon SSD0323 (128 x 64 4-bit greyscale). Looking at the specs, the SSD1339 at least shares common command instructions and data writing structures. My code isn't perfect, and is mostly a modification of the S1D15G00 code, but if you like I could polish it up a bit and release it here for you to at least have a look at.
In fact your task would be easier as the SSD0323 has 4-bit pixel data on a 8 bit bus, whereas the SSD1339 has 3-byte transfers in 262k colour mode. I have to do all sorts of read back crap to make sure that when I change 1 pixel, the adjacent one isn't changed. None of that for you!
The graphics acceleration features look pretty handy too!
Any chance you could point me in the direction of the module you are using btw? I am evaluating other OLED options since the one I originally wrote the module for has now been discontinued.
Regards,
Nathan
Hi Nathan,
Sure, Densitron offers a model with the SSD1339 in the UK. Here's a link to their contact info:
http://www.densitron.com/content.aspx?id=504
as for vendors, you can get it at Spark Fun:
http://www.sparkfun.com/commerce/produc ... cts_id=712
4D systems out of Australia also produces an SSD1339 unit
http://www.4dsystems.com.au
http://www.milinst.com in the UK sells 4D products but I don't see the OLED 128 model, only the models with built-in controllers for 59 pounds Sterling. The "bare" OLED should be no more than about 10 - 15 pounds Sterling.
4D also has a list of other vendors in other countries.
Also, I think your code would be a big help since the problem I am having is in gathering in the array bytes and putting them out the parallel interface in the proper order. Seeing how that is arranged and written would probably bridge the problem I'm stuck on now.
-Tom
Sure, Densitron offers a model with the SSD1339 in the UK. Here's a link to their contact info:
http://www.densitron.com/content.aspx?id=504
as for vendors, you can get it at Spark Fun:
http://www.sparkfun.com/commerce/produc ... cts_id=712
4D systems out of Australia also produces an SSD1339 unit
http://www.4dsystems.com.au
http://www.milinst.com in the UK sells 4D products but I don't see the OLED 128 model, only the models with built-in controllers for 59 pounds Sterling. The "bare" OLED should be no more than about 10 - 15 pounds Sterling.
4D also has a list of other vendors in other countries.
Also, I think your code would be a big help since the problem I am having is in gathering in the array bytes and putting them out the parallel interface in the proper order. Seeing how that is arranged and written would probably bridge the problem I'm stuck on now.
-Tom
Ok heres my SSD0323 code. Doesn't seem like it has the same amount of polish as yours! It was knocked up very quickly whilst I was still getting to grips with SF, and I consider it "good enough". Looks like much of it is either the same or very similar though. Hope it helps someone!
Added to GLCD:
Code: Select all
Module SSD0323
// import the graphics module...
#define GLCD_PIXEL_08
#define GLCD_COLOR_08
#define GLCD_XY_08
Include "Graphics.bas"
Include "system.bas"
// default module options - user options can override these values...
#option GLCD_DATA = PORTF // data port
#option GLCD_RS = PORTD.1 // RS pin
#option GLCD_DC = PORTD.2 // Data/Command pin
#option GLCD_RW = PORTD.3 // RW pin
#option GLCD_CS = PORTD.0 // chip select
#option GLCD_RD = PORTD.4 // RD Pin
#option GLCD_INIT_DELAY = 100 // initialisation delay (ms)
#option GLCD_ASPECT_RATIO = 100 // aspect ratio, smaller number will squeeze y for GLCD circles and box
#option GLCD_FLIP = true // Cable top exit
#option GLCD_POWER1 = PORTA.1
#option GLCD_POWER2 = PORTA.2
#option OLED_MODEL = CALGARY
#if Not (OLED_MODEL in (CALGARY, ATLANTA))
#error OLED_MODEL, "Invalid option. OLED model 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 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 DC pin...
#if IsOption(GLCD_DC) And Not IsValidPortPin(GLCD_DC)
#error GLCD_DC, "Invalid option. DC 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 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 RD pin...
#if IsOption(GLCD_RD) And Not IsValidPortPin(GLCD_RD)
#error GLCD_CS2, "Invalid option. RD 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...
#if OLED_MODEL = CALGARY
Public Const
GLCDWidth = 128,
GLCDHeight = 64
#endif
// GLCD width and height...
#if OLED_MODEL = ATLANTA
Public Const
GLCDWidth = 128,
GLCDHeight = 64
#endif
// x, y position...
Public Dim
Pos As TPosition
// SSD0323 commands...
Const
cmdSetCol = $15,
cmdEndCol = $7F,
cmdSetRow = $75,
cmdEndRow = $3F,
cmdSetReMap = $A0,
cmdOff = $AE,
cmdOn = $AF,
GLCDDelay = GLCD_INIT_DELAY
// port and pin settings, these are brought into
// the program by using the above options...
Public Dim
Data As GLCD_DATA, // data in (PORT)
TRISData As _GLCD_DATA_TRIS, // data TRIS
RS As GLCD_RS.GLCD_RS@, // RS pin (reset pin)
DC As GLCD_DC.GLCD_DC@, // DC pin (data or command)
RW As GLCD_RW.GLCD_RW@, // RW pin (read or write)
CS As GLCD_CS.GLCD_CS@, // chip select
RD As GLCD_RD.GLCD_RD@, // Read select
POWER1 As GLCD_POWER1.GLCD_POWER1@, // VDD power control
POWER2 As GLCD_POWER2.GLCD_POWER2@ // VCC power control
{
****************************************************************************
* Name : GLCDData (PRIVATE) *
* Purpose : Switch to GLCD data mode *
****************************************************************************
}
Inline Sub GLCDData()
DC = 1
End Sub
{
****************************************************************************
* Name : GLCDInst (PRIVATE) *
* Purpose : Switch to GLCD instruction mode *
****************************************************************************
}
Inline Sub GLCDInst()
DC = 0
End Sub
{
****************************************************************************
* Name : GLCDRead (PRIVATE) *
* Purpose : Strobe Read line *
****************************************************************************
}
Inline Sub Read()
RD = 0
RD = 1
End Sub
{
****************************************************************************
* Name : GLCDWrite (PRIVATE) *
* Purpose : Strobe Write line *
****************************************************************************
}
Inline Sub Write()
RW = 0
RW = 1
End Sub
{
****************************************************************************
* Name : SetData (PRIVATE) *
* Purpose : Write a data byte to GLCD *
****************************************************************************
}
Sub SetData(pData As Byte)
DC = 1 // access display RAM data
TRISData = $00 // set data bus to output
Data = pData // write to the bus
Write() // write mode
End Sub
{
****************************************************************************
* Name : GetData (PRIVATE) *
* Purpose : Read byte from GLCD *
****************************************************************************
}
Function GetData() As Byte
CS = 0
//Dummy Read First
TRISData = $FF // set data bus to input
GLCDData // access display RAM data
RD = 0
DelayUS(1)
RD = 1
//Actual Read
TRISData = $FF // set data bus to input
GLCDData // access display RAM data
RD = 0
DelayUS(1)
Result = Data // get the data
RD = 1
CS = 1
End Function
{
****************************************************************************
* Name : Command (PRIVATE) *
* Purpose : Write a command byte to GLCD *
****************************************************************************
}
Sub WriteCommand(pCommand As Byte)
RD = 1
DC = 0
CS = 0
TRISData = $00 // set data bus to output
Data = pCommand // write to the bus
RW = 0
RW = 1
CS = 1
DelayUS(1)
End Sub
Compound Sub Command(WriteCommand)
{
****************************************************************************
* Name : SetPosition (PRIVATE) *
* Purpose : Set GLCD x and y positions *
****************************************************************************
}
Sub SetPosition()
Command(cmdSetCol,Pos.x,cmdEndCol) // set x position
Command(cmdSetRow,Pos.y,cmdEndRow) // set y position
End Sub
{
****************************************************************************
* Name : SetPixel *
* Purpose : Set pixel at pixel location x,y *
****************************************************************************
}
Public Sub SetPixel(pX, pY As Byte)
Dim Pixel As Byte
Dim Mask As Byte
Dim Justify As Byte
If (pX < GLCDWidth) And (pY < GLCDHeight) Then
Justify = pX And 1
pX = (pX >> 1)
pY = pY
DC = 0
CS = 0
TRISData = $00 // set data bus to output
Data = cmdSetCol 'Set position
Write()
Data = pX
Write()
Data = cmdEndCol
Write()
Data = cmdSetRow
Write()
Data = pY
Write()
Data = cmdEndRow
Write()
Data = 255 'Dummy Read
DC = 1
Read()
TRISData = $FF // set data bus to Input
RD = 0 'Read Read
DelayUS(5) 'let things stabilise before reading
Pixel = Data
RD = 1
DC = 0
// pen is white...
If Pen.Color = $00 Then
'If Pen.Mode = pmCopy Then
If Justify = 1 Then
Mask = $F0
Else
Mask = $0F
EndIf
Pixel = Mask And Pixel
'EndIf
// pen is black...
Else
If Justify = 1 Then
Mask = Pen.Color
Else
Mask = Pen.Color * 16
EndIf
// pen copy or merge...
If Pen.Mode <> pmXOR Then
Pixel = Mask Or Pixel
// pen XOR
Else
If (Pixel And Mask) = 0 Then
Pixel = Pixel Or Mask
Else
Mask = Not Mask
Pixel = Pixel And Mask
EndIf
EndIf
EndIf
TRISData = $00 // set data bus to output
Data = cmdSetCol 'Set position
Write()
Data = pX
Write()
Data = cmdEndCol
Write()
Data = cmdSetRow
Write()
Data = pY
Write()
Data = cmdEndRow
Write()
DC = 1
Data = Pixel
Write()
CS = 1
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 = GetData >> (pY Mod 8)
Result = Pixel.0
End Function
{
********************************************************************************
* Name : Fill *
* Purpose : Fill screen area with brush color. *
* : Assumes pX1 < pX2 and pY1 < pY2 *
********************************************************************************
}
Public Sub Fill(pX1, pY1, pX2, pY2 As TXY)
For Pos.x = pX1 To pX2
For Pos.y = pY1 To pY2
SetPixel(Pos.x,Pos.y)
Next
Next
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 (OVERLOAD) *
* Purpose : Overrides the GLCD library native SetImage call with this *
* : routine which is better suited for rendering to the SSD0323 *
* : pImageAdr is the address of the image to render. *
* : Each databyte holds 2 adjactent pixels. Image must be even *
* : sized horizontally and placed in an even location. *
* : *To Be Looked At* *
****************************************************************************
}
#define GLCD_SETIMAGE // override GLCD SetImage
Public Sub SetImage(pX, pY As TXY, pImageAdr As Word)
Dim x, y As Byte
Dim Image As TImage
// get bitmap ID, width and height...
TABLEPTR = pImageAdr
Image.Width = ReadImageByte
Image.Width = (Image.Width / 2)
Image.Height = ReadImageByte
For y = pY To (pY + (image.Height - 1))
Command(cmdSetCol,pX,cmdEndCol)
Command(cmdSetRow,y,cmdEndRow)
DC = 1
CS = 0
TRISData = $00 // set data bus to output
For x = 0 To (Image.Width - 1)
Data = ReadImageByte
DelayUS(1)
Write()
DelayUS(1)
Next
CS = 1
DelayUS(1)
Next
End Sub
{
********************************************************************************
* Name : SetImage *
* Purpose : BitBlit image To GLCD at pixel location x, y. *
* : NOTE - This subroutine only supports Greyscale 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)
End Sub
{
****************************************************************************
* Name : Cls *
* Purpose : Clear the GLCD screen *
****************************************************************************
}
Public Sub Cls()
Dim x As Word
Command(cmdSetCol,$00,cmdEndCol)
Command(cmdSetRow,$00,cmdEndRow)
DC = 1
CS = 0
TRISData = $00 // set data bus to output
Data = $00
For x = 0 To 4096
Write()
Next
CS = 1
End Sub
{
****************************************************************************
* Name : BlankScreen *
* Purpose : Blanks the display, but preserves data *
****************************************************************************
}
Public Sub BlankScreen(x As Boolean)
If x = true Then
Command($A6) 'All Pixels blank (data untouched)
Else
Command($A4) 'Normal Mode (data untouched)
EndIf
End Sub
{
****************************************************************************
* Name : OLEDoff *
* Purpose : Shuts off oled display safely *
****************************************************************************
}
Public Sub OLEDoff()
Command(cmdOff) // Turn display off
Low(POWER2)
DelayMS(100)
Low(POWER1)
End Sub
{
****************************************************************************
* Name : Initialize *
* Purpose : Configure the GLCD before use *
****************************************************************************
}
Sub Initialize()
High(POWER1) // VDD on
Output(RS)
RS = 0
DelayMS(100)
RS = 1
Pos.x = 0
Pos.y = 0
DelayMS(GLCDDelay) // start up delay, allow GLCD to settle
High(DC)
High(RW)
High(CS)
High(RD)
Command(cmdOff) // Turn display off
High(POWER2) // VCC on
DelayMS(GLCDDelay)
#if OLED_MODEL = CALGARY
Command($86,$86) 'Set Current Range
Command($81,$66) 'Set Contrast Control
#if GLCD_FLIP = FALSE 'Cable Bottom Exit
Command($A0,$52) 'Set Remap
Command($A2,$4C) 'Set Display Offset
#else 'Cable Top Exit
Command($A0,$41) 'Set Remap
Command($A2,$44) 'Set Disply Offset
#endif
Command($A1,$00) 'Set Display Start Line
Command($A4) 'Set Display Mode
Command($AD,$02) 'Set DC-DC converter off
Command($A8,$3F) 'Set Multiplex Ratio
Command($B2,$46) 'Set Row Period
Command($B0,$28) 'Set Pre-Charge compensation
Command($B4,$07)
Command($B3,$91) 'Set Clock Divide was $F1
Command($B1,$22) 'Set Phase Length
Command($BF,$0D) 'Set VSL
Command($BE,$02) 'Set VCOMH
Command($BC,$10) 'Set VPrecharge
// Set Grey Scale Table
Command($B8)
Command($00)
Command($11)
Command($21)
Command($32)
Command($43)
Command($54)
Command($65)
Command($76)
#endif
#if OLED_MODEL = ATLANTA
Command($86,$86) 'Set Current Range
Command($81,$35) 'Set Contrast Control
#if GLCD_FLIP = FALSE 'Cable Bottom Exit
Command($A0,$52) 'Set Remap
Command($A2,$40) 'Set Display Offset
#else 'Cable Top Exit
Command($A0,$41) 'Set Remap
Command($A2,$44) 'Set Disply Offset
#endif
Command($A1,$00) 'Set Display Start Line
Command($A4) 'Set Display Mode
Command($AD,$02) 'Set DC-DC converter off
Command($A8,$3F) 'Set Multiplex Ratio
Command($B2,$46) 'Set Row Period
Command($B0,$28) 'Set Pre-Charge compensation
Command($B4,$07)
Command($B3,$21) 'Set Clock Divide was $F1
Command($B1,$22) 'Set Phase Length
Command($BF,$0B) 'Set VSL
Command($BE,$0B) 'Set VCOMH
Command($BC,$10) 'Set VPrecharge
// Set Grey Scale Table
Command($B8)
Command($00)
Command($11)
Command($21)
Command($32)
Command($43)
Command($54)
Command($65)
Command($76)
#endif
Cls()
// Display On
Command(cmdOn)
// Set Row & Column Address
Command(cmdSetCol,$00,cmdEndCol)
Command(cmdSetRow,$00,cmdEndRow)
End Sub
// configure the module
Initialize
Code: Select all
// validate model...
#option GLCD_MODEL = SSD0323
#if Not (GLCD_MODEL in (SSD0323, SSD0323DF, KS0108, S1D10605, S1D15G00, SED1520, S1D13700))
#error GLCD_MODEL, "Invalid option. GLCD model not recognized."
#endif
#if GLCD_MODEL = SSD0323
Include "SSD0323.bas"
Public Dim
Pos As SSD0323.Pos,
Cls As SSD0323.Cls,
SetPixel As SSD0323.SetPixel,
SetImage As SSD0323.SetImage,
Fill As SSD0323.Fill
#endif
Thanks for posting it! I'll go through our respective functions and see what I can do to get something working. This ain't rocket science, it should be a straightforward case of "fetch the font byte, then write it the way the hardware wants it". Once it works I'll repost for any and all to critique/test/etc.
-Tom
-Tom
I can already see some things to work on:
1. I didn't put in the dummy read before the actual read. This will have to be done before the function can be used for reading back bytes from the SSD1330 chip.
2. Looking at the SSD1339 datasheet, it's not entirely clear whether it's the CS line or the E line or possibly even the RW line or all these lines that optimally need to be toggled for each read or write. The Solomon Systech SSD1339 datasheet did not provide more than a single read/write cycle in the parallel data example. The datasheet is written in a very terse manner with grammatical errors, so I'm not surprised to see your code uses the R/W line to latch data and I use CS. It seems both methods "work" but I have to wonder if this will lead to "surprise" faults under conditions of stress such as temperature extremes.
3. Need to add a fill command.
4. SetImage() is key to this working, there's a big difference between them in the different code variants. WriteChar() sort of works as-is with David's original GLCD code but I need to get the MPlab debugger working with this code so I can see what is being written. My code won't compile for the MPLab software debugger for some reason, I really really hope SF will incorporate it's own debugger in the future. Writing code without decent visibility is why I'm having problems getting this routine going in the first place. I suppose I could wire up an 18F66J16 with in-circuit hardware debug but that's another week or more to get running...the idea of using BASIC instead of C, C##, etc. is to avoid long learning/implemenation curves.
-Tom
1. I didn't put in the dummy read before the actual read. This will have to be done before the function can be used for reading back bytes from the SSD1330 chip.
2. Looking at the SSD1339 datasheet, it's not entirely clear whether it's the CS line or the E line or possibly even the RW line or all these lines that optimally need to be toggled for each read or write. The Solomon Systech SSD1339 datasheet did not provide more than a single read/write cycle in the parallel data example. The datasheet is written in a very terse manner with grammatical errors, so I'm not surprised to see your code uses the R/W line to latch data and I use CS. It seems both methods "work" but I have to wonder if this will lead to "surprise" faults under conditions of stress such as temperature extremes.
3. Need to add a fill command.
4. SetImage() is key to this working, there's a big difference between them in the different code variants. WriteChar() sort of works as-is with David's original GLCD code but I need to get the MPlab debugger working with this code so I can see what is being written. My code won't compile for the MPLab software debugger for some reason, I really really hope SF will incorporate it's own debugger in the future. Writing code without decent visibility is why I'm having problems getting this routine going in the first place. I suppose I could wire up an 18F66J16 with in-circuit hardware debug but that's another week or more to get running...the idea of using BASIC instead of C, C##, etc. is to avoid long learning/implemenation curves.
-Tom
OK, after some work, here's code that uses USART port 2 for debugging and will correctly print fonts and graphics. Note the initialization strings, they are critical. I also need to clean up the line strobe functions, I put them in explicitly to make sure it worked. I'll clean it up and try to get larger sized fonts to work, they are not there yet. Also, for some reason, TBLRD*+ didn't increment the pointer - I had so add a parallel index function called count.
-Tom
-Tom
Code: Select all
Module SSD1339
Device = 18F66J16
#define GLCD_PIXEL_08
#define GLCD_COLOR_08
#define GLCD_XY_08
Include "Graphics.bas"
Include "system.bas"
Include "usart2.bas"
Include "convert.bas"
// default module options - user options can override these values...
// this code uses the 6800 format 8-bit parallel interface
// 6800 8-bit configuration used: BS0 low, BS1 low, BS2 high, BS3 low
// This display is 132x132. The RGB interpretation for 8 bit colour is the same
// as for the S1D15G00 - RRRGGGBB.
#option GLCD_RESET = PORTE.5 // reset pin, active low-like S1D15G00
#option GLCD_DATA = PORTD // data port
#option GLCD_DC = PORTE.6 // Data or Command pin, data when high
#option GLCD_CS = PORTE.7 // Chip Select pin, MCU comms enabled when low-like S1D15G00
#option GLCD_E = PORTB.2 // Enable pin, R/W data latched when pulled high-like S1D15G00
#option GLCD_RW = PORTB.3 // Read-Write pin, write mode when low-like S1D15G00
#option GLCD_ASPECT_RATIO = 100 // aspect ratio
#option GLCD_INIT_DELAY = 100 // initialisation delay (ms)
//#option GLCD_SPI = SW // use software SPI
// validate Reset pin...
#if IsOption(GLCD_RESET) And Not IsValidPortPin(GLCD_RESET)
#error GLCD_RESET, "Invalid option. RESET must be a valid port pin."
#endif
// validate DATA port...
#if IsOption(GLCD_DATA) And Not IsValidPort(GLCD_DATA)
#error GLCD_DATA, "Invalid option. DATA must be a valid port."
#endif
// validate DC pin...
#if IsOption(GLCD_DC) And Not IsValidPortPin(GLCD_DC)
#error GLCD_DC, "Invalid option. DC 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 E pin...
#if IsOption(GLCD_E) And Not IsValidPortPin(GLCD_E)
#error GLCD_E, "Invalid option. E 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 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
// SSD1339 commands...
Const
cmdDisCtl = $CA, //Display Control
cmdNOP = $E3, //NOP - $25 in S1D15G00
cmdDisOn = $AF, //Display On, out of sleep
cmdDisOff = $AE, //Display Off, in sleep mode
cmdBlank = $A4, //Sets diplay mode to All Off-all pixels have GS0 (grayscale level 0), minimum brightness
cmdAllOn = $A5, //Sets diplay mode to All On-all pixels have GS63 (grayscale level 63), maximum brightness
cmdDisNor = $A6, //Sets display mode to Display Normal
cmdDisInv = $A7, //Sets display mode to Display Invert-gray levels swapped-GS0 is GS63, GS7 is GS56, etc
cmdPaSet = $75, //Page Address Set
cmdCaSet = $15, //Column Address Set
cmdRamWr = $5C, //Writing to Memory
cmdCtrst = $C7, //Master contrast control
cmdRemap = $A0, //$A0 then $34, normal; $A0 then $26 - flips display 180 degrees
cmdStLin = $A1, //sets starting line
cmdVScrl = $A2, //set vertical scroll by row from 0-131
cmdMastC = $AD, //master configuration, int/ext VCC suppply and int/ext pre-charge V supply
cmdPwrSa = $B0, //power save mode, sets int/ext VSL and power save on/off
cmdResPr = $B1, //et reset (phase 1) & pre-charge (2) period adjustments-1 is discharge time,2 is charge time
cmdOscDv = $B3, //front clock divider and int oscillator freq set
cmdPreCV = $BB, //set the pre-charge colour voltage of each colour
cmdVCOMH = $BE, //set VCOMH - should be irrelevant since use ext supply but manuals say set it...
cmdCoCol = $C1, //Contrast currents for each colour A, B, C (RGB)
cmdMuxRa = $CA, //mux ratio - number of display lines turned on - start & end depends on A2 cmd setting
cmdDLine = $83, //draw line
cmdDRect = $84, //draw rectangle
cmdDcirc = $86, //draw circle
cmdCopy = $8A, //Copy area
cmdDimWi = $8C, //Dim Window
cmdClWin = $8E, //Clear Window
cmdFilED = $92, //Fill Enable/Disable
cmdHorSc = $96, //Horizontal Scroll
cmdSpHor = $9E, //Stop horizontal scroll
cmdStHor = $9F, //Start horizontal scroll moving
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 port
TRISData As TRISD, // Data TRIS
E As GLCD_E.GLCD_E@, // clk pin
CS As GLCD_CS.GLCD_CS@, // CS pin
DC As GLCD_DC.GLCD_DC@, // DC pin
RW As GLCD_RW.GLCD_RW@, //RW pin
count As Word,
Reset As GLCD_RESET.GLCD_RESET@ // reset pin
// GLCD width and height...
Public Const
GLCDWidth = 130,
GLCDHeight = 130
// x, y position...
Public Dim
Pos As TPosition,
tempdata As Byte
'Contrast As FContrast
{
****************************************************************************
* Name : StrobeEN (Private) *
* Purpose : Strobe the GLCD EN pin *
****************************************************************************
}
Inline Sub StrobeEN()
CS = 0
E = 1
DelayUS(1)
CS = 1
End Sub
{
****************************************************************************
* Name : GLCDData (PRIVATE) *
* Purpose : Switch To GLCD Data mode *
* Modified For KS0713 *
****************************************************************************
}
Inline Sub GLCDData()
DC = 1
End Sub
{
****************************************************************************
* Name : GLCDInst (PRIVATE) *
* Purpose : Switch To GLCD instruction mode *
* Modified For KS0713 *
****************************************************************************
}
Inline Sub GLCDInst()
DC = 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 : SetData (PRIVATE) *
* Purpose : Write a Data Byte To GLCD *
****************************************************************************
}
Sub SetData(pData As Byte)
TRISData = $00 // Set Data bus To Output
GLCDData // access display RAM Data
GLCDWrite // write mode
Data = pData // write To the bus
StrobeEN // write To GLCD
End Sub
{
****************************************************************************
* Name : WriteData (PRIVATE) *
* Purpose : Write a series of data bytes to GLCD *
****************************************************************************
}
Compound Sub WriteData(SetData)
{
****************************************************************************
* Name : GetData (PRIVATE) *
* Purpose : Read Byte from GLCD *
****************************************************************************
}
Function GetData() As Byte
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 *
****************************************************************************
}
Public Sub Command(pCommand As Byte)
TRISData = $00 // Set Data bus To Output
GLCDInst // instruction mode
GLCDWrite // write mode
Data = pCommand // write To the bus
StrobeEN // write To GLCD
End Sub
{
****************************************************************************
* Name : CommandWithData (PRIVATE) *
* Purpose : Write a command plus extra Data Byte To GLCD *
****************************************************************************
}
Sub CommandWithData(pCommand,pData As Byte)
TRISData = $00 // Set Data bus To Output
GLCDInst // instruction mode
GLCDWrite // write mode
Data = pCommand // write To the bus
StrobeEN // write To GLCD
Data = pData
GLCDData // instruction mode
GLCDWrite // write mode
StrobeEN
End Sub
{
****************************************************************************
* Name : WriteCommnad (PRIVATE) *
* Purpose : Use to write a series of command bytes to GLCD when there is *
* more than one data byte to write after the command mnemonic *
****************************************************************************
}
Public Compound Sub WriteCommands(Command,SetData)
{
****************************************************************************
* Name : MoveTo (PRIVATE) *
* Purpose : Move to position x,y on the GLCD *
****************************************************************************
}
Sub MoveTo(pX, pY As Byte)
//X position start address,X position end address,Y position start address,
//Y position end address,write to RAM
WriteCommands(cmdCaSet,pX,GLCDWidth - 1,cmdCaSet,pY + 2,GLCDHeight + 1,cmdRamWr)
End Sub
{
****************************************************************************
* Name : SetPixel *
* Purpose : Set pixel at pixel location x,y *
****************************************************************************
}
Public Sub SetPixel(pX, pY As Byte)
'MoveTo(pX, pY)
'WriteCommands(cmdCaSet,pX,pX)
'WriteCommands(cmdPaSet,pY,pY)
Command($5C)
TRISData = $00 // set data bus to output
DC = 1 //indicate it's data
RW = 0 //indicate it's a read
E = 1 //initiate a write
CS = 0 //start operation
Data = Pen.Color
CS = 1 //end operation
E = 0 //end initiation
'WriteData(Pen.Color,$55)
'WriteCommands(cmdDLine,pX,pY,pX,pY,Pen.Color,$55)
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 TColor
Pos.y = pY
Pos.x = pX
WriteCommands(cmdCaSet,Pos.x,Pos.x)
WriteCommands(cmdPaSet,Pos.y,Pos.y)
GetData
'Pixel = GetData >> (pY Mod 8)
'Result = Pixel.0
End Function
{
****************************************************************************
* Name : SetContrast *
* Purpose : Set the GLCD contrast *
****************************************************************************
}
Public Sub SetContrast(pContrast As Byte)
WriteCommands(cmdCtrst,pContrast)
End Sub
{
****************************************************************************
* Name : Cls *
* Purpose : Clear the GLCD screen *
****************************************************************************
}
Public Sub Cls(pX,pY,pEndX,pEndY As Byte)
WriteCommands(cmdClWin,pX,pY,pEndX,pEndY)
End Sub
{
****************************************************************************
* Name : MakeColor *
* Purpose : The S1D15G00 8 bit color scheme maps 3 bit R, G values and *
* : a 2 bit B value onto a 12 bit RGB. This routine allows you *
* : to create a color by specifying RGB values in the range 0..255 *
****************************************************************************
}
Public Function MakeColor(pR, pG, pB As Byte) As TColor
'result = (pR / 32 << 5) Or (pG / 32 << 2) Or (pB / 64)
End Function
{
****************************************************************************
* Name : PowerOLED *
* Purpose : Configure the GLCD before Vcc is applied - run this whenever *
* the 3.3V bus is started so the display is ready for the high *
* voltage Vcc. *
****************************************************************************
}
Public Sub PowerOLED()
Command(cmdDisOff) //turn off display
Cls(0,0,132,132) //clear screen
DelayMS(GLCDDelay) //Must be at least 100 mS between this cmd and Vcc
End Sub
{
****************************************************************************
* Name : Initialize *
* Purpose : Configure the GLCD before use. *
****************************************************************************
}
Public Sub Initialize() //first section same as PowerOLED
Command(cmdDisOff) //turn off display
Cls(0,0,132,132) //clear screen
DelayMS(GLCDDelay)
// set display clock divide ratio and oscillator frequency
WriteCommands(cmdOscDv,$F0)
//set display offset, = 132 - dummy lines from common 0
WriteCommands(cmdVScrl,$00) //setting to $01 starts the line off the display
//set multiplex ratio
WriteCommands(cmdMuxRa, $84) //use 131 lines on the display
//set master configuration
WriteCommands(cmdMastC, $8F) //use external Vcc & external pre-charge V source ($8E in Densitron manual)
//set display start line
CommandWithData(cmdStLin, $00) //set start line at 0
//set segment re-map & data format
CommandWithData(cmdRemap, $34) //$34 sets to normal display, $26 flips display 180 degrees. Notes:
//$xxxx xxx0 = X1, horizontal (xxx0), or vertical (xxx1)address pointer movement
//$xxxx xx0x = X2, column addresses mapped left to right (xx0x), or right to left (xx1x)
//$xxxx x0xx = X4, colour remap, colour sequence is ABC (x0xx), or CBA (x1xx)
//$xxxx 0xxx = X8, MCU interface 8/16 or 9/18 bit, 8/16 (0xxx), or 9/18 (1xxx)
//$xxx0 xxxx = 1X, scan remap, up to down (xxx0), or down to up (xxx1)
//$xx0x xxxx = 2X, disable com split odd even (xx0x), or enable...just try it to see it, too hard to explain (xx1x)
//$x0xx xxxx = 4X, 256 colours (00xx) or 65K colours (01xx)
//$0xxx xxxx = 8X, 262K colours with 8/9/16 bit MCU interface, or 262K colours with 16 bit MCU interface (11xx)
//set master contrast current control, user may have to adjust...
SetContrast(158)
//set contrast control for colours A,B,C (RGB)
WriteCommands(cmdCoCol,$80,$80,$80) //confirmed reset values, may change later
//set pre-charge voltage of colours A,B,C (RGB)
WriteCommands(cmdPreCV,$1C,$1C,$1C) //confirmed reset values, may change later
//set VCOMH
CommandWithData(cmdVCOMH, $1F) //use ext VCOMH so should be irrelevant but manuals say to set it...
//Set reset (phase 1) & pre-charge (2) period adjustments-1 is discharge time,2 is charge time -higher
// capacitance displays need more time and thus a higher value
CommandWithData(cmdResPr, $47) //used $47 out of FF as per defaults-old code used $11
//set power saving mode
CommandWithData(cmdPwrSa, $1A) //Power saving with external VSL, as per manual
//set display mode - turn display on
Command(cmdDisOn)
End Sub
{
****************************************************************************
* Name : SetRegion (PRIVATE) *
* Purpose : Sets the GLCD display boundary setting region *
****************************************************************************
}
Sub SetRegion(pX, pY, pWidth, pHeight As Byte)
WriteCommands(cmdCaSet,pX,pX + pWidth - 1)
WriteCommands(cmdPaSet,pY + 2,pY + pHeight + 1)
End Sub
{
****************************************************************************
* Name : Line *
* Purpose : Draw Line *
* : write start col/row, end col/row,line colour byte 1&2 *
****************************************************************************
}
Public Sub Line(pX1, pY1, pX2, pY2 As TXY,pColor,pColor2 As Byte)
WriteCommands(cmdDLine,pX1, pY1, pX2, pY2,pColor,pColor2)
End Sub
{
****************************************************************************
* Name : Rectangle *
* Purpose : Draw Rectangle *
* : write start col/row, end col/row,line colour byte 1 & 2,fill *
* colour bytes 1 & 2 *
****************************************************************************
}
Public Sub Rectangle(pX1, pY1, pX2, pY2 As TXY,pColor,pColor2,pFColor,pFColor2 As Byte)
WriteCommands(cmdDRect,pX1, pY1, pX2, pY2,pColor,pColor2,pFColor,pFColor2)
End Sub
{
****************************************************************************
* Name : Circle *
* Purpose : Draw circle *
* : write col/row address of center, radius,line colour byte 1&2, *
* fill colour bytes 1 & 2 *
****************************************************************************
}
Public Sub Circle(pX1, pY1, pRadius, pColor,pColor2,pFColor,pFColor2 As Byte)
WriteCommands(cmdDcirc,pX1, pY1, pRadius, pColor,pColor2,pFColor,pFColor2)
End Sub
{
****************************************************************************
* Name : Copy *
* Purpose : Copy one area of the screen to another *
* : Define col/row to start, col/row to end, col/row of new start *
****************************************************************************
}
Public Sub Rectangle(pX1, pY1, pX2, pY2 As TXY,CopyCol, RowCol As Byte)
//write start col/row, end col/row,line colour byte 1&2, fill colour byte 1&2
WriteCommands(cmdCopy,pX1, pY1, pX2, pY2,CopyCol, RowCol)
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 (OVERLOAD) *
* Purpose : Overrides the GLCD library native SetImage call with this *
* : routine which is better suited for rendering to the S1D15G00 *
* : pImageAdr is the address of the image to render *
****************************************************************************
}
#define GLCD_SETIMAGE // override GLCD SetImage
Public Sub SetImage(pX, pY As TXY, pImageAdr As Word)
Dim x, y As Byte
Dim Image As TImage
'Dim count As Word
Dim Index, Range As Word
Dim RLENum As Byte
Dim LastPenColor As Byte
count = 0
LastPenColor = Pen.Color
Index = 0
// get bitmap ID, width and height...
TABLEPTR = pImageAdr
Image.Header = ReadImageByte
Image.Width = ReadImageByte
//Image.Width = (Image.Width / 2)
Image.Height = ReadImageByte
'USART2.Write("Width/height,x,y,header: ", HexToStr(Image.Width),",",HexToStr(Image.Height),",",HexToStr(pX),",",HexToStr(pY),",",HexToStr(Image.Header), 13, 10)
Range = Image.Height * Image.Width
'DelayMS(10000)
'For y = pY To (pY + (image.Height - 1))
WriteCommands(cmdCaSet,pX+2,Image.Width+1)
WriteCommands(cmdPaSet,pY+6,Image.Height+10)
Command($5C)
DC = 1
CS = 0
TRISData = $00 // set data bus to output
Repeat
RLENum = 1
If Image.IsRLE Then
TABLEPTR = pImageAdr + 4 + count
Inc(count)
RLENum = ReadImageByte
EndIf
'USART2.Write("RLENum first loop check: ",HexToStr(RLENum),13, 10)
Repeat
'Inc(pImageAdr)
TABLEPTR = pImageAdr + 4 + count
DC = 1 //indicate it's data
RW = 0 //indicate it's a read
E = 1 //initiate a write
CS = 0 //start operation
Data = ReadImageByte
CS = 1 //end operation
E = 0 //end initiation
Dec(RLENum)
Inc(Index)
'USART2.Write("RLENum: ",HexToStr(RLENum),13, 10)
Until RLENum = 0
Inc(count)
Until Index >= Range
'Next
'Next
Pen.Color = LastPenColor
End Sub
{
****************************************************************************
* Name : SetImage (OVERLOAD) *
* Purpose : Overrides the GLCD library native SetImage call with this *
* : routine which is better suited for rendering to the S1D15G00 *
* : pImage is a constant array holding the image data to render *
****************************************************************************
}
Public Sub SetImage(pX, pY As TXY, ByRefConst pImage() As Byte)
SetImage(pX, pY, @pImage)
End Sub
{
****************************************************************************
* Name : WriteChar *
* Purpose : Overrides the GLCD library native WriteChar call with this *
* : routine which is better suited for rendering to the S1D15G00 *
* : This routine will only handle xFonts (that is, font files with *
* : the scan line in the x direction) *
****************************************************************************
}
#define GLCD_WRITECHAR // override GLCD WriteChar
#define GLCD_XFONT // force the use of x scanned font
Public Sub WriteChar()
Dim FontByte As Byte
Dim x, y, xRange, yRange As Byte
Dim PenColor As TColor
Dim Range, Index As Word
Dim Ignore As Boolean
'count = 0
'count = count + TABLEPTR
'USART2.Write("TABLEPTR, count:",HexToStr(TABLEPTR),",",HexToStr(TABLEPTR),13, 10)
PenColor = Pen.Color
Index = 0
// is the brush style clear...
If Brush.Style = bsClear Then
Ignore = false
yRange = Pos.y + Font.Height
y = Pos.y
While y < yRange
MoveTo(Pos.x,y)
xRange = Pos.x + Font.Width
x = Pos.x
While x < xRange
FontByte = ReadFontByte
Index = 8
Repeat
// write a font pixel with pen color...
If FontByte.7 = 1 Then
If Ignore Then
WriteCommands($15,x,Pos.x + Font.Width)
Command($5C)
Ignore = false
EndIf
Command($5C)
TRISData = $00 // set data bus to output
DC = 1 //indicate it's data
RW = 0 //indicate it's a read
E = 1 //initiate a write
CS = 0 //start operation
Data = Pen.Color
CS = 1 //end operation
E = 0 //end initiation
// skip transparent pixel...
Else
Ignore = true
EndIf
FontByte = FontByte << 1
Dec(Index)
Inc(x)
Until Index = 0
Wend
Inc(y)
Wend
// brush style is not clear, fast bit blit...
Else
x = 0
SetRegion(Pos.x, Pos.y, Font.Width, Font.Height)
Range = Font.Height * Font.Width
Repeat
// grab a font byte...
If x >= Font.Width Then
FontByte = ReadFontByte
x = 0
ElseIf x Mod 8 = 0 Then
FontByte = ReadFontByte
EndIf
Inc(x)
// set either font color or background color...
If FontByte.7 = 1 Then
Pen.Color = PenColor
Else
Pen.Color = Brush.Color
EndIf
Command($5C)
TRISData = $00 // set data bus to output
DC = 1 //indicate it's data
RW = 0 //indicate it's a read
E = 1 //initiate a write
CS = 0 //start operation
Data = Pen.Color
CS = 1 //end operation
E = 0 //end initiation
FontByte = FontByte << 1
Inc(Index)
Until Index >= Range
EndIf
Pen.Color = PenColor
Inc(Pos.x,Font.Width)
End Sub
// configure the module
Initialize
SetBaudrate(br19200)
Glad you got something working!RadioT wrote:I can already see some things to work on:
1. I didn't put in the dummy read before the actual read. This will have to be done before the function can be used for reading back bytes from the SSD1330 chip.
2. Looking at the SSD1339 datasheet, it's not entirely clear whether it's the CS line or the E line or possibly even the RW line or all these lines that optimally need to be toggled for each read or write. The Solomon Systech SSD1339 datasheet did not provide more than a single read/write cycle in the parallel data example. The datasheet is written in a very terse manner with grammatical errors, so I'm not surprised to see your code uses the R/W line to latch data and I use CS. It seems both methods "work" but I have to wonder if this will lead to "surprise" faults under conditions of stress such as temperature extremes.
3. Need to add a fill command.
4. SetImage() is key to this working, there's a big difference between them in the different code variants. WriteChar() sort of works as-is with David's original GLCD code but I need to get the MPlab debugger working with this code so I can see what is being written. My code won't compile for the MPLab software debugger for some reason, I really really hope SF will incorporate it's own debugger in the future. Writing code without decent visibility is why I'm having problems getting this routine going in the first place. I suppose I could wire up an 18F66J16 with in-circuit hardware debug but that's another week or more to get running...the idea of using BASIC instead of C, C##, etc. is to avoid long learning/implemenation curves.
-Tom
1. Yeah, the dummy read is important. I think some of the SF routines pull back data from the controller so this is pretty important.
2. The CS / R/W thing is do do with which parallel mode you have selected. I believe mine runs in 8080 mode. Is yours set to 6800 mode? The Pins behave differently depending on which is set. It might just be I misnamed my pins though, that bit of the datasheet was a bit of a mess!
You're right that the Solomon datasheets leave something to be desired. Most of my work came from the OSRAM Pictivia datasheets which helpfully explained a lot that the Solomon stuff left out.
4. Be warned - my setimage routine is a very quick and dirty hack. Because of the 2 pixels per byte addressing scheme my display has, I couldn't be bothered to process it properly on the PIC, plus it produces nicely packed datatables. I modified someone elses code to do the dirty work on the PC for me.
It is a bit frustrating running without debug, but I understand David is working hard at it as we speak. I find a few well placed Serial print routines can usually work wonders anyway!
Looks like good work to me so far! Perhaps it might stir me into properly tidying up my code!
Right, sorry, I didn't state that I am using 6800 mode. Thus, the E pin references.2. The CS / R/W thing is do do with which parallel mode you have selected. I believe mine runs in 8080 mode. Is yours set to 6800 mode? The Pins behave differently depending on which is set. It might just be I misnamed my pins though, that bit of the datasheet was a bit of a mess!
Glad to hear David is planning on a built-in debug facility. Nothing like being able to just pick variables to watch and set breakpoints instead of having to set up print statements and delays!
-Tom
Hello both,
I have written a completely bespoke driver for my little 128*160 TFT and thy VB conversion software for BMP conversion(developed over the last year).
The main things I was interested in was speed of refresh and compact data tables.
Both were achieved by splitting the high and low data bytes of the display packet into seperate data tables and then the subsequent read loop requires only one increment of the loop per pixel read as the location in the two data tables is the same, this makes a very large improvement in speed, some 30% if memory serves.
Another speed improvement in the order of 10-15% was to have two byte sized loops to count the word sized table address, the pic does not like to throw words around as much as it likes bytes.
My final throw of the dice was to do a little compression in the VB code which is quite simply counting consecutive bytes of the same value in the data tables and producing a third table which is used as a loop counter for the values in the main data tables.
Allthough there is a penalty in terms of execution time within the PIC as it requires an extra read an loop, this is usually outweighed by the fact that the stred data tables can be 25% to 95% smaller!
I have written a completely bespoke driver for my little 128*160 TFT and thy VB conversion software for BMP conversion(developed over the last year).
The main things I was interested in was speed of refresh and compact data tables.
Both were achieved by splitting the high and low data bytes of the display packet into seperate data tables and then the subsequent read loop requires only one increment of the loop per pixel read as the location in the two data tables is the same, this makes a very large improvement in speed, some 30% if memory serves.
Another speed improvement in the order of 10-15% was to have two byte sized loops to count the word sized table address, the pic does not like to throw words around as much as it likes bytes.
My final throw of the dice was to do a little compression in the VB code which is quite simply counting consecutive bytes of the same value in the data tables and producing a third table which is used as a loop counter for the values in the main data tables.
Allthough there is a penalty in terms of execution time within the PIC as it requires an extra read an loop, this is usually outweighed by the fact that the stred data tables can be 25% to 95% smaller!
Hi Mark,
Since the last posts, I've done some more work with this module. I'm using it in 256 colour mode so am directly writing 8 bits as the total data packet size but I'll keep your array ideas in mind should I go to a higher colour count, since they require a 2 byte write.
The compression you mention sounds to me like a modified form of RLE (run-length encoding) except with putting the "number of bytes of X" in a separate array. I am using the GLCD graphic plug-in to compress the image for my logo splash screen with RLE. Since the image is only a few colours, I am getting about 4 to 1 compression, quite nice.
One note about the SSD1339 controller. I was getting strange scrambling on all of the font bits on reset or power-up when running clock speeds above 4 MHz. Later font data writes often worked. After some testing, I realized the issue was not related to pin strobe timing but to synchronization of the PIC output data lines of the port (I am using Port D) to the OLED's input. I now write a line of data to appear on the screen and then immediately re-run the initialization sequence. Perhaps running the entire initialization is over-doing it, but now it always comes up perfectly. Note that I always write some data to the screen between the initializations; if I do not, I have seen where the screen comes up blank. Note the low voltage power supply is always brought up before the high-voltage supply prior to initialization. If done in the opposite sequence, I have seen where the screen comes up blank.
For example, instead of running:
I now run:
in my testing and it always comes up correctly.
73's,
de Tom
Since the last posts, I've done some more work with this module. I'm using it in 256 colour mode so am directly writing 8 bits as the total data packet size but I'll keep your array ideas in mind should I go to a higher colour count, since they require a 2 byte write.
The compression you mention sounds to me like a modified form of RLE (run-length encoding) except with putting the "number of bytes of X" in a separate array. I am using the GLCD graphic plug-in to compress the image for my logo splash screen with RLE. Since the image is only a few colours, I am getting about 4 to 1 compression, quite nice.
One note about the SSD1339 controller. I was getting strange scrambling on all of the font bits on reset or power-up when running clock speeds above 4 MHz. Later font data writes often worked. After some testing, I realized the issue was not related to pin strobe timing but to synchronization of the PIC output data lines of the port (I am using Port D) to the OLED's input. I now write a line of data to appear on the screen and then immediately re-run the initialization sequence. Perhaps running the entire initialization is over-doing it, but now it always comes up perfectly. Note that I always write some data to the screen between the initializations; if I do not, I have seen where the screen comes up blank. Note the low voltage power supply is always brought up before the high-voltage supply prior to initialization. If done in the opposite sequence, I have seen where the screen comes up blank.
For example, instead of running:
Code: Select all
InitializeOLED // initialize OLED
Cls(0,0,132,132) //clear entire screen
GLCD.SetFont(VerdanaBold)
GLCD.WriteAt(0,2,"Powered Up")
Code: Select all
InitializeOLED // initialize OLED
Cls(0,0,132,132) //clear entire screen
GLCD.SetFont(VerdanaBold)
GLCD.WriteAt(0,2,"Powered Up")
DelayUS(1)
InitializeOLED
GLCD.WriteAt(0,2,"Powered Up")
73's,
de Tom