OS96016PP08MB2B10 i2c SSD0303 OLED Display - Text Demo

nick12ab

Senior Member
Revisiting the OS96016PP08MB2B10 OLED Display (available in the Kemo Electronic S043 lucky bag) with a new demo - one for text.

This OLED does not have a built in character set so text needs to be stored in a lookup table of some sort on the PICAXE. I used the lookup command with data taken from here but M2 parts have 512 bytes of table memory so that can be used instead for a more limited character set.

The schematic

The schematic assumes use of the breakout board shown in the blog entry and positioning of the OLED Display at the far right of said breakout board as shown in this picture. The pin numbers that are shown in my schematic match those in the datasheet.



The 7660s are due to not having the correct inductor to use the built-in voltage boost circuit, but you can use the voltage boost circuit if you get the right inductor (see datasheet) or even use a 9V battery as long as it is not connected to the OLED when the low voltage power (3V) is not present (a transistor could be used for this).

If you obtain suitable components (required properties are shown in Table 3 (in the datasheet) such as the inductor needing >0.5A current rating), then you should be able to get a working voltage booster circuit to generate the voltage required for the OLED once you use the command to turn on the voltage booster circuit:
Code:
hi2cout 0,(%10101101,%10001011)	'Turn on DC-DC
If it's a project where you want to blank the OLED when not in use to save power, then you can turn off the DC-DC converter - you can find out how to do this in the datasheet. :)

