本文由 发布,转载请注明出处,如有问题请联系我们! 发布时间: 2021-07-24痞子衡嵌入式:嵌入式MCU中标准的三重中断控制设计

加载中

  各位好!,我是无赖衡,是正儿八经搞技术性的无赖。今日无赖衡给大伙儿共享的是内嵌式MCU中规范的三重终断操纵设计方案

  我们知道在 MCU 原装机中编程代码往往能进行多个任务并行处理并行处理作用,实际上 主要是靠终断来生产调度的,沒有终断,CPU 就只有按序"死板"地实行编码。很多人都说是终断工作能力授予了 MCU 真真正正的生命,能正确对待和娴熟应用 MCU 终断,大部分即使玩熟了这颗 MCU。

  无赖衡以前读过一篇 《中断处理函数(IRQHandler)的标准流程》,里边详尽讲了终断处理函数里的规范编码步骤与书写,本文可让大伙儿对 MCU 里的终断使用方法有一个基本了解。今日无赖衡以 ARM Cortex-M 核心 MCU 为例子再去详细介绍下业内规范的三重终断操纵设计方案:

一、外接设备事情终断操纵

  MCU 中底层的终断操纵对于的是外接设备里某一实际的事情,这一操纵来自于外接设备控制模块自身,以英飞凌 i.MXRT 系列产品 MCU 的 GPT 计时器控制模块为例子。以下是 GPT 控制模块存储器目录,你能发觉在其中有經典的 IR 和 SR 存储器,SR 是事情情况存储器,IR 是终断事情操纵存储器:

  GPT 计时器一旦被也就能,其运作情况(一共适用 6 个事情:请求超时、键入捕捉 x 2ch、较为輸出 x 3ch)都是会即时纪录在 SR 存储器中,假如没有 IR 存储器里将事情终断打开(默认设置是关掉的),那麼就必须 客户在编码里手动式去查看 SR 存储器置起的事情标志位以解决相匹配事情。

  • Note:SR 存储器中置起的事情标志位必须 在事故处理前手动式消除掉。假如标志位不立即消除,很有可能会忽略下一次事情的解决(例如先解决当今事情,后消除事情标志位,那麼事件处理期内再次出现的事情便会被跳开)。假如标志位忘记了消除,同一次事情便会被解决2次及之上。

  自然在具体运用中,为了更好地节约 CPU 网络带宽,我们是要打开外接设备事情终断的,MCU 生产商 SDK 包里一般都是会给予相对应接口函数(源自 fsl_gpt.h):

typedef enum _gpt_interrupt_enable
{
    kGPT_OutputCompare1InterruptEnable = GPT_IR_OF1IE_MASK,
    kGPT_OutputCompare2InterruptEnable = GPT_IR_OF2IE_MASK,
    kGPT_OutputCompare3InterruptEnable = GPT_IR_OF3IE_MASK,
    kGPT_InputCapture1InterruptEnable  = GPT_IR_IF1IE_MASK,
    kGPT_InputCapture2InterruptEnable  = GPT_IR_IF2IE_MASK,
    kGPT_RollOverFlagInterruptEnable   = GPT_IR_ROVIE_MASK,
} gpt_interrupt_enable_t;

// 打开 GPTx 的 xx 事情终断
static inline void GPT_EnableInterrupts(GPT_Type *base, uint32_t mask)
{
    base->IR |= mask;
}

// 关掉 GPTx 的 xx 事情终断
static inline void GPT_DisableInterrupts(GPT_Type *base, uint32_t mask)
{
    base->IR &= ~mask;
}

  也就能 GPT1 的请求超时事情终断编码实例以下:

void periph_int_config(void)
{
    // 复位 GPT1...
    GPT_Init(GPT1, &gptConfig);
    // ...

    // 打开 GPT1 的请求超时事情终断
    GPT_EnableInterrupts(GPT1, kGPT_RollOverFlagInterruptEnable);
}

二、外接设备全局性终断操纵

  MCU 中第二层的终断操纵对于的是全部外接设备,这一操纵来自于 Cortex-M 核心的 NVIC 控制模块。以下是 NVIC 控制模块存储器目录(源自 ARMv8-M 指南,除开 IABRn 和 ITNSn 存储器组外,其他存储器可用所有的 Cortex-M 大家族),在其中跟终断电源开关有关的是 ISER 和 ICER 存储器:

  当 MCU 中某外接设备(例如上一节里的 GPT)被也就能后,即便其內部事情终断已被打开,都不代表着异常中断一定会被开启,由于 NVIC 里针对这一外接设备的全局性终断电源开关(同一外接设备中全部事情共享资源一个异常中断資源,即一个终断号)都还没打开。ARM CMSIS 包里给予了外接设备全局性终断操纵涵数(源自 core_cm7.h 文档):

#define NVIC_EnableIRQ              ._NVIC_EnableIRQ
#define NVIC_DisableIRQ             ._NVIC_DisableIRQ

// 打开 xx 外接设备的全局性终断
._STATIC_INLINE void ._NVIC_EnableIRQ(IRQn_Type IRQn)
{
  if ((int32_t)(IRQn) >= 0)
  {
    ._COMPILER_BARRIER();
    NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL));
    ._COMPILER_BARRIER();
  }
}

