quinta-feira, novembro 17, 2022

Display LCD Circular

Estes displays apareceram nos anúncios da AliExpress e me deixaram curioso. Vamos ver o que são eles e como colocar para funcionar com o CircuitPython.


Embora existam placas diferentes com este display, as características básicas são sempre as mesmas:

  • 1,28" de diâmetro
  • Resolução de 240 x 240 pontos (reparar que parte destes pontos não existem fisicamente)
  • Display colorido (16 bits por cor, o chamado "65K" cores)
  • LCD (alguns anúncios falam em IPS e outros em TFT)
  • Controlador GC9A01 com interface SPI (apesar do conector usar os nomes SDA e SCL)
As diferenças que vi nos anúncios foram:
  • Operação a 3,3 e 5V ou apenas a 3,3V
  • Controle do backlight
  • Placa redonda (como o display) ou quadrada.
O modelo que eu comprei trabalha a 3,3 ou 5V, não tem controle do backlight e a placa é redonda.

Para um primeiro teste resolvi usar o CircuitPython e um XIAO RP2040.  Poderia ter sido um Pi Pico, mas com o XIAO ficou mais compacto. As conexões display / XIAO são:
  • RST - D0
  • CS - D1
  • DC - D2
  • SDA- D10 (MOSI)
  • SCL - DI (SCK)
  • GND - GND
  • VCC - 3V3
O CircuitPython possui módulos que facilitam bastante o uso de display gráficos e um driver para o GC9A01. Um problema é ter que baixar estes módulos e copiá-los para a placa do microcontrolador. Felizmente existe um utilitário para facilitar isso, o CircUp. Para instalá-lo e usá-lo você precisa ter instalado e acessível na linha de comando:
  • Uma versão recente do Python 3
  • O utilitário pio correspondente
  • O utilitário git
Aí basta um "pip install circup".

A instalação do CircuitPython no XIAO RP2040 (e outras placas baseadas no RP2040) é simples: baixe o arquivo uf2 de https://circuitpython.org/downloads, conecte a placa ap PC com o botão BOOT apertado e copie o arquivo uf2 para o drive RPI-RP2 que foi criado.

Para copiar para o XIAO as bibliotecas necessárias:
circup install gc9a01
circup install adafruit_display_text
circup install adafruit_imageload
O código abaixo é uma adaptação do que está em https://github.com/todbot/CircuitPython_GC9A01_demos/tree/main/examples/eyeballs, minha mexida consiste em usar os nomes adequados para os pinos do XIAO.
# qteye.py - a stand-alone GC9A01 round LCD "eye" on a QTPy
# 23 Oct 2022 - @todbot / Tod Kurt
# Part of https://github.com/todbot/CircuitPython_GC9A01_demos
# also see: https://twitter.com/todbot/status/1584309133263532033
#      and: https://twitter.com/todbot/status/1584309133263532033
# Copy this file as "code.py" and the two eyeball BMP files to CIRCUITPY drive
# To install needed libraries: "circup install adafruit_imageload gc9a01"
# 16 Nov 2020 - @dqsoft / Daniel Quadros
# Changed pin names in "wiring" for use with XIAO RP2040
#
import time, math, random
import board, busio
import displayio
import adafruit_imageload
import gc9a01

displayio.release_displays()

dw, dh = 240,240  # display dimensions

# load our eye and iris bitmaps
eyeball_bitmap, eyeball_pal = adafruit_imageload.load("imgs/eye0_ball2.bmp")
iris_bitmap, iris_pal = adafruit_imageload.load("imgs/eye0_iris0.bmp")
iris_pal.make_transparent(0)  # palette color #0 is our transparent background

# 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 = 20  # allowable deviation from center for iris

# wiring
tft0_clk = board.D8 # must be a SPI CLK
tft0_mosi= board.D10 # must be a SPI TX

tft_L0_rst = board.D0
tft_L0_dc  = board.D2
tft_L0_cs  = board.D1

spi0 = busio.SPI(clock=tft0_clk, MOSI=tft0_mosi)

# class to help us track eye info (not needed for this use exactly, but I find it interesting)
class Eye:
    def __init__(self, spi, dc, cs, rst, rot=0, eye_speed=0.25, twitch=2):
        display_bus = displayio.FourWire(spi, command=dc, chip_select=cs, reset=rst)
        display = gc9a01.GC9A01(display_bus, width=dw, height=dh, rotation=rot)
        main = displayio.Group()
        display.show(main)
        self.display = display
        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( spi0, tft_L0_dc, tft_L0_cs,  tft_L0_rst, rot=0, eye_speed=0.10),
]

while True:
    for eye in the_eyes:
        eye.update()
Para rodar o código é preciso copiar na placa a pasta "imgs" do repositório acima.



Nas referências abaixo tem outros exemplos que certamente darão ideias de outros usos para este display.

Referências:

Mais informações sobre o display:

Descrição detalhada do CircUp:

Demos diversos do display com CircuitPython:



Nenhum comentário: