s5pv210——中断实战
来源:互联网 发布:买了域名之后怎么绑定 编辑:程序博客网 时间:2024/06/04 01:30
以下内容源于博客http://www.cnblogs.com/biaohc/p/6354068.html的学习,以及朱友鹏老师课程的学习,和网络资源的整理。
一、s5pv210的中断步骤
(1)建立异常向量表;
(2)中断初始化;
(3)使能(如外部中断,写中断处理函数);
(4)建立中断号与中断处理函数的联系,使能。
当中断发生时,中断处理函数会自动处理中断;
流程如下图:
下面按上述步骤编写代码,内容细节见博客http://blog.csdn.net/oqqhutu12345678/article/details/71635611
二、代码
1、建立异常向量表
/* *s5pv210 裸机 * * 异常向量表初始化 * */#define VECTOR_TABLE_BASE0xD0037400#define Reset_offset0x0#define Undef_offset0x4#define SVC_offset0x8#define Prectch_offset0xC#define Data_Abort_offset0x10#define IRQ_offset0x18#define FIQ_offset0x1C#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);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;//但凡是中断,都会进入到此模式_PFUNC_FIQ= (unsigned int)IRQ_handle;//FIQ、IRQ都是采用IRQ中断}
其中,IRQ_handle要写在汇编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值,这里pc值是多少呢?
- 当发生中断时,肯定保存的pc是第三条指令,而我们从中断返回肯定不是执行第三条指令,而是紧接着的第二条指令,所以应该保存的 lr = pc - 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; } } 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(); //清vicaddress clean_vicaddress(); }
4、建立中断号与中断函数联系,使能中断
#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(); //创建函数 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"); } }
小总结:
一、S5PV210中断处理的编程实践
2、中断控制器初始化
- 主要工作有:第一阶段绑定异常向量表到异常处理程序;禁止所有中断源;选择所有中断类型为IRQ;清理VICnADDR寄存器为0.
3、中断的使能与禁止
- 思路是先根据中断号判断这个中断属于VIC几,然后在用中断源减去这个VIC的偏移量,得到这个中断号在本VIC中的偏移量,然后1<<x位,写入相应的VIC的INTENABLE/INTENCLEAR寄存器即可。
4、绑定自己实现的isr到VICnVECTADDR
- 搞清楚2个寄存器的区别:VICnVECTADDR和VICnADDR
- VICVECTADDR寄存器一共有4×32个,每个中断源都有一个VECTADDR寄存器,将自己为这个中断源写的isr地址丢到这个中断源对应的VECTADDR寄存器中即可。
5、真正的中断处理程序如何获取isr
- 发生中断时,硬件自动把相应中断源的isr地址从VICnVECTADDR寄存器推到VICnADDR寄存器中,所以只需要到相应的VICnADDR中去拿出isr地址,调用执行即可。
- 第4步绑定isr地址到VICnVECTADDR,以及第5步中断发生时第二阶段的第二阶段如何获取isr地址,这两步是相关的。这两个的结合技术,就是x210的硬件自动寻找isr的机制。
二、整个中断的流程梳理:
整个中断的工作分为2部分:
第一部分是我们为中断响应而做的预备工作:
1. 初始化中断控制器
2. 绑定写好的isr到中断控制器
3. 相应中断的所有条件使能
第二部分是当硬件产生中断后如何自动执行isr:
1. 第一步,经过异常向量表跳转入IRQ/FIQ的入口
2. 第二步,做中断现场保护(在start.S中),然后跳入isr_handler
3. 第三步,在isr_handler中先去搞清楚是哪个VIC中断了,然后直接去这个VIC的ADDR寄存器中取isr来执行即可。
4. 第四步,isr执行完,中断现场恢复,直接返回继续做常规任务。
- s5pv210——中断实战
- S5PV210——中断
- TQ210——S5PV210中断体系
- s5pv210——中断系统相关介绍
- s5pv210——串口通信实战
- s5pv210——LCD的原理和实战
- s5pv210——LCD的原理和实战
- 嵌入式Linux裸机开发(八)——S5PV210中断处理流程
- 嵌入式外部中断控制编程方法论—比较CC2541(51核)和S5PV210(ARM核)
- wince6.0 s5pv210 中断
- linux中断之一(s5pv210)
- wince6.0 s5pv210 中断
- s5pv210的汇编中断
- S5PV210中断配置
- S5PV210中断体系
- s5pv210中断体系
- S5PV210的中断编程
- S5PV210外部中断
- Linux 八 软件管理:RPM、YUM
- 解决jquery实现的radio再次选中的问题
- No default constructor for entity问题分析与解决
- 大型网站架构之分布式消息队列
- JavaScript的数组中添加元素的方法小结
- s5pv210——中断实战
- liferay实现 form表单有两个submit
- 第 8 章 查询语句详解
- 实验课中学到的小技巧
- 高并发Java 六 JDK并发包2
- JavaScript之模拟事件(事件)
- ubuntu创建新用户
- Spring MVC 基础教程
- OkRx扩展,让OkGo完美结合RxJava,比Retrofit更简单易用