本文是一篇偏向底層的內(nèi)容。
1.寫(xiě)在前面
編譯器內(nèi)部函數(shù)__disable_irq、__enable_irq、__disable_fiq和__enable_fiq用于控制IRQ和FIQ中斷。
只有當(dāng)處理器處于特權(quán)模式才可以使用這些內(nèi)部函數(shù),因?yàn)檫@些函數(shù)要改變寄存器CPSR和SPSR(ARM7、ARM9等)或者PRIMASK和FAULTMASK寄存器(Cortex-M3、M4等),而這些寄存器只有在特權(quán)模式下才能被訪問(wèn)。
這些內(nèi)部函數(shù)對(duì)所有架構(gòu)的處理器都有效,無(wú)論是ARM狀態(tài)還是Thumb狀態(tài),如下所述:
如果使用的是ARMv6(ARM11)或更新架構(gòu),編譯器會(huì)將這些函數(shù)用CPS指令代替。
如果使用的是ARMv4或者ARMv5架構(gòu)并且處于ARM狀態(tài),編譯器會(huì)將這些函數(shù)用MRS和MSR指令代替。一般情況下ARM7屬于ARMv4架構(gòu),ARM9屬于ARMv5架構(gòu)。
如果使用的是ARMv4或者ARMv5架構(gòu)并且處于Thumb狀態(tài)或編譯器使能-compatible參數(shù),則編譯器會(huì)調(diào)用一個(gè)輔助函數(shù)比如__ARM_disable_irq來(lái)控制中斷。
2.__enable_fiq使能FIQ中斷
通常是通過(guò)清除寄存器CPSR中的F位來(lái)實(shí)現(xiàn)的。
注意FIQ中斷一般只存在于ARMv4和ARMv5架構(gòu)中(即ARM7和ARM9),ARMv6架構(gòu)的處理器不支持此函數(shù)。
對(duì)于ARMv7架構(gòu)的處理器(Cortex-M3),這個(gè)函數(shù)清除FAULTMASK寄存器的值。
語(yǔ)法:void __enable_fiq(void)
限制:只能在特權(quán)級(jí)別下使用,用戶模式下無(wú)效。
3.__disable_fiq禁用FIQ中斷
通常是通過(guò)置一CPSR的F位來(lái)實(shí)現(xiàn)的。
注意FIQ中斷一般只存在于ARMv4和ARMv5架構(gòu)中(即ARM7和ARM9),ARMv6架構(gòu)的處理器不支持此函數(shù)。
對(duì)于ARMv7架構(gòu)的處理器(Cortex-M3),這個(gè)函數(shù)置位FAULTMASK寄存器,這意味著此后只有NMI可以響應(yīng),所有其它的異常,包括中斷和 Fault都不能響應(yīng)。
語(yǔ)法:__disable_fiq有兩個(gè)版本。
一個(gè)是返回值為空的void __disable_fiq(void)
另一個(gè)返回值為整形值的int __disable_fiq(void)
用法:int __disable_fiq(void),禁止FIQ中斷(ARMv4和ARMv5)或禁用除NMI之外的所有中斷(ARMv7)。
在禁用中斷前,將中斷使能狀態(tài)返回。
void __disable_fiq(void),禁用FIQ中斷(ARMv4和ARMv5)或禁用除NMI之外的所有中斷(ARMv7)。
限制:只能在特權(quán)級(jí)別下使用,用戶模式下無(wú)效。
如果編譯器參數(shù)設(shè)置為-cpu=7,則不支持int __disable_fiq(void)函數(shù),這是因?yàn)橥ㄓ肁RMv7架構(gòu)和ARMv7 R及ARMv7 M-profiles架構(gòu)的異常處理模式不同所導(dǎo)致的。
這意味著如果編譯器參數(shù)設(shè)置為-cpu=7,編譯器不能為int __disable_fiq(void)函數(shù)產(chǎn)生所有ARMv7架構(gòu)通用的指令序列,此時(shí)只能使用void __disable_fiq(void)。
舉例:
void func(void){ int was_masked = __disable_fiq(); /*其它處理*/ if(!was_masked) { __enable_fiq(); }}
為什么例子中要使用變量was_masked獲取之前的中斷使能信息,并且在使能中斷時(shí)還要先判斷這個(gè)變量?
直接使用__disable_fiq()和__enable_fiq()函數(shù)不是更簡(jiǎn)單嗎?
這是因?yàn)槿绻跋到y(tǒng)的中斷已經(jīng)是關(guān)閉的,當(dāng)你直接使用__enable_fiq()函數(shù)就會(huì)無(wú)條件打開(kāi)中斷,這樣可能是很危險(xiǎn)的。所以在打開(kāi)中斷前,要檢查之前中斷是不是已經(jīng)是禁止?fàn)顟B(tài),如果是的話就不要使能中斷。
4.__enable_irq使能IRQ中斷
對(duì)于ARMv4和ARMv5架構(gòu)(ARM7和ARM9),編譯器插入下列指令清除CPSR寄存器的I位。
MRS r0, CPSRAND r0, r0, #0x7FMSR CPSR_c, r0
對(duì)于ARMv6(ARM11)和ARMv7(Cortex-M3等)指令,編譯器插入下列指令使能中斷:
CPSIE I
比如Cortex-M3架構(gòu)處理器,該指令清除PRIMASK寄存器,使能中斷。
語(yǔ)法:void __enable_irq(void)
限制:只能在特權(quán)級(jí)別下使用,用戶模式下無(wú)效。
5. __disable_irq禁止IRQ中斷
對(duì)于ARMv4和ARMv5架構(gòu)(ARM7和ARM9),編譯器插入下列指令置位CPSR寄存器的I位。
MRS r0, CPSRORR r0, r0, #0x80MSR CPSR_c, r0
對(duì)于ARMv6(ARM11)和ARMv7(Cortex-M3等)指令,編譯器插入下列指令禁用中斷:
CPSID I
比如Cortex-M3架構(gòu)處理器,該指令置位PRIMASK寄存器,表示禁止中斷和可屏蔽的異常,只剩下NMI和硬Fault可以響應(yīng)。
__disable_irq函數(shù)有兩種形式,返回值為空的void __disable_irq(void)和返回值為整形數(shù)的int __disable_irq(void)。
前者直接禁用中斷,后者在禁用中斷前,將中斷使能狀態(tài)返回。
舉例:
void func(void){ int was_masked = __disable_irq(); /*其它處理*/ if(!was_masked) { __enable_irq(); }}
為什么例子中要使用變量was_masked獲取之前的中斷使能信息,并且在使能中斷時(shí)還要先判斷這個(gè)變量?
直接使用__disable_irq()和__enable_irq()函數(shù)不是更簡(jiǎn)單嗎?
這是因?yàn)槿绻跋到y(tǒng)的中斷已經(jīng)是關(guān)閉的,當(dāng)你直接使用__enable_irq()函數(shù)就會(huì)無(wú)條件打開(kāi)中斷,這樣可能是很危險(xiǎn)的。
所以在打開(kāi)中斷前,要檢查之前中斷是不是已經(jīng)是禁止?fàn)顟B(tài),如果是的話就不要使能中斷。
限制:只能在特權(quán)級(jí)別下使用,用戶模式下無(wú)效。
如果編譯器參數(shù)設(shè)置為-cpu=7,則不支持int __disable_irq(void)函數(shù),這是因?yàn)橥ㄓ肁RMv7架構(gòu)和ARMv7 R及ARMv7 M-profiles架構(gòu)的異常處理模式不同所導(dǎo)致的。
這意味著如果編譯器參數(shù)設(shè)置為-cpu=7,編譯器不能為int __disable_irq(void)函數(shù)產(chǎn)生所有ARMv7架構(gòu)通用的指令序列.
此時(shí)只能使用void __disable_irq(void)。
我們?cè)購(gòu)?a href="http://ttokpm.com/v/tag/3195/" target="_blank">匯編層面上看一下返回整形數(shù)的__disable_irq:
int disable_irq(void){ return __disable_irq();}
在-cpu=Cortex-M3時(shí),Keil MDK編譯器產(chǎn)生的匯編代碼為:
MRS r0, PRIMASKAND r0, r0, #1CPSID iBX lr
6.這些函數(shù)有什么用處?
保護(hù)共享資源
禁止中斷嵌套
保護(hù)共享資源很好理解,但禁止中斷嵌套可能很多人不理解。
中斷嵌套可以提高系統(tǒng)響應(yīng)時(shí)間,為什么要禁用掉?
雖然中斷嵌套能提高響應(yīng)時(shí)間,但絕大多數(shù)的應(yīng)用并不需要如此高的響應(yīng)時(shí)間;
更重要的是,中斷嵌套增加了程序運(yùn)行的不確定性。所以我建議在不需要極致的響應(yīng)時(shí)間使,禁止中斷嵌套。
方法也很簡(jiǎn)單,在進(jìn)入中斷服務(wù)函數(shù)后和退出中斷服務(wù)函數(shù)前中調(diào)用本文講的這些中斷控制函數(shù)即可。
7.移植性
與編譯器特性相關(guān),不具備移植性,建議使用前先用宏進(jìn)行封裝。
來(lái)源:https://blog.csdn.net/zhzht19861011/article/details/52815488
-
IRQ
+關(guān)注
關(guān)注
0文章
16瀏覽量
10748 -
編譯器
+關(guān)注
關(guān)注
1文章
1617瀏覽量
49015 -
FIQ
+關(guān)注
關(guān)注
0文章
9瀏覽量
2298
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論