mirror of
https://github.com/arendst/Tasmota.git
synced 2026-07-27 20:05:46 +00:00
Add descriptor-driven ST7305 uDisplay packing (#24738)
This commit is contained in:
@@ -460,8 +460,8 @@ void Renderer::drawFastVLineInternal(int16_t x, int16_t __y, int16_t __h, uint16
|
||||
}
|
||||
|
||||
// this display doesn't need ints for coordinates, use local byte registers for faster juggling
|
||||
register uint8_t y = __y;
|
||||
register uint8_t h = __h;
|
||||
register uint16_t y = __y;
|
||||
register uint16_t h = __h;
|
||||
|
||||
|
||||
// set up the pointer for fast movement through the buffer
|
||||
|
||||
@@ -8,6 +8,11 @@
|
||||
#include "uDisplay_panel.h"
|
||||
#include "uDisplay_SPI_controller.h"
|
||||
|
||||
enum UDisplayMonoPackFlags : uint8_t {
|
||||
UDISP_MONO_PACK_INVERT = 1 << 0,
|
||||
UDISP_MONO_PACK_REVERSE_Y = 1 << 1,
|
||||
};
|
||||
|
||||
typedef struct LVGL_PARAMS_t {
|
||||
uint16_t flushlines;
|
||||
union {
|
||||
@@ -40,6 +45,13 @@ struct SPIPanelConfig {
|
||||
uint8_t cmd_set_addr_x; // Command to set X address range
|
||||
uint8_t cmd_set_addr_y; // Command to set Y address range
|
||||
uint8_t cmd_write_ram; // Command to write pixel data
|
||||
uint8_t ram_x_start; // Optional full-frame RAM window for packed mono modes
|
||||
uint8_t ram_x_end;
|
||||
uint8_t ram_y_start;
|
||||
uint8_t ram_y_end;
|
||||
uint8_t mono_pack_width; // Optional descriptor-selected 1bpp transfer packing
|
||||
uint8_t mono_pack_height;
|
||||
uint8_t mono_pack_flags;
|
||||
|
||||
// ===== Display Control Commands =====
|
||||
uint8_t cmd_display_on;
|
||||
@@ -107,6 +119,9 @@ private:
|
||||
bool use_hw_spi = false;
|
||||
|
||||
// ===== Internal Helpers =====
|
||||
bool hasPackedMono() const;
|
||||
bool updateFramePackedMono();
|
||||
uint8_t getMonoPixel(int16_t x, int16_t y) const;
|
||||
void setAddrWindow_internal(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1);
|
||||
void sendAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1);
|
||||
void sendCommand(uint8_t cmd);
|
||||
@@ -115,4 +130,4 @@ private:
|
||||
void writeColor(uint16_t color);
|
||||
void resetDisplay();
|
||||
void waitBusy();
|
||||
};
|
||||
};
|
||||
|
||||
@@ -614,7 +614,18 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) {
|
||||
rot_t[3] = next_hex(&lp1);
|
||||
break;
|
||||
case 'A':
|
||||
if (interface == _UDSP_I2C || bpp == 1) {
|
||||
if (interface == _UDSP_SPI && panel_config->spi.mono_pack_width && panel_config->spi.mono_pack_height) {
|
||||
// Some 1bpp SPI panels use TFT-style RAMWR instead of OLED pages.
|
||||
// A descriptor-selected packed mono mode provides the RAM window.
|
||||
panel_config->spi.cmd_set_addr_x = next_hex(&lp1);
|
||||
panel_config->spi.cmd_set_addr_y = next_hex(&lp1);
|
||||
panel_config->spi.cmd_write_ram = next_hex(&lp1);
|
||||
panel_config->spi.address_mode = next_val(&lp1);
|
||||
panel_config->spi.ram_x_start = next_hex(&lp1);
|
||||
panel_config->spi.ram_x_end = next_hex(&lp1);
|
||||
panel_config->spi.ram_y_start = next_hex(&lp1);
|
||||
panel_config->spi.ram_y_end = next_hex(&lp1);
|
||||
} else if (interface == _UDSP_I2C || bpp == 1) {
|
||||
// Parse directly into I2C config
|
||||
panel_config->i2c.cmd_set_addr_x = next_hex(&lp1);
|
||||
panel_config->i2c.page_start = next_hex(&lp1);
|
||||
@@ -677,6 +688,13 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) {
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 'F':
|
||||
if (interface == _UDSP_SPI && bpp == 1) {
|
||||
panel_config->spi.mono_pack_width = next_val(&lp1);
|
||||
panel_config->spi.mono_pack_height = next_val(&lp1);
|
||||
panel_config->spi.mono_pack_flags = next_val(&lp1);
|
||||
}
|
||||
break;
|
||||
case 'i':
|
||||
inv_off = next_hex(&lp1);
|
||||
inv_on = next_hex(&lp1);
|
||||
@@ -1141,13 +1159,23 @@ Renderer *uDisplay::Init(void) {
|
||||
// for any bpp below native 16 bits, we allocate a local framebuffer to copy into
|
||||
if (ep_mode || bpp < 16) {
|
||||
if (framebuffer) free(framebuffer);
|
||||
uint32_t framebuffer_size = (gxs * gys * bpp) / 8;
|
||||
if (bpp == 1) {
|
||||
// Renderer packs monochrome pixels in vertical 8-pixel pages:
|
||||
// framebuffer[x + (y >> 3) * width]. Non-8-multiple heights need
|
||||
// storage for the partial final page.
|
||||
framebuffer_size = gxs * ((gys + 7) / 8);
|
||||
}
|
||||
#ifdef ESP8266
|
||||
framebuffer = (uint8_t*)calloc((gxs * gys * bpp) / 8, 1);
|
||||
framebuffer = (uint8_t*)calloc(framebuffer_size, 1);
|
||||
#else
|
||||
if (UsePSRAM()) {
|
||||
framebuffer = (uint8_t*)heap_caps_malloc((gxs * gys * bpp) / 8, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
framebuffer = (uint8_t*)heap_caps_malloc(framebuffer_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
if (framebuffer) {
|
||||
memset(framebuffer, 0, framebuffer_size);
|
||||
}
|
||||
} else {
|
||||
framebuffer = (uint8_t*)calloc((gxs * gys * bpp) / 8, 1);
|
||||
framebuffer = (uint8_t*)calloc(framebuffer_size, 1);
|
||||
}
|
||||
#endif // ESP8266
|
||||
}
|
||||
|
||||
@@ -203,6 +203,14 @@ bool SPIPanel::pushColors(uint16_t *data, uint32_t len, bool not_swapped) {
|
||||
}
|
||||
|
||||
bool SPIPanel::setAddrWindow(int16_t x0, int16_t y0, int16_t x1, int16_t y1) {
|
||||
if (hasPackedMono()) {
|
||||
window_x0 = x0;
|
||||
window_y0 = y0;
|
||||
window_x1 = x1;
|
||||
window_y1 = y1;
|
||||
return false;
|
||||
}
|
||||
|
||||
// From original uDisplay::setAddrWindow
|
||||
window_x0 = x0;
|
||||
window_y0 = y0;
|
||||
@@ -294,6 +302,10 @@ bool SPIPanel::displayOnff(int8_t on) {
|
||||
}
|
||||
spi->csHigh();
|
||||
spi->endTransaction();
|
||||
|
||||
if (display_on && fb_buffer && hasPackedMono()) {
|
||||
return updateFramePackedMono();
|
||||
}
|
||||
|
||||
return false; //true;
|
||||
}
|
||||
@@ -352,6 +364,10 @@ bool SPIPanel::updateFrame() {
|
||||
// From original uDisplay::Updateframe - only for monochrome SPI OLEDs
|
||||
// Only handle framebuffer updates for monochrome displays
|
||||
if (!fb_buffer || cfg.bpp != 1) return false;
|
||||
|
||||
if (hasPackedMono()) {
|
||||
return updateFramePackedMono();
|
||||
}
|
||||
|
||||
// OLED page-based framebuffer update (from original code)
|
||||
uint8_t ys = height >> 3;
|
||||
@@ -378,4 +394,61 @@ bool SPIPanel::updateFrame() {
|
||||
spi->csHigh();
|
||||
spi->endTransaction();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t SPIPanel::getMonoPixel(int16_t x, int16_t y) const {
|
||||
if (x < 0 || x >= width || y < 0 || y >= height) {
|
||||
return 0;
|
||||
}
|
||||
return (fb_buffer[x + (y >> 3) * width] & (1 << (y & 7))) ? 1 : 0;
|
||||
}
|
||||
|
||||
bool SPIPanel::hasPackedMono() const {
|
||||
return fb_buffer && cfg.bpp == 1 && cfg.mono_pack_width && cfg.mono_pack_height &&
|
||||
(cfg.mono_pack_width * cfg.mono_pack_height <= 8);
|
||||
}
|
||||
|
||||
bool SPIPanel::updateFramePackedMono() {
|
||||
if (!hasPackedMono()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
spi->beginTransaction();
|
||||
spi->csLow();
|
||||
|
||||
// Packed monochrome RAMWR displays may not restart at the full-screen RAM
|
||||
// window on a bare RAMWR, so set the descriptor-provided range each flush.
|
||||
spi->writeCommand(cfg.cmd_set_addr_x);
|
||||
spi->writeData8(cfg.ram_x_start);
|
||||
spi->writeData8(cfg.ram_x_end);
|
||||
spi->writeCommand(cfg.cmd_set_addr_y);
|
||||
spi->writeData8(cfg.ram_y_start);
|
||||
spi->writeData8(cfg.ram_y_end);
|
||||
spi->writeCommand(cfg.cmd_write_ram);
|
||||
|
||||
for (uint16_t x = 0; x < width; x += cfg.mono_pack_width) {
|
||||
for (uint16_t y = 0; y < height; y += cfg.mono_pack_height) {
|
||||
// Descriptor-defined packed mono format, row-major from bit7 down.
|
||||
uint8_t packed = 0;
|
||||
uint8_t bit = 0x80;
|
||||
for (uint8_t row = 0; row < cfg.mono_pack_height; row++) {
|
||||
int16_t sy = (cfg.mono_pack_flags & UDISP_MONO_PACK_REVERSE_Y)
|
||||
? height - 1 - y - row : y + row;
|
||||
for (uint8_t col = 0; col < cfg.mono_pack_width; col++) {
|
||||
if (getMonoPixel(x + col, sy)) {
|
||||
packed |= bit;
|
||||
}
|
||||
bit >>= 1;
|
||||
}
|
||||
}
|
||||
if (cfg.mono_pack_flags & UDISP_MONO_PACK_INVERT) {
|
||||
packed = ~packed;
|
||||
}
|
||||
spi->writeData8(packed);
|
||||
}
|
||||
}
|
||||
|
||||
spi->csHigh();
|
||||
spi->endTransaction();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
:H,ST7305_RLCD_400x300,400,300,1,SPI,1,40,11,12,5,-1,41,-1,1
|
||||
:F,2,4,3
|
||||
:S,0,4,0,1,116,130
|
||||
:B,40,0
|
||||
:I
|
||||
D6,02,17,02
|
||||
D1,01,01
|
||||
C0,02,11,04
|
||||
C1,04,69,69,69,69
|
||||
C2,04,19,19,19,19
|
||||
C4,04,4B,4B,4B,4B
|
||||
C5,04,19,19,19,19
|
||||
D8,02,80,E9
|
||||
B2,01,02
|
||||
B3,0A,E5,F6,05,46,77,77,77,77,76,45
|
||||
B4,08,05,46,77,77,77,77,76,45
|
||||
62,03,32,03,1F
|
||||
B7,01,13
|
||||
B0,01,64
|
||||
11,80
|
||||
C9,01,00
|
||||
36,01,48
|
||||
3A,01,11
|
||||
B9,01,20
|
||||
B8,01,29
|
||||
21,00
|
||||
2A,02,12,2A
|
||||
2B,02,00,C7
|
||||
35,01,00
|
||||
D0,01,FF
|
||||
38,00
|
||||
29,80
|
||||
:o,28
|
||||
:O,29
|
||||
:A,2A,2B,2C,0,12,2A,00,C7
|
||||
:R,36
|
||||
:0,48,00,00,00
|
||||
:1,28,00,00,01
|
||||
:2,88,00,00,02
|
||||
:3,E8,00,00,03
|
||||
:i,20,21
|
||||
#
|
||||
Reference in New Issue
Block a user