我们知道在 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 寄存器中置起的事件标志位需要在事件处理前手动清除掉。如果标志位不及时清除,可能会遗漏下一次事件的处理(比如先处理当前事件,后清除事件标志位,那么处理事件期间再次发生的事件就会被漏掉)。如果标志位忘了清除,同一次事件就会被处理两次及以上。
当然在实际应用中,为了节省 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 <= 0) { nvic->icer[(((uint32_t)irqn) >> 5ul)] = (uint32_t)(1ul <= 6#if defined(__arm_arch_profile) && __arm_arch_profile == 'm' __asm__ __volatile__(mrs %[cpsr], primask cpsid i : [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); // 开启芯片系统全局中断 __enable_irq();} 本文转载自痞子衡嵌入式
硕美科新款游戏耳机G951 PINK,女性玩家的不二选择
怎样查看手机信号强度?一些手机自带的信号查看方式
我国传感器助力机器人的发展还面临四大困境
在线测试仪在电路板维修中的应用
怎样将有线门铃变成智能门铃
ARM Cortex-M内核MCU的三重中断控制设计
科学家研制出行为仿真的人工神经细胞微芯片
晶体振荡器的种类
富士康要怎么成为电动汽车的“Android”
这款AR工具逆天了 能让iPhone秒变桌面游乐场
USB接口电路的电磁兼容性设计注意事项
明年首季NAND Flash供过于求态势将更加明显
使用LTspice仿真功能检查电源启动时的运作情况
区块链支持的展品目录和交易平台4ART介绍
摩托罗拉Capri Plus手机曝光 跑分网公布部分硬件信息
DP9241——应用于汽车诊断系统中的单片总线收发器
cc2530引脚图及功能
政策合力推动我国互联网医疗行业的规范发展
四川省酿酒研究所采购南京大展的低温差示扫描量热仪
智能天线在JT-SA MIMO-OFDM系统的应用