summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2016-04-12 14:01:26 +0100
committerDamien George <damien.p.george@gmail.com>2016-04-12 14:06:54 +0100
commit73bc0c24ab6419b3f41cb272286f99700846ab33 (patch)
tree097b0a9ea68dddecb8e2d63f48c79f985a2002eb
parente813ea1070391a6fb9bf2ed754190be07478cc37 (diff)
downloadmicropython-73bc0c24ab6419b3f41cb272286f99700846ab33.tar.gz
micropython-73bc0c24ab6419b3f41cb272286f99700846ab33.zip
drivers: Add SSD1306 OLED driver, with I2C and SPI interfaces.
-rw-r--r--drivers/display/ssd1306.py145
1 files changed, 145 insertions, 0 deletions
diff --git a/drivers/display/ssd1306.py b/drivers/display/ssd1306.py
new file mode 100644
index 0000000000..852e015a5e
--- /dev/null
+++ b/drivers/display/ssd1306.py
@@ -0,0 +1,145 @@
+# MicroPython SSD1306 OLED driver, I2C and SPI interfaces
+
+import time
+import framebuf
+
+# register definitions
+SET_CONTRAST = const(0x81)
+SET_ENTIRE_ON = const(0xa4)
+SET_NORM_INV = const(0xa6)
+SET_DISP = const(0xae)
+SET_MEM_ADDR = const(0x20)
+SET_COL_ADDR = const(0x21)
+SET_PAGE_ADDR = const(0x22)
+SET_DISP_START_LINE = const(0x40)
+SET_SEG_REMAP = const(0xa0)
+SET_MUX_RATIO = const(0xa8)
+SET_COM_OUT_DIR = const(0xc0)
+SET_DISP_OFFSET = const(0xd3)
+SET_COM_PIN_CFG = const(0xda)
+SET_DISP_CLK_DIV = const(0xd5)
+SET_PRECHARGE = const(0xd9)
+SET_VCOM_DESEL = const(0xdb)
+SET_CHARGE_PUMP = const(0x8d)
+
+class SSD1306:
+ def __init__(self, height, external_vcc):
+ self.width = 128
+ self.height = height
+ self.external_vcc = external_vcc
+ self.pages = self.height // 8
+ self.buffer = bytearray(self.pages * self.width)
+ self.framebuf = framebuf.FrameBuffer1(self.buffer, self.width, self.height)
+ self.poweron()
+ self.init_display()
+
+ def init_display(self):
+ for cmd in (
+ SET_DISP | 0x00, # off
+ # address setting
+ SET_MEM_ADDR, 0x00, # horizontal
+ # resolution and layout
+ SET_DISP_START_LINE | 0x00,
+ SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0
+ SET_MUX_RATIO, self.height - 1,
+ SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0
+ SET_DISP_OFFSET, 0x00,
+ SET_COM_PIN_CFG, 0x02 if self.height == 32 else 0x12,
+ # timing and driving scheme
+ SET_DISP_CLK_DIV, 0x80,
+ SET_PRECHARGE, 0x22 if self.external_vcc else 0xf1,
+ SET_VCOM_DESEL, 0x30, # 0.83*Vcc
+ # display
+ SET_CONTRAST, 0xff, # maximum
+ SET_ENTIRE_ON, # output follows RAM contents
+ SET_NORM_INV, # not inverted
+ # charge pump
+ SET_CHARGE_PUMP, 0x10 if self.external_vcc else 0x14,
+ SET_DISP | 0x01): # on
+ self.write_cmd(cmd)
+ self.fill(0)
+ self.show()
+
+ def poweroff(self):
+ self.write_cmd(SET_DISP | 0x00)
+
+ def contrast(self, contrast):
+ self.write_cmd(SET_CONTRAST)
+ self.write_cmd(contrast)
+
+ def invert(self, invert):
+ self.write_cmd(SET_NORM_INV | (invert & 1))
+
+ def show(self):
+ self.write_cmd(SET_COL_ADDR)
+ self.write_cmd(0)
+ self.write_cmd(self.width - 1)
+ self.write_cmd(SET_PAGE_ADDR)
+ self.write_cmd(0)
+ self.write_cmd(self.pages - 1)
+ self.write_data(self.buffer)
+
+ def fill(self, col):
+ self.framebuf.fill(col)
+
+ def pixel(self, x, y, col):
+ self.framebuf.pixel(x, y, col)
+
+ def scroll(self, dx, dy):
+ self.framebuf.scroll(dx, dy)
+
+ def text(self, string, x, y, col=1):
+ self.framebuf.text(string, x, y, col)
+
+class SSD1306_I2C(SSD1306):
+ def __init__(self, height, i2c, addr=0x3c, external_vcc=False):
+ self.i2c = i2c
+ self.addr = addr
+ self.temp = bytearray(2)
+ super().__init__(height, external_vcc)
+
+ def write_cmd(self, cmd):
+ self.temp[0] = 0x80 # Co=1, D/C#=0
+ self.temp[1] = cmd
+ self.i2c.writeto(self.addr, self.temp)
+
+ def write_data(self, buf):
+ self.temp[0] = self.addr << 1
+ self.temp[1] = 0x40 # Co=0, D/C#=1
+ self.i2c.start()
+ self.i2c.write(self.temp)
+ self.i2c.write(buf)
+ self.i2c.stop()
+
+ def poweron(self):
+ pass
+
+# TODO convert this class to use the new hardware API
+class SSD1306_SPI(SSD1306):
+ def __init__(self, height, spi, dc, res, cs=None, external_vcc=False):
+ rate = 10 * 1024 * 1024
+ spi.init(spi.MASTER, baudrate=rate, polarity=0, phase=0)
+ dc.init(dc.OUT, dc.PULL_NONE, value=0)
+ res.init(res.OUT, dc.PULL_NONE, value=0)
+ if cs is not None:
+ cs.init(cs.OUT, cs.PULL_NONE, value=0)
+ self.spi = spi
+ self.dc = dc
+ self.res = res
+ super().__init__(height, external_vcc)
+
+ def write_cmd(self, cmd):
+ self.dc.low()
+ self.spi.send(cmd)
+
+ def write_data(self, buf):
+ self.dc.high()
+ self.spi.send(buf)
+
+ def poweron(self):
+ self.res.high()
+ time.sleep_ms(1)
+ self.res.low()
+ time.sleep_ms(10)
+ self.res.high()
+ time.sleep_ms(10)