STM32從3.0庫開始引入了CMSIS,CMSIS是Cortex微控制器軟件接口標准(Cortex MicroController Software Interface Standard)的縮寫,這個是ARM定制的一個用於Cortex-M系列的一個標准,主要是為了提供通用api接口來訪問內核和一些片上外設,提高代碼的可移植性。
CMSIS有三個層:核內外設訪問層Core Peripheral Access Layer(CPAL),中間件訪問層Middleware Access Layer(MWAL),設備訪問層(Device Peripheral Access Layer)。
CPAL用於訪問內核的寄存器和組件,如NVIC,調試系統等。該層是由ARM實現的。
MWAL用於對中間件的訪問,現在該層還未實現。(也不知道所謂的中間件是什么東西)。
DPAL用於定義一些硬件寄存器的地址和一些外設訪問函數,由芯片制造商實現。
CPAL層的實現就是Core_cm3.c文件,DPAL層的實現就是system_stm32f10x.c文件(似乎還應該加上外設的函數庫)。
接下來就來了解一下Core_cm3.c里面有什么東東:
首先是匯編關鍵字__ASM和__INLINE的宏定義,支持不同的編譯器。由於使用的是Keil,所以就只看第一種,__CC_ARM。
這里面的函數調用都只符合ARM過程調用標准的,如R0到R3用作參數和返回值傳遞,這也是這里面唯一用到的。
此外,在Keil中使用了__asm關鍵字后,編譯器不會為函數增加返回指令,所以需要自己編寫返回命令,也就是每個函數后面的 bx lr。
1. __ASM uint32_t __get_PSP(void):獲取進程堆棧指針PSP。
2. __ASM void __set_PSP(uint32_t topOfProcStack):設置PSP。
3. __ASM uint32_t __get_MSP(void):獲取主堆棧指針MSP。
4. __ASM void __set_MSP(uint32_t mainStackPointer):設置MSP。
5. __ASM uint32_t __REV16(uint16_t value):反轉半字中字節順序,如0xABCD反轉后得到0xCDAB。
6. __ASM int32_t __REVSH(int16_t value):反轉字節順序,並做符號拓展。就是在__REV16函數得到的結果上再進行一次符號拓展。這兩個函數主要是方便進行大小端的切換。
7. __ASM void __CLREX(void):清除由LDREX指令造成的互斥鎖。LDREX和STREX是Cortex用來實現互斥訪問,保護臨界資源的指令,LDREX執行后,只有離它最近的一條存儲指令(STR,STREX)才能執行,其他的存儲指令都會被駁回,而CLREX就是用於清除互斥訪問狀態的標記。
8. __ASM uint32_t __get_BASEPRI(void):獲取BASEPRI寄存器的值,優先級號高於該寄存器的中斷都會被屏蔽(優先級號越大,優先級越低),為零時不屏蔽任何中斷。
9. __ASM void __set_BASEPRI(uint32_t basePri):設置BASEPRI的值。
10. __ASM uint32_t __get_PRIMASK(void):PRIMASK是一個只有一位的寄存器,置位時屏蔽絕大部分的異常中斷,只剩下NMI和HardFault可以響應。
11. __ASM void __set_PRIMASK(uint32_t priMask):設置PRIMASK的值。
12. __ASM uint32_t __get_FAULTMASK(void):FAULTMASK也是一個只有一位的寄存器,為1時只有NMI才能響應,其他異常與中斷全部被屏蔽。
13. __ASM void __set_FAULTMASK(uint32_t faultMask):設置FAULTMASK的值。
14. __ASM uint32_t __get_CONTROL(void):獲取CONTROL的值。寄存器CONTROL只有兩位。CONTROL[0]選擇特權級別,0為特權級,1為敵用戶級。CONTROL[1]用於選擇堆棧指針,0為MSP,1為PSP。
15. __ASM void __set_CONTROL(uint32_t control):設置CONTROL寄存器的值。
BASEPRI,PRIMASK,FAULTMASK,CONTROL都只能在特權模式下被修改。