官术网_书友最值得收藏!

第3章 LPC1700程序設(shè)計(jì)基礎(chǔ)

本章內(nèi)容是LPC17XX軟件設(shè)計(jì)的基礎(chǔ)。本章主要介紹了MDK開(kāi)發(fā)環(huán)境、ARM公司的CMSIS,以及NXP公司的固件庫(kù)。在MDK部分,主要介紹了工程建立、編譯、調(diào)試等操作。CMSIS作為ARM的軟件設(shè)計(jì)標(biāo)準(zhǔn),對(duì)ARM的軟件設(shè)計(jì)做了各項(xiàng)規(guī)定。NXP公司對(duì)CMSIS做了一些具體實(shí)現(xiàn),并在此基礎(chǔ)上定義了各種針對(duì)LPC17XX外設(shè)的操作函數(shù)與定義。

3.1 RealView MDK開(kāi)發(fā)環(huán)境

RealView MDK開(kāi)發(fā)工具源自德國(guó)的Keil公司,被全球超過(guò)10萬(wàn)的嵌入式開(kāi)發(fā)工程師驗(yàn)證和使用,是ARM公司目前最新推出的針對(duì)各種嵌入式處理器的軟件開(kāi)發(fā)工具。RealView MDK集成了業(yè)內(nèi)最領(lǐng)先的技術(shù),包括μVision集成開(kāi)發(fā)環(huán)境與RealView編譯器。它具有支持ARM7、ARM9和最新的Cortex-M3核處理器,自動(dòng)配置啟動(dòng)代碼,集成Flash燒寫(xiě)模塊,強(qiáng)大的Simulation設(shè)備模擬、性能分析等功能。與ARM之前的工具包ADS等相比,RealView編譯器的最新版本可將性能改善超過(guò)20%。

3.1.1 RealView MDK開(kāi)發(fā)環(huán)境簡(jiǎn)介

RealView MDK開(kāi)發(fā)環(huán)境提供了啟動(dòng)代碼生成向?qū)АS捎趩?dòng)代碼和系統(tǒng)硬件結(jié)合緊密,必須用匯編語(yǔ)言編寫(xiě),所以MDK開(kāi)發(fā)環(huán)境成為許多工程師難以跨越的門(mén)檻。RealView MDK的μVision工具可以幫助用戶自動(dòng)生成完善的啟動(dòng)代碼,并提供圖形化的窗口,便于用戶輕松修改。無(wú)論是初學(xué)者,還是有經(jīng)驗(yàn)的開(kāi)發(fā)工程師,它都能大大節(jié)省時(shí)間,提高開(kāi)發(fā)效率。

μVision IDE是一款集編輯、編譯和項(xiàng)目管理于一身的基于窗口的軟件開(kāi)發(fā)環(huán)境。μVision集成了C語(yǔ)言編譯器、宏編譯、鏈接/定位,以及HEX文件產(chǎn)生器。μVision具有如下特性:

(1)具備功能齊全的源代碼編輯器;

(2)具備用于配置開(kāi)發(fā)工具的設(shè)備庫(kù);

(3)具備用于創(chuàng)建工程和維護(hù)工程的項(xiàng)目管理器;

(4)所有的工具配置都采用對(duì)話框進(jìn)行;

(5)集成了源碼級(jí)的仿真調(diào)試器,包括高速CPU和外設(shè)模擬器;

(6)具備用于往Flash ROM下載應(yīng)用程序的Flash編程工具;

(7)具備完備的開(kāi)發(fā)工具幫助文檔、設(shè)備數(shù)據(jù)表和用戶使用向?qū)А?/p>

RealView MDK具有良好的界面風(fēng)格。如圖3-1所示是一個(gè)典型的μVision調(diào)試界面。

圖3-1 μVision調(diào)試界面

(1)工程區(qū):用于訪問(wèn)文件組和文件,調(diào)試時(shí)可以查看CPU寄存器。

(2)調(diào)試輸出窗口:顯示編譯結(jié)果,以便快速查找錯(cuò)誤的地方,它同時(shí)還是調(diào)試命令窗口,可以用于顯示查找結(jié)果。

(3)內(nèi)存窗口:顯示指定地址內(nèi)存里的內(nèi)容。

(4)代碼窗口:用于查看和編輯源文件。

(5)外設(shè)對(duì)話框:檢查微控制的片上外設(shè)的狀態(tài)。

RealView MDK提供了性能分析器,可根據(jù)模塊或函數(shù)實(shí)現(xiàn)對(duì)程序運(yùn)行時(shí)間、被調(diào)用次數(shù)的統(tǒng)計(jì),可用于代碼優(yōu)化、性能檢測(cè)。該分析器需要在模擬器狀態(tài)下進(jìn)行,如圖3-2所示。

圖3-2 性能分析器

3.1.2 工程創(chuàng)建、編譯

本節(jié)是結(jié)合LPC176X的兼容CMSIS標(biāo)準(zhǔn)外設(shè)的固件驅(qū)動(dòng)庫(kù)(簡(jiǎn)稱(chēng)固件庫(kù))(“LPC175X and LPC176X CMSIS-Compliant Standard Peripheral Firmware Driver Library”)進(jìn)行講解的,該固件庫(kù)提供了CMSIS兼容的驅(qū)動(dòng)程序,這里直接使用這部分驅(qū)動(dòng)程序。本節(jié)不涉及LPC176X的固件庫(kù)內(nèi)容,該部分內(nèi)容將在后續(xù)章節(jié)中介紹。

該固件庫(kù)中有一個(gè)core目錄。該目錄包含啟動(dòng)文件配置信息及CMSIS文件內(nèi)容。該目錄文件的含義參見(jiàn)3.2節(jié)及3.3節(jié)。在本節(jié)中,需要將該目錄復(fù)制到建立工程的目錄中。

一個(gè)項(xiàng)目需要經(jīng)過(guò)以下幾大步:

(1)選擇處理器與啟動(dòng)文件;

(2)配置必備文件;

(3)配置工程信息;

(4)編譯鏈接;

(5)程序下載;

(6)調(diào)試程序。

下面將詳述每個(gè)步驟。

(1)建立工程。在主菜單中選擇“new →new project”命令,建立名為“helloworld”的工程。建立工程之后,會(huì)彈出選擇CPU型號(hào)的對(duì)話框,選擇LPC1768,如圖3-3所示。

圖3-3 選擇CPU型號(hào)

(2)單擊圖3-3中的“OK”按鈕,在彈出的對(duì)話框中確定是否需要復(fù)制啟動(dòng)文件,如圖3-4所示。

圖3-4 是否復(fù)制啟動(dòng)文件

這里選擇否(當(dāng)然可以根據(jù)需要選擇是)。如果該步驟選擇是,將使用Keil自帶的啟動(dòng)文件。該啟動(dòng)文件需要在main函數(shù)里增加SystemInit函數(shù)調(diào)用。如果使用NXP提供的固件庫(kù),則不需在main函數(shù)里調(diào)用SystemInit()函數(shù)。兩者的文件區(qū)別如下:

        Reset_Handler   PROC
                      EXPORT  Reset_Handler           [WEAK]
                      IMPORT  SystemInit
                      IMPORT  __main
                      LDR    R0,=SystemInit;NXP提供的固件庫(kù)中有此調(diào)用,但Keil提供的啟
                                         ;動(dòng)文件無(wú)此啟動(dòng)文件。
                      BLX    R0
                      LDR    R0,=__main
                      BX     R0
                      ENDP

(3)管理項(xiàng)目文件組織。

在工程區(qū)單擊鼠標(biāo)右鍵,會(huì)出現(xiàn)如圖3-5所示的菜單,選擇“Manage Components…”選項(xiàng)。

圖3-5 項(xiàng)目文件組織

在彈出的如圖3-6所示的對(duì)話框中添加相應(yīng)文件。

圖3-6 添加文件

在圖3-6中,在Groups菜單里添加“Source”、“Startup”、“CMSIS-core”3個(gè)管理文件夾,然后在Files菜單里分別針對(duì)各組添加文件:

① startup管理文件夾里添加\Core\CM3\DeviceSupport\NXP\LPC17xx\startup\arm目錄下的startup_LPC17xx.s文件;

② CMSIS-core管理文件夾里分別添加\Core\CM3\CoreSupport目錄下的core_cm3.c;Core\CM3\DeviceSupport\NXP\LPC17xx目錄下的system_LPC17xx.c。

(4)選擇工具集:默認(rèn)情況使用RealView編譯器,如圖3-7所示。對(duì)于計(jì)劃使用GNU編譯器的,請(qǐng)選擇“Use GNU Compiler”。

圖3-7 工具集設(shè)置

(5)工程配置。

在圖3-5中,如果選擇“Options for Target’helloworldProject’”將會(huì)彈出“Options for Target’helloworldProject’”對(duì)話框。

如圖3-8所示是晶振設(shè)置,該時(shí)鐘信息應(yīng)與硬件環(huán)境下的時(shí)鐘信息相同。

圖3-8 晶振設(shè)置

單擊圖3-8中的“Output”選項(xiàng)卡,會(huì)出現(xiàn)如圖3-9所示的配置界面,在該界面上根據(jù)需要設(shè)置輸出文件的目錄信息。各選項(xiàng)的含義如下所示。

圖3-9 設(shè)置編譯輸出路徑及輸出文件信息

(1)Create Executable:生成axf及HEX文件。

(2)Debug Information:用于Debug版本,生成調(diào)試信息,否則無(wú)法進(jìn)行單步調(diào)試。

(3)Create Batch File:生成用于實(shí)現(xiàn)整個(gè)編譯過(guò)程的批處理文件,使用這個(gè)文件可以脫離IDE對(duì)程序進(jìn)行編譯。

(4)Create HEX File:這個(gè)選項(xiàng)在默認(rèn)情況下未被選中,如果要燒錄就必須選中該項(xiàng)。

(5)Browse Information:產(chǎn)生用于在源文件快速定位的信息。

在圖3-10中,在“Include Paths”處添加鏈接目錄“.\Core\CM3\CoreSupport;.\Core\CM3\DeviceSupport\NXP\LPC17xx”。也可以采用圖3-10中右圖所示的方式,使用彈出的“Folder Setup”對(duì)話框進(jìn)行設(shè)置。

圖3-10 定義宏及編譯鏈接路徑

在圖3-10左圖所示的“Options for Target’helloworldProject’”對(duì)話框中,Preprocessor Symbols是添加整個(gè)工程的宏定義。

單擊圖3-10中的“Debug”選項(xiàng)卡,會(huì)出現(xiàn)如圖3-11所示的界面。該頁(yè)面用于設(shè)置程序調(diào)試方式。可選擇模擬器方式,或者選擇仿真器方式。

圖3-11 選擇調(diào)試方式及設(shè)置仿真器類(lèi)型