Inserting the resistor values from the datasheet (they're what I used) into this formula for the output voltage of the booster Vcc = 1.2*(R1+R2)/R2 results in a calculated voltage of 12.1V. However when I measured the output of the booster using a multimeter (whilst the booster was powering the OLED with contrast set to $7F) the voltage was 12.2V when there was normal text on the display but when all the pixels were turned on it dropped to 11.6V.

It's likely that a component I used has an inferior property that I overlooked compared to the components they chose. This has no noticeable effect on brightness but it's consuming 90mA at 3.3V and just 3-4mA (varies according to screen content) at ~12V is being consumed by the display making it less than 20% efficient. I used a 1N5817 diode, BS170 MOSFET and capacitors and resistors with the same values. Can anyone help with this?

Just to clear up any confusion, any pins on the OLED board that are 'touched' by a wire in the schematic are connected to that wire. One of the i2c lines are connected to two pins on the OLED because the OLED uses separate pins for serial data input and serial data output and these need to be kept separate for SPI or connected together for i2c which uses a bidirectional data bus. This demo uses i2c and a PICAXE-14M2.

The Demo

This demo displays the message you see below, then a screen with all pixels lit, then it shows all the characters in the character set on screen in groups of 32 (16 per line).


[Click for high resolution]


The correct part number is OS96016PP08MB2B10 but that is 17 characters, so can't all be displayed on one line. therefore only the first 16 characters are shown in the picture.

An unfortunate drawback of the PICAXE system is that due to the slow interpreter you can see the characters being sequentially written to the OLED. This could be improved by use of a 64MHz X2 part or a smaller character set, but it's never going to be perfect on a PICAXE. At least it's not intolerably slow.

OLED commands that use more than one byte have their extra bytes sent in the same hi2cout command as the first byte, without any extra 0s.

Now I have to split this up into two posts because of the text length limit in forum posts - this post is too long now that I have added the bit about the voltage booster circuit.
 
Last edited:

nick12ab

Senior Member
The code
Code:
#picaxe 14m2
#no_end
#no_data
symbol loopcounter = b4
symbol executebyte = b5
symbol cb1 = b7
symbol cb2 = b6
symbol cb3 = b9
symbol cb4 = b8
symbol cb5 = b11
symbol cb6 = b10
symbol cw1 = w3
symbol cw2 = w4
symbol cw3 = w5

main:
	setfreq m32
	hi2csetup i2cmaster,%01111000,i2cslow_32,i2cbyte
	pause 150
	hi2cout 0,(%10100100)			'Set entire display on/[normal]
	hi2cout 0,(%10101000,15)		'Multiplex rate command (set to 15+1 rows)
	hi2cout 0,(%11010101,%01110000)	'Set display clock to defaults
	hi2cout 0,(%10110000)			'Set page address for read/write to 0
	hi2cout 0,(%11000000)			'Set scan direction
	hi2cout 0,($81,$7F)			'Set contrast
	hi2cout 0,(%10100110)			'Set display [normal]/inverse
	hi2cout 0,(%10101101,%10001011)	'Turn on DC-DC
	hi2cout 0,(%11011000,%00000101)	'Enable "low power mode" (whatever that does)
	hi2cout 0,(%10101111)		'Turn on display
	
	do
		hi2cout 0,(%10110000)		'Top line
		hi2cout 0,($00,$10)		'Reset column register
		for loopcounter = 0 to 16
			lookup loopcounter,("OS96016PP08MB2B10"),executebyte
			gosub printchar
		next
		hi2cout 0,(%10110001)		'Bottom line
		hi2cout 0,($00,$10)		'Reset column register
		for loopcounter = 0 to 15
			lookup loopcounter,(" OLED on PICAXE "),executebyte
			gosub printchar
		next
		pause 32000
		hi2cout 0,(%10110000)		'Top line
		hi2cout 0,($00,$10)		'Reset column register
		for loopcounter = 0 to 95
			hi2cout $40,($FF)
		next
		hi2cout 0,(%10110001)		'Bottom line
		hi2cout 0,($00,$10)		'Reset column register
		for loopcounter = 0 to 95
			hi2cout $40,($FF)
		next
		pause 32000
		
		
		hi2cout 0,(%10110000)		'Top line
		hi2cout 0,($00,$10)		'Reset column register
		for loopcounter = 0 to 15
			executebyte = loopcounter
			gosub printchar
		next
		hi2cout 0,(%10110001)		'Bottom line
		hi2cout 0,($00,$10)		'Reset column register
		for loopcounter = 16 to 31
			executebyte = loopcounter
			gosub printchar
		next
		
		pause 32000
		hi2cout 0,(%10110000)		'Top line
		hi2cout 0,($00,$10)		'Reset column register
		for loopcounter = 32 to 47
			executebyte = loopcounter
			gosub printchar
		next
		hi2cout 0,(%10110001)		'Bottom line
		hi2cout 0,($00,$10)		'Reset column register
		for loopcounter = 47 to 63
			executebyte = loopcounter
			gosub printchar
		next
		pause 32000
		
		hi2cout 0,(%10110000)		'Top line
		hi2cout 0,($00,$10)		'Reset column register
		for loopcounter = 64 to 79
			executebyte = loopcounter
			gosub printchar
		next
		hi2cout 0,(%10110001)		'Bottom line
		hi2cout 0,($00,$10)		'Reset column register
		for loopcounter = 80 to 95
			executebyte = loopcounter
			gosub printchar
		next
		pause 32000
		
		hi2cout 0,(%10110000)		'Top line
		hi2cout 0,($00,$10)		'Reset column register
		for loopcounter = 96 to 111
			executebyte = loopcounter
			gosub printchar
		next
		hi2cout 0,(%10110001)		'Bottom line
		hi2cout 0,($00,$10)		'Reset column register
		for loopcounter = 112 to 127
			executebyte = loopcounter
			gosub printchar
		next
		pause 32000
	loop
	#rem
	do
	pause 3000
	hi2cout 0,(%10100101)		'Set entire display [on]/normal
	pause 3000
	hi2cout 0,(%10100100)		'Set entire display on/[normal]
	loop
	#endrem

printchar:
			if executebyte < 32 then
				lookup executebyte,(0,$1020,$4444,$1474,$1D15,$1515,$1516,$1038,$FE83,$2214,$0808,$7F10,$4E71,$0002,$0808,$0000,$0808,$0000,$0000,$0808,$0808,$0808,$0000,$0808,$0808,$FFFF,$3E41,$3E41,$7F7F,$7F41,$7F00,$487E),cw1
				lookup executebyte,(0,$7F01,$5F44,$1C17,$1700,$1F00,$7C16,$5410,$8183,$0814,$2A08,$100F,$0171,$0502,$0808,$FF00,$FF08,$F808,$0F08,$0F00,$F800,$FF00,$FF08,$0F08,$F808,$FFFF,$7549,$5D49,$7F7F,$4141,$7F00,$4949),cw2
				lookup executebyte,(0,$0100,$4400,$1400,$0000,$0000,$1500,$1F00,$FE00,$2200,$0800,$1000,$4E00,$0000,$0808,$0000,$0808,$0808,$0808,$0000,$0000,$0000,$0808,$0808,$0808,$FFFF,$3E00,$3E00,$7F00,$7F00,$7F00,$4200),cw3
			elseif executebyte < 64 then
				executebyte = executebyte - 32																	  '3					  8
				lookup executebyte,($0000,$0000,$0003,$147F,$242A,$2313,$3649,$0005,$001C,$0041,$1408,$0808,$0050,$0808,$0060,$2010,$3E51,$0042,$4261,$2141,$1814,$2745,$3C4A,$0161,$3649,$0649,$0036,$0056,$0814,$1414,$0041,$0201),cw1
				lookup executebyte,($0000,$4F00,$0003,$147F,$7F2A,$0864,$5522,$0300,$2241,$221C,$3E08,$3E08,$3000,$0808,$6000,$0804,$4945,$7F40,$5149,$454B,$127F,$4545,$4949,$1905,$4949,$4929,$3600,$3600,$2241,$1414,$2214,$5109),cw2
				lookup executebyte,($0000,$0000,$0000,$1400,$1200,$6200,$5000,$0000,$0000,$0000,$1400,$0800,$0000,$0800,$0000,$0200,$3E00,$0000,$4600,$3100,$1000,$3900,$3000,$0300,$3600,$1E00,$0000,$0000,$0000,$1400,$0800,$0600),cw3
			elseif executebyte < 96 then
				executebyte = executebyte - 64  'B				  'F				  'J						  'P			  'S				  'W			 'Z					  'Underscore	
				lookup executebyte,($3E41,$7C12,$7F49,$3E41,$7F41,$7F49,$7F09,$3E41,$7F08,$0041,$2040,$7F08,$7F40,$7F02,$7F04,$3E41,$7F09,$3E41,$7F09,$2649,$0101,$3F40,$1F20,$3F40,$6314,$0304,$6151,$007F,$0204,$0041,$0402,$4040),cw1
				lookup executebyte,($5D55,$1112,$4949,$4141,$4122,$4949,$0909,$4949,$0808,$7F41,$413F,$1422,$4040,$0C02,$0810,$4141,$0909,$5121,$1929,$4949,$7F01,$4040,$4020,$3840,$0814,$7804,$4945,$4141,$0810,$417F,$0102,$4040),cw2
				lookup executebyte,($1E00,$7C00,$3600,$2200,$1C00,$4100,$0100,$7A00,$7F00,$0000,$0100,$4100,$4000,$7F00,$7F00,$3E00,$0600,$5E00,$4600,$3200,$0100,$3F00,$1F00,$3F00,$6300,$0300,$4300,$0000,$2000,$0000,$0400,$4000),cw3
			else
				executebyte = executebyte - 96
												  'b				  'f	  'g		  	  'j						  'p	  'q								  'y
				lookup executebyte,($0000,$2054,$7F48,$3844,$3844,$3854,$087E,$0C52,$7F08,$0044,$2040,$7F10,$0041,$7C04,$7C08,$3844,$7C14,$0814,$7C08,$4854,$043F,$3C40,$1C20,$3C40,$4428,$0C50,$4464,$081C,$0402,$0808,$0804,$1020),cw1
				lookup executebyte,($0305,$5454,$4444,$4444,$4448,$5454,$0901,$5252,$0404,$7D40,$443D,$2844,$7F40,$1804,$0404,$4444,$1414,$1418,$0404,$5454,$4440,$4020,$4020,$3040,$1028,$5050,$544C,$2A08,$7F02,$2A1C,$0810,$7F20),cw2
				lookup executebyte,($0000,$7800,$3800,$2000,$7F00,$1800,$0200,$3E00,$7800,$0000,$0000,$0000,$0000,$7800,$7800,$3800,$0800,$7C00,$0800,$2000,$2000,$7C00,$1C00,$3C00,$4400,$3C00,$4400,$0800,$0400,$0800,$0800,$1000),cw3
				
			end if
			hi2cout $40,(cb1,cb2,cb3,cb4,cb5,cb6)
		return
Commands of interest

Multiplex rate command -> hi2cout 0,(%10101000,[rows-1])

[rows-1] is exactly that - the number of rows of pixels that are scanned on the OLED display with 1 subtracted from it. Set it to 15 for 16 rows, set it to 0 and you get just one row of pixels. Having less rows enabled increases the brightness of the display. If for some reason the minimum contast setting is too bright for you then you can set this to 63 for it to scan 64 rows (even though most of those don't exist it won't cause any ill effects and will dim the display further).

Contrast command -> hi2cout 0,($81,[contrast])

[contrast] - value in range of 0 to 255 ($00 to $FF) where a small value is dim and a big value is bright. Current consumption of each pixel (not incuding current consumption of the IC or the quiescent consumption of the DC-DC converter) is apparently directly proportional to this value however brightness isn't and you won't see much benefit from putting this value above $80.

Horizontal scroll setup -> hi2cout 0,($26,[A],,[C],[D])

[A] - number of columns (pixels) scrolled per step
- Address of first line of 8 pixels in height to be scrolled (0 for top line, 1 for bottom line)
[C] - Number of frames between each scroll step (0 for 12, 1 for 64, 2 for 128, 3 for 256)
[D] - Address of last line of 8 pixels in height to be scrolled (0 for top line, 1 for bottom line)

Activate scrolling with this command: hi2cout 0,($2F)
The text scrolls to the right so I don't see the point in it AND the column address register locations are relative to the left of the screen not the start of the RAM!
Stop the scrolling with this command: hi2cout 0,($2E)

Set Lower Column Address -> hi2cout 0,([low address])

[low address] - Sets the lower nybble of the column address register - the register that determines what part of the screen the next data byte sent will be displayed on. The left of the screen is location 0. In order to successfully set the column addrss register you would usually have to set both the lower and higher column addresses and this can be done in one hi2cout command as shown in the code.

Set Higher Column Address -> hi2cout 0,($10 | [high address])

Sets the high nybble of the column address register. Since PICAXE is incapable of doing operations within other commands you need to combine the $10 with [high address] yourself. The value of [high address] occupies the four least significant bits.

Set page address -> hi2cout 0,(%10110000 | [page address])

The 'page' as they call it is the vertical address. Since you write data in vertical blocks of 8 pixels incrementing the page address by 1 means that the data will then be written 8 pixels lower down on the display. There are only two lines on the display so you would normally only use these:
Top line: hi2cout 0,(%10110000) or hi2cout 0,($B0)
Bottom line: hi2cout 0,(%10110001) or hi2cout 0,($B1)

To send data -> hi2cout $40,(data,data,data...)

The first data sent will be in the location specified by the column address and page address and will be 1 pixel wide and 8 pixels high. When the display is in normal mode a '1' turns on that pixel and a '0' turns it off and the opposite applies when the display is 'inversed'. The least significant bit is at the top.

Finally, on power on of the display the RAM contents is not cleared so you may wish to manually clear the RAM before turning on the display to prevent a brief flash of random pixels.
 
Top