Open
Description
CircuitPython version and board name
Adafruit CircuitPython 10.0.0-alpha.7 on 2025-06-17; Adafruit Metro RP2350 with rp2350b
Board ID:adafruit_metro_rp2350
UID:030FA9DAE6154C9A
Code/REPL
# SPDX-FileCopyrightText: 2025 Anne Barela for Adafruit Industries
#
# SPDX-License-Identifier: MIT
import supervisor
from displayio import Group, TileGrid, Palette, Bitmap
from adafruit_bitmap_font import bitmap_font
from adafruit_display_text import label
from adafruit_fruitjam.peripherals import request_display_config
import gc
colors = 2
request_display_config(640, 480)
main_group = Group()
display = supervisor.runtime.display
display.root_group = main_group
font_file = "fonts/cp437-8x12.bdf"
font = bitmap_font.load_font(font_file)
gc.collect()
char_size = font.get_bounding_box()
screen_size = (display.width // char_size[0], display.height // char_size[1])
terminal_palette = Palette(colors)
terminal_palette[0] = 0x000000
terminal_palette[1] = 0xffffff
# Display info labels
text = f"Screen size (pixels): {display.width}x{display.height}"
text_area = label.Label(font, text=text, color=terminal_palette[1])
text_area.x = 0
text_area.y = 55
main_group.append(text_area)
text = f"Screen size (characters): {screen_size[0]}x{screen_size[1]}"
text_area = label.Label(font, text=text, color=terminal_palette[1])
text_area.x = 0
text_area.y = 65
main_group.append(text_area)
text_area = label.Label(font, text=font_file, color=terminal_palette[1])
text_area.x = 0
text_area.y = 80
main_group.append(text_area)
text = f"Font size (pixels): {char_size[0]}x{char_size[1]}"
text_area = label.Label(font, text=text, color=terminal_palette[1])
text_area.x = 0
text_area.y = 90
main_group.append(text_area)
gc.collect()
# Work around glyph cache limitation by processing in batches
def display_all_chars_with_cache_management():
"""Display characters starting from 81 through 256"""
# Clear previous attempts
while len(main_group) > 4: # Keep the 4 info labels
main_group.pop()
gc.collect()
char_width = 8
char_height = char_size[1]
chars_per_line = display.width // char_width
# Start from character 81, display through 256
start_char = 89
end_char = 240
total_chars = end_char - start_char
total_lines = (total_chars + chars_per_line - 1) // chars_per_line
# Create bitmap for the character range
bitmap_height = min(total_lines * char_height, display.height - 110)
charset_bitmap = Bitmap(display.width, bitmap_height, 2)
# Create palette
charset_palette = Palette(2)
charset_palette[0] = 0x000000 # Black background
charset_palette[1] = 0xFFFFFF # White text
print(f"Created bitmap: {display.width}x{bitmap_height} pixels")
print(f"Displaying characters {start_char}-{end_char-1}")
# Process characters in batches to work around glyph cache limits
batch_size = 80 # Process 80 characters at a time
total_displayed = 0
for batch_start in range(start_char, end_char, batch_size):
batch_end = min(batch_start + batch_size, end_char)
print(f"Processing batch {batch_start}-{batch_end-1}")
# Force garbage collection before each batch
gc.collect()
batch_displayed = 0
for code in range(batch_start, batch_end):
try:
# Calculate position (adjust for starting at character 81)
adjusted_index = code - start_char
char_x = (adjusted_index % chars_per_line) * char_width
char_y = (adjusted_index // chars_per_line) * char_height
# Skip if position is outside bitmap
if char_y + char_height > bitmap_height:
print(f"Reached bitmap height limit at character {code}")
break
# Get glyph and draw it
glyph = font.get_glyph(code)
# Draw with bounds checking
glyph_height = min(glyph.bitmap.height, char_height)
glyph_width = min(glyph.bitmap.width, char_width)
for py in range(glyph_height):
for px in range(glyph_width):
if (py + char_y < bitmap_height and
px + char_x < display.width):
try:
pixel_val = glyph.bitmap[px, py]
if pixel_val:
charset_bitmap[px + char_x, py + char_y] = 1
except (IndexError, MemoryError):
continue
batch_displayed += 1
total_displayed += 1
except (MemoryError, AttributeError, ValueError) as e:
print(f"Skipped character {code} in batch: {type(e).__name__}")
continue
print(f"Batch complete: {batch_displayed} characters drawn")
# Try to clear glyph cache between batches
try:
# Force garbage collection to potentially free glyph cache
gc.collect()
# Small delay to let things settle
import time
time.sleep(0.1)
except:
pass
# Create TileGrid to display the final bitmap
charset_tilegrid = TileGrid(
charset_bitmap,
pixel_shader=charset_palette,
x=0,
y=110
)
main_group.append(charset_tilegrid)
print(f"Final result: {total_displayed} characters from {start_char}-{end_char-1}")
return total_displayed
# Try the cache-aware approach
chars_displayed = display_all_chars_with_cache_management()
gc.collect()
print(f"Successfully displayed {chars_displayed} characters")
print(f"Final free memory: {gc.mem_free()} bytes")
while(True):
pass
Behavior
This code goes to great lengths to keep the number of glyphs displayed to below 167. If more are displayed, the program halts with memory errors, even if there is enough memory available.
Description
Trying to display all 255 glyphs in a .bdf font seems impossible as if one tries to display more than 167, there is a memory error.
Additional information
Displaying <167 glyphs works just fine and results in 40k memory free, so it is not hitting a memory barrier.