espressif / esp-idf

Espressif IoT Development Framework. Official development framework for Espressif SoCs.
Apache License 2.0
13.7k stars 7.29k forks source link

[ESP32S3] [esp_lcd rgb] PSRAM Framebuffers are not flushed after allocation (IDFGH-12243) #13293

Closed seijikun closed 8 months ago

seijikun commented 8 months ago

Answers checklist.

IDF version.

v5.1

Espressif SoC revision.

esp32s3 (revision v0.2)

Operating System used.

Linux

How did you build your project?

I used Rust with esp-idf-sys. Esp-idf v5.1

If you are using Windows, please specify command line type.

None

Development Kit.

ESP32-S3-WROOM-1-N16R8

Power Supply used.

USB

What is the expected behavior?

After finalizing setup of the lcd component with esp_lcd_panel_init(), I expect the framebuffer to be completely zero'd. Meaning that the TFT shows a black blank screen.

What is the actual behavior?

The screen is corrupt at the bottom because the last bytes are stuck in the CPU cache, not yet committed to the framebuffer (in PSRAM). In this state, there further is a high chance that the entire handling gets corrupted. I've had cases where screen position (0, 0) in esp_lcd_panel_draw_bitmap() is somewhere in the middle of the screen. As well as lines shifted against each other. (Second picture)

Steps to reproduce.

  1. Create empty project with main loop
  2. Initialize psram
  3. Setup LCD exactly as is done here from line 47 to to (including) line 121.
  4. Put esp to sleep using vTaskDelay()

Debug Logs.

No response

More Information.

Unfortunately, I can't update ESP-IDF to anything newer than that because it doesn't build in that environment. However, I inspected the code and saw the problem is still there.

IMG_20240229_220103214_MFNR IMG_20240229_220126949_HDR

seijikun commented 8 months ago

Single-file reproducible example for the record: (Using Makerfabs ESP32-S3 Parallel 4.3" TFT with Touch)

#include <freertos/FreeRTOS.h>
#include <esp_log.h>
#include <esp_heap_caps.h>
#include <hal/gpio_types.h>
#include <esp_err.h>
#include <esp_psram.h>
#include <esp_lcd_panel_interface.h>
#include <esp_lcd_panel_rgb.h>
#include <freertos/timers.h>

void app_main(void) {
    esp_psram_init();

    size_t w = 800;
    size_t h = 480;

    size_t _r0 = 45;
    size_t _r1 = 48;
    size_t _r2 = 47;
    size_t _r3 = 21;
    size_t _r4 = 14;
    size_t _g0 = 5;
    size_t _g1 = 6;
    size_t _g2 = 7;
    size_t _g3 = 15;
    size_t _g4 = 16;
    size_t _g5 = 4;
    size_t _b0 = 8;
    size_t _b1 = 3;
    size_t _b2 = 46;
    size_t _b3 = 9;
    size_t _b4 = 1;

    size_t hsync_polarity = 0;
    size_t hsync_front_porch = 8;
    size_t hsync_pulse_width = 4;
    size_t hsync_back_porch = 8;
    size_t vsync_polarity = 0;
    size_t vsync_front_porch = 8;
    size_t vsync_pulse_width = 4;
    size_t vsync_back_porch = 8;
    size_t de_idle_high = 0;
    size_t pclk_active_neg = 1;
    size_t pclk_idle_high = 0;

    esp_lcd_rgb_panel_config_t *_panel_config = (esp_lcd_rgb_panel_config_t *)heap_caps_calloc(1, sizeof(esp_lcd_rgb_panel_config_t), MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);

    _panel_config->clk_src = LCD_CLK_SRC_PLL160M;
    _panel_config->timings.pclk_hz = 16000000;
    _panel_config->timings.h_res = w;
    _panel_config->timings.v_res = h;
    // The following parameters should refer to LCD spec
    _panel_config->timings.hsync_pulse_width = hsync_pulse_width;
    _panel_config->timings.hsync_back_porch = hsync_back_porch;
    _panel_config->timings.hsync_front_porch = hsync_front_porch;
    _panel_config->timings.vsync_pulse_width = vsync_pulse_width;
    _panel_config->timings.vsync_back_porch = vsync_back_porch;
    _panel_config->timings.vsync_front_porch = vsync_front_porch;
    _panel_config->timings.flags.hsync_idle_low = (hsync_polarity == 0) ? 1 : 0;
    _panel_config->timings.flags.vsync_idle_low = (vsync_polarity == 0) ? 1 : 0;
    _panel_config->timings.flags.de_idle_high = de_idle_high;
    _panel_config->timings.flags.pclk_active_neg = pclk_active_neg;
    _panel_config->timings.flags.pclk_idle_high = pclk_idle_high;

    _panel_config->data_width = 16; // RGB565 in parallel mode, thus 16bit in width
    //panel_config->bits_per_pixel = 16;
    _panel_config->sram_trans_align = 8;
    _panel_config->psram_trans_align = 64;
    _panel_config->hsync_gpio_num = 39;
    _panel_config->vsync_gpio_num = 41;
    _panel_config->de_gpio_num = 40;
    _panel_config->pclk_gpio_num = 42;

    _panel_config->data_gpio_nums[0] = _g3;
    _panel_config->data_gpio_nums[1] = _g4;
    _panel_config->data_gpio_nums[2] = _g5;
    _panel_config->data_gpio_nums[3] = _r0;
    _panel_config->data_gpio_nums[4] = _r1;
    _panel_config->data_gpio_nums[5] = _r2;
    _panel_config->data_gpio_nums[6] = _r3;
    _panel_config->data_gpio_nums[7] = _r4;
    _panel_config->data_gpio_nums[8] = _b0;
    _panel_config->data_gpio_nums[9] = _b1;
    _panel_config->data_gpio_nums[10] = _b2;
    _panel_config->data_gpio_nums[11] = _b3;
    _panel_config->data_gpio_nums[12] = _b4;
    _panel_config->data_gpio_nums[13] = _g0;
    _panel_config->data_gpio_nums[14] = _g1;
    _panel_config->data_gpio_nums[15] = _g2;

    _panel_config->disp_gpio_num = GPIO_NUM_NC;

    _panel_config->flags.disp_active_low = 0;
    _panel_config->flags.refresh_on_demand = 0;
    _panel_config->flags.fb_in_psram = 1; // allocate frame buffer in PSRAM

    esp_lcd_panel_handle_t panel_handle;
    ESP_ERROR_CHECK(esp_lcd_new_rgb_panel(_panel_config, &panel_handle));
    ESP_ERROR_CHECK(panel_handle->reset(panel_handle));
    ESP_ERROR_CHECK(panel_handle->init(panel_handle));

    while(true) {
        vTaskDelay(10);
    }
}