kopia lustrzana https://github.com/peterhinch/micropython-nano-gui
PR7682 improvements: drivers, writer.py, docs.
rodzic
31368b751c
commit
dbc4f4689b
16
DRIVERS.md
16
DRIVERS.md
|
@ -1085,6 +1085,22 @@ long as `.rgb()` and the "on the fly" converter match, this is arbitrary.
|
|||
The `Writer` (monochrome) or `CWriter` (color) classes and the `nanogui` module
|
||||
should then work automatically.
|
||||
|
||||
For color displays the following provides a substantial performance boost when
|
||||
rendering text.
|
||||
```python
|
||||
from drivers.boolpalette import BoolPalette
|
||||
```
|
||||
and, in `__init__.py`:
|
||||
```python
|
||||
mode = framebuf.GS4_HMSB # The format to be used by the driver
|
||||
self.palette = BoolPalette(mode)
|
||||
gc.collect()
|
||||
buf = bytearray(self.height * self.width // 2) # Computation must match the format
|
||||
super().__init__(buf, self.width, self.height, mode)
|
||||
```
|
||||
Assuming firmware dated after 26th Aug 2021, a fast C blit will be used to
|
||||
render glyphs instead of Python code.
|
||||
|
||||
The following script is useful for testing color display drivers after
|
||||
configuring `color_setup.py`. It draws squares at the extreme corners of the
|
||||
display and a corner to corner diagonal.
|
||||
|
|
25
README.md
25
README.md
|
@ -49,6 +49,7 @@ wiring details, pin names and hardware issues.
|
|||
1.1 [Change log](./README.md#11-change-log)
|
||||
1.2 [Description](./README.md#12-description)
|
||||
1.3 [Quick start](./README.md#13-quick-start)
|
||||
1.4 [A performance boost](./README.md#14-a-performance-boost)
|
||||
2. [Files and Dependencies](./README.md#2-files-and-dependencies)
|
||||
2.1 [Files](./README.md#21-files)
|
||||
2.1.1 [Core files](./README.md#211-core-files)
|
||||
|
@ -93,8 +94,7 @@ on ESP8266 is possible but frozen bytecode must be used owing to its restricted
|
|||
RAM.
|
||||
|
||||
As of 14th March 2021 it runs on the Raspberry Pi Pico; on that target firmware
|
||||
must be of that date or later. The `color15` demo fails because the firmware
|
||||
lacks `uos.urandom()` but hopefully it will be fixed soon.
|
||||
must be of that date or later.
|
||||
|
||||
It uses synchronous code but is compatible with `uasyncio`. Some demo programs
|
||||
illustrate this. Code is standard MicroPython, but some device drivers use the
|
||||
|
@ -108,10 +108,12 @@ displays:
|
|||
* [SSD1963 large displays](https://github.com/peterhinch/micropython-tft-gui)
|
||||
|
||||
For historical reasons and to ensure consistency, code and documentation for
|
||||
my GUI's employ the American spelling of `color`.
|
||||
my GUI's employ the American spelling of `color`.
|
||||
|
||||
## 1.1 Change log
|
||||
|
||||
26 Aug 2021 Support [PR7682](https://github.com/micropython/micropython/pull/7682)
|
||||
for fast text rendering.
|
||||
25 Apr 2021 Support TTGO T-Display.
|
||||
26 Mar 2021 Add ST7789. Alter uasyncio support on ili9341.
|
||||
14 Mar 2021 Tested on Pi Pico.
|
||||
|
@ -204,12 +206,19 @@ OLED as per `color_setup.py`, move to the root directory of the repo and run
|
|||
Note also that the `gui.demos.aclock.py` demo comprises 38 lines of actual
|
||||
code. This stuff is easier than you might think.
|
||||
|
||||
## 1.4 A performance boost
|
||||
|
||||
As of Aug 2021 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#contents)
|
||||
|
||||
# 2. Files and Dependencies
|
||||
|
||||
Firmware should be V1.13 or later. On the Pi Pico firmware should be V1.15 or
|
||||
later.
|
||||
later. For fast text rendering use a daily build or V1.17 or later.
|
||||
|
||||
Installation comprises copying the `gui` and `drivers` directories, with their
|
||||
contents, plus a hardware configuration file, to the target. The directory
|
||||
|
@ -248,10 +257,6 @@ The `gui/core` directory contains the GUI core and its principal dependencies:
|
|||
* `writer.py` Module for rendering Python fonts.
|
||||
* `fplot.py` The graph plotting module.
|
||||
* `colors.py` Color constants.
|
||||
* `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).
|
||||
|
||||
###### [Contents](./README.md#contents)
|
||||
|
||||
|
@ -348,10 +353,6 @@ to check for newer versions:
|
|||
* [writer.py](https://github.com/peterhinch/micropython-font-to-py/blob/master/writer/writer.py)
|
||||
Provides text rendering of Python font files.
|
||||
|
||||
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).
|
||||
|
||||
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).
|
||||
|
|
|
@ -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)
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
@ -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 or upside down rendering
|
||||
# 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
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue