Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@
#include "shared-bindings/epaperdisplay/EPaperDisplay.h"
#endif

#if CIRCUITPY_PICOGAME_RGB444
#include "shared-module/picogame/__init__.h"
#endif

#if CIRCUITPY_KEYPAD
#include "shared-module/keypad/__init__.h"
#endif
Expand Down Expand Up @@ -374,6 +378,11 @@ static void cleanup_after_vm(mp_obj_t exception) {
atexit_reset();
#endif

// Restore the panel's pixel format while the display bus is still alive.
#if CIRCUITPY_PICOGAME_RGB444
picogame_reset();
#endif

// Turn off the display and flush the filesystem before the heap disappears.
#if CIRCUITPY_DISPLAYIO
reset_displays();
Expand Down
37 changes: 36 additions & 1 deletion shared-module/picogame/__init__.c
Original file line number Diff line number Diff line change
Expand Up @@ -976,6 +976,12 @@ bool picogame_strip_begin(
return true;
}

#if CIRCUITPY_PICOGAME_RGB444
// The display currently switched to RGB444, or NULL. The strip path packs for it and
// picogame_reset() restores it to RGB565 at the end of the program.
static picogame_output_t *rgb444_display = NULL;
#endif

// --- output transport seam (busdisplay backend): the ONLY per-strip display ops the generic
// picogame_render_region orchestrator below touches, so a non-CircuitPython port (MicroPython
// framebuf/SPI) swaps just strip_begin + these two + set_invert/set_pixel_format. See __init__.h.
Expand All @@ -993,6 +999,14 @@ void picogame_render_region(
int16_t x0, int16_t y0, int16_t x1, int16_t y1,
uint16_t background, int ox, int oy) {

#if CIRCUITPY_PICOGAME_RGB444
// RGB444 packs 2 px into 3 bytes, so widen the region to even x bounds.
bool rgb444 = (display == rgb444_display);
if (rgb444) {
x0 &= ~1;
x1 = (x1 + 1) & ~1;
}
#endif
int region_w, strip_h;
int cx0 = x0, cy0 = y0, cx1 = x1, cy1 = y1; // strip_begin clamps these to the panel in place
if (!picogame_strip_begin(display, &cx0, &cy0, &cx1, &cy1, buffer_pixels, &region_w, &strip_h)) {
Expand All @@ -1001,7 +1015,13 @@ void picogame_render_region(
for (int sy = cy0; sy < cy1; sy += strip_h) {
int sh = picogame_imin(strip_h, cy1 - sy);
mp_obj_t exc = picogame_blit_strip_layers(buffer, region_w, sy, sh, cx0, items, kinds, n, background, ox, oy);
picogame_out_strip_send(display, (uint8_t *)buffer, region_w * sh * 2);
size_t nbytes = (size_t)region_w * sh * 2;
#if CIRCUITPY_PICOGAME_RGB444
if (rgb444) {
nbytes = picogame_pack_rgb444(buffer, (size_t)region_w * sh); // in place, 3/4 the bytes
}
#endif
picogame_out_strip_send(display, (uint8_t *)buffer, nbytes);
if (exc != MP_OBJ_NULL) { // a StripDraw callback raised a BaseException: close the
picogame_out_strip_end(display); // bus, then re-raise (Ctrl-C / reload)
nlr_raise(MP_OBJ_TO_PTR(exc));
Expand Down Expand Up @@ -1029,6 +1049,7 @@ void picogame_set_invert(picogame_output_t *display, bool on) {
// Set the panel pixel format (COLMOD 0x3A): rgb444 -> 12-bit RGB444 (0x53), else 16-bit RGB565
// (0x55). Asserting it on every Display construct also recovers from a previous program that left
// the panel in the other format (survives soft reset).

void picogame_set_pixel_format(picogame_output_t *display, bool rgb444) {
uint8_t cmd = 0x3A;
uint8_t param = rgb444 ? 0x53 : 0x55;
Expand All @@ -1038,6 +1059,20 @@ void picogame_set_pixel_format(picogame_output_t *display, bool rgb444) {
display->bus.send(display->bus.bus, DISPLAY_COMMAND, CHIP_SELECT_TOGGLE_EVERY_BYTE, &cmd, 1);
display->bus.send(display->bus.bus, DISPLAY_DATA, CHIP_SELECT_UNTOUCHED, &param, 1);
displayio_display_bus_end_transaction(&display->bus);
rgb444_display = rgb444 ? display : NULL;
}

// Called at the end of a program, before reset_displays() takes the bus away.
void picogame_reset(void) {
if (rgb444_display == NULL) {
return;
}
// A released display has a None bus.
if (mp_obj_get_type(rgb444_display->bus.bus) == &mp_type_NoneType) {
rgb444_display = NULL;
return;
}
picogame_set_pixel_format(rgb444_display, false); // clears rgb444_display
}

// Pack a strip of `npix` (must be even) WIRE-order RGB565 pixels IN-PLACE to ST7789 12-bit RGB444
Expand Down
7 changes: 6 additions & 1 deletion shared-module/picogame/__init__.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,8 @@ void picogame_blit_bitmap_affine(
//
// Strip-path contract a backend provides:
// picogame_strip_begin - open a window for [x0,y0,x1,y1); return strip geometry
// picogame_out_strip_send - push one composited strip (region_w*sh px, wire RGB565)
// picogame_out_strip_send - push one composited strip (region_w*sh px, wire RGB565; packed to
// RGB444 first when that panel is in 12-bit mode)
// picogame_out_strip_end - close the transaction
// picogame_set_invert - panel hardware colour inversion (a free full-screen flash)
// picogame_set_pixel_format - panel COLMOD (RGB565/RGB444), when CIRCUITPY_PICOGAME_RGB444
Expand Down Expand Up @@ -248,6 +249,10 @@ bool picogame_fb_take_invert_dirty(void);
// Set panel pixel format (COLMOD): rgb444 -> 12-bit RGB444, else 16-bit RGB565.
void picogame_set_pixel_format(picogame_output_t *display, bool rgb444);

// Put a panel left in RGB444 back to RGB565 at the end of a program, so the console stays
// readable. Call before reset_displays().
void picogame_reset(void);

// Pack `npix` (even) wire-order RGB565 pixels in `buf` IN-PLACE to 12-bit RGB444; returns bytes.
size_t picogame_pack_rgb444(uint16_t *buf, size_t npix);
#endif
Expand Down
Loading