esp32_lvgl_driver小缺陷

一月一星辰發表於2024-10-14

問題背景

最近在除錯一個新螢幕的過程中,使用LVGL官方的lvgl_esp32_driver驅動,在我這個解析度比較大(454 x 454)的螢幕下會出現,在分配完成buff後,若buff過大會出現,在刷屏的時候會這種警告。

txdata transfer > hardware max supported len

研究了底層程式碼後發現在spi_master.c檔案中,在傳送大量資料queue中,會檢測一下相關引數。
image.png

檢視一下這個宏SPI_LL_DMA_MAX_BIT_LEN
image.png

[!注意]
這裡注意下,這個宏在不同晶片中,體現的是不同的,在esp32s3中是1<<18 ,在esp32中卻是1<<24。

這時看下官方的這裡的驅動介面:
image.png

只呼叫了一次,所以會將buff中的資料一次性全部傳送出去, 官方推薦buff為:解析度寬 x 高 x 1/10 。
約為 454 x 45 x 8 x 2 = 326880。(16bit 畫素色彩)
1 << 18 = 262144
遠大於判斷,所以無法正常刷屏。

如何解決這個問題呢,解決方法很簡單那就是分包。把一打包資料分幾次傳送就可以了。其實esp32官方是對這個問題有一套很好的解決方法。並歸入了官方SDK的esp_lcd中,我們只需要根據官方架構編寫一套即可。

ESP32_LCD使用

首先官方例程下相關示例,可以在examples/peripherals/lcd/找到。
更多的驅動程式可以透過樂鑫元件登錄檔 獲取。
這裡我複製一套驅動(GC9A01)並且修改一下初始化程式碼既可以改寫完成。下面介紹一下如何正確的呼叫。
image.png

  • 標頭檔案
#include "esp_lcd_rm69330.h" // 自定義的驅動檔案

#include "esp_lcd_panel_io.h"

#include "esp_lcd_panel_vendor.h"

#include "esp_lcd_panel_ops.h"
  • 裝置初始化
ESP_LOGI(TAG, "Initialize SPI bus");

spi_bus_config_t buscfg = {

	.sclk_io_num = LV_PIN_NUM_LCD_CLK,

	.mosi_io_num = LV_PIN_NUM_LCD_MOSI,

	.miso_io_num = LV_PIN_NUM_LCD_MISO,

	.quadwp_io_num = -1,

	.quadhd_io_num = -1,

	.max_transfer_sz = SPI_BUS_MAX_TRANSFER_SZ,

};

ESP_ERROR_CHECK(spi_bus_initialize(SPI_LCD_HOST, &buscfg, SPI_DMA_CH_AUTO));



ESP_LOGI(TAG, "Install panel IO");

esp_lcd_panel_io_handle_t io_handle = NULL;

esp_lcd_panel_io_spi_config_t io_config = {

	.dc_gpio_num = LV_PIN_NUM_LCD_DC,

	.cs_gpio_num = LV_PIN_NUM_LCD_CS,

	.pclk_hz = SPI_TFT_CLOCK_SPEED_HZ,

	.lcd_cmd_bits = 8,

	.lcd_param_bits = 8,

	.spi_mode = 0,

	.trans_queue_depth = SPI_TRANSACTION_POOL_SIZE,

	.on_color_trans_done = notify_refresh_ready,

	.user_ctx = &disp_drv,

};



// Attach the LCD to the SPI bus

ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)SPI_LCD_HOST, &io_config, &io_handle));



esp_lcd_panel_dev_config_t panel_config = {

	.reset_gpio_num = LV_PIN_NUM_LCD_RST,

	.color_space = ESP_LCD_COLOR_SPACE_BGR,

	.bits_per_pixel = 16,

};



ESP_LOGI(TAG, "Install RM69330 panel driver");

ESP_ERROR_CHECK(esp_lcd_new_panel_rm69330(io_handle, &panel_config, &panel_handle));



ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));

ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));



ESP_ERROR_CHECK(esp_lcd_panel_invert_color(panel_handle, false));

ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel_handle, true, true));

ESP_ERROR_CHECK(esp_lcd_panel_set_gap(panel_handle, 14, 0));

// user can flush pre-defined pattern to the screen before we turn on the screen or backlight

ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));

其中:

  • SPI_BUS_MAX_TRANSFER_SZ : 我直接設定為最大 (1<<18)
  • SPI_TRANSACTION_POOL_SIZE : 50
IRAM_ATTR static bool notify_refresh_ready(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx)

{

    lv_disp_drv_t *disp_driver = (lv_disp_drv_t *)user_ctx;

    lv_disp_flush_ready(disp_driver);

    return false;

}
  • LVGL初始化步驟省略
    flush_cb:
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;

    // copy a buffer's content to a specific area of the display

    esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, color_map);

}

相關文章