diff --git a/lv_conf_templ.h b/lv_conf_templ.h index 1c9b4ba60..a06e52b32 100644 --- a/lv_conf_templ.h +++ b/lv_conf_templ.h @@ -38,14 +38,14 @@ * Required for buffered drawing, opacity and anti-aliasing * VDB makes the double buffering, you don't need to deal with it! * Typical size: ~1/10 screen */ -#define LV_VDB_SIZE (8 * LV_HOR_RES) /*Size of VDB in pixel count (1/10 screen size is good for first)*/ -#define LV_VDB_PX_BPP LV_COLOR_SIZE /*Bit-per-pixel of VDB. Useful for monochrome or non-standard color format displays. (Set `disp_drv->vdb_wr` and `disp_drv->vdb_rd` too)*/ -#define LV_VDB_ADR 0 /*Place VDB to a specific address (e.g. in external RAM) (0: allocate automatically into RAM)*/ +#define LV_VDB_SIZE (30 * LV_HOR_RES) /*Size of VDB in pixel count (1/10 screen size is good for first)*/ +#define LV_VDB_PX_BPP LV_COLOR_SIZE /*Bit-per-pixel of VDB. Useful for monochrome or non-standard color format displays. (Set `disp_drv->vdb_wr` and `disp_drv->vdb_rd` too)*/ +#define LV_VDB_ADR 0 /*Place VDB to a specific address (e.g. in external RAM) (0: allocate automatically into RAM; LV_VDB_ADR_INV: to replace it later with `lv_vdb_set_adr()`)*/ /* Use two Virtual Display buffers (VDB) parallelize rendering and flushing (optional) * The flushing should use DMA to write the frame buffer in the background*/ #define LV_VDB_DOUBLE 0 /*1: Enable the use of 2 VDBs*/ -#define LV_VDB2_ADR 0 /*Place VDB2 to a specific address (e.g. in external RAM) (0: allocate automatically into RAM)*/ +#define LV_VDB2_ADR 0 /*Place VDB2 to a specific address (e.g. in external RAM) (0: allocate automatically into RAM; LV_VDB_ADR_INV: to replace it later with `lv_vdb_set_adr()`)*/ /* Enable anti-aliasing (lines, and radiuses will be smoothed) */ #define LV_ANTIALIAS 1 /*1: Enable anti-aliasing*/ diff --git a/lv_core/lv_refr.c b/lv_core/lv_refr.c index 6f0a69498..1d9bdfe59 100644 --- a/lv_core/lv_refr.c +++ b/lv_core/lv_refr.c @@ -322,6 +322,10 @@ static void lv_refr_area_with_vdb(const lv_area_t * area_p) lv_coord_t row_last = 0; for(row = area_p->y1; row + max_row - 1 <= y2; row += max_row) { lv_vdb_t * vdb_p = lv_vdb_get(); + if(!vdb_p) { + LV_LOG_WARN("Invalid VDB pointer"); + return; + } /*Calc. the next y coordinates of VDB*/ vdb_p->area.x1 = area_p->x1; @@ -336,6 +340,10 @@ static void lv_refr_area_with_vdb(const lv_area_t * area_p) /*If the last y coordinates are not handled yet ...*/ if(y2 != row_last) { lv_vdb_t * vdb_p = lv_vdb_get(); + if(!vdb_p) { + LV_LOG_WARN("Invalid VDB pointer"); + return; + } /*Calc. the next y coordinates of VDB*/ vdb_p->area.x1 = area_p->x1; @@ -355,6 +363,10 @@ static void lv_refr_area_with_vdb(const lv_area_t * area_p) static void lv_refr_area_part_vdb(const lv_area_t * area_p) { lv_vdb_t * vdb_p = lv_vdb_get(); + if(!vdb_p) { + LV_LOG_WARN("Invalid VDB pointer"); + return; + } lv_obj_t * top_p; /*Get the new mask from the original area and the act. VDB diff --git a/lv_core/lv_vdb.c b/lv_core/lv_vdb.c index 3528f8a57..5180ddef3 100644 --- a/lv_core/lv_vdb.c +++ b/lv_core/lv_vdb.c @@ -10,6 +10,7 @@ #if LV_VDB_SIZE != 0 #include "../lv_hal/lv_hal_disp.h" +#include "../lv_misc/lv_log.h" #include /********************* @@ -38,7 +39,7 @@ typedef enum { static volatile lv_vdb_state_t vdb_state = LV_VDB_STATE_ACTIVE; # if LV_VDB_ADR == 0 /*If the buffer address is not specified simply allocate it*/ -static uint8_t vdb_buf[(LV_VDB_SIZE * LV_VDB_PX_BPP) >> 3]; +static uint8_t vdb_buf[((LV_VDB_SIZE * LV_VDB_PX_BPP) >> 3) + (((LV_VDB_SIZE * LV_VDB_PX_BPP) & 0x7) ? 1 : 0)]; static lv_vdb_t vdb = {.buf = (lv_color_t*)vdb_buf}; # else /*LV_VDB_ADR != 0*/ /*If the buffer address is specified use that address*/ @@ -49,8 +50,8 @@ static lv_vdb_t vdb = {.buf = (lv_color_t *)LV_VDB_ADR}; static volatile lv_vdb_state_t vdb_state[2] = {LV_VDB_STATE_FREE, LV_VDB_STATE_FREE}; # if LV_VDB_ADR == 0 /*If the buffer address is not specified simply allocate it*/ -static uint8_t vdb_buf1[(LV_VDB_SIZE * LV_VDB_PX_BPP) >> 3]; -static uint8_t vdb_buf2[(LV_VDB_SIZE * LV_VDB_PX_BPP) >> 3]; +static uint8_t vdb_buf1[((LV_VDB_SIZE * LV_VDB_PX_BPP) >> 3) + (((LV_VDB_SIZE * LV_VDB_PX_BPP) & 0x7) ? 1 : 0)]; +static uint8_t vdb_buf2[((LV_VDB_SIZE * LV_VDB_PX_BPP) >> 3) + (((LV_VDB_SIZE * LV_VDB_PX_BPP) & 0x7) ? 1 : 0)]; static lv_vdb_t vdb[2] = {{.buf = (lv_color_t *) vdb_buf1}, {.buf = (lv_color_t *) vdb_buf2}}; # else /*LV_VDB_ADR != 0*/ /*If the buffer address is specified use that address*/ @@ -76,6 +77,11 @@ lv_vdb_t * lv_vdb_get(void) /* Wait until VDB become ACTIVE from FLUSH by the * user call of 'lv_flush_ready()' in display drivers's flush function*/ while(vdb_state != LV_VDB_STATE_ACTIVE); + + if(vdb.buf == (void*)LV_VDB_ADR_INV) { + LV_LOG_ERROR("VDB address is invalid. Use `lv_vdb_set_adr` to set a valid address or use LV_VDB_ADR = 0 in lv_conf.h"); + return NULL; + } return &vdb; #else /*If already there is an active do nothing*/ @@ -103,8 +109,10 @@ lv_vdb_t * lv_vdb_get(void) void lv_vdb_flush(void) { lv_vdb_t * vdb_act = lv_vdb_get(); - if(vdb_act == NULL) return; - + if(!vdb_act) { + LV_LOG_WARN("Invalid VDB pointer"); + return; + } #if LV_VDB_DOUBLE == 0 vdb_state = LV_VDB_STATE_FLUSH; /*User call to 'lv_flush_ready()' will set to ACTIVE 'disp_flush'*/ #else @@ -122,6 +130,24 @@ void lv_vdb_flush(void) } + +/** + * Set the address of VDB buffer(s) manually. To use this set `LV_VDB_ADR` (and `LV_VDB2_ADR`) to `LV_VDB_ADR_INV` in `lv_conf.h`. + * It should be called before `lv_init()`. + * The size of the buffer should be: `((LV_VDB_SIZE * LV_VDB_PX_BPP) >> 3) + (((LV_VDB_SIZE * LV_VDB_PX_BPP) & 0x7) ? 1 : 0)` + * @param buf1 address of the VDB. + * @param buf2 address of the second buffer. `NULL` if `LV_VDB_DOUBLE 0` + */ +void lv_vdb_set_adr(void * buf1, void * buf2) +{ +#if LV_VDB_DOUBLE == 0 + vdb.buf = buf1; +#else + vdb[0].buf = buf1; + vdb[1].buf = buf2; +#endif +} + /** * Call in the display driver's 'disp_flush' function when the flushing is finished */ diff --git a/lv_core/lv_vdb.h b/lv_core/lv_vdb.h index 68ba61268..35d596c13 100644 --- a/lv_core/lv_vdb.h +++ b/lv_core/lv_vdb.h @@ -27,6 +27,8 @@ extern "C" { /********************* * DEFINES *********************/ +/*Can be used in `lv_conf.h` the set an invalid address for the VDB. It should be replaced later by a valid address using `lv_vdb_set_adr()`*/ +#define LV_VDB_ADR_INV 8 /*8 is still too small to be valid but it's aligned on 64 bit machines as well*/ #ifndef LV_VDB_PX_BPP #warning "LV_VDB_PX_BPP is not specified in lv_conf.h. Use the default value (LV_COLOR_SIZE)" @@ -57,6 +59,15 @@ lv_vdb_t * lv_vdb_get(void); */ void lv_vdb_flush(void); +/** + * Set the address of VDB buffer(s) manually. To use this set `LV_VDB_ADR` (and `LV_VDB2_ADR`) to `LV_VDB_ADR_INV` in `lv_conf.h`. + * It should be called before `lv_init()`. + * The size of the buffer should be: `((LV_VDB_SIZE * LV_VDB_PX_BPP) >> 3) + ((LV_VDB_SIZE * LV_VDB_PX_BPP) & 0x7) ? 1 : 0` + * @param buf1 address of the VDB. + * @param buf2 address of the second buffer. `NULL` if `LV_VDB_DOUBLE 0` + */ +void lv_vdb_set_adr(void * buf1, void * buf2); + /** * Call in the display driver's 'disp_flush' function when the flushing is finished */ diff --git a/lv_draw/lv_draw_vbasic.c b/lv_draw/lv_draw_vbasic.c index 22e340d90..16c254bfe 100644 --- a/lv_draw/lv_draw_vbasic.c +++ b/lv_draw/lv_draw_vbasic.c @@ -66,6 +66,10 @@ void lv_vpx(lv_coord_t x, lv_coord_t y, const lv_area_t * mask_p, lv_color_t col if(opa > LV_OPA_MAX) opa = LV_OPA_COVER; lv_vdb_t * vdb_p = lv_vdb_get(); + if(!vdb_p) { + LV_LOG_WARN("Invalid VDB pointer"); + return; + } /*Pixel out of the mask*/ if(x < mask_p->x1 || x > mask_p->x2 || @@ -109,6 +113,10 @@ void lv_vfill(const lv_area_t * cords_p, const lv_area_t * mask_p, lv_area_t res_a; bool union_ok; lv_vdb_t * vdb_p = lv_vdb_get(); + if(!vdb_p) { + LV_LOG_WARN("Invalid VDB pointer"); + return; + } /*Get the union of cord and mask*/ /* The mask is already truncated to the vdb size @@ -277,6 +285,11 @@ void lv_vletter(const lv_point_t * pos_p, const lv_area_t * mask_p, pos_y + letter_h < mask_p->y1 || pos_y > mask_p->y2) return; lv_vdb_t * vdb_p = lv_vdb_get(); + if(!vdb_p) { + LV_LOG_WARN("Invalid VDB pointer"); + return; + } + lv_coord_t vdb_width = lv_area_get_width(&vdb_p->area); lv_color_t * vdb_buf_tmp = vdb_p->buf; lv_coord_t col, row; @@ -371,6 +384,10 @@ void lv_vmap(const lv_area_t * cords_p, const lv_area_t * mask_p, lv_area_t masked_a; bool union_ok; lv_vdb_t * vdb_p = lv_vdb_get(); + if(!vdb_p) { + LV_LOG_WARN("Invalid VDB pointer"); + return; + } /*Get the union of map size and mask*/ /* The mask is already truncated to the vdb size