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

第1章 Cortex-M3體系結(jié)構(gòu)

ARM公司是全球領(lǐng)先的半導體知識產(chǎn)權(quán)(IP)提供商,32位嵌入式微處理器的行業(yè)領(lǐng)先提供商,已推出各種各樣基于通用架構(gòu)的處理器,這些處理器具有高性能和行業(yè)領(lǐng)先的特點,而且其系統(tǒng)成本也有所降低。ARM公司擁有至少900芯片生產(chǎn)廠家、工具和軟件的合作伙伴,并已推出一系列(20多種)處理器,可以解決每個應用挑戰(zhàn)。迄今為止,ARM公司已生產(chǎn)出超過250億個處理器,每天的銷量超過1600萬個,是真正意義上的嵌入式系統(tǒng)的基礎(chǔ)。

本章主要介紹目前ARM公司的Cortex-M3處理器,包括發(fā)展歷史、處理器結(jié)構(gòu)、各個功能特征。本章將結(jié)合LPC17XX對其功能特征進行介紹。

1.1 Cortex-M3簡介

ARM公司的Cortex-M3是一種基于ARMV7構(gòu)架的最新ARM嵌入式內(nèi)核,采用哈佛結(jié)構(gòu),具有低成本、低功耗特點。與ARM7TDMI相比,Cortex-M3具有各種優(yōu)勢。本節(jié)將介紹ARM的歷史、Cortex-M3的特點及與ARM7TDMI之間的性能對比。

1.1.1 ARM的歷史

ARM這個詞既代表了一個公司,也代表了微處理器,還代表了一項技術(shù)。1991年,ARM公司成立于英國劍橋,主要出售芯片技術(shù)的授權(quán)(目前已經(jīng)授權(quán)給多家公司)。利用這種授權(quán)關(guān)系,ARM公司很快成為許多全球性RISC標準的締造者。

1.ARM體系結(jié)構(gòu)的版本歷史

ARM體系結(jié)構(gòu)是構(gòu)建每個ARM處理器的基礎(chǔ)。ARM體系結(jié)構(gòu)支持跨越多個性能點的實現(xiàn),并已在許多細分市場中成為主導的體系結(jié)構(gòu)。ARM體系結(jié)構(gòu)支持非常廣泛的性能,因而可以利用最新的微體系結(jié)構(gòu)技術(shù)獲得極小的ARM處理器實現(xiàn)和極有效的高級設計實現(xiàn)。ARM體系結(jié)構(gòu)能夠解決實現(xiàn)規(guī)模小、性能差和功耗低的問題。

ARM體系結(jié)構(gòu)通常描述為精簡指令集計算機(RISC)體系結(jié)構(gòu),它包含以下典型的RISC體系結(jié)構(gòu)特征。

(1)大的、統(tǒng)一的寄存器文件。

(2)簡單的尋址模式。

(3)統(tǒng)一和固定長度的指令域,3地址指令格式,簡化了指令的譯碼。采用3地址指令格式、較多寄存器和對稱的指令格式便于生成優(yōu)化代碼。

(4)單周期操作。ARM指令系統(tǒng)中的指令只需要執(zhí)行簡單的和基本的操作,因此其執(zhí)行過程在一個機器周期內(nèi)完成。

(5)固定的32位長度指令。指令長度固定為32位,使得指令譯碼結(jié)構(gòu)簡單,效率提高。

(6)采用指令流水線技術(shù)。

ARM處理器對基本RISC體系結(jié)構(gòu)進行功能擴展,實現(xiàn)了高性能、較小代碼大小、較低功耗和較小硅面積的良好平衡。

ARM體系結(jié)構(gòu)自誕生至今,已經(jīng)發(fā)生了很大的演變,至今已定義了8種不同的版本,用版本號V1~V8表示。

(1)V1版架構(gòu)只在原型機ARM1中出現(xiàn)過,其基本指令包括基本的數(shù)據(jù)處理指令(無乘法),字節(jié)、半字和字的Load/Store指令,轉(zhuǎn)移指令,子程序調(diào)用及鏈接指令,軟件中斷指令,其尋址空間為64MB。

(2)V2版架構(gòu)對V1版架構(gòu)進行了擴展,如ARM2與ARM3(V2a版)架構(gòu),增加的指令包括乘法和乘加指令、支持協(xié)處理器操作指令、快速中斷模式指令、SWP/SWPB的最基本的存儲器與寄存器交換指令,其尋址空間為64MB。

(3)V3版架構(gòu)對ARM體系結(jié)構(gòu)做了較大的改動,把尋址空間增至32位(4GB),增加了當前程序狀態(tài)寄存器CPSR和程序狀態(tài)保存寄存器SPSR,以便于進行異常處理;增加了中止和未定義2種處理器模式。ARM6就采用了該版架構(gòu)。該版架構(gòu)的指令集的變化包括增加了MRS/MSR指令(以訪問新增的CPSR/SPSR寄存器)及從異常處理返回的指令。

(4)V4版架構(gòu)是目前最廣泛應用的ARM體系結(jié)構(gòu),它對V3版架構(gòu)進行了進一步擴充,有的還引進了16位的Thumb指令集,使得ARM的使用變得更加靈活。ARM7、ARM9和StrongARM都采用了該版結(jié)構(gòu)。其指令集中增加的功能包括:增加了符號化和非符號化半字及符號化字節(jié)的存/取指令,增加了16位Thumb指令集,完善了軟件中斷SWI指令的功能,處理器系統(tǒng)模式引進特權(quán)方式時使用用戶寄存器操作,把一些未使用的指令空間捕捉為未定義指令。

(5)V5版架構(gòu)在V4版架構(gòu)基礎(chǔ)上增加了一些新的指令。ARM10和XScale都采用該版架構(gòu)。這些新增指令有帶有鏈接和交換的轉(zhuǎn)移BLX指令、計數(shù)前導零計數(shù)CLZ指令、BRK中斷指令、信號處理指令(V5TE版)、協(xié)處理器的更多可選擇的指令。

(6)V6版架構(gòu)是2001年發(fā)布的。其基本特點包括100%與以前的體系兼容;SIMD媒體擴展,使媒體處理速度快了1.75倍;改進了內(nèi)存管理,使系統(tǒng)性能提高30%;改進了混合端(Endian)與不對齊數(shù)據(jù)支持,使得小端系統(tǒng)支持大端數(shù)據(jù)(如TCP/IP)。例如,許多RTOS是小端的,為實時系統(tǒng)縮短了中斷響應時間,將最壞情況下的35周期減小為11個周期。

(7)V7版架構(gòu)是2005年發(fā)布的。它使用了能夠帶來更高性能、功耗效率和代碼密度的Thumb-2技術(shù)。它首次采用了強大的信號處理擴展集,對H.264和MP3等媒體編解碼提供了加速功能。Cortex-M3處理器采用的就是V7版架構(gòu)。

(8)V8版架構(gòu)開始支持64位體系結(jié)構(gòu),它包括以下部分。

① 64位通用寄存器、SP(堆棧指針)和PC(程序計數(shù)器)。

② 64位數(shù)據(jù)處理和擴展的虛擬尋址。

③ 兩種主要執(zhí)行狀態(tài)。

a.AArch64-64位執(zhí)行狀態(tài),包括該狀態(tài)的異常模型、內(nèi)存模型、程序員模型和指令集支持。

b.AArch32-32位執(zhí)行狀態(tài),包括該狀態(tài)的異常模型、內(nèi)存模型、程序員模型和指令集支持。

④ 支持三個主要指令集。

a.A32(或ARM):32位固定長度指令集,通過不同體系結(jié)構(gòu)變體增強。部分32位體系結(jié)構(gòu)執(zhí)行環(huán)境現(xiàn)在稱為AArch32。

b.T32(Thumb):以16位固定長度指令集的形式引入,隨后在引入Thumb-2技術(shù)時增強為16位和32位混合長度指令集。

c.A64:提供與ARM和Thumb指令集有類似功能的32位固定長度指令集。它隨ARMv8-A一起引入,是一種AArch64指令集。

2.處理器內(nèi)核的歷史

ARM公司開發(fā)了多種處理器內(nèi)核,目前廣泛使用的有ARM7系列、ARM9系列、ARM9E系列、ARM11系列、SecurCore系列及Cortex系列。不同處理器內(nèi)核使用不同的體系結(jié)構(gòu)版本。

如表1-1所示是ARM內(nèi)核與ARM體系結(jié)構(gòu)版本的對應關(guān)系。

表1-1 ARM內(nèi)核與ARM體系結(jié)構(gòu)版本的對應關(guān)系

下面對幾種使用廣泛的ARM內(nèi)核做簡單介紹。

1)ARM7系列

