Skip to content

Commit bc1f002

Browse files
committed
Initial commit, direct port of micropython-adafruit-ssd1306 library.
0 parents  commit bc1f002

File tree

6 files changed

+289
-0
lines changed

6 files changed

+289
-0
lines changed

.travis.yml

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Travis CI configuration for automated .mpy file generation.
2+
# Version: 2.0 (support for both .mpy and packages)
3+
# Author: Tony DiCola
4+
# License: Public Domain
5+
# This configuration will work with Travis CI (travis-ci.org) to automacially
6+
# build .mpy files and packages for MicroPython when a new tagged release is
7+
# created. This file is relatively generic and can be shared across multiple
8+
# repositories by following these steps:
9+
# 1. Copy this file into a .travis.yml file in the root of the repository.
10+
# 2. Change the deploy > file section below to list each of the .mpy files or
11+
# package .zip files that should be generated.
12+
# For each .mpy file listed the config will automatically look for .py files
13+
# with the same name as the source for generating the .mpy files. Note that
14+
# the .mpy extension should be lower case!
15+
# For each .zip file listed the config will assume a folder with the same
16+
# name exists (minus the .zip extension) and will recursively walk the folder
17+
# to generate .mpy versions of all .py files EXCEPT __init__.py (not supported
18+
# right now because of a bug). Then a zip of the directory will be generated
19+
# with just the .mpy and __init__.py files.
20+
# 3. Commit the .travis.yml file and push it to GitHub.
21+
# 4. Go to travis-ci.org and find the repository (it needs to be setup to access
22+
# your github account, and your github account needs access to write to the
23+
# repo). Flip the 'ON' switch on for Travis and the repo, see the Travis
24+
# docs for more details: https://docs.travis-ci.com/user/getting-started/
25+
# 5. Get a GitHub 'personal access token' which has at least 'public_repo' or
26+
# 'repo' scope: https://help.github.com/articles/creating-an-access-token-for-command-line-use/
27+
# Keep this token safe and secure! Anyone with the token will be able to
28+
# access and write to your GitHub repositories. Travis will use the token
29+
# to attach the .mpy files to the release.
30+
# 6. In the Travis CI settings for the repository that was enabled find the
31+
# environment variable editing page: https://docs.travis-ci.com/user/environment-variables/#Defining-Variables-in-Repository-Settings
32+
# Add an environment variable named GITHUB_TOKEN and set it to the value
33+
# of the GitHub personal access token above. Keep 'Display value in build
34+
# log' flipped off.
35+
# 7. That's it! Tag a release and Travis should go to work to add .mpy files
36+
# to the release. It takes about a 2-3 minutes for a worker to spin up,
37+
# build mpy-cross, and add the binaries to the release.
38+
language: generic
39+
40+
sudo: true
41+
42+
deploy:
43+
provider: releases
44+
api_key: $GITHUB_TOKEN
45+
file:
46+
- adafruit_ssd1306.zip
47+
skip_cleanup: true
48+
on:
49+
tags: true
50+
51+
before_install:
52+
- wget https://raw.githubusercontent.com/adafruit/MicroPython_TravisCI_Deploy/master/install_dependencies.sh
53+
- chmod +x install_dependencies.sh
54+
- source install_dependencies.sh
55+
56+
before_deploy:
57+
- wget https://raw.githubusercontent.com/adafruit/MicroPython_TravisCI_Deploy/master/build_release.sh
58+
- chmod +x build_release.sh
59+
- ./build_release.sh

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2016 Adafruit Industries
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Adafruit CircuitPython driver for SSD1306 OLED displays.
2+
3+
This driver is based on the SSD1306 driver in the MicroPython source but differs
4+
by supporting hardware I2C interfaces and Adafruit CircuitPython API. For a
5+
MicroPython machine API compatible library see: https://github.com/adafruit/micropython-adafruit-ssd1306

adafruit_ssd1306/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from adafruit_ssd1306.ssd1306 import *

