diff --git a/Adafruit_SPITFT.cpp b/Adafruit_SPITFT.cpp new file mode 100644 index 0000000..9b6c8bb --- /dev/null +++ b/Adafruit_SPITFT.cpp @@ -0,0 +1,336 @@ +/*************************************************** + This is our library for generic SPI TFT Displays with + address windows and 16 bit color (e.g. ILI9341, HX8357D, ST7735...) + + Check out the links above for our tutorials and wiring diagrams + These displays use SPI to communicate, 4 or 5 pins are required to + interface (RST is optional) + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + Written by Limor Fried/Ladyada for Adafruit Industries. + MIT license, all text above must be included in any redistribution + ****************************************************/ + + +#include "Adafruit_SPITFT.h" +#ifndef ARDUINO_STM32_FEATHER + #include "pins_arduino.h" +#ifndef RASPI + #include "wiring_private.h" +#endif +#endif +#include + +#include "Adafruit_SPITFT_Macros.h" + + + +// Pass 8-bit (each) R,G,B, get back 16-bit packed color +uint16_t Adafruit_SPITFT::color565(uint8_t r, uint8_t g, uint8_t b) { + return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3); +} + +Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, + int8_t cs, int8_t dc, int8_t mosi, + int8_t sclk, int8_t rst, int8_t miso) + : Adafruit_GFX(w, h) { + _cs = cs; + _dc = dc; + _rst = rst; + _sclk = sclk; + _mosi = mosi; + _miso = miso; + _freq = 0; +#ifdef USE_FAST_PINIO + csport = portOutputRegister(digitalPinToPort(_cs)); + cspinmask = digitalPinToBitMask(_cs); + dcport = portOutputRegister(digitalPinToPort(_dc)); + dcpinmask = digitalPinToBitMask(_dc); + clkport = portOutputRegister(digitalPinToPort(_sclk)); + clkpinmask = digitalPinToBitMask(_sclk); + mosiport = portOutputRegister(digitalPinToPort(_mosi)); + mosipinmask = digitalPinToBitMask(_mosi); + if(miso >= 0){ + misoport = portInputRegister(digitalPinToPort(_miso)); + misopinmask = digitalPinToBitMask(_miso); + } else { + misoport = 0; + misopinmask = 0; + } +#endif +} + +Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, + int8_t cs, int8_t dc, int8_t rst) + : Adafruit_GFX(w, h) { + _cs = cs; + _dc = dc; + _rst = rst; + _sclk = -1; + _mosi = -1; + _miso = -1; + _freq = 0; +#ifdef USE_FAST_PINIO + csport = portOutputRegister(digitalPinToPort(_cs)); + cspinmask = digitalPinToBitMask(_cs); + dcport = portOutputRegister(digitalPinToPort(_dc)); + dcpinmask = digitalPinToBitMask(_dc); + clkport = 0; + clkpinmask = 0; + mosiport = 0; + mosipinmask = 0; + misoport = 0; + misopinmask = 0; +#endif +} + + +void Adafruit_SPITFT::initSPI(uint32_t freq) +{ + _freq = freq; + + // Control Pins + pinMode(_dc, OUTPUT); + digitalWrite(_dc, LOW); + pinMode(_cs, OUTPUT); + digitalWrite(_cs, HIGH); + + // Software SPI + if(_sclk >= 0){ + pinMode(_mosi, OUTPUT); + digitalWrite(_mosi, LOW); + pinMode(_sclk, OUTPUT); + digitalWrite(_sclk, HIGH); + if(_miso >= 0){ + pinMode(_miso, INPUT); + } + } + + // Hardware SPI + SPI_BEGIN(); + + // toggle RST low to reset + if (_rst >= 0) { + pinMode(_rst, OUTPUT); + digitalWrite(_rst, HIGH); + delay(100); + digitalWrite(_rst, LOW); + delay(100); + digitalWrite(_rst, HIGH); + delay(200); + } +} + +uint8_t Adafruit_SPITFT::spiRead() { + if(_sclk < 0){ + return HSPI_READ(); + } + if(_miso < 0){ + return 0; + } + uint8_t r = 0; + for (uint8_t i=0; i<8; i++) { + SSPI_SCK_LOW(); + SSPI_SCK_HIGH(); + r <<= 1; + if (SSPI_MISO_READ()){ + r |= 0x1; + } + } + return r; +} + +void Adafruit_SPITFT::spiWrite(uint8_t b) { + if(_sclk < 0){ + HSPI_WRITE(b); + return; + } + for(uint8_t bit = 0x80; bit; bit >>= 1){ + if((b) & bit){ + SSPI_MOSI_HIGH(); + } else { + SSPI_MOSI_LOW(); + } + SSPI_SCK_LOW(); + SSPI_SCK_HIGH(); + } +} + + +/* + * Transaction API + * */ + +void Adafruit_SPITFT::startWrite(void){ + SPI_BEGIN_TRANSACTION(); + SPI_CS_LOW(); +} + +void Adafruit_SPITFT::endWrite(void){ + SPI_CS_HIGH(); + SPI_END_TRANSACTION(); +} + +void Adafruit_SPITFT::writeCommand(uint8_t cmd){ + SPI_DC_LOW(); + spiWrite(cmd); + SPI_DC_HIGH(); +} + +void Adafruit_SPITFT::pushColor(uint16_t color) { + startWrite(); + SPI_WRITE16(color); + endWrite(); +} + + +void Adafruit_SPITFT::writePixel(uint16_t color){ + SPI_WRITE16(color); +} + +void Adafruit_SPITFT::writePixels(uint16_t * colors, uint32_t len){ + SPI_WRITE_PIXELS((uint8_t*)colors , len * 2); +} + +void Adafruit_SPITFT::writeColor(uint16_t color, uint32_t len){ +#ifdef SPI_HAS_WRITE_PIXELS + if(_sclk >= 0){ + for (uint32_t t=0; t SPI_MAX_PIXELS_AT_ONCE)?SPI_MAX_PIXELS_AT_ONCE:len; + uint16_t tlen = 0; + + for (uint32_t t=0; tblen)?blen:len; + writePixels(temp, tlen); + len -= tlen; + } +#else + uint8_t hi = color >> 8, lo = color; + if(_sclk < 0){ //AVR Optimization + for (uint32_t t=len; t; t--){ + HSPI_WRITE(hi); + HSPI_WRITE(lo); + } + return; + } + for (uint32_t t=len; t; t--){ + spiWrite(hi); + spiWrite(lo); + } +#endif +} + +void Adafruit_SPITFT::writePixel(int16_t x, int16_t y, uint16_t color) { + if((x < 0) ||(x >= _width) || (y < 0) || (y >= _height)) return; + setAddrWindow(x,y,1,1); + writePixel(color); +} + +void Adafruit_SPITFT::writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color){ + if((x >= _width) || (y >= _height)) return; + int16_t x2 = x + w - 1, y2 = y + h - 1; + if((x2 < 0) || (y2 < 0)) return; + + // Clip left/top + if(x < 0) { + x = 0; + w = x2 + 1; + } + if(y < 0) { + y = 0; + h = y2 + 1; + } + + // Clip right/bottom + if(x2 >= _width) w = _width - x; + if(y2 >= _height) h = _height - y; + + int32_t len = (int32_t)w * h; + setAddrWindow(x, y, w, h); + writeColor(color, len); +} + +void Adafruit_SPITFT::writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color){ + writeFillRect(x, y, 1, h, color); +} + +void Adafruit_SPITFT::writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color){ + writeFillRect(x, y, w, 1, color); +} + +void Adafruit_SPITFT::drawPixel(int16_t x, int16_t y, uint16_t color){ + startWrite(); + writePixel(x, y, color); + endWrite(); +} + +void Adafruit_SPITFT::drawFastVLine(int16_t x, int16_t y, + int16_t h, uint16_t color) { + startWrite(); + writeFastVLine(x, y, h, color); + endWrite(); +} + +void Adafruit_SPITFT::drawFastHLine(int16_t x, int16_t y, + int16_t w, uint16_t color) { + startWrite(); + writeFastHLine(x, y, w, color); + endWrite(); +} + +void Adafruit_SPITFT::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, + uint16_t color) { + startWrite(); + writeFillRect(x,y,w,h,color); + endWrite(); +} + +// 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. +void Adafruit_SPITFT::drawRGBBitmap(int16_t x, int16_t y, + uint16_t *pcolors, int16_t w, int16_t h) { + + int16_t x2, y2; // Lower-right coord + if(( x >= _width ) || // Off-edge right + ( y >= _height) || // " top + ((x2 = (x+w-1)) < 0 ) || // " left + ((y2 = (y+h-1)) < 0) ) return; // " bottom + + int16_t bx1=0, by1=0, // Clipped top-left within bitmap + saveW=w; // Save original bitmap width value + if(x < 0) { // Clip left + w += x; + bx1 = -x; + x = 0; + } + if(y < 0) { // Clip top + h += y; + by1 = -y; + y = 0; + } + if(x2 >= _width ) w = _width - x; // Clip right + if(y2 >= _height) h = _height - y; // Clip bottom + + pcolors += by1 * saveW + bx1; // Offset bitmap ptr to clipped top-left + startWrite(); + setAddrWindow(x, y, w, h); // Clipped area + while(h--) { // For each (clipped) scanline... + writePixels(pcolors, w); // Push one (clipped) row + pcolors += saveW; // Advance pointer by one full (unclipped) line + } + endWrite(); +} diff --git a/Adafruit_SPITFT.h b/Adafruit_SPITFT.h new file mode 100644 index 0000000..0024a01 --- /dev/null +++ b/Adafruit_SPITFT.h @@ -0,0 +1,80 @@ + +#ifndef _ADAFRUIT_SPITFT_ +#define _ADAFRUIT_SPITFT_ + + +#if ARDUINO >= 100 + #include "Arduino.h" + #include "Print.h" +#else + #include "WProgram.h" +#endif +#include +#include "Adafruit_GFX.h" + + +#if defined(ARDUINO_STM32_FEATHER) +typedef volatile uint32 RwReg; +#endif +#if defined(ARDUINO_FEATHER52) +typedef volatile uint32_t RwReg; +#endif + +class Adafruit_SPITFT : public Adafruit_GFX { + protected: + + public: + Adafruit_SPITFT(uint16_t w, uint16_t h, int8_t _CS, int8_t _DC, int8_t _MOSI, int8_t _SCLK, int8_t _RST = -1, int8_t _MISO = -1); + Adafruit_SPITFT(uint16_t w, uint16_t h, int8_t _CS, int8_t _DC, int8_t _RST = -1); + + virtual void begin(uint32_t freq) = 0; + void initSPI(uint32_t freq); + + // Required Non-Transaction + void drawPixel(int16_t x, int16_t y, uint16_t color); + + // Transaction API + void startWrite(void); + void endWrite(void); + void writePixel(int16_t x, int16_t y, uint16_t color); + void writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color); + void writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color); + + // Transaction API not used by GFX + virtual void setAddrWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h) = 0; + void writePixel(uint16_t color); + void writePixels(uint16_t * colors, uint32_t len); + void writeColor(uint16_t color, uint32_t len); + void pushColor(uint16_t color); + + // Recommended Non-Transaction + void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color); + void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color); + void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + + 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); + + uint16_t color565(uint8_t r, uint8_t g, uint8_t b); + + protected: + uint32_t _freq; +#if defined (__AVR__) || defined(TEENSYDUINO) || defined (ESP8266) || defined (ESP32) + int8_t _cs, _dc, _rst, _sclk, _mosi, _miso; +#else + int32_t _cs, _dc, _rst, _sclk, _mosi, _miso; +#endif + +#ifdef USE_FAST_PINIO + volatile RwReg *mosiport, *misoport, *clkport, *dcport, *csport; + RwReg mosipinmask, misopinmask, clkpinmask, cspinmask, dcpinmask; +#endif + + void writeCommand(uint8_t cmd); + void spiWrite(uint8_t v); + uint8_t spiRead(void); +}; + +#endif diff --git a/Adafruit_SPITFT_Macros.h b/Adafruit_SPITFT_Macros.h new file mode 100644 index 0000000..74391da --- /dev/null +++ b/Adafruit_SPITFT_Macros.h @@ -0,0 +1,114 @@ + +/* + * Control Pins + * */ + +#ifdef USE_FAST_PINIO +#define SPI_DC_HIGH() *dcport |= dcpinmask +#define SPI_DC_LOW() *dcport &= ~dcpinmask +#define SPI_CS_HIGH() *csport |= cspinmask +#define SPI_CS_LOW() *csport &= ~cspinmask +#else +#define SPI_DC_HIGH() digitalWrite(_dc, HIGH) +#define SPI_DC_LOW() digitalWrite(_dc, LOW) +#define SPI_CS_HIGH() digitalWrite(_cs, HIGH) +#define SPI_CS_LOW() digitalWrite(_cs, LOW) +#endif + +/* + * Software SPI Macros + * */ + +#ifdef USE_FAST_PINIO +#define SSPI_MOSI_HIGH() *mosiport |= mosipinmask +#define SSPI_MOSI_LOW() *mosiport &= ~mosipinmask +#define SSPI_SCK_HIGH() *clkport |= clkpinmask +#define SSPI_SCK_LOW() *clkport &= ~clkpinmask +#define SSPI_MISO_READ() ((*misoport & misopinmask) != 0) +#else +#define SSPI_MOSI_HIGH() digitalWrite(_mosi, HIGH) +#define SSPI_MOSI_LOW() digitalWrite(_mosi, LOW) +#define SSPI_SCK_HIGH() digitalWrite(_sclk, HIGH) +#define SSPI_SCK_LOW() digitalWrite(_sclk, LOW) +#define SSPI_MISO_READ() digitalRead(_miso) +#endif + +#define SSPI_BEGIN_TRANSACTION() +#define SSPI_END_TRANSACTION() +#define SSPI_WRITE(v) spiWrite(v) +#define SSPI_WRITE16(s) SSPI_WRITE((s) >> 8); SSPI_WRITE(s) +#define SSPI_WRITE32(l) SSPI_WRITE((l) >> 24); SSPI_WRITE((l) >> 16); SSPI_WRITE((l) >> 8); SSPI_WRITE(l) +#define SSPI_WRITE_PIXELS(c,l) for(uint32_t i=0; i<(l); i+=2){ SSPI_WRITE(((uint8_t*)(c))[i+1]); SSPI_WRITE(((uint8_t*)(c))[i]); } + +/* + * Hardware SPI Macros + * */ + +#define SPI_OBJECT SPI + +#if defined (__AVR__) || defined(TEENSYDUINO) || defined(ARDUINO_ARCH_STM32F1) + #define HSPI_SET_CLOCK() SPI_OBJECT.setClockDivider(SPI_CLOCK_DIV2); +#elif defined (__arm__) + #define HSPI_SET_CLOCK() SPI_OBJECT.setClockDivider(11); +#elif defined(ESP8266) || defined(ESP32) + #define HSPI_SET_CLOCK() SPI_OBJECT.setFrequency(_freq); +#elif defined(RASPI) + #define HSPI_SET_CLOCK() SPI_OBJECT.setClock(_freq); +#elif defined(ARDUINO_ARCH_STM32F1) + #define HSPI_SET_CLOCK() SPI_OBJECT.setClock(_freq); +#else + #define HSPI_SET_CLOCK() +#endif + +#ifdef SPI_HAS_TRANSACTION + #define HSPI_BEGIN_TRANSACTION() SPI_OBJECT.beginTransaction(SPISettings(_freq, MSBFIRST, SPI_MODE0)) + #define HSPI_END_TRANSACTION() SPI_OBJECT.endTransaction() +#else + #define HSPI_BEGIN_TRANSACTION() HSPI_SET_CLOCK(); SPI_OBJECT.setBitOrder(MSBFIRST); SPI_OBJECT.setDataMode(SPI_MODE0) + #define HSPI_END_TRANSACTION() +#endif + +#ifdef ESP32 + #define SPI_HAS_WRITE_PIXELS +#endif +#if defined(ESP8266) || defined(ESP32) + // Optimized SPI (ESP8266 and ESP32) + #define HSPI_READ() SPI_OBJECT.transfer(0) + #define HSPI_WRITE(b) SPI_OBJECT.write(b) + #define HSPI_WRITE16(s) SPI_OBJECT.write16(s) + #define HSPI_WRITE32(l) SPI_OBJECT.write32(l) + #ifdef SPI_HAS_WRITE_PIXELS + #define SPI_MAX_PIXELS_AT_ONCE 32 + #define HSPI_WRITE_PIXELS(c,l) SPI_OBJECT.writePixels(c,l) + #else + #define HSPI_WRITE_PIXELS(c,l) for(uint32_t i=0; i<((l)/2); i++){ SPI_WRITE16(((uint16_t*)(c))[i]); } + #endif +#else + // Standard Byte-by-Byte SPI + + #if defined (__AVR__) || defined(TEENSYDUINO) +static inline uint8_t _avr_spi_read(void) __attribute__((always_inline)); +static inline uint8_t _avr_spi_read(void) { + uint8_t r = 0; + SPDR = r; + while(!(SPSR & _BV(SPIF))); + r = SPDR; + return r; +} + #define HSPI_WRITE(b) {SPDR = (b); while(!(SPSR & _BV(SPIF)));} + #define HSPI_READ() _avr_spi_read() + #else + #define HSPI_WRITE(b) SPI_OBJECT.transfer((uint8_t)(b)) + #define HSPI_READ() HSPI_WRITE(0) + #endif + #define HSPI_WRITE16(s) HSPI_WRITE((s) >> 8); HSPI_WRITE(s) + #define HSPI_WRITE32(l) HSPI_WRITE((l) >> 24); HSPI_WRITE((l) >> 16); HSPI_WRITE((l) >> 8); HSPI_WRITE(l) + #define HSPI_WRITE_PIXELS(c,l) for(uint32_t i=0; i<(l); i+=2){ HSPI_WRITE(((uint8_t*)(c))[i+1]); HSPI_WRITE(((uint8_t*)(c))[i]); } +#endif + +#define SPI_BEGIN() if(_sclk < 0){SPI_OBJECT.begin();} +#define SPI_BEGIN_TRANSACTION() if(_sclk < 0){HSPI_BEGIN_TRANSACTION();} +#define SPI_END_TRANSACTION() if(_sclk < 0){HSPI_END_TRANSACTION();} +#define SPI_WRITE16(s) if(_sclk < 0){HSPI_WRITE16(s);}else{SSPI_WRITE16(s);} +#define SPI_WRITE32(l) if(_sclk < 0){HSPI_WRITE32(l);}else{SSPI_WRITE32(l);} +#define SPI_WRITE_PIXELS(c,l) if(_sclk < 0){HSPI_WRITE_PIXELS(c,l);}else{SSPI_WRITE_PIXELS(c,l);}