ARM7系列具有三級流水、空間統(tǒng)一的指令與數(shù)據(jù)Cache、平均功耗為0.6mW/MHz、時鐘速度為66MHz、每條指令平均執(zhí)行1.9個時鐘周期等特性。其中ARM710、ARM720和ARM740為內(nèi)帶Cache的ARM內(nèi)核。ARM7指令集與Thumb指令集擴展組合在一起,可以減少內(nèi)存容量和系統(tǒng)成本。同時,它還利用嵌入式ICE調(diào)試技術(shù)來簡化系統(tǒng)設計,并用一個DSP增強擴展來改進性能。ARM7體系結(jié)構(gòu)是小型、快速、低能耗、集成式的RISC內(nèi)核結(jié)構(gòu)。該產(chǎn)品的典型用途是數(shù)字蜂窩電話和硬盤驅(qū)動器等。目前主流的ARM7內(nèi)核是ARM7TDMI、ARM7TDMI-S、ARM7EJ-S、ARM720T?,F(xiàn)在市場上用得最多的ARM7系列有思智浦公司的LPC2000系列微控制器、Samsung公司的S3C44BOX與S3C4510處理器、Atmel公司的AT91FR40162系列處理器、Cirrus公司的EP73xx系列等。該系列包括ARM7TDMI、ARM7TDMI-S、帶有高速緩存處理器宏單元的ARM720T和擴充了Jazelle的ARM7EJ-S等。這些處理器提供Thumb 16位壓縮指令集和EmbededICE軟件調(diào)試方式,適用于更大規(guī)模的SoC設計中。

ARM7系列廣泛應用于多媒體和嵌入式設備中,包括互聯(lián)網(wǎng)設備、網(wǎng)絡和調(diào)制解調(diào)器設備,以及移動電話、PDA等無線設備。

2)ARM9E系列

ARM9系列采用了ARMV4T(哈佛)體系結(jié)構(gòu)。由于這種體系結(jié)構(gòu)中的程序和數(shù)據(jù)存儲器在兩個分開的物理空間中,所以取指和執(zhí)行能完全重疊。ARM9采用五級流水處理及分離的Cache結(jié)構(gòu),平均功耗為0.7mW/MHz。其時鐘速度為120~200MHz,每條指令平均執(zhí)行1.5個時鐘周期。與ARM7系列相似,ARM9系列中的ARM920、ARM940和ARM9E處理器均為含有Cache的CPU核,其性能(速率)為132MIPS(120MHz時鐘,3.3V供電)或220MIPS(200MHz時鐘)。ARM9系列同時也配備了Thumb指令擴展、調(diào)試,以及Harvard總線。在生產(chǎn)工藝相同的情況下,其性能(速率)是ARM7TDMI處理器的兩倍。它常用于無線設備、儀器儀表、聯(lián)網(wǎng)設備、機頂盒設備、高端打印機及數(shù)碼相機應用中。ARM9E內(nèi)核在ARM9內(nèi)核的基礎(chǔ)上增加了緊密耦合存儲器TCM及DSP部分。目前主流的ARM9內(nèi)核是ARM920T、ARM922T、ARM940。相關(guān)的處理器芯片有Samsung公司的S3C2510、Cirrus公司的EP93xx系列等。主流的ARM9E內(nèi)核是ARM926EJ-S、ARM946E-S、ARM966E-S等。

3)SecurCore系列

SecurCore系列提供了基于高性能的32位RISC技術(shù)的安全解決方案,該系列具有體積小、功耗低、代碼密度大和性能高等特點。另外,最為特別的是,該系列提供了安全解決方案。它采用軟內(nèi)核技術(shù),以提供最大限度的靈活性,以及防止外部對其進行掃描探測;提供面向智能卡的和低成本的存儲保護單元MPU,可以靈活地集成用戶自己的安全特性和其他的協(xié)處理器。該系列目前包括SC100、SC110、SC200、SC210共4種產(chǎn)品。

4)ARM11系列

ARM11系列可以在使用130nm工藝技術(shù)、芯片面積小至2.2mm2和功率低至0.24mW/MHz的前提下獲得高達500MHz的速率。ARM11系列處理器以眾多消費產(chǎn)品市場為目標,推出了許多新的技術(shù),包括針對媒體處理的SIMD,用以提高安全性能的TrustZone技術(shù),智能能源管理(IEM),以及需要非常高的、可升級的超過2600 Dhrystone 2.1 MIPS性能的系統(tǒng)多處理技術(shù)。主要的ARM11系列處理器有ARM1136JF-S、ARM1156T2F-S、ARM1176JZF-S、ARM11 MCORE等多種。

5)ARM Cortex系列

ARM Cortex系列基于ARMV7架構(gòu),又分為Cortex-M、Cortex-R和Cortex-A 3類。ARM Cortex系列的3款產(chǎn)品全都集成了Thumb?-2指令集,可滿足各種不同的日益增長的市場需求。ARM Cortex系列的3款處理器瞄準的領(lǐng)域如下。

(1)ARM Cortex-A系列:針對復雜操作系統(tǒng)及用戶應用設計的應用處理器。

(2)ARM Cortex-R系列:針對實時系統(tǒng)專用嵌入式處理器。

(3)ARM Cortex-M系列:針對微控制器和低成本應用、專門優(yōu)化的深嵌入式處理器。

Cortex-M3是首款基于ARMV7-M架構(gòu)的處理器,專門瞄準對功耗和成本敏感的嵌入式應用,是為使其實現(xiàn)高性能而設計的,它大大簡化了可編程的復雜性,使得ARM體系結(jié)構(gòu)成為各種應用方案(即使是最簡單的方案)的上佳選擇。

注意:NXP公司的LPC17XX系列屬于Cortex-M3的核;LPC11XX系列屬于Cortex-M0的ARM核。

Cortex系列處理器并沒有開拓新的應用領(lǐng)域,從某種意義上講,它是對原有應用領(lǐng)域的主流產(chǎn)品的一次大升級,提供了更好的性能。Cortex系列處理器對應于原有的歷史上的各種處理核。ARM公司給出了各種產(chǎn)品的替代關(guān)系表,如表1-2所示。Cortex系列處理器主要是針對ARM11、ARM9、ARM7 3款經(jīng)典處理器的升級。

表1-2 Cortex-M0/M3與ARM7/9/11的替代關(guān)系

1.1.2 Cortex-M3的特征

Cortex-M3是一個32位處理器內(nèi)核。它基于哈佛構(gòu)架,其指令和數(shù)據(jù)各使用一條總線,集成了分支預測、單周期乘法、硬件除法等特性。Cortex-M3增加了MPU,用于重要數(shù)據(jù)的保護及特權(quán)處理。它適用于高確定性的實時應用,適用于汽車車體系統(tǒng)、控制系統(tǒng)及無線網(wǎng)絡和傳感器等多個應用場合。

Cortex-M3的特點有以下幾個。

(1)功耗低:Cortex-M3使用了最少的ARM內(nèi)核,內(nèi)核的核心部分(0.18um G)的門數(shù)僅為33000個,并支持擴展時鐘門控和集成睡眠模式,使得Cortex-M3的功耗低,滿足目前的白色家電和無線網(wǎng)絡市場對低功耗的要求。

(2)位帶操作:Cortex-M3支持兩塊位帶存儲區(qū)域,其中一塊區(qū)域是SRAM,另一塊區(qū)域是外設區(qū)。使用位帶操作可簡化外設控制流程。另外,通過使用布爾變量操作位帶別名區(qū)可實現(xiàn)對位帶區(qū)的單位操作,從而降低SRAM的使用率。

(3)采用Thumb?-2指令集,能夠執(zhí)行硬件除法、單周期乘法和位字段操作,從而獲取最佳的性能和代碼大小。

(4)低延遲中斷處理機制:Cortex-M3處理器中集成的NVIC可實現(xiàn)硬件中斷處理及低延遲,有利于減弱中斷處理對處理器性能的影響。NVIC和處理器的緊密集成加快了中斷服務程序的執(zhí)行速度,并減少了進入中斷所需的周期數(shù)。

(5)Cortex-M3 NVIC在設計時是可配置的,最多可提供240個具有單獨優(yōu)先級、動態(tài)重設優(yōu)先級功能和集成系統(tǒng)時鐘的系統(tǒng)中斷。

(6)支持兩種工作模式(線程模式和處理器模式)及兩個等級(有特權(quán)和無特權(quán))的代碼訪問,在不犧牲應用程序安全性的前提下執(zhí)行復雜的開放式系統(tǒng)。

(7)豐富的連接功能和性能的組合使基于Cortex-M3的設備可以有效處理多個I/O通道和協(xié)議標準,如USB OTG(On-The-Go)。

(8)開發(fā)工具的多樣化:串行線調(diào)試端口或串行線JTAG調(diào)試端口。

(9)ARM提供標準的CMSIS標準支持。

Cortex-M0/M3是針對ARM7TDMI-S用戶群體設計的,ARM公司給出了將ARM7TDMI-S升級到Cortex-M0/3的益處,以及ARM7TDMI-S與Cortex-M0/3的性能對比,如表1-3所示。

表1-3 ARM7TDMI-S與Cortex-M0/3的對比關(guān)系表

如圖1-1所示是Cortex-M3的內(nèi)部功能接口框圖。

圖1-1 Cortex-M3的內(nèi)部功能接口框圖

NVIC是Cortex-M3處理器中一個完整的部分,它可以進行高度配置,為處理器提供出色的中斷處理能力。在NVIC的標準執(zhí)行中,它提供了1個非屏蔽中斷(NMI)和32個通用物理中斷,這些中斷帶有8級的搶占優(yōu)先權(quán)。NVIC可以通過綜合選擇配置為1~240個物理中斷中的任何一個,并帶有多達256個優(yōu)先級。

