From cc9e9c94f47ab2982f40828caadb03d8c41a9ac0 Mon Sep 17 00:00:00 2001 From: "Kwabena W. Agyeman" Date: Sun, 6 Jul 2025 18:25:54 -0700 Subject: [PATCH 1/3] modules/py_spi_display: Add vflip/hmirror support. --- modules/py_spi_display.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/modules/py_spi_display.c b/modules/py_spi_display.c index 407733ec0..1320aced8 100644 --- a/modules/py_spi_display.c +++ b/modules/py_spi_display.c @@ -360,8 +360,8 @@ static void spi_display_deinit(py_display_obj_t *self) { mp_obj_t spi_display_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { enum { - ARG_width, ARG_height, ARG_refresh, ARG_bgr, ARG_byte_swap, ARG_triple_buffer, - ARG_controller, ARG_backlight + ARG_width, ARG_height, ARG_refresh, ARG_bgr, ARG_byte_swap, ARG_hmirror, ARG_vflip, + ARG_triple_buffer, ARG_controller, ARG_backlight }; static const mp_arg_t allowed_args[] = { { MP_QSTR_width, MP_ARG_INT, {.u_int = 128 } }, @@ -369,6 +369,8 @@ mp_obj_t spi_display_make_new(const mp_obj_type_t *type, size_t n_args, size_t n { MP_QSTR_refresh, MP_ARG_INT, {.u_int = 60 } }, { MP_QSTR_bgr, MP_ARG_BOOL, {.u_bool = false} }, { MP_QSTR_byte_swap, MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_hmirror, MP_ARG_BOOL, {.u_bool = true} }, + { MP_QSTR_vflip, MP_ARG_BOOL, {.u_bool = true} }, { MP_QSTR_triple_buffer, MP_ARG_BOOL, {.u_bool = LCD_TRIPLE_BUFFER_DEFAULT} }, { MP_QSTR_controller, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_NONE} }, { MP_QSTR_backlight, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_NONE} }, @@ -435,7 +437,17 @@ mp_obj_t spi_display_make_new(const mp_obj_type_t *type, size_t n_args, size_t n spi_display_command(self, LCD_COMMAND_SLPOUT, 0); mp_hal_delay_ms(120); // Memory data access control - spi_display_command(self, LCD_COMMAND_MADCTL, self->bgr ? 0xC8 : 0xC0); + uint8_t madctl = 0; + if (args[ARG_hmirror].u_bool) { + madctl |= 0x40; + } + if (args[ARG_vflip].u_bool) { + madctl |= 0x80; + } + if (self->bgr) { + madctl |= 0x08; + } + spi_display_command(self, LCD_COMMAND_MADCTL, madctl); // Interface pixel format spi_display_command(self, LCD_COMMAND_COLMOD, 0x05); } From a5ac15a764425c2cc31dfef7f087a4f0f5458df4 Mon Sep 17 00:00:00 2001 From: "Kwabena W. Agyeman" Date: Sun, 6 Jul 2025 18:25:08 -0700 Subject: [PATCH 2/3] scripts/examples: Cleanup LCD shield example. --- .../60-Shields/60-LCD-Shield/lcd.py | 26 -------------- .../60-Shields/60-LCD-Shield/lcd_shield.py | 35 +++++++++++++++++++ 2 files changed, 35 insertions(+), 26 deletions(-) delete mode 100644 scripts/examples/50-OpenMV-Boards/60-Shields/60-LCD-Shield/lcd.py create mode 100644 scripts/examples/50-OpenMV-Boards/60-Shields/60-LCD-Shield/lcd_shield.py diff --git a/scripts/examples/50-OpenMV-Boards/60-Shields/60-LCD-Shield/lcd.py b/scripts/examples/50-OpenMV-Boards/60-Shields/60-LCD-Shield/lcd.py deleted file mode 100644 index 8af26f066..000000000 --- a/scripts/examples/50-OpenMV-Boards/60-Shields/60-LCD-Shield/lcd.py +++ /dev/null @@ -1,26 +0,0 @@ -# This work is licensed under the MIT license. -# Copyright (c) 2013-2023 OpenMV LLC. All rights reserved. -# https://github.com/openmv/openmv/blob/master/LICENSE -# -# LCD Example -# -# Note: To run this example you will need a LCD Shield for your OpenMV Cam. -# -# The LCD Shield allows you to view your OpenMV Cam's frame buffer on the go. - -import sensor -import display - -sensor.reset() # Initialize the camera sensor. -sensor.set_pixformat(sensor.RGB565) # or sensor.GRAYSCALE -sensor.set_framesize(sensor.QQVGA2) # Special 128x160 framesize for LCD Shield. -# Initialize the lcd screen. -# Note: A DAC or a PWM backlight controller can be used to control the -# backlight intensity if supported: -# lcd = display.SPIDisplay(backlight=display.DACBacklight(channel=2)) -# lcd.backlight(25) # 25% intensity -# Otherwise the default GPIO (on/off) controller is used. -lcd = display.SPIDisplay() - -while True: - lcd.write(sensor.snapshot()) # Take a picture and display the image. diff --git a/scripts/examples/50-OpenMV-Boards/60-Shields/60-LCD-Shield/lcd_shield.py b/scripts/examples/50-OpenMV-Boards/60-Shields/60-LCD-Shield/lcd_shield.py new file mode 100644 index 000000000..56a5830a9 --- /dev/null +++ b/scripts/examples/50-OpenMV-Boards/60-Shields/60-LCD-Shield/lcd_shield.py @@ -0,0 +1,35 @@ +# This work is licensed under the MIT license. +# Copyright (c) 2013-2025 OpenMV LLC. All rights reserved. +# https://github.com/openmv/openmv/blob/master/LICENSE +# +# LCD Shield Example +# +# Note: To run this example you will need a LCD Shield for your OpenMV Cam. +# +# The LCD shield allows you to view your OpenMV Cam's frame buffer on the go. + +import sensor +import time +import display +import image + +sensor.reset() +sensor.set_pixformat(sensor.RGB565) +sensor.set_framesize(sensor.LCD) + +# Initialize the lcd screen. +# Note: A DAC or a PWM backlight controller can be used to control the +# backlight intensity if supported: +# lcd = display.SPIDisplay(backlight=display.DACBacklight(channel=2)) +# lcd.backlight(25) # 25% intensity +# Otherwise the default GPIO (on/off) controller is used. +# OpenMV Cam M4/M7/H7/H7 Plus -> DAC and GPIO Support +# OpenMV Cam RT1062 -> GPIO Support +# OpenMV Cam N6 -> PWM and GPIO Support +lcd = display.SPIDisplay(vflip=True, hmirror=True) +clock = time.clock() + +while True: + clock.tick() + lcd.write(sensor.snapshot(), hint=image.CENTER | image.SCALE_ASPECT_KEEP) + print(clock.fps()) From 7602c8638b519c310cfe1f6508581631d6968699 Mon Sep 17 00:00:00 2001 From: "Kwabena W. Agyeman" Date: Sun, 6 Jul 2025 18:26:24 -0700 Subject: [PATCH 3/3] scripts/examples: Add 320x240 basic touch LCD example. --- .../69-Touch-LCD-Shield/touch_lcd_shield.py | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 scripts/examples/50-OpenMV-Boards/60-Shields/69-Touch-LCD-Shield/touch_lcd_shield.py diff --git a/scripts/examples/50-OpenMV-Boards/60-Shields/69-Touch-LCD-Shield/touch_lcd_shield.py b/scripts/examples/50-OpenMV-Boards/60-Shields/69-Touch-LCD-Shield/touch_lcd_shield.py new file mode 100644 index 000000000..3c3743322 --- /dev/null +++ b/scripts/examples/50-OpenMV-Boards/60-Shields/69-Touch-LCD-Shield/touch_lcd_shield.py @@ -0,0 +1,39 @@ +# This work is licensed under the MIT license. +# Copyright (c) 2013-2025 OpenMV LLC. All rights reserved. +# https://github.com/openmv/openmv/blob/master/LICENSE +# +# Touch LCD Shield Example +# +# Note: To run this example you will need a Touch LCD Shield for your OpenMV Cam. +# +# The touch LCD shield allows you to view your OpenMV Cam's frame buffer on the go. + +import sensor +import time +import display +import image + +sensor.reset() +sensor.set_pixformat(sensor.RGB565) +sensor.set_framesize(sensor.QVGA) + +# Initialize the lcd screen. +# Note: A DAC or a PWM backlight controller can be used to control the +# backlight intensity if supported: +# lcd = display.SPIDisplay(backlight=display.DACBacklight(channel=2)) +# lcd.backlight(25) # 25% intensity +# Otherwise the default GPIO (on/off) controller is used. +# OpenMV Cam M4/M7/H7/H7 Plus -> DAC and GPIO Support +# OpenMV Cam RT1062 -> GPIO Support +# OpenMV Cam N6 -> PWM and GPIO Support +lcd = display.SPIDisplay(width=320, + height=240, + bgr=True, + vflip=False, + hmirror=False) +clock = time.clock() + +while True: + clock.tick() + lcd.write(sensor.snapshot(), hint=image.CENTER | image.SCALE_ASPECT_KEEP) + print(clock.fps())