模擬器的使用注意事項(xiàng):在模擬器中測(cè)試程序,如果在main函數(shù)里定義了局部變量,則使用調(diào)試窗口觀察發(fā)現(xiàn)該變量的運(yùn)行結(jié)果不正常。可以將該變量改成全局變量。對(duì)于有條件能在實(shí)際環(huán)境運(yùn)行的,還是推薦使用實(shí)際環(huán)境運(yùn)行程序。

Flash編程的設(shè)置如圖3-12和圖3-13所示。圖3-12中的“Use Target Driver for Flash Programming”默認(rèn)選擇Ulink仿真器。“Settings”按鈕用于Flash編程的設(shè)置。下載參數(shù)的設(shè)置如圖3-13所示。下載參數(shù)需選擇“LPC17xx IAP 512kB Flash”。該處需要結(jié)合硬件實(shí)際情況進(jìn)行選擇,否則運(yùn)行結(jié)果不正常。

圖3-12 設(shè)置編程器類(lèi)型

圖3-13 設(shè)置Flash下載參數(shù)

(6)準(zhǔn)備好工程文件后,可以按一下F7鍵進(jìn)行編譯。編譯完畢工程文件后,需要將程序下載到LPC17XX中,可以通過(guò)主菜單中的“Flash→Download”命令進(jìn)行下載,如圖3-14所示。如果在圖3-11中選擇的是模擬器方式,則可以跳過(guò)該步。

圖3-14 程序下載

(7)下載完畢程序后,進(jìn)行仿真調(diào)試。通過(guò)主菜單中的“Debug→Start/Stop Debug Session”命令,開(kāi)啟調(diào)試,然后單擊“Run”子菜單進(jìn)行調(diào)試,如圖3-15所示。

圖3-15 調(diào)試

3.1.3 Flash編程器

ULINK2是ARM公司最新推出的配套R(shí)ealView MDK使用的仿真器,如圖3-16所示。開(kāi)發(fā)工程師通過(guò)結(jié)合使用RealView MDK的調(diào)試器和ULINK2,可以方便地在目標(biāo)硬件上進(jìn)行片上調(diào)試(使用on-chip JTAG,SWD和OCDS)、Flash編程。ULINK2可實(shí)現(xiàn)USB通信接口高速下載用戶代碼;查看存儲(chǔ)區(qū)域/寄存器;運(yùn)行快速單步程序;可設(shè)置多個(gè)程序斷點(diǎn);片內(nèi)Flash編程。

圖3-16 ULINK2

ULINK2的特點(diǎn):

(1)具備標(biāo)準(zhǔn)Windows USB驅(qū)動(dòng),支持ULINK2即插即用;

(2)支持基于ARM Cortex-M3的串行調(diào)試;

(3)支持程序運(yùn)行期間的存儲(chǔ)器讀/寫(xiě)、終端仿真和串行調(diào)試輸出;

(4)支持10-pin接線(也支持20-pin連接線)。

3.1.4 簡(jiǎn)易實(shí)例

經(jīng)過(guò)3.1.2節(jié)與3.1.3節(jié)兩小節(jié)的準(zhǔn)備工作,現(xiàn)在開(kāi)始實(shí)現(xiàn)顯示“hello world”。在C語(yǔ)言中,最簡(jiǎn)單的“hello world”只有兩行:

        void main ()
        {printf(“hello world”);
        }

在ARM環(huán)境中,可以通過(guò)UART輸出字符串(第8章中將介紹UART的使用)。本節(jié)使用MDK的模擬器輸出字符串,使之更符合我們學(xué)習(xí)任何一門(mén)語(yǔ)言所見(jiàn)到的第一個(gè)程序設(shè)計(jì)的習(xí)慣。

由于標(biāo)準(zhǔn)庫(kù)函數(shù)的默認(rèn)輸出設(shè)備是顯示器,所以要想實(shí)現(xiàn)在串口或LCD輸出,必須重定義標(biāo)準(zhǔn)庫(kù)函數(shù)里調(diào)用的與輸出設(shè)備相關(guān)的函數(shù)。這里將printf函數(shù)重定向到串口,見(jiàn)serial.c文件。由于printf()之類(lèi)的函數(shù)使用了半主機(jī)模式,使用標(biāo)準(zhǔn)庫(kù)會(huì)導(dǎo)致程序無(wú)法運(yùn)行,所以這里采用#pragma import(__use_no_semihosting) 關(guān)閉半主機(jī)模式,見(jiàn)retarget.c文件。

Serial.c與retarget.c文件,以及配套serial.h文件均在Keil\ARM\Boards\Keil\MCB1700\Blinky目錄下存在(讀者所安裝的mdk目錄)。請(qǐng)自行將其復(fù)制到3.1.3節(jié)中建立的工程目錄下。

創(chuàng)建helloworld.c文件之后,將其添加到3.1.3節(jié)創(chuàng)建的工程中。Helloworld.c文件的內(nèi)容如下:

        #include <stdio.h>
        #include"LPC17xx.H"                 /*LPC17xx definitions*/
        #include "Serial.h"
    @@@
        void  main()
        {
          SER_init(1);
        printf("hello world \n");
        }

選擇模擬器方式運(yùn)行編譯,可通過(guò)“view→serial windows→Uart#2”看到輸出的“hello world”,如圖3-17所示。

圖3-17 運(yùn)行結(jié)果

3.2 CMSIS——Cortex-M3微控制器軟件接口標(biāo)準(zhǔn)

條條大路通羅馬。ARM7TDMI的年代給出了100條甚至1萬(wàn)條大路通羅馬(供選擇的很多,而且每個(gè)都有著美好前景。但這就跟找對(duì)象/工作一樣,容易挑花眼)。但對(duì)于一個(gè)需要經(jīng)常往來(lái)于羅馬及羅馬之外的地區(qū)的人而言,每次往來(lái)都是不同路線,可能是一件痛苦的事情,畢竟去羅馬不需要那么多次旅游。對(duì)于需要經(jīng)常更換ARM7TDMI芯片型號(hào)及編譯工具的人而言,每次都走一條不同的大路去往羅馬不是一件享受的事情。Cortex-M3的年代變了,它只有一條路(也可以說(shuō)有三條路,根據(jù)編譯器的不同會(huì)有稍微差別),你往返的次數(shù)越多,越熟練,也會(huì)發(fā)現(xiàn)時(shí)間節(jié)省得越多。Cortex-M3的年代就是ARM公司提供CMSIS這一條大路。第1章中不斷提到過(guò)CMSIS,本節(jié)將詳細(xì)講解CMSIS的構(gòu)架。

3.2.1 CMSIS概述

Cortex微控制器軟件接口標(biāo)準(zhǔn)(Cortex Microcontroller Software Interface Standard,CMSIS)是Cortex-M處理器系列具備的與供應(yīng)商無(wú)關(guān)的硬件抽象層。使用CMSIS,可以為處理器和外設(shè)實(shí)現(xiàn)一致且簡(jiǎn)單的軟件接口,從而簡(jiǎn)化軟件的重用,縮短微控制器新開(kāi)發(fā)人員的學(xué)習(xí)過(guò)程,并縮短新設(shè)備的上市時(shí)間。軟件的創(chuàng)建被嵌入式行業(yè)公認(rèn)為主要成本。通過(guò)在所有Cortex-M芯片供應(yīng)商產(chǎn)品中標(biāo)準(zhǔn)化軟件接口,這一成本會(huì)明顯降低,尤其是在創(chuàng)建新項(xiàng)目或?qū)F(xiàn)有軟件遷移到新設(shè)備時(shí)。CMSIS提供了一致軟件接口,改善了軟件移植性和可重復(fù)性。通用的軟件庫(kù)可以存取不同的廠家芯片的設(shè)備庫(kù)函數(shù),減少了學(xué)習(xí)時(shí)間、開(kāi)發(fā)成本、產(chǎn)品化時(shí)間。開(kāi)發(fā)者使用標(biāo)準(zhǔn)化的軟件接口可以快速完成軟件的編寫(xiě)工作。CMSIS提供了編譯器獨(dú)立層,可用不同編譯器進(jìn)行編譯。CMSIS支持主流編譯器(ARMCC,IAR,GNU)。目前CMSIS已經(jīng)發(fā)展到版本3。

CMSIS可以分為以下3個(gè)基本功能層。

(1)核內(nèi)外設(shè)訪問(wèn)層(Core Peripheral Access Layer):包含了命名定義、地址定義、存取內(nèi)核寄存器和外圍設(shè)備的協(xié)助函數(shù),同時(shí)定義了一個(gè)與設(shè)備無(wú)關(guān)的RTOS內(nèi)核接口函數(shù);一些對(duì)特殊用途寄存器的訪問(wèn)都被定義成內(nèi)聯(lián)函數(shù)或內(nèi)嵌匯編的形式。

(2)中間件訪問(wèn)層(Middleware Access Layer):該層用于存儲(chǔ)外設(shè),由ARM公司開(kāi)發(fā),其他芯片廠家擴(kuò)展。

(3)設(shè)備訪問(wèn)層(Device Peripheral Access):用來(lái)定義一些硬件寄存器的地址及對(duì)外設(shè)的訪問(wèn)函數(shù)。另外,芯片廠商會(huì)對(duì)異常向量進(jìn)行擴(kuò)展。設(shè)備訪問(wèn)層由芯片廠商實(shí)現(xiàn)。

通過(guò)使用CMSIS兼容軟件組件,用戶可以重復(fù)使用模板代碼。

如圖3-18所示是CMSIS的組織結(jié)構(gòu)圖。

圖3-18 CMSIS的組織結(jié)構(gòu)圖

3.2.2 CMSIS編碼規(guī)范

CMSIS制定了基本規(guī)范及推薦規(guī)范,供芯片廠家及普通用戶使用。

1.基本規(guī)范

CMSIS的C代碼遵照MISRA 2004規(guī)則,使用標(biāo)準(zhǔn)ANSI C頭文件<stdint.h>中定義的標(biāo)準(zhǔn)數(shù)據(jù)類(lèi)型。

(1)由#define定義的包含表達(dá)式的常數(shù)必須用括號(hào)括起來(lái)。

(2)變量和參數(shù)必須有完整的數(shù)據(jù)類(lèi)型。

(3)CPAL層的函數(shù)必須是可重入的。

(4)CPAL層的函數(shù)不能有阻塞代碼,也就是說(shuō),等待、查詢等循環(huán)必須在其他的軟件層中。

(5)定義每個(gè)異常/中斷的

① 每個(gè)異常處理函數(shù)的后綴是_Handler,每個(gè)中斷處理器函數(shù)的后綴是_IRQHandler;

② 默認(rèn)的異常中斷處理器函數(shù)(弱定義)包含一個(gè)無(wú)限循環(huán);

③ 用#define將中斷號(hào)定義為后綴為_(kāi)IRQn的名稱(chēng)。

2.推薦規(guī)范

(1)定義核寄存器、外設(shè)寄存器和CPU指令名稱(chēng)時(shí)使用大寫(xiě)。

(2)定義外設(shè)訪問(wèn)函數(shù)、中斷函數(shù)名稱(chēng)時(shí)首字母大寫(xiě)。

