From 8bc14357cd6d252b1324cb01a25d40cecdd00574 Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Sun, 14 Apr 2024 16:54:03 +0200 Subject: [PATCH] SSD1331 driver replaced with uDisplay --- .../Adafruit_SPITFT_Renderer.cpp | 2222 ----------------- .../Adafruit_SPITFT_Renderer.h | 525 ---- .../Adafruit_SSD1331.cpp | 190 -- .../Adafruit_SSD1331-1.2.0/Adafruit_SSD1331.h | 76 - .../Adafruit_SSD1331-1.2.0/README.md | 24 - .../Adafruit_SSD1331-1.2.0/library.properties | 10 - .../Adafruit_SSD1331-1.2.0/license.txt | 26 - tasmota/include/tasmota_configurations.h | 1 - tasmota/include/tasmota_template.h | 9 +- tasmota/my_user_config.h | 2 +- tasmota/tasmota_support/support_features.ino | 7 +- .../tasmota_xdsp_display/xdsp_14_SSD1331.ino | 353 +-- 12 files changed, 188 insertions(+), 3257 deletions(-) delete mode 100644 lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SPITFT_Renderer.cpp delete mode 100644 lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SPITFT_Renderer.h delete mode 100644 lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SSD1331.cpp delete mode 100644 lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SSD1331.h delete mode 100644 lib/lib_display/Adafruit_SSD1331-1.2.0/README.md delete mode 100644 lib/lib_display/Adafruit_SSD1331-1.2.0/library.properties delete mode 100644 lib/lib_display/Adafruit_SSD1331-1.2.0/license.txt diff --git a/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SPITFT_Renderer.cpp b/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SPITFT_Renderer.cpp deleted file mode 100644 index bf1d5cb1ddce..000000000000 --- a/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SPITFT_Renderer.cpp +++ /dev/null @@ -1,2222 +0,0 @@ -/* - * This class is basically the same as Adafruit_SPITFT. - * The only difference is: it extends Renderer which extends Adafruit_GFX. - * The original Adafruit_SPITFT class directly extends Adafruit_GFX. - */ -/*! - * @file Adafruit_SPITFT_Renderer.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! - - * @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 for ATtiny, at all - -#include "Adafruit_SPITFT_Renderer.h" - -#if defined(__AVR__) -#if defined(__AVR_XMEGA__) //only tested with __AVR_ATmega4809__ -#define AVR_WRITESPI(x) for(SPI0_DATA = (x); (!(SPI0_INTFLAGS & _BV(SPI_IF_bp))); ) -#else -#define AVR_WRITESPI(x) for(SPDR = (x); (!(SPSR & _BV(SPIF))); ) -#endif -#endif - -#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 // end PORT_IOBUS - -#if defined(USE_SPI_DMA) - #include - #include "wiring_private.h" // pinPeripheral() function - #include // memalign() function - #define tcNum 2 // Timer/Counter for parallel write strobe PWM - #define wrPeripheral PIO_CCL // Use CCL to invert write strobe - - // DMA transfer-in-progress indicator and callback - static volatile bool dma_busy = false; - static void dma_callback(Adafruit_ZeroDMA *dma) { - dma_busy = false; - } - - #if defined(__SAMD51__) - // Timer/counter info by index # - static const struct { - Tc *tc; // -> Timer/Counter base address - int gclk; // GCLK ID - int evu; // EVSYS user ID - } tcList[] = { - { TC0, TC0_GCLK_ID, EVSYS_ID_USER_TC0_EVU }, - { TC1, TC1_GCLK_ID, EVSYS_ID_USER_TC1_EVU }, - { TC2, TC2_GCLK_ID, EVSYS_ID_USER_TC2_EVU }, - { TC3, TC3_GCLK_ID, EVSYS_ID_USER_TC3_EVU }, - #if defined(TC4) - { TC4, TC4_GCLK_ID, EVSYS_ID_USER_TC4_EVU }, - #endif - #if defined(TC5) - { TC5, TC5_GCLK_ID, EVSYS_ID_USER_TC5_EVU }, - #endif - #if defined(TC6) - { TC6, TC6_GCLK_ID, EVSYS_ID_USER_TC6_EVU }, - #endif - #if defined(TC7) - { TC7, TC7_GCLK_ID, EVSYS_ID_USER_TC7_EVU } - #endif - }; - #define NUM_TIMERS (sizeof tcList / sizeof tcList[0]) ///< # timer/counters - #endif // end __SAMD51__ - -#endif // end USE_SPI_DMA - -// Possible values for Adafruit_SPITFT_Renderer.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 Adafruit_SPITFT_Renderer 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_Renderer 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_Renderer::Adafruit_SPITFT_Renderer(uint16_t w, uint16_t h, - int8_t cs, int8_t dc, int8_t mosi, int8_t sck, int8_t rst, int8_t miso) : - Renderer(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) - #if !defined(KINETISK) - dcPinMask = digitalPinToBitMask(dc); - swspi.sckPinMask = digitalPinToBitMask(sck); - swspi.mosiPinMask = digitalPinToBitMask(mosi); - #endif - 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) { - #if !defined(KINETISK) - csPinMask = digitalPinToBitMask(cs); - #endif - csPortSet = portSetRegister(cs); - csPortClr = portClearRegister(cs); - } else { - #if !defined(KINETISK) - csPinMask = 0; - #endif - csPortSet = dcPortSet; - csPortClr = dcPortClr; - } - if(miso >= 0) { - swspi.misoPort = portInputRegister(miso); - #if !defined(KINETISK) - swspi.misoPinMask = digitalPinToBitMask(miso); - #endif - } 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. - csPortSet = dcPortSet; - csPortClr = dcPortClr; - csPinMask = 0; - } - if(miso >= 0) { - swspi.misoPinMask=digitalPinToBitMask(miso); - swspi.misoPort =(PORTreg_t)portInputRegister(digitalPinToPort(miso)); - } else { - swspi.misoPinMask=0; - swspi.misoPort =(PORTreg_t)portInputRegister(digitalPinToPort(dc)); - } - #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(miso); - } 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 Adafruit_SPITFT_Renderer 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_Renderer 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. -*/ -#if defined(ESP8266) // See notes below -Adafruit_SPITFT_Renderer::Adafruit_SPITFT_Renderer(uint16_t w, uint16_t h, int8_t cs, - int8_t dc, int8_t rst) : Renderer(w, h), - connection(TFT_HARD_SPI), _rst(rst), _cs(cs), _dc(dc) { - hwspi._spi = &SPI; -} -#else // !ESP8266 -Adafruit_SPITFT_Renderer::Adafruit_SPITFT_Renderer(uint16_t w, uint16_t h, int8_t cs, - int8_t dc, int8_t rst) : Adafruit_SPITFT_Renderer(w, h, &SPI, cs, dc, rst) { - // This just invokes the hardware SPI constructor below, - // passing the default SPI device (&SPI). -} -#endif // end !ESP8266 - -#if !defined(ESP8266) -// ESP8266 compiler freaks out at this constructor -- it can't disambiguate -// beteween the SPIClass pointer (argument #3) and a regular integer. -// Solution here it to just not offer this variant on the ESP8266. You can -// use the default hardware SPI peripheral, or you can use software SPI, -// but if there's any library out there that creates a 'virtual' SPIClass -// peripheral and drives it with software bitbanging, that's not supported. -/*! - @brief Adafruit_SPITFT_Renderer 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. &SPI or &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_Renderer object. - @note Output pins are not initialized in constructor; application - typically will need to call subclass' begin() function, which - in turn calls this library's initSPI() function to initialize - pins. EXCEPT...if you have built your own SERCOM SPI peripheral - (calling the SPIClass constructor) rather than one of the - built-in SPI devices (e.g. &SPI, &SPI1 and so forth), you will - need to call the begin() function for your object as well as - pinPeripheral() for the MOSI, MISO and SCK pins to configure - GPIO manually. Do this BEFORE calling the display-specific - begin or init function. Unfortunate but unavoidable. -*/ -Adafruit_SPITFT_Renderer::Adafruit_SPITFT_Renderer(uint16_t w, uint16_t h, SPIClass *spiClass, - int8_t cs, int8_t dc, int8_t rst) : Renderer(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) - #if !defined(KINETISK) - dcPinMask = digitalPinToBitMask(dc); - #endif - dcPortSet = portSetRegister(dc); - dcPortClr = portClearRegister(dc); - if(cs >= 0) { - #if !defined(KINETISK) - csPinMask = digitalPinToBitMask(cs); - #endif - csPortSet = portSetRegister(cs); - csPortClr = portClearRegister(cs); - } else { // see comments below - #if !defined(KINETISK) - csPinMask = 0; - #endif - csPortSet = dcPortSet; - csPortClr = dcPortClr; - } - #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 -} -#endif // end !ESP8266 - -/*! - @brief Adafruit_SPITFT_Renderer 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 busWidth If tft16 (enumeration in header file), is a 16-bit - parallel connection, else 8-bit. - 16-bit isn't fully implemented or tested yet so - applications should pass "tft8bitbus_Renderer" for now...needed to - stick a required enum 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 rd Arduino pin # for read strobe (optional, -1 if unused). - @return Adafruit_SPITFT_Renderer 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_Renderer::Adafruit_SPITFT_Renderer(uint16_t w, uint16_t h, tftBusWidth_Renderer busWidth, - int8_t d0, int8_t wr, int8_t dc, int8_t cs, int8_t rst, int8_t rd) : - Renderer(w, h), connection(TFT_PARALLEL), _rst(rst), _cs(cs), _dc(dc) { - tft8._d0 = d0; - tft8._wr = wr; - tft8._rd = rd; - tft8.wide = (busWidth == tft16bitbus_Renderer); -#if defined(USE_FAST_PINIO) - #if defined(HAS_PORT_SET_CLR) - #if defined(CORE_TEENSY) - tft8.wrPortSet = portSetRegister(wr); - tft8.wrPortClr = portClearRegister(wr); - #if !defined(KINETISK) - dcPinMask = digitalPinToBitMask(dc); - #endif - dcPortSet = portSetRegister(dc); - dcPortClr = portClearRegister(dc); - if(cs >= 0) { - #if !defined(KINETISK) - csPinMask = digitalPinToBitMask(cs); - #endif - csPortSet = portSetRegister(cs); - csPortClr = portClearRegister(cs); - } else { // see comments below - #if !defined(KINETISK) - csPinMask = 0; - #endif - csPortSet = dcPortSet; - csPortClr = dcPortClr; - } - 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(tft8.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. - @param spiMode SPI mode when using hardware SPI. MUST be one of the - values SPI_MODE0, SPI_MODE1, SPI_MODE2 or SPI_MODE3 - defined in SPI.h. Do NOT attempt to pass '0' for - SPI_MODE0 and so forth...the values are NOT the same! - Use ONLY the defines! (Pity it's not an enum.) - @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_Renderer::initSPI(uint32_t freq, uint8_t spiMode) { - - 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 - } - pinMode(_dc, OUTPUT); - digitalWrite(_dc, HIGH); // Data mode - - if(connection == TFT_HARD_SPI) { - -#if defined(SPI_HAS_TRANSACTION) - hwspi.settings = SPISettings(freq, MSBFIRST, spiMode); -#else - hwspi._freq = freq; // Save freq value for later -#endif - hwspi._mode = spiMode; // Save spiMode value for later - // Call hwspi._spi->begin() ONLY if this is among the 'established' - // SPI interfaces in variant.h. For DIY roll-your-own SERCOM SPIs, - // begin() and pinPeripheral() calls MUST be made in one's calling - // code, BEFORE the screen-specific begin/init function is called. - // Reason for this is that SPI::begin() makes its own calls to - // pinPeripheral() based on g_APinDescription[n].ulPinType, which - // on non-established SPI interface pins will always be PIO_DIGITAL - // or similar, while we need PIO_SERCOM or PIO_SERCOM_ALT...it's - // highly unique between devices and variants for each pin or - // SERCOM so we can't make those calls ourselves here. And the SPI - // device needs to be set up before calling this because it's - // immediately followed with initialization commands. Blargh. - if( -#if !defined(SPI_INTERFACES_COUNT) - 1 -#endif -#if SPI_INTERFACES_COUNT > 0 - (hwspi._spi == &SPI) -#endif -#if SPI_INTERFACES_COUNT > 1 - || (hwspi._spi == &SPI1) -#endif -#if SPI_INTERFACES_COUNT > 2 - || (hwspi._spi == &SPI2) -#endif -#if SPI_INTERFACES_COUNT > 3 - || (hwspi._spi == &SPI3) -#endif -#if SPI_INTERFACES_COUNT > 4 - || (hwspi._spi == &SPI4) -#endif -#if SPI_INTERFACES_COUNT > 5 - || (hwspi._spi == &SPI5) -#endif - ) { - hwspi._spi->begin(); - } - } else if(connection == 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); - } - - } else { // 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); - } - } - - if(_rst >= 0) { - // Toggle _rst low to reset - pinMode(_rst, OUTPUT); - digitalWrite(_rst, HIGH); - delay(100); - digitalWrite(_rst, LOW); - delay(100); - digitalWrite(_rst, HIGH); - delay(200); - } - -#if defined(USE_SPI_DMA) - if(((connection == TFT_HARD_SPI) || (connection == TFT_PARALLEL)) && - (dma.allocate() == DMA_STATUS_OK)) { // Allocate channel - // The DMA library needs to alloc at least one valid descriptor, - // so we do that here. It's not used in the usual sense though, - // just before a transfer we copy descriptor[0] to this address. - if(dptr = dma.addDescriptor(NULL, NULL, 42, DMA_BEAT_SIZE_BYTE, - false, false)) { - // Alloc 2 scanlines worth of pixels on display's major axis, - // whichever that is, rounding each up to 2-pixel boundary. - int major = (WIDTH > HEIGHT) ? WIDTH : HEIGHT; - major += (major & 1); // -> next 2-pixel bound, if needed. - maxFillLen = major * 2; // 2 scanlines - // Note to future self: if you decide to make the pixel buffer - // much larger, remember that DMA transfer descriptors can't - // exceed 65,535 bytes (not 65,536), meaning 32,767 pixels max. - // Not that we have that kind of RAM to throw around right now. - if((pixelBuf[0] = - (uint16_t *)malloc(maxFillLen * sizeof(uint16_t)))) { - // Alloc OK. Get pointer to start of second scanline. - pixelBuf[1] = &pixelBuf[0][major]; - // Determine number of DMA descriptors needed to cover - // entire screen when entire 2-line pixelBuf is used - // (round up for fractional last descriptor). - int numDescriptors = (WIDTH * HEIGHT + (maxFillLen - 1)) / - maxFillLen; - // DMA descriptors MUST be 128-bit (16 byte) aligned. - // memalign() is considered obsolete but it's replacements - // (aligned_alloc() or posix_memalign()) are not currently - // available in the version of ARM GCC in use, but this - // is, so here we are. - if((descriptor = (DmacDescriptor *)memalign(16, - numDescriptors * sizeof(DmacDescriptor)))) { - int dmac_id; - volatile uint32_t *data_reg; - - if(connection == TFT_HARD_SPI) { - // THIS IS AN AFFRONT TO NATURE, but I don't know - // any "clean" way to get the sercom number from the - // the SPIClass pointer (e.g. &SPI or &SPI1), which - // is all we have to work with. SPIClass does contain - // a SERCOM pointer but it is a PRIVATE member! - // Doing an UNSPEAKABLY HORRIBLE THING here, directly - // accessing the first 32-bit value in the SPIClass - // structure, knowing that's (currently) where the - // SERCOM pointer lives, but this ENTIRELY DEPENDS on - // that structure not changing nor the compiler - // rearranging things. Oh the humanity! - - if(*(SERCOM **)hwspi._spi == &sercom0) { - dmac_id = SERCOM0_DMAC_ID_TX; - data_reg = &SERCOM0->SPI.DATA.reg; -#if defined 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 **)hwspi._spi == &sercom2) { - dmac_id = SERCOM2_DMAC_ID_TX; - data_reg = &SERCOM2->SPI.DATA.reg; -#endif -#if defined 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 **)hwspi._spi == &sercom4) { - dmac_id = SERCOM4_DMAC_ID_TX; - data_reg = &SERCOM4->SPI.DATA.reg; -#endif -#if defined SERCOM5 - } else if(*(SERCOM **)hwspi._spi == &sercom5) { - dmac_id = SERCOM5_DMAC_ID_TX; - data_reg = &SERCOM5->SPI.DATA.reg; -#endif -#if defined SERCOM6 - } else if(*(SERCOM **)hwspi._spi == &sercom6) { - dmac_id = SERCOM6_DMAC_ID_TX; - data_reg = &SERCOM6->SPI.DATA.reg; -#endif -#if defined SERCOM7 - } else if(*(SERCOM **)hwspi._spi == &sercom7) { - dmac_id = SERCOM7_DMAC_ID_TX; - data_reg = &SERCOM7->SPI.DATA.reg; -#endif - } - dma.setPriority(DMA_PRIORITY_3); - dma.setTrigger(dmac_id); - dma.setAction(DMA_TRIGGER_ACTON_BEAT); - - // Initialize descriptor list. - for(int d=0; dChannel[dmaChannel].CHEVCTRL.bit.EVOE = 1; - DMAC->Channel[dmaChannel].CHEVCTRL.bit.EVOMODE = 0; - - // CONFIGURE TIMER/COUNTER (for write strobe) - - Tc *timer = tcList[tcNum].tc; // -> Timer struct - int id = tcList[tcNum].gclk; // Timer GCLK ID - GCLK_PCHCTRL_Type pchctrl; - - // Set up timer clock source from GCLK - GCLK->PCHCTRL[id].bit.CHEN = 0; // Stop timer - while(GCLK->PCHCTRL[id].bit.CHEN); // Wait for it - pchctrl.bit.GEN = GCLK_PCHCTRL_GEN_GCLK0_Val; - pchctrl.bit.CHEN = 1; // Enable - GCLK->PCHCTRL[id].reg = pchctrl.reg; - while(!GCLK->PCHCTRL[id].bit.CHEN); // Wait for it - - // Disable timer/counter before configuring it - timer->COUNT8.CTRLA.bit.ENABLE = 0; - while(timer->COUNT8.SYNCBUSY.bit.STATUS); - - timer->COUNT8.WAVE.bit.WAVEGEN = 2; // NPWM - timer->COUNT8.CTRLA.bit.MODE = 1; // 8-bit - timer->COUNT8.CTRLA.bit.PRESCALER = 0; // 1:1 - while(timer->COUNT8.SYNCBUSY.bit.STATUS); - - timer->COUNT8.CTRLBCLR.bit.DIR = 1; // Count UP - while(timer->COUNT8.SYNCBUSY.bit.CTRLB); - timer->COUNT8.CTRLBSET.bit.ONESHOT = 1; // One-shot - while(timer->COUNT8.SYNCBUSY.bit.CTRLB); - timer->COUNT8.PER.reg = 6; // PWM top - while(timer->COUNT8.SYNCBUSY.bit.PER); - timer->COUNT8.CC[0].reg = 2; // Compare - while(timer->COUNT8.SYNCBUSY.bit.CC0); - // Enable async input events, - // event action = restart. - timer->COUNT8.EVCTRL.bit.TCEI = 1; - timer->COUNT8.EVCTRL.bit.EVACT = 1; - - // Enable timer - timer->COUNT8.CTRLA.reg |= TC_CTRLA_ENABLE; - while(timer->COUNT8.SYNCBUSY.bit.STATUS); - -#if(wrPeripheral == PIO_CCL) - // CONFIGURE CCL (inverts timer/counter output) - - MCLK->APBCMASK.bit.CCL_ = 1; // Enable CCL clock - CCL->CTRL.bit.ENABLE = 0; // Disable to config - CCL->CTRL.bit.SWRST = 1; // Reset CCL registers - CCL->LUTCTRL[tcNum].bit.ENABLE = 0; // Disable LUT - CCL->LUTCTRL[tcNum].bit.FILTSEL = 0; // No filter - CCL->LUTCTRL[tcNum].bit.INSEL0 = 6; // TC input - CCL->LUTCTRL[tcNum].bit.INSEL1 = 0; // MASK - CCL->LUTCTRL[tcNum].bit.INSEL2 = 0; // MASK - CCL->LUTCTRL[tcNum].bit.TRUTH = 1; // Invert in 0 - CCL->LUTCTRL[tcNum].bit.ENABLE = 1; // Enable LUT - CCL->CTRL.bit.ENABLE = 1; // Enable CCL -#endif - - // CONFIGURE EVENT SYSTEM - - // Set up event system clock source from GCLK... - // Disable EVSYS, wait for disable - GCLK->PCHCTRL[EVSYS_GCLK_ID_0].bit.CHEN = 0; - while(GCLK->PCHCTRL[EVSYS_GCLK_ID_0].bit.CHEN); - pchctrl.bit.GEN = GCLK_PCHCTRL_GEN_GCLK0_Val; - pchctrl.bit.CHEN = 1; // Re-enable - GCLK->PCHCTRL[EVSYS_GCLK_ID_0].reg = pchctrl.reg; - // Wait for it, then enable EVSYS clock - while(!GCLK->PCHCTRL[EVSYS_GCLK_ID_0].bit.CHEN); - MCLK->APBBMASK.bit.EVSYS_ = 1; - - // Connect Timer EVU to ch 0 - EVSYS->USER[tcList[tcNum].evu].reg = 1; - // Datasheet recommends single write operation; - // reg instead of bit. Also datasheet: PATH bits - // must be zero when using async! - EVSYS_CHANNEL_Type ev; - ev.reg = 0; - ev.bit.PATH = 2; // Asynchronous - ev.bit.EVGEN = 0x22 + dmaChannel; // DMA channel 0+ - EVSYS->Channel[0].CHANNEL.reg = ev.reg; - - // Initialize descriptor list. - for(int d=0; d= 0) SPI_CS_LOW(); -} - -/*! - @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_Renderer::endWrite(void) { - if(_cs >= 0) SPI_CS_HIGH(); - SPI_END_TRANSACTION(); -} - - -// ------------------------------------------------------------------------- -// 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_Renderer::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. - @param block If true (default case if unspecified), function blocks - until DMA transfer is complete. This is simply IGNORED - if DMA is not enabled. If false, the function returns - immediately after the last DMA transfer is started, - and one should use the dmaWait() function before - doing ANY other display-related activities (or even - any SPI-related activities, if using an SPI display - that shares the bus with other devices). - @param bigEndian If using DMA, and if set true, bitmap in memory is in - big-endian order (most significant byte first). By - default this is false, as most microcontrollers seem - to be little-endian and 16-bit pixel values must be - byte-swapped before issuing to the display (which tend - to be big-endian when using SPI or 8-bit parallel). - If an application can optimize around this -- for - example, a bitmap in a uint16_t array having the byte - values already reordered big-endian, this can save - some processing time here, ESPECIALLY if using this - function's non-blocking DMA mode. Not all cases are - covered...this is really here only for SAMD DMA and - much forethought on the application side. -*/ -void Adafruit_SPITFT_Renderer::writePixels(uint16_t *colors, uint32_t len, - bool block, bool bigEndian) { - - 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; - } -#elif defined(USE_SPI_DMA) - if((connection == TFT_HARD_SPI) || (connection == TFT_PARALLEL)) { - int maxSpan = maxFillLen / 2; // One scanline max - uint8_t pixelBufIdx = 0; // Active pixel buffer number - #if defined(__SAMD51__) - if(connection == TFT_PARALLEL) { - // Switch WR pin to PWM or CCL - pinPeripheral(tft8._wr, wrPeripheral); - } - #endif // end __SAMD51__ - if(!bigEndian) { // Normal little-endian situation... - while(len) { - int count = (len < maxSpan) ? len : maxSpan; - - // Because TFT and SAMD endianisms are different, must swap - // bytes from the 'colors' array passed into a DMA working - // buffer. This can take place while the prior DMA transfer - // is in progress, hence the need for two pixelBufs. - for(int i=0; isetDataMode(hwspi._mode); - } else { - pinPeripheral(tft8._wr, PIO_OUTPUT); // Switch WR back to GPIO - } - #endif // end __SAMD51__ || _SAMD21_ - } - return; - } -#endif // end USE_SPI_DMA - - // All other cases (bitbang SPI or non-DMA hard SPI or parallel), - // use a loop with the normal 16-bit data write function: - while(len--) { - SPI_WRITE16(*colors++); - } -} - -/*! - @brief Wait for the last DMA transfer in a prior non-blocking - writePixels() call to complete. This does nothing if DMA - is not enabled, and is not needed if blocking writePixels() - was used (as is the default case). -*/ -void Adafruit_SPITFT_Renderer::dmaWait(void) { -#if defined(USE_SPI_DMA) - while(dma_busy); - #if defined(__SAMD51__) || defined(_SAMD21_) - if(connection == TFT_HARD_SPI) { - // See SAMD51/21 note in writeColor() - hwspi._spi->setDataMode(hwspi._mode); - } else { - pinPeripheral(tft8._wr, PIO_OUTPUT); // Switch WR back to GPIO - } - #endif // end __SAMD51__ || _SAMD21_ -#endif -} - -/*! - @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_Renderer::writeColor(uint16_t color, uint32_t len) { - - if(!len) return; // Avoid 0-byte transfers - - uint8_t hi = color >> 8, lo = color; - -#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; t= 16)) { // Don't bother with DMA on short pixel runs - int i, d, numDescriptors; - if(hi == lo) { // If high & low bytes are same... - onePixelBuf = color; - // Can do this with a relatively short descriptor list, - // each transferring a max of 32,767 (not 32,768) pixels. - // This won't run off the end of the allocated descriptor list, - // since we're using much larger chunks per descriptor here. - numDescriptors = (len + 32766) / 32767; - for(d=0; d lastFillLen) { - int fillStart = lastFillLen / 2, - fillEnd = (((len < maxFillLen) ? - len : maxFillLen) + 1) / 2; - for(i=fillStart; isetDataMode(hwspi._mode); - } else { - pinPeripheral(tft8._wr, PIO_OUTPUT); // Switch WR back to GPIO - } - #endif // end __SAMD51__ - return; - } - #endif // end USE_SPI_DMA -#endif // end !ESP32 - - // All other cases (non-DMA hard SPI, bitbang SPI, parallel)... - - if(connection == TFT_HARD_SPI) { -#if defined(ESP8266) - do { - uint32_t pixelsThisPass = len; - if(pixelsThisPass > 50000) pixelsThisPass = 50000; - len -= pixelsThisPass; - yield(); // Periodic yield() on long fills - while(pixelsThisPass--) { - hwspi._spi->write(hi); - hwspi._spi->write(lo); - } - } while(len); -#else // !ESP8266 - while(len--) { - #if defined(__AVR__) - AVR_WRITESPI(hi); - AVR_WRITESPI(lo); - #elif defined(ESP32) - hwspi._spi->write(hi); - hwspi._spi->write(lo); - #else - hwspi._spi->transfer(hi); - hwspi._spi->transfer(lo); - #endif - } -#endif // end !ESP8266 - } else if(connection == TFT_SOFT_SPI) { -#if defined(ESP8266) - do { - uint32_t pixelsThisPass = len; - if(pixelsThisPass > 20000) pixelsThisPass = 20000; - len -= pixelsThisPass; - yield(); // Periodic yield() on long fills - while(pixelsThisPass--) { - for(uint16_t bit=0, x=color; bit<16; bit++) { - if(x & 0x8000) SPI_MOSI_HIGH(); - else SPI_MOSI_LOW(); - SPI_SCK_HIGH(); - SPI_SCK_LOW(); - x <<= 1; - } - } - } while(len); -#else // !ESP8266 - while(len--) { - #if defined(__AVR__) - for(uint8_t bit=0, x=hi; bit<8; bit++) { - if(x & 0x80) SPI_MOSI_HIGH(); - else SPI_MOSI_LOW(); - SPI_SCK_HIGH(); - SPI_SCK_LOW(); - x <<= 1; - } - for(uint8_t bit=0, x=lo; bit<8; bit++) { - if(x & 0x80) SPI_MOSI_HIGH(); - else SPI_MOSI_LOW(); - SPI_SCK_HIGH(); - SPI_SCK_LOW(); - x <<= 1; - } - #else // !__AVR__ - for(uint16_t bit=0, x=color; bit<16; bit++) { - if(x & 0x8000) SPI_MOSI_HIGH(); - else SPI_MOSI_LOW(); - SPI_SCK_HIGH(); - x <<= 1; - SPI_SCK_LOW(); - } - #endif // end !__AVR__ - } -#endif // end !ESP8266 - } else { // PARALLEL - if(hi == lo) { -#if defined(__AVR__) - len *= 2; - *tft8.writePort = hi; - while(len--) { - TFT_WR_STROBE(); - } -#elif defined(USE_FAST_PINIO) - if(!tft8.wide) { - len *= 2; - *tft8.writePort = hi; - } else { - *(volatile uint16_t *)tft8.writePort = color; - } - while(len--) { - TFT_WR_STROBE(); - } -#endif - } else { - while(len--) { -#if defined(__AVR__) - *tft8.writePort = hi; - TFT_WR_STROBE(); - *tft8.writePort = lo; -#elif defined(USE_FAST_PINIO) - if(!tft8.wide) { - *tft8.writePort = hi; - TFT_WR_STROBE(); - *tft8.writePort = lo; - } else { - *(volatile uint16_t *)tft8.writePort = color; - } -#endif - TFT_WR_STROBE(); - } - } - } -} - -/*! - @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_Renderer::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 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 inline Adafruit_SPITFT_Renderer::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 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 h Line height in pixels (positive = below first point, - negative = above first point). - @param color 16-bit line color in '565' RGB format. -*/ -void inline Adafruit_SPITFT_Renderer::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); - } - } - } -} - -/*! - @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_Renderer::writeFillRectPreclipped(int16_t x, int16_t y, - int16_t w, int16_t h, uint16_t color) { - setAddrWindow(x, y, w, h); - writeColor(color, (uint32_t)w * h); -} - - -// ------------------------------------------------------------------------- -// 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 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_Renderer::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); - SPI_WRITE16(color); - endWrite(); - } -} - -/*! - @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_Renderer::fillRect(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 - 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_Renderer::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 h 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_Renderer::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_Renderer::pushColor(uint16_t color) { - startWrite(); - SPI_WRITE16(color); - endWrite(); -} - -/*! - @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_Renderer::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(); -} - - -// ------------------------------------------------------------------------- -// 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_Renderer::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). - @return 'Packed' 16-bit color value (565 format). -*/ -uint16_t Adafruit_SPITFT_Renderer::color565(uint8_t red, uint8_t green, uint8_t blue) { - return ((red & 0xF8) << 8) | ((green & 0xFC) << 3) | (blue >> 3); -} - -/*! - @brief Adafruit_SPITFT_Renderer Send Command handles complete sending of commands and data - @param commandByte The Command Byte - @param dataBytes A pointer to the Data bytes to send - @param numDataBytes The number of bytes we should send - */ -void Adafruit_SPITFT_Renderer::sendCommand(uint8_t commandByte, uint8_t *dataBytes, uint8_t numDataBytes) { - SPI_BEGIN_TRANSACTION(); - if(_cs >= 0) SPI_CS_LOW(); - - SPI_DC_LOW(); // Command mode - spiWrite(commandByte); // Send the command byte - - SPI_DC_HIGH(); - for (int i=0; i= 0) SPI_CS_HIGH(); - SPI_END_TRANSACTION(); -} - -/*! - @brief Adafruit_SPITFT_Renderer Send Command handles complete sending of commands and const data - @param commandByte The Command Byte - @param dataBytes A pointer to the Data bytes to send - @param numDataBytes The number of bytes we should send - */ -void Adafruit_SPITFT_Renderer::sendCommand(uint8_t commandByte, const uint8_t *dataBytes, uint8_t numDataBytes) { - SPI_BEGIN_TRANSACTION(); - if(_cs >= 0) SPI_CS_LOW(); - - SPI_DC_LOW(); // Command mode - spiWrite(commandByte); // Send the command byte - - SPI_DC_HIGH(); - for (int i=0; i= 0) SPI_CS_HIGH(); - SPI_END_TRANSACTION(); -} - -/*! - @brief Read 8 bits of data from display configuration memory (not RAM). - This is highly undocumented/supported and should be avoided, - function is only included because some of the examples use it. - @param commandByte - The command register to read data from. - @param index - The byte index into the command to read from. - @return Unsigned 8-bit data read from display register. - */ -/**************************************************************************/ -uint8_t Adafruit_SPITFT_Renderer::readcommand8(uint8_t commandByte, uint8_t index) { - uint8_t result; - startWrite(); - SPI_DC_LOW(); // Command mode - spiWrite(commandByte); - SPI_DC_HIGH(); // Data mode - do { - result = spiRead(); - } while(index--); // Discard bytes up to index'th - endWrite(); - return result; -} - -// ------------------------------------------------------------------------- -// 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_Renderer::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(hwspi._mode); -#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_Renderer::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_Renderer::spiWrite(uint8_t b) { - if(connection == TFT_HARD_SPI) { -#if defined(__AVR__) - AVR_WRITESPI(b); -#elif defined(ESP8266) || defined(ESP32) - hwspi._spi->write(b); -#else - hwspi._spi->transfer(b); -#endif - } else if(connection == TFT_SOFT_SPI) { - for(uint8_t bit=0; bit<8; bit++) { - if(b & 0x80) SPI_MOSI_HIGH(); - else SPI_MOSI_LOW(); - SPI_SCK_HIGH(); - b <<= 1; - SPI_SCK_LOW(); - } - } else { // 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(); - } -} - -/*! - @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 cmd 8-bit command to write. -*/ -void Adafruit_SPITFT_Renderer::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_Renderer::spiRead(void) { - uint8_t b = 0; - uint16_t w = 0; - if(connection == TFT_HARD_SPI) { - return hwspi._spi->transfer((uint8_t)0); - } else if(connection == TFT_SOFT_SPI) { - if(swspi._miso >= 0) { - for(uint8_t i=0; i<8; i++) { - SPI_SCK_HIGH(); - b <<= 1; - if(SPI_MISO_READ()) b++; - SPI_SCK_LOW(); - } - } - return b; - } else { // TFT_PARALLEL - if(tft8._rd >= 0) { -#if defined(USE_FAST_PINIO) - TFT_RD_LOW(); // Read line 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.portDir = 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 - } - TFT_RD_HIGH(); // Read line HIGH - #endif // end !__AVR__ -#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_Renderer::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); - #if defined(ESP32) - for(volatile uint8_t i=0; i<1; i++); - #endif // end ESP32 -#endif // end !USE_FAST_PINIO -} - -/*! - @brief Set the software (bitbang) SPI MOSI line LOW. -*/ -inline void Adafruit_SPITFT_Renderer::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); - #if defined(ESP32) - for(volatile uint8_t i=0; i<1; i++); - #endif // end ESP32 -#endif // end !USE_FAST_PINIO -} - -/*! - @brief Set the software (bitbang) SPI SCK line HIGH. -*/ -inline void Adafruit_SPITFT_Renderer::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; - #if defined(__IMXRT1052__) || defined(__IMXRT1062__) // Teensy 4.x - for(volatile uint8_t i=0; i<1; i++); - #endif - #endif - #else // !HAS_PORT_SET_CLR - *swspi.sckPort |= swspi.sckPinMaskSet; - #endif // end !HAS_PORT_SET_CLR -#else // !USE_FAST_PINIO - digitalWrite(swspi._sck, HIGH); - #if defined(ESP32) - for(volatile uint8_t i=0; i<1; i++); - #endif // end ESP32 -#endif // end !USE_FAST_PINIO -} - -/*! - @brief Set the software (bitbang) SPI SCK line LOW. -*/ -inline void Adafruit_SPITFT_Renderer::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; - #if defined(__IMXRT1052__) || defined(__IMXRT1062__) // Teensy 4.x - for(volatile uint8_t i=0; i<1; i++); - #endif - #endif - #else // !HAS_PORT_SET_CLR - *swspi.sckPort &= swspi.sckPinMaskClr; - #endif // end !HAS_PORT_SET_CLR -#else // !USE_FAST_PINIO - digitalWrite(swspi._sck, LOW); - #if defined(ESP32) - for(volatile uint8_t i=0; i<1; i++); - #endif // end ESP32 -#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_Renderer::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_Renderer::SPI_WRITE16(uint16_t w) { - if(connection == TFT_HARD_SPI) { -#if defined(__AVR__) - AVR_WRITESPI(w >> 8); - AVR_WRITESPI(w); -#elif defined(ESP8266) || defined(ESP32) - hwspi._spi->write16(w); -#else - hwspi._spi->transfer(w >> 8); - hwspi._spi->transfer(w); -#endif - } else if(connection == 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; - } - } else { // 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(); - } -} - -/*! - @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 l 32-bit value to write. -*/ -void Adafruit_SPITFT_Renderer::SPI_WRITE32(uint32_t l) { - if(connection == TFT_HARD_SPI) { -#if defined(__AVR__) - AVR_WRITESPI(l >> 24); - AVR_WRITESPI(l >> 16); - AVR_WRITESPI(l >> 8); - AVR_WRITESPI(l ); -#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 - } else if(connection == 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; - } - } else { // 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(); - } -} - -/*! - @brief Set the WR line LOW, then HIGH. Used for parallel-connected - interfaces when writing data. -*/ -inline void Adafruit_SPITFT_Renderer::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_Renderer::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_Renderer::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/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SPITFT_Renderer.h b/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SPITFT_Renderer.h deleted file mode 100644 index ce8f26d73b7a..000000000000 --- a/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SPITFT_Renderer.h +++ /dev/null @@ -1,525 +0,0 @@ -/* - * This class is basically the same as Adafruit_SPITFT. - * The only difference is: it extends Renderer which extends Adafruit_GFX. - * The original Adafruit_SPITFT class directly extends Adafruit_GFX. - */ -/*! - * @file Adafruit_SPITFT_Renderer.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! - * - * Written by Limor "ladyada" Fried for Adafruit Industries, - * with contributions from the open source community. - * - * BSD license, all text here must be included in any redistribution. - */ - -#ifndef _ADAFRUIT_SPITFT_RENDERER_H_ -#define _ADAFRUIT_SPITFT_RENDERER_H_ - -#if !defined(__AVR_ATtiny85__) // Not for ATtiny, at all - -#include -#include "Adafruit_GFX.h" -#include "renderer.h" - -// HARDWARE CONFIG --------------------------------------------------------- - -#if defined(__AVR__) - typedef uint8_t ADAGFX_PORT_t; ///< PORT values are 8-bit - #define USE_FAST_PINIO ///< Use direct PORT register access -#elif defined(ARDUINO_STM32_FEATHER) // WICED - typedef class HardwareSPI SPIClass; ///< SPI is a bit odd on WICED - typedef uint32_t ADAGFX_PORT_t; ///< PORT values are 32-bit -#elif defined(__arm__) - #if defined(ARDUINO_ARCH_SAMD) - // Adafruit M0, M4 - typedef uint32_t ADAGFX_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 - #elif defined(CORE_TEENSY) - // PJRC Teensy 4.x - #if defined(__IMXRT1052__) || defined(__IMXRT1062__) // Teensy 4.x - typedef uint32_t ADAGFX_PORT_t; ///< PORT values are 32-bit - // PJRC Teensy 3.x - #else - typedef uint8_t ADAGFX_PORT_t; ///< PORT values are 8-bit - #endif - #define USE_FAST_PINIO ///< Use direct PORT register access - #define HAS_PORT_SET_CLR ///< PORTs have set & clear registers - #else - // Arduino Due? - typedef uint32_t ADAGFX_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). - #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 ADAGFX_PORT_t; ///< PORT values are 32-bit -#endif // end !ARM -typedef volatile ADAGFX_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 - -#if defined(ADAFRUIT_PYPORTAL) || defined(ADAFRUIT_PYBADGE_M4_EXPRESS) || defined(ADAFRUIT_PYGAMER_M4_EXPRESS) - #define USE_SPI_DMA ///< Auto DMA if using PyPortal -#else - //#define USE_SPI_DMA ///< If set, use DMA if available -#endif -// Another "oops" name -- this now also handles parallel DMA. -// 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 ///< DMA currently for SAMD chips only -#endif - -#if defined(USE_SPI_DMA) - #pragma message ("GFX DMA IS ENABLED. HIGHLY EXPERIMENTAL.") - #include -#endif - -// This is kind of a kludge. Needed a way to disambiguate the software SPI -// and parallel constructors via their argument lists. Originally tried a -// bool as the first argument to the parallel constructor (specifying 8-bit -// vs 16-bit interface) but the compiler regards this as equivalent to an -// integer and thus still ambiguous. SO...the parallel constructor requires -// an enumerated type as the first argument: tft8 (for 8-bit parallel) or -// tft16 (for 16-bit)...even though 16-bit isn't fully implemented or tested -// and might never be, still needed that disambiguation from soft SPI. -enum tftBusWidth_Renderer { tft8bitbus_Renderer, tft16bitbus_Renderer }; ///< For first arg to parallel constructor - -// CLASS DEFINITION -------------------------------------------------------- - -/*! - @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_Renderer : public Renderer { - - public: - - // CONSTRUCTORS -------------------------------------------------------- - - // 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_Renderer(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); - - // 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_Renderer(uint16_t w, uint16_t h, - int8_t cs, int8_t dc, int8_t rst = -1); - -#if !defined(ESP8266) // See notes in .cpp - // 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_Renderer(uint16_t w, uint16_t h, SPIClass *spiClass, - int8_t cs, int8_t dc, int8_t rst = -1); -#endif // end !ESP8266 - - // 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_Renderer(uint16_t w, uint16_t h, tftBusWidth_Renderer busWidth, - int8_t d0, int8_t wr, int8_t dc, - int8_t cs = -1, int8_t rst = -1, int8_t rd = -1); - - // CLASS MEMBER FUNCTIONS ---------------------------------------------- - - // These first two functions MUST be declared by subclasses: - - /*! - @brief Display-specific initialization function. - @param freq SPI frequency, in hz (or 0 for default or unused). - */ - virtual void begin(uint32_t freq) = 0; - - /*! - @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; - - // 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. - - // Subclass' begin() function invokes this to initialize hardware. - // freq=0 to use default SPI speed. spiMode must be one of the SPI_MODEn - // values defined in SPI.h, which are NOT the same as 0 for SPI_MODE0, - // 1 for SPI_MODE1, etc...use ONLY the SPI_MODEn defines! Only! - // Name is outdated (interface may be parallel) but for compatibility: - void initSPI(uint32_t freq = 0, uint8_t spiMode = SPI_MODE0); - // 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); - void sendCommand(uint8_t commandByte, uint8_t *dataBytes = NULL, uint8_t numDataBytes = 0); - void sendCommand(uint8_t commandByte, const uint8_t *dataBytes, uint8_t numDataBytes); - uint8_t readcommand8(uint8_t commandByte, uint8_t index = 0); - - // 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, - bool block=true, bool bigEndian=false); - 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); - // Another new function, companion to the new non-blocking - // writePixels() variant. - void dmaWait(void); - - - // 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 - // 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) - #if defined(KINETISK) - *csPortSet = 1; - #else // !KINETISK - *csPortSet = csPinMask; - #endif // end !KINETISK - #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) - #if defined(KINETISK) - *csPortClr = 1; - #else // !KINETISK - *csPortClr = csPinMask; - #endif // end !KINETISK - #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 -#if defined(__cplusplus) && (__cplusplus >= 201100) - union { -#endif - struct { // Values specific to HARDWARE SPI: - SPIClass *_spi; ///< SPI class pointer -#if defined(SPI_HAS_TRANSACTION) - SPISettings settings; ///< SPI transaction settings -#else - uint32_t _freq; ///< SPI bitrate (if no SPI transactions) -#endif - uint32_t _mode; ///< SPI data mode (transactions or no) - } hwspi; ///< Hardware SPI values - 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) - ADAGFX_PORT_t mosiPinMask; ///< Bitmask for MOSI - ADAGFX_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 - ADAGFX_PORT_t mosiPinMaskSet; ///< Bitmask for MOSI SET (OR) - ADAGFX_PORT_t mosiPinMaskClr; ///< Bitmask for MOSI CLEAR (AND) - ADAGFX_PORT_t sckPinMaskSet; ///< Bitmask for SCK SET (OR bitmask) - ADAGFX_PORT_t sckPinMaskClr; ///< Bitmask for SCK CLEAR (AND) -#endif // end HAS_PORT_SET_CLR - #if !defined(KINETISK) - ADAGFX_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; ///< Software SPI values - struct { // Values specific to 8-bit parallel: -#if defined(USE_FAST_PINIO) - - #if defined(__IMXRT1052__) || defined(__IMXRT1062__) // Teensy 4.x - volatile uint32_t *writePort; ///< PORT register for DATA WRITE - volatile uint32_t *readPort; ///< PORT (PIN) register for DATA READ - #else - volatile uint8_t *writePort; ///< PORT register for DATA WRITE - volatile uint8_t *readPort; ///< PORT (PIN) register for DATA READ - #endif -#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. - #if defined(__IMXRT1052__) || defined(__IMXRT1062__) // Teensy 4.x - volatile uint32_t *dirSet; ///< PORT byte data direction SET - volatile uint32_t *dirClr; ///< PORT byte data direction CLEAR - #else - volatile uint8_t *dirSet; ///< PORT byte data direction SET - volatile uint8_t *dirClr; ///< PORT byte data direction CLEAR - #endif - 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) - ADAGFX_PORT_t wrPinMask; ///< Bitmask for write strobe - #endif // end !KINETISK - ADAGFX_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 - ADAGFX_PORT_t wrPinMaskSet; ///< Bitmask for write strobe SET (OR) - ADAGFX_PORT_t wrPinMaskClr; ///< Bitmask for write strobe CLEAR (AND) - ADAGFX_PORT_t rdPinMaskSet; ///< Bitmask for read strobe SET (OR) - ADAGFX_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; ///< Parallel interface settings -#if defined(__cplusplus) && (__cplusplus >= 201100) - }; ///< Only one interface is active -#endif -#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) - #if !defined(KINETISK) - ADAGFX_PORT_t csPinMask; ///< Bitmask for chip select - ADAGFX_PORT_t dcPinMask; ///< Bitmask for data/command - #endif // end !KINETISK -#else // !HAS_PORT_SET_CLR - ADAGFX_PORT_t csPinMaskSet; ///< Bitmask for chip select SET (OR) - ADAGFX_PORT_t csPinMaskClr; ///< Bitmask for chip select CLEAR (AND) - ADAGFX_PORT_t dcPinMaskSet; ///< Bitmask for data/command SET (OR) - ADAGFX_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 # - - 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 - - uint32_t _freq = 0; ///< Dummy var to keep subclasses happy -}; - -#endif // end __AVR_ATtiny85__ -#endif // end _ADAFRUIT_SPITFT_H_ diff --git a/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SSD1331.cpp b/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SSD1331.cpp deleted file mode 100644 index 799d87a791a7..000000000000 --- a/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SSD1331.cpp +++ /dev/null @@ -1,190 +0,0 @@ -/*! - * @file Adafruit_SSD1331.cpp - * - * @mainpage Adafruit SSD1331 Arduino Library - * - * @section intro_sec Introduction - * - * This is a library for the 0.96" 16-bit Color OLED with SSD1331 driver chip - * - * Pick one up today in the adafruit shop! - * ------> http://www.adafruit.com/products/684 - * - * These displays use SPI to communicate, 4 or 5 pins are required to - * interface - * 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 Fried/Ladyada for Adafruit Industries. - * - * @section license License - * - * BSD license, all text above must be included in any redistribution - */ - -#include "Adafruit_SSD1331.h" -#include "pins_arduino.h" -#include "wiring_private.h" - -/***********************************/ - -/*! - @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 -*/ -void Adafruit_SSD1331::setAddrWindow(uint16_t x, uint16_t y, uint16_t w, - uint16_t h) { - - uint8_t x1 = x; - uint8_t y1 = y; - if (x1 > 95) - x1 = 95; - if (y1 > 63) - y1 = 63; - - uint8_t x2 = (x + w - 1); - uint8_t y2 = (y + h - 1); - if (x2 > 95) - x2 = 95; - if (y2 > 63) - y2 = 63; - - if (x1 > x2) { - uint8_t t = x2; - x2 = x1; - x1 = t; - } - if (y1 > y2) { - uint8_t t = y2; - y2 = y1; - y1 = t; - } - - sendCommand(0x15); // Column addr set - sendCommand(x1); - sendCommand(x2); - - sendCommand(0x75); // Column addr set - sendCommand(y1); - sendCommand(y2); - - startWrite(); -} - -/**************************************************************************/ -/*! - @brief Initialize SSD1331 chip - Connects to the SSD1331 over SPI and sends initialization procedure commands - @param freq Desired SPI clock frequency -*/ -/**************************************************************************/ -void Adafruit_SSD1331::begin(uint32_t freq) { - initSPI(freq); - - // Initialization Sequence - sendCommand(SSD1331_CMD_DISPLAYOFF); // 0xAE - sendCommand(SSD1331_CMD_SETREMAP); // 0xA0 -#if defined SSD1331_COLORORDER_RGB - sendCommand(0x72); // RGB Color -#else - sendCommand(0x76); // BGR Color -#endif - sendCommand(SSD1331_CMD_STARTLINE); // 0xA1 - sendCommand(0x0); - sendCommand(SSD1331_CMD_DISPLAYOFFSET); // 0xA2 - sendCommand(0x0); - sendCommand(SSD1331_CMD_NORMALDISPLAY); // 0xA4 - sendCommand(SSD1331_CMD_SETMULTIPLEX); // 0xA8 - sendCommand(0x3F); // 0x3F 1/64 duty - sendCommand(SSD1331_CMD_SETMASTER); // 0xAD - sendCommand(0x8E); - sendCommand(SSD1331_CMD_POWERMODE); // 0xB0 - sendCommand(0x0B); - sendCommand(SSD1331_CMD_PRECHARGE); // 0xB1 - sendCommand(0x31); - sendCommand(SSD1331_CMD_CLOCKDIV); // 0xB3 - sendCommand(0xF0); // 7:4 = Oscillator Frequency, 3:0 = CLK Div Ratio - // (A[3:0]+1 = 1..16) - sendCommand(SSD1331_CMD_PRECHARGEA); // 0x8A - sendCommand(0x64); - sendCommand(SSD1331_CMD_PRECHARGEB); // 0x8B - sendCommand(0x78); - sendCommand(SSD1331_CMD_PRECHARGEC); // 0x8C - sendCommand(0x64); - sendCommand(SSD1331_CMD_PRECHARGELEVEL); // 0xBB - sendCommand(0x3A); - sendCommand(SSD1331_CMD_VCOMH); // 0xBE - sendCommand(0x3E); - sendCommand(SSD1331_CMD_MASTERCURRENT); // 0x87 - sendCommand(0x06); - sendCommand(SSD1331_CMD_CONTRASTA); // 0x81 - sendCommand(0x91); - sendCommand(SSD1331_CMD_CONTRASTB); // 0x82 - sendCommand(0x50); - sendCommand(SSD1331_CMD_CONTRASTC); // 0x83 - sendCommand(0x7D); - sendCommand(SSD1331_CMD_DISPLAYON); //--turn on oled panel - _width = TFTWIDTH; - _height = TFTHEIGHT; -} - -/**************************************************************************/ -/*! - @brief Instantiate Adafruit SSD1331 driver with software SPI - @param cs Chip select pin # - @param dc Data/Command pin # - @param mosi SPI MOSI pin # - @param sclk SPI Clock pin # - @param rst Reset pin # (optional, pass -1 if unused) -*/ -/**************************************************************************/ -Adafruit_SSD1331::Adafruit_SSD1331(int8_t cs, int8_t dc, int8_t mosi, - int8_t sclk, int8_t rst) - : Adafruit_SPITFT_Renderer(TFTWIDTH, TFTHEIGHT, cs, dc, mosi, sclk, rst, -1) {} - -/**************************************************************************/ -/*! - @brief Instantiate Adafruit SSD1331 driver with hardware SPI - @param cs Chip select pin # - @param dc Data/Command pin # - @param rst Reset pin # (optional, pass -1 if unused) -*/ -/**************************************************************************/ -Adafruit_SSD1331::Adafruit_SSD1331(int8_t cs, int8_t dc, int8_t rst) - : Adafruit_SPITFT_Renderer(TFTWIDTH, TFTHEIGHT, cs, dc, rst) {} - -/**************************************************************************/ -/*! - @brief Instantiate Adafruit SSD1331 driver with hardware SPI - @param spi Pointer to an existing SPIClass instance (e.g. &SPI, the - microcontroller's primary SPI bus). - @param cs Chip select pin # - @param dc Data/Command pin # - @param rst Reset pin # (optional, pass -1 if unused) -*/ -/**************************************************************************/ -Adafruit_SSD1331::Adafruit_SSD1331(SPIClass *spi, int8_t cs, int8_t dc, - int8_t rst) - : -#if defined(ESP8266) - Adafruit_SPITFT_Renderer(TFTWIDTH, TFTWIDTH, cs, dc, rst) { -#else - Adafruit_SPITFT_Renderer(TFTWIDTH, TFTWIDTH, spi, cs, dc, rst) { -#endif -} - -/**************************************************************************/ -/*! - @brief Change whether display is on or off - @param enable True if you want the display ON, false OFF -*/ -/**************************************************************************/ -void Adafruit_SSD1331::enableDisplay(boolean enable) { - sendCommand(enable ? SSD1331_CMD_DISPLAYON : SSD1331_CMD_DISPLAYOFF); -} diff --git a/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SSD1331.h b/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SSD1331.h deleted file mode 100644 index e427615c322e..000000000000 --- a/lib/lib_display/Adafruit_SSD1331-1.2.0/Adafruit_SSD1331.h +++ /dev/null @@ -1,76 +0,0 @@ -/*! - * @file Adafruit_SSD1331.h - */ - -#include "Arduino.h" -#include -// Tasmota change: use custom version of Adafruit_SPITFT which extends Renderer instead of Adafruit_GFX -#include -#include -#include - -/*! - * @brief Select one of these defines to set the pixel color order - */ -#define SSD1331_COLORORDER_RGB -// #define SSD1331_COLORORDER_BGR - -#if defined SSD1331_COLORORDER_RGB && defined SSD1331_COLORORDER_BGR -#error "RGB and BGR can not both be defined for SSD1331_COLORODER." -#endif - -// Timing Delays -#define SSD1331_DELAYS_HWFILL (3) //!< Fill delay -#define SSD1331_DELAYS_HWLINE (1) //!< Line delay - -// SSD1331 Commands -#define SSD1331_CMD_DRAWLINE 0x21 //!< Draw line -#define SSD1331_CMD_DRAWRECT 0x22 //!< Draw rectangle -#define SSD1331_CMD_FILL 0x26 //!< Fill enable/disable -#define SSD1331_CMD_SETCOLUMN 0x15 //!< Set column address -#define SSD1331_CMD_SETROW 0x75 //!< Set row adress -#define SSD1331_CMD_CONTRASTA 0x81 //!< Set contrast for color A -#define SSD1331_CMD_CONTRASTB 0x82 //!< Set contrast for color B -#define SSD1331_CMD_CONTRASTC 0x83 //!< Set contrast for color C -#define SSD1331_CMD_MASTERCURRENT 0x87 //!< Master current control -#define SSD1331_CMD_SETREMAP 0xA0 //!< Set re-map & data format -#define SSD1331_CMD_STARTLINE 0xA1 //!< Set display start line -#define SSD1331_CMD_DISPLAYOFFSET 0xA2 //!< Set display offset -#define SSD1331_CMD_NORMALDISPLAY 0xA4 //!< Set display to normal mode -#define SSD1331_CMD_DISPLAYALLON 0xA5 //!< Set entire display ON -#define SSD1331_CMD_DISPLAYALLOFF 0xA6 //!< Set entire display OFF -#define SSD1331_CMD_INVERTDISPLAY 0xA7 //!< Invert display -#define SSD1331_CMD_SETMULTIPLEX 0xA8 //!< Set multiplex ratio -#define SSD1331_CMD_SETMASTER 0xAD //!< Set master configuration -#define SSD1331_CMD_DISPLAYOFF 0xAE //!< Display OFF (sleep mode) -#define SSD1331_CMD_DISPLAYON 0xAF //!< Normal Brightness Display ON -#define SSD1331_CMD_POWERMODE 0xB0 //!< Power save mode -#define SSD1331_CMD_PRECHARGE 0xB1 //!< Phase 1 and 2 period adjustment -#define SSD1331_CMD_CLOCKDIV \ - 0xB3 //!< Set display clock divide ratio/oscillator frequency -#define SSD1331_CMD_PRECHARGEA 0x8A //!< Set second pre-charge speed for color A -#define SSD1331_CMD_PRECHARGEB 0x8B //!< Set second pre-charge speed for color B -#define SSD1331_CMD_PRECHARGEC 0x8C //!< Set second pre-charge speed for color C -#define SSD1331_CMD_PRECHARGELEVEL 0xBB //!< Set pre-charge voltage -#define SSD1331_CMD_VCOMH 0xBE //!< Set Vcomh voltge - -/// Class to manage hardware interface with SSD1331 chipset -class Adafruit_SSD1331 : public Adafruit_SPITFT_Renderer { -public: - Adafruit_SSD1331(int8_t cs, int8_t dc, int8_t mosi, int8_t sclk, int8_t rst); - Adafruit_SSD1331(int8_t cs, int8_t dc, int8_t rst); - // 3-4 args using hardware SPI (must specify peripheral) (reset optional) - Adafruit_SSD1331(SPIClass *spi, int8_t cs, int8_t dc, int8_t rst = -1); - - // commands - void begin(uint32_t begin = 8000000); - - void setAddrWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h); - - void enableDisplay(boolean enable); - - static const int16_t TFTWIDTH = 96; ///< The width of the display - static const int16_t TFTHEIGHT = 64; ///< The height of the display - -private: -}; diff --git a/lib/lib_display/Adafruit_SSD1331-1.2.0/README.md b/lib/lib_display/Adafruit_SSD1331-1.2.0/README.md deleted file mode 100644 index 24c404c59bb6..000000000000 --- a/lib/lib_display/Adafruit_SSD1331-1.2.0/README.md +++ /dev/null @@ -1,24 +0,0 @@ -# Adafruit SSD1331 Arduino Library [![Build Status](https://github.com/adafruit/Adafruit-SSD1331-OLED-Driver-Library-for-Arduino/workflows/Arduino%20Library%20CI/badge.svg)](https://github.com/adafruit/Adafruit-SSD1331-OLED-Driver-Library-for-Arduino/actions)[![Documentation](https://github.com/adafruit/ci-arduino/blob/master/assets/doxygen_badge.svg)](http://adafruit.github.io/Adafruit-SSD1331-OLED-Driver-Library-for-Arduino/html/index.html) -This is a library for the 0.96" 16-bit Color OLED with SSD1331 driver chip - - Pick one up today in the adafruit shop! - ------> http://www.adafruit.com/products/684 - -These displays use SPI to communicate, 4 or 5 pins are required to -interface - -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. -BSD license, check license.txt for more information -All text above must be included in any redistribution - -To download. click the DOWNLOADS button in the top right corner, rename the uncompressed folder Adafruit_SSD1131. Check that the Adafruit_SSD1331 folder contains Adafruit_SSD1331.cpp and Adafruit_SSD1331.h - -Place the Adafruit_SSD1331 library folder your /libraries/ folder. You may need to create the libraries subfolder if its your first library. Restart the IDE. - -You will also have to download the Adafruit GFX Graphics core which does all the circles, text, rectangles, etc. You can get it from -https://github.com/adafruit/Adafruit-GFX-Library -and download/install that library as well diff --git a/lib/lib_display/Adafruit_SSD1331-1.2.0/library.properties b/lib/lib_display/Adafruit_SSD1331-1.2.0/library.properties deleted file mode 100644 index 931f1aa38e2a..000000000000 --- a/lib/lib_display/Adafruit_SSD1331-1.2.0/library.properties +++ /dev/null @@ -1,10 +0,0 @@ -name=Adafruit SSD1331 OLED Driver Library for Arduino -version=1.2.0 -author=Adafruit -maintainer=Adafruit -sentence=For 0.96" OLEDs in the Adafruit shop -paragraph=For 0.96" OLEDs in the Adafruit shop -category=Display -url=https://github.com/adafruit/Adafruit-SSD1331-OLED-Driver-Library-for-Arduino -architectures=* -depends=Adafruit GFX Library diff --git a/lib/lib_display/Adafruit_SSD1331-1.2.0/license.txt b/lib/lib_display/Adafruit_SSD1331-1.2.0/license.txt deleted file mode 100644 index f6a0f22b826f..000000000000 --- a/lib/lib_display/Adafruit_SSD1331-1.2.0/license.txt +++ /dev/null @@ -1,26 +0,0 @@ -Software License Agreement (BSD License) - -Copyright (c) 2012, Adafruit Industries -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: -1. Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. -3. Neither the name of the copyright holders nor the -names of its contributors may be used to endorse or promote products -derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/tasmota/include/tasmota_configurations.h b/tasmota/include/tasmota_configurations.h index dcfc895bc729..8a024e60cc7d 100644 --- a/tasmota/include/tasmota_configurations.h +++ b/tasmota/include/tasmota_configurations.h @@ -368,7 +368,6 @@ // #define USE_DISPLAY_SSD1351 // [DisplayModel 9] // #define USE_DISPLAY_RA8876 // [DisplayModel 10] // #define USE_DISPLAY_ST7789 // [DisplayModel 12] Enable ST7789 module - // #define USE_DISPLAY_SSD1331 // [DisplayModel 14] Enable SSD1331 module #define USE_UNIVERSAL_DISPLAY #define USE_UNIVERSAL_TOUCH diff --git a/tasmota/include/tasmota_template.h b/tasmota/include/tasmota_template.h index cc0f34bba8b4..664001647616 100644 --- a/tasmota/include/tasmota_template.h +++ b/tasmota/include/tasmota_template.h @@ -688,10 +688,11 @@ const uint16_t kGpioNiceList[] PROGMEM = { AGPIO(GPIO_ST7789_CS), AGPIO(GPIO_ST7789_DC), #endif // USE_DISPLAY_ST7789 -#ifdef USE_DISPLAY_SSD1331 - AGPIO(GPIO_SSD1331_CS), - AGPIO(GPIO_SSD1331_DC), -#endif // USE_DISPLAY_SSD1331 +// REMOVED +// #ifdef USE_DISPLAY_SSD1331 +// AGPIO(GPIO_SSD1331_CS), +// AGPIO(GPIO_SSD1331_DC), +// #endif // USE_DISPLAY_SSD1331 #ifdef USE_DISPLAY_MAX7219_MATRIX #undef USE_DISPLAY_MAX7219 #undef USE_DISPLAY_TM1637 diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index 1903cc9482c2..a122032ae44d 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -810,7 +810,7 @@ An online tool to calculate TLS fingerprints is available here at:\n\ // #define USE_DISPLAY_SSD1351 // [DisplayModel 9] Enable SSD1351 module // #define USE_DISPLAY_RA8876 // [DisplayModel 10] [I2cDriver39] (Touch) // #define USE_DISPLAY_ST7789 // [DisplayModel 12] Enable ST7789 module -// #define USE_DISPLAY_SSD1331 // [DisplayModel 14] Enable SSD1331 module + // REMOVED -- #define USE_DISPLAY_SSD1331 // [DisplayModel 14] Enable SSD1331 module // #define USE_RC522 // Add support for MFRC522 13.56Mhz Rfid reader (+6k code) // #define USE_RC522_DATA_FUNCTION // Add support for reading data block content (+0k4 code) // #define USE_RC522_TYPE_INFORMATION // Add support for showing card type (+0k4 code) diff --git a/tasmota/tasmota_support/support_features.ino b/tasmota/tasmota_support/support_features.ino index bd064146415b..8f6d24b36412 100644 --- a/tasmota/tasmota_support/support_features.ino +++ b/tasmota/tasmota_support/support_features.ino @@ -668,9 +668,10 @@ constexpr uint32_t feature[] = { #if defined(USE_SPI) && defined(USE_DISPLAY) && defined(USE_DISPLAY_ST7789) 0x00080000 | // xdsp_12_ST7789.ino #endif -#if defined(USE_SPI) && defined(USE_DISPLAY) && defined(USE_DISPLAY_SSD1331) - 0x00100000 | // xdsp_14_SSD1331.ino -#endif +// REMOVED +// #if defined(USE_SPI) && defined(USE_DISPLAY) && defined(USE_DISPLAY_SSD1331) +// 0x00100000 | // xdsp_14_SSD1331.ino +// #endif #ifdef USE_UFILESYS 0x00200000 | // xdrv_50_filesystem.ino #endif diff --git a/tasmota/tasmota_xdsp_display/xdsp_14_SSD1331.ino b/tasmota/tasmota_xdsp_display/xdsp_14_SSD1331.ino index e455a66cea4d..26e828af04fd 100644 --- a/tasmota/tasmota_xdsp_display/xdsp_14_SSD1331.ino +++ b/tasmota/tasmota_xdsp_display/xdsp_14_SSD1331.ino @@ -17,178 +17,181 @@ along with this program. If not, see . */ -#ifdef USE_SPI -#ifdef USE_DISPLAY -#ifdef USE_DISPLAY_SSD1331 // This driver eats 5.3 K flash - -#define XDSP_14 14 - -#define COLORED 1 -#define UNCOLORED 0 -#define USE_TINY_FONT - -#define SSD1331_BLACK 0x0000 // 0, 0, 0 -#define SSD1331_WHITE 0xFFFF // 255, 255, 255 -#define SSD1331_RED 0xF800 // 255, 0, 0 -#define SSD1331_BLUE 0x001F // 0, 0, 255 - -#include -#include - -bool ssd1331_init_done = false; - -extern uint8_t color_type; -Adafruit_SSD1331 *ssd1331; - -/*********************************************************************************************/ - -void SSD1331_InitDriver() { - if (PinUsed(GPIO_SSD1331_CS) && PinUsed(GPIO_SSD1331_DC) && - ((TasmotaGlobal.soft_spi_enabled & SPI_MOSI) || (TasmotaGlobal.spi_enabled & SPI_MOSI))) { - - Settings->display_model = XDSP_14; - - if (Settings->display_width != Adafruit_SSD1331::TFTWIDTH) { - Settings->display_width = Adafruit_SSD1331::TFTWIDTH; - } - if (Settings->display_height != Adafruit_SSD1331::TFTHEIGHT) { - Settings->display_height = Adafruit_SSD1331::TFTHEIGHT; - } - - - // default colors - fg_color = SSD1331_WHITE; - bg_color = SSD1331_BLACK; - - // init renderer - if (TasmotaGlobal.soft_spi_enabled) { - ssd1331 = new Adafruit_SSD1331(Pin(GPIO_SSD1331_CS), Pin(GPIO_SSD1331_DC), Pin(GPIO_SSPI_MOSI), Pin(GPIO_SSPI_SCLK), Pin(GPIO_OLED_RESET)); - } - else if (TasmotaGlobal.spi_enabled) { - ssd1331 = new Adafruit_SSD1331(&SPI, Pin(GPIO_SSD1331_CS), Pin(GPIO_SSD1331_DC), Pin(GPIO_OLED_RESET)); - } - - delay(100); - ssd1331->begin(); - renderer = ssd1331; - // Rotation is currently broken, https://github.com/adafruit/Adafruit-SSD1331-OLED-Driver-Library-for-Arduino/issues/26 - renderer->DisplayInit(DISPLAY_INIT_MODE, Settings->display_size, Settings->display_rotate, Settings->display_font); - renderer->dim(GetDisplayDimmer16()); - -#ifdef SHOW_SPLASH - if (!Settings->flag5.display_no_splash) { - // Welcome text - renderer->clearDisplay(); - renderer->setTextFont(1); - renderer->DrawStringAt(24, 27, "SSD1331", SSD1331_RED, 0); - delay(1000); - renderer->clearDisplay(); - } -#endif - - color_type = COLOR_COLOR; - - ssd1331_init_done = true; - AddLog(LOG_LEVEL_INFO, PSTR("DSP: SSD1331")); - } -} - -#ifdef USE_DISPLAY_MODES1TO5 - -void SSD1331PrintLog(bool withDateTime) { - disp_refresh--; - if (!disp_refresh) { - disp_refresh = Settings->display_refresh; - if (!disp_screen_buffer_cols) { DisplayAllocScreenBuffer(); } - - char* txt = DisplayLogBuffer('\370'); - if (txt != NULL) { - uint8_t last_row = Settings->display_rows -1; - - renderer->clearDisplay(); - renderer->setCursor(0,0); - - if (withDateTime) { - char line[17]; - snprintf_P(line, sizeof(line), PSTR("%02d" D_HOUR_MINUTE_SEPARATOR "%02d %02d" D_MONTH_DAY_SEPARATOR "%02d" D_YEAR_MONTH_SEPARATOR "%04d"), RtcTime.hour, RtcTime.minute, RtcTime.day_of_month, RtcTime.month, RtcTime.year); // [12:34 01-02-2018] - renderer->setTextColor(SSD1331_BLUE); - renderer->println(line); - renderer->setTextColor(fg_color); - last_row--; - } - - for (byte i = 0; i < last_row; i++) { - strlcpy(disp_screen_buffer[i], disp_screen_buffer[i +1], disp_screen_buffer_cols); - renderer->println(disp_screen_buffer[i]); - } - strlcpy(disp_screen_buffer[last_row], txt, disp_screen_buffer_cols); - DisplayFillScreen(last_row); - - AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "[%s]"), disp_screen_buffer[last_row]); - - renderer->println(disp_screen_buffer[last_row]); - renderer->Updateframe(); - } - } -} - -void SSD1331Time(void) { - char line[12]; - - renderer->clearDisplay(); - snprintf_P(line, sizeof(line), PSTR(" %02d" D_HOUR_MINUTE_SEPARATOR "%02d" D_MINUTE_SECOND_SEPARATOR "%02d"), RtcTime.hour, RtcTime.minute, RtcTime.second); // [ 12:34:56 ] - renderer->setCursor(17, 20); - renderer->println(line); - snprintf_P(line, sizeof(line), PSTR("%02d" D_MONTH_DAY_SEPARATOR "%02d" D_YEAR_MONTH_SEPARATOR "%04d"), RtcTime.day_of_month, RtcTime.month, RtcTime.year); // [01-02-2018] - renderer->setCursor(17, 35); - renderer->println(line); - renderer->Updateframe(); -} - -void SSD1331Refresh(void) { // Every second - if (Settings->display_mode) { // Mode 0 is User text - switch (Settings->display_mode) { - case 1: // Time - SSD1331Time(); - break; - case 2: // Local - case 4: // Mqtt - SSD1331PrintLog(false); - break; - case 3: // Local + Time - case 5: // Mqtt + Time - SSD1331PrintLog(true); - break; - } - } -} - -#endif // USE_DISPLAY_MODES1TO5 - -/*********************************************************************************************\ - * Interface -\*********************************************************************************************/ - -bool Xdsp14(uint32_t function) { - bool result = false; - - if (FUNC_DISPLAY_INIT_DRIVER == function) { - SSD1331_InitDriver(); - } - else if (ssd1331_init_done && (XDSP_14 == Settings->display_model)) { - switch (function) { - case FUNC_DISPLAY_MODEL: - result = true; - break; -#ifdef USE_DISPLAY_MODES1TO5 - case FUNC_DISPLAY_EVERY_SECOND: - SSD1331Refresh(); - break; -#endif // USE_DISPLAY_MODES1TO5 - } - } - return result; -} -#endif // USE_DISPLAY_SSD1331 -#endif // USE_DISPLAY -#endif // USE_SPI +// REMOVED +// DEPRECATED - USE UNIVERSAL DISPLAY INSTEAD, https://tasmota.github.io/docs/Universal-Display-Driver/#migrating-to-udisplay + +// #ifdef USE_SPI +// #ifdef USE_DISPLAY +// #ifdef USE_DISPLAY_SSD1331 // This driver eats 5.3 K flash + +// #define XDSP_14 14 + +// #define COLORED 1 +// #define UNCOLORED 0 +// #define USE_TINY_FONT + +// #define SSD1331_BLACK 0x0000 // 0, 0, 0 +// #define SSD1331_WHITE 0xFFFF // 255, 255, 255 +// #define SSD1331_RED 0xF800 // 255, 0, 0 +// #define SSD1331_BLUE 0x001F // 0, 0, 255 + +// #include +// #include + +// bool ssd1331_init_done = false; + +// extern uint8_t color_type; +// Adafruit_SSD1331 *ssd1331; + +// /*********************************************************************************************/ + +// void SSD1331_InitDriver() { +// if (PinUsed(GPIO_SSD1331_CS) && PinUsed(GPIO_SSD1331_DC) && +// ((TasmotaGlobal.soft_spi_enabled & SPI_MOSI) || (TasmotaGlobal.spi_enabled & SPI_MOSI))) { + +// Settings->display_model = XDSP_14; + +// if (Settings->display_width != Adafruit_SSD1331::TFTWIDTH) { +// Settings->display_width = Adafruit_SSD1331::TFTWIDTH; +// } +// if (Settings->display_height != Adafruit_SSD1331::TFTHEIGHT) { +// Settings->display_height = Adafruit_SSD1331::TFTHEIGHT; +// } + + +// // default colors +// fg_color = SSD1331_WHITE; +// bg_color = SSD1331_BLACK; + +// // init renderer +// if (TasmotaGlobal.soft_spi_enabled) { +// ssd1331 = new Adafruit_SSD1331(Pin(GPIO_SSD1331_CS), Pin(GPIO_SSD1331_DC), Pin(GPIO_SSPI_MOSI), Pin(GPIO_SSPI_SCLK), Pin(GPIO_OLED_RESET)); +// } +// else if (TasmotaGlobal.spi_enabled) { +// ssd1331 = new Adafruit_SSD1331(&SPI, Pin(GPIO_SSD1331_CS), Pin(GPIO_SSD1331_DC), Pin(GPIO_OLED_RESET)); +// } + +// delay(100); +// ssd1331->begin(); +// renderer = ssd1331; +// // Rotation is currently broken, https://github.com/adafruit/Adafruit-SSD1331-OLED-Driver-Library-for-Arduino/issues/26 +// renderer->DisplayInit(DISPLAY_INIT_MODE, Settings->display_size, Settings->display_rotate, Settings->display_font); +// renderer->dim(GetDisplayDimmer16()); + +// #ifdef SHOW_SPLASH +// if (!Settings->flag5.display_no_splash) { +// // Welcome text +// renderer->clearDisplay(); +// renderer->setTextFont(1); +// renderer->DrawStringAt(24, 27, "SSD1331", SSD1331_RED, 0); +// delay(1000); +// renderer->clearDisplay(); +// } +// #endif + +// color_type = COLOR_COLOR; + +// ssd1331_init_done = true; +// AddLog(LOG_LEVEL_INFO, PSTR("DSP: SSD1331")); +// } +// } + +// #ifdef USE_DISPLAY_MODES1TO5 + +// void SSD1331PrintLog(bool withDateTime) { +// disp_refresh--; +// if (!disp_refresh) { +// disp_refresh = Settings->display_refresh; +// if (!disp_screen_buffer_cols) { DisplayAllocScreenBuffer(); } + +// char* txt = DisplayLogBuffer('\370'); +// if (txt != NULL) { +// uint8_t last_row = Settings->display_rows -1; + +// renderer->clearDisplay(); +// renderer->setCursor(0,0); + +// if (withDateTime) { +// char line[17]; +// snprintf_P(line, sizeof(line), PSTR("%02d" D_HOUR_MINUTE_SEPARATOR "%02d %02d" D_MONTH_DAY_SEPARATOR "%02d" D_YEAR_MONTH_SEPARATOR "%04d"), RtcTime.hour, RtcTime.minute, RtcTime.day_of_month, RtcTime.month, RtcTime.year); // [12:34 01-02-2018] +// renderer->setTextColor(SSD1331_BLUE); +// renderer->println(line); +// renderer->setTextColor(fg_color); +// last_row--; +// } + +// for (byte i = 0; i < last_row; i++) { +// strlcpy(disp_screen_buffer[i], disp_screen_buffer[i +1], disp_screen_buffer_cols); +// renderer->println(disp_screen_buffer[i]); +// } +// strlcpy(disp_screen_buffer[last_row], txt, disp_screen_buffer_cols); +// DisplayFillScreen(last_row); + +// AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "[%s]"), disp_screen_buffer[last_row]); + +// renderer->println(disp_screen_buffer[last_row]); +// renderer->Updateframe(); +// } +// } +// } + +// void SSD1331Time(void) { +// char line[12]; + +// renderer->clearDisplay(); +// snprintf_P(line, sizeof(line), PSTR(" %02d" D_HOUR_MINUTE_SEPARATOR "%02d" D_MINUTE_SECOND_SEPARATOR "%02d"), RtcTime.hour, RtcTime.minute, RtcTime.second); // [ 12:34:56 ] +// renderer->setCursor(17, 20); +// renderer->println(line); +// snprintf_P(line, sizeof(line), PSTR("%02d" D_MONTH_DAY_SEPARATOR "%02d" D_YEAR_MONTH_SEPARATOR "%04d"), RtcTime.day_of_month, RtcTime.month, RtcTime.year); // [01-02-2018] +// renderer->setCursor(17, 35); +// renderer->println(line); +// renderer->Updateframe(); +// } + +// void SSD1331Refresh(void) { // Every second +// if (Settings->display_mode) { // Mode 0 is User text +// switch (Settings->display_mode) { +// case 1: // Time +// SSD1331Time(); +// break; +// case 2: // Local +// case 4: // Mqtt +// SSD1331PrintLog(false); +// break; +// case 3: // Local + Time +// case 5: // Mqtt + Time +// SSD1331PrintLog(true); +// break; +// } +// } +// } + +// #endif // USE_DISPLAY_MODES1TO5 + +// /*********************************************************************************************\ +// * Interface +// \*********************************************************************************************/ + +// bool Xdsp14(uint32_t function) { +// bool result = false; + +// if (FUNC_DISPLAY_INIT_DRIVER == function) { +// SSD1331_InitDriver(); +// } +// else if (ssd1331_init_done && (XDSP_14 == Settings->display_model)) { +// switch (function) { +// case FUNC_DISPLAY_MODEL: +// result = true; +// break; +// #ifdef USE_DISPLAY_MODES1TO5 +// case FUNC_DISPLAY_EVERY_SECOND: +// SSD1331Refresh(); +// break; +// #endif // USE_DISPLAY_MODES1TO5 +// } +// } +// return result; +// } +// #endif // USE_DISPLAY_SSD1331 +// #endif // USE_DISPLAY +// #endif // USE_SPI