# Tips and tricks (/integration/chip_vendors/espressif/tips_and_tricks)



Improving LVGL speed of execution [#improving-lvgl-speed-of-execution]

IDF projects are generally configured to optimize the final application image for size. For some
LVGL applications this is not desirable and results in poor execution speed.

In this case it is worth setting some of the IDF project-wide options in
`sdkconfig.defaults`, such as:

```ini title="ini" lineNumbers=1
CONFIG_COMPILER_OPTIMIZATION_PERF=y
```

This compiles the application with performance as the priority, using SIMD
instructions where possible. An increase of up to 30% in overall execution speed can be observed.

It is also possible to speed up the execution of LVGL's critical code by
telling the compiler to put those sections in the IRAM area of ESP32 chips with
the following option:

```ini title="ini" lineNumbers=1
CONFIG_LV_ATTRIBUTE_FAST_MEM_USE_IRAM=y
```

The CPU can also be set to always run at its maximum speed with the
`CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_` option. The frequency varies from chip to
chip; for example, the P4 family supports 360 MHz:

```ini title="ini" lineNumbers=1
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_360
```

and the ESP32/ESP32-S3 support 240 MHz:

```ini title="ini" lineNumbers=1
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240
```

<Callout type="info">
  Some of these options need the IDF experimental options to be enabled:

  ```ini title="ini" lineNumbers=1
  CONFIG_IDF_EXPERIMENTAL_FEATURES=y
  ```
</Callout>

Configuring the PSRAM on ESP32 supported devices [#configuring-the-psram-on-esp32-supported-devices]

Some of the high-end ESP32 chips have external memory in their module: Pseudo-Static Random
Access Memory, or PSRAM. Values from 4 to 16 MB are typical, and LVGL can use a portion of this
memory to:

* Copy read-only objects from flash to PSRAM to increase speed.
* Use direct mode plus dual buffers even on an ESP32 that does not have a built-in display controller.

In both scenarios the result is less time spent flushing data to the display, resulting in higher
frame rates. To enable PSRAM usage, set:

```ini title="ini" lineNumbers=1
CONFIG_SPIRAM=y
CONFIG_SPIRAM_MODE_HEX=y
CONFIG_SPIRAM_USE=y
CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY=y
CONFIG_SPIRAM_RODATA=y
```

These options can reside in the IDF project's `sdkconfig.defaults`.

Application crashes when enabling PPA [#application-crashes-when-enabling-ppa]

An application can start crashing after the `CONFIG_LV_USE_PPA` option is enabled. The typical
symptom is a message on the monitor console indicating an error when the ESP32 calls the
`esp_msync` function.

This happens because the PPA only accepts chunks of data that are aligned to the L1 cache line
size, that is, 64 bytes. Even though the PPA draw unit handles the alignment of the source buffer,
the target draw buffer area has to be aligned as well, otherwise the transfer from the PPA to it
may fail. To prevent this, make `CONFIG_LV_DRAW_BUF_ALIGN` a multiple of the L1 cache line size,
i.e. set it to `64` instead of the default `4`.

```ini title="ini" lineNumbers=1
CONFIG_LV_DRAW_BUF_ALIGN=64
```

ESP32-P4 monitor log reports buffer underrun and frame-rate decreases [#esp32-p4-monitor-log-reports-buffer-underrun-and-frame-rate-decreases]

When PSRAM is enabled and the PPA is used, it is common to see frame rate degradation followed by
a log message reporting that the display buffer will underrun. This happens because, depending on
the IDF version, PSRAM was not enabled with the maximum supported speed.

To fix it, add the following option to `sdkconfig.defaults`:

```ini title="ini" lineNumbers=1
CONFIG_SPIRAM_SPEED_200M=y
```

Additionally, the PPA burst length can be increased to raise the memory bandwidth of a particular
channel and gain speed in the drawing operations:

```ini title="ini" lineNumbers=1
CONFIG_LV_PPA_BURST_LENGTH=128
```

There is a downside to increasing the burst length: if another piece of ESP-IDF code uses a DMA2D
channel that is shared with the PPA, the increase may slow down that channel's consumer. Also mind
that the supported burst length values are 128, 64, 32, 16, and 8 bytes; any other value results
in a build error.

Enabling LVGL logs on IDF project [#enabling-lvgl-logs-on-idf-project]

LVGL logs are not enabled by default. To enable them, add the following options to
`sdkconfig.defaults`:

```ini title="ini" lineNumbers=1
CONFIG_LV_USE_LOG=y
CONFIG_LV_LOG_LEVEL_INFO=y
CONFIG_LV_LOG_PRINTF=y
```

The logging subsystem of LVGL relies on `printf` being present in ESP-IDF.

Using the File System under ESP-IDF [#using-the-file-system-under-esp-idf]

ESP-IDF uses the standard C file operation functions (`fopen`, `fread`) in all its storage related APIs.
This allows seamless interoperability with LVGL when enabling the <ApiLink name="LV_USE_FS_STDIO" /> configuration.
The process is described in detail below, using `SPIFFS` as a demonstration.

<Steps>
  <Step>
    **Decide what storage system you want to use**

    ESP-IDF has many ready-to-use examples, like
    [SPIFFS](https://github.com/espressif/esp-idf/tree/master/examples/storage/spiffsgen),
    [SD Card](https://github.com/espressif/esp-idf/tree/master/examples/storage/sd_card/sdspi) and
    [LittleFS](https://github.com/espressif/esp-idf/tree/master/examples/storage/littlefs).
  </Step>

  <Step>
    **Enable LVGL's STDIO file system**

    You can use `menuconfig`:

    * `Component config → LVGL configuration → 3rd Party Libraries`: enable `File system on top of stdio API`
    * Then select `Set an upper cased letter on which the drive will accessible` and set it to `65` (ASCII **A**)
    * You can also set `Default driver letter` to 65 to skip the prefix in file paths.
  </Step>

  <Step>
    **Modify the partition table**

    The exact configuration depends on your flash size and existing partitions,
    but the new final result should look something like this:

    | Name      | Type | SubType | Offset  | Size   |
    | --------- | ---- | ------- | ------- | ------ |
    | nvs       | data | nvs     | 0x9000  | 0x6000 |
    | phy\_init | data | phy     | 0xf000  | 0x1000 |
    | factory   | app  | factory | 0x10000 | 1400k  |
    | storage   | data | spiffs  |         | 400k   |

    <Callout type="info">
      If you are not using a custom `partition.csv` yet, it can be added
      via `menuconfig` (`Partition Table → Partition Table → Custom partition table CSV`).
    </Callout>
  </Step>

  <Step>
    **Apply changes to the build system**

    Some ESP file systems provide automatic generation from a host folder using CMake. The proper
    line(s) must be copied to `main/CMakeLists.txt`.

    <Callout type="info">
      `LittleFS` has extra dependencies that should be added to `main/idf_component.yml`.
    </Callout>
  </Step>

  <Step>
    **Prepare the image files**

    LVGL's `LVGLImage.py` Python tool can be used to convert images to binary pixel map files.
    It supports various formats and compression.

    Meanwhile 3rd party libraries
    (like [LodePNG](/libs/image_support/lodepng) and [Tiny JPEG](/libs/image_support/tjpgd))
    allow using image files without conversion.

    After preparing the files, they should be moved to the target device:

    * If properly activated, a **SPIFFS** file system based on the `spiffs_image` folder should be automatically generated and later flashed to the target
    * A similar mechanism for **LittleFS** uses the `flash_data` folder, but it's only available for Linux hosts
    * For the **SD Card**, a traditional file browser can be used
  </Step>

  <Step>
    **Invoke proper API calls in the application code**

    The core functionality requires only a few lines. The following example draws the image as well.

    ```c title=" " lineNumbers=1
    #include "esp_spiffs.h"

    void lv_example_image_from_esp_fs(void)
    {
        esp_vfs_spiffs_conf_t conf = {
            .base_path = "/spiffs",
            .partition_label = NULL,
            .max_files = 5,
            .format_if_mount_failed = false
        };

        esp_err_t ret = esp_vfs_spiffs_register(&conf);

        if(ret != ESP_OK) {
            ESP_LOGE(TAG, "Failed to register SPIFF filesystem");
            return;
        }

        lv_obj_t * obj = lv_image_create(lv_screen_active());
        lv_image_set_src(obj, "A:/spiffs/logo.bin");
        lv_obj_center(obj);
    }
    ```
  </Step>

  <Step>
    **Build and flash**

    After calling `idf.py build flash` the picture should be displayed on the screen.
  </Step>
</Steps>

<Callout type="info">
  Changes made by `menuconfig` are not being tracked in the repository if the `sdkconfig` file is added to `.gitignore`, which is the default for many ESP-IDF projects.
  To make your configuration permanent, add the following lines to `sdkconfig.defaults`:

  ```ini title="ini" lineNumbers=1
  CONFIG_PARTITION_TABLE_CUSTOM=y
  CONFIG_LV_USE_FS_STDIO=y
  CONFIG_LV_FS_STDIO_LETTER=65
  CONFIG_LV_FS_DEFAULT_DRIVER_LETTER=65
  ```
</Callout>
