Raspberry Pi Pico / CircuitPython + ILI9341 SPI Display com toque
Neste exercício, o Raspberry Pi Pico é atualizado com o Adafruit CircuitPython 6.2.0. Exibir no display ILI9341 SPI com toque usando a biblioteca adafruit_ili9341. Para a detecção de toque, xpt2046.py de rdagger/micropython-ili9341 foi modificado para funcionar com CircuitPython.
A tela usada neste exercício é uma cor de 65K de 2,4 polegadas usando o driver ili9341 com toque, 2.4inch_SPI_Module_ILI9341_SKU: MSP2402.
Conteudo
Conexão
Conexão
ILI9341 TFT SPI RPi Pico
------------------------------
VCC 3V3
GND GND
CS GP13
RESET GP14
DC GP15
SDI(MOSI) GP7
SCK GP6
LED 3V3
SDO(MISO)
T- T_CLK GP10
O T_CS GP12
U T_DIN GP11
C T_DO GP8
H- T_IRQ
Instale a biblioteca de exibição para ili9341
Visite https://circuitpython.org/libraries, baixe o pacote apropriado para a sua versão do CircuitPython. Descompacte o arquivo e copie os diretórios adafruit_ili9341.mpy e adafruit_display_text para o diretório/lib do driver Raspberry Pi Pico CIRCUITPY.
Driver de toque para xpt2046
(Se você não usar a parte de toque, pode pular esta parte.)
xpt2046.py de rdagger/micropython-ili9341 é um driver xpt2046 para MicroPython. Eu modifico para que funcione no CircuitPython. A principal modificação é remover a interrupção e o pino de reconfiguração do CircuitPython usando o digitalio.
Salve-o no driver Raspberry Pi Pico CIRCUITPY, denomine cpy_xpt2046.py.
""" XPT2046 Touch module for CircuitPython modified from xpt2046.py of rdagger/micropython-ili9341 https://github.com/rdagger/micropython-ili9341/blob/master/xpt2046.py remove interrupt and re-config pin for CircuitPython """ from time import sleep import digitalio class Touch(object): """Serial interface for XPT2046 Touch Screen Controller.""" # Command constants from ILI9341 datasheet GET_X = const(0b11010000) # X position GET_Y = const(0b10010000) # Y position GET_Z1 = const(0b10110000) # Z1 position GET_Z2 = const(0b11000000) # Z2 position GET_TEMP0 = const(0b10000000) # Temperature 0 GET_TEMP1 = const(0b11110000) # Temperature 1 GET_BATTERY = const(0b10100000) # Battery monitor GET_AUX = const(0b11100000) # Auxiliary input to ADC """ remove support of interrupt def __init__(self, spi, cs, int_pin=None, int_handler=None, width=240, height=320, x_min=100, x_max=1962, y_min=100, y_max=1900): """ def __init__(self, spi, cs, width=240, height=320, x_min=100, x_max=1962, y_min=100, y_max=1900): """Initialize touch screen controller. Args: spi (Class Spi): SPI interface for OLED cs (Class Pin): Chip select pin int_pin (Class Pin): Touch controller interrupt pin int_handler (function): Handler for screen interrupt width (int): Width of LCD screen height (int): Height of LCD screen x_min (int): Minimum x coordinate x_max (int): Maximum x coordinate y_min (int): Minimum Y coordinate y_max (int): Maximum Y coordinate """ self.spi = spi self.cs = cs #self.cs.init(self.cs.OUT, value=1) self.cs_io = digitalio.DigitalInOut(cs) self.cs_io.direction = digitalio.Direction.OUTPUT self.cs_io.value=1 self.rx_buf = bytearray(3) # Receive buffer self.tx_buf = bytearray(3) # Transmit buffer self.width = width self.height = height # Set calibration self.x_min = x_min self.x_max = x_max self.y_min = y_min self.y_max = y_max self.x_multiplier = width / (x_max - x_min) self.x_add = x_min * -self.x_multiplier self.y_multiplier = height / (y_max - y_min) self.y_add = y_min * -self.y_multiplier """ ignore int_pin if int_pin is not None: self.int_pin = int_pin self.int_pin.init(int_pin.IN) self.int_handler = int_handler self.int_locked = False int_pin.irq(trigger=int_pin.IRQ_FALLING | int_pin.IRQ_RISING, handler=self.int_press) """ def get_touch(self): """Take multiple samples to get accurate touch reading.""" timeout = 2 # set timeout to 2 seconds confidence = 5 buff = [[0, 0] for x in range(confidence)] buf_length = confidence # Require a confidence of 5 good samples buffptr = 0 # Track current buffer position nsamples = 0 # Count samples while timeout > 0: if nsamples == buf_length: meanx = sum([c[0] for c in buff]) // buf_length meany = sum([c[1] for c in buff]) // buf_length dev = sum([(c[0] - meanx)**2 + (c[1] - meany)**2 for c in buff]) / buf_length if dev <= 50: # Deviation should be under margin of 50 return self.normalize(meanx, meany) # get a new value sample = self.raw_touch() # get a touch if sample is None: nsamples = 0 # Invalidate buff else: buff[buffptr] = sample # put in buff buffptr = (buffptr + 1) % buf_length # Incr, until rollover nsamples = min(nsamples + 1, buf_length) # Incr. until max sleep(.05) timeout -= .05 return None """ def int_press(self, pin): if not pin.value() and not self.int_locked: self.int_locked = True # Lock Interrupt buff = self.raw_touch() if buff is not None: x, y = self.normalize(*buff) self.int_handler(x, y) sleep(.1) # Debounce falling edge elif pin.value() and self.int_locked: sleep(.1) # Debounce rising edge self.int_locked = False # Unlock interrupt """ def normalize(self, x, y): """Normalize mean X,Y values to match LCD screen.""" x = int(self.x_multiplier * x + self.x_add) y = int(self.y_multiplier * y + self.y_add) return x, y def raw_touch(self): """Read raw X,Y touch values. Returns: tuple(int, int): X, Y """ x = self.send_command(self.GET_X) y = self.send_command(self.GET_Y) if self.x_min <= x <= self.x_max and self.y_min <= y <= self.y_max: return (x, y) else: return None def send_command(self, command): """Write command to XT2046 (MicroPython). Args: command (byte): XT2046 command code. Returns: int: 12 bit response """ self.tx_buf[0] = command #self.cs(0) self.cs_io.value=0 self.spi.try_lock() self.spi.write_readinto(self.tx_buf, self.rx_buf) self.spi.unlock() #self.cs(1) self.cs_io.value=1 return (self.rx_buf[1] << 4) | (self.rx_buf[2] >> 4)
Código de exemplo
cpyPico_spi_ILI9341_20210416.py
from sys import implementation from os import uname import board import time import displayio import terminalio import busio import adafruit_ili9341 from adafruit_display_text import label print('=======================') print(implementation[0], uname()[3]) displayio.release_displays() TFT_WIDTH = 320 TFT_HEIGHT = 240 tft_cs = board.GP13 tft_dc = board.GP15 tft_res = board.GP14 spi_mosi = board.GP7 #spi_miso = board.GP4 spi_clk = board.GP6 spi = busio.SPI(spi_clk, MOSI=spi_mosi) display_bus = displayio.FourWire( spi, command=tft_dc, chip_select=tft_cs, reset=tft_res) display = adafruit_ili9341.ILI9341(display_bus, width=TFT_WIDTH, height=TFT_HEIGHT, rowstart=0, colstart=0) display.rotation = 0 # Make the display context splash = displayio.Group(max_size=10) 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(max_size=10, scale=2, x=20, y=40) text1 = "RPi Pico" 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(max_size=10, scale=1, x=20, y=60) text2 = implementation[0] + ' ' + uname()[3] 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(max_size=10, scale=2, x=20, y=100) text3 = adafruit_ili9341.__name__ text_area3 = label.Label(terminalio.FONT, text=text3, color=0xF0F0F0) text_group3.append(text_area3) # Subgroup for text scaling # Draw a label text_group4 = displayio.Group(max_size=10, scale=2, x=20, y=120) text4 = adafruit_ili9341.__version__ text_area4 = label.Label(terminalio.FONT, text=text4, color=0xF0F0F0) 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) rot = 0 print('rot: ', rot, '\t-', display.width," x ", display.height) time.sleep(3.0) while True: time.sleep(5.0) rot = rot + 90 if (rot>=360): rot =0 display.rotation = rot print('rot: ', rot, '\t-', display.width," x ", display.height) print('- bye -')
cpyPico_spi_ILI9341_bitmap_20210416.py
""" Example of CircuitPython/Raspberry Pi Pico to display on 320x240 ili9341 SPI display """ import os import board import time import terminalio import displayio import busio from adafruit_display_text import label import adafruit_ili9341 print("==============================") print(os.uname()) print("Hello Raspberry Pi Pico/CircuitPython ILI8341 SPI Display") print(adafruit_ili9341.__name__ + " version: " + adafruit_ili9341.__version__) print() # Release any resources currently in use for the displays displayio.release_displays() TFT_WIDTH = 320 TFT_HEIGHT = 240 tft_spi_clk = board.GP6 tft_spi_mosi = board.GP7 #tft_spi_miso = board.GP4 tft_cs = board.GP13 tft_dc = board.GP15 tft_res = board.GP14 tft_spi = busio.SPI(tft_spi_clk, MOSI=tft_spi_mosi) display_bus = displayio.FourWire( tft_spi, command=tft_dc, chip_select=tft_cs, reset=tft_res) display = adafruit_ili9341.ILI9341(display_bus, width=TFT_WIDTH, height=TFT_HEIGHT) display.rotation = 90 print('rot: ', display.rotation, '\t-', display.width," x ", display.height) group = displayio.Group(max_size=10) display.show(group) bitmap = displayio.Bitmap(display.width, display.height, display.width) palette = displayio.Palette(display.width) for p in range(display.width): palette[p] = (0x010000*p) + (0x0100*p) + p for y in range(display.height): for x in range(display.width): bitmap[x,y] = x tileGrid = displayio.TileGrid(bitmap, pixel_shader=palette, x=0, y=0) group.append(tileGrid) time.sleep(3.0) while True: for p in range(display.width): palette[p] = p time.sleep(3.0) for p in range(display.width): palette[p] = 0x0100 * p time.sleep(3.0) for p in range(display.width): palette[p] = 0x010000 * p time.sleep(3.0) print('-bye -')
cpyPico_spi_ILI9341_touch_20210416.py
""" Example of CircuitPython/Raspberry Pi Pico to display on 320x240 ili9341 SPI display with touch detection """ from sys import implementation from os import uname import board import time import terminalio import displayio import busio from adafruit_display_text import label import adafruit_ili9341 from cpy_xpt2046 import Touch print("==============================") print(implementation[0], uname()[3]) print("Hello Raspberry Pi Pico/CircuitPython ILI8341 SPI Display") print("with touch") print(adafruit_ili9341.__name__ + " version: " + adafruit_ili9341.__version__) print() # Release any resources currently in use for the displays displayio.release_displays() TFT_WIDTH = 320 TFT_HEIGHT = 240 tft_spi_clk = board.GP6 tft_spi_mosi = board.GP7 #tft_spi_miso = board.GP4 tft_cs = board.GP13 tft_dc = board.GP15 tft_res = board.GP14 touch_spi_clk = board.GP10 touch_spi_mosi = board.GP11 touch_spi_miso = board.GP8 touch_cs = board.GP12 #touch_int = board.GP0 touch_x_min = 64 touch_x_max = 1847 touch_y_min = 148 touch_y_max = 2047 touch_spi = busio.SPI(touch_spi_clk, MOSI=touch_spi_mosi, MISO=touch_spi_miso) touch = Touch(touch_spi, cs=touch_cs, x_min=touch_x_min, x_max=touch_x_max, y_min=touch_y_min, y_max=touch_y_max) tft_spi = busio.SPI(tft_spi_clk, MOSI=tft_spi_mosi) display_bus = displayio.FourWire( tft_spi, command=tft_dc, chip_select=tft_cs, reset=tft_res) display = adafruit_ili9341.ILI9341(display_bus, width=TFT_WIDTH, height=TFT_HEIGHT) display.rotation = 90 scrWidth = display.width scrHeight = display.height print('rot: ', display.rotation, '\t-', scrWidth," x ", scrHeight) group = displayio.Group(max_size=10) display.show(group) bitmap = displayio.Bitmap(display.width, display.height, 5) BLACK = 0 WHITE = 1 RED = 2 GREEN = 3 BLUE = 4 palette = displayio.Palette(5) palette[0] = 0x000000 palette[1] = 0xFFFFFF palette[2] = 0xFF0000 palette[3] = 0x00FF00 palette[4] = 0x0000FF for y in range(display.height): for x in range(display.width): bitmap[x,y] = BLACK tileGrid = displayio.TileGrid(bitmap, pixel_shader=palette, x=0, y=0) group.append(tileGrid) taskInterval_50ms = 0.050 NxTick = time.monotonic() + taskInterval_50ms EVT_NO = const(0) EVT_PenDown = const(1) EVT_PenUp = const(2) EVT_PenRept = const(3) touchEvent = EVT_NO touchSt_Idle_0 = const(0) touchSt_DnDeb_1 = const(1) touchSt_Touching_2 = const(2) touchSt_UpDeb_3 = const(3) touchSt = touchSt_Idle_0 touchDb_NUM = const(3) touchDb = touchDb_NUM touching = False """ state diagram for touch debounce touchStIdle_0 validXY!=None-> touchSt_DnDeb_1 <-validXY==None ^ validXY!=None | | validXY==None V touchSt_UpDeb_3 <- validXY==None touchSt_Touching_2 validXY!=None-> """ """ None: no touch or invalid touch normailzedX, normailzedY: valid touch """ def validTouch(): xy = touch.raw_touch() if xy == None: return None normailzedX, normailzedY = touch.normalize(*xy) if (normailzedX < 0 or normailzedX >= scrWidth or normailzedY < 0 or normailzedY >= scrHeight): return None return (normailzedX, normailzedY) def TouchDetTask(): global touch global touching global touchSt global touchEvent global touchedX, touchedY global touchDb validXY = validTouch() if touchSt == touchSt_Idle_0: if validXY != None: touchDb = touchDb_NUM touchSt = touchSt_DnDeb_1 elif touchSt == touchSt_DnDeb_1: if validXY != None: touchDb = touchDb-1 if touchDb==0: touchSt = touchSt_Touching_2 touchEvent = EVT_PenDown touchedX, touchedY = validXY touching = True else: touchSt = touchSt_Idle_0 elif touchSt == touchSt_Touching_2: if validXY != None: touchedX, touchedY = validXY touchEvent = EVT_PenRept else: touchDb=touchDb_NUM touchSt = touchSt_UpDeb_3 elif touchSt == touchSt_UpDeb_3: if validXY != None: touchSt = touchSt_Touching_2 else: touchDb=touchDb-1 if touchDb==0: touchSt = touchSt_Idle_0 touchEvent = EVT_PenUp touching = False def drawCross(x, y, col): if y>=0 and y<scrHeight: for i in range(x-5, x+5): if i>=0 and i<scrWidth: bitmap[i, y] = col if x>=0 and y<scrWidth: for i in range(y-5, y+5): if i>=0 and i<scrHeight: bitmap[x, i] = col while True: curTick = time.monotonic() if curTick >= NxTick: NxTick = curTick + taskInterval_50ms #print(NxTick) TouchDetTask() #handle touch event if touchEvent != EVT_NO: if touchEvent == EVT_PenDown: print('ev PenDown - ', touchedX, " : ", touchedY) drawCross(touchedX, touchedY, WHITE) if touchEvent == EVT_PenUp: print('ev PenUp - ') drawCross(touchedX, touchedY, RED) if touchEvent == EVT_PenRept: if (touchedX>=0 and touchedX<scrWidth and touchedY>=0 and touchedY<scrHeight): bitmap[touchedX, touchedY] = GREEN touchEvent = EVT_NO print('-bye -')
Comentário sobre o suporte do CircuitPython para interrupção
De acordo com as Perguntas Freqüentes do CircuitPython, o CircuitPython atualmente não oferece suporte a interrupções.