(3)對(duì)于與某個(gè)外設(shè)對(duì)應(yīng)的函數(shù),一般用該外設(shè)名稱(chēng)作為其前綴。

(4)按照Doxygen規(guī)范撰寫(xiě)函數(shù)的注釋?zhuān)⑨屖褂肅90風(fēng)格(/*注釋*/)或C++風(fēng)格(//注釋?zhuān):瘮?shù)的注釋?xiě)?yīng)包含以下內(nèi)容:

① 一行函數(shù)簡(jiǎn)介;

② 參數(shù)的詳細(xì)解釋?zhuān)?/p>

③ 返回值的詳細(xì)解釋?zhuān)?/p>

④ 函數(shù)功能的詳細(xì)描述。

3.2.3 CMSIS文件結(jié)構(gòu)

本節(jié)結(jié)合LPC17XX分析一下CMSIS的文件結(jié)構(gòu),并說(shuō)明各個(gè)文件的主要功能。文件結(jié)構(gòu)如圖3-19所示。

圖3-19 CMSIS的文件結(jié)構(gòu)

CMSIS各個(gè)文件的對(duì)應(yīng)關(guān)系及功能說(shuō)明如表3-1所示。

表3-1 CMSIS各個(gè)文件的對(duì)應(yīng)關(guān)系及功能說(shuō)明

3.2.4 核內(nèi)外設(shè)訪問(wèn)層

硬件層的數(shù)據(jù)類(lèi)型定義使用了標(biāo)準(zhǔn)ANSI C頭文件stdint.h定義的數(shù)據(jù)類(lèi)型。CMSIS使用了3種標(biāo)記符指定對(duì)寄存器的訪問(wèn)權(quán)限:_I(volatile const)、_O(volatile)、_IO(volatile)。其中_I表示只讀權(quán)限,_O表示只寫(xiě)權(quán)限,_IO表示讀寫(xiě)權(quán)限。

1.Cortex-M內(nèi)核寄存器的存取

在core_cm0.h / core_cm3.h中定義了指令的內(nèi)在函數(shù),用于操作Cortex-M內(nèi)核寄存器,如表3-2所示。

表3-2 內(nèi)核寄存器的函數(shù)

2.Cortex-M指令的調(diào)用

在Coretex的時(shí)代,開(kāi)發(fā)人員幾乎可以不使用匯編語(yǔ)言進(jìn)行開(kāi)發(fā)了。但匯編語(yǔ)言仍然存在,而且在某些場(chǎng)合需要使用。ARM為此提供了一些C語(yǔ)言的封裝函數(shù),用于解決指令系統(tǒng)的調(diào)用問(wèn)題。在core_m0.h/core_m3.h中對(duì)指令系統(tǒng)進(jìn)行了定義。在core_cm0.c/core_cm3.c中實(shí)現(xiàn)了這些函數(shù)。如表3-3所示是CMSIS指令的操作函數(shù)。

表3-3 CMSIS指令的操作函數(shù)

3.嵌套中斷向量訪問(wèn)函數(shù)

第1章中介紹了中斷。中斷的設(shè)置涉及組的配置,以及組優(yōu)先級(jí)、子優(yōu)先級(jí)的設(shè)置,屬于比較復(fù)雜的配置。CMSIS提供了相應(yīng)的函數(shù),可以簡(jiǎn)化配置過(guò)程。

表3-4中給出了如何設(shè)置中斷優(yōu)先級(jí),以及與中斷使能相關(guān)的操作。

表3-4 嵌套中斷函數(shù)

說(shuō)明:IRQn_Type是一個(gè)枚舉定義的數(shù)據(jù)類(lèi)型。Cortex-M3中的處理器異常的起始值為負(fù)值。外部設(shè)備的中斷起始值從0開(kāi)始。IRQn_Type在device.h文件中。嵌套向量中斷中的__NVIC_PRIO_BITS影響NVIC_EncodePriority和NVIC_DecodePriority的使用。

4.NXP實(shí)現(xiàn)的device.h

device.h由芯片廠家提供,NXP公司提供的device.h文件名是LPC17XX.h。該文件實(shí)現(xiàn)了中斷號(hào)的枚舉定義,用于提供所有異常和中斷的配置;提供了core_cm3.h文件中針對(duì)實(shí)際芯片的配置信息;提供了對(duì)LPC17XX數(shù)據(jù)結(jié)構(gòu)和地址映射的訪問(wèn)。

