0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

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

黄工的嵌入式技术圈 来源:黄工的嵌入式技术圈 作者:黄工的嵌入式技术 2020-02-29 16:45 次阅读

本文是一篇偏向底层的内容。

1.写在前面

编译器内部函数__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来控制中断。

2.__enable_fiq使能FIQ中断

通常是通过清除寄存器CPSR中的F位来实现的。

注意FIQ中断一般只存在于ARMv4和ARMv5架构中(即ARM7和ARM9),ARMv6架构的处理器不支持此函数。

对于ARMv7架构的处理器(Cortex-M3),这个函数清除FAULTMASK寄存器的值。

语法:void __enable_fiq(void)

限制:只能在特权级别下使用,用户模式下无效。

3.__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)

用法: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()函数就会无条件打开中断,这样可能是很危险的。所以在打开中断前,要检查之前中断是不是已经是禁止状态,如果是的话就不要使能中断。

4.__enable_irq使能IRQ中断

对于ARMv4和ARMv5架构(ARM7和ARM9),编译器插入下列指令清除CPSR寄存器的I位。

MRS r0, CPSRAND r0, r0, #0x7FMSR CPSR_c, r0

对于ARMv6(ARM11)和ARMv7(Cortex-M3等)指令,编译器插入下列指令使能中断:

CPSIE I

比如Cortex-M3架构处理器,该指令清除PRIMASK寄存器,使能中断。

语法:void __enable_irq(void)

限制:只能在特权级别下使用,用户模式下无效。

5. __disable_irq禁止IRQ中断

对于ARMv4和ARMv5架构(ARM7和ARM9),编译器插入下列指令置位CPSR寄存器的I位。

MRS r0, CPSRORR r0, r0, #0x80MSR 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, PRIMASKAND r0, r0, #1CPSID iBX lr

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

保护共享资源

禁止中断嵌套

保护共享资源很好理解,但禁止中断嵌套可能很多人不理解。

中断嵌套可以提高系统响应时间,为什么要禁用掉?

虽然中断嵌套能提高响应时间,但绝大多数的应用并不需要如此高的响应时间;

更重要的是,中断嵌套增加了程序运行的不确定性。所以我建议在不需要极致的响应时间使,禁止中断嵌套。

方法也很简单,在进入中断服务函数后和退出中断服务函数前中调用本文讲的这些中断控制函数即可。

7.移植性

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

来源:https://blog.csdn.net/zhzht19861011/article/details/52815488

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • IRQ
    IRQ
    +关注

    关注

    0

    文章

    16

    浏览量

    10605
  • 编译器
    +关注

    关注

    1

    文章

    1577

    浏览量

    48638
  • FIQ
    FIQ
    +关注

    关注

    0

    文章

    9

    浏览量

    2233
收藏 人收藏

    评论

    相关推荐

    KEIL怎么禁止某个函数/某段代码被编译器优化?

    有没有大佬知道,KEIL怎么禁止某个函数/某段代码 被编译器优化?
    发表于 04-10 08:17

    使用mdk的ac6编译器一直报错是怎么回事?

    使用mdk的ac6编译器一直报错
    发表于 04-10 06:01

    STM32CubeMX生成FreeRTOS的MDK工程不支持AC6编译器吗?

    使用STM32CubeMX生成FreeRTOS的MDK工程,选择AC5编译器可以编译成功,选择AC6编译器有很多错误,是STM32CubeMX生成FreeRTOS的
    发表于 03-06 08:24

    M481系列KEIL选择ARM5编译器编译速度非常慢怎么解决?

    M481系列,如果KEIL选择ARM5编译器编译速度非常慢
    发表于 01-16 06:51

    FIQ为例说明其中断处理流程

    ,也可能是其它的,但是肯定关于此时CPU状态的。)然后跳转到异常向量 表入口处执行中断处理流程 。 2-执行中断处理流程 fiq_aarch64 函数主要
    的头像 发表于 11-07 17:48 528次阅读

    如何在特权模式下用arm汇编指令使能和禁止irq中断

    时执行,处理中断事件。 使能和禁止 IRQ 中断是通过控制 CPSR 寄存器的 IRQ 位来实现的。当
    的头像 发表于 10-19 16:42 801次阅读

    Keil修改ARM编译器及配置方法

    Keil MDK自 V5.36 版本之后,默认就不带 Arm Compiler V5版本编译器。如果需要使用 V5 版本编译器,就需要自己下载并安装。
    发表于 09-19 10:41 2262次阅读
    <b class='flag-5'>Keil</b>修改ARM<b class='flag-5'>编译器</b>及配置方法

    AMBA中断控制器数据表

    ,而无需确定中断的源。 它还减少了中断延迟,因为额外的存储体寄存可用于FIQ中断,可通过避免上下文保存来最大限度地提高效率。
    发表于 08-21 06:08

    PrimeCell矢量中断控制器(PL190)循环模型9.1.0版用户指南

    VIC PL190硬件实施的以下功能在VIC PL190周期型号中完全实现。 ·符合AMBA AHB规范·支持32个标准中断·支持16个矢量化IRQ中断·硬件中断优先级·
    发表于 08-12 06:55

    RealView编译工具NEON矢量化编译器指南

    向量指令。 编译器可以从dspfns.h头文件向量化常规的C和C++操作,如+和一些ITU内部函数。 作为编译器矢量化的替代方案,RVCT还支持将霓虹灯
    发表于 08-12 06:22

    安装适用于Nuvoton Edition 1.1版的Keil MDK应用程序说明

    Edition-Cortex-M0/M0+/M23包括ARM C/C++编译器Keil RTX5实时操作系统内核以及µVision IDE和调试。 如果您希望对Nuvoton的所有基于ARM Cortex-M
    发表于 08-11 07:39

    安装Keil MDK for Holtek Edition 1.0版应用程序说明

    编译器Keil RTX5实时操作系统内核以及µVision IDE和调试。 如果您希望对Holtek的所有基于ARM Cortex-M的设备进行编程,请在线购买Keil
    发表于 08-11 06:51

    如何将Arm Neon C#内部函数与Unity Burst编译器一起使用

    本指南解释了如何将Arm Neon C#内部函数与Unity Burst编译器一起使用,以提高Unity Android应用程序的性能。 在本指南结束时,您将了解到: •单指令多数据(SIMD)指令
    发表于 08-10 07:11

    Linux Kernel的中断处理函数中是否会被其它程序(中断/异常)打断?

    当一个irq/fiq正在执行时 ,是否可能会其它的irq/fiq打断呢?
    的头像 发表于 06-07 17:27 764次阅读
    Linux Kernel的<b class='flag-5'>中断</b>处理<b class='flag-5'>函数</b>中是否会被其它程序(<b class='flag-5'>中断</b>/异常)打断?

    为MindSDK搭建Keil MDK开发环境

    本文介绍基于Windows操作系统构建嵌入式系统开发环境过程中需要使用的主要软件Keil MDK,并对一些需要特别关注的要点重点说明。Keil MDK是灵动官方的软件开发平台MindS
    的头像 发表于 05-04 10:42 1098次阅读
    为MindSDK搭建<b class='flag-5'>Keil</b> <b class='flag-5'>MDK</b>开发环境