From df7656802a8af8921e876d4cf2c0eadf6498ab47 Mon Sep 17 00:00:00 2001 From: Peter Hinch Date: Thu, 4 Jul 2024 18:50:23 +0100 Subject: [PATCH] pico_epaper_42 drivers async refresh: improve means of limiting blocking time. --- DRIVERS.md | 4 ++++ drivers/epaper/pico_epaper_42.py | 10 ++++++---- drivers/epaper/pico_epaper_42_gs.py | 8 +++++--- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/DRIVERS.md b/DRIVERS.md index 4a36690..4a51a40 100644 --- a/DRIVERS.md +++ b/DRIVERS.md @@ -1447,6 +1447,10 @@ needed in more advanced asynchronous applications and their use is discussed in seconds to enable viewing. This enables generic nanogui demos to be run on an EPD. + Class variable: + * `MAXBLOCK = 25` Defines the maximum period (in ms) that an asynchronous + refresh can block before yielding to the scheduler. + Note that in synchronous applications with `demo_mode=False`, `refresh` returns while the display is updating. Applications should issue `wait_until_ready` before issuing another refresh. diff --git a/drivers/epaper/pico_epaper_42.py b/drivers/epaper/pico_epaper_42.py index 0dfba61..7e8d3a0 100644 --- a/drivers/epaper/pico_epaper_42.py +++ b/drivers/epaper/pico_epaper_42.py @@ -118,6 +118,7 @@ def _linv(dest: ptr32, source: ptr32, length: int): class EPD(framebuf.FrameBuffer): + MAXBLOCK = 25 # Max async blocking time in ms # A monochrome approach should be used for coding this. The rgb method ensures # nothing breaks if users specify colors. @staticmethod @@ -229,7 +230,7 @@ class EPD(framebuf.FrameBuffer): self._cs(1) # Time to convert and transmit 1000 bytes ~ 1ms: most of that is tx @ 10MHz - # Yield every 16 transfers means blocking is ~16ms + # Yield whenever code has blocked for more than EPD.MAXBLOCK # Total convert and transmit time for 15000 bytes is ~15ms. # Timing @10MHz/250MHz: full refresh 2.1s, partial 740ms: the bulk of the time # is spent spinning on the busy pin and is CPU frequency independent. @@ -238,14 +239,15 @@ class EPD(framebuf.FrameBuffer): fbidx = 0 # Index into framebuf nbytes = len(self._ibuf) # Bytes to send nleft = len(self._buf) # Size of framebuf - npass = 0 + tyield = time.ticks_ms() # Time of last yield while nleft > 0: self._bsend(fbidx, nbytes) # Invert, buffer and send nbytes fbidx += nbytes # Adjust for bytes already sent nleft -= nbytes nbytes = min(nbytes, nleft) - if not ((npass := npass + 1) % 16): - await asyncio.sleep_ms(0) # Control blocking time + if time.ticks_diff(time.ticks_ms(), tyield) > EPD.MAXBLOCK: + await asyncio.sleep_ms(0) # Don't allow excessive blocking + tyield = time.ticks_ms() self.updated.set() self._command(b"\x12") # Nonblocking .display_on() while not self._busy_pin(): # Wait on display hardware diff --git a/drivers/epaper/pico_epaper_42_gs.py b/drivers/epaper/pico_epaper_42_gs.py index 08420fc..537552e 100644 --- a/drivers/epaper/pico_epaper_42_gs.py +++ b/drivers/epaper/pico_epaper_42_gs.py @@ -112,6 +112,7 @@ def _lmap(dest: ptr8, source: ptr8, pattern: int, length: int): class EPD(framebuf.FrameBuffer): + MAXBLOCK = 25 # Max async blocking time in ms # The rgb method maps colors onto a 2-bit greyscale # colors.py creates color constants with 2-bit colors which are written to FB @staticmethod @@ -238,14 +239,15 @@ class EPD(framebuf.FrameBuffer): nbytes = len(self.ibuf) # Bytes to send didx = nbytes * 2 # Increment of framebuf index nleft = len(self._buf) # Size of framebuf - npass = 0 + tyield = time.ticks_ms() # Time of last yield while nleft > 0: self._bsend(fbidx, pattern, nbytes) # Grey-map, buffer and send nbytes fbidx += didx # Adjust for bytes already sent nleft -= didx nbytes = min(nbytes, nleft) - if not ((npass := npass + 1) % 16): - await asyncio.sleep_ms(0) # Control blocking time + if time.ticks_diff(time.ticks_ms(), tyield) > EPD.MAXBLOCK: + await asyncio.sleep_ms(0) # Don't allow excessive blocking + tyield = time.ticks_ms() self.updated.set() self._command(b"\x12") # Nonblocking .display_on()