Epaper update (#17727)

* update epaper descriptors

* epaper rewrite

* add busy invert option

* fix v2 partial refresh

* prepare for large descriptors
This commit is contained in:
gemu 2023-01-17 10:19:06 +01:00 committed by GitHub
parent beb021210d
commit 853909cb35
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 687 additions and 170 deletions

View File

@ -86,6 +86,10 @@ void Renderer::Begin(int16_t p1,int16_t p2,int16_t p3) {
}
void Renderer::Sleep(void) {
}
void Renderer::Updateframe() {
}

View File

@ -35,7 +35,7 @@ typedef struct LVGL_PARAMS {
uint8_t use_dma : 1;
uint8_t swap_color : 1;
uint8_t async_dma : 1; // force DMA completion before returning, avoid conflict with other devices on same bus. If set you should make sure the display is the only device on the bus
uint8_t resvd_1 : 1;
uint8_t busy_invert : 1;
uint8_t resvd_2 : 1;
uint8_t resvd_3 : 1;
uint8_t resvd_4 : 1;
@ -86,6 +86,7 @@ public:
virtual uint16_t bgcol(void);
virtual int8_t color_type(void);
virtual void Splash(void);
virtual void Sleep(void);
virtual char *devname(void);
virtual LVGL_PARAMS *lvgl_pars(void);
virtual void ep_update_mode(uint8_t mode);

View File

@ -30,6 +30,9 @@
#define EPD_29_V2
//#define BUSY_PIN 16
Epd::Epd(int16_t width, int16_t height) :
Paint(width,height) {
}
@ -38,30 +41,35 @@ void Epd::DisplayOnff(int8_t on) {
}
void Epd::Updateframe() {
#ifdef EPD_29_V2
if (mode == DISPLAY_INIT_PARTIAL) {
SetFrameMemory_Partial(framebuffer, 0, 0, EPD_WIDTH,EPD_HEIGHT);
DisplayFrame_Partial();
} else {
SetFrameMemory(framebuffer, 0, 0, EPD_WIDTH,EPD_HEIGHT);
DisplayFrame();
}
#else
SetFrameMemory(framebuffer, 0, 0, EPD_WIDTH,EPD_HEIGHT);
DisplayFrame();
#endif
//Serial.printf("update\n");
}
#define DISPLAY_INIT_MODE 0
#define DISPLAY_INIT_PARTIAL 1
#define DISPLAY_INIT_FULL 2
void Epd::DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font) {
// ignore update mode
if (p==DISPLAY_INIT_PARTIAL) {
if (p == DISPLAY_INIT_PARTIAL) {
Init(lut_partial_update);
//ClearFrameMemory(0xFF); // bit set = white, bit reset = black
DisplayFrame();
delay(500);
delay_busy(500);
return;
//Serial.printf("partial\n");
} else if (p==DISPLAY_INIT_FULL) {
} else if (p == DISPLAY_INIT_FULL) {
Init(lut_full_update);
//ClearFrameMemory(0xFF); // bit set = white, bit reset = black
DisplayFrame();
delay(3500);
delay_busy(3500);
//Serial.printf("full\n");
return;
} else {
@ -80,25 +88,31 @@ void Epd::DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font) {
disp_bpp = 1;
}
void Epd::Begin(int16_t cs,int16_t mosi,int16_t sclk) {
cs_pin=cs;
mosi_pin=mosi;
sclk_pin=sclk;
void Epd::Begin(int16_t cs,int16_t mosi,int16_t sclk, int16_t rst, int16_t busy) {
cs_pin = cs;
mosi_pin = mosi;
sclk_pin = sclk;
rst_pin = rst;
busy_pin = busy;
#ifdef BUSY_PIN
busy_pin = BUSY_PIN;
#endif
}
void Epd::Init(int8_t p) {
if (p==DISPLAY_INIT_PARTIAL) {
if (p == DISPLAY_INIT_PARTIAL) {
Init(lut_partial_update);
} else {
Init(lut_full_update);
}
mode = p;
ClearFrameMemory(0xFF);
DisplayFrame();
if (p==DISPLAY_INIT_PARTIAL) {
delay(350);
if (p == DISPLAY_INIT_PARTIAL) {
delay_busy(350);
} else {
delay(3500);
delay_busy(3500);
}
}
@ -114,6 +128,9 @@ int Epd::Init(const unsigned char* lut) {
sclk_pin=pin[GPIO_SSPI_SCLK];
*/
if (framebuffer) {
// free(framebuffer);
}
framebuffer = (uint8_t*)malloc(EPD_WIDTH * EPD_HEIGHT / 8);
if (!framebuffer) return -1;
@ -125,14 +142,24 @@ int Epd::Init(const unsigned char* lut) {
digitalWrite(mosi_pin,LOW);
digitalWrite(sclk_pin,LOW);
if (rst_pin >= 0) {
pinMode(rst_pin, OUTPUT);
digitalWrite(rst_pin, HIGH);
}
if (busy_pin >= 0) {
pinMode(busy_pin, INPUT_PULLUP);
}
width = EPD_WIDTH;
height = EPD_HEIGHT;
#ifdef EPD_29_V2
/* EPD hardware init start */
WaitUntilIdle();
Reset();
SendCommand(0x12); //SWRESET
WaitUntilIdle();
delay_busy(100);
SendCommand(0x01); //Driver output control
SendData(0x27);
@ -149,9 +176,10 @@ int Epd::Init(const unsigned char* lut) {
SendData(0x80);
SetMemoryPointer(0, 0);
WaitUntilIdle();
delay_busy(10);
SetLut_by_host(lut_full_update);
mode = DISPLAY_INIT_FULL;
#else
/* EPD hardware init start */
@ -197,31 +225,33 @@ void Epd::SendData(unsigned char data) {
// SpiTransfer(data);
}
/**
* @brief: Wait until the busy_pin goes LOW
*/
void Epd::WaitUntilIdle(void) {
#ifdef EPD_29_V2
delay(100);
#endif
return;
//while(DigitalRead(busy_pin) == HIGH) { //LOW: idle, HIGH: busy
// DelayMs(100);
//}
void Epd::delay_busy(uint32_t wait) {
if (busy_pin >= 0) {
while (digitalRead(busy_pin) == HIGH) { //LOW: idle, HIGH: busy
delay(10);
}
} else {
delay(wait);
}
}
/**
* @brief: module reset.
* often used to awaken the module in deep sleep,
* see Epd::Sleep();
*/
void Epd::Reset(void) {
//DigitalWrite(reset_pin, LOW); //module reset
//delay(200);
//DigitalWrite(reset_pin, HIGH);
//delay(200);
if (rst_pin >= 0) {
digitalWrite(rst_pin, LOW); //module reset
delay(200);
digitalWrite(rst_pin, HIGH);
delay(200);
} else {
SendCommand(0x12);
}
}
#ifdef EPD_29_V2
@ -230,7 +260,7 @@ void Epd::SetLut(const unsigned char *lut) {
SendCommand(0x32);
for(count=0; count<153; count++)
SendData(lut[count]);
WaitUntilIdle();
delay_busy(50);
}
@ -276,6 +306,7 @@ void Epd::SetFrameMemory(
uint16_t image_width,
uint16_t image_height
) {
uint16_t x_end;
uint16_t y_end;
@ -366,15 +397,94 @@ void Epd::ClearFrameMemory(unsigned char color) {
* set the other memory area.
*/
void Epd::DisplayFrame(void) {
SendCommand(DISPLAY_UPDATE_CONTROL_2);
SendCommand(DISPLAY_UPDATE_CONTROL_2); // 0x22
#ifdef EPD_29_V2
SendData(0xC7);
#else
SendData(0xC4);
SendCommand(MASTER_ACTIVATION);
#endif
SendCommand(MASTER_ACTIVATION); // 0x20
#ifndef EPD_29_V2
SendCommand(TERMINATE_FRAME_READ_WRITE);
WaitUntilIdle();
#endif
delay_busy(10);
}
void Epd::DisplayFrame_Partial(void) {
SendCommand(0x22);
SendData(0x0F);
SendCommand(0x20);
delay_busy(10);
}
#ifdef EPD_29_V2
void Epd::SetFrameMemory_Partial(const unsigned char* image_buffer, int x, int y, int image_width, int image_height) {
int x_end;
int y_end;
if (
image_buffer == NULL ||
x < 0 || image_width < 0 ||
y < 0 || image_height < 0
) {
return;
}
/* x point must be the multiple of 8 or the last 3 bits will be ignored */
x &= 0xF8;
image_width &= 0xF8;
if (x + image_width >= this->width) {
x_end = this->width - 1;
} else {
x_end = x + image_width - 1;
}
if (y + image_height >= this->height) {
y_end = this->height - 1;
} else {
y_end = y + image_height - 1;
}
if (rst_pin >= 0) {
digitalWrite(rst_pin, LOW);
delay(2);
digitalWrite(rst_pin, HIGH);
delay(2);
} else {
SendCommand(0x12);
}
SetLut(lut_partial_update);
SendCommand(0x37);
SendData(0x00);
SendData(0x00);
SendData(0x00);
SendData(0x00);
SendData(0x00);
SendData(0x40);
SendData(0x00);
SendData(0x00);
SendData(0x00);
SendData(0x00);
SendCommand(0x3C); //BorderWavefrom
SendData(0x80);
SendCommand(0x22);
SendData(0xC0);
SendCommand(0x20);
delay_busy(100);
SetMemoryArea(x, y, x_end, y_end);
SetMemoryPointer(x, y);
SendCommand(0x24);
/* send the image data */
for (int j = 0; j < y_end - y + 1; j++) {
for (int i = 0; i < (x_end - x + 1) / 8; i++) {
SendData(image_buffer[i + j * (image_width / 8)]^0xff);
}
}
}
#ifdef EPD_29_V2
/**
* @brief: private function to specify the memory area for data R/W
*/
@ -390,6 +500,15 @@ void Epd::SetMemoryArea(int x_start, int y_start, int x_end, int y_end) {
SendData((y_end >> 8) & 0xFF);
}
#else
void Epd::SetFrameMemory_Partial(
const unsigned char* image_buffer,
int x,
int y,
int image_width,
int image_height
) {
}
/**
* @brief: private function to specify the memory area for data R/W
*/
@ -419,7 +538,7 @@ void Epd::SetMemoryPointer(int x, int y) {
SendCommand(0x4F);
SendData(y & 0xFF);
SendData((y >> 8) & 0xFF);
WaitUntilIdle();
delay_busy(10);
}
#else
/**
@ -432,7 +551,7 @@ void Epd::SetMemoryPointer(int x, int y) {
SendCommand(SET_RAM_Y_ADDRESS_COUNTER);
SendData(y & 0xFF);
SendData((y >> 8) & 0xFF);
WaitUntilIdle();
delay_busy(10);
}
#endif
@ -444,7 +563,7 @@ void Epd::SetMemoryPointer(int x, int y) {
*/
void Epd::Sleep() {
SendCommand(DEEP_SLEEP_MODE);
WaitUntilIdle();
delay_busy(10);
}
#ifdef EPD_29_V2

View File

@ -30,6 +30,10 @@
#include "epdpaint.h"
#define DISPLAY_INIT_MODE 0
#define DISPLAY_INIT_PARTIAL 1
#define DISPLAY_INIT_FULL 2
// Display resolution
#define EPD_WIDTH 128
#define EPD_HEIGHT 296
@ -91,23 +95,27 @@ public:
void DisplayOnff(int8_t on);
void DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font);
void Begin(int16_t p1,int16_t p2,int16_t p3);
void Begin(int16_t cs,int16_t mosi,int16_t sclk, int16_t rst = -1, int16_t busy = -1);
void Updateframe();
private:
unsigned int reset_pin;
unsigned int dc_pin;
unsigned int busy_pin;
const unsigned char* lut;
unsigned int cs_pin;
signed int rst_pin;
signed int busy_pin;
unsigned int mosi_pin;
unsigned int sclk_pin;
unsigned char mode;
void delay_busy(uint32_t wait);
void SetLut(const unsigned char* lut);
void SetMemoryArea(int x_start, int y_start, int x_end, int y_end);
void SetMemoryPointer(int x, int y);
void SetLut_by_host(const unsigned char* lut);
void SetFrameMemory_Partial(const unsigned char* image_buffer,int x,int y,int image_width,int image_height);
void DisplayFrame_Partial(void);
//void fastSPIwrite(uint8_t d,uint8_t dc);
};

View File

@ -66,6 +66,18 @@ uDisplay::~uDisplay(void) {
if (_i80_bus) {
esp_lcd_del_i80_bus(_i80_bus);
}
if (lut_full) {
free(lut_full);
}
if (lut_partial) {
free(lut_partial);
}
for (uint16_t cnt = 0; cnt < MAX_LUTS; cnt++ ) {
if (lut_array[cnt]) {
free(lut_array[cnt]);
}
}
#endif // USE_ESP32_S3
}
@ -86,6 +98,7 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) {
lutptime = 35;
lutftime = 350;
lut3time = 10;
busy_pin = -1;
ep_mode = 0;
fg_col = 1;
bg_col = 0;
@ -96,6 +109,8 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) {
startline = 0xA1;
uint8_t section = 0;
dsp_ncmds = 0;
epc_part_cnt = 0;
epc_full_cnt = 0;
lut_num = 0;
lvgl_param.data = 0;
lvgl_param.fluslines = 40;
@ -103,8 +118,10 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) {
rot_t[1] = 1;
rot_t[2] = 2;
rot_t[3] = 3;
epcoffs_full = 0;
epcoffs_part = 0;
for (uint32_t cnt = 0; cnt < 5; cnt++) {
for (uint32_t cnt = 0; cnt < MAX_LUTS; cnt++) {
lut_cnt[cnt] = 0;
lut_cmd[cnt] = 0xff;
}
@ -135,9 +152,22 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) {
} else if (section == 'L') {
if (*lp1 >= '1' && *lp1 <= '5') {
lut_num = (*lp1 & 0x07);
lp1+=2;
lp1 += 2;
lut_siz[lut_num - 1] = next_val(&lp1);
lut_array[lut_num - 1] = (uint8_t*)malloc(lut_siz[lut_num - 1]);
lut_cmd[lut_num - 1] = next_hex(&lp1);
} else {
lut_num = 0;
lp1++;
lut_siz_full = next_val(&lp1);
lut_full = (uint8_t*)malloc(lut_siz_full);
lut_cmd[0] = next_hex(&lp1);
}
} else if (section == 'l') {
lp1++;
lut_siz_partial = next_val(&lp1);
lut_partial = (uint8_t*)malloc(lut_siz_partial);
lut_cmd[0] = next_hex(&lp1);
}
if (*lp1 == ',') lp1++;
}
@ -182,7 +212,6 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) {
reset = next_val(&lp1);
spi_miso = next_val(&lp1);
spi_speed = next_val(&lp1);
section = 0;
} else if (!strncmp(ibuff, "PAR", 3)) {
#ifdef USE_ESP32_S3
@ -256,13 +285,42 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) {
}
} else {
while (1) {
if (dsp_ncmds >= sizeof(dsp_cmds)) break;
if (!str2c(&lp1, ibuff, sizeof(ibuff))) {
dsp_cmds[dsp_ncmds++] = strtol(ibuff, 0, 16);
} else {
break;
}
if (dsp_ncmds >= sizeof(dsp_cmds)) break;
}
}
break;
case 'f':
// epaper full update cmds
if (!epcoffs_full) {
epcoffs_full = dsp_ncmds;
epc_full_cnt = 0;
}
while (1) {
if (epc_full_cnt >= sizeof(dsp_cmds)) break;
if (!str2c(&lp1, ibuff, sizeof(ibuff))) {
dsp_cmds[epcoffs_full + epc_full_cnt++] = strtol(ibuff, 0, 16);
} else {
break;
}
}
break;
case 'p':
// epaper partial update cmds
if (!epcoffs_part) {
epcoffs_part = dsp_ncmds + epc_full_cnt;
epc_part_cnt = 0;
}
while (1) {
if (epc_part_cnt >= sizeof(dsp_cmds)) break;
if (!str2c(&lp1, ibuff, sizeof(ibuff))) {
dsp_cmds[epcoffs_part + epc_part_cnt++] = strtol(ibuff, 0, 16);
} else {
break;
}
}
break;
@ -338,6 +396,11 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) {
sa_mode = next_val(&lp1);
}
break;
case 'a':
saw_1 = next_hex(&lp1);
saw_2 = next_hex(&lp1);
saw_3 = next_hex(&lp1);
break;
case 'P':
col_mode = next_val(&lp1);
break;
@ -350,34 +413,43 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) {
break;
case 'L':
if (!lut_num) {
if (!lut_full) {
break;
}
while (1) {
if (!str2c(&lp1, ibuff, sizeof(ibuff))) {
lut_full[lutfsize++] = strtol(ibuff, 0, 16);
} else {
break;
}
if (lutfsize >= LUTMAXSIZE) break;
if (lutfsize >= lut_siz_full) break;
}
} else {
uint8_t index = lut_num - 1;
if (!lut_array[index]) {
break;
}
while (1) {
if (!str2c(&lp1, ibuff, sizeof(ibuff))) {
lut_array[lut_cnt[index]++][index] = strtol(ibuff, 0, 16);
lut_array[index][lut_cnt[index]++] = strtol(ibuff, 0, 16);
} else {
break;
}
if (lut_cnt[index] >= LUTMAXSIZE) break;
if (lut_cnt[index] >= lut_siz[index]) break;
}
}
break;
case 'l':
if (!lut_partial) {
break;
}
while (1) {
if (!str2c(&lp1, ibuff, sizeof(ibuff))) {
lut_partial[lutpsize++] = strtol(ibuff, 0, 16);
} else {
break;
}
if (lutpsize >= LUTMAXSIZE) break;
if (lutpsize >= lut_siz_partial) break;
}
break;
case 'T':
@ -452,8 +524,8 @@ 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 == 1) {
Serial.printf("LUT_Partial : %d\n", lutpsize);
Serial.printf("LUT_Full : %d\n", lutfsize);
Serial.printf("LUT_Partial : %d - %d - %x - %d - %d\n", lut_siz_partial, lutpsize, lut_cmd[0], epcoffs_part, epc_part_cnt);
Serial.printf("LUT_Full : %d - %d - %x - %d - %d\n", lut_siz_full, lutfsize, lut_cmd[0], epcoffs_full, epc_full_cnt);
}
if (ep_mode == 2) {
Serial.printf("LUT_SIZE 1: %d\n", lut_cnt[0]);
@ -533,11 +605,144 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) {
}
#endif
#ifdef UDSP_DEBUG
Serial.printf("Dsp class init complete\n");
#endif
}
void uDisplay::delay_arg(uint32_t args) {
uint32_t delay_ms = 0;
switch (args & 0xE0) {
case 0x80: delay_ms = 150; break;
case 0xA0: delay_ms = 10; break;
case 0xE0: delay_ms = 500; break;
}
if (delay_ms > 0) {
delay(delay_ms);
#ifdef UDSP_DEBUG
Serial.printf("delay %d ms\n", delay_ms);
#endif
}
}
// epaper pseudo opcodes
#define EP_RESET 0x60
#define EP_LUT_FULL 0x61
#define EP_LUT_PARTIAL 0x62
#define EP_WAITIDLE 0x63
#define EP_SET_MEM_AREA 0x64
#define EP_SET_MEM_PTR 0x65
#define EP_SEND_DATA 0x66
#define EP_CLR_FRAME 0x67
#define EP_SEND_FRAME 0x68
void uDisplay::send_spi_cmds(uint16_t cmd_offset, uint16_t cmd_size) {
uint16_t index = 0;
#ifdef UDSP_DEBUG
Serial.printf("start send cmd table\n");
#endif
while (1) {
uint8_t iob;
SPI_CS_LOW
iob = dsp_cmds[cmd_offset++];
index++;
if (ep_mode == 1 && iob >= EP_RESET) {
// epaper pseudo opcodes
uint8_t args = dsp_cmds[cmd_offset++];
index++;
#ifdef UDSP_DEBUG
Serial.printf("cmd, args %02x, %d ", iob, args & 0x1f);
#endif
switch (iob) {
case EP_RESET:
if (args & 1) {
iob = dsp_cmds[cmd_offset++];
index++;
}
reset_pin(iob, iob);
break;
case EP_LUT_FULL:
SetLut(lut_full);
ep_update_mode = DISPLAY_INIT_FULL;
break;
case EP_LUT_PARTIAL:
SetLut(lut_partial);
ep_update_mode = DISPLAY_INIT_PARTIAL;
break;
case EP_WAITIDLE:
if (args & 1) {
iob = dsp_cmds[cmd_offset++];
index++;
}
//delay(iob * 10);
delay_sync(iob * 10);
break;
case EP_SET_MEM_AREA:
SetMemoryArea(0, 0, gxs - 1, gys - 1);
break;
case EP_SET_MEM_PTR:
SetMemoryPointer(0, 0);
break;
case EP_SEND_DATA:
Send_EP_Data();
break;
case EP_CLR_FRAME:
ClearFrameMemory(0xFF);
break;
case EP_SEND_FRAME:
SetFrameMemory(framebuffer);
break;
}
#ifdef UDSP_DEBUG
if (args & 1) {
Serial.printf("%02x ", iob );
}
Serial.printf("\n");
#endif
if (args & 0x80) { // delay after the command
delay_arg(args);
}
} else {
ulcd_command(iob);
uint8_t args = dsp_cmds[cmd_offset++];
index++;
#ifdef UDSP_DEBUG
Serial.printf("cmd, args %02x, %d ", iob, args & 0x1f);
#endif
for (uint32_t cnt = 0; cnt < (args & 0x1f); cnt++) {
iob = dsp_cmds[cmd_offset++];
index++;
#ifdef UDSP_DEBUG
Serial.printf("%02x ", iob );
#endif
if (!allcmd_mode) {
ulcd_data8(iob);
} else {
ulcd_command(iob);
}
}
SPI_CS_HIGH
#ifdef UDSP_DEBUG
Serial.printf("\n");
#endif
if (args & 0x80) { // delay after the command
delay_arg(args);
}
}
if (index >= cmd_size) break;
}
#ifdef UDSP_DEBUG
Serial.printf("end send cmd table\n");
#endif
}
Renderer *uDisplay::Init(void) {
extern bool UsePSRAM(void);
#ifdef UDSP_DEBUG
Serial.printf("Dsp Init 1 start \n");
#endif
// for any bpp below native 16 bits, we allocate a local framebuffer to copy into
if (ep_mode || bpp < 16) {
if (framebuffer) free(framebuffer);
@ -549,10 +754,9 @@ Renderer *uDisplay::Init(void) {
} else {
framebuffer = (uint8_t*)calloc((gxs * gys * bpp) / 8, 1);
}
#endif
#endif // ESP8266
}
if (interface == _UDSP_I2C) {
if (wire_n == 0) {
wire = &Wire;
@ -561,7 +765,7 @@ Renderer *uDisplay::Init(void) {
if (wire_n == 1) {
wire = &Wire1;
}
#endif
#endif // ESP32
wire->begin(i2c_sda, i2c_scl); // TODO: aren't I2C buses already initialized? Shouldn't this be moved to display driver?
#ifdef UDSP_DEBUG
@ -604,6 +808,10 @@ Renderer *uDisplay::Init(void) {
digitalWrite(spi_clk, LOW);
pinMode(spi_mosi, OUTPUT);
digitalWrite(spi_mosi, LOW);
if (spi_miso >= 0) {
pinMode(spi_miso, INPUT_PULLUP);
busy_pin = spi_miso;
}
}
#endif // ESP8266
@ -628,6 +836,13 @@ Renderer *uDisplay::Init(void) {
digitalWrite(spi_clk, LOW);
pinMode(spi_mosi, OUTPUT);
digitalWrite(spi_mosi, LOW);
if (spi_miso >= 0) {
busy_pin = spi_miso;
pinMode(spi_miso, INPUT_PULLUP);
#ifdef UDSP_DEBUG
Serial.printf("Dsp busy pin: %d\n", busy_pin);
#endif
}
}
#endif // ESP32
@ -639,56 +854,11 @@ Renderer *uDisplay::Init(void) {
pinMode(reset, OUTPUT);
digitalWrite(reset, HIGH);
delay(50);
digitalWrite(reset, LOW);
delay(50);
digitalWrite(reset, HIGH);
delay(200);
reset_pin(50, 200);
}
uint16_t index = 0;
while (1) {
uint8_t iob;
SPI_CS_LOW
send_spi_cmds(0, dsp_ncmds);
iob = dsp_cmds[index++];
ulcd_command(iob);
uint8_t args = dsp_cmds[index++];
#ifdef UDSP_DEBUG
Serial.printf("cmd, args %02x, %d ", iob, args&0x1f);
#endif
for (uint32_t cnt = 0; cnt < (args & 0x1f); cnt++) {
iob = dsp_cmds[index++];
#ifdef UDSP_DEBUG
Serial.printf("%02x ", iob );
#endif
if (!allcmd_mode) {
ulcd_data8(iob);
} else {
ulcd_command(iob);
}
}
SPI_CS_HIGH
#ifdef UDSP_DEBUG
Serial.printf("\n");
#endif
if (args & 0x80) { // delay after the command
uint32_t delay_ms = 0;
switch (args & 0xE0) {
case 0x80: delay_ms = 150; break;
case 0xA0: delay_ms = 10; break;
case 0xE0: delay_ms = 500; break;
}
if (delay_ms > 0) {
delay(delay_ms);
#ifdef UDSP_DEBUG
Serial.printf("delay %d ms\n", delay_ms);
#endif
}
}
if (index >= dsp_ncmds) break;
}
SPI_END_TRANSACTION
}
@ -795,10 +965,7 @@ Renderer *uDisplay::Init(void) {
pinMode(reset, OUTPUT);
digitalWrite(reset, HIGH);
delay(50);
digitalWrite(reset, LOW);
delay(50);
digitalWrite(reset, HIGH);
delay(200);
reset_pin(50, 200);
}
esp_lcd_i80_bus_config_t bus_config = {
@ -900,8 +1067,8 @@ Renderer *uDisplay::Init(void) {
// must init luts on epaper
if (ep_mode) {
Init_EPD(DISPLAY_INIT_FULL);
if (ep_mode == 1) Init_EPD(DISPLAY_INIT_PARTIAL);
if (ep_mode == 2) Init_EPD(DISPLAY_INIT_FULL);
//if (ep_mode == 1) Init_EPD(DISPLAY_INIT_PARTIAL);
}
#ifdef UDSP_DEBUG
@ -910,18 +1077,23 @@ Renderer *uDisplay::Init(void) {
return this;
}
void uDisplay::DisplayInit(int8_t p, int8_t size, int8_t rot, int8_t font) {
if (p != DISPLAY_INIT_MODE && ep_mode) {
ep_update_mode = p;
if (p == DISPLAY_INIT_PARTIAL) {
if (lutpsize) {
#ifdef UDSP_DEBUG
Serial.printf("init partial epaper mode\n");
#endif
SetLut(lut_partial);
Updateframe_EPD();
delay(lutptime * 10);
delay_sync(lutptime * 10);
}
return;
} else if (p == DISPLAY_INIT_FULL) {
#ifdef UDSP_DEBUG
Serial.printf("init full epaper mode\n");
#endif
if (lutfsize) {
SetLut(lut_full);
Updateframe_EPD();
@ -930,7 +1102,7 @@ void uDisplay::DisplayInit(int8_t p, int8_t size, int8_t rot, int8_t font) {
ClearFrame_42();
DisplayFrame_42();
}
delay(lutftime * 10);
delay_sync(lutftime * 10);
return;
}
} else {
@ -953,6 +1125,36 @@ void uDisplay::DisplayInit(int8_t p, int8_t size, int8_t rot, int8_t font) {
}
}
void uDisplay::reset_pin(int32_t msl, int32_t msh) {
if (reset > 0) {
digitalWrite(reset, LOW);
delay(msl);
digitalWrite(reset, HIGH);
delay(msh);
}
}
#define UDSP_BUSY_TIMEOUT 3000
// epaper sync or delay
void uDisplay::delay_sync(int32_t ms) {
uint8_t busy_level = HIGH;
if (lvgl_param.busy_invert) {
busy_level = LOW;
}
uint32_t time = millis();
if (busy_pin > 0) {
while (digitalRead(busy_pin) == busy_level) {
delay(1);
if ((millis() - time) > UDSP_BUSY_TIMEOUT) {
break;
}
}
} else {
delay(ms);
}
}
void uDisplay::ulcd_command(uint8_t val) {
@ -1462,12 +1664,16 @@ void uDisplay::Splash(void) {
if (ep_mode) {
Updateframe();
delay(lut3time * 10);
delay_sync(lut3time * 10);
}
setTextFont(splash_font);
setTextSize(splash_size);
DrawStringAt(splash_xp, splash_yp, dname, fg_col, 0);
Updateframe();
#ifdef UDSP_DEBUG
Serial.printf("draw splash\n");
#endif
}
void uDisplay::setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) {
@ -2116,7 +2322,7 @@ uint32_t uDisplay::str2c(char **sp, char *vp, uint32_t len) {
}
}
} else {
uint8_t slen = strlen(lp);
uint16_t slen = strlen(lp);
if (slen) {
strlcpy(vp, *sp, len);
*sp = lp + slen;
@ -2320,9 +2526,9 @@ void uDisplay::Init_EPD(int8_t p) {
ClearFrame_42();
}
if (p == DISPLAY_INIT_PARTIAL) {
delay(lutptime * 10);
delay_sync(lutptime * 10);
} else {
delay(lutftime * 10);
delay_sync(lutftime * 10);
}
}
@ -2338,58 +2544,66 @@ 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 (index = 0; index < MAX_LUTS; index++) {
spi_command_EPD(lut_cmd[index]);
for (count = 0; count < lut_cnt[index]; count++) {
spi_data8_EPD(lut_array[count][index]);
spi_data8_EPD(lut_array[index][count]);
}
}
}
void uDisplay::DisplayFrame_42(void) {
uint16_t Width, Height;
Width = (gxs % 8 == 0) ? (gxs / 8 ): (gxs / 8 + 1);
Height = gys;
spi_command_EPD(saw_1);
for(int i = 0; i < gxs / 8 * gys; i++) {
spi_data8_EPD(0xFF);
}
delay(2);
spi_command_EPD(saw_2);
for (uint16_t j = 0; j < Height; j++) {
for (uint16_t i = 0; i < Width; i++) {
spi_data8_EPD(framebuffer[i + j * Width] ^ 0xff);
}
for(int i = 0; i < gxs / 8 * gys; i++) {
spi_data8_EPD(framebuffer[i]^0xff);
}
delay(2);
SetLuts();
spi_command_EPD(saw_3);
delay(100);
delay_sync(100);
#ifdef UDSP_DEBUG
Serial.printf("EPD Diplayframe\n");
#endif
}
void uDisplay::ClearFrame_42(void) {
uint16_t Width, Height;
Width = (gxs % 8 == 0)? (gxs / 8 ): (gxs / 8 + 1);
Height = gys;
void uDisplay::ClearFrame_42(void) {
spi_command_EPD(saw_1);
for (uint16_t j = 0; j < Height; j++) {
for (uint16_t i = 0; i < Width; i++) {
for (uint16_t j = 0; j < gys; j++) {
for (uint16_t i = 0; i < gxs; 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++) {
for (uint16_t j = 0; j < gys; j++) {
for (uint16_t i = 0; i < gxs; i++) {
spi_data8_EPD(0xFF);
}
}
spi_command_EPD(saw_3);
delay(100);
delay_sync(100);
#ifdef UDSP_DEBUG
Serial.printf("EPD Clearframe\n");
#endif
}
void uDisplay::SetLut(const unsigned char* lut) {
spi_command_EPD(WRITE_LUT_REGISTER);
//spi_command_EPD(WRITE_LUT_REGISTER);
spi_command_EPD(lut_cmd[0]);
/* the length of look-up table is 30 bytes */
for (int i = 0; i < lutfsize; i++) {
spi_data8_EPD(lut[i]);
@ -2398,8 +2612,21 @@ void uDisplay::SetLut(const unsigned char* lut) {
void uDisplay::Updateframe_EPD(void) {
if (ep_mode == 1) {
SetFrameMemory(framebuffer, 0, 0, gxs, gys);
DisplayFrame_29();
switch (ep_update_mode) {
case DISPLAY_INIT_PARTIAL:
if (epc_part_cnt) {
send_spi_cmds(epcoffs_part, epc_part_cnt);
}
break;
case DISPLAY_INIT_FULL:
if (epc_full_cnt) {
send_spi_cmds(epcoffs_full, epc_full_cnt);
}
break;
default:
SetFrameMemory(framebuffer, 0, 0, gxs, gys);
DisplayFrame_29();
}
} else {
DisplayFrame_42();
}
@ -2443,6 +2670,28 @@ void uDisplay::SetMemoryPointer(int x, int y) {
spi_data8_EPD((y >> 8) & 0xFF);
}
#if 0
void uDisplay::Send_EP_Data() {
for (int i = 0; i < gys / 8 * gys; i++) {
spi_data8_EPD(framebuffer[i]^0xff);
}
}
#else
void uDisplay::Send_EP_Data() {
uint16_t image_width = gxs & 0xFFF8;
uint16_t x = 0;
uint16_t y = 0;
uint16_t x_end = gxs - 1;
uint16_t y_end = gys - 1;
for (uint16_t j = 0; j < y_end - y + 1; j++) {
for (uint16_t i = 0; i < (x_end - x + 1) / 8; i++) {
spi_data8_EPD(framebuffer[i + j * (image_width / 8)]^0xff);
}
}
}
#endif
void uDisplay::SetFrameMemory(
const unsigned char* image_buffer,
uint16_t x,

View File

@ -48,6 +48,8 @@ static inline void gpio_lo(int_fast8_t pin) { if (pin >= 0) *get_gpio_lo_reg(pin
#define UDISP1_WHITE 1
#define UDISP1_BLACK 0
#define MAX_LUTS 5
#define DISPLAY_INIT_MODE 0
#define DISPLAY_INIT_PARTIAL 1
#define DISPLAY_INIT_FULL 2
@ -107,7 +109,6 @@ enum uColorType { uCOLOR_BW, uCOLOR_COLOR };
#define SPI_DC_LOW if (spi_dc >= 0) GPIO_CLR_SLOW(spi_dc);
#define SPI_DC_HIGH if (spi_dc >= 0) GPIO_SET_SLOW(spi_dc);
#define LUTMAXSIZE 64
#ifdef USE_ESP32_S3
struct esp_lcd_i80_bus_t {
@ -245,7 +246,7 @@ class uDisplay : public Renderer {
uint8_t i2c_page_start;
uint8_t i2c_page_end;
int8_t reset;
uint8_t dsp_cmds[128];
uint8_t dsp_cmds[256];
uint8_t dsp_ncmds;
uint8_t dsp_on;
uint8_t dsp_off;
@ -289,16 +290,27 @@ class uDisplay : public Renderer {
uint8_t dim_op;
uint8_t lutfsize;
uint8_t lutpsize;
uint16_t lutftime;
int16_t lutftime;
int8_t busy_pin;
uint16_t lutptime;
uint16_t lut3time;
uint16_t lut_num;
uint8_t ep_mode;
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];
uint8_t ep_update_mode;
uint8_t *lut_full;
uint8_t lut_siz_full;
uint8_t *lut_partial;
uint8_t lut_siz_partial;
uint8_t epcoffs_full;
uint8_t epc_full_cnt;
uint8_t epcoffs_part;
uint8_t epc_part_cnt;
uint8_t *lut_array[MAX_LUTS];
uint8_t lut_cnt[MAX_LUTS];
uint8_t lut_cmd[MAX_LUTS];
uint8_t lut_siz[MAX_LUTS];
uint16_t seta_xp1;
uint16_t seta_xp2;
uint16_t seta_yp1;
@ -308,6 +320,11 @@ class uDisplay : public Renderer {
int16_t rotmap_ymin;
int16_t rotmap_ymax;
void pushColorsMono(uint16_t *data, uint16_t len, bool rgb16_swap = false);
void delay_sync(int32_t time);
void reset_pin(int32_t delayl, int32_t delayh);
void delay_arg(uint32_t arg);
void Send_EP_Data(void);
void send_spi_cmds(uint16_t cmd_offset, uint16_t cmd_size);
#ifdef USE_ESP32_S3
int8_t par_cs;

View File

@ -1,4 +1,4 @@
:H,E-PAPER-29,128,296,1,SPI,1,*,*,*,*,*,*,*,10
:H,E-PAPER-29-V1,128,296,1,SPI,3,*,*,*,*,*,*,*,10
:S,1,1,1,0,10,10
:I
01,3,27,01,00
@ -7,10 +7,23 @@
3A,1,1A
3B,1,08
11,1,03
:L
62,0
:f
61,0
68,0
22,1,c4
20,0
ff,0
:p
62,0
68,0
22,1,c4
20,0
ff,0
:L,30,32
02,02,01,11,12,12,22,22,66,69,69,59,58,99,99
88,00,00,00,00,F8,B4,13,51,35,51,51,19,01,00
:l
:l,30,32
10,18,18,08,18,18,08,00,00,00,00,00,00,00,00
00,00,00,00,00,13,14,44,12,00,00,00,00,00,00
:T,350,35,10

View File

@ -0,0 +1,96 @@
:H,E-PAPER-29-V2,128,296,1,SPI,4,*,*,*,*,*,*,*,10
:S,1,1,1,0,10,10
:I
12,0
63,1,80
01,3,27,01,00
11,1,03
64,0
21,2,00,80
65,0
63,1,80
61,0
63,1,80
3f,1,22
03,1,17
04,3,41,00,32
2c,1,36
67,0
22,1,c7;
20,0
63,1,80
24,0
66,0
22,1,c7
20,0
63,1,80
62
:f
64,0
65,0
24,0
66,0
22,1,c7
20,0
63,1,80
:p
60,1,2
62,0
63,1,80
37,0a,00,00,00,00,00,40,00,00,00,00
3c,1,80
22,1,c0
20,0
63,1,80
64,0
65,0
24,0
66,0
22,1,0f
20,0
63,1,80
62,0
:L,153,32
80,66,00,00,00,00,00,00,40,00,00,00
10,66,00,00,00,00,00,00,20,00,00,00
80,66,00,00,00,00,00,00,40,00,00,00
10,66,00,00,00,00,00,00,20,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00
14,08,00,00,00,00,01
0A,0A,00,0A,0A,00,01
00,00,00,00,00,00,00
00,00,00,00,00,00,00
00,00,00,00,00,00,00
00,00,00,00,00,00,00
00,00,00,00,00,00,00
00,00,00,00,00,00,00
14,08,00,01,00,00,01
00,00,00,00,00,00,01
00,00,00,00,00,00,00
00,00,00,00,00,00,00
44,44,44,44,44,44,00,00,00
:l,153,32
00,40,00,00,00,00,00,00,00,00,00,00
80,80,00,00,00,00,00,00,00,00,00,00
40,40,00,00,00,00,00,00,00,00,00,00
00,80,00,00,00,00,00,00,00,00,00,00
00,00,00,00,00,00,00,00,00,00,00,00
0A,00,00,00,00,00,02
01,00,00,00,00,00,00
01,00,00,00,00,00,00
00,00,00,00,00,00,00
00,00,00,00,00,00,00
00,00,00,00,00,00,00
00,00,00,00,00,00,00
00,00,00,00,00,00,00
00,00,00,00,00,00,00
00,00,00,00,00,00,00
00,00,00,00,00,00,00
00,00,00,00,00,00,00
22,22,22,22,22,22,00,00,00
:T,350,35,10
#

View File

@ -1,25 +1,26 @@
:H,E-PAPER-42,400,300,1,SPI,1,*,*,*,*,*,*,*,10
:H,E-PAPER-42,400,300,1,SPI,4,*,*,*,*,*,*,*,10
:S,1,1,1,0,10,10
:B,60,8
:I
01,5,03,00,2b,2b,03
01,5,03,00,2b,2b,ff
06,3,17,17,17
04,80
00,1,3F
30,1,3C
61,4,01,90,01,2C
82,1,28
82,1,12
50,1,97
:A,10,13,12
:a,10,13,12
:T,450,10,450
:L1,20
00,17,00,00,00,02
:L1,44,20
40,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
:L2,42,21
40,17,00,00,00,02
90,17,17,00,00,02
40,0A,01,00,00,01
@ -27,15 +28,15 @@ 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
:L3,42,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
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
:L4,23
:L4,42,23
80,17,00,00,00,02
90,17,17,00,00,02
80,0A,01,00,00,01
@ -43,7 +44,7 @@ A0,0A,01,00,00,01
00,00,00,00,00,00
00,00,00,00,00,00
00,00,00,00,00,00
:L5,24
:L5,42,24
80,17,00,00,00,02
90,17,17,00,00,02
80,0A,01,00,00,01

View File

@ -50,7 +50,9 @@ extern uint16_t fg_color;
extern uint16_t bg_color;
#endif
#ifndef DISPDESC_SIZE
#define DISPDESC_SIZE 1000
#endif
void Core2DisplayPower(uint8_t on);
void Core2DisplayDim(uint8_t dim);
@ -94,6 +96,11 @@ int8_t cs;
fp = ffsp->open(DISP_DESC_FILE, "r");
if (fp > 0) {
uint32_t size = fp.size();
if (size > DISPDESC_SIZE - 50) {
free(fbuff);
fbuff = (char*)calloc(size + 50, 1);
if (!fbuff) return 0;
}
fp.read((uint8_t*)fbuff, size);
fp.close();
ddesc = fbuff;
@ -148,6 +155,7 @@ int8_t cs;
if (fbuff) free(fbuff);
return 0;
}
// now replace tasmota vars before passing to driver
char *cp = strstr(ddesc, "I2C");
if (cp) {
@ -296,6 +304,7 @@ int8_t cs;
delete renderer;
AddLog(LOG_LEVEL_DEBUG, PSTR("DSP: reinit"));
}
udisp = new uDisplay(ddesc);
// checck for touch option TI1 or TI2