LVGL is unable to display background image

Hi there,

After struggling getting a decent quality picture on my display in this topic with a lot of help of @clydebarrow , which after all turned out I was trying to awake a dead display as my new display has a clear picture. This new display is this one
Specs:

  • ST7796 Display Driver
  • FT6336 Touchscreen driver
  • 480x320

While struggling with the picture quality in the earlier ment topic, I could flawlessly use wallpaper images but as soon as I changed from the ILI9488 display to the ST7796 I’m receiving these lines in my logs:

[13:11:57][W][lvgl:000]: draw_bg_img: Couldn't read the background image 	(in lv_draw_sw_rect.c line #391)
[13:11:57][W][lvgl:000]: draw_bg_img: Couldn't read the background image 	(in lv_draw_sw_rect.c line #391)
[13:11:57][W][lvgl:000]: draw_bg_img: Couldn't read the background image 	(in lv_draw_sw_rect.c line #391)
[13:11:57][W][component:237]: Component lvgl took a long time for an operation (70 ms).
[13:11:57][W][component:238]: Components should block for at most 30 ms.
[13:11:57][W][lvgl:000]: draw_bg_img: Couldn't read the background image 	(in lv_draw_sw_rect.c line #391)

Just to be clear: Exactly the same code worked with ILI9488 the only thing changed is the display driver was changed from ILI9488 sto ST7796

This is my yaml:

esphome:
  name: bath
  friendly_name: Bath
  platformio_options:
    build_flags: "-DBOARD_HAS_PSRAM"
    board_build.arduino.memory_type: qio_opi

esp32:
  board: esp32-s3-devkitc-1
  variant: esp32s3
  flash_size: 16MB
  
  #partitions: "/config/esphome/custom_16MB.csv"
  framework:
    type: arduino
    #version: latest

psram:
  mode: octal
  speed: 120MHz

# Enable logging
logger:
  level: DEBUG

# Enable Home Assistant API
api:
  encryption:
    key: "<>"

ota:
  - platform: esphome
    password: "<>"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "BathDisplay"
    password: "<>"

captive_portal:
web_server:
  port: 80

## Configuring push buttons
binary_sensor:
  - platform: gpio
    pin: GPIO3  # The GPIO pin connected to the push button
    name: "Push Button"
    id: push_button
    on_press:
      then:
        - switch.toggle: relay_s1


## Configuring the Relay Switch
switch:
  - platform: gpio
    pin: 7
    name: "S1"
    id: relay_s1
  - platform: gpio
    pin: 6
    name: "S2"
    id: relay_s2
  - platform: gpio
    pin: 5
    name: "S3"
    id: relay_s3
  - platform: gpio
    pin: 4
    name: "S4"
    id: relay_s4

# Remove the first 3 #'s to make the display work
# Configuring the SPI Pins
spi:
  clk_pin: GPIO12
  mosi_pin: GPIO11
  # miso_pin: GPIO13
  

# Assigning the i2c pins that can be used for i2c communication
i2c:
  sda: GPIO38 # Probably the boot issue due to reserved for USB_D+ --> From 20 to 38
  scl: GPIO9
  scan: True

### Configuring the Display Part
display:
  - platform: ili9xxx
    model: ST7796
    dimensions: 
      height: 320
      width: 480
      offset_height: 0
      offset_width: 0
    transform:
      swap_xy: true
      mirror_x: false
      mirror_y: false
    auto_clear_enabled: false # Disabling autoclear to be compatible with LVGL
    update_interval: 10s
    color_order: BGR # RGB or BGR
    # color_palette: IMAGE_ADAPTIVE
    # color_palette_images: 
    #   - 'bath/bg/BackgroundNightWater480x320.png'
    invert_colors: true
    #init_sequence:
    data_rate: 80Mhz
    # spi_mode: 0
    cs_pin: GPIO1
    dc_pin: GPIO42
    reset_pin: GPIO2
    # spi_mode: MODE3
    # show_test_card: true
    # rotation: 90
    #lambda: |-
    #  it.print(0, 0, id(my_font), "Hello, World!");
