我們日常使用的嵌入式應用程式開發中都是編寫c/c++語言,我們平時編輯乙個工程的話,只用從main函式開始編輯,微控制器程式也是從這個函式開始進行執行的。但是微控制器上電後是如何尋找到並執行main函式的呢?我們其實都會在心裡有乙個答案:"啟動檔案",還記得我們當初配置第乙個stm32工程的時候在工程中新增過乙個startup_stm32f10x_hd.s的檔案,這個檔案的作用就是負責執行從"復位"到開始執行main函式中間的啟動過程,下面我將對這個檔案和stm32的相關知識進行闡述。
首先了解一下stm32的三種啟動方式:在每個stm32的晶元上都有兩個管腳boot0和boot1,這兩個管腳在晶元復位時的電平狀態決定了晶元復位後從哪個區域開始執行程式,見下表:boot1=x boot0=0 從使用者快閃儲存器flash啟動,這是正常的工作模式。boot1=0 boot0=1 從系統儲存器啟動,這種模式啟動的程式功能由廠家設定。boot1=1 boot0=1 從內建sram啟動,這種模式可以用於除錯。
而cortex-m3/4核心規定,起始位址必須存放堆頂指標,而第二個位址則必須存放復位中斷入口向量位址,這樣在cortex-m3/4核心復位後,會自動從起始位址的下乙個32位空間取出復位中斷入口向量,跳轉執行復位中斷服務程式。而啟動檔案的編寫正是按著這個規定來的,下面我將對啟動檔案的**進行分析。
我挑選了我們常用的startup_stm32f40_41***.s進行原始碼分析,該檔案可以分成以下五個典型部分:
1.堆疊空間定義;
2.存放中斷向量表;
3.復位中斷函式(reset_handler);
4.其它中斷異常服務函式,以及弱[weak]宣告;
5.將堆疊位址傳遞給庫函式,利用庫函式初始化堆疊,和庫函式自身初始化。
01堆疊空間的定義
如下圖所示,定義了棧大小stack_size = 0x400,即1024個位元組;堆大小heap_size = 0x200, 512個位元組。還定義了三個標號:__initial_sp(棧頂)、__heap_base(堆起始位址)和__heap_limit(堆終止位址),它們的空間由space關鍵字來申請,並記作stack_mem和heap_mem。
02存放中斷向量表
在啟動**中,會見到許多由dcd申請空間存放的乙個個函式入口,即中斷向量表,關鍵字dcd代表申請乙個字的空間,後面的函式名即為中斷服務函式入口位址。
03中斷復位函式
程式上電後,首先載入sp和pc,arm規定從0位址處載入堆頂指標,從偏移為4的位址(0x00000004)處載入復位函式,然後後將程式控制權交給程式。我們知道0位址處存放__initial_sp,0x00000004位址處存放reset_handler,符合arm規定。
__main標號並不表示c程式中的main函式入口位址,因此第131行也並不是跳轉至main函式開始執行c程式。__main標號表示c/c++標準實時庫函式裡的乙個初始化子程式__main的入口位址。該程式的乙個主要作用是初始化堆疊(對於程式清單一來說則是跳轉__user_initial_stackheap標號進行初始化堆疊的),並初始化映像檔案,最後跳轉c程式中的main函式。這就解釋了為何所有的c程式必須有乙個main函式作為程式的起點——因為這是由c/c++標準實時庫所規定的——並且不能更改,因為c/c++標準實時庫並不對外界開發源**.
04其他中斷異常服務函式,以及弱宣告
所謂弱宣告,即:如果使用者定義了相同的函式則此處函式失效而使用使用者定義的中斷服務函式,這樣可以防止使用者使能了中斷二沒有中斷服務函式造成程式崩潰。
05將堆疊位址傳遞給庫函式
第三步驟中,呼叫__main函式,然後__main呼叫庫函式初始化堆疊,但庫函式並不知道堆疊的大小,因此我們需要告訴它。
至此可以總結一下stm32的啟動過程和啟動檔案。首先對堆疊大小進行定義,並建立中斷向量表,其第乙個表項是棧頂位址,第二個表項是復位中斷服務入口位址,然後在復位中斷服務程式中跳轉到c/c++標準實時庫的_main函式,完成使用者堆疊初始化後,跳轉到c檔案的main函式開始執行c程式。假設stm32被設定為從內部flash啟動(這也是最常見的一種情況),中斷向量表起始地位為0x8000000,則棧頂位址存放於0x8000000處,而復位中斷服務入口位址存放於0x8000004處。當stm32遇到復位訊號後,則從0x80000004處取出復位中斷服務入口位址,繼而執行復位中斷服務程式,然後跳轉__main函式,最後進入mian函式,來到c的世界。
STM32復位函式
軟體復位 void g mcureset void 其實hal nvic systemreset是 void hal nvic systemreset void 其實nvic systemreset是 static inline void nvic systemreset void 系統復位 那麼核...
關於STM32 軟體復位
對於stm32 來說軟體復位有兩種方式 1 採用官方自帶的軟體庫 在官方軟體庫的stm32f10x nvic.c 檔案裡直接提供了系統復位的函式 void nvic generatesystemreset void 但是不是直接呼叫這個函式就ok 了?在cortex m3 權威指南中有這麼一句話 這...
stm32 復位到內部bootloader
sm32的bootloader一般是通過開機時設定boot0 1來實現的。下面是通過程式來實現 原來的startup檔案是直接把flash的資料載入到ram裡面然後跑main函式迴圈 bootloader的程式在0x1fff d800 那只要在進入main函式之前先判斷是否要進入bootloader...