mirror of
https://github.com/Bodmer/TFT_eSPI.git
synced 2025-07-30 02:37:33 +02:00
RP2040: add SPI PIO interface option, enhance 8 bit parallel PIO
The RP2040 processors can now drive 8 bit parallel and SPI displays using the PIO hardware. The PIO offloads the processor by providing: 1. PIO managed setWindow sequence 2. PIO managed block and screen fill
This commit is contained in:
@ -37,6 +37,9 @@ TFT_eSprite::TFT_eSprite(TFT_eSPI *tft)
|
||||
_colorMap = nullptr;
|
||||
|
||||
_psram_enable = true;
|
||||
|
||||
// Ensure end_tft_write() does nothing in inherited functions.
|
||||
lockTransaction = true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -322,7 +322,7 @@ SPI3_HOST = 2
|
||||
|
||||
// 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 = set_mask(0xFF); to set data bus to 0xFF
|
||||
#define CONSTRUCTOR_INIT_TFT_DATA_BUS \
|
||||
#define PARALLEL_INIT_TFT_DATA_BUS \
|
||||
for (int32_t c = 0; c<256; c++) \
|
||||
{ \
|
||||
xset_mask[c] = 0; \
|
||||
|
@ -6,7 +6,7 @@
|
||||
// Global variables
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if !defined (TFT_PARALLEL_8_BIT) // SPI
|
||||
#if !defined (RP2040_PIO_INTERFACE) // SPI
|
||||
|
||||
// Select the SPI port and board package to use
|
||||
#ifdef ARDUINO_ARCH_MBED
|
||||
@ -18,9 +18,13 @@
|
||||
SPIClassRP2040 spi = SPIClassRP2040(SPI_X, TFT_MISO, -1, TFT_SCLK, TFT_MOSI);
|
||||
#endif
|
||||
|
||||
#else // 8 bit parallel
|
||||
#else // PIO interface used (8 bit parallel or SPI)
|
||||
|
||||
#include "pio_8bit_parallel.pio.h"
|
||||
#ifdef RP2040_PIO_SPI
|
||||
#include "pio_SPI.pio.h"
|
||||
#else
|
||||
#include "pio_8bit_parallel.pio.h"
|
||||
#endif
|
||||
|
||||
// Board package specific differences
|
||||
#ifdef ARDUINO_ARCH_MBED
|
||||
@ -31,11 +35,20 @@
|
||||
// Community RP2040 board package by Earle Philhower
|
||||
PIO pio = pio0; // Code will try both pio's to find a free SM
|
||||
int8_t pio_sm = 0; // pioinit will claim a free one
|
||||
|
||||
// Updated later with the loading offset of the PIO program.
|
||||
uint32_t program_offset = 0;
|
||||
|
||||
// SM stalled mask
|
||||
uint32_t pull_stall_mask = 0;
|
||||
|
||||
// SM jump instructions to change SM behaviour
|
||||
uint32_t pio_instr_jmp8 = 0;
|
||||
uint32_t pio_instr_fill = 0;
|
||||
uint32_t pio_instr_addr = 0;
|
||||
|
||||
// SM "set" instructions to control DC control signal
|
||||
uint32_t pio_instr_set_dc = 0;
|
||||
uint32_t pio_instr_clr_dc = 0;
|
||||
|
||||
#endif
|
||||
|
||||
@ -45,7 +58,7 @@
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#if defined (TFT_SDA_READ) && !defined (TFT_PARALLEL_8_BIT)
|
||||
#if defined (TFT_SDA_READ) && !defined (RP2040_PIO_INTERFACE)
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/***************************************************************************************
|
||||
@ -91,9 +104,10 @@ void TFT_eSPI::end_SDA_Read(void)
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#if defined (TFT_PARALLEL_8_BIT)
|
||||
#if defined (RP2040_PIO_INTERFACE)
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
void pioinit(uint8_t tft_d0_pin, uint8_t tft_wr_pin, uint16_t clock_div, uint16_t fract_div) {
|
||||
#ifdef RP2040_PIO_SPI
|
||||
void pioinit(uint32_t clock_freq) {
|
||||
|
||||
// Find a free SM on one of the PIO's
|
||||
pio = pio0;
|
||||
@ -108,29 +122,32 @@ void pioinit(uint8_t tft_d0_pin, uint8_t tft_wr_pin, uint16_t clock_div, uint16_
|
||||
program_offset = pio_add_program(pio, &tft_io_program);
|
||||
|
||||
// Associate pins with the PIO
|
||||
pio_gpio_init(pio, tft_wr_pin);
|
||||
for (int i = 0; i < 8; i++) {
|
||||
pio_gpio_init(pio, tft_d0_pin + i);
|
||||
}
|
||||
pio_gpio_init(pio, TFT_DC);
|
||||
pio_gpio_init(pio, TFT_SCLK);
|
||||
pio_gpio_init(pio, TFT_MOSI);
|
||||
|
||||
// Configure the pins to be outputs
|
||||
pio_sm_set_consecutive_pindirs(pio, pio_sm, tft_wr_pin, 1, true);
|
||||
pio_sm_set_consecutive_pindirs(pio, pio_sm, tft_d0_pin, 8, true);
|
||||
pio_sm_set_consecutive_pindirs(pio, pio_sm, TFT_DC, 1, true);
|
||||
pio_sm_set_consecutive_pindirs(pio, pio_sm, TFT_SCLK, 1, true);
|
||||
pio_sm_set_consecutive_pindirs(pio, pio_sm, TFT_MOSI, 1, true);
|
||||
|
||||
// Configure the state machine
|
||||
pio_sm_config c = tft_io_program_get_default_config(program_offset);
|
||||
|
||||
sm_config_set_set_pins(&c, TFT_DC, 1);
|
||||
// Define the single side-set pin
|
||||
sm_config_set_sideset_pins(&c, tft_wr_pin);
|
||||
// Define the 8 consecutive pins that are used for data output
|
||||
sm_config_set_out_pins(&c, tft_d0_pin, 8);
|
||||
// Set clock divider and fractional divider
|
||||
sm_config_set_clkdiv_int_frac(&c, clock_div, fract_div);
|
||||
sm_config_set_sideset_pins(&c, TFT_SCLK);
|
||||
// Define the pin used for data output
|
||||
sm_config_set_out_pins(&c, TFT_MOSI, 1);
|
||||
// Set clock divider, frequency is set up to 2% faster than specified, or next division down
|
||||
uint16_t clock_div = 0.98 + clock_get_hz(clk_sys) / (clock_freq * 2.0); // 2 cycles per bit
|
||||
sm_config_set_clkdiv(&c, clock_div);
|
||||
// Make a single 8 words FIFO from the 4 words TX and RX FIFOs
|
||||
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
|
||||
// The OSR register shifts to the right, sm designed to send MS byte of a colour first
|
||||
sm_config_set_out_shift(&c, true, false, 0);
|
||||
// The OSR register shifts to the left, sm designed to send MS byte of a colour first, autopull off
|
||||
sm_config_set_out_shift(&c, false, false, 0);
|
||||
// Now load the configuration
|
||||
pio_sm_init(pio, pio_sm, program_offset + tft_io_offset_start_8, &c);
|
||||
pio_sm_init(pio, pio_sm, program_offset + tft_io_offset_start_16, &c);
|
||||
|
||||
// Start the state machine.
|
||||
pio_sm_set_enabled(pio, pio_sm, true);
|
||||
@ -140,12 +157,91 @@ void pioinit(uint8_t tft_d0_pin, uint8_t tft_wr_pin, uint16_t clock_div, uint16_
|
||||
|
||||
// Create the assembler instruction for the jump to byte send routine
|
||||
pio_instr_jmp8 = pio_encode_jmp(program_offset + tft_io_offset_start_8);
|
||||
pio_instr_fill = pio_encode_jmp(program_offset + tft_io_offset_block_fill);
|
||||
pio_instr_addr = pio_encode_jmp(program_offset + tft_io_offset_set_addr_window);
|
||||
|
||||
pio_instr_set_dc = pio_encode_set((pio_src_dest)0, 1);
|
||||
pio_instr_clr_dc = pio_encode_set((pio_src_dest)0, 0);
|
||||
}
|
||||
#else
|
||||
void pioinit(uint16_t clock_div, uint16_t fract_div) {
|
||||
|
||||
// Find a free SM on one of the PIO's
|
||||
pio = pio0;
|
||||
pio_sm = pio_claim_unused_sm(pio, false); // false means don't panic
|
||||
// Try pio1 if SM not found
|
||||
if (pio_sm < 0) {
|
||||
pio = pio1;
|
||||
pio_sm = pio_claim_unused_sm(pio, true); // panic this time if no SM is free
|
||||
}
|
||||
|
||||
// Load the PIO program
|
||||
program_offset = pio_add_program(pio, &tft_io_program);
|
||||
|
||||
// Associate pins with the PIO
|
||||
pio_gpio_init(pio, TFT_DC);
|
||||
pio_gpio_init(pio, TFT_WR);
|
||||
for (int i = 0; i < 8; i++) {
|
||||
pio_gpio_init(pio, TFT_D0 + i);
|
||||
}
|
||||
|
||||
// Configure the pins to be outputs
|
||||
pio_sm_set_consecutive_pindirs(pio, pio_sm, TFT_DC, 1, true);
|
||||
pio_sm_set_consecutive_pindirs(pio, pio_sm, TFT_WR, 1, true);
|
||||
pio_sm_set_consecutive_pindirs(pio, pio_sm, TFT_D0, 8, true);
|
||||
|
||||
// Configure the state machine
|
||||
pio_sm_config c = tft_io_program_get_default_config(program_offset);
|
||||
// Define the set pin
|
||||
sm_config_set_set_pins(&c, TFT_DC, 1);
|
||||
// Define the single side-set pin
|
||||
sm_config_set_sideset_pins(&c, TFT_WR);
|
||||
// Define the 8 consecutive pins that are used for data output
|
||||
sm_config_set_out_pins(&c, TFT_D0, 8);
|
||||
// Set clock divider and fractional divider
|
||||
sm_config_set_clkdiv_int_frac(&c, clock_div, fract_div);
|
||||
// Make a single 8 words FIFO from the 4 words TX and RX FIFOs
|
||||
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
|
||||
// The OSR register shifts to the left, sm designed to send MS byte of a colour first
|
||||
sm_config_set_out_shift(&c, false, false, 0);
|
||||
// Now load the configuration
|
||||
pio_sm_init(pio, pio_sm, program_offset + tft_io_offset_start_16, &c);
|
||||
|
||||
// Start the state machine.
|
||||
pio_sm_set_enabled(pio, pio_sm, true);
|
||||
|
||||
// Create the pull stall bit mask
|
||||
pull_stall_mask = 1u << (PIO_FDEBUG_TXSTALL_LSB + pio_sm);
|
||||
|
||||
// Create the assembler instruction for the jump to byte send routine
|
||||
pio_instr_jmp8 = pio_encode_jmp(program_offset + tft_io_offset_start_8);
|
||||
//pio_instr_jmp32 = pio_encode_jmp(program_offset + tft_io_offset_start_32);
|
||||
pio_instr_fill = pio_encode_jmp(program_offset + tft_io_offset_block_fill);
|
||||
pio_instr_addr = pio_encode_jmp(program_offset + tft_io_offset_set_addr_window);
|
||||
|
||||
pio_instr_set_dc = pio_encode_set((pio_src_dest)0, 1);
|
||||
pio_instr_clr_dc = pio_encode_set((pio_src_dest)0, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: pushBlock - for generic processor and parallel display
|
||||
** Description: Write a block of pixels of the same colour
|
||||
***************************************************************************************/
|
||||
#ifdef RP2040_PIO_PUSHBLOCK
|
||||
// PIO handles pixel block fill writes
|
||||
void TFT_eSPI::pushBlock(uint16_t color, uint32_t len)
|
||||
{
|
||||
if (len) {
|
||||
WAIT_FOR_STALL;
|
||||
pio->sm[pio_sm].instr = pio_instr_fill;
|
||||
|
||||
TX_FIFO = color;
|
||||
TX_FIFO = --len; // Decrement first as PIO sends n+1
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){
|
||||
|
||||
while (len > 4) {
|
||||
@ -166,6 +262,7 @@ void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){
|
||||
while (len--) TX_FIFO = color;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: pushPixels - for generic processor and parallel display
|
||||
@ -424,7 +521,7 @@ bool TFT_eSPI::dmaBusy(void) {
|
||||
|
||||
if (dma_channel_is_busy(dma_tx_channel)) return true;
|
||||
|
||||
#if !defined (TFT_PARALLEL_8_BIT)
|
||||
#if !defined (RP2040_PIO_INTERFACE)
|
||||
// For SPI must also wait for FIFO to flush and reset format
|
||||
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
|
||||
spi_set_format(SPI_X, 16, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST);
|
||||
@ -441,7 +538,7 @@ void TFT_eSPI::dmaWait(void)
|
||||
{
|
||||
while (dma_channel_is_busy(dma_tx_channel));
|
||||
|
||||
#if !defined (TFT_PARALLEL_8_BIT)
|
||||
#if !defined (RP2040_PIO_INTERFACE)
|
||||
// For SPI must also wait for FIFO to flush and reset format
|
||||
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
|
||||
spi_set_format(SPI_X, 16, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST);
|
||||
@ -460,7 +557,7 @@ void TFT_eSPI::pushPixelsDMA(uint16_t* image, uint32_t len)
|
||||
|
||||
channel_config_set_bswap(&dma_tx_config, !_swapBytes);
|
||||
|
||||
#if !defined (TFT_PARALLEL_8_BIT)
|
||||
#if !defined (RP2040_PIO_INTERFACE)
|
||||
dma_channel_configure(dma_tx_channel, &dma_tx_config, &spi_get_hw(SPI_X)->dr, (uint16_t*)image, len, true);
|
||||
#else
|
||||
dma_channel_configure(dma_tx_channel, &dma_tx_config, &pio->txf[pio_sm], (uint16_t*)image, len, true);
|
||||
@ -513,7 +610,7 @@ void TFT_eSPI::pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t
|
||||
|
||||
channel_config_set_bswap(&dma_tx_config, !_swapBytes);
|
||||
|
||||
#if !defined (TFT_PARALLEL_8_BIT)
|
||||
#if !defined (RP2040_PIO_INTERFACE)
|
||||
dma_channel_configure(dma_tx_channel, &dma_tx_config, &spi_get_hw(SPI_X)->dr, (uint16_t*)buffer, len, true);
|
||||
#else
|
||||
dma_channel_configure(dma_tx_channel, &dma_tx_config, &pio->txf[pio_sm], (uint16_t*)buffer, len, true);
|
||||
@ -534,8 +631,8 @@ bool TFT_eSPI::initDMA(bool ctrl_cs)
|
||||
dma_tx_config = dma_channel_get_default_config(dma_tx_channel);
|
||||
|
||||
channel_config_set_transfer_data_size(&dma_tx_config, DMA_SIZE_16);
|
||||
#if !defined (TFT_PARALLEL_8_BIT)
|
||||
channel_config_set_dreq(&dma_tx_config, spi_get_index(SPI_X) ? DREQ_SPI1_TX : DREQ_SPI0_TX);
|
||||
#if !defined (RP2040_PIO_INTERFACE)
|
||||
channel_config_set_dreq(&dma_tx_config, spi_get_dreq(SPI_X, true));
|
||||
#else
|
||||
channel_config_set_dreq(&dma_tx_config, pio_get_dreq(pio, pio_sm, true));
|
||||
#endif
|
||||
|
@ -11,6 +11,7 @@
|
||||
// Required for both the official and community board packages
|
||||
#include "hardware/dma.h"
|
||||
#include "hardware/pio.h"
|
||||
#include "hardware/clocks.h"
|
||||
|
||||
// Processor ID reported by getSetup()
|
||||
#define PROCESSOR_ID 0x2040
|
||||
@ -18,8 +19,12 @@
|
||||
// Include processor specific header
|
||||
// None
|
||||
|
||||
#if defined (TFT_PARALLEL_8_BIT) || defined (RP2040_PIO_SPI)
|
||||
#define RP2040_PIO_INTERFACE
|
||||
#define RP2040_PIO_PUSHBLOCK
|
||||
#endif
|
||||
|
||||
#if !defined (TFT_PARALLEL_8_BIT) // SPI
|
||||
#if !defined (RP2040_PIO_INTERFACE)// SPI
|
||||
// Use SPI0 as default if not defined
|
||||
#ifndef TFT_SPI_PORT
|
||||
#define TFT_SPI_PORT 0
|
||||
@ -49,7 +54,7 @@
|
||||
#define DMA_BUSY_CHECK
|
||||
#endif
|
||||
|
||||
#if !defined (TFT_PARALLEL_8_BIT) // SPI
|
||||
#if !defined (RP2040_PIO_INTERFACE) // SPI
|
||||
// Initialise processor specific SPI functions, used by init()
|
||||
#define INIT_TFT_DATA_BUS // Not used
|
||||
|
||||
@ -63,10 +68,6 @@
|
||||
#define SUPPORT_TRANSACTIONS
|
||||
#endif
|
||||
#else
|
||||
// Initialise TFT data bus
|
||||
#define INIT_TFT_DATA_BUS
|
||||
|
||||
#define SPI_BUSY_CHECK
|
||||
|
||||
// ILI9481 needs a slower cycle time
|
||||
// Byte rate = (CPU clock/(4 * divider))
|
||||
@ -78,8 +79,17 @@
|
||||
#define DIV_FRACT 0
|
||||
#endif
|
||||
|
||||
// Initialise TFT data bus
|
||||
#if defined (TFT_PARALLEL_8_BIT)
|
||||
#define INIT_TFT_DATA_BUS pioinit(DIV_UNITS, DIV_FRACT);
|
||||
#elif defined (RP2040_PIO_SPI)
|
||||
#define INIT_TFT_DATA_BUS pioinit(SPI_FREQUENCY);
|
||||
#endif
|
||||
|
||||
#define SPI_BUSY_CHECK
|
||||
|
||||
// Set the state machine clock divider (from integer and fractional parts - 16:8)
|
||||
#define CONSTRUCTOR_INIT_TFT_DATA_BUS pioinit(TFT_D0, TFT_WR, DIV_UNITS, DIV_FRACT);
|
||||
#define PARALLEL_INIT_TFT_DATA_BUS // Not used
|
||||
|
||||
#endif
|
||||
|
||||
@ -98,7 +108,7 @@
|
||||
#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) // SPI
|
||||
#if !defined (RP2040_PIO_INTERFACE)// SPI
|
||||
//#define DC_C sio_hw->gpio_clr = (1ul << TFT_DC)
|
||||
//#define DC_D sio_hw->gpio_set = (1ul << TFT_DC)
|
||||
#if defined (RPI_DISPLAY_TYPE)
|
||||
@ -109,12 +119,13 @@
|
||||
#define DC_D sio_hw->gpio_set = (1ul << TFT_DC)
|
||||
#endif
|
||||
#else
|
||||
// PIO takes control of TFT_DC
|
||||
// Must wait for data to flush through before changing DC line
|
||||
#define DC_C WAIT_FOR_STALL; \
|
||||
sio_hw->gpio_clr = (1ul << TFT_DC)
|
||||
pio->sm[pio_sm].instr = pio_instr_clr_dc
|
||||
|
||||
// Flush has happened before this and mode changed back to 16 bit
|
||||
#define DC_D sio_hw->gpio_set = (1ul << TFT_DC)
|
||||
#define DC_D pio->sm[pio_sm].instr = pio_instr_set_dc
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -125,12 +136,17 @@
|
||||
#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 (RPI_DISPLAY_TYPE)
|
||||
#define CS_L digitalWrite(TFT_CS, LOW);
|
||||
#define CS_H digitalWrite(TFT_CS, HIGH);
|
||||
#else
|
||||
#if !defined (RP2040_PIO_INTERFACE) // SPI
|
||||
#if defined (RPI_DISPLAY_TYPE)
|
||||
#define CS_L digitalWrite(TFT_CS, LOW);
|
||||
#define CS_H digitalWrite(TFT_CS, HIGH);
|
||||
#else
|
||||
#define CS_L sio_hw->gpio_clr = (1ul << TFT_CS)
|
||||
#define CS_H sio_hw->gpio_set = (1ul << TFT_CS)
|
||||
#endif
|
||||
#else // PIO interface display
|
||||
#define CS_L sio_hw->gpio_clr = (1ul << TFT_CS)
|
||||
#define CS_H sio_hw->gpio_set = (1ul << TFT_CS)
|
||||
#define CS_H WAIT_FOR_STALL; sio_hw->gpio_set = (1ul << TFT_CS)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -157,7 +173,7 @@
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Define the touch screen chip select pin drive code
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#if !defined (TFT_PARALLEL_8_BIT) // SPI
|
||||
#if !defined (RP2040_PIO_INTERFACE)// SPI
|
||||
#if !defined TOUCH_CS || (TOUCH_CS < 0)
|
||||
#define T_CS_L // No macro allocated so it generates no code
|
||||
#define T_CS_H // No macro allocated so it generates no code
|
||||
@ -181,7 +197,7 @@
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Macros to write commands/pixel colour data to a SPI ILI948x TFT
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#if !defined (TFT_PARALLEL_8_BIT) // SPI
|
||||
#if !defined (RP2040_PIO_INTERFACE) // SPI
|
||||
|
||||
#if defined (SPI_18BIT_DRIVER) // SPI 18 bit colour
|
||||
|
||||
@ -277,10 +293,10 @@
|
||||
#endif // RPI_DISPLAY_TYPE
|
||||
#endif
|
||||
|
||||
#else // Parallel 8 bit
|
||||
#else // Parallel 8 bit or PIO SPI
|
||||
|
||||
// On it's own this does not appear to reliably detect a stall, found that we must wait
|
||||
// for FIFO to empty before clearing the stall flag, and then wait for it to be set
|
||||
// Wait for the PIO to stall (SM pull request finds no data in TX FIFO)
|
||||
// This is used to detect when the SM is idle and hence ready for a jump instruction
|
||||
#define WAIT_FOR_STALL pio->fdebug = pull_stall_mask; while (!(pio->fdebug & pull_stall_mask))
|
||||
|
||||
// Wait until at least "S" locations free
|
||||
@ -306,8 +322,8 @@
|
||||
// Have already waited for pio stalled (last data write complete) when DC switched to command mode
|
||||
// The wait for stall allows DC to be changed immediately afterwards
|
||||
#define tft_Write_8(C) pio->sm[pio_sm].instr = pio_instr_jmp8; \
|
||||
TX_FIFO = C; \
|
||||
WAIT_FOR_STALL; \
|
||||
TX_FIFO = (C); \
|
||||
WAIT_FOR_STALL
|
||||
|
||||
// Note: the following macros do not wait for the end of transmission
|
||||
|
||||
@ -317,7 +333,7 @@
|
||||
|
||||
#define tft_Write_16S(C) WAIT_FOR_FIFO_FREE(1); TX_FIFO = ((C)<<8) | ((C)>>8)
|
||||
|
||||
#define tft_Write_32(C) WAIT_FOR_FIFO_FREE(2); TX_FIFO = (C)>>16; TX_FIFO = (C)
|
||||
#define tft_Write_32(C) WAIT_FOR_FIFO_FREE(2); TX_FIFO = ((C)>>16); TX_FIFO = (C)
|
||||
|
||||
#define tft_Write_32C(C,D) WAIT_FOR_FIFO_FREE(2); TX_FIFO = (C); TX_FIFO = (D)
|
||||
|
||||
@ -327,7 +343,7 @@
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Macros to read from display using SPI or software SPI
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#if !defined (TFT_PARALLEL_8_BIT) // SPI
|
||||
#if !defined (RP2040_PIO_INTERFACE)// SPI
|
||||
#if defined (TFT_SDA_READ)
|
||||
// Use a bit banged function call for STM32 and bi-directional SDA pin
|
||||
#define TFT_eSPI_ENABLE_8_BIT_READ // Enable tft_Read_8(void);
|
||||
|
@ -308,7 +308,7 @@
|
||||
// Mask for the 8 data bits to set pin directions (not used)
|
||||
#define dir_mask 0
|
||||
|
||||
#define CONSTRUCTOR_INIT_TFT_DATA_BUS // None
|
||||
#define PARALLEL_INIT_TFT_DATA_BUS // None
|
||||
|
||||
#define INIT_TFT_DATA_BUS // Setup built into TFT_eSPI.cpp
|
||||
|
||||
|
@ -10,32 +10,93 @@
|
||||
.program tft_io
|
||||
.side_set 1 opt ; The TFT_WR output.
|
||||
|
||||
// The C++ code switches between the 8 bits and 16 bits loops
|
||||
// The C++ code switches between the different SM routines
|
||||
// by waiting for the SM to be idle and setting its PC.
|
||||
//
|
||||
public start_16:
|
||||
// Fetch into OSR the next 32 bit value from the TX FIFO.
|
||||
// This is a blocking operation. Sets WR high.
|
||||
pull side 1
|
||||
// Shift the OSR reg right by 8 bits, loading the low 8 bits
|
||||
// of reg x with the shifted data.
|
||||
out x, 8
|
||||
// Write the first byte (MSB) and sets WR low. This also
|
||||
// shift OSR by 8 bits which we don't care about.
|
||||
out pins, 8 side 0 [1]
|
||||
// Set TFT_WR back high.
|
||||
nop side 1
|
||||
// Move the LSB byte back to the OSR.
|
||||
mov osr, x
|
||||
// Output the second byte and set TFT_WRITE low.
|
||||
out pins, 8 side 0
|
||||
jmp start_16
|
||||
// The default SM routine is a 16 bit transfer
|
||||
|
||||
// 8 bit transfer
|
||||
public start_32:
|
||||
// Fetch the next 32 bit value from the TX FIFO and set TFT_WR high.
|
||||
pull side 1
|
||||
// Output byte, TFT_WR low.
|
||||
out pins, 8 side 0 [1]
|
||||
// Loop until 4 bytes sent, TFT_WR high.
|
||||
jmp !osre, send_xy side 1 [1]
|
||||
//Jump back to 16 bit
|
||||
jmp start_16
|
||||
|
||||
// Do a block fill of N+1 pixels.
|
||||
public block_fill:
|
||||
// Fetch colour value.
|
||||
pull side 1
|
||||
// Move colour to x.
|
||||
mov x, osr
|
||||
// Fetch pixel count N (sends N+1 pixels).
|
||||
pull
|
||||
// Move pixel count to y.
|
||||
mov y, osr
|
||||
next:
|
||||
// Copy colour value into osr, colour in LS 16 bits.
|
||||
mov osr, x side 1
|
||||
// Output colour 8 MS bits, unwanted top 16 bits shifted through.
|
||||
out pins, 24 side 0 [1]
|
||||
// Write first colour byte.
|
||||
nop side 1 [1]
|
||||
// Write second colour byte.
|
||||
out pins, 8 side 0 [1]
|
||||
// Decrement pixel count and loop.
|
||||
jmp y--, next side 1
|
||||
|
||||
.wrap_target
|
||||
// Transmit a 16 bit value (LS 16 bits of 32 bits).
|
||||
public start_16:
|
||||
// Fetch the next 32 bit value from the TX FIFO and set TFT_WR high.
|
||||
pull side 1
|
||||
// Write the first byte (MSB) and set WR low. This also
|
||||
// shifts the unused top 16 bits through.
|
||||
out pins, 24 side 0 [1]
|
||||
// Set WR high and delay to next byte.
|
||||
nop side 1 [1]
|
||||
// Output the second byte and set TFT_WRITE low.
|
||||
out pins, 8 side 0 [1]
|
||||
// Set WR high and jump back to start.
|
||||
jmp start_16 side 1
|
||||
|
||||
// Transmit an 8 bit value (LS 8 bits of 32 bits).
|
||||
public start_8:
|
||||
// Fetch into OSR the next 32 bit value from the TX FIFO.
|
||||
// This is a blocking operation. Sets WR high.
|
||||
// Fetch the next 32 bit value from the TX FIFO and set TFT_WR high.
|
||||
pull side 1
|
||||
// Write the first byte (LSB) and sets WR low. This also
|
||||
// shifts the OSR right by 8 bits.
|
||||
out pins, 8 side 0 [1]
|
||||
// shifts the unused top 24 bits through.
|
||||
out pins, 32 side 0 [1]
|
||||
// Jump to start
|
||||
jmp start_16 side 1
|
||||
|
||||
// Transmit a set window command sequence.
|
||||
public set_addr_window:
|
||||
// Loop count in x (to send caset, paset and ramwr commands).
|
||||
set x, 2 side 1
|
||||
pull_cmd:
|
||||
// Set TFT_DC low.
|
||||
set pins, 0
|
||||
// Fetch caset, paset or ramwr.
|
||||
pull
|
||||
// Output LS byte (caset, paset or ramwr), discarding top 24 bits, set TFT_WR low.
|
||||
out pins, 32 side 0
|
||||
// Jump to end if 3rd cmd byte ramwr sent (x == 0)
|
||||
jmp !x, end_set_addr
|
||||
// pull next start and end coordinates, TFT_WR high.
|
||||
pull side 1
|
||||
// Set TFT_DC high.
|
||||
set pins, 1
|
||||
send_xy:
|
||||
// Output byte, TFT_WR low.
|
||||
out pins, 8 side 0 [1]
|
||||
// Loop until 4 bytes sent, TFT_WR high.
|
||||
jmp !osre, send_xy side 1 [1]
|
||||
end_set_addr:
|
||||
// Loop back for next command and write last command.
|
||||
jmp x--, pull_cmd side 1
|
||||
// Set DC high.
|
||||
set pins, 1
|
||||
// Auto-wrap back to start_16.
|
||||
.wrap
|
@ -4,34 +4,64 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !PICO_NO_HARDWARE
|
||||
#include "hardware/pio.h"
|
||||
#endif
|
||||
|
||||
// ------ //
|
||||
// tft_io //
|
||||
// ------ //
|
||||
|
||||
#define tft_io_wrap_target 0
|
||||
#define tft_io_wrap 8
|
||||
#define tft_io_wrap_target 13
|
||||
#define tft_io_wrap 31
|
||||
|
||||
#define tft_io_offset_start_16 0u
|
||||
#define tft_io_offset_start_8 7u
|
||||
#define tft_io_offset_start_32 0u
|
||||
#define tft_io_offset_block_fill 4u
|
||||
#define tft_io_offset_start_16 13u
|
||||
#define tft_io_offset_start_8 18u
|
||||
#define tft_io_offset_set_addr_window 21u
|
||||
|
||||
static const uint16_t tft_io_program_instructions[] = {
|
||||
// .wrap_target
|
||||
0x98a0, // 0: pull block side 1
|
||||
0x6028, // 1: out x, 8
|
||||
0x7108, // 2: out pins, 8 side 0 [1]
|
||||
0xb842, // 3: nop side 1
|
||||
0xa0e1, // 4: mov osr, x
|
||||
0x7008, // 5: out pins, 8 side 0
|
||||
0x0000, // 6: jmp 0
|
||||
0x98a0, // 7: pull block side 1
|
||||
0x7108, // 8: out pins, 8 side 0 [1]
|
||||
0x7108, // 1: out pins, 8 side 0 [1]
|
||||
0x19fc, // 2: jmp !osre, 28 side 1 [1]
|
||||
0x000d, // 3: jmp 13
|
||||
0x98a0, // 4: pull block side 1
|
||||
0xa027, // 5: mov x, osr
|
||||
0x80a0, // 6: pull block
|
||||
0xa047, // 7: mov y, osr
|
||||
0xb8e1, // 8: mov osr, x side 1
|
||||
0x7118, // 9: out pins, 24 side 0 [1]
|
||||
0xb942, // 10: nop side 1 [1]
|
||||
0x7108, // 11: out pins, 8 side 0 [1]
|
||||
0x1888, // 12: jmp y--, 8 side 1
|
||||
// .wrap_target
|
||||
0x98a0, // 13: pull block side 1
|
||||
0x7118, // 14: out pins, 24 side 0 [1]
|
||||
0xb942, // 15: nop side 1 [1]
|
||||
0x7108, // 16: out pins, 8 side 0 [1]
|
||||
0x180d, // 17: jmp 13 side 1
|
||||
0x98a0, // 18: pull block side 1
|
||||
0x7100, // 19: out pins, 32 side 0 [1]
|
||||
0x180d, // 20: jmp 13 side 1
|
||||
0xf822, // 21: set x, 2 side 1
|
||||
0xe000, // 22: set pins, 0
|
||||
0x80a0, // 23: pull block
|
||||
0x7000, // 24: out pins, 32 side 0
|
||||
0x003e, // 25: jmp !x, 30
|
||||
0x98a0, // 26: pull block side 1
|
||||
0xe001, // 27: set pins, 1
|
||||
0x7108, // 28: out pins, 8 side 0 [1]
|
||||
0x19fc, // 29: jmp !osre, 28 side 1 [1]
|
||||
0x1856, // 30: jmp x--, 22 side 1
|
||||
0xe001, // 31: set pins, 1
|
||||
// .wrap
|
||||
};
|
||||
|
||||
#if !PICO_NO_HARDWARE
|
||||
static const struct pio_program tft_io_program = {
|
||||
.instructions = tft_io_program_instructions,
|
||||
.length = 9,
|
||||
.length = 32,
|
||||
.origin = -1,
|
||||
};
|
||||
|
||||
|
91
Processors/pio_SPI.pio
Normal file
91
Processors/pio_SPI.pio
Normal file
@ -0,0 +1,91 @@
|
||||
// Raspberry Pi Pico PIO program to output data to a TFT
|
||||
// controller via a SPI output data path.
|
||||
|
||||
//"Set" set: 1 output pin, TFT_DC
|
||||
// Side set: 1 output pin, TFT_SCLK
|
||||
// Data set: 1 output pin, TFT_MOSI
|
||||
|
||||
.program tft_io
|
||||
.side_set 1 opt ; The TFT_SCLK output.
|
||||
|
||||
// The C++ code switches between the 8 bits and 16 bits loops
|
||||
// by waiting for the SM to be idle and setting its PC.
|
||||
//
|
||||
|
||||
// 8 bit transfer
|
||||
public start_8:
|
||||
// Pull the next 32 bit value from the TX FIFO.
|
||||
// Lose the top 24 bits
|
||||
pull side 0
|
||||
out null, 24
|
||||
spi_out_8:
|
||||
// Output the next 8 bits
|
||||
out pins, 1 side 0
|
||||
// Set TFT_SCLK high and jump for next bit
|
||||
jmp !osre, spi_out_8 side 1
|
||||
// Return to start
|
||||
jmp start_16 side 0
|
||||
|
||||
public set_addr_window:
|
||||
// Loop count in x for caset, paset and ramwr
|
||||
set x, 2 side 0
|
||||
pull_cmd:
|
||||
// Set DC low
|
||||
set pins, 0
|
||||
// Fetch and output LS byte (caset, paset or ramwr), discarding top 24 bits, set WR low
|
||||
pull side 0
|
||||
out null, 24
|
||||
next_cmd_bit:
|
||||
out pins, 1 side 0
|
||||
jmp !osre, next_cmd_bit side 1
|
||||
// Set DC high
|
||||
set pins, 1 side 0
|
||||
// Finish if 3rd cmd byte ramwr sent (x == 0)
|
||||
jmp !x, start_16
|
||||
pull
|
||||
next_xy:
|
||||
// send 32 bit start and end coordinates
|
||||
out pins, 1 side 0
|
||||
jmp !osre, next_xy side 1
|
||||
// Loop back for next command
|
||||
jmp x--, pull_cmd side 0
|
||||
// End
|
||||
jmp start_16
|
||||
|
||||
public block_fill:
|
||||
// Fetch colour value
|
||||
pull side 0
|
||||
// Move colour to x
|
||||
mov x, osr
|
||||
// Fetch pixel count
|
||||
pull
|
||||
// Move pixel count to y
|
||||
mov y, osr
|
||||
next_16:
|
||||
// Copy colour value back into osr
|
||||
mov osr, x side 0
|
||||
// Lose the top 16 bits, send 1st bit
|
||||
out pins, 17 side 0
|
||||
nop side 1
|
||||
next_bit:
|
||||
// Output next 15 colour bits
|
||||
out pins, 1 side 0
|
||||
// Set TFT_SCLK high and jump for next bit
|
||||
jmp !osre, next_bit side 1
|
||||
// Decrement count and loop
|
||||
jmp y--, next_16 side 0
|
||||
// Now drop back to 16 bit output
|
||||
|
||||
.wrap_target
|
||||
public start_16:
|
||||
// Pull the next 32 bit value from the TX FIFO.
|
||||
// Write the top 16 bits
|
||||
pull side 0
|
||||
out null, 16
|
||||
spi_out_16:
|
||||
// Output the next 16 bits
|
||||
out pins, 1 side 0
|
||||
// Set TFT_SCLK high and jump for next bit
|
||||
jmp !osre, spi_out_16 side 1
|
||||
// Return to start
|
||||
.wrap
|
73
Processors/pio_SPI.pio.h
Normal file
73
Processors/pio_SPI.pio.h
Normal file
@ -0,0 +1,73 @@
|
||||
// -------------------------------------------------- //
|
||||
// This file is autogenerated by pioasm; do not edit! //
|
||||
// -------------------------------------------------- //
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !PICO_NO_HARDWARE
|
||||
#include "hardware/pio.h"
|
||||
#endif
|
||||
|
||||
// ------ //
|
||||
// tft_io //
|
||||
// ------ //
|
||||
|
||||
#define tft_io_wrap_target 28
|
||||
#define tft_io_wrap 31
|
||||
|
||||
#define tft_io_offset_start_8 0u
|
||||
#define tft_io_offset_set_addr_window 5u
|
||||
#define tft_io_offset_block_fill 18u
|
||||
#define tft_io_offset_start_16 28u
|
||||
|
||||
static const uint16_t tft_io_program_instructions[] = {
|
||||
0x90a0, // 0: pull block side 0
|
||||
0x6078, // 1: out null, 24
|
||||
0x7001, // 2: out pins, 1 side 0
|
||||
0x18e2, // 3: jmp !osre, 2 side 1
|
||||
0x101c, // 4: jmp 28 side 0
|
||||
0xf022, // 5: set x, 2 side 0
|
||||
0xe000, // 6: set pins, 0
|
||||
0x90a0, // 7: pull block side 0
|
||||
0x6078, // 8: out null, 24
|
||||
0x7001, // 9: out pins, 1 side 0
|
||||
0x18e9, // 10: jmp !osre, 9 side 1
|
||||
0xf001, // 11: set pins, 1 side 0
|
||||
0x003c, // 12: jmp !x, 28
|
||||
0x80a0, // 13: pull block
|
||||
0x7001, // 14: out pins, 1 side 0
|
||||
0x18ee, // 15: jmp !osre, 14 side 1
|
||||
0x1046, // 16: jmp x--, 6 side 0
|
||||
0x001c, // 17: jmp 28
|
||||
0x90a0, // 18: pull block side 0
|
||||
0xa027, // 19: mov x, osr
|
||||
0x80a0, // 20: pull block
|
||||
0xa047, // 21: mov y, osr
|
||||
0xb0e1, // 22: mov osr, x side 0
|
||||
0x7011, // 23: out pins, 17 side 0
|
||||
0xb842, // 24: nop side 1
|
||||
0x7001, // 25: out pins, 1 side 0
|
||||
0x18f9, // 26: jmp !osre, 25 side 1
|
||||
0x1096, // 27: jmp y--, 22 side 0
|
||||
// .wrap_target
|
||||
0x90a0, // 28: pull block side 0
|
||||
0x6070, // 29: out null, 16
|
||||
0x7001, // 30: out pins, 1 side 0
|
||||
0x18fe, // 31: jmp !osre, 30 side 1
|
||||
// .wrap
|
||||
};
|
||||
|
||||
#if !PICO_NO_HARDWARE
|
||||
static const struct pio_program tft_io_program = {
|
||||
.instructions = tft_io_program_instructions,
|
||||
.length = 32,
|
||||
.origin = -1,
|
||||
};
|
||||
|
||||
static inline pio_sm_config tft_io_program_get_default_config(uint offset) {
|
||||
pio_sm_config c = pio_get_default_sm_config();
|
||||
sm_config_set_wrap(&c, offset + tft_io_wrap_target, offset + tft_io_wrap);
|
||||
sm_config_set_sideset(&c, 2, true, false);
|
||||
return c;
|
||||
}
|
||||
#endif
|
20
README.md
20
README.md
@ -1,26 +1,28 @@
|
||||
A ["Discussions"](https://github.com/Bodmer/TFT_eSPI/discussions) facility has been added for Q&A etc. Use the ["Issues"](https://github.com/Bodmer/TFT_eSPI/issues) tab only for problems with the library. Thanks!
|
||||
# News
|
||||
1. DMA can now be used with the Raspberry Pi Pico (RP2040) when used with both 8 bit parallel and 16 bit colour SPI displays. See "Bouncy_Circles" sketch.
|
||||
1. The RP2040 8 bit parallel interface uses the PIO. The PIO now manages the "setWindow" and "block fill" actions, releasing the processor for other tasks when areas of the screen are being filled with a colour. The PIO can optionally be used for SPI interface displays if #define RP2040_PIO_SPI is put in the setup file. Touch screens and pixel read operations are not supported when the PIO interface is used.
|
||||
|
||||
2. DMA can now be used with the Raspberry Pi Pico (RP2040) when used with both 8 bit parallel and 16 bit colour SPI displays. See "Bouncy_Circles" sketch.
|
||||
|
||||
["Bouncing circles"](https://www.youtube.com/watch?v=njFXIzCTQ_Q&lc=UgymaUIwOIuihvYh-Qt4AaABAg)
|
||||
|
||||
2. Support hase been added for the ESP32 S2 processor variant. A [new user setup](https://github.com/Bodmer/TFT_eSPI/blob/master/User_Setups/Setup70_ESP32_S2_ILI9341.h) file has been added as an example setup with an ILI9341 TFT. You will need to load ESP32 Arduino board package 2.0.0 or later to use the updated library with an ESP32.
|
||||
3. Support hase been added for the ESP32 S2 processor variant. A [new user setup](https://github.com/Bodmer/TFT_eSPI/blob/master/User_Setups/Setup70_ESP32_S2_ILI9341.h) file has been added as an example setup with an ILI9341 TFT. You will need to load ESP32 Arduino board package 2.0.0 or later to use the updated library with an ESP32.
|
||||
|
||||
3. The library now supports the Raspberry Pi Pico with both the [official Arduino board package](https://github.com/arduino/ArduinoCore-mbed) and the one provided by [Earle Philhower](https://github.com/earlephilhower/arduino-pico). The setup file "Setup60_RP2040_ILI9341.h" has been used for tests with an ILI9341 display. At the moment only SPI interface displays have been tested. SPI port 0 is the default but SPI port 1 can be specifed in the setup file if those SPI pins are used.
|
||||
4. The library now supports the Raspberry Pi Pico with both the [official Arduino board package](https://github.com/arduino/ArduinoCore-mbed) and the one provided by [Earle Philhower](https://github.com/earlephilhower/arduino-pico). The setup file "Setup60_RP2040_ILI9341.h" has been used for tests with an ILI9341 display. At the moment only SPI interface displays have been tested. SPI port 0 is the default but SPI port 1 can be specifed in the setup file if those SPI pins are used.
|
||||
|
||||
["Rotating cube demo"](https://www.youtube.com/watch?v=4fPxEN9ImVE)
|
||||
|
||||
4. Viewports can now be applied to sprites e.g. spr.setViewport(5, 5, 20, 20); so graphics can be restricted to a particular area of the sprite. This operates in the same way as the TFT viewports, see 5. below.
|
||||
5. Viewports can now be applied to sprites e.g. spr.setViewport(5, 5, 20, 20); so graphics can be restricted to a particular area of the sprite. This operates in the same way as the TFT viewports, see 5. below.
|
||||
|
||||
5. The library now provides a "viewport" capability. See "Viewport_Demo" and "Viewport_graphicstest" examples. When a viewport is defined graphics will only appear within that window. The coordinate datum by default moves to the top left corner of the viewport, but can optionally remain at top left corner of TFT. The GUIslice library will make use of this feature to speed up the rendering of GUI objects ([see #769](https://github.com/Bodmer/TFT_eSPI/issues/769)).
|
||||
6. The library now provides a "viewport" capability. See "Viewport_Demo" and "Viewport_graphicstest" examples. When a viewport is defined graphics will only appear within that window. The coordinate datum by default moves to the top left corner of the viewport, but can optionally remain at top left corner of TFT. The GUIslice library will make use of this feature to speed up the rendering of GUI objects ([see #769](https://github.com/Bodmer/TFT_eSPI/issues/769)).
|
||||
|
||||
6. The library now supports SSD1963 based screen, this has been tested on a [480x800 screen](https://www.buydisplay.com/7-tft-screen-touch-lcd-display-module-w-ssd1963-controller-board-mcu) with an ESP32. The interface is 8 bit parallel only as that controller does not support a SPI interface.
|
||||
7. The library now supports SSD1963 based screen, this has been tested on a [480x800 screen](https://www.buydisplay.com/7-tft-screen-touch-lcd-display-module-w-ssd1963-controller-board-mcu) with an ESP32. The interface is 8 bit parallel only as that controller does not support a SPI interface.
|
||||
|
||||
7. A companion library [U8g2_for_TFT_eSPI](https://github.com/Bodmer/U8g2_for_TFT_eSPI) has been created to allow U8g2 library fonts to be used with TFT_eSPI.
|
||||
8. A companion library [U8g2_for_TFT_eSPI](https://github.com/Bodmer/U8g2_for_TFT_eSPI) has been created to allow U8g2 library fonts to be used with TFT_eSPI.
|
||||
|
||||
8. The library now supports SPI DMA transfers for both ESP32 and STM32 processors. The DMA Test examples now work on the ESP32 for SPI displays (excluding RPi type and ILI9488).
|
||||
9. The library now supports SPI DMA transfers for both ESP32 and STM32 processors. The DMA Test examples now work on the ESP32 for SPI displays (excluding RPi type and ILI9488).
|
||||
|
||||
9. A new option has been added for STM32 processors to optimise performance where Port A (or B) pins 0-7 are used for the 8 bit parallel interface data pins 0-7 to the TFT. This gives a dramatic 8 times better rendering performance for the lower clock rate STM32 processors such as the STM32F103 "Blue Pill" or STM411 "Black Pill" since no time consuming data bit manipulation is required. See setup file "User_Setups/Setup35_ILI9341_STM32_Port_Bus.h".
|
||||
10. A new option has been added for STM32 processors to optimise performance where Port A (or B) pins 0-7 are used for the 8 bit parallel interface data pins 0-7 to the TFT. This gives a dramatic 8 times better rendering performance for the lower clock rate STM32 processors such as the STM32F103 "Blue Pill" or STM411 "Black Pill" since no time consuming data bit manipulation is required. See setup file "User_Setups/Setup35_ILI9341_STM32_Port_Bus.h".
|
||||
|
||||
# TFT_eSPI
|
||||
|
||||
|
453
TFT_eSPI.cpp
453
TFT_eSPI.cpp
@ -58,10 +58,10 @@
|
||||
** Description: Start SPI transaction for writes and select TFT
|
||||
***************************************************************************************/
|
||||
inline void TFT_eSPI::begin_tft_write(void){
|
||||
#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(TFT_PARALLEL_8_BIT)
|
||||
#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(TFT_PARALLEL_8_BIT) && !defined(RP2040_PIO_INTERFACE)
|
||||
if (locked) {
|
||||
locked = false; // Flag to show SPI access now unlocked
|
||||
spi.beginTransaction(SPISettings(SPI_FREQUENCY, MSBFIRST, TFT_SPI_MODE)); // RP2040 SDK -> 68us delay!
|
||||
spi.beginTransaction(SPISettings(SPI_FREQUENCY, MSBFIRST, TFT_SPI_MODE));
|
||||
CS_L;
|
||||
SET_BUS_WRITE_MODE; // Some processors (e.g. ESP32) allow recycling the tx buffer when rx is not used
|
||||
}
|
||||
@ -77,13 +77,13 @@ inline void TFT_eSPI::begin_tft_write(void){
|
||||
** Description: End transaction for write and deselect TFT
|
||||
***************************************************************************************/
|
||||
inline void TFT_eSPI::end_tft_write(void){
|
||||
#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(TFT_PARALLEL_8_BIT)
|
||||
#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(TFT_PARALLEL_8_BIT) && !defined(RP2040_PIO_INTERFACE)
|
||||
if(!inTransaction) { // Flag to stop ending transaction during multiple graphics calls
|
||||
if (!locked) { // Locked when beginTransaction has been called
|
||||
locked = true; // Flag to show SPI access now locked
|
||||
SPI_BUSY_CHECK; // Check send complete and clean out unused rx data
|
||||
CS_H;
|
||||
spi.endTransaction(); // RP2040 SDK -> 0.7us delay
|
||||
spi.endTransaction();
|
||||
}
|
||||
SET_BUS_READ_MODE; // In case SPI has been configured for tx only
|
||||
}
|
||||
@ -99,14 +99,14 @@ inline void TFT_eSPI::end_tft_write(void){
|
||||
// Reads require a lower SPI clock rate than writes
|
||||
inline void TFT_eSPI::begin_tft_read(void){
|
||||
DMA_BUSY_CHECK; // Wait for any DMA transfer to complete before changing SPI settings
|
||||
#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(TFT_PARALLEL_8_BIT)
|
||||
#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(TFT_PARALLEL_8_BIT) && !defined(RP2040_PIO_INTERFACE)
|
||||
if (locked) {
|
||||
locked = false;
|
||||
spi.beginTransaction(SPISettings(SPI_READ_FREQUENCY, MSBFIRST, TFT_SPI_MODE));
|
||||
CS_L;
|
||||
}
|
||||
#else
|
||||
#if !defined(TFT_PARALLEL_8_BIT)
|
||||
#if !defined(TFT_PARALLEL_8_BIT) && !defined(RP2040_PIO_INTERFACE)
|
||||
spi.setFrequency(SPI_READ_FREQUENCY);
|
||||
#endif
|
||||
CS_L;
|
||||
@ -330,7 +330,7 @@ void TFT_eSPI::frameViewport(uint16_t color, int32_t w)
|
||||
** Description: End transaction for reads and deselect TFT
|
||||
***************************************************************************************/
|
||||
inline void TFT_eSPI::end_tft_read(void){
|
||||
#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(TFT_PARALLEL_8_BIT)
|
||||
#if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) && !defined(TFT_PARALLEL_8_BIT) && !defined(RP2040_PIO_INTERFACE)
|
||||
if(!inTransaction) {
|
||||
if (!locked) {
|
||||
locked = true;
|
||||
@ -339,7 +339,7 @@ inline void TFT_eSPI::end_tft_read(void){
|
||||
}
|
||||
}
|
||||
#else
|
||||
#if !defined(TFT_PARALLEL_8_BIT)
|
||||
#if !defined(TFT_PARALLEL_8_BIT) && !defined(RP2040_PIO_INTERFACE)
|
||||
spi.setFrequency(SPI_FREQUENCY);
|
||||
#endif
|
||||
if(!inTransaction) {CS_H;}
|
||||
@ -362,61 +362,6 @@ inline void TFT_eSPI::end_tft_read(void){
|
||||
***************************************************************************************/
|
||||
TFT_eSPI::TFT_eSPI(int16_t w, int16_t h)
|
||||
{
|
||||
|
||||
// The control pins are deliberately set to the inactive state (CS high) as setup()
|
||||
// might call and initialise other SPI peripherals which would could cause conflicts
|
||||
// if CS is floating or undefined.
|
||||
#ifdef TFT_CS
|
||||
pinMode(TFT_CS, OUTPUT);
|
||||
digitalWrite(TFT_CS, HIGH); // Chip select high (inactive)
|
||||
#endif
|
||||
|
||||
// Configure chip select for touchscreen controller if present
|
||||
#ifdef TOUCH_CS
|
||||
pinMode(TOUCH_CS, OUTPUT);
|
||||
digitalWrite(TOUCH_CS, HIGH); // Chip select high (inactive)
|
||||
#endif
|
||||
|
||||
// In parallel mode and with the RP2040 processor, the TFT_WR line is handled in the PIO
|
||||
#if defined (TFT_WR) && !defined (ARDUINO_ARCH_RP2040) && !defined (ARDUINO_ARCH_MBED)
|
||||
pinMode(TFT_WR, OUTPUT);
|
||||
digitalWrite(TFT_WR, HIGH); // Set write strobe high (inactive)
|
||||
#endif
|
||||
|
||||
#ifdef TFT_DC
|
||||
pinMode(TFT_DC, OUTPUT);
|
||||
digitalWrite(TFT_DC, HIGH); // Data/Command high = data mode
|
||||
#endif
|
||||
|
||||
#ifdef TFT_RST
|
||||
if (TFT_RST >= 0) {
|
||||
pinMode(TFT_RST, OUTPUT);
|
||||
digitalWrite(TFT_RST, HIGH); // Set high, do not share pin with another SPI device
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined (TFT_PARALLEL_8_BIT)
|
||||
|
||||
// Make sure read is high before we set the bus to output
|
||||
pinMode(TFT_RD, OUTPUT);
|
||||
digitalWrite(TFT_RD, HIGH);
|
||||
|
||||
#if !defined (ARDUINO_ARCH_RP2040) && !defined (ARDUINO_ARCH_MBED)// PIO manages pins
|
||||
// Set TFT data bus lines to output
|
||||
pinMode(TFT_D0, OUTPUT); digitalWrite(TFT_D0, HIGH);
|
||||
pinMode(TFT_D1, OUTPUT); digitalWrite(TFT_D1, HIGH);
|
||||
pinMode(TFT_D2, OUTPUT); digitalWrite(TFT_D2, HIGH);
|
||||
pinMode(TFT_D3, OUTPUT); digitalWrite(TFT_D3, HIGH);
|
||||
pinMode(TFT_D4, OUTPUT); digitalWrite(TFT_D4, HIGH);
|
||||
pinMode(TFT_D5, OUTPUT); digitalWrite(TFT_D5, HIGH);
|
||||
pinMode(TFT_D6, OUTPUT); digitalWrite(TFT_D6, HIGH);
|
||||
pinMode(TFT_D7, OUTPUT); digitalWrite(TFT_D7, HIGH);
|
||||
#endif
|
||||
|
||||
CONSTRUCTOR_INIT_TFT_DATA_BUS;
|
||||
|
||||
#endif
|
||||
|
||||
_init_width = _width = w; // Set by specific xxxxx_Defines.h file or by users sketch
|
||||
_init_height = _height = h; // Set by specific xxxxx_Defines.h file or by users sketch
|
||||
|
||||
@ -502,6 +447,63 @@ TFT_eSPI::TFT_eSPI(int16_t w, int16_t h)
|
||||
#endif
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: initBus
|
||||
** Description: initialise the SPI or parallel bus
|
||||
***************************************************************************************/
|
||||
void TFT_eSPI::initBus(void) {
|
||||
|
||||
#ifdef TFT_CS
|
||||
pinMode(TFT_CS, OUTPUT);
|
||||
digitalWrite(TFT_CS, HIGH); // Chip select high (inactive)
|
||||
#endif
|
||||
|
||||
// Configure chip select for touchscreen controller if present
|
||||
#ifdef TOUCH_CS
|
||||
pinMode(TOUCH_CS, OUTPUT);
|
||||
digitalWrite(TOUCH_CS, HIGH); // Chip select high (inactive)
|
||||
#endif
|
||||
|
||||
// In parallel mode and with the RP2040 processor, the TFT_WR line is handled in the PIO
|
||||
#if defined (TFT_WR) && !defined (ARDUINO_ARCH_RP2040) && !defined (ARDUINO_ARCH_MBED)
|
||||
pinMode(TFT_WR, OUTPUT);
|
||||
digitalWrite(TFT_WR, HIGH); // Set write strobe high (inactive)
|
||||
#endif
|
||||
|
||||
#ifdef TFT_DC
|
||||
pinMode(TFT_DC, OUTPUT);
|
||||
digitalWrite(TFT_DC, HIGH); // Data/Command high = data mode
|
||||
#endif
|
||||
|
||||
#ifdef TFT_RST
|
||||
if (TFT_RST >= 0) {
|
||||
pinMode(TFT_RST, OUTPUT);
|
||||
digitalWrite(TFT_RST, HIGH); // Set high, do not share pin with another SPI device
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined (TFT_PARALLEL_8_BIT)
|
||||
|
||||
// Make sure read is high before we set the bus to output
|
||||
pinMode(TFT_RD, OUTPUT);
|
||||
digitalWrite(TFT_RD, HIGH);
|
||||
|
||||
#if !defined (ARDUINO_ARCH_RP2040) && !defined (ARDUINO_ARCH_MBED)// PIO manages pins
|
||||
// Set TFT data bus lines to output
|
||||
pinMode(TFT_D0, OUTPUT); digitalWrite(TFT_D0, HIGH);
|
||||
pinMode(TFT_D1, OUTPUT); digitalWrite(TFT_D1, HIGH);
|
||||
pinMode(TFT_D2, OUTPUT); digitalWrite(TFT_D2, HIGH);
|
||||
pinMode(TFT_D3, OUTPUT); digitalWrite(TFT_D3, HIGH);
|
||||
pinMode(TFT_D4, OUTPUT); digitalWrite(TFT_D4, HIGH);
|
||||
pinMode(TFT_D5, OUTPUT); digitalWrite(TFT_D5, HIGH);
|
||||
pinMode(TFT_D6, OUTPUT); digitalWrite(TFT_D6, HIGH);
|
||||
pinMode(TFT_D7, OUTPUT); digitalWrite(TFT_D7, HIGH);
|
||||
#endif
|
||||
|
||||
PARALLEL_INIT_TFT_DATA_BUS;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: begin
|
||||
@ -521,6 +523,8 @@ void TFT_eSPI::init(uint8_t tc)
|
||||
{
|
||||
if (_booted)
|
||||
{
|
||||
initBus();
|
||||
|
||||
#if !defined (ESP32) && !defined(TFT_PARALLEL_8_BIT) && !defined(ARDUINO_ARCH_RP2040) && !defined (ARDUINO_ARCH_MBED)
|
||||
// Legacy bitmasks for GPIO
|
||||
#if defined (TFT_CS) && (TFT_CS >= 0)
|
||||
@ -549,7 +553,7 @@ void TFT_eSPI::init(uint8_t tc)
|
||||
spi.begin(); // This will set HMISO to input
|
||||
|
||||
#else
|
||||
#if !defined(TFT_PARALLEL_8_BIT)
|
||||
#if !defined(TFT_PARALLEL_8_BIT) && !defined(RP2040_PIO_INTERFACE)
|
||||
#if defined (TFT_MOSI) && !defined (TFT_SPI_OVERLAP) && !defined(ARDUINO_ARCH_RP2040) && !defined (ARDUINO_ARCH_MBED)
|
||||
spi.begin(TFT_SCLK, TFT_MISO, TFT_MOSI, -1);
|
||||
#else
|
||||
@ -564,19 +568,17 @@ void TFT_eSPI::init(uint8_t tc)
|
||||
INIT_TFT_DATA_BUS;
|
||||
|
||||
|
||||
|
||||
#ifdef TFT_CS
|
||||
#if defined (TFT_CS) && defined (ESP8266)
|
||||
// Set to output once again in case ESP8266 D6 (MISO) is used for CS
|
||||
pinMode(TFT_CS, OUTPUT);
|
||||
digitalWrite(TFT_CS, HIGH); // Chip select high (inactive)
|
||||
#elif defined (ESP8266) && !defined (TFT_PARALLEL_8_BIT)
|
||||
#elif defined (ESP8266) && !defined (TFT_PARALLEL_8_BIT) && !defined (RP2040_PIO_SPI)
|
||||
spi.setHwCs(1); // Use hardware SS toggling
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// Set to output once again in case ESP8266 D6 (MISO) is used for DC
|
||||
#ifdef TFT_DC
|
||||
#if defined (TFT_DC) && defined (ESP8266)
|
||||
pinMode(TFT_DC, OUTPUT);
|
||||
digitalWrite(TFT_DC, HIGH); // Data/Command high = data mode
|
||||
#endif
|
||||
@ -603,7 +605,7 @@ void TFT_eSPI::init(uint8_t tc)
|
||||
|
||||
begin_tft_write();
|
||||
|
||||
tc = tc; // Supress warning
|
||||
tc = tc; // Suppress warning
|
||||
|
||||
// This loads the driver specific initialisation code <<<<<<<<<<<<<<<<<<<<< ADD NEW DRIVERS TO THE LIST HERE <<<<<<<<<<<<<<<<<<<<<<<
|
||||
#if defined (ILI9341_DRIVER) || defined(ILI9341_2_DRIVER)
|
||||
@ -850,7 +852,7 @@ void TFT_eSPI::writedata(uint8_t d)
|
||||
uint8_t TFT_eSPI::readcommand8(uint8_t cmd_function, uint8_t index)
|
||||
{
|
||||
uint8_t reg = 0;
|
||||
#ifdef TFT_PARALLEL_8_BIT
|
||||
#if defined(TFT_PARALLEL_8_BIT) || defined(RP2040_PIO_INTERFACE)
|
||||
|
||||
writecommand(cmd_function); // Sets DC and CS high
|
||||
|
||||
@ -932,7 +934,7 @@ uint16_t TFT_eSPI::readPixel(int32_t x0, int32_t y0)
|
||||
// Range checking
|
||||
if ((x0 < _vpX) || (y0 < _vpY) ||(x0 >= _vpW) || (y0 >= _vpH)) return 0;
|
||||
|
||||
#if defined(TFT_PARALLEL_8_BIT)
|
||||
#if defined(TFT_PARALLEL_8_BIT) || defined(RP2040_PIO_INTERFACE)
|
||||
|
||||
CS_L;
|
||||
|
||||
@ -982,7 +984,7 @@ uint16_t TFT_eSPI::readPixel(int32_t x0, int32_t y0)
|
||||
|
||||
#else // Not TFT_PARALLEL_8_BIT
|
||||
|
||||
// This function can get called during antialiased font rendering
|
||||
// This function can get called during anti-aliased font rendering
|
||||
// so a transaction may be in progress
|
||||
bool wasInTransaction = inTransaction;
|
||||
if (inTransaction) { inTransaction= false; end_tft_write();}
|
||||
@ -1056,7 +1058,7 @@ void TFT_eSPI::readRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *da
|
||||
{
|
||||
PI_CLIP ;
|
||||
|
||||
#if defined(TFT_PARALLEL_8_BIT)
|
||||
#if defined(TFT_PARALLEL_8_BIT) || defined(RP2040_PIO_INTERFACE)
|
||||
|
||||
CS_L;
|
||||
|
||||
@ -1890,7 +1892,7 @@ bool TFT_eSPI::getSwapBytes(void)
|
||||
// If w and h are 1, then 1 pixel is read, *data array size must be 3 bytes per pixel
|
||||
void TFT_eSPI::readRectRGB(int32_t x0, int32_t y0, int32_t w, int32_t h, uint8_t *data)
|
||||
{
|
||||
#if defined(TFT_PARALLEL_8_BIT)
|
||||
#if defined(TFT_PARALLEL_8_BIT) || defined(RP2040_PIO_INTERFACE)
|
||||
|
||||
uint32_t len = w * h;
|
||||
uint8_t* buf565 = data + len;
|
||||
@ -3091,46 +3093,59 @@ void TFT_eSPI::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1)
|
||||
#endif
|
||||
|
||||
// Temporary solution is to include the RP2040 optimised code here
|
||||
#if (defined(ARDUINO_ARCH_RP2040) || defined (ARDUINO_ARCH_MBED)) && !defined(TFT_PARALLEL_8_BIT)
|
||||
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
|
||||
DC_C;
|
||||
#if !defined (SPI_18BIT_DRIVER)
|
||||
#if defined (RPI_DISPLAY_TYPE) // RPi TFT type always needs 16 bit transfers
|
||||
spi_set_format(SPI_X, 16, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST);
|
||||
#else
|
||||
spi_set_format(SPI_X, 8, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST);
|
||||
#if (defined(ARDUINO_ARCH_RP2040) || defined (ARDUINO_ARCH_MBED))
|
||||
#if !defined(RP2040_PIO_INTERFACE)
|
||||
// Use hardware SPI port, this code does not swap from 8 to 16 bit
|
||||
// to avoid the spi_set_format() call overhead
|
||||
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
|
||||
DC_C;
|
||||
#if !defined (SPI_18BIT_DRIVER)
|
||||
#if defined (RPI_DISPLAY_TYPE) // RPi TFT type always needs 16 bit transfers
|
||||
spi_set_format(SPI_X, 16, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST);
|
||||
#else
|
||||
spi_set_format(SPI_X, 8, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST);
|
||||
#endif
|
||||
#endif
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)TFT_CASET;
|
||||
|
||||
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
|
||||
DC_D;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)x0>>8;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)x0;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)x1>>8;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)x1;
|
||||
|
||||
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
|
||||
DC_C;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)TFT_PASET;
|
||||
|
||||
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
|
||||
DC_D;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)y0>>8;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)y0;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)y1>>8;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)y1;
|
||||
|
||||
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
|
||||
DC_C;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)TFT_RAMWR;
|
||||
|
||||
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
|
||||
#if !defined (SPI_18BIT_DRIVER)
|
||||
spi_set_format(SPI_X, 16, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST);
|
||||
#endif
|
||||
DC_D;
|
||||
#else
|
||||
// This is for the RP2040 and PIO interface (SPI or parallel)
|
||||
WAIT_FOR_STALL;
|
||||
pio->sm[pio_sm].instr = pio_instr_addr;
|
||||
|
||||
TX_FIFO = TFT_CASET;
|
||||
TX_FIFO = (x0<<16) | x1;
|
||||
TX_FIFO = TFT_PASET;
|
||||
TX_FIFO = (y0<<16) | y1;
|
||||
TX_FIFO = TFT_RAMWR;
|
||||
#endif
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)TFT_CASET;
|
||||
|
||||
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
|
||||
DC_D;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)x0>>8;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)x0;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)x1>>8;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)x1;
|
||||
|
||||
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
|
||||
DC_C;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)TFT_PASET;
|
||||
|
||||
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
|
||||
DC_D;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)y0>>8;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)y0;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)y1>>8;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)y1;
|
||||
|
||||
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
|
||||
DC_C;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)TFT_RAMWR;
|
||||
|
||||
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
|
||||
#if !defined (SPI_18BIT_DRIVER)
|
||||
spi_set_format(SPI_X, 16, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST);
|
||||
#endif
|
||||
DC_D;
|
||||
|
||||
#else
|
||||
SPI_BUSY_CHECK;
|
||||
DC_C; tft_Write_8(TFT_CASET);
|
||||
@ -3144,7 +3159,6 @@ void TFT_eSPI::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1)
|
||||
//end_tft_write(); // Must be called after setWindow
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************************
|
||||
** Function name: readAddrWindow
|
||||
** Description: define an area to read a stream of pixels
|
||||
@ -3171,7 +3185,7 @@ void TFT_eSPI::readAddrWindow(int32_t xs, int32_t ys, int32_t w, int32_t h)
|
||||
#endif
|
||||
|
||||
// Temporary solution is to include the RP2040 optimised code here
|
||||
#if (defined(ARDUINO_ARCH_RP2040) || defined (ARDUINO_ARCH_MBED)) && !defined(TFT_PARALLEL_8_BIT)
|
||||
#if (defined(ARDUINO_ARCH_RP2040) || defined (ARDUINO_ARCH_MBED)) && !defined(RP2040_PIO_INTERFACE)
|
||||
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
|
||||
DC_C;
|
||||
spi_set_format(SPI_X, 8, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST);
|
||||
@ -3245,12 +3259,15 @@ void TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color)
|
||||
y+=rowstart;
|
||||
#endif
|
||||
|
||||
#if (defined (MULTI_TFT_SUPPORT) || defined (GC9A01_DRIVER)) && !defined (ILI9225_DRIVER)
|
||||
addr_row = 0xFFFF;
|
||||
addr_col = 0xFFFF;
|
||||
#endif
|
||||
|
||||
begin_tft_write();
|
||||
|
||||
#if defined (ILI9225_DRIVER)
|
||||
|
||||
if (rotation & 0x01) { swap_coord(x, y); }
|
||||
|
||||
SPI_BUSY_CHECK;
|
||||
|
||||
// Set window to full screen to optimise sequential pixel rendering
|
||||
@ -3281,122 +3298,120 @@ void TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color)
|
||||
DC_D; tft_Write_16N(color);
|
||||
#endif
|
||||
|
||||
// Temporary solution is to include the RP2040 optimised code here
|
||||
#elif (defined (ARDUINO_ARCH_RP2040) || defined (ARDUINO_ARCH_MBED)) && !defined(TFT_PARALLEL_8_BIT)
|
||||
// Temporary solution is to include the RP2040 optimised code here
|
||||
#elif (defined (ARDUINO_ARCH_RP2040) || defined (ARDUINO_ARCH_MBED)) && !defined (SSD1351_DRIVER)
|
||||
|
||||
// Since the SPI functions do not terminate until transmission is complete
|
||||
// a busy check is not needed.
|
||||
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
|
||||
DC_C;
|
||||
#if defined (RPI_DISPLAY_TYPE) // RPi TFT type always needs 16 bit transfers
|
||||
spi_set_format(SPI_X, 16, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST);
|
||||
#else
|
||||
spi_set_format(SPI_X, 8, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST);
|
||||
#if defined (SSD1963_DRIVER)
|
||||
if ((rotation & 0x1) == 0) { swap_coord(x, y); }
|
||||
#endif
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)TFT_CASET;
|
||||
|
||||
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS){};
|
||||
DC_D;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)x>>8;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)x;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)x>>8;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)x;
|
||||
|
||||
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
|
||||
DC_C;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)TFT_PASET;
|
||||
|
||||
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
|
||||
DC_D;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)y>>8;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)y;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)y>>8;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)y;
|
||||
|
||||
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
|
||||
DC_C;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)TFT_RAMWR;
|
||||
|
||||
#if defined (SPI_18BIT_DRIVER) // SPI 18 bit colour
|
||||
uint8_t r = (color & 0xF800)>>8;
|
||||
uint8_t g = (color & 0x07E0)>>3;
|
||||
uint8_t b = (color & 0x001F)<<3;
|
||||
#if !defined(RP2040_PIO_INTERFACE)
|
||||
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
|
||||
DC_D;
|
||||
tft_Write_8N(r); tft_Write_8N(g); tft_Write_8N(b);
|
||||
#else
|
||||
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
|
||||
DC_D;
|
||||
|
||||
#if defined (RPI_DISPLAY_TYPE) // RPi TFT type always needs 16 bit transfers
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)color;
|
||||
spi_set_format(SPI_X, 16, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST);
|
||||
#else
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)color>>8;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)color;
|
||||
spi_set_format(SPI_X, 8, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST);
|
||||
#endif
|
||||
|
||||
if (addr_col != x) {
|
||||
DC_C;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)TFT_CASET;
|
||||
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS){};
|
||||
DC_D;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)x>>8;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)x;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)x>>8;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)x;
|
||||
addr_col = x;
|
||||
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
|
||||
}
|
||||
|
||||
if (addr_row != y) {
|
||||
DC_C;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)TFT_PASET;
|
||||
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
|
||||
DC_D;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)y>>8;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)y;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)y>>8;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)y;
|
||||
addr_row = y;
|
||||
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
|
||||
}
|
||||
|
||||
DC_C;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)TFT_RAMWR;
|
||||
|
||||
#if defined (SPI_18BIT_DRIVER) // SPI 18 bit colour
|
||||
uint8_t r = (color & 0xF800)>>8;
|
||||
uint8_t g = (color & 0x07E0)>>3;
|
||||
uint8_t b = (color & 0x001F)<<3;
|
||||
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
|
||||
DC_D;
|
||||
tft_Write_8N(r); tft_Write_8N(g); tft_Write_8N(b);
|
||||
#else
|
||||
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
|
||||
DC_D;
|
||||
#if defined (RPI_DISPLAY_TYPE) // RPi TFT type always needs 16 bit transfers
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)color;
|
||||
#else
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)color>>8;
|
||||
spi_get_hw(SPI_X)->dr = (uint32_t)color;
|
||||
#endif
|
||||
#endif
|
||||
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
|
||||
#else
|
||||
// This is for the RP2040 and PIO interface (SPI or parallel)
|
||||
WAIT_FOR_STALL;
|
||||
pio->sm[pio_sm].instr = pio_instr_addr;
|
||||
TX_FIFO = TFT_CASET;
|
||||
TX_FIFO = (x<<16) | x;
|
||||
TX_FIFO = TFT_PASET;
|
||||
TX_FIFO = (y<<16) | y;
|
||||
TX_FIFO = TFT_RAMWR;
|
||||
//DC set high by PIO
|
||||
tft_Write_16((uint16_t)color);
|
||||
#endif
|
||||
/*
|
||||
// Subsequent pixel reads work OK without draining the FIFO...
|
||||
// Drain RX FIFO, then wait for shifting to finish (which may be *after*
|
||||
// TX FIFO drains), then drain RX FIFO again
|
||||
while (spi_is_readable(SPI_X))
|
||||
(void)spi_get_hw(SPI_X)->dr;
|
||||
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS)
|
||||
tight_loop_contents();
|
||||
while (spi_is_readable(SPI_X))
|
||||
(void)spi_get_hw(SPI_X)->dr;
|
||||
//*/
|
||||
|
||||
// Subsequent pixel reads work without this
|
||||
// spi_get_hw(SPI_X)->icr = SPI_SSPICR_RORIC_BITS;
|
||||
|
||||
while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {};
|
||||
|
||||
// Next call will start with 8 bit command so changing to 16 bit not needed here
|
||||
//spi_set_format(SPI_X, 16, (spi_cpol_t)0, (spi_cpha_t)0, SPI_MSB_FIRST);
|
||||
|
||||
#else
|
||||
|
||||
#if defined (SSD1351_DRIVER) || defined (SSD1963_DRIVER)
|
||||
if ((rotation & 0x1) == 0) { swap_coord(x, y); }
|
||||
#endif
|
||||
#if defined (SSD1351_DRIVER) || defined (SSD1963_DRIVER)
|
||||
if ((rotation & 0x1) == 0) { swap_coord(x, y); }
|
||||
#endif
|
||||
|
||||
SPI_BUSY_CHECK;
|
||||
SPI_BUSY_CHECK;
|
||||
|
||||
#if defined (MULTI_TFT_SUPPORT) || defined (GC9A01_DRIVER)
|
||||
// No optimisation
|
||||
DC_C; tft_Write_8(TFT_CASET);
|
||||
DC_D; tft_Write_32D(x);
|
||||
DC_C; tft_Write_8(TFT_PASET);
|
||||
DC_D; tft_Write_32D(y);
|
||||
#elif defined (SSD1351_DRIVER)
|
||||
// No need to send x if it has not changed (speeds things up)
|
||||
if (addr_col != x) {
|
||||
DC_C; tft_Write_8(TFT_CASET);
|
||||
DC_D; tft_Write_16(x | (x << 8));
|
||||
addr_col = x;
|
||||
}
|
||||
#if defined (SSD1351_DRIVER)
|
||||
// No need to send x if it has not changed (speeds things up)
|
||||
if (addr_col != x) {
|
||||
DC_C; tft_Write_8(TFT_CASET);
|
||||
DC_D; tft_Write_16(x | (x << 8));
|
||||
addr_col = x;
|
||||
}
|
||||
|
||||
// No need to send y if it has not changed (speeds things up)
|
||||
if (addr_row != y) {
|
||||
DC_C; tft_Write_8(TFT_PASET);
|
||||
DC_D; tft_Write_16(y | (y << 8));
|
||||
addr_row = y;
|
||||
}
|
||||
#else
|
||||
// No need to send x if it has not changed (speeds things up)
|
||||
if (addr_col != x) {
|
||||
DC_C; tft_Write_8(TFT_CASET);
|
||||
DC_D; tft_Write_32D(x);
|
||||
addr_col = x;
|
||||
}
|
||||
// No need to send y if it has not changed (speeds things up)
|
||||
if (addr_row != y) {
|
||||
DC_C; tft_Write_8(TFT_PASET);
|
||||
DC_D; tft_Write_16(y | (y << 8));
|
||||
addr_row = y;
|
||||
}
|
||||
#else
|
||||
// No need to send x if it has not changed (speeds things up)
|
||||
if (addr_col != x) {
|
||||
DC_C; tft_Write_8(TFT_CASET);
|
||||
DC_D; tft_Write_32D(x);
|
||||
addr_col = x;
|
||||
}
|
||||
|
||||
// No need to send y if it has not changed (speeds things up)
|
||||
if (addr_row != y) {
|
||||
DC_C; tft_Write_8(TFT_PASET);
|
||||
DC_D; tft_Write_32D(y);
|
||||
addr_row = y;
|
||||
}
|
||||
#endif
|
||||
|
||||
// No need to send y if it has not changed (speeds things up)
|
||||
if (addr_row != y) {
|
||||
DC_C; tft_Write_8(TFT_PASET);
|
||||
DC_D; tft_Write_32D(y);
|
||||
addr_row = y;
|
||||
}
|
||||
#endif
|
||||
DC_C; tft_Write_8(TFT_RAMWR);
|
||||
|
||||
#if defined(TFT_PARALLEL_8_BIT) || !defined(ESP32)
|
||||
@ -4828,7 +4843,7 @@ void TFT_eSPI::setTextFont(uint8_t f)
|
||||
** Function name: getSPIinstance
|
||||
** Description: Get the instance of the SPI class
|
||||
***************************************************************************************/
|
||||
#if !defined (TFT_PARALLEL_8_BIT)
|
||||
#if !defined (TFT_PARALLEL_8_BIT) && ! defined (RP2040_PIO_INTERFACE)
|
||||
SPIClass& TFT_eSPI::getSPIinstance(void)
|
||||
{
|
||||
return spi;
|
||||
|
@ -16,7 +16,7 @@
|
||||
#ifndef _TFT_eSPIH_
|
||||
#define _TFT_eSPIH_
|
||||
|
||||
#define TFT_ESPI_VERSION "2.4.2"
|
||||
#define TFT_ESPI_VERSION "2.4.21"
|
||||
|
||||
// Bit level feature flags
|
||||
// Bit 0 set: viewport capability
|
||||
@ -724,6 +724,9 @@ class TFT_eSPI : public Print { friend class TFT_eSprite; // Sprite class has ac
|
||||
inline void begin_tft_read() __attribute__((always_inline));
|
||||
inline void end_tft_read() __attribute__((always_inline));
|
||||
|
||||
// Initialise the data bus GPIO and hardware interfaces
|
||||
void initBus(void);
|
||||
|
||||
// Temporary library development function TODO: remove need for this
|
||||
void pushSwapBytePixels(const void* data_in, uint32_t len);
|
||||
|
||||
|
@ -313,6 +313,9 @@
|
||||
//
|
||||
// ##################################################################################
|
||||
|
||||
// For RP2040 processor and SPI displays, uncomment the following line to use the PIO interface.
|
||||
//#define RP2040_PIO_SPI // Leave commented out to use standard RP2040 SPI port interface
|
||||
|
||||
// For the RP2040 processor define the SPI port channel used (default 0 if undefined)
|
||||
//#define TFT_SPI_PORT 1 // Set to 0 if SPI0 pins are used, or 1 if spi1 pins used
|
||||
|
||||
|
@ -90,6 +90,7 @@
|
||||
//#include <User_Setups/Setup102_RP2040_ILI9341_parallel.h>
|
||||
//#include <User_Setups/Setup103_RP2040_ILI9486_parallel.h>
|
||||
//#include <User_Setups/Setup104_RP2040_ST7796_parallel.h>
|
||||
//#include <User_Setups/Setup105_RP2040_ILI9341_PIO_SPI.h> // Setup file for Raspberry Pi Pico with SPI PIO interface and ILI9341
|
||||
|
||||
//#include <User_Setups/Setup135_ST7789.h> // Setup file for ESP8266 and ST7789 135 x 240 TFT
|
||||
|
||||
|
@ -153,6 +153,7 @@ void printProcessorName(void)
|
||||
if ( user.esp == 0x8266) Serial.println("ESP8266");
|
||||
if ( user.esp == 0x32) Serial.println("ESP32");
|
||||
if ( user.esp == 0x32F) Serial.println("STM32");
|
||||
if ( user.esp == 0x2040) Serial.println("RP2040");
|
||||
if ( user.esp == 0x0000) Serial.println("Generic");
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "TFT_eSPI",
|
||||
"version": "2.4.2",
|
||||
"version": "2.4.21",
|
||||
"keywords": "Arduino, tft, ePaper, display, Pico, RP2040, STM32, ESP8266, NodeMCU, ESP32, M5Stack, ILI9341, ST7735, ILI9163, S6D02A1, ILI9481, ILI9486, ILI9488, ST7789, RM68140, SSD1351, SSD1963, ILI9225, HX8357D",
|
||||
"description": "A TFT and ePaper SPI graphics library with optimisation for Raspberry Pi Pico, ESP8266, ESP32 and STM32",
|
||||
"repository":
|
||||
|
@ -1,5 +1,5 @@
|
||||
name=TFT_eSPI
|
||||
version=2.4.2
|
||||
version=2.4.21
|
||||
author=Bodmer
|
||||
maintainer=Bodmer
|
||||
sentence=TFT graphics library for Arduino processors with performance optimisation for RP2040, STM32, ESP8266 and ESP32
|
||||
|
Reference in New Issue
Block a user