LVGL with ILI9341 + Touch panel

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

Re: LVGL with ILI9341 + Touch panel

Post by pythoncoder » Wed Jan 27, 2021 7:02 am

Divergentti wrote:
Tue Jan 26, 2021 4:19 pm
About my code: I hit into serious memory issues and I re-structured and refactored it quite a bit. I removed comments, shortened variable names etc.

For some reason speeding up CPU to 240MHz seems to keep free memory around 40 000, but if I use standard 160MHz, free memory might dip almost 0 and sometimes I got out of memory.
I assume you've read this doc which has a lot of tips for RAM reduction.

I haven't studied your code but I have written drivers for the chip. It is not ideal for microcontroller use because it requires a large frame buffer. The RA8875 is a much better solution as the graphics primitives are handled on chip so no frame buffer is required. Frame buffers are great for small displays but their RAM usage on multi-pixel displays soon becomes excessive even if you use 4-bit color with a lookup table. The GUI in the linked RA8875 code is designed to be RAM efficient.
Peter Hinch
Index to my micropython libraries.

Divergentti
Posts: 67
Joined: Fri Sep 04, 2020 9:27 am
Location: Hanko, Finland
Contact:

Re: LVGL with ILI9341 + Touch panel

Post by Divergentti » Wed Jan 27, 2021 7:58 am

spookyrufus wrote:
Tue Jan 26, 2021 8:07 pm
Divergentti wrote:
Tue Jan 26, 2021 7:57 am
Reason is most likely Post of Finland
What are the chances.. I'm across the gulf, in Tallinn. Terve fellow micropythonist!
Heipä hei ja hauska tavata! Some dark and clear nights I can see Tallin's lights from here :)
Last edited by Divergentti on Wed Jan 27, 2021 8:15 am, edited 2 times in total.

Divergentti
Posts: 67
Joined: Fri Sep 04, 2020 9:27 am
Location: Hanko, Finland
Contact:

Re: LVGL with ILI9341 + Touch panel

Post by Divergentti » Wed Jan 27, 2021 8:14 am

pythoncoder wrote:
Wed Jan 27, 2021 7:02 am
Divergentti wrote:
Tue Jan 26, 2021 4:19 pm
About my code: I hit into serious memory issues and I re-structured and refactored it quite a bit. I removed comments, shortened variable names etc.

For some reason speeding up CPU to 240MHz seems to keep free memory around 40 000, but if I use standard 160MHz, free memory might dip almost 0 and sometimes I got out of memory.
I assume you've read this doc which has a lot of tips for RAM reduction.

I haven't studied your code but I have written drivers for the chip. It is not ideal for microcontroller use because it requires a large frame buffer. The RA8875 is a much better solution as the graphics primitives are handled on chip so no frame buffer is required. Frame buffers are great for small displays but their RAM usage on multi-pixel displays soon becomes excessive even if you use 4-bit color with a lookup table. The GUI in the linked RA8875 code is designed to be RAM efficient.
Thank you @pythoncoder for the doc. I read it while ago and I understand ram fragmentation. I managed to improve my code, but root cause seems to be the framebuffer, as you described.

I had problem finding proper driver with Google for the display and the touchscreen. Lesson learnt: maybe this forum contains section for best practises and robust drivers for the MPY, but I missed it. At least I missed to read through articles describing the framebuffer issue.

Last night went without reboots, video https://youtu.be/oqlWTdjBryk but I will redo code with RA8875 anyway, because I have lost my trust to current display driver. So, if someone already took example from my bad code, just skip it.

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

Re: LVGL with ILI9341 + Touch panel

Post by pythoncoder » Wed Jan 27, 2021 8:43 am

My view is that RA8875 is the best solution for large, touch sensitive displays. Its one drawback is that it isn't particularly fast: a complete redraw of complex screens with a lot of elements (like my keyboard demos) is not visually instantaneous.

If speed is crucial you'll find a solution based on SSD1963 and XPT2046 here. It uses a parallel interface and highly optimised code courtesy of @roberthh, but inevitably that means it uses a lot of pins. And it's Pyboard only, where my other drivers are cross-platform.

The other option is to assess whether you really need such a big display. The official LCD160CR has a factory calibrated touch overlay and with careful design can display a good deal of information: see this repo. The touch GUI allows for nested screens which enhances this.

