PDA

View Full Version : SSD1306 OLED (72x40) I2C display from scratch



flotulopex
- 13th November 2023, 17:04
Hi there,

I juste received a bunch of very small (72x40) OLED displays driven by a SSD1306 controller.

94769477

I have absolutely never used those displays, in particular the SSD1306 controller.

After a few searches in the forum, I got some examples but these don't really help unless I first understand the very basics.

So, would anyone of you have a code snippet I could start with and ready to share it or a good reference to understand the SSD1306 please?

For example, it starts right at the beginning: there seems to be a "display" address. Is this standard for I2C displays or should I get it from the manufacturer?

Voilą, that's the low I'm right now...

So again, if somenone has basic stuff to share, I would really appreciate :wink:

richard
- 14th November 2023, 00:57
I got some examples but these don't really help unless I first understand the very basics.

i would initialize the display as per my posts to start with and work from there




there seems to be a "display" address. Is this standard for I2C displays or should I get it from the manufacturer?

a simple i2c scan such as this will reveal the address



'************************************************* ***************'* Name : UNTITLED.BAS *
'* Author : [select VIEW...EDITOR OPTIONS] *
'* Notice : Copyright (c) 2014 [select VIEW...EDITOR OPTIONS] *
'* : All Rights Reserved *
'* Date : 9/23/2014 *
'* Version : 1.0 *
'* Notes : pic16f1825 *
'* : scan i2c bus *
'************************************************* ***************

#CONFIG
__config _CONFIG1, _WDTE_ON & _FOSC_INTOSC &_MCLRE_ON &_PWRTE_ON
__config _CONFIG2, _LVP_OFF & _PLLEN_ON
#ENDCONFIG
DEFINE OSC 32

DEFINE I2C_SLOW 1

osccon=$70 '8 mhz
anselA=0 'dig i/o
ANSELC=0
TRISC= %11111111
TRISA= %11111110




SCL var Portc.1 ' I2C Clock PortA.3
SDA var Portc.0 ' I2C Data PortA.2












I VAR BYTE


buff var byte[10]
addr var byte


porta.0=1
DEFINE DEBUG_REG PORTA
DEFINE DEBUG_BIT 0 ;
DEFINE DEBUG_BAUD 38400
DEFINE DEBUG_MODE 0
pause 2000
Debug "Start",13 ,10






addr=$E3








for I = $02 to $fe step 2
I2Cwrite SDA,SCL,i,addr,[0],nak
ARRAYWRITE buff[1], [ "found",0]
Debug str buff , 9
Debug "ack ",hex2 i , 13,10


nak:


Next I




end

flotulopex
- 14th November 2023, 17:01
okay, first step done!

9478

flotulopex
- 15th November 2023, 11:25
Richard,

I'm not sure to find your initialisation example.

