XIAO nRF52840 Sense/CircuitPython examples for SSD1306 I2C OLED

This post show how to display on  128x64 SSD1306 I2C OLED in XIAO nRF52840 Sense/XIAO Expansion board, running CircuitPython.

In CircuitPython, to display on SSD1306, there are two approach:
- framebuf  (using adafruit_ssd1306/adafruit_framebuf)
- displayio (using adafruit_displayio_ssd1306)

framebuf  (using adafruit_ssd1306/adafruit_framebuf)

This video show steps to run CircuitPython Library Bundle's examples using adafruit_ssd1306/adafruit_framebuf.


displayio (using adafruit_displayio_ssd1306)

This video show steps to run CircuitPython Library Bundle's examples using adafruit_displayio_ssd1306.



cpyX_nRF_displayio_ssd1306_aniCircle.py, my exercise using displayio to display a animated Circle (with title) over random pixel.
"""
coXXect:
Exercise to display on  128x64 SSD1306 I2C OLED in
XIAO nRF52840 Sense/XIAO Expansion board,
running CircuitPython.
Using displayio

Libs needed:
- adafruit_displayio_ssd1306.mpy
- adafruit_display_text folder
- adafruit_display_shapes folder

In CircuitPython for XIAO nRF52840 Sense
I2C SDA = A4
I2C SCL = A5
"""

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

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)

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)


Comments

Popular posts from this blog

MicroPython/ESP32-C3 + 1.8" 128x160 TFT ST7735 SPI, using boochow/MicroPython-ST7735 library.

CameraWebServe: ESP32-S3 (arduino-esp32) + OV5640 camera module