天天看點

給初學者的STM32(Cortex-M3)中斷原理及程式設計方法介紹 [原創www.cnblogs.com/helesheng]

給初學者的STM32(Cortex-M3)中斷原理及程式設計方法介紹 [原創www.cnblogs.com/helesheng]

給初學者的STM32(Cortex-M3)中斷原理及程式設計方法介紹

本人和教研室幾位老師編著的《基于STM32的嵌入式系統原理及應用》(ISBN:9787030697974)剛剛在科學出版社出版。這本書花費了半年以上的時間,凝聚了筆者作為高校教師和嵌入式工程師的一些經驗,希望對大學生、嵌入式初學者和有一定經驗的工程師都有參考和借鑒作用。在寫作中尤其注意了不做晶片手冊的“搬運工”和“翻譯者”,試圖從開發者和工程師的角度理清知識點之間的邏輯關系,給讀者一條清晰的學習路徑。寫作中盡量做到用生活中的執行個體來闡述抽象的概念;用工程執行個體來幫助大家提高嵌入式開發的實踐能力。另外為幫助讀者了解某些難點,我們在Bilibili上陸續釋出免費的講解的視訊,歡迎大家關注我的B站賬号:“何樂生0”(本文講解點這裡)。高校教師朋友們還可在微信中搜尋公衆号“科學EDU”公衆号,申請免費樣書和課程PPT。

下面将該書中關于STM32的Cortex-M3中斷控制器NVIC的一小節發出來供大家拍磚,歡迎大家批評指正。以下内容歡迎轉載,但請注明出處: https://www.cnblogs.com/helesheng

一、中斷機制概述

中斷是計算機系統的一種處理異步事件的重要方法。它的作用是在計算機的CPU運作軟體的同時,監測系統内外有沒有發生需要CPU處理的“緊急事件”:當需要處理的事件發生時,中斷控制器會打斷CPU正在處理的正常事務,轉而插入一段處理該緊急事件的代碼;而該事務處理完成之後,CPU又能正确地傳回剛才被打斷的地方,以繼續運作原來的代碼。中斷可以分為“中斷響應”、“中斷處理”和“中斷傳回”三個階段。

中斷處理事件的異步性是指,緊急事件在什麼時候發生與CPU正在運作的程式完全沒有關系,是無法預測的。既然無法預測,隻能随時檢視這些“緊急事件”是否發生,而中斷機制最重要的作用,是将CPU從不斷監測緊急事件是否發生這類繁重工作中解放出來,将這項“相對簡單”的繁重工作交給“中斷控制器”這個硬體來完成。中斷機制的第二個重要作用是判斷哪個或哪些中斷請求更緊急,應該優先被響應和處理,并且尋找不同中斷請求所對應的中斷處理代碼所在的位置。中斷機制的第三個作用是幫助CPU在運作完處理緊急事務的代碼後,正确地傳回之前運作被打斷的地方。根據上述中斷處理的過程及其作用,讀者會發現中斷機制既提高了CPU正常運作正常程式的效率,又提高了響應中斷的速度,是幾乎所有現代計算機都配備的一種重要機制。

嵌入式系統是嵌入宿主對象中,幫助宿主對象完成特定任務的計算機系統,其主要工作就是和真實世界打交道。能夠快速、高效地處理來自真實世界的異步事件成為嵌入式系統的重要标志,是以中斷對于嵌入式系統而言顯得尤其重要,是學習嵌入式系統的難點和重點。

1.1 中斷的基本概念

這裡通過一個生活執行個體來解釋中斷機制中涉及的各種概念:某人在家中讀書學習,假設可能有兩件打斷他學習的事情分别是:有人敲門來訪和接聽電話。安靜地讀書學習相當于嵌入式處理器的正常程式,而“有人敲門來訪”和“接聽電話”兩件事就是可能引發中斷的“中斷源”,中斷之前他讀書所達到的頁碼稱為“斷點”。如圖1所示,中斷源提出要求響應中斷稱為“中斷請求”;而CPU打斷原來的程式運作,轉而處理開門或接電話等事情稱為“中斷響應”;為響應事件而運作的程式稱為“中斷服務程式”;處理完異步事件,傳回的過程稱為“中斷傳回”。中斷響應過程又可以分為自動儲存目前寄存器值的“現場保護”和定位并跳轉到中斷服務程式位址兩個小步驟。中斷傳回也相應地分為恢複寄存器值的“恢複現場”和恢複原來主程式運作的位置的“傳回斷點”兩個小步驟。當然,也可以選擇不理睬這些打斷讀書的事情,例如,将手機設定為靜音狀态,此時就稱為“中斷屏蔽”。

給初學者的STM32(Cortex-M3)中斷原理及程式設計方法介紹 [原創www.cnblogs.com/helesheng]

圖1 中斷示意圖

 如圖2所示,當電話鈴聲和敲門聲同時響起時,隻能根據事情的重要性,先響應一件事,而決定孰先孰後的分級機制稱為“中斷優先級”。顯然圖2中開門迎客的優先級高于接聽電話。

給初學者的STM32(Cortex-M3)中斷原理及程式設計方法介紹 [原創www.cnblogs.com/helesheng]

圖2 中斷優先級示意圖

 優先級高可以有兩種展現,一種如圖2所示,兩個中斷同時到來時先響應優先級較高的那個中斷請求,再響應優先級低的那個。優先級高還可以展現為,即使優先級低的中斷服務程式在運作中,優先級高的中斷也可以打斷優先級低的中斷服務程式,而優先級低的中斷服務程式隻有等到優先級高的中斷服務程式運作完成後才能繼續運作。如圖3所示,開門任務能夠打斷接聽電話任務,形成類似“菊花”的嵌套結構,就稱為“中斷嵌套”。STM32中将能夠被打斷,實作中斷嵌套的優先級稱為“搶占優先級”,而不能夠被打斷,隻能優先響應的中斷優先級稱為“子優先級”。

給初學者的STM32(Cortex-M3)中斷原理及程式設計方法介紹 [原創www.cnblogs.com/helesheng]

圖3 中斷嵌套示意圖

 中斷機制中還有一個重要概念稱為“中斷向量表”,中斷向量表是一張由中斷服務程式的入口位址構成的表格,一般占據代碼空間的起始位址。處理器設計者會将所有可能響應的中斷源所對應的中斷服務程式入口位址按照固定的順序排列在該表格中。當某個中斷源被響應時,處理器會自動跳轉到該中斷源的中斷服務程式入口所在的表格位址,并由該表格位置進一步跳轉到中斷服務程式。

1.2 ARM Cortex-M3的中斷控制器——NVIC

ARM V7架構将處理器分為應用處理器A型、實時處理器R型和微控制器M型。M型中最重要的ARM Cortex-M3充分考慮了嵌入式應用中對異步事件處理的實時性要求。因而與之前的ARM架構不同,直接在Cortex-M3核心中內建了功能強勁的中斷控制器,并命名為NVIC。在核心中內建中斷控制器不但防止了不同晶片生産廠商間的不相容,還大大提高了中斷控制器和Cortex-M3核心的結合緊密度,降低了中斷響應時間,提高了實時性。

NVIC直譯為嵌套向量中斷控制器,顧名思義,指ARM Cortex-M3的中斷控制器支援中斷嵌套和中斷向量表的自動跳轉功能。典型的NVIC可支援256個中斷,其中包括16個由核心産生的異常中斷和240個外設中斷。其中,核心異常中斷指由Cortex-M3核心産生的複位、硬體錯誤、SysTick定時器中斷等中斷,而外設中斷則是由管腳電平變化、UART或DMA等外設變化引起的中斷。NVIC還能實作Cortex-M3核心響應中斷請求後的自動現場保護(自動儲存處理器狀态寄存器)和中斷傳回時的自動現場恢複(自動恢複處理器狀态寄存器)。另外還有一種稱為“中斷尾鍊(末尾連鎖)”的技術,能夠在從高優先級的中斷服務程式傳回時避免多餘的自動現場恢複,即自動進入低優先級的中斷服務程式,進而避免了一輪多餘的自動現場恢複和自動現場保護操作。

二、 STM32的NVIC

STM32的NVIC也隻是标準NVIC的一部分,但主要功能都已經包含在其中:STM32的NVIC可支援16個核心異常中斷和68個外設中斷(其中STM32F103系列60個,STM32F107系列68個)。同時,每個中斷源可配置4位優先級控制字PRI_n(ARM Cortex-M3核心定義了8位,STM32微控制器隻使用了其中的4位),具有16級可程式設計中斷優先級。

表1是STM32F103系列的中斷向量表,供讀者查詢。其中灰色部分是核心異常中斷。

表1 STM32F103系列的中斷向量表

