Closed alphanumeric007 closed 2 years ago
It was worth a try, but in hindsight, a bit of an unreasonable request. Do it for one and you'd have to do it for others. I'm pretty sure its all doable with a Raspberry Pi instead of a Pi Pico so I'll likely go that route. I was trying to avoid having to run an OS in the background but I just can't get there from here using a Pico.
It's something I've wanted to fix for a while, since there are some real warts with the module (singleton) driver approach that Display Pack uses. But it's also a lot of effort for very little payoff, so knowing it would also help in cases like this (rare, but relevant) gives me some motivation to prioritise it!
An "generic" ST7789 module that wasn't locked into a preset width and height would work for me, and likely others. The 1.5' LCD Breakout Micro Python driver works with the Display Pack, its just restricted to 240x240. And I can use it to setup two display packs. I was able to use my 1.5' LCD with my Display Pack with that one module. Same way you'd do it on a Breakout Garden, but mine is on a solderless breadboard. I thought I was good to go then noticed the black bottom 1/4 of the display pack. If you do anything, I think a rotate function would come in very handy for displays that are rectangular.
The ST7789 driver that underpins Pico Display probably does what you want, but is missing the glue that PicoDisplay has to stick it to PicoGraphics (for all the drawing functions). And, of course, the Python bindings :grimacing:
The ST7789 driver could definitely stand to be a little more resolution agnostic, though, it's got a lot of special cases for the different displays we support to avoid having multiple arguments for display region and offsets.
I suspect it would be a lot nicer to initialise an "ST7789" class instance in MicroPython and supply a width, height and rotation instead of the current ugliness of supplying a properly sized bytearray()
. It would also combine all of the display product libraries into a single library so we don't have duplicated functionality all over the place (getting progressively worse with every new display product :grimacing:)
I guess TODO is:
Phase 1 tests:
This would change:
import picodisplay as display
width = display.get_width()
height = display.get_height()
display_buffer = bytearray(width * height * 2)
display.init(display_buffer)
Into something a little more like:
import st7789
width = 320
height = 240
display = st7789.ST7789(width, height, BG_SPI_FRONT)
That's close to what its like now in Python. Which was why I was headed that way. I could (I think?) use the Pi Mini Display code on the Pico Display Pack, with some editing. And not have to buy new displays.
# Buttons
BUTTON_A = 5
BUTTON_B = 6
BUTTON_X = 16
BUTTON_Y = 24
# Onboard RGB LED
LED_R = 17
LED_G = 27
LED_B = 22
# General
SPI_PORT = 0
SPI_CS = 1
SPI_DC = 9
BACKLIGHT = 13
# Screen dimensions
WIDTH = 320
HEIGHT = 240
display = ST7789(
port=SPI_PORT,
cs=SPI_CS,
dc=SPI_DC,
backlight=BACKLIGHT,
width=WIDTH,
height=HEIGHT,
rotation=180,
spi_speed_hz=60 * 1000 * 1000
)
Or the ST7789 breakout driver.
disp = ST7789.ST7789(
height=135 if display_type == "rect" else 240,
rotation=0 if display_type == "rect" else 90,
port=0,
cs=ST7789.BG_SPI_CS_FRONT, # BG_SPI_CS_BACK or BG_SPI_CS_FRONT
dc=9,
backlight=19, # 18 for back BG slot, 19 for front BG slot.
spi_speed_hz=80 * 1000 * 1000,
offset_left=0 if display_type == "square" else 40,
offset_top=53 if display_type == "rect" else 0
Welp all my Pico Display boards seem to be completely unresponsive for reasons I can't fathom. Very bizarre!
I have created a very, very rough merged ST7789 driver.
Builds should be available here shortly: https://github.com/pimoroni/pimoroni-pico/actions/runs/2017564653
It's missing a lot of features, but it may... work... and current looks something like this:
import st7789
import time
display = st7789.ST7789(width=240, height=320, slot=0)
print(display)
p = display.create_pen(255, 255, 0)
display.set_backlight(1.0)
display.set_pen(p)
while True:
display.clear()
display.update()
time.sleep(0.5)
This should be able to drive the 240x240 round and square colour LCDs, Pico Display and Pico Display 2, though support for round/square differentiation doesn't exist yet.
I'd kinda like to fold ST7735 support into this somehow, for a combined, driver-agnostic "display" library, but that's a future source of pain.
The following gets me a yellow background on my display pack V2
import st7789
import time
display1 = st7789.ST7789(width=240, height=320, slot=0)
print(display1)
p1 = display1.create_pen(255, 255, 0)
display1.set_backlight(1.0)
display1.set_pen(p1)
while True:
display1.clear()
display1.update()
time.sleep(0.5)
'''
ST7789(spi = 0, cs = 17, dc = 16, sck = 18, mosi = 19, bl = 20)
And the following gets me a Blue background on my 240x240 LCD Breakout.
import st7789 import time
display2 = st7789.ST7789(width=240, height=240, slot=1)
print(display2)
p2 = display2.create_pen(0, 0, 255)
display2.set_backlight(1.0) display2.set_pen(p2)
while True:
display2.clear()
display2.update()
time.sleep(0.5)
ST7789(spi = 0, cs = 22, dc = 16, sck = 18, mosi = 19, bl = 21)
Trying to run them both in the one file gets me a MemoryError: memory allocation failed, allocating 115200 bytes with the display2 = st7789.ST7789(width=240, height=240, slot=1) line.
I had gotten around that by doing all my display text etc for display 1 only (fill buffer)
update display1 (copy buffer to display 1)
clear display1 (empty buffer)
do all my display text ext for display 2 only. (fill buffer)
update display2 (copy buffer to display2)
clear display 2 (empty buffer)
This let me use one buffer for both displays.
This is my current working file using the latest official UF2 file. Wall of text to follow.
'''
This file lets you make a little indoor weather station.
Pi Pico
Large solderless breadboard
1.5" SPI Colour Square LCD (240x240) Breakout
Pico Display Pack V2 (320x240) Colour LCD
BME280 - Temperature, Pressure, Humidity Sensor Breakout
BME688 - Temperature, Pressure, Humidity Sensor Breakout
LTR-559 - Light Sensor Breakout
RV3028 RTC Breakout
'''
import time
import picodisplay2 as display2
from machine import ADC, Pin
from pimoroni_i2c import PimoroniI2C
from breakout_colourlcd240x240 import BreakoutColourLCD240x240
from breakout_bme280 import BreakoutBME280
from breakout_bme68x import BreakoutBME68X
from breakout_ltr559 import BreakoutLTR559
from breakout_rtc import BreakoutRTC
vsys = ADC(29) # reads the system input voltage
charging = Pin(24, Pin.IN) # reading GP24 tells us whether or not USB power is connected
conversion_factor = 3 * 3.3 / 65535
full_battery = 4.2 # these are our reference voltages for a full/empty battery, in volts
empty_battery = 2.8 # the values could vary by battery size/manufacturer so you might need to adjust them
display_buffer = bytearray(320 * 240 * 2) # 2-bytes per pixel (RGB565)
display1 = BreakoutColourLCD240x240(display_buffer, cs=(22), bl=(21))
display2.init(display_buffer)
display1.set_backlight(1.0)
display2.set_backlight(1.0)
PINS_BREAKOUT_GARDEN = {"sda": 4, "scl": 5}
PINS_PICO_EXPLORER = {"sda": 20, "scl": 21}
i2c = PimoroniI2C(**PINS_BREAKOUT_GARDEN)
bme_out = BreakoutBME68X(i2c)
bme_in = BreakoutBME280(i2c,0x77)
ltr = BreakoutLTR559(i2c)
rtc = BreakoutRTC(i2c)
rtc.set_backup_switchover_mode(1)
rtc.set_24_hour()
rtc.update_time()
min_temp_in = None
max_temp_in = None
min_temp_out = None
max_temp_out = None
min_press_out = None
max_press_out = None
start_time = time.time()
rtc.enable_periodic_update_interrupt(True)
while True:
if rtc.read_periodic_update_interrupt_flag():
rtc.clear_periodic_update_interrupt_flag()
if rtc.update_time():
rtc_date = rtc.string_date()
rtc_time = rtc.string_time()
time_elapsed = time.time() - start_time
# read the sensors
temp_in, press_in, hum_in = bme_in.read()
temp_out, press_out, hum_out, gas_resistance, status, gas_index, meas_index = bme_out.read()
# convert pressure to mb
pressuremb = press_out / 100
# header
display1.set_pen(200, 200, 200)
display1.text("in", 30, 0, 240, 3)
display1.text("out", 170, 0, 240, 3)
display1.text("min", 95, 78, 240, 3)
display1.text("max", 92, 100, 240, 3)
# indoor temperature
temp_in = round(temp_in)
if temp_in < 0:
display1.set_pen(255, 255, 255)
elif 0 <= temp_in < 12:
display1.set_pen(0, 0, 255)
elif 12 <= temp_in < 17:
display1.set_pen(255, 255, 0)
elif 17 <= temp_in < 25:
display1.set_pen(0, 255, 0)
elif 25 <= temp_in < 30:
display1.set_pen(255, 140, 0)
elif temp_in >= 30:
display1.set_pen(255, 0, 0)
else:
display1.set_pen(0, 0, 0)
display1.text('{:.0f}'.format(temp_in) + '`c', 15, 35, 240, 4)
# outdoor temperature
temp_out = round(temp_out)
if temp_out < 0:
display1.set_pen(255, 255, 255)
elif 0 <= temp_out < 12:
display1.set_pen(0, 0, 255)
elif 12 <= temp_out < 17:
display1.set_pen(255, 255, 0)
elif 17 <= temp_out < 25:
display1.set_pen(0, 255, 0)
elif 25 <= temp_out < 30:
display1.set_pen(255, 140, 0)
elif temp_out >= 30:
display1.set_pen(255, 0, 0)
else:
display1.set_pen(0, 0, 0)
display1.text('{:.0f}'.format(temp_out) + '`c', 160, 35, 240, 4)
# indoor min max temperature readings
if time_elapsed > 5:
if min_temp_in is not None and max_temp_in is not None:
if temp_in < min_temp_in:
min_temp_in = int(temp_in)
elif temp_in > max_temp_in:
max_temp_in = int(temp_in)
else:
min_temp_in = int(temp_in)
max_temp_in = int(temp_in)
if min_temp_in is not None and max_temp_in is not None:
min_string_in = ('{:.0f}'.format(min_temp_in))
max_string_in = ('{:.0f}'.format(max_temp_in))
else:
min_string_in = ""
max_string_in = ""
if min_temp_in is not None and max_temp_in is not None:
if min_temp_in < 0: # very cold
display1.set_pen(255, 255, 255)
elif 0 <= min_temp_in < 12: # cold
display1.set_pen(0, 0, 255)
elif 12 <= min_temp_in < 17: # cool
display1.set_pen(255, 255, 0)
elif 17 <= min_temp_in < 25: # warm
display1.set_pen(0, 255, 0)
elif 25 <= min_temp_in < 30: # hot
display1.set_pen(255, 140, 0)
elif min_temp_in >= 30: # very hot
display1.set_pen(255, 0, 0)
else:
display.set_pen(0, 0, 0)
display1.text(min_string_in, 25, 78, 240, 3)
if max_temp_in < 0: # very cold
display1.set_pen(255, 255, 255)
elif 0 <= max_temp_in < 12: # cold
display1.set_pen(0, 0, 255)
elif 12 <= max_temp_in < 17: # cool
display1.set_pen(255, 255, 0)
elif 17 <= max_temp_in < 25: # warm
display1.set_pen(0, 255, 0)
elif 25 <= max_temp_in < 30: # hot
display1.set_pen(255, 140, 0)
elif max_temp_in >= 30: # very hot
display1.set_pen(255, 0, 0)
else:
display1.set_pen(0, 0, 0)
display1.text(max_string_in, 25, 100, 240, 3)
# outdoor min max temperature readings
if time_elapsed > 5:
if min_temp_out is not None and max_temp_out is not None:
if temp_out < min_temp_out:
min_temp_out = int(temp_out)
elif temp_out > max_temp_out:
max_temp_out = int(temp_out)
else:
min_temp_out = int(temp_out)
max_temp_out = int(temp_out)
if min_temp_out is not None and max_temp_out is not None:
min_string_out = ('{:.0f}'.format(min_temp_out))
max_string_out = ('{:.0f}'.format(max_temp_out))
else:
min_string_out = ""
max_string_out = ""
if min_temp_out is not None and max_temp_out is not None:
if min_temp_out < 0: # very cold
display1.set_pen(255, 255, 255)
elif 0 <= min_temp_out < 12: # cold
display1.set_pen(0, 0, 255)
elif 12 <= min_temp_out < 17: # cool
display1.set_pen(255, 255, 0)
elif 17 <= min_temp_out < 25: # warm
display1.set_pen(0, 255, 0)
elif 25 <= min_temp_out < 30: # hot
display1.set_pen(255, 140, 0)
elif min_temp_out >= 30: # very hot
display1.set_pen(255, 0, 0)
else:
display1.set_pen(0, 0, 0)
display1.text(min_string_out, 180, 78, 240, 3)
#max_temp_out = round(max_temp_out)
if max_temp_out < 0: # very cold
display1.set_pen(255, 255, 255)
elif 0 <= max_temp_out < 12: # cold
display1.set_pen(0, 0, 255)
elif 12 <= max_temp_out < 17: # cool
display1.set_pen(255, 255, 0)
elif 17 <= max_temp_out < 25: # warm
display1.set_pen(0, 255, 0)
elif 25 <= max_temp_out < 30: # hot
display1.set_pen(255, 140, 0)
elif max_temp_out >= 30: # very hot
display1.set_pen(255, 0, 0)
else:
display1.set_pen(0, 0, 0)
display1.text(max_string_out, 180, 100, 240, 3)
# indoor humidity
if hum_in < 30:
display1.set_pen(255, 140, 0)
elif 30 <= hum_in < 61:
display1.set_pen(0, 255,0)
elif 61 <= hum_in < 81:
display1.set_pen(255, 255, 0)
elif hum_in >= 81:
display1.set_pen(255, 0, 0)
else:
display1.set_pen(0, 0, 0)
#display1.text((int(hum_in)), 20, 80, 240, 3)
display1.text('{:.0f}'.format(hum_in) + '%', 10, 140, 240, 4)
# outdoor humidity
if hum_out < 30:
display1.set_pen(255, 140, 0)
elif 30 <= hum_out < 61:
display1.set_pen(0, 255,0)
elif 61 <= hum_out < 81:
display1.set_pen(255, 255, 0)
elif hum_out >= 81:
display1.set_pen(255, 0, 0)
else:
display1.set_pen(0, 0, 0)
#display1.text((int(hum_in)), 20, 80, 240, 3)
display1.text('{:.0f}'.format(hum_out) + '%', 160, 140, 240, 4)
# battery state
voltage = vsys.read_u16() * conversion_factor
percentage = 100 * ((voltage - empty_battery) / (full_battery - empty_battery))
if percentage > 100:
percentage = 100.00
if charging.value() == 1: # if it's plugged into USB power...
display1.set_pen(0, 255, 0)
display1.text("ok", 20, 200, 240, 3)
#display1.text('{:.1f}'.format(voltage) + "v", 10, 200, 240, 3)
display1.text("ok", 170, 200, 240, 3)
display1.text('{:.0f}%'.format(percentage), 5, 220, 240, 3)
display1.text('{:.0f}%'.format(percentage), 155, 220, 240, 3)
display1.set_backlight(1.0)
display2.set_backlight(1.0)
display2.set_led(0,0,225)
else: # if not, display the battery stats
display1.set_pen(255, 255, 0)
display1.text('{:.1f}'.format(voltage) + "v", 10, 200, 240, 3)
display1.text('{:.0f}%'.format(percentage), 5, 220, 240, 3)
display1.text('{:.1f}'.format(voltage) + "v", 160, 200, 240, 3)
display1.text('{:.0f}%'.format(percentage), 155, 220, 240, 3)
display1.set_backlight(0.5)
display2.set_backlight(0.5)
display2.set_led(125,0,0)
# time to update display 1
display1.update()
display1.set_pen(0, 0, 0)
display1.clear()
display2.set_pen(200, 200, 200)
hours = rtc.get_hours()
minutes = rtc.get_minutes()
display2.text(rtc.string_date(), 30, 0, 180, 3)
#display2.text(f"{hours:02}:{minutes:02}", 190, 0, 320, 3)
if hours <12:
display2.text(f"{hours:2}:{minutes:02}:am", 190, 0, 240, 3)
elif hours == 12:
display2.text(f"{hours:2}:{minutes:02}:pm", 190, 0, 240, 3)
elif hours >12:
hours = hours - 12
display2.text(f"{hours:2}:{minutes:02}:pm", 190, 0, 240, 3)
# outddor pressure reading on display 2
if pressuremb < 982:
display2.set_pen(255, 0, 0)
display2.text('{:.0f}'.format(pressuremb) + 'mb', 0, 110, 240, 3)
display2.text("very low", 105, 110, 240, 3)
elif 982 <= pressuremb < 1004:
display2.set_pen(255, 255, 0)
display2.text('{:.0f}'.format(pressuremb) + 'mb', 0, 110, 240, 3)
display2.text("low", 105, 110, 240, 3)
elif 1004 <= pressuremb < 1026:
display2.set_pen(0, 255, 0)
display2.text('{:.0f}'.format(pressuremb) + 'mb', 0, 110, 240, 3)
display2.text("unsetled", 105, 110, 240, 3)
elif 1026 <= pressuremb < 1048:
display2.set_pen(0, 0, 255)
display2.text('{:.0f}'.format(pressuremb) + 'mb', 0, 110, 240, 3)
display2.text("high", 105, 110, 240, 3)
elif pressuremb >= 1048:
display2.set_pen(255, 140, 0)
display2.text('{:.0f}'.format(pressuremb) + 'mb', 0, 110, 240, 3)
display2.text("very high", 105, 110, 240, 3)
else:
display2.set_pen(0, 0, 0)
display2.text('{:.0f}'.format(pressuremb) + 'mb', 0, 110, 240, 3)
display2.text("", 105, 110, 240, 3)
reading = ltr.get_reading()
#print("Lux:", reading[BreakoutLTR559.LUX], "Prox:", reading[BreakoutLTR559.PROXIMITY])
light = reading[BreakoutLTR559.LUX]
display2.set_pen(0, 255, 0)
display2.text("sun", 0, 70, 240, 3)
#Convert light level in lux to descriptive value.
if light < 50:
display2.text("dark", 60, 70, 240, 3)
elif 50 <= light < 100:
display2.text("dim", 60, 70, 240, 3)
elif 100 <= light < 500:
display2.text("light", 60, 70, 240, 3)
elif light >= 500:
display2.text("bright", 60, 70, 240, 3)
# wind speed
display2.set_pen(255, 255, 255)
display2.text("wind:", 0, 190, 240, 3)
display2.text("NE", 80, 190, 240, 3)
# wind direction
display2.set_pen(255, 255, 255)
display2.text("36 km/h", 130, 190, 240, 3)
# percipitaion
display2.set_pen(255, 255, 255)
display2.text("rain fall:", 0, 220, 240, 3)
display2.text("30 mm", 150, 220, 240, 3)
# update display 2
display2.update()
display2.set_pen(0, 0, 0)
display2.clear()
time.sleep(1.0)
My displays - all of them - are still going nothing! But I'm glad this is working for you. Suggests my code is doing what I think it should.
Step two will be to try and flesh out support for various displays in some sensible and easy to use fashion. That may involve breaking the C++ API :grimacing:
(Yay found a display that works)
Opened #309 to track this
Nice work Phil, very appreciated. One wrinkle is you can't run two displays, not enough memory for two display buffers. I almost hate mentioning it after all the work you've done, and are doing. I wouldn't think its an issue for most people. It would only crop up if you tried to run two displays in the Pico Breakout Garden. Or what I'm trying to do. Requardless I'm happy to do any testing I can. I have a Pico Display pack V2 and V1. A 240x240 LCD breakout and a ST7735S 160x80 pixel LCD Breakout. Pico Breakout Garden and Quad pack.
Is there a way to make them both use the same frame_buffer? I may also have that frame_buffer line wrong?
frame_buffer = bytearray(240 * 240 * 2) # 2-bytes per pixel (RGB565)
display1 = st7789.ST7789(width=240, height=240, *frame_buffer, slot=0) #front
display2 = st7789.ST7789(width=240, height=240, *frame_buffer, slot=1) #back
MemoryError: memory allocation failed, allocating 81920 bytes
This works with the old driver, letting me use two displays at once
display_buffer = bytearray(240 * 240 * 2) # 2-bytes per pixel (RGB565)
display1 = BreakoutColourLCD240x240(display_buffer, cs=(17), bl=(20))
display2 = BreakoutColourLCD240x240(display_buffer, cs=(22), bl=(21))
Try:
frame_buffer = bytearray(240 * 240 * 2) # 2-bytes per pixel (RGB565)
display1 = st7789.ST7789(width=240, height=240, buffer=frame_buffer, slot=0) #front
display2 = st7789.ST7789(width=240, height=240, buffer=frame_buffer, slot=1) #back
I appreciate it doesn't constitute documentation, but all the args accepted by the constructor are here:
That worked on my test setup, can't thank you enough Phil. I had looked at that file and figured out it was frame_buffer, just couldn't figure out it was "buffer=frame_buffer". What's in that file is Klingon to me, lol I'll also try it out on my Display Pack setup in a bit.
This is my test file, with your edits added. Pico Breakout Garden with two of the 1.3' 240x240 LCD Breakouts
import time
import st7789
"""
from breakout_colourlcd240x240 import BreakoutColourLCD240x240
display_buffer = bytearray(240 * 240 * 2) # 2-bytes per pixel (RGB565)
display1 = BreakoutColourLCD240x240(display_buffer, cs=(17), bl=(20))
display2 = BreakoutColourLCD240x240(display_buffer, cs=(22), bl=(21))
"""
frame_buffer = bytearray(240 * 240 * 2) # 2-bytes per pixel (RGB565)
display1 = st7789.ST7789(width=240, height=240, buffer=frame_buffer, slot=0) #front
display2 = st7789.ST7789(width=240, height=240, buffer=frame_buffer, slot=1) #back
display1.set_backlight(1.0)
display2.set_backlight(1.0)
print(display1)
print(display2)
#BreakoutColourLCD240x240(spi = 0, cs = 27, dc = 16, sck = 18, mosi = 19, bl = 20)
#BreakoutColourLCD240x240(spi = 0, cs = 22, dc = 16, sck = 18, mosi = 19, bl = 21)
while True:
display1.set_pen(0, 0, 255)
display1.clear()
display1.update()
display1.set_pen(0, 0, 0)
display1.text("display 1", 10, 10, 240, 5)
display1.update()
display1.clear()
display2.set_pen(0, 255, 0)
display2.clear()
display2.update()
display2.set_pen(0, 0, 0)
display2.text("display 2", 10, 10, 240, 5)
display2.update()
display2.clear()
time.sleep(2)
display1.set_pen(0, 255, 0)
display1.clear()
display1.update()
display1.set_pen(0, 0, 0)
display1.text("BG_front display 1", 10, 10, 240, 5)
display1.update()
display1.clear()
display2.set_pen(0, 255, 255)
display2.clear()
display2.update()
display2.set_pen(0, 0, 0)
display2.text("BG_back display 2", 10, 10, 240, 5)
display2.update()
display2.clear()
time.sleep(2)
display1.set_pen(0, 255, 255)
display1.clear()
display1.update()
display1.set_pen(0, 0, 0)
display1.text("SPI_0 BG_front display 1", 10, 10, 240, 5)
display1.update()
display1.clear()
display2.set_pen(255, 0, 0)
display2.clear()
display2.update()
display2.set_pen(0, 0, 0)
display2.text("SPI_0 BG_back display 2", 10, 10, 240, 5)
display2.update()
display2.clear()
time.sleep(2)
display1.set_pen(255, 0, 0)
display1.clear()
display1.update()
display1.set_pen(0, 0, 0)
display1.text("cs=(17) SPI_0 BG_front display 1", 10, 10, 240, 5)
display1.update()
display1.clear()
display2.set_pen(255, 0, 255)
display2.clear()
display2.update()
display2.set_pen(0, 0, 0)
display2.text("cs=(22) SPI_0 BG_back display 2", 10, 10, 240, 5)
display2.update()
display2.clear()
time.sleep(2)
display1.set_pen(255, 0, 255)
display1.clear()
display1.update()
display1.set_pen(0, 0, 0)
display1.text("bl=(20) cs=(17) SPI_0 BG_front display 1", 10, 10, 240, 5)
display1.update()
display1.clear()
display2.set_pen(255, 255, 0)
display2.clear()
display2.update()
display2.set_pen(0, 0, 0)
display2.text("bl=(21) cs=(22) SPI_0 BG_back display 2", 10, 10, 240, 5)
display2.update()
display2.clear()
time.sleep(2)
display1.set_pen(255, 255, 0)
display1.clear()
display1.update()
display1.set_pen(0, 0, 0)
display1.text("240x240 bl=(20) cs=(17) SPI_0 BG_front display 1", 10, 10, 240, 5)
display1.update()
display1.clear()
display2.set_pen(0, 0, 255)
display2.clear()
display2.update()
display2.set_pen(0, 0, 0)
display2.text("240x240 bl=(21) cs=(22) SPI_0 BG_back display 2", 10, 10, 240, 5)
display2.update()
display2.clear()
time.sleep(2)
What worked on the 240x135 Pico display pack doesn't want to work so well on the V2 240x320? Landscape worked but portrait is all garbled? Going to plug it into my quad pack and make sure its not my jumpers / wiring?
Ok, it looks like an issue with the new unifying driver. portrait mode is cropped to 240 wide and text is all garbled?
import utime
display = st7789.ST7789(width=240, height=320, slot=0) # Display Pack V2 portrait didn't work
https://github.com/pimoroni/pimoroni-pico/pull/327#
Currently running two Display Pack V2's side by side in portrait mode without issue. And have access to the full 320 height and 240 width. woot =) I don't have the buttons or LED's wired up on this setup just yet. The Display Packs are each mounted to Perma Proto half size, and the Pico to another Perma Proto half size. I just soldered male header on the Perma Proto's and then soldered wires from board to board for SPI and power.
A big big thankyou Phil. A big thumbs up. My test file is as follows.
import time
import st7789 frame_buffer = bytearray(240 320 2) # 2-bytes per pixel (RGB565) display1 = st7789.ST7789(width=240, height=320, buffer=frame_buffer, slot=0) display2 = st7789.ST7789(width=240, height=320, buffer=frame_buffer, slot=1) display1.set_backlight(1.0) display2.set_backlight(1.0)
print(display1) print(display2)
while True:
display1.set_pen(0, 0, 255)
display1.clear()
display1.update()
display1.set_pen(0, 0, 0) # Set pen to black
display1.text("display 1", 10, 10, 240, 5)
display1.update()
display1.clear()
display2.set_pen(0, 255, 0)
display2.clear()
display2.update()
display2.set_pen(0, 0, 0) # Set pen to black
display2.text("display 2", 10, 10, 240, 5)
display2.update()
display2.clear()
time.sleep(2)
display1.set_pen(0, 255, 0)
display1.clear()
display1.update()
display1.set_pen(0, 0, 0) # Set pen to black
display1.text("display 1 slot 0", 10, 10, 240, 5)
display1.update()
display1.clear()
display2.set_pen(0, 255, 255)
display2.clear()
display2.update()
display2.set_pen(0, 0, 0) # Set pen to black
display2.text("display 2 slot 1", 10, 10, 240, 5)
display2.update()
display2.clear()
time.sleep(2)
display1.set_pen(0, 255, 255)
display1.clear()
display1.update()
display1.set_pen(0, 0, 0) # Set pen to black
display1.text("display 1 slot 0 BG_front", 10, 10, 240, 5)
display1.update()
display1.clear()
display2.set_pen(255, 0, 0)
display2.clear()
display2.update()
display2.set_pen(0, 0, 0) # Set pen to black
display2.text("display 2 slot 1 BG_back", 10, 10, 240, 5)
display2.update()
display2.clear()
time.sleep(2)
display1.set_pen(255, 0, 0)
display1.clear()
display1.update()
display1.set_pen(0, 0, 0) # Set pen to black
display1.text("display 1 slot 0 BG_front cs=(17)", 10, 10, 240, 5)
display1.update()
display1.clear()
display2.set_pen(255, 0, 255)
display2.clear()
display2.update()
display2.set_pen(0, 0, 0) # Set pen to black
display2.text("display 2 slot 1 BG_back cs=(22)", 10, 10, 240, 5)
display2.update()
display2.clear()
time.sleep(2)
display1.set_pen(255, 0, 255)
display1.clear()
display1.update()
display1.set_pen(0, 0, 0) # Set pen to black
display1.text("display 1 slot 0 BG_front cs=(17) bl=(20)", 10, 10, 240, 5)
display1.update()
display1.clear()
display2.set_pen(255, 255, 0)
display2.clear()
display2.update()
display2.set_pen(0, 0, 0) # Set pen to black
display2.text("display 2 slot 1 BG_back cs=(22) bl=(21)", 10, 10, 240, 5)
display2.update()
display2.clear()
time.sleep(2)
display1.set_pen(255, 255, 0)
display1.clear()
display1.update()
display1.set_pen(0, 0, 0) # Set pen to black
display1.text("display 1 slot 0 BG_front cs=(17) bl=(20) st7789", 10, 10, 240, 5)
display1.update()
display1.clear()
display2.set_pen(0, 0, 255)
display2.clear()
display2.update()
display2.set_pen(0, 0, 0) # Set pen to black
display2.text("display 2 slot 1 BG_back cs=(22) bl=(21) st7789", 10, 10, 240, 5)
display2.update()
display2.clear()
time.sleep(2)
display1.set_pen(255, 255, 0)
display1.clear()
display1.update()
display1.set_pen(0, 0, 0) # Set pen to black
display1.text("display 1 slot 0 BG_front cs=(17) bl=(20) st7789 240 x 320", 10, 10, 240, 5)
display1.update()
display1.clear()
display2.set_pen(0, 0, 255)
display2.clear()
display2.update()
display2.set_pen(0, 0, 0) # Set pen to black
display2.text("display 2 slot 1 BG_back cs=(22) bl=(21) st7789 240 x 320", 10, 10, 240, 5)
display2.update()
display2.clear()
time.sleep(2)
display1.set_pen(255, 255, 0)
display1.clear()
display1.update()
display1.set_pen(0, 0, 0) # Set pen to black
display1.text("display 1 slot 0 BG_front cs=(17) bl=(20) st7789 240 x 320 portrait", 10, 10, 240, 5)
display1.update()
display1.clear()
display2.set_pen(0, 0, 255)
display2.clear()
display2.update()
display2.set_pen(0, 0, 0) # Set pen to black
display2.text("display 2 slot 1 BG_back cs=(22) bl=(21) st7789 240 x 320 portrait", 10, 10, 240, 5)
display2.update()
display2.clear()
time.sleep(2)
I have a need to run two Pico Display Packs side by side, portrait mode if possible. I get that this is a very unusual request, and that its not designed to be used this way. They will be mounted to proto boards so each one can use a different chip select and backlight pin. I'll just mirror what pins are used on the Pico Breakout Garden SPI slots. And ignore the button and LED connections. The stock Pimoroni Micro Python Display Pack driver / module doesn't support alternate pin select so I can't use it. The BreakoutColourLCD240x240 Micro python module does, and does work with the Display Pack, with one exception. It limits me too 240 x 240 pixels. It's already in portraited mode because of the different screen orientation of the display pack but I can't draw to the lower 1/4 of the screen. Even if I specify a height=320 and adjust the display buffer to match.
I currently have a 1.5' 240x240 LCD Breakout and Display Pack v2 running side by side, so running two displays is possible. What I need is *BreakoutColorLCD240x320* module. I don't have the skills to write my own of know where to even begin to modify the current 240x240 module. I may be asking too much, but I figure it can't hurt to at least ask. @Gadgetoid