Deepak Shah
Deepak Shah

Reputation: 1

Display is flickering when we refresh the screen

Description

We are using ESP32S3R8 and LVGL v8.3 for our project. SDK is ESP_IDF v5.3.2.

Display sometimes shows flickering whenever lvgl flush the buffer.

We want to stop flickering.

What we tried so far

We checked that eof_count for DMA is correct i.e. 12 for each vsync. We have also tried reducing the bounce buffer, removing the bounce buffer and XiP config. Also tried semaphore.

static void lvgl_flush_cb(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map)
{
    esp_lcd_panel_handle_t panel_handle = (esp_lcd_panel_handle_t)drv->user_data;
    int offsetx1 = area->x1;
    int offsetx2 = area->x2;
    int offsety1 = area->y1;
    int offsety2 = area->y2;
#if CONFIG_EXAMPLE_AVOID_TEAR_EFFECT_WITH_SEM
    xSemaphoreGive(sem_gui_ready);
    xSemaphoreTake(sem_vsync_end, portMAX_DELAY);
#endif

    // pass the draw buffer to the driver
    esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, color_map);
    lv_disp_flush_ready(drv);
}

static bool rgb_on_vsync_event(esp_lcd_panel_handle_t panel, const esp_lcd_rgb_panel_event_data_t *event_data, void *user_data)
{
    BaseType_t high_task_awoken = pdFALSE;
#if CONFIG_EXAMPLE_AVOID_TEAR_EFFECT_WITH_SEM
    if (xSemaphoreTakeFromISR(sem_gui_ready, &high_task_awoken) == pdTRUE)
    {
        xSemaphoreGiveFromISR(sem_vsync_end, &high_task_awoken);
    }
#endif
}

Code to reproduce

Below is the code for initialization as we are facing this issue in all screens

void lv_port_disp_init(void)
{
    static lv_disp_drv_t disp_drv; // contains callback functions

    st7701_reg_init(); // st7701 register config

#if CONFIG_EXAMPLE_AVOID_TEAR_EFFECT_WITH_SEM
    /* Create semaphores */
    sem_vsync_end = xSemaphoreCreateBinary();
    assert(sem_vsync_end);
    sem_gui_ready = xSemaphoreCreateBinary();
    assert(sem_gui_ready);
#endif

    gpio_config_t bk_gpio_config = {
        .mode = GPIO_MODE_OUTPUT,
        .pin_bit_mask = 1ULL << GPIO_LCD_BL};
    ESP_ERROR_CHECK(gpio_config(&bk_gpio_config));

    ESP_LOGI(TAG, "Install RGB panel driver");
    esp_lcd_rgb_panel_config_t panel_config = {
        .data_width = 16, // RGB565 in parallel mode, thus 16bit in width
        .psram_trans_align = 64,
#if CONFIG_EXAMPLE_USE_BOUNCE_BUFFER
        .bounce_buffer_size_px = 40 * LCD_WIDTH,
#endif
        .clk_src = LCD_CLK_SRC_DEFAULT,
        .disp_gpio_num = GPIO_NUM_NC,
        .pclk_gpio_num = GPIO_LCD_PCLK,
        .vsync_gpio_num = GPIO_LCD_VSYNC,
        .hsync_gpio_num = GPIO_LCD_HSYNC,
        .de_gpio_num = GPIO_LCD_DE,
        .data_gpio_nums = {
            GPIO_LCD_B0,
            GPIO_LCD_B1,
            GPIO_LCD_B2,
            GPIO_LCD_B3,
            GPIO_LCD_B4,
            GPIO_LCD_G0,
            GPIO_LCD_G1,
            GPIO_LCD_G2,
            GPIO_LCD_G3,
            GPIO_LCD_G4,
            GPIO_LCD_G5,
            GPIO_LCD_R0,
            GPIO_LCD_R1,
            GPIO_LCD_R2,
            GPIO_LCD_R3,
            GPIO_LCD_R4,
        },
        .timings = {
            .pclk_hz = 10 * 1000 * 1000, .h_res = LCD_WIDTH, .v_res = LCD_HEIGHT,
            // The following parameters should refer to LCD spec
            .hsync_back_porch = 50,
            .hsync_front_porch = 10,
            .hsync_pulse_width = 8,
            .vsync_back_porch = 20,
            .vsync_front_porch = 10,
            .vsync_pulse_width = 8,
            .flags.pclk_active_neg = false, // RGB data is clocked out on falling edge
        },
        .flags.fb_in_psram = true, // allocate frame buffer in PSRAM
        .flags.double_fb = true,
#if CONFIG_EXAMPLE_DOUBLE_FB
        .flags.double_fb = true, // allocate double frame buffer
#endif                           // CONFIG_EXAMPLE_DOUBLE_FB
    };

    ESP_ERROR_CHECK(esp_lcd_new_rgb_panel(&panel_config, &Lcd_panel_handle));

    /* Register event callbacks */
    esp_lcd_rgb_panel_event_callbacks_t cbs = {
        .on_vsync = rgb_on_vsync_event,
        .on_bounce_empty = rgb_on_bounce_buf_fill,
        .on_bounce_frame_finish = rgb_on_bounce_buf_finish,
    };

    ESP_ERROR_CHECK(esp_lcd_rgb_panel_register_event_callbacks(Lcd_panel_handle, &cbs, &disp_drv));

    /* Initialize RGB LCD panel */
    ESP_ERROR_CHECK(esp_lcd_panel_reset(Lcd_panel_handle));
    ESP_ERROR_CHECK(esp_lcd_panel_init(Lcd_panel_handle));

    ESP_LOGI(TAG, "Turn on LCD backlight");
    /*
        打开屏幕背光
    */
    gpio_set_level(GPIO_LCD_BL, 1);
    ESP_LOGI(TAG, "LCD resolution: %dx%d", LCD_WIDTH, LCD_HEIGHT);

    /* initialize LVGL draw buffers */
    /*
        对LVGL渲染屏幕缓冲区进行初始化
    */
    static lv_disp_draw_buf_t disp_buf;
    void *buf1 = NULL;
    void *buf2 = NULL;

#if CONFIG_EXAMPLE_DOUBLE_FB
    ESP_LOGI(TAG, "Use frame buffers as LVGL draw buffers");
    ESP_ERROR_CHECK(esp_lcd_rgb_panel_get_frame_buffer(Lcd_panel_handle, 2, &buf1, &buf2));
    // initialize LVGL draw buffers
    lv_disp_draw_buf_init(&disp_buf, buf1, buf2, LCD_WIDTH * LCD_HEIGHT);
#else

    ESP_LOGI(TAG, "Allocate separate LVGL draw buffers from PSRAM");
    uint16_t fact = 480;
    buf1 = heap_caps_malloc(LCD_WIDTH * fact * sizeof(lv_color_t), MALLOC_CAP_SPIRAM); // MALLOC_CAP_SPIRAM
    assert(buf1);

#if 1

    buf2 = heap_caps_malloc(LCD_WIDTH * fact * sizeof(lv_color_t), MALLOC_CAP_SPIRAM);
    assert(buf2);
    // initialize LVGL draw buffers
    lv_disp_draw_buf_init(&disp_buf, buf1, buf2, LCD_WIDTH * fact);

#else
    lv_disp_draw_buf_init(&disp_buf, buf1, NULL, LCD_WIDTH * fact);
#endif
#endif // CONFIG_EXAMPLE_DOUBLE_FB

    /* Register the display in LVGL */
    lv_disp_drv_init(&disp_drv);

    /*Set the resolution of the display*/
    disp_drv.hor_res = LCD_WIDTH;
    disp_drv.ver_res = LCD_HEIGHT;
    /*Used to copy the buffer's content to the display*/
    disp_drv.flush_cb = lvgl_flush_cb;
    /*Set a display buffer*/
    disp_drv.draw_buf = &disp_buf;

    disp_drv.user_data = Lcd_panel_handle;

    disp_drv.full_refresh = true;

#if CONFIG_EXAMPLE_DOUBLE_FB
    disp_drv.full_refresh = true; // the full_refresh mode can maintain the synchronization between the two frame buffers
#endif

    /*Finally register the driver*/
    lv_disp_drv_register(&disp_drv);
}

Upvotes: 0

Views: 15

Answers (0)

Related Questions