Im August 2023
Bring etwas Farbe ins grau: Das
5.83inch E-Paper E-Ink Display Module (B) for Raspberry Pi Pico, 648×480, Red / Black / White, SPI
https://www.waveshare.com/5.83inch-e-paper-hat-b.htm
https://www.waveshare.com/wiki/5.83inch_e-Paper_HAT_(B)
Die Auflösung ist 648x480. Eigentlich ist es für den Raspberry Pi gedacht. Mit dem Pi Zero scheint es jedoch Timing-Probleme zu geben, und das Demoprogramm funktioniert nicht bzw. gibt nur Rauschen aus. Wie früher der Fernseher.
Mit dem Pi 4 klappt alles.
Das gleiche Display gibt es aber auch für den Pi Pico, und mit etwa Kabelstecken klappt das auch mit diesem Modell.
Wo bekommt man dreifarbige Bilder her? Das Waveshare-Demo benutzt zwei Bilder, ein Bild für rot und eines für schwarz. Erfreulicherweise sind Bilder im pbm-Format schon weitgehend in dem gleichen Format, das auch der ByteBuffer des micropython-Framebuffers verwendet.
Bildbearbeitung:
Und wie werden die Bilder dann angezeigt? Ein Microypthon Beispiel, abgeleitet vom Waveshare-Demo:
# Bilder laden und anzeigen
# Bilder müssen x_r.pbm und x_b.pbm heißen. Das Programm wählt
# zufällig Bilder aus
from machine import Pin, SPI
import framebuf
import utime
import os
import sys
import random
import gc
# Display resolution
EPD_WIDTH = 648
EPD_HEIGHT = 480
RST_PIN = 12
DC_PIN = 8
CS_PIN = 9
BUSY_PIN = 13
class EPD_5in83_B():
def __init__(self):
self.reset_pin = Pin(RST_PIN, Pin.OUT)
self.busy_pin = Pin(BUSY_PIN, Pin.IN, Pin.PULL_UP)
self.cs_pin = Pin(CS_PIN, Pin.OUT)
self.width = EPD_WIDTH
self.height = EPD_HEIGHT
self.spi = SPI(1)
self.spi.init(baudrate=4000_000)
self.dc_pin = Pin(DC_PIN, Pin.OUT)
self.buffer_black = bytearray(self.height * self.width // 8)
self.buffer_red = bytearray(self.height * self.width // 8)
self.imageblack = framebuf.FrameBuffer(self.buffer_black, self.width, self.height, framebuf.MONO_HLSB)
self.imagered = framebuf.FrameBuffer(self.buffer_red, self.width, self.height, framebuf.MONO_HLSB)
self.init()
def digital_write(self, pin, value):
pin.value(value)
def digital_read(self, pin):
return pin.value()
def delay_ms(self, delaytime):
utime.sleep(delaytime / 1000.0)
def spi_writebyte(self, data):
self.spi.write(bytearray(data))
def module_exit(self):
self.digital_write(self.reset_pin, 0)
# Hardware reset
def reset(self):
self.digital_write(self.reset_pin, 1)
self.delay_ms(50)
self.digital_write(self.reset_pin, 0)
self.delay_ms(2)
self.digital_write(self.reset_pin, 1)
self.delay_ms(50)
def send_command(self, command):
self.digital_write(self.dc_pin, 0)
self.digital_write(self.cs_pin, 0)
self.spi_writebyte([command])
self.digital_write(self.cs_pin, 1)
def send_data(self, data):
self.digital_write(self.dc_pin, 1)
self.digital_write(self.cs_pin, 0)
self.spi_writebyte([data])
self.digital_write(self.cs_pin, 1)
def send_data1(self, data):
self.digital_write(self.dc_pin, 1)
self.digital_write(self.cs_pin, 0)
self.spi_writebyte(data)
self.digital_write(self.cs_pin, 1)
def ReadBusy(self):
print("e-Paper busy")
while(self.digital_read(self.busy_pin) == 0): # 1: idle, 0: busy
self.delay_ms(10)
print("e-Paper busy release")
def TurnOnDisplay(self):
self.send_command(0x12)
self.delay_ms(100)
self.ReadBusy()
def init(self):
# EPD hardware init start
self.reset()
self.send_command(0x01) #POWER SETTING
self.send_data (0x07)
self.send_data (0x07) #VGH=20V,VGL=-20V
self.send_data (0x3f) #VDH=15V
self.send_data (0x3f) #VDL=-15V
self.send_command(0x04) #POWER ON
self.delay_ms(100)
self.ReadBusy() #waiting for the electronic paper IC to release the idle signal
self.send_command(0X00) #PANNEL SETTING
self.send_data(0x0F) #KW-3f KWR-2F BWROTP 0f BWOTP 1f
self.send_command(0x61) #tres
self.send_data (0x02) #source 648
self.send_data (0x88)
self.send_data (0x01) #gate 480
self.send_data (0xe0)
self.send_command(0X15)
self.send_data(0x00)
self.send_command(0X50) #VCOM AND DATA INTERVAL SETTING
self.send_data(0x11)
self.send_data(0x07)
self.send_command(0X60) #TCON SETTING
self.send_data(0x22)
# EPD hardware init end
return 0
def display(self, imageBlack, imageRed):
if (imageBlack == None or imageRed == None):
return
self.send_command(0x10) # WRITE_RAM
self.send_data1(imageBlack)
self.send_command(0x13) # WRITE_RAM
self.send_data1(imageRed)
self.TurnOnDisplay()
def Clear(self, colorBalck, colorRed):
self.send_command(0x10) # WRITE_RAM
for i in range(0, int(self.width / 8)):
self.send_data1([colorBalck] * self.height)
self.send_command(0x13) # WRITE_RAM
for i in range(0, int(self.width / 8)):
self.send_data1([colorRed] * self.height)
self.TurnOnDisplay()
def sleep(self):
self.send_command(0x02) # DEEP_SLEEP_MODE
self.ReadBusy()
self.send_command(0x07)
self.send_data(0xa5)
self.delay_ms(2000)
self.module_exit()
if __name__=='__main__':
epd = EPD_5in83_B()
epd.Clear(0xff, 0x00)
filename = ""
# find suitable image (ending with _b.pbm)
images = []
for file in os.listdir():
if file[-6:] == '_b.pbm':
images.append(file)
if not images:
epd.imageblack.fill(0xff)
epd.imagered.fill(0x00)
epd.imageblack.text("Found no images", 0, 10, 0x00)
epd.display(epd.buffer_black, epd.buffer_red)
epd.delay_ms(2000)
print("Found no images")
sys.exit();
# pick random image file
filename = images[random.randint(0,len(images)-1)]
filenamer = filename[0:-6] + '_r.pbm'
# read and set black file
print ("Using black image ", filename)
with open(filename, mode="rb") as file:
b = file.read()
epd.buffer_black[:] = b[len(b)-(648*480//8):] # do some calculation to skip pbm header
# my black file need to be inverted
for i in range(0, len( epd.buffer_black)):
epd.buffer_black[i] = ~ epd.buffer_black[i]
del b # free some memory
# read and set red file
print ("Using red image ", filename)
with open(filenamer, mode="rb") as file:
b = file.read()
epd.buffer_red[:] = b[len(b)-(648*480//8):] # do some calculation to skip pbm header
epd.display(epd.buffer_black, epd.buffer_red)
epd.delay_ms(2000)
print("...")
# print("sleep")
# epd.sleep()
Schön schön, damit kann man das Display als Bilderrahmen verwenden.
Nett. Aber wie wäre es mit eigenem Text? Oder einer Art Sinnspruchanzeiger?
Für die Anzeige von Text kann folgendes Tool verwendet werden:
https://github.com/peterhinch/micropython-font-to-py/tree/master
Für das E-Paper Display wird dazu folgende Modifikation benötigt:
https://forum.micropython.org/viewtopic.php?t=6319&start=10
Hinweis: font-to-py funktioniert auf Linux-Systemen. Oder aur Windows unter WSL.
Aufruf z.B. mit
python font_to_py.py -x -k chars.txt BigShouldersInlineText-VariableFont_wght.ttf 96 bigs96.py
wobei chars.txt die verwendeten Zeichen enthält, inkl. äöüß.
Das folgende Programm erzeugt aus einem Font und einem Hintergrundbild (für den rot-Kanal) ein Bild mit Text:
# Text auf dem Display darstellen.
# Basiert auf dem Waveshare-Demoprogramm
# inkfree72h.py wurde mit font-to-py erstellt
# benötigt noch writer.py
#
from machine import Pin, SPI
import machine
import framebuf
import utime
import sys
import gc
import random
# Display resolution
EPD_WIDTH = 648
EPD_HEIGHT = 480
RST_PIN = 12
DC_PIN = 8
CS_PIN = 9
BUSY_PIN = 13
# Helper for Writer, see https://forum.micropython.org/viewtopic.php?t=6319&start=10
class DummyDisplay(framebuf.FrameBuffer):
def __init__(self, buffer, width, height, format):
self.height = height
self.width = width
self.buffer = buffer
self.format = format
super().__init__(buffer, width, height, format)
class EPD_5in83_B():
def __init__(self):
self.reset_pin = Pin(RST_PIN, Pin.OUT)
self.busy_pin = Pin(BUSY_PIN, Pin.IN, Pin.PULL_UP)
self.cs_pin = Pin(CS_PIN, Pin.OUT)
self.width = EPD_WIDTH
self.height = EPD_HEIGHT
self.spi = SPI(1)
self.spi.init(baudrate=4000_000)
self.dc_pin = Pin(DC_PIN, Pin.OUT)
self.buffer_black = bytearray(self.height * self.width // 8)
self.buffer_red = bytearray(self.height * self.width // 8)
self.imageblack = DummyDisplay(self.buffer_black, self.width, self.height, framebuf.MONO_HLSB)
self.imagered = DummyDisplay(self.buffer_red, self.width, self.height, framebuf.MONO_HLSB)
self.init()
def digital_write(self, pin, value):
pin.value(value)
def digital_read(self, pin):
return pin.value()
def delay_ms(self, delaytime):
utime.sleep(delaytime / 1000.0)
def spi_writebyte(self, data):
self.spi.write(bytearray(data))
def spi_writebyte2(self, data):
self.spi.write(data)
def module_exit(self):
self.digital_write(self.reset_pin, 0)
# Hardware reset
def reset(self):
self.digital_write(self.reset_pin, 1)
self.delay_ms(50)
self.digital_write(self.reset_pin, 0)
self.delay_ms(2)
self.digital_write(self.reset_pin, 1)
self.delay_ms(50)
def send_command(self, command):
self.digital_write(self.dc_pin, 0)
self.digital_write(self.cs_pin, 0)
self.spi_writebyte([command])
self.digital_write(self.cs_pin, 1)
def send_data(self, data):
self.digital_write(self.dc_pin, 1)
self.digital_write(self.cs_pin, 0)
self.spi_writebyte([data])
self.digital_write(self.cs_pin, 1)
def send_data1(self, data):
self.digital_write(self.dc_pin, 1)
self.digital_write(self.cs_pin, 0)
self.spi_writebyte(data)
self.digital_write(self.cs_pin, 1)
def send_data2(self, data):
self.digital_write(self.dc_pin, 1)
self.digital_write(self.cs_pin, 0)
self.spi_writebyte2(data)
self.digital_write(self.cs_pin, 1)
def ReadBusy(self):
print("e-Paper busy")
while(self.digital_read(self.busy_pin) == 0): # 1: idle, 0: busy
self.delay_ms(10)
print("e-Paper busy release")
def TurnOnDisplay(self):
self.send_command(0x12)
self.delay_ms(100)
self.ReadBusy()
def init(self):
# EPD hardware init start
self.reset()
self.send_command(0x01) #POWER SETTING
self.send_data (0x07)
self.send_data (0x07) #VGH=20V,VGL=-20V
self.send_data (0x3f) #VDH=15V
self.send_data (0x3f) #VDL=-15V
self.send_command(0x04) #POWER ON
self.delay_ms(100)
self.ReadBusy() #waiting for the electronic paper IC to release the idle signal
self.send_command(0X00) #PANNEL SETTING
self.send_data(0x0F) #KW-3f KWR-2F BWROTP 0f BWOTP 1f
self.send_command(0x61) #tres
self.send_data (0x02) #source 648
self.send_data (0x88)
self.send_data (0x01) #gate 480
self.send_data (0xe0)
self.send_command(0X15)
self.send_data(0x00)
self.send_command(0X50) #VCOM AND DATA INTERVAL SETTING
self.send_data(0x11)
self.send_data(0x07)
self.send_command(0X60) #TCON SETTING
self.send_data(0x22)
# EPD hardware init end
return 0
def display(self, imageBlack, imageRed):
if (imageBlack == None or imageRed == None):
return
self.send_command(0x10) # WRITE_RAM
self.send_data2(imageBlack)
self.send_command(0x13) # WRITE_RAM
self.send_data2(imageRed)
self.TurnOnDisplay()
def Clear(self, colorBalck, colorRed):
self.send_command(0x10) # WRITE_RAM
for i in range(0, int(self.width / 8)):
self.send_data1([colorBalck] * self.height)
self.send_command(0x13) # WRITE_RAM
for i in range(0, int(self.width / 8)):
self.send_data1([colorRed] * self.height)
self.TurnOnDisplay()
def sleep(self):
self.send_command(0x02) # DEEP_SLEEP_MODE
self.ReadBusy()
self.send_command(0x07)
self.send_data(0xa5)
self.delay_ms(2000)
self.module_exit()
def showRule(epd):
epd.imageblack.fill(0x00)
epd.imagered.fill(0x00)
#epd.imageblack.text("Found no images", 0, 10, 0x00)
#epd.display(epd.buffer_black, epd.buffer_red)
#epd.delay_ms(2000)
bsa = ['bg.pbm', 'bg2.pbm', 'bg3.pbm', 'bg4.pbm']
bs = bsa[random.randint(0,len(bsa)-1)]
with open(bs, mode="rb") as file:
b = file.read()
epd.buffer_red[:] = b[len(b)-(648*480//8):] # do some calculation to skip pbm header
del b
gc.collect()
from writer import Writer
# Font
fi = random.randint(0,4)
if (fi == 0):
import inkfree72
font = inkfree72
elif (fi == 1):
import alfa72
font = alfa72
elif (fi == 2):
import bwpic72
font = bwpic72
elif (fi == 3):
import acme72
font = acme72
else:
import borel72
font = borel72
# Text
texts = [
'Lebe dein Leben nie ohne ein Lachen, denn es gibt Menschen, die von deinem Lachen leben.',
'Vergiss nicht, man braucht nur wenig um ein glückliches Leben zu führen.',
'Wer ein WARUM zum Leben hat, erträgt fast jedes WIE'
]
text = texts[random.randint(0,len(texts)-1)]
# Writing text to create white background
wri = Writer(epd.imagered, font)
Writer.set_textpos(epd.imagered, 60, 50)
wri.printstring(text, invert=True)
del wri
gc.collect()
wri = Writer(epd.imageblack, font)
Writer.set_textpos(epd.imageblack, 60, 50)
wri.printstring(text)
# my black file need to be inverted
for i in range(0, len( epd.buffer_black)):
epd.buffer_black[i] = ~ epd.buffer_black[i]
# remove black information from red buffer to make them visible
for i in range(0, len( epd.buffer_black)):
epd.buffer_red[i] = epd.buffer_red[i] & epd.buffer_black[i]
del font
gc.collect()
epd.Clear(0xff, 0x00)
epd.display(epd.buffer_black, epd.buffer_red)
epd.delay_ms(2000)
if __name__=='__main__':
epd = EPD_5in83_B()
while True:
showRule(epd)
machine.lightsleep(1000 * 60 * 15) # 15min
print("...")
Das Programm writer.py habe ich auch leicht angepasst:
# writer.py with small modifications
# writer.py Implements the Writer class.
# Handles colour, word wrap and tab stops
# V0.5.1 Dec 2022 Support 4-bit color display drivers.
# V0.5.0 Sep 2021 Color now requires firmware >= 1.17.
# 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.3.5 Sept 2020 Fast rendering option for color displays
# Released under the MIT License (MIT). See LICENSE.
# Copyright (c) 2019-2021 Peter Hinch
# A Writer supports rendering text to a Display instance in a given font.
# Multiple Writer instances may be created, each rendering a font to the
# same Display object.
# Timings were run on a pyboard D SF6W comparing slow and fast rendering
# and averaging over multiple characters. Proportional fonts were used.
# 20 pixel high font, timings were 5.44ms/467μs, gain 11.7 (freesans20).
# 10 pixel high font, timings were 1.76ms/396μs, gain 4.36 (arial10).
# https://github.com/peterhinch/micropython-font-to-py
import framebuf
from uctypes import bytearray_at, addressof
from sys import implementation
__version__ = (0, 5, 1)
fast_mode = True # Does nothing. Kept to avoid breaking code.
class DisplayState():
def __init__(self):
self.text_row = 0
self.text_col = 0
def _get_id(device):
if not isinstance(device, framebuf.FrameBuffer):
raise ValueError('Device must be derived from FrameBuffer.')
return id(device)
# Basic Writer class for monochrome displays
class Writer():
state = {} # Holds a display state for each device
@staticmethod
def set_textpos(device, row=None, col=None):
devid = _get_id(device)
if devid not in Writer.state:
Writer.state[devid] = DisplayState()
s = Writer.state[devid] # Current state
if row is not None:
if row < 0 or row >= device.height:
raise ValueError('row is out of range')
s.text_row = row
if col is not None:
if col < 0 or col >= device.width:
raise ValueError('col is out of range')
s.text_col = col
s.text_start_col = col # hacked
return s.text_row, s.text_col
def __init__(self, device, font, verbose=True):
self.devid = _get_id(device)
self.device = device
if self.devid not in Writer.state:
Writer.state[self.devid] = DisplayState()
self.font = font
if font.height() >= device.height or font.max_width() >= device.width:
raise ValueError('Font too large for screen')
# Allow to work with reverse or normal font mapping
if font.hmap():
self.map = framebuf.MONO_HMSB if font.reverse() else framebuf.MONO_HLSB
else:
raise ValueError('Font must be horizontally mapped.')
if verbose:
fstr = 'Orientation: Horizontal. Reversal: {}. Width: {}. Height: {}.'
print(fstr.format(font.reverse(), device.width, device.height))
print('Start row = {} col = {}'.format(self._getstate().text_row, self._getstate().text_col))
self.screenwidth = device.width # In pixels
self.screenheight = device.height
self.bgcolor = 0 # Monochrome background and foreground colors
self.fgcolor = 1
self.row_clip = False # Clip or scroll when screen fullt
self.col_clip = False # Clip or new line when row is full
self.wrap = True # Word wrap
self.cpos = 0
self.tab = 4
self.glyph = None # Current char
self.char_height = 0
self.char_width = 0
self.clip_width = 0
self.padright = 60 # added
def _getstate(self):
return Writer.state[self.devid]
def _newline(self):
s = self._getstate()
height = self.font.height()
s.text_row += height
s.text_col = s.text_start_col # 0 # hacked, remember left border
margin = self.screenheight - (s.text_row + height)
y = self.screenheight + margin
if margin < 0:
if not self.row_clip:
self.device.scroll(0, margin)
self.device.fill_rect(0, y, self.screenwidth, abs(margin), self.bgcolor)
s.text_row += margin
def set_clip(self, row_clip=None, col_clip=None, wrap=None):
if row_clip is not None:
self.row_clip = row_clip
if col_clip is not None:
self.col_clip = col_clip
if wrap is not None:
self.wrap = wrap
return self.row_clip, self.col_clip, self.wrap
@property
def height(self): # Property for consistency with device
return self.font.height()
def printstring(self, string, invert=False):
# word wrapping. Assumes words separated by single space.
q = string.split('\n')
last = len(q) - 1
for n, s in enumerate(q):
if s:
self._printline(s, invert)
if n != last:
self._printchar('\n')
def _printline(self, string, invert):
rstr = None
if self.wrap and self.stringlen(string, True): # Length > self.screenwidth
pos = 0
lstr = string[:]
while self.stringlen(lstr, True): # Length > self.screenwidth
pos = lstr.rfind(' ')
lstr = lstr[:pos].rstrip()
if pos > 0:
rstr = string[pos + 1:]
string = lstr
for char in string:
self._printchar(char, invert)
if rstr is not None:
self._printchar('\n')
self._printline(rstr, invert) # Recurse
def stringlen(self, string, oh=False):
if not len(string):
return 0
sc = self._getstate().text_col # Start column
wd = self.screenwidth - self.padright
l = 0
for char in string[:-1]:
_, _, char_width = self.font.get_ch(char)
l += char_width
if oh and l + sc > wd:
return True # All done. Save time.
char = string[-1]
_, _, char_width = self.font.get_ch(char)
if oh and l + sc + char_width > wd:
l += self._truelen(char) # Last char might have blank cols on RHS
else:
l += char_width # Public method. Return same value as old code.
return l + sc > wd if oh else l
# Return the printable width of a glyph less any blank columns on RHS
def _truelen(self, char):
glyph, ht, wd = self.font.get_ch(char)
div, mod = divmod(wd, 8)
gbytes = div + 1 if mod else div # No. of bytes per row of glyph
mc = 0 # Max non-blank column
data = glyph[(wd - 1) // 8] # Last byte of row 0
for row in range(ht): # Glyph row
for col in range(wd -1, -1, -1): # Glyph column
gbyte, gbit = divmod(col, 8)
if gbit == 0: # Next glyph byte
data = glyph[row * gbytes + gbyte]
if col <= mc:
break
if data & (1 << (7 - gbit)): # Pixel is lit (1)
mc = col # Eventually gives rightmost lit pixel
break
if mc + 1 == wd:
break # All done: no trailing space
# print('Truelen', char, wd, mc + 1) # TEST
return mc + 1
def _get_char(self, char, recurse):
if not recurse: # Handle tabs
if char == '\n':
self.cpos = 0
elif char == '\t':
nspaces = self.tab - (self.cpos % self.tab)
if nspaces == 0:
nspaces = self.tab
while nspaces:
nspaces -= 1
self._printchar(' ', recurse=True)
self.glyph = None # All done
return
self.glyph = None # Assume all done
if char == '\n':
self._newline()
return
glyph, char_height, char_width = self.font.get_ch(char)
s = self._getstate()
np = None # Allow restriction on printable columns
if s.text_row + char_height > self.screenheight:
if self.row_clip:
return
self._newline()
oh = s.text_col + char_width - self.screenwidth # Overhang (+ve)
if oh > 0:
if self.col_clip or self.wrap:
np = char_width - oh # No. of printable columns
if np <= 0:
return
else:
self._newline()
self.glyph = glyph
self.char_height = char_height
self.char_width = char_width
self.clip_width = char_width if np is None else np
# Method using blitting. Efficient rendering for monochrome displays.
# Tested on SSD1306. Invert is for black-on-white rendering.
def _printchar(self, char, invert=False, recurse=False):
s = self._getstate()
self._get_char(char, recurse)
if self.glyph is None:
return # All done
buf = bytearray(self.glyph)
if invert:
for i, v in enumerate(buf):
buf[i] = 0xFF & ~ v
fbc = framebuf.FrameBuffer(buf, self.clip_width, self.char_height, self.map)
if invert:
# hacked. Invert now defines transparent white font (for outlines)
for x in range(0,12,3):
for y in range(0,12,3):
self.device.blit(fbc, s.text_col-5+y, s.text_row-5+x, 1)
else:
self.device.blit(fbc, s.text_col, s.text_row)
s.text_col += self.char_width
self.cpos += 1
def tabsize(self, value=None):
if value is not None:
self.tab = value
return self.tab
def setcolor(self, *_):
return self.fgcolor, self.bgcolor
# Writer for colour displays.
class CWriter(Writer):
@staticmethod
def create_color(ssd, idx, r, g, b):
c = ssd.rgb(r, g, b)
if not hasattr(ssd, 'lut'):
return c
if not 0 <= idx <= 15:
raise ValueError('Color nos must be 0..15')
x = idx << 1
ssd.lut[x] = c & 0xff
ssd.lut[x + 1] = c >> 8
return idx
def __init__(self, device, font, fgcolor=None, bgcolor=None, verbose=True):
if not hasattr(device, 'palette'):
raise OSError('Incompatible device driver.')
if implementation[1] < (1, 17, 0):
raise OSError('Firmware must be >= 1.17.')
super().__init__(device, font, verbose)
if bgcolor is not None: # Assume monochrome.
self.bgcolor = bgcolor
if fgcolor is not None:
self.fgcolor = fgcolor
self.def_bgcolor = self.bgcolor
self.def_fgcolor = self.fgcolor
def _printchar(self, char, invert=False, recurse=False):
s = self._getstate()
self._get_char(char, recurse)
if self.glyph is None:
return # All done
buf = bytearray_at(addressof(self.glyph), len(self.glyph))
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
def setcolor(self, fgcolor=None, bgcolor=None):
if fgcolor is None and bgcolor is None:
self.fgcolor = self.def_fgcolor
self.bgcolor = self.def_bgcolor
else:
if fgcolor is not None:
self.fgcolor = fgcolor
if bgcolor is not None:
self.bgcolor = bgcolor
return self.fgcolor, self.bgcolor
Erstmal schön. Allerdings wird der Speicher schnell knapp, und die 1,4 MB im Pi Pico Flash reichen nicht für allzuviele Bilder oder Fonts.