超詳細(xì)的2440中斷機(jī)制分析!
至于具體怎么跳轉(zhuǎn)的?
首先,我們說(shuō)了,HandleEINT0 開(kāi)始的一段內(nèi)存里面,存放的就是中斷服務(wù)函數(shù)的函數(shù)指針,ARM的體系的話,每個(gè)指針變量就是占4個(gè)字節(jié),這里就解釋了,為什么這里為每個(gè)標(biāo)號(hào)分配了4個(gè)字節(jié)的空間,里面放的就是函數(shù)指針?。?!下面再看看怎么跳轉(zhuǎn),繼續(xù)看 IsrIRQ 里面就實(shí)現(xiàn)了跳轉(zhuǎn)了
str r8,[sp,#8]
ldmfd sp!,{r8-r9,pc}
其實(shí)最核心就是這兩句了,先查找到當(dāng)前中斷服務(wù)程序的地址,將他放到 R8 里面,然后出棧,彈出給PC那么PC很自然就跳到中斷服務(wù)程序了。至于這里的堆棧問(wèn)題又是一個(gè)非常棘手的,需要好好的參透ARM的中斷架構(gòu),需要了解的可以自己仔細(xì)的閱讀 《ARM體系結(jié)構(gòu)與編程》里面說(shuō)的很詳細(xì)。我們這里的重點(diǎn)是研究怎么跳轉(zhuǎn)。
最后,我們看看在C代碼中是怎么安裝終端向量的,例如看 按鍵的外部中斷,是怎么具體設(shè)置的,參看/src/keyscan.c 里面的代碼很簡(jiǎn)單,里面只有3個(gè)函數(shù)
KeyScan_Test 是按鍵測(cè)試的主函數(shù)
Key_ISR 是按鍵中斷服務(wù)函數(shù)
在 KeyScan_Test里面,我們發(fā)現(xiàn)了有這么一句
pISR_EINT0 = pISR_EINT2 = pISR_EINT8_23 = (U32)Key_ISR;
可以理解否? Key_ISR就是上面提到的按鍵中斷服務(wù)函數(shù),函數(shù)的名字,代表的就是函數(shù)的地址?。。?!
將中斷服務(wù)函數(shù)的地址,注意了,是地址,這是一個(gè) U32型的變量。送到幾個(gè)變量,我們以pISR_EINT0 作為例子,查看頭文件定義,在 2440addr.h 里面找到
// Interrupt vector
#define pISR_EINT0 (*(unsigned *)(_ISR_STARTADDRESS+0x20))
_ISR_STARTADDRESS有沒(méi)有似曾相識(shí)的感覺(jué)?沒(méi)錯(cuò),剛才分析的匯編代碼里面就提到了
^ _ISR_STARTADDRESS ; _ISR_STARTADDRESS=0x33FF_FF00
HandleReset # 4
HandleUndef # 4
......
對(duì),地址就是這里,然后 _ISR_STARTADDRESS+0x20 就是跳過(guò)前面的異常向量,進(jìn)入IRQ中斷向量的入口,所以說(shuō)到尾
pISR_EINT0 = (U32)Key_ISR;
完成的操作就是,將 Key_ISR 的地址存放到
HandleEINT0 # 4
這個(gè)IRQ向量表里面?。。。?div>
當(dāng)按鍵中斷發(fā)生的時(shí)候,發(fā)生IRQ異常中斷當(dāng)前PC值-4 保存到LR_IRQ里面,然后執(zhí)行
b HandlerIRQ
然后是執(zhí)行
HandlerIRQ
sub sp,sp,#4 ; 預(yù)留一個(gè)用來(lái)存放PC地址
stmfd sp!,{r0} ; 保存R0,因?yàn)橄旅媸褂昧?div>
ldr r0,=HandleIRQ ; 將HandleIRQ(服務(wù)程序)的地址裝載到R0
ldr r0,[r0]
str r0,[sp,#4] ; 保存到剛才預(yù)留的地方
ldmfd sp!,{r0,pc} ; 彈出堆棧,恢復(fù)R0,并且將剛才計(jì)算好的 HandleIRQ 地址彈出到 PC堆棧是向下生長(zhǎng)的,所以 SUB SP,SP,#4 就相當(dāng)于 PUSH XX,但是這個(gè)XX這個(gè)時(shí)候并沒(méi)有用,因?yàn)檫@里用的是強(qiáng)制移動(dòng) SP 指針實(shí)現(xiàn)的。然后得到服務(wù)程序的地址,再將這個(gè)值放回剛才預(yù)留的棧的空位上面,最后就是POP出R0恢復(fù),并且將剛才得到的服務(wù)程序的地址送到 PC,那么實(shí)現(xiàn)的效果就是跳轉(zhuǎn)到 HandleIRQ 里面了。
接著看剛才是怎么安裝的HandleIRQ 的
; Setup IRQ handler
ldr r0,=HandleIRQ ;This routine is needed
ldr r1,=IsrIRQ ;if there is not subs pc,lr,#4 at 0x18, 0x1c
str r1,[r0]
可以看出,這里將 IsrIRQ 的地址的值保存到 HandleIRQ 中,也就是說(shuō),上面的 IRQ 服務(wù)程序,這個(gè)時(shí)候?qū)嶋H上就是指 IsrIRQ !
所以接著的事情就是轉(zhuǎn)移到 IsrIRQ 中執(zhí)行:
IsrIRQ
sub sp,sp,#4 ; 預(yù)留一個(gè)值來(lái)保存PC
stmfd sp!,{r8-r9}
ldr r9,=INTOFFSET ; 計(jì)算偏移量,下面解釋
ldr r9,[r9]
ldr r8,=HandleEINT0
add r8,r8,r9,lsl #2
ldr r8,[r8]
str r8,[sp,#8] ; 因?yàn)楸4媪?個(gè)寄存器R8 R9 ,所以SP下移了8位
ldmfd sp!,{r8-r9,pc} ; 恢復(fù)寄存器,彈出到PC,同上面的一樣怎么保存,操作SP,跟最后彈出到PC的部分和上面的例子一樣,下面說(shuō)說(shuō)中間的計(jì)算部分計(jì)算偏移量,其實(shí)原理很簡(jiǎn)單,首先 INTOFFSET 保存著當(dāng)前是哪個(gè)IRQ中斷,例如 0代表著 HandleEINT0,1代表HandleEINT1 ..... 等等,這不是亂來(lái),有一個(gè)表的,這個(gè)是由 S3C2440 的datasheet說(shuō)的,自己可以去查看。
然后得到 中斷處理函數(shù)的向量表,這個(gè)表的首地址就是 HandleEINT0,那么很自然的想到,怎么查表?那還不簡(jiǎn)單?HandleEINT0 + INTOFFSET 不就完了?基地址加偏移量就得到表中某項(xiàng)了,當(dāng)然,因?yàn)檫@里是中斷處理向量
每一項(xiàng)占用4個(gè)字節(jié),所以用lsl #2處理一下,左移2位相當(dāng)于乘以4,偏移量乘以4,這應(yīng)該很好理解的。
我們這個(gè)例子找到的就是 HandleEINT0 ,將里面的值讀出來(lái),里面放的是 HandleEINT0 服務(wù)函數(shù)的地址,這個(gè)地址怎么來(lái)的?是在C程序里面設(shè)置的。我們看 keyscan.c 程序,找到一個(gè) void KeyScan_Test(void) 函數(shù),
里面有這么一句:
pISR_EINT0 = pISR_EINT2 = pISR_EINT8_23 = (U32)Key_ISR;
這里是安裝了3個(gè)按鍵中斷服務(wù)程序,我們只關(guān)注 0號(hào)中斷,也就是
pISR_EINT0 = (U32)Key_ISR;
這句話什么意思?先看看pISR_EINT0的定義,在 2440addr.h 中定義
#define pISR_EINT0 (*(unsigned *)(_ISR_STARTADDRESS+0x20))
看到?jīng)]有?_ISR_STARTADDRESS 不就是剛才說(shuō)的那個(gè)異常向量的入口地址?加上一個(gè) 0x20 之后實(shí)際上指向的,就是 HandleEINT0 ?。?!這么說(shuō)來(lái),上面的意思就是,將 Key_ISR 處理函數(shù)的入口地址,送到 HandleEINT0 中。
再來(lái)看 Key_ISR ,這是一個(gè)典型的服務(wù)程序,加了_irq 作為編譯關(guān)鍵字,告訴編譯器,這個(gè)函數(shù)是中斷服務(wù)程序
得保存需要的寄存器,免得被破壞。具體可以參考 《ARM體系結(jié)構(gòu)與編程》P283 頁(yè)的描述。
static void __irq Key_ISR(void)
{
.......
}
加上 _irq 關(guān)鍵字之后,編譯器就會(huì)處理好所有的保存動(dòng)作了,并不需要多關(guān)心。但是這個(gè)是 ARM-CC 編譯器的關(guān)鍵字,GCC中并沒(méi)有這個(gè)東西,所以GCC處理中斷的時(shí)候最好還是自己保存一下。
關(guān)鍵詞:
2440中斷機(jī)
相關(guān)推薦
技術(shù)專區(qū)
- FPGA
- DSP
- MCU
- 示波器
- 步進(jìn)電機(jī)
- Zigbee
- LabVIEW
- Arduino
- RFID
- NFC
- STM32
- Protel
- GPS
- MSP430
- Multisim
- 濾波器
- CAN總線
- 開(kāi)關(guān)電源
- 單片機(jī)
- PCB
- USB
- ARM
- CPLD
- 連接器
- MEMS
- CMOS
- MIPS
- EMC
- EDA
- ROM
- 陀螺儀
- VHDL
- 比較器
- Verilog
- 穩(wěn)壓電源
- RAM
- AVR
- 傳感器
- 可控硅
- IGBT
- 嵌入式開(kāi)發(fā)
- 逆變器
- Quartus
- RS-232
- Cyclone
- 電位器
- 電機(jī)控制
- 藍(lán)牙
- PLC
- PWM
- 汽車電子
- 轉(zhuǎn)換器
- 電源管理
- 信號(hào)放大器
評(píng)論