Thursday, March 31, 2022
Raspberry Pi Pico/MicroPython generate QR Code and display on SSD1306 I2C OLED
Run on Raspberry Pi Pico/MicroPython, to generate QR Code, and display on
SSD1306 128x64 I2C OLED.
For SSD1306 driver, visit https://github.com/micropython/micropython/blob/master/drivers/display/ssd1306.py to download ssd1306.py, save to Raspberry Pi Pico driver.
For QR Code, JASchilz/uQR is used. Download uQR.py and save to Raspberry Pi Pico driver.
mpyPico_i2c.py, simple verify I2C(0) pins and connection to SSD1306 I2C OLED.
import uos
import usys
print("====================================================")
print(usys.implementation[0],
str(usys.implementation[1][0]) + "." +
str(usys.implementation[1][1]) + "." +
str(usys.implementation[1][2]))
print(uos.uname()[3])
print("run on", uos.uname()[4])
print("====================================================")
i2c0 = machine.I2C(0)
print(i2c0)
print("Available i2c devices: "+ str(i2c0.scan()))
print("~ bye ~")
mpyPico_ssd1306.py, simple test program for SSD1306 I2C OLED.
"""
Run on Raspbery Pi Pico/MicroPython
display on ssd1306 I2C OLED
connec ssd1306 using I2C(0)
scl=9
sda=8
- Libs needed:
ssd1306 library
https://github.com/micropython/micropython/blob/master/drivers/display/ssd1306.py
"""
import uos
import usys
from ssd1306 import SSD1306_I2C
print("====================================================")
print(usys.implementation[0],
str(usys.implementation[1][0]) + "." +
str(usys.implementation[1][1]) + "." +
str(usys.implementation[1][2]))
print(uos.uname()[3])
print("run on", uos.uname()[4])
print("====================================================")
i2c0 = machine.I2C(0)
print(i2c0)
print("Available i2c devices: "+ str(i2c0.scan()))
WIDTH = 128
HEIGHT = 64
oled = SSD1306_I2C(WIDTH, HEIGHT, i2c0)
oled.fill(0)
oled.text(usys.implementation[0], 0, 0)
strVersion = str(usys.implementation[1][0]) + "." + \
str(usys.implementation[1][1]) + "." + \
str(usys.implementation[1][2])
oled.text(strVersion, 0, 10)
oled.text(uos.uname()[3], 0, 20)
oled.text(uos.uname()[4], 0, 40)
oled.show()
mpyPico_ssd1306_uQR.py, generate QR Code using uQR.py, and display on SSD1306 I2C OLED.
"""
Run on Raspbery Pi Pico/MicroPython
to generate QR code using uQR,
and display on ssd1306 I2C OLED
- Libs needed:
ssd1306 library
https://github.com/micropython/micropython/blob/master/drivers/
display/ssd1306.py
JASchilz/uQR:
https://github.com/JASchilz/uQR
remark:
in the original example on uQR to display on ssd1306, scale of 2 is used.
It's found:
- If the data is too long, the small 128x64 OLED cannot display the whole matrix.
- In my test using my phone, scale of 1 is more easy to recognize.
Such that I use scale of 1 inside the loop to generate qr code.
"""
from uos import uname
from usys import implementation
from machine import I2C
from time import sleep
from ssd1306 import SSD1306_I2C
from uQR import QRCode
print("====================================================")
print(implementation[0],
str(implementation[1][0]) + "." +
str(implementation[1][1]) + "." +
str(implementation[1][2]))
print(uname()[3])
print("run on", uname()[4])
print("====================================================")
i2c0 = I2C(0)
print(i2c0)
print("Available i2c devices: "+ str(i2c0.scan()))
WIDTH = 128
HEIGHT = 64
oled = SSD1306_I2C(WIDTH, HEIGHT, i2c0)
oled.fill(0)
oled.text("RPi Pico", 0, 0)
oled.text("MicroPython", 0, 10)
oled.text("OLED(ssd1306)", 0, 20)
oled.text("uQR exercise", 0, 40)
oled.show()
sleep(5)
qr = QRCode()
qr.add_data("uQR example")
matrix = qr.get_matrix()
print("version:", qr.version)
print("len of matrix", len(matrix))
oled.fill(1)
for y in range(len(matrix)*2): # Scaling the bitmap by 2
for x in range(len(matrix[0])*2): # because my screen is tiny.
value = not matrix[int(y/2)][int(x/2)] # Inverting the values because
oled.pixel(x, y, value) # black is `True` in the matrix.
oled.show()
while True:
userinput = input("\nEnter something: ")
if userinput == "":
break
print(userinput)
qr.clear()
qr.add_data(userinput)
matrix = qr.get_matrix()
print("version:", qr.version)
print("len of matrix", len(matrix))
oled.fill(1)
scale = 1
for y in range(len(matrix)*scale):
for x in range(len(matrix[0])*scale):
value = not matrix[int(y/scale)][int(x/scale)]
oled.pixel(x, y, value)
oled.show()
print("~ bye ~")
mpyPico_simpletest_uQR.py, generate QR Code and display on REPL.
"""
Run on Raspbery Pi Pico/MicroPython
to generate QR code using uQR,
and display on screen
- Libs needed:
JASchilz/uQR:
https://github.com/JASchilz/uQR
"""
from uos import uname
from usys import implementation
from usys import stdout
from uQR import QRCode
print("====================================================")
print(implementation[0],
str(implementation[1][0]) + "." +
str(implementation[1][1]) + "." +
str(implementation[1][2]))
print(uname()[3])
print("run on", uname()[4])
print("====================================================")
# For drawing filled rectangles to the console:
stdout = stdout
WHITE = "\x1b[1;47m \x1b[40m"
BLACK = " "
NORMAL = '033円[1;37;0m'
def print_QR(uqr):
qr_matrix = uqr.get_matrix()
print("version:", uqr.version)
qr_height = len(qr_matrix)
qr_width = len(qr_matrix[0])
print("qr_height: ", qr_height)
print("qr_width: ", qr_width)
for _ in range(4):
for _ in range(qr_width + 8): #margin on top
stdout.write(WHITE)
print()
for y in range(qr_height):
stdout.write(WHITE * 4) #margin on right
for x in range(len(matrix[0])):
value = qr_matrix[int(y)][int(x)]
if value == True:
stdout.write(BLACK)
else:
stdout.write(WHITE)
stdout.write(WHITE * 4) #margin on left
print()
for _ in range(4):
for _ in range(qr_width + 8): #margin on bottom
stdout.write(WHITE)
print()
print(NORMAL)
qr = QRCode()
qr.add_data("uQR example")
matrix = qr.get_matrix()
print_QR(qr)
while True:
userinput = input("\nEnter something: ")
if userinput == "":
break
print(userinput)
qr.clear()
qr.add_data(userinput)
matrix = qr.get_matrix()
print_QR(qr)
print("~ bye ~")
~ More exercise for Raspberry Pi Pico Wednesday, February 23, 2022
Raspberry Pi Pico/MicroPython: get MicroPython version programmatically
A simple exercise run on Raspberry Pi Pico/MicroPython to get installed MicroPython version programmatically.
mpyPico_info.py
import uos
import usys
class color:
BLACK = '033円[1;30;48m'
RED = '033円[1;31;48m'
GREEN = '033円[1;32;48m'
YELLOW = '033円[1;33;48m'
BLUE = '033円[1;34;48m'
MAGENTA = '033円[1;35;48m'
CYAN = '033円[1;36;48m'
END = '033円[1;37;0m'
#print(uos.uname())
#print(usys.implementation)
print("====================================================")
print(color.BLUE, usys.implementation[0],
str(usys.implementation[1][0]) + "." +
str(usys.implementation[1][1]) + "." +
str(usys.implementation[1][2]), color.END)
print(uos.uname()[3])
print("run on", color.RED, uos.uname()[4], color.END)
print("====================================================")
~ more exercises for Raspberry Pi Pico
Sunday, May 30, 2021
Raspberry Pi Pico/MicroPython: uasyncio
Raspberry Pi Pico MicroPython exercise of using uasyncio :
"""
MicroPython uasyncio exercise on RP2040
"""
from sys import implementation
from os import uname
import uasyncio as asyncio
from machine import Pin
import utime
led = Pin(25, Pin.OUT)
print(implementation.name)
print(uname()[3])
print(uname()[4])
print()
print(asyncio.__name__)
print(asyncio.__version__)
#Toggle onboard LED every 500ms
async def asyncTask1():
while True:
led.toggle()
await asyncio.sleep_ms(500)
#print time every 1 second
async def asyncTask2():
while True:
print(utime.time())
await asyncio.sleep_ms(1000)
loop = asyncio.get_event_loop()
loop.create_task(asyncTask1())
loop.create_task(asyncTask2())
loop.run_forever()
print("- bye -")
~ More exercise on Raspberry Pi Pico
Saturday, May 29, 2021
RPi Pico BOOTSEL button broken! How to enter BOOTLOADER mode using Python code; without BOOTSEL button and un-plug/re-plug USB.
The BOOTSEL button on my Raspberry Pi Pico broken! Here is how to reset Pico and enter BOOTLOADER mode using Python (MicroPython/CircuitPython) code; such that no need touch BOOTSEL button and un-plug/re-plug USB.
Thursday, May 6, 2021
Raspberry Pi Pico/MicroPython, read and set CPU Frequency (overclock)
Change CPU Frequency and monitor Temperature, at runtime, with graphical display on ili9341 SPI display.
"""
Exercise on Raspberry Pi Pico/MicroPython
with 320x240 ILI9341 SPI Display
Pico plot internal temperature graphically
vs CPU Clock
"""
from ili934xnew import ILI9341, color565
from machine import Pin, SPI, Timer
from micropython import const
import os
import glcdfont
import tt24
import tt32
#import freesans20fixed
import utime
sensor_temp = machine.ADC(4) #internal temperature sensor
conversion_factor = 3.3/(65535)
SCR_WIDTH = const(320)
SCR_HEIGHT = const(240)
SCR_ROT = const(0)
#SCR_ROT = const(2)
dispW = 240
dispH = 320
marginX = const(20)
marginY = const(10)
TempFrame_W = dispW-(2*marginX)
TempFrame_H = 100
TempFrame_X0 = marginX
TempFrame_Y0 = marginY
TempFrame_Y1 = marginY+TempFrame_H
TempPanel_X0 = TempFrame_X0
TempPanel_Y0 = TempFrame_Y1 + 10
TempPanel_W = TempFrame_W
TempPanel_H = 32
sampleSize = TempFrame_W #200
tempValueLim = TempFrame_H #100
FreqFrame_W = dispW-(2*marginX)
FreqFrame_H = 100
FreqFrame_X0 = marginX
FreqFrame_Y0 = marginY + 150
FreqFrame_Y1 = marginY+FreqFrame_H + 150
FreqPanel_X0 = FreqFrame_X0
FreqPanel_Y0 = FreqFrame_Y1 + 10
led = Pin(25, Pin.OUT)
#set default CPU freq
machine.freq(125000000)
FreqChangeInterval = 15 #change freq in 15 sec interval
freqSet = [50000000, 250000000, 40000000, 260000000]
freqCnt = FreqChangeInterval
freqIdx = 0
print("MicroPython:")
print(os.uname()[3])
print(os.uname()[4])
print()
TFT_CLK_PIN = const(6)
TFT_MOSI_PIN = const(7)
TFT_MISO_PIN = const(4)
TFT_CS_PIN = const(13)
TFT_RST_PIN = const(14)
TFT_DC_PIN = const(15)
spi = SPI(
0,
baudrate=40000000,
miso=Pin(TFT_MISO_PIN),
mosi=Pin(TFT_MOSI_PIN),
sck=Pin(TFT_CLK_PIN))
print(spi)
display = ILI9341(
spi,
cs=Pin(TFT_CS_PIN),
dc=Pin(TFT_DC_PIN),
rst=Pin(TFT_RST_PIN),
w=SCR_WIDTH,
h=SCR_HEIGHT,
r=SCR_ROT)
def drawHLine(x, y, w, color):
for i in range(w):
display.pixel(x+i,y,color)
def drawVLine(x, y, h, color):
for i in range(h):
display.pixel(x,y+i,color)
def drawVLineUp(x, y, h, color):
for i in range(h):
display.pixel(x,y-i,color)
frameBGcolor = color565(150, 150, 150)
TempPanel = color565(0, 0, 0)
def drawFrame(x, y, w, h):
display.fill_rectangle(x, y, w, h, frameBGcolor)
l1x = x-1
l2x = x+w
l1y = y-1
l2y = y+h+1
lcolor = color565(250, 250, 250)
for i in range(w+2):
display.pixel(l1x+i,l1y,lcolor)
display.pixel(l1x+i,l2y,lcolor)
for i in range(h+2):
display.pixel(l1x,l1y+i,lcolor)
display.pixel(l2x,l1y+i,lcolor)
display.erase()
display.set_font(tt24)
display.set_pos(0, 0)
display.set_color(color565(250, 250, 0), color565(0, 0, 0))
display.print("Pico plot internal temperature vs CPU Clock")
display.print("")
display.set_color(color565(250, 250, 250), color565(0, 0, 0))
display.print("MicroPython:")
display.print(os.uname()[3])
display.print("")
display.print(os.uname()[4])
utime.sleep(3)
timReached = False
tim = Timer()
def TimerTick(timer):
global led
led.toggle()
global timReached
timReached = True
tim.init(freq=1, mode=Timer.PERIODIC, callback=TimerTick)
display.set_font(tt32)
#display.set_font(freesans20fixed)
display.set_color(color565(250, 250, 0), color565(0, 0,0))
display.erase()
drawFrame(TempFrame_X0, TempFrame_Y0, TempFrame_W, TempFrame_H)
drawFrame(FreqFrame_X0, FreqFrame_Y0, FreqFrame_W, FreqFrame_H)
utime.sleep(1)
#sampleTemp=[0]*sampleSize
sampleIndex=0
tempString = "0"
while True:
if timReached:
timReached = False
reading = sensor_temp.read_u16()*conversion_factor
tempValue = 27-(reading-0.706)/0.001721
print(tempValue)
tempString=str(tempValue)
if tempValue >= tempValueLim:
display.set_color(color565(250, 0, 0), color565(0, 0, 0))
else:
display.set_color(color565(0, 0, 250), color565(0, 0, 0))
display.set_pos(TempPanel_X0, TempPanel_Y0)
display.print(tempString)
if sampleIndex == 0:
#clear frame
display.fill_rectangle(TempFrame_X0,
TempFrame_Y0,
TempFrame_W,
TempFrame_H,
frameBGcolor)
display.fill_rectangle(FreqFrame_X0,
FreqFrame_Y0,
FreqFrame_W,
FreqFrame_H,
frameBGcolor)
#plot temperature
if tempValue >= tempValueLim:
drawVLineUp(TempFrame_X0+sampleIndex,
TempFrame_Y1,
tempValueLim,
color565(250, 0, 0))
else:
drawVLineUp(TempFrame_X0+sampleIndex,
TempFrame_Y1,
tempValue,
color565(0, 0, 250))
#plot CPU freq
freqValue = machine.freq()
print(freqValue)
freqBar = freqValue/3000000 #freqBar in range 0~100
drawVLineUp(FreqFrame_X0+sampleIndex,
FreqFrame_Y1,
freqBar,
color565(250, 250, 0))
freqString=str(freqValue/1000000) + " (MHz)"
display.set_color(color565(0, 0, 250), color565(0, 0, 0))
display.set_pos(FreqPanel_X0, FreqPanel_Y0)
display.print(freqString)
sampleIndex = sampleIndex+1
if(sampleIndex>=sampleSize):
sampleIndex = 0
#check if frequency changeinterval reached
freqCnt = freqCnt-1
if freqCnt == 0:
freqCnt = FreqChangeInterval
newFreq = freqSet[freqIdx]
print(newFreq)
machine.freq(newFreq)
freqIdx = freqIdx + 1
if freqIdx == len(freqSet):
freqIdx = 0;
print("- bye-")
Thursday, April 8, 2021
ESP32/MicroPython server + Raspberry Pi/Python client, transmit image via WiFi TCP socket.
In this exercise, ESP32 (ESP32-DevKitC V4)/MicroPython play the role of AP, act as socket server. Raspberry Pi connect to ESP32 WiFi network, run Python code to load image, act as client and transmit the image to ESP32 server. The ESP32 server display the image on a 240*240 IPS (ST7789 SPI) LCD. It's is role reversed version of my previous exercise "Raspberry Pi/Python Server send image to ESP32/MicroPython Client via WiFi TCP socket".
protocol:
Client | | Server
(Raspberry Pi/Python) | | (ESP32/MicroPython)
| |
| | Reset
|| Setup AP
| | Setup socket server
(connect to ESP32 WiFi) | |
| |
connect to ESP32 server | | accepted
|<-- ACK ---|
send the 0th line |---------->| display the 0th line
|<-- ACK ---| send ACK
send the 1st line |---------->| display the 1st line
|<-- ACK ---| send ACK
.
.
.
send the 239th line |---------->| display the 239th line
|<-- ACK ---| send ACK
close socket | | close socket
| |
from os import uname
from sys import implementation
import machine
import network
import socket
import ubinascii
import utime
import st7789py as st7789
from fonts import vga1_16x32 as font
import ustruct as struct
"""
ST7789 Display ESP32-DevKitC (SPI2)
SCL GPIO18
SDA GPIO23
GPIO19 (miso not used)
ST7789_rst GPIO5
ST7789_dc GPIO4
"""
#ST7789 use SPI(2)
st7789_res = 5
st7789_dc = 4
pin_st7789_res = machine.Pin(st7789_res, machine.Pin.OUT)
pin_st7789_dc = machine.Pin(st7789_dc, machine.Pin.OUT)
disp_width = 240
disp_height = 240
ssid = "ssid"
AP_ssid = "ESP32"
password = "password"
serverIP = '192.168.1.30'
serverPort = 80
print(implementation.name)
print(uname()[3])
print(uname()[4])
print()
#spi2 = machine.SPI(2, baudrate=40000000, polarity=1)
pin_spi2_sck = machine.Pin(18, machine.Pin.OUT)
pin_spi2_mosi = machine.Pin(23, machine.Pin.OUT)
pin_spi2_miso = machine.Pin(19, machine.Pin.IN)
spi2 = machine.SPI(2, sck=pin_spi2_sck, mosi=pin_spi2_mosi, miso=pin_spi2_miso,
baudrate=40000000, polarity=1)
print(spi2)
display = st7789.ST7789(spi2, disp_width, disp_width,
reset=pin_st7789_res,
dc=pin_st7789_dc,
xstart=0, ystart=0, rotation=0)
display.fill(st7789.BLACK)
mac = ubinascii.hexlify(network.WLAN().config('mac'),':').decode()
print("MAC: " + mac)
print()
#init ESP32 as STA
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.disconnect()
utime.sleep(1)
def do_connect():
global wlan
print('connect to network...')
display.fill(st7789.BLACK)
display.text(font, "connect...", 10, 10)
wlan.active(True)
if not wlan.isconnected():
print('...')
wlan.connect(ssid, password)
while not wlan.isconnected():
pass
print()
print('network config:')
print("interface's IP/netmask/gw/DNS addresses")
#print(wlan.ifconfig())
myIP = wlan.ifconfig()[0]
print(myIP)
display.fill(st7789.BLACK)
display.text(font, myIP, 10, 10)
def do_setupAP():
global wlan
print('setup AP...')
display.fill(st7789.BLACK)
display.text(font, "setup AP...", 10, 10)
utime.sleep(1)
ap = network.WLAN(network.AP_IF)
ap.active(True)
ap.config(essid=AP_ssid, password=password)
while ap.active() == False:
pass
print(ap.active())
print()
print('network config:')
myIP = ap.ifconfig()
print(myIP)
display.fill(st7789.BLACK)
display.text(font, myIP[0], 10, 10)
def do_setupServer():
global wlan
global display
addr = socket.getaddrinfo('0.0.0.0', serverPort)[0][-1]
s = socket.socket()
s.bind(addr)
s.listen(1)
print('listening on', addr)
display.text(font, ':'+str(serverPort), 10, 50)
while True:
print('waiting connection...')
cl, addr = s.accept()
cl.settimeout(5)
print('client connected from:', addr)
display.fill(st7789.BLACK)
display.text(font, addr[0], 10, 10)
cl.sendall('ACK')
print('Firt ACK sent')
display.set_window(0, 0, disp_width-1, disp_height-1)
pin_st7789_dc.on()
for j in range(disp_height):
try:
buff = cl.recv(disp_width*3)
#print('recv ok: ' + str(j))
except:
print('except: ' + str(j))
for i in range(disp_width):
offset= i*3
spi2.write(struct.pack(st7789._ENCODE_PIXEL,
(buff[offset] & 0xf8) << 8 |
(buff[offset+1] & 0xfc) << 3 |
buff[offset+2] >> 3))
#print('send ACK : ' + str(j))
cl.sendall(bytes("ACK","utf-8"))
#print('ACK -> : ' + str(j))
utime.sleep(1)
cl.close()
print('socket closed')
#do_connect()
do_setupAP()
try:
do_setupServer()
except:
print('error')
display.text(font, "Error", 10, 200)
finally:
print('wlan.disconnect()')
wlan.disconnect()
print('\n- bye -')
import sys
from pkg_resources import require
import time
import matplotlib.image as mpimg
import socket
#HOST = '192.168.1.34' # The server's hostname or IP address
HOST = '192.168.4.1'
PORT = 80 # The port used by the server
from PyQt5.QtWidgets import (QApplication, QWidget, QPushButton, QLabel,
QFileDialog, QHBoxLayout, QVBoxLayout)
from PyQt5.QtGui import QPixmap, QImage
print(sys.version)
class AppWindow(QWidget):
camPreviewState = False #not in Preview
fileToUpload = ""
def __init__(self):
super().__init__()
lbSysInfo = QLabel('Python:\n' + sys.version)
vboxInfo = QVBoxLayout()
vboxInfo.addWidget(lbSysInfo)
#setup UI
btnOpenFile = QPushButton("Open File", self)
btnOpenFile.clicked.connect(self.evBtnOpenFileClicked)
self.btnUpload = QPushButton("Upload", self)
self.btnUpload.clicked.connect(self.evBtnUploadClicked)
self.btnUpload.setEnabled(False)
vboxCamControl = QVBoxLayout()
vboxCamControl.addWidget(btnOpenFile)
vboxCamControl.addWidget(self.btnUpload)
vboxCamControl.addStretch()
self.lbImg = QLabel(self)
self.lbImg.resize(240, 240)
self.lbImg.setStyleSheet("border: 1px solid black;")
hboxCam = QHBoxLayout()
hboxCam.addWidget(self.lbImg)
hboxCam.addLayout(vboxCamControl)
self.lbPath = QLabel(self)
vboxMain = QVBoxLayout()
vboxMain.addLayout(vboxInfo)
vboxMain.addLayout(hboxCam)
vboxMain.addWidget(self.lbPath)
vboxMain.addStretch()
self.setLayout(vboxMain)
self.setGeometry(100, 100, 500,400)
self.show()
#wait client response in 3 byte len
def wait_RESP(self, sock):
#sock.settimeout(10)
res = str()
data = sock.recv(4)
return data.decode("utf-8")
def sendImageToServer(self, imgFile):
print(imgFile)
imgArray = mpimg.imread(imgFile)
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, PORT))
print(self.wait_RESP(s))
for j in range(240):
time.sleep(0.1)
b = bytes(imgArray[j])
#print('send img : ' + str(j))
s.sendall(bytes(b))
#print('img sent : ' + str(j))
ans = self.wait_RESP(s)
#print(ans + " : " + str(j))
print('image sent finished')
s.close()
def evBtnUploadClicked(self):
print("evBtnUploadClicked()")
print(self.fileToUpload)
self.sendImageToServer(self.fileToUpload)
def evBtnOpenFileClicked(self):
options = QFileDialog.Options()
options |= QFileDialog.DontUseNativeDialog
targetPath, _ = QFileDialog.getOpenFileName(
self, 'Open file', '/home/pi/Desktop',
'Image files (*.jpg)', options=options)
if targetPath:
print(targetPath)
self.lbPath.setText(targetPath)
with open(targetPath):
pixmap = QPixmap(targetPath)
#accept 240x240 image only
if pixmap.width()==240 and pixmap.height()==240:
self.lbImg.setPixmap(pixmap)
self.btnUpload.setEnabled(True)
self.fileToUpload = targetPath
else:
self.btnUpload.setEnabled(False)
def evBtnOpenFileClickedX(self):
targetPath="/home/pi/Desktop/image.jpg"
print(targetPath)
self.lbPath.setText(targetPath)
try:
with open(targetPath):
pixmap = QPixmap(targetPath)
self.lbImg.setPixmap(pixmap)
#as a exercise, get some info from pixmap
print('\npixmap:')
print(pixmap)
print(type(pixmap))
print(str(pixmap.width()) + " : " + str(pixmap.height()))
print()
print('convert to Image')
qim = pixmap.toImage()
print(qim)
print(type(qim))
print()
print('read a pixel from image')
qrgb = qim.pixel(0, 0)
print(hex(qrgb))
print(type(qrgb))
r, g, b = qRed(qrgb), qGreen(qrgb), qBlue(qrgb)
print([hex(r), hex(g), hex(b)])
print()
except FileNotFoundError:
print('File Not Found Error')
if __name__ == '__main__':
print('run __main__')
app = QApplication(sys.argv)
window = AppWindow()
sys.exit(app.exec_())
print("- bye -")
Wednesday, March 24, 2021
Raspberry Pi/Python Server send image to ESP32/MicroPython Client via WiFi TCP socket
protocol:
Server | | Client
(Raspberry Pi/Python) | | (ESP32/MicroPython)
| |
Start | | Reset
| |
Setup as | |
socketserver.TCPServer | |
| |
| | Join the WiFi network
| | Connect to server with socket
| |
|<-- ACK ---| send ACK
send the 0th line |---------->| display the 0th line
|<-- ACK ---| send ACK
send the 1st line |---------->| display the 1st line
.
.
.
send the 239th line |---------->| display the 239th line
|<-- ACK ---| send ACK
close socket | | close socket
| |
wait next | | bye
Client side:
(ESP32/MicroPython)
The ESP32 used is a ESP32-DevKitC V4, display is a 240*240 IPS (ST7789 SPI) LCD. Library setup and connection, refer to former post "ESP32 (ESP32-DevKitC V4)/MicroPython + 240*240 IPS (ST7789 SPI) using russhughes/st7789py_mpy lib".
upyESP32_ImgClient_20210324c.py, MicroPython code run on ESP32. Modify ssid/password and serverIP for your WiFi network.from os import uname
from sys import implementation
import machine
import network
import socket
import ubinascii
import utime
import st7789py as st7789
from fonts import vga1_16x32 as font
import ustruct as struct
"""
ST7789 Display ESP32-DevKitC (SPI2)
SCL GPIO18
SDA GPIO23
GPIO19 (miso not used)
ST7789_rst GPIO5
ST7789_dc GPIO4
"""
#ST7789 use SPI(2)
st7789_res = 5
st7789_dc = 4
pin_st7789_res = machine.Pin(st7789_res, machine.Pin.OUT)
pin_st7789_dc = machine.Pin(st7789_dc, machine.Pin.OUT)
disp_width = 240
disp_height = 240
ssid = "your ssid"
password = "your password"
serverIP = '192.168.1.30'
serverPort = 9999
print(implementation.name)
print(uname()[3])
print(uname()[4])
print()
spi2 = machine.SPI(2, baudrate=40000000, polarity=1)
print(spi2)
display = st7789.ST7789(spi2, disp_width, disp_width,
reset=pin_st7789_res,
dc=pin_st7789_dc,
xstart=0, ystart=0, rotation=0)
display.fill(st7789.BLACK)
mac = ubinascii.hexlify(network.WLAN().config('mac'),':').decode()
print("MAC: " + mac)
print()
#init ESP32 as STA
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.disconnect()
utime.sleep(1)
def do_connect():
global wlan
print('connect to network...')
display.fill(st7789.BLACK)
display.text(font, "connect...", 10, 10)
wlan.active(True)
if not wlan.isconnected():
print('...')
wlan.connect(ssid, password)
while not wlan.isconnected():
pass
print()
print('network config:')
print("interface's IP/netmask/gw/DNS addresses")
print(wlan.ifconfig())
display.fill(st7789.BLACK)
display.text(font, "connected", 10, 10)
def do_scan():
global wlan
print('scan network...')
wlan.active(True)
for network in wlan.scan():
print(network)
def do_connectServer():
global wlan
global display
addr = socket.getaddrinfo(serverIP, serverPort)[0][-1]
print(addr)
s = socket.socket()
s.connect(addr)
print('---')
display.fill(st7789.BLACK)
display.text(font, "waiting...", 10, 10)
print('Send ACK')
s.sendall(bytes("ACK","utf-8"))
display.set_window(0, 0, disp_width-1, disp_height-1)
pin_st7789_dc.on()
for j in range(disp_height):
buff = s.recv(disp_width*3)
for i in range(disp_width):
offset= i*3
spi2.write(struct.pack(st7789._ENCODE_PIXEL,
(buff[offset] & 0xf8) << 8 |
(buff[offset+1] & 0xfc) << 3 |
buff[offset+2] >> 3))
s.sendall(bytes("ACK","utf-8"))
s.close()
print('socket closed')
do_connect()
try:
do_connectServer()
except:
print('error')
display.text(font, "Error", 10, 200)
finally:
print('wlan.disconnect()')
wlan.disconnect()
print('\n- bye -')
Server Side:
(Raspberry Pi/Python)
The server will send Desktop/image.jpg with fixed resolution 240x240 (match with the display in client side). My former post "min. version of RPi/Python Code to control Camera Module with preview on local HDMI" is prepared for this purpose to capture using Raspberry Pi Camera Module .
pyMyTCP_ImgServer_20210324c.py, Python3 code run on Raspberry Pi.import socketserver
import platform
import matplotlib.image as mpimg
imageFile = '/home/pi/Desktop/image.jpg'
print("sys info:")
for info in platform.uname():
print(info)
class MyTCPHandler(socketserver.BaseRequestHandler):
#wait client response in 3 byte len
def wait_RESPONSE(self, client):
client.settimeout(10)
res = str()
data = client.recv(4)
return data.decode("utf-8")
def handle(self):
msocket = self.request
print("{} connected:".format(self.client_address[0]))
imgArray = mpimg.imread(imageFile)
self.wait_RESPONSE(msocket) #dummy assume 'ACK' received
print('first RESPONSE received')
for j in range(240):
b = bytes(imgArray[j])
msocket.sendall(bytes(b))
self.wait_RESPONSE(msocket) #dummy assume 'ACK' received
print('image sent finished')
msocket.close()
if __name__ == "__main__":
HOST, PORT = "localhost", 9999
# Create the server, binding to localhost on port 9999
#with socketserver.TCPServer((HOST, PORT), MyTCPHandler) as server:
with socketserver.TCPServer(('', PORT), MyTCPHandler) as server:
# Activate the server; this will keep running until you
# interrupt the program with Ctrl-C
server.serve_forever()
This socketserver.TCPServer((HOST, PORT), MyTCPHandler) as server example is
modify from
Python 3 socketserver.TCPServer Example. I assume socketserver.TCPServer will handle Ctrl-C with port close. But
in my test, SOMETIMES throw OSError of "Address already in use". In my practice,
try pressing Ctrl-C in REPL/restart repeatedly.
Next:
Saturday, March 20, 2021
ESP32 (ESP32-DevKitC V4)/MicroPython + 240*240 IPS (ST7789 SPI) using russhughes/st7789py_mpy lib
To display with 240*240 IPS (ST7789 SPI) LCD on ESP32 (ESP32-DevKitC V4)/MicroPython using russhughes/st7789py_mpy lib.
Connection:
In my exercise, SPI2 is used to send command to ST7789.
ST7789 ESP32-DevKitC
GND GND
VCC 3V3
SCL GPIO18
SDA GPIO23
RES GPIO5
DC GPIO4
BLK 3V3
self.xstart = xstart
self.ystart = ystart
"""
ESP32-DevKitC V4/MicroPython exercise
240x240 ST7789 SPI LCD
using MicroPython library:
https://github.com/russhughes/st7789py_mpy
"""
import uos
import machine
import st7789py as st7789
from fonts import vga1_16x32 as font
import random
import ustruct as struct
import utime
"""
ST7789 Display ESP32-DevKitC (SPI2)
SCL GPIO18
SDA GPIO23
GPIO19 (miso not used)
ST7789_rst GPIO5
ST7789_dc GPIO4
"""
#ST7789 use SPI(2)
st7789_res = 5
st7789_dc = 4
pin_st7789_res = machine.Pin(st7789_res, machine.Pin.OUT)
pin_st7789_dc = machine.Pin(st7789_dc, machine.Pin.OUT)
disp_width = 240
disp_height = 240
CENTER_Y = int(disp_width/2)
CENTER_X = int(disp_height/2)
print(uos.uname())
spi2 = machine.SPI(2, baudrate=40000000, polarity=1)
print(spi2)
display = st7789.ST7789(spi2, disp_width, disp_width,
reset=pin_st7789_res,
dc=pin_st7789_dc,
xstart=0, ystart=0, rotation=0)
display.fill(st7789.BLACK)
display.text(font, "Hello!", 10, 10)
display.text(font, "ESP32", 10, 40)
display.text(font, "MicroPython", 10, 70)
display.text(font, "ST7789 SPI", 10, 100)
display.text(font, "240*240 IPS", 10, 130)
for i in range(1000):
display.pixel(random.randint(0, disp_width),
random.randint(0, disp_height),
st7789.color565(random.getrandbits(8),random.getrandbits(8),random.getrandbits(8)))
# Helper function to draw a circle from a given position with a given radius
# This is an implementation of the midpoint circle algorithm,
# see https://en.wikipedia.org/wiki/Midpoint_circle_algorithm#C_example
# for details
def draw_circle(xpos0, ypos0, rad, col=st7789.color565(255, 255, 255)):
x = rad - 1
y = 0
dx = 1
dy = 1
err = dx - (rad << 1)
while x >= y:
display.pixel(xpos0 + x, ypos0 + y, col)
display.pixel(xpos0 + y, ypos0 + x, col)
display.pixel(xpos0 - y, ypos0 + x, col)
display.pixel(xpos0 - x, ypos0 + y, col)
display.pixel(xpos0 - x, ypos0 - y, col)
display.pixel(xpos0 - y, ypos0 - x, col)
display.pixel(xpos0 + y, ypos0 - x, col)
display.pixel(xpos0 + x, ypos0 - y, col)
if err <= 0:
y += 1
err += dy
dy += 2
if err > 0:
x -= 1
dx += 2
err += dx - (rad << 1)
draw_circle(CENTER_X, CENTER_Y, 100, st7789.color565(255, 255, 255))
draw_circle(CENTER_X, CENTER_Y, 97, st7789.color565(255, 0, 0))
draw_circle(CENTER_X, CENTER_Y, 94, st7789.color565(0, 255, 0))
draw_circle(CENTER_X, CENTER_Y, 91, st7789.color565(0, 0, 255))
utime.sleep(2)
display.fill(st7789.BLACK)
display.text(font, "Test various", 20, 10)
display.text(font, "approach to", 20, 50)
display.text(font, "fill pixels", 20, 90)
utime.sleep(2)
#test various approach to fill pixels
display.fill(st7789.BLACK)
display.text(font, "pixel()", 20, 10)
display.text(font, "optimized", 20, 70)
display.text(font, "blit_buffer()", 20, 130)
display.text(font, "fill_rect()", 20, 190)
utime.sleep(1)
# fill area with display.pixel()
ms_start = utime.ticks_ms()
for y in range(60):
for x in range(240):
display.pixel(x, y, st7789.color565(x, 0, 0))
ms_now = utime.ticks_ms()
display.text(font, str(utime.ticks_diff(ms_now,ms_start))+" ms", 50, 10)
# fill area optimized
#!!! may be NOT suit your setup
ms_start = utime.ticks_ms()
display.set_window(0, 60, 239, 119)
pin_st7789_dc.on()
for y in range(60, 120):
for x in range(240):
spi2.write(struct.pack(st7789._ENCODE_PIXEL,
(0 & 0xf8) << 8 | (x & 0xfc) << 3 | 0 >> 3))
ms_now = utime.ticks_ms()
display.text(font, str(utime.ticks_diff(ms_now,ms_start))+" ms", 50, 70)
# fill with blit_buffer(buffer, x, y, width, height)
buffer = bytearray(240*60*2)
ms_pre = utime.ticks_ms()
#prepare buffer
for y in range(60):
for x in range(240):
idx = ((y*240) + x)*2
pxCol = (y & 0xf8) << 8 | (0 & 0xfc) << 3 | x >> 3
packedPx = struct.pack(st7789._ENCODE_PIXEL, pxCol)
buffer[idx] = packedPx[0]
buffer[idx+1] = packedPx[1]
ms_start = utime.ticks_ms()
display.blit_buffer(buffer, 0, 120, 240, 60)
ms_now = utime.ticks_ms()
strToDisp = str(utime.ticks_diff(ms_start,ms_pre)) + \
"/" + str(utime.ticks_diff(ms_now,ms_start)) + " ms"
display.text(font, strToDisp, 50, 130)
# fill area with display.fill_rect()
ms_start = utime.ticks_ms()
display.fill_rect(0, 180, 240, 60, st7789.color565(0, 150, 150))
ms_now = utime.ticks_ms()
display.text(font, str(utime.ticks_diff(ms_now,ms_start))+" ms", 50, 190)
print("- bye-")
Remark about SPI@2021年04月07日:
pin_spi2_sck = machine.Pin(18, machine.Pin.OUT)
pin_spi2_mosi = machine.Pin(23, machine.Pin.OUT)
pin_spi2_miso = machine.Pin(19, machine.Pin.IN)
spi2 = machine.SPI(2, sck=pin_spi2_sck, mosi=pin_spi2_mosi, miso=pin_spi2_miso,
baudrate=40000000, polarity=1)
Saturday, March 13, 2021
RPi Pico + ESP32-S remote control ESP32-DevKitC via WiFi TCP, using MicroPython.
This exercise program Raspberry Pi Pico/MicroPython + ESP32-S (ESP-AT) as WiFi TCP client to remote control ESP32-DevKitC V4/MicroPython WiFi TCP server onboard LED.
In Client side:
ESP32-S is a wireless module based on ESP32. It's flashed with AT-command firmware ESP-AT. It's act as a WiFi co-processor. Raspberry Pi Pico/MicroPython send AT-command to ESP32-S via UART. Please note that for ESP32 flashed with ESP-AT: UART1 (IO16/IO17) is used to send AT commands and receive AT responses, connected to GP0/GP1 of Pico.
Pico GP15 connected to ESP32-S EN pin, to reset it in power up.
Pico GP16 is used control remote LED.
In Server side:
ESP32-DevKitC V4 (with ESP32-WROVER-E module)/MicroPython is programed as WiFi server, receive command from client to turn ON/OFF LED accordingly.
Connection:
import uos
import machine
import utime
"""
Raspberry Pi Pico/MicroPython + ESP32-S exercise
ESP32-S with AT-command firmware (ESP-AT):
---------------------------------------------------
AT version:2.1.0.0(883f7f2 - Jul 24 2020 11:50:07)
SDK version:v4.0.1-193-ge7ac221
compile time(0ad6331):Jul 28 2020 02:47:21
Bin version:2.1.0WROM-3)
---------------------------------------------------
Pico send AT command to ESP32-S via UART,
Send command to server (ESP32/MicroPython)
to turn ON/OFF LED on server.
---------------------------------------------------
Connection:
powered by separated power supply
Pico ESP32-S
GND GND
GP0 (TX) (pin 1) IO16 (RXD)
GP1 (RX) (pin 2) IO17 (TXD)
GP15 (pin 20) EN
GP16 (pin 21) button
---------------------------------------------------
"""
#server port & ip hard-coded,
#have to match with server side setting
server_ip="192.168.4.1"
server_port=8000
network_ssid = "ESP32-ssid"
network_password = "password"
ESP_EN = 15
PIN_ESP_EN = machine.Pin(ESP_EN, machine.Pin.IN, machine.Pin.PULL_UP)
DIn = machine.Pin(16, machine.Pin.IN, machine.Pin.PULL_UP)
print()
print("Machine: \t" + uos.uname()[4])
print("MicroPython: \t" + uos.uname()[3])
#indicate program started visually
led_onboard = machine.Pin(25, machine.Pin.OUT)
led_onboard.value(0) # Toggle onboard LED
utime.sleep(0.5) # to indiacte program start
led_onboard.value(1)
utime.sleep(1)
led_onboard.value(0)
#Reset ESP
PIN_ESP_EN = machine.Pin(ESP_EN, machine.Pin.OUT)
PIN_ESP_EN.value(1)
utime.sleep(0.5)
PIN_ESP_EN.value(0)
utime.sleep(0.5)
PIN_ESP_EN.value(1)
PIN_ESP_EN = machine.Pin(ESP_EN, machine.Pin.IN, machine.Pin.PULL_UP)
uart = machine.UART(0, baudrate=115200)
print(uart)
RES_OK = b'OK\r\n'
len_OK = len(RES_OK)
RESULT_OK = '0'
RESULT_TIMEOUT = '1'
def sendCMD_waitResult(cmd, timeout=2000):
print("CMD: " + cmd)
uart.write(cmd)
prvMills = utime.ticks_ms()
result = RESULT_TIMEOUT
resp = b""
while (utime.ticks_ms()-prvMills)<timeout:
if uart.any():
resp = b"".join([resp, uart.read(1)])
resp_len = len(resp)
if resp[resp_len-len_OK:]==RES_OK:
print(RES_OK + " found!")
result = RESULT_OK
break
print("resp:")
try:
print(resp.decode())
except UnicodeError:
print(resp)
return result
#to make it simple to detect, RMCMD & RMSTA designed same length
#Remote Command from client to serve
RMCMD_len = 6
RMCMD_ON = "LEDONN" #turn LED ON
RMCMD_OFF = "LEDOFF" #turn LED OFF
#Remote status from server to client
RMSTA_len = 6
RMSTA_timeout = "timeout" #time out without/unknown reply
RMSTA_LEDON = "LedOnn"
RMSTA_LEDOFF = "LedOff"
"""
#Expected flow to send command to wifi is:
Pico (client) to ESP-01S response from ESP-01S to Pico
AT+CIPSEND=<cmd len>\r\n
AT+CIPSEND=<cmd len>\r\n
OK\r\n
>\r\n
<cmd>
Recv x bytes\r\n
SEND OK\r\n ---> ESP (server)
<--- ESP (server) end with OK\r\n
+IPD,10:<RMSTA>OK\r\n
+IPD,2:\r\n
"""
def sendRemoteCmd(rmcmd, timeout=2000):
result = RMSTA_timeout
if sendCMD_waitResult('AT+CIPSEND=' + str(len(rmcmd)) + '\r\n', timeout)==RESULT_OK:
#dummy read '>'
while not uart.any():
pass
print(uart.read(1))
print("Remote CMD: " + rmcmd)
if sendCMD_waitResult(rmcmd) == RESULT_OK:
endMills = utime.ticks_ms() + timeout
resp = b""
while utime.ticks_ms()<endMills:
if uart.any():
resp = b"".join([resp, uart.read(1)])
resp_len = len(resp)
if resp[resp_len-len_OK:]==RES_OK:
print(RES_OK + " found!")
rmSta=resp[resp_len-len_OK-RMSTA_len:resp_len-len_OK]
strRmSta=rmSta.decode() #convert bytes to string
print(strRmSta)
if strRmSta == RMSTA_LEDON:
result = strRmSta
elif strRmSta == RMSTA_LEDOFF:
result = strRmSta
break
print("resp:")
try:
print(resp.decode())
except UnicodeError:
print(resp)
return result
def sendCMD_waitResp(cmd, timeout=2000):
print("CMD: " + cmd)
uart.write(cmd)
waitResp(timeout)
print()
def waitResp(timeout=2000):
prvMills = utime.ticks_ms()
resp = b""
while (utime.ticks_ms()-prvMills)<timeout:
if uart.any():
resp = b"".join([resp, uart.read(1)])
print("resp:")
try:
print(resp.decode())
except UnicodeError:
print(resp)
"""
everytimes send command to server:
- join ESP32 network
- connect to ESP32 socket
- send command to server and receive status
"""
def connectRemoteSendCmd(cmdsend):
clearRxBuf()
print("join wifi network: " + "ESP32-ssid")
while sendCMD_waitResult('AT+CWJAP="' + network_ssid + '","'
+ network_password + '"\r\n') != RESULT_OK:
pass
sendCMD_waitResp('AT+CIFSR\r\n') #Obtain the Local IP Address
sendCMD_waitResult('AT+CIPSTATUS\r\n')
print("wifi network joint")
print("connect socket")
if sendCMD_waitResult('AT+CIPSTART="TCP","'
+ server_ip
+ '",'
+ str(server_port) + '\r\n', timeout=5000) == RESULT_OK:
sendCMD_waitResult('AT+CIPSTATUS\r\n')
print("RMST: " + sendRemoteCmd(rmcmd=cmdsend))
clearRxBuf()
sendCMD_waitResult('AT+CIPSTATUS\r\n')
sendCMD_waitResult('AT+CWQAP\r\n')
def clearRxBuf():
print("--- clear Rx buffer ---")
buf = b""
while uart.any():
buf = b"".join([buf, uart.read(1)])
print(buf)
print("-----------------------")
led_onboard.value(0)
clearRxBuf()
sendCMD_waitResult('AT\r\n') #Test AT startup
sendCMD_waitResult('AT+CWMODE=1\r\n') #Set the Wi-Fi mode 1 = Station mode
sendCMD_waitResult('AT+CIPMUX=0\r\n') #single connection.
led_onboard.value(1)
connectRemoteSendCmd(cmdsend=RMCMD_ON)
utime.sleep(1)
connectRemoteSendCmd(cmdsend=RMCMD_OFF)
#fast toggle led 5 times to indicate startup finished
for i in range(5):
led_onboard.value(0)
utime.sleep(0.2)
led_onboard.value(1)
utime.sleep(0.2)
led_onboard.value(0)
print("Started")
print("waiting for button")
#read digital input every 10ms
dinMills = utime.ticks_ms() + 30
prvDin = 1
debounced = False
while True:
if utime.ticks_ms() > dinMills:
dinMills = utime.ticks_ms() + 30
curDin = DIn.value()
if curDin != prvDin:
#Din changed
prvDin = curDin
debounced = False
else:
if not debounced:
#DIn changed for > 30ms
debounced = True
if curDin:
connectRemoteSendCmd(cmdsend=RMCMD_OFF)
else:
connectRemoteSendCmd(cmdsend=RMCMD_ON)
import utime
import uos
import network
import usocket
from machine import Pin
"""
ESP32/MicroPython exercise:
ESP32 act as Access Point,
and setup a simple TCP server
receive command from client and turn ON/OFF LED,
and send back status.
"""
ssid= "ESP32-ssid"
password="password"
led=Pin(13,Pin.OUT)
print("----- MicroPython -----")
for u in uos.uname():
print(u)
print("-----------------------")
for i in range(3):
led.on()
utime.sleep(0.5)
led.off()
utime.sleep(0.5)
ap = network.WLAN(network.AP_IF) # Access Point
ap.config(essid=ssid,
password=password,
authmode=network.AUTH_WPA_WPA2_PSK)
ap.config(max_clients=1) # max number of client
ap.active(True) # activate the access point
print(ap.ifconfig())
print(dir(ap))
mysocket = usocket.socket(usocket.AF_INET, usocket.SOCK_STREAM)
mysocket.setsockopt(usocket.SOL_SOCKET, usocket.SO_REUSEADDR, 1)
port = 8000
mysocket.bind(('',8000))
print("bind: " + str(port))
mysocket.listen(1)
#tomake it simple to detect, RMCMD & RMSTA designed same length
#Remote Command from client to serve
RMCMD_len = 6
RMCMD_ON = "LEDONN" #turn LED ON
RMCMD_OFF = "LEDOFF" #turn LED OFF
#Remote status from server to client
RMSTA_len = 6
RMSTA_timeout = "timeout" #time out without/unknown reply
RMSTA_LEDON = "LedOnn"
RMSTA_LEDOFF = "LedOff"
while True:
conn, addr = mysocket.accept()
print('Connected from: %s' % str(addr))
print()
request = conn.recv(1024)
print('request: %s' % str(request))
print()
strRqs = request.decode()
print("strRqs: "+strRqs)
if strRqs==RMCMD_ON:
conn.send(RMSTA_LEDON+'OK\r\n')
led.on()
elif strRqs==RMCMD_OFF:
conn.send(RMSTA_LEDOFF+'OK\r\n')
led.off()
else:
#unknown command
conn.send(request.upper())
conn.send('\r\n')
conn.close()
Saturday, March 6, 2021
RPi Pico/MicroPython + ILI9341 SPI Display with Touch, using rdagger/micropython-ili9341
The display used in this exercise is a 2.4-inch 65K color using ili9341 driver with touch, 2.4inch_SPI_Module_ILI9341_SKU:MSP2402. I have other exercises using jeffmer/micropython-ili9341 library. This exercise using another lib rdagger/micropython-ili9341.
rdagger/micropython-ili9341 is a MicroPython ILI9341 Display and XPT2046 Touch Screen Drivers.
Connection:
from ili9341 import Display
from machine import Pin, SPI
TFT_CLK_PIN = const(6)
TFT_MOSI_PIN = const(7)
TFT_MISO_PIN = const(4)
TFT_CS_PIN = const(13)
TFT_RST_PIN = const(14)
TFT_DC_PIN = const(15)
def createMyDisplay():
#spi = SPI(0, baudrate=40000000, sck=Pin(TFT_CLK_PIN), mosi=Pin(TFT_MOSI_PIN))
spiTFT = SPI(0, baudrate=51200000,
sck=Pin(TFT_CLK_PIN), mosi=Pin(TFT_MOSI_PIN))
display = Display(spiTFT,
dc=Pin(TFT_DC_PIN), cs=Pin(TFT_CS_PIN), rst=Pin(TFT_RST_PIN))
return display
"""
Raspperry Pi Pico exercise display on ili9341 SPI Display
using rdagger/micropython-ili9341,
MicroPython ILI9341 Display and XPT2046 Touch Screen Drivers
https://github.com/rdagger/micropython-ili9341
"""
from machine import Pin, SPI
from sys import implementation
from os import uname
import utime
import ili9341
from xglcd_font import XglcdFont
import mySetup
print(implementation.name)
print(uname()[3])
print(uname()[4])
print(SPI(0))
print(SPI(1))
display = mySetup.createMyDisplay()
print('Loading fonts...')
print('Loading unispace')
unispace = XglcdFont('fonts/Unispace12x24.c', 12, 24)
display.draw_text(0, 0, ili9341.__name__, unispace,
ili9341.color565(255, 128, 0))
display.draw_text(0, 25, ili9341.implementation.name, unispace,
ili9341.color565(0, 0, 200))
display.draw_text(0, 50, str(ili9341.implementation.version), unispace,
ili9341.color565(0, 0, 200))
display.draw_text(0, 100, "https://github.com/", unispace,
ili9341.color565(200, 200, 200))
display.draw_text(0, 125, "rdagger/micropython-ili9341", unispace,
ili9341.color565(200, 200, 200))
display.draw_text(0, 175, "ABCDEFGHIJKLMNOPQRS", unispace,
ili9341.color565(200, 200, 200))
display.draw_text(0, 200, "TUVWXYZ", unispace,
ili9341.color565(200, 200, 200))
display.draw_text(0, 225, "abcdefghijklmnopqrs", unispace,
ili9341.color565(200, 200, 200))
display.draw_text(0, 250, "tuvwxyz", unispace,
ili9341.color565(200, 200, 200))
display.draw_text(0, 275, "01234567890", unispace,
ili9341.color565(200, 200, 200))
display.draw_text(0, 300, "~!@#$%^&*()_+`-={}[]", unispace,
ili9341.color565(200, 200, 200))
display.draw_text(0, 325, "\|;:'<>,.?/", unispace,
ili9341.color565(200, 200, 200))
for i in range(320):
display.scroll(i)
utime.sleep(0.02)
for i in range(320, 0, -1):
display.scroll(i)
utime.sleep(0.02)
utime.sleep(0.5)
# Display inversion on
display.write_cmd(display.INVON)
utime.sleep(2)
# Display inversion off
display.write_cmd(display.INVOFF)
while True:
pass
print("- bye -")
"""ILI9341 demo (bouncing boxes)."""
from machine import Pin, SPI
from random import random, seed
from ili9341 import Display, color565
from utime import sleep_us, ticks_cpu, ticks_us, ticks_diff
import mySetup
class Box(object):
"""Bouncing box."""
def __init__(self, screen_width, screen_height, size, display, color):
"""Initialize box.
Args:
screen_width (int): Width of screen.
screen_height (int): Width of height.
size (int): Square side length.
display (ILI9341): display object.
color (int): RGB565 color value.
"""
self.size = size
self.w = screen_width
self.h = screen_height
self.display = display
self.color = color
# Generate non-zero random speeds between -5.0 and 5.0
seed(ticks_cpu())
r = random() * 10.0
self.x_speed = 5.0 - r if r < 5.0 else r - 10.0
r = random() * 10.0
self.y_speed = 5.0 - r if r < 5.0 else r - 10.0
self.x = self.w / 2.0
self.y = self.h / 2.0
self.prev_x = self.x
self.prev_y = self.y
def update_pos(self):
"""Update box position and speed."""
x = self.x
y = self.y
size = self.size
w = self.w
h = self.h
x_speed = abs(self.x_speed)
y_speed = abs(self.y_speed)
self.prev_x = x
self.prev_y = y
if x + size >= w - x_speed:
self.x_speed = -x_speed
elif x - size <= x_speed + 1:
self.x_speed = x_speed
if y + size >= h - y_speed:
self.y_speed = -y_speed
elif y - size <= y_speed + 1:
self.y_speed = y_speed
self.x = x + self.x_speed
self.y = y + self.y_speed
def draw(self):
"""Draw box."""
x = int(self.x)
y = int(self.y)
size = self.size
prev_x = int(self.prev_x)
prev_y = int(self.prev_y)
self.display.fill_hrect(prev_x - size,
prev_y - size,
size, size, 0)
self.display.fill_hrect(x - size,
y - size,
size, size, self.color)
def test():
"""Bouncing box."""
try:
# Baud rate of 40000000 seems about the max
#spi = SPI(1, baudrate=40000000, sck=Pin(14), mosi=Pin(13))
#display = Display(spi, dc=Pin(4), cs=Pin(16), rst=Pin(17))
display = mySetup.createMyDisplay()
display.clear()
colors = [color565(255, 0, 0),
color565(0, 255, 0),
color565(0, 0, 255),
color565(255, 255, 0),
color565(0, 255, 255),
color565(255, 0, 255)]
sizes = [12, 11, 10, 9, 8, 7]
boxes = [Box(239, 319, sizes[i], display,
colors[i]) for i in range(6)]
while True:
timer = ticks_us()
for b in boxes:
b.update_pos()
b.draw()
# Attempt to set framerate to 30 FPS
timer_dif = 33333 - ticks_diff(ticks_us(), timer)
if timer_dif > 0:
sleep_us(timer_dif)
except KeyboardInterrupt:
display.cleanup()
test()
demo_colored_squares_.py
"""ILI9341 demo (colored squares)."""
from time import sleep
from ili9341 import Display
from machine import Pin, SPI
from sys import modules
import mySetup
RED = const(0XF800) # (255, 0, 0)
GREEN = const(0X07E0) # (0, 255, 0)
BLUE = const(0X001F) # (0, 0, 255)
YELLOW = const(0XFFE0) # (255, 255, 0)
FUCHSIA = const(0XF81F) # (255, 0, 255)
AQUA = const(0X07FF) # (0, 255, 255)
MAROON = const(0X8000) # (128, 0, 0)
DARKGREEN = const(0X0400) # (0, 128, 0)
NAVY = const(0X0010) # (0, 0, 128)
TEAL = const(0X0410) # (0, 128, 128)
PURPLE = const(0X8010) # (128, 0, 128)
OLIVE = const(0X8400) # (128, 128, 0)
ORANGE = const(0XFC00) # (255, 128, 0)
DEEP_PINK = const(0XF810) # (255, 0, 128)
CHARTREUSE = const(0X87E0) # (128, 255, 0)
SPRING_GREEN = const(0X07F0) # (0, 255, 128)
INDIGO = const(0X801F) # (128, 0, 255)
DODGER_BLUE = const(0X041F) # (0, 128, 255)
CYAN = const(0X87FF) # (128, 255, 255)
PINK = const(0XFC1F) # (255, 128, 255)
LIGHT_YELLOW = const(0XFFF0) # (255, 255, 128)
LIGHT_CORAL = const(0XFC10) # (255, 128, 128)
LIGHT_GREEN = const(0X87F0) # (128, 255, 128)
LIGHT_SLATE_BLUE = const(0X841F) # (128, 128, 255)
WHITE = const(0XFFF) # (255, 255, 255)
colors = [RED,
GREEN,
BLUE,
YELLOW,
FUCHSIA,
AQUA,
MAROON,
DARKGREEN,
NAVY,
TEAL,
PURPLE,
OLIVE,
ORANGE,
DEEP_PINK,
CHARTREUSE,
SPRING_GREEN,
INDIGO,
DODGER_BLUE,
CYAN,
PINK,
LIGHT_YELLOW,
LIGHT_CORAL,
LIGHT_GREEN,
LIGHT_SLATE_BLUE,
WHITE ]
def test():
"""Test code."""
"""
# Baud rate of 40000000 seems about the max
spi = SPI(0, baudrate=40000000, sck=Pin(TFT_CLK_PIN), mosi=Pin(TFT_MOSI_PIN))
display = Display(spi, dc=Pin(TFT_DC_PIN), cs=Pin(TFT_CS_PIN), rst=Pin(TFT_RST_PIN))
"""display = mySetup.createMyDisplay()"""
# Build color list from all upper case constants (lazy approach)
colors = [getattr(modules[__name__], name) for name in dir(
modules[__name__]) if name.isupper() and name is not 'SPI']
"""
colors.sort()
c = 0
for x in range(0, 240, 48):
for y in range(0, 320, 64):
display.fill_rectangle(x, y, 47, 63, colors[c])
c += 1
sleep(9)
display.cleanup()
test()
demo_color_palette_.py
"""ILI9341 demo (color palette)."""
from time import sleep
from ili9341 import Display, color565
from machine import Pin, SPI
import mySetup
def hsv_to_rgb(h, s, v):
"""
Convert HSV to RGB (based on colorsys.py).
Args:
h (float): Hue 0 to 1.
s (float): Saturation 0 to 1.
v (float): Value 0 to 1 (Brightness).
"""
if s == 0.0:
return v, v, v
i = int(h * 6.0)
f = (h * 6.0) - i
p = v * (1.0 - s)
q = v * (1.0 - s * f)
t = v * (1.0 - s * (1.0 - f))
i = i % 6
v = int(v * 255)
t = int(t * 255)
p = int(p * 255)
q = int(q * 255)
if i == 0:
return v, t, p
if i == 1:
return q, v, p
if i == 2:
return p, v, t
if i == 3:
return p, q, v
if i == 4:
return t, p, v
if i == 5:
return v, p, q
def test():
"""Test code."""
# Baud rate of 40000000 seems about the max
#spi = SPI(1, baudrate=40000000, sck=Pin(14), mosi=Pin(13))
#display = Display(spi, dc=Pin(4), cs=Pin(16), rst=Pin(17))
display = mySetup.createMyDisplay()
c = 0
for x in range(0, 240, 20):
for y in range(0, 320, 20):
color = color565(*hsv_to_rgb(c / 192, 1, 1))
display.fill_circle(x + 9, y + 9, 9, color)
c += 1
sleep(9)
display.cleanup()
test()
demo_color_wheel_.py
"""ILI9341 demo (color wheel)."""
from time import sleep
from ili9341 import Display, color565
from machine import Pin, SPI
from math import cos, pi, sin
import mySetup
HALF_WIDTH = const(120)
HALF_HEIGHT = const(160)
CENTER_X = const(119)
CENTER_Y = const(159)
ANGLE_STEP_SIZE = 0.05 # Decrease step size for higher resolution
PI2 = pi * 2
def hsv_to_rgb(h, s, v):
"""
Convert HSV to RGB (based on colorsys.py).
Args:
h (float): Hue 0 to 1.
s (float): Saturation 0 to 1.
v (float): Value 0 to 1 (Brightness).
"""
if s == 0.0:
return v, v, v
i = int(h * 6.0)
f = (h * 6.0) - i
p = v * (1.0 - s)
q = v * (1.0 - s * f)
t = v * (1.0 - s * (1.0 - f))
i = i % 6
v = int(v * 255)
t = int(t * 255)
p = int(p * 255)
q = int(q * 255)
if i == 0:
return v, t, p
if i == 1:
return q, v, p
if i == 2:
return p, v, t
if i == 3:
return p, q, v
if i == 4:
return t, p, v
if i == 5:
return v, p, q
def test():
"""Test code."""
# Baud rate of 40000000 seems about the max
#spi = SPI(1, baudrate=40000000, sck=Pin(14), mosi=Pin(13))
#display = Display(spi, dc=Pin(4), cs=Pin(16), rst=Pin(17))
display = mySetup.createMyDisplay()
x, y = 0, 0
angle = 0.0
# Loop all angles from 0 to 2 * PI radians
while angle < PI2:
# Calculate x, y from a vector with known length and angle
x = int(CENTER_X * sin(angle) + HALF_WIDTH)
y = int(CENTER_Y * cos(angle) + HALF_HEIGHT)
color = color565(*hsv_to_rgb(angle / PI2, 1, 1))
display.draw_line(x, y, CENTER_X, CENTER_Y, color)
angle += ANGLE_STEP_SIZE
sleep(5)
for r in range(CENTER_X, 0, -1):
color = color565(*hsv_to_rgb(r / HALF_WIDTH, 1, 1))
display.fill_circle(CENTER_X, CENTER_Y, r, color)
sleep(9)
display.cleanup()
test()
demo_shapes_.py
"""ILI9341 demo (shapes)."""
from time import sleep
from ili9341 import Display, color565
from machine import Pin, SPI
import mySetup
def test():
"""Test code."""
# Baud rate of 40000000 seems about the max
#spi = SPI(1, baudrate=40000000, sck=Pin(14), mosi=Pin(13))
#display = Display(spi, dc=Pin(4), cs=Pin(16), rst=Pin(17))
display = mySetup.createMyDisplay()
display.clear(color565(64, 0, 255))
sleep(1)
display.clear()
display.draw_hline(10, 319, 229, color565(255, 0, 255))
sleep(1)
display.draw_vline(10, 0, 319, color565(0, 255, 255))
sleep(1)
display.fill_hrect(23, 50, 30, 75, color565(255, 255, 255))
sleep(1)
display.draw_hline(0, 0, 222, color565(255, 0, 0))
sleep(1)
display.draw_line(127, 0, 64, 127, color565(255, 255, 0))
sleep(2)
display.clear()
coords = [[0, 63], [78, 80], [122, 92], [50, 50], [78, 15], [0, 63]]
display.draw_lines(coords, color565(0, 255, 255))
sleep(1)
display.clear()
display.fill_polygon(7, 120, 120, 100, color565(0, 255, 0))
sleep(1)
display.fill_rectangle(0, 0, 15, 227, color565(255, 0, 0))
sleep(1)
display.clear()
display.fill_rectangle(0, 0, 163, 163, color565(128, 128, 255))
sleep(1)
display.draw_rectangle(0, 64, 163, 163, color565(255, 0, 255))
sleep(1)
display.fill_rectangle(64, 0, 163, 163, color565(128, 0, 255))
sleep(1)
display.draw_polygon(3, 120, 286, 30, color565(0, 64, 255), rotate=15)
sleep(3)
display.clear()
display.fill_circle(132, 132, 70, color565(0, 255, 0))
sleep(1)
display.draw_circle(132, 96, 70, color565(0, 0, 255))
sleep(1)
display.fill_ellipse(96, 96, 30, 16, color565(255, 0, 0))
sleep(1)
display.draw_ellipse(96, 256, 16, 30, color565(255, 255, 0))
sleep(5)
display.cleanup()
test()
Detect Touch:
from ili9341 import Display
from machine import Pin, SPI
from xpt2046 import Touch
TFT_CLK_PIN = const(6)
TFT_MOSI_PIN = const(7)
TFT_MISO_PIN = const(4)
TFT_CS_PIN = const(13)
TFT_RST_PIN = const(14)
TFT_DC_PIN = const(15)
XPT_CLK_PIN = const(10)
XPT_MOSI_PIN = const(11)
XPT_MISO_PIN = const(8)
XPT_CS_PIN = const(12)
XPT_INT = const(0)
def createMyDisplay():
spiTFT = SPI(0, baudrate=40000000, sck=Pin(TFT_CLK_PIN), mosi=Pin(TFT_MOSI_PIN))
display = Display(spiTFT,
dc=Pin(TFT_DC_PIN), cs=Pin(TFT_CS_PIN), rst=Pin(TFT_RST_PIN))
return display
def createXPT(touch_handler):
spiXPT = SPI(1, baudrate=1000000,
sck=Pin(XPT_CLK_PIN), mosi=Pin(XPT_MOSI_PIN), miso=Pin(XPT_MISO_PIN))
xpt = Touch(spiXPT, cs=Pin(XPT_CS_PIN), int_pin=Pin(XPT_INT),
int_handler=touch_handler)
return xpt
from machine import Pin, SPI
from sys import implementation
from os import uname
import ili9341
from xglcd_font import XglcdFont
import mySetupX
print(implementation.name)
print(uname()[3])
print(uname()[4])
print(SPI(0))
print(SPI(1))
minX = maxX = minY = maxY = 500
def xpt_touch(x, y):
global xptTouch
global minX, maxX, minY, maxY
touchXY = xptTouch.get_touch()
rawX = xptTouch.send_command(xptTouch.GET_X)
rawY = xptTouch.send_command(xptTouch.GET_Y)
if rawX != 0:
if rawX > maxX:
maxX = rawX
elif rawX < minX:
minX = rawX
if rawY != 0:
if rawY > maxY:
maxY = rawY
elif rawY < minY:
minY = rawY
display.fill_circle(x, y, 2, ili9341.color565(0, 255, 0))
print(str(x) + ":" + str(y) + " / " + str(rawX) + ":" + str(rawY))
if touchXY != None:
touchX = touchXY[0]
touchY = touchXY[1]
display.fill_circle(touchX, touchY, 2, ili9341.color565(255, 0, 0))
print(str(touchX) + ":" + str(touchY))
xReading = "X: " + str(minX) + " - " + str(maxX) + " "
yReading = "Y: " + str(minY) + " - " + str(maxY) + " "
display.draw_text(0, 100, xReading, unispace,
ili9341.color565(255, 128, 0))
display.draw_text(0, 125, yReading, unispace,
ili9341.color565(255, 128, 0))
display = mySetupX.createMyDisplay()
xptTouch = mySetupX.createXPT(xpt_touch)
print('Loading fonts...')
print('Loading unispace')
unispace = XglcdFont('fonts/Unispace12x24.c', 12, 24)
display.draw_text(0, 0, ili9341.__name__, unispace,
ili9341.color565(255, 128, 0))
display.draw_text(0, 25, ili9341.implementation.name, unispace,
ili9341.color565(0, 0, 200))
display.draw_text(0, 50, str(ili9341.implementation.version), unispace,
ili9341.color565(0, 0, 200))
while True:
pass
print("- bye -")
xpt = Touch(spiXPT, cs=Pin(XPT_CS_PIN), int_pin=Pin(XPT_INT),
int_handler=touch_handler,
x_min=64, x_max=1847, y_min=148, y_max=2047)
from machine import Pin, SPI, Timer
from sys import implementation
from os import uname
import ili9341
from xglcd_font import XglcdFont
import mySetupX
print(implementation.name)
print(uname()[3])
print(uname()[4])
print(SPI(0))
print(SPI(1))
led = Pin(25, Pin.OUT)
#=== variable share btween ISR and main loop ===
x_passedTo_ISR = 0
y_passwsTo_ISR = 0
EVT_NO = const(0)
EVT_PenDown = const(1)
EVT_PenUp = const(2)
event = EVT_NO
TimerReached = False
#===============================================
def xpt_touch(x, y):
global event, x_passedTo_ISR, y_passedTo_ISR
event = EVT_PenDown
x_passedTo_ISR = x
y_passedTo_ISR = y
display = mySetupX.createMyDisplay()
xptTouch = mySetupX.createXPT(xpt_touch)
print('Loading fonts...')
print('Loading unispace')
unispace = XglcdFont('fonts/Unispace12x24.c', 12, 24)
display.clear()
display.draw_text(0, 0, ili9341.__name__, unispace,
ili9341.color565(255, 128, 0))
display.draw_text(0, 25, ili9341.implementation.name, unispace,
ili9341.color565(0, 0, 200))
display.draw_text(0, 50, str(ili9341.implementation.version), unispace,
ili9341.color565(0, 0, 200))
tim = Timer()
def TimerTick(timer):
global TimerReached
TimerReached = True
tim.init(freq=50, mode=Timer.PERIODIC, callback=TimerTick)
touching = False
lastX = lastY = 0
while True:
curEvent = event
event = EVT_NO
if curEvent!= EVT_NO:
if curEvent == EVT_PenDown:
print("Pen Down")
touching = True
lastX = x_passedTo_ISR
lastY = y_passedTo_ISR
touchXY = xptTouch.get_touch()
rawX = xptTouch.send_command(xptTouch.GET_X)
rawY = xptTouch.send_command(xptTouch.GET_Y)
display.clear()
display.fill_circle(x_passedTo_ISR, y_passedTo_ISR,
8, ili9341.color565(0, 255, 0))
print(str(x_passedTo_ISR) + ":" + str(y_passedTo_ISR) +
" / " + str(rawX) + ":" + str(rawY))
if touchXY != None:
touchX = touchXY[0]
touchY = touchXY[1]
display.fill_circle(touchX, touchY, 5, ili9341.color565(255, 0, 0))
print(str(touchX) + ":" + str(touchY))
elif curEvent == EVT_PenUp:
print("Pen Up")
pass
else:
print("unknown event!!!")
if TimerReached:
TimerReached = False
if touching:
led.toggle()
buff = xptTouch.raw_touch()
if buff is not None:
x, y = xptTouch.normalize(*buff)
lastX = x
lastY = y
display.fill_circle(x, y, 1, ili9341.color565(255, 255, 255))
print("... " + str(x) + " : " + str(y))
else:
event = EVT_PenUp
touching = False
led.off()
display.fill_circle(lastX, lastY, 5, ili9341.color565(0, 0, 255))
print("- bye -")
from machine import Pin, SPI, Timer
from sys import implementation
from os import uname
import ili9341
from xglcd_font import XglcdFont
import mySetupX
print(implementation.name)
print(uname()[3])
print(uname()[4])
print(SPI(0))
print(SPI(1))
led = Pin(25, Pin.OUT)
#=== variable share btween ISR and main loop ===
x_passedTo_ISR = 0
y_passwsTo_ISR = 0
EVT_NO = const(0)
EVT_PenDown = const(1)
EVT_PenUp = const(2)
event = EVT_NO
TimerReached = False
#===============================================
def xpt_touch(x, y):
global event, x_passedTo_ISR, y_passedTo_ISR
event = EVT_PenDown
x_passedTo_ISR = x
y_passedTo_ISR = y
display = mySetupX.createMyDisplay()
xptTouch = mySetupX.createXPT(xpt_touch)
print('Loading fonts...')
print('Loading unispace')
unispace = XglcdFont('fonts/Unispace12x24.c', 12, 24)
display.clear()
display.draw_text(0, 0, ili9341.__name__, unispace,
ili9341.color565(255, 128, 0))
display.draw_text(0, 25, ili9341.implementation.name, unispace,
ili9341.color565(0, 0, 200))
display.draw_text(0, 50, str(ili9341.implementation.version), unispace,
ili9341.color565(0, 0, 200))
tim = Timer()
def TimerTick(timer):
global TimerReached
TimerReached = True
tim.init(freq=50, mode=Timer.PERIODIC, callback=TimerTick)
touching = False
lastX = lastY = 0
while True:
curEvent = event
event = EVT_NO
if curEvent!= EVT_NO:
if curEvent == EVT_PenDown:
print("Pen Down")
touching = True
lastX = x_passedTo_ISR
lastY = y_passedTo_ISR
touchXY = xptTouch.get_touch()
rawX = xptTouch.send_command(xptTouch.GET_X)
rawY = xptTouch.send_command(xptTouch.GET_Y)
display.clear()
display.fill_circle(240-x_passedTo_ISR, y_passedTo_ISR,
8, ili9341.color565(0, 255, 0))
print(str(x_passedTo_ISR) + ":" + str(y_passedTo_ISR) +
" / " + str(rawX) + ":" + str(rawY))
if touchXY != None:
touchX = touchXY[0]
touchY = touchXY[1]
display.fill_circle(240-touchX, touchY, 5, ili9341.color565(255, 0, 0))
print(str(touchX) + ":" + str(touchY))
elif curEvent == EVT_PenUp:
print("Pen Up")
pass
else:
print("unknown event!!!")
if TimerReached:
TimerReached = False
if touching:
led.toggle()
buff = xptTouch.raw_touch()
if buff is not None:
x, y = xptTouch.normalize(*buff)
lastX = x
lastY = y
display.fill_circle(240-x, y, 1, ili9341.color565(255, 255, 255))
print("... " + str(x) + " : " + str(y))
else:
event = EVT_PenUp
touching = False
led.off()
display.fill_circle(240-lastX, lastY, 5, ili9341.color565(0, 0, 255))
print("- bye -")
Related: