Block write pixel alignment

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);
	}
}