device.h可存取設(shè)備中斷,并通過(guò)使用枚舉方式定義了所有設(shè)備的中斷號(hào)。LPC17XX.h中的定義方式如下:

        typedef enum IRQn
        {
        /******  Cortex-M3 異常號(hào) ***************************************************/
          NonMaskableInt_IRQn      =-14,    /*!<2 NMI                    */
          MemoryManagement_IRQn   =-12,    /*!<4 Cortex-M3 存儲(chǔ)管理中斷     */
          BusFault_IRQn           =-11,    /*!<5 Cortex-M3 總線故障中斷     */
          UsageFault_IRQn          =-10,    /*!<6 Cortex-M3 用法故障中斷     */
          SVCall_IRQn            =-5,    /*!<11 Cortex-M3 SV調(diào)用中斷     */
          DebugMonitor_IRQn       =-4,    /*!<12 Cortex-M3 調(diào)試監(jiān)視中斷    */
          PendSV_IRQn            =-2,    /*!<14 Cortex-M3 Pend SV中斷     */
          SysTick_IRQn            =-1,    /*!<15 Cortex-M3 系統(tǒng)定時(shí)器中斷   */
    @@@
        /******  LPC17XX指定中斷號(hào) *******************************************************/
          WDT_IRQn              =0,     /*!< 看門(mén)狗定時(shí)器中斷           */
          TIMER0_IRQn           =1,     /*!<定時(shí)器0 中斷               */
          TIMER1_IRQn           =2,     /*!< 定時(shí)器1 中斷              */
          TIMER2_IRQn           =3,     /*!< 定時(shí)器2 中斷              */
          TIMER3_IRQn           =4,     /*!< 定時(shí)器3中斷               */
          UART0_IRQn            =5,     /*!<UART0 中斷                */
          UART1_IRQn            =6,     /*!<UART1 中斷                */
          UART2_IRQn            =7,     /*!<UART2 中斷               */
          UART3_IRQn            =8,     /*!<UART3 中斷               */
        PWM1_IRQn         =9,     /*!<PWM1 中斷               */
        I2C0_IRQn          =10,    /*!<I2C0 中斷                 */
        I2C1_IRQn          =11,    /*!<I2C1 中斷                 */
        I2C2_IRQn          =12,    /*!<I2C2 中斷                 */
        SPI_IRQn           =13,    /*!<SPI中斷                  */
        SSP0_IRQn          =14,    /*!<SSP0 中斷                 */
        SSP1_IRQn          =15,    SSP1 中斷                    */
        PLL0_IRQn          =16,    /*!<PLL0 鎖存 (Main PLL) 中斷   */
        RTC_IRQn          =17,    /*!< 實(shí)時(shí)時(shí)鐘中斷              */
        EINT0_IRQn         =18,    /*!< 外部中斷0                */
        EINT1_IRQn         =19,    /*!< 外部中斷1                */
        EINT2_IRQn         =20,    /*!< 外部中斷2                */
        EINT3_IRQn         =21,    /*!< 外部中斷3                */
        ADC_IRQn          =22,    /*!<A/D轉(zhuǎn)換中斷              */
        BOD_IRQn          =23,     /*!<Brown-Out Detect Interrupt      */
        USB_IRQn          =24,    /*!<USB中斷                 */
        CAN_IRQn          =25,    /*!<CAN中斷                 */
        DMA_IRQn         =26,    /*!<GPDMA中斷              */
        I2S_IRQn           =27,    /*!<I2S中斷                  */
        ENET_IRQn         =28,    /*!< 網(wǎng)絡(luò) 中斷                */
        RIT_IRQn           =29,    /*!< 可重復(fù)定時(shí)器中斷          */
        MCPWM_IRQn       =30,    /*!< 電機(jī)控制PWM中斷         */
        QEI_IRQn           =31,    /*!<QEI中斷                  */
        PLL1_IRQn          =32,    /*!<PLL1 鎖存中斷             */
        USBActivity_IRQn     =33,    /*!<USB活躍中斷              */
        CANActivity_IRQn    =34     /*!<CAN活躍中斷             */
      } IRQn_Type;

由于Cortex-M3對(duì)所有外設(shè)采用了內(nèi)存映射方式,所以LPC17XX.h提供了芯片外設(shè)的內(nèi)存映射訪問(wèn)方式。固件庫(kù)采用了結(jié)構(gòu)體定義寄存器,然后通過(guò)地址強(qiáng)制類(lèi)型轉(zhuǎn)換成結(jié)構(gòu)體。例如,LPC17XX系列處理器的I2C寄存器組的數(shù)據(jù)結(jié)構(gòu)定義如下:

        /*-------------Inter-IntegratedCircuit(I2C)---------------*/
        typedefstruct
        {
        __IOuint32_tI2CONSET;
        __Iuint32_tI2STAT;
        __IOuint32_tI2DAT;
        __IOuint32_tI2ADR0;
        __IOuint32_tI2SCLH;
        __IOuint32_tI2SCLL;
        __Ouint32_tI2CONCLR;
        __IOuint32_tMMCTRL;
        __IOuint32_tI2ADR1;
        __IOuint32_tI2ADR2;
        __IOuint32_tI2ADR3;
        __Iuint32_tI2DATA_BUFFER;
        __IOuint32_tI2MASK0;
        __IOuint32_tI2MASK1;
        __IOuint32_tI2MASK2;
        __IOuint32_tI2MASK3;
        }LPC_I2C_TypeDef;

LPC17XX處理器I2C接口的基地址定義如下:

        #defineLPC_I2C0_BASE(LPC_APB0_BASE+0x1C000)

訪問(wèn)LPC17XX處理器I2C接口的方法如下:

        #defineLPC_I2C0((LPC_I2C_TypeDef*)LPC_I2C0_BASE)

5.NXP提供的啟動(dòng)文件startup_LPC17xx.s

在Cortex-M3中斷的使用方面,也是從ARM7轉(zhuǎn)到Cortex-M編程的程序員感到困惑的地方,即在Cortex-M3中,雖然原來(lái)的interrupt修飾符消失了,但需要使用與startup_LPC17XX.s中定義一模一樣的函數(shù)名字去定義中斷。

在startup_LPC17xx.s文件中包含了所有外設(shè)的中斷向量。每個(gè)中斷句柄都定義成了weak屬性,即成為啞函數(shù),這樣中斷句柄可以直接使用應(yīng)用程序里的函數(shù),而不用修改startup_device(即startup_LPC17xx.s)的內(nèi)容。

使用weak屬性后,將通知鏈接器,如果可以使用其他源中的不同符號(hào)實(shí)例,則不同實(shí)例將優(yōu)先于此實(shí)例。weak屬性可與任何符號(hào)的可見(jiàn)性屬性一起使用。

