Proper way to use partial drawing mode with ILI9341 LCD controller chip?

I am using a touch-screen LCD with an ILI9341 control chip. I have setup the chip in 8080 16-bit control mode, streaming 5-6-5 pixels over 16 data lines. I’ve tried 3 different ways of using partial mode of the ILI9341 (which allows you to describe the x/y/w/h region you’re going to stream pixels to).

Here’s the first thing I tried:

void my_disp_flush(lv_disp_drv_t * disp, const lv_area_t * area, lv_color_t * color_p)
{
	int32_t x, y;
	ILI9341_Partial(area->x1,area->y1,(area->x2-area->x1)+1,(area->y2-area->y1)+1);
	for(y = area->y1; y <= area->y2; y++) {
		for(x = area->x1; x <= area->x2; x++) {
			lcd_draw_565_pixel(color_p->full);
			color_p++;
		}
	}
	lv_disp_flush_ready(disp);         /* Indicate you are ready with the flushing*/
}

This doesn’t work. It draws the entire screen OK, but when I press buttons for instance they appear corrupted. Same with dragging a slider that updates a text label, the label appears corrupted.

Next, I tried this:

void my_disp_flush(lv_disp_drv_t * disp, const lv_area_t * area, lv_color_t * color_p)
{
	int32_t x, y;
	for(y = area->y1; y <= area->y2; y++) {
		for(x = area->x1; x <= area->x2; x++) {
			ILI9341_Partial(x,y,1,1);
			lcd_draw_565_pixel(color_p->full);
			color_p++;
		}
	}
	lv_disp_flush_ready(disp);         /* Indicate you are ready with the flushing*/
}

This does work, but is slow because it has to send commands over the bus to put the display in partial mode for each and every pixel.

So I tried this:

void my_disp_flush(lv_disp_drv_t * disp, const lv_area_t * area, lv_color_t * color_p)
{
	int32_t x, y;
	for(y = area->y1; y <= area->y2; y++) {
		ILI9341_Partial(area->x1,y,(area->x2-area->x1)+1,1);
		for(x = area->x1; x <= area->x2; x++) {
			lcd_draw_565_pixel(color_p->full);
			color_p++;
		}
	}
	lv_disp_flush_ready(disp);         /* Indicate you are ready with the flushing*/
}

This does work and is fast enough to be usable. However, I’d much rather use the 1st option as it would only require a single partial mode command per call to my_disp_flush versus calls for every line referenced in each call in my_disp_flush. I’m surprised option #1 didn’t work.

Unless there’s an option in the ILI9341 to reverse Y wrapping direction in partial mode I’m not sure what else would explain why #2 and #3 work but not #1

Can you send a picture of the corruption/describe it? If it’s a staircase effect (i.e. every row is off by one more pixel) you may be giving the ILI9341_Partial function the wrong width. I’m particularly suspicious of this since you’re effectively resetting the horizontal cursor to the right spot every time you call ILI9341_Partial in solution 3.

See the video posted to the thread.

Issue is resolved.

The function call to set the drawing area was always increasing the width by 1 pixel if the width was odd. That code originally was used with 18bit pixels over a 16bit bus so you had to group transfers into 2 pixels at a time, making a transfer with an odd number of pixels impossible.

Code is now 565 on a 16 bit bus so I can send 1 pixel at a time, removing the check for oddness and the arbitrary increase to width fixed it.

Resetting on each line hid the problem because the missing data would just be ignored and position would be reset on each line.

Also shows why some things looked fine and others did not, anything with even width worked.

@bradcb212 Hi, I´m interested in you connection of ESP32 and LCD. Could you pls share it? Many thanks :wink: