kopia lustrzana https://github.com/peterhinch/micropython-nano-gui
Minor changes to ePaper files and docs.
rodzic
35e1a6b1b2
commit
4108aa32a4
30
DRIVERS.md
30
DRIVERS.md
|
@ -34,7 +34,7 @@ a bare minimum of functionality required to support the above.
|
||||||
6.4.1 [Micropower applications](./DRIVERS.md#641-micropower-applications)
|
6.4.1 [Micropower applications](./DRIVERS.md#641-micropower-applications)
|
||||||
6.5 [Resources](./DRIVERS.md#65-resources)
|
6.5 [Resources](./DRIVERS.md#65-resources)
|
||||||
7. [ePaper displays](./DRIVERS.md#7-epaper-displays)
|
7. [ePaper displays](./DRIVERS.md#7-epaper-displays)
|
||||||
7.1 [Adafruit flexible eInk Display](./DRIVERS.md#71-adafruit-flexible-eink-display)
|
7.1 [Adafruit monochrome eInk Displays](./DRIVERS.md#71-adafruit-monochrome-eink-displays)
|
||||||
7.1.1 [EPD constructor args](./DRIVERS.md#711-epd-constructor-args)
|
7.1.1 [EPD constructor args](./DRIVERS.md#711-epd-constructor-args)
|
||||||
7.1.2 [EPD public methods](./DRIVERS.md#712-epd-public-methods)
|
7.1.2 [EPD public methods](./DRIVERS.md#712-epd-public-methods)
|
||||||
7.1.3 [EPD public bound variables](./DRIVERS.md#713-epd-public-bound-variables)
|
7.1.3 [EPD public bound variables](./DRIVERS.md#713-epd-public-bound-variables)
|
||||||
|
@ -538,9 +538,9 @@ more - which may be problematic for applications which need to respond to
|
||||||
external events. A specific asynchronous mode provides support for reducing
|
external events. A specific asynchronous mode provides support for reducing
|
||||||
blocking time. See [EPD Asynchronous support](./DRIVERS.md#8-epd-asynchronous-support).
|
blocking time. See [EPD Asynchronous support](./DRIVERS.md#8-epd-asynchronous-support).
|
||||||
|
|
||||||
## 7.1 Adafruit flexible eInk Display
|
## 7.1 Adafruit monochrome eInk Displays
|
||||||
|
|
||||||
The driver assumes an Adafruit 2.9 inch 296*128 pixel flexible
|
The driver supports two Adafruit 2.9 inch 296*128 pixel units. A flexible
|
||||||
[display](https://www.adafruit.com/product/4262) interfaced via their
|
[display](https://www.adafruit.com/product/4262) interfaced via their
|
||||||
[interface breakout](https://www.adafruit.com/product/4224).
|
[interface breakout](https://www.adafruit.com/product/4224).
|
||||||
|
|
||||||
|
@ -548,28 +548,32 @@ An alternative is the
|
||||||
[Adafruit 2.9" eInk FeatherWing](https://www.adafruit.com/product/4777) with
|
[Adafruit 2.9" eInk FeatherWing](https://www.adafruit.com/product/4777) with
|
||||||
[wiring details](./DRIVERS.md#714-featherwing-wiring) listed below.
|
[wiring details](./DRIVERS.md#714-featherwing-wiring) listed below.
|
||||||
|
|
||||||
These alternatives behave identically except that the FeatherWing shows a black
|
In my testing there are differences between these alternatives. The FeatherWing
|
||||||
border around the display. The reason for this is
|
shows a black border around the display. The reason for this is
|
||||||
[unclear](https://github.com/adafruit/Adafruit_CircuitPython_IL0373/issues/11#issuecomment-763704622).
|
[unclear](https://github.com/adafruit/Adafruit_CircuitPython_IL0373/issues/11#issuecomment-763704622).
|
||||||
|
Secondly, while the FeatherWing behaves as expected the image on the flexible
|
||||||
|
display gradually degrades if the display is powered down. The white background
|
||||||
|
becomes speckled over a period of a few minutes.
|
||||||
|
|
||||||
The breakout has an `ENA` pin which enables the display to be powered down.
|
The interface breakout for the flexible display has an `ENA` pin which enables
|
||||||
This facilitates micropower applications: the host shuts down the display
|
the display to be powered down. This facilitates micropower applications: the
|
||||||
before going into deep sleep.
|
host shuts down the display before itself going into deep sleep.
|
||||||
|
|
||||||
The driver is cross platform and supports landscape or portrait mode. To keep
|
The driver is cross platform and supports landscape or portrait mode. To keep
|
||||||
the buffer size down (to 4736 bytes) there is no greyscale support. It should
|
the buffer size down (to 4736 bytes) there is no greyscale support. It should
|
||||||
be noted that the Adafruit site cautions against refreshing these displays more
|
be noted that the Adafruit site cautions against refreshing the flexible
|
||||||
frequently than every 180s. It is
|
displays more frequently than every 180s. This warning does not appear on the
|
||||||
|
FeatherWing pages. No reason for the warning is given and it is
|
||||||
[unclear](https://forums.adafruit.com/viewtopic.php?f=19&t=174091) if this is
|
[unclear](https://forums.adafruit.com/viewtopic.php?f=19&t=174091) if this is
|
||||||
an absolute limit or an average rate.
|
an absolute limit or an average rate.
|
||||||
|
|
||||||
##### Wiring
|
##### Wiring
|
||||||
|
|
||||||
The [interface schematic is here](https://learn.adafruit.com/assets/86038). The
|
The [interface schematic is here](https://learn.adafruit.com/assets/86038). The
|
||||||
drawing title is confusing but I balieve this is the correct schematic.
|
drawing title is confusing but I believe this is the correct schematic.
|
||||||
|
|
||||||
The following assumes a Pyboard host. Pyboard pin numbers are based on hardware
|
The following assumes a Pyboard host. Pyboard pin numbers are based on hardware
|
||||||
SPI 2 and my arbitrary choice of GPIO. All may be changed and soft SPI may be
|
SPI 2 and an arbitrary choice of GPIO. All may be changed and soft SPI may be
|
||||||
used.
|
used.
|
||||||
|
|
||||||
| Pyb | Breakout |
|
| Pyb | Breakout |
|
||||||
|
@ -677,7 +681,7 @@ This 2.7" 176*274 display is designed for the Raspberry Pi and is detailed
|
||||||
I bought two of these units from different sources. Both have hardware issues
|
I bought two of these units from different sources. Both have hardware issues
|
||||||
discussed [here](https://forum.micropython.org/viewtopic.php?f=2&t=9564). I
|
discussed [here](https://forum.micropython.org/viewtopic.php?f=2&t=9564). I
|
||||||
have failed to achieve consistent behaviour. Units behave perfectly one day and
|
have failed to achieve consistent behaviour. Units behave perfectly one day and
|
||||||
fail the next. I published this driver on the assumption that I was sold
|
fail the next. I published this driver on the assumption that I was twice sold
|
||||||
dubious Chinese clones and that genuine ones would be reliable.
|
dubious Chinese clones and that genuine ones would be reliable.
|
||||||
|
|
||||||
The driver is cross-platform.
|
The driver is cross-platform.
|
||||||
|
|
4
FPLOT.md
4
FPLOT.md
|
@ -45,7 +45,7 @@ two varying vectors.
|
||||||
4.2.1 [Scaling](./FPLOT.md#421-scaling) Required scaling of complex points.
|
4.2.1 [Scaling](./FPLOT.md#421-scaling) Required scaling of complex points.
|
||||||
4.3 [class TSequence](./FPLOT.md#43-class-tsequence) Plot Y values on time axis.
|
4.3 [class TSequence](./FPLOT.md#43-class-tsequence) Plot Y values on time axis.
|
||||||
|
|
||||||
###### [Main README](../README.md)
|
###### [Main README](./README.md)
|
||||||
|
|
||||||
# 1. Python files
|
# 1. Python files
|
||||||
|
|
||||||
|
@ -170,7 +170,7 @@ The Cartesian curve constructor takes the following positional arguments:
|
||||||
|
|
||||||
Mandatory arguments:
|
Mandatory arguments:
|
||||||
1. `graph` The `CartesianGraph` instance.
|
1. `graph` The `CartesianGraph` instance.
|
||||||
2. `color`
|
2. `color` If `None` is passed, the `graph` foreground color is used.
|
||||||
|
|
||||||
Optional arguments:
|
Optional arguments:
|
||||||
3. `populate=None` A generator to populate the curve. See below.
|
3. `populate=None` A generator to populate the curve. See below.
|
||||||
|
|
|
@ -33,6 +33,9 @@ floats as the notionally very long scale moves behind its small window.
|
||||||
![Image](images/textbox1.JPG) The Textbox widget for scrolling text with word
|
![Image](images/textbox1.JPG) The Textbox widget for scrolling text with word
|
||||||
wrap or clipping.
|
wrap or clipping.
|
||||||
|
|
||||||
|
![Image](images/seismo.JPG) A mockup of a seismograph screen on an ePaper
|
||||||
|
display.
|
||||||
|
|
||||||
Notes on [Adafruit and other OLED displays](./ADAFRUIT.md) including
|
Notes on [Adafruit and other OLED displays](./ADAFRUIT.md) including
|
||||||
wiring details, pin names and hardware issues.
|
wiring details, pin names and hardware issues.
|
||||||
|
|
||||||
|
@ -258,7 +261,8 @@ Demos for larger displays.
|
||||||
|
|
||||||
Demos for ePaper displays:
|
Demos for ePaper displays:
|
||||||
* `waveshare_test.py` For the Waveshare eInk Display HAT 2.7" 176*274 display.
|
* `waveshare_test.py` For the Waveshare eInk Display HAT 2.7" 176*274 display.
|
||||||
* `epd29_test.py` Demo for Adafruit 2.9" eInk display.
|
* `epd29_sync.py` Demo for Adafruit 2.9" eInk display: emulates a seismograph.
|
||||||
|
* `epd29_async.py` Asynchronous demo for Adafruit 2.9" eInk display.
|
||||||
|
|
||||||
Demos for Sharp displays:
|
Demos for Sharp displays:
|
||||||
* `sharptest.py` Basic functionality check.
|
* `sharptest.py` Basic functionality check.
|
||||||
|
@ -311,7 +315,8 @@ copied to the hardware root as `color_setup.py`. Example files:
|
||||||
[Adafruit 1.44 inch TFT display](https://www.adafruit.com/product/2088).
|
[Adafruit 1.44 inch TFT display](https://www.adafruit.com/product/2088).
|
||||||
* `ili9341_setup.py` A 240*320 ILI9341 display on ESP32.
|
* `ili9341_setup.py` A 240*320 ILI9341 display on ESP32.
|
||||||
* `waveshare_setup.py` 176*274 ePaper display.
|
* `waveshare_setup.py` 176*274 ePaper display.
|
||||||
* `epd96_asyn.py` Adafruit 2.9 inch ePaper display, optimised for `uasyncio`.
|
* `epd29_sync.py` Adafruit 2.9 inch ePaper display for synchronous code.
|
||||||
|
* `epd29_async.py` Adafruit 2.9 inch ePaper display: `uasyncio` applications.
|
||||||
|
|
||||||
## 2.2 Dependencies
|
## 2.2 Dependencies
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# epd96_asyn.py Config for asynchronous applications on 2.9" ePaper.
|
# epd29_async.py Config for asynchronous applications on 2.9" ePaper.
|
||||||
# Customise for your hardware config
|
# Customise for your hardware config.
|
||||||
|
|
||||||
# Released under the MIT License (MIT). See LICENSE.
|
# Released under the MIT License (MIT). See LICENSE.
|
||||||
# Copyright (c) 2020 Peter Hinch
|
# Copyright (c) 2020 Peter Hinch
|
|
@ -1,7 +1,5 @@
|
||||||
# epd96_demo.py Allow standard demos to run on ePaper.
|
# epd29_sync.py Config for synchronous applications on 2.9" ePaper.
|
||||||
# Customise for your hardware config.
|
# Customise for your hardware config
|
||||||
# Beware of running demos for long as they refresh the display more frequently
|
|
||||||
# than is advised by Adafruit.
|
|
||||||
|
|
||||||
# Released under the MIT License (MIT). See LICENSE.
|
# Released under the MIT License (MIT). See LICENSE.
|
||||||
# Copyright (c) 2020 Peter Hinch
|
# Copyright (c) 2020 Peter Hinch
|
||||||
|
@ -41,4 +39,4 @@ pbusy = machine.Pin('Y4', machine.Pin.IN)
|
||||||
spi = machine.SPI(2, baudrate=5_000_000)
|
spi = machine.SPI(2, baudrate=5_000_000)
|
||||||
gc.collect() # Precaution before instantiating framebuf
|
gc.collect() # Precaution before instantiating framebuf
|
||||||
ssd = SSD(spi, pcs, pdc, prst, pbusy) # Create a display instance
|
ssd = SSD(spi, pcs, pdc, prst, pbusy) # Create a display instance
|
||||||
ssd.demo_mode = True
|
# ssd.demo_mode = True
|
|
@ -58,7 +58,7 @@ class Curve():
|
||||||
self.graph = graph
|
self.graph = graph
|
||||||
self.origin = origin
|
self.origin = origin
|
||||||
self.excursion = excursion
|
self.excursion = excursion
|
||||||
self.color = color
|
self.color = color if color is not None else graph.fgcolor
|
||||||
self.lastpoint = None
|
self.lastpoint = None
|
||||||
self.newpoint = None
|
self.newpoint = None
|
||||||
if populate is not None and self._valid(populate):
|
if populate is not None and self._valid(populate):
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
# epd29_test.py Demo program for nano_gui on an Adafruit 2.9" flexible ePaper screen
|
# epd29_async.py Demo program for nano_gui on an Adafruit 2.9" flexible ePaper screen
|
||||||
|
|
||||||
# Released under the MIT License (MIT). See LICENSE.
|
# Released under the MIT License (MIT). See LICENSE.
|
||||||
# Copyright (c) 2020 Peter Hinch
|
# Copyright (c) 2020 Peter Hinch
|
||||||
|
|
||||||
# color_setup must set landcsape True, asyn True and must not set demo_mode
|
# color_setup must set landcsape True, asyn True and must not set demo_mode
|
||||||
|
from cmath import exp, pi
|
||||||
import uasyncio as asyncio
|
import uasyncio as asyncio
|
||||||
from color_setup import ssd
|
from color_setup import ssd
|
||||||
# On a monochrome display Writer is more efficient than CWriter.
|
# On a monochrome display Writer is more efficient than CWriter.
|
||||||
|
@ -11,11 +12,13 @@ from gui.core.writer import Writer
|
||||||
from gui.core.nanogui import refresh
|
from gui.core.nanogui import refresh
|
||||||
from gui.widgets.meter import Meter
|
from gui.widgets.meter import Meter
|
||||||
from gui.widgets.label import Label
|
from gui.widgets.label import Label
|
||||||
|
from gui.widgets.dial import Dial, Pointer
|
||||||
|
|
||||||
# Fonts
|
# Fonts
|
||||||
import gui.fonts.arial10 as arial10
|
import gui.fonts.arial10 as arial10
|
||||||
import gui.fonts.font6 as small
|
import gui.fonts.font6 as small
|
||||||
|
|
||||||
|
ssd._asyn = True # HACK to make it config agnostic
|
||||||
# Some ports don't support uos.urandom.
|
# Some ports don't support uos.urandom.
|
||||||
# See https://github.com/peterhinch/micropython-samples/tree/master/random
|
# See https://github.com/peterhinch/micropython-samples/tree/master/random
|
||||||
def xorshift64star(modulo, seed = 0xf9ac6ba4):
|
def xorshift64star(modulo, seed = 0xf9ac6ba4):
|
||||||
|
@ -28,22 +31,21 @@ def xorshift64star(modulo, seed = 0xf9ac6ba4):
|
||||||
return (x * 0x2545F4914F6CDD1D) % modulo
|
return (x * 0x2545F4914F6CDD1D) % modulo
|
||||||
return func
|
return func
|
||||||
|
|
||||||
async def fields(evt):
|
async def compass(evt): # TODO why does this not get drawn on 1st pass?
|
||||||
wri = Writer(ssd, small, verbose=False)
|
wri = Writer(ssd, arial10, verbose=False)
|
||||||
wri.set_clip(False, False, False)
|
wri.set_clip(False, False, False)
|
||||||
textfield = Label(wri, 0, 2, wri.stringlen('longer'))
|
v1 = 0 + 0.9j
|
||||||
numfield = Label(wri, 25, 2, wri.stringlen('99.990'), bdcolor=None)
|
v2 = exp(0 - (pi / 6) * 1j)
|
||||||
countfield = Label(wri, 0, 60, wri.stringlen('1'))
|
dial = Dial(wri, 5, 5, height = 75, ticks = 12, bdcolor=None,
|
||||||
n = 1
|
label='Direction', style = Dial.COMPASS)
|
||||||
random = xorshift64star(65535)
|
ptr = Pointer(dial)
|
||||||
while True:
|
while True:
|
||||||
for s in ('short', 'longer', '1', ''):
|
ptr.value(v1)
|
||||||
textfield.value(s)
|
v1 *= v2
|
||||||
numfield.value('{:5.2f}'.format(random() /1000))
|
# await asyncio.sleep_ms(100)
|
||||||
countfield.value('{:1d}'.format(n))
|
|
||||||
n += 1
|
|
||||||
await evt.wait()
|
await evt.wait()
|
||||||
|
|
||||||
|
|
||||||
async def multi_fields(evt):
|
async def multi_fields(evt):
|
||||||
wri = Writer(ssd, small, verbose=False)
|
wri = Writer(ssd, small, verbose=False)
|
||||||
wri.set_clip(False, False, False)
|
wri.set_clip(False, False, False)
|
||||||
|
@ -68,15 +70,16 @@ async def multi_fields(evt):
|
||||||
|
|
||||||
async def meter(evt):
|
async def meter(evt):
|
||||||
wri = Writer(ssd, arial10, verbose=False)
|
wri = Writer(ssd, arial10, verbose=False)
|
||||||
|
wri.set_clip(False, False, False)
|
||||||
row = 10
|
row = 10
|
||||||
col = 150
|
col = 170
|
||||||
args = {'height' : 80,
|
args = {'height' : 80,
|
||||||
'width' : 15,
|
'width' : 15,
|
||||||
'divisions' : 4,
|
'divisions' : 4,
|
||||||
'style' : Meter.BAR}
|
'style' : Meter.BAR}
|
||||||
m0 = Meter(wri, row, col, legends=('0.0', '0.5', '1.0'), **args)
|
m0 = Meter(wri, row, col, legends=('0.0', '0.5', '1.0'), **args)
|
||||||
m1 = Meter(wri, row, col + 50, legends=('-1', '0', '+1'), **args)
|
m1 = Meter(wri, row, col + 40, legends=('-1', '0', '+1'), **args)
|
||||||
m2 = Meter(wri, row, col + 100, legends=('-1', '0', '+1'), **args)
|
m2 = Meter(wri, row, col + 80, legends=('-1', '0', '+1'), **args)
|
||||||
random = xorshift64star(2**24 - 1)
|
random = xorshift64star(2**24 - 1)
|
||||||
while True:
|
while True:
|
||||||
steps = 10
|
steps = 10
|
||||||
|
@ -93,7 +96,7 @@ async def main():
|
||||||
evt = asyncio.Event()
|
evt = asyncio.Event()
|
||||||
asyncio.create_task(meter(evt))
|
asyncio.create_task(meter(evt))
|
||||||
asyncio.create_task(multi_fields(evt))
|
asyncio.create_task(multi_fields(evt))
|
||||||
asyncio.create_task(fields(evt))
|
asyncio.create_task(compass(evt))
|
||||||
while True:
|
while True:
|
||||||
# Normal procedure before refresh, but 10s sleep should mean it always returns immediately
|
# Normal procedure before refresh, but 10s sleep should mean it always returns immediately
|
||||||
await ssd.wait()
|
await ssd.wait()
|
||||||
|
@ -103,7 +106,7 @@ async def main():
|
||||||
# framebuffer in background
|
# framebuffer in background
|
||||||
evt.set()
|
evt.set()
|
||||||
evt.clear()
|
evt.clear()
|
||||||
await asyncio.sleep(20) # Allow for slow refresh
|
await asyncio.sleep(10) # Allow for slow refresh
|
||||||
|
|
||||||
|
|
||||||
tstr = '''Test of asynchronous code updating the EPD. This should
|
tstr = '''Test of asynchronous code updating the EPD. This should
|
|
@ -0,0 +1,79 @@
|
||||||
|
# epd29_sync.py Demo of synchronous code on 2.9" EPD display
|
||||||
|
|
||||||
|
# Released under the MIT License (MIT). See LICENSE.
|
||||||
|
# Copyright (c) 2020 Peter Hinch
|
||||||
|
|
||||||
|
# color_setup must set landcsape True, asyn False and must not set demo_mode
|
||||||
|
|
||||||
|
from math import pi, sin
|
||||||
|
from color_setup import ssd
|
||||||
|
from gui.core.writer import Writer
|
||||||
|
from gui.core.nanogui import refresh
|
||||||
|
from gui.core.fplot import CartesianGraph, Curve
|
||||||
|
from gui.widgets.meter import Meter
|
||||||
|
from gui.widgets.label import Label
|
||||||
|
from gui.widgets.dial import Dial, Pointer
|
||||||
|
|
||||||
|
# Fonts
|
||||||
|
import gui.fonts.arial10 as arial10
|
||||||
|
import gui.fonts.freesans20 as large
|
||||||
|
|
||||||
|
wri = Writer(ssd, arial10, verbose=False)
|
||||||
|
wri.set_clip(False, False, False)
|
||||||
|
|
||||||
|
wri_large = Writer(ssd, large, verbose=False)
|
||||||
|
wri_large.set_clip(False, False, False)
|
||||||
|
|
||||||
|
# 296*128
|
||||||
|
def graph():
|
||||||
|
row, col, ht, wd = 5, 140, 75, 150
|
||||||
|
def populate():
|
||||||
|
x = -0.998
|
||||||
|
while x < 1.01:
|
||||||
|
z = 6 * pi * x
|
||||||
|
y = sin(z) / z
|
||||||
|
yield x, y
|
||||||
|
x += 0.05
|
||||||
|
|
||||||
|
g = CartesianGraph(wri, row, col, height = ht, width = wd, bdcolor=False)
|
||||||
|
curve2 = Curve(g, None, populate())
|
||||||
|
Label(wri, row + ht + 5, col - 10, '-2.0 t: secs')
|
||||||
|
Label(wri, row + ht + 5, col - 8 + int(wd//2), '0.0')
|
||||||
|
Label(wri, row + ht + 5, col - 10 + wd, '2.0')
|
||||||
|
|
||||||
|
def compass():
|
||||||
|
dial = Dial(wri, 5, 5, height = 75, ticks = 12, bdcolor=None,
|
||||||
|
label='Direction', style = Dial.COMPASS)
|
||||||
|
ptr = Pointer(dial)
|
||||||
|
ptr.value(1 + 1j)
|
||||||
|
|
||||||
|
def meter():
|
||||||
|
m = Meter(wri, 5, 100, height = 75, divisions = 4,
|
||||||
|
label='Peak', style=Meter.BAR, legends=('0', '50', '100'))
|
||||||
|
m.value(0.72)
|
||||||
|
|
||||||
|
def labels():
|
||||||
|
row = 100
|
||||||
|
col = 0
|
||||||
|
Label(wri_large, row, col, 'Seismograph')
|
||||||
|
col = 140
|
||||||
|
Label(wri, row, col + 0, 'Event time')
|
||||||
|
Label(wri, row, col + 60, '01:35', bdcolor=None)
|
||||||
|
Label(wri, row, col + 95, 'UTC')
|
||||||
|
row = 115
|
||||||
|
Label(wri, row, col + 0, 'Event date')
|
||||||
|
Label(wri, row, col + 60, '6th Jan 2021', bdcolor=None)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
refresh(ssd, True)
|
||||||
|
graph()
|
||||||
|
compass()
|
||||||
|
meter()
|
||||||
|
labels()
|
||||||
|
ssd.wait_until_ready()
|
||||||
|
refresh(ssd)
|
||||||
|
print('Waiting for display update')
|
||||||
|
ssd.wait_until_ready()
|
||||||
|
|
||||||
|
main()
|
||||||
|
|
Plik binarny nie jest wyświetlany.
Po Szerokość: | Wysokość: | Rozmiar: 24 KiB |
Ładowanie…
Reference in New Issue