## Configuring things for ontrolling the display's ledled
# Define the LED pin as a PWM output
output:
  - platform: ledc
    pin: GPIO39  
    id: gpio_backlight_pwm
light:
  - platform: monochromatic
    output: gpio_backlight_pwm
    name: "Display Backlight"
    id: display_backlight
    restore_mode: ALWAYS_ON



## Configuring the touchscreen part
touchscreen:
  - platform: ft63x6
    id: my_touchscreen
    reset_pin: GPIO40
    interrupt_pin: GPIO21 # boot issue due to reserved for USB_D- --> From 19 to 21
    transform:
      mirror_x: true
      mirror_y: false
      swap_xy: true
## If LVGl needs to be enabled remove hashes START
    on_release:
      - if:
          condition: lvgl.is_paused
          then:
            - logger.log: "LVGL resuming"
            - lvgl.resume:
            - lvgl.widget.redraw:
            - light.turn_on: display_backlight
## If LVGl needs to be enabled remove hashes END

## Configuring the SD card Slot (based on assumption if it 'll be supported ever by ESPHOME')
# sd_card:
#  cs_pin: GPIO48 (This is the real connected GPIO port in preparation of potential support in the future)
#  spi_id: spi_bus

font:
  - file: "fonts/calibri.ttf"
    id: my_font
    size: 30
    bpp: 4
    extras:
      - file: "fonts/materialdesignicons-webfont.ttf"
        glyphs: [
          "\U000F0142", # mdi:chevron-right
          "\U000F0141", # mdi:chevron-left
          "\U000F02DC", # mdi:home
          ]

#Setting a wall paper for use in lvgl (Stopped working after new display)
image:
  - file: 'bath/bg/BackgroundWaterdrop.png'
    id: wallpaper
    resize: 480x320
    type: RGB565
    use_transparency: true
  - file: 'bath/bg/BackgroundNightWater480x320.png'
    id: wallpaper1
    # resize: 480x320
    type: RGB565
    use_transparency: true

### LVGL START
lvgl:
  buffer_size: 100%
  disp_bg_image: wallpaper


  
### START Theme Part
  theme:
    label:
      text_font: my_font # set all your labels to use your custom defined font
    button:
      bg_color: 0x2F8CD8
      bg_grad_color: 0x005782
      bg_grad_dir: VER
      bg_opa: COVER
      border_color: 0x0077b3
      border_width: 1
      text_color: 0xFFFFFF
      pressed: # set some button colors to be different in pressed state
        bg_color: 0x006699
        bg_grad_color: 0x00334d
      checked: # set some button colors to be different in checked state
        bg_color: 0x1d5f96
        bg_grad_color: 0x03324A
        text_color: 0xfff300
    buttonmatrix:
      bg_opa: TRANSP
      border_color: 0x0077b3
      border_width: 0
      text_color: 0xFFFFFF
      pad_all: 0
      items: # set all your buttonmatrix buttons to use your custom defined styles and font
        bg_color: 0x2F8CD8
        bg_grad_color: 0x005782
        bg_grad_dir: VER
        bg_opa: COVER
        border_color: 0x0077b3
        border_width: 1
        text_color: 0xFFFFFF
        text_font: my_font
        pressed:
          bg_color: 0x006699
          bg_grad_color: 0x00334d
        checked:
          bg_color: 0x1d5f96
          bg_grad_color: 0x03324A
          text_color: 0x005580
    switch:
      bg_color: 0xC0C0C0
      bg_grad_color: 0xb0b0b0
      bg_grad_dir: VER
      bg_opa: COVER
      checked:
        bg_color: 0x1d5f96
        bg_grad_color: 0x03324A
        bg_grad_dir: VER
        bg_opa: COVER
      knob:
        bg_color: 0xFFFFFF
        bg_grad_color: 0xC0C0C0
        bg_grad_dir: VER
        bg_opa: COVER
    slider:
      border_width: 1
      border_opa: 80%
      bg_color: 0xcccaca
      bg_opa: 80%
      indicator:
        bg_color: 0x1d5f96
        bg_grad_color: 0x03324A
        bg_grad_dir: VER
        bg_opa: COVER
      knob:
        bg_color: 0x2F8CD8
        bg_grad_color: 0x005782
        bg_grad_dir: VER
        bg_opa: COVER
        border_color: 0x0077b3
        border_width: 1
        text_color: 0xFFFFFF
  style_definitions:
    - id: header_footer
      bg_color: 0x2F8CD8
      bg_grad_color: 0x005782
      bg_grad_dir: VER
      bg_opa: TRANSP
      border_opa: TRANSP
      radius: 0
      pad_all: 0
      pad_row: 0
      pad_column: 0
      border_color: 0x0077b3
      text_color: 0xFFFFFF
      width: 100%
      height: 30
### END Theme Part
### START Page navigation footer
  top_layer:
      widgets:
        - buttonmatrix:
            align: bottom_mid
            styles: header_footer
            pad_all: 0
            outline_width: 0
            id: top_layer
            items:
              styles: header_footer
            rows:
              - buttons:
                - id: page_prev
                  text: "\U000F0141" #"\uF053"
                  on_press:
                    then:
                      lvgl.page.previous:
                - id: page_home
                  text: "\U000F02DC" # "\uF015"
                  on_press:
                    then:
                      lvgl.page.show: main_page
                - id: page_next
                  text: "\U000F0142" # "\uF054"
                  on_press:
                    then:
                      lvgl.page.next:
### END Page navigation footer

  pages:
    - id: main_page
      bg_image_src: wallpaper
      widgets:
      - switch:
          #x: 100
          #y: 100
          id: s1_lvglswitch
          on_value:
            then:
              - switch.toggle: relay_s1
      - button:
          #x: 150
          #y: 150
          #width: 100
          #height: 100
          id: s1_lgvlbtn
          checkable: false
          align: center
          widgets:
            - label:
                align: center
                text: "Relay_S1"
          on_release:
            then:
              - switch.toggle: relay_s1
    - id: led_page
      bg_image_src: wallpaper1
      widgets:
      - button:
          #x: 150
          #y: 150
          #width: 100
          #height: 100
          id: s2_lgvlbtn
          checkable: false
          align: center
          widgets:
            - label:
                align: center
                text: "Relay_S2"
          on_release:
            then:
              - switch.toggle: relay_s2
    - id: settings
      # bg_image_src: wallpaper
      widgets:
        - label:
            text: Display Brightness
        - slider:
            id: backlight_pwm_slider
            x: 50
            y: 100
            width: 220
            height: 30
            pad_all: 8
            min_value: 30
            max_value: 100
            on_release:
              then:
                - light.turn_on:
                    id: display_backlight # ID of the to be controlled light source
                    brightness: !lambda 'return x / 100.0;'
    - id: displayimagetest
      widgets:
        - label:
            text: Display Brightness
        - image:
            src: wallpaper

  on_idle:
    timeout: !lambda "return (id(display_timeout).state * 1000);" # was 1000 for 10s
    then:
      - logger.log: "LVGL is idle"
      - light.turn_off: display_backlight
      - lvgl.pause:
### LVGL END

number:
  - platform: template
    name: LVGL Screen timeout
    optimistic: true
    id: display_timeout
    unit_of_measurement: "s"
    initial_value: 20
    restore_value: true
    min_value: 1
    max_value: 180
    step: 5
    mode: box

And below the complete logs:

