Use hardware 9-bit SPI to talk to ST7787 controller.

This commit is contained in:
Kristian Nielsen 2017-06-29 00:00:48 +02:00
parent c52327324f
commit aa9352a7b2
4 changed files with 223 additions and 13 deletions

3
.gitignore vendored
View File

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

View File

@ -24,9 +24,7 @@
//#include <limits.h>
//#include "pins_arduino.h"
//#include "wiring_private.h"
#ifndef ST7787_DRIVER
#include <SPI.h>
#endif
// If it is a 16bit serial display we must transfer 16 bits every time
#ifdef RPI_ILI9486_DRIVER
@ -46,7 +44,13 @@ void spiWriteBlock(uint16_t color, uint32_t repeat);
inline void TFT_eSPI::spi_begin(void){
#ifdef SPI_HAS_TRANSACTION
#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
}
@ -54,7 +58,15 @@ inline void TFT_eSPI::spi_begin(void){
inline void TFT_eSPI::spi_end(void){
#ifdef SPI_HAS_TRANSACTION
#ifdef SUPPORT_TRANSACTIONS
if(!inTransaction) {if (!locked) {locked = true; SPI.endTransaction();}}
if(!inTransaction) {
if (!locked) {
locked = true;
SPI.endTransaction();
#ifdef IFACE_3WIRE_ESP8266
SPI1U &= ~(uint32_t)(SPIUWRBYO|SPIURDBYO);
#endif
}
}
#endif
#endif
}
@ -192,11 +204,12 @@ void TFT_eSPI::init(void)
cspinmask = (uint32_t) digitalPinToBitMask(TFT_CS);
#endif
#ifndef ST7787_DRIVER
SPI.begin(); // This will set HMISO to input
#endif
#if !defined(IFACE_3WIRE) || defined(IFACE_3WIRE_ESP8266)
SPI.begin(); // This will set HMISO to input
#endif
#else
#if defined (TFT_MOSI) && !defined (TFT_SPI_OVERLAP)
// ToDo: handle 3-wire interface on ESP32.
SPI.begin(TFT_SCLK, TFT_MISO, TFT_MOSI, -1);
#else
SPI.begin();
@ -207,20 +220,21 @@ void TFT_eSPI::init(void)
inTransaction = false;
locked = true;
#ifdef ST7787_DRIVER
#ifndef SUPPORT_TRANSACTIONS
SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE0);
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
SPI.beginTransaction(SPISettings(SPI_FREQUENCY, MSBFIRST, SPI_MODE0));
inTransaction = true; // Flag to stop intermediate spi_end calls
locked = false; // Flag to stop repeat beginTransaction calls
#endif
#endif
#endif
// Set to output once again in case D6 (MISO) is used for CS
@ -368,6 +382,62 @@ void TFT_eSPI::spiwrite(uint8_t c)
}
#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
void TFT_eSPI::docommand(uint8_t c, uint8_t *in, uint32_t in_len, uint8_t *out, uint32_t out_len)
{
uint32_t i;
@ -455,21 +525,76 @@ void TFT_eSPI::docommand(uint8_t c, uint8_t *in, uint32_t in_len, uint8_t *out,
delay_ns(ST7787_T_CHW);
}
#endif
#endif
/***************************************************************************************
** Function name: writecommand
** 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)
{
DC_C;
CS_L;
#ifdef SEND_16_BITS
SPI.transfer(0);
#endif
SPI.transfer(c);
CS_H;
DC_D;
}
#endif /* IFACE_3WIRE */
/***************************************************************************************
** Function name: writedata
** Description: Send a 8 bit data value to the TFT
***************************************************************************************/
#ifdef IFACE_3WIRE
#ifdef IFACE_3WIRE_ESP8266
void TFT_eSPI::writedata(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)0x80000000 | ((uint32_t)c << 23);
SPI1CMD |= SPIBUSY;
while(SPI1CMD & SPIBUSY) {}
CS_H;
}
#else
void TFT_eSPI::writedata(uint8_t c)
{
uint32_t i;
@ -505,7 +630,19 @@ void TFT_eSPI::writedata(uint8_t c)
CS_H;
delay_ns(ST7787_T_CHW);
}
#endif
#else /* !IFACE_3WIRE */
void TFT_eSPI::writedata(uint8_t c)
{
CS_L;
#ifdef SEND_16_BITS
SPI.transfer(0);
#endif
SPI.transfer(c);
CS_H;
}
#endif
/***************************************************************************************
** Function name: readcommand8 (for ILI9341 Interface II i.e. IM [3:0] = "1101")
@ -3749,11 +3886,71 @@ void TFT_eSPI::setTextFont(uint8_t f)
#endif
#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_; }
/***************************************************************************************
** Function name: spiBlockWrite
** Description: Write a block of pixels of the same colour
***************************************************************************************/
#if defined(ESP8266) && defined(ST7787_DRIVER)
#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
void spiWriteBlock(uint16_t color, uint32_t repeat)
{
uint32_t i;
@ -3808,6 +4005,7 @@ void spiWriteBlock(uint16_t color, uint32_t repeat)
DAT_I;
}
#endif /* IFACE_3WIRE */
#elif defined (ESP8266) && (SPI_FREQUENCY != 80000000)
void spiWriteBlock(uint16_t color, uint32_t repeat)
{

View File

@ -30,6 +30,15 @@
#define SPI_FREQUENCY 20000000
#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)
// Set flag so RLE rendering code is optionally compiled
#ifdef LOAD_GLCD

View File

@ -160,8 +160,8 @@
// #define SPI_FREQUENCY 1000000
// #define SPI_FREQUENCY 5000000
// #define SPI_FREQUENCY 10000000
// #define SPI_FREQUENCY 20000000
#define SPI_FREQUENCY 27000000 // Actually sets it to 26.67MHz = 80/3
#define SPI_FREQUENCY 20000000
// #define SPI_FREQUENCY 27000000 // Actually sets it to 26.67MHz = 80/3
// #define SPI_FREQUENCY 40000000 // Maximum to use SPIFFS
// #define SPI_FREQUENCY 80000000