Best driver for ili9341 display

All ESP32 boards running MicroPython.
Target audience: MicroPython users with an ESP32 board.
Online
User avatar
pythoncoder
Posts: 5066
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

ili9341: possible GUI support

Post by pythoncoder » Tue Dec 01, 2020 7:14 am

@uCTRL I tend to favour Adafruit hardware for my reference boards as their hardware design is published and (IMO) good and their products are well documented and supported. That isn't the case for all manufacturers. I've just ported drivers for ST7735r displays for nano-gui. Looking at the code of others it seems that Sainsmart have at least four variants all with differing setup requirements. If you buy a Sainsmart display how do you know which it is? Might it be variant 5 or 95? With Adafruit I have confidence that, if I test ST7735r product ID X and a user buys that product two years down the line, it will work.

I have had experience of poor quality Chinese components: nRF24L01 radios fit only for the bin. OLED displays which work, all except for the leftmost pixels which appear on the right. Life is far too short for wasting on this crap, not to mention the endless support queries if I tried to support them.

The Adafruit resistive touch controller uses the STMPE610 which rather backs up my assertion of a wide variety of touch controllers. Do you know a reputable preferably US or European supplier of XPT2046 displays? On the plus side I already have a driver for XPT2046 contributed by Robert Hammelrath. On the minus side it's STM only and I aim to write cross-platform code these days. The XPT2046 is rather old and primitive, judging by the work Robert had to do in his driver.

To date the most promising options seem to be the Adafruit capacitive display or the resistive one with the STMPE610. But the first is rather costly, and the second isn't cheap and requires two boards. I'm not sure many users would go for these.

I also have doubts about the general interest in larger displays. My RA8875 driver has a mere 5 stars on GitHub, and even the driver for official touch panel has only 17. The exception is my original TFT GUI which does appear to be widely used despite difficult hardware connections and STM-only design. But it has high performance and has been around for a lot longer. It's hard to assess potential interest.
Peter Hinch

Online
User avatar
pythoncoder
Posts: 5066
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Best driver for ili9341 display

Post by pythoncoder » Tue Dec 01, 2020 7:24 am

Minyiky wrote:
Mon Nov 30, 2020 3:30 pm
... a similar length diagonal would take 100, and therefore is taking far longer, it would be far quicker to update the entire screen...
Based on a glance at the driver I would concentrate on the pixel method, which doesn't look ideal. Possibly implement a "draw multiple pixels" method taking a bytearray of pixel data as an arg. Optimisation is a complex issue, you need to read this doc. The viper code emitter can work wonders, but it does require some expertise to deploy. The key to optimisation is to determine exactly which pieces of code are taking the time and concentrating your efforts there.

The ultimate optimisation tools are the inline assembler and the use of dynamically loadable C modules, but I'd only go there if viper didn't deliver adequate performance.
Peter Hinch

User avatar
Minyiky
Posts: 26
Joined: Sat Oct 24, 2020 5:53 pm

Re: Best driver for ili9341 display

Post by Minyiky » Tue Dec 01, 2020 3:12 pm

Having done some more work today and looking through documentation it looks like you can only send data in rectangular sections by providing x1, x2, y1, y2. Therefore i tdont see a way of sending over data that isnt in a rectanglular format, unless the ram is read first and then over writtenfor a section. I have implimented a very minor increase in speed by removing unneccesary bytearray conversions from the command list. I have also sped up line drawing by converting into line segments and then displaying those, rather that it being 100% pixel writes.
ili9341 data write.png
ili9341 data write.png (49.92 KiB) Viewed 921 times
This is the datasheet on how to wirte to the ram, unless I am wrong this would have to be done for each pixel that is on its own, i.e. in a 40 degree line.

Looking at timings for each part (the timing function adds some time but i did the best I could) the data write for 1 pixel is about 0.5ms while the overall command takes 2.5ms.

Also when looking at lines, a 100 pixel line takes ~0.6ms compared to the 0.5ms of the 1 pixel and so clearly writing more data at one is beneficial.
Optimisation is a complex issue, you need to read this doc. The viper code emitter can work wonders, but it does require some expertise to deploy
I think I am going to have to do a lot of reading before I can get that working nicely, but I will try to investigate to see where it works.

Online
User avatar
pythoncoder
Posts: 5066
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Best driver for ili9341 display

Post by pythoncoder » Tue Dec 01, 2020 6:05 pm

Minyiky wrote:
Tue Dec 01, 2020 3:12 pm
Having done some more work today and looking through documentation it looks like you can only send data in rectangular sections by providing x1, x2, y1, y2...
Good grief: what a cumbersome way to draw a single pixel :?: That explains the driver: the pixel draw routine looked odd to me, but you have evidently found the reason. Looking at that datasheet again, it's a crude chip compared to (say) the RA8875. I think, like the ST7735r, it's designed for use with an external frame buffer: as discussed this isn't practicable with these larger displays. I see the problems that you (and @rdagger) are up against.

Viper is very effective especially for low level bit shifting, maths and suchlike. There is a learning curve and some of the concepts are more familiar if you have experience of C or assembler. However I think you're taking the right approach of concentrating on the overall design before delving into detailed optimisations.

My enthusiasm for porting my GUI to this chip is wilting by the day: it draws objects like circles, filled circles and suchlike which (subject to your findings) would probably take an age to render.
Peter Hinch

User avatar
Minyiky
Posts: 26
Joined: Sat Oct 24, 2020 5:53 pm

Re: Best driver for ili9341 display

Post by Minyiky » Tue Dec 01, 2020 7:52 pm

it's designed for use with an external frame buffer: as discussed this isn't practicable with these larger displays. I see the problems that you (and @rdagger) are up against.
As a quick side note, there is the option os the esp32 WROVER module or something like the tiny pico which have 4MiB external PSRAM. I believe this would allow for sufficient space for a framebuffer in the same way as you are using for nano GUI (obviously with a suitable driver).

Am I correct in thinking that?

Online
User avatar
pythoncoder
Posts: 5066
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Best driver for ili9341 display

Post by pythoncoder » Wed Dec 02, 2020 6:27 am

Yes, although there is a question mark over the stability of ESP32 with SPIRAM. The Pyboard D SF6W probably also has sufficient RAM, but is an expensive solution unless the project requires its other facilities. Whether it would work on an SF2W is moot.

A port to nano-gui would be easy, but there would be no touch support. Latency would be rather high owing to the size of the buffer (I'm guessing at 100ms).

At the moment I can't see a sensible way forward with this. Any solution with touch would be slow and be limited to my arbitrary choice of one of the many touch controllers available. A nano-gui version would (I suspect) have limited appeal owing to the RAM requirement and lack of touch.
Peter Hinch

User avatar
Minyiky
Posts: 26
Joined: Sat Oct 24, 2020 5:53 pm

Re: Best driver for ili9341 display

Post by Minyiky » Wed Dec 02, 2020 10:05 pm

An update from today, I spent some time looking tat c code to see if I could get some speed increases.

I will start off by saying I know nothing about c and so will almost certainly have made it less efficient than possible. I strongly based it (forked and modified) from a driver for an st7789 display as they seemed to follow a similar principle and compiled it as a micropython library. I was able to get big speed increases for small operations, drawing a short line along one axis when from ~2.5ms to ~0.5ms. When writing big chunks of data however there wasn't much speed change 40 down to 35.

I also managed to get the lvgl driver and gui working and it appears very quick, I will see if I can investigate how it is so fast

Online
User avatar
pythoncoder
Posts: 5066
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Best driver for ili9341 display

Post by pythoncoder » Thu Dec 03, 2020 7:47 am

Minyiky wrote:
Wed Dec 02, 2020 10:05 pm
...
I also managed to get the lvgl driver and gui working and it appears very quick, I will see if I can investigate how it is so fast
I've had a look at the code. They are evidently doing some very clever ESP32-specific stuff with DMA and direct access to SPI. However they set the bus to 40MHz and even suggest 80MHz. My reading of the hardware datasheet is that the write limit is 10MHz. This accounts for much of the speed. My engineering training is to treat datasheet limits as gospel.

By default they seem to create two buffers, see here and the following lines. In my reading of the code here it seems that the buffer size is 240*320*2//4 (2 coming from lv.color_t.SIZE and 4 coming from factor). However I think I must be missing something here. If you're using DMA to send 16 bit data to an ILI9341 you'd need 153600 byte buffers. Perhaps you can spot the discrepancy?

Double buffering presumably allows updates to one buffer while the other is being sent to the device as a background process. Powerful stuff.

I'll be interested to hear your findings.

LVGL is a major achievement enabling lovely GUI design. Their design criteria could hardly be more different from mine. I aim to write small, portable code in pure MicroPython which runs on official firmware. The tradeoff is a limited set of simple widgets. Theirs is heavily ESP32-specific and largely written in C.

As an aside it occurred to me that nano-gui could support larger displays (or reduce buffer size for smaller ones) using framebuf.GS4_HMSB. A lookup table could dynamically map 4 bit greyscale to hardware color - I currently use framebuf.GS8 with some simple bit-shifting. My widgets and demos currently use fewer than 16 colors. I feel an experiment coming on...
Peter Hinch

User avatar
Minyiky
Posts: 26
Joined: Sat Oct 24, 2020 5:53 pm

Re: Best driver for ili9341 display

Post by Minyiky » Thu Dec 03, 2020 10:11 am

LVGL is a major achievement enabling lovely GUI design. Their design criteria could hardly be more different from mine. I aim to write small, portable code in pure MicroPython which runs on official firmware. The tradeoff is a limited set of simple widgets.
I completely understand that, and having pure micropython code makes things far easier from a testing and usablility point. While trying out the C code for mine the process of making changes was much slower than trying to improve the micropython code, and is one of the reasons I wanted to stick with micropython for the esp32 rather than going towards c.
As an aside it occurred to me that nano-gui could support larger displays (or reduce buffer size for smaller ones) using framebuf.GS4_HMSB
Funny you should mention this, it is actually exactly what I was looking into yesterday but felt I would need to look into it a bit more as I wasnt sure how to perform that colour transformation with how framebuffers are structured. With testing I was able to create a 320x240*(1/2) framebuffer using GS4_HMSB. If the color transformations can be done then it shouldcertainly be a possibility, although 320x240 was still pushing it a bit.

I will have a look at the LVGLcode and see if there is any way to impliment wat they are doing in poure micropython / make it portable

Online
User avatar
pythoncoder
Posts: 5066
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Best driver for ili9341 display

Post by pythoncoder » Thu Dec 03, 2020 5:57 pm

You might like to look at this driver, the show method which buffers one line at a time, with _lcopy doing the on-the-fly conversion from 8bit greyscale to 16 bit color. The st7735r is rather similar to the ili9341, but for smaller displays. Changing _lcopy to handle 4 bit greyscale would be simple: add an arg which is a 16-bit*16 element array containing a LUT.

Unless I'm missing something the timing seems inescapable. The datasheet 19.3.4. gives 100ns as the minimum clock period. The chip expects 240*320*16 bits of data at 100ns per bit which I make 122ms. Add some overhead for the 4-16 bit conversion and the latency will be >=150ms. I can't see a way round this short of the extreme overclocking which LVGL seem to be using.
Peter Hinch

Post Reply