I found the one from Tim (https://www.picbasic.co.uk/forum/showthread.php/20179-SSD1306-Include-example).

I'll try this one if it is okay.

Ioannis
- 15th November 2023, 11:56
Have a look here:

https://www.picbasic.co.uk/forum/showthread.php/23758-SSD1306-INCLUDE-for-PBP3?highlight=SSD1306

Ioannis

flotulopex
- 15th November 2023, 14:32
Thanks Ioannis.

I saw them all but there are many files and includes (...) that Tim's example seemed "easier" to start with.

Not knowing what I really need to keep among them for a start, it's a little bit more confusing.

I need help so I'll go back to the post you mentionned and (try to) compose/compile what I need to run on a 16F :wink:

flotulopex
- 15th November 2023, 14:52
I really appreciate anyone's help but maybe to help me get my head out of the myst, could someone roughly tell me at at least how these displays work?

Appart from the easiest part which is to connect them to ą µC, how does it basically work like:
- connect it
- on power-up, initialize it (seems there's a bunch of parameters to send to the display)
- will it already light-up something (backlight or any dot on the screen?)
- prepare a bunch of data to actually define the caracters you will want to display in a LOOKUP table
- call-up and send this or that caracter to display
- does the display need to be refreshed every x time or is it a one-shot command that will suffice to have something displayed
....

When I mean "basics", I really mean it.... I have absolutely no clue how this little things work....:confused:

Ioannis
- 15th November 2023, 16:58
These LCD's are difficult to use. Indeed there are too many parameters to set and also you have to design the characters to display.

The good thing is that you have flexibility in designing the characters, the bad is that you have to do it!

The good member Richard has done much of the dirty work to use these LCD's and gave us the libraries. But you have to do your part too, especially if you have different LCD. You need to adapt to the dimensions of the screen, design your graphics etc...

Powering up the display may not light any LED's and display nothing. All are software controlled.

I tried an 0.9" LCD and with the support of the Richard managed to display text in various sizes. But I admit I have not fully mastered the beast.

Ioannis

richard
- 15th November 2023, 23:49
The latest version of the include is on post #90 of the link posted by ionnis reposted here for your convenience

this display is not something you can sneak up on easily , you really need a 100% solution before you can get anywhere

your 42x40 version will very likely need a few tweaks to match the way the oled array has been mapped onto the segment/com pins
and represented on the graphic memory overlay of the driver chip, i don't have one to experiment with

there is an alternative version here for p18 chips only that is more versatile, it would still need the same tweaks too
https://www.picbasic.co.uk/forum/showthread.php/24218-Graphical-Displays-with-PBP3


the init routine is fairly well commented if you read it in conjunction with the ssd1306 data sheet

'************************************************* ***************'* Name : ssd1306_I2C.INC *
'* Author : richard *
'* Notice : *
'* : *
'* Date : 8/2/2022 *
'* Version : 1.2 *
'* *
'* *
'* Notes : font address banksel fixed *
'* :FOR pic 16/18 SSD1306 *
'************************************************* ***************

goto overglcd
; adjust to suit and place these in main prg
;use this define for hw i2c
;#define hwi2c 1
;#DEFINE PIC16 1 ;IF PIC 16 USED [USE PIC16 FONT TOO}
' ssdheight con 7 ; 7 = 8 PAGES 64*128 , 3 = 4 pages 32*128
' ssdwidth con 127 ; 128 PIXELS WIDE
' SCL var PortC.3 ' I2C Clock
' SDA var PortC.4 ' I2C Data
' sdd1306_addr con $78

USERCOMMAND "GLCDC" ; X,Y,CHR 0 < X < 127 , 0 < Y < 7 31 < CHR > 127
USERCOMMAND "GLCD_CLR" ;clear area x,y,W,H
USERCOMMAND "GLCDSTR" ;STRING @ X,Y or Constant String
USERCOMMAND "GLCDDHL" ; x,y,L ,bit-patten
USERCOMMAND "GLCDDVL" ; x,y,H
USERCOMMAND "SSDC" ;cmd BYTE TO SSD1306
USERCOMMAND "SSDBM" ;x,y,w,h,label


ASM


;----------------------VERT LINE------------------------------------
GLCDDVL?CCC macro Xin ,Yin , Hin
MOVE?CB Xin ,_gx
MOVE?CB Yin,_gy
MOVE?CB Hin ,_gl
L?CALL _xyy
endm

;----------------------HORIZ LINE------------------------------------
GLCDDHL?CCCC macro Xin ,Yin , Win ,Cin
MOVE?CB Xin ,_gx
MOVE?CB Yin,_gy
MOVE?CB Win ,_gl
MOVE?CB Cin ,_glcdData
L?CALL _xyx
endm

;----[const String]---------------------------------------------------------------
GLCDSTR?CCS macro Xin ,Yin,Cin
IFNDEF TBLPTRL
local TheString, OverStr ; define local labels so you can call macro multiple times
goto OverStr ; goto over string stored in FLASH, so processor can't execute that
TheString ;label to get address of your string
da Cin, 0 ;add string to flash at TheString address and end string with 0
OverStr
MOVE?CW TheString, _glcd_bigaddress
MOVE?CB Xin , _gx
MOVE?CB Yin , _gy
L?GOTO _GlcdUnpackStr
ELSE
local TheString, OverStr ; define local labels so you can call macro multiple times
goto OverStr ; goto over string stored in FLASH, so processor can't execute that
TheString ;label to get address of your string
data Cin, 0 ;add string to flash at TheString address and end string with 0
OverStr
movlw UPPER TheString
movwf TBLPTRU
movlw HIGH TheString
movwf TBLPTRH
movlw LOW TheString
movwf TBLPTRL
MOVE?CB Xin , _gx
MOVE?CB Yin , _gy
L?CALL GLCD_Cstr_out
ENDIF
endm


SSDBM?CCCCL macro Xin ,Yin ,Win,Hin,BMin
IFNDEF TBLPTRL
ERROR BITMAPS ONLY SUPPORTED ON PIC18
ENDIF
MOVE?CB Xin , _gx
MOVE?CB Yin , _gy
MOVE?CB Hin/8-1 , _gy_
MOVE?CB Win+Xin-1 , _gx_
MOVE?CW Win*Hin/8 , _glcd_rad
banksel _glcdbm
movlw low BMin
movwf _glcdbm
movlw high BMin
movwf _glcdbm +1
BANKSEL 0
L?CALL _ssd_bitmap
endm




;----------------------Strings------------------------------------
GLCDSTR?CBB macro Xin ,Yin ,Bin
MOVE?CB Xin , _gx
MOVE?BB Yin , _gy
MOVE?CB high Bin, FSR1H ;load highbyte
MOVE?CB low Bin, FSR1L ;load low byte
L?CALL GLCD_str_out
endm
GLCDSTR?CCB macro Xin ,Yin ,Bin
MOVE?CB Xin , _gx
MOVE?CB Yin ,_gy
MOVE?CB high (Bin), FSR1H ;load highbyte
MOVE?CB low (Bin), FSR1L ;load low byte
L?CALL GLCD_str_out
endm
GLCDSTR?BBB macro Xin ,Yin ,Bin
MOVE?B Xin, _gx
MOVE?B Yin, _gy
MOVE?CB high Bin, FSR1H ;load highbyte
MOVE?CB low Bin, FSR1L ;load low byte
L?CALL GLCD_str_out
endm
GLCDSTR?WBB macro Xin ,Yin ,Bin
MOVE?WB Xin, _gx
MOVE?BB Yin, _gy
MOVE?CB high Bin, FSR1H ;load highbyte
MOVE?CB low Bin, FSR1L ;load low byte
L?CALL GLCD_str_out
endm
GLCDSTR?WWB macro Xin ,Yin ,Bin
MOVE?WB Xin, _gx
MOVE?WB Yin, _gy
MOVE?CB high Bin, FSR1H ;load highbyte
MOVE?CB low Bin, FSR1L ;load low byte
L?CALL GLCD_str_out
endm


SSDC?C macro Cin
MOVE?CB Cin , _glcdData
L?CALL _cmd_byte
endm
SSDC?B macro Cin
MOVE?BB Cin , _glcdData
L?CALL _cmd_byte
endm


GLCD_CLR? macro
MOVE?CB 0, _gx
MOVE?CB 0, _gy
MOVE?CB _ssdwidth, _gx_
MOVE?CB _ssdheight, _gy_
L?CALL _glcd_clrxy
endm


GLCD_CLR?CCCC macro Xin ,Yin,X1in ,Y1in
MOVE?CB Xin, _gx
MOVE?CB Yin, _gy
MOVE?CB X1in, _gx_
MOVE?CB Y1in, _gy_
L?CALL _glcd_clrxy
endm

;----------------------Character @ X,Y ------------------------------------
GLCDC?BBB macro Xin ,Yin , Bin
MOVE?BB Xin, _gx
MOVE?BB Yin, _gy
MOVE?BB Bin, _glcdCh
L?CALL _gcga
endm
GLCDC?WBB macro Xin ,Yin , Bin
MOVE?WB Xin, _gx
MOVE?BB Yin, _gy
MOVE?BB Bin, _glcdCh
L?CALL _gcga
endm
GLCDC?WWB macro Xin ,Yin , Bin
MOVE?WB Xin, _gx
MOVE?WB Yin, _gy
MOVE?BB Bin, _glcdCh
L?CALL _gcga
endm

GLCDC?BBC macro Xin ,Yin , Cin
MOVE?BB Xin, _gx
MOVE?BB Yin, _gy
MOVE?CB Cin ,_glcdCh
L?CALL _gcga
endm
GLCDC?WBC macro Xin ,Yin , Cin
MOVE?WB Xin, _gx
MOVE?BB Yin, _gy
MOVE?CB Cin ,_glcdCh
L?CALL _gcga
endm
GLCDC?CCC macro Xin ,Yin ,Cin
MOVE?CB Xin , _gx
MOVE?CB Yin, _gy
MOVE?CB Cin, _glcdCh
L?CALL _gcga
endm
GLCDC?CCB macro Xin ,Yin ,Bin
MOVE?CB Xin , _gx
MOVE?CB Yin, _gy
MOVE?BB Bin, _glcdCh
L?CALL _gcga
endm




GLetAddress macro Label, Wout
BANKSEL Wout
movlw low Label ; get low byte
movwf Wout
movlw High Label ; get high byte
movwf Wout + 1
BANKSEL 0
endm

IFDEF TBLPTRL

GLCD_Cstr_out
tblrd *+
movf TABLAT,w
bz GLCD_exit_Cstr_out ; EXIT ON Null char
CHK?RP _glcdCh
MOVWF _glcdCh
CHK?RP _glcd_bigaddress
movff TBLPTRU,_glcd_bigaddress
movff TBLPTRH,_glcd_bigaddress+1
movff TBLPTRL,_glcd_bigaddress+2
L?CALL _gcga
CHK?RP _glcd_bigaddress
movff _glcd_bigaddress ,TBLPTRU
movff _glcd_bigaddress+1 ,TBLPTRH
movff _glcd_bigaddress+2 ,TBLPTRL
bra GLCD_Cstr_out
GLCD_exit_Cstr_out
BANKSEL 0
return




GLCD_str_out
movf POSTINC1, W ; Get a character
bz GLCD_exit_strout ; EXIT ON Null char
CHK?RP _glcdCh
MOVWF _glcdCh
BANKSEL 0
L?CALL _gcga
bra GLCD_str_out
GLCD_exit_strout
BANKSEL 0
return
ELSE



GLCD_str_out
IFDEF BSR
MOVIW FSR1++ ; Get a character
BTFSC STATUS,Z
BRA GLCD_exit_strout ; EXIT ON Null char
ELSE
movf INDF, W ; Get a character
BTFSC STATUS,Z
GOTO GLCD_exit_strout ; EXIT ON Null char
INCF FSR,F
ENDIF
CHK?RP _glcdCh
MOVWF _glcdCh
MOVE?BB FSR1L,_glcd_bigaddress
MOVE?BB FSR1H,_glcd_bigaddress+1
BANKSEL 0
L?CALL _gcga
MOVE?BB _glcd_bigaddress,FSR1L
MOVE?BB _glcd_bigaddress+1,FSR1H
GOTO GLCD_str_out
GLCD_exit_strout
BANKSEL 0
return
ENDIF
endasm

glcd_bigaddress VAR BYTE[3]
glcd_buff VAR BYTE[32]
BIG_TEXT var byte
glcd_rad var word
glcdCh var byte 'chr DATA
glcdData VAR byte 'DATA
glcdBC VAR word 'gca var
glcdDC VAR BYTE 'gca var
glcdFont var word bank0'font address
glcdOffset VAR word 'font offset
glcdbm VAR word 'bitmap offset
gl var byte 'width/height
gy var byte 'gca pg address
gy_ var byte 'gca pg address
gx var byte 'gca row address
gx_ var byte 'gca row address
GRX var byte 'DATA
ctemp var word
ctemp1 var word
ssd_add var byte
glcdStrAddr var word ext
@glcdStrAddr = _glcd_bigaddress


GlcdUnpackStr:
readcode glcdStrAddr,CTEMP
glcd_bigaddress[2] = CTEMP&$7f
ctemp=ctemp<<1
glcdCh = CTEMP.HIGHBYTE
glcdStrAddr=glcdStrAddr+1
if glcdCh then
gosub gcga
glcdCh = glcd_bigaddress[2]
else
return
endif
if glcdCh then
gosub gcga
else
return
endif
goto GlcdUnpackStr:
return



glcd_init:
#ifdef hwi2c
SSPSTAT = 0 'High Speed Filter
SSPADD = $26'400 kHz @32 MHz
SSPCON1 = %00101000 'I2C Master Mode Enable
SSPCON3 = 0

#endif
@ GLetAddress _font7x5,_glcdFont
ssd_add = sdd1306_addr
SSDc $AE ' Display OFF
SSDc $d5
SSDc $80
SSDc $a8 : SSDc $3f
SSDc $D3 : SSDc $00 ; Set Display Offset Mode Set 0
if ssdheight > 3 then
SSDc $40 ' Set display start line 0
else
SSDc $60 ' Set display start line 4
endif
SSDc $8D : SSDc $14 ' Set Charge Pump Internal
SSDc $20 : SSDc $00 ' Adressing mode Horizontal
SSDc $A1 ' set segment remap column 127 as start
SSDc $C8 ' Com Scan Direction, Flip display vertically
SSDc $DA ' set COM pins
if ssdheight > 3 then
SSDc$12 ' set COM pins = 128x64=$12
else
SSDc$02 ' set COM pins = 128x32=$02
endif
SSDc $81 : SSDc$7F ' Set brightness to $01 to $FF ($7F is default, $01 is faint)
SSDc $DB : SSDc$40 ' Set VCOM Deselect Level
SSDc $B0 ' Set Page Address From $B0 to $B7
SSDc $2e ; scroll off
SSDc $A4 ' display ON continue
SSDc $A6 ' $A6=NORMAL MODE; $A7=INVERSE MODE
SSDc $AF ' Display ON
return




xyx: ;draw HORIZ LINE @X,Y for W len 0<X>127 1<W>127
FOR GRX = 0 TO 31
glcd_buff[GRX] = glcdData ;uses this var to set which bit/s is used to generate line
NEXT
gx = gx&ssdwidth
gx_= gx + gl
gy = gy&ssdheight
gy_= gy
gosub setxy
GRX = gl/32
glcd_rad = 32
WHILE GRX
gosub ssd_data
GRX = GRX-1
WEND
glcd_rad = gl//32
IF glcd_rad THEN
gosub ssd_data
ENDIF
return




xyy: ;draw VERT LINE @X,Y for W len @X 0<X>127 1<W>7
FOR GRX = 0 TO ssdheight
glcd_buff[GRX] = 255
NEXT
gx = gx&ssdwidth
gx_= gx
gy = gy&ssdheight
gy_= gy+GL
gosub setxy
glcd_rad = gl
gosub ssd_data
return


glcd_clrxy: ' clear area x1y1 to x2 y2
FOR GRX = 0 TO 31
glcd_buff[GRX] = 0
NEXT
CTEMP = (1 + GX_ - GX)*(1 + GY_ - GY)
gosub setxy
GRX = CTEMP/32
glcd_rad=32
WHILE GRX
gosub ssd_data
GRX = GRX-1
WEND
glcd_rad = CTEMP//32
IF GRX THEN
gosub ssd_data
ENDIF
return


gcga: ;draw a chr
GY = gy&ssdheight
GY_= gy + BIG_TEXT
gx = gx&ssdwidth
#ifdef PIC16
glcdOffset = (glcdch-32)*3 + glcdFont ; point to cga data
#ELSE
glcdOffset = (glcdch-32)*6 + glcdFont ; point to cga data
#ENDIF
gosub unpack
IF BIG_TEXT THEN
GOSUB SSD_BIG
glcd_rad = 24
gx_= gx + 11
ELSE
glcd_rad = 6
gx_= gx + 5
ENDIF
gosub setxy
gosub ssd_data
gx = gx_+ 1 + BIG_TEXT
IF GX > 121 THEN gx=0 ;wrap
return


ssd_data: ;send data block
#ifdef hwi2c
glcdBC=0
SSPCON2.0 = 1 ; SEN - Start Condition Enable Bit
WHILE SSPCON2.0 = 1 : WEND ; Wait for Start to complete
SSPBUF = ssd_add ; Move data to SSPBUF
WHILE SSPSTAT.2 = 1 : WEND ; SSPSTAT = 1 Transmit in progress
While SSPCON2.6 = 1 : WEND ; Wait for Acknowledge from slave
SSPBUF = $40 ; Move data to SSPBUF
WHILE SSPSTAT.2 = 1 : WEND ; SSPSTAT = 1 Transmit in progress
While SSPCON2.6 = 1 : WEND ; Wait for Acknowledge from slave
while glcdBC < glcd_rad
SSPBUF = glcd_buff[glcdBC] ; Move data to SSPBUF
WHILE SSPSTAT.2 = 1 : WEND ; SSPSTAT = 1 Transmit in progress
While SSPCON2.6 = 1 : WEND ; Wait for Acknowledge from slave
glcdBC=glcdBC+1
wend
SSPCON2.2 = 1 ; PEN - send stop bit
While SSPCON2.2 = 1 : Wend ; Wait for SSP to complete
#else
i2Cwrite SDA,SCL,ssd_add,[$40,str glcd_buff\ glcd_rad]
#endif
return
#ifndef PIC16
ssd_bitmap: ;send graphic block from flash
gosub setxy
glcdBC=0
SSPCON2.0 = 1 ; SEN - Start Condition Enable Bit
WHILE SSPCON2.0 = 1 : WEND ; Wait for Start to complete
SSPBUF = ssd_add ; Move data to SSPBUF
WHILE SSPSTAT.2 = 1 : WEND ; SSPSTAT = 1 Transmit in progress
While SSPCON2.6 = 1 : WEND ; Wait for Acknowledge from slave
SSPBUF = $40 ; Move data to SSPBUF
WHILE SSPSTAT.2 = 1 : WEND ; SSPSTAT = 1 Transmit in progress
While SSPCON2.6 = 1 : WEND ; Wait for Acknowledge from slave
while glcdBC < glcd_rad
readcode glcdbm+glcdBC,CTEMP
SSPBUF = ctemp.LOWBYTE ; Move data to SSPBUF
WHILE SSPSTAT.2 = 1 : WEND ; SSPSTAT = 1 Transmit in progress
While SSPCON2.6 = 1 : WEND ; Wait for Acknowledge from slave
SSPBUF = ctemp.highBYTE ; Move data to SSPBUF
WHILE SSPSTAT.2 = 1 : WEND ; SSPSTAT = 1 Transmit in progress
While SSPCON2.6 = 1 : WEND ; Wait for Acknowledge from slave
glcdBC=glcdBC+2
wend
SSPCON2.2 = 1 ; PEN - send stop bit
While SSPCON2.2 = 1 : Wend ; Wait for SSP to complete
return
#endif

SSD_BIG: ;create a big chr from a small one
for glcddc = 5 to 0 STEP -1
ctemp = 0
ctemp1 = 3
gL = glcd_buff[glcddc]
for glcdBc = 0 to 7
IF GL & 1 THEN ctemp = ctemp|ctemp1
ctemp1 = ctemp1<<2
GL = GL>>1
NEXT
gL = glcddc*2
glcd_buff[GL] =ctemp.LOWBYTE
glcd_buff[GL+1] =ctemp.LOWBYTE
glcd_buff[GL+12]=ctemp.HIGHBYTE
glcd_buff[GL+13]=ctemp.HIGHBYTE
NEXT
RETURN


unpack: ;unpack font from flash
for glcddc = 0 to 2
GL = glcddc<<1
readcode glcdOffset,CTEMP
#ifdef PIC16
glcd_buff[gl] = CTEMP&$7f
ctemp=ctemp<<1
glcd_buff[gl+1]= CTEMP.HIGHBYTE
glcdOffset = glcdOffset + 1
#else
glcd_buff[gl] = CTEMP
glcd_buff[gl+1]= CTEMP.HIGHBYTE
glcdOffset = glcdOffset + 2
#endif
next
return


cmd_byte: 'send command sequence "glcdData "
#ifdef hwi2c
;hw i2c
SSPCON2.0 = 1 ; SEN - Start Condition Enable Bit
WHILE SSPCON2.0 = 1 : WEND ; Wait for Start to complete
SSPBUF = ssd_add ; Move data to SSPBUF
WHILE SSPSTAT.2 = 1 : WEND ; SSPSTAT = 1 Transmit in progress
While SSPCON2.6 = 1 : WEND ; Wait for Acknowledge from slave
SSPBUF = 0 ; Move data to SSPBUF
WHILE SSPSTAT.2 = 1 : WEND ; SSPSTAT = 1 Transmit in progress
While SSPCON2.6 = 1 : WEND ; Wait for Acknowledge from slave
SSPBUF = glcdData ; Move data to SSPBUF
WHILE SSPSTAT.2 = 1 : WEND ; SSPSTAT = 1 Transmit in progress
While SSPCON2.6 = 1 : WEND ; Wait for Acknowledge from slave
SSPCON2.2 = 1 ; PEN - send stop bit
While SSPCON2.2 = 1: Wend ; Wait for SSP to complete
#else
;soft i2c
I2Cwrite SDA,SCL,ssd_add,[0,glcdData]
#ENDIF
return




setxy: ;set PAGE WINDOW
SSDc $22
SSDc gy
SSDc gy_
SSDc $21
SSDc gx
SSDc gx_
return






overglcd :

flotulopex
- 16th November 2023, 05:51
Thanks a lot guys 👍

I'll give it a try this week-end.

And thanks Richard for condensing the information here :wink:

flotulopex
- 17th November 2023, 22:03
Only garbage at this time...but it's alive:)

9480

Ioannis
- 18th November 2023, 13:24
Seems that the character size is too big to fit there..

Ioannis

flotulopex
- 19th November 2023, 08:04
...still struggeling with the ssd1306's datasheet to understand the "page" concept and how to display things.

This is the simplest and shortest code I'm working with for now, composed of different sources I found in this forum and also on ARDUINO's one:



' ====== DESCRIPTION ================================================== =============================
' Use mini OLED 72x40 pixel display

' ====== FUSES ================================================== ===================================
' PIC 16F690 Fuses
' Internal oscillator (activate OSCCON register)
@ __config _FCMEN_OFF &_IESO_OFF &_CPD_OFF &_WDT_OFF &_INTRC_OSC_NOCLKOUT &_BOR_OFF &_CP_OFF &_PWRTE_OFF &_MCLRE_OFF

@ ERRORLEVEL -306
@ ERRORLEVEL -202

' ====== REGISTERS ================================================== ===============================
' 76543210
OPTION_REG = %10000000 'PORT A&B Pull-Ups disabled (see WPUA & WPUB)
OSCCON = %01100000 'Internal RC set to 4MHZ
'ANSEL = %00000000 'Select analog inputs Channels 0 to 7 (AN2 + AN4 selected)
'ANSELH = %00000000 'Select analog inputs Channels 8 to 11
'ADCON0 = %10000000 'A/D Module (Bit5:2 select channels 0:11)
'ADCON1 = %00000000 'A/D control register
'CM1CON0 = %00000000 'Comparator1 Module is OFF
'CM2CON0 = %00000000 'Comparator2 Module is OFF
'INTCON = %00000000 'INTerrupts CONtrol (TMR0 OFF)
'TRISA = %00000000 'Set Input/Output (0 to 5)
'PORTA = %00000000 'Ports High/Low (0 to 5)
'TRISB = %00000000 'Set Input/Output (4 to 7)
'PORTB = %00000000 'Ports High/Low (4 to 7)
'TRISC = %00000000 'Set Input/Output (0 to 7)
'PORTC = %00000000 'Ports High/Low (0 to 7)

' ====== DEFINES ================================================== =================================
DEFINE OSC 4
'DEFINE NO_CLRWDT 1 'Don't waste cycles clearing WDT
'DEFINE HSER_CLOERR 1 'Automatic clear overrun error

' ====== VARIABLES ================================================== ===============================
I2CDevice var byte

SDA VAR PORTB.4 ' I2C Data
SCL VAR PORTB.6 ' I2C Clock

TEXT VAR BYTE[20]
LENGTH VAR BYTE[2]
DC VAR Byte ' "DATA OR COMMAND", $40=DATA; $0=COMMAND --> changed from bit to byte
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)

' ====== INITIALIZE VARIABLES ================================================== ====================
I2CDevice = $78

'======= SSD1306 I2C OLED initialization ================================================== =========
COM = $AE : GOSUB SEND_COMMAND ' turn off oled panel
COM = $D5 : GOSUB SEND_COMMAND ' set display clock divide ratio/oscillator frequency
COM = $80 : GOSUB SEND_COMMAND ' set divide ratio
COM = $A8 : GOSUB SEND_COMMAND ' set multiplex ratio
COM = $27 : GOSUB SEND_COMMAND ' 1/40 duty
COM = $D3 : GOSUB SEND_COMMAND ' set display offset
COM = $00 : GOSUB SEND_COMMAND ' not offset
COM = $AD : GOSUB SEND_COMMAND ' Internal IREF Setting
COM = $30 : GOSUB SEND_COMMAND ' --
COM = $8D : GOSUB SEND_COMMAND ' set Charge Pump enable/disable
COM = $14 : GOSUB SEND_COMMAND ' set(0x10) disable
COM = $40 : GOSUB SEND_COMMAND ' set start line address
COM = $A6 : GOSUB SEND_COMMAND ' set normal display
COM = $A4 : GOSUB SEND_COMMAND ' Disable Entire Display On
COM = $A1 : GOSUB SEND_COMMAND ' set segment re-map 128 to 0
COM = $C8 : GOSUB SEND_COMMAND ' Set COM Output Scan Direction 64 to 0
COM = $DA : GOSUB SEND_COMMAND ' set com pins hardware configuration
COM = $12 : GOSUB SEND_COMMAND '
COM = $81 : GOSUB SEND_COMMAND ' set contrast control register
COM = $AF : GOSUB SEND_COMMAND '
COM = $D9 : GOSUB SEND_COMMAND ' set pre-charge period
COM = $22 : GOSUB SEND_COMMAND '
COM = $DB : GOSUB SEND_COMMAND ' set vcomh
COM = $20 : GOSUB SEND_COMMAND '
COM = $AF : GOSUB SEND_COMMAND ' turn on oled panel

' ====== PROGRAM ================================================== =================================
PAUSE 20
GOSUB CLEAR_LCD
GOSUB TITLE

MAIN:
PAUSE 1000
GOTO MAIN
END

' ====== CLEAR LCD ================================================== ===============================
CLEAR_LCD:
FOR J = 0 TO 7
FOR I = 0 TO 71 '127
LCD_DATA = $00 : GOSUB SEND_DATA
NEXT I
NEXT J
RETURN

' ====== SEND COMMAND ================================================== ============================
SEND_COMMAND:
dc = $0
I2CWrite SDA,SCL,I2CDevice,DC,[COM]
dc = $40
RETURN

' ====== CLEAR LCD ================================================== ===============================
SEND_DATA:
DC = $40
I2CWrite SDA,SCL,I2CDevice,DC,[LCD_DATA]
RETURN

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

' ====== TITLE ================================================== ===================================
TITLE:
X = 0 : Y = 0 : GOSUB SET_XY
FOR I = 0 TO 71 '127
LOOKUP I,[$00,$40,$60,$50,$7E,$50,$60,$40,$02,$06,$0E,$1E,$3 E,$00,$00,$00,_
$00,$00,$00,$00,$00,$1F,$3F,$60,$60,$60,$60,$60,$6 0,$3C,$1C,$00,_
$00,$7F,$7F,$61,$61,$61,$61,$61,$61,$3F,$1E,$00,$0 0,$1E,$3F,$61,_
$61,$61,$61,$61,$61,$38,$18,$00,$00,$00,$00,$00,$0 0,$00,$00,$00,_
$00,$00,$00,$00,$00,$00,$00,$1F,$3F,$60,$60,$60,$6 0,$60,$60,$3C,_
$1C,$00,$00,$1E,$3F,$61,$61,$61,$61,$61,$61,$38,$1 8,$00,$00,$3F,_
$7F,$60,$18,$06,$06,$18,$60,$7F,$3F,$00,$00,$00,$0 0,$00,$00,$00,_
$00,$00,$00,$1C,$63,$41,$5D,$41,$5D,$41,$5D,$41,$5 D,$41,$7F,$00],LCD_DATA
lcd_data = lcd_data rev 8
GOSUB SEND_DATA
NEXT I

X = 0 : Y = 1 : GOSUB SET_XY
for i = 0 to 71 '127
lookup i,[$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$0 0,$00,$00,$00,_
$00,$00,$00,$00,$00,$F8,$FC,$06,$06,$06,$C6,$C6,$C 6,$FC,$F8,$00,_
$00,$FE,$FE,$80,$80,$80,$80,$80,$80,$00,$00,$00,$0 0,$18,$1C,$86,_
$86,$86,$86,$86,$86,$FC,$78,$00,$00,$00,$00,$00,$0 0,$00,$00,$00,_
$00,$00,$00,$00,$00,$00,$00,$F8,$FC,$06,$06,$06,$C 6,$C6,$C6,$FC,_
$F8,$00,$00,$18,$1C,$86,$86,$86,$86,$86,$86,$FC,$7 8,$00,$00,$FE,_
$FE,$00,$00,$00,$00,$00,$00,$FE,$FE,$00,$00,$00,$0 0,$00,$00,$00,_
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$0 0,$00,$00,$00],lcd_data
lcd_data=lcd_data rev 8
GOSUB SEND_DATA
NEXT I

X = 0 : Y = 3 : GOSUB SET_XY
for i = 0 to 71 '127
lookup i,[$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3C,$7E,$C 3,$C3,$C3,$C3,_
$C3,$C3,$71,$30,$00,$00,$7F,$FF,$C3,$C3,$C3,$C3,$C 3,$C3,$C3,$C3,_
$00,$00,$7F,$FF,$C1,$C1,$C1,$C1,$C1,$C1,$FF,$7F,$0 0,$00,$7F,$FF,_
$C3,$C3,$C3,$C3,$C3,$C3,$7E,$3C,$00,$00,$3F,$7F,$C 0,$C0,$C0,$C0,_
$C0,$C0,$70,$30,$00,$00,$FF,$FF,$03,$03,$03,$03,$0 3,$03,$FF,$FF,_
$00,$00,$C0,$C0,$C0,$C0,$FF,$FF,$C0,$C0,$C0,$C0,$0 0,$00,$FF,$FF,_
$0C,$0C,$03,$03,$00,$00,$FF,$FF,$00,$00,$3F,$7F,$C 0,$C0,$C0,$C1,_
$C1,$C1,$79,$39,$00,$00,$00,$00,$00,$00,$00,$00,$0 0,$00,$00,$00],lcd_data
lcd_data=lcd_data rev 8
GOSUB SEND_DATA
NEXT I

X = 0 : Y = 4 : GOSUB SET_XY
for i = 0 to 71 '127
lookup i,[$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$30,$38,$0 C,$0C,$0C,$0C,_
$0C,$0C,$F8,$F0,$00,$00,$F8,$FC,$0C,$0C,$0C,$0C,$0 C,$0C,$0C,$0C,_
$00,$00,$FC,$FC,$80,$80,$80,$80,$80,$80,$FC,$FC,$0 0,$00,$FC,$FC,_
$80,$C0,$60,$30,$18,$0C,$04,$00,$00,$00,$F0,$F8,$0 C,$0C,$0C,$0C,_
$0C,$0C,$38,$30,$00,$00,$FC,$FC,$00,$00,$00,$00,$0 0,$00,$FC,$FC,_
$00,$00,$0C,$0C,$0C,$0C,$FC,$FC,$0C,$0C,$0C,$0C,$0 0,$00,$FC,$FC,_
$00,$00,$00,$00,$C0,$C0,$FC,$FC,$00,$00,$F0,$F8,$0 C,$0C,$0C,$8C,_
$8C,$8C,$F8,$F0,$00,$00,$00,$00,$00,$00,$00,$00,$0 0,$00,$00,$00],lcd_data
lcd_data=lcd_data rev 8
GOSUB SEND_DATA
NEXT I

X = 0 : Y = 5 : GOSUB SET_XY
for i = 0 to 71 '127
lookup i,[$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$1F,$3F,$3 0,$30,$30,$30,_
$30,$30,$30,$30,$00,$00,$0F,$1F,$30,$30,$30,$30,$3 0,$30,$1F,$0F,_
$00,$00,$1F,$3F,$30,$30,$30,$30,$30,$30,$1F,$0F,$0 0,$00,$00,$00,_
$00,$00,$00,$0F,$1F,$30,$30,$30,$30,$30,$30,$1C,$0 C,$00,$00,$30,_
$30,$30,$30,$3F,$3F,$30,$30,$30,$30,$00,$00,$0F,$1 F,$30,$30,$30,_
$30,$30,$30,$1E,$0E,$00,$00,$3F,$3F,$03,$03,$00,$0 0,$00,$00,$3F,_
$3F,$00,$00,$1F,$3F,$30,$30,$30,$30,$30,$30,$3F,$1 F,$00,$00,$3F,_
$3F,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$0 0,$00,$00,$00],lcd_data
lcd_data=lcd_data rev 8
GOSUB SEND_DATA
NEXT I

X = 0 : Y = 6 : GOSUB SET_XY
for i = 0 to 71 '127
lookup i,[$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$FF,$FF,$C 0,$C0,$C0,$C0,_
$C0,$C0,$00,$00,$00,$00,$FC,$FE,$03,$03,$03,$03,$0 3,$03,$FE,$FC,_
$00,$00,$FF,$FF,$E0,$F0,$D8,$CC,$C6,$C3,$81,$00,$0 0,$00,$00,$00,_
$00,$00,$00,$0C,$8E,$C3,$C3,$C3,$C3,$C3,$C3,$7E,$3 C,$00,$00,$03,_
$03,$03,$03,$FF,$FF,$03,$03,$03,$03,$00,$00,$FC,$F E,$03,$03,$03,_
$63,$63,$63,$7E,$7C,$00,$00,$FF,$FF,$00,$00,$C0,$C 0,$30,$30,$FF,_
$FF,$00,$00,$FF,$FF,$60,$60,$60,$60,$60,$60,$FF,$F F,$00,$00,$FF,_
$FF,$03,$03,$03,$03,$03,$03,$03,$03,$00,$00,$00,$0 0,$00,$00,$00],lcd_data
lcd_data=lcd_data rev 8
GOSUB SEND_DATA
NEXT I
RETURN

'======= SET_XY ================================================== ==================================
SET_XY:
COM = $21 : GOSUB SEND_COMMAND
COM = X : GOSUB SEND_COMMAND
COM = 71 : GOSUB SEND_COMMAND
COM = $22 : GOSUB SEND_COMMAND
COM = Y : GOSUB SEND_COMMAND
COM = 41 : GOSUB SEND_COMMAND
RETURN




Seems that the character size is too big to fit there..
Originally, this code is made for a larger display so I need to adapt it.

Ioannis
- 19th November 2023, 12:46
Is it worth it the effort to spend much time on this LCD's?

It tried it and seems a lot of waste of time. Also too small for my age:)

Ioannis

flotulopex
- 19th November 2023, 16:58
Up to now, I couldn't find any pixel map for the 72x40 display so I'm relying on information for the 128x64 one.

This is the information I have found in the 72x40 datasheet:
9481

Can anybody tell me how I should convert this in "pages" if I have to do so? I don't understand how data has to be displayed...

This is the example from the 128x64's datasheet (to be found in attachment):
9482

richard
- 19th November 2023, 23:44
Some comments
is the display 72x40 of 42x40 ? you describe it both ways
the write window should be set to width and page height you require and the pixel/page offset to begin write from for proper operation

and

with your attempted title page transmission, sending every byte of data like that as individual senddata transactions is extremely inefficient the entire thing could be sent as a single data block in half the time




====== DESCRIPTION ================================================== =============================' Use mini OLED 72x40 pixel display


' ====== FUSES ================================================== ===================================
' PIC 16F690 Fuses
' Internal oscillator (activate OSCCON register)
@ __config _FCMEN_OFF &_IESO_OFF &_CPD_OFF &_WDT_OFF &_INTRC_OSC_NOCLKOUT &_BOR_OFF &_CP_OFF &_PWRTE_OFF &_MCLRE_OFF


@ ERRORLEVEL -306
@ ERRORLEVEL -202


