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

嵌入式学习的第四十八天-中断+OCP原则

一、GIC通用中断控制器

1.GIC通用中断控制器

        GIC 是 ARM 公司给 Cortex-A/R 内核提供的一个中断控制器,GIC接收众多外部中断,然后对其进行处理,最终通过VFIQ、VIRQ、FIQ 和 IRQ给内核;这四个 信号的含义如下: VFIQ:虚拟快速 FIQ。 VIRQ:虚拟 IRQ。 FIQ:快速中断 IRQ。 IRQ:中断 IRQ。

2.GIC中断分类

SPI(Shared Peripheral Interrupt),共享中断, (注意!不是 SPI 总线那个中断),这类中断泛指所有的 外设中断;
PPI(Private Peripheral Interrupt),私有中断,我们说了 GIC 是支持多核的,每个核肯定有自己独有 的中断。这些独有的中断肯定是要指定的核心处理,因此这些中断就叫做私有中断;
SGI(Software-generated Interrupt),软件中断,由软件触发引起的中断,通过向寄存器GICD_SGIR 写入数据来触发,系统会使用 SGI 中断来完成多核之间的通信。

 从图中可以明显看出,Distributor(分发器)可以分发所有共享中断给8个内核,但是私有中断和 软件中断只出现自己独自的内核中。

中断ID:中断源有很多,为了区分这些不同的中断源肯定要给他们分配一个唯一 ID,这些 ID 就 是中断 ID。每一个 CPU 最多支持 1020 个中断 ID,中断 ID 号为 ID0~ID1019。

ID0~ID15:这 16 个 ID 分配给 SGI; ID16~ID31:这 16 个 ID 分配给 PPI;ID32~ID1019:
这 988 个 ID 分配给 SPI。

3.GIC的组成

   由分发器 (1个)、CPU接口(几核就几个)

(1)分发器

功能:

  • 全局中断使能控制;
  • 控制每一个中断的使能或者关闭;
  • 设置每个中断的优先级;
  • 设置每个中断的目标处理器列表;
  • 设置每个外部中断的触发模式:电平触发或边沿触发;
  • 设置每个中 断属于组 0 还是组 1;
(2)CPU接口

功能:

  • 使能或者关闭发送到 CPU Core 的中断请求信号;
  • 应答中断;
  • 通知中断处理完成;
  • 设置优先级掩码,通过掩码来设 置哪些中断不需要上报给 CPU Core;
  • 定义抢占策略;
  • 当多个中断到来的时候,选择优先级最高的 中断通知给 CPU Core;

4.协处理器

总共由16个,cp0~cp15;其中最常使用的cp15

(1)作用

  • 获取GIC的基地址(CBAR)
  • MMU的配置(使能/禁用;SCTLR)
  • cache的配置
  • 监控系统性能
  • 配置中断控制器(优先级、分组、使能/禁用,VBAR:设置中断向量表基地址)
  • 访问寄存器(mrc读、mcr写)
  • 获取或结束中断(IAR、EOIR)

(2)读写访问指令

MRC: 将 CP15 协处理器中的寄存器 数据读到 ARM 寄存器中;
MCR: 将 ARM 寄存器的数据写入到 CP15 协处理器寄存器中。
以MRC指令
为例,从CP15的某个寄存器读取数据到ARM寄存器的指令格式为:
MRC{cond} p15, <opc1>, <Rt>, <CRn>, <CRm>, <opc2>
cond:指令执行的条件码,就是之前我们使用过的指令条件,eq,lt什么的。如果忽略的话就表示无条件执行;
p15:表示要读取的是CP15当中的某个寄存器;
opc1:协处理器要执行的操作码1,其实就是一个数,要做什么将来查表;
Rt:ARM 目标寄存器,读出来的数据放到哪个ARM寄存器里。CP15
CRn:CP15 协处理器的目标寄存器,就是你要读取CP15的哪个寄存器(C0~C15);
CRm:协处理器中附加的目标寄存器或者源操作数寄存器,如果不需要附加信息就将CRm 设置 为 C0,否则结果不可预测。
opc2:可选的协处理器特定操作码2,使用时查表。
MCR与MRC类似的,只是Rt的作用变成了要写入CP15某个寄存器的值。

 mrc p15 0, r0, c0, c0, 0

         简单总结一下,通过 MIDR 寄存器可以获取到处理器内核信息;通过 SCTLR 寄存器可以使能或禁止 MMU、I/D Cache 等;通过 VBAR 寄存器可以设置中断向量偏移;通过CBAR 寄存器可以获取 GIC 基地址。

二、外部中断

1.设置GIC

(1)读取SCTLR,将V位置0(软件可以通过 VBAR来重新映射这个基地址)I位置1(I cache使能)

(2)通过GIC查询当前中断ID;先获取GIC基地址(CBAR);对其进行偏移(IAR),获得中断ID,然后进入中断处理函数

2.中断服务函数       

(1)中断初始化;重新定位异常向量表的位置到0x87800000;并且调用GIC_Init函数

(2)对于GPIO1->ICR2(触发方式)、GPIO1->IMR(该中断使能)在中断源初始化进行配置


(3)中断服务函数
  
注意:先要在相对应的中断源的初始化函数里面注册在中断向量数组中;

例子:注册完中断之后,中断发生就会调用中断服务函数

内敛函数:INLINE,定义被放在头文件中

三、OCP原则(开闭原则)  

对代码扩展是开放的,对代码的修改是关闭的。

四、启动代码

.global _start
//异常向量表
//位于内存起始位置,当特定异常发生时,处理器会自动跳转到对应的地址上
_start:ldr pc, = _reset_handlerldr pc, = _undefined_handlerldr pc, = _svc_handlerldr pc, = _prefetch_handlerldr pc, = _data_abort_handlerldr pc, = _not_user_handlerldr pc, = _irq_handlerldr pc, = _fiq_handler
//异常处理程序 大多是简单的无限循环
_undefined_handler:ldr pc, = _undefined_handler
_svc_handler:ldr pc, = _svc_handler
_prefetch_handler:ldr pc, = _prefetch_handler
_data_abort_handler:ldr pc, = _data_abort_handler
_not_user_handler:ldr pc, = _not_user_handler
_fiq_handler:ldr pc, = _fiq_handler//IRQ中断处理程序_irq_handler:subs lr,lr,#4           //调整返回地址stmfd sp!,{r0-r12,lr}   //保存寄存器//读取中断控制器状态mrc p15,4,r1,c15,c0,0   //获取外设基地址add r1,r1,#0x2000       //偏移到中断控制器ldr r0,[r1,#0x0C]       //读取中断状态stmfd sp!,{r0,r1}       //保存临时寄存器//切换到系统模式处理中断cps #0x1F               //切换到系统模式stmfd sp!,{lr}          //保存系统模式LRbl system_interrupt_handler //调用C中断处理函数ldmfd sp!,{lr}          //恢复LR模式cps #0x12               //切换回IRQ模式//清除中断ldmfd sp!,{r0,r1}       //恢复临时寄存器str r0,[r1,#0x10]       //写EQIR寄存器ldmfd sp!,{r0-r12,pc}^  //恢复寄存器并返回//启动代码执行程序
_reset_handler:cpsid i                 //禁用中断//配置CP15系统控制寄存器mrc p15,0,r0,c1,c0,0    //读取控制寄存器bic r0,r0,#(1<<13)      //清除V位(异常向量表位置)orr r0,r0,#(1<<12)      //设置I位(启用指令缓存)mcr p15,0,r0,c1,c0,0    //写回控制寄存器// 设置IRQ模式栈指针cps #0x12               // 切换到IRQ模式ldr sp, =0x82000000     // 设置IRQ栈cps #0x1F               // 切换到系统模式ldr sp, =0x84000000     // 设置系统栈cpsie i                 // 启用中断bl _init_bss            // 初始化BSS段b main                  // 跳转到主程序b finished              // 永远不会执行(冗余)
//初始化BSS段(清零)
_init_bss:ldr r0,= __bss_start    // BSS段起始地址ldr r1,= __bss_end      // BSS段结束地址
loop:mov r2,#0               // 清零值str r2,[r0]             // 存储0到当前地址add r0,r0,#4            // 移动到下一个字cmp r0,r1               // 比较是否到达结束blt  loop               // 如果未结束则循环bx lrfinished:b finished    

http://www.dtcms.com/a/326584.html

相关文章:

  • Photoshop图层混合模式:实现图像元素透明度渐变过渡的终极指南
  • Effective C++ 条款36: 绝不重新定义继承而来的非虚函数
  • 数据结构:树与二叉树
  • ARM基础概念 day51
  • easyExcel嵌套子集合导出Excel
  • 2025第十六届蓝桥杯大赛青少组省赛C++真题(初级组和中级组)
  • MCU的设计原理
  • SNMP入门教程:Windows下编译
  • Linux811 YUM;SHELL:if else fi,for
  • 进程线程切换的区别
  • 【k近邻】 K-Nearest Neighbors算法k值的选择
  • 第4节 大模型推理内存与计算优化
  • 【FreeRTOS】任务间通讯6: 任务通知- Task Notification
  • python+requests+yaml实现接口自动化用例
  • 【软件分享】格式工厂FormatFactory便携版本(解压即用)
  • 介绍一下jQuery的AJAX异步请求
  • Salesforce案例:零售企业会员积分体系
  • 新人如何简化学习Vue3文件
  • LangChain框架之 invoke() 方法
  • 【每日一错】PDB之间数据迁移
  • 7.Java的继承
  • 分享一款基于STC8H8K32U-45I-LQFP48单片机的4路数字量输入输出模块
  • 多重时间聚合算法(MAPA)改进需求预测模型
  • Redis实现排行榜
  • C++11 auto关键字:智能类型推导指南
  • 字符串相关例题(查询子串在主串中的个数)
  • GB17761-2024标准与电动自行车防火安全的技术革新
  • 编译GCC-12.1.0
  • Linux内核网络设备框架及其注册流程分析
  • Cursor 实用技巧与常见难题解析:从入门到进阶的技术实践