SSD1306 OLED (72x40) I2C display from scratch


+ Reply to Thread
Results 1 to 40 of 74

Hybrid View

  1. #1
    Join Date
    Aug 2006
    Location
    SWITZERLAND (french speaking)
    Posts
    938


    Did you find this post helpful? Yes | No

    Default SSD1306 OLED (72x40) I2C display from scratch

    Thanks a lot Richard.

    The fog lifts somehow a little bit....

    I'll give it a try with y 18F 👍
    Last edited by flotulopex; - 20th November 2023 at 09:36.
    Roger

  2. #2
    Join Date
    May 2013
    Location
    australia
    Posts
    2,652


    Did you find this post helpful? Yes | No

    Default Re: SSD1306 OLED (42x40) I2C display from scratch

    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
    Name:  sd1306.jpg
Views: 14922
Size:  512.8 KB






    #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
    Last edited by richard; - 22nd November 2023 at 02:14.
    Warning I'm not a teacher

  3. #3
    Join Date
    Aug 2006
    Location
    SWITZERLAND (french speaking)
    Posts
    938


    Did you find this post helpful? Yes | No

    Default Re: SSD1306 OLED (42x40) I2C display from scratch

    Thanks a lot Richard.

    I'll give it a try asap
    Roger

  4. #4
    Join Date
    Aug 2006
    Location
    SWITZERLAND (french speaking)
    Posts
    938


    Did you find this post helpful? Yes | No

    Default SSD1306 OLED (72x40) I2C display from scratch

    Voilą.

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

    Name:  Oled.png
Views: 13986
Size:  394.1 KB

    Code:
    ' ====== 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
    Roger

  5. #5
    Join Date
    Aug 2006
    Location
    SWITZERLAND (french speaking)
    Posts
    938


    Did you find this post helpful? Yes | No

    Default SSD1306 OLED (72x40) I2C display from scratch

    BTW, the number of pixels displayed is 50x20

    Name:  OLED detail.png
Views: 13995
Size:  159.1 KB
    Roger

  6. #6
    Join Date
    May 2013
    Location
    australia
    Posts
    2,652


    Did you find this post helpful? Yes | No

    Default Re: SSD1306 OLED (42x40) I2C display from scratch

    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
    Warning I'm not a teacher

  7. #7
    Join Date
    Aug 2006
    Location
    SWITZERLAND (french speaking)
    Posts
    938


    Did you find this post helpful? Yes | No

    Default Re: SSD1306 OLED (72x40) I2C display from scratch

    Are you using my exact code ?
    Absolutely!

    With this "untouched" code, I get this display:
    Name:  org_code_.png
Views: 13689
Size:  372.0 KB

    Then, with the new value of $67, here is what I get:
    Name:  org_code_.png
