diff --git a/examples/ArduinoLogo/ArduinoLogo.ino b/examples/ArduinoLogo/ArduinoLogo.ino index 346b12e..529146e 100644 --- a/examples/ArduinoLogo/ArduinoLogo.ino +++ b/examples/ArduinoLogo/ArduinoLogo.ino @@ -17,7 +17,10 @@ INCBIN(test, "/home/user/Downloads/test.bin"); */ +// Default: video over the USB-C port Arduino_Video Display; +// To drive the Giga Display Shield on a Portenta H7 + Portenta Mid Carrier, use: +// Arduino_Video Display(800, 480, GigaDisplayShield); Image img_arduinologo(ENCODING_RGB16, (uint8_t *) texture_raw, 300, 300); diff --git a/src/Arduino_Video.cpp b/src/Arduino_Video.cpp index e1b3e46..5f5eb0a 100644 --- a/src/Arduino_Video.cpp +++ b/src/Arduino_Video.cpp @@ -11,13 +11,14 @@ #include "Arduino_Video.h" +#include "video_backend.h" #include "dsi.h" #include "logging.h" extern "C" { #include "video_modes.h" } -#if defined(__ZEPHYR__) && defined(ARDUINO_GIGA) +#if defined(ARDUINO_VIDEO_DIRECT_FB) #include #include #include @@ -43,7 +44,7 @@ void lvgl_displayFlushing(lv_display_t *display, const lv_area_t *area, unsigned #endif #endif /* __has_include ("lvgl.h") */ -#if defined(ARDUINO_GIGA) && defined(__ZEPHYR__) +#if defined(ARDUINO_VIDEO_DIRECT_FB) /* Note: These variables are defined in the global scope because the LVGL * 'lvgl_displayFlushing' callback is a static function */ const struct device *display_dev; @@ -96,7 +97,7 @@ int Arduino_Video::begin() { textFont(Font_5x7); #endif -#if defined(ARDUINO_GIGA) && defined(__ZEPHYR__) // Backend for Arduino Giga R1 +#if defined(ARDUINO_VIDEO_DIRECT_FB) // Framebuffer-managed panel (ST7701) display_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display)); if (!device_is_ready(display_dev)) { @@ -107,6 +108,8 @@ int Arduino_Video::begin() { } #if DT_NODE_EXISTS(DT_NODELABEL(st7701)) + /* The ST7701 panel is deferred-init: bring it up now that the DSI host and + LTDC are ready (its boot-time init runs too early and fails). */ const struct device *panel_dev = DEVICE_DT_GET(DT_NODELABEL(st7701)); if (!device_is_ready(panel_dev)) { if (zephyr::arduino::init_dev_apply_pinctrl(panel_dev) < 0) { @@ -207,7 +210,7 @@ void Arduino_Video::end() { void Arduino_Video::beginDraw() { ArduinoGraphics::beginDraw(); -#if defined(ARDUINO_GIGA) && defined(__ZEPHYR__) +#if defined(ARDUINO_VIDEO_DIRECT_FB) uint16_t *fb = (uint16_t *)display_get_framebuffer(display_dev); memset(fb, 0, display_caps.x_resolution * display_caps.y_resolution * sizeof(uint16_t)); #else @@ -218,7 +221,7 @@ void Arduino_Video::beginDraw() { void Arduino_Video::endDraw() { ArduinoGraphics::endDraw(); -#if defined(ARDUINO_GIGA) && defined(__ZEPHYR__) +#if defined(ARDUINO_VIDEO_DIRECT_FB) // no need to explicitly flush, as we are writing directly to the framebuffer #else dsi_drawCurrentFrameBuffer(); @@ -229,7 +232,7 @@ void Arduino_Video::clear() { [[maybe_unused]] uint32_t bg = ArduinoGraphics::background(); [[maybe_unused]] uint32_t x_size, y_size; -#if defined(ARDUINO_GIGA) && defined(__ZEPHYR__) +#if defined(ARDUINO_VIDEO_DIRECT_FB) uint16_t *fb = (uint16_t *)display_get_framebuffer(display_dev); memset(fb, 0, display_caps.x_resolution * display_caps.y_resolution * 2); #else @@ -262,7 +265,7 @@ void Arduino_Video::set(int x, int y, uint8_t r, uint8_t g, uint8_t b) { return; } -#if defined(ARDUINO_GIGA) && defined(__ZEPHYR__) +#if defined(ARDUINO_VIDEO_DIRECT_FB) if (x_rot >= display_caps.x_resolution || y_rot >= display_caps.y_resolution) return; #else @@ -270,7 +273,7 @@ void Arduino_Video::set(int x, int y, uint8_t r, uint8_t g, uint8_t b) { return; #endif -#if defined(ARDUINO_GIGA) && defined(__ZEPHYR__) +#if defined(ARDUINO_VIDEO_DIRECT_FB) // The pixel is written directly into the framebuffer in RGB565 format. // Rotation is automatically handled if the display is rotated. uint16_t color = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3); @@ -318,7 +321,7 @@ void lvgl_displayFlushing(lv_display_t *disp, const lv_area_t *area, unsigned ch h = temp; } -#if defined(ARDUINO_GIGA) && defined(__ZEPHYR__) +#if defined(ARDUINO_VIDEO_DIRECT_FB) uint16_t *dst = buffer; uint16_t *src = (uint16_t *)px_map; @@ -336,7 +339,7 @@ void lvgl_displayFlushing(lv_display_t *disp, const lv_area_t *area, unsigned ch #endif //end lvgl int Arduino_Video::drawBuffer([[maybe_unused]]uint16_t x, [[maybe_unused]]uint16_t y, [[maybe_unused]]const void *buf) { -#if defined(ARDUINO_GIGA) && defined(__ZEPHYR__) +#if defined(ARDUINO_VIDEO_DIRECT_FB) if (!device_is_ready(display_dev)) { return -ENODEV; } @@ -347,7 +350,7 @@ int Arduino_Video::drawBuffer([[maybe_unused]]uint16_t x, [[maybe_unused]]uint16 } void *Arduino_Video::getFramebuffer() { -#if defined(ARDUINO_GIGA) && defined(__ZEPHYR__) +#if defined(ARDUINO_VIDEO_DIRECT_FB) /* * In Zephyr, 'buffer' is the pointer allocated or retrieved from the display device during begin() */ void *fb = display_get_framebuffer(display_dev); return fb; @@ -356,7 +359,7 @@ void *Arduino_Video::getFramebuffer() { #endif } -#if defined(ARDUINO_GIGA) && defined(__ZEPHYR__) +#if defined(ARDUINO_VIDEO_DIRECT_FB) void Arduino_Video::setFrameDesc(uint16_t w, uint16_t h, uint16_t pitch, uint32_t buf_size) { desc.buf_size = buf_size; desc.width = w; /** Number of pixels between consecutive rows in the data buffer */ diff --git a/src/DisplayShield.cpp b/src/DisplayShield.cpp index 498bc58..ba825ee 100644 --- a/src/DisplayShield.cpp +++ b/src/DisplayShield.cpp @@ -13,11 +13,13 @@ #include "Arduino.h" #include "anx7625.h" +#include "video_backend.h" extern "C" { #include "video_modes.h" } -#if defined(ARDUINO_GIGA) && defined(__ZEPHYR__) +#if defined(ARDUINO_VIDEO_DIRECT_FB) +// Panel driven by the Zephyr ST7701 driver; the library uses the framebuffer. int GigaDisplayShieldClass::init([[maybe_unused]]int edidmode) { return 0; } @@ -31,9 +33,31 @@ int GigaDisplayShieldClass::getStatus() { } GigaDisplayShieldClass GigaDisplayShield; -#endif /* ARDUINO_GIGA && __ZEPHYR__ */ +#elif defined(ARDUINO_PORTENTA_H7_M7) && defined(__ZEPHYR__) +// The Giga Display Shield needs the core built with the Portenta H7 Giga +// Display configuration (ST7701 panel enabled in devicetree). +int GigaDisplayShieldClass::init([[maybe_unused]]int edidmode) { + return -1; +} + +int GigaDisplayShieldClass::getEdidMode([[maybe_unused]]int h, [[maybe_unused]] int v) { + return EDID_MODE_480x800_60Hz; +} + +int GigaDisplayShieldClass::getStatus() { + return 0; +} + +GigaDisplayShieldClass GigaDisplayShield; +#endif int USBCVideoClass::init(int edidmode) { +#if defined(ARDUINO_VIDEO_DIRECT_FB) + /* USB-C/ANX7625 pipeline is not built in a framebuffer-managed (ST7701) + configuration; the panel is driven directly by its Zephyr driver. */ + (void)edidmode; + return -1; +#else struct edid recognized_edid; int err_code = 0; @@ -61,6 +85,7 @@ int USBCVideoClass::init(int edidmode) { } return 0; +#endif } int USBCVideoClass::getEdidMode(int h, int v) { @@ -70,9 +95,13 @@ int USBCVideoClass::getEdidMode(int h, int v) { } int USBCVideoClass::getStatus() { +#if defined(ARDUINO_VIDEO_DIRECT_FB) + return 0; +#else int detected = anx7625_get_hpd_event(0); return detected; +#endif } USBCVideoClass USBCVideo; diff --git a/src/anx7625.cpp b/src/anx7625.cpp index 0ed8800..a62bc61 100644 --- a/src/anx7625.cpp +++ b/src/anx7625.cpp @@ -23,8 +23,9 @@ #include #include "logging.h" +#include "video_backend.h" -#if defined(ARDUINO_PORTENTA_H7_M7) +#if defined(ARDUINO_PORTENTA_H7_M7) && !defined(ARDUINO_VIDEO_DIRECT_FB) #include "dsi.h" #include "anx7625.h" diff --git a/src/dsi.cpp b/src/dsi.cpp index 979e40f..2b57b74 100644 --- a/src/dsi.cpp +++ b/src/dsi.cpp @@ -9,7 +9,9 @@ */ -#if defined(__ZEPHYR__) && !defined(ARDUINO_GIGA) +#include "video_backend.h" + +#if defined(__ZEPHYR__) && !defined(ARDUINO_VIDEO_DIRECT_FB) #include #include diff --git a/src/platform.cpp b/src/platform.cpp index e92c04f..5f49d83 100644 --- a/src/platform.cpp +++ b/src/platform.cpp @@ -19,12 +19,13 @@ #include "platform.h" #include "logging.h" +#include "video_backend.h" #if __has_include("lvgl.h") #include "lvgl.h" #endif -#if defined(ARDUINO_PORTENTA_H7_M7) +#if defined(ARDUINO_PORTENTA_H7_M7) && !defined(ARDUINO_VIDEO_DIRECT_FB) /* GPIO specifications from devicetree */ #define ANX7625_NODE DT_NODELABEL(anx7625) diff --git a/src/video_backend.h b/src/video_backend.h new file mode 100644 index 0000000..b93320f --- /dev/null +++ b/src/video_backend.h @@ -0,0 +1,34 @@ +/* + This file is part of the Arduino_Video library. + + Copyright (C) Arduino s.r.l. and/or its affiliated companies + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +*/ + +#ifndef _ARDUINO_VIDEO_BACKEND_H +#define _ARDUINO_VIDEO_BACKEND_H + +/* + * ARDUINO_VIDEO_DIRECT_FB selects the display backend at build time: + * + * - defined -> the panel is fully managed by a Zephyr display driver + * (ST7701 on the Giga Display Shield, either on the Giga R1 or + * on a Portenta H7 + midcarrier built with the Giga Display + * core configuration). The library draws straight into the + * LTDC framebuffer; the Zephyr driver performs the DSI panel + * bring-up at boot. + * - undefined -> the library drives the MIPI-DSI bridge itself (anx7625 over + * USB-C on the Portenta H7). + */ +#if defined(__ZEPHYR__) +#include +#if DT_HAS_COMPAT_STATUS_OKAY(sitronix_st7701) +#define ARDUINO_VIDEO_DIRECT_FB 1 +#endif +#endif + +#endif /* _ARDUINO_VIDEO_BACKEND_H */