PDA

View Full Version : Cannot drive I2C Oled :(



elcrcp
- 13th June 2015, 01:45
Hello guys, I tried to drive a 0.96" 128x64 I2C oled screen whole week and I'm about to go crazy because of this... I'm able to run the screen with arduino but I want to do it with a 877f (well I'm stubborn...)
My oled screen using ssd1306 driver and I read it's datasheet, I examined all lines of arduino codes and PICC codes (I didn't try PICC codes just viewed) But I wasn't able to run the screen :\ I can't see if I'm missing something or there is something I don't know about. Is there anyone who used these oled screens with PIC ? Or any hint what might I'd be missing.

I worked on CircuitDomain's codes and tried many changes on it but none work in the end... I started with this topic : http://www.picbasic.co.uk/forum/showthread.php?t=17973

N (http://www.picbasic.co.uk/forum/showthread.php?t=17973)ow I'm just trying to see a working pixel on screen, and these are my codes;


'==========================MCU SETUP============================================
Include "modedefs.bas"
DEFINE OSC 16
DEFINE I2C_SLOW 1 'to use 100kHz device over 4MHz oscillator
DEFINE I2C_HOLD 1


OPTION_REG=0
ADCON0=0
ADCON1=7
TRISA=%00111111
TRISB=%00000001
TRISC=0






'================================usuart=========== =============================


'==============================BAUD SETUP=======================================


I2CDevice var byte
SCL var PortC.3 ' I2C Clock PortC.3
SDA var PortC.4 ' I2C Data PortC.4
DC VAR byte' "DATA OR COMMAND", $40=DATA; $80=COMMAND
LCD_DATA VAR BYTE
COM VAR BYTE'COMMAND




I VAR BYTE
J VAR BYTE
X VAR BYTE' LCD POSITION X(0 TO 127)
Y VAR BYTE'LCD POSITION Y(0 TO 7)
CLEAR
'================================================= ============================
'PAGE = $B0


I2CDevice = $78 'Display Address = $78,


PAUSE 20


GOSUB INIT




MAIN:


gosub FILL
pause 1000
gosub CLEAR_LCD
pause 1000


GOTO MAIN




'=========================lcd initialization====================================
INIT:


COM=$AE:GOSUB SEND_COMMAND' DISPLAY OFF
pause 10
COM=$20:GOSUB SEND_COMMAND' ADRESSING MODE
COM=$02:GOSUB SEND_COMMAND' Page adressing mode
COM=$81:GOSUB SEND_COMMAND' Send contrast
COM=$FF:GOSUB SEND_COMMAND'
COM=$A4:GOSUB SEND_COMMAND' display on continue
COM=$A6:GOSUB SEND_COMMAND' $A6=NORMAL MODE;$A7=INVERSE MODE
COM=$AF:GOSUB SEND_COMMAND' DISPLAY ON
pause 10
gosub CLEAR_LCD
return
'================================================= ==============================
'==============================clear lcd========================================
CLEAR_LCD:




FOR J=0 TO 7
FOR I=0 TO 127
LCD_DATA=$00:GOSUB SEND_DATA
NEXT I
NEXT J


RETURN


'****************SEND COMMAND******************************************* *****


SEND_COMMAND:
dc=$80


I2CWrite SDA,SCL,I2CDevice,DC,[COM]


RETURN
'************************************************* ****************************


'======================Send data============================================== =
SEND_DATA:
DC=$40


I2CWrite SDA,SCL,I2CDevice,DC,[LCD_DATA]


RETURN
'================================================= ==============================
'=============================FILL================ =============================
FILL:
FOR J=0 TO 7
FOR I=0 TO 127
LCD_DATA=$FF:GOSUB SEND_DATA
NEXT I
NEXT J
RETURN
'================================================= ==============================


'===========================================SET X AND Y=========================
SET_XY:
COM=$21:GOSUB SEND_COMMAND
COM=X:GOSUB SEND_COMMAND
COM=127:GOSUB SEND_COMMAND
COM=$22:GOSUB SEND_COMMAND
COM=Y:GOSUB SEND_COMMAND
COM=Y:GOSUB SEND_COMMAND
RETURN
'================================================= ==============================
END

Demon
- 13th June 2015, 13:41
Until someone has something useful, I'd embed INIT instead of using GOSUB; just to simplify code.

(Gosubs are used when code is executed in more than one place)

Robert

Sherbrook
- 14th June 2015, 10:00
Is it the CRIUS display you have? If it is then I have some code that works. I did it a long time ago so it may take a while to find it.

Phil

elcrcp
- 14th June 2015, 13:33
Until someone has something useful, I'd embed INIT instead of using GOSUB; just to simplify code.

(Gosubs are used when code is executed in more than one place)

Robert
Thanks Demon, you are right about it :)

elcrcp
- 14th June 2015, 13:37
Is it the CRIUS display you have? If it is then I have some code that works. I did it a long time ago so it may take a while to find it.

Phil
Thanks Sherbrook,
It's label is not CRIUS but I checked CRIUS, they are same displays. I would be really greateful if you can find those codes so I can crosscheck my codes with yours to find what I'm missing.

Sherbrook
- 15th June 2015, 12:24
Here is some code. It fills the screen with 8 lines of vertical bars then clears it.
If the screen does not start up correctly dissconnect and wait or discharge with a resistor and try again. Apparently this is normal.
The 'INIT' routine was arrived at by trial and error, if you can improve on it let me know.
The 'RESET' routine makes no difference and is included for you to experiment.
Not an easy display to work with.

Phil



'************************************************* ***************
'* Name : CRIUS_OLED_Test.pbp *
'* Author : Philtronix *
'* Notice : Copyright (c) 2015 Philtronix *
'* : All Rights Reserved *
'* Date : 15/06/2015 *
'* Version : 1.0 *
'* Notes : PIC18F2550 int osc @ 4mHz 3.3v *
'* : CRIUS OLED display 3.3v *
'************************************************* ***************
osccon = %01100010 'Int OSC @ 4mHz
adcon1 = %00001111 'All ports digital
ucon.3 = 0 'Disable USB port
ucfg.3 = 1 'Digital in RC4 & RC5
cmcon = 7 'Comparators off

led var LatC.0
scl var PortC.1
sda var PortC.2
dat var byte
counter var word

control con %01111000 'I2C slave address (write mode)

trisb = %11000000
PortB = %00000000
pause 500

trisc = %11111000 'PortC 0, 1, 2 outputs
PortC = %00000110 'scl & sda high to start

pause 2000
' gosub RESET:
gosub init_oled:
i2cwrite sda,scl,control,[$80,$AF] 'Display ON
pause 10

Start:
led = 1 'Code running
i2cwrite sda,scl,control,[$80,$A7] 'Inverse Display
pause 500
i2cwrite sda,scl,control,[$80,$A6] 'Normal Display
pause 20
' i2cwrite sda,scl,control,[$80,$21,$00,$40] 'Set columns
pause 20
' i2cwrite sda,scl,control,[$80,$22,$00,$04] 'Set pages
pause 500
for counter = 0 to 1023
i2cwrite sda,scl,control,[$40,$FF]
next
led = 0 'Code running
for counter = 0 to 1023
i2cwrite sda,scl,control,[$40,$00]
next
GOTO Start:

