kopia lustrzana https://github.com/peterhinch/micropython-nano-gui
Add UNSTABLE st7789 driver.
rodzic
396773f284
commit
0ad88e3512
205
DRIVERS.md
205
DRIVERS.md
|
@ -18,36 +18,39 @@ a bare minimum of functionality required to support the above.
|
|||
|
||||
1. [Introduction](./DRIVERS.md#1-introduction)
|
||||
1.1 [Color handling](./DRIVERS.md#11-color-handling)
|
||||
2. [Drivers for SSD1351](./DRIVERS.md#2-drivers-for-ssd1351) Color OLEDs
|
||||
3. [Drivers for SSD1331](./DRIVERS.md#3-drivers-for-ssd1331) Small color OLEDs
|
||||
4. [Drivers for ST7735R](./DRIVERS.md#4-drivers-for-st7735r) Small color TFTs
|
||||
5. [Drivers for ILI9341](./DRIVERS.md#5-drivers-for-ili9341) Large color TFTs
|
||||
6. [Drivers for sharp displays](./DRIVERS.md#6-drivers-for-sharp-displays) Large low power monochrome displays
|
||||
6.1 [Display characteristics](./DRIVERS.md#61-display-characteristics)
|
||||
6.1.1 [The VCOM bit](./DRIVERS.md#611-the-vcom-bit)
|
||||
6.1.2 [Refresh rate](./DRIVERS.md#612-refresh-rate)
|
||||
6.2 [Test scripts](./DRIVERS.md#62-test-scripts)
|
||||
6.3 [Device driver constructor](./DRIVERS.md#63-device-driver-constructor)
|
||||
6.3.1 [Device driver methods](./DRIVERS.md#631-device-driver-methods)
|
||||
6.3.2 [The vcom arg](./DRIVERS.md#632-the-vcom-arg)
|
||||
6.4 [Application design](./DRIVERS.md#64-application-design)
|
||||
6.4.1 [Micropower applications](./DRIVERS.md#641-micropower-applications)
|
||||
6.5 [Resources](./DRIVERS.md#65-resources)
|
||||
7. [ePaper displays](./DRIVERS.md#7-epaper-displays)
|
||||
7.1 [Adafruit monochrome eInk Displays](./DRIVERS.md#71-adafruit-monochrome-eink-displays)
|
||||
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.1.3 [EPD public bound variables](./DRIVERS.md#713-epd-public-bound-variables)
|
||||
7.1.4 [FeatherWing Wiring](./DRIVERS.md#714-featherwing-wiring)
|
||||
7.1.5 [Micropower use](./DRIVERS.md#715-micropower-use)
|
||||
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#9-writing-device-drivers)
|
||||
2. [OLED displays](./DRIVERS.md#2-oled-displays)
|
||||
2.1 [Drivers for SSD1351](./DRIVERS.md#21-drivers-for-ssd1351) Color OLEDs
|
||||
2.2 [Drivers for SSD1331](./DRIVERS.md#22-drivers-for-ssd1331) Small color OLEDs
|
||||
3. [Color TFT displays](./DRIVERS.md#3-color-tft-displays)
|
||||
3.1 [Drivers for ST7735R](./DRIVERS.md#31-drivers-for-st7735r) Small TFTs
|
||||
3.2 [Drivers for ILI9341](./DRIVERS.md#32-drivers-for-ili9341) Large TFTs
|
||||
3.3 [Drivers for ST7789](./DRIVERS.md#33-drivers-for-st7789) Small high density TFTs
|
||||
4. [Drivers for sharp displays](./DRIVERS.md#4-drivers-for-sharp-displays) Large low power monochrome displays
|
||||
4.1 [Display characteristics](./DRIVERS.md#41-display-characteristics)
|
||||
4.1.1 [The VCOM bit](./DRIVERS.md#411-the-vcom-bit)
|
||||
4.1.2 [Refresh rate](./DRIVERS.md#412-refresh-rate)
|
||||
4.2 [Test scripts](./DRIVERS.md#42-test-scripts)
|
||||
4.3 [Device driver constructor](./DRIVERS.md#43-device-driver-constructor)
|
||||
4.3.1 [Device driver methods](./DRIVERS.md#431-device-driver-methods)
|
||||
4.3.2 [The vcom arg](./DRIVERS.md#432-the-vcom-arg)
|
||||
4.4 [Application design](./DRIVERS.md#44-application-design)
|
||||
4.4.1 [Micropower applications](./DRIVERS.md#441-micropower-applications)
|
||||
4.5 [Resources](./DRIVERS.md#45-resources)
|
||||
5. [ePaper displays](./DRIVERS.md#5-epaper-displays)
|
||||
5.1 [Adafruit monochrome eInk Displays](./DRIVERS.md#51-adafruit-monochrome-eink-displays)
|
||||
5.1.1 [EPD constructor args](./DRIVERS.md#511-epd-constructor-args)
|
||||
5.1.2 [EPD public methods](./DRIVERS.md#512-epd-public-methods)
|
||||
5.1.3 [EPD public bound variables](./DRIVERS.md#513-epd-public-bound-variables)
|
||||
5.1.4 [FeatherWing Wiring](./DRIVERS.md#514-featherwing-wiring)
|
||||
5.1.5 [Micropower use](./DRIVERS.md#515-micropower-use)
|
||||
5.2 [Waveshare eInk Display HAT](./DRIVERS.md#52-waveshare-eink-display-hat)
|
||||
5.2.1 [EPD constructor args](./DRIVERS.md#521-epd-constructor-args)
|
||||
5.2.2 [EPD public methods](./DRIVERS.md#522-epd-public-methods)
|
||||
5.2.3 [EPD public bound variables](./DRIVERS.md#523-epd-public-bound-variables)
|
||||
6. [EPD Asynchronous support](./DRIVERS.md#6-epd-asynchronous-support)
|
||||
7. [Writing device drivers](./DRIVERS.md#7-writing-device-drivers)
|
||||
|
||||
The [Micropower use](./DRIVERS.md#715-micropower-use) section is applicable to
|
||||
The [Micropower use](./DRIVERS.md#515-micropower-use) section is applicable to
|
||||
EPD's in general but makes specific reference to the 2.9" micropower demo.
|
||||
|
||||
###### [Main README](./README.md#1-introduction)
|
||||
|
@ -96,7 +99,9 @@ specifying custom colors. For detail see the main README
|
|||
|
||||
###### [Contents](./DRIVERS.md#contents)
|
||||
|
||||
# 2. Drivers for SSD1351
|
||||
# 2. OLED displays
|
||||
|
||||
## 2.1 Drivers for SSD1351
|
||||
|
||||
This is an OLED driver. The supported displays produce excellent images with
|
||||
extreme contrast and bright colors. Power consumption is low.
|
||||
|
@ -173,7 +178,7 @@ color streams sent to the display are:
|
|||
|
||||
###### [Contents](./DRIVERS.md#contents)
|
||||
|
||||
# 3. Drivers for SSD1331
|
||||
## 2.2 Drivers for SSD1331
|
||||
|
||||
This is an OLED driver for small displays. The supported display produces
|
||||
excellent images with extreme contrast and bright colors. Power consumption is
|
||||
|
@ -219,7 +224,9 @@ def spi_init(spi):
|
|||
|
||||
###### [Contents](./DRIVERS.md#contents)
|
||||
|
||||
# 4. Drivers for ST7735R
|
||||
# 3. Color TFT displays
|
||||
|
||||
## 3.1 Drivers for ST7735R
|
||||
|
||||
This chip is for small TFT displays. Four drivers are provided. All are
|
||||
cross-platform but assume `micropython.viper` capability. They use 8-bit or
|
||||
|
@ -287,7 +294,7 @@ def spi_init(spi):
|
|||
|
||||
###### [Contents](./DRIVERS.md#contents)
|
||||
|
||||
# 5. Drivers for ILI9341
|
||||
## 3.2 Drivers for ILI9341
|
||||
|
||||
Adafruit make several displays using this chip, for example
|
||||
[this 3.2 inch unit](https://www.adafruit.com/product/1743).
|
||||
|
@ -360,7 +367,83 @@ The response may be of interest.
|
|||
|
||||
###### [Contents](./DRIVERS.md#contents)
|
||||
|
||||
# 6. Drivers for sharp displays
|
||||
## 3.3 Drivers for ST7789
|
||||
|
||||
** UNDER DEVELOPMENT **
|
||||
Works on Adafruit display in landscape mode. Anything else is dubious.
|
||||
|
||||
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
|
||||
bit RGB565 at runtime. This uses a lookup table (LUT) enabling user defined
|
||||
colors. The resultant buffer size for the Adafruit displays is 28800 bytes.
|
||||
|
||||
[Tested display](# https://www.adafruit.com/product/4313). The Adafruit
|
||||
[1.54 inch](https://www.adafruit.com/product/3787) has identical resolution and
|
||||
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.
|
||||
|
||||
#### ST7789 Constructor args:
|
||||
* `spi` An initialised SPI bus instance. The chip supports clock rates of upto
|
||||
62.5MHz (datasheet table 6). I have tested 60MHz. High speeds may be sensitive
|
||||
to electrical issues such as lead lengths, PCB layout and grounding.
|
||||
* `cs` An initialised output pin. Initial value should be 1.
|
||||
* `dc` An initialised output pin. Initial value should be 0.
|
||||
* `rst` An initialised output pin. Initial value should be 1.
|
||||
* `height=240` Display dimensions in pixels. For portrait mode exchange
|
||||
`height` and `width` values: this ensures that `nano-gui` gets the correct
|
||||
aspect ratio.
|
||||
* `width=240`
|
||||
* `disp_mode=0` By default the display chip operates in landscape mode. This
|
||||
arg enables portrait mode and other configurations. See below.
|
||||
* `init_spi=False` This optional arg enables flexible options in configuring
|
||||
the SPI bus. The default assumes exclusive access to the bus. In this normal
|
||||
case, `color_setup.py` initialises it and the settings will be left in place.
|
||||
If the bus is shared with devices which require different settings, a callback
|
||||
function should be passed. It will be called prior to each SPI bus write. The
|
||||
callback will receive a single arg being the SPI bus instance. It will
|
||||
typically be a one-liner or lambda initialising the bus. A minimal example is
|
||||
this function:
|
||||
```python
|
||||
def spi_init(spi):
|
||||
spi.init(baudrate=30_000_000)
|
||||
```
|
||||
#### Display mode
|
||||
|
||||
This is povided in the hope of supporting other displays which may not be
|
||||
symmetrical. It also enables the Adafruit display image to be rotated.
|
||||
|
||||
The driver exports the following constants:
|
||||
```python
|
||||
PORTRAIT = 0x20 # Rotate 90°
|
||||
REFLECT = 0x40 # Swap pixels left-right
|
||||
USD = 0x80 # Upside down: swap pixels top-bottom
|
||||
```
|
||||
For non-standard modes these may be combined using the bitwise-or `|` operator.
|
||||
Exammple `color_setup.py` is for Pi Pico.
|
||||
```python
|
||||
from drivers.st7789.st7789_4bit import ST7789 as SSD, PORTRAIT, USD
|
||||
|
||||
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, 40_000_000, sck=Pin(10), mosi=Pin(11), miso=Pin(8))
|
||||
ssd = SSD(spi, dc=pdc, cs=pcs, rst=prst, disp_mode=PORTRAIT | USD)
|
||||
```
|
||||
On Adafruit displays, valid combinations are:
|
||||
1. No arg: landscape mode.
|
||||
2. `USD | REFLECT` Upside down landscape mode (rotate 180°).
|
||||
3. `PORTRAIT | REFLECT` Portrait mode (rotate 90°)
|
||||
|
||||
###### [Contents](./DRIVERS.md#contents)
|
||||
|
||||
# 4. Drivers for sharp displays
|
||||
|
||||
These displays have characteristics which mean that they are best suited to
|
||||
micropower applications. Inevitably this means that deployment is more involved
|
||||
|
@ -376,7 +459,7 @@ I have tested on the first of these. However the
|
|||
[Adfruit driver](https://github.com/adafruit/Adafruit_CircuitPython_SharpMemoryDisplay)
|
||||
supports all of these and I would expect this one also to do so.
|
||||
|
||||
## 6.1. Display characteristics
|
||||
## 4.1. Display characteristics
|
||||
|
||||
These displays have extremely low current consumption: I measured ~90μA on the
|
||||
2.7" board when in use. Refresh is fast, visually excellent and can run at up
|
||||
|
@ -395,7 +478,7 @@ fonts. In other respects the display quality is not as good as ePaper. For good
|
|||
contrast best results are achieved if the viewing angle and the direction of
|
||||
the light source are positioned to achieve reflection.
|
||||
|
||||
### 6.1.1 The VCOM bit
|
||||
### 4.1.1 The VCOM bit
|
||||
|
||||
The significance of this is somewhat glossed-over in the Adafruit docs, and a
|
||||
study of the datasheet is confusing in the absence of prior knowledge of LCD
|
||||
|
@ -430,11 +513,11 @@ In my opinion the easiest way to deal with this is usually to use software
|
|||
control, ensuring that the driver's `show` method is called at regular
|
||||
intervals of at least 1Hz.
|
||||
|
||||
### 6.1.2 Refresh rate
|
||||
### 4.1.2 Refresh rate
|
||||
|
||||
The datasheet specifies a minimum refresh rate of 1Hz.
|
||||
|
||||
## 6.2. Test scripts
|
||||
## 4.2. Test scripts
|
||||
|
||||
1. `sharptest.py` Basic functionality test.
|
||||
2. `clocktest.py` Digital and analog clock display.
|
||||
|
@ -453,7 +536,7 @@ Testing was done on a Pyboard D SF6W: frozen bytecode was not required. I
|
|||
suspect a Pyboard 1.x would require it to prevent memory errors. Fonts in
|
||||
particular benefit from freezing as their RAM usage is radically reduced.
|
||||
|
||||
## 6.3. Device driver constructor
|
||||
## 4.3. Device driver constructor
|
||||
|
||||
Positional args:
|
||||
1. `spi` An SPI bus instance. The constructor initialises this to the baudrate
|
||||
|
@ -463,9 +546,9 @@ Positional args:
|
|||
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
|
||||
[6.3.2](./DRIVERS.md#632-the-vcom-arg).
|
||||
[4.3.2](./DRIVERS.md#432-the-vcom-arg).
|
||||
|
||||
### 6.3.1 Device driver methods
|
||||
### 4.3.1 Device driver methods
|
||||
|
||||
1. `show` No args. Transfers the framebuffer contents to the device, updating
|
||||
the display.
|
||||
|
@ -473,7 +556,7 @@ Positional args:
|
|||
is a power saving method for cases where the application calls `show` at a
|
||||
rate of < 1Hz. In such cases `update` should be called at a 1Hz rate.
|
||||
|
||||
### 6.3.2 The vcom arg
|
||||
### 4.3.2 The vcom arg
|
||||
|
||||
It purpose is to support micropower applications which use `pyb.standby`.
|
||||
Wakeup from standby is similar to a reboot in that program execution starts
|
||||
|
@ -486,14 +569,14 @@ Persistent storage exists in the RTC registers and backup RAM. See
|
|||
[micopython-micropower](https://github.com/peterhinch/micropython-micropower)
|
||||
for details of how to acces these resources.
|
||||
|
||||
## 6.4. Application design
|
||||
## 4.4. Application design
|
||||
|
||||
In all cases the frame buffer is located on the target hardware. In the case of
|
||||
the 2.7 inch display this is 400*240//8 = 12000 bytes in size. This should be
|
||||
instantiated as soon as possible in the application to ensure that sufficient
|
||||
contiguous RAM is available.
|
||||
|
||||
### 6.4.1 Micropower applications
|
||||
### 4.4.1 Micropower applications
|
||||
|
||||
These comments largely assume a Pyboard host. The application should import
|
||||
`upower` from
|
||||
|
@ -515,7 +598,7 @@ frozen bytecode is used, there is still significant power usage importing
|
|||
modules and instantiating classes; this usage is not incurred in the loop in
|
||||
the demo.
|
||||
|
||||
## 6.5. Resources
|
||||
## 4.5. Resources
|
||||
|
||||
[Schematic for 2.7" unit](https://learn.adafruit.com/assets/94077)
|
||||
|
||||
|
@ -525,7 +608,7 @@ the demo.
|
|||
|
||||
###### [Contents](./DRIVERS.md#contents)
|
||||
|
||||
# 7. ePaper displays
|
||||
# 5. ePaper displays
|
||||
|
||||
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
|
||||
|
@ -540,9 +623,9 @@ methods only and the standard demos (some of which use `uasyncio`) may be run.
|
|||
However copying the framebuffer to the device blocks for some time - 250ms or
|
||||
more - which may be problematic for applications which need to respond to
|
||||
external events. A specific asynchronous mode provides support for reducing
|
||||
blocking time. See [EPD Asynchronous support](./DRIVERS.md#8-epd-asynchronous-support).
|
||||
blocking time. See [EPD Asynchronous support](./DRIVERS.md#6-epd-asynchronous-support).
|
||||
|
||||
## 7.1 Adafruit monochrome eInk Displays
|
||||
## 5.1 Adafruit monochrome eInk Displays
|
||||
|
||||
The driver supports two Adafruit 2.9 inch 296*128 pixel units. A flexible
|
||||
[display](https://www.adafruit.com/product/4262) interfaced via their
|
||||
|
@ -550,7 +633,7 @@ The driver supports two Adafruit 2.9 inch 296*128 pixel units. A flexible
|
|||
|
||||
An alternative is the
|
||||
[Adafruit 2.9" eInk FeatherWing](https://www.adafruit.com/product/4777) with
|
||||
[wiring details](./DRIVERS.md#714-featherwing-wiring) listed below.
|
||||
[wiring details](./DRIVERS.md#514-featherwing-wiring) listed below.
|
||||
|
||||
In my testing there are differences between these alternatives. The FeatherWing
|
||||
shows a black border around the display. The reason for this is
|
||||
|
@ -595,7 +678,7 @@ used.
|
|||
In normal use the `ENA` pin (12) may be left unconnected. For micropower use,
|
||||
see below.
|
||||
|
||||
### 7.1.1 EPD constructor args
|
||||
### 5.1.1 EPD constructor args
|
||||
* `spi` An initialised SPI bus instance. The device can support clock rates of
|
||||
upto 10MHz.
|
||||
* `cs` An initialised output pin. Initial value should be 1.
|
||||
|
@ -604,9 +687,9 @@ see below.
|
|||
* `busy` An initialised input pin.
|
||||
* `landscape=True` By default the long axis is horizontal.
|
||||
* `asyn=False` Setting this `True` invokes an asynchronous mode. See
|
||||
[EPD Asynchronous support](./DRIVERS.md#8-epd-asynchronous-support).
|
||||
[EPD Asynchronous support](./DRIVERS.md#6-epd-asynchronous-support).
|
||||
|
||||
### 7.1.2 EPD public methods
|
||||
### 5.1.2 EPD public methods
|
||||
|
||||
##### Synchronous methods
|
||||
* `init` No args. Issues a hardware reset and initialises the hardware. This
|
||||
|
@ -624,7 +707,7 @@ see below.
|
|||
to the display.
|
||||
* `wait` Asynchronous. No args. Pause until the display refresh is complete.
|
||||
|
||||
### 7.1.3 EPD public bound variables
|
||||
### 5.1.3 EPD public bound variables
|
||||
|
||||
* `height` Integer. Height in pixels. Treat as read-only.
|
||||
* `width` Integer. Width in pixels. Treat as read-only.
|
||||
|
@ -633,7 +716,7 @@ see below.
|
|||
seconds to enable viewing. This enables generic nanogui demos to be run on an
|
||||
EPD.
|
||||
|
||||
### 7.1.4 FeatherWing wiring
|
||||
### 5.1.4 FeatherWing wiring
|
||||
|
||||
The [pinout is listed here](https://learn.adafruit.com/adafruit-eink-display-breakouts/pinouts-2).
|
||||
The `busy` line is brought out to a labelled pad on the PCB. It can be linked
|
||||
|
@ -666,7 +749,7 @@ The FeatherWing has a reset button which shorts the RST line to Gnd. To avoid
|
|||
risk of damage to the microcontroller pin if the button is pressed, the pin
|
||||
should be configured as open drain.
|
||||
|
||||
### 7.1.5 Micropower use
|
||||
### 5.1.5 Micropower use
|
||||
|
||||
Developers of micropower applications will need to familiarise themselves with
|
||||
the power saving features of their board. Information may be found in
|
||||
|
@ -733,7 +816,7 @@ of magnitude improvement.
|
|||
|
||||
###### [Contents](./DRIVERS.md#contents)
|
||||
|
||||
## 7.2 Waveshare eInk Display HAT
|
||||
## 5.2 Waveshare eInk Display HAT
|
||||
|
||||
This 2.7" 176*274 display is designed for the Raspberry Pi and is detailed
|
||||
[here](https://www.waveshare.com/wiki/2.7inch_e-Paper_HAT).
|
||||
|
@ -772,7 +855,7 @@ powered from 5V or 3.3V: there is a regulator on board.
|
|||
|
||||
Pins 26-40 unused and omitted.
|
||||
|
||||
### 7.2.1 EPD constructor args
|
||||
### 5.2.1 EPD constructor args
|
||||
* `spi` An initialised SPI bus instance. The device can support clock rates of
|
||||
upto 2MHz.
|
||||
* `cs` An initialised output pin. Initial value should be 1.
|
||||
|
@ -782,7 +865,7 @@ Pins 26-40 unused and omitted.
|
|||
* `landscape=False` By default the long axis is vertical.
|
||||
* `asyn=False`
|
||||
|
||||
### 7.2.2 EPD public methods
|
||||
### 5.2.2 EPD public methods
|
||||
|
||||
##### Synchronous methods
|
||||
* `init` No args. Issues a hardware reset and initialises the hardware. This
|
||||
|
@ -800,7 +883,7 @@ 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
|
||||
### 5.2.3 EPD public bound variables
|
||||
|
||||
* `height` Integer. Height in pixels. Treat as read-only.
|
||||
* `width` Integer. Width in pixels. Treat as read-only.
|
||||
|
@ -811,7 +894,7 @@ Pins 26-40 unused and omitted.
|
|||
|
||||
###### [Contents](./DRIVERS.md#contents)
|
||||
|
||||
# 8. EPD Asynchronous support
|
||||
# 6. EPD Asynchronous support
|
||||
|
||||
Normally when GUI code issues
|
||||
```python
|
||||
|
@ -854,7 +937,7 @@ The following illustrates the kind of approach which may be used:
|
|||
|
||||
###### [Contents](./DRIVERS.md#contents)
|
||||
|
||||
# 9. Writing device drivers
|
||||
# 7. Writing device drivers
|
||||
|
||||
Device drivers capable of supporting `nanogui` can be extremely simple: see
|
||||
`drivers/sharp/sharp.py` for a minimal example. It should be noted that the
|
||||
|
|
|
@ -355,14 +355,15 @@ 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.colors import RED, BLUE, GREEN
|
||||
from gui.core.nanogui import refresh
|
||||
refresh(ssd, True) # Initialise and clear display.
|
||||
# Uncomment for ePaper displays
|
||||
# ssd.wait_until_ready()
|
||||
ssd.fill(0)
|
||||
ssd.line(0, 0, ssd.width - 1, ssd.height - 1, ssd.rgb(0, 255, 0)) # Green diagonal corner-to-corner
|
||||
ssd.rect(0, 0, 15, 15, ssd.rgb(255, 0, 0)) # Red square at top left
|
||||
ssd.rect(ssd.width -15, ssd.height -15, 15, 15, ssd.rgb(0, 0, 255)) # Blue square at bottom right
|
||||
ssd.line(0, 0, ssd.width - 1, ssd.height - 1, GREEN) # Green diagonal corner-to-corner
|
||||
ssd.rect(0, 0, 15, 15, RED) # Red square at top left
|
||||
ssd.rect(ssd.width -15, ssd.height -15, 15, 15, BLUE) # Blue square at bottom right
|
||||
ssd.show()
|
||||
```
|
||||
|
||||
|
|
|
@ -0,0 +1,163 @@
|
|||
# st7789.py Driver for ST7789 LCD displays for nano-gui
|
||||
|
||||
# Released under the MIT License (MIT). See LICENSE.
|
||||
# Copyright (c) 2021 Peter Hinch
|
||||
|
||||
# Tested display
|
||||
# Adafruit 1.3" 240x240 Wide Angle TFT LCD Display with MicroSD - ST7789
|
||||
# https://www.adafruit.com/product/4313
|
||||
# Based on
|
||||
# Adfruit https://github.com/adafruit/Adafruit_CircuitPython_ST7789/blob/master/adafruit_st7789.py
|
||||
# Also see st7735r_4bit.py for other source acknowledgements
|
||||
|
||||
# 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
|
||||
import framebuf
|
||||
import gc
|
||||
import micropython
|
||||
|
||||
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
|
||||
for x in range(length):
|
||||
c = source[x]
|
||||
d = (c & 0xf0) >> 3 # 2* LUT indices (LUT is 16 bit color)
|
||||
e = (c & 0x0f) << 1
|
||||
dest[n] = lut[d]
|
||||
n += 1
|
||||
dest[n] = lut[d + 1]
|
||||
n += 1
|
||||
dest[n] = lut[e]
|
||||
n += 1
|
||||
dest[n] = lut[e + 1]
|
||||
n += 1
|
||||
|
||||
class ST7789(framebuf.FrameBuffer):
|
||||
|
||||
lut = bytearray(32)
|
||||
|
||||
# Convert r, g, b in range 0-255 to a 16 bit colour value
|
||||
# LS byte goes into LUT offset 0, MS byte into offset 1
|
||||
# Same mapping in linebuf so LS byte is shifted out 1st
|
||||
@staticmethod
|
||||
def rgb(r, g, b):
|
||||
return ((b & 0xf8) << 5 | (g & 0x1c) << 11 | (g & 0xe0) >> 5 | (r & 0xf8)) ^ 0xffff
|
||||
|
||||
# rst and cs are active low, SPI is mode 0
|
||||
def __init__(self, spi, cs, dc, rst, height=240, width=240, disp_mode=PORTRAIT | REFLECT, init_spi=False):
|
||||
self._spi = spi # Clock cycle time for write 16ns 62.5MHz max (read is 150ns)
|
||||
self._rst = rst # Pins
|
||||
self._dc = dc
|
||||
self._cs = cs
|
||||
self.height = height # Required by Writer class
|
||||
self.width = width
|
||||
self._spi_init = init_spi
|
||||
mode = framebuf.GS4_HMSB # Use 4bit greyscale.
|
||||
gc.collect()
|
||||
buf = bytearray(height * width // 2)
|
||||
self._mvb = memoryview(buf)
|
||||
super().__init__(buf, width, height, mode)
|
||||
self._linebuf = bytearray(self.width * 2) # 16 bit color out
|
||||
self._init(disp_mode)
|
||||
self.show()
|
||||
|
||||
# Hardware reset
|
||||
def _hwreset(self):
|
||||
self._dc(0)
|
||||
self._rst(1)
|
||||
sleep_ms(1)
|
||||
self._rst(0)
|
||||
sleep_ms(1)
|
||||
self._rst(1)
|
||||
sleep_ms(1)
|
||||
|
||||
# Write a command, a bytes instance (in practice 1 byte).
|
||||
def _wcmd(self, buf):
|
||||
self._dc(0)
|
||||
self._cs(0)
|
||||
self._spi.write(buf)
|
||||
self._cs(1)
|
||||
|
||||
# Write a command followed by a data arg.
|
||||
def _wcd(self, c, d):
|
||||
self._dc(0)
|
||||
self._cs(0)
|
||||
self._spi.write(c)
|
||||
self._cs(1)
|
||||
self._dc(1)
|
||||
self._cs(0)
|
||||
self._spi.write(d)
|
||||
self._cs(1)
|
||||
|
||||
# Initialise the hardware. Blocks 163ms. Adafruit have various sleep delays
|
||||
# where I can find no requirement in the datasheet. I have removed them.
|
||||
def _init(self, disp_mode):
|
||||
self._hwreset() # Hardware reset. Blocks 3ms
|
||||
if self._spi_init: # A callback was passed
|
||||
self._spi_init(self._spi) # Bus may be shared
|
||||
cmd = self._wcmd
|
||||
wcd = self._wcd
|
||||
cmd(b'\x01') # SW reset datasheet specifies 120ms before SLPOUT
|
||||
sleep_ms(150)
|
||||
cmd(b'\x11') # SLPOUT: exit sleep mode
|
||||
sleep_ms(10) # ? Adafruit delay 500ms (datsheet 5ms)
|
||||
wcd(b'\x3a', b'\x55') # _COLMOD 16 bit/pixel, 64Kib color space
|
||||
cmd(b'\x20') # INVOFF Adafruit turn inversion on. This driver fixes .rgb
|
||||
cmd(b'\x13') # NORON Normal display mode
|
||||
|
||||
# Adafruit skip setting CA and RA but using it may help portability
|
||||
# CASET column address. start=0, end=width
|
||||
if (disp_mode & USD) and (disp_mode & PORTRAIT):
|
||||
wcd(b'\x2b', int.to_bytes(240 - self.width, 2, 'big') + int.to_bytes(239, 2, 'big'))
|
||||
else:
|
||||
wcd(b'\x2a', int.to_bytes(self.width - 1, 4, 'big'))
|
||||
# RASET row addr. start=0, end=height
|
||||
if (disp_mode & USD) and not (disp_mode & PORTRAIT):
|
||||
wcd(b'\x2b', int.to_bytes(320 - self.height, 2, 'big') + int.to_bytes(319, 2, 'big'))
|
||||
else:
|
||||
wcd(b'\x2b', int.to_bytes(self.height - 1, 4, 'big'))
|
||||
|
||||
# d7..d5 of MADCTL determine rotation/orientation datasheet P124, P231
|
||||
# d7 = MY page addr order
|
||||
# d6 = MX col addr order
|
||||
# d5 = MV row/col exchange
|
||||
wcd(b'\x36', int.to_bytes(disp_mode, 1, 'little'))
|
||||
cmd(b'\x29') # DISPON
|
||||
#sleep_ms(500) # Adafruit. Seems unnecessary. No mention in datasheet.
|
||||
|
||||
def show(self): # Blocks for 83ms @60MHz SPI
|
||||
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._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))
|
Ładowanie…
Reference in New Issue