├── .github ├── ISSUE_TEMPLATE.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── githubci.yml ├── .gitignore ├── Adafruit_GC9A01A.cpp ├── Adafruit_GC9A01A.h ├── README.md ├── examples └── graphicstest │ └── graphicstest.ino ├── extras ├── Adafruit_Arcada_FeatherM4.h └── Adafruit_Arcada_ItsyBitsyM4.h └── library.properties /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Thank you for opening an issue on an Adafruit Arduino library repository. To 2 | improve the speed of resolution please review the following guidelines and 3 | common troubleshooting steps below before creating the issue: 4 | 5 | - **Do not use GitHub issues for troubleshooting projects and issues.** Instead use 6 | the forums at http://forums.adafruit.com to ask questions and troubleshoot why 7 | something isn't working as expected. In many cases the problem is a common issue 8 | that you will more quickly receive help from the forum community. GitHub issues 9 | are meant for known defects in the code. If you don't know if there is a defect 10 | in the code then start with troubleshooting on the forum first. 11 | 12 | - **If following a tutorial or guide be sure you didn't miss a step.** Carefully 13 | check all of the steps and commands to run have been followed. Consult the 14 | forum if you're unsure or have questions about steps in a guide/tutorial. 15 | 16 | - **For Arduino projects check these very common issues to ensure they don't apply**: 17 | 18 | - For uploading sketches or communicating with the board make sure you're using 19 | a **USB data cable** and **not** a **USB charge-only cable**. It is sometimes 20 | very hard to tell the difference between a data and charge cable! Try using the 21 | cable with other devices or swapping to another cable to confirm it is not 22 | the problem. 23 | 24 | - **Be sure you are supplying adequate power to the board.** Check the specs of 25 | your board and plug in an external power supply. In many cases just 26 | plugging a board into your computer is not enough to power it and other 27 | peripherals. 28 | 29 | - **Double check all soldering joints and connections.** Flakey connections 30 | cause many mysterious problems. See the [guide to excellent soldering](https://learn.adafruit.com/adafruit-guide-excellent-soldering/tools) for examples of good solder joints. 31 | 32 | - **Ensure you are using an official Arduino or Adafruit board.** We can't 33 | guarantee a clone board will have the same functionality and work as expected 34 | with this code and don't support them. 35 | 36 | If you're sure this issue is a defect in the code and checked the steps above 37 | please fill in the following fields to provide enough troubleshooting information. 38 | You may delete the guideline and text above to just leave the following details: 39 | 40 | - Arduino board: **INSERT ARDUINO BOARD NAME/TYPE HERE** 41 | 42 | - Arduino IDE version (found in Arduino -> About Arduino menu): **INSERT ARDUINO 43 | VERSION HERE** 44 | 45 | - List the steps to reproduce the problem below (if possible attach a sketch or 46 | copy the sketch code in too): **LIST REPRO STEPS BELOW** 47 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Thank you for creating a pull request to contribute to Adafruit's GitHub code! 2 | Before you open the request please review the following guidelines and tips to 3 | help it be more easily integrated: 4 | 5 | - **Describe the scope of your change--i.e. what the change does and what parts 6 | of the code were modified.** This will help us understand any risks of integrating 7 | the code. 8 | 9 | - **Describe any known limitations with your change.** For example if the change 10 | doesn't apply to a supported platform of the library please mention it. 11 | 12 | - **Please run any tests or examples that can exercise your modified code.** We 13 | strive to not break users of the code and running tests/examples helps with this 14 | process. 15 | 16 | Thank you again for contributing! We will try to test and integrate the change 17 | as soon as we can, but be aware we have many GitHub repositories to manage and 18 | can't immediately respond to every request. There is no need to bump or check in 19 | on a pull request (it will clutter the discussion of the request). 20 | 21 | Also don't be worried if the request is closed or not integrated--sometimes the 22 | priorities of Adafruit's GitHub code (education, ease of use) might not match the 23 | priorities of the pull request. Don't fret, the open source community thrives on 24 | forks and GitHub makes it easy to keep your changes in a forked repo. 25 | 26 | After reviewing the guidelines above you can delete this text from the pull request. 27 | -------------------------------------------------------------------------------- /.github/workflows/githubci.yml: -------------------------------------------------------------------------------- 1 | name: Arduino Library CI 2 | 3 | on: [pull_request, push, repository_dispatch] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - uses: actions/setup-python@v1 11 | with: 12 | python-version: '3.x' 13 | - uses: actions/checkout@v2 14 | - uses: actions/checkout@v2 15 | with: 16 | repository: adafruit/ci-arduino 17 | path: ci 18 | 19 | - name: pre-install 20 | run: bash ci/actions_install.sh 21 | 22 | - name: test platforms 23 | run: python3 ci/build_platform.py main_platforms 24 | 25 | - name: clang 26 | run: python3 ci/run-clang-format.py -e "ci/*" -e "bin/*" -r . 27 | 28 | - name: doxygen 29 | env: 30 | GH_REPO_TOKEN: ${{ secrets.GH_REPO_TOKEN }} 31 | PRETTYNAME : "Adafruit GC9A01A" 32 | run: bash ci/doxy_gen_and_deploy.sh 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Our handy .gitignore for automation ease 2 | Doxyfile* 3 | doxygen_sqlite3.db 4 | html 5 | -------------------------------------------------------------------------------- /Adafruit_GC9A01A.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file Adafruit_GC9A01A.cpp 3 | * 4 | * @mainpage GC9A01A TFT Display library for Adafruit_GFX 5 | * 6 | * @section intro_sec Introduction 7 | * 8 | * Library to provide GC9A01A display driver support in Adafruit_GFX. 9 | * 10 | * These displays use SPI to communicate, 4 or 5 pins are required 11 | * to interface (RST is optional). 12 | * 13 | * Adafruit invests time and resources providing this open source code, 14 | * please support Adafruit and open-source hardware by purchasing 15 | * products from Adafruit! 16 | * 17 | * @section dependencies Dependencies 18 | * 19 | * This library depends on 20 | * Adafruit_GFX being present on your system. Please make sure you have 21 | * installed the latest version before using this library. 22 | * 23 | * @section author Author 24 | * 25 | * Written by Limor "ladyada" Fried for Adafruit Industries. 26 | * GC9A01A adaptation by Phil "PaintYourDragon" Burgess. 27 | * 28 | * @section license License 29 | * 30 | * BSD license, all text here must be included in any redistribution. 31 | * 32 | */ 33 | 34 | #include "Adafruit_GC9A01A.h" 35 | #ifndef ARDUINO_STM32_FEATHER 36 | #include "pins_arduino.h" 37 | #ifndef RASPI 38 | #include "wiring_private.h" 39 | #endif 40 | #endif 41 | #include 42 | 43 | #if defined(ARDUINO_ARCH_ARC32) || defined(ARDUINO_MAXIM) 44 | #define SPI_DEFAULT_FREQ 16000000 45 | // Teensy 3.0, 3.1/3.2, 3.5, 3.6 46 | #elif defined(__MK20DX128__) || defined(__MK20DX256__) || \ 47 | defined(__MK64FX512__) || defined(__MK66FX1M0__) 48 | #define SPI_DEFAULT_FREQ 40000000 49 | #elif defined(__AVR__) || defined(TEENSYDUINO) 50 | #define SPI_DEFAULT_FREQ 8000000 51 | #elif defined(ESP8266) || defined(ESP32) 52 | #define SPI_DEFAULT_FREQ 40000000 53 | #elif defined(RASPI) 54 | #define SPI_DEFAULT_FREQ 80000000 55 | #elif defined(ARDUINO_ARCH_STM32F1) 56 | #define SPI_DEFAULT_FREQ 36000000 57 | #else 58 | #define SPI_DEFAULT_FREQ 24000000 ///< Default SPI data clock frequency 59 | #endif 60 | 61 | #define MADCTL_MY 0x80 ///< Bottom to top 62 | #define MADCTL_MX 0x40 ///< Right to left 63 | #define MADCTL_MV 0x20 ///< Reverse Mode 64 | #define MADCTL_ML 0x10 ///< LCD refresh Bottom to top 65 | #define MADCTL_RGB 0x00 ///< Red-Green-Blue pixel order 66 | #define MADCTL_BGR 0x08 ///< Blue-Green-Red pixel order 67 | #define MADCTL_MH 0x04 ///< LCD refresh right to left 68 | 69 | /*! 70 | @brief Instantiate Adafruit GC9A01A driver with software SPI 71 | @param cs Chip select pin # 72 | @param dc Data/Command pin # 73 | @param mosi SPI MOSI pin # 74 | @param sclk SPI Clock pin # 75 | @param rst Reset pin # (optional, pass -1 if unused) 76 | @param miso SPI MISO pin # (optional, pass -1 if unused) 77 | */ 78 | Adafruit_GC9A01A::Adafruit_GC9A01A(int8_t cs, int8_t dc, int8_t mosi, 79 | int8_t sclk, int8_t rst, int8_t miso) 80 | : Adafruit_SPITFT(GC9A01A_TFTWIDTH, GC9A01A_TFTHEIGHT, cs, dc, mosi, sclk, 81 | rst, miso) {} 82 | 83 | /*! 84 | @brief Instantiate Adafruit GC9A01A driver with hardware SPI using the 85 | default SPI peripheral. 86 | @param cs Chip select pin # (OK to pass -1 if CS tied to GND). 87 | @param dc Data/Command pin # (required). 88 | @param rst Reset pin # (optional, pass -1 if unused). 89 | */ 90 | Adafruit_GC9A01A::Adafruit_GC9A01A(int8_t cs, int8_t dc, int8_t rst) 91 | : Adafruit_SPITFT(GC9A01A_TFTWIDTH, GC9A01A_TFTHEIGHT, cs, dc, rst) {} 92 | 93 | #if !defined(ESP8266) 94 | /*! 95 | @brief Instantiate Adafruit GC9A01A driver with hardware SPI using 96 | a specific SPI peripheral (not necessarily default). 97 | @param spiClass Pointer to SPI peripheral (e.g. &SPI or &SPI1). 98 | @param dc Data/Command pin # (required). 99 | @param cs Chip select pin # (optional, pass -1 if unused and 100 | CS is tied to GND). 101 | @param rst Reset pin # (optional, pass -1 if unused). 102 | */ 103 | Adafruit_GC9A01A::Adafruit_GC9A01A(SPIClass *spiClass, int8_t dc, int8_t cs, 104 | int8_t rst) 105 | : Adafruit_SPITFT(GC9A01A_TFTWIDTH, GC9A01A_TFTHEIGHT, spiClass, cs, dc, 106 | rst) {} 107 | #endif // end !ESP8266 108 | 109 | /*! 110 | @brief Instantiate Adafruit GC9A01A driver using parallel interface. 111 | @param busWidth If tft16 (enumeration in Adafruit_SPITFT.h), is a 112 | 16-bit interface, else 8-bit. 113 | @param d0 Data pin 0 (MUST be a byte- or word-aligned LSB of a 114 | PORT register -- pins 1-n are extrapolated from this). 115 | @param wr Write strobe pin # (required). 116 | @param dc Data/Command pin # (required). 117 | @param cs Chip select pin # (optional, pass -1 if unused and CS 118 | is tied to GND). 119 | @param rst Reset pin # (optional, pass -1 if unused). 120 | @param rd Read strobe pin # (optional, pass -1 if unused). 121 | */ 122 | Adafruit_GC9A01A::Adafruit_GC9A01A(tftBusWidth busWidth, int8_t d0, int8_t wr, 123 | int8_t dc, int8_t cs, int8_t rst, int8_t rd) 124 | : Adafruit_SPITFT(GC9A01A_TFTWIDTH, GC9A01A_TFTHEIGHT, busWidth, d0, wr, dc, 125 | cs, rst, rd) {} 126 | 127 | // clang-format off 128 | // Initialization sequence came from some early code provided by the 129 | // manufacturer. Many of these registers are undocumented, some might 130 | // be unnecessary, just playing along... 131 | static const uint8_t PROGMEM initcmd[] = { 132 | GC9A01A_INREGEN2, 0, 133 | 0xEB, 1, 0x14, // ? 134 | GC9A01A_INREGEN1, 0, 135 | GC9A01A_INREGEN2, 0, 136 | 0xEB, 1, 0x14, // ? 137 | 0x84, 1, 0x40, // ? 138 | 0x85, 1, 0xFF, // ? 139 | 0x86, 1, 0xFF, // ? 140 | 0x87, 1, 0xFF, // ? 141 | 0x88, 1, 0x0A, // ? 142 | 0x89, 1, 0x21, // ? 143 | 0x8A, 1, 0x00, // ? 144 | 0x8B, 1, 0x80, // ? 145 | 0x8C, 1, 0x01, // ? 146 | 0x8D, 1, 0x01, // ? 147 | 0x8E, 1, 0xFF, // ? 148 | 0x8F, 1, 0xFF, // ? 149 | 0xB6, 2, 0x00, 0x00, // ? 150 | GC9A01A_MADCTL, 1, MADCTL_MX | MADCTL_BGR, 151 | GC9A01A_COLMOD, 1, 0x05, 152 | 0x90, 4, 0x08, 0x08, 0x08, 0x08, // ? 153 | 0xBD, 1, 0x06, // ? 154 | 0xBC, 1, 0x00, // ? 155 | 0xFF, 3, 0x60, 0x01, 0x04, // ? 156 | GC9A01A1_POWER2, 1, 0x13, 157 | GC9A01A1_POWER3, 1, 0x13, 158 | GC9A01A1_POWER4, 1, 0x22, 159 | 0xBE, 1, 0x11, // ? 160 | 0xE1, 2, 0x10, 0x0E, // ? 161 | 0xDF, 3, 0x21, 0x0c, 0x02, // ? 162 | GC9A01A_GAMMA1, 6, 0x45, 0x09, 0x08, 0x08, 0x26, 0x2A, 163 | GC9A01A_GAMMA2, 6, 0x43, 0x70, 0x72, 0x36, 0x37, 0x6F, 164 | GC9A01A_GAMMA3, 6, 0x45, 0x09, 0x08, 0x08, 0x26, 0x2A, 165 | GC9A01A_GAMMA4, 6, 0x43, 0x70, 0x72, 0x36, 0x37, 0x6F, 166 | 0xED, 2, 0x1B, 0x0B, // ? 167 | 0xAE, 1, 0x77, // ? 168 | 0xCD, 1, 0x63, // ? 169 | // Unsure what this line (from manufacturer's boilerplate code) is 170 | // meant to do, but users reported issues, seems to work OK without: 171 | //0x70, 9, 0x07, 0x07, 0x04, 0x0E, 0x0F, 0x09, 0x07, 0x08, 0x03, // ? 172 | GC9A01A_FRAMERATE, 1, 0x34, 173 | 0x62, 12, 0x18, 0x0D, 0x71, 0xED, 0x70, 0x70, // ? 174 | 0x18, 0x0F, 0x71, 0xEF, 0x70, 0x70, 175 | 0x63, 12, 0x18, 0x11, 0x71, 0xF1, 0x70, 0x70, // ? 176 | 0x18, 0x13, 0x71, 0xF3, 0x70, 0x70, 177 | 0x64, 7, 0x28, 0x29, 0xF1, 0x01, 0xF1, 0x00, 0x07, // ? 178 | 0x66, 10, 0x3C, 0x00, 0xCD, 0x67, 0x45, 0x45, 0x10, 0x00, 0x00, 0x00, // ? 179 | 0x67, 10, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x01, 0x54, 0x10, 0x32, 0x98, // ? 180 | 0x74, 7, 0x10, 0x85, 0x80, 0x00, 0x00, 0x4E, 0x00, // ? 181 | 0x98, 2, 0x3e, 0x07, // ? 182 | GC9A01A_TEON, 0, 183 | GC9A01A_INVON, 0, 184 | GC9A01A_SLPOUT, 0x80, // Exit sleep 185 | GC9A01A_DISPON, 0x80, // Display on 186 | 0x00 // End of list 187 | }; 188 | // clang-format on 189 | 190 | /*! 191 | @brief Initialize GC9A01A chip. Connects to the GC9A01A over SPI 192 | and sends initialization commands. 193 | @param freq Desired SPI clock frequency 194 | */ 195 | void Adafruit_GC9A01A::begin(uint32_t freq) { 196 | 197 | if (!freq) 198 | freq = SPI_DEFAULT_FREQ; 199 | initSPI(freq); 200 | 201 | if (_rst < 0) { // If no hardware reset pin... 202 | sendCommand(GC9A01A_SWRESET); // Engage software reset 203 | delay(150); 204 | } 205 | 206 | uint8_t cmd, x, numArgs; 207 | const uint8_t *addr = initcmd; 208 | while ((cmd = pgm_read_byte(addr++)) > 0) { 209 | x = pgm_read_byte(addr++); 210 | numArgs = x & 0x7F; 211 | sendCommand(cmd, addr, numArgs); 212 | addr += numArgs; 213 | if (x & 0x80) 214 | delay(150); 215 | } 216 | 217 | _width = GC9A01A_TFTWIDTH; 218 | _height = GC9A01A_TFTHEIGHT; 219 | } 220 | 221 | /*! 222 | @brief Set origin of (0,0) and orientation of TFT display 223 | @param m The index for rotation, from 0-3 inclusive 224 | */ 225 | void Adafruit_GC9A01A::setRotation(uint8_t m) { 226 | rotation = m % 4; // can't be higher than 3 227 | switch (rotation) { 228 | case 0: 229 | m = (MADCTL_MX | MADCTL_BGR); 230 | _width = GC9A01A_TFTWIDTH; 231 | _height = GC9A01A_TFTHEIGHT; 232 | break; 233 | case 1: 234 | m = (MADCTL_MV | MADCTL_BGR); 235 | _width = GC9A01A_TFTHEIGHT; 236 | _height = GC9A01A_TFTWIDTH; 237 | break; 238 | case 2: 239 | m = (MADCTL_MY | MADCTL_BGR); 240 | _width = GC9A01A_TFTWIDTH; 241 | _height = GC9A01A_TFTHEIGHT; 242 | break; 243 | case 3: 244 | m = (MADCTL_MX | MADCTL_MY | MADCTL_MV | MADCTL_BGR); 245 | _width = GC9A01A_TFTHEIGHT; 246 | _height = GC9A01A_TFTWIDTH; 247 | break; 248 | } 249 | 250 | sendCommand(GC9A01A_MADCTL, &m, 1); 251 | } 252 | 253 | /*! 254 | @brief Enable/Disable display color inversion 255 | @param invert True to invert, False to have normal color 256 | */ 257 | void Adafruit_GC9A01A::invertDisplay(bool invert) { 258 | sendCommand(invert ? GC9A01A_INVON : GC9A01A_INVOFF); 259 | } 260 | 261 | /*! 262 | @brief Set the "address window" - the rectangle we will write to RAM 263 | with the next chunk of SPI data. The GC9A01A will automatically 264 | wrap the data as each row is filled. 265 | @param x1 TFT memory 'x' origin 266 | @param y1 TFT memory 'y' origin 267 | @param w Width of rectangle 268 | @param h Height of rectangle 269 | */ 270 | void Adafruit_GC9A01A::setAddrWindow(uint16_t x1, uint16_t y1, uint16_t w, 271 | uint16_t h) { 272 | uint16_t x2 = (x1 + w - 1), y2 = (y1 + h - 1); 273 | writeCommand(GC9A01A_CASET); // Column address set 274 | SPI_WRITE16(x1); 275 | SPI_WRITE16(x2); 276 | writeCommand(GC9A01A_RASET); // Row address set 277 | SPI_WRITE16(y1); 278 | SPI_WRITE16(y2); 279 | writeCommand(GC9A01A_RAMWR); // Write to RAM 280 | } 281 | -------------------------------------------------------------------------------- /Adafruit_GC9A01A.h: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file Adafruit_GC9A01A.h 3 | * 4 | * Library to provide GC9A01A display driver support in Adafruit_GFX. 5 | * 6 | * Adafruit invests time and resources providing this open source code, 7 | * please support Adafruit and open-source hardware by purchasing 8 | * products from Adafruit! 9 | * 10 | * This library depends on 11 | * Adafruit_GFX being present on your system. Please make sure you have 12 | * installed the latest version before using this library. 13 | * 14 | * Written by Limor "ladyada" Fried for Adafruit Industries. 15 | * GC9A01A adaptation by Phil "PaintYourDragon" Burgess. 16 | * 17 | * BSD license, all text here must be included in any redistribution. 18 | * 19 | */ 20 | 21 | #pragma once 22 | 23 | #include "Adafruit_GFX.h" 24 | #include "Arduino.h" 25 | #include "Print.h" 26 | #include 27 | #include 28 | #include 29 | 30 | #define GC9A01A_TFTWIDTH 240 ///< Display width in pixels 31 | #define GC9A01A_TFTHEIGHT 240 ///< Display height in pixels 32 | 33 | #define GC9A01A_SWRESET 0x01 ///< Software Reset (maybe, not documented) 34 | #define GC9A01A_RDDID 0x04 ///< Read display identification information 35 | #define GC9A01A_RDDST 0x09 ///< Read Display Status 36 | #define GC9A01A_SLPIN 0x10 ///< Enter Sleep Mode 37 | #define GC9A01A_SLPOUT 0x11 ///< Sleep Out 38 | #define GC9A01A_PTLON 0x12 ///< Partial Mode ON 39 | #define GC9A01A_NORON 0x13 ///< Normal Display Mode ON 40 | #define GC9A01A_INVOFF 0x20 ///< Display Inversion OFF 41 | #define GC9A01A_INVON 0x21 ///< Display Inversion ON 42 | #define GC9A01A_DISPOFF 0x28 ///< Display OFF 43 | #define GC9A01A_DISPON 0x29 ///< Display ON 44 | #define GC9A01A_CASET 0x2A ///< Column Address Set 45 | #define GC9A01A_RASET 0x2B ///< Row Address Set 46 | #define GC9A01A_RAMWR 0x2C ///< Memory Write 47 | #define GC9A01A_PTLAR 0x30 ///< Partial Area 48 | #define GC9A01A_VSCRDEF 0x33 ///< Vertical Scrolling Definition 49 | #define GC9A01A_TEOFF 0x34 ///< Tearing Effect Line OFF 50 | #define GC9A01A_TEON 0x35 ///< Tearing Effect Line ON 51 | #define GC9A01A_MADCTL 0x36 ///< Memory Access Control 52 | #define GC9A01A_VSCRSADD 0x37 ///< Vertical Scrolling Start Address 53 | #define GC9A01A_IDLEOFF 0x38 ///< Idle mode OFF 54 | #define GC9A01A_IDLEON 0x39 ///< Idle mode ON 55 | #define GC9A01A_COLMOD 0x3A ///< Pixel Format Set 56 | #define GC9A01A_CONTINUE 0x3C ///< Write Memory Continue 57 | #define GC9A01A_TEARSET 0x44 ///< Set Tear Scanline 58 | #define GC9A01A_GETLINE 0x45 ///< Get Scanline 59 | #define GC9A01A_SETBRIGHT 0x51 ///< Write Display Brightness 60 | #define GC9A01A_SETCTRL 0x53 ///< Write CTRL Display 61 | #define GC9A01A1_POWER7 0xA7 ///< Power Control 7 62 | #define GC9A01A_TEWC 0xBA ///< Tearing effect width control 63 | #define GC9A01A1_POWER1 0xC1 ///< Power Control 1 64 | #define GC9A01A1_POWER2 0xC3 ///< Power Control 2 65 | #define GC9A01A1_POWER3 0xC4 ///< Power Control 3 66 | #define GC9A01A1_POWER4 0xC9 ///< Power Control 4 67 | #define GC9A01A_RDID1 0xDA ///< Read ID 1 68 | #define GC9A01A_RDID2 0xDB ///< Read ID 2 69 | #define GC9A01A_RDID3 0xDC ///< Read ID 3 70 | #define GC9A01A_FRAMERATE 0xE8 ///< Frame rate control 71 | #define GC9A01A_SPI2DATA 0xE9 ///< SPI 2DATA control 72 | #define GC9A01A_INREGEN2 0xEF ///< Inter register enable 2 73 | #define GC9A01A_GAMMA1 0xF0 ///< Set gamma 1 74 | #define GC9A01A_GAMMA2 0xF1 ///< Set gamma 2 75 | #define GC9A01A_GAMMA3 0xF2 ///< Set gamma 3 76 | #define GC9A01A_GAMMA4 0xF3 ///< Set gamma 4 77 | #define GC9A01A_IFACE 0xF6 ///< Interface control 78 | #define GC9A01A_INREGEN1 0xFE ///< Inter register enable 1 79 | 80 | // Color definitions 81 | #define GC9A01A_BLACK 0x0000 ///< 0, 0, 0 82 | #define GC9A01A_NAVY 0x000F ///< 0, 0, 123 83 | #define GC9A01A_DARKGREEN 0x03E0 ///< 0, 125, 0 84 | #define GC9A01A_DARKCYAN 0x03EF ///< 0, 125, 123 85 | #define GC9A01A_MAROON 0x7800 ///< 123, 0, 0 86 | #define GC9A01A_PURPLE 0x780F ///< 123, 0, 123 87 | #define GC9A01A_OLIVE 0x7BE0 ///< 123, 125, 0 88 | #define GC9A01A_LIGHTGREY 0xC618 ///< 198, 195, 198 89 | #define GC9A01A_DARKGREY 0x7BEF ///< 123, 125, 123 90 | #define GC9A01A_BLUE 0x001F ///< 0, 0, 255 91 | #define GC9A01A_GREEN 0x07E0 ///< 0, 255, 0 92 | #define GC9A01A_CYAN 0x07FF ///< 0, 255, 255 93 | #define GC9A01A_RED 0xF800 ///< 255, 0, 0 94 | #define GC9A01A_MAGENTA 0xF81F ///< 255, 0, 255 95 | #define GC9A01A_YELLOW 0xFFE0 ///< 255, 255, 0 96 | #define GC9A01A_WHITE 0xFFFF ///< 255, 255, 255 97 | #define GC9A01A_ORANGE 0xFD20 ///< 255, 165, 0 98 | #define GC9A01A_GREENYELLOW 0xAFE5 ///< 173, 255, 41 99 | #define GC9A01A_PINK 0xFC18 ///< 255, 130, 198 100 | 101 | /*! 102 | @brief Class to manage hardware interface with GC9A01A chipset. 103 | */ 104 | class Adafruit_GC9A01A : public Adafruit_SPITFT { 105 | public: 106 | Adafruit_GC9A01A(int8_t _CS, int8_t _DC, int8_t _MOSI, int8_t _SCLK, 107 | int8_t _RST = -1, int8_t _MISO = -1); 108 | Adafruit_GC9A01A(int8_t _CS, int8_t _DC, int8_t _RST = -1); 109 | #if !defined(ESP8266) 110 | Adafruit_GC9A01A(SPIClass *spiClass, int8_t dc, int8_t cs = -1, 111 | int8_t rst = -1); 112 | #endif // end !ESP8266 113 | Adafruit_GC9A01A(tftBusWidth busWidth, int8_t d0, int8_t wr, int8_t dc, 114 | int8_t cs = -1, int8_t rst = -1, int8_t rd = -1); 115 | 116 | void begin(uint32_t freq = 0); 117 | void setRotation(uint8_t r); 118 | void invertDisplay(bool i); 119 | 120 | void setAddrWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h); 121 | }; 122 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GC9A01A Arduino Library 2 | 3 | Library to provide GC9A01A display driver support in Adafruit_GFX. 4 | 5 | Adafruit invests time and resources providing this open source code, 6 | please support Adafruit and open-source hardware by purchasing 7 | products from Adafruit! 8 | 9 | Written by Limor Fried/Ladyada for Adafruit Industries. 10 | GC9A01A adaptation by Phil "PaintYourDragon" Burgess. 11 | BSD license, all text above must be included in any redistribution 12 | 13 | Requires the Adafruit_GFX library for Arduino. 14 | 15 | EXTRAS FOLDER: Adafruit_Arcada_FeatherM4.h file can be used with 16 | Adafruit_Arcada library to make the M4_Eyes sketch compile on Adafruit 17 | Feather M4 with this display (second display has not been tested, 18 | would require setting up a second SPI SERCOM, but in theory it should work). 19 | -------------------------------------------------------------------------------- /examples/graphicstest/graphicstest.ino: -------------------------------------------------------------------------------- 1 | #include "SPI.h" 2 | #include "Adafruit_GFX.h" 3 | #include "Adafruit_GC9A01A.h" 4 | 5 | // Define pins for display interface. You'll probably need to edit this for 6 | // your own needs: 7 | 8 | #if defined(ARDUINO_SEEED_XIAO_RP2040) 9 | 10 | // Pinout when using Seed Round Display for XIAO in combination with 11 | // Seeed XIAO RP2040. Other (non-RP2040) XIAO boards, any Adafruit Qt Py 12 | // boards, and other GC9A01A display breakouts will require different pins. 13 | #define TFT_CS D1 // Chip select 14 | #define TFT_DC D3 // Data/command 15 | #define TFT_BL D6 // Backlight control 16 | 17 | #else // ALL OTHER BOARDS - EDIT AS NEEDED 18 | 19 | // Other RP2040-based boards might not have "D" pin defines as shown above 20 | // and will use GPIO bit numbers. On non-RP2040 boards, you can usually use 21 | // pin numbers silkscreened on the board. 22 | #define TFT_DC 9 23 | #define TFT_CS 10 24 | // If display breakout has a backlight control pin, that can be defined here 25 | // as TFT_BL. On some breakouts it's not needed, backlight is always on. 26 | 27 | #endif 28 | 29 | // Display constructor for primary hardware SPI connection -- the specific 30 | // pins used for writing to the display are unique to each board and are not 31 | // negotiable. "Soft" SPI (using any pins) is an option but performance is 32 | // reduced; it's rarely used, see header file for syntax if needed. 33 | Adafruit_GC9A01A tft(TFT_CS, TFT_DC); 34 | 35 | void setup() { 36 | Serial.begin(9600); 37 | Serial.println("GC9A01A Test!"); 38 | 39 | tft.begin(); 40 | 41 | #if defined(TFT_BL) 42 | pinMode(TFT_BL, OUTPUT); 43 | digitalWrite(TFT_BL, HIGH); // Backlight on 44 | #endif // end TFT_BL 45 | 46 | Serial.println(F("Benchmark Time (microseconds)")); 47 | delay(10); 48 | Serial.print(F("Screen fill ")); 49 | Serial.println(testFillScreen()); 50 | delay(500); 51 | 52 | Serial.print(F("Text ")); 53 | Serial.println(testText()); 54 | delay(3000); 55 | 56 | Serial.print(F("Lines ")); 57 | Serial.println(testLines(GC9A01A_CYAN)); 58 | delay(500); 59 | 60 | Serial.print(F("Horiz/Vert Lines ")); 61 | Serial.println(testFastLines(GC9A01A_RED, GC9A01A_BLUE)); 62 | delay(500); 63 | 64 | Serial.print(F("Rectangles (outline) ")); 65 | Serial.println(testRects(GC9A01A_GREEN)); 66 | delay(500); 67 | 68 | Serial.print(F("Rectangles (filled) ")); 69 | Serial.println(testFilledRects(GC9A01A_YELLOW, GC9A01A_MAGENTA)); 70 | delay(500); 71 | 72 | Serial.print(F("Circles (filled) ")); 73 | Serial.println(testFilledCircles(10, GC9A01A_MAGENTA)); 74 | 75 | Serial.print(F("Circles (outline) ")); 76 | Serial.println(testCircles(10, GC9A01A_WHITE)); 77 | delay(500); 78 | 79 | Serial.print(F("Triangles (outline) ")); 80 | Serial.println(testTriangles()); 81 | delay(500); 82 | 83 | Serial.print(F("Triangles (filled) ")); 84 | Serial.println(testFilledTriangles()); 85 | delay(500); 86 | 87 | Serial.print(F("Rounded rects (outline) ")); 88 | Serial.println(testRoundRects()); 89 | delay(500); 90 | 91 | Serial.print(F("Rounded rects (filled) ")); 92 | Serial.println(testFilledRoundRects()); 93 | delay(500); 94 | 95 | Serial.println(F("Done!")); 96 | } 97 | 98 | void loop(void) { 99 | for(uint8_t rotation=0; rotation<4; rotation++) { 100 | tft.setRotation(rotation); 101 | testText(); 102 | delay(1000); 103 | } 104 | } 105 | 106 | unsigned long testFillScreen() { 107 | unsigned long start = micros(); 108 | tft.fillScreen(GC9A01A_BLACK); 109 | yield(); 110 | tft.fillScreen(GC9A01A_RED); 111 | yield(); 112 | tft.fillScreen(GC9A01A_GREEN); 113 | yield(); 114 | tft.fillScreen(GC9A01A_BLUE); 115 | yield(); 116 | tft.fillScreen(GC9A01A_BLACK); 117 | yield(); 118 | return micros() - start; 119 | } 120 | 121 | unsigned long testText() { 122 | tft.fillScreen(GC9A01A_BLACK); 123 | unsigned long start = micros(); 124 | tft.setCursor(0, 0); 125 | tft.setTextColor(GC9A01A_WHITE); tft.setTextSize(1); 126 | tft.println("Hello World!"); 127 | tft.setTextColor(GC9A01A_YELLOW); tft.setTextSize(2); 128 | tft.println(1234.56); 129 | tft.setTextColor(GC9A01A_RED); tft.setTextSize(3); 130 | tft.println(0xDEADBEEF, HEX); 131 | tft.println(); 132 | tft.setTextColor(GC9A01A_GREEN); 133 | tft.setTextSize(5); 134 | tft.println("Groop"); 135 | tft.setTextSize(2); 136 | tft.println("I implore thee,"); 137 | tft.setTextSize(1); 138 | tft.println("my foonting turlingdromes."); 139 | tft.println("And hooptiously drangle me"); 140 | tft.println("with crinkly bindlewurdles,"); 141 | tft.println("Or I will rend thee"); 142 | tft.println("in the gobberwarts"); 143 | tft.println("with my blurglecruncheon,"); 144 | tft.println("see if I don't!"); 145 | return micros() - start; 146 | } 147 | 148 | unsigned long testLines(uint16_t color) { 149 | unsigned long start, t; 150 | int x1, y1, x2, y2, 151 | w = tft.width(), 152 | h = tft.height(); 153 | 154 | tft.fillScreen(GC9A01A_BLACK); 155 | yield(); 156 | 157 | x1 = y1 = 0; 158 | y2 = h - 1; 159 | start = micros(); 160 | for(x2=0; x20; i-=6) { 245 | i2 = i / 2; 246 | start = micros(); 247 | tft.fillRect(cx-i2, cy-i2, i, i, color1); 248 | t += micros() - start; 249 | // Outlines are not included in timing results 250 | tft.drawRect(cx-i2, cy-i2, i, i, color2); 251 | yield(); 252 | } 253 | 254 | return t; 255 | } 256 | 257 | unsigned long testFilledCircles(uint8_t radius, uint16_t color) { 258 | unsigned long start; 259 | int x, y, w = tft.width(), h = tft.height(), r2 = radius * 2; 260 | 261 | tft.fillScreen(GC9A01A_BLACK); 262 | start = micros(); 263 | for(x=radius; x10; i-=5) { 317 | start = micros(); 318 | tft.fillTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i, 319 | tft.color565(0, i*10, i*10)); 320 | t += micros() - start; 321 | tft.drawTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i, 322 | tft.color565(i*10, i*10, 0)); 323 | yield(); 324 | } 325 | 326 | return t; 327 | } 328 | 329 | unsigned long testRoundRects() { 330 | unsigned long start; 331 | int w, i, i2, 332 | cx = tft.width() / 2 - 1, 333 | cy = tft.height() / 2 - 1; 334 | 335 | tft.fillScreen(GC9A01A_BLACK); 336 | w = min(tft.width(), tft.height()); 337 | start = micros(); 338 | for(i=0; i20; i-=6) { 355 | i2 = i / 2; 356 | tft.fillRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(0, i, 0)); 357 | yield(); 358 | } 359 | 360 | return micros() - start; 361 | } 362 | -------------------------------------------------------------------------------- /extras/Adafruit_Arcada_FeatherM4.h: -------------------------------------------------------------------------------- 1 | // Header file to use Adafruit_Arcada library on Feather M4 with GC9A01A 2 | // displays. Allows M4_Eyes sketch to run on this hardware combo. 3 | // As written, this only handles a single GC9A01A screen. See 4 | // Adafruit_Arcada_ItsyBitsyM4.h for insights on handling 2 screens 5 | // (requires setting up a second SPI SERCOM). 6 | // Place file in Adafruit_Arcada/Boards and add line to Adafruit_Arcada.h: 7 | // #include "Boards/Adafruit_Arcada_FeatherM4.h" 8 | 9 | #if defined(_VARIANT_FEATHER_M4_) 10 | #include 11 | 12 | #define ARCADA_TFT_SPI SPI 13 | #define ARCADA_TFT_CS 10 // Display CS Arduino pin number 14 | #define ARCADA_TFT_DC 9 // Display D/C Arduino pin number 15 | #define ARCADA_TFT_RST -1 // Display reset Arduino pin number 16 | #define ARCADA_TFT_ROTATION 2 17 | #define ARCADA_TFT_DEFAULTFILL 0xFFFF 18 | #define ARCADA_TFT_WIDTH 240 19 | #define ARCADA_TFT_HEIGHT 240 20 | // #define ARCADA_TFT_LITE 47 21 | 22 | #define ARCADA_AUDIO_OUT A0 23 | 24 | #define ARCADA_CALLBACKTIMER 4 25 | #define ARCADA_CALLBACKTIMER_HANDLER TC4_Handler 26 | 27 | #define ARCADA_USE_JSON 28 | 29 | #include "arcadatype.h" 30 | 31 | class Adafruit_Arcada : public Adafruit_Arcada_SPITFT { 32 | public: 33 | Adafruit_Arcada(void) { _has_accel = false; }; 34 | 35 | bool variantBegin(void) { return true; } 36 | 37 | void displayBegin(void) { 38 | Adafruit_GC9A01A *tft = new Adafruit_GC9A01A(&ARCADA_TFT_SPI, ARCADA_TFT_DC, 39 | ARCADA_TFT_CS, ARCADA_TFT_RST); 40 | tft->begin(); 41 | tft->setRotation(ARCADA_TFT_ROTATION); 42 | tft->fillScreen(ARCADA_TFT_DEFAULTFILL); 43 | uint8_t rtna = 44 | 0x01; // Screen refresh rate control (datasheet 9.2.18, FRCTRL2) 45 | tft->sendCommand(0xC6, &rtna, 1); 46 | tft->setSPISpeed(50000000); // yes fast 47 | display = tft; 48 | } 49 | 50 | uint32_t variantReadButtons(void) { return 0; } 51 | 52 | private: 53 | }; 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /extras/Adafruit_Arcada_ItsyBitsyM4.h: -------------------------------------------------------------------------------- 1 | #if defined(ADAFRUIT_ITSYBITSY_M4_EXPRESS) 2 | // INCLUDE ONLY **ONE** OF THESE DISPLAY TYPES: 3 | #include // Round 240 pixel diameter TFT 4 | // #include // Square 240x240 TFT 5 | // #include // Rectangular 320x240 TFT 6 | #include "wiring_private.h" 7 | #include 8 | 9 | #define TWO_DISPLAYS 10 | 11 | #define ARCADA_TFT_SPI SPI 12 | #define ARCADA_TFT_DC A5 13 | #define ARCADA_TFT_CS A4 14 | #define ARCADA_TFT_RST -1 15 | // #define ARCADA_TFT_LITE 47 16 | #define ARCADA_TFT_ROTATION 1 17 | #define ARCADA_TFT_DEFAULTFILL 0xFFFF 18 | #if defined(_ADAFRUIT_ILI9341H_) 19 | #define ARCADA_TFT_WIDTH 320 20 | #else 21 | #define ARCADA_TFT_WIDTH 240 22 | #endif 23 | #define ARCADA_TFT_HEIGHT 240 24 | 25 | #if defined(TWO_DISPLAYS) 26 | // SECOND DISPLAY ON SEPARATE SPI BUS: 27 | #if defined(GLOBAL_VAR) 28 | // SPI is on sercom0, I2C on sercom1, 2-5 are available 29 | // Sercom3 is normally serial1 but let use it for 2nd SPI 30 | // 0 and 1 are RX, TX respectively - PORTA16, 17 31 | // sercom_alts are SERCOM3/PAD1 and SERCOM3/PAD0 32 | // This puts MOSI on TX, SCK on RX 33 | SPIClass SPI1(&sercom3, 0, 1, 2, SPI_PAD_0_SCK_1, SERCOM_RX_PAD_3); 34 | #else 35 | extern SPIClass SPI1; 36 | #endif 37 | #define ARCADA_LEFTTFT_SPI SPI1 38 | #define ARCADA_LEFTTFT_DC 9 39 | #define ARCADA_LEFTTFT_CS 7 40 | #define ARCADA_LEFTTFT_RST -1 41 | #endif // end TWO_DISPLAYS 42 | 43 | #define TFT_RESET 2 // Used for BOTH displays 44 | 45 | #define ARCADA_AUDIO_OUT A0 46 | 47 | #define ARCADA_CALLBACKTIMER 4 48 | #define ARCADA_CALLBACKTIMER_HANDLER TC4_Handler 49 | 50 | #define ARCADA_USE_JSON 51 | 52 | #include "arcadatype.h" 53 | 54 | class Adafruit_Arcada : public Adafruit_Arcada_SPITFT { 55 | public: 56 | Adafruit_Arcada(void) { _has_accel = false; }; 57 | #if defined(_ADAFRUIT_ST7789H_) 58 | Adafruit_ST7789 *_display, *display2; 59 | #elif defined(_ADAFRUIT_ILI9341H_) 60 | Adafruit_ILI9341 *_display, *display2; 61 | #else 62 | Adafruit_GC9A01A *_display, *display2; 63 | #endif 64 | 65 | bool variantBegin(void) { 66 | Adafruit_DotStar dot = Adafruit_DotStar(1, 8, 6); 67 | dot.show(); // Turn off DotStar 68 | return true; 69 | } 70 | 71 | void displayBegin(void) { 72 | // Hard reset both displays 73 | pinMode(TFT_RESET, OUTPUT); 74 | digitalWrite(TFT_RESET, LOW); 75 | delay(10); 76 | digitalWrite(TFT_RESET, HIGH); 77 | delay(10); 78 | 79 | // IMPORTANT: CS and DC are different order among displays 80 | #if defined(_ADAFRUIT_ST7789H_) 81 | _display = new Adafruit_ST7789(&ARCADA_TFT_SPI, ARCADA_TFT_CS, 82 | ARCADA_TFT_DC, ARCADA_TFT_RST); 83 | _display->init(240, 240); 84 | #elif defined(_ADAFRUIT_ILI9341H_) 85 | _display = new Adafruit_ILI9341(&ARCADA_TFT_SPI, ARCADA_TFT_DC, 86 | ARCADA_TFT_CS, ARCADA_TFT_RST); 87 | _display->begin(); 88 | #else 89 | uint8_t rtna = 0x01; // Screen refresh rate control 90 | _display = new Adafruit_GC9A01A(&ARCADA_TFT_SPI, ARCADA_TFT_DC, 91 | ARCADA_TFT_CS, ARCADA_TFT_RST); 92 | _display->begin(); 93 | _display->sendCommand(0xC6, &rtna, 1); // Helps contrast a little 94 | #endif 95 | _display->setSPISpeed(50000000); // yes fast 96 | _display->setRotation(ARCADA_TFT_ROTATION); 97 | _display->fillScreen(ARCADA_TFT_DEFAULTFILL); 98 | 99 | #if defined(ARCADA_LEFTTFT_SPI) 100 | pinPeripheral(0, PIO_SERCOM_ALT); // Enable SPI1 on RX, TX 101 | pinPeripheral(1, PIO_SERCOM_ALT); 102 | // IMPORTANT: CS and DC are different order among displays 103 | #if defined(_ADAFRUIT_ST7789H_) 104 | display2 = new Adafruit_ST7789(&ARCADA_LEFTTFT_SPI, ARCADA_LEFTTFT_CS, 105 | ARCADA_LEFTTFT_DC, ARCADA_LEFTTFT_RST); 106 | display2->init(240, 240); 107 | #elif defined(_ADAFRUIT_ILI9341H_) 108 | display2 = new Adafruit_ILI9341(&ARCADA_LEFTTFT_SPI, ARCADA_LEFTTFT_DC, 109 | ARCADA_LEFTTFT_CS, ARCADA_LEFTTFT_RST); 110 | display2->begin(); 111 | #else 112 | display2 = new Adafruit_GC9A01A(&ARCADA_LEFTTFT_SPI, ARCADA_LEFTTFT_DC, 113 | ARCADA_LEFTTFT_CS, ARCADA_LEFTTFT_RST); 114 | display2->begin(); 115 | display2->sendCommand(0xC6, &rtna, 1); // Helps contrast a little 116 | #endif 117 | display2->setSPISpeed(50000000); 118 | display2->setRotation(ARCADA_TFT_ROTATION); 119 | display2->fillScreen(ARCADA_TFT_DEFAULTFILL); 120 | #endif 121 | 122 | display = _display; 123 | } 124 | 125 | uint32_t variantReadButtons(void) { return 0; } 126 | 127 | private: 128 | }; 129 | 130 | #endif 131 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=Adafruit GC9A01A 2 | version=1.1.1 3 | author=Adafruit 4 | maintainer=Adafruit 5 | sentence=Library for GC9A01A displays 6 | paragraph=Library for GC9A01A displays 7 | category=Display 8 | url=https://github.com/Adafruit/Adafruit_GC9A01A 9 | architectures=* 10 | depends=Adafruit GFX Library 11 | --------------------------------------------------------------------------------