MPU是Cortex-M3處理器中一個可選的部分,它通過保護用戶應用程序中操作系統(tǒng)所使用的重要數(shù)據(jù),分離處理任務(禁止訪問各自的數(shù)據(jù)),禁止訪問存儲器區(qū)域,將存儲器區(qū)域定義為只讀,以及對有可能破壞系統(tǒng)的未知的存儲器訪問進行檢測等手段來改善嵌入式系統(tǒng)的可靠性。

對Cortex-M3處理器系統(tǒng)的調(diào)試訪問是通過調(diào)試訪問端口(Debug Access Port)來實現(xiàn)的。該端口可以作為串行線調(diào)試端口(SW-DP)[構(gòu)成一個兩腳(時鐘和數(shù)據(jù))接口]或串行線JTAG調(diào)試端口(SWJ-DP)(使能JTAG或SW協(xié)議)使用。SWJ-DP在上電復位時默認為JTAG模式,并且可以通過外部調(diào)試硬件所提供的控制序列進行協(xié)議的切換。

總線矩陣用來將處理器和調(diào)試接口與外部總線相連。總線矩陣與下面的外部總線相連。

(1)I-Code總線:該總線用于從代碼空間取指令和向量,是32位AHB-Lite總線。

(2)D-Code總線:該總線用于對代碼空間進行數(shù)據(jù)加載/存儲及調(diào)試訪問,是32位AHB-Lite總線。

(3)系統(tǒng)總線:該總線用于對系統(tǒng)空間執(zhí)行取指令和向量,數(shù)據(jù)加載/存儲及調(diào)試訪問,是32位AHB-Lite總線。

(4)PPB:該總線用于對PPB空間進行數(shù)據(jù)加載/存儲及調(diào)試訪問,是32位APB(v2.0)總線。

總線矩陣還對以下方面進行控制。

(1)非對齊訪問:總線矩陣將非對齊的處理器訪問轉(zhuǎn)換為對齊訪問。

(2)總線矩陣將位帶別名訪問轉(zhuǎn)換為對位帶區(qū)的訪問:對位帶加載進行位域提??;對位帶存儲進行原子讀—修改—寫;寫緩沖??偩€矩陣包含一個單入口寫緩沖區(qū),該緩沖區(qū)使得處理器內(nèi)核不受到總線延遲的影響。

1.2 內(nèi)核寄存器

Cortex-M3處理器擁有R0~R15的寄存器組,其中R13用做堆棧指針SP(SP有兩個,但在同一時刻只能有一個可以看到),R14為寄存器,R15為程序計數(shù)寄存器。Cortex-M3有5個專用寄存器。

如表1-4所示是Cortex-M3的寄存器表,該表中給出了是否需要特權(quán)才能訪問的情況。

表1-4 Cortex-M3的寄存器表

1.2.1 通用寄存器

R0~R12都是32位通用寄存器,用于數(shù)據(jù)操作,保存數(shù)據(jù)或地址值。R0~R7被稱為低寄存器,其余的被稱為高寄存器。16位Thumb指令只能訪問R0~R7,而32位Thumb-2指令可以訪問所有寄存器。

1.2.2 連接寄存器

連接寄存器在匯編代碼中可以寫成R14或LR。它用于存儲函數(shù)調(diào)用(程序寄存器返回值)和異常的返回信息。當執(zhí)行分支(branch)和鏈接(BL)指令或帶有交換的分支和鏈接指令(BLX)時,LR用于接收來自PC的返回地址。復位時,LR的數(shù)值為0xFFFFFFFF。

startup_LPC17xx.s文件中定義了__user_initial_stackheap函數(shù),該函數(shù)由MDK自動調(diào)用,不用用戶調(diào)用。其格式如下:

            __user_initial_stackheap
            …
            BX     LR;返回

1.2.3 程序計數(shù)器

程序計數(shù)器(PC)指向當前的程序地址。如果修改它的值,就能改變程序的執(zhí)行流。PC[0]總是0,這是因為指令的取值必須按半字對齊。復位時,處理器用復位向量的值加載PC,復位向量地址為0x00000004。

1.2.4 專用寄存器

Cortex-M3包含了一些專用寄存器,主要有3種類型,5(或者說7)個寄存器,這些寄存器只能通過MSR或MRS指令操作,無對應內(nèi)存地址。

(1)程序狀態(tài)寄存器:該寄存器又分為3個子狀態(tài)寄存器,分別是應用程序狀態(tài)寄存器(APSR)、中斷號狀態(tài)寄存器(IPSR)、執(zhí)行狀態(tài)寄存器(EPSR)。

(2)中斷屏蔽寄存器,有PRIMASK、FAULTMASK、BASEPRI。

(3)控制寄存器(CONTROL)。

1.程序狀態(tài)寄存器

程序狀態(tài)寄存器(如表1-5所示)可以作為一個整體訪問或通過APSR、IPSR、EPSR形式獨立訪問。程序狀態(tài)寄存器作為一個整體訪問時,寄存器的名字是“xPSR”。可以使用MRS指令讀取程序狀態(tài)寄存器的內(nèi)容,使用MSR指令改變APSR的內(nèi)容;EPSR和IPSR為只讀寄存器。CMSIS中的core_cm3.c給出了__get_IPSR, __get_xPSR, __get_APSR 3個函數(shù)實現(xiàn)讀取APSR、IPSR與xPSR,其中__get_APSR的代碼如下,該函數(shù)通過MRS指令讀取APSR。

表1-5 程序狀態(tài)寄存器

            __ASM uint32_t __get_APSR(void)
            {
            mrs r0, apsr
            bx lr
            }

當需要讀取EPSR及設置APSR寄存器時,可通過以下兩條指令實現(xiàn):

            MRS r0,EPSR
            MSR APSR,r0

2.中斷屏蔽寄存器

中斷屏蔽寄存器用于實現(xiàn)對中斷的開放與關(guān)閉。中斷屏蔽寄存器主要有PRIMASK、FAULTMASK、BASEPRI。

(1)PRIMASK:只有一位的寄存器。該寄存器被置1后,除了NMI和硬故障(hard fault)之外的所有異常將被關(guān)閉;寫0,不影響。在特權(quán)模式下,可通過MSR、MRS、CPS指令對該寄存器進行訪問。

(2)FAULTMASK:只有一位的寄存器。該寄存器被置1后,除NMI外的所有異常將被關(guān)閉。在特權(quán)模式下,可通過MSR、MRS、CPS指令對該寄存器進行訪問。

(3)BASEPRI:定義了屏蔽異常的最低優(yōu)先級。當BASEPRI設置為某數(shù)值時,所有不大于數(shù)值的異常將被屏蔽;寫0,不影響。

對時序要求嚴格的應用程序,可以通過PRIMASK與BASEPRI寄存器臨時屏蔽中斷,以達到時序控制目的。FAULTNASK主要用于在操作系統(tǒng)中關(guān)閉任務崩潰的各種異常。

CMSIS提供了如下函數(shù),用于讀取或設置中斷屏蔽寄存器:

            uint32_t __get_PRIMASK(void)
            uint32_t  __get_BASEPRI(void)
            uint32_t  __get_FAULTMASK(void)
            void __set_BASEPRI(uint32_t basePri)
            void __set_FAULTMASK(uint32_t faultMask)
            void __set_PRIMASK(uint32_t priMask)

3.控制寄存器

控制寄存器(CONTROL)主要用于定義特權(quán)級別,以及選擇使用哪個堆棧指針。

如表1-6所示是控制寄存器的位含義。

表1-6 控制寄存器的位含義

在處理模式下,始終使用主堆棧指針MSP。只有在異常進入和返回情況下,才會更新控制寄存器。

CONTROL[0]:僅當在特權(quán)級下操作時才允許寫該位。一旦進入了用戶級,唯一返回特權(quán)級的途徑就是觸發(fā)一個(軟)中斷(SVC指令),再由服務例程改寫該位。

CMSIS中提供了對該寄存器進行訪問及操作的函數(shù):

            __get_CONTROL();// 讀取當前CONTROL寄存器中的內(nèi)容
            __set_CONTROL(x);// 設置CONTROL寄存器中的內(nèi)容

1.3 操作模式和特權(quán)級別

Cortex-M3有兩種操作模式,分別是線程模式和處理器模式,它們與ARM7TDM的操作模式有很大的區(qū)別。這兩個模式的訪問方式為特權(quán)和非特權(quán)方式,可以在不犧牲應用程序安全的前提下實現(xiàn)對復雜的開放式系統(tǒng)的執(zhí)行。

線程模式:用于執(zhí)行應用軟件。處理器在退出復位時進入線程模式。該模式是常用的工作模式。它同時支持享有特權(quán)的代碼和沒有特權(quán)的代碼。

處理器模式(handler mode):用于處理異常。處理器在完成異常處理后退回線程模式。該模式中的所有代碼都享有特權(quán)。

軟件執(zhí)行的特權(quán)級別分別為非特權(quán)等級(或者稱為用戶等級)和特權(quán)等級。

