實驗證明,巨集定義 LV_MEM_CUSTOM 從 0 改為 1,對 LVGL+TFT_eSPI 編譯時不再提示 “section `.rodata' will not fit in region `dram0_0_seg'” 或“section `.bss' is not within region... ...
#NodeMCU# #PlatformIO#或#Arduino IDE# 能規避 lvgl+TFT_eSPI 經典編譯錯誤(如下所示)的點不多。
Linking .pio\build\nodemcu\firmware.elf ld.exe: address 0x3fffd538 of .pio\build\nodemcu\firmware.elf section `.bss' is not within region `dram0_0_seg' collect2.exe: error: ld returned 1 exit status *** [.pio\build\nodemcu\firmware.elf] Error 1因為我們在源碼上能做的事情不多: (1)在 lvgl 庫的 lv_conf.h 中將這個自定義記憶體分配標誌
/* 1: use custom malloc/free, 0: use the built-in `lv_mem_alloc` and `lv_mem_free` */
#define LV_MEM_CUSTOM 0
從0改為1。
(2)在 TFT_eSPI 庫的 User_Setup.h 里,選完 driver 之後,再選擇如下屏幕設置選項的其中之一
//#define ST7735_GREENTAB
//#define ST7735_GREENTAB2
//#define ST7735_GREENTAB3
#define ST7735_GREENTAB128 // For 128 x 128 display
(3)在 TFT_eSPI 庫的 User_Setup.h 里,關閉下麵的巨集定義,不使用SPIFFS:
// Comment out the #define below to stop the SPIFFS filing system and smooth font code being loaded
// this will save ~20kbytes of FLASH
#define SMOOTH_FONT
同樣,在與 driver 對應的 Setup7_ST7735_128x128.h 里,註釋掉下麵的巨集定義:
#define SMOOTH_FONT//註釋掉,避免spiffs-deprecation-warning
(4)在 platformio.ini 中增加一條編譯選項,表明開發板有 PSRAM 可用:
build_flags = -D BOARD_HAS_PSRAM
小結:
實驗證明,巨集定義 LV_MEM_CUSTOM 從 0 改為 1,對 LVGL+TFT_eSPI 編譯時不再提示
“section `.rodata' will not fit in region `dram0_0_seg'”
或
“section `.bss' is not within region `dram0_0_seg'”錯誤,有關鍵性幫助。這時 lvlg 將使用 stdlib.h 頭文件內的函數進行記憶體分配,從而可以充分使用到 SRAM 和 PSRAM 的記憶體。
這種錯誤說白了就是,編譯出來的數據量太大,DRAM 放不下了。我們知道,代碼被分為許多個section,常見的如:
.bss
.text
.rodata
.data
可以簡單理解為,IRAM 是用來存放指令的,而 DRAM 用來存放數據的。
如下圖所示, ESP32 內部存儲器(SRAM)有 3 個存儲塊 SRAM0、SRAM1 和SRAM2。
SRAM 以兩種方式使用:一種用於指令存儲,稱為 IRAM(用於執行代碼,text 段),另一種用於數據存儲,稱為 DRAM(用作 .bss 段,.data 段和堆)。SRAM0 和 SRAM1 可以用作連續的 IRAM,而 SRAM1 和 SRAM2 可以用作連續的 DRAM 地址空間。
圖1 ESP32 SRAM 佈局
編譯報錯的地址段“address 0x3fffd538”就落在上圖中的 DRAM 中。
我們再來看一下 DRAM 的記憶體佈局,如下圖所示。
圖2 DRAM 佈局
上圖顯示了應用程式的典型(簡化)DRAM 佈局。由於 DRAM 地址從 SRAM2 的末尾開始,並向後增加,因此鏈接階段空間的分配從 SRAM2 的末尾開始。
- 前 8KB(0x3FFA_E000–0x3FFA_FFFF)用作某些 ROM 內置函數的數據空間;
- 鏈接器緊接著將已初始化的數據段放在第一個 8KB 存儲器之後;
- 接下來是未初始化的 .bss 段;
- 數據段和 .bss 段之後剩餘的記憶體被配置為堆,典型的動態記憶體分配一般分配至該位置。