mirror of
https://github.com/Bodmer/TFT_eSPI.git
synced 2025-07-30 18:57:30 +02:00
Update RP2040 PIO and smooth graphics fns
This commit is contained in:
@ -191,6 +191,11 @@
|
|||||||
SPI1CMD |= SPIBUSY; \
|
SPI1CMD |= SPIBUSY; \
|
||||||
while(SPI1CMD & SPIBUSY) {;}
|
while(SPI1CMD & SPIBUSY) {;}
|
||||||
|
|
||||||
|
#define tft_Write_16N(C) \
|
||||||
|
SPI1U1 = (15 << SPILMOSI) | (15 << SPILMISO); \
|
||||||
|
SPI1W0 = ((C)<<8 | (C)>>8); \
|
||||||
|
SPI1CMD |= SPIBUSY
|
||||||
|
|
||||||
#define tft_Write_16S(C) \
|
#define tft_Write_16S(C) \
|
||||||
SPI1U1 = (15 << SPILMOSI) | (15 << SPILMISO); \
|
SPI1U1 = (15 << SPILMOSI) | (15 << SPILMISO); \
|
||||||
SPI1W0 = C; \
|
SPI1W0 = C; \
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Community RP2040 board package by Earle Philhower
|
// Community RP2040 board package by Earle Philhower
|
||||||
PIO pio = pio0; // Code will try both pio's to find a free SM
|
PIO tft_pio = pio0; // Code will try both pio's to find a free SM
|
||||||
int8_t pio_sm = 0; // pioinit will claim a free one
|
int8_t pio_sm = 0; // pioinit will claim a free one
|
||||||
// Updated later with the loading offset of the PIO program.
|
// Updated later with the loading offset of the PIO program.
|
||||||
uint32_t program_offset = 0;
|
uint32_t program_offset = 0;
|
||||||
@ -53,7 +53,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef RP2040_DMA
|
#ifdef RP2040_DMA
|
||||||
uint32_t dma_tx_channel;
|
int32_t dma_tx_channel;
|
||||||
dma_channel_config dma_tx_config;
|
dma_channel_config dma_tx_config;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -114,26 +114,41 @@ void TFT_eSPI::end_SDA_Read(void)
|
|||||||
void pioinit(uint32_t clock_freq) {
|
void pioinit(uint32_t clock_freq) {
|
||||||
|
|
||||||
// Find a free SM on one of the PIO's
|
// Find a free SM on one of the PIO's
|
||||||
pio = pio0;
|
tft_pio = pio0;
|
||||||
pio_sm = pio_claim_unused_sm(pio, false); // false means don't panic
|
|
||||||
|
/*
|
||||||
|
pio_sm = pio_claim_unused_sm(tft_pio, false); // false means don't panic
|
||||||
// Try pio1 if SM not found
|
// Try pio1 if SM not found
|
||||||
if (pio_sm < 0) {
|
if (pio_sm < 0) {
|
||||||
pio = pio1;
|
tft_pio = pio1;
|
||||||
pio_sm = pio_claim_unused_sm(pio, true); // panic this time if no SM is free
|
pio_sm = pio_claim_unused_sm(tft_pio, true); // panic this time if no SM is free
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Find enough free space on one of the PIO's
|
||||||
|
tft_pio = pio0;
|
||||||
|
if (!pio_can_add_program(tft_pio, &tft_io_program)) {
|
||||||
|
tft_pio = pio1;
|
||||||
|
if (!pio_can_add_program(tft_pio, &tft_io_program)) {
|
||||||
|
Serial.println("No room for PIO program!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pio_sm = pio_claim_unused_sm(tft_pio, false);
|
||||||
|
|
||||||
// Load the PIO program
|
// Load the PIO program
|
||||||
program_offset = pio_add_program(pio, &tft_io_program);
|
program_offset = pio_add_program(tft_pio, &tft_io_program);
|
||||||
|
|
||||||
// Associate pins with the PIO
|
// Associate pins with the PIO
|
||||||
pio_gpio_init(pio, TFT_DC);
|
pio_gpio_init(tft_pio, TFT_DC);
|
||||||
pio_gpio_init(pio, TFT_SCLK);
|
pio_gpio_init(tft_pio, TFT_SCLK);
|
||||||
pio_gpio_init(pio, TFT_MOSI);
|
pio_gpio_init(tft_pio, TFT_MOSI);
|
||||||
|
|
||||||
// Configure the pins to be outputs
|
// Configure the pins to be outputs
|
||||||
pio_sm_set_consecutive_pindirs(pio, pio_sm, TFT_DC, 1, true);
|
pio_sm_set_consecutive_pindirs(tft_pio, pio_sm, TFT_DC, 1, true);
|
||||||
pio_sm_set_consecutive_pindirs(pio, pio_sm, TFT_SCLK, 1, true);
|
pio_sm_set_consecutive_pindirs(tft_pio, pio_sm, TFT_SCLK, 1, true);
|
||||||
pio_sm_set_consecutive_pindirs(pio, pio_sm, TFT_MOSI, 1, true);
|
pio_sm_set_consecutive_pindirs(tft_pio, pio_sm, TFT_MOSI, 1, true);
|
||||||
|
|
||||||
// Configure the state machine
|
// Configure the state machine
|
||||||
pio_sm_config c = tft_io_program_get_default_config(program_offset);
|
pio_sm_config c = tft_io_program_get_default_config(program_offset);
|
||||||
@ -151,10 +166,10 @@ void pioinit(uint32_t clock_freq) {
|
|||||||
// The OSR register shifts to the left, sm designed to send MS byte of a colour first, autopull off
|
// 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);
|
sm_config_set_out_shift(&c, false, false, 0);
|
||||||
// Now load the configuration
|
// Now load the configuration
|
||||||
pio_sm_init(pio, pio_sm, program_offset + tft_io_offset_start_16, &c);
|
pio_sm_init(tft_pio, pio_sm, program_offset + tft_io_offset_start_16, &c);
|
||||||
|
|
||||||
// Start the state machine.
|
// Start the state machine.
|
||||||
pio_sm_set_enabled(pio, pio_sm, true);
|
pio_sm_set_enabled(tft_pio, pio_sm, true);
|
||||||
|
|
||||||
// Create the pull stall bit mask
|
// Create the pull stall bit mask
|
||||||
pull_stall_mask = 1u << (PIO_FDEBUG_TXSTALL_LSB + pio_sm);
|
pull_stall_mask = 1u << (PIO_FDEBUG_TXSTALL_LSB + pio_sm);
|
||||||
@ -171,28 +186,40 @@ void pioinit(uint32_t clock_freq) {
|
|||||||
void pioinit(uint16_t clock_div, uint16_t fract_div) {
|
void pioinit(uint16_t clock_div, uint16_t fract_div) {
|
||||||
|
|
||||||
// Find a free SM on one of the PIO's
|
// Find a free SM on one of the PIO's
|
||||||
pio = pio0;
|
tft_pio = pio0;
|
||||||
pio_sm = pio_claim_unused_sm(pio, false); // false means don't panic
|
pio_sm = pio_claim_unused_sm(tft_pio, false); // false means don't panic
|
||||||
// Try pio1 if SM not found
|
// Try pio1 if SM not found
|
||||||
if (pio_sm < 0) {
|
if (pio_sm < 0) {
|
||||||
pio = pio1;
|
tft_pio = pio1;
|
||||||
pio_sm = pio_claim_unused_sm(pio, true); // panic this time if no SM is free
|
pio_sm = pio_claim_unused_sm(tft_pio, true); // panic this time if no SM is free
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
// Find enough free space on one of the PIO's
|
||||||
|
tft_pio = pio0;
|
||||||
|
if (!pio_can_add_program(tft_pio, &tft_io_program) {
|
||||||
|
tft_pio = pio1;
|
||||||
|
if (!pio_can_add_program(tft_pio, &tft_io_program) {
|
||||||
|
Serial.println("No room for PIO program!");
|
||||||
|
while(1) delay(100);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// Load the PIO program
|
// Load the PIO program
|
||||||
program_offset = pio_add_program(pio, &tft_io_program);
|
program_offset = pio_add_program(tft_pio, &tft_io_program);
|
||||||
|
|
||||||
// Associate pins with the PIO
|
// Associate pins with the PIO
|
||||||
pio_gpio_init(pio, TFT_DC);
|
pio_gpio_init(tft_pio, TFT_DC);
|
||||||
pio_gpio_init(pio, TFT_WR);
|
pio_gpio_init(tft_pio, TFT_WR);
|
||||||
for (int i = 0; i < 8; i++) {
|
for (int i = 0; i < 8; i++) {
|
||||||
pio_gpio_init(pio, TFT_D0 + i);
|
pio_gpio_init(tft_pio, TFT_D0 + i);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure the pins to be outputs
|
// Configure the pins to be outputs
|
||||||
pio_sm_set_consecutive_pindirs(pio, pio_sm, TFT_DC, 1, true);
|
pio_sm_set_consecutive_pindirs(tft_pio, pio_sm, TFT_DC, 1, true);
|
||||||
pio_sm_set_consecutive_pindirs(pio, pio_sm, TFT_WR, 1, true);
|
pio_sm_set_consecutive_pindirs(tft_pio, pio_sm, TFT_WR, 1, true);
|
||||||
pio_sm_set_consecutive_pindirs(pio, pio_sm, TFT_D0, 8, true);
|
pio_sm_set_consecutive_pindirs(tft_pio, pio_sm, TFT_D0, 8, true);
|
||||||
|
|
||||||
// Configure the state machine
|
// Configure the state machine
|
||||||
pio_sm_config c = tft_io_program_get_default_config(program_offset);
|
pio_sm_config c = tft_io_program_get_default_config(program_offset);
|
||||||
@ -209,10 +236,10 @@ void pioinit(uint16_t clock_div, uint16_t fract_div) {
|
|||||||
// The OSR register shifts to the left, sm designed to send MS byte of a colour first
|
// 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);
|
sm_config_set_out_shift(&c, false, false, 0);
|
||||||
// Now load the configuration
|
// Now load the configuration
|
||||||
pio_sm_init(pio, pio_sm, program_offset + tft_io_offset_start_16, &c);
|
pio_sm_init(tft_pio, pio_sm, program_offset + tft_io_offset_start_16, &c);
|
||||||
|
|
||||||
// Start the state machine.
|
// Start the state machine.
|
||||||
pio_sm_set_enabled(pio, pio_sm, true);
|
pio_sm_set_enabled(tft_pio, pio_sm, true);
|
||||||
|
|
||||||
// Create the pull stall bit mask
|
// Create the pull stall bit mask
|
||||||
pull_stall_mask = 1u << (PIO_FDEBUG_TXSTALL_LSB + pio_sm);
|
pull_stall_mask = 1u << (PIO_FDEBUG_TXSTALL_LSB + pio_sm);
|
||||||
@ -238,7 +265,7 @@ void TFT_eSPI::pushBlock(uint16_t color, uint32_t len)
|
|||||||
{
|
{
|
||||||
if (len) {
|
if (len) {
|
||||||
WAIT_FOR_STALL;
|
WAIT_FOR_STALL;
|
||||||
pio->sm[pio_sm].instr = pio_instr_fill;
|
tft_pio->sm[pio_sm].instr = pio_instr_fill;
|
||||||
|
|
||||||
TX_FIFO = color;
|
TX_FIFO = color;
|
||||||
TX_FIFO = --len; // Decrement first as PIO sends n+1
|
TX_FIFO = --len; // Decrement first as PIO sends n+1
|
||||||
@ -564,7 +591,7 @@ void TFT_eSPI::pushPixelsDMA(uint16_t* image, uint32_t len)
|
|||||||
#if !defined (RP2040_PIO_INTERFACE)
|
#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);
|
dma_channel_configure(dma_tx_channel, &dma_tx_config, &spi_get_hw(SPI_X)->dr, (uint16_t*)image, len, true);
|
||||||
#else
|
#else
|
||||||
dma_channel_configure(dma_tx_channel, &dma_tx_config, &pio->txf[pio_sm], (uint16_t*)image, len, true);
|
dma_channel_configure(dma_tx_channel, &dma_tx_config, &tft_pio->txf[pio_sm], (uint16_t*)image, len, true);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -617,7 +644,7 @@ void TFT_eSPI::pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t
|
|||||||
#if !defined (RP2040_PIO_INTERFACE)
|
#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);
|
dma_channel_configure(dma_tx_channel, &dma_tx_config, &spi_get_hw(SPI_X)->dr, (uint16_t*)buffer, len, true);
|
||||||
#else
|
#else
|
||||||
dma_channel_configure(dma_tx_channel, &dma_tx_config, &pio->txf[pio_sm], (uint16_t*)buffer, len, true);
|
dma_channel_configure(dma_tx_channel, &dma_tx_config, &tft_pio->txf[pio_sm], (uint16_t*)buffer, len, true);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -631,14 +658,17 @@ bool TFT_eSPI::initDMA(bool ctrl_cs)
|
|||||||
|
|
||||||
ctrl_cs = ctrl_cs; // stop unused parameter warning
|
ctrl_cs = ctrl_cs; // stop unused parameter warning
|
||||||
|
|
||||||
dma_tx_channel = dma_claim_unused_channel(true);
|
dma_tx_channel = dma_claim_unused_channel(false);
|
||||||
|
|
||||||
|
if (dma_tx_channel < 0) return false;
|
||||||
|
|
||||||
dma_tx_config = dma_channel_get_default_config(dma_tx_channel);
|
dma_tx_config = dma_channel_get_default_config(dma_tx_channel);
|
||||||
|
|
||||||
channel_config_set_transfer_data_size(&dma_tx_config, DMA_SIZE_16);
|
channel_config_set_transfer_data_size(&dma_tx_config, DMA_SIZE_16);
|
||||||
#if !defined (RP2040_PIO_INTERFACE)
|
#if !defined (RP2040_PIO_INTERFACE)
|
||||||
channel_config_set_dreq(&dma_tx_config, spi_get_index(SPI_X) ? DREQ_SPI1_TX : DREQ_SPI0_TX);
|
channel_config_set_dreq(&dma_tx_config, spi_get_index(SPI_X) ? DREQ_SPI1_TX : DREQ_SPI0_TX);
|
||||||
#else
|
#else
|
||||||
channel_config_set_dreq(&dma_tx_config, pio_get_dreq(pio, pio_sm, true));
|
channel_config_set_dreq(&dma_tx_config, pio_get_dreq(tft_pio, pio_sm, true));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
DMA_Enabled = true;
|
DMA_Enabled = true;
|
||||||
|
@ -101,7 +101,7 @@
|
|||||||
|
|
||||||
|
|
||||||
// If smooth fonts are enabled the filing system may need to be loaded
|
// If smooth fonts are enabled the filing system may need to be loaded
|
||||||
#ifdef SMOOTH_FONT
|
#if defined (SMOOTH_FONT) && !defined (ARDUINO_ARCH_MBED)
|
||||||
// Call up the filing system for the anti-aliased fonts
|
// Call up the filing system for the anti-aliased fonts
|
||||||
//#define FS_NO_GLOBALS
|
//#define FS_NO_GLOBALS
|
||||||
#include <FS.h>
|
#include <FS.h>
|
||||||
@ -128,10 +128,10 @@
|
|||||||
// PIO takes control of TFT_DC
|
// PIO takes control of TFT_DC
|
||||||
// Must wait for data to flush through before changing DC line
|
// Must wait for data to flush through before changing DC line
|
||||||
#define DC_C WAIT_FOR_STALL; \
|
#define DC_C WAIT_FOR_STALL; \
|
||||||
pio->sm[pio_sm].instr = pio_instr_clr_dc
|
tft_pio->sm[pio_sm].instr = pio_instr_clr_dc
|
||||||
|
|
||||||
// Flush has happened before this and mode changed back to 16 bit
|
// Flush has happened before this and mode changed back to 16 bit
|
||||||
#define DC_D pio->sm[pio_sm].instr = pio_instr_set_dc
|
#define DC_D tft_pio->sm[pio_sm].instr = pio_instr_set_dc
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -315,22 +315,22 @@
|
|||||||
|
|
||||||
// Wait for the PIO to stall (SM pull request finds no data in TX FIFO)
|
// 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
|
// 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))
|
#define WAIT_FOR_STALL tft_pio->fdebug = pull_stall_mask; while (!(tft_pio->fdebug & pull_stall_mask))
|
||||||
|
|
||||||
// Wait until at least "S" locations free
|
// Wait until at least "S" locations free
|
||||||
#define WAIT_FOR_FIFO_FREE(S) while (((pio->flevel >> (pio_sm * 8)) & 0x000F) > (8-S)){}
|
#define WAIT_FOR_FIFO_FREE(S) while (((tft_pio->flevel >> (pio_sm * 8)) & 0x000F) > (8-S)){}
|
||||||
|
|
||||||
// Wait until at least 5 locations free
|
// Wait until at least 5 locations free
|
||||||
#define WAIT_FOR_FIFO_5_FREE while ((pio->flevel) & (0x000c << (pio_sm * 8))){}
|
#define WAIT_FOR_FIFO_5_FREE while ((tft_pio->flevel) & (0x000c << (pio_sm * 8))){}
|
||||||
|
|
||||||
// Wait until at least 1 location free
|
// Wait until at least 1 location free
|
||||||
#define WAIT_FOR_FIFO_1_FREE while ((pio->flevel) & (0x0008 << (pio_sm * 8))){}
|
#define WAIT_FOR_FIFO_1_FREE while ((tft_pio->flevel) & (0x0008 << (pio_sm * 8))){}
|
||||||
|
|
||||||
// Wait for FIFO to empty (use before swapping to 8 bits)
|
// Wait for FIFO to empty (use before swapping to 8 bits)
|
||||||
#define WAIT_FOR_FIFO_EMPTY while(!(pio->fstat & (1u << (PIO_FSTAT_TXEMPTY_LSB + pio_sm))))
|
#define WAIT_FOR_FIFO_EMPTY while(!(tft_pio->fstat & (1u << (PIO_FSTAT_TXEMPTY_LSB + pio_sm))))
|
||||||
|
|
||||||
// The write register of the TX FIFO.
|
// The write register of the TX FIFO.
|
||||||
#define TX_FIFO pio->txf[pio_sm]
|
#define TX_FIFO tft_pio->txf[pio_sm]
|
||||||
|
|
||||||
// Temporary - to be deleted
|
// Temporary - to be deleted
|
||||||
#define dir_mask 0
|
#define dir_mask 0
|
||||||
@ -339,7 +339,7 @@
|
|||||||
// This writes 8 bits, then switches back to 16 bit mode automatically
|
// This writes 8 bits, then switches back to 16 bit mode automatically
|
||||||
// Have already waited for pio stalled (last data write complete) when DC switched to command mode
|
// 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
|
// The wait for stall allows DC to be changed immediately afterwards
|
||||||
#define tft_Write_8(C) pio->sm[pio_sm].instr = pio_instr_jmp8; \
|
#define tft_Write_8(C) tft_pio->sm[pio_sm].instr = pio_instr_jmp8; \
|
||||||
TX_FIFO = (C); \
|
TX_FIFO = (C); \
|
||||||
WAIT_FOR_STALL
|
WAIT_FOR_STALL
|
||||||
|
|
||||||
|
@ -15,16 +15,11 @@
|
|||||||
// 8 bit transfer
|
// 8 bit transfer
|
||||||
public start_8:
|
public start_8:
|
||||||
// Pull the next 32 bit value from the TX FIFO.
|
// Pull the next 32 bit value from the TX FIFO.
|
||||||
// Lose the top 24 bits
|
|
||||||
pull side 0
|
pull side 0
|
||||||
|
// Lose the top 24 bits
|
||||||
out null, 24
|
out null, 24
|
||||||
spi_out_8:
|
// Now send remaining bits
|
||||||
// Output the next 8 bits
|
jmp spi_out side 0
|
||||||
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:
|
public set_addr_window:
|
||||||
// Loop count in x for caset, paset and ramwr
|
// Loop count in x for caset, paset and ramwr
|
||||||
@ -34,7 +29,8 @@ pull_cmd:
|
|||||||
set pins, 0
|
set pins, 0
|
||||||
// Fetch and output LS byte (caset, paset or ramwr), discarding top 24 bits, set WR low
|
// Fetch and output LS byte (caset, paset or ramwr), discarding top 24 bits, set WR low
|
||||||
pull side 0
|
pull side 0
|
||||||
out null, 24
|
out pins, 25
|
||||||
|
nop side 1
|
||||||
next_cmd_bit:
|
next_cmd_bit:
|
||||||
out pins, 1 side 0
|
out pins, 1 side 0
|
||||||
jmp !osre, next_cmd_bit side 1
|
jmp !osre, next_cmd_bit side 1
|
||||||
@ -79,13 +75,15 @@ next_bit:
|
|||||||
.wrap_target
|
.wrap_target
|
||||||
public start_16:
|
public start_16:
|
||||||
// Pull the next 32 bit value from the TX FIFO.
|
// Pull the next 32 bit value from the TX FIFO.
|
||||||
// Write the top 16 bits
|
// Send the bottom 16 bits
|
||||||
pull side 0
|
pull side 0
|
||||||
out null, 16
|
// Drop the first 16 bits, write first bit
|
||||||
spi_out_16:
|
out pins, 17 side 0
|
||||||
// Output the next 16 bits
|
nop side 1
|
||||||
|
spi_out:
|
||||||
|
// Output the next 15 bits
|
||||||
out pins, 1 side 0
|
out pins, 1 side 0
|
||||||
// Set TFT_SCLK high and jump for next bit
|
// Set TFT_SCLK high and jump for next bit
|
||||||
jmp !osre, spi_out_16 side 1
|
jmp !osre, spi_out side 1
|
||||||
// Return to start
|
// Return to start
|
||||||
.wrap
|
.wrap
|
||||||
|
@ -12,46 +12,46 @@
|
|||||||
// tft_io //
|
// tft_io //
|
||||||
// ------ //
|
// ------ //
|
||||||
|
|
||||||
#define tft_io_wrap_target 28
|
#define tft_io_wrap_target 27
|
||||||
#define tft_io_wrap 31
|
#define tft_io_wrap 31
|
||||||
|
|
||||||
#define tft_io_offset_start_8 0u
|
#define tft_io_offset_start_8 0u
|
||||||
#define tft_io_offset_set_addr_window 5u
|
#define tft_io_offset_set_addr_window 3u
|
||||||
#define tft_io_offset_block_fill 18u
|
#define tft_io_offset_block_fill 17u
|
||||||
#define tft_io_offset_start_16 28u
|
#define tft_io_offset_start_16 27u
|
||||||
|
|
||||||
static const uint16_t tft_io_program_instructions[] = {
|
static const uint16_t tft_io_program_instructions[] = {
|
||||||
0x90a0, // 0: pull block side 0
|
0x90a0, // 0: pull block side 0
|
||||||
0x6078, // 1: out null, 24
|
0x6078, // 1: out null, 24
|
||||||
0x7001, // 2: out pins, 1 side 0
|
0x101e, // 2: jmp 30 side 0
|
||||||
0x18e2, // 3: jmp !osre, 2 side 1
|
0xf022, // 3: set x, 2 side 0
|
||||||
0x101c, // 4: jmp 28 side 0
|
0xe000, // 4: set pins, 0
|
||||||
0xf022, // 5: set x, 2 side 0
|
0x90a0, // 5: pull block side 0
|
||||||
0xe000, // 6: set pins, 0
|
0x6019, // 6: out pins, 25
|
||||||
0x90a0, // 7: pull block side 0
|
0xb842, // 7: nop side 1
|
||||||
0x6078, // 8: out null, 24
|
0x7001, // 8: out pins, 1 side 0
|
||||||
0x7001, // 9: out pins, 1 side 0
|
0x18e8, // 9: jmp !osre, 8 side 1
|
||||||
0x18e9, // 10: jmp !osre, 9 side 1
|
0xf001, // 10: set pins, 1 side 0
|
||||||
0xf001, // 11: set pins, 1 side 0
|
0x003b, // 11: jmp !x, 27
|
||||||
0x003c, // 12: jmp !x, 28
|
0x80a0, // 12: pull block
|
||||||
0x80a0, // 13: pull block
|
0x7001, // 13: out pins, 1 side 0
|
||||||
0x7001, // 14: out pins, 1 side 0
|
0x18ed, // 14: jmp !osre, 13 side 1
|
||||||
0x18ee, // 15: jmp !osre, 14 side 1
|
0x1044, // 15: jmp x--, 4 side 0
|
||||||
0x1046, // 16: jmp x--, 6 side 0
|
0x001b, // 16: jmp 27
|
||||||
0x001c, // 17: jmp 28
|
0x90a0, // 17: pull block side 0
|
||||||
0x90a0, // 18: pull block side 0
|
0xa027, // 18: mov x, osr
|
||||||
0xa027, // 19: mov x, osr
|
0x80a0, // 19: pull block
|
||||||
0x80a0, // 20: pull block
|
0xa047, // 20: mov y, osr
|
||||||
0xa047, // 21: mov y, osr
|
0xb0e1, // 21: mov osr, x side 0
|
||||||
0xb0e1, // 22: mov osr, x side 0
|
0x7011, // 22: out pins, 17 side 0
|
||||||
0x7011, // 23: out pins, 17 side 0
|
0xb842, // 23: nop side 1
|
||||||
0xb842, // 24: nop side 1
|
0x7001, // 24: out pins, 1 side 0
|
||||||
0x7001, // 25: out pins, 1 side 0
|
0x18f8, // 25: jmp !osre, 24 side 1
|
||||||
0x18f9, // 26: jmp !osre, 25 side 1
|
0x1095, // 26: jmp y--, 21 side 0
|
||||||
0x1096, // 27: jmp y--, 22 side 0
|
|
||||||
// .wrap_target
|
// .wrap_target
|
||||||
0x90a0, // 28: pull block side 0
|
0x90a0, // 27: pull block side 0
|
||||||
0x6070, // 29: out null, 16
|
0x7011, // 28: out pins, 17 side 0
|
||||||
|
0xb842, // 29: nop side 1
|
||||||
0x7001, // 30: out pins, 1 side 0
|
0x7001, // 30: out pins, 1 side 0
|
||||||
0x18fe, // 31: jmp !osre, 30 side 1
|
0x18fe, // 31: jmp !osre, 30 side 1
|
||||||
// .wrap
|
// .wrap
|
||||||
|
92
TFT_eSPI.cpp
92
TFT_eSPI.cpp
@ -3214,7 +3214,7 @@ void TFT_eSPI::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1)
|
|||||||
#else
|
#else
|
||||||
// This is for the RP2040 and PIO interface (SPI or parallel)
|
// This is for the RP2040 and PIO interface (SPI or parallel)
|
||||||
WAIT_FOR_STALL;
|
WAIT_FOR_STALL;
|
||||||
pio->sm[pio_sm].instr = pio_instr_addr;
|
tft_pio->sm[pio_sm].instr = pio_instr_addr;
|
||||||
|
|
||||||
TX_FIFO = TFT_CASET;
|
TX_FIFO = TFT_CASET;
|
||||||
TX_FIFO = (x0<<16) | x1;
|
TX_FIFO = (x0<<16) | x1;
|
||||||
@ -3441,14 +3441,15 @@ void TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color)
|
|||||||
#else
|
#else
|
||||||
// This is for the RP2040 and PIO interface (SPI or parallel)
|
// This is for the RP2040 and PIO interface (SPI or parallel)
|
||||||
WAIT_FOR_STALL;
|
WAIT_FOR_STALL;
|
||||||
pio->sm[pio_sm].instr = pio_instr_addr;
|
tft_pio->sm[pio_sm].instr = pio_instr_addr;
|
||||||
TX_FIFO = TFT_CASET;
|
TX_FIFO = TFT_CASET;
|
||||||
TX_FIFO = (x<<16) | x;
|
TX_FIFO = (x<<16) | x;
|
||||||
TX_FIFO = TFT_PASET;
|
TX_FIFO = TFT_PASET;
|
||||||
TX_FIFO = (y<<16) | y;
|
TX_FIFO = (y<<16) | y;
|
||||||
TX_FIFO = TFT_RAMWR;
|
TX_FIFO = TFT_RAMWR;
|
||||||
//DC set high by PIO
|
//DC set high by PIO
|
||||||
tft_Write_16((uint16_t)color);
|
TX_FIFO = color;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#else
|
#else
|
||||||
@ -3667,7 +3668,7 @@ void TFT_eSPI::drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t
|
|||||||
** Description: Constants for anti-aliased line drawing on TFT and in Sprites
|
** Description: Constants for anti-aliased line drawing on TFT and in Sprites
|
||||||
***************************************************************************************/
|
***************************************************************************************/
|
||||||
constexpr float PixelAlphaGain = 255.0;
|
constexpr float PixelAlphaGain = 255.0;
|
||||||
constexpr float LoAlphaTheshold = 1.0/31.0;
|
constexpr float LoAlphaTheshold = 1.0/32.0;
|
||||||
constexpr float HiAlphaTheshold = 1.0 - LoAlphaTheshold;
|
constexpr float HiAlphaTheshold = 1.0 - LoAlphaTheshold;
|
||||||
|
|
||||||
/***************************************************************************************
|
/***************************************************************************************
|
||||||
@ -3677,9 +3678,9 @@ constexpr float HiAlphaTheshold = 1.0 - LoAlphaTheshold;
|
|||||||
uint16_t TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color, uint8_t alpha, uint32_t bg_color)
|
uint16_t TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color, uint8_t alpha, uint32_t bg_color)
|
||||||
{
|
{
|
||||||
if (bg_color == 0x00FFFFFF) bg_color = readPixel(x, y);
|
if (bg_color == 0x00FFFFFF) bg_color = readPixel(x, y);
|
||||||
bg_color = alphaBlend(alpha, color, bg_color);
|
color = alphaBlend(alpha, color, bg_color);
|
||||||
drawPixel(x, y, bg_color);
|
drawPixel(x, y, color);
|
||||||
return bg_color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************************************************************************
|
/***************************************************************************************
|
||||||
@ -3688,27 +3689,45 @@ uint16_t TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color, uint8_t alpha
|
|||||||
***************************************************************************************/
|
***************************************************************************************/
|
||||||
void TFT_eSPI::fillSmoothCircle(int32_t x, int32_t y, int32_t r, uint32_t color, uint32_t bg_color)
|
void TFT_eSPI::fillSmoothCircle(int32_t x, int32_t y, int32_t r, uint32_t color, uint32_t bg_color)
|
||||||
{
|
{
|
||||||
|
if (r <= 0) return;
|
||||||
|
|
||||||
inTransaction = true;
|
inTransaction = true;
|
||||||
int16_t xs = 0;
|
|
||||||
int16_t cx;
|
drawFastHLine(x - r, y, 2 * r + 1, color);
|
||||||
|
int32_t xs = 1;
|
||||||
|
int32_t cx = 0;
|
||||||
|
|
||||||
|
int32_t r1 = r * r;
|
||||||
r++;
|
r++;
|
||||||
for (int16_t cy = r; cy > 0; cy--)
|
int32_t r2 = r * r;
|
||||||
|
|
||||||
|
for (int32_t cy = r - 1; cy > 0; cy--)
|
||||||
{
|
{
|
||||||
for (cx = xs; cx <= xs + 1 && cx < r; cx++)
|
int32_t dy2 = (r - cy) * (r - cy);
|
||||||
|
for (cx = xs; cx < r; cx++)
|
||||||
{
|
{
|
||||||
float deltaX = r - cx;
|
int32_t hyp2 = (r - cx) * (r - cx) + dy2;
|
||||||
float deltaY = r - cy;
|
if (hyp2 <= r1) break;
|
||||||
float alphaf = r - sqrtf(deltaX * deltaX + deltaY * deltaY);
|
if (hyp2 >= r2) continue;
|
||||||
if (alphaf > 1.0) continue;
|
float alphaf = (float)r - sqrtf(hyp2);
|
||||||
|
if (alphaf > HiAlphaTheshold) break;
|
||||||
xs = cx;
|
xs = cx;
|
||||||
if (alphaf < LoAlphaTheshold) continue;
|
if (alphaf < LoAlphaTheshold) continue;
|
||||||
uint8_t alpha = alphaf * 255;
|
uint8_t alpha = alphaf * 255;
|
||||||
drawPixel(x + cx - r, y + cy - r, color, alpha, bg_color);
|
|
||||||
drawPixel(x - cx + r, y + cy - r, color, alpha, bg_color);
|
if (bg_color == 0x00FFFFFF) {
|
||||||
drawPixel(x - cx + r, y - cy + r, color, alpha, bg_color);
|
drawPixel(x + cx - r, y + cy - r, color, alpha, bg_color);
|
||||||
drawPixel(x + cx - r, y - cy + r, color, alpha, bg_color);
|
drawPixel(x - cx + r, y + cy - r, color, alpha, bg_color);
|
||||||
|
drawPixel(x - cx + r, y - cy + r, color, alpha, bg_color);
|
||||||
|
drawPixel(x + cx - r, y - cy + r, color, alpha, bg_color);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
uint16_t pcol = drawPixel(x + cx - r, y + cy - r, color, alpha, bg_color);
|
||||||
|
drawPixel(x - cx + r, y + cy - r, pcol);
|
||||||
|
drawPixel(x - cx + r, y - cy + r, pcol);
|
||||||
|
drawPixel(x + cx - r, y - cy + r, pcol);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
cx--;
|
|
||||||
drawFastHLine(x + cx - r, y + cy - r, 2 * (r - cx) + 1, color);
|
drawFastHLine(x + cx - r, y + cy - r, 2 * (r - cx) + 1, color);
|
||||||
drawFastHLine(x + cx - r, y - cy + r, 2 * (r - cx) + 1, color);
|
drawFastHLine(x + cx - r, y - cy + r, 2 * (r - cx) + 1, color);
|
||||||
}
|
}
|
||||||
@ -3716,40 +3735,45 @@ void TFT_eSPI::fillSmoothCircle(int32_t x, int32_t y, int32_t r, uint32_t color,
|
|||||||
end_tft_write();
|
end_tft_write();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************************************
|
/***************************************************************************************
|
||||||
** Function name: fillSmoothCircle
|
** Function name: fillSmoothRoundRect
|
||||||
** Description: Draw a filled anti-aliased circle
|
** Description: Draw a filled anti-aliased rounded corner rectangle
|
||||||
***************************************************************************************/
|
***************************************************************************************/
|
||||||
void TFT_eSPI::fillSmoothRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t r, uint32_t color, uint32_t bg_color)
|
void TFT_eSPI::fillSmoothRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t r, uint32_t color, uint32_t bg_color)
|
||||||
{
|
{
|
||||||
inTransaction = true;
|
inTransaction = true;
|
||||||
int16_t xs = 0;
|
int32_t xs = 0;
|
||||||
int16_t cx;
|
int32_t cx = 0;
|
||||||
|
|
||||||
y += r;
|
y += r;
|
||||||
h -= 2*r;
|
h -= 2*r;
|
||||||
fillRect(x, y, w, h, color);
|
fillRect(x, y, w, h + 1, color);
|
||||||
x += r;
|
x += r;
|
||||||
w -= 2*r+1;
|
w -= 2*r+1;
|
||||||
|
int32_t r1 = r * r;
|
||||||
r++;
|
r++;
|
||||||
|
int32_t r2 = r * r;
|
||||||
|
|
||||||
for (int16_t cy = r; cy > 0; cy--)
|
for (int32_t cy = r - 1; cy > 0; cy--)
|
||||||
{
|
{
|
||||||
for (cx = xs; cx <= xs + 1 && cx < r; cx++)
|
int32_t dy2 = (r - cy) * (r - cy);
|
||||||
|
for (cx = xs; cx < r; cx++)
|
||||||
{
|
{
|
||||||
float deltaX = r - cx;
|
int32_t hyp2 = (r - cx) * (r - cx) + dy2;
|
||||||
float deltaY = r - cy;
|
if (hyp2 <= r1) break;
|
||||||
float weight = r - sqrtf(deltaX * deltaX + deltaY * deltaY);
|
if (hyp2 >= r2) continue;
|
||||||
if (weight > 1.0) continue;
|
float alphaf = (float)r - sqrtf(hyp2);
|
||||||
|
if (alphaf > HiAlphaTheshold) break;
|
||||||
xs = cx;
|
xs = cx;
|
||||||
if (weight < LoAlphaTheshold) continue;
|
if (alphaf < LoAlphaTheshold) continue;
|
||||||
uint8_t alpha = weight * 255;
|
uint8_t alpha = alphaf * 255;
|
||||||
|
|
||||||
drawPixel(x + cx - r, y + cy - r, color, alpha, bg_color);
|
drawPixel(x + cx - r, y + cy - r, color, alpha, bg_color);
|
||||||
drawPixel(x - cx + r + w, y + cy - r, color, alpha, bg_color);
|
drawPixel(x - cx + r + w, y + cy - r, color, alpha, bg_color);
|
||||||
drawPixel(x - cx + r + w, y - cy + r + h, color, alpha, bg_color);
|
drawPixel(x - cx + r + w, y - cy + r + h, color, alpha, bg_color);
|
||||||
drawPixel(x + cx - r, y - cy + r + h, color, alpha, bg_color);
|
drawPixel(x + cx - r, y - cy + r + h, color, alpha, bg_color);
|
||||||
}
|
}
|
||||||
cx--;
|
|
||||||
drawFastHLine(x + cx - r, y + cy - r, 2 * (r - cx) + 1 + w, color);
|
drawFastHLine(x + cx - r, y + cy - r, 2 * (r - cx) + 1 + w, color);
|
||||||
drawFastHLine(x + cx - r, y - cy + r + h, 2 * (r - cx) + 1 + w, color);
|
drawFastHLine(x + cx - r, y - cy + r + h, 2 * (r - cx) + 1 + w, color);
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
#ifndef _TFT_eSPIH_
|
#ifndef _TFT_eSPIH_
|
||||||
#define _TFT_eSPIH_
|
#define _TFT_eSPIH_
|
||||||
|
|
||||||
#define TFT_ESPI_VERSION "2.4.40"
|
#define TFT_ESPI_VERSION "2.4.41"
|
||||||
|
|
||||||
// Bit level feature flags
|
// Bit level feature flags
|
||||||
// Bit 0 set: viewport capability
|
// Bit 0 set: viewport capability
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "TFT_eSPI",
|
"name": "TFT_eSPI",
|
||||||
"version": "2.4.40",
|
"version": "2.4.41",
|
||||||
"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",
|
"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",
|
"description": "A TFT and ePaper SPI graphics library with optimisation for Raspberry Pi Pico, ESP8266, ESP32 and STM32",
|
||||||
"repository":
|
"repository":
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
name=TFT_eSPI
|
name=TFT_eSPI
|
||||||
version=2.4.40
|
version=2.4.41
|
||||||
author=Bodmer
|
author=Bodmer
|
||||||
maintainer=Bodmer
|
maintainer=Bodmer
|
||||||
sentence=TFT graphics library for Arduino processors with performance optimisation for RP2040, STM32, ESP8266 and ESP32
|
sentence=TFT graphics library for Arduino processors with performance optimisation for RP2040, STM32, ESP8266 and ESP32
|
||||||
|
Reference in New Issue
Block a user