From b55666be6d3a52aacbad9107699eb7190ccb605a Mon Sep 17 00:00:00 2001 From: Liz Date: Mon, 10 Feb 2025 11:00:31 -0500 Subject: [PATCH 1/7] Create gc9a01a.py --- adafruit_rgb_display/gc9a01a.py | 145 ++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 adafruit_rgb_display/gc9a01a.py diff --git a/adafruit_rgb_display/gc9a01a.py b/adafruit_rgb_display/gc9a01a.py new file mode 100644 index 0000000..33800f9 --- /dev/null +++ b/adafruit_rgb_display/gc9a01a.py @@ -0,0 +1,145 @@ +# SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries +# +# SPDX-License-Identifier: MIT +""" +`adafruit_rgb_display.gc9a01a` +==================================================== +A simple driver for the GC9A01A-based displays. + +* Author(s): Liz Clark + +Implementation Notes +-------------------- +Adapted from the CircuitPython GC9A01A driver for use with the RGB Display library. +""" +import struct +import busio +import digitalio +from micropython import const +from adafruit_rgb_display.rgb import DisplaySPI + +try: + from typing import Optional +except ImportError: + pass + +__version__ = "0.0.0+auto.0" +__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_RGB_Display.git" + +# Command constants +_NOP = const(0x00) +_SWRESET = const(0x01) +_SLPIN = const(0x10) +_SLPOUT = const(0x11) +_PTLON = const(0x12) +_NORON = const(0x13) +_INVOFF = const(0x20) +_INVON = const(0x21) +_DISPOFF = const(0x28) +_DISPON = const(0x29) +_CASET = const(0x2A) +_RASET = const(0x2B) +_RAMWR = const(0x2C) +_RAMRD = const(0x2E) +_MADCTL = const(0x36) +_COLMOD = const(0x3A) +_TEON = const(0x35) + +# Extended command constants +_PWCTR1 = const(0xC3) +_PWCTR2 = const(0xC4) +_PWCTR3 = const(0xC9) +_GMCTRP1 = const(0xF0) +_GMCTRN1 = const(0xF1) +_GMCTRP2 = const(0xF2) +_GMCTRN2 = const(0xF3) + +class GC9A01A(DisplaySPI): + """ + A simple driver for the GC9A01A-based displays. + + >>> import busio + >>> import digitalio + >>> import board + >>> from adafruit_rgb_display import color565 + >>> import adafruit_rgb_display.gc9a01a as gc9a01a + >>> spi = busio.SPI(clock=board.SCK, MOSI=board.MOSI, MISO=board.MISO) + >>> display = gc9a01a.GC9A01A(spi, cs=digitalio.DigitalInOut(board.GPIO0), + ... dc=digitalio.DigitalInOut(board.GPIO15), rst=digitalio.DigitalInOut(board.GPIO16)) + >>> display.fill(0x7521) + >>> display.pixel(64, 64, 0) + """ + # pylint: disable=too-few-public-methods + + COLUMN_SET = _CASET + PAGE_SET = _RASET + RAM_WRITE = _RAMWR + RAM_READ = _RAMRD + + _INIT = ( + (_SWRESET, None), + (0xFE, None), # Inter Register Enable1 + (0xEF, None), # Inter Register Enable2 + (0xB6, b"\x00\x00"), # Display Function Control + (_MADCTL, b"\x48"), # Memory Access Control + (_COLMOD, b"\x05"), # Interface Pixel Format (16 bits/pixel) + (_PWCTR1, b"\x13"), # Power Control 2 + (_PWCTR2, b"\x13"), # Power Control 3 + (_PWCTR3, b"\x22"), # Power Control 4 + (_GMCTRP1, b"\x45\x09\x08\x08\x26\x2a"), # Set Gamma 1 + (_GMCTRN1, b"\x43\x70\x72\x36\x37\x6f"), # Set Gamma 2 + (_GMCTRP2, b"\x45\x09\x08\x08\x26\x2a"), # Set Gamma 3 + (_GMCTRN2, b"\x43\x70\x72\x36\x37\x6f"), # Set Gamma 4 + (0x66, b"\x3c\x00\xcd\x67\x45\x45\x10\x00\x00\x00"), + (0x67, b"\x00\x3c\x00\x00\x00\x01\x54\x10\x32\x98"), + (0x74, b"\x10\x85\x80\x00\x00\x4e\x00"), + (0x98, b"\x3e\x07"), + (_TEON, None), # Tearing Effect Line ON + (_INVON, None), # Display Inversion ON + (_SLPOUT, None), # Exit Sleep Mode + (_NORON, None), # Normal Display Mode ON + (_DISPON, None), # Display ON + ) + + def __init__( + self, + spi: busio.SPI, + dc: digitalio.DigitalInOut, + cs: digitalio.DigitalInOut, + rst: Optional[digitalio.DigitalInOut] = None, + width: int = 240, + height: int = 240, + baudrate: int = 16000000, + polarity: int = 0, + phase: int = 0, + *, + x_offset: int = 0, + y_offset: int = 0, + rotation: int = 0 + ) -> None: + super().__init__( + spi, + dc, + cs, + rst, + width, + height, + baudrate=baudrate, + polarity=polarity, + phase=phase, + x_offset=x_offset, + y_offset=y_offset, + rotation=rotation, + ) + + def init(self) -> None: + super().init() + cols = struct.pack(">HH", 0, self.width - 1) + rows = struct.pack(">HH", 0, self.height - 1) + + for command, data in ( + (_CASET, cols), + (_RASET, rows), + (_MADCTL, b"\xc0"), # Set rotation to 0 and use RGB + ): + self.write(command, data) From 7d5528f6c6aa45c9493d0c8bf65db4e33328a3e6 Mon Sep 17 00:00:00 2001 From: Liz Date: Mon, 10 Feb 2025 11:23:56 -0500 Subject: [PATCH 2/7] Update gc9a01a.py --- adafruit_rgb_display/gc9a01a.py | 41 ++++++++++++++++----------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/adafruit_rgb_display/gc9a01a.py b/adafruit_rgb_display/gc9a01a.py index 33800f9..d556911 100644 --- a/adafruit_rgb_display/gc9a01a.py +++ b/adafruit_rgb_display/gc9a01a.py @@ -77,28 +77,26 @@ class GC9A01A(DisplaySPI): RAM_READ = _RAMRD _INIT = ( - (_SWRESET, None), - (0xFE, None), # Inter Register Enable1 - (0xEF, None), # Inter Register Enable2 - (0xB6, b"\x00\x00"), # Display Function Control - (_MADCTL, b"\x48"), # Memory Access Control - (_COLMOD, b"\x05"), # Interface Pixel Format (16 bits/pixel) - (_PWCTR1, b"\x13"), # Power Control 2 - (_PWCTR2, b"\x13"), # Power Control 3 + (0xFE, b"\x00"), # Inter Register Enable1 + (0xEF, b"\x00"), # Inter Register Enable2 + (0xB6, b"\x00\x00"), # Display Function Control [S1→S360 source, G1→G32 gate] + (_MADCTL, b"\x48"), # Memory Access Control [Invert Row order, invert vertical scan order] + (_COLMOD, b"\x05"), # COLMOD: Pixel Format Set [16 bits/pixel] + (_PWCTR1, b"\x13"), # Power Control 2 [VREG1A = 5.06, VREG1B = 0.68] + (_PWCTR2, b"\x13"), # Power Control 3 [VREG2A = -3.7, VREG2B = 0.68] (_PWCTR3, b"\x22"), # Power Control 4 - (_GMCTRP1, b"\x45\x09\x08\x08\x26\x2a"), # Set Gamma 1 - (_GMCTRN1, b"\x43\x70\x72\x36\x37\x6f"), # Set Gamma 2 - (_GMCTRP2, b"\x45\x09\x08\x08\x26\x2a"), # Set Gamma 3 - (_GMCTRN2, b"\x43\x70\x72\x36\x37\x6f"), # Set Gamma 4 + (_GMCTRP1, b"\x45\x09\x08\x08\x26\x2a"), # SET_GAMMA1 + (_GMCTRN1, b"\x43\x70\x72\x36\x37\x6f"), # SET_GAMMA2 + (_GMCTRP2, b"\x45\x09\x08\x08\x26\x2a"), # SET_GAMMA3 + (_GMCTRN2, b"\x43\x70\x72\x36\x37\x6f"), # SET_GAMMA4 (0x66, b"\x3c\x00\xcd\x67\x45\x45\x10\x00\x00\x00"), (0x67, b"\x00\x3c\x00\x00\x00\x01\x54\x10\x32\x98"), (0x74, b"\x10\x85\x80\x00\x00\x4e\x00"), (0x98, b"\x3e\x07"), - (_TEON, None), # Tearing Effect Line ON - (_INVON, None), # Display Inversion ON - (_SLPOUT, None), # Exit Sleep Mode - (_NORON, None), # Normal Display Mode ON - (_DISPON, None), # Display ON + (_TEON, b"\x00"), # Tearing Effect Line ON [both V-blanking and H-blanking] + (_INVON, b"\x00"), # Display Inversion ON + (_SLPOUT, None), # Sleep Out Mode (with 120ms delay) + (_DISPON, None), # Display ON (with 20ms delay) ) def __init__( @@ -134,12 +132,13 @@ def __init__( def init(self) -> None: super().init() - cols = struct.pack(">HH", 0, self.width - 1) - rows = struct.pack(">HH", 0, self.height - 1) + # Account for offsets in the column and row addressing + cols = struct.pack(">HH", self._X_START, self.width + self._X_START - 1) + rows = struct.pack(">HH", self._Y_START, self.height + self._Y_START - 1) for command, data in ( - (_CASET, cols), - (_RASET, rows), (_MADCTL, b"\xc0"), # Set rotation to 0 and use RGB + (_CASET, b"\x00\x00\x00\xef"), # Column Address Set [Start col = 0, end col = 239] + (_RASET, b"\x00\x00\x00\xef"), # Row Address Set [Start row = 0, end row = 239] ): self.write(command, data) From 67547fadb2e197e32aeaf8dd5bcbcaa21c177baf Mon Sep 17 00:00:00 2001 From: Liz Date: Mon, 10 Feb 2025 11:32:10 -0500 Subject: [PATCH 3/7] Update gc9a01a.py --- adafruit_rgb_display/gc9a01a.py | 35 ++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/adafruit_rgb_display/gc9a01a.py b/adafruit_rgb_display/gc9a01a.py index d556911..c882a95 100644 --- a/adafruit_rgb_display/gc9a01a.py +++ b/adafruit_rgb_display/gc9a01a.py @@ -26,11 +26,14 @@ __version__ = "0.0.0+auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_RGB_Display.git" -# Command constants -_NOP = const(0x00) -_SWRESET = const(0x01) -_SLPIN = const(0x10) -_SLPOUT = const(0x11) +# Constants for MADCTL +_MADCTL_MY = const(0x80) # Bottom to top +_MADCTL_MX = const(0x40) # Right to left +_MADCTL_MV = const(0x20) # Reverse Mode +_MADCTL_ML = const(0x10) # LCD refresh Bottom to top +_MADCTL_RGB = const(0x00) # Red-Green-Blue pixel order +_MADCTL_BGR = const(0x08) # Blue-Green-Red pixel order +_MADCTL_MH = const(0x04) # LCD refresh right to left _PTLON = const(0x12) _NORON = const(0x13) _INVOFF = const(0x20) @@ -136,9 +139,19 @@ def init(self) -> None: cols = struct.pack(">HH", self._X_START, self.width + self._X_START - 1) rows = struct.pack(">HH", self._Y_START, self.height + self._Y_START - 1) - for command, data in ( - (_MADCTL, b"\xc0"), # Set rotation to 0 and use RGB - (_CASET, b"\x00\x00\x00\xef"), # Column Address Set [Start col = 0, end col = 239] - (_RASET, b"\x00\x00\x00\xef"), # Row Address Set [Start row = 0, end row = 239] - ): - self.write(command, data) + def init(self) -> None: + """Initialize the display""" + super().init() + + # Initialize display + self.write(_SWRESET) + time.sleep(0.150) # 150ms delay after reset + + # Set addressing mode and color format + self.write(_MADCTL, bytes([_MADCTL_MX | _MADCTL_BGR])) + + # Set addressing windows + self.write(_CASET, b"\x00\x00\x00\xef") # Column Address Set [0-239] + self.write(_RASET, b"\x00\x00\x00\xef") # Row Address Set [0-239] + + time.sleep(0.150) # 150ms delay before turning on display \ No newline at end of file From 9f02995bbca0523adc6453aa2b547159aa262dd7 Mon Sep 17 00:00:00 2001 From: Liz Date: Mon, 10 Feb 2025 12:31:41 -0500 Subject: [PATCH 4/7] pre-commit, tested --- adafruit_rgb_display/gc9a01a.py | 107 ++++++++++++-------------------- 1 file changed, 39 insertions(+), 68 deletions(-) diff --git a/adafruit_rgb_display/gc9a01a.py b/adafruit_rgb_display/gc9a01a.py index c882a95..4b95604 100644 --- a/adafruit_rgb_display/gc9a01a.py +++ b/adafruit_rgb_display/gc9a01a.py @@ -8,11 +8,10 @@ * Author(s): Liz Clark -Implementation Notes --------------------- -Adapted from the CircuitPython GC9A01A driver for use with the RGB Display library. """ + import struct +import time import busio import digitalio from micropython import const @@ -26,15 +25,9 @@ __version__ = "0.0.0+auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_RGB_Display.git" -# Constants for MADCTL -_MADCTL_MY = const(0x80) # Bottom to top -_MADCTL_MX = const(0x40) # Right to left -_MADCTL_MV = const(0x20) # Reverse Mode -_MADCTL_ML = const(0x10) # LCD refresh Bottom to top -_MADCTL_RGB = const(0x00) # Red-Green-Blue pixel order -_MADCTL_BGR = const(0x08) # Blue-Green-Red pixel order -_MADCTL_MH = const(0x04) # LCD refresh right to left -_PTLON = const(0x12) +# Command constants +_SWRESET = const(0xFE) +_SLPOUT = const(0x11) _NORON = const(0x13) _INVOFF = const(0x20) _INVON = const(0x21) @@ -46,16 +39,7 @@ _RAMRD = const(0x2E) _MADCTL = const(0x36) _COLMOD = const(0x3A) -_TEON = const(0x35) -# Extended command constants -_PWCTR1 = const(0xC3) -_PWCTR2 = const(0xC4) -_PWCTR3 = const(0xC9) -_GMCTRP1 = const(0xF0) -_GMCTRN1 = const(0xF1) -_GMCTRP2 = const(0xF2) -_GMCTRN2 = const(0xF3) class GC9A01A(DisplaySPI): """ @@ -64,42 +48,40 @@ class GC9A01A(DisplaySPI): >>> import busio >>> import digitalio >>> import board - >>> from adafruit_rgb_display import color565 - >>> import adafruit_rgb_display.gc9a01a as gc9a01a + >>> from adafruit_rgb_display import gc9a01a >>> spi = busio.SPI(clock=board.SCK, MOSI=board.MOSI, MISO=board.MISO) - >>> display = gc9a01a.GC9A01A(spi, cs=digitalio.DigitalInOut(board.GPIO0), - ... dc=digitalio.DigitalInOut(board.GPIO15), rst=digitalio.DigitalInOut(board.GPIO16)) + >>> display = gc9a01a.GC9A01A(spi, cs=digitalio.DigitalInOut(board.CE0), + ... dc=digitalio.DigitalInOut(board.D25), rst=digitalio.DigitalInOut(board.D27)) >>> display.fill(0x7521) >>> display.pixel(64, 64, 0) """ - # pylint: disable=too-few-public-methods - - COLUMN_SET = _CASET - PAGE_SET = _RASET - RAM_WRITE = _RAMWR - RAM_READ = _RAMRD + _COLUMN_SET = _CASET + _PAGE_SET = _RASET + _RAM_WRITE = _RAMWR + _RAM_READ = _RAMRD _INIT = ( - (0xFE, b"\x00"), # Inter Register Enable1 - (0xEF, b"\x00"), # Inter Register Enable2 - (0xB6, b"\x00\x00"), # Display Function Control [S1→S360 source, G1→G32 gate] - (_MADCTL, b"\x48"), # Memory Access Control [Invert Row order, invert vertical scan order] - (_COLMOD, b"\x05"), # COLMOD: Pixel Format Set [16 bits/pixel] - (_PWCTR1, b"\x13"), # Power Control 2 [VREG1A = 5.06, VREG1B = 0.68] - (_PWCTR2, b"\x13"), # Power Control 3 [VREG2A = -3.7, VREG2B = 0.68] - (_PWCTR3, b"\x22"), # Power Control 4 - (_GMCTRP1, b"\x45\x09\x08\x08\x26\x2a"), # SET_GAMMA1 - (_GMCTRN1, b"\x43\x70\x72\x36\x37\x6f"), # SET_GAMMA2 - (_GMCTRP2, b"\x45\x09\x08\x08\x26\x2a"), # SET_GAMMA3 - (_GMCTRN2, b"\x43\x70\x72\x36\x37\x6f"), # SET_GAMMA4 + (_SWRESET, None), + (0xEF, None), # Inter Register Enable2 + (0xB6, b"\x00\x00"), # Display Function Control + (_MADCTL, b"\x48"), # Memory Access Control - Set to BGR color filter panel + (_COLMOD, b"\x05"), # Interface Pixel Format - 16 bits per pixel + (0xC3, b"\x13"), # Power Control 2 + (0xC4, b"\x13"), # Power Control 3 + (0xC9, b"\x22"), # Power Control 4 + (0xF0, b"\x45\x09\x08\x08\x26\x2a"), # SET_GAMMA1 + (0xF1, b"\x43\x70\x72\x36\x37\x6f"), # SET_GAMMA2 + (0xF2, b"\x45\x09\x08\x08\x26\x2a"), # SET_GAMMA3 + (0xF3, b"\x43\x70\x72\x36\x37\x6f"), # SET_GAMMA4 (0x66, b"\x3c\x00\xcd\x67\x45\x45\x10\x00\x00\x00"), (0x67, b"\x00\x3c\x00\x00\x00\x01\x54\x10\x32\x98"), (0x74, b"\x10\x85\x80\x00\x00\x4e\x00"), (0x98, b"\x3e\x07"), - (_TEON, b"\x00"), # Tearing Effect Line ON [both V-blanking and H-blanking] - (_INVON, b"\x00"), # Display Inversion ON - (_SLPOUT, None), # Sleep Out Mode (with 120ms delay) - (_DISPON, None), # Display ON (with 20ms delay) + (0x35, None), # Tearing Effect Line ON + (_INVON, None), # Display Inversion ON + (_SLPOUT, None), # Sleep Out Mode + (_NORON, None), # Normal Display Mode ON + (_DISPON, None), # Display ON ) def __init__( @@ -110,7 +92,7 @@ def __init__( rst: Optional[digitalio.DigitalInOut] = None, width: int = 240, height: int = 240, - baudrate: int = 16000000, + baudrate: int = 24000000, polarity: int = 0, phase: int = 0, *, @@ -134,24 +116,13 @@ def __init__( ) def init(self) -> None: + """Initialize the display.""" + if self.rst: + self.rst.value = 0 + time.sleep(0.05) + self.rst.value = 1 + time.sleep(0.05) + super().init() - # Account for offsets in the column and row addressing - cols = struct.pack(">HH", self._X_START, self.width + self._X_START - 1) - rows = struct.pack(">HH", self._Y_START, self.height + self._Y_START - 1) - - def init(self) -> None: - """Initialize the display""" - super().init() - - # Initialize display - self.write(_SWRESET) - time.sleep(0.150) # 150ms delay after reset - - # Set addressing mode and color format - self.write(_MADCTL, bytes([_MADCTL_MX | _MADCTL_BGR])) - - # Set addressing windows - self.write(_CASET, b"\x00\x00\x00\xef") # Column Address Set [0-239] - self.write(_RASET, b"\x00\x00\x00\xef") # Row Address Set [0-239] - - time.sleep(0.150) # 150ms delay before turning on display \ No newline at end of file + + self._block(0, 0, self.width - 1, self.height - 1) From 8ce10d5951aa86e722b301109c5a72c8c91075d3 Mon Sep 17 00:00:00 2001 From: Liz Date: Mon, 10 Feb 2025 12:34:06 -0500 Subject: [PATCH 5/7] lint --- adafruit_rgb_display/gc9a01a.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/adafruit_rgb_display/gc9a01a.py b/adafruit_rgb_display/gc9a01a.py index 4b95604..d7b28cb 100644 --- a/adafruit_rgb_display/gc9a01a.py +++ b/adafruit_rgb_display/gc9a01a.py @@ -10,7 +10,6 @@ """ -import struct import time import busio import digitalio @@ -83,7 +82,7 @@ class GC9A01A(DisplaySPI): (_NORON, None), # Normal Display Mode ON (_DISPON, None), # Display ON ) - + # pylint: disable-msg=useless-super-delegation, too-many-arguments def __init__( self, spi: busio.SPI, From 664dcd28144f05df5833a23003a73d2fc089b2a1 Mon Sep 17 00:00:00 2001 From: Liz Date: Mon, 10 Feb 2025 12:36:42 -0500 Subject: [PATCH 6/7] oy vey, black --- adafruit_rgb_display/gc9a01a.py | 1 + 1 file changed, 1 insertion(+) diff --git a/adafruit_rgb_display/gc9a01a.py b/adafruit_rgb_display/gc9a01a.py index d7b28cb..f360cc0 100644 --- a/adafruit_rgb_display/gc9a01a.py +++ b/adafruit_rgb_display/gc9a01a.py @@ -82,6 +82,7 @@ class GC9A01A(DisplaySPI): (_NORON, None), # Normal Display Mode ON (_DISPON, None), # Display ON ) + # pylint: disable-msg=useless-super-delegation, too-many-arguments def __init__( self, From f56a9eeb4d7fdc42787d1ecb3882e86155ac0d02 Mon Sep 17 00:00:00 2001 From: Liz Date: Mon, 10 Feb 2025 16:06:29 -0500 Subject: [PATCH 7/7] remove _block --- adafruit_rgb_display/gc9a01a.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/adafruit_rgb_display/gc9a01a.py b/adafruit_rgb_display/gc9a01a.py index f360cc0..613bc7a 100644 --- a/adafruit_rgb_display/gc9a01a.py +++ b/adafruit_rgb_display/gc9a01a.py @@ -124,5 +124,3 @@ def init(self) -> None: time.sleep(0.05) super().init() - - self._block(0, 0, self.width - 1, self.height - 1)