kopia lustrzana https://github.com/peterhinch/micropython-nano-gui
ST7789 add uasyncio support.
rodzic
7bd781033b
commit
e1a61b67e8
32
DRIVERS.md
32
DRIVERS.md
|
@ -350,13 +350,14 @@ are required. However this period may be unacceptable for some `uasyncio`
|
|||
applications. The driver provides an asynchronous `do_refresh(split=4)` method.
|
||||
If this is run the display will regularly be refreshed, but will periodically
|
||||
yield to the scheduler enabling other tasks to run. The arg determines the
|
||||
number of times this will occur, so by default it will block for about 50ms.
|
||||
A `ValueError` will result if `split` is not an integer divisor of the display
|
||||
height.
|
||||
number of times in a frame where this will occur, so by default it will block
|
||||
for about 50ms. A `ValueError` will result if `split` is not an integer divisor
|
||||
of the `height` passed to the constructor.
|
||||
|
||||
An application using this should call `refresh(ssd, True)` once at the start,
|
||||
then launch the `do_refresh` method. After that, no calls to `refresh` should
|
||||
be made. See `gui/demos/scale_ili.py`.
|
||||
be made. See `gui/demos/scale_async.py`. The initial synchronous `refresh` call
|
||||
will block for the full refresh period.
|
||||
|
||||
Another option to reduce blocking is overclocking the SPI bus.
|
||||
|
||||
|
@ -376,9 +377,6 @@ The response may be of interest.
|
|||
|
||||
## 3.3 Drivers for ST7789
|
||||
|
||||
**UNDER DEVELOPMENT**
|
||||
Initial testing on Adafruit display looks good.
|
||||
|
||||
These displays tend to be physically small with a high pixel density. The chip
|
||||
supports up to 240x320 displays. The Adafruit units tested are 240x240. To keep
|
||||
the buffer size down, the driver uses 4-bit color with dynamic conversion to 16
|
||||
|
@ -394,7 +392,7 @@ uses the same CircuitPython driver so can be expected to work.
|
|||
The `color_setup.py` file should initialise the SPI bus with a baudrate of
|
||||
30_000_000. Args `polarity`, `phase`, `bits`, `firstbit` are defaults. Hard or
|
||||
soft SPI may be used but hard may be faster. 30MHz is a conservative value: see
|
||||
below.
|
||||
below. An example file for the Pi Pico is in `color_setup/ssd7789.py`.
|
||||
|
||||
#### ST7789 Constructor args:
|
||||
* `spi` An initialised SPI bus instance. The chip supports clock rates of upto
|
||||
|
@ -453,8 +451,22 @@ On Adafruit displays, combinations that don't produce mirror images are:
|
|||
|
||||
#### Use with uasyncio
|
||||
|
||||
Running the SPI bus at 60MHz a refresh blocks for 83ms. Considering whether to
|
||||
offer a solution as per ili9341.
|
||||
Running the SPI bus at 60MHz a refresh blocks for 83ms. If this is acceptable,
|
||||
no special precautions are required. This period may be unacceptable for some
|
||||
`uasyncio` applications. Some may use lower SPI baudrates either for electrical
|
||||
reasons or where the host cannot support high speeds.
|
||||
|
||||
The driver provides an asynchronous `do_refresh(split=4)` method. If this is
|
||||
run the display will regularly be refreshed, but will periodically yield to the
|
||||
scheduler enabling other tasks to run. The arg determines the number of times
|
||||
in a frame where this will occur, so by default it will block for about 15ms. A
|
||||
`ValueError` will result if `split` is not an integer divisor of the `height`
|
||||
passed to the constructor.
|
||||
|
||||
An application using this should call `refresh(ssd, True)` once at the start,
|
||||
then launch the `do_refresh` method. After that, no calls to `refresh` should
|
||||
be made. See `gui/demos/scale_async.py`. The initial synchronous `refresh` call
|
||||
will block for the full refresh period.
|
||||
|
||||
###### [Contents](./DRIVERS.md#contents)
|
||||
|
||||
|
|
|
@ -26,15 +26,14 @@
|
|||
from machine import Pin, SPI
|
||||
import gc
|
||||
|
||||
# *** Choose your color display driver here ***
|
||||
|
||||
from drivers.st7789.st7789_4bit import ST7789 as SSD, PORTRAIT, USD
|
||||
from drivers.st7789.st7789_4bit import ST7789 as SSD, PORTRAIT, USD, REFLECT
|
||||
|
||||
pdc = Pin(13, Pin.OUT, value=0) # Arbitrary pins
|
||||
pcs = Pin(14, Pin.OUT, value=1)
|
||||
prst = Pin(15, Pin.OUT, value=1)
|
||||
|
||||
gc.collect() # Precaution before instantiating framebuf
|
||||
spi = SPI(1, 60_000_000, sck=Pin(10), mosi=Pin(11), miso=Pin(8))
|
||||
# Conservative low baudrate. Can go to 62.5MHz.
|
||||
spi = SPI(1, 30_000_000, sck=Pin(10), mosi=Pin(11), miso=Pin(8))
|
||||
ssd = SSD(spi, dc=pdc, cs=pcs, rst=prst) #, disp_mode=PORTRAIT | USD)
|
||||
|
||||
|
|
|
@ -13,27 +13,17 @@
|
|||
# SPI bus: default mode. Driver performs no read cycles.
|
||||
# Datasheet table 6 p44 scl write cycle 16ns == 62.5MHz
|
||||
|
||||
from time import sleep_ms, ticks_us, ticks_diff
|
||||
from time import sleep_ms #, ticks_us, ticks_diff
|
||||
import framebuf
|
||||
import gc
|
||||
import micropython
|
||||
import uasyncio as asyncio
|
||||
|
||||
PORTRAIT = 0x20
|
||||
REFLECT = 0x40
|
||||
USD = 0x80
|
||||
|
||||
|
||||
#_INIT_SEQUENCE = (
|
||||
#b"\x01\x80\x96" # _SWRESET and Delay 150ms
|
||||
#b"\x11\x80\xFF" # _SLPOUT and Delay 500ms
|
||||
#b"\x3A\x81\x55\x0A" # _COLMOD and Delay 10ms
|
||||
#b"\x36\x01\x08" # _MADCTL
|
||||
#b"\x21\x80\x0A" # _INVON Hack and Delay 10ms
|
||||
#b"\x13\x80\x0A" # _NORON and Delay 10ms
|
||||
#b"\x36\x01\xC0" # _MADCTL
|
||||
#b"\x29\x80\xFF" # _DISPON and Delay 500ms
|
||||
#)
|
||||
|
||||
@micropython.viper
|
||||
def _lcopy(dest:ptr8, source:ptr8, lut:ptr8, length:int):
|
||||
n = 0
|
||||
|
@ -62,7 +52,6 @@ class ST7789(framebuf.FrameBuffer):
|
|||
return ((b & 0xf8) << 5 | (g & 0x1c) << 11 | (g & 0xe0) >> 5 | (r & 0xf8)) ^ 0xffff
|
||||
|
||||
# rst and cs are active low, SPI is mode 0
|
||||
# TEST height=140, width=200, disp_mode=PORTRAIT|REFLECT
|
||||
def __init__(self, spi, cs, dc, rst, height=240, width=240, disp_mode=0, init_spi=False):
|
||||
self._spi = spi # Clock cycle time for write 16ns 62.5MHz max (read is 150ns)
|
||||
self._rst = rst # Pins
|
||||
|
@ -167,21 +156,47 @@ class ST7789(framebuf.FrameBuffer):
|
|||
# Row address set
|
||||
self._wcd(b'\x2b', int.to_bytes(ys, 2, 'big') + int.to_bytes(ye, 2, 'big'))
|
||||
|
||||
#@micropython.native # Made virtually no difference to timing.
|
||||
def show(self): # Blocks for 83ms @60MHz SPI
|
||||
# ts = ticks_us()
|
||||
#ts = ticks_us()
|
||||
clut = ST7789.lut
|
||||
wd = self.width // 2
|
||||
end = self.height * wd
|
||||
lb = self._linebuf
|
||||
buf = self._mvb
|
||||
self._dc(0)
|
||||
self._cs(0)
|
||||
if self._spi_init: # A callback was passed
|
||||
self._spi_init(self._spi) # Bus may be shared
|
||||
self._dc(0)
|
||||
self._cs(0)
|
||||
self._spi.write(b'\x2c') # RAMWR
|
||||
self._dc(1)
|
||||
for start in range(0, end, wd):
|
||||
_lcopy(lb, buf[start :], clut, wd) # Copy and map colors
|
||||
self._spi.write(lb)
|
||||
self._cs(1)
|
||||
# print(ticks_diff(ticks_us(), ts))
|
||||
#print(ticks_diff(ticks_us(), ts))
|
||||
|
||||
# Asynchronous refresh with support for reducing blocking time.
|
||||
async def do_refresh(self, split=4):
|
||||
lines, mod = divmod(self.height, split) # Lines per segment
|
||||
if mod:
|
||||
raise ValueError('Invalid do_refresh arg.')
|
||||
clut = ST7789.lut
|
||||
wd = self.width // 2
|
||||
lb = self._linebuf
|
||||
buf = self._mvb
|
||||
while True:
|
||||
line = 0
|
||||
for n in range(split):
|
||||
if self._spi_init: # A callback was passed
|
||||
self._spi_init(self._spi) # Bus may be shared
|
||||
self._dc(0)
|
||||
self._cs(0)
|
||||
self._spi.write(b'\x3c' if n else b'\x2c') # RAMWR/Write memory continue
|
||||
self._dc(1)
|
||||
for start in range(wd * line, wd * (line + lines), wd):
|
||||
_lcopy(lb, buf[start :], clut, wd) # Copy and map colors
|
||||
self._spi.write(lb)
|
||||
line += lines
|
||||
self._cs(1)
|
||||
await asyncio.sleep(0)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# scale_ili.py Test/demo of scale widget for nano-gui
|
||||
# scale_async.py Test/demo of scale widget for nano-gui using asynchronous code
|
||||
# Requires a supporting display (ili9341 or ST7789)
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2020 Peter Hinch
|
Ładowanie…
Reference in New Issue