kopia lustrzana https://github.com/peterhinch/micropython-nano-gui
Complete refactor as Python package.
rodzic
dca99bf247
commit
b7e0ef153e
262
README.md
262
README.md
|
@ -28,6 +28,9 @@ wiring details, pin names and hardware issues.
|
|||
# Contents
|
||||
|
||||
1. [Introduction](./README.md#1-introduction)
|
||||
1.1 [Update](./README.md#11-update)
|
||||
1.2 [Description](./README.md#12-description)
|
||||
1.3 [Quick start](./README.md#13-quick-start)
|
||||
2. [Files and Dependencies](./README.md#2-files-and-dependencies)
|
||||
2.1 [Dependencies](./README.md#21-dependencies)
|
||||
2.2.1 [Monochrome use](./README.md#211-monochrome-use)
|
||||
|
@ -44,12 +47,40 @@ wiring details, pin names and hardware issues.
|
|||
|
||||
# 1. Introduction
|
||||
|
||||
This library provides a limited set of GUI objects (widgets) for displays whose
|
||||
display driver is subclassed from the `framebuf` class. The GUI is display-only
|
||||
and lacks provision for user input. This is because no `framebuf` based display
|
||||
drivers exist for screens with a touch overlay. This is probably because touch
|
||||
overlays require too many pixels and are best suited to displays with internal
|
||||
frame buffers.
|
||||
|
||||
The GUI is cross-platform. By default it is configured for a Pyboard (1.x or D).
|
||||
This doc explains how to configure for other platforms by adapting a single
|
||||
small file. The GUI supports multiple displays attached to a single target, but
|
||||
bear in mind the RAM requirements for multiple frame buffers.
|
||||
|
||||
Authors of applications requiring touch should consider my touch GUI's for the
|
||||
following displays. These have internal buffers:
|
||||
* [Official lcd160cr](https://github.com/peterhinch/micropython-lcd160cr-gui)
|
||||
* [RA8875 large displays](https://github.com/peterhinch/micropython_ra8875)
|
||||
* [SSD1963 large displays](https://github.com/peterhinch/micropython-tft-gui)
|
||||
|
||||
## 1.1 Update
|
||||
|
||||
This library has been refactored as a Python package. The aim is to reduce RAM
|
||||
usage: widgets are imported on demand rather than unconditionally. This enabled
|
||||
the addition of new widgets with zero impact on existsing applications.
|
||||
the addition of new widgets with zero impact on existsing applications. Another
|
||||
aim was to simplify installation with dependencies such as `writer` included in
|
||||
the tree. Finally hardware configuration is contained in a single file: details
|
||||
only need to be edited in one place to run all demo scripts.
|
||||
|
||||
This library provides a limited set of GUI objects (widgets) for displays whose
|
||||
display driver is subclassed from the `framebuf` class. Display drivers include:
|
||||
Existing users should re-install from scratch. In existing applications, import
|
||||
statements will need to be adapted as per the demos. The GUI API is otherwise
|
||||
unchanged.
|
||||
|
||||
## 1.2 Description
|
||||
|
||||
Compatible and tested display drivers include:
|
||||
|
||||
* The official [SSD1306 driver](https://github.com/micropython/micropython/blob/master/drivers/display/ssd1306.py).
|
||||
* The [PCD8544/Nokia 5110](https://github.com/mcauser/micropython-pcd8544.git).
|
||||
|
@ -63,60 +94,88 @@ display driver is subclassed from the `framebuf` class. Display drivers include:
|
|||
is [here](./drivers/sharp/README.md).
|
||||
|
||||
Widgets are intended for the display of data from physical devices such as
|
||||
sensors. The GUI is display-only: there is no provision for user input. This
|
||||
is because there are no `frmebuf`- based display drivers for screens with a
|
||||
touch overlay. Authors of applications requiring input should consider my touch
|
||||
GUI's for the official lcd160cr, for RA8875 based displays or for SSD1963 based
|
||||
displays.
|
||||
|
||||
Widgets are drawn using graphics primitives rather than icons to minimise RAM
|
||||
usage. It also enables them to be effciently rendered at arbitrary scale on
|
||||
sensors. They are drawn using graphics primitives rather than icons to minimise
|
||||
RAM usage. It also enables them to be effciently rendered at arbitrary scale on
|
||||
devices with restricted processing power. The approach also enables widgets to
|
||||
provide information in ways that are difficult with icons, in particular using
|
||||
maximise information in ways that are difficult with icons, in particular using
|
||||
dynamic color changes in conjunction with moving elements.
|
||||
|
||||
Owing to RAM requirements and limitations on communication speed, `framebuf`
|
||||
based display drivers are intended for physically small displays with limited
|
||||
numbers of pixels. The widgets are designed for displays as small as 0.96
|
||||
inches: this involves some compromises. They aim to maximise the information
|
||||
on screen by offering the option of dynamically changing colors.
|
||||
inches: this involves some compromises.
|
||||
|
||||
Copying the contents of the frame buffer to the display is relatively slow. The
|
||||
time depends on the size of the frame buffer and the interface speed, but the
|
||||
latency may be too high for applications such as games. For example the time to
|
||||
update a 128*128*8 color ssd1351 display on a Pyboard 1.0 is 41ms.
|
||||
update a 128x128x8 color ssd1351 display on a Pyboard 1.0 is 41ms.
|
||||
|
||||
Drivers based on `framebuf` must allocate contiguous RAM for the buffer. To
|
||||
avoid 'out of memory' errors it is best to instantiate the display early,
|
||||
possibly before importing many other modules. The `aclock.py` and `alevel.py`
|
||||
demos illustrate this.
|
||||
avoid 'out of memory' errors it is best to instantiate the display before
|
||||
importing other modules. The demos illustrate this.
|
||||
|
||||
## 1.3 Quick start
|
||||
|
||||
A GUI description can seem daunting because of the number of class config
|
||||
options. Defaults can usually be accepted and meaningful applications can be
|
||||
minimal. Installation can seem difficult. To counter this, this session using
|
||||
[rshell](https://github.com/dhylands/rshell) installed and ran a demo showing
|
||||
analog and digital clocks.
|
||||
|
||||
Clone the repo to your PC, wire up a Pyboard (1.x or D) to an Adafruit 1.27"
|
||||
OLED as per `color_setup.py`, move to the root directory of the repo and run
|
||||
`rshell`.
|
||||
```bash
|
||||
> cp -r drivers /sd
|
||||
> cp -r gui /sd
|
||||
> cp color_setup.py /sd
|
||||
> repl ~ import gui.demos.aclock
|
||||
```
|
||||
Note also that the `gui.demos.aclock.py` demo comprises 38 lines of actual
|
||||
code. This stuff is easier than you might think.
|
||||
|
||||
# 2. Files and Dependencies
|
||||
|
||||
In general installation comprises copying the `ngui` and `drivers` directories,
|
||||
with their contents, to the target hardware
|
||||
Firmware should be V1.13 or later.
|
||||
|
||||
Installation comprises copying the `gui` and `drivers` directories, with their
|
||||
contents, plus a hardware configuration file, to the target. The directory
|
||||
structure on the target must match that in the repo.
|
||||
|
||||
Filesystem space may be conserved by copying only the required driver from
|
||||
`drivers`, but the directory path to that file must be retained. For example,
|
||||
for SSD1351 displays only the following is actually required:
|
||||
`drivers/ssd1351/ssd1351.py`
|
||||
|
||||
## 2.1 Files
|
||||
|
||||
### 2.1.1 Core files
|
||||
|
||||
The `ngui/core` directory contains the GUI core and its principal dependencies:
|
||||
The root directory contains setup files for monochrome and color displays. The
|
||||
relevant file will need to be edited to match the display in use, the
|
||||
MicroPython target and the electrical connections between display and target.
|
||||
* `color_setup.py` 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.
|
||||
|
||||
The `gui/core` directory contains the GUI core and its principal dependencies:
|
||||
|
||||
* `nanogui.py` The library.
|
||||
* `writer.py` Module for rendering Python fonts.
|
||||
* `fplot.py` The graph plotting module.
|
||||
* `ssd1306_setup.py` Applications using an SSD1306 monochrome OLED display
|
||||
import this file to determine hardware initialisation. On non Pyboard targets
|
||||
this will require adaptation to match the hardware connections.
|
||||
* `colors.py` Color constants.
|
||||
* `framebuf_utils.mpy` Accelerator for the `CWriter` class. This optional file
|
||||
is compiled for STM hardware and will be ignored on other ports. Instructions
|
||||
and code for compiling for other architectures may be found
|
||||
is compiled for STM hardware and will be ignored on other ports unless
|
||||
recompiled. Instructions and code for compiling for other architectures may be
|
||||
found
|
||||
[here](https://github.com/peterhinch/micropython-font-to-py/blob/master/writer/WRITER.md#224-a-performance-boost).
|
||||
|
||||
### 2.1.2 Demo scripts
|
||||
|
||||
The `ngui/demos` directory contains test/demo scripts. In general these will
|
||||
need minor adaptation to match your display hardware.
|
||||
The `gui/demos` directory contains test/demo scripts.
|
||||
|
||||
* `mono_test.py` Tests/demos using the official SSD1306 library for a
|
||||
monochrome 128*64 OLED display.
|
||||
|
@ -126,77 +185,95 @@ need minor adaptation to match your display hardware.
|
|||
|
||||
Demos for Adafruit 1.27 inch and 1.5 inch color OLEDs. Edit the `height = 96`
|
||||
line as per the code comment for the larger display.
|
||||
* `aclock.py` Analog clock demo.
|
||||
* `aclock.py` Analog clock demo. Cross platform.
|
||||
* `alevel.py` Spirit level using Pyboard accelerometer.
|
||||
* `fpt.py` Plot demo. Cross platform.
|
||||
* `scale.py` A demo of the new `Scale` widget. Cross platform.
|
||||
* `asnano_sync.py` Two Pyboard specific demos using the GUI with `uasyncio`.
|
||||
* `asnano.py` Could readily be adapted for other targets.
|
||||
|
||||
Compatibility with `uasyncio` and the last two demos are discussed
|
||||
[here](./ASYNC.md).
|
||||
|
||||
Demo scripts for Sharp displays are in `drivers/sharp`. Check source code for
|
||||
wiring details. See [the README](./drivers/sharp/README.md). They may be run as
|
||||
follows:
|
||||
```python
|
||||
import drivers.sharp.sharptest
|
||||
# or
|
||||
import drivers.sharp.clocktest
|
||||
```
|
||||
|
||||
### 2.1.3 Fonts
|
||||
|
||||
Python font files are in the root directory. This facilitates freezing them to
|
||||
conserve RAM. Python fonts may be created using
|
||||
[font_to_py.py](https://github.com/peterhinch/micropython-font-to-py.git).
|
||||
Supplied examples are:
|
||||
Python font files are in the `gui/fonts` directory. The easiest way to conserve
|
||||
RAM is to freeze them which is highly recommended. In doing so the directory
|
||||
structure must be maintained. Python fonts may be created using
|
||||
[font_to_py.py](https://github.com/peterhinch/micropython-font-to-py.git). The
|
||||
`-x` option for horizontal mapping must be specified. Supplied examples are:
|
||||
|
||||
* `arial10.py`
|
||||
* `courier20.py`
|
||||
* `arial10.py` Variable pitch Arial in various sizes.
|
||||
* `arial35.py`
|
||||
* `arial_50.py`
|
||||
* `courier20.py` Fixed pitch font.
|
||||
* `font6.py`
|
||||
* `font10.py`
|
||||
* `freesans20.py`
|
||||
|
||||
Demos showing the use of `nanogui` with `uasyncio` may be found [here](./ASYNC.md).
|
||||
|
||||
## 2.2 Dependencies
|
||||
|
||||
All applicatons require a device driver for the display in use plus any Python
|
||||
font files in use. The following is required by all applications:
|
||||
The source tree now includes all dependencies. These are listed to enable users
|
||||
to check for newer versions.
|
||||
|
||||
* [writer.py](https://github.com/peterhinch/micropython-font-to-py/blob/master/writer/writer.py)
|
||||
Provides text rendering.
|
||||
|
||||
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).
|
||||
|
||||
|
||||
### 2.2.1 Monochrome use
|
||||
|
||||
OLED displays using the SSD1306 chip require:
|
||||
* [ssd1306_setup.py](https://github.com/peterhinch/micropython-font-to-py/blob/master/writer/ssd1306_setup.py)
|
||||
Contains wiring information.
|
||||
* The official [SSD1306 driver](https://github.com/micropython/micropython/blob/master/drivers/display/ssd1306.py).
|
||||
The official driver for OLED displays using the SSD1306 chip is provided, but
|
||||
the source is here:
|
||||
* [SSD1306 driver](https://github.com/micropython/micropython/blob/master/drivers/display/ssd1306.py).
|
||||
|
||||
Displays based on the PCD8544 chip require:
|
||||
Displays based on the Nokia 5110 (PCD8544 chip) require this driver. It is not
|
||||
in this repo but may be found here:
|
||||
* [PCD8544/Nokia 5110](https://github.com/mcauser/micropython-pcd8544.git)
|
||||
|
||||
### 2.2.2 Color use
|
||||
|
||||
Supported displays amd their drivers are listed below:
|
||||
Drivers for Adafruit 0.96", 1.27" and 1.5" OLEDS and the Sharp display are
|
||||
included in the source tree. Each driver has its own small `README.md`. The
|
||||
default driver for the larger OLEDs is Pyboard specific, but there are cross
|
||||
platform alternatives in the directory.
|
||||
|
||||
* [Adafruit 0.96 inch color OLED](https://github.com/peterhinch/micropython-nano-gui/tree/master/drivers/ssd1331).
|
||||
Driver for SSD1331 controller.
|
||||
* [Adafruit 1.5 and 1.27 inch color OLEDs](./drivers/ssd1351/README.md)
|
||||
Driver for SSD1351 controller.
|
||||
|
||||
Test script for Adafruit 1.5 and 1.27 inch color OLED displays. It's a good
|
||||
idea to paste this at the REPL to ensure the display is working before
|
||||
progressing to the GUI. Remember to change `height` if using the 1.5 inch
|
||||
display.
|
||||
If using the Adafruit 1.5 or 1.27 inch color OLED displays it is suggested that
|
||||
after installing the GUI the following script is pasted at the REPL. This will
|
||||
verify the hardware. Please change `height` to 128 if using the 1.5 inch
|
||||
display. Note the commented-out cross platform alternative.
|
||||
```python
|
||||
import machine
|
||||
from ssd1351 import SSD1351 as SSD
|
||||
|
||||
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)
|
||||
from drivers.ssd1351.ssd1351 import SSD1351 as SSD
|
||||
# from drivers.ssd1351.ssd1351_generic import SSD1351 as SSD
|
||||
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)
|
||||
ssd = SSD(spi, pcs, pdc, prst, height=96) # Ensure height is correct (96/128)
|
||||
ssd.fill(0)
|
||||
ssd.line(0, 0, 127, 95, ssd.rgb(0, 255, 0)) # Green diagonal corner-to-corner
|
||||
ssd.rect(0, 0, 15, 15, ssd.rgb(255, 0, 0)) # Red square at top left
|
||||
ssd.show()
|
||||
```
|
||||
Color applications which do a lot of text rendering may achieve a speed gain by
|
||||
means of
|
||||
[this optimisation](https://github.com/peterhinch/micropython-font-to-py/blob/master/writer/WRITER.md#224-a-performance-boost).
|
||||
|
||||
###### [Contents](./README.md#contents)
|
||||
|
||||
# 3. The nanogui module
|
||||
|
||||
This supports widgets whose text components are drawn using the `Writer`
|
||||
The GUI supports widgets whose text components are drawn using the `Writer`
|
||||
(monochrome) or `CWriter` (colour) classes. Upside down rendering is not
|
||||
supported: attempts to specify it will produce unexpected results.
|
||||
|
||||
|
@ -204,28 +281,29 @@ Widgets are drawn at specific locations on screen and are incompatible with the
|
|||
display of scrolling text: they are therefore not intended for use with the
|
||||
`Writer.printstring` method. The coordinates of a widget are those of its top
|
||||
left corner. If a border is specified, this is drawn outside of the limits of
|
||||
the widgets with a margin of 2 pixels. If the widget is placed at [row, col]
|
||||
the top left hand corner of the border is at [row-2, col-2].
|
||||
the widgets with a margin of 2 pixels. If the widget is placed at `[row, col]`
|
||||
the top left hand corner of the border is at `[row-2, col-2]`.
|
||||
|
||||
When a widget is drawn or updated (typically with its `value` method) it is not
|
||||
immediately displayed. To update the display `nanogui.refresh` is called: this
|
||||
ensures that the `framebuf` contents are updated before copying the contents to
|
||||
the display. This postponement is for performance reasons and to provide the
|
||||
appearance of a rapid update.
|
||||
enables multiple updates to the `framebuf` contents before once copying the
|
||||
buffer to the display. Postponement is for performance and provides a visually
|
||||
rapid update.
|
||||
|
||||
## 3.1 Initialisation
|
||||
|
||||
The GUI is initialised in the following stages. The aim is to allocate the
|
||||
`framebuf` before importing other modules. This is intended to reduce the risk
|
||||
of memory failures when instantiating a large framebuf in an application which
|
||||
imports multiple modules.
|
||||
imports multiple modules. Note that the hardware dependent code is located in
|
||||
`color_setup.py`: it is illustrated here to explain the process.
|
||||
|
||||
Firstly set the display height and import 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 ssd1351 import SSD1351 as SSD # Import the display driver
|
||||
from drivers.ssd1351.ssd1351 import SSD1351 as SSD # Import the display driver
|
||||
```
|
||||
Then set up the bus (SPI or I2C) and instantiate the display. At this point the
|
||||
framebuffer is created:
|
||||
|
@ -242,20 +320,20 @@ modules required by the application. For each font to be used import the
|
|||
Python font and create a `CWriter` instance (for monochrome displays a `Writer`
|
||||
is used):
|
||||
```python
|
||||
from nanogui import Label, Dial, Pointer, refresh # Whatever you need
|
||||
from color_setup import ssd, height # Create a display instance
|
||||
from gui.core.nanogui import refresh
|
||||
from gui.widgets.label import Label # Import any widgets you plan to use
|
||||
from gui.widgets.dial import Dial, Pointer
|
||||
|
||||
refresh(ssd) # Initialise and clear display.
|
||||
|
||||
from writer import CWriter # Import other modules
|
||||
import arial10 # Font
|
||||
GREEN = SSD.rgb(0, 255, 0) # Define colors
|
||||
RED = SSD.rgb(255, 0, 0)
|
||||
BLUE = SSD.rgb(0, 0, 255)
|
||||
YELLOW = SSD.rgb(255, 255, 0)
|
||||
BLACK = 0
|
||||
from gui.core.writer import CWriter # Import other modules
|
||||
import gui.fonts.arial10 # Font
|
||||
from gui.core.colors import * # Define colors
|
||||
|
||||
CWriter.set_textpos(ssd, 0, 0) # In case previous tests have altered it
|
||||
# Instantiate any CWriters to be used (one for each font)
|
||||
wri = CWriter(ssd, arial10, GREEN, BLACK, verbose=False)
|
||||
wri = CWriter(ssd, arial10, GREEN, BLACK, verbose=False) # Colors are defaults
|
||||
wri.set_clip(True, True, False)
|
||||
```
|
||||
|
||||
|
@ -317,17 +395,18 @@ The following is a complete "Hello world" script.
|
|||
height = 96 # 1.27 inch 96*128 (rows*cols) display. Set to 128 for 1.5 inch
|
||||
import machine
|
||||
import gc
|
||||
from ssd1351 import SSD1351 as SSD # Import the display driver
|
||||
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)
|
||||
from drivers.ssd1351.ssd1351 import SSD1351 as SSD
|
||||
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)
|
||||
gc.collect() # Precaution before instantiating framebuf
|
||||
ssd = SSD(spi, pcs, pdc, prst, height) # Create a display instance
|
||||
from nanogui import Label, refresh
|
||||
from gui.core.nanogui import refresh
|
||||
from gui.widgets.label import Label
|
||||
refresh(ssd) # Initialise and clear display.
|
||||
from writer import CWriter # Import other modules
|
||||
import freesans20 # Font
|
||||
from gui.core.writer import CWriter # Import other modules
|
||||
import gui.fonts.freesans20 as freesans20 # Font
|
||||
GREEN = SSD.rgb(0, 255, 0) # Define colors
|
||||
BLACK = 0
|
||||
CWriter.set_textpos(ssd, 0, 0) # In case previous tests have altered it
|
||||
|
@ -521,9 +600,8 @@ This should be amended if the hardware uses a different 8-bit format.
|
|||
The `Writer` (monochrome) or `CWriter` (color) classes and the `nanogui` module
|
||||
should then work automatically.
|
||||
|
||||
If a display uses I2C note that owing to
|
||||
[this issue](https://github.com/micropython/micropython/pull/4020) soft I2C
|
||||
may be required, depending on the detailed specification of the chip.
|
||||
|
||||
Drivers for displays using I2C may need to use
|
||||
[I2C.writevto](http://docs.micropython.org/en/latest/library/machine.I2C.html?highlight=writevto#machine.I2C.writevto)
|
||||
depending on the chip requirements.
|
||||
|
||||
###### [Contents](./README.md#contents)
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
# ssd1351_setup.py Customise for your hardware config
|
||||
# color_setup.py Customise for your hardware config
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2020 Peter Hinch
|
||||
|
||||
# As written, supports:
|
||||
# Adafruit 1.5" 128*128 OLED display: https://www.adafruit.com/product/1431
|
||||
# Adafruit 1.27" 128*96 display https://www.adafruit.com/product/1673
|
||||
# Edit the driver import for other displays.
|
||||
|
||||
# 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.
|
||||
|
@ -17,10 +22,14 @@
|
|||
# Y6 CLK (2 CL SCK)
|
||||
# Y8 DATA (1 SI MOSI)
|
||||
|
||||
height = 96 # 1.27 inch 96*128 (rows*cols) display
|
||||
|
||||
import machine
|
||||
import gc
|
||||
|
||||
# *** Choose your color display driver here ***
|
||||
# Driver supporting non-STM platforms
|
||||
# from drivers.ssd1351.ssd1351_generic import SSD1351 as SSD
|
||||
|
||||
# STM specific driver
|
||||
from drivers.ssd1351.ssd1351 import SSD1351 as SSD
|
||||
|
||||
height = 96 # 1.27 inch 96*128 (rows*cols) display
|
|
@ -74,17 +74,17 @@ The datasheet specifies a minimum refresh rate of 1Hz.
|
|||
3. `clock_batt.py` As above but designed for low power operation. Pyboard
|
||||
specific.
|
||||
|
||||
`sharptest` should not be run for long periods as it does not regularly refresh
|
||||
the display. It tests `writer.py` and some `framebuffer` graphics primitives.
|
||||
`clocktest` tests `nanogui.py`.
|
||||
Tests assume that `nanogui` is installed as per the instructions. `sharptest`
|
||||
should not be run for long periods as it does not regularly refresh the
|
||||
display. It tests `writer.py` and some `framebuffer` graphics primitives.
|
||||
`clocktest` demostrates use with `nanogui`.
|
||||
|
||||
To run the tests the fonts in the directory, `writer.py` and `nanogui.py` must
|
||||
be copied to the device or frozen as bytecode. The `clack_batt.py` demo needs
|
||||
`upower.py` from
|
||||
The `clock_batt.py` demo needs `upower.py` from
|
||||
[micropython-micropower](https://github.com/peterhinch/micropython-micropower).
|
||||
|
||||
Testing was done on a Pyboard D SF6W: frozen bytecode was not required. I
|
||||
suspect a Pyboard 1.x would require it to prevent memory errors.
|
||||
suspect a Pyboard 1.x would require it to prevent memory errors. Fonts in
|
||||
particular benefit from freezing as their RAM usage is radically reduced.
|
||||
|
||||
# 3. Device driver constructor
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
import machine
|
||||
import gc
|
||||
from sharp import SHARP as SSD
|
||||
from drivers.sharp.sharp import SHARP as SSD
|
||||
|
||||
# Initialise hardware
|
||||
pcs = machine.Pin('Y5', machine.Pin.OUT_PP, value=0) # Active high
|
||||
|
@ -30,14 +30,18 @@ ssd = SSD(spi, pcs)
|
|||
|
||||
# Now import other modules
|
||||
import upower
|
||||
from nanogui import Dial, Pointer, refresh, Label
|
||||
from gui.core.nanogui import refresh
|
||||
from gui.widgets.label import Label
|
||||
from gui.widgets.dial import Dial, Pointer
|
||||
|
||||
import pyb
|
||||
import cmath
|
||||
from writer import Writer
|
||||
|
||||
from gui.core.writer import Writer
|
||||
|
||||
# Fonts for Writer
|
||||
import freesans20 as font_small
|
||||
import arial35 as font_large
|
||||
import gui.fonts.freesans20 as font_small
|
||||
import gui.fonts.arial35 as font_large
|
||||
|
||||
refresh(ssd) # Initialise display.
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
import machine
|
||||
import gc
|
||||
from sharp import SHARP as SSD
|
||||
from drivers.sharp.sharp import SHARP as SSD
|
||||
|
||||
# Initialise hardware
|
||||
pcs = machine.Pin('Y5', machine.Pin.OUT_PP, value=0) # Active high
|
||||
|
@ -27,14 +27,18 @@ gc.collect() # Precaution before instantiating framebuf
|
|||
ssd = SSD(spi, pcs)
|
||||
|
||||
# Now import other modules
|
||||
from nanogui import Dial, Pointer, refresh, Label
|
||||
from gui.core.nanogui import refresh
|
||||
from gui.widgets.label import Label
|
||||
from gui.widgets.dial import Dial, Pointer
|
||||
|
||||
import cmath
|
||||
import utime
|
||||
from writer import Writer
|
||||
|
||||
from gui.core.writer import Writer
|
||||
|
||||
# Fonts for Writer
|
||||
import freesans20 as font_small
|
||||
import arial35 as font_large
|
||||
import gui.fonts.freesans20 as font_small
|
||||
import gui.fonts.arial35 as font_large
|
||||
|
||||
refresh(ssd) # Initialise display.
|
||||
|
||||
|
|
|
@ -14,15 +14,18 @@
|
|||
# Y5 CS
|
||||
|
||||
import machine
|
||||
from sharp import SHARP
|
||||
import freesans20, arial_50
|
||||
from writer import Writer
|
||||
from drivers.sharp.sharp import SHARP as SSD
|
||||
# Fonts for Writer
|
||||
import gui.fonts.freesans20 as freesans20
|
||||
import gui.fonts.arial_50 as arial_50
|
||||
|
||||
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 = SHARP(spi, pcs)
|
||||
ssd = SSD(spi, pcs)
|
||||
rhs = ssd.width -1
|
||||
ssd.line(rhs - 80, 0, rhs, 80, 1)
|
||||
square_side = 40
|
||||
|
|
|
@ -3,13 +3,18 @@
|
|||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2020 Peter Hinch
|
||||
|
||||
from drivers.ssd1351.ssd1351 import SSD1351 as SSD
|
||||
from color_setup import SSD
|
||||
|
||||
GREEN = SSD.rgb(0, 255, 0)
|
||||
RED = SSD.rgb(255, 0, 0)
|
||||
LIGHTRED = SSD.rgb(140, 0, 0)
|
||||
BLUE = SSD.rgb(0, 0, 255)
|
||||
YELLOW = SSD.rgb(255, 255, 0)
|
||||
BLACK = 0
|
||||
WHITE = SSD.rgb(255, 255, 255)
|
||||
GREY = SSD.rgb(100, 100, 100)
|
||||
MAGENTA = SSD.rgb(255, 0, 255)
|
||||
CYAN = SSD.rgb(0, 255, 255)
|
||||
LIGHTGREEN = SSD.rgb(0, 100, 0)
|
||||
|
||||
DARKGREEN = SSD.rgb(0, 80, 0)
|
||||
DARKBLUE = SSD.rgb(0, 0, 90)
|
||||
|
|
|
@ -5,18 +5,8 @@
|
|||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2018-2020 Peter Hinch
|
||||
|
||||
# WIRING
|
||||
# Pyb SSD
|
||||
# 3v3 Vin
|
||||
# Gnd Gnd
|
||||
# X1 DC
|
||||
# X2 CS
|
||||
# X3 Rst
|
||||
# X6 CLK
|
||||
# X8 DATA
|
||||
|
||||
# Initialise hardware
|
||||
from ssd1351_setup import ssd, height # Create a display instance
|
||||
# Initialise hardware and framebuf before importing modules.
|
||||
from color_setup import ssd, height # Create a display instance
|
||||
from gui.core.nanogui import refresh
|
||||
from gui.widgets.label import Label
|
||||
from gui.widgets.dial import Dial, Pointer
|
||||
|
|
|
@ -1,28 +1,12 @@
|
|||
# alevel.py Test/demo program for Adafruit ssd1351-based OLED displays
|
||||
# Adafruit 1.5" 128*128 OLED display: https://www.adafruit.com/product/1431
|
||||
# Adafruit 1.27" 128*96 display https://www.adafruit.com/product/1673
|
||||
# alevel.py Test/demo "spirit level" program.
|
||||
# Requires Pyboard for accelerometer.
|
||||
# Tested with Adafruit ssd1351 OLED display.
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2018-2020 Peter Hinch
|
||||
|
||||
# WIRING
|
||||
# Pyb SSD
|
||||
# 3v3 Vin
|
||||
# Gnd Gnd
|
||||
# X1 DC
|
||||
# X2 CS
|
||||
# X3 Rst
|
||||
# X6 CLK
|
||||
# X8 DATA
|
||||
|
||||
# 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.
|
||||
|
||||
import gc
|
||||
|
||||
# Initialise hardware
|
||||
from ssd1351_setup import ssd # Create a display instance
|
||||
# Initialise hardware and framebuf before importing modules.
|
||||
from color_setup import ssd # Create a display instance
|
||||
|
||||
from gui.core.nanogui import refresh
|
||||
from gui.widgets.dial import Dial, Pointer
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
# Copyright (c) 2020 Peter Hinch
|
||||
# Released under the MIT License (MIT) - see LICENSE file
|
||||
|
||||
# Initialise hardware and framebuf before importing modules
|
||||
from ssd1351_setup import ssd # Create a display instance
|
||||
# Initialise hardware and framebuf before importing modules.
|
||||
from color_setup import ssd # Create a display instance
|
||||
|
||||
import uasyncio as asyncio
|
||||
import pyb
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
# asnano_sync.py Test/demo program for use of nanogui with uasyncio
|
||||
# Uses Adafruit ssd1351-based OLED displays (change height to suit)
|
||||
# Adafruit 1.5" 128*128 OLED display: https://www.adafruit.com/product/1431
|
||||
# Adafruit 1.27" 128*96 display https://www.adafruit.com/product/1673
|
||||
# Requires Pyboard for switch and LEDs.
|
||||
# Tested with Adafruit ssd1351 OLED display.
|
||||
|
||||
# Copyright (c) 2020 Peter Hinch
|
||||
# Released under the MIT License (MIT) - see LICENSE file
|
||||
|
||||
# Initialise hardware and framebuf before importing modules
|
||||
from ssd1351_setup import ssd # Create a display instance
|
||||
from color_setup import ssd # Create a display instance
|
||||
|
||||
import uasyncio as asyncio
|
||||
import pyb
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# color15.py Test/demo program for Adafruit ssd1351-based OLED displays
|
||||
# color15.py Test/demo program for larger displays. Cross-platform.
|
||||
# Tested on Adafruit ssd1351-based OLED displays:
|
||||
# Adafruit 1.5" 128*128 OLED display: https://www.adafruit.com/product/1431
|
||||
# Adafruit 1.27" 128*96 display https://www.adafruit.com/product/1673
|
||||
# For wiring details see drivers/ADAFRUIT.md in this repo.
|
||||
|
@ -6,7 +7,8 @@
|
|||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2018-2020 Peter Hinch
|
||||
|
||||
from ssd1351_setup import ssd # Create a display instance
|
||||
# Initialise hardware and framebuf before importing modules.
|
||||
from color_setup import ssd # Create a display instance
|
||||
|
||||
import cmath
|
||||
import utime
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
# color96.py Test/demo program for ssd1331 Adafruit 0.96" OLED display
|
||||
# color96.py Test/demo program for ssd1331 Adafruit 0.96" OLED display.
|
||||
# Cross-platfom.
|
||||
# Works on larger displays, but only occupies the top left region.
|
||||
# https://www.adafruit.com/product/684
|
||||
# For wiring details see drivers/ADAFRUIT.md in this repo.
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2018-2020 Peter Hinch
|
||||
|
||||
from ssd1351_setup import ssd # Create a display instance
|
||||
# Initialise hardware and framebuf before importing modules.
|
||||
from color_setup import ssd # Create a display instance
|
||||
|
||||
from gui.core.nanogui import refresh
|
||||
from gui.widgets.led import LED
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
# fpt.py Test/demo program for framebuf plot
|
||||
# Uses Adafruit ssd1351-based OLED displays (change height to suit)
|
||||
# fpt.py Test/demo program for framebuf plot. Cross-patform,
|
||||
# but requires a large enough display.
|
||||
# Tested on Adafruit ssd1351-based OLED displays:
|
||||
# Adafruit 1.5" 128*128 OLED display: https://www.adafruit.com/product/1431
|
||||
# Adafruit 1.27" 128*96 display https://www.adafruit.com/product/1673
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2018-2020 Peter Hinch
|
||||
|
||||
from ssd1351_setup import ssd # Create a display instance
|
||||
# Initialise hardware and framebuf before importing modules.
|
||||
from color_setup import ssd # Create a display instance
|
||||
|
||||
import cmath
|
||||
import math
|
||||
|
@ -17,7 +19,6 @@ from gui.core.fplot import PolarGraph, PolarCurve, CartesianGraph, Curve, TSeque
|
|||
from gui.core.nanogui import refresh
|
||||
from gui.widgets.label import Label
|
||||
|
||||
|
||||
refresh(ssd)
|
||||
|
||||
# Fonts
|
||||
|
|
|
@ -6,19 +6,33 @@
|
|||
# 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.31 9th Sep 2018
|
||||
# V0.32 5th Nov 2020 Replace uos.urandom for minimal ports
|
||||
|
||||
import utime
|
||||
import uos
|
||||
# import uos
|
||||
from ssd1306_setup import WIDTH, HEIGHT, setup
|
||||
from gui.core.writer import Writer, CWriter
|
||||
from gui.core.nanogui import Label, Meter, refresh
|
||||
from gui.core.nanogui import refresh
|
||||
from gui.widgets.meter import Meter
|
||||
from gui.widgets.label import Label
|
||||
|
||||
# Fonts
|
||||
import gui.fonts.arial10 as arial10
|
||||
import gui.courier20 as fixed
|
||||
import gui.fonts.courier20 as fixed
|
||||
import gui.fonts.font6 as small
|
||||
|
||||
# Some ports don't support uos.urandom.
|
||||
# See https://github.com/peterhinch/micropython-samples/tree/master/random
|
||||
def xorshift64star(modulo, seed = 0xf9ac6ba4):
|
||||
x = seed
|
||||
def func():
|
||||
nonlocal x
|
||||
x ^= x >> 12
|
||||
x ^= ((x << 25) & 0xffffffffffffffff) # modulo 2**64
|
||||
x ^= x >> 27
|
||||
return (x * 0x2545F4914F6CDD1D) % modulo
|
||||
return func
|
||||
|
||||
def fields(use_spi=False, soft=True):
|
||||
ssd = setup(use_spi, soft) # Create a display instance
|
||||
Writer.set_textpos(ssd, 0, 0) # In case previous tests have altered it
|
||||
|
@ -28,9 +42,10 @@ def fields(use_spi=False, soft=True):
|
|||
numfield = Label(wri, 25, 2, wri.stringlen('99.99'), bdcolor=None)
|
||||
countfield = Label(wri, 0, 90, wri.stringlen('1'))
|
||||
n = 1
|
||||
random = xorshift64star(65535)
|
||||
for s in ('short', 'longer', '1', ''):
|
||||
textfield.value(s)
|
||||
numfield.value('{:5.2f}'.format(int.from_bytes(uos.urandom(2),'little')/1000))
|
||||
numfield.value('{:5.2f}'.format(random() /1000))
|
||||
countfield.value('{:1d}'.format(n))
|
||||
n += 1
|
||||
refresh(ssd)
|
||||
|
@ -54,9 +69,10 @@ def multi_fields(use_spi=False, soft=True):
|
|||
nfields.append(Label(wri, y, col, width, bdcolor=None)) # Draw border
|
||||
y += dy
|
||||
|
||||
random = xorshift64star(2**24 - 1)
|
||||
for _ in range(10):
|
||||
for field in nfields:
|
||||
value = int.from_bytes(uos.urandom(3),'little')/167772
|
||||
value = random() / 167772
|
||||
field.value('{:5.2f}'.format(value))
|
||||
refresh(ssd)
|
||||
utime.sleep(1)
|
||||
|
@ -72,8 +88,9 @@ def meter(use_spi=False, soft=True):
|
|||
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'))
|
||||
steps = 10
|
||||
random = xorshift64star(2**24 - 1)
|
||||
for n in range(steps + 1):
|
||||
m0.value(int.from_bytes(uos.urandom(3),'little')/16777216)
|
||||
m0.value(random() / 16777216)
|
||||
m1.value(n/steps)
|
||||
m2.value(1 - n/steps)
|
||||
refresh(ssd)
|
||||
|
|
|
@ -5,8 +5,10 @@
|
|||
|
||||
# Usage:
|
||||
# import gui.demos.scale
|
||||
# Initialise hardware
|
||||
from ssd1351_setup import ssd # Create a display instance
|
||||
|
||||
# Initialise hardware and framebuf before importing modules.
|
||||
from color_setup import ssd # Create a display instance
|
||||
|
||||
from gui.core.nanogui import refresh
|
||||
from gui.core.writer import CWriter
|
||||
|
||||
|
@ -48,12 +50,26 @@ async def default(scale, lbl):
|
|||
|
||||
|
||||
def test():
|
||||
def tickcb(f, c):
|
||||
if f > 0.8:
|
||||
return RED
|
||||
if f < -0.8:
|
||||
return BLUE
|
||||
return c
|
||||
def legendcb(f):
|
||||
return '{:2.0f}'.format(88 + ((f + 1) / 2) * (108 - 88))
|
||||
refresh(ssd) # Initialise and clear display.
|
||||
CWriter.set_textpos(ssd, 0, 0) # In case previous tests have altered it
|
||||
wri = CWriter(ssd, arial10, GREEN, BLACK, verbose=False)
|
||||
wri.set_clip(True, True, False)
|
||||
lbl = Label(wri, ssd.height - wri.height - 2, 0, 50)
|
||||
scale = Scale(wri, 5, 5)
|
||||
scale1 = Scale(wri, 2, 2, width = 124, legendcb = legendcb,
|
||||
pointercolor=RED, fontcolor=YELLOW)
|
||||
asyncio.create_task(radio(scale1))
|
||||
|
||||
lbl = Label(wri, ssd.height - wri.height - 2, 2, 50,
|
||||
bgcolor = DARKGREEN, bdcolor = RED, fgcolor=WHITE)
|
||||
scale = Scale(wri, 45, 2, width = 124, tickcb = tickcb,
|
||||
pointercolor=RED, fontcolor=YELLOW)
|
||||
asyncio.run(default(scale, lbl))
|
||||
|
||||
test()
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
# Usage:
|
||||
# from gui.widgets.scale import Scale
|
||||
|
||||
# NEED print_left, get_stringsize
|
||||
|
||||
from gui.core.nanogui import DObject
|
||||
from gui.core.writer import Writer
|
||||
from gui.core.colors import BLACK
|
||||
|
@ -34,6 +32,7 @@ class Scale(DObject):
|
|||
ctrl_ht = height - min_ht # adjust ticks for greater height
|
||||
width &= 0xfffe # Make divisible by 2: avoid 1 pixel pointer offset
|
||||
super().__init__(writer, row, col, height, width, fgcolor, bgcolor, fgcolor)
|
||||
self.fontcolor = fontcolor if fontcolor is not None else self.fgcolor
|
||||
self.x0 = col + border
|
||||
self.x1 = col + self.width - border
|
||||
self.y0 = row + border
|
||||
|
@ -86,7 +85,7 @@ class Scale(DObject):
|
|||
txt = self.legendcb(self._fvalue(iv * 10))
|
||||
tlen = wri.stringlen(txt)
|
||||
Writer.set_textpos(dev, y0, min(x, x1 - tlen))
|
||||
wri.setcolor(self.fgcolor, self.bgcolor)
|
||||
wri.setcolor(self.fontcolor, self.bgcolor)
|
||||
wri.printstring(txt)
|
||||
wri.setcolor()
|
||||
ys = self.ldy0 # Large tick
|
||||
|
|
Ładowanie…
Reference in New Issue