ZYNQ的中断(一)

https://blog.csdn.net/v13910/article/details/83540289

1.ARM中断体系

中断的意思就不多说了。主要说明几个知识点:

(1)ARM体系中,在存储地址的低位,固化了一个32字节的硬件中断向量表。

(2)异常中断发生时,程序计数器PC所指的位置不同,异常中断就不同。中断结束后,中断不同,返回地址也不同。但是,对于系统复位中断,不需要返回,因为整个应用系统就是从复位中断中开始的。

数据访问终止:数据访问的地址不存在,或者当前地址不允许访问。

快速中断请求:外部引脚的快速中断请求,比外部中断请求等级高,但是一般外设的中断请求使用外部中断请求

指令预取终止:预取指令的地址不存在,或者当前地址不允许访问。

未定义的指令:ARM或协处理器认为当前指令未定义。

ARM中断流程:

首先在主程序中发生IRQ中断请求,程序跳到中断向量表找IRQ中断对应的解析程序地址,然后再跳到中断解析程序,进而执行中断程序。

2.ZYNQ中断体系

ZYNQ包括三种中断:私有中断,软件中断和共享中断。

(1)私有中断:每个CPU连接5个私有中断,中断ID27—31。

(2)软件中断:16个,中断号:0—15。通过CPU私有总线向ICDSGIR寄存器写中断号,并且制定CPU。

(3)共享中断:接收来自如GPIO、DMA、定时器等模块的中断信号。中断号32-95。

它们之间的关系:

3.中断点亮LED

PL端的一个按键,点亮PS端LED。

首先还是硬件配置,加入ZYNQ的软核,配置一下DDR和UART。

然后,因为要用到PL端的按键,所以要建立PL与PS之间的联系,通过EMIO或者AXI总线,EMIO能不能中断还没有研究,这里用的AXI。

1.加AXI_GPIO IP核,设置GPIO端口中断使能,GPIO宽度为1(只用了一个按键),设置方向为全输入。

(如果想控制PL端LED,就再加一个AXI_GPIO核),设置输出就可以了。

2.打开中断

IRQ_F2P是PL与PS的共享中断,下面的是两个ARM核的快速中断和外部中断(都来自PL属于CPU私有中断),私有中断如何点亮LED还没有测试。

3.PS端LED,设置I/O外设,GPIO里勾选MIO,点亮的LED管脚为MIO0。

然后自动连接,(手动连接AXI_GPIO ip2intc_irpt),绑定gpio_rtl的管脚为T17(按键),3.3V,然后输出,生成HDL Wrapper,导出硬件(包含比特流文件),载入SDK。

4.中断代码

各种初始化:

1.初始化按键:


  
  
  1. status = XGpio_Initialize(& key, KEY1_ID);
  2. if(status!=XST_SUCCESS)
  3. return XST_FAILURE;
  4. XGpio_SetDataDirection(& key, 1, 1);

设置单通道,方向为输入。

2.初始化LED:


  
  
  1. led_config = XGpioPs_LookupConfig(LED1_ID);
  2. status = XGpioPs_CfgInitialize(&led, led_config, led_config->BaseAddr);
  3. if(status!=XST_SUCCESS)
  4. return XST_FAILURE;
  5. XGpioPs_SetDirectionPin(&led, 0, 1); //output
  6. XGpioPs_SetOutputEnablePin(&led, 0, 1);
  7. XGpioPs_WritePin(&led, 0, 1);

设置MIO0为输出,使能引脚(不使能不能点亮,与AXI接PL端LED有点区别,后者不需要使能)。然后引脚写高电平,使LED初始状态为灭。

3.初始化中断:


  
  
  1. status = InitIntrFunction(INTR_ID);
  2. if(status!=XST_SUCCESS)
  3. return XST_FAILURE;

中断初始化写成一个函数,传入参数是中断的ID,另外以上各种初始化,需要实例化XGpio、XGpioPs、XScuGic类型的变量,直接定义为全局变量,这样会比较方便。

中断函数:


  
  
  1. u32 InitIntrFunction(u16 device_ID){ //INTR ID
  2. XScuGic_Config* intr_config;
  3. int status;
  4. //init
  5. intr_config = XScuGic_LookupConfig(device_ID);
  6. status = XScuGic_CfgInitialize(&gpio_intr, intr_config, intr_config->CpuBaseAddress);
  7. if(status!=XST_SUCCESS)
  8. return XST_FAILURE;
  9. //call to interrupt setup Function
  10. status = InterruptSystemSetup(&gpio_intr);
  11. if(status != XST_SUCCESS)
  12. return XST_FAILURE;
  13. //connect
  14. status = XScuGic_Connect(&gpio_intr, INTR_GPIO, (Xil_ExceptionHandler)BTN_Intr_Handler, (void*)&key);
  15. if(status!=XST_SUCCESS)
  16. return XST_FAILURE;
  17. //Enable Intr
  18. XGpio_InterruptEnable(&key, 1);
  19. XGpio_InterruptGlobalEnable(&key);
  20. //print("Hello World");
  21. //Enable Intr in controller
  22. XScuGic_Enable(&gpio_intr, INTR_GPIO);
  23. return XST_SUCCESS;
  24. }

1.函数首先是中断初始化,与先前的按键初始化与LED初始化差不多。

2.接着是定义了一个InterruptSystemSetup函数,定义为:


  
  
  1. u32 InterruptSystemSetup(XScuGic* XScuGicInstancePtr){
  2. Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
  3. (Xil_ExceptionHandler)XScuGic_InterruptHandler,
  4. XScuGicInstancePtr);
  5. Xil_ExceptionEnable();
  6. return XST_SUCCESS;
  7. }

查了查,说是Xil_ExceptionRegisterHandler函数是Xilinx提供的通用异常处理程序,中断触发之后统一由XScuGic_InterruptHandler先处理,然后在HandlerTable中查找相应的处理函数。Xil_ExceptionEnable函数使能异常处理。

3.连接,我理解的就是,将这个中断与按键的行为,连接起来。XScuGic_Connect(&gpio_intr, INTR_GPIO, (Xil_ExceptionHandler)BTN_Intr_Handler, (void*)&key),这个函数中参数的意思,第一个参数就是实例化的XScuGic对象了,第二个参数,是对应的XPAR_FABRIC_AXI_GPIO_0_IP2INTC_IRPT_INTR,也就是定义的那个中断IRQ_F2P,定义在xparameters.h里。

定义为61,这也就是IRQ_F2P的中断号为61-68和84-91,共同组成了IRQ_F2P[15:0]。

第三个参数,调用的中断处理函数,发生的中断操作写在里面。第四个参数,连接的对象,这里是按键,即将中断行为与按键行为连接起来。

4.使能中断与挂起中断。

中断调用函数:

在函数里,点亮LED即可。

5.问题

1.首先在文档里写了:

这个中断触发方式,是否是高电平触发?如果是高电平触发

没有按下的时候,输入为高电平,为何不触发呢?懂的朋友留个评论!

猜你喜欢

转载自blog.csdn.net/baidu_37503452/article/details/90747620