tCam - an ESP32 based thermal imaging camera with a LVGL GUI

I’m a big fan of LVGL and have used it in a lot of projects, for clients and for myself. One of my most in-depth projects uses it for a thermal imaging camera called tCam. tCam is comprised of an ESP32 development board called gCore and a Flir Lepton 3.5 based thermal imaging module called tCam-Mini. gCore has an 8-bit parallel port to the 480x320 pixel ILI9488 based capacitive touch display connected to the ESP32 VSPI peripheral that lets it run at 80 MHz which makes LVGL scream.


The project has been released as open source (GPLv3) at the tCam respository.

tCam uses the now old v6 LVGL because it had easy-to-use themes and I liked the night theme (sorry kisvegabor :slight_smile: )

One cool thing I implemented was a memory frame buffer that enables a screen dump function. You can send the camera a command and get back the contents of the display. It does this by switching the low-level driver from the ILI9488 driver to the memory frame buffer and forcing LVGL to redraw, then dumping the memory frame buffer to the external application that can save it as a png. Here are a few screen shots from the camera (some are annotated as they went into the documentation).


Great project! In the last LVGL newletters I added a sections for interesting projects and I will definitely include this project in the next one!

I’m trying to calm down. :smiley: FYI, v8 also has a dark theme option :slight_smile:

Awesome, thank you.

I have used v7 if that counts :slight_smile: But I need to move to v8 and I want to see how fast my gCore runs your benchmark and music demo. It ought to be quite speedy.

I hope it will be fast enough. :slight_smile:

I got LVGL Micropython working on gCore with a cool addition. Since gCore uses the ILI9488 with an 8-bit parallel interface I can support 16-bit pixels (as well as 32-bit pixels). I modified the driver to have a new class, ili9488g, which properly initializes and configures the driver for either 16- or 32-bit LVGL builds. The original ili9488 class is left alone. Running 16-bit pixels is much faster since there’s 1/3 less data transferred and the driver doesn’t have to spend time converting the 32-bit data to 24-bits before sending it to the display.

It’s nice to play with LVGL using Micropython. The REPL makes it easy to play around. I also got the demo running (even added a keyboard to it).

I put copies of the new driver and demo program in gCore’s repository but am curious if you’d accept a pull-request to integrate it in your repository?

I cc @amirgon, the maintainer of the MicroPython binding.

Very nice project! :+1:

PRs are very welcome!
Please feel free to open a PR and I’ll review it.

What’s the motivation to split this to two classes? To avoid code duplication it may be better to have a single class, if it’s not too difficult.

Thank you Amir. I will open a PR and I want it to be in the best format for the overall project. I understand the desire to have one class. I have a second class for the following reasons.

  1. gCore can support 16-bit pixels since the ILI9488 on it is configured with a parallel interface (the ili9488 can’t support 16-bit pixels when configured to use SPI directly - gCore has dedicated hardware that takes the SPI and converts it to 8-bit parallel). So the new class has support for this instead of generating an error message if LVGL has been compiled with 16-bit pixels. Support includes a slightly different initialization sequence as well colormode, factor, format and display_type settings.
  2. I set a default SPI clock rate of 80 MHz (since the parallel hardware supports this) and changed to using the VSPI peripheral and native pins used by gCore so the user wouldn’t have to enter all this manually when instancing the class.

Item 2 above is about convenience but I could provide a line to cut&paste if we integrated into a unified driver. I’m not sure what to do about item 1 however since someone using a pure SPI interface to the ILI9488 shouldn’t be using 16-bit pixels.

You can see my driver here: Look for ili9488g right under ili9488.

Let me know what you think.

I think it’s ok to add a new dedicated class for ili9488g, but please try to avoid code duplication where you can.

For example, I noticed in your code that the initialization commands sequence is duplicated 3 times (once in ili9488 and twice again in ili9488g) with a very small variation between them (on the 0x3A command).
Instead, why not re-use ili9488 initialization sequence on ili9488g and only override the difference? (replace the ‘data’ of the 0x3A ‘cmd’)
This may require a small change in ili9488 so you could access its initialization commands sequence from ili9488g.

btw, why did you hard-code factor? It could be useful as parameter to let the user control the tradeoff between RAM usage and performance.

Ok. I’ll work on removing the duplication. Thanks.

Regarding factor: I think I may have misunderstood it. I saw it was 4 for ili9341 and was 8 for ili9488, so I just copied that. I can return it to being configurable.

I think I addressed your concerns and suggestions. Thank you. I issued a pull request for the updated driver. However the PR had a failure generated automatically when it built for unix and a runtime failed. But I don’t understand your environment enough to know what I did wrong.

Thanks @danjulio! I’ve just merged your PR.
The GitHub Actions failure was unrelated to your PR and was also fixed.

1 Like