From 73bc0c24ab6419b3f41cb272286f99700846ab33 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 12 Apr 2016 14:01:26 +0100 Subject: [PATCH] drivers: Add SSD1306 OLED driver, with I2C and SPI interfaces. --- drivers/display/ssd1306.py | 145 +++++++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 drivers/display/ssd1306.py 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)