当前位置: 首页 > news >正文

ARM中断处理流程

1.设置异常向量表地址为0(为0则可以重映射)//start.S

配置协处理器,将协处理器的SCTLR的第12位置1,开启指令缓存I-Cache,将第13位清零,当第13位 = 0 时,异常向量表位于由 VBAR 寄存器指定的地址。

mrc p15, 0, r1, c1, c0, 0 /**将 CP15 的 SCTLR 寄存器的内容读取到通用寄存器 r1 中 */ orr r1, r1, #(1 << 12) /*将 r1 的第 12 位置 1。第 12 位(I 位)是 指令缓存使能位。置 1 表示启用 I-Cache,提高指令取指速度。 */ bic r1, r1, #(1 << 13) /**将 r1 的第 13 位清零。第 13 位(V 位)是 向量表位置选择位。*/ /* 当 V = 1 时,异常向量表位于 0xFFFF0000(高向量)。 当 V = 0 时,异常向量表位于由 VBAR 寄存器指定的地址(通常是 0x00000000 或重定位后的地址)。 清零 V 位,配合后续通过 __set_VBAR(0x87800000) 设置 VBAR,使得 CPU 在发生中断/异常时从 0x87800000 处获取向量表(而不是默认的 0xFFFF0000)。 */ mcr p15, 0, r1, c1, c0, 0 /**将修改后的值写回 SCTLR 寄存器,使配置生效。 */

中断(GIC)初始化

1.重映射异常向量表基地址

2.初始化GIC

#include "MCIMX6Y2.h" #include "fsl_iomuxc.h" #include "core_ca7.h" #include "led.h" #include "beep.h" #include "key.h" void ccm_ccgr_enable(void) { CCM->CCGR0 = 0xffffffff; CCM->CCGR1 = 0xffffffff; CCM->CCGR2 = 0xffffffff; CCM->CCGR3 = 0xffffffff; CCM->CCGR4 = 0xffffffff; CCM->CCGR5 = 0xffffffff; CCM->CCGR6 = 0xffffffff; } static void delay(unsigned int num) { while(num--); } void system_irq_init(void) { __set_VBAR(0x87800000);//由协处理器p15的VBAR配置寄存器重定位向量表 GIC_Init(); } void system_irq_handler(IRQn_Type irq_num)//中断处理函数 { if (irq_num == GPIO1_Combined_16_31_IRQn)//检查是否是gpio1产生的中断 { if (GPIO1->ISR & (1 << 18)) //检查是否是gpio1_io18产生的中断 检查GPIO1->ISR寄存器的第18位状态码 { led_on(); beep_on(); GPIO1->ISR |= (1 << 18);//写1清楚标志位 } } } int main(void) { system_irq_init(); ccm_ccgr_enable(); led_init(); beep_init(); key_irq_init(); while(1) { /* led_on(); beep_on(); delay(0x80000); led_off(); beep_off(); delay(0x80000); */ } return 0; }

void system_irq_init(void):对中断和GIC的初始化,设置GIC的VBAR(向量表基地址)为编译时链接的地址,并初始化GIC.

当外部中断产生后,跳到汇编中的_irq_handler,

_irq_handler: sub lr, lr, #4 /*当 CPU 进入 IRQ 模式时,LR_irq 保存的是被中断指令的下一条指令地址(即 PC + 4),因此需要减去 4 得到正确的返回地址,以便中断结束后能够返回到被中断的指令。 */ stmfd sp!, {r0-r12, lr} /*将通用寄存器 r0-r12 和调整后的 lr 压入 IRQ 模式的栈中,保存当前程序的执行现场。 */ mrc p15, 4, r1, c15, c0, 0/*读取协处理器 p15 的 CBAR(Configuration Base Address Register),该寄存器保存 GIC 的物理基址,结果存入 r1 */ add r1, r1, #0x2000 /*CPU 接口基址 CPU Interface Control Register */ ldr r0, [r1, #0xc] /** get GIC--IAR 此时r1保存了GIC基地址,r0(IAR、EOIR)也基于GIC基地址,由于不想变,所以这里将r0,r1入站*/ /**根据 CPU 接口基址 找到IAR */ stmfd sp!, {r0,r1} cps #0x1f /* change to system mode */ stmfd sp!, {r0-r12, lr} bl system_irq_handler/*deal irq 调用c语言中断处理函数 */ stmfd sp!, {r0-r12, pc} cps #0x12 /*change to irq mode */ ldmfd sp!, {r0, r1} str r0, [r1, #0x10] /**set GIC--EOIR r0是IAR中的中断号 将中断号写入GIC的EOIR寄存器(偏移0x10* 将 r0 中的值(即之前从 IAR 读取的中断号)写入 EOIR 寄存器。/ /* get GIC--IAR deal irq set GIC--EOIR */ ldmfd sp!, {r0-r12, pc}^

此时因为系统进入IRQ模式,LR的地址会变成下一条指令的地址,所以需要先将LR寄存器-4,再保存现场(压栈),然后读取协处理器的CBAR,其中存放了GIC的基地址,得到GIC基地址后可以通过偏移量得到CPU接口CTLR的地址,将GIC机制重定向后,CTLR为CPU控制接口,CPU可以IAR访问中断号,完成中断后向EOIR写入中断号。由于r0,r1此时存放了IAR地址和GIC地址,如果要跳到系统模式去调用会修改两个寄存器的值,所以这里入栈能让寄存器的值不变。

