S5PV210裸机之外部中断
S5PV210中斷體系介紹
一、什么是中斷??
(1)中斷的發(fā)明是用來解決宏觀上的并行需要的。宏觀就是從整體上來看,并行就是多件事情都完成了。?
(2)微觀上的并行,就是指的真正的并行,就是精確到每一秒甚至每一刻,多個(gè)事情都是在同時(shí)進(jìn)行的。宏觀上面的并行并不等于圍觀的并行,有時(shí)候宏觀上是并行的,微觀上是串行的。?
(3)例子中一個(gè)人在看電影,快遞來了暫停電影跑去收快遞,收完快遞繼續(xù)回來看電影,這個(gè)例子就是宏觀上的并行和微觀上的串行。例子中一個(gè)人等同于SoC中1個(gè)CPU(也就是單核CPU),這個(gè)CPU看電影就不能收快遞,收快遞就不能看電影(也就是說不能真正的并行)。單核心CPU在微觀角度是串行的,但是因?yàn)镃PU很快,所以在宏觀看來可以并行。?
(4)上例中大部分時(shí)間在看電影,中間少量時(shí)間去收快遞,那么類比于CPU來說,看電影就應(yīng)該是CPU的常規(guī)任務(wù),而收快遞則應(yīng)該是中斷例程。也就是說CPU平時(shí)一直在進(jìn)行看電影任務(wù),等快遞來了(中斷發(fā)生了)快遞員(類似于中斷源)會(huì)打電話叫人去收快遞(中斷源會(huì)觸發(fā)中斷通知CPU去處理中斷),人收到電話(CPU收到中斷信號(hào))后會(huì)暫定電影(CPU保存常規(guī)任務(wù)的現(xiàn)場(chǎng))跑去收快遞(CPU去執(zhí)行中斷處理程序ISR處理中斷),收完快遞(執(zhí)行完ISR)回來繼續(xù)看電影(CPU恢復(fù)常規(guī)任務(wù)的現(xiàn)場(chǎng),繼續(xù)執(zhí)行常規(guī)任務(wù))?
(5)為什么需要中斷?因?yàn)閱魏薈PU實(shí)際無法并行的,但是通過中斷機(jī)制,可以實(shí)現(xiàn)假并行(宏觀上的并行,微觀上實(shí)際還是串行的)。?
二、 Soc對(duì)中斷的實(shí)現(xiàn)機(jī)制:異常向量表?
(1)異常向量表是CPU中某些特定地址的特定定義。當(dāng)中斷發(fā)生的時(shí)候,中斷要想辦法通知CPU去處理中斷,怎么做到?這就要靠異常向量表。?
(2)在CPU設(shè)計(jì)時(shí),就事先定義了CPU中一些特定地址作為特定異常的入口地址(譬如定義0x00000000地址為復(fù)位異常向量地址,則發(fā)生復(fù)位異常時(shí)CPU會(huì)自動(dòng)跳轉(zhuǎn)到0x00000000地址去執(zhí)行指令。又譬如外部中斷對(duì)應(yīng)的異常向量地址為0x30000008,則發(fā)生外部中斷后,CPU會(huì)硬件自動(dòng)跳轉(zhuǎn)到0x30000008地址去執(zhí)行指令。)如?
(3)以上講的是CPU硬件設(shè)計(jì)時(shí)對(duì)異常向量表的支持,下來就需要軟件支持了。硬件已經(jīng)決定了發(fā)生什么異常CPU自動(dòng)跳轉(zhuǎn)PC到哪個(gè)地址去執(zhí)行,軟件需要做的就是把處理這個(gè)異常的代碼的首地址填入這個(gè)異常向量地址。?
三、S5PV210的異常向量表?
(1)s5pv210異常向量表的基地址為0xD003_7400,下圖為異常對(duì)于基地址的偏移量;?
?
?
(2)異常向量表中各個(gè)向量的相對(duì)位置是固定的,但是他們的起始地址是不固定的,各種SoC可以不一樣,而且復(fù)雜ARM中還可以讓用戶來軟件設(shè)置這個(gè)異常向量表的基地址;?
(3)擴(kuò)展到所有架構(gòu)的CPU中:所有架構(gòu)(譬如51單片機(jī)、PIC單片機(jī))的CPU實(shí)現(xiàn)中斷都是通過異常向量表實(shí)現(xiàn)的,這個(gè)機(jī)制是不變的;但是不同CPU異常向量表的構(gòu)造和位置是不同的。?
四、異常和中斷的區(qū)別和聯(lián)系?
(1)針對(duì)SoC來說,發(fā)生復(fù)位、軟中斷、中斷、快速中斷、取指令異常、數(shù)據(jù)異常等,我們都統(tǒng)一叫異常。所以說:中斷其實(shí)是異常的一種。
(2)異常的定義就是突發(fā)事件,打斷了CPU的正常常規(guī)業(yè)務(wù),CPU不得不跳轉(zhuǎn)到異常向量表中去執(zhí)行異常處理程序;中斷是異常的一種,一般特指SoC內(nèi)的內(nèi)部外設(shè)產(chǎn)生的打斷SoC常規(guī)業(yè)務(wù),或者外部中斷(SoC的GPIO引腳傳回來的中斷)。
五、 S5PV210異常向量表的編程處理?
1、像內(nèi)存一樣去訪問異常向量表?
(1)S5PV210的異常向量表可以改變(在CP15協(xié)處理器中),以適應(yīng)操作系統(tǒng)的需求。但是目前系統(tǒng)剛啟動(dòng)時(shí),此時(shí)DRAM尚未初始化,程序都在SRAM中運(yùn)行。210在iRAM中設(shè)置了異常向量表,供暫時(shí)性使用。?
(2)查210的iROM application note文檔中iRAM的地址分配,可知,iRAM中的異常向量表起始地址為0xD0037400。知道了異常向量表的起始地址后,各個(gè)異常對(duì)應(yīng)的入口就很好知道了。?
2、函數(shù)名的實(shí)質(zhì)就是函數(shù)的首地址?
(1)函數(shù)名在C語(yǔ)言中的理解方法和變量名其實(shí)沒區(qū)別。編譯器會(huì)把這個(gè)函數(shù)的函數(shù)體對(duì)應(yīng)的代碼段和這個(gè)函數(shù)的函數(shù)名(實(shí)質(zhì)是符號(hào))對(duì)應(yīng)起來,等我們?cè)谑褂眠@個(gè)函數(shù)名符號(hào)時(shí),編譯器會(huì)將函數(shù)的函數(shù)體實(shí)際上做替換。因?yàn)楹瘮?shù)體都不止4字節(jié),而函數(shù)名這個(gè)符號(hào)只能對(duì)應(yīng)1個(gè)地址,所以實(shí)際對(duì)應(yīng)的是函數(shù)體那一個(gè)代碼段的首地址。?
(2)拿C語(yǔ)言中的語(yǔ)法來講,函數(shù)名就是這個(gè)函數(shù)的函數(shù)指針。?
總結(jié):當(dāng)我們將異常處理程序的首地址和異常向量表綁定起來后,異常處理初步階段就完成了。到目前可以保證相應(yīng)異常發(fā)生后,硬件自動(dòng)跳轉(zhuǎn)到對(duì)應(yīng)異常向量表入口去執(zhí)行時(shí),可以執(zhí)行到我們事先綁定的函數(shù)。?
總結(jié):當(dāng)我們將異常處理程序的首地址和異常向量表綁定起來后,異常處理初步階段就完成了。到目前可以保證相應(yīng)異常發(fā)生后,硬件自動(dòng)跳轉(zhuǎn)到對(duì)應(yīng)異常向量表入口去執(zhí)行時(shí),可以執(zhí)行到我們事先綁定的函數(shù)。?
3、為什么中斷處理要先在匯編中進(jìn)行?
(1)中斷處理要注意保護(hù)現(xiàn)場(chǎng)(中斷從SVC模式來,則保存SVC模式下的必要寄存器的值)和恢復(fù)現(xiàn)場(chǎng)(中斷處理完成后,準(zhǔn)備返回SVC模式前,要將保存的SVC模式下的必要寄存器的值恢復(fù)回去,不然到了SVC模式后寄存器的值亂了,SVC模式下原來正在進(jìn)行的常規(guī)任務(wù)就被你搞壞了)?
(2)保存現(xiàn)場(chǎng)包括:第一:設(shè)置IRQ棧;第二,保存LR;第三,保存R0~R12?
(3)為什么要保存LR寄存器?要考慮中斷返回的問題。中斷ISR執(zhí)行完后如何返回SVC模式下去接著執(zhí)行原來的代碼。中斷返回其實(shí)取決于我們進(jìn)入中斷時(shí)如何保存現(xiàn)場(chǎng)。中斷返回時(shí)關(guān)鍵的2個(gè)寄存器就是PC和CPSR。所以我們?cè)谶M(jìn)入IRQ模式時(shí),應(yīng)該將SVC模式下的下一句指令的地址(中斷返回地址)和CPSR保存起來,將來恢復(fù)時(shí)才可以將中斷返回地址給PC,將保存的CPSR給CPSR。?
(4)中斷返回地址就保存在LR中,而CPSR(自動(dòng))保存在(IRQ模式下的)SPSR中?
4、匯編保存現(xiàn)場(chǎng)和恢復(fù)現(xiàn)場(chǎng)
(1)保護(hù)現(xiàn)場(chǎng)關(guān)鍵是保存:中斷處理程序的返回地址,r0-r12(cpsr是自動(dòng)保存的)
(2)恢復(fù)現(xiàn)場(chǎng)主要是恢復(fù):r0-r12,pc,cpsr
六、 S5PV210的向量中斷控制寄存器?
1、異常處理的2個(gè)階段?
可以將異常處理分為2個(gè)階段來理解。第一個(gè)階段是異常向量表跳轉(zhuǎn);第二個(gè)階段就是進(jìn)入了真正的異常處理程序irq_handler之后的部分。
(1)第一個(gè)階段之所以能夠進(jìn)行,主要依賴于CPU設(shè)計(jì)時(shí)提供的異常向量表機(jī)制。第一個(gè)階段的主要任務(wù)是從異常發(fā)生到響應(yīng)異常并且保存/恢復(fù)現(xiàn)場(chǎng)、跳轉(zhuǎn)到真正的異常處理程序處。?
(2)第二個(gè)階段的目的是識(shí)別多個(gè)中斷源中究竟哪一個(gè)發(fā)生了中斷,然后調(diào)用相應(yīng)的中斷處理程序來處理這個(gè)中斷。
2、 S3C2440的第二階段處理過程
(1)第一個(gè)問題,怎么找到具體是哪個(gè)中斷:S3C2440的中斷控制器中有一個(gè)寄存器(32位的),寄存器的每一個(gè)位對(duì)應(yīng)一個(gè)中斷源(為了解決支持更多中斷源,2440又設(shè)計(jì)了
一個(gè)子中斷機(jī)制。在一級(jí)中斷寄存器中有一些中斷是共用的一個(gè)bit位,譬如AC97和WDT。對(duì)于共用中斷,用子中斷來區(qū)分究竟是哪一個(gè)發(fā)生了中斷)
(2)第二個(gè)問題,怎么找到對(duì)應(yīng)的isr的問題:首先給每個(gè)中斷做了個(gè)編號(hào),進(jìn)入isr_handler之后先通過查閱中斷源寄存器和子中斷寄存器(中哪一位為1)確定中斷的編號(hào),然后
用這個(gè)編號(hào)去isr數(shù)組(isr數(shù)組是中斷初始化時(shí)事先設(shè)定好的,就是把各個(gè)中斷的isr的函數(shù)名組成一個(gè)數(shù)組,用中斷對(duì)應(yīng)的編號(hào)作為索引來查詢這個(gè)數(shù)組)中查閱得到isr地址。
評(píng)價(jià):2440的中斷處理設(shè)計(jì)不是特別優(yōu)秀:第一個(gè)過程中使用子中斷搞成2級(jí)的很麻煩;第二個(gè)過程中計(jì)算中斷編號(hào)是個(gè)麻煩事,很耗費(fèi)時(shí)間。而中斷處理的時(shí)間是很寶貴的(
系統(tǒng)有一個(gè)性能指標(biāo),叫實(shí)時(shí)性。實(shí)時(shí)性就是中斷發(fā)生到響應(yīng)的時(shí)間,這個(gè)時(shí)間越短越好。)
3、S5PV210的第二階段處理過程
(1)第一個(gè)問題,怎么找到具體是哪個(gè)中斷:S5PV210中因?yàn)橹С值闹袛嘣春芏?#xff0c;所以直接設(shè)計(jì)了4個(gè)中斷寄存器,每個(gè)32位,每位對(duì)應(yīng)一個(gè)中斷源。(理論上210最多支持128個(gè)中斷,實(shí)際支持不足128個(gè),有些位是空的);210沒有子中斷寄存器,每個(gè)中斷源都是并列的。當(dāng)中斷發(fā)生時(shí),在irq_handler中依次去查詢4個(gè)中斷源寄存器,看哪一個(gè)的哪一位被置1,則這個(gè)位對(duì)應(yīng)的寄存器就發(fā)生了中斷,即找到了中斷編號(hào)。
(2)第二個(gè)問題,怎么找到對(duì)應(yīng)的isr的問題:210中支持的中斷源多了很多,如果還使用2440的那一套來尋找isr地址就太慢了,太影響實(shí)時(shí)性了。于是210開拓了一種全新的尋找isr的機(jī)制。210提供了很多寄存器來解決每個(gè)中斷源對(duì)應(yīng)isr的尋找問題,具體尋找過程和建立過程見下節(jié),實(shí)現(xiàn)的效果是當(dāng)發(fā)生相應(yīng)中斷時(shí),硬件會(huì)自動(dòng)的將相應(yīng)isr推入一定的寄存器中,我們軟件只要去這個(gè)寄存器中執(zhí)行函數(shù)就行了。
4、總結(jié):第一階段都相同,第二階段各不同
(1)第一階段(異常向量表階段)2440和210幾乎是完全相同的。實(shí)際上幾乎所有的CPU在第一階段都是相同的。
(2)第二階段就彼此不同了。各個(gè)SoC根據(jù)自己對(duì)實(shí)時(shí)性的要求,和支持的中斷源的多少,各自發(fā)明了各自處理中斷,找到中斷編號(hào),進(jìn)一步找到對(duì)應(yīng)isr地址的方式。
七、 S5PV210中斷處理的主要寄存器?
1、VICnINTENABLE和VICnINTENCLEAR?
(1)VICnINTENABLE 對(duì)應(yīng)interrupt enable,INTENCLEAR對(duì)應(yīng)interrupt enable clear?
(2)INTENABLE寄存器負(fù)責(zé)相應(yīng)的中斷的使能,INTENCLEAR寄存器負(fù)責(zé)相應(yīng)的中斷的禁止。?
(3)當(dāng)我們想使能(意思就是啟用這個(gè)中斷,意思就是當(dāng)硬件產(chǎn)生中斷時(shí)CPU能接收的到)某個(gè)中斷時(shí),只要在這個(gè)中斷編號(hào)對(duì)應(yīng)的VICnINTENABLE的相應(yīng)bit位寫1即可(注意這個(gè)位寫1其他位寫0對(duì)其他位沒有影響);如果我們想禁止某個(gè)中斷源時(shí),只要向VICnINTENCLEAR中相應(yīng)的位寫1即可。注意:這里的設(shè)計(jì)一共有2種:有些CPU是中斷使能和禁止是一個(gè)寄存器位,寫1就使能寫0就禁止(或者反過來寫1就禁止寫0就使能),這樣的中斷使能設(shè)計(jì)就要非常小心,要使用我們之前說過的讀改寫三部曲來操作;?
另一種就是使能和禁止分開為2個(gè)寄存器,要使能就寫使能寄存器,要禁止就寫禁止寄存器。這樣的好處是我們使能/禁止操作時(shí)不需要讀改寫,直接寫即可。
2、VICnINTSELECT(Interrupt Select Register,中斷模式選擇寄存器,0選擇IRQ ,1FIQ)?
(1)設(shè)置各個(gè)中斷的模式為irq還是fiq。一般都設(shè)置成irq?
(2)IRQ和FIQ究竟有何區(qū)別。210中支持2種中斷,irq和fiq。irq是普通中斷,fiq是快速中斷。快速中斷提供一種更快響應(yīng)處理的中斷通道,用于對(duì)實(shí)時(shí)性要求很高的中斷源。fiq在CPU設(shè)計(jì)時(shí)預(yù)先提供了一些機(jī)制保證fiq可以被快速處理,從而保證實(shí)時(shí)性。fiq的限制就是只能有一個(gè)中斷源被設(shè)置為fiq,其他都是irq。?
(3)CPU如何保證fiq比irq快?有2個(gè)原因:第一,fiq模式有專用的r8~r12,因此在fiq的isr中可以直接使用r8-r12而不用保存,這就能節(jié)省時(shí)間;第二,異常向量表中fiq是最后一個(gè)異常向量入口。因此fiq的isr不需要跳轉(zhuǎn),可以直接寫在原地,這樣就比其他異常少跳轉(zhuǎn)一次,省了些時(shí)間。
3、VICnIRQSTATUS和VICnFIQSTATUS?
(1)中斷狀態(tài)寄存器,是只讀的。當(dāng)發(fā)生了中斷時(shí),硬件會(huì)自動(dòng)將該寄存器的對(duì)應(yīng)位置為1,表示中斷發(fā)生了。軟件在處理中斷第二階段的第一階段,就是靠查詢這個(gè)寄存器來得到中斷編號(hào)的。?
4、VICnVECTPRIORITY0~VICnVECTPRIORITY31?
(1)中斷優(yōu)先級(jí)設(shè)置寄存器,設(shè)置多個(gè)中斷同時(shí)發(fā)生時(shí)先處理誰后處理誰的問題。一般來說高優(yōu)先級(jí)的中斷可以打斷低優(yōu)先級(jí)的中斷,從而嵌套處理中斷。當(dāng)然了有些硬件/軟件可以設(shè)置不支持中斷嵌套。?
5、VICnVECTADDR0~VICnVECTADDR31、VICnADDR
(1)這三個(gè)寄存器和210中斷處理第二階段的第二階段有關(guān)。?
(2)VICnVECTADDR0到31這32個(gè)寄存器分別用來存放真正的各個(gè)中斷對(duì)應(yīng)的isr的函數(shù)地址。相當(dāng)于每一個(gè)中斷源都有一個(gè)VECTADDR寄存器,程序員在設(shè)置中斷的時(shí)候,把這個(gè)?
中斷的isr地址直接放入這個(gè)中斷對(duì)應(yīng)的VECTADDR寄存器即可。?
(3)VICnADDR這個(gè)寄存器是只需要讀的,它里面的內(nèi)容是由硬件自動(dòng)設(shè)置的。當(dāng)發(fā)生了相應(yīng)中斷時(shí),硬件會(huì)自動(dòng)識(shí)別中斷編號(hào),并且會(huì)自動(dòng)找到這個(gè)中斷的VECTADDR寄存器,然?
后將其讀出復(fù)制到VICnADDR中,供我們使用。這樣的設(shè)計(jì)避免了軟件查找中斷源和isr,節(jié)省了時(shí)間,提高了210的中斷響應(yīng)速度。?
八、S5PV210中斷處理的編程實(shí)踐?
start.s文件
interrupt.c文件
#include "int.h" #include "stdio.h"void reset_exception(void) {printf("reset_exception.\n"); }void undef_exception(void) {printf("undef_exception.\n"); }void sotf_int_exception(void) {printf("sotf_int_exception.\n"); }void prefetch_exception(void) {printf("prefetch_exception.\n"); }void data_exception(void) {printf("data_exception.\n"); }// 主要功能:綁定第一階段異常向量表;禁止所有中斷;選擇所有中斷類型為IRQ; // 清除VICnADDR為0 void system_init_exception(void) {// 第一階段處理,綁定異常向量表r_exception_reset = (unsigned int)reset_exception;r_exception_undef = (unsigned int)undef_exception;r_exception_sotf_int = (unsigned int)sotf_int_exception;r_exception_prefetch = (unsigned int)prefetch_exception;r_exception_data = (unsigned int)data_exception;r_exception_irq = (unsigned int)IRQ_handle;r_exception_fiq = (unsigned int)IRQ_handle;// 初始化中斷控制器的基本寄存器intc_init(); }// 清除需要處理的中斷的中斷處理函數(shù)的地址 void intc_clearvectaddr(void) {// VICxADDR:當(dāng)前正在處理的中斷的中斷處理函數(shù)的地址VIC0ADDR = 0;VIC1ADDR = 0;VIC2ADDR = 0;VIC3ADDR = 0; }// 初始化中斷控制器 void intc_init(void) {// 禁止所有中斷// 為什么在中斷初始化之初要禁止所有中斷?// 因?yàn)橹袛嘁坏┐蜷_,因?yàn)橥獠炕蛘哂布约旱脑虍a(chǎn)生中斷后一定就會(huì)尋找isr// 而我們可能認(rèn)為自己用不到這個(gè)中斷就沒有提供isr,這時(shí)它自動(dòng)拿到的就是亂碼// 則程序很可能跑飛,所以不用的中斷一定要關(guān)掉。// 一般的做法是先全部關(guān)掉,然后再逐一打開自己感興趣的中斷。一旦打開就必須// 給這個(gè)中斷提供相應(yīng)的isr并綁定好。VIC0INTENCLEAR = 0xffffffff;VIC1INTENCLEAR = 0xffffffff;VIC2INTENCLEAR = 0xffffffff;VIC3INTENCLEAR = 0xffffffff;// 選擇中斷類型為IRQVIC0INTSELECT = 0x0;VIC1INTSELECT = 0x0;VIC2INTSELECT = 0x0;VIC3INTSELECT = 0x0;// 清VICxADDRintc_clearvectaddr(); }// 綁定我們寫的isr到VICnVECTADDR寄存器 // 綁定過之后我們就把isr地址交給硬件了,剩下的我們不用管了,硬件自己會(huì)處理 // 等發(fā)生相應(yīng)中斷的時(shí)候,我們直接到相應(yīng)的VICnADDR中去取isr地址即可。 // 參數(shù):intnum是int.h定義的物理中斷號(hào),handler是函數(shù)指針,就是我們寫的isr// VIC0VECTADDR定義為VIC0VECTADDR0寄存器的地址,就相當(dāng)于是VIC0VECTADDR0~31這個(gè) // 數(shù)組(這個(gè)數(shù)組就是一個(gè)函數(shù)指針數(shù)組)的首地址,然后具體計(jì)算每一個(gè)中斷的時(shí)候 // 只需要首地址+偏移量即可。 void intc_setvectaddr(unsigned long intnum, void (*handler)(void)) {//VIC0if(intnum<32){*( (volatile unsigned long *)(VIC0VECTADDR + 4*(intnum-0)) ) = (unsigned)handler;}//VIC1else if(intnum<64){*( (volatile unsigned long *)(VIC1VECTADDR + 4*(intnum-32)) ) = (unsigned)handler;}//VIC2else if(intnum<96){*( (volatile unsigned long *)(VIC2VECTADDR + 4*(intnum-64)) ) = (unsigned)handler;}//VIC3else{*( (volatile unsigned long *)(VIC3VECTADDR + 4*(intnum-96)) ) = (unsigned)handler;}return; }// 使能中斷 // 通過傳參的intnum來使能某個(gè)具體的中斷源,中斷號(hào)在int.h中定義,是物理中斷號(hào) void intc_enable(unsigned long intnum) {unsigned long temp;// 確定intnum在哪個(gè)寄存器的哪一位// <32就是0~31,必然在VIC0if(intnum<32){temp = VIC0INTENABLE;temp |= (1<<intnum); // 如果是第一種設(shè)計(jì)則必須位操作,第二種設(shè)計(jì)可以// 直接寫。VIC0INTENABLE = temp;}else if(intnum<64){temp = VIC1INTENABLE;temp |= (1<<(intnum-32));VIC1INTENABLE = temp;}else if(intnum<96){temp = VIC2INTENABLE;temp |= (1<<(intnum-64));VIC2INTENABLE = temp;}else if(intnum<NUM_ALL){temp = VIC3INTENABLE;temp |= (1<<(intnum-96));VIC3INTENABLE = temp;}// NUM_ALL : enable all interruptelse{VIC0INTENABLE = 0xFFFFFFFF;VIC1INTENABLE = 0xFFFFFFFF;VIC2INTENABLE = 0xFFFFFFFF;VIC3INTENABLE = 0xFFFFFFFF;}}// 禁止中斷 // 通過傳參的intnum來禁止某個(gè)具體的中斷源,中斷號(hào)在int.h中定義,是物理中斷號(hào) void intc_disable(unsigned long intnum) {unsigned long temp;if(intnum<32){temp = VIC0INTENCLEAR;temp |= (1<<intnum);VIC0INTENCLEAR = temp;}else if(intnum<64){temp = VIC1INTENCLEAR;temp |= (1<<(intnum-32));VIC1INTENCLEAR = temp;}else if(intnum<96){temp = VIC2INTENCLEAR;temp |= (1<<(intnum-64));VIC2INTENCLEAR = temp;}else if(intnum<NUM_ALL){temp = VIC3INTENCLEAR;temp |= (1<<(intnum-96));VIC3INTENCLEAR = temp;}// NUM_ALL : disable all interruptelse{VIC0INTENCLEAR = 0xFFFFFFFF;VIC1INTENCLEAR = 0xFFFFFFFF;VIC2INTENCLEAR = 0xFFFFFFFF;VIC3INTENCLEAR = 0xFFFFFFFF;}return; }// 通過讀取VICnIRQSTATUS寄存器,判斷其中哪個(gè)有一位為1,來得知哪個(gè)VIC發(fā)生中斷了 unsigned long intc_getvicirqstatus(unsigned long ucontroller) {if(ucontroller == 0)return VIC0IRQSTATUS;else if(ucontroller == 1)return VIC1IRQSTATUS;else if(ucontroller == 2)return VIC2IRQSTATUS;else if(ucontroller == 3)return VIC3IRQSTATUS;else{}return 0; }// 真正的中斷處理程序。意思就是說這里只考慮中斷處理,不考慮保護(hù)/恢復(fù)現(xiàn)場(chǎng) void irq_handler(void) {printf("irq_handler.\n");// SoC支持很多個(gè)(在低端CPU例如2440中有30多個(gè),在210中有100多個(gè))中斷// 這么多中斷irq在第一個(gè)階段走的是一條路,都會(huì)進(jìn)入到irq_handler來// 我們?cè)趇rq_handler中要去區(qū)分究竟是哪個(gè)中斷發(fā)生了,然后再去調(diào)用該中斷// 對(duì)應(yīng)的isr。// 雖然硬件已經(jīng)自動(dòng)幫我們把isr放入了VICnADDR中,但是因?yàn)橛?個(gè),所以我們必須// 先去軟件的檢查出來到底哪個(gè)VIC中斷了,也就是說isr到底在哪個(gè)VICADDR寄存器中unsigned long vicaddr[4] = {VIC0ADDR,VIC1ADDR,VIC2ADDR,VIC3ADDR};int i=0;void (*isr)(void) = NULL;for(i=0; i<4; i++){// 發(fā)生一個(gè)中斷時(shí),4個(gè)VIC中有3個(gè)是全0,1個(gè)的其中一位不是0if(intc_getvicirqstatus(i) != 0){isr = (void (*)(void)) vicaddr[i];break;}}(*isr)(); // 通過函數(shù)指針來調(diào)用函數(shù) }整個(gè)中斷的流程梳理:
整個(gè)中斷的工作分為2部分:
第一部分是我們?yōu)橹袛囗憫?yīng)而做的預(yù)備工作:
1. 初始化中斷控制器2. 綁定寫好的isr到中斷控制器3. 相應(yīng)中斷的所有條件使能第二部分是當(dāng)硬件產(chǎn)生中斷后如何自動(dòng)執(zhí)行isr:
1. 第一步,經(jīng)過異常向量表跳轉(zhuǎn)入IRQ/FIQ的入口2. 第二步,做中斷現(xiàn)場(chǎng)保護(hù)(在start.S中),然后跳入isr_handler3. 第三步,在isr_handler中先去搞清楚是哪個(gè)VIC中斷了,然后直接去這個(gè)VIC的ADDR寄存器中取isr來執(zhí)行即可。4. 第四步,isr執(zhí)行完,中斷現(xiàn)場(chǎng)恢復(fù),直接返回繼續(xù)做常規(guī)任務(wù)。總結(jié)
以上是生活随笔為你收集整理的S5PV210裸机之外部中断的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【知识】人工智能数学基础知识
- 下一篇: 大数据杀熟!用苹果手机怪我咯?