Adafruit_SPITFT.cpp (95650B)
1 /*! 2 * @file Adafruit_SPITFT.cpp 3 * 4 * @mainpage Adafruit SPI TFT Displays (and some others) 5 * 6 * @section intro_sec Introduction 7 * 8 * Part of Adafruit's GFX graphics library. Originally this class was 9 * written to handle a range of color TFT displays connected via SPI, 10 * but over time this library and some display-specific subclasses have 11 * mutated to include some color OLEDs as well as parallel-interfaced 12 * displays. The name's been kept for the sake of older code. 13 * 14 * Adafruit invests time and resources providing this open source code, 15 * please support Adafruit and open-source hardware by purchasing 16 * products from Adafruit! 17 18 * @section dependencies Dependencies 19 * 20 * This library depends on <a href="https://github.com/adafruit/Adafruit_GFX"> 21 * Adafruit_GFX</a> being present on your system. Please make sure you have 22 * installed the latest version before using this library. 23 * 24 * @section author Author 25 * 26 * Written by Limor "ladyada" Fried for Adafruit Industries, 27 * with contributions from the open source community. 28 * 29 * @section license License 30 * 31 * BSD license, all text here must be included in any redistribution. 32 */ 33 34 #if !defined(__AVR_ATtiny85__) // Not for ATtiny, at all 35 36 #include "Adafruit_SPITFT.h" 37 38 #if defined(__AVR__) 39 #if defined(__AVR_XMEGA__) // only tested with __AVR_ATmega4809__ 40 #define AVR_WRITESPI(x) \ 41 for (SPI0_DATA = (x); (!(SPI0_INTFLAGS & _BV(SPI_IF_bp)));) 42 #else 43 #define AVR_WRITESPI(x) for (SPDR = (x); (!(SPSR & _BV(SPIF)));) 44 #endif 45 #endif 46 47 #if defined(PORT_IOBUS) 48 // On SAMD21, redefine digitalPinToPort() to use the slightly-faster 49 // PORT_IOBUS rather than PORT (not needed on SAMD51). 50 #undef digitalPinToPort 51 #define digitalPinToPort(P) (&(PORT_IOBUS->Group[g_APinDescription[P].ulPort])) 52 #endif // end PORT_IOBUS 53 54 #if defined(USE_SPI_DMA) && (defined(__SAMD51__) || defined(ARDUINO_SAMD_ZERO)) 55 // #pragma message ("GFX DMA IS ENABLED. HIGHLY EXPERIMENTAL.") 56 #include "wiring_private.h" // pinPeripheral() function 57 #include <Adafruit_ZeroDMA.h> 58 #include <malloc.h> // memalign() function 59 #define tcNum 2 // Timer/Counter for parallel write strobe PWM 60 #define wrPeripheral PIO_CCL // Use CCL to invert write strobe 61 62 // DMA transfer-in-progress indicator and callback 63 static volatile bool dma_busy = false; 64 static void dma_callback(Adafruit_ZeroDMA *dma) { dma_busy = false; } 65 66 #if defined(__SAMD51__) 67 // Timer/counter info by index # 68 static const struct { 69 Tc *tc; // -> Timer/Counter base address 70 int gclk; // GCLK ID 71 int evu; // EVSYS user ID 72 } tcList[] = {{TC0, TC0_GCLK_ID, EVSYS_ID_USER_TC0_EVU}, 73 {TC1, TC1_GCLK_ID, EVSYS_ID_USER_TC1_EVU}, 74 {TC2, TC2_GCLK_ID, EVSYS_ID_USER_TC2_EVU}, 75 {TC3, TC3_GCLK_ID, EVSYS_ID_USER_TC3_EVU}, 76 #if defined(TC4) 77 {TC4, TC4_GCLK_ID, EVSYS_ID_USER_TC4_EVU}, 78 #endif 79 #if defined(TC5) 80 {TC5, TC5_GCLK_ID, EVSYS_ID_USER_TC5_EVU}, 81 #endif 82 #if defined(TC6) 83 {TC6, TC6_GCLK_ID, EVSYS_ID_USER_TC6_EVU}, 84 #endif 85 #if defined(TC7) 86 {TC7, TC7_GCLK_ID, EVSYS_ID_USER_TC7_EVU} 87 #endif 88 }; 89 #define NUM_TIMERS (sizeof tcList / sizeof tcList[0]) ///< # timer/counters 90 #endif // end __SAMD51__ 91 92 #endif // end USE_SPI_DMA 93 94 // Possible values for Adafruit_SPITFT.connection: 95 #define TFT_HARD_SPI 0 ///< Display interface = hardware SPI 96 #define TFT_SOFT_SPI 1 ///< Display interface = software SPI 97 #define TFT_PARALLEL 2 ///< Display interface = 8- or 16-bit parallel 98 99 // CONSTRUCTORS ------------------------------------------------------------ 100 101 /*! 102 @brief Adafruit_SPITFT constructor for software (bitbang) SPI. 103 @param w Display width in pixels at default rotation setting (0). 104 @param h Display height in pixels at default rotation setting (0). 105 @param cs Arduino pin # for chip-select (-1 if unused, tie CS low). 106 @param dc Arduino pin # for data/command select (required). 107 @param mosi Arduino pin # for bitbang SPI MOSI signal (required). 108 @param sck Arduino pin # for bitbang SPI SCK signal (required). 109 @param rst Arduino pin # for display reset (optional, display reset 110 can be tied to MCU reset, default of -1 means unused). 111 @param miso Arduino pin # for bitbang SPI MISO signal (optional, 112 -1 default, many displays don't support SPI read). 113 @note Output pins are not initialized; application typically will 114 need to call subclass' begin() function, which in turn calls 115 this library's initSPI() function to initialize pins. 116 */ 117 Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, int8_t cs, int8_t dc, 118 int8_t mosi, int8_t sck, int8_t rst, 119 int8_t miso) 120 : Adafruit_GFX(w, h), connection(TFT_SOFT_SPI), _rst(rst), _cs(cs), 121 _dc(dc) { 122 swspi._sck = sck; 123 swspi._mosi = mosi; 124 swspi._miso = miso; 125 #if defined(USE_FAST_PINIO) 126 #if defined(HAS_PORT_SET_CLR) 127 #if defined(CORE_TEENSY) 128 #if !defined(KINETISK) 129 dcPinMask = digitalPinToBitMask(dc); 130 swspi.sckPinMask = digitalPinToBitMask(sck); 131 swspi.mosiPinMask = digitalPinToBitMask(mosi); 132 #endif 133 dcPortSet = portSetRegister(dc); 134 dcPortClr = portClearRegister(dc); 135 swspi.sckPortSet = portSetRegister(sck); 136 swspi.sckPortClr = portClearRegister(sck); 137 swspi.mosiPortSet = portSetRegister(mosi); 138 swspi.mosiPortClr = portClearRegister(mosi); 139 if (cs >= 0) { 140 #if !defined(KINETISK) 141 csPinMask = digitalPinToBitMask(cs); 142 #endif 143 csPortSet = portSetRegister(cs); 144 csPortClr = portClearRegister(cs); 145 } else { 146 #if !defined(KINETISK) 147 csPinMask = 0; 148 #endif 149 csPortSet = dcPortSet; 150 csPortClr = dcPortClr; 151 } 152 if (miso >= 0) { 153 swspi.misoPort = portInputRegister(miso); 154 #if !defined(KINETISK) 155 swspi.misoPinMask = digitalPinToBitMask(miso); 156 #endif 157 } else { 158 swspi.misoPort = portInputRegister(dc); 159 } 160 #else // !CORE_TEENSY 161 dcPinMask = digitalPinToBitMask(dc); 162 swspi.sckPinMask = digitalPinToBitMask(sck); 163 swspi.mosiPinMask = digitalPinToBitMask(mosi); 164 dcPortSet = &(PORT->Group[g_APinDescription[dc].ulPort].OUTSET.reg); 165 dcPortClr = &(PORT->Group[g_APinDescription[dc].ulPort].OUTCLR.reg); 166 swspi.sckPortSet = &(PORT->Group[g_APinDescription[sck].ulPort].OUTSET.reg); 167 swspi.sckPortClr = &(PORT->Group[g_APinDescription[sck].ulPort].OUTCLR.reg); 168 swspi.mosiPortSet = &(PORT->Group[g_APinDescription[mosi].ulPort].OUTSET.reg); 169 swspi.mosiPortClr = &(PORT->Group[g_APinDescription[mosi].ulPort].OUTCLR.reg); 170 if (cs >= 0) { 171 csPinMask = digitalPinToBitMask(cs); 172 csPortSet = &(PORT->Group[g_APinDescription[cs].ulPort].OUTSET.reg); 173 csPortClr = &(PORT->Group[g_APinDescription[cs].ulPort].OUTCLR.reg); 174 } else { 175 // No chip-select line defined; might be permanently tied to GND. 176 // Assign a valid GPIO register (though not used for CS), and an 177 // empty pin bitmask...the nonsense bit-twiddling might be faster 178 // than checking _cs and possibly branching. 179 csPortSet = dcPortSet; 180 csPortClr = dcPortClr; 181 csPinMask = 0; 182 } 183 if (miso >= 0) { 184 swspi.misoPinMask = digitalPinToBitMask(miso); 185 swspi.misoPort = (PORTreg_t)portInputRegister(digitalPinToPort(miso)); 186 } else { 187 swspi.misoPinMask = 0; 188 swspi.misoPort = (PORTreg_t)portInputRegister(digitalPinToPort(dc)); 189 } 190 #endif // end !CORE_TEENSY 191 #else // !HAS_PORT_SET_CLR 192 dcPort = (PORTreg_t)portOutputRegister(digitalPinToPort(dc)); 193 dcPinMaskSet = digitalPinToBitMask(dc); 194 swspi.sckPort = (PORTreg_t)portOutputRegister(digitalPinToPort(sck)); 195 swspi.sckPinMaskSet = digitalPinToBitMask(sck); 196 swspi.mosiPort = (PORTreg_t)portOutputRegister(digitalPinToPort(mosi)); 197 swspi.mosiPinMaskSet = digitalPinToBitMask(mosi); 198 if (cs >= 0) { 199 csPort = (PORTreg_t)portOutputRegister(digitalPinToPort(cs)); 200 csPinMaskSet = digitalPinToBitMask(cs); 201 } else { 202 // No chip-select line defined; might be permanently tied to GND. 203 // Assign a valid GPIO register (though not used for CS), and an 204 // empty pin bitmask...the nonsense bit-twiddling might be faster 205 // than checking _cs and possibly branching. 206 csPort = dcPort; 207 csPinMaskSet = 0; 208 } 209 if (miso >= 0) { 210 swspi.misoPort = (PORTreg_t)portInputRegister(digitalPinToPort(miso)); 211 swspi.misoPinMask = digitalPinToBitMask(miso); 212 } else { 213 swspi.misoPort = (PORTreg_t)portInputRegister(digitalPinToPort(dc)); 214 swspi.misoPinMask = 0; 215 } 216 csPinMaskClr = ~csPinMaskSet; 217 dcPinMaskClr = ~dcPinMaskSet; 218 swspi.sckPinMaskClr = ~swspi.sckPinMaskSet; 219 swspi.mosiPinMaskClr = ~swspi.mosiPinMaskSet; 220 #endif // !end HAS_PORT_SET_CLR 221 #endif // end USE_FAST_PINIO 222 } 223 224 /*! 225 @brief Adafruit_SPITFT constructor for hardware SPI using the board's 226 default SPI peripheral. 227 @param w Display width in pixels at default rotation setting (0). 228 @param h Display height in pixels at default rotation setting (0). 229 @param cs Arduino pin # for chip-select (-1 if unused, tie CS low). 230 @param dc Arduino pin # for data/command select (required). 231 @param rst Arduino pin # for display reset (optional, display reset 232 can be tied to MCU reset, default of -1 means unused). 233 @note Output pins are not initialized; application typically will 234 need to call subclass' begin() function, which in turn calls 235 this library's initSPI() function to initialize pins. 236 */ 237 #if defined(ESP8266) // See notes below 238 Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, int8_t cs, int8_t dc, 239 int8_t rst) 240 : Adafruit_GFX(w, h), connection(TFT_HARD_SPI), _rst(rst), _cs(cs), 241 _dc(dc) { 242 hwspi._spi = &SPI; 243 } 244 #else // !ESP8266 245 Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, int8_t cs, int8_t dc, 246 int8_t rst) 247 : Adafruit_SPITFT(w, h, &SPI, cs, dc, rst) { 248 // This just invokes the hardware SPI constructor below, 249 // passing the default SPI device (&SPI). 250 } 251 #endif // end !ESP8266 252 253 #if !defined(ESP8266) 254 // ESP8266 compiler freaks out at this constructor -- it can't disambiguate 255 // beteween the SPIClass pointer (argument #3) and a regular integer. 256 // Solution here it to just not offer this variant on the ESP8266. You can 257 // use the default hardware SPI peripheral, or you can use software SPI, 258 // but if there's any library out there that creates a 'virtual' SPIClass 259 // peripheral and drives it with software bitbanging, that's not supported. 260 /*! 261 @brief Adafruit_SPITFT constructor for hardware SPI using a specific 262 SPI peripheral. 263 @param w Display width in pixels at default rotation (0). 264 @param h Display height in pixels at default rotation (0). 265 @param spiClass Pointer to SPIClass type (e.g. &SPI or &SPI1). 266 @param cs Arduino pin # for chip-select (-1 if unused, tie CS low). 267 @param dc Arduino pin # for data/command select (required). 268 @param rst Arduino pin # for display reset (optional, display reset 269 can be tied to MCU reset, default of -1 means unused). 270 @note Output pins are not initialized in constructor; application 271 typically will need to call subclass' begin() function, which 272 in turn calls this library's initSPI() function to initialize 273 pins. EXCEPT...if you have built your own SERCOM SPI peripheral 274 (calling the SPIClass constructor) rather than one of the 275 built-in SPI devices (e.g. &SPI, &SPI1 and so forth), you will 276 need to call the begin() function for your object as well as 277 pinPeripheral() for the MOSI, MISO and SCK pins to configure 278 GPIO manually. Do this BEFORE calling the display-specific 279 begin or init function. Unfortunate but unavoidable. 280 */ 281 Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, SPIClass *spiClass, 282 int8_t cs, int8_t dc, int8_t rst) 283 : Adafruit_GFX(w, h), connection(TFT_HARD_SPI), _rst(rst), _cs(cs), 284 _dc(dc) { 285 hwspi._spi = spiClass; 286 #if defined(USE_FAST_PINIO) 287 #if defined(HAS_PORT_SET_CLR) 288 #if defined(CORE_TEENSY) 289 #if !defined(KINETISK) 290 dcPinMask = digitalPinToBitMask(dc); 291 #endif 292 dcPortSet = portSetRegister(dc); 293 dcPortClr = portClearRegister(dc); 294 if (cs >= 0) { 295 #if !defined(KINETISK) 296 csPinMask = digitalPinToBitMask(cs); 297 #endif 298 csPortSet = portSetRegister(cs); 299 csPortClr = portClearRegister(cs); 300 } else { // see comments below 301 #if !defined(KINETISK) 302 csPinMask = 0; 303 #endif 304 csPortSet = dcPortSet; 305 csPortClr = dcPortClr; 306 } 307 #else // !CORE_TEENSY 308 dcPinMask = digitalPinToBitMask(dc); 309 dcPortSet = &(PORT->Group[g_APinDescription[dc].ulPort].OUTSET.reg); 310 dcPortClr = &(PORT->Group[g_APinDescription[dc].ulPort].OUTCLR.reg); 311 if (cs >= 0) { 312 csPinMask = digitalPinToBitMask(cs); 313 csPortSet = &(PORT->Group[g_APinDescription[cs].ulPort].OUTSET.reg); 314 csPortClr = &(PORT->Group[g_APinDescription[cs].ulPort].OUTCLR.reg); 315 } else { 316 // No chip-select line defined; might be permanently tied to GND. 317 // Assign a valid GPIO register (though not used for CS), and an 318 // empty pin bitmask...the nonsense bit-twiddling might be faster 319 // than checking _cs and possibly branching. 320 csPortSet = dcPortSet; 321 csPortClr = dcPortClr; 322 csPinMask = 0; 323 } 324 #endif // end !CORE_TEENSY 325 #else // !HAS_PORT_SET_CLR 326 dcPort = (PORTreg_t)portOutputRegister(digitalPinToPort(dc)); 327 dcPinMaskSet = digitalPinToBitMask(dc); 328 if (cs >= 0) { 329 csPort = (PORTreg_t)portOutputRegister(digitalPinToPort(cs)); 330 csPinMaskSet = digitalPinToBitMask(cs); 331 } else { 332 // No chip-select line defined; might be permanently tied to GND. 333 // Assign a valid GPIO register (though not used for CS), and an 334 // empty pin bitmask...the nonsense bit-twiddling might be faster 335 // than checking _cs and possibly branching. 336 csPort = dcPort; 337 csPinMaskSet = 0; 338 } 339 csPinMaskClr = ~csPinMaskSet; 340 dcPinMaskClr = ~dcPinMaskSet; 341 #endif // end !HAS_PORT_SET_CLR 342 #endif // end USE_FAST_PINIO 343 } 344 #endif // end !ESP8266 345 346 /*! 347 @brief Adafruit_SPITFT constructor for parallel display connection. 348 @param w Display width in pixels at default rotation (0). 349 @param h Display height in pixels at default rotation (0). 350 @param busWidth If tft16 (enumeration in header file), is a 16-bit 351 parallel connection, else 8-bit. 352 16-bit isn't fully implemented or tested yet so 353 applications should pass "tft8bitbus" for now...needed to 354 stick a required enum argument in there to 355 disambiguate this constructor from the soft-SPI case. 356 Argument is ignored on 8-bit architectures (no 'wide' 357 support there since PORTs are 8 bits anyway). 358 @param d0 Arduino pin # for data bit 0 (1+ are extrapolated). 359 The 8 (or 16) data bits MUST be contiguous and byte- 360 aligned (or word-aligned for wide interface) within 361 the same PORT register (might not correspond to 362 Arduino pin sequence). 363 @param wr Arduino pin # for write strobe (required). 364 @param dc Arduino pin # for data/command select (required). 365 @param cs Arduino pin # for chip-select (optional, -1 if unused, 366 tie CS low). 367 @param rst Arduino pin # for display reset (optional, display reset 368 can be tied to MCU reset, default of -1 means unused). 369 @param rd Arduino pin # for read strobe (optional, -1 if unused). 370 @note Output pins are not initialized; application typically will need 371 to call subclass' begin() function, which in turn calls this 372 library's initSPI() function to initialize pins. 373 Yes, the name is a misnomer...this library originally handled 374 only SPI displays, parallel being a recent addition (but not 375 wanting to break existing code). 376 */ 377 Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, tftBusWidth busWidth, 378 int8_t d0, int8_t wr, int8_t dc, int8_t cs, 379 int8_t rst, int8_t rd) 380 : Adafruit_GFX(w, h), connection(TFT_PARALLEL), _rst(rst), _cs(cs), 381 _dc(dc) { 382 tft8._d0 = d0; 383 tft8._wr = wr; 384 tft8._rd = rd; 385 tft8.wide = (busWidth == tft16bitbus); 386 #if defined(USE_FAST_PINIO) 387 #if defined(HAS_PORT_SET_CLR) 388 #if defined(CORE_TEENSY) 389 tft8.wrPortSet = portSetRegister(wr); 390 tft8.wrPortClr = portClearRegister(wr); 391 #if !defined(KINETISK) 392 dcPinMask = digitalPinToBitMask(dc); 393 #endif 394 dcPortSet = portSetRegister(dc); 395 dcPortClr = portClearRegister(dc); 396 if (cs >= 0) { 397 #if !defined(KINETISK) 398 csPinMask = digitalPinToBitMask(cs); 399 #endif 400 csPortSet = portSetRegister(cs); 401 csPortClr = portClearRegister(cs); 402 } else { // see comments below 403 #if !defined(KINETISK) 404 csPinMask = 0; 405 #endif 406 csPortSet = dcPortSet; 407 csPortClr = dcPortClr; 408 } 409 if (rd >= 0) { // if read-strobe pin specified... 410 #if defined(KINETISK) 411 tft8.rdPinMask = 1; 412 #else // !KINETISK 413 tft8.rdPinMask = digitalPinToBitMask(rd); 414 #endif 415 tft8.rdPortSet = portSetRegister(rd); 416 tft8.rdPortClr = portClearRegister(rd); 417 } else { 418 tft8.rdPinMask = 0; 419 tft8.rdPortSet = dcPortSet; 420 tft8.rdPortClr = dcPortClr; 421 } 422 // These are all uint8_t* pointers -- elsewhere they're recast 423 // as necessary if a 'wide' 16-bit interface is in use. 424 tft8.writePort = portOutputRegister(d0); 425 tft8.readPort = portInputRegister(d0); 426 tft8.dirSet = portModeRegister(d0); 427 tft8.dirClr = portModeRegister(d0); 428 #else // !CORE_TEENSY 429 tft8.wrPinMask = digitalPinToBitMask(wr); 430 tft8.wrPortSet = &(PORT->Group[g_APinDescription[wr].ulPort].OUTSET.reg); 431 tft8.wrPortClr = &(PORT->Group[g_APinDescription[wr].ulPort].OUTCLR.reg); 432 dcPinMask = digitalPinToBitMask(dc); 433 dcPortSet = &(PORT->Group[g_APinDescription[dc].ulPort].OUTSET.reg); 434 dcPortClr = &(PORT->Group[g_APinDescription[dc].ulPort].OUTCLR.reg); 435 if (cs >= 0) { 436 csPinMask = digitalPinToBitMask(cs); 437 csPortSet = &(PORT->Group[g_APinDescription[cs].ulPort].OUTSET.reg); 438 csPortClr = &(PORT->Group[g_APinDescription[cs].ulPort].OUTCLR.reg); 439 } else { 440 // No chip-select line defined; might be permanently tied to GND. 441 // Assign a valid GPIO register (though not used for CS), and an 442 // empty pin bitmask...the nonsense bit-twiddling might be faster 443 // than checking _cs and possibly branching. 444 csPortSet = dcPortSet; 445 csPortClr = dcPortClr; 446 csPinMask = 0; 447 } 448 if (rd >= 0) { // if read-strobe pin specified... 449 tft8.rdPinMask = digitalPinToBitMask(rd); 450 tft8.rdPortSet = &(PORT->Group[g_APinDescription[rd].ulPort].OUTSET.reg); 451 tft8.rdPortClr = &(PORT->Group[g_APinDescription[rd].ulPort].OUTCLR.reg); 452 } else { 453 tft8.rdPinMask = 0; 454 tft8.rdPortSet = dcPortSet; 455 tft8.rdPortClr = dcPortClr; 456 } 457 // Get pointers to PORT write/read/dir bytes within 32-bit PORT 458 uint8_t dBit = g_APinDescription[d0].ulPin; // d0 bit # in PORT 459 PortGroup *p = (&(PORT->Group[g_APinDescription[d0].ulPort])); 460 uint8_t offset = dBit / 8; // d[7:0] byte # within PORT 461 if (tft8.wide) 462 offset &= ~1; // d[15:8] byte # within PORT 463 // These are all uint8_t* pointers -- elsewhere they're recast 464 // as necessary if a 'wide' 16-bit interface is in use. 465 tft8.writePort = (volatile uint8_t *)&(p->OUT.reg) + offset; 466 tft8.readPort = (volatile uint8_t *)&(p->IN.reg) + offset; 467 tft8.dirSet = (volatile uint8_t *)&(p->DIRSET.reg) + offset; 468 tft8.dirClr = (volatile uint8_t *)&(p->DIRCLR.reg) + offset; 469 #endif // end !CORE_TEENSY 470 #else // !HAS_PORT_SET_CLR 471 tft8.wrPort = (PORTreg_t)portOutputRegister(digitalPinToPort(wr)); 472 tft8.wrPinMaskSet = digitalPinToBitMask(wr); 473 dcPort = (PORTreg_t)portOutputRegister(digitalPinToPort(dc)); 474 dcPinMaskSet = digitalPinToBitMask(dc); 475 if (cs >= 0) { 476 csPort = (PORTreg_t)portOutputRegister(digitalPinToPort(cs)); 477 csPinMaskSet = digitalPinToBitMask(cs); 478 } else { 479 // No chip-select line defined; might be permanently tied to GND. 480 // Assign a valid GPIO register (though not used for CS), and an 481 // empty pin bitmask...the nonsense bit-twiddling might be faster 482 // than checking _cs and possibly branching. 483 csPort = dcPort; 484 csPinMaskSet = 0; 485 } 486 if (rd >= 0) { // if read-strobe pin specified... 487 tft8.rdPort = (PORTreg_t)portOutputRegister(digitalPinToPort(rd)); 488 tft8.rdPinMaskSet = digitalPinToBitMask(rd); 489 } else { 490 tft8.rdPort = dcPort; 491 tft8.rdPinMaskSet = 0; 492 } 493 csPinMaskClr = ~csPinMaskSet; 494 dcPinMaskClr = ~dcPinMaskSet; 495 tft8.wrPinMaskClr = ~tft8.wrPinMaskSet; 496 tft8.rdPinMaskClr = ~tft8.rdPinMaskSet; 497 tft8.writePort = (PORTreg_t)portOutputRegister(digitalPinToPort(d0)); 498 tft8.readPort = (PORTreg_t)portInputRegister(digitalPinToPort(d0)); 499 tft8.portDir = (PORTreg_t)portModeRegister(digitalPinToPort(d0)); 500 #endif // end !HAS_PORT_SET_CLR 501 #endif // end USE_FAST_PINIO 502 } 503 504 // end constructors ------- 505 506 // CLASS MEMBER FUNCTIONS -------------------------------------------------- 507 508 // begin() and setAddrWindow() MUST be declared by any subclass. 509 510 /*! 511 @brief Configure microcontroller pins for TFT interfacing. Typically 512 called by a subclass' begin() function. 513 @param freq SPI frequency when using hardware SPI. If default (0) 514 is passed, will fall back on a device-specific value. 515 Value is ignored when using software SPI or parallel 516 connection. 517 @param spiMode SPI mode when using hardware SPI. MUST be one of the 518 values SPI_MODE0, SPI_MODE1, SPI_MODE2 or SPI_MODE3 519 defined in SPI.h. Do NOT attempt to pass '0' for 520 SPI_MODE0 and so forth...the values are NOT the same! 521 Use ONLY the defines! (Pity it's not an enum.) 522 @note Another anachronistically-named function; this is called even 523 when the display connection is parallel (not SPI). Also, this 524 could probably be made private...quite a few class functions 525 were generously put in the public section. 526 */ 527 void Adafruit_SPITFT::initSPI(uint32_t freq, uint8_t spiMode) { 528 529 if (!freq) 530 freq = DEFAULT_SPI_FREQ; // If no freq specified, use default 531 532 // Init basic control pins common to all connection types 533 if (_cs >= 0) { 534 pinMode(_cs, OUTPUT); 535 digitalWrite(_cs, HIGH); // Deselect 536 } 537 pinMode(_dc, OUTPUT); 538 digitalWrite(_dc, HIGH); // Data mode 539 540 if (connection == TFT_HARD_SPI) { 541 542 #if defined(SPI_HAS_TRANSACTION) 543 hwspi.settings = SPISettings(freq, MSBFIRST, spiMode); 544 #else 545 hwspi._freq = freq; // Save freq value for later 546 #endif 547 hwspi._mode = spiMode; // Save spiMode value for later 548 // Call hwspi._spi->begin() ONLY if this is among the 'established' 549 // SPI interfaces in variant.h. For DIY roll-your-own SERCOM SPIs, 550 // begin() and pinPeripheral() calls MUST be made in one's calling 551 // code, BEFORE the screen-specific begin/init function is called. 552 // Reason for this is that SPI::begin() makes its own calls to 553 // pinPeripheral() based on g_APinDescription[n].ulPinType, which 554 // on non-established SPI interface pins will always be PIO_DIGITAL 555 // or similar, while we need PIO_SERCOM or PIO_SERCOM_ALT...it's 556 // highly unique between devices and variants for each pin or 557 // SERCOM so we can't make those calls ourselves here. And the SPI 558 // device needs to be set up before calling this because it's 559 // immediately followed with initialization commands. Blargh. 560 if ( 561 #if !defined(SPI_INTERFACES_COUNT) 562 1 563 #endif 564 #if SPI_INTERFACES_COUNT > 0 565 (hwspi._spi == &SPI) 566 #endif 567 #if SPI_INTERFACES_COUNT > 1 568 || (hwspi._spi == &SPI1) 569 #endif 570 #if SPI_INTERFACES_COUNT > 2 571 || (hwspi._spi == &SPI2) 572 #endif 573 #if SPI_INTERFACES_COUNT > 3 574 || (hwspi._spi == &SPI3) 575 #endif 576 #if SPI_INTERFACES_COUNT > 4 577 || (hwspi._spi == &SPI4) 578 #endif 579 #if SPI_INTERFACES_COUNT > 5 580 || (hwspi._spi == &SPI5) 581 #endif 582 ) { 583 hwspi._spi->begin(); 584 } 585 } else if (connection == TFT_SOFT_SPI) { 586 587 pinMode(swspi._mosi, OUTPUT); 588 digitalWrite(swspi._mosi, LOW); 589 pinMode(swspi._sck, OUTPUT); 590 digitalWrite(swspi._sck, LOW); 591 if (swspi._miso >= 0) { 592 pinMode(swspi._miso, INPUT); 593 } 594 595 } else { // TFT_PARALLEL 596 // Initialize data pins. We were only passed d0, so scan 597 // the pin description list looking for the other pins. 598 // They'll be on the same PORT, and within the next 7 (or 15) bits 599 // (because we need to write to a contiguous PORT byte or word). 600 #if defined(__AVR__) 601 // PORT registers are 8 bits wide, so just need a register match... 602 for (uint8_t i = 0; i < NUM_DIGITAL_PINS; i++) { 603 if ((PORTreg_t)portOutputRegister(digitalPinToPort(i)) == 604 tft8.writePort) { 605 pinMode(i, OUTPUT); 606 digitalWrite(i, LOW); 607 } 608 } 609 #elif defined(USE_FAST_PINIO) 610 #if defined(CORE_TEENSY) 611 if (!tft8.wide) { 612 *tft8.dirSet = 0xFF; // Set port to output 613 *tft8.writePort = 0x00; // Write all 0s 614 } else { 615 *(volatile uint16_t *)tft8.dirSet = 0xFFFF; 616 *(volatile uint16_t *)tft8.writePort = 0x0000; 617 } 618 #else // !CORE_TEENSY 619 uint8_t portNum = g_APinDescription[tft8._d0].ulPort, // d0 PORT # 620 dBit = g_APinDescription[tft8._d0].ulPin, // d0 bit in PORT 621 lastBit = dBit + (tft8.wide ? 15 : 7); 622 for (uint8_t i = 0; i < PINS_COUNT; i++) { 623 if ((g_APinDescription[i].ulPort == portNum) && 624 (g_APinDescription[i].ulPin >= dBit) && 625 (g_APinDescription[i].ulPin <= (uint32_t)lastBit)) { 626 pinMode(i, OUTPUT); 627 digitalWrite(i, LOW); 628 } 629 } 630 #endif // end !CORE_TEENSY 631 #endif 632 pinMode(tft8._wr, OUTPUT); 633 digitalWrite(tft8._wr, HIGH); 634 if (tft8._rd >= 0) { 635 pinMode(tft8._rd, OUTPUT); 636 digitalWrite(tft8._rd, HIGH); 637 } 638 } 639 640 if (_rst >= 0) { 641 // Toggle _rst low to reset 642 pinMode(_rst, OUTPUT); 643 digitalWrite(_rst, HIGH); 644 delay(100); 645 digitalWrite(_rst, LOW); 646 delay(100); 647 digitalWrite(_rst, HIGH); 648 delay(200); 649 } 650 651 #if defined(USE_SPI_DMA) && (defined(__SAMD51__) || defined(ARDUINO_SAMD_ZERO)) 652 if (((connection == TFT_HARD_SPI) || (connection == TFT_PARALLEL)) && 653 (dma.allocate() == DMA_STATUS_OK)) { // Allocate channel 654 // The DMA library needs to alloc at least one valid descriptor, 655 // so we do that here. It's not used in the usual sense though, 656 // just before a transfer we copy descriptor[0] to this address. 657 if (dptr = dma.addDescriptor(NULL, NULL, 42, DMA_BEAT_SIZE_BYTE, false, 658 false)) { 659 // Alloc 2 scanlines worth of pixels on display's major axis, 660 // whichever that is, rounding each up to 2-pixel boundary. 661 int major = (WIDTH > HEIGHT) ? WIDTH : HEIGHT; 662 major += (major & 1); // -> next 2-pixel bound, if needed. 663 maxFillLen = major * 2; // 2 scanlines 664 // Note to future self: if you decide to make the pixel buffer 665 // much larger, remember that DMA transfer descriptors can't 666 // exceed 65,535 bytes (not 65,536), meaning 32,767 pixels max. 667 // Not that we have that kind of RAM to throw around right now. 668 if ((pixelBuf[0] = (uint16_t *)malloc(maxFillLen * sizeof(uint16_t)))) { 669 // Alloc OK. Get pointer to start of second scanline. 670 pixelBuf[1] = &pixelBuf[0][major]; 671 // Determine number of DMA descriptors needed to cover 672 // entire screen when entire 2-line pixelBuf is used 673 // (round up for fractional last descriptor). 674 int numDescriptors = (WIDTH * HEIGHT + (maxFillLen - 1)) / maxFillLen; 675 // DMA descriptors MUST be 128-bit (16 byte) aligned. 676 // memalign() is considered obsolete but it's replacements 677 // (aligned_alloc() or posix_memalign()) are not currently 678 // available in the version of ARM GCC in use, but this 679 // is, so here we are. 680 if ((descriptor = (DmacDescriptor *)memalign( 681 16, numDescriptors * sizeof(DmacDescriptor)))) { 682 int dmac_id; 683 volatile uint32_t *data_reg; 684 685 if (connection == TFT_HARD_SPI) { 686 // THIS IS AN AFFRONT TO NATURE, but I don't know 687 // any "clean" way to get the sercom number from the 688 // the SPIClass pointer (e.g. &SPI or &SPI1), which 689 // is all we have to work with. SPIClass does contain 690 // a SERCOM pointer but it is a PRIVATE member! 691 // Doing an UNSPEAKABLY HORRIBLE THING here, directly 692 // accessing the first 32-bit value in the SPIClass 693 // structure, knowing that's (currently) where the 694 // SERCOM pointer lives, but this ENTIRELY DEPENDS on 695 // that structure not changing nor the compiler 696 // rearranging things. Oh the humanity! 697 698 if (*(SERCOM **)hwspi._spi == &sercom0) { 699 dmac_id = SERCOM0_DMAC_ID_TX; 700 data_reg = &SERCOM0->SPI.DATA.reg; 701 #if defined SERCOM1 702 } else if (*(SERCOM **)hwspi._spi == &sercom1) { 703 dmac_id = SERCOM1_DMAC_ID_TX; 704 data_reg = &SERCOM1->SPI.DATA.reg; 705 #endif 706 #if defined SERCOM2 707 } else if (*(SERCOM **)hwspi._spi == &sercom2) { 708 dmac_id = SERCOM2_DMAC_ID_TX; 709 data_reg = &SERCOM2->SPI.DATA.reg; 710 #endif 711 #if defined SERCOM3 712 } else if (*(SERCOM **)hwspi._spi == &sercom3) { 713 dmac_id = SERCOM3_DMAC_ID_TX; 714 data_reg = &SERCOM3->SPI.DATA.reg; 715 #endif 716 #if defined SERCOM4 717 } else if (*(SERCOM **)hwspi._spi == &sercom4) { 718 dmac_id = SERCOM4_DMAC_ID_TX; 719 data_reg = &SERCOM4->SPI.DATA.reg; 720 #endif 721 #if defined SERCOM5 722 } else if (*(SERCOM **)hwspi._spi == &sercom5) { 723 dmac_id = SERCOM5_DMAC_ID_TX; 724 data_reg = &SERCOM5->SPI.DATA.reg; 725 #endif 726 #if defined SERCOM6 727 } else if (*(SERCOM **)hwspi._spi == &sercom6) { 728 dmac_id = SERCOM6_DMAC_ID_TX; 729 data_reg = &SERCOM6->SPI.DATA.reg; 730 #endif 731 #if defined SERCOM7 732 } else if (*(SERCOM **)hwspi._spi == &sercom7) { 733 dmac_id = SERCOM7_DMAC_ID_TX; 734 data_reg = &SERCOM7->SPI.DATA.reg; 735 #endif 736 } 737 dma.setPriority(DMA_PRIORITY_3); 738 dma.setTrigger(dmac_id); 739 dma.setAction(DMA_TRIGGER_ACTON_BEAT); 740 741 // Initialize descriptor list. 742 for (int d = 0; d < numDescriptors; d++) { 743 // No need to set SRCADDR, DESCADDR or BTCNT -- 744 // those are done in the pixel-writing functions. 745 descriptor[d].BTCTRL.bit.VALID = true; 746 descriptor[d].BTCTRL.bit.EVOSEL = DMA_EVENT_OUTPUT_DISABLE; 747 descriptor[d].BTCTRL.bit.BLOCKACT = DMA_BLOCK_ACTION_NOACT; 748 descriptor[d].BTCTRL.bit.BEATSIZE = DMA_BEAT_SIZE_BYTE; 749 descriptor[d].BTCTRL.bit.DSTINC = 0; 750 descriptor[d].BTCTRL.bit.STEPSEL = DMA_STEPSEL_SRC; 751 descriptor[d].BTCTRL.bit.STEPSIZE = 752 DMA_ADDRESS_INCREMENT_STEP_SIZE_1; 753 descriptor[d].DSTADDR.reg = (uint32_t)data_reg; 754 } 755 756 } else { // Parallel connection 757 758 #if defined(__SAMD51__) 759 int dmaChannel = dma.getChannel(); 760 // Enable event output, use EVOSEL output 761 DMAC->Channel[dmaChannel].CHEVCTRL.bit.EVOE = 1; 762 DMAC->Channel[dmaChannel].CHEVCTRL.bit.EVOMODE = 0; 763 764 // CONFIGURE TIMER/COUNTER (for write strobe) 765 766 Tc *timer = tcList[tcNum].tc; // -> Timer struct 767 int id = tcList[tcNum].gclk; // Timer GCLK ID 768 GCLK_PCHCTRL_Type pchctrl; 769 770 // Set up timer clock source from GCLK 771 GCLK->PCHCTRL[id].bit.CHEN = 0; // Stop timer 772 while (GCLK->PCHCTRL[id].bit.CHEN) 773 ; // Wait for it 774 pchctrl.bit.GEN = GCLK_PCHCTRL_GEN_GCLK0_Val; 775 pchctrl.bit.CHEN = 1; // Enable 776 GCLK->PCHCTRL[id].reg = pchctrl.reg; 777 while (!GCLK->PCHCTRL[id].bit.CHEN) 778 ; // Wait for it 779 780 // Disable timer/counter before configuring it 781 timer->COUNT8.CTRLA.bit.ENABLE = 0; 782 while (timer->COUNT8.SYNCBUSY.bit.STATUS) 783 ; 784 785 timer->COUNT8.WAVE.bit.WAVEGEN = 2; // NPWM 786 timer->COUNT8.CTRLA.bit.MODE = 1; // 8-bit 787 timer->COUNT8.CTRLA.bit.PRESCALER = 0; // 1:1 788 while (timer->COUNT8.SYNCBUSY.bit.STATUS) 789 ; 790 791 timer->COUNT8.CTRLBCLR.bit.DIR = 1; // Count UP 792 while (timer->COUNT8.SYNCBUSY.bit.CTRLB) 793 ; 794 timer->COUNT8.CTRLBSET.bit.ONESHOT = 1; // One-shot 795 while (timer->COUNT8.SYNCBUSY.bit.CTRLB) 796 ; 797 timer->COUNT8.PER.reg = 6; // PWM top 798 while (timer->COUNT8.SYNCBUSY.bit.PER) 799 ; 800 timer->COUNT8.CC[0].reg = 2; // Compare 801 while (timer->COUNT8.SYNCBUSY.bit.CC0) 802 ; 803 // Enable async input events, 804 // event action = restart. 805 timer->COUNT8.EVCTRL.bit.TCEI = 1; 806 timer->COUNT8.EVCTRL.bit.EVACT = 1; 807 808 // Enable timer 809 timer->COUNT8.CTRLA.reg |= TC_CTRLA_ENABLE; 810 while (timer->COUNT8.SYNCBUSY.bit.STATUS) 811 ; 812 813 #if (wrPeripheral == PIO_CCL) 814 // CONFIGURE CCL (inverts timer/counter output) 815 816 MCLK->APBCMASK.bit.CCL_ = 1; // Enable CCL clock 817 CCL->CTRL.bit.ENABLE = 0; // Disable to config 818 CCL->CTRL.bit.SWRST = 1; // Reset CCL registers 819 CCL->LUTCTRL[tcNum].bit.ENABLE = 0; // Disable LUT 820 CCL->LUTCTRL[tcNum].bit.FILTSEL = 0; // No filter 821 CCL->LUTCTRL[tcNum].bit.INSEL0 = 6; // TC input 822 CCL->LUTCTRL[tcNum].bit.INSEL1 = 0; // MASK 823 CCL->LUTCTRL[tcNum].bit.INSEL2 = 0; // MASK 824 CCL->LUTCTRL[tcNum].bit.TRUTH = 1; // Invert in 0 825 CCL->LUTCTRL[tcNum].bit.ENABLE = 1; // Enable LUT 826 CCL->CTRL.bit.ENABLE = 1; // Enable CCL 827 #endif 828 829 // CONFIGURE EVENT SYSTEM 830 831 // Set up event system clock source from GCLK... 832 // Disable EVSYS, wait for disable 833 GCLK->PCHCTRL[EVSYS_GCLK_ID_0].bit.CHEN = 0; 834 while (GCLK->PCHCTRL[EVSYS_GCLK_ID_0].bit.CHEN) 835 ; 836 pchctrl.bit.GEN = GCLK_PCHCTRL_GEN_GCLK0_Val; 837 pchctrl.bit.CHEN = 1; // Re-enable 838 GCLK->PCHCTRL[EVSYS_GCLK_ID_0].reg = pchctrl.reg; 839 // Wait for it, then enable EVSYS clock 840 while (!GCLK->PCHCTRL[EVSYS_GCLK_ID_0].bit.CHEN) 841 ; 842 MCLK->APBBMASK.bit.EVSYS_ = 1; 843 844 // Connect Timer EVU to ch 0 845 EVSYS->USER[tcList[tcNum].evu].reg = 1; 846 // Datasheet recommends single write operation; 847 // reg instead of bit. Also datasheet: PATH bits 848 // must be zero when using async! 849 EVSYS_CHANNEL_Type ev; 850 ev.reg = 0; 851 ev.bit.PATH = 2; // Asynchronous 852 ev.bit.EVGEN = 0x22 + dmaChannel; // DMA channel 0+ 853 EVSYS->Channel[0].CHANNEL.reg = ev.reg; 854 855 // Initialize descriptor list. 856 for (int d = 0; d < numDescriptors; d++) { 857 // No need to set SRCADDR, DESCADDR or BTCNT -- 858 // those are done in the pixel-writing functions. 859 descriptor[d].BTCTRL.bit.VALID = true; 860 // Event strobe on beat xfer: 861 descriptor[d].BTCTRL.bit.EVOSEL = 0x3; 862 descriptor[d].BTCTRL.bit.BLOCKACT = DMA_BLOCK_ACTION_NOACT; 863 descriptor[d].BTCTRL.bit.BEATSIZE = 864 tft8.wide ? DMA_BEAT_SIZE_HWORD : DMA_BEAT_SIZE_BYTE; 865 descriptor[d].BTCTRL.bit.SRCINC = 1; 866 descriptor[d].BTCTRL.bit.DSTINC = 0; 867 descriptor[d].BTCTRL.bit.STEPSEL = DMA_STEPSEL_SRC; 868 descriptor[d].BTCTRL.bit.STEPSIZE = 869 DMA_ADDRESS_INCREMENT_STEP_SIZE_1; 870 descriptor[d].DSTADDR.reg = (uint32_t)tft8.writePort; 871 } 872 #endif // __SAMD51 873 } // end parallel-specific DMA setup 874 875 lastFillColor = 0x0000; 876 lastFillLen = 0; 877 dma.setCallback(dma_callback); 878 return; // Success! 879 // else clean up any partial allocation... 880 } // end descriptor memalign() 881 free(pixelBuf[0]); 882 pixelBuf[0] = pixelBuf[1] = NULL; 883 } // end pixelBuf malloc() 884 // Don't currently have a descriptor delete function in 885 // ZeroDMA lib, but if we did, it would be called here. 886 } // end addDescriptor() 887 dma.free(); // Deallocate DMA channel 888 } 889 #endif // end USE_SPI_DMA 890 } 891 892 /*! 893 @brief Allow changing the SPI clock speed after initialization 894 @param freq Desired frequency of SPI clock, may not be the 895 end frequency you get based on what the chip can do! 896 */ 897 void Adafruit_SPITFT::setSPISpeed(uint32_t freq) { 898 #if defined(SPI_HAS_TRANSACTION) 899 hwspi.settings = SPISettings(freq, MSBFIRST, hwspi._mode); 900 #else 901 hwspi._freq = freq; // Save freq value for later 902 #endif 903 } 904 905 /*! 906 @brief Call before issuing command(s) or data to display. Performs 907 chip-select (if required) and starts an SPI transaction (if 908 using hardware SPI and transactions are supported). Required 909 for all display types; not an SPI-specific function. 910 */ 911 void Adafruit_SPITFT::startWrite(void) { 912 SPI_BEGIN_TRANSACTION(); 913 if (_cs >= 0) 914 SPI_CS_LOW(); 915 } 916 917 /*! 918 @brief Call after issuing command(s) or data to display. Performs 919 chip-deselect (if required) and ends an SPI transaction (if 920 using hardware SPI and transactions are supported). Required 921 for all display types; not an SPI-specific function. 922 */ 923 void Adafruit_SPITFT::endWrite(void) { 924 if (_cs >= 0) 925 SPI_CS_HIGH(); 926 SPI_END_TRANSACTION(); 927 } 928 929 // ------------------------------------------------------------------------- 930 // Lower-level graphics operations. These functions require a chip-select 931 // and/or SPI transaction around them (via startWrite(), endWrite() above). 932 // Higher-level graphics primitives might start a single transaction and 933 // then make multiple calls to these functions (e.g. circle or text 934 // rendering might make repeated lines or rects) before ending the 935 // transaction. It's more efficient than starting a transaction every time. 936 937 /*! 938 @brief Draw a single pixel to the display at requested coordinates. 939 Not self-contained; should follow a startWrite() call. 940 @param x Horizontal position (0 = left). 941 @param y Vertical position (0 = top). 942 @param color 16-bit pixel color in '565' RGB format. 943 */ 944 void Adafruit_SPITFT::writePixel(int16_t x, int16_t y, uint16_t color) { 945 if ((x >= 0) && (x < _width) && (y >= 0) && (y < _height)) { 946 setAddrWindow(x, y, 1, 1); 947 SPI_WRITE16(color); 948 } 949 } 950 951 /*! 952 @brief Issue a series of pixels from memory to the display. Not self- 953 contained; should follow startWrite() and setAddrWindow() calls. 954 @param colors Pointer to array of 16-bit pixel values in '565' RGB 955 format. 956 @param len Number of elements in 'colors' array. 957 @param block If true (default case if unspecified), function blocks 958 until DMA transfer is complete. This is simply IGNORED 959 if DMA is not enabled. If false, the function returns 960 immediately after the last DMA transfer is started, 961 and one should use the dmaWait() function before 962 doing ANY other display-related activities (or even 963 any SPI-related activities, if using an SPI display 964 that shares the bus with other devices). 965 @param bigEndian If using DMA, and if set true, bitmap in memory is in 966 big-endian order (most significant byte first). By 967 default this is false, as most microcontrollers seem 968 to be little-endian and 16-bit pixel values must be 969 byte-swapped before issuing to the display (which tend 970 to be big-endian when using SPI or 8-bit parallel). 971 If an application can optimize around this -- for 972 example, a bitmap in a uint16_t array having the byte 973 values already reordered big-endian, this can save 974 some processing time here, ESPECIALLY if using this 975 function's non-blocking DMA mode. Not all cases are 976 covered...this is really here only for SAMD DMA and 977 much forethought on the application side. 978 */ 979 void Adafruit_SPITFT::writePixels(uint16_t *colors, uint32_t len, bool block, 980 bool bigEndian) { 981 982 if (!len) 983 return; // Avoid 0-byte transfers 984 985 // avoid paramater-not-used complaints 986 (void)block; 987 (void)bigEndian; 988 989 #if defined(ESP32) // ESP32 has a special SPI pixel-writing function... 990 if (connection == TFT_HARD_SPI) { 991 hwspi._spi->writePixels(colors, len * 2); 992 return; 993 } 994 #elif defined(ARDUINO_NRF52_ADAFRUIT) && \ 995 defined(NRF52840_XXAA) // Adafruit nRF52 use SPIM3 DMA at 32Mhz 996 // TFT and SPI DMA endian is different we need to swap bytes 997 if (!bigEndian) { 998 for (uint32_t i = 0; i < len; i++) { 999 colors[i] = __builtin_bswap16(colors[i]); 1000 } 1001 } 1002 1003 // use the separate tx, rx buf variant to prevent overwrite the buffer 1004 hwspi._spi->transfer(colors, NULL, 2 * len); 1005 1006 // swap back color buffer 1007 if (!bigEndian) { 1008 for (uint32_t i = 0; i < len; i++) { 1009 colors[i] = __builtin_bswap16(colors[i]); 1010 } 1011 } 1012 1013 return; 1014 #elif defined(USE_SPI_DMA) && \ 1015 (defined(__SAMD51__) || defined(ARDUINO_SAMD_ZERO)) 1016 if ((connection == TFT_HARD_SPI) || (connection == TFT_PARALLEL)) { 1017 int maxSpan = maxFillLen / 2; // One scanline max 1018 uint8_t pixelBufIdx = 0; // Active pixel buffer number 1019 #if defined(__SAMD51__) 1020 if (connection == TFT_PARALLEL) { 1021 // Switch WR pin to PWM or CCL 1022 pinPeripheral(tft8._wr, wrPeripheral); 1023 } 1024 #endif // end __SAMD51__ 1025 if (!bigEndian) { // Normal little-endian situation... 1026 while (len) { 1027 int count = (len < maxSpan) ? len : maxSpan; 1028 1029 // Because TFT and SAMD endianisms are different, must swap 1030 // bytes from the 'colors' array passed into a DMA working 1031 // buffer. This can take place while the prior DMA transfer 1032 // is in progress, hence the need for two pixelBufs. 1033 for (int i = 0; i < count; i++) { 1034 pixelBuf[pixelBufIdx][i] = __builtin_bswap16(*colors++); 1035 } 1036 // The transfers themselves are relatively small, so we don't 1037 // need a long descriptor list. We just alternate between the 1038 // first two, sharing pixelBufIdx for that purpose. 1039 descriptor[pixelBufIdx].SRCADDR.reg = 1040 (uint32_t)pixelBuf[pixelBufIdx] + count * 2; 1041 descriptor[pixelBufIdx].BTCTRL.bit.SRCINC = 1; 1042 descriptor[pixelBufIdx].BTCNT.reg = count * 2; 1043 descriptor[pixelBufIdx].DESCADDR.reg = 0; 1044 1045 while (dma_busy) 1046 ; // Wait for prior line to finish 1047 1048 // Move new descriptor into place... 1049 memcpy(dptr, &descriptor[pixelBufIdx], sizeof(DmacDescriptor)); 1050 dma_busy = true; 1051 dma.startJob(); // Trigger SPI DMA transfer 1052 if (connection == TFT_PARALLEL) 1053 dma.trigger(); 1054 pixelBufIdx = 1 - pixelBufIdx; // Swap DMA pixel buffers 1055 1056 len -= count; 1057 } 1058 } else { // bigEndian == true 1059 // With big-endian pixel data, this can be handled as a single 1060 // DMA transfer using chained descriptors. Even full screen, this 1061 // needs only a relatively short descriptor list, each 1062 // transferring a max of 32,767 (not 32,768) pixels. The list 1063 // was allocated large enough to accommodate a full screen's 1064 // worth of data, so this won't run past the end of the list. 1065 int d, numDescriptors = (len + 32766) / 32767; 1066 for (d = 0; d < numDescriptors; d++) { 1067 int count = (len < 32767) ? len : 32767; 1068 descriptor[d].SRCADDR.reg = (uint32_t)colors + count * 2; 1069 descriptor[d].BTCTRL.bit.SRCINC = 1; 1070 descriptor[d].BTCNT.reg = count * 2; 1071 descriptor[d].DESCADDR.reg = (uint32_t)&descriptor[d + 1]; 1072 len -= count; 1073 colors += count; 1074 } 1075 descriptor[d - 1].DESCADDR.reg = 0; 1076 1077 while (dma_busy) 1078 ; // Wait for prior transfer (if any) to finish 1079 1080 // Move first descriptor into place and start transfer... 1081 memcpy(dptr, &descriptor[0], sizeof(DmacDescriptor)); 1082 dma_busy = true; 1083 dma.startJob(); // Trigger SPI DMA transfer 1084 if (connection == TFT_PARALLEL) 1085 dma.trigger(); 1086 } // end bigEndian 1087 1088 lastFillColor = 0x0000; // pixelBuf has been sullied 1089 lastFillLen = 0; 1090 if (block) { 1091 while (dma_busy) 1092 ; // Wait for last line to complete 1093 #if defined(__SAMD51__) || defined(ARDUINO_SAMD_ZERO) 1094 if (connection == TFT_HARD_SPI) { 1095 // See SAMD51/21 note in writeColor() 1096 hwspi._spi->setDataMode(hwspi._mode); 1097 } else { 1098 pinPeripheral(tft8._wr, PIO_OUTPUT); // Switch WR back to GPIO 1099 } 1100 #endif // end __SAMD51__ || ARDUINO_SAMD_ZERO 1101 } 1102 return; 1103 } 1104 #endif // end USE_SPI_DMA 1105 1106 // All other cases (bitbang SPI or non-DMA hard SPI or parallel), 1107 // use a loop with the normal 16-bit data write function: 1108 while (len--) { 1109 SPI_WRITE16(*colors++); 1110 } 1111 } 1112 1113 /*! 1114 @brief Wait for the last DMA transfer in a prior non-blocking 1115 writePixels() call to complete. This does nothing if DMA 1116 is not enabled, and is not needed if blocking writePixels() 1117 was used (as is the default case). 1118 */ 1119 void Adafruit_SPITFT::dmaWait(void) { 1120 #if defined(USE_SPI_DMA) && (defined(__SAMD51__) || defined(ARDUINO_SAMD_ZERO)) 1121 while (dma_busy) 1122 ; 1123 #if defined(__SAMD51__) || defined(ARDUINO_SAMD_ZERO) 1124 if (connection == TFT_HARD_SPI) { 1125 // See SAMD51/21 note in writeColor() 1126 hwspi._spi->setDataMode(hwspi._mode); 1127 } else { 1128 pinPeripheral(tft8._wr, PIO_OUTPUT); // Switch WR back to GPIO 1129 } 1130 #endif // end __SAMD51__ || ARDUINO_SAMD_ZERO 1131 #endif 1132 } 1133 1134 /*! 1135 @brief Issue a series of pixels, all the same color. Not self- 1136 contained; should follow startWrite() and setAddrWindow() calls. 1137 @param color 16-bit pixel color in '565' RGB format. 1138 @param len Number of pixels to draw. 1139 */ 1140 void Adafruit_SPITFT::writeColor(uint16_t color, uint32_t len) { 1141 1142 if (!len) 1143 return; // Avoid 0-byte transfers 1144 1145 uint8_t hi = color >> 8, lo = color; 1146 1147 #if defined(ESP32) // ESP32 has a special SPI pixel-writing function... 1148 if (connection == TFT_HARD_SPI) { 1149 #define SPI_MAX_PIXELS_AT_ONCE 32 1150 #define TMPBUF_LONGWORDS (SPI_MAX_PIXELS_AT_ONCE + 1) / 2 1151 #define TMPBUF_PIXELS (TMPBUF_LONGWORDS * 2) 1152 static uint32_t temp[TMPBUF_LONGWORDS]; 1153 uint32_t c32 = color * 0x00010001; 1154 uint16_t bufLen = (len < TMPBUF_PIXELS) ? len : TMPBUF_PIXELS, xferLen, 1155 fillLen; 1156 // Fill temp buffer 32 bits at a time 1157 fillLen = (bufLen + 1) / 2; // Round up to next 32-bit boundary 1158 for (uint32_t t = 0; t < fillLen; t++) { 1159 temp[t] = c32; 1160 } 1161 // Issue pixels in blocks from temp buffer 1162 while (len) { // While pixels remain 1163 xferLen = (bufLen < len) ? bufLen : len; // How many this pass? 1164 writePixels((uint16_t *)temp, xferLen); 1165 len -= xferLen; 1166 } 1167 return; 1168 } 1169 #elif defined(ARDUINO_NRF52_ADAFRUIT) && \ 1170 defined(NRF52840_XXAA) // Adafruit nRF52840 use SPIM3 DMA at 32Mhz 1171 // at most 2 scan lines 1172 uint32_t const pixbufcount = min(len, ((uint32_t)2 * width())); 1173 uint16_t *pixbuf = (uint16_t *)rtos_malloc(2 * pixbufcount); 1174 1175 // use SPI3 DMA if we could allocate buffer, else fall back to writing each 1176 // pixel loop below 1177 if (pixbuf) { 1178 uint16_t const swap_color = __builtin_bswap16(color); 1179 1180 // fill buffer with color 1181 for (uint32_t i = 0; i < pixbufcount; i++) { 1182 pixbuf[i] = swap_color; 1183 } 1184 1185 while (len) { 1186 uint32_t const count = min(len, pixbufcount); 1187 writePixels(pixbuf, count, true, true); 1188 len -= count; 1189 } 1190 1191 rtos_free(pixbuf); 1192 return; 1193 } 1194 #else // !ESP32 1195 #if defined(USE_SPI_DMA) && (defined(__SAMD51__) || defined(ARDUINO_SAMD_ZERO)) 1196 if (((connection == TFT_HARD_SPI) || (connection == TFT_PARALLEL)) && 1197 (len >= 16)) { // Don't bother with DMA on short pixel runs 1198 int i, d, numDescriptors; 1199 if (hi == lo) { // If high & low bytes are same... 1200 onePixelBuf = color; 1201 // Can do this with a relatively short descriptor list, 1202 // each transferring a max of 32,767 (not 32,768) pixels. 1203 // This won't run off the end of the allocated descriptor list, 1204 // since we're using much larger chunks per descriptor here. 1205 numDescriptors = (len + 32766) / 32767; 1206 for (d = 0; d < numDescriptors; d++) { 1207 int count = (len < 32767) ? len : 32767; 1208 descriptor[d].SRCADDR.reg = (uint32_t)&onePixelBuf; 1209 descriptor[d].BTCTRL.bit.SRCINC = 0; 1210 descriptor[d].BTCNT.reg = count * 2; 1211 descriptor[d].DESCADDR.reg = (uint32_t)&descriptor[d + 1]; 1212 len -= count; 1213 } 1214 descriptor[d - 1].DESCADDR.reg = 0; 1215 } else { 1216 // If high and low bytes are distinct, it's necessary to fill 1217 // a buffer with pixel data (swapping high and low bytes because 1218 // TFT and SAMD are different endianisms) and create a longer 1219 // descriptor list pointing repeatedly to this data. We can do 1220 // this slightly faster working 2 pixels (32 bits) at a time. 1221 uint32_t *pixelPtr = (uint32_t *)pixelBuf[0], 1222 twoPixels = __builtin_bswap16(color) * 0x00010001; 1223 // We can avoid some or all of the buffer-filling if the color 1224 // is the same as last time... 1225 if (color == lastFillColor) { 1226 // If length is longer than prior instance, fill only the 1227 // additional pixels in the buffer and update lastFillLen. 1228 if (len > lastFillLen) { 1229 int fillStart = lastFillLen / 2, 1230 fillEnd = (((len < maxFillLen) ? len : maxFillLen) + 1) / 2; 1231 for (i = fillStart; i < fillEnd; i++) 1232 pixelPtr[i] = twoPixels; 1233 lastFillLen = fillEnd * 2; 1234 } // else do nothing, don't set pixels or change lastFillLen 1235 } else { 1236 int fillEnd = (((len < maxFillLen) ? len : maxFillLen) + 1) / 2; 1237 for (i = 0; i < fillEnd; i++) 1238 pixelPtr[i] = twoPixels; 1239 lastFillLen = fillEnd * 2; 1240 lastFillColor = color; 1241 } 1242 1243 numDescriptors = (len + maxFillLen - 1) / maxFillLen; 1244 for (d = 0; d < numDescriptors; d++) { 1245 int pixels = (len < maxFillLen) ? len : maxFillLen, bytes = pixels * 2; 1246 descriptor[d].SRCADDR.reg = (uint32_t)pixelPtr + bytes; 1247 descriptor[d].BTCTRL.bit.SRCINC = 1; 1248 descriptor[d].BTCNT.reg = bytes; 1249 descriptor[d].DESCADDR.reg = (uint32_t)&descriptor[d + 1]; 1250 len -= pixels; 1251 } 1252 descriptor[d - 1].DESCADDR.reg = 0; 1253 } 1254 memcpy(dptr, &descriptor[0], sizeof(DmacDescriptor)); 1255 #if defined(__SAMD51__) 1256 if (connection == TFT_PARALLEL) { 1257 // Switch WR pin to PWM or CCL 1258 pinPeripheral(tft8._wr, wrPeripheral); 1259 } 1260 #endif // end __SAMD51__ 1261 1262 dma_busy = true; 1263 dma.startJob(); 1264 if (connection == TFT_PARALLEL) 1265 dma.trigger(); 1266 while (dma_busy) 1267 ; // Wait for completion 1268 // Unfortunately blocking is necessary. An earlier version returned 1269 // immediately and checked dma_busy on startWrite() instead, but it 1270 // turns out to be MUCH slower on many graphics operations (as when 1271 // drawing lines, pixel-by-pixel), perhaps because it's a volatile 1272 // type and doesn't cache. Working on this. 1273 #if defined(__SAMD51__) || defined(ARDUINO_SAMD_ZERO) 1274 if (connection == TFT_HARD_SPI) { 1275 // SAMD51: SPI DMA seems to leave the SPI peripheral in a freaky 1276 // state on completion. Workaround is to explicitly set it back... 1277 // (5/17/2019: apparently SAMD21 too, in certain cases, observed 1278 // with ST7789 display.) 1279 hwspi._spi->setDataMode(hwspi._mode); 1280 } else { 1281 pinPeripheral(tft8._wr, PIO_OUTPUT); // Switch WR back to GPIO 1282 } 1283 #endif // end __SAMD51__ 1284 return; 1285 } 1286 #endif // end USE_SPI_DMA 1287 #endif // end !ESP32 1288 1289 // All other cases (non-DMA hard SPI, bitbang SPI, parallel)... 1290 1291 if (connection == TFT_HARD_SPI) { 1292 #if defined(ESP8266) 1293 do { 1294 uint32_t pixelsThisPass = len; 1295 if (pixelsThisPass > 50000) 1296 pixelsThisPass = 50000; 1297 len -= pixelsThisPass; 1298 yield(); // Periodic yield() on long fills 1299 while (pixelsThisPass--) { 1300 hwspi._spi->write(hi); 1301 hwspi._spi->write(lo); 1302 } 1303 } while (len); 1304 #else // !ESP8266 1305 while (len--) { 1306 #if defined(__AVR__) 1307 AVR_WRITESPI(hi); 1308 AVR_WRITESPI(lo); 1309 #elif defined(ESP32) 1310 hwspi._spi->write(hi); 1311 hwspi._spi->write(lo); 1312 #else 1313 hwspi._spi->transfer(hi); 1314 hwspi._spi->transfer(lo); 1315 #endif 1316 } 1317 #endif // end !ESP8266 1318 } else if (connection == TFT_SOFT_SPI) { 1319 #if defined(ESP8266) 1320 do { 1321 uint32_t pixelsThisPass = len; 1322 if (pixelsThisPass > 20000) 1323 pixelsThisPass = 20000; 1324 len -= pixelsThisPass; 1325 yield(); // Periodic yield() on long fills 1326 while (pixelsThisPass--) { 1327 for (uint16_t bit = 0, x = color; bit < 16; bit++) { 1328 if (x & 0x8000) 1329 SPI_MOSI_HIGH(); 1330 else 1331 SPI_MOSI_LOW(); 1332 SPI_SCK_HIGH(); 1333 SPI_SCK_LOW(); 1334 x <<= 1; 1335 } 1336 } 1337 } while (len); 1338 #else // !ESP8266 1339 while (len--) { 1340 #if defined(__AVR__) 1341 for (uint8_t bit = 0, x = hi; bit < 8; bit++) { 1342 if (x & 0x80) 1343 SPI_MOSI_HIGH(); 1344 else 1345 SPI_MOSI_LOW(); 1346 SPI_SCK_HIGH(); 1347 SPI_SCK_LOW(); 1348 x <<= 1; 1349 } 1350 for (uint8_t bit = 0, x = lo; bit < 8; bit++) { 1351 if (x & 0x80) 1352 SPI_MOSI_HIGH(); 1353 else 1354 SPI_MOSI_LOW(); 1355 SPI_SCK_HIGH(); 1356 SPI_SCK_LOW(); 1357 x <<= 1; 1358 } 1359 #else // !__AVR__ 1360 for (uint16_t bit = 0, x = color; bit < 16; bit++) { 1361 if (x & 0x8000) 1362 SPI_MOSI_HIGH(); 1363 else 1364 SPI_MOSI_LOW(); 1365 SPI_SCK_HIGH(); 1366 x <<= 1; 1367 SPI_SCK_LOW(); 1368 } 1369 #endif // end !__AVR__ 1370 } 1371 #endif // end !ESP8266 1372 } else { // PARALLEL 1373 if (hi == lo) { 1374 #if defined(__AVR__) 1375 len *= 2; 1376 *tft8.writePort = hi; 1377 while (len--) { 1378 TFT_WR_STROBE(); 1379 } 1380 #elif defined(USE_FAST_PINIO) 1381 if (!tft8.wide) { 1382 len *= 2; 1383 *tft8.writePort = hi; 1384 } else { 1385 *(volatile uint16_t *)tft8.writePort = color; 1386 } 1387 while (len--) { 1388 TFT_WR_STROBE(); 1389 } 1390 #endif 1391 } else { 1392 while (len--) { 1393 #if defined(__AVR__) 1394 *tft8.writePort = hi; 1395 TFT_WR_STROBE(); 1396 *tft8.writePort = lo; 1397 #elif defined(USE_FAST_PINIO) 1398 if (!tft8.wide) { 1399 *tft8.writePort = hi; 1400 TFT_WR_STROBE(); 1401 *tft8.writePort = lo; 1402 } else { 1403 *(volatile uint16_t *)tft8.writePort = color; 1404 } 1405 #endif 1406 TFT_WR_STROBE(); 1407 } 1408 } 1409 } 1410 } 1411 1412 /*! 1413 @brief Draw a filled rectangle to the display. Not self-contained; 1414 should follow startWrite(). Typically used by higher-level 1415 graphics primitives; user code shouldn't need to call this and 1416 is likely to use the self-contained fillRect() instead. 1417 writeFillRect() performs its own edge clipping and rejection; 1418 see writeFillRectPreclipped() for a more 'raw' implementation. 1419 @param x Horizontal position of first corner. 1420 @param y Vertical position of first corner. 1421 @param w Rectangle width in pixels (positive = right of first 1422 corner, negative = left of first corner). 1423 @param h Rectangle height in pixels (positive = below first 1424 corner, negative = above first corner). 1425 @param color 16-bit fill color in '565' RGB format. 1426 @note Written in this deep-nested way because C by definition will 1427 optimize for the 'if' case, not the 'else' -- avoids branches 1428 and rejects clipped rectangles at the least-work possibility. 1429 */ 1430 void Adafruit_SPITFT::writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, 1431 uint16_t color) { 1432 if (w && h) { // Nonzero width and height? 1433 if (w < 0) { // If negative width... 1434 x += w + 1; // Move X to left edge 1435 w = -w; // Use positive width 1436 } 1437 if (x < _width) { // Not off right 1438 if (h < 0) { // If negative height... 1439 y += h + 1; // Move Y to top edge 1440 h = -h; // Use positive height 1441 } 1442 if (y < _height) { // Not off bottom 1443 int16_t x2 = x + w - 1; 1444 if (x2 >= 0) { // Not off left 1445 int16_t y2 = y + h - 1; 1446 if (y2 >= 0) { // Not off top 1447 // Rectangle partly or fully overlaps screen 1448 if (x < 0) { 1449 x = 0; 1450 w = x2 + 1; 1451 } // Clip left 1452 if (y < 0) { 1453 y = 0; 1454 h = y2 + 1; 1455 } // Clip top 1456 if (x2 >= _width) { 1457 w = _width - x; 1458 } // Clip right 1459 if (y2 >= _height) { 1460 h = _height - y; 1461 } // Clip bottom 1462 writeFillRectPreclipped(x, y, w, h, color); 1463 } 1464 } 1465 } 1466 } 1467 } 1468 } 1469 1470 /*! 1471 @brief Draw a horizontal line on the display. Performs edge clipping 1472 and rejection. Not self-contained; should follow startWrite(). 1473 Typically used by higher-level graphics primitives; user code 1474 shouldn't need to call this and is likely to use the self- 1475 contained drawFastHLine() instead. 1476 @param x Horizontal position of first point. 1477 @param y Vertical position of first point. 1478 @param w Line width in pixels (positive = right of first point, 1479 negative = point of first corner). 1480 @param color 16-bit line color in '565' RGB format. 1481 */ 1482 void inline Adafruit_SPITFT::writeFastHLine(int16_t x, int16_t y, int16_t w, 1483 uint16_t color) { 1484 if ((y >= 0) && (y < _height) && w) { // Y on screen, nonzero width 1485 if (w < 0) { // If negative width... 1486 x += w + 1; // Move X to left edge 1487 w = -w; // Use positive width 1488 } 1489 if (x < _width) { // Not off right 1490 int16_t x2 = x + w - 1; 1491 if (x2 >= 0) { // Not off left 1492 // Line partly or fully overlaps screen 1493 if (x < 0) { 1494 x = 0; 1495 w = x2 + 1; 1496 } // Clip left 1497 if (x2 >= _width) { 1498 w = _width - x; 1499 } // Clip right 1500 writeFillRectPreclipped(x, y, w, 1, color); 1501 } 1502 } 1503 } 1504 } 1505 1506 /*! 1507 @brief Draw a vertical line on the display. Performs edge clipping and 1508 rejection. Not self-contained; should follow startWrite(). 1509 Typically used by higher-level graphics primitives; user code 1510 shouldn't need to call this and is likely to use the self- 1511 contained drawFastVLine() instead. 1512 @param x Horizontal position of first point. 1513 @param y Vertical position of first point. 1514 @param h Line height in pixels (positive = below first point, 1515 negative = above first point). 1516 @param color 16-bit line color in '565' RGB format. 1517 */ 1518 void inline Adafruit_SPITFT::writeFastVLine(int16_t x, int16_t y, int16_t h, 1519 uint16_t color) { 1520 if ((x >= 0) && (x < _width) && h) { // X on screen, nonzero height 1521 if (h < 0) { // If negative height... 1522 y += h + 1; // Move Y to top edge 1523 h = -h; // Use positive height 1524 } 1525 if (y < _height) { // Not off bottom 1526 int16_t y2 = y + h - 1; 1527 if (y2 >= 0) { // Not off top 1528 // Line partly or fully overlaps screen 1529 if (y < 0) { 1530 y = 0; 1531 h = y2 + 1; 1532 } // Clip top 1533 if (y2 >= _height) { 1534 h = _height - y; 1535 } // Clip bottom 1536 writeFillRectPreclipped(x, y, 1, h, color); 1537 } 1538 } 1539 } 1540 } 1541 1542 /*! 1543 @brief A lower-level version of writeFillRect(). This version requires 1544 all inputs are in-bounds, that width and height are positive, 1545 and no part extends offscreen. NO EDGE CLIPPING OR REJECTION IS 1546 PERFORMED. If higher-level graphics primitives are written to 1547 handle their own clipping earlier in the drawing process, this 1548 can avoid unnecessary function calls and repeated clipping 1549 operations in the lower-level functions. 1550 @param x Horizontal position of first corner. MUST BE WITHIN 1551 SCREEN BOUNDS. 1552 @param y Vertical position of first corner. MUST BE WITHIN SCREEN 1553 BOUNDS. 1554 @param w Rectangle width in pixels. MUST BE POSITIVE AND NOT 1555 EXTEND OFF SCREEN. 1556 @param h Rectangle height in pixels. MUST BE POSITIVE AND NOT 1557 EXTEND OFF SCREEN. 1558 @param color 16-bit fill color in '565' RGB format. 1559 @note This is a new function, no graphics primitives besides rects 1560 and horizontal/vertical lines are written to best use this yet. 1561 */ 1562 inline void Adafruit_SPITFT::writeFillRectPreclipped(int16_t x, int16_t y, 1563 int16_t w, int16_t h, 1564 uint16_t color) { 1565 setAddrWindow(x, y, w, h); 1566 writeColor(color, (uint32_t)w * h); 1567 } 1568 1569 // ------------------------------------------------------------------------- 1570 // Ever-so-slightly higher-level graphics operations. Similar to the 'write' 1571 // functions above, but these contain their own chip-select and SPI 1572 // transactions as needed (via startWrite(), endWrite()). They're typically 1573 // used solo -- as graphics primitives in themselves, not invoked by higher- 1574 // level primitives (which should use the functions above for better 1575 // performance). 1576 1577 /*! 1578 @brief Draw a single pixel to the display at requested coordinates. 1579 Self-contained and provides its own transaction as needed 1580 (see writePixel(x,y,color) for a lower-level variant). 1581 Edge clipping is performed here. 1582 @param x Horizontal position (0 = left). 1583 @param y Vertical position (0 = top). 1584 @param color 16-bit pixel color in '565' RGB format. 1585 */ 1586 void Adafruit_SPITFT::drawPixel(int16_t x, int16_t y, uint16_t color) { 1587 // Clip first... 1588 if ((x >= 0) && (x < _width) && (y >= 0) && (y < _height)) { 1589 // THEN set up transaction (if needed) and draw... 1590 startWrite(); 1591 setAddrWindow(x, y, 1, 1); 1592 SPI_WRITE16(color); 1593 endWrite(); 1594 } 1595 } 1596 1597 /*! 1598 @brief Draw a filled rectangle to the display. Self-contained and 1599 provides its own transaction as needed (see writeFillRect() or 1600 writeFillRectPreclipped() for lower-level variants). Edge 1601 clipping and rejection is performed here. 1602 @param x Horizontal position of first corner. 1603 @param y Vertical position of first corner. 1604 @param w Rectangle width in pixels (positive = right of first 1605 corner, negative = left of first corner). 1606 @param h Rectangle height in pixels (positive = below first 1607 corner, negative = above first corner). 1608 @param color 16-bit fill color in '565' RGB format. 1609 @note This repeats the writeFillRect() function almost in its entirety, 1610 with the addition of a transaction start/end. It's done this way 1611 (rather than starting the transaction and calling writeFillRect() 1612 to handle clipping and so forth) so that the transaction isn't 1613 performed at all if the rectangle is rejected. It's really not 1614 that much code. 1615 */ 1616 void Adafruit_SPITFT::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, 1617 uint16_t color) { 1618 if (w && h) { // Nonzero width and height? 1619 if (w < 0) { // If negative width... 1620 x += w + 1; // Move X to left edge 1621 w = -w; // Use positive width 1622 } 1623 if (x < _width) { // Not off right 1624 if (h < 0) { // If negative height... 1625 y += h + 1; // Move Y to top edge 1626 h = -h; // Use positive height 1627 } 1628 if (y < _height) { // Not off bottom 1629 int16_t x2 = x + w - 1; 1630 if (x2 >= 0) { // Not off left 1631 int16_t y2 = y + h - 1; 1632 if (y2 >= 0) { // Not off top 1633 // Rectangle partly or fully overlaps screen 1634 if (x < 0) { 1635 x = 0; 1636 w = x2 + 1; 1637 } // Clip left 1638 if (y < 0) { 1639 y = 0; 1640 h = y2 + 1; 1641 } // Clip top 1642 if (x2 >= _width) { 1643 w = _width - x; 1644 } // Clip right 1645 if (y2 >= _height) { 1646 h = _height - y; 1647 } // Clip bottom 1648 startWrite(); 1649 writeFillRectPreclipped(x, y, w, h, color); 1650 endWrite(); 1651 } 1652 } 1653 } 1654 } 1655 } 1656 } 1657 1658 /*! 1659 @brief Draw a horizontal line on the display. Self-contained and 1660 provides its own transaction as needed (see writeFastHLine() for 1661 a lower-level variant). Edge clipping and rejection is performed 1662 here. 1663 @param x Horizontal position of first point. 1664 @param y Vertical position of first point. 1665 @param w Line width in pixels (positive = right of first point, 1666 negative = point of first corner). 1667 @param color 16-bit line color in '565' RGB format. 1668 @note This repeats the writeFastHLine() function almost in its 1669 entirety, with the addition of a transaction start/end. It's 1670 done this way (rather than starting the transaction and calling 1671 writeFastHLine() to handle clipping and so forth) so that the 1672 transaction isn't performed at all if the line is rejected. 1673 */ 1674 void Adafruit_SPITFT::drawFastHLine(int16_t x, int16_t y, int16_t w, 1675 uint16_t color) { 1676 if ((y >= 0) && (y < _height) && w) { // Y on screen, nonzero width 1677 if (w < 0) { // If negative width... 1678 x += w + 1; // Move X to left edge 1679 w = -w; // Use positive width 1680 } 1681 if (x < _width) { // Not off right 1682 int16_t x2 = x + w - 1; 1683 if (x2 >= 0) { // Not off left 1684 // Line partly or fully overlaps screen 1685 if (x < 0) { 1686 x = 0; 1687 w = x2 + 1; 1688 } // Clip left 1689 if (x2 >= _width) { 1690 w = _width - x; 1691 } // Clip right 1692 startWrite(); 1693 writeFillRectPreclipped(x, y, w, 1, color); 1694 endWrite(); 1695 } 1696 } 1697 } 1698 } 1699 1700 /*! 1701 @brief Draw a vertical line on the display. Self-contained and provides 1702 its own transaction as needed (see writeFastHLine() for a lower- 1703 level variant). Edge clipping and rejection is performed here. 1704 @param x Horizontal position of first point. 1705 @param y Vertical position of first point. 1706 @param h Line height in pixels (positive = below first point, 1707 negative = above first point). 1708 @param color 16-bit line color in '565' RGB format. 1709 @note This repeats the writeFastVLine() function almost in its 1710 entirety, with the addition of a transaction start/end. It's 1711 done this way (rather than starting the transaction and calling 1712 writeFastVLine() to handle clipping and so forth) so that the 1713 transaction isn't performed at all if the line is rejected. 1714 */ 1715 void Adafruit_SPITFT::drawFastVLine(int16_t x, int16_t y, int16_t h, 1716 uint16_t color) { 1717 if ((x >= 0) && (x < _width) && h) { // X on screen, nonzero height 1718 if (h < 0) { // If negative height... 1719 y += h + 1; // Move Y to top edge 1720 h = -h; // Use positive height 1721 } 1722 if (y < _height) { // Not off bottom 1723 int16_t y2 = y + h - 1; 1724 if (y2 >= 0) { // Not off top 1725 // Line partly or fully overlaps screen 1726 if (y < 0) { 1727 y = 0; 1728 h = y2 + 1; 1729 } // Clip top 1730 if (y2 >= _height) { 1731 h = _height - y; 1732 } // Clip bottom 1733 startWrite(); 1734 writeFillRectPreclipped(x, y, 1, h, color); 1735 endWrite(); 1736 } 1737 } 1738 } 1739 } 1740 1741 /*! 1742 @brief Essentially writePixel() with a transaction around it. I don't 1743 think this is in use by any of our code anymore (believe it was 1744 for some older BMP-reading examples), but is kept here in case 1745 any user code relies on it. Consider it DEPRECATED. 1746 @param color 16-bit pixel color in '565' RGB format. 1747 */ 1748 void Adafruit_SPITFT::pushColor(uint16_t color) { 1749 startWrite(); 1750 SPI_WRITE16(color); 1751 endWrite(); 1752 } 1753 1754 /*! 1755 @brief Draw a 16-bit image (565 RGB) at the specified (x,y) position. 1756 For 16-bit display devices; no color reduction performed. 1757 Adapted from https://github.com/PaulStoffregen/ILI9341_t3 1758 by Marc MERLIN. See examples/pictureEmbed to use this. 1759 5/6/2017: function name and arguments have changed for 1760 compatibility with current GFX library and to avoid naming 1761 problems in prior implementation. Formerly drawBitmap() with 1762 arguments in different order. Handles its own transaction and 1763 edge clipping/rejection. 1764 @param x Top left corner horizontal coordinate. 1765 @param y Top left corner vertical coordinate. 1766 @param pcolors Pointer to 16-bit array of pixel values. 1767 @param w Width of bitmap in pixels. 1768 @param h Height of bitmap in pixels. 1769 */ 1770 void Adafruit_SPITFT::drawRGBBitmap(int16_t x, int16_t y, uint16_t *pcolors, 1771 int16_t w, int16_t h) { 1772 1773 int16_t x2, y2; // Lower-right coord 1774 if ((x >= _width) || // Off-edge right 1775 (y >= _height) || // " top 1776 ((x2 = (x + w - 1)) < 0) || // " left 1777 ((y2 = (y + h - 1)) < 0)) 1778 return; // " bottom 1779 1780 int16_t bx1 = 0, by1 = 0, // Clipped top-left within bitmap 1781 saveW = w; // Save original bitmap width value 1782 if (x < 0) { // Clip left 1783 w += x; 1784 bx1 = -x; 1785 x = 0; 1786 } 1787 if (y < 0) { // Clip top 1788 h += y; 1789 by1 = -y; 1790 y = 0; 1791 } 1792 if (x2 >= _width) 1793 w = _width - x; // Clip right 1794 if (y2 >= _height) 1795 h = _height - y; // Clip bottom 1796 1797 pcolors += by1 * saveW + bx1; // Offset bitmap ptr to clipped top-left 1798 startWrite(); 1799 setAddrWindow(x, y, w, h); // Clipped area 1800 while (h--) { // For each (clipped) scanline... 1801 writePixels(pcolors, w); // Push one (clipped) row 1802 pcolors += saveW; // Advance pointer by one full (unclipped) line 1803 } 1804 endWrite(); 1805 } 1806 1807 // ------------------------------------------------------------------------- 1808 // Miscellaneous class member functions that don't draw anything. 1809 1810 /*! 1811 @brief Invert the colors of the display (if supported by hardware). 1812 Self-contained, no transaction setup required. 1813 @param i true = inverted display, false = normal display. 1814 */ 1815 void Adafruit_SPITFT::invertDisplay(bool i) { 1816 startWrite(); 1817 writeCommand(i ? invertOnCommand : invertOffCommand); 1818 endWrite(); 1819 } 1820 1821 /*! 1822 @brief Given 8-bit red, green and blue values, return a 'packed' 1823 16-bit color value in '565' RGB format (5 bits red, 6 bits 1824 green, 5 bits blue). This is just a mathematical operation, 1825 no hardware is touched. 1826 @param red 8-bit red brightnesss (0 = off, 255 = max). 1827 @param green 8-bit green brightnesss (0 = off, 255 = max). 1828 @param blue 8-bit blue brightnesss (0 = off, 255 = max). 1829 @return 'Packed' 16-bit color value (565 format). 1830 */ 1831 uint16_t Adafruit_SPITFT::color565(uint8_t red, uint8_t green, uint8_t blue) { 1832 return ((red & 0xF8) << 8) | ((green & 0xFC) << 3) | (blue >> 3); 1833 } 1834 1835 /*! 1836 @brief Adafruit_SPITFT Send Command handles complete sending of commands and 1837 data 1838 @param commandByte The Command Byte 1839 @param dataBytes A pointer to the Data bytes to send 1840 @param numDataBytes The number of bytes we should send 1841 */ 1842 void Adafruit_SPITFT::sendCommand(uint8_t commandByte, uint8_t *dataBytes, 1843 uint8_t numDataBytes) { 1844 SPI_BEGIN_TRANSACTION(); 1845 if (_cs >= 0) 1846 SPI_CS_LOW(); 1847 1848 SPI_DC_LOW(); // Command mode 1849 spiWrite(commandByte); // Send the command byte 1850 1851 SPI_DC_HIGH(); 1852 for (int i = 0; i < numDataBytes; i++) { 1853 if ((connection == TFT_PARALLEL) && tft8.wide) { 1854 SPI_WRITE16(*(uint16_t *)dataBytes); 1855 dataBytes += 2; 1856 } else { 1857 spiWrite(*dataBytes); // Send the data bytes 1858 dataBytes++; 1859 } 1860 } 1861 1862 if (_cs >= 0) 1863 SPI_CS_HIGH(); 1864 SPI_END_TRANSACTION(); 1865 } 1866 1867 /*! 1868 @brief Adafruit_SPITFT Send Command handles complete sending of commands and 1869 data 1870 @param commandByte The Command Byte 1871 @param dataBytes A pointer to the Data bytes to send 1872 @param numDataBytes The number of bytes we should send 1873 */ 1874 void Adafruit_SPITFT::sendCommand(uint8_t commandByte, const uint8_t *dataBytes, 1875 uint8_t numDataBytes) { 1876 SPI_BEGIN_TRANSACTION(); 1877 if (_cs >= 0) 1878 SPI_CS_LOW(); 1879 1880 SPI_DC_LOW(); // Command mode 1881 spiWrite(commandByte); // Send the command byte 1882 1883 SPI_DC_HIGH(); 1884 for (int i = 0; i < numDataBytes; i++) { 1885 if ((connection == TFT_PARALLEL) && tft8.wide) { 1886 SPI_WRITE16(*(uint16_t *)dataBytes); 1887 dataBytes += 2; 1888 } else { 1889 spiWrite(pgm_read_byte(dataBytes++)); 1890 } 1891 } 1892 1893 if (_cs >= 0) 1894 SPI_CS_HIGH(); 1895 SPI_END_TRANSACTION(); 1896 } 1897 1898 /*! 1899 @brief Adafruit_SPITFT sendCommand16 handles complete sending of 1900 commands and data for 16-bit parallel displays. Currently somewhat 1901 rigged for the NT35510, which has the odd behavior of wanting 1902 commands 16-bit, but subsequent data as 8-bit values, despite 1903 the 16-bit bus (high byte is always 0). Also seems to require 1904 issuing and incrementing address with each transfer. 1905 @param commandWord The command word (16 bits) 1906 @param dataBytes A pointer to the data bytes to send 1907 @param numDataBytes The number of bytes we should send 1908 */ 1909 void Adafruit_SPITFT::sendCommand16(uint16_t commandWord, 1910 const uint8_t *dataBytes, 1911 uint8_t numDataBytes) { 1912 SPI_BEGIN_TRANSACTION(); 1913 if (_cs >= 0) 1914 SPI_CS_LOW(); 1915 1916 if (numDataBytes == 0) { 1917 SPI_DC_LOW(); // Command mode 1918 SPI_WRITE16(commandWord); // Send the command word 1919 SPI_DC_HIGH(); // Data mode 1920 } 1921 for (int i = 0; i < numDataBytes; i++) { 1922 SPI_DC_LOW(); // Command mode 1923 SPI_WRITE16(commandWord); // Send the command word 1924 SPI_DC_HIGH(); // Data mode 1925 commandWord++; 1926 SPI_WRITE16((uint16_t)pgm_read_byte(dataBytes++)); 1927 } 1928 1929 if (_cs >= 0) 1930 SPI_CS_HIGH(); 1931 SPI_END_TRANSACTION(); 1932 } 1933 1934 /*! 1935 @brief Read 8 bits of data from display configuration memory (not RAM). 1936 This is highly undocumented/supported and should be avoided, 1937 function is only included because some of the examples use it. 1938 @param commandByte 1939 The command register to read data from. 1940 @param index 1941 The byte index into the command to read from. 1942 @return Unsigned 8-bit data read from display register. 1943 */ 1944 /**************************************************************************/ 1945 uint8_t Adafruit_SPITFT::readcommand8(uint8_t commandByte, uint8_t index) { 1946 uint8_t result; 1947 startWrite(); 1948 SPI_DC_LOW(); // Command mode 1949 spiWrite(commandByte); 1950 SPI_DC_HIGH(); // Data mode 1951 do { 1952 result = spiRead(); 1953 } while (index--); // Discard bytes up to index'th 1954 endWrite(); 1955 return result; 1956 } 1957 1958 /*! 1959 @brief Read 16 bits of data from display register. 1960 For 16-bit parallel displays only. 1961 @param addr Command/register to access. 1962 @return Unsigned 16-bit data. 1963 */ 1964 uint16_t Adafruit_SPITFT::readcommand16(uint16_t addr) { 1965 #if defined(USE_FAST_PINIO) // NOT SUPPORTED without USE_FAST_PINIO 1966 uint16_t result = 0; 1967 if ((connection == TFT_PARALLEL) && tft8.wide) { 1968 startWrite(); 1969 SPI_DC_LOW(); // Command mode 1970 SPI_WRITE16(addr); 1971 SPI_DC_HIGH(); // Data mode 1972 TFT_RD_LOW(); // Read line LOW 1973 #if defined(HAS_PORT_SET_CLR) 1974 *(volatile uint16_t *)tft8.dirClr = 0xFFFF; // Input state 1975 result = *(volatile uint16_t *)tft8.readPort; // 16-bit read 1976 *(volatile uint16_t *)tft8.dirSet = 0xFFFF; // Output state 1977 #else // !HAS_PORT_SET_CLR 1978 *(volatile uint16_t *)tft8.portDir = 0x0000; // Input state 1979 result = *(volatile uint16_t *)tft8.readPort; // 16-bit read 1980 *(volatile uint16_t *)tft8.portDir = 0xFFFF; // Output state 1981 #endif // end !HAS_PORT_SET_CLR 1982 TFT_RD_HIGH(); // Read line HIGH 1983 endWrite(); 1984 } 1985 return result; 1986 #else 1987 (void)addr; // disable -Wunused-parameter warning 1988 return 0; 1989 #endif // end !USE_FAST_PINIO 1990 } 1991 1992 // ------------------------------------------------------------------------- 1993 // Lowest-level hardware-interfacing functions. Many of these are inline and 1994 // compile to different things based on #defines -- typically just a few 1995 // instructions. Others, not so much, those are not inlined. 1996 1997 /*! 1998 @brief Start an SPI transaction if using the hardware SPI interface to 1999 the display. If using an earlier version of the Arduino platform 2000 (before the addition of SPI transactions), this instead attempts 2001 to set up the SPI clock and mode. No action is taken if the 2002 connection is not hardware SPI-based. This does NOT include a 2003 chip-select operation -- see startWrite() for a function that 2004 encapsulated both actions. 2005 */ 2006 inline void Adafruit_SPITFT::SPI_BEGIN_TRANSACTION(void) { 2007 if (connection == TFT_HARD_SPI) { 2008 #if defined(SPI_HAS_TRANSACTION) 2009 hwspi._spi->beginTransaction(hwspi.settings); 2010 #else // No transactions, configure SPI manually... 2011 #if defined(__AVR__) || defined(TEENSYDUINO) || defined(ARDUINO_ARCH_STM32F1) 2012 hwspi._spi->setClockDivider(SPI_CLOCK_DIV2); 2013 #elif defined(__arm__) 2014 hwspi._spi->setClockDivider(11); 2015 #elif defined(ESP8266) || defined(ESP32) 2016 hwspi._spi->setFrequency(hwspi._freq); 2017 #elif defined(RASPI) || defined(ARDUINO_ARCH_STM32F1) 2018 hwspi._spi->setClock(hwspi._freq); 2019 #endif 2020 hwspi._spi->setBitOrder(MSBFIRST); 2021 hwspi._spi->setDataMode(hwspi._mode); 2022 #endif // end !SPI_HAS_TRANSACTION 2023 } 2024 } 2025 2026 /*! 2027 @brief End an SPI transaction if using the hardware SPI interface to 2028 the display. No action is taken if the connection is not 2029 hardware SPI-based or if using an earlier version of the Arduino 2030 platform (before the addition of SPI transactions). This does 2031 NOT include a chip-deselect operation -- see endWrite() for a 2032 function that encapsulated both actions. 2033 */ 2034 inline void Adafruit_SPITFT::SPI_END_TRANSACTION(void) { 2035 #if defined(SPI_HAS_TRANSACTION) 2036 if (connection == TFT_HARD_SPI) { 2037 hwspi._spi->endTransaction(); 2038 } 2039 #endif 2040 } 2041 2042 /*! 2043 @brief Issue a single 8-bit value to the display. Chip-select, 2044 transaction and data/command selection must have been 2045 previously set -- this ONLY issues the byte. This is another of 2046 those functions in the library with a now-not-accurate name 2047 that's being maintained for compatibility with outside code. 2048 This function is used even if display connection is parallel. 2049 @param b 8-bit value to write. 2050 */ 2051 void Adafruit_SPITFT::spiWrite(uint8_t b) { 2052 if (connection == TFT_HARD_SPI) { 2053 #if defined(__AVR__) 2054 AVR_WRITESPI(b); 2055 #elif defined(ESP8266) || defined(ESP32) 2056 hwspi._spi->write(b); 2057 #else 2058 hwspi._spi->transfer(b); 2059 #endif 2060 } else if (connection == TFT_SOFT_SPI) { 2061 for (uint8_t bit = 0; bit < 8; bit++) { 2062 if (b & 0x80) 2063 SPI_MOSI_HIGH(); 2064 else 2065 SPI_MOSI_LOW(); 2066 SPI_SCK_HIGH(); 2067 b <<= 1; 2068 SPI_SCK_LOW(); 2069 } 2070 } else { // TFT_PARALLEL 2071 #if defined(__AVR__) 2072 *tft8.writePort = b; 2073 #elif defined(USE_FAST_PINIO) 2074 if (!tft8.wide) 2075 *tft8.writePort = b; 2076 else 2077 *(volatile uint16_t *)tft8.writePort = b; 2078 #endif 2079 TFT_WR_STROBE(); 2080 } 2081 } 2082 2083 /*! 2084 @brief Write a single command byte to the display. Chip-select and 2085 transaction must have been previously set -- this ONLY sets 2086 the device to COMMAND mode, issues the byte and then restores 2087 DATA mode. There is no corresponding explicit writeData() 2088 function -- just use spiWrite(). 2089 @param cmd 8-bit command to write. 2090 */ 2091 void Adafruit_SPITFT::writeCommand(uint8_t cmd) { 2092 SPI_DC_LOW(); 2093 spiWrite(cmd); 2094 SPI_DC_HIGH(); 2095 } 2096 2097 /*! 2098 @brief Read a single 8-bit value from the display. Chip-select and 2099 transaction must have been previously set -- this ONLY reads 2100 the byte. This is another of those functions in the library 2101 with a now-not-accurate name that's being maintained for 2102 compatibility with outside code. This function is used even if 2103 display connection is parallel. 2104 @return Unsigned 8-bit value read (always zero if USE_FAST_PINIO is 2105 not supported by the MCU architecture). 2106 */ 2107 uint8_t Adafruit_SPITFT::spiRead(void) { 2108 uint8_t b = 0; 2109 uint16_t w = 0; 2110 if (connection == TFT_HARD_SPI) { 2111 return hwspi._spi->transfer((uint8_t)0); 2112 } else if (connection == TFT_SOFT_SPI) { 2113 if (swspi._miso >= 0) { 2114 for (uint8_t i = 0; i < 8; i++) { 2115 SPI_SCK_HIGH(); 2116 b <<= 1; 2117 if (SPI_MISO_READ()) 2118 b++; 2119 SPI_SCK_LOW(); 2120 } 2121 } 2122 return b; 2123 } else { // TFT_PARALLEL 2124 if (tft8._rd >= 0) { 2125 #if defined(USE_FAST_PINIO) 2126 TFT_RD_LOW(); // Read line LOW 2127 #if defined(__AVR__) 2128 *tft8.portDir = 0x00; // Set port to input state 2129 w = *tft8.readPort; // Read value from port 2130 *tft8.portDir = 0xFF; // Restore port to output 2131 #else // !__AVR__ 2132 if (!tft8.wide) { // 8-bit TFT connection 2133 #if defined(HAS_PORT_SET_CLR) 2134 *tft8.dirClr = 0xFF; // Set port to input state 2135 w = *tft8.readPort; // Read value from port 2136 *tft8.dirSet = 0xFF; // Restore port to output 2137 #else // !HAS_PORT_SET_CLR 2138 *tft8.portDir = 0x00; // Set port to input state 2139 w = *tft8.readPort; // Read value from port 2140 *tft8.portDir = 0xFF; // Restore port to output 2141 #endif // end HAS_PORT_SET_CLR 2142 } else { // 16-bit TFT connection 2143 #if defined(HAS_PORT_SET_CLR) 2144 *(volatile uint16_t *)tft8.dirClr = 0xFFFF; // Input state 2145 w = *(volatile uint16_t *)tft8.readPort; // 16-bit read 2146 *(volatile uint16_t *)tft8.dirSet = 0xFFFF; // Output state 2147 #else // !HAS_PORT_SET_CLR 2148 *(volatile uint16_t *)tft8.portDir = 0x0000; // Input state 2149 w = *(volatile uint16_t *)tft8.readPort; // 16-bit read 2150 *(volatile uint16_t *)tft8.portDir = 0xFFFF; // Output state 2151 #endif // end !HAS_PORT_SET_CLR 2152 } 2153 TFT_RD_HIGH(); // Read line HIGH 2154 #endif // end !__AVR__ 2155 #else // !USE_FAST_PINIO 2156 w = 0; // Parallel TFT is NOT SUPPORTED without USE_FAST_PINIO 2157 #endif // end !USE_FAST_PINIO 2158 } 2159 return w; 2160 } 2161 } 2162 2163 /*! 2164 @brief Issue a single 16-bit value to the display. Chip-select, 2165 transaction and data/command selection must have been 2166 previously set -- this ONLY issues the word. 2167 Thus operates ONLY on 'wide' (16-bit) parallel displays! 2168 @param w 16-bit value to write. 2169 */ 2170 void Adafruit_SPITFT::write16(uint16_t w) { 2171 if (connection == TFT_PARALLEL) { 2172 #if defined(USE_FAST_PINIO) 2173 if (tft8.wide) 2174 *(volatile uint16_t *)tft8.writePort = w; 2175 #else 2176 (void)w; // disable -Wunused-parameter warning 2177 #endif 2178 TFT_WR_STROBE(); 2179 } 2180 } 2181 2182 /*! 2183 @brief Write a single command word to the display. Chip-select and 2184 transaction must have been previously set -- this ONLY sets 2185 the device to COMMAND mode, issues the byte and then restores 2186 DATA mode. This operates ONLY on 'wide' (16-bit) parallel 2187 displays! 2188 @param cmd 16-bit command to write. 2189 */ 2190 void Adafruit_SPITFT::writeCommand16(uint16_t cmd) { 2191 SPI_DC_LOW(); 2192 write16(cmd); 2193 SPI_DC_HIGH(); 2194 } 2195 2196 /*! 2197 @brief Read a single 16-bit value from the display. Chip-select and 2198 transaction must have been previously set -- this ONLY reads 2199 the byte. This operates ONLY on 'wide' (16-bit) parallel 2200 displays! 2201 @return Unsigned 16-bit value read (always zero if USE_FAST_PINIO is 2202 not supported by the MCU architecture). 2203 */ 2204 uint16_t Adafruit_SPITFT::read16(void) { 2205 uint16_t w = 0; 2206 if (connection == TFT_PARALLEL) { 2207 if (tft8._rd >= 0) { 2208 #if defined(USE_FAST_PINIO) 2209 TFT_RD_LOW(); // Read line LOW 2210 if (tft8.wide) { // 16-bit TFT connection 2211 #if defined(HAS_PORT_SET_CLR) 2212 *(volatile uint16_t *)tft8.dirClr = 0xFFFF; // Input state 2213 w = *(volatile uint16_t *)tft8.readPort; // 16-bit read 2214 *(volatile uint16_t *)tft8.dirSet = 0xFFFF; // Output state 2215 #else // !HAS_PORT_SET_CLR 2216 *(volatile uint16_t *)tft8.portDir = 0x0000; // Input state 2217 w = *(volatile uint16_t *)tft8.readPort; // 16-bit read 2218 *(volatile uint16_t *)tft8.portDir = 0xFFFF; // Output state 2219 #endif // end !HAS_PORT_SET_CLR 2220 } 2221 TFT_RD_HIGH(); // Read line HIGH 2222 #else // !USE_FAST_PINIO 2223 w = 0; // Parallel TFT is NOT SUPPORTED without USE_FAST_PINIO 2224 #endif // end !USE_FAST_PINIO 2225 } 2226 } 2227 return w; 2228 } 2229 2230 /*! 2231 @brief Set the software (bitbang) SPI MOSI line HIGH. 2232 */ 2233 inline void Adafruit_SPITFT::SPI_MOSI_HIGH(void) { 2234 #if defined(USE_FAST_PINIO) 2235 #if defined(HAS_PORT_SET_CLR) 2236 #if defined(KINETISK) 2237 *swspi.mosiPortSet = 1; 2238 #else // !KINETISK 2239 *swspi.mosiPortSet = swspi.mosiPinMask; 2240 #endif 2241 #else // !HAS_PORT_SET_CLR 2242 *swspi.mosiPort |= swspi.mosiPinMaskSet; 2243 #endif // end !HAS_PORT_SET_CLR 2244 #else // !USE_FAST_PINIO 2245 digitalWrite(swspi._mosi, HIGH); 2246 #if defined(ESP32) 2247 for (volatile uint8_t i = 0; i < 1; i++) 2248 ; 2249 #endif // end ESP32 2250 #endif // end !USE_FAST_PINIO 2251 } 2252 2253 /*! 2254 @brief Set the software (bitbang) SPI MOSI line LOW. 2255 */ 2256 inline void Adafruit_SPITFT::SPI_MOSI_LOW(void) { 2257 #if defined(USE_FAST_PINIO) 2258 #if defined(HAS_PORT_SET_CLR) 2259 #if defined(KINETISK) 2260 *swspi.mosiPortClr = 1; 2261 #else // !KINETISK 2262 *swspi.mosiPortClr = swspi.mosiPinMask; 2263 #endif 2264 #else // !HAS_PORT_SET_CLR 2265 *swspi.mosiPort &= swspi.mosiPinMaskClr; 2266 #endif // end !HAS_PORT_SET_CLR 2267 #else // !USE_FAST_PINIO 2268 digitalWrite(swspi._mosi, LOW); 2269 #if defined(ESP32) 2270 for (volatile uint8_t i = 0; i < 1; i++) 2271 ; 2272 #endif // end ESP32 2273 #endif // end !USE_FAST_PINIO 2274 } 2275 2276 /*! 2277 @brief Set the software (bitbang) SPI SCK line HIGH. 2278 */ 2279 inline void Adafruit_SPITFT::SPI_SCK_HIGH(void) { 2280 #if defined(USE_FAST_PINIO) 2281 #if defined(HAS_PORT_SET_CLR) 2282 #if defined(KINETISK) 2283 *swspi.sckPortSet = 1; 2284 #else // !KINETISK 2285 *swspi.sckPortSet = swspi.sckPinMask; 2286 #if defined(__IMXRT1052__) || defined(__IMXRT1062__) // Teensy 4.x 2287 for (volatile uint8_t i = 0; i < 1; i++) 2288 ; 2289 #endif 2290 #endif 2291 #else // !HAS_PORT_SET_CLR 2292 *swspi.sckPort |= swspi.sckPinMaskSet; 2293 #endif // end !HAS_PORT_SET_CLR 2294 #else // !USE_FAST_PINIO 2295 digitalWrite(swspi._sck, HIGH); 2296 #if defined(ESP32) 2297 for (volatile uint8_t i = 0; i < 1; i++) 2298 ; 2299 #endif // end ESP32 2300 #endif // end !USE_FAST_PINIO 2301 } 2302 2303 /*! 2304 @brief Set the software (bitbang) SPI SCK line LOW. 2305 */ 2306 inline void Adafruit_SPITFT::SPI_SCK_LOW(void) { 2307 #if defined(USE_FAST_PINIO) 2308 #if defined(HAS_PORT_SET_CLR) 2309 #if defined(KINETISK) 2310 *swspi.sckPortClr = 1; 2311 #else // !KINETISK 2312 *swspi.sckPortClr = swspi.sckPinMask; 2313 #if defined(__IMXRT1052__) || defined(__IMXRT1062__) // Teensy 4.x 2314 for (volatile uint8_t i = 0; i < 1; i++) 2315 ; 2316 #endif 2317 #endif 2318 #else // !HAS_PORT_SET_CLR 2319 *swspi.sckPort &= swspi.sckPinMaskClr; 2320 #endif // end !HAS_PORT_SET_CLR 2321 #else // !USE_FAST_PINIO 2322 digitalWrite(swspi._sck, LOW); 2323 #if defined(ESP32) 2324 for (volatile uint8_t i = 0; i < 1; i++) 2325 ; 2326 #endif // end ESP32 2327 #endif // end !USE_FAST_PINIO 2328 } 2329 2330 /*! 2331 @brief Read the state of the software (bitbang) SPI MISO line. 2332 @return true if HIGH, false if LOW. 2333 */ 2334 inline bool Adafruit_SPITFT::SPI_MISO_READ(void) { 2335 #if defined(USE_FAST_PINIO) 2336 #if defined(KINETISK) 2337 return *swspi.misoPort; 2338 #else // !KINETISK 2339 return *swspi.misoPort & swspi.misoPinMask; 2340 #endif // end !KINETISK 2341 #else // !USE_FAST_PINIO 2342 return digitalRead(swspi._miso); 2343 #endif // end !USE_FAST_PINIO 2344 } 2345 2346 /*! 2347 @brief Issue a single 16-bit value to the display. Chip-select, 2348 transaction and data/command selection must have been 2349 previously set -- this ONLY issues the word. Despite the name, 2350 this function is used even if display connection is parallel; 2351 name was maintaned for backward compatibility. Naming is also 2352 not consistent with the 8-bit version, spiWrite(). Sorry about 2353 that. Again, staying compatible with outside code. 2354 @param w 16-bit value to write. 2355 */ 2356 void Adafruit_SPITFT::SPI_WRITE16(uint16_t w) { 2357 if (connection == TFT_HARD_SPI) { 2358 #if defined(__AVR__) 2359 AVR_WRITESPI(w >> 8); 2360 AVR_WRITESPI(w); 2361 #elif defined(ESP8266) || defined(ESP32) 2362 hwspi._spi->write16(w); 2363 #else 2364 hwspi._spi->transfer(w >> 8); 2365 hwspi._spi->transfer(w); 2366 #endif 2367 } else if (connection == TFT_SOFT_SPI) { 2368 for (uint8_t bit = 0; bit < 16; bit++) { 2369 if (w & 0x8000) 2370 SPI_MOSI_HIGH(); 2371 else 2372 SPI_MOSI_LOW(); 2373 SPI_SCK_HIGH(); 2374 SPI_SCK_LOW(); 2375 w <<= 1; 2376 } 2377 } else { // TFT_PARALLEL 2378 #if defined(__AVR__) 2379 *tft8.writePort = w >> 8; 2380 TFT_WR_STROBE(); 2381 *tft8.writePort = w; 2382 #elif defined(USE_FAST_PINIO) 2383 if (!tft8.wide) { 2384 *tft8.writePort = w >> 8; 2385 TFT_WR_STROBE(); 2386 *tft8.writePort = w; 2387 } else { 2388 *(volatile uint16_t *)tft8.writePort = w; 2389 } 2390 #endif 2391 TFT_WR_STROBE(); 2392 } 2393 } 2394 2395 /*! 2396 @brief Issue a single 32-bit value to the display. Chip-select, 2397 transaction and data/command selection must have been 2398 previously set -- this ONLY issues the longword. Despite the 2399 name, this function is used even if display connection is 2400 parallel; name was maintaned for backward compatibility. Naming 2401 is also not consistent with the 8-bit version, spiWrite(). 2402 Sorry about that. Again, staying compatible with outside code. 2403 @param l 32-bit value to write. 2404 */ 2405 void Adafruit_SPITFT::SPI_WRITE32(uint32_t l) { 2406 if (connection == TFT_HARD_SPI) { 2407 #if defined(__AVR__) 2408 AVR_WRITESPI(l >> 24); 2409 AVR_WRITESPI(l >> 16); 2410 AVR_WRITESPI(l >> 8); 2411 AVR_WRITESPI(l); 2412 #elif defined(ESP8266) || defined(ESP32) 2413 hwspi._spi->write32(l); 2414 #else 2415 hwspi._spi->transfer(l >> 24); 2416 hwspi._spi->transfer(l >> 16); 2417 hwspi._spi->transfer(l >> 8); 2418 hwspi._spi->transfer(l); 2419 #endif 2420 } else if (connection == TFT_SOFT_SPI) { 2421 for (uint8_t bit = 0; bit < 32; bit++) { 2422 if (l & 0x80000000) 2423 SPI_MOSI_HIGH(); 2424 else 2425 SPI_MOSI_LOW(); 2426 SPI_SCK_HIGH(); 2427 SPI_SCK_LOW(); 2428 l <<= 1; 2429 } 2430 } else { // TFT_PARALLEL 2431 #if defined(__AVR__) 2432 *tft8.writePort = l >> 24; 2433 TFT_WR_STROBE(); 2434 *tft8.writePort = l >> 16; 2435 TFT_WR_STROBE(); 2436 *tft8.writePort = l >> 8; 2437 TFT_WR_STROBE(); 2438 *tft8.writePort = l; 2439 #elif defined(USE_FAST_PINIO) 2440 if (!tft8.wide) { 2441 *tft8.writePort = l >> 24; 2442 TFT_WR_STROBE(); 2443 *tft8.writePort = l >> 16; 2444 TFT_WR_STROBE(); 2445 *tft8.writePort = l >> 8; 2446 TFT_WR_STROBE(); 2447 *tft8.writePort = l; 2448 } else { 2449 *(volatile uint16_t *)tft8.writePort = l >> 16; 2450 TFT_WR_STROBE(); 2451 *(volatile uint16_t *)tft8.writePort = l; 2452 } 2453 #endif 2454 TFT_WR_STROBE(); 2455 } 2456 } 2457 2458 /*! 2459 @brief Set the WR line LOW, then HIGH. Used for parallel-connected 2460 interfaces when writing data. 2461 */ 2462 inline void Adafruit_SPITFT::TFT_WR_STROBE(void) { 2463 #if defined(USE_FAST_PINIO) 2464 #if defined(HAS_PORT_SET_CLR) 2465 #if defined(KINETISK) 2466 *tft8.wrPortClr = 1; 2467 *tft8.wrPortSet = 1; 2468 #else // !KINETISK 2469 *tft8.wrPortClr = tft8.wrPinMask; 2470 *tft8.wrPortSet = tft8.wrPinMask; 2471 #endif // end !KINETISK 2472 #else // !HAS_PORT_SET_CLR 2473 *tft8.wrPort &= tft8.wrPinMaskClr; 2474 *tft8.wrPort |= tft8.wrPinMaskSet; 2475 #endif // end !HAS_PORT_SET_CLR 2476 #else // !USE_FAST_PINIO 2477 digitalWrite(tft8._wr, LOW); 2478 digitalWrite(tft8._wr, HIGH); 2479 #endif // end !USE_FAST_PINIO 2480 } 2481 2482 /*! 2483 @brief Set the RD line HIGH. Used for parallel-connected interfaces 2484 when reading data. 2485 */ 2486 inline void Adafruit_SPITFT::TFT_RD_HIGH(void) { 2487 #if defined(USE_FAST_PINIO) 2488 #if defined(HAS_PORT_SET_CLR) 2489 *tft8.rdPortSet = tft8.rdPinMask; 2490 #else // !HAS_PORT_SET_CLR 2491 *tft8.rdPort |= tft8.rdPinMaskSet; 2492 #endif // end !HAS_PORT_SET_CLR 2493 #else // !USE_FAST_PINIO 2494 digitalWrite(tft8._rd, HIGH); 2495 #endif // end !USE_FAST_PINIO 2496 } 2497 2498 /*! 2499 @brief Set the RD line LOW. Used for parallel-connected interfaces 2500 when reading data. 2501 */ 2502 inline void Adafruit_SPITFT::TFT_RD_LOW(void) { 2503 #if defined(USE_FAST_PINIO) 2504 #if defined(HAS_PORT_SET_CLR) 2505 *tft8.rdPortClr = tft8.rdPinMask; 2506 #else // !HAS_PORT_SET_CLR 2507 *tft8.rdPort &= tft8.rdPinMaskClr; 2508 #endif // end !HAS_PORT_SET_CLR 2509 #else // !USE_FAST_PINIO 2510 digitalWrite(tft8._rd, LOW); 2511 #endif // end !USE_FAST_PINIO 2512 } 2513 2514 #endif // end __AVR_ATtiny85__