Add ePaper support. Monochrome setup is now consistent with color.

pull/8/head
Peter Hinch 2021-01-17 16:08:08 +00:00
rodzic bfba0b71a6
commit d92470cb45
14 zmienionych plików z 259 dodań i 204 usunięć

Wyświetl plik

@ -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

Wyświetl plik

@ -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
Wyświetl plik

@ -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)

Wyświetl plik

@ -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)

Wyświetl plik

@ -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)

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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))

Wyświetl plik

@ -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.

Wyświetl plik

@ -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.')

Wyświetl plik

@ -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

Wyświetl plik

@ -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