STM32固件庫的CMSIS的學習


STM32固件庫CMSIS簡析(摘自網絡2011-02)

 CMSIS軟件層次CMSIS可以分為多個軟件層次,分別由ARM公司、芯片供應商提供。

1、ARM Cortex™ 微控制器軟件接口標准(CMSIS:Cortex Microcontroller Software Interface Standard)

        是 Cortex-M 處理器系列的與供應商無關的硬件抽象層。 使用CMSIS,可以為處理器和外設實現一致且簡單的軟件接口,從而簡化軟件的重用、縮短微控制器新開發人員的學習過程,並縮短新設備的上市時間。軟件的創建被嵌入式行業公認為主要成本系數。通過在所有Cortex-M 芯片供應商產品中標准化軟件接口,這一成本會明顯降低,尤其是在創建新項目或將現有軟件遷移到新設備時。最新版本的CMSIS[2]為3.5。

2結構

CMSIS是ARM公司與多家不同的芯片和軟件供應商一起緊密合作定義的,提供了內核與外設、實時操作系統和中間設備之間的通用接口。
CMSIS軟件層次

CMSIS可以分為多個軟件層次,分別由ARM公司、芯片供應商提供。
其中ARM提供了下列部分,可用於多種編譯器:
● 內核設備訪問層:包含了用來訪問內核的寄存器設備的名稱定義,地址定義和助手函數。同時也為RTOS(實時操作系統)定義了獨立於微控制器的接口,該接口包括調試通道定義。
● 中間設備訪問層:為軟件提供了訪問外設的通用方法。芯片供應商應當修改中間設備訪問層,以適應中間設備組件用到的微控制器上的外設。目前中間設備訪問層仍處於開發過程中,本文不做詳述。 芯片供應商擴展下列軟件層:
● 微控制器外設訪問層:提供片上所有外設的定義。
● 外設的訪問函數(可選):為外設提供額外的助手函數。CMSIS為Cortex-Mx微控制器系統定義了:
● 訪問外設寄存器的通用方法和定義異常向量的通用方法。
● 內核設備的寄存器名稱和內核異常向量的名稱。
● 獨立於微控制器的RTOS接口,帶調試通道。
● 中間設備組件接口(TCP/IP協議棧,閃存文件系統)。


CMSIS包含的組件

1、外圍寄存器和中斷定義: 適用於設備寄存器和中斷的一致接口
2、內核外設函數:特定處理器功能和內核外設的訪問函數
3、DSP 庫:優化的信號處理算法,並為 SIMD 指令提供Cortex-M4 支持
4、系統視圖說明(SVD):描述設備外設和中斷的XML 文件。
該標准完全可擴展,可確保其適合於所有 Cortex-M處理器系列微控制器,從最小的8 KB 設備到具有復雜通信外設(如以太網或USB)的設備。(內核外設函數的內存要求少於1 KB 代碼,少於10 字節RAM)。


基於CMSIS應用程序的基本結構CMSIS-外設訪問層的文件

基於CMSIS應用程序的基本結構[3]

獨立於編譯器的文件:
● Cortex-M3內核及其設備文件(core_cm3.h + core_cm3.c)
─ 訪問Cortex-M3內核及其設備:NVIC,SysTick等
─ 訪問Cortex-M3的CPU寄存器和內核外設的函數
● 微控制器專用頭文件(device.h)
─ 指定中斷號碼(與啟動文件一致)
─ 外設寄存器定義(寄存器的基地址和布局)
─ 控制微控制器其他特有的功能的函數(可選)
● 微控制器專用系統文件(system_device.c)
─ 函數SystemInit,用來初始化微控制器
─ 函數Sysem_ExtMemCtl,用來配置外部存儲器控制器。它位於文件
startup_stm32f10x_xx.s /.c,在跳轉到main前調用
─SystemFrequncy,該值代表系統時鍾頻率
─ 微控制器的其他功能(可選)
編譯器供應商+微控制器專用啟動文件
● 編譯器啟動代碼(匯編或者C)(startup_device.s)
─ 微控制器專用的中斷處理程序列表(與頭文件一致)
─ 弱定義(Weak)的中斷處理程序默認函數(可以被用戶代碼覆蓋)

CMSIS軟件包詳細目錄

下載的CMSIS軟件包含有Cortex M3核的支持文件以及基於Cortex M3核處理器的啟動代碼和庫引導文件。

使用步驟以STM32F10XX序列處理為例,介紹CMSIS的使用步驟。

