ARM CORTEX-M3 內(nèi)核架構(gòu)理解歸納
1、寄存器組2、地址功能劃分映射3、中斷機(jī)制(NVIC)。
本文引用地址:http://m.butianyuan.cn/article/201611/319530.htm1)寄存器組
Cortex-M3內(nèi)核共有19組32位寄存器:
R0——R12(通用寄存器);
低寄存器組R0——R7
32位Thumb-2指令與16位Thumb指令均可訪問(wèn)
高寄存器組R8——R12
32位Thumb-2指令與極少數(shù)16位Thumb指令可訪問(wèn)
R13(堆棧指針寄存器);
主堆棧寄存器MSP(main-SP)/進(jìn)程堆棧寄存器PSP(Process-SP)同一時(shí)間只能使用其中一個(gè)。MSP供操作系統(tǒng)內(nèi)核及中斷(異常)處理子程序使用,PSP只供用戶的應(yīng)用程序代碼使用(詳細(xì)使用詳見3、嵌套向量中斷控制器(NVIC)的總結(jié))。
堆棧指針是4字節(jié)對(duì)齊的,故最低兩位永遠(yuǎn)是00;
R14(連接寄存器)
用于存儲(chǔ)程序返回的地址及PC的返回地址;
R15(程序寄存器)指向當(dāng)前程序執(zhí)行的地址;
2)特殊功能寄存器組
xPSR(程序狀態(tài)字寄存器組),32位,可分為三個(gè)寄存器分別進(jìn)行訪問(wèn),也可以PSR或xPSR的名字直接組合訪問(wèn)。
應(yīng)用程序PSR(APSR)
中斷號(hào)PSR(IPSR)
執(zhí)行PSR (EPSR)
中斷屏蔽寄存器
PRIMASK單一比特位,置位后,除NMI與硬fault外,其他中斷都不響應(yīng);
FAULTMASK單一比特位,置位后,除NMI外,其他中斷都不響應(yīng);
BASEPRI共有9位,中斷號(hào)小于等于該寄存器設(shè)置值的中斷都不響應(yīng);
控制寄存器control
Control[0]0決定特權(quán)級(jí)線程模式;1用戶級(jí)線程模式;
Control[1]0主堆棧;1進(jìn)程堆棧;
控制寄存器只能在特權(quán)級(jí)模式下改寫,handler模式永遠(yuǎn)是特權(quán)級(jí),且只允許使用主堆棧MSP
復(fù)位后,處理器進(jìn)入特權(quán)級(jí)+線程模式下;
2、地址功能劃分映射
Cortex-m3是一個(gè)32位處理器,其地址總線、數(shù)據(jù)總線都是32位的,故可在4G的地址范圍上資源尋址。Cortex-m3內(nèi)核把4G空間劃定了基本的框架,定義不同的使用用途。
0x0000 0000 ----0x1FFF FFFF (512MB)該區(qū)域?yàn)閏ode區(qū)(flash區(qū)),供指令總線與數(shù)據(jù)總線取指取數(shù)使用;可以執(zhí)行指令;
0x2000 0000 ----0x3FFF FFFF (512MB)該區(qū)域?yàn)槠蟂RAM區(qū),芯片制造商可在此布設(shè)RAM,可以將代碼復(fù)制到此處運(yùn)行,該區(qū)域也是可以執(zhí)行指令code的;低1MB空間可位尋址,通過(guò)位帶別名可擴(kuò)展為32Mb的位尋址。
0x4000 0000 ----0x5FFF FFFF (512MB)該區(qū)域?yàn)?ldquo;片上外設(shè)”區(qū) ,主要為片上外設(shè)的相關(guān)寄存器,即特殊功能寄存器區(qū),同理低1MB也可位尋址;該區(qū)域不可執(zhí)行代碼;
0x6000 0000 ----0x9FFF FFFF(1G)該區(qū)域?yàn)槠釸AM區(qū),該區(qū)域可執(zhí)行代碼;
0xA000 0000 ----0xDFFF FFFF(1G)該區(qū)域?yàn)槠馔庠O(shè)區(qū),該區(qū)域不可執(zhí)行代碼;
0xE000 0000 ----0xFFFF FFFF(1G)該區(qū)域?yàn)橄到y(tǒng)區(qū),該區(qū)域不可執(zhí)行代碼;
所以不同地址片段的起始地址可簡(jiǎn)記為:0,2,4,6,10,E,
該系統(tǒng)區(qū)又分為兩部分:
內(nèi)部私有外設(shè)區(qū)0xE000 0000 ----0xE003 FFFF(256KB)主要有NVIC,FPB,DWT,ITM等
外部私有外設(shè)區(qū)0xE004 0000 ----0xE00F FFFF(512+256=768KB)有ROM表,ETM,TPIU等
數(shù)據(jù)的大小端模式:CM-3既支持大端模式也支持小端模式,其中對(duì)于大端模式,ARM7中使用的是字不變大端模式,CM3中則為字節(jié)不變大端模式。雖說(shuō)大小端模式都支持,但依然建議在絕大多數(shù)情況下使用小端模式,如果一些外設(shè)是大端模式,可以通過(guò)REV/REVH指令便可輕松完成端模式的轉(zhuǎn)換。
3、中斷機(jī)制(NVIC)
既然稱之為MCU而非MPU,那么就是以控制為主,控制的一個(gè)關(guān)鍵指標(biāo)就是實(shí)時(shí)性,能夠及時(shí)對(duì)變化的情況作出反應(yīng),而這主要是通過(guò)中斷機(jī)制來(lái)完成的,可以說(shuō)除卻運(yùn)算性能,cortex-M3內(nèi)核的主要修為都體現(xiàn)在控制的實(shí)時(shí)性上——也即中斷的即時(shí)響應(yīng)機(jī)制。
CM3對(duì)中斷是怎么定義的呢?
一個(gè)是CM3內(nèi)核異常導(dǎo)致當(dāng)前運(yùn)行程序的中斷,一個(gè)是外部事件引入導(dǎo)致的。
系統(tǒng)異常主要是CM3內(nèi)核層面的,復(fù)位,NMI,硬fault,這三者優(yōu)先級(jí)固定且最高,此外還有總線fault、內(nèi)存管理fault、用法fault等,svc系統(tǒng)調(diào)用服務(wù)、systick等的優(yōu)先級(jí)可以通過(guò)編程來(lái)設(shè)定;這些都放在一個(gè)向量表里,存儲(chǔ)的是中斷服務(wù)函數(shù)的入口地址,32位,共256項(xiàng),前16個(gè)是系統(tǒng)內(nèi)的中斷,除去保留位,系統(tǒng)中斷共有16-5-1=10個(gè),剩余240個(gè)外部中斷IRQ,其中有三個(gè)的優(yōu)先級(jí)是固定的:復(fù)位,NMI,硬fault,中斷號(hào)分別為-3,-2,-1,中斷號(hào)越小,優(yōu)先級(jí)也就越高,其他優(yōu)先級(jí)都是可編程的。此外,對(duì)于復(fù)位啟動(dòng)過(guò)程,M3內(nèi)核的MCU與傳統(tǒng)的單片機(jī)復(fù)位是不一樣的,傳統(tǒng)的單片機(jī)是直接從地址0處開始運(yùn)行,然后再執(zhí)行地址0處的跳轉(zhuǎn)指令,跳轉(zhuǎn)到設(shè)定的程序起始段;而CM3復(fù)位后首先是在地址零處0x0000 0000取出主堆棧MSP的初始值,(因?yàn)镃M3的堆棧是向下生長(zhǎng)型的,所以這個(gè)初始值一般設(shè)為RAM區(qū)的末地址+1,以保證堆棧足夠大,再啰嗦下,比方說(shuō)RAM區(qū)為0x2000 0000——0x3FFF FFFF那么初始值就設(shè)置為0x4000 0000);然后通過(guò)復(fù)位中斷號(hào)找到存放復(fù)位程序入口地址的地址單元(0x00000004),地址單元(0x00000004)存放著第一條指令執(zhí)行的地址(0x0000 0100)并賦給PC,PC就從這個(gè)地址里存放的指令依次執(zhí)行。關(guān)于指令執(zhí)行的地址需要嚴(yán)重關(guān)切:CM3運(yùn)行在thumb狀態(tài),所以加載到PC中的值的最低位LSB必須置1,以區(qū)別ARM狀態(tài)(ARM為偶數(shù)),所以若想指向0x0000 0100的地址值,中斷向量表中存的復(fù)位程序入口地址應(yīng)為0x0000 0101,用0x0000 0101表示0x0000 0100,這里不要把存儲(chǔ)數(shù)據(jù)的地址和PC的指向地址搞混,只有PC的執(zhí)行地址LSB不能等于0,其他總線訪問(wèn)地址則沒(méi)有此限制。(為了把問(wèn)題解釋清楚,啰嗦的我自己都受不了了)為什么要首先初始化堆棧MSP呢?因?yàn)樵趶?fù)位的過(guò)程中也可能發(fā)生中斷,例如NMI,硬fault等。
中斷從發(fā)生到結(jié)束主要需要經(jīng)過(guò)以下這么幾個(gè)步驟:1捕獲并響應(yīng)中斷,2現(xiàn)場(chǎng)保護(hù),3中斷程序入口,4返回。下面就根據(jù)這個(gè)脈絡(luò)來(lái)總結(jié)cortexM3在提高中斷響應(yīng)速度方面所涉及的重要知識(shí)點(diǎn)(這個(gè)講解順序針對(duì)已具備一定的基礎(chǔ)人員):
說(shuō)到中斷必涉及到優(yōu)先級(jí)、涉及到嵌套,在CM3中用8位來(lái)編程中斷的優(yōu)先級(jí)數(shù),可實(shí)現(xiàn)256級(jí)優(yōu)先級(jí),其中這8位又分為兩段,一段決定搶占優(yōu)先級(jí)的級(jí)數(shù),一個(gè)決定亞優(yōu)先級(jí)的級(jí)數(shù),其中規(guī)定搶占優(yōu)先級(jí)不得少于3位(8級(jí)優(yōu)先級(jí)),亞優(yōu)先級(jí)最少不得少于1位,所以搶占優(yōu)先級(jí)在M3中最多128級(jí),在哪一位開始分組由NVIC中的寄存器中(應(yīng)用程序中斷及復(fù)位控制寄存器)的PRIGROUP來(lái)決定;但實(shí)際中,芯片制造商一般只使用最高幾位,比如5位,高三位(7,6,5)編程搶占優(yōu)先級(jí),剩下的兩個(gè)次高位(4,3)用來(lái)決定亞優(yōu)先級(jí),從第4位處作為亞優(yōu)先級(jí)的分組,這里通過(guò)一個(gè)分組寄存器來(lái)決定從哪一位做亞優(yōu)先級(jí)分組。
優(yōu)先級(jí)確定好了,那么在眾多不同優(yōu)先級(jí)的中斷面前,CM3又是以什么樣的機(jī)制來(lái)提高響應(yīng)速度的呢?這就需要表一表在響應(yīng)之前,處理器必須要做的工作——現(xiàn)場(chǎng)保護(hù)即保護(hù)當(dāng)前的程序運(yùn)行環(huán)境,依次入棧以下8個(gè)寄存器:程序狀態(tài)寄存器XPSR,程序計(jì)數(shù)器PC,返回地址寄存器LR(連接寄存器),R12,R0——R3,這些都是硬件自動(dòng)完成的。如果當(dāng)前正在使用堆棧,則壓入相應(yīng)的堆棧寄存器MSP/PSP值,當(dāng)前在用PSP就壓入PSP,反之則壓入MSP,進(jìn)入中斷服務(wù)程序就將一直用MSP了;好了,請(qǐng)注意,提高中斷的響應(yīng)速度就在這些寄存器的入棧順序上,我們知道,堆棧是建立在片上RAM中的,通過(guò)系統(tǒng)總線(system code)來(lái)操作(為什么要建立在RAM上,因?yàn)槎褩P枰煌5刈龀鰲?、入棧等?dòng)作,需要不斷改變存儲(chǔ)的值,而flash或rom只在燒寫的時(shí)候?qū)懭霐?shù)據(jù)),指令是存放在flash中的即code區(qū)通過(guò)指令總線(code bus)來(lái)操作,所以在入棧的時(shí)候先壓入xPSR的值,再壓入PC的值,壓入PC的值后,就可以通過(guò)指令總線,根據(jù)中斷向量號(hào)取出中斷服務(wù)函數(shù)的地址賦給PC新的指令地址,進(jìn)行指令的預(yù)取,而堆棧仍然可以通過(guò)系統(tǒng)總線繼續(xù)壓入其他寄存器的值,與取指令操作并行不悖,互不干擾,加快了中斷的響應(yīng)速度。相關(guān)寄存器可查詢權(quán)威手冊(cè)。
在響應(yīng)中斷前所做的準(zhǔn)備工作都做好了,那么當(dāng)眾多中斷前來(lái)叫門時(shí),應(yīng)該如何以最短的延時(shí)處理一系列的中斷呢?第一級(jí)中斷自不必說(shuō),根據(jù)中斷號(hào)來(lái)進(jìn)行仲裁,當(dāng)發(fā)生中斷嵌套的時(shí)候,CM3中的一些響應(yīng)機(jī)制就能加快整個(gè)中斷響應(yīng)過(guò)程的速度了,低優(yōu)先級(jí)由于高優(yōu)先級(jí)中斷的搶占而處于掛起狀態(tài),當(dāng)高優(yōu)先級(jí)中斷處理完畢,按照傳統(tǒng)的嵌套中斷處理流程,高優(yōu)先級(jí)中斷處理完成后應(yīng)該出棧彈出內(nèi)容,然后再入棧壓入先前彈出的內(nèi)容,再處理被掛起的低優(yōu)先級(jí)中斷,按書中所說(shuō),這就是砸鍋煉鐵再鑄鍋的過(guò)程,完全沒(méi)有必要,于是CM3內(nèi)核在處理一系列嵌套的中斷時(shí),總共只執(zhí)行一次入棧,出棧工作,這樣處理連續(xù)的幾個(gè)嵌套中斷時(shí),就減少了很多環(huán)節(jié),縮短了時(shí)間,尤其是嵌套級(jí)別計(jì)較深的時(shí)候,尤為明顯。但是要注意的是:不要嵌套太深,因?yàn)槊壳短滓患?jí)就至少入棧8個(gè)32位的寄存器值(32B),如果本身就是中斷進(jìn)程,當(dāng)前代碼正在使用堆棧,還要將堆棧的值再入棧,這樣無(wú)疑加大了堆棧的存儲(chǔ)壓力,如果用穿堆棧,發(fā)生溢出,程序十有八九就跑飛了,是很危險(xiǎn)的,所以在應(yīng)用中,要盡量減小中斷的嵌套深度。
之前的中斷響應(yīng)機(jī)制發(fā)生在高級(jí)中斷打斷低優(yōu)先級(jí)中斷完成響應(yīng)之后,譯者將其名曰:咬尾中斷;下面的中斷則發(fā)生在高優(yōu)先級(jí)中斷打斷低優(yōu)先級(jí)中斷準(zhǔn)備響應(yīng)之時(shí),當(dāng)高優(yōu)先級(jí)中斷還沒(méi)來(lái)的時(shí)候,低優(yōu)先級(jí)中斷已經(jīng)把前期準(zhǔn)備工作給做完了,這時(shí)候高優(yōu)先級(jí)中斷來(lái)了,那么此時(shí)高優(yōu)先級(jí)中斷會(huì)直接利用低優(yōu)先級(jí)中斷的前期工作成果,直接開始響應(yīng),進(jìn)入服務(wù)中斷服務(wù)程序,而之前的低級(jí)中斷則被迫掛起,為別人做嫁衣了,沒(méi)辦法,內(nèi)核就是這樣規(guī)定的,譯者將其譯為“晚到(的高優(yōu)先級(jí))異常”我將其名為“后來(lái)居上”中斷。
中斷延遲時(shí)間:從檢測(cè)到中斷,到執(zhí)行中斷服務(wù)程序的第一條指令,其間所流逝的時(shí)間。
書中云:如果存儲(chǔ)系統(tǒng)足夠快,入棧與取指令可以分別進(jìn)行,且中斷可以即刻得到響應(yīng)不被搶占,那么所耗費(fèi)的時(shí)間就是固定的12個(gè)周期(滿足硬實(shí)時(shí)要求的確定性)。如果多級(jí)嵌套中斷響應(yīng),算上咬尾中斷省去的出入棧時(shí)間,每個(gè)中斷可減少至6個(gè)周期。
最后再說(shuō)說(shuō)異常即fault,內(nèi)核活動(dòng)層面的東西,這個(gè)本應(yīng)是需要大書特書的東西,尤其是在調(diào)試程序的時(shí)候找bug上,是體現(xiàn)一個(gè)人技能水平的很重要的方面,但是限于時(shí)間與研究深度,暫時(shí)不深究了,
就一句話吧:運(yùn)行時(shí)出現(xiàn)的系統(tǒng)錯(cuò)誤有時(shí)候不是編程上的語(yǔ)法錯(cuò)誤,如果不了解內(nèi)核架構(gòu)和一些使用準(zhǔn)則,是很難發(fā)現(xiàn)bug在哪里,這就需要追溯到底是程序運(yùn)行到哪里出了問(wèn)題,導(dǎo)致內(nèi)核運(yùn)行出現(xiàn)了錯(cuò)誤,得益于CM3完備的調(diào)試架構(gòu),很多fault的產(chǎn)生都會(huì)被監(jiān)測(cè)到,并記錄在對(duì)應(yīng)的寄存器中,按圖索驥就知道問(wèn)題出在哪里,是哪條指令導(dǎo)致的,借此針對(duì)性的自查、分析、修改。
下面將結(jié)合上面的內(nèi)核架構(gòu)以及內(nèi)核運(yùn)行機(jī)制,針對(duì)具體的基于cortex—M4內(nèi)核(M4比M3內(nèi)核多了DSP與FPU)的STM32F407芯片,進(jìn)行硬件資源的對(duì)比。
評(píng)論