天天看點

按鍵和中斷

1.8.1.什麼是按鍵

1.8.1.1、按鍵的實體特性

(1)、平時沒人按的時候,彈簧把按鍵按鈕彈開。此時内部斷開的。

(2)、有人按下的時候,手的力量克服彈簧的彈力,将按鈕按下,此時内部保持接通(閉合)狀态;如果手拿開,則彈簧作用下按鈕又彈開,同時内部又斷開。

(3)、一般的按鍵都有4個引腳,這4個引腳成2對:其中一對是常開觸點(像上面描述的不按則斷開,按下則閉合);一對是常閉觸點(平時不按時是閉合的,按下後是斷開的)

1.8.1.2、按鍵的電學原理(結合原理圖分析)

(1)硬體接法: SW5:GPH0_2 SW6:GPH0_3 SW78910:GPH2_0123

(2)按鍵的電路連接配接分析:平時按鈕沒有按下時,按鈕内部斷開,GPIO引腳處電壓為高電平;當有人按下按鈕時,按鈕内部導通,外部VDD經過電阻和按鈕連接配接到地,形成回路,此時GPIO引腳處電壓就變成了低電平。此時VDD電壓全部分壓在了電阻上(這個電阻就叫分壓電阻,這個電阻不能太小,因為電阻的功率是U*U/R)

(3)總結:按鍵的工作方法:其實就是按鍵的按下與彈開,分别對應GPIO的兩種電平狀态(按下則GPIO為低電平,彈開則GPIO為高電平)。此時SoC内部可以通過檢測這個GPIO的電平高低來判斷按鍵有沒有被按下,這個判斷結果即可作為SoC的輸入信号。

1.8.1.3、按鍵屬于輸入類裝置

(1)按鍵一般用來做輸入裝置(由人向SoC發送資訊的裝置,叫輸入裝置),由人向SoC發送按鍵信号(按鍵信号有2種:按下信号和彈開信号)。

(2)有些裝置就是單純的輸入裝置,譬如按鍵、觸摸屏等;有些裝置就是單純的輸出裝置,譬如LCD;還有一些裝置是既能輸入又能輸出的,叫輸入輸出裝置(IO),譬如序列槽。

1.8.1.4、按鍵的2種響應方法

(1)SoC處理按鍵有2種思路:輪詢方式和中斷方式。

(2)輪詢方式,就是SoC主動的每隔一段時間去讀取(按鍵所對應的)GPIO的電平高低,以此獲得按鍵資訊;缺點在于CPU要一直注意按鍵事件,會影響CPU做其他事情。

(3)中斷方式,就是SoC事先設定好GPIO觸發的中斷所對應的中斷處理程式ISR,當外部按鍵按下或彈開時會自動觸發GPIO對應的外部中斷,導緻ISR執行,進而自動處理按鍵資訊。

1.8.2.輪詢方式處理按鍵

1.8.2.1、X210開發闆的按鍵接法

(1)查原理圖,找到按鍵對應的GPIO:SW5:GPH0_2 SW6:GPH0_3 SW78910:GPH2_0123

(2)原理圖上可以看出:按下時是低電平,彈起時是高電平

1.8.2.2、按鍵對應的GPIO模式設定

(1)按鍵接到GPIO上,按鍵按下還是彈起,決定外部電路的接通與否,進而決定這個GPIO引腳的電壓是高還是低;這個電壓可以作為這個GPIO引腳的輸入信号,此時GPIO配置為輸入模式,即可從SoC内部讀取該引腳的電平為1還是0(1對應高電平,0對應低電平)。

(2)GPH0CON(0xE0200C00) GPH2DAT(0xE0200C04) GPH2CON(0xE0200C40) GPH2DAT(0xE0200C44)

(3)應該在CON寄存器中将GPIO設定為input模式,然後去讀取DAT寄存器(讀取到的相應位的值為1表示外部是高電平(對應按鍵彈起),讀取到的位的值為0表明外部是低電平(按鍵按下))

1.8.2.3、輪詢方式處理按鍵的程式流程

(1)第一步,先初始化GPIO模式為input;

