Raspberry Pi Pico
Four Letter pHAT
The Four Letter pHAT is a Raspberry Pi breakout made by the company Pimoroni. It's a segemented alphanumeric display with 14 segements used to display characters. As a result, you can display digits, letters and many punctuation characters and symbols. The breakout uses an HT16K33 integrated cricuit to drive the LED segments. You control the display using i2c.
This is an image showing it connected to a Pico using a Waveshare accessory, which makes the connections easier. The display looks much cooler than this in real life. The high speed refreshing means that the LEDs look less bright in photographs than they appear in real life. The display does look much brighter than this suggests and all segements do appear in the same brightness.

My connections are GP2 and GP3 to pins 2 and 3 on the pHAT. You also need to connect to the 5V, 3V3 and GND pins of the pHAT. You can see a diagram showing the pHAT pins at Gadgetoid's superb Pinout site,https://pinout.xyz/pinout/four_letter_phat.
Here is my library code for interacting with the pHAT. Save it to the Pico as flh.py. There is a font defined that you can use to display strings of four letters. I haven't added any code for scrolling. That leaves a project for you to work on if you wish.
from machine import Pin, I2C
class FLH:
ADDRESS = 0x70
BLINK_CMD = 0x80
CMD_BRIGHTNESS = 0xE0
DIGITS = {
' ': 0b0000000000000000,
'!': 0b0000000000000110,
'"': 0b0000001000100000,
'#': 0b0001001011001110,
'$': 0b0001001011101101,
'%': 0b0000110000100100,
'&': 0b0010001101011101,
'\'': 0b0000010000000000,
'(': 0b0010010000000000,
')': 0b0000100100000000,
'*': 0b0011111111000000,
'+': 0b0001001011000000,
',': 0b0000100000000000,
'-': 0b0000000011000000,
'.': 0b0000000000000000,
'/': 0b0000110000000000,
'0': 0b0000110000111111,
'1': 0b0000000000000110,
'2': 0b0000000011011011,
'3': 0b0000000010001111,
'4': 0b0000000011100110,
'5': 0b0010000001101001,
'6': 0b0000000011111101,
'7': 0b0000000000000111,
'8': 0b0000000011111111,
'9': 0b0000000011101111,
':': 0b0001001000000000,
';': 0b0000101000000000,
'<': 0b0010010000000000,
'=': 0b0000000011001000,
'>': 0b0000100100000000,
'?': 0b0001000010000011,
'@': 0b0000001010111011,
'A': 0b0000000011110111,
'B': 0b0001001010001111,
'C': 0b0000000000111001,
'D': 0b0001001000001111,
'E': 0b0000000011111001,
'F': 0b0000000001110001,
'G': 0b0000000010111101,
'H': 0b0000000011110110,
'I': 0b0001001000000000,
'J': 0b0000000000011110,
'K': 0b0010010001110000,
'L': 0b0000000000111000,
'M': 0b0000010100110110,
'N': 0b0010000100110110,
'O': 0b0000000000111111,
'P': 0b0000000011110011,
'Q': 0b0010000000111111,
'R': 0b0010000011110011,
'S': 0b0000000011101101,
'T': 0b0001001000000001,
'U': 0b0000000000111110,
'V': 0b0000110000110000,
'W': 0b0010100000110110,
'X': 0b0010110100000000,
'Y': 0b0001010100000000,
'Z': 0b0000110000001001,
'a': 0b0001000001011000,
'b': 0b0010000001111000,
'c': 0b0000000011011000,
'd': 0b0000100010001110,
'e': 0b0000100001011000,
'f': 0b0000000001110001,
'g': 0b0000010010001110,
'h': 0b0001000001110000,
'i': 0b0001000000000000,
'j': 0b0000000000001110,
'k': 0b0011011000000000,
'l': 0b0000000000110000,
'm': 0b0001000011010100,
'n': 0b0001000001010000,
'o': 0b0000000011011100,
'p': 0b0000000101110000,
'q': 0b0000010010000110,
'r': 0b0000000001010000,
's': 0b0010000010001000,
't': 0b0000000001111000,
'u': 0b0000000000011100,
'v': 0b0010000000000100,
'w': 0b0010100000010100,
'x': 0b0010100011000000,
'y': 0b0010000000001100,
'z': 0b0000100001001000
}
def __init__(self,i, d, c):
self.buffer = bytearray([0]*16)
self.i2c=I2C(i,sda=Pin(d), scl=Pin(c))
self.i2c.writeto(self.ADDRESS,b'\x21')
# 0 to 3
self.blink_rate(0)
# 0 to 15
self.set_brightness(15)
self.update_display()
def set_brightness(self,b):
self.i2c.writeto(self.ADDRESS,bytes([self.CMD_BRIGHTNESS | b]))
def blink_rate(self, b):
self.i2c.writeto(self.ADDRESS,bytes([self.BLINK_CMD | 1 | (b << 1)]))
def update_display(self):
data = bytearray([0]) + self.buffer
self.i2c.writeto(self.ADDRESS,data)
def clear(self):
self.buffer = bytearray([0]*16)
self.update_display()
def raw_digit(self, value, position):
self.buffer[position*2] = value & 0xFF
self.buffer[position*2+1] = (value >> 8) & 0xFF
def set_digit(self, value, position):
self.raw_digit(self.DIGITS.get(str(value), 0x00), position)
def set_decimal(self, decimal, pos):
if pos < 0 or pos > 3:
return
# Set bit 14
if decimal:
self.buffer[pos*2+1] |= (1 << 6)
else:
self.buffer[pos*2+1] &= ~(1 << 6)
def print_str(self, value, ralign=True):
# Calculate starting position of digits
pos = (4-len(value)) if ralign else 0
for i, ch in enumerate(value):
self.set_digit(ch,i+pos)
Here is some test code to save as main.py,
from flh import FLH
from time import sleep
four = FLH(1,2,3)
# test word printing
four.print_str("Byte")
four.update_display()
sleep(5)
#test decimals
for i in range(4):
four.set_decimal(True, i)
four.update_display()
sleep(0.5)
four.clear()
# test numbers
for i in range(10000):
four.print_str(str(i), ralign="True")
four.update_display()
sleep(0.1)