' ====== REGISTERS ================================================== ===============================
' 76543210
OPTION_REG = 000000 'PORT A&B Pull-Ups disabled (see WPUA & WPUB)
OSCCON = 100000 'Internal RC set to 4MHZ
'ANSEL = 000000 'Select analog inputs Channels 0 to 7 (AN2 + AN4 selected)
'ANSELH = 000000 'Select analog inputs Channels 8 to 11
'ADCON0 = 000000 'A/D Module (Bit5:2 select channels 0:11)
'ADCON1 = 000000 'A/D control register
'CM1CON0 = 000000 'Comparator1 Module is OFF
'CM2CON0 = 000000 'Comparator2 Module is OFF
'INTCON = 000000 'INTerrupts CONtrol (TMR0 OFF)
'TRISA = 000000 'Set Input/Output (0 to 5)
'PORTA = 000000 'Ports High/Low (0 to 5)
'TRISB = 000000 'Set Input/Output (4 to 7)
'PORTB = 000000 'Ports High/Low (4 to 7)
'TRISC = 000000 'Set Input/Output (0 to 7)
'PORTC = 000000 'Ports High/Low (0 to 7)


' ====== DEFINES ================================================== =================================
DEFINE OSC 4
'DEFINE NO_CLRWDT 1 'Don't waste cycles clearing WDT
'DEFINE HSER_CLOERR 1 'Automatic clear overrun error


' ====== VARIABLES ================================================== ===============================
I2CDevice var byte


SDA VAR PORTB.4 ' I2C Data
SCL VAR PORTB.6 ' I2C Clock


TEXT VAR BYTE[20]
LENGTH VAR BYTE[2]
DC VAR Byte ' "DATA OR COMMAND", $40=DATA; $0=COMMAND --> changed from bit to byte
;seems a pointless waste if a variable
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)


' ====== INITIALIZE VARIABLES ================================================== ====================
I2CDevice = $78


'======= SSD1306 I2C OLED initialization ================================================== =========
COM = $AE : GOSUB SEND_COMMAND ' turn off oled panel
COM = $D5 : GOSUB SEND_COMMAND ' set display clock divide ratio/oscillator frequency
COM = $80 : GOSUB SEND_COMMAND ' set divide ratio
COM = $A8 : GOSUB SEND_COMMAND ' set multiplex ratio
COM = $27 : GOSUB SEND_COMMAND ' 1/40 duty
COM = $D3 : GOSUB SEND_COMMAND ' set display offset
COM = $00 : GOSUB SEND_COMMAND ' not offset
COM = $AD : GOSUB SEND_COMMAND ' Internal IREF Setting
COM = $30 : GOSUB SEND_COMMAND ' --
COM = $8D : GOSUB SEND_COMMAND ' set Charge Pump enable/disable
COM = $14 : GOSUB SEND_COMMAND ' set(0x10) disable
COM = $40 : GOSUB SEND_COMMAND ' set start line address
COM = $A6 : GOSUB SEND_COMMAND ' set normal display
; you assume display is mapped from page 0 , this may not be correct ans could be 0,1,2,3


COM = $A4 : GOSUB SEND_COMMAND ' Disable Entire Display On
COM = $A1 : GOSUB SEND_COMMAND ' set segment re-map 128 to 0
COM = $C8 : GOSUB SEND_COMMAND ' Set COM Output Scan Direction 64 to 0
COM = $DA : GOSUB SEND_COMMAND ' set com pins hardware configuration
COM = $12 : GOSUB SEND_COMMAND '
COM = $81 : GOSUB SEND_COMMAND ' set contrast control register
COM = $AF : GOSUB SEND_COMMAND '
COM = $D9 : GOSUB SEND_COMMAND ' set pre-charge period
COM = $22 : GOSUB SEND_COMMAND '
COM = $DB : GOSUB SEND_COMMAND ' set vcomh
COM = $20 : GOSUB SEND_COMMAND '
COM = $AF : GOSUB SEND_COMMAND ' turn on oled panel


' ====== PROGRAM ================================================== =================================
PAUSE 20
GOSUB CLEAR_LCD
GOSUB TITLE


