SSD1306 PBM Viewer
I recently bought a SSD1306 miniature OLED display. This communicates through I2C and can be connected to various boards, like the Raspberry Pi 3 which I have used.
As an initial experiment, I have made a Python script that will load a 2-color PBM image file and display it on the OLED. The image has to be in binary (P4) format and exactly 128x64 which is the same as the resolution. I have re-used the same initialization commands as mentioned here to get up and running quickly.
Enjoy:
#!/usr/bin/python import smbus class SSD1306(object): def __init__(self, bus=1, address=0x3c): self._address = address self._bus = smbus.SMBus(bus) self._command(0xae) # Display off. self._command(0xa8) # Multiplex ratio... self._command(0x3f) # ...63 self._command(0xd3) # Display offset... self._command(0x00) # ...0 self._command(0x40) # Display start line at 0. self._command(0xa1) # Segment Re-map with column 127 mapped to SEG0. self._command(0xc8) # Remapped mode, scan from COM[N-1] to COM0. self._command(0xda) # COM pins hardware configuration... self._command(0x32) # ...Alternative and Left/Right self._command(0xa4) # Entire display ON. self._command(0xa6) # Inverse display mode. self._command(0xd5) # Display clock... self._command(0x80) # ...No clock divide ratio and max frequency. self._command(0x8d) # Charge pump... self._command(0x14) # ...Enabled. self._command(0x20) # Memory addressing mode... self._command(0x20) # ...Horizontal. self._command(0xaf) # Display on. def _command(self, command_byte): self._bus.write_byte_data(self._address, 0x00, command_byte) def _data(self, data_byte): self._bus.write_byte_data(self._address, 0x40, data_byte) def reset_cursor(self): self._command(0x21) # Column address... self._command(0x00) # ...start at 0... self._command(0x7f) # ...end at 127. self._command(0x22) # Page address... self._command(0x00) # ...start at 0... self._command(0x07) # ...end at 7. def pbm(self, filename): fh = open(filename, "r") if not fh.readline().startswith("P4"): raise Exception("Not a binary PBM image!") header = fh.readline() while header.startswith("#"): header = fh.readline() # Ignore comments. if not header.startswith("128 64"): raise Exception("Dimensions must be 128x64!") data = fh.read() fh.close() if len(data) != 1024: raise Exception("Size of data is not 1024 bytes!") self.reset_cursor() for row_offset in [0, 128, 256, 384, 512, 640, 768, 896]: for column in range(0, 128): byte = ((ord(data[row_offset + (column / 8) ]) >> (7 - (column % 8))) & 1) << 1 byte += ((ord(data[row_offset + (column / 8) + 16 ]) >> (7 - (column % 8))) & 1) << 0 byte += ((ord(data[row_offset + (column / 8) + 32 ]) >> (7 - (column % 8))) & 1) << 3 byte += ((ord(data[row_offset + (column / 8) + 48 ]) >> (7 - (column % 8))) & 1) << 2 byte += ((ord(data[row_offset + (column / 8) + 64 ]) >> (7 - (column % 8))) & 1) << 5 byte += ((ord(data[row_offset + (column / 8) + 80 ]) >> (7 - (column % 8))) & 1) << 4 byte += ((ord(data[row_offset + (column / 8) + 96 ]) >> (7 - (column % 8))) & 1) << 7 byte += ((ord(data[row_offset + (column / 8) + 112]) >> (7 - (column % 8))) & 1) << 6 self._data(byte ^ 0xff) if __name__ == "__main__": import sys if len(sys.argv) < 2: print "Usage: %s <128x64 binary PBM image>" % (sys.argv[0]) sys.exit(1) display = SSD1306() display.pbm(sys.argv[1])
And here is how it looks with an image loaded: