Add ssd1327 driver (not yet documented).

pull/43/head
peterhinch 2022-11-06 09:02:25 +00:00
rodzic 443b40c564
commit 766f3d3efa
2 zmienionych plików z 195 dodań i 0 usunięć

Wyświetl plik

@ -21,6 +21,7 @@ Width and height are pixels.
| 1.44C | 128 | 128 | TFT | [ST7735R][4d] | [Adafruit 2088][5m] | |
| 1.5C | 160 | 128 | TFT | [ST7735R][4d] | [Adafruit 358][6m] | |
| 1.3C | 240 | 240 | TFT | [ST7789][5d] | [Adafruit 4313][7m] | |
| 1.5GS | 128 | 128 | OLED | [SSD1327][11d]| [Waveshare 13992][20m] | User contributed |
| 2.0C | 320 | 240 | TFT | [ST7789][5d] | [Waveshare Pico LCD 2][18m]| For Pi Pico |
| 1.54C | 240 | 240 | TFT | [ST7789][5d] | [Adafruit 3787][8m] | |
| 1.14C | 240 | 135 | TFT | [ST7789][5d] | [T-Display][9m] | ESP32 with attached display |
@ -86,6 +87,7 @@ simple. See [this doc](./DRIVERS.md#7-writing-device-drivers) for details.
[8d]: https://github.com/peterhinch/micropython-nano-gui/blob/master/DRIVERS.md#52-waveshare-eink-display-hat
[9d]: https://github.com/peterhinch/micropython-nano-gui/blob/master/DRIVERS.md#4-drivers-for-sharp-displays
[10d]: https://github.com/peterhinch/micropython-nano-gui/blob/master/DRIVERS.md#53-waveshare-400x300-pi-pico-display
[11d]:
[1m]: https://www.adafruit.com/product/684
[2m]: https://www.adafruit.com/product/1673
@ -106,3 +108,4 @@ simple. See [this doc](./DRIVERS.md#7-writing-device-drivers) for details.
[17m]: https://www.adafruit.com/product/3502
[18m]: https://www.waveshare.com/wiki/Pico-LCD-2
[19m]: https://thepihut.com/collections/epaper-displays-for-raspberry-pi/products/4-2-e-paper-display-module-for-raspberry-pi-pico-black-white-400x300
[20m]: https://www.waveshare.com/product/ai/displays/oled/1.5inch-oled-module.htm?___SID=U

Wyświetl plik

@ -0,0 +1,192 @@
"""
MicroPython SSD1327 OLED I2C driver
Adapted for CWriter, nano-gui and micro-gui from
https://github.com/mcauser/micropython-ssd1327
by @mcauser (Mike Causer) and @Treadbrook (Philip Adamson).
MIT License
Copyright (c) 2022 Mike Causer
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
__version__ = '1.1.2'
from micropython import const
from framebuf import FrameBuffer, GS4_HMSB
from boolpalette import BoolPalette
# commands
SET_COL_ADDR = const(0x15)
SET_SCROLL_DEACTIVATE = const(0x2E)
SET_ROW_ADDR = const(0x75)
SET_CONTRAST = const(0x81)
SET_SEG_REMAP = const(0xA0)
SET_DISP_START_LINE = const(0xA1)
SET_DISP_OFFSET = const(0xA2)
SET_DISP_MODE = const(0xA4) # 0xA4 normal, 0xA5 all on, 0xA6 all off, 0xA7 when inverted
SET_MUX_RATIO = const(0xA8)
SET_FN_SELECT_A = const(0xAB)
SET_DISP = const(0xAE) # 0xAE power off, 0xAF power on
SET_PHASE_LEN = const(0xB1)
SET_DISP_CLK_DIV = const(0xB3)
SET_SECOND_PRECHARGE = const(0xB6)
SET_GRAYSCALE_TABLE = const(0xB8)
SET_GRAYSCALE_LINEAR = const(0xB9)
SET_PRECHARGE = const(0xBC)
SET_VCOM_DESEL = const(0xBE)
SET_FN_SELECT_B = const(0xD5)
SET_COMMAND_LOCK = const(0xFD)
# registers
REG_CMD = const(0x80)
REG_DATA = const(0x40)
class SSD1327(FrameBuffer):
lut = bytearray(32)
def __init__(self, width=128, height=128):
self.width = width
self.height = height
self.buffer = bytearray(self.width * self.height // 2)
mode = GS4_HMSB
self.palette = BoolPalette(mode)
super().__init__(self.buffer, 128, 128, GS4_HMSB)
self.col_addr = ((128 - self.width) // 4, 63 - ((128 - self.width) // 4))
# 96x96 (8, 55)
# 128x128 (0, 63)
self.row_addr = (0, self.height - 1)
# 96x96 (0, 95)
# 128x128 (0, 127)
self.offset = 128 - self.height
# 96x96 32
# 128x128 0
self.poweron()
self.init_display()
def init_display(self):
for cmd in (
SET_COMMAND_LOCK, 0x12, # Unlock
SET_DISP, # Display off
# Resolution and layout
SET_DISP_START_LINE, 0x00,
SET_DISP_OFFSET, self.offset, # Set vertical offset by COM from 0~127
# Set re-map
# Enable column address re-map
# Disable nibble re-map
# Horizontal address increment
# Enable COM re-map
# Enable COM split odd even
SET_SEG_REMAP, 0x51,
SET_MUX_RATIO, self.height - 1,
# Timing and driving scheme
SET_FN_SELECT_A, 0x01, # Enable internal VDD regulator
SET_PHASE_LEN, 0x51, # Phase 1: 1 DCLK, Phase 2: 5 DCLKs
SET_DISP_CLK_DIV, 0x01, # Divide ratio: 1, Oscillator Frequency: 0
SET_PRECHARGE, 0x08, # Set pre-charge voltage level: VCOMH
SET_VCOM_DESEL, 0x07, # Set VCOMH COM deselect voltage level: 0.86*Vcc
SET_SECOND_PRECHARGE, 0x01, # Second Pre-charge period: 1 DCLK
SET_FN_SELECT_B, 0x62, # Enable enternal VSL, Enable second precharge
# Display
SET_GRAYSCALE_LINEAR, # Use linear greyscale lookup table
SET_CONTRAST, 0x7f, # Medium brightness
SET_DISP_MODE, # Normal, not inverted
SET_COL_ADDR, self.col_addr[0], self.col_addr[1],
SET_ROW_ADDR, self.row_addr[0], self.row_addr[1],
SET_SCROLL_DEACTIVATE,
SET_DISP | 0x01): # Display on
self.write_cmd(cmd)
self.fill(0)
self.write_data(self.buffer)
def poweroff(self):
self.write_cmd(SET_FN_SELECT_A)
self.write_cmd(0x00) # Disable internal VDD regulator, to save power
self.write_cmd(SET_DISP)
def poweron(self):
self.write_cmd(SET_FN_SELECT_A)
self.write_cmd(0x01) # Enable internal VDD regulator
self.write_cmd(SET_DISP | 0x01)
def contrast(self, contrast):
self.write_cmd(SET_CONTRAST)
self.write_cmd(contrast) # 0-255
def rotate(self, rotate):
self.poweroff()
self.write_cmd(SET_DISP_OFFSET)
self.write_cmd(self.height if rotate else self.offset)
self.write_cmd(SET_SEG_REMAP)
self.write_cmd(0x42 if rotate else 0x51)
self.poweron()
def invert(self, invert):
self.write_cmd(SET_DISP_MODE | (invert & 1) << 1 | (invert & 1)) # 0xA4=Normal, 0xA7=Inverted
def show(self):
self.write_cmd(SET_COL_ADDR)
self.write_cmd(self.col_addr[0])
self.write_cmd(self.col_addr[1])
self.write_cmd(SET_ROW_ADDR)
self.write_cmd(self.row_addr[0])
self.write_cmd(self.row_addr[1])
self.write_data(self.buffer)
def write_cmd(self):
raise NotImplementedError
def write_data(self):
raise NotImplementedError
class SSD1327_I2C(SSD1327):
def __init__(self, width, height, i2c, addr=0x3c):
self.i2c = i2c
self.addr = addr
self.cmd_arr = bytearray([REG_CMD, 0]) # Co=1, D/C#=0
self.data_list = [bytes((REG_DATA,)), None]
super().__init__(width, height)
def write_cmd(self, cmd):
self.cmd_arr[1] = cmd
self.i2c.writeto(self.addr, self.cmd_arr)
def write_data(self, data_buf):
self.data_list[1] = data_buf
self.i2c.writevto(self.addr, self.data_list)
class SEEED_OLED_96X96(SSD1327_I2C):
def __init__(self, i2c):
super().__init__(96, 96, i2c)
def lookup(self, table):
# GS0 has no pre-charge and current drive
self.write_cmd(SET_GRAYSCALE_TABLE)
for i in range(0,15):
self.write_cmd(table[i])
class WS_OLED_128X128(SSD1327_I2C):
def __init__(self, i2c, addr=0x3c):
super().__init__(128, 128, i2c, addr)