370 likes | 495 Views
第七章 中斷控制器工作原理與程式設計. Ping-Liang Lai ( 賴秉樑 ). 中斷控制器工作原理. 中斷向量表. 中斷控制器工作原理. 中斷基本概念與特性 S3C4510B 支援多達 21 個中斷源,且中斷請求可由內部功能模組或外部引腳信號產生 兩種類型的中斷 正常中斷請求 (Normal Interrupt Request, IRQ) 快速中斷請求 (Fast Interrupt Request, FIQ) 每個中斷源都有一個中斷懸置位元 ( Interrupt Pending Bit) 由四個暫存器來控制中斷的產生以及中斷進行處理
E N D
第七章中斷控制器工作原理與程式設計 Ping-Liang Lai (賴秉樑)
中斷控制器工作原理 • 中斷向量表
中斷控制器工作原理 • 中斷基本概念與特性 • S3C4510B支援多達21個中斷源,且中斷請求可由內部功能模組或外部引腳信號產生 • 兩種類型的中斷 • 正常中斷請求(Normal Interrupt Request, IRQ) • 快速中斷請求(Fast Interrupt Request, FIQ) • 每個中斷源都有一個中斷懸置位元( Interrupt Pending Bit) • 由四個暫存器來控制中斷的產生以及中斷進行處理 • 中斷優先順序暫存器 (Interrupt Priority Register) • 中斷模式暫存器 (Interrupt Mode Register) • 中斷懸置暫存器 (Interrupt Pending Register) • 中斷遮罩暫存器(Interrupt Mask Register)
中斷控制器工作原理 • 中斷優先順序暫存器 (Interrupt Priority Register) • 每一個中斷源的索引號寫入一個預定義的中斷優先順序暫存器,以獲得特定的優先順序。 • 中斷優先順序預定義為0~20
中斷控制器工作原理 • 中斷優先順序暫存器 (Interrupt Priority Register)
中斷控制器工作原理 • 中斷優先順序暫存器 (Interrupt Priority Register)
中斷控制器工作原理 • 中斷模式暫存器 (Interrupt Mode Register) • INTMOD會透過對每一位元的設定來決定每一種中斷是按照快速中斷(FIQ)還是按照正常中斷(IRQ)加以回應 • [20:0]中斷模式位元元, 當中斷模式位元元被置為 “1”: FIQ方式處理中斷 “0”: IRQ方式處理中斷
中斷控制器工作原理 • 中斷懸置暫存器 (Interrupt Pending Register) • INTPND是用來保持每一個中斷源的中斷懸置位元 • 指示中斷請求是否處於懸置狀態(未處理)。 • 如果中斷懸置位元被設定的話,則中斷懸狀態會一直保存著,直到CPU透過寫入 ‘1’ 到中斷懸置暫存器的相對應位元來加以清除 (注意,是寫 ‘1’ 來清除,而不是寫 ‘0’ ) • 當中斷懸置位元被設定時,無論中斷遮罩暫存器是否為 ‘0’,中斷服務程式都會開始執行。
中斷控制器工作原理 • 在中斷服務程式中,必須透過向中斷懸置暫存器的相對應位元寫入 ‘1’ 來清除中斷懸置旗標,以避免由於同一個中斷懸置位元導致了中斷服務程式的反覆執行。
中斷控制器工作原理 • 中斷遮罩暫存器(Interrupt Mask Register) • 當中斷遮罩位元被置為 ‘1’ 時,對應的中斷請求不能被CPU回應,當中斷遮罩位元為 ‘0’ 時,中斷請求會被回應 • 全局遮罩位(位元21)為 ‘1’時,所有的中斷請求都不能被回應,但只要中斷請求產生,對應的中斷懸置位元會被設定為‘1’,當全域遮罩位元被清除時,中斷請求會得到回應。 • 當有中斷請定產生時,對應的中斷懸置位元會被設定為 ‘1’ ,且在整體中斷遮罩位元和對應的中斷遮罩位元為 ‘0’時,中斷請求就會被加以回應
計時器工作原理 • S3C4510B提供兩個32位元的計時器T0和T1 • 可工作在間隔模式(Interval Mode)或觸發模式(Toggle Mode),對應的信號輸出為 TOUT0 和 TOUT1。 • 間隔模式(Interval Mode) • 當計時器計數溢位時產生一個脈衝輸出,該脈衝輸出產生定時中斷請求,同時從計時器配置輸出接腳(TOUTn)Pin196、Pin199輸出。 • 接腳的輸出脈衝頻率可按下式計算: fOUT = fMCLK/計時器的數據值 ; fMCLK = 50MHz • 觸發模式(Toggle Mode) • 計時器的輸出電位會持續到下一次的計數溢位時觸發產生翻轉 • 發生計時器計數溢位時,會產生計時器中斷請求,同時由配置接腳輸出電位狀態。 • 計時器輸出接腳輸出工作週期為50%的Clock信號。 • 接腳的輸出脈衝頻率可按下式計算: fOUT= fMCLK/(2×計時器的數據值)
計時器工作原理 • 計時器輸出信號時序
計時器工作原理 • 計時器的工作描述 • 當致能計數器時,會向計數器的計數暫存器填入一個資料值,然後計數暫存器開始遞減。 • 當計時器計數溢位時,會產生相對應的中斷請求,同時重新填入原來的資料值並開始加以遞減。 • 在禁用計時器的情況下,可以向計時器的暫存器寫入一個新的資料 • 如果計時器在執行時暫停,且原來的資料值不會被自動重新填入。
計時器工作原理 • 通過設置計時器控制暫存器TCON中的控制位元可以禁止或致能T0和T1。 • 計時器模式暫存器 (Timer Mode Register, TMOD) • TMOD是用於控制兩個32位元計時器的操作。 [0]計時器0致能(TE0) [1]計時器模式選擇(TMD0) 0 = 禁止計時器0 0 = 間隔模式 1 = 致能計時器0 1 = 觸發模式
計時器工作原理 [2]計時器0初始化TOUT0的值(TCLR0) 0 = 在觸發模式下,初始化TOUT0為0 1 = 在觸發模式下,初始化TOUT0為1 [3]計時器1致能(TE1) 0 = 禁用計時器1 1 = 致能計時器1 [4]計時器1模式選擇(TMD1) 0 = 間隔模式 1 = 觸發模式 [5]計時器1初始化TOUT1的值(TCLR1) 0 = 在觸發模式下初始化TOUT1為0 1 = 在觸發模式下初始化TOUT1為1
計時器工作原理 • 計時器資料暫存器(Timer Data Registers,TDATA0,TDATA1): • 其值決定計時器的計數溢位時間的長短。 • 該時間的計算公式為: (計時器資料+1)個Clock週期 [31:0]計時器0或計時器1 的數據值
計時器工作原理 • 計時器計數暫存器(Timer Count Register): • 保存計時器0或計時器1在正常工作情況下的當前計數值 [31:0]計時器0或計時器1 的計數值
計時器工作原理 • 計時器的工作過程描述 • 當致能計數器時,向計數器的計數暫存器寫入資料值,然後計數暫存器開始遞減。 • 計時器計數溢位產生相應的中斷請求,同時重新裝入原來的資料值並開始遞減。 • 在禁用計時器的情況下,可以向計時器的暫存器寫入一個新的資料。 • 如果計時器在執行時暫停,原來的資料值不會被自動重新裝入。 • 中斷控制器的工作過程描述 • 當中斷遮罩暫存器的整體遮罩位元與相對應的中斷遮罩位元清除為0時,對應的中斷請求被打開 • 當中斷條件發生時,PC指標會跳躍到例外事件處理程式中,執行相對應的操作
程式設計原理 • 一般中斷服務常式可以由三種方式來建立 • 跳躍指令 • 程式計數器傳輸指令 • 使用C語言建立中斷向量表 • 跳躍指令 • 使用跳躍指令設計中斷向量表是比較簡單的方式,但跳躍空間只有32M位內 B Reset_Handler B Underfined_Handler B SWI_Handler B Prefetch_Handler B Abort_Handler NOP B IRQ_Handler B FIQ_Handler
程式設計原理 • 程式計數器傳輸指令 • 此一方式主要是將程式計數器直接指到中斷服務常式的位址。 LDR PC, Reset_Addr LDR PC, Undefined_Addr LDR PC, SWI_Addr LDR PC, Prefetch_Addr LDR PC, Abort_Addr NOP LDR PC, IRQ_Addr LDR PC, FIQ_Addr Reset_Addr DCD Reset_Handler Underfined_Addr DCD Undefined_Addr SWI_Addr DCD SWI_Addr Prefetch_Addr DCD Prefetch_Addr Abort_Addr DCD Abort_Addr DCD 0 IRQ_Addr DCD IRQ_Addr FIQ_Addr DCD FIQ_Addr DCD P4-7
程式設計原理 • 使用C語言建立中斷向量表 • 由MAIN主函式中直接加入中斷向量表的建立。 • 使用跳躍指令的方法如下所列: • 取得中斷服務常式的位址。 • 將這位址減去相對應的向量。 • 為了允許執行預先存取的工作,需先減去0x8(2個字元組,8個位元組) • 將所得的結果向右偏移一個字元組,而不是作一個位元組的偏移。 • 測試最高的8位元是已被清除的,如此可確定結果值只有24位元長度(這是因為跳躍指令限制了偏移值) • 與0xEA000000(此為跳躍指令的指令運算碼)做OR邏輯運算,以產生在向量中所要放置的數值。 unsigned Install_Handle(unsigned routine, unsigned *vector) { unsigned vec, oldvect; vec = (( routine-(unsigned)vector-0x8) >> 2); vec = 0xea000000 | vec; oldvect = *vector; *vector = vec; return (oldvect); }
程式設計原理 • 使用程式計數器(PC)傳輸指令的方法如下 • 取得包含例外事件處理器位址(中斷服務常式的位址)的字元組位址。 • 將這位址減去相對向量的位址。 • 允許預先存取,所以需先減去0x8. • 檢查結果值是否以12位元來表示。 • 與0x59FF000做OR邏輯運算(此為程式計數器傳輸指令的指令碼,LDR pc,[pc,#offset])來產生替換向量的數值。 • 將中斷服務常式的位址放到儲存的區域。 unsigned Install_Handle(unsigned location, unsigned *vector) { unsigned vec, oldvect; vec = ( (unsigned)location - (unsigned)vector - 0x8 ) | 0xe59ff000; oldvect = *vector; *vector = vec; return (oldvect); }
實驗內容 • 編寫一個計時器定時中斷程式,並實現用計時器中斷的方式來測試實驗系統中GPIO模組的指示燈作定時的閃爍。 • 在實驗器上,下載並執行計時器中斷程式,並設定如何實現精確的定時。 • 參考程式碼在光碟中
INIT.S 程式碼 GET mem.a GET casia1.a IMPORT C_Entry CODE32 AREA Init,CODE,READONLY ENTRY B Reset_Handler B . B . B . B . NOP B . B . Reset_Handler LDR r0, =0x3FF0000 LDR r1, =0xE7FFFFA0 ;Start_addr = 0x3FE00000 STR r1, [r0] ;8K SRAM ;****************************************************** ;除能所有的中斷 ;****************************************************** LDR R2,=0x3fffff LDR R3,=0x3ff4008 ; INTMSK 中斷遮罩暫存器 STR R2,[R3]
INIT.S 程式碼 ;******************************************************* ;對於不同的處理器模式啟始化系統的堆疊 ;******************************************************* MRS R0,CPSR BIC R0,R0,#MODE_MASK ORR R0,R0,#SUP_MODE ORR R0,R0,#IBit ORR R0,R0,#FBit MSR CPSR_cf,R0 …………………………… …………………………… ;******************************************************** ;計時器設定 ;******************************************************** LDR R1,=0x3FF6000 ; TMOD 計時器模式暫式器 LDR R0,=&01 ; 啟動Timer0 STR R0,[R1] LDR R1,=0x3FF6004 ; TDATA0 計時器0資料暫存器 LDR R0,=&3FFFFF ; 計數 0x400000 次產生中斷 STR R0,[R1]
INIT.S 程式碼 ;******************************************************** ;對所有的IRQ中斷源去掉遮罩 ;******************************************************** LDR R1,=INTMOD ; 設定INTMOD為0,按IRQ方式處理中斷 LDR R0,=&0 STR R0,[R1] BL C_Entry B . END
MAIN.C 程式碼 #include "s3c4510b_add.h" unsigned Install_Handle(unsigned routine,unsigned *vector); void __irq IRQHandler(void); void C_Entry(void) { unsigned *irqvec=(unsigned*)0x18; // IRQ 例外事件向量 IOPMOD=0xff; // 將所有的埠置為輸出模式 Install_Handle((unsigned)IRQHandler,irqvec); // 設定例外事件入口點 INTMSK=0x1ffbff; // 設定INTMSK為0x1FFbFF值,計時器0中斷遮罩為0 while(1); // 無窮迴圈,等待Timer中斷產生 }
MAIN.C 程式碼 void __irq IRQHandler(void) { INTPND=INTPND|0x400; //清除中斷懸置位元 switch(IOPDATA & 0xf0) // 閃爍LED,以表示進入中斷服務常式 { case 0x0: IOPDATA=0x10; break; case 0x10: IOPDATA=0x20; break; case 0x20: IOPDATA=0x40; break; case 0x40: IOPDATA=0x80; break; default : IOPDATA=0x0; break; } }
MAIN.C 程式碼 unsigned Install_Handle(unsigned routine,unsigned *vector) { unsigned vec,oldvect; vec=((routine-(unsigned)vector-0x8)>>2); // vec=0xea000000|vec; oldvect=*vector; *vector=vec; return(oldvect); }
ARM DEBUGGER • 載入映像檔案進行除錯
ARM DEBUGGER • 按F10單步執行程式或點工作列上的圖示 觀察計時器設定的方式
ARM DEBUGGER • 設定 TMOD ( 計時器模式暫存器 ) • 設定 TDATA0 ( 計時器0資料暫存器 ) • 設定 INTMOD ( 中斷模式暫存器 ) 初始值 致能計時器0 初始值 計數 0x400000 後產生中斷 設定所有的中斷都 使用IRQ方式處理中斷
ARM DEBUGGER • 設定 IOPMOD ( I/O埠模式暫存器 ) • 設定 INTMSK ( 中斷遮罩暫存器 ) • 進入while無窮迴圈,等待中斷產生 • 當中斷產生時,計數器0的INTPND (中斷懸置暫存器 ) 訊號就會設定為1 P0~P7 為輸出 啟動計數器0中斷的回應 產生中斷 無中斷
ARM DEBUGGER • 設定 Breakpoint,程式中斷點,觀察中斷產生的情況 • 在想要在位置點滑鼠右鍵 • 或按F9 • 設定Breakpoint的位置會有紅色標號 • 點選執行後,程試會在Breakpoint停下 Go
ARM DEBUGGER • 清除計數器0的中斷懸置暫存器 • 執行完 INTPND = INTPND | 0x400 後,0x3ff4004記憶體中的值應該為 0x00000000,但由於計數器速度太快,所以執行完此行,計數器也產生了下一個中斷,所以INTPND 一直保持在0x00000400
ARM DEBUGGER • 此程式就每隔計數器0,計數0x400000次後就進入中斷副程式中,執行LED燈號的顯示。
HOME WORK • 修改計數器0資料暫存器,改變LED閃爍速度 • 加入Switch功能,來控制不同的LED閃爍