ARM Cortex-M3權威指南-中斷和異常(2)


中斷和異常

它支持16-4-1=11 種系統異常(同步)(保留了 4+1 個檔位),外加 240 個外部中斷輸入(異步)。在 CM3 中取消了 FIQ 的概念(v7 前的 ARM 都有這個 FIQ,快中斷請求),這是因為有了更新更好的機制——中斷優先級管理以及嵌套中斷支持,它們被納入 CM3 的中斷管理邏輯中。因此,支持嵌套中斷的系統就更容易實現 FIQ。雖然 CM3 是支持 240 個外中斷的,但具體使用了多少個是由芯片生產商決定。 CM3 還有一個NMI(不可屏蔽中斷)輸入腳。當它被置為有效(assert)時, NMI 服務例程會無條件地執行。 NMI 究竟被拿去做什么,還要視處理器的設計而定。在多數情況下, NMI 會被連接到一個看門狗定時器,有時也會是電壓監視功能塊,以便在電壓掉至危險級別后警告處理器。 

  • 向量表

當 CM3 內核響應了一個發生的異常后,對應的異常服務例程(ESR)就會執行。為了決定 ESR 的入口地址, CM3 使用了“向量表查表機制”。這里使用一張向量表。向量表其實是一個 WORD(32 位整數)數組,每個下標對應一種異常,該下標元素的值則是該 ESR 的入口地址。向量表在地址空間中的位置是可以設置的,通過 NVIC 中的一個重定位寄存器來指出向量表的地址。在復位后,該寄存器的值為 0。因此,在地址 0 處必須包含一張向量表,用於初始時的異常分配。 舉個例子,如果發生了異常 11(SVC),則 NVIC 會計算出偏移移量是 11x4=0x2C,然后從那里取出服務例程的入口地址並跳入。要注意的是這里有個另類: 0 號類型並不是什么入口地址,而是給出了復位后 MSP 的初值。

CM3允許向量表重定位即從其它地址處開始執行各異常向量。這些地址對應的區域可以是代碼區,但也可以是 RAM 區。在 RAM區就可以修改向量的入口地址了。為了實現這個功能, NVIC中有一個寄存器,稱為“向量表偏移量寄存器”(在地址 0xE000_ED08 處),通過修改它的值就能定位向量表。

  • 異常堆棧操作

內核還會在異常處理的始末自動地執行 PUSH 與 POP 操作。注意:在寄存器列表中,不管寄存器的序號是以什么順序給出的,匯編器都將把它們升序排序。然后先 push 序號大的寄存器,所以也就先 pop 序號小的寄存器。如果不按升序寫寄存器,也許有些匯編器會給出語法錯誤。在進入 ESR 時, CM3 會自動把一些寄存器壓棧,這里使用的是發生本異常的瞬間正在使用的 SP指針(MSP 或者是 PSP)。離開 ESR 后,只要 ESR 沒有更改過 CONTROL[1],就依然使用發生本次異常的瞬間正在使用的 SP 指針來執行出棧操作。

  • 異常復位流程

復位流程:1)從地址 0x0000,0000 處取出 MSP 的初始值。2)從地址 0x0000,0004 處取出 PC 的初始值——這個值是復位向量, LSB 必須是 1。 然后從這個值所對應的地址處取指。

請注意,這與傳統的 ARM 架構不同——其實也和絕大多數的其它單片機不同。傳統的 ARM 架構總是從 0 地址開始執行第一條指令。它們的 0 地址處總是一條跳轉指令。 在 CM3 中,在 0 地址處提供 MSP 的初始值,然后緊跟着就是向量表。 向量表中的數值是 32 位的地址,而不是跳轉指令。向量表的第一個條目指向復位后應執行的第一條指令。

向量表跟隨在 MSP 的初始值之后——也就是第 2 個表目。要注意因為 CM3 是在 Thumb 態下執行,所以向量表中的每個數值都必須把 LSB 置 1(也就是奇數)。正是因為這個原因,圖 3.18 中使用0x101 來表達地址 0x100。當 0x100 處的指令得到執行后,就正式開始了程序的執行。在此之前初始化 MSP 是必需的,因為可能第 1 條指令還沒來得及執行,就發生了 NMI 或是其它 fault。 MSP 初始化好后就已經為它們的服務例程准備好了堆棧

中斷與異常的區別
中斷對 CM3 核來說都是“意外突發事件” ——也就是說,該請求信號來自 CM3 內核的外面,來自各種片上外設和外擴的外設,
對 CM3 來說是“異步”的;而異常則是因 CM3 內核的活動產生的——在執行指令或訪問存儲器時產生, 因此對 CM3 來說是“同步”的。

pending懸起的功能

如果一個發生的異常不能被即刻響應,就稱它被“懸起” (pending)。不過,少數 fault 異常是不允許被懸起的。一個異常被懸起的原因,可能是系統當前正在執行一個更高優先級異常的服務例程,或者因相關掩蔽位的設置導致該異常被除能。對於每個異常源,在被懸起的情況下,都會有一個對應的“懸起狀態寄存器”保存其異常請求。待到該異常能夠響應時,執行其服務例程,這與傳統的 ARM 是完全不同的。在以前,是由產生中斷的設備保持住請求信號;CM3 則由 NVIC 的懸起狀態寄存器來解決這個問題。於是,哪怕設備在后來已經釋放了請求信號,曾經的中斷請求也不會錯失。

中斷優先級

CM3支持中斷搶占。優先級的數值越小,則優先級越高有3個系統異常:復位, NMI 以及硬fault,它們有固定的優先級,並且它們的優先級號是負數,從而高於所有其它異常。所有其它異常的優先級則都是可編程的,但不能被編程為負數。
如果使用更多的位來表達優先級,則可以使用的值也更多,同時需要的門也更多——帶來更多的成本和功耗。 CM3 允許的最少使用位數為 3 個位,亦即至少要支持 8 級優先級。

搶占優先級決定了搶占行為:當系統正在響應某異常 L 時,如果來了搶占優先級更高的異常 H,則 H 可以搶占 L。亞優先級則處理“內務”:當搶占優先級相同的異常有不止一個懸起時,就優先響應亞優先級最高的異常。在計算搶占優先級和亞優先級的有效位數時,芯片實際使用了多少位來表達優先級;優先級組是如何划分的。舉個例子,如果只使用 3 個位來表達優先級([7:5]),並且優先級組的值是 5(從比特 5處分組),則你得到 4 級搶占優先級,且在每個搶占優先級的內部有 2 個亞優先級。如果優先級完全相同的多個異常同時懸起,則先響應異常編號最小的那一個

中斷處理時序圖

當中斷輸入腳被 assert后,該中斷就被懸起。當某中斷的服務例程開始執行時,就稱此中斷進入了“活躍”狀態,並且其懸起位會被硬件自動清除,在一個中斷活躍后,直到其服務例程執行完畢,並且返回了,才能對該中斷的新請求予以響應。當然,新請求的響應亦是由硬件自動清零懸起標志位。

如果中斷源咬住請求信號不放,該中斷就會在其上次服務例程返回后再次被置為懸起狀態。

異常類型

總線faults異常

當 AHB 接口上正在傳送數據時,如果回復了一個錯誤信號(error response),則會產生總線faults,產生的場合可以是,1)取指,通常被稱作“預取流產”(prefetch abort);2)數據讀/寫,通常被稱作“數據流產”(data abort)

哪些因素會導致 AHB 回復一個錯誤信號?
AHB 回復的錯誤信號會觸發總線 fault,誘因可以是:

  1.  企圖訪問無效的存儲器 region。常見於訪問的地址沒有相對應的存儲器。
  2. 設備還沒有作好傳送數據的准備。比如,在尚未初始化 SDRAM 控制器的時候試圖訪問 SDRAM。
  3.  在企圖啟動一次數據傳送時,傳送的尺寸不能為目標設備所支持。例如,某設備只接受字型數據,卻試圖送給它字節型數據。
  4.  因為某些原因,設備不能接受數據傳送。例如,某些設備只有在特權級下才允許訪問,可當前卻是用戶級。

使能總線fault需要在NVIC中配置BUSFAULTENA位,並且配置好中斷向量表。發生總線fault后,NVIC提供了事故原因的狀態寄存器,總線fault狀態寄存器(BFSR):是在數據訪問時,在取指時,還是在中斷的堆棧操作時。總線 fault 地址寄存器(BFAR):存儲異常指令地址。

數據訪問產生的總線 fault可分為精確的總線fault不精確的總線fault:例如緩沖區寫入就是不精確總線fault,啟動緩沖區寫入時指令早已執行,中途觸發了總線fault。

存儲器管理fault

存儲器管理 faults 多與 MPU 有關,其誘因常常是某次訪問觸犯了 MPU 設置的保護規范。另外,某些非法訪問,例如,在不可執行的存儲器區域試圖取指,也會觸發一個 MemManage fault,而且在這種場合下,即使沒有 MPU 也會觸發 MemMange fault。
MemManage faults 的常見誘因如下所示:
 訪問了所有 MPU regions 覆蓋范圍之外的地址
 訪問了沒有存儲器與之對應的空地址
 往只讀 region 寫數據
 用戶級下訪問了只允許在特權級下訪問的地址
在 MemManage fault 發生后,如果其服務例程是使能的,則執行服務例程。如果同時還發生了其它高優先級異常,則優先處理這些高優先級的異常, MemManage 異常被懸起。如果 MemMange fault是被同級或高優先級異常的服務例程引發的,或者MemManage fault被除能,則和總線fault一樣:上訪成硬 fault,最終執行的是硬 fault 的服務例程。如果硬 fault 服務例程或 NMI 服務例程的執行也導致了 MemManage fault,那就不可救要了——內核將被鎖定。

為了調查 MemManage fault 的案發現場, NVIC 中有一個“存儲器管理 fault 狀態寄存器(MFSR)”,它指出導致 MemManage fault 的原因。如果是因為一個數據訪問違例(DACCVIOL 位)或是一個取指訪問違例(IACCVIOL 位),則違例指令的地址已經被壓入棧中。如果還有 MMARVALID位被置位,則還能進一步查出引發此 fault 時訪問的地址——讀取 NVIC“存儲器管理地址寄存器(MMAR)”的值。

用法fault

用法 faults 發生的場合可以是:

  1. 執行了協處理器指令。 Cortex-M3 本身並不支持協處理器,但是通過 fault 異常機制,可以建立一套“軟件模擬”的機制,來執行一段程序模擬協處理器的功能,從而可以方便地在其它 Cortex 處理器間移植。
  2. 執行了未定義的指令。同上一點的道理,亦可以軟件模擬未定義指令的功能。
  3. 嘗試進入 ARM 狀態。因為 CM3 不支持 ARM 狀態,所以用法 fault 會在切換時產生。軟件可以利用此機制來測試某處理器是否支持 ARM 狀態。
  4. 無效的中斷返回(LR 中包含了無效/錯誤的值)
  5. 使用多重加載/存儲指令時,地址沒有對齊。

硬fault

硬 fault 是上文討論的總線 fault、存儲器管理 fault 以及用法 fault 上訪的結果。在取向量(異常處理時對異常向量表的讀取)時產生的總線 fault 也按硬 fault 處理。在 NVIC中有一個硬 fault 狀態寄存器(HFSR),它指出產生硬 fault 的原因。如果不是由於取向量造成的,則硬 fault 服務例程必須檢查其它的 fault 狀態寄存器,以最終決定是誰上訪的。硬 fault 狀態寄存器(地址: 0xE000_ED2C):

 應對fault策略

在軟件開發過程中,我們可以根據各種 fault 狀態寄存器的值來判定程序錯誤,並且改正它們。
在一個RTOS實時系統中,發生了 Faults 后,如果不加以處理常會危及系統的運行。因此在找出了導致 fault 的原因后,軟件必須決定下一步該怎么辦。下面就給出一些應付 fault 的常用方法。

  1. 復位:這通常是最后一招。通過設置 NVIC“應用程序中斷及復位控制寄存器”中的 VECTRESET位,將只復位處理器內核而不復位其它片上設施。取決於芯片的復位設計,有些 CM3 芯片可以使用該寄存器的 SYSRESETREQ 位來復位。這種只限於內核中的復位不會殃及其它的系統部件。
  2. 恢復:在一些場合下,還是有希望解決產生 fault 的問題的。例如,如果程序嘗試訪問了協處理器,可以通過一個協處理器的軟件模擬器來解決此問題——當然是以犧牲性能為代價的,要不然還要硬件加速干啥。
  3. 中止相關任務:如果系統運行了一個 RTOS,則相關的任務可以被終結或者重新開始。各個 fault 狀態寄存器(FSRs)都保持住它們的狀態,直到手工清除。 Fault 服務例程在處理了相應的 fault 后不要忘記清除這些狀態,否則如果下次又有新的 fault 發生,服務例程在檢視fault 源時,又將看到早先已經處理的 fault 遺留下來的狀態標志。此時,將無法判斷哪個 fault是新發生的。 FSRs 采用一個寫時清除機制(寫 1 時清除)。芯片廠商也可以再添加自己的 FSR,以表示其它 fault 情況。

CM3 中的 fault 狀態寄存器組

SVC和PendSV

SVC用於產生系統函數的調用,目的是不讓用戶程序直接訪問硬件,而是通過一些系統服務函數,讓用戶程序使用SVC發出對系統服務函數的呼叫請求。好處是:

  1. 解耦用戶程序與底層驅動,由os控制具體的硬件,用戶程序移植更方便。
  2. 使用特權等級優勢,由os操作硬件,提高了系統的健壯性和可靠性。

SVC指令需要一個立即數來充當系統調用代號,從而獲取響應的服務函數。在 SVC 服務例程中不能嵌套使用 SVC 指令,因為同優先級的異常不能搶占自身。這種作法會產生一個用法 fault。同理,在 NMI服務例程中也不得使用 SVC,否則將觸發硬 fault。

PendSV是讓請求緩期執行,當其他中斷完畢后再執行,因此PendSV優先級最低。

NVIC控制器與中斷控制

NVIC 的寄存器以存儲器映射的方式來訪問,除了包含控制寄存器和中斷處理的控制邏輯之外, NVIC 還包含了 MPU、 SysTick 定時器以及調試控制相關的寄存器。NVIC 的訪問地址是 0xE000_E000。

中斷配置基礎

每個外部中斷都在 NVIC 的下列寄存器中“掛號”:

  • 使能與除能寄存器
  • 懸起與“解懸”寄存器
  • 優先級寄存器
  • 活動狀態寄存器

另外,下列寄存器也對中斷處理有重大影響

  • 異常掩蔽寄存器(PRIMASK, FAULTMASK 以及 BASEPRI)
  • 向量表偏移量寄存器
  • 軟件觸發中斷寄存器
  • 優先級分組位段

中斷使能與除能

CM3 中可以有 240 對使能位/除能位,每個中斷擁有一對。這 240 個對子分布在 8 對 32 位寄存器中(最后一對沒有用完)。欲使能一個中斷,你需要寫 1 到對應 SETENA 的位中;欲除能一個中斷,你需要寫 1 到對應的 CLRENA 位中。

地址:SETENAs: xE000_E100 – 0xE000_E11C ; CLRENAs:0xE000E180 - 0xE000_E19C

中斷的懸起與解懸

如果中斷發生時,正在處理同級或高優先級異常,或者被掩蔽,則中斷不能立即得到響應。此時中斷被懸起。中斷的懸起狀態可以通過“中斷設置懸起寄存器(SETPEND)”和“中斷懸起清除寄存器(CLRPEND)”來讀取,還可以寫它們來手工懸起中斷。

地址:SETPENDs:0xE000_E200 – 0xE000_E21C ; CLRPENDs:0xE000E280 - 0xE000_E29C

優先級

每個外部中斷都有一個對應的優先級寄存器,每個寄存器占用 8 bit,但是允許最少只使用最高 3 bit。 4 個相臨的優先級寄存器拼成一個 32 位寄存器。如前所述,根據優先級組設置,優先級可以被分為高低兩個位段,分別是搶占優先級和亞優先級。優先級寄存器都可以按字節訪問,當然也可以按半字/字來訪問。

地址:中斷優先級寄存器陣列 0xE000_E400 – 0xE000_E4EF    系統異常優先級寄存器陣列 0xE000_ED18 - 0xE000_ED23

活動狀態

每個外部中斷都有一個活動狀態位。在處理器執行了其 ISR 的第一條指令后,它的活動位就被置 1,並且直到 ISR 返回時才硬件清零。

地址 ACTIVE 寄存器族 0xE000_E300_0xE000_E31C

PRIMASK 與 FAULTMASK 特殊功能寄存器

PRIMASK 用於除能在 NMI 和硬 fault 之外的所有異常,它有效地把當前優先級改為 0;FAULTMASK更絕,它把當前優先級改為‐1,這么一來,連硬fault都被掩蔽了。NMI不會被掩蔽。

系統異常中斷配置寄存器

各種fault異常的使能是通過系統handler控制及狀態寄存器(SHCSR)來實現的。

軟件中斷

軟件中斷,能以多種方式產生。最簡單的就是使用相應的SETPEND寄存器;而更專業更快捷的作法,則是通過使用軟件觸發中斷寄存器STIR,如表8.8所示。

systick定時器

SysTick定時器被捆綁在NVIC中,用於產生SYSTICK異常(異常號:15)。大多操作系統需要一個硬件定時器來產生操作系統需要的滴答中斷,作為整個系統的時基,提供定時器、任務切換等作用。CM3芯片內部都帶有一個定時器,軟件在不同CM3器件間移植工作得以簡化。該定時器的時鍾源可以是內部時鍾(FCLK,CM3的自由時鍾)、或者外部時鍾(CM3處理器的STCLK信號)。

校准值寄存器提供了這樣一個解決方案:TENMS值為芯片產生10ms中斷的默認值。最簡單的作法就是:直接把TENMS的值寫入重裝載寄存器,這樣一來,就能做到每10ms來一次 SysTick異常。如果需要其它的SysTick異常周期,則可以根據TENMS的值加以比例計算。

異常的具體行為

異常的響應序列

入棧->取向量->選擇堆棧指針MSP/PSP

  • 入棧

響應異常的第一個動作就是要保護現場,CM3自動的將寄存器放到正確的位置。先把PC與xPSR值保存起來就可以更好的啟動服務例程指令的預取和執行。根據ARM函數調用約定,保護異常時的中間結果R0-R3以及R12。

Cortex-M3 在進入異常服務例程時,自動壓棧了 R0-R3, R12, LR, PSR 和 PC,並且在返回時自動彈出它們,這多清爽!既加速了中斷的響應,也再不需要匯編語言代碼了

  •  取向量

在數據總線忙着入棧操作時,指令總線在同時從向量表中找出正確的異常向量。

  • 更新寄存器

在入棧和取向量完畢之后執行服務程序之前。會更新SP,PSR、PC、LR等寄存器。

  • 異常返回

異常服務程序執行完成之后,需要一個正式的返回指令,目的是改變PC值。出棧、更新NVIC寄存器。

 嵌套的中斷

CM3內核和NVIC全力支持了中斷嵌套的功能,。表現在1)自動編排異常優先級,相同或者低優先級的異常無法搶占,只能阻塞,因此對於SVC里面再次SVC會發生fault錯誤。2)自動入棧和出棧。

風險:如果嵌套過深而且此時住堆棧所剩無幾使,很容易發生堆棧被踩的風險,從而導致系統紊亂跑飛。

  • 咬尾中斷

當處理器在響應某異常時,如果又發生其它異常,但它們優先級不夠高,則被阻塞——這個我們已經知道。那么在當前的異常執行返回后,系統處理懸起的異常時,倘若還是先POP然后又把POP出來的內容PUSH回去,這不是白白浪費CPU時間嗎。為了改進這種鋪張浪費行為,引入了咬尾中斷機制。

晚到的高優先級異常

CM3的中斷處理還有另一個機制,它強調了優先級的作用,這就是“晚到的異常處理”。當CM3對某異常的響應序列還處在早期:入棧的階段,尚未執行其服務例程時,如果此時收到了高優先級異常的請求,則本次入棧就成了為高優先級中斷所做的入棧。可見,它雖然來晚了,卻還是因優先級高而受到偏袒,低優先級的異常為它“火中取栗”。

異常的返回值

在進入異常服務程序后, LR的值被自動更新為特殊的EXC_RETURN,這是一個高28位全為1的值,只有[3:0]的值有特殊含義,如表9.3所示。當異常服務例程把這個值送往PC時,就會啟動處理器的中斷返回序列。因為LR的值是由CM3自動設置的,所以只要沒有特殊需求,就不要改動它。

中斷延遲

在設計實時系統時,必須對中斷延遲進行嚴肅和仔細地估算。在這里,中斷延遲的定義是:從檢測到某中斷請求,到執行了其服務例程的第一條指令時,已經流逝了的時間。在CM3中,若存儲器系統夠快,且總線系統允許入棧與取指同時進行,同時該中斷可以立即響應,則中斷延遲是雷打不動的12周期(滿足硬實時所要求的確定性)。在與時間賽跑的這12個周期里,處理器內部一直開足馬力,進行了入棧、取向量、更新寄存器以及服務例程取指的一系列操作。但若存儲器太慢以至於引入等待周期,或者還有其它因素,則會引入額外的延時。反正CM3內核是決不會拖后腿的。

幾個特殊情況:

  • 當處理咬尾中斷時,省去了堆棧操作,因此切入新異常服務例程的耗時可以短至6周期。
  • 如果在總線接口上還有未完成的(outstanding)數據傳送,例如有一個帶緩沖的寫操作未完成,處理器也只能等待此傳送完成。這是迫不得以的——只有這樣,才能保證在發生了總線fault時,其服務例程能夠安全地搶占其它程序。
  • 當多個中斷同時請求時,也會發生中斷延遲,這表現在只有優先級最高的得到立即響應。
  • 如果中斷被掩蔽(也就是俗稱的關中,在多任務系統下滿地都有),則在掩蔽期間也會附加中斷延遲。

異常響應期間的faults

中斷響應的每步驟都可以觸發faults。

入棧錯誤:

  1. 如果在入棧期間引起了總線fault,則本次入棧操作將被強行中止,並且把總線異常懸起或者在允許時立即響應。若除能了總線fault,則此次故障將成為“硬傷”——上訪至硬fault。
  2. 在總線fault被使能的情況下,如果它的優先級比正在響應的異常高,則搶占之;否則將懸起直到引起fault的異常執行完畢。如果入棧操作引起MPU訪問違例,則產生存儲管理fault,並且必須立即執行MemFault服務例程,否則將無條件上訪成硬fault。
  3. 入棧是自動完成的,因此不可能產生用法fault。

出棧錯誤:

如果在中斷返回時的出棧期間引起了總線fault,則本次出棧操作將被強行中止,並且把總線異常懸起或立即響應。若除能了總線fault,則此次故障將成為“硬傷”——上訪至硬fault。其它情況下,只要總線fault的優先級比當前的高(也包括比當前最深嵌套的優先級高),則可以立即響應。類似地,如果是因MPU訪問違例造成的MemManage fault,且MemManage ault的服務例程必須能立即執行,否則無條件硬fault。

取向量期間:

取向量期間若是在取向量期間發生總線fault,則比較罕見,這也是最嚴重的,因此直接上硬fault。

無效返回時:

如果LR中的EXC_RETURN不是合法的值,則引起用法fault。如果用法fault被除能,也上訪成硬fault。

處理器鎖定(lockup)

在下列場合會導致鎖定

  1. 在硬fault服務程序中產生fault(雙重fault)
  2. 在NMI服務程序中纏身fault
  3. 在復位序列中產生總線fault

在鎖定狀態下寄存器和存儲器都被“凍結”, PC的值被強制為0xFFFF_FFFx,並且原地打轉地定死在那里一直取指。與此同時, CM3的另一條名叫“LOCKUP”的輸出信號線將被置為有效,芯片廠商可以檢測此信號,並且在系統復位發生器上觸發一個復位。因在雙重fault下的優先級為-1,NMI優先級為-2,NMI還能響應(再次證明了它的第一優先地位)。然而在NMI服務例程退出后,又回到鎖定狀態。

如何避免鎖定狀態

避免不必要的堆棧訪問,對於NMI來說,進入NMI常常是在危急關頭,比如掉電、短路等硬件故障,這時存儲系統可能已經失效,而對於硬fault來說,有可能SP指針已經出錯了(干擾,堆棧溢出),再次操作fault會重蹈覆轍。在設計硬fault、總線fault,存儲管理fault的服務例程時,要檢查下SP的值是否在合理范圍,再做后續工作。


免責聲明!

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



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