ARM Cortex-M底層技術(1)—程序在Flash和SRAM的空間分配


ARM Cortex-M底層技術(1)—程序在Flash和SRAM的空間分配

1. keil編譯介紹

  當使用keil進行單片機的開發時,運行一段程序后,在output輸出框會看到如下圖的結果。

圖1 keil 的output框

  其中,Compiler編譯器,使用的版本是 V5.06,程序會先經過編譯、后鏈接linking生成可執行的代碼,如果要下載單片機的Flash上,還需要轉換成二進制(bin)或者十六進制(hex)的文件。具體過程如下:

 

圖2 keil的編譯過程

  值得注意的是,經過編譯后,並不會給變量賦地址(.o文件),只有經過鏈接器鏈接后變量才有地址,鏈接的作用可以看做是便於管理而做的分類,在鏈接階段起作用的是分散加載文件,分散加載文件用來描述生成映像文件時所需的信息,即通過分散加載文件指定ARM鏈接器在鏈接階段如何分配Code、RO-data、RW-data、ZI-data地址,只用使用了分散加載文件后,你程序的變量、函數等數據才會有地址,只有如此做,程序在運行時,才能根據分配的地址去下一步執行程序,分散加載文件后面會詳細講解,這里只初步了解一下就可以。經鏈接后代碼分為Code、RO-data、RW-data、ZI-data四部分。接下來是老生常談的問題,每個區都是干嘛的呢?

 

  • CODE:代碼區,指程序中代碼即函數體的大小,注意程序中未使用的函數也會算在CODE中,也即會占用FLASH空間,因此不用的函數最好刪除掉,以免占用過多FLASH空間;
  • RO-DATA:RO就是只讀的意思,程序中只讀的變量(也就是帶Const的)和已初始化的字符串等;
  • RW-DATA:特指已初始化的可讀可寫全局/靜態變量;
  • ZI-DATA:未初始化的可讀可寫全局/靜態變量,注意初始化為0也算做未初始化,用到的堆空間和棧空間也會被算入這里面;

  之前我一直在想的一個問題是我的局部變量存放在哪里,其實是這樣的,局部變量只有在程序運行的過程中才會生成,當程序不運行,即將關閉單片機的電源后,是沒有局部變量的。所以這就要涉及到程序的兩種狀態存儲態和運行態。

圖3 程序的存儲態和運行態

 

存儲態:向Flash中下載程序時,其實僅僅下載的是CODE+RO-data+RW-data的內容,意思就是說,在掉電情況下,Flash里面的內存僅包含CODE+RO-data+RW-data這三塊。

運行態:當上電后,程序運行時,首先程序會從特定的地址進行啟動,下一節我會詳細分析啟動文件,啟動時會將RW-data的數據加載到SRAM中(啟用文件中有一段代碼是干這件事的,說的在具體點是分散加載文件會做這件事,在默認情況下,keil中的鏈接器armlink工具(D:\Keil_v526\ARM\ARMCC\bin\armlink.exe)已經幫你做完了這件事),單片機的 RO區域不需要加載到 SRAM,內核直接從 FLASH 讀取指令運行。那ZI-data的數據怎么辦呢?對於初始值為0全局變量來說,因為要在Code區要調用該全局變量,所以肯定要對其進行描述,程序運行時就知道了,原來你是初始值為0的全局變量呀,然后分散加載文件就在SRAM中給它分配了一段固定區域的地址;對於局部變量來說, 會自動分配大小,不用我們管。RW-DATA+ZI-DATA就是程序運行總共會占用SRAM的長度,為什么說總共呢?因為當某一個函數運行完后,在這個函數內部的局部變量會被釋放掉。再次強調一下,生成局部變量的棧空間包含在ZI-data區的范圍

 

圖4 程序的組成

  計算機系統的應用程序運行過程很類似,不過計算機系統的程序在存儲狀態時位於硬盤,執行的時候甚至會把上述的 RO 區域(代碼、只讀數據)加載到內存,加快運行速度,還有虛擬內存管理單元(MMU)輔助加載數據,使得可以運行比物理內存還大的應用程序,因為單片機中沒有MMU,所以無法支持 Linux 和 Windows 系統,這里我說的單片是指M系列的單片機,但是可以跑ucos或FreeRTOS系統。

