Skip to content

Commit 73bc0c2

Browse files
committed
drivers: Add SSD1306 OLED driver, with I2C and SPI interfaces.
1 parent e813ea1 commit 73bc0c2

1 file changed

Lines changed: 145 additions & 0 deletions

File tree

drivers/display/ssd1306.py

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
# MicroPython SSD1306 OLED driver, I2C and SPI interfaces
2+
3+
import time
4+
import framebuf
5+
6+
# register definitions
7+
SET_CONTRAST = const(0x81)
8+
SET_ENTIRE_ON = const(0xa4)
9+
SET_NORM_INV = const(0xa6)
10+
SET_DISP = const(0xae)
11+
SET_MEM_ADDR = const(0x20)
12+
SET_COL_ADDR = const(0x21)
13+
SET_PAGE_ADDR = const(0x22)
14+
SET_DISP_START_LINE = const(0x40)
15+
SET_SEG_REMAP = const(0xa0)
16+
SET_MUX_RATIO = const(0xa8)
17+
SET_COM_OUT_DIR = const(0xc0)
18+
SET_DISP_OFFSET = const(0xd3)
19+
SET_COM_PIN_CFG = const(0xda)
20+
SET_DISP_CLK_DIV = const(0xd5)
21+
SET_PRECHARGE = const(0xd9)
22+
SET_VCOM_DESEL = const(0xdb)
23+
SET_CHARGE_PUMP = const(0x8d)
24+
25+
class SSD1306:
26+
def __init__(self, height, external_vcc):
27+
self.width = 128
28+
self.height = height
29+
self.external_vcc = external_vcc
30+
self.pages = self.height // 8
31+
self.buffer = bytearray(self.pages * self.width)
32+
self.framebuf = framebuf.FrameBuffer1(self.buffer, self.width, self.height)
33+
self.poweron()
34+
self.init_display()
35+
36+
def init_display(self):
37+
for cmd in (
38+
SET_DISP | 0x00, # off
39+
# address setting
40+
SET_MEM_ADDR, 0x00, # horizontal
41+
# resolution and layout
42+
SET_DISP_START_LINE | 0x00,
43+
SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0
44+
SET_MUX_RATIO, self.height - 1,
45+
SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0
46+
SET_DISP_OFFSET, 0x00,
47+
SET_COM_PIN_CFG, 0x02 if self.height == 32 else 0x12,
48+
# timing and driving scheme
49+
SET_DISP_CLK_DIV, 0x80,
50+
SET_PRECHARGE, 0x22 if self.external_vcc else 0xf1,
51+
SET_VCOM_DESEL, 0x30, # 0.83*Vcc
52+
# display
53+
SET_CONTRAST, 0xff, # maximum
54+
SET_ENTIRE_ON, # output follows RAM contents
55+
SET_NORM_INV, # not inverted
56+
# charge pump
57+
SET_CHARGE_PUMP, 0x10 if self.external_vcc else 0x14,
58+
SET_DISP | 0x01): # on
59+
self.write_cmd(cmd)
60+
self.fill(0)
61+
self.show()
62+
63+
def poweroff(self):
64+
self.write_cmd(SET_DISP | 0x00)
65+
66+
def contrast(self, contrast):
67+
self.write_cmd(SET_CONTRAST)
68+
self.write_cmd(contrast)
69+
70+
def invert(self, invert):
71+
self.write_cmd(SET_NORM_INV | (invert & 1))
72+
73+
def show(self):
74+
self.write_cmd(SET_COL_ADDR)
75+
self.write_cmd(0)
76+
self.write_cmd(self.width - 1)
77+
self.write_cmd(SET_PAGE_ADDR)
78+
self.write_cmd(0)
79+
self.write_cmd(self.pages - 1)
80+
self.write_data(self.buffer)
81+
82+
def fill(self, col):
83+
self.framebuf.fill(col)
84+
85+
def pixel(self, x, y, col):
86+
self.framebuf.pixel(x, y, col)
87+
88+
def scroll(self, dx, dy):
89+
self.framebuf.scroll(dx, dy)
90+
91+
def text(self, string, x, y, col=1):
92+
self.framebuf.text(string, x, y, col)
93+
94+
class SSD1306_I2C(SSD1306):
95+
def __init__(self, height, i2c, addr=0x3c, external_vcc=False):
96+
self.i2c = i2c
97+
self.addr = addr
98+
self.temp = bytearray(2)
99+
super().__init__(height, external_vcc)
100+
101+
def write_cmd(self, cmd):
102+
self.temp[0] = 0x80 # Co=1, D/C#=0
103+
self.temp[1] = cmd
104+
self.i2c.writeto(self.addr, self.temp)
105+
106+
def write_data(self, buf):
107+
self.temp[0] = self.addr << 1
108+
self.temp[1] = 0x40 # Co=0, D/C#=1
109+
self.i2c.start()
110+
self.i2c.write(self.temp)
111+
self.i2c.write(buf)
112+
self.i2c.stop()
113+
114+
def poweron(self):
115+
pass
116+
117+
# TODO convert this class to use the new hardware API
118+
class SSD1306_SPI(SSD1306):
119+
def __init__(self, height, spi, dc, res, cs=None, external_vcc=False):
120+
rate = 10 * 1024 * 1024
121+
spi.init(spi.MASTER, baudrate=rate, polarity=0, phase=0)
122+
dc.init(dc.OUT, dc.PULL_NONE, value=0)
123+
res.init(res.OUT, dc.PULL_NONE, value=0)
124+
if cs is not None:
125+
cs.init(cs.OUT, cs.PULL_NONE, value=0)
126+
self.spi = spi
127+
self.dc = dc
128+
self.res = res
129+
super().__init__(height, external_vcc)
130+
131+
def write_cmd(self, cmd):
132+
self.dc.low()
133+
self.spi.send(cmd)
134+
135+
def write_data(self, buf):
136+
self.dc.high()
137+
self.spi.send(buf)
138+
139+
def poweron(self):
140+
self.res.high()
141+
time.sleep_ms(1)
142+
self.res.low()
143+
time.sleep_ms(10)
144+
self.res.high()
145+
time.sleep_ms(10)

0 commit comments

Comments
 (0)