Adsense HTML/JavaScript

Showing posts with label CircuitPython. Show all posts
Showing posts with label CircuitPython. Show all posts

Friday, July 22, 2022

Display on I2C SSD1327 grayscale OLED with Arduino Nano RP2040 Connect/CircuitPython

Exercise to display on I2C SSD1327 grayscale OLED with Arduino Nano RP2040 Connect/CircuitPython 7.3.2.


CircuitPython Libraries is needed, visit https://circuitpython.org/libraries to download.

The default I2C pins assigned for Arduino Nano RP2040 Connect/CircuitPython are:
SDA - A4
SCL - A5

The I2C address of my no-brand SSD1327 OLED is 0x3C.



cpyNrp2040_i2c_test.py, I2C test code to I2C pins and address.
import board

i2c = board.I2C()

print("SDA :", board.SDA)
print("SCL :", board.SCL)

while not i2c.try_lock():
    pass

print([hex(x) for x in i2c.scan()])
i2c.unlock()


cpyNrp2040_ssd1327_ani.py
"""
Arduino Nano RP2040 Connect/CircuitPython
128x128 I2C ssd1327 OLED support grayscale
- with something animation.

CircuitPython lib need,
have to be copied to CircutPytho device's /lib:
- adafruit_ssd1327.mpy
- adafruit_display_text folder
- adafruit_display_shapes folder
"""

import time
import board
import displayio
import adafruit_ssd1327
import terminalio
from adafruit_display_text import label
from adafruit_display_shapes.roundrect import RoundRect
from adafruit_display_shapes.rect import Rect

import sys, os

displayio.release_displays()

# print system info
print(board.board_id)
print(sys.implementation[0] + ' ' +
      str(sys.implementation[1][0]) +'.'+
      str(sys.implementation[1][1]) +'.'+
      str(sys.implementation[1][2]))
print("=====================================")
info = sys.implementation[0] + ' ' + \
       os.uname()[3] + '\n' + \
       'run on ' + os.uname()[4]
print(info)
print("=====================================")
print(adafruit_ssd1327.__name__,
      adafruit_ssd1327.__version__)

# Use for I2C
i2c = board.I2C()
#display_bus = displayio.I2CDisplay(i2c, device_address=0x3D)
display_bus = displayio.I2CDisplay(i2c, device_address=0x3C)

display_width = display_height = 128

time.sleep(1)
display = adafruit_ssd1327.SSD1327(display_bus,
                                   width=display_width,
                                   height=display_height)

print()
print(display)
print(display.width,"x", display.height)
print()

g = displayio.Group()
color_count = 128
pattern = displayio.Bitmap(display_width,
                           display_height,
                           color_count)
palette = displayio.Palette(color_count)
t = displayio.TileGrid(pattern, pixel_shader=palette)

pattern.fill(color_count-1)

#init palette
for i in range(color_count):
    component = i * 255 // (color_count - 1)
    #print(component)
    palette[i] = component << 16 | component << 8 | component
    
    """
    print(i, ' - ' ,
          component,":",
          hex(component << 16),
          hex(component << 8),
          hex(component))
    """

g.append(t)

display.show(g)

time.sleep(1)

for i in range(color_count):
    for z in range(i+1):
        pattern[z, 0] = i
        pattern[z, i] = i
        pattern[0, z] = i
        pattern[i, z] = i
    #for y in range(i+1):
    #    pattern[0, y] = i
    #    pattern[i, y] = i

    #time.sleep(0.2)

time.sleep(1)

#================================================
#reverse palette
for i in range(color_count):
    component = i * 255 // (color_count - 1)
    palette[color_count-1-i] = (
        component << 16 | component << 8 | component)
    
time.sleep(3)

#re-reverse palette
for i in range(color_count):
    component = i * 255 // (color_count - 1)
    palette[i] = (
        component << 16 | component << 8 | component)
    
time.sleep(1)
#================================================
#prepare to animate somethin
group_ani = displayio.Group(scale=1)
group_ani.x = 0
group_ani.y = 0
label_ani = label.Label(terminalio.FONT,
                        text="  hello  ",
                        color=0xFFFFFF)
label_ani.anchor_point = (0.0, 0.0)
label_ani.anchored_position = (0, 0)
label_ani_width = label_ani.bounding_box[2]
label_ani_height = label_ani.bounding_box[3]
shape_ani = RoundRect(x=0, y=0,
                       width=label_ani_width,
                       height=label_ani_height,
                       r=6,
                       fill=0x000000,
                       outline=0xFFFFFF, stroke=1)

group_ani.append(shape_ani)
group_ani.append(label_ani)
g.append(group_ani)
#================================================
#prepare to somethin on fixed position
group_fix = displayio.Group(scale=2)
group_fix.x = 70
group_fix.y = 20
label_fix = label.Label(terminalio.FONT,
                        text=":)",
                        color=0xFFFFFF)
label_fix.anchor_point = (0.0, 0.0)
label_fix.anchored_position = (0, 0)
label_fix_width = label_fix.bounding_box[2]
label_fix_height = label_fix.bounding_box[3]
shape_fix = Rect(x=0, y=0,
                 width=label_fix_width,
                 height=label_fix_height,
                 fill=0x000000,
                 outline=0xFFFFFF, stroke=1)

group_fix.append(shape_fix)
group_fix.append(label_fix)
g.append(group_fix)
#=== loop of animation ===
aniXMove = +1
aniYMove = +1
aniXLim = display_width - 1 - label_ani_width
aniYLim = display_height - 1 - label_ani_height

NxAniMs = time.monotonic() + 3

while True:
    time.sleep(0.05)
    
    if time.monotonic() > NxAniMs:
        NxAniMs = time.monotonic() + 1
        
    #Move Temperate group
    x = group_ani.x + aniXMove
    group_ani.x = x
    if aniXMove > 0:
        if x >= aniXLim:
            aniXMove = -1
    else:
        if x <= 0:
            aniXMove = +1
            
    y = group_ani.y + aniYMove
    group_ani.y = y
    if aniYMove > 0:
        if y > aniYLim:
            aniYMove = -1
    else:
        if y <= 0:
            aniYMove = +1

#================================================
            
print("~ bye ~")



cpyNrp2040_ssd1327_ani2.py
"""
Arduino Nano RP2040 Connect/CircuitPython
128x128 I2C ssd1327 OLED support grayscale
- Change background bitmap by changing palette

CircuitPython lib need,
have to be copied to CircutPytho device's /lib:
- adafruit_ssd1327.mpy
- adafruit_display_text folder
- adafruit_display_shapes folder
"""

import time
import board
import displayio
import adafruit_ssd1327
import terminalio
from adafruit_display_text import label
from adafruit_display_shapes.circle import Circle

import sys, os

displayio.release_displays()

# print system info
print(board.board_id)
print(sys.implementation[0] + ' ' +
      str(sys.implementation[1][0]) +'.'+
      str(sys.implementation[1][1]) +'.'+
      str(sys.implementation[1][2]))
print("=====================================")
info = sys.implementation[0] + ' ' + \
       os.uname()[3] + '\n' + \
       'run on ' + os.uname()[4]
print(info)
print("=====================================")
print(adafruit_ssd1327.__name__,
      adafruit_ssd1327.__version__)

# Use for I2C
i2c = board.I2C()
#display_bus = displayio.I2CDisplay(i2c, device_address=0x3D)
display_bus = displayio.I2CDisplay(i2c, device_address=0x3C)

display_width = display_height = 128

time.sleep(1)
display = adafruit_ssd1327.SSD1327(display_bus,
                                   width=display_width,
                                   height=display_height)

print()
print(display)
print(display.width,"x", display.height)
print()

g = displayio.Group()

# I define the OLED in 16 grayscale,
# hardcode defined in a list (instead of by calculating),
# such that you can manual set according to your need.
grayscale = [0x00, 0x10, 0x20, 0x30,
             0x40, 0x50, 0x60, 0x70,
             0x80, 0x90, 0xA0, 0xB0,
             0xC0, 0xD0, 0xE0, 0xF0]
grayscale_count = len(grayscale)
#print([hex(g) for g in grayscale])
#print(grayscale_count)

#back ground have on color only
bg_color_count = 1
bg_bitmap = displayio.Bitmap(display_width,
                           display_height,
                           bg_color_count)
bg_palette = displayio.Palette(bg_color_count)
t = displayio.TileGrid(bg_bitmap,
                       pixel_shader=bg_palette)

bg_bitmap.fill(0)

print()
print("default bg_palette without init")
print([hex(p) for p in bg_palette])
print()

#================================================
#prepare to display grayscale
group_gray = displayio.Group(scale=1)
group_gray.x = 0
group_gray.y = 0
label_gray = label.Label(terminalio.FONT,
                        text="    ",
                        color=0xB0B0B0)
label_gray.anchor_point = (0.0, 0.0)
label_gray.anchored_position = (10, 10)
label_gray_width = label_gray.bounding_box[2]
label_gray_height = label_gray.bounding_box[3]

shape_gray = Circle(x0=0,
                    y0=0,
                    r=80,
                    fill=0xFFFFFF,
                    outline=0x000000,
                    stroke=3)

group_gray.append(shape_gray)
group_gray.append(label_gray)

#====================================

g.append(t)
g.append(group_gray)

display.show(g)

for gs in grayscale:
    
    bg_palette[0] = (gs << 16
                     | gs << 8
                     | gs)
    
    # you can try to remove any elements
    # to check the effect.
    #bg_palette[0] = (0
    #                 | gs << 8
    #                 | 0)
    
    #print([hex(p) for p in bg_palette])
    label_gray.text = str(hex(bg_palette[0]))
    time.sleep(0.5)

time.sleep(1)

#================================================
            
print("~ bye ~")



Monday, April 4, 2022

CircuitPython BLE UART between XIAO BLE Sense and ESP32-C3/S3

It's a exercise of CircuitPython to implement BLE UART between server and client. All boards are flashed with CircuitPython 7.2.4 firmware, with adafruit_ble 8.2.3.


The server side run on Seeed XIAO BLE Sense (nRF52840) + Expansion board. The code modified from Adafruit CircuitPython ble_uart_echo_test.py example, or here, setup BLE UART Server, but display on SSD1306 I2C OLED instead of echo back.

The client side run on Ai-Thinker NodeMCU ESP-C3-32S-Kit and Espressif ESP32-S3-DevKitC-1. The code modified from ble_uart_echo_client.py, or here. The user enter text in REPL to send to server side and display on SSD1306 I2C OLED.

un-solved issue:

If server side offline and the BLE link disconnected, then server side online again and re-connected, the client side will fail; tested on both ESP-C3-32S-Kit and ESP32-S3-DevKitC-1.


Exercise code:

cpyXIAOBLE_ble_uart_server_ssd1306.py, run on server side.
"""
Run CircuitPython 7.2.4 on
Seeed XIAO nRF52840 Sense with nRF52840 + Expansion Board.
Modified from ble_uart_echo_test.py.
Act as BLE server, wait connection and
display received line on ssd13106 OLED.

libs need:
- adafruit_ble folder
- adafruit_displayio_ssd1306.mpy
"""
import os
import sys
import board
import busio
import displayio
import adafruit_displayio_ssd1306

from adafruit_ble import BLERadio
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
from adafruit_ble.services.nordic import UARTService
from adafruit_ble import __name__ as BLE_NAME
from adafruit_ble import __version__ as BLE_VERSION

displayio.release_displays()

# Create the I2C interface and display object of SSD1306_I2C.
i2c = busio.I2C(board.SCL, board.SDA)

ssd1306_i2c_addr = 60
display_width =128
display_height = 64
display_bus = displayio.I2CDisplay(
    i2c, device_address=ssd1306_i2c_addr)
display = adafruit_displayio_ssd1306.SSD1306(
    display_bus, width=display_width, height=display_height)

# with displayio initialized, and have nothing displayed.
# displayio act like a REPL terminal.
# anything print() will be displayed on displayio also.

print("=================================================")
info = sys.implementation[0] + ' ' + os.uname()[3] + '\n' + \
       'run on ' + os.uname()[4]
print(info)
print("=================================================")
print(BLE_NAME, ":", BLE_VERSION)
print("=================================================")
print(adafruit_displayio_ssd1306.__name__, adafruit_displayio_ssd1306.__version__)
print("SCL: ", board.SCL)
print("SDA: ", board.SDA)

print(display)
print("display.width x height: ",
      display.width, " x ", display.height)
#=================================

ble = BLERadio()
uart = UARTService()
advertisement = ProvideServicesAdvertisement(uart)

#=== scroll up to print screen ===
print()
print()
print()
print(" ---- hello ----")

while True:
    ble.start_advertising(advertisement)
    print("Waiting to connect")
    while not ble.connected:
        pass
    print("Connected")
    while ble.connected:
        s = uart.readline()
        if s:
            print(s.decode())
            uart.write(s)

print("~ bye ~")

cpyESP32x3_ble_uart_client_repl.py, run on client side.
"""
Run CircuitPython 7.2.4 on
AITHinker ESP32-C3S_Kit with ESP32-C3FN4/ESP32-S3-DevKitC-1-N8R8 with ESP32S3.
Modified from ble_uart_echo_client.py.
Act as BLE client, connect to server,
get user input from REPL and send to server.

libs need:
- adafruit_ble folder
"""
import os
import sys
import time

from adafruit_ble import BLERadio
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
from adafruit_ble.services.nordic import UARTService
from adafruit_ble import __name__ as BLE_NAME
from adafruit_ble import __version__ as BLE_VERSION

print("=================================================")
info = sys.implementation[0] + ' ' + os.uname()[3] + '\n' + \
       'run on ' + os.uname()[4]
print(info)
print("=================================================")
print(BLE_NAME, ":", BLE_VERSION)
print("=================================================")

ble = BLERadio()
while True:
    while ble.connected and any(
        UARTService in connection for connection in ble.connections
    ):
        for connection in ble.connections:
            if UARTService not in connection:
                continue
            
            uart = connection[UARTService]
            
            # input() will block the code.
            # if connection lost while waiting user input,
            # ConnectionError will thrown in uart.write()
            userinput = input("\nEnter something: ")
            print(userinput)
            
            try:
                uart.write(userinput)
            except ConnectionError as exc:
                print("ConnectionError:", exc)
            
    print("disconnected, scanning")
    for advertisement in ble.start_scan(ProvideServicesAdvertisement, timeout=1):
        if UARTService not in advertisement.services:
            continue
        ble.connect(advertisement)
        print("connected")
        break
    ble.stop_scan()




It you cannot open two Thonny instance, read last post How to open dual Thonny instance.



Wednesday, March 30, 2022

XIAO BLE Sense (nRF52840)/CircuitPython generate QR Code and display on SSD1306 I2C OLED

adafruit_miniqr is a A non-hardware dependant miniature QR generator library.

