中断——S5PV210的中断案例

以下内容源于朱有鹏嵌入式课程的学习与整理,如有侵权请告知删除。

参考博客

s5pv210——中断 - biaohc - 博客园

S5PV210的中断体系简介_天糊土的博客-CSDN博客

一、S5PV210的中断流程

第一部分是我们为中断响应而做的预备工作。

1、初始化中断控制器

比如先关闭所有中断,然后设置中断方式为IRQ,接着把保存有中断服务程序ISR地址的寄存器的内容置为0(方便下次装入ISR地址)。

2、将isr绑定到中断控制器

也就是把中断服务程序ISR的地址,放入这个中断对应的寄存器中。如何对应呢?每个中断都对应着一个中断号,比如S5PV210的按键简介讲述的,按键sw5、sw6对应着的中断号为2、3,也就是说,如果我想使用中断方式来处理按键sw5、sw6,我通过查原理图可以知道这两个按键对应的中断号。然后通过判断这个中断号的大小,来确定这个中断号对应哪个寄存器,然后再把这个中断的中断服务程序的地址写进这个中断对应的寄存器中。

3、相应中断的所有条件使能

也就是把表示中断是否开启的寄存器的相关的位置1。


第二部分是当硬件产生中断后如何自动执行isr。

1、自动根据异常向量表跳转到IRQ处理入口IRQ_handle

发生中断的时候,硬件自动跳到IRQ的处理入口IRQ_handle。这个IRQ_handle是某个汇编文件里的标号,是自己随意取的名字。之所以使用汇编语言编写这个文件,是因为要完成栈的设置、现场保存等工作。

2、在IRQ_handle里完成一些设置后,跳转到真正的中断服务程序ISR

在这个汇编文件的IRQ_handle这个标号下,需要完成栈的设置、现场保存、跳转到真正的中断服务程序isr、处理完中断后返回并恢复现场等工作。注意,这个IRQ_handle不是真正的中断服务程序,而是在IRQ_handle中设置好栈、保存好好现场之后,才跳转到真正的中断服务程序isr中。

3、中断服务程序isr完成相关内容

在中断服务程序中,先判断哪个VICnIRQSTATUS不为1,不为1则表示发生了中断,然后直接去这个VICnIRQSTATUS对应的VICnADDRESS寄存器中,取出isr的地址然后执行。

4、 中断现场恢复

中断服务程序isr完成后,返回继续做常规任务。


流程如下图:

二、代码

1、构建异常向量表

/**  异常向量表初始化*/#define VECTOR_TABLE_BASE			0xD0037400
#define Reset_offset				0x0
#define Undef_offset				0x4
#define SVC_offset					0x8
#define Prectch_offset				0xC
#define Data_Abort_offset			0x10
#define IRQ_offset					0x18
#define FIQ_offset					0x1C#define _PFUNC_Reset		(*(unsigned int*)(VECTOR_TABLE_BASE+Reset_offset))
#define _PFUNC_Undef		(*(unsigned int*)(VECTOR_TABLE_BASE+Undef_offset))
#define _PFUNC_SVC			(*(unsigned int*)(VECTOR_TABLE_BASE+SVC_offset))
#define _PFUNC_Prectch		(*(unsigned int*)(VECTOR_TABLE_BASE+Prectch_offset))
#define _PFUNC_Data_Abort	(*(unsigned int*)(VECTOR_TABLE_BASE+Data_Abort_offset))
#define _PFUNC_IRQ			(*(unsigned int*)(VECTOR_TABLE_BASE+IRQ_offset))
#define _PFUNC_FIQ			(*(unsigned int*)(VECTOR_TABLE_BASE+FIQ_offset))
extern void IRQ_handle(void);//因为我们只处理IRQ和FIQ这两种异常,所以其他异常的处理函数是空的函数体
void Reset_handle(void){}
void Undef_handle(void){}
void SVC_handle(void){}
void Prectch_handle(void){}
void Data_Abort_handle(void){}//构建异常向量表
void vector_table_init(void)
{	_PFUNC_Reset		=   (unsigned int)Reset_handle;_PFUNC_Undef		=   (unsigned int)Undef_handle;_PFUNC_SVC		    =   (unsigned int)SVC_handle;_PFUNC_Prectch		=     (unsigned int)Prectch_handle;_PFUNC_Data_Abort	=     (unsigned int)Data_Abort_handle;_PFUNC_IRQ	        =   (unsigned int)IRQ_handle;//假定FIQ、IRQ都是采用IRQ中断_PFUNC_FIQ	        =   (unsigned int)IRQ_handle;//因此但凡是中断,都会进入此函数}

其中,IRQ_handle函数要写在汇编IRQ_handle.S中,因为要设置栈以及保存现场 。

IRQ_handle.S文件内容如下:

#define IRQ_STACK        0xD0037F80 .global IRQ_handleIRQ_handle://设置IRQ的栈ldr sp, =IRQ_STACK//由于三级流水线的存在,pc为此时的程序语句+8,保存的时候要把下一句保存到lr中sub lr, lr, #4//保存现场stmd sp! {r0-r12, lr}//跳转到中断处理函数bl isr_handler//恢复现场ldmfd sp! {r0-r8, pc}^//这里为什么不是恢复r0~r12

ARM保存中断时为什么使用 sub lr, lr, #4?

(1)在arm执行过程中一般分为取指,译码,执行阶段;假设当前第一条指令在执行阶段,第二条指令在译码阶段,第三条指令在取指阶段;若当前正在执行的指令地址为pc-8,那第二条就为pc-4,第三条则为pc(它指向取址)。

(2)当发生中断时,pc指向第三条指令,而从中断返回肯定不是执行第三条指令,而是紧接着的第二条指令,所以 lr 应该保存的是 pc - 4。但是当执行到“sub lr,lr,#4”这个位置时,pc值又会发生改变,还好发生中断时会“mov lr,pc” ,所以这里可以直接使用“sub lr,lr,#4”,即 lr=pc-4。

2、中断控制器的初始化

//清除4个中断处理函数的地址
void clean_vicaddress(void)
{_REG_VIC0ADDRESS = 0x0;_REG_VIC1ADDRESS = 0x0;_REG_VIC2ADDRESS = 0x0;_REG_VIC3ADDRESS = 0x0;}//初始化中断
void interrupt_init(void)
{//第一步初始化中断之前要关闭所有中断_REG_VIC0INTENCLEAR = 0xFFFFFFFF;_REG_VIC1INTENCLEAR = 0xFFFFFFFF;_REG_VIC2INTENCLEAR = 0xFFFFFFFF;_REG_VIC3INTENCLEAR = 0xFFFFFFFF;//第三步:设置中断为IRQ中断_REG_VIC0INTSELECT = 0x0;_REG_VIC1INTSELECT = 0x0;_REG_VIC2INTSELECT = 0x0;_REG_VIC3INTSELECT = 0x0;//第三步:清中断处理函数地址clean_vicaddress();}//禁止某个中断
void int_disable(unsigned int num)
{if (num < 32) {_REG_VIC0INTENCLEAR = (0x1<<num);}else if (num < 64) {_REG_VIC1INTENCLEAR = (0x1<<(num-32));        }else if (num < 96) {_REG_VIC2INTENCLEAR = (0x1<<(num-64));}else if (num < 128) {_REG_VIC3INTENCLEAR = (0x1<<(num-96));}else {} 
}//使能某个中断 
void int_enable(unsigned int num)
{if (num < 32) {_REG_VIC0INTENABLE = (0x1<<num);}else if (num < 64) {_REG_VIC1INTENABLE = (0x1<<(num-32));        }else if (num < 96) {_REG_VIC2INTENABLE = (0x1<<(num-64));}else if (num < 128) {_REG_VIC3INTENABLE = (0x1<<(num-96));}else {_REG_VIC0INTENABLE = 0xFFFFFFFF;_REG_VIC1INTENABLE = 0xFFFFFFFF;_REG_VIC2INTENABLE = 0xFFFFFFFF;_REG_VIC3INTENABLE = 0xFFFFFFFF;}}
//先由中断编号得到对应的VICnVECTADDRm 寄存器
//然后将中断服务函数的地址放入对应的 VICnVECTADDRm 寄存器中
void creat_israddr(unsigned int num, void (*PIRQ_handler)(void))
{if (num < 32) {        //*( (void (*)(void))(VIC0VECTADDR + 4*num) )= PIRQ_handler;*( (volatile unsigned long *)(VIC0VECTADDR + 4*(num-0)) ) = (unsigned)PIRQ_handler;}else if (num < 64) {//(void (*)(void))(VIC1VECTADDR + 4*(num-32))= PIRQ_handler;*( (volatile unsigned long *)(VIC1VECTADDR + 4*(num-32)) ) = (unsigned)PIRQ_handler;}else if (num < 96) {//(void (*)(void))(VIC2VECTADDR + 4*(num-64))= PIRQ_handler;*( (volatile unsigned long *)(VIC2VECTADDR + 4*(num-64)) ) = (unsigned)PIRQ_handler;}else {//(void (*)(void))(VIC3VECTADDR + 4*(num-96))= PIRQ_handler;*( (volatile unsigned long *)(VIC3VECTADDR + 4*(num-96)) ) = (unsigned)PIRQ_handler;}   
}//判断中断在哪个address中
static int check_int_addr(void)
{if (_REG_VIC0IRQSTATUS) {return 0;}else if (_REG_VIC1IRQSTATUS) {return 1;}else if (_REG_VIC2IRQSTATUS) {return 2;}else if (_REG_VIC3IRQSTATUS) {return 3;}else {return -1;}
} //
void isr_handler(void)
{void (*p_isr)(void) = NULL;int i;i = check_int_addr();switch (i) {case 0 :p_isr = (void (*)(void))_REG_VIC0ADDRESS;break;case 1 :p_isr = (void (*)(void))_REG_VIC1ADDRESS;break;case 2 :p_isr = (void (*)(void))_REG_VIC2ADDRESS;break;case 3 :p_isr = (void (*)(void))_REG_VIC2ADDRESS;break;default :break;}p_isr();}

3、中断处理函数

//中断处理函数 
void int_led_blink(void)
{led_blink();//清楚外部中断挂起,注意写1清挂起clean_int_pend();//清vicaddressclean_vicaddress(); 
}

4、将中断号与中断服务程序isr绑定

#include "interrupt.h"
#include "stdio.h"
extern void led_blink(void);
extern void led1_on(void);
extern void vector_table_init(void);
extern void key_init(void);
extern void uart_init(void);int main(void)
{//按键初始化key_inter_init();//异常向量表初始化vector_table_init();//中断初始化interrupt_init();//将中断号与中断服务程序isr绑定creat_israddr(NUM_EINT2, int_led_blink);creat_israddr(NUM_EINT3, int_led_blink);creat_israddr(NUM_EINT16_31, int_led_blink);//使能中断int_enable(NUM_EINT2);int_enable(NUM_EINT3);int_enable(NUM_EINT16_31);while (1) {printf("a");}}

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

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

相关文章

按键——S5PV210的按键简介(轮询方式+中断方式)

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 参考博客 s5pv210——按键 - biaohc - 博客园 一、按键的简介 1、按键的物理特性 按钮没有被按下时&#xff0c;内部是断开的。按钮被按下时&#xff0c;内部保持接通状态&#xff1b;放手后由于弹…

HAproxy + Keepalive实现LDAP代理服务

HAproxy Keepalive实现LDAP代理服务因为公司的各种高自研发的系统非常多&#xff0c;这些系统又全部是在使用LDAP做认证&#xff0c;目前我们有几台DC控制器来分担这些ldap请求&#xff0c;用户通过访问ldap.xxxx.com这个域名来连接ldap服务器&#xff0c;我们通过DNS轮询的方…

中断——S5PV210的中断源

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 前言 s5pv210中因为支持的中断源很多&#xff0c;因此直接设计了4个中断寄存器&#xff0c;每个32位&#xff0c;每位对应一个中断源。理论上210最多支持128个中断&#xff0c;实际支持不足128个&a…

排序与查找

为什么80%的码农都做不了架构师&#xff1f;>>> sort.h #ifndef SORT_H_INCLUDED #define SORT_H_INCLUDEDvoid bubble_sort(int a[], int len);void select_sort(int a[], int len);#endif // SORT_H_INCLUDED sort.cpp #include "sort.h"void bubble_s…

LCD——S5PV210的LCD的理论与操作

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 参考博客 s5pv210 LCD编程原理 - biaohc - 博客园 一、关于LCD的简介 1、LCD简介 &#xff08;1&#xff09;什么是LCD LCD&#xff08;Liquid Crystal Display&#xff09;俗称液晶。液晶是一种材…

分析三星提供的sd_fusing文件夹(用来制作SD卡启动镜像)

以下内容源于网络资源的学习与整理&#xff0c;如有其侵权请告知删除。 参考博客 uboot分析&#xff1a;SD卡镜像制作脚本分析 - 走看看 如何烧写u-boot到SD卡 S5PV210 Uboot开发与移植01&#xff1a;Uboot概述&#xff08;推荐&#xff09; 一、sd_fusing文件夹简介 1、文件…

Linux系统管理----LVM逻辑卷和磁盘配额作业习题

1&#xff0e;为主机增加80G SCSI 接口硬盘 2&#xff0e;划分三个各20G的主分区 [rootlocalhost chen]# fdisk /dev/sdb 命令(输入 m 获取帮助)&#xff1a;n Partition type: p primary (0 primary, 0 extended, 4 free) e extended Select (default p): Using default r…

外存——S5PV210的外部存储器(nandflash与inand的介绍)

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 参考内容 关于iNand ,oneNand,moviNAND的区别——大家一起来扫盲 - 嵌入式系统 总结 本文首先介绍了目前主流的外存设备有哪些。 然后介绍了NandFlash芯片的接口、结构、常见操作&#xff0c;以及…

uboot中关于LCD的代码分析

以下内容源于朱有鹏《物联网大讲坛》课程的学习&#xff0c;如有侵权&#xff0c;请告知删除。 1、在uboot-jiuding/board.c中&#xff0c;init_sequence中的display_banner中的open_backlight函数中&#xff0c;给GPF3_5输出高电平。 注释掉这一句uboot的LCD显示照样正常的&am…

寒假自助游之济南

以前很少去旅行&#xff0c;主要原因是孩子年龄比较小&#xff0c;再就是经济方面的考虑。如今孩子渐渐长大了&#xff0c;行路与读万卷书同等重要&#xff0c;遂决定以后无论寒暑假都应陪孩子到处走一走。我不喜欢那种走马观花式的跟团游&#xff0c;因而自助游便是最佳选择。…

与fastboot相关的知识

以下内容源于朱有鹏嵌入式课程的学习&#xff0c;如有侵权&#xff0c;请告知删除。 一、fastboot的基本知识 1、什么是fastboot &#xff08;1&#xff09;fastboot是android使用的一种刷机方法。 android系统设计了2种刷机方式&#xff1a;fastboot和recovery。 &#xf…

Android中Activity启动模式详解

在Android中每个界面都是一个Activity&#xff0c;切换界面操作其实是多个不同Activity之间的实例化操作。在Android中Activity的启动模式决定了Activity的启动运行方式。 Android总Activity的启动模式分为四种&#xff1a; Activity启动模式设置&#xff1a; <activity and…

第一次软工作业展示——潘学

第一次软工作业完成啦&#xff01; 回首这个作业的完成过程&#xff0c;我是很有收获。这个作业有几个难点&#xff1a;1、在给定目录下读取TXT文件的内容&#xff1b;2、从读到的内容中分析出单词&#xff1b;3、统计单词的出现频率并输出。 我之前只学习过C和java&#xff0c…

uboot源码——命令体系

以下内容源于朱有鹏嵌入式课程的学习&#xff0c;如有侵权&#xff0c;请告知删除。 参考资料&#xff1a;http://www.cnblogs.com/biaohc/p/6394710.html 一、uboot命令体系基础 1、使用uboot命令 uboot启动后进入命令行环境&#xff0c;在此输入命令按回车结束&#xff0…

XMPP文件传输(XEP-0096协议说明)

XMPP XEP-0096协议是XMPP中的文件传输协议。 关于文件传输&#xff0c;在xmpp协议中有不少协议可以实现&#xff0c;而XEP-0096协议是其中非常简单的一个协议。由于邮件被删&#xff0c;我的代码demo丢失&#xff0c;因此只能在这里给大家讲一下其中的逻辑实现&#xff0…

uboot源码——环境变量

以下内容源于朱有鹏嵌入式课程的学习&#xff0c;如有侵权&#xff0c;请告知删除。 参考资料&#xff1a;http://www.cnblogs.com/biaohc/p/6398515.html。 一、uboot的环境变量基础 1、环境变量的作用 在不改变源码、不用重新编译的情况下&#xff0c;可以通过设置环境变量…

Linq To Sql进阶系列 -目录导航

博客园CLR基础研究团队|CLR团队精品系列|C# 3.0专题 [Linq To Sql进阶系列] 目录导航 1 Linq To Sql进阶系列&#xff08;一&#xff09;-从映射讲起 本系列&#xff0c;或多或少&#xff0c;直接或间接依赖入门系列知识。但&#xff0c;依然追求独立成章。因本文作者水平有限&…

uboot源码——mmc驱动分析

以下内容源于朱有鹏《物联网大讲坛》课程的学习&#xff0c;以及博客http://www.cnblogs.com/biaohc/p/6409197.html的学习整理&#xff0c;如有侵权&#xff0c;请告知删除。 一、uboot与linux驱动 1、uboot是裸机程序 狭义的驱动的概念&#xff1a;操作系统中用来具体操控硬…

RDIFramework.NET(.NET快速开发框架) 答客户问(2014-02-23)

1、框架的部署安装&#xff0c;服务器端和客户端 答&#xff1a;开发版以上版本支持SOA模式&#xff0c;也即真正的面向服务端的模式&#xff0c;在实际使用过程中&#xff0c;可根据项目的实际需要&#xff0c;来选择性的进行部署&#xff08;直连模式或SOA模式&#xff09;&a…