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