From e946b4c483140086854cfd2706310466e7a45302 Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Mon, 19 Apr 2021 17:01:33 +0200 Subject: [PATCH 1/2] epaper 42 support --- lib/lib_display/UDisplay/uDisplay.cpp | 194 +++++++++++++++++++++++--- lib/lib_display/UDisplay/uDisplay.h | 30 +++- tasmota/xdrv_10_scripter.ino | 2 +- tasmota/xdrv_13_display.ino | 17 ++- tasmota/xdsp_17_universal.ino | 19 ++- 5 files changed, 227 insertions(+), 35 deletions(-) diff --git a/lib/lib_display/UDisplay/uDisplay.cpp b/lib/lib_display/UDisplay/uDisplay.cpp index fe34e9d40..99f8aabfe 100644 --- a/lib/lib_display/UDisplay/uDisplay.cpp +++ b/lib/lib_display/UDisplay/uDisplay.cpp @@ -52,6 +52,11 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) { startline = 0xA1; uint8_t section = 0; dsp_ncmds = 0; + lut_num = 0; + for (uint32_t cnt = 0; cnt < 5; cnt++) { + lut_cnt[cnt] = 0; + lut_cmd[cnt] = 0xff; + } char linebuff[128]; while (*lp) { @@ -76,6 +81,12 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) { allcmd_mode = 1; lp1++; } + } else if (section == 'L') { + if (*lp1 >= '1' && *lp1 <= '5') { + lut_num = (*lp1 & 0x07); + lp1+=2; + lut_cmd[lut_num - 1] = next_hex(&lp1); + } } if (*lp1 == ',') lp1++; } @@ -213,13 +224,25 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) { dim_op = next_hex(&lp1); break; case 'L': - while (1) { - if (!str2c(&lp1, ibuff, sizeof(ibuff))) { - lut_full[lutfsize++] = strtol(ibuff, 0, 16); - } else { - break; + if (!lut_num) { + while (1) { + if (!str2c(&lp1, ibuff, sizeof(ibuff))) { + lut_full[lutfsize++] = strtol(ibuff, 0, 16); + } else { + break; + } + if (lutfsize >= LUTMAXSIZE) break; + } + } else { + uint8_t index = lut_num - 1; + while (1) { + if (!str2c(&lp1, ibuff, sizeof(ibuff))) { + lut_array[lut_cnt[index]++][index] = strtol(ibuff, 0, 16); + } else { + break; + } + if (lut_cnt[index] >= LUTMAXSIZE) break; } - if (lutfsize >= sizeof(lut_full)) break; } break; case 'l': @@ -229,7 +252,7 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) { } else { break; } - if (lutpsize >= sizeof(lut_partial)) break; + if (lutpsize >= LUTMAXSIZE) break; } break; case 'T': @@ -250,9 +273,15 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) { } if (lutfsize && lutpsize) { + // 2 table mode ep_mode = 1; } + if (lut_cnt[0]>0 && lut_cnt[1]==lut_cnt[2] && lut_cnt[1]==lut_cnt[3] && lut_cnt[1]==lut_cnt[4]) { + // 5 table mode + ep_mode = 2; + } + #ifdef UDSP_DEBUG Serial.printf("xs : %d\n", gxs); @@ -278,10 +307,18 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) { Serial.printf("Rot 0: %x,%x - %d - %d\n", madctrl, rot[0], x_addr_offs[0], y_addr_offs[0]); - if (ep_mode) { + if (ep_mode == 1) { Serial.printf("LUT_Partial : %d\n", lutpsize); Serial.printf("LUT_Full : %d\n", lutfsize); } + if (ep_mode == 2) { + Serial.printf("LUT_SIZE 1: %d\n", lut_cnt[0]); + Serial.printf("LUT_SIZE 2: %d\n", lut_cnt[1]); + Serial.printf("LUT_SIZE 3: %d\n", lut_cnt[2]); + Serial.printf("LUT_SIZE 4: %d\n", lut_cnt[3]); + Serial.printf("LUT_SIZE 5: %d\n", lut_cnt[4]); + Serial.printf("LUT_CMDS %02x-%02x-%02x-%02x-%02x\n", lut_cmd[0], lut_cmd[1], lut_cmd[2], lut_cmd[3], lut_cmd[4]); + } } if (interface == _UDSP_I2C) { Serial.printf("Addr : %02x\n", i2caddr); @@ -443,7 +480,7 @@ Renderer *uDisplay::Init(void) { // must init luts on epaper if (ep_mode) { Init_EPD(DISPLAY_INIT_FULL); - Init_EPD(DISPLAY_INIT_PARTIAL); + if (ep_mode == 1) Init_EPD(DISPLAY_INIT_PARTIAL); } return this; @@ -451,7 +488,7 @@ Renderer *uDisplay::Init(void) { void uDisplay::DisplayInit(int8_t p, int8_t size, int8_t rot, int8_t font) { - if (p !=DISPLAY_INIT_MODE && ep_mode) { + if (p != DISPLAY_INIT_MODE && ep_mode) { if (p == DISPLAY_INIT_PARTIAL) { if (lutpsize) { SetLut(lut_partial); @@ -463,8 +500,12 @@ void uDisplay::DisplayInit(int8_t p, int8_t size, int8_t rot, int8_t font) { if (lutfsize) { SetLut(lut_full); Updateframe_EPD(); - delay(lutftime * 10); } + if (ep_mode == 2) { + ClearFrame_42(); + DisplayFrame_42(); + } + delay(lutftime * 10); return; } } else { @@ -489,14 +530,22 @@ void uDisplay::spi_command(uint8_t val) { if (spi_dc < 0) { if (spi_nr > 2) { - write9(val, 0); + if (spi_nr == 3) { + write9(val, 0); + } else { + write9_slow(val, 0); + } } else { hw_write9(val, 0); } } else { SPI_DC_LOW if (spi_nr > 2) { - write8(val); + if (spi_nr == 3) { + write8(val); + } else { + write8_slow(val); + } } else { uspi->write(val); } @@ -507,13 +556,21 @@ void uDisplay::spi_command(uint8_t val) { void uDisplay::spi_data8(uint8_t val) { if (spi_dc < 0) { if (spi_nr > 2) { - write9(val, 1); + if (spi_nr == 3) { + write9(val, 1); + } else { + write9_slow(val, 1); + } } else { hw_write9(val, 1); } } else { if (spi_nr > 2) { - write8(val); + if (spi_nr == 3) { + write8(val); + } else { + write8_slow(val); + } } else { uspi->write(val); } @@ -827,6 +884,7 @@ for(y=h; y>0; y--) { void uDisplay::Splash(void) { if (ep_mode) { + Updateframe(); delay(lut3time * 10); } setTextFont(splash_font); @@ -1230,6 +1288,7 @@ void uDisplay::hw_write9(uint8_t val, uint8_t dc) { #define USECACHE ICACHE_RAM_ATTR +// slow software spi needed for displays with max 10 Mhz clck void USECACHE uDisplay::write8(uint8_t val) { for (uint8_t bit = 0x80; bit; bit >>= 1) { @@ -1240,6 +1299,15 @@ void USECACHE uDisplay::write8(uint8_t val) { } } +void uDisplay::write8_slow(uint8_t val) { + for (uint8_t bit = 0x80; bit; bit >>= 1) { + GPIO_CLR_SLOW(spi_clk); + if (val & bit) GPIO_SET_SLOW(spi_mosi); + else GPIO_CLR_SLOW(spi_mosi); + GPIO_SET_SLOW(spi_clk); + } +} + void USECACHE uDisplay::write9(uint8_t val, uint8_t dc) { GPIO_CLR(spi_clk); @@ -1255,6 +1323,21 @@ void USECACHE uDisplay::write9(uint8_t val, uint8_t dc) { } } +void uDisplay::write9_slow(uint8_t val, uint8_t dc) { + + GPIO_CLR_SLOW(spi_clk); + if (dc) GPIO_SET_SLOW(spi_mosi); + else GPIO_CLR_SLOW(spi_mosi); + GPIO_SET_SLOW(spi_clk); + + for (uint8_t bit = 0x80; bit; bit >>= 1) { + GPIO_CLR_SLOW(spi_clk); + if (val & bit) GPIO_SET_SLOW(spi_mosi); + else GPIO_CLR_SLOW(spi_mosi); + GPIO_SET_SLOW(spi_clk); + } +} + void USECACHE uDisplay::write16(uint16_t val) { for (uint16_t bit = 0x8000; bit; bit >>= 1) { GPIO_CLR(spi_clk); @@ -1318,12 +1401,23 @@ void uDisplay::spi_command_EPD(uint8_t val) { void uDisplay::Init_EPD(int8_t p) { if (p == DISPLAY_INIT_PARTIAL) { - SetLut(lut_partial); + if (lutpsize) { + SetLut(lut_partial); + } } else { - SetLut(lut_full); + if (lutfsize) { + SetLut(lut_full); + } + if (lut_cnt[0]) { + SetLuts(); + } + } + if (ep_mode == 1) { + ClearFrameMemory(0xFF); + Updateframe_EPD(); + } else { + ClearFrame_42(); } - ClearFrameMemory(0xFF); - Updateframe_EPD(); if (p == DISPLAY_INIT_PARTIAL) { delay(lutptime * 10); } else { @@ -1341,6 +1435,58 @@ void uDisplay::ClearFrameMemory(unsigned char color) { } } +void uDisplay::SetLuts(void) { + uint8_t index, count; + for (index = 0; index < 5; index++) { + spi_command_EPD(lut_cmd[index]); //vcom + for (count = 0; count < lut_cnt[index]; count++) { + spi_data8_EPD(lut_array[count][index]); + } + } +} + +void uDisplay::DisplayFrame_42(void) { + uint16_t Width, Height; + Width = (gxs % 8 == 0) ? (gxs / 8 ): (gxs / 8 + 1); + Height = gys; + + spi_command_EPD(saw_2); + for (uint16_t j = 0; j < Height; j++) { + for (uint16_t i = 0; i < Width; i++) { + spi_data8_EPD(buffer[i + j * Width] ^ 0xff); + } + } + spi_command_EPD(saw_3); + delay(100); + //Serial.printf("EPD Diplayframe\n"); +} + + +void uDisplay::ClearFrame_42(void) { + uint16_t Width, Height; + Width = (gxs % 8 == 0)? (gxs / 8 ): (gxs / 8 + 1); + Height = gys; + + spi_command_EPD(saw_1); + for (uint16_t j = 0; j < Height; j++) { + for (uint16_t i = 0; i < Width; i++) { + spi_data8_EPD(0xFF); + } + } + + spi_command_EPD(saw_2); + for (uint16_t j = 0; j < Height; j++) { + for (uint16_t i = 0; i < Width; i++) { + spi_data8_EPD(0xFF); + } + } + + spi_command_EPD(saw_3); + delay(100); + //Serial.printf("EPD Clearframe\n"); +} + + void uDisplay::SetLut(const unsigned char* lut) { spi_command_EPD(WRITE_LUT_REGISTER); /* the length of look-up table is 30 bytes */ @@ -1350,11 +1496,15 @@ void uDisplay::SetLut(const unsigned char* lut) { } void uDisplay::Updateframe_EPD(void) { - SetFrameMemory(buffer, 0, 0, gxs, gys); - DisplayFrame(); + if (ep_mode == 1) { + SetFrameMemory(buffer, 0, 0, gxs, gys); + DisplayFrame_29(); + } else { + DisplayFrame_42(); + } } -void uDisplay::DisplayFrame(void) { +void uDisplay::DisplayFrame_29(void) { spi_command_EPD(DISPLAY_UPDATE_CONTROL_2); spi_data8_EPD(0xC4); spi_command_EPD(MASTER_ACTIVATION); diff --git a/lib/lib_display/UDisplay/uDisplay.h b/lib/lib_display/UDisplay/uDisplay.h index 006f093a8..a03c0c764 100644 --- a/lib/lib_display/UDisplay/uDisplay.h +++ b/lib/lib_display/UDisplay/uDisplay.h @@ -44,11 +44,18 @@ enum uColorType { uCOLOR_BW, uCOLOR_COLOR }; #define PIN_OUT_CLEAR 0x60000308 #define GPIO_SET(A) WRITE_PERI_REG( PIN_OUT_SET, 1 << A) #define GPIO_CLR(A) WRITE_PERI_REG( PIN_OUT_CLEAR, 1 << A) +#define GPIO_CLR_SLOW(A) digitalWrite(A, LOW) +#define GPIO_SET_SLOW(A) digitalWrite(A, HIGH) #else #undef GPIO_SET -#define GPIO_SET(A) GPIO.out_w1ts = (1 << A) #undef GPIO_CLR +#undef GPIO_SET_SLOW +#undef GPIO_CLR_SLOW #define GPIO_CLR(A) GPIO.out_w1tc = (1 << A) +#define GPIO_SET(A) GPIO.out_w1ts = (1 << A) +#define GPIO_CLR_SLOW(A) digitalWrite(A, LOW) +#define GPIO_SET_SLOW(A) digitalWrite(A, HIGH) + #endif #define SPI_BEGIN_TRANSACTION if (spi_nr <= 2) uspi->beginTransaction(spiSettings); @@ -60,6 +67,8 @@ enum uColorType { uCOLOR_BW, uCOLOR_COLOR }; #define ESP32_PWM_CHANNEL 1 +#define LUTMAXSIZE 64 + class uDisplay : public Renderer { public: uDisplay(char *); @@ -87,21 +96,25 @@ class uDisplay : public Renderer { void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color); uint32_t str2c(char **sp, char *vp, uint32_t len); void i2c_command(uint8_t val); - void spi_command(uint8_t val); void spi_command_one(uint8_t val); + void spi_command(uint8_t val); void spi_data8(uint8_t val); void spi_data16(uint16_t val); void spi_data32(uint32_t val); void write8(uint8_t val); + void write8_slow(uint8_t val); void write9(uint8_t val, uint8_t dc); + void write9_slow(uint8_t val, uint8_t dc); void hw_write9(uint8_t val, uint8_t dc); void write16(uint16_t val); void write32(uint32_t val); void spi_data9(uint8_t d, uint8_t dc); void WriteColor(uint16_t color); void SetLut(const unsigned char* lut); - void DisplayFrame(void); + void SetLuts(void); + void DisplayFrame_29(void); void Updateframe_EPD(); + //void DisplayFrame_42(const unsigned char* frame_buffer); void SetFrameMemory(const unsigned char* image_buffer); void SetFrameMemory(const unsigned char* image_buffer, uint16_t x, uint16_t y, uint16_t image_width, uint16_t image_height); void SetMemoryArea(int x_start, int y_start, int x_end, int y_end); @@ -114,7 +127,10 @@ class uDisplay : public Renderer { void Init_EPD(int8_t p); void spi_command_EPD(uint8_t val); void spi_data8_EPD(uint8_t val); + //void SetPartialWindow_42(uint8_t* frame_buffer, int16_t x, int16_t y, int16_t w, int16_t l, int16_t dtm); void ClearFrameMemory(unsigned char color); + void ClearFrame_42(void); + void DisplayFrame_42(void); uint8_t strlen_ln(char *str); int32_t next_val(char **sp); uint32_t next_hex(char **sp); @@ -176,9 +192,13 @@ class uDisplay : public Renderer { uint16_t lutftime; uint16_t lutptime; uint16_t lut3time; + uint16_t lut_num; uint8_t ep_mode; - uint8_t lut_full[64]; - uint8_t lut_partial[64]; + uint8_t lut_full[LUTMAXSIZE]; + uint8_t lut_partial[LUTMAXSIZE]; + uint8_t lut_array[LUTMAXSIZE][5]; + uint8_t lut_cnt[5]; + uint8_t lut_cmd[5]; }; diff --git a/tasmota/xdrv_10_scripter.ino b/tasmota/xdrv_10_scripter.ino index 372cfa994..307b6f53d 100755 --- a/tasmota/xdrv_10_scripter.ino +++ b/tasmota/xdrv_10_scripter.ino @@ -5199,7 +5199,7 @@ void HandleScriptTextareaConfiguration(void) { if (Webserver->hasArg("save")) { ScriptSaveSettings(); - HandleConfiguration(); + HandleManagement(); return; } } diff --git a/tasmota/xdrv_13_display.ino b/tasmota/xdrv_13_display.ino index 1d2335901..72996d9d3 100755 --- a/tasmota/xdrv_13_display.ino +++ b/tasmota/xdrv_13_display.ino @@ -736,19 +736,30 @@ extern FS *ffsp; { char *ep = strchr(cp,':'); if (ep) { static uint8_t *ram_font; + char fname[24]; *ep = 0; ep++; + if (*cp != '/') { + fname[0] = '/'; + fname[1] = 0; + } else { + fname[0] = 0; + } + strlcat(fname, cp, sizeof(fname)); + if (!strstr(cp, ".fnt")) { + strlcat(fname, ".fnt", sizeof(fname)); + } if (ffsp) { File fp; - fp = ffsp->open(cp, "r"); + fp = ffsp->open(fname, "r"); if (fp > 0) { uint32_t size = fp.size(); if (ram_font) free (ram_font); - ram_font = (uint8_t*)special_malloc(size+4); + ram_font = (uint8_t*)special_malloc(size + 4); fp.read((uint8_t*)ram_font, size); fp.close(); if (renderer) renderer->SetRamfont(ram_font); - Serial.printf("Font loaded: %s\n",cp ); + //Serial.printf("Font loaded: %s\n",fname ); } } cp = ep; diff --git a/tasmota/xdsp_17_universal.ino b/tasmota/xdsp_17_universal.ino index b91cc0550..12f40a8e9 100644 --- a/tasmota/xdsp_17_universal.ino +++ b/tasmota/xdsp_17_universal.ino @@ -182,6 +182,15 @@ char *fbuff; replacepin(&cp, Pin(GPIO_BACKLIGHT)); replacepin(&cp, Pin(GPIO_OLED_RESET)); replacepin(&cp, Pin(GPIO_SPI_MISO)); + } else if (*cp == '2') { + cp+=2; + replacepin(&cp, Pin(GPIO_SPI_CS, 1)); + replacepin(&cp, Pin(GPIO_SPI_CLK, 1)); + replacepin(&cp, Pin(GPIO_SPI_MOSI, 1)); + replacepin(&cp, Pin(GPIO_SPI_DC, 1)); + replacepin(&cp, Pin(GPIO_BACKLIGHT, 1)); + replacepin(&cp, Pin(GPIO_OLED_RESET, 1)); + replacepin(&cp, Pin(GPIO_SPI_MISO, 1)); } else { // soft spi pins cp+=2; @@ -211,20 +220,22 @@ char *fbuff; cp = strstr(ddesc, ":TI"); if (cp) { uint8_t wire_n = 1; - cp+=3; + cp += 3; wire_n = (*cp & 3) - 1; - cp+=2; + cp += 2; uint8_t i2caddr = strtol(cp, &cp, 16); int8_t scl, sda; - scl = replacepin(&cp, Pin(GPIO_I2C_SCL)); - sda = replacepin(&cp, Pin(GPIO_I2C_SDA)); if (wire_n == 0) { + scl = replacepin(&cp, Pin(GPIO_I2C_SCL)); + sda = replacepin(&cp, Pin(GPIO_I2C_SDA)); Wire.begin(sda, scl); } #ifdef ESP32 if (wire_n == 1) { + scl = replacepin(&cp, Pin(GPIO_I2C_SCL, 1)); + sda = replacepin(&cp, Pin(GPIO_I2C_SDA, 1)); Wire1.begin(sda, scl, 400000); } #endif From 97a66f824d45bd5c6404e4ac314a0287259150f2 Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Mon, 19 Apr 2021 17:05:24 +0200 Subject: [PATCH 2/2] add epaper 4.2 desc --- tasmota/displaydesc/WS_epaper42_desc.txt | 54 ++++++++++++++++++++++++ tasmota/displaydesc/readme.md | 2 +- 2 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 tasmota/displaydesc/WS_epaper42_desc.txt diff --git a/tasmota/displaydesc/WS_epaper42_desc.txt b/tasmota/displaydesc/WS_epaper42_desc.txt new file mode 100644 index 000000000..7bbaba269 --- /dev/null +++ b/tasmota/displaydesc/WS_epaper42_desc.txt @@ -0,0 +1,54 @@ +H,E-PAPER-42,400,300,1,SPI,1,*,*,*,*,*,*,*,10 +:S,1,1,1,0,10,10 +:I +01,5,03,00,2b,2b,03 +06,3,17,17,17 +04,80 +00,1,3F +30,1,3C +61,4,01,90,01,2C +82,1,28 +50,1,97 +:A,10,13,12 +:T,450,10,450 +:L1,20 +00,17,00,00,00,02 +00,17,17,00,00,02 +00,0A,01,00,00,01 +00,0E,0E,00,00,02 +00,00,00,00,00,00 +00,00,00,00,00,00 +00,00,00,00,00,00,00,00 +:L2,21 +40,17,00,00,00,02 +90,17,17,00,00,02 +40,0A,01,00,00,01 +A0,0E,0E,00,00,02 +00,00,00,00,00,00 +00,00,00,00,00,00 +00,00,00,00,00,00 +:L3,22 +40,17,00,00,00,02 +90,17,17,00,00,02 +A0,0A,01,00,00,01 +00,0E,0E,00,00,02 +00,00,00,00,00,00 +00,00,00,00,00,00 +00,00,00,00,00,00 +:L4,23 +80,17,00,00,00,02 +90,17,17,00,00,02 +80,0A,01,00,00,01 +50,0E,0E,00,00,02 +00,00,00,00,00,00 +00,00,00,00,00,00 +00,00,00,00,00,00 +:L5,24 +80,17,00,00,00,02 +90,17,17,00,00,02 +80,0A,01,00,00,01 +50,0E,0E,00,00,02 +00,00,00,00,00,00 +00,00,00,00,00,00 +00,00,00,00,00,00 +# diff --git a/tasmota/displaydesc/readme.md b/tasmota/displaydesc/readme.md index a9e29555d..6bb6e0c02 100644 --- a/tasmota/displaydesc/readme.md +++ b/tasmota/displaydesc/readme.md @@ -1,5 +1,5 @@ Display Descriptor files for use with universal display driver. -2 (3) options to select a display driver +4 (3) options to select a display driver 1. file system driven if UFILESYSTEM is in place (preferred option for normal use) to select a display rename the file to "dispdesc.txt" and put into flash file system.