MAIN:
PAUSE 1000
GOTO MAIN
END


' ====== CLEAR LCD ================================================== ===============================
CLEAR_LCD:
FOR J = 0 TO 7
FOR I = 0 TO 71 '127
LCD_DATA = $00 : GOSUB SEND_DATA
NEXT I
NEXT J
RETURN
; cant see this working without setting a "window" to write into properly

' ====== SEND COMMAND ================================================== ============================
SEND_COMMAND:
dc = $0
I2CWrite SDA,SCL,I2CDevice,DC,[COM]
dc = $40
RETURN

; why not just
SEND_COMMAND:
I2CWrite SDA,SCL,I2CDevice,[0,COM]
RETURN


' ====== CLEAR LCD ================================================== ===============================
SEND_DATA:
DC = $40
I2CWrite SDA,SCL,I2CDevice,DC,[LCD_DATA]
RETURN
; why not just
SEND_COMMAND:
I2CWrite SDA,SCL,I2CDevice,[$40,LCD_DATA]
RETURN
' ====== SEND DATA ================================================== ===============================
FILL:
FOR J = 0 TO 7
FOR I = 0 TO 71 '127
LCD_DATA = $FF : GOSUB SEND_DATA
NEXT I
NEXT J
RETURN
; cant see this working without setting a "window" to write into properly
' ====== TITLE ================================================== ===================================
;here you set 6 pages "Y" of data from page 0 to 7 with page 2 missing when a 40 pixel height can have 5 pages maximum

TITLE:
X = 0 : Y = 0 : GOSUB SET_XY
FOR I = 0 TO 71 '127
LOOKUP I,[$00,$40,$60,$50,$7E,$50,$60,$40,$02,$06,$0E,$1E,$3 E,$00,$00,$00,_
$00,$00,$00,$00,$00,$1F,$3F,$60,$60,$60,$60,$60,$6 0,$3C,$1C,$00,_
$00,$7F,$7F,$61,$61,$61,$61,$61,$61,$3F,$1E,$00,$0 0,$1E,$3F,$61,_
$61,$61,$61,$61,$61,$38,$18,$00,$00,$00,$00,$00,$0 0,$00,$00,$00,_
$00,$00,$00,$00,$00,$00,$00,$1F,$3F,$60,$60,$60,$6 0,$60,$60,$3C,_
$1C,$00,$00,$1E,$3F,$61,$61,$61,$61,$61,$61,$38,$1 8,$00,$00,$3F,_
$7F,$60,$18,$06,$06,$18,$60,$7F,$3F,$00,$00,$00,$0 0,$00,$00,$00,_
$00,$00,$00,$1C,$63,$41,$5D,$41,$5D,$41,$5D,$41,$5 D,$41,$7F,$00],LCD_DATA
lcd_data = lcd_data rev 8
GOSUB SEND_DATA
NEXT I


X = 0 : Y = 1 : GOSUB SET_XY
for i = 0 to 71 '127
lookup i,[$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$0 0,$00,$00,$00,_
$00,$00,$00,$00,$00,$F8,$FC,$06,$06,$06,$C6,$C6,$C 6,$FC,$F8,$00,_
$00,$FE,$FE,$80,$80,$80,$80,$80,$80,$00,$00,$00,$0 0,$18,$1C,$86,_
$86,$86,$86,$86,$86,$FC,$78,$00,$00,$00,$00,$00,$0 0,$00,$00,$00,_
$00,$00,$00,$00,$00,$00,$00,$F8,$FC,$06,$06,$06,$C 6,$C6,$C6,$FC,_
$F8,$00,$00,$18,$1C,$86,$86,$86,$86,$86,$86,$FC,$7 8,$00,$00,$FE,_
$FE,$00,$00,$00,$00,$00,$00,$FE,$FE,$00,$00,$00,$0 0,$00,$00,$00,_
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$0 0,$00,$00,$00],lcd_data
lcd_data=lcd_data rev 8
GOSUB SEND_DATA
NEXT I


X = 0 : Y = 3 : GOSUB SET_XY
for i = 0 to 71 '127
lookup i,[$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$3C,$7E,$C 3,$C3,$C3,$C3,_
$C3,$C3,$71,$30,$00,$00,$7F,$FF,$C3,$C3,$C3,$C3,$C 3,$C3,$C3,$C3,_
$00,$00,$7F,$FF,$C1,$C1,$C1,$C1,$C1,$C1,$FF,$7F,$0 0,$00,$7F,$FF,_
$C3,$C3,$C3,$C3,$C3,$C3,$7E,$3C,$00,$00,$3F,$7F,$C 0,$C0,$C0,$C0,_
$C0,$C0,$70,$30,$00,$00,$FF,$FF,$03,$03,$03,$03,$0 3,$03,$FF,$FF,_
$00,$00,$C0,$C0,$C0,$C0,$FF,$FF,$C0,$C0,$C0,$C0,$0 0,$00,$FF,$FF,_
$0C,$0C,$03,$03,$00,$00,$FF,$FF,$00,$00,$3F,$7F,$C 0,$C0,$C0,$C1,_
$C1,$C1,$79,$39,$00,$00,$00,$00,$00,$00,$00,$00,$0 0,$00,$00,$00],lcd_data
lcd_data=lcd_data rev 8
GOSUB SEND_DATA
NEXT I


X = 0 : Y = 4 : GOSUB SET_XY
for i = 0 to 71 '127
lookup i,[$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$30,$38,$0 C,$0C,$0C,$0C,_
$0C,$0C,$F8,$F0,$00,$00,$F8,$FC,$0C,$0C,$0C,$0C,$0 C,$0C,$0C,$0C,_
$00,$00,$FC,$FC,$80,$80,$80,$80,$80,$80,$FC,$FC,$0 0,$00,$FC,$FC,_
$80,$C0,$60,$30,$18,$0C,$04,$00,$00,$00,$F0,$F8,$0 C,$0C,$0C,$0C,_
$0C,$0C,$38,$30,$00,$00,$FC,$FC,$00,$00,$00,$00,$0 0,$00,$FC,$FC,_
$00,$00,$0C,$0C,$0C,$0C,$FC,$FC,$0C,$0C,$0C,$0C,$0 0,$00,$FC,$FC,_
$00,$00,$00,$00,$C0,$C0,$FC,$FC,$00,$00,$F0,$F8,$0 C,$0C,$0C,$8C,_
$8C,$8C,$F8,$F0,$00,$00,$00,$00,$00,$00,$00,$00,$0 0,$00,$00,$00],lcd_data
lcd_data=lcd_data rev 8
GOSUB SEND_DATA
NEXT I


X = 0 : Y = 5 : GOSUB SET_XY
for i = 0 to 71 '127
lookup i,[$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$1F,$3F,$3 0,$30,$30,$30,_
$30,$30,$30,$30,$00,$00,$0F,$1F,$30,$30,$30,$30,$3 0,$30,$1F,$0F,_
$00,$00,$1F,$3F,$30,$30,$30,$30,$30,$30,$1F,$0F,$0 0,$00,$00,$00,_
$00,$00,$00,$0F,$1F,$30,$30,$30,$30,$30,$30,$1C,$0 C,$00,$00,$30,_
$30,$30,$30,$3F,$3F,$30,$30,$30,$30,$00,$00,$0F,$1 F,$30,$30,$30,_
$30,$30,$30,$1E,$0E,$00,$00,$3F,$3F,$03,$03,$00,$0 0,$00,$00,$3F,_
$3F,$00,$00,$1F,$3F,$30,$30,$30,$30,$30,$30,$3F,$1 F,$00,$00,$3F,_
$3F,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$0 0,$00,$00,$00],lcd_data
lcd_data=lcd_data rev 8
GOSUB SEND_DATA
NEXT I


X = 0 : Y = 6 : GOSUB SET_XY
for i = 0 to 71 '127
lookup i,[$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$FF,$FF,$C 0,$C0,$C0,$C0,_
$C0,$C0,$00,$00,$00,$00,$FC,$FE,$03,$03,$03,$03,$0 3,$03,$FE,$FC,_
$00,$00,$FF,$FF,$E0,$F0,$D8,$CC,$C6,$C3,$81,$00,$0 0,$00,$00,$00,_
$00,$00,$00,$0C,$8E,$C3,$C3,$C3,$C3,$C3,$C3,$7E,$3 C,$00,$00,$03,_
$03,$03,$03,$FF,$FF,$03,$03,$03,$03,$00,$00,$FC,$F E,$03,$03,$03,_
$63,$63,$63,$7E,$7C,$00,$00,$FF,$FF,$00,$00,$C0,$C 0,$30,$30,$FF,_
$FF,$00,$00,$FF,$FF,$60,$60,$60,$60,$60,$60,$FF,$F F,$00,$00,$FF,_
$FF,$03,$03,$03,$03,$03,$03,$03,$03,$00,$00,$00,$0 0,$00,$00,$00],lcd_data
lcd_data=lcd_data rev 8
GOSUB SEND_DATA
NEXT I
RETURN

'======= SET_XY ================================================== ==================================
SET_XY:
COM = $21 : GOSUB SEND_COMMAND
COM = X : GOSUB SEND_COMMAND
COM = 71 : GOSUB SEND_COMMAND
COM = $22 : GOSUB SEND_COMMAND
COM = Y : GOSUB SEND_COMMAND
COM = 41 : GOSUB SEND_COMMAND
;attempt to set page to 41 when it cannot be > than 5 pages


RETURN

flotulopex
- 20th November 2023, 07:34
It's definitively a 72x40 pixel display.

Thanks Richard for pointing to all changes (and tips) I can/should make in the code :wink:

Now, regarding the way to display data, I still don't get it; I'm completely lost since I have no clue how to do it.

I'm mostly using serial "common" LCDs in text mode so I don't have to create any font or so.

In my case, I will use this LCD to display, as big as possible, a number as a percentage (0.0%...99.9%).

What is the approach? I have a display 72 pixels wide and 40 pixels high (= 2'880 pixels). I assume, the display is divided in what they call "pages" and I should write a data table (LOOKUP) for each page. Is this correct?

But how do I address the pages? Do I have to do so? Is there a way to send "text" to the display like common LCDs? Is there a way to "design" a font that will in big appear all over the entire display?

I'm missing fundamentals 😔

richard
- 20th November 2023, 09:15
Basically the display is 360 bytes of ram where every bit is a oled, the ram is divided into 5 pages each of 72 bytes
the 5 pages are overlaid onto a larger array that is 8 pages of 128 bytes, precisely where is not known to me [i have never seen one of those modules]
the ssd1306 is very versatile and allows vertical and horiz offsets to be set along with scan direction and various mem access methods to suit you.
to write to a byte you must address its x and y position , the width to be written and number of pages is also expected to be set

ie to write a 10x14 chr 14 high 10 wide at page 1 posn 12

SET_XY:
COM = $21 : GOSUB SEND_COMMAND
COM = 12 : GOSUB SEND_COMMAND ;x=12
COM = 22 : GOSUB SEND_COMMAND ;12+10
COM = $22 : GOSUB SEND_COMMAND
COM = 1 : GOSUB SEND_COMMAND ;y=1
COM = 2 : GOSUB SEND_COMMAND ;1+1
RETURN
then send the 20 bytes needed to represent your chr



In my case, I will use this LCD to display, as big as possible, a number as a percentage (0.0%...99.9%).
easy you need to create a big font with the chrs you need in it



Is there a way to send "text" to the display like common LCDs?
no not even close

if you want easy use a pic18 and my code from here (https://www.picbasic.co.uk/forum/showthread.php/24218-Graphical-Displays-with-PBP3)

where you can define the screen size and create fonts as you need

or use an enhanced core pic16 and my earlier code that can do double size chrs

flotulopex
- 20th November 2023, 09:34
Thanks a lot Richard.

The fog lifts somehow a little bit....

I'll give it a try with y 18F 👍

richard
- 22nd November 2023, 02:07
is this more clear ?
draws a 7x5 chr A and 14x10 A in a 72x40 window located @ x=0y=0 after clearing screen [ outside of window is just random noise ]

here's a pic on a 128x64 screen , there is no telling how it line up for your screen
9484







#CONFIG __config _INTRC_OSC_NOCLKOUT & _WDT_ON & _PWRTE_OFF & _MCLRE_ON & _CP_OFF & _CPD_OFF & _BOD_ON & _IESO_ON & _FCMEN_ON
#ENDCONFIG




define OSC 8




OSCCON = 110000 'Internal RC set to 8MHZ
'ANSEL = 000000 'Select analog inputs Channels 0 to 7 (AN2 + AN4 selected)
'ANSELH = 000000 'Select analog inputs Channels 8 to 11


'TRISB = 000000 'Set Input/Output (4 to 7)
'PORTB = 000000 'Ports High/Low (4 to 7)








' ====== VARIABLES ================================================== ===============================
I2CDevice var byte


SDA VAR PORTB.6 ' I2C Data
SCL VAR PORTB.4 ' I2C Clock






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)


' ====== INITIALIZE VARIABLES ================================================== ====================
I2CDevice = $78


'======= SSD1306 I2C OLED initialization ================================================== =========
COM = $AE : GOSUB SEND_COMMAND ' turn off oled panel
COM = $D5 : GOSUB SEND_COMMAND ' set display clock divide ratio/oscillator frequency
COM = $80 : GOSUB SEND_COMMAND ' set divide ratio
COM = $A8 : GOSUB SEND_COMMAND ' set multiplex ratio
COM = $3F : GOSUB SEND_COMMAND ' 1/40 duty
COM = $D3 : GOSUB SEND_COMMAND ' set display offset
COM = $0 : GOSUB SEND_COMMAND
COM = $20 : GOSUB SEND_COMMAND
COM = $0 : GOSUB SEND_COMMAND
COM = $AD : GOSUB SEND_COMMAND ' Internal IREF Setting
COM = $30 : GOSUB SEND_COMMAND ' --
COM = $8D : GOSUB SEND_COMMAND ' set Charge Pump enable/disable
COM = $14 : GOSUB SEND_COMMAND ' set(0x10) disable
COM = $40 : GOSUB SEND_COMMAND ' set start line address
COM = $A6 : GOSUB SEND_COMMAND ' set normal display
COM = $A4 : GOSUB SEND_COMMAND ' Disable Entire Display On
COM = $A1 : GOSUB SEND_COMMAND ' set segment re-map 128 to 0
COM = $C8 : GOSUB SEND_COMMAND ' Set COM Output Scan Direction 64 to 0
COM = $DA : GOSUB SEND_COMMAND ' set com pins hardware configuration
COM = $12 : GOSUB SEND_COMMAND '
COM = $81 : GOSUB SEND_COMMAND ' set contrast control register
COM = $7F : GOSUB SEND_COMMAND '
COM = $D9 : GOSUB SEND_COMMAND ' set pre-charge period
COM = $22 : GOSUB SEND_COMMAND '
COM = $DB : GOSUB SEND_COMMAND ' set vcomh
COM = $40 : GOSUB SEND_COMMAND '
COM = $AF : GOSUB SEND_COMMAND ' turn on oled panel


' ====== PROGRAM ================================================== =================================


GOSUB CLEAR_LCD


MAIN:
;7x5 "A"
X = 15 : Y = 0 : GOSUB SET_7
I2CWrite SDA,SCL,I2CDevice,[$40,$fc,$12,$12,$12,$fc]
;14x10 "A"
X = 15 : Y = 2 : GOSUB SET_14
I2CWrite SDA,SCL,I2CDevice,[$40,$f0,$f8,12,12,14,14,12,12,$f8,$f0_
,$ff,$ff,6,6,6,6,6,6,$ff,$ff]
PAUSE 1000
GOTO MAIN
END


' ====== CLEAR LCD ================================================== ===============================
CLEAR_LCD:
COM = $21 : GOSUB SEND_COMMAND
COM = 0 : GOSUB SEND_COMMAND
COM = 71 : GOSUB SEND_COMMAND
COM = $22 : GOSUB SEND_COMMAND
COM = 0 : GOSUB SEND_COMMAND
COM = 4 : GOSUB SEND_COMMAND
LCD_DATA = $00
FOR J = 0 TO 4
FOR I = 0 TO 71
I2CWrite SDA,SCL,I2CDevice,[$40,LCD_DATA]
NEXT I
NEXT J
RETURN

' ====== SEND COMMAND ================================================== ============================
SEND_COMMAND:
I2CWrite SDA,SCL,I2CDevice,[0,COM]
RETURN



'======= SET_XY ================================================== ==================================
SET_7: '7x5
COM = $21 : GOSUB SEND_COMMAND
COM = X : GOSUB SEND_COMMAND
COM = x+4 : GOSUB SEND_COMMAND
COM = $22 : GOSUB SEND_COMMAND
COM = Y : GOSUB SEND_COMMAND
COM = y : GOSUB SEND_COMMAND
RETURN
SET_14: ;14x10
COM = $21 : GOSUB SEND_COMMAND
COM = X : GOSUB SEND_COMMAND
COM = x+9 : GOSUB SEND_COMMAND
COM = $22 : GOSUB SEND_COMMAND
COM = Y : GOSUB SEND_COMMAND
COM = y+1 : GOSUB SEND_COMMAND
RETURN

flotulopex
- 22nd November 2023, 08:36
Thanks a lot Richard.

I'll give it a try asap :smile:

flotulopex
- 22nd November 2023, 14:51
Voilą.

As no caracter would display, I changed the fill caracter in the CLEAR routine to make someting visible.

9489


' ====== CLEAR LCD ================================================== ===============================
CLEAR_LCD:
COM = $21 : GOSUB SEND_COMMAND ' set column address
COM = 0 : GOSUB SEND_COMMAND ' column start address
COM = 71 : GOSUB SEND_COMMAND ' column end address
COM = $22 : GOSUB SEND_COMMAND ' set page address
COM = 0 : GOSUB SEND_COMMAND ' page start address
COM = 4 : GOSUB SEND_COMMAND ' page end address
FOR J = 0 TO 4
FOR I = 0 TO 71
I2CWrite SDA,SCL,I2CDevice,[$40,$FF]
NEXT I
NEXT J
RETURN

flotulopex
- 22nd November 2023, 15:19
BTW, the number of pixels displayed is 50x20

9490

richard
- 22nd November 2023, 19:33
are you using my exact code ?
there are many changes from your orig code including swapping over the scl/sda pins to suit my dev board

i doubt the pullup resistors are needed most modules have then already installed


change
COM = $40 : GOSUB SEND_COMMAND ' set start line address
to
COM = $67 : GOSUB SEND_COMMAND ' set start line address
it looks like display is mapped onto last 5 pages of ram array

flotulopex
- 24th November 2023, 14:37
Are you using my exact code ? Absolutely!

With this "untouched" code, I get this display:
9491

Then, with the new value of $67, here is what I get:
9492

richard
- 24th November 2023, 20:11
try this, looking for full white screen

re pull up resistors for i2c bus , looking at the pic in post #1 that module has none on board , every other module i can find on ebay etc has resistors on board
so you might need them after all




#CONFIG __config _INTRC_OSC_NOCLKOUT & _WDT_ON & _PWRTE_OFF & _MCLRE_ON & _CP_OFF & _CPD_OFF & _BOD_ON & _IESO_ON & _FCMEN_ON
#ENDCONFIG
define OSC 8
OSCCON = 10000 'Internal RC set to 8MHZ
' ====== VARIABLES ================================================== ===============================
I2CDevice var byte
SDA VAR PORTB.6 ' I2C Data
SCL VAR PORTB.4 ' I2C Clock
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)
' ====== INITIALIZE VARIABLES ================================================== ====================
I2CDevice = $78
'======= SSD1306 I2C OLED initialization ================================================== =========
COM = $AE : GOSUB SEND_COMMAND ' turn off oled panel
COM = $D5 : GOSUB SEND_COMMAND ' set display clock divide ratio/oscillator frequency
COM = $80 : GOSUB SEND_COMMAND ' set divide ratio
COM = $A8 : GOSUB SEND_COMMAND ' set multiplex ratio
COM = $3F : GOSUB SEND_COMMAND ' 1/40 duty
COM = $D3 : GOSUB SEND_COMMAND ' set display offset
COM = $0 : GOSUB SEND_COMMAND
COM = $20 : GOSUB SEND_COMMAND
COM = $0 : GOSUB SEND_COMMAND
COM = $AD : GOSUB SEND_COMMAND ' Internal IREF Setting
COM = $30 : GOSUB SEND_COMMAND ' --
COM = $8D : GOSUB SEND_COMMAND ' set Charge Pump enable/disable
COM = $14 : GOSUB SEND_COMMAND ' set(0x10) disable
COM = $68 : GOSUB SEND_COMMAND ' set start line address
COM = $A6 : GOSUB SEND_COMMAND ' set normal display
COM = $A4 : GOSUB SEND_COMMAND ' Disable Entire Display On
COM = $A1 : GOSUB SEND_COMMAND ' set segment re-map 128 to 0
COM = $C8 : GOSUB SEND_COMMAND ' Set COM Output Scan Direction 64 to 0
COM = $DA : GOSUB SEND_COMMAND ' set com pins hardware configuration
COM = $12 : GOSUB SEND_COMMAND '
COM = $81 : GOSUB SEND_COMMAND ' set contrast control register
COM = $7F : GOSUB SEND_COMMAND '
COM = $D9 : GOSUB SEND_COMMAND ' set pre-charge period
COM = $22 : GOSUB SEND_COMMAND '
COM = $DB : GOSUB SEND_COMMAND ' set vcomh
COM = $40 : GOSUB SEND_COMMAND '
COM = $AF : GOSUB SEND_COMMAND ' turn on oled panel


' ====== PROGRAM ================================================== =================================