(2)第二步,循環讀取GPIO的電平值,然後判斷有無按鍵按下

1.8.2.4、代碼編寫和調試

1.8.3.序列槽輸出和按鍵消抖

1.8.3.1、基于序列槽标準輸出的按鍵調試

(1)以之前的序列槽stdio的工程為基礎來移植添加輪詢方式按鍵處理。

(2)注意USB下載下傳方式可能有錯誤(有可能不下載下傳,也有可能下載下傳了執行不對),解決方案是用SD卡啟動來替代。

1.8.3.2、什麼是按鍵消抖

(1)按鍵這種實體器件本身會有抖動信号,抖動信号指的是在電平由高到低(也就是按鍵按下時)或者電平由低到高(也就是按鍵彈起時)過程中,電平的變化不是立刻變化,而是經過了一段時間的不穩定期才完成變化,在這個不穩定期間電平可能會時高時低反複變化,這個不穩定期就叫抖動(抖動期内擷取按鍵資訊是不可靠的,要想辦法消抖)。

(2)什麼叫消抖?消抖就是用硬體或者軟體方法來盡量減小抖動期對按鍵擷取的影響。消抖常用2種思路:第一是硬體消抖,消抖思路就是盡量減小抖動時間,方法是通過硬體添加電容等元件來減小抖動;第二是軟體消抖,消抖思路是發現一次按鍵按下/彈起事件後,不立即處理按鍵,而是延時一段時間(一般10~20ms,這就是消抖時間)後再次擷取按鍵鍵值,如果此次擷取和上次一樣是按下/彈起,那就認為真的按下/彈起了。

(3)一般比較精密需要的時候,需要硬體消抖和軟體消抖一起配合。

1.8.3.3、程式設計實踐

1.8.4.S5PV210的中斷體系介紹

1.8.4.1、什麼是中斷

(1)中斷的發明是用來解決宏觀上的并行需要的。宏觀就是從整體上來看,并行就是多件事情都完成了。

(2)微觀上的并行,就是指的真正的并行,就是精确到每一秒甚至每一刻,多個事情都是在同時進行的。宏觀上面的并行并不等于圍觀的并行,有時候宏觀上是并行的,微觀上是串行的。

(3)例子中一個人在看電影,快遞來了暫停電影跑去收快遞,收完快遞繼續回來看電影,這個例子就是宏觀上的并行和微觀上的串行。例子中一個人等同于SoC中1個CPU(也就是單核CPU),這個CPU看電影就不能收快遞,收快遞就不能看電影(也就是說不能真正的并行)。單核心CPU在微觀角度是串行的,但是因為CPU很快,是以在宏觀看來可以并行。

(4)上例中大部分時間在看電影,中間少量時間去收快遞,那麼類比于CPU來說,看電影就應該是CPU的正常任務,而收快遞則應該是中斷例程。也就是說CPU平時一直在進行看電影任務,等快遞來了(中斷發生了)快遞員(類似于中斷源)會打電話叫人去收快遞(中斷源會觸發中斷通知CPU去進行中斷),人收到電話(CPU收到中斷信号)後會暫定電影(CPU儲存正常任務的現場)跑去收快遞(CPU去執行中斷處理程式ISR進行中斷),收完快遞(執行完ISR)回來繼續看電影(CPU恢複正常任務的現場,繼續執行正常任務)

(5)為什麼需要中斷?因為單核CPU實際無法并行的,但是通過中斷機制,可以實作假并行(宏觀上的并行,微觀上實際還是串行的)。

1.8.4.2、SoC對中斷的實作機制:異常向量表

(1)異常向量表是CPU中某些特定位址的特定定義。當中斷發生的時候,中斷要想辦法通知CPU去進行中斷,怎麼做到?這就要靠異常向量表。

(2)在CPU設計時,就事先定義了CPU中一些特定位址作為特定異常的入口位址(譬如定義0x00000000位址為複位異常向量位址,則發生複位異常時CPU會自動跳轉到0x00000000位址去執行指令。又譬如外部中斷對應的異常向量位址為0x30000008,則發生外部中斷後,CPU會硬體自動跳轉到0x30000008位址去執行指令。)如

