Re-work the support for bi-directional SDA line

Tested on ESP32 and ST7789V display only. It may not work with other
displays!

Use:
#define TFT_SDA_READ

in setup file to use bi-directional SDA pin support.
This commit is contained in:
Bodmer committed 2018-11-24 01:30:41 +00:00
1 parent ef9e4660f1
commit d13f84e4a6
4 files changed
+112 -140

No files matched your search

+90 -130
View File
@@ -534,7 +534,7 @@ uint8_t TFT_eSPI::readcommand8(uint8_t cmd_function, uint8_t index)
CS_L;
tft_Write_8(cmd_function);
DC_D;
reg = tft_Read_8(0);
reg = tft_Read_8();
CS_H;
spi_end_read();
@@ -624,62 +624,40 @@ uint16_t TFT_eSPI::readPixel(int32_t x0, int32_t y0)
spi_begin_read();
#ifdef ST7789_DRIVER
writecommand(ST7789_COLMOD); // Switch from 16 bit colour to 18 bit (required)
writedata(0x66);
#endif
readAddrWindow(x0, y0, x0, y0); // Sets CS low
#ifdef TFT_SDA_READ
// To be investigated: spi_end_read() is VERY slow on the ESP8266 here
spi_end_read(); // Releasing the HAL mutex is mandatory for the ESP32
SPI.end(); // Disconnect the SPI peripheral to release the pins
digitalWrite(TFT_SCLK, HIGH); // Set clock pin high
pinMode(TFT_SCLK, OUTPUT); // Set the SCLK pin to output
pinMode(TFT_MOSI, INPUT_PULLUP); // Set the MOSI pin to input
begin_SDA_Read();
#endif
// Dummy read to throw away don't care value
tft_Read_8(0);
tft_Read_8();
#if !defined (ILI9488_DRIVER)
// 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
#if !defined (ILI9488_DRIVER)
uint8_t r = tft_Read_8(0);
uint8_t g = tft_Read_8(0);
uint8_t b = tft_Read_8(0);
uint8_t r = tft_Read_8();
uint8_t g = tft_Read_8();
uint8_t b = tft_Read_8();
#else
// The 6 colour bits are in MS 6 bits of each byte, but the ILI9488 needs an extra clock pulse
// so bits appear shifted right 1 bit, so mask the middle 6 bits then shift 1 place left
uint8_t r = (tft_Read_8(0)&0x7E)<<1;
uint8_t g = (tft_Read_8(0)&0x7E)<<1;
uint8_t b = (tft_Read_8(0)&0x7E)<<1;
uint8_t r = (tft_Read_8()&0x7E)<<1;
uint8_t g = (tft_Read_8()&0x7E)<<1;
uint8_t b = (tft_Read_8()&0x7E)<<1;
#endif
CS_H;
#ifdef TFT_SDA_READ
#ifdef ESP32
SPI.begin(TFT_SCLK, TFT_MISO, TFT_MOSI, -1);
#else
#ifdef TFT_SPI_OVERLAP
SPI.pins(6, 7, 8, 0);
#else
SPI.begin();
#endif
#ifdef TFT_SDA_READ
end_SDA_Read();
#endif
#ifdef ST7789_DRIVER
writecommand(ST7789_COLMOD);
writedata(0x55);
#endif
#else
spi_end_read();
#endif
return color565(r, g, b);
@@ -793,44 +771,34 @@ void TFT_eSPI::readRect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint16_t
spi_begin_read();
#ifdef ST7789_DRIVER
writecommand(ST7789_COLMOD); // Switch from 16 bit colour to 18 bit (required)
writedata(0x66);
#endif
readAddrWindow(x, y, x + w - 1, y + h - 1); // Sets CS low
#ifdef TFT_SDA_READ
// To be investigated: spi_end_read() is VERY slow on the ESP8266 here
spi_end_read(); // Releasing the HAL mutex is mandatory for the ESP32
SPI.end(); // Disconnect the SPI peripheral to release the pins
digitalWrite(TFT_SCLK, HIGH); // Set clock pin high
pinMode(TFT_SCLK, OUTPUT); // Set the SCLK pin to output
pinMode(TFT_MOSI, INPUT_PULLUP); // Set the MOSI pin to input
begin_SDA_Read();
#endif
// Dummy read to throw away don't care value
tft_Read_8(0);
tft_Read_8();
// 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
// as the TFT stores colours as 18 bits
#if !defined (ILI9488_DRIVER)
uint8_t r = tft_Read_8(0);
uint8_t g = tft_Read_8(0);
uint8_t b = tft_Read_8(0);
// 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
uint8_t r = tft_Read_8();
uint8_t g = tft_Read_8();
uint8_t b = tft_Read_8();
#else
// The 6 colour bits are in LS 6 bits of each byte but we do not include the extra clock pulse
// so we use a trick and mask the middle 6 bits of the byte, then only shift 1 place left
uint8_t r = (tft_Read_8(0)&0x7E)<<1;
uint8_t g = (tft_Read_8(0)&0x7E)<<1;
uint8_t b = (tft_Read_8(0)&0x7E)<<1;
uint8_t r = (tft_Read_8()&0x7E)<<1;
uint8_t g = (tft_Read_8()&0x7E)<<1;
uint8_t b = (tft_Read_8()&0x7E)<<1;
#endif
@@ -840,23 +808,11 @@ void TFT_eSPI::readRect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint16_t
CS_H;
#ifdef TFT_SDA_READ
#ifdef ESP32
SPI.begin(TFT_SCLK, TFT_MISO, TFT_MOSI, -1);
#else
#ifdef TFT_SPI_OVERLAP
SPI.pins(6, 7, 8, 0);
#else
SPI.begin();
#endif
#ifdef TFT_SDA_READ
end_SDA_Read();
#endif
#ifdef ST7789_DRIVER
writecommand(ST7789_COLMOD);
writedata(0x55);
#endif
#else
spi_end_read();
#endif
#endif
}
@@ -865,40 +821,66 @@ void TFT_eSPI::readRect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint16_t
** Function name: tft_Read_8
** Description: Software SPI to read bidirectional SDA line
***************************************************************************************/
// For the ST7789 the tft_Read_8() macro is replaced by a function
#ifdef TFT_SDA_READ
#ifdef ESP32
#define SCLK_L GPIO.out_w1tc = (1 << TFT_SCLK)
#define SCLK_H GPIO.out_w1ts = (1 << TFT_SCLK)
#else // ESP8266
#define SCLK_L GPOC=sclkpinmask
#define SCLK_H GPOS=sclkpinmask
#endif
uint8_t TFT_eSPI::tft_Read_8(uint8_t dummy)
#if defined (ESP8266) && defined (TFT_SDA_READ)
uint8_t TFT_eSPI::tft_Read_8(void)
{
uint8_t ret = 0;
uint32_t reg = 0;
for (uint8_t i = 0; i < 8; i++) { // read results
ret <<= 1;
#ifdef ESP32 // bit bangs at around 1MHz
SCLK_L;
//SCLK_L;
reg = gpio_input_get(); // SDA must connect to ESP32 pin in range 0-31
SCLK_H;
if (reg&(1<<TFT_MOSI)) ret |= 1;
SCLK_H; // Extra delay - must read slowly on an ST7789 to avoid bad data
#else
SCLK_L;
if (digitalRead(TFT_MOSI)) ret |= 1;
SCLK_H;
#endif
SCLK_L;
if (digitalRead(TFT_MOSI)) ret |= 1;
SCLK_H;
}
return ret;
}
#endif
/***************************************************************************************
** Function name: beginSDA
** Description: Detach SPI from pin to permit software SPI
***************************************************************************************/
#ifdef TFT_SDA_READ
void TFT_eSPI::begin_SDA_Read(void)
{
#ifdef ESP32
pinMatrixOutDetach(TFT_MOSI, false, false);
pinMode(TFT_MOSI, INPUT);
pinMatrixInAttach(TFT_MOSI, VSPIQ_IN_IDX, false);
#else // ESP8266
#ifdef TFT_SPI_OVERLAP
// Reads in overlap mode not supported
#else
SPI.end();
#endif
#endif
}
#endif
/***************************************************************************************
** Function name: endSDA
** Description: Attach SPI pins after software SPI
***************************************************************************************/
#ifdef TFT_SDA_READ
void TFT_eSPI::end_SDA_Read(void)
{
#ifdef ESP32
pinMode(TFT_MOSI, OUTPUT);
pinMatrixOutAttach(TFT_MOSI, VSPID_OUT_IDX, false, false);
pinMode(TFT_MISO, INPUT);
pinMatrixInAttach(TFT_MISO, VSPIQ_IN_IDX, false);
#else
#ifdef TFT_SPI_OVERLAP
SPI.pins(6, 7, 8, 0);
#else
SPI.begin();
#endif
#endif
}
#endif
/***************************************************************************************
** Function name: push rectangle (for SPI Interface II i.e. IM [3:0] = "1101")
** Description: push 565 pixel colours into a defined area
@@ -1454,44 +1436,34 @@ void TFT_eSPI::readRectRGB(int32_t x0, int32_t y0, int32_t w, int32_t h, uint8_
spi_begin_read();
#ifdef ST7789_DRIVER
writecommand(ST7789_COLMOD); // Switch from 16 bit colour to 18 bit (required)
writedata(0x66);
#endif
readAddrWindow(x0, y0, x0 + w - 1, y0 + h - 1); // Sets CS low
#ifdef TFT_SDA_READ
// To be investigated: spi_end_read() is VERY slow on the ESP8266 here
spi_end_read(); // Releasing the HAL mutex is mandatory for the ESP32
SPI.end(); // Disconnect the SPI peripheral to release the pins
digitalWrite(TFT_SCLK, HIGH); // Set clock pin high
pinMode(TFT_SCLK, OUTPUT); // Set the SCLK pin to output
pinMode(TFT_MOSI, INPUT_PULLUP); // Set the MOSI pin to input
begin_SDA_Read();
#endif
// Dummy read to throw away don't care value
tft_Read_8(0);
tft_Read_8();
// 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
#if !defined (ILI9488_DRIVER)
*data++ = tft_Read_8(0);
*data++ = tft_Read_8(0);
*data++ = tft_Read_8(0);
// 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
*data++ = tft_Read_8();
*data++ = tft_Read_8();
*data++ = tft_Read_8();
#else
// The 6 colour bits are in MS 6 bits of each byte, but the ILI9488 needs an extra clock pulse
// so bits appear shifted right 1 bit, so mask the middle 6 bits then shift 1 place left
*data++ = (tft_Read_8(0)&0x7E)<<1;
*data++ = (tft_Read_8(0)&0x7E)<<1;
*data++ = (tft_Read_8(0)&0x7E)<<1;
*data++ = (tft_Read_8()&0x7E)<<1;
*data++ = (tft_Read_8()&0x7E)<<1;
*data++ = (tft_Read_8()&0x7E)<<1;
#endif
@@ -1499,23 +1471,11 @@ void TFT_eSPI::readRectRGB(int32_t x0, int32_t y0, int32_t w, int32_t h, uint8_
CS_H;
#ifdef TFT_SDA_READ
#ifdef ESP32
SPI.begin(TFT_SCLK, TFT_MISO, TFT_MOSI, -1);
#else
#ifdef TFT_SPI_OVERLAP
SPI.pins(6, 7, 8, 0);
#else
SPI.begin();
#endif
#ifdef TFT_SDA_READ
end_SDA_Read();
#endif
#ifdef ST7789_DRIVER
writecommand(ST7789_COLMOD);
writedata(0x55);
#endif
#else
spi_end_read();
#endif
#endif
}
@@ -2966,7 +2926,6 @@ void TFT_eSPI::readAddrWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1)
tft_Write_8(TFT_CASET);
DC_D;
tft_Write_32(SPI_32(x0, x1));
@@ -2981,6 +2940,7 @@ void TFT_eSPI::readAddrWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1)
tft_Write_32(SPI_32(y0, y1));
DC_C;
tft_Write_8(TFT_RAMRD); // Read CGRAM command
DC_D;