非特權(quán):對MSR和MRS指令的有限訪問權(quán)限,且不能執(zhí)行CPS指令;不能訪問系統(tǒng)定時器、NVIC、系統(tǒng)控制模塊;可能限制對存儲器或外設的訪問。

特權(quán):軟件可使用所有指令,并可訪問全部資源。

如圖1-2所示是操作模式與特權(quán)等級之間的切換過程。

圖1-2 操作模式與特權(quán)等級之間的切換過程

特權(quán)級下的代碼可以通過置位CONTROL[0]來進入用戶級。不管是由于什么原因產(chǎn)生了什么異常,處理器都將用特權(quán)級來運行其服務例程,異常返回后,處理器將回到產(chǎn)生異常時所處的級別。用戶級下的代碼不能再通過試圖修改CONTROL[0]來回到特權(quán)等級。它必須通過SVC指令實現(xiàn)一個異常處理器模式,由這個異常處理器模式來修改CONTROL[0],然后才能在返回線程模式后拿到特權(quán)等級。

1.4 存儲器映射

ARM7內(nèi)核沒有定義存儲器映射,各芯片廠商自己定義了存儲器映射。Cortex-M3內(nèi)核規(guī)定了存儲器映射,從而使得各廠商生產(chǎn)的基于Cortex-M3內(nèi)核的微控制器芯片具有相同的存儲器映射。Cortex-M3留給了各廠商存儲器空間,廠商可在此基礎(chǔ)上進行擴展使用。本節(jié)將介紹Cortex-M3預定義的存儲器映射,并說明LPC17XX在遵照Cortex-M3的預定義基礎(chǔ)上使用的預留空間情況。

1.4.1 地址空間

Cortex-M3采用了預定義的內(nèi)存映射方式。Cortex-M3的中斷控制器及調(diào)試組件可通過簡單的內(nèi)存存儲指令進行訪問,從而使得軟件設計適合用C語言編程實現(xiàn)。預定義的內(nèi)存方式使得Cortex-M3更優(yōu)化與高度集成。

如圖1-3所示是Cortex-M3預定義的存儲器映射,其空間是4G(0x00000000~0xFFFFFFFF)。

圖1-3 Cortex-M3預定義的存儲器映射

程序可以在代碼區(qū)(0x00000000~0x1FFFFFFF)、內(nèi)部SRAM區(qū)及外部RAM區(qū)中執(zhí)行。由于指令總線與數(shù)據(jù)總線是分開的,所以最理想的是把程序放到代碼區(qū),從而使取指和數(shù)據(jù)訪問各自使用自己的總線。

片上SRAM區(qū)的大小是512MB,用于讓芯片制造商連接片上的SRAM,這個區(qū)通過系統(tǒng)總線來訪問。有一個1MB的區(qū)間被稱為“位帶區(qū)”。該位帶區(qū)還有一個對應的32MB的“位帶別名(alias)區(qū)”。位帶區(qū)對應的是最低的1MB地址范圍,而位帶別名區(qū)里的每個字對應的是位帶區(qū)的一個比特。位帶操作只適用于數(shù)據(jù)訪問,不適用于取指。通過位帶的功能,可以把多個布爾型數(shù)據(jù)打包在單一的字中,但是依然可以從位帶別名區(qū)中像訪問普通內(nèi)存一樣地使用它們。

片上外設區(qū)(0x40000000~0x5FFFFFFF)供片上寄存器使用。這個區(qū)中也有一個32MB的位帶別名區(qū),以便于快捷地訪問外設寄存器,其用法與內(nèi)部SRAM區(qū)中的位帶相同。例如,可以方便地訪問各種控制位和狀態(tài)位。要注意的是,外設區(qū)內(nèi)不允許執(zhí)行指令。

0x60000000~0x9FFFFFFF區(qū)域與0xA0000000~0xDFFFFFFF區(qū)域分別用于連接外部RAM和外部設備,它們之中沒有位帶。兩者的區(qū)別在于外部RAM區(qū)允許執(zhí)行指令,而外部設備區(qū)則不允許執(zhí)行指令。

0xE0000000~0xE00FFFFF是Cortex-M3獨立擁有的區(qū)域,該區(qū)域不提供給芯片制造廠家使用。如圖1-4所示是Cortex-M3的私有外設總線的內(nèi)存映射圖。私有外設總線有以下兩條。

圖1-4 Cortex-M3的私有外設總線的內(nèi)存映射圖

(1)AHB私有外設總線:只用于CM3內(nèi)部的AHB外設,它們是NVIC,F(xiàn)PB,DWT和ITM。

(2)APB私有外設總線:既用于CM3內(nèi)部的APB設備,也用于外部設備(指的是芯片生產(chǎn)廠家的APB外設)。CM3允許芯片生產(chǎn)廠家增添一些片上APB外設到APB私有總線上,它們通過APB接口來訪問。

下面來看一下LPC17XX是如何使用Cortex-M3規(guī)定的內(nèi)存映射的。如表1-7所示是LPC17XX的內(nèi)存映射。LPC17XX在Cortex-M3的預定義的代碼區(qū)中有64KB的SRAM,該部分用于執(zhí)行代碼與保存數(shù)據(jù)。

表1-7 LPC17XX的內(nèi)存映射

如圖1-5所示是LPC1768的存儲器映射情況。LPC177X/LPC178X與LPC1768除了AHB外設(即DMA、USB、以太網(wǎng)及新增加的LCD)的存儲空間不一樣外,其余的APB占用空間幾乎一樣。Cortex-M3的內(nèi)核空間均符合Cortex-M3的存儲空間分配要求。

圖1-5 LPC176X的存儲器映射情況

技巧:編譯程序時,輸出map文件可以查看內(nèi)存分配情況,以及程序代碼、數(shù)據(jù)占用空間情況。

1.4.2 位帶操作

1.位帶概念

位帶(bit-band)操作更像C語言中的union與struct相結(jié)合后的位操作。為了更好地理解它,下面先舉一個例子:

            struct_Bitband_Alias_Bits  {
                Uint32 Alias0:1;
            …
                Uint32 Alias31:1;
            };
            @@@
            union BitBand_Operator {
                Uint32  BitBand;
                struct  _Bitband_Alias_Bits Bitband_Alias_Bits;
            };
        BitBand_Operator myBitBand;

由上述程序可知,通過myBitband. Bitband_Alias_Bits. Alias0的訪問是通過對myBitBand. BitBand的第0位操作實現(xiàn)的。

Cortex-M3的位帶操作類似于上面的C語言操作方式,但區(qū)別在于BitBand與Bitband_Alias_Bits是兩塊獨立的內(nèi)存地址,而且位帶操作中的Alias0代表一個32位的數(shù)據(jù),但只有最低0位是有效數(shù)據(jù)。

Cortex-M3支持了位帶操作后,可以使用普通的加載/存儲指令來對單一的比特進行讀/寫。在Cortex-M3中,有兩個區(qū)中實現(xiàn)了位帶:一個是SRAM區(qū)的最低1MB范圍(0x20000000-0x200FFFFF),對應的位帶別名區(qū)是0x22000000~0x23FFFFFF;第二個則是片內(nèi)外設區(qū)的最低1MB范圍(0x40000000~0x400FFFFF),對應的別名區(qū)是0x42000000~0x43FFFFFF。

映射公式顯示如何將別名區(qū)中的字與bit-band區(qū)中的對應位或目標位關(guān)聯(lián)。映射公式舉例:

        bit_word_offset=(byte_offset×32)+(bit_number×4)
        bit_word_addr=bit_band_base+bit_word_offset

這里:

        Bit_word_offset為bit-band存儲區(qū)中的目標位的位置;
        Bit_word_addr為別名存儲區(qū)中映射為目標位的字的地址;
        Bit_band_base是別名區(qū)的開始地址;
        Bit_offset為bit-band區(qū)中包含目標位的字節(jié)的編號;
        Bit_number為目標位的位置(0~7)。

如圖1-6所示為SRAM位帶區(qū)與對應的別名區(qū)之間的關(guān)系圖。圖1-6中箭頭所指映射的轉(zhuǎn)換關(guān)系如下:

圖1-6 SRAM位帶區(qū)與對應的別名區(qū)之間的關(guān)系圖

        地址0x23FFFFE0的別名字映射為0x200FFFFC的位帶字節(jié)的位0:
        0x23FFFFE0=0x22000000+(0xFFFFF*32)+0*4
        地址 0x23FFFFEC的別名字映射為 0x200FFFFC的位帶字節(jié)的位 7:
        0x23FFFFEC=0x22000000+(0xFFFFF*32)+7*4
        地址 0x22000000 的別名字映射為 0x20000000 的位帶字節(jié)的位 0:
        0x22000000=0x22000000+(0*32)+0*4
        地址 0x220001C的別名字映射為 0x20000000 的位帶字節(jié)的位 0:
        0x2200001C=0x22000000+(0*32)+7*4

2.位帶操作方法

向別名區(qū)中的一個字執(zhí)行寫操作會更新位帶區(qū)中的單個位。但并不是別名區(qū)的所有位都有效,別名區(qū)的一個字的第0位是有效的,會影響對應位帶區(qū)的數(shù)值,即向別名區(qū)中的一個字寫入值的位[0]決定了寫入位帶區(qū)中目標位的值:寫入一個位[0]設為1的值,則會向位帶位寫入一個1;寫入一個位[0]設為0的值,則會向位帶位寫入一個0。

