Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# Editor
.vscode

# Prerequisites
*.d

Expand Down Expand Up @@ -59,4 +62,4 @@ build

# Kconfig files
sdkconfig
sdkconfig.old
sdkconfig.old
6 changes: 6 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ if(CONFIG_LV_TOUCH_CONTROLLER)
list(APPEND SOURCES "lvgl_touch/l58.cpp")
elseif(CONFIG_LV_TOUCH_CONTROLLER_GT911)
list(APPEND SOURCES "lvgl_touch/gt911.c")
elseif(CONFIG_LV_TOUCH_CONTROLLER_TT21100)
list(APPEND SOURCES "lvgl_touch/tt21100.c")
elseif(CONFIG_LV_TOUCH_CONTROLLER_TMA445)
list(APPEND SOURCES "lvgl_touch/tma445.c")
elseif(CONFIG_LV_TOUCH_CONTROLLER_STMPE610)
list(APPEND SOURCES "lvgl_touch/stmpe610.c")
elseif(CONFIG_LV_TOUCH_CONTROLLER_ADCRAW)
Expand All @@ -95,6 +99,8 @@ idf_component_register(SRCS ${SOURCES}
#CalEPD
#sharp-lcd
#espressif__esp_lcd_touch_gt911
#espressif__esp_lcd_touch_tt21100
touch_tma445
)

target_compile_definitions(${COMPONENT_LIB} PUBLIC "-DLV_LVGL_H_INCLUDE_SIMPLE")
Expand Down
4 changes: 2 additions & 2 deletions lvgl_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
#include "driver/i2c.h"

#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "src/lv_core/lv_refr.h"
#include "src/core/lv_refr.h"
#else
#include "lvgl/src/lv_core/lv_refr.h"
#include "lvgl/src/core/lv_refr.h"
#endif

/*********************
Expand Down
6 changes: 6 additions & 0 deletions lvgl_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ extern "C" {
#include "lvgl_tft/disp_driver.h"
#include "lvgl_touch/touch_driver.h"

#define DISPLAY_WIDTH 1024
#define DISPLAY_HEIGHT 768
/* Backward compatibility for LV_HOR_RES_MAX & LV_VER_RES_MAX */
#define LV_HOR_RES_MAX 1024
#define LV_VER_RES_MAX 768

/*********************
* DEFINES
*********************/
Expand Down
196 changes: 103 additions & 93 deletions lvgl_tft/epdiy_epaper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

EpdiyHighlevelState hl;
uint16_t flushcalls = 0;
uint8_t * framebuffer;
uint8_t *framebuffer;
uint8_t temperature = 25;
bool init = true;
// MODE_DU: Fast monochrome | MODE_GC16 slow with 16 grayscales
Expand All @@ -15,121 +15,131 @@ enum EpdDrawMode updateMode = MODE_DU;
/* Display initialization routine */
void epdiy_init(void)
{
// epd_init(&epd_board_v7, &ED097TC2, EPD_LUT_64K);
epd_init(&epd_board_v7, &EC060KH3, EPD_LUT_64K);
epd_init(&epd_board_v7, &ED060XC3, EPD_LUT_64K);
// Set VCOM for boards that allow to set this in software (in mV).
// This will print an error if unsupported. In this case,
// set VCOM using the hardware potentiometer and delete this line.
epd_set_vcom(1760);
hl = epd_hl_init(EPD_BUILTIN_WAVEFORM);
framebuffer = epd_hl_get_framebuffer(&hl);
epd_poweron();
//Clear all display in initialization to remove any ghosts
epd_fullclear(&hl, temperature);
epd_set_vcom(1760);
hl = epd_hl_init(EPD_BUILTIN_WAVEFORM);
framebuffer = epd_hl_get_framebuffer(&hl);
epd_poweron();
// Clear all display in initialization to remove any ghosts
epd_fullclear(&hl, temperature);
}

/* Suggested by @kisvegabor https://forum.lvgl.io/t/lvgl-port-to-be-used-with-epaper-displays/5630/26
* @deprecated
*/
void buf_area_to_framebuffer(const lv_area_t *area, const uint8_t *image_data) {
/* Suggested by @kisvegabor https://forum.lvgl.io/t/lvgl-port-to-be-used-with-epaper-displays/5630/26
* @deprecated
*/
void buf_area_to_framebuffer(const lv_area_t *area, const uint8_t *image_data)
{
assert(framebuffer != NULL);
uint8_t *fb_ptr = &framebuffer[area->y1 * epd_width() / 2 + area->x1 / 2];
lv_coord_t img_w = lv_area_get_width(area);
for(uint32_t y = area->y1; y < area->y2; y++) {
memcpy(fb_ptr, image_data, img_w / 2);
fb_ptr += epd_width() / 2;
image_data += img_w / 2;
for (uint32_t y = area->y1; y < area->y2; y++)
{
memcpy(fb_ptr, image_data, img_w / 2);
fb_ptr += epd_width() / 2;
image_data += img_w / 2;
}
}

/* A copy from epd_copy_to_framebuffer with temporary lenght prediction */
void buf_copy_to_framebuffer(EpdRect image_area, const uint8_t *image_data) {
void buf_copy_to_framebuffer(EpdRect image_area, const uint8_t *image_data)
{
assert(framebuffer != NULL);
int x, xx = image_area.x;
int y, yy = image_area.y;
int w = image_area.width;
int h = image_area.height;
const uint8_t ucCLRMask[3] = {0xc0,0x38,0x7};
uint8_t uc, *s, *d;
// source data is one byte per pixel (RGB233)
for (y=yy; y<(yy + h); y++) {
int i = (xx+y) % 3; // which color filter is in use?
s = (uint8_t *)&image_data[(y-yy) * w];
d = &framebuffer[(y * epd_width() / 2) + (xx / 2)];
x = xx;
if (x & 1) {
uc = d[0] & 0xf0; // special case for odd starting pixel
if (s[0] & ucCLRMask[i])
uc |= 0xf;
i++;
s++;
*d++ = uc;
x++;
if (i >= 3) i-=3;
}
for (; x<(xx + w); x+=2) { // work 2 pixels at a time
uc = 0;
if (s[0] & ucCLRMask[i]) uc |= 0xf;
i++; if (i >= 3) i -= 3;
if (s[1] & ucCLRMask[i]) uc |= 0xf0;
i++; if (i >= 3) i -= 3;
*d++ = uc;
s += 2;
} // for x
} // for y
} /* buf_copy_to_framebuffer() */

for (uint32_t i = 0; i < image_area.width * image_area.height; i++)
{
uint8_t val = (i % 2) ? (image_data[i / 2] & 0xF0) >> 4 : image_data[i / 2] & 0x0F;
int xx = image_area.x + i % image_area.width;
if (xx < 0 || xx >= epd_width())
{
continue;
}
int yy = image_area.y + i / image_area.width;
if (yy < 0 || yy >= epd_height())
{
continue;
}
uint8_t *buf_ptr = &framebuffer[yy * epd_width() / 2 + xx / 2];
if (xx % 2)
{
*buf_ptr = (*buf_ptr & 0x0F) | (val << 4);
}
else
{
*buf_ptr = (*buf_ptr & 0xF0) | val;
}
}
}

/* Required by LVGL. Sends the color_map to the screen with a partial update */
void epdiy_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map)
{
static int x1=65535,y1=65535,x2=-1,y2=-1;

++flushcalls;
uint16_t w = lv_area_get_width(area);
uint16_t h = lv_area_get_height(area);
static int x1 = 65535, y1 = 65535, x2 = -1, y2 = -1;
++flushcalls;
uint16_t w = lv_area_get_width(area);
uint16_t h = lv_area_get_height(area);

EpdRect update_area = {
.x = (uint16_t)area->x1,
.y = (uint16_t)area->y1,
.width = w,
.height = h
};
EpdRect update_area = {
.x = (uint16_t)area->x1,
.y = (uint16_t)area->y1,
.width = w,
.height = h};

// capture the upper left and lower right corners
if (area->x1 < x1) x1 = area->x1;
if (area->y1 < y1) y1 = area->y1;
if (area->x2 > x2) x2 = area->x2;
if (area->y2 > y2) y2 = area->y2;
// capture the upper left and lower right corners
if (area->x1 < x1)
x1 = area->x1;
if (area->y1 < y1)
y1 = area->y1;
if (area->x2 > x2)
x2 = area->x2;
if (area->y2 > y2)
y2 = area->y2;
uint8_t *buf = (uint8_t *)color_map;

uint8_t* buf = (uint8_t *) color_map;
// Buffer debug
/* for (int index=0; index<400; index++) {
printf("%x ", buf[index]);
} */
// This is the slower version that works good without leaving any white line
buf_copy_to_framebuffer(update_area, buf);
// This is the slower version that works good without leaving any white line
buf_copy_to_framebuffer(update_area, buf);

//Faster mode suggested in LVGL forum (Leaves ghosting&prints bad sections / experimental) NOTE: Do NOT use in production
//buf_area_to_framebuffer(area, buf);
if (lv_disp_flush_is_last(drv)) { // only send to e-paper when complete
update_area.x = x1;
update_area.y = y1;
update_area.width = (x2-x1)+1;
update_area.height = (y2-y1)+1;
epd_hl_update_area(&hl, updateMode, temperature, update_area); //update_area
x1 = y1 = 65535; x2 = y2 = -1; // reset update boundary
}
//printf("epdiy_flush %d x:%d y:%d w:%d h:%d\n", flushcalls,(uint16_t)area->x1,(uint16_t)area->y1,w,h);
/* Inform the graphics library that you are ready with the flushing */
lv_disp_flush_ready(drv); // do this after the check for "is_last"
// Faster mode suggested in LVGL forum (Leaves ghosting&prints bad sections / experimental) NOTE: Do NOT use in production
// buf_area_to_framebuffer(area, buf);
if (lv_disp_flush_is_last(drv))
{ // only send to e-paper when complete
update_area.x = x1;
update_area.y = y1;
update_area.width = (x2 - x1) + 1;
update_area.height = (y2 - y1) + 1;
epd_hl_update_area(&hl, updateMode, temperature, update_area); // update_area
x1 = y1 = 65535;
x2 = y2 = -1; // reset update boundary
}
// printf("epdiy_flush %d x:%d y:%d w:%d h:%d\n", flushcalls,(uint16_t)area->x1,(uint16_t)area->y1,w,h);
/* Inform the graphics library that you are ready with the flushing */
lv_disp_flush_ready(drv);
}

/*
/*
* Called for each pixel. Designed with the idea to fill the buffer directly, not to set each pixel, see LVGL Forum (buf_area_to_framebuffer)
*/
void epdiy_set_px_cb(lv_disp_drv_t * disp_drv, uint8_t* buf,
lv_coord_t buf_w, lv_coord_t x, lv_coord_t y,
lv_color_t color, lv_opa_t opa)
*/
void epdiy_set_px_cb(lv_disp_drv_t *disp_drv, uint8_t *buf,
lv_coord_t buf_w, lv_coord_t x, lv_coord_t y,
lv_color_t color, lv_opa_t opa)
{
buf[(y * buf_w)+x] = color.full;
// Test using RGB232
int16_t epd_color = 255;
if ((int16_t)color.full < 254)
{
epd_color = (updateMode == MODE_DU) ? 0 : (int16_t)color.full / 3;
}

// Instead of using epd_draw_pixel: Set pixel directly in *buf that comes afterwards in flush as *color_map
uint16_t idx = (int16_t)y * buf_w / 2 + (int16_t)x / 2;
if (x % 2)
{
buf[idx] = (buf[idx] & 0x0F) | (epd_color & 0xF0);
}
else
{
buf[idx] = (buf[idx] & 0xF0) | (epd_color >> 4);
}
}
Loading