Add EPD micropower demo and docs.

pull/8/head
Peter Hinch 2021-01-25 18:44:04 +00:00
rodzic 834e5da770
commit bfe679d169
3 zmienionych plików z 168 dodań i 13 usunięć

Wyświetl plik

@ -39,6 +39,7 @@ a bare minimum of functionality required to support the above.
     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.4 [FeatherWing Wiring](./DRIVERS.md#714-featherwing-wiring)
     7.1.5 [Micropower use](./DRIVERS.md#715-micropower-use)
7.2 [Waveshare eInk Display HAT](./DRIVERS.md#72-waveshare-eink-display-hat)
     7.2.1 [EPD constructor args](./DRIVERS.md#721-epd-constructor-args)
     7.2.2 [EPD public methods](./DRIVERS.md#722-epd-public-methods)
@ -46,6 +47,9 @@ a bare minimum of functionality required to support the above.
8. [EPD Asynchronous support](./DRIVERS.md#8-epd-asynchronous-support)
9. [Writing device drivers](./DRIVERS.md#9-writing-device-drivers)
The [Micropower use](./DRIVERS.md#715-micropower-use) section is applicable to
EPD's in general but makes specific reference to the 2.9" micropower demo.
###### [Main README](./README.md#1-introduction)
# 1. Introduction
@ -551,9 +555,10 @@ An alternative is the
In my testing there are differences between these alternatives. The FeatherWing
shows a black border around the display. The reason for this is
[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.
In development I encountered instances where the image on the flexible display
gradually degraded after the system was powered down. The white background
becomes speckled over a period of a few minutes. I'm unsure of the reason for
this. The `epd29_lowpower` demo did not exhibit this.
The interface breakout for the flexible display has an `ENA` pin which enables
the display to be powered down. This facilitates micropower applications: the
@ -628,16 +633,6 @@ see below.
seconds to enable viewing. This enables generic nanogui demos to be run on an
EPD.
##### Micropower use
To power down the breakout the `ENA` pin must be pulled to 0v. Some
microcontrollers can ensure that a GPIO pin is able to sink current when the
chip goes into deep sleep. In other cases the pin becomes high impedance. The
following ensures that a high impedance pin will cause `ENA` to be pulled low.
The N channel MOSFET must have a low threshold voltage.
![Image](images/epd_enable.png)
### 7.1.4 FeatherWing wiring
The [pinout is listed here](https://learn.adafruit.com/adafruit-eink-display-breakouts/pinouts-2).
@ -671,6 +666,50 @@ 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.
### 7.1.5 Micropower use
Developers of micropower applications will need to familiarise themselves with
the power saving features of their board. Information may be found in
[micropython-micropower](https://github.com/peterhinch/micropython-micropower).
Some information is generic, but the code is Pyboard specific. Pyboard users
should copy `upower.py` to the filesystem root. Further power savings may be
achieved by precompiling or freezing code as this avoids the energy used by the
compiler (on each wakeup). Users of other platforms will need to know how to
enter and exit from deep sleep.
I developed this using the breakout board linked to Wbus DIP28 adaptor and a
Pyboard D, powered from a LiPo cell. A Pyboard 1.1 could be used identically.
The test script `epd29_lowpower.py` requires `upower.py` as described above.
This simplifies access to the Pyboard RTC's alarms which can wake the board
from deep sleep. Wakeup from certain pins is also possible.
To power down the breakout the `ENA` pin must be pulled to 0v. Some
microcontrollers can ensure that a GPIO pin is able to sink current when the
chip goes into deep sleep. In other cases the pin becomes high impedance. The
following ensures that a high impedance pin will cause `ENA` to be pulled low.
The N channel MOSFET must have a low threshold voltage.
![Image](images/epd_enable.png)
An alternative, slightly less efficient approach, is to pull down `ENA` with
a 2.2KΩ resistor and link it to a GPIO pin. The breakout has a 100KΩ resistor
to Vin. The 2.2KΩ resistor causes the breakout and display to assume the power
off state if the GPIO pin is high impedance.
The test script `epd29_lowpower.py` assumes pin `Y5` linked to the breakout
enable. I used the 2.2KΩ resistor pull down. The code comments clarify the mode
of operation. The demo wakes every 30s. Real applications would do it much less
frequently with attendant power savings.
Users of other EPD's may want to develop other means of powering down the EPD.
A p-channel MOSFET could be considered as described
[here](https://github.com/peterhinch/micropython-micropower/blob/master/HARDWARE.md#hardware-issues).
In use I measured 500μA in the periods when the display is refreshing (a total
of 10s for each wakeup) and 58μA between wakeups. The Pyboard accounts for
about 6μA. 33μA will be used by the 100KΩ pullup on the breakout's power enable
line. I haven't attempted to figure out where the other 19μA is going.
###### [Contents](./DRIVERS.md#contents)
## 7.2 Waveshare eInk Display HAT

Wyświetl plik

@ -264,6 +264,9 @@ Demos for ePaper displays:
* `waveshare_test.py` For the Waveshare eInk Display HAT 2.7" 176*274 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.
* `epd29_lowpower.py` Micropower demo for Adafruit 2.9" eInk display. This doc
[Micropower use](./DRIVERS.md#715-micropower-use) should be read before
attempting to run this.
Demos for Sharp displays:
* `sharptest.py` Basic functionality check.

Wyświetl plik

@ -0,0 +1,113 @@
# 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
import upower
import machine
import pyb
pon = machine.Pin('Y5', machine.Pin.OUT_PP, value=1) # Power on before instantiating display
upower.lpdelay(1000) # Give the valves (tubes) time to warm up :)
from color_setup import ssd # Instantiate
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)
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)
# Populate the display - GUI and Writer code goes here
def populate():
graph()
compass()
meter()
labels()
# Initialise GUI clearing display. Populate frame buffer. Update diplay and
# leave in power down state ready for phsyical loss of power
def show():
# Low power version of .wait_until_ready()
def wait_ready():
while not ssd.ready():
upower.lpdelay(1000)
refresh(ssd, True) # Init and clear. busy will go True for ~5s
populate()
wait_ready() # wait for display ready (seconds)
refresh(ssd)
wait_ready()
ssd.sleep() # Put into "off" state
# Handle initial power up and subsequent wakeup.
rtc = pyb.RTC()
# If we have a backup battery clear down any setting from a previously running program
rtc.wakeup(None)
reason = machine.reset_cause() # Why have we woken?
red = pyb.LED(1)
if reason in (machine.PWRON_RESET, machine.HARD_RESET, machine.SOFT_RESET):
# Code to run when the application is first started
aa = upower.Alarm('a')
aa.timeset(second = 39)
ab = upower.Alarm('b')
ab.timeset(second = 9)
elif reason == machine.DEEPSLEEP_RESET:
# Display on. Pin is pulled down by 2K2 so hi-z turns display off.
red.on()
show()
pon(0) # Physically power down display
red.off()
pyb.standby()