注意:別名字的位[31:1]對位帶位無影響,寫入0x01與寫入0xFF效果相同,寫入0x00與寫入0x0E效果相同。

讀取別名區(qū)中的一個字,如讀取數(shù)據(jù)為

(1)0x00000000,表示位帶區(qū)中的目標位被設為0;

(2)0x00000001,表示位帶區(qū)中的目標位被設為1。

位帶區(qū)的訪問可通過字節(jié)、半字、字的方式進行訪問。

通過C語言實現(xiàn)對Cortex-M3的位帶操作一般使用宏定義方式進行,并通過“1位帶概念”中的位帶與別名區(qū)映射公式進行。下列代碼給出的定義中采用了右移代替乘法運算。

        /*SRAM的位帶區(qū)與別名區(qū)對應地址*/
        #define BITBAND_SRAM_REF   0x20000000
        #define BITBAND_SRAM_BASE  0x22000000
        // 將位帶地址轉(zhuǎn)換到別名區(qū),其中a代表位帶區(qū)地址,b代表要轉(zhuǎn)換的位帶字節(jié)的位數(shù)
        #define BITBAND_SRAM(a,b) ((BITBAND_SRAM_BASE + ((a-BITBAND_SRAM_REF)<<5) +
(b<<2)))
        /* 外設位帶地址宏定義 */
        #define BITBAND_PERI_REF   0x40000000
        #define BITBAND_PERI_BASE  0x42000000
        // 將位帶地址轉(zhuǎn)換到別名區(qū),其中a代表位帶區(qū)地址,b代表要轉(zhuǎn)換的位帶字節(jié)的位數(shù)
        #define BITBAND_PERI(a,b)((BITBAND_PERI_BASE+((a-BITBAND_PERI_REF)<<5)+(b<<2)))

當使用位帶功能時,要訪問的變量必須用volatile來定義。因為C編譯器并不知道同一個比特可以有兩個地址,所以需要通過volatile使編譯器每次都如實地把新數(shù)值寫入存儲器中,而不再出于優(yōu)化的考慮,在中途使用寄存器來操作數(shù)據(jù)的復本,直到最后才把復本寫回——這會導致按不同的方式訪問同一個位得到不一致的結(jié)果。

小知識:對于volatile聲明的變量,編譯器在訪問該變量的代碼時不再進行優(yōu)化,從而可以提供對特殊地址的穩(wěn)定訪問。

下列程序演示了通過位帶方式操作SPI控制寄存器的過程。

        /* SRAM的位帶區(qū)與別名區(qū)對應地址*/
        #define BITBAND_SRAM_REF   0x20000000
        #define BITBAND_SRAM_BASE  0x22000000
        // 將位帶地址轉(zhuǎn)換到別名區(qū),其中a代表位帶區(qū)地址,b代表要轉(zhuǎn)換的位帶字節(jié)的位數(shù)
        #define BITBAND_SRAM(a,b) ((BITBAND_SRAM_BASE + ((a-BITBAND_SRAM_REF)<<5) +
    (b<<2)))
        /* 外設位帶地址宏定義 */
        #define BITBAND_PERI_REF   0x40000000
        #define BITBAND_PERI_BASE  0x42000000
        // 將位帶地址轉(zhuǎn)換到別名區(qū),其中a代表位帶區(qū)地址,b代表要轉(zhuǎn)換的位帶字節(jié)的位數(shù)
        #define BITBAND_PERI(a,b) ((BITBAND_PERI_BASE + ((a-BITBAND_PERI_REF)<<5) + (b<<2)))
        /* 位帶區(qū)操作函數(shù) */
        #define BITBAND_SRAM_ClearBit(a,b) (*(volatile uint32_t *) (BITBAND_SRAM(a,b)) = 0)
        #define BITBAND_SRAM_SetBit(a,b) (*(volatile uint32_t*)(BITBAND_SRAM(a,b))=1)
        #define BITBAND_SRAM_GetBit(a,b) (*(volatile uint32_t *) (BITBAND_SRAM(a,b)))
    @@@
        #define BITBAND_PERI_ClearBit(a,b) (*(volatile uint32_t *) (BITBAND_PERI(a,b)) = 0)
        #define BITBAND_PERI_SetBit(a,b)  (*(volatile uint32_t*)(BITBAND_PERI(a,b))=1)
        #define BITBAND_PERI_GetBit(a,b)  (*(volatile uint32_t*)(BITBAND_PERI(a,b)))
        #define VAR_ADDRESS      LPC_GPIO2_BASE//0x2007C000
        #define VAR_BIT           3//bit 3
    @@@
        #define PERI_ADDRESS  0x40020000//SPI控制寄存器地址(S0SPCR)
        #define PERI_BIT       5//bit 5-Master mode select(主模式選擇)
        uint32_t temp;
        uint32_t temp1;
    @@@
        int main(void) {
    @@@
          //SRAM
              temp = (*(volatile uint32_t *)(VAR_ADDRESS));
          temp1 = BITBAND_SRAM_GetBit(VAR_ADDRESS,VAR_BIT);
          if(temp1==(temp&1<<VAR_BIT))
          {
          ;//可在此設置斷點,驗證結(jié)果的正確性
          }
    @@@
          //設置第3位為1
          BITBAND_SRAM_SetBit(VAR_ADDRESS,VAR_BIT);
          temp=(*(volatile uint32_t*)(VAR_ADDRESS));  //temp的第3位為1,即temp=0x8
          temp1= BITBAND_SRAM_GetBit(VAR_ADDRESS,VAR_BIT); //temp1 =1
          //外設區(qū)代碼演示
          LPC_SPI->SPCR=(1<<5);  //直接設置0x40020000
          temp1 = (*(volatile uint32_t *)(PERI_ADDRESS));//讀取0x40020000
          temp=BITBAND_PERI_GetBit(PERI_ADDRESS,PERI_BIT);  //讀取對應別名區(qū),即temp=1
          BITBAND_PERI_ClearBit(PERI_ADDRESS,PERI_BIT);
          temp=BITBAND_PERI_GetBit(PERI_ADDRESS,PERI_BIT);  //temp=0
          temp1=(*(volatile uint32_t*)(PERI_ADDRESS));
          BITBAND_PERI_SetBit(PERI_ADDRESS,PERI_BIT);
          temp=BITBAND_PERI_GetBit(PERI_ADDRESS,PERI_BIT);  //temp=1
          temp1=(*(volatile uint32_t*)(PERI_ADDRESS));   //temp1=0x20,即temp結(jié)果右移5位
          while(1);
          return 0;
        }

3.位帶操作的用途

對應于LPC17XX的外設,所有外設(除了以太網(wǎng)、USB、DMA、GPIO以外)都位于位帶操作區(qū)域。APB0與APB1對應的外設內(nèi)存都屬于位帶區(qū)域。

注意:由于GPIO不屬于位帶區(qū),所以如果經(jīng)常需要設置引腳狀態(tài)時,不能通過位帶方式進行操作。

1.4.3 端模式

Cortex-M3支持32位字、16位半字、8位字節(jié)數(shù)據(jù)類型。Cortex-M3處理器將存儲器看做一個從0開始增長的線性集合。存儲器可理解成:

(1)地址0~3保存了第一個要保存的字。

(2)地址4~7保存了第二個要保存的字。

Cortex-M3支持大端模式和小端模式(但對應于具體芯片時,可能不遵守這個約定)。可以通過讀取AIRCR.ENDIANNESS的位判斷當前的端模式。端模式的配置通過Cortex-M3提供的BIGEND引腳進行。

注意:LPC17XX僅支持小端模式,不支持大端模式。它沒有提供配置引腳。如果程序中出現(xiàn)大端模式需求,需要自己手工解決這個問題(即大端模式需求)。

鑒于LPC17XX僅支持小端模式,本節(jié)僅給出小端模式的概念。

小端模式是指處理器將一個字的最低(有效)位位字節(jié)存儲在序號最小的字節(jié)中,將最高(有效)位位字節(jié)存儲在序號最大的字節(jié)中。圖1-7給出了小端模式下,在地址A到地址A+3之間如何保存一個字數(shù)據(jù)及將數(shù)據(jù)存儲在寄存器中的情況。

圖1-7 小端模式舉例

1.5 總線接口

Cortex-M3內(nèi)部有若干條總線接口,使得Cortex-M3能同時取指和訪問內(nèi)存。本節(jié)將介紹各總線,以及LPC17XX的總線對應的外設情況。

1.5.1 3級流水線

原有的ARM7TDMI的指令執(zhí)行速度為0.9MIPS/MHz。目前采用ARMv6構(gòu)建的Cortex-M0已經(jīng)可以達到這個執(zhí)行速度,而采用哈佛總線結(jié)構(gòu)的Cortex-M3的指令執(zhí)行速度可達到1.25 DMIPS/MHz。Cortex-M3處理器使用一個3級流水線。流水線的3級分別是取指、譯碼和執(zhí)行,如圖1-8所示。

圖1-8 Cortex-M3的3級流水線

