Jump to content
remon

Write_data

Recommended Posts

Hi,

I'm writing a driver for my lcd screen (ST7586 IC) however it requires a strange frame format. The spi transmission is as follows

D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0
P1 | P1 | x  | P2 | P2 | x  | P3 | P3

where P1, P2, and P3 are the pixels represented by a 2 bit value where a 1 on both bits turns the pixel on and a 0 turns it off. After this the column counter increases by two, so that the last pixel of the previous transmission is the same as the first pixel of the second transmission.

I wanted to implement this in the "write_data" function of the driver template, whoever I'm having issues understanding the format of the framebuffer (RAM(g)), e.g. how to the data is related to the x,y position. I tried looking on the wiki and the api docs, however is was unable to find the format.

Regards,

Remon

Edited by remon

Share this post


Link to post
Share on other sites

The reason that there is no documentation about the framebuffer format is because there is no framebuffer in µGFX. One of the strong suits of µGFX compared to similar libraries is that it can work without a framebuffer.

I assume that as you are talking about the RAM() macro you are taking the existing ST7565 driver as a template?
Upon closer inspection you will see that the framebuffer is entirely handled inside of that driver. µGFX itself doesn't know about it at all. The first line in the gdisp_lld_init() function allocates a framebuffer. Note again that the framebuffer pointer is stored in the driver's private area. There is no call that submits/registers the framebuffer to µGFX itself. All that µGFX will do is calling the gdisp_lld_draw_pixel() function. In that function, the driver stores the pixel information in the framebuffer that he himself is managing. Therefore, it can use any kind of format.
All you have to do is storing the pixel information in a way inside the gdisp_lld_draw_pixel() function (and similar) that you can retrieve them once it's time to send that information to the display controller.

Note: I haven't checked the datasheet of the ST7586 display controller. However, note that may display controllers provide a frame buffer themselves. In that case, you might want to use a different display driver model. More information can be found here: http://wiki.ugfx.org/index.php/Display_Driver_Model

I hope that helps. Please don't hesitate to ask if there's anything unclear :)

Share this post


Link to post
Share on other sites

The ST7586 controller column address is 2 pixels wide. Therefore, when the gdisp_lld_draw_pixel() function is called, I can't simply draw only one pixel since the information on the neighbouring pixel will be lost. Unfortunately it is not possible to read from the controller ram, so I think I have to keep a buffer of all the pixels on the display.

Share this post


Link to post
Share on other sites

Yes sure, that's no problem. If the display controller design calls for a framebuffer you can implement it in the µGFX display driver without any issues - as shown in the ST7565 driver. You can store the pixel information however you like.

Just to be sure: Does this answer your question or did we leave something open?

Share this post


Link to post
Share on other sites

Yes, but I'm still a bit confused about the order in which the data is stored in the framebuffer( i.e. which bit relates to which x,y position).

Share this post


Link to post
Share on other sites

Let's have a look at the gdisp_lld_draw_pixel() implementation of the existing ST7565 driver:

LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g)
{
	coord_t	x, y;

	// Calculate pixel position
	switch(g->g.Orientation) {
	default:
	case GDISP_ROTATE_0:
		x = g->p.x;
		y = g->p.y;
		break;
	case GDISP_ROTATE_90:
		x = g->p.y;
		y = GDISP_SCREEN_HEIGHT-1 - g->p.x;
		break;
	case GDISP_ROTATE_180:
		x = GDISP_SCREEN_WIDTH-1 - g->p.x;
		y = GDISP_SCREEN_HEIGHT-1 - g->p.y;
		break;
	case GDISP_ROTATE_270:
		x = GDISP_SCREEN_HEIGHT-1 - g->p.y;
		y = g->p.x;
		break;
	}
	
	// Sore the pixel information in our own framebuffer
	if (gdispColor2Native(g->p.color) != Black) {
		RAM(g)[xyaddr(x, y)] |= xybit(y);
	} else {
		RAM(g)[xyaddr(x, y)] &= ~xybit(y);
	}
	
	// Framebuffer content changed, need to flush it
	g->flags |= GDISP_FLG_NEEDFLUSH;
}

The µGFX rendering engine calls the that function when a pixel value needs to be changed. The pixel coordinates and value are part of the GDisplay struct that is passed as a parameter. The first thing that happens is that we calculate the pixel position depending on the orientation. This is because the µGFX engine itself doesn't handle the orientations, it's up to the driver to handle this. The reason for this is because some display controllers have native orientation support built-in. The ST7565 doesn't - that's why we have to calculate it manually.
As previously established the ST7565 doesn't have a built-in frame buffer. This is why the driver maintains a frame buffer itself (the one that is allocated in the first line of gdisp_lld_ini()). We have store the pixel value that was supplied to us through the GDisplay structure in that framebuffer. This is the point where we decide how we want to store the pixel information in the framebuffer. This is where you decide how you put it in the framebuffer. Store the information however it's convenient to you.

Does this help?

Share this post


Link to post
Share on other sites

This is a bit old, but as I’ve not really seen anyone else implement st7586, wanted to share progress.

I have done a framebuffer implementation on a 360x160 2 bpp display (but using 1bpp monochrome fb for now).  It works ok, but consumes lots of ram, and is relatively slow to sync (about 230-250ms).

the project with my ugfx fork is here:

https://github.com/zerog2k/rcqr01

I would like to improve this, with such an odd packed pixel format, it doesn’t allow us to write individual pixels horizontally, only in groups of three (so very strange!] So I’m not sure if one way would be to handle each line write by reading the line from controller into row buffer, updating and writing back out.  Not sure how to approach this yet, but open to ideas. 

Share this post


Link to post
Share on other sites

According to the datasheet of the ST7586 the controller has a built in GRAM. So in theory you should not need a full framebuffer on the MCU.

10 hours ago, Jens J said:

So I’m not sure if one way would be to handle each line write by reading the line from controller into row buffer, updating and writing back out.

Reading from the displays GRAM is according to the datasheet only possible when using the parallel interface. So when using SPI it won't be possible to do this. Otherwise this would probably be the best solution to use the least resources.

10 hours ago, Jens J said:

it doesn’t allow us to write individual pixels horizontally, only in groups of three (so very strange!] 

Some designers make some very weird decisions...

When not using the parallel interface, I don't think it will be possible to omit the framebuffer.
I think the easiest approach is to keep the framebuffer but only do partial flushing. The controller supports setting a window for the GRAM. So set the window and only write the data that changed.

Share this post


Link to post
Share on other sites

If the controller supports a pixel addressable window (rather than a 3 pixel addressable window) it should be possible to not use a framebuffer even without read back.

A similar example is the nokia-ge8 driver which uses 12 bits per pixel and requires pixels to be written in pairs. It also allows a single pixel addressable window but wraps the extra pixel if you specify an odd pixel length. It also has other orientation bugs that definitely make it the strangest driver.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×