This commit is contained in:
Kristian Nielsen 2017-09-15 23:47:27 +00:00 committed by GitHub
commit 1e3ecb3f4e
14 changed files with 1041 additions and 12 deletions

3
.gitignore vendored
View File

@ -17,6 +17,9 @@ $RECYCLE.BIN/
# Windows shortcuts # Windows shortcuts
*.lnk *.lnk
# Backup files
*~
# ========================= # =========================
# Operating System Files # Operating System Files
# ========================= # =========================

View File

@ -1,11 +1,14 @@
# TFT_eSPI # TFT_eSPI
An Arduino IDE compatible graphics and fonts library for ESP8266 and ESP32 processors with a driver for ILI9341, ILI9163, ST7735 and S6D02A1 based TFT displays that support SPI. An Arduino IDE compatible graphics and fonts library for ESP8266 and ESP32 processors with a driver for ILI9341, ILI9163, ST7735, ST7787 and S6D02A1 based TFT displays that support SPI.
The library also supports TFT displays designed for the Raspberry Pi that are based on a ILI9486 driver chip with a 480 x 320 pixel screen. This display must be of the Waveshare design and use a 16 bit serial interface based on the 74HC04, 74HC4040 and 2 x 74HC4094 logic chips. A modification to these displays is possible (see mod image in Tools folder) to make many graphics functions much faster (e.g. 23ms to clear the screen, 1.2ms to draw a 72 pixel high numeral). The library also supports TFT displays designed for the Raspberry Pi that are based on a ILI9486 driver chip with a 480 x 320 pixel screen. This display must be of the Waveshare design and use a 16 bit serial interface based on the 74HC04, 74HC4040 and 2 x 74HC4094 logic chips. A modification to these displays is possible (see mod image in Tools folder) to make many graphics functions much faster (e.g. 23ms to clear the screen, 1.2ms to draw a 72 pixel high numeral).
The library supports SPI overlap so the TFT screen can share MOSI, MISO and SCLK pins with the program FLASH. The library supports SPI overlap so the TFT screen can share MOSI, MISO and SCLK pins with the program FLASH.
The library supports the 3-wire mode of some display controllers (currently tested with ST7787 only, and currently only on ESP8266). This mode reduces pin count by not using the DC and MISO pins.
The library contains proportional fonts, different sizes can be enabled/disabled at compile time to optimise the use of FLASH memory. The library has been tested with the NodeMCU (ESP8266 based) and an ESP32 demo board. The library contains proportional fonts, different sizes can be enabled/disabled at compile time to optimise the use of FLASH memory. The library has been tested with the NodeMCU (ESP8266 based) and an ESP32 demo board.
The library is based on the Adafruit GFX and Adafruit driver libraries and the aim is to retain compatibility. Significant additions have been made to the library to boost the speed for ESP8266/ESP32 processors (it is typically 3 to 10 times faster) and to add new features. The new graphics functions include different size proportional fonts and formatting features. There are a significant number of example sketches to demonstrate the different features. The library is based on the Adafruit GFX and Adafruit driver libraries and the aim is to retain compatibility. Significant additions have been made to the library to boost the speed for ESP8266/ESP32 processors (it is typically 3 to 10 times faster) and to add new features. The new graphics functions include different size proportional fonts and formatting features. There are a significant number of example sketches to demonstrate the different features.

View File

@ -0,0 +1,123 @@
// Change the width and height if required (defined in portrait mode)
// or use the constructor to over-ride defaults
#ifndef TFT_WIDTH
#define TFT_WIDTH 240
#endif
#ifndef TFT_HEIGHT
#define TFT_HEIGHT 320
#endif
// Color definitions for backwards compatibility with old sketches
// use colour definitions like TFT_BLACK to make sketches more portable
#define ST7735_BLACK 0x0000 /* 0, 0, 0 */
#define ST7735_NAVY 0x000F /* 0, 0, 128 */
#define ST7735_DARKGREEN 0x03E0 /* 0, 128, 0 */
#define ST7735_DARKCYAN 0x03EF /* 0, 128, 128 */
#define ST7735_MAROON 0x7800 /* 128, 0, 0 */
#define ST7735_PURPLE 0x780F /* 128, 0, 128 */
#define ST7735_OLIVE 0x7BE0 /* 128, 128, 0 */
#define ST7735_LIGHTGREY 0xC618 /* 192, 192, 192 */
#define ST7735_DARKGREY 0x7BEF /* 128, 128, 128 */
#define ST7735_BLUE 0x001F /* 0, 0, 255 */
#define ST7735_GREEN 0x07E0 /* 0, 255, 0 */
#define ST7735_CYAN 0x07FF /* 0, 255, 255 */
#define ST7735_RED 0xF800 /* 255, 0, 0 */
#define ST7735_MAGENTA 0xF81F /* 255, 0, 255 */
#define ST7735_YELLOW 0xFFE0 /* 255, 255, 0 */
#define ST7735_WHITE 0xFFFF /* 255, 255, 255 */
#define ST7735_ORANGE 0xFD20 /* 255, 165, 0 */
#define ST7735_GREENYELLOW 0xAFE5 /* 173, 255, 47 */
#define ST7735_PINK 0xF81F
#define ILI9341_BLACK ST7735_BLACK
#define ILI9341_WHITE ST7735_WHITE
#define ILI9341_VSCRDEF ST7787_SCRLAR
#define ILI9341_VSCRSADD ST7787_VSCSAD
// Delay between some initialisation commands
#define TFT_INIT_DELAY 0x80
// Generic commands used by TFT_eSPI.cpp
#define TFT_NOP 0x00
#define TFT_SWRST 0x01
#define TFT_CASET 0x2A
#define TFT_PASET 0x2B
#define TFT_RAMWR 0x2C
#define TFT_RAMRD 0x2E
#define TFT_IDXRD 0x00 //0xDD // ILI9341 only, indexed control register read
#define TFT_MADCTL 0x36
#define TFT_MAD_MY 0x80
#define TFT_MAD_MX 0x40
#define TFT_MAD_MV 0x20
#define TFT_MAD_ML 0x10
#define TFT_MAD_BGR 0x08
#define TFT_MAD_MH 0x04
#define TFT_MAD_RGB 0x00
#define TFT_INVOFF 0x20
#define TFT_INVON 0x21
// ST7787 specific commands used in init
#define ST7787_NOP 0x00
#define ST7787_SWRESET 0x01
#define ST7787_RDDID 0x04
#define ST7787_RDDST 0x09
#define ST7787_SLPIN 0x10
#define ST7787_SLPOUT 0x11
#define ST7787_PTLON 0x12
#define ST7787_NORON 0x13
#define ST7787_INVOFF 0x20
#define ST7787_INVON 0x21
#define ST7787_DISPOFF 0x28
#define ST7787_DISPON 0x29
#define ST7787_CASET 0x2A
#define ST7787_RASET 0x2B // PASET
#define ST7787_RAMWR 0x2C
#define ST7787_RAMRD 0x2E
#define ST7787_PTLAR 0x30
#define ST7787_SCRLAR 0x33
#define ST7787_TEOFF 0x34
#define ST7787_TEON 0x35
#define ST7787_MADCTL 0x36
#define ST7787_VSCSAD 0x37
#define ST7787_COLMOD 0x3A
#define ST7787_FRMCTR1 0xB1
#define ST7787_FRMCTR2 0xB2
#define ST7787_FRMCTR3 0xB3
#define ST7787_INVCTR 0xB4
#define ST7787_DISSET5 0xB6
#define ST7787_VSYNCOUT 0xBC
#define ST7787_VSYNCIN 0xBD
#define ST7787_PWCTR1 0xC0
#define ST7787_PWCTR2 0xC1
#define ST7787_PWCTR3 0xC2
#define ST7787_PWCTR4 0xC3
#define ST7787_PWCTR5 0xC4
#define ST7787_VMCTR1 0xC5
#define ST7787_RDID1 0xDA
#define ST7787_RDID2 0xDB
#define ST7787_RDID3 0xDC
#define ST7787_GMCTRP1 0xE0
#define ST7787_GMCTRN1 0xE1
/* Timing delays from ST7787 datasheet (in nanoseconds). */
#define ST7787_T_CSS 60
#define ST7787_T_SCC 20
#define ST7787_T_CHW 40
#define ST7787_T_SHW 20
#define ST7787_T_SLW 20
#define ST7787_T_SHR 60
#define ST7787_T_SLR 60

