kopia lustrzana https://github.com/peterhinch/micropython-nano-gui
Add ePaper support. Monochrome setup is now consistent with color.
rodzic
bfba0b71a6
commit
d92470cb45
11
ASYNC.md
11
ASYNC.md
|
@ -9,17 +9,22 @@ frame buffer on the host, transferring its entire contents to the display
|
|||
hardware, usually via I2C or SPI. Current drivers block for the time taken by
|
||||
this.
|
||||
|
||||
In the case of the Pyboard driver for Adafruit 1.5 and 1.27 inch displays,
|
||||
In the case of the Pyboard driver for Adafruit 1.5 and 1.27 inch OLED displays,
|
||||
running on a Pyboard 1.x, blocking is for 41ms. Blocking periods for monochrome
|
||||
or smaller colour dislays will be shorter. On hosts which don't support inline
|
||||
or smaller colour displays will be shorter. On hosts which don't support inline
|
||||
Arm Thumb assembler or the viper emitter it will be very much longer.
|
||||
|
||||
For large displays such as ePaper the blocking time is on the order of 250ms on
|
||||
a Pyboard, longer on hardware such as ESP32. Such drivers have a special `asyn`
|
||||
constructor arg which causes refresh to be performed by a coroutine; this
|
||||
periodically yields to the scheduler and limits blocking to around 30ms.
|
||||
|
||||
Blocking occurs when the `nanogui.refresh` function is called. In typical
|
||||
applications which might wait for user input from a switch this blocking is
|
||||
not apparent and the response appears immediate. It may have consequences in
|
||||
applications performing fast concurrent input over devices such as UARTs.
|
||||
|
||||
# Demo scripts
|
||||
## Demo scripts
|
||||
|
||||
These require uasyncio V3. This is incorporated in daily builds and will be
|
||||
available in release builds starting with MicroPython V1.13. The demos assume
|
||||
|
|
128
DRIVERS.md
128
DRIVERS.md
|
@ -2,6 +2,15 @@
|
|||
|
||||
The nano-gui project currently supports four display technologies: OLED (color
|
||||
and monochrome), color TFT, monochrome Sharp displays and EPD (ePaper/eInk).
|
||||
All drivers provide a display class subclassed from the built-in
|
||||
`framebuf.FrameBuffer` class. This provides three increasing levels of support:
|
||||
* Graphics via the `FrameBuffer` graphics primitives.
|
||||
* Text rendering in arbitrary fonts via `Writer` and `Cwriter` classes (see
|
||||
[font_to_py.py](https://github.com/peterhinch/micropython-font-to-py.git)).
|
||||
* Use with nano-gui.
|
||||
|
||||
It should be noted that in the interests of conserving RAM these drivers offer
|
||||
a bare minimum of functionality required to support the above.
|
||||
|
||||
# Contents
|
||||
|
||||
|
@ -26,9 +35,11 @@ and monochrome), color TFT, monochrome Sharp displays and EPD (ePaper/eInk).
|
|||
7.1 [Adafruit flexible eInk Display](./DRIVERS.md#71-adafruit-flexible-eink-display)
|
||||
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.2 [Waveshare eInk Display HAT](./DRIVERS.md#71-waveshare-eink-display-hat)
|
||||
7.2.1 [EPD constructor args](./DRIVERS.md#711-epd-constructor-args)
|
||||
7.2.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.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)
|
||||
7.2.3 [EPD public bound variables](./DRIVERS.md#723-epd-public-bound-variables)
|
||||
8. [EPD Asynchronous support](./DRIVERS.md#8-epd-asynchronous-support)
|
||||
9. [Writing device drivers](./DRIVERS.md#8-writing-device-drivers)
|
||||
|
||||
|
@ -36,13 +47,8 @@ and monochrome), color TFT, monochrome Sharp displays and EPD (ePaper/eInk).
|
|||
|
||||
# 1. Introduction
|
||||
|
||||
With the exception of the Sharp displays use of these drivers is very simple:
|
||||
the main reason to consult this doc is to select the right driver for your
|
||||
display, platform and application.
|
||||
|
||||
An application specifies a driver by means of `color_setup.py` or
|
||||
`ssd1306_setup.py` located in the root directory of the target. This typically
|
||||
contains code along these lines:
|
||||
An application specifies a driver by means of `color_setup.py` located in the
|
||||
root directory of the target. This typically contains code along these lines:
|
||||
```python
|
||||
import machine
|
||||
import gc
|
||||
|
@ -51,12 +57,15 @@ pdc = machine.Pin('Y1', machine.Pin.OUT_PP, value=0)
|
|||
pcs = machine.Pin('Y2', machine.Pin.OUT_PP, value=1)
|
||||
prst = machine.Pin('Y3', machine.Pin.OUT_PP, value=1)
|
||||
spi = machine.SPI(2, baudrate=10_000_000) # baudrate depends on display chip
|
||||
gc.collect() # Precaution before instantiating framebuf
|
||||
gc.collect()
|
||||
# Precaution before instantiating framebuf. The next line creates the buffer.
|
||||
ssd = SSD(spi, pcs, pdc, prst, 96) # Create a display instance
|
||||
```
|
||||
In the interests of conserving RAM, supplied drivers support only the
|
||||
functionality required by the GUI. More fully featured drivers may better suit
|
||||
other applications.
|
||||
The directory `color_setup` contains example files for various displays. These
|
||||
may be adapted and copied to `color_setup.py` on the target's root. The entry
|
||||
in this doc for the specific display should be consulted for SSD constructor
|
||||
arguments and SPI baudrate. The more exotic displays (Sharp and ePaper) have
|
||||
additional features and requirements detailed below.
|
||||
|
||||
## 1.1 Color handling
|
||||
|
||||
|
@ -438,7 +447,8 @@ Positional args:
|
|||
with value 0 (unusually the hardware CS line is active high).
|
||||
3. `height=240` Dimensions in pixels. Defaults are for 2.7" display.
|
||||
4. `width=400`
|
||||
5. `vcom=False` Accept the default unless using `pyb.standby`. See 3.2.
|
||||
5. `vcom=False` Accept the default unless using `pyb.standby`. See
|
||||
[6.3.2](./DRIVERS.md#632-the-vcom-arg).
|
||||
|
||||
### 6.3.1 Device driver methods
|
||||
|
||||
|
@ -502,12 +512,13 @@ the demo.
|
|||
|
||||
# 7. ePaper displays
|
||||
|
||||
These tend to be monochrome or to support no more than three colors. They also
|
||||
have very long refresh times (many seconds). The benefit is zero current
|
||||
between refreshes: it is possible to switch off power completely with the
|
||||
device retaining the image indefinitely. Some devices such as the Waveshare
|
||||
units perform the refresh internally. Earlier devices required the driver to
|
||||
perform this, tying up the CPU for the duration.
|
||||
Known as ePaper or eInk, electrophoretic (EPD) displays are usually monochrome.
|
||||
Some support a few levels of grey or a very small range of colors. They have
|
||||
long refresh times (many seconds). The principal benefit that they consume zero
|
||||
current except while being refreshed: it is possible to switch off power
|
||||
completely with the device retaining the image indefinitely. Present day EPD
|
||||
units perform the slow refresh autonomously. It makes no demands on the CPU
|
||||
enabling user code to continue to run.
|
||||
|
||||
The drivers are compatible with `uasyncio`. One approach is to use synchronous
|
||||
methods only and the standard demos (some of which use `uasyncio`) may be run.
|
||||
|
@ -527,7 +538,11 @@ enables the display to be completely powered down. This facilitates micropower
|
|||
applications: the host shuts down the display before going into deep sleep.
|
||||
|
||||
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.
|
||||
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
|
||||
frequently than every 180s. It is
|
||||
[unclear](https://forums.adafruit.com/viewtopic.php?f=19&t=174091) if this is
|
||||
an absolute limit or an average rate.
|
||||
|
||||
##### Wiring
|
||||
|
||||
|
@ -578,9 +593,24 @@ see below.
|
|||
to the display.
|
||||
* `wait` Asynchronous. No args. Pause until the display refresh is complete.
|
||||
|
||||
### 7.1.3 EPD 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.
|
||||
|
||||
** POWER DOWN HARDWARE **
|
||||
##### Micropower use
|
||||
|
||||
To power down the display 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.2 Waveshare eInk Display HAT
|
||||
|
||||
|
@ -649,38 +679,54 @@ Pins 26-40 unused and omitted.
|
|||
to the display.
|
||||
* `wait` Asynchronous. No args. Pause until the display refresh is complete.
|
||||
|
||||
### 7.2.3 EPD 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.
|
||||
|
||||
# 8. EPD Asynchronous support
|
||||
|
||||
Normally when GUI code issues
|
||||
```python
|
||||
refresh(ssd)
|
||||
refresh(ssd) # 250ms or longer depending on platform
|
||||
```
|
||||
display data is copied to the device and a physical refresh is initiated. The
|
||||
code blocks - typically for 250ms or more - before returning, with physical
|
||||
refresh being performed by the display hardware and taking several seconds.
|
||||
This blocking period, which may be longer on non-Pyboard hosts, is too long for
|
||||
many `uasyncio` applications.
|
||||
code blocks while copying data to the display before returning. Subsequent
|
||||
physical refresh is performed by the display hardware taking several seconds.
|
||||
While physical refresh is nonblocking, the initial blocking period is too long
|
||||
for many `uasyncio` applications.
|
||||
|
||||
If an `EPD` is instantiated with `asyn=True` the process of copying the data to
|
||||
the device is performed by a task which periodically yields to the scheduler.
|
||||
By default blocking is limited to around 30ms.
|
||||
|
||||
An `updated` method allows user code to pause after issuing `refresh` before
|
||||
modifying the content of the framebuf - at which time the old data has been
|
||||
entirely copied to the hardware. The `wait` method will pause until any
|
||||
physical update is complete.
|
||||
A `.updated()` method lets user code pause after issuing `refresh()`. The pause
|
||||
lasts until the framebuf has been entirely copied to the hardware. The
|
||||
application is then free to alter the framebuf contents.
|
||||
|
||||
It is invalid to issue `.refresh()` until the physical display refresh is
|
||||
complete; if this is attempted a `RuntimeError` will occur. The most efficient
|
||||
way to ensure that this cannot occur is to await the `.wait()` prior to any
|
||||
refresh. This method will pause until any physical update is complete.
|
||||
|
||||
The following illustrates the kind of approach which may be used
|
||||
```python
|
||||
while True:
|
||||
# Normal procedure before refresh, but 10s sleep should mean it always returns immediately
|
||||
# Before refresh, ensure that a previous refresh is complete
|
||||
await ssd.wait()
|
||||
refresh(ssd) # Launches ._as_show()
|
||||
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()
|
||||
# Content has now been shifted out so coros can update
|
||||
# Trigger an event which allows other tasks to update the
|
||||
# framebuffer in background
|
||||
evt.set()
|
||||
evt.clear()
|
||||
await asyncio.sleep(20) # Allow for slow refresh
|
||||
# The 2.9 inch display should not be updated too frequently
|
||||
await asyncio.sleep(180)
|
||||
```
|
||||
|
||||
# 9. Writing device drivers
|
||||
|
@ -700,7 +746,15 @@ using a forum search.
|
|||
For a driver to support `nanogui` it must be subclassed from
|
||||
`framebuf.FrameBuffer` and provide `height` and `width` bound variables being
|
||||
the display size in pixels. This, and a `show` method, are all that is required
|
||||
for monochrome drivers.
|
||||
for monochrome drivers. Generality can be extended by providing this static
|
||||
method:
|
||||
```python
|
||||
@staticmethod
|
||||
def rgb(r, g, b):
|
||||
return int((r > 127) or (g > 127) or (b > 127))
|
||||
```
|
||||
This ensures compatibility with code written for color displays by converting
|
||||
RGB values to a single bit.
|
||||
|
||||
Refresh must be handled by a `show` method taking no arguments; when called,
|
||||
the contents of the buffer underlying the `FrameBuffer` must be copied to the
|
||||
|
|
110
README.md
110
README.md
|
@ -1,6 +1,7 @@
|
|||
A lightweight and minimal MicroPython GUI library for display drivers based on
|
||||
the `FrameBuffer` class. Various display technologies are supported, including
|
||||
small color and monochrome OLED's and color TFT's. The GUI is cross-platform.
|
||||
small color and monochrome OLED's, color TFT's, ePaper and Sharp units. The GUI
|
||||
is cross-platform.
|
||||
|
||||
These images, most from OLED displays, fail to reproduce the quality of these
|
||||
displays. OLEDs are visually impressive displays with bright colors, wide
|
||||
|
@ -44,10 +45,9 @@ wiring details, pin names and hardware issues.
|
|||
2.1.1 [Core files](./README.md#211-core-files)
|
||||
2.1.2 [Demo Scripts](./README.md#212-demo-scripts)
|
||||
2.1.3 [Fonts](./README.md#213-fonts)
|
||||
2.1.4 [Color setup examples](./README.md#214-color-setup-examples)
|
||||
2.1.4 [Hardware setup examples](./README.md#214-hardware-setup-examples)
|
||||
2.2 [Dependencies](./README.md#21-dependencies)
|
||||
2.2.1 [Monochrome use](./README.md#211-monochrome-use)
|
||||
2.2.2 [Color use](./README.md#222-color-use)
|
||||
2.3 [Verifying hardware configuration](./README.md#23-verifying-hardware-configuration)
|
||||
3. [The nanogui module](./README.md#3-the-nanogui-module)
|
||||
3.1 [Application Initialisation](./README.md#31-application-initialisation) Initial setup and refresh method.
|
||||
3.1.1 [User defined colors](./README.md#311-user-defined-colors)
|
||||
|
@ -60,8 +60,6 @@ wiring details, pin names and hardware issues.
|
|||
3.7 [Class Textbox](./README.md#37-class-textbox) Scrolling text display.
|
||||
4. [ESP8266](./README.md#4-esp8266) This can work. Contains information on
|
||||
minimising the RAM and flash footprints of the GUI.
|
||||
5. [Hardware configuration](./README.md#5-hardware-configuration) How to write
|
||||
color_setup.py
|
||||
|
||||
#### [Device driver document.](./DRIVERS.md)
|
||||
|
||||
|
@ -96,6 +94,8 @@ my GUI's employ the American spelling of `color`.
|
|||
|
||||
## 1.1 Change log
|
||||
|
||||
17 Jan 2021 Add ePaper drivers. Ensure monochrome and color setup requirements
|
||||
are identical. Substantial update to docs.
|
||||
16 Dec 2020 Add ILI9341 driver, 4-bit drivers and SPI bus sharing improvements.
|
||||
These mean that `color_setup.py` should now set SPI baudrate.
|
||||
29 Nov 2020 Add ST7735R TFT drivers.
|
||||
|
@ -134,6 +134,10 @@ Compatible and tested display drivers include:
|
|||
[1.44 inch](https://www.adafruit.com/product/2088) documented [here](./DRIVERS.md#4-drivers-for-st7735r).
|
||||
* Drivers for ILI9341 such as [Adafruit 3.2 inch](https://www.adafruit.com/product/1743)
|
||||
documented [here](./DRIVERS.md#5-drivers-for-ili9341).
|
||||
* [Adafruit 2.9 inch ePaper display](https://www.adafruit.com/product/4262)
|
||||
documented [here](./DRIVERS.md#71-adafruit-flexible-eink-display).
|
||||
* [Waveshare 2.7 inch ePaper HAT](https://www.waveshare.com/wiki/2.7inch_e-Paper_HAT)
|
||||
documented [here with a warning](./DRIVERS.md#72-waveshare-eink-display-hat).
|
||||
|
||||
Widgets are intended for the display of data from physical devices such as
|
||||
sensors. They are drawn using graphics primitives rather than icons to minimise
|
||||
|
@ -187,25 +191,26 @@ Filesystem space may be conserved by copying only the required driver from
|
|||
for SSD1351 displays only the following are actually required:
|
||||
`drivers/ssd1351/ssd1351.py`, `drivers/ssd1351/__init__.py`.
|
||||
|
||||
The small `color_setup.py` file contains all hardware definitions (for color or
|
||||
monochrome displays). This is the only file which will require editing to match
|
||||
the display and its wiring. For information on how to do this, see
|
||||
[the drivers document](./DRIVERS.md#1-introduction).
|
||||
|
||||
## 2.1 Files
|
||||
|
||||
### 2.1.1 Core files
|
||||
|
||||
The root directory contains two example setup files, for monochrome and color
|
||||
displays respectively. Other examples may be found in the `color_setup`
|
||||
directory. These are templates for adaptation: only one file is copied to the
|
||||
target. On the target a color file should be named `color_setup.py`. The
|
||||
monochrome `ssd1306_setup.py` retains its own name.
|
||||
The root directory contains an example setup file `color_setup.py` for a color
|
||||
OLED display. Other examples may be found in the `color_setup` directory. These
|
||||
are templates for adaptation: only one file is copied to the target. On the
|
||||
target the file should be named `color_setup.py` and put in the root of the
|
||||
filesystem.
|
||||
|
||||
The chosen template will need to be edited to match the display in use, the
|
||||
MicroPython target and the electrical connections between display and target.
|
||||
Electrical connections are detailed in the driver source.
|
||||
* `color_setup.py` Setup for color displays. As written supports an SSD1351
|
||||
display connected to a Pyboard.
|
||||
* `ssd1306_setup.py` Setup file for monochrome displays using the official
|
||||
driver. Supports hard or soft SPI or I2C connections, as does the test script
|
||||
`mono_test.py`. On non Pyboard targets this will require adaptation to match
|
||||
the hardware connections.
|
||||
* `color_setup.py` Hardware setup for the display. As written supports an
|
||||
SSD1351 display connected to a Pyboard.
|
||||
|
||||
The `gui/core` directory contains the GUI core and its principal dependencies:
|
||||
|
||||
|
@ -225,6 +230,7 @@ The `gui/core` directory contains the GUI core and its principal dependencies:
|
|||
|
||||
The `gui/demos` directory contains test/demo scripts.
|
||||
|
||||
Demos for small displays:
|
||||
* `mono_test.py` Tests/demos using the official SSD1306 driver for a
|
||||
monochrome 128*64 OLED display.
|
||||
* `color96.py` Tests/demos for the Adafruit 0.96 inch color OLED.
|
||||
|
@ -240,23 +246,20 @@ Demos for larger displays.
|
|||
* `tbox.py` Demo `Textbox` class. Cross-platform.
|
||||
* `scale_ili.py` A special demo of the asychronous mode of the ILI9341 driver.
|
||||
|
||||
Demos for ePaper displays:
|
||||
Demos for ePaper displays:
|
||||
* `waveshare_test.py` For the Waveshare eInk Display HAT 2.7" 176*274 portrait
|
||||
mode display.
|
||||
* `epd29_test.py` Demo for Adafruit 2.9" eInk display.
|
||||
|
||||
Demos for Sharp displays:
|
||||
* `sharptest.py` Basic functionality check.
|
||||
* `clocktest.py` Digital and analog clock demo.
|
||||
* `clock_batt.py` Low power demo of battery operated clock.
|
||||
|
||||
Usage with `uasyncio` is discussed [here](./ASYNC.md). In summary the blocking
|
||||
which occurs during transfer of the framebuffer to the display may affect more
|
||||
demanding `uasyncio` applications. More generally the GUI works well with it.
|
||||
|
||||
Demo scripts for Sharp displays are in `drivers/sharp`. Check source code for
|
||||
wiring details. See [the docs](./DRIVERS.md#6-drivers-for-sharp-displays). They
|
||||
may be run as follows:
|
||||
```python
|
||||
import drivers.sharp.sharptest
|
||||
# or
|
||||
import drivers.sharp.clocktest
|
||||
```
|
||||
|
||||
###### [Contents](./README.md#contents)
|
||||
|
||||
### 2.1.3 Fonts
|
||||
|
@ -280,12 +283,14 @@ is required `-f` is also required. Supplied examples are:
|
|||
* `font10.py`
|
||||
* `freesans20.py`
|
||||
|
||||
### 2.1.4 Color setup examples
|
||||
### 2.1.4 Hardware setup examples
|
||||
|
||||
The `color_setup` directory contains example setup files for various hardware.
|
||||
These are templates which may be adapted to suit the hardware in use, then
|
||||
copied to the hardware root as `color_setup.py`.
|
||||
copied to the hardware root as `color_setup.py`. Example files:
|
||||
|
||||
* `ssd1306_setup.py` Setup file for monochrome displays using the official
|
||||
driver. Supports hard or soft SPI or I2C connections.
|
||||
* `esp32_setup.py` As written supports an ESP32 connected to a 128x128 SSD1351
|
||||
display. After editing to match the display and wiring, it should be copied to
|
||||
the target as `/pyboard/color_setup.py`.
|
||||
|
@ -297,6 +302,7 @@ copied to the hardware root as `color_setup.py`.
|
|||
[Adafruit 1.44 inch TFT display](https://www.adafruit.com/product/2088).
|
||||
* `ili9341_setup.py` A 240*320 ILI9341 display on ESP32.
|
||||
* `waveshare_setup.py` 176*274 portrait mode ePaper display.
|
||||
* `epd96_asyn.py` Adafruit 2.9 inch ePaper display, optimised for `uasyncio`.
|
||||
|
||||
## 2.2 Dependencies
|
||||
|
||||
|
@ -310,10 +316,6 @@ Optional feature:
|
|||
* An STM32 implementation of
|
||||
[this optimisation](https://github.com/peterhinch/micropython-font-to-py/blob/master/writer/WRITER.md#224-a-performance-boost).
|
||||
|
||||
###### [Contents](./README.md#contents)
|
||||
|
||||
### 2.2.1 Monochrome use
|
||||
|
||||
A copy of the official driver for OLED displays using the SSD1306 chip is
|
||||
provided. The official file is here:
|
||||
* [SSD1306 driver](https://github.com/micropython/micropython/blob/master/drivers/display/ssd1306.py).
|
||||
|
@ -325,11 +327,13 @@ in this repo but may be found here:
|
|||
The Sharp display is supported in `drivers/sharp`. See
|
||||
[README](./DRIVERS.md#6-drivers-for-sharp-displays) and demos.
|
||||
|
||||
### 2.2.2 Color use
|
||||
###### [Contents](./README.md#contents)
|
||||
|
||||
## 2.3 Verifying hardware configuration
|
||||
|
||||
This script performs a basic check that the `color_setup.py` file matches the
|
||||
hardware, that all three primary colors can be displayed and that pixels up to
|
||||
the edges of the display can be accessed.
|
||||
hardware, that (on color units) all three primary colors can be displayed and
|
||||
that pixels up to the edges of the display can be accessed.
|
||||
```python
|
||||
from color_setup import ssd # Create a display instance
|
||||
from gui.core.nanogui import refresh
|
||||
|
@ -362,11 +366,11 @@ Text components of widgets are rendered using the `Writer` (monochrome) or
|
|||
|
||||
## 3.1 Application Initialisation
|
||||
|
||||
The GUI is initialised for color display by issuing:
|
||||
The GUI is initialised by issuing:
|
||||
```python
|
||||
from color_setup import ssd
|
||||
```
|
||||
This defines the hardware as described in [Hardware configuration](./README.md#5-hardware-configuration).
|
||||
This defines the hardware as described in [the drivers document](./DRIVERS.md#1-introduction).
|
||||
|
||||
A typical application then imports `nanogui` modules and clears the display:
|
||||
```python
|
||||
|
@ -846,33 +850,3 @@ With the 4 bit driver `scale.py` reported 18112 bytes. In conclusion I think
|
|||
that applications of moderate complexity should be feasible.
|
||||
|
||||
###### [Contents](./README.md#contents)
|
||||
|
||||
# 5. Hardware configuration
|
||||
|
||||
The file `color_setup.py` contains the hardware dependent code. It works as
|
||||
described below, with the aim of allocating the `FrameBuffer` before importing
|
||||
other modules. This is intended to reduce the risk of memory failures.
|
||||
|
||||
This example is for SSD1351 devices where a single driver supports displays of
|
||||
two different heights. In general [the driver doc](./DRIVERS.md) should be
|
||||
consulted for correct SSD constructor arguments.
|
||||
|
||||
Firstly the file sets the display height and imports the driver:
|
||||
```python
|
||||
height = 96 # 1.27 inch 96*128 (rows*cols) display. Set to 128 for 1.5 inch
|
||||
import machine
|
||||
import gc
|
||||
from drivers.ssd1351.ssd1351 import SSD1351 as SSD # Import the display driver
|
||||
```
|
||||
It then sets up the bus (SPI or I2C) and instantiates the display. At this
|
||||
point the framebuffer is created:
|
||||
```python
|
||||
pdc = machine.Pin('X1', machine.Pin.OUT_PP, value=0)
|
||||
pcs = machine.Pin('X2', machine.Pin.OUT_PP, value=1)
|
||||
prst = machine.Pin('X3', machine.Pin.OUT_PP, value=1)
|
||||
spi = machine.SPI(1)
|
||||
gc.collect() # Precaution before instantiating framebuf
|
||||
ssd = SSD(spi, pcs, pdc, prst, height) # Create a display instance
|
||||
```
|
||||
|
||||
###### [Contents](./README.md#contents)
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
# sharp_setup.py Customise for your hardware config
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2020 Peter Hinch
|
||||
|
||||
# As written, supports Adafruit 2.7 inch 400*240 Sharp display
|
||||
# https://www.adafruit.com/product/4694
|
||||
|
||||
# Demo of initialisation procedure designed to minimise risk of memory fail
|
||||
# when instantiating the frame buffer. The aim is to do this as early as
|
||||
# possible before importing other modules.
|
||||
|
||||
# SSD1331 drivers are cross-platform.
|
||||
# WIRING (Adafruit pin nos and names with Pyboard pins).
|
||||
# Pyb SSD
|
||||
# Vin Vin Pyboard: Vin is a 5V output when powered by USB
|
||||
# Gnd Gnd
|
||||
# Y8 DI
|
||||
# Y6 CLK
|
||||
# Y5 CS
|
||||
|
||||
import machine
|
||||
import gc
|
||||
|
||||
from drivers.sharp.sharp import SHARP as SSD
|
||||
|
||||
pcs = machine.Pin('Y5', machine.Pin.OUT_PP, value=0) # Active high
|
||||
# Baudrate ref. https://learn.adafruit.com/adafruit-sharp-memory-display-breakout/circuitpython-displayio-usage
|
||||
spi = machine.SPI(2, baudrate=2_000_000)
|
||||
gc.collect()
|
||||
ssd = SSD(spi, pcs)
|
|
@ -0,0 +1,49 @@
|
|||
# ssd1306_setup.py Demo pogram for rendering arbitrary fonts to an SSD1306 OLED display.
|
||||
# ssd1306_setup.py Device initialisation. Copy to color_setup.py on host.
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2018-2021 Peter Hinch
|
||||
|
||||
|
||||
# https://learn.adafruit.com/monochrome-oled-breakouts/wiring-128x32-spi-oled-display
|
||||
# https://www.proto-pic.co.uk/monochrome-128x32-oled-graphic-display.html
|
||||
|
||||
import machine
|
||||
from drivers.ssd1306.ssd1306 import SSD1306_SPI, SSD1306_I2C
|
||||
|
||||
WIDTH = const(128)
|
||||
HEIGHT = const(64)
|
||||
use_spi = False # I2C or SPI
|
||||
soft = True # Soft or hard I2C/SPI
|
||||
|
||||
# Export an initialised ssd display object.
|
||||
if use_spi:
|
||||
# Pyb SSD
|
||||
# 3v3 Vin
|
||||
# Gnd Gnd
|
||||
# X1 DC
|
||||
# X2 CS
|
||||
# X3 Rst
|
||||
# X6 CLK
|
||||
# X8 DATA
|
||||
pdc = machine.Pin('Y1', machine.Pin.OUT_PP)
|
||||
pcs = machine.Pin('Y2', machine.Pin.OUT_PP)
|
||||
prst = machine.Pin('Y3', machine.Pin.OUT_PP)
|
||||
if soft:
|
||||
spi = machine.SPI(sck=machine.Pin('Y6'), mosi=machine.Pin('Y8'), miso=machine.Pin('Y7'))
|
||||
else:
|
||||
spi = machine.SPI(2)
|
||||
ssd = SSD1306_SPI(WIDTH, HEIGHT, spi, pdc, prst, pcs)
|
||||
else: # I2C
|
||||
# Pyb SSD
|
||||
# 3v3 Vin
|
||||
# Gnd Gnd
|
||||
# Y9 CLK
|
||||
# Y10 DATA
|
||||
if soft:
|
||||
pscl = machine.Pin('Y9', machine.Pin.OPEN_DRAIN)
|
||||
psda = machine.Pin('Y10', machine.Pin.OPEN_DRAIN)
|
||||
i2c = machine.SoftI2C(scl=pscl, sda=psda)
|
||||
else:
|
||||
i2c = machine.I2C(2)
|
||||
ssd = SSD1306_I2C(WIDTH, HEIGHT, i2c)
|
|
@ -1,4 +1,4 @@
|
|||
# color_setup.py Customise for your hardware config
|
||||
# ssd1331_setup.py Customise for your hardware config
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2020 Peter Hinch
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
# https://www.adafruit.com/product/3502 1.3 inch 144x168
|
||||
# https://www.adafruit.com/product/1393 1.3 inch 96x96 Monochrome
|
||||
|
||||
# Copyright (c) Peter Hinch 2020
|
||||
# Copyright (c) Peter Hinch 2020-2021
|
||||
# Released under the MIT license see LICENSE
|
||||
|
||||
# Code checked against https://github.com/adafruit/Adafruit_CircuitPython_SharpMemoryDisplay
|
||||
|
@ -23,6 +23,9 @@ _VCOM = const(2)
|
|||
|
||||
|
||||
class SHARP(framebuf.FrameBuffer):
|
||||
@staticmethod
|
||||
def rgb(r, g, b):
|
||||
return int((r > 127) or (g > 127) or (b > 127))
|
||||
|
||||
def __init__(self, spi, pincs, height=240, width=400, vcom=False):
|
||||
spi.init(baudrate=2_000_000, firstbit=machine.SPI.LSB) # Data sheet: should support 2MHz
|
||||
|
|
|
@ -26,6 +26,10 @@ SET_CHARGE_PUMP = const(0x8D)
|
|||
# Subclassing FrameBuffer provides support for graphics primitives
|
||||
# http://docs.micropython.org/en/latest/pyboard/library/framebuf.html
|
||||
class SSD1306(framebuf.FrameBuffer):
|
||||
@staticmethod
|
||||
def rgb(r, g, b):
|
||||
return int((r > 127) or (g > 127) or (b > 127))
|
||||
|
||||
def __init__(self, width, height, external_vcc):
|
||||
self.width = width
|
||||
self.height = height
|
||||
|
|
|
@ -18,17 +18,8 @@
|
|||
# when instantiating the frame buffer. The aim is to do this as early as
|
||||
# possible before importing other modules.
|
||||
|
||||
import machine
|
||||
import gc
|
||||
from drivers.sharp.sharp import SHARP as SSD
|
||||
from color_setup import ssd # Create a display instance
|
||||
|
||||
# Initialise hardware
|
||||
pcs = machine.Pin('Y5', machine.Pin.OUT_PP, value=0) # Active high
|
||||
spi = machine.SPI(2)
|
||||
gc.collect() # Precaution before instantiating framebuf
|
||||
ssd = SSD(spi, pcs)
|
||||
|
||||
# Now import other modules
|
||||
import upower
|
||||
from gui.core.nanogui import refresh
|
||||
from gui.widgets.label import Label
|
|
@ -16,17 +16,8 @@
|
|||
# when instantiating the frame buffer. The aim is to do this as early as
|
||||
# possible before importing other modules.
|
||||
|
||||
import machine
|
||||
import gc
|
||||
from drivers.sharp.sharp import SHARP as SSD
|
||||
from color_setup import ssd # Create a display instance
|
||||
|
||||
# Initialise hardware
|
||||
pcs = machine.Pin('Y5', machine.Pin.OUT_PP, value=0) # Active high
|
||||
spi = machine.SPI(2)
|
||||
gc.collect() # Precaution before instantiating framebuf
|
||||
ssd = SSD(spi, pcs)
|
||||
|
||||
# Now import other modules
|
||||
from gui.core.nanogui import refresh
|
||||
from gui.widgets.label import Label
|
||||
from gui.widgets.dial import Dial, Pointer
|
||||
|
@ -68,11 +59,11 @@ def aclock():
|
|||
sstart = 0 + 0.92j
|
||||
while True:
|
||||
t = utime.localtime()
|
||||
hang = -t[4]*pi/6 - t[5]*pi/360 # Angles of hour and minute hands
|
||||
mang = -t[5] * pi/30
|
||||
sang = -t[6] * pi/30
|
||||
hang = -t[3]*pi/6 - t[4]*pi/360 # Angles of hour and minute hands
|
||||
mang = -t[4] * pi/30
|
||||
sang = -t[5] * pi/30
|
||||
if abs(hang - mang) < pi/360: # Avoid overlap of hr and min hands
|
||||
hang += pi/30 # which is visually confusing. Add slight lag to hts
|
||||
hang += pi/30 # which is visually confusing. Add slight lag to hrs
|
||||
hrs.value(hstart * uv(hang))
|
||||
mins.value(mstart * uv(mang))
|
||||
secs.value(sstart * uv(sang))
|
|
@ -6,6 +6,7 @@
|
|||
# color_setup must set landcsape True, asyn True and must not set demo_mode
|
||||
import uasyncio as asyncio
|
||||
from color_setup import ssd
|
||||
# On a monochrome display Writer is more efficient than CWriter.
|
||||
from gui.core.writer import Writer
|
||||
from gui.core.nanogui import refresh
|
||||
from gui.widgets.meter import Meter
|
||||
|
@ -13,7 +14,6 @@ from gui.widgets.label import Label
|
|||
|
||||
# Fonts
|
||||
import gui.fonts.arial10 as arial10
|
||||
#import gui.fonts.courier20 as fixed
|
||||
import gui.fonts.font6 as small
|
||||
|
||||
# Some ports don't support uos.urandom.
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
# mono_test.py Demo program for nano_gui on an SSD1306 OLED display.
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2018-2020 Peter Hinch
|
||||
# Copyright (c) 2018-2021 Peter Hinch
|
||||
|
||||
# https://learn.adafruit.com/monochrome-oled-breakouts/wiring-128x32-spi-oled-display
|
||||
# https://www.proto-pic.co.uk/monochrome-128x32-oled-graphic-display.html
|
||||
|
||||
# V0.33 16th Jan 2021 Hardware configuration is now defined in color_setup to be
|
||||
# consistent with other displays.
|
||||
# V0.32 5th Nov 2020 Replace uos.urandom for minimal ports
|
||||
|
||||
import utime
|
||||
# import uos
|
||||
from ssd1306_setup import setup
|
||||
from color_setup import ssd
|
||||
# On a monochrome display Writer is more efficient than CWriter.
|
||||
from gui.core.writer import Writer
|
||||
from gui.core.nanogui import refresh
|
||||
from gui.widgets.meter import Meter
|
||||
|
@ -33,8 +36,9 @@ def xorshift64star(modulo, seed = 0xf9ac6ba4):
|
|||
return (x * 0x2545F4914F6CDD1D) % modulo
|
||||
return func
|
||||
|
||||
def fields(use_spi=False, soft=True):
|
||||
ssd = setup(use_spi, soft) # Create a display instance
|
||||
def fields():
|
||||
ssd.fill(0)
|
||||
refresh(ssd)
|
||||
Writer.set_textpos(ssd, 0, 0) # In case previous tests have altered it
|
||||
wri = Writer(ssd, fixed, verbose=False)
|
||||
wri.set_clip(False, False, False)
|
||||
|
@ -53,8 +57,9 @@ def fields(use_spi=False, soft=True):
|
|||
textfield.value('Done', True)
|
||||
refresh(ssd)
|
||||
|
||||
def multi_fields(use_spi=False, soft=True):
|
||||
ssd = setup(use_spi, soft) # Create a display instance
|
||||
def multi_fields():
|
||||
ssd.fill(0)
|
||||
refresh(ssd)
|
||||
Writer.set_textpos(ssd, 0, 0) # In case previous tests have altered it
|
||||
wri = Writer(ssd, small, verbose=False)
|
||||
wri.set_clip(False, False, False)
|
||||
|
@ -79,11 +84,10 @@ def multi_fields(use_spi=False, soft=True):
|
|||
Label(wri, 0, 64, ' DONE ', True)
|
||||
refresh(ssd)
|
||||
|
||||
def meter(use_spi=False, soft=True):
|
||||
ssd = setup(use_spi, soft)
|
||||
wri = Writer(ssd, arial10, verbose=False)
|
||||
def meter():
|
||||
ssd.fill(0)
|
||||
refresh(ssd)
|
||||
wri = Writer(ssd, arial10, verbose=False)
|
||||
m0 = Meter(wri, 5, 2, height = 50, divisions = 4, legends=('0.0', '0.5', '1.0'))
|
||||
m1 = Meter(wri, 5, 44, height = 50, divisions = 4, legends=('-1', '0', '+1'))
|
||||
m2 = Meter(wri, 5, 86, height = 50, divisions = 4, legends=('-1', '0', '+1'))
|
||||
|
@ -99,14 +103,15 @@ def meter(use_spi=False, soft=True):
|
|||
|
||||
tstr = '''Test assumes a 128*64 (w*h) display. Edit WIDTH and HEIGHT in ssd1306_setup.py for others.
|
||||
Device pinouts are comments in ssd1306_setup.py.
|
||||
All tests take two boolean args:
|
||||
use_spi = False. Set True for SPI connected device
|
||||
soft=True set False to use hardware I2C/SPI. Hardware I2C option currently fails with official SSD1306 driver.
|
||||
|
||||
Available tests:
|
||||
fields() Label test with dynamic data.
|
||||
multi_fields() More Labels.
|
||||
meter() Demo of Meter object.
|
||||
Test runs to completion.
|
||||
'''
|
||||
|
||||
print(tstr)
|
||||
print('Basic test of fields.')
|
||||
fields()
|
||||
print('More fields.')
|
||||
multi_fields()
|
||||
print('Meters.')
|
||||
meter()
|
||||
print('Done.')
|
||||
|
|
|
@ -13,8 +13,7 @@
|
|||
# Y6 CLK
|
||||
# Y5 CS
|
||||
|
||||
import machine
|
||||
from drivers.sharp.sharp import SHARP as SSD
|
||||
from color_setup import ssd # Create a display instance
|
||||
# Fonts for Writer
|
||||
import gui.fonts.freesans20 as freesans20
|
||||
import gui.fonts.arial_50 as arial_50
|
||||
|
@ -23,9 +22,6 @@ from gui.core.writer import Writer
|
|||
import time
|
||||
|
||||
def test():
|
||||
pcs = machine.Pin('Y5', machine.Pin.OUT_PP, value=0) # Active high
|
||||
spi = machine.SPI(2)
|
||||
ssd = SSD(spi, pcs)
|
||||
rhs = ssd.width -1
|
||||
ssd.line(rhs - 80, 0, rhs, 80, 1)
|
||||
square_side = 40
|
|
@ -1,48 +0,0 @@
|
|||
# ssd1306_setup.py Demo pogram for rendering arbitrary fonts to an SSD1306 OLED display.
|
||||
# Device initialisation
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2018-2020 Peter Hinch
|
||||
|
||||
|
||||
# https://learn.adafruit.com/monochrome-oled-breakouts/wiring-128x32-spi-oled-display
|
||||
# https://www.proto-pic.co.uk/monochrome-128x32-oled-graphic-display.html
|
||||
|
||||
import machine
|
||||
from drivers.ssd1306.ssd1306 import SSD1306_SPI, SSD1306_I2C
|
||||
|
||||
WIDTH = const(128)
|
||||
HEIGHT = const(64)
|
||||
|
||||
def setup(use_spi=False, soft=True):
|
||||
if use_spi:
|
||||
# Pyb SSD
|
||||
# 3v3 Vin
|
||||
# Gnd Gnd
|
||||
# X1 DC
|
||||
# X2 CS
|
||||
# X3 Rst
|
||||
# X6 CLK
|
||||
# X8 DATA
|
||||
pdc = machine.Pin('Y1', machine.Pin.OUT_PP)
|
||||
pcs = machine.Pin('Y2', machine.Pin.OUT_PP)
|
||||
prst = machine.Pin('Y3', machine.Pin.OUT_PP)
|
||||
if soft:
|
||||
spi = machine.SPI(sck=machine.Pin('Y6'), mosi=machine.Pin('Y8'), miso=machine.Pin('Y7'))
|
||||
else:
|
||||
spi = machine.SPI(2)
|
||||
ssd = SSD1306_SPI(WIDTH, HEIGHT, spi, pdc, prst, pcs)
|
||||
else: # I2C
|
||||
# Pyb SSD
|
||||
# 3v3 Vin
|
||||
# Gnd Gnd
|
||||
# Y9 CLK
|
||||
# Y10 DATA
|
||||
if soft:
|
||||
pscl = machine.Pin('Y9', machine.Pin.OPEN_DRAIN)
|
||||
psda = machine.Pin('Y10', machine.Pin.OPEN_DRAIN)
|
||||
i2c = machine.I2C(scl=pscl, sda=psda)
|
||||
else:
|
||||
i2c = machine.I2C(2)
|
||||
ssd = SSD1306_I2C(WIDTH, HEIGHT, i2c)
|
||||
return ssd
|
Ładowanie…
Reference in New Issue