1、從ST官方網站下載3.0以上版本的標准外設庫。
2、基於開發軟件新建工程,建立相應的文件目錄,注意詢問是否加入啟動文件時,選擇“否”。
3、根據所選芯片,把Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup\arm中的啟動代碼加到工程中。
4、根據處理器FLASH容量的大小,選擇啟動代碼。stm32f10x.h 的66-73 行表明了啟動代碼的類型。例如STM32F10X_HD 行表示大容量的,如果不需要直接注釋掉即可。
5、選擇是否啟用標准外設庫。stm32f10x.h的105行的USE_STDPERIPH_DRIVER用於確定是否啟用,如果不啟用直接注釋掉。
6、確定處理器的頻率。system_stm32f10x.c的110-115行用於確定處理器的頻率,注釋掉不需要的即可。例如處理器的頻率為是36MHz,注釋SYSCLK_FREQ_72MHz,去掉SYSCLK_FREQ_36MHz注釋。

 

STM32的V3.5.0庫,內有CMSIS的文件夾為arm Cortex微控制器軟件接口標准,現將實際工作中應用作一個簡要分析:

1.選擇啟動文件:

根據自己所用的芯片的型號,選擇正確的啟動文件。這個根據數據手冊上的划分選擇STM32F107系列的處理器,我們就選擇startup_stm32f10x_hd.s。選擇STM32F103VBT6,就選擇startup_stm32f10x_md.s,在這個文件里,首選要定義自已的堆和棧的大小,這個根據自已的需要確定。文件中已經定義好了中斷向量的位置及堆和棧的初始化操作。

Reset_Handler    PROC 

EXPORT  Reset_Handler     [WEAK] 

IMPORT  __main

IMPORT  SystemInit 

LDR     R0, =SystemInit

BLX     R0

LDR     R0, =__main 

BX      R0 

END     

下面對上面的一段匯編進行解釋,相同的就省略解釋。

              Reset_Handler    PROC   //0x0復位入口

             EXPORT  Reset_Handler     [WEAK] // EXPORT或者GLOBAL:制定某標號代表的程序可為其它文件調用,即是聲明一個全局標號,[WEAK]選項聲明其他的同名標號優先於該標號被引用。聲明一個可全局引用的標號Reset_Handler
             IMPORT  __main  //通知編譯器當前文件要引用標號__main,但__main在其他源文件中定義
             IMPORT  SystemInit //通知編譯器當前文件要引用標號SystemInit ,但SystemInit 在其他源文件中定義

                 LDR     R0, =SystemInit //
                 BLX     R0              //BLX指令進行ARM/Thumb狀態切換並且保存返回地址的轉移指令,放回地址(BLX指令指向下一條指令地址)保存鏈接寄存器R14
                 LDR     R0, =__main   //向通用寄存器傳輸任意不大於232的立即數,即__main,立即數用=32位立即數,等同於MOV R0,#_main
                 BX      R0             //BX指令進行ARM/Thumb狀態切換但不保存返回地址的轉移指令,R0為包含目標指令絕對地址的寄存器
                 END                   //結束