Lastly, if you don't need touch, nano-gui supports a good many smaller displays up to (at a pinch) ILI9341. But the buffer is 34K even with 4-bit pixels. Note the monochrome ePaper displays that have quite a lot of pixels with a small frame buffer (1 bit per pixel).

There is quite a lot of choice.
Peter Hinch
Index to my micropython libraries.

Divergentti
Posts: 67
Joined: Fri Sep 04, 2020 9:27 am
Location: Hanko, Finland
Contact:

Re: LVGL with ILI9341 + Touch panel

Post by Divergentti » Wed Jan 27, 2021 9:55 am

pythoncoder wrote:
Wed Jan 27, 2021 8:43 am
My view is that RA8875 is the best solution for large, touch sensitive displays. Its one drawback is that it isn't particularly fast: a complete redraw of complex screens with a lot of elements (like my keyboard demos) is not visually instantaneous.

If speed is crucial you'll find a solution based on SSD1963 and XPT2046 here. It uses a parallel interface and highly optimised code courtesy of @roberthh, but inevitably that means it uses a lot of pins. And it's Pyboard only, where my other drivers are cross-platform.

The other option is to assess whether you really need such a big display. The official LCD160CR has a factory calibrated touch overlay and with careful design can display a good deal of information: see this repo. The touch GUI allows for nested screens which enhances this.

Lastly, if you don't need touch, nano-gui supports a good many smaller displays up to (at a pinch) ILI9341. But the buffer is 34K even with 4-bit pixels. Note the monochrome ePaper displays that have quite a lot of pixels with a small frame buffer (1 bit per pixel).

There is quite a lot of choice.
You have done excellect job with drivers! I try to adapt best practises to my code.

First try with your example I had no success.

I have to learn more about what goes wrong with memory allocation ...

REPL:

Code: Select all

Ignoring framebuf_utils.mpy: compiled for incorrect architecture.
Traceback (most recent call last):
  File "main.py", line 674, in <module>
  File "drivers/ili93xx/ili9341.py", line 58, in __init__
MemoryError: memory allocation failed, allocating 38400 bytes
MicroPython v1.13 on 2020-09-02; ESP32 module with ESP32
Type "help()" for more information.
main.py

Code: Select all

from drivers.ili93xx.ili9341 import ILI9341 as SSD
from gui.core.nanogui import refresh
...
665:height = 240
666:
667: pdc = Pin(TFT_DC_PIN, Pin.OUT, value=0)  # Arbitrary pins
668: pcs = Pin(TFT_CS_PIN, Pin.OUT, value=1)
669: prst = Pin(TFT_RST_PIN, Pin.OUT, value=1)
670: # Hardware SPI on native pins for performance. Check DRIVERS.md for optimum baudrate.
671: spi = SPI(TFT_SPI, baudrate=10000000, sck=Pin(TFT_CLK_PIN), mosi=Pin(TFT_MOSI_PIN), miso=Pin(TFT_MISO_PIN))
672: gc.collect()
673: # ssd = SSD(spi, pcs, pdc, prst, height=height)  # Must specify height for SSD1351
674: ssd = SSD(spi, pcs, pdc, prst)  # The other Adafruit displays use defaults
675: # On st7735r 1.8 inch display can exchange height and width for portrait mode. See docs.
676: # The 1.44 inch display is symmetrical so this doesn't apply
677: 
678:
679: refresh(ssd, True)  # Initialise and clear display.
680: # Uncomment for ePaper displays
681: # ssd.wait_until_ready()
682: ssd.fill(0)
683: ssd.line(0, 0, ssd.width - 1, ssd.height - 1, ssd.rgb(0, 255, 0))  # Green diagonal corner-to-corner
684: ssd.rect(0, 0, 15, 15, ssd.rgb(255, 0, 0))  # Red square at top left
685: ssd.rect(ssd.width -15, ssd.height -15, 15, 15, ssd.rgb(0, 0, 255))  # Blue square at bottom right
686: ssd.show()
and in the ili9341.py

Code: Select all

...
57: gc.collect()
58: buf = bytearray(self.height * self.width // 2)
Update:

I tried with IDFv3 and IDFv4, same result. In ili9341.py I changed from time import sleep_ms to utime, and then memory allocation error is only 4xx bytes, but still does not work. I commented out @micropython.viper and I tried to understand def _lcopy(dest: ptr8, source: ptr8, lut: ptr8, length: int): meaning, because I do not see from where ptr8 shall inherit from.

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

Re: LVGL with ILI9341 + Touch panel

Post by pythoncoder » Wed Jan 27, 2021 4:39 pm

Nearly 35K is a large buffer. It is vital to instantiate the ILI9341 as early as possible in your code. It is advisable to issue gc.collect() immediately before instantiating. The message about "Ignoring framebuf_utils.mpy" is normal and harmless. To give you an idea of how I do it, the demos in nano-gui have this as their first executable line:

Code: Select all

from color_setup import ssd  # Create a display instance
And a typical color_setup.py (which contains the hardware specific code and instantiates the display) looks like this:

Code: Select all

from machine import Pin, SPI
import gc
from drivers.ili93xx.ili9341 import ILI9341 as SSD

pdc = Pin(25, Pin.OUT, value=0)  # Arbitrary pins
pcs = Pin(26, Pin.OUT, value=1)
prst = Pin(27, Pin.OUT, value=1)

gc.collect()  # Precaution before instantiating framebuf
spi = SPI(1, 10_000_000, sck=Pin(14), mosi=Pin(13), miso=Pin(12))
ssd = SSD(spi, dc=pdc, cs=pcs, rst=prst)  # Huge buffer created now
The point being that the absolute bare minimum of code gets to run before the buffer is created.

That said, the ILI9341 is pushing things with its buffer size and I did debate for some time whether to support it. In my testing
on the ESP32 it worked fine, but mileages may vary. ;)
Peter Hinch
Index to my micropython libraries.

Divergentti
Posts: 67
Joined: Fri Sep 04, 2020 9:27 am
Location: Hanko, Finland
Contact:

Re: LVGL with ILI9341 + Touch panel

Post by Divergentti » Thu Jan 28, 2021 11:30 am

pythoncoder wrote:
Wed Jan 27, 2021 4:39 pm
Nearly 35K is a large buffer. It is vital to instantiate the ILI9341 as early as possible in your code. It is advisable to issue gc.collect() immediately before instantiating. The message about "Ignoring framebuf_utils.mpy" is normal and harmless. To give you an idea of how I do it, the demos in nano-gui have this as their first executable line:

Code: Select all

from color_setup import ssd  # Create a display instance
And a typical color_setup.py (which contains the hardware specific code and instantiates the display) looks like this:

Code: Select all

from machine import Pin, SPI
import gc
from drivers.ili93xx.ili9341 import ILI9341 as SSD

pdc = Pin(25, Pin.OUT, value=0)  # Arbitrary pins
pcs = Pin(26, Pin.OUT, value=1)
prst = Pin(27, Pin.OUT, value=1)

gc.collect()  # Precaution before instantiating framebuf
spi = SPI(1, 10_000_000, sck=Pin(14), mosi=Pin(13), miso=Pin(12))
ssd = SSD(spi, dc=pdc, cs=pcs, rst=prst)  # Huge buffer created now
The point being that the absolute bare minimum of code gets to run before the buffer is created.

That said, the ILI9341 is pushing things with its buffer size and I did debate for some time whether to support it. In my testing
on the ESP32 it worked fine, but mileages may vary. ;)
Thank you again @pythoncoder for the help. I see you use gc.collect() a lot as an example in MQTT_AS.py. I strugled almost a day with line 538 loop.create_task(self._connect_handler(self)) # User handler. which always gave me error "function takes 0 positional arguments but 1 were given" .... until I realized that in the connect_coro sub I have to use (client) instead of just () in the function :)

Code https://github.com/divergentti/airquali ... ouchscreen seems to work now fine with old display driver, but I will give your drivers new try when I have finished these basic functionality with current setup.

Code: Select all

mqtt-publish 160
WiFi Connected True
MQTT Connected True
Memory free: 19296
Memory alloc: 91920
Toucscreen pressed: False
Details screen active: False
Image

User avatar
spookyrufus
Posts: 12
Joined: Wed Jul 15, 2020 8:09 am
Location: Estonia
Contact:

Re: LVGL with ILI9341 + Touch panel

Post by spookyrufus » Sun Feb 14, 2021 8:06 pm

Just to update this original thread, I finally got the new display, *with* the touch driver chip soldered on, and connected it to the same SPI bus as the display (using a lower frequency), and everything works just perfectly :)
LVGL seems like a really powerful tool to quickly build interfaces: I look forward learning to work with it.

Post Reply