Jump to content

Porting uGFX for RA8876


JohnLKW

Recommended Posts

Hi

Some progress has been made to port uGFX to RA8876 which is an advanced display driver for high resolution TFT (up to 1366x768x24-bit).

Up to now, basic operations like gfxInit(), gdispDrawBox(), gdispFillArea(), gdispDrawPixel(), gdispClear(), and gdispDrawLine() are working.

But I have difficulty in getting gdispFillString() to work.

Running function gdispFillString(10,10,"Hello World", font_DejaVuSans24, White, Black) only print a solid black color bar with white bar of the same size sweeping across it with no character can be seen.

My questions are:

1. What else macro(s) should I put in to use gdispFillString()?

2. There is a font rendering feature by hardware on RA8876. Any where I implement this in uGFX?

3. Although Startup Logo has been enabled but there is no logo shown. What interface functions should I do for this?

 

File gfxconf.h  looks like:

#ifndef _GFXCONF_H

#define _GFXCONF_H

#define GFX_USE_OS_ARDUINO   TRUE

#define GFX_USE_GDISP   TRUE

#define GDISP_NEED_TEXT   TRUE

#define GDISP_INCLUDE_FONT_DEJAVUSAN24_AA   TRUE

#endif

From gdisp_lld_RA8876.c, I have three interface functions implemented:

  • LLDSPEC bool_t gdisp_lld_init(GDisplay *g),
  • LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g)
  • LLDSPEC void gdisp_lld_fill_area(GDisplay *g)

The following options enabled in gdisp_lld_config.h for hardware pixel draw, hardware fill, and startup logo.

#define GDISP_HARDWARE_DRAWPIXEL   TRUE
#define GDISP_HARDWARE_FILLS   TRUE

#define GDISP_NEED_STARTUP_LOGO   TRUE
#define GDISP_LLD_PIXELFORMAT   GDISP_PIXELFORMAT_RGB565

Remarks:

There are many nice features with this controller like:

  • 2D blit operation.
  • Accelerated graphic operation incl. square draw, circle draw, line draw, etc.
  • Internal Font and external font stored in font chip support. That means we may print characters by hardware instead of rendering pixel-by-pixel.
  • Graphic assets can be stored in external SPI Flash in bin format and transfer to display by DMA.
  • External SDRAM (up to 512Mbit) is used for frame buffer that contains more than 10 pages of graphical contents in 1366x768. This implies that we may store graphic assets in non-visible window to wait until a slow rendering operation finished in that frame and then copy it to the main window by a single instruction. This is what I am going to port with Pixmap, and this is the key for slow MCU like Arduino to use a large TFT screen. SPI write in 4MHz clock is used in my setup. A whole page clear screen is done in no time by 2D operation. No pixel by pixel raster is seen.

Any help is appreciated.

John Leung

 

Link to comment
Share on other sites

There is likely a bug in your fillarea driver routine.

The easy way to test this is to turn off GDISP_HARDWARE_FILLS in your gdisp_lld_config.h file.

If everything works (albiet slowly) then the problem is in your gdisp_fill_area routine. If it still doesn't look right then the problem is in the gdisp_draw_pixel routine.

Also the GDISP_STARTUP_LOGO macro belongs in your gfxconf.h not in the driver config file.

 

Link to comment
Share on other sites

To do a chip like this well would require significant architecture changes to uGFX. Things like hardware accelerated fonts are also not a good idea if you want to maintain consistancy accros platforms as hardware fonts vary from vendor to vendor.

There are several approaches to implementation for this chip:

1. (Recommended) The existing available acceleration functions are implemented ie fillarea, blit and scroll. This should give good performance for most situations. uGFX internally uses these for all more complex operations so adding extra acceleration has diminishing returns.

2. Extra features that are specific to this chip can be taken advantage of using the gdispControl interface and other uGFX interfaces eg. Page switching (gdispControl), storing of graphic assets (GFILE using NATIVE format messages), multiple display surfaces (extra GDisplay objects)

3. The extra acceleration functions for line, circle etc could be shoe horned into uGFX. This is complex, requires archetecture changes in uGFX and is redundant given the uGFX V3 is completely changing the GDISP driver interface. I would definitely suggest that this part not be attempted until atleast stage 1 and 2 above are complete.

