Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
T
TFT_eSPI
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Analytics
Analytics
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
xpstem
TFT_eSPI
Commits
cfb4689c
Commit
cfb4689c
authored
Apr 24, 2022
by
Bodmer
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Patch for ESP32 C3 - may or may not work!
I do NOT have and ESP32 C3 to test with!
parent
416a84e5
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
1471 additions
and
0 deletions
+1471
-0
Processors/TFT_eSPI_ESP32_C3.c
Processors/TFT_eSPI_ESP32_C3.c
+859
-0
Processors/TFT_eSPI_ESP32_C3.h
Processors/TFT_eSPI_ESP32_C3.h
+608
-0
TFT_eSPI.cpp
TFT_eSPI.cpp
+2
-0
TFT_eSPI.h
TFT_eSPI.h
+2
-0
No files found.
Processors/TFT_eSPI_ESP32_C3.c
0 → 100644
View file @
cfb4689c
////////////////////////////////////////////////////
// TFT_eSPI driver functions for ESP32 processors //
////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////
// Global variables
////////////////////////////////////////////////////////////////////////////////////////
// Select the SPI port to use, ESP32 has 2 options
#if !defined (TFT_PARALLEL_8_BIT)
#ifdef CONFIG_IDF_TARGET_ESP32
#ifdef USE_HSPI_PORT
SPIClass
spi
=
SPIClass
(
HSPI
);
#elif defined(USE_FSPI_PORT)
SPIClass
spi
=
SPIClass
(
FSPI
);
#else // use default VSPI port
SPIClass
spi
=
SPIClass
(
VSPI
);
#endif
#else
#ifdef USE_HSPI_PORT
SPIClass
spi
=
SPIClass
(
HSPI
);
#elif defined(USE_FSPI_PORT)
SPIClass
spi
=
SPIClass
(
FSPI
);
#else // use FSPI port
SPIClass
&
spi
=
SPI
;
#endif
#endif
#endif
#ifdef ESP32_DMA
// DMA SPA handle
spi_device_handle_t
dmaHAL
;
#ifdef CONFIG_IDF_TARGET_ESP32
#define DMA_CHANNEL 1
#ifdef USE_HSPI_PORT
spi_host_device_t
spi_host
=
HSPI_HOST
;
#elif defined(USE_FSPI_PORT)
spi_host_device_t
spi_host
=
SPI_HOST
;
#else // use VSPI port
spi_host_device_t
spi_host
=
VSPI_HOST
;
#endif
#else
#ifdef USE_HSPI_PORT
#define DMA_CHANNEL 2
spi_host_device_t
spi_host
=
(
spi_host_device_t
)
DMA_CHANNEL
;
// Draws once then freezes
#else // use FSPI port
#define DMA_CHANNEL 1
spi_host_device_t
spi_host
=
(
spi_host_device_t
)
DMA_CHANNEL
;
// Draws once then freezes
#endif
#endif
#endif
#if !defined (TFT_PARALLEL_8_BIT)
// Volatile for register reads:
volatile
uint32_t
*
_spi_cmd
=
(
volatile
uint32_t
*
)(
SPI_CMD_REG
(
SPI_PORT
));
volatile
uint32_t
*
_spi_user
=
(
volatile
uint32_t
*
)(
SPI_USER_REG
(
SPI_PORT
));
// Register writes only:
volatile
uint32_t
*
_spi_mosi_dlen
=
(
volatile
uint32_t
*
)(
SPI_MOSI_DLEN_REG
(
SPI_PORT
));
volatile
uint32_t
*
_spi_w
=
(
volatile
uint32_t
*
)(
SPI_W0_REG
(
SPI_PORT
));
#endif
////////////////////////////////////////////////////////////////////////////////////////
#if defined (TFT_SDA_READ) && !defined (TFT_PARALLEL_8_BIT)
////////////////////////////////////////////////////////////////////////////////////////
/***************************************************************************************
** Function name: beginSDA
** Description: Detach SPI from pin to permit software SPI
***************************************************************************************/
void
TFT_eSPI
::
begin_SDA_Read
(
void
)
{
pinMatrixOutDetach
(
TFT_MOSI
,
false
,
false
);
pinMode
(
TFT_MOSI
,
INPUT
);
pinMatrixInAttach
(
TFT_MOSI
,
VSPIQ_IN_IDX
,
false
);
SET_BUS_READ_MODE
;
}
/***************************************************************************************
** Function name: endSDA
** Description: Attach SPI pins after software SPI
***************************************************************************************/
void
TFT_eSPI
::
end_SDA_Read
(
void
)
{
pinMode
(
TFT_MOSI
,
OUTPUT
);
pinMatrixOutAttach
(
TFT_MOSI
,
VSPID_OUT_IDX
,
false
,
false
);
pinMode
(
TFT_MISO
,
INPUT
);
pinMatrixInAttach
(
TFT_MISO
,
VSPIQ_IN_IDX
,
false
);
SET_BUS_WRITE_MODE
;
}
////////////////////////////////////////////////////////////////////////////////////////
#endif // #if defined (TFT_SDA_READ)
////////////////////////////////////////////////////////////////////////////////////////
/***************************************************************************************
** Function name: read byte - supports class functions
** Description: Read a byte from ESP32 8 bit data port
***************************************************************************************/
// Parallel bus MUST be set to input before calling this function!
uint8_t
TFT_eSPI
::
readByte
(
void
)
{
uint8_t
b
=
0xAA
;
#if defined (TFT_PARALLEL_8_BIT)
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
;
}
////////////////////////////////////////////////////////////////////////////////////////
#ifdef TFT_PARALLEL_8_BIT
////////////////////////////////////////////////////////////////////////////////////////
/***************************************************************************************
** Function name: GPIO direction control - supports class functions
** Description: Set parallel bus to INPUT or OUTPUT
***************************************************************************************/
void
TFT_eSPI
::
busDir
(
uint32_t
mask
,
uint8_t
mode
)
{
// Arduino generic native function
pinMode
(
TFT_D0
,
mode
);
pinMode
(
TFT_D1
,
mode
);
pinMode
(
TFT_D2
,
mode
);
pinMode
(
TFT_D3
,
mode
);
pinMode
(
TFT_D4
,
mode
);
pinMode
(
TFT_D5
,
mode
);
pinMode
(
TFT_D6
,
mode
);
pinMode
(
TFT_D7
,
mode
);
return
;
}
/***************************************************************************************
** Function name: GPIO direction control - supports class functions
** Description: Set ESP32 GPIO pin to input or output (set high) ASAP
***************************************************************************************/
void
TFT_eSPI
::
gpioMode
(
uint8_t
gpio
,
uint8_t
mode
)
{
pinMode
(
gpio
,
mode
);
digitalWrite
(
gpio
,
HIGH
);
}
////////////////////////////////////////////////////////////////////////////////////////
#endif // #ifdef TFT_PARALLEL_8_BIT
////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////
#if defined (RPI_WRITE_STROBE) && !defined (TFT_PARALLEL_8_BIT) // Code for RPi TFT
////////////////////////////////////////////////////////////////////////////////////////
/***************************************************************************************
** Function name: pushBlock - for ESP32 or ESP8266 RPi TFT
** Description: Write a block of pixels of the same colour
***************************************************************************************/
void
TFT_eSPI
::
pushBlock
(
uint16_t
color
,
uint32_t
len
)
{
uint8_t
colorBin
[]
=
{
(
uint8_t
)
(
color
>>
8
),
(
uint8_t
)
color
};
if
(
len
)
spi
.
writePattern
(
&
colorBin
[
0
],
2
,
1
);
len
--
;
while
(
len
--
)
{
WR_L
;
WR_H
;}
}
/***************************************************************************************
** Function name: pushPixels - for ESP32 or ESP8266 RPi TFT
** Description: Write a sequence of pixels
***************************************************************************************/
void
TFT_eSPI
::
pushPixels
(
const
void
*
data_in
,
uint32_t
len
)
{
uint8_t
*
data
=
(
uint8_t
*
)
data_in
;
if
(
_swapBytes
)
{
while
(
len
--
)
{
tft_Write_16
(
*
data
);
data
++
;}
return
;
}
while
(
len
>=
64
)
{
spi
.
writePattern
(
data
,
64
,
1
);
data
+=
64
;
len
-=
64
;
}
if
(
len
)
spi
.
writePattern
(
data
,
len
,
1
);
}
////////////////////////////////////////////////////////////////////////////////////////
#elif !defined (SPI_18BIT_DRIVER) && !defined (TFT_PARALLEL_8_BIT) // Most SPI displays
////////////////////////////////////////////////////////////////////////////////////////
/***************************************************************************************
** Function name: pushBlock - for ESP32
** Description: Write a block of pixels of the same colour
***************************************************************************************/
/*
void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){
uint32_t color32 = (color<<8 | color >>8)<<16 | (color<<8 | color >>8);
bool empty = true;
volatile uint32_t* spi_w = (volatile uint32_t*)_spi_w;
if (len > 31)
{
*_spi_mosi_dlen = 511;
spi_w[0] = color32;
spi_w[1] = color32;
spi_w[2] = color32;
spi_w[3] = color32;
spi_w[4] = color32;
spi_w[5] = color32;
spi_w[6] = color32;
spi_w[7] = color32;
spi_w[8] = color32;
spi_w[9] = color32;
spi_w[10] = color32;
spi_w[11] = color32;
spi_w[12] = color32;
spi_w[13] = color32;
spi_w[14] = color32;
spi_w[15] = color32;
while(len>31)
{
while ((*_spi_cmd)&SPI_USR);
*_spi_cmd = SPI_USR;
len -= 32;
}
empty = false;
}
if (len)
{
if(empty) {
for (uint32_t i=0; i <= len; i+=2) *spi_w++ = color32;
}
len = (len << 4) - 1;
while (*_spi_cmd&SPI_USR);
*_spi_mosi_dlen = len;
*_spi_cmd = SPI_USR;
}
while ((*_spi_cmd)&SPI_USR); // Move to later in code to use transmit time usefully?
}
//*/
//*
void
TFT_eSPI
::
pushBlock
(
uint16_t
color
,
uint32_t
len
){
volatile
uint32_t
*
spi_w
=
_spi_w
;
uint32_t
color32
=
(
color
<<
8
|
color
>>
8
)
<<
16
|
(
color
<<
8
|
color
>>
8
);
uint32_t
i
=
0
;
uint32_t
rem
=
len
&
0x1F
;
len
=
len
-
rem
;
// Start with partial buffer pixels
if
(
rem
)
{
while
(
*
_spi_cmd
&
SPI_USR
);
for
(
i
=
0
;
i
<
rem
;
i
+=
2
)
*
spi_w
++
=
color32
;
*
_spi_mosi_dlen
=
(
rem
<<
4
)
-
1
;
#if CONFIG_IDF_TARGET_ESP32C3
*
_spi_cmd
=
SPI_UPDATE
;
while
(
*
_spi_cmd
&
SPI_UPDATE
);
#endif
*
_spi_cmd
=
SPI_USR
;
if
(
!
len
)
return
;
//{while (*_spi_cmd&SPI_USR); return; }
i
=
i
>>
1
;
while
(
i
++<
16
)
*
spi_w
++
=
color32
;
}
while
(
*
_spi_cmd
&
SPI_USR
);
if
(
!
rem
)
while
(
i
++<
16
)
*
spi_w
++
=
color32
;
*
_spi_mosi_dlen
=
511
;
// End with full buffer to maximise useful time for downstream code
while
(
len
)
{
while
(
*
_spi_cmd
&
SPI_USR
);
#if CONFIG_IDF_TARGET_ESP32C3
*
_spi_cmd
=
SPI_UPDATE
;
while
(
*
_spi_cmd
&
SPI_UPDATE
);
#endif
*
_spi_cmd
=
SPI_USR
;
len
-=
32
;
}
// Do not wait here
//while (*_spi_cmd&SPI_USR);
}
//*/
/***************************************************************************************
** Function name: pushSwapBytePixels - for ESP32
** Description: Write a sequence of pixels with swapped bytes
***************************************************************************************/
void
TFT_eSPI
::
pushSwapBytePixels
(
const
void
*
data_in
,
uint32_t
len
){
uint8_t
*
data
=
(
uint8_t
*
)
data_in
;
uint32_t
color
[
16
];
if
(
len
>
31
)
{
WRITE_PERI_REG
(
SPI_MOSI_DLEN_REG
(
SPI_PORT
),
511
);
while
(
len
>
31
)
{
uint32_t
i
=
0
;
while
(
i
<
16
)
{
color
[
i
++
]
=
DAT8TO32
(
data
);
data
+=
4
;
}
while
(
READ_PERI_REG
(
SPI_CMD_REG
(
SPI_PORT
))
&
SPI_USR
);
WRITE_PERI_REG
(
SPI_W0_REG
(
SPI_PORT
),
color
[
0
]);
WRITE_PERI_REG
(
SPI_W1_REG
(
SPI_PORT
),
color
[
1
]);
WRITE_PERI_REG
(
SPI_W2_REG
(
SPI_PORT
),
color
[
2
]);
WRITE_PERI_REG
(
SPI_W3_REG
(
SPI_PORT
),
color
[
3
]);
WRITE_PERI_REG
(
SPI_W4_REG
(
SPI_PORT
),
color
[
4
]);
WRITE_PERI_REG
(
SPI_W5_REG
(
SPI_PORT
),
color
[
5
]);
WRITE_PERI_REG
(
SPI_W6_REG
(
SPI_PORT
),
color
[
6
]);
WRITE_PERI_REG
(
SPI_W7_REG
(
SPI_PORT
),
color
[
7
]);
WRITE_PERI_REG
(
SPI_W8_REG
(
SPI_PORT
),
color
[
8
]);
WRITE_PERI_REG
(
SPI_W9_REG
(
SPI_PORT
),
color
[
9
]);
WRITE_PERI_REG
(
SPI_W10_REG
(
SPI_PORT
),
color
[
10
]);
WRITE_PERI_REG
(
SPI_W11_REG
(
SPI_PORT
),
color
[
11
]);
WRITE_PERI_REG
(
SPI_W12_REG
(
SPI_PORT
),
color
[
12
]);
WRITE_PERI_REG
(
SPI_W13_REG
(
SPI_PORT
),
color
[
13
]);
WRITE_PERI_REG
(
SPI_W14_REG
(
SPI_PORT
),
color
[
14
]);
WRITE_PERI_REG
(
SPI_W15_REG
(
SPI_PORT
),
color
[
15
]);
#if CONFIG_IDF_TARGET_ESP32C3
SET_PERI_REG_MASK
(
SPI_CMD_REG
(
SPI_PORT
),
SPI_UPDATE
);
while
(
READ_PERI_REG
(
SPI_CMD_REG
(
SPI_PORT
))
&
SPI_UPDATE
);
#endif
SET_PERI_REG_MASK
(
SPI_CMD_REG
(
SPI_PORT
),
SPI_USR
);
len
-=
32
;
}
}
if
(
len
>
15
)
{
uint32_t
i
=
0
;
while
(
i
<
8
)
{
color
[
i
++
]
=
DAT8TO32
(
data
);
data
+=
4
;
}
while
(
READ_PERI_REG
(
SPI_CMD_REG
(
SPI_PORT
))
&
SPI_USR
);
WRITE_PERI_REG
(
SPI_MOSI_DLEN_REG
(
SPI_PORT
),
255
);
WRITE_PERI_REG
(
SPI_W0_REG
(
SPI_PORT
),
color
[
0
]);
WRITE_PERI_REG
(
SPI_W1_REG
(
SPI_PORT
),
color
[
1
]);
WRITE_PERI_REG
(
SPI_W2_REG
(
SPI_PORT
),
color
[
2
]);
WRITE_PERI_REG
(
SPI_W3_REG
(
SPI_PORT
),
color
[
3
]);
WRITE_PERI_REG
(
SPI_W4_REG
(
SPI_PORT
),
color
[
4
]);
WRITE_PERI_REG
(
SPI_W5_REG
(
SPI_PORT
),
color
[
5
]);
WRITE_PERI_REG
(
SPI_W6_REG
(
SPI_PORT
),
color
[
6
]);
WRITE_PERI_REG
(
SPI_W7_REG
(
SPI_PORT
),
color
[
7
]);
#if CONFIG_IDF_TARGET_ESP32C3
SET_PERI_REG_MASK
(
SPI_CMD_REG
(
SPI_PORT
),
SPI_UPDATE
);
while
(
READ_PERI_REG
(
SPI_CMD_REG
(
SPI_PORT
))
&
SPI_UPDATE
);
#endif
SET_PERI_REG_MASK
(
SPI_CMD_REG
(
SPI_PORT
),
SPI_USR
);
len
-=
16
;
}
if
(
len
)
{
while
(
READ_PERI_REG
(
SPI_CMD_REG
(
SPI_PORT
))
&
SPI_USR
);
WRITE_PERI_REG
(
SPI_MOSI_DLEN_REG
(
SPI_PORT
),
(
len
<<
4
)
-
1
);
for
(
uint32_t
i
=
0
;
i
<=
(
len
<<
1
);
i
+=
4
)
{
WRITE_PERI_REG
(
SPI_W0_REG
(
SPI_PORT
)
+
i
,
DAT8TO32
(
data
));
data
+=
4
;
}
#if CONFIG_IDF_TARGET_ESP32C3
SET_PERI_REG_MASK
(
SPI_CMD_REG
(
SPI_PORT
),
SPI_UPDATE
);
while
(
READ_PERI_REG
(
SPI_CMD_REG
(
SPI_PORT
))
&
SPI_UPDATE
);
#endif
SET_PERI_REG_MASK
(
SPI_CMD_REG
(
SPI_PORT
),
SPI_USR
);
}
while
(
READ_PERI_REG
(
SPI_CMD_REG
(
SPI_PORT
))
&
SPI_USR
);
}
/***************************************************************************************
** Function name: pushPixels - for ESP32
** Description: Write a sequence of pixels
***************************************************************************************/
void
TFT_eSPI
::
pushPixels
(
const
void
*
data_in
,
uint32_t
len
){
if
(
_swapBytes
)
{
pushSwapBytePixels
(
data_in
,
len
);
return
;
}
uint32_t
*
data
=
(
uint32_t
*
)
data_in
;
if
(
len
>
31
)
{
WRITE_PERI_REG
(
SPI_MOSI_DLEN_REG
(
SPI_PORT
),
511
);
while
(
len
>
31
)
{
while
(
READ_PERI_REG
(
SPI_CMD_REG
(
SPI_PORT
))
&
SPI_USR
);
WRITE_PERI_REG
(
SPI_W0_REG
(
SPI_PORT
),
*
data
++
);
WRITE_PERI_REG
(
SPI_W1_REG
(
SPI_PORT
),
*
data
++
);
WRITE_PERI_REG
(
SPI_W2_REG
(
SPI_PORT
),
*
data
++
);
WRITE_PERI_REG
(
SPI_W3_REG
(
SPI_PORT
),
*
data
++
);
WRITE_PERI_REG
(
SPI_W4_REG
(
SPI_PORT
),
*
data
++
);
WRITE_PERI_REG
(
SPI_W5_REG
(
SPI_PORT
),
*
data
++
);
WRITE_PERI_REG
(
SPI_W6_REG
(
SPI_PORT
),
*
data
++
);
WRITE_PERI_REG
(
SPI_W7_REG
(
SPI_PORT
),
*
data
++
);
WRITE_PERI_REG
(
SPI_W8_REG
(
SPI_PORT
),
*
data
++
);
WRITE_PERI_REG
(
SPI_W9_REG
(
SPI_PORT
),
*
data
++
);
WRITE_PERI_REG
(
SPI_W10_REG
(
SPI_PORT
),
*
data
++
);
WRITE_PERI_REG
(
SPI_W11_REG
(
SPI_PORT
),
*
data
++
);
WRITE_PERI_REG
(
SPI_W12_REG
(
SPI_PORT
),
*
data
++
);
WRITE_PERI_REG
(
SPI_W13_REG
(
SPI_PORT
),
*
data
++
);
WRITE_PERI_REG
(
SPI_W14_REG
(
SPI_PORT
),
*
data
++
);
WRITE_PERI_REG
(
SPI_W15_REG
(
SPI_PORT
),
*
data
++
);
#if CONFIG_IDF_TARGET_ESP32C3
SET_PERI_REG_MASK
(
SPI_CMD_REG
(
SPI_PORT
),
SPI_UPDATE
);
while
(
READ_PERI_REG
(
SPI_CMD_REG
(
SPI_PORT
))
&
SPI_UPDATE
);
#endif
SET_PERI_REG_MASK
(
SPI_CMD_REG
(
SPI_PORT
),
SPI_USR
);
len
-=
32
;
}
}
if
(
len
)
{
while
(
READ_PERI_REG
(
SPI_CMD_REG
(
SPI_PORT
))
&
SPI_USR
);
WRITE_PERI_REG
(
SPI_MOSI_DLEN_REG
(
SPI_PORT
),
(
len
<<
4
)
-
1
);
for
(
uint32_t
i
=
0
;
i
<=
(
len
<<
1
);
i
+=
4
)
WRITE_PERI_REG
((
SPI_W0_REG
(
SPI_PORT
)
+
i
),
*
data
++
);
#if CONFIG_IDF_TARGET_ESP32C3
SET_PERI_REG_MASK
(
SPI_CMD_REG
(
SPI_PORT
),
SPI_UPDATE
);
while
(
READ_PERI_REG
(
SPI_CMD_REG
(
SPI_PORT
))
&
SPI_UPDATE
);
#endif
SET_PERI_REG_MASK
(
SPI_CMD_REG
(
SPI_PORT
),
SPI_USR
);
}
while
(
READ_PERI_REG
(
SPI_CMD_REG
(
SPI_PORT
))
&
SPI_USR
);
}
////////////////////////////////////////////////////////////////////////////////////////
#elif defined (SPI_18BIT_DRIVER) // SPI 18 bit colour
////////////////////////////////////////////////////////////////////////////////////////
/***************************************************************************************
** Function name: pushBlock - for ESP32 and 3 byte RGB display
** Description: Write a block of pixels of the same colour
***************************************************************************************/
void
TFT_eSPI
::
pushBlock
(
uint16_t
color
,
uint32_t
len
)
{
// Split out the colours
uint32_t
r
=
(
color
&
0xF800
)
>>
8
;
uint32_t
g
=
(
color
&
0x07E0
)
<<
5
;
uint32_t
b
=
(
color
&
0x001F
)
<<
19
;
// Concatenate 4 pixels into three 32 bit blocks
uint32_t
r0
=
r
<<
24
|
b
|
g
|
r
;
uint32_t
r1
=
r0
>>
8
|
g
<<
16
;
uint32_t
r2
=
r1
>>
8
|
b
<<
8
;
if
(
len
>
19
)
{
WRITE_PERI_REG
(
SPI_MOSI_DLEN_REG
(
SPI_PORT
),
479
);
while
(
len
>
19
)
{
while
(
READ_PERI_REG
(
SPI_CMD_REG
(
SPI_PORT
))
&
SPI_USR
);
WRITE_PERI_REG
(
SPI_W0_REG
(
SPI_PORT
),
r0
);
WRITE_PERI_REG
(
SPI_W1_REG
(
SPI_PORT
),
r1
);
WRITE_PERI_REG
(
SPI_W2_REG
(
SPI_PORT
),
r2
);
WRITE_PERI_REG
(
SPI_W3_REG
(
SPI_PORT
),
r0
);
WRITE_PERI_REG
(
SPI_W4_REG
(
SPI_PORT
),
r1
);
WRITE_PERI_REG
(
SPI_W5_REG
(
SPI_PORT
),
r2
);
WRITE_PERI_REG
(
SPI_W6_REG
(
SPI_PORT
),
r0
);
WRITE_PERI_REG
(
SPI_W7_REG
(
SPI_PORT
),
r1
);
WRITE_PERI_REG
(
SPI_W8_REG
(
SPI_PORT
),
r2
);
WRITE_PERI_REG
(
SPI_W9_REG
(
SPI_PORT
),
r0
);
WRITE_PERI_REG
(
SPI_W10_REG
(
SPI_PORT
),
r1
);
WRITE_PERI_REG
(
SPI_W11_REG
(
SPI_PORT
),
r2
);
WRITE_PERI_REG
(
SPI_W12_REG
(
SPI_PORT
),
r0
);
WRITE_PERI_REG
(
SPI_W13_REG
(
SPI_PORT
),
r1
);
WRITE_PERI_REG
(
SPI_W14_REG
(
SPI_PORT
),
r2
);
#if CONFIG_IDF_TARGET_ESP32C3
SET_PERI_REG_MASK
(
SPI_CMD_REG
(
SPI_PORT
),
SPI_UPDATE
);
while
(
READ_PERI_REG
(
SPI_CMD_REG
(
SPI_PORT
))
&
SPI_UPDATE
);
#endif
SET_PERI_REG_MASK
(
SPI_CMD_REG
(
SPI_PORT
),
SPI_USR
);
len
-=
20
;
}
while
(
READ_PERI_REG
(
SPI_CMD_REG
(
SPI_PORT
))
&
SPI_USR
);
}
if
(
len
)
{
WRITE_PERI_REG
(
SPI_MOSI_DLEN_REG
(
SPI_PORT
),
(
len
*
24
)
-
1
);
WRITE_PERI_REG
(
SPI_W0_REG
(
SPI_PORT
),
r0
);
WRITE_PERI_REG
(
SPI_W1_REG
(
SPI_PORT
),
r1
);
WRITE_PERI_REG
(
SPI_W2_REG
(
SPI_PORT
),
r2
);
WRITE_PERI_REG
(
SPI_W3_REG
(
SPI_PORT
),
r0
);
WRITE_PERI_REG
(
SPI_W4_REG
(
SPI_PORT
),
r1
);
WRITE_PERI_REG
(
SPI_W5_REG
(
SPI_PORT
),
r2
);
if
(
len
>
8
)
{
WRITE_PERI_REG
(
SPI_W6_REG
(
SPI_PORT
),
r0
);
WRITE_PERI_REG
(
SPI_W7_REG
(
SPI_PORT
),
r1
);
WRITE_PERI_REG
(
SPI_W8_REG
(
SPI_PORT
),
r2
);
WRITE_PERI_REG
(
SPI_W9_REG
(
SPI_PORT
),
r0
);
WRITE_PERI_REG
(
SPI_W10_REG
(
SPI_PORT
),
r1
);
WRITE_PERI_REG
(
SPI_W11_REG
(
SPI_PORT
),
r2
);
WRITE_PERI_REG
(
SPI_W12_REG
(
SPI_PORT
),
r0
);
WRITE_PERI_REG
(
SPI_W13_REG
(
SPI_PORT
),
r1
);
WRITE_PERI_REG
(
SPI_W14_REG
(
SPI_PORT
),
r2
);
}
#if CONFIG_IDF_TARGET_ESP32C3
SET_PERI_REG_MASK
(
SPI_CMD_REG
(
SPI_PORT
),
SPI_UPDATE
);
while
(
READ_PERI_REG
(
SPI_CMD_REG
(
SPI_PORT
))
&
SPI_UPDATE
);
#endif
SET_PERI_REG_MASK
(
SPI_CMD_REG
(
SPI_PORT
),
SPI_USR
);
while
(
READ_PERI_REG
(
SPI_CMD_REG
(
SPI_PORT
))
&
SPI_USR
);
}
}
/***************************************************************************************
** Function name: pushPixels - for ESP32 and 3 byte RGB display
** Description: Write a sequence of pixels
***************************************************************************************/
void
TFT_eSPI
::
pushPixels
(
const
void
*
data_in
,
uint32_t
len
){
uint16_t
*
data
=
(
uint16_t
*
)
data_in
;
// ILI9488 write macro is not endianess dependant, hence !_swapBytes
if
(
!
_swapBytes
)
{
while
(
len
--
)
{
tft_Write_16S
(
*
data
);
data
++
;}
}
else
{
while
(
len
--
)
{
tft_Write_16
(
*
data
);
data
++
;}
}
}
/***************************************************************************************
** Function name: pushSwapBytePixels - for ESP32 and 3 byte RGB display
** Description: Write a sequence of pixels with swapped bytes
***************************************************************************************/
void
TFT_eSPI
::
pushSwapBytePixels
(
const
void
*
data_in
,
uint32_t
len
){
uint16_t
*
data
=
(
uint16_t
*
)
data_in
;
// ILI9488 write macro is not endianess dependant, so swap byte macro not used here
while
(
len
--
)
{
tft_Write_16
(
*
data
);
data
++
;}
}
////////////////////////////////////////////////////////////////////////////////////////
#elif defined (TFT_PARALLEL_8_BIT) // Now the code for ESP32 8 bit parallel
////////////////////////////////////////////////////////////////////////////////////////
/***************************************************************************************
** Function name: pushBlock - for ESP32 and parallel display
** Description: Write a block of pixels of the same colour
***************************************************************************************/
void
TFT_eSPI
::
pushBlock
(
uint16_t
color
,
uint32_t
len
){
if
(
(
color
>>
8
)
==
(
color
&
0x00FF
)
)
{
if
(
!
len
)
return
;
tft_Write_16
(
color
);
#if defined (SSD1963_DRIVER)
while
(
--
len
)
{
WR_L
;
WR_H
;
WR_L
;
WR_H
;
WR_L
;
WR_H
;}
#else
#ifdef PSEUDO_16_BIT
while
(
--
len
)
{
WR_L
;
WR_H
;}
#else
while
(
--
len
)
{
WR_L
;
WR_H
;
WR_L
;
WR_H
;}
#endif
#endif
}
else
while
(
len
--
)
{
tft_Write_16
(
color
);}
}
/***************************************************************************************
** Function name: pushSwapBytePixels - for ESP32 and parallel display
** Description: Write a sequence of pixels with swapped bytes
***************************************************************************************/
void
TFT_eSPI
::
pushSwapBytePixels
(
const
void
*
data_in
,
uint32_t
len
){
uint16_t
*
data
=
(
uint16_t
*
)
data_in
;
while
(
len
--
)
{
tft_Write_16
(
*
data
);
data
++
;}
}
/***************************************************************************************
** Function name: pushPixels - for ESP32 and parallel display
** Description: Write a sequence of pixels
***************************************************************************************/
void
TFT_eSPI
::
pushPixels
(
const
void
*
data_in
,
uint32_t
len
){
uint16_t
*
data
=
(
uint16_t
*
)
data_in
;
if
(
_swapBytes
)
{
while
(
len
--
)
{
tft_Write_16
(
*
data
);
data
++
;
}
}
else
{
while
(
len
--
)
{
tft_Write_16S
(
*
data
);
data
++
;}
}
}
////////////////////////////////////////////////////////////////////////////////////////
#endif // End of display interface specific functions
////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////
#if defined (ESP32_DMA) && !defined (TFT_PARALLEL_8_BIT) // DMA FUNCTIONS
////////////////////////////////////////////////////////////////////////////////////////
/***************************************************************************************
** Function name: dmaBusy
** Description: Check if DMA is busy
***************************************************************************************/
bool
TFT_eSPI
::
dmaBusy
(
void
)
{
if
(
!
DMA_Enabled
||
!
spiBusyCheck
)
return
false
;
spi_transaction_t
*
rtrans
;
esp_err_t
ret
;
uint8_t
checks
=
spiBusyCheck
;
for
(
int
i
=
0
;
i
<
checks
;
++
i
)
{
ret
=
spi_device_get_trans_result
(
dmaHAL
,
&
rtrans
,
0
);
if
(
ret
==
ESP_OK
)
spiBusyCheck
--
;
}
//Serial.print("spiBusyCheck=");Serial.println(spiBusyCheck);
if
(
spiBusyCheck
==
0
)
return
false
;
return
true
;
}
/***************************************************************************************
** Function name: dmaWait
** Description: Wait until DMA is over (blocking!)
***************************************************************************************/
void
TFT_eSPI
::
dmaWait
(
void
)
{
if
(
!
DMA_Enabled
||
!
spiBusyCheck
)
return
;
spi_transaction_t
*
rtrans
;
esp_err_t
ret
;
for
(
int
i
=
0
;
i
<
spiBusyCheck
;
++
i
)
{
ret
=
spi_device_get_trans_result
(
dmaHAL
,
&
rtrans
,
portMAX_DELAY
);
assert
(
ret
==
ESP_OK
);
}
spiBusyCheck
=
0
;
}
/***************************************************************************************
** Function name: pushPixelsDMA
** Description: Push pixels to TFT (len must be less than 32767)
***************************************************************************************/
// This will byte swap the original image if setSwapBytes(true) was called by sketch.
void
TFT_eSPI
::
pushPixelsDMA
(
uint16_t
*
image
,
uint32_t
len
)
{
if
((
len
==
0
)
||
(
!
DMA_Enabled
))
return
;
dmaWait
();
if
(
_swapBytes
)
{
for
(
uint32_t
i
=
0
;
i
<
len
;
i
++
)
(
image
[
i
]
=
image
[
i
]
<<
8
|
image
[
i
]
>>
8
);
}
esp_err_t
ret
;
static
spi_transaction_t
trans
;
memset
(
&
trans
,
0
,
sizeof
(
spi_transaction_t
));
trans
.
user
=
(
void
*
)
1
;
trans
.
tx_buffer
=
image
;
//finally send the line data
trans
.
length
=
len
*
16
;
//Data length, in bits
trans
.
flags
=
0
;
//SPI_TRANS_USE_TXDATA flag
ret
=
spi_device_queue_trans
(
dmaHAL
,
&
trans
,
portMAX_DELAY
);
assert
(
ret
==
ESP_OK
);
spiBusyCheck
++
;
}
/***************************************************************************************
** Function name: pushImageDMA
** Description: Push image to a window (w*h must be less than 65536)
***************************************************************************************/
// Fixed const data assumed, will NOT clip or swap bytes
void
TFT_eSPI
::
pushImageDMA
(
int32_t
x
,
int32_t
y
,
int32_t
w
,
int32_t
h
,
uint16_t
const
*
image
)
{
if
((
w
==
0
)
||
(
h
==
0
)
||
(
!
DMA_Enabled
))
return
;
uint32_t
len
=
w
*
h
;
dmaWait
();
setAddrWindow
(
x
,
y
,
w
,
h
);
esp_err_t
ret
;
static
spi_transaction_t
trans
;
memset
(
&
trans
,
0
,
sizeof
(
spi_transaction_t
));
trans
.
user
=
(
void
*
)
1
;
trans
.
tx_buffer
=
image
;
//Data pointer
trans
.
length
=
len
*
16
;
//Data length, in bits
trans
.
flags
=
0
;
//SPI_TRANS_USE_TXDATA flag
ret
=
spi_device_queue_trans
(
dmaHAL
,
&
trans
,
portMAX_DELAY
);
assert
(
ret
==
ESP_OK
);
spiBusyCheck
++
;
}
/***************************************************************************************
** Function name: pushImageDMA
** Description: Push image to a window (w*h must be less than 65536)
***************************************************************************************/
// This will clip and also swap bytes if setSwapBytes(true) was called by sketch
void
TFT_eSPI
::
pushImageDMA
(
int32_t
x
,
int32_t
y
,
int32_t
w
,
int32_t
h
,
uint16_t
*
image
,
uint16_t
*
buffer
)
{
if
((
x
>=
_vpW
)
||
(
y
>=
_vpH
)
||
(
!
DMA_Enabled
))
return
;
int32_t
dx
=
0
;
int32_t
dy
=
0
;
int32_t
dw
=
w
;
int32_t
dh
=
h
;
if
(
x
<
_vpX
)
{
dx
=
_vpX
-
x
;
dw
-=
dx
;
x
=
_vpX
;
}
if
(
y
<
_vpY
)
{
dy
=
_vpY
-
y
;
dh
-=
dy
;
y
=
_vpY
;
}
if
((
x
+
dw
)
>
_vpW
)
dw
=
_vpW
-
x
;
if
((
y
+
dh
)
>
_vpH
)
dh
=
_vpH
-
y
;
if
(
dw
<
1
||
dh
<
1
)
return
;
uint32_t
len
=
dw
*
dh
;
if
(
buffer
==
nullptr
)
{
buffer
=
image
;
dmaWait
();
}
// If image is clipped, copy pixels into a contiguous block
if
(
(
dw
!=
w
)
||
(
dh
!=
h
)
)
{
if
(
_swapBytes
)
{
for
(
int32_t
yb
=
0
;
yb
<
dh
;
yb
++
)
{
for
(
int32_t
xb
=
0
;
xb
<
dw
;
xb
++
)
{
uint32_t
src
=
xb
+
dx
+
w
*
(
yb
+
dy
);
(
buffer
[
xb
+
yb
*
dw
]
=
image
[
src
]
<<
8
|
image
[
src
]
>>
8
);
}
}
}
else
{
for
(
int32_t
yb
=
0
;
yb
<
dh
;
yb
++
)
{
memcpy
((
uint8_t
*
)
(
buffer
+
yb
*
dw
),
(
uint8_t
*
)
(
image
+
dx
+
w
*
(
yb
+
dy
)),
dw
<<
1
);
}
}
}
// else, if a buffer pointer has been provided copy whole image to the buffer
else
if
(
buffer
!=
image
||
_swapBytes
)
{
if
(
_swapBytes
)
{
for
(
uint32_t
i
=
0
;
i
<
len
;
i
++
)
(
buffer
[
i
]
=
image
[
i
]
<<
8
|
image
[
i
]
>>
8
);
}
else
{
memcpy
(
buffer
,
image
,
len
*
2
);
}
}
if
(
spiBusyCheck
)
dmaWait
();
// In case we did not wait earlier
setAddrWindow
(
x
,
y
,
dw
,
dh
);
esp_err_t
ret
;
static
spi_transaction_t
trans
;
memset
(
&
trans
,
0
,
sizeof
(
spi_transaction_t
));
trans
.
user
=
(
void
*
)
1
;
trans
.
tx_buffer
=
buffer
;
//finally send the line data
trans
.
length
=
len
*
16
;
//Data length, in bits
trans
.
flags
=
0
;
//SPI_TRANS_USE_TXDATA flag
ret
=
spi_device_queue_trans
(
dmaHAL
,
&
trans
,
portMAX_DELAY
);
assert
(
ret
==
ESP_OK
);
spiBusyCheck
++
;
}
////////////////////////////////////////////////////////////////////////////////////////
// Processor specific DMA initialisation
////////////////////////////////////////////////////////////////////////////////////////
// The DMA functions here work with SPI only (not parallel)
/***************************************************************************************
** Function name: dc_callback
** Description: Toggles DC line during transaction
***************************************************************************************/
extern
"C"
void
dc_callback
();
void
IRAM_ATTR
dc_callback
(
spi_transaction_t
*
spi_tx
)
{
if
((
bool
)
spi_tx
->
user
)
{
DC_D
;}
else
{
DC_C
;}
}
/***************************************************************************************
** Function name: initDMA
** Description: Initialise the DMA engine - returns true if init OK
***************************************************************************************/
bool
TFT_eSPI
::
initDMA
(
bool
ctrl_cs
)
{
if
(
DMA_Enabled
)
return
false
;
esp_err_t
ret
;
spi_bus_config_t
buscfg
=
{
.
mosi_io_num
=
TFT_MOSI
,
.
miso_io_num
=
TFT_MISO
,
.
sclk_io_num
=
TFT_SCLK
,
.
quadwp_io_num
=
-
1
,
.
quadhd_io_num
=
-
1
,
.
max_transfer_sz
=
TFT_WIDTH
*
TFT_HEIGHT
*
2
+
8
,
// TFT screen size
.
flags
=
0
,
.
intr_flags
=
0
};
int8_t
pin
=
-
1
;
if
(
ctrl_cs
)
pin
=
TFT_CS
;
spi_device_interface_config_t
devcfg
=
{
.
command_bits
=
0
,
.
address_bits
=
0
,
.
dummy_bits
=
0
,
.
mode
=
TFT_SPI_MODE
,
.
duty_cycle_pos
=
0
,
.
cs_ena_pretrans
=
0
,
.
cs_ena_posttrans
=
0
,
.
clock_speed_hz
=
SPI_FREQUENCY
,
.
input_delay_ns
=
0
,
.
spics_io_num
=
pin
,
.
flags
=
SPI_DEVICE_NO_DUMMY
,
//0,
.
queue_size
=
1
,
.
pre_cb
=
0
,
//dc_callback, //Callback to handle D/C line
.
post_cb
=
0
};
ret
=
spi_bus_initialize
(
spi_host
,
&
buscfg
,
DMA_CHANNEL
);
ESP_ERROR_CHECK
(
ret
);
ret
=
spi_bus_add_device
(
spi_host
,
&
devcfg
,
&
dmaHAL
);
ESP_ERROR_CHECK
(
ret
);
DMA_Enabled
=
true
;
spiBusyCheck
=
0
;
return
true
;
}
/***************************************************************************************
** Function name: deInitDMA
** Description: Disconnect the DMA engine from SPI
***************************************************************************************/
void
TFT_eSPI
::
deInitDMA
(
void
)
{
if
(
!
DMA_Enabled
)
return
;
spi_bus_remove_device
(
dmaHAL
);
spi_bus_free
(
spi_host
);
DMA_Enabled
=
false
;
}
////////////////////////////////////////////////////////////////////////////////////////
#endif // End of DMA FUNCTIONS
////////////////////////////////////////////////////////////////////////////////////////
Processors/TFT_eSPI_ESP32_C3.h
0 → 100644
View file @
cfb4689c
////////////////////////////////////////////////////
// TFT_eSPI driver functions for ESP32 processors //
////////////////////////////////////////////////////
#ifndef _TFT_eSPI_ESP32H_
#define _TFT_eSPI_ESP32H_
// Processor ID reported by getSetup()
#define PROCESSOR_ID 0x32
// Include processor specific header
#include "soc/spi_reg.h"
#include "driver/spi_master.h"
#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32)
#define CONFIG_IDF_TARGET_ESP32
#endif
#ifndef VSPI
#define VSPI FSPI
#endif
// Fix IDF problems with ESP32C3
#if CONFIG_IDF_TARGET_ESP32C3
// Fix ESP32C3 IDF bug for missing definition (VSPI/FSPI only tested at the moment)
#ifndef REG_SPI_BASE
//Will this work as per S3? #define REG_SPI_BASE(i) (((i)>1) ? (DR_REG_SPI3_BASE) : (DR_REG_SPI2_BASE))
#define REG_SPI_BASE(i) (DR_REG_SPI1_BASE + (((i)>1) ? (((i)* 0x1000) + 0x20000) : (((~(i)) & 1)* 0x1000 )))
#endif
// Fix ESP32C3 IDF bug for name change
#ifndef SPI_MOSI_DLEN_REG
#define SPI_MOSI_DLEN_REG(x) SPI_MS_DLEN_REG(x)
#endif
#endif
// SUPPORT_TRANSACTIONS is mandatory for ESP32 so the hal mutex is toggled
#if !defined (SUPPORT_TRANSACTIONS)
#define SUPPORT_TRANSACTIONS
#endif
/*
ESP32:
FSPI not defined
HSPI = 2, uses SPI2
VSPI = 3, uses SPI3
ESP32-S2:
FSPI = 1, uses SPI2
HSPI = 2, uses SPI3
VSPI not defined
ESP32 C3:
FSPI = 0, uses SPI2 ???? To be checked
HSPI = 1, uses SPI3 ???? To be checked
VSPI not defined
For ESP32/S2/C3:
SPI1_HOST = 0
SPI2_HOST = 1
SPI3_HOST = 2
*/
// ESP32 specific SPI port selection
#ifdef USE_HSPI_PORT
#ifdef CONFIG_IDF_TARGET_ESP32
#define SPI_PORT HSPI //HSPI is port 2 on ESP32
#else
#define SPI_PORT 3 //HSPI is port 3 on ESP32 S2
#endif
#elif defined(USE_FSPI_PORT)
#define SPI_PORT 2 //FSPI(ESP32 S2)
#else
#ifdef CONFIG_IDF_TARGET_ESP32
#define SPI_PORT VSPI
#elif CONFIG_IDF_TARGET_ESP32S2
#define SPI_PORT 2 //FSPI(ESP32 S2)
#elif CONFIG_IDF_TARGET_ESP32C3
#define SPI_PORT FSPI
#endif
#endif
#ifdef RPI_DISPLAY_TYPE
#define CMD_BITS (16-1)
#else
#define CMD_BITS (8-1)
#endif
// Initialise processor specific SPI functions, used by init()
#define INIT_TFT_DATA_BUS // Not used
// Define a generic flag for 8 bit parallel
#if defined (ESP32_PARALLEL) // Specific to ESP32 for backwards compatibility
#if !defined (TFT_PARALLEL_8_BIT)
#define TFT_PARALLEL_8_BIT // Generic parallel flag
#endif
#endif
// Ensure ESP32 specific flag is defined for 8 bit parallel
#if defined (TFT_PARALLEL_8_BIT)
#if !defined (ESP32_PARALLEL)
#define ESP32_PARALLEL
#endif
#endif
// Processor specific code used by SPI bus transaction startWrite and endWrite functions
#if !defined (ESP32_PARALLEL)
#if (TFT_SPI_MODE == SPI_MODE1) || (TFT_SPI_MODE == SPI_MODE2)
#define SET_BUS_WRITE_MODE *_spi_user = SPI_USR_MOSI | SPI_CK_OUT_EDGE
#define SET_BUS_READ_MODE *_spi_user = SPI_USR_MOSI | SPI_USR_MISO | SPI_DOUTDIN | SPI_CK_OUT_EDGE
#else
#define SET_BUS_WRITE_MODE *_spi_user = SPI_USR_MOSI
#define SET_BUS_READ_MODE *_spi_user = SPI_USR_MOSI | SPI_USR_MISO | SPI_DOUTDIN
#endif
#else
// Not applicable to parallel bus
#define SET_BUS_WRITE_MODE
#define SET_BUS_READ_MODE
#endif
// Code to check if DMA is busy, used by SPI bus transaction transaction and endWrite functions
#if !defined(TFT_PARALLEL_8_BIT) && !defined(SPI_18BIT_DRIVER)
#define ESP32_DMA
// Code to check if DMA is busy, used by SPI DMA + transaction + endWrite functions
#define DMA_BUSY_CHECK dmaWait()
#else
#define DMA_BUSY_CHECK
#endif
#if defined(TFT_PARALLEL_8_BIT)
#define SPI_BUSY_CHECK
#else
#define SPI_BUSY_CHECK while (*_spi_cmd&SPI_USR)
#endif
// If smooth font is used then it is likely SPIFFS will be needed
#ifdef SMOOTH_FONT
// Call up the SPIFFS (SPI FLASH Filing System) for the anti-aliased fonts
#define FS_NO_GLOBALS
#include <FS.h>
#include "SPIFFS.h" // ESP32 only
#define FONT_FS_AVAILABLE
#endif
////////////////////////////////////////////////////////////////////////////////////////
// Define the DC (TFT Data/Command or Register Select (RS))pin drive code
////////////////////////////////////////////////////////////////////////////////////////
#ifndef TFT_DC
#define DC_C // No macro allocated so it generates no code
#define DC_D // No macro allocated so it generates no code
#else
#if defined (TFT_PARALLEL_8_BIT)
// TFT_DC, by design, must be in range 0-31 for single register parallel write
#if (TFT_DC >= 0) && (TFT_DC < 32)
#define DC_C GPIO.out_w1tc.val = (1 << TFT_DC)
#define DC_D GPIO.out_w1ts.val = (1 << TFT_DC)
#else
#define DC_C
#define DC_D
#endif
#else
#if (TFT_DC >= 32)
#ifdef RPI_DISPLAY_TYPE // RPi displays need a slower DC change
#define DC_C GPIO.out_w1ts.val = (1 << (TFT_DC - 32)); \
GPIO.out_w1tc.val = (1 << (TFT_DC - 32))
#define DC_D GPIO.out_w1tc.val = (1 << (TFT_DC - 32)); \
GPIO.out_w1ts.val = (1 << (TFT_DC - 32))
#else
#define DC_C GPIO.out_w1tc.val = (1 << (TFT_DC - 32))//;GPIO.out_w1tc.val = (1 << (TFT_DC - 32))
#define DC_D GPIO.out_w1ts.val = (1 << (TFT_DC - 32))//;GPIO.out_w1ts.val = (1 << (TFT_DC - 32))
#endif
#elif (TFT_DC >= 0)
#if defined (RPI_DISPLAY_TYPE)
#if defined (ILI9486_DRIVER)
// RPi ILI9486 display needs a slower DC change
#define DC_C GPIO.out_w1tc.val = (1 << TFT_DC); \
GPIO.out_w1tc.val = (1 << TFT_DC)
#define DC_D GPIO.out_w1tc.val = (1 << TFT_DC); \
GPIO.out_w1ts.val = (1 << TFT_DC)
#else
// Other RPi displays need a slower C->D change
#define DC_C GPIO.out_w1tc.val = (1 << TFT_DC)
#define DC_D GPIO.out_w1tc.val = (1 << TFT_DC); \
GPIO.out_w1ts.val = (1 << TFT_DC)
#endif
#else
#define DC_C GPIO.out_w1tc.val = (1 << TFT_DC)//;GPIO.out_w1tc.val = (1 << TFT_DC)
#define DC_D GPIO.out_w1ts.val = (1 << TFT_DC)//;GPIO.out_w1ts.val = (1 << TFT_DC)
#endif
#else
#define DC_C
#define DC_D
#endif
#endif
#endif
////////////////////////////////////////////////////////////////////////////////////////
// Define the CS (TFT chip select) pin drive code
////////////////////////////////////////////////////////////////////////////////////////
#ifndef TFT_CS
#define TFT_CS -1 // Keep DMA code happy
#define CS_L // No macro allocated so it generates no code
#define CS_H // No macro allocated so it generates no code
#else
#if defined (TFT_PARALLEL_8_BIT)
#if TFT_CS >= 32
#define CS_L GPIO.out_w1tc.val = (1 << (TFT_CS - 32))
#define CS_H GPIO.out_w1ts.val = (1 << (TFT_CS - 32))
#elif TFT_CS >= 0
#define CS_L GPIO.out_w1tc.val = (1 << TFT_CS)
#define CS_H GPIO.out_w1ts.val = (1 << TFT_CS)
#else
#define CS_L
#define CS_H
#endif
#else
#if (TFT_CS >= 32)
#ifdef RPI_DISPLAY_TYPE // RPi display needs a slower CS change
#define CS_L GPIO.out_w1ts.val = (1 << (TFT_CS - 32)); \
GPIO.out_w1tc.val = (1 << (TFT_CS - 32))
#define CS_H GPIO.out_w1tc.val = (1 << (TFT_CS - 32)); \
GPIO.out_w1ts.val = (1 << (TFT_CS - 32))
#else
#define CS_L GPIO.out_w1tc.val = (1 << (TFT_CS - 32)); GPIO.out_w1tc.val = (1 << (TFT_CS - 32))
#define CS_H GPIO.out_w1ts.val = (1 << (TFT_CS - 32))//;GPIO.out_w1ts.val = (1 << (TFT_CS - 32))
#endif
#elif (TFT_CS >= 0)
#ifdef RPI_DISPLAY_TYPE // RPi display needs a slower CS change
#define CS_L GPIO.out_w1ts.val = (1 << TFT_CS); GPIO.out_w1tc.val = (1 << TFT_CS)
#define CS_H GPIO.out_w1tc.val = (1 << TFT_CS); GPIO.out_w1ts.val = (1 << TFT_CS)
#else
#define CS_L GPIO.out_w1tc.val = (1 << TFT_CS); GPIO.out_w1tc.val = (1 << TFT_CS)
#define CS_H GPIO.out_w1ts.val = (1 << TFT_CS)//;GPIO.out_w1ts.val = (1 << TFT_CS)
#endif
#else
#define CS_L
#define CS_H
#endif
#endif
#endif
////////////////////////////////////////////////////////////////////////////////////////
// Define the WR (TFT Write) pin drive code
////////////////////////////////////////////////////////////////////////////////////////
#if defined (TFT_WR)
#if (TFT_WR >= 32)
// Note: it will be ~1.25x faster if the TFT_WR pin uses a GPIO pin lower than 32
#define WR_L GPIO.out_w1tc.val = (1 << (TFT_WR - 32))
#define WR_H GPIO.out_w1ts.val = (1 << (TFT_WR - 32))
#elif (TFT_WR >= 0)
// TFT_WR, for best performance, should be in range 0-31 for single register parallel write
#define WR_L GPIO.out_w1tc.val = (1 << TFT_WR)
#define WR_H GPIO.out_w1ts.val = (1 << TFT_WR)
#else
#define WR_L
#define WR_H
#endif
#else
#define WR_L
#define WR_H
#endif
////////////////////////////////////////////////////////////////////////////////////////
// Define the touch screen chip select pin drive code
////////////////////////////////////////////////////////////////////////////////////////
#ifndef TOUCH_CS
#define T_CS_L // No macro allocated so it generates no code
#define T_CS_H // No macro allocated so it generates no code
#else // XPT2046 is slow, so use slower digitalWrite here
#define T_CS_L digitalWrite(TOUCH_CS, LOW)
#define T_CS_H digitalWrite(TOUCH_CS, HIGH)
#endif
////////////////////////////////////////////////////////////////////////////////////////
// Make sure SPI default pins are assigned if not specified by user or set to -1
////////////////////////////////////////////////////////////////////////////////////////
#if !defined (TFT_PARALLEL_8_BIT)
#ifdef USE_HSPI_PORT
#ifndef TFT_MISO
#define TFT_MISO -1
#endif
#ifndef TFT_MOSI
#define TFT_MOSI 13
#endif
#if (TFT_MOSI == -1)
#undef TFT_MOSI
#define TFT_MOSI 13
#endif
#ifndef TFT_SCLK
#define TFT_SCLK 14
#endif
#if (TFT_SCLK == -1)
#undef TFT_SCLK
#define TFT_SCLK 14
#endif
#else // VSPI port
#ifndef TFT_MISO
#define TFT_MISO -1
#endif
#ifndef TFT_MOSI
#define TFT_MOSI 23
#endif
#if (TFT_MOSI == -1)
#undef TFT_MOSI
#define TFT_MOSI 23
#endif
#ifndef TFT_SCLK
#define TFT_SCLK 18
#endif
#if (TFT_SCLK == -1)
#undef TFT_SCLK
#define TFT_SCLK 18
#endif
#if defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S2)
#if (TFT_MISO == -1)
#undef TFT_MISO
#define TFT_MISO TFT_MOSI
#endif
#endif
#endif
#endif
////////////////////////////////////////////////////////////////////////////////////////
// Define the parallel bus interface chip pin drive code
////////////////////////////////////////////////////////////////////////////////////////
#if defined (TFT_PARALLEL_8_BIT)
// Create a bit set lookup table for data bus - wastes 1kbyte of RAM but speeds things up dramatically
// can then use e.g. GPIO.out_w1ts.val = set_mask(0xFF); to set data bus to 0xFF
#define PARALLEL_INIT_TFT_DATA_BUS \
for (int32_t 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); \
} \
// Mask for the 8 data bits to set pin directions
#define dir_mask ((1 << TFT_D0) | (1 << TFT_D1) | (1 << TFT_D2) | (1 << TFT_D3) | (1 << TFT_D4) | (1 << TFT_D5) | (1 << TFT_D6) | (1 << TFT_D7))
#if (TFT_WR >= 32)
// Data bits and the write line are cleared sequentially
#define clr_mask (dir_mask); WR_L
#elif (TFT_WR >= 0)
// Data bits and the write line are cleared to 0 in one step (1.25x faster)
#define clr_mask (dir_mask | (1 << TFT_WR))
#else
#define clr_mask
#endif
// A lookup table is used to set the different bit patterns, this uses 1kByte of RAM
#define set_mask(C) xset_mask[C] // 63fps Sprite rendering test 33% faster, graphicstest only 1.8% faster than shifting in real time
// Real-time shifting alternative to above to save 1KByte RAM, 47 fps Sprite rendering test
/*#define set_mask(C) (((C)&0x80)>>7)<<TFT_D7 | (((C)&0x40)>>6)<<TFT_D6 | (((C)&0x20)>>5)<<TFT_D5 | (((C)&0x10)>>4)<<TFT_D4 | \
(((C)&0x08)>>3)<<TFT_D3 | (((C)&0x04)>>2)<<TFT_D2 | (((C)&0x02)>>1)<<TFT_D1 | (((C)&0x01)>>0)<<TFT_D0
//*/
// Write 8 bits to TFT
#define tft_Write_8(C) GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t)(C)); WR_H
#if defined (SSD1963_DRIVER)
// Write 18 bit color to TFT
#define tft_Write_16(C) GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) (((C) & 0xF800)>> 8)); WR_H; \
GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) (((C) & 0x07E0)>> 3)); WR_H; \
GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) (((C) & 0x001F)<< 3)); WR_H
// 18 bit color write with swapped bytes
#define tft_Write_16S(C) Cswap = ((C) >>8 | (C) << 8); tft_Write_16(Cswap)
#else
#ifdef PSEUDO_16_BIT
// One write strobe for both bytes
#define tft_Write_16(C) GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 0)); WR_H
#define tft_Write_16S(C) GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 8)); WR_H
#else
// Write 16 bits to TFT
#define tft_Write_16(C) GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 8)); WR_H; \
GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 0)); WR_H
// 16 bit write with swapped bytes
#define tft_Write_16S(C) GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 0)); WR_H; \
GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 8)); WR_H
#endif
#endif
// Write 32 bits to TFT
#define tft_Write_32(C) GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 24)); WR_H; \
GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 16)); WR_H; \
GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 8)); WR_H; \
GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 0)); WR_H
// Write two concatenated 16 bit values to TFT
#define tft_Write_32C(C,D) GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 8)); WR_H; \
GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 0)); WR_H; \
GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) ((D) >> 8)); WR_H; \
GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) ((D) >> 0)); WR_H
// Write 16 bit value twice to TFT - used by drawPixel()
#define tft_Write_32D(C) GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 8)); WR_H; \
GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 0)); WR_H; \
GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 8)); WR_H; \
GPIO.out_w1tc.val = clr_mask; GPIO.out_w1ts.val = set_mask((uint8_t) ((C) >> 0)); WR_H
// Read pin
#ifdef TFT_RD
#if (TFT_RD >= 32)
#define RD_L GPIO.out_w1tc.val = (1 << (TFT_RD - 32))
#define RD_H GPIO.out_w1ts.val = (1 << (TFT_RD - 32))
#elif (TFT_RD >= 0)
#define RD_L GPIO.out_w1tc.val = (1 << TFT_RD)
//#define RD_L digitalWrite(TFT_WR, LOW)
#define RD_H GPIO.out_w1ts.val = (1 << TFT_RD)
//#define RD_H digitalWrite(TFT_WR, HIGH)
#else
#define RD_L
#define RD_H
#endif
#else
#define TFT_RD -1
#define RD_L
#define RD_H
#endif
////////////////////////////////////////////////////////////////////////////////////////
// Macros to write commands/pixel colour data to a SPI ILI948x TFT
////////////////////////////////////////////////////////////////////////////////////////
#elif defined (SPI_18BIT_DRIVER) // SPI 18 bit colour
// Write 8 bits to TFT
#define tft_Write_8(C) spi.transfer(C)
// Convert 16 bit colour to 18 bit and write in 3 bytes
#define tft_Write_16(C) spi.transfer(((C) & 0xF800)>>8); \
spi.transfer(((C) & 0x07E0)>>3); \
spi.transfer(((C) & 0x001F)<<3)
// Future option for transfer without wait
#define tft_Write_16N(C) tft_Write_16(C)
// Convert swapped byte 16 bit colour to 18 bit and write in 3 bytes
#define tft_Write_16S(C) spi.transfer((C) & 0xF8); \
spi.transfer(((C) & 0xE000)>>11 | ((C) & 0x07)<<5); \
spi.transfer(((C) & 0x1F00)>>5)
// Write 32 bits to TFT
#define tft_Write_32(C) spi.write32(C)
// Write two concatenated 16 bit values to TFT
#define tft_Write_32C(C,D) spi.write32((C)<<16 | (D))
// Write 16 bit value twice to TFT
#define tft_Write_32D(C) spi.write32((C)<<16 | (C))
////////////////////////////////////////////////////////////////////////////////////////
// Macros to write commands/pixel colour data to an Raspberry Pi TFT
////////////////////////////////////////////////////////////////////////////////////////
#elif defined (RPI_DISPLAY_TYPE)
// ESP32 low level SPI writes for 8, 16 and 32 bit values
// to avoid the function call overhead
#define TFT_WRITE_BITS(D, B) \
WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), B-1); \
WRITE_PERI_REG(SPI_W0_REG(SPI_PORT), D); \
SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); \
while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR);
// Write 8 bits
#define tft_Write_8(C) TFT_WRITE_BITS((C)<<8, 16)
// Write 16 bits with corrected endianness for 16 bit colours
#define tft_Write_16(C) TFT_WRITE_BITS((C)<<8 | (C)>>8, 16)
// Future option for transfer without wait
#define tft_Write_16N(C) tft_Write_16(C)
// Write 16 bits
#define tft_Write_16S(C) TFT_WRITE_BITS(C, 16)
// Write 32 bits
#define tft_Write_32(C) TFT_WRITE_BITS(C, 32)
// Write two address coordinates
#define tft_Write_32C(C,D) TFT_WRITE_BITS((C)<<24 | (C), 32); \
TFT_WRITE_BITS((D)<<24 | (D), 32)
// Write same value twice
#define tft_Write_32D(C) tft_Write_32C(C,C)
////////////////////////////////////////////////////////////////////////////////////////
// Macros for all other SPI displays
////////////////////////////////////////////////////////////////////////////////////////
#else
/* Old macros
// ESP32 low level SPI writes for 8, 16 and 32 bit values
// to avoid the function call overhead
#define TFT_WRITE_BITS(D, B) \
WRITE_PERI_REG(SPI_MOSI_DLEN_REG(SPI_PORT), B-1); \
WRITE_PERI_REG(SPI_W0_REG(SPI_PORT), D); \
SET_PERI_REG_MASK(SPI_CMD_REG(SPI_PORT), SPI_USR); \
while (READ_PERI_REG(SPI_CMD_REG(SPI_PORT))&SPI_USR);
// Write 8 bits
#define tft_Write_8(C) TFT_WRITE_BITS(C, 8)
// Write 16 bits with corrected endianness for 16 bit colours
#define tft_Write_16(C) TFT_WRITE_BITS((C)<<8 | (C)>>8, 16)
// Write 16 bits
#define tft_Write_16S(C) TFT_WRITE_BITS(C, 16)
// Write 32 bits
#define tft_Write_32(C) TFT_WRITE_BITS(C, 32)
// Write two address coordinates
#define tft_Write_32C(C,D) TFT_WRITE_BITS((uint16_t)((D)<<8 | (D)>>8)<<16 | (uint16_t)((C)<<8 | (C)>>8), 32)
// Write same value twice
#define tft_Write_32D(C) TFT_WRITE_BITS((uint16_t)((C)<<8 | (C)>>8)<<16 | (uint16_t)((C)<<8 | (C)>>8), 32)
//*/
//* Replacement slimmer macros
#if !defined(CONFIG_IDF_TARGET_ESP32C3)
#define TFT_WRITE_BITS(D, B) *_spi_mosi_dlen = B-1; \
*_spi_w = D; \
*_spi_cmd = SPI_USR; \
while (*_spi_cmd & SPI_USR);
#else
#define TFT_WRITE_BITS(D, B) *_spi_mosi_dlen = B-1; \
*_spi_w = D; \
*_spi_cmd = SPI_UPDATE; \
while (*_spi_cmd & SPI_UPDATE); \
*_spi_cmd = SPI_USR; \
while (*_spi_cmd & SPI_USR);
#endif
// Write 8 bits
#define tft_Write_8(C) TFT_WRITE_BITS(C, 8)
// Write 16 bits with corrected endianness for 16 bit colours
#define tft_Write_16(C) TFT_WRITE_BITS((C)<<8 | (C)>>8, 16)
// Future option for transfer without wait
#if !defined(CONFIG_IDF_TARGET_ESP32C3)
#define tft_Write_16N(C) *_spi_mosi_dlen = 16-1; \
*_spi_w = ((C)<<8 | (C)>>8); \
*_spi_cmd = SPI_USR;
#else
#define tft_Write_16N(C) *_spi_mosi_dlen = 16-1; \
*_spi_w = ((C)<<8 | (C)>>8); \
*_spi_cmd = SPI_UPDATE; \
while (*_spi_cmd & SPI_UPDATE); \
*_spi_cmd = SPI_USR;
#endif
// Write 16 bits
#define tft_Write_16S(C) TFT_WRITE_BITS(C, 16)
// Write 32 bits
#define tft_Write_32(C) TFT_WRITE_BITS(C, 32)
// Write two address coordinates
#define tft_Write_32C(C,D) TFT_WRITE_BITS((uint16_t)((D)<<8 | (D)>>8)<<16 | (uint16_t)((C)<<8 | (C)>>8), 32)
// Write same value twice
#define tft_Write_32D(C) TFT_WRITE_BITS((uint16_t)((C)<<8 | (C)>>8)<<16 | (uint16_t)((C)<<8 | (C)>>8), 32)
//*/
#endif
#ifndef tft_Write_16N
#define tft_Write_16N tft_Write_16
#endif
////////////////////////////////////////////////////////////////////////////////////////
// Macros to read from display using SPI or software SPI
////////////////////////////////////////////////////////////////////////////////////////
#if !defined (TFT_PARALLEL_8_BIT)
// Read from display using SPI or software SPI
// Use a SPI read transfer
#define tft_Read_8() spi.transfer(0)
#endif
// Concatenate a byte sequence A,B,C,D to CDAB, P is a uint8_t pointer
#define DAT8TO32(P) ( (uint32_t)P[0]<<8 | P[1] | P[2]<<24 | P[3]<<16 )
#endif // Header end
TFT_eSPI.cpp
View file @
cfb4689c
...
...
@@ -19,6 +19,8 @@
#if defined (ESP32)
#if defined(CONFIG_IDF_TARGET_ESP32S3)
#include "Processors/TFT_eSPI_ESP32_S3.c"
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
#include "Processors/TFT_eSPI_ESP32_C3.c"
#else
#include "Processors/TFT_eSPI_ESP32.c"
#endif
...
...
TFT_eSPI.h
View file @
cfb4689c
...
...
@@ -67,6 +67,8 @@
// Include the processor specific drivers
#if defined(CONFIG_IDF_TARGET_ESP32S3)
#include "Processors/TFT_eSPI_ESP32_S3.h"
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
#include "Processors/TFT_eSPI_ESP32_C3.h"
#elif defined (ESP32)
#include "Processors/TFT_eSPI_ESP32.h"
#elif defined (ESP8266)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment