国产毛片a精品毛-国产毛片黄片-国产毛片久久国产-国产毛片久久精品-青娱乐极品在线-青娱乐精品

查看: 4120|回復(fù): 6
打印 上一主題 下一主題

庖丁解牛 ARM9 中斷處理過程

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
發(fā)表于 2013-11-11 16:35:04 | 只看該作者 |只看大圖 回帖獎勵 |倒序瀏覽 |閱讀模式
關(guān)鍵詞: ARM9 , 中斷

這個 2440test里面的中斷寫的向量有些隱蔽,兜了很多個圈,也難怪這么難理解,下面
就對這個東西抽絲剝繭,看清楚這究竟是一個怎么樣的過程。
中斷向量
b HandlerIRQ ;handler for IRQ interrupt
很自然,因為所有的單片機都是那樣,中斷向量一般放在開頭,用過單片機的人都會很熟悉
那就不多說了。
異常服務(wù)程序
這里不用中斷(interrupt)而用異常(exception),畢竟中斷只是異常的一種情況,呵呵
下面主要分析的是“中斷異常”說白了,就是我們平時單片機里面用的中斷!!!所有有器件
引起的中斷,例如TIMER中斷,UART中斷,外部中斷等等,都有一個統(tǒng)一的入口,那就是中斷
異常 IRQ ! 然后從IRQ的服務(wù)函數(shù)里面分辨出,當前究竟是什么中斷,再跳轉(zhuǎn)到相應(yīng)的中斷
服務(wù)程序。這樣看來,ARM比單片機要復(fù)雜一些了,不過原理是不變的。
上面說的就是思路,跟著這個思路來接著分析。
HandlerIRQ 很明顯是一個標號,我們找到了
HandlerIRQ HANDLER HandleIRQ
這里是一個宏定義,我們再找到這個宏,看他是怎么定義的:
MACRO
$HandlerLabel HANDLER $HandleLabel
$HandlerLabel
sub sp,sp,#4 ;decrement sp(to store jump address)
stmfd sp!,{r0} ;PUSH the work register to stack(lr does not push because it return to original
address)
ldr r0,=$HandleLabel ;load the address of HandleXXX to r0
ldr r0,[r0] ;load the contents(service routine start address) of HandleXXX
str r0,[sp,#4] ;store the contents(ISR) of HandleXXX to stack
ldmfd sp!,{r0,pc} ;POP the work register and pc(jump to ISR)
MEND
用 HandlerIRQ 將這個宏展開之后得到的結(jié)果實際是這樣的
HandlerIRQ
sub sp,sp,#4 ;decrement sp(to store jump address)
stmfd sp!,{r0} ;PUSH the work register to stack(lr does not push because it return to original
address)
ldr r0,=HandleIRQ ;load the address of HandleXXX to r0
ldr r0,[r0] ;load the contents(service routine start address) of HandleXXX
str r0,[sp,#4] ;store the contents(ISR) of HandleXXX to stack
ldmfd sp!,{r0,pc} ;POP the work register and pc(jump to ISR)
至于具體的跳轉(zhuǎn)原理下面再說好了,這樣的話就容易看的多了,很明顯, HandlerIRQ 還是一個標號,IRQ異常向量就是跳
轉(zhuǎn)到這里執(zhí)行的,這里粗略看一下,應(yīng)該是保存現(xiàn)場,然后跳轉(zhuǎn)到真正的處理函數(shù),那么很容易
發(fā)現(xiàn)了這么一句 ldr r0,=HandleIRQ ,沒錯,我們又找到了一個標號 HandleIRQ ,看來真正的處理函數(shù)應(yīng)該是這個 HandleIRQ ,繼續(xù)尋找
AREA RamData, DATA, READWRITE
^ _ISR_STARTADDRESS ; _ISR_STARTADDRESS=0x33FF_FF00
HandleReset # 4
HandleUndef # 4
HandleSWI # 4
HandlePabort # 4
HandleDabort # 4
HandleReserved # 4
HandleIRQ # 4
最后我們發(fā)現(xiàn)在這里找到了 HandleIRQ ,^ 其實就是 MAP ,這段程序的意思是,從 _ISR_STARTADDRESS
開始,預(yù)留一個變量,每個變量一個標號,預(yù)留的空間為 4個字節(jié),也就是 32BIT,其實這里放的是真正
的C寫的處理函數(shù)的地址,說白了,就是函數(shù)指針 - -
這樣做的話就很靈活了

接著,我們需要安裝IRQ處理句柄,說白了,就是設(shè)置處理函數(shù)的地址,讓PC指針可以正確的跳轉(zhuǎn)。
于是我們在接著的找到安裝句柄的語句

; 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對應(yīng)的地址里面,前面說了 HandleIRQ 放的是中斷處理的函數(shù)的入口地址,我們繼續(xù)找 IsrIRQ
IsrIRQ
sub sp,sp,#4 ;reserved for PC
stmfd sp!,{r8-r9}
ldr r9,=INTOFFSET
ldr r9,[r9]
ldr r8,=HandleEINT0
add r8,r8,r9,lsl #2
ldr r8,[r8]
str r8,[sp,#8]
ldmfd sp!,{r8-r9,pc}

要理解這個代碼,得先學(xué)學(xué)2440的中斷系統(tǒng)了,INTOFFSET存放的是當前中斷的偏移號,根據(jù)偏移就知道當前是哪個中斷源發(fā)生的中斷。
注意了,我們說的是中斷,而不是異常,看看原來的表是啥樣子的
^ _ISR_STARTADDRESS ; _ISR_STARTADDRESS=0x33FF_FF00
HandleReset # 4
HandleUndef # 4
HandleSWI # 4
HandlePabort # 4
HandleDabort # 4
HandleReserved # 4
HandleIRQ # 4
HandleFIQ # 4
HandleEINT0 # 4
HandleEINT1 # 4
HandleEINT2 # 4
HandleEINT3 # 4
.......
可以看到,前面幾個是異常,從 HandleEINT0 就是 IRQ異常的向量存放的地方了,這樣就可以理解為什么上面 IsrIRQ 里面里面要執(zhí)行那條指令
ldr r8,=HandleEINT0
add r8,r8,r9,lsl #2
道理很簡單, HandleEINT0 就是所有IRQ中斷向量表的入口,在這個地址上面,加上一個適當?shù)钠屏浚?br /> INTOFFSET ,那么我們知道現(xiàn)在,到底是哪個IRQ在申請中斷了。
至于具體怎么跳轉(zhuǎn)的?
首先,我們說了,HandleEINT0 開始的一段內(nèi)存里面,存放的就是中斷服務(wù)函數(shù)的函數(shù)指針,ARM的體系的話,每個指針變量就是占4個字節(jié),這里就解釋了,為什么這里為每個標號分配了4個字節(jié)的空間,里面放的就是函數(shù)指針!!!下面再看看怎么跳轉(zhuǎn),繼續(xù)看 IsrIRQ 里面就實現(xiàn)了跳轉(zhuǎn)了
str r8,[sp,#8]
ldmfd sp!,{r8-r9,pc}
其實最核心就是這兩句了,先查找到當前中斷服務(wù)程序的地址,將他放到 R8 里面,然后出棧,彈出給PC
那么PC很自然就跳到中斷服務(wù)程序了。至于這里的堆棧問題又是一個非常棘手的,需要好好的參透ARM的中斷架構(gòu),需要了解的可以自己仔細的閱讀 《ARM體系結(jié)構(gòu)與編程》里面說的很詳細。我們這里的重點是研究怎么跳轉(zhuǎn)。
最后,我們看看在C代碼中是怎么安裝終端向量的,例如看 按鍵的外部中斷,是怎么具體設(shè)置的,參看/src/keyscan.c 里面的代碼很簡單,里面只有3個函數(shù)
KeyScan_Test 是按鍵測試的主函數(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ù)的地址,注意了,是地址,這是一個 U32型的變量。送到幾個變量,我們以pISR_EINT0
作為例子,查看頭文件定義,在 2440addr.h 里面找到
// Interrupt vector
#define pISR_EINT0 (*(unsigned *)(_ISR_STARTADDRESS+0x20))
_ISR_STARTADDRESS有沒有似曾相識的感覺?沒錯,剛才分析的匯編代碼里面就提到了
^ _ISR_STARTADDRESS ; _ISR_STARTADDRESS=0x33FF_FF00
HandleReset # 4
HandleUndef # 4
......
對,地址就是這里,然后 _ISR_STARTADDRESS+0x20 就是跳過前面的異常向量,進入IRQ中斷向量的入口
所以說到尾
pISR_EINT0 = (U32)Key_ISR;
完成的操作就是,將 Key_ISR 的地址存放到
HandleEINT0 # 4
這個IRQ向量表里面!!!!
當按鍵中斷發(fā)生的時候,發(fā)生IRQ異常中斷
當前PC值-4 保存到LR_IRQ里面,然后執(zhí)行
b HandlerIRQ
然后是執(zhí)行
HandlerIRQ
sub sp,sp,#4 ; 預(yù)留一個用來存放PC地址
stmfd sp!,{r0} ; 保存R0,因為下面使用了
ldr r0,=HandleIRQ ; 將HandleIRQ(服務(wù)程序)的地址裝載到R0
ldr r0,[r0]
str r0,[sp,#4] ; 保存到剛才預(yù)留的地方
ldmfd sp!,{r0,pc} ; 彈出堆棧,恢復(fù)R0,并且將剛才計算好的 HandleIRQ 地址彈出到 PC
堆棧是向下生長的,所以 SUB SP,SP,#4 就相當于 PUSH XX,但是這個XX這個時候并沒有用,因為這里用的是強制移動 SP 指針實現(xiàn)的。然后得到服務(wù)程序的地址,再將這個值放回剛才預(yù)留的棧的空位上面,最后
就是POP出R0恢復(fù),并且將剛才得到的服務(wù)程序的地址送到 PC,那么實現(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 中,也就是說,上面的 IRQ 服務(wù)程序,這個時候?qū)嶋H上就是指 IsrIRQ !
所以接著的事情就是轉(zhuǎn)移到 IsrIRQ 中執(zhí)行:
IsrIRQ
sub sp,sp,#4 ; 預(yù)留一個值來保存PC
stmfd sp!,{r8-r9}
ldr r9,=INTOFFSET ; 計算偏移量,下面解釋
ldr r9,[r9]
ldr r8,=HandleEINT0
add r8,r8,r9,lsl #2
ldr r8,[r8]
str r8,[sp,#8] ; 因為保存了2個寄存器R8 R9 ,所以SP下移了8位
ldmfd sp!,{r8-r9,pc} ; 恢復(fù)寄存器,彈出到PC,同上面的一樣
怎么保存,操作SP,跟最后彈出到PC的部分和上面的例子一樣,下面說說中間的計算部分
計算偏移量,其實原理很簡單,首先 INTOFFSET 保存著當前是哪個IRQ中斷,例如 0代表著 HandleEINT0,1代表HandleEINT1 ..... 等等,這不是亂來,有一個表的,這個是由 S3C2440 的datasheet說的,自己可以去查看。
然后得到 中斷處理函數(shù)的向量表,這個表的首地址就是 HandleEINT0,那么很自然的想到,怎么查表?那還不簡
單?HandleEINT0 + INTOFFSET 不就完了?基地址加偏移量就得到表中某項了,當然,因為這里是中斷處理向量每一項占用4個字節(jié),所以用lsl #2處理一下,左移2位相當于乘以4,偏移量乘以4,這應(yīng)該很好理解的。
我們這個例子找到的就是 HandleEINT0 ,將里面的值讀出來,里面放的是 HandleEINT0 服務(wù)函數(shù)的地址,這個
地址怎么來的?是在C程序里面設(shè)置的。我們看 keyscan.c 程序,找到一個 void KeyScan_Test(void) 函數(shù),里面有這么一句:
pISR_EINT0 = pISR_EINT2 = pISR_EINT8_23 = (U32)Key_ISR;
這里是安裝了3個按鍵中斷服務(wù)程序,我們只關(guān)注 0號中斷,也就是
pISR_EINT0 = (U32)Key_ISR;
這句話什么意思?先看看pISR_EINT0的定義,在 2440addr.h 中定義
#define pISR_EINT0 (*(unsigned *)(_ISR_STARTADDRESS+0x20))
看到?jīng)]有?_ISR_STARTADDRESS 不就是剛才說的那個異常向量的入口地址?加上一個 0x20
之后實際上指向的,就是 HandleEINT0 !!!這么說來,上面的意思就是,將 Key_ISR 處理函數(shù)的入口地址,送到 HandleEINT0 中。嵌入式學(xué)習(xí)QQ754634522
再來看 Key_ISR ,這是一個典型的服務(wù)程序,加了_irq 作為編譯關(guān)鍵字,告訴編譯器,這個函數(shù)是中斷服務(wù)程序得保存需要的寄存器,免得被破壞。具體可以參考 《ARM體系結(jié)構(gòu)與編程》P283 頁的描述。
static void __irq Key_ISR(void)
{
.......
}
加上 _irq 關(guān)鍵字之后,編譯器就會處理好所有的保存動作了,并不需要多關(guān)心。但是這個是 ARM-CC 編譯器的關(guān)鍵字,GCC中并沒有這個東西,所以GCC處理中斷的時候最好還是自己保存一下。深圳專業(yè)嵌入式ARM、Linux、單片機專業(yè)技術(shù)實訓(xùn),學(xué)習(xí)顧問郭老師:QQ754634522


沙發(fā)
 樓主| 發(fā)表于 2013-11-18 10:23:04 | 只看該作者
支持
板凳
 樓主| 發(fā)表于 2013-11-19 14:15:15 | 只看該作者
不錯,學(xué)習(xí)支持
地板
發(fā)表于 2014-2-10 09:49:15 | 只看該作者
復(fù)制下來!!!!!!!!!我自己好好學(xué)習(xí)!!!!!!!!!!!!!!

謝謝.jpg (8.65 KB)

謝謝.jpg
地下室
 樓主| 發(fā)表于 2014-2-10 10:23:17 | 只看該作者
spy007868 發(fā)表于 2014-2-10 09:49
復(fù)制下來!!!!!!!!!我自己好好學(xué)習(xí)!!!!!!!!!!!!!!

好好學(xué)習(xí),天天向上
6
發(fā)表于 2014-2-20 01:41:48 | 只看該作者
這個 2440test里面的中斷寫的向量有些隱蔽,兜了很多個圈,也難怪這么難理解,下面
就對這個東西抽絲剝繭,看清楚這究竟是一個怎么樣的過程。
中斷向量
b HandlerIRQ ;handler for IRQ interrupt
很自然,因為所有的單片機都是那樣,中斷向量一般放在開頭,用過單片機的人都會很熟悉
那就不多說了。
異常服務(wù)程序
這里不用中斷(interrupt)而用異常(exception),畢竟中斷只是異常的一種情況,呵呵
下面主要分析的是“中斷異常”說白了,就是我們平時單片機里面用的中斷!!!所有有器件
引起的中斷,例如TIMER中斷,UART中斷,外部中斷等等,都有一個統(tǒng)一的入口,那就是中斷
異常 IRQ ! 然后從IRQ的服務(wù)函數(shù)里面分辨出,當前究竟是什么中斷,再跳轉(zhuǎn)到相應(yīng)的中斷
服務(wù)程序。這樣看來,ARM比單片機要復(fù)雜一些了,不過原理是不變的。
上面說的就是思路,跟著這個思路來接著分析。
HandlerIRQ 很明顯是一個標號,我們找到了
HandlerIRQ HANDLER HandleIRQ
這里是一個宏定義,我們再找到這個宏,看他是怎么定義的:
MACRO
$HandlerLabel HANDLER $HandleLabel
$HandlerLabel
sub sp,sp,#4 ;decrement sp(to store jump address)
stmfd sp!,{r0} USH the work register to stack(lr does not push because it return to original
address)
ldr r0,=$HandleLabel ;load the address of HandleXXX to r0
ldr r0,[r0] ;load the contents(service routine start address) of HandleXXX
str r0,[sp,#4] ;store the contents(ISR) of HandleXXX to stack
ldmfd sp!,{r0,pc} OP the work register and pc(jump to ISR)
MEND
用 HandlerIRQ 將這個宏展開之后得到的結(jié)果實際是這樣的
HandlerIRQ
sub sp,sp,#4 ;decrement sp(to store jump address)
stmfd sp!,{r0} USH the work register to stack(lr does not push because it return to original
address)
ldr r0,=HandleIRQ ;load the address of HandleXXX to r0
ldr r0,[r0] ;load the contents(service routine start address) of HandleXXX
str r0,[sp,#4] ;store the contents(ISR) of HandleXXX to stack
ldmfd sp!,{r0,pc} OP the work register and pc(jump to ISR)
至于具體的跳轉(zhuǎn)原理下面再說好了,這樣的話就容易看的多了,很明顯, HandlerIRQ 還是一個標號,IRQ異常向量就是跳
轉(zhuǎn)到這里執(zhí)行的,這里粗略看一下,應(yīng)該是保存現(xiàn)場,然后跳轉(zhuǎn)到真正的處理函數(shù),那么很容易
發(fā)現(xiàn)了這么一句 ldr r0,=HandleIRQ ,沒錯,我們又找到了一個標號 HandleIRQ ,看來真正的處理函數(shù)應(yīng)該是這個 HandleIRQ ,繼續(xù)尋找
AREA RamData, DATA, READWRITE
^ _ISR_STARTADDRESS ; _ISR_STARTADDRESS=0x33FF_FF00
HandleReset # 4
HandleUndef # 4
HandleSWI # 4
HandlePabort # 4
HandleDabort # 4
HandleReserved # 4
HandleIRQ # 4
最后我們發(fā)現(xiàn)在這里找到了 HandleIRQ ,^ 其實就是 MAP ,這段程序的意思是,從 _ISR_STARTADDRESS
開始,預(yù)留一個變量,每個變量一個標號,預(yù)留的空間為 4個字節(jié),也就是 32BIT,其實這里放的是真正
的C寫的處理函數(shù)的地址,說白了,就是函數(shù)指針 - -
這樣做的話就很靈活了

接著,我們需要安裝IRQ處理句柄,說白了,就是設(shè)置處理函數(shù)的地址,讓PC指針可以正確的跳轉(zhuǎn)。
于是我們在接著的找到安裝句柄的語句

; 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對應(yīng)的地址里面,前面說了 HandleIRQ 放的是中斷處理的函數(shù)的入口地址,我們繼續(xù)找 IsrIRQ
IsrIRQ
sub sp,sp,#4 ;reserved for PC
stmfd sp!,{r8-r9}
ldr r9,=INTOFFSET
ldr r9,[r9]
ldr r8,=HandleEINT0
add r8,r8,r9,lsl #2
ldr r8,[r8]
str r8,[sp,#8]
ldmfd sp!,{r8-r9,pc}

要理解這個代碼,得先學(xué)學(xué)2440的中斷系統(tǒng)了,INTOFFSET存放的是當前中斷的偏移號,根據(jù)偏移就知道當前是哪個中斷源發(fā)生的中斷。
注意了,我們說的是中斷,而不是異常,看看原來的表是啥樣子的
^ _ISR_STARTADDRESS ; _ISR_STARTADDRESS=0x33FF_FF00
HandleReset # 4
HandleUndef # 4
HandleSWI # 4
HandlePabort # 4
HandleDabort # 4
HandleReserved # 4
HandleIRQ # 4
HandleFIQ # 4
HandleEINT0 # 4
HandleEINT1 # 4
HandleEINT2 # 4
HandleEINT3 # 4
.......
可以看到,前面幾個是異常,從 HandleEINT0 就是 IRQ異常的向量存放的地方了,這樣就可以理解為什么上面 IsrIRQ 里面里面要執(zhí)行那條指令
ldr r8,=HandleEINT0
add r8,r8,r9,lsl #2
道理很簡單, HandleEINT0 就是所有IRQ中斷向量表的入口,在這個地址上面,加上一個適當?shù)钠屏浚?br /> INTOFFSET ,那么我們知道現(xiàn)在,到底是哪個IRQ在申請中斷了。
至于具體怎么跳轉(zhuǎn)的?
首先,我們說了,HandleEINT0 開始的一段內(nèi)存里面,存放的就是中斷服務(wù)函數(shù)的函數(shù)指針,ARM的體系的話,每個指針變量就是占4個字節(jié),這里就解釋了,為什么這里為每個標號分配了4個字節(jié)的空間,里面放的就是函數(shù)指針!!!下面再看看怎么跳轉(zhuǎn),繼續(xù)看 IsrIRQ 里面就實現(xiàn)了跳轉(zhuǎn)了
str r8,[sp,#8]
ldmfd sp!,{r8-r9,pc}
其實最核心就是這兩句了,先查找到當前中斷服務(wù)程序的地址,將他放到 R8 里面,然后出棧,彈出給PC
那么PC很自然就跳到中斷服務(wù)程序了。至于這里的堆棧問題又是一個非常棘手的,需要好好的參透ARM的中斷架構(gòu),需要了解的可以自己仔細的閱讀 《ARM體系結(jié)構(gòu)與編程》里面說的很詳細。我們這里的重點是研究怎么跳轉(zhuǎn)。
最后,我們看看在C代碼中是怎么安裝終端向量的,例如看 按鍵的外部中斷,是怎么具體設(shè)置的,參看/src/keyscan.c 里面的代碼很簡單,里面只有3個函數(shù)
KeyScan_Test 是按鍵測試的主函數(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ù)的地址,注意了,是地址,這是一個 U32型的變量。送到幾個變量,我們以pISR_EINT0
作為例子,查看頭文件定義,在 2440addr.h 里面找到
// Interrupt vector
#define pISR_EINT0 (*(unsigned *)(_ISR_STARTADDRESS+0x20))
_ISR_STARTADDRESS有沒有似曾相識的感覺?沒錯,剛才分析的匯編代碼里面就提到了
^ _ISR_STARTADDRESS ; _ISR_STARTADDRESS=0x33FF_FF00
HandleReset # 4
HandleUndef # 4
......
對,地址就是這里,然后 _ISR_STARTADDRESS+0x20 就是跳過前面的異常向量,進入IRQ中斷向量的入口
所以說到尾
pISR_EINT0 = (U32)Key_ISR;
完成的操作就是,將 Key_ISR 的地址存放到
HandleEINT0 # 4
這個IRQ向量表里面!!!!
當按鍵中斷發(fā)生的時候,發(fā)生IRQ異常中斷
當前PC值-4 保存到LR_IRQ里面,然后執(zhí)行
b HandlerIRQ
然后是執(zhí)行
HandlerIRQ
sub sp,sp,#4 ; 預(yù)留一個用來存放PC地址
stmfd sp!,{r0} ; 保存R0,因為下面使用了
ldr r0,=HandleIRQ ; 將HandleIRQ(服務(wù)程序)的地址裝載到R0
ldr r0,[r0]
str r0,[sp,#4] ; 保存到剛才預(yù)留的地方
ldmfd sp!,{r0,pc} ; 彈出堆棧,恢復(fù)R0,并且將剛才計算好的 HandleIRQ 地址彈出到 PC
堆棧是向下生長的,所以 SUB SP,SP,#4 就相當于 PUSH XX,但是這個XX這個時候并沒有用,因為這里用的是強制移動 SP 指針實現(xiàn)的。然后得到服務(wù)程序的地址,再將這個值放回剛才預(yù)留的棧的空位上面,最后
就是POP出R0恢復(fù),并且將剛才得到的服務(wù)程序的地址送到 PC,那么實現(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 中,也就是說,上面的 IRQ 服務(wù)程序,這個時候?qū)嶋H上就是指 IsrIRQ !
所以接著的事情就是轉(zhuǎn)移到 IsrIRQ 中執(zhí)行:
IsrIRQ
sub sp,sp,#4 ; 預(yù)留一個值來保存PC
stmfd sp!,{r8-r9}
ldr r9,=INTOFFSET ; 計算偏移量,下面解釋
ldr r9,[r9]
ldr r8,=HandleEINT0
add r8,r8,r9,lsl #2
ldr r8,[r8]
str r8,[sp,#8] ; 因為保存了2個寄存器R8 R9 ,所以SP下移了8位
ldmfd sp!,{r8-r9,pc} ; 恢復(fù)寄存器,彈出到PC,同上面的一樣
怎么保存,操作SP,跟最后彈出到PC的部分和上面的例子一樣,下面說說中間的計算部分
計算偏移量,其實原理很簡單,首先 INTOFFSET 保存著當前是哪個IRQ中斷,例如 0代表著 HandleEINT0,1代表HandleEINT1 ..... 等等,這不是亂來,有一個表的,這個是由 S3C2440 的datasheet說的,自己可以去查看。
然后得到 中斷處理函數(shù)的向量表,這個表的首地址就是 HandleEINT0,那么很自然的想到,怎么查表?那還不簡
單?HandleEINT0 + INTOFFSET 不就完了?基地址加偏移量就得到表中某項了,當然,因為這里是中斷處理向量每一項占用4個字節(jié),所以用lsl #2處理一下,左移2位相當于乘以4,偏移量乘以4,這應(yīng)該很好理解的。
我們這個例子找到的就是 HandleEINT0 ,將里面的值讀出來,里面放的是 HandleEINT0 服務(wù)函數(shù)的地址,這個
地址怎么來的?是在C程序里面設(shè)置的。我們看 keyscan.c 程序,找到一個 void KeyScan_Test(void) 函數(shù),里面有這么一句:
pISR_EINT0 = pISR_EINT2 = pISR_EINT8_23 = (U32)Key_ISR;
這里是安裝了3個按鍵中斷服務(wù)程序,我們只關(guān)注 0號中斷,也就是
pISR_EINT0 = (U32)Key_ISR;
這句話什么意思?先看看pISR_EINT0的定義,在 2440addr.h 中定義
#define pISR_EINT0 (*(unsigned *)(_ISR_STARTADDRESS+0x20))
看到?jīng)]有?_ISR_STARTADDRESS 不就是剛才說的那個異常向量的入口地址?加上一個 0x20
之后實際上指向的,就是 HandleEINT0 !!!這么說來,上面的意思就是,將 Key_ISR 處理函數(shù)的入口地址,送到 HandleEINT0 中。嵌入式學(xué)習(xí)QQ754634522
再來看 Key_ISR ,這是一個典型的服務(wù)程序,加了_irq 作為編譯關(guān)鍵字,告訴編譯器,這個函數(shù)是中斷服務(wù)程序得保存需要的寄存器,免得被破壞。具體可以參考 《ARM體系結(jié)構(gòu)與編程》P283 頁的描述。
static void __irq Key_ISR(void)
{
.......
}
加上 _irq 關(guān)鍵字之后,編譯器就會處理好所有的保存動作了,并不需要多關(guān)心。但是這個是 ARM-CC 編譯器的關(guān)鍵字,GCC中并沒有這個東西,所以GCC處理中斷的時候最好還是自己保存一下。深圳專業(yè)嵌入式ARM、Linux、單片機專業(yè)技術(shù)實訓(xùn),學(xué)習(xí)顧問郭老師:QQ754634522

------
這想當場聽聽老師講課,估計受益更大!
7
 樓主| 發(fā)表于 2014-2-26 10:40:49 | 只看該作者
歡迎現(xiàn)場感受
您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

關(guān)于我們  -  服務(wù)條款  -  使用指南  -  站點地圖  -  友情鏈接  -  聯(lián)系我們
電子工程網(wǎng) © 版權(quán)所有   京ICP備16069177號 | 京公網(wǎng)安備11010502021702
快速回復(fù) 返回頂部 返回列表
主站蜘蛛池模板: 青青青手机视频在线观看 | 精品欧美一区二区三区在线 | 狠狠狠综合色 | 欧美日韩片 | 男女午夜视频 | 无毒不卡在线观看 | 精品国产一区二区三区19 | 国产色视频在线观看免费 | 天海翼一区二区在线观看 | 91极品女神嫩模在线播放 | 欧美精品在欧美一区二区 | www.亚洲精品.com | 国产成人一区二区在线不卡 | 日本亚洲欧美国产ay | 色妹子在线 | 国产成人久久精品麻豆二区 | 五婷婷| 欧美日本一道道一区二区三 | 91麻豆精品国产高清在线 | 中文在线亚洲 | 国产一级特黄a大片99 | 成年女人18毛片毛片免费 | 欧美精品一区二区久久 | 亚洲国产精品一区二区三区久久 | 免费不卡中文字幕在线 | 91精品欧美| 天空之城动漫在线观看完整版免费 | 色综合天天综合网国产成人网 | 成人激情黄色 | 日本不卡在线一区二区三区视频 | igao网 | 中文字幕日韩在线观看 | 亚欧毛片 | www青青草 | 99久久久久国产精品免费 | 欧美一区色 | 香蕉视频亚洲一级 | 在线观看精品自拍视频 | 欧美一级精品 | 国产欧美一区二区精品性色 | 综合色在线观看 |