Link to comment
Share on other sites

3 hours ago, inmarket said:

The easy way to test this is to turn off GDISP_HARDWARE_FILLS in your gdisp_lld_config.h file.

Thanks a lot. GDISP_HARDWARE_FILLS turned off leaving GDISP_HARDWARE_DRAWPIXEL  alone. A video is better to show this. Please download it from a dropbox link here. I have tuned it to 720x480P @60Hz for faster rendering. A monitor is connected to RA8876 via HDMI transmitter. The host is an Arduino Due with SPI interface.

https://www.dropbox.com/s/oft4zu8vmvc3rt9/with_GDISP_HARDWARE_DRAWPIXEL.mp4?dl=0

3 hours ago, inmarket said:

Also the GDISP_STARTUP_LOGO macro belongs in your gfxconf.h not in the driver config file.

Again, thank you. Putting GDISP_STARTUP_LOGO macro to gfxconf.h with GDISP_HARDWARE_DRAWPIXEL  does draw the LOGO OK. Another video is seen in this link.

Does it restrict to gfxconf.h for GDISP_STARTUP_LOGO macro ?

https://www.dropbox.com/s/akhtfz3mwia2cpm/Logo_render_w_pixel_streaming.mp4?dl=0

3 hours ago, inmarket said:

There is likely a bug in your fillarea driver routine.

Yes it seems there is a bug. When GDISP_HARDWARE_FILLS turned on together with GDISP_HARDWARE_DRAWPIXEL defined TRUE, no string can be drawn and the logo vanished too. Function gdispDrawBox(0,0, 300, 300, random(0,65535)) became a solid fill. Still looking into it. However, as you can see from this video, the performance with 2D acceleration is very acceptable, even with 1280x720P@60Hz.

https://www.dropbox.com/s/m2mewza8xzgv0le/with_GDISP_HARDWARE_FILLS.mp4?dl=0

 

Code for the main is extracted here:

void loop() {

    //Hot plug detect for a new monitor
    edidHandler();
    gdispDrawBox(0,0, 300, 300, random(0,65535));
    delay(1000);
    gdispFillString(10,10,"Hello World Hello World Hello World Hello World", font_DejaVuSans24, White, Black);
    delay(1000);
    gdispFillArea(0, 0, width-1, height-1, random(0,65535));
    delay(500);
    gdispFillArea(random(0,300), random(0,300), random(300,900), random(300,900), random(0,65535));
    delay(500);
    uint16_t i;
    for(i=0; i<10000; i++){
      gdispDrawPixel(random(10,width-10), random(10,height-10), random(0,65535));
    }
    delay(500);
    for(i=0; i<10; i++){
      gdispDrawLine(random(0,width-1), random(0,height-1), random(0,width-1), random(0,height-1), random(0,65535));
    }
    delay(500);
}

Best Regards

John

Link to comment
Share on other sites

It may not restrict you from putting it in the driver config file - it is just the wrong place to put it. It is a global setting for a user to change on a per project basis hence its placement in gfxconf.h

If you fix your gdisp_fill_area routine I think that looks to be quite suitable in terms of speed.

Link to comment
Share on other sites

12 hours ago, inmarket said:

If you fix your gdisp_fill_area routine I think that looks to be quite suitable in terms of speed.

Guru

Yes, gdisp_fill_area routine got fixed just now. I had mixed up the fact that in gdisp_fill_area function, arguments are (x,y) and (width,height). In RA887x it should be translated to coordinates. And the pixel draw should be a cursor based routine as well. Extract of the lld_driver look like this:

#if GDISP_HARDWARE_STREAM_WRITE
 LLDSPEC void gdisp_lld_write_start(GDisplay *g) { }

 LLDSPEC void gdisp_lld_write_color(GDisplay *g) {
  LLDCOLOR_TYPE c;
  c = gdispColor2Native(g->p.color);
  hal_lcdDataWrite16bbp(c);
 }
 LLDSPEC void gdisp_lld_write_stop(GDisplay *g) {
 }
#endif

//cursor based streaming for RA8876
#if GDISP_HARDWARE_STREAM_POS
 LLDSPEC void gdisp_lld_write_pos(GDisplay *g){
  ra8876SetPixelCursor(g->p.x, g->p.y);
  hal_lcdRegWrite(RA8876_MRWDP);
 }
#endif


#if GDISP_HARDWARE_FILLS
  LLDSPEC void gdisp_lld_fill_area(GDisplay *g) {
  drawSquare(g->p.x, g->p.y, g->p.x+g->p.cx-1, g->p.y+g->p.cy-1, gdispColor2Native(g->p.color), 1); 
  }
#endif // GDISP_HARDWARE_FILLS

Link to comment
Share on other sites

Glad to hear that you managed to got it working! :) 

 

15 minutes ago, JohnLKW said:

  LLDSPEC void gdisp_lld_fill_area(GDisplay *g) {
      drawSquare(g->p.x, g->p.y, g->p.x+g->p.cx-1, g->p.y+g->p.cy-1, gdispColor2Native(g->p.color), 1); 
  }

Well, somebody screw up the API naming :P

Link to comment
Share on other sites

On ‎5‎/‎1‎/‎2017 at 00:43, JohnLKW said:

Some progress has been made to port uGFX to RA8876 which is an advanced display driver for high resolution TFT (up to 1366x768x24-bit).

Functions tested with basic primitive draw, font printing, solid area fill by hardware, line draw & pixel draw and confirmed the system is now stable. Going further I am going to port PIXMAP for RA8876 now. Searching over uGFX library there are two files gdisp_pixmap.h & gdisp_pixmap.c.

Inside there is GDisplay *gdispPixmapCreate(coord_t width, coord_t height) calling void *gfxAlloc(size_t sz) from main memory of the MCU but this doesn't work for low resource system.

Because an external SDRAM is bonded with RA8876 and there is 2D blit function built-in the chip, a preference is to make use of off-screen area from the SDRAM to allocate a whole page for assets storage. Simply say I would need to change the *gdispPixmapCreate(coord_t width, coord_t height) function to use an off-chip memory from the MCU for a virtual screen.

There is no gdisp_lld_xxx function related to Pixmap as far as I see, right? Is it a nice approach to do this?

John

 

Link to comment
Share on other sites

You won't be able to use pixmap as pixmap assumes an addressible framebuffer. 

What you can do is create an equivalent create function for your ra8876 driver that allows creating a display surface in the extended ram of the ra8876.

Note you won't be able to use the image equivalent appearance of the pixmap and the standard gdispBlit routine because again the virtual image and the blit functions need the image bits to be in addressable ram. The way around this is to have a ra8876blit routine for transferring the offscreen images to the onscreen image.

Link to comment
Share on other sites

  • 1 month later...
On ‎5‎/‎3‎/‎2017 at 21:54, inmarket said:

You won't be able to use pixmap as pixmap assumes an addressible framebuffer. 

Over the weekend I have studied virtmem which is an Arduino library that maps external memory sources to extend the (limited) amount of available MCU's RAM. This library supports several memory resources including SPI ram & SD card hence it is possible to extend this library for a SPI-based gfx controller like ra8876. The library is made in such a way that managing and using this virtual memory closely resembles working with data from 'normal' memory. I think this will solve the problem of an external SDRAM previously "not addressable."

Actual virtmem implementation can be found in https://github.com/rhelmus/virtmem. A diagram below shows the idea.

Because dereferencing data from the external SDRAM still needs to copy the whole data structure to the main memory of MCU, a virtual pointer VPtr is used here to point to framebuffer1 reside in SDRAM. In this case only a virtual pointer is stored that the structure Surface can now fit in MCU memory!

After allocation we will be able to fill up the framebuffer1 with a certain color (yellow) like addressable ram.

Not sure if this can be implemented in Pixmap?

 

virtmem_implementation.png

Edited by JohnLKW
Link to comment
Share on other sites

1 hour ago, inmarket said:

The problem is likely to be speed. External ram is still external ram running at whatever the bus interface speed is. In this case it is likely to be very slow for a framebuffer. 

Yes, the speed won't be high for a SPI bus. The plan is to copy all assets required from a SDcard to SDRAM during initialization. Once an asset in .c array is stored in SDRAM, pictures can be copied to main window via blit. Will see...

Thank you.

Link to comment
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
×
×
  • Create New...