給初學者的STM32(Cortex-M3)中斷原理及程式設計方法介紹 [原創www.cnblogs.com/helesheng]
給初學者的STM32(Cortex-M3)中斷原理及程式設計方法介紹 [原創www.cnblogs.com/helesheng]

 NVIC通過中斷優先級控制字PRI_n既支援嵌套中斷又支援非嵌套中斷,方法如表2所示,将每個中斷的優先級控制字PRI_n(4位)分為兩截:前半截用于定義本中斷的搶占優先級,後半截用于定義子優先級。而分割的具體辦法由優先級組别寄存器定義:若優先級組别定義為4,則前半截的搶占優先級占據全部4位(共可定義24=16中搶占優先級),而後半截的子優先級占據0位(無法定義子優先級);若優先級組别定義為3,則前半截的搶占優先級占據全部3位(共可定義23=8種搶占優先級),而後半截的子優先級占據1位(共可定義21=2種子優先級);其他優先級組别定義以此類推,表2所示是NVIC的中斷優先級配置。

表2 NVIC的中斷優先級配置

優先級組别

搶占優先級

子優先級

4

4位/16級

0位/0級

3

3位/8級

1位/2級

2

2位/4級

1

值得注意的是,每個中斷源都擁有自己的優先級控制字PRI_n(n為中斷源編号),但優先級組别寄存器隻有一個。即一旦對NVIC定義了優先級控制字的分割方式,則對所有中斷源的所有PRI_n,分割方式都是相同的,并且意法半導體官方不建議在程式中頻繁修改優先級組别寄存器的内容。

與本節關于通用中斷嵌套規則的描述相同,STM32的NVIC的優先級嵌套規則如下:

(1)搶占優先級高的中斷可以打斷搶占優先級低的中斷服務,構成中斷嵌套。

(2)當兩個或多個同級别搶占優先級的中斷出現時,它們不能構成中斷嵌套,但STM32先響應子優先級高的中斷請求。

(3)當兩個或者多個同級别搶占優先級和同級别子優先級的中斷同時出現時,STM32先響應在中斷向量表中靠前的那個中斷。

通過實際生活的例子類比上述NVIC響應順序原則:在火車站購票時,先比較搶占優先級,搶占優先級高(軍人)的中斷優先響應;當搶占優先級相同時,比較子優先級,子優先級高(軍銜)的中斷優先響應;當上述兩者都相同時,比較它們在中斷向量表中的位置(年齡),位置低(年齡大)的中斷優先響應。

再通過一個中斷配置執行個體,說明STM32的NVIC配置和響應順序:假定設定優先級組為2,然後進行以下設定。

(1)中斷3(RTC中斷)的搶占優先級為2,子優先級為1。

(2)中斷6(外部中斷0)的搶占優先級為3,子優先級為0。

(3)中斷7(外部中斷1)的搶占優先級為2,子優先級為0。

則中斷優先級順序為:中斷7 >中斷3 >中斷6。其中,中斷3和中斷7的搶占優先級相同,是以中斷3不能被中斷7打斷,但中斷6可以被中斷3或中斷7打斷。

三、NVIC的配置和使用

STM32的嵌套向量中斷控制器需要和中斷源配合使用,本書将在後續章節中采用标準外設庫提供的庫函數,并結合具體中斷源外設來詳細講解。這裡為了幫助讀者了解NVIC的工作方式,僅給出基于标準外設庫的NVIC通用配置流程。

(1)配置中斷優先級分組,例如:

上面代碼調用的函數“void NVIC_PriorityGroupConfig(uint32_t NVIC_Priority Group);”是意法半導體官方提供的标準外設庫函數,其功能是對中斷優先級組别進行配置。而其參數NVIC_PriorityGroup_2是由标準外設庫事先定義的宏,代表将組别設為2,也就是2位搶占優先級,2位子優先級。

(2)針對具體需要的中斷源,設定對應的搶占優先級和子優先級,初始化NVIC,例如: 

函數“void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);”也是标準外設庫中提供的函數。&NVIC_InitStructure是指向初始化結構體NVIC_InitStructure的指針。結構體NVIC_InitStructure的定義如下,其成員包含了NVIC的主要參數。

(3)編寫對應的中斷服務程式。官方提供的标準外設庫已經在檔案stm32f10 x_it.c中為STM32所包含的每一個外設編寫了中斷服務程式的架構。其命名規則為“void PPP_IRQHandler(void);”,其中PPP代表了具體中斷源的縮寫,如:

給初學者的STM32(Cortex-M3)中斷原理及程式設計方法介紹 [原創www.cnblogs.com/helesheng]