PR7682 improvements: drivers, writer.py, docs.

pull/8/head
Peter Hinch 2021-08-29 11:50:49 +01:00
rodzic 034b84a199
commit 355cd97981
20 zmienionych plików z 103 dodań i 51 usunięć

Wyświetl plik

@ -24,9 +24,6 @@ Raspberry Pico with an ILI9341 from eBay.
TTGO T-Display. A joystick switch and an SIL resistor make a simple inexpensive
and WiFi-capable system.
Please look at the GitHub Wiki for this project where I am requesting feedback
on an alternative user interface scheme.
# Rationale
Touch GUI's have many advantages, however they have drawbacks, principally cost
@ -61,8 +58,11 @@ target and a C device driver (unless you can acquire a suitable binary).
Code has been tested on ESP32, Pi Pico and Pyboard. The API shuld be stable.
Code is new and issues are likely: please report any found. The project is
under development so check for updates. I also plan to upgrade the performance
of some display drivers.
under development so check for updates.
A recent firmware update [PR7682](https://github.com/micropython/micropython/pull/7682)
has provided a major boost to text rendering speed on color displays. See
[section 1.8](./README.md#18-performance-and-hardware-notes) for details.
# 0. Contents
@ -412,12 +412,23 @@ bytecode: in this configuration running the `various.py` demo there was 29K of
free RAM. Note that, at 37.5KiB, this display is the worst-case in terms of
RAM usage. A smaller display or a Pyboard D would offer more headroom.
#### A performance boost
As of Aug 2021 a firmware update
[PR7682](https://github.com/micropython/micropython/pull/7682) means that color
displays can benefit from a substantial performance boost in rendering text. To
take advantage of this, firmware should be dated after 26 Aug 21. The display
driver and GUI core files should be updated. Ensure that the new file
`drivers/boolpalette.py` exists on the target hardware.
###### [Contents](./README.md#0-contents)
## 1.9 Firmware and dependencies
Firmware should be V1.15 or later. The source tree includes all dependencies.
These are listed to enable users to check for newer versions or to read docs:
Firmware should be V1.15 or later. For fast text rendering a daily build or
a release build >= 1.17 should be used. The source tree includes all
dependencies. These are listed to enable users to check for newer versions or
to read docs:
* [writer.py](https://github.com/peterhinch/micropython-font-to-py/blob/master/writer/writer.py)
Provides text rendering of Python font files.
@ -453,17 +464,14 @@ Display drivers are documented [here](https://github.com/peterhinch/micropython-
## 1.11 Files
Display drivers may be found in the `drivers` directory. These are copies of
those in `nano-gui`, included for convenience.
those in `nano-gui`, included for convenience. Note the file
`drivers/boolpalette.py`, required by all color drivers.
The system is organised as a Python package with the root being `gui`. Core
files in `gui/core` are:
* `colors.py` Constants including colors and shapes.
* `ugui.py` The main GUI code.
* `writer.py` Supports the `Writer` and `CWriter` classes.
* `framebuf_utils.mpy` Accelerator for the `CWriter` class. This optional file
is compiled for STM hardware. It is specific to Pyboards (1.x and D) and will
be ignored on other ports. Details may be found
[here](https://github.com/peterhinch/micropython-font-to-py/blob/master/writer/WRITER.md#224-a-performance-boost).
The `gui/primitives` directory contains the following files:
* `switch.py` Interface to physical pushbuttons.

Wyświetl plik

@ -0,0 +1,20 @@
# boolpalette.py Implement BoolPalette class
# This is a 2-value color palette for rendering monochrome glyphs to color
# FrameBuffer instances. Supports destinations with up to 16 bit color.
# Copyright (c) Peter Hinch 2021
# Released under the MIT license see LICENSE
import framebuf
class BoolPalette(framebuf.FrameBuffer):
def __init__(self, mode):
buf = bytearray(4) # OK for <= 16 bit color
super().__init__(buf, 2, 1, mode)
def fg(self, color): # Set foreground color
self.pixel(1, 0, color)
def bg(self, color):
self.pixel(0, 0, color)

Wyświetl plik

@ -1,7 +1,7 @@
# ILI9341 nano-gui driver for ili9341 displays
# As with all nano-gui displays, touch is not supported.
# Copyright (c) Peter Hinch 2020-2021
# Copyright (c) Peter Hinch 2020
# Released under the MIT license see LICENSE
# This work is based on the following sources.
@ -13,6 +13,7 @@ from time import sleep_ms
import gc
import framebuf
import uasyncio as asyncio
from drivers.boolpalette import BoolPalette
@micropython.viper
def _lcopy(dest:ptr16, source:ptr8, lut:ptr16, length:int):
@ -49,6 +50,7 @@ class ILI9341(framebuf.FrameBuffer):
self.width = width
self._spi_init = init_spi
mode = framebuf.GS4_HMSB
self.palette = BoolPalette(mode)
gc.collect()
buf = bytearray(self.height * self.width // 2)
self._mvb = memoryview(buf)
@ -133,12 +135,7 @@ class ILI9341(framebuf.FrameBuffer):
self._spi.write(lb)
self._cs(1)
def busy(self):
return self._lock.locked()
async def do_refresh(self, split=4):
if self.busy():
print('Warning: refresh paused until prior refresh completed.')
async with self._lock:
lines, mod = divmod(self.height, split) # Lines per segment
if mod:

Wyświetl plik

@ -33,6 +33,8 @@ import framebuf
import utime
import gc
import sys
from drivers.boolpalette import BoolPalette
# https://github.com/peterhinch/micropython-nano-gui/issues/2
# The ESP32 does not work reliably in SPI mode 1,1. Waveforms look correct.
# Mode 0, 0 works on ESP and STM
@ -54,6 +56,7 @@ class SSD1331(framebuf.FrameBuffer):
self.width = width
self._spi_init = init_spi
mode = framebuf.GS8 # Use 8bit greyscale for 8 bit color.
self.palette = BoolPalette(mode)
gc.collect()
self.buffer = bytearray(self.height * self.width)
super().__init__(self.buffer, self.width, self.height, mode)

Wyświetl plik

@ -30,6 +30,7 @@
import framebuf
import utime
import gc
from drivers.boolpalette import BoolPalette
# https://github.com/peterhinch/micropython-nano-gui/issues/2
# The ESP32 does not work reliably in SPI mode 1,1. Waveforms look correct.
@ -52,6 +53,7 @@ class SSD1331(framebuf.FrameBuffer):
self.width = width
self._spi_init = init_spi
mode = framebuf.RGB565
self.palette = BoolPalette(mode)
gc.collect()
self.buffer = bytearray(self.height * self.width * 2)
super().__init__(self.buffer, self.width, self.height, mode)

Wyświetl plik

@ -16,6 +16,7 @@ import utime
import gc
import micropython
from uctypes import addressof
from drivers.boolpalette import BoolPalette
# Timings with standard emitter
# 1.86ms * 128 lines = 240ms. copy dominates: show() took 272ms
@ -90,6 +91,7 @@ class SSD1351(framebuf.FrameBuffer):
self.height = height # Required by Writer class
self.width = width
mode = framebuf.GS8 # Use 8bit greyscale for 8 bit color.
self.palette = BoolPalette(mode)
gc.collect()
self.buffer = bytearray(self.height * self.width)
super().__init__(self.buffer, self.width, self.height, mode)

Wyświetl plik

@ -15,6 +15,7 @@ import utime
import gc
import micropython
from uctypes import addressof
from drivers.boolpalette import BoolPalette
# https://github.com/peterhinch/micropython-nano-gui/issues/2
# The ESP32 does not work reliably in SPI mode 1,1. Waveforms look correct.
@ -59,6 +60,7 @@ class SSD1351(framebuf.FrameBuffer):
self.height = height # Required by Writer class
self.width = width
mode = framebuf.RGB565
self.palette = BoolPalette(mode)
gc.collect()
self.buffer = bytearray(self.height * self.width * 2)
super().__init__(self.buffer, self.width, self.height, mode)

Wyświetl plik

@ -16,6 +16,7 @@ import utime
import gc
import micropython
from uctypes import addressof
from drivers.boolpalette import BoolPalette
# https://github.com/peterhinch/micropython-nano-gui/issues/2
# The ESP32 does not work reliably in SPI mode 1,1. Waveforms look correct.
@ -87,6 +88,7 @@ class SSD1351(framebuf.FrameBuffer):
self.width = width
self.spi_init = init_spi
mode = framebuf.GS4_HMSB # Use 4bit greyscale.
self.palette = BoolPalette(mode)
gc.collect()
self.buffer = bytearray(self.height * self.width // 2)
super().__init__(self.buffer, self.width, self.height, mode)

Wyświetl plik

@ -17,6 +17,7 @@ import utime
import gc
import micropython
from uctypes import addressof
from drivers.boolpalette import BoolPalette
import sys
# https://github.com/peterhinch/micropython-nano-gui/issues/2
@ -77,6 +78,7 @@ class SSD1351(framebuf.FrameBuffer):
self.height = height # Required by Writer class
self.width = width
mode = framebuf.GS8 # Use 8bit greyscale for 8 bit color.
self.palette = BoolPalette(mode)
gc.collect()
self.buffer = bytearray(self.height * self.width)
super().__init__(self.buffer, self.width, self.height, mode)

Wyświetl plik

@ -20,6 +20,7 @@ from time import sleep_ms
import framebuf
import gc
import micropython
from drivers.boolpalette import BoolPalette
# Datasheet para 8.4 scl write cycle 66ns == 15MHz
@ -60,6 +61,7 @@ class ST7735R(framebuf.FrameBuffer):
self.width = width
self._spi_init = init_spi
mode = framebuf.GS8 # Use 8bit greyscale for 8 bit color.
self.palette = BoolPalette(mode)
gc.collect()
buf = bytearray(height * width)
self._mvb = memoryview(buf)

Wyświetl plik

@ -20,6 +20,7 @@ from time import sleep_ms
import framebuf
import gc
import micropython
from drivers.boolpalette import BoolPalette
# Datasheet para 8.4 scl write cycle 66ns == 15MHz
@ -58,6 +59,7 @@ class ST7735R(framebuf.FrameBuffer):
self.width = width
self._spi_init = init_spi
mode = framebuf.GS8 # Use 8bit greyscale for 8 bit color.
self.palette = BoolPalette(mode)
gc.collect()
buf = bytearray(self.height * self.width)
self._mvb = memoryview(buf)

Wyświetl plik

@ -20,6 +20,7 @@ from time import sleep_ms
import framebuf
import gc
import micropython
from drivers.boolpalette import BoolPalette
# Datasheet para 8.4 scl write cycle 66ns == 15MHz
@ -61,6 +62,7 @@ class ST7735R(framebuf.FrameBuffer):
self.width = width
self._spi_init = init_spi
mode = framebuf.GS4_HMSB # Use 4bit greyscale.
self.palette = BoolPalette(mode)
gc.collect()
buf = bytearray(self.height * self.width // 2)
self._mvb = memoryview(buf)

Wyświetl plik

@ -20,6 +20,7 @@ from time import sleep_ms
import framebuf
import gc
import micropython
from drivers.boolpalette import BoolPalette
# Datasheet para 8.4 scl write cycle 66ns == 15MHz
@ -61,6 +62,7 @@ class ST7735R(framebuf.FrameBuffer):
self.width = width
self._spi_init = init_spi
mode = framebuf.GS4_HMSB # Use 4bit greyscale.
self.palette = BoolPalette(mode)
gc.collect()
buf = bytearray(height * width // 2)
self._mvb = memoryview(buf)

Wyświetl plik

@ -21,6 +21,7 @@ import framebuf
import gc
import micropython
import uasyncio as asyncio
from drivers.boolpalette import BoolPalette
# User orientation constants
LANDSCAPE = 0 # Default
@ -73,6 +74,7 @@ class ST7789(framebuf.FrameBuffer):
self._spi_init = init_spi # Possible user callback
self._lock = asyncio.Lock()
mode = framebuf.GS4_HMSB # Use 4bit greyscale.
self.palette = BoolPalette(mode)
gc.collect()
buf = bytearray(height * -(-width // 2)) # Ceiling division for odd widths
self._mvb = memoryview(buf)

Plik binarny nie jest wyświetlany.

Wyświetl plik

@ -1,9 +1,10 @@
# writer.py Implements the Writer class.
# Handles colour, word wrap and tab stops
# V0.40 Jan 2021 Improved handling of word wrap and line clip. Upside-down
# V0.4.3 Aug 2021 Support for fast blit to color displays (PR7682).
# V0.4.0 Jan 2021 Improved handling of word wrap and line clip. Upside-down
# rendering no longer supported: delegate to device driver.
# V0.35 Sept 2020 Fast rendering option for color displays
# V0.3.5 Sept 2020 Fast rendering option for color displays
# Released under the MIT License (MIT). See LICENSE.
# Copyright (c) 2019-2021 Peter Hinch
@ -14,35 +15,34 @@
# Timings based on a 20 pixel high proportional font, run on a pyboard V1.0.
# Using CWriter's slow rendering: _printchar 9.5ms typ, 13.5ms max.
# Using Writer's fast rendering: _printchar 115μs min 480μs typ 950μs max.
# CWriter on Pyboard D SF2W at standard clock rate
# Fast method 500-600μs typical, up to 1.07ms on larger fonts
# Revised fast method 691μs avg, up to 2.14ms on larger fonts
# Slow method 2700μs typical, up to 11ms on larger fonts
import framebuf
from uctypes import bytearray_at, addressof
from sys import platform
from sys import implementation
import os
__version__ = (0, 4, 2)
__version__ = (0, 4, 3)
fast_mode = platform == 'pyboard'
if fast_mode:
def buildcheck(device):
if not hasattr(device, 'palette'):
return False
i0, i1, _ = implementation[1]
if i0 > 1 or i1 > 16:
return True
# After release of V1.17 require that build. Until then check for date.
# TODO simplify this once V1.17 is released.
try:
try:
from framebuf_utils import render
except ImportError: # May be running in GUI. Try relative import.
try:
from .framebuf_utils import render
except ImportError:
fast_mode = False
except ValueError:
fast_mode = False
if not fast_mode:
print('Ignoring missing or invalid framebuf_utils.mpy.')
datestring = os.uname()[3]
date = datestring.split(' on')[1]
date = date.lstrip()[:10]
idate = tuple([int(x) for x in date.split('-')])
return idate >= (2021, 8, 25)
except AttributeError:
return False
fast_mode = False # False for mono displays although actually these render fast
class DisplayState():
def __init__(self):
self.text_row = 0
@ -264,12 +264,14 @@ class Writer():
def setcolor(self, *_):
return self.fgcolor, self.bgcolor
# Writer for colour displays
# Writer for colour displays.
class CWriter(Writer):
def __init__(self, device, font, fgcolor=None, bgcolor=None, verbose=True):
super().__init__(device, font, verbose)
global fast_mode
fast_mode = buildcheck(device)
if bgcolor is not None: # Assume monochrome.
self.bgcolor = bgcolor
if fgcolor is not None:
@ -285,11 +287,12 @@ class CWriter(Writer):
if self.glyph is None:
return # All done
buf = bytearray_at(addressof(self.glyph), len(self.glyph))
fbc = framebuf.FrameBuffer(buf, self.char_width, self.char_height, self.map)
fgcolor = self.bgcolor if invert else self.fgcolor
bgcolor = self.fgcolor if invert else self.bgcolor
# render clips a glyph if outside bounds of destination
render(self.device, fbc, s.text_col, s.text_row, fgcolor, bgcolor)
fbc = framebuf.FrameBuffer(buf, self.clip_width, self.char_height, self.map)
palette = self.device.palette
palette.bg(self.fgcolor if invert else self.bgcolor)
palette.fg(self.bgcolor if invert else self.fgcolor)
self.device.blit(fbc, s.text_col, s.text_row, -1, palette)
s.text_col += self.char_width
self.cpos += 1

Wyświetl plik

@ -69,7 +69,7 @@ class BaseScreen(Screen):
'bgcolor' : DARKGREEN,
}
wri = CWriter(ssd, font, GREEN, BLACK, verbose=False)
wri = CWriter(ssd, font, GREEN, BLACK) # verbose = True
dial = Dial(wri, 2, 2, height = 70, ticks = 12,
fgcolor = GREEN, pip = GREEN)
# Set up clock display: instantiate labels

Wyświetl plik

@ -24,8 +24,8 @@ class BaseScreen(Screen):
print('Button pressed', arg)
super().__init__()
wri = CWriter(ssd, arial10, GREEN, BLACK, verbose=False)
# verbose default indicates if fast rendering is enabled
wri = CWriter(ssd, arial10, GREEN, BLACK)
col = 2
row = 2
Label(wri, row, col, 'Simple Demo')

Wyświetl plik

@ -19,7 +19,7 @@ from gui.widgets.label import Label
from gui.widgets.textbox import Textbox
from gui.widgets.buttons import Button, CloseButton
wri = CWriter(ssd, arial10, verbose=False)
wri = CWriter(ssd, arial10) # verbose = True
def fwdbutton(wri, row, col, cls_screen, text='Next'):
def fwd(button):

Wyświetl plik

@ -3,6 +3,7 @@
# Copyright (c) 2021 Peter Hinch
# Released under the MIT License (MIT) - see LICENSE file
# https://github.com/peterhinch/micropython-async/blob/master/v3/primitives/encoder.py
# This driver is intended for encoder-based control knobs. It is
# unsuitable for NC machine applications. Please see the docs.