S3C6410中斷控制,基於OK6410A裸機按鍵中斷程序設計

近來爲了學習Linux嵌入式系統的移植,買了塊OK6410A的開發板,當然從裸機程序的開發開始了,然後不可避免遇到了按鍵中斷這樣的程序,下面按照思考的過程,寫下總結吧!

 

一:首先,弄清楚硬件連接,通過查看原理圖,得到了這樣的硬件連接

KEYINT1-GPN0-EINT_G0_0

KEYINT2-GPN1-EINT_G0_1

KEYINT3-GPN2-EINT_G0_2

KEYINT4-GPN3-EINT_G0_3

KEYINT5-GPN4-EINT_G0_4

KEYINT6-GPN5-EINT_G0_5,然後就去S3C6410datasheet尋找對應的端口說明吧,一看不知道,看了嚇一跳,三星這個英文文檔寫的,感覺忒不嚴謹了,有叫“External Interrupt Group 1”的,有叫“Ext. Interrupt Group 8”的,還有“Ext. Interrupt Group”的,其實他們都是並列關係,外部中斷的9個Group,你說爲啥不統一寫成“Ext. Interrupt Group0、Ext. Interrupt Group1”這樣呢,非要一會兒縮寫一會兒把0都省去了,害得我前後看了幾遍GPIO部分。

 

既然端口對應上了外部中斷EINT,決定去統一的整理下S3C6410的中斷機制。

1、外部中斷源控制器EINT,他一共被分爲9個組,每組裏面對應不同的IO管腳,S3C6410共有127個外部中斷,其外接I/O引腳及分組如下:

外部中斷組0   EINT_G0  GPN0---GPN15 、GPL8---GPL14、GPM0---GPM4

外部中斷組1   EINT_G1  GPA0---GPA7、GPB0---GPB6

外部中斷組2   EINT_G2  GPC0---GPC7

外部中斷組3   EINT_G3  GPD0---GPD5

外部中斷組4   EINT_G4  GPF0---GPF14

外部中斷組5   EINT_G5  GPG0---GPG7

外部中斷組6   EINT_G6  GPH0---GPH9

外部中斷組7   EINT_G7  GPO0---GPO15

外部中斷組8   EINT_G8  GPP0---GPP14

外部中斷組9   EINT_G9  GPQ0---GPQ9

以上127個引腳每個引腳都可以產生一個外部中斷

 

2、ARM的總中斷控制器VIC,他由兩個VIC組成,聯合起來控制了64箇中斷源,每個控制32個,因此我們發現VIC的控制寄存器都是對應的有VIC0就有VIC1,其中我們找到了與外部中斷有關的127個外部中斷在VIC裏的中斷號的對應關係:

NO.      中斷源          說明明                            GROUP

0        INT_EINT0       外部中斷組0 (EINT_G0)引腳號0-3              VIC0

1        INT_EINT1       外部中斷組0 (EINT_G0)引腳號4-11             VIC0

32       INT_EINT2       外部中斷組0 (EINT_G0)引腳號12-19            VIC1

33       INT_EINT3       外部中斷組0 (EINT_G0)引腳號20-27            VIC1

53       INT_EINT4       外部中斷組1-9 (EINT_G1~9)                    VIC1

我們發現屬於外部中斷組0的27箇中斷佔用了VIC裏的4箇中斷號,外部中斷組1-9只佔用了1箇中斷號,世界就是這麼的不公平,努力吧!

 

3、S3C6410的中斷流程,說到這裏,大家是不是覺得有點亂(如果使用過STM32應該不會亂,因爲STM32的中斷也是兩級控制的),我們總結下具體的中斷流程:

外設(GPIO)——》EINT——》VIC——?,因此對應的我們編程序也就是

外設配置——》EINT配置——VIC配置——?,這是我們現在所能想到的,大家也覺得分析的不錯吧,可惜錯誤也再此埋下了伏筆,即是問號處,


二: 前面大概講了一下外部中斷的流程,現在我就開始按照此流程,結合具體的硬件進行整理和編程了。下面講到具體的寄存器都按照OK6410開發板對應的GPN講解。

 

1GPIO的配置

相信你已經開始寫中斷程序了,基礎的IO控制LED的程序肯定已經寫過了,那一定知道控制GPIO一般就如下幾個寄存器:

GPNCON——端口控制寄存器、可讀可寫

GPNDAT——端口數據寄存器、可讀可寫

GPNPUD——端口上下拉寄存器、可讀可寫,對於按鍵中斷,顯然我們只需要用到GPNCON,將端口設置爲中斷模式即可,按照下圖,將對應的位設置爲10即可。

rGPNCON &= ~((0x03<<0)|(0x03<<2)|(0x03<<4)|(0x03<<6)|(0x03<<8)|(0x03<<10));//把兩位都變爲00,也可以寫成~(0xfff<<0)

