/*! * @file Adafruit_GC9A01A.cpp * * @mainpage GC9A01A TFT Display library for Adafruit_GFX * * @section intro_sec Introduction * * Library to provide GC9A01A display driver support in Adafruit_GFX. * * These displays use SPI to communicate, 4 or 5 pins are required * to interface (RST is optional). * * Adafruit invests time and resources providing this open source code, * please support Adafruit and open-source hardware by purchasing * products from Adafruit! * * @section dependencies Dependencies * * This library depends on * Adafruit_GFX being present on your system. Please make sure you have * installed the latest version before using this library. * * @section author Author * * Written by Limor "ladyada" Fried for Adafruit Industries. * GC9A01A adaptation by Phil "PaintYourDragon" Burgess. * * @section license License * * BSD license, all text here must be included in any redistribution. * */ #include "Adafruit_GC9A01A.h" #ifndef ARDUINO_STM32_FEATHER #include "pins_arduino.h" #ifndef RASPI #include "wiring_private.h" #endif #endif #include #if defined(ARDUINO_ARCH_ARC32) || defined(ARDUINO_MAXIM) #define SPI_DEFAULT_FREQ 16000000 // Teensy 3.0, 3.1/3.2, 3.5, 3.6 #elif defined(__MK20DX128__) || defined(__MK20DX256__) || \ defined(__MK64FX512__) || defined(__MK66FX1M0__) #define SPI_DEFAULT_FREQ 40000000 #elif defined(__AVR__) || defined(TEENSYDUINO) #define SPI_DEFAULT_FREQ 8000000 #elif defined(ESP8266) || defined(ESP32) #define SPI_DEFAULT_FREQ 40000000 #elif defined(RASPI) #define SPI_DEFAULT_FREQ 80000000 #elif defined(ARDUINO_ARCH_STM32F1) #define SPI_DEFAULT_FREQ 36000000 #else #define SPI_DEFAULT_FREQ 24000000 ///< Default SPI data clock frequency #endif #define MADCTL_MY 0x80 ///< Bottom to top #define MADCTL_MX 0x40 ///< Right to left #define MADCTL_MV 0x20 ///< Reverse Mode #define MADCTL_ML 0x10 ///< LCD refresh Bottom to top #define MADCTL_RGB 0x00 ///< Red-Green-Blue pixel order #define MADCTL_BGR 0x08 ///< Blue-Green-Red pixel order #define MADCTL_MH 0x04 ///< LCD refresh right to left /*! @brief Instantiate Adafruit GC9A01A driver with software SPI @param cs Chip select pin # @param dc Data/Command pin # @param mosi SPI MOSI pin # @param sclk SPI Clock pin # @param rst Reset pin # (optional, pass -1 if unused) @param miso SPI MISO pin # (optional, pass -1 if unused) */ Adafruit_GC9A01A::Adafruit_GC9A01A(int8_t cs, int8_t dc, int8_t mosi, int8_t sclk, int8_t rst, int8_t miso) : Adafruit_SPITFT(GC9A01A_TFTWIDTH, GC9A01A_TFTHEIGHT, cs, dc, mosi, sclk, rst, miso) {} /*! @brief Instantiate Adafruit GC9A01A driver with hardware SPI using the default SPI peripheral. @param cs Chip select pin # (OK to pass -1 if CS tied to GND). @param dc Data/Command pin # (required). @param rst Reset pin # (optional, pass -1 if unused). */ Adafruit_GC9A01A::Adafruit_GC9A01A(int8_t cs, int8_t dc, int8_t rst) : Adafruit_SPITFT(GC9A01A_TFTWIDTH, GC9A01A_TFTHEIGHT, cs, dc, rst) {} #if !defined(ESP8266) /*! @brief Instantiate Adafruit GC9A01A driver with hardware SPI using a specific SPI peripheral (not necessarily default). @param spiClass Pointer to SPI peripheral (e.g. &SPI or &SPI1). @param dc Data/Command pin # (required). @param cs Chip select pin # (optional, pass -1 if unused and CS is tied to GND). @param rst Reset pin # (optional, pass -1 if unused). */ Adafruit_GC9A01A::Adafruit_GC9A01A(SPIClass *spiClass, int8_t dc, int8_t cs, int8_t rst) : Adafruit_SPITFT(GC9A01A_TFTWIDTH, GC9A01A_TFTHEIGHT, spiClass, cs, dc, rst) {} #endif // end !ESP8266 /*! @brief Instantiate Adafruit GC9A01A driver using parallel interface. @param busWidth If tft16 (enumeration in Adafruit_SPITFT.h), is a 16-bit interface, else 8-bit. @param d0 Data pin 0 (MUST be a byte- or word-aligned LSB of a PORT register -- pins 1-n are extrapolated from this). @param wr Write strobe pin # (required). @param dc Data/Command pin # (required). @param cs Chip select pin # (optional, pass -1 if unused and CS is tied to GND). @param rst Reset pin # (optional, pass -1 if unused). @param rd Read strobe pin # (optional, pass -1 if unused). */ Adafruit_GC9A01A::Adafruit_GC9A01A(tftBusWidth busWidth, int8_t d0, int8_t wr, int8_t dc, int8_t cs, int8_t rst, int8_t rd) : Adafruit_SPITFT(GC9A01A_TFTWIDTH, GC9A01A_TFTHEIGHT, busWidth, d0, wr, dc, cs, rst, rd) {} // clang-format off // Initialization sequence came from some early code provided by the // manufacturer. Many of these registers are undocumented, some might // be unnecessary, just playing along... static const uint8_t PROGMEM initcmd[] = { GC9A01A_INREGEN2, 0, 0xEB, 1, 0x14, // ? GC9A01A_INREGEN1, 0, GC9A01A_INREGEN2, 0, 0xEB, 1, 0x14, // ? 0x84, 1, 0x40, // ? 0x85, 1, 0xFF, // ? 0x86, 1, 0xFF, // ? 0x87, 1, 0xFF, // ? 0x88, 1, 0x0A, // ? 0x89, 1, 0x21, // ? 0x8A, 1, 0x00, // ? 0x8B, 1, 0x80, // ? 0x8C, 1, 0x01, // ? 0x8D, 1, 0x01, // ? 0x8E, 1, 0xFF, // ? 0x8F, 1, 0xFF, // ? 0xB6, 2, 0x00, 0x00, // ? GC9A01A_MADCTL, 1, MADCTL_MX | MADCTL_BGR, GC9A01A_COLMOD, 1, 0x05, 0x90, 4, 0x08, 0x08, 0x08, 0x08, // ? 0xBD, 1, 0x06, // ? 0xBC, 1, 0x00, // ? 0xFF, 3, 0x60, 0x01, 0x04, // ? GC9A01A1_POWER2, 1, 0x13, GC9A01A1_POWER3, 1, 0x13, GC9A01A1_POWER4, 1, 0x22, 0xBE, 1, 0x11, // ? 0xE1, 2, 0x10, 0x0E, // ? 0xDF, 3, 0x21, 0x0c, 0x02, // ? GC9A01A_GAMMA1, 6, 0x45, 0x09, 0x08, 0x08, 0x26, 0x2A, GC9A01A_GAMMA2, 6, 0x43, 0x70, 0x72, 0x36, 0x37, 0x6F, GC9A01A_GAMMA3, 6, 0x45, 0x09, 0x08, 0x08, 0x26, 0x2A, GC9A01A_GAMMA4, 6, 0x43, 0x70, 0x72, 0x36, 0x37, 0x6F, 0xED, 2, 0x1B, 0x0B, // ? 0xAE, 1, 0x77, // ? 0xCD, 1, 0x63, // ? // Unsure what this line (from manufacturer's boilerplate code) is // meant to do, but users reported issues, seems to work OK without: //0x70, 9, 0x07, 0x07, 0x04, 0x0E, 0x0F, 0x09, 0x07, 0x08, 0x03, // ? GC9A01A_FRAMERATE, 1, 0x34, 0x62, 12, 0x18, 0x0D, 0x71, 0xED, 0x70, 0x70, // ? 0x18, 0x0F, 0x71, 0xEF, 0x70, 0x70, 0x63, 12, 0x18, 0x11, 0x71, 0xF1, 0x70, 0x70, // ? 0x18, 0x13, 0x71, 0xF3, 0x70, 0x70, 0x64, 7, 0x28, 0x29, 0xF1, 0x01, 0xF1, 0x00, 0x07, // ? 0x66, 10, 0x3C, 0x00, 0xCD, 0x67, 0x45, 0x45, 0x10, 0x00, 0x00, 0x00, // ? 0x67, 10, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x01, 0x54, 0x10, 0x32, 0x98, // ? 0x74, 7, 0x10, 0x85, 0x80, 0x00, 0x00, 0x4E, 0x00, // ? 0x98, 2, 0x3e, 0x07, // ? GC9A01A_TEON, 0, GC9A01A_INVON, 0, GC9A01A_SLPOUT, 0x80, // Exit sleep GC9A01A_DISPON, 0x80, // Display on 0x00 // End of list }; // clang-format on /*! @brief Initialize GC9A01A chip. Connects to the GC9A01A over SPI and sends initialization commands. @param freq Desired SPI clock frequency */ void Adafruit_GC9A01A::begin(uint32_t freq) { if (!freq) freq = SPI_DEFAULT_FREQ; initSPI(freq); if (_rst < 0) { // If no hardware reset pin... sendCommand(GC9A01A_SWRESET); // Engage software reset delay(150); } uint8_t cmd, x, numArgs; const uint8_t *addr = initcmd; while ((cmd = pgm_read_byte(addr++)) > 0) { x = pgm_read_byte(addr++); numArgs = x & 0x7F; sendCommand(cmd, addr, numArgs); addr += numArgs; if (x & 0x80) delay(150); } _width = GC9A01A_TFTWIDTH; _height = GC9A01A_TFTHEIGHT; } /*! @brief Set origin of (0,0) and orientation of TFT display @param m The index for rotation, from 0-3 inclusive */ void Adafruit_GC9A01A::setRotation(uint8_t m) { rotation = m % 4; // can't be higher than 3 switch (rotation) { case 0: m = (MADCTL_MX | MADCTL_BGR); _width = GC9A01A_TFTWIDTH; _height = GC9A01A_TFTHEIGHT; break; case 1: m = (MADCTL_MV | MADCTL_BGR); _width = GC9A01A_TFTHEIGHT; _height = GC9A01A_TFTWIDTH; break; case 2: m = (MADCTL_MY | MADCTL_BGR); _width = GC9A01A_TFTWIDTH; _height = GC9A01A_TFTHEIGHT; break; case 3: m = (MADCTL_MX | MADCTL_MY | MADCTL_MV | MADCTL_BGR); _width = GC9A01A_TFTHEIGHT; _height = GC9A01A_TFTWIDTH; break; } sendCommand(GC9A01A_MADCTL, &m, 1); } /*! @brief Enable/Disable display color inversion @param invert True to invert, False to have normal color */ void Adafruit_GC9A01A::invertDisplay(bool invert) { sendCommand(invert ? GC9A01A_INVON : GC9A01A_INVOFF); } /*! @brief Set the "address window" - the rectangle we will write to RAM with the next chunk of SPI data. The GC9A01A will automatically wrap the data as each row is filled. @param x1 TFT memory 'x' origin @param y1 TFT memory 'y' origin @param w Width of rectangle @param h Height of rectangle */ void Adafruit_GC9A01A::setAddrWindow(uint16_t x1, uint16_t y1, uint16_t w, uint16_t h) { uint16_t x2 = (x1 + w - 1), y2 = (y1 + h - 1); writeCommand(GC9A01A_CASET); // Column address set SPI_WRITE16(x1); SPI_WRITE16(x2); writeCommand(GC9A01A_RASET); // Row address set SPI_WRITE16(y1); SPI_WRITE16(y2); writeCommand(GC9A01A_RAMWR); // Write to RAM }