閱讀本筆記沒有暗示或要求的特殊知識,但對MAXQ架構和寄存器映射有基本的熟悉是一個加分項。這些信息可以在MAXQ系列用戶指南、數據資料(如MAXQ2000)和其他應用筆記(如MAXQ架構簡介;使用MAXQ2000評估板的示例應用)。本應用筆記中使用的示例的源代碼和項目文件可以下載。
MAXQ10和MAXQ20微控制器具有簡單、廉價的單向量中斷機制,而中斷源和控制則在邏輯上組織成三級分層結構。硬件不會優(yōu)先考慮中斷。應用程序代碼負責通過單個向量調度各種中斷,因此,對中斷進行編程和調試是應用程序開發(fā)周期的重要組成部分。本說明提供:
為需要編寫簡單中斷功能編程的用戶提供的入門指南
有關實現更詳細的中斷優(yōu)先級方案、嵌套中斷和可用硬件資源的最佳利用的提示。
MAXQ中斷機制概述
MAXQ系列微控制器具有一個寄存器IV(中斷向量),用于保存中斷例程的地址,以及一個位INS(中斷iN服務),用于指示中斷活動。當中斷被觸發(fā)時,處理器內核的行為就像在代碼中插入了“呼叫IV”和“移動INS,#1”指令一樣。MAXQ內核執(zhí)行子程序調用,即指令指針I(yè)P被推入堆棧并加載IV寄存器的內容,然后設置INS位表示存在活動的“服務中斷”,以防止進一步的中斷調用。中斷服務以“RETI”(或“POPI”)指令結束,該指令將返回地址從堆棧彈出到 IP 中并清除 INS 位,用戶代碼從中斷的位置恢復。
中斷觸發(fā)邏輯如圖1所示,以MAXQ2000微控制器為例。其它MAXQ微控制器可能具有不同的中斷源集,但邏輯結構在整個MAXQ系列中都是通用的。
邏輯結構從圖 1 左側列出的各個中斷源開始。每個源都有一個關聯的中斷標志,即在檢測到來自該源的中斷事件時由硬件設置的特殊位。每個源還具有單獨的使能位,允許應用程序啟用或禁用中斷源。僅當標志位和使能位都設置為 1 時,來自該源的中斷信號才有效。這些位在MAXQ架構中提供單獨的中斷信號和控制。
圖1.MAXQ2000微控制器中的中斷觸發(fā)邏輯
由于MAXQ架構是模塊化的,中斷也根據其在模塊中的位置進行分組。與單個中斷源一樣,每個模塊都有自己的中斷標志和使能位,如圖 1 中間所示。該標志是來自該模塊的所有底層中斷信號的邏輯“OR”,而使能位允許應用程序啟用或禁用整個模塊的中斷。這些位分配在兩個8位寄存器中(IIR中的標志和IMR中的使能),并在模塊級別提供中斷信號和控制。
最后,來自所有模塊的中斷信號被“OR化”以形成全局中斷觸發(fā)信號,如圖1右側所示。“中斷全局使能”位IGE允許應用禁用或啟用此信號,從而提供全局級別的中斷控制。
設置后,單個中斷標志將保持設置狀態(tài),直到被軟件(即中斷服務代碼)清除,即使導致設置該標志的條件消失或刪除。如果軟件清除標志失敗,退出服務代碼后將反復觸發(fā)中斷。模塊化中斷標志(IIR 寄存器)是只讀的;一旦應用程序代碼清除了模塊中的所有基礎單個標志,它就會自動清除。
在圖 1 所示的配置中,右側的全局中斷觸發(fā)信號處于活動狀態(tài),由左側的三個獨立源引起:UART1 傳輸、定時器1 溢出和看門狗定時器。這三者都設置了各自的標志和啟用位。另一個源(模塊 8 中的 Ext1)也是信令,但該信號在模塊級別被屏蔽(禁用),因為中斷掩碼位 IMR.1 為 0。中斷服務例程 (ISR) 中的軟件通過分析標志和使能位(圖 1 中以相反的順序顯示,即從右到左)來識別信令源,然后為每個活動源提供服務并清除各個中斷標志。
對簡單的中斷服務例程進行編程
許多應用程序不需要復雜的中斷功能,只需要一兩個中斷,而不考慮優(yōu)先級。讓我們看看如何為MAXQ編程這樣的服務例程。我們使用IAR嵌入式工作臺作為示例編程工具,但是我們的代碼主要是可移植的(除了一些特定于工具的功能,如下所示)。?
假設現有應用程序需要每毫秒在端口引腳上觸發(fā)短脈沖,同時執(zhí)行許多其他重要任務。這可以使用配置為每 1ms 生成一次中斷請求的板載定時器來實現。
為了完成中斷編程,我們需要向現有的無中斷應用程序添加一些與中斷相關的代碼。與中斷相關的代碼由兩部分組成:初始化和 ISR。初始化代碼放置在應用程序開頭的某個位置,以設置正確的中斷配置:使能位(單個、模塊和全局)和 IV 寄存器。ISR 可以放置在任何位置,并且在退出之前應執(zhí)行三個基本任務:
確定中斷源(如果僅使用一個源,則不需要)
清除中斷標志
執(zhí)行所需的操作
首先,讓我們看看這一切在匯編語言中是如何工作的。C程序員可以跳過這一部分,盡管它確實提供了對幕后發(fā)生的事情的有用見解。圖 2 顯示了我們的無中斷應用程序的源代碼。除了許多其他非常重要的任務外,它還以0的波特率連續(xù)輸出字節(jié)35x5(ASCII符號“115200”)。在硬件上運行時,可以通過COM端口輕松捕獲輸出,如圖3所示。
圖2.沒有中斷的示例應用程序代碼。
圖3.圖 2 中示例無中斷應用程序的輸出。
現在我們按照上述四個步驟添加中斷代碼,從 ISR 開始。
由于只有一個中斷處于活動狀態(tài),因此不需要源標識;
如果我們使用 Timer1 溢出中斷,則標志是模塊 3 的寄存器 8 的第 4 位。清除它
move M4[8].3,#0 ; clear interrupt flag
如果我們使用端口引腳 P0.0 觸發(fā)脈沖,則操作代碼可能如下所示:
move M0[0].0,#1 ; set pin high move M0[0].0,#0 ; set pin low
這解決了任務,但是如果沒有示波器,我們就無法看到結果。為了可視化它,讓我們通過串行端口輸出“5”以外的內容,例如“$”符號(0x24):
move M2[7],#0x24 ; start transmission
通過此添加,我們希望在輸出上的 5 中偶爾出現$s(如果執(zhí)行 ISR)。請注意,當串行端口忙于傳輸時,可以調用 ISR,從而導致“$”和“5”字符之間的沖突。當然,正確編寫的 ISR 應該避免此類沖突,但為了簡單起見,我們有意忽略了這個問題。
退出
reti ; exit ISR
中斷初始化代碼應:
將定時器1配置為每1ms溢出一次。
move M4[10],#(65536-16000) ; ovfl every 1ms @ 16MHz move M4[9],M4[10] ; init counter move M4[16],#0x0 ; 16-bit timer mode
使用ISR的地址加載IV寄存器。
move IV,# ; load interrupt vector
在所有三個級別啟用 Timer1 溢出中斷:單個、模塊和全局。
move M4[0],#0x88 ; int enabled, start the timer move IMR.4,#1 ; enable ints from module 4 move IC.0,#1 ; enable global interrupts (IGE=1)
我們還必須初始化端口引腳,即設置方向和電壓電平:
move M0[16].0,#1 ; Configure Port Pin P0.0 direction (output) move M0[0].0,#0 ; Set Port Pin P0.0 Low
將所有部分組裝在一起,我們最終得到圖 4 中所示的代碼及其輸出(如圖 5 所示)。$s如預期的那樣,端口引腳P0.0每1ms發(fā)射一次短脈沖。由于上述傳輸沖突,$s和 5 的模式并不完全規(guī)則——有些$s無法通過。
現在讓我們在 C 中重做相同的應用程序。這甚至更容易,因為C編譯器將為我們做一些工作。也就是說,IAR C 編譯器將中斷向量 IV 設置為通用 ISR,用于標識信令模塊并調用與此模塊對應的 C 函數。它還負責保存/恢復 ISR 內部使用的寄存器,因此應用程序流不會因中斷而中斷。我們需要做的就是為每個模塊編寫 ISR 函數,該函數將生成中斷并進行配置,即正確設置啟用位。后者很重要 — 如果應用程序錯誤地啟用了沒有相應 ISR 功能的中斷,則結果將難以預測。
圖4.帶中斷的示例應用程序代碼。
圖5.圖 4 和圖 6 中示例應用程序的典型輸出。
我們現在遵循相同的邏輯步驟,但這次對 ISR 函數使用 C 語法。
來源識別。我們必須告訴編譯器哪個模塊是中斷的來源:
#pragma vector=4 __interrupt void isr_module4() {}
#pragma 指令和關鍵字__interrupt通知編譯器,當模塊 4 有活動中斷信號時,應調用以下示例中的 isr_module4())。由于模塊 4 中只有一個源處于活動狀態(tài),因此不需要更多源標識。
清除標志。如果我們使用定時器1溢出中斷,則標志在寄存器T2CNB2中為位TF1。清除它
T2CNB1_bit.TF2=0; // clear interrupt flag
請注意,名稱 TF2 和 T2CNB1_bit 分別只是位 3 和寄存器 M4[8] 的替代品。它們在特定于工具的包含文件“iomaxq200x.h”中定義。
中斷操作。在端口引腳 P0.0 上發(fā)出脈沖:
PO0=1; // set pin high PO0=0; // set pin low
退出。無事可做;編譯器會處理這個問題。
SBUF0='$'; // start transmission
同樣,中斷初始化代碼是直接的ASM到C轉換,除了設置由編譯器自動完成的IV寄存器:
將定時器1配置為每1ms溢出一次。
T2R1=65536-16000; // ovfl every 1ms @ 16MHz T2V1=T2R1; // init counter T2CFG1=0; // 16-bit timer mode
使用 ISR 地址加載 IV 寄存器 — 由編譯器完成。
在所有三個級別啟用 Timer1 溢出中斷:單個、模塊和全局。
T2CNA1=0x88; // int enabled, start the timer IMR_bit.IM4=1; // enable ints from module 4 IC_bit.IGE=1; // enable global interrupts (IGE=1)
圖6.在 C 語言中使用中斷的示例應用程序。
我們還必須初始化端口引腳,即設置方向和電壓電平:
PD0=1; // Configure P0.0 direction (output) PO0=0; // Set P0.0 Low
將所有部分組裝在一起,我們最終得到圖 6 中所示的代碼。在硬件上運行時,其輸出看起來與圖 5 所示相同。
對嵌套中斷進行編程
通常,當中斷被處理時,觸發(fā)信號在全局級別被稱為INS的特殊位阻止(圖1中未顯示)。該位在進入 ISR 時由硬件自動設置,并在執(zhí)行 RETI 或 POPI 指令時清除(通常在退出 ISR 時)。當 INS = 1 時,無法觸發(fā)中斷。但是,某些應用程序可能希望允許嵌套或遞歸中斷。這可以通過清除 ISR 內的 INS 位來完成,從而允許中斷中斷服務例程流。請注意,第二個中斷調用將向量到與第一個中斷調用相同的 IV 寄存器指向的 ISR,因此應用程序在允許遞歸中斷調用時應針對無限循環(huán)進行配置。
圖7顯示了一個在端口引腳(連接到按鈕)的下降沿激活中斷的應用。本應用使用模塊0中的MAXQ2000上的Ext0中斷。按鈕連接到相應的端口引腳P0.4。中斷服務例程旨在通過清除 INS 位(圖 14 中的第 7 行)來中斷其自身的代碼。為此目的提供了內在函數 __reenable_interrupt(),盡管可以通過直接寫入位來完成相同的工作:IC_bit。INS=0;。為了防止無限循環(huán),ISR 通過在進入時遞增全局變量nest_level和在退出時遞減來計算嵌套級別。僅當嵌套級別不超過特定限制時,才會清除 INS 位(此示例中最多允許 7 個級別)。
當沒有發(fā)生中斷時,應用程序通過串行端口連續(xù)輸出字符“0”,指示正在執(zhí)行 main() 函數。按下按鈕時,ISR 會打印當前嵌套級別并執(zhí)行空閑循環(huán)幾秒鐘,以便在 ISR 仍在運行時再次按下按鈕。當嵌套達到級別 7 時,不再清除 INS 位。如果在級別 7 執(zhí)行 ISR 時按下該按鈕,則新的中斷請求將保持掛起狀態(tài)(設置了標志,但觸發(fā)信號被 INS = 1 阻止),直到 ISR 完成并退出,清除 INS 位并在級別 6 恢復 ISR。然后,掛起的中斷變?yōu)榛顒訝顟B(tài),并再次導致級別 7 的 ISR 呼叫。圖 8 說明了這種描述的行為 — 每個非零數字表示一個 ISR 條目,包括遞歸中斷調用。
編程中斷優(yōu)先級方案
到目前為止,我們只考慮了一個中斷源的簡單應用程序。更高級的應用可以同時使用多個中斷源,例如RTC報警,定時器/計數器,按鈕或其他外部I / O信號,看門狗,發(fā)送/接收與UART的通信,SPI?、1-Wire等各種中斷可能會來來去去,多個中斷源可能會同時變?yōu)榛顒訝顟B(tài),但應用程序一次只能為它們提供服務。因此,應用程序必須應用一些規(guī)則來決定應首先、第二、依此類推為哪些同時處于活動狀態(tài)的源提供服務。這些規(guī)則通常以中斷優(yōu)先級表示 — 為每個中斷源分配一個稱為優(yōu)先級的整數。如果發(fā)生沖突,優(yōu)先級較高的源會先于優(yōu)先級較低的源進行服務。?
在MAXQ架構中,這種中斷服務排序必須在軟件中實現,因為不存在硬件優(yōu)先級。在本應用筆記中,我們僅考慮確定中斷服務優(yōu)先級的眾多可能方法中的兩種:
源標識排序(無遞歸中斷)
動態(tài)中斷重新配置(帶遞歸中斷)
事實上,這兩種方法都可以在一個應用程序中混合在一起,正如我們將在下面的示例中看到的那樣,創(chuàng)建靈活有效的中斷服務結構。
圖7.在 C 語言中具有嵌套中斷的示例應用程序。
前一種方法意味著安排ISR的來源識別部分,以便首先識別和維修優(yōu)先級較高的源,然后再識別和維修優(yōu)先級較低的源。例如,假設圖 1 中的三個源同時發(fā)出信號,但應用程序希望首先處理看門狗中斷,然后處理 Timer1 溢出,然后處理 UART1 傳輸。該任務可以通過以下偽代碼解決:
if () { } if ( ) { } if ( ) { }
這種簡單的技術幾乎沒有開銷;它不需要額外的內存或遞歸中斷調用。每個中斷都按照接收順序從頭到尾執(zhí)行,除非有兩個或多個中斷掛起。在這種情況下,服務順序由應用程序代碼中的源標識排列定義。但這種方法有一個缺點:如果在為另一個源提供服務時發(fā)生緊急、優(yōu)先級最高的中斷,則必須等到 ISR 完成,到那時可能為時已晚。為了克服這個問題,我們必須允許中斷ISR流,這就引出了第二種方法——動態(tài)中斷重新配置。
后一種方法更通用,意味著每個單獨的 ISR 需要執(zhí)行以下步驟:
保存當前中斷配置并重新配置整個使能位集,以禁用所有較低(低于當前)或同等優(yōu)先級的源,但啟用更高優(yōu)先級的源
允許遞歸中斷,即清除 INS 位
執(zhí)行當前中斷的操作
禁止遞歸中斷,即設置 INS 位
恢復保存在步驟i)中斷配置并退出。
此實現允許幾乎立即為較高優(yōu)先級的中斷提供服務,即使它在為較低優(yōu)先級的源提供服務時發(fā)生。但是,此方法會消耗更多的數據和程序空間,并且隨著方案中添加的每個額外中斷源而增加。
圖8.圖 7 中示例應用程序的輸出。
為了演示這兩種方法,我們創(chuàng)建一個MAXQ2000應用示例,具有以下中斷優(yōu)先級方案:
中斷源 | 源模塊 | 優(yōu)先權 | 中斷操作 |
看門狗定時器 | 7 | 99 (最高) | 清除看門狗定時器;將符號打印到 UART0 |
UART0 傳輸 | 2 | 70 | 從緩沖區(qū)傳輸下一個字節(jié)(如果有) |
定時器1 溢出 | 4 | 50 | 在端口引腳 P0.0 上觸發(fā)脈沖(每 128 毫秒) |
外部國際 0 | 0 | 30 | 非常重要的按鈕操作(紅色按鈕) |
外部國際 10,11,12 | 1 | 10, 11, 12 | 按鈕操作(綠色按鈕) |
看門狗定時器具有最高優(yōu)先級,因為如果未及時清除,它將重置設備。然后我們利用UART的傳輸中斷,它表示一個字節(jié)已成功發(fā)送,下一個字節(jié)傳輸可以開始。此中斷也是確保快速通信和防止緩沖區(qū)溢出的高優(yōu)先級。接下來是Timer1,它以相對較慢但有規(guī)律的速度發(fā)射脈沖。按鈕中斷的優(yōu)先級較低,因為它們是不規(guī)則的。
模塊化架構使在模塊級別分配優(yōu)先級變得簡單方便。在這種情況下,唯一要保存/重新配置/恢復的配置數據是 IMR 寄存器,即 8 位模塊中斷掩碼。否則,必須在每個單獨的 ISR 中存儲、重新配置和恢復整個分散的單個使能位集。因此,我們?yōu)槟K實現了通用優(yōu)先級方法(動態(tài)重新配置),但對模塊內的中斷源實現了簡單的排序方法。
我們示例中的模塊 1 有多個中斷源,圖 9 顯示了如何在模塊 1 中斷例程 isr_module1() 中實現優(yōu)先級。首先,它保存當前中斷配置(圖 39 中的第 9 行),然后重新配置中斷以禁用模塊 1 中的源,但啟用更高優(yōu)先級的模塊 0、4、2、7(第 40 行),并通過清除 INS 位(第 41 行)重新啟用中斷。然后,它按照優(yōu)先級順序識別模塊 1 中的中斷源并為其提供服務。首先檢查優(yōu)先級較高的 int12(第 45-50 行),其次檢查優(yōu)先級較低的 int11(第 52-57 行),最后檢查優(yōu)先級最低的 int10(第 59-64 行)。這些中斷的服務例程具有較長的延遲循環(huán)(在 button() 函數內部,圖 48 中的第 55、62 和 9 行),因此在中斷例程 isr_module1() 仍在運行時可能會發(fā)生其他中斷。
其他中斷也以類似的方式設計(請參閱附錄A中的完整源代碼,可供下載),但優(yōu)先級最高的看門狗中斷除外,其中不需要重新配置。應用程序通過 UART0 寫入各種 ASCII 標記,以便可以在 PC 上捕獲它們以可視化執(zhí)行流程。為了演示,硬件組裝有兩個按鈕:一個連接到引腳P0.4,按下時激活外部中斷0;另一個連接到引腳 P5.2、P5.3、P6.0,分別對應于外部中斷 10、11、12,因此當按下該按鈕時,所有三個中斷都會同時激活。由于前一個中斷 Ext0 具有更高的優(yōu)先級,因此我們將其稱為“紅色按鈕”,而另一個按鈕將稱為“綠色按鈕”,激活三個優(yōu)先級較低的中斷。
當未按下任何按鈕時,應用程序打印“=Reset=”,然后連續(xù)寫入單詞“Main”,點“...”和單詞“”,表示重置后它執(zhí)行main()函數,并且經常被看門狗(點)中斷,偶爾被Timer1溢出打斷(參見圖10)。當檢測到任何按鈕中斷時,應用程序在 ISR 條目上打印“”,在 ISR 出口時打印“ExtN>”(N 是外部中斷的編號)。對于圖 10 中的示例,按下“綠色”按鈕一次,然后按幾次“紅色”按鈕。“綠色”按鈕同時激活了三個外部中斷 — 10、11 和 12 — 但如圖 10 所示,int12 首先根據其優(yōu)先級提供服務,而 int11 和 int10 處于掛起狀態(tài)。ISR 顯然被看門狗和計時器打斷。緊接著是 int11(int10 仍處于掛起狀態(tài)),它被使用“紅色”按鈕激活的更高優(yōu)先級的 int0 打斷。最后,緊跟在 int11 之后的是 int10,而 int0 又被按下 (int10) 的“紅色”按鈕打斷了幾次。在這個過程中的某個時刻,所有優(yōu)先中斷都被嵌套了:main功能被int0按鈕中斷,被int1按鈕中斷,被Timer<>溢出中斷,被UART傳輸中斷,被看門狗中斷!
圖9.具有多個優(yōu)先級中斷的示例應用程序(片段)。
圖 10.圖 9(附錄 A)中示例應用程序的輸出。
結論
MAXQ微控制器的中斷機制非常簡單,可配置性強,使得MAXQ的中斷編程變得容易。盡管硬件資源有限,但MAXQ獨特的模塊化架構允許開發(fā)人員以極低的開銷實現復雜的中斷優(yōu)先方案。
審核編輯:郭婷
-
微控制器
+關注
關注
48文章
7835瀏覽量
153272 -
處理器
+關注
關注
68文章
19686瀏覽量
232689 -
寄存器
+關注
關注
31文章
5397瀏覽量
122650
發(fā)布評論請先 登錄
相關推薦
帶紅外模塊的16位微控制器MAXQ61C電子資料
16位微控制器MAXQ613電子資料
16位微控制器具有紅外模塊MAXQ610電子資料
MAXQ微控制器的中斷編程

在應用編程MAXQ微控制器中可分區(qū)擦除的程序和數據閃存

在MAXQ8913微控制器中從RAM執(zhí)行應用程序

MAXQ61H 低功耗、16位MAXQ微控制器

MAXQ618 低功耗6位MAXQ微控制器
MAXQ612/MAXQ622低功耗、16位MAXQ微控制器

使用uIP堆棧將MAXQ微控制器聯網

評論