Last active
August 20, 2019 03:45
-
-
Save bryanjhv/517a380806a3bd84ad3cad9ee17770c5 to your computer and use it in GitHub Desktop.
Simplified Adafruit Python SSD1306 for Raspberry Pi 3B+ (I2C only)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from __future__ import division | |
from smbus import SMBus | |
SSD1306_ADDRESS = 0x3C | |
SSD1306_MEMORYMODE = 0x20 | |
SSD1306_COLUMNADDR = 0x21 | |
SSD1306_PAGEADDR = 0x22 | |
SSD1306_SETCONTRAST = 0x81 | |
SSD1306_CHARGEPUMP = 0x8D | |
SSD1306_SEGREMAP = 0xA0 | |
SSD1306_DISPLAYALLON_RESUME = 0xA4 | |
SSD1306_DISPLAYALLON = 0xA5 #< Not currently used | |
SSD1306_NORMALDISPLAY = 0xA6 | |
SSD1306_INVERTDISPLAY = 0xA7 | |
SSD1306_SETMULTIPLEX = 0xA8 | |
SSD1306_DISPLAYOFF = 0xAE | |
SSD1306_DISPLAYON = 0xAF | |
SSD1306_COMSCANINC = 0xC0 #< Not currently used | |
SSD1306_COMSCANDEC = 0xC8 | |
SSD1306_SETDISPLAYOFFSET = 0xD3 | |
SSD1306_SETDISPLAYCLOCKDIV = 0xD5 | |
SSD1306_SETPRECHARGE = 0xD9 | |
SSD1306_SETCOMPINS = 0xDA | |
SSD1306_SETVCOMDETECT = 0xDB | |
SSD1306_SETLOWCOLUMN = 0x00 #< Not currently used | |
SSD1306_SETHIGHCOLUMN = 0x10 #< Not currently used | |
SSD1306_SETSTARTLINE = 0x40 | |
SSD1306_EXTERNALVCC = 0x01 #< External display voltage source | |
SSD1306_SWITCHCAPVCC = 0x02 #< Gen. display voltage from 3.3V | |
SSD1306_RIGHT_HORIZONTAL_SCROLL = 0x26 #< Init rt scroll | |
SSD1306_LEFT_HORIZONTAL_SCROLL = 0x27 #< Init left scroll | |
SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL = 0x29 #< Init diag scroll | |
SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL = 0x2A #< Init diag scroll | |
SSD1306_DEACTIVATE_SCROLL = 0x2E #< Stop scroll | |
SSD1306_ACTIVATE_SCROLL = 0x2F #< Start scroll | |
SSD1306_SET_VERTICAL_SCROLL_AREA = 0xA3 #< Set scroll range | |
class SSD1306(object): | |
def __init__(self, width, height, address=SSD1306_ADDRESS): | |
self.width = width | |
self.height = height | |
self.address = address | |
self.bus = SMBus(1) | |
self.pages = height//8 | |
self.clear() | |
def command(self, values): | |
try: | |
iter(values) | |
except TypeError: | |
values = [values] | |
finally: | |
for value in values: | |
self.bus.write_byte_data(self.address, 0x00, value) | |
def data(self, value): | |
try: | |
iter(values) | |
except TypeError: | |
values = [values] | |
finally: | |
for value in values: | |
self.bus.write_byte_data(self.address, 0x40, value) | |
def begin(self, vccstate=SSD1306_SWITCHCAPVCC): | |
self.vccstate = vccstate | |
self.initialize() | |
def display(self): | |
self.command([ | |
SSD1306_PAGEADDR, 0x00, self.pages-1, | |
SSD1306_COLUMNADDR, 0x00, self.width-1, | |
]) | |
for i in range(0, len(self.buffer), 16): | |
self.bus.write_i2c_block_data(self.address, 0x40, self.buffer[i:i+16]) | |
def image(self, image): | |
if image.mode=='1': | |
imwidth, imheight = image.size | |
if imwidth==self.width and imheight==self.height: | |
pix = image.load() | |
index = 0 | |
for page in range(self.pages): | |
for x in range(self.width): | |
bits = 0 | |
for bit in [0,1,2,3,4,5,6,7]: | |
bits = bits << 1 | |
bits |= 0 if pix[(x,page*8+7-bit)]==0 else 1 | |
self.buffer[index] = bits | |
index += 1 | |
def clear(self): | |
self.buffer = [0] * (self.width * self.pages) | |
def set_contrast(self, contrast): | |
self.command([ | |
SSD1306_SETCONTRAST, contrast, | |
]) | |
def initialize(self): | |
self.command([ | |
SSD1306_DISPLAYOFF, | |
SSD1306_SETDISPLAYCLOCKDIV, 0x80, | |
SSD1306_SETMULTIPLEX, self.height-1, | |
]) | |
self.command([ | |
SSD1306_SETDISPLAYOFFSET, 0x00, | |
SSD1306_SETSTARTLINE|0x00, | |
SSD1306_CHARGEPUMP, 0x10 if self.vccstate==SSD1306_EXTERNALVCC else 0x14, | |
]) | |
self.command([ | |
SSD1306_MEMORYMODE, 0x00, | |
SSD1306_SEGREMAP|0x01, | |
SSD1306_COMSCANDEC, | |
]) | |
if self.width==128 and self.height==64: | |
self.command([ | |
SSD1306_SETCOMPINS, 0x12, | |
SSD1306_SETCONTRAST, 0x9F if self.vccstate==SSD1306_EXTERNALVCC else 0xCF, | |
]) | |
elif self.width==128 and self.height==32: | |
self.command([ | |
SSD1306_SETCOMPINS, 0x02, | |
SSD1306_SETCONTRAST, 0x8F, | |
]) | |
elif self.width==96 and self.height==16: | |
self.command([ | |
SSD1306_SETCOMPINS, 0x02, | |
SSD1306_SETCONTRAST, 0x10 if self.vccstate==SSD1306_EXTERNALVCC else 0xAF, | |
]) | |
else: | |
# TODO: map other screens | |
pass | |
self.command([ | |
SSD1306_SETPRECHARGE, 0x22 if self.vccstate==SSD1306_EXTERNALVCC else 0xF1, | |
]) | |
self.command([ | |
SSD1306_SETVCOMDETECT, 0x40, | |
SSD1306_DISPLAYALLON_RESUME, SSD1306_NORMALDISPLAY, | |
SSD1306_DEACTIVATE_SCROLL, | |
SSD1306_DISPLAYON, | |
]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment