ARM Cortex-M3中斷跳轉過程
在學習CM3的時候,仔細學習了CM3的中斷跳轉過程,發現嵌入式的MCU在這一塊基本上是一樣的,當然不同架構的MCU也有自己的特性。
我來介紹下CM3的中斷跳轉過程,首先假設中斷髮生,CM3核心開始響應中斷,由於不同廠家的CM3可能略有區別,但CM3的核心肯定是一樣的,所以我們在這個前提下開始討論,暫時把中斷遮蔽位,標誌位之類的東西放在一邊。
現在介紹中斷響應的過程:
1、壓棧。從這一點來講幾乎所有的處理器都是一樣的,用壓棧保護現場。壓入哪些暫存器呢,又是怎樣一個順序?如果就大多數的C語音程式設計來講,這個不是很關心的內容。但是CM3的壓棧暫存器特點,讓我們來見識下ARM設計的特點。其壓棧順序如下圖所示,請注意壓棧的地址順序和時間順序不是相同的。
地址(SP) |
暫存器 |
被保護順序(時間順序) |
N-0 |
之前已壓棧內容 |
|
N-4 |
xPSR |
2 |
N-8 |
PC |
1 |
N-12 |
LR |
8 |
N-16 |
R12 |
7 |
N-20 |
R3 |
6 |
N-24 |
R2 |
5 |
N-28 |
R1 |
4 |
N-32 |
R0 |
3 |
這一點就我們普通coding來講,是非常奇特的,堆疊的空間順利和進棧時間沒有必然聯絡,跟我們“後進先出”的觀點有很大出入,那麼顯然這裡的“堆疊”,並不是我們傳統意義的上的堆疊,具體怎樣實現ARM沒有詳述,只是說他們可以做到這點。
我們可以看到PC,xPSR,R0,R1,R2,R3是率先入棧的(時間上),這樣做的目的,是為了編譯器優先使用入棧了的暫存器來儲存中間結果(如果程式過大也可能要用到R4-R11,此時編譯器負責生成程式碼來push它們)。這也是要求ISR儘量短小的原因,用更少的暫存器,以加快響應。
2、查詢中斷向量表。其實這一步跟第一步是並行的,只是為了分別介紹我,列了序號。ARM是有D-Code(資料匯流排)和I-Code(指令匯流排),兩條匯流排。可以看到PC是第一個壓棧的,此時資料匯流排正忙於壓棧操作,與此同時指令匯流排就可以查詢中斷向量表,查詢中斷服務程式的入口地址。在CM3中中斷向量表位於地址從0x00000000開始的一段儲存空間,每個表項佔一個字(4byte)。這是中斷向量表沒有重定位的情況,當然中斷向量表也可以重定位,即儲存在其他地方。這個需要設定相應的暫存器,我個人認為還是讓其固定在這個預設的位置比較好,以免出現以外情況。在看中斷向量表的時候我遇到了一個很有意思的問題:
中斷服務函式的入口地址為0x67C(圖1所示),但是中斷向量表中儲存的地址確是0x67D(圖2所示),竟然加了1。
這讓我糾結了很久,後來一位整ARM7的大牛解答了我的問題。ARM的PC最低位是0的時候ARM會進入ARM模式,但是最低位是1的時候會進入thumb模式。而我們的CM只支援thumb模式,所以PC最低位必須為1。而且thumb指令集是16位的,所以0x67D就是指向0x67C所儲存的指令,但是減一就不行了,就變成了指令空間內上一個地址儲存的指令。
把CM3中斷跳轉過程寫出來跟大家分享,若有不妥之處,望大家斧正。
圖1 方框內為所對應中斷服務函式入口地
圖2 方框內為中斷向量表中中斷服務函式入口地址
***************************************************************************
記得在DSP TMS32F2812中,中斷向量的初始化是由一段地址拷貝程式碼完成的,在STM32(Cortex-M3)中沒有顯示的程式碼拷貝,只有啟動程式碼進行了向量的初始化,一直以為是編譯器在程式影像中自己完成了相關向量的拷貝,即,拷貝到固定的NVIC區,事實上並不是這樣,cortex-m3並沒有一塊專門用於存放NVIC向量表的地方,這張表實際是存放在程式碼(程式映像)的開始,下面引用cortex-M3權威指南進行解釋:
當發生了異常並且要響應它時,CM3需要定位其服務例程的入口地址。這些入口地址儲存在所謂的“(異常)向量表”中。預設情況下,CM3認為該表位於零地址處,且各向量佔用4位元組。因此每個表項佔用4位元組,如表7.6所示。
因為地址0處應該儲存引導程式碼,所以它通常對映到Flash或者是ROM器件,並且它們的值不得在執行時改變。然而,為了支援動態重分發中斷,CM3允許向量表重定位——從其它地址處開始定位各異常向量。這些地址對應的區域可以是程式碼區,但更多是在RAM區。在RAM區就可以修改向量的入口地址了。為了實現這個功能,NVIC中有一個暫存器,稱為“向量表偏移量暫存器”(在地址0xE000_ED08處),通過修改它的值就能重定位向量表。但必須注意的是:向量表的起始地址是有要求的:必須先求出系統中共有多少個向量,再把這個數字向上“圓整”到2的整次冪,而起始地址必須對齊到後者的邊界上。例如,如果一共有32箇中斷,則共有32+16(系統異常)=48個向量,向上圓整到2的整次冪後值為64,因此向量表重定位的地址必須能被64*4=256整除,從而合法的起始地址可以是:0x0, 0x100, 0x200等。向量表偏移量暫存器的定義如表7.7所示。
如果需要動態地更改向量表,則對於任何器件來說,向量表的起始處都必須包含以下向量:
主堆疊指標(MSP)的初始值
復位向量
NMI
硬fault服務例程
後兩者也是必需的,因為有可能在引導過程中發生這兩種異常。
可以在SRAM中開出一塊空間用於儲存向量表。在引導期間先填寫好各向量,然後在引導完成後,就可以啟用記憶體中的新向量表,從而實現向量可動態調整的能力。