Skip to content

Commit

Permalink
Merge pull request #10062 from jepler/feather-rp2350-autodvi-rebased
Browse files Browse the repository at this point in the history
Add supervisor.runtime.display & RP2350 DVI autoconfig (rebased version)
  • Loading branch information
tannewt authored Feb 14, 2025
2 parents 73c4b46 + e8eed62 commit e5e7c9e
Show file tree
Hide file tree
Showing 14 changed files with 338 additions and 11 deletions.
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
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

0 comments on commit e5e7c9e

Please sign in to comment.