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. 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. 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. [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 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. [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 [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 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 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). 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. 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) 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 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 quick and visually satisfactory response to button events. However ghosting may
accumulate after long periods of running, and an application may occasionally accumulate after long periods of running, and an application may occasionally
need to perform a full refresh. This requires the "done" interlock described need to perform a full refresh. This requires the "done" interlock described
above. in section 9.
```python ```python
async def full_refresh(): 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\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): class EPD(framebuf.FrameBuffer):
# A monochrome approach should be used for coding this. The rgb method ensures # A monochrome approach should be used for coding this. The rgb method ensures
# nothing breaks if users specify colors. # nothing breaks if users specify colors.
@ -245,33 +251,41 @@ class EPD(framebuf.FrameBuffer):
def ready(self): def ready(self):
return not (self._busy or (self.busy_pin() == 0)) # 0 == busy return not (self._busy or (self.busy_pin() == 0)) # 0 == busy
def _line(self, n, buf=bytearray(_BWIDTH)): @micropython.native
img = self.mvb def _line(self, start, buf=bytearray(_BWIDTH)): # Sending 50 bytes 40us at 10MHz, 12ms for 300 lines
s = n * _BWIDTH _linv(buf, self.mvb[start:], _BWIDTH) # Invert image data for EPD
for x, b in enumerate(img[s : s + _BWIDTH]):
buf[x] = b ^ 0xFF
self.send_bytes(buf) 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") self.send_command(b"\x13")
for j in range(_EPD_HEIGHT): # Loop would block ~300ms lps = _EPD_HEIGHT // split
self._line(j) 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) await asyncio.sleep_ms(0)
#print("Time", time.ticks_diff(time.ticks_ms(), ttt))
self._updated.set() self._updated.set()
self.send_command(b"\x12") # Async .display_on() self.send_command(b"\x12") # Nonblocking .display_on()
while not self.busy_pin(): 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 self._busy = False
#print("Time", time.ticks_diff(time.ticks_ms(), ttt)) # ~630ms
async def do_refresh(self, split): # For micro-gui 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: if self._busy:
raise RuntimeError('Cannot refresh: display is busy.') raise RuntimeError('Cannot refresh: display is busy.')
self._busy = True # Immediate busy flag. Pin goes low much later. self._busy = True # Immediate busy flag. Pin goes low much later.
if self._asyn: if self._asyn:
asyncio.create_task(self._as_show()) asyncio.create_task(self._as_show(5)) # split into 5 segments
return return
self.send_command(b"\x13") self.send_command(b"\x13")
for j in range(_EPD_HEIGHT): for j in range(_EPD_HEIGHT):

Wyświetl plik

@ -119,7 +119,7 @@ class FooScreen(Screen):
Checkbox(wri, row, col, callback=self.cbcb) Checkbox(wri, row, col, callback=self.cbcb)
col+= 40 col+= 40
self.led = LED(wri, row, col, color=YELLOW, bdcolor=GREEN) self.led = LED(wri, row, col, color=YELLOW, bdcolor=GREEN)
CloseButton(wri) CloseButton(wri, bgcolor=BLACK)
asyncio.create_task(run(dial, lbltim, m0, scale)) asyncio.create_task(run(dial, lbltim, m0, scale))
@ -174,10 +174,9 @@ async def run(dial, lbltim, m0, scale):
def test(): def test():
if ssd.height < 240 or ssd.width < 320: print('Testing micro-gui...')
print(' This test requires a display of at least 320x240 pixels.') Screen.change(FooScreen)
else: print("End")
print('Testing micro-gui...') ssd.sleep() # Tidy shutdown of EPD
Screen.change(FooScreen)
test() test()

Wyświetl plik

@ -29,7 +29,6 @@
from machine import Pin, SPI, freq from machine import Pin, SPI, freq
import gc import gc
from drivers.epaper.pico_epaper_42 import EPD as SSD from drivers.epaper.pico_epaper_42 import EPD as SSD
freq(250_000_000) # RP2 overclock freq(250_000_000) # RP2 overclock
# Create and export an SSD instance # Create and export an SSD instance
@ -37,7 +36,8 @@ prst = Pin(9, Pin.OUT, value=1)
pcs = Pin(10, Pin.OUT, value=1) pcs = Pin(10, Pin.OUT, value=1)
pdc = Pin(8, Pin.OUT, value=0) # Arbitrary pins pdc = Pin(8, Pin.OUT, value=0) # Arbitrary pins
busy = Pin(15, Pin.IN) 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 gc.collect() # Precaution before instantiating framebuf
# Using normal socket connection default args apply # Using normal socket connection default args apply

Wyświetl plik

@ -29,7 +29,6 @@
from machine import Pin, SPI, freq from machine import Pin, SPI, freq
import gc import gc
from drivers.epaper.pico_epaper_42 import EPD as SSD from drivers.epaper.pico_epaper_42 import EPD as SSD
freq(250_000_000) # RP2 overclock freq(250_000_000) # RP2 overclock
# Create and export an SSD instance # Create and export an SSD instance
@ -37,7 +36,8 @@ prst = Pin(9, Pin.OUT, value=1)
pcs = Pin(10, Pin.OUT, value=1) pcs = Pin(10, Pin.OUT, value=1)
pdc = Pin(8, Pin.OUT, value=0) # Arbitrary pins pdc = Pin(8, Pin.OUT, value=0) # Arbitrary pins
busy = Pin(15, Pin.IN) 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 gc.collect() # Precaution before instantiating framebuf
# Using normal socket connection default args apply # Using normal socket connection default args apply