Driving a controller-less TFT directly

I would like to run lvgl on an XMOS MCU and drive a 5" TFT directly. That means the TFT doesn’t have a controller chip and no internal frame buffer either. It needs to be continuosly re-updated pixel by pixel, line by line, with a specific timing, similar to generating a VGA signal. And this needs to happen all the time, even if nothing changes on the screen. There is a library available for XMOS chips that handles communication with LCDs. Now I need to make this work with lvgl.

I don’t have enough memory for the whole screen and I want to avoid having to attach an external SDRAM since I need the pins for other stuff. Thus I need to work with buffers that store only a few lines. There will not be a memory representation of the whole screen contents anywhere (neither in the application nor in the display hardware).

It seems that lvgl is designed to write to the screen only in those places where something changes and only when something changes. What I need is something different though: I need to make lvgl continuously re-render the screen from top to bottom into small buffers. Ideally I would call a function with the Y-offset and number of lines and lvgl would fill the buffer for me.

  1. Is that even possible with lvgl, and how would I do that?

  2. What processing time should I typically expect to render an 8 lines * 800 pixels portion of the screen on a 100 MIPS system (based on typical applications)?


It’s really not supported directly.

Let’s start with the required time to render the screen. If there are 800 pixels horizontally I suppose there are 480 vertically. With 100 MIPS let’s say it takes 5 ms to paint the screen to color. Adding a button and some text should be +5…15 ms (highly depends on the complexity of the UI). In total it’s ~25 ms which is 40 FPS (40 Hz) Probably the display needs a similar refresh rate. So it might be possible for a very simple UI but then all your resources will be used for the rendering.

The “how to do it” part: You can continuously invalidate the whole screen with lv_obj_invalidate(lv_scr_sct()) and set 8 lines buffer for lvgl. You should use 2x8 lines (in 2 buffers) to let lvgl draw while the previous part is being displayed. In your disp_flush callback you can hold back lvgl to start the next chunk until it’s time comes.

1 Like

Hi Gabor! Your reply answers question 1 I think. Thank you, I will try that.

Regarding question 2, I probably didn’t express myself clearly. I was not asking how long it would take to send a full screen to the display, but how long it takes to render 8 lines (out of 480) to a buffer. That’s only 6400 pixels (2% of the screen). But I suppose that rendering an 800x8px area out of a 800x480px total area will take longer than 2% because lvgl will have to process all elements (also those not in that area), in order to generate that small part. So it comes down to how well lvgl is optimized for rendering a small part of the screen.

It would be quite interesting to see a graph with buffer size on the X axis and processing time to fill that buffer on the Y axis, and I thought someone may have done that before.

With regards to the processor: XMOS makes multi-core chips with 100 MIPS per core. The smallest chip has 8 cores. As I see it, it would not be hard to offload the code that sends data to the diplay (i.e. the display driver I need to develop) to a second core. In that case, lvgl would have 100 MIPS all to itself, just for the rendering (not counting reading input devices). That seems plenty… but the question is: how small of a buffer can I get away with. RAM is scarce on these devices. I think it would be quite cool to get lvgl working on an XMOS chip.

Actually I tried to answer both questions. I’ve calculated how long could it take to render a screen not to send it to the display. But in your case, the two things are tightly related because the rendering time should be less than sending time.
If you have only a few RAM you should really break down the rendering to smaller chunks, but you still need to calculate with the full-screen refresh time (which as you mentioned get longer with smaller buffers). I usually use 1/10 screen-sized buffer. 1/5 is faster but not that much. However, 1/50 will be much slower. (Can say an exact number right now).

Also note that 800x480 displays are usually used with 200MHz MCUs, so 100 MIPS seems a little bit slow. Just to illustrate it:
800x480 = 384,000 pixels. If you need to render 50 times in a second it’s 19,200,000 pixels. With a 100 MHz MCU, it means only 5 instructions per pixel.

1 Like