Update RP2040 PIO and smooth graphics fns

This commit is contained in:
Bodmer 2022-02-22 21:12:33 +00:00
parent d1e6637b88
commit 284893c374
9 changed files with 183 additions and 126 deletions

View File

@ -191,6 +191,11 @@
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) \
SPI1U1 = (15 << SPILMOSI) | (15 << SPILMISO); \
SPI1W0 = C; \

View File

@ -33,7 +33,7 @@
#endif
// 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
// Updated later with the loading offset of the PIO program.
uint32_t program_offset = 0;
@ -53,7 +53,7 @@
#endif
#ifdef RP2040_DMA
uint32_t dma_tx_channel;
int32_t dma_tx_channel;
dma_channel_config dma_tx_config;
#endif
@ -114,26 +114,41 @@ void TFT_eSPI::end_SDA_Read(void)
void pioinit(uint32_t clock_freq) {
// 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
tft_pio = pio0;
/*
pio_sm = pio_claim_unused_sm(tft_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
tft_pio = pio1;
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
program_offset = pio_add_program(pio, &tft_io_program);
program_offset = pio_add_program(tft_pio, &tft_io_program);
// Associate pins with the PIO
pio_gpio_init(pio, TFT_DC);
pio_gpio_init(pio, TFT_SCLK);
pio_gpio_init(pio, TFT_MOSI);
pio_gpio_init(tft_pio, TFT_DC);
pio_gpio_init(tft_pio, TFT_SCLK);
pio_gpio_init(tft_pio, TFT_MOSI);
// 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_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_DC, 1, true);
pio_sm_set_consecutive_pindirs(tft_pio, pio_sm, TFT_SCLK, 1, true);
pio_sm_set_consecutive_pindirs(tft_pio, pio_sm, TFT_MOSI, 1, true);
// Configure the state machine
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
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);
pio_sm_init(tft_pio, pio_sm, program_offset + tft_io_offset_start_16, &c);
// 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
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) {
// 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
tft_pio = pio0;
pio_sm = pio_claim_unused_sm(tft_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
tft_pio = pio1;
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
program_offset = pio_add_program(pio, &tft_io_program);
program_offset = pio_add_program(tft_pio, &tft_io_program);
// Associate pins with the PIO
pio_gpio_init(pio, TFT_DC);
pio_gpio_init(pio, TFT_WR);
pio_gpio_init(tft_pio, TFT_DC);
pio_gpio_init(tft_pio, TFT_WR);
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
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);
pio_sm_set_consecutive_pindirs(tft_pio, pio_sm, TFT_DC, 1, true);
pio_sm_set_consecutive_pindirs(tft_pio, pio_sm, TFT_WR, 1, true);
pio_sm_set_consecutive_pindirs(tft_pio, pio_sm, TFT_D0, 8, true);
// Configure the state machine
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
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);
pio_sm_init(tft_pio, pio_sm, program_offset + tft_io_offset_start_16, &c);
// 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
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) {
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 = --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)
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);
dma_channel_configure(dma_tx_channel, &dma_tx_config, &tft_pio->txf[pio_sm], (uint16_t*)image, len, true);
#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)
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);
dma_channel_configure(dma_tx_channel, &dma_tx_config, &tft_pio->txf[pio_sm], (uint16_t*)buffer, len, true);
#endif
}
@ -631,14 +658,17 @@ bool TFT_eSPI::initDMA(bool ctrl_cs)
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);
channel_config_set_transfer_data_size(&dma_tx_config, DMA_SIZE_16);
#if !defined (RP2040_PIO_INTERFACE)
channel_config_set_dreq(&dma_tx_config, spi_get_index(SPI_X) ? DREQ_SPI1_TX : DREQ_SPI0_TX);
#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
DMA_Enabled = true;

View File

@ -101,7 +101,7 @@
// 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
//#define FS_NO_GLOBALS
#include <FS.h>
@ -128,10 +128,10 @@
// PIO takes control of TFT_DC
// Must wait for data to flush through before changing DC line
#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
#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
@ -315,22 +315,22 @@
// 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))
#define WAIT_FOR_STALL tft_pio->fdebug = pull_stall_mask; while (!(tft_pio->fdebug & pull_stall_mask))
// 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
#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
#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)
#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.
#define TX_FIFO pio->txf[pio_sm]
#define TX_FIFO tft_pio->txf[pio_sm]
// Temporary - to be deleted
#define dir_mask 0
@ -339,7 +339,7 @@
// 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
// 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); \
WAIT_FOR_STALL

View File

@ -15,16 +15,11 @@
// 8 bit transfer
public start_8:
// Pull the next 32 bit value from the TX FIFO.
// Lose the top 24 bits
pull side 0
// Lose the top 24 bits
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
// Now send remaining bits
jmp spi_out side 0
public set_addr_window:
// Loop count in x for caset, paset and ramwr
@ -34,7 +29,8 @@ pull_cmd:
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
out pins, 25
nop side 1
next_cmd_bit:
out pins, 1 side 0
jmp !osre, next_cmd_bit side 1
@ -79,13 +75,15 @@ next_bit:
.wrap_target
public start_16:
// Pull the next 32 bit value from the TX FIFO.
// Write the top 16 bits
// Send the bottom 16 bits
pull side 0
out null, 16
spi_out_16:
// Output the next 16 bits
// Drop the first 16 bits, write first bit
out pins, 17 side 0
nop side 1
spi_out:
// Output the next 15 bits
out pins, 1 side 0
// 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
.wrap

View File

@ -12,46 +12,46 @@
// tft_io //
// ------ //
#define tft_io_wrap_target 28
#define tft_io_wrap_target 27
#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
#define tft_io_offset_set_addr_window 3u
#define tft_io_offset_block_fill 17u
#define tft_io_offset_start_16 27u
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
0x101e, // 2: jmp 30 side 0
0xf022, // 3: set x, 2 side 0
0xe000, // 4: set pins, 0
0x90a0, // 5: pull block side 0
0x6019, // 6: out pins, 25
0xb842, // 7: nop side 1
0x7001, // 8: out pins, 1 side 0
0x18e8, // 9: jmp !osre, 8 side 1
0xf001, // 10: set pins, 1 side 0
0x003b, // 11: jmp !x, 27
0x80a0, // 12: pull block
0x7001, // 13: out pins, 1 side 0
0x18ed, // 14: jmp !osre, 13 side 1
0x1044, // 15: jmp x--, 4 side 0
0x001b, // 16: jmp 27
0x90a0, // 17: pull block side 0
0xa027, // 18: mov x, osr
0x80a0, // 19: pull block
0xa047, // 20: mov y, osr
0xb0e1, // 21: mov osr, x side 0
0x7011, // 22: out pins, 17 side 0
0xb842, // 23: nop side 1
0x7001, // 24: out pins, 1 side 0
0x18f8, // 25: jmp !osre, 24 side 1
0x1095, // 26: jmp y--, 21 side 0
// .wrap_target
0x90a0, // 28: pull block side 0
0x6070, // 29: out null, 16
0x90a0, // 27: pull block side 0
0x7011, // 28: out pins, 17 side 0
0xb842, // 29: nop side 1
0x7001, // 30: out pins, 1 side 0
0x18fe, // 31: jmp !osre, 30 side 1
// .wrap

View File

@ -3214,7 +3214,7 @@ void TFT_eSPI::setWindow(int32_t x0, int32_t y0, int32_t x1, int32_t y1)
#else
// This is for the RP2040 and PIO interface (SPI or parallel)
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 = (x0<<16) | x1;
@ -3441,14 +3441,15 @@ void TFT_eSPI::drawPixel(int32_t x, int32_t y, uint32_t color)
#else
// This is for the RP2040 and PIO interface (SPI or parallel)
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 = (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);
TX_FIFO = color;
#endif
#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
***************************************************************************************/
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;
/***************************************************************************************
@ -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)
{
if (bg_color == 0x00FFFFFF) bg_color = readPixel(x, y);
bg_color = alphaBlend(alpha, color, bg_color);
drawPixel(x, y, bg_color);
return bg_color;
color = alphaBlend(alpha, color, bg_color);
drawPixel(x, y, 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)
{
if (r <= 0) return;
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++;
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;
float deltaY = r - cy;
float alphaf = r - sqrtf(deltaX * deltaX + deltaY * deltaY);
if (alphaf > 1.0) continue;
int32_t hyp2 = (r - cx) * (r - cx) + dy2;
if (hyp2 <= r1) break;
if (hyp2 >= r2) continue;
float alphaf = (float)r - sqrtf(hyp2);
if (alphaf > HiAlphaTheshold) break;
xs = cx;
if (alphaf < LoAlphaTheshold) continue;
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, 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);
}
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);
}
@ -3716,40 +3735,45 @@ void TFT_eSPI::fillSmoothCircle(int32_t x, int32_t y, int32_t r, uint32_t color,
end_tft_write();
}
/***************************************************************************************
** Function name: fillSmoothCircle
** Description: Draw a filled anti-aliased circle
** Function name: fillSmoothRoundRect
** 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)
{
inTransaction = true;
int16_t xs = 0;
int16_t cx;
int32_t xs = 0;
int32_t cx = 0;
y += r;
h -= 2*r;
fillRect(x, y, w, h, color);
fillRect(x, y, w, h + 1, color);
x += r;
w -= 2*r+1;
int32_t r1 = 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;
float deltaY = r - cy;
float weight = r - sqrtf(deltaX * deltaX + deltaY * deltaY);
if (weight > 1.0) continue;
int32_t hyp2 = (r - cx) * (r - cx) + dy2;
if (hyp2 <= r1) break;
if (hyp2 >= r2) continue;
float alphaf = (float)r - sqrtf(hyp2);
if (alphaf > HiAlphaTheshold) break;
xs = cx;
if (weight < LoAlphaTheshold) continue;
uint8_t alpha = weight * 255;
if (alphaf < LoAlphaTheshold) continue;
uint8_t alpha = alphaf * 255;
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 + 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 + h, 2 * (r - cx) + 1 + w, color);
}

View File

@ -16,7 +16,7 @@
#ifndef _TFT_eSPIH_
#define _TFT_eSPIH_
#define TFT_ESPI_VERSION "2.4.40"
#define TFT_ESPI_VERSION "2.4.41"
// Bit level feature flags
// Bit 0 set: viewport capability

View File

@ -1,6 +1,6 @@
{
"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",
"description": "A TFT and ePaper SPI graphics library with optimisation for Raspberry Pi Pico, ESP8266, ESP32 and STM32",
"repository":

View File

@ -1,5 +1,5 @@
name=TFT_eSPI
version=2.4.40
version=2.4.41
author=Bodmer
maintainer=Bodmer
sentence=TFT graphics library for Arduino processors with performance optimisation for RP2040, STM32, ESP8266 and ESP32