INFO ESPHome 2024.12.2
INFO Reading configuration /config/esphome/bath.yaml...
WARNING GPIO3 is a strapping PIN and should only be used for I/O with care.
Attaching external pullup/down resistors to strapping pins can cause unexpected failures.
See https://esphome.io/guides/faq.html#why-am-i-getting-a-warning-about-strapping-pins
INFO Starting log output from <> using esphome API
INFO Successfully connected to bath @ <> in 0.094s
INFO Successful handshake with bath @ <> in 0.060s
[13:17:58][I][app:100]: ESPHome version 2024.12.2 compiled on Dec 23 2024, 13:10:44
[13:17:58][C][wifi:600]: WiFi:
[13:17:58][C][wifi:428]:   Local MAC: <>
[13:17:58][C][wifi:433]:   SSID: 'Dagobert-Duck2'[redacted]
[13:17:58][C][wifi:436]:   IP Address: 192.<>
[13:17:58][C][wifi:440]:   BSSID: <>[redacted]
[13:17:58][C][wifi:441]:   Hostname: 'bath'
[13:17:58][C][wifi:443]:   Signal strength: -60 dB ▂▄▆█
[13:17:58][C][wifi:447]:   Channel: 9
[13:17:58][C][wifi:448]:   Subnet: <>
[13:17:58][C][wifi:449]:   Gateway: <>
[13:17:58][C][wifi:450]:   DNS1: <>
[13:17:58][C][wifi:451]:   DNS2: <>
[13:17:58][C][logger:185]: Logger:
[13:17:58][C][logger:186]:   Level: DEBUG
[13:17:58][C][logger:188]:   Log Baud Rate: 115200
[13:17:58][C][logger:189]:   Hardware UART: USB_CDC
[13:17:58][C][spi:064]: SPI bus:
[13:17:58][C][spi:065]:   CLK Pin: GPIO12
[13:17:58][C][spi:066]:   SDI Pin: 
[13:17:58][C][spi:067]:   SDO Pin: GPIO11
[13:17:58][C][spi:072]:   Using HW SPI: SPI
[13:17:58][C][i2c.arduino:071]: I2C Bus:
[13:17:58][C][i2c.arduino:072]:   SDA Pin: GPIO38
[13:17:58][C][i2c.arduino:073]:   SCL Pin: GPIO9
[13:17:58][C][i2c.arduino:074]:   Frequency: 50000 Hz
[13:17:58][C][i2c.arduino:086]:   Recovery: bus successfully recovered
[13:17:58][I][i2c.arduino:096]: Results from i2c bus scan:
[13:17:58][I][i2c.arduino:102]: Found i2c device at address 0x38
[13:17:58][C][switch.gpio:068]: GPIO Switch 'S1'
[13:17:58][C][switch.gpio:091]:   Restore Mode: always OFF
[13:17:58][C][switch.gpio:031]:   Pin: GPIO7
[13:17:58][C][switch.gpio:068]: GPIO Switch 'S2'
[13:17:58][C][switch.gpio:091]:   Restore Mode: always OFF
[13:17:58][C][switch.gpio:031]:   Pin: GPIO6
[13:17:58][C][switch.gpio:068]: GPIO Switch 'S3'
[13:17:58][C][switch.gpio:091]:   Restore Mode: always OFF
[13:17:58][C][switch.gpio:031]:   Pin: GPIO5
[13:17:58][C][switch.gpio:068]: GPIO Switch 'S4'
[13:17:58][C][switch.gpio:091]:   Restore Mode: always OFF
[13:17:58][C][switch.gpio:031]:   Pin: GPIO4
[13:17:58][C][ili9xxx:094]: ili9xxx
[13:17:58][C][ili9xxx:094]:   Rotations: 0 °
[13:17:58][C][ili9xxx:094]:   Dimensions: 480px x 320px
[13:17:58][C][ili9xxx:095]:   Width Offset: 0
[13:17:58][C][ili9xxx:096]:   Height Offset: 0
[13:17:58][C][ili9xxx:102]:   Color mode: 16bit
[13:17:58][C][ili9xxx:111]:   Data rate: 80MHz
[13:17:58][C][ili9xxx:113]:   Reset Pin: GPIO2
[13:17:58][C][ili9xxx:114]:   CS Pin: GPIO1
[13:17:58][C][ili9xxx:115]:   DC Pin: GPIO42
[13:17:58][C][ili9xxx:117]:   Color order: BGR
[13:17:58][C][ili9xxx:118]:   Swap_xy: YES
[13:17:58][C][ili9xxx:119]:   Mirror_x: NO
[13:17:58][C][ili9xxx:120]:   Mirror_y: NO
[13:17:58][C][ili9xxx:121]:   Invert colors: YES
[13:17:58][C][ili9xxx:126]:   Update Interval: 10.0s
[13:17:58][C][ledc.output:180]: LEDC Output:
[13:17:58][C][ledc.output:181]:   Pin GPIO39
[13:17:58][C][ledc.output:182]:   LEDC Channel: 0
[13:17:58][C][ledc.output:183]:   PWM Frequency: 1000.0 Hz
[13:17:58][C][ledc.output:184]:   Phase angle: 0.0°
[13:17:58][C][ledc.output:185]:   Bit depth: 14
[13:17:58][C][template.number:050]: Template Number 'LVGL Screen timeout'
[13:17:58][C][template.number:050]:   Unit of Measurement: 's'
[13:17:58][C][template.number:051]:   Optimistic: YES
[13:17:58][C][template.number:052]:   Update Interval: 60.0s
[13:17:58][C][gpio.binary_sensor:015]: GPIO Binary Sensor 'Push Button'
[13:17:58][C][gpio.binary_sensor:016]:   Pin: GPIO3
[13:17:58][C][light:092]: Light 'Display Backlight'
[13:17:58][C][light:094]:   Default Transition Length: 1.0s
[13:17:58][C][light:095]:   Gamma Correct: 2.80
[13:17:58][C][psram:020]: PSRAM:
[13:17:58][C][psram:021]:   Available: YES
[13:17:58][C][psram:024]:   Size: 8191 KB
[13:17:58][C][FT63X6:070]: FT63X6 Touchscreen:
[13:17:58][C][FT63X6:071]:   Address: 0x38
[13:17:58][C][FT63X6:072]:   Interrupt Pin: GPIO21
[13:17:58][C][FT63X6:073]:   Reset Pin: GPIO40
[13:17:58][C][FT63X6:074]:   Update Interval: 0.050s
[13:17:58][C][lvgl:086]: LVGL:
[13:17:58][C][lvgl:087]:   Display width/height: 480 x 320
[13:17:58][C][lvgl:088]:   Rotation: 0
[13:17:58][C][lvgl:089]:   Draw rounding: 2
[13:17:58][C][captive_portal:089]: Captive Portal:
[13:17:58][C][web_server:153]: Web Server:
[13:17:58][C][web_server:154]:   Address: bath.local:80
[13:17:58][C][mdns:116]: mDNS:
[13:17:58][C][mdns:117]:   Hostname: bath
[13:17:58][C][esphome.ota:073]: Over-The-Air updates:
[13:17:58][C][esphome.ota:074]:   Address: bath.local:3232
[13:17:58][C][esphome.ota:075]:   Version: 2
[13:17:58][C][esphome.ota:078]:   Password configured
[13:17:58][C][safe_mode:018]: Safe Mode:
[13:17:58][C][safe_mode:020]:   Boot considered successful after 60 seconds
[13:17:58][C][safe_mode:021]:   Invoke after 10 boot attempts
[13:17:58][C][safe_mode:023]:   Remain in safe mode for 300 seconds
[13:17:58][C][api:140]: API Server:
[13:17:58][C][api:141]:   Address: bath.local:6053
[13:17:58][C][api:143]:   Using noise encryption: YES
[13:18:03][D][main:366]: LVGL resuming
[13:18:03][D][light:036]: 'Display Backlight' Setting:
[13:18:03][D][light:047]:   State: ON
[13:18:03][D][light:085]:   Transition length: 1.0s
[13:18:04][W][component:237]: Component lvgl took a long time for an operation (91 ms).
[13:18:04][W][component:238]: Components should block for at most 30 ms.
[13:18:06][W][lvgl:000]: draw_bg_img: Couldn't read the background image 	(in lv_draw_sw_rect.c line #391)
[13:18:06][W][component:237]: Component lvgl took a long time for an operation (69 ms).
[13:18:06][W][component:238]: Components should block for at most 30 ms.
[13:18:06][W][lvgl:000]: draw_bg_img: Couldn't read the background image 	(in lv_draw_sw_rect.c line #391)

