diff --git a/components/esp_lcd/src/esp_lcd_panel_rgb.c b/components/esp_lcd/src/esp_lcd_panel_rgb.c index 6d1b49fac9..9ff8bcc96a 100644 --- a/components/esp_lcd/src/esp_lcd_panel_rgb.c +++ b/components/esp_lcd/src/esp_lcd_panel_rgb.c @@ -105,6 +105,8 @@ struct esp_rgb_panel_t { size_t bb_size; // If not-zero, the driver uses two bounce buffers allocated from internal memory int bounce_pos_px; // Position in whatever source material is used for the bounce buffer, in pixels uint8_t *bounce_buffer[RGB_LCD_PANEL_BOUNCE_BUF_NUM]; // Pointer to the bounce buffers + size_t bb_eof_count; // record the number we received the DMA EOF event, compare with `expect_eof_count` in the VSYNC_END ISR + size_t expect_eof_count; // record the number of DMA EOF event we expected to receive gdma_channel_handle_t dma_chan; // DMA channel handle esp_lcd_rgb_panel_vsync_cb_t on_vsync; // VSYNC event callback esp_lcd_rgb_panel_bounce_buf_fill_cb_t on_bounce_empty; // callback used to fill a bounce buffer rather than copying from the frame buffer @@ -245,10 +247,12 @@ esp_err_t esp_lcd_new_rgb_panel(const esp_lcd_rgb_panel_config_t *rgb_panel_conf // calculate buffer size size_t fb_size = rgb_panel_config->timings.h_res * rgb_panel_config->timings.v_res * fb_bits_per_pixel / 8; size_t bb_size = rgb_panel_config->bounce_buffer_size_px * fb_bits_per_pixel / 8; + size_t expect_bb_eof_count = 0; if (bb_size) { // we want the bounce can always end in the second buffer ESP_GOTO_ON_FALSE(fb_size % (2 * bb_size) == 0, ESP_ERR_INVALID_ARG, err, TAG, "fb size must be even multiple of bounce buffer size"); + expect_bb_eof_count = fb_size / bb_size; } // calculate the number of DMA descriptors @@ -270,6 +274,7 @@ esp_err_t esp_lcd_new_rgb_panel(const esp_lcd_rgb_panel_config_t *rgb_panel_conf rgb_panel->num_fbs = num_fbs; rgb_panel->fb_size = fb_size; rgb_panel->bb_size = bb_size; + rgb_panel->expect_eof_count = expect_bb_eof_count; rgb_panel->panel_id = -1; // register to platform int panel_id = lcd_com_register_device(LCD_COM_DEVICE_TYPE_RGB, rgb_panel); @@ -915,6 +920,9 @@ static IRAM_ATTR bool lcd_rgb_panel_eof_handler(gdma_channel_handle_t dma_chan, // Figure out which bounce buffer to write to. // Note: what we receive is the *last* descriptor of this bounce buffer. int bb = (desc == &panel->dma_nodes[panel->num_dma_nodes - 1]) ? 0 : 1; + portENTER_CRITICAL_ISR(&panel->spinlock); + panel->bb_eof_count++; + portEXIT_CRITICAL_ISR(&panel->spinlock); return lcd_rgb_panel_fill_bounce_buffer(panel, panel->bounce_buffer[bb]); } @@ -1008,6 +1016,10 @@ static IRAM_ATTR void lcd_rgb_panel_try_restart_transmission(esp_rgb_panel_t *pa panel->flags.need_restart = false; do_restart = true; } + if (panel->bb_eof_count < panel->expect_eof_count) { + do_restart = true; + } + panel->bb_eof_count = 0; portEXIT_CRITICAL_ISR(&panel->spinlock); #endif // CONFIG_LCD_RGB_RESTART_IN_VSYNC diff --git a/docs/en/api-reference/peripherals/lcd.rst b/docs/en/api-reference/peripherals/lcd.rst index 49707bb1b9..7358fe8709 100644 --- a/docs/en/api-reference/peripherals/lcd.rst +++ b/docs/en/api-reference/peripherals/lcd.rst @@ -387,6 +387,10 @@ More LCD panel drivers and touch drivers are available in `IDF Component Registr It's highly recommended to turn on the "PSRAM XIP (Execute In Place)" feature in this mode by enabling the Kconfig options: :ref:`CONFIG_SPIRAM_FETCH_INSTRUCTIONS` and :ref:`CONFIG_SPIRAM_RODATA`, which allows the CPU to fetch instructions and readonly data from the PSRAM instead of the main flash. What's more, the external memory cache won't be disabled even if you attempt to write to the main flash through SPI1. This makes it possible to display an OTA progress bar for your application. + .. note:: + + This mode still has another problem which is also caused by insufficient PSRAM bandwidth. e.g. when your draw buffers are allocated from PSRAM, and their contents are copied into the internal frame buffer on CPU core 1. On CPU core 0, there's another memory copy happening in the DMA EOF ISR. In this situation, both CPUs are accessing the PSRAM by cache and sharing the bandwidth of the PSRAM. This increases the memory copy time that spent in the DMA EOF ISR significantly. The driver can't switch the bounce buffer in time, thus leading to a shift on the LCD screen. Although the driver can detect such a condition and perform a restart in the LCD's VSYNC interrupt handler, you still can see a flickering on the screen. + .. code:: c esp_lcd_panel_handle_t panel_handle = NULL;