lv11 嵌入式开发 中断处理 15

前言:中断属于7种异常的1种,这节主要讲CPU接收到中断之后怎么处理,回顾之前的知识。

目录

1 异常

1.1 概念

1.2 异常处理机制 

1.3 ARM异常源

1.4 异常模式 

1.5 ARM异常响应

1.6 异常向量表

1.7 异常返回

​编辑 1.8 IRQ异常举例

2 中断处理框架搭建 

2.1 代码框架介绍

2.2 当中断信号来,ARM如何处理

2.2.1 以BL为例说明LR如何保存下一条指令的地址。

2.2.2 IRQ异常LR寄存器说明如何保存下一条地址指令。 

2.3 编写IRQ异常处理程序

3 补充


1 异常

1.1 概念

处理器在正常执行程序的过程中可能会遇到一些不正常的事件发生    

这时处理器就要将当前的程序暂停下来转而去处理这个异常的事件    

异常事件处理完成之后再返回到被异常打断的点继续执行程序

1.2 异常处理机制 

不同的处理器对异常的处理的流程大体相似,但是不同的处理器在具体实现的机制上有所不同;比如处理器遇到哪些事件认为是异常事件遇到异常事件之后处理器有哪些动作、处理器如何跳转到异常处理程序如何处理异常、处理完异常之后又如何返回到被打断的程序继续执行等我们将这些细节的实现称为处理器的异常处理机制

1.3 ARM异常源

导致异常产生的事件称为异常源

FIQ、IRQ作为外部中断,驱动IRQ用得较多,FIQ速度较快。

1.4 异常模式 

在ARM的基本工作模式中有5个属于异常模式,即ARM遇到异常后会切换成对应的异常模式

1.5 ARM异常响应

2.1中相应的中断的意思:高优先级的可以打断低优先级的,但是平级中断不能被打断

真正处理跳转在第4点,自动修改成了向量表对应的地址。 

1.6 异常向量表

 ARM的异常向量表的基地址默认在0x00地址,但可以通过配置协处理器来修改其地址,如基址修改为0x40000000,那么IRQ的地址对应0x40000018

1.7 异常返回

ARM异常返回的动作(自己编写)

 1.8 IRQ异常举例

2 中断处理框架搭建 

2.1 代码框架介绍

common中写得是头文件和源文件,包含.c和.s的可以调用,如exynos_4412.h是寄存器的封装

start中放得是启动代码start.s,启动的汇编代码

makefile用于编译规则

map.lds链接脚本,用于生成文件的排版和格式

最终编译所有.c、.s等组成了一个.bin的文件。所有.c .s的源文件的内容的排版由map.lds决定。

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{. = 0x40008000;. = ALIGN(4);.text      :{start/start.o(.text)*(.text)}. = ALIGN(4);.rodata : { *(.rodata) }. = ALIGN(4);.data : { *(.data) }. = ALIGN(4);.bss :{ *(.bss) }
}

协处理器cp15中有个寄存器c12,往里面写什么地址,异常向量表就在什么地址

r0已经存了start的地址,把r0给c12,当arm遇到异常时就会跳转到异常向量表

目前没有写跳转指令 b.代表跳转到自身,占用了32个字节。

详细内容参考往期内容:

lv11 嵌入式开发 C工程与寄存器封装 10-CSDN博客

2.2 当中断信号来,ARM如何处理

 回顾:

 ARM寄存器

注:在某个特定模式下只能使用当前模式下的寄存器,一个模式下特有的寄存器其他模式下不可使用 

LR寄存器两种用途:

2.2.1 以BL为例说明LR如何保存下一条指令的地址。

当正在执行BL ADDR指令的时候,BL指令的下一条指令正在译码(三级流水线)BL指令的下下条正在取址。PC寄存器指向的永远是在取址的指令,CPU会执行BL的时候,会把PC的值减4的地址拷贝到LR

2.2.2 IRQ异常LR寄存器说明如何保存下一条地址指令。 

2.3 编写IRQ异常处理程序

start.s

处理函数中做了几件事:

  • 修正LR返回地址
  • 压栈保护现场
  • 跳转异常处理程序
  • 恢复现场

处理跳转异常处理程序,只能使用汇编编写,因为C语言没有压栈出栈的操作函数

.text
.global _start
_start:/** Vector table*/ b resetb .b .b .b .b ./** 从异常向量表再跳转到IRQ的异常处理程序*/b irq_handlerb .reset:/** Set vector address in CP15 VBAR register*/ ldr	r0, =_startmcr	p15, 0, r0, c12, c0, 0	@Set VBAR/** Set the cpu to SVC32 mode, Disable FIQ/IRQ*/  mrs r0, cpsrbic r0, r0, #0x1forr	r0, r0, #0xd3msr	cpsr ,r0/** Defines access permissions for each coprocessor*/  mov	r0, #0xfffffffmcr	p15, 0, r0, c1, c0, 2  	/** Invalidate L1 I/D                                                                                                                   */mov	r0, #0					@Set up for MCRmcr	p15, 0, r0, c8, c7, 0	@Invalidate TLBsmcr	p15, 0, r0, c7, c5, 0	@Invalidate icache/** Set the FPEXC EN bit to enable the FPU*/ mov r3, #0x40000000fmxr FPEXC, r3/** Disable MMU stuff and caches*/mrc	p15, 0, r0, c1, c0, 0bic	r0, r0, #0x00002000		@Clear bits 13 (--V-)bic	r0, r0, #0x00000007		@Clear bits 2:0 (-CAM)orr	r0, r0, #0x00001000		@Set bit 12 (---I) Icacheorr	r0, r0, #0x00000002		@Set bit 1 (--A-) Alignorr	r0, r0, #0x00000800		@Set bit 11 (Z---) BTBmcr	p15, 0, r0, c1, c0, 0/** Initialize stacks                                                                                                                  */
init_stack:     /*svc mode stack*/msr cpsr, #0xd3ldr sp, _stack_svc_end/*undef mode stack*/msr cpsr, #0xdbldr sp, _stack_und_end/*abort mode stack*/	msr cpsr,#0xd7ldr sp,_stack_abt_end/*irq mode stack*/	msr cpsr,#0xd2ldr sp, _stack_irq_end/*fiq mode stack*/msr cpsr,#0xd1ldr sp, _stack_fiq_end/*user mode stack, enable FIQ/IRQ*/msr cpsr,#0x10ldr sp, _stack_usr_end/*Call main*/b main/** IRQ的异常处理程序,需要写在main函数之后,否则就执行了。*/
irq_handler:/** 因为产生IRQ异常后ARM自动保存到LR中的返回地址是被IRQ打断的指令* 的下一条再下一条指令的地址,所以我们需要人为的去修正一下*/sub lr, lr, #4/** 因为IRQ模式下使用的R0-R12寄存器和USER模式下使用的是同一组* 所以在处理异常之前需要先将之前寄存器中的值压栈保护*/stmfd sp!, {r0-r12,lr}/** 跳转到do_irq处理异常*/bl do_irq/** 异常返回* 1.将R0-R12寄存器中的值出栈,使其恢复到被异常打断之前的值* 2.将SPSR寄存器中的值恢复到CPSR,使CPU的状态恢复到被异常打断之前* 3.将栈中保存的LR寄存器的值出栈给PC,使程序跳转回被异常打断的点继续执行*/ldmfd sp!,{r0-r12,pc}^_stack_svc_end:      .word stack_svc + 512
_stack_und_end:      .word stack_und + 512
_stack_abt_end:      .word stack_abt + 512
_stack_irq_end:      .word stack_irq + 512
_stack_fiq_end:.word stack_fiq + 512
_stack_usr_end:      .word stack_usr + 512.data
stack_svc:      .space 512
stack_und:.space 512
stack_abt:      .space 512
stack_irq:      .space 512
stack_fiq:      .space 512
stack_usr:      .space 512

编写do_irq

 获取中断号

诉中断控制器,当前中断已经处理完成,可以发送其他中断

#include "exynos_4412.h"void Delay(unsigned int Time)
{while(Time--);
}//IRQ异常处理
void do_irq(void)
{unsigned int IrqNum = 0;/*从中断控制器中获取当前中断的中断号,只需要10位*/IrqNum = CPU0.ICCIAR & 0x3FF;/*根据中断号处理不同的中断*/switch(IrqNum){case 0://0号中断的处理程序break;case 1://1号中断的处理程序break;/** ... ...*/case 57:printf("Key2 Pressed\n");/*清除GPIO控制器中GPX1_1的中断挂起标志位,不清楚结束会跳转到main3然后再持续执行上面的中断处理函数*/EXT_INT41_PEND = (1 << 1);/*将当前中断的中断号写回到中断控制器中,以这种方式来告知中断控制器当前的中断已经处理完成,可以发送其它中断*/CPU0.ICCEOIR = CPU0.ICCEOIR & (~(0x3FF)) | (57);break;/** ... ...*/case 159://159号中断的处理程序break;default:break;}}int main()
{/*外设层次 - 让外部的硬件控制器产生一个中断信号发送给中断控制器*//*将GPX1_1设置成中断功能*/GPX1.CON = GPX1.CON | (0xF << 4);/*设置GPX1_1的中断触发方式为下降沿触发*/EXT_INT41_CON = EXT_INT41_CON & (~(0x7 << 4)) | (0x2 << 4);/*使能GPX1_1的中断功能*/EXT_INT41_MASK = EXT_INT41_MASK & (~(1 << 1));/*中断控制器层次 - 让中断控制器接收外设产生的中断信号并对其进行管理然后再转发给CPU处理*//*全局使能中断控制器使其能接收外设产生的中断信号并转发到CPU接口*/ICDDCR = ICDDCR | 1;/*在中断控制器中使能57号中断,使中断控制器接收到57号中断后能将其转发到CPU接口*/ICDISER.ICDISER1 = ICDISER.ICDISER1 | (1 << 25);/*选择由CPU0来处理57号中断*/ICDIPTR.ICDIPTR14 = ICDIPTR.ICDIPTR14 & (~(0xFF << 8)) | (0X01 << 8);/*使能中断控制器和CPU0之间的接口,使中断控制器转发的中断信号能够到达CPU0*/CPU0.ICCICR = CPU0.ICCICR | 1;GPX2.CON = GPX2.CON & (~(0xF << 28)) | (0x1 << 28);while(1){   /*点亮LED2*/GPX2.DAT = GPX2.DAT | (1 << 7); /*延时*/Delay(1000000);/*熄灭LED2*/GPX2.DAT = GPX2.DAT & (~(1 << 7));/*延时*/Delay(1000000);}   return 0;
}

注:清除GPIO控制器中GPX1_1的中断挂起标志位,不清楚会持续发送给CPU。写1清零。

正在开发的时候linux或者其他操作系统会帮我们写好,重点理解中断和轮询处理流程。

3 补充

frq速度快的原因:

  • 优先级高
  • 异常向量表最后一位,可以不写跳转指令,直接接着写处理函数
  • frq模式下r8-r12是私有的,如果用了r8-r12可以不用压栈,但如果用了r0-r7寄存器,那么还是需要压栈的。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/191394.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

scrapyd及gerapy的使用及docker-compse部署

一、scrapyd的介绍 scrapyd是一个用于部署和运行scrapy爬虫的程序&#xff0c;它允许你通过JSON API(也即是web api)来部署爬虫项目和控制爬虫运行&#xff0c;scrapyd是一个守护进程&#xff0c;监听爬虫的运行和请求&#xff0c;然后启动进程来执行它们 scrapyd的安装 scr…

从“芯”到云,看亚马逊云科技如何让未来“平等”发生

文章目录 业界最全面算力选择&#xff0c;有效解决多样性需求多年自研芯片积累&#xff0c;带来性能与性价比双重优势全球基础设施与独特的业务模式&#xff0c;让创新不受限 “科幻作家威廉吉布森说‘未来已至&#xff0c;只是还没有均匀分布’。”2023年6月底&#xff0c;当亚…

抖音短视频账号矩阵系统开发新规则

一、抖音官方平台开发新规&#xff1a; 1.代发布管理应用api接口无法在做新的应用申请 仅针对企事业单位开放&#xff0c;目前要想开发新的抖音矩阵系统&#xff0c;就需要在原有的技术算法上进行新一步的调整。 能力介绍 网站应用开发者可以申请开通【代替用户发布内容到抖…

Unity Meta Quest 一体机开发(八):【手势追踪】实现 Hand Grab 扔物体功能

文章目录 &#x1f4d5;教程说明&#x1f4d5;设置刚体和碰撞体&#x1f4d5;给物体添加 Physics Grabbable 脚本&#x1f4d5;给手部添加 Hand Velocity Calculator 物体 此教程相关的详细教案&#xff0c;文档&#xff0c;思维导图和工程文件会放入 Seed XR 社区。这是一个高…

【实战教程】PHP如何轻松对接腾讯云COS,实现文件上传下载?

腾讯云提供了一系列丰富的云服务&#xff0c;其中包括对象存储&#xff08;Cloud Object Storage&#xff0c;简称COS&#xff09;&#xff0c;它是一种高可靠性、可扩展性强的云存储服务。本文将介绍如何使用PHP对接腾讯云COS存储服务&#xff0c;实现文件的上传和下载功能。 …

【Unity入门】声音组件AudioSource简介及实现声音的近大远小

AudioSource组件 将需要播放声音的物体挂载Audio Listener组件&#xff0c;实现声音的播放 AudioSource组件属性 &#xff08;1&#xff09;AudioClip&#xff08;音频剪辑&#xff09;&#xff1a;指定播放的音频文件。 &#xff08;2&#xff09;Output&#xff08;音频输…

hbase Master is initializing

问题如下&#xff1a; ERROR: org.apache.hadoop.hbase.PleaseHoldException: Master is initializing ERROR: org.apache.hadoop.hbase.PleaseHoldException: Master is initializingat org.apache.hadoop.hbase.master.HMaster.checkInitialized(HMaster.java:2452)at org.…

栈实现队列,力扣

题目地址&#xff1a; 232. 用栈实现队列 - 力扣&#xff08;LeetCode&#xff09; 难度&#xff1a;简单 今天刷栈实现队列&#xff0c;大家有兴趣可以点上看看题目要求&#xff0c;试着做一下。 题目&#xff1a; 请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支…

一篇带你串通数据结构

文章目录 导论数据结构的定义数据结构在计算机科学中的重要性为什么学习数据结构很重要 1、基本概念1.1、数据、数据元素和数据项的概念1.2、数据对象与数据结构的关系1.3、逻辑结构与物理结构 2、线性结构2.1、数组2.2、链表2.3、栈2.4、队列 3、非线性结构3.1、树3.2、图 4、…

prometheus|云原生|kubernetes内部安装prometheus

架构说明&#xff1a; prometheus是云原生系统内的事实上的监控标准&#xff0c;而kubernetes集群内部自然还是需要就地取材的部署prometheus服务了 那么&#xff0c;prometheus-server部署的方式其实是非常多的&#xff0c;比如&#xff0c;kubesphere集成方式&#xff0c;h…

Linux ____04、文件内容查看(命令),网络配置(命令),软硬链接(命令)

文件内容查看&#xff0c;软硬链接 一、文件内容查看1、cat 由第一行开始显示文件内容&#xff0c;用来读文章&#xff0c;或者读取配置文件啊&#xff0c;都使用cat名2、tac 从最后一行开始显示&#xff0c;可以看出 tac 是 cat 的倒着写&#xff01;3、显示的时候&#xff0c…

CGAL的三维曲面网格生成

1、介绍 此程序包提供了一个函数模板&#xff0c;用于计算三角网格&#xff0c;以近似表面。 网格化算法要求仅通过一个能够判断给定线段、直线或射线是否与曲面相交&#xff0c;并且如果相交则计算交点的oracle来了解待网格化的表面。这一特性使该软件包具有足够的通用性&…

子集(回溯、图解)

78. 子集 - 力扣&#xff08;LeetCode&#xff09; 题目描述 给你一个整数数组 nums &#xff0c;数组中的元素 互不相同 。返回该数组所有可能的子集&#xff08;幂集&#xff09;。 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 样例输入 示例 1&#xff1a;…

深入理解同源限制:网络安全的守护者(下)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

VMware安装Debian12.2作为服务器(无桌面)

[TOC]VMware安装Debian12.2作为服务器&#xff08;无桌面&#xff09; 下载Debian系统 官方网站&#xff1a;https://www.debian.org/index.zh-cn.html 创建新的虚拟机 打开VMware Workstation&#xff0c;点击创建新的虚拟机 向导虚拟机类型选择 一般我会选择典型&…

C#网络编程(System.Net命名空间和System.Net.Sockets命名空间)

目录 一、System.Net命名空间 1.Dns类 &#xff08;1&#xff09;示例源码 &#xff08;2&#xff09;生成效果 2.IPAddress类 &#xff08;1&#xff09;示例源码 &#xff08;2&#xff09;生成效果 3.IPEndPoint类 &#xff08;1&#xff09; 示例源码 &#xff0…

Unity Image - 镜像

1、为什么要使用镜像 在游戏开发过程中&#xff0c;我们经常会为了节省 美术图片资源大小&#xff0c;美术会将两边相同的图片进行切一半来处理。如下所示一个按钮 需要 400 * 236&#xff0c;然而美术只需要切一张 74*236的大小就可以了。这样一来图集就可以容纳更多的图片。…

基于spring boot电子商务系统

一、 系统总体结构设计 (一) 功能结构图 图1-1 后台管理子系统 图1-2 电子商务子系统功能结构图 (二) 项目结构目录截图&#xff08;例如下图&#xff09; 图 1-3 系统目录图 (三) 系统依赖截图 图 1-2 所有依赖截图 (四) 配置文件 1、 全局配置文件 2、 其他配置文…

Leetcode226. 翻转二叉树

文章目录 题目介绍题目分析解题思路边界条件&#xff1a;节点为空时返回空子问题&#xff1a;交换左右子节点 整体代码 题目介绍 题目分析 题目要求我们将树中每个节点的左右子节点全部交换,最后返回交换后的树的根节点。 解题思路 这题是比较常见的递归&#xff0c;直接找边…

Simple_SSTI_1-WEB-bugku-解题步骤

——CTF解题专栏—— 声明&#xff1a;文章由作者weoptions学习或练习过程中的步骤及思路&#xff0c;非正式答案&#xff0c;仅供学习和参考。 题目信息&#xff1a; 题目&#xff1a;Simple_SSTI_1 作者&#xff1a;valecalida 提示&#xff1a;无 场景&#xff1a; 解题…