(3)以上講的是CPU硬體設計時對異常向量表的支援,下來就需要軟體支援了。硬體已經決定了發生什麼異常CPU自動跳轉PC到哪個位址去執行,軟體需要做的就是把處理這個異常的代碼的首位址填入這個異常向量位址。

1.8.4.3、S5PV210的異常向量表

(1)異常向量表在1.2.14節講過,可以傳回去聽一下

(2)異常向量表中各個向量的相對位置是固定的,但是他們的起始位址是不固定的,各種SoC可以不一樣,而且複雜ARM中還可以讓使用者來軟體設定這個異常向量表的基位址。

(3)擴充到所有架構的CPU中:所有架構(譬如51單片機、PIC單片機)的CPU實作中斷都是通過異常向量表實作的,這個機制是不變的;但是不同CPU異常向量表的構造和位置是不同的。

1.8.4.4、異常和中斷的差別和聯系

(1)針對SoC來說,發生複位、軟中斷、中斷、快速中斷、取指令異常、資料異常等,我們都統一叫異常。是以說:中斷其實是異常的一種。

(2)異常的定義就是突發事件,打斷了CPU的正常正常業務,CPU不得不跳轉到異常向量表中去執行異常處理程式;中斷是異常的一種,一般特指SoC内的内部外設産生的打斷SoC正常業務,或者外部中斷(SoC的GPIO引腳傳回來的中斷)。

1.8.5.異常向量表的程式設計處理

1.8.5.1、像記憶體一樣去通路異常向量表

(1)S5PV210的異常向量表可以改變(在CP15協處理器中),以适應作業系統的需求。但是目前系統剛啟動時,此時DRAM尚未初始化,程式都在SRAM中運作。210在iRAM中設定了異常向量表,供暫時性使用。

(2)查210的iROM application note文檔中iRAM的位址配置設定,可知,iRAM中的異常向量表起始位址為0xD0037400。知道了異常向量表的起始位址後,各個異常對應的入口就很好知道了。

1.8.5.2、函數名的實質就是函數的首位址

(1)函數名在C語言中的了解方法和變量名其實沒差別。編譯器會把這個函數的函數體對應的代碼段和這個函數的函數名(實質是符号)對應起來,等我們在使用這個函數名符号時,編譯器會将函數的函數體實際上做替換。因為函數體都不止4位元組,而函數名這個符号隻能對應1個位址,是以實際對應的是函數體那一個代碼段的首位址。

(2)拿C語言中的文法來講,函數名就是這個函數的函數指針。

總結:當我們将異常處理程式的首位址和異常向量表綁定起來後,異常處理初步階段就完成了。到目前可以保證相應異常發生後,硬體自動跳轉到對應異常向量表入口去執行時,可以執行到我們事先綁定的函數。

1.8.5.3、為什麼中斷處理要先在彙編中進行

(1)中斷處理要注意保護現場(中斷從SVC模式來,則儲存SVC模式下的必要寄存器的值)和恢複現場(中斷處理完成後,準備傳回SVC模式前,要将儲存的SVC模式下的必要寄存器的值恢複回去,不然到了SVC模式後寄存器的值亂了,SVC模式下原來正在進行的正常任務就被你搞壞了)

(2)儲存現場包括:第一:設定IRQ棧;第二,儲存LR;第三,儲存R0~R12

(3)為什麼要儲存LR寄存器?要考慮中斷傳回的問題。中斷ISR執行完後如何傳回SVC模式下去接着執行原來的代碼。中斷傳回其實取決于我們進入中斷時如何儲存現場。中斷傳回時關鍵的2個寄存器就是PC和CPSR。是以我們在進入IRQ模式時,應該将SVC模式下的下一句指令的位址(中斷傳回位址)和CPSR儲存起來,将來恢複時才可以将中斷傳回位址給PC,将儲存的CPSR給CPSR。

(4)中斷傳回位址就儲存在LR中,而CPSR(自動)儲存在(IRQ模式下的)SPSR中