As you can see in the yaml file I added an extra page to test if the image is displayed when it isnt set as background image and it does. This proves that loading the images at lines 178-188 actually works.

So far it seems the issue relies within LVGL but I didnt’s find anyone else facing this issue.

What I already tried:

  • Changing from Arduino to ESP-IDF
  • Running without any theme config
  • Trying to add the background image to the theme
  • Add the disp_bg_image: wallpaper directly under lvgl:
  • Tried playing with transparancy here and then
  • tried to set the bg_opa within the theme from COVER to TRANSP (perhaps the code was respecting the COVER parameter since changing display driver)
  • Tried to brake down where to exactly look at and made clear the issue relies within lvgl.

I’m pretty much out of options now so I could use a little help here :wink:

I troubleshooted a bit further and discovered loading the image directly from URL by adding this image:

  - file: https://<myNabuCasaCustomDomain>.nl/local/BG/BackgroundWaterdrop.png
    id: wallpaper3
    resize: 480x320
    type: RGB565

Also results in exactly the same error:
[W][lvgl:000]: draw_bg_img: Couldn't read the background image (in lv_draw_sw_rect.c line #391)

The web doesnt report anything regarding this error. So I’m the only one in the whole wide world facing this issue, or it’s some kind of bug which only exists my specific situation.

Another tought of me is that LVGL isn’t performing well which lead to timeouts on loading the background image. I tought that it perhaps was due to the resize setting but without resizing (and offering an image of 480x320px) is also resulting in the same issue.

I have same problem
[lvgl:000]: draw_bg_img: Couldn’t read the background image (in lv_draw_sw_rect.c line #391)
while trying make buttons background.
I have succes with main bg image (ignoring warning about too large image).

Some code parts:

image:
  - file: "image.jpg"
    id: bg_image
    # resize: 320x480
    type: RGB565
  - file: "arrow1.png"
    id: img_vent1
    type: TRANSPARENT_BINARY
          widgets:
            - button:
                id: vent1
                bg_opa: TRANSP
                bg_image_src: img_vent1
                width: 120px
                height: 120px

ps: Looks like i heve bootloop

It’s a bug. Add this to your yaml:

external_components:
  - source: github://pr#8005
    components: [lvgl]

The fix won’t be merged until the new year but that will get you going for now.

5 Likes

Tested using your solution → Solved

Spend hours on this one, so glad to hear this is a bug and also very nice there is a workaround for it.

Now I can continue my project

I’ll keep an eye on the new releases next year.

Thank you very much :+1:

Heyo, in my case this workaround, worked pretty well, but after n upgrade this morning, it stopped working.

This is the Log:

In file included from src/esphome/components/lvgl/font.cpp:1:
src/esphome/components/lvgl/lvgl_esphome.h:67:8: error: 'lv_meter_indicator_t' does not name a type
   67 | inline lv_meter_indicator_t *lv_meter_add_needle_img(lv_obj_t *obj, lv_meter_scale_t *scale, esphome::image::Image *src,
      |        ^~~~~~~~~~~~~~~~~~~~
*** [.pioenvs/doorbell/src/esphome/components/lvgl/font.cpp.o] Error 1
In file included from src/esphome/components/lvgl/lvgl_esphome.cpp:6:
src/esphome/components/lvgl/lvgl_esphome.h:67:8: error: 'lv_meter_indicator_t' does not name a type
   67 | inline lv_meter_indicator_t *lv_meter_add_needle_img(lv_obj_t *obj, lv_meter_scale_t *scale, esphome::image::Image *src,
      |        ^~~~~~~~~~~~~~~~~~~~
*** [.pioenvs/doorbell/src/esphome/components/lvgl/lvgl_esphome.cpp.o] Error 1
========================= [FAILED] Took 209.78 seconds =========================

Its pretty strange bc i dont used any kind of Meters ect. in my config…
Any ideas?

Thanks

I just pushed an update to the PR that fixes that.

1 Like