30
TFT_Drivers/ST7787_Init.h Normal file
View File

@ -0,0 +1,30 @@
// This is the command sequence that initialises the ST7787 driver
//
// This setup information uses simple 8 bit SPI writecommand() and writedata() functions
//
// See ST7735_Setup.h file for an alternative format
{
/* Take the display out of sleep mode. */
writecommand(ST7787_SLPOUT);
/*
Wait for sleep-out command to complete.
Datasheet says 5 msec is enough before next command, but 120 msec is
needed before the display is fully out of sleep mode.
*/
delay(120);
/*
Select 16-bit 565 RGB pixel format (mode 5).
Same for RGB mode (but we don't use it).
*/
writecommand(ST7787_COLMOD);
writedata((13 << 4) | 5);
/* Initialise to Rotation 0. */
writecommand(TFT_MADCTL);
writedata(TFT_MAD_ML | TFT_MAD_RGB);
/* Disable external vsync. */
writecommand(ST7787_VSYNCOUT);
/* Turn on the display */
writecommand(ST7787_DISPON);
}

View File

@ -0,0 +1,36 @@
// This is the command sequence that rotates the ST7787 driver coordinate frame
//
// Rotation 0 is portrait mode. Rotations 1, 2, and 3 are rotated clockwise
// by 90, 180, and 270 degrees.
//
// Vertical refresh direction is set to be the same as data write order.
// So coordinate 0 is refresh first, and coordinate 319 is refreshed last.
// For some reason, counter to datasheet information, MADCTL must be set
// with the ML bit as the inverse of the MY bit to achieve this.
rotation = m % 4; // Limit the range of values to 0-3
writecommand(TFT_MADCTL);
switch (rotation) {
case 0:
writedata(TFT_MAD_ML | TFT_MAD_RGB);
_width = TFT_WIDTH;
_height = TFT_HEIGHT;
break;
case 1:
writedata(TFT_MAD_ML | TFT_MAD_MX | TFT_MAD_MV | TFT_MAD_RGB);
_width = TFT_HEIGHT;
_height = TFT_WIDTH;
break;
case 2:
writedata(TFT_MAD_MX | TFT_MAD_MY | TFT_MAD_RGB);
_width = TFT_WIDTH;
_height = TFT_HEIGHT;
break;
case 3:
writedata(TFT_MAD_MY | TFT_MAD_MV | TFT_MAD_RGB);
_width = TFT_HEIGHT;
_height = TFT_WIDTH;
break;
}

View File

@ -37,6 +37,25 @@
// Fast SPI block write prototype // Fast SPI block write prototype
void spiWriteBlock(uint16_t color, uint32_t repeat); void spiWriteBlock(uint16_t color, uint32_t repeat);
// Bit-stuffing for fast ESP8266 9-bit SPI (for 3-wire protocol used
// by ST7787_DRIVER).
#ifdef IFACE_3WIRE_ESP8266
#define STARTBITS(cur_, pos_, spireg_) { cur_ = 0; pos_ = 32; spireg_ = &SPI1W0; }
#define ADDBITS(val_, bits_, cur_, pos_, spireg_) { \
if ((pos_) < (bits_)) \
{ \
cur_ |= (val_) >> ((bits_) - (pos_)); \
*spireg_++ = cur_; \
pos_ = 32 - ((bits_) - (pos_)); \
cur_ = ((uint32_t)(val_) << (pos_)); \
} else { \
pos_ -= (bits_); \
cur_ |= ((uint32_t)(val_) << (pos_)); \
} \
}
#define FLUSHBITS(cur_, spireg_) { *spireg_ = cur_; }
#endif
// If the SPI library has transaction support, these functions // If the SPI library has transaction support, these functions
// establish settings and protect from interference from other // establish settings and protect from interference from other
// libraries. Otherwise, they simply do nothing. // libraries. Otherwise, they simply do nothing.
@ -44,7 +63,13 @@ void spiWriteBlock(uint16_t color, uint32_t repeat);
inline void TFT_eSPI::spi_begin(void){ inline void TFT_eSPI::spi_begin(void){
#ifdef SPI_HAS_TRANSACTION #ifdef SPI_HAS_TRANSACTION
#ifdef SUPPORT_TRANSACTIONS #ifdef SUPPORT_TRANSACTIONS
if (locked) {locked = false; SPI.beginTransaction(SPISettings(SPI_FREQUENCY, MSBFIRST, SPI_MODE0));} if (locked) {
locked = false;
SPI.beginTransaction(SPISettings(SPI_FREQUENCY, MSBFIRST, SPI_MODE0));
#ifdef IFACE_3WIRE_ESP8266
SPI1U |= (uint32_t)(SPIUWRBYO|SPIURDBYO);
#endif
}
#endif #endif
#endif #endif
} }
@ -52,7 +77,15 @@ inline void TFT_eSPI::spi_begin(void){
inline void TFT_eSPI::spi_end(void){ inline void TFT_eSPI::spi_end(void){
#ifdef SPI_HAS_TRANSACTION #ifdef SPI_HAS_TRANSACTION
#ifdef SUPPORT_TRANSACTIONS #ifdef SUPPORT_TRANSACTIONS
if(!inTransaction) {if (!locked) {locked = true; SPI.endTransaction();}} if(!inTransaction) {
if (!locked) {
locked = true;
#ifdef IFACE_3WIRE_ESP8266
SPI1U &= ~(uint32_t)(SPIUWRBYO|SPIURDBYO);
#endif
SPI.endTransaction();
}
}
#endif #endif
#endif #endif
} }
@ -191,6 +224,10 @@ void TFT_eSPI::init(void)
SPI.setDataMode(SPI_MODE0); SPI.setDataMode(SPI_MODE0);
SPI.setFrequency(SPI_FREQUENCY); SPI.setFrequency(SPI_FREQUENCY);
#ifdef IFACE_3WIRE_ESP8266
SPI1U |= (uint32_t)(SPIUWRBYO|SPIURDBYO);
#endif
#ifdef ESP32 // Unlock the SPI hal mutex and set the lock management flags #ifdef ESP32 // Unlock the SPI hal mutex and set the lock management flags
SPI.beginTransaction(SPISettings(SPI_FREQUENCY, MSBFIRST, SPI_MODE0)); SPI.beginTransaction(SPISettings(SPI_FREQUENCY, MSBFIRST, SPI_MODE0));
inTransaction = true; // Flag to stop intermediate spi_end calls inTransaction = true; // Flag to stop intermediate spi_end calls
@ -249,6 +286,9 @@ void TFT_eSPI::init(void)
#elif defined (RPI_ILI9486_DRIVER) #elif defined (RPI_ILI9486_DRIVER)
#include "TFT_Drivers/RPI_ILI9486_Init.h" #include "TFT_Drivers/RPI_ILI9486_Init.h"
#elif defined(ST7787_DRIVER)
#include "TFT_Drivers/ST7787_Init.h"
#endif #endif
spi_end(); spi_end();
@ -281,6 +321,9 @@ void TFT_eSPI::setRotation(uint8_t m)
#elif defined (RPI_ILI9486_DRIVER) #elif defined (RPI_ILI9486_DRIVER)
#include "TFT_Drivers/RPI_ILI9486_Rotation.h" #include "TFT_Drivers/RPI_ILI9486_Rotation.h"
#elif defined (ST7787_DRIVER)
#include "TFT_Drivers/ST7787_Rotation.h"
#endif #endif
delayMicroseconds(10); delayMicroseconds(10);
@ -332,16 +375,111 @@ void TFT_eSPI::commandList (const uint8_t *addr)
** Function name: spiwrite ** Function name: spiwrite
** Description: Write 8 bits to SPI port (legacy support only) ** Description: Write 8 bits to SPI port (legacy support only)
***************************************************************************************/ ***************************************************************************************/
// Does not make sense in 3-wire mode, which requires an extra data/command bit
// with every byte.
#ifndef IFACE_3WIRE
void TFT_eSPI::spiwrite(uint8_t c) void TFT_eSPI::spiwrite(uint8_t c)
{ {
SPI.transfer(c); SPI.transfer(c);
} }
#endif
/***************************************************************************************
** Function name: docommand
** Description: Send command, with optional input data in IN buffer and
** optional read out result to OUT buffer
***************************************************************************************/
#ifdef IFACE_3WIRE
#ifdef IFACE_3WIRE_ESP8266
void TFT_eSPI::docommand(uint8_t c, uint8_t *in, uint32_t in_len, uint8_t *out, uint32_t out_len)
{
uint32_t i;
uint32_t val;
CS_L;
uint32_t mask = ~((SPIMMOSI << SPILMOSI) | (SPIMMISO << SPILMISO));
mask = SPI1U1 & mask;
// Send the command byte, with a '0' DC bit.
SPI1U1 = mask | ((CMD_BITS+1) << SPILMOSI) | ((CMD_BITS+1) << SPILMISO);
SPI1W0 = (uint32_t)c << 23;
SPI1CMD |= SPIBUSY;
while(SPI1CMD & SPIBUSY) {}
if (in_len) {
do {
val = *in++;
SPI1U1 = mask | ((CMD_BITS+1) << SPILMOSI) | ((CMD_BITS+1) << SPILMISO);
SPI1W0 = (uint32_t)0x80000000 | (val << 23);
SPI1CMD |= SPIBUSY;
val <<= 1;
--in_len;
while(SPI1CMD & SPIBUSY) {}
} while (in_len > 0);
}
if (out_len) {
// temporarily disable the MOSI pin while we read into MISO.
pinMode(MOSI, INPUT);
SPI1U1 = mask | ((CMD_BITS+1) << SPILMOSI) | ((CMD_BITS+1) << SPILMISO);
SPI1W0 = 0;
SPI1CMD |= SPIBUSY;
while(SPI1CMD & SPIBUSY) {}
*out++ = SPI1W0 >> 23;
while (--out_len > 0) {
SPI1U1 = mask | (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO);
SPI1W0 = 0;
SPI1CMD |= SPIBUSY;
while(SPI1CMD & SPIBUSY) {}
*out++ = SPI1W0 >> 24;
}
pinMode(MOSI, SPECIAL);
}
CS_H;
}
#else
#error 3WIRE protocol currently only implemented for ESP8266
#endif
#endif
/*************************************************************************************** /***************************************************************************************
** Function name: writecommand ** Function name: writecommand
** Description: Send an 8 bit command to the TFT ** Description: Send an 8 bit command to the TFT
***************************************************************************************/ ***************************************************************************************/
#ifdef IFACE_3WIRE
#ifdef IFACE_3WIRE_ESP8266
void TFT_eSPI::writecommand(uint8_t c)
{
CS_L;
uint32_t mask = ~((SPIMMOSI << SPILMOSI) | (SPIMMISO << SPILMISO));
mask = SPI1U1 & mask;
SPI1U1 = mask | ((CMD_BITS+1) << SPILMOSI) | ((CMD_BITS+1) << SPILMISO);
SPI1W0 = (uint32_t)c << 23;
SPI1CMD |= SPIBUSY;
while(SPI1CMD & SPIBUSY) {}
CS_H;
}
#else
void TFT_eSPI::writecommand(uint8_t c)
{
docommand(c, NULL, 0, NULL, 0);
}
#endif
#else
void TFT_eSPI::writecommand(uint8_t c) void TFT_eSPI::writecommand(uint8_t c)
{ {
DC_C; DC_C;
@ -354,14 +492,37 @@ void TFT_eSPI::writecommand(uint8_t c)
DC_D; DC_D;
} }
#endif /* IFACE_3WIRE */
/*************************************************************************************** /***************************************************************************************
** Function name: writedata ** Function name: writedata
** Description: Send a 8 bit data value to the TFT ** Description: Send a 8 bit data value to the TFT
***************************************************************************************/ ***************************************************************************************/
#ifdef IFACE_3WIRE
#ifdef IFACE_3WIRE_ESP8266
void TFT_eSPI::writedata(uint8_t c) void TFT_eSPI::writedata(uint8_t c)
{ {
CS_L; CS_L;
uint32_t mask = ~((SPIMMOSI << SPILMOSI) | (SPIMMISO << SPILMISO));
mask = SPI1U1 & mask;
SPI1U1 = mask | ((CMD_BITS+1) << SPILMOSI) | ((CMD_BITS+1) << SPILMISO);
SPI1W0 = (uint32_t)0x80000000 | ((uint32_t)c << 23);
SPI1CMD |= SPIBUSY;
while(SPI1CMD & SPIBUSY) {}
CS_H;
}
#else
#error 3WIRE protocol currently only implemented for ESP8266
#endif
#else /* !IFACE_3WIRE */
void TFT_eSPI::writedata(uint8_t c)
{
CS_L;
#ifdef SEND_16_BITS #ifdef SEND_16_BITS
SPI.transfer(0); SPI.transfer(0);
#endif #endif
@ -369,11 +530,31 @@ void TFT_eSPI::writedata(uint8_t c)
CS_H; CS_H;
} }
#endif
/*************************************************************************************** /***************************************************************************************
** Function name: readcommand8 (for ILI9341 Interface II i.e. IM [3:0] = "1101") ** Function name: readcommand8 (for ILI9341 Interface II i.e. IM [3:0] = "1101")
** Description: Read a 8 bit data value from an indexed command register ** Description: Read a 8 bit data value from an indexed command register
***************************************************************************************/ ***************************************************************************************/
#ifdef IFACE_3WIRE
// The 3-wire readcommand8() function is currently untested. The ST7787 is the
// only driver using this protocol, and it does not have the 0xD9 command for
// reading partial registers. Instead, the docommand() function can be used
// to do a full read with the various read commands available (RDDID, RDDST, ...)
uint8_t TFT_eSPI::readcommand8(uint8_t cmd_function, uint8_t index)
{
spi_begin();
index = 0x10 + (index & 0x0F);
docommand(0xD9, &index, 1, NULL, 0);
uint8_t reg;
docommand(cmd_function, NULL, 0, &reg, 1);
spi_end();
return reg;
}
#else
uint8_t TFT_eSPI::readcommand8(uint8_t cmd_function, uint8_t index) uint8_t TFT_eSPI::readcommand8(uint8_t cmd_function, uint8_t index)
{ {
spi_begin(); spi_begin();
@ -396,6 +577,7 @@ void TFT_eSPI::writedata(uint8_t c)
spi_end(); spi_end();
return reg; return reg;
} }
#endif
/*************************************************************************************** /***************************************************************************************
@ -433,6 +615,40 @@ void TFT_eSPI::writedata(uint8_t c)
** Function name: read pixel (for SPI Interface II i.e. IM [3:0] = "1101") ** Function name: read pixel (for SPI Interface II i.e. IM [3:0] = "1101")
** Description: Read 565 pixel colours from a pixel ** Description: Read 565 pixel colours from a pixel
***************************************************************************************/ ***************************************************************************************/
#ifdef IFACE_3WIRE
#ifdef IFACE_3WIRE_ESP8266
uint16_t TFT_eSPI::readPixel(int32_t x0, int32_t y0)
{
spi_begin();
readAddrWindow(x0, y0, x0, y0); // Sets CS low and MOSI in input
// Read 4 bytes - one dummy value and the three RGB values.
// Apparently there is also a dummy bit before, just like other reads.
uint32_t mask = ~((SPIMMOSI << SPILMOSI) | (SPIMMISO << SPILMISO));
mask = SPI1U1 & mask;
SPI1U1 = mask | ((33-1) << SPILMOSI) | ((33-1) << SPILMISO);
SPI1W0 = 0;
SPI1CMD |= SPIBUSY;
while(SPI1CMD & SPIBUSY) {}
uint32_t result = (SPI1W0 << 1) | (SPI1W1 >> 31);
uint8_t r = result >> 16;
uint8_t g = result >> 8;
uint8_t b = result;
pinMode(MOSI, SPECIAL);
CS_H;
spi_end();
return color565(r, g, b);
}
#else
// ToDo: ESP32 3-wire version of readPixel().
#endif /* IFACE_3WIRE_ESP8266 */
#else
uint16_t TFT_eSPI::readPixel(int32_t x0, int32_t y0) uint16_t TFT_eSPI::readPixel(int32_t x0, int32_t y0)
{ {
spi_begin(); spi_begin();
@ -453,12 +669,92 @@ uint16_t TFT_eSPI::readPixel(int32_t x0, int32_t y0)
return color565(r, g, b); return color565(r, g, b);
} }
#endif
/*************************************************************************************** /***************************************************************************************
** Function name: read rectangle (for SPI Interface II i.e. IM [3:0] = "1101") ** Function name: read rectangle (for SPI Interface II i.e. IM [3:0] = "1101")
** Description: Read 565 pixel colours from a defined area ** Description: Read 565 pixel colours from a defined area
***************************************************************************************/ ***************************************************************************************/
#ifdef IFACE_3WIRE
#ifdef IFACE_3WIRE_ESP8266
void TFT_eSPI::readRect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint16_t *data)
{
if ((x > _width) || (y > _height) || (w == 0) || (h == 0)) return;
addr_col = 0xFFFF;
addr_row = 0xFFFF;
#ifdef CGRAM_OFFSET
x+=colstart;
y+=rowstart;
#endif
spi_begin();
CS_L;
uint32_t mask = ~((SPIMMOSI << SPILMOSI) | (SPIMMISO << SPILMISO));
mask = SPI1U1 & mask;
// Apparently, the 3-wire serial interface in the ST7787 does not support
// reading out multiple pixels. The data pin goes high-Z after one pixel no
// matter the size of the read window, and the datasheet seems to hint at
// this as well.
// So we have to go the slow way, with one RAMRD command per pixel :-/
uint32_t i, j;
for (j = 0; j < h; ++j) {
for (i = 0; i < w; ++i) {
uint32_t cur, pos;
volatile uint32_t *spireg;
uint32_t numbits = 9-1;
STARTBITS(cur, pos, spireg);
if (w != 1 || (j == 0 && i == 0)) {
uint32_t tmp = (uint32_t)0x20100 | (((x+i) & 0xff00) << 1) | ((x+i) & 0xff);
ADDBITS(((uint32_t)TFT_CASET << 18) | tmp, 27, cur, pos, spireg);
ADDBITS(tmp, 18, cur, pos, spireg);
numbits += 27+18;
}
if (i == 0) {
uint32_t tmp = (uint32_t)0x20100 | (((y+j) & 0xff00) << 1) | ((y+j) & 0xff);
ADDBITS(((uint32_t)TFT_PASET << 18) | tmp, 27, cur, pos, spireg);
ADDBITS(tmp, 18, cur, pos, spireg);
numbits += 27+18;
}
ADDBITS(TFT_RAMRD, 9, cur, pos, spireg);
FLUSHBITS(cur, spireg);
SPI1U1 = mask | (numbits << SPILMOSI) | (numbits << SPILMISO);
SPI1CMD |= SPIBUSY;
while(SPI1CMD & SPIBUSY) {}
// temporarily disable the MOSI pin while we read into MISO.
pinMode(MOSI, INPUT);
// There is one dummy bit and one dummy byte before the real data.
SPI1U1 = mask | ((9+24-1) << SPILMOSI) | ((9+24-1) << SPILMISO);
SPI1CMD |= SPIBUSY;
while(SPI1CMD & SPIBUSY) {}
uint32_t val1 = SPI1W0;
uint32_t val2 = SPI1W1;
uint8_t r = val1 >> 15;
uint8_t g = val1 >> 7;
uint8_t b = (val1 << 1) | (val2 >> 31);
// Swapped colour byte order for compatibility with pushRect()
*data++ = (r & 0xF8) | (g & 0xE0) >> 5 | (b & 0xF8) << 5 | (g & 0x1C) << 11;
pinMode(MOSI, SPECIAL);
}
}
CS_H;
spi_end();
}
#else
// ToDo: ESP32 3-wire version of readRect().
#endif /* IFACE_3WIRE_ESP8266 */
#else
void TFT_eSPI::readRect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint16_t *data) void TFT_eSPI::readRect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint16_t *data)
{ {
if ((x > _width) || (y > _height) || (w == 0) || (h == 0)) return; if ((x > _width) || (y > _height) || (w == 0) || (h == 0)) return;
@ -491,12 +787,60 @@ uint16_t TFT_eSPI::readPixel(int32_t x0, int32_t y0)
spi_end(); spi_end();
} }
#endif
/*************************************************************************************** /***************************************************************************************
** Function name: push rectangle (for SPI Interface II i.e. IM [3:0] = "1101") ** Function name: push rectangle (for SPI Interface II i.e. IM [3:0] = "1101")
** Description: push 565 pixel colours into a defined area ** Description: push 565 pixel colours into a defined area
***************************************************************************************/ ***************************************************************************************/
#ifdef IFACE_3WIRE
#ifdef IFACE_3WIRE_ESP8266
void TFT_eSPI::pushRect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint16_t *data)
{
if ((x > _width) || (y > _height) || (w == 0) || (h == 0)) return;
spi_begin();
setAddrWindow(x, y, x + w - 1, y + h - 1); // Sets CS low and sent RAMWR
uint32_t mask = ~((SPIMMOSI << SPILMOSI) | (SPIMMISO << SPILMISO));
mask = SPI1U1 & mask;
uint32_t len = w * h;
while (len > 0) {
uint32_t cur, pos;
volatile uint32_t *spireg;
STARTBITS(cur, pos, spireg);
uint32_t chunk = len;
if (chunk > 28)
chunk = 28;
uint32_t count = chunk;
while (count-- > 0) {
uint32_t val = *data++;
uint32_t color18 = (uint32_t)0x20100 | ((val & 0xff) << 9) | ((val >> 8) & 0xff);
ADDBITS(color18, 18, cur, pos, spireg);
}
FLUSHBITS(cur, spireg);
SPI1U1 = mask | ((chunk*18-1) << SPILMOSI) | ((chunk*18-1) << SPILMISO);
SPI1CMD |= SPIBUSY;
while(SPI1CMD & SPIBUSY) {}
len -= chunk;
}
CS_H;
spi_end();
}
#else
// ToDo: ESP32 3-wire version of pushRect().
#endif /* IFACE_3WIRE_ESP8266 */
#else
void TFT_eSPI::pushRect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint16_t *data) void TFT_eSPI::pushRect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint16_t *data)
{ {
if ((x > _width) || (y > _height) || (w == 0) || (h == 0)) return; if ((x > _width) || (y > _height) || (w == 0) || (h == 0)) return;
@ -514,6 +858,7 @@ uint16_t TFT_eSPI::readPixel(int32_t x0, int32_t y0)
spi_end(); spi_end();
} }
#endif
/*************************************************************************************** /***************************************************************************************
@ -1333,10 +1678,17 @@ void TFT_eSPI::drawChar(int32_t x, int32_t y, unsigned char c, uint32_t color, u
column[5] = 0; column[5] = 0;
#if defined (ESP8266) #if defined (ESP8266)
#ifdef IFACE_3WIRE_ESP8266
color = (uint32_t)0x80400000 | ((color & 0xff00) << 15) | ((color & 0xff) << 14);
bg = (uint32_t)0x80400000 | ((bg & 0xff00) << 15) | ((bg & 0xff) << 14);
uint32_t spimask = ~((SPIMMOSI << SPILMOSI) | (SPIMMISO << SPILMISO));
SPI1U1 = (SPI1U1 & spimask) | (17 << SPILMOSI) | (17 << SPILMISO);
#else
color = (color >> 8) | (color << 8); color = (color >> 8) | (color << 8);
bg = (bg >> 8) | (bg << 8); bg = (bg >> 8) | (bg << 8);
uint32_t spimask = ~((SPIMMOSI << SPILMOSI) | (SPIMMISO << SPILMISO)); uint32_t spimask = ~((SPIMMOSI << SPILMOSI) | (SPIMMISO << SPILMISO));
SPI1U1 = (SPI1U1 & spimask) | (15 << SPILMOSI) | (15 << SPILMISO); SPI1U1 = (SPI1U1 & spimask) | (15 << SPILMOSI) | (15 << SPILMISO);
#endif
for (int8_t j = 0; j < 8; j++) { for (int8_t j = 0; j < 8; j++) {
for (int8_t k = 0; k < 5; k++ ) { for (int8_t k = 0; k < 5; k++ ) {
if (column[k] & mask) { if (column[k] & mask) {
@ -1573,7 +1925,83 @@ void TFT_eSPI::setWindow(int16_t x0, int16_t y0, int16_t x1, int16_t y1)
***************************************************************************************/ ***************************************************************************************/
// Chip select stays low, use setWindow() from sketches // Chip select stays low, use setWindow() from sketches
#if defined (ESP8266) && !defined (RPI_WRITE_STROBE) && !defined (RPI_ILI9486_DRIVER) #ifdef IFACE_3WIRE
#ifdef IFACE_3WIRE_ESP8266
inline void TFT_eSPI::setAddrWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye)
{
//spi_begin();
addr_col = 0xFFFF;
addr_row = 0xFFFF;
#ifdef CGRAM_OFFSET
xs+=colstart;
xe+=colstart;
ys+=rowstart;
ye+=rowstart;
#endif
// Column addr set
CS_L;
uint32_t mask = ~((SPIMMOSI << SPILMOSI) | (SPIMMISO << SPILMISO));
mask = SPI1U1 & mask;
uint32_t cur, pos;
volatile uint32_t *spireg;
uint32_t numbits = 9+36+9+36+9-1;
STARTBITS(cur, pos, spireg);
ADDBITS(((uint32_t)TFT_CASET << 18) | (uint32_t)0x20100 | ((xs & 0xff00) << 1) | (xs & 0xff),
27, cur, pos, spireg);
ADDBITS((uint32_t)0x20100 | ((xe & 0xff00) << 1) | (xe & 0xff), 18, cur, pos, spireg);
ADDBITS(((uint32_t)TFT_PASET << 18) | (uint32_t)0x20100 | ((ys & 0xff00) << 1) | (ys & 0xff),
27, cur, pos, spireg);
ADDBITS((uint32_t)0x20100 | ((ye & 0xff00) << 1) | (ye & 0xff), 18, cur, pos, spireg);
ADDBITS(TFT_RAMWR, 9, cur, pos, spireg);
FLUSHBITS(cur, spireg);
SPI1U1 = mask | (numbits << SPILMOSI) | (numbits << SPILMISO);
SPI1CMD |= SPIBUSY;
while(SPI1CMD & SPIBUSY) {}
//spi_end();
}
#else /* !IFACE_3WIRE_ESP8266 */
inline void TFT_eSPI::setAddrWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye)
{
uint8_t buf[4];
addr_col = 0xFFFF;
addr_row = 0xFFFF;
#ifdef CGRAM_OFFSET
xs+=colstart;
xe+=colstart;
ys+=rowstart;
ye+=rowstart;
#endif
// Column addr set
buf[0] = xs >> 8;
buf[1] = xs & 0xff;
buf[2] = xe >> 8;
buf[3] = xe & 0xff;
docommand(TFT_CASET, buf, 4, NULL, 0);
// Row addr set
buf[0] = ys >> 8;
buf[1] = ys & 0xff;
buf[2] = ye >> 8;
buf[3] = ye & 0xff;
docommand(TFT_PASET, buf, 4, NULL, 0);
// write to RAM
docommand(TFT_RAMWR, NULL, 0, NULL, 0);
CS_L;
/* ToDo: This could be done smarter, for now just made simple to match other code. */
}
#endif /* IFACE_3WIRE_ESP8266 */
#elif defined (ESP8266) && !defined (RPI_WRITE_STROBE) && !defined (RPI_ILI9486_DRIVER)
inline void TFT_eSPI::setAddrWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye) inline void TFT_eSPI::setAddrWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye)
{ {
//spi_begin(); //spi_begin();
@ -1853,7 +2281,54 @@ inline void TFT_eSPI::setAddrWindow(int32_t x0, int32_t y0, int32_t x1, int32_t
** Description: define an area to read a stream of pixels ** Description: define an area to read a stream of pixels
***************************************************************************************/ ***************************************************************************************/
// Chip select stays low // Chip select stays low
#if defined (ESP8266) && !defined (RPI_WRITE_STROBE) #ifdef IFACE_3WIRE
#ifdef IFACE_3WIRE_ESP8266
void TFT_eSPI::readAddrWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye)
{
//spi_begin();
addr_col = 0xFFFF;
addr_row = 0xFFFF;
#ifdef CGRAM_OFFSET
xs+=colstart;
xe+=colstart;
ys+=rowstart;
ye+=rowstart;
#endif
CS_L;
uint32_t mask = ~((SPIMMOSI << SPILMOSI) | (SPIMMISO << SPILMISO));
mask = SPI1U1 & mask;
uint32_t cur, pos;
volatile uint32_t *spireg;
uint32_t numbits = 9+36+9+36+9-1;
STARTBITS(cur, pos, spireg);
ADDBITS(((uint32_t)TFT_CASET << 18) | (uint32_t)0x20100 | ((xs & 0xff00) << 1) | (xs & 0xff),
27, cur, pos, spireg);
ADDBITS((uint32_t)0x20100 | ((xe & 0xff00) << 1) | (xe & 0xff), 18, cur, pos, spireg);
ADDBITS(((uint32_t)TFT_PASET << 18) | (uint32_t)0x20100 | ((ys & 0xff00) << 1) | (ys & 0xff),
27, cur, pos, spireg);
ADDBITS((uint32_t)0x20100 | ((ye & 0xff00) << 1) | (ye & 0xff), 18, cur, pos, spireg);
ADDBITS(TFT_RAMRD, 9, cur, pos, spireg);
FLUSHBITS(cur, spireg);
SPI1U1 = mask | (numbits << SPILMOSI) | (numbits << SPILMISO);
SPI1CMD |= SPIBUSY;
while(SPI1CMD & SPIBUSY) {}
// temporarily disable the MOSI pin while we read into MISO.
pinMode(MOSI, INPUT);
//spi_end();
}
#else
// ToDo: ESP32 3-wire version of readAddrWindow().
#endif /* IFACE_3WIRE_ESP8266 */
#elif defined (ESP8266) && !defined (RPI_WRITE_STROBE)
void TFT_eSPI::readAddrWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye) void TFT_eSPI::readAddrWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye)
{ {
//spi_begin(); //spi_begin();
@ -1969,7 +2444,107 @@ void TFT_eSPI::readAddrWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1)
** Function name: drawPixel ** Function name: drawPixel
** Description: push a single pixel at an arbitrary position ** Description: push a single pixel at an arbitrary position
***************************************************************************************/ ***************************************************************************************/
#if defined (ESP8266) && !defined (RPI_WRITE_STROBE) #ifdef IFACE_3WIRE
#ifdef IFACE_3WIRE_ESP8266
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;
#ifdef CGRAM_OFFSET
x+=colstart;
y+=rowstart;
#endif
spi_begin();
CS_L;
uint32_t mask = ~((SPIMMOSI << SPILMOSI) | (SPIMMISO << SPILMISO));
mask = SPI1U1 & mask;
uint32_t cur, pos;
volatile uint32_t *spireg;
uint32_t numbits = 27;
STARTBITS(cur, pos, spireg);
// No need to send x if it has not changed (speeds things up)
if (addr_col != x) {
ADDBITS(((uint32_t)TFT_CASET << 18) | ((uint32_t)0x20100 | ((x & 0xff00) << 1) | (x & 0xff)),
27, cur, pos, spireg);
ADDBITS((uint32_t)0x20100 | ((x & 0xff00) << 1) | (x & 0xff), 18, cur, pos, spireg);
numbits += 45;
addr_col = x;
}
// No need to send y if it has not changed (speeds things up)
if (addr_row != y) {
ADDBITS(((uint32_t)TFT_PASET << 18) | ((uint32_t)0x20100 | ((y & 0xff00) << 1) | (y & 0xff)),
27, cur, pos, spireg);
ADDBITS((uint32_t)0x20100 | ((y & 0xff00) << 1) | (y & 0xff), 18, cur, pos, spireg);
numbits += 45;
addr_row = y;
}
ADDBITS(((uint32_t)TFT_RAMWR << 18) | (uint32_t)0x20100 | ((color & 0xff00) << 1) | (color & 0xff),
27, cur, pos, spireg);
FLUSHBITS(cur, spireg);
SPI1U1 = mask | (numbits << SPILMOSI) | (numbits << SPILMISO);
SPI1CMD |= SPIBUSY;
while(SPI1CMD & SPIBUSY) {}
CS_H;
spi_end();
}
#else
void TFT_eSPI::drawPixel(uint32_t x, uint32_t y, uint32_t color)
{
uint8_t buf[4];
// Faster range checking, possible because x and y are unsigned
if ((x >= _width) || (y >= _height)) return;
#ifdef CGRAM_OFFSET
x+=colstart;
y+=rowstart;
#endif
spi_begin();
CS_L;
// No need to send x if it has not changed (speeds things up)
if (addr_col != x) {
buf[0] = x >> 8;
buf[1] = x & 0xff;
buf[2] = x >> 8;
buf[3] = x & 0xff;
docommand(TFT_CASET, buf, 4, NULL, 0);
addr_col = x;
}
// No need to send y if it has not changed (speeds things up)
if (addr_row != y) {
buf[0] = y >> 8;
buf[1] = y & 0xff;
buf[2] = y >> 8;
buf[3] = y & 0xff;
docommand(TFT_PASET, buf, 4, NULL, 0);
addr_row = y;
}
buf[0] = color >> 8;
buf[1] = color & 0xff;
docommand(TFT_RAMWR, buf, 2, NULL, 0);
spi_end();
}
#endif
#elif defined (ESP8266) && !defined (RPI_WRITE_STROBE)
void TFT_eSPI::drawPixel(uint32_t x, uint32_t y, uint32_t color) void TFT_eSPI::drawPixel(uint32_t x, uint32_t y, uint32_t color)
{ {
// Faster range checking, possible because x and y are unsigned // Faster range checking, possible because x and y are unsigned
@ -2239,6 +2814,33 @@ void TFT_eSPI::drawPixel(uint32_t x, uint32_t y, uint32_t color)
** Function name: pushColor ** Function name: pushColor
** Description: push a single pixel ** Description: push a single pixel
***************************************************************************************/ ***************************************************************************************/
#ifdef IFACE_3WIRE
#ifdef IFACE_3WIRE_ESP8266
void TFT_eSPI::pushColor(uint16_t color)
{
spi_begin();
CS_L;
uint32_t mask = ~((SPIMMOSI << SPILMOSI) | (SPIMMISO << SPILMISO));
mask = SPI1U1 & mask;
SPI1U1 = mask | ((18-1) << SPILMOSI) | ((18-1) << SPILMISO);
SPI1W0 = (uint32_t)0x80400000 |
(((uint32_t)color & 0xff00) << 15) |
(((uint32_t)color & 0xff) << 14);
SPI1CMD |= SPIBUSY;
while(SPI1CMD & SPIBUSY) {}
CS_H;
spi_end();
}
#else
// ToDo: ESP32 3-wire version of pushColor().
#endif /* IFACE_3WIRE_ESP8266 */
#else
void TFT_eSPI::pushColor(uint16_t color) void TFT_eSPI::pushColor(uint16_t color)
{ {
spi_begin(); spi_begin();
@ -2251,6 +2853,7 @@ void TFT_eSPI::pushColor(uint16_t color)
spi_end(); spi_end();
} }
#endif
/*************************************************************************************** /***************************************************************************************
@ -2296,6 +2899,35 @@ void TFT_eSPI::pushColors(uint16_t *data, uint8_t len)
while (len--) SPI.write16(*(data++)); while (len--) SPI.write16(*(data++));
#elif defined(IFACE_3WIRE_ESP8266)
uint32_t mask = ~((SPIMMOSI << SPILMOSI) | (SPIMMISO << SPILMISO));
mask = SPI1U1 & mask;
while (len > 0) {
uint32_t cur, pos;
volatile uint32_t *spireg;
STARTBITS(cur, pos, spireg);
uint32_t chunk = len;
if (chunk > 28)
chunk = 28;
uint32_t count = chunk;
while (count-- > 0) {
uint32_t val = *data++;
uint32_t color18 = (uint32_t)0x20100 | ((val & 0xff00) << 1) | (val & 0xff);
ADDBITS(color18, 18, cur, pos, spireg);
}
FLUSHBITS(cur, spireg);
SPI1U1 = mask | ((chunk*18-1) << SPILMOSI) | ((chunk*18-1) << SPILMISO);
SPI1CMD |= SPIBUSY;
while(SPI1CMD & SPIBUSY) {}
len -= chunk;
}
#else #else
uint32_t mask = ~((SPIMMOSI << SPILMOSI) | (SPIMMISO << SPILMISO)); uint32_t mask = ~((SPIMMOSI << SPILMOSI) | (SPIMMISO << SPILMISO));
@ -2356,6 +2988,37 @@ void TFT_eSPI::pushColors(uint8_t *data, uint32_t len)
//while ( len ) {SPI.writePattern(data, 2, 1); data += 2; len -= 2; } //while ( len ) {SPI.writePattern(data, 2, 1); data += 2; len -= 2; }
while ( len >=64 ) {SPI.writePattern(data, 64, 1); data += 64; len -= 64; } while ( len >=64 ) {SPI.writePattern(data, 64, 1); data += 64; len -= 64; }
if (len) SPI.writePattern(data, len, 1); if (len) SPI.writePattern(data, len, 1);
#elif defined(IFACE_3WIRE_ESP8266)
uint32_t mask = ~((SPIMMOSI << SPILMOSI) | (SPIMMISO << SPILMISO));
mask = SPI1U1 & mask;
len /= 2;
while (len > 0) {
uint32_t cur, pos;
volatile uint32_t *spireg;
STARTBITS(cur, pos, spireg);
uint32_t chunk = len;
if (chunk > 28)
chunk = 28;
uint32_t count = chunk;
while (count-- > 0) {
uint32_t val1 = *data++;
uint32_t val2 = *data++;
uint32_t color18 = (uint32_t)0x20100 | (val1 << 9) | val2;
ADDBITS(color18, 18, cur, pos, spireg);
}
FLUSHBITS(cur, spireg);
SPI1U1 = mask | ((chunk*18-1) << SPILMOSI) | ((chunk*18-1) << SPILMISO);
SPI1CMD |= SPIBUSY;
while(SPI1CMD & SPIBUSY) {}
len -= chunk;
}
#else #else
#if (SPI_FREQUENCY == 80000000) #if (SPI_FREQUENCY == 80000000)
while ( len >=64 ) {SPI.writePattern(data, 64, 1); data += 64; len -= 64; } while ( len >=64 ) {SPI.writePattern(data, 64, 1); data += 64; len -= 64; }
@ -2378,7 +3041,7 @@ void TFT_eSPI::pushColors(uint8_t *data, uint32_t len)
// Bresenham's algorithm - thx wikipedia - speed enhanced by Bodmer to use // Bresenham's algorithm - thx wikipedia - speed enhanced by Bodmer to use
// an eficient FastH/V Line draw routine for line segments of 2 pixels or more // an eficient FastH/V Line draw routine for line segments of 2 pixels or more
#if defined (RPI_ILI9486_DRIVER) || defined (ESP32) || defined (RPI_WRITE_STROBE) #if defined (RPI_ILI9486_DRIVER) || defined (ESP32) || defined (RPI_WRITE_STROBE) || defined(IFACE_3WIRE)
void TFT_eSPI::drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t color) void TFT_eSPI::drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t color)
{ {
@ -2981,6 +3644,16 @@ int16_t TFT_eSPI::drawChar(unsigned int uniCode, int x, int y, int font)
spi_begin(); spi_begin();
setAddrWindow(x, y, (x + w * 8) - 1, y + height - 1); setAddrWindow(x, y, (x + w * 8) - 1, y + height - 1);
#ifdef IFACE_3WIRE_ESP8266
uint32_t textcolor18 = (uint32_t)0x80400000 |
((textcolor & 0xff00) << 15) | ((textcolor & 0xff) << 14);
uint32_t textbgcolor18 = (uint32_t)0x80400000 |
((textbgcolor & 0xff00) << 15) | ((textbgcolor & 0xff) << 14);
uint32_t spi_mask = ~((SPIMMOSI << SPILMOSI) | (SPIMMISO << SPILMISO));
spi_mask = SPI1U1 & spi_mask;
SPI1U1 = spi_mask | ((18-1) << SPILMOSI) | ((18-1) << SPILMISO);
#endif
byte mask; byte mask;
for (int i = 0; i < height; i++) for (int i = 0; i < height; i++)
{ {
@ -2991,10 +3664,22 @@ int16_t TFT_eSPI::drawChar(unsigned int uniCode, int x, int y, int font)
mask = 0x80; mask = 0x80;
while (mask) { while (mask) {
if (line & mask) { if (line & mask) {
#ifdef IFACE_3WIRE_ESP8266
SPI1W0 = textcolor18;
SPI1CMD |= SPIBUSY;
while(SPI1CMD & SPIBUSY) {}
#else
SPI.write16(textcolor); SPI.write16(textcolor);
#endif
} }
else { else {
#ifdef IFACE_3WIRE_ESP8266
SPI1W0 = textbgcolor18;
SPI1CMD |= SPIBUSY;
while(SPI1CMD & SPIBUSY) {}
#else
SPI.write16(textbgcolor); SPI.write16(textbgcolor);
#endif
} }
mask = mask >> 1; mask = mask >> 1;
} }
@ -3024,6 +3709,13 @@ int16_t TFT_eSPI::drawChar(unsigned int uniCode, int x, int y, int font)
int pc = 0; // Pixel count int pc = 0; // Pixel count
byte np = textsize * textsize; // Number of pixels in a drawn pixel byte np = textsize * textsize; // Number of pixels in a drawn pixel
#ifdef IFACE_3WIRE_ESP8266
uint32_t textcolor18 = (uint32_t)0x80400000 |
((textcolor & 0xff00) << 15) | ((textcolor & 0xff) << 14);
uint32_t spi_mask = ~((SPIMMOSI << SPILMOSI) | (SPIMMISO << SPILMISO));
spi_mask = SPI1U1 & spi_mask;
#endif
byte tnp = 0; // Temporary copy of np for while loop byte tnp = 0; // Temporary copy of np for while loop
byte ts = textsize - 1; // Temporary copy of textsize byte ts = textsize - 1; // Temporary copy of textsize
// 16 bit pixel count so maximum font size is equivalent to 180x180 pixels in area // 16 bit pixel count so maximum font size is equivalent to 180x180 pixels in area
@ -3047,14 +3739,29 @@ int16_t TFT_eSPI::drawChar(unsigned int uniCode, int x, int y, int font)
pc++; // This is faster than putting pc+=line before while()? pc++; // This is faster than putting pc+=line before while()?
setAddrWindow(px, py, px + ts, py + ts); setAddrWindow(px, py, px + ts, py + ts);
#ifdef IFACE_3WIRE_ESP8266
SPI1U1 = spi_mask | (((18-1) << SPILMOSI) | ((18-1) << SPILMISO));
#endif
if (ts) { if (ts) {
tnp = np; tnp = np;
while (tnp--) { while (tnp--) {
#ifdef IFACE_3WIRE_ESP8266
SPI1W0 = textcolor18;
SPI1CMD |= SPIBUSY;
while(SPI1CMD & SPIBUSY) {}
#else
SPI.write16(textcolor); SPI.write16(textcolor);
#endif
} }
} }
else { else {
#ifdef IFACE_3WIRE_ESP8266
SPI1W0 = textcolor18;
SPI1CMD |= SPIBUSY;
while(SPI1CMD & SPIBUSY) {}
#else
SPI.write16(textcolor); SPI.write16(textcolor);
#endif
} }
px += textsize; px += textsize;
@ -3538,7 +4245,55 @@ void TFT_eSPI::setTextFont(uint8_t f)
** Function name: spiBlockWrite ** Function name: spiBlockWrite
** Description: Write a block of pixels of the same colour ** Description: Write a block of pixels of the same colour
***************************************************************************************/ ***************************************************************************************/
#if defined (ESP8266) && (SPI_FREQUENCY != 80000000) #ifdef IFACE_3WIRE
#ifdef IFACE_3WIRE_ESP8266
void spiWriteBlock(uint16_t color, uint32_t repeat)
{
uint32_t mask = ~(SPIMMOSI << SPILMOSI);
mask = SPI1U1 & mask;
// Stuff two color bytes with two '1' DC bits.
uint32_t color18 = (uint32_t)0x20100 | (((uint32_t)color & 0xff00) << 1) | (color & 0xff);
uint32_t cur, pos;
volatile uint32_t *spireg;
STARTBITS(cur, pos, spireg);
SPI1U = SPIUMOSI | SPIUSSE | SPIUWRBYO | SPIURDBYO;
uint32_t fillcount = repeat;
if (fillcount > 28)
fillcount = 28;
while (fillcount-- > 0)
ADDBITS(color18, 18, cur, pos, spireg);
FLUSHBITS(cur, spireg);
if (repeat >= 28)
{
SPI1U1 = mask | ((18*28-1) << SPILMOSI);
while(repeat>=28)
{
while(SPI1CMD & SPIBUSY) {}
SPI1CMD |= SPIBUSY;
repeat -= 28;
}
while(SPI1CMD & SPIBUSY) {}
}
if (repeat)
{
repeat = (repeat * 18) - 1;
SPI1U1 = mask | (repeat << SPILMOSI);
SPI1CMD |= SPIBUSY;
while(SPI1CMD & SPIBUSY) {}
}
SPI1U = SPIUMOSI | SPIUDUPLEX | SPIUSSE | SPIUWRBYO | SPIURDBYO;
}
#else
#error 3WIRE protocol currently only implemented for ESP8266
#endif /* IFACE_3WIRE */
#elif defined (ESP8266) && (SPI_FREQUENCY != 80000000)
void spiWriteBlock(uint16_t color, uint32_t repeat) void spiWriteBlock(uint16_t color, uint32_t repeat)
{ {
uint16_t color16 = (color >> 8) | (color << 8); uint16_t color16 = (color >> 8) | (color << 8);

View File

@ -30,6 +30,15 @@
#define SPI_FREQUENCY 20000000 #define SPI_FREQUENCY 20000000
#endif #endif
#ifdef ST7787_DRIVER
// ST7787 only supports a 3-wire serial interface, where the data/command bit
// is sent as a 9th bit in the SPI protocol, not on a separate wire.
#define IFACE_3WIRE 1
#ifdef ESP8266
#define IFACE_3WIRE_ESP8266 1
#endif
#endif
// Only load the fonts defined in User_Setup.h (to save space) // Only load the fonts defined in User_Setup.h (to save space)
// Set flag so RLE rendering code is optionally compiled // Set flag so RLE rendering code is optionally compiled
#ifdef LOAD_GLCD #ifdef LOAD_GLCD
@ -361,6 +370,7 @@ class TFT_eSPI : public Print {
setTextFont(uint8_t font), setTextFont(uint8_t font),
#endif #endif
spiwrite(uint8_t), spiwrite(uint8_t),
docommand(uint8_t c, uint8_t *in, uint32_t in_len, uint8_t *out, uint32_t out_len),
writecommand(uint8_t c), writecommand(uint8_t c),
writedata(uint8_t d), writedata(uint8_t d),
commandList(const uint8_t *addr); commandList(const uint8_t *addr);

View File

@ -19,6 +19,7 @@
//#define ILI9163_DRIVER //#define ILI9163_DRIVER
//#define S6D02A1_DRIVER //#define S6D02A1_DRIVER
//#define RPI_ILI9486_DRIVER // 20MHz maximum SPI //#define RPI_ILI9486_DRIVER // 20MHz maximum SPI
//#define ST7787_DRIVER
// For ST7735 and ILI9163 ONLY, define the pixel width and height in portrait orientation // For ST7735 and ILI9163 ONLY, define the pixel width and height in portrait orientation
//#define TFT_WIDTH 128 //#define TFT_WIDTH 128
@ -72,6 +73,11 @@
// //
// See Section 2. below if DC or CS is connected to D0 // See Section 2. below if DC or CS is connected to D0
// //
// On ST7787, using 3-wire mode, the DC pin is not needed and TFT_DC can be
// left undefined. MOSI should be connected to D0 on the display. MISO should
// also be connected to D0 to be able to read from the display, or can be left
// unconnected if reading is not needed.
//
// Note: only some versions of the NodeMCU provide the USB 5V on the VIN pin // Note: only some versions of the NodeMCU provide the USB 5V on the VIN pin
// If 5V is not available at a pin you can use 3.3V but backlight brightness // If 5V is not available at a pin you can use 3.3V but backlight brightness
// will be lower. // will be lower.

View File

@ -51,6 +51,8 @@
#include <TFT_Drivers/S6D02A1_Defines.h> #include <TFT_Drivers/S6D02A1_Defines.h>
#elif defined (RPI_ILI9486_DRIVER) #elif defined (RPI_ILI9486_DRIVER)
#include <TFT_Drivers/RPI_ILI9486_Defines.h> #include <TFT_Drivers/RPI_ILI9486_Defines.h>
#elif defined (ST7787_DRIVER)
#include <TFT_Drivers/ST7787_Defines.h>
#endif #endif
// These are the pins for all ESP8266 boards // These are the pins for all ESP8266 boards

View File

@ -28,7 +28,7 @@
TFT_eSPI tft = TFT_eSPI(); // Invoke library, pins defined in User_Setup.h TFT_eSPI tft = TFT_eSPI(); // Invoke library, pins defined in User_Setup.h
// Include the header files that contain the icons // Include the header files that contain the icons
#include "alert.h" #include "Alert.h"
#include "Close.h" #include "Close.h"
#include "Info.h" #include "Info.h"

View File

@ -24,7 +24,7 @@
TFT_eSPI tft = TFT_eSPI(); // Invoke custom library TFT_eSPI tft = TFT_eSPI(); // Invoke custom library
// Include the header files that contain the icons // Include the header files that contain the icons
#include "alert.h" #include "Alert.h"
#include "Close.h" #include "Close.h"
#include "Info.h" #include "Info.h"

View File

@ -0,0 +1,61 @@
// Test readPixel() and readRect()
#include <TFT_eSPI.h> // Hardware-specific library
#include <SPI.h>
TFT_eSPI tft = TFT_eSPI(); // Invoke custom library
unsigned long runTime = 0;
void setup()
{
//randomSeed(analogRead(A0));
Serial.begin(115200);
// Setup the LCD
tft.init();
}
uint16_t pixel_buf[16*16];
void loop()
{
runTime = millis();
tft.fillScreen(ILI9341_BLACK);
tft.drawPixel(1, 1, tft.color565(255, 0, 0));
tft.drawPixel(10, 10, tft.color565(0, 255, 0));
tft.drawPixel(3, 15, tft.color565(0, 0, 255));
tft.drawPixel(13, 4, tft.color565(30<<3, 20<<2, 10<<3));
Serial.println("readPixel() test:");
printRGB(tft.readPixel(0, 0));
printRGB(tft.readPixel(1, 1));
printRGB(tft.readPixel(10, 10));
printRGB(tft.readPixel(3, 15));
printRGB(tft.readPixel(13, 4));
tft.fillRect(20, 5, 18, 18, tft.color565(0x22, 0x22, 0x22));
tft.drawPixel(11, 10, tft.color565(3<<3, 5<<2, 9<<3));
tft.drawPixel(10, 11, tft.color565(0<<3, 1<<2, 2<<3));
Serial.println("readRect() test:");
tft.readRect(10, 10, 2, 2, pixel_buf);
int i;
for (i = 0; i < 4; ++i)
printRGB((pixel_buf[i]<<8)|(pixel_buf[i]>>8));
tft.readRect(0, 0, 16, 16, pixel_buf);
tft.pushRect(20+1, 5+1, 16, 16, pixel_buf);
while(1) yield();
}
void printRGB(uint16_t pixel)
{
Serial.print("RGB: ");
Serial.print(pixel >> 11);
Serial.print(" ");
Serial.print((pixel >> 5) & 0x3f);
Serial.print(" ");
Serial.println(pixel & 0x1f);
}

View File

@ -31,7 +31,7 @@
TFT_eSPI tft = TFT_eSPI(); // Invoke custom library with default width and height TFT_eSPI tft = TFT_eSPI(); // Invoke custom library with default width and height
// Include the header files that contain the icons // Include the header files that contain the icons
#include "alert.h" #include "Alert.h"
#include "Close.h" #include "Close.h"
#include "Info.h" #include "Info.h"

View File

@ -15,7 +15,7 @@
#define TFT_GREY 0x2104 // Dark grey 16 bit colour #define TFT_GREY 0x2104 // Dark grey 16 bit colour
#include "alert.h" // Out of range alert icon #include "Alert.h" // Out of range alert icon
#include <TFT_eSPI.h> // Hardware-specific library #include <TFT_eSPI.h> // Hardware-specific library
#include <SPI.h> #include <SPI.h>