/*************************************************** This is a library for the Adafruit 1.8" SPI display. This library works with the Adafruit 1.8" TFT Breakout w/SD card ----> http://www.adafruit.com/products/358 as well as Adafruit raw 1.8" TFT display ----> http://www.adafruit.com/products/618 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 ****************************************************/ #ifndef __ST7735_t3_H_ #define __ST7735_t3_H_ #include "Arduino.h" #include "DMAChannel.h" #ifdef __cplusplus #include #endif #include "ILI9341_fonts.h" #ifndef DISABLE_ST77XX_FRAMEBUFFER #if defined(__MK64FX512__) || defined(__MK66FX1M0__) #define ENABLE_ST77XX_FRAMEBUFFER #elif defined(__IMXRT1062__) #define ENABLE_ST77XX_FRAMEBUFFER #endif // Lets allow the user to define if they want T3.2 to enable frame buffer. // it will only work on subset of displays due to memory #define ENABLE_ST77XX_FRAMEBUFFER_T32 #if defined(__MK20DX256__) && defined(ENABLE_ST77XX_FRAMEBUFFER_T32) #define ENABLE_ST77XX_FRAMEBUFFER #endif #endif #define ST7735_SPICLOCK 24000000 //#define ST7735_SPICLOCK 16000000 // some flags for initR() :( #define INITR_GREENTAB 0x0 #define INITR_REDTAB 0x1 #define INITR_BLACKTAB 0x2 #define INITR_18GREENTAB INITR_GREENTAB #define INITR_18REDTAB INITR_REDTAB #define INITR_18BLACKTAB INITR_BLACKTAB #define INITR_144GREENTAB 0x1 #define INITR_144GREENTAB_OFFSET 0x4 #define INITR_MINI160x80 0x05 #define INITR_MINI160x80_ST7735S 0x06 #define INIT_ST7789_TABCOLOR 42 // Not used except as a indicator to the code... #define ST7735_TFTWIDTH 128 #define ST7735_TFTWIDTH_80 80 // for mini // for 1.44" display #define ST7735_TFTHEIGHT_144 128 // for 1.8" display and mini #define ST7735_TFTHEIGHT_160 160 // for 1.8" and mini display #define ST7735_NOP 0x00 #define ST7735_SWRESET 0x01 #define ST7735_RDDID 0x04 #define ST7735_RDDST 0x09 #define ST7735_SLPIN 0x10 #define ST7735_SLPOUT 0x11 #define ST7735_PTLON 0x12 #define ST7735_NORON 0x13 #define ST7735_INVOFF 0x20 #define ST7735_INVON 0x21 #define ST7735_DISPOFF 0x28 #define ST7735_DISPON 0x29 #define ST7735_CASET 0x2A #define ST7735_RASET 0x2B #define ST7735_RAMWR 0x2C #define ST7735_RAMRD 0x2E #define ST7735_PTLAR 0x30 #define ST7735_COLMOD 0x3A #define ST7735_MADCTL 0x36 #define ST7735_FRMCTR1 0xB1 #define ST7735_FRMCTR2 0xB2 #define ST7735_FRMCTR3 0xB3 #define ST7735_INVCTR 0xB4 #define ST7735_DISSET5 0xB6 #define ST7735_PWCTR1 0xC0 #define ST7735_PWCTR2 0xC1 #define ST7735_PWCTR3 0xC2 #define ST7735_PWCTR4 0xC3 #define ST7735_PWCTR5 0xC4 #define ST7735_VMCTR1 0xC5 #define ST7735_RDID1 0xDA #define ST7735_RDID2 0xDB #define ST7735_RDID3 0xDC #define ST7735_RDID4 0xDD #define ST7735_PWCTR6 0xFC #define ST7735_GMCTRP1 0xE0 #define ST7735_GMCTRN1 0xE1 // Color definitions #define ST7735_BLACK 0x0000 #define ST7735_BLUE 0x001F #define ST7735_RED 0xF800 #define ST7735_GREEN 0x07E0 #define ST7735_CYAN 0x07FF #define ST7735_MAGENTA 0xF81F #define ST7735_YELLOW 0xFFE0 #define ST7735_WHITE 0xFFFF // Also define them in a non specific ST77XX specific name #define ST77XX_BLACK 0x0000 #define ST77XX_WHITE 0xFFFF #define ST77XX_RED 0xF800 #define ST77XX_GREEN 0x07E0 #define ST77XX_BLUE 0x001F #define ST77XX_CYAN 0x07FF #define ST77XX_MAGENTA 0xF81F #define ST77XX_YELLOW 0xFFE0 #define ST77XX_ORANGE 0xFC00 #define ST77XX_PINK 0xF81F // Map fonts that were modified back to the ILI9341 font #define ST7735_t3_font_t ILI9341_t3_font_t // Lets see about supporting Adafruit fonts as well? #if __has_include() #include #endif #ifndef _GFXFONT_H_ #define _GFXFONT_H_ /// Font data stored PER GLYPH typedef struct { uint16_t bitmapOffset; ///< Pointer into GFXfont->bitmap uint8_t width; ///< Bitmap dimensions in pixels uint8_t height; ///< Bitmap dimensions in pixels uint8_t xAdvance; ///< Distance to advance cursor (x axis) int8_t xOffset; ///< X dist from cursor pos to UL corner int8_t yOffset; ///< Y dist from cursor pos to UL corner } GFXglyph; /// Data stored for FONT AS A WHOLE typedef struct { uint8_t *bitmap; ///< Glyph bitmaps, concatenated GFXglyph *glyph; ///< Glyph array uint8_t first; ///< ASCII extents (first char) uint8_t last; ///< ASCII extents (last char) uint8_t yAdvance; ///< Newline distance (y axis) } GFXfont; #endif // _GFXFONT_H_ #ifndef st7735_swap #define st7735_swap(a, b) { typeof(a) t = a; a = b; b = t; } #endif #ifdef __cplusplus #if defined(__IMXRT1062__) // Teensy 4.x // Also define these in lower memory so as to make sure they are not cached... // try work around DMA memory cached. So have a couple of buffers we copy frame buffer into // as to move it out of the memory that is cached... #define ST77XX_DMA_BUFFER_SIZE 512 typedef struct { DMASetting _dmasettings[2]; DMAChannel _dmatx; uint16_t _dma_buffer1[ST77XX_DMA_BUFFER_SIZE] __attribute__ ((aligned(4))); uint16_t _dma_buffer2[ST77XX_DMA_BUFFER_SIZE] __attribute__ ((aligned(4))); } ST7735DMA_Data; #endif #define CL(_r,_g,_b) ((((_r)&0xF8)<<8)|(((_g)&0xFC)<<3)|((_b)>>3)) //These enumerate the text plotting alignment (reference datum point) #define TL_DATUM 0 // Top left (default) #define TC_DATUM 1 // Top centre #define TR_DATUM 2 // Top right #define ML_DATUM 3 // Middle left #define CL_DATUM 3 // Centre left, same as above #define MC_DATUM 4 // Middle centre #define CC_DATUM 4 // Centre centre, same as above #define MR_DATUM 5 // Middle right #define CR_DATUM 5 // Centre right, same as above #define BL_DATUM 6 // Bottom left #define BC_DATUM 7 // Bottom centre #define BR_DATUM 8 // Bottom right //#define L_BASELINE 9 // Left character baseline (Line the 'A' character would sit on) //#define C_BASELINE 10 // Centre character baseline //#define R_BASELINE 11 // Right character baseline class ST7735_t3 : public Print { public: ST7735_t3(uint8_t CS, uint8_t RS, uint8_t SID, uint8_t SCLK, uint8_t RST = -1); ST7735_t3(uint8_t CS, uint8_t RS, uint8_t RST = -1); void initB(void), // for ST7735B displays initR(uint8_t options = INITR_GREENTAB), // for ST7735R setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1), pushColor(uint16_t color, boolean last_pixel=false), fillScreen(uint16_t color), drawPixel(int16_t x, int16_t y, uint16_t color), drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color), drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color), fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); inline void fillWindow(uint16_t color) {fillScreen(color);} virtual void setRotation(uint8_t r); void invertDisplay(boolean i); void setRowColStart(uint16_t x, uint16_t y); uint16_t rowStart() {return _rowstart;} uint16_t colStart() {return _colstart;} void setAddr(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) __attribute__((always_inline)) { writecommand(ST7735_CASET); // Column addr set writedata16(x0+_xstart); // XSTART writedata16(x1+_xstart); // XEND writecommand(ST7735_RASET); // Row addr set writedata16(y0+_ystart); // YSTART writedata16(y1+_ystart); // YEND } //// // from Adafruit_GFX.h int16_t width(void) const { return _width; }; int16_t height(void) const { return _height; } uint8_t getRotation(void); void drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color); void drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, uint16_t color); void fillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color); void fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, int16_t delta, uint16_t color); void drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color); void fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color); void drawRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, int16_t radius, uint16_t color); void fillRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, int16_t radius, uint16_t color); void drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color); void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color); void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); void drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size_x, uint8_t size_y); void inline drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size) { drawChar(x, y, c, color, bg, size, size);} static const int16_t CENTER = 9998; void setCursor(int16_t x, int16_t y, bool autoCenter=false); void getCursor(int16_t *x, int16_t *y); void setTextColor(uint16_t c); void setTextColor(uint16_t c, uint16_t bg); void setTextSize(uint8_t sx, uint8_t sy); void inline setTextSize(uint8_t s) { setTextSize(s,s); } uint8_t getTextSizeX(); uint8_t getTextSizeY(); uint8_t getTextSize(); void setTextWrap(boolean w); boolean getTextWrap(); ////// virtual size_t write(uint8_t); virtual size_t write(const uint8_t *buffer, size_t size); int16_t getCursorX(void) const { return cursor_x; } int16_t getCursorY(void) const { return cursor_y; } void setFont(const ILI9341_t3_font_t &f); void setFont(const GFXfont *f = NULL); void setFontAdafruit(void) { setFont(); } void drawFontChar(unsigned int c); void drawGFXFontChar(unsigned int c); void getTextBounds(const uint8_t *buffer, uint16_t len, int16_t x, int16_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h); void getTextBounds(const char *string, int16_t x, int16_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h); void getTextBounds(const String &str, int16_t x, int16_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h); int16_t strPixelLen(const char * str); // added support for drawing strings/numbers/floats with centering // modified from tft_ili9341_ESP github library // Handle numbers int16_t drawNumber(long long_num,int poX, int poY); int16_t drawFloat(float floatNumber,int decimal,int poX, int poY); // Handle char arrays int16_t drawString(const String& string, int poX, int poY); int16_t drawString1(char string[], int16_t len, int poX, int poY); void setTextDatum(uint8_t datum); // added support for scrolling text area // https://github.com/vitormhenrique/ILI9341_t3 // Discussion regarding this optimized version: //http://forum.pjrc.com/threads/26305-Highly-optimized-ILI9341-%28320x240-TFT-color-display%29-library // void setScrollTextArea(int16_t x, int16_t y, int16_t w, int16_t h); void setScrollBackgroundColor(uint16_t color); void enableScroll(void); void disableScroll(void); void scrollTextArea(uint8_t scrollSize); void resetScrollBackgroundColor(uint16_t color); uint16_t readPixel(int16_t x, int16_t y); void readRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t *pcolors); // setOrigin sets an offset in display pixels where drawing to (0,0) will appear // for example: setOrigin(10,10); drawPixel(5,5); will cause a pixel to be drawn at hardware pixel (15,15) void setOrigin(int16_t x = 0, int16_t y = 0) { _originx = x; _originy = y; //if (Serial) Serial.printf("Set Origin %d %d\n", x, y); updateDisplayClip(); } void getOrigin(int16_t* x, int16_t* y) { *x = _originx; *y = _originy; } // setClipRect() sets a clipping rectangle (relative to any set origin) for drawing to be limited to. // Drawing is also restricted to the bounds of the display void setClipRect(int16_t x1, int16_t y1, int16_t w, int16_t h) { _clipx1 = x1; _clipy1 = y1; _clipx2 = x1+w; _clipy2 = y1+h; //if (Serial) Serial.printf("Set clip Rect %d %d %d %d\n", x1, y1, w, h); updateDisplayClip(); } void setClipRect() { _clipx1 = 0; _clipy1 = 0; _clipx2 = _width; _clipy2 = _height; //if (Serial) Serial.printf("clear clip Rect\n"); updateDisplayClip(); } //// void sendCommand(uint8_t commandByte, const uint8_t *dataBytes, uint8_t numDataBytes); // Pass 8-bit (each) R,G,B, get back 16-bit packed color inline uint16_t Color565(uint8_t r, uint8_t g, uint8_t b) { return ((b & 0xF8) << 8) | ((g & 0xFC) << 3) | (r >> 3); } void setBitrate(uint32_t n); /* These are not for current use, 8-bit protocol only! uint8_t readdata(void), readcommand8(uint8_t); uint16_t readcommand16(uint8_t); uint32_t readcommand32(uint8_t); void dummyclock(void); */ // Useful methods added from ili9341_t3 void writeRect(int16_t x, int16_t y, int16_t w, int16_t h, const uint16_t *pcolors); // Frame buffer support #ifdef ENABLE_ST77XX_FRAMEBUFFER enum {ST77XX_DMA_INIT=0x01, ST77XX_DMA_CONT=0x02, ST77XX_DMA_FINISH=0x04,ST77XX_DMA_ACTIVE=0x80}; // added support to use optional Frame buffer void setFrameBuffer(uint16_t *frame_buffer); uint8_t useFrameBuffer(boolean b); // use the frame buffer? First call will allocate void freeFrameBuffer(void); // explicit call to release the buffer void updateScreen(void); // call to say update the screen now. bool updateScreenAsync(bool update_cont = false); // call to say update the screen optinoally turn into continuous mode. void waitUpdateAsyncComplete(void); void endUpdateAsync(); // Turn of the continueous mode fla void dumpDMASettings(); uint16_t *getFrameBuffer() {return _pfbtft;} uint32_t frameCount() {return _dma_frame_count; } boolean asyncUpdateActive(void) {return (_dma_state & ST77XX_DMA_ACTIVE);} void initDMASettings(void); #else // added support to use optional Frame buffer void setFrameBuffer(uint16_t *frame_buffer) {return;} uint8_t useFrameBuffer(boolean b) {return 0;}; // use the frame buffer? First call will allocate void freeFrameBuffer(void) {return;} // explicit call to release the buffer void updateScreen(void) {return;} // call to say update the screen now. bool updateScreenAsync(bool update_cont = false) {return false;} // call to say update the screen optinoally turn into continuous mode. void waitUpdateAsyncComplete(void) {return;} void endUpdateAsync() {return;} // Turn of the continueous mode fla void dumpDMASettings() {return;} uint32_t frameCount() {return 0; } uint16_t *getFrameBuffer() {return NULL;} boolean asyncUpdateActive(void) {return false;} #endif protected: uint8_t tabcolor; void spiwrite(uint8_t), spiwrite16(uint16_t d), writecommand(uint8_t c), writecommand_last(uint8_t c), writedata(uint8_t d), writedata_last(uint8_t d), writedata16(uint16_t d), writedata16_last(uint16_t d), commandList(const uint8_t *addr), commonInit(const uint8_t *cmdList, uint8_t mode=SPI_MODE0); void charBounds(char c, int16_t *x, int16_t *y, int16_t *minx, int16_t *miny, int16_t *maxx, int16_t *maxy); //uint8_t spiread(void); boolean hwSPI; //// int16_t cursor_x, cursor_y; bool _center_x_text = false; bool _center_y_text = false; int16_t _clipx1, _clipy1, _clipx2, _clipy2; int16_t _originx, _originy; int16_t _displayclipx1, _displayclipy1, _displayclipx2, _displayclipy2; bool _invisible = false; bool _standard = true; // no bounding rectangle or origin set. inline void updateDisplayClip() { _displayclipx1 = max(0,min(_clipx1+_originx, width())); _displayclipx2 = max(0,min(_clipx2+_originx, width())); _displayclipy1 = max(0,min(_clipy1+_originy, height())); _displayclipy2 = max(0,min(_clipy2+_originy, height())); _invisible = (_displayclipx1 == _displayclipx2 || _displayclipy1 == _displayclipy2); _standard = (_displayclipx1 == 0) && (_displayclipx2 == _width) && (_displayclipy1 == 0) && (_displayclipy2 == _height); if (Serial) { //Serial.printf("UDC (%d %d)-(%d %d) %d %d\n", _displayclipx1, _displayclipy1, _displayclipx2, _displayclipy2, _invisible, _standard); } } int16_t _width, _height; int16_t scroll_x, scroll_y, scroll_width, scroll_height; boolean scrollEnable,isWritingScrollArea; // If set, 'wrap' text at right edge of display uint16_t textcolor, textbgcolor, scrollbgcolor; uint32_t textcolorPrexpanded, textbgcolorPrexpanded; uint8_t textsize_x, textsize_y, rotation, textdatum; boolean wrap; // If set, 'wrap' text at right edge of display const ILI9341_t3_font_t *font; // Anti-aliased font support uint8_t fontbpp = 1; uint8_t fontbppindex = 0; uint8_t fontbppmask = 1; uint8_t fontppb = 8; uint8_t* fontalphalut; float fontalphamx = 1; uint32_t padX; // GFX Font support const GFXfont *gfxFont = nullptr; int8_t _gfxFont_min_yOffset = 0; // Opaque font chracter overlap? unsigned int _gfx_c_last; int16_t _gfx_last_cursor_x, _gfx_last_cursor_y; int16_t _gfx_last_char_x_write = 0; uint16_t _gfx_last_char_textcolor; uint16_t _gfx_last_char_textbgcolor; bool gfxFontLastCharPosFG(int16_t x, int16_t y); void drawFontBits(bool opaque, uint32_t bits, uint32_t numbits, int32_t x, int32_t y, uint32_t repeat); void drawFontPixel( uint8_t alpha, uint32_t x, uint32_t y ); uint32_t fetchpixel(const uint8_t *p, uint32_t index, uint32_t x); uint16_t _colstart, _rowstart, _xstart, _ystart, _rot, _screenHeight, _screenWidth; SPISettings _spiSettings; #if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) uint8_t _cs, _rs, _rst, _sid, _sclk; uint8_t pcs_data, pcs_command; uint32_t ctar; volatile uint8_t *datapin, *clkpin, *cspin, *rspin; SPIClass *_pspi = nullptr; uint8_t _spi_num; // Which buss is this spi on? KINETISK_SPI_t *_pkinetisk_spi; SPIClass::SPI_Hardware_t *_spi_hardware; void waitTransmitComplete(void); void waitTransmitComplete(uint32_t mcr); uint32_t _fifo_full_test; inline void beginSPITransaction() { if (_pspi) _pspi->beginTransaction(_spiSettings); if (cspin) *cspin = 0; } inline void endSPITransaction() { if (cspin) *cspin = 1; if (_pspi) _pspi->endTransaction(); } #endif #if defined(__IMXRT1062__) // Teensy 4.x SPIClass *_pspi = nullptr; uint8_t _spi_num = 0; // Which buss is this spi on? IMXRT_LPSPI_t *_pimxrt_spi = nullptr; SPIClass::SPI_Hardware_t *_spi_hardware; uint8_t _pending_rx_count = 0; uint32_t _spi_tcr_current = 0; uint32_t _tcr_dc_assert; uint32_t _tcr_dc_not_assert; void DIRECT_WRITE_LOW(volatile uint32_t * base, uint32_t mask) __attribute__((always_inline)) { *(base+34) = mask; } void DIRECT_WRITE_HIGH(volatile uint32_t * base, uint32_t mask) __attribute__((always_inline)) { *(base+33) = mask; } #define TCR_MASK (LPSPI_TCR_PCS(3) | LPSPI_TCR_FRAMESZ(31) | LPSPI_TCR_CONT | LPSPI_TCR_RXMSK ) void maybeUpdateTCR(uint32_t requested_tcr_state) { if ((_spi_tcr_current & TCR_MASK) != requested_tcr_state) { bool dc_state_change = (_spi_tcr_current & LPSPI_TCR_PCS(3)) != (requested_tcr_state & LPSPI_TCR_PCS(3)); _spi_tcr_current = (_spi_tcr_current & ~TCR_MASK) | requested_tcr_state ; // only output when Transfer queue is empty. if (!dc_state_change || !_dcpinmask) { while ((_pimxrt_spi->FSR & 0x1f) ) ; _pimxrt_spi->TCR = _spi_tcr_current; // update the TCR } else { waitTransmitComplete(); if (requested_tcr_state & LPSPI_TCR_PCS(3)) DIRECT_WRITE_HIGH(_dcport, _dcpinmask); else DIRECT_WRITE_LOW(_dcport, _dcpinmask); _pimxrt_spi->TCR = _spi_tcr_current & ~(LPSPI_TCR_PCS(3) | LPSPI_TCR_CONT); // go ahead and update TCR anyway? } } } inline void beginSPITransaction() { if (hwSPI) _pspi->beginTransaction(_spiSettings); if (!_dcport) _spi_tcr_current = _pimxrt_spi->TCR; // Only if DC is on hardware CS if (_csport)DIRECT_WRITE_LOW(_csport, _cspinmask); } inline void endSPITransaction() { if (_csport)DIRECT_WRITE_HIGH(_csport, _cspinmask); if (hwSPI) _pspi->endTransaction(); } void waitFifoNotFull(void) { uint32_t tmp __attribute__((unused)); do { if ((_pimxrt_spi->RSR & LPSPI_RSR_RXEMPTY) == 0) { tmp = _pimxrt_spi->RDR; // Read any pending RX bytes in if (_pending_rx_count) _pending_rx_count--; //decrement count of bytes still levt } } while ((_pimxrt_spi->SR & LPSPI_SR_TDF) == 0) ; } void waitTransmitComplete(void) { uint32_t tmp __attribute__((unused)); // digitalWriteFast(2, HIGH); while (_pending_rx_count) { if ((_pimxrt_spi->RSR & LPSPI_RSR_RXEMPTY) == 0) { tmp = _pimxrt_spi->RDR; // Read any pending RX bytes in _pending_rx_count--; //decrement count of bytes still levt } } _pimxrt_spi->CR = LPSPI_CR_MEN | LPSPI_CR_RRF; // Clear RX FIFO // digitalWriteFast(2, LOW); } uint8_t _cs, _rs, _rst, _sid, _sclk; uint32_t _cspinmask; volatile uint32_t *_csport; uint32_t _dcpinmask; volatile uint32_t *_dcport; uint32_t _mosipinmask; volatile uint32_t *_mosiport; uint32_t _sckpinmask; volatile uint32_t *_sckport; uint32_t ctar; #endif #if defined(__MKL26Z64__) volatile uint8_t *dataport, *clkport, *csport, *rsport; uint8_t _cs, _rs, _rst, _sid, _sclk, datapinmask, clkpinmask, cspinmask, rspinmask; boolean hwSPI1; inline void beginSPITransaction() { if (hwSPI) SPI.beginTransaction(_spiSettings); else if (hwSPI1) SPI1.beginTransaction(_spiSettings); if (csport)*csport &= ~cspinmask; } inline void endSPITransaction() { if (csport) *csport |= cspinmask; if (hwSPI) SPI.endTransaction(); else if (hwSPI1) SPI1.endTransaction(); } #endif #ifdef ENABLE_ST77XX_FRAMEBUFFER // Add support for optional frame buffer uint16_t *_pfbtft; // Optional Frame buffer uint8_t _use_fbtft; // Are we in frame buffer mode? uint16_t *_we_allocated_buffer; // We allocated the buffer; uint32_t _count_pixels; // How big is the display in total pixels... // Add DMA support. // Note: We have enough memory to have more than one, so could have multiple active devices (one per SPI BUS) // All three devices have 3 SPI buss so hard coded static ST7735_t3 *_dmaActiveDisplay[3]; // Use pointer to this as a way to get back to object... volatile uint8_t _dma_state; // DMA status volatile uint32_t _dma_frame_count; // Can return a frame count... #if defined(__MK66FX1M0__) // T3.6 use Scatter/gather with chain to do transfer static DMASetting _dmasettings[3][4]; DMAChannel _dmatx; uint8_t _cnt_dma_settings; // how many do we need for this display? #elif defined(__IMXRT1062__) // Teensy 4.x static ST7735DMA_Data _dma_data[3]; // one structure for each SPI buss... // try work around DMA memory cached. So have a couple of buffers we copy frame buffer into // as to move it out of the memory that is cached... volatile uint32_t _dma_pixel_index = 0; volatile uint16_t _dma_sub_frame_count = 0; // Can return a frame count... uint16_t _dma_buffer_size; // the actual size we are using <= DMA_BUFFER_SIZE; uint16_t _dma_cnt_sub_frames_per_frame; uint32_t _spi_fcr_save; // save away previous FCR register value #elif defined(__MK64FX512__) // T3.5 - had issues scatter/gather so do just use channels/interrupts // and update and continue uint8_t _cspinmask; volatile uint8_t *_csport = nullptr; DMAChannel _dmatx; DMAChannel _dmarx; uint32_t _dma_count_remaining; uint16_t _dma_write_size_words; #elif defined(__MK20DX256__) // For first pass maybe emulate T3.5 on SPI... uint8_t _cspinmask; volatile uint8_t *_csport = nullptr; DMAChannel _dmatx; DMAChannel _dmarx; uint16_t _dma_count_remaining; uint16_t _dma_write_size_words; #endif static void dmaInterrupt(void); static void dmaInterrupt1(void); static void dmaInterrupt2(void); void process_dma_interrupt(void); #endif void HLine(int16_t x, int16_t y, int16_t w, uint16_t color) __attribute__((always_inline)) { #ifdef ENABLE_ST77XX_FRAMEBUFFER if (_use_fbtft) { drawFastHLine(x, y, w, color); return; } #endif x+=_originx; y+=_originy; // Rectangular clipping if((y < _displayclipy1) || (x >= _displayclipx2) || (y >= _displayclipy2)) return; if(x<_displayclipx1) { w = w - (_displayclipx1 - x); x = _displayclipx1; } if((x+w-1) >= _displayclipx2) w = _displayclipx2-x; if (w<1) return; setAddr(x, y, x+w-1, y); writecommand(ST7735_RAMWR); do { writedata16(color); } while (--w > 0); } void VLine(int16_t x, int16_t y, int16_t h, uint16_t color) __attribute__((always_inline)) { #ifdef ENABLE_ST77XX_FRAMEBUFFER if (_use_fbtft) { drawFastVLine(x, y, h, color); return; } #endif x+=_originx; y+=_originy; // Rectangular clipping if((x < _displayclipx1) || (x >= _displayclipx2) || (y >= _displayclipy2)) return; if(y < _displayclipy1) { h = h - (_displayclipy1 - y); y = _displayclipy1;} if((y+h-1) >= _displayclipy2) h = _displayclipy2-y; if(h<1) return; setAddr(x, y, x, y+h-1); writecommand(ST7735_RAMWR); do { writedata16(color); } while (--h > 0); } /** * Found in a pull request for the Adafruit framebuffer library. Clever! * https://github.com/tricorderproject/arducordermini/pull/1/files#diff-d22a481ade4dbb4e41acc4d7c77f683d * Converts 0000000000000000rrrrrggggggbbbbb * into 00000gggggg00000rrrrr000000bbbbb * with mask 00000111111000001111100000011111 * This is useful because it makes space for a parallel fixed-point multiply * This implements the linear interpolation formula: result = bg * (1.0 - alpha) + fg * alpha * This can be factorized into: result = bg + (fg - bg) * alpha * alpha is in Q1.5 format, so 0.0 is represented by 0, and 1.0 is represented by 32 * @param fg Color to draw in RGB565 (16bit) * @param bg Color to draw over in RGB565 (16bit) * @param alpha Alpha in range 0-255 **/ uint16_t alphaBlendRGB565( uint32_t fg, uint32_t bg, uint8_t alpha ) __attribute__((always_inline)) { alpha = ( alpha + 4 ) >> 3; // from 0-255 to 0-31 bg = (bg | (bg << 16)) & 0b00000111111000001111100000011111; fg = (fg | (fg << 16)) & 0b00000111111000001111100000011111; uint32_t result = ((((fg - bg) * alpha) >> 5) + bg) & 0b00000111111000001111100000011111; return (uint16_t)((result >> 16) | result); // contract result } /** * Same as above, but fg and bg are premultiplied, and alpah is already in range 0-31 */ uint16_t alphaBlendRGB565Premultiplied( uint32_t fg, uint32_t bg, uint8_t alpha ) __attribute__((always_inline)) { uint32_t result = ((((fg - bg) * alpha) >> 5) + bg) & 0b00000111111000001111100000011111; return (uint16_t)((result >> 16) | result); // contract result } void Pixel(int16_t x, int16_t y, uint16_t color) __attribute__((always_inline)) { x+=_originx; y+=_originy; //if((x < _displayclipx1) ||(x >= _displayclipx2) || (y < _displayclipy1) || (y >= _displayclipy2)) return; #ifdef ENABLE_ST77XX_FRAMEBUFFER if (_use_fbtft) { _pfbtft[y*_screenWidth + x] = color; return; } #endif setAddr(x, y, x, y); writecommand(ST7735_RAMWR); writedata16(color); } }; // To avoid conflict when also using Adafruit_GFX or any Adafruit library // which depends on Adafruit_GFX, #include the Adafruit library *BEFORE* // you #include ST7735_t3.h. // Warning the implemention of class needs to be here, else the code // compiled in the c++ file will cause duplicate defines in the link phase. #define Adafruit_GFX_Button ST7735_Button class ST7735_Button { public: ST7735_Button(void) { _gfx = NULL; } void initButton(ST7735_t3 *gfx, int16_t x, int16_t y, uint8_t w, uint8_t h, uint16_t outline, uint16_t fill, uint16_t textcolor, const char *label, uint8_t textsize_x, uint8_t textsize_y) { _x = x; _y = y; _w = w; _h = h; _outlinecolor = outline; _fillcolor = fill; _textcolor = textcolor; _textsize_x = textsize_x; _textsize_y = textsize_y; _gfx = gfx; strncpy(_label, label, 9); _label[9] = 0; } void drawButton(bool inverted = false) { uint16_t fill, outline, text; if (! inverted) { fill = _fillcolor; outline = _outlinecolor; text = _textcolor; } else { fill = _textcolor; outline = _outlinecolor; text = _fillcolor; } _gfx->fillRoundRect(_x - (_w/2), _y - (_h/2), _w, _h, min(_w,_h)/4, fill); _gfx->drawRoundRect(_x - (_w/2), _y - (_h/2), _w, _h, min(_w,_h)/4, outline); _gfx->setCursor(_x - strlen(_label)*3*_textsize_x, _y-4*_textsize_y); _gfx->setTextColor(text); _gfx->setTextSize(_textsize_x, _textsize_y); _gfx->print(_label); } bool contains(int16_t x, int16_t y) { if ((x < (_x - _w/2)) || (x > (_x + _w/2))) return false; if ((y < (_y - _h/2)) || (y > (_y + _h/2))) return false; return true; } void press(boolean p) { laststate = currstate; currstate = p; } bool isPressed() { return currstate; } bool justPressed() { return (currstate && !laststate); } bool justReleased() { return (!currstate && laststate); } private: ST7735_t3 *_gfx; int16_t _x, _y; uint16_t _w, _h; uint8_t _textsize_x, _textsize_y; uint16_t _outlinecolor, _fillcolor, _textcolor; char _label[10]; boolean currstate, laststate; }; #endif //end cplus #endif