控制IRQ和FIQ中断的编译器内部函数 - 基于Keil MDK

2717人阅读 评论(0) 收藏 举报
分类:
编译器内部函数__disable_irq、__enable_irq、__disable_fiq和__enable_fiq用于控制IRQ和FIQ中断。
只有当处理器处于特权模式才可以使用这些内部函数,因为这些函数要改变寄存器CPSR和SPSR(ARM7、ARM9等)或者PRIMASK和FAULTMASK寄存器(Cortex-M3、M4等),而这些寄存器只有在特权模式下才能被访问。
这些内部函数对所有架构的处理器都有效,无论是ARM状态还是Thumb状态,如下所述:
如果使用的是ARMv6(ARM11)或更新架构,编译器会将这些函数用CPS指令代替。
如果使用的是ARMv4或者ARMv5架构并且处于ARM状态,编译器会将这些函数用MRS和MSR指令代替。一般情况下ARM7属于ARMv4架构,ARM9属于ARMv5架构。
如果使用的是ARMv4或者ARMv5架构并且处于Thumb状态或编译器使能-compatible参数,则编译器会调用一个辅助函数比如__ARM_disable_irq来控制中断。

1. __enable_fiq

使能FIQ中断。
通常是通过清除寄存器CPSR中的F位来实现的。注意FIQ中断一般只存在于ARMv4和ARMv5架构中(即ARM7和ARM9),ARMv6架构的处理器不支持此函数。对于ARMv7架构的处理器(Cortex-M3),这个函数清除FAULTMASK寄存器的值。
语法:void __enable_fiq(void)
限制:只能在特权级别下使用,用户模式下无效。

2.__disable_fiq

禁用FIQ中断。
通常是通过置一CPSR的F位来实现的。注意FIQ中断一般只存在于ARMv4和ARMv5架构中(即ARM7和ARM9),ARMv6架构的处理器不支持此函数。对于ARMv7架构的处理器(Cortex-M3),这个函数置位FAULTMASK寄存器,这意味着此后只有NMI可以响应,所有其它的异常,包括中断和 Fault都不能响应。
语法:__disable_fiq有两个版本,一个是返回值为空的void __disable_fiq(void),另一个返回值为整形值的int __disable_fiq(void),函数名都是__disable_fiq。
用法:int __disable_fiq(void),禁止FIQ中断(ARMv4和ARMv5)或禁用除NMI之外的所有中断(ARMv7)。在禁用中断前,将中断使能状态返回。
void __disable_fiq(void),禁用FIQ中断(ARMv4和ARMv5)或禁用除NMI之外的所有中断(ARMv7)。
限制:只能在特权级别下使用,用户模式下无效。如果编译器参数设置为-cpu=7,则不支持int __disable_fiq(void)函数,这是因为通用ARMv7架构和ARMv7 R及ARMv7 M-profiles架构的异常处理模式不同所导致的。这意味着如果编译器参数设置为-cpu=7,编译器不能为int __disable_fiq(void)函数产生所有ARMv7架构通用的指令序列,此时只能使用void __disable_fiq(void)。
举例:
void func(void)
{
int was_masked = __disable_fiq();
/*其它处理*/
if(!was_masked)
    __enable_fiq();
}
为什么例子中要使用变量was_masked获取之前的中断使能信息,并且在使能中断时还要先判断这个变量?直接使用__disable_fiq()和__enable_fiq()函数不是更简单吗?
这是因为如果之前系统的中断已经是关闭的,当你直接使用__enable_fiq()函数就会无条件打开中断,这样可能是很危险的。所以在打开中断前,要检查之前中断是不是已经是禁止状态,如果是的话就不要使能中断。

3.__enable_irq

使能IRQ中断。
对于ARMv4和ARMv5架构(ARM7和ARM9),编译器插入下列指令清除CPSR寄存器的I位。
MRS  r0, CPSR
AND  r0, r0, #0x7F
MSR  CPSR_c, r0
对于ARMv6(ARM11)和ARMv7(Cortex-M3等)指令,编译器插入下列指令使能中断:
CPSIE  I
比如Cortex-M3架构处理器,该指令清除PRIMASK寄存器,使能中断。
语法:void __enable_irq(void)
限制:只能在特权级别下使用,用户模式下无效。

4. __disable_irq

禁止IRQ中断。
对于ARMv4和ARMv5架构(ARM7和ARM9),编译器插入下列指令置位CPSR寄存器的I位。
MRS  r0, CPSR
ORR  r0, r0, #0x80
MSR  CPSR_c, r0
对于ARMv6(ARM11)和ARMv7(Cortex-M3等)指令,编译器插入下列指令禁用中断:
CPSID  I
比如Cortex-M3架构处理器,该指令置位PRIMASK寄存器,表示禁止中断和可屏蔽的异常,只剩下NMI和硬Fault可以响应。
__disable_irq函数有两种形式,返回值为空的void __disable_irq(void)和返回值为整形数的int __disable_irq(void)。前者直接禁用中断,后者在禁用中断前,将中断使能状态返回。
举例:
void func(void)
{
int was_masked = __disable_irq();
/*其它处理*/
if(!was_masked)
    __enable_irq();
}
为什么例子中要使用变量was_masked获取之前的中断使能信息,并且在使能中断时还要先判断这个变量?直接使用__disable_irq()和__enable_irq()函数不是更简单吗?
这是因为如果之前系统的中断已经是关闭的,当你直接使用__enable_irq()函数就会无条件打开中断,这样可能是很危险的。所以在打开中断前,要检查之前中断是不是已经是禁止状态,如果是的话就不要使能中断。
限制:只能在特权级别下使用,用户模式下无效。如果编译器参数设置为-cpu=7,则不支持int __disable_irq(void)函数,这是因为通用ARMv7架构和ARMv7 R及ARMv7 M-profiles架构的异常处理模式不同所导致的。这意味着如果编译器参数设置为-cpu=7,编译器不能为int __disable_irq(void)函数产生所有ARMv7架构通用的指令序列,此时只能使用void __disable_irq(void)。

我们再从汇编层面上看一下返回整形数的__disable_irq:
int disable_irq(void)
{
    return __disable_irq();
}
在-cpu=Cortex-M3时,Keil MDK编译器产生的汇编代码为:
MRS    r0, PRIMASK
AND    r0, r0, #1
CPSID  i
BX     lr

5.这些函数有什么用处?

  1. 保护共享资源
  2. 禁止中断嵌套
保护共享资源很好理解,但禁止中断嵌套可能很多人不理解:中断嵌套可以提高系统响应时间,为什么要禁用掉?
虽然中断嵌套能提高响应时间,但绝大多数的应用并不需要如此高的响应时间;更重要的是,中断嵌套增加了程序运行的不确定性。所以我建议在不需要极致的响应时间使,禁止中断嵌套。方法也很简单,在进入中断服务函数后和退出中断服务函数前中调用本文讲的这些中断控制函数即可。

6.移植性

与编译器特性相关,不具备移植性,建议使用前先用宏进行封装。




查看评论

IRQ和FIQ中断的区别

FIQ和IRQ是两种不同类型的中断,ARM为了支持这两种不同的中断,提供了对应的叫做FIQ和IRQ处理器模式(ARM有7种处理模式)。 一般的中断控制器里我们可以配置与控制器相连的某个中断输入是F...
  • michaelcao1980
  • michaelcao1980
  • 2014年02月20日 10:12
  • 19884

ARM 中断--IRQ and FIQ配置--外部配置

中断分为外部中断和定时器中断; 中断源都是有一个触发条件,条件满足就会产生中断。不同的中断源触发条件不一样 ARM中中断分为两种:FIQ(fast interrupt request)快速中断请求,...
  • Mce_19
  • Mce_19
  • 2016年11月25日 19:56
  • 1192

__disable_irq是在哪里定义的

在原代码中见到__disable_irq(),看起来像是
  • booksyhay
  • booksyhay
  • 2014年11月25日 10:21
  • 3007

ARM的irq和fiq中断以及中断嵌套

几天前一个学生问我ARM中断嵌套的问题,我才发现原在我心中理所当然的事对学生来说理解实属不易。      ARM有七种模式,我们这里只讨论SVC、IRQ和FIQ模式。      我们可以假设ARM...
  • linyangspring
  • linyangspring
  • 2014年09月29日 15:19
  • 1710

【stm32f0】stm32 总中断的打开与关闭

问题: 对于基于ARM Cortex M0内核的STM32芯片各类应用开发时,有的时候需要进行总的中断的开、关处理。那就究竟有没有开、关总的中断的函数或者指令呢? 回答: 随着Corte Mn各种内...
  • u014647208
  • u014647208
  • 2017年08月23日 09:44
  • 2163

ARM 指令

处理器使用的是ARMv6-M Thumb指令集,包括大量的32位的使用Thumb-2技术的指令。表7-22列出了Cortex-M0指令和它们的周期数。周期计数以零等待状态的系统为基准。 表7-22 ...
  • TestFamily
  • TestFamily
  • 2014年06月09日 10:39
  • 7776

如何利用keil C实现单片机中断功能(interrupt,using关键字的用法)

C语言在8051单片机上的扩展(interrupt、using关键字的用法)直接访问寄存器和端口 定义sfr P0 0x80 sfr P1 0x81 sfr ADCON; 0xDEsbit EA  0...
  • qp_12
  • qp_12
  • 2017年01月22日 00:11
  • 1519

中断处理函数中不用disable_irq而…

今天在写触摸屏驱动时在中断处理函数中使用disable_irq关中断发现在进入中断处理后内核就挂掉了,于是研究了一下才发现disable_irq关闭中断并等待中断处理完后返回, 而disable_ir...
  • shangyaowei
  • shangyaowei
  • 2013年12月19日 20:51
  • 467

Cortex-M3 中断的具体行为

ARM Cortex-M3学习记录:Crotex-M3中断响应与中断返回序列
  • sagitta_zl
  • sagitta_zl
  • 2016年05月19日 00:08
  • 1969

MDK中如何使用中断关键词__irq

根据ARM提供的资料,在使用快速中断的时候一般对时间要求比较高,这时建议客户使用汇编语言进行编写FIQ的中断处理函数. Realview MDK使用的RVCT编译器提供了__irq关键字,用此关键字...
  • wfq0624
  • wfq0624
  • 2012年06月09日 18:11
  • 1221
    个人资料
    专栏达人 持之以恒
    等级:
    访问量: 169万+
    积分: 1万+
    排名: 1162
    博客专栏
    最新评论
    友情链接