rGPNCON |= ((0x02<<0)|(0x02<<2)|(0x02<<4)|(0x02<<6)|(0x02<<8)|(0x02<<10));//把前一位變爲1,也可寫成0xaaa<<0     

此處爲了更清楚的表明設置的過程,設置的稍有複雜,大家可以直接簡化爲註釋後面的,同時爲了不對其他端口造成影響,嚴格採用了對應的與或操作。

 

2EINT配置,對應前面描述的中斷知識,本按鍵GPN0~5只涉及到了GROUP0的中斷EINTEINT_G0,具體說是EINT_G0_0~5

關於EINT的配置,我們先總結一下可能涉及到的寄存器:

總結下來就是四類,EINT控制寄存器,濾波控制寄存器,中斷屏蔽寄存器,中斷掛載寄存器,當然還有關於優先級等寄存器,如PRIORTY,SERVICE,SERVICEPEND這些,比較高級的功能,我也沒有深入,此處暫不表。

此處說一下常用的這三類,(1EINT控制寄存器,用來控制外部中斷的觸發方式,比如此處可以設定爲低電平觸發。

//設置外部中斷EINT觸發方式低電平觸發爲x000,最高位忽略,默認爲x000,兩個共用一個

rEINT0CON0 &= ~((0x07<<0)|(0x07<<4)|(0x07<<8));//把三位都變爲0,也可以寫爲~(0x777<<0)

2)中斷屏蔽寄存器EIN0MASK,可讀可寫,寫1屏蔽中斷,寫0使能中斷。此時,我們首先肯定要使能按鍵中斷口。

//設置中斷使能,即將中斷屏蔽寄存器置0,

rEINT0MASK &= ~((0x01<<0)|(0x01<<1)|(0x01<<2)|(0x01<<3)|(0x01<<4)|(0x01<<5));//把一位變爲0,也可以寫成~(0x3f<<0)

3)中斷掛載寄存器EINT0PEND,可讀可寫,讀1表示發生中斷,讀0表示未發生中斷,寫1表示清除外部中斷。

//清楚外部中斷掛載,即外部中斷掛載寄存器寫1,清楚中斷

rEINT0PEND |= ((0x01<<0)|(0x01<<1)|(0x01<<2)|(0x01<<3)|(0x01<<4)|(0x01<<5));//把一位變爲1,也可以寫成(0x3f<<0)


三:

VIC的配置,對應前面講的對應前面描述的中斷知識,本按鍵GPN0~5只涉及到了GROUP0的中斷EINTEINT_G0,具體說是EINT_G0_0~5。再次對應到VIC,我們看到其中GPN0~3對應了EINT_G0_0~3,對應了INT_EINT0GPN4~5對應了EINT_G0_4~5,對應了INT_EINT1,這兩者都是在VIC0中,分屬NO0NO1

然後關於VIC我們總結下相應的寄存器:此處僅以VIC0爲例,選出了常用的一些寄存器,其他類似於中斷優先級,軟中斷等等,還沒有研究,需要共同學習。

1VIC0INTSELECT——中斷選擇寄存器,可讀可寫,0-選擇IRQ1-選擇FIQFIQ更快,一般選IRQ32位分別對應每一箇中斷源;

2VIC0INTENABLEVIC0INTENCLEAR,這兩者是一對的,其中VIC0INTENABLE——系統中斷使能寄存器,可讀可寫,0-中斷禁止,1-中斷使能,一般只能用來使能中斷,不能用來寫0禁止中斷,禁止中斷使用VIC0INTENCLEAR——系統中斷清除,可寫,寫0無效,寫1-禁止中斷,大家注意配合使用,32位分別對應每一箇中斷源;

3VIC0VECTADDR[0~31] ——矢量地址寄存器,即對應的中斷服務程序的入口地址,一共32個地址,對應VIC032箇中斷源。可讀可寫;

4VIC0ADDRESS——又一個矢量地址寄存器,糊塗了吧,記住它的功能就行,通過向其寫入任意值,就可以清除中斷服務標誌,類似於外部中斷EINT中的EINT0PEND了,我們可以通過它在中斷服務程序中清除系統中斷標誌,32位分別對應每一箇中斷源;

 

介紹完了這些VIC對應的寄存器,現在開始說說其配置的流程:

(1)       首先肯定是需要設定中斷的類型IRQ還是FIQ,配置之前呢,先把對應的中斷關了,因此,先需要禁止對應的系統中斷。

//關閉對應的中斷,對應位寫1關閉系統中斷,只能寫32位,同rVIC1INTENCLEAR一起與rVIC0INTENABLE/rVIC1INTENABLE配套

rVIC0INTENCLEAR |= (0x01<<0|(0x01<<1));//外部中斷0_0~5屬於系統中斷INT_EINT0/INT_EINT1

2)那其次就是上面說的設定中斷的類型IRQ還是FIQ了。

//設置系統中斷類型,對應位寫0-IRQ,1-FIQ,只能寫32位,同rVIC1INTSELECT一起

