SSD1306 OLED Screen Help

Andrei IRL

Senior Member
Hello.

I am trying to learn on how to use OLED SSD1306 Screen 128x32 pixels.

I have loaded the code into PICAXE Editor but upon Checking of the code i get an error (see attachment)SSD1306 Error.PNG

Any idea what i might be doing wrong?

I am using chip and not 40M

The code i am trying to use was taken from this thread here

Code:
#picaxe 08m2

setfreq m8

'Constants
Symbol I2CSpeed = i2cfast_8

'I/O pins, C.3&C.4 reserved for I2C
Symbol UpBtnPin = pinB.0
Symbol DnBtnPin = pinB.1
Symbol SelBtnPin = pinB.2

'I2C addresses
Symbol Memory = %10100000
Symbol Display = $3C << 1                      '[$78]

'Display command constants
Symbol TWI_BUFFER_LENGTH = 32 
Symbol LCDWIDTH = 128
Symbol LCDHEIGHT = 64
Symbol SETCONTRAST =0x81
Symbol DISPLAYALLON_RESUME =0xA4
Symbol DISPLAYALLON =0xA5
Symbol NORMALDISPLAY =0xA6
Symbol INVERTDISPLAY =0xA7
Symbol DISPLAYOFF =0xAE
Symbol DISPLAYON =0xAF
Symbol SETDISPLAYOFFSET =0xD3
Symbol SETCOMPINS =0xDA
Symbol SETVCOMDETECT =0xDB
Symbol SETDISPLAYCLOCKDIV =0xD5
Symbol SETPRECHARGE =0xD9
Symbol SETMULTIPLEX =0xA8
Symbol SETLOWCOLUMN =0x00
Symbol SETHIGHCOLUMN =0x10
Symbol SETSTARTLINE =0x40
Symbol MEMORYMODE =0x20
Symbol COLUMNADDR =0x21
Symbol PAGEADDR =0x22
Symbol COMSCANINC =0xC0
Symbol COMSCANDEC =0xC8
Symbol SEGREMAP =0xA0 | 1
Symbol CHARGEPUMP =0x8D
Symbol EXTERNALVCC =0x1
Symbol SWITCHCAPVCC =0x2

'Display scrolling commands
Symbol ACTIVATE_SCROLL =0x2F
Symbol DEACTIVATE_SCROLL =0x2E
Symbol SET_VERTICAL_SCROLL_AREA =0xA3
Symbol HORIZONTAL_SCROLL_RIGHT =0x26
Symbol HORIZONTAL_SCROLL_LEFT =0x27
Symbol VERT_AND_RIGHT_HORIZONTAL =0x29
Symbol VERT_AND_LEFT_HORIZONTAL =0x2A

'Byte variables
Symbol row = b6
Symbol col = b7

init:

b0 = 0
b1 = 0
b2 = 0

pause 500

hi2csetup i2cmaster, Display, I2CSpeed, I2cbyte

hi2cout (0, DISPLAYOFF)
hi2cout (0, SETDISPLAYCLOCKDIV)
hi2cout (0, 0x80)
hi2cout (0, SETMULTIPLEX)
hi2cout (0, 0x3F)
hi2cout (0, SETDISPLAYOFFSET)
hi2cout (0, 0x0)
hi2cout (0, SETSTARTLINE)
hi2cout (0, CHARGEPUMP)
hi2cout (0, 0x14)
hi2cout (0, MEMORYMODE)
hi2cout (0, 0x00)
hi2cout (0, SEGREMAP)
hi2cout (0, COMSCANDEC)
hi2cout (0, SETCOMPINS)
hi2cout (0, 0x12)
hi2cout (0, SETCONTRAST)
hi2cout (0, 0xCF)
hi2cout (0, SETPRECHARGE)
hi2cout (0, 0xF1)
hi2cout (0, SETVCOMDETECT)
hi2cout (0, 0x40)
hi2cout (0, DISPLAYALLON_RESUME)
hi2cout (0, DISPLAYON)

pause 500

main:
  'say something. anything.
  gosub ClearDisplay
  row = 4
  col = 30
  gosub SetPosition

  hi2cout (0x40, 0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00)   'H with extra pixel added for char spacing (8x6 font here)
  hi2cout (0x40, 0x7F, 0x49, 0x49, 0x49, 0x41, 0x00)   'E
  hi2cout (0x40, 0x7F, 0x40, 0x40, 0x40, 0x40, 0x00)   'L
  hi2cout (0x40, 0x7F, 0x40, 0x40, 0x40, 0x40, 0x00)   'L
  hi2cout (0x40, 0x3E, 0x41, 0x41, 0x41, 0x3E, 0x00)   'O

  hi2cout (0x40, 0x00, 0x00, 0x00, 0x00, 0x00)             'space

  hi2cout (0x40, 0x3F, 0x40, 0x38, 0x40, 0x3F, 0x00)   'W
  hi2cout (0x40, 0x3E, 0x41, 0x41, 0x41, 0x3E, 0x00)   'O
  hi2cout (0x40, 0x7F, 0x09, 0x19, 0x29, 0x46, 0x00)   'R
  hi2cout (0x40, 0x7F, 0x40, 0x40, 0x40, 0x40, 0x00)   'L
  hi2cout (0x40, 0x7F, 0x41, 0x41, 0x41, 0x3E, 0x00)   'D
  hi2cout (0x40, 0x00, 0x5F, 0x00, 0x00, 0x00)             '! with the first col removed, looks better
  
  pause 10000
 
goto main	

SetPosition:
  hi2cout (0, PAGEADDR)
  hi2cout (0, row)
  hi2cout (0, 7)

  hi2cout (0, COLUMNADDR)
;  col = col * 5 'columns per character   -   !!! NB not sure what this does or does not !!!
  hi2cout (0, col)
  hi2cout (0, 127)

return

ClearDisplay:

  for b2 = 0 to LCDWIDTH
    hi2cout (0x40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
  next b2

  hi2cout (0, COLUMNADDR)
  hi2cout (0, 0)
  hi2cout (0, 127)
  hi2cout (0, PAGEADDR)
  hi2cout (0, 0)
  hi2cout (0, 7)
  
return



' STANDARD FONT

'table (0x00, 0x00, 0x00, 0x00, 0x00)	' Space
'table (0x00, 0x00, 0x5F, 0x00, 0x00)	' !
'table (0x00, 0x07, 0x00, 0x07, 0x00) ' "
'table (0x14, 0x7F, 0x14, 0x7F, 0x14) ' #
'table (0x24, 0x2A, 0x7F, 0x2A, 0x12) ' $
'table (0x23, 0x13, 0x08, 0x64, 0x62) ' %
'table (0x36, 0x49, 0x56, 0x20, 0x50) ' &
'table (0x00, 0x08, 0x07, 0x03, 0x00) ' '

table (0x00, 0x1C, 0x22, 0x41, 0x00) ' (
table (0x00, 0x41, 0x22, 0x1C, 0x00) ' )
table (0x2A, 0x1C, 0x7F, 0x1C, 0x2A) ' *
table (0x08, 0x08, 0x3E, 0x08, 0x08) ' +
table (0x00, 0x80, 0x70, 0x30, 0x00) ' ,
table (0x08, 0x08, 0x08, 0x08, 0x08)	' -
table (0x00, 0x00, 0x5F, 0x00, 0x0)	' .
table (0x20, 0x10, 0x08, 0x04, 0x02)	' /

table (0x3E, 0x51, 0x49, 0x45, 0x3E)   ;9 : pos40
table (0x00, 0x42, 0x7F, 0x40, 0x00)	 ; 1
table (0x72, 0x49, 0x49, 0x49, 0x46)
table (0x21, 0x41, 0x49, 0x4D, 0x33)
table (0x18, 0x14, 0x12, 0x7F, 0x10)
table (0x27, 0x45, 0x45, 0x45, 0x39)
table (0x3C, 0x4A, 0x49, 0x49, 0x31)
table (0x41, 0x21, 0x11, 0x09, 0x07)
table (0x36, 0x49, 0x49, 0x49, 0x36)
table (0x46, 0x49, 0x49, 0x29, 0x1E)
table (0x00, 0x00, 0x14, 0x00, 0x00)
table (0x00, 0x40, 0x34, 0x00, 0x00)
table (0x00, 0x08, 0x14, 0x22, 0x41)
table (0x14, 0x14, 0x14, 0x14, 0x14)
table (0x00, 0x41, 0x22, 0x14, 0x08)
table (0x02, 0x01, 0x59, 0x09, 0x06)
table (0x3E, 0x41, 0x5D, 0x59, 0x4E)
table (0x7C, 0x12, 0x11, 0x12, 0x7C) ;A most likely and extra blank pixel would need to be added
table (0x7F, 0x49, 0x49, 0x49, 0x36)  ;B
table (0x3E, 0x41, 0x41, 0x41, 0x22)  ;C
table (0x7F, 0x41, 0x41, 0x41, 0x3E)  ;D
table (0x7F, 0x49, 0x49, 0x49, 0x41)  ;E
table (0x7F, 0x09, 0x09, 0x09, 0x01)  ;F
table (0x3E, 0x41, 0x41, 0x51, 0x73)  ;G
table (0x7F, 0x08, 0x08, 0x08, 0x7F)  ;H
table (0x00, 0x41, 0x7F, 0x41, 0x00)  ;I
table (0x20, 0x40, 0x41, 0x3F, 0x01)  ;J
table (0x7F, 0x08, 0x14, 0x22, 0x41)  ;K
table (0x7F, 0x40, 0x40, 0x40, 0x40)  ;L
table (0x7F, 0x02, 0x1C, 0x02, 0x7F)  ;M
table (0x7F, 0x04, 0x08, 0x10, 0x7F)  ;N
table (0x3E, 0x41, 0x41, 0x41, 0x3E)  ;O
table (0x7F, 0x09, 0x09, 0x09, 0x06)  ;P
table (0x3E, 0x41, 0x51, 0x21, 0x5E)  ;Q
table (0x7F, 0x09, 0x19, 0x29, 0x46)  ;R
table (0x26, 0x49, 0x49, 0x49, 0x32)  ;S
table (0x03, 0x01, 0x7F, 0x01, 0x03)  ;T
table (0x3F, 0x40, 0x40, 0x40, 0x3F)   ;U
table (0x1F, 0x20, 0x40, 0x20, 0x1F)   ;V
table (0x3F, 0x40, 0x38, 0x40, 0x3F)   ;W 
table (0x63, 0x14, 0x08, 0x14, 0x63)  ;X
table (0x03, 0x04, 0x78, 0x04, 0x03)  ;Y
table (0x61, 0x59, 0x49, 0x4D, 0x43)	;Z
 

lbenson

Senior Member
Shift left/right not supported on the M2 chips. Instead of "Symbol Display = $3C << 1" use the value indicated in the comment:

Symbol Display = $78

Note that while UpBtnPin is not used in the code you posted, it is defined as pinB.0. B.0 is output only on the 08M2.
 

Andrei IRL

Senior Member
Thanks very much.

Quick qestion, where can i find in the code how to specify the pins for SCL and SDA for the screen?
 

lbenson

Senior Member
Manual 1 specifies the pinouts for each PICAXE. For the 08M2, SCL is C.1 and SDA is C.2 (the B port and the C port are equivalent for the 08M2). So DnBtnPin and SelBtnPin could not be used as defined in the program. When you use the HI2C commands you don't need to specify the pins.
 

Andrei IRL

Senior Member
Manual 1 specifies the pinouts for each PICAXE. For the 08M2, SCL is C.1 and SDA is C.2 (the B port and the C port are equivalent for the 08M2). So DnBtnPin and SelBtnPin could not be used as defined in the program. When you use the HI2C commands you don't need to specify the pins.
Thanks very much for taking the time to reply.

Much appreciated.
 

hippy

Technical Support
Staff member
Quick qestion, where can i find in the code how to specify the pins for SCL and SDA for the screen?
The pins are predefined for the specific PICAXE device, they don't need to be defined within the code but it doesn't do any harm to include them in any list of I/O pin allocations.

Within PE6, in Workspace Explorer, usually to the top left, just below the PICAXE type dropdown selector for there is an "Input/Output Table" link. Click that and you get an editor tab which shows the pinout.
 

Andrei IRL

Senior Member
The pins are predefined for the specific PICAXE device, they don't need to be defined within the code but it doesn't do any harm to include them in any list of I/O pin allocations.

Within PE6, in Workspace Explorer, usually to the top left, just below the PICAXE type dropdown selector for there is an "Input/Output Table" link. Click that and you get an editor tab which shows the pinout.
Thanks very much for that.

I will do that.

And i have just realized that 08m2 chip does not support tables , so have to wait till i receive some more 14M2 chips to try more.
 

lbenson

Senior Member
This compiles for an 08M2, and might even work to print uppercase letters to the OLED.
Code:
' 08LCD_128x64 writes strings to lcd
#picaxe 08M2

'Display command constants
Symbol TWI_BUFFER_LENGTH = 32 
Symbol LCDWIDTH = 128
Symbol LCDHEIGHT = 64
Symbol SETCONTRAST =0x81
Symbol DISPLAYALLON_RESUME =0xA4
Symbol DISPLAYALLON =0xA5
Symbol NORMALDISPLAY =0xA6
Symbol INVERTDISPLAY =0xA7
Symbol DISPLAYOFF =0xAE
Symbol DISPLAYON =0xAF
Symbol SETDISPLAYOFFSET =0xD3
Symbol SETCOMPINS =0xDA
Symbol SETVCOMDETECT =0xDB
Symbol SETDISPLAYCLOCKDIV =0xD5
Symbol SETPRECHARGE =0xD9
Symbol SETMULTIPLEX =0xA8
Symbol SETLOWColUMN =0x00
Symbol SETHIGHColUMN =0x10
Symbol SETSTARTLINE =0x40
Symbol MEMORYMODE =0x20
Symbol COLUMNADDR =0x21
Symbol PAGEADDR =0x22
Symbol COMSCANINC =0xC0
Symbol COMSCANDEC =0xC8
Symbol SEGREMAP =0xA0 | 1
Symbol CHARGEPUMP =0x8D
Symbol EXTERNALVCC =0x1
Symbol SWITCHCAPVCC =0x2

symbol A_addr = 28 ' beginning of upper ram
Symbol I2CSpeed = i2cfast_32
Symbol Display = $78 '       $3C << 1  '[$78]

poke A_addr,0x7C, 0x12, 0x11, 0x12, 0x7C, 0x7F, 0x49, 0x49, 0x49, 0x36, _
            0x3E, 0x41, 0x41, 0x41, 0x22, 0x7F, 0x41, 0x41, 0x41, 0x3E, _
            0x7F, 0x49, 0x49, 0x49, 0x41, 0x7F, 0x09, 0x09, 0x09, 0x01, _
            0x3E, 0x41, 0x41, 0x51, 0x73, 0x7F, 0x08, 0x08, 0x08, 0x7F, _
            0x00, 0x41, 0x7F, 0x41, 0x00, 0x20, 0x40, 0x41, 0x3F, 0x01, _
            0x7F, 0x08, 0x14, 0x22, 0x41, 0x7F, 0x40, 0x40, 0x40, 0x40, _
            0x7F, 0x02, 0x1C, 0x02, 0x7F, 0x7F, 0x04, 0x08, 0x10, 0x7F, _
            0x3E, 0x41, 0x41, 0x41, 0x3E, 0x7F, 0x09, 0x09, 0x09, 0x06, _
            0x3E, 0x41, 0x51, 0x21, 0x5E, 0x7F, 0x09, 0x19, 0x29, 0x46, _
            0x26, 0x49, 0x49, 0x49, 0x32, 0x03, 0x01, 0x7F, 0x01, 0x03, _
            0x3F, 0x40, 0x40, 0x40, 0x3F, 0x1F, 0x20, 0x40, 0x20, 0x1F, _
            0x3F, 0x40, 0x38, 0x40, 0x3F, 0x63, 0x14, 0x08, 0x14, 0x63, _
            0x03, 0x04, 0x78, 0x04, 0x03, 0x61, 0x59, 0x49, 0x4D, 0x43
' above are 5-byte codes for ABCDEFGHIJKLMNOPQRSTUVWXYZ


  setfreq m32
  hi2csetup i2cmaster, Display, I2CSpeed, I2cbyte   'Need to initialise I2C 
  gosub InitDisplay
  b1 = 0 : do : LookUp b1, ( "HELLO WORLD",0 ), b0 
    if b0 <> 0 then : Gosub ShowChar : endif : inc b1
  loop until b0 = 0

  do : loop
  end

ShowChar:
' sertxd(b0)
  if b0 >= "A" and b0 <= "Z" then
      bptr = b0 - "A" * 5 + A_addr ' point to 5 unique char bytes in upper ram
      hi2cout (0x40, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, 0)
    endif
  return
  
  InitDisplay:
  hi2cout (0, DISPLAYOFF)
  hi2cout (0, SETDISPLAYCLOCKDIV)
  hi2cout (0, 0x80)
  hi2cout (0, SETMULTIPLEX)
  hi2cout (0, 0x3F)
  hi2cout (0, SETDISPLAYOFFSET)
  hi2cout (0, 0x0)
  hi2cout (0, SETSTARTLINE)
  hi2cout (0, CHARGEPUMP)
  hi2cout (0, 0x14)
  hi2cout (0, MEMORYMODE)
  hi2cout (0, 0x00)
  hi2cout (0, SEGREMAP)
  hi2cout (0, COMSCANDEC)
  hi2cout (0, SETCOMPINS)
  hi2cout (0, 0x12)
  hi2cout (0, SETCONTRAST)
  hi2cout (0, 0xCF)
  hi2cout (0, SETPRECHARGE)
  hi2cout (0, 0xF1)
  hi2cout (0, SETVCOMDETECT)
  hi2cout (0, 0x40)
  hi2cout (0, DISPLAYALLON_RESUME)
  hi2cout (0, DISPLAYON)
return
Untested. It uses upper ram to store the 5-byte character codes (starting at address 28, above w13 and b27). The 14M2 has 512 minus 28 bytes of upper ram, so it could store the whole printable ascii table below character 128, not just the upper case letters.

The heart of the commands which allow a string to be printed is: LookUp b1, ( "HELLO WORLD",0 ), b0 The DO LOOP which encloses it iterates through each character until it gets to the terminating zero.
 
Last edited:

lbenson

Senior Member
Here's an 08M2 version with upper case letters, numbers, and space.
Code:
' 08OLED_128x64 writes strings to lcd
#picaxe 08M2
#no_data
#terminal 38400

'Display command constants
Symbol TWI_BUFFER_LENGTH = 32 
Symbol LCDWIDTH = 128
Symbol LCDHEIGHT = 64
Symbol SETCONTRAST =0x81
Symbol DISPLAYALLON_RESUME =0xA4
Symbol DISPLAYALLON =0xA5
Symbol NORMALDISPLAY =0xA6
Symbol INVERTDISPLAY =0xA7
Symbol DISPLAYOFF =0xAE
Symbol DISPLAYON =0xAF
Symbol SETDISPLAYOFFSET =0xD3
Symbol SETCOMPINS =0xDA
Symbol SETVCOMDETECT =0xDB
Symbol SETDISPLAYCLOCKDIV =0xD5
Symbol SETPRECHARGE =0xD9
Symbol SETMULTIPLEX =0xA8
Symbol SETLOWColUMN =0x00
Symbol SETHIGHColUMN =0x10
Symbol SETSTARTLINE =0x40
Symbol MEMORYMODE =0x20
Symbol COLUMNADDR =0x21
Symbol PAGEADDR =0x22
Symbol COMSCANINC =0xC0
Symbol COMSCANDEC =0xC8
Symbol SEGREMAP =0xA0 | 1
Symbol CHARGEPUMP =0x8D
Symbol EXTERNALVCC =0x1
Symbol SWITCHCAPVCC =0x2

symbol RAM_base = 28 ' beginning of upper ram
symbol A_addr = 0 ' beginning of upper case letters in eeprom
symbol N_addr = 130 ' beginning numbers in of upper eeprom
Symbol I2CSpeed = i2cfast_32
Symbol Display = $78 '       $3C << 1  '[$78]

'Byte variables
' symbol xb0 = b0 ' used to hold ascii charactor to be written
' symbol xb1 = b1 ' index into string to be written
' symbol xb2 = b2 ' used in ClearDisplay
Symbol ch     = b4
Symbol i      = b5
Symbol row    = b6
Symbol col    = b7
symbol eeAdr = b8

  setfreq m32
  read A_addr,ch
  i = 0x7C ' first of 5 bytes defining pixel pattern for "A"
  if ch <> i then ' eeprom not established
    gosub writeEEPROM
  endif

  hi2csetup i2cmaster, Display, I2CSpeed, I2cbyte   'Need to initialise I2C 
  gosub InitDisplay
  gosub ClearDisplay
  sertxd("08OLED_128x64",cr,lf)
  pause 5000
  row = 0 : col = 0 : gosub SetPosition
'  b1 = 0 : do : LookUp b1, ( "0123456789",0 ), b0 
  b1 = 0 : do : LookUp b1, ( "HELLO WORLD",0 ), b0 
    if b0 <> 0 then : Gosub ShowChar : endif : inc b1
  loop until b0 = 0
  sertxd(cr,lf)
'#rem
  for row = 1 to 7
    col = 0
    sertxd(#row,"/",#col," ")
    gosub SetPosition
    b1 = 0 : do : LookUp b1, ( "LINE ",0 ), b0 
      if b0 <> 0 then : Gosub ShowChar : endif : inc b1
    loop until b0 = 0
    b0 = row + "0" ' display line number
    Gosub ShowChar
    sertxd(cr,lf)
'    pause 32000
  next row
  b1 = 0 : do : LookUp b1, ( " 0123456789",0 ), b0 
    if b0 <> 0 then : Gosub ShowChar : endif : inc b1
  loop until b0 = 0
  sertxd(cr,lf)
'#endrem
  do : loop
  end

ShowChar: ' A-Z, 0-9, space
  sertxd(b0)
  if b0 >= "A" and b0 <= "Z" then
    bptr = RAM_base ' base of upper ram 
    eeAdr = b0 - "A" * 5 + A_addr ' point to 5 unique char bytes in eeprom
    read eeAdr,@bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc ' move from eeprom to ram
    bptr = RAM_base ' base of upper ram 
    hi2cout (0x40, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, 0)
  elseif b0 >= "0" and b0 <= "9" then
    bptr = RAM_base ' base of upper ram 
    eeAdr = b0 - "0" * 5 + N_addr ' point to 5 unique char bytes in eeprom
    read eeAdr,@bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc ' move from eeprom to ram
    bptr = RAM_base ' base of upper ram 
    hi2cout (0x40, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, 0)
  elseif b0 = " " then
    hi2cout (0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0)
  endif
  return

' code below by edmonds: http://www.picaxeforum.co.uk/showthread.php?27651-I2C-OLED-display
  InitDisplay:
  hi2cout (0, DISPLAYOFF)
  hi2cout (0, SETDISPLAYCLOCKDIV)
  hi2cout (0, 0x80)
  hi2cout (0, SETMULTIPLEX)
  hi2cout (0, 0x3F)
  hi2cout (0, SETDISPLAYOFFSET)
  hi2cout (0, 0x0)
  hi2cout (0, SETSTARTLINE)
  hi2cout (0, CHARGEPUMP)
  hi2cout (0, 0x14)
  hi2cout (0, MEMORYMODE)
  hi2cout (0, 0x00)
  hi2cout (0, SEGREMAP)
  hi2cout (0, COMSCANDEC)
  hi2cout (0, SETCOMPINS)
  hi2cout (0, 0x12)
  hi2cout (0, SETCONTRAST)
  hi2cout (0, 0xCF)
  hi2cout (0, SETPRECHARGE)
  hi2cout (0, 0xF1)
  hi2cout (0, SETVCOMDETECT)
  hi2cout (0, 0x40)
  hi2cout (0, DISPLAYALLON_RESUME)
  hi2cout (0, DISPLAYON)
return

SetPosition:
  hi2cout (0, PAGEADDR)
  hi2cout (0, row)
  hi2cout (0, 7)

  hi2cout (0, COLUMNADDR)
;  col = col * 5 'columns per character   -   !!! NB not sure what this does or does not !!!
  hi2cout (0, col)
  hi2cout (0, 127)

return

ClearDisplay:

  for b2 = 0 to LCDWIDTH
    hi2cout (0x40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
  next b2

  hi2cout (0, COLUMNADDR)
  hi2cout (0, 0)
  hi2cout (0, 127)
  hi2cout (0, PAGEADDR)
  hi2cout (0, 0)
  hi2cout (0, 7)
  
return

writeEEPROM:
    pause 32000
    sertxd("invalid check char: ",#ch," not ",0x7c,"; writing eeprom",cr,lf)
    write A_addr, _
            0x7C, 0x12, 0x11, 0x12, 0x7C, 0x7F, 0x49, 0x49, 0x49, 0x36, _
            0x3E, 0x41, 0x41, 0x41, 0x22, 0x7F, 0x41, 0x41, 0x41, 0x3E, _
            0x7F, 0x49, 0x49, 0x49, 0x41, 0x7F, 0x09, 0x09, 0x09, 0x01, _
            0x3E, 0x41, 0x41, 0x51, 0x73, 0x7F, 0x08, 0x08, 0x08, 0x7F, _
            0x00, 0x41, 0x7F, 0x41, 0x00, 0x20, 0x40, 0x41, 0x3F, 0x01, _
            0x7F, 0x08, 0x14, 0x22, 0x41, 0x7F, 0x40, 0x40, 0x40, 0x40, _
            0x7F, 0x02, 0x1C, 0x02, 0x7F, 0x7F, 0x04, 0x08, 0x10, 0x7F, _
            0x3E, 0x41, 0x41, 0x41, 0x3E, 0x7F, 0x09, 0x09, 0x09, 0x06, _
            0x3E, 0x41, 0x51, 0x21, 0x5E, 0x7F, 0x09, 0x19, 0x29, 0x46, _
            0x26, 0x49, 0x49, 0x49, 0x32, 0x03, 0x01, 0x7F, 0x01, 0x03, _
            0x3F, 0x40, 0x40, 0x40, 0x3F, 0x1F, 0x20, 0x40, 0x20, 0x1F, _
            0x3F, 0x40, 0x38, 0x40, 0x3F, 0x63, 0x14, 0x08, 0x14, 0x63, _
            0x03, 0x04, 0x78, 0x04, 0x03, 0x61, 0x59, 0x49, 0x4D, 0x43
' above are 5-byte codes for ABCDEFGHIJKLMNOPQRSTUVWXYZ
    pause 160
    write N_addr, _
            0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00, 0x42, 0x7F, 0x40, 0x00, _
            0x72, 0x49, 0x49, 0x49, 0x46, 0x21, 0x41, 0x49, 0x4D, 0x33, _
            0x18, 0x14, 0x12, 0x7F, 0x10, 0x27, 0x45, 0x45, 0x45, 0x39, _
            0x3C, 0x4A, 0x49, 0x49, 0x31, 0x41, 0x21, 0x11, 0x09, 0x07, _
            0x36, 0x49, 0x49, 0x49, 0x36, 0x46, 0x49, 0x49, 0x29, 0x1E
' above are 5-byte codes for 0123456789
    pause 160
  return
OLED_128x64.jpg
Note that while the text in the photo is blurry, it is crisp on the display itself. I couldn't get my camera or my phone to capture that crispness.

The pixel information for the characters is stored in eeprom. The "LOOKUP" command is utilized to send strings to the OLED.
 
Last edited:

Andrei IRL

Senior Member
Here's an 08M2 version with upper case letters, numbers, and space.
Code:
' 08OLED_128x64 writes strings to lcd
#picaxe 08M2
#no_data
#terminal 38400

'Display command constants
Symbol TWI_BUFFER_LENGTH = 32 
Symbol LCDWIDTH = 128
Symbol LCDHEIGHT = 64
Symbol SETCONTRAST =0x81
Symbol DISPLAYALLON_RESUME =0xA4
Symbol DISPLAYALLON =0xA5
Symbol NORMALDISPLAY =0xA6
Symbol INVERTDISPLAY =0xA7
Symbol DISPLAYOFF =0xAE
Symbol DISPLAYON =0xAF
Symbol SETDISPLAYOFFSET =0xD3
Symbol SETCOMPINS =0xDA
Symbol SETVCOMDETECT =0xDB
Symbol SETDISPLAYCLOCKDIV =0xD5
Symbol SETPRECHARGE =0xD9
Symbol SETMULTIPLEX =0xA8
Symbol SETLOWColUMN =0x00
Symbol SETHIGHColUMN =0x10
Symbol SETSTARTLINE =0x40
Symbol MEMORYMODE =0x20
Symbol COLUMNADDR =0x21
Symbol PAGEADDR =0x22
Symbol COMSCANINC =0xC0
Symbol COMSCANDEC =0xC8
Symbol SEGREMAP =0xA0 | 1
Symbol CHARGEPUMP =0x8D
Symbol EXTERNALVCC =0x1
Symbol SWITCHCAPVCC =0x2

symbol RAM_base = 28 ' beginning of upper ram
symbol A_addr = 0 ' beginning of upper case letters in eeprom
symbol N_addr = 130 ' beginning numbers in of upper eeprom
Symbol I2CSpeed = i2cfast_32
Symbol Display = $78 '       $3C << 1  '[$78]

'Byte variables
' symbol xb0 = b0 ' used to hold ascii charactor to be written
' symbol xb1 = b1 ' index into string to be written
' symbol xb2 = b2 ' used in ClearDisplay
Symbol ch     = b4
Symbol i      = b5
Symbol row    = b6
Symbol col    = b7
symbol eeAdr = b8

  setfreq m32
  read A_addr,ch
  i = 0x7C ' first of 5 bytes defining pixel pattern for "A"
  if ch <> i then ' eeprom not established
    gosub writeEEPROM
  endif

  hi2csetup i2cmaster, Display, I2CSpeed, I2cbyte   'Need to initialise I2C 
  gosub InitDisplay
  gosub ClearDisplay
  sertxd("08OLED_128x64",cr,lf)
  pause 5000
  row = 0 : col = 0 : gosub SetPosition
'  b1 = 0 : do : LookUp b1, ( "0123456789",0 ), b0 
  b1 = 0 : do : LookUp b1, ( "HELLO WORLD",0 ), b0 
    if b0 <> 0 then : Gosub ShowChar : endif : inc b1
  loop until b0 = 0
  sertxd(cr,lf)
'#rem
  for row = 1 to 7
    col = 0
    sertxd(#row,"/",#col," ")
    gosub SetPosition
    b1 = 0 : do : LookUp b1, ( "LINE ",0 ), b0 
      if b0 <> 0 then : Gosub ShowChar : endif : inc b1
    loop until b0 = 0
    b0 = row + "0" ' display line number
    Gosub ShowChar
    sertxd(cr,lf)
'    pause 32000
  next row
  b1 = 0 : do : LookUp b1, ( " 0123456789",0 ), b0 
    if b0 <> 0 then : Gosub ShowChar : endif : inc b1
  loop until b0 = 0
  sertxd(cr,lf)
'#endrem
  do : loop
  end

ShowChar: ' A-Z, 0-9, space
  sertxd(b0)
  if b0 >= "A" and b0 <= "Z" then
    bptr = RAM_base ' base of upper ram 
    eeAdr = b0 - "A" * 5 + A_addr ' point to 5 unique char bytes in eeprom
    read eeAdr,@bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc ' move from eeprom to ram
    bptr = RAM_base ' base of upper ram 
    hi2cout (0x40, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, 0)
  elseif b0 >= "0" and b0 <= "9" then
    bptr = RAM_base ' base of upper ram 
    eeAdr = b0 - "0" * 5 + N_addr ' point to 5 unique char bytes in eeprom
    read eeAdr,@bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc ' move from eeprom to ram
    bptr = RAM_base ' base of upper ram 
    hi2cout (0x40, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, 0)
  elseif b0 = " " then
    hi2cout (0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0)
  endif
  return

' code below by edmonds: http://www.picaxeforum.co.uk/showthread.php?27651-I2C-OLED-display
  InitDisplay:
  hi2cout (0, DISPLAYOFF)
  hi2cout (0, SETDISPLAYCLOCKDIV)
  hi2cout (0, 0x80)
  hi2cout (0, SETMULTIPLEX)
  hi2cout (0, 0x3F)
  hi2cout (0, SETDISPLAYOFFSET)
  hi2cout (0, 0x0)
  hi2cout (0, SETSTARTLINE)
  hi2cout (0, CHARGEPUMP)
  hi2cout (0, 0x14)
  hi2cout (0, MEMORYMODE)
  hi2cout (0, 0x00)
  hi2cout (0, SEGREMAP)
  hi2cout (0, COMSCANDEC)
  hi2cout (0, SETCOMPINS)
  hi2cout (0, 0x12)
  hi2cout (0, SETCONTRAST)
  hi2cout (0, 0xCF)
  hi2cout (0, SETPRECHARGE)
  hi2cout (0, 0xF1)
  hi2cout (0, SETVCOMDETECT)
  hi2cout (0, 0x40)
  hi2cout (0, DISPLAYALLON_RESUME)
  hi2cout (0, DISPLAYON)
return

SetPosition:
  hi2cout (0, PAGEADDR)
  hi2cout (0, row)
  hi2cout (0, 7)

  hi2cout (0, COLUMNADDR)
;  col = col * 5 'columns per character   -   !!! NB not sure what this does or does not !!!
  hi2cout (0, col)
  hi2cout (0, 127)

return

ClearDisplay:

  for b2 = 0 to LCDWIDTH
    hi2cout (0x40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
  next b2

  hi2cout (0, COLUMNADDR)
  hi2cout (0, 0)
  hi2cout (0, 127)
  hi2cout (0, PAGEADDR)
  hi2cout (0, 0)
  hi2cout (0, 7)
  
return

writeEEPROM:
    pause 32000
    sertxd("invalid check char: ",#ch," not ",0x7c,"; writing eeprom",cr,lf)
    write A_addr, _
            0x7C, 0x12, 0x11, 0x12, 0x7C, 0x7F, 0x49, 0x49, 0x49, 0x36, _
            0x3E, 0x41, 0x41, 0x41, 0x22, 0x7F, 0x41, 0x41, 0x41, 0x3E, _
            0x7F, 0x49, 0x49, 0x49, 0x41, 0x7F, 0x09, 0x09, 0x09, 0x01, _
            0x3E, 0x41, 0x41, 0x51, 0x73, 0x7F, 0x08, 0x08, 0x08, 0x7F, _
            0x00, 0x41, 0x7F, 0x41, 0x00, 0x20, 0x40, 0x41, 0x3F, 0x01, _
            0x7F, 0x08, 0x14, 0x22, 0x41, 0x7F, 0x40, 0x40, 0x40, 0x40, _
            0x7F, 0x02, 0x1C, 0x02, 0x7F, 0x7F, 0x04, 0x08, 0x10, 0x7F, _
            0x3E, 0x41, 0x41, 0x41, 0x3E, 0x7F, 0x09, 0x09, 0x09, 0x06, _
            0x3E, 0x41, 0x51, 0x21, 0x5E, 0x7F, 0x09, 0x19, 0x29, 0x46, _
            0x26, 0x49, 0x49, 0x49, 0x32, 0x03, 0x01, 0x7F, 0x01, 0x03, _
            0x3F, 0x40, 0x40, 0x40, 0x3F, 0x1F, 0x20, 0x40, 0x20, 0x1F, _
            0x3F, 0x40, 0x38, 0x40, 0x3F, 0x63, 0x14, 0x08, 0x14, 0x63, _
            0x03, 0x04, 0x78, 0x04, 0x03, 0x61, 0x59, 0x49, 0x4D, 0x43
' above are 5-byte codes for ABCDEFGHIJKLMNOPQRSTUVWXYZ
    pause 160
    write N_addr, _
            0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00, 0x42, 0x7F, 0x40, 0x00, _
            0x72, 0x49, 0x49, 0x49, 0x46, 0x21, 0x41, 0x49, 0x4D, 0x33, _
            0x18, 0x14, 0x12, 0x7F, 0x10, 0x27, 0x45, 0x45, 0x45, 0x39, _
            0x3C, 0x4A, 0x49, 0x49, 0x31, 0x41, 0x21, 0x11, 0x09, 0x07, _
            0x36, 0x49, 0x49, 0x49, 0x36, 0x46, 0x49, 0x49, 0x29, 0x1E
' above are 5-byte codes for 0123456789
    pause 160
  return
View attachment 22203
Note that while the text in the photo is blurry, it is crisp on the display itself. I couldn't get my camera or my phone to capture that crispness.

The pixel information for the characters is stored in eeprom. The "LOOKUP" command is utilized to send strings to the OLED.
Wow, thanks very much for that.

I cant wait to try get the project working.

Just want to say a massive thanks to everyone who replied on this thread,

I really appreciate your time.

And special thanks to Ibenson for the code. I will update here when i get to work on the project this weekend.
 

AllyCat

Senior Member
Hu,

Wouldn't it be easier (and save a lot of program space) to omit the #NO_DATA command and the writeEEPROM: subroutine, and put the character font directly into DATA (or EEPROM) commands? e.g.:

Code:
data  (0x7C, 0x12, 0x11, 0x12, 0x7C)  ; A
data  (0x7F, 0x49, 0x49, 0x49, 0x36)  ; B
data  (0x3E, 0x41, 0x41, 0x41, 0x22, 0x7F, 0x41, 0x41, 0x41, 0x3E)    ; CD
; etc...
The EEPROM can hold 51 characters in that form, but the "top" bit (7) is not used, so you could store data for another 7 (of the less common) symbols in the top bit and/or use the upper RAM (as described before, for 20+ characters) if more are required.

Cheers, Alan.
 

hippy

Technical Support
Staff member
The font table we use for our OLED display is below. That seems to be compatible with what is currently being used, though a different font, slightly taller;

$7C, $12, $11, $12, $7C : Your "A"
$7E, $11, $11, $11, $7E : Our "A"

Code:
eeprom $00, ( $00                 )   ; Unused
eeprom $01, ( $7F,$3E,$1C,$08,$00 )   ; $1A - Right Arrow
eeprom $06, ( $00,$08,$1C,$3E,$7F )   ; $1B - Left Arrow
eeprom $0B, ( $08,$0C,$0E,$0C,$08 )   ; $1C - Up Arrow
eeprom $10, ( $08,$18,$38,$18,$08 )   ; $1D - Down Arrow
eeprom $15, ( $48,$7E,$49,$4A,$00 )   ; $1E - Pound
eeprom $1A, ( $00,$02,$05,$02,$00 )   ; $1F - Degree
eeprom $1F, ( $00,$00,$00,$00,$00 )   ; $20 - Space
eeprom $24, ( $00,$00,$2F,$00,$00 )   ; $21 - Exclamation mark
eeprom $29, ( $00,$07,$00,$07,$00 )   ; $22 - Double quote
eeprom $2E, ( $14,$7F,$14,$7F,$14 )   ; $23 - Hash
eeprom $33, ( $24,$2A,$7F,$2A,$12 )   ; $24 - Dollar sign
eeprom $38, ( $23,$13,$08,$64,$62 )   ; $25 - Percent
eeprom $3D, ( $36,$49,$55,$22,$50 )   ; $26 - Ampersand
eeprom $42, ( $00,$05,$03,$00,$00 )   ; $27 - Single quote
eeprom $47, ( $00,$1C,$22,$41,$00 )   ; $28 - (
eeprom $4C, ( $00,$41,$22,$1C,$00 )   ; $29 - )
eeprom $51, ( $14,$08,$3E,$08,$14 )   ; $2A - Star / Astrix
eeprom $56, ( $08,$08,$3E,$08,$08 )   ; $2B - Plus
eeprom $5B, ( $00,$00,$58,$38,$00 )   ; $2C - Comma
eeprom $60, ( $10,$10,$10,$10,$10 )   ; $2D - Minus
eeprom $65, ( $00,$60,$60,$00,$00 )   ; $2E - Period / Full Stop
eeprom $6A, ( $20,$10,$08,$04,$02 )   ; $2F - /
eeprom $6F, ( $3E,$51,$49,$45,$3E )   ; $30 - 0
eeprom $74, ( $00,$42,$7F,$40,$00 )   ; $31 - 1
eeprom $79, ( $42,$61,$51,$49,$46 )   ; $32 - 2
eeprom $7E, ( $21,$41,$45,$4B,$31 )   ; $33 - 3
eeprom $83, ( $18,$14,$12,$7F,$10 )   ; $34 - 4
eeprom $88, ( $27,$45,$45,$45,$39 )   ; $35 - 5
eeprom $8D, ( $3C,$4A,$49,$49,$30 )   ; $36 - 6
eeprom $92, ( $01,$71,$09,$05,$03 )   ; $37 - 7
eeprom $97, ( $36,$49,$49,$49,$36 )   ; $38 - 8
eeprom $9C, ( $06,$49,$49,$29,$1E )   ; $39 - 9
eeprom $A1, ( $00,$36,$36,$00,$00 )   ; $3A - Colon
eeprom $A6, ( $00,$56,$36,$00,$00 )   ; $3B - Semicolon
eeprom $AB, ( $08,$14,$22,$41,$00 )   ; $3C - <
eeprom $B0, ( $14,$14,$14,$14,$14 )   ; $3D - =
eeprom $B5, ( $00,$41,$22,$14,$08 )   ; $3E - >
eeprom $BA, ( $02,$01,$51,$09,$06 )   ; $3F - ?
eeprom $BF, ( $3E,$41,$19,$25,$3E )   ; $40 - @
eeprom $C4, ( $7E,$11,$11,$11,$7E )   ; $41 - A
eeprom $C9, ( $7F,$49,$49,$49,$36 )   ; $42 - B
eeprom $CE, ( $3E,$41,$41,$41,$22 )   ; $43 - C
eeprom $D3, ( $7F,$41,$41,$22,$1C )   ; $44 - D
eeprom $D8, ( $7F,$49,$49,$49,$41 )   ; $45 - E
eeprom $DD, ( $7F,$09,$09,$09,$01 )   ; $46 - F
eeprom $E2, ( $3E,$41,$49,$49,$7A )   ; $47 - G
eeprom $E7, ( $7F,$08,$08,$08,$7F )   ; $48 - H
eeprom $EC, ( $00,$41,$7F,$41,$00 )   ; $49 - I
eeprom $F1, ( $20,$40,$41,$3F,$01 )   ; $4A - J
eeprom $F6, ( $7F,$08,$14,$22,$41 )   ; $4B - K
eeprom $FB, ( $7F,$40,$40,$40,$40 )   ; $4C - L
table  $00, ( $7F,$02,$0C,$02,$7F )   ; $4D - M
table  $05, ( $7F,$04,$08,$10,$7F )   ; $4E - N
table  $0A, ( $3E,$41,$41,$41,$3E )   ; $4F - O
table  $0F, ( $7F,$09,$09,$09,$06 )   ; $50 - P
table  $14, ( $3E,$41,$51,$21,$5E )   ; $51 - Q
table  $19, ( $7F,$09,$19,$29,$46 )   ; $52 - R
table  $1E, ( $46,$49,$49,$49,$31 )   ; $53 - S
table  $23, ( $01,$01,$7F,$01,$01 )   ; $54 - T
table  $28, ( $3F,$40,$40,$40,$3F )   ; $55 - U
table  $2D, ( $1F,$20,$40,$20,$1F )   ; $56 - V
table  $32, ( $3F,$40,$38,$40,$3F )   ; $57 - W
table  $37, ( $63,$14,$08,$14,$63 )   ; $58 - X
table  $3C, ( $07,$08,$70,$08,$07 )   ; $59 - Y
table  $41, ( $61,$51,$49,$45,$43 )   ; $5A - Z
table  $46, ( $00,$7F,$41,$41,$00 )   ; $5B - [
table  $4B, ( $02,$04,$08,$10,$20 )   ; $5C - Backslash
table  $50, ( $00,$41,$41,$7F,$00 )   ; $5D - ]
table  $55, ( $04,$02,$01,$02,$04 )   ; $5E - Up arrow
table  $5A, ( $40,$40,$40,$40,$40 )   ; $5F - Underscore
table  $5F, ( $00,$01,$02,$04,$00 )   ; $60 - Back tick
table  $64, ( $20,$54,$54,$54,$78 )   ; $61 - a
table  $69, ( $7F,$48,$44,$44,$38 )   ; $62 - b
table  $6E, ( $38,$44,$44,$44,$20 )   ; $63 - c
table  $73, ( $38,$44,$44,$48,$7F )   ; $64 - d
table  $78, ( $38,$54,$54,$54,$18 )   ; $65 - e
table  $7D, ( $08,$7E,$09,$01,$02 )   ; $66 - f
table  $82, ( $0C,$52,$52,$52,$3E )   ; $67 - g
table  $87, ( $7F,$08,$04,$04,$78 )   ; $68 - h
table  $8C, ( $00,$44,$7D,$40,$00 )   ; $69 - i
table  $91, ( $20,$40,$44,$3D,$00 )   ; $6A - j
table  $96, ( $7F,$10,$28,$44,$00 )   ; $6B - k
table  $9B, ( $00,$41,$7F,$40,$00 )   ; $6C - l
table  $A0, ( $7C,$04,$18,$04,$78 )   ; $6D - m
table  $A5, ( $7C,$08,$04,$04,$78 )   ; $6E - n
table  $AA, ( $38,$44,$44,$44,$38 )   ; $6F - o
table  $AF, ( $7C,$14,$14,$14,$08 )   ; $70 - p
table  $B4, ( $08,$14,$14,$18,$7C )   ; $71 - q
table  $B9, ( $7C,$08,$04,$04,$08 )   ; $72 - r
table  $BE, ( $48,$54,$54,$54,$20 )   ; $73 - s
table  $C3, ( $04,$3F,$44,$40,$20 )   ; $74 - t
table  $C8, ( $3C,$40,$40,$20,$7C )   ; $75 - u
table  $CD, ( $1C,$20,$40,$20,$1C )   ; $76 - v
table  $D2, ( $3C,$40,$30,$40,$3C )   ; $77 - w
table  $D7, ( $44,$28,$10,$28,$44 )   ; $78 - x
table  $DC, ( $0C,$50,$50,$50,$3C )   ; $79 - y
table  $E1, ( $44,$64,$54,$4C,$44 )   ; $7A - z
table  $E6, ( $00,$08,$36,$41,$00 )   ; $7B - {
table  $EB, ( $00,$00,$7F,$00,$00 )   ; $7C - Vertical bar
table  $F0, ( $00,$41,$36,$08,$00 )   ; $7D - }
table  $F5, ( $04,$02,$04,$08,$04 )   ; $7E - Tilde
table  $FA, ( $7F,$41,$41,$41,$7F )   ; $7F - Rectangle
table  $FF, ( $0E,$51,$51,$71,$11 )   ; $80 - C,
table $104, ( $38,$42,$40,$42,$38 )   ; $81 - u:
table $109, ( $38,$54,$56,$55,$18 )   ; $82 - e/
table $10E, ( $30,$56,$55,$56,$78 )   ; $83 - a^
table $113, ( $30,$55,$54,$55,$78 )   ; $84 - a:
table $118, ( $30,$55,$56,$54,$78 )   ; $85 - a`
table $11D, ( $30,$54,$55,$54,$78 )   ; $86 - a.
table $122, ( $0E,$51,$71,$11,$00 )   ; $87 - c,
table $127, ( $38,$56,$55,$56,$18 )   ; $88 - e^
table $12C, ( $38,$55,$54,$55,$18 )   ; $89 - e:
table $131, ( $38,$55,$56,$54,$18 )   ; $8A - e`
table $136, ( $00,$49,$78,$41,$00 )   ; $8B - i:
table $13B, ( $00,$4A,$79,$42,$00 )   ; $8C - i^
table $140, ( $00,$49,$7A,$40,$00 )   ; $8D - i`
table $145, ( $78,$15,$14,$15,$78 )   ; $8E - A:
table $14A, ( $70,$2A,$2D,$2A,$70 )   ; $8F - Ao
table $14F, ( $7C,$54,$56,$55,$44 )   ; $90 - E/
table $154, ( $09,$15,$1E,$15,$16 )   ; $91 - s reversed
table $159, ( $7E,$09,$0F,$09,$01 )   ; $92 - fF
table $15E, ( $38,$46,$45,$46,$38 )   ; $93 - O^
table $163, ( $30,$49,$48,$49,$30 )   ; $94 - o:
table $168, ( $30,$49,$4A,$48,$30 )   ; $95 - o`
table $16D, ( $38,$42,$41,$22,$78 )   ; $96 - u^
table $172, ( $38,$41,$42,$20,$78 )   ; $97 - u`
table $177, ( $3C,$41,$42,$20,$78 )   ; $98 - U`
table $17C, ( $0C,$51,$50,$51,$3C )   ; $99 - y:
table $181, ( $3D,$42,$42,$42,$3D )   ; $9A - O:
table $186, ( $79,$0A,$12,$22,$79 )   ; $9B - N~
table $18B, ( $79,$12,$0A,$0A,$71 )   ; $9C - n~
table $190, ( $48,$55,$55,$55,$5E )   ; $9D - a_
table $195, ( $4E,$51,$51,$51,$4E )   ; $9E - o_
table $19A, ( $30,$48,$45,$40,$20 )   ; $9F - ? inverted
table $19F, ( $20,$54,$56,$55,$78 )   ; $A0 - a/
table $1A4, ( $00,$48,$7A,$41,$00 )   ; $A1 - i/
table $1A9, ( $30,$48,$4A,$49,$30 )   ; $A2 - o/
table $1AE, ( $38,$40,$42,$21,$78 )   ; $A3 - u/
table $1B3, ( $0C,$12,$3F,$12,$12 )   ; $A4 - c| cent
table $1B8, ( $48,$7E,$49,$41,$42 )   ; $A5 - ? pound
table $1BD, ( $15,$16,$7C,$16,$15 )   ; $A6 - Y yen
table $1C2, ( $7F,$05,$15,$7A,$50 )   ; $A7 - Pt
table $1C7, ( $40,$48,$3E,$09,$01 )   ; $A8 - f
table $1CC, ( $00,$00,$7A,$00,$00 )   ; $A9 - i
table $1D1, ( $72,$29,$29,$2A,$71 )   ; $AA - A~
table $1D6, ( $22,$51,$55,$56,$79 )   ; $AB - a~
table $1DB, ( $32,$49,$49,$4A,$31 )   ; $AC - o~
table $1E0, ( $3A,$45,$45,$46,$39 )   ; $AD - O~
table $1E5, ( $5C,$32,$2A,$26,$1D )   ; $AE - O slashed
table $1EA, ( $58,$24,$3C,$24,$1A )   ; $AF - o slashed
 

lbenson

Senior Member
Right, Alan--doh! I simply didn't think of it when switching from writing to upper ram to writing to Eeprom. That reduces code size from 1186 to 603 after also adding "."--period, full stop. (I used hippy's 5-byte pixel codes for "."--the codes in the other program gave "!".)
Code:
' 08OLED_128x64 writes strings to lcd
' OLED code by edmonds: http://www.picaxeforum.co.uk/showthread.php?27651-I2C-OLED-display
' font gives 8 lines by 21 characters; characters are 5 pixels wide plus an inter-character space
' lines are 7 pixels high plus an inter-line space. 128/6=21 characters per line; 64/8=8 lines per screen
#picaxe 08M2
'#no_data
#terminal 38400

'Display command constants
Symbol TWI_BUFFER_LENGTH = 32 
Symbol LCDWIDTH = 128
Symbol LCDHEIGHT = 64
Symbol SETCONTRAST =0x81
Symbol DISPLAYALLON_RESUME =0xA4
Symbol DISPLAYALLON =0xA5
Symbol NORMALDISPLAY =0xA6
Symbol INVERTDISPLAY =0xA7
Symbol DISPLAYOFF =0xAE
Symbol DISPLAYON =0xAF
Symbol SETDISPLAYOFFSET =0xD3
Symbol SETCOMPINS =0xDA
Symbol SETVCOMDETECT =0xDB
Symbol SETDISPLAYCLOCKDIV =0xD5
Symbol SETPRECHARGE =0xD9
Symbol SETMULTIPLEX =0xA8
Symbol SETLOWColUMN =0x00
Symbol SETHIGHColUMN =0x10
Symbol SETSTARTLINE =0x40
Symbol MEMORYMODE =0x20
Symbol COLUMNADDR =0x21
Symbol PAGEADDR =0x22
Symbol COMSCANINC =0xC0
Symbol COMSCANDEC =0xC8
Symbol SEGREMAP =0xA0 | 1
Symbol CHARGEPUMP =0x8D
Symbol EXTERNALVCC =0x1
Symbol SWITCHCAPVCC =0x2

symbol RAM_base = 28 ' beginning of upper ram
symbol A_addr = 0 ' beginning of upper case letters in eeprom
symbol N_addr = 130 ' beginning numbers in of upper eeprom
Symbol I2CSpeed = i2cfast_32
Symbol Display = $78 '       $3C << 1  '[$78]

'Byte variables
' symbol xb0 = b0 ' used to hold ascii charactor to be written
' symbol xb1 = b1 ' index into string to be written
' symbol xb2 = b2 ' used in ClearDisplay
Symbol ch     = b4
Symbol i      = b5
Symbol row    = b6
Symbol col    = b7
symbol eeAdr = b8

  setfreq m32
  read A_addr,ch
  i = 0x7C ' first of 5 bytes defining pixel pattern for "A"
  if ch <> i then ' eeprom not established
    gosub writeEEPROM
  endif

  hi2csetup i2cmaster, Display, I2CSpeed, I2cbyte   'Need to initialise I2C 
  gosub InitDisplay
  gosub ClearDisplay
  sertxd("08OLED_128x64",cr,lf)
  pause 5000
  row = 0 : col = 0 : gosub SetPosition
'  b1 = 0 : do : LookUp b1, ( "0123456789",0 ), b0 
  b1 = 0 : do : LookUp b1, ( "HELLO WORLD",0 ), b0 
    if b0 <> 0 then : Gosub ShowChar : endif : inc b1
  loop until b0 = 0
  sertxd(cr,lf)
'#rem
  for row = 1 to 7
    col = 0
    sertxd(#row,"/",#col," ")
    gosub SetPosition
    b1 = 0 : do : LookUp b1, ( "LINE ",0 ), b0 
      if b0 <> 0 then : Gosub ShowChar : endif : inc b1
    loop until b0 = 0
    b0 = row + "0" ' display line number
    Gosub ShowChar
    sertxd(cr,lf)
'    pause 32000
  next row
  b1 = 0 : do : LookUp b1, ( " 0123456789.555",0 ), b0 
    if b0 <> 0 then : Gosub ShowChar : endif : inc b1
  loop until b0 = 0
  sertxd(cr,lf)
'#endrem
  do : loop
  end

ShowChar: ' A-Z, 0-9, space
  sertxd(b0)
  if b0 >= "A" and b0 <= "Z" then
    bptr = RAM_base ' base of upper ram 
    eeAdr = b0 - "A" * 5 + A_addr ' point to 5 unique char bytes in eeprom
    read eeAdr,@bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc ' move from eeprom to ram
    bptr = RAM_base ' base of upper ram 
    hi2cout (0x40, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, 0)
  elseif b0 >= "0" and b0 <= "9" then
    bptr = RAM_base ' base of upper ram 
    eeAdr = b0 - "0" * 5 + N_addr ' point to 5 unique char bytes in eeprom
    read eeAdr,@bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc ' move from eeprom to ram
    bptr = RAM_base ' base of upper ram 
    hi2cout (0x40, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, 0)
  elseif b0 = " " then
    hi2cout (0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0)
  elseif b0 = "." then
    hi2cout (0x40, 0x00, 0x60, 0x60, 0x00, 0x0, 0)
  endif
  return

' code below by edmonds: http://www.picaxeforum.co.uk/showthread.php?27651-I2C-OLED-display
  InitDisplay:
  hi2cout (0, DISPLAYOFF)
  hi2cout (0, SETDISPLAYCLOCKDIV)
  hi2cout (0, 0x80)
  hi2cout (0, SETMULTIPLEX)
  hi2cout (0, 0x3F)
  hi2cout (0, SETDISPLAYOFFSET)
  hi2cout (0, 0x0)
  hi2cout (0, SETSTARTLINE)
  hi2cout (0, CHARGEPUMP)
  hi2cout (0, 0x14)
  hi2cout (0, MEMORYMODE)
  hi2cout (0, 0x00)
  hi2cout (0, SEGREMAP)
  hi2cout (0, COMSCANDEC)
  hi2cout (0, SETCOMPINS)
  hi2cout (0, 0x12)
  hi2cout (0, SETCONTRAST)
  hi2cout (0, 0xCF)
  hi2cout (0, SETPRECHARGE)
  hi2cout (0, 0xF1)
  hi2cout (0, SETVCOMDETECT)
  hi2cout (0, 0x40)
  hi2cout (0, DISPLAYALLON_RESUME)
  hi2cout (0, DISPLAYON)
return

SetPosition:
  hi2cout (0, PAGEADDR)
  hi2cout (0, row)
  hi2cout (0, 7)

  hi2cout (0, COLUMNADDR)
;  col = col * 5 'columns per character   -   !!! NB not sure what this does or does not !!!
  hi2cout (0, col)
  hi2cout (0, 127)

return

ClearDisplay:

  for b2 = 0 to LCDWIDTH
    hi2cout (0x40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
  next b2

  hi2cout (0, COLUMNADDR)
  hi2cout (0, 0)
  hi2cout (0, 127)
  hi2cout (0, PAGEADDR)
  hi2cout (0, 0)
  hi2cout (0, 7)
  
return

writeEEPROM:
    pause 32000
    sertxd("invalid check char: ",#ch," not ",#i,"; writing eeprom",cr,lf)
'    write A_addr, _
    DATA A_addr, ( _
            0x7C, 0x12, 0x11, 0x12, 0x7C, 0x7F, 0x49, 0x49, 0x49, 0x36, _
            0x3E, 0x41, 0x41, 0x41, 0x22, 0x7F, 0x41, 0x41, 0x41, 0x3E, _
            0x7F, 0x49, 0x49, 0x49, 0x41, 0x7F, 0x09, 0x09, 0x09, 0x01, _
            0x3E, 0x41, 0x41, 0x51, 0x73, 0x7F, 0x08, 0x08, 0x08, 0x7F, _
            0x00, 0x41, 0x7F, 0x41, 0x00, 0x20, 0x40, 0x41, 0x3F, 0x01, _
            0x7F, 0x08, 0x14, 0x22, 0x41, 0x7F, 0x40, 0x40, 0x40, 0x40, _
            0x7F, 0x02, 0x1C, 0x02, 0x7F, 0x7F, 0x04, 0x08, 0x10, 0x7F, _
            0x3E, 0x41, 0x41, 0x41, 0x3E, 0x7F, 0x09, 0x09, 0x09, 0x06, _
            0x3E, 0x41, 0x51, 0x21, 0x5E, 0x7F, 0x09, 0x19, 0x29, 0x46, _
            0x26, 0x49, 0x49, 0x49, 0x32, 0x03, 0x01, 0x7F, 0x01, 0x03, _
            0x3F, 0x40, 0x40, 0x40, 0x3F, 0x1F, 0x20, 0x40, 0x20, 0x1F, _
            0x3F, 0x40, 0x38, 0x40, 0x3F, 0x63, 0x14, 0x08, 0x14, 0x63, _
            0x03, 0x04, 0x78, 0x04, 0x03, 0x61, 0x59, 0x49, 0x4D, 0x43) 
' above are 5-byte codes for ABCDEFGHIJKLMNOPQRSTUVWXYZ
    pause 160
'    write N_addr, _
    DATA N_addr, ( _
            0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00, 0x42, 0x7F, 0x40, 0x00, _
            0x72, 0x49, 0x49, 0x49, 0x46, 0x21, 0x41, 0x49, 0x4D, 0x33, _
            0x18, 0x14, 0x12, 0x7F, 0x10, 0x27, 0x45, 0x45, 0x45, 0x39, _
            0x3C, 0x4A, 0x49, 0x49, 0x31, 0x41, 0x21, 0x11, 0x09, 0x07, _
            0x36, 0x49, 0x49, 0x49, 0x36, 0x46, 0x49, 0x49, 0x29, 0x1E)
' above are 5-byte codes for 0123456789
    pause 160
  return
I left in the writeEeprom subroutine as a stub for switching back to writing to upper ram for the 14M2, 18M2+, 20M2 if additional ASCII characters are needed, or the full set.

Hippy's extended codes won't work for the 08M2 because of the absence of table memory, but it's nice to have examples of the pixel map for the full displayable set.

If a few additional characters are needed, the codes for them can be added to the ShowChar routine, using the code for " " and "." as examples.

The code seems snappy enough--about a second for writing the full screen. The font gives 8 lines by 21 characters. If you write more than 21, they wrap around to the beginning of the line (that is, about half of the 22nd character will go at the end of the line and the rest at the beginning).
 
Last edited:

lbenson

Senior Member
Here's a version with a menu.
Code:
' 08OLED_menu ' handles menu on 128x64 oled
' OLED code by edmonds: http://www.picaxeforum.co.uk/showthread.php?27651-I2C-OLED-display
' font gives 8 lines by 21 characters; characters are 5 pixels wide plus an inter-character space
' lines are 7 pixels high plus an inter-line space. 128/6=21 characters per line; 64/8=8 lines per screen
#picaxe 08M2
'#no_data
#terminal 38400

Symbol DnBtnPin = pinC.3

#Macro writeString( string ) 
  b1 = 0 : do : LookUp b1, ( string,0 ), b0 
    if b0 <> 0 then : Gosub ShowChar : endif : inc b1
  loop until b0 = 0
#EndMacro

'Display command constants
Symbol TWI_BUFFER_LENGTH = 32 
Symbol LCDWIDTH = 128
Symbol LCDHEIGHT = 64
Symbol SETCONTRAST =0x81
Symbol DISPLAYALLON_RESUME =0xA4
Symbol DISPLAYALLON =0xA5
Symbol NORMALDISPLAY =0xA6
Symbol INVERTDISPLAY =0xA7
Symbol DISPLAYOFF =0xAE
Symbol DISPLAYON =0xAF
Symbol SETDISPLAYOFFSET =0xD3
Symbol SETCOMPINS =0xDA
Symbol SETVCOMDETECT =0xDB
Symbol SETDISPLAYCLOCKDIV =0xD5
Symbol SETPRECHARGE =0xD9
Symbol SETMULTIPLEX =0xA8
Symbol SETLOWColUMN =0x00
Symbol SETHIGHColUMN =0x10
Symbol SETSTARTLINE =0x40
Symbol MEMORYMODE =0x20
Symbol COLUMNADDR =0x21
Symbol PAGEADDR =0x22
Symbol COMSCANINC =0xC0
Symbol COMSCANDEC =0xC8
Symbol SEGREMAP =0xA0 | 1
Symbol CHARGEPUMP =0x8D
Symbol EXTERNALVCC =0x1
Symbol SWITCHCAPVCC =0x2

symbol RAM_base = 28 ' beginning of upper ram
symbol A_addr = 0 ' beginning of upper case letters in eeprom
symbol N_addr = 130 ' beginning numbers in of upper eeprom
Symbol I2CSpeed = i2cfast_32
Symbol Display = $78 '       $3C << 1  '[$78]
Symbol ACTIVE = 0 ' pushbuttons have weak pullups, active on low
Symbol MAXROW = 7 ' rows 0-7

'Byte variables
' symbol xb0 = b0 ' used to hold ascii charactor to be written
' symbol xb1 = b1 ' index into string to be written
' symbol xb2 = b2 ' used in ClearDisplay
Symbol ch     = b4
Symbol i      = b5
Symbol row    = b6
Symbol col    = b7
symbol eeAdr  = b8
symbol menu   = b9 ' main menu = 0, others 1-7
symbol item   = b10

  setfreq m32
  read A_addr,ch
  i = 0x7C ' first of 5 bytes defining pixel pattern for "A"
  if ch <> i then ' eeprom not established
    gosub writeEEPROM
  endif

  hi2csetup i2cmaster, Display, I2CSpeed, I2cbyte   'Need to initialise I2C 
  gosub InitDisplay
  pullup %11000 ' on 08M2, pullups on C.3 & C.4
  sertxd("08OLED_128x64",cr,lf)
  pause 5000
  gosub displayMenu

main:
  do 
    if DnBtnPin = ACTIVE then
      time = 0
      do : loop while DnBtnPin = ACTIVE ' until button released
      if time > 4 then ' if button held, then select item
        item = row - 1
        sertxd("menu item ",#item," selected",cr,lf)
        if row = MAXROW and menu > 0 then ' return to main menu
          menu = 0
        elseif menu = 0 then
          menu = item
        else
        endif
        
        gosub displayMenu
      else
        gosub SetPosition ' still at beginning of current row
        hi2cout (0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0) ' blank cursor character
        inc row
        if row > MAXROW then : row = 2 : endif ' cycle around
        gosub SetPosition ' beginning of new row
        hi2cout (0x40, 0x00, 0x41, 0x22, 0x14, 0x08, 0) ' cursor char (">")
      endif
    endif
  loop
  end

displayMenu:
  row = 0 : col = 0 : gosub SetPosition
  gosub ClearDisplay
  row = 0 : col = 0 : gosub SetPosition
  if menu = 0 then
    writeString("MAIN MENU")
  else
    writeString("SUBMENU ")
    b0 = "0" + menu : Gosub ShowChar
  endif
  sertxd(cr,lf)
  for row = 2 to 7
    col = 6
'    sertxd(#row,"/",#col," ")
    gosub SetPosition
    if menu = 0 then
      writeString("MENU ITEM ")
    else
      if row = 7 then
        writeString("RETURN")
      else
        writeString("ITEM ")
      endif
    endif
    if menu = 0 or row <> 7 then
      b0 = row + "0" -1 ' display menu item number
      Gosub ShowChar
    endif
    sertxd(cr,lf)
'    pause 32000
  next row
  row = 2 : col = 0 : gosub SetPosition ' First Menu Item
'  b0 = ">" : Gosub ShowChar
   hi2cout (0x40, 0x00, 0x41, 0x22, 0x14, 0x08, 0) ' cursor char (">")
 return

ShowChar: ' A-Z, 0-9, space
  sertxd(b0)
  if b0 >= "A" and b0 <= "Z" then
    bptr = RAM_base ' base of upper ram 
    eeAdr = b0 - "A" * 5 + A_addr ' point to 5 unique char bytes in eeprom
    read eeAdr,@bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc ' move from eeprom to ram
    bptr = RAM_base ' base of upper ram 
    hi2cout (0x40, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, 0)
  elseif b0 >= "0" and b0 <= "9" then
    bptr = RAM_base ' base of upper ram 
    eeAdr = b0 - "0" * 5 + N_addr ' point to 5 unique char bytes in eeprom
    read eeAdr,@bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc ' move from eeprom to ram
    bptr = RAM_base ' base of upper ram 
    hi2cout (0x40, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, 0)
  elseif b0 = " " then
    hi2cout (0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0)
  elseif b0 = "." then
    hi2cout (0x40, 0x00, 0x60, 0x60, 0x00, 0x0, 0)
  elseif b0 = ">" then 
    hi2cout (0x40, 0x00, 0x41, 0x22, 0x14, 0x08, 0)
  endif
  return

' code below by edmonds: http://www.picaxeforum.co.uk/showthread.php?27651-I2C-OLED-display
  InitDisplay:
  hi2cout (0, DISPLAYOFF)
  hi2cout (0, SETDISPLAYCLOCKDIV)
  hi2cout (0, 0x80)
  hi2cout (0, SETMULTIPLEX)
  hi2cout (0, 0x3F)
  hi2cout (0, SETDISPLAYOFFSET)
  hi2cout (0, 0x0)
  hi2cout (0, SETSTARTLINE)
  hi2cout (0, CHARGEPUMP)
  hi2cout (0, 0x14)
  hi2cout (0, MEMORYMODE)
  hi2cout (0, 0x00)
  hi2cout (0, SEGREMAP)
  hi2cout (0, COMSCANDEC)
  hi2cout (0, SETCOMPINS)
  hi2cout (0, 0x12)
  hi2cout (0, SETCONTRAST)
  hi2cout (0, 0xCF)
  hi2cout (0, SETPRECHARGE)
  hi2cout (0, 0xF1)
  hi2cout (0, SETVCOMDETECT)
  hi2cout (0, 0x40)
  hi2cout (0, DISPLAYALLON_RESUME)
  hi2cout (0, DISPLAYON)
return

SetPosition:
  hi2cout (0, PAGEADDR)
  hi2cout (0, row)
  hi2cout (0, 7)

  hi2cout (0, COLUMNADDR)
;  col = col * 5 'columns per character   -   !!! NB not sure what this does or does not !!!
  hi2cout (0, col)
  hi2cout (0, 127)

return

ClearDisplay:
  for b2 = 0 to LCDWIDTH
    hi2cout (0x40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
  next b2
  row = 0 : col = 0 : gosub SetPosition
return

writeEEPROM:
    pause 32000
    sertxd("invalid check char: ",#ch," not ",#i,"; writing eeprom",cr,lf)
'    write A_addr, _
    DATA A_addr, ( _
            0x7C, 0x12, 0x11, 0x12, 0x7C, 0x7F, 0x49, 0x49, 0x49, 0x36, _
            0x3E, 0x41, 0x41, 0x41, 0x22, 0x7F, 0x41, 0x41, 0x41, 0x3E, _
            0x7F, 0x49, 0x49, 0x49, 0x41, 0x7F, 0x09, 0x09, 0x09, 0x01, _
            0x3E, 0x41, 0x41, 0x51, 0x73, 0x7F, 0x08, 0x08, 0x08, 0x7F, _
            0x00, 0x41, 0x7F, 0x41, 0x00, 0x20, 0x40, 0x41, 0x3F, 0x01, _
            0x7F, 0x08, 0x14, 0x22, 0x41, 0x7F, 0x40, 0x40, 0x40, 0x40, _
            0x7F, 0x02, 0x1C, 0x02, 0x7F, 0x7F, 0x04, 0x08, 0x10, 0x7F, _
            0x3E, 0x41, 0x41, 0x41, 0x3E, 0x7F, 0x09, 0x09, 0x09, 0x06, _
            0x3E, 0x41, 0x51, 0x21, 0x5E, 0x7F, 0x09, 0x19, 0x29, 0x46, _
            0x26, 0x49, 0x49, 0x49, 0x32, 0x03, 0x01, 0x7F, 0x01, 0x03, _
            0x3F, 0x40, 0x40, 0x40, 0x3F, 0x1F, 0x20, 0x40, 0x20, 0x1F, _
            0x3F, 0x40, 0x38, 0x40, 0x3F, 0x63, 0x14, 0x08, 0x14, 0x63, _
            0x03, 0x04, 0x78, 0x04, 0x03, 0x61, 0x59, 0x49, 0x4D, 0x43) 
' above are 5-byte codes for ABCDEFGHIJKLMNOPQRSTUVWXYZ
    pause 160
'    write N_addr, _
    DATA N_addr, ( _
            0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00, 0x42, 0x7F, 0x40, 0x00, _
            0x72, 0x49, 0x49, 0x49, 0x46, 0x21, 0x41, 0x49, 0x4D, 0x33, _
            0x18, 0x14, 0x12, 0x7F, 0x10, 0x27, 0x45, 0x45, 0x45, 0x39, _
            0x3C, 0x4A, 0x49, 0x49, 0x31, 0x41, 0x21, 0x11, 0x09, 0x07, _
            0x36, 0x49, 0x49, 0x49, 0x36, 0x46, 0x49, 0x49, 0x29, 0x1E)
' above are 5-byte codes for 0123456789
    pause 160
  return
After a header title on row 0, menu items are presented on rows 2-8, labelled "1"-"7" (starting, on each row, at character position 2). The cursor is shown by the ">" character in the first character position. An active-low button is on pinC.3. Depressing it and immediately releasing caused the cursor to move to the next row. If pressed when on the last row, it moves to row 2. This is a "down" button--there is no "up" button because there are only 6 item rows and then it cycles back to the beginning.

The same button is the select button. If you hold it down for about 3 seconds, the item which the cursor is on will be selected. If on the main menu, this will cause a submenu page to be displayed--again with 6 selectable rows, but the last one is always "RETURN". This is just an example so nothing is done when a submenu item is selected (except that RETURN goes back to the main menu) (and besides, on the 08M2, only C.4 is available).

The LOOKUP statement is in a macro, so all you need to write a string is 'writeString("SOME TEXT")'. This makes the program easier to read. This code takes up 859 bytes. Of course, providing distinct text for each menu item would increase that.

Here is a very poor quality video which illustrates navigating the menus. It's nearly as short as it is bad.
https://youtu.be/Rfh_QO_oCdA
 
Last edited:

Andrei IRL

Senior Member
Guys, what modifications to the code do i need to make to make this work on the 128x32 screen?

At the moment everything is squished :-(
 

lbenson

Senior Member
Offhand, "Symbol LCDHEIGHT = 64" needs to be changed to 32, and everywhere the display is cleared with "hi2cout (0x40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)", there need to be half as many zeroes (I think).

Post screen shots and code if there still are problems.
 
Last edited:

Andrei IRL

Senior Member
This is what i see on the screen at the moment with the current code below:

128x32 Screen.PNG

Code:
' 08OLED_128x64 writes strings to lcd
#picaxe 08M2
#no_data
#terminal 38400

'Display command constants
Symbol TWI_BUFFER_LENGTH = 32 
Symbol LCDWIDTH = 128
Symbol LCDHEIGHT = 32
Symbol SETCONTRAST =0x81
Symbol DISPLAYALLON_RESUME =0xA4
Symbol DISPLAYALLON =0xA5
Symbol NORMALDISPLAY =0xA6
Symbol INVERTDISPLAY =0xA7
Symbol DISPLAYOFF =0xAE
Symbol DISPLAYON =0xAF
Symbol SETDISPLAYOFFSET =0xD3
Symbol SETCOMPINS =0xDA
Symbol SETVCOMDETECT =0xDB
Symbol SETDISPLAYCLOCKDIV =0xD5
Symbol SETPRECHARGE =0xD9
Symbol SETMULTIPLEX =0xA8
Symbol SETLOWColUMN =0x00
Symbol SETHIGHColUMN =0x10
Symbol SETSTARTLINE =0x40
Symbol MEMORYMODE =0x20
Symbol COLUMNADDR =0x21
Symbol PAGEADDR =0x22
Symbol COMSCANINC =0xC0
Symbol COMSCANDEC =0xC8
Symbol SEGREMAP =0xA0 | 1
Symbol CHARGEPUMP =0x8D
Symbol EXTERNALVCC =0x1
Symbol SWITCHCAPVCC =0x2

symbol RAM_base = 28 ' beginning of upper ram
symbol A_addr = 0 ' beginning of upper case letters in eeprom
symbol N_addr = 130 ' beginning numbers in of upper eeprom
Symbol I2CSpeed = i2cfast_32
Symbol Display = $78 '       $3C << 1  '[$78]

'Byte variables
' symbol xb0 = b0 ' used to hold ascii charactor to be written
' symbol xb1 = b1 ' index into string to be written
' symbol xb2 = b2 ' used in ClearDisplay
Symbol ch     = b4
Symbol i      = b5
Symbol row    = b6
Symbol col    = b7
symbol eeAdr = b8

  setfreq m32
  read A_addr,ch
  i = 0x7C ' first of 5 bytes defining pixel pattern for "A"
  if ch <> i then ' eeprom not established
    gosub writeEEPROM
  endif

  hi2csetup i2cmaster, Display, I2CSpeed, I2cbyte   'Need to initialise I2C 
  gosub InitDisplay
  gosub ClearDisplay
  sertxd("08OLED_128x64",cr,lf)
  pause 5000
  row = 0 : col = 0 : gosub SetPosition
'  b1 = 0 : do : LookUp b1, ( "0123456789",0 ), b0 
  b1 = 0 : do : LookUp b1, ( "HELLO WORLD",0 ), b0 
    if b0 <> 0 then : Gosub ShowChar : endif : inc b1
  loop until b0 = 0
  sertxd(cr,lf)
'#rem
  for row = 1 to 7
    col = 0
    sertxd(#row,"/",#col," ")
    gosub SetPosition
    b1 = 0 : do : LookUp b1, ( "LINE ",0 ), b0 
      if b0 <> 0 then : Gosub ShowChar : endif : inc b1
    loop until b0 = 0
    b0 = row + "0" ' display line number
    Gosub ShowChar
    sertxd(cr,lf)
'    pause 32000
  next row
  b1 = 0 : do : LookUp b1, ( " 0123456789",0 ), b0 
    if b0 <> 0 then : Gosub ShowChar : endif : inc b1
  loop until b0 = 0
  sertxd(cr,lf)
'#endrem
  do : loop
  end

ShowChar: ' A-Z, 0-9, space
  sertxd(b0)
  if b0 >= "A" and b0 <= "Z" then
    bptr = RAM_base ' base of upper ram 
    eeAdr = b0 - "A" * 5 + A_addr ' point to 5 unique char bytes in eeprom
    read eeAdr,@bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc ' move from eeprom to ram
    bptr = RAM_base ' base of upper ram 
    hi2cout (0x40, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, 0)
  elseif b0 >= "0" and b0 <= "9" then
    bptr = RAM_base ' base of upper ram 
    eeAdr = b0 - "0" * 5 + N_addr ' point to 5 unique char bytes in eeprom
    read eeAdr,@bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc ' move from eeprom to ram
    bptr = RAM_base ' base of upper ram 
    hi2cout (0x40, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, 0)
  elseif b0 = " " then
    hi2cout (0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0)
  endif
  return

' code below by edmonds: http://www.picaxeforum.co.uk/showthread.php?27651-I2C-OLED-display
  InitDisplay:
  hi2cout (0, DISPLAYOFF)
  hi2cout (0, SETDISPLAYCLOCKDIV)
  hi2cout (0, 0x80)
  hi2cout (0, SETMULTIPLEX)
  hi2cout (0, 0x3F)
  hi2cout (0, SETDISPLAYOFFSET)
  hi2cout (0, 0x0)
  hi2cout (0, SETSTARTLINE)
  hi2cout (0, CHARGEPUMP)
  hi2cout (0, 0x14)
  hi2cout (0, MEMORYMODE)
  hi2cout (0, 0x00)
  hi2cout (0, SEGREMAP)
  hi2cout (0, COMSCANDEC)
  hi2cout (0, SETCOMPINS)
  hi2cout (0, 0x12)
  hi2cout (0, SETCONTRAST)
  hi2cout (0, 0xCF)
  hi2cout (0, SETPRECHARGE)
  hi2cout (0, 0xF1)
  hi2cout (0, SETVCOMDETECT)
  hi2cout (0, 0x40)
  hi2cout (0, DISPLAYALLON_RESUME)
  hi2cout (0, DISPLAYON)
return

SetPosition:
  hi2cout (0, PAGEADDR)
  hi2cout (0, row)
  hi2cout (0, 7)

  hi2cout (0, COLUMNADDR)
;  col = col * 5 'columns per character   -   !!! NB not sure what this does or does not !!!
  hi2cout (0, col)
  hi2cout (0, 127)

return

ClearDisplay:

  for b2 = 0 to LCDWIDTH
    hi2cout (0x40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
  next b2

  hi2cout (0, COLUMNADDR)
  hi2cout (0, 0)
  hi2cout (0, 127)
  hi2cout (0, PAGEADDR)
  hi2cout (0, 0)
  hi2cout (0, 7)
  
return

writeEEPROM:
    pause 32000
    sertxd("invalid check char: ",#ch," not ",0x7c,"; writing eeprom",cr,lf)
    write A_addr, _
            0x7C, 0x12, 0x11, 0x12, 0x7C, 0x7F, 0x49, 0x49, 0x49, 0x36, _
            0x3E, 0x41, 0x41, 0x41, 0x22, 0x7F, 0x41, 0x41, 0x41, 0x3E, _
            0x7F, 0x49, 0x49, 0x49, 0x41, 0x7F, 0x09, 0x09, 0x09, 0x01, _
            0x3E, 0x41, 0x41, 0x51, 0x73, 0x7F, 0x08, 0x08, 0x08, 0x7F, _
            0x00, 0x41, 0x7F, 0x41, 0x00, 0x20, 0x40, 0x41, 0x3F, 0x01, _
            0x7F, 0x08, 0x14, 0x22, 0x41, 0x7F, 0x40, 0x40, 0x40, 0x40, _
            0x7F, 0x02, 0x1C, 0x02, 0x7F, 0x7F, 0x04, 0x08, 0x10, 0x7F, _
            0x3E, 0x41, 0x41, 0x41, 0x3E, 0x7F, 0x09, 0x09, 0x09, 0x06, _
            0x3E, 0x41, 0x51, 0x21, 0x5E, 0x7F, 0x09, 0x19, 0x29, 0x46, _
            0x26, 0x49, 0x49, 0x49, 0x32, 0x03, 0x01, 0x7F, 0x01, 0x03, _
            0x3F, 0x40, 0x40, 0x40, 0x3F, 0x1F, 0x20, 0x40, 0x20, 0x1F, _
            0x3F, 0x40, 0x38, 0x40, 0x3F, 0x63, 0x14, 0x08, 0x14, 0x63, _
            0x03, 0x04, 0x78, 0x04, 0x03, 0x61, 0x59, 0x49, 0x4D, 0x43
' above are 5-byte codes for ABCDEFGHIJKLMNOPQRSTUVWXYZ
    pause 160
    write N_addr, _
            0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00, 0x42, 0x7F, 0x40, 0x00, _
            0x72, 0x49, 0x49, 0x49, 0x46, 0x21, 0x41, 0x49, 0x4D, 0x33, _
            0x18, 0x14, 0x12, 0x7F, 0x10, 0x27, 0x45, 0x45, 0x45, 0x39, _
            0x3C, 0x4A, 0x49, 0x49, 0x31, 0x41, 0x21, 0x11, 0x09, 0x07, _
            0x36, 0x49, 0x49, 0x49, 0x36, 0x46, 0x49, 0x49, 0x29, 0x1E
' above are 5-byte codes for 0123456789
    pause 160
  return
 

Andrei IRL

Senior Member
I have been trying to play around with the example code and to be honest i am struggling.

Is there a simplified code somewhere just to write numbers in the middle of the screen?

What lines of the existing code are responsible for the font side?

For my current project i only really want to display possible one single word and a 2 digit number, or even just the number in the middle of the screen.

Thanks very much in advance.
 

Andrei IRL

Senior Member
I managed to figure out some of the code but not enough to make the letters display fully.

All letters are cut off at the top and bottom.

The line of text on the screen is THIS IS A TEST.

There is something funny going on.

Any idea on how to fix it and possibly make it larger at the same time?

Thank you.

128x32 Screen_1.JPG


Code:
' 08OLED_128x64 writes strings to lcd
#picaxe 08M2
#no_data
#terminal 38400

'Display command constants
Symbol TWI_BUFFER_LENGTH = 32 
Symbol LCDWIDTH = 128
Symbol LCDHEIGHT = 32
Symbol SETCONTRAST =0x81
Symbol DISPLAYALLON_RESUME =0xA4
Symbol DISPLAYALLON =0xA5
Symbol NORMALDISPLAY =0xA6
Symbol INVERTDISPLAY =0xA7
Symbol DISPLAYOFF =0xAE
Symbol DISPLAYON =0xAF
Symbol SETDISPLAYOFFSET =0xD3
Symbol SETCOMPINS =0xDA
Symbol SETVCOMDETECT =0xDB
Symbol SETDISPLAYCLOCKDIV =0xD5
Symbol SETPRECHARGE =0xD9
Symbol SETMULTIPLEX =0xA8
Symbol SETLOWColUMN =0x00
Symbol SETHIGHColUMN =0x10
Symbol SETSTARTLINE =0x40
Symbol MEMORYMODE =0x20
Symbol COLUMNADDR =0x21
Symbol PAGEADDR =0x22
Symbol COMSCANINC =0xC0
Symbol COMSCANDEC =0xC8
Symbol SEGREMAP =0xA0 | 1
Symbol CHARGEPUMP =0x8D
Symbol EXTERNALVCC =0x1
Symbol SWITCHCAPVCC =0x2

symbol RAM_base = 28 ' beginning of upper ram
symbol A_addr = 0 ' beginning of upper case letters in eeprom
symbol N_addr = 130 ' beginning numbers in of upper eeprom
Symbol I2CSpeed = i2cfast_32
Symbol Display = $78 '       $3C << 1  '[$78]

'Byte variables
' symbol xb0 = b0 ' used to hold ascii charactor to be written
' symbol xb1 = b1 ' index into string to be written
' symbol xb2 = b2 ' used in ClearDisplay
Symbol ch     = b4
Symbol i      = b5
Symbol row    = b6
Symbol col    = b7
symbol eeAdr = b8

  setfreq m32
  read A_addr,ch
  i = 0x7C ' first of 5 bytes defining pixel pattern for "A"
  if ch <> i then ' eeprom not established
    gosub writeEEPROM
  endif

  hi2csetup i2cmaster, Display, I2CSpeed, I2cbyte   'Need to initialise I2C 
  gosub InitDisplay
  gosub ClearDisplay
  sertxd("08OLED_128x32",cr,lf)
  pause 5000
  row = 20 : col = 20 : gosub SetPosition
'b1 = 0 : do : LookUp b1, ( "0123456789",0 ), b0 
  b1 = 0 : do : LookUp b1, ( "THIS IS A TEST",0 ), b0 
    if b0 <> 0 then : Gosub ShowChar : endif : inc b1
  loop until b0 = 0
  sertxd(cr,lf)
#rem
  for row = 1 to 7
    col = 0
    sertxd(#row,"/",#col," ")
    gosub SetPosition
    b1 = 0 : do : LookUp b1, ( "LINE ",0 ), b0 
      if b0 <> 0 then : Gosub ShowChar : endif : inc b1
    loop until b0 = 0
    b0 = row + "0" ' display line number
    Gosub ShowChar
    sertxd(cr,lf)
'    pause 32000
  next row
  b1 = 0 : do : LookUp b1, ( " 0123456789",0 ), b0 
    if b0 <> 0 then : Gosub ShowChar : endif : inc b1
  loop until b0 = 0
  sertxd(cr,lf)
#endrem
  do : loop
  end

ShowChar: ' A-Z, 0-9, space
  sertxd(b0)
  if b0 >= "A" and b0 <= "Z" then
    bptr = RAM_base ' base of upper ram 
    eeAdr = b0 - "A" * 5 + A_addr ' point to 5 unique char bytes in eeprom
    read eeAdr,@bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc ' move from eeprom to ram
    bptr = RAM_base ' base of upper ram 
    hi2cout (0x40, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, 0)
  elseif b0 >= "0" and b0 <= "9" then
    bptr = RAM_base ' base of upper ram 
    eeAdr = b0 - "0" * 5 + N_addr ' point to 5 unique char bytes in eeprom
    read eeAdr,@bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc ' move from eeprom to ram
    bptr = RAM_base ' base of upper ram 
    hi2cout (0x40, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, 0)
  elseif b0 = " " then
    hi2cout (0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0)
  endif
  return

' code below by edmonds: http://www.picaxeforum.co.uk/showthread.php?27651-I2C-OLED-display
  InitDisplay:
  hi2cout (0, DISPLAYOFF)
  hi2cout (0, SETDISPLAYCLOCKDIV)
  hi2cout (0, 0x80)
  hi2cout (0, SETMULTIPLEX)
  hi2cout (0, 0x3F)
  hi2cout (0, SETDISPLAYOFFSET)
  hi2cout (0, 0x0)
  hi2cout (0, SETSTARTLINE)
  hi2cout (0, CHARGEPUMP)
  hi2cout (0, 0x14)
  hi2cout (0, MEMORYMODE)
  hi2cout (0, 0x00)
  hi2cout (0, SEGREMAP)
  hi2cout (0, COMSCANDEC)
  hi2cout (0, SETCOMPINS)
  hi2cout (0, 0x12)
  hi2cout (0, SETCONTRAST)
  hi2cout (0, 0xCF)
  hi2cout (0, SETPRECHARGE)
  hi2cout (0, 0xF1)
  hi2cout (0, SETVCOMDETECT)
  hi2cout (0, 0x40)
  hi2cout (0, DISPLAYALLON_RESUME)
  hi2cout (0, DISPLAYON)
return

SetPosition:
  hi2cout (0, PAGEADDR)
  hi2cout (0, row)
  hi2cout (0, 7)

  hi2cout (0, COLUMNADDR)
;  col = col * 5 'columns per character   -   !!! NB not sure what this does or does not !!!
  hi2cout (0, col)
  hi2cout (0, 127)

return

ClearDisplay:

  for b2 = 0 to LCDWIDTH
    hi2cout (0x40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
  next b2

  hi2cout (0, COLUMNADDR)
  hi2cout (0, 0)
  hi2cout (0, 127)
  hi2cout (0, PAGEADDR)
  hi2cout (0, 0)
  hi2cout (0, 7)
  
return

writeEEPROM:
    pause 32000
    sertxd("invalid check char: ",#ch," not ",0x7c,"; writing eeprom",cr,lf)
    write A_addr, _
            0x7C, 0x12, 0x11, 0x12, 0x7C, 0x7F, 0x49, 0x49, 0x49, 0x36, _
            0x3E, 0x41, 0x41, 0x41, 0x22, 0x7F, 0x41, 0x41, 0x41, 0x3E, _
            0x7F, 0x49, 0x49, 0x49, 0x41, 0x7F, 0x09, 0x09, 0x09, 0x01, _
            0x3E, 0x41, 0x41, 0x51, 0x73, 0x7F, 0x08, 0x08, 0x08, 0x7F, _
            0x00, 0x41, 0x7F, 0x41, 0x00, 0x20, 0x40, 0x41, 0x3F, 0x01, _
            0x7F, 0x08, 0x14, 0x22, 0x41, 0x7F, 0x40, 0x40, 0x40, 0x40, _
            0x7F, 0x02, 0x1C, 0x02, 0x7F, 0x7F, 0x04, 0x08, 0x10, 0x7F, _
            0x3E, 0x41, 0x41, 0x41, 0x3E, 0x7F, 0x09, 0x09, 0x09, 0x06, _
            0x3E, 0x41, 0x51, 0x21, 0x5E, 0x7F, 0x09, 0x19, 0x29, 0x46, _
            0x26, 0x49, 0x49, 0x49, 0x32, 0x03, 0x01, 0x7F, 0x01, 0x03, _
            0x3F, 0x40, 0x40, 0x40, 0x3F, 0x1F, 0x20, 0x40, 0x20, 0x1F, _
            0x3F, 0x40, 0x38, 0x40, 0x3F, 0x63, 0x14, 0x08, 0x14, 0x63, _
            0x03, 0x04, 0x78, 0x04, 0x03, 0x61, 0x59, 0x49, 0x4D, 0x43
' above are 5-byte codes for ABCDEFGHIJKLMNOPQRSTUVWXYZ
    pause 160
    write N_addr, _
            0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00, 0x42, 0x7F, 0x40, 0x00, _
            0x72, 0x49, 0x49, 0x49, 0x46, 0x21, 0x41, 0x49, 0x4D, 0x33, _
            0x18, 0x14, 0x12, 0x7F, 0x10, 0x27, 0x45, 0x45, 0x45, 0x39, _
            0x3C, 0x4A, 0x49, 0x49, 0x31, 0x41, 0x21, 0x11, 0x09, 0x07, _
            0x36, 0x49, 0x49, 0x49, 0x36, 0x46, 0x49, 0x49, 0x29, 0x1E
' above are 5-byte codes for 0123456789
    pause 160
  return
 

hippy

Technical Support
Staff member
OLED graphic displays are complicated to work with. One needs to know exactly what model of display one has, what the screen memory mapping is, the command set and configuration used. That does vary between models from the same manufacturer, for example, not all SSD displays are the same.

It can be quite a struggle getting things right. The best advice is to start with displaying a single vertical line of pixels at the top left, then bottom right, enhancing those two two and more vertical lines of pixels.

Set the location being written to before every byte to start with, just in case auto-location incrementing isn't exactly how you want it to be. That can be removed later.

Once it comes to full character display start with single characters top left, bottom right. Displaying "F" and "9" can help ensure that what's being shown is as should be shown.

Diving in with something 'in the middle' is probably going to make things complicated. Your middle might not be what the display has as middle. You may be crossing 'sets of 8 pixel' boundaries and causing odd things to happen. Start with top character line, then next character line.

Although a display may be 128x32 it is probably best to think of it as 21x4 characters, each character 6x8.

Making characters bigger, wider, then taller and then both, should be the last thing to do. That's a case of double writing to make wider, splitting pixels and doubling them up to write across two lines to be taller.
 

lbenson

Senior Member
It looks like the display is acting like it's being told that it has 8 rows of characters, so it's truncating the 8-pixel deep character map to fit into the 4 pixels per row that you have if you divided 32 pixels deep by 8.

I don't know what in the initialization is causing that, and without a datasheet it's hard to guess.

It might have to do with the MEMORYMODE setting. Or in SetPosition you might change (0, 7) to (0, 3). This may be completely wrong.

Also, I would not set "row = 20". It looks to me like the "row" variable is not pixel-oriented (as col is), but it somehow knows how many pixels deep a "row" is. To test, program with "row = 1", "row = 5", etc. to see exactly where the line shows up.

As hippy says, changing the size of the characters will be non-trivial. The font is for a specific 5-wide by 7-deep pixel map per character. You might find something by searching which defines other fonts, but the codes would have to be brought into PICAXE format, as well as the initialization values, as Edmonds did in the post you originally linked to. You might also be able to find non-PICAXE programs which use the 128x32 display, and find clues there.

I won't be able to provide much assistance before Monday--building a boathouse this weekend.
 

hippy

Technical Support
Staff member
As hippy says, changing the size of the characters will be non-trivial. The font is for a specific 5-wide by 7-deep pixel map per character.
That's not too hard; for widening it's just write the vertical pixel row twice.

For doubling height, assuming the 8-pixel vertical row is held in 'b0', top pixel in 'bit0' ...

Code:
bit15 = bit7 : bit14 = bit7
bit13 = bit6 : bit12 = bit6
bit11 = bit5 : bit10 = bit5
bit9  = bit4 : bit8  = bit4
bit7  = bit3 : bit6  = bit3
bit5  = bit2 : bit4  = bit2
bit3  = bit1 : bit2  = bit1
bit1  = bit0
Then write 'b0' to the top line row, 'b1' to the line below it.

For doubling height and widening just double as above then write 'b0' and 'b1' twice.
 

lbenson

Senior Member
In the adafruit c++ library, the only difference I see in initialization other than LCDHEIGHT = 32 is that the value following the SETCOMPINS line is 0x2 instead of 0x12. In the SetPosition routine, the line after "hi2cout (0, row)" is "hi2cout (0, 3)", not 7.

Try those changes and let us know what you see.
 

lbenson

Senior Member
I had a reason to use an SSD1306 128x32 I2C OLED on an 08M2, so I'm revisiting this thread from over 2 years ago. Things appear to have been left unresolved.

I discovered that, at least for the OLED I had, that the 4 lines of 5x8 characters were numbered (for the purpose of setting cursor positions by row) 4-7 rather than 0-3. And hippy's suggestions for double-width and double-width+double-height characters had not been implemented.

I also added space (" ") and period (".") to the numerals in eeprom. Other characters can be added based on hippy's post 14, but you must remember to comment out the line, "i = 0x7C" so that the eeprom is updated.

I2c OLED 128x32a.jpg

Big and Bigger fonts:
I2c OLED 128x32b.jpg
Some of the bigger characters run together with no between-character spacing.
Here's the code:
Code:
' 08OLED_128x32 writes strings to lcd SSD1306
'   Note: for 128x32, row numbers are 4,5,6,7
'   big (double-width) and bigger (double-width+double-height) characters provided for
#picaxe 08M2
#no_data
#terminal 38400

'Display command constants
Symbol TWI_BUFFER_LENGTH = 32 
Symbol LCDWIDTH = 128
Symbol LCDHEIGHT = 32
Symbol SETCONTRAST =0x81
Symbol DISPLAYALLON_RESUME =0xA4
Symbol DISPLAYALLON =0xA5
Symbol NORMALDISPLAY =0xA6
Symbol INVERTDISPLAY =0xA7
Symbol DISPLAYOFF =0xAE
Symbol DISPLAYON =0xAF
Symbol SETDISPLAYOFFSET =0xD3
Symbol SETCOMPINS =0xDA
Symbol SETVCOMDETECT =0xDB
Symbol SETDISPLAYCLOCKDIV =0xD5
Symbol SETPRECHARGE =0xD9
Symbol SETMULTIPLEX =0xA8
Symbol SETLOWColUMN =0x00
Symbol SETHIGHColUMN =0x10
Symbol SETSTARTLINE =0x40
Symbol MEMORYMODE =0x20
Symbol COLUMNADDR =0x21
Symbol PAGEADDR =0x22
Symbol COMSCANINC =0xC0
Symbol COMSCANDEC =0xC8
Symbol SEGREMAP =0xA0 | 1
Symbol CHARGEPUMP =0x8D
Symbol EXTERNALVCC =0x1
Symbol SWITCHCAPVCC =0x2

symbol RAM_base = 28 ' beginning of upper ram
symbol A_addr = 0 ' beginning of upper case letters in eeprom
symbol N_addr = 130 ' beginning numbers in of upper eeprom
Symbol I2CSpeed = i2cfast_32
Symbol Display = $78 '       $3C << 1  '[$78]

'Byte variables
' symbol xb0 = b0 ' reserved for flags
symbol bigFlag   =bit0
symbol biggerFlag=bit1
' symbol xb2 = b2 ' reserved for bigger font
' symbol xb2 = b3 ' reserved for bigger font

Symbol ch     = b4
Symbol i      = b5
Symbol row    = b6
Symbol col    = b7
symbol eeAdr  = b8
Symbol ndx    = b9

  setfreq m32
  read A_addr,ch
  ' comment out following line if eeprom changed
  i = 0x7C ' first of 5 bytes defining pixel pattern for "A"
  if ch <> i then ' eeprom not established
    gosub writeEEPROM
  endif

  hi2csetup i2cmaster, Display, I2CSpeed, I2cbyte   'Need to initialise I2C 
  gosub InitDisplay
  gosub ClearDisplay
  sertxd("08OLED_128x32",cr,lf)
  pause 24000
'  do: loop
  col = 10
 for row=4 to 7 ' rows 1-4 on 128x32
   gosub SetPosition ' 5 works, 15,20
'ndx = 0 : do : LookUp ndx, ( "0123456789",0 ), ch 
  ndx = 0 : do : LookUp ndx, ( "THIS IS A TEST 1.0",0 ), ch 
    if ch <> 0 then : Gosub ShowChar : endif : inc ndx
  loop until ch = 0
  ch=row+"0" : Gosub ShowChar
  sertxd(cr,lf)
  pause 3000
 next row
  pause 40000 ' @32mHa
  row = 5 : col = 5 : gosub SetPosition
  bigFlag=1
  ndx = 0 : do : LookUp ndx, ( "BIG LETTERS ",0 ), ch 
'    if ch <> 0 then : Gosub ShowBigChar : endif : inc ndx
    if ch <> 0 then : Gosub ShowChar : endif : inc ndx
  loop until ch = 0
  bigFlag=0
  sertxd(cr,lf)
row = 6 : gosub SetPosition
  biggerFlag=1
  ndx = 0 : do : LookUp ndx, ( "  BIGGER .5 ",0 ), ch 
'    if ch <> 0 then : Gosub ShowBigChar : endif : inc ndx
    if ch <> 0 then : Gosub ShowBiggerChar : endif : inc ndx
  loop until ch = 0
  biggerFlag=0
  sertxd(cr,lf)
#rem
  for row = 1 to 7
    col = 0
    sertxd(#row,"/",#col," ")
    gosub SetPosition
    b1 = 0 : do : LookUp b1, ( "LINE ",0 ), ch 
      if ch <> 0 then : Gosub ShowChar : endif : inc b1
    loop until ch = 0
    ch = row + "0" ' display line number
    Gosub ShowChar
    sertxd(cr,lf)
'    pause 32000
  next row
  b1 = 0 : do : LookUp b1, ( " 0123456789",0 ), ch 
    if ch <> 0 then : Gosub ShowChar : endif : inc b1
  loop until ch = 0
  sertxd(cr,lf)
#endrem
  do : loop
  end

ShowChar: ' A-Z, 0-9, space
  sertxd(ch)
  if ch >= "A" and ch <= "Z" then
    eeAdr = ch - "A" * 5 + A_addr ' point to 5 unique char bytes in eeprom
  elseif ch >= "0" and ch <= "9" then
    eeAdr = ch - "0" * 5 + N_addr ' point to 5 unique char bytes in eeprom
  elseif ch = " " then
    eeAdr=N_addr+50
  elseif ch = "." then
    eeAdr=N_addr+55
  endif

  bptr = RAM_base ' base of upper ram 
  read eeAdr,@bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc ' move from eeprom to ram
  bptr = RAM_base ' base of upper ram 
  if bigFlag=1 then
    hi2cout (0x40, @bptr, @bptrinc, @bptr, @bptrinc, @bptr, @bptrinc, @bptr, @bptrinc, @bptr, @bptrinc, 0)
  else
    hi2cout (0x40, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, 0)
  endif
  return

ShowBiggerChar: ' A-Z, 0-9, space
  sertxd(ch)
  eeAdr=255
  if ch >= "A" and ch <= "Z" then
    eeAdr = ch - "A" * 5 + A_addr ' point to 5 unique char bytes in eeprom
  elseif ch >= "0" and ch <= "9" then
    eeAdr = ch - "0" * 5 + N_addr ' point to 5 unique char bytes in eeprom
  elseif ch = " " then
    eeAdr=N_addr+50
  elseif ch = "." then
    eeAdr=N_addr+55
  endif
    bptr = RAM_base ' base of upper ram 
    for i=1 to 5 ' for each 5x8 character
'    read eeAdr,@bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc ' move from eeprom to ram
      read eeAdr,b2
      bit24=bit20: bit25=bit20: bit26=bit21: bit27=bit21: bit28=bit22: bit29=bit22: bit30=bit23: bit31=bit23 
      bit23=bit19: bit22=bit19: bit21=bit18: bit20=bit18: bit19=bit17: bit18=bit17: bit17=bit16
      @bptr=b2: bptr=bptr+8: @bptr=b3: bptr=bptr-7
      inc eeAdr
    next i
    bptr = RAM_base ' base of upper ram 
    hi2cout (0x40, @bptr, @bptrinc, @bptr, @bptrinc, @bptr, @bptrinc, @bptr, @bptrinc, @bptr, @bptrinc, 0)
    row=row+1: gosub SetPosition
    bptr = RAM_base+8 ' base of upper ram+offset to bigger font lower half
    hi2cout (0x40, @bptr, @bptrinc, @bptr, @bptrinc, @bptr, @bptrinc, @bptr, @bptrinc, @bptr, @bptrinc, 0)
    row=row-1: col=col+10: gosub SetPosition ' for next character
  return

' code below by edmonds: http://www.picaxeforum.co.uk/showthread.php?27651-I2C-OLED-display
  InitDisplay:
  hi2cout (0, DISPLAYOFF)
  hi2cout (0, SETDISPLAYCLOCKDIV)
  hi2cout (0, 0x80)
  hi2cout (0, SETMULTIPLEX)
  hi2cout (0, 0x3F)
  hi2cout (0, SETDISPLAYOFFSET)
  hi2cout (0, 0x0)
  hi2cout (0, SETSTARTLINE)
  hi2cout (0, CHARGEPUMP)
  hi2cout (0, 0x14)
  hi2cout (0, MEMORYMODE)
  hi2cout (0, 0x00)
  hi2cout (0, SEGREMAP)
  hi2cout (0, COMSCANDEC)
  hi2cout (0, SETCOMPINS)
'  hi2cout (0, 0x12)
  hi2cout (0, 0x02)
  hi2cout (0, SETCONTRAST)
  hi2cout (0, 0xCF)
  hi2cout (0, SETPRECHARGE)
  hi2cout (0, 0xF1)
  hi2cout (0, SETVCOMDETECT)
  hi2cout (0, 0x40)
  hi2cout (0, DISPLAYALLON_RESUME)
  hi2cout (0, DISPLAYON)
return

SetPosition:
  hi2cout (0, PAGEADDR)
  hi2cout (0, row)
  hi2cout (0, 7)

  hi2cout (0, COLUMNADDR)
;  col = col * 5 'columns per character   -   !!! NB not sure what this does or does not !!!
  hi2cout (0, col)
  hi2cout (0, 127)

return

ClearDisplay:

  for i = 0 to LCDWIDTH
    hi2cout (0x40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
  next i

  hi2cout (0, COLUMNADDR)
  hi2cout (0, 0)
  hi2cout (0, 127)
  hi2cout (0, PAGEADDR)
  hi2cout (0, 0)
  hi2cout (0, 7)
  
return

writeEEPROM:
    pause 32000
    sertxd("invalid check char: ",#ch," not ",0x7c,"; writing eeprom",cr,lf)
    write A_addr, _
            0x7C, 0x12, 0x11, 0x12, 0x7C, 0x7F, 0x49, 0x49, 0x49, 0x36, _
            0x3E, 0x41, 0x41, 0x41, 0x22, 0x7F, 0x41, 0x41, 0x41, 0x3E, _
            0x7F, 0x49, 0x49, 0x49, 0x41, 0x7F, 0x09, 0x09, 0x09, 0x01, _
            0x3E, 0x41, 0x41, 0x51, 0x73, 0x7F, 0x08, 0x08, 0x08, 0x7F, _
            0x00, 0x41, 0x7F, 0x41, 0x00, 0x20, 0x40, 0x41, 0x3F, 0x01, _
            0x7F, 0x08, 0x14, 0x22, 0x41, 0x7F, 0x40, 0x40, 0x40, 0x40, _
            0x7F, 0x02, 0x1C, 0x02, 0x7F, 0x7F, 0x04, 0x08, 0x10, 0x7F, _
            0x3E, 0x41, 0x41, 0x41, 0x3E, 0x7F, 0x09, 0x09, 0x09, 0x06, _
            0x3E, 0x41, 0x51, 0x21, 0x5E, 0x7F, 0x09, 0x19, 0x29, 0x46, _
            0x26, 0x49, 0x49, 0x49, 0x32, 0x03, 0x01, 0x7F, 0x01, 0x03, _
            0x3F, 0x40, 0x40, 0x40, 0x3F, 0x1F, 0x20, 0x40, 0x20, 0x1F, _
            0x3F, 0x40, 0x38, 0x40, 0x3F, 0x63, 0x14, 0x08, 0x14, 0x63, _
            0x03, 0x04, 0x78, 0x04, 0x03, 0x61, 0x59, 0x49, 0x4D, 0x43
' above are 5-byte codes for ABCDEFGHIJKLMNOPQRSTUVWXYZ
    pause 160
    write N_addr, _
            0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00, 0x42, 0x7F, 0x40, 0x00, _
            0x72, 0x49, 0x49, 0x49, 0x46, 0x21, 0x41, 0x49, 0x4D, 0x33, _
            0x18, 0x14, 0x12, 0x7F, 0x10, 0x27, 0x45, 0x45, 0x45, 0x39, _
            0x3C, 0x4A, 0x49, 0x49, 0x31, 0x41, 0x21, 0x11, 0x09, 0x07, _
            0x36, 0x49, 0x49, 0x49, 0x36, 0x46, 0x49, 0x49, 0x29, 0x1E, _
            0,0,0,0,0,0x00, 0x60, 0x60, 0x00, 0x00 ' " ","."
' above are 5-byte codes for 0123456789," ","." ' remember to re-write eeprom if changed
    pause 160
  return
 

AllyCat

Senior Member
Hi,

I think I've covered most of those requirements in my recent "A/V Finished Project". There's also this thread which follows on from a previous one, and another from Westaust55 which dealt with "large" characters in about 2007.. There was also another thread where I discussed (Teletext) "character rounding" and I still have more code to post for converting the basic 5 x 8 font to a "Quadruple Height / Double-Width" (rounded) display. Sadly, this time, I seem to have omitted my usual cross-linking between inter-related threads. :(

But ask if you need more detail and I'll do some additional searching. ;)

Cheers, Alan.
 

AllyCat

Senior Member
Hi,

Another three links, I won't edit my previous post as the forum software has a habit of deleting embedded links. :(

https://picaxeforum.co.uk/threads/cheap-i2c-oled-display-with-08m2.29793/page-4.

https://picaxeforum.co.uk/threads/character-rounding-for-double-sized-characters-on-bitmapped-displays-such-as-ssd1306.31923/.

https://picaxeforum.co.uk/threads/large-characters-on-128-x-64-oled.31707/

And I think one of those links references WestAust55's original post from 2008 (I already have his 48 Greek characters converted to add to the 96. :).

Cheers, Alan.
 

WhiteSpace

Well-known member
@lbenson - interesting that your rows are numbered 4-7. Mine are 0-4 - the starting point for the temperature display pictured in post #11 in this thread from a couple of months ago: https://picaxeforum.co.uk/threads/ds18b20-displaying-on-128-x-32-ssd1306-oled-with-08m2.32048/#post-333739 is row 1, column 30, intended to centre the display in the OLED. Happy to share my code (just digits, plus C, temperature symbol and a decimal point), but large font and on an 08M2 with no eeprom, if it's any help, although you're probably better off looking at the code by @AllyCat - he has the advantage of understanding what he's doing!
 

lbenson

Senior Member
Thanks for the posts--I guess I didn't search thoroughly enough--or look through what I had found after I thought the first thread I looked at got me close enough. So now I guess there are at least 4 working examples for the 128x32 ssd1306 oled with at least somewhat different approaches and different fonts.

These little I2C OLEDs are handy. What I have working is satisfactory for my needs at present.
 

lbenson

Senior Member
Just to round out this thread, understanding that other threads have their own solutions, here's code for the full printable ascii character set (" "-"~") taken from hippy's post 14 and put into table memory for the 14M2 and 20M2:
OLED_128x64_abcd.jpg
As before, the actual OLED text is crisp (if tiny).

Code exceeds 10000 characters so I had to zip it.
 

Attachments

Top