diff --git a/docs/environment.rst b/docs/environment.rst
index 7ee914e0a16ec..461fd9273acd8 100644
--- a/docs/environment.rst
+++ b/docs/environment.rst
@@ -101,15 +101,14 @@ Wi-Fi SSID to auto-connect to even if user code is not running.
Additional board specific keys
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-`MaTouch ESP32-S3 Parallel TFT with Touch 7“ `_
-
-CIRCUITPY_DISPLAY_WIDTH
-~~~~~~~~~~~~~~~~~~~~~~~
+CIRCUITPY_DISPLAY_WIDTH (Sunton, MaTouch)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Selects the correct screen resolution (1024x600 or 800x640) for the particular board variant.
If the CIRCUITPY_DISPLAY_WIDTH parameter is set to a value of 1024 the display is initialized
during power up at 1024x600 otherwise the display will be initialized at a resolution
of 800x480.
+`MaTouch ESP32-S3 Parallel TFT with Touch 7“ `_
`Sunton ESP32-2432S028 `_
`Sunton ESP32-2432S024C `_
@@ -122,6 +121,8 @@ a rotation of 0. Attempting to initialize the screen with a rotation other than
90, 180 or 270 is not supported and will result in an unexpected screen rotation.
`Sunton ESP32-8048S050 `_
+`Adafruit Feather RP2350 `_
+`Adafruit Metro RP2350 `_
CIRCUITPY_DISPLAY_FREQUENCY
~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -130,3 +131,46 @@ If a valid frequency is not defined the board will initialize the framebuffer wi
frequency of 12500000hz (12.5Mhz). The value should be entered as an integer in hertz
i.e. CIRCUITPY_DISPLAY_FREQUENCY=16000000 will override the default value with a 16Mhz
display frequency.
+
+`Sunton ESP32-8048S050 `_
+
+
+CIRCUITPY_PICODVI_ENABLE
+~~~~~~~~~~~~~~~~~~~~~~~~
+Whether to configure the display at board initialization time, one of the following:
+
+.. code-block::
+
+ CIRCUITPY_PICODVI_ENABLE="detect" # when EDID EEPROM is detected (default)
+ CIRCUITPY_PICODVI_ENABLE="always"
+ CIRCUITPY_PICODVI_ENABLE="never"
+
+A display configured in this manner is available at ``supervisor.runtime.display``
+until it is released by ``displayio.release_displays()``. It does not appear at
+``board.DISPLAY``.
+
+`Adafruit Feather RP2350 `_
+`Adafruit Metro RP2350 `_
+
+CIRCUITPY_DISPLAY_WIDTH, CIRCUITPY_DISPLAY_HEIGHT, and CIRCUITPY_DISPLAY_COLOR_DEPTH (RP2350 boards with DVI or HSTX connector)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Selects the desired resolution and color depth.
+
+Supported resolutions are:
+ * 640x480 with color depth 1, 2, 4 or 8 bits per pixel
+ * 320x240 with color depth 8 or 16 bits per pixel
+
+The default value, if unspecified, is 320x240 with 16 bits per pixel.
+
+If height is unspecified, it is set from the width. For example, a width of 640
+implies a height of 480.
+
+Example: Configure the display to 640x480 black and white (1 bit per pixel):
+
+.. code-block::
+
+ CIRCUITPY_DISPLAY_WIDTH=640
+ CIRCUITPY_DISPLAY_COLOR_DEPTH=1
+
+`Adafruit Feather RP2350 `_
+`Adafruit Metro RP2350 `_
diff --git a/main.c b/main.c
index 7ac4194a75f04..763a3c1e0c197 100644
--- a/main.c
+++ b/main.c
@@ -772,6 +772,9 @@ static bool __attribute__((noinline)) run_code_py(safe_mode_t safe_mode, bool *s
#if CIRCUITPY_ALARM
if (fake_sleeping) {
board_init();
+ #if CIRCUITPY_DISPLAYIO
+ common_hal_displayio_auto_primary_display();
+ #endif
// Pretend that the next run is the first run, as if we were reset.
*simulate_reset = true;
}
@@ -1053,6 +1056,10 @@ int __attribute__((used)) main(void) {
// displays init after filesystem, since they could share the flash SPI
board_init();
+ #if CIRCUITPY_DISPLAYIO
+ common_hal_displayio_auto_primary_display();
+ #endif
+
mp_hal_stdout_tx_str(line_clear);
// This is first time we are running CircuitPython after a reset or power-up.
diff --git a/ports/raspberrypi/Makefile b/ports/raspberrypi/Makefile
index cf40af7baba64..9e36a93490d3a 100644
--- a/ports/raspberrypi/Makefile
+++ b/ports/raspberrypi/Makefile
@@ -556,6 +556,7 @@ ifeq ($(CIRCUITPY_PICODVI),1)
SRC_C += \
bindings/picodvi/__init__.c \
bindings/picodvi/Framebuffer.c \
+ common-hal/picodvi/__init__.c \
common-hal/picodvi/Framebuffer_$(CHIP_VARIANT).c \
ifeq ($(CHIP_VARIANT),RP2040)
diff --git a/ports/raspberrypi/bindings/picodvi/Framebuffer.h b/ports/raspberrypi/bindings/picodvi/Framebuffer.h
index 7cb335e91e767..280c3c9b8bf92 100644
--- a/ports/raspberrypi/bindings/picodvi/Framebuffer.h
+++ b/ports/raspberrypi/bindings/picodvi/Framebuffer.h
@@ -12,6 +12,9 @@
extern const mp_obj_type_t picodvi_framebuffer_type;
+bool common_hal_picodvi_framebuffer_preflight(
+ mp_uint_t width, mp_uint_t height,
+ mp_uint_t color_depth);
void common_hal_picodvi_framebuffer_construct(picodvi_framebuffer_obj_t *self,
mp_uint_t width, mp_uint_t height,
const mcu_pin_obj_t *clk_dp, const mcu_pin_obj_t *clk_dn,
diff --git a/ports/raspberrypi/boards/adafruit_feather_rp2350/board.c b/ports/raspberrypi/boards/adafruit_feather_rp2350/board.c
index e6a868ab21226..fddd2572c1fcd 100644
--- a/ports/raspberrypi/boards/adafruit_feather_rp2350/board.c
+++ b/ports/raspberrypi/boards/adafruit_feather_rp2350/board.c
@@ -4,6 +4,13 @@
//
// SPDX-License-Identifier: MIT
+#include "py/obj.h"
#include "supervisor/board.h"
+#include "common-hal/picodvi/__init__.h"
+
// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here.
+
+void board_init(void) {
+ picodvi_autoconstruct();
+}
diff --git a/ports/raspberrypi/boards/adafruit_feather_rp2350/mpconfigboard.h b/ports/raspberrypi/boards/adafruit_feather_rp2350/mpconfigboard.h
index 1e238789a3dde..d0c114a97e4ef 100644
--- a/ports/raspberrypi/boards/adafruit_feather_rp2350/mpconfigboard.h
+++ b/ports/raspberrypi/boards/adafruit_feather_rp2350/mpconfigboard.h
@@ -20,3 +20,12 @@
#define DEFAULT_UART_BUS_TX (&pin_GPIO0)
#define CIRCUITPY_PSRAM_CHIP_SELECT (&pin_GPIO8)
+
+#define DEFAULT_DVI_BUS_CLK_DN (&pin_GPIO15)
+#define DEFAULT_DVI_BUS_CLK_DP (&pin_GPIO14)
+#define DEFAULT_DVI_BUS_RED_DN (&pin_GPIO19)
+#define DEFAULT_DVI_BUS_RED_DP (&pin_GPIO18)
+#define DEFAULT_DVI_BUS_GREEN_DN (&pin_GPIO17)
+#define DEFAULT_DVI_BUS_GREEN_DP (&pin_GPIO16)
+#define DEFAULT_DVI_BUS_BLUE_DN (&pin_GPIO13)
+#define DEFAULT_DVI_BUS_BLUE_DP (&pin_GPIO12)
diff --git a/ports/raspberrypi/boards/adafruit_metro_rp2350/board.c b/ports/raspberrypi/boards/adafruit_metro_rp2350/board.c
index 111fc5175139c..f85d1076c0b4f 100644
--- a/ports/raspberrypi/boards/adafruit_metro_rp2350/board.c
+++ b/ports/raspberrypi/boards/adafruit_metro_rp2350/board.c
@@ -9,6 +9,8 @@
#include "shared-bindings/usb_host/Port.h"
#include "supervisor/board.h"
+#include "common-hal/picodvi/__init__.h"
+
// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here.
@@ -29,8 +31,9 @@ bool board_reset_pin_number(uint8_t pin_number) {
}
#endif
-#if defined(DEFAULT_USB_HOST_DATA_PLUS)
void board_init(void) {
+ #if defined(DEFAULT_USB_HOST_DATA_PLUS)
common_hal_usb_host_port_construct(DEFAULT_USB_HOST_DATA_PLUS, DEFAULT_USB_HOST_DATA_MINUS);
+ #endif
+ picodvi_autoconstruct();
}
-#endif
diff --git a/ports/raspberrypi/boards/adafruit_metro_rp2350/mpconfigboard.h b/ports/raspberrypi/boards/adafruit_metro_rp2350/mpconfigboard.h
index c8e73600d07df..694a07027354d 100644
--- a/ports/raspberrypi/boards/adafruit_metro_rp2350/mpconfigboard.h
+++ b/ports/raspberrypi/boards/adafruit_metro_rp2350/mpconfigboard.h
@@ -26,3 +26,12 @@
#define DEFAULT_USB_HOST_DATA_MINUS (&pin_GPIO33)
#define DEFAULT_USB_HOST_5V_POWER (&pin_GPIO29)
#define CIRCUITPY_PSRAM_CHIP_SELECT (&pin_GPIO47)
+
+#define DEFAULT_DVI_BUS_CLK_DN (&pin_GPIO15)
+#define DEFAULT_DVI_BUS_CLK_DP (&pin_GPIO14)
+#define DEFAULT_DVI_BUS_RED_DN (&pin_GPIO19)
+#define DEFAULT_DVI_BUS_RED_DP (&pin_GPIO18)
+#define DEFAULT_DVI_BUS_GREEN_DN (&pin_GPIO17)
+#define DEFAULT_DVI_BUS_GREEN_DP (&pin_GPIO16)
+#define DEFAULT_DVI_BUS_BLUE_DN (&pin_GPIO13)
+#define DEFAULT_DVI_BUS_BLUE_DP (&pin_GPIO12)
diff --git a/ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c b/ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c
index c3d2b7bea2f17..d5845b1182202 100644
--- a/ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c
+++ b/ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c
@@ -129,6 +129,20 @@ static void __not_in_flash_func(dma_irq_handler)(void) {
ch->al3_read_addr_trig = (uintptr_t)active_picodvi->dma_commands;
}
+bool common_hal_picodvi_framebuffer_preflight(
+ mp_uint_t width, mp_uint_t height,
+ mp_uint_t color_depth) {
+
+ // for each supported resolution, check the color depth is supported
+ if (width == 640 && height == 640) {
+ return color_depth == 1 || color_depth == 2 || color_depth == 4 || color_depth == 8;
+ }
+ if (width == 320 && height == 240) {
+ return color_depth == 8 || color_depth == 16;
+ }
+ return false;
+}
+
void common_hal_picodvi_framebuffer_construct(picodvi_framebuffer_obj_t *self,
mp_uint_t width, mp_uint_t height,
const mcu_pin_obj_t *clk_dp, const mcu_pin_obj_t *clk_dn,
@@ -140,7 +154,7 @@ void common_hal_picodvi_framebuffer_construct(picodvi_framebuffer_obj_t *self,
mp_raise_msg_varg(&mp_type_RuntimeError, MP_ERROR_TEXT("%q in use"), MP_QSTR_picodvi);
}
- if (!(width == 640 && height == 480) && !(width == 320 && height == 240 && (color_depth == 16 || color_depth == 8))) {
+ if (!common_hal_picodvi_framebuffer_preflight(width, height, color_depth)) {
mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q and %q"), MP_QSTR_width, MP_QSTR_height);
}
diff --git a/ports/raspberrypi/common-hal/picodvi/__init__.c b/ports/raspberrypi/common-hal/picodvi/__init__.c
new file mode 100644
index 0000000000000..bf448dd16688d
--- /dev/null
+++ b/ports/raspberrypi/common-hal/picodvi/__init__.c
@@ -0,0 +1,119 @@
+// This file is part of the CircuitPython project: https://circuitpython.org
+//
+// SPDX-FileCopyrightText: Copyright (c) 2025 Jeff Epler for Adafruit Industries
+//
+// SPDX-License-Identifier: MIT
+
+#include "common-hal/picodvi/__init__.h"
+#include "common-hal/picodvi/Framebuffer.h"
+#include "bindings/picodvi/Framebuffer.h"
+#include "shared-bindings/busio/I2C.h"
+#include "shared-bindings/board/__init__.h"
+#include "shared-module/displayio/__init__.h"
+#include "shared-module/os/__init__.h"
+#include "supervisor/shared/safe_mode.h"
+#include "py/gc.h"
+#include "py/runtime.h"
+#include "supervisor/port_heap.h"
+
+#if defined(DEFAULT_DVI_BUS_CLK_DP)
+static bool picodvi_autoconstruct_enabled(void) {
+ char buf[sizeof("detect")];
+ buf[0] = 0;
+
+ // (any failure leaves the content of buf untouched: an empty nul-terminated string
+ (void)common_hal_os_getenv_str("CIRCUITPY_PICODVI_ENABLE", buf, sizeof(buf));
+
+ if (!strcasecmp(buf, "never")) {
+ return false;
+ }
+ if (!strcasecmp(buf, "always")) {
+ return true;
+ }
+
+ // It's "detect" or else an invalid value which is treated the same as "detect".
+
+ // check if address 0x50 is live on the I2C bus
+ busio_i2c_obj_t *i2c = common_hal_board_create_i2c(0);
+ if (!i2c) {
+ return false;
+ }
+ if (!common_hal_busio_i2c_try_lock(i2c)) {
+ return false;
+ }
+ bool probed = common_hal_busio_i2c_probe(i2c, 0x50);
+ common_hal_busio_i2c_unlock(i2c);
+ return probed;
+}
+
+// For picodvi_autoconstruct to work, the 8 DVI/HSTX pin names must be defined, AND
+// i2c bus 0 must also be connected to DVI with on-board pull ups
+void picodvi_autoconstruct(void) {
+ if (get_safe_mode() != SAFE_MODE_NONE) {
+ return;
+ }
+
+ if (!picodvi_autoconstruct_enabled()) {
+ return;
+ }
+
+ mp_int_t width = 320;
+ mp_int_t height = 0;
+ mp_int_t color_depth = 16;
+ mp_int_t rotation = 0;
+
+ (void)common_hal_os_getenv_int("CIRCUITPY_DISPLAY_WIDTH", &width);
+ (void)common_hal_os_getenv_int("CIRCUITPY_DISPLAY_HEIGHT", &height);
+ (void)common_hal_os_getenv_int("CIRCUITPY_DISPLAY_COLOR_DEPTH", &color_depth);
+ (void)common_hal_os_getenv_int("CIRCUITPY_DISPLAY_ROTATION", &rotation);
+
+ if (height == 0) {
+ switch (width) {
+ case 640:
+ height = 480;
+ break;
+ case 320:
+ height = 240;
+ break;
+ }
+ }
+
+ if (rotation != 0 && rotation != 90 && rotation != 180 && rotation != 270) {
+ // invalid rotation
+ rotation = 0;
+ }
+
+ if (!common_hal_picodvi_framebuffer_preflight(width, height, color_depth)) {
+ // invalid configuration, set back to default
+ width = 320;
+ height = 240;
+ color_depth = 16;
+ }
+
+ // construct framebuffer and display
+ picodvi_framebuffer_obj_t *fb = &allocate_display_bus_or_raise()->picodvi;
+ fb->base.type = &picodvi_framebuffer_type;
+ common_hal_picodvi_framebuffer_construct(fb,
+ width, height,
+ DEFAULT_DVI_BUS_CLK_DP,
+ DEFAULT_DVI_BUS_CLK_DN,
+ DEFAULT_DVI_BUS_RED_DP,
+ DEFAULT_DVI_BUS_RED_DN,
+ DEFAULT_DVI_BUS_GREEN_DP,
+ DEFAULT_DVI_BUS_GREEN_DN,
+ DEFAULT_DVI_BUS_BLUE_DP,
+ DEFAULT_DVI_BUS_BLUE_DN,
+ color_depth);
+
+ framebufferio_framebufferdisplay_obj_t *display = &allocate_display()->framebuffer_display;
+ display->base.type = &framebufferio_framebufferdisplay_type;
+ common_hal_framebufferio_framebufferdisplay_construct(
+ display,
+ MP_OBJ_FROM_PTR(fb),
+ rotation,
+ true);
+}
+#else
+void picodvi_autoconstruct(void) {
+}
+#endif
diff --git a/ports/raspberrypi/common-hal/picodvi/__init__.h b/ports/raspberrypi/common-hal/picodvi/__init__.h
new file mode 100644
index 0000000000000..41f3656339a50
--- /dev/null
+++ b/ports/raspberrypi/common-hal/picodvi/__init__.h
@@ -0,0 +1,9 @@
+// This file is part of the CircuitPython project: https://circuitpython.org
+//
+// SPDX-FileCopyrightText: Copyright (c) 2025 Jeff Epler for Adafruit Industries
+//
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+extern void picodvi_autoconstruct(void);
diff --git a/shared-bindings/displayio/__init__.h b/shared-bindings/displayio/__init__.h
index 33987ebe38ae5..88e9650cf44a9 100644
--- a/shared-bindings/displayio/__init__.h
+++ b/shared-bindings/displayio/__init__.h
@@ -23,6 +23,9 @@ typedef enum displayio_colorspace {
} displayio_colorspace_t;
void common_hal_displayio_release_displays(void);
+mp_obj_t common_hal_displayio_get_primary_display(void);
+void common_hal_displayio_set_primary_display(mp_obj_t o);
+void common_hal_displayio_auto_primary_display(void);
extern const mp_obj_type_t displayio_colorspace_type;
extern const cp_enum_obj_t displayio_colorspace_RGB888_obj;
diff --git a/shared-bindings/supervisor/Runtime.c b/shared-bindings/supervisor/Runtime.c
index 9332cacb3eccd..15a0096361013 100644
--- a/shared-bindings/supervisor/Runtime.c
+++ b/shared-bindings/supervisor/Runtime.c
@@ -20,6 +20,10 @@
#include "supervisor/shared/status_leds.h"
#include "supervisor/shared/bluetooth/bluetooth.h"
+#if CIRCUITPY_DISPLAYIO
+#include "shared-bindings/displayio/__init__.h"
+#endif
+
#if CIRCUITPY_TINYUSB
#include "tusb.h"
#endif
@@ -183,7 +187,6 @@ MP_PROPERTY_GETSET(supervisor_runtime_ble_workflow_obj,
//| after the current code finishes and the status LED is used to show
//| the finish state."""
//|
-//|
static mp_obj_t supervisor_runtime_get_rgb_status_brightness(mp_obj_t self) {
return MP_OBJ_NEW_SMALL_INT(get_status_brightness());
}
@@ -204,6 +207,39 @@ MP_PROPERTY_GETSET(supervisor_runtime_rgb_status_brightness_obj,
(mp_obj_t)&supervisor_runtime_get_rgb_status_brightness_obj,
(mp_obj_t)&supervisor_runtime_set_rgb_status_brightness_obj);
+#if CIRCUITPY_DISPLAYIO
+//| display: Any
+//| """The primary configured displayio display, if any. Read-only.
+//|
+//| If the board has a display that is hard coded, or that was explicitly set
+//| in boot.py or code.py (including a previous run of code.py), it is
+//| available here until it is released with ``displayio.releasee_displays()``.
+//|
+//| The display can be of any supported display type, such as `busdisplay.BusDisplay`.
+//|
+//| If no display is configured, this property is `None`.
+//|
+//| In a future release of CircuitPython, any display that is not the primary display
+//| will be automatically released at the end of running a code file.
+//|
+//| On boards without displayio, this property is present but the value is always `None`."""
+//|
+//|
+static mp_obj_t supervisor_runtime_get_display(mp_obj_t self) {
+ return common_hal_displayio_get_primary_display();
+}
+MP_DEFINE_CONST_FUN_OBJ_1(supervisor_runtime_get_display_obj, supervisor_runtime_get_display);
+static mp_obj_t supervisor_runtime_set_display(mp_obj_t self, mp_obj_t new_primary_display) {
+ common_hal_displayio_set_primary_display(new_primary_display);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(supervisor_runtime_set_display_obj, supervisor_runtime_set_display);
+
+MP_PROPERTY_GETSET(supervisor_runtime_display_obj,
+ (mp_obj_t)&supervisor_runtime_get_display_obj,
+ (mp_obj_t)&supervisor_runtime_set_display_obj);
+#endif
+
static const mp_rom_map_elem_t supervisor_runtime_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_usb_connected), MP_ROM_PTR(&supervisor_runtime_usb_connected_obj) },
{ MP_ROM_QSTR(MP_QSTR_serial_connected), MP_ROM_PTR(&supervisor_runtime_serial_connected_obj) },
@@ -213,6 +249,11 @@ static const mp_rom_map_elem_t supervisor_runtime_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_autoreload), MP_ROM_PTR(&supervisor_runtime_autoreload_obj) },
{ MP_ROM_QSTR(MP_QSTR_ble_workflow), MP_ROM_PTR(&supervisor_runtime_ble_workflow_obj) },
{ MP_ROM_QSTR(MP_QSTR_rgb_status_brightness), MP_ROM_PTR(&supervisor_runtime_rgb_status_brightness_obj) },
+ #if CIRCUITPY_DISPLAYIO
+ { MP_ROM_QSTR(MP_QSTR_display), MP_ROM_PTR(&supervisor_runtime_display_obj) },
+ #else
+ { MP_ROM_QSTR(MP_QSTR_display), MP_ROM_NONE },
+ #endif
};
static MP_DEFINE_CONST_DICT(supervisor_runtime_locals_dict, supervisor_runtime_locals_dict_table);
diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c
index 3e1246b087600..4b467b75589d1 100644
--- a/shared-module/displayio/__init__.c
+++ b/shared-module/displayio/__init__.c
@@ -44,6 +44,9 @@
#include "supervisor/spi_flash_api.h"
#endif
+// The default indicates no primary display
+static int primary_display_number = -1;
+
primary_display_bus_t display_buses[CIRCUITPY_DISPLAY_LIMIT];
primary_display_t displays[CIRCUITPY_DISPLAY_LIMIT];
@@ -108,10 +111,16 @@ void displayio_background(void) {
}
-void common_hal_displayio_release_displays(void) {
+static void common_hal_displayio_release_displays_impl(bool keep_primary) {
// Release displays before busses so that they can send any final commands to turn the display
// off properly.
+ if (!keep_primary) {
+ primary_display_number = -1;
+ }
for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) {
+ if (i == primary_display_number) {
+ continue;
+ }
mp_const_obj_t display_type = displays[i].display_base.type;
if (display_type == NULL || display_type == &mp_type_NoneType) {
continue;
@@ -177,7 +186,14 @@ void common_hal_displayio_release_displays(void) {
supervisor_stop_terminal();
}
+void common_hal_displayio_release_displays(void) {
+ common_hal_displayio_release_displays_impl(false);
+}
+
void reset_displays(void) {
+ // In CircuitPython 10, release secondary displays before doing anything else:
+ // common_hal_displayio_release_displays_impl(true);
+
// The SPI buses used by FourWires may be allocated on the heap so we need to move them inline.
for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) {
mp_const_obj_t display_bus_type = display_buses[i].bus_base.type;
@@ -392,10 +408,13 @@ void displayio_gc_collect(void) {
}
}
+static bool is_display_active(mp_obj_base_t *display_maybe) {
+ return display_maybe->type != &mp_type_NoneType && display_maybe->type != NULL;
+}
+
primary_display_t *allocate_display(void) {
for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) {
- mp_const_obj_t display_type = displays[i].display_base.type;
- if (display_type == NULL || display_type == &mp_type_NoneType) {
+ if (!is_display_active(&displays[i].display_base)) {
// Clear this memory so it is in a known state before init.
memset(&displays[i], 0, sizeof(displays[i]));
// Default to None so that it works as board.DISPLAY.
@@ -434,3 +453,42 @@ primary_display_bus_t *allocate_display_bus_or_raise(void) {
}
mp_raise_RuntimeError(MP_ERROR_TEXT("Too many display busses; forgot displayio.release_displays() ?"));
}
+
+mp_obj_t common_hal_displayio_get_primary_display(void) {
+ if (primary_display_number == -1 || primary_display_number >= CIRCUITPY_DISPLAY_LIMIT) {
+ return mp_const_none;
+ }
+ mp_obj_base_t *primary_display = &displays[primary_display_number].display_base;
+ if (is_display_active(primary_display)) {
+ return MP_OBJ_FROM_PTR(primary_display);
+ }
+ return mp_const_none;
+}
+
+void common_hal_displayio_set_primary_display(mp_obj_t new_primary_display) {
+ if (new_primary_display == mp_const_none) {
+ primary_display_number = -1;
+ return;
+ }
+ for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) {
+ mp_obj_t display = MP_OBJ_FROM_PTR(&displays[i]);
+ if (new_primary_display == display && is_display_active(display)) {
+ primary_display_number = i;
+ return;
+ }
+ }
+ // object was not a display after all...
+ mp_raise_TypeError_varg(MP_ERROR_TEXT("%q must be of type %q or %q, not %q"), MP_QSTR_Display, MP_QSTR_AnyDisplay, MP_QSTR_None, mp_obj_get_type(new_primary_display)->name);
+}
+
+void common_hal_displayio_auto_primary_display(void) {
+ if (primary_display_number != -1) {
+ return;
+ }
+ for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) {
+ if (is_display_active(&displays[i].display_base)) {
+ primary_display_number = i;
+ return;
+ }
+ }
+}
pFad - Phonifier reborn
Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies:
Alternative Proxy
pFad Proxy
pFad v3 Proxy
pFad v4 Proxy