2. Flash和Sram的理解

  存儲器是計算機結構的重要組成部分,存儲器是用來存儲程序代碼和數據的部件,有了存儲器計算機才具有記憶功能。按照存儲介質的特性,可以分“易失性存儲器”和“非易失性存儲器”兩類,易失和非易失是指存儲器斷電后,里面存儲的內容是否會丟失,另一邊的速度而言呢,易失性存儲器的速度要快於非易失性存儲器。

 

 

 

2.1 易失性存儲器

  按照RAM的物理存儲機制,可以分為DRAM(Dynamic)和SRAM(Static)兩類。首先,說一下目前所用的DRAM,其通訊時序是利用時鍾進行同步通訊,所以起名為Synchronous DRAM,那么,后期為了進一步提高SDRAM的通訊速度,人們設計了DDR SDRAM存儲器(Double Data Rate SDRAM),隨后又發展出二、三、四代SDRAM,現在很多PC機上的內存條是DDRIII SDRAM存儲器。另外,靜態隨機存儲器SRAM的存儲單元以鎖存器來存儲數據,結構比DRAM要復雜很多,所以生產相同容量的存儲器,DRAM的成本要更低,且集成度更高。這里我只講基本概念,怎么去操作這些易失性存儲器需要可以自行查找資料分析。

 

 

2.2 非易失性存儲器

  半導體類的非易失性存儲器有ROM和FLASH,感覺現在ROM使用的比較少了,貌似很多都被flash代替了。之前學單片機的時候,用的外接EEPROM算是一種ROM,不作過多介紹。FLASH的容量一般比EEPROM大得多,且在擦除時,一般以多個字節為單位。如有的FLASH存儲器以4096個字節為扇區,最小的擦除單位為一個扇區,有的也稱作頁page。根據存儲單元電路的不同,FLASH存儲器又分為NOR FLASH和NAND FLASH。

  NOR與NAND的共性是在數據寫入前都需要有擦除操作,而擦除操作一般是以“扇區/塊”為單位,而NOR與NAND特性的差別,主要是其內部“地址/數據線”是否分開導致的。

  • 由於NOR的地址線和數據線分開,它可以按“字節”讀寫數據,符合CPU的指令譯碼執行要求,所以假如NOR上存儲了代碼指令,CPU給NOR一個地址,NOR就能向CPU返回一個數據讓CPU執行,中間不需要額外的處理操作。所以,在功能上可以認為NOR是一種斷電后數據不丟失的RAM,但它的擦除單位與RAM有區別,且讀寫速度比RAM要慢得多。
  • 由於NAND的數據和地址線共用,只能按“塊”來讀寫數據,假如NAND上存儲了代碼指令,CPU給NAND地址后,它無法直接返回該地址的數據,所以不符合指令譯碼要求。若代碼存儲在NAND上,可以把它先加載到RAM存儲器上,再由CPU執行。

  目前,單片機SOC內部普遍使用的是SRAM和NorFlash。如果記不住,只需要知道,不跑linux操作系統的Flash全部是norflash,但是不絕對。

 

  Flash,SRAM寄存器和輸入輸出端口被組織在同一個4GB的線性地址空間內,可訪問的存儲器空間被分成8個主要塊,每個塊為512MB。存儲器本身不具有地址信息,它的地址是由芯片廠商或用戶分配,給存儲器分配地址的過程就稱為存儲器映射,如果給存儲器再分配一個地址就叫存儲器重映射。NRF52832的內存映射如下圖所示,

  在nordic芯片中FLASH存儲編譯后下載的程序,SRAM是存儲在程序運行中的臨時創建數據(ARMv7,哈弗結構),故只要你不外擴存儲器,寫完的程序中只要在芯片上運行起來,所有數據也就會出現在這兩個存儲器中。Flsah或者Ram內部又會根據不同的功能把他們分為多個模塊。

  在網上看到一張圖,感覺很有意思。這張圖是STM32程序下載到Flash上的存儲結構。如果你知道了這些具體地址,及地址塊的作用,就可以做BootLoader以便產品后期升級。具體分析寫Bootloader以及怎么分析這些地址,會在以后的分散加載文件中詳細講解。

參考網址:https://www.cnblogs.com/amanlikethis/p/3719529.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM