以下來自:https://blog.csdn.net/guosir_/article/details/78627980
CMSIS是Cortex微控制器軟件接口標准(CortexMicroController Software Interface Standard)的縮寫,這個是ARM定制的一個用於Cortex-M系列的一個標准,主要是為了提供通用api接口來訪問內核和一些片上外設,提高代碼的可移植性。
CMSIS有三個層:核內外設訪問層CorePeripheral Access Layer(CPAL),中間件訪問層Middleware Access Layer(MWAL),設備訪問層(DevicePeripheral 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. __ASMuint32_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_tpriMask):設置PRIMASK的值。
12. __ASM uint32_t __get_FAULTMASK(void):FAULTMASK也是一個只有一位的寄存器,為1時只有NMI才能響應,其他異常與中斷全部被屏蔽。
13. __ASM void __set_FAULTMASK(uint32_tfaultMask):設置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_tcontrol):設置CONTROL寄存器的值。
BASEPRI,PRIMASK,FAULTMASK,CONTROL都只能在特權模式下被修改。
還有兩個文件,一個是Core_cmFunc.h 和 Core_cmInstr.h 這兩個文件是干嘛的,第一個文件是不同編譯器下的一些系統級的匯編函數,第二個文件是不同編譯器下的指令,我猜Keil公司這樣做是為了兼容不同的編譯器做設計的。把這兩個頭文件在Core_cm3.h頭文件里注釋掉也是可以的。說明這兩個頭文件對於keil開發環境是不需要的。
最后剩下Core_cm3.h文件了,這個文件是內核文件,就是定義了一些Cortex-M3的寄存器和一些函數,包括NVIC,MPU,SCB,SysTick,Debug寄存器。
最近在看LPC17XX系列的東東,發現這個文章說得有一些不對(上面是復制別人的),我用的是MDK4.14版本的開發環境。
說說我對這幾個文件的理解:
第一個:core_cm3.c是定義了一些兼容各個開發環境的一些內嵌匯編函數,都是關於M3內核寄存器操作的函數。其實這個函數在工程中根本沒有使用到,用的是Core_cmFunc.h的匯編函數,因為Core_cmFunc.h里的函數和core_cm3.c差不多是一樣的。不信自己建一個工程,調試一下就知道不是進去core_cm3.c,而是去Core_cmFunc.h執行的。所以core_cm3.h包含了Core_cmFunc.h 和 Core_cmInstr.h頭文件。
第二個:core_cm3.h定義了兼容各種編譯器的關於debug和NVIC的一些函數,這些函數在中斷設置中是很好用的。其中還有系統節拍器函數。我覺得core_cm3.h和core_cm3.c是一點關系都沒有的,雖然他們同名。擔不是頭文件和源文件的關系。當然這個文件一開頭還有內核寄存器的定義。下面才能用操作內核寄存器。
第三個:Core_cmInstr.h定義了很多內核指令的函數,這個應該不常用,先不管。
第四個:Core_cmFunc.h和core_cm3.c是非常相似的,大多數函數連函數名都一樣的,不知道為什么要這樣做,實際用函數是在Core_cmFunc.h里的函數,甚至把core_cm3.c從工程里刪除,都沒有問題的。但是屏蔽core_cm3.h里的Core_cmFunc.h 和 Core_cmInstr.h,就不行了。說明這個core_cm3.c是沒什么用的,起碼在Keil開發環境下是沒用的。
暫時研究到這里,后面開始實踐咯,就是使用幾個文件中的各種函數試試。
上面是轉載的,經過測試,上面說的不完全對,在老版本的core_cm3.c文件中,是有調用的很多匯編指令的,但是新版的文件就入上面所說的實際情況,core_cm3.c和core_cm3.h不相關,所以這個也是挺奇怪的。