Views: 13439
Size:  389.5 KB
    Roger

  8. #8
    Join Date
    Oct 2024
    Posts
    3


    Did you find this post helpful? Yes | No

    Default Re: SSD1306 OLED (72x40) I2C display from scratch

    Hi Richard, & all others in the post.

    I've just started out with my OLED display, writing in PIC assembler so I'm presently reading the fine-print on the SSD1306 datasheet to ensure I leave no bits un-turned. I'm cross-referencing my program to others I've found, albeit none in assembler, as such I joined the forum to maybe smooth any glitches I stumble across as this discussion seems rather detailed.

    Although the datasheet shows an approximate Initialise flowchart, I've noticed a few differences (in order) between some of the subroutines I've found:

    An interesting one within the datasheet informs the Set-Charge-Pump command (8Dh) should be followed by the Display On (AFh) command, has yours been okay as such in your Richard?

    Your 'set lower column address' & 'set higher column address', should these variables not be preceded with the actual 'Set Column Address' command, 21h?

    Also, the 'Internal IREF Setting' command ($AD) , where in the datasheet is that command listed, I can find ample references to the Iref current & the calcs etc but can'f find the actual command.

    If your sequence has proved okay, I'll use its order as a reference to set mine up, although I'll set Segment-0 as column-0 just to get it up & running then make changes as required.

    Albeit writes to my CGRAM showed a blank display, as such I've yet to find if it's either my I2C timing (I'm bit banging), (OR) my actual programming sequence, hence firstly confirming the Initialise sequence.

    This is my sequence;

    0AEh ; Set Display OFF. AE h = display OFF, while AF= display ON.
    0D5h ; Set Display Clock Divide Ratio/ Oscillator Frequency.
    80h ; (value)
    0A8h ; Set Multiplex Ratio.
    3Fh ; (value)
    40h ; Set Display Start Line (row) 0 - 63 (40h 7Fh). [as I'm using the 64x32 display]
    20h ; Set Memory Addressing Mode;
    00h ; Three choices, I use the Horizontal mode.
    21h ; Set Column Address;
    00h ; Column start address (0 for me)
    3Fh ; Column end address (63 for me) [as I'm using the 64x32 display]
    22h ; Set Page Address;
    00h ; PAGE start address (0 for me).
    03h ; PAGE end address (3 for me). [as I'm using the 64x32 display]
    81h ; Set Contrast Control.
    0CFh ; (value)
    0D9h ; Set Pre-charge period.
    0F1h ; (value)
    0DBh ; Set VCOMH Deselect Level.
    40h ; (value)
    0A4h ; Entire display on. A4h= Display as per RAM content. A5h= Display is ON, **BUT** unafected by changes to RAM content.
    0A6h ; Set Normal/Inverse Display. A6h= normal, A7h= inverse.
    0x8D ; Set charge pump;
    0x14 ; (value) - ON
    0AFh ; Turn Display ON.

    Mark.
    ------------

    '======= 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

  9. #9
    Join Date
    May 2013
    Location
    australia
    Posts
    2,652


    Did you find this post helpful? Yes | No

    Default Re: SSD1306 OLED (72x40) I2C display from scratch

    Your 'set lower column address' & 'set higher column address', should these variables not be preceded with the actual 'Set Column Address' command, 21h?
    no , that is setting the offset of the actual display as it is overlaid into the memory map

    Also, the 'Internal IREF Setting' command ($AD) , where in the datasheet is that command listed, I can find ample references to the Iref current & the calcs etc but can'f find the actual command.
    its probably not a command at all but a data value that followed the contrast command that's become dislodged in space and time.
    Warning I'm not a teacher

  10. #10
    Join Date
    Oct 2024
    Posts
    3


    Did you find this post helpful? Yes | No

    Default Re: SSD1306 OLED (72x40) I2C display from scratch

    I've just realised I'd wrote your name Richard, instead of Rogers, as it was his initialisation listing I was querying, no worry.

    I see one of Roger's later posts shows the two subsequent bytes, as with the subsequent Page Address command ($22) two bytes.





    The Internal IREF Setting' command ($AD), appears to be listed on older pdf's for the 72x40 type(?), a command not required on later board as set by a resistor.

  11. #11
    Join Date
    Oct 2024
    Posts
    3


    Did you find this post helpful? Yes | No

    Default Re: SSD1306 OLED (72x40) I2C display from scratch

    I've sorted my glitch out, copying a double-byte send I2C section to create the triple byte I'd overlooked the unwanted I2C_Stop call before sending the 3rd byte, so was never seeing it.

    Code:
    ;======
    	call I2C_Start
    	call I2C_Address
    	movlw 00h		; 00=Command stream.
    	movwf I2C_Command_or_Data
    	call I2C_byte
    	movlw 21h		;Column Address;
    	movwf I2C_Command_or_Data
    	call I2C_byte
    	movlw 00h		;  Low column.
    	movwf I2C_Command_or_Data
    	call I2C_byte
    	movlw 3Fh		;  High column.
    	movwf I2C_Command_or_Data
    	call I2C_byte
    	call I2C_Stop
    ;
    ;======
    	call I2C_Start
    	call I2C_Address
    	movlw 00h		; 00=Command stream.
    	movwf I2C_Command_or_Data
    	call I2C_byte
    	movlw 22h		;[3] Page Address;
    	movwf I2C_Command_or_Data
    	call I2C_byte
    	movlw 00h		;  Start page.
    	movwf I2C_Command_or_Data
    	call I2C_byte
    	movlw 03h		; End page.
    	movwf I2C_Command_or_Data
    	call I2C_byte
    	call I2C_Stop
    ;
    I2C_Start
    ;-- Start --
    	bcf PORTA,SDA		;START commence, 
    	call _nops
    	bcf PORTA,SCK		;	START complete.
    	return
    I2C_Address
    ;-- Address_byte --			;= 78h (bit [0] = R/W. Writing, so = 0.
    	bcf PORTA,SDA		;bit 7
    	call clk_it		
    	bsf PORTA,SDA		;bit 6
    	call clk_it		
    	bsf PORTA,SDA		;bit 5
    	call clk_it
    	bsf PORTA,SDA		;bit 4		
    	call clk_it	
    	bsf PORTA,SDA		;bit 3	
    	call clk_it
    	bcf PORTA,SDA		;bit 2	
    	call clk_it
    	bcf PORTA,SDA		;bit 1
    	call clk_it
    	bcf PORTA,SDA		;bit 0 (R/W bit)
    	call clk_it
    ;	return
    ;
    I2C_Ack
    ;-- Ack --
    	bsf STATUS,RP0	;Page 1.
    	bsf TRISA,SDA		;Set as input to release the line
    	bcf STATUS,RP0	;Page 0.
    	call clk_it
    	bsf STATUS,RP0	;Page 1.
    	bcf TRISA,SDA		;Set back to output.
    	bcf STATUS,RP0	;Page 0.
    	return
    ;
    I2C_byte
    ;-- Command or Data byte --
    	movlw 08h		
    	movwf countbits	;count the 8 bits RLF
    byte_bits
    	btfss I2C_Command_or_Data,7
    	goto low_bit1
    	bsf PORTA,SDA
    	goto _clk1
    low_bit1
    	bcf PORTA,SDA
    _clk1	call clk_it
    	decfsz countbits,same
    	goto _rlf
    	goto I2C_Ack ;return
    _rlf	rlf I2C_Command_or_Data
    	goto byte_bits
    ;
    I2C_Stop
    ;-- Stop --
    	bcf PORTA,SDA		;Before STOP, ensure its low.
    	call _nops
    	bsf PORTA,SCK		;STOP commence,
    	call _nops
    	bsf PORTA,SDA		;	STOP completed.
    ;	call _nops
    	call d50mS
    
    	return			;I2C over.

Similar Threads

  1. big char oled display
    By mombasa in forum mel PIC BASIC Pro
    Replies: 2
    Last Post: - 19th September 2020, 07:02
  2. SSD1306 start display problem
    By harryweb in forum mel PIC BASIC Pro
    Replies: 1
    Last Post: - 14th December 2016, 19:16
  3. Cannot drive I2C Oled :(
    By elcrcp in forum mel PIC BASIC Pro
    Replies: 21
    Last Post: - 20th August 2016, 12:19
  4. OLED Display Noise problem
    By gunayburak in forum mel PIC BASIC Pro
    Replies: 24
    Last Post: - 5th July 2016, 10:15
  5. Help With OLED Display / 128X64 SSD1306
    By Denner in forum General
    Replies: 6
    Last Post: - 25th May 2013, 15:40

Members who have read this thread : 22

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts