嵌入式硬件平台接口开发之中断接口
按键中断点亮熄灭led
硬件:Samsung Exynossoc
参考手册:SEC_Exynos4412 SCP_Users Manual_Ver.0.10.00_Preliminary
1. ARM中断的架构
cpu响应外设中断流程如下:
1) 每个cpu 响应外设中断有irq 和fiq,一般外设都是用的irq这根线
2) 中断源很多,但是通往cpu中断接口只有一根,所以需要一个设备来管理所有的中断源,该设备叫中断控制器,多核的称为GIC,单核 的称为VIC
3) 第一级中断控制器,比如GPX1 、GPX2只管理若干个中断源,会对中断源做初步的控制【中断使能屏蔽、触发方式、引脚滤波】
4) 中断信号就是由外设的发生中断信号的部件发出的,该电信号经过request line到达第一级中断控制器,通过第一级中断控制器,该信号就会到达GIC
5) GIC也会针对该中断源操作【使能屏蔽、优先级、发送到哪个cpu】,中断信号通过GIC就会到达cpu,
6)cpu收到中断信号之后硬件会自动进行arm处理器工作模式,然后跳到中断处理程序,执行中断程序。
7) 中断控制器如何标识这些中断源,soc设计的时候就已经给所有中断源编号称为HWinterrupt ID。
4) 设置GPX1 的EXT_INT41_MASK这个寄存器 使能/屏蔽中断
5) 中断到达GIC,通过设置ICDISER 寄存器使能中断源
6) 通过设置ICDPTR寄存器决定该中断源送到哪个CPUinterface
7)使能GIC
还有两个需要做的是:
1)设置CPU的中断屏蔽级别,若屏蔽级别0xFF,表示所有的中断都处理
2) 中断信号到达cpu interface,通过ICCICR寄存器全局使能cpu
1)找到中断对应的HWinterrupt ID
3)设置中断的触发方式,首先找到GPX1对应的的设置中断的寄存器EXT_INT41CO,其他的相关的寄存器标注如下图所示:
EXT_INT41_MASK
EXT_INT41_PEND
57 /32 = 1 余 25 ICDISER1 25位
6)发送给具体的cpu
CPU interface57 / 4 = 14 余 1 ICDIPTR14 [15:8]
7)gic使能
还有两个要做的是:
1)设置CPU中断屏蔽级别
ICCPMR_CPU
ICCICR_CPUn
3. 在中断程序中,清除相关中断,否则中断控制器会以为这个中断一直在发生。清除中断要做的有三是件事,一是找到中断号,二是清除相关中断标志位,三是告知cpu中断处理结束。
2)清除中断。GPX1对应的清中断寄存器为EXT_INT41_PEND
3)将中断号发给ICCEOIR_CPU寄存器,告知cpu,中断处理结束
利用按键中断点亮熄灭led示例代码如下:
S文件部分汇编代码:
/**** irq_handler ****/
irq_handler:
sub lr,lr,#4 //修正返回地址,3级流水线
stmfd sp!,{r0-r12,lr}//保存现场
.weak do_irq //
mrs r0,cpsr
bl do_irq
ldmfd sp!,{r0-r12,pc}^//恢复现场
C文件代码:
#include "exynos_4412.h"
static flag = 0;
void delay_ms(int num);
void led_init(void);
void led_on(void);
void led_off(void);
void key_int_init(void);
void main()
{
key_int_init();
led_init();
led_off();
flag = 0;
while(1);
{}
}
void delay_ms(int num)
{
int i,j;
for(i=num;i>0;i--)
for(j=1000;j>0;j--)
;
}
void led_init(void)
{
GPX2.CON = (GPX2.CON & (~(0xf<<28))) | (0x1<<28);
}
void led_on(void)
{
GPX2.DAT |= 0X1<<7;
}
void led_off(void)
{
GPX2.DAT = GPX2.DAT & (~(0X1<<7));
}
void do_irq(void)
{
int irq_num;
//读取需要处理的中断号,中断处理开始信号
//Penging状态--->Active状态
irq_num = CPU0.ICCIAR & 0x3ff;
switch(irq_num)
{
case 57:
if(flag ==0)
{
led_on();
flag =1;
}
else
{
led_off();
flag =0;
}
//清GPIO控制器中断挂起位
EXT_INT41_PEND |= 0x1<<1;
break;
}
//中断处理结束,写入处理的中断号,作为中断处理结束信号
//Active-->Inactive(Inactive and Pending)
CPU0.ICCEOIR = (CPU0.ICCEOIR&(~(0x3ff))) | irq_num;
}
void key_int_init(void)
{
//设置管脚为接收中断方式
GPX1.CON = (GPX1.CON & (~(0XF<<4)))| (0XF<<4);
//设置中断触发方式为下降沿触发
EXT_INT41_CON = (EXT_INT41_CON &(~(0XF<<4)))|(0X2<<4);
//使能中断
EXT_INT41_MASK &= ~(0X1<<1);
//在GIC中,使能CPU0的SPI25/ID57,57 / 32 = 1 余 25
ICDISER.ICDISER1 |= 0X1<<25;
//设置将SPI25发送给CPU0处理,57 / 4 = 14 余 1
ICDIPTR.ICDIPTR14 = (ICDIPTR.ICDIPTR14&(~(0XFF<<8)))|(0X1<<8);
//GIC使能
ICDDCR = 1;
//设置CPU0中断屏蔽级别为0XFF,最低级,所有中断都处理
CPU0.ICCPMR = 255;
//全局使能CPU0
CPU0.ICCICR = 1;
}