2:在keil環(huán)境中,編譯器是通過***.sct分散加載文件來組織映像文件,分散加載文件中包含加載地址、運(yùn)行地址以及哪一個(gè)段的位置(啟動(dòng)代碼中的RESET代碼段就被描述放在特定的地址中);
LR_IROM1 0x08000000 0x00040000 { ; load region size_region
ER_IROM1 0x08000000 0x00040000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
RW_IRAM1 0x20000000 0x00010000 { ; RW data
.ANY (+RW +ZI)
}
}
3:M3的優(yōu)先級
M3的異常,包括系統(tǒng)異常(15個(gè)系統(tǒng)異常:復(fù)位、NMI、hardfault、SysTick等,編號從1~15,0表示沒有異常運(yùn)行)與外部中斷(總共240個(gè),編號從16~255,NVIC最多支持1~240個(gè)外部中斷IRQ,芯片具體支持多少個(gè)由芯片廠商設(shè)計(jì)),支持中斷嵌套,使得高優(yōu)先級的異?梢該屨嫉蛢(yōu)先級的中斷。
其中3個(gè)系統(tǒng)異常(復(fù)位、NMI、hardfault)有固定的優(yōu)先級且都是負(fù)數(shù)級優(yōu)先級,所以他們的優(yōu)先級高于其他的所有可編程的優(yōu)先級(非負(fù)),除這三個(gè)系統(tǒng)異常外,其他的異常與中斷的優(yōu)先級都是可以編程的。
因此M3擁有3個(gè)固定的高優(yōu)先級與最多256級可編程的優(yōu)先級。
M3所有可編程優(yōu)先級的異常(系統(tǒng)異常與外部中斷)都擁有一個(gè)對應(yīng)的8位的優(yōu)先級寄存器,且中斷優(yōu)先級的值(8位)又分為兩個(gè)域:搶占域與亞優(yōu)先(非搶占)域;高搶占域的異?梢該屨嫉蛽屨加虻漠惓#ㄟ@時(shí)不考慮亞優(yōu)先級誰高誰低),如果兩個(gè)異常搶占域相同,其中一個(gè)異常已在服務(wù)中,那此時(shí)不論另一中斷的亞優(yōu)先級是高或低都不能搶占它,而如果這兩個(gè)中斷同時(shí)出現(xiàn),那么系統(tǒng)會(huì)先響應(yīng)亞優(yōu)先級高的中斷;如果兩個(gè)異常優(yōu)先級完全相同,同時(shí)出現(xiàn)時(shí)則會(huì)優(yōu)先響應(yīng)異常編號小的那個(gè)異常。
重要規(guī)則:多個(gè)中斷源在它們的搶占式優(yōu)先級相同的情況下,子優(yōu)先級不論是否相同,如果某個(gè)中斷已經(jīng)在服務(wù)當(dāng)中,則其它中斷源都不能打斷它(可以末尾連鎖);只有搶占式優(yōu)先級高的中斷才可以打斷其它搶占式優(yōu)先級低的中斷。優(yōu)先級分組規(guī)定:亞優(yōu)先級至少1位,因此搶占式優(yōu)先級最多7位;
優(yōu)先級分組在AIRCR(應(yīng)用程序中斷與復(fù)位控制寄存器(0XE000_ED00))中的[10:8]PRIGROUP位域設(shè)置(芯片的標(biāo)準(zhǔn)庫函數(shù)中一般都會(huì)有相應(yīng)的這樣的設(shè)置函數(shù)給用戶調(diào)用:如
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
void NVIC_SystemHandlerPriorityConfig(u32 SystemHandler, u8 SystemHandlerPreemptionPriority, u8 SystemHandlerSubPriority)
具體的芯片支持的M3的優(yōu)先級分組情況不一樣,芯片在設(shè)計(jì)時(shí)已經(jīng)確定了它支持多個(gè)種分組,如我的STM32只支持0~4分組,這個(gè)具有要看芯片手冊(其實(shí)查看芯片提供的相關(guān)代碼就可以查出了),為了更好的支持代碼的跨平臺特性,優(yōu)先級是以MSB對齊的(這里的對齊,比如3位搶占式優(yōu)先級移植到另一款芯片變成2位,這時(shí)丟失的是最高位,如搶占式優(yōu)先級5會(huì)變成1);
4:《權(quán)威指南》第一章小結(jié)
ARM處理器支持的指令集:ARM(32位,對應(yīng)CPU的ARM狀態(tài))、Thumb(16,對應(yīng)CPU的Thumb狀態(tài))、Thumb2(32、16);
Thumb指令在功能上時(shí)ARM指令的一個(gè)子集,它的優(yōu)點(diǎn)是提高代碼密度;Thumb2是Thumb指令的超集(16和32位的指令共存);
Cortex M3使用的就是2003年盛產(chǎn)的Thumb2指令集,M3支持Thumb2指令的好處:1.支持絕大多數(shù)的傳統(tǒng)的Thumb指令,方便在只支持Thumb指令平臺上寫的代碼的移植;2.不用進(jìn)行處理器的狀態(tài)切換(在一些運(yùn)算復(fù)雜的地方需要Thumb<->ARM切換),提高效率。
5:《權(quán)威指南》第二章小結(jié)
CPU的寄存器:R0~R12(通用寄存器)、R13(M/P SP)、R14(LR)、R15(PC)、xPSR(程序狀態(tài)字寄存器)、PRIMASK/FAULTMASK/BASEPRI(中斷屏蔽寄存器)、CONTROL(控制寄存器)【最后三類為特殊功能寄存器,具體功能后面分析】
堆棧指針(R13)的最低兩位永遠(yuǎn)為0,因?yàn)槎褩J?字節(jié)對齊(ARM是32位處理器,各寄存器都是32位的);
M3支持兩種處理器的操作模式以及兩種特權(quán)操作;
操作模式:handler mode 、thread mode (異常時(shí)處理器處于handler mode ,其他時(shí)候是thread mode)
特權(quán)操作:特權(quán)級(復(fù)位后系統(tǒng)默認(rèn)、handler mode下總是特權(quán)級)、用戶級(非特權(quán)級);這是一種安全策略,特權(quán)級是可以訪問所有的存儲器(有MPU,要除去MPU規(guī)定的禁區(qū)),可執(zhí)行所有的指令【這是特權(quán)級與用戶級的區(qū)別所在,配上MPU,就可以對特權(quán)級訪問和用戶級訪問施加不同的限制】。
CONTROL[1]、CONTROL[0]只有在特權(quán)級模式下才允許寫(從用戶級到特權(quán)級的唯一路徑就是異常:觸發(fā)一個(gè)異常,處理器總是先切換到特權(quán)級,異常退出時(shí),返回先前的狀態(tài),也可通過LR手動(dòng)修改返回狀態(tài)),特權(quán)級的線程模式可通過修改CONTROL[0]=1進(jìn)入用戶模式,這樣就只能通過異常才能返回特權(quán)級;
Cortex M3 擁有4G的存儲空間,且對這4G的存儲空間進(jìn)行了粗線條的規(guī)劃:
0x0000_0000--0x1FFF_FFFF:代碼區(qū)。 0x2000_0000--0x3FFF_FFFF:用于片上靜態(tài)RAM。
0x4000_0000--0x5FFF_FFFF:片上外設(shè)空間。 0x6000_0000--0x9FFF_FFFF:擴(kuò)展外部存儲器。
0xA000_0000--0xDFFF_FFFF:擴(kuò)展片外外設(shè)。 0xE000_0000--0xFFFF_FFFF:系統(tǒng)控制空間(NVIC、SCB等)
處于最高地址的系統(tǒng)級存儲區(qū)包括NVIC、MPU、SCB、調(diào)試組件等,且所有這些控制模塊的寄存器地址是固定的,不隨芯片廠家的不同而發(fā)生改變,這樣就方便移植了。
MPU:MPU保護(hù)內(nèi)存是按region(區(qū))來管理的,當(dāng)檢測到訪問犯規(guī)時(shí),MPU會(huì)產(chǎn)生一個(gè)異常,進(jìn)入對應(yīng)的異常服務(wù)程序。最常見的MPU玩法是操作系統(tǒng)使用MPU來包含特權(quán)級代碼的數(shù)據(jù),包括操作系統(tǒng)本身的數(shù)據(jù)不被其他的用戶程序破壞。
MRS、MSR訪問特殊功能寄存器。
調(diào)試:M3不同于以往的ARM處理器,內(nèi)核本身不再含有JTAG接口,取而代之的是CPU提高的DAP“調(diào)試訪問接口”的總線接口,通過這個(gè)總線接口,可以訪問芯片的寄存器、系統(tǒng)存儲器等,甚至可以在內(nèi)核運(yùn)行時(shí)訪問,而對此總線接口的使用是通過一個(gè)調(diào)試端口(DP)設(shè)備完成,DP不屬于M3內(nèi)核,但它是在芯片內(nèi)部實(shí)現(xiàn)的。DP包括SWJ-DP(支持JTAG調(diào)試與串行線調(diào)試)、SW-DP(串行線調(diào)試),也可以使用JTAG-DP,具體使用哪一個(gè)由廠家選擇提供給用戶(通常為SWJ-DP); M3還掛載了一個(gè)ETM(嵌入式跟蹤宏單元),ETM不斷發(fā)出跟蹤信息,這些信息通過一個(gè)被稱為TPIU(跟蹤端口接口單元)的模塊送到內(nèi)核的外部,如果再芯片外使用“跟蹤信息分析儀”就可以捕捉TPIU的“已執(zhí)行指令信息”,送給調(diào)試PC機(jī)。
通過WFI(等待中斷指令)與WFE(等待事件指令),內(nèi)核可以進(jìn)入睡眠模式。
M3支持“位尋址帶”操作,支持非對齊的數(shù)據(jù)訪問。
6:《權(quán)威指南》第三章小結(jié)
M3中指令至少是半字對齊,所以讀取PC的值時(shí),PC的LSB總是讀回0,且PC的LSB位表示的是CPU所處的狀態(tài),1表示Thumb狀態(tài),0表示ARM狀態(tài),所以無論是在直接寫PC值還是使用分支指令,都必須保證加載到PC的數(shù)值是奇數(shù)(LSB=1),用以表示這是在Thumb狀態(tài)下執(zhí)行,若寫了0,則試圖轉(zhuǎn)入ARM狀態(tài),CM3將產(chǎn)生一個(gè)異常。
讀取PC值時(shí)獲得的數(shù)值是與CPU的流水線級數(shù)【M3的是三級:取指、譯碼、執(zhí)行】有關(guān)的,CM3在讀PC時(shí)返回的值是當(dāng)前指令的地址+4,PC(取指) = PC(執(zhí)行) + 4(16位的是兩個(gè)字節(jié),2*2)【這里出于對Thumb代碼兼容,Thumb2既有16位的指令也包含32位的指令】
【復(fù)位序列】在離開復(fù)位狀態(tài)后,CM3做的第一件事就是讀取下列兩個(gè)32位整數(shù)的值:
1:從地址0x0000_0000處取出MSP(默認(rèn)使用MSP)的初始值
2:從地址0x0000_0004處取出PC的初始值(這個(gè)值是復(fù)位向量,LSB必須是1)
這與傳統(tǒng)的ARM架構(gòu)以及絕大多數(shù)的單片機(jī)不同,傳統(tǒng)ARM架構(gòu)總是從0地址開始執(zhí)行第一條指令(0地址處一般總是一條跳轉(zhuǎn)指令),在CM3中,0地址處提供MSP的初始值,然后緊跟的是向量表(向量表在以后還可以被移到其他的位置),向量表中存放的是32位的服務(wù)程序的地址(我們通過工具查看這些地址值時(shí),他們的最低位都是1)
7:M3的堆棧大小如何設(shè)置?
我們可以通過查看0地址處的MSP初始值?梢灾老到y(tǒng)最開始使用的堆棧的大小,如:0x20004430(減去RAM的起始地址就可知道大小)。那怎么設(shè)置?
Stack_Size EQU 0x200【512個(gè)字節(jié)】
AREA STACK(段名), NOINIT, READWRITE(兩個(gè)屬性), ALIGN=3(對齊)
Stack
SPACE Stack_Size
AREA RESET, CODE, READONLY
THUMB
EXPORT __Vectors
__Vectors
DCD Stack + Stack_Size ; Top of Stack【堆棧是往下生長的滿棧,Stack是棧底】
DCD Reset_Handler
8:M3的fault分析
fault分為:總線fault、存儲器管理fault、用法fault、硬fault;
總線fault:當(dāng)AHB接口上正在傳送數(shù)據(jù)時(shí),如果回復(fù)了一個(gè)錯(cuò)誤信號(Error Response),則會(huì)產(chǎn)生總線fault,產(chǎn)生的場合可以是:
9:M3的SVC、PendSV
SVC(系統(tǒng)調(diào)用)【學(xué)linux時(shí),在帶操作系統(tǒng)的系統(tǒng)中,用戶空間系統(tǒng)調(diào)用(直接使用操作系統(tǒng)提供的接口函數(shù))與C庫調(diào)用,且C庫調(diào)用最后會(huì)使用系統(tǒng)提供的系統(tǒng)調(diào)用接口函數(shù)(也就變?yōu)榱讼到y(tǒng)調(diào)用),通過系統(tǒng)調(diào)用請求(通過系統(tǒng)調(diào)用號:對應(yīng)各個(gè)系統(tǒng)提供的對應(yīng)接口函數(shù))從用戶空間進(jìn)入內(nèi)核空間,C庫調(diào)用接口具有很好的跨平臺特性】
PendSV(可掛起的系統(tǒng)調(diào)用)
SVC異常 通過 執(zhí)行SVC指令來產(chǎn)生,如SVC 0X3 //0X3是系統(tǒng)調(diào)用號
不能再SVC服務(wù)例程中嵌套使用SVC指令(因?yàn)橥瑑?yōu)先級的異常不能搶占自身,都是系統(tǒng)調(diào)用異常),否則會(huì)產(chǎn)生一個(gè)用法fault;同樣也不能在NMI服務(wù)例程中使用SVC,否則會(huì)導(dǎo)致hardfault【因?yàn)閳?zhí)行SVC指令后,如因優(yōu)先級不比當(dāng)前正在處理的高,或是其他原因使之無法響應(yīng),則將造成hardfault】.
PendSV可以像普通的中斷一樣被掛起(不像SVC一樣會(huì)上訪hardfault),OS可以利用它緩期執(zhí)行一個(gè)異常,直到其他重要的任務(wù)完成后才執(zhí)行動(dòng)作,為了能讓其他很重要的任務(wù)優(yōu)先完成,PendSV的優(yōu)先級可以調(diào)到最低。
通過向PendSV掛起寄存器中寫1,可以手工掛起PendSV,掛起后,如果優(yōu)先級不夠高,則將緩期執(zhí)行。
PendSV的典型使用場合是上下文切換;