WiFi模組樂鑫信息科技代理商ESP32程序的內存模型,MCU中的內存資源可能是其寶貴的資源,因為它在芯片中占據大的面積。更新的應用程序對內存的需求正在不斷增長。為了充分利用硬件資源,理解內存架構并能針對應用程序的實際用例進行內存優化變得至關重要。特別是對于包含通信子系統(Wi-Fi和BT/BLE)的ESP32SoC架構,通信子系統本身需要占用一定數量的內存才能運行,因此有必要明確應用程序的需求并對其進行內存優化。
WiFi模組樂鑫信息科技代理商經常會遇到有關應用程序可用內存余量的問題;除非我們深入了解用例,否則這個問題沒有簡單的答案。但是,當開發人員了解有關內存布局,系統要求和常見優化方法的詳細信息時,就會發現ESP32可以適應各種有趣的應用程序用例。
本文旨在為開發者提供ESP32SoC的內存布局概述,介紹不同的內存區域及其特性,并討論典型ESP32固件的內存分配。
SRAM分為3個存儲塊SRAM0、SRAM1和SRAM2(以及RTC快速和慢速存儲器2個小塊,我們將在后面分別討論)。SRAM以兩種方式使用:一種用于指令存儲,稱為IRAM(用于執行代碼,text段),另一種用于數據存儲,稱為DRAM(用作BSS段,Data段和堆)。SRAM0和SRAM1可以用作連續的IRAM,而SRAM1和SRAM2可以用作連續的DRAM地址空間。
雖然SRAM1可以同時用作IRAM和DRAM,但實際上ESP-IDF會默認使用SRAM1作為DRAM,這是因為通常在應用程序中數據空間會比較緊缺。上圖的淺藍色圖表顯示了程序員在開發應用程序時需要考慮的內存映射,可以利用的內存包括192KB的IRAM和328KB的DRAM(譯者注:不是所有的空間都能被用戶程序使用)。因為沒有重疊部分,所以對應用程序來說沒有太大影響,WiFi模組樂鑫信息科技代理商提醒各位需要注意的是IRAM和DRAM地址空間,地址范圍的方向是相反的。
現在讓我們放大 IRAM 分段。ESP32中192KB的可用IRAM用于代碼執行,并且其中一部分作為高速緩存(Cache)用于訪問Flash(和PSRAM)。前32KBIRAM用作CPU0的高速緩存,接下來的32KB用作CPU1高速緩存。這是在硬件中靜態配置的,無法更改。在一個64KB之后,鏈接腳本開始將text段放置在IRAM中。它首先放置所有中斷向量,然后放置已編譯應用程序中所有標記為放置在IRAM中的text段。在通常情況下,大多數應用程序代碼從flash(XiP)執行,但某些代碼對執行時間有較高要求,或者本身需要操作flash,需要將它們放置在IRAM中。這項操作通過對這些函數或代碼文件添加特定屬性標識實現,鏈接程序腳本將據屬性標識將它們放置在IRAM中。鏈接腳本將 _iram_text_start 和 _iram_text_end 符號放置在text段的兩個邊界處。text段之后的IRAM保持未使用狀態,并添加到堆中。鏈接腳本將 _iram_text_start 和 _iram_text_end 符號放置在text段的兩個邊界處。text段之后的IRAM保持未使用狀態,并被添加到堆中。并且,當應用程序配置為單核模式時,CPU1不工作并且不啟用CPU1Cache。在這種情況下,CPU1Cache的空間(0x40078000–0x4007FFFF)將被添加到堆中。放置在堆中的未使用的IRAM可以通過動態分配訪問。如果應用程序有此要求,它可用于在IRAM中放置任何代碼。但是,這種情況很少見。
IRAM也可以用于放置數據,但有兩個重要限制條件:
用于訪問IRAM中數據的地址必須是32位對齊的;
訪問的數據大小也必須是32位對齊的。
如果應用程序具有可以遵循這兩個訪問規則的數據,則IRAM空間可用于存儲該數據。
還有一種方法可以不受此限制的訪問 IRAM 空間。但是作為訪問速度會變慢。這將在后面的部分中討論。
WiFi模組樂鑫信息科技代理商ESP32應用程序的典型(簡化)DRAM布局。由于DRAM地址從SRAM2的末尾開始,并向后增加,因此鏈接階段段空間的分配從SRAM2的末尾開始。
前8KB(0x3FFA_E000–0x3FFA_FFFF)用作某些ROM內置函數的數據空間;
鏈接器緊接著將已初始化的數據段放在一個8KB存儲器之后;
接下來是未初始化的BSS段;
數據段和BSS段之后剩余的內存被配置為堆,典型的動態內存分配一般分配至該位置。
請注意,數據段和BSS段的大小取決于應用程序。因此,每個應用程序根據其使用的組件和所調用的API都有不同的可用堆大小。
堆代碼中有兩個區域(0x3FFE_0000–0x3FFE_0440-共1088字節)和(0x3FFE_3F20–0x3FFE_4350-共1072字節)供ROM代碼存放數據。這些區域被標記為保留,并且堆分配器不會從這些區域分配內存。
啟用藍牙(BT)功能后,BT控制器(軟件和硬件)需要使用專用的數據空間。該空間作為控制器的Data\/BSS段,同時作為傳輸空間用于BT數據包在軟件和硬件之間傳輸。因此,鏈接腳本在默認的DRAM空間中保留了0x3FFB_0000–0x3FFB_DB5C之間的54KB空間,在該區域之后才進行應用程序的數據段和BSS段分配。
當應用程序僅使用低功耗藍牙(BLE)功能時,可以將BT控制器內存的一部分交還給堆。釋放并添加到堆中的內存大小約為19KB。
應用程序級的跟蹤調試(Trace)啟用以后,它將在DRAM的末尾保留一個固定為32KB的內存空間。請注意,上圖顯示了未啟用BT時的內存布局。但是應用程序也可以在啟用BT的情況下使用跟蹤,在這種情況下,鏈接腳本中也會保留BT控制器的內存空間。
WiFi模組樂鑫信息科技代理商ESP32提供了在QSPI總線上外接偽靜態RAM(PSRAM又名SPIRAM)的能力,該總線同時用于訪問flash,二者同時工作時利用片選信號進行切換。該存儲器同flash一樣可直接尋址,訪問過程通過IRAM中的Cache進行。ESP32在其地址空間0x3F80_0000至0x3FBF_FFFF多可映射4MBSPIRAM(譯者注:新版本IDF可使用 HimemAPI 訪問大為8MB的SPIRAM)。應用程序通過三種方式使用SPIRAM:
.使用SPIRAM保存特定軟件模塊的BSS段;
.使用堆分配器從SPIRAM動態分配內存;
.通過直接內存映射,在應用程序中使用靜態地址訪問SPIRAM。
雖然這允許應用程序使用額外的內存,但對SPIRAM的使用有以下限制:
.SPIRAM不支持DMA,在需要使用DMA向/從外設傳輸數據的情況下,不能使用它;
.由于flash和SPIRAM使用同一QSPI總線與ESP32通信,因此在執行禁用XiP模式的代碼中不能使用SPIRAM;
.由于SPIRAM訪問比內部SRAM慢,因此建議對性能有要求的代碼使用內部SRAM保存數據。
此處詳細介紹了使用SPIRAM的這些方式以及使用限制。
IRAM和DRAM內存布局可以看到,DRAM區域 _bss_end 到 0x3FFF_FFFF(或 _heap_end 在跟蹤調試啟用時)和IRAM區 _iram_text_end 到 0x4009_FFFF 是未使用的內存空間。如果系統中有SPIRAM,則該內存也屬于未使用的內存空間。應用程序和SDK組件始終需要按需分配和釋放內存。因此,通用內存分配器(也稱為堆分配器)用于操作可用內存空間,并為其提供內存分配和釋放API。如您所見,堆分配器控制下的內存區域具有不同的功能和訪問屬性。因此,ESP-IDF實現了一個基于功能的堆分配器,調用者可以在指定分配大小時同時指定用途。例如,應用程序可能指定分配具有DMA功能的內存空間,以便與某些外設一起使用,或者它可以指定從外部SPIRAM為音頻緩沖區分配內存,因為從內部DRAM分配不是更好的選擇。ESP-IDF還在基于功能的堆分配器的API之封裝了通用的malloc和freeAPI,以使應用程序易于從POSIX類型的系統移植。應用程序配置項可以包含一組管理規則,使mallocAPI能夠根據分配的大小自動選擇實際的內存段位置。
使用IRAM保存數據,從ESP-IDF4.2版本開始,我們增加了使用IRAM進行數據存儲的功能。如上所述,IRAM具有地址和大小對齊的訪問限制。如果進行未對齊訪問,則會導致異常。在4.2版之后,ESP-IDF透明地處理這些異常,以提供調用者所需的load/store功能。由于這些未對齊的訪問會導致異常,因此訪問速度將比DRAM慢。通常,每個異常處理大約需要167個CPU周期(即240MHz時每次訪問0.7usc或160MHz時每次訪問1usec)。應用程序或SDK組件可以在鏈接時將IRAM用于BSS數據,或者在運行時通過堆分配器使用IRAM。使用IRAM進行數據有兩個限制:
.IRAM訪問不是多核安全的。因此,需要在單核運行模式,或在系統和應用程序已知對IRAM的訪問來自同一個內核時使用它(例如,將任務固定到一個內核上);
.用于DMA的內存分配不應從IRAM分配。
ESP-IDF4.2提供了一些現成的配置,可以有效地利用未使用的IRAM進行數據操作,例如以單核模式下發送和接收TLS片段。