Description
Method lv_refr_area is unable to refresh areas which are 1 pixel height.
What MCU/Processor/Board and compiler are you using?
STM32F4xx on Keil uVision MDK 5.27 using ARMCC V5.06 update 6 toolchain.
What do you experience?
When refresh is called for an invalid area that has a height of only 1 pixel. The refresh method returns early and does not refresh the area.
What do you expect?
Refresh should occur for areas of all heights/widths.
Code to reproduce
Code of interest found in method static void lv_refr_area(const lv_area_t * area_p) in file lv_refr.c.
When using rounder callback refresh method attempts to
This code sets up the temp Y height. If the height is only 1, then y_tmp is 0.
lv_coord_t y_tmp = max_row - 1;
After this a loop is used to decrement y_tmp until it fits within the height. The loops exits on the break in the first iteration (indicating that a height of 1 did fit).
do {
tmp.y2 = y_tmp;
disp_refr->driver.rounder_cb(&disp_refr->driver, &tmp);
/*If this height fits into `max_row` then fine*/
if(lv_area_get_height(&tmp) <= max_row) break;
/*Decrement the height of the area until it fits into `max_row` after rounding*/
y_tmp--;
} while(y_tmp != 0);
Where the issue occurs is that there is a check that the size of the height is not zero. The problem is that for single pixel height objects y_tmp was already set to zero before the beginning of the loop and thus fails and does not redraw.
if(y_tmp == 0) {
LV_LOG_WARN("Can't set VDB height using the round function. (Wrong round_cb or to "
"small VDB)");
return;
} else {
max_row = tmp.y2 + 1;
}
Proposed Fix
I have resolved this problem on my end by changing the y_tmp var (renamed h_tmp to better represent that it is height) to equal max_row. I then have the internal tmp.y2 equal h_tmp -1. Also the checks for zero should be > for the while loop and <= for the h_tmp check at the end.
Code:
lv_coord_t h_tmp = max_row;
do {
tmp.y2 = h_tmp - 1;
disp_refr->driver.rounder_cb(&disp_refr->driver, &tmp);
/*If this height fits into `max_row` then fine*/
if(lv_area_get_height(&tmp) <= max_row) break;
/*Decrement the height of the area until it fits into `max_row` after rounding*/
h_tmp--;
} while(h_tmp > 0);
if(h_tmp <= 0) {
LV_LOG_WARN("Can't set VDB height using the round function. (Wrong round_cb or to "
"small VDB)");
return;
} else {
max_row = tmp.y2 + 1;
}