Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

One pixel transformation for ILI948x #103

Closed
wants to merge 1 commit into from

Conversation

tore-espressif
Copy link
Collaborator

ILI948x doesn't support 16bit color data in SPI mode, so we have to extrapolate from LVGL's RGB565 (16bit) to 18 bits.

Previously, the whole buffer was transformed, which required a lot of DMA capable RAM. This PR changes to transformation algorithm to process one pixel at a time.

Closes #85

Copy link
Member

@kisvegabor kisvegabor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi,

I found a few things that might be worth to discuss.

lv_color16_t *color_565 = (lv_color16_t *) color_map;
for (uint32_t i = 0; i < size; i++, color_565++) {
uint8_t spi_buf[3];
spi_buf[0] = color_565->ch.blue << 3; // Blue is 5bits wide, align to 8 bits
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This way there is no maxima blue. E.g. 0b11111 << 3 is 0b11111000 instead of 0b11111111.

The original code converted to RGB666 and added the LSB twice.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I couldn't get me head around the old conversion function. Will fix

lvgl_tft/ili9481.c Show resolved Hide resolved
lv_color16_t *color_565 = (lv_color16_t *) color_map;
for (uint32_t i = 0; i < size; i++, color_565++) {
uint8_t spi_buf[3];
spi_buf[0] = color_565->ch.blue << 3; // Blue is 5bits wide, align to 8 bits
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assuming that on UI there are a lot of adjacent same color (e.g. a large white background, a blue button, etc) calculating only if the current color is different from the previous else coping the previous result might cause significant speed up.

@C47D
Copy link
Collaborator

C47D commented Sep 7, 2021

@tore-espressif Let me know if you want me to test this PR, I got this hardware and an ESP32 dev kit.

@SinglWolf
Copy link

I tried to apply your patch for my ILI9488 display.
The red color is gone. The picture, which should be in color, appears as monochrome on a blue background (appears on the screen very, very slowly).
On the watch, the colon, which should be blinking in time with the seconds, no longer blinks, but looks like a smooth slideshow from top to bottom. The numbers are updated very slowly too.
The only thing that made me happy was that the artifacts were gone.

Or have I done something wrong again?

@SinglWolf
Copy link

SinglWolf commented Sep 24, 2021

After a lot of searching on github, I stumbled upon repo https://github.com/anuprao/esp32_ili9488, which implements something similar for the ILI9488 display controller. Only the version of the LVGL is very old 5.3.0. Maybe this will come in handy for solving the problem?
Fragment of code:

uint8_t buffConv[320*3] = {};

// Used in buffered mode
void ili9488_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_map)
{
	uint8_t data[4];
	
	uint8_t* pbuf;
	uint16_t i, len, chunk;
	//uint8_t r,g,b;
	
	lv_color16_t s;
	lv_color16_t* pColor = color_map;

	/*Column addresses*/
	ili9488_send_cmd(0x2A);
	data[0] = (x1 >> 8) & 0xFF;
	data[1] = x1 & 0xFF;
	data[2] = (x2 >> 8) & 0xFF;
	data[3] = x2 & 0xFF;
	ili9488_send_data(data, 4);

	/*Page addresses*/
	ili9488_send_cmd(0x2B);
	data[0] = (y1 >> 8) & 0xFF;
	data[1] = y1 & 0xFF;
	data[2] = (y2 >> 8) & 0xFF;
	data[3] = y2 & 0xFF;
	ili9488_send_data(data, 4);

	/*Memory write*/
	ili9488_send_cmd(0x2C);
	
	uint32_t size = (x2 - x1 + 1) * (y2 - y1 + 1);

	//Original code
	//ili9488_send_color((void*)color_map, size * 2);	/*Send the remaining data*/
	
	//ili9488_send_color((void*)color_map, size * 2);
	//ili9488_send_color(arrSample, 32);
	
	chunk = 0;
	len = size;
	while(len > 0)
	{
		chunk = (320 < len)? 320: len;
		
		pbuf = buffConv;
		for(i = 0; i<chunk; i++)
		{
			s = *pColor;
			
			*pbuf = s.red << 3;
			pbuf++;
			
			*pbuf = (s.green_h << 3 | s.green_l) << 2;
			pbuf++;
			
			*pbuf = s.blue << 3;
			pbuf++;
			
			pColor++;
		}
		
		ili9488_send_color(buffConv, chunk*3);
		
		len = len - chunk;
	}
	
	printf("size_flush = %d\r\n", size);
	
	//lv_flush_ready();

}

@tore-espressif
Copy link
Collaborator Author

Hello @SinglWolf ,
Thank you for your patience.
I ordered ILI9488 LCD controller a while ago, so I could test the performance, but the package got stuck at customs.
I will finalize this PR as soon as I get it.
Thanks!

@wreyford
Copy link

In my experience, this solution helps for the DMA issue, but renders the updates so slow, that the screen is not usable.
I have ordered extra PSRAM to try and solve this issue using hardware - still await that in the mail.

@tore-espressif
Copy link
Collaborator Author

Hello everyone,
I finally got my ILI9488 display and tested the performance. With the fix proposed in the PR it is really poor.
So if someone is interested in using ILI9488 (or any other that doesn't support RGB565 over SPI) I propose one of the following:

  1. If you can, use different controller, that supports RGB565 over SPI
  2. Use parallel interface (supports RGB565)
  3. Use already implemented SW transformation (allocates lot of RAM)
  4. Use hardware serial->parallel transformation. Example here: https://www.waveshare.com/w/upload/8/85/Pico-ResTouch-LCD-3.5_Sch.pdf

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants