From 2efdd7b4c6fbef887f58b209c846f8f82d17436b Mon Sep 17 00:00:00 2001 From: Yidi Lin Date: Sun, 8 May 2022 12:01:36 +0800 Subject: [PATCH] Add support for GC9A01 and WaveShare 1.28 inch GC9A01 240x240 ISP display module --- CMakeLists.txt | 6 ++ README.md | 3 + display.h | 2 + gc9a01.cpp | 180 +++++++++++++++++++++++++++++++++++++++++++++ gc9a01.h | 27 +++++++ waveshare_gc9a01.h | 19 +++++ 6 files changed, 237 insertions(+) create mode 100644 gc9a01.cpp create mode 100644 gc9a01.h create mode 100644 waveshare_gc9a01.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 243f489..abd1adf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -265,6 +265,12 @@ elseif(MPI3501) if (USE_DMA_TRANSFERS) message(FATAL_ERROR "DMA is unfortunately not possible with MPI3501. Please disable with -DUSE_DMA_TRANSFERS=OFF.") endif() +elseif(WAVESHARE_GC9A01) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGC9A01 -DWAVESHARE_GC9A01") + message(STATUS "Targeting WaveShare 240x240 1.28inch IPS LCD Hat with GC9A01 controller") +elseif(GC9A01) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGC9A01") + message(STATUS "Targeting GC9A01") else() message(FATAL_ERROR "Please specify which display controller to use on command line to CMake!") endif() diff --git a/README.md b/README.md index 6f0f497..83ddec1 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,7 @@ The following LCD displays have been tested: - [WaveShare 128x128, 1.44inch LCD display HAT for Raspberry Pi](https://www.waveshare.com/1.44inch-lcd-hat.htm) with ST7735S controller - [KeDei 3.5 inch SPI TFTLCD 480*320 16bit/18bit version 6.3 2018/4/9](https://github.com/juj/fbcp-ili9341/issues/40) with MPI3501 controller - Unbranded 2.8" 320x240 display with ILI9340 controller + - [WaveShare 240×240, General 1.28inch Round LCD Display Module, 65K RGB](https://www.waveshare.com/product/1.28inch-lcd-module.htm) with GC9A01 controller ### Installation @@ -120,6 +121,7 @@ When using one of the displays that stack on top of the Pi that are already reco - `-DWAVESHARE_ST7789VW_HAT=ON`: If specified, targets a [240x240, 1.3inch IPS LCD display HAT for Raspberry Pi](https://www.waveshare.com/1.3inch-lcd-hat.htm) with ST7789VW display controller. - `-DWAVESHARE_ST7735S_HAT=ON`: If specified, targets a [128x128, 1.44inch LCD display HAT for Raspberry Pi](https://www.waveshare.com/1.3inch-lcd-hat.htm) with ST7735S display controller. - `-DKEDEI_V63_MPI3501=ON`: If specified, targets a [KeDei 3.5 inch SPI TFTLCD 480*320 16bit/18bit version 6.3 2018/4/9](https://github.com/juj/fbcp-ili9341/issues/40) display with MPI3501 display controller. +- `-DWAVESHARE_GC9A01=ON`: If specified, targets a [WaveShare 240×240, General 1.28inch Round LCD Display Module, 65K RGB](https://www.waveshare.com/product/1.28inch-lcd-module.htm) with GC9A01 display controller ###### If you wired the display to the Pi yourself @@ -137,6 +139,7 @@ If you connected wires directly on the Pi instead of using a Hat from the above - `-DILI9486L=ON`: If you have a ILI9486L display, pass this directive. Note that ILI9486 and ILI9486L are quite different, mutually incompatible controller chips, so be careful here identifying which one you have. (or just try both, should not break if you misidentified) - `-DILI9488=ON`: If you have a ILI9488 display, pass this directive. - `-DMPI3501=ON`: If specified, targets a display with MPI3501 display controller. +- `-DGC9A01=ON`: If you have a GC9A01 display, pass this directive. And additionally, pass the following to customize the GPIO pin assignments you used: diff --git a/display.h b/display.h index ff0bd72..3a8c37c 100644 --- a/display.h +++ b/display.h @@ -23,6 +23,8 @@ #include "mz61581.h" #elif defined(MPI3501) #include "mpi3501.h" +#elif defined(GC9A01) +#include "gc9a01.h" #else #error Please reconfigure CMake with your display controller directive set! #endif diff --git a/gc9a01.cpp b/gc9a01.cpp new file mode 100644 index 0000000..1ec316c --- /dev/null +++ b/gc9a01.cpp @@ -0,0 +1,180 @@ +#include "config.h" + +#if defined(GC9A01) + +#include "spi.h" + +#include +#include + +void InitGC9A01() +{ + // If a Reset pin is defined, toggle it briefly high->low->high to enable the device. Some devices do not have a reset pin, in which case compile with GPIO_TFT_RESET_PIN left undefined. +#if defined(GPIO_TFT_RESET_PIN) && GPIO_TFT_RESET_PIN >= 0 + printf("Resetting display at reset GPIO pin %d\n", GPIO_TFT_RESET_PIN); + SET_GPIO_MODE(GPIO_TFT_RESET_PIN, 1); + SET_GPIO(GPIO_TFT_RESET_PIN); + usleep(120 * 1000); + CLEAR_GPIO(GPIO_TFT_RESET_PIN); + usleep(120 * 1000); + SET_GPIO(GPIO_TFT_RESET_PIN); + usleep(120 * 1000); +#endif + + // Do the initialization with a very low SPI bus speed, so that it will succeed even if the bus speed chosen by the user is too high. + spi->clk = 34; + __sync_synchronize(); + + BEGIN_SPI_COMMUNICATION(); + { + // The init sequence reference: + // https://www.waveshare.com/wiki/File:LCD_Module_code.zip + // File: RaspberryPi/c/lib/LCD/LCD_1in28.c + SPI_TRANSFER(0xEF); + SPI_TRANSFER(0xEB, 0x14); + + SPI_TRANSFER(0xFE); + SPI_TRANSFER(0xEF); + + SPI_TRANSFER(0xEB, 0x14); + + SPI_TRANSFER(0x84, 0x40); + + SPI_TRANSFER(0x85, 0xFF); + + SPI_TRANSFER(0x86, 0xFF); + + SPI_TRANSFER(0x87, 0xFF); + + SPI_TRANSFER(0x88, 0x0A); + + SPI_TRANSFER(0x89, 0x21); + + SPI_TRANSFER(0x8A, 0x00); + + SPI_TRANSFER(0x8B, 0x80); + + SPI_TRANSFER(0x8C, 0x01); + + SPI_TRANSFER(0x8D, 0x01); + + SPI_TRANSFER(0x8E, 0xFF); + + SPI_TRANSFER(0x8F, 0xFF); + + + SPI_TRANSFER(0xB6, 0x00, 0x20); + + SPI_TRANSFER(0x36, 0x08);//Set as vertical screen + + SPI_TRANSFER(0x3A, 0x05); + + + SPI_TRANSFER(0x90, 0x08, 0x08, 0x08, 0x08); + + SPI_TRANSFER(0xBD, 0x06); + + SPI_TRANSFER(0xBC, 0x00); + + SPI_TRANSFER(0xFF, 0x60, 0x01, 0x04); + + SPI_TRANSFER(0xC3, 0x13); + + SPI_TRANSFER(0xC4, 0x13); + + SPI_TRANSFER(0xC9, 0x22); + + SPI_TRANSFER(0xBE, 0x11); + + SPI_TRANSFER(0xE1, 0x10, 0x0E); + + SPI_TRANSFER(0xDF, 0x21, 0x0c, 0x02); + + SPI_TRANSFER(0xF0, 0x45, 0x09, 0x08, 0x08, 0x26, 0x2A); + + SPI_TRANSFER(0xF1, 0x43, 0x70, 0x72, 0x36, 0x37, 0x6F); + + + SPI_TRANSFER(0xF2, 0x45, 0x09, 0x08, 0x08, 0x26, 0x2A); + + SPI_TRANSFER(0xF3, 0x43, 0x70, 0x72, 0x36, 0x37, 0x6F); + + SPI_TRANSFER(0xED, 0x1B, 0x0B); + + SPI_TRANSFER(0xAE, 0x77); + + SPI_TRANSFER(0xCD, 0x63); + + + SPI_TRANSFER(0x70, 0x07, 0x07, 0x04, 0x0E, 0x0F, 0x09, 0x07, 0x08, 0x03); + + SPI_TRANSFER(0xE8, 0x34); + + SPI_TRANSFER(0x62, 0x18, 0x0D, 0x71, 0xED, 0x70, 0x70, 0x18, 0x0F, 0x71, 0xEF, 0x70, 0x70); + + SPI_TRANSFER(0x63, 0x18, 0x11, 0x71, 0xF1, 0x70, 0x70, 0x18, 0x13, 0x71, 0xF3, 0x70, 0x70); + + SPI_TRANSFER(0x64, 0x28, 0x29, 0xF1, 0x01, 0xF1, 0x00, 0x07); + + SPI_TRANSFER(0x66, 0x3C, 0x00, 0xCD, 0x67, 0x45, 0x45, 0x10, 0x00, 0x00, 0x00); + + SPI_TRANSFER(0x67, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x01, 0x54, 0x10, 0x32, 0x98); + + SPI_TRANSFER(0x74, 0x10, 0x85, 0x80, 0x00, 0x00, 0x4E, 0x00); + + SPI_TRANSFER(0x98, 0x3e, 0x07); + + SPI_TRANSFER(0x35); + + SPI_TRANSFER(0x21); + + SPI_TRANSFER(0x11); + usleep(120 * 1000); + SPI_TRANSFER(0x29); + usleep(20 * 1000); + + ClearScreen(); + } +#ifndef USE_DMA_TRANSFERS // For DMA transfers, keep SPI CS & TA active. + END_SPI_COMMUNICATION(); +#endif + + // And speed up to the desired operation speed finally after init is done. + usleep(10 * 1000); // Delay a bit before restoring CLK, or otherwise this has been observed to cause the display not init if done back to back after the clear operation above. + spi->clk = SPI_BUS_CLOCK_DIVISOR; +} + +void TurnBacklightOn() +{ +#if defined(GPIO_TFT_BACKLIGHT) && defined(BACKLIGHT_CONTROL) + SET_GPIO_MODE(GPIO_TFT_BACKLIGHT, 0x01); // Set backlight pin to digital 0/1 output mode (0x01) in case it had been PWM controlled + SET_GPIO(GPIO_TFT_BACKLIGHT); // And turn the backlight on. +#endif +} + +void TurnBacklightOff() +{ +#if defined(GPIO_TFT_BACKLIGHT) && defined(BACKLIGHT_CONTROL) + SET_GPIO_MODE(GPIO_TFT_BACKLIGHT, 0x01); // Set backlight pin to digital 0/1 output mode (0x01) in case it had been PWM controlled + CLEAR_GPIO(GPIO_TFT_BACKLIGHT); // And turn the backlight off. +#endif +} + +void TurnDisplayOff() +{ + TurnBacklightOff(); +} + +void TurnDisplayOn() +{ + TurnBacklightOn(); +} + +void DeinitSPIDisplay() +{ + ClearScreen(); + SPI_TRANSFER(/*Display OFF*/ 0x28); + TurnBacklightOff(); +} + +#endif diff --git a/gc9a01.h b/gc9a01.h new file mode 100644 index 0000000..9c4afc2 --- /dev/null +++ b/gc9a01.h @@ -0,0 +1,27 @@ +#pragma once + +#if defined(GC9A01) + +// Data specific to the GC9A01 controller +#define DISPLAY_SET_CURSOR_X 0x2A +#define DISPLAY_SET_CURSOR_Y 0x2B +#define DISPLAY_WRITE_PIXELS 0x2C + +#define MUST_SEND_FULL_CURSOR_WINDOW + +#define DISPLAY_NATIVE_WIDTH 240 +#define DISPLAY_NATIVE_HEIGHT 240 + +#define ALL_TASKS_SHOULD_DMA +#define UPDATE_FRAMES_WITHOUT_DIFFING +#undef SAVE_BATTERY_BY_SLEEPING_WHEN_IDLE // workaround for preventing crash in idle. + +#ifdef WAVESHARE_GC9A01 +#include "waveshare_gc9a01.h" +#endif + +#define InitSPIDisplay InitGC9A01 + +void InitGC9A01(void); + +#endif diff --git a/waveshare_gc9a01.h b/waveshare_gc9a01.h new file mode 100644 index 0000000..95f607c --- /dev/null +++ b/waveshare_gc9a01.h @@ -0,0 +1,19 @@ +#pragma once + +// Data specific to WaveShare 240x240, 1.28 inch ISP LCD GC9A01, https://www.waveshare.net/w/upload/5/5e/GC9A01A.pdf +#ifdef WAVESHARE_GC9A01 + +#if !defined(GPIO_TFT_DATA_CONTROL) +#define GPIO_TFT_DATA_CONTROL 25 +#endif + +#if !defined(GPIO_TFT_BACKLIGHT) +#define GPIO_TFT_BACKLIGHT 18 +#endif + +#if !defined(GPIO_TFT_RESET_PIN) +#define GPIO_TFT_RESET_PIN 27 +#endif + +#undef DISPLAY_OUTPUT_LANDSCAPE +#endif