diff --git a/Adafruit_SPITFT.cpp b/Adafruit_SPITFT.cpp
index 559c431..d48750d 100644
--- a/Adafruit_SPITFT.cpp
+++ b/Adafruit_SPITFT.cpp
@@ -1,205 +1,438 @@
/*!
-* @file Adafruit_SPITFT.cpp
-*
-* @mainpage Adafruit SPI TFT Displays
-*
-* @section intro_sec Introduction
-* This is our library for SPI TFT Displays with address windows and 16-bit
-* color (e.g. ILI9341, HX8357D, ST7735...)
-*
-* These displays use SPI to communicate, 4 or 5 pins are required to
-* interface (RST is optional)
-* Adafruit invests time and resources providing this open source code,
-* please support Adafruit and open-source hardware by purchasing
-* products from Adafruit!
+ * @file Adafruit_SPITFT.cpp
+ *
+ * @mainpage Adafruit SPI TFT Displays (and some others)
+ *
+ * @section intro_sec Introduction
+ *
+ * Part of Adafruit's GFX graphics library. Originally this class was
+ * written to handle a range of color TFT displays connected via SPI,
+ * but over time this library and some display-specific subclasses have
+ * mutated to include some color OLEDs as well as parallel-interfaced
+ * displays. The name's been kept for the sake of older code.
+ *
+ * Adafruit invests time and resources providing this open source code,
+ * please support Adafruit and open-source hardware by purchasing
+ * products from Adafruit!
-* Written by Limor Fried/Ladyada for Adafruit Industries.
-* MIT license, all text above must be included in any redistribution
-* @section dependencies Dependencies
-*
-* This library depends on
-* Adafruit_GFX being present on your system. Please make sure you have
-* installed the latest version before using this library.
-*
-* @section author Author
-*
-* Written by Limor "ladyada" Fried for Adafruit Industries.
-*
-* @section license License
-*
-* BSD license, all text here must be included in any redistribution.
-*
-*/
+ * @section dependencies Dependencies
+ *
+ * This library depends on
+ * Adafruit_GFX being present on your system. Please make sure you have
+ * installed the latest version before using this library.
+ *
+ * @section author Author
+ *
+ * Written by Limor "ladyada" Fried for Adafruit Industries,
+ * with contributions from the open source community.
+ *
+ * @section license License
+ *
+ * BSD license, all text here must be included in any redistribution.
+ */
-#if !defined(__AVR_ATtiny85__) // NOT A CHANCE of this stuff working on ATtiny
+#if !defined(__AVR_ATtiny85__) // Not for ATtiny, at all
#include "Adafruit_SPITFT.h"
-#if !defined(ARDUINO_STM32_FEATHER)
- #include "pins_arduino.h"
-#endif
-#if !defined(ARDUINO_STM32_FEATHER) && !defined(RASPI)
- #include "wiring_private.h"
-#endif
-#include
-#ifdef PORT_IOBUS
+#if defined(PORT_IOBUS)
// On SAMD21, redefine digitalPinToPort() to use the slightly-faster
// PORT_IOBUS rather than PORT (not needed on SAMD51).
#undef digitalPinToPort
#define digitalPinToPort(P) (&(PORT_IOBUS->Group[g_APinDescription[P].ulPort]))
-#endif
+#endif // end PORT_IOBUS
-#include "Adafruit_SPITFT_Macros.h"
-
-#ifdef USE_SPI_DMA
+#if defined(USE_SPI_DMA)
#include
#include // memalign() function
// DMA transfer-in-progress indicator and callback
-static volatile boolean dma_busy = false;
+static volatile bool dma_busy = false;
static void dma_callback(Adafruit_ZeroDMA *dma) {
dma_busy = false;
}
+#endif // end USE_SPI_DMA
-#endif // USE_SPI_DMA
+// Possible values for Adafruit_SPITFT.connection:
+#define TFT_HARD_SPI 0 ///< Display interface = hardware SPI
+#define TFT_SOFT_SPI 1 ///< Display interface = software SPI
+#define TFT_PARALLEL 2 ///< Display interface = 8- or 16-bit parallel
+
+
+// CONSTRUCTORS ------------------------------------------------------------
-/**************************************************************************/
/*!
- @brief Pass 8-bit (each) R,G,B, get back 16-bit packed color
- This function converts 8-8-8 RGB data to 16-bit 5-6-5
- @param red Red 8 bit color
- @param green Green 8 bit color
- @param blue Blue 8 bit color
- @return Unsigned 16-bit down-sampled color in 5-6-5 format
+ @brief Adafruit_SPITFT constructor for software (bitbang) SPI.
+ @param w Display width in pixels at default rotation setting (0).
+ @param h Display height in pixels at default rotation setting (0).
+ @param cs Arduino pin # for chip-select (-1 if unused, tie CS low).
+ @param dc Arduino pin # for data/command select (required).
+ @param mosi Arduino pin # for bitbang SPI MOSI signal (required).
+ @param sck Arduino pin # for bitbang SPI SCK signal (required).
+ @param rst Arduino pin # for display reset (optional, display reset
+ can be tied to MCU reset, default of -1 means unused).
+ @param miso Arduino pin # for bitbang SPI MISO signal (optional,
+ -1 default, many displays don't support SPI read).
+ @return Adafruit_SPITFT object.
+ @note Output pins are not initialized; application typically will need
+ to call subclass' begin() function, which in turn calls this
+ library's initSPI() function to initialize pins.
*/
-/**************************************************************************/
-uint16_t Adafruit_SPITFT::color565(uint8_t red, uint8_t green, uint8_t blue) {
- return ((red & 0xF8) << 8) | ((green & 0xFC) << 3) | ((blue & 0xF8) >> 3);
-}
-
-
-/**************************************************************************/
-/*!
- @brief Instantiate Adafruit SPI display driver with software SPI
- @param w Display width in pixels
- @param h Display height in pixels
- @param cs Chip select pin #
- @param dc Data/Command pin #
- @param mosi SPI MOSI pin #
- @param sclk SPI Clock pin #
- @param rst Reset pin # (optional, pass -1 if unused)
- @param miso SPI MISO pin # (optional, pass -1 if unused)
-*/
-/**************************************************************************/
Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h,
- int8_t cs, int8_t dc, int8_t mosi,
- int8_t sclk, int8_t rst, int8_t miso)
- : Adafruit_GFX(w, h) {
- _cs = cs;
- _dc = dc;
- _rst = rst;
- _sclk = sclk;
- _mosi = mosi;
- _miso = miso;
- _freq = 0;
-#ifdef USE_FAST_PINIO
- dcport = (RwReg *)portOutputRegister(digitalPinToPort(dc));
- dcpinmask = digitalPinToBitMask(dc);
- clkport = (RwReg *)portOutputRegister(digitalPinToPort(sclk));
- clkpinmask = digitalPinToBitMask(sclk);
- mosiport = (RwReg *)portOutputRegister(digitalPinToPort(mosi));
- mosipinmask = digitalPinToBitMask(mosi);
- if(miso >= 0){
- misoport = (RwReg *)portInputRegister(digitalPinToPort(miso));
- misopinmask = digitalPinToBitMask(miso);
- } else {
- misoport = 0;
- misopinmask = 0;
- }
+ int8_t cs, int8_t dc, int8_t mosi, int8_t sck, int8_t rst, int8_t miso) :
+ Adafruit_GFX(w, h), connection(TFT_SOFT_SPI), _rst(rst), _cs(cs), _dc(dc) {
+ swspi._sck = sck;
+ swspi._mosi = mosi;
+ swspi._miso = miso;
+#if defined(USE_FAST_PINIO)
+ #if defined(HAS_PORT_SET_CLR)
+ #if defined(CORE_TEENSY)
+ dcPortSet = portSetRegister(dc);
+ dcPortClr = portClearRegister(dc);
+ swspi.sckPortSet = portSetRegister(sck);
+ swspi.sckPortClr = portClearRegister(sck);
+ swspi.mosiPortSet = portSetRegister(mosi);
+ swspi.mosiPortClr = portClearRegister(mosi);
if(cs >= 0) {
- csport = (RwReg *)portOutputRegister(digitalPinToPort(cs));
- cspinmask = digitalPinToBitMask(cs);
+ csPortSet = portSetRegister(cs);
+ csPortClr = portClearRegister(cs);
+ } else {
+ csPortSet = dcPortSet;
+ csPortClr = dcPortClr;
+ }
+ if(miso >= 0) {
+ swspi.misoPort = portInputRegister(miso);
+ } else {
+ swspi.misoPort = portInputRegister(dc);
+ }
+ #else // !CORE_TEENSY
+ dcPinMask =digitalPinToBitMask(dc);
+ swspi.sckPinMask =digitalPinToBitMask(sck);
+ swspi.mosiPinMask=digitalPinToBitMask(mosi);
+ dcPortSet =&(PORT->Group[g_APinDescription[dc].ulPort].OUTSET.reg);
+ dcPortClr =&(PORT->Group[g_APinDescription[dc].ulPort].OUTCLR.reg);
+ swspi.sckPortSet =&(PORT->Group[g_APinDescription[sck].ulPort].OUTSET.reg);
+ swspi.sckPortClr =&(PORT->Group[g_APinDescription[sck].ulPort].OUTCLR.reg);
+ swspi.mosiPortSet=&(PORT->Group[g_APinDescription[mosi].ulPort].OUTSET.reg);
+ swspi.mosiPortClr=&(PORT->Group[g_APinDescription[mosi].ulPort].OUTCLR.reg);
+ if(cs >= 0) {
+ csPinMask = digitalPinToBitMask(cs);
+ csPortSet = &(PORT->Group[g_APinDescription[cs].ulPort].OUTSET.reg);
+ csPortClr = &(PORT->Group[g_APinDescription[cs].ulPort].OUTCLR.reg);
} else {
// No chip-select line defined; might be permanently tied to GND.
// Assign a valid GPIO register (though not used for CS), and an
// empty pin bitmask...the nonsense bit-twiddling might be faster
// than checking _cs and possibly branching.
- csport = dcport;
- cspinmask = 0;
+ csPortSet = dcPortSet;
+ csPortClr = dcPortClr;
+ csPinMask = 0;
}
-#endif
-}
-
-/**************************************************************************/
-/*!
- @brief Instantiate Adafruit SPI display driver with hardware SPI
- @param w Display width in pixels
- @param h Display height in pixels
- @param cs Chip select pin #
- @param dc Data/Command pin #
- @param rst Reset pin # (optional, pass -1 if unused)
-*/
-/**************************************************************************/
-Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h,
- int8_t cs, int8_t dc, int8_t rst)
- : Adafruit_SPITFT(w, h, &SPI, cs, dc, rst)
-{
- // We just call the hardware SPI instantiator with the default SPI device (&SPI)
-}
-
-/**************************************************************************/
-/*!
- @brief Instantiate Adafruit SPI display driver with hardware SPI
- @param w Display width in pixels
- @param h Display height in pixels
- @param spiClass A pointer to an SPI hardware interface, e.g. &SPI1
- @param cs Chip select pin #
- @param dc Data/Command pin #
- @param rst Reset pin # (optional, pass -1 if unused)
-*/
-/**************************************************************************/
-Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, SPIClass *spiClass,
- int8_t cs, int8_t dc, int8_t rst)
- : Adafruit_GFX(w, h) {
- _cs = cs;
- _dc = dc;
- _rst = rst;
- _spi = spiClass;
- _sclk = -1;
- _mosi = -1;
- _miso = -1;
- _freq = 0;
-#ifdef USE_FAST_PINIO
- clkport = 0;
- clkpinmask = 0;
- mosiport = 0;
- mosipinmask = 0;
- misoport = 0;
- misopinmask = 0;
- dcport = (RwReg *)portOutputRegister(digitalPinToPort(dc));
- dcpinmask = digitalPinToBitMask(dc);
- if(cs >= 0) {
- csport = (RwReg *)portOutputRegister(digitalPinToPort(cs));
- cspinmask = digitalPinToBitMask(cs);
+ if(miso >= 0) {
+ swspi.misoPinMask=digitalPinToBitMask(miso);
+ swspi.misoPort =(PORTreg_t)portInputRegister(digitalPinToPort(miso));
} else {
- // See notes in prior constructor.
- csport = dcport;
- cspinmask = 0;
+ swspi.misoPinMask=0;
+ swspi.misoPort =(PORTreg_t)portInputRegister(digitalPinToPort(dc));
}
-#endif
+ #endif // end !CORE_TEENSY
+ #else // !HAS_PORT_SET_CLR
+ dcPort =(PORTreg_t)portOutputRegister(digitalPinToPort(dc));
+ dcPinMaskSet =digitalPinToBitMask(dc);
+ swspi.sckPort =(PORTreg_t)portOutputRegister(digitalPinToPort(sck));
+ swspi.sckPinMaskSet =digitalPinToBitMask(sck);
+ swspi.mosiPort =(PORTreg_t)portOutputRegister(digitalPinToPort(mosi));
+ swspi.mosiPinMaskSet=digitalPinToBitMask(mosi);
+ if(cs >= 0) {
+ csPort = (PORTreg_t)portOutputRegister(digitalPinToPort(cs));
+ csPinMaskSet = digitalPinToBitMask(cs);
+ } else {
+ // No chip-select line defined; might be permanently tied to GND.
+ // Assign a valid GPIO register (though not used for CS), and an
+ // empty pin bitmask...the nonsense bit-twiddling might be faster
+ // than checking _cs and possibly branching.
+ csPort = dcPort;
+ csPinMaskSet = 0;
+ }
+ if(miso >= 0) {
+ swspi.misoPort =(PORTreg_t)portInputRegister(digitalPinToPort(miso));
+ swspi.misoPinMask=digitalPinToBitMask(cs);
+ } else {
+ swspi.misoPort =(PORTreg_t)portInputRegister(digitalPinToPort(dc));
+ swspi.misoPinMask=0;
+ }
+ csPinMaskClr = ~csPinMaskSet;
+ dcPinMaskClr = ~dcPinMaskSet;
+ swspi.sckPinMaskClr = ~swspi.sckPinMaskSet;
+ swspi.mosiPinMaskClr = ~swspi.mosiPinMaskSet;
+ #endif // !end HAS_PORT_SET_CLR
+#endif // end USE_FAST_PINIO
}
-
-/**************************************************************************/
/*!
- @brief Initialiaze the SPI interface (hardware or software)
- @param freq The desired maximum SPI hardware clock frequency
+ @brief Adafruit_SPITFT constructor for hardware SPI using the board's
+ default SPI peripheral.
+ @param w Display width in pixels at default rotation setting (0).
+ @param h Display height in pixels at default rotation setting (0).
+ @param cs Arduino pin # for chip-select (-1 if unused, tie CS low).
+ @param dc Arduino pin # for data/command select (required).
+ @param rst Arduino pin # for display reset (optional, display reset
+ can be tied to MCU reset, default of -1 means unused).
+ @return Adafruit_SPITFT object.
+ @note Output pins are not initialized; application typically will need
+ to call subclass' begin() function, which in turn calls this
+ library's initSPI() function to initialize pins.
*/
-/**************************************************************************/
-void Adafruit_SPITFT::initSPI(uint32_t freq) {
- _freq = freq;
+Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, int8_t cs,
+ int8_t dc, int8_t rst) : Adafruit_SPITFT(w, h, &SPI, cs, dc, rst) {
+ // This just invokes the hardware SPI constructor below,
+ // passing the default SPI device (&SPI).
+}
- // Control Pins
+/*!
+ @brief Adafruit_SPITFT constructor for hardware SPI using a specific
+ SPI peripheral.
+ @param w Display width in pixels at default rotation (0).
+ @param h Display height in pixels at default rotation (0).
+ @param spiClass Pointer to SPIClass type (e.g. &SPI1).
+ @param cs Arduino pin # for chip-select (-1 if unused, tie CS low).
+ @param dc Arduino pin # for data/command select (required).
+ @param rst Arduino pin # for display reset (optional, display reset
+ can be tied to MCU reset, default of -1 means unused).
+ @return Adafruit_SPITFT object.
+ @note Output pins are not initialized; application typically will need
+ to call subclass' begin() function, which in turn calls this
+ library's initSPI() function to initialize pins.
+*/
+Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, SPIClass *spiClass,
+ int8_t cs, int8_t dc, int8_t rst) : Adafruit_GFX(w, h),
+ connection(TFT_HARD_SPI), _rst(rst), _cs(cs), _dc(dc) {
+ hwspi._spi = spiClass;
+#if defined(USE_FAST_PINIO)
+ #if defined(HAS_PORT_SET_CLR)
+ #if defined(CORE_TEENSY)
+ dcPortSet =portSetRegister(dc);
+ dcPortClr =portClearRegister(dc);
+ if(cs >= 0) {
+ csPinMask=digitalPinToBitMask(cs);
+ csPortSet=portSetRegister(cs);
+ csPortClr=portClearRegister(dc);
+ } else { // see comments below
+ csPortSet = dcPortSet;
+ csPortClr = dcPortClr;
+ csPinMask = 0;
+ }
+ #else // !CORE_TEENSY
+ dcPinMask =digitalPinToBitMask(dc);
+ dcPortSet =&(PORT->Group[g_APinDescription[dc].ulPort].OUTSET.reg);
+ dcPortClr =&(PORT->Group[g_APinDescription[dc].ulPort].OUTCLR.reg);
+ if(cs >= 0) {
+ csPinMask=digitalPinToBitMask(cs);
+ csPortSet=&(PORT->Group[g_APinDescription[cs].ulPort].OUTSET.reg);
+ csPortClr=&(PORT->Group[g_APinDescription[cs].ulPort].OUTCLR.reg);
+ } else {
+ // No chip-select line defined; might be permanently tied to GND.
+ // Assign a valid GPIO register (though not used for CS), and an
+ // empty pin bitmask...the nonsense bit-twiddling might be faster
+ // than checking _cs and possibly branching.
+ csPortSet = dcPortSet;
+ csPortClr = dcPortClr;
+ csPinMask = 0;
+ }
+ #endif // end !CORE_TEENSY
+ #else // !HAS_PORT_SET_CLR
+ dcPort = (PORTreg_t)portOutputRegister(digitalPinToPort(dc));
+ dcPinMaskSet = digitalPinToBitMask(dc);
+ if(cs >= 0) {
+ csPort = (PORTreg_t)portOutputRegister(digitalPinToPort(cs));
+ csPinMaskSet = digitalPinToBitMask(cs);
+ } else {
+ // No chip-select line defined; might be permanently tied to GND.
+ // Assign a valid GPIO register (though not used for CS), and an
+ // empty pin bitmask...the nonsense bit-twiddling might be faster
+ // than checking _cs and possibly branching.
+ csPort = dcPort;
+ csPinMaskSet = 0;
+ }
+ csPinMaskClr = ~csPinMaskSet;
+ dcPinMaskClr = ~dcPinMaskSet;
+ #endif // end !HAS_PORT_SET_CLR
+#endif // end USE_FAST_PINIO
+}
+
+/*!
+ @brief Adafruit_SPITFT constructor for parallel display connection.
+ @param w Display width in pixels at default rotation (0).
+ @param h Display height in pixels at default rotation (0).
+
+ @param wide If true, is a 16-bit parallel connection, else 8-bit.
+ 16-bit isn't fully implemented or tested yet so
+ applications should pass "false" for now...needed to
+ stick a required boolean argument in there to
+ disambiguate this constructor from the soft-SPI case.
+ Argument is ignored on 8-bit architectures (no 'wide'
+ support there since PORTs are 8 bits anyway).
+ @param d0 Arduino pin # for data bit 0 (1+ are extrapolated).
+ The 8 (or 16) data bits MUST be contiguous and byte-
+ aligned (or word-aligned for wide interface) within the
+ same PORT register (might not correspond to Arduino pin
+ sequence).
+ @param wr Arduino pin # for write strobe (required).
+ @param dc Arduino pin # for data/command select (required).
+ @param cs Arduino pin # for chip-select (optional, -1 if unused,
+ tie CS low).
+ @param rst Arduino pin # for display reset (optional, display reset
+ can be tied to MCU reset, default of -1 means unused).
+ @param wr Arduino pin # for read strobe (optional, -1 if unused).
+ @return Adafruit_SPITFT object.
+ @note Output pins are not initialized; application typically will need
+ to call subclass' begin() function, which in turn calls this
+ library's initSPI() function to initialize pins.
+ Yes, the name is a misnomer...this library originally handled
+ only SPI displays, parallel being a recent addition (but not
+ wanting to break existing code).
+*/
+Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, bool wide,
+ int8_t d0, int8_t wr, int8_t dc, int8_t cs, int8_t rst, int8_t rd) :
+ Adafruit_GFX(w, h), connection(TFT_PARALLEL), _rst(rst), _cs(cs), _dc(dc) {
+ tft8._d0 = d0;
+ tft8._wr = wr;
+ tft8._rd = rd;
+ tft8.wide = wide;
+#if defined(USE_FAST_PINIO)
+ #if defined(HAS_PORT_SET_CLR)
+ #if defined(CORE_TEENSY)
+ tft8.wrPortSet =portSetRegister(wr);
+ tft8.wrPortClr =portClearRegister(wr);
+ dcPortSet =portSetRegister(dc);
+ dcPortClr =portClearRegister(dc);
+ if(cs >= 0) {
+ csPinMask=digitalPinToBitMask(cs);
+ csPortSet=portSetRegister(cs);
+ csPortClr=portClearRegister(cs);
+ } else { // see comments below
+ csPortSet = dcPortSet;
+ csPortClr = dcPortClr;
+ csPinMask = 0;
+ }
+ if(rd >= 0) { // if read-strobe pin specified...
+ #if defined(KINETISK)
+ tft8.rdPinMask = 1;
+ #else // !KINETISK
+ tft8.rdPinMask = digitalPinToBitMask(rd);
+ #endif
+ tft8.rdPortSet = portSetRegister(rd);
+ tft8.rdPortClr = portClearRegister(rd);
+ } else {
+ tft8.rdPinMask = 0;
+ tft8.rdPortSet = dcPortSet;
+ tft8.rdPortClr = dcPortClr;
+ }
+ // These are all uint8_t* pointers -- elsewhere they're recast
+ // as necessary if a 'wide' 16-bit interface is in use.
+ tft8.writePort = portOutputRegister(d0);
+ tft8.readPort = portInputRegister(d0);
+ tft8.dirSet = portModeRegister(d0);
+ tft8.dirClr = portModeRegister(d0);
+ #else // !CORE_TEENSY
+ tft8.wrPinMask =digitalPinToBitMask(wr);
+ tft8.wrPortSet =&(PORT->Group[g_APinDescription[wr].ulPort].OUTSET.reg);
+ tft8.wrPortClr =&(PORT->Group[g_APinDescription[wr].ulPort].OUTCLR.reg);
+ dcPinMask =digitalPinToBitMask(dc);
+ dcPortSet =&(PORT->Group[g_APinDescription[dc].ulPort].OUTSET.reg);
+ dcPortClr =&(PORT->Group[g_APinDescription[dc].ulPort].OUTCLR.reg);
+ if(cs >= 0) {
+ csPinMask=digitalPinToBitMask(cs);
+ csPortSet=&(PORT->Group[g_APinDescription[cs].ulPort].OUTSET.reg);
+ csPortClr=&(PORT->Group[g_APinDescription[cs].ulPort].OUTCLR.reg);
+ } else {
+ // No chip-select line defined; might be permanently tied to GND.
+ // Assign a valid GPIO register (though not used for CS), and an
+ // empty pin bitmask...the nonsense bit-twiddling might be faster
+ // than checking _cs and possibly branching.
+ csPortSet = dcPortSet;
+ csPortClr = dcPortClr;
+ csPinMask = 0;
+ }
+ if(rd >= 0) { // if read-strobe pin specified...
+ tft8.rdPinMask =digitalPinToBitMask(rd);
+ tft8.rdPortSet =&(PORT->Group[g_APinDescription[rd].ulPort].OUTSET.reg);
+ tft8.rdPortClr =&(PORT->Group[g_APinDescription[rd].ulPort].OUTCLR.reg);
+ } else {
+ tft8.rdPinMask = 0;
+ tft8.rdPortSet = dcPortSet;
+ tft8.rdPortClr = dcPortClr;
+ }
+ // Get pointers to PORT write/read/dir bytes within 32-bit PORT
+ uint8_t dBit = g_APinDescription[d0].ulPin; // d0 bit # in PORT
+ PortGroup *p = (&(PORT->Group[g_APinDescription[d0].ulPort]));
+ uint8_t offset = dBit / 8; // d[7:0] byte # within PORT
+ if(wide) offset &= ~1; // d[15:8] byte # within PORT
+ // These are all uint8_t* pointers -- elsewhere they're recast
+ // as necessary if a 'wide' 16-bit interface is in use.
+ tft8.writePort = (volatile uint8_t *)&(p->OUT.reg) + offset;
+ tft8.readPort = (volatile uint8_t *)&(p->IN.reg) + offset;
+ tft8.dirSet = (volatile uint8_t *)&(p->DIRSET.reg) + offset;
+ tft8.dirClr = (volatile uint8_t *)&(p->DIRCLR.reg) + offset;
+ #endif // end !CORE_TEENSY
+ #else // !HAS_PORT_SET_CLR
+ tft8.wrPort =(PORTreg_t)portOutputRegister(digitalPinToPort(wr));
+ tft8.wrPinMaskSet =digitalPinToBitMask(wr);
+ dcPort =(PORTreg_t)portOutputRegister(digitalPinToPort(dc));
+ dcPinMaskSet =digitalPinToBitMask(dc);
+ if(cs >= 0) {
+ csPort = (PORTreg_t)portOutputRegister(digitalPinToPort(cs));
+ csPinMaskSet = digitalPinToBitMask(cs);
+ } else {
+ // No chip-select line defined; might be permanently tied to GND.
+ // Assign a valid GPIO register (though not used for CS), and an
+ // empty pin bitmask...the nonsense bit-twiddling might be faster
+ // than checking _cs and possibly branching.
+ csPort = dcPort;
+ csPinMaskSet = 0;
+ }
+ if(rd >= 0) { // if read-strobe pin specified...
+ tft8.rdPort =(PORTreg_t)portOutputRegister(digitalPinToPort(rd));
+ tft8.rdPinMaskSet =digitalPinToBitMask(rd);
+ } else {
+ tft8.rdPort = dcPort;
+ tft8.rdPinMaskSet = 0;
+ }
+ csPinMaskClr = ~csPinMaskSet;
+ dcPinMaskClr = ~dcPinMaskSet;
+ tft8.wrPinMaskClr = ~tft8.wrPinMaskSet;
+ tft8.rdPinMaskClr = ~tft8.rdPinMaskSet;
+ tft8.writePort = (PORTreg_t)portOutputRegister(digitalPinToPort(d0));
+ tft8.readPort = (PORTreg_t)portInputRegister(digitalPinToPort(d0));
+ tft8.portDir = (PORTreg_t)portModeRegister(digitalPinToPort(d0));
+ #endif // end !HAS_PORT_SET_CLR
+#endif // end USE_FAST_PINIO
+}
+
+// end constructors -------
+
+
+// CLASS MEMBER FUNCTIONS --------------------------------------------------
+
+// begin() and setAddrWindow() MUST be declared by any subclass.
+
+/*!
+ @brief Configure microcontroller pins for TFT interfacing. Typically
+ called by a subclass' begin() function.
+ @param freq SPI frequency when using hardware SPI. If default (0)
+ is passed, will fall back on a device-specific value.
+ Value is ignored when using software SPI or parallel
+ connection.
+ @note Another anachronistically-named function; this is called even
+ when the display connection is parallel (not SPI). Also, this
+ could probably be made private...quite a few class functions
+ were generously put in the public section.
+*/
+void Adafruit_SPITFT::initSPI(uint32_t freq) {
+
+ if(!freq) freq = DEFAULT_SPI_FREQ; // If no freq specified, use default
+
+ // Init basic control pins common to all connection types
if(_cs >= 0) {
pinMode(_cs, OUTPUT);
digitalWrite(_cs, HIGH); // Deselect
@@ -207,22 +440,73 @@ void Adafruit_SPITFT::initSPI(uint32_t freq) {
pinMode(_dc, OUTPUT);
digitalWrite(_dc, LOW);
- // Software SPI
- if(_sclk >= 0){
- pinMode(_mosi, OUTPUT);
- digitalWrite(_mosi, LOW);
- pinMode(_sclk, OUTPUT);
- digitalWrite(_sclk, HIGH);
- if(_miso >= 0){
- pinMode(_miso, INPUT);
+ switch(connection) {
+ case TFT_HARD_SPI:
+#if defined(SPI_HAS_TRANSACTION)
+ hwspi._spi->begin();
+ hwspi.settings = SPISettings(freq, MSBFIRST, SPI_MODE0);
+#else
+ hwspi._freq = freq; // Save freq value for later
+ hwspi._spi->begin();
+#endif
+ break;
+ case TFT_SOFT_SPI:
+ pinMode(swspi._mosi, OUTPUT);
+ digitalWrite(swspi._mosi, LOW);
+ pinMode(swspi._sck, OUTPUT);
+ digitalWrite(swspi._sck, LOW);
+ if(swspi._miso >= 0) {
+ pinMode(swspi._miso, INPUT);
}
+ break;
+ case TFT_PARALLEL:
+ // Initialize data pins. We were only passed d0, so scan
+ // the pin description list looking for the other pins.
+ // They'll be on the same PORT, and within the next 7 (or 15) bits
+ // (because we need to write to a contiguous PORT byte or word).
+#if defined(__AVR__)
+ // PORT registers are 8 bits wide, so just need a register match...
+ for(uint8_t i=0; i= dBit ) &&
+ (g_APinDescription[i].ulPin <= (uint32_t)lastBit)) {
+ pinMode(i, OUTPUT);
+ digitalWrite(i, LOW);
+ }
+ }
+ #endif // end !CORE_TEENSY
+#endif
+ pinMode(tft8._wr, OUTPUT);
+ digitalWrite(tft8._wr, HIGH);
+ if(tft8._rd >= 0) {
+ pinMode(tft8._rd, OUTPUT);
+ digitalWrite(tft8._rd, HIGH);
+ }
+ break;
}
- // Hardware SPI
- SPI_BEGIN();
-
- // toggle RST low to reset
- if (_rst >= 0) {
+ if(_rst >= 0) {
+ // Toggle _rst low to reset
pinMode(_rst, OUTPUT);
digitalWrite(_rst, HIGH);
delay(100);
@@ -232,7 +516,7 @@ void Adafruit_SPITFT::initSPI(uint32_t freq) {
delay(200);
}
-#ifdef USE_SPI_DMA
+#if defined(USE_SPI_DMA)
// INITIALIZE DMA
@@ -282,31 +566,31 @@ void Adafruit_SPITFT::initSPI(uint32_t freq) {
// on that structure not changing nor the compiler
// rearranging things. Oh the humanity!
- if(*(SERCOM **)_spi == &sercom0) {
+ if(*(SERCOM **)hwspi._spi == &sercom0) {
dmac_id = SERCOM0_DMAC_ID_TX;
data_reg = &SERCOM0->SPI.DATA.reg;
#if defined SERCOM1
- } else if(*(SERCOM **)_spi == &sercom1) {
+ } else if(*(SERCOM **)hwspi._spi == &sercom1) {
dmac_id = SERCOM1_DMAC_ID_TX;
data_reg = &SERCOM1->SPI.DATA.reg;
#endif
#if defined SERCOM2
- } else if(*(SERCOM **)_spi == &sercom2) {
+ } else if(*(SERCOM **)hwspi._spi == &sercom2) {
dmac_id = SERCOM2_DMAC_ID_TX;
data_reg = &SERCOM2->SPI.DATA.reg;
#endif
#if defined SERCOM3
- } else if(*(SERCOM **)_spi == &sercom3) {
+ } else if(*(SERCOM **)hwspi._spi == &sercom3) {
dmac_id = SERCOM3_DMAC_ID_TX;
data_reg = &SERCOM3->SPI.DATA.reg;
#endif
#if defined SERCOM4
- } else if(*(SERCOM **)_spi == &sercom4) {
+ } else if(*(SERCOM **)hwspi._spi == &sercom4) {
dmac_id = SERCOM4_DMAC_ID_TX;
data_reg = &SERCOM4->SPI.DATA.reg;
#endif
#if defined SERCOM5
- } else if(*(SERCOM **)_spi == &sercom5) {
+ } else if(*(SERCOM **)hwspi._spi == &sercom5) {
dmac_id = SERCOM5_DMAC_ID_TX;
data_reg = &SERCOM5->SPI.DATA.reg;
#endif
@@ -349,112 +633,69 @@ void Adafruit_SPITFT::initSPI(uint32_t freq) {
#endif // end DMA init
}
-/**************************************************************************/
/*!
- @brief Read one byte from SPI interface (hardware or software)
- @returns One byte, MSB order
+ @brief Call before issuing command(s) or data to display. Performs
+ chip-select (if required) and starts an SPI transaction (if
+ using hardware SPI and transactions are supported). Required
+ for all display types; not an SPI-specific function.
*/
-/**************************************************************************/
-uint8_t Adafruit_SPITFT::spiRead() {
- if(_sclk < 0){
- return HSPI_READ();
- }
- if(_miso < 0){
- return 0;
- }
- uint8_t r = 0;
- for (uint8_t i=0; i<8; i++) {
- SSPI_SCK_LOW();
- SSPI_SCK_HIGH();
- r <<= 1;
- if (SSPI_MISO_READ()){
- r |= 0x1;
- }
- }
- return r;
+void Adafruit_SPITFT::startWrite(void) {
+ if(_cs >= 0) SPI_CS_LOW();
+ SPI_BEGIN_TRANSACTION();
}
-/**************************************************************************/
/*!
- @brief Write one byte to SPI interface (hardware or software)
- @param b One byte to send, MSB order
+ @brief Call after issuing command(s) or data to display. Performs
+ chip-deselect (if required) and ends an SPI transaction (if
+ using hardware SPI and transactions are supported). Required
+ for all display types; not an SPI-specific function.
*/
-/**************************************************************************/
-void Adafruit_SPITFT::spiWrite(uint8_t b) {
- if(_sclk < 0){
- HSPI_WRITE(b);
+void Adafruit_SPITFT::endWrite(void) {
+ SPI_END_TRANSACTION();
+ if(_cs >= 0) SPI_CS_HIGH();
+}
+
+
+// -------------------------------------------------------------------------
+// Lower-level graphics operations. These functions require a chip-select
+// and/or SPI transaction around them (via startWrite(), endWrite() above).
+// Higher-level graphics primitives might start a single transaction and
+// then make multiple calls to these functions (e.g. circle or text
+// rendering might make repeated lines or rects) before ending the
+// transaction. It's more efficient than starting a transaction every time.
+
+/*!
+ @brief Draw a single pixel to the display at requested coordinates.
+ Not self-contained; should follow a startWrite() call.
+ @param x Horizontal position (0 = left).
+ @param y Vertical position (0 = top).
+ @param color 16-bit pixel color in '565' RGB format.
+*/
+void Adafruit_SPITFT::writePixel(int16_t x, int16_t y, uint16_t color) {
+ if((x >= 0) && (x < _width) && (y >= 0) && (y < _height)) {
+ setAddrWindow(x, y, 1, 1);
+ SPI_WRITE16(color);
+ }
+}
+
+/*!
+ @brief Issue a series of pixels from memory to the display. Not self-
+ contained; should follow startWrite() and setAddrWindow() calls.
+ @param colors Pointer to array of 16-bit pixel values in '565' RGB
+ format.
+ @param len Number of elements in 'colors' array.
+*/
+void Adafruit_SPITFT::writePixels(uint16_t *colors, uint32_t len) {
+
+ if(!len) return; // Avoid 0-byte transfers
+
+#if defined(ESP32) // ESP32 has a special SPI pixel-writing function...
+ if(connection == TFT_HARD_SPI) {
+ hwspi._spi->writePixels(colors, len * 2);
return;
}
- for(uint8_t bit = 0x80; bit; bit >>= 1){
- if((b) & bit){
- SSPI_MOSI_HIGH();
- } else {
- SSPI_MOSI_LOW();
- }
- SSPI_SCK_LOW();
- SSPI_SCK_HIGH();
- }
-}
-
-
-/*
- * Transaction API
- * */
-
-/**************************************************************************/
-/*!
- @brief Begin an SPI transaction & set CS low.
-*/
-/**************************************************************************/
-void inline Adafruit_SPITFT::startWrite(void){
- SPI_BEGIN_TRANSACTION();
- SPI_CS_LOW();
-}
-
-/**************************************************************************/
-/*!
- @brief Begin an SPI transaction & set CS high.
-*/
-/**************************************************************************/
-void inline Adafruit_SPITFT::endWrite(void){
- SPI_CS_HIGH();
- SPI_END_TRANSACTION();
-}
-
-/**************************************************************************/
-/*!
- @brief Write a command byte (must have a transaction in progress)
- @param cmd The 8-bit command to send
-*/
-/**************************************************************************/
-void Adafruit_SPITFT::writeCommand(uint8_t cmd){
- SPI_DC_LOW();
- spiWrite(cmd);
- SPI_DC_HIGH();
-}
-
-/**************************************************************************/
-/*!
- @brief Push a 2-byte color to the framebuffer RAM, will start transaction
- @param color 16-bit 5-6-5 Color to draw
-*/
-/**************************************************************************/
-void Adafruit_SPITFT::pushColor(uint16_t color) {
- startWrite();
- SPI_WRITE16(color);
- endWrite();
-}
-
-/**************************************************************************/
-/*!
- @brief Blit multiple 2-byte colors (must have a transaction in progress)
- @param colors Array of 16-bit 5-6-5 Colors to draw
- @param len How many pixels to draw - 2 bytes per pixel!
-*/
-/**************************************************************************/
-void Adafruit_SPITFT::writePixels(uint16_t *colors, uint32_t len) {
-#ifdef USE_SPI_DMA
- if(_sclk < 0) { // using hardware SPI?
+#elif defined(USE_SPI_DMA)
+ if(connection == TFT_HARD_SPI) {
int maxSpan = maxFillLen / 2; // One scanline max
uint8_t pixelBufIdx = 0; // Active pixel buffer number
while(len) {
@@ -489,33 +730,57 @@ void Adafruit_SPITFT::writePixels(uint16_t *colors, uint32_t len) {
lastFillColor = 0x0000; // pixelBuf has been sullied
lastFillLen = 0;
while(dma_busy); // Wait for last line to complete
-#ifdef __SAMD51__
- _spi->setDataMode(SPI_MODE0); // See note in writeColor()
+#if defined(__SAMD51__)
+ hwspi._spi->setDataMode(SPI_MODE0); // See SAMD51 note in writeColor()
#endif
return;
}
-#else
- SPI_WRITE_PIXELS((uint8_t*)colors , len * 2);
-#endif
+#endif // end USE_SPI_DMA
+
+ // All other cases (non-DMA hard SPI, bitbang SPI, parallel),
+ // use a loop with the normal 16-bit data write function:
+ while(len--) {
+ SPI_WRITE16(*colors++);
+ }
}
-/**************************************************************************/
/*!
- @brief Blit a 2-byte color many times (must have a transaction in progress)
- @param color The 16-bit 5-6-5 Color to draw
- @param len How many pixels to draw
+ @brief Issue a series of pixels, all the same color. Not self-
+ contained; should follow startWrite() and setAddrWindow() calls.
+ @param color 16-bit pixel color in '565' RGB format.
+ @param len Number of pixels to draw.
*/
-/**************************************************************************/
void Adafruit_SPITFT::writeColor(uint16_t color, uint32_t len) {
if(!len) return; // Avoid 0-byte transfers
uint8_t hi = color >> 8, lo = color;
- if(_sclk < 0) { // Using hardware SPI
-
-#ifdef USE_SPI_DMA
-
+#if defined(ESP32) // ESP32 has a special SPI pixel-writing function...
+ if(connection == TFT_HARD_SPI) {
+ #define SPI_MAX_PIXELS_AT_ONCE 32
+ #define TMPBUF_LONGWORDS (SPI_MAX_PIXELS_AT_ONCE + 1) / 2
+ #define TMPBUF_PIXELS (TMPBUF_LONGWORDS * 2)
+ static uint32_t temp[TMPBUF_LONGWORDS];
+ uint32_t c32 = color * 0x00010001;
+ uint16_t bufLen = (len < TMPBUF_PIXELS) ? len : TMPBUF_PIXELS,
+ xferLen, fillLen;
+ // Fill temp buffer 32 bits at a time
+ fillLen = (bufLen + 1) / 2; // Round up to next 32-bit boundary
+ for(uint32_t t=0; tsetDataMode(SPI_MODE0);
-#endif
-
// Unfortunately blocking is necessary. An earlier version returned
// immediately and checked dma_busy on startWrite() instead, but it
// turns out to be MUCH slower on many graphics operations (as when
// drawing lines, pixel-by-pixel), perhaps because it's a volatile
// type and doesn't cache. Working on this.
-
-#else // Non-DMA
-
- #ifdef SPI_HAS_WRITE_PIXELS
- #define TMPBUF_LONGWORDS (SPI_MAX_PIXELS_AT_ONCE + 1) / 2
- #define TMPBUF_PIXELS (TMPBUF_LONGWORDS * 2)
- static uint32_t temp[TMPBUF_LONGWORDS];
- uint32_t c32 = color * 0x00010001;
- uint16_t bufLen = (len < TMPBUF_PIXELS) ? len : TMPBUF_PIXELS,
- xferLen, fillLen;
-
- // Fill temp buffer 32 bits at a time
- fillLen = (bufLen + 1) / 2; // Round up to next 32-bit boundary
- for(uint32_t t=0; tsetDataMode(SPI_MODE0);
#endif
+ return;
+ }
+ #endif // end USE_SPI_DMA
+#endif // end !ESP32
-#endif // end non-DMA
+ // All other cases (non-DMA hard SPI, bitbang SPI, parallel),
+ // use a loop with the normal write function:
+ while(len--) {
+ spiWrite(hi);
+ spiWrite(lo);
+ }
+}
- } else { // Bitbang SPI
- while(len--) {
- spiWrite(hi);
- spiWrite(lo);
+/*!
+ @brief Draw a filled rectangle to the display. Not self-contained;
+ should follow startWrite(). Typically used by higher-level
+ graphics primitives; user code shouldn't need to call this and
+ is likely to use the self-contained fillRect() instead.
+ writeFillRect() performs its own edge clipping and rejection;
+ see writeFillRectPreclipped() for a more 'raw' implementation.
+ @param x Horizontal position of first corner.
+ @param y Vertical position of first corner.
+ @param w Rectangle width in pixels (positive = right of first
+ corner, negative = left of first corner).
+ @param h Rectangle height in pixels (positive = below first
+ corner, negative = above first corner).
+ @param color 16-bit fill color in '565' RGB format.
+ @note Written in this deep-nested way because C by definition will
+ optimize for the 'if' case, not the 'else' -- avoids branches
+ and rejects clipped rectangles at the least-work possibility.
+*/
+void Adafruit_SPITFT::writeFillRect(int16_t x, int16_t y,
+ int16_t w, int16_t h, uint16_t color) {
+ if(w && h) { // Nonzero width and height?
+ if(w < 0) { // If negative width...
+ x += w + 1; // Move X to left edge
+ w = -w; // Use positive width
+ }
+ if(x < _width) { // Not off right
+ if(h < 0) { // If negative height...
+ y += h + 1; // Move Y to top edge
+ h = -h; // Use positive height
+ }
+ if(y < _height) { // Not off bottom
+ int16_t x2 = x + w - 1;
+ if(x2 >= 0) { // Not off left
+ int16_t y2 = y + h - 1;
+ if(y2 >= 0) { // Not off top
+ // Rectangle partly or fully overlaps screen
+ if(x < 0) { x = 0; w = x2 + 1; } // Clip left
+ if(y < 0) { y = 0; h = y2 + 1; } // Clip top
+ if(x2 >= _width) { w = _width - x; } // Clip right
+ if(y2 >= _height) { h = _height - y; } // Clip bottom
+ writeFillRectPreclipped(x, y, w, h, color);
+ }
+ }
+ }
}
}
}
-/**************************************************************************/
/*!
- @brief Write a pixel (must have a transaction in progress)
- @param x x coordinate
- @param y y coordinate
- @param color 16-bit 5-6-5 Color to draw with
+ @brief Draw a horizontal line on the display. Performs edge clipping
+ and rejection. Not self-contained; should follow startWrite().
+ Typically used by higher-level graphics primitives; user code
+ shouldn't need to call this and is likely to use the self-
+ contained drawFastHLine() instead.
+ @param x Horizontal position of first point.
+ @param y Vertical position of first point.
+ @param w Line width in pixels (positive = right of first point,
+ negative = point of first corner).
+ @param color 16-bit line color in '565' RGB format.
*/
-/**************************************************************************/
-void Adafruit_SPITFT::writePixel(int16_t x, int16_t y, uint16_t color) {
- if((x < 0) ||(x >= _width) || (y < 0) || (y >= _height)) return;
- setAddrWindow(x,y,1,1);
- writePixel(color);
+void inline Adafruit_SPITFT::writeFastHLine(int16_t x, int16_t y, int16_t w,
+ uint16_t color) {
+ if((y >= 0) && (y < _height) && w) { // Y on screen, nonzero width
+ if(w < 0) { // If negative width...
+ x += w + 1; // Move X to left edge
+ w = -w; // Use positive width
+ }
+ if(x < _width) { // Not off right
+ int16_t x2 = x + w - 1;
+ if(x2 >= 0) { // Not off left
+ // Line partly or fully overlaps screen
+ if(x < 0) { x = 0; w = x2 + 1; } // Clip left
+ if(x2 >= _width) { w = _width - x; } // Clip right
+ writeFillRectPreclipped(x, y, w, 1, color);
+ }
+ }
+ }
}
-/**************************************************************************/
/*!
- @brief Write a filled rectangle (must have a transaction in progress)
- @param x Top left corner x coordinate
- @param y Top left corner y coordinate
- @param w Width in pixels
- @param h Height in pixels
- @param color 16-bit 5-6-5 Color to fill with
+ @brief Draw a vertical line on the display. Performs edge clipping and
+ rejection. Not self-contained; should follow startWrite().
+ Typically used by higher-level graphics primitives; user code
+ shouldn't need to call this and is likely to use the self-
+ contained drawFastVLine() instead.
+ @param x Horizontal position of first point.
+ @param y Vertical position of first point.
+ @param w Line height in pixels (positive = below first point,
+ negative = above first point).
+ @param color 16-bit line color in '565' RGB format.
*/
-/**************************************************************************/
-void Adafruit_SPITFT::writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color){
- if((x >= _width) || (y >= _height)) return;
- int16_t x2 = x + w - 1, y2 = y + h - 1;
- if((x2 < 0) || (y2 < 0)) return;
-
- // Clip left/top
- if(x < 0) {
- x = 0;
- w = x2 + 1;
- }
- if(y < 0) {
- y = 0;
- h = y2 + 1;
+void inline Adafruit_SPITFT::writeFastVLine(int16_t x, int16_t y, int16_t h,
+ uint16_t color) {
+ if((x >= 0) && (x < _width) && h) { // X on screen, nonzero height
+ if(h < 0) { // If negative height...
+ y += h + 1; // Move Y to top edge
+ h = -h; // Use positive height
+ }
+ if(y < _height) { // Not off bottom
+ int16_t y2 = y + h - 1;
+ if(y2 >= 0) { // Not off top
+ // Line partly or fully overlaps screen
+ if(y < 0) { y = 0; h = y2 + 1; } // Clip top
+ if(y2 >= _height) { h = _height - y; } // Clip bottom
+ writeFillRectPreclipped(x, y, 1, h, color);
+ }
+ }
}
+}
- // Clip right/bottom
- if(x2 >= _width) w = _width - x;
- if(y2 >= _height) h = _height - y;
-
+/*!
+ @brief A lower-level version of writeFillRect(). This version requires
+ all inputs are in-bounds, that width and height are positive,
+ and no part extends offscreen. NO EDGE CLIPPING OR REJECTION IS
+ PERFORMED. If higher-level graphics primitives are written to
+ handle their own clipping earlier in the drawing process, this
+ can avoid unnecessary function calls and repeated clipping
+ operations in the lower-level functions.
+ @param x Horizontal position of first corner. MUST BE WITHIN
+ SCREEN BOUNDS.
+ @param y Vertical position of first corner. MUST BE WITHIN SCREEN
+ BOUNDS.
+ @param w Rectangle width in pixels. MUST BE POSITIVE AND NOT
+ EXTEND OFF SCREEN.
+ @param h Rectangle height in pixels. MUST BE POSITIVE AND NOT
+ EXTEND OFF SCREEN.
+ @param color 16-bit fill color in '565' RGB format.
+ @note This is a new function, no graphics primitives besides rects
+ and horizontal/vertical lines are written to best use this yet.
+*/
+inline void Adafruit_SPITFT::writeFillRectPreclipped(int16_t x, int16_t y,
+ int16_t w, int16_t h, uint16_t color) {
setAddrWindow(x, y, w, h);
- writeColor(color, (int32_t)w * h);
+ writeColor(color, (uint32_t)w * h);
}
-/**************************************************************************/
/*!
- @brief Write a perfectly vertical line (must have a transaction in progress)
- @param x Top-most x coordinate
- @param y Top-most y coordinate
- @param h Height in pixels
- @param color 16-bit 5-6-5 Color to fill with
+ @brief Writes a single color value to the display. Not self-contained;
+ should follow startWrite() and setAddrWindow() calls.
+ Since this just calls SPI_WRITE16(), one could just call that
+ directly to get the same effect.
+ @param color 16-bit pixel color in '565' RGB format.
*/
-/**************************************************************************/
-void inline Adafruit_SPITFT::writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color){
- writeFillRect(x, y, 1, h, color);
+inline void Adafruit_SPITFT::writePixel(uint16_t color) {
+ SPI_WRITE16(color);
}
-/**************************************************************************/
-/*!
- @brief Write a perfectly horizontal line (must have a transaction in progress)
- @param x Left-most x coordinate
- @param y Left-most y coordinate
- @param w Width in pixels
- @param color 16-bit 5-6-5 Color to fill with
-*/
-/**************************************************************************/
-void inline Adafruit_SPITFT::writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color){
- writeFillRect(x, y, w, 1, color);
-}
-/**************************************************************************/
+// -------------------------------------------------------------------------
+// Ever-so-slightly higher-level graphics operations. Similar to the 'write'
+// functions above, but these contain their own chip-select and SPI
+// transactions as needed (via startWrite(), endWrite()). They're typically
+// used solo -- as graphics primitives in themselves, not invoked by higher-
+// level primitives (which should use the functions above for better
+// performance).
+
/*!
- @brief Draw a pixel - sets up transaction
- @param x x coordinate
- @param y y coordinate
- @param color 16-bit 5-6-5 Color to draw with
+ @brief Draw a single pixel to the display at requested coordinates.
+ Self-contained and provides its own transaction as needed
+ (see writePixel(x,y,color) for a lower-level variant).
+ Edge clipping is performed here.
+ @param x Horizontal position (0 = left).
+ @param y Vertical position (0 = top).
+ @param color 16-bit pixel color in '565' RGB format.
*/
-/**************************************************************************/
-void Adafruit_SPITFT::drawPixel(int16_t x, int16_t y, uint16_t color){
+void Adafruit_SPITFT::drawPixel(int16_t x, int16_t y, uint16_t color) {
// Clip first...
if((x >= 0) && (x < _width) && (y >= 0) && (y < _height)) {
// THEN set up transaction (if needed) and draw...
startWrite();
setAddrWindow(x, y, 1, 1);
- writePixel(color);
+ SPI_WRITE16(color);
endWrite();
}
}
-/**************************************************************************/
/*!
- @brief Write a perfectly vertical line - sets up transaction
- @param x Top-most x coordinate
- @param y Top-most y coordinate
- @param h Height in pixels
- @param color 16-bit 5-6-5 Color to fill with
+ @brief Draw a filled rectangle to the display. Self-contained and
+ provides its own transaction as needed (see writeFillRect() or
+ writeFillRectPreclipped() for lower-level variants). Edge
+ clipping and rejection is performed here.
+ @param x Horizontal position of first corner.
+ @param y Vertical position of first corner.
+ @param w Rectangle width in pixels (positive = right of first
+ corner, negative = left of first corner).
+ @param h Rectangle height in pixels (positive = below first
+ corner, negative = above first corner).
+ @param color 16-bit fill color in '565' RGB format.
+ @note This repeats the writeFillRect() function almost in its entirety,
+ with the addition of a transaction start/end. It's done this way
+ (rather than starting the transaction and calling writeFillRect()
+ to handle clipping and so forth) so that the transaction isn't
+ performed at all if the rectangle is rejected. It's really not
+ that much code.
*/
-/**************************************************************************/
-void Adafruit_SPITFT::drawFastVLine(int16_t x, int16_t y,
- int16_t h, uint16_t color) {
- startWrite();
- writeFastVLine(x, y, h, color);
- endWrite();
-}
-
-/**************************************************************************/
-/*!
- @brief Write a perfectly horizontal line - sets up transaction
- @param x Left-most x coordinate
- @param y Left-most y coordinate
- @param w Width in pixels
- @param color 16-bit 5-6-5 Color to fill with
-*/
-/**************************************************************************/
-void Adafruit_SPITFT::drawFastHLine(int16_t x, int16_t y,
- int16_t w, uint16_t color) {
- startWrite();
- writeFastHLine(x, y, w, color);
- endWrite();
-}
-
-/**************************************************************************/
-/*!
- @brief Fill a rectangle completely with one color.
- @param x Top left corner x coordinate
- @param y Top left corner y coordinate
- @param w Width in pixels
- @param h Height in pixels
- @param color 16-bit 5-6-5 Color to fill with
-*/
-/**************************************************************************/
void Adafruit_SPITFT::fillRect(int16_t x, int16_t y, int16_t w, int16_t h,
- uint16_t color) {
+ uint16_t color) {
+ if(w && h) { // Nonzero width and height?
+ if(w < 0) { // If negative width...
+ x += w + 1; // Move X to left edge
+ w = -w; // Use positive width
+ }
+ if(x < _width) { // Not off right
+ if(h < 0) { // If negative height...
+ y += h + 1; // Move Y to top edge
+ h = -h; // Use positive height
+ }
+ if(y < _height) { // Not off bottom
+ int16_t x2 = x + w - 1;
+ if(x2 >= 0) { // Not off left
+ int16_t y2 = y + h - 1;
+ if(y2 >= 0) { // Not off top
+ // Rectangle partly or fully overlaps screen
+ if(x < 0) { x = 0; w = x2 + 1; } // Clip left
+ if(y < 0) { y = 0; h = y2 + 1; } // Clip top
+ if(x2 >= _width) { w = _width - x; } // Clip right
+ if(y2 >= _height) { h = _height - y; } // Clip bottom
+ startWrite();
+ writeFillRectPreclipped(x, y, w, h, color);
+ endWrite();
+ }
+ }
+ }
+ }
+ }
+}
+
+/*!
+ @brief Draw a horizontal line on the display. Self-contained and
+ provides its own transaction as needed (see writeFastHLine() for
+ a lower-level variant). Edge clipping and rejection is performed
+ here.
+ @param x Horizontal position of first point.
+ @param y Vertical position of first point.
+ @param w Line width in pixels (positive = right of first point,
+ negative = point of first corner).
+ @param color 16-bit line color in '565' RGB format.
+ @note This repeats the writeFastHLine() function almost in its
+ entirety, with the addition of a transaction start/end. It's
+ done this way (rather than starting the transaction and calling
+ writeFastHLine() to handle clipping and so forth) so that the
+ transaction isn't performed at all if the line is rejected.
+*/
+void Adafruit_SPITFT::drawFastHLine(int16_t x, int16_t y, int16_t w,
+ uint16_t color) {
+ if((y >= 0) && (y < _height) && w) { // Y on screen, nonzero width
+ if(w < 0) { // If negative width...
+ x += w + 1; // Move X to left edge
+ w = -w; // Use positive width
+ }
+ if(x < _width) { // Not off right
+ int16_t x2 = x + w - 1;
+ if(x2 >= 0) { // Not off left
+ // Line partly or fully overlaps screen
+ if(x < 0) { x = 0; w = x2 + 1; } // Clip left
+ if(x2 >= _width) { w = _width - x; } // Clip right
+ startWrite();
+ writeFillRectPreclipped(x, y, w, 1, color);
+ endWrite();
+ }
+ }
+ }
+}
+
+/*!
+ @brief Draw a vertical line on the display. Self-contained and provides
+ its own transaction as needed (see writeFastHLine() for a lower-
+ level variant). Edge clipping and rejection is performed here.
+ @param x Horizontal position of first point.
+ @param y Vertical position of first point.
+ @param w Line height in pixels (positive = below first point,
+ negative = above first point).
+ @param color 16-bit line color in '565' RGB format.
+ @note This repeats the writeFastVLine() function almost in its
+ entirety, with the addition of a transaction start/end. It's
+ done this way (rather than starting the transaction and calling
+ writeFastVLine() to handle clipping and so forth) so that the
+ transaction isn't performed at all if the line is rejected.
+*/
+void Adafruit_SPITFT::drawFastVLine(int16_t x, int16_t y, int16_t h,
+ uint16_t color) {
+ if((x >= 0) && (x < _width) && h) { // X on screen, nonzero height
+ if(h < 0) { // If negative height...
+ y += h + 1; // Move Y to top edge
+ h = -h; // Use positive height
+ }
+ if(y < _height) { // Not off bottom
+ int16_t y2 = y + h - 1;
+ if(y2 >= 0) { // Not off top
+ // Line partly or fully overlaps screen
+ if(y < 0) { y = 0; h = y2 + 1; } // Clip top
+ if(y2 >= _height) { h = _height - y; } // Clip bottom
+ startWrite();
+ writeFillRectPreclipped(x, y, 1, h, color);
+ endWrite();
+ }
+ }
+ }
+}
+
+/*!
+ @brief Essentially writePixel() with a transaction around it. I don't
+ think this is in use by any of our code anymore (believe it was
+ for some older BMP-reading examples), but is kept here in case
+ any user code relies on it. Consider it DEPRECATED.
+ @param color 16-bit pixel color in '565' RGB format.
+*/
+void Adafruit_SPITFT::pushColor(uint16_t color) {
startWrite();
- writeFillRect(x,y,w,h,color);
+ SPI_WRITE16(color);
endWrite();
}
-
-/**************************************************************************/
/*!
- @brief Invert the display using built-in hardware command
- @param i True if you want to invert, false to make 'normal'
+ @brief Draw a 16-bit image (565 RGB) at the specified (x,y) position.
+ For 16-bit display devices; no color reduction performed.
+ Adapted from https://github.com/PaulStoffregen/ILI9341_t3
+ by Marc MERLIN. See examples/pictureEmbed to use this.
+ 5/6/2017: function name and arguments have changed for
+ compatibility with current GFX library and to avoid naming
+ problems in prior implementation. Formerly drawBitmap() with
+ arguments in different order. Handles its own transaction and
+ edge clipping/rejection.
+ @param x Top left corner horizontal coordinate.
+ @param y Top left corner vertical coordinate.
+ @param pcolors Pointer to 16-bit array of pixel values.
+ @param w Width of bitmap in pixels.
+ @param h Height of bitmap in pixels.
*/
-/**************************************************************************/
-void Adafruit_SPITFT::invertDisplay(boolean i) {
- startWrite();
- writeCommand(i ? invertOnCommand : invertOffCommand);
- endWrite();
-}
-
-
-/**************************************************************************/
-/*!
- @brief Draw a 16-bit image (RGB 5/6/5) at the specified (x,y) position.
- For 16-bit display devices; no color reduction performed.
- Adapted from https://github.com/PaulStoffregen/ILI9341_t3
- by Marc MERLIN. See examples/pictureEmbed to use this.
- 5/6/2017: function name and arguments have changed for compatibility
- with current GFX library and to avoid naming problems in prior
- implementation. Formerly drawBitmap() with arguments in different order.
-
- @param x Top left corner x coordinate
- @param y Top left corner y coordinate
- @param pcolors 16-bit array with 16-bit color bitmap
- @param w Width of bitmap in pixels
- @param h Height of bitmap in pixels
-*/
-/**************************************************************************/
void Adafruit_SPITFT::drawRGBBitmap(int16_t x, int16_t y,
uint16_t *pcolors, int16_t w, int16_t h) {
@@ -835,5 +1229,469 @@ void Adafruit_SPITFT::drawRGBBitmap(int16_t x, int16_t y,
endWrite();
}
-#endif // !__AVR_ATtiny85__
+// -------------------------------------------------------------------------
+// Miscellaneous class member functions that don't draw anything.
+
+/*!
+ @brief Invert the colors of the display (if supported by hardware).
+ Self-contained, no transaction setup required.
+ @param i true = inverted display, false = normal display.
+*/
+void Adafruit_SPITFT::invertDisplay(bool i) {
+ startWrite();
+ writeCommand(i ? invertOnCommand : invertOffCommand);
+ endWrite();
+}
+
+/*!
+ @brief Given 8-bit red, green and blue values, return a 'packed'
+ 16-bit color value in '565' RGB format (5 bits red, 6 bits
+ green, 5 bits blue). This is just a mathematical operation,
+ no hardware is touched.
+ @param red 8-bit red brightnesss (0 = off, 255 = max).
+ @param green 8-bit green brightnesss (0 = off, 255 = max).
+ @param blue 8-bit blue brightnesss (0 = off, 255 = max).
+*/
+uint16_t Adafruit_SPITFT::color565(uint8_t red, uint8_t green, uint8_t blue) {
+ return ((red & 0xF8) << 8) | ((green & 0xFC) << 3) | (blue >> 3);
+}
+
+
+// -------------------------------------------------------------------------
+// Lowest-level hardware-interfacing functions. Many of these are inline and
+// compile to different things based on #defines -- typically just a few
+// instructions. Others, not so much, those are not inlined.
+
+/*!
+ @brief Start an SPI transaction if using the hardware SPI interface to
+ the display. If using an earlier version of the Arduino platform
+ (before the addition of SPI transactions), this instead attempts
+ to set up the SPI clock and mode. No action is taken if the
+ connection is not hardware SPI-based. This does NOT include a
+ chip-select operation -- see startWrite() for a function that
+ encapsulated both actions.
+*/
+inline void Adafruit_SPITFT::SPI_BEGIN_TRANSACTION(void) {
+ if(connection == TFT_HARD_SPI) {
+#if defined(SPI_HAS_TRANSACTION)
+ hwspi._spi->beginTransaction(hwspi.settings);
+#else // No transactions, configure SPI manually...
+ #if defined(__AVR__) || defined(TEENSYDUINO) || defined(ARDUINO_ARCH_STM32F1)
+ hwspi._spi->setClockDivider(SPI_CLOCK_DIV2);
+ #elif defined(__arm__)
+ hwspi._spi->setClockDivider(11);
+ #elif defined(ESP8266) || defined(ESP32)
+ hwspi._spi->setFrequency(hwspi._freq);
+ #elif defined(RASPI) || defined(ARDUINO_ARCH_STM32F1)
+ hwspi._spi->setClock(hwspi._freq);
+ #endif
+ hwspi._spi->setBitOrder(MSBFIRST);
+ hwspi._spi->setDataMode(SPI_MODE0);
+#endif // end !SPI_HAS_TRANSACTION
+ }
+}
+
+/*!
+ @brief End an SPI transaction if using the hardware SPI interface to
+ the display. No action is taken if the connection is not
+ hardware SPI-based or if using an earlier version of the Arduino
+ platform (before the addition of SPI transactions). This does
+ NOT include a chip-deselect operation -- see endWrite() for a
+ function that encapsulated both actions.
+*/
+inline void Adafruit_SPITFT::SPI_END_TRANSACTION(void) {
+#if defined(SPI_HAS_TRANSACTION)
+ if(connection == TFT_HARD_SPI) {
+ hwspi._spi->endTransaction();
+ }
+#endif
+}
+
+/*!
+ @brief Issue a single 8-bit value to the display. Chip-select,
+ transaction and data/command selection must have been
+ previously set -- this ONLY issues the byte. This is another of
+ those functions in the library with a now-not-accurate name
+ that's being maintained for compatibility with outside code.
+ This function is used even if display connection is parallel.
+ @param b 8-bit value to write.
+*/
+void Adafruit_SPITFT::spiWrite(uint8_t b) {
+ switch(connection) {
+ case TFT_HARD_SPI:
+#if defined(__AVR__)
+ for(SPDR = b; !(SPSR & _BV(SPIF)); );
+#elif defined(ESP8266) || defined(ESP32)
+ hwspi._spi->write(b);
+#else
+ hwspi._spi->transfer(b);
+#endif
+ break;
+ case TFT_SOFT_SPI:
+ for(uint8_t bit=0; bit<8; bit++) {
+ if(b & 0x80) SPI_MOSI_HIGH();
+ else SPI_MOSI_LOW();
+ SPI_SCK_HIGH();
+ SPI_SCK_LOW();
+ b <<= 1;
+ }
+ break;
+ case TFT_PARALLEL:
+#if defined(__AVR__)
+ *tft8.writePort = b;
+#elif defined(USE_FAST_PINIO)
+ if(!tft8.wide) *tft8.writePort = b;
+ else *(volatile uint16_t *)tft8.writePort = b;
+#endif
+ TFT_WR_STROBE();
+ break;
+ }
+}
+
+/*!
+ @brief Write a single command byte to the display. Chip-select and
+ transaction must have been previously set -- this ONLY sets
+ the device to COMMAND mode, issues the byte and then restores
+ DATA mode. There is no corresponding explicit writeData()
+ function -- just use spiWrite().
+ @param b 8-bit command to write.
+*/
+void Adafruit_SPITFT::writeCommand(uint8_t cmd) {
+ SPI_DC_LOW();
+ spiWrite(cmd);
+ SPI_DC_HIGH();
+}
+
+/*!
+ @brief Read a single 8-bit value from the display. Chip-select and
+ transaction must have been previously set -- this ONLY reads
+ the byte. This is another of those functions in the library
+ with a now-not-accurate name that's being maintained for
+ compatibility with outside code. This function is used even if
+ display connection is parallel.
+ @return Unsigned 8-bit value read (always zero if USE_FAST_PINIO is
+ not supported by the MCU architecture).
+*/
+uint8_t Adafruit_SPITFT::spiRead(void) {
+ uint8_t b = 0;
+ uint16_t w = 0;
+ switch(connection) {
+ case TFT_HARD_SPI:
+ return hwspi._spi->transfer((uint8_t)0);
+ case TFT_SOFT_SPI:
+ if(swspi._miso >= 0) {
+ for(uint8_t i=0; i<8; i++) {
+ SPI_SCK_HIGH();
+ SPI_SCK_LOW();
+ b <<= 1;
+ if(SPI_MISO_READ()) b |= 1;
+ }
+ }
+ return b;
+ // case TFT_PARALLEL:
+ default: // Avoids compiler warning about no return value
+ if(tft8._rd >= 0) {
+#if defined(USE_FAST_PINIO)
+ TFT_RD_LOW(); // Read strobe LOW
+ #if defined(__AVR__)
+ *tft8.portDir = 0x00; // Set port to input state
+ w = *tft8.readPort; // Read value from port
+ *tft8.portDir = 0xFF; // Restore port to output
+ #else // !__AVR__
+ if(!tft8.wide) { // 8-bit TFT connection
+ #if defined(HAS_PORT_SET_CLR)
+ *tft8.dirClr = 0xFF; // Set port to input state
+ w = *tft8.readPort; // Read value from port
+ *tft8.dirSet = 0xFF; // Restore port to output
+ #else // !HAS_PORT_SET_CLR
+ *tft8.portDir = 0x00; // Set port to input state
+ w = *tft8.readPort; // Read value from port
+ *tft8.dirSet = 0xFF; // Restore port to output
+ #endif // end HAS_PORT_SET_CLR
+ } else { // 16-bit TFT connection
+ #if defined(HAS_PORT_SET_CLR)
+ *(volatile uint16_t *)tft8.dirClr = 0xFFFF; // Input state
+ w = *(volatile uint16_t *)tft8.readPort; // 16-bit read
+ *(volatile uint16_t *)tft8.dirSet = 0xFFFF; // Output state
+ #else // !HAS_PORT_SET_CLR
+ *(volatile uint16_t *)tft8.portDir = 0x0000; // Input state
+ w = *(volatile uint16_t *)tft8.readPort; // 16-bit read
+ *(volatile uint16_t *)tft8.portDir = 0xFFFF; // Output state
+ #endif // end !HAS_PORT_SET_CLR
+ }
+ #endif // end !__AVR__
+ TFT_RD_HIGH(); // Read strobe HIGH
+#else // !USE_FAST_PINIO
+ w = 0; // Parallel TFT is NOT SUPPORTED without USE_FAST_PINIO
+#endif // end !USE_FAST_PINIO
+ }
+ return w;
+ }
+}
+
+/*!
+ @brief Set the software (bitbang) SPI MOSI line HIGH.
+*/
+inline void Adafruit_SPITFT::SPI_MOSI_HIGH(void) {
+#if defined(USE_FAST_PINIO)
+ #if defined(HAS_PORT_SET_CLR)
+ #if defined(KINETISK)
+ *swspi.mosiPortSet = 1;
+ #else // !KINETISK
+ *swspi.mosiPortSet = swspi.mosiPinMask;
+ #endif
+ #else // !HAS_PORT_SET_CLR
+ *swspi.mosiPort |= swspi.mosiPinMaskSet;
+ #endif // end !HAS_PORT_SET_CLR
+#else // !USE_FAST_PINIO
+ digitalWrite(swspi._mosi, HIGH);
+#endif // end !USE_FAST_PINIO
+}
+
+/*!
+ @brief Set the software (bitbang) SPI MOSI line LOW.
+*/
+inline void Adafruit_SPITFT::SPI_MOSI_LOW(void) {
+#if defined(USE_FAST_PINIO)
+ #if defined(HAS_PORT_SET_CLR)
+ #if defined(KINETISK)
+ *swspi.mosiPortClr = 1;
+ #else // !KINETISK
+ *swspi.mosiPortClr = swspi.mosiPinMask;
+ #endif
+ #else // !HAS_PORT_SET_CLR
+ *swspi.mosiPort &= swspi.mosiPinMaskClr;
+ #endif // end !HAS_PORT_SET_CLR
+#else // !USE_FAST_PINIO
+ digitalWrite(swspi._mosi, LOW);
+#endif // end !USE_FAST_PINIO
+}
+
+/*!
+ @brief Set the software (bitbang) SPI SCK line HIGH.
+*/
+inline void Adafruit_SPITFT::SPI_SCK_HIGH(void) {
+#if defined(USE_FAST_PINIO)
+ #if defined(HAS_PORT_SET_CLR)
+ #if defined(KINETISK)
+ *swspi.sckPortSet = 1;
+ #else // !KINETISK
+ *swspi.sckPortSet = swspi.sckPinMask;
+ #endif
+ #else // !HAS_PORT_SET_CLR
+ *swspi.sckPort |= swspi.sckPinMaskSet;
+ #endif // end !HAS_PORT_SET_CLR
+#else // !USE_FAST_PINIO
+ digitalWrite(swspi._sck, HIGH);
+#endif // end !USE_FAST_PINIO
+}
+
+/*!
+ @brief Set the software (bitbang) SPI SCK line LOW.
+*/
+inline void Adafruit_SPITFT::SPI_SCK_LOW(void) {
+#if defined(USE_FAST_PINIO)
+ #if defined(HAS_PORT_SET_CLR)
+ #if defined(KINETISK)
+ *swspi.sckPortClr = 1;
+ #else // !KINETISK
+ *swspi.sckPortClr = swspi.sckPinMask;
+ #endif
+ #else // !HAS_PORT_SET_CLR
+ *swspi.sckPort &= swspi.sckPinMaskClr;
+ #endif // end !HAS_PORT_SET_CLR
+#else // !USE_FAST_PINIO
+ digitalWrite(swspi._sck, LOW);
+#endif // end !USE_FAST_PINIO
+}
+
+/*!
+ @brief Read the state of the software (bitbang) SPI MISO line.
+ @return true if HIGH, false if LOW.
+*/
+inline bool Adafruit_SPITFT::SPI_MISO_READ(void) {
+#if defined(USE_FAST_PINIO)
+ #if defined(KINETISK)
+ return *swspi.misoPort;
+ #else // !KINETISK
+ return *swspi.misoPort & swspi.misoPinMask;
+ #endif // end !KINETISK
+#else // !USE_FAST_PINIO
+ return digitalRead(swspi._miso);
+#endif // end !USE_FAST_PINIO
+}
+
+/*!
+ @brief Issue a single 16-bit value to the display. Chip-select,
+ transaction and data/command selection must have been
+ previously set -- this ONLY issues the word. Despite the name,
+ this function is used even if display connection is parallel;
+ name was maintaned for backward compatibility. Naming is also
+ not consistent with the 8-bit version, spiWrite(). Sorry about
+ that. Again, staying compatible with outside code.
+ @param w 16-bit value to write.
+*/
+void Adafruit_SPITFT::SPI_WRITE16(uint16_t w) {
+ switch(connection) {
+ case TFT_HARD_SPI:
+#if defined(__AVR__)
+ for(SPDR = (w >> 8); !(SPSR & _BV(SPIF)); );
+ for(SPDR = w ; !(SPSR & _BV(SPIF)); );
+#elif defined(ESP8266) || defined(ESP32)
+ hwspi._spi->write16(w);
+#else
+ hwspi._spi->transfer(w >> 8);
+ hwspi._spi->transfer(w);
+#endif
+ break;
+ case TFT_SOFT_SPI:
+ for(uint8_t bit=0; bit<16; bit++) {
+ if(w & 0x8000) SPI_MOSI_HIGH();
+ else SPI_MOSI_LOW();
+ SPI_SCK_HIGH();
+ SPI_SCK_LOW();
+ w <<= 1;
+ }
+ break;
+ case TFT_PARALLEL:
+#if defined(__AVR__)
+ *tft8.writePort = w >> 8;
+ TFT_WR_STROBE();
+ *tft8.writePort = w;
+#elif defined(USE_FAST_PINIO)
+ if(!tft8.wide) {
+ *tft8.writePort = w >> 8;
+ TFT_WR_STROBE();
+ *tft8.writePort = w;
+ } else {
+ *(volatile uint16_t *)tft8.writePort = w;
+ }
+#endif
+ TFT_WR_STROBE();
+ break;
+ }
+}
+
+/*!
+ @brief Issue a single 32-bit value to the display. Chip-select,
+ transaction and data/command selection must have been
+ previously set -- this ONLY issues the longword. Despite the
+ name, this function is used even if display connection is
+ parallel; name was maintaned for backward compatibility. Naming
+ is also not consistent with the 8-bit version, spiWrite().
+ Sorry about that. Again, staying compatible with outside code.
+ @param w 16-bit value to write.
+*/
+void Adafruit_SPITFT::SPI_WRITE32(uint32_t l) {
+ switch(connection) {
+ case TFT_HARD_SPI:
+#if defined(__AVR__)
+ for(SPDR = (l >> 24); !(SPSR & _BV(SPIF)); );
+ for(SPDR = (l >> 16); !(SPSR & _BV(SPIF)); );
+ for(SPDR = (l >> 8); !(SPSR & _BV(SPIF)); );
+ for(SPDR = l ; !(SPSR & _BV(SPIF)); );
+#elif defined(ESP8266) || defined(ESP32)
+ hwspi._spi->write32(l);
+#else
+ hwspi._spi->transfer(l >> 24);
+ hwspi._spi->transfer(l >> 16);
+ hwspi._spi->transfer(l >> 8);
+ hwspi._spi->transfer(l);
+#endif
+ break;
+ case TFT_SOFT_SPI:
+ for(uint8_t bit=0; bit<32; bit++) {
+ if(l & 0x80000000) SPI_MOSI_HIGH();
+ else SPI_MOSI_LOW();
+ SPI_SCK_HIGH();
+ SPI_SCK_LOW();
+ l <<= 1;
+ }
+ break;
+ case TFT_PARALLEL:
+#if defined(__AVR__)
+ *tft8.writePort = l >> 24;
+ TFT_WR_STROBE();
+ *tft8.writePort = l >> 16;
+ TFT_WR_STROBE();
+ *tft8.writePort = l >> 8;
+ TFT_WR_STROBE();
+ *tft8.writePort = l;
+#elif defined(USE_FAST_PINIO)
+ if(!tft8.wide) {
+ *tft8.writePort = l >> 24;
+ TFT_WR_STROBE();
+ *tft8.writePort = l >> 16;
+ TFT_WR_STROBE();
+ *tft8.writePort = l >> 8;
+ TFT_WR_STROBE();
+ *tft8.writePort = l;
+ } else {
+ *(volatile uint16_t *)tft8.writePort = l >> 16;
+ TFT_WR_STROBE();
+ *(volatile uint16_t *)tft8.writePort = l;
+ }
+#endif
+ TFT_WR_STROBE();
+ break;
+ }
+}
+
+/*!
+ @brief Set the RD line LOW, then HIGH. Used for parallel-connected
+ interfaces when writing data.
+*/
+inline void Adafruit_SPITFT::TFT_WR_STROBE(void) {
+#if defined(USE_FAST_PINIO)
+ #if defined(HAS_PORT_SET_CLR)
+ #if defined(KINETISK)
+ *tft8.wrPortClr = 1;
+ *tft8.wrPortSet = 1;
+ #else // !KINETISK
+ *tft8.wrPortClr = tft8.wrPinMask;
+ *tft8.wrPortSet = tft8.wrPinMask;
+ #endif // end !KINETISK
+ #else // !HAS_PORT_SET_CLR
+ *tft8.wrPort &= tft8.wrPinMaskClr;
+ *tft8.wrPort |= tft8.wrPinMaskSet;
+ #endif // end !HAS_PORT_SET_CLR
+#else // !USE_FAST_PINIO
+ digitalWrite(tft8._wr, LOW);
+ digitalWrite(tft8._wr, HIGH);
+#endif // end !USE_FAST_PINIO
+}
+
+/*!
+ @brief Set the RD line HIGH. Used for parallel-connected interfaces
+ when reading data.
+*/
+inline void Adafruit_SPITFT::TFT_RD_HIGH(void) {
+#if defined(USE_FAST_PINIO)
+ #if defined(HAS_PORT_SET_CLR)
+ *tft8.rdPortSet = tft8.rdPinMask;
+ #else // !HAS_PORT_SET_CLR
+ *tft8.rdPort |= tft8.rdPinMaskSet;
+ #endif // end !HAS_PORT_SET_CLR
+#else // !USE_FAST_PINIO
+ digitalWrite(tft8._rd, HIGH);
+#endif // end !USE_FAST_PINIO
+}
+
+/*!
+ @brief Set the RD line LOW. Used for parallel-connected interfaces
+ when reading data.
+*/
+inline void Adafruit_SPITFT::TFT_RD_LOW(void) {
+#if defined(USE_FAST_PINIO)
+ #if defined(HAS_PORT_SET_CLR)
+ *tft8.rdPortClr = tft8.rdPinMask;
+ #else // !HAS_PORT_SET_CLR
+ *tft8.rdPort &= tft8.rdPinMaskClr;
+ #endif // end !HAS_PORT_SET_CLR
+#else // !USE_FAST_PINIO
+ digitalWrite(tft8._rd, LOW);
+#endif // end !USE_FAST_PINIO
+}
+
+#endif // end __AVR_ATtiny85__
diff --git a/Adafruit_SPITFT.h b/Adafruit_SPITFT.h
index d0707de..8bea32b 100644
--- a/Adafruit_SPITFT.h
+++ b/Adafruit_SPITFT.h
@@ -1,154 +1,465 @@
-#ifndef _ADAFRUIT_SPITFT_
-#define _ADAFRUIT_SPITFT_
+/*!
+ * @file Adafruit_SPITFT.h
+ *
+ * Part of Adafruit's GFX graphics library. Originally this class was
+ * written to handle a range of color TFT displays connected via SPI,
+ * but over time this library and some display-specific subclasses have
+ * mutated to include some color OLEDs as well as parallel-interfaced
+ * displays. The name's been kept for the sake of older code.
+ *
+ * Adafruit invests time and resources providing this open source code,
+ * please support Adafruit and open-source hardware by purchasing
+ * products from Adafruit!
+ *
+ * @section author Author
+ *
+ * Written by Limor "ladyada" Fried for Adafruit Industries,
+ * with contributions from the open source community.
+ *
+ * @section license License
+ *
+ * BSD license, all text here must be included in any redistribution.
+ */
-#if !defined(__AVR_ATtiny85__) // NOT A CHANCE of this stuff working on ATtiny
+#ifndef _ADAFRUIT_SPITFT_H_
+#define _ADAFRUIT_SPITFT_H_
+
+#if !defined(__AVR_ATtiny85__) // Not for ATtiny, at all
-#if ARDUINO >= 100
- #include "Arduino.h"
- #include "Print.h"
-#else
- #include "WProgram.h"
-#endif
#include
#include "Adafruit_GFX.h"
-#define USE_FAST_PINIO ///< If set, use PORT access instead of digitalWrite()
-//#define USE_SPI_DMA ///< If set, use SPI DMA if available
+// HARDWARE CONFIG ---------------------------------------------------------
+
+#if defined(__AVR__)
+ typedef uint8_t PORT_t; ///< PORT values are 8-bit
+ #define USE_FAST_PINIO ///< Use direct PORT register access
+#elif defined(__arm__)
+ #if defined(SAM)
+ // Arduino Due
+ typedef uint32_t PORT_t; ///< PORT values are 32-bit
+ // USE_FAST_PINIO not available here (yet)...Due has a totally different
+ // GPIO register set and will require some changes elsewhere (e.g. in
+ // constructors especially).
+ #elif defined(CORE_TEENSY)
+ // PJRC Teensy 3.x
+ typedef uint8_t PORT_t; ///< PORT values are 8-bit
+ #define USE_FAST_PINIO ///< Use direct PORT register access
+ #define HAS_PORT_SET_CLR ///< PORTs have set & clear registers
+ #else
+ // Adafruit M0, M4
+ typedef uint32_t PORT_t; ///< PORT values are 32-bit
+ #define USE_FAST_PINIO ///< Use direct PORT register access
+ #define HAS_PORT_SET_CLR ///< PORTs have set & clear registers
+ #endif
+#else // !ARM
+ // Probably ESP8266 or ESP32. USE_FAST_PINIO is not available here (yet)
+ // but don't worry about it too much...the digitalWrite() implementation
+ // on these platforms is reasonably efficient and already RAM-resident,
+ // only gotcha then is no parallel connection support for now.
+ typedef uint32_t PORT_t; ///< PORT values are 32-bit
+#endif // end !ARM
+typedef volatile PORT_t* PORTreg_t; ///< PORT register type
+
+#if defined(__AVR__)
+ #define DEFAULT_SPI_FREQ 8000000L ///< Hardware SPI default speed
+#else
+ #define DEFAULT_SPI_FREQ 16000000L ///< Hardware SPI default speed
+#endif
+
+//#define USE_SPI_DMA ///< If set, use SPI DMA if available
+// Another "oops" name -- in the future parallel DMA will also be handled.
// If DMA is enabled, Arduino sketch MUST #include
// Estimated RAM usage:
// 4 bytes/pixel on display major axis + 8 bytes/pixel on minor axis,
// e.g. 320x240 pixels = 320 * 4 + 240 * 8 = 3,200 bytes.
#if !defined(ARDUINO_ARCH_SAMD)
- #undef USE_SPI_DMA ///< Only for SAMD chips
+ #undef USE_SPI_DMA ///< DMA currently for SAMD chips only
#endif
-#ifdef USE_SPI_DMA
- #pragma message ("SPI DMA IS ENABLED. HIGHLY EXPERIMENTAL.")
+#if defined(USE_SPI_DMA)
+ #pragma message ("GFX DMA IS ENABLED. HIGHLY EXPERIMENTAL.")
#include
#endif
-#if defined(__AVR__)
- typedef volatile uint8_t RwReg;
-#elif defined(ARDUINO_STM32_FEATHER)
- typedef volatile uint32_t RwReg;
- #undef USE_FAST_PINIO
- typedef class HardwareSPI SPIClass;
-#elif defined(__OPENCR__) || defined (__OPENCM904__)
- #undef USE_FAST_PINIO
-#elif defined(ARDUINO_FEATHER52) || defined(__arm__)
- typedef volatile uint32_t RwReg;
-#elif defined(ESP32) || defined(ESP8266)
- typedef volatile uint32_t RwReg;
- #undef USE_FAST_PINIO
-#else
- #undef USE_FAST_PINIO
-#endif
+// CLASS DEFINITION --------------------------------------------------------
-#include "Adafruit_SPITFT_Macros.h"
-
-/// A heavily optimized SPI display subclass of GFX. Manages SPI bitbanging, transactions, DMA, etc! Despite being called SPITFT, the classic SPI data/command interface is also used by OLEDs.
+/*!
+ @brief Adafruit_SPITFT is an intermediary class between Adafruit_GFX
+ and various hardware-specific subclasses for different displays.
+ It handles certain operations that are common to a range of
+ displays (address window, area fills, etc.). Originally these were
+ all color TFT displays interfaced via SPI, but it's since expanded
+ to include color OLEDs and parallel-interfaced TFTs. THE NAME HAS
+ BEEN KEPT TO AVOID BREAKING A LOT OF SUBCLASSES AND EXAMPLE CODE.
+ Many of the class member functions similarly live on with names
+ that don't necessarily accurately describe what they're doing,
+ again to avoid breaking a lot of other code. If in doubt, read
+ the comments.
+*/
class Adafruit_SPITFT : public Adafruit_GFX {
- public:
- Adafruit_SPITFT(uint16_t w, uint16_t h, int8_t _CS, int8_t _DC, int8_t _MOSI, int8_t _SCLK, int8_t _RST = -1, int8_t _MISO = -1);
- Adafruit_SPITFT(uint16_t w, uint16_t h, int8_t _CS, int8_t _DC, int8_t _RST = -1);
- Adafruit_SPITFT(uint16_t w, uint16_t h, SPIClass *spiClass, int8_t _CS, int8_t _DC, int8_t _RST = -1);
- virtual void begin(uint32_t freq) = 0; ///< Virtual begin() function to set SPI frequency, must be overridden in subclass. @param freq Maximum SPI hardware clock speed
+ public:
- void initSPI(uint32_t freq);
+ // CONSTRUCTORS --------------------------------------------------------
- // Required Non-Transaction
- void drawPixel(int16_t x, int16_t y, uint16_t color);
+ // Software SPI constructor: expects width & height (at default rotation
+ // setting 0), 4 signal pins (cs, dc, mosi, sclk), 2 optional pins
+ // (reset, miso). cs argument is required but can be -1 if unused --
+ // rather than moving it to the optional arguments, it was done this way
+ // to avoid breaking existing code (-1 option was a later addition).
+ Adafruit_SPITFT(uint16_t w, uint16_t h,
+ int8_t cs, int8_t dc, int8_t mosi, int8_t sck,
+ int8_t rst = -1, int8_t miso = -1);
- // Transaction API
- void startWrite(void);
- void endWrite(void);
+ // Hardware SPI constructor using the default SPI port: expects width &
+ // height (at default rotation setting 0), 2 signal pins (cs, dc),
+ // optional reset pin. cs is required but can be -1 if unused -- rather
+ // than moving it to the optional arguments, it was done this way to
+ // avoid breaking existing code (-1 option was a later addition).
+ Adafruit_SPITFT(uint16_t w, uint16_t h,
+ int8_t cs, int8_t dc, int8_t rst = -1);
- void writePixel(int16_t x, int16_t y, uint16_t color);
- void writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
- void writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
- void writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
+ // Hardware SPI constructor using an arbitrary SPI peripheral: expects
+ // width & height (rotation 0), SPIClass pointer, 2 signal pins (cs, dc)
+ // and optional reset pin. cs is required but can be -1 if unused.
+ Adafruit_SPITFT(uint16_t w, uint16_t h, SPIClass *spiClass,
+ int8_t cs, int8_t dc, int8_t rst = -1);
- // Transaction API not used by GFX
+ // Parallel constructor: expects width & height (rotation 0), flag
+ // indicating whether 16-bit (true) or 8-bit (false) interface, 3 signal
+ // pins (d0, wr, dc), 3 optional pins (cs, rst, rd). 16-bit parallel
+ // isn't even fully implemented but the 'wide' flag was added as a
+ // required argument to avoid ambiguity with other constructors.
+ Adafruit_SPITFT(uint16_t w, uint16_t h, bool wide,
+ int8_t d0, int8_t wr, int8_t dc,
+ int8_t cs = -1, int8_t rst = -1, int8_t rd = -1);
- /*!
- @brief SPI displays set an address window rectangle for blitting pixels
- @param x Top left corner x coordinate
- @param y Top left corner x coordinate
- @param w Width of window
- @param h Height of window
- */
- virtual void setAddrWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h) = 0;
+ // CLASS MEMBER FUNCTIONS ----------------------------------------------
- /*!
- @brief Write a 2-byte color (must have a transaction in progress)
- @param color 16-bit 5-6-5 Color to draw
- */
- void inline writePixel(uint16_t color) { SPI_WRITE16(color); }
- void writePixels(uint16_t * colors, uint32_t len);
- void writeColor(uint16_t color, uint32_t len);
- void pushColor(uint16_t color);
+ // These first two functions MUST be declared by subclasses:
- // Recommended Non-Transaction
- void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
- void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
- void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
+ /*!
+ @brief Display-specific initialization function.
+ @param freq SPI frequency, in hz (or 0 for default or unused).
+ */
+ virtual void begin(uint32_t freq) = 0;
- using Adafruit_GFX::drawRGBBitmap; // Check base class first
- void drawRGBBitmap(int16_t x, int16_t y,
- uint16_t *pcolors, int16_t w, int16_t h);
- void invertDisplay(boolean i);
+ /*!
+ @brief Set up the specific display hardware's "address window"
+ for subsequent pixel-pushing operations.
+ @param x Leftmost pixel of area to be drawn (MUST be within
+ display bounds at current rotation setting).
+ @param y Topmost pixel of area to be drawn (MUST be within
+ display bounds at current rotation setting).
+ @param w Width of area to be drawn, in pixels (MUST be >0 and,
+ added to x, within display bounds at current rotation).
+ @param h Height of area to be drawn, in pixels (MUST be >0 and,
+ added to x, within display bounds at current rotation).
+ */
+ virtual void setAddrWindow(
+ uint16_t x, uint16_t y, uint16_t w, uint16_t h) = 0;
- uint16_t color565(uint8_t r, uint8_t g, uint8_t b);
- void writeCommand(uint8_t cmd);
- void spiWrite(uint8_t v);
- uint8_t spiRead(void);
+ // Remaining functions do not need to be declared in subclasses
+ // unless they wish to provide hardware-specific optimizations.
+ // Brief comments here...documented more thoroughly in .cpp file.
- protected:
- SPIClass *_spi; ///< The SPI device we want to use (set in constructor)
- uint32_t _freq; ///< SPI clock frequency (for hardware SPI)
-#if defined (__AVR__) || defined(TEENSYDUINO) || defined (ESP8266) || defined (ESP32)
- int8_t _cs, _dc, _rst, _sclk, _mosi, _miso;
-#else
- int32_t _cs, ///< Arduino pin # for chip-select pin
- _dc, ///< Arduino pin # for data-command pin
- _rst, ///< Arduino pin # for reset pin
- _sclk, ///< Arduino pin # for SPI clock pin
- _mosi, ///< Arduino pin # for SPI MOSI pin
- _miso; ///< Arduino pin # for SPI MISO pin
+ // Subclass' begin() function invokes this to initialize hardware.
+ // Name is outdated (interface may be parallel) but for compatibility:
+ void initSPI(uint32_t freq = 0); // 0 = use default SPI speed
+ // Chip select and/or hardware SPI transaction start as needed:
+ void startWrite(void);
+ // Chip deselect and/or hardware SPI transaction end as needed:
+ void endWrite(void);
+
+ // These functions require a chip-select and/or SPI transaction
+ // around them. Higher-level graphics primitives might start a
+ // single transaction and then make multiple calls to these functions
+ // (e.g. circle or text rendering might make repeated lines or rects)
+ // before ending the transaction. It's more efficient than starting a
+ // transaction every time.
+ void writePixel(int16_t x, int16_t y, uint16_t color);
+ void writePixels(uint16_t *colors, uint32_t len);
+ void writeColor(uint16_t color, uint32_t len);
+ void writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h,
+ uint16_t color);
+ void writeFastHLine(int16_t x, int16_t y, int16_t w,
+ uint16_t color);
+ void writeFastVLine(int16_t x, int16_t y, int16_t h,
+ uint16_t color);
+ // This is a new function, similar to writeFillRect() except that
+ // all arguments MUST be onscreen, sorted and clipped. If higher-level
+ // primitives can handle their own sorting/clipping, it avoids repeating
+ // such operations in the low-level code, making it potentially faster.
+ // CALLING THIS WITH UNCLIPPED OR NEGATIVE VALUES COULD BE DISASTROUS.
+ inline void writeFillRectPreclipped(int16_t x, int16_t y,
+ int16_t w, int16_t h, uint16_t color);
+ // This variant of writePixel() just calls SPI_WRITE16()...new code
+ // should probably just do the latter, consider this deprecated:
+ inline void writePixel(uint16_t color);
+
+ // These functions are similar to the 'write' functions above, but with
+ // a chip-select and/or SPI transaction built-in. They're typically used
+ // solo -- that is, as graphics primitives in themselves, not invoked by
+ // higher-level primitives (which should use the functions above).
+ void drawPixel(int16_t x, int16_t y, uint16_t color);
+ void fillRect(int16_t x, int16_t y, int16_t w, int16_t h,
+ uint16_t color);
+ void drawFastHLine(int16_t x, int16_t y, int16_t w,
+ uint16_t color);
+ void drawFastVLine(int16_t x, int16_t y, int16_t h,
+ uint16_t color);
+ // A single-pixel push encapsulated in a transaction. I don't think
+ // this is used anymore (BMP demos might've used it?) but is provided
+ // for backward compatibility, consider it deprecated:
+ void pushColor(uint16_t color);
+
+ using Adafruit_GFX::drawRGBBitmap; // Check base class first
+ void drawRGBBitmap(int16_t x, int16_t y,
+ uint16_t *pcolors, int16_t w, int16_t h);
+
+ void invertDisplay(bool i);
+ uint16_t color565(uint8_t r, uint8_t g, uint8_t b);
+
+ // Despite parallel additions, function names kept for compatibility:
+ void spiWrite(uint8_t b); // Write single byte as DATA
+ void writeCommand(uint8_t cmd); // Write single byte as COMMAND
+ uint8_t spiRead(void); // Read single byte of data
+
+ // Most of these low-level functions were formerly macros in
+ // Adafruit_SPITFT_Macros.h. Some have been made into inline functions
+ // to avoid macro mishaps. Despite the addition of code for a parallel
+ // display interface, the names have been kept for backward
+ // compatibility (some subclasses may be invoking these):
+ void SPI_WRITE16(uint16_t w); // Not inline
+ void SPI_WRITE32(uint32_t l); // Not inline
+ void SPI_WRITE_PIXELS(uint16_t *data, uint32_t bytes); // ditto
+ // Old code had both a spiWrite16() function and SPI_WRITE16 macro
+ // in addition to the SPI_WRITE32 macro. The latter two have been
+ // made into functions here, and spiWrite16() removed (use SPI_WRITE16()
+ // instead). It looks like most subclasses had gotten comfortable with
+ // SPI_WRITE16 and SPI_WRITE32 anyway so those names were kept rather
+ // than the less-obnoxious camelcase variants, oh well.
+
+ // Placing these functions entirely in the class definition inlines
+ // them implicitly them while allowing their use in other code:
+
+ /*!
+ @brief Set the chip-select line HIGH. Does NOT check whether CS pin
+ is set (>=0), that should be handled in calling function.
+ Despite function name, this is used even if the display
+ connection is parallel.
+ */
+ void SPI_CS_HIGH(void) {
+ #if defined(USE_FAST_PINIO)
+ #if defined(HAS_PORT_SET_CLR)
+ *csPortSet = csPinMask;
+ #else // !HAS_PORT_SET_CLR
+ *csPort |= csPinMaskSet;
+ #endif // end !HAS_PORT_SET_CLR
+ #else // !USE_FAST_PINIO
+ digitalWrite(_cs, HIGH);
+ #endif // end !USE_FAST_PINIO
+ }
+
+ /*!
+ @brief Set the chip-select line LOW. Does NOT check whether CS pin
+ is set (>=0), that should be handled in calling function.
+ Despite function name, this is used even if the display
+ connection is parallel.
+ */
+ void SPI_CS_LOW(void) {
+ #if defined(USE_FAST_PINIO)
+ #if defined(HAS_PORT_SET_CLR)
+ *csPortClr = csPinMask;
+ #else // !HAS_PORT_SET_CLR
+ *csPort &= csPinMaskClr;
+ #endif // end !HAS_PORT_SET_CLR
+ #else // !USE_FAST_PINIO
+ digitalWrite(_cs, LOW);
+ #endif // end !USE_FAST_PINIO
+ }
+
+ /*!
+ @brief Set the data/command line HIGH (data mode).
+ */
+ void SPI_DC_HIGH(void) {
+ #if defined(USE_FAST_PINIO)
+ #if defined(HAS_PORT_SET_CLR)
+ #if defined(KINETISK)
+ *dcPortSet = 1;
+ #else // !KINETISK
+ *dcPortSet = dcPinMask;
+ #endif // end !KINETISK
+ #else // !HAS_PORT_SET_CLR
+ *dcPort |= dcPinMaskSet;
+ #endif // end !HAS_PORT_SET_CLR
+ #else // !USE_FAST_PINIO
+ digitalWrite(_dc, HIGH);
+ #endif // end !USE_FAST_PINIO
+ }
+
+ /*!
+ @brief Set the data/command line LOW (command mode).
+ */
+ void SPI_DC_LOW(void) {
+ #if defined(USE_FAST_PINIO)
+ #if defined(HAS_PORT_SET_CLR)
+ #if defined(KINETISK)
+ *dcPortClr = 1;
+ #else // !KINETISK
+ *dcPortClr = dcPinMask;
+ #endif // end !KINETISK
+ #else // !HAS_PORT_SET_CLR
+ *dcPort &= dcPinMaskClr;
+ #endif // end !HAS_PORT_SET_CLR
+ #else // !USE_FAST_PINIO
+ digitalWrite(_dc, LOW);
+ #endif // end !USE_FAST_PINIO
+ }
+
+ protected:
+
+ // A few more low-level member functions -- some may have previously
+ // been macros. Shouldn't have a need to access these externally, so
+ // they've been moved to the protected section. Additionally, they're
+ // declared inline here and the code is in the .cpp file, since outside
+ // code doesn't need to see these.
+ inline void SPI_MOSI_HIGH(void);
+ inline void SPI_MOSI_LOW(void);
+ inline void SPI_SCK_HIGH(void);
+ inline void SPI_SCK_LOW(void);
+ inline bool SPI_MISO_READ(void);
+ inline void SPI_BEGIN_TRANSACTION(void);
+ inline void SPI_END_TRANSACTION(void);
+ inline void TFT_WR_STROBE(void); // Parallel interface write strobe
+ inline void TFT_RD_HIGH(void); // Parallel interface read high
+ inline void TFT_RD_LOW(void); // Parallel interface read low
+
+ // CLASS INSTANCE VARIABLES --------------------------------------------
+
+ // Here be dragons! There's a big union of three structures here --
+ // one each for hardware SPI, software (bitbang) SPI, and parallel
+ // interfaces. This is to save some memory, since a display's connection
+ // will be only one of these. The order of some things is a little weird
+ // in an attempt to get values to align and pack better in RAM.
+
+#if defined(USE_FAST_PINIO)
+#if defined(HAS_PORT_SET_CLR)
+ PORTreg_t csPortSet; ///< PORT register for chip select SET
+ PORTreg_t csPortClr; ///< PORT register for chip select CLEAR
+ PORTreg_t dcPortSet; ///< PORT register for data/command SET
+ PORTreg_t dcPortClr; ///< PORT register for data/command CLEAR
+#else // !HAS_PORT_SET_CLR
+ PORTreg_t csPort; ///< PORT register for chip select
+ PORTreg_t dcPort; ///< PORT register for data/command
+#endif // end HAS_PORT_SET_CLR
+#endif // end USE_FAST_PINIO
+ union {
+ struct { // Values specific to HARDWARE SPI:
+ SPIClass *_spi; ///< SPI class pointer
+ uint32_t _freq;
+ SPISettings settings;
+ } hwspi;
+ struct { // Values specific to SOFTWARE SPI:
+#if defined(USE_FAST_PINIO)
+ PORTreg_t misoPort; ///< PORT (PIN) register for MISO
+#if defined(HAS_PORT_SET_CLR)
+ PORTreg_t mosiPortSet; ///< PORT register for MOSI SET
+ PORTreg_t mosiPortClr; ///< PORT register for MOSI CLEAR
+ PORTreg_t sckPortSet; ///< PORT register for SCK SET
+ PORTreg_t sckPortClr; ///< PORT register for SCK CLEAR
+ #if !defined(KINETISK)
+ PORT_t mosiPinMask; ///< Bitmask for MOSI
+ PORT_t sckPinMask; ///< Bitmask for SCK
+ #endif // end !KINETISK
+#else // !HAS_PORT_SET_CLR
+ PORTreg_t mosiPort; ///< PORT register for MOSI
+ PORTreg_t sckPort; ///< PORT register for SCK
+ PORT_t mosiPinMaskSet; ///< Bitmask for MOSI SET (OR)
+ PORT_t mosiPinMaskClr; ///< Bitmask for MOSI CLEAR (AND)
+ PORT_t sckPinMaskSet; ///< Bitmask for SCK SET (OR bitmask)
+ PORT_t sckPinMaskClr; ///< Bitmask for SCK CLEAR (AND)
+#endif // end HAS_PORT_SET_CLR
+ #if !defined(KINETISK)
+ PORT_t misoPinMask; ///< Bitmask for MISO
+ #endif // end !KINETISK
+#endif // end USE_FAST_PINIO
+ int8_t _mosi; ///< MOSI pin #
+ int8_t _miso; ///< MISO pin #
+ int8_t _sck; ///< SCK pin #
+ } swspi;
+ struct { // Values specific to 8-bit parallel:
+#if defined(USE_FAST_PINIO)
+ volatile uint8_t *writePort; ///< PORT register for DATA WRITE
+ volatile uint8_t *readPort; ///< PORT (PIN) register for DATA READ
+#if defined(HAS_PORT_SET_CLR)
+ // Port direction register pointers are always 8-bit regardless of
+ // PORTreg_t -- even if 32-bit port, we modify a byte-aligned 8 bits.
+ volatile uint8_t *dirSet; ///< PORT byte data direction SET
+ volatile uint8_t *dirClr; ///< PORT byte data direction CLEAR
+ PORTreg_t wrPortSet; ///< PORT register for write strobe SET
+ PORTreg_t wrPortClr; ///< PORT register for write strobe CLEAR
+ PORTreg_t rdPortSet; ///< PORT register for read strobe SET
+ PORTreg_t rdPortClr; ///< PORT register for read strobe CLEAR
+ #if !defined(KINETISK)
+ PORT_t wrPinMask; ///< Bitmask for write strobe
+ #endif // end !KINETISK
+ PORT_t rdPinMask; ///< Bitmask for read strobe
+#else // !HAS_PORT_SET_CLR
+ // Port direction register pointer is always 8-bit regardless of
+ // PORTreg_t -- even if 32-bit port, we modify a byte-aligned 8 bits.
+ volatile uint8_t *portDir; ///< PORT direction register
+ PORTreg_t wrPort; ///< PORT register for write strobe
+ PORTreg_t rdPort; ///< PORT register for read strobe
+ PORT_t wrPinMaskSet; ///< Bitmask for write strobe SET (OR)
+ PORT_t wrPinMaskClr; ///< Bitmask for write strobe CLEAR (AND)
+ PORT_t rdPinMaskSet; ///< Bitmask for read strobe SET (OR)
+ PORT_t rdPinMaskClr; ///< Bitmask for read strobe CLEAR (AND)
+#endif // end HAS_PORT_SET_CLR
+#endif // end USE_FAST_PINIO
+ int8_t _d0; ///< Data pin 0 #
+ int8_t _wr; ///< Write strobe pin #
+ int8_t _rd; ///< Read strobe pin # (or -1)
+ bool wide = 0; ///< If true, is 16-bit interface
+ } tft8;
+ };
+#if defined(USE_SPI_DMA) // Used by hardware SPI and tft8
+ Adafruit_ZeroDMA dma; ///< DMA instance
+ DmacDescriptor *dptr = NULL; ///< 1st descriptor
+ DmacDescriptor *descriptor = NULL; ///< Allocated descriptor list
+ uint16_t *pixelBuf[2]; ///< Working buffers
+ uint16_t maxFillLen; ///< Max pixels per DMA xfer
+ uint16_t lastFillColor = 0; ///< Last color used w/fill
+ uint32_t lastFillLen = 0; ///< # of pixels w/last fill
+ uint8_t onePixelBuf; ///< For hi==lo fill
#endif
+#if defined(USE_FAST_PINIO)
+#if defined(HAS_PORT_SET_CLR)
+ PORT_t csPinMask; ///< Bitmask for chip select
+ #if !defined(KINETISK)
+ PORT_t dcPinMask; ///< Bitmask for data/command
+ #endif // end !KINETISK
+#else // !HAS_PORT_SET_CLR
+ PORT_t csPinMaskSet; ///< Bitmask for chip select SET (OR)
+ PORT_t csPinMaskClr; ///< Bitmask for chip select CLEAR (AND)
+ PORT_t dcPinMaskSet; ///< Bitmask for data/command SET (OR)
+ PORT_t dcPinMaskClr; ///< Bitmask for data/command CLEAR (AND)
+#endif // end HAS_PORT_SET_CLR
+#endif // end USE_FAST_PINIO
+ uint8_t connection; ///< TFT_HARD_SPI, TFT_SOFT_SPI, etc.
+ int8_t _rst; ///< Reset pin # (or -1)
+ int8_t _cs; ///< Chip select pin # (or -1)
+ int8_t _dc; ///< Data/command pin #
-#ifdef USE_FAST_PINIO
- volatile RwReg *mosiport, ///< Direct chip register for toggling MOSI with fast bitbang IO
- *misoport, ///< Direct chip register for toggling MISO with fast bitbang IO
- *clkport, ///< Direct chip register for toggling CLK with fast bitbang IO
- *dcport, ///< Direct chip register for toggling DC with fast bitbang IO
- *csport; ///< Direct chip register for toggling CS with fast bitbang IO
- RwReg mosipinmask, ///< bitmask for turning on/off MOSI with fast register bitbang IO
- misopinmask, ///< bitmask for turning on/off MISO with fast register bitbang IO
- clkpinmask, ///< bitmask for turning on/off CLK with fast register bitbang IO
- cspinmask, ///< bitmask for turning on/off CS with fast register bitbang IO
- dcpinmask; ///< bitmask for turning on/off DC with fast register bitbang IO
-#endif
+ int16_t _xstart = 0; ///< Internal framebuffer X offset
+ int16_t _ystart = 0; ///< Internal framebuffer Y offset
+ uint8_t invertOnCommand = 0; ///< Command to enable invert mode
+ uint8_t invertOffCommand = 0; ///< Command to disable invert mode
- uint8_t invertOnCommand = 0, ///< SPI command byte to turn on invert
- invertOffCommand = 0; ///< SPI command byte to turn off invert
- int16_t _xstart = 0; ///< Many displays don't have pixels starting at (0,0) of the internal framebuffer, this is the x offset from 0 to align
- int16_t _ystart = 0; ///< Many displays don't have pixels starting at (0,0) of the internal framebuffer, this is the y offset from 0 to align
-
-#ifdef USE_SPI_DMA
- Adafruit_ZeroDMA dma; ///< DMA instance
- DmacDescriptor *dptr = NULL; ///< 1st descriptor
- DmacDescriptor *descriptor = NULL; ///< Allocated descriptor list
- uint16_t *pixelBuf[2]; ///< Working buffers
- uint16_t maxFillLen; ///< Max pixels per DMA xfer
- uint16_t lastFillColor = 0; ///< Last color used w/fill
- uint32_t lastFillLen = 0; ///< # of pixels w/last fill
- uint8_t onePixelBuf; ///< For hi==lo fill
-#endif
+ uint32_t _freq = 0; ///< Dummy var to keep subclasses happy
};
-#endif // !__AVR_ATtiny85__
-
-#endif // !_ADAFRUIT_SPITFT_
+#endif // end __AVR_ATtiny85__
+#endif // end _ADAFRUIT_SPITFT_H_
diff --git a/Adafruit_SPITFT_Macros.h b/Adafruit_SPITFT_Macros.h
index 1b5bd47..fcd6253 100644
--- a/Adafruit_SPITFT_Macros.h
+++ b/Adafruit_SPITFT_Macros.h
@@ -1,116 +1,6 @@
-#ifndef _ADAFRUIT_SPITFT_MACROS
-#define _ADAFRUIT_SPITFT_MACROS
+// THIS FILE INTENTIONALLY LEFT BLANK.
-/*
- * Control Pins
- * */
-
-#ifdef USE_FAST_PINIO
-#define SPI_DC_HIGH() *dcport |= dcpinmask
-#define SPI_DC_LOW() *dcport &= ~dcpinmask
-#define SPI_CS_HIGH() *csport |= cspinmask
-#define SPI_CS_LOW() *csport &= ~cspinmask
-#else
-#define SPI_DC_HIGH() digitalWrite(_dc, HIGH)
-#define SPI_DC_LOW() digitalWrite(_dc, LOW)
-#define SPI_CS_HIGH() { if(_cs >= 0) digitalWrite(_cs, HIGH); }
-#define SPI_CS_LOW() { if(_cs >= 0) digitalWrite(_cs, LOW); }
-#endif
-
-/*
- * Software SPI Macros
- * */
-
-#ifdef USE_FAST_PINIO
-#define SSPI_MOSI_HIGH() *mosiport |= mosipinmask
-#define SSPI_MOSI_LOW() *mosiport &= ~mosipinmask
-#define SSPI_SCK_HIGH() *clkport |= clkpinmask
-#define SSPI_SCK_LOW() *clkport &= ~clkpinmask
-#define SSPI_MISO_READ() ((*misoport & misopinmask) != 0)
-#else
-#define SSPI_MOSI_HIGH() digitalWrite(_mosi, HIGH)
-#define SSPI_MOSI_LOW() digitalWrite(_mosi, LOW)
-#define SSPI_SCK_HIGH() digitalWrite(_sclk, HIGH)
-#define SSPI_SCK_LOW() digitalWrite(_sclk, LOW)
-#define SSPI_MISO_READ() digitalRead(_miso)
-#endif
-
-#define SSPI_BEGIN_TRANSACTION()
-#define SSPI_END_TRANSACTION()
-#define SSPI_WRITE(v) spiWrite(v)
-#define SSPI_WRITE16(s) SSPI_WRITE((s) >> 8); SSPI_WRITE(s)
-#define SSPI_WRITE32(l) SSPI_WRITE((l) >> 24); SSPI_WRITE((l) >> 16); SSPI_WRITE((l) >> 8); SSPI_WRITE(l)
-#define SSPI_WRITE_PIXELS(c,l) for(uint32_t i=0; i<(l); i+=2){ SSPI_WRITE(((uint8_t*)(c))[i+1]); SSPI_WRITE(((uint8_t*)(c))[i]); }
-
-/*
- * Hardware SPI Macros
- * */
-
-#if defined (__AVR__) || defined(TEENSYDUINO) || defined(ARDUINO_ARCH_STM32F1)
- #define HSPI_SET_CLOCK() _spi->setClockDivider(SPI_CLOCK_DIV2);
-#elif defined (__arm__)
- #define HSPI_SET_CLOCK() _spi->setClockDivider(11);
-#elif defined(ESP8266) || defined(ESP32)
- #define HSPI_SET_CLOCK() _spi->setFrequency(_freq);
-#elif defined(RASPI)
- #define HSPI_SET_CLOCK() _spi->setClock(_freq);
-#elif defined(ARDUINO_ARCH_STM32F1)
- #define HSPI_SET_CLOCK() _spi->setClock(_freq);
-#else
- #define HSPI_SET_CLOCK()
-#endif
-
-#ifdef SPI_HAS_TRANSACTION
- #define HSPI_BEGIN_TRANSACTION() _spi->beginTransaction(SPISettings(_freq, MSBFIRST, SPI_MODE0))
- #define HSPI_END_TRANSACTION() _spi->endTransaction()
-#else
- #define HSPI_BEGIN_TRANSACTION() HSPI_SET_CLOCK(); _spi->setBitOrder(MSBFIRST); _spi->setDataMode(SPI_MODE0)
- #define HSPI_END_TRANSACTION()
-#endif
-
-#ifdef ESP32
- #define SPI_HAS_WRITE_PIXELS
-#endif
-#if defined(ESP8266) || defined(ESP32)
- // Optimized SPI (ESP8266 and ESP32)
- #define HSPI_READ() _spi->transfer(0)
- #define HSPI_WRITE(b) _spi->write(b)
- #define HSPI_WRITE16(s) _spi->write16(s)
- #define HSPI_WRITE32(l) _spi->write32(l)
- #ifdef SPI_HAS_WRITE_PIXELS
- #define SPI_MAX_PIXELS_AT_ONCE 32
- #define HSPI_WRITE_PIXELS(c,l) _spi->writePixels(c,l)
- #else
- #define HSPI_WRITE_PIXELS(c,l) for(uint32_t i=0; i<((l)/2); i++){ SPI_WRITE16(((uint16_t*)(c))[i]); }
- #endif
-#else
- // Standard Byte-by-Byte SPI
-
- #if defined (__AVR__) || defined(TEENSYDUINO)
-static inline uint8_t _avr_spi_read(void) __attribute__((always_inline));
-static inline uint8_t _avr_spi_read(void) {
- uint8_t r = 0;
- SPDR = r;
- while(!(SPSR & _BV(SPIF)));
- r = SPDR;
- return r;
-}
- #define HSPI_WRITE(b) {SPDR = (b); while(!(SPSR & _BV(SPIF)));}
- #define HSPI_READ() _avr_spi_read()
- #else
- #define HSPI_WRITE(b) _spi->transfer((uint8_t)(b))
- #define HSPI_READ() HSPI_WRITE(0)
- #endif
- #define HSPI_WRITE16(s) HSPI_WRITE((s) >> 8); HSPI_WRITE(s)
- #define HSPI_WRITE32(l) HSPI_WRITE((l) >> 24); HSPI_WRITE((l) >> 16); HSPI_WRITE((l) >> 8); HSPI_WRITE(l)
- #define HSPI_WRITE_PIXELS(c,l) for(uint32_t i=0; i<(l); i+=2){ HSPI_WRITE(((uint8_t*)(c))[i+1]); HSPI_WRITE(((uint8_t*)(c))[i]); }
-#endif
-
- #define SPI_BEGIN() if(_sclk < 0){_spi->begin();}
- #define SPI_BEGIN_TRANSACTION() if(_sclk < 0){HSPI_BEGIN_TRANSACTION();}
- #define SPI_END_TRANSACTION() if(_sclk < 0){HSPI_END_TRANSACTION();}
- #define SPI_WRITE16(s) if(_sclk < 0){HSPI_WRITE16(s);}else{SSPI_WRITE16(s);}
- #define SPI_WRITE32(l) if(_sclk < 0){HSPI_WRITE32(l);}else{SSPI_WRITE32(l);}
- #define SPI_WRITE_PIXELS(c,l) if(_sclk < 0){HSPI_WRITE_PIXELS(c,l);}else{SSPI_WRITE_PIXELS(c,l);}
-
-#endif // _ADAFRUIT_SPITFT_MACROS
+// Macros previously #defined here have been made into (mostly) inline
+// functions in the Adafruit_SPITFT class. Other libraries might still
+// contain code trying to #include this header file, so until everything's
+// updated this file still exists (but doing nothing) to avoid trouble.
diff --git a/Adafruit_TFT8.cpp b/Adafruit_TFT8.cpp
deleted file mode 100644
index 67f9937..0000000
--- a/Adafruit_TFT8.cpp
+++ /dev/null
@@ -1,608 +0,0 @@
-/*!
-* @file Adafruit_TFT8.cpp
-*
-* @mainpage Adafruit 8-bit Parallel TFT Displays
-*
-* @section intro_sec Introduction
-* This is our library for TFT Displays using an 8-bit parallel interface
-* with address windows and 16 bit color.
-*
-* These displays use ip to 13 pins to communicate:
-* - 8 data lines (required)
-* - Write strobe (required)
-* - Command/data (required)
-* - Chip select (optional, can be tied LOW)
-* - Read strobe (optional)
-* - Reset (optional, can connect to MCU reset)
-*
-* Adafruit invests time and resources providing this open source code,
-* please support Adafruit and open-source hardware by purchasing
-* products from Adafruit!
-*
-* Written by Limor Fried/Ladyada for Adafruit Industries.
-* MIT license, all text above must be included in any redistribution
-* @section dependencies Dependencies
-*
-* This library depends on
-* Adafruit_GFX being present on your system. Please make sure you have
-* installed the latest version before using this library.
-*
-* @section author Author
-*
-* Written by Limor "ladyada" Fried for Adafruit Industries.
-*
-* @section license License
-*
-* BSD license, all text here must be included in any redistribution.
-*
-*/
-
-#if !defined(__AVR_ATtiny85__) // Not for ATtiny, at all
-
-#include "Adafruit_TFT8.h"
-
-#ifdef PORT_IOBUS
-// On SAMD21, redefine digitalPinToPort() to use the slightly-faster
-// PORT_IOBUS rather than PORT (not needed on SAMD51).
-#undef digitalPinToPort
-#define digitalPinToPort(P) (&(PORT_IOBUS->Group[g_APinDescription[P].ulPort]))
-#endif
-
-#ifdef USE_PORT_DMA
- #include
- #include // memalign() function
-
- // DMA transfer-in-progress indicator and callback
- static volatile boolean dma_busy = false;
- static void dma_callback(Adafruit_ZeroDMA *dma) {
- dma_busy = false;
- }
-#endif // USE_PORT_DMA
-
-#if defined(__AVR__)
- #define WR_LOW() *wrPort &= wrPinMaskClr;
- #define WR_HIGH() *wrPort |= wrPinMaskSet;
- #define DC_LOW() *dcPort &= dcPinMaskClr;
- #define DC_HIGH() *dcPort |= dcPinMaskSet;
- #define CS_LOW() if(_cs >= 0) *csPort &= csPinMaskClr;
- #define CS_HIGH() if(_cs >= 0) *csPort |= csPinMaskSet;
- #define RD_LOW() *rdPort &= rdPinMaskClr;
- #define RD_HIGH() *rdPort |= rdPinMaskSet;
- #define PORT_OUTPUT() *portDir = 0xFF;
- #define PORT_INPUT() *portDir = 0x00;
-#else
- #define WR_LOW() *wrPortClr = wrPinMask;
- #define WR_HIGH() *wrPortSet = wrPinMask;
- #define DC_LOW() *dcPortClr = dcPinMask;
- #define DC_HIGH() *dcPortSet = dcPinMask;
- #define CS_LOW() if(_cs >= 0) *csPortClr = csPinMask;
- #define CS_HIGH() if(_cs >= 0) *csPortSet = csPinMask;
- #define RD_LOW() *rdPortClr = rdPinMask;
- #define RD_HIGH() *rdPortSet = rdPinMask;
- #define PORT_OUTPUT() *dirSet = 0xFF;
- #define PORT_INPUT() *dirClr = 0xFF;
- #define PORT_OUTPUT16() *(volatile uint16_t *)dirSet = 0xFFFF;
- #define PORT_INPUT16() *(volatile uint16_t *)dirClr = 0xFFFF;
-#endif
-#define WR_STROBE() { WR_LOW(); WR_HIGH(); }
-
-/*!
- @brief Instantiate Adafruit TFT8 display driver.
- @param w Display width in pixels.
- @param h Display height in pixels.
- @param D0 Arduino pin # for data bit 0 (1+ are extrapolated).
- The 8 data bits MUST be contiguous and byte-aligned
- (word-aligned for 'wide' interface) within the same
- PORT register (may not correspond to Arduino pin sequence).
- @param WR Arduino pin # for write strobe.
- @param DC Arduino pin # for data/command.
- @param CS Arduino pin # for chip select (-1 if unused, tie CS low).
- @param RST Arduino pin # for reset (-1 if unused, tie to MCU reset).
- @param RD Arduino pin # for read strobe (-1 if unused).
- @param wide If true, use 16-bit wide interface (not on AVR).
-*/
-Adafruit_TFT8::Adafruit_TFT8(uint16_t w, uint16_t h,
- int8_t D0, int8_t WR, int8_t DC, int8_t CS, int8_t RST, int8_t RD,
- bool wide) : Adafruit_GFX(w, h),
- _d0(D0), _wr(WR), _dc(DC), _cs(CS), _rst(RST), _rd(RD)
-{
-#if defined(__AVR__)
- if(digitalPinToBitMask(D0) != 1) return; // D0 MUST be port bit 0
- _d0 = D0; // Save D0 pin to indicate valid alignment
- wrPort = (PORTreg_t)portOutputRegister(digitalPinToPort(WR));
- wrPinMaskSet = digitalPinToBitMask(WR);
- dcPort = (PORTreg_t)portOutputRegister(digitalPinToPort(DC));
- dcPinMaskSet = digitalPinToBitMask(DC);
- if(CS >= 0) {
- csPort = (PORTreg_t)portOutputRegister(digitalPinToPort(CS));
- csPinMaskSet = digitalPinToBitMask(CS);
- } else {
- // No chip-select line defined; might be permanently tied to GND.
- // Assign a valid GPIO register (though not used for CS), and an
- // empty pin bitmask...the nonsense bit-twiddling might be faster
- // than checking _cs and possibly branching.
- csPort = dcPort;
- csPinMaskSet = 0;
- }
- if(RD >= 0) {
- rdPort = (PORTreg_t)portOutputRegister(digitalPinToPort(RD));
- rdPinMaskSet = digitalPinToBitMask(RD);
- } else {
- // No read-strobe line defined; similar to CS case above
- rdPort = dcPort;
- rdPinMaskSet = 0;
- }
- wrPinMaskClr = ~wrPinMaskSet;
- dcPinMaskClr = ~dcPinMaskSet;
- csPinMaskClr = ~csPinMaskSet;
- rdPinMaskClr = ~rdPinMaskSet;
- writePort = (PORTreg_t)portOutputRegister(digitalPinToPort(D0));
- readPort = (PORTreg_t)portInputRegister(digitalPinToPort(D0));
- portDir = (PORTreg_t)portModeRegister(digitalPinToPort(D0));
-#else
- // Confirm D0 bit is byte- or word-aligned in PORT...
- if(g_APinDescription[D0].ulPin & (wide ? 15 : 7)) return;
- _d0 = D0; // Save D0 pin to indicate valid alignment
- _wide = wide;
- wrPinMask = digitalPinToBitMask(WR);
- wrPortSet = &(PORT->Group[g_APinDescription[WR].ulPort].OUTSET.reg);
- wrPortClr = &(PORT->Group[g_APinDescription[WR].ulPort].OUTCLR.reg);
- dcPinMask = digitalPinToBitMask(DC);
- dcPortSet = &(PORT->Group[g_APinDescription[DC].ulPort].OUTSET.reg);
- dcPortClr = &(PORT->Group[g_APinDescription[DC].ulPort].OUTCLR.reg);
- if(CS >= 0) { // If chip-select pin is specified...
- csPinMask = digitalPinToBitMask(CS);
- csPortSet = &(PORT->Group[g_APinDescription[CS].ulPort].OUTSET.reg);
- csPortClr = &(PORT->Group[g_APinDescription[CS].ulPort].OUTCLR.reg);
- } else {
- // No chip-select line defined; might be permanently tied to GND.
- // Assign a valid GPIO register (though not used for CS), and an
- // empty pin bitmask...the nonsense bit-twiddling might be faster
- // than checking _cs and possibly branching.
- csPinMask = 0;
- csPortSet = dcPortSet;
- csPortClr = dcPortClr;
- }
- if(RD >= 0) { // If read-strobe pin is specified...
- rdPinMask = digitalPinToBitMask(RD);
- rdPortSet = &(PORT->Group[g_APinDescription[RD].ulPort].OUTSET.reg);
- rdPortClr = &(PORT->Group[g_APinDescription[RD].ulPort].OUTCLR.reg);
- } else {
- rdPinMask = 0;
- rdPortSet = dcPortSet;
- rdPortClr = dcPortClr;
- }
-
- // Get pointers to PORT write/read/dir bytes within 32-bit PORT
- uint8_t dBit = g_APinDescription[_d0].ulPin; // d0 bit # in PORT
- PortGroup *p = (&(PORT->Group[g_APinDescription[_d0].ulPort]));
- uint8_t offset = dBit / 8; // d[7:0] byte # within PORT
- if(wide) offset &= ~1; // d[15:8] byte # within PORT
- // These are all uint8_t* pointers -- elsewhere they're recast
- // as necessary if a 'wide' 16-bit interface is in use.
- writePort = (volatile uint8_t *)&(p->OUT.reg) + offset;
- readPort = (volatile uint8_t *)&(p->IN.reg) + offset;
- dirSet = (volatile uint8_t *)&(p->DIRSET.reg) + offset;
- dirClr = (volatile uint8_t *)&(p->DIRCLR.reg) + offset;
-#endif
-}
-
-/*!
- @brief Initialiaze hardware interface.
-*/
-bool Adafruit_TFT8::init(void) {
-
- if(_d0 < 0) return false; // Bad alignment in constructor
-
- // Initialize data pins. We were only passed d0, so scan
- // the pin description list looking for the other pins.
- // They'll be on the same PORT, and within the next 7 (or 15) bits
- // (because we need to write to a contiguous PORT byte or word).
-#if defined(__AVR__)
- // PORT registers are 8 bits wide, so just need a register match...
- for(uint8_t i=0; i= dBit ) &&
- (g_APinDescription[i].ulPin <= (uint32_t)lastBit)) {
- pinMode(i, OUTPUT);
- digitalWrite(i, LOW);
- }
- }
-#endif
-
- // Initialize control signal pins, all active LOW
- pinMode(_wr, OUTPUT);
- digitalWrite(_wr, HIGH);
- pinMode(_dc, OUTPUT);
- digitalWrite(_dc, HIGH);
- if(_cs >= 0) {
- pinMode(_cs, OUTPUT);
- digitalWrite(_cs, HIGH); // Deselect
- }
- if(_rd >= 0) {
- pinMode(_rd, OUTPUT);
- digitalWrite(_rd, HIGH);
- }
- if(_rst >= 0) {
- pinMode(_rst, OUTPUT);
- digitalWrite(_rst, HIGH);
- delay(100);
- digitalWrite(_rst, LOW); // Toggle RST low to reset
- delay(100);
- digitalWrite(_rst, HIGH);
- delay(200);
- }
-
- return true;
-}
-
-/*!
- @brief Initiate write (or read!) operation.
-*/
-inline void Adafruit_TFT8::startWrite(void) {
- CS_LOW(); // Chip select LOW
-}
-
-/*!
- @brief End write (or read!) operation.
-*/
-inline void Adafruit_TFT8::endWrite(void) {
- CS_HIGH(); // Chip select HIGH
-}
-
-/*!
- @brief Write one byte to hardware interface.
- @param b One byte to send, MSB order
-*/
-void Adafruit_TFT8::write8(uint8_t b) {
-#if defined(__AVR__)
- *writePort = b;
-#else
- if(!_wide) {
- *writePort = b;
- } else {
- *(volatile uint16_t *)writePort = b;
- }
-#endif
- WR_STROBE(); // Write strobe LOW, HIGH
-}
-
-/*!
- @brief Write one word to hardware interface.
- @param w One word to send, MSB order
-*/
-void Adafruit_TFT8::write16(uint16_t w) {
-#if defined(__AVR__)
- *writePort = w >> 8; // MSB
- WR_STROBE(); // Write strobe LOW, HIGH
- *writePort = w; // LSB
- WR_STROBE(); // Write strobe LOW, HIGH
-#else
- if(!_wide) {
- *writePort = w >> 8; // MSB
- WR_STROBE(); // Write strobe LOW, HIGH
- *writePort = w; // LSB
- } else {
- *(volatile uint16_t *)writePort = w;
- }
- WR_STROBE(); // Write strobe LOW, HIGH
-#endif
-}
-
-/*!
- @brief Write a command byte.
- @param cmd The 8-bit command to send.
-*/
-void Adafruit_TFT8::writeCommand(uint8_t cmd) {
- DC_LOW(); // Data/Command LOW (command mode)
- write8(cmd); // Issue value
- DC_HIGH(); // Data/Command HIGH (data mode)
-}
-
-/*!
- @brief Read one byte or word from TFT interface.
- @returns One byte or word, native order.
-*/
-uint16_t Adafruit_TFT8::read(void) {
- uint16_t r = 0;
- if(_rd >= 0) {
-#if defined(__AVR__)
- PORT_INPUT(); // Set port to INPUT
- RD_LOW(); // Read strobe LOW
- r = *readPort; // Read value from port
- RD_HIGH(); // Read strobe HIGH
- PORT_OUTPUT(); // Set port back to OUTPUT
-#else
- if(!_wide) {
- PORT_INPUT(); // Set port to INPUT
- RD_LOW(); // Read strobe LOW
- r = *readPort; // Read value from port
- RD_HIGH(); // Read strobe HIGH
- PORT_OUTPUT(); // Set port back to OUTPUT
- } else {
- PORT_INPUT16(); // Set port to INPUT (16-bit)
- RD_LOW(); // Read strobe LOW
- r = *(volatile uint16_t *)readPort; // Read value from port
- RD_HIGH(); // Read strobe HIGH
- PORT_OUTPUT16(); // Set port back to OUTPUT (16-bit)
- }
-#endif
- }
- return r;
-}
-
-/*!
- @brief Draw a single pixel.
- @param x X coordinate.
- @param y Y coordinate.
- @param color 16-bit 5-6-5 pixel color.
-*/
-void Adafruit_TFT8::drawPixel(int16_t x, int16_t y, uint16_t color) {
- // Clip first...
- if((x >= 0) && (x < _width) && (y >= 0) && (y < _height)) {
- // THEN device-select and draw...
- startWrite();
- setAddrWindow(x, y, 1, 1);
- writePixel(color);
- endWrite();
- }
-}
-
-
-
-
-/*!
- @brief Converts 8-bit (each) R,G,B color to 16-bit packed 5-6-5 value.
- @param red Red level, 0 to 255
- @param green Green level, 0 to 255
- @param blue Blue level, 0 to 255
- @return Unsigned 16-bit decimated color in "5-6-5" format
-*/
-uint16_t Adafruit_TFT8::color565(uint8_t red, uint8_t green, uint8_t blue) {
- return ((red & 0xF8) << 8) | ((green & 0xFC) << 3) | (blue >> 3);
-}
-
-
-#if 0
-
-
-
-
-
-
-/*!
- @brief Issue multiple 2-byte colors.
- @param colors Array of 16-bit 5-6-5 Colors to draw.
- @param len How many pixels to draw.
-*/
-void Adafruit_TFT8::writePixels(uint16_t *colors, uint32_t len) {
- SPI_WRITE_PIXELS((uint8_t*)colors , len * 2);
-}
-
-/*!
- @brief Issue a 2-byte color many times.
- @param color The 16-bit 5-6-5 Color to draw.
- @param len How many pixels to draw.
-*/
-void Adafruit_TFT8::writeColor(uint16_t color, uint32_t len) {
-
- if(!len) return; // Avoid 0-byte transfers
-
- uint8_t hi = color >> 8, lo = color;
-
- if(hi != lo) {
- } else {
- len *= 2;
-// Issue as bytes
- }
-}
-
-/**************************************************************************/
-/*!
- @brief Write a pixel (must have a transaction in progress)
- @param x x coordinate
- @param y y coordinate
- @param color 16-bit 5-6-5 Color to draw with
-*/
-/**************************************************************************/
-void Adafruit_SPITFT::writePixel(int16_t x, int16_t y, uint16_t color) {
- if((x < 0) ||(x >= _width) || (y < 0) || (y >= _height)) return;
- setAddrWindow(x,y,1,1);
- writePixel(color);
-}
-
-/**************************************************************************/
-/*!
- @brief Write a filled rectangle (must have a transaction in progress)
- @param x Top left corner x coordinate
- @param y Top left corner y coordinate
- @param w Width in pixels
- @param h Height in pixels
- @param color 16-bit 5-6-5 Color to fill with
-*/
-/**************************************************************************/
-void Adafruit_SPITFT::writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color){
- if((x >= _width) || (y >= _height)) return;
- int16_t x2 = x + w - 1, y2 = y + h - 1;
- if((x2 < 0) || (y2 < 0)) return;
-
- // Clip left/top
- if(x < 0) {
- x = 0;
- w = x2 + 1;
- }
- if(y < 0) {
- y = 0;
- h = y2 + 1;
- }
-
- // Clip right/bottom
- if(x2 >= _width) w = _width - x;
- if(y2 >= _height) h = _height - y;
-
- setAddrWindow(x, y, w, h);
- writeColor(color, (int32_t)w * h);
-}
-
-/**************************************************************************/
-/*!
- @brief Write a perfectly vertical line (must have a transaction in progress)
- @param x Top-most x coordinate
- @param y Top-most y coordinate
- @param h Height in pixels
- @param color 16-bit 5-6-5 Color to fill with
-*/
-/**************************************************************************/
-void inline Adafruit_SPITFT::writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color){
- writeFillRect(x, y, 1, h, color);
-}
-
-/**************************************************************************/
-/*!
- @brief Write a perfectly horizontal line (must have a transaction in progress)
- @param x Left-most x coordinate
- @param y Left-most y coordinate
- @param w Width in pixels
- @param color 16-bit 5-6-5 Color to fill with
-*/
-/**************************************************************************/
-void inline Adafruit_SPITFT::writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color){
- writeFillRect(x, y, w, 1, color);
-}
-
-/**************************************************************************/
-/*!
- @brief Write a perfectly vertical line - sets up transaction
- @param x Top-most x coordinate
- @param y Top-most y coordinate
- @param h Height in pixels
- @param color 16-bit 5-6-5 Color to fill with
-*/
-/**************************************************************************/
-void Adafruit_SPITFT::drawFastVLine(int16_t x, int16_t y,
- int16_t h, uint16_t color) {
- startWrite();
- writeFastVLine(x, y, h, color);
- endWrite();
-}
-
-/**************************************************************************/
-/*!
- @brief Write a perfectly horizontal line - sets up transaction
- @param x Left-most x coordinate
- @param y Left-most y coordinate
- @param w Width in pixels
- @param color 16-bit 5-6-5 Color to fill with
-*/
-/**************************************************************************/
-void Adafruit_SPITFT::drawFastHLine(int16_t x, int16_t y,
- int16_t w, uint16_t color) {
- startWrite();
- writeFastHLine(x, y, w, color);
- endWrite();
-}
-
-/**************************************************************************/
-/*!
- @brief Fill a rectangle completely with one color.
- @param x Top left corner x coordinate
- @param y Top left corner y coordinate
- @param w Width in pixels
- @param h Height in pixels
- @param color 16-bit 5-6-5 Color to fill with
-*/
-/**************************************************************************/
-void Adafruit_SPITFT::fillRect(int16_t x, int16_t y, int16_t w, int16_t h,
- uint16_t color) {
- startWrite();
- writeFillRect(x,y,w,h,color);
- endWrite();
-}
-
-
-/**************************************************************************/
-/*!
- @brief Invert the display using built-in hardware command
- @param i True if you want to invert, false to make 'normal'
-*/
-/**************************************************************************/
-void Adafruit_SPITFT::invertDisplay(boolean i) {
- startWrite();
- writeCommand(i ? invertOnCommand : invertOffCommand);
- endWrite();
-}
-
-
-/**************************************************************************/
-/*!
- @brief Draw a 16-bit image (RGB 5/6/5) at the specified (x,y) position.
- For 16-bit display devices; no color reduction performed.
- Adapted from https://github.com/PaulStoffregen/ILI9341_t3
- by Marc MERLIN. See examples/pictureEmbed to use this.
- 5/6/2017: function name and arguments have changed for compatibility
- with current GFX library and to avoid naming problems in prior
- implementation. Formerly drawBitmap() with arguments in different order.
-
- @param x Top left corner x coordinate
- @param y Top left corner y coordinate
- @param pcolors 16-bit array with 16-bit color bitmap
- @param w Width of bitmap in pixels
- @param h Height of bitmap in pixels
-*/
-/**************************************************************************/
-void Adafruit_SPITFT::drawRGBBitmap(int16_t x, int16_t y,
- uint16_t *pcolors, int16_t w, int16_t h) {
-
- int16_t x2, y2; // Lower-right coord
- if(( x >= _width ) || // Off-edge right
- ( y >= _height) || // " top
- ((x2 = (x+w-1)) < 0 ) || // " left
- ((y2 = (y+h-1)) < 0) ) return; // " bottom
-
- int16_t bx1=0, by1=0, // Clipped top-left within bitmap
- saveW=w; // Save original bitmap width value
- if(x < 0) { // Clip left
- w += x;
- bx1 = -x;
- x = 0;
- }
- if(y < 0) { // Clip top
- h += y;
- by1 = -y;
- y = 0;
- }
- if(x2 >= _width ) w = _width - x; // Clip right
- if(y2 >= _height) h = _height - y; // Clip bottom
-
- pcolors += by1 * saveW + bx1; // Offset bitmap ptr to clipped top-left
- startWrite();
- setAddrWindow(x, y, w, h); // Clipped area
- while(h--) { // For each (clipped) scanline...
- writePixels(pcolors, w); // Push one (clipped) row
- pcolors += saveW; // Advance pointer by one full (unclipped) line
- }
- endWrite();
-}
-
-
-
-
-
-
-#endif // 0
-
-
-
-
-#endif // !__AVR_ATtiny85__
-
diff --git a/Adafruit_TFT8.h b/olde/Adafruit_TFT8.h
similarity index 100%
rename from Adafruit_TFT8.h
rename to olde/Adafruit_TFT8.h
diff --git a/olde/ttt.ttt b/olde/ttt.ttt
new file mode 100644
index 0000000..e52072c
--- /dev/null
+++ b/olde/ttt.ttt
@@ -0,0 +1,60 @@
+#define TFT_HARD_SPI 0
+#define TFT_SOFT_SPI 1
+#define TFT_PARALLEL 2
+
+#if defined(USE_FAST_PINIO)
+#if defined(HAS_PORT_SET_CLR)
+ #define TFT_CS_HIGH() { *csPortSet = csPinMask; }
+ #define TFT_CS_LOW() { *csPortClr = csPinMask; }
+ #define TFT_DC_HIGH() { *dcPortSet = dcPinMask; }
+ #define TFT_DC_LOW() { *dcPortClr = dcPinMask; }
+ #define TFT_MOSI_HIGH() { *mosiPortSet = mosiPinMask; }
+ #define TFT_MOSI_LOW() { *mosiPortClr = mosiPinMask; }
+ #define TFT_SCK_HIGH() { *sckPortSet = sckPinMask; }
+ #define TFT_SCK_LOW() { *sckPortClr = sckPinMask; }
+ #define TFT_WR_HIGH() { *wrPortSet = wrPinMask; }
+ #define TFT_WR_LOW() { *wrPortClr = wrPinMask; }
+ #define TFT_RD_HIGH() { *rdPortSet = rdPinMask; }
+ #define TFT_RD_LOW() { *rdPortClr = rdPinMask; }
+ #define TFT_PORT_OUTPUT() { *dirSet = 0xFF; }
+ #define TFT_PORT_INPUT() { *dirClr = 0xFF; }
+ #define TFT_PORT_OUTPUT16() { *(volatile uint16_t *)dirSet = 0xFFFF; }
+ #define TFT_PORT_INPUT16() { *(volatile uint16_t *)dirClr = 0xFFFF; }
+#else // !HAS_PORT_SET_CLR
+ #define TFT_CS_HIGH() { *csPort |= csPinMaskSet; }
+ #define TFT_CS_LOW() { *csPort &= csPinMaskClr; }
+ #define TFT_DC_HIGH() { *dcPort |= dcPinMaskSet; }
+ #define TFT_DC_LOW() { *dcPort &= dcPinMaskClr; }
+ #define TFT_MOSI_HIGH() { *mosiPort |= mosiPinMaskSet; }
+ #define TFT_MOSI_LOW() { *mosiPort &= mosiPinMaskClr; }
+ #define TFT_SCK_HIGH() { *sckPort |= sckPinMaskSet; }
+ #define TFT_SCK_LOW() { *sckPort &= sckPinMaskClr; }
+ #define TFT_WR_HIGH() { *wrPort |= wrPinMaskSet; }
+ #define TFT_WR_LOW() { *wrPort &= wrPinMaskClr; }
+ #define TFT_RD_HIGH() { *rdPort |= rdPinMaskSet; }
+ #define TFT_RD_LOW() { *rdPort &= rdPinMaskClr; }
+ #define TFT_PORT_OUTPUT() { *portDir = 0xFF; }
+ #define TFT_PORT_INPUT() { *portDir = 0x00; }
+ #define TFT_PORT_OUTPUT16() { *(volatile uint16_t *)portDir = 0xFFFF; }
+ #define TFT_PORT_INPUT16() { *(volatile uint16_t *)portDir = 0x0000; }
+#endif // end HAS_PORT_SET_CLR
+ #define TFT_SPI_READ() (*misoPort & misoPinMask)
+#else // !USE_FAST_PINIO
+ #define TFT_CS_HIGH() digitalWrite(_cs , HIGH)
+ #define TFT_CS_LOW() digitalWrite(_cs , LOW )
+ #define TFT_DC_HIGH() digitalWrite(_dc , HIGH)
+ #define TFT_DC_LOW() digitalWrite(_dc , LOW )
+ #define TFT_MOSI_HIGH() digitalWrite(_mosi, HIGH)
+ #define TFT_MOSI_LOW() digitalWrite(_mosi, LOW )
+ #define TFT_SCK_HIGH() digitalWrite(_sck , HIGH)
+ #define TFT_SCK_LOW() digitalWrite(_sck , LOW )
+ #define TFT_WR_HIGH() digitalWrite(_wr , HIGH)
+ #define TFT_WR_LOW() digitalWrite(_wr , LOW )
+ #define TFT_RD_HIGH() digitalWrite(_rd , HIGH)
+ #define TFT_RD_LOW() digitalWrite(_rd , LOW )
+ #define TFT_PORT_OUTPUT() { } // 8-bit parallel is not supported
+ #define TFT_PORT_INPUT() { } // if USE_FAST_PINIO is unavailable.
+ #define TFT_PORT_OUTPUT16() { } // No plans to implement this. If no
+ #define TFT_PORT_INPUT16() { } // PORT access, use an SPI display!
+ #define TFT_SPI_READ() digitalRead(_miso)
+#endif // end USE_FAST_PINIO