#include "MCIMX6Y2.h" #include "fsl_iomuxc.h" #include "core_ca7.h" #include "key.h" void key_init(void) { IOMUXC_SetPinMux(IOMUXC_UART1_CTS_B_GPIO1_IO18, 0); IOMUXC_SetPinConfig(IOMUXC_UART1_CTS_B_GPIO1_IO18, 0x10b0); GPIO1->GDIR &= ~(1 << 18); } int get_key_status(void)//判断引脚的状态 { if (GPIO1->DR & (1 << 18)) return 0; else return 1; } void key_irq_init(void)//初始化按键触发的中断 { IOMUXC_SetPinMux(IOMUXC_UART1_CTS_B_GPIO1_IO18, 0); IOMUXC_SetPinConfig(IOMUXC_UART1_CTS_B_GPIO1_IO18, 0x10b0); GPIO1->GDIR &= ~(1 << 18); //配置为输入 GPIO1->ICR2 |= (0x3 << 4); //配置为下降沿触发中断 GPIO1->IMR |= (1 << 18); GIC_EnableIRQ(GPIO1_Combined_16_31_IRQn); //使能 GIC 中的对应中断 允许 GIC 将该中断转发给 CPU GIC_SetPriority(GPIO1_Combined_16_31_IRQn, 0);//设置中断优先级 }

对案件Key0进行初始化和中断请求初始化,设置方向为输,设置中断触发方式为下降沿触发,设置掩码,使能对应的中断号,即允许GIC将该中断转发给cpu,设置中断优先级。

由于得到中断号后需要跳入main.c中的system_irq_handler进行中断服务,所以这里切换为系统模式,并保护现场。

system_irq_handler中对GPIO1_ISR写入1后表示中断服务结束,服务完成后继续执行汇编代码,此时由于需要设置GIC的EOIR寄存器表示中断结束,所以需要切回中断模式(IRQ),由于之前保存了r0进行了入栈,r0中存储了IAR的值,其值不变,所以此时将IAR的值即中断结束的中断号写入EOIR中。

void system_irq_handler(IRQn_Type irq_num):中断处理函数,检查中断类型和中断号,检查中断状态寄存器以得知是否是目标中断,如若是,这处理中断。处理完中断后要将中断状态寄存器GPIO1_ISR的相应位置写1,表示中断服务结束。

注意:ISR无论是都使能,只要中断产生都会被置位,知道软件写入1结束。

http://www.jsqmd.com/news/543838/

相关文章:

  • 【CVPR 2025】HVI低光增强网络架构解析:从颜色空间到交叉注意力机制
  • 联想M920x黑苹果配置指南:从硬件适配到性能优化的完整方案
  • MBPFan:解决MacBook Linux系统散热难题的智能温控工具
  • 稀疏卷积在医学图像分析中的5个实战技巧(附MinkowskiEngine代码)
  • Linux系统性能监控:确保FRCRN语音降噪服务稳定运行
  • 基于三菱PLC和MCGS组态农田智能灌溉系统 我们主要的后发送的产品有,带解释的梯形图接线图原...
  • 在 SAP 中,应收票据的收取、到期承兑、贴现均有标准操作路径与事务码,以下按业务场景给出操作步骤、T-code、会计分录(含附 / 不附追索权)
  • 保姆级教程:用Cloudreve+Obsidian打造私人云笔记(附WebDAV配置避坑指南)
  • 别再乱传参数了!手把手教你调试uniapp抖音小程序的getPhoneNumber接口
  • HoRain云--CMake高级特性完全指南
  • HunyuanVideo-Foley惊艳效果展示:城市街道环境音效+动态视频同步生成作品集
  • 麒麟系统桌面右下角时间卡顿?别急着重启,先查查mate-indicators这个‘内存刺客’
  • 手把手教你用TwinCAT3和Matlab 2019b配置松下A6伺服(EtherCAT通讯避坑指南)
  • OpenClaw+GLM-4.7-Flash内容创作:自动生成技术文档与博客
  • VScode Verilog辅助开发插件 VScode SystemVerilog辅助开发插件
  • 5步掌握Meshroom革新性3D重建技术:从图像到模型的全流程指南
  • Ubuntu 20.04 Auditd实战:如何优雅地解析用户命令日志(附ausearch技巧)
  • PyTorch 3.0静态图分布式训练全链路剖析:从FX Graph捕获、Dynamo后端注册到自定义DeviceMesh编译优化的6层技术栈解密
  • NumPy:数组元素修改
  • 内网明明通了,外网却“一顿一顿”?手撕动态NAT,真相让人恍然大悟
  • Wan2.2-I2V-A14B惊艳案例:‘量子波动撕裂时空’科幻感特效视频生成
  • 告别论文熬夜焦虑:Paperxie AI 毕业论文写作,让初稿生成不再是噩梦
  • 解放双手!部署这套AI数字员工源码系统,让AI替你写代码、回邮件、做报表
  • 【带AI】基于SpringBoot+Vue3的仓库库存管理系统设计与实现+万字文档+指导搭建视频
  • OpCore-Simplify:零代码3步完成黑苹果EFI配置的终极指南
  • BiliTools哔哩哔哩工具箱完整指南:5个实用技巧高效下载B站资源
  • Pixel Dimension Fissioner 实时生成挑战与优化:WebSocket流式传输方案
  • OpenClaw低配优化:在4GB内存运行Qwen3.5-4B-Claude
  • 【辅助工具】文心快码PyCharm插件全解析:从安装配置到高效开发的万字实战指南
  • 如何让LLM输出指定字段的数据类型