123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321 |
- #!/usr/bin/env python3
-
- # ----------------------------------------------------------------------------
- # Copyright (c) 2023 Thomas Buck (thomas@xythobuz.de)
- #
- # This program is free software: you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation, either version 3 of the License, or
- # (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # See <http://www.gnu.org/licenses/>.
- # ----------------------------------------------------------------------------
-
- # https://www.waveshare.com/wiki/Pico-LCD-1.3
- # https://thepihut.com/blogs/raspberry-pi-tutorials/coding-graphics-with-micropython-on-raspberry-pi-pico-displays
- # https://api.arcade.academy/en/latest/_modules/arcade/draw_commands.html#draw_arc_filled
-
- from machine import Pin, SPI, PWM
- from array import array
- import framebuf
- import time
- import os
- import math
- import gc
-
- class KeyCheck:
- def __init__(self, new, old):
- self.new = new
- self.old = old
-
- def once(self, k):
- return self.new[k] and not self.old[k]
-
- def held(self, k):
- return self.new[k]
-
- class LCD(framebuf.FrameBuffer):
- def __init__(self):
- self.pwm = PWM(Pin(13))
- self.pwm.freq(1000)
- self.brightness(0.0)
-
- self.width = 240
- self.height = 240
-
- self.cs = Pin(9, Pin.OUT)
- self.rst = Pin(12, Pin.OUT)
-
- self.cs(1)
-
- self.spi = SPI(1, 100_000_000, polarity=0, phase=0, sck=Pin(10), mosi=Pin(11), miso=None)
-
- self.dc = Pin(8, Pin.OUT)
- self.dc(1)
-
- gc.collect()
- self.buffer = bytearray(self.height * self.width * 2)
-
- super().__init__(self.buffer, self.width, self.height, framebuf.RGB565)
- self.init_display()
-
- self.red = self.color(0xFF, 0x00, 0x00)
- self.green = self.color(0x00, 0xFF, 0x00)
- self.blue = self.color(0x00, 0x00, 0xFF)
- self.yellow = self.color(0xFF, 0xFF, 0x00)
- self.white = self.color(0xFF, 0xFF, 0xFF)
- self.black = self.color(0x00, 0x00, 0x00)
-
- self.fill(self.black)
- self.show()
-
- self.keyA = Pin(15, Pin.IN, Pin.PULL_UP)
- self.keyB = Pin(17, Pin.IN, Pin.PULL_UP)
- self.keyX = Pin(19, Pin.IN, Pin.PULL_UP)
- self.keyY = Pin(21, Pin.IN, Pin.PULL_UP)
- self.up = Pin( 2, Pin.IN, Pin.PULL_UP)
- self.down = Pin(18, Pin.IN, Pin.PULL_UP)
- self.left = Pin(16, Pin.IN, Pin.PULL_UP)
- self.right = Pin(20, Pin.IN, Pin.PULL_UP)
- self.ctrl = Pin( 3, Pin.IN, Pin.PULL_UP)
-
- self.keys_old = {
- "a": False,
- "b": False,
- "x": False,
- "y": False,
- "up": False,
- "down": False,
- "left": False,
- "right": False,
- "enter": False,
- }
-
- self.curr_brightness = 0.0
- try:
- with open("_cur_bright.txt", "r") as f:
- s = next(f).split()[0]
- self.curr_brightness = float(s)
- except:
- pass
- self.brightness(self.curr_brightness)
-
- def buttons(self):
- keys = {
- "a": self.keyA.value() == 0,
- "b": self.keyB.value() == 0,
- "x": self.keyX.value() == 0,
- "y": self.keyY.value() == 0,
- "up": self.up.value() == 0,
- "down": self.down.value() == 0,
- "left": self.left.value() == 0,
- "right": self.right.value() == 0,
- "enter": self.ctrl.value() == 0,
- }
- kc = KeyCheck(keys, self.keys_old)
- self.keys_old = keys.copy()
- return kc
-
- # Convert RGB888 to RGB565
- def color(self, R, G, B):
- return (((G & 0b00011100) << 3) + ((B & 0b11111000) >> 3) << 8) + (R & 0b11111000) + ((G & 0b11100000) >> 5)
-
- def store_brightness(self):
- old = -1.0
- try:
- with open("_cur_bright.txt", "r") as f:
- s = next(f).split()[0]
- old = float(s)
- except:
- pass
- if self.curr_brightness != old:
- with open("_cur_bright.txt", "w") as f:
- s = "{}\n".format(self.curr_brightness)
- f.write(s)
-
- def brightness(self, v):
- if v < 0.0:
- v = 0.0
- if v > 1.0:
- v = 1.0
- self.curr_brightness = v
- self.pwm.duty_u16(int(v * 65535))
-
- def write_cmd(self, cmd):
- self.cs(1)
- self.dc(0)
- self.cs(0)
- self.spi.write(bytearray([cmd]))
- self.cs(1)
-
- def write_data(self, buf):
- self.cs(1)
- self.dc(1)
- self.cs(0)
- self.spi.write(bytearray([buf]))
- self.cs(1)
-
- def init_display(self):
- self.rst(1)
- self.rst(0)
- self.rst(1)
- self.write_cmd(0x36)
- self.write_data(0x70)
- self.write_cmd(0x3A)
- self.write_data(0x05)
- self.write_cmd(0xB2)
- self.write_data(0x0C)
- self.write_data(0x0C)
- self.write_data(0x00)
- self.write_data(0x33)
- self.write_data(0x33)
- self.write_cmd(0xB7)
- self.write_data(0x35)
- self.write_cmd(0xBB)
- self.write_data(0x19)
- self.write_cmd(0xC0)
- self.write_data(0x2C)
- self.write_cmd(0xC2)
- self.write_data(0x01)
- self.write_cmd(0xC3)
- self.write_data(0x12)
- self.write_cmd(0xC4)
- self.write_data(0x20)
- self.write_cmd(0xC6)
- self.write_data(0x0F)
- self.write_cmd(0xD0)
- self.write_data(0xA4)
- self.write_data(0xA1)
- self.write_cmd(0xE0)
- self.write_data(0xD0)
- self.write_data(0x04)
- self.write_data(0x0D)
- self.write_data(0x11)
- self.write_data(0x13)
- self.write_data(0x2B)
- self.write_data(0x3F)
- self.write_data(0x54)
- self.write_data(0x4C)
- self.write_data(0x18)
- self.write_data(0x0D)
- self.write_data(0x0B)
- self.write_data(0x1F)
- self.write_data(0x23)
- self.write_cmd(0xE1)
- self.write_data(0xD0)
- self.write_data(0x04)
- self.write_data(0x0C)
- self.write_data(0x11)
- self.write_data(0x13)
- self.write_data(0x2C)
- self.write_data(0x3F)
- self.write_data(0x44)
- self.write_data(0x51)
- self.write_data(0x2F)
- self.write_data(0x1F)
- self.write_data(0x1F)
- self.write_data(0x20)
- self.write_data(0x23)
- self.write_cmd(0x21)
- self.write_cmd(0x11)
- self.write_cmd(0x29)
-
- def show(self):
- self.write_cmd(0x2A)
- self.write_data(0x00)
- self.write_data(0x00)
- self.write_data(0x00)
- self.write_data(0xef)
- self.write_cmd(0x2B)
- self.write_data(0x00)
- self.write_data(0x00)
- self.write_data(0x00)
- self.write_data(0xEF)
- self.write_cmd(0x2C)
- self.cs(1)
- self.dc(1)
- self.cs(0)
- self.spi.write(self.buffer)
- self.cs(1)
-
- def circle(self, x, y, r, c):
- self.hline(x-r,y,r*2,c)
- for i in range(1,r):
- a = int(math.sqrt(r*r-i*i)) # Pythagoras!
- self.hline(x-a,y+i,a*2,c) # Lower half
- self.hline(x-a,y-i,a*2,c) # Upper half
-
- def ring(self, x, y, r, c):
- self.pixel(x-r,y,c)
- self.pixel(x+r,y,c)
- self.pixel(x,y-r,c)
- self.pixel(x,y+r,c)
- for i in range(1, r):
- a = int(math.sqrt(r*r-i*i))
- self.pixel(x-a,y-i,c)
- self.pixel(x+a,y-i,c)
- self.pixel(x-a,y+i,c)
- self.pixel(x+a,y+i,c)
- self.pixel(x-i,y-a,c)
- self.pixel(x+i,y-a,c)
- self.pixel(x-i,y+a,c)
- self.pixel(x+i,y+a,c)
-
- def arc(self, x_off, y_off, w, h, c,
- start_angle, end_angle,
- filled = True,
- num_segments = 64):
- start_segment = int(start_angle / 360 * num_segments)
- end_segment = int(end_angle / 360 * num_segments)
-
- gc.collect()
- point_list = array('h')
- point_list.append(0)
- point_list.append(0)
-
- for segment in range(start_segment, end_segment + 1):
- theta = 2.0 * 3.1415926 * segment / num_segments
- x = w * math.cos(theta) / 2
- y = h * math.sin(theta) / 2
-
- i = (segment - start_segment + 1) * 2
- point_list.append(int(x))
- point_list.append(int(y))
-
- self.poly(int(x_off), int(y_off), point_list, c, filled)
-
- def pie(self, x0, y0, w, c_border, c_circle, v):
- if v > 0.0:
- self.arc(int(x0), int(y0), int(w), int(w), c_circle, -90, int(v * 360) - 90)
- self.ring(int(x0), int(y0), int(w / 2), c_border)
-
- def textC(self, s, x, y, c, bgColor = None):
- xStart = x - int(len(s) * 8 / 2)
- yStart = y - 5
-
- if bgColor != None:
- self.rect(xStart, yStart - 1, len(s) * 8, 10, bgColor, True)
-
- self.text(s, xStart, yStart, c)
-
- def textLine(self, s, c, off = 0):
- charsPerLine = int(self.width / 8)
- lines = list(s[0+i:charsPerLine+i] for i in range(0, len(s), charsPerLine))
- n = 0
- for i, l in enumerate(lines):
- self.text(l, 0, (i + off) * 10, c)
- n += 1
- if i >= (self.height / 10):
- break
- return n
-
- def textBlock(self, s, c):
- lines = s.split("\n")
- off = 0
- for l in lines:
- off += self.textLine(l, c, off)
|