STM32外設(shè)庫文件分析(V3.5)
1._htmresc 里面有兩個(gè)logo,沒用,刪除。
2.Release_Notes.html 發(fā)行版本,可以看到各個(gè)版本的發(fā)行時(shí)間,修改內(nèi)容。
3.Utilities 里面是一些測試C文件,評(píng)估使用。
4.stm32f10x_stdperiph_lib_um.chm 幫助文件。
5.Project 文件夾有個(gè)模版和一個(gè)例程。以工程模式提供。
6.Libraries 文件夾下面包括兩個(gè)文件夾:
CMSIS Cortex Microcontroller Software Interface Standard
CM3
CoreSupport:core_cm3.c core_cm3.h
DeviceSupport
ST
STM32F10x:stm32f10x.h,system_stm32f10x.c,system_stm32f10x.h startup
arm:啟動(dòng)文件
Documentation:Cortex Microcontroller Software Interface Standard 發(fā)行版本記錄
STM32F10x_StdPeriph_Driver
根據(jù)需要和開發(fā)環(huán)境對文件進(jìn)行了一些精簡,精簡后的內(nèi)容:
CMSIS Cortex Microcontroller Software Interface Standard
CoreSupport
Core_cm3.c:
STM32從3.0庫開始引入了CMSIS,CMSIS是Cortex微控制器軟件接口標(biāo)準(zhǔn)(Cortex MicroController Software Interface Standard)的縮寫,
這個(gè)是ARM定制的一個(gè)用于Cortex-M系列的一個(gè)標(biāo)準(zhǔn),主要是為了提供通用api接口來訪問內(nèi)核和一些片上外設(shè),提高代碼的可移植性。
CMSIS有三個(gè)層:
核內(nèi)外設(shè)訪問層 Core Peripheral Access Layer(CPAL),
中間件訪問層 Middleware Access Layer(MWAL),
設(shè)備訪問層 Device Peripheral Access Layer(DPAL)。
CPAL用于訪問內(nèi)核的寄存器和組件,如NVIC,調(diào)試系統(tǒng)等。該層是由ARM實(shí)現(xiàn)的。
MWAL用于對中間件的訪問,現(xiàn)在該層還未實(shí)現(xiàn)。(也不知道所謂的中間層是什么東西)。
DPAL用于定義一些硬件寄存器的地址和一些外設(shè)訪問函數(shù),由芯片制造商實(shí)現(xiàn)。
CPAL層的實(shí)現(xiàn)就是Core_cm3.c文件,DPAL層的實(shí)現(xiàn)就是system_stm32f10x.c文件(似乎還應(yīng)該加上外設(shè)的函數(shù)庫)。
接下來就來了解一下Core_cm3.c里面有什么東東:
首先是匯編關(guān)鍵字__ASM和__INLINE的宏定義,支持不同的編譯器。由于使用的是Keil,所以就只看第一種,__CC_ARM。
這里面的函數(shù)調(diào)用都只符合ARM過程調(diào)用標(biāo)準(zhǔn)的,如R0到R3用作參數(shù)和返回值傳遞,這也是這里面唯一用到的。
此外,在Keil中使用了__asm關(guān)鍵字后,編譯器不會(huì)為函數(shù)增加返回指令,所以需要自己編寫返回命令,也就是每個(gè)函數(shù)后面的 bx lr。
1. __ASM uint32_t __get_PSP(void):獲取進(jìn)程堆棧指針PSP。
2. __ASM void __set_PSP(uint32_t topOfProcStack):設(shè)置PSP。
3. __ASM uint32_t __get_MSP(void):獲取主堆棧指針MSP。
4. __ASM void __set_MSP(uint32_t mainStackPointer):設(shè)置MSP。
5. __ASM uint32_t __REV16(uint16_t value):反轉(zhuǎn)半字中字節(jié)順序,如0xABCD反轉(zhuǎn)后得到0xCDAB。
6. __ASM int32_t __REVSH(int16_t value):反轉(zhuǎn)字節(jié)順序,并做符號(hào)拓展。
就是在__REV16函數(shù)得到的結(jié)果上再進(jìn)行一次符號(hào)拓展。這兩個(gè)函數(shù)主要是方便進(jìn)行大小端的切換。
7. __ASM void __CLREX(void):清除由LDREX指令造成的互斥鎖。LDREX和STREX是Cortex用來實(shí)現(xiàn)互斥訪問,
保護(hù)臨界資源的指令,LDREX執(zhí)行后,只有離它最近的一條存儲(chǔ)指令(STR,STREX)才能執(zhí)行,其他的存儲(chǔ)指令都會(huì)被駁回,
而CLREX就是用于清除互斥訪問狀態(tài)的標(biāo)記。
8. __ASM uint32_t __get_BASEPRI(void):獲取BASEPRI寄存器的值,
優(yōu)先級(jí)號(hào)高于該寄存器的中斷都會(huì)被屏蔽(優(yōu)先級(jí)號(hào)越大,優(yōu)先級(jí)越低),為零時(shí)不屏蔽任何中斷。
9. __ASM void __set_BASEPRI(uint32_t basePri):設(shè)置BASEPRI的值。
10. __ASM uint32_t __get_PRIMASK(void):PRIMASK是一個(gè)只有一位的寄存器,置位時(shí)屏蔽絕大部分的異常中斷,
只剩下NMI和HardFault可以響應(yīng)。
11. __ASM void __set_PRIMASK(uint32_t priMask):設(shè)置PRIMASK的值。
12. __ASM uint32_t __get_FAULTMASK(void):FAULTMASK也是一個(gè)只有一位的寄存器,為1時(shí)只有NMI才能響應(yīng),
其他異常與中斷全部被屏蔽。
13. __ASM void __set_FAULTMASK(uint32_t faultMask):設(shè)置FAULTMASK的值。
14. __ASM uint32_t __get_CONTROL(void):獲取CONTROL的值。寄存器CONTROL只有兩位。
CONTROL[0]選擇特權(quán)級(jí)別,0為特權(quán)級(jí),1為敵用戶級(jí)。CONTROL[1]用于選擇堆棧指針,0為MSP,1為PSP。
15. __ASM void __set_CONTROL(uint32_t control):設(shè)置CONTROL寄存器的值。
BASEPRI,PRIMASK,F(xiàn)AULTMASK,CONTROL都只能在特權(quán)模式下被修改。
C++的關(guān)鍵字 asm
微軟詳述:
__asm關(guān)鍵字啟動(dòng)內(nèi)聯(lián)匯編并且能寫在任何c/c++合法語句之處.它不能單獨(dú)出現(xiàn).
它必須接匯編指令、一組被大括號(hào)包含的指令或一對空括號(hào).術(shù)語“__asm 塊”在這里是任意一個(gè)指令或一組指令無論是否在括號(hào)內(nèi)。
以下代碼片段是在括號(hào)內(nèi)的一個(gè)簡單的__asm塊。
__asm
{
mov al, 2
mov dx, 0xD007
out al, dx
}
另一種方法是,你可以在每個(gè)匯編指令前放置__asm
__asm mov al, 2
__asm mov dx, 0xD007
__asm out al, dx
因?yàn)開_asm關(guān)鍵字是一個(gè)語句分隔符,你也可以將匯編指令放在同一行:
__asm mov al, 2 __asm mov dx, 0xD007 __asm out al, dx
以上三個(gè)的例子產(chǎn)生相同的代碼,但是第一種風(fēng)格(把__asm塊用括號(hào)括起來)有一些優(yōu)勢。
括號(hào)可以清晰的將C或C++代碼和匯編代碼分開,并且避免了不必要的重復(fù)__asm關(guān)鍵字。括號(hào)也能避免模糊性。
如果你想在__asm塊的同一行放置一個(gè)C或C++語句,你必須將塊用括號(hào)括起來。
沒有括號(hào),編譯器不能告訴匯編代碼在哪里停止而C或C++代碼在哪里開始。
最后,因?yàn)樵诶ㄌ?hào)的文字有和原始MASM一樣的格式,你能輕松的從一個(gè)已有的MASM源文件里剪切和黏貼文字到文件來。
不同于C和C++的括號(hào),包含__asm塊的括號(hào)對變量的作用域并沒有效果。你也能嵌套__asm塊,嵌套對變量作用域也沒有效果。
core_cm3.h:里面包含了一些內(nèi)聯(lián)函數(shù),數(shù)據(jù)結(jié)構(gòu),這些數(shù)據(jù)結(jié)構(gòu)都是核心的外設(shè)數(shù)據(jù)結(jié)構(gòu),大概包括:NVIC,SCB,ITM,CoreDebug,SysTick.
對以上設(shè)備進(jìn)行設(shè)置的函數(shù)也在這個(gè)頭文件里,以靜態(tài)內(nèi)聯(lián)函數(shù)的形式出現(xiàn),例如 static __INLINE uint32_t NVIC_GetPriority(IRQn_Type IRQn),
其中,__INLINE 是__inline 的替代。 靜態(tài)函數(shù) static 聲明。
Core_cm3.c 文件中定義的函數(shù)聲明也在這個(gè)文件中。
invlude包含指令不僅僅限于.h頭文件,可以包含任何編譯器能識(shí)別的C/C++代碼文件,包括.c,.hpp,.cpp,.hxx,.cxx等,甚至.txt,.abc等等都可以。
預(yù)處理器發(fā)現(xiàn) #include 指令后,就會(huì)尋找后跟的文件名并把這個(gè)文件的內(nèi)容包含到當(dāng)前文件中。
被包含文件中的文本將替換源代碼文件中的#include 指令,
就像你把被包含文件中的全部內(nèi)容鍵入到源文件中的這個(gè)位置一樣。
DeviceSupport
stm32f10x.h:
新版的固件庫V3.0以上 main等源文件中不再直接包含stm32f10x_conf.h,
而是stm32f10x.h,stm32f10x.h則定義了啟動(dòng)設(shè)置,以及所有寄存器宏定義,
此文件中需要注意的有:
1、device選擇
#if !defined (STM32F10X_LD) && !defined (STM32F10X_LD_VL) && !defined (STM32F10X_MD)
&& !defined (STM32F10X_MD_VL)&& !defined (STM32F10X_HD) && !defined (STM32F10X_HD_VL)
&& !defined (STM32F10X_XL) && !defined (STM32F10X_CL)
/* #define STM32F10X_LD */ /*!< STM32F10X_LD: STM32 Low density devices */
/* #define STM32F10X_LD_VL */ /*!< STM32F10X_LD_VL: STM32 Low density Value Line devices */
/* #define STM32F10X_MD */ /*!< STM32F10X_MD: STM32 Medium density devices */
/* #define STM32F10X_MD_VL */ /*!< STM32F10X_MD_VL: STM32 Medium density Value Line devices */
/* #define STM32F10X_HD */ /*!< STM32F10X_HD: STM32 High density devices */
/* #define STM32F10X_HD_VL */ /*!< STM32F10X_HD_VL: STM32 High density value line devices */
/* #define STM32F10X_XL */ /*!< STM32F10X_XL: STM32 XL-density devices */
/* #define STM32F10X_CL */ /*!< STM32F10X_CL: STM32 Connectivity line devices */
#endif
#if !defined (STM32F10X_LD) && !defined (STM32F10X_LD_VL)
&& !defined (STM32F10X_MD) && !defined (STM32F10X_MD_VL)
&& !defined (STM32F10X_HD) && !defined (STM32F10X_HD_VL)
&& !defined (STM32F10X_XL) && !defined (STM32F10X_CL)
#error "Please select first the target STM32F10x device used in your application (in stm32f10x.h file)"
#endif
如果都沒有定義,編譯器會(huì)報(bào)錯(cuò)。
2、外設(shè)宏定義USE_STDPERIPH_DRIVER
#if !defined USE_STDPERIPH_DRIVER
#endif
注意stm32f10x.h文件的后面有這樣的代碼,大概8300行左右:
#ifdef USE_STDPERIPH_DRIVER
#include "stm32f10x_conf.h"
#endif
stm32f10x_conf.h中包含了所有外設(shè)的頭文件,因此任意源文件只要包含了stm32f10x.h,就可以在源文件調(diào)用任意外設(shè)的函數(shù)。
3、外部時(shí)鐘頻率選擇
#if !defined HSE_VALUE
#ifdef STM32F10X_CL
#define HSE_VALUE ((uint32_t)25000000)
#else
#define HSE_VALUE ((uint32_t)8000000)
#endif
#endif
注意STM32F10X_CL,STM32F10X_CL是stm32f105 和stm32f107 互聯(lián)型的device,
用到此器件外部要選用25MHz的晶體,此處默認(rèn)的外部8MHz的晶體
4.stm32f10x.h包含了這些頭文件,include"stm32f10x.h",就不用包含下面這些了。
#include "core_cm3.h"
#include "system_stm32f10x.h"
#include
system_stm32f10x.c:
這個(gè)文件中包含系統(tǒng)上電復(fù)位之后時(shí)鐘設(shè)置要調(diào)用的函數(shù):
SystemInit()系統(tǒng)初始化,系統(tǒng)上電復(fù)位,main()在啟動(dòng)其它分支程序以前調(diào)用的函數(shù)。
SetSysClock(),被SystemInit()函數(shù)調(diào)用,設(shè)置系統(tǒng)時(shí)鐘頻率,根據(jù)宏定義選擇系統(tǒng)運(yùn)行的時(shí)鐘頻率。
SetSysClockTo24
SetSysClockTo36
SetSysClockTo48
SetSysClockTo56
SetSysClockTo72
SetSysClockToHSE
system_stm32f10x.h 源文件函數(shù)聲明的頭文件。
startup文件夾包含各個(gè)系列的啟動(dòng)代碼,用戶應(yīng)該根據(jù)自己的芯片類型來選擇啟動(dòng)代碼。
STM32F10x_StdPeriph_Driver
inc:頭文件沒什么好說的了,一個(gè)頭文件對用一個(gè)源文件,包括函數(shù),數(shù)據(jù)結(jié)構(gòu)的的一些聲明
src:這一層就是Device Peripheral Access Layer(DPAL)了,看看名字就知道是關(guān)于哪個(gè)設(shè)備的,沒什么
說的。唯一有一個(gè)例外就是misc.c文件,STM32 V3.5版本的庫函數(shù)中沒有原來版本中單獨(dú)對于NVIC(中斷向量嵌套)的外設(shè)驅(qū)動(dòng),
把NVIC的外設(shè)驅(qū)動(dòng)放在了misc.c中,實(shí)際上是代替原來的stm32f10x_nvic.c.
評(píng)論