由于使用了指令流水線,所以讀PC時返回的值是當前指令的地址+4。例如:

    0x1000:   MOV   R0,   PC   ;  讀到R0=0x1004,而不是0x1000

這個偏移量總是4,不管是執(zhí)行16位指令還是32位指令,這就保證了在Thumb和Thumb2之間的一致性。

1.5.2 總線矩陣

總線矩陣用來將處理器和調(diào)試接口與外部總線相連??偩€矩陣與下面的外部總線相連。

(1)I-Code總線:該總線用于從代碼空間取指令和向量,是32位AHB-Lite總線。

(2)D-Code總線:該總線用于對代碼空間進行數(shù)據(jù)加載/存儲及調(diào)試訪問,是32位AHB-Lite總線。

(3)系統(tǒng)總線:該總線用于對系統(tǒng)空間執(zhí)行取指令和向量,數(shù)據(jù)加載/存儲及調(diào)試訪問,是32位AHB-Lite總線。

(4)PPB:該總線用于對PPB空間進行數(shù)據(jù)加載/存儲及調(diào)試訪問,是32位APB(v2.0)總線。

注意:對于多層AHB矩陣,只有當多個主機試圖同時訪問同一矩陣的從機端口時,才會做主機之間的仲裁。在默認情況下,Cortex-M3的D-Code總線有最高優(yōu)先級,然后是I-Code總線。所有其他主機的優(yōu)先級較低。

如圖1-9所示是Cortex-M3總線接口示例,該圖結(jié)合LPC17XX,說明了系統(tǒng)總線與各個設備之間的連接關(guān)系。在LPC17XX中,Cortex-M3內(nèi)核總線通過多層AHB總線矩陣連接各個外設設備。圖1-9中給出的外設是LPC17XX的部分外設。

圖1-9 Cortex-M3總線接口示例

1.I-Code總線

I-Code總線是一條基于AHB-Lite總線協(xié)議的32位總線,負責在0x00000000~0x1FFFFFFF之間的取指操作。取指以字的長度執(zhí)行,即使是對于16位指令也如此。因此,CPU內(nèi)核可以一次取出兩條16位Thumb指令。

2.D-Code總線

D-Code總線也是一條基于AHB-Lite總線協(xié)議的32位總線,負責在0x00000000~0x1FFFFFFF之間的數(shù)據(jù)訪問操作。盡管Cortex-M3支持非對齊訪問,但該總線不允許這樣操作,這是因為處理器的總線接口會把非對齊的數(shù)據(jù)傳送都轉(zhuǎn)換成對齊的數(shù)據(jù)傳送。因此,連接到D-Code總線上的任何設備都只需要支持AHB-Lite的對齊訪問,而不需要支持非對齊訪問。

ARM公司推薦D-Code總線的優(yōu)先級高于I-Code總線的優(yōu)先級。

3.系統(tǒng)總線

系統(tǒng)總線也是一條基于AHB-Lite總線協(xié)議的32位總線,負責在0x20000000~0xDFFFFFFF和0xE0100000~0xFFFFFFFF之間的所有數(shù)據(jù)傳送,取指和數(shù)據(jù)訪問都包括在內(nèi)。和D-Code總線一樣,系統(tǒng)總線的所有數(shù)據(jù)傳送都是對齊的。

4.私有外設總線

私有外設總線是一條基于APB總線協(xié)議的32位總線。此總線負責0xE0040000~0xE00FFFFF之間的私有外設訪問。但是由于此APB存儲空間的一部分已經(jīng)被TPIU、ETM及ROM表用掉了,所以只留下0xE0042000~E00FF000這個區(qū)間用于配接附加的(私有)外設。

1.6 存儲器保護單元(MPU)

1.6.1 MPU概述

存儲器保護單元(MPU)是Cortex-M3選配的功能,用于實現(xiàn)對存儲器的保護,從而使軟件更加健壯和可靠。MPU將存儲器映射劃分為多個區(qū),并定義了每個區(qū)的位置、大小、訪問權(quán)限及存儲器屬性??啥x8個單獨的存儲區(qū)及1個背景區(qū)。存儲區(qū)可重疊,此時存儲器訪問受最大的區(qū)的屬性影響(7的優(yōu)先級最高,0的優(yōu)先級最低)。每個區(qū)域的大小可以是32B~4GB。

背景區(qū)具有與默認存儲映射相同的存儲器訪問屬性,但只能被特權(quán)軟件訪問。

如果程序訪問被MPU禁止的存儲區(qū),則處理器會產(chǎn)生一個存儲器管理異常。因此,在嵌入式操作系統(tǒng)中,內(nèi)核可根據(jù)執(zhí)行的任務動態(tài)更新MPU區(qū)設置,從而實現(xiàn)存儲器保護。

例如,F(xiàn)reeRTOS實現(xiàn)了具有MPU功能的FreeRTOS-MPU,用于根據(jù)任務情況實現(xiàn)對存儲區(qū)設置只讀屬性、將其他區(qū)設置成不可執(zhí)行及利用xTaskCreateRestricted()生成一些訪問受限的任務。

1.6.2 MPU的寄存器

MPU的寄存器如表1-8所示。

表1-8 MPU的寄存器

TYPE寄存器指示是否存在MPU,以及如果存在,它支持多少個存儲區(qū)。

CTRL寄存器用于使能MPU;使能默認存儲器映射的背景區(qū);在硬故障、不可屏蔽中斷(NMI)和FAULTMASK升級的處理程序中,使能MPU的使用。

RNR寄存器用于選擇哪個存儲區(qū)被RBAR和RASR寄存器引用。

RBAR寄存器定義了RNR所選擇MPU區(qū)的基址,并可以更新RNR的值。

RASR寄存器定義了區(qū)的大小和RNR所指定的MPU區(qū)的存儲器屬性,并使能該區(qū),以及其子區(qū)的寄存器匯總。

1.6.3 MPU的使用

CMSIS給出了MPU寄存器的C語言訪問方式,主要有MPU->TYPE、MPU->RNR、MPU->RBAR、MPU->RASR、MPU->CTRL,與表1-8中名字相同的寄存器一一對應。MPU的設置流程如圖1-10所示。

圖1-10 MPU的設置流程

1.7 中斷和異常

Cortex-M3采用ARMV7-M體系結(jié)構(gòu)中的異常(中斷)模型,取消了原來在ARM7(如LPC23XX,LPC24XX)系列中的FIQ,但采用了中斷優(yōu)先級,引入了嵌套中斷模式,從而實現(xiàn)了嵌套中斷,即一個高優(yōu)先級的中斷能夠覆蓋或搶占低優(yōu)先級的中斷。Cortex-M3支持11個系統(tǒng)異常,最多240個外部中斷。外設產(chǎn)生的中斷信號,除了SysTick外,全部連接到NVIC的中斷輸入信號線上。

注意:LPC17XX的外部中斷是35個。實際上芯片制造商并不會全部使用240個外部中斷。

所有的異常處理都是在處理模式下實現(xiàn)的。當出現(xiàn)中斷時,處理器的狀態(tài)自動保存到堆棧中,并在中斷服務程序(ISR)結(jié)束時自動從堆棧中恢復。取出向量和保存狀態(tài)是同時進行的,從而提高了進入中斷的效率。Cortex-M3還支持末尾連鎖(Tail-chaining),使得處理器無須保存和恢復狀態(tài)便可執(zhí)行連續(xù)的中斷。

注意:末尾連鎖(Tail-chaining)指的是當處理器響應某中斷時,又發(fā)生了其他優(yōu)先級較低的中斷,則低優(yōu)先級的中斷先被掛起。在當前中斷執(zhí)行返回后,不再執(zhí)行出棧和入棧操作,直接處理掛起的中斷,就好像后一個中斷與前一個中斷的尾連接起來了,前后只執(zhí)行了一次入棧/出棧操作,從而使得兩個ISR之間的間隔大大縮短。

Cortex-M3的中斷處理方式與原有的ARM處理中斷方式相比,具有不易丟失中斷的特點。如果一個發(fā)生的異常不能被即刻響應,就稱它被“掛起”(pending)。不過,少數(shù)fault異常是不允許被掛起的。一個異常被掛起的原因,可能是系統(tǒng)當前正在執(zhí)行一個更高優(yōu)先級異常的服務例程,或者因相關(guān)掩蔽位的設置導致該異常被禁能。對于每個異常源,在被掛起的情況下,都會有一個對應的“掛起狀態(tài)寄存器”保存其異常請求。等到該異常能夠響應時,執(zhí)行其服務例程,這與傳統(tǒng)的ARM是完全不同的。在以前,是由產(chǎn)生中斷的設備保持住請求信號的;在Cortex-M3中,則由NVIC的掛起狀態(tài)寄存器來保持住請求信號的。于是,哪怕設備在后來已經(jīng)釋放了請求信號,曾經(jīng)的中斷請求也不會錯失。

1.7.1 異常類型

Cortex-M3自帶的異常是16個,其中異常號為0與7~10的異常保留,以供將來使用。異常主要有以下幾種。

1.復位

復位的異常號為0,優(yōu)先級為-3(最高優(yōu)先級)。

