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