在上電復位后,我們都知道會先運行啟動代碼,但是啟動代碼到底使干什么用的呢?下面小弟給大家一一列出來。 1、初始化堆棧指針
2、初始化 PC 指針
3、初始化中斷向量表
4、配置系統時鐘
5、調用 C 庫函數_main 初始化用戶堆棧 我們根據這以上的幾個步驟一一進行詳細的解析: 1、棧的內存分配
547_20180514160511_pc4jc.png (13.36 KB, 下載次數: 31)
下載附件
2018-5-16 17:40 上傳
這段代碼的意思是,開辟了一個棧,這個棧的大小是0x00000400也就是1KB的大小,名字為STACK,不初始化,可讀可寫,2^3=8字節對齊。 那么問題來了,那這個棧到底使干什么的呢?小弟相信大家在學習C語言的時候應該也是知道了,棧區保存的是局部變量,只是當時并沒有深入研究它的大小問題。那在這里小弟給大家詳細講解一下棧的作用: 1、局部變量 2、函數調用 3、函數形參 以上的這三種情況的開銷都是使用我們的棧區的資源的。所以!這里小弟給個位提個醒,千萬不要把棧區當成無止境大小的 哦!STM32可不比我們的電腦,沒有那么多的空間可以給大伙揮霍,如果我們定義的局部變量過大可是會莫名其妙報錯的。 溫馨提示:請不要在寫程序時,過度使用局部變量,會造成棧的益處,從而導致編譯報錯,如果在特殊情況下真的需要很大的棧區空間,只需來這里進行棧區大小的修改即可。 那么小弟再來給這個程序段里的匯編指令做一個詳細的介紹 Stack_Size EQU 0x00000400 EQU:宏定義的偽指令,相當于等于,類似與 C 中的 define。 這句話的意思是,定義一個宏名Stack_Size這個宏代表0x00000400的意思,用我們C語言來表示就是 #define Stack_Size 0x00000400
AREA STACK, NOINIT, READWRITE, ALIGN=3 AREA:告訴匯編器匯編一個新的代碼段或者數據段。 STACK:表示段名 NOINIT:表示不初始化 READWRITE:表示可讀可寫 ALIGN=n:表示按照 2^n字節對齊 這里小弟就不多說了,解釋已經很詳細了,小哥哥小姐姐們自己組合起來吧 Stack_Mem SPACE Stack_Size SPACE:用于分配一定大小的內存空間,單位為字節。 這句話的意思是,分配一個內存空間,這個內存空間的大小為Stack_Size,也就是我們剛才宏定義的0x00000400 然后最后標號__initial_sp 緊挨著 SPACE 語句放置,表示棧的結束地址。也就是棧頂的地址。 溫馨提示:棧的生長是由高地址向低地址生長的。
2、堆的內存分配
547_20180514160511_w10di.png (15.3 KB, 下載次數: 31)
下載附件
2018-5-16 17:40 上傳
這段代碼的意思是,開辟堆的大小為0x00000200也就是512B的大小,名字為HEAP,不初始化,8字節對齊。
在之前我們一直認為的是,全局變量,靜態變量都分配在堆區中,這里是不正確的,我們的全局變量和靜態變量,并不是直接 分配在堆中,這里的堆只有malloc函數分配的內存,會在這里進行分配,而靜態變量和局部變量都是在SRAM中分配,這也就是為什么我們全局變量可以定義一個大于512B大小的空間了。
溫馨提示:如果使用了malloc函數一定要注意這個堆咯!不可以大于512B呢!當然這里也可以進行修改。
那咱們再來一條一條語句進行分析吧! Heap_Size EQU 0x00000200 這里我們就不多說了這條代碼和上面那條是一個意思
AREA HEAP, NOINIT, READWRITE, ALIGN=3 這里也和上面差不多,唯一改變的就是段名是HEAP而不是STACK了
__heap_base 在SPACE前出現這條代碼代表的是堆的起始地址
Heap_Mem SPACE Heap_Size 這里是分配一個0X00000200大小的空間
__heap_limit 在SPACE后出現這條代碼代表的是堆的結束地址
PRESERVE8 指定當前文件的堆棧按照 8 字節對齊 THUMB
表示后面指令兼容 THUMB 指令。THUBM 是 ARM 以前的指令集,16bit,現在 Cortex-M 系列的都使用 THUMB-2 指令集,THUMB-2 是 32 位的,兼容 16 位和 32 位的指令。 3、向量表
547_20180514170507_u3ren.png (9.88 KB, 下載次數: 37)
下載附件
2018-5-16 17:40 上傳
這段代碼的意思是,定義了一個數據短,名字叫RESET,只可讀。 那么這里問題來了,什么是向量表呢!在這里,這個向量表示為了決定中斷服務函數的入口的,每一個向量表都是4個字節, 向量表決定了入口的偏移地址。 AREA RESET, DATA, READONLY
這句話的意思是定義了一個代碼段RESET,只可讀
EXPORT __Vectors
EXPORT __Vectors_End
EXPORT __Vectors_Size 這三句話都是同一個意思,相當于C語言中的EXPORT可以被外部文件所引用
向量表如下
547_20180514170524_1q411.png (35.86 KB, 下載次數: 29)
下載附件
2018-5-16 17:40 上傳
...........................省略部分.................................
547_20180514170545_nsuzx.png (15.82 KB, 下載次數: 32)
下載附件
2018-5-16 17:40 上傳
這里呢,就是我們的中斷向量表了,我們可以發現,它是從棧區中開始加載的,從棧頂開始, __Vectors 代表向量起始地址 __Vectors_End 代表向量結束地址 DCD:分配一個或者多個以字為單位的內存,以四字節對齊,并要求初始化這些內存。在向量表中,DCD 分配了一堆內存,并且以 ESR 的入口地址初始化它們
Reset_Handler
NMI_Handler
HardFault_Handler
MemManage_Handler
BusFault_Handler
UsageFault_Handler 這些都是地址,我們的知道,函數名就是函數的地址,所以我們的中斷服務函數必須使用這些作為函數名,否則無法正確進入中斷服務函數。
__Vectors_Size EQU __Vectors_End - __Vectors 通過這句話我們知道結束地址-起始地址,自然就是向量表的大小了。
好的,個位小哥哥小姐姐,今天的課就上到這里了,剩下的部分我們下回分解。 |