INIT_OLED:
i2cwrite sda,scl,control,[$80,$AE] 'Display OFF ****
pause 1
i2cwrite sda,scl,control,[$80,$2E] 'Deactivate scrolling
pause 1
i2cwrite sda,scl,control,[$80,$20,$10] 'Page addressing mode ****
pause 1
i2cwrite sda,scl,control,[$80,$A0] ' ****
' i2cwrite sda,scl,control,[$80,$A1] ' ****
pause 1
i2cwrite sda,scl,control,[$80,$A6] 'WHITE chars BLACK backround
' i2cwrite sda,scl,control,[$80,$A7] 'BLACK chars WHITE backround
pause 1
i2cwrite sda,scl,control,[$80,$81,$7F] 'Setup contrast XXXX
pause 1
i2cwrite sda,scl,control,[$80,$AF] 'Display on ****
pause 1
i2cwrite sda,scl,control,[$80,$40]
pause 1
' i2cwrite sda,scl,control,[$80,$C0] 'Flip display vertically ****
i2cwrite sda,scl,control,[$80,$C8] 'Flip display vertically ****
pause 1
' i2cwrite sda,scl,control,[$80,$A0] ' ****
i2cwrite sda,scl,control,[$80,$A1] ' ****
pause 1
i2cwrite sda,scl,control,[$80,$00,$80,$10] 'Set column start address ****
pause 1
i2cwrite sda,scl,control,[$80,$B0] 'Set page start address ****
pause 1
return

RESET:
i2cwrite sda,scl,control,[$80,$AE] 'Display OFF
pause 10
I2Cwrite sda,scl,control,[$80,$20,$02] 'Page addressing mode
pause 10
i2cwrite sda,scl,control,[$80,$B0] 'Page start address
pause 10
i2cwrite sda,scl,control,[$80,$00,$80,$10] 'Set column start address
pause 10
i2cwrite sda,scl,control,[$80,$A0] 'Address 0 mapped to SEG 0
pause 10
' i2cwrite sda,scl,control,[$80,$A1] 'Address 0 mapped to SEG 127
pause 10
i2cwrite sda,scl,control,[$80,$D3,$00] 'Display offset
pause 10

pause 10
i2cwrite sda,scl,control,[$80,$40] 'Display start line
Pause 10
i2cwrite sda,scl,control,[$80,$C0] 'Output scan direction
pause 10
i2cwrite sda,scl,control,[$80,$A6] 'WHITE chars BLACK backround
pause 10
i2cwrite sda,scl,control,[$80,$81,$7F] 'Contrast control
pause 10
i2cwrite sda,scl,control,[$80,$A4] 'Entire display OFF
pause 10
i2cwrite sda,scl,control,[$80,$A6] 'Normal display
pause 10
i2cwrite sda,scl,control,[$80,$A3,$00,$40] 'Set vertical scroll
pause 10
i2cwrite sda,scl,control,[$80,$20,$00] 'Horizontal addressing mode
' i2cwrite sda,scl,control,[$80,$20,$01] 'Vertical addressing mode
RETURN

elcrcp
- 15th June 2015, 15:57
Thank you so much, I'm able to drive the screen and light up any pixel I want on screen. I think I was misusing i2cwrite command on my code. Now its ok.
Here is my trial code for blinking any line on the screen.



'==========================MCU SETUP============================================
Include "modedefs.bas"
DEFINE OSC 16
DEFINE I2C_SLOW 1 'Used to work with 100KHz devicez when using over 4MHz (my screen working without this too)
DEFINE I2C_HOLD 1 'Holding Lines low when not sending data (not necessary)

OPTION_REG=0
ADCON0=0
ADCON1=7
TRISA=%00111111
TRISB=%00000001
TRISC=0
PORTC=$FF

'==============================Variables========== =============================

I2CDevice var byte
SCL var PortC.3 ' I2C Clock PortC.3
SDA var PortC.4 ' I2C Data PortC.4
DC VAR byte' "DATA OR COMMAND", $40=DATA; $80=COMMAND
LCD_DATA VAR BYTE
COM VAR BYTE' COMMAND


I VAR BYTE
J VAR BYTE
X VAR BYTE' LCD Column POSITION (0 TO 127)
Y VAR BYTE'LCD Line POSITION FOR PAGE MODE(0 TO 7)
CLEAR
'================================================= ============================
I2CDevice = $78 ' Display = $78,
PAUSE 20
'=========================lcd initialization====================================
INIT:
I2CWrite SDA,SCL,I2CDevice,[DC,$AE]'Display Off
pause 10
I2CWrite SDA,SCL,I2CDevice,[DC,$20,$10]' Page adressing mode
I2CWrite SDA,SCL,I2CDevice,[DC,$D3,$00]' Set offset to 0
I2CWrite SDA,SCL,I2CDevice,[DC,$40]' Set display start line 0
I2CWrite SDA,SCL,I2CDevice,[DC,$81,$FF]' Set contrast to full
I2CWrite SDA,SCL,I2CDevice,[DC,$A4]' display on continue
I2CWrite SDA,SCL,I2CDevice,[DC,$A6]' $A6=NORMAL MODE;$A7=INVERSE MODE
I2CWrite SDA,SCL,I2CDevice,[DC,$A1]' set column 127 as start
i2cwrite sda,scl,I2CDevice,[DC,$C8]'Flip display vertically ****
'above 2 lines for arranging screen direction, deleting them will
'turn the display direction 180 degree
I2CWrite SDA,SCL,I2CDevice,[DC,$AF]'Display On
pause 10
'================================================= ==============================
GOSUB CLEAR_LCD
pause 500
GOSUB TITLE


MAIN:

'gosub FILL_LINE
'pause 1000
'gosub CLEAR_LCD
'pause 1000

GOTO MAIN

'======================Send data============================================== =
SEND_DATA:
DC=$40
I2CWrite SDA,SCL,I2CDevice,[DC,LCD_DATA]
RETURN
'================================================= ==============================
'======================Send Command=========================================== ==
SEND_COMMAND:
DC=$80
I2CWrite SDA,SCL,I2CDevice,[DC,COM]
RETURN
'================================================= ==============================

'==============================clear lcd========================================
CLEAR_LCD:
X=0
Y=0
LCD_DATA=$00
'Send 0 to every column in every line
FOR Y=0 TO 7
gosub SET_XY
FOR I=0 TO 127
GOSUB SEND_DATA
NEXT I
NEXT Y
RETURN

'=============================FILL_LINE=========== ==============================
FILL_LINE:
X=0
Y=4 'I choose 4.th line to blink
LCD_DATA=$FF ' Every line contains pixels $01 is bottom pixel, $80 is top pixel
gosub SET_XY
FOR I=0 TO 127
GOSUB SEND_DATA
NEXT I
RETURN
'================================================= ==============================

'===========================================SET X AND Y=========================
SET_XY:
COM=$21:GOSUB SEND_COMMAND
COM=X:GOSUB SEND_COMMAND
COM=127:GOSUB SEND_COMMAND
'Above 3 lines means; Column starts at X and End at 127
COM=$22:GOSUB SEND_COMMAND
COM=Y:GOSUB SEND_COMMAND
COM=Y:GOSUB SEND_COMMAND
'Above 3 lines means; Line starts at Y and end at Y,
'which means ; Only work on specified line!
RETURN
'================================================= ==============================
END

elcrcp
- 16th June 2015, 15:38
Hi guys, I again thank you for your code examples Sherbrook. Now I completed my codes and I think they can be helpful.
Anyway I wanted to share my codes for others too. Maybe someone can improve and chage them into a include file.

By the way, is it possible to use a variable's content in a lookup table? I'll try to print out variable contents on screen but I'm not sure the way right now. I think I'll open a new thread for this =)



'This code is for driving an OLED screen
'My screen was 0.96" 128x64 B/W SSD1306 chip with I2C protocol
'I used a 16f877a, you must change definitions and register settings due to
'your hardware.
'This code have a large char library in it, so it takes some memory, you may
'delete some of chars you won't use if you need some space for your program
'My codes don't include bitmap drawing I only intended to write texts on screen
'So if you want to draw bitmap, you must alter printing codes.
'Now
'Screen contains 8 lines (which are 8 pixel height) and 128 columns
'there are 1 printout subroutine for each Line, Simply change the X value on
'that line's subroutine and your text will start from that column.
'There also 8 text sobroutines which are contains text for each line, you can
'write your text on these subroutines, but !!!REMEMBER!!! to change the first
'value of lookup table to number of chars u used in your text.


'==========================MCU SETUP============================================
DEFINE OSC 16
OPTION_REG=0
ADCON0=0
ADCON1=7
TRISA=%00111111
TRISB=%00000001
TRISC=0
PORTC=$FF

'==============================BAUD SETUP=======================================

I2CDevice var byte
SCL var PortC.3 ' I2C Clock PortC.3
SDA var PortC.4 ' I2C Data PortC.4
DC VAR byte' "DATA OR COMMAND", $40=DATA; $80=COMMAND
LCD_DATA VAR BYTE
COM VAR BYTE'COMMAND
X VAR BYTE' LCD Column POSITION (0 TO 127)
Y VAR BYTE'LCD Line POSITION FOR PAGE MODE(0 TO 7)
I var byte
charset var byte 'Char codes index
say var byte 'counter
text_reg var byte 'index for text
letter_reg var byte 'data carrier for text chars
letter_count var byte 'count of letters in your text
CLEAR
'================================================= ============================
I2CDevice = $78 ' Display = $78,
PAUSE 20
'=========================lcd initialization====================================
INIT:
I2CWrite SDA,SCL,I2CDevice,[DC,$AE]'Display Off
pause 10
I2CWrite SDA,SCL,I2CDevice,[DC,$20,$10]' Page adressing mode
I2CWrite SDA,SCL,I2CDevice,[DC,$D3,$00]' Set offset to 0
I2CWrite SDA,SCL,I2CDevice,[DC,$40]' Set display start line 0
I2CWrite SDA,SCL,I2CDevice,[DC,$81,$FF]' Set contrast to full
I2CWrite SDA,SCL,I2CDevice,[DC,$A4]' display on continue
I2CWrite SDA,SCL,I2CDevice,[DC,$A6]' $A6=NORMAL MODE;$A7=INVERSE MODE
I2CWrite SDA,SCL,I2CDevice,[DC,$A1]' set column 127 as start
i2cwrite sda,scl,I2CDevice,[DC,$C8]'Flip display vertically ****
'above 2 lines for arranging screen direction, deleting them will
'turn the display direction 180 degree
I2CWrite SDA,SCL,I2CDevice,[DC,$AF]'Display On
pause 10
'================================================= ==============================
GOSUB CLEAR_LCD
pause 500

MAIN:

gosub Print_Line_0
gosub Print_Line_1
gosub Print_Line_2
gosub Print_Line_3
gosub Print_Line_4
'gosub Print_Line_5 'You can comment out the lines you don't want to use
'gosub Print_Line_6
'gosub Print_Line_7

sleep 5

GOTO MAIN

'=============================Text to Write=====================================
Line_0:
lookup text_reg,[4,"Test"],letter_reg' first data is number of chars in your
'text
return

Line_1:
lookup text_reg,[9,"Test teST"],letter_reg' first data is number of chars in your
'text
return

Line_2:
lookup text_reg,[7,"T e s t"],letter_reg' first data is number of chars in your
'text
return

Line_3:
lookup text_reg,[8,"%]Test{-"],letter_reg' first data is number of chars in your
'text
return

Line_4:
lookup text_reg,[7,"Hop Hop"],letter_reg' first data is number of chars in your
'text
return

Line_5:
lookup text_reg,[4,"Test"],letter_reg' first data is number of chars in your
'text
return

Line_6:
lookup text_reg,[4,"Test"],letter_reg' first data is number of chars in your
'text
return

Line_7:
lookup text_reg,[4,"Test"],letter_reg' first data is number of chars in your
'text
return

'======================Print Lines============================================= =
Print_Line_0:
X=0 'You can change this value to set starting column
Y=0 'Don't change this line
gosub SET_XY
gosub Line_0
letter_count=letter_reg
text_reg=text_reg+1
for say=1 to letter_count
gosub Line_0
gosub Find_Char
text_reg=text_reg+1
next say
text_reg=0
return

Print_Line_1:
X=10 'You can change this value to set starting column
Y=1 'Don't change this line
gosub SET_XY
gosub Line_1
letter_count=letter_reg
text_reg=text_reg+1
for say=1 to letter_count
gosub Line_1
gosub Find_Char
text_reg=text_reg+1
next say
text_reg=0
return

Print_Line_2:
X=20 'You can change this value to set starting column
Y=2 'Don't change this line
gosub SET_XY
gosub Line_2
letter_count=letter_reg
text_reg=text_reg+1
for say=1 to letter_count
gosub Line_2
gosub Find_Char
text_reg=text_reg+1
next say
text_reg=0
return

Print_Line_3:
X=30 'You can change this value to set starting column
Y=3 'Don't change this line
gosub SET_XY
gosub Line_3
letter_count=letter_reg
text_reg=text_reg+1
for say=1 to letter_count
gosub Line_3
gosub Find_Char
text_reg=text_reg+1
next say
text_reg=0
return

Print_Line_4:
X=40 'You can change this value to set starting column
Y=4 'Don't change this line
gosub SET_XY
gosub Line_4
letter_count=letter_reg
text_reg=text_reg+1
for say=1 to letter_count
gosub Line_4
gosub Find_Char
text_reg=text_reg+1
next say
text_reg=0
return

Print_Line_5:
X=50 'You can change this value to set starting column
Y=5 'Don't change this line
gosub SET_XY
gosub Line_5
letter_count=letter_reg
text_reg=text_reg+1
for say=1 to letter_count
gosub Line_5
gosub Find_Char
text_reg=text_reg+1
next say
text_reg=0
return

Print_Line_6:
X=60 'You can change this value to set starting column
Y=6 'Don't change this line
gosub SET_XY
gosub Line_6
letter_count=letter_reg
text_reg=text_reg+1
for say=1 to letter_count
gosub Line_6
gosub Find_Char
text_reg=text_reg+1
next say
text_reg=0
return

Print_Line_7:
X=55 'You can change this value to set starting column
Y=7 'Don't change this line
gosub SET_XY
gosub Line_7
letter_count=letter_reg
text_reg=text_reg+1
for say=1 to letter_count
gosub Line_7
gosub Find_Char
text_reg=text_reg+1
next say
text_reg=0
return
'================================================= ==============================

'=======================Send data============================================== =
SEND_DATA:
DC=$40
I2CWrite SDA,SCL,I2CDevice,[DC,LCD_DATA]
RETURN
'================================================= ==============================
'======================Send Command=========================================== ==
SEND_COMMAND:
DC=$80
I2CWrite SDA,SCL,I2CDevice,[DC,COM]
RETURN
'================================================= ==============================

'==============================clear lcd========================================
CLEAR_LCD:
X=0
Y=0
LCD_DATA=$00
'Send 0 to every column in every line
FOR Y=0 TO 7
gosub SET_XY
FOR I=0 TO 127
GOSUB SEND_DATA
NEXT I
NEXT Y
X=0
Y=0
gosub SET_XY
RETURN
'=============================Find Char=========================================
Find_Char:
select case letter_reg
case " "
for charset=0 to 5
lookup charset,[$00,$00,$00,$00,$00,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "!"
for charset=0 to 5
lookup charset,[$00,$00,$5F,$00,$00,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "#"
for charset=0 to 5
lookup charset,[$14,$7F,$14,$7F,$14,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "$"
for charset=0 to 5
lookup charset,[$24,$2A,$7F,$2A,$12,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "%"
for charset=0 to 5
lookup charset,[$23,$13,$08,$64,$62,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "&"
for charset=0 to 5
lookup charset,[$36,$49,$56,$20,$50,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "'"
for charset=0 to 5
lookup charset,[$00,$08,$07,$03,$00,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "("
for charset=0 to 5
lookup charset,[$00,$1C,$22,$41,$00,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case ")"
for charset=0 to 5
lookup charset,[$00,$41,$22,$1C,$00,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "*"
for charset=0 to 5
lookup charset,[$2A,$1C,$7F,$1C,$2A,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "+"
for charset=0 to 5
lookup charset,[$08,$08,$3E,$08,$08,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case ","
for charset=0 to 5
lookup charset,[$00,$00,$70,$30,$00,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "-"
for charset=0 to 5
lookup charset,[$08,$08,$08,$08,$08,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "."
for charset=0 to 5
lookup charset,[$00,$00,$60,$60,$00,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "/"
for charset=0 to 5
lookup charset,[$20,$10,$08,$04,$02,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "0"
for charset=0 to 5
lookup charset,[$3E,$51,$49,$45,$3E,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "1"
for charset=0 to 5
lookup charset,[$00,$42,$7F,$40,$00,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "2"
for charset=0 to 5
lookup charset,[$72,$49,$49,$49,$46,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "3"
for charset=0 to 5
lookup charset,[$21,$41,$49,$4D,$33,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "4"
for charset=0 to 5
lookup charset,[$18,$14,$12,$7F,$10,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "5"
for charset=0 to 5
lookup charset,[$27,$45,$45,$45,$39,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "6"
for charset=0 to 5
lookup charset,[$3C,$4A,$49,$49,$31,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "7"
for charset=0 to 5
lookup charset,[$41,$21,$11,$09,$07,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "8"
for charset=0 to 5
lookup charset,[$36,$49,$49,$49,$36,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "9"
for charset=0 to 5
lookup charset,[$46,$49,$49,$29,$1E,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case ":"
for charset=0 to 5
lookup charset,[$00,$00,$14,$00,$00,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case ";"
for charset=0 to 5
lookup charset,[$00,$40,$34,$00,$00,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "<"
for charset=0 to 5
lookup charset,[$00,$08,$14,$22,$41,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "="
for charset=0 to 5
lookup charset,[$14,$14,$14,$14,$14,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case ">"
for charset=0 to 5
lookup charset,[$00,$41,$22,$14,$08,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "?"
for charset=0 to 5
lookup charset,[$02,$01,$59,$09,$06,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "@"
for charset=0 to 5
lookup charset,[$3E,$41,$5D,$59,$4E,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "A"
for charset=0 to 5
lookup charset,[$7C,$12,$11,$12,$7C,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "B"
for charset=0 to 5
lookup charset,[$7F,$49,$49,$49,$36,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "C"
for charset=0 to 5
lookup charset,[$3E,$41,$41,$41,$22,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "D"
for charset=0 to 5
lookup charset,[$7F,$41,$41,$41,$3E,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "E"
for charset=0 to 5
lookup charset,[$7F,$49,$49,$49,$41,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "F"
for charset=0 to 5
lookup charset,[$7F,$09,$09,$09,$01,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "G"
for charset=0 to 5
lookup charset,[$3E,$41,$41,$51,$73,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "H"
for charset=0 to 5
lookup charset,[$7F,$08,$08,$08,$7F,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "I"
for charset=0 to 5
lookup charset,[$00,$41,$7F,$41,$00,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "J"
for charset=0 to 5
lookup charset,[$20,$40,$41,$3F,$01,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "K"
for charset=0 to 5
lookup charset,[$7F,$08,$14,$22,$41,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "L"
for charset=0 to 5
lookup charset,[$7F,$40,$40,$40,$40,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "M"
for charset=0 to 5
lookup charset,[$7F,$02,$1C,$02,$7F,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "N"
for charset=0 to 5
lookup charset,[$7F,$04,$08,$10,$7F,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "O"
for charset=0 to 5
lookup charset,[$3E,$41,$41,$41,$3E,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "P"
for charset=0 to 5
lookup charset,[$7F,$09,$09,$09,$06,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "Q"
for charset=0 to 5
lookup charset,[$3E,$41,$51,$21,$5E,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "R"
for charset=0 to 5
lookup charset,[$7F,$09,$19,$29,$46,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "S"
for charset=0 to 5
lookup charset,[$26,$49,$49,$49,$32,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "T"
for charset=0 to 5
lookup charset,[$03,$01,$7F,$01,$03,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "U"
for charset=0 to 5
lookup charset,[$3F,$40,$40,$40,$3F,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "V"
for charset=0 to 5
lookup charset,[$1F,$20,$40,$20,$1F,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "W"
for charset=0 to 5
lookup charset,[$3F,$40,$38,$40,$3F,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "X"
for charset=0 to 5
lookup charset,[$63,$14,$08,$14,$63,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "Y"
for charset=0 to 5
lookup charset,[$03,$04,$78,$04,$03,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "Z"
for charset=0 to 5
lookup charset,[$61,$59,$49,$4D,$43,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "["
for charset=0 to 5
lookup charset,[$00,$7F,$41,$41,$41,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "\"
for charset=0 to 5
lookup charset,[$02,$04,$08,$10,$20,$00 ],LCD_DATA
gosub SEND_DATA
next charset
return
case "]"
for charset=0 to 5
lookup charset,[$00,$41,$41,$41,$7F,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "^"
for charset=0 to 5
lookup charset,[$04,$02,$01,$02,$04,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "_"
for charset=0 to 5
lookup charset,[$40,$40,$40,$40,$40,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "`"
for charset=0 to 5
lookup charset,[$00,$03,$07,$08,$00,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "a"
for charset=0 to 5
lookup charset,[$20,$54,$54,$38,$40,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "b"
for charset=0 to 5
lookup charset,[$7F,$28,$44,$44,$38,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "c"
for charset=0 to 5
lookup charset,[$38,$44,$44,$44,$28,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "d"
for charset=0 to 5
lookup charset,[$38,$44,$44,$28,$7F,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "e"
for charset=0 to 5
lookup charset,[$38,$54,$54,$54,$18,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "f"
for charset=0 to 5
lookup charset,[$00,$08,$7E,$09,$02,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "g"
for charset=0 to 5
lookup charset,[$0C,$52,$52,$4A,$3C,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "h"
for charset=0 to 5
lookup charset,[$7F,$08,$04,$04,$78,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "i"
for charset=0 to 5
lookup charset,[$00,$44,$7D,$40,$00,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "j"
for charset=0 to 5
lookup charset,[$20,$40,$40,$3D,$00,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "k"
for charset=0 to 5
lookup charset,[$7F,$10,$28,$44,$00,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "l"
for charset=0 to 5
lookup charset,[$00,$41,$7F,$40,$00,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "m"
for charset=0 to 5
lookup charset,[$7C,$04,$78,$04,$78,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "n"
for charset=0 to 5
lookup charset,[$7C,$08,$04,$04,$78,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "o"
for charset=0 to 5
lookup charset,[$38,$44,$44,$44,$38,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "p"
for charset=0 to 5
lookup charset,[$7C,$18,$24,$24,$18,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "q"
for charset=0 to 5
lookup charset,[$18,$24,$24,$18,$7C,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "r"
for charset=0 to 5
lookup charset,[$7C,$08,$04,$04,$08,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "s"
for charset=0 to 5
lookup charset,[$48,$54,$54,$54,$24,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "t"
for charset=0 to 5
lookup charset,[$04,$04,$3F,$44,$24,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "u"
for charset=0 to 5
lookup charset,[$3C,$40,$40,$20,$7C,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "v"
for charset=0 to 5
lookup charset,[$1C,$20,$40,$20,$1C,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "w"
for charset=0 to 5
lookup charset,[$3C,$40,$30,$40,$3C,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "x"
for charset=0 to 5
lookup charset,[$44,$28,$10,$28,$44,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "y"
for charset=0 to 5
lookup charset,[$4C,$50,$50,$50,$3C,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "z"
for charset=0 to 5
lookup charset,[$44,$64,$54,$4C,$44,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "{"
for charset=0 to 5
lookup charset,[$00,$08,$36,$41,$00,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "|"
for charset=0 to 5
lookup charset,[$00,$00,$77,$00,$00,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "}"
for charset=0 to 5
lookup charset,[$00,$41,$36,$08,$00,$00],LCD_DATA
gosub SEND_DATA
next charset
return
case "~"
for charset=0 to 5
lookup charset,[$02,$01,$02,$04,$02,$00],LCD_DATA
gosub SEND_DATA
next charset
return
end select
return
'================================================= ==============================
'=========================CHAR_SET================ ==============================

'===========================================SET X AND Y=========================
SET_XY:
COM=$21:GOSUB SEND_COMMAND
COM=X:GOSUB SEND_COMMAND
COM=127:GOSUB SEND_COMMAND
'Above 3 lines means; Column starts at X and End at 127
COM=$22:GOSUB SEND_COMMAND
COM=Y:GOSUB SEND_COMMAND
COM=Y:GOSUB SEND_COMMAND
'Above 3 lines means; Line starts at Y and end at Y,
'which means ; Only work on specified line!
RETURN
'================================================= ==============================
END

CuriousOne
- 19th June 2015, 11:20
Using above code, I've tried to use this display with 16F870:

http://www.ebay.com/itm/221727746237?_trksid=p2057872.m2749.l2649&ssPageName=STRK%3AMEBIDX%3AIT

But it does not works:



'************************************************* ***************
'* Name : UNTITLED.BAS *
'* Author : [select VIEW...EDITOR OPTIONS] *
'* Notice : Copyright (c) 2014 [select VIEW...EDITOR OPTIONS] *
'* : All Rights Reserved *
'* Date : 07.02.2014 *
'* Version : 1.0 *
'* Notes : *
'* : *
'************************************************* ***************

Include "modedefs.bas" ' Include serial modes
TRISA = %11111111 ' Set PORTA to all input
TRISC = %00000000 ' Sets all PortB pins to output
ADCON1 = %10001001 ' Set PORTA analog and right justify result
ADCON0=%00000000
low portc.4
low portc.5

DEFINE LCD_DREG PORTB
DEFINE LCD_DBIT 4
DEFINE LCD_RSREG PORTB
DEFINE LCD_RSBIT 0
DEFINE LCD_EREG PORTB
DEFINE LCD_EBIT 1
DEFINE LCD_BITS 4
DEFINE LCD_LINES 2
DEFINE LCD_COMMANDUS 1500
DEFINE LCD_DATAUS 44
DEFINE OSC 4

'==========================MCU SETUP============================================


'DEFINE I2C_SLOW 1 'Used to work with 100KHz devicez when using over 4MHz (my screen working without this too)
'DEFINE I2C_HOLD 1 'Holding Lines low when not sending data (not necessary)

OPTION_REG=0
ADCON0=0
ADCON1=7
TRISB=%00000001
trisc = %11111111 'PortC 0, 1, 2 outputs
PortC = %00110000 'scl & sda high to start


led var portC.0
scl var PortC.4
sda var PortC.5
dat var byte
counter var word

control con %01111000 'I2C slave address (write mode)

pause 500



pause 2000
gosub RESET:
gosub init_oled:
i2cwrite sda,scl,control,[$78,$AF] 'Display ON
pause 10

Start:

led = 1 'Code running
i2cwrite sda,scl,control,[$78,$A7] 'Inverse Display
pause 500
i2cwrite sda,scl,control,[$78,$A6] 'Normal Display
pause 20
' i2cwrite sda,scl,control,[$78,$21,$00,$40] 'Set columns
pause 20
' i2cwrite sda,scl,control,[$78,$22,$00,$04] 'Set pages
pause 500
for counter = 0 to 1023
i2cwrite sda,scl,control,[$40,$FF]
next
led = 0 'Code running
for counter = 0 to 1023
lcdout $fe,$C0, #counter, " main "
i2cwrite sda,scl,control,[$40,$00]
next
GOTO Start:

INIT_OLED:
lcdout $fe,$C0, "init "
i2cwrite sda,scl,control,[$78,$AE] 'Display OFF ****
pause 1
i2cwrite sda,scl,control,[$78,$2E] 'Deactivate scrolling
pause 1
i2cwrite sda,scl,control,[$78,$20,$10] 'Page addressing mode ****
pause 1
i2cwrite sda,scl,control,[$78,$A0] ' ****
' i2cwrite sda,scl,control,[$78,$A1] ' ****
pause 1
i2cwrite sda,scl,control,[$78,$A6] 'WHITE chars BLACK backround
' i2cwrite sda,scl,control,[$78,$A7] 'BLACK chars WHITE backround
pause 1
i2cwrite sda,scl,control,[$78,$81,$7F] 'Setup contrast XXXX
pause 1
i2cwrite sda,scl,control,[$78,$AF] 'Display on ****
pause 1
i2cwrite sda,scl,control,[$78,$40]
pause 1
' i2cwrite sda,scl,control,[$78,$C0] 'Flip display vertically ****
i2cwrite sda,scl,control,[$78,$C8] 'Flip display vertically ****
pause 1
' i2cwrite sda,scl,control,[$78,$A0] ' ****
i2cwrite sda,scl,control,[$78,$A1] ' ****
pause 1
i2cwrite sda,scl,control,[$78,$00,$78,$10] 'Set column start address ****
pause 1
i2cwrite sda,scl,control,[$78,$B0] 'Set page start address ****
pause 1
return

RESET:
i2cwrite sda,scl,control,[$78,$AE] 'Display OFF
pause 10
I2Cwrite sda,scl,control,[$78,$20,$02] 'Page addressing mode
pause 10
i2cwrite sda,scl,control,[$78,$B0] 'Page start address
pause 10
i2cwrite sda,scl,control,[$78,$00,$78,$10] 'Set column start address
pause 10
i2cwrite sda,scl,control,[$78,$A0] 'Address 0 mapped to SEG 0
pause 10
' i2cwrite sda,scl,control,[$78,$A1] 'Address 0 mapped to SEG 127
pause 10
i2cwrite sda,scl,control,[$78,$D3,$00] 'Display offset
pause 10

pause 10
i2cwrite sda,scl,control,[$78,$40] 'Display start line
Pause 10
i2cwrite sda,scl,control,[$78,$C0] 'Output scan direction
pause 10
i2cwrite sda,scl,control,[$78,$A6] 'WHITE chars BLACK backround
pause 10
i2cwrite sda,scl,control,[$78,$81,$7F] 'Contrast control
pause 10
i2cwrite sda,scl,control,[$78,$A4] 'Entire display OFF
pause 10
i2cwrite sda,scl,control,[$78,$A6] 'Normal display
pause 10
i2cwrite sda,scl,control,[$78,$A3,$00,$40] 'Set vertical scroll
pause 10
i2cwrite sda,scl,control,[$78,$20,$00] 'Horizontal addressing mode
' i2cwrite sda,scl,control,[$78,$20,$01] 'Vertical addressing mode
RETURN


The initial address was $80, so I've changed it to $78, as shown on picture of the OLED itself.

elcrcp
- 20th June 2015, 11:17
It is same oled I used. First of all, sending 00 and FF for seeing empty and full screen won't work try 00 and 0F. I think ssd1306 outputs are not able to drive all leds at same time. Secondly, your mcu setup is in a mess, you are setting trises and adcons 2 times and differently. Plus, you should set portc.4 and 5 as outputs since PIC is master here, you are setting them inputs in these codes. Both your RESET and INIT subroutines are actually INIT routunies, Sending wrong commands may interrupt oled's working, keep them simple and use only 1 INIT routine(you can use same routine as reset) You may use these codes as init.

'=========================lcd initialization====================================
INIT:
I2CWrite SDA,SCL,I2CDevice,[DC,$AE]'Display Off
pause 10
I2CWrite SDA,SCL,I2CDevice,[DC,$20,$10]' Page adressing mode
I2CWrite SDA,SCL,I2CDevice,[DC,$D3,$00]' Set offset to 0
I2CWrite SDA,SCL,I2CDevice,[DC,$40]' Set display start line 0
I2CWrite SDA,SCL,I2CDevice,[DC,$81,$FF]' Set contrast to full
I2CWrite SDA,SCL,I2CDevice,[DC,$A4]' display on continue
I2CWrite SDA,SCL,I2CDevice,[DC,$A6]' $A6=NORMAL MODE;$A7=INVERSE MODE
I2CWrite SDA,SCL,I2CDevice,[DC,$A1]' set column 127 as start
i2cwrite sda,scl,I2CDevice,[DC,$C8]'Flip display vertically ****
'above 2 lines for arranging screen direction, deleting them will
'turn the display direction 180 degree
I2CWrite SDA,SCL,I2CDevice,[DC,$AF]'Display On
pause 10
'================================================= ==============================
You don't need to send control commands in your main routine unless you want to really control the screen, delete them. Put some delay after sending 00 / 0f to screen,

Aaannnd last of all, before entering my comment, I checked 16f870's datasheet for SDA SCL pins but I couldn't see I2C support in device specs. I don't know if you can use I2CWrite command with that model.

CuriousOne
- 23rd June 2015, 09:23
Thanks, I will try with PIC16F876A, which has hardware I2C capabilities.

timc
- 17th July 2015, 04:01
Been working on a new char table for the OLED. Problem is the LOOKUP command can only take 255 bytes. This new routine can replace the one from elcrcp above. I have added a few new variables:


'charset var byte 'Char codes index
charset var word 'Char codes index
chartmp var byte 'char codes index temp
letter_temp var byte ' working copy


Just change Find_Char to Find_Char2


'=============================Find Char 2=======================================
Find_Char2:
' Enter this Subroutine with printable character: letter_reg
' letter_reg is subtracted from " " (space char) and * by 5 to be able to index into one table
' One table is broken into 3 to avoid the 255 max. Index into table must be a byte variable.

letter_temp = letter_reg - 32 ' Space is now at index 0 all other characters are 32 less into index
letter_temp = letter_temp * 5 ' Every character is made of 5 bytes
for charset=letter_temp to letter_temp+4
IF letter_reg < "A" then
chartmp = charset - 0 ' lookup variable must be 8 bits
lookup chartmp,[$00,$00,$00,$00,$00,$00,$00,$5F,$00,$00,$14,$7F,$1 4,$7F,$14,$00,$08,$07,$03,$00,_ 'sp,!,#,"
$24,$2A,$7F,$2A,$12,$23,$13,$08,$64,$62,$36,$49,$5 6,$20,$50,_ '$,%,&
$00,$08,$07,$03,$00,$00,$1C,$22,$41,$00,$00,$41,$2 2,$1C,$00,_ '',(,)
$2A,$1C,$7F,$1C,$2A,$08,$08,$3E,$08,$08,$00,$00,$7 0,$30,$00,_ '*,+,,
$08,$08,$08,$08,$08,$00,$00,$60,$60,$00,$20,$10,$0 8,$04,$02,_ '-,.,/
$3E,$51,$49,$45,$3E,$00,$42,$7F,$40,$00,$72,$49,$4 9,$49,$46,_ '0,1,2
$21,$41,$49,$4D,$33,$18,$14,$12,$7F,$10,$27,$45,$4 5,$45,$39,_ '3,4,5
$3C,$4A,$49,$49,$31,$41,$21,$11,$09,$07,$36,$49,$4 9,$49,$36,_ '6,7,8
$46,$49,$49,$29,$1E,$00,$00,$14,$00,$00,$00,$40,$3 4,$00,$00,_ '9,:,;
$00,$08,$14,$22,$41,$14,$14,$14,$14,$14,$00,$41,$2 2,$14,$08,_ '<,=,>
$02,$01,$59,$09,$06,$3E,$41,$5D,$59,$4E],LCD_DATA '?,@
elseif (letter_reg < "[") then
chartmp = charset - 165 ' subtract previous table length so "A" = zero
lookup chartmp,[$7C,$12,$11,$12,$7C,_ 'A
$7F,$49,$49,$49,$36,$3E,$41,$41,$41,$22,$7F,$41,$4 1,$41,$3E,_ 'B,C,D
$7F,$49,$49,$49,$41,$7F,$09,$09,$09,$01,$3E,$41,$4 1,$51,$73,_ 'E,F,G
$7F,$08,$08,$08,$7F,$00,$41,$7F,$41,$00,$20,$40,$4 1,$3F,$01,_ 'H,I,J
$7F,$08,$14,$22,$41,$7F,$40,$40,$40,$40,$7F,$02,$1 C,$02,$7F,_ 'K,L,M
$7F,$04,$08,$10,$7F,$3E,$41,$41,$41,$3E,$7F,$09,$0 9,$09,$06,_ 'N,O,P
$3E,$41,$51,$21,$5E,$7F,$09,$19,$29,$46,$26,$49,$4 9,$49,$32,_ 'Q,R,S
$03,$01,$7F,$01,$03,$3F,$40,$40,$40,$3F,$1F,$20,$4 0,$20,$1F,_ 'T,U,V
$3F,$40,$38,$40,$3F,$63,$14,$08,$14,$63,$03,$04,$7 8,$04,$03,_ 'W,X,Y
$61,$59,$49,$4D,$43],LCD_DATA 'Z
else
chartmp = charset - 295 ' subtract previous tables length so "[" = zero
lookup chartmp,[$00,$7F,$41,$41,$41,$02,$04,$08,$10,$20,_ '[,\
$00,$41,$41,$41,$7F,$04,$02,$01,$02,$04,$40,$40,$4 0,$40,$40,_ '],^,_
$00,$03,$07,$08,$00,$20,$54,$54,$38,$40,$7F,$28,$4 4,$44,$38,_ '`,a,b
$38,$44,$44,$44,$28,$38,$44,$44,$28,$7F,$38,$54,$5 4,$54,$18,_ 'c,d,e
$00,$08,$7E,$09,$02,$0C,$52,$52,$4A,$3C,$7F,$08,$0 4,$04,$78,_ 'f,g,h
$00,$44,$7D,$40,$00,$20,$40,$40,$3D,$00,$7F,$10,$2 8,$44,$00,_ 'i,j,k
$00,$41,$7F,$40,$00,$7C,$04,$78,$04,$78,$7C,$08,$0 4,$04,$78,_ 'l,m,n
$38,$44,$44,$44,$38,$7C,$18,$24,$24,$18,$18,$24,$2 4,$18,$7C,_ 'o,p,q
$7C,$08,$04,$04,$08,$48,$54,$54,$54,$24,$04,$04,$3 F,$44,$24,_ 'r,s,t
$3C,$40,$40,$20,$7C,$1C,$20,$40,$20,$1C,$3C,$40,$3 0,$40,$3C,_ 'u,v,w
$44,$28,$10,$28,$44,$4C,$50,$50,$50,$3C,$44,$64,$5 4,$4C,$44,_ 'x,y,z
$00,$08,$36,$41,$00,$00,$00,$77,$00,$00,$00,$41,$3 6,$08,$00,_ '{,|,}
$02,$01,$02,$04,$02],LCD_DATA '~
endif
gosub SEND_DATA
next charset
LCD_DATA = $00 ' space between characters always $00
gosub SEND_DATA
return

'================================================= ==============================



IDE says this compiles in less than 4K so I tried the 16F877 and that compiles as well.
Regards
TimC

timc
- 17th July 2015, 05:51
The INIT routine is critical and no single INIT routine will work for all SSD1306 displays. If you get your display to work in under an hour consider yourself lucky. This INIT routine can replace the one from elcrcp above if your display did not work. I have tried this same "routine" for both PIC's, AVR's and in Basic and C.
Regards
TimC




'================== SSD1306 I2C OLED initialization ======================
INIT:
I2CWrite SDA,SCL,I2CDevice,[DC,$AE]'Display OFF
I2CWrite SDA,SCL,I2CDevice,[DC,$D3,$00]' Set offset to 0
'I2CWrite SDA,SCL,I2CDevice,[DC,$40]' Set display start line 0, usually not needed
I2CWrite SDA,SCL,I2CDevice,[DC,$8D,$14]' Set Charge Pump Internal, USUALLY needed
I2CWrite SDA,SCL,I2CDevice,[DC,$20,$10]' Adressing mode $10=Page, $00=Horizontal
I2CWrite SDA,SCL,I2CDevice,[DC,$A1]' set segment remap column 127 as start
i2cwrite sda,scl,I2CDevice,[DC,$C8]' Com Scan Direction, Flip display vertically
i2cwrite sda,scl,I2CDevice,[DC,$DA,$12]' set COM pins = 128x64=$12 128x32=$02
I2CWrite SDA,SCL,I2CDevice,[DC,$81,$7F]' Set contrast to $01 to $FF ($7F is default, $01 is faint)
I2CWrite SDA,SCL,I2CDevice,[DC,$A4]' display ON continue
I2CWrite SDA,SCL,I2CDevice,[DC,$A6]' $A6=NORMAL MODE; $A7=INVERSE MODE
I2CWrite SDA,SCL,I2CDevice,[DC,$AF]'Display ON
' longer delay here because we need to see if display shows random bytes.
' If you see random bytes - your display and INIT are probably working!
pause 500 ' remove when you like


Wait what's DC? Well it should be $00 but I have read it might be $80. Is this why they are only $4 on EBAY?

elcrcp
- 17th July 2015, 11:49
Good question there timc
I realised that I forgot setting DC in init after some time.
Funny Fact: After I set DC to $80 for INIT routine, oled not worked properly (or maybe not worked at all, can't remember right now) while SET_XY routine working fine with DC $80. So actually I'm not sure if command mode is 00 or 80 but it's working this way :D

elcrcp
- 17th July 2015, 16:01
By the way TimC, your character table is clearly more efficient and Flash friendly. I will try it too when I have opportunity.
But I want to ask something first; I'm not sure how LOOKUP and LOOKUP2 commands treats different data types, so that is why I'm asking this, lets say I wrote;
"lookup2 variable,['string',variable2],variable3"
And variable 2 contains 7 as data.
Now, since string and variable2 are different data types, will this char table be able to recognize them both? I mean, is it working for both of '7' and 7 ?
I'm just asking because I really don't know the behavior of lookup commands for different data types.

timc
- 17th July 2015, 17:33
Personally I would not alternate different data types in a big character table because you want to make it as simple and small as possible. From the PBP manual it says: "Lookup2 generates code that is about 3 times larger then Lookup."
So I went back to Lookup. The only other reason that you might use Lookup2 is because it can address 1024 values. The new manual for V3 says Lookup can address 1024 values but it failed after "S" and before it reached "T" which is exactly 256 values.

Me thinks the V3.0.8 compiler has a bug!

timc
- 20th July 2015, 03:21
I posted a full demo of a SSD1306 add-in over on the code example forum. elcrcp I think this is what you were asking for earlier.
Best part is you can start to use it like a regular LCD with data from other devices and formatted output.

http://www.picbasic.co.uk/forum/showthread.php?t=20179

TimC

elcrcp
- 21st July 2015, 16:28
Yes TimC that is my answer =)
By the way, I tried your init suggestion and it's fine (I didn't know that upper limit of contrast was 7F) then I wanted to see your include file and sample code (good job you did there :) ) but I couldn't make it work don't know why, I'll examine them detailed later but they are definetly very useful and easy to work with.

timc
- 21st July 2015, 22:13
The Contrast Init line should read
Set contrast FROM $01 to $FF NOT Set contrast to $01 to $FF.
Therefore $FF is the upper limit.

Good luck

Alberto
- 20th July 2016, 09:29
Hi all, I did use the Timc code to drive a 0.96 '' oled display and it works fine (thank you Timc)
The only doubt now I have is the warning message I get compiling the code:

"ASM WARNING Argument out of range. Last significant bits used. (0) : Warninig [202]"

What does it mean?
How can I remove it?

Alberto

wellyboot
- 18th August 2016, 20:16
I bought a OLED display on ebay saying it had a SSD1306 chip, trying running some code from here and I got a display full of noise

Turns out it has SH1106 driver

I modified the code here to work with it on 18F877
this draws a box around the display


<code>

'OLED driver 16F877
'SH1106 driver
'NOT SSD1306

'==========================MCU SETUP============================================
Include "modedefs.bas"

DEFINE OSC 8


ADCON0=0
ADCON1=7
TRISA=%00111111
TRISB=%00000001
TRISC=0
TRISD=0
TRISE=0
PORTC=$FF

'==============================Variables========== =============================

I2CDevice var byte
SCL var PortC.3 ' I2C Clock PortC.3
SDA var PortC.4 ' I2C Data PortC.4
DC VAR byte' "DATA OR COMMAND", $40=DATA; $0=COMMAND
LCD_DATA VAR BYTE
COM VAR BYTE' COMMAND


I VAR BYTE
J VAR BYTE
X VAR BYTE' LCD Column POSITION (0 TO 127)
Y VAR BYTE'LCD Line POSITION FOR PAGE MODE(0 TO 7)
Xlow VAR BYTE 'Low 4 bits of X
Xhigh VAR BYTE 'High 4 bits of X
CLEAR
'================================================= ============================
I2CDevice = $78 ' Display = $78,
PAUSE 500
'=========================lcd initialization====================================
DC = 0
INIT:
I2CWrite SDA,SCL,I2CDevice,[DC,$AE]'Display Off
pause 10
I2CWrite SDA,SCL,I2CDevice,[DC,$D3,$00]' Set offset to 0
I2CWrite SDA,SCL,I2CDevice,[DC,$40]' Set display start line 0
I2CWrite SDA,SCL,I2CDevice,[DC,$8D,$14]' Set Charge Pump Internal, usually needed
'I2CWrite SDA,SCL,I2CDevice,[DC,$20,$10]' Page adressing mode
I2CWrite SDA,SCL,I2CDevice,[DC,$A1]' set column 0 as start
i2cwrite sda,scl,I2CDevice,[DC,$C8]'
I2CWrite SDA,SCL,I2CDevice,[DC,$DA,$12]' set COM pins = 128x64=$12 128x32=$02'
I2CWrite SDA,SCL,I2CDevice,[DC,$81,$01]' Set contrast to low
I2CWrite SDA,SCL,I2CDevice,[DC,$A4]' display on continue
I2CWrite SDA,SCL,I2CDevice,[DC,$A6]' $A6=NORMAL MODE;$A7=INVERSE MODE

I2CWrite SDA,SCL,I2CDevice,[DC,$AF]'Display On
pause 500




'================================================= ==============================
GOSUB CLEAR_LCD
pause 500



MAIN:

gosub CLEAR_LCD
pause 1000
gosub BOX1
pause 1000

GOTO MAIN

'======================Send data============================================== =
SEND_DATA:
DC=$40
I2CWrite SDA,SCL,I2CDevice,[DC,LCD_DATA]
RETURN
'================================================= ==============================
'======================Send Command=========================================== ==
SEND_COMMAND:
DC=0
I2CWrite SDA,SCL,I2CDevice,[DC,COM]
RETURN
'================================================= ==============================

'==============================clear lcd========================================
CLEAR_LCD:
X=2
Y=0
LCD_DATA=$00
'Send 0 to every column in every line
FOR Y=0 TO 7
gosub SET_XY
FOR I=0 TO 127
GOSUB SEND_DATA
NEXT I
NEXT Y
RETURN

'================================================= ==============================
BOX1:
FOR Y = 0 TO 7
X=2
GOSUB SET_XY
LCD_DATA=%11111111
GOSUB SEND_DATA
X=129
GOSUB SET_XY
GOSUB SEND_DATA
NEXT Y
FOR X = 3 TO 128
Y=0
GOSUB SET_XY
LCD_DATA=%00000001
GOSUB SEND_DATA
Y=7
GOSUB SET_XY
LCD_DATA=%10000000
GOSUB SEND_DATA
NEXT


RETURN

'===========================================SET X AND Y=========================
SET_XY:
COM = $B0
COM = COM + Y '<<<--- SET PAGE ADDRESS %1011DDDD
GOSUB SEND_COMMAND

Xhigh = X >> 4
Xlow = X &$0F
COM=Xlow '<<<--- SET COL ADDRESS LOW bits %0000DDDD
GOSUB SEND_COMMAND
Xhigh.4 = 1
COM = Xhigh '<<<--- SET COL ADDRESS HIGH bits %0001DDDD
GOSUB SEND_COMMAND

RETURN
'================================================= ==============================


END

</code>

Art
- 20th August 2016, 12:19
Probably this:


chartmp = charset - 295

char temp is a byte who’s maximum value is 255.
It will probably also break it if it was working, to fix it,
you’d probably have to rotate the values in the lookup table by some amount.



Hi all, I did use the Timc code to drive a 0.96 '' oled display and it works fine (thank you Timc)
The only doubt now I have is the warning message I get compiling the code:

"ASM WARNING Argument out of range. Last significant bits used. (0) : Warninig [202]"

What does it mean?
How can I remove it?

Alberto