Documentation / Shipping it

Flashing and configuration

From the zip to a running board, and the settings you will touch after the first boot.

You have a zip from the export dialog. This page takes it to a running board, on either PlatformIO or the Arduino IDE, and then covers the configuration you are most likely to have to touch afterwards: rotation, colour, touch calibration, the filesystem for images, and the handful of boards that need something extra.

Before you power anything. Check the wiring against your board's schematic, not just against the preset. Board pinouts change between revisions, and a wrong backlight or reset pin can damage a panel. The preset's verify note and the Configuration notes in the generated README.md say what to look at.

What you need

Route A: PlatformIO

  1. Unzip. Open the project folder (the one containing platformio.ini) in VS Code with the PlatformIO extension, or cd into it.
  2. Plug the board in. If it has a BOOT button and is not detected for upload, hold BOOT while pressing RESET, then release BOOT.
  3. Build and upload:
    pio run -t upload
    The first run downloads the platform, the core and every library in lib_deps, which takes a few minutes.
  4. If the project has image assets in data/, upload the filesystem as well:
    pio run -t uploadfs
    A board with resistive touch also has data/touch_cal.txt, the touch calibration file with its starting values. Uploading it is optional - the board writes the file itself when it is missing - but uploadfs resets it, so the next boot calibrates again.
  5. Open the monitor:
    pio device monitor
    at 115200 baud. You should see <Name> starting..., any device probe results, and UI ready.

platformio.ini already sets monitor_speed, on an ESP32 the flash size, the PSRAM kind and the partitions.csv the Board tab's Partitions setting wrote, the TFT_eSPI defines where that library is used, and -DLV_CONF_INCLUDE_SIMPLE -I . so the generated lv_conf.h is the one LVGL picks up. Nothing needs copying anywhere.

Route B: Arduino IDE

  1. Unzip the project and keep its folder whole. The .ino has to stay in the folder named after it, with src/ and the other files beside it. If the IDE offers to move the sketch into a new folder, the folder has been renamed - say no and name it back, or it moves the .ino alone and leaves everything else behind.
  2. Install the board core. For an ESP32, esp32 by Espressif Systems in the Boards Manager, version 3.3 or newer - the release exports are built against. The README names the oldest that builds your design: 3.0.0 at the least, 3.1.0 with GFX Library for Arduino, 3.3.0 for anything that plays audio. A 2.x core does not search the sketch folder and stops at lv_conf.h: No such file.
  3. Install the libraries. Open LIBRARIES.md; for each entry in Install these, search for the quoted name in Sketch > Include Library > Manage Libraries and install it. Match the LVGL major version - 9.x or 8.3.x - to the one in the file's Versions table.
  4. lv_conf.h. On an ESP32, leave it where it is: the ESP32 core (3.0 or newer) reads it from the sketch folder, so each project keeps its own. On an STM32 or RP2040, copy it into your Arduino libraries/ folder, next to the lvgl folder (not inside it), replacing one left there by another project - the generated file enables only the fonts and widgets this design uses.
  5. The driver configuration. On an ESP32 there is nothing to copy for any library: with TFT_eSPI the core reads the generated User_Setup.h from the sketch folder, ahead of the one inside the library. On an STM32 or RP2040, copy it over libraries/TFT_eSPI/User_Setup.h. LovyanGFX, GFX Library for Arduino and esp_lcd are configured in the sketch folder on every chip.
  6. Open the sketch. Double-click the .ino. The IDE shows the files beside it as tabs and compiles everything under src/ with them - the screens, fonts and images are in src/ui/. src is the one subfolder the Arduino IDE builds, so do not rename or move it.
  7. Choose the board under Tools > Board - the FQBN on the Board tab, and the Board core line in LIBRARIES.md, name it. Then the settings that matter - on an ESP32 the README lists the first three for your module:
    • Flash Size: the module's - 16MB (128Mb) for an N16R8.
    • PSRAM: on an ESP32-S3, QSPI PSRAM for an R2 or R4 module and OPI PSRAM for R8 or R16; Enabled on other ESP32s with PSRAM. The wrong kind finds no PSRAM. LVGL's memory pool is taken from PSRAM on these boards, and an RGB panel's framebuffer too, so without it the sketch stops as LVGL starts.
    • Partition Scheme: the one the README names. On a 4 MB module that is Huge APP (3MB No OTA/1MB SPIFFS) for the Big app layout or No OTA (2MB APP/2MB SPIFFS) for Half and half - the same tables as the partitions.csv beside the sketch, so the size check and the filesystem uploader agree with what is flashed. On a larger module it is Custom, which needs ESP32 core 3.0 or newer. The partitions.csv is what gets flashed whichever is chosen.
    • Upload Speed: 921600 usually works; drop to 115200 if uploads fail.
    • USB CDC On Boot: enabled on S3 and C3 boards that expose native USB, or the serial monitor stays silent.
  8. Upload, then open the serial monitor at 115200.
  9. Upload the images, if there are any - see below.

