S3C2440中斷體系結(jié)構(gòu)
1)ARM體系CPU的7種工作模式
本文引用地址:http://butianyuan.cn/article/201611/316269.htm用戶模式(usr):ARM處理器正常的程序執(zhí)行狀態(tài)
快速中斷模式(fiq):用于高速數(shù)據(jù)傳輸或通道處理
中斷模式(irq):用于通用的中斷處理
管理模式(svc):操作系統(tǒng)使用的保護模式
數(shù)據(jù)訪問終止模式(abt):當(dāng)數(shù)據(jù)或指令預(yù)取終止時進入該模式,可用于虛擬存儲及存儲保護
系統(tǒng)模式(sys):運行具有特權(quán)的操作系統(tǒng)任務(wù)
未定義指令中止模式(und):當(dāng)未定義的指令執(zhí)行時進入該模式,可用于支持硬件協(xié)處理器的軟件仿真
除用戶模式外,其他6種工作模式都屬于特權(quán)模式,大多數(shù)程序運行于用戶模式,進入特權(quán)模式是為了處理中斷、異常,或者訪問被保護的系統(tǒng)資源。
ARM體系的CPU有以下兩個工作狀態(tài)
ARM狀態(tài):此時處理器執(zhí)行32位的字對齊的ARM指令
Thumb狀態(tài):此時處理器執(zhí)行16位的、半字對齊的Thumb指令
ARM920T有31個通用的32位寄存器和6個程序狀態(tài)寄存器。這37個寄存器分為7組,如下圖所示:
圖中R0-R15可以直接訪問,這些寄存器除了R15外都是通用寄存器,既可以保存地址也可以保存數(shù)據(jù)。
R13稱為棧指針寄存器,通常用于保存棧指針
R14稱為程序連接寄存器(LR),當(dāng)執(zhí)行BL子程序調(diào)用指令時,R14得到R15(程序計數(shù)器PC)的備份。
而當(dāng)發(fā)生中斷或異常時,對應(yīng)的R14_svc,R14_irq,R14_abt或R14_und中保存R15的返回值
R15是程序計數(shù)器
快 速中斷模式有7個備份寄存器R8_fiq-R14_fiq,這使得進入快速中斷模式執(zhí)行很大部分程序時(不改變R0-R7),不需要保存任何寄存器。用戶 模式、管理模式、數(shù)據(jù)訪問終止模式和未定義指令中止模式都含有兩個獨占的寄存器副本R13、R14,這樣令每個模式擁有自己的棧指針寄存器和連接寄存器。
每種工作模式還有寄存器CPSR(當(dāng)前程序狀態(tài)寄存器),它被用于標(biāo)識各種狀態(tài)和當(dāng)前處于哪種工作模式,如下圖所示:
當(dāng)一個異常發(fā)生時,將切換進入相應(yīng)的工作模式,這是ARM920T CPU將自動完成如下工作:
①在異常工作模式的連接寄存器R14中保存前一個工作模式的下一條即將執(zhí)行的指令地址。對于ARM狀態(tài),這個值是當(dāng)前PC值加4或加8
②將CPSR的值復(fù)制到異常模式的SPSR
③將CPSR的工作模式位設(shè)為這個異常對應(yīng)的工作模式
④令PC值等于這個異常模式在異常向量表中的地址,即跳轉(zhuǎn)去執(zhí)行異常向量表中的相應(yīng)指令
從異常工作模式回到之前的工作模式時,需要通過軟件完成如下事情:
①前面進入異常工作模式時,連接寄存器中保存了前一工作模式的一個指令地址,將它減去適當(dāng)?shù)闹岛筚x值給PC寄存器
②將SPSR的復(fù)制回CPSR
異常模式 | 退出異常模式時PC的計算方法 | 進入異常模式時R14中保存的值 |
管理模式(SWI指令進入) | MOVS PC, R14 | PC+4(1) |
未定義指令終止模式 | MOVS PC, R14 | PC+4(1) |
快速中斷模式 | SUBS PC, R14, #4 | PC+4(2) |
中斷模式 | SUBS PC, R14, #4 | PC+4(2) |
數(shù)據(jù)訪問終止模式 | 異常原因:指令預(yù)取終止 SUBS PC, R14, #4 | PC+4(1) |
異常原因:數(shù)據(jù)訪問終止 SUBS PC, R14, #8 | PC+8(3) |
注:
(1)PC為這些指令的地址:SWI、未定義的指令、在預(yù)取指時就失敗的指令
(2)PC為這些指令的地址:進入快速中斷模式、中斷模式前,被打斷而未執(zhí)行的指令
(3)PC為這些指令的地址:導(dǎo)致數(shù)據(jù)訪問終止的加載/存儲指令(LDR、STR、LDM和STM)
二、S3C2440中斷控制器
當(dāng)某事件發(fā)生時,硬件會設(shè)置某個寄存器,CPU在執(zhí)行完一個指令時,通過硬件查看這個寄存器,如果發(fā)現(xiàn)所關(guān)注的事件發(fā)生了,則中斷當(dāng)前程序流程,跳轉(zhuǎn)到一個固定的地址處理這個事件,最后返回繼續(xù)執(zhí)行被中斷的程序。
中斷處理的過程:
①中斷控制器匯集各類外設(shè)發(fā)出的中斷信號,告訴CPU
②CPU保存當(dāng)前程序的運行環(huán)境,調(diào)用中斷服務(wù)程序(ISR)來處理這些中斷
③在ISR中通過讀取中斷控制器、外設(shè)的相關(guān)寄存器來識別時哪個中斷,并進行相應(yīng)處理
④清除中斷:通過讀寫中斷控制器和外設(shè)的相關(guān)寄存器來實現(xiàn)
⑤最后恢復(fù)被中斷程序的運行環(huán)境(恢復(fù)寄存器),繼續(xù)執(zhí)行
s3c2440的中斷控制器結(jié)構(gòu)如上圖所示:
①request sources(without sub-register)中的中斷源被觸發(fā)后,SRCPND寄存器中相應(yīng)位被置1,如果此中斷沒有被INTMSK寄存器屏蔽或者快速中斷的話,它將被進一步處理。
② 對于request sources(with sub-register)中的中斷源被觸發(fā)后,SUBSRCPEND寄存器中的相應(yīng)位被置1,如果此中斷沒有被INTSUBMSK寄存器屏蔽的話,它在 SRCPND寄存器中的相應(yīng)位也被置1,以后的處理過程就和①步驟類似。
③如果被觸發(fā)的中斷中有快速中斷,INTMOD寄存器中為1的位對應(yīng)的中斷是FIQ,則CPU進入快速中斷模式進行處理
④ 對于一般的中斷IRQ,可能同時有幾個中斷被觸發(fā),未被INTMSK寄存器屏蔽的中斷經(jīng)過比較后,選出優(yōu)先級最高的中斷,此中斷在INTPND寄存器中的 相應(yīng)位被置1,然后CPU進入中斷模式進行處理。中斷服務(wù)程序通過讀取INTPND或者INTOFFSET來確定中斷源
三、中斷控制寄存器
1)SUBSRCPND寄存器
它用來表示INT_RXD0、INT_TXD0等中斷是否發(fā)生,每位對應(yīng)一個中斷,當(dāng)這些中斷發(fā)生并且沒有被INTSUBMSK寄存器屏蔽,則它們中的若干位將匯集出現(xiàn)在SRCPND寄存器的某一位上。要清除中斷,往此寄存器中某位寫1
2)INTSUBMSK寄存器
它用來屏蔽SUBSRCPND寄存器所標(biāo)識的中斷,INTSUBMSK寄存器中某位設(shè)置1時,對應(yīng)的中斷被屏蔽
3)SRCPND寄存器
它每一位被用來表示一個或一類中斷是否發(fā)生,要清除某一位,往此位寫1,具體參考數(shù)據(jù)手冊
4)INTMSK寄存器
用來屏蔽SRCPND寄存器所標(biāo)識的中斷。INTMSK寄存器中某位被設(shè)為1時,對應(yīng)的中斷被屏蔽,它只能屏蔽IRQ中斷,不能屏蔽FIQ
5)INTMOD寄存器
它某位被設(shè)為1時,對應(yīng)的中斷被設(shè)為FIQ,同一時間,INTMOD只能有一位被設(shè)為1
6)PRIORITY寄存器
當(dāng)有多個IRQ同時發(fā)生時,中斷控制器選出最高優(yōu)先級的中斷,首先處理它。中斷優(yōu)先級通過7個仲裁器來完成,結(jié)構(gòu)圖如下所示:
每個仲裁器基于一個位仲裁器模式控制(ARB_MODE)和選擇控制信號(ARB_SEL)的兩位來處理 6個中斷請求。
如果ARB_SEL位是 00b,優(yōu)先級是REQ0,REQ1,REQ2,REQ3,REQ4,和REQ5.
如果ARB_SEL位是 01b,優(yōu)先級是REQ0,REQ2,REQ3,REQ4,REQ1,和REQ5.
如果ARB_SEL位是 10b,優(yōu)先級是REQ0,REQ3,REQ4,REQ1,REQ2,和REQ5.
如果ARB_SEL位是 11b,優(yōu)先級是REQ0,REQ4,REQ1,REQ2,REQ3,和REQ5.
注 意仲裁器的 REQ0 總是有最高優(yōu)先級,REQ5 總是有最低優(yōu)先級。此外通過改變ARB_SEL 位,我們可以翻轉(zhuǎn) REQ1 到 REQ4 的優(yōu)先級。如果ARB_MODE位置0,ARB_SEL位不會自動改變,使得仲裁器在一個固定優(yōu)先級的模式下操作(注意在此模式下,我們通過手工改變 ARB_SEL 位來配置優(yōu)先級)。另外,如果 ARB_MODE 位是 1,ARB_SEL 位以翻轉(zhuǎn)的方式改變。例如如果 REQ1 被服務(wù),則ARB_SEL位自動的變?yōu)?1b,把REQ1放到最低的優(yōu)先級。ARB_SEL變化的詳細(xì)規(guī)則如下:
如果REQ0 或REQ5 被服務(wù),ARB_SEL位完全不會變化。
如果REQ1 被服務(wù),ARB_SEL位變?yōu)?01b。
如果REQ2 被服務(wù),ARB_SEL位變?yōu)?10b。
如果REQ3 被服務(wù),ARB_SEL位變?yōu)?11b。
如果REQ4 被服務(wù),ARB_SEL位變?yōu)?00b。
7)INTPND寄存器
經(jīng)過中斷優(yōu)先級選出優(yōu)先級最高的中斷后,這個中斷在INTPND寄存器中的相應(yīng)位被置1,隨后CPU進入中斷模式處理它
同一時間,此寄存器只有一位被置1,在ISR中,可以根據(jù)這個位確定是哪個中斷,清除中斷時,往此位寫入1
8)INTOFFSET寄存器
用來表示INTPND寄存器中哪位被置1了,即INTPND寄存器中位[x]為1時,INTOFFSET寄存器的值為x(x為0-31)
清除SRCPND、INTPND寄存器時,INTOFFSET寄存器被自動清除
四、中斷控制器操作實例:外部中斷
開發(fā)板上,K1-K4四個按鍵所接的CPU引腳可以設(shè)為外部中斷,本程序的功能是,當(dāng)按下某個按鍵時,CPU調(diào)用中斷服務(wù)程序點亮對應(yīng)的LED
@******************************************************************************
@ File:head.S
@ 功能:初始化,設(shè)置中斷模式、系統(tǒng)模式的棧,設(shè)置好中斷處理函數(shù)
@******************************************************************************
.extern main
.text
.global _start
_start:
@******************************************************************************
@ 中斷向量,本程序中,除Reset和HandleIRQ外,其它異常都沒有使用
@******************************************************************************
b Reset
@ 0x04: 未定義指令中止模式的向量地址
HandleUndef:
b HandleUndef
@ 0x08: 管理模式的向量地址,通過SWI指令進入此模式
HandleSWI:
b HandleSWI
@ 0x0c: 指令預(yù)取終止導(dǎo)致的異常的向量地址
HandlePrefetchAbort:
b HandlePrefetchAbort
@ 0x10: 數(shù)據(jù)訪問終止導(dǎo)致的異常的向量地址
HandleDataAbort:
b HandleDataAbort
@ 0x14: 保留
HandleNotUsed:
b HandleNotUsed
@ 0x18: 中斷模式的向量地址
b HandleIRQ
@ 0x1c: 快中斷模式的向量地址
HandleFIQ:
b HandleFIQ
Reset:
ldr sp, =4096 @ 設(shè)置棧指針,以下都是C函數(shù),調(diào)用前需要設(shè)好棧
bl disable_watch_dog @ 關(guān)閉WATCHDOG,否則CPU會不斷重啟
msr cpsr_c, #0xd2 @ 進入中斷模式,cpsr_c表示cpsr[7:0],0xd2=0b1101 0010
ldr sp, =3072 @ 設(shè)置中斷模式棧指針
msr cpsr_c, #0xdf @ 進入系統(tǒng)模式
ldr sp, =4096 @ 設(shè)置系統(tǒng)模式棧指針,
@ 其實復(fù)位之后,CPU就處于系統(tǒng)模式,
@ 前面的“ldr sp, =4096”完成同樣的功能,此句可省略
bl init_led @ 初始化LED的GPIO管腳
bl init_irq @ 調(diào)用中斷初始化函數(shù),在init.c中
msr cpsr_c, #0x5f @ 設(shè)置I-bit=0,開IRQ中斷
ldr lr, =halt_loop @ 設(shè)置返回地址
ldr pc, =main @ 調(diào)用main函數(shù)
halt_loop:
b halt_loop
HandleIRQ:
sub lr, lr, #4 @ 計算返回地址
stmdb sp!, { r0-r12,lr } @ 保存使用到的寄存器
@ 注意,此時的sp是中斷模式的sp
@ 初始值是上面設(shè)置的3072
ldr lr, =int_return @ 設(shè)置調(diào)用ISR即EINT_Handle函數(shù)后的返回地址
ldr pc, =EINT_Handle @ 調(diào)用中斷服務(wù)函數(shù),在interrupt.c中
int_return:
ldmia sp!, { r0-r12,pc }^ @ 中斷返回, ^表示將spsr的值復(fù)制到cpsr
/*
* init.c: 進行一些初始化
*/
#include "s3c24xx.h"
/*
* LED1-4對應(yīng)GPB5、GPB6、GPB7、GPB8
*/
#define GPB5_out (1<<(5*2)) // LED1
#define GPB6_out (1<<(6*2)) // LED2
#define GPB7_out (1<<(7*2)) // LED3
#define GPB8_out (1<<(8*2)) // LED4
/*
* K1-K4對應(yīng)GPG0,GPG3,GPG5,GPG6
*/
#define GPG0_eint (2<<(0*2)) // K1,EINT8
#define GPG3_eint (2<<(3*2)) // K2,EINT11
#define GPF5_eint (2<<(5*2)) // K3,EINT13
#define GPF6_eint (2<<(6*2)) // K4,EINT14
/*
* 關(guān)閉WATCHDOG,否則CPU會不斷重啟
*/
void disable_watch_dog(void)
{
WTCON = 0;// 關(guān)閉WATCHDOG很簡單,往這個寄存器寫0即可
}
void init_led(void)
{
GPBCON = GPB5_out | GPB6_out | GPB7_out | GPB8_out ;
}
/*
* 初始化GPIO引腳為外部中斷
* GPIO引腳用作外部中斷時,默認(rèn)為低電平觸發(fā)、IRQ方式(不用設(shè)置INTMOD)
*/
void init_irq( )
{
GPGCON = GPG0_eint | GPG3_eint |GPG5_eint |GPG6_eint;
// 對于EINT8、11、13、14,需要在EINTMASK寄存器中使能它們
EINTMASK &= (~(1<<8)) & (~(1<<11)) & (~(1<<13)) & (~(1<<14));
/*
* 設(shè)定優(yōu)先級:
* ARB_SEL0 = 00b, ARB_MODE0 = 0: REQ1 > REQ3,即EINT0 > EINT2
* 仲裁器1、6無需設(shè)置
* 最終:
* EINT0 > EINT2 > EINT11,EINT19,即K4 > K3 > K1,K2
* EINT11和EINT19的優(yōu)先級相同
*/
PRIORITY = (PRIORITY & ((~0x01) | (0x3<<7))) | (0x0 << 7) ;
//開啟EINT8_23
INTMSK &= ~(1<<5);
}
interrupt.c
#include "s3c24xx.h"
void EINT_Handle()
{
unsigned long oft = INTOFFSET;
switch( oft )
{
//INTOFFSET為5時,代表INTPND的位[5]為1,則EINT8-23中斷發(fā)生
case 5:
{
GPBDAT |= (0x0f<<5); //LED全滅
if (EINTPEND & (1<<8)) //EINT8發(fā)生(EINT8對應(yīng)K1)
GPBDAT &= ~(1<<5);
if (EINTPEND & (1<<11)) //EINT11發(fā)生(EINT8對應(yīng)K2)
GPBDAT &= ~(1<<6);
if (EINTPEND & (1<<13)) //EINT13發(fā)生(EINT8對應(yīng)K3)
GPBDAT &= ~(1<<7);
if (EINTPEND & (1<<14)) //EINT14發(fā)生(EINT8對應(yīng)K4)
GPBDAT &= ~(1<<8);
break;
}
default:
break;
}
//清除中斷
if(oft == 5)
EINTPEND = (1<<8) | (1<<11) | (1<<13) | (1<<14);
SRCPND = 1< INTPND = 1< } main.c int main() { while(1); return 0; }
評論