remove(lcd): remove restart support for p4 and s31

This commit is contained in:
Chen Jichang
2026-07-17 16:56:05 +08:00
parent fef97f4436
commit 9a196c8416
7 changed files with 32 additions and 15 deletions

View File

@@ -7,3 +7,4 @@ CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC=y
CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_DEC=y
CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE=y
CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED=y
CONFIG_SPIRAM_ECC_ENABLE=y

View File

@@ -14,6 +14,7 @@ menu "ESP-Driver:LCD Controller Configurations"
config LCD_RGB_RESTART_IN_VSYNC
bool "Always restart RGB LCD transmission in VSYNC"
depends on IDF_TARGET_ESP32S3
default n
help
Reset the GDMA channel every VBlank to stop permanent desyncs from happening.

View File

@@ -527,9 +527,11 @@ esp_err_t esp_lcd_rgb_panel_set_pclk(esp_lcd_panel_handle_t panel, uint32_t freq
esp_err_t esp_lcd_rgb_panel_restart(esp_lcd_panel_handle_t panel)
{
ESP_RETURN_ON_FALSE(panel, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
#if !RGB_LCD_NEEDS_SEPARATE_RESTART_LINK
ESP_RETURN_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, TAG, "restart is not supported on this target");
#endif
esp_rgb_panel_t *rgb_panel = __containerof(panel, esp_rgb_panel_t, base);
ESP_RETURN_ON_FALSE(rgb_panel->flags.stream_mode, ESP_ERR_INVALID_STATE, TAG, "not in stream mode");
// the underlying restart job will be done in the `LCD_LL_EVENT_VSYNC_END` event handler
portENTER_CRITICAL(&rgb_panel->spinlock);
rgb_panel->flags.need_restart = true;
@@ -1259,7 +1261,8 @@ static esp_err_t lcd_rgb_panel_init_trans_link(esp_rgb_panel_t *rgb_panel)
return ESP_OK;
}
// reset the GDMA channel every VBlank to stop permanent desyncs from happening.
#if RGB_LCD_NEEDS_SEPARATE_RESTART_LINK
// Reset the GDMA channel every VBlank to stop permanent desyncs from happening.
// Note that this fix can lead to single-frame desyncs itself, as in: if this interrupt
// is late enough, the display will shift as the LCD controller already read out the
// first data bytes, and resetting DMA will re-send those. However, the single-frame
@@ -1321,6 +1324,7 @@ static IRAM_ATTR void lcd_rgb_panel_try_restart_transmission(esp_rgb_panel_t *pa
}
}
#endif // RGB_LCD_NEEDS_SEPARATE_RESTART_LINK
static void lcd_rgb_panel_start_transmission(esp_rgb_panel_t *rgb_panel)
{
@@ -1391,10 +1395,12 @@ IRAM_ATTR static void rgb_lcd_default_isr_handler(void *args)
// check whether to update the PCLK frequency, it should be safe to update the PCLK frequency in the VSYNC interrupt
lcd_rgb_panel_try_update_pclk(rgb_panel);
#if RGB_LCD_NEEDS_SEPARATE_RESTART_LINK
if (rgb_panel->flags.stream_mode) {
// check whether to restart the transmission
lcd_rgb_panel_try_restart_transmission(rgb_panel);
}
#endif
}
// yield if needed

View File

@@ -215,6 +215,7 @@ esp_err_t esp_lcd_rgb_panel_set_pclk(esp_lcd_panel_handle_t panel, uint32_t freq
/**
* @brief Restart the LCD transmission
*
* @note This function is only supported on ESP32-S3.
* @note This function can be useful when the LCD controller is out of sync with the DMA because of insufficient bandwidth.
* To save the screen from a permanent shift, you can call this function to restart the LCD DMA.
* @note This function doesn't restart the DMA immediately but to set a flag internally.
@@ -225,7 +226,8 @@ esp_err_t esp_lcd_rgb_panel_set_pclk(esp_lcd_panel_handle_t panel, uint32_t freq
* @param[in] panel panel LCD panel handle, returned from `esp_lcd_new_rgb_panel`
* @return
* - ESP_ERR_INVALID_ARG: Restart the LCD failed because of invalid argument
* - ESP_ERR_INVALID_STATE: Restart the LCD failed because the LCD diver is working in refresh-on-demand mode
* - ESP_ERR_INVALID_STATE: Restart the LCD failed because the LCD driver is working in refresh-on-demand mode
* - ESP_ERR_NOT_SUPPORTED: Restarting the LCD is not supported on this target
* - ESP_OK: Restart the LCD successfully
*/
esp_err_t esp_lcd_rgb_panel_restart(esp_lcd_panel_handle_t panel);

View File

@@ -219,10 +219,7 @@ TEST_CASE("lcd_rgb_panel_update_pclk", "[lcd]")
TEST_CASE("lcd_rgb_panel_restart", "[lcd]")
{
#if CONFIG_IDF_TARGET_ESP32S31 // IDF-15960
TEST_IGNORE_MESSAGE("Known issue: lcd_rgb_panel_restart underruns on flash-encrypted runners");
#endif // CONFIG_IDF_TARGET_ESP32S31
#if CONFIG_IDF_TARGET_ESP32S3
uint8_t *img = malloc(TEST_IMG_SIZE);
TEST_ASSERT_NOT_NULL(img);
@@ -244,6 +241,12 @@ TEST_CASE("lcd_rgb_panel_restart", "[lcd]")
printf("delete RGB panel\r\n");
TEST_ESP_OK(esp_lcd_panel_del(panel_handle));
free(img);
#else
printf("initialize RGB panel with stream mode\r\n");
esp_lcd_panel_handle_t panel_handle = test_rgb_panel_initialization(16, LCD_COLOR_FMT_RGB565, 0, LCD_CLK_SRC_DEFAULT, false, false, NULL, NULL);
TEST_ASSERT_EQUAL(ESP_ERR_NOT_SUPPORTED, esp_lcd_rgb_panel_restart(panel_handle));
TEST_ESP_OK(esp_lcd_panel_del(panel_handle));
#endif
}
TEST_CASE("lcd_rgb_panel_rotate", "[lcd]")

View File

@@ -260,7 +260,7 @@ This mode allocates two "bounce buffers" from internal memory and a main frame b
.. note::
This mode also faces issues due to limited PSRAM bandwidth. For instance, if your draw buffers are in PSRAM and their contents are copied to the internal frame buffer by CPU Core 1, while CPU Core 0 is performing another memory copy in the DMA EOF ISR, both CPUs will be accessing PSRAM via cache, sharing its bandwidth. This significantly increases the memory copy time in the DMA EOF ISR, causing the driver to fail in switching the bounce buffer promptly, resulting in a screen shift. Although the driver can detect this condition and restart in the LCD's VSYNC interrupt handler, you may still notice flickering on the screen.
This mode also faces issues due to limited PSRAM bandwidth. For instance, if your draw buffers are in PSRAM and their contents are copied to the internal frame buffer by CPU Core 1, while CPU Core 0 is performing another memory copy in the DMA EOF ISR, both CPUs will be accessing PSRAM via cache, sharing its bandwidth. This significantly increases the memory copy time in the DMA EOF ISR, causing the driver to fail in switching the bounce buffer promptly, resulting in a screen shift. On ESP32-S3, the driver can detect this condition and restart in the LCD's VSYNC interrupt handler, although you may still notice flickering on the screen.
.. code:: c
@@ -305,10 +305,12 @@ Bounce Buffer Only
This mode is similar to :ref:`bounce_buffer_with_single_psram_frame_buffer`, but there is no PSRAM frame buffer initialized by the LCD driver. Instead, the user supplies a callback function that is responsible for filling the bounce buffers. As this driver does not care where the written pixels come from, this allows for the callback doing e.g., on-the-fly conversion from a smaller, 8-bit-per-pixel PSRAM frame buffer to a 16-bit LCD, or even procedurally generated frame-buffer-less graphics. This option is selected by setting the :cpp:member:`esp_lcd_rgb_panel_config_t::no_fb` flag and supplying a :cpp:member:`esp_lcd_rgb_panel_config_t::bounce_buffer_size_px` value. And then register the :cpp:member:`esp_lcd_rgb_panel_event_callbacks_t::on_bounce_empty` callback by calling :cpp:func:`esp_lcd_rgb_panel_register_event_callbacks`.
.. note::
.. only:: esp32s3
In a well-designed embedded application, situations where the DMA cannot deliver data as fast as the LCD consumes it should be avoided. However, such scenarios can theoretically occur. In the {IDF_TARGET_NAME} hardware, this results in the LCD outputting dummy bytes while the DMA waits for data. If the DMA were to run in a continuous stream, it could cause a desynchronization between the LCD address from which the DMA reads data and the address from which the LCD peripheral outputs data, leading to a **permanently** shifted image.
To prevent this, you can either enable the :ref:`CONFIG_LCD_RGB_RESTART_IN_VSYNC` option, allowing the driver to automatically restart the DMA during the VBlank interrupt, or call :cpp:func:`esp_lcd_rgb_panel_restart` to manually restart the DMA. Note that :cpp:func:`esp_lcd_rgb_panel_restart` does not restart the DMA immediately; instead, the DMA will be restarted at the next VSYNC event.
.. note::
In a well-designed embedded application, situations where the DMA cannot deliver data as fast as the LCD consumes it should be avoided. However, such scenarios can theoretically occur. In the {IDF_TARGET_NAME} hardware, this results in the LCD outputting dummy bytes while the DMA waits for data. If the DMA were to run in a continuous stream, it could cause a desynchronization between the LCD address from which the DMA reads data and the address from which the LCD peripheral outputs data, leading to a **permanently** shifted image.
To prevent this, you can either enable the :ref:`CONFIG_LCD_RGB_RESTART_IN_VSYNC` option, allowing the driver to automatically restart the DMA during the VBlank interrupt, or call :cpp:func:`esp_lcd_rgb_panel_restart` to manually restart the DMA. Note that :cpp:func:`esp_lcd_rgb_panel_restart` does not restart the DMA immediately; instead, the DMA will be restarted at the next VSYNC event.
API Reference
-------------

View File

@@ -260,7 +260,7 @@ bounce buffer 与 PSRAM frame buffer
.. note::
由于 PSRAM 带宽不足,此模式还可能存在另一个问题。例如,从 PSRAM 中分配绘图 buffer且 buffer 中的数据被复制到 CPU 核 1 上的内部 frame buffer 中,此时在 CPU 核 0 上DMA EOF ISR 也在进行内存复制。这种情况下,两个内核都通过 cache 访问 PSRAM 并共享 PSRAM 的带宽DMA EOF ISR 复制内存的时间大大增加。驱动程序无法及时切换 bounce buffer造成 LCD 屏幕移位。尽管驱动程序可以检测到这种情况并在 LCD 的 VSYNC 中断处理程序中执行重新启动,但仍会出现屏幕闪烁现象。
由于 PSRAM 带宽不足,此模式还可能存在另一个问题。例如,从 PSRAM 中分配绘图 buffer且 buffer 中的数据被复制到 CPU 核 1 上的内部 frame buffer 中,此时在 CPU 核 0 上DMA EOF ISR 也在进行内存复制。这种情况下,两个内核都通过 cache 访问 PSRAM 并共享 PSRAM 的带宽DMA EOF ISR 复制内存的时间大大增加。驱动程序无法及时切换 bounce buffer造成 LCD 屏幕移位。在 ESP32-S3 上,驱动程序可以检测到这种情况并在 LCD 的 VSYNC 中断处理程序中执行重新启动,但仍会出现屏幕闪烁现象。
.. code:: c
@@ -305,10 +305,12 @@ bounce buffer 与 PSRAM frame buffer
该模式与 :ref:`bounce_buffer_with_single_psram_frame_buffer` 模式类似,但 LCD 驱动程序不会初始化 PSRAM frame buffer。相反该模式依赖用户提供的回调函数来填充 bounce buffer。LCD 驱动程序无需指定写入像素的来源,因此回调函数可以执行一些操作:例如,将较小的每像素 8 位 PSRAM frame buffer 即时转换为 16 位 LCD 数据,甚至还可以转换为无 frame buffer 图形。若想选择此模式,可以设置 :cpp:member:`esp_lcd_rgb_panel_config_t::no_fb` 标志并提供 :cpp:member:`esp_lcd_rgb_panel_config_t::bounce_buffer_size_px` 值。然后通过调用 :cpp:func:`esp_lcd_rgb_panel_register_event_callbacks` 注册回调函数 :cpp:member:`esp_lcd_rgb_panel_event_callbacks_t::on_bounce_empty`
.. note::
.. only:: esp32s3
虽说在设计良好的嵌入式应用程序中, DMA 传递数据的速度不应该赶不上 LCD 读取数据的速度。但理论上,此种情况还是有可能出现的。在 {IDF_TARGET_NAME} 的硬件中,这种情况会导致 LCD 在 DMA 等待数据时单纯输出 dummy 字节。若以流式传输运行 DMA则 DMA 会将读取到的数据传输到某个 LCD 地址,同时 LCD 也会将数据输出到某个 LCD 地址,但上述两个地址可能会不同步,导致图像 **永久** 偏移。
为防止类似情况发生,可以启用 :ref:`CONFIG_LCD_RGB_RESTART_IN_VSYNC` 选项,以便驱动程序在 VBlank 中断时自动重启 DMA或者也可以调用 :cpp:func:`esp_lcd_rgb_panel_restart`,手动重启 DMA。请注意调用 :cpp:func:`esp_lcd_rgb_panel_restart` 不会立即重启 DMADMA 只会在下一个 VSYNC 事件中重启。
.. note::
虽说在设计良好的嵌入式应用程序中, DMA 传递数据的速度不应该赶不上 LCD 读取数据的速度。但理论上,此种情况还是有可能出现的。在 {IDF_TARGET_NAME} 的硬件中,这种情况会导致 LCD 在 DMA 等待数据时单纯输出 dummy 字节。若以流式传输运行 DMA则 DMA 会将读取到的数据传输到某个 LCD 地址,同时 LCD 也会将数据输出到某个 LCD 地址,但上述两个地址可能会不同步,导致图像 **永久** 偏移。
为防止类似情况发生,可以启用 :ref:`CONFIG_LCD_RGB_RESTART_IN_VSYNC` 选项,以便驱动程序在 VBlank 中断时自动重启 DMA或者也可以调用 :cpp:func:`esp_lcd_rgb_panel_restart`,手动重启 DMA。请注意调用 :cpp:func:`esp_lcd_rgb_panel_restart` 不会立即重启 DMADMA 只会在下一个 VSYNC 事件中重启。
API 参考
--------