1.8.5.4、彙編儲存現場和恢複現場

(1)保護現場關鍵是儲存:中斷處理程式的傳回位址,r0-r12(cpsr是自動儲存的)

(2)恢複現場主要是恢複:r0-r12,pc,cpsr

1.8.6.S5PV210的向量中斷控制器

1.8.6.1、異常處理的2個階段

(1)可以将異常處理分為2個階段來了解。第一個階段是異常向量表跳轉;第二個階段就是進入了真正的異常處理程式irq_handler之後的部分。

1.8.6.2、回顧:中斷處理的第一階段(異常向量表階段)處理。

(1)第一個階段之是以能夠進行,主要依賴于CPU設計時提供的異常向量表機制。第一個階段的主要任務是從異常發生到響應異常并且儲存/恢複現場、跳轉到真正的異常處理程式處。

(2)第二個階段的目的是識别多個中斷源中究竟哪一個發生了中斷,然後調用相應的中斷處理程式來處理這個中斷。

1.8.6.3、S3C2440的第二階段處理過程

(1)第一個問題,怎麼找到具體是哪個中斷:S3C2440的中斷控制器中有一個寄存器(32位的),寄存器的每一個位對應一個中斷源(為了解決支援更多中斷源,2440又設計了一個子中斷機制。在一級中斷寄存器中有一些中斷是共用的一個bit位,譬如AC97和WDT。對于共用中斷,用子中斷來區分究竟是哪一個發生了中斷)

(2)第二個問題,怎麼找到對應的isr的問題:首先給每個中斷做了個編号,進入isr_handler之後先通過查閱中斷源寄存器和子中斷寄存器(中哪一位為1)确定中斷的編号,然後用這個編号去isr數組(isr數組是中斷初始化時事先設定好的,就是把各個中斷的isr的函數名組成一個數組,用中斷對應的編号作為索引來查詢這個數組)中查閱得到isr位址。

評價:2440的中斷處理設計不是特别優秀:第一個過程中使用子中斷搞成2級的很麻煩;第二個過程中計算中斷編号是個麻煩事,很耗費時間。而中斷處理的時間是很寶貴的(系統有一個性能名額,叫實時性。實時性就是中斷發生到響應的時間,這個時間越短越好。)

1.8.6.4、S5PV210的第二階段處理過程

(1)第一個問題,怎麼找到具體是哪個中斷:S5PV210中因為支援的中斷源很多,是以直接設計了4個中斷寄存器,每個32位,每位對應一個中斷源。(理論上210最多支援128個中斷,實際支援不足128個,有些位是空的);210沒有子中斷寄存器,每個中斷源都是并列的。當中斷發生時,在irq_handler中依次去查詢4個中斷源寄存器,看哪一個的哪一位被置1,則這個位對應的寄存器就發生了中斷,即找到了中斷編号。

(2)第二個問題,怎麼找到對應的isr的問題:210中支援的中斷源多了很多,如果還使用2440的那一套來尋找isr位址就太慢了,太影響實時性了。于是210開拓了一種全新的尋找isr的機制。210提供了很多寄存器來解決每個中斷源對應isr的尋找問題,具體尋找過程和建立過程見下節,實作的效果是當發生相應中斷時,硬體會自動的将相應isr推入一定的寄存器中,我們軟體隻要去這個寄存器中執行函數就行了。

1.8.6.5、總結:第一階段都相同,第二階段各不同

(1)第一階段(異常向量表階段)2440和210幾乎是完全相同的。實際上幾乎所有的CPU在第一階段都是相同的。

(2)第二階段就彼此不同了。各個SoC根據自己對實時性的要求,和支援的中斷源的多少,各自發明了各自進行中斷,找到中斷編号,進一步找到對應isr位址的方式。

1.8.7.S5PV210中斷處理的主要寄存器

1.8.7.1、VICnINTENABLE和VICnINTENCLEAR

(1)VICnINTENABLE 對應interrupt enable,INTENCLEAR對應interrupt enable clear

(2)INTENABLE寄存器負責相應的中斷的使能,INTENCLEAR寄存器負責相應的中斷的禁止。

(3)當我們想使能(意思就是啟用這個中斷,意思就是當硬體産生中斷時CPU能接收的到)某個中斷時,隻要在這個中斷編号對應的VICnINTENABLE的相應bit位寫1即可(注意這個位寫1其他位寫0對其他位沒有影響);如果我們想禁止某個中斷源時,隻要向VICnINTENCLEAR中相應的位寫1即可。

注意:這裡的設計一共有2種:有些CPU是中斷使能和禁止是一個寄存器位,寫1就使能寫0就進制(或者反過來寫1就進制寫0就使能),這樣的中斷使能設計就要非常小心,要使用我們之前說過的讀改寫三部曲來操作;另一種就是使能和禁止分開為2個寄存器,要使能就寫使能寄存器,要禁止就寫禁止寄存器。這樣的好處是我們使能/禁止操作時不需要讀改寫,直接寫即可。

1.8.7.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快?有2個原因:第一,fiq模式有專用的r8~r12,是以在fiq的isr中可以直接使用r8-r12而不用儲存,這就能節省時間;第二,異常向量表中fiq是最後一個異常向量入口。是以fiq的isr不需要跳轉,可以直接寫在原地,這樣就比其他異常少跳轉一次,省了些時間。

1.8.7.3、VICnIRQSTATUS和VICnFIQSTATUS

(1)中斷狀态寄存器,是隻讀的。當發生了中斷時,硬體會自動将該寄存器的對應位置為1,表示中斷發生了。軟體在進行中斷第二階段的第一階段,就是靠查詢這個寄存器來得到中斷編号的。

1.8.7.4、VICnVECTPRIORITY0~VICnVECTPRIORITY31

(1)中斷優先級設定寄存器,設定多個中斷同時發生時先處理誰後處理誰的問題。一般來說高優先級的中斷可以打斷低優先級的中斷,進而嵌套進行中斷。當然了有些硬體/軟體可以設定不支援中斷嵌套。

1.8.7.5、VICnVECTADDR0~VICnVECTADDR31、VICnADDR

(1)這三個寄存器和210中斷處理第二階段的第二階段有關。

(2)VICnVECTADDR0到31這32個寄存器分别用來存放真正的各個中斷對應的isr的函數位址。相當于每一個中斷源都有一個VECTADDR寄存器,程式員在設定中斷的時候,把這個中斷的isr位址直接放入這個中斷對應的VECTADDR寄存器即可。

(3)VICnADDR這個寄存器是隻需要讀的,它裡面的内容是由硬體自動設定的。當發生了相應中斷時,硬體會自動識别中斷編号,并且會自動找到這個中斷的VECTADDR寄存器,然後将其讀出複制到VICnADDR中,供我們使用。這樣的設計避免了軟體查找中斷源和isr,節省了時間,提高了210的中斷響應速度。

1.8.8.S5PV210中斷處理的程式設計實踐1

1.8.8.1、上節中代碼中的小問題

主要集中在start.S中,原因就是不常寫,格式忽略。解決方案就是編譯時發現再解決。

1.8.8.2、中斷控制器初始化

主要工作有:第一階段綁定異常向量表到異常處理程式;禁止所有中斷源;選擇所有中斷類型為IRQ;清理VICnADDR寄存器為0.

1.8.8.3、中斷的使能與禁止

思路是先根據中斷号判斷這個中斷屬于VIC幾,然後在用中斷源減去這個VIC的偏移量,得到這個中斷号在本VIC中的偏移量,然後1<<x位,寫入相應的VIC的INTENABLE/INTENCLEAR寄存器即可。

1.8.8.4、綁定自己實作的isr到VICnVECTADDR

(1)搞清楚2個寄存器的差別:VICnVECTADDR和VICnADDR

(1)VICVECTADDR寄存器一共有4×32個,每個中斷源都有一個VECTADDR寄存器,我們應該将自己為這個中斷源寫的isr位址丢到這個中斷源對應的VECTADDR寄存器中即可。

1.8.8.5、真正的中斷處理程式如何擷取isr