對(duì)于Cortex-M3系列,下列代碼的編寫(xiě)都是相同的,定義中斷向量地址的同時(shí)定義了中斷服務(wù)程序的名字,并都定義在中斷向量表的起始位置。

        __Vectors      DCD    __initial_sp              ; 堆棧起始地址
                      DCD    Reset_Handler            ; 復(fù)位中斷
                      DCD    NMI_Handler            ;NMI句柄
                      DCD    HardFault_Handler         ; 硬故障
                      DCD    MemManage_Handler       ;MPU故障
                      DCD    BusFault_Handler          ; 總線故障
                      DCD    UsageFault_Handler        ; 用法故障
                      DCD    0                     ; 保留
                      DCD    0                     ; 保留
                      DCD    0                     ; 保留
                      DCD    0                     ; 保留
                      DCD    SVC_Handler             ;SVCall
                      DCD    DebugMon_Handler        ; 調(diào)試監(jiān)視
                      DCD    0                      ;Reserved
                      DCD    PendSV_Handler          ;PendSV
                      DCD    SysTick_Handler          ;SysTick
                      ; 外部中斷,廠商指定中斷
                      DCD    WDT_IRQHandler         ;16: 定時(shí)器中斷
                      DCD    TIMER0_IRQHandler       ;17: 定時(shí)器0
       ?
        Default_Handler PROC
                      EXPORT  WDT_IRQHandler          [WEAK];;WEAK聲明其他的同名
    標(biāo)號(hào)優(yōu)先于該標(biāo)號(hào)被引用,也就是說(shuō),如果外面聲明了,則會(huì)調(diào)用外面的
                      EXPORT  TIMER0_IRQHandler        [WEAK]
                      EXPORT  TIMER1_IRQHandler        [WEAK]
        ?
                WDT_IRQHandler
                TIMER0_IRQHandler
                TIMER1_IRQHandler
                        ?
                      B.
                      ENDP

用戶程序可以簡(jiǎn)單定義一個(gè)中斷服務(wù)程序的函數(shù)名字,即替代了原有ARM7TDMI必須采用__irq表示中斷函數(shù)的步驟。簡(jiǎn)單定義函數(shù)的實(shí)例如下所示:

        void WDT_IRQHandler (void)
        {
        ?
        }

6.NXP實(shí)現(xiàn)的其他文件

ARM公司提供了system_device.c文件模板,NXP公司將其調(diào)整成system_LPC17xx.c。該文件實(shí)現(xiàn)了:

        void SystemInit (void);//設(shè)置微控制器系統(tǒng);主要配置時(shí)鐘;更新SystemCoreClock;SystemInit
    //由啟動(dòng)文件調(diào)用
        void SystemCoreClockUpdate (void);//更新SystemCoreClock變量值。只要內(nèi)核時(shí)鐘改變,該函
    //數(shù)必須被調(diào)用
        uint32_t SystemCoreClock;//包含系統(tǒng)內(nèi)核時(shí)鐘,該變量可以用來(lái)設(shè)置SysTick時(shí)鐘定時(shí)器,然
    //后配置其他參數(shù);也可用于調(diào)試器查詢調(diào)試時(shí)間或配置跟蹤時(shí)鐘速度。在應(yīng)用程序不使用該變量的情況
    //下,編譯器必須避免刪除該變量。該變量對(duì)調(diào)試器系統(tǒng)是非常重要的

Cortex-M3提供儀器跟蹤宏單元。該單元主要提供了ITM_SendChar的實(shí)現(xiàn)。但在LPC17XX中沒(méi)有提供該功能。NXP公司有屬于自己的debug_frmwrk.c文件,用于通過(guò)UART進(jìn)行調(diào)試。

3.3 LPC1700 CMSIS標(biāo)準(zhǔn)固件庫(kù)

如果將ARM7TDMI年代對(duì)各種外設(shè)驅(qū)動(dòng)的編寫(xiě)理解成徒步,則針對(duì)LPC1700的芯片,LPC1700的固件庫(kù)可以看成在唯一(CMSIS基礎(chǔ))的一條通往羅馬(Cortex-M3)的大路上的坐騎。雖然現(xiàn)在還有不少人喜歡徒步通往羅馬,但不少?gòu)S家出于商業(yè)性、兼容自己老產(chǎn)品的風(fēng)格習(xí)慣,以及學(xué)習(xí)新產(chǎn)品的需要時(shí)間等原因仍然繼續(xù)使用原有的自己配置、管理各種寄存器的方式。通過(guò)本節(jié)的介紹,你會(huì)發(fā)現(xiàn)坐騎年代絕對(duì)比徒步時(shí)代更方便、更快捷、成本還少。

注意:CMSIS指的是ARM公司提供的,即不管你使用哪個(gè)廠家的Cortex-M3芯片,CMSIS與芯片廠商沒(méi)有任何關(guān)系,僅僅與ARM公司有關(guān)。

本書(shū)談到的固件庫(kù)是指NXP公司提供的,而且是針對(duì)LPC175X/6X的固件庫(kù)。固件庫(kù)因芯片的不同而不同。

3.3.1 固件庫(kù)的組織結(jié)構(gòu)

LPC1700 CMSIS標(biāo)準(zhǔn)固件庫(kù)是LPC17XX的標(biāo)準(zhǔn)外圍器件驅(qū)動(dòng)函數(shù)庫(kù),包括宏定義、數(shù)據(jù)類(lèi)型定義、結(jié)構(gòu)體定義和功能函數(shù)。用戶不需要深刻理解LPC1700的外圍器件就可以編寫(xiě)出外圍功能應(yīng)用程序。