GOSUB CLEAR_LCD
MAIN:
';7x5 "A"
'X = 15 : Y = 0 : GOSUB SET_7
'I2CWrite SDA,SCL,I2CDevice,[$40,$fc,$12,$12,$12,$fc]
';14x10 "A"
'X = 15 : Y = 2 : GOSUB SET_14
'I2CWrite SDA,SCL,I2CDevice,[$40,$f0,$f8,12,12,14,14,12,12,$f8,$f0_
',$ff,$ff,6,6,6,6,6,6,$ff,$ff]
PAUSE 1000
GOTO MAIN
END
' ====== CLEAR LCD ================================================== ===============================
CLEAR_LCD:
COM = $21 : GOSUB SEND_COMMAND
COM = 20 : GOSUB SEND_COMMAND
COM = 91 : GOSUB SEND_COMMAND
COM = $22 : GOSUB SEND_COMMAND
COM = 0 : GOSUB SEND_COMMAND
COM = 4 : GOSUB SEND_COMMAND
LCD_DATA = $ff
FOR J = 0 TO 4
FOR I = 0 TO 71
I2CWrite SDA,SCL,I2CDevice,[$40,LCD_DATA]
NEXT I
NEXT J
RETURN
' ====== SEND COMMAND ================================================== ============================
SEND_COMMAND:
I2CWrite SDA,SCL,I2CDevice,[0,COM]
RETURN
'======= SET_XY ================================================== ==================================
SET_7: '7x5
COM = $21 : GOSUB SEND_COMMAND
COM = X : GOSUB SEND_COMMAND
COM = x+4 : GOSUB SEND_COMMAND
COM = $22 : GOSUB SEND_COMMAND
COM = Y : GOSUB SEND_COMMAND
COM = y : GOSUB SEND_COMMAND
RETURN
SET_14: ;14x10
COM = $21 : GOSUB SEND_COMMAND
COM = X : GOSUB SEND_COMMAND
COM = x+9 : GOSUB SEND_COMMAND
COM = $22 : GOSUB SEND_COMMAND
COM = Y : GOSUB SEND_COMMAND
COM = y+1 : GOSUB SEND_COMMAND
RETURN

flotulopex
- 24th November 2023, 22:06
Thanks Richard.

This it looks now, with your code ni post #26.



https://drive.google.com/file/d/1Ud4e7x9zEtmkAiGH5nL2YTRGvx_cVtMm/view?usp=drive_link

flotulopex
- 24th November 2023, 22:14
These few changes will fill the whole screen in white.


' ====== CLEAR LCD ================================================== ===============================
CLEAR_LCD:
COM = $21 : GOSUB SEND_COMMAND
COM = 28 : GOSUB SEND_COMMAND
COM = 99 : GOSUB SEND_COMMAND '91
COM = $22 : GOSUB SEND_COMMAND
COM = 0 : GOSUB SEND_COMMAND
COM = 4 : GOSUB SEND_COMMAND
LCD_DATA = $ff
FOR J = 0 TO 4
FOR I = 28 TO 99
I2CWrite SDA,SCL,I2CDevice,[$40,LCD_DATA]
NEXT I
NEXT J
RETURN

richard
- 24th November 2023, 22:24
ok, then this should be pretty close


#CONFIG __config _INTRC_OSC_NOCLKOUT & _WDT_ON & _PWRTE_OFF & _MCLRE_ON & _CP_OFF & _CPD_OFF & _BOD_ON & _IESO_ON & _FCMEN_ON
#ENDCONFIG
define OSC 8
OSCCON = %01110000 'Internal RC set to 8MHZ
' ====== VARIABLES ================================================== ===============================
I2CDevice var byte
SDA VAR PORTB.6 ' I2C Data
SCL VAR PORTB.4 ' I2C Clock
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)
hshift con 28
' ====== INITIALIZE VARIABLES ================================================== ====================
I2CDevice = $78
'======= SSD1306 I2C OLED initialization ================================================== =========
COM = $AE : GOSUB SEND_COMMAND ' turn off oled panel
COM = $D5 : GOSUB SEND_COMMAND ' set display clock divide ratio/oscillator frequency
COM = $80 : GOSUB SEND_COMMAND ' set divide ratio
COM = $A8 : GOSUB SEND_COMMAND ' set multiplex ratio
COM = $3F : GOSUB SEND_COMMAND ' 1/40 duty
COM = $D3 : GOSUB SEND_COMMAND ' set display offset
COM = $0 : GOSUB SEND_COMMAND
COM = $20 : GOSUB SEND_COMMAND
COM = $0 : GOSUB SEND_COMMAND
COM = $AD : GOSUB SEND_COMMAND ' Internal IREF Setting
COM = $30 : GOSUB SEND_COMMAND ' --
COM = $8D : GOSUB SEND_COMMAND ' set Charge Pump enable/disable
COM = $14 : GOSUB SEND_COMMAND ' set(0x10) disable
COM = $68 : GOSUB SEND_COMMAND ' set start line address
COM = $A6 : GOSUB SEND_COMMAND ' set normal display
COM = $A4 : GOSUB SEND_COMMAND ' Disable Entire Display On
COM = $A1 : GOSUB SEND_COMMAND ' set segment re-map 128 to 0
COM = $C8 : GOSUB SEND_COMMAND ' Set COM Output Scan Direction 64 to 0
COM = $DA : GOSUB SEND_COMMAND ' set com pins hardware configuration
COM = $12 : GOSUB SEND_COMMAND '
COM = $81 : GOSUB SEND_COMMAND ' set contrast control register
COM = $7F : GOSUB SEND_COMMAND '
COM = $D9 : GOSUB SEND_COMMAND ' set pre-charge period
COM = $22 : GOSUB SEND_COMMAND '
COM = $DB : GOSUB SEND_COMMAND ' set vcomh
COM = $40 : GOSUB SEND_COMMAND '
COM = $AF : GOSUB SEND_COMMAND ' turn on oled panel


' ====== PROGRAM ================================================== =================================


GOSUB CLEAR_LCD
MAIN:
;7x5 "A"
X = 15 : Y = 0 : GOSUB SET_7
I2CWrite SDA,SCL,I2CDevice,[$40,$fc,$12,$12,$12,$fc]
;14x10 "A"
X = 15 : Y = 2 : GOSUB SET_14
I2CWrite SDA,SCL,I2CDevice,[$40,$f0,$f8,12,12,14,14,12,12,$f8,$f0_
,$ff,$ff,6,6,6,6,6,6,$ff,$ff]
PAUSE 1000
GOTO MAIN
END
' ====== CLEAR LCD ================================================== ===============================
CLEAR_LCD:
COM = $21 : GOSUB SEND_COMMAND
COM = hshift : GOSUB SEND_COMMAND
COM = 71 + hshift : GOSUB SEND_COMMAND
COM = $22 : GOSUB SEND_COMMAND
COM = 0 : GOSUB SEND_COMMAND
COM = 4 : GOSUB SEND_COMMAND
LCD_DATA = 0
FOR J = 0 TO 4
FOR I = 0 TO 71
I2CWrite SDA,SCL,I2CDevice,[$40,LCD_DATA]
NEXT I
NEXT J
RETURN
' ====== SEND COMMAND ================================================== ============================
SEND_COMMAND:
I2CWrite SDA,SCL,I2CDevice,[0,COM]
RETURN
'======= SET_XY ================================================== ==================================
SET_7: '7x5
COM = $21 : GOSUB SEND_COMMAND
COM = X+hshift : GOSUB SEND_COMMAND
COM = x+hshift+4 : GOSUB SEND_COMMAND
COM = $22 : GOSUB SEND_COMMAND
COM = Y : GOSUB SEND_COMMAND
COM = y : GOSUB SEND_COMMAND
RETURN
SET_14: ;14x10
COM = $21 : GOSUB SEND_COMMAND
COM = X+hshift: GOSUB SEND_COMMAND
COM = x+hshift+9 : GOSUB SEND_COMMAND
COM = $22 : GOSUB SEND_COMMAND
COM = Y : GOSUB SEND_COMMAND
COM = y+1 : GOSUB SEND_COMMAND
RETURN

richard
- 24th November 2023, 22:27
the google drive link is a dud

flotulopex
- 24th November 2023, 22:39
I also adjusted your code as:

' ====== PROGRAM ================================================== =================================
GOSUB CLEAR_LCD

MAIN:
'7x5 "A"
X = 28 : Y = 0 : GOSUB SET_7
I2CWrite SDA,SCL,I2CDevice,[$40,$fc,$12,$12,$12,$fc]

'14x10 "A"
X = 28 : Y = 2 : GOSUB SET_14
I2CWrite SDA,SCL,I2CDevice,[$40,$f0,$f8,12,12,14,14,12,12,$f8,$f0_
,$ff,$ff,6,6,6,6,6,6,$ff,$ff]
PAUSE 1000
GOTO MAIN
END

9494

flotulopex
- 24th November 2023, 22:49
the google drive link is a dud

Sorry for that.

How do I post a small video then?

flotulopex
- 24th November 2023, 22:51
Maybe this will work....
https://drive.google.com/file/d/1Ud4e7x9zEtmkAiGH5nL2YTRGvx_cVtMm/view?usp=sharing

richard
- 24th November 2023, 23:11
link worked.


all you need to do now is
1 create a 14x10 font with the chrs you need
2 workout an efficient way to store and retrieve the font
3 develop a nice way to plonk it on the screen

easy as pie
ps
if you only need numbers and "%" ,"." it could fit on a 16f690 easily




hint , pic16 flash memory is 14 bits wide, the ssd1306 can fill memory in vertical mode too

flotulopex
- 24th November 2023, 23:15
Thank you so much Richard!!!

I'll give it a try to create a super big font.

Let you know for any progress in the next days :wink:

flotulopex
- 28th November 2023, 17:06
First look at what it could look like :)

9495

Ioannis
- 28th November 2023, 21:37
It looks great!

Well done Roger!

Ioannis

flotulopex
- 28th November 2023, 22:18
...credits are all for Richard :wink:

richard
- 30th November 2023, 00:33
something to consider about fonts
it looks like you want 40x22 size font
a pic16 has a flash word size of 14 bits therefore a font that size
will take if encoded horizontally by row take 2x40 words per chr
it will take 3x22 words if encoded vertically by column a reasonable saving.

one of the benefits of the ssd1306 controller is that it can address its graphics ram either way with ease
9497

flotulopex
- 3rd December 2023, 08:59
Richard,

I'm still trying to understand your previous post but just for now, there's a question burning my mind: how do I address the display pixel by pixel?

richard
- 3rd December 2023, 09:05
you cannot, the smallest element is 1 byte ie one column[page] of 8 rows

flotulopex
- 3rd December 2023, 18:51
you cannot

Right, so you are talking about using data in a more efficient way using the vertical display mode as described in figure 10-4, correct?

9500

richard
- 3rd December 2023, 19:54
yes , aligning the font data packing with the ssd1306's memory page layout is more efficient usage of the 14 bit width of the flash memory
while it will still need some clever manipulation to unpack it into a 8 bit data stream

9501

flotulopex
- 3rd December 2023, 20:03
Okay, found!

9502

flotulopex
- 6th December 2023, 22:34
Here is a simple code to get started with this 72x40 display.

I also include the SSD1306 command and display's datasheets.

Since I use EXCEL to design characters, here's the sheet you may want to have a look at.

And again, lots of thanks to Richard :wink:

9504

richard
- 7th December 2023, 02:33
You seem to have the communication to the controller well under control
next step is to try to store a font economically, you have probably discovered a large font on a very resource limited chip
like a 690 stored as a series of code structures like
I2CWrite SDA,SCL,I2CDevice,_
[$40,192,224,240,248,252,126,63,63,63,63,63,63,63,6 3,126,252,248,240,224,192,_
255,255,255,255,128,128,128,128,128,128,128,128,12 8,128,128,128,255,255,255,255,_
255,255,255,255,15,15,15,15,15,15,15,15,15,15,15,1 5,255,255,255,255,_
255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,255,255,25 5,255]
will by the time you have 10 digits covered will have blown 75% of the chips flash.
fonts can be stored in much better ways, even expanded out as the are read back

flotulopex
- 7th December 2023, 07:19
fonts can be stored in much better ways

Richard, can you point me the direction to do this?

Should I use some kind of algorithm where repetitive numbers could be stored differently or find a way to make better use of the 14 bits word size of the 16F690?

richard
- 7th December 2023, 08:04
the font is just a simple block of data
this one is for digits 0 to 9 + "." + "%" its 14 bits high and 10 bits wide [to match chip flash]
so total size is 120 words
for convenience lets locate it a the end of flash - 120 words ie. 0xf88
note this is only partially "filled" in and not very carefully at that


asm ;incomplete and very rough font 14x10
org 0xf88
dw 0x1ffc,0x3ffe,0x3006,0x3006,0x3006,0x3006,0x3006,0 x3006,0x3ffe,0x1ffc ;"0"
dw 0,0x300C,0x300E,0x300F,0x3ffF,0x3ffF,0x3ffF,0x3000 ,0x3000,0
dw 0x3806,0x3C07,0x3E03,0x3703,0x3383,0x31E3,0x30F3,0 x307F,0x303E,0
dw 0x3018,0x3006,0x3186,0x3186,0x3186,0x3186,0x3186,0 x3006,0x3cf8,0x1ffc ;"3"
dw 0,0x3ffe,0,0x3ffe,0,0x3ffe,0,0x3ffe,0,0
dw 0,0x3ffe,0,0x3ffe,0x3ffe,0x3ffe,0,0x3ffe,0,0
dw 0x3ffe,0x3ffe,0x3ffe,0,0,0,0,0x3ffe,0x3ffe,0x3ffe
dw 0x3ffe,0x3ffe,0x3ffe,0,0,0x3ffe,0,0x3ffe,0x3ffe,0x 3ffe
dw 0x1ffc,0x3ffe,0x3186,0x3186,0x3186,0x3186,0x3186,0 x3186,0x3ffe,0x1ffc ;"8"
dw 0,0x3ffe,0x3ffe,0x3ffe,0x3ffe,0x3ffe,0x3ffe,0x3ffe ,0x3ffe,0x3ffe
dw 0,0,0,0xE00,0x1F00,0x1F00,0xE00,0,0,0 ;"."
dw 0x181f,0xC11,0x611,0x31f,0x1C0,0x60,0x1F38,0x110c, 0x1106,0x1F02 ;"%"
endasm


normally i would make the font an include and give it a label rather than manually locate it like this
dt's macro as found in dt-ints is ideal to find and numerate the font address

GetAddress macro Label, Wout
CHK?RP Wout
movlw low Label ; get low byte
movwf Wout
movlw High Label ; get high byte
movwf Wout + 1
endm


when the fonts address is known its simple to use readcode command to retrieve font data

flotulopex
- 8th December 2023, 23:04
Just for fun, scrolling text example :wink:

9511

richard
- 9th December 2023, 01:37
i'm not seeing a font , i had a look at a 40x18 font this morning with my new 72x40 that just arrived
encoded this way seems the best compromise for easy of unpacking into a 18 x 5 byte stream to send to display

9512
9513







i dont like most of you inital sfr settings
i would replace the entire section with
OSCCON = $70 ;% 01110000 'Internal RC set to 8MHZ


for these reasons
OPTION_REG = % 10000000 'PORT A&B Pull-Ups disabled (see WPUA & WPUB)
Pull-Ups are set that way by default anyway . that does other things to that may later prove to be incorrect Like set int edge to falling, reassign and alter the prescaler, change timer 0 clock source

OSCCON = % 11100000 'Internal RC set to 8MHZ
no 'OSCCON = % 01110000 for 8mhz you have set it for 4 mhz


ANSEL = % 00010100 'Select analog inputs Channels 0 to 7 (AN2 + AN4 selected)
ok but you then go on to make those pins be digital outputs , not recommended except for smoke generation if used as analog inputs


ADCON0 = % 10000000 'A/D Module (Bit5:2 select channels 0:11)
ADCON1 = % 00000000 'A/D control register
why ? makes no sense adc is off by default


CM1CON0 = % 00000000 'Comparator1 Module is OFF
CM2CON0 = % 00000000 'Comparator2 Module is OFF
why ? Comparator 1 and 2 Modules are OFF by default


INTCON = % 00000000 'INTerrupts CONtrol (TMR0 OFF)
why serves no purpose ints are off by default


TRISA = % 00000000 'Set Input/Output (0 to 5)
bad call when an2
TRISB = % 00000000 'Set Input/Output (4 to 7)
bad call when 4,6 used for i2c
TRISC = % 00000000 'Set Input/Output (0 to 7)
bad call when an4


why ? i2c pins can left as be inputs
when breadboarding leave unused pins as inputs. fine set them as low outputs for the "production" version if a few microwatts of power dissipation makes a difference



PORTB = % 00000000 'Ports High/Low (4 to 7)
why ? i2c pins being set low is not useful

richard
- 9th December 2023, 07:10
i have tried a 14x10 , a 14x10 doubled to 28x20
a 13x7 doubled to 26x14 and tripled to 39x21
they all work ok. imho by leaps and bounds a 40x18 full size font looks best and is only 540 words for ten digits

https://youtu.be/_blpLnHxYH8

flotulopex
- 9th December 2023, 07:12
Richard,

You're absolutely right about the useless register settings I mention in my code.

Most of them, if not all, just reflect their default state as per datasheet.

This is because I use a pic specific template so they are there everytime I start a new project and ready to be deleted in case of no use :wink:

BTW, your video looks great!! :cool:

flotulopex
- 12th December 2023, 16:52
These LCD's are difficult to use. Indeed there are too many parameters to set....

Yes, I agree, this is definitively the hardest part to get it work.

Richard, how did you come to this $68 value please? I can't figure it out :confused:

9514



'======= SSD1306 I2C OLED initialization ================================================== =========
COM = $AE : GOSUB SEND_COMMAND ' turn off OLED panel
COM = $D5 : GOSUB SEND_COMMAND ' set display clock divide ratio/oscillator frequency
COM = $F0 : GOSUB SEND_COMMAND ' set divide ratio
COM = $A8 : GOSUB SEND_COMMAND ' set multiplex ratio
COM = $27 : GOSUB SEND_COMMAND ' 1/40 duty
COM = $D3 : GOSUB SEND_COMMAND ' set display offset
COM = $00 : GOSUB SEND_COMMAND
COM = $40 : GOSUB SEND_COMMAND ' set display start line
COM = $8D : GOSUB SEND_COMMAND ' set Charge Pump enable/disable
COM = $14 : GOSUB SEND_COMMAND ' set(0x10) disable
COM = $20 : GOSUB SEND_COMMAND ' Addressing Setting Command Table
COM = $00 : GOSUB SEND_COMMAND ' Page Addressing Mode
COM = $A1 : GOSUB SEND_COMMAND ' set segment re-map: column address 127 is mapped to SEG0
COM = $C8 : GOSUB SEND_COMMAND ' Set COM Output Scan Direction 64 to 0
COM = $DA : GOSUB SEND_COMMAND ' set com pins hardware configuration
COM = $12 : GOSUB SEND_COMMAND ' Sequential COM pin configuration
COM = $AD : GOSUB SEND_COMMAND ' Internal IREF Setting
COM = $30 : GOSUB SEND_COMMAND ' --
COM = $81 : GOSUB SEND_COMMAND ' set contrast control register
COM = $2F : GOSUB SEND_COMMAND ' set contrast value 0..255
COM = $D9 : GOSUB SEND_COMMAND ' set pre-charge period
COM = $22 : GOSUB SEND_COMMAND ' set pre-charge value
COM = $DB : GOSUB SEND_COMMAND ' set vcomh deselect level
COM = $20 : GOSUB SEND_COMMAND ' set vcomh value
COM = $A4 : GOSUB SEND_COMMAND ' Disable Entire Display On
COM = $A6 : GOSUB SEND_COMMAND ' set normal display
COM = $0C : GOSUB SEND_COMMAND ' set lower column address
COM = $11 : GOSUB SEND_COMMAND ' set higher column address
COM = $68 : GOSUB SEND_COMMAND ' set display start line register
COM = $AF : GOSUB SEND_COMMAND ' turn on OLED panel

richard
- 12th December 2023, 21:09
Richard, how did you come to this $68 value please? I can't figure it out

the info supplied with the display makes calculating the value somewhat difficult . in fact i cannot see the connection at all

the command basically sets where the memory line representing page 0 bit 0 maps to the physical display top row pixels, it can be vertically offset by 0 to 63 pixels in a virtually identical way to the way the display scrolls horizontally

it needed to be offset by -23 pixels to get the top row to align with page 0 bit 0

command range = 0x40 to 0x7f , 0x7f - 23 = 0x68

flotulopex
- 14th December 2023, 12:46
Well, I think I'm just gonna remember this settings "as is".

Thanks for trying to make things more clear for me :wink:

CuriousOne
- 15th December 2023, 05:19
This is very interesting thread, giving me some hope that I will be able to use OLED screens with PBP one day, but I have a quesiton - 24C64 or something like that costs under $1. Why not use it for font storage?

richard
- 16th December 2023, 04:40
I have a quesiton - 24C64 or something like that costs under $1. Why not use it for font storage


because you can save your $1 and another one by buying a better pic to start with and :-

not have a costlier more complex circuit board .
use a standard font file generated by glcd font creator.
its faster, uses hardware i2c and can do proper graphics too.

as i said at the beginning if you want easy get a pic 18

9515

CuriousOne
- 16th December 2023, 06:39
So expensive :)
I'm buying 2nd hand 886 and 1829 for about 50 and 90 cents in China :)
Since I'm not doing anything commercial, this is just fine for me.

CuriousOne
- 16th December 2023, 06:40
And by the way, I don't see any reasons, why you can't write GLCD (which can't save file on windows 10-11) generated or any other software generated font into external EEPROM.

richard
- 16th December 2023, 09:04
don't see any reasons, why you can't write GLCD generated or any other software generated font into external EEPROM.
Nor do I , but I have never come anything to make a bin or hex file easily from the generated code





(which can't save file on windows 10-11)

mine works perfectly win 10 and 11 , make sure to add the .lcd extension to the file name when saving it otherwise it goes funny

tumbleweed
- 16th December 2023, 12:29
Why not use it for font storage?
Because this thread will be followed with "how can I speed up my OLED display routines?".

The choice is obviously yours, but the 18F27Q43 has 128K of flash, 8K of ram, and runs at 64MHz.
The only downside is the hardware I2C peripheral isn't compatible with the old MSSP I2C, so you're stuck using PBP's software I2CWRITE/I2CREAD or rolling your own (which is not trivial for these new parts).