s5pv210——中断系统相关介绍
以下內(nèi)容源于朱有鵬課程的學(xué)習(xí),如有侵權(quán),請告知?jiǎng)h除。
參考資料:http://www.cnblogs.com/biaohc/p/6354068.html
一、S5PV210的中斷體系介紹
1、什么是中斷?
- 中斷用來解決宏觀上的并行需求;
- 微觀上的并行,指的真正的并行,就是精確到每一秒甚至每一刻,多個(gè)事情都是在同時(shí)進(jìn)行的。
- 宏觀上的并行,并不等于微觀上的并行,有時(shí)候宏觀上是并行的,微觀上是串行的。
- 單核CPU無法并行,但是通過中斷機(jī)制,可以實(shí)現(xiàn)假并行(宏觀上的并行,微觀上實(shí)際還是串行的)。
2、中斷的實(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í)行指令。
- 譬如外部中斷對應(yīng)的異常向量地址為0x30000008,則發(fā)生外部中斷后,CPU會(huì)硬件自動(dòng)跳轉(zhuǎn)到0x30000008地址去執(zhí)行指令。
- 硬件決定發(fā)生什么異常時(shí),CPU自動(dòng)跳轉(zhuǎn)PC到哪個(gè)地址去執(zhí)行;
- 軟件把處理這個(gè)異常的代碼的首地址填入這個(gè)異常向量地址。
3、S5PV210的異常向量表
- 異常向量表中各個(gè)向量的相對位置是固定的,但是起始地址是不固定的,各種SoC可以不一樣。
- 復(fù)雜ARM中還可以讓用戶來軟件設(shè)置異常向量表的基地址。
- 所有架構(gòu)(譬如51單片機(jī)、PIC單片機(jī))的CPU的中斷,都是通過異常向量表實(shí)現(xiàn)的,但是不同CPU異常向量表的構(gòu)造和位置是不同的。
4、異常和中斷的區(qū)別和聯(lián)系
(1)對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引腳傳回來的中斷)。
二、異常向量表的編程處理
1、像內(nèi)存一樣去訪問異常向量表
- S5PV210的異常向量表可以改變(在CP15協(xié)處理器中),以適應(yīng)操作系統(tǒng)的需求。
- 但是系統(tǒng)剛啟動(dòng)時(shí),DRAM尚未初始化,程序都在SRAM中運(yùn)行。210在iRAM中設(shè)置了異常向量表,供暫時(shí)性使用。
- 查閱iRAM的地址分配,可知,iRAM中的異常向量表起始地址為0xD0037400。
2、函數(shù)名的實(shí)質(zhì)就是函數(shù)的首地址
(1)編譯器把函數(shù)體對應(yīng)的代碼段和這個(gè)函數(shù)的函數(shù)名(實(shí)質(zhì)是符號(hào))對應(yīng)起來
- 當(dāng)使用這個(gè)函數(shù)名符號(hào)時(shí),編譯器會(huì)將函數(shù)的函數(shù)體實(shí)際上做替換。因?yàn)楹瘮?shù)體都不止4字節(jié),而函數(shù)名這個(gè)符號(hào)只能對應(yīng)1個(gè)地址,所以實(shí)際對應(yīng)的是函數(shù)體那一個(gè)代碼段的首地址。
- 拿C語言中的語法來講,函數(shù)名就是這個(gè)函數(shù)的函數(shù)指針。
(2)將異常處理程序的首地址和異常向量表綁定后,異常處理初步階段就完成了。
到目前可以保證相應(yīng)異常發(fā)生后,硬件自動(dòng)跳轉(zhuǎn)到對應(yīng)異常向量表入口去執(zhí)行時(shí),可以執(zhí)行到我們事先綁定的函數(shù)。
3、為什么中斷處理要先在匯編中進(jìn)行
(1)中斷處理,需要保護(hù)現(xiàn)場和恢復(fù)現(xiàn)場
- 比如中斷從SVC模式來,則保存SVC模式下的必要寄存器的值;
- 中斷處理完成后,準(zhǔn)備返回SVC模式前,要將相關(guān)寄存器的值恢復(fù)回去,否則到了SVC模式后寄存器的值亂了,SVC模式下原來正在進(jìn)行的常規(guī)任務(wù)將會(huì)被破壞。
(2)保存現(xiàn)場
- 第一,設(shè)置IRQ棧;
- 第二,保存LR;
- 第三,保存R0~R12;
(3)為什么要保存LR寄存器?
- 要考慮中斷返回的問題,即中斷ISR執(zhí)行完后如何返回SVC模式下去接著執(zhí)行原來的代碼。
- 中斷返回其實(shí)取決于我們進(jìn)入中斷時(shí)如何保存現(xiàn)場。
- 中斷返回時(shí)關(guān)鍵的2個(gè)寄存器就是PC和CPSR。
- 在進(jìn)入IRQ模式時(shí),應(yīng)該將SVC模式下的下一句指令的地址(中斷返回地址)和CPSR保存起來,將來恢復(fù)時(shí)才可以將中斷返回地址給PC,將保存的CPSR給CPSR。
- 中斷返回地址保存在LR中,而CPSR(自動(dòng))保存在(IRQ模式下的)SPSR中。
- 見博客http://blog.csdn.net/oqqhutu12345678/article/details/71215628
(4)恢復(fù)現(xiàn)場主要是恢復(fù):r0-r12,pc,cpsr
三、S5PV210的向量中斷控制器
1、異常處理的2個(gè)階段
- 第一個(gè)階段是異常向量表跳轉(zhuǎn);
- 第二個(gè)階段是進(jìn)入真正的異常處理程序。
2、中斷處理的第一階段(異常向量表階段)處理。
- 第一個(gè)階段主要依賴CPU設(shè)計(jì)時(shí)提供的異常向量表機(jī)制,主要任務(wù)是從異常發(fā)生到響應(yīng)異常并且保存/恢復(fù)現(xiàn)場、跳轉(zhuǎn)到真正的異常處理程序處。
- 第二個(gè)階段的目的是識(shí)別多個(gè)中斷源中究竟哪一個(gè)發(fā)生了中斷,然后調(diào)用相應(yīng)的中斷處理程序來處理這個(gè)中斷。
3、S3C2440的第二階段處理過程
(1)怎么找到具體是哪個(gè)中斷?
- S3C2440的中斷控制器中有一個(gè)寄存器(32位的),寄存器的每一個(gè)位對應(yīng)一個(gè)中斷源(為了解決支持更多中斷源,2440又設(shè)計(jì)了一個(gè)子中斷機(jī)制。在一級(jí)中斷寄存器中有一些中斷是共用的一個(gè)bit位,譬如AC97和WDT。對于共用中斷,用子中斷來區(qū)分究竟是哪一個(gè)發(fā)生了中斷)
(2)怎么找到對應(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ù)組,用中斷對應(yīng)的編號(hào)作為索引來查詢這個(gè)數(shù)組)中查閱得到isr地址。
4、S5PV210的第二階段處理過程
(1)怎么找到具體是哪個(gè)中斷?
- S5PV210中因?yàn)橹С值闹袛嘣春芏?#xff0c;所以直接設(shè)計(jì)了4個(gè)中斷寄存器,每個(gè)32位,每位對應(yīng)一個(gè)中斷源。
- 理論上210最多支持128個(gè)中斷,實(shí)際支持不足128個(gè),有些位是空的;見博客http://blog.csdn.net/oqqhutu12345678/article/details/71747613。
- 210沒有子中斷寄存器,每個(gè)中斷源都是并列的。
- 當(dāng)中斷發(fā)生時(shí),在irq_handler中依次去查詢4個(gè)中斷源寄存器,看哪一個(gè)中斷源寄存器的哪一位被置1,則這個(gè)位對應(yīng)的寄存器就發(fā)生了中斷,即找到了中斷編號(hào)。
(2)怎么找到對應(yīng)的isr?
- 210中支持的中斷源多了很多,如果還使用2440的那一套來尋找isr地址就太慢了,太影響實(shí)時(shí)性了。于是210開拓了一種全新的尋找isr的機(jī)制。210提供了很多寄存器來解決每個(gè)中斷源對應(yīng)isr的尋找問題,具體尋找過程和建立過程見下節(jié),實(shí)現(xiàn)的效果是當(dāng)發(fā)生相應(yīng)中斷時(shí),硬件會(huì)自動(dòng)的將相應(yīng)isr推入一定的寄存器中,我們軟件只要去這個(gè)寄存器中執(zhí)行函數(shù)就行了。
5、總結(jié):第一階段都相同,第二階段各不同
- 第一階段(異常向量表階段)2440和210幾乎是完全相同的。實(shí)際上幾乎所有的CPU在第一階段都是相同的。
- 第二階段彼此不同。各個(gè)SoC根據(jù)自己對實(shí)時(shí)性的要求,和支持的中斷源的多少,發(fā)明了各自處理中斷,找到中斷編號(hào),進(jìn)一步找到對應(yīng)isr地址的方式。
四、S5PV210中斷處理的主要寄存器
1、VICnINTENABLE、VICnINTENCLEAR
(1)VICnINTENABLE寄存器負(fù)責(zé)相應(yīng)的中斷的使能,VICnINTENCLEAR寄存器負(fù)責(zé)相應(yīng)的中斷的禁止。
- 啟用(即當(dāng)硬件產(chǎn)生中斷時(shí)CPU能接收的到)某個(gè)中斷時(shí),需要在此中斷編號(hào)對應(yīng)的VICnINTENABLE的相應(yīng)bit位寫1;
- 禁止某個(gè)中斷源時(shí),需要向VICnINTENCLEAR中相應(yīng)的位寫1;
- 有些CPU是中斷使能和禁止是一個(gè)寄存器位,寫1就使能寫0就禁止(或者反過來寫1就進(jìn)制寫0就使能);
- 有些CPU是使能和禁止分開為2個(gè)寄存器,要使能就寫使能寄存器,要禁止就寫禁止寄存器。
(2)這里的n=0,1,2,3共四個(gè)寄存器,每個(gè)寄存器都是32bit,每個(gè)bit對應(yīng)一個(gè)中斷源是否使能 。?
- VIC0INTENABLE ?VIC0INTCLEAR;
- VIC1INTENABLE ?VIC1INTCLEAR
- VIC2INTENABLE ?VIC2INTCLEAR
- VIC3INTENABLE ?VIC3INTCLEAR
(3)例如下面的代碼
// 使能中斷 // 通過傳參的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; }
2、VICnINTSELECT寄存器
(1)設(shè)置各個(gè)中斷的模式為irq還是fiq。一般都設(shè)置成irq。
(2)IRQ和FIQ究竟有何區(qū)別?
- 210中支持2種中斷,irq和fiq。irq是普通中斷,fiq是快速中斷。
- 快速中斷提供一種更快響應(yīng)處理的中斷通道,用于對實(shí)時(shí)性要求很高的中斷源。
- fiq在CPU設(shè)計(jì)時(shí)預(yù)先提供了一些機(jī)制保證fiq可以被快速處理,從而保證實(shí)時(shí)性。
- fiq的限制就是只能有一個(gè)中斷源被設(shè)置為fiq,其他都是irq。
(3)CPU如何保證fiq比irq快?
- 第一,fiq模式有專用的r8~r12,因此在fiq的isr中可以直接使用r8-r12而不用保存,這就能節(jié)省時(shí)間;
- 第二,異常向量表中fiq是最后一個(gè)異常向量入口。因此fiq的isr不需要跳轉(zhuǎn),可以直接寫在原地,這樣就比其他異常少跳轉(zhuǎn)一次,省了些時(shí)間。
(4)這里的n=0,1,2,3共四個(gè)寄存器,可以設(shè)置各個(gè)中斷的模式。
- VIC0INTSELECT,VIC1INTSELECT,VIC2INTSELECT,VIC3INTSELECT。
(5)代碼
// 清除需要處理的中斷的中斷處理函數(shù)的地址 void intc_clearvectaddr(void) {// VICxADDR:當(dāng)前正在處理的中斷的中斷處理函數(shù)的地址(即isr的入口地址,見3的代碼示例)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;// 這里把所有的中斷源的中斷類型設(shè)置為IRQ;其實(shí)可以具體到設(shè)置每一個(gè)中斷的中斷模式 VIC0INTSELECT = 0x0;VIC1INTSELECT = 0x0;VIC2INTSELECT = 0x0;VIC3INTSELECT = 0x0;// 清VICxADDRintc_clearvectaddr(); }
3、VICnIRQSTATUS、VICnFIQSTATUS
(1)中斷狀態(tài)寄存器
- 該寄存器是只讀的。
- 當(dāng)發(fā)生了中斷時(shí),硬件會(huì)自動(dòng)將該寄存器的對應(yīng)位置為1,表示中斷發(fā)生了。
- 軟件在處理中斷第二階段的第一階段,就是靠查詢這個(gè)寄存器來得到中斷編號(hào)的。
- 有四個(gè):VIC0IRQSTATUS,VIC1IRQSTATUS,VIC2IRQSTATUS,VIC3IRQSTATUS。
(2)代碼示例
// 通過讀取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)場 void irq_handler(void) {//printf("irq_handler.\n");// SoC支持很多個(gè)(在低端CPU例如2440中有30多個(gè),在210中有100多個(gè))中斷// 這么多中斷irq在第一個(gè)階段走的是一條路,都會(huì)進(jìn)入到irq_handler來// 我們在irq_handler中要去區(qū)分究竟是哪個(gè)中斷發(fā)生了,然后再去調(diào)用該中斷// 對應(yīng)的isr。// 雖然硬件已經(jīng)自動(dòng)幫我們把isr放入了VICnADDRESS中,但是因?yàn)橛?個(gè),所以我們必須// 先去軟件的檢查出來到底哪個(gè)VIC中斷了,也就是說isr到底在哪個(gè)VICnADDRESS寄存器中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ù) }
4、VICnVECTPRIORITY0~VICnVECTPRIORITY31寄存器
- 中斷優(yōu)先級(jí)設(shè)置寄存器,設(shè)置多個(gè)中斷同時(shí)發(fā)生時(shí)先處理誰后處理誰的問題。
- 一般來說高優(yōu)先級(jí)的中斷可以打斷低優(yōu)先級(jí)的中斷,從而嵌套處理中斷。
5、VICnVECTADDR0~VICnVECTADDR31寄存器
(1)這些寄存器和210中斷處理第二階段的第二階段有關(guān)。
(2)VICnVECTADDR0~31這32個(gè)寄存器。
- 分別用來存放真正的各個(gè)中斷對應(yīng)的isr的函數(shù)地址。即中斷處理函數(shù)的存放地址。
- 相當(dāng)于每一個(gè)中斷源都有一個(gè)VECTADDR寄存器,程序員在設(shè)置中斷的時(shí)候,把這個(gè)中斷的isr地址直接放入這個(gè)中斷對應(yīng)的VECTADDR寄存器即可。
- n=0,1,2,3;
6、VICnADDRESS寄存器
- 內(nèi)容由硬件自動(dòng)設(shè)置。當(dāng)發(fā)生中斷時(shí),硬件自動(dòng)識(shí)別中斷編號(hào),并且自動(dòng)找到這個(gè)中斷的VECTADDR寄存器,把寄存器的內(nèi)容復(fù)制到VICADDRESS中,以供使用。
- 這樣的設(shè)計(jì)避免了軟件查找中斷源和isr,節(jié)省了時(shí)間,提高了210的中斷響應(yīng)速度。
五、總結(jié)
整個(gè)中斷過程可以分為兩部分第一部分是我們?yōu)橹袛囗憫?yīng)而做的預(yù)備工作:
- 初始化中斷控制器
- ?綁定寫好的isr到中斷控制器
- 相應(yīng)中斷的所有條件使能
- 第一步,經(jīng)過異常向量表跳轉(zhuǎn)入IRQ/FIQ的入口(IRQ_handl:)
- 第二步,做中斷現(xiàn)場保護(hù)(在start.S中),然后跳入isr_handler
- 第三步,在isr_handler中先去搞清楚是哪個(gè)VIC中斷了,然后直接去這個(gè)VIC的ADDR寄存器中取isr來執(zhí)行即可
- 第四步,isr執(zhí)行完,中斷現(xiàn)場恢復(fù),直接返回繼續(xù)做常規(guī)任務(wù)。
總結(jié)
以上是生活随笔為你收集整理的s5pv210——中断系统相关介绍的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: dev cpp的常用快捷键
- 下一篇: Windows-server-2008-