S5PV210开发之1.0.8------中断系统

本文详细介绍了S5PV210处理器的中断处理流程,包括中断控制器的初始化、按键中断的配置、中断服务例程的设置以及中断的启用。通过设置异常向量表、配置中断控制器、初始化按键相关寄存器和绑定中断处理函数,实现了对按键中断的响应。同时,展示了如何通过中断控制器硬件来调用中断处理函数,并提供了中断处理的示例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

S5PV210中断+按键

//中断大致过程
1.中断前的保护现场操作
2.进入中断执行isr程序
3.退出isr,返回现场

1.初始化中断控制器

1.异常向量表关联相应中断函数


#define exception_irq	(exception_vector_table_base + 0x18)
#define exception_fiq	(exception_vector_table_base + 0x1C)


#define r_exception_irq		(*(volatile unsigned int *)exception_irq)
#define r_exception_fiq		(*(volatile unsigned int *)exception_fiq)

r_exception_irq = (unsigned int)IRQ_handle;
r_exception_fiq = (unsigned int)IRQ_handle;

2.关联好IRQ_handle之后,在调用isr之前,就要做一些中断相关的初始化

在这里插入图片描述
在这里插入图片描述

    // 禁止所有中断
    VIC0INTENCLEAR = 0xffffffff;
    VIC1INTENCLEAR = 0xffffffff;
    VIC2INTENCLEAR = 0xffffffff;
    VIC3INTENCLEAR = 0xffffffff;

    // 选择中断类型为IRQ
    VIC0INTSELECT = 0x0;
    VIC1INTSELECT = 0x0;
    VIC2INTSELECT = 0x0;
    VIC3INTSELECT = 0x0;

    // 清VICxADDR
    VIC0ADDR = 0;
    VIC1ADDR = 0;
    VIC2ADDR = 0;
    VIC3ADDR = 0;

2.初始化按键相关寄存器

//通过查文档、原理图、按键对应的中断类型号

SW5->GPH0_2
SW6->GPH0_2

//按键->外设->通过GPIO来读取状态
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

void key_init_interrupt(void)
{
	// 1. 外部中断对应的GPIO模式设置
	rGPH0CON |= 0xFF<<8;		// GPH0_2 GPH0_3设置为外部中断模式
	rGPH2CON |= 0xFFFF<<0;		// GPH2_0123共4个引脚设置为外部中断模式
	
	// 2. 中断触发模式设置
	rEXT_INT_0_CON &= ~(0xFF<<8);	// bit8~bit15全部清零
	rEXT_INT_0_CON |= ((2<<8)|(2<<12));		// EXT_INT2和EXT_INT3设置为下降沿触发
	rEXT_INT_2_CON &= ~(0xFFFF<<0);
	rEXT_INT_2_CON |= ((2<<0)|(2<<4)|(2<<8)|(2<<12));	
	
	// 3. 中断允许
	rEXT_INT_0_MASK &= ~(3<<2);		// 外部中断允许
	rEXT_INT_2_MASK &= ~(0x0f<<0);
	
	// 4. 清挂起,清除是写1,不是写0
	rEXT_INT_0_PEND |= (3<<2);
	rEXT_INT_2_PEND |= (0x0F<<0);
}

3.绑定isr到中断控制器硬件

在这里插入图片描述
一个VICVECTADDR中,能存放一个地址(4个字节)
32个VICVECTADDR成为一组
一共有4组
一共能存放128个地址(函数指针)

在这里插入图片描述
物理中断类型号理论上也有128个
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

//intc_setvectaddr函数的作用就是把isr放到VICVECTADDR里面,
//如何放?是借助intnum(物理中断号)来寻址、选择到对应的
//VICVECTADDR在中断响应时,硬件自动把VICnVECTADDR的函数放到VECTADDRESS
void intc_setvectaddr(unsigned long intnum, void (*handler)(void))
{
    //VIC0
    if(intnum<32)
    {
        *( (volatile unsigned long *)(VIC0VECTADDR + 4*(intnum-0)) ) = (unsigned)handler;
    }
    //VIC1
    else if(intnum<64)
    {
        *( (volatile unsigned long *)(VIC1VECTADDR + 4*(intnum-32)) ) = (unsigned)handler;
    }
    //VIC2
    else if(intnum<96)
    {
        *( (volatile unsigned long *)(VIC2VECTADDR + 4*(intnum-64)) ) = (unsigned)handler;
    }
    //VIC3
    else
    {
        *( (volatile unsigned long *)(VIC3VECTADDR + 4*(intnum-96)) ) = (unsigned)handler;
    }
    return;
}

//isr:
void isr_eint2(void)
{
	// 真正的isr应该做2件事情。
	// 第一,中断处理代码,就是真正干活的代码
	printf("isr_eint2_LEFT.\n");
	// 第二,清除中断挂起
	rEXT_INT_0_PEND |= (1<<2);
	intc_clearvectaddr();
	
}