從上面這段文字中,可以看到,在系統復位后,先執行SystemInit(),再進入main()函數。SystemInit()在文件system_stm32f10x.c中定義,稍后再說。

 

    2.stm32f10x.h:這個頭文件包含了STM32的大部份定義:

       a.定義芯片的類型,如#define STM32F10x_MD

       b.定義是否包含標准庫,#define USE_STDPERIPH_DRIVER

       c.定義外部振盪器頻率,#define HSE_VALUE

       上面三個定義,建議在main.c文件中剛開始就定義好,或者是在編譯器選項中定義好,這樣就可以不修改這個文件了。

        d.采用枚舉的方式定義中斷號。定義中斷號在stm32f10x_it.c    stm32f10x_it.h

        e.包含 core_cm3.hsystem_stm32f10x.h        (#include "core_cm3.h" #include "system_stm32f10x.h" #include <stdint.h> )

        f.定義數據類型,例如:typedef uint32_t  u32此外還定義了FlagStatus,ITStatus及ErrorStatus等。u8s8等為了兼容以前的庫所定義的數據,建議程序中用標准的uint8_t這樣的類型。此外還定義了boolFlagStatusalStatusErrorStatus

        g.定義外設結構體,地址及用到的數據常量。 

 

        h.包含stm32f10x_conf.h來配置外設。#ifdef USE_STDPERIPH_DRIVER     #include "stm32f10x_conf.h"       #endif

        i.定義位操作的宏

 

   3.system_stm32f10x.h和system_stm32f10x.c,這兩個文件中:

       a.定義一個全局變量 extern uint32_t SystemCoreClock: 系統時鍾頻率與你選擇有關

 

       b.SystemInit():這個函數就是啟動文件中調用的函數

        (1) system_stm32f10x.c的開始部份,選擇相關的系統時鍾頻率,

             如#define  SYSCLK_FREQ_24MHz  24000000

        (2) 通過SystemInit()函數,就將SYSCLK = HCLK = PCLK1=PCLK2=PLL輸出24MHz注意:這個頻率為HSE8MHz時為條件,如果HSE不為8MHz或用HSI時,就會有問題。

       c.SystemCoreClockUpdate():更新SystemCoreClock的值,與系統頻率一致。

       可能看到,這個文件中的RCC設置很有局限性,所以在程序中,可以不用它,而用標准庫存中的stm32f10x_rcc中的函數進行設置。

 

  4.stm32f10x_conf.h

     a.配置需要的標准外設庫,需要用到的外設,把相應頭文件包含進去就可以。

     b.定義assert_Param的模式,選擇#define USE_FULL_ASSERT時,斷言輸出問題所在的位置,在調試時很有用,在正式版本時,把它注釋掉即可。

 

   5.core_cm3:與CM3內核相關的操作,重點如下:

      a. MDK中,開總中斷:__enable_irq();   關總中斷:__disable_irq();

      b. 中斷處理程序:

          (1) NVIC_SetPriorityGrouping(uint32_t PriorityGroup);

          設置中斷組,這里的值只能是0~7,在STM32中,只能用8位中的前4位來設置組,可以分為兩部份:搶占優先級和亞優先級。這個數值就是亞優先級開始的位。它前面的位是搶占式優先級的位。例如:NVIC_SetPriorityGrouping(5),那么D7D6表示搶占式優先級(0~3),D5D4表示亞優先級(0~3)。優先級數值越小,優先級越高。搶占式優先級高的中斷可以打斷搶占式優先級低的中斷。搶占式優先級相同,亞優先級不同的兩個中斷,如果同時到來,先執行亞優先級高的中斷,再執行亞優先級低的中斷,但不能打斷。

可以理解為搶占式多任務。

         (2) NVIC_EnableIRQ(IRQn_Type IRQn);   使能一個中斷EnableIRQ

         (3) NVIC_DisableIRQ(IRQn_Type IRQn);   禁止一個中斷DisableIRQ

         (4) NVIC_SetPriority(IRQn_Type IRQn,uint32 priority); 設置一個中斷的優先級

         (5)NVIC_EncodePriority(uint32_t PriorityGroup,uint32_t PreemptPriority,uint32_t SubPriority);

         (4)(5)通常一起使用,這樣設置更直觀,例如要將外部中斷0設為搶占式優先級為0,亞優先級為2,則:

         NVIC_SetPriority(EXTI0_IRQn,NVIC_EncodePriority(5,0,2));

         注意PriorityGroup的參數應與(1)中設置的一致。

         除了這種方式設置中斷外,也可以使用標准庫中的misc中的中斷設置函數來操作。
     c. SysTick_Config(uint32_t ticks):設置系統嘀嗒時鍾並使能中斷

         在STM32中與CM3內核描述不太一樣,這個時鍾源有兩個選擇:AHB/8AHB,在該函數中是選擇了HCLK(SysTick_CTRL_CLKSOURCE_Msk),所以定時時間=ticks / HCLK,當要定時10ms,而HCLK24MHz時,ticks = 10000 * 24 = 240000

         如果需要選擇HCLK/8,可以直接修改這個函數,或在這個函數后跟隨misc中的SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource)來設置。

      d.NVIC_SystemReset():復位芯片。

 

  6. stm32f10x_it中斷實現,在這里編寫相應的中斷服務函數。

  7.還需要注意的一點是:進入main函數后,除了設置嘀嗒時鍾和中斷外,在操作各外設之前,需要調用:

RCC_AHBPeriphClockCmd(),RCC_APB1PeriphClockCmd(),RCC_APB2PeriphClockCmd(),啟動相應的時鍾,否則外設就不能正常工作。

 

在這里簡單介紹一下NVIC

NVIC嵌套向量中斷控制器 Nested Vectored Interrupt Controller

系統中斷管理。——管理系統內部的中斷,負責打開和關閉中斷。
基礎應用1,中斷的初始化函數,包括設置中斷向量表位置,和開啟所需的中斷兩部分。所有程序中必須的。
用法:void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;//中斷管理恢復默認參數
#ifdef  VECT_TAB_RAM  
//如果C/C++ Compiler\Preprocessor\Defined symbols中的定義了VECT_TAB_RAM(見程序庫更改內容的表格)
NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); //則在RAM調試
#else        //如果沒有定義VECT_TAB_RAM
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);//則在Flash里調試
#endif        //結束判斷語句
//以下為中斷的開啟過程,不是所有程序必須的。
//NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 
//設置NVIC優先級分組,方式。
//注:一共16個優先級,分為搶占式和響應式。兩種優先級所占的數量由此代碼確定,NVIC_PriorityGroup_x可以是01、 234,分別代表搶占優先級有124816個和響應優先級有168421個。規定兩種優先級的數量后,所有的中斷級別必須在其中選擇,搶占級別高的會打斷其他中斷優先執行,而響應級別高的會在其他中斷執行完優先執行。
//NVIC_InitStructure.NVIC_IRQChannel = 中斷通道名;
//開中斷,中斷名稱見函數庫
//NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
//搶占優先級
//NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; 
//響應優先級
//NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//啟動此通道的中斷
//NVIC_Init(&NVIC_InitStructure);     //中斷初始化
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM