MicroBlaze里面的中断主要有两类:一类是外部中断,另一类是内部中断。
1. 外部中断:
如果只有一个元件产生中断(比如只有一个定时器产生中断)或者只有一个外部中断管脚连接MB(这儿说的外部是相对于CPU说的,可以是FPGA内部的其他模块产生的中断,也可以是FPGA外部的输入中断),那么Intc可以不使用。
这种情况,在EDK里面实现是最简单的。
下面摘录MHS文件:
PORT fifo_full_pin = fifo_full, DIR = I, SIGIS = INTERRUPT, SENSITIVITY = LEVEL_HIGH
BEGIN microblaze
PARAMETER INSTANCE = microblaze_0
PARAMETER HW_VER = 4.00.a
BUS_INTERFACE DLMB = dlmb
BUS_INTERFACE ILMB = ilmb
BUS_INTERFACE DOPB = mb_opb
BUS_INTERFACE IOPB = mb_opb
PORT CLK = sys_clk_s
PORT Interrupt = fifo_full
END
PORT后面的几个参数(SIGIS等)参见psf_rm.pdf。从实际操作看,这些不加也可以。建议加上。特别是SENSITIVITY,可以设置中断是上升沿、下降沿、高电平、低电平中断。
Note:By the way, interrupts connected to the microblaze directly needs to be level sensitive, in case of using an edge triggered interrupt you'll need an interrupt controller.
注册中断函数可以在C文件里面调用注册函数,更为简单的办法是在MSS文件里面直接说明。
注: 如果既有外部中断,又有内部中断,那么还是要用中断控制器,在mhs文件中加上PORT fifo_full_pin = fifo_full, DIR = I, SIGIS = INTERRUPT, SENSITIVITY = LEVEL_HIGH,之后, fifo_full_pin会自动连接到中断控制器的输入端Intr,点击加入就好了。加好之后的mhs文件如下所示:
BEGIN opb_intc
parameter INSTANCE = myintc
parameter HW_VER = 1.00.b
parameter C_BASEADDR = 0xFFFF1000
parameter C_HIGHADDR = 0xFFFF10ff
bus_interface SOPB = opb_bus
port Irq = interrupt
port Intr = uart_int & ext_int & gpio_int & fifo_full
MSS文件摘录:
PARAMETER VERSION = 2.2.0
PARAMETER int_handler = gpio_int_handler, int_port = fifo_full_pin
BEGIN OS
PARAMETER OS_NAME = standalone
PARAMETER OS_VER = 1.00.a
PARAMETER PROC_INSTANCE = microblaze_0
END
特 意把OS也摘出来是为了说PARAMETER int_handler = gpio_int_handler, int_port = fifo_full_pin这个是全局设定,不要放在Begin … End里面。此外,需要注意这个int_port,与它连接的应该是Port,而不是Interrupt Signal (注意:这里说的是外部中断,如果是内部中断,比如定时器中断,那么PARAMETER int_handler = gpio_int_handler, int_port = fifo_full_pin得放入Timer的Begin End里面,int_port指Timer的Interrupt Port,参见psf_rm.pdf )。gpio_int_handler,中断服务程序,需要在c中定义。
注:现在新出的EDK版本,XPS9.2,已经将这种在mss文件中添加句柄(handler)的作用去掉了,句柄(handler)最好在软件中添加。
2.内部中断
内部中断需要使用中断控制器。
如果在EDK的生成CPU向导中,选GPIO时选择了中断,那么中断控制器(以下称 Intc )会自动被加上。
这个中断控制器的使用是非常简单的。
很多中断都连接到Intc的Intr端口,然后从它的Irq端口连接MB的Interrupt。
MHS文件描述如下:
BEGIN opb_intc
parameter INSTANCE = myintc
parameter HW_VER = 1.00.b
parameter C_BASEADDR = 0xFFFF1000
parameter C_HIGHADDR = 0xFFFF10ff
bus_interface SOPB = opb_bus
port Irq = interrupt
port Intr = uart_int & ext_int & gpio_int
END
begin microblaze
parameter INSTANCE = mblaze
parameter HW_VER = 1.00.c
bus_interface DOPB = opb_bus
bus_interface DLMB = d_lmb
bus_interface ILMB = i_lmb
port INTERRUPT = interrupt
end
需要说明一下的是中断优先级的设定。大家看这句:
port Intr = uart_int & ext_int & gpio_int
在 这种情况下,EDK会自动设定OPB_INTC的C_NUM_INTR_INPUTS参数为3,因为有三个中断。其中gpio_int的优先级是最高的, 因为它连接到intr[0]上。中断优先级右边最高,左边最低,即uart_int最低。因此,大家可以根据实际需要来设定。
在MHS设定完毕后,生成的Lib里面的xparameters.h会定义一些比较重要的宏,包括了所有中断信号的一些属性。它们的命名符合一定的格式。
大家可以在头文件里面看到:
XPAR_< font="" />的实例名> _<产生中断的元件的实例名>_<中断信号名>_MASK
XPAR_<产生中断的元件的实例名>_<中断信号名> _INTR
比如说我们上面这段MHS, gpio_int中断的相关宏定义(跟具体设置有关,可能名字有出入):
#define XPAR_DIP_SWITCHES_IP2INTC_IRPT_MASK 0X000001
#define XPAR_OPB_INTC_0_DIP_SWITCHES_IP2INTC_IRPT_INTR 0
INTR中的0拥有最高中断优先级。
我们在写OPB_Intc的c程序时,代码是基本相同的,大家只要copy一下,做一些参数的修改即可。
代码片断如下:
/* 允许MB中断*/
microblaze_enable_interrupts();
/*注册中断子程序,就是告诉MB,发生中断之后,执行哪个中断服务程序 */
XIntc_RegisterHandler(XPAR_OPB_INTC_0_BASEADDR, \ /* Intc的基址 */
XPAR_OPB_INTC_0_DIP_SWITCHES_IP2INTC_IRPT_INTR, \
/*这个参数就是上面提到的XPAR_<产生中断的元件的实例名>_<中断信号名> _INTR */
(XInterruptHandler)gpio_int_handler, \ /* 中断服务程序名,因此我们在c文件里还应该写一个void gpio_int_handler(void *bassaddr_p) ,用于处理中断 */
(void *)XPAR_DIP_SWITCHES_BASEADDR);
/* 这个是产生中断的元件基址,如果是外部中断,就用 NULL */
/* start the interrupt controller */
XIntc_mMasterEnable(XPAR_OPB_INTC_0_BASEADDR);
/* enable the gpio interrupt*/
XIntc_mEnableIntr(XPAR_OPB_INTC_0_BASEADDR, XPAR_DIP_SWITCHES_IP2INTC_IRPT_MASK); /*这个就是上面提到的XPAR_< span="" />的实例名> _<产生中断的元件的实例名>_<中断信号名>_MASK */