void isr_eint16171819(void)
{
	// 真正的isr应该做2件事情。
	// 第一,中断处理代码,就是真正干活的代码
	// 因为EINT16~31是共享中断,所以要在这里再次去区分具体是哪个子中断
	if (rEXT_INT_2_PEND & (1<<0))
	{
		printf("eint16\n");
	}
	if (rEXT_INT_2_PEND & (1<<1))
	{
		printf("eint17\n");
	}
	if (rEXT_INT_2_PEND & (1<<2))
	{
		printf("eint18\n");
	}
	if (rEXT_INT_2_PEND & (1<<3))
	{
		printf("eint19\n");
	}

	// 第二,清除中断挂起
	rEXT_INT_2_PEND |= (0x0f<<0);
	intc_clearvectaddr();//清除ADDRESS寄存器
}

//绑定:
	intc_setvectaddr(KEY_EINT2, isr_eint2);
	intc_setvectaddr(KEY_EINT3, isr_eint3);
	intc_setvectaddr(KEY_EINT16_19, isr_eint16171819);

IRQ_handle:


2.

//通过查文档、原理图、按键对应的中断类型号
SW5->GPH0_2
SW6->GPH0_2
...如上图

//按键->外设->通过GPIO来读取状态
//其实几个宏,只是一个中断类型号
#define KEY_EINT2		NUM_EINT2		// left
#define KEY_EINT3		NUM_EINT3		// down
#define KEY_EINT16_19	NUM_EINT16_31	// 其余4个共用的

intc_setvectaddr(KEY_EINT2, isr_eint2);
intc_setvectaddr(KEY_EINT3, isr_eint3);
intc_setvectaddr(KEY_EINT16_19, isr_eint16171819);
IRQ_handle:
	// 设置IRQ模式下的栈
	ldr sp, =IRQ_STACK
	// 保存LR
	// 因为ARM有流水线,所以PC的值会比真正执行的代码+8,
	sub lr, lr, #4
	// 保存r0-r12和lr到irq模式下的栈上面
	stmfd sp!, {r0-r12, lr}
	// 在此调用真正的isr来处理中断
	bl irq_handler
	// 处理完成开始恢复现场,其实就是做中断返回,关键是将r0-r12,pc,cpsr一起回复
	ldmfd sp!, {r0-r12, pc}^
	

4.使能中断

在这里插入图片描述

void intc_enable(unsigned long intnum)
{
    unsigned long temp;
	// 确定intnum在哪个寄存器的哪一位
	// <32就是0~31,必然在VIC0
    if(intnum<32)
    {
        temp = VIC0INTENABLE;
        temp |= (1<<intnum);		// 如果是第一种设计则必须位操作,第二种设计可以
									// 直接写。
        VIC0INTENABLE = temp;
    }
    else if(intnum<64)
    {
        temp = VIC1INTENABLE;
        temp |= (1<<(intnum-32));
        VIC1INTENABLE = temp;
    }
    else if(intnum<96)
    {
        temp = VIC2INTENABLE;
        temp |= (1<<(intnum-64));
        VIC2INTENABLE = temp;
    }
    else if(intnum<NUM_ALL)
    {
        temp = VIC3INTENABLE;
        temp |= (1<<(intnum-96));
        VIC3INTENABLE = temp;
    }
    // NUM_ALL : enable all interrupt
    else
    {
        VIC0INTENABLE = 0xFFFFFFFF;
        VIC1INTENABLE = 0xFFFFFFFF;
        VIC2INTENABLE = 0xFFFFFFFF;
        VIC3INTENABLE = 0xFFFFFFFF;
    }

}

	intc_enable(KEY_EINT2);
	intc_enable(KEY_EINT3);
	intc_enable(KEY_EINT16_19);

5.irq_handler(访问isr)

在这里插入图片描述

功能:进入addr拿出函数指针、访问函数

void irq_handler(void)
{
	printf("irq_handler.\n");
	unsigned long vicaddr[4] = {VIC0ADDR,VIC1ADDR,VIC2ADDR,VIC3ADDR};
    int i=0;
    void (*isr)(void) = NULL;

    for(i=0; i<4; i++)
    {
		// 发生一个中断时,4个VIC中有3个是全0,1个的其中一位不是0
        if(intc_getvicirqstatus(i) != 0)
        {
            isr = (void (*)(void)) vicaddr[i];
            break;
        }
    }
    (*isr)();		// 通过函数指针来调用函数
}

unsigned long intc_getvicirqstatus(unsigned long ucontroller)
{
    if(ucontroller == 0)
        return	VIC0IRQSTATUS;//返回addr0的状态,空为0
    else if(ucontroller == 1)
        return 	VIC1IRQSTATUS;
    else if(ucontroller == 2)
        return 	VIC2IRQSTATUS;
    else if(ucontroller == 3)
        return 	VIC3IRQSTATUS;
    else
    {}
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值