Add limited ePaper support.

encoder_driver
peterhinch 2023-04-13 13:34:37 +01:00
rodzic 43c19b7b48
commit e510739daf
5 zmienionych plików z 582 dodań i 17 usunięć

Wyświetl plik

@ -60,6 +60,8 @@ target and a C device driver (unless you can acquire a suitable binary).
# Project status
April 2023: Add limited ePaper support, grid widget, calendar and epaper demos.
July 2022: Add ESP32 touch pad support.
June 2022: Add [QRMap](./README.md#620-qrmap-widget) and
@ -147,6 +149,7 @@ development so check for updates.
7.4 [Class TSequence](./README.md#74-class-tsequence) Plotting realtime, time sequential data.
8. [ESP32 touch pads](./README.md#8-esp32-touch-pads) Replacing buttons with touch pads.
9. [Realtime applications](./README.md#9-realtime-applications) Accommodating tasks requiring fast RT performance.
9.1 [ePaper refresh](./README.md#91-epaper-refresh) Using these techniques to provide a full refresh.
[Appendix 1 Application design](./README.md#appendix-1-application-design) Tab order, button layout, encoder interface, use of graphics primitives
[Appendix 2 Freezing bytecode](./README.md#appendix-2-freezing-bytecode) Optional way to save RAM.
@ -501,8 +504,12 @@ some builds.
Supported displays are as per
[the nano-gui list](https://github.com/peterhinch/micropython-nano-gui/blob/master/README.md#12-description).
In practice usage with ePaper displays is questionable because of their slow
refresh times. I haven't tested these, or the Sharp displays.
In general ePaper and Sharp displays are unlikely to yield good results because
of slow and visually intrusive refreshing. However there is an exception: the
[Waveshare pico_epaper_42](https://www.waveshare.com/pico-epaper-4.2.htm). This
supports partial updates which work remarkably well with minimal ghosting. Note
that it can be used with hosts other than the Pico via the supplied cable. See
[ePaper refresh](./README.md#91-epaper-refresh).
Display drivers are documented [here](https://github.com/peterhinch/micropython-nano-gui/blob/master/DRIVERS.md).
@ -565,6 +572,11 @@ minimal and aim to demonstrate a single technique.
* `adjust_vec.py` A pair of `Adjuster`s vary a vector.
* `bitmap.py` Demo of the `BitMap` widget showing a changing image.
* `qrcode.py` Display a QR code. Requires the uQR module.
* `calendar.py` Demo of grid widget.
* `epaper.py` Warts-and-all demo for an ePaper display. Currently the only
supported display is the
[Waveshare pico_epaper_42](https://www.waveshare.com/pico-epaper-4.2.htm)
with Pico or other host.
### 1.11.2 Test scripts
@ -784,8 +796,8 @@ display such as an OLED. On a Sharp display it indicates reflection.
There is an issue regarding ePaper displays discussed
[here](https://github.com/peterhinch/micropython-nano-gui/blob/master/README.md#312-monochrome-displays).
I don't consider ePaper displays suitable for I/O because of their slow refresh
time.
The driver for the [Waveshare pico_epaper_42](https://www.waveshare.com/pico-epaper-4.2.htm)
renders colored objects as black on white.
###### [Contents](./README.md#0-contents)
@ -3030,6 +3042,27 @@ another from occurring.
```
The demo `gui/demos/audio.py` provides example usage.
## 9.1 ePaper refresh
The [Waveshare pico_epaper_42](https://www.waveshare.com/pico-epaper-4.2.htm)
is currently the only fully supported ePaper display, with a hardware_setup.py
copied or adapted from `setup_examples/pico_epaper_42_pico.py`. After an
initial refresh the driver is put into partial mode to provide reasonably
quick and visually satisfactory response to button events. However ghosting may
accumulate after long periods of running, and an application may occasionally
need to perform a full refresh. This requires the "done" interlock described
above.
```python
async def full_refresh():
Screen.rfsh_done.clear() # Enable completion flag
await Screen.rfsh_done.wait() # Wait for a refresh to end
ssd.set_full()
Screen.rfsh_done.clear() # Enable completion flag
await Screen.rfsh_done.wait() # Wait for a single full refresh to end
ssd.set_partial()
```
###### [Contents](./README.md#0-contents)
# Appendix 1 Application design

Wyświetl plik

@ -0,0 +1,287 @@
# pico_epaper_42.py A 1-bit monochrome display driver for the Waveshare Pico
# ePaper 4.2" display. This version fixes bugs and supports partial updates.
# https://github.com/peterhinch/micropython-nano-gui/blob/master/drivers/epaper/pico_epaper_42.py
# Adapted from the Waveshare driver by Peter Hinch Sept 2022-March 2023.
# https://www.waveshare.com/pico-epaper-4.2.htm
# UC8176 manual https://www.waveshare.com/w/upload/8/88/UC8176.pdf
# Waveshare's copy of this driver.
# https://github.com/waveshare/Pico_ePaper_Code/blob/main/pythonNanoGui/drivers/ePaper4in2.py
# *****************************************************************************
# * | File : Pico_ePaper-3.7.py
# * | Author : Waveshare team
# * | Function : Electronic paper driver
# * | Info :
# *----------------
# * | This version: V1.0
# * | Date : 2021-06-01
# # | Info : python demo
# -----------------------------------------------------------------------------
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documnetation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
# If .set_partial() is called, subsequent updates will be partial. To restore normal
# updates, issue .set_full()
from machine import Pin, SPI
import framebuf
import time
import uasyncio as asyncio
from drivers.boolpalette import BoolPalette
# Display resolution
_EPD_WIDTH = const(400)
_BWIDTH = _EPD_WIDTH // 8
_EPD_HEIGHT = const(300)
RST_PIN = 12
DC_PIN = 8
CS_PIN = 9
BUSY_PIN = 13
EPD_lut_vcom0 = b"\x00\x08\x08\x00\x00\x02\x00\x0F\x0F\x00\x00\x01\x00\x08\x08\x00\
\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x00\x00\x00"
EPD_lut_ww = b"\x50\x08\x08\x00\x00\x02\x90\x0F\x0F\x00\x00\x01\xA0\x08\x08\x00\x00\x02\
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
EPD_lut_bw = b"\x50\x08\x08\x00\x00\x02\x90\x0F\x0F\x00\x00\x01\xA0\x08\x08\x00\x00\x02\
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
EPD_lut_wb = b"\xA0\x08\x08\x00\x00\x02\x90\x0F\x0F\x00\x00\x01\x50\x08\x08\x00\x00\x02\
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
EPD_lut_bb = b"\x20\x08\x08\x00\x00\x02\x90\x0F\x0F\x00\x00\x01\x10\x08\x08\x00\x00\x02\
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
# ******************************partial screen update LUT********************************* #
EPD_partial_lut_vcom1 = b"\x00\x19\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x00\x00\x00"
EPD_partial_lut_ww1 = b"\x00\x19\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x00"
EPD_partial_lut_bw1 =b"\x80\x19\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x00"
EPD_partial_lut_wb1 = b"\x40\x19\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x00"
EPD_partial_lut_bb1 = b"\x00\x19\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x00"
class EPD(framebuf.FrameBuffer):
# A monochrome approach should be used for coding this. The rgb method ensures
# nothing breaks if users specify colors.
@staticmethod
def rgb(r, g, b):
return int((r > 127) or (g > 127) or (b > 127))
def __init__(self, spi=None, cs=None, dc=None, rst=None, busy=None, asyn=False):
self.reset_pin = Pin(RST_PIN, Pin.OUT) if rst is None else rst
self.busy_pin = Pin(BUSY_PIN, Pin.IN, Pin.PULL_UP) if busy is None else busy
self.cs_pin = Pin(CS_PIN, Pin.OUT) if cs is None else cs
self.dc_pin = Pin(DC_PIN, Pin.OUT) if dc is None else dc
self.spi = SPI(1, sck = Pin(10), mosi = Pin(11), miso = Pin(28)) if spi is None else spi
self.spi.init(baudrate = 4_000_000)
self._asyn = asyn
self._busy = False # Set immediately on .show(). Cleared when busy pin is logically false (physically 1).
self._updated = asyncio.Event()
self.width = _EPD_WIDTH
self.height = _EPD_HEIGHT
self.buf = bytearray(_EPD_HEIGHT * _BWIDTH)
self.mvb = memoryview(self.buf)
mode = framebuf.MONO_HLSB
self.palette = BoolPalette(mode)
super().__init__(self.buf, _EPD_WIDTH, _EPD_HEIGHT, mode)
self.init()
time.sleep_ms(500)
# Hardware reset
def reset(self):
for v in (1, 0, 1):
self.reset_pin(v)
time.sleep_ms(20)
def send_command(self, command):
self.dc_pin(0)
self.cs_pin(0)
self.spi.write(command)
self.cs_pin(1)
def send_bytes(self, data):
self.dc_pin(1)
self.cs_pin(0)
self.spi.write(data)
self.cs_pin(1)
def display_on(self):
self.send_command(b"\x12")
time.sleep_ms(100)
self.wait_until_ready()
def init(self):
self.reset()
self.send_command(b"\x01") # POWER SETTING
self.send_bytes(b"\x03")
self.send_bytes(b"\x00")
self.send_bytes(b"\x2b")
self.send_bytes(b"\x2b")
self.send_command(b"\x06") # boost soft start
self.send_bytes(b"\x17") # A
self.send_bytes(b"\x17") # B
self.send_bytes(b"\x17") # C
self.send_command(b"\x04") # POWER_ON
self.wait_until_ready()
self.send_command(b"\x00") # panel setting
self.send_bytes(b"\xbf") # KW-BF KWR-AF BWROTP 0f BWOTP 1f
self.send_bytes(b"\x0d")
self.send_command(b"\x30") # PLL setting
self.send_bytes(b"\x3C") # 3A 100HZ 29 150Hz 39 200HZ 31 171HZ
self.send_command(b"\x61") # resolution setting
self.send_bytes(b"\x01")
self.send_bytes(b"\x90") # 128
self.send_bytes(b"\x01")
self.send_bytes(b"\x2c")
self.send_command(b"\x82") # vcom_DC setting
self.send_bytes(b"\x28")
self.send_command(b"\x50") # VCOM AND DATA INTERVAL SETTING
self.send_bytes(b"\x97") # 97white border 77black border VBDF 17|D7 VBDW 97 VBDB 57 VBDF F7 VBDW 77 VBDB 37 VBDR B7
self.set_full()
# Clear display
self.send_command(b"\x10")
for j in range(_EPD_HEIGHT):
self.send_bytes(b"\xff" * _BWIDTH)
self.send_command(b"\x13")
for j in range(_EPD_HEIGHT):
self.send_bytes(b"\xff" * _BWIDTH)
self.send_command(b"\x12")
time.sleep_ms(10)
self.display_on()
def set_full(self): # Normal full updates
self.send_command(b"\x20")
self.send_bytes(EPD_lut_vcom0)
self.send_command(b"\x21")
self.send_bytes(EPD_lut_ww)
self.send_command(b"\x22")
self.send_bytes(EPD_lut_bw)
self.send_command(b"\x23")
self.send_bytes(EPD_lut_wb)
self.send_command(b"\x24")
self.send_bytes(EPD_lut_bb)
def set_partial(self): # Partial updates
self.send_command(b"\x20")
self.send_bytes(EPD_partial_lut_vcom1)
self.send_command(b"\x21")
self.send_bytes(EPD_partial_lut_ww1)
self.send_command(b"\x22")
self.send_bytes(EPD_partial_lut_bw1)
self.send_command(b"\x23")
self.send_bytes(EPD_partial_lut_wb1)
self.send_command(b"\x24")
self.send_bytes(EPD_partial_lut_bb1)
def wait_until_ready(self):
while not self.ready():
time.sleep_ms(100)
async def wait(self):
while not self.ready():
await asyncio.sleep_ms(100)
# Pause until framebuf has been copied to device.
async def updated(self):
self._updated.clear()
await self._updated.wait()
self._updated.clear()
# For polling in asynchronous code. Just checks pin state.
# 0 == busy. Comment in official code is wrong. Code is correct.
def ready(self):
return not (self._busy or (self.busy_pin() == 0)) # 0 == busy
def _line(self, n, buf=bytearray(_BWIDTH)):
img = self.mvb
s = n * _BWIDTH
for x, b in enumerate(img[s : s + _BWIDTH]):
buf[x] = b ^ 0xFF
self.send_bytes(buf)
async def _as_show(self):
self.send_command(b"\x13")
for j in range(_EPD_HEIGHT): # Loop would block ~300ms
self._line(j)
await asyncio.sleep_ms(0)
self._updated.set()
self.send_command(b"\x12") # Async .display_on()
while not self.busy_pin():
await asyncio.sleep_ms(10) # About 1.7s
self._busy = False
async def do_refresh(self, split): # For micro-gui
await self._as_show()
def show(self):
if self._busy:
raise RuntimeError('Cannot refresh: display is busy.')
self._busy = True # Immediate busy flag. Pin goes low much later.
if self._asyn:
asyncio.create_task(self._as_show())
return
self.send_command(b"\x13")
for j in range(_EPD_HEIGHT):
self._line(j)
self._busy = False
self.display_on()
self.wait_until_ready()
def sleep(self):
# self.send_command(b"\x02") # power off
# self.wait_until_ready()
self.send_command(b"\x07") # deep sleep
self.send_bytes(b"\xA5")

183
gui/demos/epaper.py 100644
Wyświetl plik

@ -0,0 +1,183 @@
# epaper.py micro-gui demo of multiple controls on an ePaper display type
# https://www.waveshare.com/pico-epaper-4.2.htm
# Use with setup_examples/pico_epaper_42_pico.py
# Released under the MIT License (MIT). See LICENSE.
# Copyright (c) 2023 Peter Hinch
# Initialise hardware and framebuf before importing modules.
# Create SSD instance. Must be done first because of RAM use.
import hardware_setup
from gui.core.ugui import Screen, ssd
from gui.core.writer import CWriter
import gui.fonts.arial10 as arial10 # Font for CWriter
from gui.core.colors import *
# Widgets
from gui.widgets.label import Label
from gui.widgets.dial import Dial, Pointer
from gui.widgets.meter import Meter
from gui.widgets.scale import Scale
from gui.widgets.buttons import Button, ButtonList, RadioButtons, CloseButton
from gui.widgets.checkbox import Checkbox
from gui.widgets.led import LED
import cmath
import uasyncio as asyncio
import utime
import gc
async def full_refresh():
Screen.rfsh_done.clear() # Enable completion flag
await Screen.rfsh_done.wait() # Wait for a refresh to end
ssd.set_full()
Screen.rfsh_done.clear() # Enable completion flag
await Screen.rfsh_done.wait() # Wait for a single full refresh to end
ssd.set_partial()
class FooScreen(Screen):
def __init__(self):
buttons = []
# A ButtonList with two entries
table_buttonset = (
{'fgcolor' : RED, 'text' : 'Disable', 'args' : (buttons, True)},
{'fgcolor' : GREEN, 'text' : 'Enable', 'args' : (buttons, False)},
)
table_radiobuttons = (
{'text' : '1', 'args' : ('1',)},
{'text' : '2', 'args' : ('2',)},
{'text' : '3', 'args' : ('3',)},
{'text' : '4', 'args' : ('4',)},
)
def tickcb(f, c):
if f > 0.8:
return RED
if f < -0.8:
return BLUE
return c
def bcb(b):
print('Button pressed', b)
super().__init__()
self.rb0 = None
self.bs0 = None
wri = CWriter(ssd, arial10, GREEN, BLACK, verbose=False)
lbltim = Label(wri, 65, 100, 'this is a test', bdcolor=RED)
m0 = Meter(wri, 10, 240, divisions = 4, ptcolor=YELLOW, height=80, width=15,
label='Meter example', style=Meter.BAR, legends=('0.0', '0.5', '1.0'))
# Instantiate displayable objects. bgcolor forces complete redraw.
dial = Dial(wri, 2, 2, height = 75, ticks = 12, bgcolor=BLACK, bdcolor=None, label=120) # Border in fg color
scale = Scale(wri, 2, 100, width = 124, tickcb = tickcb,
pointercolor=RED, fontcolor=YELLOW, bdcolor=CYAN)
row = 105
col = 2
Label(wri, row, col, 'Normal buttons')
# Four Button instances
row = 120
ht = 30
for i, s in enumerate(('a', 'b', 'c', 'd')):
col= 2 + i * (ht + 5)
buttons.append(Button(wri, row, col, height=ht, callback=bcb, text=s, litcolor=RED, shape=CIRCLE, bgcolor=DARKGREEN))
# ButtonList
self.bs = ButtonList(self.callback)
self.bs0 = None
col+= 50
Label(wri, row - 15, col, 'ButtonList')
for t in table_buttonset: # Buttons overlay each other at same location
button = self.bs.add_button(wri, row, col, shape=RECTANGLE, textcolor=BLUE, height=30, **t)
if self.bs0 is None: # Save for reset button callback
self.bs0 = button
# Reset button
col+= 60
btn = Button(wri, row, col, height=30, callback=self.rstcb, text='reset', litcolor=RED, fgcolor=GREEN, bgcolor=DARKGREEN)
col = 2
row = 170
Label(wri, row, col, 'Radio buttons')
# Radio buttons
row = 185
self.rb = RadioButtons(BLUE, self.rbcb) # color of selected button
self.rb0 = None
for t in table_radiobuttons:
button = self.rb.add_button(wri, row, col, textcolor = WHITE,
fgcolor = BLUE, bgcolor = DARKBLUE, shape=CIRCLE, height = 30, **t)
if self.rb0 is None: # Save for reset button callback
self.rb0 = button
col+= 35
# Checkbox
col+= 35
Label(wri, row - 15, col, 'Checkbox and LED')
Checkbox(wri, row, col, callback=self.cbcb)
col+= 40
self.led = LED(wri, row, col, color=YELLOW, bdcolor=GREEN)
CloseButton(wri)
asyncio.create_task(run(dial, lbltim, m0, scale))
def callback(self, button, buttons, val):
buttons[2].greyed_out(val)
def rbcb(self, button, val):
print('RadioButtons callback', val)
def rstcb(self, button):
print('Reset button: init ButtonList and RadioButtons, do full refresh.')
self.bs.value(self.bs0)
self.rb.value(self.rb0)
asyncio.create_task(full_refresh())
def cbcb(self, cb):
self.led.value(cb.value())
gc.collect()
print('Free RAM:', gc.mem_free())
async def run(dial, lbltim, m0, scale):
days = ('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday',
'Sunday')
months = ('Jan', 'Feb', 'March', 'April', 'May', 'June', 'July',
'Aug', 'Sept', 'Oct', 'Nov', 'Dec')
uv = lambda phi : cmath.rect(1, phi) # Return a unit vector of phase phi
pi = cmath.pi
hrs = Pointer(dial)
mins = Pointer(dial)
secs = Pointer(dial)
hstart = 0 + 0.7j # Pointer lengths and position at top
mstart = 0 + 0.92j
sstart = 0 + 0.92j
cv = -1.0 # Scale
dv = 0.005
while True:
t = utime.localtime()
hrs.value(hstart * uv(-t[3]*pi/6 - t[4]*pi/360), YELLOW)
mins.value(mstart * uv(-t[4] * pi/30), YELLOW)
secs.value(sstart * uv(-t[5] * pi/30), RED)
lbltim.value('{:02d}.{:02d}.{:02d}'.format(t[3], t[4], t[5]))
dial.text('{} {} {} {}'.format(days[t[6]], t[2], months[t[1] - 1], t[0]))
m0.value(t[5]/60)
scale.value(cv)
await asyncio.sleep_ms(200)
cv += dv
if abs(cv) > 1.0:
dv = -dv
cv += dv
def test():
if ssd.height < 240 or ssd.width < 320:
print(' This test requires a display of at least 320x240 pixels.')
else:
print('Testing micro-gui...')
Screen.change(FooScreen)
test()

Wyświetl plik

@ -1,15 +1,12 @@
# ili9341_pico.py Customise for your hardware config
# pico_epaper_42.py on my PCB (non-standard connection)
# Released under the MIT License (MIT). See LICENSE.
# Copyright (c) 2021 Peter Hinch
# Copyright (c) 2023 Peter Hinch
# As written, supports:
# ili9341 240x320 displays on Pi Pico
# Edit the driver import for other displays.
# Demo of initialisation procedure designed to minimise risk of memory fail
# when instantiating the frame buffer. The aim is to do this as early as
# possible before importing other modules.
# This Hardware_setup.py is for # https://www.waveshare.com/pico-epaper-4.2.htm
# wired to the Pico using the ribbon cable rather than the default socket.
# This was to enable testing using my ILI9341 PCB and its pushbuttons.
# Use commented-out code below if using the built-in Pico socket.
# WIRING
# Pico Display
@ -33,15 +30,19 @@
from machine import Pin, SPI, freq
import gc
from drivers.ili93xx.ili9341 import ILI9341 as SSD
from drivers.epaper.pico_epaper_42 import EPD as SSD
freq(250_000_000) # RP2 overclock
# Create and export an SSD instance
prst = Pin(9, Pin.OUT, value=1)
pcs = Pin(10, Pin.OUT, value=1)
pdc = Pin(8, Pin.OUT, value=0) # Arbitrary pins
spi = SPI(0, sck=Pin(6), mosi=Pin(7), miso=Pin(4), baudrate=30_000_000)
busy = Pin(15, Pin.IN)
spi = SPI(0, sck=Pin(6), mosi=Pin(7), miso=Pin(4), baudrate=4_000_000)
gc.collect() # Precaution before instantiating framebuf
ssd = SSD(spi, pcs, pdc, prst, usd=True)
# Using normal socket connection default args apply
# ssd = SSD()
ssd = SSD(spi, pcs, pdc, prst, busy)
gc.collect()
from gui.core.ugui import Display, quiet
# quiet()
@ -53,4 +54,6 @@ prev = Pin(18, Pin.IN, Pin.PULL_UP) # Move to previous control
increase = Pin(20, Pin.IN, Pin.PULL_UP) # Increase control's value
decrease = Pin(17, Pin.IN, Pin.PULL_UP) # Decrease control's value
# display = Display(ssd, nxt, sel, prev) # 3-button mode
display = Display(ssd, nxt, sel, prev, increase, decrease, 4) # Encoder mode
display = Display(ssd, nxt, sel, prev, increase, decrease) # 5-button mode
ssd.wait_until_ready() # Blocking wait
ssd.set_partial() # Subsequent refreshes are partial

Wyświetl plik

@ -0,0 +1,59 @@
# pico_epaper_42.py on my PCB (non-standard connection)
# Released under the MIT License (MIT). See LICENSE.
# Copyright (c) 2023 Peter Hinch
# This Hardware_setup.py is for # https://www.waveshare.com/pico-epaper-4.2.htm
# wired to the Pico using the ribbon cable rather than the default socket.
# This was to enable testing using my ILI9341 PCB and its pushbuttons.
# Use commented-out code below if using the built-in Pico socket.
# WIRING
# Pico Display
# GPIO Pin
# 3v3 36 Vin
# IO6 9 CLK Hardware SPI0
# IO7 10 DATA (AKA SI MOSI)
# IO8 11 DC
# IO9 12 Rst
# Gnd 13 Gnd
# IO10 14 CS
# Pushbuttons are wired between the pin and Gnd
# Pico pin Meaning
# 16 Operate current control
# 17 Decrease value of current control
# 18 Select previous control
# 19 Select next control
# 20 Increase value of current control
from machine import Pin, SPI, freq
import gc
from drivers.epaper.pico_epaper_42 import EPD as SSD
freq(250_000_000) # RP2 overclock
# Create and export an SSD instance
prst = Pin(9, Pin.OUT, value=1)
pcs = Pin(10, Pin.OUT, value=1)
pdc = Pin(8, Pin.OUT, value=0) # Arbitrary pins
busy = Pin(15, Pin.IN)
spi = SPI(0, sck=Pin(6), mosi=Pin(7), miso=Pin(4), baudrate=4_000_000)
gc.collect() # Precaution before instantiating framebuf
# Using normal socket connection default args apply
# ssd = SSD()
ssd = SSD(spi, pcs, pdc, prst, busy)
gc.collect()
from gui.core.ugui import Display, quiet
# quiet()
# Create and export a Display instance
# Define control buttons
nxt = Pin(19, Pin.IN, Pin.PULL_UP) # Move to next control
sel = Pin(16, Pin.IN, Pin.PULL_UP) # Operate current control
prev = Pin(18, Pin.IN, Pin.PULL_UP) # Move to previous control
increase = Pin(20, Pin.IN, Pin.PULL_UP) # Increase control's value
decrease = Pin(17, Pin.IN, Pin.PULL_UP) # Decrease control's value
# display = Display(ssd, nxt, sel, prev) # 3-button mode
display = Display(ssd, nxt, sel, prev, increase, decrease) # 5-button mode
ssd.wait_until_ready() # Blocking wait
ssd.set_partial() # Subsequent refreshes are partial