Uploading image assets

Images stored on the filesystem are flashed separately from the sketch. The symptom of forgetting is every image drawing as an empty box, and ui_fs_init() printing a warning per missing file on the serial monitor. data/README.md in the export lists each file, the total against the partition, and the exact steps:

FilesystemPlatformIOArduino IDE
LittleFSpio run -t uploadfsThe arduino-littlefs-upload plugin, then Ctrl+Shift+P > Upload LittleFS to Pico/ESP8266/ESP32. It reads partitions.csv from the sketch folder, so it works with any module and layout.
SPIFFSpio run -t uploadfsOn a 4 MB module, the arduino-spiffs-upload plugin, then Ctrl+Shift+P > Upload SPIFFS to Pico/ESP8266/ESP32. It takes the filesystem's position from Tools > Partition Scheme and nowhere else, so that must be the scheme the README names - with Custom it stops with "Partitions not defined for this ESP32 board". On an 8 or 16 MB module no stock scheme matches, so it cannot be used: switch to LittleFS in Assets > Filesystem, or run the two commands data/README.md gives.
FFatpio run -t uploadfsNo Arduino IDE uploader, and the ESP32 core has no tool that builds a FAT image. Use PlatformIO for the upload, or switch to LittleFS.
SD cardCopy the files to the card's rootCopy the files to the card's root.

Both Arduino IDE plugins are for IDE 2: put the plugin's .vsix in .arduinoIDE/plugins/ in your home folder (make plugins if it is not there), restart the IDE, and close the Serial Monitor before uploading. Whichever tool you use, the files must sit in a folder named data/ next to the .ino - which is where the export puts them - and they must fit the filesystem partition: on an ESP32, the Partitions setting on the Board tab.

First boot

A good boot prints the project name, a line saying whether the touch controller answered (touch: GT911 answering at 0x5D, or touch: XPT2046 answering), a line per device the hardware layer probed, then UI ready, and the panel shows the first screen.

On a resistive touch panel the first boot calibrates touch first. A cross appears near each corner in turn; touch the centre of each one. The screen then says Touch calibrated, with which way round the axes turned out to be, or Calibration failed and why - tap to try again. The same happens after every new firmware upload, and whenever you hold a finger on the screen for a second while powering on. The serial monitor shows the raw x and y of every tap and the file as saved; see Calibrating on the board.

If the screen is blank or wrong, the serial output narrows it down fast:

The troubleshooting page has the full symptom table.

Configuration after the first boot

Almost everything is a setting in the designer, and the right fix is to change it there and re-export - the generated files are meant to be replaced, ui_events.c among them, so keep your own code in a file of your own (Your own code). The ones you are most likely to need:

SymptomSetting
The image is rotated or mirroredHardware > Display > Rotation. Touch follows the display rotation on every controller.
Colours are a negativeHardware > Display > Invert.
Red and blue are swappedHardware > Display > Colour order, RGB or BGR.
Touch lands in the wrong place (capacitive)Hardware > Touch: Swap X/Y, Invert X, Invert Y. Try Swap first if a horizontal drag moves vertically.
Touch lands in the wrong place, or is offset at the edges (resistive)Calibrate again: hold a finger on the screen for a second while powering on. The calibration measures the axis swap and direction itself, so the switches only matter until it has run. With Hardware > Touch > Calibrate touch on the board switched off, enter the raw range by hand instead.
Touch stops working until the power is removedExport again: older exports could leave an XPT2046 with its pen interrupt switched off, and did not reset I2C controllers. Current ones reset the controller on every boot and whenever it goes quiet.
Flicker, tearing, noise on the panelLower the SPI clock on the Display tab, or shorten the wires. RGB panels: check the PSRAM speed and the pixel clock.
Backlight off, or on when it should be offHardware > Display > Backlight: the pin and its active level.
Brightness is wrong, or cannot be changed on the deviceHardware > Display > Backlight > Default % is the level it starts at. To change it on the device, give a slider or a pair of buttons a Set backlight event. It dims only with PWM dimming on and the backlight on a GPIO; on an I/O expander it can only switch on and off.
The board reboots as the UI startsExport settings > Buffer height, lower. Or enable PSRAM in the IDE to match the project.
A sensor reads its initial value foreverIt was not found at boot: check its address on the Devices tab and the bus pins on the Buses tab against the serial output.

For a quick experiment you can edit lcd_pins.h directly - every one of these is a #define there - but carry the change back into the designer before the next export or it will be lost.

Board-specific notes

Re-exporting

Change the design, export again, unzip over the old folder. Everything is replaced, src/ui/ui_events.c included, so copy back your own copy of it afterwards; if the new export declares a new Call function stub, add its body to your copy from the fresh ui_events.h. A file of your own beside the sketch is never touched, because no export contains it. A changed LVGL version also means re-installing the matching library and re-uploading any image assets, whose binary format differs between 8 and 9.