Skip to content

Allow setting of CIRCUITPY_DISPLAY_LIMIT in settings.toml #10214

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 14 commits into from
Closed
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
21 changes: 21 additions & 0 deletions docs/environment.rst
Original file line number Diff line number Diff line change
@@ -179,6 +179,27 @@ Example: Configure the display to 640x480 black and white (1 bit per pixel):
`Adafruit Feather RP2350 <https://circuitpython.org/board/adafruit_feather_rp2350/>`_
`Adafruit Metro RP2350 <https://circuitpython.org/board/adafruit_metro_rp2350/>`_

CIRCUITPY_DISPLAY_LIMIT
~~~~~~~~~~~~~~~~~~~~~~~
Set the maximum supported number of displayio displays. This value overrides the
CIRCUITPY_DISPLAY_LIMIT compile-time flag defined in mpconfigport.h.
It specifies the maximum number of active display objects that can be supported simultaneously
on a CircuitPython board.

By default, the value of CIRCUITPY_DISPLAY_LIMIT is set to 1 for most boards, meaning only
one display can be active at a time. Users can modify this value by adding a settings.toml entry
to support additional displays.

The value of CIRCUITPY_DISPLAY_LIMIT should be set to a value that is supported by the
hardware and does not exceed the available memory and resources on the board. Setting the
value too high may result in unexpected behavior or crashes.

Example: Set the maximum supported number of displayio displays to 2:

.. code-block::

CIRCUITPY_DISPLAY_LIMIT=2

CIRCUITPY_TERMINAL_SCALE
~~~~~~~~~~~~~~~~~~~~~~~~
Allows the entry of a display scaling factor used during the terminalio console construction.
1 change: 1 addition & 0 deletions ports/atmel-samd/mpconfigport.mk
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@ CIRCUITPY_LTO = 1

CIRCUITPY_KEYPAD_DEMUX ?= 0
CIRCUITPY_LVFONTIO ?= 0
CIRCUITPY_SET_DISPLAY_LIMIT ?= 0

######################################################################
# Put samd21-only choices here.
1 change: 1 addition & 0 deletions ports/stm/boards/stm32f411ve_discovery/mpconfigboard.mk
Original file line number Diff line number Diff line change
@@ -24,3 +24,4 @@ CIRCUITPY_BLEIO_HCI = 0
CIRCUITPY_CODEOP = 0
CIRCUITPY_MSGPACK = 0
CIRCUITPY_VECTORIO = 0
CIRCUITPY_SET_DISPLAY_LIMIT = 0
3 changes: 3 additions & 0 deletions py/circuitpy_mpconfig.mk
Original file line number Diff line number Diff line change
@@ -227,6 +227,9 @@ CFLAGS += -DCIRCUITPY_COUNTIO=$(CIRCUITPY_COUNTIO)
CIRCUITPY_DISPLAYIO ?= $(CIRCUITPY_FULL_BUILD)
CFLAGS += -DCIRCUITPY_DISPLAYIO=$(CIRCUITPY_DISPLAYIO)

CIRCUITPY_SET_DISPLAY_LIMIT ?= $(CIRCUITPY_DISPLAYIO)
CFLAGS += -DCIRCUITPY_SET_DISPLAY_LIMIT=$(CIRCUITPY_SET_DISPLAY_LIMIT)

CIRCUITPY_BUSDISPLAY ?= $(CIRCUITPY_DISPLAYIO)
CFLAGS += -DCIRCUITPY_BUSDISPLAY=$(CIRCUITPY_BUSDISPLAY)

26 changes: 19 additions & 7 deletions shared-module/board/__init__.c
Original file line number Diff line number Diff line change
@@ -10,6 +10,10 @@
#include "mpconfigboard.h"
#include "py/runtime.h"

#if CIRCUITPY_OS_GETENV && CIRCUITPY_SET_DISPLAY_LIMIT
#include "shared-module/os/__init__.h"
#endif

#if CIRCUITPY_BUSIO
#include "shared-bindings/busio/I2C.h"
#include "shared-bindings/busio/SPI.h"
@@ -172,12 +176,20 @@ mp_obj_t common_hal_board_create_uart(const mp_int_t instance) {
#endif

void reset_board_buses(void) {
#if (CIRCUITPY_BOARD_I2C && CIRCUITPY_I2CDISPLAYBUS) || (CIRCUITPY_BOARD_SPI && (CIRCUITPY_FOURWIRE || CIRCUITPY_SHARPDISPLAY || CIRCUITPY_AURORA_EPAPER))
#if CIRCUITPY_OS_GETENV && CIRCUITPY_SET_DISPLAY_LIMIT
#define DYN_DISPLAY_BUSES(indx) (indx < CIRCUITPY_DISPLAY_LIMIT ? display_buses[indx] : display_buses_dyn[indx - CIRCUITPY_DISPLAY_LIMIT])
#else
#define DYN_DISPLAY_BUSES(indx) (display_buses[indx])
#endif
#endif

#if CIRCUITPY_BOARD_I2C
for (uint8_t instance = 0; instance < CIRCUITPY_BOARD_I2C; instance++) {
bool display_using_i2c = false;
#if CIRCUITPY_I2CDISPLAYBUS
for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) {
if (display_buses[i].bus_base.type == &i2cdisplaybus_i2cdisplaybus_type && display_buses[i].i2cdisplay_bus.bus == &i2c_obj[instance]) {
for (uint8_t i = 0; i < max_allocated_display; i++) {
if (DYN_DISPLAY_BUSES(i).bus_base.type == &i2cdisplaybus_i2cdisplaybus_type && DYN_DISPLAY_BUSES(i).i2cdisplay_bus.bus == &i2c_obj[instance]) {
display_using_i2c = true;
break;
}
@@ -197,22 +209,22 @@ void reset_board_buses(void) {
for (uint8_t instance = 0; instance < CIRCUITPY_BOARD_SPI; instance++) {
bool display_using_spi = false;
#if CIRCUITPY_FOURWIRE || CIRCUITPY_SHARPDISPLAY || CIRCUITPY_AURORA_EPAPER
for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) {
mp_const_obj_t bus_type = display_buses[i].bus_base.type;
for (uint8_t i = 0; i < max_allocated_display; i++) {
mp_const_obj_t bus_type = DYN_DISPLAY_BUSES(i).bus_base.type;
#if CIRCUITPY_FOURWIRE
if (bus_type == &fourwire_fourwire_type && display_buses[i].fourwire_bus.bus == &spi_obj[instance]) {
if (bus_type == &fourwire_fourwire_type && DYN_DISPLAY_BUSES(i).fourwire_bus.bus == &spi_obj[instance]) {
display_using_spi = true;
break;
}
#endif
#if CIRCUITPY_SHARPDISPLAY
if (bus_type == &sharpdisplay_framebuffer_type && display_buses[i].sharpdisplay.bus == &spi_obj[instance]) {
if (bus_type == &sharpdisplay_framebuffer_type && DYN_DISPLAY_BUSES(i).sharpdisplay.bus == &spi_obj[instance]) {
display_using_spi = true;
break;
}
#endif
#if CIRCUITPY_AURORA_EPAPER
if (bus_type == &aurora_epaper_framebuffer_type && display_buses[i].aurora_epaper.bus == &spi_obj[instance]) {
if (bus_type == &aurora_epaper_framebuffer_type && DYN_DISPLAY_BUSES(i).aurora_epaper.bus == &spi_obj[instance]) {
display_using_spi = true;
break;
}
217 changes: 162 additions & 55 deletions shared-module/displayio/__init__.c

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions shared-module/displayio/__init__.h
Original file line number Diff line number Diff line change
@@ -101,11 +101,17 @@ typedef struct {

extern primary_display_bus_t display_buses[CIRCUITPY_DISPLAY_LIMIT];
extern primary_display_t displays[CIRCUITPY_DISPLAY_LIMIT];
extern mp_int_t max_allocated_display;
#if CIRCUITPY_OS_GETENV && CIRCUITPY_SET_DISPLAY_LIMIT
extern primary_display_bus_t *display_buses_dyn;
extern primary_display_t *displays_dyn;
#endif

extern displayio_group_t circuitpython_splash;

void displayio_background(void);
void reset_displays(void);
void malloc_display_memory(void);
void displayio_gc_collect(void);

primary_display_t *allocate_display(void);
23 changes: 19 additions & 4 deletions shared-module/epaperdisplay/EPaperDisplay.c
Original file line number Diff line number Diff line change
@@ -20,6 +20,10 @@
#include "supervisor/usb.h"
#endif

#if CIRCUITPY_OS_GETENV && CIRCUITPY_SET_DISPLAY_LIMIT
#include "shared-module/os/__init__.h"
#endif

#include <stdint.h>
#include <string.h>

@@ -501,13 +505,24 @@ void epaperdisplay_epaperdisplay_collect_ptrs(epaperdisplay_epaperdisplay_obj_t
}

size_t maybe_refresh_epaperdisplay(void) {
for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) {
if (displays[i].epaper_display.base.type != &epaperdisplay_epaperdisplay_type ||
displays[i].epaper_display.core.current_group != &circuitpython_splash) {
for (uint8_t i = 0; i < max_allocated_display; i++) {
epaperdisplay_epaperdisplay_obj_t *display;
#if CIRCUITPY_OS_GETENV && CIRCUITPY_SET_DISPLAY_LIMIT
if (i < CIRCUITPY_DISPLAY_LIMIT) {
display = &displays[i].epaper_display;
} else {
display = &displays_dyn[i - CIRCUITPY_DISPLAY_LIMIT].epaper_display;
}
#else
display = &displays[i].epaper_display;
#endif

if (display->base.type != &epaperdisplay_epaperdisplay_type ||
display->core.current_group != &circuitpython_splash) {
// Skip regular displays and those not showing the splash.
continue;
}
epaperdisplay_epaperdisplay_obj_t *display = &displays[i].epaper_display;

size_t time_to_refresh = common_hal_epaperdisplay_epaperdisplay_get_time_to_refresh(display);
if (time_to_refresh > 0) {
return time_to_refresh;
22 changes: 15 additions & 7 deletions supervisor/shared/web_workflow/web_workflow.c
Original file line number Diff line number Diff line change
@@ -1554,24 +1554,32 @@ static void _process_request(socketpool_socket_obj_t *socket, _request *request)
}

static bool supervisor_filesystem_access_could_block(void) {
bool could_block = false;
#if CIRCUITPY_FOURWIRE
mp_vfs_mount_t *vfs = MP_STATE_VM(vfs_mount_table);
if (!vfs->next) {
// Assume that the CIRCUITPY root is not sharing a SPI bus with the display SPI bus
return false;
}
// Check display 0 to see if it's on a fourwire (SPI) bus. If it is, blocking is possible
// in theory other displays could block but also in reality there's generally 0 or 1 displays
for (size_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) {
if (display_buses[i].bus_base.type != &fourwire_fourwire_type) {

#if CIRCUITPY_OS_GETENV && CIRCUITPY_SET_DISPLAY_LIMIT
#define DYN_DISPLAY_BUSES(indx) (indx < CIRCUITPY_DISPLAY_LIMIT ? display_buses[indx] : display_buses_dyn[indx - CIRCUITPY_DISPLAY_LIMIT])
#define DYN_DISPLAY_BUSES_ADR(indx, membr) (indx < CIRCUITPY_DISPLAY_LIMIT ? &display_buses[indx].membr : &display_buses_dyn[indx - CIRCUITPY_DISPLAY_LIMIT].membr)
#else
#define DYN_DISPLAY_BUSES(indx) (display_buses[indx])
#define DYN_DISPLAY_BUSES_ADR(indx, membr) (&display_buses[indx].membr)
#endif
// Check displays to see if it's on a fourwire (SPI) bus. If it is, blocking is possible
for (mp_int_t i = 0; i < max_allocated_display; i++) {
if (DYN_DISPLAY_BUSES(i).bus_base.type != &fourwire_fourwire_type) {
continue;
}
if (!common_hal_fourwire_fourwire_bus_free(MP_OBJ_FROM_PTR(&display_buses[i].bus_base))) {
return true;
if (!common_hal_fourwire_fourwire_bus_free(MP_OBJ_FROM_PTR(DYN_DISPLAY_BUSES_ADR(i, bus_base)))) {
could_block = true;
}
}
#endif
return false;
return could_block;
}

void supervisor_web_workflow_background(void *data) {