新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > S3C2440外部中斷詳解

        S3C2440外部中斷詳解

        作者: 時間:2016-12-02 來源:網絡 收藏
        要想正確地執行2440的外部中斷,一般需要完成兩個部分內容:中斷初始化和中斷處理函數。
        在具體執行中斷之前,要初始化好要用的中斷。2440的外部中斷引腳EINT與通用IO引腳F和G復用,要想使用中斷功能,就要把相應的引腳配置成中斷模式,如我們想把端口F0設置成外部中斷,而其他引腳功能不變,則GPFCON=(GPFCON & ~0x3) | 0x2。配置完引腳后,還需要配置具體的中斷功能。我們要打開某一中斷的屏蔽,這樣才能響應該中斷,相對應的寄存器為INTMSK;還要設置外部中斷的觸發方式,如低電平、高電平、上升沿、下降沿等,相對應的寄存器為EXTINTn。另外由于EINT4到EINT7共用一個中斷向量,EINT8到EINT23也共用一個中斷向量,而INTMSK只負責總的中斷向量的屏蔽,要具體打開某一具體的中斷屏蔽,還需要設置EINTMASK。上面介紹的是最基本的初始化,當然還有一些其他的配置,如當需要用到快速中斷時,要使用INTMOD,當需要配置中斷優先級時,要使用PRIORITY等。
        中斷處理函數負責執行具體的中斷指令,除此以外還需要把SRCPND和INTPND中的相應的位清零(通過置1來清零),因為當中斷發生時,2440會自動把這兩個寄存器中相對應的位置1,以表示某一中斷發生,如果不在中斷處理函數內把它們清零,系統會一直執行該中斷函數。另外還是由于前面介紹過的,有一些中斷是共用一個中斷向量的,而一個中斷向量只能有一個中斷執行函數,因此具體是哪個外部中斷,還需要EINTPEND來判斷,并同樣還要通過置1的方式把相應的位清零。一般來說,使用__irq這個關鍵詞來定義中斷處理函數,這樣系統會為我們自動保存一些必要的變量,并能夠在中斷處理函數執行完后正確地返回。還需要注意的是,中斷處理函數不能有返回值,也不能傳遞任何參數。
        為了把這個中斷處理函數與在2440啟動文件中定義的中斷向量表相對應上,需要先定義中斷入口地址變量,該中斷入口地址必須與中斷向量表中的地址一致,然后把該中斷處理函數的首地址傳遞給該變量,即中斷入口地址。
        下面就是一個外部中斷的實例。開發板上一共有四個按鍵,分別連到了EINT0,EINT1,EINT2和EINT4,我們讓這四個按鍵分別控制連接在B5~B8引腳上的四個LED:按一下鍵則LED亮,再按一下則滅:
        #define _ISR_STARTADDRESS 0x33ffff00
        #define U32 unsigned int
        #define pISR_EINT0 (*(unsigned *)(_ISR_STARTADDRESS+0x20))
        #define pISR_EINT1 (*(unsigned *)(_ISR_STARTADDRESS+0x24))
        #define pISR_EINT2 (*(unsigned *)(_ISR_STARTADDRESS+0x28))
        #define pISR_EINT4_7 (*(unsigned *)(_ISR_STARTADDRESS+0x30))
        #define rSRCPND (*(volatile unsigned *)0x4a000000) //Interrupt request status
        #define rINTMSK (*(volatile unsigned *)0x4a000008) //Interrupt mask control
        #define rINTPND (*(volatile unsigned *)0x4a000010) //Interrupt request status
        #define rGPBCON (*(volatile unsigned *)0x56000010) //Port B control
        #define rGPBDAT (*(volatile unsigned *)0x56000014) //Port B data
        #define rGPBUP (*(volatile unsigned *)0x56000018) //Pull-up control B
        #define rGPFCON (*(volatile unsigned *)0x56000050) //Port F control
        #define rEXTINT0 (*(volatile unsigned *)0x56000088) //External interrupt control register 0
        #define rEINTMASK (*(volatile unsigned *)0x560000a4) //External interrupt mask
        #define rEINTPEND (*(volatile unsigned *)0x560000a8) //External interrupt pending
        static void __irq Key1_ISR(void) //EINT1
        {
        int led;
        rSRCPND = rSRCPND | (0x1<<1);
        rINTPND = rINTPND | (0x1<<1);
        led = rGPBDAT & (0x1<<5);
        if (led ==0)
        rGPBDAT = rGPBDAT | (0x1<<5);
        else
        rGPBDAT = rGPBDAT & ~(0x1<<5);
        }
        static void __irq Key2_ISR(void) //EINT4
        {
        int led;
        rSRCPND = rSRCPND | (0x1<<4);
        rINTPND = rINTPND | (0x1<<4);
        if(rEINTPEND&(1<<4))
        {
        rEINTPEND = rEINTPEND | (0x1<<4);
        led = rGPBDAT & (0x1<<6);
        if (led ==0)
        rGPBDAT = rGPBDAT | (0x1<<6);
        else
        rGPBDAT = rGPBDAT & ~(0x1<<6);
        }
        }
        static void __irq Key3_ISR(void) //EINT2
        {
        int led;
        rSRCPND = rSRCPND | (0x1<<2);
        rINTPND = rINTPND | (0x1<<2);
        led = rGPBDAT & (0x1<<7);
        if (led ==0)
        rGPBDAT = rGPBDAT | (0x1<<7);
        else
        rGPBDAT = rGPBDAT & ~(0x1<<7);
        }
        void __irq Key4_ISR(void) //EINT0
        {
        int led;
        rSRCPND = rSRCPND | 0x1;
        rINTPND = rINTPND | 0x1;
        led = rGPBDAT & (0x1<<8);
        if (led ==0)
        rGPBDAT = rGPBDAT | (0x1<<8);
        else
        rGPBDAT = rGPBDAT & ~(0x1<<8);
        }
        void Main(void)
        {
        int light;
        rGPBCON = 0x015550;
        rGPBUP = 0x7ff;
        rGPFCON = 0xaaaa;
        rSRCPND = 0x17;
        rINTMSK = ~0x17;
        rINTPND =0x17;
        rEINTPEND = (1<<4);
        rEINTMASK = ~(1<<4);
        rEXTINT0 = 0x20222;
        light = 0x0;
        rGPBDAT = ~light;
        pISR_EINT0 = (U32)Key4_ISR;
        pISR_EINT1 = (U32)Key1_ISR;
        pISR_EINT2 = (U32)Key3_ISR;
        pISR_EINT4_7 = (U32)Key2_ISR;
        while(1)
        ;
        }
        /******************************************************************************************************************************************************************************************************/

        1.中斷分兩大類:內部中斷和外部中斷。

        本文引用地址:http://www.104case.com/article/201612/325056.htm

        2.外部中斷。24個外部中斷占用GPF0-GPF7(EINT0-EINT7),GPG0-GPG15(EINT8-EINT23)。用這些腳做中斷輸入,則必須配置引腳為中斷,并且不要上拉。具體參考datesheet數據手冊。

        寄存器:EXTINT0-EXTINT2:三個寄存器設定EINT0-EINT23的觸發方式。

        EINTFLT0-EINTFLT3:控制濾波時鐘和濾波寬度。

        EINTPEND:這個是中斷掛起寄存器,清除時要寫1,后面還有幾個是寫1清除。當一個外部中斷(EINT4-EINT23)發生后,那么相應的位會被置1。為什么沒有EINT0-EINT3,呵呵,看看SRCPND就知道了,里面沒有EINT4-EINT23的位子(SRCPND第[3]位為EINT4-7組,第[4]位為EINT8-23組),所以有了EINTPENDx用以細化補充SRCPND。

        EINTMASK:這個簡單,是屏蔽中斷用的,也就是說位為1時,此次中斷無效。

        3.內部中斷。內部中斷有8個寄存器,下面逐一來看。

        寄存器:SUBSRCPND:當一個中斷發生后,那么相應的位會被置1,表示一個中斷發生了。

        INTSUBMSK:與上一個是一伙的,中斷屏蔽寄存器,具體屏蔽什么,自己看手冊去吧。

        INTMOD:中斷的方式。一個中斷可以是普通中斷,也可以是快中斷,在這里設置,但只能有一個快中斷。

        PRIORITY:優先級寄存器,不說了。

        SRCPND:當一個中斷發生后,那么相應的位會被置1,表示一個或一類中斷發生了。

        INTMSK:中斷屏蔽寄存器。

        INTPND:中斷發生后,SRCPND中會有位置1,可能好幾個(因為同時可能發生幾個中斷),這些中斷會由優先級仲裁器選出一個最緊迫的,然后把INTPND中相應位置1,所以同一時間只有一位是1。也就是說前面的寄存器置1是表示發生了,只有INTPND置1,CPU才會處理。

        INTOFFSET:用來表示INTPND中哪一位置1了,好讓你查詢,普通中斷跳轉時查詢用。清除INTPND、SRCPND時自動清除。

        4.各寄存器關系:

        下面看圖說明:

        5.中斷過程。

        a如果是不帶子中斷的內部中斷:發生后SRCPND相應位置1,如果沒有被INTMSK屏蔽,那么等待進一步處理。

        b如果是帶子中斷的內部中斷:發生后SUBSRCPND相應位置1,如果沒有被INTSUBMSK屏蔽,那么SRCPND相應位置1,等待進一步處理,幾個SUBSRCPND可能對應同一個SRCPND,對應表如下:

        SRCPND SUBSRCPND
        INT_UART0 INT_RXD0,INT_TXD0,INT_ERR0
        INT_UART1 INT_RXD1,INT_TXD1,INT_ERR1
        INT_UART2 INT_RXD2,INT_TXD2,INT_ERR2
        INT_ADC INT_ADC_S, INT_TC
        INT_CAM INT_CAM_C, INT_CAM_P
        INT_WDT_AC97 INT_WDT, INT_AC97

        c如果是外部中斷:EINT0-EINT3發生后SRCPND相應位置1,如果沒有被INTMSK屏蔽,那么等待進一步處理。EINT4-EINT23發生后EINTPEND相應位置1,如果沒有被EINTMASK屏蔽,那么SRCPND相應位EINT4-7或EINT8-23置1,如果沒有被INTMSK屏蔽,等待進一步處理。幾個EINTPEND對應同一個SRCPND,對應表如下:

        SRCPND EINTPEND

        EINT0 EINT0

        EINT1 EINT1

        EINT2 EINT2

        EINT3 EINT3

        EINT4-7 EINT4 EINT5EINT6EINT7

        EINT8-23 EINT8 EINT9EINT10EINT11……EINT23

        三種中斷都等待進一步處理了。接下來從SRCPND往下看,看INTMSK。如果中斷被屏蔽了,就不用說了。如果沒有被屏蔽,那么會進一步到INTMOD。如果是快中斷,那么直接出來,進入FIQ(即CPU進入快中斷模式處理)。如果是普通中斷,那么SRCPND可以有多位為置1(FIQ只能有一個),這時就會經過PRIORITY選出一個優先級高的,然后把根據選出的中斷把INTPND相應位置1(注意:只能選出一個),進入IRQ,讓CPU處理。

        6.中斷的開啟。

        a.如果是不帶子中斷的內部中斷,只需設置INTMSK,讓它不屏蔽中斷就可以了。

        b如果是帶子中斷的內部中斷,需設置INTSUBMSK和INTMSK,讓它們不屏蔽中斷就可以了。

        c如果是外部中斷,對于EINT8-23需要設置EINTMASK和INTMSK。對于EINT0-EINT3只需設置INTMSK。

        7.中斷的清除。

        a.如果是不帶子中斷的內部中斷,只需清除SRCPND,注意清除需位置1。

        b如果是帶子中斷的內部中斷,需清除SRCPND和SUBSRCPND,注意先清除SUBSRCPND,再清除SRCPND。因為,如果你先清除SRCPND的話,然后在清除SUBSRCPND的過程中,SRCPND會以為又有中斷發生,又會置1。也就是說一次中斷會響應兩次。所以必須先掐斷源頭。

        c如果是外部中斷,對于EINT8-23需要清除EINTPEND和SRCPND(同樣注意順序)。對于EINT0-EINT3只需清除SRCPND。

        本文詳細分析了S3C2440的中斷寄存器,對arm初學者有一定的幫助。




        關鍵詞: S3C2440外部中

        評論


        技術專區

        關閉
        主站蜘蛛池模板: 葵青区| 黎平县| 大邑县| 偃师市| 绍兴市| 阿克| 达日县| 杭锦旗| 县级市| 唐河县| 镇康县| 广德县| 郸城县| 苍溪县| 西林县| 湟源县| 翼城县| 焉耆| 苏尼特左旗| 顺平县| 铜川市| 梅州市| 平邑县| 东平县| 高淳县| 三原县| 泸西县| 桦南县| 南投市| 临高县| 武安市| 富宁县| 龙井市| 彝良县| 莒南县| 湖北省| 丘北县| 瑞丽市| 马关县| 松潘县| 伊金霍洛旗|