SSD1306 SPI OLED on Raspberry Pi Pico/CircuitPython using displayio
Raspberry Pi Pico (RP2040) running CircuitPython 7.3.2, to drive 0.96" 128x64 SSD1306 SPI OLED using displayio.
Connection:
Raspberry Pi Pico
---------+
VBUS |
VSYS |
GND |
3V3_EN|
3V3 |---------------+
. | |
. | |
. | |
. | |
. | |
GP22 |---x |
GND | |
GP21 |-----------+ |
GP20 |---------+ | |
GP19 |-------+ | | |
GP18 |-----+ | | | |
GND |--+ | | | | |
GP17 } | | | | | |
GP16 | | | | | | |
---------+ | | | | | |
| | | | | |
SSD1306 | | | | | |
SPI OLED | | | | | |
---------+ | | | | | |
GND |--+ | | | | |
VCC |-----|-|-|-|---+
SCL |-----+ | | |
SDA |-------+ | |
RST |---------+ |
D/C |-----------+
---------+
SSD1306 Raspberry Pi Pico
GND 3V3
VCC GND
SCL GP18
SDA GP19
RST GP20
D/C GP21
GP22 (dummy)
My 0.96" 128x64 SSD1306 SPI OLED have no CS (chip select) pin, it's
connected to GND. The adafruit_displayio_ssd1306.mpy used require CS pin,
so it's dummy assigned to GP22, actually it have no connection.Libraries needed:
- adafruit_display_shapes folder
- adafruit_display_text folder
- adafruit_displayio_ssd1306.mpy
If you don't know how to download Adafruit CircuitPython Library Bundle or run the examples code, read Download and install CircuitPython Library to CIRCUITPY drive's lib folder and XIAO nRF52840 Sense/CircuitPython examples for SSD1306 I2C OLE.
Exercise code:
cpy_rpiPico_displayio_ssd1306_simpletest.py, modified from Adafruit CircuitPython Library Bundle's displayio_ssd1306_simpletest.py example.
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT
"""
This test will initialize the display using displayio and draw a solid white
background, a smaller black rectangle, and some white text.
"""
import board
import displayio
import terminalio
from adafruit_display_text import label
import adafruit_displayio_ssd1306
import busio
displayio.release_displays()
#oled_reset = board.D9
# Use for I2C
#i2c = board.I2C()
#display_bus = displayio.I2CDisplay(i2c, device_address=0x3C, reset=oled_reset)
# Use for SPI
# spi = board.SPI()
# oled_cs = board.D5
# oled_dc = board.D6
# display_bus = displayio.FourWire(spi, command=oled_dc, chip_select=oled_cs,
# reset=oled_reset, baudrate=1000000)
oled_clk = board.GP18
oled_mosi = board.GP19
oled_reset = board.GP20
oled_dc = board.GP21
oled_cs = board.GP22 # dummy, no connection
oled_spi = busio.SPI(oled_clk, MOSI=oled_mosi)
display_bus = displayio.FourWire(oled_spi, command=oled_dc, chip_select=oled_cs,
reset=oled_reset, baudrate=1000000)
WIDTH = 128
HEIGHT = 64
BORDER = 5
display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=WIDTH, height=HEIGHT)
# Make the display context
splash = displayio.Group()
display.show(splash)
color_bitmap = displayio.Bitmap(WIDTH, HEIGHT, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0xFFFFFF # White
bg_sprite = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=0, y=0)
splash.append(bg_sprite)
# Draw a smaller inner rectangle
inner_bitmap = displayio.Bitmap(WIDTH - BORDER * 2, HEIGHT - BORDER * 2, 1)
inner_palette = displayio.Palette(1)
inner_palette[0] = 0x000000 # Black
inner_sprite = displayio.TileGrid(
inner_bitmap, pixel_shader=inner_palette, x=BORDER, y=BORDER
)
splash.append(inner_sprite)
# Draw a label
text = "Hello World!"
text_area = label.Label(
terminalio.FONT, text=text, color=0xFFFFFF, x=28, y=HEIGHT // 2 - 1
)
splash.append(text_area)
while True:
pass
cpy_rpiPico_displayio_ssd1306_aniCircle.py, modified from
cpyX_nRF_displayio_ssd1306_aniCircle.py in my previouse exercise XIAO nRF52840 Sense/CircuitPython examples for SSD1306 I2C OLED, to display a animating label over random.
"""
coXXect:
Exercise to display on 128x64 SSD1306 SPI OLED with
Raspberry Pi Pico (RP2040) running CircuitPython.
Using displayio
Libs needed:
- adafruit_displayio_ssd1306.mpy
- adafruit_display_text folder
- adafruit_display_shapes folder
port from my previous exercise
XIAO nRF52840 Sense/CircuitPython examples for SSD1306 I2C OLED
using displayio, cpyX_nRF_displayio_ssd1306_aniCircle.py in
https://coxxect.blogspot.com/2022/08/xiao-nrf52840-sensecircuitpython.html
"""
import board
import displayio
import terminalio
from adafruit_display_text import label
from adafruit_display_shapes.circle import Circle
import adafruit_displayio_ssd1306
import time
import random
import busio
displayio.release_displays()
print(adafruit_displayio_ssd1306.__name__,
adafruit_displayio_ssd1306.__version__)
#===========================================
# Use for I2C
# i2c = board.I2C()
# display_bus = displayio.I2CDisplay(i2c, device_address=0x3C)
#===========================================
# Use for SPI
oled_clk = board.GP18
oled_mosi = board.GP19
oled_reset = board.GP20
oled_dc = board.GP21
oled_cs = board.GP22 # dummy, no connection
oled_spi = busio.SPI(oled_clk, MOSI=oled_mosi)
display_bus = displayio.FourWire(oled_spi,
command=oled_dc,
chip_select=oled_cs,
reset=oled_reset,
baudrate=1000000)
#===========================================
DISP_WIDTH = 128
DISP_HEIGHT = 64
BORDER = 5
display = adafruit_displayio_ssd1306.SSD1306(
display_bus,
width=DISP_WIDTH,
height=DISP_HEIGHT)
# Make the display context
splash = displayio.Group()
display.show(splash)
bg_bitmap = displayio.Bitmap(DISP_WIDTH, DISP_HEIGHT, 2)
bg_palette = displayio.Palette(2)
bg_palette[0] = 0x000000 # Black
bg_palette[1] = 0xFFFFFF # White
bg_sprite = displayio.TileGrid(
bg_bitmap,
pixel_shader=bg_palette,
x=0, y=0)
#===========================================
#prepare Label of title
title = " coXXect "
group_title = displayio.Group(scale=1)
label_title = label.Label(terminalio.FONT,
text=title,
color=0xFFFFFF)
label_title.anchor_point = (0.0, 0.0)
label_title.anchored_position = (0, 0)
label_title_width = label_title.bounding_box[2]
label_title_height = label_title.bounding_box[3]
shape_title_r = label_title_width//2
shape_title = Circle(x0=label_title_width//2,
y0=label_title_height//2,
r=shape_title_r,
fill=0x000000,
outline=0xFFFFFF, stroke=1)
group_title.x = (DISP_WIDTH-label_title_width)//2
group_title.y = (DISP_HEIGHT-label_title_height)//2
group_title.append(shape_title)
group_title.append(label_title)
#===========================================
splash.append(bg_sprite)
splash.append(group_title)
#===========================================
def background_random():
global bg_bitmap
x = random.randrange(DISP_WIDTH)
y = random.randrange(DISP_HEIGHT)
c = bg_bitmap[x, y]
c = not c
bg_bitmap[x, y] = c
aniXMove = +1
aniYMove = +1
aniXLim = DISP_WIDTH - 1 - shape_title.width
aniYdelta = (DISP_HEIGHT-1)//2 - shape_title_r
aniYLowLim = group_title.y - aniYdelta
aniYUppLim = group_title.y + aniYdelta
"""
# it's used to help me calculate the Y-limit
# just comment it
print("group_title.x", group_title.x)
print("group_title.y", group_title.y)
print(dir(group_title))
for x in range(-5, 5):
bg_bitmap[x+group_title.x, group_title.y]=1
for y in range(-5, 5):
bg_bitmap[group_title.x, y+group_title.y]=1
print("aniXLim", aniXLim)
print("aniYLowLim", aniYLowLim)
print("aniYUppLim", aniYUppLim)
for x in range(128):
bg_bitmap[x, aniYLowLim] = 1
bg_bitmap[x, aniYUppLim] = 1
"""
def title_animation():
global group_title
global aniXMove
global aniYMove
global aniXLim
global aniYLim
#Move Title group
x = group_title.x + aniXMove
group_title.x = x
if aniXMove > 0:
if x >= aniXLim:
aniXMove = -1
else:
if x <= 0:
aniXMove = +1
y = group_title.y + aniYMove
group_title.y = y
if aniYMove > 0:
if y >= aniYUppLim:
aniYMove = -1
else:
if y <= aniYLowLim:
aniYMove = +1
BG_CHANGE_DURATION = 0.05
bg_change_nx = time.monotonic() + BG_CHANGE_DURATION
TITLE_CHANGE_DURATION = 0.25
title_change_nx = time.monotonic() + TITLE_CHANGE_DURATION
while True:
now = time.monotonic()
if now >= bg_change_nx:
bg_change_nx = now+BG_CHANGE_DURATION
background_random()
if now >= title_change_nx:
title_change_nx = now+TITLE_CHANGE_DURATION
title_animation()
time.sleep(0.01)
cpy_rpiPico_displayio_ssd1306_aniCircle_2.py, further modified to keep changing the label text.
"""
coXXect:
Exercise to display on 128x64 SSD1306 SPI OLED with
Raspberry Pi Pico (RP2040) running CircuitPython.
Using displayio
Libs needed:
- adafruit_displayio_ssd1306.mpy
- adafruit_display_text folder
- adafruit_display_shapes folder
port from my previous exercise
XIAO nRF52840 Sense/CircuitPython examples for SSD1306 I2C OLED
using displayio, cpyX_nRF_displayio_ssd1306_aniCircle.py in
https://coxxect.blogspot.com/2022/08/xiao-nrf52840-sensecircuitpython.html
"""
import board
import displayio
import terminalio
from adafruit_display_text import label
from adafruit_display_shapes.circle import Circle
import adafruit_displayio_ssd1306
import time
import random
import busio
displayio.release_displays()
print(adafruit_displayio_ssd1306.__name__,
adafruit_displayio_ssd1306.__version__)
#===========================================
# Use for I2C
# i2c = board.I2C()
# display_bus = displayio.I2CDisplay(i2c, device_address=0x3C)
#===========================================
# Use for SPI
oled_clk = board.GP18
oled_mosi = board.GP19
oled_reset = board.GP20
oled_dc = board.GP21
oled_cs = board.GP22 # dummy, no connection
oled_spi = busio.SPI(oled_clk, MOSI=oled_mosi)
display_bus = displayio.FourWire(oled_spi,
command=oled_dc,
chip_select=oled_cs,
reset=oled_reset,
baudrate=1000000)
#===========================================
DISP_WIDTH = 128
DISP_HEIGHT = 64
BORDER = 5
display = adafruit_displayio_ssd1306.SSD1306(
display_bus,
width=DISP_WIDTH,
height=DISP_HEIGHT)
# Make the display context
splash = displayio.Group()
display.show(splash)
bg_bitmap = displayio.Bitmap(DISP_WIDTH, DISP_HEIGHT, 2)
bg_palette = displayio.Palette(2)
bg_palette[0] = 0x000000 # Black
bg_palette[1] = 0xFFFFFF # White
bg_sprite = displayio.TileGrid(
bg_bitmap,
pixel_shader=bg_palette,
x=0, y=0)
#===========================================
#prepare Label of title
title = " coXXect "
group_title = displayio.Group(scale=1)
label_title = label.Label(terminalio.FONT,
text=title,
color=0xFFFFFF)
label_title.anchor_point = (0.0, 0.0)
label_title.anchored_position = (0, 0)
label_title_width = label_title.bounding_box[2]
label_title_height = label_title.bounding_box[3]
shape_title_r = label_title_width//2
shape_title = Circle(x0=label_title_width//2,
y0=label_title_height//2,
r=shape_title_r,
fill=0x000000,
outline=0xFFFFFF, stroke=1)
group_title.x = (DISP_WIDTH-label_title_width)//2
group_title.y = (DISP_HEIGHT-label_title_height)//2
group_title.append(shape_title)
group_title.append(label_title)
#===========================================
splash.append(bg_sprite)
splash.append(group_title)
#===========================================
def background_random():
global bg_bitmap
x = random.randrange(DISP_WIDTH)
y = random.randrange(DISP_HEIGHT)
c = bg_bitmap[x, y]
c = not c
bg_bitmap[x, y] = c
aniXMove = +1
aniYMove = +1
aniXLim = DISP_WIDTH - 1 - shape_title.width
aniYdelta = (DISP_HEIGHT-1)//2 - shape_title_r
aniYLowLim = group_title.y - aniYdelta
aniYUppLim = group_title.y + aniYdelta
"""
# it's used to help me calculate the Y-limit
# just comment it
print("group_title.x", group_title.x)
print("group_title.y", group_title.y)
print(dir(group_title))
for x in range(-5, 5):
bg_bitmap[x+group_title.x, group_title.y]=1
for y in range(-5, 5):
bg_bitmap[group_title.x, y+group_title.y]=1
print("aniXLim", aniXLim)
print("aniYLowLim", aniYLowLim)
print("aniYUppLim", aniYUppLim)
for x in range(128):
bg_bitmap[x, aniYLowLim] = 1
bg_bitmap[x, aniYUppLim] = 1
"""
TOGGLE_TITLE_NUM = 5
toggle_title_cnt = TOGGLE_TITLE_NUM
TOG_TITLE = [[" coXXect ", 5],
[" SSD1306 ", 5],
[" SPI ", 1],
[" SPI ", 1],
[" SPI ", 1],
[" SPI ", 1],
[" SPI ", 1],
[" OLED ", 5]]
toggle_title_st = 0
def title_animation():
global group_title
global aniXMove
global aniYMove
global aniXLim
global aniYLim
global label_title
global toggle_title_cnt
global toggle_title_st
#Move Title group
x = group_title.x + aniXMove
group_title.x = x
if aniXMove > 0:
if x >= aniXLim:
aniXMove = -1
else:
if x <= 0:
aniXMove = +1
y = group_title.y + aniYMove
group_title.y = y
if aniYMove > 0:
if y >= aniYUppLim:
aniYMove = -1
else:
if y <= aniYLowLim:
aniYMove = +1
toggle_title_cnt = toggle_title_cnt-1
if toggle_title_cnt <= 0:
toggle_title_st = toggle_title_st+1
if toggle_title_st >= len(TOG_TITLE):
toggle_title_st = 0
label_title.text = TOG_TITLE[toggle_title_st][0]
toggle_title_cnt = TOG_TITLE[toggle_title_st][1]
BG_CHANGE_DURATION = 0.05
bg_change_nx = time.monotonic() + BG_CHANGE_DURATION
TITLE_CHANGE_DURATION = 0.25
title_change_nx = time.monotonic() + TITLE_CHANGE_DURATION
while True:
now = time.monotonic()
if now >= bg_change_nx:
bg_change_nx = now+BG_CHANGE_DURATION
background_random()
if now >= title_change_nx:
title_change_nx = now+TITLE_CHANGE_DURATION
title_animation()
time.sleep(0.01)
Comments
Post a Comment