Once Adafruit CircuitPython Libraries downloaded (as shown in last post's video), there are two examples miniqr_simpletest.py and miniqr_displaytest.py in extracted examples foler, or can be found here.

cpyX_miniqr_ssd1306.py is modified from miniqr_displaytest.py, to run on Seeed XIAO BLE Sense (nRF52840)/CircuitPython 7.2.3 to generate QR Code and display on SSD1306 I2C OLED.


cpyX_miniqr_ssd1306.py
"""
CircuitPython 7.2.3 exercise run on
Seeed XIAO nRF52840 Sense with nRF52840
- generate QR Code using adafruit_miniqr
- display on SSD1306 I2C OLED

lib needed:
- adafruit_displayio_ssd1306.mpy
- adafruit_miniqr.mpy
"""

import os
import sys
import board
import busio
import displayio
import adafruit_displayio_ssd1306
import adafruit_miniqr

displayio.release_displays()

print("=================================================")
info = sys.implementation[0] + ' ' + os.uname()[3] + '\n' + \
       'run on ' + os.uname()[4]
print(info)
print("=================================================")
print(adafruit_miniqr.__name__,
      adafruit_miniqr.__version__)
print(adafruit_displayio_ssd1306.__name__,
      adafruit_displayio_ssd1306.__version__)

# Create the I2C interface and display object of SSD1306_I2C.
i2c = busio.I2C(board.SCL, board.SDA)

ssd1306_i2c_addr = 60
display_width =128
display_height = 64
display_bus = displayio.I2CDisplay(
    i2c, device_address=ssd1306_i2c_addr)
display = adafruit_displayio_ssd1306.SSD1306(
    display_bus, width=display_width, height=display_height)

# remark by Erik:
# base on my testing on 128x64 SSD1306,
# A full white background can improve the recognition
# so I add a background in white
background_bitmap = displayio.Bitmap(display_width,
                                     display_height, 1)
background_palette = displayio.Palette(1)
background_palette[0] = 0xFFFFFF
bg_sprite = displayio.TileGrid(background_bitmap,
                               pixel_shader=background_palette,
                               x=0, y=0)

def bitmap_QR(matrix):

    # monochome (2 color) palette
    BORDER_PIXELS = 2

    # bitmap the size of the screen, monochrome (2 colors)
    bitmap = displayio.Bitmap(
        matrix.width + 2 * BORDER_PIXELS,
        matrix.height + 2 * BORDER_PIXELS, 2
    )
    # raster the QR code
    for y in range(matrix.height):  # each scanline in the height
        for x in range(matrix.width):
            if matrix[x, y]:
                bitmap[x + BORDER_PIXELS, y + BORDER_PIXELS] = 1
            else:
                bitmap[x + BORDER_PIXELS, y + BORDER_PIXELS] = 0
    return bitmap


qr = adafruit_miniqr.QRCode(qr_type=3,
                            error_correct=adafruit_miniqr.L)
qr.add_data(b"http://embedded-things.blogspot.com/")
qr.make()

# generate the 1-pixel-per-bit bitmap
qr_bitmap = bitmap_QR(qr.matrix)
# We'll draw with a classic black/white palette
palette = displayio.Palette(2)
palette[0] = 0xFFFFFF
palette[1] = 0x000000
# we'll scale the QR code as big as the display can handle
scale = min(
    display_width // qr_bitmap.width,
    display_height // qr_bitmap.height
)
# then center it!
pos_x = int(((display_width / scale) - qr_bitmap.width) / 2)
pos_y = int(((display_height / scale) - qr_bitmap.height) / 2)
qr_img = displayio.TileGrid(qr_bitmap,
                            pixel_shader=palette,
                            x=pos_x, y=pos_y)

splash = displayio.Group(scale=scale)
splash.append(bg_sprite)
splash.append(qr_img)
display.show(splash)

# Hang out forever
while True:
    pass

Tuesday, March 29, 2022

Seeed XIAO BLE Sense (nRF52840)/CircuitPython 7.2.3 display on SSD1306 I2C OLED

Updated@2024-01-31

Somethings in displayio changed in CircuitPython 9, check the updated on ESP32-S3:
Waveshare ESP32-S3-Zero/CircuitPython 9.0.0-beta.0 to display on 128x64 SSD1306 I2C OLED



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

The video demo Seeed XIAO BLE Sense (nRF52840)/CircuitPython 7.2.3 display on Seeeduino XIAO Expansion board onboard SSD1306 I2C OLED using both framebuf  and displayio.


Exercise code:

cpyX_i2c.py
"""
Seeed XIAO nRF52840 Sense with nRF52840/CircuitPython 7.2.3
- verify I2C SCL/SDA pin
- Scan available I2C devices
"""

import os
import sys
import busio
import board

print("=================================================")
info = sys.implementation[0] + ' ' + os.uname()[3] + '\n' + \
       'run on ' + os.uname()[4]
print(info)
print("=================================================")

print("SCL: ", board.SCL)
print("SDA: ", board.SDA)
i2c = board.I2C()
print(i2c)
print()

#Scan I2C devices
if(i2c.try_lock()):
    print("i2c.scan(): " + str(i2c.scan()))
    i2c.unlock()
print()

cpyX_ssd1306.py
"""
CircuitPython 7.2.3 exercise run on
Seeed XIAO nRF52840 Sense with nRF52840
- display on SSD1306 I2C OLED
- using adafruit_ssd1306

lib needed:
- adafruit_ssd1306.mpy
- adafruit_framebuf.mpy
- font5x8.bin (from examples folder,
  to current folder in CircuitPython device)
"""

import os
import sys
import board
import busio
import time

import adafruit_ssd1306

# Create the I2C interface and display object of SSD1306_I2C.
i2c = busio.I2C(board.SCL, board.SDA)
display = adafruit_ssd1306.SSD1306_I2C(128, 64, i2c)

print("=================================================")
info = sys.implementation[0] + ' ' + os.uname()[3] + '\n' + \
       'run on ' + os.uname()[4]
print(info)
print("=================================================")
print(adafruit_ssd1306.__name__, adafruit_ssd1306.__version__)
print("SCL: ", board.SCL)
print("SDA: ", board.SDA)

print(display)
print("display.width x height: ",
      display.width, " x ", display.height)
    
display.fill(0)
display.show()
time.sleep(1)
display.fill(1)
display.show()
time.sleep(1)

display.fill(0)


strSys = sys.implementation[0] + ' ' + \
         str(sys.implementation[1][0]) +'.'+ \
         str(sys.implementation[1][1]) +'.'+ \
         str(sys.implementation[1][2])

strLib = adafruit_ssd1306.__name__ + '\n' \
         + adafruit_ssd1306.__version__

def drawInfo():
    display.text(strSys, 0, 0, 1)
    display.text(strLib, 0, 10, 1)
    display.text(os.uname()[4], 0, 30, 1)
    display.text("SSD1306", 0, 40, 1)
    strResolution = str(display.rotation) + ' : ' \
                    + str(display.width) + ' x ' \
                    + str(display.height)
    display.text(strResolution, 0, 50, 1)
    
for r in range(0, 4):
    display.fill(0)
    display.rotation = r
    drawInfo()
    display.show()
    time.sleep(5)

display.rotation = 0

#draw rectangle
display.fill(0)
display.rect(0, 0, display.width, display.height, 1)
display.show()
time.sleep(1)
display.fill(0)
display.fill_rect(0, 0, display.width, display.height, 1)
display.show()
time.sleep(1)

#draw circle
display.fill(0)
if display.width > display.height:
    r = (int)(display.height/2)
else:
    r = (int)(display.width/2)
display.circle((int)(display.width/2),
               (int)(display.height/2), r, 1)
display.show()
time.sleep(1)

display.fill(0)
display.show()

# draw pixels
for y in range(0, display.height, 8):
    for x in range(0, display.width, 8):
        display.pixel(x, y, 1)
        display.show()
time.sleep(1)
display.invert(1)
time.sleep(2)
display.invert(0)
time.sleep(1)

cpyX_displayio_ssd1306.py
"""
CircuitPython 7.2.3 exercise run on
Seeed XIAO nRF52840 Sense with nRF52840
- display on SSD1306 I2C OLED
- using adafruit_displayio_ssd1306

lib needed:
- adafruit_displayio_ssd1306.mpy
- adafruit_display_text folder
"""

import os
import sys
import board
import busio
import time

import displayio
import terminalio
import adafruit_displayio_ssd1306
from adafruit_display_text import label

displayio.release_displays()

# Create the I2C interface and display object of SSD1306_I2C.
i2c = busio.I2C(board.SCL, board.SDA)

ssd1306_i2c_addr = 60
display_width =128
display_height = 64
display_bus = displayio.I2CDisplay(
    i2c, device_address=ssd1306_i2c_addr)
display = adafruit_displayio_ssd1306.SSD1306(
    display_bus, width=display_width, height=display_height)

print("=================================================")
info = sys.implementation[0] + ' ' + os.uname()[3] + '\n' + \
       'run on ' + os.uname()[4]
print(info)
print("=================================================")
print(adafruit_displayio_ssd1306.__name__,
      adafruit_displayio_ssd1306.__version__)
print("SCL: ", board.SCL)
print("SDA: ", board.SDA)

print(display)
print("display.width x height: ",
      display.width, " x ", display.height)
#================================================
# Make the display context
group = displayio.Group()

NUM_OF_COLOR = 2
bitmap = displayio.Bitmap(display_width,
                          display_height,
                          NUM_OF_COLOR)
bitmap_palette = displayio.Palette(NUM_OF_COLOR)
bitmap_palette[0] = 0x000000
bitmap_palette[1] = 0xFFFFFF

tileGrid = displayio.TileGrid(bitmap,
                              pixel_shader=bitmap_palette,
                              x=0, y=0)
group.append(tileGrid)
display.show(group)

time.sleep(1)
bitmap.fill(1)

def range_f(start, stop, step):
    f = start
    while f < stop:
        yield f
        f += step
        
time.sleep(1)
for y in range_f(0, display_height-1, 2):
    for x in range_f(0, display_width-1, 2):
        #print(str(x) + " : " + str(y))
        bitmap[x, y] = 0

time.sleep(1)
#========================================================
# Draw a label
text_group1 = displayio.Group(scale=3, x=0, y=0)
text1 = "Hello"
text_area1 = label.Label(terminalio.FONT,
                         text=text1, color=0xFFFFFF)
text_group1.append(text_area1)
group.append(text_group1)

for xy in range(20):
    time.sleep(0.1)
    text_group1.x=xy
    text_group1.y=xy
#========================================================
#invert palette
time.sleep(1)
bitmap_palette[1] = 0x000000
bitmap_palette[0] = 0xFFFFFF

time.sleep(1)
y = 0
for x in range_f(0, display_width-1, 1):
    bitmap[x, y] = 0
    time.sleep(0.01)
x = display_width-1
for y in range_f(0, display_height-1, 1):
    bitmap[x, y] = 0
    time.sleep(0.01)

y = display_height-1
for x in range_f(0, display_width-1, 1):
    bitmap[x, y] = 0
    time.sleep(0.01)
x = 0
for y in range_f(0, display_height-1, 1):
    bitmap[x, y] = 0
    time.sleep(0.01)

#invert palette
time.sleep(1)
bitmap_palette[0] = 0x000000
bitmap_palette[1] = 0xFFFFFF
#invert palette
time.sleep(1)
bitmap_palette[1] = 0x000000
bitmap_palette[0] = 0xFFFFFF

time.sleep(1)
bitmap.fill(1)
time.sleep(1)
for xy in range(20):
    time.sleep(0.1)
    text_group1.x=xy+20
    text_group1.y=xy+20
time.sleep(1)
print("- bye -")

cpyX_displayio_ssd1306_ani.py
"""
CircuitPython 7.2.3 exercise run on
Seeed XIAO nRF52840 Sense with nRF52840
- display on SSD1306 I2C OLED
- using adafruit_displayio_ssd1306
- with animation

lib needed:
- adafruit_displayio_ssd1306.mpy
- adafruit_display_text folder
- adafruit_display_shapes folder
"""

import os
import sys
import board
import busio
import time

import displayio
import terminalio
import adafruit_displayio_ssd1306
from adafruit_display_text import label
from adafruit_display_shapes.roundrect import RoundRect
from adafruit_display_shapes.rect import Rect

displayio.release_displays()

# Create the I2C interface and display object of SSD1306_I2C.
i2c = busio.I2C(board.SCL, board.SDA)

ssd1306_i2c_addr = 60
display_width =128
display_height = 64
display_bus = displayio.I2CDisplay(
    i2c, device_address=ssd1306_i2c_addr)
display = adafruit_displayio_ssd1306.SSD1306(
    display_bus, width=display_width, height=display_height)

print("=================================================")
info = sys.implementation[0] + ' ' + os.uname()[3] + '\n' + \
       'run on ' + os.uname()[4]
print(info)
print("=================================================")
print(adafruit_displayio_ssd1306.__name__,
      adafruit_displayio_ssd1306.__version__)
print("SCL: ", board.SCL)
print("SDA: ", board.SDA)

print(display)
print("display.width x height: ",
      display.width, " x ", display.height)
#================================================
# Make the display context
group = displayio.Group()

NUM_OF_COLOR = 2
bitmap = displayio.Bitmap(display_width,
                          display_height,
                          NUM_OF_COLOR)
bitmap_palette = displayio.Palette(NUM_OF_COLOR)
bitmap_palette[0] = 0x000000
bitmap_palette[1] = 0xFFFFFF

tileGrid = displayio.TileGrid(bitmap,
                              pixel_shader=bitmap_palette,
                              x=0, y=0)
group.append(tileGrid)
display.show(group)

time.sleep(1)
bitmap.fill(1)

def range_f(start, stop, step):
    f = start
    while f < stop:
        yield f
        f += step
 
time.sleep(1)
for y in range_f(0, display_height-1, 2):
    for x in range_f(0, display_width-1, 2):
        #print(str(x) + " : " + str(y))
        bitmap[x, y] = 0

time.sleep(1)

#========================================================
# Draw a label
text_group1 = displayio.Group(scale=3, x=0, y=0)
text1 = "Hello"
text_area1 = label.Label(terminalio.FONT, text=text1, color=0xFFFFFF)
text_group1.append(text_area1)
group.append(text_group1)

text_group1.x=20
text_group1.y=20
#========================================================
#invert palette
time.sleep(1)
bitmap_palette[1] = 0x000000
bitmap_palette[0] = 0xFFFFFF

time.sleep(1)
y = 0
for x in range_f(0, display_width-1, 1):
    bitmap[x, y] = 0
    time.sleep(0.01)
x = display_width-1
for y in range_f(0, display_height-1, 1):
    bitmap[x, y] = 0
    time.sleep(0.01)

y = display_height-1
for x in range_f(0, display_width-1, 1):
    bitmap[x, y] = 0
    time.sleep(0.01)
x = 0
for y in range_f(0, display_height-1, 1):
    bitmap[x, y] = 0
    time.sleep(0.01)

#================================================
#prepare to animate somethin
group_ani = displayio.Group(scale=1)
group_ani.x = 0
group_ani.y = 0
label_ani = label.Label(terminalio.FONT,
                        text="  hello  ",
                        color=0xFFFFFF)
label_ani.anchor_point = (0.0, 0.0)
label_ani.anchored_position = (0, 0)
label_ani_width = label_ani.bounding_box[2]
label_ani_height = label_ani.bounding_box[3]
shape_ani = RoundRect(x=0, y=0,
                       width=label_ani_width,
                       height=label_ani_height,
                       r=6,
                       fill=0x000000,
                       outline=0xFFFFFF, stroke=1)

group_ani.append(shape_ani)
group_ani.append(label_ani)
group.append(group_ani)
#================================================
#prepare to somethin on fixed position
group_fix = displayio.Group(scale=2)
group_fix.x = 70
group_fix.y = 20
label_fix = label.Label(terminalio.FONT,
                        text=":)",
                        color=0xFFFFFF)
label_fix.anchor_point = (0.0, 0.0)
label_fix.anchored_position = (0, 0)
label_fix_width = label_fix.bounding_box[2]
label_fix_height = label_fix.bounding_box[3]
shape_fix = Rect(x=0, y=0,
                 width=label_fix_width,
                 height=label_fix_height,
                 fill=0x000000,
                 outline=0xFFFFFF, stroke=1)

group_fix.append(shape_fix)
group_fix.append(label_fix)
group.append(group_fix)
#=== loop of animation ===
aniXMove = +1
aniYMove = +1
aniXLim = display_width - 1 - label_ani_width
aniYLim = display_height - 1 - label_ani_height

NxAniMs = time.monotonic() + 3

while True:
    time.sleep(0.05)
    
    if time.monotonic() > NxAniMs:
        NxAniMs = time.monotonic() + 1
        
    #Move Temperate group
    x = group_ani.x + aniXMove
    group_ani.x = x
    if aniXMove > 0:
        if x >= aniXLim:
            aniXMove = -1
    else:
        if x <= 0:
            aniXMove = +1
            
    y = group_ani.y + aniYMove
    group_ani.y = y
    if aniYMove > 0:
        if y > aniYLim:
            aniYMove = -1
    else:
        if y <= 0:
            aniYMove = +1
                        
print("- bye -")
next:
XIAO BLE Sense (nRF52840)/CircuitPython generate QR Code and display on SSD1306 I2C OLED


Saturday, March 26, 2022

CircuitPython 7 on Seeed XIAO BLE Sense

TO install CircuitPython on XIAO BLE Sense, follow the page XIAO BLE with CircuitPython.

cpyX_info.py, get system info.
"""
CircuitPython 7 exercise run on XIAO BLE Sense,
get system info.
"""
import board
import sys
import os
import microcontroller
# ref:
# The entire table of ANSI color codes working in C:
# https://gist.github.com/RabaDabaDoba/145049536f815903c79944599c6f952a
class color:
   RED = '\033[1;31;48m'
   BLUE = '\033[1;34;48m'
   BLACK = '\033[1;30;48m'
   END = '\033[1;37;0m'

print(sys.implementation[0] + ' ' +
      str(sys.implementation[1][0]) +'.'+
      str(sys.implementation[1][1]) +'.'+
      str(sys.implementation[1][2]))
print("=====================================")
info = color.RED + \
       sys.implementation[0] + ' ' + \
       os.uname()[3] + color.END + '\n' + \
       'run on ' + color.BLUE + os.uname()[4] + color.END
print(info)
print("=====================================")
print("microcontroller.cpu.frequency:\t\t" + color.RED +
      str(microcontroller.cpu.frequency) + color.END + " Hz")
print("microcontroller.cpu.temperature:\t" + color.RED +
      str(microcontroller.cpu.temperature) + color.END + " C")
print("microcontroller.cpu.voltage:\t\t" + color.RED +
      str(microcontroller.cpu.voltage) + color.END + " V")
print()



cpyX_pins_name.py, list pins name.
"""CircuitPython Essentials Pin Map Script"""
import microcontroller
import board

board_pins = []
for pin in dir(microcontroller.pin):
    if isinstance(getattr(microcontroller.pin, pin), microcontroller.Pin):
        pins = []
        
        pins.append("microcontroller.{}".format(pin))
        pins.append('\t-')
        
        for alias in dir(board):
            if getattr(board, alias) is getattr(microcontroller.pin, pin):
                pins.append("board.{}\t".format(alias))
        if len(pins) > 0:
            board_pins.append(" ".join(pins))
for pins in sorted(board_pins):
    print(pins)


output:

microcontroller.P0_00 	-
microcontroller.P0_01 	-
microcontroller.P0_02 	- board.A0	 board.D0	
microcontroller.P0_03 	- board.A1	 board.D1	
microcontroller.P0_04 	- board.A4	 board.D4	 board.SDA	
microcontroller.P0_05 	- board.A5	 board.D5	 board.SCL	
microcontroller.P0_06 	- board.LED_BLUE	
microcontroller.P0_07 	- board.IMU_SDA	
microcontroller.P0_08 	-
microcontroller.P0_09 	- board.NFC1	
microcontroller.P0_10 	- board.NFC2	
microcontroller.P0_11 	- board.IMU_INT1	
microcontroller.P0_12 	-
microcontroller.P0_13 	-
microcontroller.P0_14 	- board.READ_BATT_ENABLE	
microcontroller.P0_15 	-
microcontroller.P0_16 	- board.PDM_DATA	
microcontroller.P0_17 	- board.CHARGE_STATUS	
microcontroller.P0_18 	-
microcontroller.P0_19 	-
microcontroller.P0_20 	-
microcontroller.P0_21 	-
microcontroller.P0_22 	-
microcontroller.P0_23 	-
microcontroller.P0_24 	-
microcontroller.P0_25 	-
microcontroller.P0_26 	- board.LED	 board.LED_RED	
microcontroller.P0_27 	- board.IMU_SCL	
microcontroller.P0_28 	- board.A2	 board.D2	
microcontroller.P0_29 	- board.A3	 board.D3	
microcontroller.P0_30 	- board.LED_GREEN	
microcontroller.P0_31 	- board.VBATT	
microcontroller.P1_00 	- board.PDM_CLK	
microcontroller.P1_01 	-
microcontroller.P1_02 	-
microcontroller.P1_03 	-
microcontroller.P1_04 	-
microcontroller.P1_05 	-
microcontroller.P1_06 	-
microcontroller.P1_07 	-
microcontroller.P1_08 	- board.IMU_PWR	
microcontroller.P1_09 	-
microcontroller.P1_10 	- board.MIC_PWR	
microcontroller.P1_11 	- board.D6	 board.TX	
microcontroller.P1_12 	- board.D7	 board.RX	
microcontroller.P1_13 	- board.D8	 board.SCK	
microcontroller.P1_14 	- board.D9	 board.MISO	
microcontroller.P1_15 	- board.D10	 board.MOSI






reference:

more exercise:
Seeed XIAO BLE Sense (nRF52840)/CircuitPython 7.2.3 display on SSD1306 I2C OLED
XIAO BLE Sense (nRF52840)/CircuitPython generate QR Code and display on SSD1306 I2C OLED
CircuitPython BLE UART between XIAO BLE Sense and ESP32-C3/S3

Monday, March 21, 2022

Arduino Nano RP2040 Connect/CircuitPython + ov7670 cam (incomplete) display on st7789 Display

It's just my exercise running on Arduino Nano RP2040 Connect/CircuitPython 7.2.3, to work with ov7670 cam module and display on ST7789 SPI display.


For the connection between Nano RP2040 Connect and ov7670/st7789, refer to the code listed below.

In my practice, pre-defined SPI MOSI/SCK are assigned to SDA/SCL for ST7789. I2C SCL/SDA are assigned to SCL/SDA for ov7670.

*ov7670 SCL/SDA are I2C-like control pins, pull-up resistors are needed. 2K ohm resistors are used in my exercise.

For the st7789 part, it's very straightforward - just install libraries and run the exercise code.
Libraries adafruit_st7789 and adafruit_display_text are needed.

For ov7670 part, libraries adafruit_st7789 and adafruit_ov7670 are needed. adafruit_ov7670 is a CircuitPython driver for OV7670 cameras.

The problem is in adafruit_ov7670, data_pins is a list of 8 data pins in sequential order.  But I can't find 8 continuous sequence GPIO on Nano RP2040 Connect. As an exercise, GPIO14~21 are assigned to ov7670 d0~d7, GPIO14 is internal connceted to SCK of the onboard ESP32 (U-blox Nina W102), so it's actually no use. So there are only 7 bits in parallel data bus, and ESP32 SCK is mis-used (you should cannot use ESP32 at the same time). That's why I call it "incomplete".

It seem functionally work, as shown in the video. But I don't know any side-effect. It's just my exercise and not suggested, or follow at your own risk.

To list pins name of all GPIOs (include internal), read last post.


cpyNrp2040_spiST7789_320.py
"""
Example of Arduino Nano RP2040 Connect/CircuitPython 7.2.3
to display on 2.0" IPS 240x320 (RGB) screen
with SPI ST7789 driver.

Connection between Nano RP2040 Connect and
the SPI ST7789 IPS screen.

BLK  - 3V3 (backlight, always on)
CS   - A0
DC   - A1
RES  - A2
SDA  - D11 (=MOSI)
SCL  - D13 (=SCK)
VCC  - 3V3
GND  - GND
"""

import os
import sys
import board
import microcontroller
import time
import terminalio
import displayio
import busio
from adafruit_display_text import label
#from adafruit_st7789 import ST7789
import adafruit_st7789

print("=====================================")
info = sys.implementation[0] + ' ' + \
       os.uname()[3] + '\n' + \
       'run on ' + os.uname()[4]
print(info)
print("board_id:", board.board_id)

print("with number of cpu: " +
      str(len(microcontroller.cpus)))
print("=====================================")
print(adafruit_st7789.__name__ + " version: "
      + adafruit_st7789.__version__)

print()

# Release any resources currently in use for the displays
displayio.release_displays()

tft_cs = board.A0
tft_dc = board.A1
tft_res = board.A2
spi_mosi = board.D11
spi_clk = board.D13

"""
classbusio.SPI(clock: microcontroller.Pin,
                MOSI: Optional[microcontroller.Pin] = None,
                MISO: Optional[microcontroller.Pin] = None)
"""
spi = busio.SPI(clock=spi_clk, MOSI=spi_mosi)

display_bus = displayio.FourWire(
    spi, command=tft_dc, chip_select=tft_cs, reset=tft_res
)

display = adafruit_st7789.ST7789(display_bus,
                    width=240, height=320)

# Make the display context
splash = displayio.Group()
display.show(splash)

color_bitmap = displayio.Bitmap(135, 240, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0x00FF00

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(133, 238, 1)
inner_palette = displayio.Palette(1)
inner_palette[0] = 0x0000FF
inner_sprite = displayio.TileGrid(inner_bitmap,
                                  pixel_shader=inner_palette,
                                  x=1, y=1)
splash.append(inner_sprite)

# Draw a label
text_group1 = displayio.Group(scale=1, x=20, y=40)
text1 = os.uname()[4]
text_area1 = label.Label(terminalio.FONT, text=text1, color=0xFF0000)
text_group1.append(text_area1)  # Subgroup for text scaling
# Draw a label
text_group2 = displayio.Group(scale=1, x=20, y=60)
text2 = sys.implementation[0] + " " + os.uname()[3]
text_area2 = label.Label(terminalio.FONT, text=text2, color=0x00FF00)
text_group2.append(text_area2)  # Subgroup for text scaling

# Draw a label
text_group3 = displayio.Group(scale=2, x=20, y=100)
text3 = adafruit_st7789.__name__
text_area3 = label.Label(terminalio.FONT, text=text3, color=0xFFFFFF)
text_group3.append(text_area3)  # Subgroup for text scaling
# Draw a label
text_group4 = displayio.Group(scale=2, x=20, y=120)
text4 = adafruit_st7789.__version__
text_area4 = label.Label(terminalio.FONT, text=text4, color=0xFFFFFF)
text_group4.append(text_area4)  # Subgroup for text scaling

splash.append(text_group1)
splash.append(text_group2)
splash.append(text_group3)
splash.append(text_group4)

time.sleep(3.0)

rot = 0
while True:
    time.sleep(5.0)
    rot = rot + 90
    if (rot>=360):
        rot =0
    display.rotation = rot

cpyNrp2040_ov7670_displayio_pico_st7789.py
"""
Run on Arduino NANO RP2040 Connect/CircuitPython 7.2.3
+ ov7670 cam + st7789 LCD.

Capture images from the camera and display it on LCD.

Modified from ov7670_displayio_pico_st7789_2in.py example

ref:
Adafruit CircuitPython ov7670 Library
https://docs.circuitpython.org/projects/ov7670/
"""

import time
from displayio import (
    Bitmap,
    Group,
    TileGrid,
    FourWire,
    release_displays,
    ColorConverter,
    Colorspace,
)

import board
import microcontroller
import busio
import digitalio
import displayio
import adafruit_st7789
import adafruit_ov7670

"""
Connection between Nano RP2040 Connect and
the SPI ST7789 IPS screen.
==========================================
BLK  - 3V3 (backlight, always on)
CS   - A0
DC   - A1
RES  - A2
SDA  - D11 (MOSI)
SCL  - D13 (SCK)
VCC  - 3V3
GND  - GND
"""

tft_cs = board.A0
tft_dc = board.A1
tft_res = board.A2
spi_mosi = board.D11
spi_clk = board.D13

"""
Connection between Arduino Nano RP2040 Connect and
the ov7670 camera module.
==========================================
              ov7670
             +-----------+
    3V3      |3V3    GND | GND
    A5 (SCL) |SCL    SDA | A4 (SDA)
    TX       |VS     HS  | RX
    D12      |PLK    XLK | D10
    D9       |D7     D6  | D8
    D7       |D5     D4  | D6
    D5       |D3     D2  | D4
    D3       |D1     D0  | XXX
    A3       |RET    PWDN| -
             +-----------+
			 
*ov7670 SCL/SDA are I2C-like control pins, pull-up resistors are needed.
 I use 2K ohm resistor for it.
"""
cam_scl = board.A5
cam_sda = board.A4
cam_vs = board.TX
cam_hs = board.RX
cam_plk = board.D12
cam_xlk = board.D10
cam_ret = board.A3

# cam data pins must be sequential
# I can't find 8 continuous sequence GPIO on Nano RP2040 Connect
# As a exercise, I assign GPIO14~21 to d0~d7,
# GPIO14 is internal connceted to onboard ESP32 SCK,
# so it's actually no use.
cam_d0 = board.SCK1 # GPIO14
cam_d1 = board.D3   # GPIO15
cam_d2 = board.D4   # GPIO16
cam_d3 = board.D5   # GPIO17
cam_d4 = board.D6   # GPIO18
cam_d5 = board.D7   # GPIO19
cam_d6 = board.D8   # GPIO20
cam_d7 = board.D9   # GPIO21

release_displays()

# Set up the display
spi = busio.SPI(clock=spi_clk, MOSI=spi_mosi)
display_bus = displayio.FourWire(
    spi, command=tft_dc, chip_select=tft_cs, reset=tft_res)
display = adafruit_st7789.ST7789(display_bus,
                    width=240, height=320)

display.auto_refresh = False

# Ensure the camera is shut down,
# so that it releases the SDA/SCL lines,
# then create the configuration I2C bus

with digitalio.DigitalInOut(cam_ret) as reset:
    reset.switch_to_output(False)
    time.sleep(0.001)
    bus = busio.I2C(cam_scl, cam_sda)

# Set up the camera
cam = adafruit_ov7670.OV7670(
    bus,
    data_pins=[
        cam_d0,
        cam_d1,
        cam_d2,
        cam_d3,
        cam_d4,
        cam_d5,
        cam_d6,
        cam_d7,
    ],  #Pins must be sequential
    clock=cam_plk,
    vsync=cam_vs,
    href=cam_hs,
    mclk=cam_xlk,
    shutdown=None,
    reset=cam_ret,
)

#cam.test_pattern = adafruit_ov7670.OV7670_TEST_PATTERN_COLOR_BAR

print(adafruit_ov7670.__name__ + " version: "
      + adafruit_ov7670.__version__)
print(adafruit_st7789.__name__ + " version: "
      + adafruit_st7789.__version__)
pid = cam.product_id
ver = cam.product_version
print(f"Detected cam pid={pid:x} ver={ver:x}")

width = display.width
height = display.height

bitmap = None
# Select the biggest size for which we can allocate a bitmap successfully,
# and which is not bigger than the display
for size in range(adafruit_ov7670.OV7670_SIZE_DIV1,
                  adafruit_ov7670.OV7670_SIZE_DIV16 + 1):
    cam.size = size
    if cam.width > width:
        continue
    if cam.height > height:
        continue
    try:
        bitmap = Bitmap(cam.width, cam.height, 65536)
        break
    except MemoryError:
        continue

print(width, height, cam.width, cam.height)
if bitmap is None:
    raise SystemExit("Could not allocate a bitmap")

g = Group(scale=1,
          x=(width - cam.width) // 2,
          y=(height - cam.height) // 2)
tg = TileGrid(
    bitmap, pixel_shader=ColorConverter(
        input_colorspace=Colorspace.RGB565_SWAPPED)
)
g.append(tg)
display.show(g)

#t0 = time.monotonic_ns()
display.auto_refresh = False
while True:
    cam.capture(bitmap)
    bitmap.dirty()
    display.refresh(minimum_frames_per_second=0)
    #t1 = time.monotonic_ns()
    #print("fps", 1e9 / (t1 - t0))
    #t0 = t1


Saturday, March 19, 2022

Nano RP2040 Connect/CircuitPython: list pins name of GPIOs

Many pins on CircuitPython compatible microcontroller boards have multiple names, however, typically, there's only one name labeled on the physical board. This example (modified from CircuitPython on the Arduino Nano RP2040 Connect > CircuitPython Pins and Modules > What Are All the Available Names?) run on Arduino Nano RP2040 Connect/CircuitPython 7.2.3 to list available pin names for all GPIOs.

"""CircuitPython Essentials Pin Map Script"""
import microcontroller
import board

board_pins = []
for pin in dir(microcontroller.pin):
    if isinstance(getattr(microcontroller.pin, pin), microcontroller.Pin):
        pins = []
        
        pins.append("microcontroller.{}".format(pin))
        pins.append('\t-')
        
        for alias in dir(board):
            if getattr(board, alias) is getattr(microcontroller.pin, pin):
                pins.append("board.{}\t".format(alias))
        if len(pins) > 0:
            board_pins.append(" ".join(pins))
for pins in sorted(board_pins):
    print(pins)




Fix "RuntimeError: None data for /?", in CircuitPython on Arduino Nano RP2040 Connect

To install CircuitPython on Arduino Nano RP2040 Connect, it's straightforward to following instruction in Adafruit document  "CircuitPython on the Arduino Nano RP2040 Connect > Install CircuitPython".

After CircuitPython 7.2.3 was installed on Arduino Nano RP2040 Connect, I can run REPL. BUT...I can't access CircuitPython device (named "?"), Problem when handling 'get_dirs_children_info_response' with "RuntimeError: None data for /?"!

Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/thonny/workbench.py", line 1711, in event_generate
    handler(event)
  File "/usr/lib/python3/dist-packages/thonny/base_file_browser.py", line 1001, in update_dir_data
    self.render_children_from_cache(msg["node_id"])
  File "/usr/lib/python3/dist-packages/thonny/base_file_browser.py", line 430, in render_children_from_cache
    raise RuntimeError("None data for %s" % path)
RuntimeError: None data for /?



Solution in my case:

I follow "To erase CIRCUITPY" section in CircuitPython on the Arduino Nano RP2040 Connect > Troubleshooting.

Enter in CircuitPython REPL:
>>> import storage
>>> storage.erase_filesystem()

Then, the problem fixed.


Friday, March 11, 2022

Install CircuitPython 7.2.0 on ESP32-S3 (ESP32-S3-DevKitC-1), using esptool v3.2 on Linux Mint

CircuitPython 7.2.0 was released. With espressif ESP32-S3 and ESP32-C3 supported (considered alpha and will have bugs and missing functionality).

To flash firmware on esp32s3, esptool v3.2 is needed. This post show the steps to flash CircuitPython 7.2.0 on ESP32-S3-DevKitC-1 N8R8 (with 8MB Flash and 8MB PSRAM) run on Linux Mint (over VirtualBox/Windows 10).



Visit CircuitPython download page, search "S3" and download .BIN for "ESP32-S3-DevKitC-1-N8R8 by Espressif".

Connect USB to the port marked "UART".

To check the ESP chip ID and Flash using commands:
$ esptool.py --chip auto --port /dev/ttyUSB0 chip_id
$ esptool.py --chip auto --port /dev/ttyUSB0 flash_id

Erase flash:
$ esptool.py --port /dev/ttyUSB0 erase_flash

Flash firmware:
$ esptool.py --chip esp32s3 --port <port> write_flash \-z 0x0 <file.BIN>

To program using CircuitPython, re-connect USB to the port marked "USB".

cpyESP32S3_info.py

"""
CircuitPython 7.2.0 exercise run on ESP32-S3,
get system info.
"""
import board
import sys
import os
"""
ref:
The entire table of ANSI color codes working in C:
https://gist.github.com/RabaDabaDoba/145049536f815903c79944599c6f952a
"""
class color:
   RED = '\033[1;31;48m'
   BLUE = '\033[1;34;48m'
   BLACK = '\033[1;30;48m'
   END = '\033[1;37;0m'

print(board.board_id)
print(sys.implementation[0] + ' ' +
      str(sys.implementation[1][0]) +'.'+
      str(sys.implementation[1][1]) +'.'+
      str(sys.implementation[1][2]))
print("==========================================")
info = color.RED + \
       sys.implementation[0] + ' ' + \
       os.uname()[3] + color.END + '\n' + \
       'run on ' + color.BLUE + os.uname()[4] + color.END
print(info)
print("==========================================")

print()
cpyESP32S3_NEOPIXEL.py, control onboard RGB LED.
import time
import os
import microcontroller
import neopixel
import board

def cycleNeopixel(wait):
    for r in range(255):
        pixel[0] = (r, 0, 0)
        time.sleep(wait)
    for r in range(255, 0, -1):
        pixel[0] = (r, 0, 0)
        time.sleep(wait)
        
    for g in range(255):
        pixel[0] = (0, g, 0)
        time.sleep(wait)
    for g in range(255, 0, -1):
        pixel[0] = (0, g, 0)
        time.sleep(wait)
        
    for b in range(255):
        pixel[0] = (0, 0, b)
        time.sleep(wait)
    for b in range(255, 0, -1):
        pixel[0] = (0, 0, b)
        time.sleep(wait)
        
print("==============================")
print("Hello ESP32-C3/CircuitPython NeoPixel exercise")
#print(os.uname())
for u in os.uname():
    print(u)
print()
print("neopixel version: " + neopixel.__version__)
print()

# Create the NeoPixel object
pixel = neopixel.NeoPixel(board.NEOPIXEL,
                          1,
                          pixel_order=neopixel.GRB)
pixel[0] = (0, 0, 0)
time.sleep(2.0)

cycleNeopixel(0.01)

pixel[0] = (0, 0, 0)
time.sleep(2.0)

print("- bye -\n")

Related:
~ To flash ESP32-S3, esptool v3.2 or above is needed. With esptool upgraded, we can now flash ESP32-S3 on Rspberry Pi.

Next:
CircuitPython BLE UART between XIAO BLE Sense and ESP32-C3/S3


Sunday, March 6, 2022

ESP32-C3/CircuitPython 7.2.0 + ST7735 TFT, display bmp in slideshow, and using displayio.OnDiskBitmap/adafruit_imageload.

Exercise of using CircuitPython 7.2.0 on  ESP32-C3-DevKitM-1 with 1.44" 128x128 ST7735 SPI TFT (KMR1441_SPI V2):
- display bmp in slideshow
- display bmp using OnDiskBitmap/adafruit_imageload

The display module used in this exercise is a with 1.44" 128x128 SPI TFT marked "KMR1441_SPI V2".


Connection:

Firstly, connect the display to ESP32-C3-DevKitM-1.

	ST7735		ESP32-C3-DevKitM-1
	------------------------------
	VCC		3V3
	GND		GND
	CS		IO10
	RESET		IO1
	A0		IO0
	SDA		IO3
	SCK		IO2
	LED		3V3

Library:

Visit CircuitPython Library page to download Bundle for Version 7.x, and extract it.

Copy the libraries to lib folder in Circuit device.
- adafruit_st7735r.mpy
- adafruit_display_text folder
- adafruit_slideshow.mpy
- adafruit_imageload folder

Exercise code:

cpyESP32C3_st7735_128x128.py, functional testing.

"""
CircuitPython 7.2.0 exercise run on  ESP32-C3-DevKitM-1
with 1.44" 128x128 (KMR1441_SPI V2)

ref:
adafruit/Adafruit_CircuitPython_ST7735R
https://github.com/adafruit/Adafruit_CircuitPython_ST7735R
"""

from sys import implementation as sysImplementation
import time
import os
import board
import busio
import displayio
import terminalio

from adafruit_st7735r import ST7735R as TFT_ST7735
from adafruit_st7735r import __name__ as ST7735_NAME
from adafruit_st7735r import __version__ as ST7735_VERSION

from adafruit_display_text import label

# Release any resources currently in use for the displays
displayio.release_displays()

#Connection between ESP32-C3 and SPI ST7735 display
                        #marking on display
tft_sck = board.IO2     #SCK
tft_mosi = board.IO3    #SDA
tft_dc = board.IO0      #A0
tft_reset = board.IO1   #RESET
tft_cs = board.IO10     #CS
#Backlight (LED) connect to ESP32-C3 3V3
#TFT VCC - ESP32-C3 3V3
#TFT GND - ESP32-C3 GND

tft_spi = busio.SPI(clock=tft_sck, MOSI=tft_mosi)
display_bus = displayio.FourWire(
    tft_spi, command=tft_dc, chip_select=tft_cs, reset=tft_reset)

display = TFT_ST7735(display_bus, width=128, height=128,
                     rotation=90,
                     bgr=True)

strSys = sysImplementation[0] + ' ' + \
         str(sysImplementation[1][0]) +'.'+ \
         str(sysImplementation[1][1]) +'.'+ \
         str(sysImplementation[1][2])

print("==========================================")

print(strSys)
print('run on ' + os.uname()[4])
print('using', ST7735_NAME, ST7735_VERSION)
print("==========================================")

print(type(display))
print("display.width:  ", display.width)
print("display.height: ", display.height)

# Make the display context
splash = displayio.Group()
display.show(splash)

color_bitmap = displayio.Bitmap(display.width, display.height, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0x000000
time.sleep(1)

bg_sprite = displayio.TileGrid(color_bitmap,
                               pixel_shader=color_palette, x=0, y=0)
splash.append(bg_sprite)

for c in [["RED", 0xFF0000],
          ["GREEN", 0x00FF00],
          ["BLUE", 0x0000FF]]:
    print(c[0], " : ", hex(c[1]))
    color_palette[0] = c[1]
    time.sleep(2)

splash.remove(bg_sprite)
#---

# Make the display context
#splash = displayio.Group()
#display.show(splash)

color_bitmap = displayio.Bitmap(display.width, display.height, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0x00FF00

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(display.width-2, display.height-2, 1)
inner_palette = displayio.Palette(1)
inner_palette[0] = 0x0000FF
inner_sprite = displayio.TileGrid(inner_bitmap,
                                  pixel_shader=inner_palette, x=1, y=1)
splash.append(inner_sprite)

# Draw a label
text_group1 = displayio.Group(scale=1, x=5, y=10)
text1 = "ESP32-C3"
text_area1 = label.Label(terminalio.FONT, text=text1, color=0xFF0000)
text_group1.append(text_area1)  # Subgroup for text scaling

# Draw a label

text_group2 = displayio.Group(scale=1, x=5, y=25)
text2 = strSys
text_area2 = label.Label(terminalio.FONT, text=text2, color=0xFFFFFF)
text_group2.append(text_area2)  # Subgroup for text scaling

# Draw a label
text_group3 = displayio.Group(scale=1, x=5, y=40)
text3 = ST7735_NAME
text_area3 = label.Label(terminalio.FONT, text=text3, color=0x0000000)
text_group3.append(text_area3)  # Subgroup for text scaling
# Draw a label
text_group4 = displayio.Group(scale=1, x=5, y=55)
text4 = ST7735_VERSION
text_area4 = label.Label(terminalio.FONT, text=text4, color=0x000000)
text_group4.append(text_area4)  # Subgroup for text scaling

text_group5 = displayio.Group(scale=1, x=5, y=70)
text5 = str(display.width) + " x " + str(display.height)
text_area5 = label.Label(terminalio.FONT, text=text5, color=0x000000)
text_group5.append(text_area5)  # Subgroup for text scaling

splash.append(text_group1)
splash.append(text_group2)
splash.append(text_group3)
splash.append(text_group4)
splash.append(text_group5)

time.sleep(3.0)

rot = 90
while True:
    time.sleep(5.0)
    rot = rot + 90
    if (rot>=360):
        rot = 0
    display.rotation = rot
cpyESP32C3_st7735_slideshow.py, Test with exercise in "Creating Slideshows in CircuitPython".
"""
CircuitPython 7.2.0 exercise run on  ESP32-C3-DevKitM-1
with 1.44" 128x128 (KMR1441_SPI V2)
- slideshow

ref:
adafruit/Adafruit_CircuitPython_ST7735R
https://github.com/adafruit/Adafruit_CircuitPython_ST7735R
"""

from sys import implementation as sysImplementation
import time
import os
import board
import busio
import displayio
import terminalio

from adafruit_st7735r import ST7735R as TFT_ST7735
from adafruit_st7735r import __name__ as ST7735_NAME
from adafruit_st7735r import __version__ as ST7735_VERSION

from adafruit_display_text import label

# Release any resources currently in use for the displays
displayio.release_displays()

#Connection between ESP32-C3 and SPI ST7735 display
                        #marking on display
tft_sck = board.IO2     #SCK
tft_mosi = board.IO3    #SDA
tft_dc = board.IO0      #A0
tft_reset = board.IO1   #RESET
tft_cs = board.IO10     #CS
#Backlight (LED) connect to ESP32-C3 3V3
#TFT VCC - ESP32-C3 3V3
#TFT GND - ESP32-C3 GND

tft_spi = busio.SPI(clock=tft_sck, MOSI=tft_mosi)
display_bus = displayio.FourWire(
    tft_spi, command=tft_dc, chip_select=tft_cs, reset=tft_reset)

display = TFT_ST7735(display_bus, width=128, height=128,
                     rotation=90,
                     bgr=True)

strSys = sysImplementation[0] + ' ' + \
         str(sysImplementation[1][0]) +'.'+ \
         str(sysImplementation[1][1]) +'.'+ \
         str(sysImplementation[1][2])

print("==========================================")

print(strSys)
print('run on ' + os.uname()[4])
print('using', ST7735_NAME, ST7735_VERSION)
print("==========================================")

print(type(display))
print("display.width:  ", display.width)
print("display.height: ", display.height)

#===============================
# SPDX-FileCopyrightText: 2019 Anne Barela for Adafruit Industries
#
# SPDX-License-Identifier: MIT

# CircuitPython Slideshow - uses the adafruit_slideshow.mpy library
#import board
from adafruit_slideshow import PlayBackOrder, SlideShow

# Create the slideshow object that plays through once alphabetically.
slideshow = SlideShow(display,
                      folder="/images",
                      loop=True,
                      order=PlayBackOrder.ALPHABETICAL,
                      dwell=5)

while slideshow.update():
    pass
cpyESP32C3_st7735_OnDiskBitmap.py, test with OnDiskBitmap example in "Display a Bitmap".
"""
CircuitPython 7.2.0 exercise run on  ESP32-C3-DevKitM-1
with 1.44" 128x128 (KMR1441_SPI V2)
- OnDiskBitmap

ref:
adafruit/Adafruit_CircuitPython_ST7735R
https://github.com/adafruit/Adafruit_CircuitPython_ST7735R
"""

from sys import implementation as sysImplementation
import time
import os
import board
import busio
import displayio
import terminalio

from adafruit_st7735r import ST7735R as TFT_ST7735
from adafruit_st7735r import __name__ as ST7735_NAME
from adafruit_st7735r import __version__ as ST7735_VERSION

from adafruit_display_text import label

# Release any resources currently in use for the displays
displayio.release_displays()

#Connection between ESP32-C3 and SPI ST7735 display
                        #marking on display
tft_sck = board.IO2     #SCK
tft_mosi = board.IO3    #SDA
tft_dc = board.IO0      #A0
tft_reset = board.IO1   #RESET
tft_cs = board.IO10     #CS
#Backlight (LED) connect to ESP32-C3 3V3
#TFT VCC - ESP32-C3 3V3
#TFT GND - ESP32-C3 GND

tft_spi = busio.SPI(clock=tft_sck, MOSI=tft_mosi)
display_bus = displayio.FourWire(
    tft_spi, command=tft_dc, chip_select=tft_cs, reset=tft_reset)

display = TFT_ST7735(display_bus, width=128, height=128,
                     rotation=90,
                     bgr=True)

strSys = sysImplementation[0] + ' ' + \
         str(sysImplementation[1][0]) +'.'+ \
         str(sysImplementation[1][1]) +'.'+ \
         str(sysImplementation[1][2])

print("==========================================")

print(strSys)
print('run on ' + os.uname()[4])
print('using', ST7735_NAME, ST7735_VERSION)
print("==========================================")

print(type(display))
print("display.width:  ", display.width)
print("display.height: ", display.height)

#===============================
# SPDX-FileCopyrightText: 2019 Carter Nelson for Adafruit Industries
#
# SPDX-License-Identifier: MIT

#import board
#import displayio

#display = board.DISPLAY

# Future method for CircuitPython 7 onwards

# Setup the file as the bitmap data source
bitmap = displayio.OnDiskBitmap("images/002.bmp")

# Create a TileGrid to hold the bitmap
tile_grid = displayio.TileGrid(bitmap, pixel_shader=bitmap.pixel_shader)

# Create a Group to hold the TileGrid
group = displayio.Group()

# Add the TileGrid to the Group
group.append(tile_grid)

# Add the Group to the Display
display.show(group)

# Loop forever so you can enjoy your image
while True:
    pass
cpyESP32C3_st7735_ImageLoad.py, test with example of ImageLoad in "Display a Bitmap"
"""
CircuitPython 7.2.0 exercise run on  ESP32-C3-DevKitM-1
with 1.44" 128x128 (KMR1441_SPI V2)
- ImageLoad

ref:
adafruit/Adafruit_CircuitPython_ST7735R
https://github.com/adafruit/Adafruit_CircuitPython_ST7735R
"""

from sys import implementation as sysImplementation
import time
import os
import board
import busio
import displayio
import terminalio

from adafruit_st7735r import ST7735R as TFT_ST7735
from adafruit_st7735r import __name__ as ST7735_NAME
from adafruit_st7735r import __version__ as ST7735_VERSION

from adafruit_display_text import label

# Release any resources currently in use for the displays
displayio.release_displays()

#Connection between ESP32-C3 and SPI ST7735 display
                        #marking on display
tft_sck = board.IO2     #SCK
tft_mosi = board.IO3    #SDA
tft_dc = board.IO0      #A0
tft_reset = board.IO1   #RESET
tft_cs = board.IO10     #CS
#Backlight (LED) connect to ESP32-C3 3V3
#TFT VCC - ESP32-C3 3V3
#TFT GND - ESP32-C3 GND

tft_spi = busio.SPI(clock=tft_sck, MOSI=tft_mosi)
display_bus = displayio.FourWire(
    tft_spi, command=tft_dc, chip_select=tft_cs, reset=tft_reset)

display = TFT_ST7735(display_bus, width=128, height=128,
                     rotation=90,
                     bgr=True)

strSys = sysImplementation[0] + ' ' + \
         str(sysImplementation[1][0]) +'.'+ \
         str(sysImplementation[1][1]) +'.'+ \
         str(sysImplementation[1][2])

print("==========================================")

print(strSys)
print('run on ' + os.uname()[4])
print('using', ST7735_NAME, ST7735_VERSION)
print("==========================================")

print(type(display))
print("display.width:  ", display.width)
print("display.height: ", display.height)

#===============================
# SPDX-FileCopyrightText: 2019 Carter Nelson for Adafruit Industries
#
# SPDX-License-Identifier: MIT

#import board
#import displayio
import adafruit_imageload

#display = board.DISPLAY

bitmap, palette = adafruit_imageload.load("images/003i.bmp",
                                          bitmap=displayio.Bitmap,
                                          palette=displayio.Palette)

# Create a TileGrid to hold the bitmap
tile_grid = displayio.TileGrid(bitmap, pixel_shader=palette)

# Create a Group to hold the TileGrid
group = displayio.Group()

# Add the TileGrid to the Group
group.append(tile_grid)

# Add the Group to the Display
display.show(group)

# Loop forever so you can enjoy your image
while True:
    pass


Sunday, February 27, 2022

Install CircuitPython 7.2.0 on ESP32-C3 (ESP32-C3-DevKitM-1/NodeMCU ESP-C3-32S-Kit)

CircuitPython 7.2.0 was released. With espressif ESP32-S3 and ESP32-C3 supported (considered alpha and will have bugs and missing functionality).


This post show how to install CircuitPython 7.2.0 on ESP32-C3-DevKitM-1 (ESP32-C3-MINI-1), using Raspberry Pi 4B running Raspberry Pi OS 32-bit (buster). Then test with exercise to read system info, control onboard RGB (NEOPIXEL), and 0.96" 80x160 IPS.



Download Firmware:

Visit CircuitPython Download page, search C3.

I can't find exact board named "ESP32-C3-DevKitM-1", so I try "ESP32-C3-DevKitC-1-N4 by Espressif". DOWNLOAD .BIN NOW under CircuitPython 7.2.0, it's adafruit-circuitpython-espressif_esp32c3_devkitm_1_n4-en_US-7.2.0.bin.

Identify USB port:

Before connect the board to USB.
Run the command to clear dmesg buffer -
$ sudo dmesg -c

Connect the ESP32-C3-DevKitM-1 board to USB.
Run dmesg again, the connected port will be shown -
$ dmesg

Install CircuitPython firmware using esptool:

esptool is needed to flash firmware on ESP devices.
~ Install esptool on Raspberry Pi OS (32 bit)

With esptool installed, you can check the ESP chip ID and Flash using commands:
$ esptool.py --chip auto --port /dev/ttyUSB0 chip_id
$ esptool.py --chip auto --port /dev/ttyUSB0 flash_id

To erase the flash, enter:
$ esptool.py --port /dev/ttyUSB0 erase_flash

To flash the firmware, I follow the command in MicroPython document > Getting started with MicroPython on the ESP32 > Deploying the firmware.
replace:
- chip to esp32c3
- port
- address start from 0x0
- file name
$ esptool.py --chip esp32c3 --port /dev/ttyUSB0 write_flash \-z 0x0 \
adafruit-circuitpython-espressif_esp32c3_devkitm_1_n4-en_US-7.2.0.bin
Exercise code:

cpyESP32C3_info.py, get CircuitPython info
"""
CircuitPython 7.2.0 exercise run on ESP32-C3,
get system info.
"""
import board
import sys
import os
"""
ref:
The entire table of ANSI color codes working in C:
https://gist.github.com/RabaDabaDoba/145049536f815903c79944599c6f952a
"""
class color:
   RED = '\033[1;31;48m'
   BLUE = '\033[1;34;48m'
   BLACK = '\033[1;30;48m'
   END = '\033[1;37;0m'

print(board.board_id)
print(sys.implementation[0] + ' ' +
      str(sys.implementation[1][0]) +'.'+
      str(sys.implementation[1][1]) +'.'+
      str(sys.implementation[1][2]))
print("==========================================")
info = color.RED + \
       sys.implementation[0] + ' ' + \
       os.uname()[3] + color.END + '\n' + \
       'run on ' + color.BLUE + os.uname()[4] + color.END
print(info)
print("==========================================")

print()

cpyESP32C3_NEOPIXEL.py, control onboard RGB (Neopixel).
import time
import os
import microcontroller
import neopixel
import board

def cycleNeopixel(wait):
    for r in range(255):
        pixel[0] = (r, 0, 0)
        time.sleep(wait)
    for r in range(255, 0, -1):
        pixel[0] = (r, 0, 0)
        time.sleep(wait)
        
    for g in range(255):
        pixel[0] = (0, g, 0)
        time.sleep(wait)
    for g in range(255, 0, -1):
        pixel[0] = (0, g, 0)
        time.sleep(wait)
        
    for b in range(255):
        pixel[0] = (0, 0, b)
        time.sleep(wait)
    for b in range(255, 0, -1):
        pixel[0] = (0, 0, b)
        time.sleep(wait)
        
print("==============================")
print("Hello ESP32-C3/CircuitPython NeoPixel exercise")
#print(os.uname())
for u in os.uname():
    print(u)
print()
print("neopixel version: " + neopixel.__version__)
print()

# Create the NeoPixel object
pixel = neopixel.NeoPixel(board.NEOPIXEL,
                          1,
                          pixel_order=neopixel.RGB)
pixel[0] = (0, 0, 0)
time.sleep(2.0)

cycleNeopixel(0.01)

pixel[0] = (0, 0, 0)
time.sleep(2.0)

print("- bye -\n")

cpyESP32C3_st7735_80x160.py, test with 0.96" 80x160 IPS.
"""
CircuitPython 7.2.0 exercise run on ESP32-C3
with unknown brand 0.96 inch 80x160 SPI ST7735 IPS

ref:
adafruit/Adafruit_CircuitPython_ST7735R
https://github.com/adafruit/Adafruit_CircuitPython_ST7735R
"""

from sys import implementation as sysImplementation
import time
import board
import busio
import displayio
import terminalio

from adafruit_st7735r import ST7735R as TFT_ST7735
from adafruit_st7735r import __name__ as ST7735_NAME
from adafruit_st7735r import __version__ as ST7735_VERSION

from adafruit_display_text import label

# Release any resources currently in use for the displays
displayio.release_displays()

#Connection between ESP32-C3 and SPI ST7735 display
                        #marking on display
tft_sck = board.IO2     #SCL
tft_mosi = board.IO3    #SDA
tft_reset = board.IO0   #RES
tft_dc = board.IO1      #DC
tft_cs = board.IO10     #CS
#Backlight (BLK) connect to ESP32-C3 3V3
#TFT VCC - ESP32-C31 3V3
#TFT GND - ESP32-C3 GND

tft_spi = busio.SPI(clock=tft_sck, MOSI=tft_mosi)
display_bus = displayio.FourWire(
    tft_spi, command=tft_dc, chip_select=tft_cs, reset=tft_reset
)

# I find out colrstart/rowstart by try/error and retry
display = TFT_ST7735(display_bus, width=160, height=80,
                     colstart=26, rowstart=1,
                     rotation=90,
                     invert=True
                     )

print(type(display))
print("display.width:  ", display.width)
print("display.height: ", display.height)

# Make the display context
splash = displayio.Group()
display.show(splash)

color_bitmap = displayio.Bitmap(display.width, display.height, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0x000000
time.sleep(1)

bg_sprite = displayio.TileGrid(color_bitmap,
                               pixel_shader=color_palette, x=0, y=0)
splash.append(bg_sprite)

for c in [["RED", 0xFF0000],
          ["GREEN", 0x00FF00],
          ["BLUE", 0x0000FF]]:
    print(c[0], " : ", hex(c[1]))
    color_palette[0] = c[1]
    time.sleep(2)

splash.remove(bg_sprite)
#---

# Make the display context
#splash = displayio.Group()
#display.show(splash)

color_bitmap = displayio.Bitmap(display.width, display.height, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0x00FF00

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(display.width-2, display.height-2, 1)
inner_palette = displayio.Palette(1)
inner_palette[0] = 0x0000FF
inner_sprite = displayio.TileGrid(inner_bitmap,
                                  pixel_shader=inner_palette, x=1, y=1)
splash.append(inner_sprite)

# Draw a label
text_group1 = displayio.Group(scale=1, x=5, y=10)
text1 = "ESP32-C3"
text_area1 = label.Label(terminalio.FONT, text=text1, color=0xFF0000)
text_group1.append(text_area1)  # Subgroup for text scaling

# Draw a label
strSys = sysImplementation[0] + ' ' + \
         str(sysImplementation[1][0]) +'.'+ \
         str(sysImplementation[1][1]) +'.'+ \
         str(sysImplementation[1][2])
text_group2 = displayio.Group(scale=1, x=5, y=25)
text2 = strSys
text_area2 = label.Label(terminalio.FONT, text=text2, color=0xFFFFFF)
text_group2.append(text_area2)  # Subgroup for text scaling

# Draw a label
text_group3 = displayio.Group(scale=1, x=5, y=40)
text3 = ST7735_NAME
text_area3 = label.Label(terminalio.FONT, text=text3, color=0x0000000)
text_group3.append(text_area3)  # Subgroup for text scaling
# Draw a label
text_group4 = displayio.Group(scale=1, x=5, y=55)
text4 = ST7735_VERSION
text_area4 = label.Label(terminalio.FONT, text=text4, color=0x000000)
text_group4.append(text_area4)  # Subgroup for text scaling

text_group5 = displayio.Group(scale=1, x=5, y=70)
text5 = str(display.width) + " x " + str(display.height)
text_area5 = label.Label(terminalio.FONT, text=text5, color=0x000000)
text_group5.append(text_area5)  # Subgroup for text scaling

splash.append(text_group1)
splash.append(text_group2)
splash.append(text_group3)
splash.append(text_group4)
splash.append(text_group5)

time.sleep(3.0)

rot = 90
while True:
    time.sleep(5.0)
    rot = rot + 90
    if (rot>=360):
        rot = 0
    display.rotation = rot

Download firmware for "ESP-C3-32S by Ai-Thinker",  adafruit-circuitpython-ai_thinker_esp32-c3s-en_US-7.2.0.bin.



Replace the file name in flashing command:
$ esptool.py --chip esp32c3 --port /dev/ttyUSB0 write_flash \-z 0x0
adafruit-circuitpython-ai_thinker_esp32-c3s-en_US-7.2.0.bin
cpyESP32C3_info.py run on NodeMCU ESP-C3-32S-Kit:


check the board assignment:





next:
ESP32-C3/CircuitPython 7.2.0 + ST7735 TFT, display bmp in slideshow, and using displayio.OnDiskBitmap/adafruit_imageload.

Sunday, October 17, 2021

STM32F411/CircuitPython 7, with 2" 240x320 SPI ST7789 IPS LCD

To use ST7789 SPI LCD on STM32F411/CircuitPython 7.0.0, basically same as shown in the post: "CircuitPython 7 exercises on STM32F411, with SPI ST7735 LCD", except using library of adafruit_st7789 instead of using adafruit_st7735/adafruit_st7735r.


cpyF411_st7789_240x320.py
"""
CircuitPython 7 exercise run on STM32F411
with 2" 240x320 SPI ST7789 IPS

"""

from sys import implementation as sysImplementation
import time
import board
import busio
import displayio
import terminalio

from adafruit_st7789 import ST7789 as TFT_ST77xx
from adafruit_st7789 import __name__ as ST77xx_NAME
from adafruit_st7789 import __version__ as ST77xx_VERSION

from adafruit_display_text import label

# Release any resources currently in use for the displays
displayio.release_displays()

#Connection between STM32F411 and SPI ST7789 display
#marking on display     
tft_sck = board.B13     #SCL
tft_mosi = board.A1     #SDA


tft_dc = board.A2       #DC
tft_reset = board.A3    #RES
tft_cs = board.A4       #CS
#Backlight (LED/BLK) connect to STM32F411 3V3
#TFT VCC - STM32F411 3V3
#TFT GND - STM32F411 GND

tft_spi = busio.SPI(clock=tft_sck, MOSI=tft_mosi)
display_bus = displayio.FourWire(
    tft_spi, command=tft_dc, chip_select=tft_cs, reset=tft_reset
)

# I find out colrstart/rowstart by try/error and retry
display = TFT_ST77xx(display_bus, width=320, height=240,
                     colstart=0, rowstart=0,
                     rotation=90,
                     )

print(type(display))
print("display.width:  ", display.width)
print("display.height: ", display.height)

# Make the display context
splash = displayio.Group()
display.show(splash)

color_bitmap = displayio.Bitmap(display.width, display.height, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0x000000
time.sleep(1)

bg_sprite = displayio.TileGrid(color_bitmap,
                               pixel_shader=color_palette, x=0, y=0)
splash.append(bg_sprite)

for c in [["RED", 0xFF0000],
          ["GREEN", 0x00FF00],
          ["BLUE", 0x0000FF]]:
    print(c[0], " : ", hex(c[1]))
    color_palette[0] = c[1]
    time.sleep(2)

splash.remove(bg_sprite)
#---

# Make the display context
#splash = displayio.Group()
#display.show(splash)

color_bitmap = displayio.Bitmap(display.width, display.height, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0x00FF00

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(display.width-2, display.height-2, 1)
inner_palette = displayio.Palette(1)
inner_palette[0] = 0x0000FF
inner_sprite = displayio.TileGrid(inner_bitmap,
                                  pixel_shader=inner_palette, x=1, y=1)
splash.append(inner_sprite)

# Draw a label
text_group1 = displayio.Group(scale=1, x=5, y=10)
text1 = "STM32F411"
text_area1 = label.Label(terminalio.FONT, text=text1, color=0xFF0000)
text_group1.append(text_area1)  # Subgroup for text scaling

# Draw a label
strSys = sysImplementation[0] + ' ' + \
         str(sysImplementation[1][0]) +'.'+ \
         str(sysImplementation[1][1]) +'.'+ \
         str(sysImplementation[1][2])
text_group2 = displayio.Group(scale=1, x=5, y=25)
text2 = strSys
text_area2 = label.Label(terminalio.FONT, text=text2, color=0xFFFFFF)
text_group2.append(text_area2)  # Subgroup for text scaling

# Draw a label
text_group3 = displayio.Group(scale=1, x=5, y=40)
text3 = ST77xx_NAME
text_area3 = label.Label(terminalio.FONT, text=text3, color=0x0000000)
text_group3.append(text_area3)  # Subgroup for text scaling
# Draw a label
text_group4 = displayio.Group(scale=1, x=5, y=55)
text4 = ST77xx_VERSION
text_area4 = label.Label(terminalio.FONT, text=text4, color=0x000000)
text_group4.append(text_area4)  # Subgroup for text scaling

text_group5 = displayio.Group(scale=1, x=5, y=70)
text5 = str(display.width) + " x " + str(display.height)
text_area5 = label.Label(terminalio.FONT, text=text5, color=0x000000)
text_group5.append(text_area5)  # Subgroup for text scaling

splash.append(text_group1)
splash.append(text_group2)
splash.append(text_group3)
splash.append(text_group4)
splash.append(text_group5)

time.sleep(3.0)

rot = 90
while True:
    time.sleep(5.0)
    rot = rot + 90
    if (rot>=360):
        rot =0
    display.rotation = rot