Merge pull request #11753 from gemu2015/udisp

update universal display
This commit is contained in:
Theo Arends 2021-04-17 09:02:56 +02:00 committed by GitHub
commit 4155b5b90e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 660 additions and 85 deletions

View File

@ -18,8 +18,6 @@
*/ */
#include <Arduino.h> #include <Arduino.h>
#include <Wire.h>
#include <SPI.h>
#include "uDisplay.h" #include "uDisplay.h"
#define UDSP_DEBUG #define UDSP_DEBUG
@ -42,6 +40,14 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) {
sa_mode = 16; sa_mode = 16;
saw_3 = 0xff; saw_3 = 0xff;
dim_op = 0xff; dim_op = 0xff;
dsp_off = 0xff;
dsp_on = 0xff;
lutpsize = 0;
lutfsize = 0;
lutptime = 35;
lutftime = 350;
lut3time = 10;
ep_mode = 0;
startline = 0xA1; startline = 0xA1;
uint8_t section = 0; uint8_t section = 0;
dsp_ncmds = 0; dsp_ncmds = 0;
@ -174,10 +180,20 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) {
rot_t[3] = next_hex(&lp1); rot_t[3] = next_hex(&lp1);
break; break;
case 'A': case 'A':
saw_1 = next_hex(&lp1); if (interface == _UDSP_I2C) {
saw_2 = next_hex(&lp1); saw_1 = next_hex(&lp1);
saw_3 = next_hex(&lp1); i2c_page_start = next_hex(&lp1);
sa_mode = next_val(&lp1); i2c_page_end = next_hex(&lp1);
saw_2 = next_hex(&lp1);
i2c_col_start = next_hex(&lp1);
i2c_col_end = next_hex(&lp1);
saw_3 = next_hex(&lp1);
} else {
saw_1 = next_hex(&lp1);
saw_2 = next_hex(&lp1);
saw_3 = next_hex(&lp1);
sa_mode = next_val(&lp1);
}
break; break;
case 'P': case 'P':
col_mode = next_val(&lp1); col_mode = next_val(&lp1);
@ -189,6 +205,31 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) {
case 'D': case 'D':
dim_op = next_hex(&lp1); dim_op = next_hex(&lp1);
break; break;
case 'L':
while (1) {
if (!str2c(&lp1, ibuff, sizeof(ibuff))) {
lut_full[lutfsize++] = strtol(ibuff, 0, 16);
} else {
break;
}
if (lutfsize >= sizeof(lut_full)) break;
}
break;
case 'l':
while (1) {
if (!str2c(&lp1, ibuff, sizeof(ibuff))) {
lut_partial[lutpsize++] = strtol(ibuff, 0, 16);
} else {
break;
}
if (lutpsize >= sizeof(lut_partial)) break;
}
break;
case 'T':
lutftime = next_val(&lp1);
lutptime = next_val(&lp1);
lut3time = next_val(&lp1);
break;
} }
} }
} }
@ -200,26 +241,54 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) {
lp++; lp++;
} }
} }
if (lutfsize && lutpsize) {
ep_mode = 1;
}
#ifdef UDSP_DEBUG #ifdef UDSP_DEBUG
Serial.printf("Nr. : %d\n", spi_nr);
Serial.printf("CS : %d\n", spi_cs);
Serial.printf("CLK : %d\n", spi_clk);
Serial.printf("MOSI: %d\n", spi_mosi);
Serial.printf("DC : %d\n", spi_dc);
Serial.printf("BPAN: %d\n", bpanel);
Serial.printf("RES : %d\n", reset);
Serial.printf("MISO: %d\n", spi_miso);
Serial.printf("SPED: %d\n", spi_speed*1000000);
Serial.printf("Pixels: %d\n", col_mode);
Serial.printf("SaMode: %d\n", sa_mode);
Serial.printf("xs : %d\n", gxs);
Serial.printf("ys : %d\n", gys);
Serial.printf("bpp: %d\n", bpp);
Serial.printf("opts: %02x,%02x,%02x\n", saw_3, dim_op, startline); if (interface == _UDSP_SPI) {
Serial.printf("Nr. : %d\n", spi_nr);
Serial.printf("CS : %d\n", spi_cs);
Serial.printf("CLK : %d\n", spi_clk);
Serial.printf("MOSI: %d\n", spi_mosi);
Serial.printf("DC : %d\n", spi_dc);
Serial.printf("BPAN: %d\n", bpanel);
Serial.printf("RES : %d\n", reset);
Serial.printf("MISO: %d\n", spi_miso);
Serial.printf("SPED: %d\n", spi_speed*1000000);
Serial.printf("Pixels: %d\n", col_mode);
Serial.printf("SaMode: %d\n", sa_mode);
Serial.printf("SetAddr : %x,%x,%x\n", saw_1, saw_2, saw_3); Serial.printf("opts: %02x,%02x,%02x\n", saw_3, dim_op, startline);
Serial.printf("Rot 0: %x,%x - %d - %d\n", madctrl, rot[0], x_addr_offs[0], y_addr_offs[0]); Serial.printf("SetAddr : %x,%x,%x\n", saw_1, saw_2, saw_3);
Serial.printf("Rot 0: %x,%x - %d - %d\n", madctrl, rot[0], x_addr_offs[0], y_addr_offs[0]);
if (ep_mode) {
Serial.printf("LUT_Partial : %d\n", lutpsize);
Serial.printf("LUT_Full : %d\n", lutfsize);
}
}
if (interface == _UDSP_I2C) {
Serial.printf("Addr : %02x\n", i2caddr);
Serial.printf("SCL : %d\n", i2c_scl);
Serial.printf("SDA : %d\n", i2c_sda);
Serial.printf("SPA : %x\n", saw_1);
Serial.printf("pa_sta: %x\n", i2c_page_start);
Serial.printf("pa_end: %x\n", i2c_page_end);
Serial.printf("SCA : %x\n", saw_2);
Serial.printf("ca_sta: %x\n", i2c_col_start);
Serial.printf("pa_end: %x\n", i2c_col_end);
Serial.printf("WRA : %x\n", saw_3);
}
#endif #endif
} }
@ -237,26 +306,46 @@ Renderer *uDisplay::Init(void) {
} }
if (interface == _UDSP_I2C) { if (interface == _UDSP_I2C) {
Wire.begin(i2c_sda, i2c_scl); wire = &Wire;
wire->begin(i2c_sda, i2c_scl);
if (bpp < 16) { if (bpp < 16) {
if (buffer) free(buffer); if (buffer) free(buffer);
#ifdef ESP8266 #ifdef ESP8266
buffer = (uint8_t*)calloc((width()*height()*bpp)/8, 1); buffer = (uint8_t*)calloc((gxs * gys * bpp) / 8, 1);
#else #else
if (psramFound()) { if (psramFound()) {
buffer = (uint8_t*)heap_caps_malloc((width()*height()*bpp)/8, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); buffer = (uint8_t*)heap_caps_malloc((gxs * gys * bpp) / 8, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
} else { } else {
buffer = (uint8_t*)calloc((width()*height()*bpp)/8, 1); buffer = (uint8_t*)calloc((gxs * gys * bpp) / 8, 1);
} }
#endif #endif
} }
#ifdef UDSP_DEBUG
Serial.printf("I2C cmds: %d\n", dsp_ncmds);
#endif
for (uint32_t cnt = 0; cnt < dsp_ncmds; cnt++) { for (uint32_t cnt = 0; cnt < dsp_ncmds; cnt++) {
i2c_command(dsp_cmds[cnt]); i2c_command(dsp_cmds[cnt]);
#ifdef UDSP_DEBUG
Serial.printf("cmd = %x\n", dsp_cmds[cnt]);
#endif
} }
} }
if (interface == _UDSP_SPI) { if (interface == _UDSP_SPI) {
if (ep_mode) {
#ifdef ESP8266
buffer = (uint8_t*)calloc((gxs * gys * bpp) / 8, 1);
#else
if (psramFound()) {
buffer = (uint8_t*)heap_caps_malloc((gxs * gys * bpp) / 8, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
} else {
buffer = (uint8_t*)calloc((gxs * gys * bpp) / 8, 1);
}
#endif
}
if (bpanel >= 0) { if (bpanel >= 0) {
#ifdef ESP32 #ifdef ESP32
ledcSetup(ESP32_PWM_CHANNEL, 4000, 8); ledcSetup(ESP32_PWM_CHANNEL, 4000, 8);
@ -285,8 +374,6 @@ Renderer *uDisplay::Init(void) {
digitalWrite(spi_clk, LOW); digitalWrite(spi_clk, LOW);
pinMode(spi_mosi, OUTPUT); pinMode(spi_mosi, OUTPUT);
digitalWrite(spi_mosi, LOW); digitalWrite(spi_mosi, LOW);
pinMode(spi_dc, OUTPUT);
digitalWrite(spi_dc, LOW);
} }
#endif // ESP8266 #endif // ESP8266
@ -302,8 +389,6 @@ Renderer *uDisplay::Init(void) {
digitalWrite(spi_clk, LOW); digitalWrite(spi_clk, LOW);
pinMode(spi_mosi, OUTPUT); pinMode(spi_mosi, OUTPUT);
digitalWrite(spi_mosi, LOW); digitalWrite(spi_mosi, LOW);
pinMode(spi_dc, OUTPUT);
digitalWrite(spi_dc, LOW);
} }
#endif // ESP32 #endif // ESP32
@ -321,7 +406,7 @@ Renderer *uDisplay::Init(void) {
uint8_t args = dsp_cmds[index++]; uint8_t args = dsp_cmds[index++];
#ifdef UDSP_DEBUG #ifdef UDSP_DEBUG
Serial.printf("cmd, args %x, %d ", iob, args&0x1f); Serial.printf("cmd, args %02x, %d ", iob, args&0x1f);
#endif #endif
for (uint32_t cnt = 0; cnt < (args & 0x1f); cnt++) { for (uint32_t cnt = 0; cnt < (args & 0x1f); cnt++) {
iob = dsp_cmds[index++]; iob = dsp_cmds[index++];
@ -343,10 +428,35 @@ Renderer *uDisplay::Init(void) {
SPI_END_TRANSACTION SPI_END_TRANSACTION
} }
// must init luts on epaper
if (ep_mode) {
Init_EPD(DISPLAY_INIT_FULL);
Init_EPD(DISPLAY_INIT_PARTIAL);
}
return this; return this;
} }
void uDisplay::DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font) {
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_PARTIAL) {
if (lutpsize) {
SetLut(lut_partial);
Updateframe_EPD();
delay(lutptime * 10);
}
return;
} else if (p == DISPLAY_INIT_FULL) {
if (lutfsize) {
SetLut(lut_full);
Updateframe_EPD();
delay(lutftime * 10);
}
return;
}
} else {
setRotation(rot); setRotation(rot);
invertDisplay(false); invertDisplay(false);
setTextWrap(false); setTextWrap(false);
@ -357,6 +467,11 @@ void uDisplay::DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font) {
setCursor(0,0); setCursor(0,0);
fillScreen(bg_col); fillScreen(bg_col);
Updateframe(); Updateframe();
#ifdef UDSP_DEBUG
Serial.printf("Dsp Init complete \n");
#endif
}
} }
void uDisplay::spi_command(uint8_t val) { void uDisplay::spi_command(uint8_t val) {
@ -444,25 +559,59 @@ void uDisplay::spi_command_one(uint8_t val) {
void uDisplay::i2c_command(uint8_t val) { void uDisplay::i2c_command(uint8_t val) {
//Serial.printf("%02x\n",val ); //Serial.printf("%02x\n",val );
Wire.beginTransmission(i2caddr); wire->beginTransmission(i2caddr);
Wire.write(0); wire->write(0);
Wire.write(val); wire->write(val);
Wire.endTransmission(); wire->endTransmission();
} }
#define WIRE_MAX 32
void uDisplay::Updateframe(void) { void uDisplay::Updateframe(void) {
if (ep_mode) {
Updateframe_EPD();
return;
}
if (interface == _UDSP_I2C) { if (interface == _UDSP_I2C) {
i2c_command(saw_1 | 0x0); // low col = 0
i2c_command(saw_2 | 0x0); // hi col = 0 #if 0
i2c_command(saw_3 | 0x0); // line #0 i2c_command(saw_1);
i2c_command(i2c_page_start);
i2c_command(i2c_page_end);
i2c_command(saw_2);
i2c_command(i2c_col_start);
i2c_command(i2c_col_end);
uint16_t count = gxs * ((gys + 7) / 8);
uint8_t *ptr = buffer;
wire->beginTransmission(i2caddr);
i2c_command(saw_3);
uint8_t bytesOut = 1;
while (count--) {
if (bytesOut >= WIRE_MAX) {
wire->endTransmission();
wire->beginTransmission(i2caddr);
i2c_command(saw_3);
bytesOut = 1;
}
i2c_command(*ptr++);
bytesOut++;
}
wire->endTransmission();
#else
i2c_command(saw_1 | 0x0); // set low col = 0, 0x00
i2c_command(i2c_page_start | 0x0); // set hi col = 0, 0x10
i2c_command(i2c_page_end | 0x0); // set startline line #0, 0x40
uint8_t ys = gys >> 3; uint8_t ys = gys >> 3;
uint8_t xs = gxs >> 3; uint8_t xs = gxs >> 3;
//uint8_t xs = 132 >> 3; //uint8_t xs = 132 >> 3;
uint8_t m_row = 0; uint8_t m_row = saw_2;
uint8_t m_col = 2; uint8_t m_col = i2c_col_start;
uint16_t p = 0; uint16_t p = 0;
@ -470,24 +619,32 @@ void uDisplay::Updateframe(void) {
for ( i = 0; i < ys; i++) { for ( i = 0; i < ys; i++) {
// send a bunch of data in one xmission // send a bunch of data in one xmission
i2c_command(0xB0 + i + m_row);//set page address i2c_command(0xB0 + i + m_row); //set page address
i2c_command(m_col & 0xf);//set lower column address i2c_command(m_col & 0xf); //set lower column address
i2c_command(0x10 | (m_col >> 4));//set higher column address i2c_command(0x10 | (m_col >> 4)); //set higher column address
for( j = 0; j < 8; j++){ for ( j = 0; j < 8; j++) {
Wire.beginTransmission(i2caddr); wire->beginTransmission(i2caddr);
Wire.write(0x40); wire->write(0x40);
for ( k = 0; k < xs; k++, p++) { for ( k = 0; k < xs; k++, p++) {
Wire.write(buffer[p]); wire->write(buffer[p]);
} }
Wire.endTransmission(); wire->endTransmission();
}
} }
} }
#endif
}
} }
void uDisplay::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) { void uDisplay::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) {
if (ep_mode) {
drawFastVLine_EPD(x, y, h, color);
return;
}
if (interface != _UDSP_SPI) { if (interface != _UDSP_SPI) {
Renderer::drawFastVLine(x, y, h, color); Renderer::drawFastVLine(x, y, h, color);
return; return;
@ -528,6 +685,12 @@ void uDisplay::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) {
void uDisplay::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) { void uDisplay::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) {
if (ep_mode) {
drawFastHLine_EPD(x, y, w, color);
return;
}
if (interface != _UDSP_SPI) { if (interface != _UDSP_SPI) {
Renderer::drawFastHLine(x, y, w, color); Renderer::drawFastHLine(x, y, w, color);
return; return;
@ -575,6 +738,12 @@ void uDisplay::fillScreen(uint16_t color) {
// fill a rectangle // fill a rectangle
void uDisplay::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) { void uDisplay::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) {
if (ep_mode) {
fillRect_EPD(x, y, w, h, color);
return;
}
if (interface != _UDSP_SPI) { if (interface != _UDSP_SPI) {
Renderer::fillRect(x, y, w, h, color); Renderer::fillRect(x, y, w, h, color);
return; return;
@ -646,6 +815,9 @@ for(y=h; y>0; y--) {
void uDisplay::Splash(void) { void uDisplay::Splash(void) {
if (ep_mode) {
delay(lut3time * 10);
}
setTextFont(splash_font); setTextFont(splash_font);
setTextSize(splash_size); setTextSize(splash_size);
DrawStringAt(splash_xp, splash_yp, dname, fg_col, 0); DrawStringAt(splash_xp, splash_yp, dname, fg_col, 0);
@ -670,7 +842,7 @@ void uDisplay::setAddrWindow_int(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
x += x_addr_offs[cur_rot]; x += x_addr_offs[cur_rot];
y += y_addr_offs[cur_rot]; y += y_addr_offs[cur_rot];
if (sa_mode == 16) { if (sa_mode != 8) {
uint32_t xa = ((uint32_t)x << 16) | (x+w-1); uint32_t xa = ((uint32_t)x << 16) | (x+w-1);
uint32_t ya = ((uint32_t)y << 16) | (y+h-1); uint32_t ya = ((uint32_t)y << 16) | (y+h-1);
@ -735,11 +907,19 @@ void uDisplay::WriteColor(uint16_t color) {
void uDisplay::drawPixel(int16_t x, int16_t y, uint16_t color) { void uDisplay::drawPixel(int16_t x, int16_t y, uint16_t color) {
if (ep_mode) {
drawPixel_EPD(x, y, color);
return;
}
if (interface != _UDSP_SPI) { if (interface != _UDSP_SPI) {
Renderer::drawPixel(x, y, color); Renderer::drawPixel(x, y, color);
return; return;
} }
if ((x < 0) || (x >= _width) || (y < 0) || (y >= _height)) return; if ((x < 0) || (x >= _width) || (y < 0) || (y >= _height)) return;
@ -763,7 +943,13 @@ void uDisplay::setRotation(uint8_t rotation) {
Renderer::setRotation(cur_rot); Renderer::setRotation(cur_rot);
return; return;
} }
if (interface == _UDSP_SPI) { if (interface == _UDSP_SPI) {
if (ep_mode) {
Renderer::setRotation(cur_rot);
return;
}
SPI_BEGIN_TRANSACTION SPI_BEGIN_TRANSACTION
SPI_CS_LOW SPI_CS_LOW
spi_command(madctrl); spi_command(madctrl);
@ -801,6 +987,10 @@ void udisp_bpwr(uint8_t on);
void uDisplay::DisplayOnff(int8_t on) { void uDisplay::DisplayOnff(int8_t on) {
if (ep_mode) {
return;
}
udisp_bpwr(on); udisp_bpwr(on);
if (interface == _UDSP_I2C) { if (interface == _UDSP_I2C) {
@ -811,7 +1001,7 @@ void uDisplay::DisplayOnff(int8_t on) {
} }
} else { } else {
if (on) { if (on) {
spi_command_one(dsp_on); if (dsp_on != 0xff) spi_command_one(dsp_on);
if (bpanel >= 0) { if (bpanel >= 0) {
#ifdef ESP32 #ifdef ESP32
ledcWrite(ESP32_PWM_CHANNEL, dimmer); ledcWrite(ESP32_PWM_CHANNEL, dimmer);
@ -821,7 +1011,7 @@ void uDisplay::DisplayOnff(int8_t on) {
} }
} else { } else {
spi_command_one(dsp_off); if (dsp_off != 0xff) spi_command_one(dsp_off);
if (bpanel >= 0) { if (bpanel >= 0) {
#ifdef ESP32 #ifdef ESP32
ledcWrite(ESP32_PWM_CHANNEL, 0); ledcWrite(ESP32_PWM_CHANNEL, 0);
@ -834,10 +1024,24 @@ void uDisplay::DisplayOnff(int8_t on) {
} }
void uDisplay::invertDisplay(boolean i) { void uDisplay::invertDisplay(boolean i) {
if (i) {
spi_command_one(inv_on); if (ep_mode) {
} else { return;
spi_command_one(inv_off); }
if (interface == _UDSP_SPI) {
if (i) {
spi_command_one(inv_on);
} else {
spi_command_one(inv_off);
}
}
if (interface == _UDSP_I2C) {
if (i) {
i2c_command(inv_on);
} else {
i2c_command(inv_off);
}
} }
} }
@ -845,22 +1049,30 @@ void udisp_dimm(uint8_t dim);
void uDisplay::dim(uint8_t dim) { void uDisplay::dim(uint8_t dim) {
dimmer = dim; dimmer = dim;
if (dimmer > 15) dimmer = 15;
dimmer = ((float)dimmer / 15.0) * 255.0; if (ep_mode) {
#ifdef ESP32 return;
if (bpanel >= 0) {
ledcWrite(ESP32_PWM_CHANNEL, dimmer);
} else {
udisp_dimm(dim);
} }
if (interface == _UDSP_SPI) {
if (dimmer > 15) dimmer = 15;
dimmer = ((float)dimmer / 15.0) * 255.0;
#ifdef ESP32
if (bpanel >= 0) {
ledcWrite(ESP32_PWM_CHANNEL, dimmer);
} else {
udisp_dimm(dim);
}
#endif #endif
if (dim_op != 0xff) {
SPI_BEGIN_TRANSACTION if (dim_op != 0xff) {
SPI_CS_LOW SPI_BEGIN_TRANSACTION
spi_command(dim_op); SPI_CS_LOW
spi_data8(dim); spi_command(dim_op);
SPI_CS_HIGH spi_data8(dim);
SPI_END_TRANSACTION SPI_CS_HIGH
SPI_END_TRANSACTION
}
} }
} }
@ -1033,3 +1245,249 @@ void USECACHE uDisplay::write32(uint32_t val) {
GPIO_SET(spi_clk); GPIO_SET(spi_clk);
} }
} }
// epaper section
// EPD2IN9 commands
#define DRIVER_OUTPUT_CONTROL 0x01
#define BOOSTER_SOFT_START_CONTROL 0x0C
#define GATE_SCAN_START_POSITION 0x0F
#define DEEP_SLEEP_MODE 0x10
#define DATA_ENTRY_MODE_SETTING 0x11
#define SW_RESET 0x12
#define TEMPERATURE_SENSOR_CONTROL 0x1A
#define MASTER_ACTIVATION 0x20
#define DISPLAY_UPDATE_CONTROL_1 0x21
#define DISPLAY_UPDATE_CONTROL_2 0x22
#define WRITE_RAM 0x24
#define WRITE_VCOM_REGISTER 0x2C
#define WRITE_LUT_REGISTER 0x32
#define SET_DUMMY_LINE_PERIOD 0x3A
#define SET_GATE_TIME 0x3B
#define BORDER_WAVEFORM_CONTROL 0x3C
#define SET_RAM_X_ADDRESS_START_END_POSITION 0x44
#define SET_RAM_Y_ADDRESS_START_END_POSITION 0x45
#define SET_RAM_X_ADDRESS_COUNTER 0x4E
#define SET_RAM_Y_ADDRESS_COUNTER 0x4F
#define TERMINATE_FRAME_READ_WRITE 0xFF
void uDisplay::spi_data8_EPD(uint8_t val) {
SPI_BEGIN_TRANSACTION
SPI_CS_LOW
spi_data8(val);
SPI_CS_HIGH
SPI_END_TRANSACTION
}
void uDisplay::spi_command_EPD(uint8_t val) {
SPI_BEGIN_TRANSACTION
SPI_CS_LOW
spi_command(val);
SPI_CS_HIGH
SPI_END_TRANSACTION
}
void uDisplay::Init_EPD(int8_t p) {
if (p == DISPLAY_INIT_PARTIAL) {
SetLut(lut_partial);
} else {
SetLut(lut_full);
}
ClearFrameMemory(0xFF);
Updateframe_EPD();
if (p == DISPLAY_INIT_PARTIAL) {
delay(lutptime * 10);
} else {
delay(lutftime * 10);
}
}
void uDisplay::ClearFrameMemory(unsigned char color) {
SetMemoryArea(0, 0, gxs - 1, gys - 1);
SetMemoryPointer(0, 0);
spi_command_EPD(WRITE_RAM);
/* send the color data */
for (int i = 0; i < gxs / 8 * gys; i++) {
spi_data8_EPD(color);
}
}
void uDisplay::SetLut(const unsigned char* lut) {
spi_command_EPD(WRITE_LUT_REGISTER);
/* the length of look-up table is 30 bytes */
for (int i = 0; i < lutfsize; i++) {
spi_data8_EPD(lut[i]);
}
}
void uDisplay::Updateframe_EPD(void) {
SetFrameMemory(buffer, 0, 0, gxs, gys);
DisplayFrame();
}
void uDisplay::DisplayFrame(void) {
spi_command_EPD(DISPLAY_UPDATE_CONTROL_2);
spi_data8_EPD(0xC4);
spi_command_EPD(MASTER_ACTIVATION);
spi_data8_EPD(TERMINATE_FRAME_READ_WRITE);
}
void uDisplay::SetMemoryArea(int x_start, int y_start, int x_end, int y_end) {
spi_command_EPD(SET_RAM_X_ADDRESS_START_END_POSITION);
/* x point must be the multiple of 8 or the last 3 bits will be ignored */
spi_data8_EPD((x_start >> 3) & 0xFF);
spi_data8_EPD((x_end >> 3) & 0xFF);
spi_command_EPD(SET_RAM_Y_ADDRESS_START_END_POSITION);
spi_data8_EPD(y_start & 0xFF);
spi_data8_EPD((y_start >> 8) & 0xFF);
spi_data8_EPD(y_end & 0xFF);
spi_data8_EPD((y_end >> 8) & 0xFF);
}
void uDisplay::SetFrameMemory(const unsigned char* image_buffer) {
SetMemoryArea(0, 0, gxs - 1, gys - 1);
SetMemoryPointer(0, 0);
spi_command_EPD(WRITE_RAM);
/* send the image data */
for (int i = 0; i < gxs / 8 * gys; i++) {
spi_data8_EPD(image_buffer[i] ^ 0xff);
}
}
void uDisplay::SetMemoryPointer(int x, int y) {
spi_command_EPD(SET_RAM_X_ADDRESS_COUNTER);
/* x point must be the multiple of 8 or the last 3 bits will be ignored */
spi_data8_EPD((x >> 3) & 0xFF);
spi_command_EPD(SET_RAM_Y_ADDRESS_COUNTER);
spi_data8_EPD(y & 0xFF);
spi_data8_EPD((y >> 8) & 0xFF);
}
void uDisplay::SetFrameMemory(
const unsigned char* image_buffer,
uint16_t x,
uint16_t y,
uint16_t image_width,
uint16_t image_height
) {
uint16_t x_end;
uint16_t 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 &= 0xFFF8;
image_width &= 0xFFF8;
if (x + image_width >= gxs) {
x_end = gxs - 1;
} else {
x_end = x + image_width - 1;
}
if (y + image_height >= gys) {
y_end = gys - 1;
} else {
y_end = y + image_height - 1;
}
if (!x && !y && image_width == gxs && image_height == gys) {
SetFrameMemory(image_buffer);
return;
}
SetMemoryArea(x, y, x_end, y_end);
SetMemoryPointer(x, y);
spi_command_EPD(WRITE_RAM);
/* send the image data */
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(image_buffer[i + j * (image_width / 8)]^0xff);
}
}
}
#define IF_INVERT_COLOR 1
#define renderer_swap(a, b) { int16_t t = a; a = b; b = t; }
/**
* @brief: this draws a pixel by absolute coordinates.
* this function won't be affected by the rotate parameter.
* we must use this for epaper because these displays have a strange and different bit pattern
*/
void uDisplay::DrawAbsolutePixel(int x, int y, int16_t color) {
int16_t w = width(), h = height();
if (cur_rot == 1 || cur_rot == 3) {
renderer_swap(w, h);
}
if (x < 0 || x >= w || y < 0 || y >= h) {
return;
}
if (IF_INVERT_COLOR) {
if (color) {
buffer[(x + y * w) / 8] |= 0x80 >> (x % 8);
} else {
buffer[(x + y * w) / 8] &= ~(0x80 >> (x % 8));
}
} else {
if (color) {
buffer[(x + y * w) / 8] &= ~(0x80 >> (x % 8));
} else {
buffer[(x + y * w) / 8] |= 0x80 >> (x % 8);
}
}
}
void uDisplay::drawPixel_EPD(int16_t x, int16_t y, uint16_t color) {
if (!buffer) return;
if ((x < 0) || (x >= width()) || (y < 0) || (y >= height()))
return;
// check rotation, move pixel around if necessary
switch (cur_rot) {
case 1:
renderer_swap(x, y);
x = gxs - x - 1;
break;
case 2:
x = gxs - x - 1;
y = gys - y - 1;
break;
case 3:
renderer_swap(x, y);
y = gys - y - 1;
break;
}
// x is which column
DrawAbsolutePixel(x, y, color);
}
void uDisplay::fillRect_EPD(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) {
for (uint32_t yp = y; yp < y + h; yp++) {
for (uint32_t xp = x; xp < x + w; xp++) {
drawPixel_EPD(xp , yp , color);
}
}
}
void uDisplay::drawFastVLine_EPD(int16_t x, int16_t y, int16_t h, uint16_t color) {
while (h--) {
drawPixel_EPD(x , y , color);
y++;
}
}
void uDisplay::drawFastHLine_EPD(int16_t x, int16_t y, int16_t w, uint16_t color) {
while (w--) {
drawPixel_EPD(x , y , color);
x++;
}
}

View File

@ -3,6 +3,8 @@
#include <Adafruit_GFX.h> #include <Adafruit_GFX.h>
#include <renderer.h> #include <renderer.h>
#include <Wire.h>
#include <SPI.h>
#define _UDSP_I2C 1 #define _UDSP_I2C 1
#define _UDSP_SPI 2 #define _UDSP_SPI 2
@ -10,6 +12,10 @@
#define UDISP1_WHITE 1 #define UDISP1_WHITE 1
#define UDISP1_BLACK 0 #define UDISP1_BLACK 0
#define DISPLAY_INIT_MODE 0
#define DISPLAY_INIT_PARTIAL 1
#define DISPLAY_INIT_FULL 2
enum uColorType { uCOLOR_BW, uCOLOR_COLOR }; enum uColorType { uCOLOR_BW, uCOLOR_COLOR };
// Color definitions // Color definitions
@ -93,7 +99,22 @@ class uDisplay : public Renderer {
void write32(uint32_t val); void write32(uint32_t val);
void spi_data9(uint8_t d, uint8_t dc); void spi_data9(uint8_t d, uint8_t dc);
void WriteColor(uint16_t color); void WriteColor(uint16_t color);
void SetLut(const unsigned char* lut);
void DisplayFrame(void);
void Updateframe_EPD();
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);
void SetMemoryPointer(int x, int y);
void DrawAbsolutePixel(int x, int y, int16_t color);
void drawPixel_EPD(int16_t x, int16_t y, uint16_t color);
void fillRect_EPD(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
void drawFastVLine_EPD(int16_t x, int16_t y, int16_t h, uint16_t color);
void drawFastHLine_EPD(int16_t x, int16_t y, int16_t w, uint16_t color);
void Init_EPD(int8_t p);
void spi_command_EPD(uint8_t val);
void spi_data8_EPD(uint8_t val);
void ClearFrameMemory(unsigned char color);
uint8_t strlen_ln(char *str); uint8_t strlen_ln(char *str);
int32_t next_val(char **sp); int32_t next_val(char **sp);
uint32_t next_hex(char **sp); uint32_t next_hex(char **sp);
@ -103,7 +124,12 @@ class uDisplay : public Renderer {
uint8_t interface; uint8_t interface;
uint8_t i2caddr; uint8_t i2caddr;
int8_t i2c_scl; int8_t i2c_scl;
TwoWire *wire;
int8_t i2c_sda; int8_t i2c_sda;
uint8_t i2c_col_start;
uint8_t i2c_col_end;
uint8_t i2c_page_start;
uint8_t i2c_page_end;
int8_t reset; int8_t reset;
uint8_t dsp_cmds[128]; uint8_t dsp_cmds[128];
uint8_t dsp_ncmds; uint8_t dsp_ncmds;
@ -144,6 +170,14 @@ class uDisplay : public Renderer {
uint8_t inv_off; uint8_t inv_off;
uint8_t sa_mode; uint8_t sa_mode;
uint8_t dim_op; uint8_t dim_op;
uint8_t lutfsize;
uint8_t lutpsize;
uint16_t lutftime;
uint16_t lutptime;
uint16_t lut3time;
uint8_t ep_mode;
uint8_t lut_full[64];
uint8_t lut_partial[64];
}; };

View File

@ -25,10 +25,11 @@ E1,0F,00,0E,14,03,11,07,31,C1,48,08,0F,0C,31,36,0F
29,80 29,80
:o,28 :o,28
:O,29 :O,29
:A,2A,2B,2C :A,2A,2B,2C,16
:R,36 :R,36
:0,48,00,00,00 :0,48,00,00,00
:1,28,00,00,01 :1,28,00,00,01
:2,88,00,00,02 :2,88,00,00,02
:3,E8,00,00,02 :3,E8,00,00,03
:i,20,21
# #

View File

@ -26,11 +26,12 @@ E1,0F,00,0E,14,03,11,07,31,C1,48,08,0F,0C,31,36,0F
29,80 29,80
:o,28 :o,28
:O,29 :O,29
:A,2A,2B,2C :A,2A,2B,2C,16
:R,36 :R,36
:0,08,00,00,00 :0,08,00,00,00
:1,A8,00,00,01 :1,A8,00,00,01
:2,C8,00,00,02 :2,C8,00,00,02
:3,68,00,00,03 :3,68,00,00,03
:i,21,20
:TI2,38,22,21 :TI2,38,22,21
# #

View File

@ -1,4 +1,4 @@
:H,ILI9488,480,320,16,SPI,1,*,*,*,*,*,*,-1,10 :H,ILI9488,480,320,16,SPI,1,*,*,*,*,*,*,*,10
:S,2,1,1,0,40,20 :S,2,1,1,0,40,20
:I :I
E0,0F,00,03,09,08,16,0A,3F,78,4C,09,0A,08,16,1A,0F E0,0F,00,03,09,08,16,0A,3F,78,4C,09,0A,08,16,1A,0F
@ -18,7 +18,7 @@ F7,4,A9,51,2C,82
29,0 29,0
:o,28 :o,28
:O,29 :O,29
:A,2A,2B,2C :A,2A,2B,2C,16
:R,36 :R,36
;:0,48,00,00,00 ;:0,48,00,00,00
:0,28,00,00,01 :0,28,00,00,01
@ -26,5 +26,6 @@ F7,4,A9,51,2C,82
:2,E8,00,00,03 :2,E8,00,00,03
:3,88,00,00,02 :3,88,00,00,02
:P,18 :P,18
:TI1,38,4,5 :i,20,21
:TI1,38,*,*
# #

View File

@ -0,0 +1,24 @@
:H,SD1306,128,64,1,I2C,3c,*,*,*
:S,0,2,1,0,30,20
:I
AE
D5,80
A8,3f
D3,00
40
8D,14
20,00
A1
C8
DA,12
81,9F
D9F1
DB,40
A4
A6
AF
:o,AE
:O,AF
:A,00,10,40,00,00
:i,A6,A7
#

View File

@ -19,5 +19,6 @@ A6
AF AF
:o,AE :o,AE
:O,AF :O,AF
:A,00,10,40 :A,00,10,40,00,02
:i,A6,A7
# #

View File

@ -1,4 +1,4 @@
:H,SSD1351,128,128,16,SPI,1,*,*,*,-1,-1,-1,-1,10 :H,SSD1351,128,128,16,SPI,1,*,*,*,*,*,*,*,10
:S,1,1,1,0,40,10 :S,1,1,1,0,40,10
:I :I
FD,1,12 FD,1,12

View File

@ -1,5 +1,5 @@
:H,ST7789,240,240,16,SPI,1,*,*,*,*,*,-1,-1,40 :H,ST7789,240,240,16,SPI,1,*,*,*,*,*,*,*,40
:S,2,1,3,0,80,30 :S,2,1,3,0,80,30
:I :I
01,A0 01,A0
@ -17,5 +17,6 @@
:1,A0,50,00,01 :1,A0,50,00,01
:2,00,00,00,02 :2,00,00,00,02
:3,60,00,00,03 :3,60,00,00,03
i:20,21
:TI2,38,32,23 :TI2,38,32,23
# #

View File

@ -0,0 +1,17 @@
H,E-PAPER-29,128,296,1,SPI,1,*,*,*,*,*,*,*,10
:S,1,1,1,0,10,10
:I
01,3,27,01,00
0C,3,D7,D6,9D
2C,1,A8
3A,1,1A
3B,1,08
11,1,03
:L
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
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,19 @@
Display Descriptor files for use with universal display driver.
2 (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.
2. scripter driven as a special section >d in scripter.
copy the file to a script section >d and place a ->displayreinit cmd into the >B section
(preferred for developing or modifying display driver)
3. rule buffer 3 driven
copy descriptor to rule buffer number 3 but do not enable rule 3
(descriptor may not contain ANY spaces in this mode)
(4.) compile the descriptor into driver.
convert the file to a const char array and place into source xdsp_universal.ino
and replace the example array there + #define DSP_ROM_DESC
for further info about display descriptors read the tasmota docs display part.
the current files define the standard resolutions. if you change the resolution settings
sometimes you also have to change some register values in the init or address map section

View File

@ -71,7 +71,8 @@ const char DSP_SAMPLE_DESC[] PROGMEM =
":o,AE\n" ":o,AE\n"
// switch display on // switch display on
":O,AF\n" ":O,AF\n"
":A,00,10,40\n" ":A,00,10,40,00,02\n"
":i,A6,A7\n"
"#\n"; "#\n";
#endif // DSP_ROM_DESC #endif // DSP_ROM_DESC
@ -117,6 +118,24 @@ char *fbuff;
} }
#endif // USE_SCRIPT #endif // USE_SCRIPT
#ifdef USE_RULES
if (!bitRead(Settings.rule_enabled, 2) && !ddesc) {
// only if rule3 is not enabled for rules
char *cp = Settings.rules[2];
while (*cp == ' ') cp++;
memcpy(fbuff, cp, DISPDESC_SIZE - 1);
if (fbuff[0] == ':' && fbuff[1] == 'H') {
// assume display descriptor, replace space with line feed
for (uint32_t cnt = 0; cnt < DISPDESC_SIZE; cnt++) {
if (fbuff[cnt] == ' ') fbuff[cnt] = '\n';
}
ddesc = fbuff;
AddLog(LOG_LEVEL_INFO, PSTR("DSP: Rule 3 descriptor used"));
}
}
#endif // USE_RULES
#ifdef DSP_ROM_DESC #ifdef DSP_ROM_DESC
if (!ddesc) { if (!ddesc) {
@ -176,17 +195,16 @@ char *fbuff;
} }
} }
// init renderer
if (udisp) delete udisp;
udisp = new uDisplay(ddesc);
/* /*
File fp; File fp;
fp = ffsp->open("/dump.txt", "w"); fp = ffsp->open("/dump.txt", "w");
fp.write((uint8_t*)ddesc, DISPDESC_SIZE); fp.write((uint8_t*)ddesc, DISPDESC_SIZE);
fp.close(); fp.close();
*/ */
// init renderer
if (udisp) delete udisp;
udisp = new uDisplay(ddesc);
// checck for touch option TI1 or TI2 // checck for touch option TI1 or TI2
#ifdef USE_FT5206 #ifdef USE_FT5206