ePaper optimisations.

encoder_driver
peterhinch 2023-04-13 18:37:21 +01:00
rodzic e510739daf
commit 1424c06bb6
5 zmienionych plików z 40 dodań i 27 usunięć

Wyświetl plik

@ -149,7 +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.
10. [ePaper displays](./README.md#10-epaper-displays) 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.
@ -509,7 +509,7 @@ 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).
[ePaper displays](./README.md#10-epaper-displays).
Display drivers are documented [here](https://github.com/peterhinch/micropython-nano-gui/blob/master/DRIVERS.md).
@ -3042,7 +3042,7 @@ another from occurring.
```
The demo `gui/demos/audio.py` provides example usage.
## 9.1 ePaper refresh
# 10 ePaper displays
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
@ -3051,7 +3051,7 @@ 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.
in section 9.
```python
async def full_refresh():

Wyświetl plik

@ -94,6 +94,12 @@ 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"
@micropython.viper
def _linv(dest:ptr8, source:ptr8, length:int):
for n in range(length):
c = source[n]
dest[n] = c ^ 0xFF
class EPD(framebuf.FrameBuffer):
# A monochrome approach should be used for coding this. The rgb method ensures
# nothing breaks if users specify colors.
@ -245,33 +251,41 @@ class EPD(framebuf.FrameBuffer):
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
@micropython.native
def _line(self, start, buf=bytearray(_BWIDTH)): # Sending 50 bytes 40us at 10MHz, 12ms for 300 lines
_linv(buf, self.mvb[start:], _BWIDTH) # Invert image data for EPD
self.send_bytes(buf)
async def _as_show(self):
# Timing @10MHz/250MHz: full refresh 2.1s, partial 740ms
# Blocking with split=5 740/5=150ms
async def _as_show(self, split):
self.send_command(b"\x13")
for j in range(_EPD_HEIGHT): # Loop would block ~300ms
self._line(j)
lps = _EPD_HEIGHT // split
idx = 0
#ttt = time.ticks_ms()
for _ in range(split): # For each segment
for _ in range(lps):
self._line(idx)
idx += _BWIDTH
await asyncio.sleep_ms(0)
#print("Time", time.ticks_diff(time.ticks_ms(), ttt))
self._updated.set()
self.send_command(b"\x12") # Async .display_on()
self.send_command(b"\x12") # Nonblocking .display_on()
while not self.busy_pin():
await asyncio.sleep_ms(10) # About 1.7s
await asyncio.sleep_ms(0) # About 1.7s for full refresh
self._busy = False
#print("Time", time.ticks_diff(time.ticks_ms(), ttt)) # ~630ms
async def do_refresh(self, split): # For micro-gui
await self._as_show()
assert (not self._busy), "Refresh while busy"
await self._as_show(split) # split=5
def show(self):
def show(self): # nanogui
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())
asyncio.create_task(self._as_show(5)) # split into 5 segments
return
self.send_command(b"\x13")
for j in range(_EPD_HEIGHT):

Wyświetl plik

@ -119,7 +119,7 @@ class FooScreen(Screen):
Checkbox(wri, row, col, callback=self.cbcb)
col+= 40
self.led = LED(wri, row, col, color=YELLOW, bdcolor=GREEN)
CloseButton(wri)
CloseButton(wri, bgcolor=BLACK)
asyncio.create_task(run(dial, lbltim, m0, scale))
@ -174,10 +174,9 @@ async def run(dial, lbltim, m0, scale):
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)
print('Testing micro-gui...')
Screen.change(FooScreen)
print("End")
ssd.sleep() # Tidy shutdown of EPD
test()

Wyświetl plik

@ -29,7 +29,6 @@
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
@ -37,7 +36,8 @@ 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)
# Datasheet allows 10MHz
spi = SPI(0, sck=Pin(6), mosi=Pin(7), miso=Pin(4), baudrate=10_000_000)
gc.collect() # Precaution before instantiating framebuf
# Using normal socket connection default args apply

Wyświetl plik

@ -29,7 +29,6 @@
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
@ -37,7 +36,8 @@ 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)
# Datasheet allows 10MHz
spi = SPI(0, sck=Pin(6), mosi=Pin(7), miso=Pin(4), baudrate=10_000_000)
gc.collect() # Precaution before instantiating framebuf
# Using normal socket connection default args apply