kopia lustrzana https://github.com/peterhinch/micropython-nano-gui
ePaper drivers test for uasyncio running.
rodzic
35f8b23a52
commit
7be1073f48
54
DRIVERS.md
54
DRIVERS.md
|
@ -1039,8 +1039,8 @@ see below.
|
|||
* `rst` An initialised output pin. Initial value should be 1.
|
||||
* `busy` An initialised input pin.
|
||||
* `landscape=True` By default the long axis is horizontal.
|
||||
* `asyn=False` Setting this `True` invokes an asynchronous mode. See
|
||||
[EPD Asynchronous support](./DRIVERS.md#6-epd-asynchronous-support).
|
||||
|
||||
The `asyn` arg has been removed: the driver now detects asynchronous use.
|
||||
|
||||
### 5.1.2 Public methods
|
||||
|
||||
|
@ -1058,9 +1058,9 @@ All methods are synchronous.
|
|||
|
||||
### 5.1.3 Events
|
||||
|
||||
These provide synchronisation in asynchronous applications where `asyn=True`.
|
||||
They are only needed in more advanced asynchronous applications and their use
|
||||
is discussed in [EPD Asynchronous support](./DRIVERS.md#6-epd-asynchronous-support).
|
||||
These provide synchronisation in asynchronous applications. They are only
|
||||
needed in more advanced asynchronous applications and their use is discussed in
|
||||
[EPD Asynchronous support](./DRIVERS.md#6-epd-asynchronous-support).
|
||||
* `updated` Set when framebuf has been copied to device. It is now safe to
|
||||
modify widgets without risk of display corruption.
|
||||
* `complete` Set when display update is complete. It is now safe to call
|
||||
|
@ -1227,8 +1227,8 @@ Pins 26-40 unused and omitted.
|
|||
* `rst` An initialised output pin. Initial value should be 1.
|
||||
* `busy` An initialised input pin.
|
||||
* `landscape=False` By default the long axis is vertical.
|
||||
* `asyn=False` Setting this `True` invokes an asynchronous mode. See
|
||||
[EPD Asynchronous support](./DRIVERS.md#6-epd-asynchronous-support).
|
||||
|
||||
The `asyn` arg has been removed: the driver now detects asynchronous use.
|
||||
|
||||
### 5.2.2 EPD public methods
|
||||
|
||||
|
@ -1246,9 +1246,9 @@ All methods are synchronous.
|
|||
|
||||
### 5.2.3 Events
|
||||
|
||||
These provide synchronisation in asynchronous applications where `asyn=True`.
|
||||
They are only needed in more advanced asynchronous applications and their use
|
||||
is discussed in [EPD Asynchronous support](./DRIVERS.md#6-epd-asynchronous-support).
|
||||
These provide synchronisation in asynchronous applications. They are only
|
||||
needed in more advanced asynchronous applications and their use is discussed in
|
||||
[EPD Asynchronous support](./DRIVERS.md#6-epd-asynchronous-support).
|
||||
* `updated` Set when framebuf has been copied to device. It is now safe to
|
||||
modify widgets without risk of display corruption.
|
||||
* `complete` Set when display update is complete. It is now safe to call
|
||||
|
@ -1280,8 +1280,7 @@ import gc
|
|||
from drivers.epaper.pico_epaper_42 import EPD as SSD
|
||||
|
||||
gc.collect() # Precaution before instantiating framebuf.
|
||||
ssd = SSD() # Create a display instance. For normal applications.
|
||||
# ssd = SSD(asyn=True) # Alternative for asynchronous applications.
|
||||
ssd = SSD() # Create a display instance based on a Pico in socket.
|
||||
```
|
||||
### 5.3.1 Constructor args
|
||||
|
||||
|
@ -1293,8 +1292,8 @@ following constructor args:
|
|||
* `dc=None` A `Pin` instance defined as `Pin.OUT`.
|
||||
* `rst=None` A `Pin` instance defined as `Pin.OUT`.
|
||||
* `busy=None` A `Pin` instance defined as `Pin.IN, Pin.PULL_UP`.
|
||||
* `asyn=False` Set `True` for asynchronous applications. Leave `False` for
|
||||
microgui where the arg has no effect.
|
||||
|
||||
The `asyn` arg has been removed: the driver now detects asynchronous use.
|
||||
|
||||
### 5.3.2 Public methods
|
||||
|
||||
|
@ -1321,9 +1320,9 @@ ghosting.
|
|||
|
||||
### 5.3.3 Events
|
||||
|
||||
These provide synchronisation in asynchronous applications where `asyn=True`.
|
||||
They are only needed in more advanced asynchronous applications and their use
|
||||
is discussed in [EPD Asynchronous support](./DRIVERS.md#6-epd-asynchronous-support).
|
||||
These provide synchronisation in asynchronous applications. They are only
|
||||
needed in more advanced asynchronous applications and their use is discussed in
|
||||
[EPD Asynchronous support](./DRIVERS.md#6-epd-asynchronous-support).
|
||||
* `updated` Set when framebuf has been copied to device. It is now safe to
|
||||
modify widgets without risk of display corruption.
|
||||
* `complete` Set when display update is complete. It is now safe to call
|
||||
|
@ -1349,8 +1348,6 @@ before issuing another refresh.
|
|||
The following applies to nano-gui. Under micro-gui the update mechanism is
|
||||
a background task. Use with micro-gui is covered
|
||||
[here](https://github.com/peterhinch/micropython-micro-gui/blob/main/README.md#10-epaper-displays).
|
||||
Further, the comments address the case where the driver is instantiated with
|
||||
`asyn=True`.
|
||||
|
||||
When synchronous code issues
|
||||
```python
|
||||
|
@ -1364,15 +1361,14 @@ refresh is complete. If `demo_mode` is set, device drivers block for an
|
|||
additional 2 seconds to enable demos written for normal displays to work (the
|
||||
2 second pause allows the result of each refresh to be seen).
|
||||
|
||||
This long blocking period is not ideal in asynchronous code, and the process is
|
||||
modified if, in `color_setup.py`, an `EPD` is instantiated with `asyn=True`. In
|
||||
this case `refresh` calls the `show` method as before, but `show` creates a
|
||||
task `._as_show` and returns immediately. The task yields to the scheduler as
|
||||
necessary to ensure that blocking is limited to around 30ms. If screen updates
|
||||
take place at a low rate the only precaution necessary is to ensure that
|
||||
sufficient time elapses between calls to `ssd.refresh()` for the update to
|
||||
complete. For example the following code fragment illustrates an application
|
||||
which performs a full EPD refresh once per minute:
|
||||
This long blocking period is not ideal in asynchronous code. If `refresh` is
|
||||
called from a task, `refresh` calls the `show` method as before, but `show`
|
||||
creates a task `._as_show` and returns immediately. The task yields to the
|
||||
scheduler as necessary to ensure that blocking is limited to around 30ms. If
|
||||
screen updates take place at a low rate the only precaution necessary is to
|
||||
ensure that sufficient time elapses between calls to `ssd.refresh()` for the
|
||||
update to complete. For example the following code fragment illustrates an
|
||||
application which performs a full EPD refresh once per minute:
|
||||
|
||||
```python
|
||||
async def run():
|
||||
|
@ -1382,7 +1378,7 @@ async def run():
|
|||
ssd.refresh() # Launches background refresh
|
||||
await asyncio.sleep(60)
|
||||
```
|
||||
With `asyn=True` other running tasks experience latency measured in tens of ms.
|
||||
Other running tasks experience latency measured in tens of ms.
|
||||
|
||||
Finer control is available using the two public bound `Event` instances. This
|
||||
fragment assumes an application with a single task performing refreshes. The
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# EPD is subclassed from framebuf.FrameBuffer for use with Writer class and nanogui.
|
||||
# Optimisations to reduce allocations and RAM use.
|
||||
|
||||
# Copyright (c) Peter Hinch 2020
|
||||
# Copyright (c) Peter Hinch 2020-2023
|
||||
# Released under the MIT license see LICENSE
|
||||
|
||||
# Based on the following sources:
|
||||
|
@ -16,6 +16,13 @@ import framebuf
|
|||
import uasyncio as asyncio
|
||||
from time import sleep_ms, ticks_ms, ticks_us, ticks_diff
|
||||
|
||||
def asyncio_running():
|
||||
try:
|
||||
_ = asyncio.current_task()
|
||||
except:
|
||||
return False
|
||||
return True
|
||||
|
||||
class EPD(framebuf.FrameBuffer):
|
||||
# A monochrome approach should be used for coding this. The rgb method ensures
|
||||
# nothing breaks if users specify colors.
|
||||
|
@ -23,6 +30,7 @@ class EPD(framebuf.FrameBuffer):
|
|||
def rgb(r, g, b):
|
||||
return int((r > 127) or (g > 127) or (b > 127))
|
||||
|
||||
# Discard asyn: autodetect
|
||||
def __init__(self, spi, cs, dc, rst, busy, landscape=False, asyn=False):
|
||||
self._spi = spi
|
||||
self._cs = cs # Pins
|
||||
|
@ -30,7 +38,6 @@ class EPD(framebuf.FrameBuffer):
|
|||
self._rst = rst
|
||||
self._busy = busy
|
||||
self._lsc = landscape
|
||||
self._asyn = asyn
|
||||
self._as_busy = False # Set immediately on start of task. Cleared when busy pin is logically false (physically 1).
|
||||
self.updated = asyncio.Event()
|
||||
self.complete = asyncio.Event()
|
||||
|
@ -198,7 +205,7 @@ class EPD(framebuf.FrameBuffer):
|
|||
|
||||
# draw the current frame memory. Blocking time ~180ms
|
||||
def show(self, buf1=bytearray(1)):
|
||||
if self._asyn:
|
||||
if asyncio_running():
|
||||
if self._as_busy:
|
||||
raise RuntimeError('Cannot refresh: display is busy.')
|
||||
self._as_busy = True
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
# EPD is subclassed from framebuf.FrameBuffer for use with Writer class and nanogui.
|
||||
|
||||
# Copyright (c) Peter Hinch 2020
|
||||
# Copyright (c) Peter Hinch 2020-2023
|
||||
# Released under the MIT license see LICENSE
|
||||
|
||||
# Based on the following sources:
|
||||
|
@ -22,7 +22,14 @@ import uasyncio as asyncio
|
|||
from micropython import const
|
||||
from time import sleep_ms, sleep_us, ticks_ms, ticks_us, ticks_diff
|
||||
|
||||
_MAX_BLOCK = const(20) # Maximum blocking time (ms) for asynchronous show.
|
||||
_def asyncio_running():
|
||||
try:
|
||||
_ = asyncio.current_task()
|
||||
except:
|
||||
return False
|
||||
return True
|
||||
|
||||
MAX_BLOCK = const(20) # Maximum blocking time (ms) for asynchronous show.
|
||||
|
||||
class EPD(framebuf.FrameBuffer):
|
||||
# A monochrome approach should be used for coding this. The rgb method ensures
|
||||
|
@ -31,6 +38,7 @@ class EPD(framebuf.FrameBuffer):
|
|||
def rgb(r, g, b):
|
||||
return int((r > 127) or (g > 127) or (b > 127))
|
||||
|
||||
# Discard asyn: autodetect
|
||||
def __init__(self, spi, cs, dc, rst, busy, landscape=True, asyn=False):
|
||||
self._spi = spi
|
||||
self._cs = cs # Pins
|
||||
|
@ -38,7 +46,6 @@ class EPD(framebuf.FrameBuffer):
|
|||
self._rst = rst # Active low.
|
||||
self._busy = busy # Active low on IL0373
|
||||
self._lsc = landscape
|
||||
self._asyn = asyn
|
||||
# ._as_busy is set immediately on start of task. Cleared
|
||||
# when busy pin is logically false (physically 1).
|
||||
self._as_busy = False
|
||||
|
@ -165,7 +172,7 @@ class EPD(framebuf.FrameBuffer):
|
|||
|
||||
# draw the current frame memory.
|
||||
def show(self, buf1=bytearray(1)):
|
||||
if self._asyn:
|
||||
if asyncio_running():
|
||||
if self._as_busy:
|
||||
raise RuntimeError('Cannot refresh: display is busy.')
|
||||
self._as_busy = True # Immediate busy flag. Pin goes low much later.
|
||||
|
|
|
@ -45,6 +45,13 @@ import time
|
|||
import uasyncio as asyncio
|
||||
from drivers.boolpalette import BoolPalette
|
||||
|
||||
def asyncio_running():
|
||||
try:
|
||||
_ = asyncio.current_task()
|
||||
except:
|
||||
return False
|
||||
return True
|
||||
|
||||
# Display resolution
|
||||
_EPD_WIDTH = const(400)
|
||||
_BWIDTH = _EPD_WIDTH // 8
|
||||
|
@ -111,6 +118,7 @@ class EPD(framebuf.FrameBuffer):
|
|||
def rgb(r, g, b):
|
||||
return int((r > 127) or (g > 127) or (b > 127))
|
||||
|
||||
# Discard asyn: autodetect
|
||||
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
|
||||
|
@ -118,7 +126,6 @@ class EPD(framebuf.FrameBuffer):
|
|||
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.complete = asyncio.Event()
|
||||
|
@ -284,7 +291,9 @@ class EPD(framebuf.FrameBuffer):
|
|||
self._busy = False
|
||||
self.complete.set()
|
||||
|
||||
async def do_refresh(self, split): # For micro-gui
|
||||
# Specific method for micro-gui. Unsuitable EPD's lack this method. Micro-gui
|
||||
# does not test for asyncio as this is guaranteed to be up.
|
||||
async def do_refresh(self, split):
|
||||
assert (not self._busy), "Refresh while busy"
|
||||
await self._as_show() # split=5
|
||||
|
||||
|
@ -292,7 +301,7 @@ class EPD(framebuf.FrameBuffer):
|
|||
if self._busy:
|
||||
raise RuntimeError('Cannot refresh: display is busy.')
|
||||
self._busy = True # Immediate busy flag. Pin goes low much later.
|
||||
if self._asyn:
|
||||
if asyncio_running():
|
||||
self.updated.clear()
|
||||
self.complete.clear()
|
||||
asyncio.create_task(self._as_show())
|
||||
|
|
|
@ -38,4 +38,4 @@ pbusy = machine.Pin('Y4', machine.Pin.IN)
|
|||
# Datasheet P35 indicates up to 10MHz.
|
||||
spi = machine.SPI(2, baudrate=5_000_000)
|
||||
gc.collect() # Precaution before instantiating framebuf
|
||||
ssd = SSD(spi, pcs, pdc, prst, pbusy, asyn=True) # Create a display instance
|
||||
ssd = SSD(spi, pcs, pdc, prst, pbusy) # Create a display instance
|
||||
|
|
|
@ -13,6 +13,6 @@ import gc
|
|||
from drivers.epaper.pico_epaper_42 import EPD as SSD
|
||||
|
||||
gc.collect() # Precaution before instantiating framebuf
|
||||
# Set asyn True to run asynchronous code such as epd_async.py
|
||||
# Set False for normal synchronous code e.g. other demos.
|
||||
ssd = SSD(asyn=True) # Create a display instance
|
||||
ssd = SSD() # Create a display instance
|
||||
# Set this to run demos written for arbitrary displays:
|
||||
# ssd.demo_mode = True
|
||||
|
|
|
@ -32,5 +32,5 @@ prst = machine.Pin('Y3', machine.Pin.OUT_PP, value=1)
|
|||
pbusy = machine.Pin('Y4', machine.Pin.IN)
|
||||
spi = machine.SPI(2, baudrate=4_000_000) # From https://github.com/mcauser/micropython-waveshare-epaper/blob/master/examples/2in9-hello-world/test.py
|
||||
gc.collect() # Precaution before instantiating framebuf
|
||||
ssd = SSD(spi, pcs, pdc, prst, pbusy, landscape=False, asyn=True) # Create a display instance
|
||||
ssd = SSD(spi, pcs, pdc, prst, pbusy, landscape=False) # Create a display instance
|
||||
#ssd.demo_mode = True
|
||||
|
|
Ładowanie…
Reference in New Issue