// 关掉 xx 外接设备的全局性终断
._STATIC_INLINE void ._NVIC_DisableIRQ(IRQn_Type IRQn)
{
  if ((int32_t)(IRQn) >= 0)
  {
    NVIC->ICER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL));
    ._DSB();
    ._ISB();
  }
}

  提升了也就能 GPT1 的全局性终断编码实例以下,在其中 GPT1_IRQn 和 GPT1_IRQHandler 是固定不动名称,在 MCU 生产商给予的库函数(MIMXRT1176_cm7.h)和运行文档(startup_MIMXRT1176_cm7.s)里有界定。

void periph_int_config(void)
{
    // 复位 GPT1...
    GPT_Init(GPT1, &gptConfig);
    // ...

    // 打开 GPT1 的请求超时事情终断
    GPT_EnableInterrupts(GPT1, kGPT_RollOverFlagInterruptEnable);

    // 打开 GPT1 的全局性终断
    NVIC_EnableIRQ(GPT1_IRQn);
}

// GPT1 的终断响应函数
void GPT1_IRQHandler(void)
{
    GPT_ClearStatusFlags(GPT1, kGPT_RollOverFlagInterruptEnable);

    // 终断业务流程解决编码
}

三、系统软件全局性终断操纵

  MCU 中最高层的终断操纵对于的是全部集成ic系统软件,这一操纵来自于 Cortex-M 核心的 CPS 命令。以下是 CPS 命令使用方法(源自 ARMv7-M 指南):

  如果你想对 MCU 全部集成ic的全部终断开展统一电源开关操纵时,就务必依靠 CPS 命令。一般状况下打开集成ic系统软件全局性终断姿势在 MCU 运行文档里早已搞好了,全部在客户编码自然环境里经常不用也就能系统软件全局性终断的姿势。以下是 IAR 自然环境下 i.MXRT1170 运行文档中系统软件全局性终断实际操作,根据汇编语言指令完成:

  为了更好地有利于客户在 C 编码中电脑操作系统全局性终断,各 IDE 下均按一样的接口函数( ._disable_irq / ._enable_irq )干了封裝完成。IAR 自然环境见 \IAR Systems\Embedded Workbench 8.50.6\arm\inc\c\iccarm_builtin.h 文档,可是封裝进其 Lib 了,沒有曝露源代码:

#include "iccarm_builtin.h"

#define ._disable_irq       ._iar_builtin_disable_interrupt
#define ._enable_irq        ._iar_builtin_enable_interrupt

  Keil 自然环境见 \Keil_v5\ARM\ARMCLANG\include\arm_compat.h 文档,我们可以见到源代码:

static ._inline._ unsigned int ._attribute._((._always_inline._, ._nodebug._))
._disable_irq(void) {
  unsigned int cpsr;
#if ._ARM_ARCH >= 6
#if defined(._ARM_ARCH_PROFILE) && ._ARM_ARCH_PROFILE == 'M'
  ._asm._ ._volatile._("mrs %[cpsr], primask\n"
                       "cpsid i\n"
                       : [cpsr] "=r"(cpsr));
  return cpsr & 0x1;
#endif
#endif
}

static ._inline._ void ._attribute._((._always_inline._, ._nodebug._))
._enable_irq(void) {
#if ._ARM_ARCH >= 6
  ._asm._ ._volatile._("cpsie i");
#endif
}

  最后 GPT 方法里详细的三重终断也就能编码应以下:

void periph_int_config(void)
{
    // 复位 GPT1...
    GPT_Init(GPT1, &gptConfig);
    // ...

    // 打开 GPT1 的请求超时事情终断
    GPT_EnableInterrupts(GPT1, kGPT_RollOverFlagInterruptEnable);

    // 打开 GPT1 的全局性终断
    NVIC_EnableIRQ(GPT1_IRQn);

    // 打开集成ic系统软件全局性终断
    ._enable_irq();
}

  到此,内嵌式MCU中规范的三重终断操纵设计方案无赖衡便详细介绍结束了,欢呼声在哪儿~~~

热烈欢迎定阅

文章发表与此同时公布到我的 博客园首页、CSDN首页、知乎问答首页、微信公众平台 服务平台上。

搜索微信"无赖衡内嵌式"或是扫描仪下边二维码,就可以在手机上第一时间看过哦。

  最终热烈欢迎关心无赖衡本人微信公众平台【无赖衡内嵌式】,一个潜心嵌入式系统的微信公众号,跟随无赖衡一起轻松玩内嵌式。

痞子衡嵌入式-微信二维码 痞子衡嵌入式-微信收款二维码 痞子衡嵌入式-支付宝收款二维码

  衡杰(无赖衡),现阶段任职于英飞凌MCU系统软件单位,出任嵌入式操作系统应用工程师。

  栏目内全部文章内容的转截请标明来源:http://www.cnblogs.com/henjay724/

  与无赖衡进一步沟通交流或资询业务流程协作请发送邮件至 hengjie1989@foxmail.com

  能够 关心无赖衡的GitHub首页 https://github.com/JayHeng,有很多好玩儿的内嵌式新项目。

  有关栏目文章内容有一切有意者立即在blog下边留言板留言,无赖衡会立即回应完全免费(划重点)答疑解惑。

  无赖衡电子邮箱已被私聊爆满,技术性难题不强烈推荐私聊,坚持不懈私聊请先扫码支付(5元发展)再发。


评论(0条)

刀客源码 游客评论