Commit 284893c3 authored by Bodmer's avatar Bodmer

Update RP2040 PIO and smooth graphics fns

parent d1e6637b
...@@ -191,6 +191,11 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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) ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) ...@@ -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) ...@@ -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 ...@@ -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) ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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: ...@@ -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: ...@@ -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 @@ ...@@ -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
......
...@@ -3214,7 +3214,7 @@ void TFT_eSPI::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1) ...@@ -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) ...@@ -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 ...@@ -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; ...@@ -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 ...@@ -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, ...@@ -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 @@ ...@@ -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
......
{ {
"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":
......
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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment