s5pv210——中断

biaohc biaohc     2022-08-21     121

关键词:

1:s5pv210的中断步骤

(1):建立异常向量表;

(2):中断初始化;

(3):使能(如外部中断,写中断处理函数);

(4):建立中断号与中断处理函数的联系,使能中断;

当中断发生时,中断处理函数会自动处理中断;

流程如下:

 

2:建立异常向量表:

s5pv210异常向量表的基地址为0xD003_7400,下图为异常对于基地址的偏移量;

 

 第一步建立异常向量表:

代码如下:

/*
* s5pv210 裸机
*
* 异常向量表初始化
*
*/

#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);


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_handle
IRQ_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}^

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

1. 首先要谈流水线,在arm执行过程中一般分为取指,译码,执行阶段

  也就是假设当前                                                                      第一条指令在执行阶段

                                                              第二条指令在译码阶段

                          第三条指令在取指阶段

  当前正在执行的指令地址为pc-8,第二条就为pc-4,而pc现在真正指向已处于pc位置

 

2. 一般pc在发生中断时lr保存的是当前的pc值,这里pc值是多少呢??

     当发生中断肯定保存的pc是第三条指令,而我们从中断返回肯定不是执行第三条指令,而是紧接着的第二条指令,所以应该保存的 lr = pc - 4,

但是当执行到此位置时pc值已经改变,肯定不对,还好发生中断时 mov lr,pc 所以这里就可以直接使用 sub lr,lr,#4

 

————————————————————未完待续————————————————————————————

第二部:中断初始化

相关寄存器:

使能中断:

Disable中断

中断处理函数自动保存地址

 中断处理函数存放地址

代码实战:

//清除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();
    
}

 

第三部:使能外部中断中断处理函数;

详细请看

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

  clean_vicaddress();
}

 

第四部:建立中断号与中断函数联系,使能中断

#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的中断处理机制详解

1、ARM的中断机制介绍参考博客:《ARM架构的中断机制详解(S5PV210芯片)》;2、S5PV210芯片的中断处理过程2.1、中断处理第一阶段S5PV210芯片的中断处理第一阶段就是异常向量表的跳转,并没有任何特别,看上面的参考... 查看详情

s5pv210的中断处理机制详解

1、ARM的中断机制介绍参考博客:《ARM架构的中断机制详解(S5PV210芯片)》;2、S5PV210芯片的中断处理过程2.1、中断处理第一阶段S5PV210芯片的中断处理第一阶段就是异常向量表的跳转,并没有任何特别,看上面的参考... 查看详情

s5pv210串口实验(中断方式)

结合之前的串口实验(轮询方式)与中断体系分析,我们来做下中断方式的串口接收实验。start.S.global_start.globalIRQ_handle_start:/*关WatchDog*/ldrr0,=0xE2700000movr1,#0strr1,[r0]/*设置系统模式栈指针*/ldrsp,=0x40000000/*开IRQ总中断开关*/movr0,#0x53msrCPS... 查看详情

s5pv210中断体系

一、什么是中断?1、中断的发明是用来解决宏观上的并行需要的。宏观就是从整体上来看,并行就是多件事情都完成了。2、微观上的并行,就是指的真正的并行,就是精确到每一秒甚至每一刻,多个事情都是在同时进行的。宏... 查看详情

s5pv210中断处理过程

一、异常处理的两个过程    第一,异常向量表的跳转    第二,进入异常处理程序中二、异常处理中的第一个过程    1、当发生异常时,CPU会自动跳转PC到异常向量表对应的地址处,软... 查看详情

gpio中断

...V210_GPJ3(0))作为输出,来控制两个作为中断的GPIO(S5PV210_GPH1(4)和S5PV210_GPH1(2)),从而触发两个LED灯( S5PV210_GPH0(6)和S5PV210_GPH0(7))。主要参考文件linux/interrupt.h,kernel... 查看详情

gpio中断

主要功能:通过两个GPIO(S5PV210_GPJ2(7)和S5PV210_GPJ3(0))作为输出,来控制两个作为中断的GPIO(S5PV210_GPH1(4)和S5PV210_GPH1(2)) 查看详情

arm架构的外部中断介绍(s5pv210芯片)(代码片段)

1、外部中断介绍(1)中断源的划分:内部中断和外部中断。所谓内部中断和外部中断,是根据中断源来自Soc内部还是外部,(1)比如串口、定时器等都是Soc内部自带的,所以触发的中断都是内部中断;(2)给Soc外接... 查看详情

arm架构的外部中断介绍(s5pv210芯片)(代码片段)

1、外部中断介绍(1)中断源的划分:内部中断和外部中断。所谓内部中断和外部中断,是根据中断源来自Soc内部还是外部,(1)比如串口、定时器等都是Soc内部自带的,所以触发的中断都是内部中断;(2)给Soc外接... 查看详情

s5pv210时钟体系分析

...SYS:用来给cortexa8处理器、DRAM控制器、3D、IRAM、IROM、INTC(中断控制器)等提供时钟;2)DSYS:用来给显示相关的部件提供时钟,包括FIMC、FIMD、JPEG和multimedia 查看详情

s5pv210-arm裸机-异常中的中断实现过程

210中的异常中的中断实现过程: 首先异常分为很多种,异常中包含了中断异常,有一个东西叫做异常向量表,在异常向量表中有很多相应异常的的地址。异常向量表中的所有异常中断的地址是不会变化的。地址都是固定的,但... 查看详情

arm架构的中断机制详解(s5pv210芯片)(代码片段)

1、中断介绍(1)中断是指计算机运行过程中,出现某些意外情况需主机干预时,机器能自动停止正在运行的程序并转入处理新情况的程序,处理完毕后又返回原被暂停的程序继续运行;(2)中断是为了实现宏观上的并发。... 查看详情

arm架构的中断机制详解(s5pv210芯片)(代码片段)

1、中断介绍(1)中断是指计算机运行过程中,出现某些意外情况需主机干预时,机器能自动停止正在运行的程序并转入处理新情况的程序,处理完毕后又返回原被暂停的程序继续运行;(2)中断是为了实现宏观上的并发。... 查看详情

s5pv210——初始化时钟

1:s5pv210的时钟域MSYSDomain:为处理器、3D、intc(中断)、DMC0、DMC1、IRAM、IROM提供时钟,HCLK_MSYS:200MHZ、PCLK_MSYS:100MHzDSYSDomain:为音视频等设备提供时钟,HCLK_DSYS:166MHZ、PCLK_DSYS:83MHzPSYSDomain:为外设提供时钟,如GPIO、I2C、PWM、... 查看详情

嵌入式外部中断控制编程方法论—比較cc2541(51核)和s5pv210(arm核)

这是一篇阐述怎样对嵌入式SOC外部中断进行控制编程的方法论文章。希望读者理解本篇文章后。能够具备对市场上全部已经面世和将来面世的嵌入式芯片的外部中断进行控制编程的能力。 笔者原创的技术分享一直都恪守下面原... 查看详情

s5pv210的启动过程

一、硬件结构 S5PV210存储部分的硬件结构大致为:内置SRAM+外接大容量DRAM+外接大容量Nand(S5PV210采用的是iNand)。 S5PV210内置了一块96kb的SRAM(即iRAM),同时还内置了一块64kb的NorFlash(即iROM)。二、启动过程 1、当CPU上... 查看详情

s5pv210|微处理器启动流程(代码片段)

S5PV210|微处理器启动流程目录S5PV210|微处理器启动流程S5PV210启动概述S5PV210的启动顺序iROM(BL0)的启动顺序V210启动流程图第一次启动失败时的iROM第二次启动顺序用于引导代码描述的标题信息数据编写校验和示例代码S5PV210启动概... 查看详情

s5pv210的启动过程

s5pv210的启动方式:SD0启动,SD2启动,USB启动s5pv210启动涉及的硬件不需要初始化的外存Norflash(iROM)+静态内存SRAM (iRAM )需要初始化的大动态内存DRAM +大外存iNand上电后,先从64KB的iROM中读取预先设置的代码BL0,这部... 查看详情