上電或熱復位時,復位啟動。異常模型將復位當做一種特殊的異常形式。當復位使能時,處理器可能在一條指令的任何位置停止操作。當復位禁能時,由向量表中的復位表項提供重新開始執(zhí)行的地址。在線程模式下,重新執(zhí)行是特權(quán)執(zhí)行。

2.NMI

不可屏蔽中斷(NMI)可由一個外設發(fā)出信號或由軟件觸發(fā)。這是除復位外的最高優(yōu)先級的異常。它被永久性使能,具有固定的優(yōu)先級-2。NMI不能因任何其他異常的激活而被屏蔽或阻止,不能被除復位外的其他任何異常搶占。

3.硬故障

硬故障是一種異常,其發(fā)生原因是異常在處理期間出錯,或異常無法被任何其他異常機制管理。硬故障具有固定優(yōu)先級-1,這意味著它的優(yōu)先級高于任何具有可配置優(yōu)先級的異常。

4.存儲器管理故障

存儲器管理故障是一種由與存儲器保護相關(guān)的故障引發(fā)的異常。對于指令和數(shù)據(jù)存儲事務,MPU或固定的存儲器保護約束條件決定此故障。此故障用于終止對從不執(zhí)行(XN)存儲區(qū)的指令的訪問,即使MPU被禁能也是如此。

5.總線故障

總線故障是一種異常,由一個指令或數(shù)據(jù)存儲器事務的存儲器的相關(guān)故障引發(fā)。這可能源于從一個存儲器系統(tǒng)總線上檢測出的錯誤。

6.使用故障

使用故障是與指令執(zhí)行相關(guān)的故障導致的一種異常。使用故障包括:

(1)未定義的指令;

(2)非法的非對齊訪問;

(3)指令執(zhí)行時的無效狀態(tài);

(4)異常返回時的錯誤。

當內(nèi)核被配置為報告使用故障時,以下情況可以導致一個使用故障:

(1)字和半字存儲器訪問時的非對齊地址;

(2)除以零。

7.SVCall

SVCall是指執(zhí)行系統(tǒng)服務調(diào)用指令(SVC)引發(fā)的異常。一次超級用戶調(diào)用是由SVC指令觸發(fā)的異常。在OS環(huán)境中,應用程序可使用SVC指令來訪問OS內(nèi)核函數(shù)和設備驅(qū)動程序。

8.PendSV

PendSV是一個對系統(tǒng)級服務的中斷驅(qū)動請求。在OS環(huán)境中,當無其他有效的異常時,使用PendSV進行上下文切換。

9.SysTick

SysTick是當系統(tǒng)定時器達到零時產(chǎn)生的異常。軟件也可以產(chǎn)生一個SysTick。在OS環(huán)境中,處理器可將此異常用做系統(tǒng)節(jié)拍。

10.中斷(IRQ)

中斷(IRQ)是由一個外設發(fā)出信號,或由一個軟件請求產(chǎn)生的異常。所有中斷都與指令執(zhí)行異步。在系統(tǒng)中,外設使用中斷與處理器進行通信。

注意:中斷(IRQ)在LPC17XX中是指一些外設的中斷,如看門狗、UART的中斷。在LPC176X總共有35個中斷(LPC177X/LPC178X中為41個)。

1.7.2 異常優(yōu)先級

Cortex-M3中的異常優(yōu)先級可決定一個異常是否能被掩蔽,以及在未掩蔽的情況下何時可以響應。優(yōu)先級的數(shù)值越小,優(yōu)先級越高。Cortex-M3支持中斷嵌套,使得高優(yōu)先級異常會搶占低優(yōu)先級異常。有3個系統(tǒng)異常:復位,NMI及硬fault,它們有固定的優(yōu)先級,并且它們的優(yōu)先級號是負數(shù),高于所有其他異常。所有其他異常的優(yōu)先級都是可編程的。

異常優(yōu)先級的設置分為兩步:

(1)設置組優(yōu)先級有效位(LPC17XX通過設置系統(tǒng)控制寄存器AIRCR[10:8]實現(xiàn));

(2)設置組優(yōu)先級及子優(yōu)先級(LPC17XX通過設置各自的IPRx或系統(tǒng)控制中的SHPx寄存器實現(xiàn))。

注意:組優(yōu)先級在有的書中也叫做搶占優(yōu)先級或主優(yōu)先級。有的文獻中使用group priority,有的文獻中使用preempt priority,雖然使用的詞語不一樣,但它們的含義是一樣的,均指具有搶占功能。

如表1-9所示是優(yōu)先級分組。其中分組位置指的是AIRCR[10:8]中的數(shù)值。IPRx寄存器分成搶占優(yōu)先級與子優(yōu)先級兩部分。

表1-9 優(yōu)先級分組

如果有多個掛起異常共用相同的組優(yōu)先級,則需使用次優(yōu)先級區(qū)來決定同組中異常的優(yōu)先級,這就是同組內(nèi)的次優(yōu)先級。組優(yōu)先級和次優(yōu)先級的結(jié)合就是通常所說的優(yōu)先級。如果兩個掛起異常具有相同的優(yōu)先級,則掛起異常的編號越低,優(yōu)先級越高。這與優(yōu)先級機制是一致的。

搶占優(yōu)先級(組優(yōu)先級)決定了搶占行為:當系統(tǒng)正在響應某異常L時,如果來了搶占優(yōu)先級更高的異常H,則H可以搶占L。只有組優(yōu)先級才能決定中斷異常的搶占。當處理器正在執(zhí)行一個中斷異常處理程序時,另一個與正在處理中的中斷具有相同組優(yōu)先級的中斷不會搶占處理程序。

子優(yōu)先級處理組內(nèi)優(yōu)先級的情況:當搶占優(yōu)先級相同的異常有不止一個掛起時,就最先響應子優(yōu)先級最高的異常。這種優(yōu)先級分組做出了如下規(guī)定:子優(yōu)先級至少是1個位。因此,搶占優(yōu)先級最多是7個位,128級。

從表1-9中可以看出,Cortex-M3允許從比特7處分組,此時所有的位都表達子優(yōu)先級,沒有任何位表達搶占優(yōu)先級,因此所有優(yōu)先級可編程的異常之間就不會發(fā)生搶占——相當于在它們之中禁用了Cortex-M3的中斷嵌套機制。復位、NMI和硬fault屬于例外情況,它們無論何時出現(xiàn),都立即搶占所有中斷(異常)。

CMSIS提供設置優(yōu)先級函數(shù):

        void NVIC_SetPriorityGrouping(uint32_t PriorityGroup);   //如何進行優(yōu)先級分組
        void NVIC_SetPriority(IRQn_Type IRQn,uint32_t priority);//設置中斷源IRQn的優(yōu)先級情況(包
                                                      //含組優(yōu)先級與子優(yōu)先級)
    NVIC_EncodePriority(uint32_tPriorityGroup,uint32_tPreemptPriority,uint32_t SubPriority);;//將組優(yōu)
                                      //先級與子優(yōu)先級組合起來,用于給NVIC_SetPriority函數(shù)賦值

LPC17XX中存在EINT0、EINT1、EINT2、EINT3四個外部中斷,在使用時分別給予了不同優(yōu)先級。在這里設定EINT0>EINT1的優(yōu)先級。可以根據(jù)需要采用兩種方式:一種是設定不同組,這樣EINT0可以搶占EINT1的優(yōu)先級,并可能存在優(yōu)先級嵌套方式;另外一種設定同一組,但EINT0的子優(yōu)先級高于EINT1的優(yōu)先級。

程序代碼如下所示。該程序使用宏定義方式來區(qū)分兩種方式,并根據(jù)需要設定了INT_MODE的數(shù)值,以及采用了NVIC_EncodePriority簡化組優(yōu)先級和子優(yōu)先級的組合計算問題。

        #define P_Group  4     //組屬性定義
        #if(INT_MODE==0)    //相同組,不同子優(yōu)先級
        NVIC_SetPriorityGrouping(P_Group);//設定組屬性;子優(yōu)先級為3
        NVIC_SetPriority(EINT0_IRQn,NVIC_EncodePriority(P_Group,0,2));  //組優(yōu)先級:0;子優(yōu)先
                                                              //級:2
        NVIC_SetPriority(EINT3_IRQn,NVIC_EncodePriority(P_Group,0,1));  //組優(yōu)先級:0;子優(yōu)先
                                                              //級:1
        #else//不同組,搶占模式
        NVIC_SetPriorityGrouping(P_Group);  //sets group priorities:8-subpriorities:3
        NVIC_SetPriority(EINT0_IRQn,NVIC_EncodePriority(P_Group,0,0));   //組優(yōu)先級:0;子優(yōu)先
                                                              //級:0
        NVIC_SetPriority(EINT3_IRQn,NVIC_EncodePriority(P_Group,1,0));  //組優(yōu)先級:1;子優(yōu)先
                                                              //級:0
        #endif

1.7.3 異常響應過程

異常響應的基本原則就是只要中斷掛起寄存器為0,而且該中斷沒有被屏蔽,就可進入中斷掛起狀態(tài)。如果在進入handler模式之前,掛起寄存器被清除掉,則進入中斷服務程序。

如果掛起寄存器被清0(不管是軟件清除,還是通過進入中斷服務程序方式清除),就可響應新的異常觸發(fā)信號。如果掛起寄存器已經(jīng)為1,對于外部新的中斷請求,也僅響應一次。

異常響應的狀態(tài)主要有以下6種。

(1)當中斷輸入腳生效后,該中斷就被掛起。即使后來中斷源取消了中斷請求,已經(jīng)被標記成掛起的中斷也被記錄下來。當在系統(tǒng)中它的優(yōu)先級最高時,它就會得到響應,如圖1-11所示。

圖1-11 中斷響應

(2)如果在某個中斷得到響應之前,其掛起狀態(tài)被清除了(例如,當PRIMASK或FAULTMASK置位時,軟件清除了掛起狀態(tài)標志),則中斷被取消,如圖1-12所示。

圖1-12 掛起狀態(tài)被提前清除掉

(3)當某中斷的服務例程開始執(zhí)行時,就稱此中斷進入了“活躍”狀態(tài),并且其掛起位會被硬件自動清除。在一個中斷活躍后,直到其服務例程執(zhí)行完畢,并且返回后,才能對該中斷的新請求予以響應。當然,新請求的響應也是由硬件自動清零并掛起標志位的。中斷服務例程也可以在執(zhí)行過程中把自己對應的中斷重新掛起(使用時要注意避免進入“死循環(huán)”),如圖1-13所示。

圖1-13 中斷請求被清除

(4)如果中斷源上一直存在請求信號,該中斷就會在其上次服務例程返回后再次被置為掛起狀態(tài),在這一點上,CM3和傳統(tǒng)的ARM7TDMI是相同的。這種情況發(fā)生在電平觸發(fā)源類型的中斷過程中,如圖1-14所示。

圖1-14 請求一直有效

(5)如果某個中斷在得到響應之前,其請求信號以若干脈沖形式呈現(xiàn),則被視為只有一次中斷請求,多出的請求脈沖全部丟失,這種情況是由于中斷請求過快造成的。

假如設計程序時,將外部中斷EINT0的優(yōu)先級設定得比較低,雖然觸發(fā)多次中斷,但因為其他高優(yōu)先級的中斷一直占用CPU,所以最后將僅表現(xiàn)為響應一次中斷。因此,對中斷的優(yōu)先級及中斷響應時長都需要嚴格規(guī)劃好,否則會出現(xiàn)各種意想不到的問題,如圖1-15所示。

圖1-15 中斷請求多次觸發(fā)

(6)如果在服務例程執(zhí)行過程中,中斷請求釋放了,但是在服務例程返回前又重新被置為有效,則CM3會記住此動作,重新掛起該中斷。例如,使用SysTick時,如果中斷處理程序比較長(運行時間需要1ms),但時鐘間隔設置比較短(設置成了500μs),這種情況發(fā)生后,程序?qū)⒁恢闭加锰幚砥?,除非具有更高?yōu)先級的中斷產(chǎn)生,如圖1-16所示。

圖1-16 中斷掛起狀態(tài)消失后重新觸發(fā)

從最后兩種形式可以看出,中斷的掛起狀態(tài)影響著中斷的響應次數(shù)。因為中斷掛起狀態(tài)只能是0和1,無其他狀態(tài),所以只要該狀態(tài)寄存器被清除,就可以響應下一次中斷了。該寄存器如果已經(jīng)為1,則將無法響應新的狀態(tài)。

1.8 指令系統(tǒng)

Cortex-M3不再支持ARM指令,而是支持ARMV6Thumb指令,同時引入了Thumb-2指令。Thumb-2指令是一種新型混合指令集,融合了16位和32位指令,用于實現(xiàn)密度和性能的最佳平衡。在不對性能進行折中的情況下,它節(jié)省了許多高集成度系統(tǒng)級設計的總體存儲成本。

Cortex-M3支持的指令可歸納為6大類:數(shù)據(jù)傳送、數(shù)據(jù)處理、分支指令、系統(tǒng)指令、飽和指令和雜項指令。

數(shù)據(jù)傳送指令可:

(1)在兩個寄存器之間傳送數(shù)據(jù);

(2)在寄存器與存儲器之間傳送數(shù)據(jù);

(3)在寄存器與特殊功能寄存器之間傳送數(shù)據(jù);

(4)將一個立即數(shù)加載到寄存器中。

數(shù)據(jù)處理指令主要是一些四則運算指令與移位操作指令,包含16位與32位操作指令。

分支指令又分為無條件跳轉(zhuǎn)及有條件跳轉(zhuǎn),如B、BL、CBZ指令。

系統(tǒng)指令主要是一些直接針對Cortex-M3寄存器的操作指令,如CPSIE和CPSID。

飽和指令主要是SSAT和USAT,用于對寄存器進行飽和操作。

由于目前Cortex-M3進行軟件開發(fā)時,更多地關(guān)注于C語言開發(fā),所以CMSIS也提供了各種對應指令的C語言版本函數(shù)及操作寄存器的C語言函數(shù)。僅僅在Cortex-M3的啟動文件涉及部分匯編代碼。

下面將對啟動文件(Startup.s)中涉及的跳轉(zhuǎn)指令和加載指令進行解釋說明。

啟動文件中使用的跳轉(zhuǎn)指令:

    B   Label   ;跳轉(zhuǎn)到Label處對應的地址
    BX   reg    ;跳轉(zhuǎn)到由寄存器reg給出的地址
    BLX   reg    ;跳轉(zhuǎn)到由寄存器reg給出的地址,并根據(jù)REG的LSB切換處理器狀態(tài),還要
    ;把轉(zhuǎn)移前的下條指令地址保存到LR

BL和BLX指令可將下一條指令的地址復制到鏈接寄存器(LR)R14中。使用BL與BLX時要小心,因為它們還帶有改變狀態(tài)的功能。寄存器reg的LSB必須是1,以確保處理器不會試圖進入ARM狀態(tài)。如果忘記置位LSB,將會出現(xiàn)UsageFault異常。

加載指令LDR用于把存儲器中的內(nèi)容加載到寄存器中。Startup.s使用了LDR偽指令。如果匯編器發(fā)現(xiàn)要產(chǎn)生的立即數(shù)是一個程序地址,它會自動地把LSB置位,例如:

          LDR   r0,   =address1   ;R0=0x40001
          …
      address1
      0x4000:  MOV  R0,  R1

在這個例子中,由于匯編器會認出address1是一個程序地址,所以自動置位LSB,即R0的復制不是0x4000,而是0x4001。另外,如果匯編器發(fā)現(xiàn)要加載的是數(shù)據(jù)地址,則不會自動置位LSB,例如:

        LDR   R0,   =address1   ; 會把0x4000 原封不動地加載到R0
        …
      address1
      0x4000:   DCD   0x0    ;0x4000 處記錄的是一個數(shù)據(jù)

至此,我們可以看一下Startup.s里面的使用情況:

      IMPORT  SystemInit
      IMPORT  __main
      LDR    R0,=SystemInit;自動將R0的LSB置位
      BLX    R0;切換到Thumb狀態(tài),并加載下一條指令
      LDR    R0,=__main
      BX     R0

由于C語言不能直接訪問Cortex-M3指令,所以CMSIS提供了通過C語言訪問指令及直接訪問寄存器的方式,這些方式通過內(nèi)聯(lián)匯編的方式實現(xiàn)。

表1-10中給出了CMSIS指令關(guān)系。

表1-10 CMSIS指令關(guān)系

1.9 小結(jié)

本章介紹了Cortex-M3的基本框圖、寄存器、存儲器的使用情況及異常的基礎(chǔ)理論,對比了Cortex-M3與ARM7TDMI,并結(jié)合LPC17XX,給出了一些Cortex-M3具體應用于某款芯片時的一些特點和用法。

本章中的中斷知識是以后章節(jié)中經(jīng)常使用的內(nèi)容。Cortex-M3對中斷的處理機制與ARM7TDMI有非常大的區(qū)別。本章中結(jié)合CMSIS給出了對中斷進行設置的方法。

本章對原有ARM7TDMI經(jīng)常涉及的指令系統(tǒng)只做了簡單介紹。這主要是因為目前Cortex-M3的產(chǎn)品設計是C語言的天下(當然對于ARM公司而言,可能仍是匯編語言的天下,但對于普通用戶而言,就是C語言的天下了),在Cortex-M3的軟件設計中幾乎可以不用了解匯編。ARM公司為Cortex-M3軟件設計提供的便捷方法會在第3章的CMSIS一節(jié)中介紹到。

第2章將介紹進行LPC17XX硬件設計的基礎(chǔ)理論內(nèi)容。

主站蜘蛛池模板: 平罗县| 定安县| 柳河县| 九寨沟县| 绍兴县| 芒康县| 博湖县| 罗田县| 平顺县| 德化县| 康乐县| 乌拉特中旗| 龙里县| 手机| 唐海县| 淮南市| 台江县| 叶城县| 巴楚县| 云浮市| 嘉禾县| 陇南市| 陇西县| 沅江市| 庐江县| 枣强县| 那曲县| 商城县| 安福县| 肇东市| 宁夏| 吉木乃县| 新竹县| 海丰县| 平原县| 丹东市| 三穗县| 桦川县| 黔西县| 嘉定区| 周口市|