kopia lustrzana https://github.com/peterhinch/micropython-micro-gui
PR7682 improvements: drivers, writer.py, docs.
rodzic
034b84a199
commit
355cd97981
32
README.md
32
README.md
|
@ -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.
|
||||
|
|
|
@ -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)
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
# 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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue