0 引言
在嵌入式系統(tǒng)設(shè)計(jì)中,需要根據(jù)系統(tǒng)的功能需求選擇相應(yīng)的單片機(jī)。筆者參與開(kāi)發(fā)的一款中央空調(diào)主控制板選用了意法半導(dǎo)體公司的 STM32F407 單片機(jī),這一系列的單片機(jī)具有高集成度、高性能、嵌入式存儲(chǔ)器和外設(shè),適合作為主控制板的核心單片機(jī)使用。STM32F407 主要特征如下:提供了工作頻率為 168 MHz 的 Cortex-M4 內(nèi)核(具有浮點(diǎn)單元)的性能,在168MHz 頻率下,從 Flash 存儲(chǔ)器執(zhí)行時(shí),STM32F407 能夠提供 210 DMIPS/566 CoreMark 性能,并且利用意法半導(dǎo)體的 ART 加速器實(shí)現(xiàn)了 Flash 零等待狀態(tài)。DSP 指令和浮點(diǎn)單元擴(kuò)大了產(chǎn)品的應(yīng)用范圍。
STM32F407產(chǎn)品系列具有 512 KB~1MB Flash 和 192 KBSRAM,采用尺寸小至 10 mm×10mm 的 100~ 176 引腳封裝。在開(kāi)發(fā)該控制板的軟件時(shí)發(fā)現(xiàn),由于 STM32F407 的 SRAM 地址不連續(xù),造成動(dòng)態(tài)內(nèi)存分配存在問(wèn)題,不能利用全部的片內(nèi) 192 KB SRAM 資源,有必要深入分析并解決。
1 EWARM 7.40C/C++編譯器的數(shù)據(jù)存儲(chǔ)
筆者在開(kāi)發(fā)該控制板的軟件時(shí),使用IAR公司的EWARM7.40作為 C/C++ 編譯器,該編譯器提供了靜態(tài)內(nèi)存分配與動(dòng)態(tài)內(nèi)存分配2種不同的內(nèi)存分配機(jī)制。
1.1 簡(jiǎn)介
ARM內(nèi)核可處理4GB 的連續(xù)內(nèi)存,范圍從0x00000000到0xFFFF FFFF。不同類型的物理內(nèi)存可以放置在上述內(nèi)存范圍中。典型的應(yīng)用程序同時(shí)具有只讀存儲(chǔ)器(ROM)和隨機(jī)存取內(nèi)存(RAM)。此外,內(nèi)存范圍的某些部分包含處理器控制寄存器和外圍單元。
在典型的應(yīng)用程序中,數(shù)據(jù)可以通過(guò)以下3種不同的方式存儲(chǔ)在內(nèi)存中:
(1)自動(dòng)變量
除已聲明為靜態(tài)變量者外,所有函數(shù)的局部變量都存儲(chǔ)在寄存器或堆棧上。這些變量在函數(shù)執(zhí)行時(shí)可以使用。當(dāng)函數(shù)返回到其調(diào)用者時(shí),內(nèi)存空間不再有效。
(2)全局變量、模塊靜態(tài)變量和聲明為 static的局部變量
在這種情況下,內(nèi)存的分配是一勞永逸的。在此語(yǔ)境中,“靜態(tài)”一詞表示應(yīng)用程序運(yùn)行時(shí)分配給此類變量的內(nèi)存數(shù)量不會(huì)改變。ARM 內(nèi)核有一個(gè)單一的地址空間且編譯器支持完整的內(nèi)存尋址。
(3)動(dòng)態(tài)分配的數(shù)據(jù)
應(yīng)用程序可以在堆上分配數(shù)據(jù),此數(shù)據(jù)一直有效,直到它被應(yīng)用程序顯式地釋放回系統(tǒng)。對(duì)于在應(yīng)用程序執(zhí)行之前不知道對(duì)象數(shù)量的場(chǎng)合,這種類型的內(nèi)存是有用的。注意:就內(nèi)存量有限的系統(tǒng)或預(yù)期運(yùn)行很久的系統(tǒng)而言,存在著與使用動(dòng)態(tài)分配的數(shù)據(jù)相關(guān)的潛在風(fēng)險(xiǎn)。
1.2 自動(dòng)變量和參數(shù)的存儲(chǔ)
按照 C 語(yǔ)言標(biāo)準(zhǔn),函數(shù)內(nèi)定義且未聲明為靜態(tài)的變 量被命名為自動(dòng)變量。其中一些變量被放置在處理器寄存器中,其余的放在堆棧上。從語(yǔ)義的角度來(lái)看,這是等價(jià)的。與放在堆棧上的變量相比,主要區(qū)別在于訪問(wèn)寄存器更快,并且需要的內(nèi)存更少。自動(dòng)變量只能在函數(shù)執(zhí)行時(shí)存活;當(dāng)函數(shù)返回時(shí),分配在堆棧上的內(nèi)存被釋放。
(1)堆棧
堆??梢园何创鎯?chǔ)在寄存器中的局部變量和參數(shù);表達(dá)式的臨時(shí)結(jié)果;函數(shù)的返回值(在寄存器中傳遞的除外);中斷期間的處理器狀態(tài);應(yīng)在函數(shù)返回前恢復(fù)的處理器寄存器(被調(diào)用者保存的寄存器)。
堆棧是一個(gè)固定的內(nèi)存塊,分為兩部分:第一部分包含為調(diào)用當(dāng)前函數(shù)的函數(shù),以及調(diào)用該函數(shù)的函數(shù)所使用而分配的內(nèi)存;第二部分包含可分配的自由內(nèi)存。這兩個(gè)區(qū)域之間的邊界線稱為棧頂,由一個(gè)專門的處理器寄存器——堆棧指針來(lái)表示。通過(guò)移動(dòng)堆棧指針,內(nèi)存被分配到堆棧上。
函數(shù)絕不應(yīng)指向包含自由內(nèi)存的堆棧區(qū)域。原因是,如果發(fā)生中斷,被調(diào)用的中斷函數(shù)會(huì)分配、修改,當(dāng)然還有在堆棧上去分配內(nèi)存。
(2)優(yōu)點(diǎn)
堆棧的主要優(yōu)點(diǎn)是:程序不同部分的函數(shù)可以使用相同的內(nèi)存空間存儲(chǔ)其數(shù)據(jù)。不同于堆,堆棧永遠(yuǎn)不會(huì)變成碎片或出現(xiàn)內(nèi)存泄漏。
函數(shù)可以直接或間接地調(diào)用自己(遞歸函數(shù)),每個(gè)調(diào)用可以在堆棧上存儲(chǔ)自己的數(shù)據(jù)。
(3)潛在的問(wèn)題
堆棧的工作方式使得臆想在函數(shù)返回后存儲(chǔ)數(shù)據(jù)變得不可能。以下函數(shù)演示了常見(jiàn)的編程錯(cuò)誤。它返回指向變量 x 的指針,該變量在函數(shù)返回后已不存在。
int * MyFunction(){
int x;
/*在此處理一些事情*/
return &.x; /* 不正確*/
}
另一個(gè)問(wèn)題是堆棧耗盡的風(fēng)險(xiǎn)。這個(gè)問(wèn)題在一個(gè)函數(shù)調(diào)用另一個(gè)、被調(diào)函數(shù)繼續(xù)調(diào)用第3個(gè)函數(shù)等,每個(gè)函數(shù)使用堆棧的總和大于堆棧的大小時(shí)會(huì)發(fā)生。當(dāng)大型數(shù)據(jù)對(duì)象存儲(chǔ)在堆棧上或使用遞歸函數(shù)時(shí),風(fēng)險(xiǎn)更高。
1.3 堆上的動(dòng)態(tài)內(nèi)存
分配在堆上的對(duì)象的內(nèi)存將一直存在,直到對(duì)象被顯式釋放。這種類型的內(nèi)存存儲(chǔ)對(duì)于直到運(yùn)行時(shí)才知道數(shù)據(jù)量的應(yīng)用程序是非常有用的。
在 C 語(yǔ)言中,使用標(biāo)準(zhǔn)庫(kù)函數(shù) malloc或相關(guān)函數(shù) calloc 和 realloc 中的一個(gè)來(lái)分配內(nèi)存,使用free 來(lái)釋放內(nèi)存。
在 C++ 語(yǔ)言中,一個(gè)特殊的關(guān)鍵字new 分配內(nèi)存和運(yùn)行構(gòu)造器。通過(guò) new 分配的內(nèi)存必須使用關(guān)鍵字 delete 來(lái)釋放。
設(shè)計(jì)使用堆分配對(duì)象的應(yīng)用程序時(shí)必須非常仔細(xì),因?yàn)楹苋菀壮霈F(xiàn)無(wú)法在堆上分配對(duì)象的情形。如果你的應(yīng)用程序使用過(guò)多的內(nèi)存,堆可能會(huì)耗盡。如果不再使用的內(nèi)存未被釋放,則堆也會(huì)用完。
對(duì)于每個(gè)分配的內(nèi)存塊,若干字節(jié)用于管理目的的數(shù)據(jù)是必需的。對(duì)于分配大量小塊的應(yīng)用程序,此管理開(kāi)銷可能很大。
還存在碎片化的問(wèn)題。這意味著在堆中,一小部分自由內(nèi)存被分配對(duì)象使用的內(nèi)存所分隔。如果沒(méi)有一塊足夠大的自由內(nèi)存給對(duì)象,即使自由內(nèi)存大小的總和超過(guò)對(duì)象的大小,還是無(wú)法分配一個(gè)新的對(duì)象。不幸的是,隨著內(nèi)存的分配和釋放,碎片化往往會(huì)增加?;诖耍O(shè)計(jì)長(zhǎng)時(shí)間運(yùn)行的應(yīng)用程序時(shí)應(yīng)盡量避免使用分配在堆上的內(nèi)存。
2 問(wèn)題分析與解決方案
以下介紹的程序?qū)嵗诰幾g器EWARM7.40、Fre-eRTOS 10.0.0 下驗(yàn)證通過(guò)。
2.1 STM32F407 的片內(nèi) SRAM
STM32F407 具有192 KB 的片內(nèi) SRAM 。片內(nèi) SRAM 可以字節(jié)、半字(16位)或全字(32位)的形式訪問(wèn)。讀取和寫(xiě)人操作以 CPU 速度執(zhí)行,等待狀態(tài)為0。片內(nèi) SRAM 最多分為兩個(gè)模塊:SRAM1 和 SRAM2 映射地址0x20000000,可以被所有 AHB 主設(shè)備存?。籆CM(核心耦合存儲(chǔ)器)映射到地址0x10000000, 只能由 CPU 通過(guò) D 總線存取。
STM32F407 的內(nèi)存映射如圖1所示,應(yīng)用程序可以使用的系統(tǒng)SRAM 地址為0x20000000~0x2001 FFFF(128KB),CCM地址為0x10000000~0x1000 FFFF(64 KB)。
由于兩塊內(nèi)存的地址不連續(xù),使用編譯器 EWARM 7.40時(shí),new 運(yùn)算符只能夠在一片連續(xù)的空間分配內(nèi)存,無(wú)法同時(shí)使用另外一片連續(xù)的空間。換言之,堆的實(shí)現(xiàn)只能在128 KB 的 SRAM 內(nèi)存空間內(nèi),另外1/3的片內(nèi) SRAM 被白白浪費(fèi)了,這在應(yīng)用程序較為復(fù)雜時(shí)是個(gè)嚴(yán)重的缺陷,必須設(shè)法解決。
圖1 STM32F407 的內(nèi)存映射
2.2 解決方案
由于編譯器 EWARM7.40 的局限性,堆無(wú)法在兩片不連續(xù)的內(nèi)存空間實(shí)現(xiàn)。為了解決此問(wèn)題,筆者聯(lián)想到了免費(fèi)的實(shí)時(shí)操作系統(tǒng) FreeRTOS, 該操作系統(tǒng)在2014年8月發(fā)布的 V8.1.0中提供了新的內(nèi)存管理文件 heap_5.c, 允許堆跨越多個(gè)不連續(xù)的內(nèi)存區(qū)域。后續(xù)版本對(duì)此功能做了優(yōu)化與改進(jìn)。筆者嘗試用此方案解決堆的實(shí)現(xiàn)問(wèn)題,取得了成功。具體方法如下:
①把FreeRTOS源程序包中的heap_5.c添加到軟件工程中。
②在頭文件中定義堆的大小。
#define configTOTAL_HEAP1_SIZE((size_t)(64*1024))
//HEAP164KB
#define configTOTAL_HEAP2_SIZE((size_t)(100*1024))
//HEAP2100KB
說(shuō)明:HEAP1 使用CCM 的全部 64KB;HEAP2 使用 SRAM 的100 KB, 剩余部分留給操作系統(tǒng)使用。此數(shù)值可根據(jù)應(yīng)用程序的需求靈活調(diào)整。
③在main.c中定義兩片內(nèi)存區(qū)域:
#pragmalocation=".ccmram"
uint8_tucHeapl[configTOTAL_HEAP1_SIZE];
uint8_tucHeap2[configTOTAL_HEAP2_SIZE];
constHeapRegion_txHeapRegions[]={
/*Startaddress with dummy offsets Size */
{ucHeapl,configTOTAL_HEAP1_SIZE},
{ucHeap2,configTOTAL_HEAP2_SIZE},
{NULL,0}
};
④ 在 main.c 中重載new 和delete:
void *operator new(size_t size){
void *p=0;
p=pvPortMalloc(size); //調(diào)用FreeRTOS 的內(nèi)存分配函數(shù)
return p;
void operator delete(void *p){
vPortFree(p); // 調(diào)用 FreeRTOS 的內(nèi)存釋放函數(shù)
經(jīng)過(guò)上述改進(jìn)后,應(yīng)用程序可以使用的堆的大小為 164KB, 徹底擺脫了編譯器 EWARM7.40 的局限性,滿足了復(fù)雜應(yīng)用程序的需求。
3 結(jié)語(yǔ)
本文詳細(xì)介紹了使用多塊不連續(xù)內(nèi)存空間實(shí)現(xiàn)堆的軟件方法,以及在 STM32F407 單片機(jī)上的軟件實(shí)現(xiàn)方法。使用該技術(shù)可以在多塊不連續(xù)內(nèi)存空間實(shí)現(xiàn)堆,更好 地實(shí)現(xiàn)了內(nèi)存的動(dòng)態(tài)分配。使用該軟件的控制器產(chǎn)品至今已在現(xiàn)場(chǎng)穩(wěn)定運(yùn)行18個(gè)月。
審核編輯:劉清
-
嵌入式系統(tǒng)
+關(guān)注
關(guān)注
41文章
3683瀏覽量
131397 -
加速器
+關(guān)注
關(guān)注
2文章
827瀏覽量
39121 -
Flash存儲(chǔ)器
+關(guān)注
關(guān)注
3文章
105瀏覽量
26432 -
STM32F407
+關(guān)注
關(guān)注
15文章
188瀏覽量
30611 -
靜態(tài)變量
+關(guān)注
關(guān)注
0文章
13瀏覽量
6792
原文標(biāo)題:使用多塊不連續(xù)空間實(shí)現(xiàn)堆的軟件方法
文章出處:【微信號(hào):麥克泰技術(shù),微信公眾號(hào):麥克泰技術(shù)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
介紹一下單片機(jī)和STM32F407芯片
STM32F407 UCOS III實(shí)驗(yàn)
如何實(shí)現(xiàn)STM32F407單片機(jī)的ADC轉(zhuǎn)換

STM32F407與STM32F105 CAN通訊失敗的定位解決

STM32F407芯片介紹

RM0090_STM32F405/415, STM32F407/417, STM32F427/437和STM32F429/439單片機(jī)參考手冊(cè)

評(píng)論