From 73a73a08068d87e32e6d664d3f80158a1a7db521 Mon Sep 17 00:00:00 2001 From: "Kwabena W. Agyeman" Date: Sun, 15 Jun 2025 22:40:57 -0700 Subject: [PATCH] scripts/libraries: Add support for the SSD1351 OLED display. --- boards/OPENMV_AE3/manifest.py | 1 + .../51-OLED-Shield/oled_display.py | 27 +++++++++ scripts/libraries/display.py | 5 ++ scripts/libraries/ssd1351.py | 55 +++++++++++++++++++ 4 files changed, 88 insertions(+) create mode 100644 scripts/examples/50-OpenMV-Boards/52-Alif-Boards/51-OLED-Shield/oled_display.py create mode 100644 scripts/libraries/ssd1351.py diff --git a/boards/OPENMV_AE3/manifest.py b/boards/OPENMV_AE3/manifest.py index 8413762e2..9069b62c3 100644 --- a/boards/OPENMV_AE3/manifest.py +++ b/boards/OPENMV_AE3/manifest.py @@ -6,6 +6,7 @@ require("lsm6dsox") #freeze ("$(OMV_LIB_DIR)/", "pid.py") #freeze ("$(OMV_LIB_DIR)/", "bno055.py") #freeze ("$(OMV_LIB_DIR)/", "ssd1306.py") +freeze ("$(OMV_LIB_DIR)/", "ssd1351.py") #freeze ("$(OMV_LIB_DIR)/", "tb6612.py") freeze ("$(OMV_LIB_DIR)/", "vl53l1x.py") freeze ("$(OMV_LIB_DIR)/", "machine.py") diff --git a/scripts/examples/50-OpenMV-Boards/52-Alif-Boards/51-OLED-Shield/oled_display.py b/scripts/examples/50-OpenMV-Boards/52-Alif-Boards/51-OLED-Shield/oled_display.py new file mode 100644 index 000000000..94bcb83ca --- /dev/null +++ b/scripts/examples/50-OpenMV-Boards/52-Alif-Boards/51-OLED-Shield/oled_display.py @@ -0,0 +1,27 @@ +# 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 +# +# OLED Display Example +# +# Note: To run this example you will need a OLED Breakout Board for your OpenMV AE3 +# +# The OLED Breakout Board allows you to view your OpenMV AE3'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.VGA) +sensor.set_windowing((400, 400)) + +lcd = display.SPIDisplay(width=128, height=128, controller=display.SSD1351()) +clock = time.clock() + +while True: + clock.tick() + lcd.write(sensor.snapshot(), hint=image.CENTER | image.SCALE_ASPECT_KEEP) + print(clock.fps()) diff --git a/scripts/libraries/display.py b/scripts/libraries/display.py index 7c3195d88..de0b6e5ff 100644 --- a/scripts/libraries/display.py +++ b/scripts/libraries/display.py @@ -16,6 +16,11 @@ try: except (ImportError, AttributeError): pass +try: + from ssd1351 import * # noqa +except (ImportError, AttributeError): + pass + class DACBacklight: def __init__(self, channel, bits=8): diff --git a/scripts/libraries/ssd1351.py b/scripts/libraries/ssd1351.py new file mode 100644 index 000000000..b1523c17d --- /dev/null +++ b/scripts/libraries/ssd1351.py @@ -0,0 +1,55 @@ +# This file is part of the OpenMV project. +# +# Copyright (c) 2025 Ibrahim Abdelkader +# Copyright (c) 2025 Kwabena W. Agyeman +# Copyright (c) 2017 https://github.com/rdagger/micropython-ssd1351 +# +# This work is licensed under the MIT license, see the file LICENSE for details. +# +# SSD1351 LCD controller driver. + +from micropython import const + +WRITE_RAM = const(0x5C) +SET_REMAP = const(0xA0) +DISPLAY_OFFSET = const(0xA2) +DISPLAY_OFF = const(0xAE) +DISPLAY_ON = const(0xAF) +PRECHARGE = const(0xB1) +DISPLAY_ENHANCEMENT = const(0xB2) +CLOCK_DIV = const(0xB3) +PRECHARGE2 = const(0xB6) +PRECHARGE_LEVEL = const(0xBB) +CONTRAST_ABC = const(0xC1) +CONTRAST_MASTER = const(0xC7) +MUX_RATIO = const(0xCA) +COMMAND_LOCK = const(0xFD) + + +class SSD1351: + + def __init__(self): + pass + + def init(self, dc): + dc.bus_write(COMMAND_LOCK, 0x12) # Unlock IC MCU interface + dc.bus_write(COMMAND_LOCK, 0xB1) # A2,B1,B3,BB,BE,C1 + dc.bus_write(DISPLAY_ENHANCEMENT, bytes([0xA4, 0x00, 0x00])) + dc.bus_write(CLOCK_DIV, 0xF0) # Clock divider F1 or F0 + dc.bus_write(MUX_RATIO, 0x7F) # Mux ratio + dc.bus_write(SET_REMAP, 0x74) # Segment remapping + dc.bus_write(DISPLAY_OFFSET, 0x00) # Set display offset + dc.bus_write(PRECHARGE, 0x32), # Precharge + dc.bus_write(PRECHARGE_LEVEL, 0x1F) # Precharge level + dc.bus_write(CONTRAST_MASTER, 0x0A) # Contrast master + dc.bus_write(CONTRAST_ABC, bytes([0xFF, 0xFF, 0xFF])) # Contrast RGB + dc.bus_write(PRECHARGE2, 0x01) # Precharge2 + + def ram_write(self, dc): + dc.bus_write(WRITE_RAM) + + def display_on(self, dc): + dc.bus_write(DISPLAY_ON) + + def display_off(self, dc): + dc.bus_write(DISPLAY_OFF)