動7寸屏完整指南)
先說結(jié)論STM32F103裸機跑LVGL 8.2、帶一塊7寸800x480的屏幕這事能成而且沒有想象中那么恐怖。網(wǎng)上搜F103LVGL十個帖子有八個在勸退理由不外乎內(nèi)存不夠、沒有FPU、刷新跟不上。這些理由在F407上成立放到F103上要分情況看——LVGL從v7到v8一直在為低資源設備做優(yōu)化分塊渲染加臟矩形刷新機制讓全幀緩沖不再是必需品。下面這套流程是我這次實際移植時走通的完整路線包括源碼裁剪、lv_conf.h配置、顯示和觸摸回調(diào)對接還有移植過程中踩過的幾個坑。適合手上正好有F103和一塊7寸屏、想徹底換掉老式控件UI的人參考也適合被舊教程的v7/v8 API差異搞到頭疼的初學者。1. 移植前的資源賬72MHz主頻和64KB SRAM夠不夠1.1 內(nèi)存賬為什么全幀緩沖直接出局但LVGL依然能跑7寸屏分辨率通常是800x480RGB565一個像素占2字節(jié)一幀全畫面需要768000字節(jié)約750KB。STM32F103ZET6的SRAM只有64KBC8T6只有20KB。凡是上來就在代碼里定義一個uint16_t framebuffer[800 * 480]的編譯能過運行必掛。這是很多人在F103上移植失敗的第一道墻不是LVGL不行是方案選錯了。LVGL解決這個問題的思路是分塊渲染。它內(nèi)部維護一個draw buffer大小遠小于全幀緩沖需要刷新時LVGL把整個需要重繪的區(qū)域切成一堆小塊一塊一塊地完成像素計算再通過flush_cb把這塊像素交給LCD。對一塊800寬的屏來說如果給draw buffer分配16KB大約能存800x10行像素也就是一次只畫10行。渲染完這10行就馬上丟給屏幕控制器接著畫下一批10行。屏幕控制器內(nèi)部自帶GRAM的型號比如RA8875、SSD1963這類驅(qū)動IC帶數(shù)百KB顯存MCU其實只負責把小塊數(shù)據(jù)傳過去真正的一幀畫面存在屏端。這也解釋了為什么F103這種小內(nèi)存MCU跑大屏UI理論上是可行的。內(nèi)存具體怎么分以ZET6的64KB SRAM為例兩個draw buffer各16KB加起來32KB丟給刷新用LVGL對象內(nèi)存池LV_MEM_SIZE開24KB用來存放控件、樣式、事件等數(shù)據(jù)結(jié)構(gòu)剩下8KB左右留給中斷、局部變量和棧。如果屏幕是SPI接口且沒有足夠吞吐率可以退化成單draw buffer省16KB。這個預算很緊但做幾個頁面加若干控件夠用。1.2 刷新賬并口和SPI屏的差距不是一點半點7寸屏模塊的接口五花八門但對F103來說接口基本決定了UI能做到多順滑。16位并口8080時序通過FSMC外設把LCD映射成一塊外部SRAM寫一個像素就是一次普通總線寫。72MHz下FSMC總線帶寬遠大于UI刷新需求只要規(guī)劃好LCD窗口一屏畫面理論寫入時間在二三十毫秒量級跑LVGL的過渡動畫可以接受。8位并口寫入一個像素需要兩次總線寫速度下降一半用是能用畫面略慢。SPI接口SPI1最高18Mbit/s換算約2.25MB/s傳完整屏768KB需要340ms以上。也就是說刷新一整個畫面要接近0.35秒拖動畫、滑菜單這類操作基本沒法看。SPI屏更適合做靜態(tài)界面或者在屏廠驅(qū)動IC自帶局部刷新指令時針對小塊區(qū)域更新。所以要玩LVGLF1037寸屏我的建議很直接手上是并口屏就用起來SPI屏盡量換塊屏再折騰。網(wǎng)傳“F103帶不動7寸屏”的說法很多是用SPI慢屏試出來的錯覺換成FSMC并口后體驗完全不同。1.3 芯片型號ZET6、RCT6和C8T6的差別移植到一半才會暴露資源賬算完具體芯片選型也有講究。F103系列SRAM容量差異很大STM32F103ZET664KB SRAM、512KB Flash做這個方案最合適。STM32F103RCT648KB SRAM、256KB Flash湊合能用draw buffer壓到每塊12KBLV_MEM_SIZE給16KB也能轉(zhuǎn)起來。STM32F103C8T620KB SRAM、64KB Flash不推薦。draw buffer和LVGL內(nèi)存池根本分不過來加上LVGL 8.2編譯出來基礎體積就有小幾十KBFlash也很緊張。這幾個型號的工程代碼基本通用差別主要在啟動文件的堆棧大小和linker腳本的內(nèi)存范圍。如果手上只有C8T6我的建議是降低分辨率換4.3寸屏或2.4寸屏UI一樣能玩別硬上7寸。2. LVGL 8.2源碼整理與lv_conf.h配置后面能不能跑起來全看這里2.1 源碼目錄精簡三個該拿掉的文件夾和其他注意事項下載LVGL 8.2源碼后解壓出來會看到demos、examples、src幾個主要目錄。裸機移植時編譯對象只需要srcdemos和examples里的東西統(tǒng)統(tǒng)拿掉它們主要是給你參考和演示用的加進來會拖慢編譯并且白白消耗Flash。很多CubeMX工程模板默認會把整個lvgl文件夾全編譯等燒錄后才發(fā)現(xiàn)Flash不夠排查半天最后發(fā)現(xiàn)是demo占了三分之一。src目錄內(nèi)部不建議按文件夾手動刪文件因為LVGL各模塊之間依賴比較復雜刪錯一個文件編譯報錯會讓你懷疑人生。正確做法是保留整個src然后通過lv_conf.h里的開關把用不到的組件、主題、字體關掉。例如不做圖表就不開LV_USE_CHART不用下拉框就關LV_USE_DROPDOWN每關一個組件都能省下對應的Flash和內(nèi)存占用。還有一點LVGL 8.2要求工程能編譯那些帶lv_前綴的一堆源文件。用Keil時建議直接把src下所有.c文件加入工程組文件數(shù)量很多但值得編譯時間也就幾十秒。官方提供的lvgl.mk是給Makefile工程用的也能自動收集文件如果用Makefile不必手動羅列。2.2 lv_conf.h里必改的宏顏色深度、內(nèi)存池、緩沖區(qū)掛鉤把lvgl根目錄下的lv_conf_template.h復制出來改名為lv_conf.h并確保它能被所有源文件包含。這個文件是整個移植最關鍵的一環(huán)幾個宏直接決定系統(tǒng)能不能跑#define LV_COLOR_DEPTH 16 #define LV_COLOR_16_SWAP 1 /* 后續(xù)根據(jù)屏幕實測再調(diào) */ #define LV_MEM_CUSTOM 0 /* 使用LVGL內(nèi)部內(nèi)存分配器 */ #define LV_MEM_SIZE (24 * 1024) #define LV_TICK_CUSTOM 0 #define LV_DISP_DEF_REFR_PERIOD 30 #define LV_FONT_MONTSERRAT_14 1 #define LV_FONT_MONTSERRAT_20 1LV_COLOR_DEPTH必須跟LCD面板實際格式一致絕大多數(shù)7寸屏是RGB565也就是16位色。如果板子配的是RGB888的屏修改成24后draw buffer占用會暴漲50%內(nèi)存預算要重新算。LV_COLOR_16_SWAP是個很容易踩的坑。它是用來調(diào)整像素字節(jié)序的LVGL在內(nèi)存中按小端方式存放16位色但不同LCD控制器對RGB兩個字節(jié)的接收順序有差異。現(xiàn)象就是界面“顏色偏藍”或“偏紫”把這項在0和1之間切換有時候就能解決。LV_MEM_SIZE直接決定能創(chuàng)建多少控件。24KB聽起來不多但LVGL內(nèi)部是按對象拆分的一個普通按鈕幾十字節(jié)一頁十幾二十個控件完全能放下。如果創(chuàng)建控件后界面沒反應、復位循環(huán)先懷疑這個值太小。2.3 別急著用malloc裸機環(huán)境下內(nèi)存分配有更穩(wěn)的選擇LV_MEM_CUSTOM這個宏是很多人會忽略的。它設為1時LVGL會調(diào)用malloc/free設為0時LVGL使用內(nèi)置的lv_mem_alloc/lv_mem_free內(nèi)存池就是2.2里那個LV_MEM_SIZE定義的靜態(tài)數(shù)組。裸機上直接用標準malloc我踩過坑。Keil的MicroLIB或者默認堆分配器在長時間運行后容易產(chǎn)生碎片而且標準malloc的堆大小由啟動文件里的Heap_Size決定跟linker腳本又耦合排查起來很麻煩。LVGL內(nèi)置分配器是為嵌入式場景設計的內(nèi)部有塊合并機制更適合裸機。如果確實想用自己的分配邏輯比如外部PSRAM才把LV_MEM_CUSTOM設為1并讓LV_MEM_CUSTOM_INCLUDE包含對應的頭文件。F103沒有外部內(nèi)存控制器老老實實用內(nèi)置分配器最省心。主循環(huán)里調(diào)試時還可以用lv_mem_monitor函數(shù)看內(nèi)存占用判斷控件創(chuàng)建多了還是泄漏了后面避坑部分會再提。3. flush_cb顯示回調(diào)像素如何從LVGL畫布跑到LCD上3.1 FSMC并口屏把7寸屏映射成一塊外部SRAM16位并口8080屏接到F103ZET6最標準的方式是用FSMC外設。FSMC本是用來擴展NOR Flash和SRAM的但LCD控制器本質(zhì)上也是“讀寄存器/寫數(shù)據(jù)”的并行設備于是可以把LCD當成一塊外部SRAM掛在Bank1上。我們只要對某個內(nèi)存地址寫一個值FSMC就會自動產(chǎn)生時序把數(shù)據(jù)送到LCD數(shù)據(jù)總線。連線思路是NE1負責片選NOE接RD引腳NWE接WR引腳地址線A16接LCD寄存器選擇RS16根數(shù)據(jù)線D0-D15接LCD的DB0-DB15。FSMC對應的GPIO要設置為50MHz復用推挽輸出同時打開FSMC外設時鐘GPIO_InitStructure.GPIO_Pin GPIO_Pin_0 | GPIO_Pin_1 | ... | GPIO_Pin_15; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; GPIO_Init(GPIOD, GPIO_InitStructure);關鍵在CMD和DATA的地址區(qū)分。LCD控制器通過RS引腳高低來區(qū)分當前是寫命令還是寫數(shù)據(jù)。RS接到FSMC的A16在16位數(shù)據(jù)模式下對應地址偏移是0x20000。源碼里可以這樣定義#define LCD_BASE ((uint32_t)0x60000000) #define LCD_REG (*(volatile uint16_t *)(LCD_BASE)) #define LCD_RAM (*(volatile uint16_t *)(LCD_BASE | 0x00020000))先給LCD_REG寫命令再給LCD_RAM寫數(shù)據(jù)。很多例程會把第二個地址寫成0x60010000這是把A16偏移算錯了結(jié)果就是LCD控制器收到的命令一塌糊涂屏幕初始化失敗白屏。如果RS接的是A18偏移就是0x80000務必對著自己的原理圖算偏移別照抄。FSMC時序初始化時地址建立時間給1個HCLK、數(shù)據(jù)建立時間給2個HCLK通常就能穩(wěn)定驅(qū)動SSD1963這類控制器FSMC_NORSRAMInitStructure.FSMC_AddressSetupTime 1; FSMC_NORSRAMInitStructure.FSMC_DataSetupTime 2;如果屏幕出現(xiàn)閃爍或偶爾花屏把DataSetupTime加到3往往就好了。這也是個經(jīng)驗值具體參照屏幕控制器datasheet的讀寫周期要求調(diào)整。3.2 flush_cb完整寫法設置窗口再連續(xù)寫像素LVGL要刷新一塊區(qū)域時會調(diào)用注冊的flush_cb給一個area區(qū)域左上右下坐標和一個color_p像素指針。我們收到這套數(shù)據(jù)后要先告訴LCD控制器一個窗口范圍然后連續(xù)寫入像素。static void lcd_fill_area(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, const uint16_t *pixels) { LCD_REG 0x2A; /* 列地址設置 */ LCD_RAM x1 8; LCD_RAM x1 0xFF; LCD_RAM x2 8; LCD_RAM x2 0xFF; LCD_REG 0x2B; /* 行地址設置 */ LCD_RAM y1 8; LCD_RAM y1 0xFF; LCD_RAM y2 8; LCD_RAM y2 0xFF; LCD_REG 0x2C; /* 存儲器寫 */ uint32_t len (uint32_t)(x2 - x1 1) * (y2 - y1 1); for (uint32_t i 0; i len; i) { LCD_RAM pixels[i]; } }注意一定要先設置窗口再連續(xù)寫數(shù)據(jù)別按整個屏幕的線性地址去推算像素位置。不同LCD控制器具體命令號有差異RA8875的窗口設置命令和SSD1963不一樣但思路相同。flush回調(diào)本身不復雜static void disp_flush_cb(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p) { lcd_fill_area(area-x1, area-y1, area-x2, area-y2, (uint16_t *)color_p); lv_disp_flush_ready(disp_drv); }FSMC循環(huán)寫是同步操作數(shù)據(jù)寫完后就能通知LVGL緩沖區(qū)可以復用了。這里有一個很多教程沒講透的細節(jié)在flush_cb里調(diào)lv_disp_flush_ready的位置本質(zhì)上表示“這塊區(qū)域的數(shù)據(jù)我已經(jīng)拿走了”。FSMC寫法簡單直接寫完立刻調(diào)用沒問題DMA后臺傳輸則不行必須等傳輸完成中斷里再調(diào)用不然下一幀的像素可能覆蓋當前正在傳輸?shù)木彌_區(qū)畫面會出現(xiàn)撕裂。3.3 SPI屏的DMA方案與“等傳輸完成再發(fā)ready”問題如果手里的7寸屏是SPI接口建議先權衡刷新速度非要移植的話DMA是必須的否則每像素都走CPU等待收發(fā)刷新直接沒法看。SPI屏的flush思路是先向LCD控制器發(fā)送窗口設置命令再啟動DMA把color_p里的像素數(shù)據(jù)轉(zhuǎn)成SPI輸出。關鍵點是lv_disp_flush_ready不能在啟動DMA后立刻調(diào)用要在DMA傳輸完成中斷里調(diào)用void DMA1_Channel3_IRQHandler(void) { if (DMA_GetITStatus(DMA1_IT_TC3)) { DMA_ClearITPendingBit(DMA1_IT_TC3); lv_disp_flush_ready(disp_drv); } }這里還有一個對齊問題。STM32F103的DMA對源地址有對齊要求color_p是LVGL從draw buffer里切出來的地址是隨機偏移可能不滿足4字節(jié)或2字節(jié)對齊。實測中不放心的話可以在自己定義的flush函數(shù)里先把像素拷貝到一個靜態(tài)對齊數(shù)組里再啟動DMA。注意數(shù)組要帶對齊屬性static uint16_t dma_buf[800 * 10] __attribute__((aligned(4)));不過拷貝也費時間若能確保draw buffer起始地址和每次切塊的偏移都對齊就能省掉這步。剛上手時我建議先加拷貝穩(wěn)定性比重那一點速度重要。4. SysTick心跳與XPT2046觸摸讓UI活過來的兩個底層驅(qū)動4.1 心跳時基SysTick被HAL庫占用后怎么辦LVGL所有動畫、定時器、控件狀態(tài)刷新都依賴一個毫秒級時基裸機上就是把lv_tick_inc(1)按固定周期喂給它。最簡單方案是SysTick 1ms中斷但如果你用CubeMX的HAL庫生成工程SysTick已經(jīng)被HAL庫用來做HAL_GetTick的時基此時直接覆蓋中斷函數(shù)會引發(fā)HAL_Delay死循環(huán)。兩個處理辦法。第一在SysTick_Handler里同時調(diào)用HAL_IncTick()和lv_tick_inc(1)void SysTick_Handler(void) { HAL_IncTick(); lv_tick_inc(1); }這個辦法代碼少但SysTick里干了兩件事以后想改時基會牽一發(fā)動全身。第二用TIM2做1ms定時中斷單獨把時基交給LVGLvoid TIM2_IRQHandler(void) { if (TIM_GetITStatus(TIM2, TIM_IT_Update)) { TIM_ClearITPendingBit(TIM2, TIM_IT_Update); lv_tick_inc(1); } }我推薦第二種。TIM2和HAL互不干擾排查問題的時候邏輯清晰。lv_conf.h里LV_TICK_CUSTOM保持0LVGL就會用lv_tick_inc這個接口。主循環(huán)結(jié)構(gòu)也需要注意while (1) { lv_timer_handler(); delay_ms(5); }lv_timer_handler的調(diào)用間隔決定了LVGL的刷新速率不能讓它被其他耗時任務阻塞太久。如果主循環(huán)里還有別的業(yè)務邏輯盡量保證一次循環(huán)的耗時在10ms以內(nèi)。4.2 XPT2046讀取代碼從SPI時序到觸摸點坐標7寸電阻觸摸屏最常見的觸摸控制器是XPT2046它用SPI接口輸出12位坐標數(shù)據(jù)。讀取流程是拉低CS發(fā)送一個控制字節(jié)然后把SPI時鐘繼續(xù)打兩輪從返回數(shù)據(jù)中拼出坐標。控制字節(jié)里0xD0表示讀X坐標0x90表示讀Y坐標。一個可用的讀取函數(shù)static uint16_t tp_read_channel(uint8_t cmd) { uint16_t value 0; TP_CS_LOW(); spi_read_write(cmd); uint8_t b0 spi_read_write(0x00); uint8_t b1 spi_read_write(0x00); TP_CS_HIGH(); value ((uint16_t)b0 8 | b1) 3; return value; }右移3位是把16位拼接結(jié)果里的多余低位丟掉保留12位有效數(shù)據(jù)。SPI頻率建議控制在1MHz左右XPT2046對時序要求不高但線長干擾多時降速更穩(wěn)。裸機上讀取觸摸可以放在LVGL的indev回調(diào)里被動讀取也可以用定時器主動掃描后保存全局變量。LVGL的indev回調(diào)本身就是周期調(diào)用直接在回調(diào)里讀就行。電阻屏有個物理特性按下瞬間的采樣值不穩(wěn)定建議連續(xù)讀三到五次取中間值或者做平均不然會出現(xiàn)點擊跳點。4.3 坐標映射與旋轉(zhuǎn)觸摸錯位的三個高頻原因觸摸回調(diào)用來喂給LVGL的是屏幕邏輯坐標而屏幕上應當是控件所在的像素坐標。XPT2046輸出的是0-4095范圍內(nèi)的12位原始值背后是觸摸面板的物理坐標系跟屏幕像素坐標系可能有鏡像、翻轉(zhuǎn)、縮放三種關系。最簡單的一種映射是線性縮放data-point.x (uint16_t)((uint32_t)raw_x * 800 / 4096);>x 800 - x; /* 水平鏡像 */ y 480 - y; /* 垂直鏡像 */第二個是xy互換。有些7寸屏觸摸面板的X方向?qū)狶CD的Y方向需要交換x和y再做縮放。第三個是LVGL的顯示旋轉(zhuǎn)和觸摸旋轉(zhuǎn)沒有同步。LVGL 8.2的disp_drv結(jié)構(gòu)體里有rotated字段旋轉(zhuǎn)屏幕后觸摸回調(diào)收到的坐標系仍然是原始物理坐標如果只旋轉(zhuǎn)顯示不旋轉(zhuǎn)觸摸點擊必然錯位。我踩坑后的做法是盡量不依賴LVGL的rotated字段而是在自己的觸摸映射函數(shù)里統(tǒng)一完成旋轉(zhuǎn)和鏡像這樣邏輯最簡單出錯也容易排查。5. 實測避坑記錄從白屏到觸摸偏位的完整排查過程5.1 白屏不是LVGL沒跑是FSMC寫操作壓根沒進LCD白屏是7寸屏移植時遇到最多的現(xiàn)象大部分人第一反應是LVGL初始化失敗其實九成是LCD通路本身沒打通。我的排查順序是這樣的先在main函數(shù)里、任何LVGL代碼之前單獨跑一段LCD驅(qū)動測試——直接向LCD_REG寫0x2C命令然后連續(xù)寫1000個0xF800紅色和0x07E0綠色。如果屏幕有紅綠交替顯示說明FSMC映射、LCD控制器初始化、GPIO配置都正確問題在LVGL側(cè)如果屏一直白著問題在FSMC或LCD驅(qū)動跟LVGL無關。白屏時重點檢查這四處FSMC時鐘是否開啟GPIO是否配置為AF_PPCMD/DATA地址偏移是否按RS所接地址線正確計算LCD控制器初始化時序是否夠?qū)捤捎绕涫荄ataSetupTime太小有沒有把LCD的復位腳拉高并延時足夠長有些屏需要50ms以上。按這個順序排查基本能定位到根因。5.2 顏色發(fā)藍或偏紅RGB與BGR的字節(jié)序問題UI跑起來了但顏色整體不對比如紅色按鈕變成藍色、膚色發(fā)紫。這個現(xiàn)象百分之八十是RGB565字節(jié)序不匹配。LVGL內(nèi)部畫像素時用的是16位整數(shù)值內(nèi)存里低字節(jié)和高字節(jié)的排列順序是固定的但LCD控制器端的串轉(zhuǎn)并邏輯可能期望高字節(jié)在前或低字節(jié)在前。這時去lv_conf.h里切換LV_COLOR_16_SWAP的值0改1或1改0問題通常立刻消失。如果切換后顏色還是偏再去看LCD控制器的RGB順序寄存器。RA8875和SSD1963都有類似“RGB/BGR”的模式位例如設置0x36寄存器可以讓內(nèi)存中的RGB順序最終映射到屏幕像素。我當時同時動了lv_conf.h和LCD寄存器才把顏色調(diào)正而且兩個地方的效果是疊加的所以調(diào)試時要一次只改一個變量別兩個一起改。另外要注意draw buffer里的顏色位深必須與LV_COLOR_DEPTH一致。如果源工程是8位屏改過來的LV_COLOR_DEPTH還是8會出現(xiàn)顏色慘不忍睹的塊狀漸變。直接確認這個宏在16就行。5.3 運行幾分鐘后HardFault內(nèi)存碎片與棧溢出界面能顯示但運行一段時間后突然卡死進HardFault中斷這是裸機移植的經(jīng)典難題。原因通常是以下三個之一棧溢出。LVGL繪制過程中會嵌套調(diào)用大量函數(shù)尤其帶樣式、帶圓弧的控件棧使用量比想象中大。啟動文件里Stack_Size如果用默認的0x200或0x400很容易爆棧。我建議把Stack_Size改成0x1000也就是4KB。對于64KB RAM的ZET6來說這個開銷值得。內(nèi)存池耗盡。LV_MEM_SIZE設小了控件創(chuàng)建多了之后LVGL內(nèi)部分配失敗但上層代碼沒有正確判斷繼續(xù)操作空指針。解決方法是打開lv_conf.h里的LV_USE_MEM_MONITOR在外部循環(huán)定期調(diào)用lv_mem_monitor輸出剩余內(nèi)存觀察是不是隨著操作單調(diào)遞減。如果數(shù)值在下降多半是某些控件的事件回調(diào)里反復創(chuàng)建對象但沒有刪除。DMA緩沖對齊問題。SPI DMA傳輸時如果源地址不滿足控制器要求DMA會卡住或者傳錯數(shù)據(jù)。最穩(wěn)妥是給DMA專用緩沖加aligned屬性或者先拷貝到對齊數(shù)組成員。HardFault問題難排查好解決之后要總結(jié)出規(guī)律每次添加新控件或新動畫后先把棧加大一檔、內(nèi)存池觀察一段時間再上線復雜業(yè)務邏輯。5.4 界面刷新慢優(yōu)化效果與參數(shù)實測7寸屏上LVGL的默認刷新率配置是30Hz理論上每33ms刷新一次臟區(qū)域。實際卡頓的優(yōu)化方向很清晰編譯器優(yōu)化。Keil下-O0和-O2在純渲染場景實測差距可能有1.5倍以上。LVGL這類需要密集像素計算和內(nèi)存操作的代碼不開優(yōu)化等于讓F103背著沙袋跑步。工程最終發(fā)布時務必開-O2。draw buffer尺寸。從一個16KB單緩沖改成兩個16KB雙緩沖撕裂明顯減少再把每個buffer從16KB提到24KB渲染整塊區(qū)域時批處理比例更高CPU反而更輕松。內(nèi)存如果實在緊張優(yōu)先保雙緩沖尺寸可以壓縮。減少透明效果和陰影。LVGL的默認主題帶圓角、陰影、透明度這些效果在F103上每幀要額外計算一遍alpha混合。想流暢就把LV_THEME_DEFAULT的shadow_width改為0border_width用默認但關掉陰影。下面是我在ZET6上測過的幾種配置效果配置實際感受單緩沖16KB-O0切頁有明顯閃爍滑動卡頓雙緩沖16KBx2-O0不閃了但拖動響應不夠跟手雙緩沖16KBx2-O2基本流暢動畫能看雙緩沖24KBx2-O2主觀跟手復雜頁面偶有掉幀F(xiàn)103畢竟是72MHz的老架構(gòu)想把7寸屏拖出F4那種絲滑感不現(xiàn)實但只要避開透明動畫、大面積全屏重繪這幾個高成本操作簡單列表、按鈕、儀表盤頁面完全穩(wěn)得住。我這次移植用的是SSD1963并口屏、XPT2046電阻觸摸最后定下來雙緩沖24KBx2、LV_MEM_SIZE 24KB、-O2優(yōu)化。7寸屏跑起來普通頁面切換和按鈕交互都沒問題唯一需要注意的是別在F103上做大量列表項的同時開陰影和漸變否則幀率肉眼可見地掉。這套參數(shù)在RCT6上我也試過把draw buffer壓到12KBx2之后依然能跑只是內(nèi)存更緊張。如果你也打算移植先在裸板上把LCD單通測試過了再談LVGL配置這條路走下來會順暢很多。