固件庫(kù)遵循CMSIS標(biāo)準(zhǔn)。其使用的芯片主要是LPC176X和LPC175X。NXP公司針對(duì)LPC177X與LPC178X提供了另外一套固件庫(kù),但與本書(shū)使用的固件庫(kù)基本一致。

該固件庫(kù)支持的編譯器是:

(1)CodeSourcery G++ Lite toolchain version 4.3.3;

(2)KEIL的RVMDK 4.0以上;

(3)IAR 5.4。

該固件庫(kù)主要分為內(nèi)核(Core)、驅(qū)動(dòng)(Drivers)、例程、MAKE部分,Lib文件構(gòu)建,其中Core與Drivers是開(kāi)發(fā)的基礎(chǔ)。內(nèi)核部分即為CMSIS的內(nèi)容,其中關(guān)于Cortex-M3的內(nèi)容已經(jīng)在3.2節(jié)做過(guò)介紹,NXP公司實(shí)現(xiàn)了需要廠家移植部分的內(nèi)容。這部分內(nèi)容被稱(chēng)為CMSIS的設(shè)備支持部分。

CMSIS的設(shè)備支持部分提供了LPC17XX設(shè)備支持文件,允許用戶調(diào)用設(shè)備外圍。設(shè)備支持部分包含支持ARM(KEIL MDK)/GCC/IAR編譯器的啟動(dòng)文件、頭文件、系統(tǒng)文件。

(1)啟動(dòng)文件根據(jù)編譯器類(lèi)型分別放在如下目錄下。

① ARM編譯器(KEIL MDK):“\Core\CM3\DeviceSupport\NXP\LPC17xx\startup\arm\startup_LPC17xx.s”。

② GCC編譯器:“\Core\CM3\DeviceSupport\NXP\LPC17xx\startup\gcc\startup_LPC17xx.s”。

③ IAR編譯器:“\Core\CM3\DeviceSupport\NXP\LPC17xx\startup\iar\startup_LPC17xx.s”。

(2)頭文件(LPC17xx.h):LPC17XX外設(shè)設(shè)備的存取層定義了所有LPC17XX的外設(shè),如如何訪問(wèn)ADC寄存器。

(3)系統(tǒng)文件包含了system_LPC17xx.h:與system_LPC17xx.c,定義了設(shè)備的特定配置信息,用于配置LPC17XX的時(shí)鐘。

3.3.2 固件庫(kù)的驅(qū)動(dòng)部分

給LPC17XX外圍設(shè)備提供驅(qū)動(dòng)的部分位于“..\Driver”目錄下。它被分成兩部分:

(1)頭文件部分,提供了宏定義、結(jié)構(gòu)體、枚舉類(lèi)型的定義;

(2)源代碼部分,提供了設(shè)備驅(qū)動(dòng)的函數(shù)部分。

如表3-5所示是固件庫(kù)的組織結(jié)構(gòu)。

表3-5 固件庫(kù)的組織結(jié)構(gòu)

LPC1700驅(qū)動(dòng)庫(kù)包含利用UART端口連接的調(diào)試工具,它包含在兩個(gè)文件中:debug_frmwrk.h與debug_frmwrk.c。

固件庫(kù)中的默認(rèn)端口是UART0,采用115200波特率、8位數(shù)據(jù)、無(wú)奇偶校驗(yàn)、一個(gè)停止位。如表3-6所示是固件庫(kù)中的調(diào)試函數(shù)及其功能描述。

表3-6 固件庫(kù)中的調(diào)試函數(shù)及其功能描述

3.3.3 驅(qū)動(dòng)標(biāo)識(shí)定義

LPC17XX固件庫(kù)中的“l(fā)pc17xx_libcfg.h”文件定義了每個(gè)驅(qū)動(dòng)源文件的使用問(wèn)題。該文件通過(guò)宏定義的方式?jīng)Q定具體的某一個(gè)功能模塊是否可被使用。如表3-7所示為lpc17xx_libcfg.h中的宏定義解釋。

表3-7 lpc17xx_libcfg.h中的宏定義解釋

3.4 小結(jié)

本章是進(jìn)行LPC17XX軟件開(kāi)發(fā)的基礎(chǔ)工作。本章介紹了開(kāi)發(fā)環(huán)境,以及如何使用開(kāi)發(fā)環(huán)境建立第一個(gè)軟件程序。本章還對(duì)CMSIS與LPC17XX固件庫(kù)進(jìn)行了詳細(xì)解釋?zhuān)@兩部分是進(jìn)行LPC17XX開(kāi)發(fā)的基礎(chǔ)。后續(xù)章節(jié)的軟件開(kāi)發(fā)將建立在本章介紹的內(nèi)容基礎(chǔ)上。尤其是CMSIS部分,它是理解軟件設(shè)計(jì)的基礎(chǔ)。

主站蜘蛛池模板: 长白| 镇宁| 罗田县| 常德市| 买车| 乌拉特后旗| 鲁甸县| 启东市| 田阳县| 佛山市| 通海县| 囊谦县| 太仆寺旗| 雷山县| 丽江市| 耒阳市| 沂南县| 晋中市| 加查县| 平阴县| 兴安盟| 金沙县| 高密市| 波密县| 江门市| 阿尔山市| 册亨县| 胶州市| 弥渡县| 尚义县| 舞钢市| 三都| 靖西县| 广河县| 根河市| 汾阳市| 芒康县| 永登县| 凌源市| 临安市| 平湖市|