#pragma once #define FONT_COUNT 7 #include #define SPI_FREQUENCY 7500000 #define SPI_READ_FREQUENCY 20000000 #define SPI_TOUCH_FREQUENCY 2500000 #define OR_REGISTER(register, value) WRITE_PERI_REG(register, READ_PERI_REG(register | value)) #define SPI_SET_CLOCK_FREQ(target_freq_hz) \ do { \ uint32_t sys_freq = getApbFrequency(); \ if(sys_freq == target_freq_hz) { \ *_spi_clock = 1 << 31;\ return; \ } \ uint32_t pre_div = 1; \ uint32_t cnt_n = 1; \ \ /* Find optimal dividers: sys_freq / pre_div / cnt_n = target_freq */ \ uint32_t total_div = (sys_freq + (target_freq_hz) - 1) / (target_freq_hz); \ \ /* Try to balance pre_div and cnt_n for best accuracy */ \ for (uint32_t p = 1; p <= 0x2000; p++) { \ uint32_t c = (total_div + p - 1) / p; \ if (c >= 1 && c <= 0x40) { \ pre_div = p; \ cnt_n = c; \ break; \ } \ } \ \ /* Adjust to register format (values are minus one) */ \ pre_div = (pre_div > 1) ? (pre_div - 1) : 0; \ cnt_n = (cnt_n > 1) ? (cnt_n - 1) : 0; \ \ /* Calculate cnt_h for 50% duty cycle */ \ uint32_t cnt_h = (cnt_n > 0) ? ((cnt_n + 1) / 2 - 1) : 0; \ \ /* Build register value */ \ uint32_t reg_val = 0; \ reg_val |= (0 << 31); /* SPI_CLK_EQU_SYSCLK = 0 (use dividers) */ \ reg_val |= (pre_div << 18); /* SPI_CLKDIV_PRE */ \ reg_val |= (cnt_n << 12); /* SPI_CLKCNT_N */ \ reg_val |= (cnt_h << 6); /* SPI_CLKCNT_H */ \ reg_val |= (cnt_n << 0); /* SPI_CLKCNT_L = SPI_CLKCNT_N */ \ \ *_spi_clock = reg_val; \ } while(0) #define TFT_WIDTH 240 #define TFT_HEIGHT 320 #define TFT_NOP 0x00 #define TFT_INVOFF 0x20 #define TFT_INVON 0x21 #define TFT_CASET 0x2A #define TFT_PASET 0x2B #define TFT_RAMWR 0x2C #define TFT_RAMRD 0x2E #define TFT_IDXRD 0xDD #define TFT_MADCTL 0x36 #define TFT_MAD_MY 0x80 #define TFT_MAD_MX 0x40 #define TFT_MAD_MV 0x20 #define TFT_MAD_ML 0x10 #define TFT_MAD_BGR 0x08 #define TFT_MAD_MH 0x04 #define TFT_MAD_RGB 0x00 #define ILI9341_SLPOUT 0x11 #define ILI9341_NORON 0x13 #define ILI9341_GAMMASET 0x26 #define ILI9341_DISPON 0x29 #define ILI9341_MADCTL 0x36 #define ILI9341_PIXFMT 0x3A #define ILI9341_FRMCTR1 0xB1 #define ILI9341_DFUNCTR 0xB6 #define ILI9341_PWCTR1 0xC0 #define ILI9341_PWCTR2 0xC1 #define ILI9341_VMCTR1 0xC5 #define ILI9341_VMCTR2 0xC7 #define ILI9341_GMCTRP1 0xE0 #define ILI9341_GMCTRN1 0xE1 #define ILI9341_MADCTL_MY 0x80 #define ILI9341_MADCTL_MX 0x40 #define ILI9341_MADCTL_MV 0x20 #define ILI9341_MADCTL_ML 0x10 #define ILI9341_MADCTL_RGB 0x00 #define ILI9341_MADCTL_BGR 0x08 #define ILI9341_MADCTL_MH 0x04 #include #include "soc/spi_reg.h" #include "soc/rtc.h" #include "driver/spi_master.h" #include "hal/gpio_ll.h" #define SET_BUS_WRITE_MODE *_spi_user = SPI_USR_MOSI #define SET_BUS_READ_MODE *_spi_user = SPI_USR_MOSI | SPI_USR_MISO | SPI_DOUTDIN #define SPI_BUSY_CHECK while (*_spi_cmd&SPI_USR) #define FS_NO_GLOBALS #include #include "SPIFFS.h" #define DC_C GPIO.out_w1tc = (1 << TFT_DC)//;GPIO.out_w1tc = (1 << TFT_DC) #define DC_D GPIO.out_w1ts = (1 << TFT_DC)//;GPIO.out_w1ts = (1 << TFT_DC) #define CS_L GPIO.out_w1tc = (1 << TFT_CS); GPIO.out_w1tc = (1 << TFT_CS) #define CS_H GPIO.out_w1ts = (1 << TFT_CS)//;GPIO.out_w1ts = (1 << TFT_CS) #define WR_L #define WR_H #define TFT_MISO 19 #define TFT_MOSI 23 #define TFT_SCLK 18 #define TFT_CS 5 #define TFT_DC 17 #define TFT_RST 16 #define TOUCH_CS 32 #define TFT_WRITE_BITS(D, B) *_spi_mosi_dlen = B-1; \ *_spi_w = D; \ *_spi_cmd = SPI_USR; \ while (*_spi_cmd & SPI_USR); // Write 8 bits #define tft_Write_8(C) TFT_WRITE_BITS(C, 8) // Write 16 bits with corrected endianness for 16-bit colours #define tft_Write_16(C) TFT_WRITE_BITS((C)<<8 | (C)>>8, 16) // Future option for transfer without wait #define tft_Write_16N(C) *_spi_mosi_dlen = 16-1; \ *_spi_w = ((C)<<8 | (C)>>8); \ *_spi_cmd = SPI_USR; // Write 16 bits #define tft_Write_16S(C) TFT_WRITE_BITS(C, 16) // Write 32 bits #define tft_Write_32(C) TFT_WRITE_BITS(C, 32) // Write two address coordinates #define tft_Write_32C(C,D) TFT_WRITE_BITS((uint16_t)((D)<<8 | (D)>>8)<<16 | (uint16_t)((C)<<8 | (C)>>8), 32) // Write same value twice #define tft_Write_32D(C) TFT_WRITE_BITS((uint16_t)((C)<<8 | (C)>>8)<<16 | (uint16_t)((C)<<8 | (C)>>8), 32) #define tft_Read_8() spi_transfer(0) #define DAT8TO32(P) ( (uint32_t)P[0]<<8 | P[1] | P[2]<<24 | P[3]<<16 ) //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 /*************************************************************************************** ** Section 6: Colour enumeration ***************************************************************************************/ // Default color definitions #define TFT_BLACK 0x0000 /* 0, 0, 0 */ #define TFT_NAVY 0x000F /* 0, 0, 128 */ #define TFT_DARKGREEN 0x03E0 /* 0, 128, 0 */ #define TFT_DARKCYAN 0x03EF /* 0, 128, 128 */ #define TFT_MAROON 0x7800 /* 128, 0, 0 */ #define TFT_PURPLE 0x780F /* 128, 0, 128 */ #define TFT_OLIVE 0x7BE0 /* 128, 128, 0 */ #define TFT_LIGHTGREY 0xD69A /* 211, 211, 211 */ #define TFT_DARKGREY 0x7BEF /* 128, 128, 128 */ #define TFT_BLUE 0x001F /* 0, 0, 255 */ #define TFT_GREEN 0x07E0 /* 0, 255, 0 */ #define TFT_CYAN 0x07FF /* 0, 255, 255 */ #define TFT_RED 0xF800 /* 255, 0, 0 */ #define TFT_MAGENTA 0xF81F /* 255, 0, 255 */ #define TFT_YELLOW 0xFFE0 /* 255, 255, 0 */ #define TFT_WHITE 0xFFFF /* 255, 255, 255 */ #define TFT_ORANGE 0xFDA0 /* 255, 180, 0 */ #define TFT_GREENYELLOW 0xB7E0 /* 180, 255, 0 */ #define TFT_PINK 0xFE19 /* 255, 192, 203 */ //Lighter pink, was 0xFC9F #define TFT_BROWN 0x9A60 /* 150, 75, 0 */ #define TFT_GOLD 0xFEA0 /* 255, 215, 0 */ #define TFT_SILVER 0xC618 /* 192, 192, 192 */ #define TFT_SKYBLUE 0x867D /* 135, 206, 235 */ #define TFT_VIOLET 0x915C /* 180, 46, 226 */ // Next is a special 16-bit colour value that encodes to 8 bits // and will then decode back to the same 16-bit value. // Convenient for 8-bit and 16-bit transparent sprites. #define TFT_TRANSPARENT 0x0120 // This is actually a dark green class TFT_eSPI { friend class TFT_eSprite; public: void setSPISpeed(uint8_t speed_Mhz); TFT_eSPI(int16_t _W = TFT_WIDTH, int16_t _H = TFT_HEIGHT); void init(); virtual void drawPixel(int32_t x, int32_t y, uint32_t color), drawLine(int32_t xs, int32_t ys, int32_t xe, int32_t ye, uint32_t color), drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color), drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color), fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color); virtual int16_t height(), width(); virtual void setWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye); virtual void pushColor(uint16_t color); virtual void begin_nin_write(); virtual void end_nin_write(); void setRotation(uint8_t r); void invertDisplay(bool i); void setAddrWindow(int32_t xs, int32_t ys, int32_t w, int32_t h); void setViewport(int32_t x, int32_t y, int32_t w, int32_t h, bool vpDatum = true); void resetViewport(); void pushColor(uint16_t color, uint32_t len); void pushBlock(uint16_t color, uint32_t len); void pushPixels(const void * data_in, uint32_t len); void fillScreen(uint32_t color), drawRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color), drawRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t radius, uint32_t color), fillRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t radius, uint32_t color); void drawCircleHelper(int32_t x, int32_t y, int32_t r, uint8_t cornername, uint32_t color), fillCircle(int32_t x, int32_t y, int32_t r, uint32_t color), fillCircleHelper(int32_t x, int32_t y, int32_t r, uint8_t cornername, int32_t delta, uint32_t color), fillTriangle(int32_t x1,int32_t y1, int32_t x2,int32_t y2, int32_t x3,int32_t y3, uint32_t color); uint16_t drawPixel(int32_t x, int32_t y, uint32_t color, uint8_t alpha, uint32_t bg_color = 0x00FFFFFF); void setSwapBytes(bool swap); bool getSwapBytes(); void drawBitmap( int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t fgcolor), drawBitmap( int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t fgcolor, uint16_t bgcolor); void pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data); void pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *data, uint16_t transparent); void pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t *data, uint16_t transparent); void pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint16_t *data); void pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint8_t *data, bool bpp8 = true, uint16_t *cmap = nullptr); void pushImage(int32_t x, int32_t y, int32_t w, int32_t h, uint8_t *data, uint8_t transparent, bool bpp8 = true, uint16_t *cmap = nullptr); void pushImage(int32_t x, int32_t y, int32_t w, int32_t h, const uint8_t *data, bool bpp8, uint16_t *cmap = nullptr); // Text rendering - value returned is the pixel width of the rendered text int16_t drawNumber(long intNumber, int32_t x, int32_t y, uint8_t font), // Draw integer using specified font number drawNumber(long intNumber, int32_t x, int32_t y), // Draw integer using current font // Decimal is the number of decimal places to render // Use with setTextDatum() to position values on TFT, and setTextPadding() to blank old displayed values drawFloat(float floatNumber, uint8_t decimal, int32_t x, int32_t y, uint8_t font), // Draw float using specified font number drawFloat(float floatNumber, uint8_t decimal, int32_t x, int32_t y), // Draw float using current font // Handle char arrays // Use with setTextDatum() to position string on TFT, and setTextPadding() to blank old displayed strings drawString(const char *string, int32_t x, int32_t y, uint8_t font), // Draw string using specified font number drawString(const char *string, int32_t x, int32_t y), // Draw string using current font drawString(const String& string, int32_t x, int32_t y, uint8_t font),// Draw string using specified font number drawString(const String& string, int32_t x, int32_t y); // Draw string using current font // Text rendering and font handling support functions void setCursor(int16_t x, int16_t y), setCursor(int16_t x, int16_t y, uint8_t font); void setTextColor(uint16_t color), // Set character (glyph) color only (background not over-written) setTextColor(uint16_t fgcolor, uint16_t bgcolor, bool bgfill = false); // Set character (glyph) foreground and background colour, optional background fill for smooth fonts void setTextDatum(uint8_t datum); // Set text datum position (default is top left), see Section 5 above void setTextPadding(uint16_t x_width); // Set text padding (background blanking) width in pixels void setTextFont(uint8_t font); // Set the font number to use in future int16_t textWidth(const char *string, uint8_t font), // Returns pixel width of string in specified font textWidth(const char *string), // Returns pixel width of string in current font textWidth(const String& string, uint8_t font), // As above for String types textWidth(const String& string), fontHeight(uint8_t font), // Returns pixel height of specified font fontHeight(); // Returns pixel height of current font // Used by library and Smooth font class to extract Unicode point codes from a UTF8 encoded string uint16_t decodeUTF8(uint8_t *buf, uint16_t *index, uint16_t remaining), decodeUTF8(uint8_t c); void writecommand(uint8_t c); // Send an 8-bit command, function resets DC/RS high ready for data void writedata(uint8_t d); // Send data with DC/RS set high // Colour conversion // Convert 8-bit red, green and blue to 16 bits uint16_t color565(uint8_t red, uint8_t green, uint8_t blue); // Alpha blend 2 colours, see generic "alphaBlend_Test" example // alpha = 0 = 100% background colour // alpha = 255 = 100% foreground colour uint16_t alphaBlend(uint8_t alpha, uint16_t fgc, uint16_t bgc); // 16-bit colour alphaBlend with alpha dither (dither reduces colour banding) uint16_t alphaBlend(uint8_t alpha, uint16_t fgc, uint16_t bgc, uint8_t dither); void writeColor(uint16_t color, uint32_t len); // Deprecated, use pushBlock() // Global variables uint32_t textcolor, textbgcolor; // Text foreground and background colours uint32_t bitmap_fg, bitmap_bg; // Bitmap foreground (bit=1) and background (bit=0) colours uint8_t textfont, // Current selected font number textdatum, // Text reference datum rotation; // Display rotation (0-3) uint8_t decoderState = 0; // UTF8 decoder state - not for user access uint16_t decoderBuffer; // Unicode code-point buffer - not for user access void loadFont(const uint8_t array[], uint8_t font); void unloadFont(uint8_t font); bool getUnicodeIndex(uint16_t unicode, uint16_t *index, uint16_t font); virtual void drawGlyph(uint16_t code, uint16_t font); bool booted; typedef struct { const uint8_t* gArray; //array start pointer uint16_t gCount; // Total number of characters uint16_t yAdvance; // Line advance uint16_t spaceWidth; // Width of a space character int16_t ascent; // Height of top of 'd' above baseline, other characters may be taller int16_t descent; // Offset to bottom of 'p', other characters may have a larger descent uint16_t maxAscent; // Maximum ascent found in font uint16_t maxDescent; // Maximum descent found in font } fontMetrics; fontMetrics gFonts[FONT_COUNT] = { { nullptr, 0, 0, 0, 0, 0, 0, 0 } }; // These are for the metrics for each individual glyph (so we don't need to seek this in file and waste time) uint16_t* gUnicode[FONT_COUNT] = {NULL}; //UTF-16 code, the codes are searched so do not need to be sequential uint8_t* gHeight[FONT_COUNT] = {NULL}; //cheight uint8_t* gWidth[FONT_COUNT] = {NULL}; //cwidth uint8_t* gxAdvance[FONT_COUNT] = {NULL}; //setWidth int16_t* gdY[FONT_COUNT] = {NULL}; //topExtent int8_t* gdX[FONT_COUNT] = {NULL}; //leftExtent uint32_t* gBitmap[FONT_COUNT] = {NULL}; //file pointer to greyscale bitmap bool fontOwned[FONT_COUNT] = {false}; uint8_t getTouchRaw(uint16_t *x, uint16_t *y); uint16_t getTouchRawZ(); void convertRawXY(uint16_t *x, uint16_t *y); uint8_t getTouch(uint16_t *x, uint16_t *y, uint16_t threshold = 600); void calibrateTouch(uint16_t *data, uint32_t color_fg, uint32_t color_bg, uint8_t size); void setTouch(uint16_t *data); void begin_tft_write(); void end_tft_write(); void begin_tft_read(); void end_tft_read(); private: void initBus(); void pushSwapBytePixels(const void* data_in, uint32_t len); void readAddrWindow(int32_t xs, int32_t ys, int32_t w, int32_t h); void loadMetrics(uint8_t font); uint32_t readInt32(); uint8_t* fontPtr = nullptr; //-------------------------------------- protected ----------------------------------// protected: uint8_t spi_write_speed; int32_t _init_width, _init_height; // Display w/h as input, used by setRotation() int32_t _width, _height; // Display w/h as modified by current rotation int32_t addr_row, addr_col; // Window position - used to minimise window commands // Viewport variables int32_t _vpX, _vpY, _vpW, _vpH; // Note: x start, y start, x end + 1, y end + 1 int32_t _xDatum; int32_t _yDatum; int32_t _xWidth; int32_t _yHeight; bool _vpDatum; bool _vpOoB; int32_t cursor_x, cursor_y, padX; int32_t bg_cursor_x; int32_t last_cursor_x; bool isDigits; bool textwrapX, textwrapY; bool _swapBytes; uint32_t _lastColor; bool _fillbg; private: inline void begin_touch_read_write() __attribute__((always_inline)); inline void end_touch_read_write() __attribute__((always_inline)); uint8_t validTouch(uint16_t *x, uint16_t *y, uint16_t threshold = 600); uint16_t touchCalibration_x0 = 300, touchCalibration_x1 = 3600, touchCalibration_y0 = 300, touchCalibration_y1 = 3600; uint8_t touchCalibration_rotate = 1, touchCalibration_invert_x = 2, touchCalibration_invert_y = 0; uint32_t _pressTime; }; class TFT_eSprite : public TFT_eSPI { public: explicit TFT_eSprite(TFT_eSPI *tft); ~TFT_eSprite(); void* createSprite(int16_t width = TFT_WIDTH, int16_t height = TFT_HEIGHT); void* getPointer(); bool created(); void deleteSprite(); void drawPixel(int32_t x, int32_t y, uint32_t color); void fillSprite(uint32_t color), setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1), pushColor(uint16_t color), pushColor(uint16_t color, uint32_t len), writeColor(uint16_t color), drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t color), drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color), drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color), fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color); void pushImage(int32_t x0, int32_t y0, int32_t w, int32_t h, uint16_t *data, uint8_t sbpp = 0); void pushImage(int32_t x0, int32_t y0, int32_t w, int32_t h, const uint16_t *data); void pushSprite(int32_t x, int32_t y); void pushSprite(int32_t x, int32_t y, uint16_t transparent); bool pushSprite(int32_t tx, int32_t ty, int32_t sx, int32_t sy, int32_t sw, int32_t sh); bool pushToSprite(TFT_eSprite *dspr, int32_t x, int32_t y); bool pushToSprite(TFT_eSprite *dspr, int32_t x, int32_t y, uint16_t transparent); int16_t width(), height(); void drawGlyph(uint16_t code, uint16_t font); void copyFontFromTFT(uint8_t source, uint8_t destination); void copyAllFontsFromTFT(); private: TFT_eSPI *_tft; void* callocSprite(int16_t width, int16_t height); protected: uint16_t *_img; // pointer to 16-bit sprite int32_t _sinra; // Sine of rotation angle in fixed point int32_t _cosra; // Cosine of rotation angle in fixed point bool _created; int32_t _xs, _ys, _xe, _ye, _xptr, _yptr; int32_t _sx, _sy; uint32_t _sw, _sh; uint32_t _scolor; int32_t _iwidth, _iheight; // Sprite memory image bit width and height (swapped during rotations) int32_t _dwidth, _dheight; // Real sprite width and height }; template static inline void transpose(T& a, T& b) { T t = a; a = b; b = t; } template static inline uint16_t fastBlend(A alpha, F fgc, B bgc) { // Split out and blend 5-bit red and blue channels uint32_t rxb = bgc & 0xF81F; rxb += ((fgc & 0xF81F) - rxb) * (alpha >> 2) >> 6; // Split out and blend 6-bit green channel uint32_t xgx = bgc & 0x07E0; xgx += ((fgc & 0x07E0) - xgx) * alpha >> 8; // Recombine channels return (rxb & 0xF81F) | (xgx & 0x07E0); }