2017-02-22 03:07:17 +00:00
|
|
|
/***************************************************
|
2018-02-22 22:33:49 +00:00
|
|
|
Arduino TFT graphics library targeted at ESP8266
|
2018-01-08 23:19:42 +00:00
|
|
|
and ESP32 based boards.
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
This is a standalone library that contains the
|
2018-02-22 22:33:49 +00:00
|
|
|
hardware driver, the graphics functions and the
|
2017-02-22 03:07:17 +00:00
|
|
|
proportional fonts.
|
|
|
|
|
|
|
|
The larger fonts are Run Length Encoded to reduce their
|
|
|
|
size.
|
|
|
|
|
|
|
|
Created by Bodmer 2/12/16
|
2017-03-24 23:23:35 +00:00
|
|
|
Bodmer: Added RPi 16 bit display support
|
2017-02-22 03:07:17 +00:00
|
|
|
****************************************************/
|
|
|
|
|
|
|
|
#include "TFT_eSPI.h"
|
|
|
|
|
|
|
|
#include <pgmspace.h>
|
|
|
|
|
2018-03-10 23:08:57 +00:00
|
|
|
#ifndef ESP32_PARALLEL
|
|
|
|
#include <SPI.h>
|
|
|
|
#endif
|
2017-02-22 03:07:17 +00:00
|
|
|
|
2018-02-22 22:33:49 +00:00
|
|
|
// SUPPORT_TRANSACTIONS is mandatory for ESP32 so the hal mutex is toggled
|
2017-10-20 17:05:21 +00:00
|
|
|
#if defined (ESP32) && !defined (SUPPORT_TRANSACTIONS)
|
|
|
|
#define SUPPORT_TRANSACTIONS
|
|
|
|
#endif
|
|
|
|
|
2017-03-24 23:23:35 +00:00
|
|
|
// If it is a 16bit serial display we must transfer 16 bits every time
|
|
|
|
#ifdef RPI_ILI9486_DRIVER
|
|
|
|
#define CMD_BITS 16-1
|
|
|
|
#else
|
|
|
|
#define CMD_BITS 8-1
|
|
|
|
#endif
|
|
|
|
|
2018-03-10 23:08:57 +00:00
|
|
|
// Fast block write prototype
|
|
|
|
void writeBlock(uint16_t color, uint32_t repeat);
|
|
|
|
|
|
|
|
// Byte read prototype
|
|
|
|
uint8_t readByte(void);
|
|
|
|
|
|
|
|
// GPIO parallel input/output control
|
|
|
|
void busDir(uint32_t mask, uint8_t mode);
|
2017-04-23 17:50:53 +00:00
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
// If the SPI library has transaction support, these functions
|
|
|
|
// establish settings and protect from interference from other
|
|
|
|
// libraries. Otherwise, they simply do nothing.
|
|
|
|
|
|
|
|
inline void TFT_eSPI::spi_begin(void){
|
2018-03-10 23:08:57 +00:00
|
|
|
#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(ESP32_PARALLEL)
|
2018-07-06 17:48:24 +00:00
|
|
|
if (locked) {locked = false; SPI.beginTransaction(SPISettings(SPI_FREQUENCY, MSBFIRST, TFT_SPI_MODE));}
|
2017-02-22 03:07:17 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void TFT_eSPI::spi_end(void){
|
2018-03-10 23:08:57 +00:00
|
|
|
#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(ESP32_PARALLEL)
|
2017-05-20 00:37:58 +00:00
|
|
|
if(!inTransaction) {if (!locked) {locked = true; SPI.endTransaction();}}
|
2017-02-22 03:07:17 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2018-03-10 23:08:57 +00:00
|
|
|
#if defined (TOUCH_CS) && defined (SPI_TOUCH_FREQUENCY) // && !defined(ESP32_PARALLEL)
|
2018-02-24 19:02:20 +00:00
|
|
|
|
|
|
|
inline void TFT_eSPI::spi_begin_touch(void){
|
|
|
|
#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS)
|
|
|
|
if (locked) {locked = false; SPI.beginTransaction(SPISettings(SPI_TOUCH_FREQUENCY, MSBFIRST, SPI_MODE0));}
|
|
|
|
#else
|
|
|
|
SPI.setFrequency(SPI_TOUCH_FREQUENCY);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void TFT_eSPI::spi_end_touch(void){
|
|
|
|
#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS)
|
|
|
|
if(!inTransaction) {if (!locked) {locked = true; SPI.endTransaction();}}
|
|
|
|
#else
|
|
|
|
SPI.setFrequency(SPI_FREQUENCY);
|
|
|
|
#endif
|
|
|
|
}
|
2017-11-04 19:11:50 +00:00
|
|
|
|
|
|
|
#endif
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: TFT_eSPI
|
|
|
|
** Description: Constructor , we must use hardware SPI pins
|
|
|
|
***************************************************************************************/
|
|
|
|
TFT_eSPI::TFT_eSPI(int16_t w, int16_t h)
|
|
|
|
{
|
|
|
|
|
|
|
|
// The control pins are deliberately set to the inactive state (CS high) as setup()
|
2017-03-28 22:56:54 +00:00
|
|
|
// might call and initialise other SPI peripherals which would could cause conflicts
|
2017-02-22 03:07:17 +00:00
|
|
|
// if CS is floating or undefined.
|
|
|
|
#ifdef TFT_CS
|
|
|
|
digitalWrite(TFT_CS, HIGH); // Chip select high (inactive)
|
|
|
|
pinMode(TFT_CS, OUTPUT);
|
|
|
|
#endif
|
|
|
|
|
2017-09-30 22:32:30 +00:00
|
|
|
// Configure chip select for touchscreen controller if present
|
|
|
|
#ifdef TOUCH_CS
|
|
|
|
digitalWrite(TOUCH_CS, HIGH); // Chip select high (inactive)
|
|
|
|
pinMode(TOUCH_CS, OUTPUT);
|
|
|
|
#endif
|
|
|
|
|
2017-03-27 01:15:30 +00:00
|
|
|
#ifdef TFT_WR
|
2017-03-28 22:56:54 +00:00
|
|
|
digitalWrite(TFT_WR, HIGH); // Set write strobe high (inactive)
|
2017-03-27 01:15:30 +00:00
|
|
|
pinMode(TFT_WR, OUTPUT);
|
|
|
|
#endif
|
2017-02-22 03:07:17 +00:00
|
|
|
|
2017-03-28 22:56:54 +00:00
|
|
|
#ifdef TFT_DC
|
2017-02-22 03:07:17 +00:00
|
|
|
digitalWrite(TFT_DC, HIGH); // Data/Command high = data mode
|
|
|
|
pinMode(TFT_DC, OUTPUT);
|
2017-03-28 22:56:54 +00:00
|
|
|
#endif
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
#ifdef TFT_RST
|
|
|
|
if (TFT_RST >= 0) {
|
|
|
|
digitalWrite(TFT_RST, HIGH); // Set high, do not share pin with another SPI device
|
|
|
|
pinMode(TFT_RST, OUTPUT);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-03-10 23:08:57 +00:00
|
|
|
#ifdef ESP32_PARALLEL
|
|
|
|
|
|
|
|
// Create a bit set lookup table for data bus - wastes 1kbyte of RAM but speeds things up dramatically
|
|
|
|
for (int c = 0; c<256; c++)
|
|
|
|
{
|
|
|
|
xset_mask[c] = 0;
|
|
|
|
if ( c & 0x01 ) xset_mask[c] |= (1 << TFT_D0);
|
|
|
|
if ( c & 0x02 ) xset_mask[c] |= (1 << TFT_D1);
|
|
|
|
if ( c & 0x04 ) xset_mask[c] |= (1 << TFT_D2);
|
|
|
|
if ( c & 0x08 ) xset_mask[c] |= (1 << TFT_D3);
|
|
|
|
if ( c & 0x10 ) xset_mask[c] |= (1 << TFT_D4);
|
|
|
|
if ( c & 0x20 ) xset_mask[c] |= (1 << TFT_D5);
|
|
|
|
if ( c & 0x40 ) xset_mask[c] |= (1 << TFT_D6);
|
|
|
|
if ( c & 0x80 ) xset_mask[c] |= (1 << TFT_D7);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure read is high before we set the bus to output
|
|
|
|
digitalWrite(TFT_RD, HIGH);
|
|
|
|
pinMode(TFT_RD, OUTPUT);
|
|
|
|
|
|
|
|
GPIO.out_w1ts = set_mask(255); // Set data bus to 0xFF
|
|
|
|
|
|
|
|
// Set TFT data bus lines to output
|
|
|
|
busDir(dir_mask, OUTPUT);
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2018-02-24 19:02:20 +00:00
|
|
|
_init_width = _width = w; // Set by specific xxxxx_Defines.h file or by users sketch
|
|
|
|
_init_height = _height = h; // Set by specific xxxxx_Defines.h file or by users sketch
|
2017-02-22 03:07:17 +00:00
|
|
|
rotation = 0;
|
2018-03-26 00:02:23 +00:00
|
|
|
cursor_y = cursor_x = 0;
|
2017-02-22 03:07:17 +00:00
|
|
|
textfont = 1;
|
|
|
|
textsize = 1;
|
2018-03-26 00:02:23 +00:00
|
|
|
textcolor = bitmap_fg = 0xFFFF; // White
|
|
|
|
textbgcolor = bitmap_bg = 0x0000; // Black
|
2017-02-22 03:07:17 +00:00
|
|
|
padX = 0; // No padding
|
2018-02-24 19:02:20 +00:00
|
|
|
textwrapX = true; // Wrap text at end of line when using print stream
|
|
|
|
textwrapY = false; // Wrap text at bottom of screen when using print stream
|
2017-02-22 03:07:17 +00:00
|
|
|
textdatum = TL_DATUM; // Top Left text alignment is default
|
|
|
|
fontsloaded = 0;
|
|
|
|
|
2018-01-08 23:19:42 +00:00
|
|
|
_swapBytes = false; // Do not swap colour bytes by default
|
|
|
|
|
2017-05-20 00:37:58 +00:00
|
|
|
locked = true; // ESP32 transaction mutex lock flags
|
|
|
|
inTransaction = false;
|
|
|
|
|
2018-07-06 17:48:24 +00:00
|
|
|
_booted = true;
|
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
addr_row = 0xFFFF;
|
|
|
|
addr_col = 0xFFFF;
|
|
|
|
|
|
|
|
#ifdef LOAD_GLCD
|
2017-04-14 00:04:04 +00:00
|
|
|
fontsloaded = 0x0002; // Bit 1 set
|
2017-02-22 03:07:17 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef LOAD_FONT2
|
|
|
|
fontsloaded |= 0x0004; // Bit 2 set
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef LOAD_FONT4
|
|
|
|
fontsloaded |= 0x0010; // Bit 4 set
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef LOAD_FONT6
|
|
|
|
fontsloaded |= 0x0040; // Bit 6 set
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef LOAD_FONT7
|
|
|
|
fontsloaded |= 0x0080; // Bit 7 set
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef LOAD_FONT8
|
|
|
|
fontsloaded |= 0x0100; // Bit 8 set
|
|
|
|
#endif
|
|
|
|
|
2018-04-11 00:03:26 +00:00
|
|
|
#ifdef LOAD_FONT8N
|
|
|
|
fontsloaded |= 0x0200; // Bit 9 set
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef SMOOTH_FONT
|
|
|
|
fontsloaded |= 0x8000; // Bit 15 set
|
|
|
|
#endif
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: begin
|
|
|
|
** Description: Included for backwards compatibility
|
|
|
|
***************************************************************************************/
|
2018-05-25 21:48:15 +00:00
|
|
|
void TFT_eSPI::begin(uint8_t tc)
|
2017-02-22 03:07:17 +00:00
|
|
|
{
|
2018-05-25 21:48:15 +00:00
|
|
|
init(tc);
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
2018-07-06 17:48:24 +00:00
|
|
|
** Function name: init (tc is tab colour for ST7735 displays only)
|
2017-02-22 03:07:17 +00:00
|
|
|
** Description: Reset, then initialise the TFT display registers
|
|
|
|
***************************************************************************************/
|
2018-05-25 21:48:15 +00:00
|
|
|
void TFT_eSPI::init(uint8_t tc)
|
2017-02-22 03:07:17 +00:00
|
|
|
{
|
2018-07-06 17:48:24 +00:00
|
|
|
if (_booted)
|
|
|
|
{
|
2017-05-20 00:37:58 +00:00
|
|
|
#if !defined (ESP32)
|
|
|
|
#ifdef TFT_CS
|
|
|
|
cspinmask = (uint32_t) digitalPinToBitMask(TFT_CS);
|
|
|
|
#endif
|
2017-03-28 22:56:54 +00:00
|
|
|
|
2017-05-20 00:37:58 +00:00
|
|
|
#ifdef TFT_DC
|
|
|
|
dcpinmask = (uint32_t) digitalPinToBitMask(TFT_DC);
|
|
|
|
#endif
|
2017-03-28 22:56:54 +00:00
|
|
|
|
2017-05-20 00:37:58 +00:00
|
|
|
#ifdef TFT_WR
|
|
|
|
wrpinmask = (uint32_t) digitalPinToBitMask(TFT_WR);
|
|
|
|
#endif
|
2017-07-15 17:44:49 +00:00
|
|
|
|
|
|
|
#ifdef TFT_SPI_OVERLAP
|
|
|
|
// Overlap mode SD0=MISO, SD1=MOSI, CLK=SCLK must use D3 as CS
|
|
|
|
// pins(int8_t sck, int8_t miso, int8_t mosi, int8_t ss);
|
|
|
|
//SPI.pins( 6, 7, 8, 0);
|
|
|
|
SPI.pins(6, 7, 8, 0);
|
|
|
|
#endif
|
2017-03-27 01:15:30 +00:00
|
|
|
|
2018-07-06 17:48:24 +00:00
|
|
|
SPI.begin(); // This will set HMISO to input
|
2017-05-20 00:37:58 +00:00
|
|
|
#else
|
2018-03-10 23:08:57 +00:00
|
|
|
#if !defined(ESP32_PARALLEL)
|
|
|
|
#if defined (TFT_MOSI) && !defined (TFT_SPI_OVERLAP)
|
|
|
|
SPI.begin(TFT_SCLK, TFT_MISO, TFT_MOSI, -1);
|
|
|
|
#else
|
|
|
|
SPI.begin();
|
|
|
|
#endif
|
2017-03-24 23:23:35 +00:00
|
|
|
#endif
|
2017-05-20 00:37:58 +00:00
|
|
|
#endif
|
|
|
|
|
2018-07-06 17:48:24 +00:00
|
|
|
inTransaction = false;
|
|
|
|
locked = true;
|
2017-05-20 00:37:58 +00:00
|
|
|
|
2018-03-10 23:08:57 +00:00
|
|
|
// SUPPORT_TRANSACTIONS is mandatory for ESP32 so the hal mutex is toggled
|
2017-10-20 17:05:21 +00:00
|
|
|
// so the code here is for ESP8266 only
|
|
|
|
#if !defined (SUPPORT_TRANSACTIONS) && defined (ESP8266)
|
2018-07-06 17:48:24 +00:00
|
|
|
SPI.setBitOrder(MSBFIRST);
|
|
|
|
SPI.setDataMode(TFT_SPI_MODE);
|
|
|
|
SPI.setFrequency(SPI_FREQUENCY);
|
2017-02-22 03:07:17 +00:00
|
|
|
#endif
|
|
|
|
|
2018-03-10 23:08:57 +00:00
|
|
|
#if defined(ESP32_PARALLEL)
|
|
|
|
digitalWrite(TFT_CS, LOW); // Chip select low permanently
|
|
|
|
pinMode(TFT_CS, OUTPUT);
|
2017-07-15 17:44:49 +00:00
|
|
|
#else
|
2018-03-10 23:08:57 +00:00
|
|
|
#ifdef TFT_CS
|
|
|
|
// Set to output once again in case D6 (MISO) is used for CS
|
|
|
|
digitalWrite(TFT_CS, HIGH); // Chip select high (inactive)
|
|
|
|
pinMode(TFT_CS, OUTPUT);
|
|
|
|
#else
|
|
|
|
SPI.setHwCs(1); // Use hardware SS toggling
|
|
|
|
#endif
|
2017-03-12 03:31:51 +00:00
|
|
|
#endif
|
2018-03-10 23:08:57 +00:00
|
|
|
|
2017-03-28 22:56:54 +00:00
|
|
|
// Set to output once again in case D6 (MISO) is used for DC
|
|
|
|
#ifdef TFT_DC
|
2018-07-06 17:48:24 +00:00
|
|
|
digitalWrite(TFT_DC, HIGH); // Data/Command high = data mode
|
|
|
|
pinMode(TFT_DC, OUTPUT);
|
2017-03-28 22:56:54 +00:00
|
|
|
#endif
|
2017-03-11 16:38:29 +00:00
|
|
|
|
2018-07-06 17:48:24 +00:00
|
|
|
_booted = false;
|
|
|
|
} // end of: if just _booted
|
|
|
|
|
2017-03-28 22:56:54 +00:00
|
|
|
// Toggle RST low to reset
|
2018-07-06 17:48:24 +00:00
|
|
|
spi_begin();
|
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
#ifdef TFT_RST
|
|
|
|
if (TFT_RST >= 0) {
|
|
|
|
digitalWrite(TFT_RST, HIGH);
|
|
|
|
delay(5);
|
|
|
|
digitalWrite(TFT_RST, LOW);
|
|
|
|
delay(20);
|
|
|
|
digitalWrite(TFT_RST, HIGH);
|
|
|
|
}
|
2018-07-06 17:48:24 +00:00
|
|
|
else writecommand(TFT_SWRST); // Software reset
|
|
|
|
#else
|
|
|
|
writecommand(TFT_SWRST); // Software reset
|
2018-02-24 19:02:20 +00:00
|
|
|
#endif
|
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
spi_end();
|
2018-07-06 17:48:24 +00:00
|
|
|
delay(150); // Wait for reset to complete
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
spi_begin();
|
|
|
|
|
|
|
|
// This loads the driver specific initialisation code <<<<<<<<<<<<<<<<<<<<< ADD NEW DRIVERS TO THE LIST HERE <<<<<<<<<<<<<<<<<<<<<<<
|
|
|
|
#if defined (ILI9341_DRIVER)
|
2017-04-14 00:04:04 +00:00
|
|
|
#include "TFT_Drivers/ILI9341_Init.h"
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
#elif defined (ST7735_DRIVER)
|
2018-05-25 21:48:15 +00:00
|
|
|
tabcolor = tc;
|
2017-04-14 00:04:04 +00:00
|
|
|
#include "TFT_Drivers/ST7735_Init.h"
|
2017-02-22 03:07:17 +00:00
|
|
|
|
2017-02-26 03:03:41 +00:00
|
|
|
#elif defined (ILI9163_DRIVER)
|
2017-04-14 00:04:04 +00:00
|
|
|
#include "TFT_Drivers/ILI9163_Init.h"
|
2017-02-26 03:03:41 +00:00
|
|
|
|
|
|
|
#elif defined (S6D02A1_DRIVER)
|
2017-04-14 00:04:04 +00:00
|
|
|
#include "TFT_Drivers/S6D02A1_Init.h"
|
|
|
|
|
2017-03-24 23:23:35 +00:00
|
|
|
#elif defined (RPI_ILI9486_DRIVER)
|
2018-07-06 17:48:24 +00:00
|
|
|
#include "TFT_Drivers/ILI9486_Init.h"
|
2017-04-14 00:04:04 +00:00
|
|
|
|
2018-05-25 21:48:15 +00:00
|
|
|
#elif defined (ILI9486_DRIVER)
|
|
|
|
#include "TFT_Drivers/ILI9486_Init.h"
|
|
|
|
|
2018-03-10 23:08:57 +00:00
|
|
|
#elif defined (ILI9481_DRIVER)
|
|
|
|
#include "TFT_Drivers/ILI9481_Init.h"
|
|
|
|
|
|
|
|
#elif defined (ILI9488_DRIVER)
|
|
|
|
#include "TFT_Drivers/ILI9488_Init.h"
|
|
|
|
|
|
|
|
#elif defined (HX8357D_DRIVER)
|
|
|
|
#include "TFT_Drivers/HX8357D_Init.h"
|
|
|
|
|
2018-06-01 17:26:09 +00:00
|
|
|
#elif defined (ST7789_DRIVER)
|
|
|
|
#include "TFT_Drivers/ST7789_Init.h"
|
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
spi_end();
|
|
|
|
|
2018-07-06 17:48:24 +00:00
|
|
|
setRotation(rotation);
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: setRotation
|
|
|
|
** Description: rotate the screen orientation m = 0-3 or 4-7 for BMP drawing
|
|
|
|
***************************************************************************************/
|
|
|
|
void TFT_eSPI::setRotation(uint8_t m)
|
|
|
|
{
|
|
|
|
|
|
|
|
spi_begin();
|
|
|
|
|
|
|
|
// This loads the driver specific rotation code <<<<<<<<<<<<<<<<<<<<< ADD NEW DRIVERS TO THE LIST HERE <<<<<<<<<<<<<<<<<<<<<<<
|
|
|
|
#if defined (ILI9341_DRIVER)
|
2017-04-14 00:04:04 +00:00
|
|
|
#include "TFT_Drivers/ILI9341_Rotation.h"
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
#elif defined (ST7735_DRIVER)
|
2017-04-14 00:04:04 +00:00
|
|
|
#include "TFT_Drivers/ST7735_Rotation.h"
|
2017-02-26 03:03:41 +00:00
|
|
|
|
|
|
|
#elif defined (ILI9163_DRIVER)
|
2017-04-14 00:04:04 +00:00
|
|
|
#include "TFT_Drivers/ILI9163_Rotation.h"
|
2017-02-26 03:03:41 +00:00
|
|
|
|
|
|
|
#elif defined (S6D02A1_DRIVER)
|
2017-04-14 00:04:04 +00:00
|
|
|
#include "TFT_Drivers/S6D02A1_Rotation.h"
|
2017-02-26 03:03:41 +00:00
|
|
|
|
2017-03-24 23:23:35 +00:00
|
|
|
#elif defined (RPI_ILI9486_DRIVER)
|
2018-07-06 17:48:24 +00:00
|
|
|
#include "TFT_Drivers/ILI9486_Rotation.h"
|
2017-03-24 23:23:35 +00:00
|
|
|
|
2018-05-25 21:48:15 +00:00
|
|
|
#elif defined (ILI9486_DRIVER)
|
|
|
|
#include "TFT_Drivers/ILI9486_Rotation.h"
|
|
|
|
|
2018-03-10 23:08:57 +00:00
|
|
|
#elif defined (ILI9481_DRIVER)
|
|
|
|
#include "TFT_Drivers/ILI9481_Rotation.h"
|
|
|
|
|
|
|
|
#elif defined (ILI9488_DRIVER)
|
|
|
|
#include "TFT_Drivers/ILI9488_Rotation.h"
|
|
|
|
|
|
|
|
#elif defined (HX8357D_DRIVER)
|
|
|
|
#include "TFT_Drivers/HX8357D_Rotation.h"
|
|
|
|
|
2018-06-01 17:26:09 +00:00
|
|
|
#elif defined (ST7789_DRIVER)
|
|
|
|
#include "TFT_Drivers/ST7789_Rotation.h"
|
|
|
|
|
2017-04-14 00:04:04 +00:00
|
|
|
#endif
|
2017-02-22 03:07:17 +00:00
|
|
|
|
2017-05-20 00:37:58 +00:00
|
|
|
delayMicroseconds(10);
|
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
spi_end();
|
|
|
|
|
|
|
|
addr_row = 0xFFFF;
|
|
|
|
addr_col = 0xFFFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: commandList, used for FLASH based lists only (e.g. ST7735)
|
|
|
|
** Description: Get initialisation commands from FLASH and send to TFT
|
|
|
|
***************************************************************************************/
|
|
|
|
void TFT_eSPI::commandList (const uint8_t *addr)
|
|
|
|
{
|
|
|
|
uint8_t numCommands;
|
|
|
|
uint8_t numArgs;
|
|
|
|
uint8_t ms;
|
|
|
|
|
|
|
|
spi_begin();
|
|
|
|
|
|
|
|
numCommands = pgm_read_byte(addr++); // Number of commands to follow
|
|
|
|
|
|
|
|
while (numCommands--) // For each command...
|
|
|
|
{
|
|
|
|
writecommand(pgm_read_byte(addr++)); // Read, issue command
|
|
|
|
numArgs = pgm_read_byte(addr++); // Number of args to follow
|
|
|
|
ms = numArgs & TFT_INIT_DELAY; // If hibit set, delay follows args
|
|
|
|
numArgs &= ~TFT_INIT_DELAY; // Mask out delay bit
|
|
|
|
|
|
|
|
while (numArgs--) // For each argument...
|
|
|
|
{
|
|
|
|
writedata(pgm_read_byte(addr++)); // Read, issue argument
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ms)
|
|
|
|
{
|
|
|
|
ms = pgm_read_byte(addr++); // Read post-command delay time (ms)
|
|
|
|
delay( (ms==255 ? 500 : ms) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
spi_end();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: spiwrite
|
|
|
|
** Description: Write 8 bits to SPI port (legacy support only)
|
|
|
|
***************************************************************************************/
|
|
|
|
void TFT_eSPI::spiwrite(uint8_t c)
|
|
|
|
{
|
2018-03-12 22:49:18 +00:00
|
|
|
tft_Write_8(c);
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: writecommand
|
|
|
|
** Description: Send an 8 bit command to the TFT
|
|
|
|
***************************************************************************************/
|
|
|
|
void TFT_eSPI::writecommand(uint8_t c)
|
|
|
|
{
|
|
|
|
DC_C;
|
|
|
|
CS_L;
|
2018-03-10 23:08:57 +00:00
|
|
|
|
2018-03-12 22:49:18 +00:00
|
|
|
tft_Write_8(c);
|
2018-03-10 23:08:57 +00:00
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
CS_H;
|
|
|
|
DC_D;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: writedata
|
|
|
|
** Description: Send a 8 bit data value to the TFT
|
|
|
|
***************************************************************************************/
|
2018-03-10 23:08:57 +00:00
|
|
|
void TFT_eSPI::writedata(uint8_t d)
|
2017-02-22 03:07:17 +00:00
|
|
|
{
|
|
|
|
CS_L;
|
2018-03-10 23:08:57 +00:00
|
|
|
|
2018-03-12 22:49:18 +00:00
|
|
|
tft_Write_8(d);
|
2018-03-10 23:08:57 +00:00
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
CS_H;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
2018-03-10 23:08:57 +00:00
|
|
|
** Function name: readcommand8
|
2017-02-22 03:07:17 +00:00
|
|
|
** Description: Read a 8 bit data value from an indexed command register
|
|
|
|
***************************************************************************************/
|
2017-12-03 02:29:39 +00:00
|
|
|
uint8_t TFT_eSPI::readcommand8(uint8_t cmd_function, uint8_t index)
|
2017-02-22 03:07:17 +00:00
|
|
|
{
|
2018-03-10 23:08:57 +00:00
|
|
|
uint8_t reg = 0;
|
|
|
|
#ifdef ESP32_PARALLEL
|
|
|
|
|
|
|
|
writecommand(cmd_function); // Sets DC and CS high
|
|
|
|
|
|
|
|
busDir(dir_mask, INPUT);
|
|
|
|
|
|
|
|
CS_L;
|
|
|
|
|
|
|
|
// Read nth parameter (assumes caller discards 1st parameter or points index to 2nd)
|
|
|
|
while(index--) reg = readByte();
|
|
|
|
|
|
|
|
busDir(dir_mask, OUTPUT);
|
|
|
|
|
|
|
|
CS_H;
|
|
|
|
|
|
|
|
#else
|
|
|
|
// for ILI9341 Interface II i.e. IM [3:0] = "1101"
|
2017-02-22 03:07:17 +00:00
|
|
|
spi_begin();
|
|
|
|
index = 0x10 + (index & 0x0F);
|
|
|
|
|
|
|
|
DC_C;
|
|
|
|
CS_L;
|
2018-03-12 22:49:18 +00:00
|
|
|
tft_Write_8(0xD9);
|
2017-02-22 03:07:17 +00:00
|
|
|
DC_D;
|
2018-03-12 22:49:18 +00:00
|
|
|
tft_Write_8(index);
|
2017-02-22 03:07:17 +00:00
|
|
|
CS_H;
|
|
|
|
|
|
|
|
DC_C;
|
|
|
|
CS_L;
|
2018-03-12 22:49:18 +00:00
|
|
|
tft_Write_8(cmd_function);
|
2017-02-22 03:07:17 +00:00
|
|
|
DC_D;
|
2018-03-12 22:49:18 +00:00
|
|
|
reg = tft_Write_8(0);
|
2017-02-22 03:07:17 +00:00
|
|
|
CS_H;
|
|
|
|
|
|
|
|
spi_end();
|
2018-03-10 23:08:57 +00:00
|
|
|
#endif
|
2017-02-22 03:07:17 +00:00
|
|
|
return reg;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
2018-03-10 23:08:57 +00:00
|
|
|
** Function name: readcommand16
|
2017-02-22 03:07:17 +00:00
|
|
|
** Description: Read a 16 bit data value from an indexed command register
|
|
|
|
***************************************************************************************/
|
2017-12-03 02:29:39 +00:00
|
|
|
uint16_t TFT_eSPI::readcommand16(uint8_t cmd_function, uint8_t index)
|
2017-02-22 03:07:17 +00:00
|
|
|
{
|
2018-03-10 23:08:57 +00:00
|
|
|
uint32_t reg;
|
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
reg |= (readcommand8(cmd_function, index + 0) << 8);
|
|
|
|
reg |= (readcommand8(cmd_function, index + 1) << 0);
|
|
|
|
|
|
|
|
return reg;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
2018-03-10 23:08:57 +00:00
|
|
|
** Function name: readcommand32
|
2017-02-22 03:07:17 +00:00
|
|
|
** Description: Read a 32 bit data value from an indexed command register
|
|
|
|
***************************************************************************************/
|
2017-12-03 02:29:39 +00:00
|
|
|
uint32_t TFT_eSPI::readcommand32(uint8_t cmd_function, uint8_t index)
|
2017-02-22 03:07:17 +00:00
|
|
|
{
|
|
|
|
uint32_t reg;
|
|
|
|
|
|
|
|
reg = (readcommand8(cmd_function, index + 0) << 24);
|
|
|
|
reg |= (readcommand8(cmd_function, index + 1) << 16);
|
|
|
|
reg |= (readcommand8(cmd_function, index + 2) << 8);
|
|
|
|
reg |= (readcommand8(cmd_function, index + 3) << 0);
|
|
|
|
|
|
|
|
return reg;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: read pixel (for SPI Interface II i.e. IM [3:0] = "1101")
|
|
|
|
** Description: Read 565 pixel colours from a pixel
|
|
|
|
***************************************************************************************/
|
|
|
|
uint16_t TFT_eSPI::readPixel(int32_t x0, int32_t y0)
|
|
|
|
{
|
2018-03-10 23:08:57 +00:00
|
|
|
#if defined(ESP32_PARALLEL)
|
|
|
|
|
|
|
|
readAddrWindow(x0, y0, x0, y0); // Sets CS low
|
|
|
|
|
|
|
|
// Set masked pins D0- D7 to input
|
|
|
|
busDir(dir_mask, INPUT);
|
|
|
|
|
|
|
|
// Dummy read to throw away don't care value
|
|
|
|
readByte();
|
|
|
|
|
|
|
|
// Fetch the 16 bit BRG pixel
|
|
|
|
//uint16_t rgb = (readByte() << 8) | readByte();
|
|
|
|
|
2018-07-06 17:48:24 +00:00
|
|
|
#if defined (ILI9341_DRIVER) | defined (ILI9488_DRIVER) // Read 3 bytes
|
2018-03-10 23:08:57 +00:00
|
|
|
|
|
|
|
// Read window pixel 24 bit RGB values and fill in LS bits
|
|
|
|
uint16_t rgb = ((readByte() & 0xF8) << 8) | ((readByte() & 0xFC) << 3) | (readByte() >> 3);
|
|
|
|
|
|
|
|
CS_H;
|
|
|
|
|
|
|
|
// Set masked pins D0- D7 to output
|
|
|
|
busDir(dir_mask, OUTPUT);
|
|
|
|
|
|
|
|
return rgb;
|
|
|
|
|
2018-07-06 17:48:24 +00:00
|
|
|
#else // ILI9481 16 bit read
|
2018-03-10 23:08:57 +00:00
|
|
|
|
|
|
|
// Fetch the 16 bit BRG pixel
|
|
|
|
uint16_t bgr = (readByte() << 8) | readByte();
|
|
|
|
|
|
|
|
CS_H;
|
|
|
|
|
|
|
|
// Set masked pins D0- D7 to output
|
|
|
|
busDir(dir_mask, OUTPUT);
|
|
|
|
|
|
|
|
// Swap Red and Blue (could check MADCTL setting to see if this is needed)
|
|
|
|
return (bgr>>11) | (bgr<<11) | (bgr & 0x7E0);
|
2018-07-06 17:48:24 +00:00
|
|
|
#endif
|
2018-03-10 23:08:57 +00:00
|
|
|
|
|
|
|
#else // Not ESP32_PARALLEL
|
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
spi_begin();
|
|
|
|
|
2017-03-11 16:59:34 +00:00
|
|
|
readAddrWindow(x0, y0, x0, y0); // Sets CS low
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
// Dummy read to throw away don't care value
|
2018-03-12 22:49:18 +00:00
|
|
|
tft_Write_8(0);
|
2017-04-14 00:04:04 +00:00
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
// Read window pixel 24 bit RGB values
|
2018-03-12 22:49:18 +00:00
|
|
|
uint8_t r = tft_Write_8(0);
|
|
|
|
uint8_t g = tft_Write_8(0);
|
|
|
|
uint8_t b = tft_Write_8(0);
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
CS_H;
|
|
|
|
|
|
|
|
spi_end();
|
2017-04-14 00:04:04 +00:00
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
return color565(r, g, b);
|
2018-03-10 23:08:57 +00:00
|
|
|
|
|
|
|
#endif
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-03-10 23:08:57 +00:00
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: read byte - supports class functions
|
|
|
|
** Description: Read a byte from ESP32 8 bit data port
|
|
|
|
***************************************************************************************/
|
|
|
|
// Bus MUST be set to input before calling this function!
|
|
|
|
uint8_t readByte(void)
|
|
|
|
{
|
|
|
|
uint8_t b = 0;
|
|
|
|
|
|
|
|
#ifdef ESP32_PARALLEL
|
|
|
|
RD_L;
|
|
|
|
uint32_t reg; // Read all GPIO pins 0-31
|
|
|
|
reg = gpio_input_get(); // Read three times to allow for bus access time
|
|
|
|
reg = gpio_input_get();
|
|
|
|
reg = gpio_input_get(); // Data should be stable now
|
|
|
|
RD_H;
|
|
|
|
|
|
|
|
// Check GPIO bits used and build value
|
|
|
|
b = (((reg>>TFT_D0)&1) << 0);
|
|
|
|
b |= (((reg>>TFT_D1)&1) << 1);
|
|
|
|
b |= (((reg>>TFT_D2)&1) << 2);
|
|
|
|
b |= (((reg>>TFT_D3)&1) << 3);
|
|
|
|
b |= (((reg>>TFT_D4)&1) << 4);
|
|
|
|
b |= (((reg>>TFT_D5)&1) << 5);
|
|
|
|
b |= (((reg>>TFT_D6)&1) << 6);
|
|
|
|
b |= (((reg>>TFT_D7)&1) << 7);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return b;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: masked GPIO direction control - supports class functions
|
|
|
|
** Description: Set masked ESP32 GPIO pins to input or output
|
|
|
|
***************************************************************************************/
|
|
|
|
void busDir(uint32_t mask, uint8_t mode)
|
|
|
|
{
|
|
|
|
#ifdef ESP32_PARALLEL
|
|
|
|
|
|
|
|
// Supports GPIO 0 - 31 on ESP32 only
|
|
|
|
gpio_config_t gpio;
|
|
|
|
|
|
|
|
gpio.pin_bit_mask = mask;
|
|
|
|
gpio.mode = GPIO_MODE_INPUT;
|
|
|
|
gpio.pull_up_en = GPIO_PULLUP_ENABLE;
|
|
|
|
gpio.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
|
|
|
gpio.intr_type = GPIO_INTR_DISABLE;
|
|
|
|
|
|
|
|
if (mode == OUTPUT) gpio.mode = GPIO_MODE_OUTPUT;
|
|
|
|
|
|
|
|
gpio_config(&gpio);
|
|
|
|
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: read rectangle (for SPI Interface II i.e. IM [3:0] = "1101")
|
|
|
|
** Description: Read 565 pixel colours from a defined area
|
|
|
|
***************************************************************************************/
|
2017-12-03 02:29:39 +00:00
|
|
|
void TFT_eSPI::readRect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint16_t *data)
|
2017-02-22 03:07:17 +00:00
|
|
|
{
|
|
|
|
if ((x > _width) || (y > _height) || (w == 0) || (h == 0)) return;
|
2018-03-10 23:08:57 +00:00
|
|
|
|
|
|
|
#if defined(ESP32_PARALLEL)
|
|
|
|
|
|
|
|
readAddrWindow(x, y, x + w - 1, y + h - 1); // Sets CS low
|
|
|
|
|
|
|
|
// Set masked pins D0- D7 to input
|
|
|
|
busDir(dir_mask, INPUT);
|
|
|
|
|
|
|
|
// Dummy read to throw away don't care value
|
|
|
|
readByte();
|
|
|
|
|
|
|
|
// Total pixel count
|
|
|
|
uint32_t len = w * h;
|
|
|
|
|
|
|
|
#if defined (ILI9341_DRIVER) | defined (ILI9488_DRIVER) // Read 3 bytes
|
|
|
|
// Fetch the 24 bit RGB value
|
|
|
|
while (len--) {
|
|
|
|
// Assemble the RGB 16 bit colour
|
|
|
|
uint16_t rgb = ((readByte() & 0xF8) << 8) | ((readByte() & 0xFC) << 3) | (readByte() >> 3);
|
|
|
|
|
|
|
|
// Swapped byte order for compatibility with pushRect()
|
|
|
|
*data++ = (rgb<<8) | (rgb>>8);
|
|
|
|
}
|
|
|
|
#else // ILI9481 reads as 16 bits
|
|
|
|
// Fetch the 16 bit BRG pixels
|
|
|
|
while (len--) {
|
|
|
|
// Read the BRG 16 bit colour
|
|
|
|
uint16_t bgr = (readByte() << 8) | readByte();
|
|
|
|
|
|
|
|
// Swap Red and Blue (could check MADCTL setting to see if this is needed)
|
|
|
|
uint16_t rgb = (bgr>>11) | (bgr<<11) | (bgr & 0x7E0);
|
|
|
|
|
|
|
|
// Swapped byte order for compatibility with pushRect()
|
|
|
|
*data++ = (rgb<<8) | (rgb>>8);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
CS_H;
|
|
|
|
|
|
|
|
// Set masked pins D0- D7 to output
|
|
|
|
busDir(dir_mask, OUTPUT);
|
|
|
|
|
|
|
|
#else // Not ESP32_PARALLEL
|
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
spi_begin();
|
|
|
|
|
2017-03-11 16:59:34 +00:00
|
|
|
readAddrWindow(x, y, x + w - 1, y + h - 1); // Sets CS low
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
// Dummy read to throw away don't care value
|
2018-03-12 22:49:18 +00:00
|
|
|
tft_Write_8(0);
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
// Read window pixel 24 bit RGB values
|
|
|
|
uint32_t len = w * h;
|
|
|
|
while (len--) {
|
|
|
|
// Read the 3 RGB bytes, colour is actually only in the top 6 bits of each byte
|
2017-04-14 00:04:04 +00:00
|
|
|
// as the TFT stores colours as 18 bits
|
2018-03-12 22:49:18 +00:00
|
|
|
uint8_t r = tft_Write_8(0);
|
|
|
|
uint8_t g = tft_Write_8(0);
|
|
|
|
uint8_t b = tft_Write_8(0);
|
2018-03-10 23:08:57 +00:00
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
// Swapped colour byte order for compatibility with pushRect()
|
|
|
|
*data++ = (r & 0xF8) | (g & 0xE0) >> 5 | (b & 0xF8) << 5 | (g & 0x1C) << 11;
|
|
|
|
}
|
|
|
|
|
|
|
|
CS_H;
|
|
|
|
|
|
|
|
spi_end();
|
2018-03-10 23:08:57 +00:00
|
|
|
#endif
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: push rectangle (for SPI Interface II i.e. IM [3:0] = "1101")
|
|
|
|
** Description: push 565 pixel colours into a defined area
|
|
|
|
***************************************************************************************/
|
2017-12-03 02:29:39 +00:00
|
|
|
void TFT_eSPI::pushRect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint16_t *data)
|
2017-02-22 03:07:17 +00:00
|
|
|
{
|
2018-01-08 23:19:42 +00:00
|
|
|
// Function deprecated, remains for backwards compatibility
|
|
|
|
// pushImage() is better as it will crop partly off-screen image blocks
|
|
|
|
pushImage(x, y, w, h, data);
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-11-15 20:26:22 +00:00
|
|
|
/***************************************************************************************
|
2017-12-10 23:04:31 +00:00
|
|
|
** Function name: pushImage
|
|
|
|
** Description: plot 16 bit colour sprite or image onto TFT
|
2017-11-15 20:26:22 +00:00
|
|
|
***************************************************************************************/
|
2017-12-10 23:04:31 +00:00
|
|
|
void TFT_eSPI::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, uint16_t *data)
|
2017-11-15 20:26:22 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
if ((x >= (int32_t)_width) || (y >= (int32_t)_height)) return;
|
|
|
|
|
|
|
|
int32_t dx = 0;
|
|
|
|
int32_t dy = 0;
|
|
|
|
int32_t dw = w;
|
|
|
|
int32_t dh = h;
|
|
|
|
|
|
|
|
if (x < 0) { dw += x; dx = -x; x = 0; }
|
|
|
|
if (y < 0) { dh += y; dy = -y; y = 0; }
|
2018-01-08 23:19:42 +00:00
|
|
|
|
2017-11-29 00:38:05 +00:00
|
|
|
if ((x + w) > _width ) dw = _width - x;
|
|
|
|
if ((y + h) > _height) dh = _height - y;
|
2017-11-15 20:26:22 +00:00
|
|
|
|
2017-11-24 14:12:29 +00:00
|
|
|
if (dw < 1 || dh < 1) return;
|
2017-11-15 20:26:22 +00:00
|
|
|
|
|
|
|
spi_begin();
|
2018-01-08 23:19:42 +00:00
|
|
|
inTransaction = true;
|
2017-11-15 20:26:22 +00:00
|
|
|
|
|
|
|
setAddrWindow(x, y, x + dw - 1, y + dh - 1); // Sets CS low and sent RAMWR
|
|
|
|
|
|
|
|
data += dx + dy * w;
|
|
|
|
|
|
|
|
while (dh--)
|
|
|
|
{
|
2018-01-08 23:19:42 +00:00
|
|
|
pushColors(data, dw, _swapBytes);
|
2017-11-15 20:26:22 +00:00
|
|
|
data += w;
|
2017-11-21 22:57:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CS_H;
|
|
|
|
|
2018-01-08 23:19:42 +00:00
|
|
|
inTransaction = false;
|
2017-11-21 22:57:11 +00:00
|
|
|
spi_end();
|
|
|
|
}
|
|
|
|
|
2017-12-03 02:29:39 +00:00
|
|
|
/***************************************************************************************
|
2017-12-10 23:04:31 +00:00
|
|
|
** Function name: pushImage
|
|
|
|
** Description: plot 16 bit sprite or image with 1 colour being transparent
|
2017-12-03 02:29:39 +00:00
|
|
|
***************************************************************************************/
|
2017-12-10 23:04:31 +00:00
|
|
|
void TFT_eSPI::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, uint16_t *data, uint16_t transp)
|
2017-12-03 02:29:39 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
if ((x >= (int32_t)_width) || (y >= (int32_t)_height)) return;
|
|
|
|
|
|
|
|
int32_t dx = 0;
|
|
|
|
int32_t dy = 0;
|
|
|
|
int32_t dw = w;
|
|
|
|
int32_t dh = h;
|
|
|
|
|
|
|
|
if (x < 0) { dw += x; dx = -x; x = 0; }
|
|
|
|
if (y < 0) { dh += y; dy = -y; y = 0; }
|
|
|
|
|
|
|
|
if ((x + w) > _width ) dw = _width - x;
|
|
|
|
if ((y + h) > _height) dh = _height - y;
|
|
|
|
|
|
|
|
if (dw < 1 || dh < 1) return;
|
|
|
|
|
|
|
|
spi_begin();
|
2018-01-08 23:19:42 +00:00
|
|
|
inTransaction = true;
|
2017-12-03 02:29:39 +00:00
|
|
|
|
|
|
|
data += dx + dy * w;
|
|
|
|
|
|
|
|
int32_t xe = x + dw - 1, ye = y + dh - 1;
|
2017-12-03 02:55:43 +00:00
|
|
|
|
2018-01-08 23:19:42 +00:00
|
|
|
uint16_t lineBuf[dw];
|
|
|
|
|
|
|
|
if (!_swapBytes) transp = transp >> 8 | transp << 8;
|
|
|
|
|
2017-12-03 02:29:39 +00:00
|
|
|
while (dh--)
|
|
|
|
{
|
|
|
|
int32_t len = dw;
|
|
|
|
uint16_t* ptr = data;
|
|
|
|
int32_t px = x;
|
|
|
|
boolean move = true;
|
2018-01-08 23:19:42 +00:00
|
|
|
uint16_t np = 0;
|
|
|
|
|
2017-12-03 02:29:39 +00:00
|
|
|
while (len--)
|
|
|
|
{
|
|
|
|
if (transp != *ptr)
|
|
|
|
{
|
|
|
|
if (move) { move = false; setAddrWindow(px, y, xe, ye); }
|
2018-01-08 23:19:42 +00:00
|
|
|
lineBuf[np] = *ptr;
|
|
|
|
np++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
move = true;
|
|
|
|
if (np)
|
|
|
|
{
|
|
|
|
pushColors((uint16_t*)lineBuf, np, _swapBytes);
|
|
|
|
np = 0;
|
|
|
|
}
|
2017-12-03 02:29:39 +00:00
|
|
|
}
|
|
|
|
px++;
|
|
|
|
ptr++;
|
|
|
|
}
|
2018-01-08 23:19:42 +00:00
|
|
|
if (np) pushColors((uint16_t*)lineBuf, np, _swapBytes);
|
2017-12-03 02:29:39 +00:00
|
|
|
|
|
|
|
y++;
|
|
|
|
data += w;
|
|
|
|
}
|
|
|
|
|
|
|
|
CS_H;
|
|
|
|
|
2018-01-08 23:19:42 +00:00
|
|
|
inTransaction = false;
|
2017-12-03 02:29:39 +00:00
|
|
|
spi_end();
|
|
|
|
}
|
|
|
|
|
2018-01-08 23:19:42 +00:00
|
|
|
|
2017-12-10 23:04:31 +00:00
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: pushImage - for FLASH (PROGMEM) stored images
|
2018-01-08 23:19:42 +00:00
|
|
|
** Description: plot 16 bit image
|
|
|
|
***************************************************************************************/
|
|
|
|
void TFT_eSPI::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, const uint16_t *data)
|
|
|
|
{
|
|
|
|
|
|
|
|
if ((x >= (int32_t)_width) || (y >= (int32_t)_height)) return;
|
|
|
|
|
|
|
|
int32_t dx = 0;
|
|
|
|
int32_t dy = 0;
|
|
|
|
int32_t dw = w;
|
|
|
|
int32_t dh = h;
|
|
|
|
|
|
|
|
if (x < 0) { dw += x; dx = -x; x = 0; }
|
|
|
|
if (y < 0) { dh += y; dy = -y; y = 0; }
|
|
|
|
|
|
|
|
if ((x + w) > _width ) dw = _width - x;
|
|
|
|
if ((y + h) > _height) dh = _height - y;
|
|
|
|
|
|
|
|
if (dw < 1 || dh < 1) return;
|
|
|
|
|
|
|
|
spi_begin();
|
|
|
|
inTransaction = true;
|
|
|
|
|
|
|
|
data += dx + dy * w;
|
|
|
|
|
|
|
|
uint16_t buffer[64];
|
|
|
|
uint16_t* pix_buffer = buffer;
|
|
|
|
|
|
|
|
setAddrWindow(x, y, x + dw - 1, y + dh - 1);
|
|
|
|
|
|
|
|
// Work out the number whole buffers to send
|
|
|
|
uint16_t nb = (dw * dh) / 64;
|
|
|
|
|
|
|
|
// Fill and send "nb" buffers to TFT
|
|
|
|
for (int i = 0; i < nb; i++) {
|
|
|
|
for (int j = 0; j < 64; j++) {
|
|
|
|
pix_buffer[j] = pgm_read_word(&data[i * 64 + j]);
|
|
|
|
}
|
|
|
|
pushColors(pix_buffer, 64, !_swapBytes);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Work out number of pixels not yet sent
|
|
|
|
uint16_t np = (dw * dh) % 64;
|
|
|
|
|
|
|
|
// Send any partial buffer left over
|
|
|
|
if (np) {
|
|
|
|
for (int i = 0; i < np; i++)
|
|
|
|
{
|
|
|
|
pix_buffer[i] = pgm_read_word(&data[nb * 64 + i]);
|
|
|
|
}
|
|
|
|
pushColors(pix_buffer, np, !_swapBytes);
|
|
|
|
}
|
|
|
|
|
|
|
|
CS_H;
|
|
|
|
|
|
|
|
inTransaction = false;
|
|
|
|
spi_end();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: pushImage - for FLASH (PROGMEM) stored images
|
|
|
|
** Description: plot 16 bit image with 1 colour being transparent
|
2017-12-10 23:04:31 +00:00
|
|
|
***************************************************************************************/
|
2018-01-08 23:19:42 +00:00
|
|
|
void TFT_eSPI::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, const uint16_t *data, uint16_t transp)
|
2017-12-10 23:04:31 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
if ((x >= (int32_t)_width) || (y >= (int32_t)_height)) return;
|
|
|
|
|
|
|
|
int32_t dx = 0;
|
|
|
|
int32_t dy = 0;
|
|
|
|
int32_t dw = w;
|
|
|
|
int32_t dh = h;
|
|
|
|
|
|
|
|
if (x < 0) { dw += x; dx = -x; x = 0; }
|
|
|
|
if (y < 0) { dh += y; dy = -y; y = 0; }
|
|
|
|
|
|
|
|
if ((x + w) > _width ) dw = _width - x;
|
|
|
|
if ((y + h) > _height) dh = _height - y;
|
|
|
|
|
|
|
|
if (dw < 1 || dh < 1) return;
|
|
|
|
|
|
|
|
spi_begin();
|
2018-01-08 23:19:42 +00:00
|
|
|
inTransaction = true;
|
2017-12-10 23:04:31 +00:00
|
|
|
|
|
|
|
data += dx + dy * w;
|
|
|
|
|
|
|
|
int32_t xe = x + dw - 1, ye = y + dh - 1;
|
|
|
|
|
2018-01-08 23:19:42 +00:00
|
|
|
uint16_t lineBuf[dw];
|
|
|
|
|
|
|
|
if (_swapBytes) transp = transp >> 8 | transp << 8;
|
2017-12-10 23:04:31 +00:00
|
|
|
|
|
|
|
while (dh--)
|
|
|
|
{
|
|
|
|
int32_t len = dw;
|
|
|
|
uint16_t* ptr = (uint16_t*)data;
|
|
|
|
int32_t px = x;
|
|
|
|
boolean move = true;
|
2018-01-08 23:19:42 +00:00
|
|
|
|
|
|
|
uint16_t np = 0;
|
|
|
|
|
2017-12-10 23:04:31 +00:00
|
|
|
while (len--)
|
|
|
|
{
|
|
|
|
uint16_t color = pgm_read_word(ptr);
|
|
|
|
if (transp != color)
|
|
|
|
{
|
|
|
|
if (move) { move = false; setAddrWindow(px, y, xe, ye); }
|
2018-01-08 23:19:42 +00:00
|
|
|
lineBuf[np] = color;
|
|
|
|
np++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
move = true;
|
|
|
|
if (np)
|
|
|
|
{
|
|
|
|
pushColors(lineBuf, np, !_swapBytes);
|
|
|
|
np = 0;
|
|
|
|
}
|
2017-12-10 23:04:31 +00:00
|
|
|
}
|
|
|
|
px++;
|
|
|
|
ptr++;
|
|
|
|
}
|
2018-01-08 23:19:42 +00:00
|
|
|
if (np) pushColors(lineBuf, np, !_swapBytes);
|
2017-12-10 23:04:31 +00:00
|
|
|
|
|
|
|
y++;
|
|
|
|
data += w;
|
|
|
|
}
|
|
|
|
|
|
|
|
CS_H;
|
|
|
|
|
2018-01-08 23:19:42 +00:00
|
|
|
inTransaction = false;
|
2017-12-10 23:04:31 +00:00
|
|
|
spi_end();
|
|
|
|
}
|
|
|
|
|
2017-11-24 14:12:29 +00:00
|
|
|
|
|
|
|
/***************************************************************************************
|
2017-12-10 23:04:31 +00:00
|
|
|
** Function name: pushImage
|
|
|
|
** Description: plot 8 bit image or sprite using a line buffer
|
2017-11-24 14:12:29 +00:00
|
|
|
***************************************************************************************/
|
2018-03-26 00:02:23 +00:00
|
|
|
void TFT_eSPI::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, uint8_t *data, bool bpp8)
|
2017-11-21 22:57:11 +00:00
|
|
|
{
|
|
|
|
if ((x >= (int32_t)_width) || (y >= (int32_t)_height)) return;
|
|
|
|
|
|
|
|
int32_t dx = 0;
|
|
|
|
int32_t dy = 0;
|
|
|
|
int32_t dw = w;
|
|
|
|
int32_t dh = h;
|
|
|
|
|
|
|
|
if (x < 0) { dw += x; dx = -x; x = 0; }
|
|
|
|
if (y < 0) { dh += y; dy = -y; y = 0; }
|
|
|
|
|
2017-11-29 00:38:05 +00:00
|
|
|
if ((x + w) > _width ) dw = _width - x;
|
|
|
|
if ((y + h) > _height) dh = _height - y;
|
2017-11-21 22:57:11 +00:00
|
|
|
|
2017-11-24 14:12:29 +00:00
|
|
|
if (dw < 1 || dh < 1) return;
|
2017-11-21 22:57:11 +00:00
|
|
|
|
|
|
|
spi_begin();
|
2018-01-08 23:19:42 +00:00
|
|
|
inTransaction = true;
|
2017-11-21 22:57:11 +00:00
|
|
|
|
|
|
|
setAddrWindow(x, y, x + dw - 1, y + dh - 1); // Sets CS low and sent RAMWR
|
|
|
|
|
2018-01-08 23:19:42 +00:00
|
|
|
// Line buffer makes plotting faster
|
|
|
|
uint16_t lineBuf[dw];
|
2017-11-24 14:12:29 +00:00
|
|
|
|
2018-03-26 00:02:23 +00:00
|
|
|
if (bpp8)
|
|
|
|
{
|
|
|
|
uint8_t blue[] = {0, 11, 21, 31}; // blue 2 to 5 bit colour lookup table
|
2017-11-24 14:12:29 +00:00
|
|
|
|
2018-03-26 00:02:23 +00:00
|
|
|
_lastColor = -1; // Set to illegal value
|
2017-11-21 22:57:11 +00:00
|
|
|
|
2018-03-26 00:02:23 +00:00
|
|
|
// Used to store last shifted colour
|
|
|
|
uint8_t msbColor = 0;
|
|
|
|
uint8_t lsbColor = 0;
|
2017-11-21 22:57:11 +00:00
|
|
|
|
2018-03-26 00:02:23 +00:00
|
|
|
data += dx + dy * w;
|
|
|
|
while (dh--)
|
2017-11-21 22:57:11 +00:00
|
|
|
{
|
2018-03-26 00:02:23 +00:00
|
|
|
uint32_t len = dw;
|
|
|
|
uint8_t* ptr = data;
|
|
|
|
uint8_t* linePtr = (uint8_t*)lineBuf;
|
|
|
|
|
|
|
|
while(len--)
|
|
|
|
{
|
|
|
|
uint32_t color = *ptr++;
|
|
|
|
|
|
|
|
// Shifts are slow so check if colour has changed first
|
|
|
|
if (color != _lastColor) {
|
|
|
|
// =====Green===== ===============Red==============
|
|
|
|
msbColor = (color & 0x1C)>>2 | (color & 0xC0)>>3 | (color & 0xE0);
|
|
|
|
// =====Green===== =======Blue======
|
|
|
|
lsbColor = (color & 0x1C)<<3 | blue[color & 0x03];
|
|
|
|
_lastColor = color;
|
|
|
|
}
|
|
|
|
|
|
|
|
*linePtr++ = msbColor;
|
|
|
|
*linePtr++ = lsbColor;
|
2017-11-24 14:12:29 +00:00
|
|
|
}
|
2018-01-08 23:19:42 +00:00
|
|
|
|
2018-03-26 00:02:23 +00:00
|
|
|
pushColors(lineBuf, dw, false);
|
|
|
|
|
|
|
|
data += w;
|
2017-11-24 14:12:29 +00:00
|
|
|
}
|
2018-03-26 00:02:23 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
while (dh--)
|
|
|
|
{
|
|
|
|
w = (w+7) & 0xFFF8;
|
|
|
|
|
|
|
|
int32_t len = dw;
|
|
|
|
uint8_t* ptr = data;
|
|
|
|
uint8_t* linePtr = (uint8_t*)lineBuf;
|
|
|
|
uint8_t bits = 8;
|
|
|
|
while(len>0)
|
|
|
|
{
|
|
|
|
if (len < 8) bits = len;
|
|
|
|
uint32_t xp = dx;
|
|
|
|
for (uint16_t i = 0; i < bits; i++)
|
|
|
|
{
|
|
|
|
uint8_t col = (ptr[(xp + dy * w)>>3] << (xp & 0x7)) & 0x80;
|
|
|
|
if (col) {*linePtr++ = bitmap_fg>>8; *linePtr++ = (uint8_t) bitmap_fg;}
|
|
|
|
else {*linePtr++ = bitmap_bg>>8; *linePtr++ = (uint8_t) bitmap_bg;}
|
|
|
|
//if (col) drawPixel((dw-len)+xp,h-dh,bitmap_fg);
|
|
|
|
//else drawPixel((dw-len)+xp,h-dh,bitmap_bg);
|
|
|
|
xp++;
|
|
|
|
}
|
|
|
|
*ptr++;
|
|
|
|
len -= 8;
|
|
|
|
}
|
2017-11-21 22:57:11 +00:00
|
|
|
|
2018-03-26 00:02:23 +00:00
|
|
|
pushColors(lineBuf, dw, false);
|
2017-11-21 22:57:11 +00:00
|
|
|
|
2018-03-26 00:02:23 +00:00
|
|
|
dy++;
|
|
|
|
}
|
2017-11-21 22:57:11 +00:00
|
|
|
}
|
2017-11-15 20:26:22 +00:00
|
|
|
|
|
|
|
CS_H;
|
|
|
|
|
2018-01-08 23:19:42 +00:00
|
|
|
inTransaction = false;
|
2017-11-15 20:26:22 +00:00
|
|
|
spi_end();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-12-03 02:29:39 +00:00
|
|
|
/***************************************************************************************
|
2017-12-10 23:04:31 +00:00
|
|
|
** Function name: pushImage
|
2018-03-26 00:02:23 +00:00
|
|
|
** Description: plot 8 or 1 bit image or sprite with a transparent colour
|
2017-12-03 02:29:39 +00:00
|
|
|
***************************************************************************************/
|
2018-03-26 00:02:23 +00:00
|
|
|
void TFT_eSPI::pushImage(int32_t x, int32_t y, uint32_t w, uint32_t h, uint8_t *data, uint8_t transp, bool bpp8)
|
2017-12-03 02:29:39 +00:00
|
|
|
{
|
|
|
|
if ((x >= (int32_t)_width) || (y >= (int32_t)_height)) return;
|
|
|
|
|
|
|
|
int32_t dx = 0;
|
|
|
|
int32_t dy = 0;
|
|
|
|
int32_t dw = w;
|
|
|
|
int32_t dh = h;
|
|
|
|
|
|
|
|
if (x < 0) { dw += x; dx = -x; x = 0; }
|
|
|
|
if (y < 0) { dh += y; dy = -y; y = 0; }
|
|
|
|
|
|
|
|
if ((x + w) > _width ) dw = _width - x;
|
|
|
|
if ((y + h) > _height) dh = _height - y;
|
|
|
|
|
|
|
|
if (dw < 1 || dh < 1) return;
|
|
|
|
|
|
|
|
spi_begin();
|
2018-01-08 23:19:42 +00:00
|
|
|
inTransaction = true;
|
2017-12-03 02:29:39 +00:00
|
|
|
|
|
|
|
int32_t xe = x + dw - 1, ye = y + dh - 1;
|
|
|
|
|
2018-01-08 23:19:42 +00:00
|
|
|
// Line buffer makes plotting faster
|
|
|
|
uint16_t lineBuf[dw];
|
|
|
|
|
2018-03-26 00:02:23 +00:00
|
|
|
if (bpp8)
|
|
|
|
{
|
|
|
|
data += dx + dy * w;
|
2017-12-03 02:29:39 +00:00
|
|
|
|
2018-03-26 00:02:23 +00:00
|
|
|
uint8_t blue[] = {0, 11, 21, 31}; // blue 2 to 5 bit colour lookup table
|
2018-01-08 23:19:42 +00:00
|
|
|
|
2018-03-26 00:02:23 +00:00
|
|
|
_lastColor = -1; // Set to illegal value
|
2017-12-03 02:29:39 +00:00
|
|
|
|
2018-03-26 00:02:23 +00:00
|
|
|
// Used to store last shifted colour
|
|
|
|
uint8_t msbColor = 0;
|
|
|
|
uint8_t lsbColor = 0;
|
2018-01-08 23:19:42 +00:00
|
|
|
|
2018-03-26 00:02:23 +00:00
|
|
|
int32_t spx = x, spy = y;
|
2018-01-08 23:19:42 +00:00
|
|
|
|
2018-03-26 00:02:23 +00:00
|
|
|
while (dh--)
|
2017-12-03 02:29:39 +00:00
|
|
|
{
|
2018-03-26 00:02:23 +00:00
|
|
|
int32_t len = dw;
|
|
|
|
uint8_t* ptr = data;
|
|
|
|
uint8_t* linePtr = (uint8_t*)lineBuf;
|
2017-12-03 02:29:39 +00:00
|
|
|
|
2018-03-26 00:02:23 +00:00
|
|
|
int32_t px = x;
|
|
|
|
boolean move = true;
|
|
|
|
uint16_t np = 0;
|
|
|
|
|
|
|
|
while (len--)
|
|
|
|
{
|
|
|
|
if (transp != *ptr)
|
|
|
|
{
|
|
|
|
if (move) { move = false; setAddrWindow(px, y, xe, ye);}
|
|
|
|
uint8_t color = *ptr;
|
|
|
|
|
|
|
|
// Shifts are slow so check if colour has changed first
|
|
|
|
if (color != _lastColor) {
|
|
|
|
// =====Green===== ===============Red==============
|
|
|
|
msbColor = (color & 0x1C)>>2 | (color & 0xC0)>>3 | (color & 0xE0);
|
|
|
|
// =====Green===== =======Blue======
|
|
|
|
lsbColor = (color & 0x1C)<<3 | blue[color & 0x03];
|
|
|
|
_lastColor = color;
|
|
|
|
}
|
|
|
|
*linePtr++ = msbColor;
|
|
|
|
*linePtr++ = lsbColor;
|
|
|
|
np++;
|
2017-12-03 02:29:39 +00:00
|
|
|
}
|
2018-03-26 00:02:23 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
move = true;
|
|
|
|
if (np)
|
|
|
|
{
|
|
|
|
pushColors(lineBuf, np, false);
|
|
|
|
linePtr = (uint8_t*)lineBuf;
|
|
|
|
np = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
px++;
|
|
|
|
ptr++;
|
2018-01-08 23:19:42 +00:00
|
|
|
}
|
2018-03-26 00:02:23 +00:00
|
|
|
|
|
|
|
if (np) pushColors(lineBuf, np, false);
|
|
|
|
|
|
|
|
y++;
|
|
|
|
data += w;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
w = (w+7) & 0xFFF8;
|
|
|
|
while (dh--)
|
|
|
|
{
|
|
|
|
int32_t px = x;
|
|
|
|
boolean move = true;
|
|
|
|
uint16_t np = 0;
|
|
|
|
int32_t len = dw;
|
|
|
|
uint8_t* ptr = data;
|
|
|
|
uint8_t bits = 8;
|
|
|
|
while(len>0)
|
2018-01-08 23:19:42 +00:00
|
|
|
{
|
2018-03-26 00:02:23 +00:00
|
|
|
if (len < 8) bits = len;
|
|
|
|
uint32_t xp = dx;
|
|
|
|
uint32_t yp = (dy * w)>>3;
|
|
|
|
for (uint16_t i = 0; i < bits; i++)
|
2018-01-08 23:19:42 +00:00
|
|
|
{
|
2018-03-26 00:02:23 +00:00
|
|
|
//uint8_t col = (ptr[(xp + dy * w)>>3] << (xp & 0x7)) & 0x80;
|
|
|
|
if ((ptr[(xp>>3) + yp] << (xp & 0x7)) & 0x80)
|
|
|
|
{
|
|
|
|
if (move)
|
|
|
|
{
|
|
|
|
move = false;
|
|
|
|
setAddrWindow(px, y, xe, ye);
|
|
|
|
}
|
|
|
|
np++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (np)
|
|
|
|
{
|
|
|
|
pushColor(bitmap_fg, np);
|
|
|
|
np = 0;
|
|
|
|
move = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
px++;
|
|
|
|
xp++;
|
2018-01-08 23:19:42 +00:00
|
|
|
}
|
2018-03-26 00:02:23 +00:00
|
|
|
*ptr++;
|
|
|
|
len -= 8;
|
2017-12-03 02:29:39 +00:00
|
|
|
}
|
2018-03-26 00:02:23 +00:00
|
|
|
if (np) pushColor(bitmap_fg, np);
|
|
|
|
y++;
|
|
|
|
dy++;
|
2017-12-03 02:29:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CS_H;
|
|
|
|
|
2018-01-08 23:19:42 +00:00
|
|
|
inTransaction = false;
|
2017-12-03 02:29:39 +00:00
|
|
|
spi_end();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-01-08 23:19:42 +00:00
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: setSwapBytes
|
|
|
|
** Description: Used by 16 bit pushImage() to swap byte order in colours
|
|
|
|
***************************************************************************************/
|
|
|
|
void TFT_eSPI::setSwapBytes(bool swap)
|
|
|
|
{
|
|
|
|
_swapBytes = swap;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: getSwapBytes
|
|
|
|
** Description: Return the swap byte order for colours
|
|
|
|
***************************************************************************************/
|
|
|
|
bool TFT_eSPI::getSwapBytes(void)
|
|
|
|
{
|
|
|
|
return _swapBytes;
|
|
|
|
}
|
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: read rectangle (for SPI Interface II i.e. IM [3:0] = "1101")
|
|
|
|
** Description: Read RGB pixel colours from a defined area
|
|
|
|
***************************************************************************************/
|
|
|
|
// If w and h are 1, then 1 pixel is read, *data array size must be 3 bytes per pixel
|
2017-12-03 02:29:39 +00:00
|
|
|
void TFT_eSPI::readRectRGB(int32_t x0, int32_t y0, int32_t w, int32_t h, uint8_t *data)
|
2017-02-22 03:07:17 +00:00
|
|
|
{
|
2018-03-10 23:08:57 +00:00
|
|
|
#if !defined(ESP32_PARALLEL)
|
2017-04-14 00:04:04 +00:00
|
|
|
spi_begin();
|
2017-02-22 03:07:17 +00:00
|
|
|
|
2017-04-14 00:04:04 +00:00
|
|
|
readAddrWindow(x0, y0, x0 + w - 1, y0 + h - 1); // Sets CS low
|
2017-02-22 03:07:17 +00:00
|
|
|
|
2017-04-14 00:04:04 +00:00
|
|
|
// Dummy read to throw away don't care value
|
2018-03-12 22:49:18 +00:00
|
|
|
tft_Write_8(0);
|
2017-04-14 00:04:04 +00:00
|
|
|
|
|
|
|
// Read window pixel 24 bit RGB values, buffer must be set in sketch to 3 * w * h
|
|
|
|
uint32_t len = w * h;
|
|
|
|
while (len--) {
|
|
|
|
// Read the 3 RGB bytes, colour is actually only in the top 6 bits of each byte
|
|
|
|
// as the TFT stores colours as 18 bits
|
2018-03-12 22:49:18 +00:00
|
|
|
*data++ = tft_Write_8(0);
|
|
|
|
*data++ = tft_Write_8(0);
|
|
|
|
*data++ = tft_Write_8(0);
|
2017-04-14 00:04:04 +00:00
|
|
|
}
|
|
|
|
CS_H;
|
2017-02-22 03:07:17 +00:00
|
|
|
|
2017-04-14 00:04:04 +00:00
|
|
|
spi_end();
|
2018-03-10 23:08:57 +00:00
|
|
|
#endif
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: drawCircle
|
|
|
|
** Description: Draw a circle outline
|
|
|
|
***************************************************************************************/
|
|
|
|
// Optimised midpoint circle algorithm
|
|
|
|
void TFT_eSPI::drawCircle(int32_t x0, int32_t y0, int32_t r, uint32_t color)
|
|
|
|
{
|
|
|
|
int32_t x = 0;
|
|
|
|
int32_t dx = 1;
|
|
|
|
int32_t dy = r+r;
|
|
|
|
int32_t p = -(r>>1);
|
|
|
|
|
2017-05-20 00:37:58 +00:00
|
|
|
spi_begin();
|
|
|
|
inTransaction = true;
|
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
// These are ordered to minimise coordinate changes in x or y
|
|
|
|
// drawPixel can then send fewer bounding box commands
|
|
|
|
drawPixel(x0 + r, y0, color);
|
|
|
|
drawPixel(x0 - r, y0, color);
|
|
|
|
drawPixel(x0, y0 - r, color);
|
|
|
|
drawPixel(x0, y0 + r, color);
|
|
|
|
|
|
|
|
while(x<r){
|
|
|
|
|
|
|
|
if(p>=0) {
|
|
|
|
dy-=2;
|
|
|
|
p-=dy;
|
|
|
|
r--;
|
|
|
|
}
|
|
|
|
|
|
|
|
dx+=2;
|
|
|
|
p+=dx;
|
|
|
|
|
|
|
|
x++;
|
|
|
|
|
|
|
|
// These are ordered to minimise coordinate changes in x or y
|
|
|
|
// drawPixel can then send fewer bounding box commands
|
|
|
|
drawPixel(x0 + x, y0 + r, color);
|
|
|
|
drawPixel(x0 - x, y0 + r, color);
|
|
|
|
drawPixel(x0 - x, y0 - r, color);
|
|
|
|
drawPixel(x0 + x, y0 - r, color);
|
|
|
|
|
|
|
|
drawPixel(x0 + r, y0 + x, color);
|
|
|
|
drawPixel(x0 - r, y0 + x, color);
|
|
|
|
drawPixel(x0 - r, y0 - x, color);
|
|
|
|
drawPixel(x0 + r, y0 - x, color);
|
2017-04-14 00:04:04 +00:00
|
|
|
}
|
2017-05-20 00:37:58 +00:00
|
|
|
|
|
|
|
inTransaction = false;
|
|
|
|
spi_end();
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: drawCircleHelper
|
|
|
|
** Description: Support function for circle drawing
|
|
|
|
***************************************************************************************/
|
|
|
|
void TFT_eSPI::drawCircleHelper( int32_t x0, int32_t y0, int32_t r, uint8_t cornername, uint32_t color)
|
|
|
|
{
|
|
|
|
int32_t f = 1 - r;
|
|
|
|
int32_t ddF_x = 1;
|
|
|
|
int32_t ddF_y = -2 * r;
|
|
|
|
int32_t x = 0;
|
|
|
|
|
|
|
|
while (x < r) {
|
|
|
|
if (f >= 0) {
|
|
|
|
r--;
|
|
|
|
ddF_y += 2;
|
|
|
|
f += ddF_y;
|
|
|
|
}
|
|
|
|
x++;
|
|
|
|
ddF_x += 2;
|
|
|
|
f += ddF_x;
|
|
|
|
if (cornername & 0x4) {
|
|
|
|
drawPixel(x0 + x, y0 + r, color);
|
|
|
|
drawPixel(x0 + r, y0 + x, color);
|
|
|
|
}
|
|
|
|
if (cornername & 0x2) {
|
|
|
|
drawPixel(x0 + x, y0 - r, color);
|
|
|
|
drawPixel(x0 + r, y0 - x, color);
|
|
|
|
}
|
|
|
|
if (cornername & 0x8) {
|
|
|
|
drawPixel(x0 - r, y0 + x, color);
|
|
|
|
drawPixel(x0 - x, y0 + r, color);
|
|
|
|
}
|
|
|
|
if (cornername & 0x1) {
|
|
|
|
drawPixel(x0 - r, y0 - x, color);
|
|
|
|
drawPixel(x0 - x, y0 - r, color);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: fillCircle
|
|
|
|
** Description: draw a filled circle
|
|
|
|
***************************************************************************************/
|
2018-01-08 23:19:42 +00:00
|
|
|
// Optimised midpoint circle algorithm, changed to horizontal lines (faster in sprites)
|
2017-02-22 03:07:17 +00:00
|
|
|
void TFT_eSPI::fillCircle(int32_t x0, int32_t y0, int32_t r, uint32_t color)
|
|
|
|
{
|
|
|
|
int32_t x = 0;
|
|
|
|
int32_t dx = 1;
|
|
|
|
int32_t dy = r+r;
|
|
|
|
int32_t p = -(r>>1);
|
|
|
|
|
2017-05-20 00:37:58 +00:00
|
|
|
spi_begin();
|
|
|
|
inTransaction = true;
|
|
|
|
|
2018-01-08 23:19:42 +00:00
|
|
|
drawFastHLine(x0 - r, y0, dy+1, color);
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
while(x<r){
|
|
|
|
|
|
|
|
if(p>=0) {
|
|
|
|
dy-=2;
|
|
|
|
p-=dy;
|
|
|
|
r--;
|
|
|
|
}
|
|
|
|
|
|
|
|
dx+=2;
|
|
|
|
p+=dx;
|
|
|
|
|
|
|
|
x++;
|
|
|
|
|
2018-01-08 23:19:42 +00:00
|
|
|
drawFastHLine(x0 - r, y0 + x, 2 * r+1, color);
|
|
|
|
drawFastHLine(x0 - r, y0 - x, 2 * r+1, color);
|
|
|
|
drawFastHLine(x0 - x, y0 + r, 2 * x+1, color);
|
|
|
|
drawFastHLine(x0 - x, y0 - r, 2 * x+1, color);
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
}
|
2017-05-20 00:37:58 +00:00
|
|
|
|
|
|
|
inTransaction = false;
|
|
|
|
spi_end();
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: fillCircleHelper
|
|
|
|
** Description: Support function for filled circle drawing
|
|
|
|
***************************************************************************************/
|
2018-01-08 23:19:42 +00:00
|
|
|
// Used to support drawing roundrects, changed to horizontal lines (faster in sprites)
|
2017-02-22 03:07:17 +00:00
|
|
|
void TFT_eSPI::fillCircleHelper(int32_t x0, int32_t y0, int32_t r, uint8_t cornername, int32_t delta, uint32_t color)
|
|
|
|
{
|
|
|
|
int32_t f = 1 - r;
|
|
|
|
int32_t ddF_x = 1;
|
|
|
|
int32_t ddF_y = -r - r;
|
2018-01-08 23:19:42 +00:00
|
|
|
int32_t y = 0;
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
delta++;
|
2018-01-08 23:19:42 +00:00
|
|
|
while (y < r) {
|
2017-02-22 03:07:17 +00:00
|
|
|
if (f >= 0) {
|
|
|
|
r--;
|
|
|
|
ddF_y += 2;
|
|
|
|
f += ddF_y;
|
|
|
|
}
|
2018-01-08 23:19:42 +00:00
|
|
|
y++;
|
|
|
|
//x++;
|
2017-02-22 03:07:17 +00:00
|
|
|
ddF_x += 2;
|
|
|
|
f += ddF_x;
|
|
|
|
|
2018-01-08 23:19:42 +00:00
|
|
|
if (cornername & 0x1)
|
|
|
|
{
|
|
|
|
drawFastHLine(x0 - r, y0 + y, r + r + delta, color);
|
|
|
|
drawFastHLine(x0 - y, y0 + r, y + y + delta, color);
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
if (cornername & 0x2) {
|
2018-01-08 23:19:42 +00:00
|
|
|
drawFastHLine(x0 - r, y0 - y, r + r + delta, color); // 11995, 1090
|
|
|
|
drawFastHLine(x0 - y, y0 - r, y + y + delta, color);
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: drawEllipse
|
|
|
|
** Description: Draw a ellipse outline
|
|
|
|
***************************************************************************************/
|
|
|
|
void TFT_eSPI::drawEllipse(int16_t x0, int16_t y0, int16_t rx, int16_t ry, uint16_t color)
|
|
|
|
{
|
|
|
|
if (rx<2) return;
|
|
|
|
if (ry<2) return;
|
|
|
|
int32_t x, y;
|
|
|
|
int32_t rx2 = rx * rx;
|
|
|
|
int32_t ry2 = ry * ry;
|
|
|
|
int32_t fx2 = 4 * rx2;
|
|
|
|
int32_t fy2 = 4 * ry2;
|
|
|
|
int32_t s;
|
|
|
|
|
2017-05-20 00:37:58 +00:00
|
|
|
spi_begin();
|
|
|
|
inTransaction = true;
|
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
for (x = 0, y = ry, s = 2*ry2+rx2*(1-2*ry); ry2*x <= rx2*y; x++)
|
|
|
|
{
|
2017-04-14 00:04:04 +00:00
|
|
|
// These are ordered to minimise coordinate changes in x or y
|
2017-02-22 03:07:17 +00:00
|
|
|
// drawPixel can then send fewer bounding box commands
|
|
|
|
drawPixel(x0 + x, y0 + y, color);
|
|
|
|
drawPixel(x0 - x, y0 + y, color);
|
|
|
|
drawPixel(x0 - x, y0 - y, color);
|
|
|
|
drawPixel(x0 + x, y0 - y, color);
|
|
|
|
if (s >= 0)
|
|
|
|
{
|
|
|
|
s += fx2 * (1 - y);
|
|
|
|
y--;
|
|
|
|
}
|
|
|
|
s += ry2 * ((4 * x) + 6);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (x = rx, y = 0, s = 2*rx2+ry2*(1-2*rx); rx2*y <= ry2*x; y++)
|
|
|
|
{
|
2017-04-14 00:04:04 +00:00
|
|
|
// These are ordered to minimise coordinate changes in x or y
|
2017-02-22 03:07:17 +00:00
|
|
|
// drawPixel can then send fewer bounding box commands
|
|
|
|
drawPixel(x0 + x, y0 + y, color);
|
|
|
|
drawPixel(x0 - x, y0 + y, color);
|
|
|
|
drawPixel(x0 - x, y0 - y, color);
|
|
|
|
drawPixel(x0 + x, y0 - y, color);
|
|
|
|
if (s >= 0)
|
|
|
|
{
|
|
|
|
s += fy2 * (1 - x);
|
|
|
|
x--;
|
|
|
|
}
|
|
|
|
s += rx2 * ((4 * y) + 6);
|
|
|
|
}
|
2017-05-20 00:37:58 +00:00
|
|
|
|
|
|
|
inTransaction = false;
|
|
|
|
spi_end();
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: fillEllipse
|
|
|
|
** Description: draw a filled ellipse
|
|
|
|
***************************************************************************************/
|
|
|
|
void TFT_eSPI::fillEllipse(int16_t x0, int16_t y0, int16_t rx, int16_t ry, uint16_t color)
|
|
|
|
{
|
|
|
|
if (rx<2) return;
|
|
|
|
if (ry<2) return;
|
|
|
|
int32_t x, y;
|
|
|
|
int32_t rx2 = rx * rx;
|
|
|
|
int32_t ry2 = ry * ry;
|
|
|
|
int32_t fx2 = 4 * rx2;
|
|
|
|
int32_t fy2 = 4 * ry2;
|
|
|
|
int32_t s;
|
|
|
|
|
2017-05-20 00:37:58 +00:00
|
|
|
spi_begin();
|
|
|
|
inTransaction = true;
|
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
for (x = 0, y = ry, s = 2*ry2+rx2*(1-2*ry); ry2*x <= rx2*y; x++)
|
|
|
|
{
|
|
|
|
drawFastHLine(x0 - x, y0 - y, x + x + 1, color);
|
|
|
|
drawFastHLine(x0 - x, y0 + y, x + x + 1, color);
|
|
|
|
|
|
|
|
if (s >= 0)
|
|
|
|
{
|
|
|
|
s += fx2 * (1 - y);
|
|
|
|
y--;
|
|
|
|
}
|
|
|
|
s += ry2 * ((4 * x) + 6);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (x = rx, y = 0, s = 2*rx2+ry2*(1-2*rx); rx2*y <= ry2*x; y++)
|
|
|
|
{
|
|
|
|
drawFastHLine(x0 - x, y0 - y, x + x + 1, color);
|
|
|
|
drawFastHLine(x0 - x, y0 + y, x + x + 1, color);
|
|
|
|
|
|
|
|
if (s >= 0)
|
|
|
|
{
|
|
|
|
s += fy2 * (1 - x);
|
|
|
|
x--;
|
|
|
|
}
|
|
|
|
s += rx2 * ((4 * y) + 6);
|
|
|
|
}
|
|
|
|
|
2017-05-20 00:37:58 +00:00
|
|
|
inTransaction = false;
|
|
|
|
spi_end();
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: fillScreen
|
|
|
|
** Description: Clear the screen to defined colour
|
|
|
|
***************************************************************************************/
|
|
|
|
void TFT_eSPI::fillScreen(uint32_t color)
|
|
|
|
{
|
|
|
|
fillRect(0, 0, _width, _height, color);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: drawRect
|
|
|
|
** Description: Draw a rectangle outline
|
|
|
|
***************************************************************************************/
|
|
|
|
// Draw a rectangle
|
|
|
|
void TFT_eSPI::drawRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color)
|
|
|
|
{
|
2017-05-20 00:37:58 +00:00
|
|
|
spi_begin();
|
|
|
|
inTransaction = true;
|
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
drawFastHLine(x, y, w, color);
|
|
|
|
drawFastHLine(x, y + h - 1, w, color);
|
|
|
|
drawFastVLine(x, y, h, color);
|
|
|
|
drawFastVLine(x + w - 1, y, h, color);
|
2017-05-20 00:37:58 +00:00
|
|
|
|
|
|
|
inTransaction = false;
|
|
|
|
spi_end();
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: drawRoundRect
|
|
|
|
** Description: Draw a rounded corner rectangle outline
|
|
|
|
***************************************************************************************/
|
|
|
|
// Draw a rounded rectangle
|
|
|
|
void TFT_eSPI::drawRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t r, uint32_t color)
|
|
|
|
{
|
2017-05-20 00:37:58 +00:00
|
|
|
spi_begin();
|
|
|
|
inTransaction = true;
|
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
// smarter version
|
|
|
|
drawFastHLine(x + r , y , w - r - r, color); // Top
|
|
|
|
drawFastHLine(x + r , y + h - 1, w - r - r, color); // Bottom
|
|
|
|
drawFastVLine(x , y + r , h - r - r, color); // Left
|
|
|
|
drawFastVLine(x + w - 1, y + r , h - r - r, color); // Right
|
|
|
|
// draw four corners
|
|
|
|
drawCircleHelper(x + r , y + r , r, 1, color);
|
|
|
|
drawCircleHelper(x + w - r - 1, y + r , r, 2, color);
|
|
|
|
drawCircleHelper(x + w - r - 1, y + h - r - 1, r, 4, color);
|
|
|
|
drawCircleHelper(x + r , y + h - r - 1, r, 8, color);
|
2017-05-20 00:37:58 +00:00
|
|
|
|
|
|
|
inTransaction = false;
|
|
|
|
spi_end();
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: fillRoundRect
|
|
|
|
** Description: Draw a rounded corner filled rectangle
|
|
|
|
***************************************************************************************/
|
2018-01-08 23:19:42 +00:00
|
|
|
// Fill a rounded rectangle, changed to horizontal lines (faster in sprites)
|
2017-02-22 03:07:17 +00:00
|
|
|
void TFT_eSPI::fillRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t r, uint32_t color)
|
|
|
|
{
|
2017-05-20 00:37:58 +00:00
|
|
|
spi_begin();
|
|
|
|
inTransaction = true;
|
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
// smarter version
|
2018-01-08 23:19:42 +00:00
|
|
|
fillRect(x, y + r, w, h - r - r, color);
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
// draw four corners
|
2018-01-08 23:19:42 +00:00
|
|
|
fillCircleHelper(x + r, y + h - r - 1, r, 1, w - r - r - 1, color);
|
|
|
|
fillCircleHelper(x + r , y + r, r, 2, w - r - r - 1, color);
|
|
|
|
|
2017-05-20 00:37:58 +00:00
|
|
|
inTransaction = false;
|
|
|
|
spi_end();
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: drawTriangle
|
|
|
|
** Description: Draw a triangle outline using 3 arbitrary points
|
|
|
|
***************************************************************************************/
|
|
|
|
// Draw a triangle
|
|
|
|
void TFT_eSPI::drawTriangle(int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint32_t color)
|
|
|
|
{
|
2017-05-20 00:37:58 +00:00
|
|
|
spi_begin();
|
|
|
|
inTransaction = true;
|
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
drawLine(x0, y0, x1, y1, color);
|
|
|
|
drawLine(x1, y1, x2, y2, color);
|
|
|
|
drawLine(x2, y2, x0, y0, color);
|
2017-05-20 00:37:58 +00:00
|
|
|
|
|
|
|
inTransaction = false;
|
|
|
|
spi_end();
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: fillTriangle
|
|
|
|
** Description: Draw a filled triangle using 3 arbitrary points
|
|
|
|
***************************************************************************************/
|
|
|
|
// Fill a triangle - original Adafruit function works well and code footprint is small
|
|
|
|
void TFT_eSPI::fillTriangle ( int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint32_t color)
|
|
|
|
{
|
|
|
|
int32_t a, b, y, last;
|
|
|
|
|
|
|
|
// Sort coordinates by Y order (y2 >= y1 >= y0)
|
|
|
|
if (y0 > y1) {
|
2017-04-12 23:20:19 +00:00
|
|
|
swap_coord(y0, y1); swap_coord(x0, x1);
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
if (y1 > y2) {
|
2017-04-12 23:20:19 +00:00
|
|
|
swap_coord(y2, y1); swap_coord(x2, x1);
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
if (y0 > y1) {
|
2017-04-12 23:20:19 +00:00
|
|
|
swap_coord(y0, y1); swap_coord(x0, x1);
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (y0 == y2) { // Handle awkward all-on-same-line case as its own thing
|
|
|
|
a = b = x0;
|
|
|
|
if (x1 < a) a = x1;
|
|
|
|
else if (x1 > b) b = x1;
|
|
|
|
if (x2 < a) a = x2;
|
|
|
|
else if (x2 > b) b = x2;
|
|
|
|
drawFastHLine(a, y0, b - a + 1, color);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-01-08 23:19:42 +00:00
|
|
|
spi_begin();
|
|
|
|
inTransaction = true;
|
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
int32_t
|
|
|
|
dx01 = x1 - x0,
|
|
|
|
dy01 = y1 - y0,
|
|
|
|
dx02 = x2 - x0,
|
|
|
|
dy02 = y2 - y0,
|
|
|
|
dx12 = x2 - x1,
|
|
|
|
dy12 = y2 - y1,
|
|
|
|
sa = 0,
|
|
|
|
sb = 0;
|
|
|
|
|
|
|
|
// For upper part of triangle, find scanline crossings for segments
|
|
|
|
// 0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1
|
|
|
|
// is included here (and second loop will be skipped, avoiding a /0
|
|
|
|
// error there), otherwise scanline y1 is skipped here and handled
|
|
|
|
// in the second loop...which also avoids a /0 error here if y0=y1
|
|
|
|
// (flat-topped triangle).
|
|
|
|
if (y1 == y2) last = y1; // Include y1 scanline
|
|
|
|
else last = y1 - 1; // Skip it
|
|
|
|
|
|
|
|
for (y = y0; y <= last; y++) {
|
|
|
|
a = x0 + sa / dy01;
|
|
|
|
b = x0 + sb / dy02;
|
|
|
|
sa += dx01;
|
|
|
|
sb += dx02;
|
|
|
|
|
2017-04-12 23:20:19 +00:00
|
|
|
if (a > b) swap_coord(a, b);
|
2017-02-22 03:07:17 +00:00
|
|
|
drawFastHLine(a, y, b - a + 1, color);
|
|
|
|
}
|
|
|
|
|
|
|
|
// For lower part of triangle, find scanline crossings for segments
|
|
|
|
// 0-2 and 1-2. This loop is skipped if y1=y2.
|
|
|
|
sa = dx12 * (y - y1);
|
|
|
|
sb = dx02 * (y - y0);
|
|
|
|
for (; y <= y2; y++) {
|
|
|
|
a = x1 + sa / dy12;
|
|
|
|
b = x0 + sb / dy02;
|
|
|
|
sa += dx12;
|
|
|
|
sb += dx02;
|
|
|
|
|
2017-04-12 23:20:19 +00:00
|
|
|
if (a > b) swap_coord(a, b);
|
2017-02-22 03:07:17 +00:00
|
|
|
drawFastHLine(a, y, b - a + 1, color);
|
|
|
|
}
|
2017-05-20 00:37:58 +00:00
|
|
|
|
|
|
|
inTransaction = false;
|
|
|
|
spi_end();
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: drawBitmap
|
|
|
|
** Description: Draw an image stored in an array on the TFT
|
|
|
|
***************************************************************************************/
|
2018-04-23 16:16:18 +00:00
|
|
|
void TFT_eSPI::drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color)
|
|
|
|
{
|
2017-05-20 00:37:58 +00:00
|
|
|
spi_begin();
|
|
|
|
inTransaction = true;
|
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
int32_t i, j, byteWidth = (w + 7) / 8;
|
|
|
|
|
|
|
|
for (j = 0; j < h; j++) {
|
|
|
|
for (i = 0; i < w; i++ ) {
|
|
|
|
if (pgm_read_byte(bitmap + j * byteWidth + i / 8) & (128 >> (i & 7))) {
|
|
|
|
drawPixel(x + i, y + j, color);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-05-20 00:37:58 +00:00
|
|
|
|
|
|
|
inTransaction = false;
|
|
|
|
spi_end();
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-04-23 16:16:18 +00:00
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: drawXBitmap
|
|
|
|
** Description: Draw an image stored in an XBM array onto the TFT
|
|
|
|
***************************************************************************************/
|
|
|
|
void TFT_eSPI::drawXBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color)
|
|
|
|
{
|
|
|
|
spi_begin();
|
|
|
|
inTransaction = true;
|
|
|
|
|
|
|
|
int32_t i, j, byteWidth = (w + 7) / 8;
|
|
|
|
|
|
|
|
for (j = 0; j < h; j++) {
|
|
|
|
for (i = 0; i < w; i++ ) {
|
|
|
|
if (pgm_read_byte(bitmap + j * byteWidth + i / 8) & (1 << (i & 7))) {
|
|
|
|
drawPixel(x + i, y + j, color);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
inTransaction = false;
|
|
|
|
spi_end();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: drawXBitmap
|
|
|
|
** Description: Draw an XBM image with foreground and background colors
|
|
|
|
***************************************************************************************/
|
|
|
|
void TFT_eSPI::drawXBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bgcolor)
|
|
|
|
{
|
|
|
|
spi_begin();
|
|
|
|
inTransaction = true;
|
|
|
|
|
|
|
|
int32_t i, j, byteWidth = (w + 7) / 8;
|
|
|
|
|
|
|
|
for (j = 0; j < h; j++) {
|
|
|
|
for (i = 0; i < w; i++ ) {
|
|
|
|
if (pgm_read_byte(bitmap + j * byteWidth + i / 8) & (1 << (i & 7)))
|
|
|
|
drawPixel(x + i, y + j, color);
|
|
|
|
else drawPixel(x + i, y + j, bgcolor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
inTransaction = false;
|
|
|
|
spi_end();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: setCursor
|
|
|
|
** Description: Set the text cursor x,y position
|
|
|
|
***************************************************************************************/
|
|
|
|
void TFT_eSPI::setCursor(int16_t x, int16_t y)
|
|
|
|
{
|
|
|
|
cursor_x = x;
|
|
|
|
cursor_y = y;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: setCursor
|
|
|
|
** Description: Set the text cursor x,y position and font
|
|
|
|
***************************************************************************************/
|
|
|
|
void TFT_eSPI::setCursor(int16_t x, int16_t y, uint8_t font)
|
|
|
|
{
|
|
|
|
textfont = font;
|
|
|
|
cursor_x = x;
|
|
|
|
cursor_y = y;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-01-26 15:19:40 +00:00
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: getCursorX
|
|
|
|
** Description: Get the text cursor x position
|
|
|
|
***************************************************************************************/
|
|
|
|
int16_t TFT_eSPI::getCursorX(void)
|
|
|
|
{
|
|
|
|
return cursor_x;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: getCursorY
|
|
|
|
** Description: Get the text cursor y position
|
|
|
|
***************************************************************************************/
|
|
|
|
int16_t TFT_eSPI::getCursorY(void)
|
|
|
|
{
|
|
|
|
return cursor_y;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: setTextSize
|
|
|
|
** Description: Set the text size multiplier
|
|
|
|
***************************************************************************************/
|
|
|
|
void TFT_eSPI::setTextSize(uint8_t s)
|
|
|
|
{
|
|
|
|
if (s>7) s = 7; // Limit the maximum size multiplier so byte variables can be used for rendering
|
|
|
|
textsize = (s > 0) ? s : 1; // Don't allow font size 0
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: setTextColor
|
|
|
|
** Description: Set the font foreground colour (background is transparent)
|
|
|
|
***************************************************************************************/
|
|
|
|
void TFT_eSPI::setTextColor(uint16_t c)
|
|
|
|
{
|
|
|
|
// For 'transparent' background, we'll set the bg
|
|
|
|
// to the same as fg instead of using a flag
|
|
|
|
textcolor = textbgcolor = c;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: setTextColor
|
|
|
|
** Description: Set the font foreground and background colour
|
|
|
|
***************************************************************************************/
|
|
|
|
void TFT_eSPI::setTextColor(uint16_t c, uint16_t b)
|
|
|
|
{
|
|
|
|
textcolor = c;
|
|
|
|
textbgcolor = b;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-03-26 00:02:23 +00:00
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: setBitmapColor
|
|
|
|
** Description: Set the foreground foreground and background colour
|
|
|
|
***************************************************************************************/
|
|
|
|
void TFT_eSPI::setBitmapColor(uint16_t c, uint16_t b)
|
|
|
|
{
|
|
|
|
if (c == b) b = ~c;
|
|
|
|
bitmap_fg = c;
|
|
|
|
bitmap_bg = b;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: setTextWrap
|
|
|
|
** Description: Define if text should wrap at end of line
|
|
|
|
***************************************************************************************/
|
2018-02-24 19:02:20 +00:00
|
|
|
void TFT_eSPI::setTextWrap(boolean wrapX, boolean wrapY)
|
2017-02-22 03:07:17 +00:00
|
|
|
{
|
2018-02-24 19:02:20 +00:00
|
|
|
textwrapX = wrapX;
|
|
|
|
textwrapY = wrapY;
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: setTextDatum
|
|
|
|
** Description: Set the text position reference datum
|
|
|
|
***************************************************************************************/
|
|
|
|
void TFT_eSPI::setTextDatum(uint8_t d)
|
|
|
|
{
|
|
|
|
textdatum = d;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: setTextPadding
|
|
|
|
** Description: Define padding width (aids erasing old text and numbers)
|
|
|
|
***************************************************************************************/
|
|
|
|
void TFT_eSPI::setTextPadding(uint16_t x_width)
|
|
|
|
{
|
|
|
|
padX = x_width;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: getRotation
|
|
|
|
** Description: Return the rotation value (as used by setRotation())
|
|
|
|
***************************************************************************************/
|
|
|
|
uint8_t TFT_eSPI::getRotation(void)
|
|
|
|
{
|
|
|
|
return rotation;
|
|
|
|
}
|
|
|
|
|
2017-10-23 00:59:37 +00:00
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: getTextDatum
|
|
|
|
** Description: Return the text datum value (as used by setTextDatum())
|
|
|
|
***************************************************************************************/
|
|
|
|
uint8_t TFT_eSPI::getTextDatum(void)
|
|
|
|
{
|
|
|
|
return textdatum;
|
|
|
|
}
|
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: width
|
|
|
|
** Description: Return the pixel width of display (per current rotation)
|
|
|
|
***************************************************************************************/
|
|
|
|
// Return the size of the display (per current rotation)
|
|
|
|
int16_t TFT_eSPI::width(void)
|
|
|
|
{
|
|
|
|
return _width;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: height
|
|
|
|
** Description: Return the pixel height of display (per current rotation)
|
|
|
|
***************************************************************************************/
|
|
|
|
int16_t TFT_eSPI::height(void)
|
|
|
|
{
|
|
|
|
return _height;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: textWidth
|
|
|
|
** Description: Return the width in pixels of a string in a given font
|
|
|
|
***************************************************************************************/
|
|
|
|
int16_t TFT_eSPI::textWidth(const String& string)
|
|
|
|
{
|
2017-04-14 00:04:04 +00:00
|
|
|
int16_t len = string.length() + 2;
|
|
|
|
char buffer[len];
|
|
|
|
string.toCharArray(buffer, len);
|
|
|
|
return textWidth(buffer, textfont);
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int16_t TFT_eSPI::textWidth(const String& string, int font)
|
|
|
|
{
|
2017-04-14 00:04:04 +00:00
|
|
|
int16_t len = string.length() + 2;
|
|
|
|
char buffer[len];
|
|
|
|
string.toCharArray(buffer, len);
|
|
|
|
return textWidth(buffer, font);
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int16_t TFT_eSPI::textWidth(const char *string)
|
|
|
|
{
|
2017-04-14 00:04:04 +00:00
|
|
|
return textWidth(string, textfont);
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int16_t TFT_eSPI::textWidth(const char *string, int font)
|
|
|
|
{
|
2018-02-24 19:02:20 +00:00
|
|
|
int str_width = 0;
|
|
|
|
|
|
|
|
#ifdef SMOOTH_FONT
|
|
|
|
if(fontLoaded)
|
|
|
|
{
|
|
|
|
while (*string)
|
|
|
|
{
|
|
|
|
uint16_t unicode = decodeUTF8(*string++);
|
|
|
|
if (unicode)
|
|
|
|
{
|
|
|
|
if (unicode == 0x20) str_width += gFont.spaceWidth;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
uint16_t gNum = 0;
|
|
|
|
bool found = getUnicodeIndex(unicode, &gNum);
|
|
|
|
if (found)
|
|
|
|
{
|
|
|
|
if(str_width == 0 && gdX[gNum] < 0) str_width -= gdX[gNum];
|
|
|
|
if (*string) str_width += gxAdvance[gNum];
|
|
|
|
else str_width += (gdX[gNum] + gWidth[gNum]);
|
|
|
|
}
|
|
|
|
else str_width += gFont.spaceWidth + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return str_width;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-11-29 00:38:05 +00:00
|
|
|
unsigned char uniCode;
|
2017-02-22 03:07:17 +00:00
|
|
|
char *widthtable;
|
|
|
|
|
|
|
|
if (font>1 && font<9)
|
|
|
|
{
|
|
|
|
widthtable = (char *)pgm_read_dword( &(fontdata[font].widthtbl ) ) - 32; //subtract the 32 outside the loop
|
|
|
|
|
|
|
|
while (*string)
|
|
|
|
{
|
|
|
|
uniCode = *(string++);
|
2017-11-29 00:38:05 +00:00
|
|
|
if (uniCode > 31 && uniCode < 128)
|
2017-02-22 03:07:17 +00:00
|
|
|
str_width += pgm_read_byte( widthtable + uniCode); // Normally we need to subract 32 from uniCode
|
2017-11-29 00:38:05 +00:00
|
|
|
else str_width += pgm_read_byte( widthtable + 32); // Set illegal character = space width
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
|
|
|
|
#ifdef LOAD_GFXFF
|
|
|
|
if(gfxFont) // New font
|
|
|
|
{
|
|
|
|
while (*string)
|
|
|
|
{
|
|
|
|
uniCode = *(string++);
|
2017-11-29 02:00:47 +00:00
|
|
|
if ((uniCode >= (uint8_t)pgm_read_byte(&gfxFont->first)) && (uniCode <= (uint8_t)pgm_read_byte(&gfxFont->last )))
|
|
|
|
{
|
|
|
|
uniCode -= pgm_read_byte(&gfxFont->first);
|
|
|
|
GFXglyph *glyph = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[uniCode]);
|
|
|
|
// If this is not the last character then use xAdvance
|
|
|
|
if (*string) str_width += pgm_read_byte(&glyph->xAdvance);
|
|
|
|
// Else use the offset plus width since this can be bigger than xAdvance
|
|
|
|
else str_width += ((int8_t)pgm_read_byte(&glyph->xOffset) + pgm_read_byte(&glyph->width));
|
|
|
|
}
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
#ifdef LOAD_GLCD
|
|
|
|
while (*string++) str_width += 6;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return str_width * textsize;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: fontsLoaded
|
|
|
|
** Description: return an encoded 16 bit value showing the fonts loaded
|
|
|
|
***************************************************************************************/
|
|
|
|
// Returns a value showing which fonts are loaded (bit N set = Font N loaded)
|
|
|
|
|
|
|
|
uint16_t TFT_eSPI::fontsLoaded(void)
|
|
|
|
{
|
|
|
|
return fontsloaded;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: fontHeight
|
|
|
|
** Description: return the height of a font (yAdvance for free fonts)
|
|
|
|
***************************************************************************************/
|
|
|
|
int16_t TFT_eSPI::fontHeight(int16_t font)
|
|
|
|
{
|
2018-02-24 19:02:20 +00:00
|
|
|
#ifdef SMOOTH_FONT
|
|
|
|
if(fontLoaded) return gFont.yAdvance;
|
|
|
|
#endif
|
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
#ifdef LOAD_GFXFF
|
|
|
|
if (font==1)
|
|
|
|
{
|
|
|
|
if(gfxFont) // New font
|
|
|
|
{
|
|
|
|
return pgm_read_byte(&gfxFont->yAdvance) * textsize;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return pgm_read_byte( &fontdata[font].height ) * textsize;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: drawChar
|
|
|
|
** Description: draw a single character in the Adafruit GLCD font
|
|
|
|
***************************************************************************************/
|
|
|
|
void TFT_eSPI::drawChar(int32_t x, int32_t y, unsigned char c, uint32_t color, uint32_t bg, uint8_t size)
|
|
|
|
{
|
|
|
|
if ((x >= (int16_t)_width) || // Clip right
|
|
|
|
(y >= (int16_t)_height) || // Clip bottom
|
|
|
|
((x + 6 * size - 1) < 0) || // Clip left
|
|
|
|
((y + 8 * size - 1) < 0)) // Clip top
|
|
|
|
return;
|
|
|
|
|
2017-11-29 00:38:05 +00:00
|
|
|
if (c < 32) return;
|
2017-02-22 03:07:17 +00:00
|
|
|
#ifdef LOAD_GLCD
|
|
|
|
//>>>>>>>>>>>>>>>>>>
|
|
|
|
#ifdef LOAD_GFXFF
|
|
|
|
if(!gfxFont) { // 'Classic' built-in font
|
|
|
|
#endif
|
|
|
|
//>>>>>>>>>>>>>>>>>>
|
|
|
|
|
|
|
|
boolean fillbg = (bg != color);
|
|
|
|
|
|
|
|
if ((size==1) && fillbg)
|
|
|
|
{
|
2018-01-08 23:19:42 +00:00
|
|
|
uint8_t column[6];
|
|
|
|
uint8_t mask = 0x1;
|
2017-05-20 00:37:58 +00:00
|
|
|
spi_begin();
|
2017-11-29 00:38:05 +00:00
|
|
|
//inTransaction = true;
|
2017-02-22 03:07:17 +00:00
|
|
|
setAddrWindow(x, y, x+5, y+8);
|
|
|
|
for (int8_t i = 0; i < 5; i++ ) column[i] = pgm_read_byte(font + (c * 5) + i);
|
|
|
|
column[5] = 0;
|
2017-05-20 00:37:58 +00:00
|
|
|
|
2018-07-06 17:48:24 +00:00
|
|
|
#if defined (ESP8266) && !defined (ILI9488_DRIVER)
|
2017-04-14 00:04:04 +00:00
|
|
|
color = (color >> 8) | (color << 8);
|
|
|
|
bg = (bg >> 8) | (bg << 8);
|
2017-03-24 23:23:35 +00:00
|
|
|
uint32_t spimask = ~((SPIMMOSI << SPILMOSI) | (SPIMMISO << SPILMISO));
|
2017-04-23 17:50:53 +00:00
|
|
|
SPI1U1 = (SPI1U1 & spimask) | (15 << SPILMOSI) | (15 << SPILMISO);
|
2017-02-22 03:07:17 +00:00
|
|
|
for (int8_t j = 0; j < 8; j++) {
|
|
|
|
for (int8_t k = 0; k < 5; k++ ) {
|
|
|
|
if (column[k] & mask) {
|
2017-03-28 22:56:54 +00:00
|
|
|
SPI1W0 = color;
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
else {
|
2017-03-28 22:56:54 +00:00
|
|
|
SPI1W0 = bg;
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
2017-04-14 00:04:04 +00:00
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
mask <<= 1;
|
2017-03-24 23:23:35 +00:00
|
|
|
|
2017-04-14 00:04:04 +00:00
|
|
|
SPI1W0 = bg;
|
2017-03-24 23:23:35 +00:00
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
2018-07-06 17:48:24 +00:00
|
|
|
#else // for ESP32 or ILI9488
|
2018-03-10 23:08:57 +00:00
|
|
|
|
2017-05-20 00:37:58 +00:00
|
|
|
for (int8_t j = 0; j < 8; j++) {
|
|
|
|
for (int8_t k = 0; k < 5; k++ ) {
|
2018-03-12 22:49:18 +00:00
|
|
|
if (column[k] & mask) {tft_Write_16(color);}
|
|
|
|
else {tft_Write_16(bg);}
|
2017-05-20 00:37:58 +00:00
|
|
|
}
|
|
|
|
mask <<= 1;
|
2018-03-12 22:49:18 +00:00
|
|
|
tft_Write_16(bg);
|
2017-05-20 00:37:58 +00:00
|
|
|
}
|
2018-03-10 23:08:57 +00:00
|
|
|
|
2017-05-20 00:37:58 +00:00
|
|
|
#endif
|
2017-02-22 03:07:17 +00:00
|
|
|
CS_H;
|
2017-11-29 00:38:05 +00:00
|
|
|
//inTransaction = false;
|
2017-05-20 00:37:58 +00:00
|
|
|
spi_end();
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-05-20 00:37:58 +00:00
|
|
|
spi_begin();
|
|
|
|
inTransaction = true;
|
2017-02-22 03:07:17 +00:00
|
|
|
for (int8_t i = 0; i < 6; i++ ) {
|
|
|
|
uint8_t line;
|
|
|
|
if (i == 5)
|
|
|
|
line = 0x0;
|
|
|
|
else
|
|
|
|
line = pgm_read_byte(font + (c * 5) + i);
|
|
|
|
|
|
|
|
if (size == 1) // default size
|
|
|
|
{
|
|
|
|
for (int8_t j = 0; j < 8; j++) {
|
|
|
|
if (line & 0x1) drawPixel(x + i, y + j, color);
|
|
|
|
line >>= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else { // big size
|
|
|
|
for (int8_t j = 0; j < 8; j++) {
|
|
|
|
if (line & 0x1) fillRect(x + (i * size), y + (j * size), size, size, color);
|
|
|
|
else if (fillbg) fillRect(x + i * size, y + j * size, size, size, bg);
|
|
|
|
line >>= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-05-20 00:37:58 +00:00
|
|
|
inTransaction = false;
|
|
|
|
spi_end();
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
|
|
|
#ifdef LOAD_GFXFF
|
|
|
|
} else { // Custom font
|
|
|
|
#endif
|
|
|
|
//>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
|
|
|
#endif // LOAD_GLCD
|
|
|
|
|
|
|
|
#ifdef LOAD_GFXFF
|
2017-11-29 02:00:47 +00:00
|
|
|
// Filter out bad characters not present in font
|
|
|
|
if ((c >= (uint8_t)pgm_read_byte(&gfxFont->first)) && (c <= (uint8_t)pgm_read_byte(&gfxFont->last )))
|
|
|
|
{
|
|
|
|
spi_begin();
|
|
|
|
inTransaction = true;
|
2017-02-22 03:07:17 +00:00
|
|
|
//>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
2017-11-29 02:00:47 +00:00
|
|
|
|
|
|
|
c -= pgm_read_byte(&gfxFont->first);
|
|
|
|
GFXglyph *glyph = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[c]);
|
|
|
|
uint8_t *bitmap = (uint8_t *)pgm_read_dword(&gfxFont->bitmap);
|
|
|
|
|
|
|
|
uint16_t bo = pgm_read_word(&glyph->bitmapOffset);
|
|
|
|
uint8_t w = pgm_read_byte(&glyph->width),
|
|
|
|
h = pgm_read_byte(&glyph->height),
|
|
|
|
xa = pgm_read_byte(&glyph->xAdvance);
|
|
|
|
int8_t xo = pgm_read_byte(&glyph->xOffset),
|
|
|
|
yo = pgm_read_byte(&glyph->yOffset);
|
|
|
|
uint8_t xx, yy, bits, bit=0;
|
|
|
|
int16_t xo16 = 0, yo16 = 0;
|
|
|
|
|
|
|
|
if(size > 1) {
|
|
|
|
xo16 = xo;
|
|
|
|
yo16 = yo;
|
|
|
|
}
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
// Here we have 3 versions of the same function just for evaluation purposes
|
|
|
|
// Comment out the next two #defines to revert to the slower Adafruit implementation
|
|
|
|
|
|
|
|
// If FAST_LINE is defined then the free fonts are rendered using horizontal lines
|
|
|
|
// this makes rendering fonts 2-5 times faster. Particularly good for large fonts.
|
|
|
|
// This is an elegant solution since it still uses generic functions present in the
|
|
|
|
// stock library.
|
|
|
|
|
|
|
|
// If FAST_SHIFT is defined then a slightly faster (at least for AVR processors)
|
|
|
|
// shifting bit mask is used
|
|
|
|
|
|
|
|
// Free fonts don't look good when the size multiplier is >1 so we could remove
|
|
|
|
// code if this is not wanted and speed things up
|
|
|
|
|
|
|
|
#define FAST_HLINE
|
|
|
|
#define FAST_SHIFT
|
|
|
|
//FIXED_SIZE is an option in User_Setup.h that only works with FAST_LINE enabled
|
|
|
|
|
|
|
|
#ifdef FIXED_SIZE
|
2017-11-29 02:00:47 +00:00
|
|
|
x+=xo; // Save 88 bytes of FLASH
|
|
|
|
y+=yo;
|
2017-02-22 03:07:17 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef FAST_HLINE
|
|
|
|
|
|
|
|
#ifdef FAST_SHIFT
|
2017-11-29 02:00:47 +00:00
|
|
|
uint16_t hpc = 0; // Horizontal foreground pixel count
|
|
|
|
for(yy=0; yy<h; yy++) {
|
|
|
|
for(xx=0; xx<w; xx++) {
|
|
|
|
if(bit == 0) {
|
|
|
|
bits = pgm_read_byte(&bitmap[bo++]);
|
|
|
|
bit = 0x80;
|
|
|
|
}
|
|
|
|
if(bits & bit) hpc++;
|
|
|
|
else {
|
|
|
|
if (hpc) {
|
2017-02-22 03:07:17 +00:00
|
|
|
#ifndef FIXED_SIZE
|
2017-11-29 02:00:47 +00:00
|
|
|
if(size == 1) drawFastHLine(x+xo+xx-hpc, y+yo+yy, hpc, color);
|
|
|
|
else fillRect(x+(xo16+xx-hpc)*size, y+(yo16+yy)*size, size*hpc, size, color);
|
2017-02-22 03:07:17 +00:00
|
|
|
#else
|
2017-11-29 02:00:47 +00:00
|
|
|
drawFastHLine(x+xx-hpc, y+yy, hpc, color);
|
2017-02-22 03:07:17 +00:00
|
|
|
#endif
|
2017-11-29 02:00:47 +00:00
|
|
|
hpc=0;
|
|
|
|
}
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
2017-11-29 02:00:47 +00:00
|
|
|
bit >>= 1;
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
// Draw pixels for this line as we are about to increment yy
|
2017-11-29 02:00:47 +00:00
|
|
|
if (hpc) {
|
2017-02-22 03:07:17 +00:00
|
|
|
#ifndef FIXED_SIZE
|
2017-11-29 02:00:47 +00:00
|
|
|
if(size == 1) drawFastHLine(x+xo+xx-hpc, y+yo+yy, hpc, color);
|
|
|
|
else fillRect(x+(xo16+xx-hpc)*size, y+(yo16+yy)*size, size*hpc, size, color);
|
2017-02-22 03:07:17 +00:00
|
|
|
#else
|
2017-11-29 02:00:47 +00:00
|
|
|
drawFastHLine(x+xx-hpc, y+yy, hpc, color);
|
2017-02-22 03:07:17 +00:00
|
|
|
#endif
|
2017-11-29 02:00:47 +00:00
|
|
|
hpc=0;
|
|
|
|
}
|
2017-04-14 00:04:04 +00:00
|
|
|
}
|
2017-02-22 03:07:17 +00:00
|
|
|
#else
|
2017-11-29 02:00:47 +00:00
|
|
|
uint16_t hpc = 0; // Horizontal foreground pixel count
|
|
|
|
for(yy=0; yy<h; yy++) {
|
|
|
|
for(xx=0; xx<w; xx++) {
|
|
|
|
if(!(bit++ & 7)) {
|
|
|
|
bits = pgm_read_byte(&bitmap[bo++]);
|
|
|
|
}
|
|
|
|
if(bits & 0x80) hpc++;
|
|
|
|
else {
|
|
|
|
if (hpc) {
|
|
|
|
if(size == 1) drawFastHLine(x+xo+xx-hpc, y+yo+yy, hpc, color);
|
|
|
|
else fillRect(x+(xo16+xx-hpc)*size, y+(yo16+yy)*size, size*hpc, size, color);
|
|
|
|
hpc=0;
|
|
|
|
}
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
2017-11-29 02:00:47 +00:00
|
|
|
bits <<= 1;
|
|
|
|
}
|
|
|
|
// Draw pixels for this line as we are about to increment yy
|
|
|
|
if (hpc) {
|
|
|
|
if(size == 1) drawFastHLine(x+xo+xx-hpc, y+yo+yy, hpc, color);
|
|
|
|
else fillRect(x+(xo16+xx-hpc)*size, y+(yo16+yy)*size, size*hpc, size, color);
|
|
|
|
hpc=0;
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#else
|
2017-11-29 02:00:47 +00:00
|
|
|
for(yy=0; yy<h; yy++) {
|
|
|
|
for(xx=0; xx<w; xx++) {
|
|
|
|
if(!(bit++ & 7)) {
|
|
|
|
bits = pgm_read_byte(&bitmap[bo++]);
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
2017-11-29 02:00:47 +00:00
|
|
|
if(bits & 0x80) {
|
|
|
|
if(size == 1) {
|
|
|
|
drawPixel(x+xo+xx, y+yo+yy, color);
|
|
|
|
} else {
|
|
|
|
fillRect(x+(xo16+xx)*size, y+(yo16+yy)*size, size, size, color);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bits <<= 1;
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2017-11-29 02:00:47 +00:00
|
|
|
inTransaction = false;
|
|
|
|
spi_end();
|
|
|
|
}
|
2017-02-22 03:07:17 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef LOAD_GLCD
|
|
|
|
#ifdef LOAD_GFXFF
|
|
|
|
} // End classic vs custom font
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: setWindow
|
|
|
|
** Description: define an area to receive a stream of pixels
|
|
|
|
***************************************************************************************/
|
|
|
|
// Chip select is high at the end of this function
|
|
|
|
void TFT_eSPI::setWindow(int16_t x0, int16_t y0, int16_t x1, int16_t y1)
|
|
|
|
{
|
|
|
|
spi_begin();
|
|
|
|
setAddrWindow(x0, y0, x1, y1);
|
|
|
|
CS_H;
|
|
|
|
spi_end();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: setAddrWindow
|
|
|
|
** Description: define an area to receive a stream of pixels
|
|
|
|
***************************************************************************************/
|
|
|
|
// Chip select stays low, use setWindow() from sketches
|
|
|
|
|
2017-03-27 01:15:30 +00:00
|
|
|
#if defined (ESP8266) && !defined (RPI_WRITE_STROBE) && !defined (RPI_ILI9486_DRIVER)
|
2017-02-22 03:07:17 +00:00
|
|
|
inline void TFT_eSPI::setAddrWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye)
|
|
|
|
{
|
2017-05-20 00:37:58 +00:00
|
|
|
//spi_begin();
|
2017-02-22 03:07:17 +00:00
|
|
|
|
2017-04-16 15:13:12 +00:00
|
|
|
#ifdef CGRAM_OFFSET
|
2017-02-22 03:07:17 +00:00
|
|
|
xs+=colstart;
|
|
|
|
xe+=colstart;
|
|
|
|
ys+=rowstart;
|
|
|
|
ye+=rowstart;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Column addr set
|
|
|
|
DC_C;
|
|
|
|
CS_L;
|
|
|
|
|
|
|
|
uint32_t mask = ~((SPIMMOSI << SPILMOSI) | (SPIMMISO << SPILMISO));
|
|
|
|
mask = SPI1U1 & mask;
|
|
|
|
|
2017-03-24 23:23:35 +00:00
|
|
|
SPI1U1 = mask | (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO);
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
SPI1W0 = TFT_CASET;
|
|
|
|
SPI1CMD |= SPIBUSY;
|
2018-01-08 23:19:42 +00:00
|
|
|
|
|
|
|
addr_col = 0xFFFF;
|
|
|
|
addr_row = 0xFFFF;
|
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
|
|
|
|
|
|
|
DC_D;
|
|
|
|
|
|
|
|
SPI1U1 = mask | (31 << SPILMOSI) | (31 << SPILMISO);
|
|
|
|
// Load the two coords as a 32 bit value and shift in one go
|
|
|
|
SPI1W0 = (xs >> 8) | (uint16_t)(xs << 8) | ((uint8_t)(xe >> 8)<<16 | (xe << 24));
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
|
|
|
|
|
|
|
// Row addr set
|
|
|
|
DC_C;
|
|
|
|
|
2017-03-24 23:23:35 +00:00
|
|
|
SPI1U1 = mask | (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO);
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
SPI1W0 = TFT_PASET;
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
|
|
|
|
|
|
|
DC_D;
|
|
|
|
|
|
|
|
SPI1U1 = mask | (31 << SPILMOSI) | (31 << SPILMISO);
|
|
|
|
// Load the two coords as a 32 bit value and shift in one go
|
|
|
|
SPI1W0 = (ys >> 8) | (uint16_t)(ys << 8) | ((uint8_t)(ye >> 8)<<16 | (ye << 24));
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
|
|
|
|
|
|
|
// write to RAM
|
|
|
|
DC_C;
|
|
|
|
|
2017-03-24 23:23:35 +00:00
|
|
|
SPI1U1 = mask | (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO);
|
2017-02-22 03:07:17 +00:00
|
|
|
SPI1W0 = TFT_RAMWR;
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
|
|
|
|
|
|
|
DC_D;
|
|
|
|
|
2017-05-20 00:37:58 +00:00
|
|
|
//spi_end();
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
2017-03-11 16:59:34 +00:00
|
|
|
|
2017-03-27 01:15:30 +00:00
|
|
|
#elif defined (ESP8266) && !defined (RPI_WRITE_STROBE) && defined (RPI_ILI9486_DRIVER) // This is for the RPi display that needs 16 bits
|
2017-03-24 23:23:35 +00:00
|
|
|
|
2017-03-28 22:56:54 +00:00
|
|
|
void TFT_eSPI::setAddrWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye)
|
2017-03-24 23:23:35 +00:00
|
|
|
{
|
2017-05-20 00:37:58 +00:00
|
|
|
//spi_begin();
|
2017-03-24 23:23:35 +00:00
|
|
|
|
|
|
|
addr_col = 0xFFFF;
|
|
|
|
addr_row = 0xFFFF;
|
|
|
|
|
|
|
|
// Column addr set
|
|
|
|
DC_C;
|
|
|
|
CS_L;
|
|
|
|
|
|
|
|
uint32_t mask = ~((SPIMMOSI << SPILMOSI) | (SPIMMISO << SPILMISO));
|
|
|
|
mask = SPI1U1 & mask;
|
|
|
|
|
|
|
|
SPI1U1 = mask | (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO);
|
|
|
|
|
|
|
|
SPI1W0 = TFT_CASET<<8;
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
|
|
|
|
|
|
|
DC_D;
|
|
|
|
|
|
|
|
uint8_t xBin[] = { 0, (uint8_t) (xs>>8), 0, (uint8_t) (xs>>0), 0, (uint8_t) (xe>>8), 0, (uint8_t) (xe>>0), };
|
|
|
|
SPI.writePattern(&xBin[0], 8, 1);
|
|
|
|
|
|
|
|
// Row addr set
|
|
|
|
DC_C;
|
|
|
|
|
|
|
|
SPI1U1 = mask | (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO);
|
|
|
|
|
|
|
|
SPI1W0 = TFT_PASET<<8;
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
|
|
|
|
|
|
|
DC_D;
|
|
|
|
|
|
|
|
uint8_t yBin[] = { 0, (uint8_t) (ys>>8), 0, (uint8_t) (ys>>0), 0, (uint8_t) (ye>>8), 0, (uint8_t) (ye>>0), };
|
|
|
|
SPI.writePattern(&yBin[0], 8, 1);
|
|
|
|
|
|
|
|
// write to RAM
|
|
|
|
DC_C;
|
|
|
|
|
|
|
|
SPI1U1 = mask | (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO);
|
|
|
|
SPI1W0 = TFT_RAMWR<<8;
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
|
|
|
|
|
|
|
DC_D;
|
|
|
|
|
2017-05-20 00:37:58 +00:00
|
|
|
//spi_end();
|
2017-03-24 23:23:35 +00:00
|
|
|
}
|
|
|
|
|
2017-04-23 17:50:53 +00:00
|
|
|
#else
|
2017-03-24 23:23:35 +00:00
|
|
|
|
2017-05-20 00:37:58 +00:00
|
|
|
#if defined (ESP8266) && defined (RPI_ILI9486_DRIVER) // This is for the RPi display that needs 16 bits
|
2017-03-24 23:23:35 +00:00
|
|
|
inline void TFT_eSPI::setAddrWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1)
|
|
|
|
{
|
2017-05-20 00:37:58 +00:00
|
|
|
//spi_begin();
|
2017-03-24 23:23:35 +00:00
|
|
|
|
2017-03-27 01:15:30 +00:00
|
|
|
CS_L;
|
|
|
|
uint32_t mask = ~((SPIMMOSI << SPILMOSI) | (SPIMMISO << SPILMISO));
|
|
|
|
mask = SPI1U1 & mask;
|
|
|
|
SPI1U1 = mask | (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO);
|
|
|
|
|
|
|
|
// Column addr set
|
|
|
|
DC_C;
|
|
|
|
|
2017-04-14 00:04:04 +00:00
|
|
|
SPI1W0 = TFT_CASET<<(CMD_BITS + 1 - 8);
|
2017-03-27 01:15:30 +00:00
|
|
|
SPI1CMD |= SPIBUSY;
|
2017-04-14 00:04:04 +00:00
|
|
|
addr_col = 0xFFFF; // Use the waiting time to do something useful
|
|
|
|
addr_row = 0xFFFF;
|
2017-03-27 01:15:30 +00:00
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
|
|
|
DC_D;
|
|
|
|
|
2017-04-14 00:04:04 +00:00
|
|
|
SPI1W0 = x0 >> 0;
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
x0 = x0 << 8; // Use the waiting time to do something useful
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
2017-03-24 23:23:35 +00:00
|
|
|
|
2017-04-14 00:04:04 +00:00
|
|
|
SPI1W0 = x0;
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
2017-03-24 23:23:35 +00:00
|
|
|
|
2017-04-14 00:04:04 +00:00
|
|
|
SPI1W0 = x1 >> 0;
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
x1 = x1 << 8; // Use the waiting time to do something useful
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
2017-03-24 23:23:35 +00:00
|
|
|
|
2017-04-14 00:04:04 +00:00
|
|
|
SPI1W0 = x1;
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
2017-03-24 23:23:35 +00:00
|
|
|
|
|
|
|
// Row addr set
|
|
|
|
DC_C;
|
|
|
|
|
2017-04-14 00:04:04 +00:00
|
|
|
SPI1W0 = TFT_PASET<<(CMD_BITS + 1 - 8);
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
2017-03-24 23:23:35 +00:00
|
|
|
DC_D;
|
|
|
|
|
2017-04-14 00:04:04 +00:00
|
|
|
SPI1W0 = y0 >> 0;
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
y0 = y0 << 8; // Use the waiting time to do something useful
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
|
|
|
|
|
|
|
SPI1W0 = y0;
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
|
|
|
|
|
|
|
SPI1W0 = y1 >> 0;
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
y1 = y1 << 8; // Use the waiting time to do something useful
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
|
|
|
|
|
|
|
SPI1W0 = y1;
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
2017-03-24 23:23:35 +00:00
|
|
|
|
|
|
|
// write to RAM
|
|
|
|
DC_C;
|
|
|
|
|
2017-04-14 00:04:04 +00:00
|
|
|
SPI1W0 = TFT_RAMWR<<(CMD_BITS + 1 - 8);
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
2017-03-24 23:23:35 +00:00
|
|
|
|
|
|
|
DC_D;
|
|
|
|
|
2017-05-20 00:37:58 +00:00
|
|
|
//spi_end();
|
2017-03-24 23:23:35 +00:00
|
|
|
}
|
2017-04-14 00:04:04 +00:00
|
|
|
|
2017-05-20 00:37:58 +00:00
|
|
|
#else // This is for the ESP32
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
inline void TFT_eSPI::setAddrWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1)
|
|
|
|
{
|
2017-05-20 00:37:58 +00:00
|
|
|
//spi_begin();
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
addr_col = 0xFFFF;
|
|
|
|
addr_row = 0xFFFF;
|
|
|
|
|
2017-04-16 15:13:12 +00:00
|
|
|
#ifdef CGRAM_OFFSET
|
2017-02-22 03:07:17 +00:00
|
|
|
x0+=colstart;
|
|
|
|
x1+=colstart;
|
|
|
|
y0+=rowstart;
|
|
|
|
y1+=rowstart;
|
|
|
|
#endif
|
|
|
|
|
2017-06-16 14:17:28 +00:00
|
|
|
#if !defined (RPI_ILI9486_DRIVER)
|
2017-05-20 00:37:58 +00:00
|
|
|
uint32_t xaw = ((uint32_t)x0 << 16) | x1;
|
|
|
|
uint32_t yaw = ((uint32_t)y0 << 16) | y1;
|
2017-06-16 14:17:28 +00:00
|
|
|
#endif
|
2017-05-20 00:37:58 +00:00
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
// Column addr set
|
|
|
|
DC_C;
|
|
|
|
CS_L;
|
|
|
|
|
2018-03-12 22:49:18 +00:00
|
|
|
tft_Write_8(TFT_CASET);
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
DC_D;
|
|
|
|
|
2017-06-16 14:17:28 +00:00
|
|
|
#if defined (RPI_ILI9486_DRIVER)
|
|
|
|
uint8_t xBin[] = { 0, (uint8_t) (x0>>8), 0, (uint8_t) (x0>>0), 0, (uint8_t) (x1>>8), 0, (uint8_t) (x1>>0), };
|
|
|
|
SPI.writePattern(&xBin[0], 8, 1);
|
|
|
|
#else
|
2018-03-12 22:49:18 +00:00
|
|
|
tft_Write_32(xaw);
|
2017-06-16 14:17:28 +00:00
|
|
|
#endif
|
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
// Row addr set
|
|
|
|
DC_C;
|
2018-03-12 22:49:18 +00:00
|
|
|
tft_Write_8(TFT_PASET);
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
DC_D;
|
|
|
|
|
2017-06-16 14:17:28 +00:00
|
|
|
#if defined (RPI_ILI9486_DRIVER)
|
|
|
|
uint8_t yBin[] = { 0, (uint8_t) (y0>>8), 0, (uint8_t) (y0>>0), 0, (uint8_t) (y1>>8), 0, (uint8_t) (y1>>0), };
|
|
|
|
SPI.writePattern(&yBin[0], 8, 1);
|
|
|
|
#else
|
2018-03-12 22:49:18 +00:00
|
|
|
tft_Write_32(yaw);
|
2017-06-16 14:17:28 +00:00
|
|
|
#endif
|
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
// write to RAM
|
|
|
|
DC_C;
|
|
|
|
|
2018-03-12 22:49:18 +00:00
|
|
|
tft_Write_8(TFT_RAMWR);
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
DC_D;
|
|
|
|
|
2017-05-20 00:37:58 +00:00
|
|
|
//spi_end();
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
2017-03-24 23:23:35 +00:00
|
|
|
#endif // end RPI_ILI9486_DRIVER check
|
|
|
|
#endif // end ESP32 check
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
|
2017-03-11 16:59:34 +00:00
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: readAddrWindow
|
|
|
|
** Description: define an area to read a stream of pixels
|
|
|
|
***************************************************************************************/
|
|
|
|
// Chip select stays low
|
2017-03-27 01:15:30 +00:00
|
|
|
#if defined (ESP8266) && !defined (RPI_WRITE_STROBE)
|
2017-03-11 16:59:34 +00:00
|
|
|
void TFT_eSPI::readAddrWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye)
|
|
|
|
{
|
|
|
|
//spi_begin();
|
|
|
|
|
|
|
|
addr_col = 0xFFFF;
|
|
|
|
addr_row = 0xFFFF;
|
|
|
|
|
2017-04-16 15:13:12 +00:00
|
|
|
#ifdef CGRAM_OFFSET
|
2017-03-11 16:59:34 +00:00
|
|
|
xs+=colstart;
|
|
|
|
xe+=colstart;
|
|
|
|
ys+=rowstart;
|
|
|
|
ye+=rowstart;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Column addr set
|
|
|
|
DC_C;
|
|
|
|
CS_L;
|
|
|
|
|
|
|
|
uint32_t mask = ~((SPIMMOSI << SPILMOSI) | (SPIMMISO << SPILMISO));
|
|
|
|
mask = SPI1U1 & mask;
|
|
|
|
|
2017-03-24 23:23:35 +00:00
|
|
|
SPI1U1 = mask | (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO);
|
2017-03-11 16:59:34 +00:00
|
|
|
|
|
|
|
SPI1W0 = TFT_CASET;
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
|
|
|
|
|
|
|
DC_D;
|
|
|
|
|
|
|
|
SPI1U1 = mask | (31 << SPILMOSI) | (31 << SPILMISO);
|
|
|
|
// Load the two coords as a 32 bit value and shift in one go
|
|
|
|
SPI1W0 = (xs >> 8) | (uint16_t)(xs << 8) | ((uint8_t)(xe >> 8)<<16 | (xe << 24));
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
|
|
|
|
|
|
|
// Row addr set
|
|
|
|
DC_C;
|
|
|
|
|
2017-03-24 23:23:35 +00:00
|
|
|
SPI1U1 = mask | (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO);
|
2017-03-11 16:59:34 +00:00
|
|
|
|
|
|
|
SPI1W0 = TFT_PASET;
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
|
|
|
|
|
|
|
DC_D;
|
|
|
|
|
|
|
|
SPI1U1 = mask | (31 << SPILMOSI) | (31 << SPILMISO);
|
|
|
|
// Load the two coords as a 32 bit value and shift in one go
|
|
|
|
SPI1W0 = (ys >> 8) | (uint16_t)(ys << 8) | ((uint8_t)(ye >> 8)<<16 | (ye << 24));
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
|
|
|
|
|
|
|
// read from RAM
|
|
|
|
DC_C;
|
|
|
|
|
2017-03-24 23:23:35 +00:00
|
|
|
SPI1U1 = mask | (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO);
|
2017-03-11 16:59:34 +00:00
|
|
|
SPI1W0 = TFT_RAMRD;
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
|
|
|
|
|
|
|
DC_D;
|
|
|
|
//spi_end();
|
|
|
|
}
|
2017-03-24 23:23:35 +00:00
|
|
|
|
2017-05-20 00:37:58 +00:00
|
|
|
#else //ESP32
|
2017-03-11 16:59:34 +00:00
|
|
|
|
|
|
|
void TFT_eSPI::readAddrWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1)
|
|
|
|
{
|
|
|
|
//spi_begin();
|
|
|
|
|
|
|
|
addr_col = 0xFFFF;
|
|
|
|
addr_row = 0xFFFF;
|
|
|
|
|
2017-04-16 15:13:12 +00:00
|
|
|
#ifdef CGRAM_OFFSET
|
2017-03-11 16:59:34 +00:00
|
|
|
x0+=colstart;
|
|
|
|
x1+=colstart;
|
|
|
|
y0+=rowstart;
|
|
|
|
y1+=rowstart;
|
|
|
|
#endif
|
|
|
|
|
2017-05-20 00:37:58 +00:00
|
|
|
uint32_t xaw = ((uint32_t)x0 << 16) | x1;
|
|
|
|
uint32_t yaw = ((uint32_t)y0 << 16) | y1;
|
|
|
|
|
2017-03-11 16:59:34 +00:00
|
|
|
// Column addr set
|
|
|
|
DC_C;
|
|
|
|
CS_L;
|
|
|
|
|
2018-03-12 22:49:18 +00:00
|
|
|
tft_Write_8(TFT_CASET);
|
2018-03-10 23:08:57 +00:00
|
|
|
|
2017-03-11 16:59:34 +00:00
|
|
|
|
|
|
|
DC_D;
|
|
|
|
|
2018-03-12 22:49:18 +00:00
|
|
|
tft_Write_32(xaw);
|
2017-03-11 16:59:34 +00:00
|
|
|
|
|
|
|
// Row addr set
|
|
|
|
DC_C;
|
|
|
|
|
2018-03-12 22:49:18 +00:00
|
|
|
tft_Write_8(TFT_PASET);
|
2017-03-11 16:59:34 +00:00
|
|
|
|
|
|
|
DC_D;
|
|
|
|
|
2018-03-12 22:49:18 +00:00
|
|
|
tft_Write_32(yaw);
|
2017-05-20 00:37:58 +00:00
|
|
|
|
2017-03-11 16:59:34 +00:00
|
|
|
DC_C;
|
2018-03-12 22:49:18 +00:00
|
|
|
tft_Write_8(TFT_RAMRD); // Read CGRAM command
|
2018-03-10 23:08:57 +00:00
|
|
|
|
2017-03-11 16:59:34 +00:00
|
|
|
DC_D;
|
|
|
|
|
|
|
|
//spi_end();
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: drawPixel
|
|
|
|
** Description: push a single pixel at an arbitrary position
|
|
|
|
***************************************************************************************/
|
2017-03-27 01:15:30 +00:00
|
|
|
#if defined (ESP8266) && !defined (RPI_WRITE_STROBE)
|
2017-02-22 03:07:17 +00:00
|
|
|
void TFT_eSPI::drawPixel(uint32_t x, uint32_t y, uint32_t color)
|
|
|
|
{
|
|
|
|
// Faster range checking, possible because x and y are unsigned
|
|
|
|
if ((x >= _width) || (y >= _height)) return;
|
|
|
|
|
2017-04-16 15:13:12 +00:00
|
|
|
#ifdef CGRAM_OFFSET
|
2017-02-22 03:07:17 +00:00
|
|
|
x+=colstart;
|
|
|
|
y+=rowstart;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
spi_begin();
|
|
|
|
|
|
|
|
CS_L;
|
|
|
|
|
|
|
|
uint32_t mask = ~((SPIMMOSI << SPILMOSI) | (SPIMMISO << SPILMISO));
|
|
|
|
mask = SPI1U1 & mask;
|
|
|
|
// No need to send x if it has not changed (speeds things up)
|
|
|
|
if (addr_col != x) {
|
|
|
|
|
|
|
|
DC_C;
|
|
|
|
|
2017-03-24 23:23:35 +00:00
|
|
|
SPI1U1 = mask | (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO);
|
|
|
|
SPI1W0 = TFT_CASET<<(CMD_BITS + 1 - 8);
|
2017-02-22 03:07:17 +00:00
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
|
|
|
|
|
|
|
DC_D;
|
|
|
|
|
2017-03-24 23:23:35 +00:00
|
|
|
#if defined (RPI_ILI9486_DRIVER) // This is for the RPi display that needs 16 bits per byte
|
|
|
|
uint8_t cBin[] = { 0, (uint8_t) (x>>8), 0, (uint8_t) (x>>0)};
|
|
|
|
SPI.writePattern(&cBin[0], 4, 2);
|
|
|
|
#else
|
2017-02-22 03:07:17 +00:00
|
|
|
SPI1U1 = mask | (31 << SPILMOSI) | (31 << SPILMISO);
|
|
|
|
// Load the two coords as a 32 bit value and shift in one go
|
2017-04-14 00:04:04 +00:00
|
|
|
uint32_t xswap = (x >> 8) | (uint16_t)(x << 8);
|
2017-02-22 03:07:17 +00:00
|
|
|
SPI1W0 = xswap | (xswap << 16);
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
2017-03-24 23:23:35 +00:00
|
|
|
#endif
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
addr_col = x;
|
|
|
|
}
|
|
|
|
|
|
|
|
// No need to send y if it has not changed (speeds things up)
|
|
|
|
if (addr_row != y) {
|
|
|
|
|
|
|
|
DC_C;
|
|
|
|
|
2017-03-24 23:23:35 +00:00
|
|
|
SPI1U1 = mask | (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO);
|
2017-02-22 03:07:17 +00:00
|
|
|
|
2017-03-24 23:23:35 +00:00
|
|
|
SPI1W0 = TFT_PASET<<(CMD_BITS + 1 - 8);
|
2017-02-22 03:07:17 +00:00
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
2017-03-24 23:23:35 +00:00
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
DC_D;
|
|
|
|
|
2017-03-24 23:23:35 +00:00
|
|
|
#if defined (RPI_ILI9486_DRIVER) // This is for the RPi display that needs 16 bits per byte
|
|
|
|
uint8_t cBin[] = { 0, (uint8_t) (y>>8), 0, (uint8_t) (y>>0)};
|
|
|
|
SPI.writePattern(&cBin[0], 4, 2);
|
|
|
|
#else
|
2017-02-22 03:07:17 +00:00
|
|
|
SPI1U1 = mask | (31 << SPILMOSI) | (31 << SPILMISO);
|
|
|
|
// Load the two coords as a 32 bit value and shift in one go
|
2017-04-14 00:04:04 +00:00
|
|
|
uint32_t yswap = (y >> 8) | (uint16_t)(y << 8);
|
2017-02-22 03:07:17 +00:00
|
|
|
SPI1W0 = yswap | (yswap << 16);
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
2017-03-24 23:23:35 +00:00
|
|
|
#endif
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
addr_row = y;
|
|
|
|
}
|
|
|
|
|
|
|
|
DC_C;
|
|
|
|
|
2017-03-24 23:23:35 +00:00
|
|
|
SPI1U1 = mask | (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO);
|
2017-02-22 03:07:17 +00:00
|
|
|
|
2017-03-24 23:23:35 +00:00
|
|
|
SPI1W0 = TFT_RAMWR<<(CMD_BITS + 1 - 8);
|
2017-02-22 03:07:17 +00:00
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
|
|
|
|
|
|
|
DC_D;
|
|
|
|
|
2018-07-07 21:41:53 +00:00
|
|
|
#if defined (ILI9488_DRIVER)
|
|
|
|
tft_Write_16(color);
|
|
|
|
#else
|
2017-02-22 03:07:17 +00:00
|
|
|
SPI1U1 = mask | (15 << SPILMOSI) | (15 << SPILMISO);
|
|
|
|
|
|
|
|
SPI1W0 = (color >> 8) | (color << 8);
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
2018-07-07 21:41:53 +00:00
|
|
|
#endif
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
CS_H;
|
|
|
|
|
|
|
|
spi_end();
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
2017-05-20 00:37:58 +00:00
|
|
|
#if defined (ESP8266) && defined (RPI_ILI9486_DRIVER) // This is for the RPi display that needs 16 bits
|
2017-03-24 23:23:35 +00:00
|
|
|
|
|
|
|
void TFT_eSPI::drawPixel(uint32_t x, uint32_t y, uint32_t color)
|
|
|
|
{
|
|
|
|
// Faster range checking, possible because x and y are unsigned
|
|
|
|
if ((x >= _width) || (y >= _height)) return;
|
|
|
|
spi_begin();
|
|
|
|
|
|
|
|
CS_L;
|
2017-03-27 01:15:30 +00:00
|
|
|
uint32_t mask = ~((SPIMMOSI << SPILMOSI) | (SPIMMISO << SPILMISO));
|
|
|
|
mask = SPI1U1 & mask;
|
|
|
|
SPI1U1 = mask | (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO);
|
2017-03-24 23:23:35 +00:00
|
|
|
// No need to send x if it has not changed (speeds things up)
|
|
|
|
if (addr_col != x) {
|
|
|
|
DC_C;
|
|
|
|
|
2017-03-27 01:15:30 +00:00
|
|
|
SPI1W0 = TFT_CASET<<(CMD_BITS + 1 - 8);
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
2017-03-24 23:23:35 +00:00
|
|
|
DC_D;
|
|
|
|
|
2017-03-27 01:15:30 +00:00
|
|
|
SPI1W0 = x >> 0;
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
2017-04-14 00:04:04 +00:00
|
|
|
|
2017-03-27 01:15:30 +00:00
|
|
|
SPI1W0 = x << 8;
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
2017-04-14 00:04:04 +00:00
|
|
|
|
2017-03-27 01:15:30 +00:00
|
|
|
SPI1W0 = x >> 0;
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
2017-04-14 00:04:04 +00:00
|
|
|
|
2017-03-27 01:15:30 +00:00
|
|
|
SPI1W0 = x << 8;
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
2017-04-14 00:04:04 +00:00
|
|
|
|
2017-03-24 23:23:35 +00:00
|
|
|
addr_col = x;
|
|
|
|
}
|
|
|
|
|
|
|
|
// No need to send y if it has not changed (speeds things up)
|
|
|
|
if (addr_row != y) {
|
|
|
|
DC_C;
|
|
|
|
|
2017-03-27 01:15:30 +00:00
|
|
|
SPI1W0 = TFT_PASET<<(CMD_BITS + 1 - 8);
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
2017-03-24 23:23:35 +00:00
|
|
|
DC_D;
|
|
|
|
|
2017-03-27 01:15:30 +00:00
|
|
|
SPI1W0 = y >> 0;
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
2017-04-14 00:04:04 +00:00
|
|
|
|
2017-03-27 01:15:30 +00:00
|
|
|
SPI1W0 = y << 8;
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
2017-04-14 00:04:04 +00:00
|
|
|
|
2017-03-27 01:15:30 +00:00
|
|
|
SPI1W0 = y >> 0;
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
2017-04-14 00:04:04 +00:00
|
|
|
|
2017-03-27 01:15:30 +00:00
|
|
|
SPI1W0 = y << 8;
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
2017-04-14 00:04:04 +00:00
|
|
|
|
2017-03-24 23:23:35 +00:00
|
|
|
addr_row = y;
|
|
|
|
}
|
|
|
|
|
|
|
|
DC_C;
|
|
|
|
|
2017-03-27 01:15:30 +00:00
|
|
|
SPI1W0 = TFT_RAMWR<<(CMD_BITS + 1 - 8);
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
2017-03-24 23:23:35 +00:00
|
|
|
|
|
|
|
DC_D;
|
|
|
|
|
2017-03-27 01:15:30 +00:00
|
|
|
SPI1W0 = (color >> 8) | (color << 8);
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
2017-03-24 23:23:35 +00:00
|
|
|
|
|
|
|
CS_H;
|
|
|
|
|
|
|
|
spi_end();
|
|
|
|
}
|
|
|
|
|
2017-05-20 00:37:58 +00:00
|
|
|
#else // ESP32
|
2017-03-24 23:23:35 +00:00
|
|
|
|
|
|
|
void TFT_eSPI::drawPixel(uint32_t x, uint32_t y, uint32_t color)
|
2017-02-22 03:07:17 +00:00
|
|
|
{
|
|
|
|
// Faster range checking, possible because x and y are unsigned
|
|
|
|
if ((x >= _width) || (y >= _height)) return;
|
|
|
|
spi_begin();
|
|
|
|
|
2017-04-16 15:13:12 +00:00
|
|
|
#ifdef CGRAM_OFFSET
|
2017-02-22 03:07:17 +00:00
|
|
|
x+=colstart;
|
|
|
|
y+=rowstart;
|
|
|
|
#endif
|
|
|
|
|
2017-06-16 14:17:28 +00:00
|
|
|
#if !defined (RPI_ILI9486_DRIVER)
|
2017-05-20 00:37:58 +00:00
|
|
|
uint32_t xaw = ((uint32_t)x << 16) | x;
|
|
|
|
uint32_t yaw = ((uint32_t)y << 16) | y;
|
2017-06-16 14:17:28 +00:00
|
|
|
#endif
|
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
CS_L;
|
|
|
|
|
|
|
|
// No need to send x if it has not changed (speeds things up)
|
|
|
|
if (addr_col != x) {
|
|
|
|
|
|
|
|
DC_C;
|
|
|
|
|
2018-03-12 22:49:18 +00:00
|
|
|
tft_Write_8(TFT_CASET);
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
DC_D;
|
|
|
|
|
2017-06-16 14:17:28 +00:00
|
|
|
#if defined (RPI_ILI9486_DRIVER)
|
|
|
|
uint8_t xBin[] = { 0, (uint8_t) (x>>8), 0, (uint8_t) (x>>0), 0, (uint8_t) (x>>8), 0, (uint8_t) (x>>0), };
|
|
|
|
SPI.writePattern(&xBin[0], 8, 1);
|
|
|
|
#else
|
2018-03-12 22:49:18 +00:00
|
|
|
tft_Write_32(xaw);
|
2017-06-16 14:17:28 +00:00
|
|
|
#endif
|
2017-05-20 00:37:58 +00:00
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
addr_col = x;
|
|
|
|
}
|
|
|
|
|
|
|
|
// No need to send y if it has not changed (speeds things up)
|
|
|
|
if (addr_row != y) {
|
|
|
|
|
|
|
|
DC_C;
|
|
|
|
|
2018-03-12 22:49:18 +00:00
|
|
|
tft_Write_8(TFT_PASET);
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
DC_D;
|
|
|
|
|
2017-06-16 14:17:28 +00:00
|
|
|
#if defined (RPI_ILI9486_DRIVER)
|
|
|
|
uint8_t yBin[] = { 0, (uint8_t) (y>>8), 0, (uint8_t) (y>>0), 0, (uint8_t) (y>>8), 0, (uint8_t) (y>>0), };
|
|
|
|
SPI.writePattern(&yBin[0], 8, 1);
|
|
|
|
#else
|
2018-03-12 22:49:18 +00:00
|
|
|
tft_Write_32(yaw);
|
2017-06-16 14:17:28 +00:00
|
|
|
#endif
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
addr_row = y;
|
|
|
|
}
|
|
|
|
|
|
|
|
DC_C;
|
|
|
|
|
2018-03-12 22:49:18 +00:00
|
|
|
tft_Write_8(TFT_RAMWR);
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
DC_D;
|
|
|
|
|
2018-03-12 22:49:18 +00:00
|
|
|
tft_Write_16(color);
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
CS_H;
|
|
|
|
|
|
|
|
spi_end();
|
|
|
|
}
|
2017-03-24 23:23:35 +00:00
|
|
|
#endif
|
2017-02-22 03:07:17 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: pushColor
|
|
|
|
** Description: push a single pixel
|
|
|
|
***************************************************************************************/
|
|
|
|
void TFT_eSPI::pushColor(uint16_t color)
|
|
|
|
{
|
|
|
|
spi_begin();
|
|
|
|
|
|
|
|
CS_L;
|
2018-03-10 23:08:57 +00:00
|
|
|
|
2018-03-12 22:49:18 +00:00
|
|
|
tft_Write_16(color);
|
2018-03-10 23:08:57 +00:00
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
CS_H;
|
|
|
|
|
|
|
|
spi_end();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: pushColor
|
|
|
|
** Description: push a single colour to "len" pixels
|
|
|
|
***************************************************************************************/
|
|
|
|
void TFT_eSPI::pushColor(uint16_t color, uint16_t len)
|
|
|
|
{
|
|
|
|
spi_begin();
|
|
|
|
|
|
|
|
CS_L;
|
|
|
|
|
2017-03-27 01:15:30 +00:00
|
|
|
#ifdef RPI_WRITE_STROBE
|
2017-04-23 17:50:53 +00:00
|
|
|
uint8_t colorBin[] = { (uint8_t) (color >> 8), (uint8_t) color };
|
2017-03-27 01:15:30 +00:00
|
|
|
if(len) SPI.writePattern(&colorBin[0], 2, 1); len--;
|
|
|
|
while(len--) {WR_L; WR_H;}
|
|
|
|
#else
|
2018-07-07 21:41:53 +00:00
|
|
|
#if defined (ESP32_PARALLEL)
|
2018-03-12 22:49:18 +00:00
|
|
|
while (len--) {tft_Write_16(color);}
|
2018-03-10 23:08:57 +00:00
|
|
|
#else
|
|
|
|
writeBlock(color, len);
|
|
|
|
#endif
|
2017-03-27 01:15:30 +00:00
|
|
|
#endif
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
CS_H;
|
|
|
|
|
|
|
|
spi_end();
|
|
|
|
}
|
|
|
|
|
2018-01-27 13:46:59 +00:00
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: pushColors
|
2018-02-24 19:02:20 +00:00
|
|
|
** Description: push an array of pixels for 16 bit raw image drawing
|
2018-01-27 13:46:59 +00:00
|
|
|
***************************************************************************************/
|
|
|
|
// Assumed that setWindow() has previously been called
|
|
|
|
|
|
|
|
void TFT_eSPI::pushColors(uint8_t *data, uint32_t len)
|
|
|
|
{
|
|
|
|
spi_begin();
|
|
|
|
|
|
|
|
CS_L;
|
|
|
|
|
|
|
|
#if defined (RPI_WRITE_STROBE)
|
|
|
|
while ( len >=64 ) {SPI.writePattern(data, 64, 1); data += 64; len -= 64; }
|
|
|
|
if (len) SPI.writePattern(data, len, 1);
|
|
|
|
#else
|
2018-03-10 23:08:57 +00:00
|
|
|
#ifdef ESP32_PARALLEL
|
2018-03-12 22:49:18 +00:00
|
|
|
while (len--) {tft_Write_8(*data); data++;}
|
2018-07-07 21:41:53 +00:00
|
|
|
#elif defined (ILI9488_DRIVER)
|
|
|
|
uint16_t color;
|
|
|
|
while (len>1) {color = (*data++) | ((*data++)<<8); tft_Write_16(color); len-=2;}
|
2018-01-27 13:46:59 +00:00
|
|
|
#else
|
2018-03-10 23:08:57 +00:00
|
|
|
#if (SPI_FREQUENCY == 80000000)
|
|
|
|
while ( len >=64 ) {SPI.writePattern(data, 64, 1); data += 64; len -= 64; }
|
|
|
|
if (len) SPI.writePattern(data, len, 1);
|
|
|
|
#else
|
|
|
|
SPI.writeBytes(data, len);
|
|
|
|
#endif
|
2018-01-27 13:46:59 +00:00
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
CS_H;
|
|
|
|
|
|
|
|
spi_end();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-01-08 23:19:42 +00:00
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: pushColors
|
|
|
|
** Description: push an array of pixels, for image drawing
|
|
|
|
***************************************************************************************/
|
|
|
|
void TFT_eSPI::pushColors(uint16_t *data, uint32_t len, bool swap)
|
|
|
|
{
|
|
|
|
spi_begin();
|
|
|
|
|
|
|
|
CS_L;
|
|
|
|
|
2018-07-07 21:41:53 +00:00
|
|
|
#if defined (ESP32) || defined (ILI9488_DRIVER)
|
|
|
|
#if defined (ESP32_PARALLEL) || defined (ILI9488_DRIVER)
|
2018-03-12 22:49:18 +00:00
|
|
|
if (swap) while ( len-- ) {tft_Write_16(*data); data++;}
|
2018-03-26 00:02:23 +00:00
|
|
|
else while ( len-- ) {tft_Write_16S(*data); data++;}
|
2018-03-10 23:08:57 +00:00
|
|
|
#else
|
|
|
|
if (swap) SPI.writePixels(data,len<<1);
|
|
|
|
else SPI.writeBytes((uint8_t*)data,len<<1);
|
|
|
|
#endif
|
2018-01-08 23:19:42 +00:00
|
|
|
#else
|
|
|
|
|
|
|
|
uint32_t color[8];
|
|
|
|
|
|
|
|
uint32_t mask = ~((SPIMMOSI << SPILMOSI) | (SPIMMISO << SPILMISO));
|
|
|
|
|
|
|
|
SPI1U1 = (SPI1U1 & mask) | (255 << SPILMOSI) | (255 << SPILMISO);
|
|
|
|
|
|
|
|
while(len>15)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (swap)
|
|
|
|
{
|
|
|
|
uint32_t i = 0;
|
|
|
|
while(i<8)
|
|
|
|
{
|
|
|
|
color[i] = (*data >> 8) | (uint16_t)(*data << 8);
|
|
|
|
data++;
|
|
|
|
color[i] |= ((*data >> 8) | (*data << 8)) << 16;
|
|
|
|
data++;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
memcpy(color,data,32);
|
|
|
|
data+=16;
|
|
|
|
}
|
|
|
|
|
|
|
|
len -= 16;
|
2018-03-26 00:02:23 +00:00
|
|
|
|
|
|
|
// ESP8266 wait time here at 40MHz SPI is ~5.45us
|
2018-01-08 23:19:42 +00:00
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
|
|
|
SPI1W0 = color[0];
|
|
|
|
SPI1W1 = color[1];
|
|
|
|
SPI1W2 = color[2];
|
|
|
|
SPI1W3 = color[3];
|
|
|
|
SPI1W4 = color[4];
|
|
|
|
SPI1W5 = color[5];
|
|
|
|
SPI1W6 = color[6];
|
|
|
|
SPI1W7 = color[7];
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(len)
|
|
|
|
{
|
|
|
|
uint32_t bits = (len*16-1); // bits left to shift - 1
|
|
|
|
if (swap)
|
|
|
|
{
|
|
|
|
uint16_t* ptr = (uint16_t*)color;
|
|
|
|
while(len--)
|
|
|
|
{
|
|
|
|
*ptr++ = (*(data) >> 8) | (uint16_t)(*(data) << 8);
|
|
|
|
data++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
memcpy(color,data,len<<1);
|
|
|
|
}
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
|
|
|
SPI1U1 = (SPI1U1 & mask) | (bits << SPILMOSI) | (bits << SPILMISO);
|
|
|
|
SPI1W0 = color[0];
|
|
|
|
SPI1W1 = color[1];
|
|
|
|
SPI1W2 = color[2];
|
|
|
|
SPI1W3 = color[3];
|
|
|
|
SPI1W4 = color[4];
|
|
|
|
SPI1W5 = color[5];
|
|
|
|
SPI1W6 = color[6];
|
|
|
|
SPI1W7 = color[7];
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
}
|
|
|
|
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
CS_H;
|
|
|
|
|
|
|
|
spi_end();
|
|
|
|
}
|
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: drawLine
|
|
|
|
** Description: draw a line between 2 arbitrary points
|
|
|
|
***************************************************************************************/
|
|
|
|
// Bresenham's algorithm - thx wikipedia - speed enhanced by Bodmer to use
|
2018-02-22 22:33:49 +00:00
|
|
|
// an efficient FastH/V Line draw routine for line segments of 2 pixels or more
|
2017-02-22 03:07:17 +00:00
|
|
|
|
2018-07-07 21:41:53 +00:00
|
|
|
#if defined (RPI_ILI9486_DRIVER) || defined (ESP32) || defined (RPI_WRITE_STROBE) || defined (HX8357D_DRIVER) || defined (ILI9488_DRIVER)
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
void TFT_eSPI::drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t color)
|
|
|
|
{
|
2017-05-20 00:37:58 +00:00
|
|
|
spi_begin();
|
|
|
|
inTransaction = true;
|
2017-02-22 03:07:17 +00:00
|
|
|
boolean steep = abs(y1 - y0) > abs(x1 - x0);
|
|
|
|
if (steep) {
|
2017-04-12 23:20:19 +00:00
|
|
|
swap_coord(x0, y0);
|
|
|
|
swap_coord(x1, y1);
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (x0 > x1) {
|
2017-04-12 23:20:19 +00:00
|
|
|
swap_coord(x0, x1);
|
|
|
|
swap_coord(y0, y1);
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int32_t dx = x1 - x0, dy = abs(y1 - y0);;
|
|
|
|
|
|
|
|
int32_t err = dx >> 1, ystep = -1, xs = x0, dlen = 0;
|
|
|
|
|
|
|
|
if (y0 < y1) ystep = 1;
|
|
|
|
|
|
|
|
// Split into steep and not steep for FastH/V separation
|
|
|
|
if (steep) {
|
|
|
|
for (; x0 <= x1; x0++) {
|
|
|
|
dlen++;
|
|
|
|
err -= dy;
|
|
|
|
if (err < 0) {
|
|
|
|
err += dx;
|
|
|
|
if (dlen == 1) drawPixel(y0, xs, color);
|
|
|
|
else drawFastVLine(y0, xs, dlen, color);
|
|
|
|
dlen = 0; y0 += ystep; xs = x0 + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (dlen) drawFastVLine(y0, xs, dlen, color);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (; x0 <= x1; x0++) {
|
|
|
|
dlen++;
|
|
|
|
err -= dy;
|
|
|
|
if (err < 0) {
|
|
|
|
err += dx;
|
|
|
|
if (dlen == 1) drawPixel(xs, y0, color);
|
|
|
|
else drawFastHLine(xs, y0, dlen, color);
|
|
|
|
dlen = 0; y0 += ystep; xs = x0 + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (dlen) drawFastHLine(xs, y0, dlen, color);
|
|
|
|
}
|
2017-05-20 00:37:58 +00:00
|
|
|
inTransaction = false;
|
|
|
|
spi_end();
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
// This is a weeny bit faster
|
|
|
|
void TFT_eSPI::drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t color)
|
|
|
|
{
|
|
|
|
|
|
|
|
boolean steep = abs(y1 - y0) > abs(x1 - x0);
|
|
|
|
|
2017-04-14 00:04:04 +00:00
|
|
|
if (steep) {
|
|
|
|
swap_coord(x0, y0);
|
|
|
|
swap_coord(x1, y1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (x0 > x1) {
|
|
|
|
swap_coord(x0, x1);
|
|
|
|
swap_coord(y0, y1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (x1 < 0) return;
|
|
|
|
|
|
|
|
int16_t dx, dy;
|
|
|
|
dx = x1 - x0;
|
|
|
|
dy = abs(y1 - y0);
|
|
|
|
|
|
|
|
int16_t err = dx / 2;
|
|
|
|
int8_t ystep = (y0 < y1) ? 1 : (-1);
|
|
|
|
|
2018-01-08 23:19:42 +00:00
|
|
|
spi_begin();
|
|
|
|
|
2017-04-14 00:04:04 +00:00
|
|
|
uint32_t mask = ~((SPIMMOSI << SPILMOSI) | (SPIMMISO << SPILMISO));
|
|
|
|
mask = (SPI1U1 & mask) | (15 << SPILMOSI) | (15 << SPILMISO);
|
2017-04-23 17:50:53 +00:00
|
|
|
SPI1U = SPIUMOSI | SPIUSSE;
|
2017-04-14 00:04:04 +00:00
|
|
|
int16_t swapped_color = (color >> 8) | (color << 8);
|
|
|
|
|
|
|
|
if (steep) // y increments every iteration (y0 is x-axis, and x0 is y-axis)
|
|
|
|
{
|
|
|
|
if (x1 >= _height) x1 = _height - 1;
|
|
|
|
|
|
|
|
for (; x0 <= x1; x0++) {
|
|
|
|
if ((x0 >= 0) && (y0 >= 0) && (y0 < _width)) break;
|
|
|
|
err -= dy;
|
|
|
|
if (err < 0) {
|
|
|
|
err += dx;
|
|
|
|
y0 += ystep;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-08 23:19:42 +00:00
|
|
|
if (x0 > x1) {spi_end(); return;}
|
2017-04-14 00:04:04 +00:00
|
|
|
|
|
|
|
setAddrWindow(y0, x0, y0, _height);
|
|
|
|
SPI1U1 = mask;
|
2017-04-23 17:50:53 +00:00
|
|
|
SPI1W0 = swapped_color;
|
2017-04-14 00:04:04 +00:00
|
|
|
for (; x0 <= x1; x0++) {
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
|
|
|
|
err -= dy;
|
|
|
|
if (err < 0) {
|
|
|
|
y0 += ystep;
|
|
|
|
if ((y0 < 0) || (y0 >= _width)) break;
|
|
|
|
err += dx;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
|
|
|
setAddrWindow(y0, x0+1, y0, _height);
|
|
|
|
SPI1U1 = mask;
|
2017-04-23 17:50:53 +00:00
|
|
|
SPI1W0 = swapped_color;
|
2017-04-14 00:04:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else // x increments every iteration (x0 is x-axis, and y0 is y-axis)
|
|
|
|
{
|
|
|
|
if (x1 >= _width) x1 = _width - 1;
|
|
|
|
|
|
|
|
for (; x0 <= x1; x0++) {
|
|
|
|
if ((x0 >= 0) && (y0 >= 0) && (y0 < _height)) break;
|
|
|
|
err -= dy;
|
|
|
|
if (err < 0) {
|
|
|
|
err += dx;
|
|
|
|
y0 += ystep;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-08 23:19:42 +00:00
|
|
|
if (x0 > x1) {spi_end(); return;}
|
2017-04-14 00:04:04 +00:00
|
|
|
|
|
|
|
setAddrWindow(x0, y0, _width, y0);
|
|
|
|
SPI1U1 = mask;
|
2017-04-23 17:50:53 +00:00
|
|
|
SPI1W0 = swapped_color;
|
2017-04-14 00:04:04 +00:00
|
|
|
for (; x0 <= x1; x0++) {
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
|
|
|
|
err -= dy;
|
|
|
|
if (err < 0) {
|
|
|
|
y0 += ystep;
|
|
|
|
if ((y0 < 0) || (y0 >= _height)) break;
|
|
|
|
err += dx;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
|
|
|
setAddrWindow(x0+1, y0, _width, y0);
|
|
|
|
SPI1U1 = mask;
|
2018-01-08 23:19:42 +00:00
|
|
|
SPI1W0 = swapped_color;
|
2017-04-14 00:04:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
2017-04-23 17:50:53 +00:00
|
|
|
SPI1U = SPIUMOSI | SPIUDUPLEX | SPIUSSE;
|
2017-04-14 00:04:04 +00:00
|
|
|
CS_H;
|
2017-02-22 03:07:17 +00:00
|
|
|
spi_end();
|
|
|
|
}
|
2018-01-08 23:19:42 +00:00
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: drawFastVLine
|
|
|
|
** Description: draw a vertical line
|
|
|
|
***************************************************************************************/
|
2017-03-27 01:15:30 +00:00
|
|
|
#if defined (ESP8266) && !defined (RPI_WRITE_STROBE)
|
2017-02-22 03:07:17 +00:00
|
|
|
void TFT_eSPI::drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color)
|
|
|
|
{
|
|
|
|
// Rudimentary clipping
|
|
|
|
if ((x >= _width) || (y >= _height) || (h < 1)) return;
|
|
|
|
if ((y + h - 1) >= _height) h = _height - y;
|
|
|
|
|
|
|
|
spi_begin();
|
|
|
|
|
|
|
|
setAddrWindow(x, y, x, y + h - 1);
|
|
|
|
|
2018-03-10 23:08:57 +00:00
|
|
|
writeBlock(color, h);
|
2017-04-23 17:50:53 +00:00
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
CS_H;
|
|
|
|
|
|
|
|
spi_end();
|
|
|
|
}
|
2017-04-14 00:04:04 +00:00
|
|
|
|
2017-03-27 01:15:30 +00:00
|
|
|
#else
|
2017-04-14 00:04:04 +00:00
|
|
|
|
2017-03-27 01:15:30 +00:00
|
|
|
void TFT_eSPI::drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color)
|
|
|
|
{
|
|
|
|
// Rudimentary clipping
|
|
|
|
if ((x >= _width) || (y >= _height) || (h < 1)) return;
|
|
|
|
if ((y + h - 1) >= _height) h = _height - y;
|
|
|
|
|
|
|
|
spi_begin();
|
2017-02-22 03:07:17 +00:00
|
|
|
|
2017-03-27 01:15:30 +00:00
|
|
|
setAddrWindow(x, y, x, y + h - 1);
|
2017-04-14 00:04:04 +00:00
|
|
|
|
2017-03-27 01:15:30 +00:00
|
|
|
#ifdef RPI_WRITE_STROBE
|
2017-05-20 00:37:58 +00:00
|
|
|
#if defined (ESP8266)
|
2018-03-10 23:08:57 +00:00
|
|
|
// SPI1U1 will already be set to transfer 16 bits by setAddrWindow()
|
2017-05-20 00:37:58 +00:00
|
|
|
SPI1W0 = (color >> 8) | (color << 8);
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
|
|
|
#else
|
2018-03-12 22:49:18 +00:00
|
|
|
tft_Write_16(color);
|
2017-05-20 00:37:58 +00:00
|
|
|
#endif
|
2018-03-10 23:08:57 +00:00
|
|
|
h--;
|
|
|
|
while(h--) {WR_L; WR_H;}
|
2017-03-27 01:15:30 +00:00
|
|
|
#else
|
2018-03-10 23:08:57 +00:00
|
|
|
#ifdef ESP32_PARALLEL
|
2018-03-12 22:49:18 +00:00
|
|
|
while (h--) {tft_Write_16(color);}
|
2018-03-10 23:08:57 +00:00
|
|
|
#else
|
|
|
|
writeBlock(color, h);
|
|
|
|
#endif
|
2017-03-27 01:15:30 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
CS_H;
|
|
|
|
|
|
|
|
spi_end();
|
|
|
|
}
|
|
|
|
#endif
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: drawFastHLine
|
|
|
|
** Description: draw a horizontal line
|
|
|
|
***************************************************************************************/
|
2017-03-27 01:15:30 +00:00
|
|
|
#if defined (ESP8266) && !defined (RPI_WRITE_STROBE)
|
2017-02-22 03:07:17 +00:00
|
|
|
void TFT_eSPI::drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color)
|
|
|
|
{
|
|
|
|
// Rudimentary clipping
|
|
|
|
if ((x >= _width) || (y >= _height) || (w < 1)) return;
|
|
|
|
if ((x + w - 1) >= _width) w = _width - x;
|
|
|
|
|
|
|
|
spi_begin();
|
|
|
|
|
|
|
|
setAddrWindow(x, y, x + w - 1, y);
|
|
|
|
|
2018-03-10 23:08:57 +00:00
|
|
|
writeBlock(color, w);
|
2017-04-23 17:50:53 +00:00
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
CS_H;
|
|
|
|
|
|
|
|
spi_end();
|
|
|
|
}
|
2017-04-14 00:04:04 +00:00
|
|
|
|
2017-03-27 01:15:30 +00:00
|
|
|
#else
|
2017-04-14 00:04:04 +00:00
|
|
|
|
2017-03-27 01:15:30 +00:00
|
|
|
void TFT_eSPI::drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color)
|
|
|
|
{
|
|
|
|
// Rudimentary clipping
|
|
|
|
if ((x >= _width) || (y >= _height) || (w < 1)) return;
|
|
|
|
if ((x + w - 1) >= _width) w = _width - x;
|
2017-02-22 03:07:17 +00:00
|
|
|
|
2017-03-27 01:15:30 +00:00
|
|
|
spi_begin();
|
|
|
|
setAddrWindow(x, y, x + w - 1, y);
|
|
|
|
|
|
|
|
#ifdef RPI_WRITE_STROBE
|
2017-05-20 00:37:58 +00:00
|
|
|
#if defined (ESP8266)
|
2018-03-10 23:08:57 +00:00
|
|
|
// SPI1U1 will already be set to transfer 16 bits by setAddrWindow()
|
2017-05-20 00:37:58 +00:00
|
|
|
SPI1W0 = (color >> 8) | (color << 8);
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
|
|
|
#else
|
2018-03-12 22:49:18 +00:00
|
|
|
tft_Write_16(color);
|
2017-05-20 00:37:58 +00:00
|
|
|
#endif
|
2018-03-10 23:08:57 +00:00
|
|
|
w--;
|
|
|
|
while(w--) {WR_L; WR_H;}
|
2017-03-27 01:15:30 +00:00
|
|
|
#else
|
2018-03-10 23:08:57 +00:00
|
|
|
#ifdef ESP32_PARALLEL
|
2018-03-12 22:49:18 +00:00
|
|
|
while (w--) {tft_Write_16(color);}
|
2018-03-10 23:08:57 +00:00
|
|
|
#else
|
|
|
|
writeBlock(color, w);
|
|
|
|
#endif
|
2017-03-27 01:15:30 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
CS_H;
|
|
|
|
|
|
|
|
spi_end();
|
|
|
|
}
|
|
|
|
#endif
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: fillRect
|
|
|
|
** Description: draw a filled rectangle
|
|
|
|
***************************************************************************************/
|
2017-03-27 01:15:30 +00:00
|
|
|
#if defined (ESP8266) && !defined (RPI_WRITE_STROBE)
|
2018-01-27 02:35:25 +00:00
|
|
|
void TFT_eSPI::fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color)
|
2017-02-22 03:07:17 +00:00
|
|
|
{
|
|
|
|
// rudimentary clipping (drawChar w/big text requires this)
|
|
|
|
if ((x > _width) || (y > _height) || (w < 1) || (h < 1)) return;
|
|
|
|
if ((x + w - 1) > _width) w = _width - x;
|
|
|
|
if ((y + h - 1) > _height) h = _height - y;
|
|
|
|
|
|
|
|
spi_begin();
|
|
|
|
setAddrWindow(x, y, x + w - 1, y + h - 1);
|
|
|
|
|
2018-03-10 23:08:57 +00:00
|
|
|
writeBlock(color, w * h);
|
2017-04-23 17:50:53 +00:00
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
CS_H;
|
|
|
|
|
|
|
|
spi_end();
|
|
|
|
}
|
2017-04-14 00:04:04 +00:00
|
|
|
|
2017-03-27 01:15:30 +00:00
|
|
|
#else
|
2017-04-14 00:04:04 +00:00
|
|
|
|
2018-01-27 02:35:25 +00:00
|
|
|
void TFT_eSPI::fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color)
|
2017-03-27 01:15:30 +00:00
|
|
|
{
|
|
|
|
// rudimentary clipping (drawChar w/big text requires this)
|
|
|
|
if ((x > _width) || (y > _height) || (w < 1) || (h < 1)) return;
|
|
|
|
if ((x + w - 1) > _width) w = _width - x;
|
|
|
|
if ((y + h - 1) > _height) h = _height - y;
|
2017-02-22 03:07:17 +00:00
|
|
|
|
2017-03-27 01:15:30 +00:00
|
|
|
spi_begin();
|
|
|
|
setAddrWindow(x, y, x + w - 1, y + h - 1);
|
|
|
|
|
|
|
|
uint32_t n = (uint32_t)w * (uint32_t)h;
|
|
|
|
|
|
|
|
#ifdef RPI_WRITE_STROBE
|
2018-03-12 22:49:18 +00:00
|
|
|
tft_Write_16(color);
|
2017-03-27 01:15:30 +00:00
|
|
|
while(n--) {WR_L; WR_H;}
|
|
|
|
#else
|
2018-03-10 23:08:57 +00:00
|
|
|
#ifdef ESP32_PARALLEL
|
|
|
|
if (color>>8 == (uint8_t)color)
|
|
|
|
{
|
2018-03-12 22:49:18 +00:00
|
|
|
tft_Write_8(color);
|
2018-03-10 23:08:57 +00:00
|
|
|
n--; WR_L; WR_H;
|
|
|
|
while (n) {WR_L; WR_H; n--; WR_L; WR_H;}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-03-12 22:49:18 +00:00
|
|
|
while (n--) {tft_Write_16(color);}
|
2018-03-10 23:08:57 +00:00
|
|
|
}
|
|
|
|
#else
|
|
|
|
writeBlock(color, n);
|
|
|
|
#endif
|
2017-03-27 01:15:30 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
CS_H;
|
|
|
|
|
|
|
|
spi_end();
|
|
|
|
}
|
|
|
|
#endif
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: color565
|
|
|
|
** Description: convert three 8 bit RGB levels to a 16 bit colour value
|
|
|
|
***************************************************************************************/
|
|
|
|
uint16_t TFT_eSPI::color565(uint8_t r, uint8_t g, uint8_t b)
|
|
|
|
{
|
|
|
|
return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-01-08 23:19:42 +00:00
|
|
|
/***************************************************************************************
|
2018-02-24 19:02:20 +00:00
|
|
|
** Function name: color16to8
|
2018-01-08 23:19:42 +00:00
|
|
|
** Description: convert 16 bit colour to an 8 bit 332 RGB colour value
|
|
|
|
***************************************************************************************/
|
2018-02-24 19:02:20 +00:00
|
|
|
uint8_t TFT_eSPI::color16to8(uint16_t c)
|
2018-01-08 23:19:42 +00:00
|
|
|
{
|
|
|
|
return ((c & 0xE000)>>8) | ((c & 0x0700)>>6) | ((c & 0x0018)>>3);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-02-24 19:02:20 +00:00
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: color8to16
|
|
|
|
** Description: convert 8 bit colour to a 16 bit 565 colour value
|
|
|
|
***************************************************************************************/
|
|
|
|
uint16_t TFT_eSPI::color8to16(uint8_t color)
|
|
|
|
{
|
|
|
|
uint8_t blue[] = {0, 11, 21, 31}; // blue 2 to 5 bit colour lookup table
|
|
|
|
uint16_t color16 = 0;
|
|
|
|
|
|
|
|
// =====Green===== ===============Red==============
|
|
|
|
color16 = (color & 0x1C)<<6 | (color & 0xC0)<<5 | (color & 0xE0)<<8;
|
|
|
|
// =====Green===== =======Blue======
|
|
|
|
color16 |= (color & 0x1C)<<3 | blue[color & 0x03];
|
|
|
|
|
|
|
|
return color16;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: invertDisplay
|
|
|
|
** Description: invert the display colours i = 1 invert, i = 0 normal
|
|
|
|
***************************************************************************************/
|
|
|
|
void TFT_eSPI::invertDisplay(boolean i)
|
|
|
|
{
|
|
|
|
spi_begin();
|
|
|
|
// Send the command twice as otherwise it does not always work!
|
|
|
|
writecommand(i ? TFT_INVON : TFT_INVOFF);
|
|
|
|
writecommand(i ? TFT_INVON : TFT_INVOFF);
|
|
|
|
spi_end();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: write
|
|
|
|
** Description: draw characters piped through serial stream
|
|
|
|
***************************************************************************************/
|
|
|
|
size_t TFT_eSPI::write(uint8_t utf8)
|
|
|
|
{
|
|
|
|
if (utf8 == '\r') return 1;
|
|
|
|
|
2018-02-24 19:02:20 +00:00
|
|
|
#ifdef SMOOTH_FONT
|
|
|
|
if(fontLoaded)
|
|
|
|
{
|
|
|
|
uint16_t unicode = decodeUTF8(utf8);
|
|
|
|
if (!unicode) return 0;
|
|
|
|
|
|
|
|
//fontFile = SPIFFS.open( _gFontFilename, "r" );
|
|
|
|
|
|
|
|
if(!fontFile)
|
|
|
|
{
|
|
|
|
fontLoaded = false;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
drawGlyph(unicode);
|
|
|
|
|
|
|
|
//fontFile.close();
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
uint8_t uniCode = utf8; // Work with a copy
|
|
|
|
if (utf8 == '\n') uniCode+=22; // Make it a valid space character to stop errors
|
2017-11-29 00:38:05 +00:00
|
|
|
else if (utf8 < 32) return 0;
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
uint16_t width = 0;
|
|
|
|
uint16_t height = 0;
|
|
|
|
|
|
|
|
//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv DEBUG vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
|
|
|
|
//Serial.print((uint8_t) uniCode); // Debug line sends all printed TFT text to serial port
|
|
|
|
//Serial.println(uniCode, HEX); // Debug line sends all printed TFT text to serial port
|
|
|
|
//delay(5); // Debug optional wait for serial port to flush through
|
|
|
|
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ DEBUG ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
|
|
|
|
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
|
|
|
#ifdef LOAD_GFXFF
|
|
|
|
if(!gfxFont) {
|
|
|
|
#endif
|
|
|
|
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
|
|
|
|
|
|
|
#ifdef LOAD_FONT2
|
|
|
|
if (textfont == 2)
|
|
|
|
{
|
2017-11-29 00:38:05 +00:00
|
|
|
if (utf8 > 127) return 0;
|
2017-04-14 00:04:04 +00:00
|
|
|
// This is 20us faster than using the fontdata structure (0.443ms per character instead of 0.465ms)
|
|
|
|
width = pgm_read_byte(widtbl_f16 + uniCode-32);
|
|
|
|
height = chr_hgt_f16;
|
|
|
|
// Font 2 is rendered in whole byte widths so we must allow for this
|
|
|
|
width = (width + 6) / 8; // Width in whole bytes for font 2, should be + 7 but must allow for font width change
|
2018-02-24 19:02:20 +00:00
|
|
|
width = width * 8; // Width converted back to pixels
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
#ifdef LOAD_RLE
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef LOAD_RLE
|
|
|
|
{
|
|
|
|
if ((textfont>2) && (textfont<9))
|
|
|
|
{
|
2017-11-29 00:38:05 +00:00
|
|
|
if (utf8 > 127) return 0;
|
2017-02-22 03:07:17 +00:00
|
|
|
// Uses the fontinfo struct array to avoid lots of 'if' or 'switch' statements
|
|
|
|
// A tad slower than above but this is not significant and is more convenient for the RLE fonts
|
2017-05-01 22:42:17 +00:00
|
|
|
width = pgm_read_byte( (uint8_t *)pgm_read_dword( &(fontdata[textfont].widthtbl ) ) + uniCode-32 );
|
2017-02-22 03:07:17 +00:00
|
|
|
height= pgm_read_byte( &fontdata[textfont].height );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef LOAD_GLCD
|
|
|
|
if (textfont==1)
|
|
|
|
{
|
|
|
|
width = 6;
|
|
|
|
height = 8;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
if (textfont==1) return 0;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
height = height * textsize;
|
|
|
|
|
|
|
|
if (utf8 == '\n') {
|
|
|
|
cursor_y += height;
|
|
|
|
cursor_x = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-02-24 19:02:20 +00:00
|
|
|
if (textwrapX && (cursor_x + width * textsize > _width))
|
2017-02-22 03:07:17 +00:00
|
|
|
{
|
|
|
|
cursor_y += height;
|
|
|
|
cursor_x = 0;
|
|
|
|
}
|
2018-02-24 19:02:20 +00:00
|
|
|
if (textwrapY && (cursor_y >= _height)) cursor_y = 0;
|
2017-02-22 03:07:17 +00:00
|
|
|
cursor_x += drawChar(uniCode, cursor_x, cursor_y, textfont);
|
|
|
|
}
|
|
|
|
|
|
|
|
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
|
|
|
#ifdef LOAD_GFXFF
|
|
|
|
} // Custom GFX font
|
|
|
|
else
|
|
|
|
{
|
|
|
|
|
|
|
|
if(utf8 == '\n') {
|
|
|
|
cursor_x = 0;
|
|
|
|
cursor_y += (int16_t)textsize *
|
|
|
|
(uint8_t)pgm_read_byte(&gfxFont->yAdvance);
|
2017-11-29 00:38:05 +00:00
|
|
|
} else {
|
|
|
|
if (uniCode > (uint8_t)pgm_read_byte(&gfxFont->last )) return 0;
|
|
|
|
if (uniCode < (uint8_t)pgm_read_byte(&gfxFont->first)) return 0;
|
2017-02-22 03:07:17 +00:00
|
|
|
|
2017-11-29 00:38:05 +00:00
|
|
|
uint8_t c2 = uniCode - pgm_read_byte(&gfxFont->first);
|
|
|
|
GFXglyph *glyph = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[c2]);
|
|
|
|
uint8_t w = pgm_read_byte(&glyph->width),
|
|
|
|
h = pgm_read_byte(&glyph->height);
|
|
|
|
if((w > 0) && (h > 0)) { // Is there an associated bitmap?
|
|
|
|
int16_t xo = (int8_t)pgm_read_byte(&glyph->xOffset);
|
2018-02-24 19:02:20 +00:00
|
|
|
if(textwrapX && ((cursor_x + textsize * (xo + w)) > _width)) {
|
2017-11-29 00:38:05 +00:00
|
|
|
// Drawing character would go off right edge; wrap to new line
|
|
|
|
cursor_x = 0;
|
|
|
|
cursor_y += (int16_t)textsize *
|
|
|
|
(uint8_t)pgm_read_byte(&gfxFont->yAdvance);
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
2018-02-24 19:02:20 +00:00
|
|
|
if (textwrapY && (cursor_y >= _height)) cursor_y = 0;
|
2017-11-29 00:38:05 +00:00
|
|
|
drawChar(cursor_x, cursor_y, uniCode, textcolor, textbgcolor, textsize);
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
2017-11-29 00:38:05 +00:00
|
|
|
cursor_x += pgm_read_byte(&glyph->xAdvance) * (int16_t)textsize;
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif // LOAD_GFXFF
|
|
|
|
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: drawChar
|
2018-02-24 19:02:20 +00:00
|
|
|
** Description: draw a Unicode onto the screen
|
2017-02-22 03:07:17 +00:00
|
|
|
***************************************************************************************/
|
|
|
|
int16_t TFT_eSPI::drawChar(unsigned int uniCode, int x, int y)
|
|
|
|
{
|
2017-04-14 00:04:04 +00:00
|
|
|
return drawChar(uniCode, x, y, textfont);
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int16_t TFT_eSPI::drawChar(unsigned int uniCode, int x, int y, int font)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (font==1)
|
|
|
|
{
|
|
|
|
#ifdef LOAD_GLCD
|
|
|
|
#ifndef LOAD_GFXFF
|
|
|
|
drawChar(x, y, uniCode, textcolor, textbgcolor, textsize);
|
|
|
|
return 6 * textsize;
|
|
|
|
#endif
|
|
|
|
#else
|
|
|
|
#ifndef LOAD_GFXFF
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef LOAD_GFXFF
|
2017-04-14 00:04:04 +00:00
|
|
|
drawChar(x, y, uniCode, textcolor, textbgcolor, textsize);
|
|
|
|
if(!gfxFont) { // 'Classic' built-in font
|
|
|
|
#ifdef LOAD_GLCD
|
|
|
|
return 6 * textsize;
|
|
|
|
#else
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-11-29 02:00:47 +00:00
|
|
|
if((uniCode >= pgm_read_byte(&gfxFont->first)) && (uniCode <= pgm_read_byte(&gfxFont->last) ))
|
2017-04-14 00:04:04 +00:00
|
|
|
{
|
|
|
|
uint8_t c2 = uniCode - pgm_read_byte(&gfxFont->first);
|
|
|
|
GFXglyph *glyph = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[c2]);
|
|
|
|
return pgm_read_byte(&glyph->xAdvance) * textsize;
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-04-14 00:04:04 +00:00
|
|
|
return 0;
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
2017-04-14 00:04:04 +00:00
|
|
|
}
|
2017-02-22 03:07:17 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2017-11-29 02:00:47 +00:00
|
|
|
if ((font>1) && (font<9) && ((uniCode < 32) || (uniCode > 127))) return 0;
|
2017-11-29 00:38:05 +00:00
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
int width = 0;
|
|
|
|
int height = 0;
|
|
|
|
uint32_t flash_address = 0;
|
|
|
|
uniCode -= 32;
|
|
|
|
|
|
|
|
#ifdef LOAD_FONT2
|
|
|
|
if (font == 2)
|
|
|
|
{
|
2017-04-14 00:04:04 +00:00
|
|
|
// This is faster than using the fontdata structure
|
|
|
|
flash_address = pgm_read_dword(&chrtbl_f16[uniCode]);
|
|
|
|
width = pgm_read_byte(widtbl_f16 + uniCode);
|
|
|
|
height = chr_hgt_f16;
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
#ifdef LOAD_RLE
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef LOAD_RLE
|
|
|
|
{
|
|
|
|
if ((font>2) && (font<9))
|
|
|
|
{
|
|
|
|
// This is slower than above but is more convenient for the RLE fonts
|
|
|
|
flash_address = pgm_read_dword( pgm_read_dword( &(fontdata[font].chartbl ) ) + uniCode*sizeof(void *) );
|
2017-05-01 22:42:17 +00:00
|
|
|
width = pgm_read_byte( (uint8_t *)pgm_read_dword( &(fontdata[font].widthtbl ) ) + uniCode );
|
2017-02-22 03:07:17 +00:00
|
|
|
height= pgm_read_byte( &fontdata[font].height );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
int w = width;
|
|
|
|
int pX = 0;
|
|
|
|
int pY = y;
|
2018-01-08 23:19:42 +00:00
|
|
|
uint8_t line = 0;
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
#ifdef LOAD_FONT2 // chop out code if we do not need it
|
|
|
|
if (font == 2) {
|
|
|
|
w = w + 6; // Should be + 7 but we need to compensate for width increment
|
|
|
|
w = w / 8;
|
|
|
|
if (x + width * textsize >= (int16_t)_width) return width * textsize ;
|
|
|
|
|
|
|
|
if (textcolor == textbgcolor || textsize != 1) {
|
2018-01-08 23:19:42 +00:00
|
|
|
spi_begin();
|
|
|
|
inTransaction = true;
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < height; i++)
|
|
|
|
{
|
|
|
|
if (textcolor != textbgcolor) fillRect(x, pY, width * textsize, textsize, textbgcolor);
|
|
|
|
|
|
|
|
for (int k = 0; k < w; k++)
|
|
|
|
{
|
2017-05-01 22:42:17 +00:00
|
|
|
line = pgm_read_byte((uint8_t *)flash_address + w * i + k);
|
2017-02-22 03:07:17 +00:00
|
|
|
if (line) {
|
|
|
|
if (textsize == 1) {
|
|
|
|
pX = x + k * 8;
|
|
|
|
if (line & 0x80) drawPixel(pX, pY, textcolor);
|
|
|
|
if (line & 0x40) drawPixel(pX + 1, pY, textcolor);
|
|
|
|
if (line & 0x20) drawPixel(pX + 2, pY, textcolor);
|
|
|
|
if (line & 0x10) drawPixel(pX + 3, pY, textcolor);
|
|
|
|
if (line & 0x08) drawPixel(pX + 4, pY, textcolor);
|
|
|
|
if (line & 0x04) drawPixel(pX + 5, pY, textcolor);
|
|
|
|
if (line & 0x02) drawPixel(pX + 6, pY, textcolor);
|
|
|
|
if (line & 0x01) drawPixel(pX + 7, pY, textcolor);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
pX = x + k * 8 * textsize;
|
|
|
|
if (line & 0x80) fillRect(pX, pY, textsize, textsize, textcolor);
|
|
|
|
if (line & 0x40) fillRect(pX + textsize, pY, textsize, textsize, textcolor);
|
|
|
|
if (line & 0x20) fillRect(pX + 2 * textsize, pY, textsize, textsize, textcolor);
|
|
|
|
if (line & 0x10) fillRect(pX + 3 * textsize, pY, textsize, textsize, textcolor);
|
|
|
|
if (line & 0x08) fillRect(pX + 4 * textsize, pY, textsize, textsize, textcolor);
|
|
|
|
if (line & 0x04) fillRect(pX + 5 * textsize, pY, textsize, textsize, textcolor);
|
|
|
|
if (line & 0x02) fillRect(pX + 6 * textsize, pY, textsize, textsize, textcolor);
|
|
|
|
if (line & 0x01) fillRect(pX + 7 * textsize, pY, textsize, textsize, textcolor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pY += textsize;
|
|
|
|
}
|
2018-01-08 23:19:42 +00:00
|
|
|
|
|
|
|
inTransaction = false;
|
|
|
|
spi_end();
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
// Faster drawing of characters and background using block write
|
|
|
|
{
|
|
|
|
spi_begin();
|
|
|
|
setAddrWindow(x, y, (x + w * 8) - 1, y + height - 1);
|
|
|
|
|
2018-01-08 23:19:42 +00:00
|
|
|
uint8_t mask;
|
2017-02-22 03:07:17 +00:00
|
|
|
for (int i = 0; i < height; i++)
|
|
|
|
{
|
|
|
|
for (int k = 0; k < w; k++)
|
|
|
|
{
|
2017-05-01 22:42:17 +00:00
|
|
|
line = pgm_read_byte((uint8_t *)flash_address + w * i + k);
|
2017-02-22 03:07:17 +00:00
|
|
|
pX = x + k * 8;
|
|
|
|
mask = 0x80;
|
|
|
|
while (mask) {
|
2018-03-12 22:49:18 +00:00
|
|
|
if (line & mask) {tft_Write_16(textcolor);}
|
|
|
|
else {tft_Write_16(textbgcolor);}
|
2017-02-22 03:07:17 +00:00
|
|
|
mask = mask >> 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pY += textsize;
|
|
|
|
}
|
|
|
|
|
|
|
|
CS_H;
|
|
|
|
spi_end();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef LOAD_RLE
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
#endif //FONT2
|
|
|
|
|
|
|
|
#ifdef LOAD_RLE //674 bytes of code
|
|
|
|
// Font is not 2 and hence is RLE encoded
|
|
|
|
{
|
|
|
|
spi_begin();
|
|
|
|
|
|
|
|
w *= height; // Now w is total number of pixels in the character
|
|
|
|
if ((textsize != 1) || (textcolor == textbgcolor)) {
|
|
|
|
if (textcolor != textbgcolor) fillRect(x, pY, width * textsize, textsize * height, textbgcolor);
|
|
|
|
int px = 0, py = pY; // To hold character block start and end column and row values
|
|
|
|
int pc = 0; // Pixel count
|
2018-01-08 23:19:42 +00:00
|
|
|
uint8_t np = textsize * textsize; // Number of pixels in a drawn pixel
|
2017-02-22 03:07:17 +00:00
|
|
|
|
2018-01-08 23:19:42 +00:00
|
|
|
uint8_t tnp = 0; // Temporary copy of np for while loop
|
|
|
|
uint8_t ts = textsize - 1; // Temporary copy of textsize
|
2017-02-22 03:07:17 +00:00
|
|
|
// 16 bit pixel count so maximum font size is equivalent to 180x180 pixels in area
|
|
|
|
// w is total number of pixels to plot to fill character block
|
|
|
|
while (pc < w)
|
|
|
|
{
|
2017-05-01 22:42:17 +00:00
|
|
|
line = pgm_read_byte((uint8_t *)flash_address);
|
2018-02-24 19:02:20 +00:00
|
|
|
flash_address++;
|
2017-02-22 03:07:17 +00:00
|
|
|
if (line & 0x80) {
|
|
|
|
line &= 0x7F;
|
|
|
|
line++;
|
|
|
|
if (ts) {
|
|
|
|
px = x + textsize * (pc % width); // Keep these px and py calculations outside the loop as they are slow
|
|
|
|
py = y + textsize * (pc / width);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
px = x + pc % width; // Keep these px and py calculations outside the loop as they are slow
|
|
|
|
py = y + pc / width;
|
|
|
|
}
|
|
|
|
while (line--) { // In this case the while(line--) is faster
|
|
|
|
pc++; // This is faster than putting pc+=line before while()?
|
|
|
|
setAddrWindow(px, py, px + ts, py + ts);
|
|
|
|
|
|
|
|
if (ts) {
|
|
|
|
tnp = np;
|
2018-03-12 22:49:18 +00:00
|
|
|
while (tnp--) {tft_Write_16(textcolor);}
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
2018-03-12 22:49:18 +00:00
|
|
|
else {tft_Write_16(textcolor);}
|
2017-02-22 03:07:17 +00:00
|
|
|
px += textsize;
|
|
|
|
|
|
|
|
if (px >= (x + width * textsize))
|
|
|
|
{
|
|
|
|
px = x;
|
|
|
|
py += textsize;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
line++;
|
|
|
|
pc += line;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CS_H;
|
|
|
|
spi_end();
|
|
|
|
}
|
|
|
|
else // Text colour != background && textsize = 1
|
|
|
|
// so use faster drawing of characters and background using block write
|
|
|
|
{
|
2017-05-20 00:37:58 +00:00
|
|
|
//spi_begin();
|
2017-02-22 03:07:17 +00:00
|
|
|
setAddrWindow(x, y, x + width - 1, y + height - 1);
|
|
|
|
|
|
|
|
uint8_t textcolorBin[] = { (uint8_t) (textcolor >> 8), (uint8_t) textcolor };
|
|
|
|
uint8_t textbgcolorBin[] = { (uint8_t) (textbgcolor >> 8), (uint8_t) textbgcolor };
|
|
|
|
|
|
|
|
// Maximum font size is equivalent to 180x180 pixels in area
|
|
|
|
while (w > 0)
|
|
|
|
{
|
2017-05-01 22:42:17 +00:00
|
|
|
line = pgm_read_byte((uint8_t *)flash_address++); // 8 bytes smaller when incrementing here
|
2017-02-22 03:07:17 +00:00
|
|
|
if (line & 0x80) {
|
|
|
|
line &= 0x7F;
|
|
|
|
line++; w -= line;
|
2017-03-27 01:15:30 +00:00
|
|
|
#ifdef RPI_WRITE_STROBE
|
|
|
|
SPI.writePattern(&textcolorBin[0], 2, 1); line--;
|
|
|
|
while(line--) {WR_L; WR_H;}
|
|
|
|
#else
|
2018-03-10 23:08:57 +00:00
|
|
|
#ifdef ESP32_PARALLEL
|
2018-03-12 22:49:18 +00:00
|
|
|
while (line--) {tft_Write_16(textcolor);}
|
2018-03-10 23:08:57 +00:00
|
|
|
#else
|
|
|
|
writeBlock(textcolor,line);
|
|
|
|
#endif
|
2017-03-27 01:15:30 +00:00
|
|
|
#endif
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
line++; w -= line;
|
2017-03-27 01:15:30 +00:00
|
|
|
#ifdef RPI_WRITE_STROBE
|
|
|
|
SPI.writePattern(&textbgcolorBin[0], 2, 1); line--;
|
|
|
|
while(line--) {WR_L; WR_H;}
|
|
|
|
#else
|
2018-03-10 23:08:57 +00:00
|
|
|
#ifdef ESP32_PARALLEL
|
2018-03-12 22:49:18 +00:00
|
|
|
while (line--) {tft_Write_16(textbgcolor);}
|
2018-03-10 23:08:57 +00:00
|
|
|
#else
|
|
|
|
writeBlock(textbgcolor,line);
|
|
|
|
#endif
|
2017-03-27 01:15:30 +00:00
|
|
|
#endif
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
CS_H;
|
|
|
|
spi_end();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// End of RLE font rendering
|
|
|
|
#endif
|
|
|
|
return width * textsize; // x +
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: drawString (with or without user defined font)
|
|
|
|
** Description : draw string with padding if it is defined
|
|
|
|
***************************************************************************************/
|
|
|
|
// Without font number, uses font set by setTextFont()
|
|
|
|
int16_t TFT_eSPI::drawString(const String& string, int poX, int poY)
|
|
|
|
{
|
2017-04-14 00:04:04 +00:00
|
|
|
int16_t len = string.length() + 2;
|
|
|
|
char buffer[len];
|
|
|
|
string.toCharArray(buffer, len);
|
|
|
|
return drawString(buffer, poX, poY, textfont);
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
// With font number
|
|
|
|
int16_t TFT_eSPI::drawString(const String& string, int poX, int poY, int font)
|
|
|
|
{
|
2017-04-14 00:04:04 +00:00
|
|
|
int16_t len = string.length() + 2;
|
|
|
|
char buffer[len];
|
|
|
|
string.toCharArray(buffer, len);
|
|
|
|
return drawString(buffer, poX, poY, font);
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Without font number, uses font set by setTextFont()
|
|
|
|
int16_t TFT_eSPI::drawString(const char *string, int poX, int poY)
|
|
|
|
{
|
2017-04-14 00:04:04 +00:00
|
|
|
return drawString(string, poX, poY, textfont);
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
// With font number
|
|
|
|
int16_t TFT_eSPI::drawString(const char *string, int poX, int poY, int font)
|
|
|
|
{
|
|
|
|
int16_t sumX = 0;
|
|
|
|
uint8_t padding = 1, baseline = 0;
|
|
|
|
uint16_t cwidth = textWidth(string, font); // Find the pixel width of the string in the font
|
2017-10-23 00:59:37 +00:00
|
|
|
uint16_t cheight = 8 * textsize;
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
#ifdef LOAD_GFXFF
|
|
|
|
if (font == 1) {
|
|
|
|
if(gfxFont) {
|
|
|
|
cheight = glyph_ab * textsize;
|
|
|
|
poY += cheight; // Adjust for baseline datum of free fonts
|
|
|
|
baseline = cheight;
|
|
|
|
padding =101; // Different padding method used for Free Fonts
|
|
|
|
|
2018-02-24 19:02:20 +00:00
|
|
|
// We need to make an adjustment for the bottom of the string (eg 'y' character)
|
2017-02-22 03:07:17 +00:00
|
|
|
if ((textdatum == BL_DATUM) || (textdatum == BC_DATUM) || (textdatum == BR_DATUM)) {
|
|
|
|
cheight += glyph_bb * textsize;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (textdatum || padX)
|
|
|
|
{
|
|
|
|
|
2018-02-24 19:02:20 +00:00
|
|
|
// If it is not font 1 (GLCD or free font) get the baseline and pixel height of the font
|
|
|
|
#ifdef SMOOTH_FONT
|
|
|
|
if(fontLoaded) {
|
|
|
|
baseline = gFont.maxAscent;
|
|
|
|
cheight = fontHeight(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
#endif
|
2017-02-22 03:07:17 +00:00
|
|
|
if (font!=1) {
|
|
|
|
baseline = pgm_read_byte( &fontdata[font].baseline ) * textsize;
|
|
|
|
cheight = fontHeight(font);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(textdatum) {
|
|
|
|
case TC_DATUM:
|
|
|
|
poX -= cwidth/2;
|
|
|
|
padding += 1;
|
|
|
|
break;
|
|
|
|
case TR_DATUM:
|
|
|
|
poX -= cwidth;
|
|
|
|
padding += 2;
|
|
|
|
break;
|
|
|
|
case ML_DATUM:
|
|
|
|
poY -= cheight/2;
|
|
|
|
//padding += 0;
|
|
|
|
break;
|
|
|
|
case MC_DATUM:
|
|
|
|
poX -= cwidth/2;
|
|
|
|
poY -= cheight/2;
|
|
|
|
padding += 1;
|
|
|
|
break;
|
|
|
|
case MR_DATUM:
|
|
|
|
poX -= cwidth;
|
|
|
|
poY -= cheight/2;
|
|
|
|
padding += 2;
|
|
|
|
break;
|
|
|
|
case BL_DATUM:
|
|
|
|
poY -= cheight;
|
|
|
|
//padding += 0;
|
|
|
|
break;
|
|
|
|
case BC_DATUM:
|
|
|
|
poX -= cwidth/2;
|
|
|
|
poY -= cheight;
|
|
|
|
padding += 1;
|
|
|
|
break;
|
|
|
|
case BR_DATUM:
|
|
|
|
poX -= cwidth;
|
|
|
|
poY -= cheight;
|
|
|
|
padding += 2;
|
|
|
|
break;
|
|
|
|
case L_BASELINE:
|
|
|
|
poY -= baseline;
|
|
|
|
//padding += 0;
|
|
|
|
break;
|
|
|
|
case C_BASELINE:
|
|
|
|
poX -= cwidth/2;
|
|
|
|
poY -= baseline;
|
2017-04-23 17:50:53 +00:00
|
|
|
padding += 1;
|
2017-02-22 03:07:17 +00:00
|
|
|
break;
|
|
|
|
case R_BASELINE:
|
|
|
|
poX -= cwidth;
|
|
|
|
poY -= baseline;
|
|
|
|
padding += 2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// Check coordinates are OK, adjust if not
|
|
|
|
if (poX < 0) poX = 0;
|
2018-04-12 17:48:01 +00:00
|
|
|
if (poX+cwidth > width()) poX = width() - cwidth;
|
2017-02-22 03:07:17 +00:00
|
|
|
if (poY < 0) poY = 0;
|
2018-04-12 17:48:01 +00:00
|
|
|
if (poY+cheight-baseline> height()) poY = height() - cheight;
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
|
2017-04-23 17:50:53 +00:00
|
|
|
|
2017-03-12 01:16:07 +00:00
|
|
|
int8_t xo = 0;
|
2017-04-23 17:50:53 +00:00
|
|
|
#ifdef LOAD_GFXFF
|
2017-02-22 03:07:17 +00:00
|
|
|
if ((font == 1) && (gfxFont) && (textcolor!=textbgcolor))
|
|
|
|
{
|
|
|
|
cheight = (glyph_ab + glyph_bb) * textsize;
|
2017-04-14 00:04:04 +00:00
|
|
|
// Get the offset for the first character only to allow for negative offsets
|
2017-11-29 00:38:05 +00:00
|
|
|
uint8_t c2 = *string;
|
2017-11-29 02:00:47 +00:00
|
|
|
if((c2 >= pgm_read_byte(&gfxFont->first)) && (c2 <= pgm_read_byte(&gfxFont->last) ))
|
|
|
|
{
|
|
|
|
c2 -= pgm_read_byte(&gfxFont->first);
|
|
|
|
GFXglyph *glyph = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[c2]);
|
|
|
|
xo = pgm_read_byte(&glyph->xOffset) * textsize;
|
|
|
|
// Adjust for negative xOffset
|
2017-11-30 22:41:23 +00:00
|
|
|
if (xo > 0) xo = 0;
|
|
|
|
else cwidth -= xo;
|
2017-11-29 02:00:47 +00:00
|
|
|
// Add 1 pixel of padding all round
|
|
|
|
//cheight +=2;
|
|
|
|
//fillRect(poX+xo-1, poY - 1 - glyph_ab * textsize, cwidth+2, cheight, textbgcolor);
|
|
|
|
fillRect(poX+xo, poY - glyph_ab * textsize, cwidth, cheight, textbgcolor);
|
|
|
|
}
|
2017-02-22 03:07:17 +00:00
|
|
|
padding -=100;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-02-24 19:02:20 +00:00
|
|
|
#ifdef SMOOTH_FONT
|
|
|
|
if(fontLoaded)
|
|
|
|
{
|
|
|
|
if (textcolor!=textbgcolor) fillRect(poX, poY, cwidth, cheight, textbgcolor);
|
|
|
|
//drawLine(poX - 5, poY, poX + 5, poY, TFT_GREEN);
|
|
|
|
//drawLine(poX, poY - 5, poX, poY + 5, TFT_GREEN);
|
|
|
|
//fontFile = SPIFFS.open( _gFontFilename, "r");
|
|
|
|
if(!fontFile) return 0;
|
|
|
|
uint16_t len = strlen(string);
|
|
|
|
uint16_t n = 0;
|
|
|
|
setCursor(poX, poY);
|
|
|
|
while (n < len)
|
|
|
|
{
|
|
|
|
uint16_t unicode = decodeUTF8((uint8_t*)string, &n, len - n);
|
|
|
|
drawGlyph(unicode);
|
|
|
|
}
|
|
|
|
sumX += cwidth;
|
|
|
|
//fontFile.close();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
while (*string) sumX += drawChar(*(string++), poX+sumX, poY, font);
|
2017-02-22 03:07:17 +00:00
|
|
|
|
|
|
|
//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv DEBUG vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
|
|
|
|
// Switch on debugging for the padding areas
|
|
|
|
//#define PADDING_DEBUG
|
|
|
|
|
|
|
|
#ifndef PADDING_DEBUG
|
|
|
|
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ DEBUG ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
|
|
|
|
if((padX>cwidth) && (textcolor!=textbgcolor))
|
|
|
|
{
|
2017-03-12 03:31:51 +00:00
|
|
|
int16_t padXc = poX+cwidth+xo;
|
2017-02-22 03:07:17 +00:00
|
|
|
#ifdef LOAD_GFXFF
|
|
|
|
if ((font == 1) && (gfxFont))
|
|
|
|
{
|
2017-03-12 01:16:07 +00:00
|
|
|
poX +=xo; // Adjust for negative offset start character
|
2017-07-07 22:52:01 +00:00
|
|
|
poY -= glyph_ab * textsize;
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
switch(padding) {
|
|
|
|
case 1:
|
|
|
|
fillRect(padXc,poY,padX-cwidth,cheight, textbgcolor);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
fillRect(padXc,poY,(padX-cwidth)>>1,cheight, textbgcolor);
|
|
|
|
padXc = (padX-cwidth)>>1;
|
|
|
|
if (padXc>poX) padXc = poX;
|
|
|
|
fillRect(poX - padXc,poY,(padX-cwidth)>>1,cheight, textbgcolor);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
if (padXc>padX) padXc = padX;
|
|
|
|
fillRect(poX + cwidth - padXc,poY,padXc-cwidth,cheight, textbgcolor);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv DEBUG vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
|
|
|
|
// This is debug code to show text (green box) and blanked (white box) areas
|
|
|
|
// It shows that the padding areas are being correctly sized and positioned
|
|
|
|
|
|
|
|
if((padX>sumX) && (textcolor!=textbgcolor))
|
|
|
|
{
|
|
|
|
int16_t padXc = poX+sumX; // Maximum left side padding
|
|
|
|
#ifdef LOAD_GFXFF
|
|
|
|
if ((font == 1) && (gfxFont)) poY -= glyph_ab;
|
|
|
|
#endif
|
|
|
|
drawRect(poX,poY,sumX,cheight, TFT_GREEN);
|
|
|
|
switch(padding) {
|
|
|
|
case 1:
|
|
|
|
drawRect(padXc,poY,padX-sumX,cheight, TFT_WHITE);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
drawRect(padXc,poY,(padX-sumX)>>1, cheight, TFT_WHITE);
|
|
|
|
padXc = (padX-sumX)>>1;
|
|
|
|
if (padXc>poX) padXc = poX;
|
|
|
|
drawRect(poX - padXc,poY,(padX-sumX)>>1,cheight, TFT_WHITE);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
if (padXc>padX) padXc = padX;
|
|
|
|
drawRect(poX + sumX - padXc,poY,padXc-sumX,cheight, TFT_WHITE);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ DEBUG ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
|
|
|
|
return sumX;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: drawCentreString (deprecated, use setTextDatum())
|
|
|
|
** Descriptions: draw string centred on dX
|
|
|
|
***************************************************************************************/
|
|
|
|
int16_t TFT_eSPI::drawCentreString(const String& string, int dX, int poY, int font)
|
|
|
|
{
|
2017-04-14 00:04:04 +00:00
|
|
|
int16_t len = string.length() + 2;
|
|
|
|
char buffer[len];
|
|
|
|
string.toCharArray(buffer, len);
|
|
|
|
return drawCentreString(buffer, dX, poY, font);
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int16_t TFT_eSPI::drawCentreString(const char *string, int dX, int poY, int font)
|
|
|
|
{
|
2018-01-08 23:19:42 +00:00
|
|
|
uint8_t tempdatum = textdatum;
|
2017-02-22 03:07:17 +00:00
|
|
|
int sumX = 0;
|
|
|
|
textdatum = TC_DATUM;
|
|
|
|
sumX = drawString(string, dX, poY, font);
|
|
|
|
textdatum = tempdatum;
|
|
|
|
return sumX;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: drawRightString (deprecated, use setTextDatum())
|
|
|
|
** Descriptions: draw string right justified to dX
|
|
|
|
***************************************************************************************/
|
|
|
|
int16_t TFT_eSPI::drawRightString(const String& string, int dX, int poY, int font)
|
|
|
|
{
|
2017-04-14 00:04:04 +00:00
|
|
|
int16_t len = string.length() + 2;
|
|
|
|
char buffer[len];
|
|
|
|
string.toCharArray(buffer, len);
|
|
|
|
return drawRightString(buffer, dX, poY, font);
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int16_t TFT_eSPI::drawRightString(const char *string, int dX, int poY, int font)
|
|
|
|
{
|
2018-01-08 23:19:42 +00:00
|
|
|
uint8_t tempdatum = textdatum;
|
2017-02-22 03:07:17 +00:00
|
|
|
int16_t sumX = 0;
|
|
|
|
textdatum = TR_DATUM;
|
|
|
|
sumX = drawString(string, dX, poY, font);
|
|
|
|
textdatum = tempdatum;
|
|
|
|
return sumX;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: drawNumber
|
|
|
|
** Description: draw a long integer
|
|
|
|
***************************************************************************************/
|
|
|
|
int16_t TFT_eSPI::drawNumber(long long_num, int poX, int poY)
|
|
|
|
{
|
|
|
|
char str[12];
|
|
|
|
ltoa(long_num, str, 10);
|
|
|
|
return drawString(str, poX, poY, textfont);
|
|
|
|
}
|
|
|
|
|
|
|
|
int16_t TFT_eSPI::drawNumber(long long_num, int poX, int poY, int font)
|
|
|
|
{
|
|
|
|
char str[12];
|
|
|
|
ltoa(long_num, str, 10);
|
|
|
|
return drawString(str, poX, poY, font);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: drawFloat
|
|
|
|
** Descriptions: drawFloat, prints 7 non zero digits maximum
|
|
|
|
***************************************************************************************/
|
|
|
|
// Assemble and print a string, this permits alignment relative to a datum
|
|
|
|
// looks complicated but much more compact and actually faster than using print class
|
|
|
|
int16_t TFT_eSPI::drawFloat(float floatNumber, int dp, int poX, int poY)
|
|
|
|
{
|
2017-04-14 00:04:04 +00:00
|
|
|
return drawFloat(floatNumber, dp, poX, poY, textfont);
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int16_t TFT_eSPI::drawFloat(float floatNumber, int dp, int poX, int poY, int font)
|
|
|
|
{
|
|
|
|
char str[14]; // Array to contain decimal string
|
|
|
|
uint8_t ptr = 0; // Initialise pointer for array
|
|
|
|
int8_t digits = 1; // Count the digits to avoid array overflow
|
|
|
|
float rounding = 0.5; // Round up down delta
|
|
|
|
|
|
|
|
if (dp > 7) dp = 7; // Limit the size of decimal portion
|
|
|
|
|
|
|
|
// Adjust the rounding value
|
|
|
|
for (uint8_t i = 0; i < dp; ++i) rounding /= 10.0;
|
|
|
|
|
|
|
|
if (floatNumber < -rounding) // add sign, avoid adding - sign to 0.0!
|
|
|
|
{
|
|
|
|
str[ptr++] = '-'; // Negative number
|
|
|
|
str[ptr] = 0; // Put a null in the array as a precaution
|
|
|
|
digits = 0; // Set digits to 0 to compensate so pointer value can be used later
|
|
|
|
floatNumber = -floatNumber; // Make positive
|
|
|
|
}
|
|
|
|
|
|
|
|
floatNumber += rounding; // Round up or down
|
|
|
|
|
|
|
|
// For error put ... in string and return (all TFT_eSPI library fonts contain . character)
|
|
|
|
if (floatNumber >= 2147483647) {
|
|
|
|
strcpy(str, "...");
|
|
|
|
return drawString(str, poX, poY, font);
|
|
|
|
}
|
|
|
|
// No chance of overflow from here on
|
|
|
|
|
|
|
|
// Get integer part
|
|
|
|
unsigned long temp = (unsigned long)floatNumber;
|
|
|
|
|
|
|
|
// Put integer part into array
|
|
|
|
ltoa(temp, str + ptr, 10);
|
|
|
|
|
|
|
|
// Find out where the null is to get the digit count loaded
|
|
|
|
while ((uint8_t)str[ptr] != 0) ptr++; // Move the pointer along
|
|
|
|
digits += ptr; // Count the digits
|
|
|
|
|
|
|
|
str[ptr++] = '.'; // Add decimal point
|
|
|
|
str[ptr] = '0'; // Add a dummy zero
|
|
|
|
str[ptr + 1] = 0; // Add a null but don't increment pointer so it can be overwritten
|
|
|
|
|
|
|
|
// Get the decimal portion
|
|
|
|
floatNumber = floatNumber - temp;
|
|
|
|
|
|
|
|
// Get decimal digits one by one and put in array
|
|
|
|
// Limit digit count so we don't get a false sense of resolution
|
|
|
|
uint8_t i = 0;
|
|
|
|
while ((i < dp) && (digits < 9)) // while (i < dp) for no limit but array size must be increased
|
|
|
|
{
|
|
|
|
i++;
|
|
|
|
floatNumber *= 10; // for the next decimal
|
|
|
|
temp = floatNumber; // get the decimal
|
|
|
|
ltoa(temp, str + ptr, 10);
|
|
|
|
ptr++; digits++; // Increment pointer and digits count
|
|
|
|
floatNumber -= temp; // Remove that digit
|
|
|
|
}
|
|
|
|
|
|
|
|
// Finally we can plot the string and return pixel length
|
|
|
|
return drawString(str, poX, poY, font);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: setFreeFont
|
|
|
|
** Descriptions: Sets the GFX free font to use
|
|
|
|
***************************************************************************************/
|
|
|
|
|
|
|
|
#ifdef LOAD_GFXFF
|
|
|
|
|
2017-04-14 00:04:04 +00:00
|
|
|
void TFT_eSPI::setFreeFont(const GFXfont *f)
|
|
|
|
{
|
2017-02-22 03:07:17 +00:00
|
|
|
textfont = 1;
|
|
|
|
gfxFont = (GFXfont *)f;
|
|
|
|
|
2017-03-12 01:16:07 +00:00
|
|
|
glyph_ab = 0;
|
|
|
|
glyph_bb = 0;
|
|
|
|
uint8_t numChars = pgm_read_byte(&gfxFont->last) - pgm_read_byte(&gfxFont->first);
|
|
|
|
|
|
|
|
// Find the biggest above and below baseline offsets
|
|
|
|
for (uint8_t c = 0; c < numChars; c++)
|
|
|
|
{
|
|
|
|
GFXglyph *glyph1 = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[c]);
|
|
|
|
int8_t ab = -pgm_read_byte(&glyph1->yOffset);
|
|
|
|
if (ab > glyph_ab) glyph_ab = ab;
|
|
|
|
int8_t bb = pgm_read_byte(&glyph1->height) - ab;
|
|
|
|
if (bb > glyph_bb) glyph_bb = bb;
|
|
|
|
}
|
2017-02-22 03:07:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: setTextFont
|
|
|
|
** Description: Set the font for the print stream
|
|
|
|
***************************************************************************************/
|
|
|
|
void TFT_eSPI::setTextFont(uint8_t f)
|
|
|
|
{
|
|
|
|
textfont = (f > 0) ? f : 1; // Don't allow font 0
|
|
|
|
gfxFont = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
2017-04-14 00:04:04 +00:00
|
|
|
|
2017-02-22 03:07:17 +00:00
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: setFreeFont
|
|
|
|
** Descriptions: Sets the GFX free font to use
|
|
|
|
***************************************************************************************/
|
|
|
|
|
|
|
|
// Alternative to setTextFont() so we don't need two different named functions
|
2017-04-14 00:04:04 +00:00
|
|
|
void TFT_eSPI::setFreeFont(uint8_t font)
|
|
|
|
{
|
2017-02-22 03:07:17 +00:00
|
|
|
setTextFont(font);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: setTextFont
|
|
|
|
** Description: Set the font for the print stream
|
|
|
|
***************************************************************************************/
|
|
|
|
void TFT_eSPI::setTextFont(uint8_t f)
|
|
|
|
{
|
|
|
|
textfont = (f > 0) ? f : 1; // Don't allow font 0
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2017-04-23 17:50:53 +00:00
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: spiBlockWrite
|
|
|
|
** Description: Write a block of pixels of the same colour
|
|
|
|
***************************************************************************************/
|
2018-01-08 23:19:42 +00:00
|
|
|
//Clear screen test 76.8ms theoretical. 81.5ms TFT_eSPI, 967ms Adafruit_ILI9341
|
|
|
|
//Performance 26.15Mbps@26.66MHz, 39.04Mbps@40MHz, 75.4Mbps@80MHz SPI clock
|
|
|
|
//Efficiency:
|
|
|
|
// TFT_eSPI 98.06% 97.59% 94.24%
|
|
|
|
// Adafruit_GFX 19.62% 14.31% 7.94%
|
|
|
|
//
|
2018-07-07 21:41:53 +00:00
|
|
|
#if defined (ESP8266) && !defined (ILI9488_DRIVER)
|
2018-03-10 23:08:57 +00:00
|
|
|
void writeBlock(uint16_t color, uint32_t repeat)
|
2017-04-23 17:50:53 +00:00
|
|
|
{
|
|
|
|
uint16_t color16 = (color >> 8) | (color << 8);
|
|
|
|
uint32_t color32 = color16 | color16 << 16;
|
|
|
|
uint32_t mask = ~(SPIMMOSI << SPILMOSI);
|
|
|
|
mask = SPI1U1 & mask;
|
|
|
|
SPI1U = SPIUMOSI | SPIUSSE;
|
|
|
|
|
|
|
|
SPI1W0 = color32;
|
|
|
|
SPI1W1 = color32;
|
|
|
|
SPI1W2 = color32;
|
|
|
|
SPI1W3 = color32;
|
|
|
|
if (repeat > 8)
|
|
|
|
{
|
|
|
|
SPI1W4 = color32;
|
|
|
|
SPI1W5 = color32;
|
|
|
|
SPI1W6 = color32;
|
|
|
|
SPI1W7 = color32;
|
|
|
|
}
|
|
|
|
if (repeat > 16)
|
|
|
|
{
|
|
|
|
SPI1W8 = color32;
|
|
|
|
SPI1W9 = color32;
|
|
|
|
SPI1W10 = color32;
|
|
|
|
SPI1W11 = color32;
|
|
|
|
}
|
|
|
|
if (repeat > 24)
|
|
|
|
{
|
|
|
|
SPI1W12 = color32;
|
|
|
|
SPI1W13 = color32;
|
|
|
|
SPI1W14 = color32;
|
|
|
|
SPI1W15 = color32;
|
|
|
|
}
|
|
|
|
if (repeat > 31)
|
|
|
|
{
|
|
|
|
SPI1U1 = mask | (511 << SPILMOSI);
|
|
|
|
while(repeat>31)
|
|
|
|
{
|
2018-01-08 23:19:42 +00:00
|
|
|
#if defined SPI_FREQUENCY && (SPI_FREQUENCY == 80000000)
|
|
|
|
if(SPI1CMD & SPIBUSY) // added to sync with flag change
|
|
|
|
#endif
|
2017-04-23 17:50:53 +00:00
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
repeat -= 32;
|
|
|
|
}
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (repeat)
|
|
|
|
{
|
|
|
|
repeat = (repeat << 4) - 1;
|
|
|
|
SPI1U1 = mask | (repeat << SPILMOSI);
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
|
|
|
}
|
|
|
|
|
|
|
|
SPI1U = SPIUMOSI | SPIUDUPLEX | SPIUSSE;
|
|
|
|
}
|
2017-05-20 00:37:58 +00:00
|
|
|
|
2018-07-07 21:41:53 +00:00
|
|
|
#elif defined (ILI9488_DRIVER)
|
|
|
|
|
|
|
|
#ifdef ESP8266
|
|
|
|
void writeBlock(uint16_t color, uint32_t repeat)
|
|
|
|
{
|
|
|
|
|
|
|
|
uint32_t mask = ~(SPIMMOSI << SPILMOSI);
|
|
|
|
mask = SPI1U1 & mask;
|
|
|
|
SPI1U = SPIUMOSI | SPIUSSE;
|
|
|
|
|
|
|
|
// Split out the colours
|
|
|
|
uint8_t r = (color & 0xF800)>>8;
|
|
|
|
uint8_t g = (color & 0x07E0)>>3;
|
|
|
|
uint8_t b = (color & 0x001F)<<3;
|
|
|
|
// Concatenate 4 pixels into three 32 bit blocks
|
|
|
|
uint32_t r0 = r<<24 | b<<16 | g<<8 | r;
|
|
|
|
uint32_t r1 = g<<24 | r<<16 | b<<8 | g;
|
|
|
|
uint32_t r2 = b<<24 | g<<16 | r<<8 | b;
|
|
|
|
|
|
|
|
SPI1W0 = r0;
|
|
|
|
SPI1W1 = r1;
|
|
|
|
SPI1W2 = r2;
|
|
|
|
|
|
|
|
if (repeat > 4)
|
|
|
|
{
|
|
|
|
SPI1W3 = r0;
|
|
|
|
SPI1W4 = r1;
|
|
|
|
SPI1W5 = r2;
|
|
|
|
}
|
|
|
|
if (repeat > 8)
|
|
|
|
{
|
|
|
|
SPI1W6 = r0;
|
|
|
|
SPI1W7 = r1;
|
|
|
|
SPI1W8 = r2;
|
|
|
|
}
|
|
|
|
if (repeat > 12)
|
|
|
|
{
|
|
|
|
SPI1W9 = r0;
|
|
|
|
SPI1W10 = r1;
|
|
|
|
SPI1W11 = r2;
|
|
|
|
SPI1W12 = r0;
|
|
|
|
SPI1W13 = r1;
|
|
|
|
SPI1W14 = r2;
|
|
|
|
SPI1W15 = r0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (repeat > 20)
|
|
|
|
{
|
|
|
|
SPI1U1 = mask | (503 << SPILMOSI);
|
|
|
|
while(repeat>20)
|
|
|
|
{
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
repeat -= 21;
|
|
|
|
}
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (repeat)
|
|
|
|
{
|
|
|
|
repeat = (repeat * 24) - 1;
|
|
|
|
SPI1U1 = mask | (repeat << SPILMOSI);
|
|
|
|
SPI1CMD |= SPIBUSY;
|
|
|
|
while(SPI1CMD & SPIBUSY) {}
|
|
|
|
}
|
|
|
|
|
|
|
|
SPI1U = SPIUMOSI | SPIUDUPLEX | SPIUSSE;
|
|
|
|
}
|
|
|
|
#else // Now the code for ESP32 and ILI9488
|
|
|
|
|
|
|
|
#include "soc/spi_reg.h"
|
|
|
|
#define SPI_NUM 0x3
|
|
|
|
|
|
|
|
void writeBlock(uint16_t color, uint32_t repeat)
|
|
|
|
{
|
|
|
|
// Split out the colours
|
|
|
|
uint8_t r = (color & 0xF800)>>8;
|
|
|
|
uint8_t g = (color & 0x07E0)>>3;
|
|
|
|
uint8_t b = (color & 0x001F)<<3;
|
|
|
|
// Concatenate 4 pixels into three 32 bit blocks
|
|
|
|
uint32_t r0 = r<<24 | b<<16 | g<<8 | r;
|
|
|
|
uint32_t r1 = g<<24 | r<<16 | b<<8 | g;
|
|
|
|
uint32_t r2 = b<<24 | g<<16 | r<<8 | b;
|
|
|
|
|
|
|
|
if (repeat > 9)
|
|
|
|
{
|
|
|
|
SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(SPI_NUM), SPI_USR_MOSI_DBITLEN, 239, SPI_USR_MOSI_DBITLEN_S);
|
|
|
|
|
|
|
|
while(repeat>9)
|
|
|
|
{
|
|
|
|
while (READ_PERI_REG(SPI_CMD_REG(SPI_NUM))&SPI_USR);
|
|
|
|
WRITE_PERI_REG((SPI_W0_REG(SPI_NUM) + 0), r0);
|
|
|
|
WRITE_PERI_REG((SPI_W0_REG(SPI_NUM) + 4), r1);
|
|
|
|
WRITE_PERI_REG((SPI_W0_REG(SPI_NUM) + 8), r2);
|
|
|
|
WRITE_PERI_REG((SPI_W0_REG(SPI_NUM) + 12), r0);
|
|
|
|
WRITE_PERI_REG((SPI_W0_REG(SPI_NUM) + 16), r1);
|
|
|
|
WRITE_PERI_REG((SPI_W0_REG(SPI_NUM) + 20), r2);
|
|
|
|
WRITE_PERI_REG((SPI_W0_REG(SPI_NUM) + 24), r0);
|
|
|
|
WRITE_PERI_REG((SPI_W0_REG(SPI_NUM) + 28), r1);
|
|
|
|
SET_PERI_REG_MASK(SPI_CMD_REG(SPI_NUM), SPI_USR);
|
|
|
|
repeat -= 10;
|
|
|
|
}
|
|
|
|
while (READ_PERI_REG(SPI_CMD_REG(SPI_NUM))&SPI_USR);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (repeat)
|
|
|
|
{
|
|
|
|
repeat = (repeat * 24) - 1;
|
|
|
|
SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(SPI_NUM), SPI_USR_MOSI_DBITLEN, repeat, SPI_USR_MOSI_DBITLEN_S);
|
|
|
|
WRITE_PERI_REG((SPI_W0_REG(SPI_NUM) + 0), r0);
|
|
|
|
WRITE_PERI_REG((SPI_W0_REG(SPI_NUM) + 4), r1);
|
|
|
|
WRITE_PERI_REG((SPI_W0_REG(SPI_NUM) + 8), r2);
|
|
|
|
WRITE_PERI_REG((SPI_W0_REG(SPI_NUM) + 12), r0);
|
|
|
|
WRITE_PERI_REG((SPI_W0_REG(SPI_NUM) + 16), r1);
|
|
|
|
WRITE_PERI_REG((SPI_W0_REG(SPI_NUM) + 20), r2);
|
|
|
|
WRITE_PERI_REG((SPI_W0_REG(SPI_NUM) + 24), r0);
|
|
|
|
WRITE_PERI_REG((SPI_W0_REG(SPI_NUM) + 28), r1);
|
|
|
|
SET_PERI_REG_MASK(SPI_CMD_REG(SPI_NUM), SPI_USR);
|
|
|
|
while (READ_PERI_REG(SPI_CMD_REG(SPI_NUM))&SPI_USR);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#else // Low level register based ESP32 code for 16 bit colour SPI TFTs
|
2017-05-20 00:37:58 +00:00
|
|
|
|
|
|
|
#include "soc/spi_reg.h"
|
|
|
|
#define SPI_NUM 0x3
|
|
|
|
|
2018-03-10 23:08:57 +00:00
|
|
|
void writeBlock(uint16_t color, uint32_t repeat)
|
2017-05-20 00:37:58 +00:00
|
|
|
{
|
|
|
|
uint16_t color16 = (color >> 8) | (color << 8);
|
|
|
|
uint32_t color32 = color16 | color16 << 16;
|
2017-06-16 14:17:28 +00:00
|
|
|
|
2017-05-20 00:37:58 +00:00
|
|
|
if (repeat > 15)
|
|
|
|
{
|
|
|
|
SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(SPI_NUM), SPI_USR_MOSI_DBITLEN, 255, SPI_USR_MOSI_DBITLEN_S);
|
|
|
|
|
|
|
|
while(repeat>15)
|
|
|
|
{
|
|
|
|
while (READ_PERI_REG(SPI_CMD_REG(SPI_NUM))&SPI_USR);
|
2018-07-07 21:41:53 +00:00
|
|
|
for (uint32_t i=0; i<8; i++) WRITE_PERI_REG((SPI_W0_REG(SPI_NUM) + (i << 2)), color32);
|
2017-05-20 00:37:58 +00:00
|
|
|
SET_PERI_REG_MASK(SPI_CMD_REG(SPI_NUM), SPI_USR);
|
|
|
|
repeat -= 16;
|
|
|
|
}
|
|
|
|
while (READ_PERI_REG(SPI_CMD_REG(SPI_NUM))&SPI_USR);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (repeat)
|
|
|
|
{
|
|
|
|
repeat = (repeat << 4) - 1;
|
|
|
|
SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(SPI_NUM), SPI_USR_MOSI_DBITLEN, repeat, SPI_USR_MOSI_DBITLEN_S);
|
2018-07-07 21:41:53 +00:00
|
|
|
for (uint32_t i=0; i<8; i++) WRITE_PERI_REG((SPI_W0_REG(SPI_NUM) + (i << 2)), color32);
|
2017-05-20 00:37:58 +00:00
|
|
|
SET_PERI_REG_MASK(SPI_CMD_REG(SPI_NUM), SPI_USR);
|
|
|
|
while (READ_PERI_REG(SPI_CMD_REG(SPI_NUM))&SPI_USR);
|
|
|
|
}
|
|
|
|
|
2017-04-23 17:50:53 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-11-04 19:11:50 +00:00
|
|
|
|
2018-03-26 00:02:23 +00:00
|
|
|
/***************************************************************************************
|
|
|
|
** Function name: getSetup
|
|
|
|
** Description: Get the setup details for diagnostic and sketch access
|
|
|
|
***************************************************************************************/
|
|
|
|
void TFT_eSPI::getSetup(setup_t &tft_settings)
|
|
|
|
{
|
|
|
|
|
|
|
|
#if defined (ESP8266)
|
|
|
|
tft_settings.esp = 8266;
|
|
|
|
#elif defined (ESP32)
|
|
|
|
tft_settings.esp = 32;
|
|
|
|
#else
|
|
|
|
tft_settings.esp = -1;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined (SUPPORT_TRANSACTIONS)
|
|
|
|
tft_settings.trans = true;
|
|
|
|
#else
|
|
|
|
tft_settings.trans = false;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined (ESP32_PARALLEL)
|
|
|
|
tft_settings.serial = false;
|
|
|
|
tft_settings.tft_spi_freq = 0;
|
|
|
|
#else
|
|
|
|
tft_settings.serial = true;
|
|
|
|
tft_settings.tft_spi_freq = SPI_FREQUENCY/100000;
|
|
|
|
#endif
|
|
|
|
|
2018-04-11 00:03:26 +00:00
|
|
|
#if defined(TFT_SPI_OVERLAP)
|
|
|
|
tft_settings.overlap = true;
|
|
|
|
#else
|
|
|
|
tft_settings.overlap = false;
|
|
|
|
#endif
|
|
|
|
|
2018-03-26 00:02:23 +00:00
|
|
|
tft_settings.tft_driver = TFT_DRIVER;
|
|
|
|
tft_settings.tft_width = _init_width;
|
|
|
|
tft_settings.tft_height = _init_height;
|
|
|
|
|
|
|
|
#ifdef CGRAM_OFFSET
|
|
|
|
tft_settings.r0_x_offset = colstart;
|
|
|
|
tft_settings.r0_y_offset = rowstart;
|
|
|
|
tft_settings.r1_x_offset = 0;
|
|
|
|
tft_settings.r1_y_offset = 0;
|
|
|
|
tft_settings.r2_x_offset = 0;
|
|
|
|
tft_settings.r2_y_offset = 0;
|
|
|
|
tft_settings.r3_x_offset = 0;
|
|
|
|
tft_settings.r3_y_offset = 0;
|
|
|
|
#else
|
|
|
|
tft_settings.r0_x_offset = 0;
|
|
|
|
tft_settings.r0_y_offset = 0;
|
|
|
|
tft_settings.r1_x_offset = 0;
|
|
|
|
tft_settings.r1_y_offset = 0;
|
|
|
|
tft_settings.r2_x_offset = 0;
|
|
|
|
tft_settings.r2_y_offset = 0;
|
|
|
|
tft_settings.r3_x_offset = 0;
|
|
|
|
tft_settings.r3_y_offset = 0;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined (TFT_MOSI)
|
|
|
|
tft_settings.pin_tft_mosi = TFT_MOSI;
|
|
|
|
#else
|
|
|
|
tft_settings.pin_tft_mosi = -1;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined (TFT_MISO)
|
|
|
|
tft_settings.pin_tft_miso = TFT_MISO;
|
|
|
|
#else
|
|
|
|
tft_settings.pin_tft_miso = -1;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined (TFT_SCLK)
|
|
|
|
tft_settings.pin_tft_clk = TFT_SCLK;
|
|
|
|
#else
|
|
|
|
tft_settings.pin_tft_clk = -1;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined (TFT_CS)
|
|
|
|
tft_settings.pin_tft_cs = TFT_CS;
|
|
|
|
#else
|
|
|
|
tft_settings.pin_tft_cs = -1;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined (TFT_DC)
|
|
|
|
tft_settings.pin_tft_dc = TFT_DC;
|
|
|
|
#else
|
|
|
|
tft_settings.pin_tft_dc = -1;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined (TFT_RD)
|
|
|
|
tft_settings.pin_tft_rd = TFT_RD;
|
|
|
|
#else
|
|
|
|
tft_settings.pin_tft_rd = -1;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined (TFT_WR)
|
|
|
|
tft_settings.pin_tft_wr = TFT_WR;
|
|
|
|
#else
|
|
|
|
tft_settings.pin_tft_wr = -1;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined (TFT_RST)
|
|
|
|
tft_settings.pin_tft_rst = TFT_RST;
|
|
|
|
#else
|
|
|
|
tft_settings.pin_tft_rst = -1;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined (ESP32_PARALLEL)
|
|
|
|
tft_settings.pin_tft_d0 = TFT_D0;
|
|
|
|
tft_settings.pin_tft_d1 = TFT_D1;
|
|
|
|
tft_settings.pin_tft_d2 = TFT_D2;
|
|
|
|
tft_settings.pin_tft_d3 = TFT_D3;
|
|
|
|
tft_settings.pin_tft_d4 = TFT_D4;
|
|
|
|
tft_settings.pin_tft_d5 = TFT_D5;
|
|
|
|
tft_settings.pin_tft_d6 = TFT_D6;
|
|
|
|
tft_settings.pin_tft_d7 = TFT_D7;
|
|
|
|
#else
|
|
|
|
tft_settings.pin_tft_d0 = -1;
|
|
|
|
tft_settings.pin_tft_d1 = -1;
|
|
|
|
tft_settings.pin_tft_d2 = -1;
|
|
|
|
tft_settings.pin_tft_d3 = -1;
|
|
|
|
tft_settings.pin_tft_d4 = -1;
|
|
|
|
tft_settings.pin_tft_d5 = -1;
|
|
|
|
tft_settings.pin_tft_d6 = -1;
|
|
|
|
tft_settings.pin_tft_d7 = -1;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined (TOUCH_CS)
|
|
|
|
tft_settings.pin_tch_cs = TOUCH_CS;
|
|
|
|
tft_settings.tch_spi_freq = SPI_TOUCH_FREQUENCY/100000;
|
|
|
|
#else
|
|
|
|
tft_settings.pin_tch_cs = -1;
|
|
|
|
tft_settings.tch_spi_freq = 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2018-02-24 19:02:20 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifdef TOUCH_CS
|
|
|
|
#include "Extensions/Touch.cpp"
|
2018-04-11 00:03:26 +00:00
|
|
|
#include "Extensions/Button.cpp"
|
2018-02-24 19:02:20 +00:00
|
|
|
#endif
|
2017-10-23 00:59:37 +00:00
|
|
|
|
2018-02-24 19:02:20 +00:00
|
|
|
#include "Extensions/Sprite.cpp"
|
2017-10-23 00:59:37 +00:00
|
|
|
|
2018-02-24 19:02:20 +00:00
|
|
|
#ifdef SMOOTH_FONT
|
|
|
|
#include "Extensions/Smooth_font.cpp"
|
|
|
|
#endif
|
2017-10-23 00:59:37 +00:00
|
|
|
|
2018-02-24 19:02:20 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
2017-02-22 03:07:17 +00:00
|
|
|
|