arduinoprojects

git clone https://git.tarina.org/arduinoprojects
Log | Files | Refs

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__