ARM CORTEX-M3 內核架構理解概括 編程
來源:網絡 我的以爲對CM3架構概括的很是不錯,所以轉載 網絡
基於《ARM-CORTEX M3 權威指南》作學習總結; 架構
在我看來,Cotex-M3內核的主要包括:嵌套向量中斷控制器(NVIC),取值單元,指令譯碼器,算數邏輯單元(ALU),寄存器組,存儲器映射(4GB統一編址各區域功能的劃分與界定),對於開發者而言,其實主要關注的主要分爲三大塊: 框架
1、寄存器組2、地址功能劃分映射3、中斷機制(NVIC)。 函數
1)寄存器組 性能
Cortex-M3內核共有19組32位寄存器: 學習
R0——R12(通用寄存器); spa
低寄存器組R0——R7 操作系統
32位Thumb-2指令與16位Thumb指令都可訪問 線程
高寄存器組R8——R12
32位Thumb-2指令與極少數16位Thumb指令可訪問
R13(堆棧指針寄存器);
主堆棧寄存器MSP(main-SP)/進程堆棧寄存器PSP(Process-SP)同一時間只能使用其中一個。MSP供操做系統內核及中斷(異常)處理子程序使用,PSP只供用戶的應用程序代碼使用(詳細使用詳見3、嵌套向量中斷控制器(NVIC)的總結)。
堆棧指針是4字節對齊的,故最低兩位永遠是00;
R14(鏈接寄存器)
用於存儲程序返回的地址及PC的返回地址;
R15(程序寄存器)指向當前程序執行的地址;
2)特殊功能寄存器組
xPSR(程序狀態字寄存器組),32位,可分爲三個寄存器分別進行訪問,也能夠PSR或xPSR的名字直接組合訪問。
應用程序PSR(APSR)
中斷號PSR(IPSR)
執行PSR (EPSR)
中斷屏蔽寄存器
PRIMASK 單一比特位,置位後,除NMI與硬fault外,其餘中斷都不響應;
FAULTMASK 單一比特位,置位後,除NMI外,其餘中斷都不響應;
BASEPRI 共有9位,中斷號小於等於該寄存器設置值的中斷都不響應;
控制寄存器control
Control[0] 0決定特權級線程模式;1用戶級線程模式;
Control[1] 0主堆棧;1進程堆棧;
控制寄存器只能在特權級模式下改寫,handler模式永遠是特權級,且只容許使用主堆棧MSP
復位後,處理器進入特權級+線程模式下;
2、地址功能劃分映射
Cortex-m3是一個32位處理器,其地址總線、數據總線都是32位的,故可在4G的地址範圍上資源尋址。Cortex-m3內核把4G空間劃定了基本的框架,定義不一樣的使用用途。
0x0000 0000 ----0x1FFF FFFF (512MB) 該區域爲code區(flash區),供指令總線與數據總線取指取數使用;能夠執行指令;
0x2000 0000 ----0x3FFF FFFF (512MB) 該區域爲片上SRAM區,芯片製造商可在此佈設RAM,能夠將代碼複製到此處運行,該區域也是能夠執行指令code的;低1MB空間可位尋址,經過位帶別名可擴展爲32Mb的位尋址。
0x4000 0000 ----0x5FFF FFFF (512MB)該區域爲"片上外設"區 ,主要爲片上外設的相關寄存器,即特殊功能寄存器區,同理低1MB也可位尋址;該區域不可執行代碼;
0x6000 0000 ----0x9FFF FFFF(1G)該區域爲片外RAM區,該區域可執行代碼;
0xA000 0000 ----0xDFFF FFFF(1G)該區域爲片外外設區,該區域不可執行代碼;
0xE000 0000 ----0xFFFF FFFF(1G)該區域爲系統區,該區域不可執行代碼;
因此不一樣地址片斷的起始地址可簡記爲:0,2,4,6,10,E,
該系統區又分爲兩部分:
內部私有外設區0xE000 0000 ----0xE003 FFFF(256KB)主要有NVIC,FPB,DWT,ITM等
外部私有外設區0xE004 0000 ----0xE00F FFFF(512+256=768KB)有ROM表,ETM,TPIU等
數據的大小端模式:CM-3既支持大端模式也支持小端模式,其中對於大端模式,ARM7中使用的是字不變大端模式,CM3中則爲字節不變大端模式。雖然說大小端模式都支持,但依然建議在絕大多數狀況下使用小端模式,若是一些外設是大端模式,能夠經過REV/REVH指令即可輕鬆完成端模式的轉換。
3、中斷機制(NVIC)
既然稱之爲MCU而非MPU,那麼就是以控制爲主,控制的一個關鍵指標就是實時性,可以及時對變化的狀況做出反應,而這主要是經過中斷機制來完成的,能夠說除卻運算性能,cortex-M3內核的主要修爲都體如今控制的實時性上——也即中斷的即時響應機制。
CM3對中斷是怎麼定義的呢?
一個是CM3內核異常致使當前運行程序的中斷,一個是外部事件引入致使的。
系統異常主要是CM3內核層面的,復位,NMI,硬fault,這三者優先級固定且最高,此外還有總線fault、內存管理fault、用法fault等,svc系統調用服務、systick等的優先級能夠經過編程來設定;這些都放在一個向量表裏,存儲的是中斷服務函數的入口地址,32位,共256項,前16個是系統內的中斷,除去保留位,系統中斷共有16-5-1=10個,剩餘240個外部中斷IRQ,其中有三個的優先級是固定的:復位,NMI,硬fault,中斷號分別爲-3,-2,-1,中斷號越小,優先級也就越高,其餘優先級都是可編程的。此外,對於復位啓動過程,M3內核的MCU與傳統的單片機復位是不同的,傳統的單片機是直接從地址0處開始運行,而後再執行地址0處的跳轉指令,跳轉到設定的程序起始段;而CM3復位後首先是在地址零處0x0000 0000取出主堆棧MSP的初始值,(由於CM3的堆棧是向下生長型的,因此這個初始值通常設爲RAM區的末地址+1,以保證堆棧足夠大,再囉嗦下,比方說RAM區爲0x2000 0000——0x3FFF FFFF那麼初始值就設置爲0x4000 0000);而後經過復位中斷號找到存放復位程序入口地址的地址單元(0x00000004),地址單元(0x00000004)存放着第一條指令執行的地址(0x0000 0100)並賦給PC,PC就從這個地址裏存放的指令依次執行。關於指令執行的地址須要嚴重關切:CM3運行在thumb狀態,因此加載到PC中的值的最低位LSB必須置1,以區別ARM狀態(ARM爲偶數),因此若想指向0x0000 0100的地址值,中斷向量表中存的復位程序入口地址應爲0x0000 0101,用0x0000 0101表示0x0000 0100,這裏不要把存儲數據的地址和PC的指向地址搞混,只有PC的執行地址LSB不能等於0,其餘總線訪問地址則沒有此限制。(爲了把問題解釋清楚,囉嗦的我本身都受不了了)爲何要首先初始化堆棧MSP呢?由於在復位的過程當中也可能發生中斷,例如NMI,硬fault等。
中斷從發生到結束主要須要通過如下這麼幾個步驟:1捕獲並響應中斷,2現場保護,3中斷程序入口,4返回。下面就根據這個脈絡來總結cortexM3在提升中斷響應速度方面所涉及的重要知識點(這個講解順序針對已具有必定的基礎人員):
說到中斷必涉及到優先級、涉及到嵌套,在CM3中用8位來編程中斷的優先級數,可實現256級優先級,其中這8位又分爲兩段,一段決定搶佔優先級的級數,一個決定亞優先級的級數,其中規定搶佔優先級不得少於3位(8級優先級),亞優先級最少不得少於1位,因此搶佔優先級在M3中最多128級,在哪一位開始分組由NVIC中的寄存器中(應用程序中斷及復位控制寄存器)的PRIGROUP來決定;但實際中,芯片製造商通常只使用最高几位,好比5位,高三位(7,6,5)編程搶佔優先級,剩下的兩個次高位(4,3)用來決定亞優先級,從第4位處做爲亞優先級的分組,這裏經過一個分組寄存器來決定從哪一位作亞優先級分組。
優先級肯定好了,那麼在衆多不一樣優先級的中斷面前,CM3又是以什麼樣的機制來提升響應速度的呢?這就須要表一表在響應以前,處理器必需要作的工做——現場保護即保護當前的程序運行環境,依次入棧如下8個寄存器:程序狀態寄存器XPSR,程序計數器PC,返回地址寄存器LR(鏈接寄存器),R12,R0——R3,這些都是硬件自動完成的。若是當前正在使用堆棧,則壓入相應的堆棧寄存器MSP/PSP值,當前在用PSP就壓入PSP,反之則壓入MSP,進入中斷服務程序就將一直用MSP了;好了,請注意,提升中斷的響應速度就在這些寄存器的入棧順序上,咱們知道,堆棧是創建在片上RAM中的,經過系統總線(system code)來操做(爲何要創建在RAM上,由於堆棧須要不停地作出棧、入棧等動做,須要不斷改變存儲的值,而flash或rom只在燒寫的時候寫入數據),指令是存放在flash中的即code區經過指令總線(code bus)來操做,因此在入棧的時候先壓入xPSR的值,再壓入PC的值,壓入PC的值後,就能夠經過指令總線,根據中斷向量號取出中斷服務函數的地址賦給PC新的指令地址,進行指令的預取,而堆棧仍然能夠經過系統總線繼續壓入其餘寄存器的值,與取指令操做並行不悖,互不干擾,加快了中斷的響應速度。相關寄存器可查詢權威手冊。
在響應中斷前所作的準備工做都作好了,那麼當衆多中斷前來叫門時,應該如何以最短的延時處理一系列的中斷呢?第一級中斷自沒必要說,根據中斷號來進行仲裁,當發生中斷嵌套的時候,CM3中的一些響應機制就能加快整個中斷響應過程的速度了,低優先級因爲高優先級中斷的搶佔而處於掛起狀態,當高優先級中斷處理完畢,按照傳統的嵌套中斷處理流程,高優先級中斷處理完成後應該出棧彈出內容,而後再入棧壓入先前彈出的內容,再處理被掛起的低優先級中斷,按書中所說,這就是砸鍋鍊鐵再鑄鍋的過程,徹底沒有必要,因而CM3內核在處理一系列嵌套的中斷時,總共只執行一次入棧,出棧工做,這樣處理連續的幾個嵌套中斷時,就減小了不少環節,縮短了時間,尤爲是嵌套級別計較深的時候,尤其明顯。可是要注意的是:不要嵌套太深,由於每嵌套一級就至少入棧8個32位的寄存器值(32B),若是自己就是中斷進程,當前代碼正在使用堆棧,還要將堆棧的值再入棧,這樣無疑加大了堆棧的存儲壓力,若是用穿堆棧,發生溢出,程序十有八九就跑飛了,是很危險的,因此在應用中,要儘可能減少中斷的嵌套深度。
以前的中斷響應機制發生在高級中斷打斷低優先級中斷完成響應以後,譯者將其名曰:咬尾中斷;下面的中斷則發生在高優先級中斷打斷低優先級中斷準備響應之時,當高優先級中斷還沒來的時候,低優先級中斷已經把前期準備工做給作完了,這時候高優先級中斷來了,那麼此時高優先級中斷會直接利用低優先級中斷的前期工做成果,直接開始響應,進入服務中斷服務程序,而以前的低級中斷則被迫掛起,爲別人作嫁衣了,沒辦法,內核就是這樣規定的,譯者將其譯爲"晚到(的高優先級)異常"我將其名爲"後來居上"中斷。
中斷延遲時間:從檢測到中斷,到執行中斷服務程序的第一條指令,其間所流逝的時間。
書中雲:若是存儲系統足夠快,入棧與取指令能夠分別進行,且中斷能夠即刻獲得響應不被搶佔,那麼所耗費的時間就是固定的12個週期(知足硬實時要求的肯定性)。若是多級嵌套中斷響應,算上咬尾中斷省去的出入棧時間,每一箇中斷可減小至6個週期。
最後再說說異常即fault,內核活動層面的東西,這個本應是須要大書特書的東西,尤爲是在調試程序的時候找bug上,是體現一我的技能水平的很重要的方面,可是限於時間與研究深度,暫時不深究了,
就一句話吧:運行時出現的系統錯誤有時候不是編程上的語法錯誤,若是不瞭解內核架構和一些使用準則,是很難發現bug在哪裏,這就須要追溯究竟是程序運行到哪裏出了問題,致使內核運行出現了錯誤,得益於CM3完備的調試架構,不少fault的產生都會被監測到,並記錄在對應的寄存器中,按圖索驥就知道問題出在哪裏,是哪條指令致使的,藉此針對性的自查、分析、修改。