pimoroni / pimoroni-pico

Libraries and examples to support Pimoroni Pico add-ons in C++ and MicroPython.
https://shop.pimoroni.com/collections/pico
MIT License
1.32k stars 496 forks source link

ST7789 display connect to custom pins #384

Closed AlexeyPechnikov closed 8 months ago

AlexeyPechnikov commented 2 years ago

I'm trying v1.18.8 to use ST7789 with custom pins:

image

but it doesn't work:

import st7789
st7789.ST7789(135, 240, rotate180=False, slot=0, cs=5, dc=1)

> ST7789(spi = 0, cs = 17, dc = 16, sck = 18, mosi = 19, bl = 20)

Is it possible to use all the custom display connection pins for the driver? I think 'slot' variable is not documented, right?

Also, 'cs' and 'dc' arguments looks weird because we can't use machine.Pin() instances here:

st7789.ST7789(135, 240, rotate180=False, slot=0, cs=machine.Pin(5), dc=machine.Pin(1))

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't convert Pin to int

so it's not clear if GP0 is equal to 0 or 1 here. Anyway, these arguments don't work and we have no ability to define backlight pin and so on.

AlexeyPechnikov commented 2 years ago

Aha, I checked the module sources and I have the solution:

import machine
import st7789
display = st7789.ST7789(135, 240, rotate180=False, spi=0, cs=5, dc=1, sck=2, mosi=3, bl=4)
display.set_backlight(1.0)
display.set_pen(0, 0, 255)
display.clear()
display.update()
display.set_pen(0, 0, 0)
display.text("display", 10, 10, 240, 3)  
display.update()
display.clear()

So the driver ignores all the pins when 'slot' argument presented. Note: I have only one Pico Display V2 so I don't need to connect lots of them to the same pins.

Gadgetoid commented 2 years ago

This will all change with #373 and I definitely recommend giving those builds a try if you're using a display.

Gadgetoid commented 2 years ago

In your case you will be wanting something like:

from pimoroni_bus import SPIBus
from picographics import PicoGraphics, DISPLAY_PICO_DISPLAY, PEN_RGB565

spibus = SPIBus(cs=5, dc=1, sck=2, mosi=3, bl=4)

display = PicoGraphics(display=DISPLAY_PICO_DISPLAY, bus=spibus, pen_type=PEN_RGB565)

And a bleeding edge build like https://github.com/pimoroni/pimoroni-pico/actions/runs/2462877886 or later.

If you want to half your RAM usage and just use 256 colours you can use PEN_RGB332. Handy if you want multiple displays.

AlexeyPechnikov commented 2 years ago

Ah, thanks! It works for rotate=0 but not for rotate=90:

from pimoroni_bus import SPIBus
from picographics import PicoGraphics, DISPLAY_PICO_DISPLAY, PEN_RGB565

spibus = SPIBus(cs=5, dc=1, sck=2, mosi=3, bl=4)
display = PicoGraphics(display=DISPLAY_PICO_DISPLAY, bus=spibus, pen_type=PEN_RGB565, rotate=90)

Please see the picture below where the rotated display filled by random coloured points at bottom line (due to uninitialised or too small frame buffer, I suppose): IMG_0904

Gadgetoid commented 2 years ago

Ha, I thought I'd tested them all. I'll add this to my TODO!

Gadgetoid commented 2 years ago

Rotations seem to work fine on the 160x80 PicoDisplay, so I think this might be a disagreement in how your display works, or some other issue.

AlexeyPechnikov commented 2 years ago

Hmm, for Pico Display V2 I see the same small picture on the display for the both rotate=0 and rotate=90:

spibus = SPIBus(cs=17, dc=16, sck=18, mosi=19)

display = PicoGraphics(display=DISPLAY_PICO_DISPLAY, bus=spibus, pen_type=PEN_RGB565, rotate=0)

IMG_0905

Gadgetoid commented 2 years ago

Change DISPLAY_PICO_DISPLAY in your code to DISPLAY_PICO_DISPLAY_2

AlexeyPechnikov commented 2 years ago

Yes, it works with display=DISPLAY_PICO_DISPLAY_2 but how about different display sizes?

Gadgetoid commented 2 years ago

They were never supported in the first place- supplying width/height was more a nuisance than a feature since unsupported values would break or be ignored.

AlexeyPechnikov commented 2 years ago

I think we were able to define any size of a framebuffer before:

width = display.get_width()
height = display.get_height()
display_buffer = bytearray(width * height * 2)  # 2-bytes per pixel (RGB565)
display.init(display_buffer)

For now the framebuffer size is always limited by the pre-defined choices. Correct?

Gadgetoid commented 2 years ago

Sort of- the buffer size didn't really do anything useful. If it's too small you'd get an error, and if it's too large you'd waste RAM.

The whole display.init(buffer) thing was a workaround for our lack of understanding about how MicroPython worked :laughing:

You can still supply a custom buffer using the buffer argument in PicoGraphics, but there's no real purpose to that*

Supporting different screen resolutions must be done in the underlying driver itself. That's done pretty naively by a hard-coded table of values that work with our products:

https://github.com/pimoroni/pimoroni-pico/blob/b41631bc14953453d2719592640adde8437f6d12/drivers/st7789/st7789.cpp#L100-L150

(Though this has since been somewhat rewritten)

Edit: * - other than, you know, sharing the same buffer between multiple displays, having a buffer you can write arbitrary data to, etc, etc

AlexeyPechnikov commented 2 years ago

Ok, got it. Anyway, please save ability to change the driver for the display wrapper ("picographics") for your future products (maybe touch screen-enabled ones)! It looks as you are going to hide too deep all the details about st7789 driver...

P.S. At the end of the day I think it doesn't look user friendly to disable usage of other [larger] screens! Why should we look for other library and adopt our codes when we buy additional displays on the same driver? It'd be great to use "picographics" for any screen [using many drivers ;)].

Gadgetoid commented 2 years ago

Supporting other screens would be nice, but I need:

  1. Time
  2. The screens to test with

Ignoring all the MicroPython veneer over the top, PicoGraphics and the display drivers are quite separate- in fact "PicoGraphics" as presented to MicroPython already transparently supports both ST7789 and ST7735 based displays with more to come.

AlexeyPechnikov commented 2 years ago

Yes, sure. picographics library looks great, thanks! I just worry if we will be able to use it smoothly in the future. For an example, it’d be nice to have some touchscreen display for Pico like to pair of touch controller XPT2046 plus ILI9488 driver for 480x320 display.

Gadgetoid commented 8 months ago

Closing as complete. I think there are enough supported display types now to set a pretty good example for how supporting another one might be accomplished. And you can memoryview(picographics) to get to the raw buffer and copy it over with your own Python driver if you're so inclined.

I can't merge support for anything we don't make because flash storage is getting really tight on particularly the Pico W and, long term, more things will probably have to be done in pure Python anyway.