XIAO Round Display

Is there circuitpython support for the XIAO Round Display?

I am programming my XIAO NRFs using circuitpython and would like to incorporate the round display in a project.

I have just received my board and so far I have managed to make it work in CircuitPython.
The display itself is a GC9A01, that is fully supported.
You could install the library using circup install gc9a01.
Then you could run any example from todbot Github: GitHub - todbot/CircuitPython_GC9A01_demos: Demos showing how to use CircuitPython displayio driver for GC9A01 round LCDs

The touch module is CHSC6X running at 0x2e address. The Touch_Int is board.D7.
I haven’t found any drivers for that module yet. It looks like there is a Micropython version.

You just need to watch the initialization settings and some minor changes in displayio calls in new Circuitpython version (9.01).

Bellow is the code for c9a01_lizard_eye.py with all the changes needed…

import time, math, random
import board, busio
import displayio
import adafruit_imageload
import gc9a01

# This is the correct pinout for my Xiao RP2040
# Does not need the reset line...

tft_dc  = board.D3
tft_cs  = board.D1
tft_bl  = board.D6
touch_int = board.D7

spi = busio.SPI(clock=board.SCK, MOSI=board.MOSI)

# load our eye and iris bitmaps
dw, dh = 240,240  # display dimensions

# Don't forget to save the images in correct folder on your board

eyeball_bitmap, eyeball_pal = adafruit_imageload.load("imgs/Lizard_Sclera.bmp")
iris_bitmap, iris_pal = adafruit_imageload.load("imgs/Lizard_Iris_White.bmp")
iris_pal.make_transparent(244)

# compute or declare some useful info about the eyes
iris_w, iris_h = iris_bitmap.width, iris_bitmap.height  # iris is normally 110x110
iris_cx, iris_cy = dw//2 - iris_w//2, dh//2 - iris_h//2
r = 15  # allowable deviation from center for iris

# Sometimes they use this approach when need more than one eye
# But I never could get it wor in CircuitPython...

class Eye:
    # You could remove rst from __init__
    def __init__(self, spi, dc, cs, rot=0, eye_speed=0.5, twitch=1):
        display_bus = displayio.FourWire(spi, command=dc, chip_select=cs)
        display = gc9a01.GC9A01(display_bus, width=dw, height=dh, rotation=rot)
        main = displayio.Group()
        # This is the new way to show something in display. 
        display.root_group = main
        self.display = display # istead of display.show()
        self.eyeball = displayio.TileGrid(eyeball_bitmap, pixel_shader=eyeball_pal)
        self.iris = displayio.TileGrid(iris_bitmap, pixel_shader=iris_pal, x=iris_cx,y=iris_cy)
        main.append(self.eyeball)
        main.append(self.iris)
        self.x, self.y = iris_cx, iris_cy
        self.tx, self.ty = self.x, self.y
        self.next_time = time.monotonic()
        self.eye_speed = eye_speed
        self.twitch = twitch

    def update(self):
        self.x = self.x * (1-self.eye_speed) + self.tx * self.eye_speed # "easing"
        self.y = self.y * (1-self.eye_speed) + self.ty * self.eye_speed
        self.iris.x = int( self.x )
        self.iris.y = int( self.y )
        if time.monotonic() > self.next_time:
            t = random.uniform(0.25,self.twitch)
            self.next_time = time.monotonic() + t
            self.tx = iris_cx + random.uniform(-r,r)
            self.ty = iris_cy + random.uniform(-r,r)
        self.display.refresh()

# a list of all the eyes, in this case, only one
the_eyes = [
    Eye( spi, tft_dc, tft_cs,  rot=0),
]

while True:
    for eye in the_eyes:
        eye.update()

A sugestão do Chat GPT para converter a biblioteca de Micropython para Circuitpython é essa aqui. Eu ainda não fiz o teste.

Na pasta lib, crie uma nova pasta chamada chsc6x. Dentro dessa pasta, salve um arquivo init.py com o seguinte conteúdo:

import board
import busio
import digitalio
from time import sleep

class CHSC6X:
    CHSC6X_I2C_ID = 0x2e
    CHSC6X_READ_POINT_LEN = 5

    def __init__(self, i2c, irq_pin=None):
        self._i2c = i2c
        self._addr = self.CHSC6X_I2C_ID
        self._irq = digitalio.DigitalInOut(irq_pin) if irq_pin else None
        if self._irq:
            self._irq.switch_to_input(pull=digitalio.Pull.UP)
        self._buffer = bytearray(self.CHSC6X_READ_POINT_LEN)
        sleep(0.1)

    def is_touched(self):
        if self._irq:
            return not self._irq.value
        return self.touch_read() is not None

    def touch_read(self):
        if self._irq and not self._irq.value:
            self._i2c.readfrom_into(self._addr, self._buffer)
        else:
            try:
                self._i2c.readfrom_into(self._addr, self._buffer)
            except OSError:  # Thrown when reading too fast
                return None

        results = [i for i in self._buffer]
        # first byte is non-zero when touched, 3rd byte is x, 5th byte is y
        if results[0]:
            return results[2], results[4]
        return None

def main():
    print("Started...")
    i2c = busio.I2C(board.SCL, board.SDA, frequency=400000)
    irq_pin = digitalio.DigitalInOut(board.D7)
    touch = CHSC6X(i2c, irq_pin=irq_pin)

    while True:
        if touch.is_touched():
            print("Touched: ", touch.touch_read())
        sleep(0.1)

if __name__ == "__main__":
    main()

The above version does not work properly on Circuitpython. It detects the touch on the screen, but soon an error message appears. It’s probably worth studying Adafruit’s library for the TSC2007 parent company and seeing if it’s possible to adapt. The datasheet for CHSC6X can be downloaded in https://szzxv.com/static/upload/file/20220301/1646141990530969.pdf