Running LVGL from main loop i have some gliches on the screen which i found came from display restrictions. Turns out the first pixel (area->x1) must be a even number.
Is there a way of telling LVGL that the fist pixel should always be a even numer?
I fixed the width by setting LV_DRAW_BUF_STRIDE_ALIGN 2 but cant seem to find a way of forcing the first pixel (area->x1) to be a even number.
I’m using a STM32U5 processor using partial render mode using the DMA controller to write to a CO5300 display.
Using LVGL version 9.2
The code below shows how i almost fixed the problem by moving the whole block to write 1 pixel to the right if the first pixel number is not a even number.
The CO5300 datasheet states for ‘set row start address’ and ‘set column start address’:
- The SC[9:0] and EC[9:0]-SC[9:0]+1 must can be divisible by 2
- The SP[9:0] and EP[9:0]-SP[9:0]+1 must can be divisible by 2
int main(void){
#ifdef USE_LVGL
lv_init();
lv_display_t *disp = lv_display_create(DISPLAY_WIDTH, DISPLAY_HEIGHT); /* Create the display */
lv_display_set_flush_cb(disp, my_flush_cb); /* Set a flush callback to draw to the display */
lv_display_set_buffers(disp, buf_1, NULL, sizeof(buf_1), LV_DISPLAY_RENDER_MODE_PARTIAL); /* Set an initialized buffer */ // LV_DISPLAY_RENDER_MODE_PARTIAL, LV_DISPLAY_RENDER_MODE_FULL
/* Register the touch controller with LVGL - Not included here for brevity. */
/* Change Active Screen's background color */
lv_obj_set_style_bg_color(lv_screen_active(), lv_color_hex(0x003a57), LV_PART_MAIN);
lv_obj_set_style_text_color(lv_screen_active(), lv_color_hex(0xffffff), LV_PART_MAIN);
LV_ALIGN_BOTTOM_MID
/* Create a buttons */
lv_obj_t * btn = lv_btn_create(lv_scr_act()); /*Add a button the current screen*/
lv_obj_set_pos(btn, 200, 10); /*Set its position*/
lv_obj_set_size(btn, 120, 51); /*Set its size*/
//lv_obj_add_event_cb(btn, btn_event_cb, LV_EVENT_ALL, NULL); /*Assign a callback to the button*/
int button_dirx = 1, button_diry = 1, button_locx=200, button_locy=10;
lv_obj_t * label = lv_label_create(btn); /*Add a label to the button*/
lv_label_set_text(label, "Button"); /*Set the labels text*/
lv_obj_center(label);
/*Create an Arc*/
int arcVal = 0, arcDir = 1;
lv_obj_t * arc = lv_arc_create(lv_scr_act());
//lv_arc_set_rotation(arc, 270);
//lv_arc_set_bg_angles(arc, 0, 360);
lv_obj_set_size(arc, 400, 400);
lv_obj_set_style_arc_width(arc, 40, LV_PART_MAIN); // Changes background arc width
lv_obj_set_style_arc_width(arc, 40, LV_PART_INDICATOR); // Changes set part width
lv_obj_set_style_arc_color(arc, lv_color_hex(0xffe000), LV_PART_INDICATOR);
lv_obj_remove_style(arc, NULL, LV_PART_KNOB); /*Be sure the knob is not displayed*/
lv_obj_clear_flag(arc, LV_OBJ_FLAG_CLICKABLE); /*To not allow adjusting by click*/
lv_obj_center(arc);
#endif
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_Delay(5);
lv_tick_inc(5);
#ifdef USE_LVGL
lv_timer_handler();
button_locx += button_dirx;
if((button_dirx) && (button_locx >= (DISPLAY_WIDTH-126))){
button_dirx = -1;
} else if ((button_dirx == -1) && (button_locx == 0)) {
button_dirx = 1;
}
button_locy += button_diry;
if((button_diry) && (button_locy >= (DISPLAY_HEIGHT-51))){
button_diry = -1;
} else if ((button_diry == -1) && (button_locy == 0)) {
button_diry = 1;
}
lv_obj_set_pos(btn, button_locx, button_locy);
lv_arc_set_value(arc, arcVal/10);
arcVal += arcDir;
if(arcVal == 1000 && arcDir == 1){
arcDir = -1;
} else if(arcVal == 0 && arcDir == -1){
arcDir = 1;
}
#endif
}
/* USER CODE END 3 */
}
void QuadSPI_display::draw_16bit_DMA(int Xstart,int Xstop,int Ystart,int Ystop,uint8_t* data, void* callbackFunction, int timeout){
int width = Xstop - Xstart + 1;
/* Adding this part fixes the gliches but misplaces the blocks */
if( (Xstart % 2 != 0)){ // works better but still skips some data
BlockWrite(Xstart+1,Xstop+1,Ystart,Ystop);
if(callbackFunction){
callbackFunc = callbackFunction;
reportTxCmplt = true;
}
qspi.write_DMA(CMD_4PIXEL_WRITE, 4, 0x002C00, 3, data, (2*width*(Ystop-Ystart+1)), timeout);
return;
}
BlockWrite(Xstart,Xstop,Ystart,Ystop);
if(callbackFunction){
callbackFunc = callbackFunction;
reportTxCmplt = true;
}
qspi.write_DMA(CMD_4PIXEL_WRITE, 4, 0x002C00, 3, data, (2*width*(Ystop-Ystart+1)), timeout);
}
void my_flush_cb(lv_display_t * disp_drv, const lv_area_t * area, uint8_t * px_map) // should be static
{
while(!initState){
HAL_Delay(100);
}
if(i2cBusy){
lv_display_flush_ready(disp_drvx);
return;
}
i2cBusy = true;
if( (2*(area->x2 - area->x1 + 1)*(area->y2 - area->y1 + 1) ) < 0xff00){
disp_drvx = disp_drv;
waitForTxCmplt = true;
display.draw_16bit_DMA(area->x1, area->x2, area->y1, area->y2, px_map, (void*)&myCallback, 1000);
} else {
cnt += 1;
/* message to big for DMA */
display.draw_16bit(area->x1, area->x2, area->y1, area->y2, px_map, 5000);
i2cBusy = false;
lv_display_flush_ready(disp_drv);
}
/*IMPORTANT!!!
*Inform the graphics library that you are ready with the flushing*/
//lv_display_flush_ready(disp_drv);
/* done in HAL_OSPI_TxCpltCallback */
}
void myCallback(void){
if(waitForTxCmplt){
waitForTxCmplt = false;
i2cBusy = false;
lv_display_flush_ready(disp_drvx);
}
}