rVIC0INTSELECT &= ~((0x01<<0)|(0x01<<1));//外部中斷0_0~5屬於系統中斷INT_EINT0/INT_EINT1

3)然後呢清除系統中斷標誌

/清除系統中斷,對應位寫0或者1都行,只能寫32位,同rVIC1ADDRESS一起

rVIC0ADDRESS &= ~((0x01<<0)|(0x01<<1));//外部中斷0_0~5屬於系統中斷INT_EINT0/INT_EINT1

4)設定中斷服務程序的入口地址

//寫中斷處理程序地址,rVIC0VECTADDR

VIC0VECTADDR[0] = (unsigned)Key1_handler;//unsigned說明是32位地址

VIC0VECTADDR[1] = (unsigned)Key2_handler;//unsigned說明是32位地址,這裏需要說明,這邊是3232位的數組對應32箇中斷源的處理地址,因此宏定義的時候需要注意,此處宏定義跟其他寄存器定義有區別。

#define VIC0VECTADDR             (( unsigned *)(0x71200100))

#define VIC1VECTADDR                    (( unsigned *)(0x71300100))

5)使能系統中斷

//使能系統中斷,對應位寫1使能系統中斷,只能寫32位,同rVIC1INTENABLE一起與rVIC0INTENCLEAR/rVIC1INTENCLEAR配套

rVIC0INTENABLE |= (0x01<<0|(0x01<<1));//外部中斷0_0~5屬於系統中斷INT_EINT0/INT_EINT1

GPIO的配置

這樣一個簡單的系統中斷VIC配置就算完成了。

 

4、接下來就是中斷服務程序了,這個大家都弄膩了,需要注意的就是清除中斷標誌,從上面可以看出,這裏需要清除兩個中斷標誌,分別是外部中斷EINT和系統中斷VIC的標誌,例如rVIC0ADDRESS &= ~(0x01<<0);//清除系統中斷INT_EINT0

以及rEINT0PEND |= (0x01<<0);//清除外部中斷0_0

例外可以通過讀rEINT0PEND的某一位,知道具體是外部中斷EINT_G0的哪一個口發生中斷。

 

大家是不是覺得這樣就OK了呢,我也是這麼想的,然後就下載程序進行了在線調試,可惜啥效果沒有,然後又認真的把每一個寄存器又都檢查了一遍,還是沒有發現錯誤,疑惑不解啊。這就又回到了一開始埋下的伏筆那, 

四:

經過前面的準備,0K6410的按鍵中斷基本搞定了,但是還有一個地方被我們大家遺漏了,於是我跟衆多網友一樣,停滯在這裏,調不通按鍵中斷了,沒辦法啊,中斷就是不響應。

 

於是又回到了一開始埋下的伏筆那,S3C6410的中斷響應流程那,外設(GPIO)——》EINT——》VIC——?,因此對應的我們編程序也就是外設配置——EINT配置——VIC配置——?,這個問號處,是被我們忽視的地方。(此處各種上網查找,也有好多網友給出了正確答案,這裏不一一致謝了哈,反正是各種實驗哦)

 

下面是S3C6410應用筆記(apnv1.0)中斷部分的截圖,通過圖我們發現,第一部分,我們沒有做啊,即使能VIC接口(enable vic port)。當然還有另外一個方法,不太常用,一般都用這個調用VIC PORT

按照筆記,使能VIC PORT,這裏給出了一段彙編代碼,尼瑪,彙編不太會啊,這個放在哪兒呢,如果放在C程序中,需要內嵌彙編,使用asm又報錯,沒能解決,參考網上,有人放在了啓動代碼中,果斷複製到啓動代碼中。

;------------------------------------

;     Enable VIC Port

;------------------------------------

             mrc p15,0,r0,c1,c0,0

                   orr r0,r0,#(1<<24)

                   mcr p15,0,r0,c1,c0,0

 

到了這裏,好多網友都運行成功了,可是我這裏還是沒有運行成功,這又讓我很鬱悶,最終在網上衆多博客中,找到了一篇http://blog.csdn.net/tankai19880619/article/details/8310050

,他裏面另外還有一段彙編,使能IRQ,我把這段彙編copy到啓動代碼中,經過嘗試,成功了,哈哈,雖然他博客中寫的他自己沒有調試成功。這個哥們的博客http://blog.csdn.net/yin138/article/details/6738917中也有類似的這段代碼。

;------------------------------------

;     Enable IRQ

;------------------------------------               

                   mrs r0,cpsr

                bic r0,r0,#0x80

        msr cpsr_c,r0

就這樣,最終按鍵中斷的功能得以實現,真是一波三折啊。最終彙總一下整個流程:

外設(GPIO)——》EINT——》VIC——協處理器,因此對應的我們編程流程也就是

外設配置——EINT配置——VIC配置——使能VIC PORT和使能IRQ



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章