kopia lustrzana https://github.com/peterhinch/micropython-micro-gui
ePaper optimisations.
rodzic
e510739daf
commit
1424c06bb6
|
@ -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():
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Ładowanie…
Reference in New Issue