adafruit_ssd1306/ssd1306.py

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
# MicroPython SSD1306 OLED driver, I2C and SPI interfaces
2+
import time
3+
import framebuf
4+
5+
from adafruit_bus_device import i2c_device, spi_device
6+
7+
8+
# register definitions
9+
SET_CONTRAST = const(0x81)
10+
SET_ENTIRE_ON = const(0xa4)
11+
SET_NORM_INV = const(0xa6)
12+
SET_DISP = const(0xae)
13+
SET_MEM_ADDR = const(0x20)
14+
SET_COL_ADDR = const(0x21)
15+
SET_PAGE_ADDR = const(0x22)
16+
SET_DISP_START_LINE = const(0x40)
17+
SET_SEG_REMAP = const(0xa0)
18+
SET_MUX_RATIO = const(0xa8)
19+
SET_COM_OUT_DIR = const(0xc0)
20+
SET_DISP_OFFSET = const(0xd3)
21+
SET_COM_PIN_CFG = const(0xda)
22+
SET_DISP_CLK_DIV = const(0xd5)
23+
SET_PRECHARGE = const(0xd9)
24+
SET_VCOM_DESEL = const(0xdb)
25+
SET_CHARGE_PUMP = const(0x8d)
26+
27+
28+
class SSD1306:
29+
def __init__(self, width, height, external_vcc):
30+
self.width = width
31+
self.height = height
32+
self.external_vcc = external_vcc
33+
self.pages = self.height // 8
34+
# Note the subclass must initialize self.framebuf to a framebuffer.
35+
# This is necessary because the underlying data buffer is different
36+
# between I2C and SPI implementations (I2C needs an extra byte).
37+
self.poweron()
38+
self.init_display()
39+
40+
def init_display(self):
41+
for cmd in (
42+
SET_DISP | 0x00, # off
43+
# address setting
44+
SET_MEM_ADDR, 0x00, # horizontal
45+
# resolution and layout
46+
SET_DISP_START_LINE | 0x00,
47+
SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0
48+
SET_MUX_RATIO, self.height - 1,
49+
SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0
50+
SET_DISP_OFFSET, 0x00,
51+
SET_COM_PIN_CFG, 0x02 if self.height == 32 else 0x12,
52+
# timing and driving scheme
53+
SET_DISP_CLK_DIV, 0x80,
54+
SET_PRECHARGE, 0x22 if self.external_vcc else 0xf1,
55+
SET_VCOM_DESEL, 0x30, # 0.83*Vcc
56+
# display
57+
SET_CONTRAST, 0xff, # maximum
58+
SET_ENTIRE_ON, # output follows RAM contents
59+
SET_NORM_INV, # not inverted
60+
# charge pump
61+
SET_CHARGE_PUMP, 0x10 if self.external_vcc else 0x14,
62+
SET_DISP | 0x01): # on
63+
self.write_cmd(cmd)
64+
self.fill(0)
65+
self.show()
66+
67+
def poweroff(self):
68+
self.write_cmd(SET_DISP | 0x00)
69+
70+
def contrast(self, contrast):
71+
self.write_cmd(SET_CONTRAST)
72+
self.write_cmd(contrast)
73+
74+
def invert(self, invert):
75+
self.write_cmd(SET_NORM_INV | (invert & 1))
76+
77+
def show(self):
78+
x0 = 0
79+
x1 = self.width - 1
80+
if self.width == 64:
81+
# displays with width of 64 pixels are shifted by 32
82+
x0 += 32
83+
x1 += 32
84+
self.write_cmd(SET_COL_ADDR)
85+
self.write_cmd(x0)
86+
self.write_cmd(x1)
87+
self.write_cmd(SET_PAGE_ADDR)
88+
self.write_cmd(0)
89+
self.write_cmd(self.pages - 1)
90+
self.write_framebuf()
91+
92+
def fill(self, col):
93+
self.framebuf.fill(col)
94+
95+
def pixel(self, x, y, col):
96+
self.framebuf.pixel(x, y, col)
97+
98+
def scroll(self, dx, dy):
99+
self.framebuf.scroll(dx, dy)
100+
101+
def text(self, string, x, y, col=1):
102+
self.framebuf.text(string, x, y, col)
103+
104+
105+
class SSD1306_I2C(SSD1306):
106+
def __init__(self, width, height, i2c, addr=0x3c, external_vcc=False):
107+
self.i2c_device = i2c_device.I2CDevice(i2c, addr)
108+
self.addr = addr
109+
self.temp = bytearray(2)
110+
# Add an extra byte to the data buffer to hold an I2C data/command byte
111+
# to use hardware-compatible I2C transactions. A memoryview of the
112+
# buffer is used to mask this byte from the framebuffer operations
113+
# (without a major memory hit as memoryview doesn't copy to a separate
114+
# buffer).
115+
self.buffer = bytearray(((height // 8) * width) + 1)
116+
self.buffer[0] = 0x40 # Set first byte of data buffer to Co=0, D/C=1
117+
self.framebuf = framebuf.FrameBuffer1(memoryview(self.buffer)[1:], width, height)
118+
super().__init__(width, height, external_vcc)
119+
120+
def write_cmd(self, cmd):
121+
self.temp[0] = 0x80 # Co=1, D/C#=0
122+
self.temp[1] = cmd
123+
with self.i2c_device:
124+
self.i2c_device.writeto(self.temp)
125+
126+
def write_framebuf(self):
127+
# Blast out the frame buffer using a single I2C transaction to support
128+
# hardware I2C interfaces.
129+
with self.i2c_device:
130+
self.i2c_device.writeto(self.buffer)
131+
132+
def poweron(self):
133+
pass
134+
135+
136+
class SSD1306_SPI(SSD1306):
137+
def __init__(self, width, height, spi, dc, res, cs, external_vcc=False,
138+
baudrate=8000000, polarity=0, phase=0):
139+
self.rate = 10 * 1024 * 1024
140+
dc.switch_to_output(value=0)
141+
res.switch_to_output(value=0)
142+
self.spi_device = spi_device.SPIDevice(spi, cs, baudrate=baudrate,
143+
polarity=polarity, phase=phase)
144+
self.dc = dc
145+
self.res = res
146+
self.buffer = bytearray((height // 8) * width)
147+
self.framebuf = framebuf.FrameBuffer1(self.buffer, width, height)
148+
super().__init__(width, height, external_vcc)
149+
150+
def write_cmd(self, cmd):
151+
self.dc.value = 0
152+
with self.spi_device:
153+
self.spi_device.write(bytearray([cmd]))
154+
155+
def write_framebuf(self):
156+
self.dc.value = 1
157+
with self.spi_device:
158+
self.spi.write(self.buffer)
159+
160+
def poweron(self):
161+
self.res.value = 1
162+
time.sleep(0.001)
163+
self.res.value = 0
164+
time.sleep(0.010)
165+
self.res.value = 1

examples/simpletest.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Basic example of clearing and drawing pixels on a SSD1306 OLED display.
2+
# This example and library is meant to work with Adafruit CircuitPython API.
3+
# Author: Tony DiCola
4+
# License: Public Domain
5+
6+
# Import all board pins.
7+
from board import *
8+
# Use this import for ESP8266 and other boards with software I2C interfaces:
9+
import bitbangio as io
10+
# Or use this import for SAMD21 and boards with a native hardware I2C interace:
11+
#import nativeio as io
12+
13+
# Import the SSD1306 module.
14+
import adafruit_ssd1306
15+
16+
17+
# Create the I2C interface.
18+
i2c = io.I2C(SCL, SDA)
19+
20+
# Create the SSD1306 OLED class.
21+
# The first two parameters are the pixel width and pixel height. Change these
22+
# to the right size for your display!
23+
display = adafruit_ssd1306.SSD1306_I2C(128, 32, i2c)
24+
# Alternatively you can change the I2C address of the device with an addr parameter:
25+
#display = adafruit_ssd1306.SSD1306_I2C(128, 32, i2c, addr=0x31)
26+
27+
# Clear the display. Always call show after changing pixels to make the display
28+
# update visible!
29+
display.fill(0)
30+
display.show()
31+
32+
# Set a pixel in the origin 0,0 position.
33+
display.pixel(0, 0, 1)
34+
# Set a pixel in the middle 64, 16 position.
35+
display.pixel(64, 16, 1)
36+
# Set a pixel in the opposite 127, 31 position.
37+
display.pixel(127, 31, 1)
38+
display.show()

0 commit comments

Comments
 (0)