(1)當發生中斷時,硬體會自動把相應中斷源的isr位址從VICnVECTADDR寄存器中推入VICnADDR寄存器中,是以我們第二階段的第二階段isr_handler中,隻需要到相應的VICnADDR中去拿出isr位址,調用執行即可。

總結:第4步綁定isr位址到VICnVECTADDR和第5步中斷發生時第二階段的第二階段如何擷取isr位址,這兩步是相關的。這兩個的結合技術,就是我們一直在說的210的硬體自動尋找isr的機制。

整個中斷的流程梳理:

整個中斷的工作分為2部分:

第一部分是我們為中斷響應而做的預備工作:

1. 初始化中斷控制器

2. 綁定寫好的isr到中斷控制器

3. 相應中斷的所有條件使能

第二部分是當硬體産生中斷後如何自動執行isr:

1. 第一步,經過異常向量表跳轉入IRQ/FIQ的入口

2. 第二步,做中斷現場保護(在start.S中),然後跳入isr_handler

3. 第三步,在isr_handler中先去搞清楚是哪個VIC中斷了,然後直接去這個VIC的ADDR

寄存器中取isr來執行即可。

4. 第四步,isr執行完,中斷現場恢複,直接傳回繼續做正常任務。

1.8.9.S5PV210中斷處理的程式設計實踐2

見上節

1.8.10.外部中斷

1.8.10.1、什麼是外部中斷?資料手冊在哪裡?

(1)SoC支援的中斷類型中有一類叫外部中斷。内部中斷就是指的中斷源來自于SoC内部(一般是内部外設),譬如序列槽、定時器等部件産生的中斷;外部中斷是SoC外部的裝置,通過外部中斷對應的GPIO引腳産生的中斷。

(2)按鍵在SoC中就使用外部中斷來實作。具體實作方法是:将按鍵電路接在外部中斷的GPIO上,然後将GPIO配置為外部中斷模式。此時人通過按按鍵改變按鍵電路的電壓高低,這個電壓高低會觸發GPIO對應的外部中斷,通過引腳傳進去給CPU處理。

(3)外部中斷相關的介紹和寄存器都在2.2.6章節(屬于GPIO部分)

1.8.10.2、電平觸發和邊沿觸發

(1)外部中斷的觸發模式主要有2種:電平觸發和邊沿觸發。

(1)電平觸發就是說GPIO上的電平隻要滿足條件,就會不停觸發中斷。電平觸發分為高電平觸發和低電平觸發。電平觸發的特點是,隻要電平滿足條件就會不停觸發中斷。

(2)邊沿觸發分為上升沿觸發、下降沿觸發和雙邊沿觸發三種。邊沿觸發不關心電平正常狀态,隻關心電平變化的瞬間(邊沿觸發不關心電平本身是高還是低,隻關心變化是從高到低還是從低到高的這個過程)。

分析按鍵的工作:如果我們關注的是按鍵按下和彈起這兩個事件本身,那麼應該用邊沿觸發來處理按鍵;如果我們關心的是按鍵按下/彈起的那一段時間,那麼應該用電平觸發。

1.8.10.3、關鍵寄存器:CON、PEND、MASK

(1)外部中斷的主要配置寄存器有3個:EXT_CON、EXT_PEND、EXT_MASK

(2)EXT_CON配置外部中斷的觸發方式。觸發方式就是說外部電平怎麼變化就能觸發中斷,也就是說這個外部中斷産生的條件是什麼

(3)EXT_PEND寄存器是中斷挂起寄存器。這個寄存器中每一位對應一個外部中斷,平時沒有中斷時值為0。當發生了中斷後,硬體會自動将這個寄存器中該中斷對應的位置1,我們去處理完這個中斷後應該手工将該位置0。這個PEND寄存器的位就相當于是一個标志,如果發生了中斷但是我們暫時忙來不及去處理時,這個位一直是1(這就是挂起),直到我有空了去處理了這個中斷才會手工清除(寫代碼清除)這個挂起位表示這個中斷被我處理了。

(4)EXT_MASK寄存器就是各個外部中斷的使能/禁止開關。

繼續閱讀