8000 Auto-configure display on some RP2350 boards by jepler · Pull Request #10028 · adafruit/circuitpython · GitHub
[go: up one dir, main page]

Skip to content

Auto-configure display on some RP2350 boards #10028

New issue
8000

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 20 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
db8d517
Auto-configure display on Feather RP2350
jepler Feb 4, 2025
4c61d61
Use module attribute delegation to make board.DISPLAY always work
jepler Feb 11, 2025
890c7f2
Move MaTouch link to the right spot
jepler Feb 11, 2025
9cbfc41
Document RP2350 DVI display configuration
jepler Feb 11, 2025
7e373ad
Add preflight function for picodvi display
jepler Feb 11, 2025
8675097
picodvi_autoconstruct: preflight settings, use width=0 to disable
jepler Feb 11, 2025
22f25c5
board: fix build errors
jepler Feb 11, 2025
551b981
metro rp2350: configure display pins & autoconstruct
jepler Feb 11, 2025
8be1681
remove this, it got moved to common code
jepler Feb 11, 2025
61ea718
eliminate a bit more code if the DVI/hstx pins aren't defined
jepler Feb 12, 2025
3a84599
fix the DISPLAYIO_ITEMS they were backwards
jepler Feb 12, 2025
e820416
Add an environment variable to disable or force picodvi
jepler Feb 12, 2025
1d9b83f
Merge remote-tracking branch 'origin/main' into feather-rp2350-autodvi
jepler Feb 12, 2025
201bc69
Remove a comment that refers to previously deleted code
jepler Feb 12, 2025
f0e3130
picodvi: Fall back to the default mode if preflight fails
jepler Feb 12, 2025
0846aa4
circuitpy_mpconfig: fix build config
jepler Feb 12, 2025
025f4fd
fix WIDTH unintentionally changed to HEIGHT
jepler Feb 12, 2025
4aeddf2
spell out environment variable names in full
jepler Feb 13, 2025
86fe684
Move the new display accessor to supervisor.runtime.display
jepler Feb 13, 2025
83415e7
Make primary display settable, defaults to None unless set by board_init
jepler Feb 13, 2025
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
52 changes: 48 additions & 4 deletions docs/environment.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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“ <https://circuitpython.org/board/makerfabs_tft7/>`_

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“ <https://circuitpython.org/board/makerfabs_tft7/>`_
`Sunton ESP32-2432S028 <https://circuitpython.org/board/sunton_esp32_2432S028/>`_
`Sunton ESP32-2432S024C <https://circuitpython.org/board/sunton_esp32_2432S024C/>`_

Expand All @@ -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 <https://circuitpython.org/board/sunton_esp32_8048S050/>`_
`Adafruit Feather RP2350 <https://circuitpython.org/board/adafruit_feather_rp2350/>`_
`Adafruit Metro RP2350 <https://circuitpython.org/board/adafruit_metro_rp2350/>`_

CIRCUITPY_DISPLAY_FREQUENCY
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand All @@ -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 <https://circuitpython.org/board/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 <https://circuitpython.org/board/adafruit_feather_rp2350/>`_
`Adafruit Metro RP2350 <https://circuitpython.org/board/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 <https://circuitpython.org/board/adafruit_feather_rp2350/>`_
`Adafruit Metro RP2350 <https://circuitpython.org/board/adafruit_metro_rp2350/>`_
7 changes: 7 additions & 0 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions ports/raspberrypi/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 3 additions & 0 deletions ports/raspberrypi/bindings/picodvi/Framebuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
7 changes: 7 additions & 0 deletions ports/raspberrypi/boards/adafruit_feather_rp2350/board.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)
7 changes: 5 additions & 2 deletions ports/raspberrypi/boards/adafruit_metro_rp2350/board.c
F438
Original file line number Diff line number Diff line change
Expand Up @@ -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.


Expand All @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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)
16 changes: 15 additions & 1 deletion ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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);
}

Expand Down
119 changes: 119 additions & 0 deletions ports/raspberrypi/common-hal/picodvi/__init__.c
Original file line number Diff line number Diff line change
@@ -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
9 changes: 9 additions & 0 deletions ports/raspberrypi/common-hal/picodvi/__init__.h
Original file line number Diff line number Diff line change
@@ -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);
3 changes: 3 additions & 0 deletions shared-bindings/displayio/__init__.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading
Loading
0