基於ARM的嵌入式系統程式開發要點

2022-10-21 21:45:13 字數 4421 閱讀 6972

異常處理機制的設計

異常或中斷是使用者程式中最基本的一種執行流程或形態,這部分對arm架構下異常處理程式的編寫作乙個全面的介紹。

arm一共有7種型別的異常,按優先從高到低排列如下:

reset

data abort

fiqirqprefetch abort

swiundefined instruction

請注意在arm的文件中,使用術語exception來描述異常。exception主要是從處理被動接受異常的角度出發描述,而interrupt帶有向處理器主動神情的色彩。本文中,對「異常」和「中斷」不作嚴格區分,都是指請求處理器打斷正常的程式執行流程,進入特定程式迴圈的一種機制。

1. 異常響應流程

如以前介紹異常向量表是所提起過的,每乙個異常發生是,總是從異常向量表開始起跳的,最簡單的一種情況是:

向量表裡面的每一條指令直接跳向對應的異常處理函式。其中fiq_handler()可直接從位址0x1c處開始,省下一條跳轉指令。

但是當執行跳轉的時候有2個問題需要討論:跳轉範圍和異常分支。

1.1 跳轉範圍

我們知道arm的跳轉指令(b)是有範圍限制的(32mb),但很多情況下不能保證所有的異常處理函式都定位在向量表的32mb範圍內,需要大於32mb的長跳轉,而且因為向量表空間的限制只能有一條指令完成。這可以通過下面二種方法實現。

(a)mov pc,#imme_value

把目標位址直接賦給pc暫存器。

但是這條指令手格式限制看並不能處理任意立即數,只能當這個立即數能夠表示乙個8-bit數值通過迴圈右移偶數字而得到,才是合法的。例如:

mov pc,#0x30000000 是合法的,因為0x30000000可以通過0x03迴圈右移4位而得到。

而mov pc,#0x30003000 就是非法指令。

(b) ldr pc,[pc+offset]

把目標位址先儲存在某乙個合適的位址空間,然後把這個儲存其單元上的32位資料傳送給pc來實現跳轉。

這種方法對目標位址值沒有要求,可以是任意有效位址。但是儲存目標位址的儲存器單元必須在當前指令的4kb空間範圍內。

注意在計算指令中引用的offset數值的時候,要考慮處理器流水線指令預取對pc值的影響,以圖-2的情況為例:

1.2 異常分支

arm核心只有二個外部中斷輸入訊號nfiq和nirq,但對於乙個系統來說,中斷源可能多達幾十個。為此,在系統整合的時候,一般都會有乙個異常控制器來處理異常訊號。

這時候,使用者程式可能存在多個irq/fiq的中斷處理函式,為了從向量表開始的跳轉最終能找到正確的處理函式入口,需要設計一套處理機制和方法。

(a) 硬體處理

有的系統在arm的異常向量表之外,又增加了一張由中斷控制器控制的特殊向量表。當由外設觸發乙個中斷以後,pc能夠自動跳到這張特殊向量表中去,特殊向量表中的每個向量空間對應乙個具體的中斷源。

舉例來說,下面的系統一共有20個外設中斷源,特殊向量表被直接放置在普通向量表後面。

當某個外部中斷觸發之後,首先觸發arm的核心異常,中斷控制器檢測到arm的這種狀態變化,再通過識別具體的中斷源,使pc自動跳轉到特殊向量表中的對應位址,從而開始一次異常響應。需要檢查具體的晶元說明,是否支援這類特性。

(b) 軟體處理

多處情況下是用軟體來處理異常分支。因為軟體可以通過讀取中斷控制器來獲得中斷源的詳細資訊。

因為軟體設計的靈活性,使用者可以設計出比上圖更好的流程控制方法來。下面是乙個例子:

int_vector_table是使用者自己開闢的一塊儲存器空間,裡面按次序存放異常處理函式的位址。irq_handler()從中斷控制器獲取中斷源資訊,然後再從int_vector_table中的對應位址單元得到異常處理函式的入口位址,完成一次異常響應的跳轉。這種方法的好處是使用者程式在執行過程中,能夠很方便地動態改變異常服務內容。

2. 異常處理函式的設計

2.1異常發生時處理器的動作

當任何乙個異常發生並得到響應時,arm核心自動完成以下動作:

◆ 拷貝cpsr到spsr_

◆ 設定適當的cpsr位:

● 改變處理器狀態進入arm狀態

● 改變處理器模式進入相應的異常模式

● 設定中斷禁止位禁止相應中斷

◆ 更新lr_

◆ 設定pc到相應的異常向量

注意當響應異常後,不管異常發生在arm還是thumb狀態下,處理器都將自動進入arm狀態。另乙個需要注意的地方是中斷使能被自動關閉,也就是說預設情況下中斷是不可重入的。單純的把中斷使能位開啟接受重入的中斷會帶來新的問題,在第3部分中對此會有詳細介紹。

除這些自動完成的動作之外,如果在彙編級進行手動程式設計,還需要注意儲存必要的通用暫存器。

2.2進入異常處理迴圈後軟體的任務

進入異常處理程式以後,使用者可以完全按照自己的億元來進行程式設計,包括呼叫thumb狀態的函式,等等。但是對於絕大多數的系統來說,有乙個步驟必須處理,就是要把中斷控制器中對應的中斷狀態標識清掉,表明該中斷請求已經得到響應。否則等退出中斷函式以後,又馬上會被再一次觸發,從而進入周而復始的死迴圈。

2.3異常的返回

當乙個異常處理返回時,一共有3件事情需要處理:通用暫存器的恢復、狀態暫存器的恢復以及pc指標的恢復。

通用暫存器的恢復採用一般的堆疊操作指令,而pc和cpsr的恢復可以通過一條指令來實現,下面是3個例子:

movs pc,lr或subs pc,lr,#4或ldmfd sp!,^

這幾條指令都是普通的資料處理指令,特殊之處就是把pc暫存器作為了目標暫存器,並且帶了特殊的字尾「s」或「^」,在特權模式下,「s」或「^」的作用就是使指令在執行時,同時完成從spsr到cpsr的拷貝,達到恢復狀態暫存器的目的。

異常返回時另乙個非常重要的問題是返回位址的確定。在2.1節中提到進入異常時處理器會有乙個儲存lr的動作,但是該儲存值並不一定是正確中斷的返回位址。

下面以乙個簡單的指令執行流水狀態圖來對此加以說明。

我們知道在arm架構裡,pc值指向當前指令的位址加8處。也就是說,當執行指令a(位址0x8000)時,pc等於指令c的位址(0x8008)。假如指令a是「bl」指令,則當執行時,會把pc(=0x8008)儲存到lr暫存器裡面,但是接下去處理器會馬上對lr進行乙個自動的調整動作:

lr=lr-0x4。這樣,最終儲存在lr裡面的是b指令的位址,所以當從bl返回時,lr裡面正好是正確的返回位址。

同樣的調整機制在所有lr自儲存操作都存在,比如進入中斷響應時處理器所做的lr儲存中,也進行了一次自動調整,並且調整動作都是lr=lr-0x4。由此我們來對不同異常型別的返回位址進行依次比較:

假設在指令b處(位址0x8004)發生了中斷響應,進入知道響應後lr上經過調整儲存的位址值應該是c的位址0x8008。

(a) 如果發生的是軟體知道,即b是「swi」指令

從swi知道返回後下一條執行指令就是c,正好是lr暫存器儲存的位址。所以只要直接把lr恢復給pc。

(b) 如果發生的是「irq」或「fiq」等指令

因為外部知道請求中斷了b指令的執行,當中斷返回後,需要重新回到b指令執行,也就是返回位址應該是b(0x8004),需要把lr減4。

(c) 如果發生的是「data abort」

在b上進入資料異常的響應,但導致資料異常的原因缺應該是上一條指令a。當中斷處理程式修復資料異常以後,要回到a上重新執行導致資料異常的指令,因此返回位址應該是lr減8。

如果原來的指令執行狀態是thumb,異常返回位址的分析與此類似,對lr的調整正好與arm狀態完全一致。

2.4 arm編譯器對異常處理函式編寫的擴充套件

考慮到異常處理函式在現場保護和返回位址的處理上與普通函式的不同之處,不能直接把普通函式體連線到異常向量表上,需要在上面加一層封裝,下面是乙個例子:

irq_handler中斷響應,從向量表直接跳來

stmfd sp! , 即可

bl irqhandler進入普通處理函式,c或彙編均可

ldmfd sp!,

2.5 軟體中斷處理

軟體中斷有專門的軟中斷指令swi觸發,swi指令後面跟乙個中斷編號,以標識可能共存的多個軟體中斷程式。

在c程式中呼叫軟體中斷需要用到編譯器的擴充套件功能,使用關鍵字「_swi」來宣告中斷函式。注意軟中斷號碼同時在函式定義時指定。

__swi(0x24)void my_swi(void);

這樣當呼叫函式my_swi的時候,就會用「swi 0x24」來代替普通的函式呼叫「bl my_swi」。

分析圖-9的流程,可以發現軟體中斷同樣存在著中斷分支問題,即需要根據中斷號碼來決定呼叫不同的處理程式。軟中斷號碼只存在於swi指令碼當中,因此需要在中斷處理程式中讀取觸發中斷的指令**,然後提取中斷號資訊,再進一步處理。下面是軟中斷指令的編碼格式:

為了在中斷處理程式裡面得到swi指令的位址,可以利用lr暫存器。每當響應一次swi的時候,處理器都會自動儲存並調整lr暫存器,使裡面的內容指向swi下一條指令的位址,所以把lr裡面的位址內容上溯一條指令就是所需的swi指令位址。需要注意的一點的是當swi指令的執行狀態不同時,其指令位址間隔不一樣,如果進入swi執行前是在arm狀態下,則只要lr-2就可以了。

基於ARM的嵌入式工業控制系統設計

嵌入式系統如今已經廣泛的應用到了科學研究,工程設計,軍事技術,各類產業和商業等領域。並且還在不斷的發展和延續,嵌入式系統中又以arm架構的運用最為有發展前景,普及最為廣泛。在嵌入式作業系統領域中則是種類繁多,各有特色,windows ce作業系統由微軟開發,還繼承了windows等系列作業系統的有點...

嵌入式開發入門者ARM學習必要步驟

針對嵌入式開發的入門者給出嵌入式開發的 arm 基礎知識和入門必 要步驟 1.做個最小系統板 如果你從沒有做過 arm 嵌入式開發,建議 你一開始不要貪大求全,把所有的應用都做好,因為 arm 的啟動方式和 dsp 或微控制器有所不同,往往會遇到各種問題,所以建議先布乙個僅有 flash,sram ...

嵌入式ARM彙編指令實驗

5 選擇選單項project build target 或快捷鍵f7,生成目標 6 選擇選單項debug start stop debug session 或快捷鍵ctrl f5,即可進入除錯模式。這裡使用的是 vision3 ide中的軟體 器。7 選擇選單項debug run 或快捷鍵f5,即可...