kopia lustrzana https://github.com/peterhinch/micropython-nano-gui
Prior to merge
rodzic
2868bcaf2e
commit
35f8b23a52
180
DRIVERS.md
180
DRIVERS.md
|
@ -55,15 +55,21 @@ access via the `Writer` and `CWriter` classes is documented
|
|||
5. [ePaper displays](./DRIVERS.md#5-epaper-displays)
|
||||
5.1 [Adafruit monochrome eInk Displays](./DRIVERS.md#51-adafruit-monochrome-eink-displays)
|
||||
5.1.1 [EPD constructor args](./DRIVERS.md#511-epd-constructor-args)
|
||||
5.1.2 [EPD public methods](./DRIVERS.md#512-epd-public-methods)
|
||||
5.1.3 [EPD public bound variables](./DRIVERS.md#513-epd-public-bound-variables)
|
||||
5.1.4 [FeatherWing Wiring](./DRIVERS.md#514-featherwing-wiring)
|
||||
5.1.5 [Micropower use](./DRIVERS.md#515-micropower-use)
|
||||
5.1.2 [Public methods](./DRIVERS.md#512-public-methods)
|
||||
5.1.3 [Events](./DRIVERS.md#513-events)
|
||||
5.1.4 [Public bound variables](./DRIVERS.md#514-public-bound-variables)
|
||||
5.1.5 [FeatherWing Wiring](./DRIVERS.md#515-featherwing-wiring)
|
||||
5.1.6 [Micropower use](./DRIVERS.md#516-micropower-use)
|
||||
5.2 [Waveshare eInk Display HAT](./DRIVERS.md#52-waveshare-eink-display-hat) Pi HAT repurposed for MP hosts.
|
||||
5.2.1 [EPD constructor args](./DRIVERS.md#521-epd-constructor-args)
|
||||
5.2.2 [EPD public methods](./DRIVERS.md#522-epd-public-methods)
|
||||
5.2.3 [EPD public bound variables](./DRIVERS.md#523-epd-public-bound-variables)
|
||||
5.2.2 [Public methods](./DRIVERS.md#522-public-methods)
|
||||
5.2.3 [Events](./DRIVERS.md#523-events)
|
||||
5.2.4 [public bound variables](./DRIVERS.md#524-public-bound-variables)
|
||||
5.3 [Waveshare 400x300 Pi Pico display](./DRIVERS.md#53-waveshare-400x300-pi-pico-display) Excellent display can also be used with other hosts.
|
||||
5.3.1 [Constructor args](./DRIVERS.md#531-constructor-args)
|
||||
5.3.2 [Public methods](./DRIVERS.md#532-public-methods)
|
||||
5.3.3 [Events](./DRIVERS.md#533-events)
|
||||
5.3.4 [Public bound variables](./DRIVERS.md#534-public-bound-variables)
|
||||
6. [EPD Asynchronous support](./DRIVERS.md#6-epd-asynchronous-support)
|
||||
7. [Writing device drivers](./DRIVERS.md#7-writing-device-drivers)
|
||||
8. [Links](./DRIVERS.md#8-links)
|
||||
|
@ -1036,9 +1042,10 @@ see below.
|
|||
* `asyn=False` Setting this `True` invokes an asynchronous mode. See
|
||||
[EPD Asynchronous support](./DRIVERS.md#6-epd-asynchronous-support).
|
||||
|
||||
### 5.1.2 EPD public methods
|
||||
### 5.1.2 Public methods
|
||||
|
||||
All methods are synchronous.
|
||||
|
||||
##### Synchronous methods
|
||||
* `init` No args. Issues a hardware reset and initialises the hardware. This
|
||||
is called by the constructor. It needs to explicitly be called to exit from a
|
||||
deep sleep.
|
||||
|
@ -1049,12 +1056,18 @@ see below.
|
|||
a period: `ready` status should be checked before issuing `refresh`.
|
||||
* `wait_until_ready` No args. Pause until the device is ready.
|
||||
|
||||
##### Asynchronous methods
|
||||
* `updated` Asynchronous. No args. Pause until the framebuffer has been copied
|
||||
to the display.
|
||||
* `wait` Asynchronous. No args. Pause until the display refresh is complete.
|
||||
### 5.1.3 Events
|
||||
|
||||
### 5.1.3 EPD public bound variables
|
||||
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).
|
||||
* `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
|
||||
`ssd.refresh()`.
|
||||
EPD.
|
||||
|
||||
### 5.1.4 Public bound variables
|
||||
|
||||
* `height` Integer. Height in pixels. Treat as read-only.
|
||||
* `width` Integer. Width in pixels. Treat as read-only.
|
||||
|
@ -1063,7 +1076,11 @@ see below.
|
|||
seconds to enable viewing. This enables generic nanogui demos to be run on an
|
||||
EPD.
|
||||
|
||||
### 5.1.4 FeatherWing wiring
|
||||
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.
|
||||
|
||||
### 5.1.5 FeatherWing wiring
|
||||
|
||||
The [pinout is listed here](https://learn.adafruit.com/adafruit-eink-display-breakouts/pinouts-2).
|
||||
The `busy` line is brought out to a labelled pad on the PCB. It can be linked
|
||||
|
@ -1096,7 +1113,7 @@ The FeatherWing has a reset button which shorts the RST line to Gnd. To avoid
|
|||
risk of damage to the microcontroller pin if the button is pressed, the pin
|
||||
should be configured as open drain.
|
||||
|
||||
### 5.1.5 Micropower use
|
||||
### 5.1.6 Micropower use
|
||||
|
||||
Developers of micropower applications will need to familiarise themselves with
|
||||
the power saving features of their board. Information may be found in
|
||||
|
@ -1210,12 +1227,14 @@ 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`
|
||||
* `asyn=False` Setting this `True` invokes an asynchronous mode. See
|
||||
[EPD Asynchronous support](./DRIVERS.md#6-epd-asynchronous-support).
|
||||
|
||||
### 5.2.2 EPD public methods
|
||||
|
||||
##### Synchronous methods
|
||||
* `init` No args. Issues a hardware reset and initialises the hardware. This
|
||||
All methods are synchronous.
|
||||
|
||||
* `init` No args. Issues a hardware reset and initialises the hardware. This
|
||||
is called by the constructor. It needs to explicitly be called to exit from a
|
||||
deep sleep.
|
||||
* `sleep` No args. Puts the display into deep sleep. If called while a refresh
|
||||
|
@ -1225,12 +1244,17 @@ Pins 26-40 unused and omitted.
|
|||
a period: `ready` status should be checked before issuing `refresh`.
|
||||
* `wait_until_ready` No args. Pause until the device is ready.
|
||||
|
||||
##### Asynchronous methods
|
||||
* `updated` Asynchronous. No args. Pause until the framebuffer has been copied
|
||||
to the display.
|
||||
* `wait` Asynchronous. No args. Pause until the display refresh is complete.
|
||||
### 5.2.3 Events
|
||||
|
||||
### 5.2.3 EPD public bound variables
|
||||
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).
|
||||
* `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
|
||||
`ssd.refresh()`.
|
||||
|
||||
### 5.2.4 Public bound variables
|
||||
|
||||
* `height` Integer. Height in pixels. Treat as read-only.
|
||||
* `width` Integer. Width in pixels. Treat as read-only.
|
||||
|
@ -1239,6 +1263,10 @@ Pins 26-40 unused and omitted.
|
|||
seconds to enable viewing. This enables generic nanogui demos to be run on an
|
||||
EPD.
|
||||
|
||||
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.
|
||||
|
||||
## 5.3 Waveshare 400x300 Pi Pico display
|
||||
|
||||
The driver for this display now supports partial updates.
|
||||
|
@ -1255,6 +1283,8 @@ gc.collect() # Precaution before instantiating framebuf.
|
|||
ssd = SSD() # Create a display instance. For normal applications.
|
||||
# ssd = SSD(asyn=True) # Alternative for asynchronous applications.
|
||||
```
|
||||
### 5.3.1 Constructor args
|
||||
|
||||
For other hosts the pins need to be specified in `color_setup.py` via the
|
||||
following constructor args:
|
||||
|
||||
|
@ -1266,7 +1296,9 @@ following constructor args:
|
|||
* `asyn=False` Set `True` for asynchronous applications. Leave `False` for
|
||||
microgui where the arg has no effect.
|
||||
|
||||
##### Synchronous methods
|
||||
### 5.3.2 Public methods
|
||||
|
||||
All methods are synchronous.
|
||||
|
||||
* `init` No args. Issues a hardware reset and initialises the hardware. This
|
||||
is called by the constructor. It needs to explicitly be called to exit from a
|
||||
|
@ -1280,22 +1312,37 @@ following constructor args:
|
|||
* `set_partial()` Enable partial updates.
|
||||
* `set_full()` Restore normal update operation.
|
||||
|
||||
After issuing `set_partial()`, subsequent updates will be partial. Normal
|
||||
After issuing `set_partial()`, subsequent updates will be partial. Normal
|
||||
updates are restored by issuing `set_full()`. These methods should not be
|
||||
issued while an update is in progress.
|
||||
|
||||
Partial updates are fast and visually unobtrusive but they are prone to
|
||||
ghosting.
|
||||
|
||||
##### Asynchronous methods
|
||||
### 5.3.3 Events
|
||||
|
||||
* `wait` No args. If an update is in progress, pause until the display refresh
|
||||
is complete, otherwise return is immediate.
|
||||
* `updated` No args. Pause until the framebuffer has been copied to the
|
||||
display. It is now safe to modify the framebuf, but display update may still
|
||||
be in progress.
|
||||
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).
|
||||
* `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
|
||||
`ssd.refresh()`.
|
||||
|
||||
###### [Contents](./DRIVERS.md#contents)
|
||||
### 5.3.4 Public bound variables
|
||||
|
||||
* `height` Integer. Height in pixels. Treat as read-only.
|
||||
* `width` Integer. Width in pixels. Treat as read-only.
|
||||
* `demo_mode=False` Boolean. If set `True` after instantiating, `refresh()`
|
||||
will block until display update is complete, and then for a further two
|
||||
seconds to enable viewing. This enables generic nanogui demos to be run on an
|
||||
EPD.
|
||||
|
||||
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.
|
||||
|
||||
###### [Contents](./DRIVERS.md#contents)
|
||||
|
||||
# 6. EPD Asynchronous support
|
||||
|
||||
|
@ -1303,9 +1350,9 @@ 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`. In the default case an EPD can be used like any other display.
|
||||
`asyn=True`.
|
||||
|
||||
When GUI code issues
|
||||
When synchronous code issues
|
||||
```python
|
||||
refresh(ssd) # Several seconds on an EPD
|
||||
```
|
||||
|
@ -1313,45 +1360,48 @@ the GUI updates the frame buffer contents and calls the device driver's `show`
|
|||
method. This causes the contents to be copied to the display hardware and a
|
||||
redraw to be inititated. This typically takes several seconds unless partial
|
||||
updates are enabled. The method (and hence `refresh`) blocks until the physical
|
||||
refresh is complete. The device drivers block for an additional 2 seconds: this
|
||||
enables demos written for normal displays to work (the 2 second pause allowing
|
||||
the result of each refresh to be seen).
|
||||
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. With `asyn=True`
|
||||
synchronous applications will not work: it is necessary to take control of the
|
||||
sequencing of refresh.
|
||||
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:
|
||||
|
||||
In this case user code should ensure that changes to the framebuffer are
|
||||
postponed until the buffer contents have been copied to the display. Further, a
|
||||
subsequent refresh should be postponed until the physical refresh is complete.
|
||||
To achieve this the `ssd` instance has the following methods:
|
||||
* `.updated()` (async) Pauses until the buffer is copied to the device.
|
||||
* `.wait()` (async) Pauses until physical refresh is complete.
|
||||
* `.ready()` (synchronous) Immediate return: `True` if physical refresh is
|
||||
complete.
|
||||
|
||||
If `.refresh()` is issued before the physical display refresh is complete a
|
||||
`RuntimeError` will occur.
|
||||
|
||||
The following illustrates the kind of approach which may be used with a display
|
||||
instantiated with `asyn=True`:
|
||||
```python
|
||||
async def run():
|
||||
while True:
|
||||
# Before refresh, ensure that a previous refresh is complete
|
||||
# Not strictly necessary if .updated() used after refresh.
|
||||
await ssd.wait()
|
||||
refresh(ssd) # Immediate return. Creates a task to copy content to EPD.
|
||||
# Wait until the framebuf content has been passed to EPD.
|
||||
await ssd.updated()
|
||||
# Trigger an event which allows other tasks to update the
|
||||
# framebuffer in background
|
||||
evt.set() # Waiting task must clear the Event
|
||||
await asyncio.sleep(180) #
|
||||
# get data
|
||||
# Update screen widgets
|
||||
ssd.refresh() # Launches background refresh
|
||||
await asyncio.sleep(60)
|
||||
```
|
||||
With `asyn=True` 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
|
||||
application has two `Event` instances, one requesting refresh and the other
|
||||
requesting widget updates:
|
||||
```python
|
||||
async def refresh_task():
|
||||
while True:
|
||||
await refresh_request.wait() # Another task has requested refresh
|
||||
refresh_request.clear()
|
||||
ssd.refresh() # Launch background refresh
|
||||
await ssd.updated.wait() # Wait until framebuf copied to device
|
||||
data_request.set() # Ask other tasks to update widgets
|
||||
await ssd.complete.wait()
|
||||
# Now safe to respond to refresh_request and issue ssd.refresh()
|
||||
```
|
||||
The `updated` and `complete` events are cleared when `ssd.refresh` is called
|
||||
and are set as the background refresh proceeds.
|
||||
|
||||
Some displays support partial updates. This is currently restricted to the
|
||||
[Pico Epaper 4.2"](https://www.waveshare.com/pico-epaper-4.2.htm). Partial
|
||||
updates are much faster and are visually non-intrusive at a cost of "ghosting"
|
||||
|
@ -1363,7 +1413,7 @@ synchronous methods are provided:
|
|||
These must not be issued while an update is in progress.
|
||||
|
||||
See the demo `eclock_async.py` for an example of managing partial updates: once
|
||||
per hour a full update is performed.
|
||||
per hour (on the half-hour) a full update is performed.
|
||||
|
||||
###### [Contents](./DRIVERS.md#contents)
|
||||
|
||||
|
|
|
@ -32,7 +32,8 @@ class EPD(framebuf.FrameBuffer):
|
|||
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.updated = asyncio.Event()
|
||||
self.complete = asyncio.Event()
|
||||
# Dimensions in pixels. Waveshare code is portrait mode.
|
||||
# Public bound variables required by nanogui.
|
||||
self.width = 264 if landscape else 176
|
||||
|
@ -130,15 +131,6 @@ class EPD(framebuf.FrameBuffer):
|
|||
dt = ticks_diff(ticks_ms(), t)
|
||||
print('wait_until_ready {}ms {:5.1f}mins'.format(dt, dt/60_000))
|
||||
|
||||
async def wait(self):
|
||||
await asyncio.sleep_ms(0) # Ensure tasks run that might make it unready
|
||||
while not self.ready():
|
||||
await asyncio.sleep_ms(100)
|
||||
|
||||
# Pause until framebuf has been copied to device.
|
||||
async def updated(self):
|
||||
await self._updated.wait()
|
||||
|
||||
# For polling in asynchronous code. Just checks pin state.
|
||||
# 0 == busy. Comment in official code is wrong. Code is correct.
|
||||
def ready(self):
|
||||
|
@ -196,13 +188,13 @@ class EPD(framebuf.FrameBuffer):
|
|||
await asyncio.sleep_ms(0)
|
||||
t = ticks_ms()
|
||||
|
||||
self._updated.set() # framebuf has now been copied to the device
|
||||
self._updated.clear()
|
||||
self.updated.set() # framebuf has now been copied to the device
|
||||
cmd(b'\x12') # DISPLAY_REFRESH
|
||||
await asyncio.sleep(1)
|
||||
while self._busy() == 0:
|
||||
await asyncio.sleep_ms(200) # Don't release lock until update is complete
|
||||
self._as_busy = False
|
||||
self.complete.set()
|
||||
|
||||
# draw the current frame memory. Blocking time ~180ms
|
||||
def show(self, buf1=bytearray(1)):
|
||||
|
@ -210,6 +202,8 @@ class EPD(framebuf.FrameBuffer):
|
|||
if self._as_busy:
|
||||
raise RuntimeError('Cannot refresh: display is busy.')
|
||||
self._as_busy = True
|
||||
self.updated.clear()
|
||||
self.complete.clear()
|
||||
asyncio.create_task(self._as_show())
|
||||
return
|
||||
t = ticks_us()
|
||||
|
|
|
@ -42,7 +42,8 @@ class EPD(framebuf.FrameBuffer):
|
|||
# ._as_busy is set immediately on start of task. Cleared
|
||||
# when busy pin is logically false (physically 1).
|
||||
self._as_busy = False
|
||||
self._updated = asyncio.Event()
|
||||
self.updated = asyncio.Event()
|
||||
self.complete = asyncio.Event()
|
||||
# Public bound variables required by nanogui.
|
||||
# Dimensions in pixels as seen by nanogui (landscape mode).
|
||||
self.width = 296 if landscape else 128
|
||||
|
@ -114,16 +115,6 @@ class EPD(framebuf.FrameBuffer):
|
|||
while not self.ready():
|
||||
sleep_ms(100)
|
||||
|
||||
# Asynchronous wait on ready state. Pause (4.9s) for physical refresh.
|
||||
async def wait(self):
|
||||
await asyncio.sleep_ms(0) # Ensure tasks run that might make it unready
|
||||
while not self.ready():
|
||||
await asyncio.sleep_ms(100)
|
||||
|
||||
# Pause until framebuf has been copied to device.
|
||||
async def updated(self):
|
||||
await self._updated.wait()
|
||||
|
||||
# Return immediate status. Pin state: 0 == busy.
|
||||
def ready(self):
|
||||
return not(self._as_busy or (self._busy() == 0))
|
||||
|
@ -162,8 +153,7 @@ class EPD(framebuf.FrameBuffer):
|
|||
t = ticks_ms()
|
||||
|
||||
cmd(b'\x11') # Data stop
|
||||
self._updated.set()
|
||||
self._updated.clear()
|
||||
self.updated.set()
|
||||
sleep_us(20) # Allow for data coming back: currently ignore this
|
||||
cmd(b'\x12') # DISPLAY_REFRESH
|
||||
# busy goes low now, for ~4.9 seconds.
|
||||
|
@ -171,6 +161,7 @@ class EPD(framebuf.FrameBuffer):
|
|||
while self._busy() == 0:
|
||||
await asyncio.sleep_ms(200)
|
||||
self._as_busy = False
|
||||
self.complete.set()
|
||||
|
||||
# draw the current frame memory.
|
||||
def show(self, buf1=bytearray(1)):
|
||||
|
@ -178,6 +169,8 @@ class EPD(framebuf.FrameBuffer):
|
|||
if self._as_busy:
|
||||
raise RuntimeError('Cannot refresh: display is busy.')
|
||||
self._as_busy = True # Immediate busy flag. Pin goes low much later.
|
||||
self.updated.clear()
|
||||
self.complete.clear()
|
||||
asyncio.create_task(self._as_show())
|
||||
return
|
||||
|
||||
|
|
|
@ -120,10 +120,17 @@ class EPD(framebuf.FrameBuffer):
|
|||
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.updated = asyncio.Event()
|
||||
self.complete = asyncio.Event()
|
||||
|
||||
# Public bound variables required by nanogui.
|
||||
# Dimensions in pixels as seen by nanogui
|
||||
self.width = _EPD_WIDTH
|
||||
self.height = _EPD_HEIGHT
|
||||
# Other public bound variable.
|
||||
# Special mode enables demos written for generic displays to run.
|
||||
self.demo_mode = False
|
||||
|
||||
self.buf = bytearray(_EPD_HEIGHT * _BWIDTH)
|
||||
self.mvb = memoryview(self.buf)
|
||||
self.ibuf = bytearray(1000) # Buffer for inverted pixels
|
||||
|
@ -241,16 +248,6 @@ class EPD(framebuf.FrameBuffer):
|
|||
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):
|
||||
|
@ -280,11 +277,12 @@ class EPD(framebuf.FrameBuffer):
|
|||
nbytes = min(nbytes, nleft)
|
||||
if not ((npass := npass + 1) % 16):
|
||||
await asyncio.sleep_ms(0) # Control blocking time
|
||||
self._updated.set()
|
||||
self.updated.set()
|
||||
self.send_command(b"\x12") # Nonblocking .display_on()
|
||||
while not self.busy_pin(): # Wait on display hardware
|
||||
await asyncio.sleep_ms(0)
|
||||
self._busy = False
|
||||
self.complete.set()
|
||||
|
||||
async def do_refresh(self, split): # For micro-gui
|
||||
assert (not self._busy), "Refresh while busy"
|
||||
|
@ -295,6 +293,8 @@ class EPD(framebuf.FrameBuffer):
|
|||
raise RuntimeError('Cannot refresh: display is busy.')
|
||||
self._busy = True # Immediate busy flag. Pin goes low much later.
|
||||
if self._asyn:
|
||||
self.updated.clear()
|
||||
self.complete.clear()
|
||||
asyncio.create_task(self._as_show())
|
||||
return
|
||||
self.send_command(b"\x13")
|
||||
|
@ -308,6 +308,10 @@ class EPD(framebuf.FrameBuffer):
|
|||
nbytes = min(nbytes, nleft)
|
||||
self._busy = False
|
||||
self.display_on()
|
||||
if not self.demo_mode:
|
||||
# Immediate return to avoid blocking the whole application.
|
||||
# User should wait for ready before calling refresh()
|
||||
return
|
||||
self.wait_until_ready()
|
||||
time.sleep_ms(2000) # Give time for user to see result
|
||||
|
||||
|
|
|
@ -31,12 +31,12 @@ async def test():
|
|||
wri.set_clip(True, True, False) # Clip to screen, no wrap
|
||||
refresh(ssd, True)
|
||||
if epaper:
|
||||
await ssd.wait()
|
||||
await ssd.complete.wait()
|
||||
ec = EClock(wri, 10, 10, 200, fgcolor=WHITE, bgcolor=BLACK)
|
||||
ec.value(t := time.localtime()) # Initial drawing
|
||||
refresh(ssd)
|
||||
if epaper:
|
||||
await ssd.wait()
|
||||
await ssd.complete.wait()
|
||||
mins = t[4]
|
||||
|
||||
while True:
|
||||
|
@ -51,7 +51,7 @@ async def test():
|
|||
ec.value(t)
|
||||
refresh(ssd)
|
||||
if epaper:
|
||||
await ssd.wait()
|
||||
await ssd.complete.wait()
|
||||
await asyncio.sleep(10)
|
||||
|
||||
try:
|
||||
|
|
Ładowanie…
Reference in New Issue