mirror of
https://github.com/mbirth/wipy-ussd1306.git
synced 2024-12-25 22:44:06 +00:00
Initial import
This commit is contained in:
commit
10bb48b95a
21
LICENSE.md
Normal file
21
LICENSE.md
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2016 Markus Birth <markus@birth-online.de>
|
||||||
|
|
||||||
|
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.
|
6
README.md
Normal file
6
README.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
ussd1306
|
||||||
|
========
|
||||||
|
|
||||||
|
MicroPython module for the SSD1306 OLED.
|
||||||
|
|
||||||
|
[Datasheet](doc/SSD1306.pdf)
|
BIN
doc/SSD1306.pdf
Normal file
BIN
doc/SSD1306.pdf
Normal file
Binary file not shown.
183
ussd1306-i2c.py
Normal file
183
ussd1306-i2c.py
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
MicroPython SSD1306 I2C driver
|
||||||
|
"""
|
||||||
|
|
||||||
|
__author__ = "Markus Birth"
|
||||||
|
__copyright__ = "Copyright 2016, Markus Birth"
|
||||||
|
__credits__ = ["Markus Birth"]
|
||||||
|
__license__ = "MIT"
|
||||||
|
__version__ = "1.0"
|
||||||
|
__maintainer__ = "Markus Birth"
|
||||||
|
__email__ = "markus@birth-online.de"
|
||||||
|
__status__ = "Production"
|
||||||
|
|
||||||
|
# Datasheet: https://www.adafruit.com/datasheets/SSD1306.pdf
|
||||||
|
# Inspiration from:
|
||||||
|
# - https://github.com/khenderick/micropython-drivers/tree/master/ssd1306
|
||||||
|
#
|
||||||
|
# PINOUT
|
||||||
|
# WiPy/pyBoard display function
|
||||||
|
#
|
||||||
|
# 3V3 or any Pin => VCC 3.3V logic voltage (0=off, 1=on)
|
||||||
|
# SDA => SDM data
|
||||||
|
# SCL => SCL clock
|
||||||
|
# GND => GND
|
||||||
|
#
|
||||||
|
# WiPy (on Exp board, SD and User-LED jumper have to be removed!)
|
||||||
|
# PWR = directly from 3V3 pin of the WiPy
|
||||||
|
|
||||||
|
try:
|
||||||
|
import pyb as machine
|
||||||
|
except:
|
||||||
|
# WiPy
|
||||||
|
import machine
|
||||||
|
|
||||||
|
import struct
|
||||||
|
import time
|
||||||
|
|
||||||
|
class SSD1306:
|
||||||
|
ADDRESSING_HORIZ = 0x00
|
||||||
|
ADDRESSING_VERT = 0x01
|
||||||
|
ADDRESSING_PAGE = 0x02
|
||||||
|
POWER_UP = 0xaf
|
||||||
|
POWER_DOWN = 0xae
|
||||||
|
DISPLAY_BLANK = 0xae
|
||||||
|
DISPLAY_ALL = 0xa5
|
||||||
|
DISPLAY_NORMAL = [0xaf, 0xa4, 0xa6]
|
||||||
|
DISPLAY_INVERSE = 0xa7
|
||||||
|
DC_CMD = 0x80
|
||||||
|
DC_DATA = 0x40
|
||||||
|
|
||||||
|
def __init__(self, i2c, pwr=None, devid=0x3c):
|
||||||
|
self.width = 128
|
||||||
|
self.height = 64
|
||||||
|
self.devid = devid
|
||||||
|
self.power = self.POWER_DOWN
|
||||||
|
self.addressing = self.ADDRESSING_HORIZ
|
||||||
|
self.display_mode = self.DISPLAY_NORMAL
|
||||||
|
|
||||||
|
# init the I2C bus and pins
|
||||||
|
i2c.init(i2c.MASTER, baudrate=400000) # 400 kHz
|
||||||
|
if pwr:
|
||||||
|
if "OUT_PP" in dir(pwr):
|
||||||
|
# pyBoard style
|
||||||
|
pwr.init(pwr.OUT_PP, pwr_PULL_NONE)
|
||||||
|
else:
|
||||||
|
# WiPy style
|
||||||
|
pwr.init(pwr.OUT, None)
|
||||||
|
|
||||||
|
self.i2c = i2c
|
||||||
|
self.pwr = pwr
|
||||||
|
|
||||||
|
self.power_on()
|
||||||
|
# set disp off : 0xae
|
||||||
|
# set clock div : 0xd5, 0x80
|
||||||
|
# set multiplex : 0xa8, 0x3f (for 32px: 0x1f)
|
||||||
|
# set disp offset: 0xd3 0x00
|
||||||
|
# set start line : 0x40|0x00
|
||||||
|
# chargepump on : 0x8d, 0x14 (ext. VCC: 0x10)
|
||||||
|
# memory mode : 0x20, 0x00
|
||||||
|
# segment remap : 0xa0|0x10 (invalid value: 0xb0, maybe 0x01?)
|
||||||
|
# com scan dir : 0xc8 (decreasing, inc.: 0xc0)
|
||||||
|
# com pins : 0xda, 0x12 (for 32px: 0x02)
|
||||||
|
# contrast : 0x81, 0xff
|
||||||
|
# precharge : 0xd9, 0xf1 (ext. VCC: 0x22 = RESET)
|
||||||
|
# Vcom deselect : 0xdb, 0x40
|
||||||
|
# disp resume ram: 0xa4
|
||||||
|
# disp not invers: 0xa6
|
||||||
|
# set disp on : 0xaf
|
||||||
|
self.clear()
|
||||||
|
|
||||||
|
def set_power(self, power, set=True):
|
||||||
|
""" Sets the power mode of the LCD controller """
|
||||||
|
assert power in [self.POWER_UP, self.POWER_DOWN], "Power must be POWER_UP or POWER_DOWN."
|
||||||
|
self.power = power
|
||||||
|
self.command(power)
|
||||||
|
|
||||||
|
def set_adressing(self, addr):
|
||||||
|
""" Sets the adressing mode """
|
||||||
|
assert addr in [self.ADDRESSING_HORIZ, self.ADDRESSING_VERT, self.ADDRESSING_PAGE], "Addressing must be ADDRESSING_HORIZ, ADDRESSING_VERT or ADDRESSING_PAGE."
|
||||||
|
self.addressing = addr
|
||||||
|
self.command([0x20, addr])
|
||||||
|
|
||||||
|
def set_display(self, display_mode):
|
||||||
|
""" Sets display mode (blank, black, normal, inverse) """
|
||||||
|
assert display_mode in [self.DISPLAY_BLANK, self.DISPLAY_ALL, self.DISPLAY_NORMAL, self.DISPLAY_INVERSE], "Mode must be one of DISPLAY_BLANK, DISPLAY_ALL, DISPLAY_NORMAL or DISPLAY_INVERSE."
|
||||||
|
self.display_mode = display_mode
|
||||||
|
self.command([display_mode])
|
||||||
|
|
||||||
|
def set_contrast(self, value):
|
||||||
|
""" set OLED contrast """
|
||||||
|
assert 0x00 <= value <= 0xff, "Contrast value must be between 0x00 and 0xff"
|
||||||
|
self.command([0x81, value])
|
||||||
|
|
||||||
|
def position(self, x, y):
|
||||||
|
""" set cursor to page y, column x """
|
||||||
|
assert 0 <= x < self.width, "x must be between 0 and 127"
|
||||||
|
assert 0 <= y < self.height // 8, "y must be between 0 and 7"
|
||||||
|
self.command([0x20, 0x00, x, 0x21, 0x00, y])
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
""" clear screen """
|
||||||
|
self.position(0, 0)
|
||||||
|
self.data([0] * (self.height * self.width // 8))
|
||||||
|
self.position(0, 0)
|
||||||
|
|
||||||
|
def sleep_ms(self, mseconds):
|
||||||
|
try:
|
||||||
|
time.sleep_ms(mseconds)
|
||||||
|
except AttributeError:
|
||||||
|
machine.delay(mseconds)
|
||||||
|
|
||||||
|
def sleep_us(self, useconds):
|
||||||
|
try:
|
||||||
|
time.sleep_us(useconds)
|
||||||
|
except AttributeError:
|
||||||
|
machine.udelay(useconds)
|
||||||
|
|
||||||
|
def power_on(self):
|
||||||
|
if self.pwr:
|
||||||
|
self.pwr.value(1)
|
||||||
|
self.reset()
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
""" issue reset impulse to reset the display """
|
||||||
|
self.rst.value(0) # RST on
|
||||||
|
self.sleep_us(100) # reset impulse has to be >100 ns and <100 ms
|
||||||
|
self.rst.value(1) # RST off
|
||||||
|
# Defaults after reset:
|
||||||
|
# 1. Display is OFF
|
||||||
|
# 2. 128 x 64 Display Mode
|
||||||
|
# 3. Normal segment and display data column address and row address mapping (SEG0 mapped to
|
||||||
|
# address 00h and COM0 mapped to address 00h)
|
||||||
|
# 4. Shift register data clear in serial interface
|
||||||
|
# 5. Display start line is set at display RAM address 0
|
||||||
|
# 6. Column address counter is set at 0
|
||||||
|
# 7. Normal scan direction of the COM outputs
|
||||||
|
# 8. Contrast control register is set at 7Fh
|
||||||
|
# 9. Normal display mode (Equivalent to A4h command)
|
||||||
|
self.power = self.POWER_DOWN
|
||||||
|
self.addressing = self.ADDRESSING_HORIZ
|
||||||
|
self.display_mode = self.DISPLAY_NORMAL
|
||||||
|
|
||||||
|
def power_off(self):
|
||||||
|
self.clear()
|
||||||
|
self.set_power(self.POWER_DOWN)
|
||||||
|
self.sleep_ms(10)
|
||||||
|
if self.pwr:
|
||||||
|
self.pwr.value(0) # turn off power
|
||||||
|
|
||||||
|
def command(self, arr):
|
||||||
|
""" send bytes in command mode """
|
||||||
|
self.bitmap(arr, self.DC_CMD)
|
||||||
|
|
||||||
|
def data(self, arr):
|
||||||
|
""" send bytes in data mode """
|
||||||
|
self.bitmap(arr, self.DC_DATA)
|
||||||
|
|
||||||
|
def bitmap(self, arr, dc):
|
||||||
|
arr = [dc] + arr
|
||||||
|
buf = struct.pack('B'*len(arr), *arr)
|
||||||
|
self.i2c.send(buf, addr=self.devid, timeout=5000)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user