很多情况下,要实现一个嵌入式程序,用到某一功能或者某一个硬件资源时,我经常拿厂家或者是其他人给提供的代码,参考其中的配置代码段部分,只去修改实现成我需要的功能就好。相信大家也和我有相似的经历吧!?从工程的角度来说,这没问题。但是理论上总感觉少了点什么,今天以外部中断的寄存器配置为例,进一步讲解中断源是如何进入CPU中,CPU又如何处理中断信号的,这一过程。单纯学术的角度,具体涉及到哪些寄存器、填写什么值,就不细述了。这里用的单片机是FS4412多核ARM芯片。

 

 

中断的实现过程(程序的角度)

中断发生后,硬件自动跳转到异常向量表中对应异常类型的位置,然后进行处理。处理过程,先进行现场保护(数据进栈操作),然后根据处理中断函数,根据中断号进行特定的中断处理,等中断程序处理完后,还要恢复中断前的现场(数据出栈操作)。

 

这里可以参考我的另外一篇:汇编语言 --实现软中断机制

 

 

对中断源的处理过程(硬件的角度)

这个过程涉及到我们要讲的中断初始化配置,从图中可以看到,一个外部中断信号需要经过这么多步骤才能到达ARM内核。

首先,外部中断信号需经过GPIO管脚进入CPU内部,然后再内部经使能-->分发-->分发使能-->cpu接口-->接口使能和优先级-->ARM内核  过五关 斩六将 终于到达ARM内核,然后产生中断标志位,再执行之前讲到的中断实现(程序实现)。

 


中断初始化配置

单片机有内置外设,GPIO属于外围功能模块,中断控制器GIC属于内部外设。由于中断源从IO口进入到中断控制器GIC,才能进入ARM内核。我们需要同时配置这两块资源。

#define  GPX1CON        (*(volatile unsigned int *)0x11000c20)
#define  EXT_INT41CON   (*(volatile  int *)0x11000E04)
#define  EXT_INT41_MASK (*(volatile  int *)0x11000F04)
#define ICDISER1_CPU0  (*(volatile  int *)0x10490104)
#define ICDIPTR14_CPU0 (*(volatile  int *)0x10490838)
#define ICDDCR (*(volatile  int *)0x10490000)
#define ICCICR_CPU0  (*(volatile  int *)0x10480000)
#define ICCPMR_CPU0  (*(volatile  int *)0x10480004)
#define EXT_INT41_PEND (*(volatile  int *)0x11000f44)
#define ICCIAR_CPU0  (*(volatile  int *)0x1048000C)
#define ICCEOIR_CPU0 (*(volatile  int *)0x10480010)
#define ICDICPR1_CPU0 (*(volatile  int *)0x10490284)



void interrupt_init(void)
{
	//-----外: 配置管脚的工作模式
	GPX1CON = (GPX1CON & ~(0xF<<4))|(0xF<<4);  //配置 GPX1_1为中断模式
	
	EXT_INT41CON = (EXT_INT41CON & ~(0x7<<4))|(0x2<<4);  //设置GPX1_1的触发方式为 下降沿触 
 
	EXT_INT41_MASK = EXT_INT41_MASK & (~0x02);		//GPX1_1 中断使能

	
	
	//-----内: 功能块设置
	ICDISER1_CPU0 = ICDISER1_CPU0 | (1<<25);	//EINT9 (GPX1_1)  GIC中断使能
	ICDIPTR14_CPU0 = 0x01010101;   //参考例子背景,用默认设置 
	ICDDCR = ICDDCR|1; //GIC 分发总使能
	ICCICR_CPU0 = 1;  // CPU0  中断使能
	ICCPMR_CPU0 = 0XFF;   //设置CPU0的优先级门槛为最低

}

 

 

原本想是深入研究一下,然后再写的。发现还真不简单,怪不得说中断是最难的也是最重要的一个知识点。笔者水平有限,就这样吧。