S02_CH07_ ZYNQ PL中断请求
S02_CH07_ ZYNQ PL中断请求
7.1 ZYNQ 中断介绍
7.1.1 ZYNQ中断框图
可以看到本例子中PL到PS部分的中断经过ICD控制器分发器后同时进入CPU1 和CPU0。从下面的表格中可以看到中断向量的具体值。PL到PS部分一共有20个中断可以使用。其中4个是快速中断。剩余的16个是本章中涉及了,可以任意定义。如下表所示。
7.1.2 ZYNQ CPU软件中断 (SGI)
ZYNQ 2个CPU 都具备各自16个软件中断。
7.1.3 ZYNQ CPU 私有端口中断
这些中断都是固定死的,不能修改。这里有2个PL到CPU的快速中断nFIQ
7.1.4 ZYNQ PS和PL共享中断
共享中断就是PL的中断可以发送给PS处理。上图中,黄色区域就是16个PL的中断,它们可以设置为高电平或者低电平触发。
7.2 搭建硬件地址
Step1:新建一个名为为Miz_sys的工程,芯片类型根据自身情况设置。
Step2:创建一个BD文件,并命名为system。
Step3:添加 ZYNQ7 Processing System,根据自己的硬件类型配置好输入时钟频率与内存型号。
Step4:在ZYNQ7 Processing System配置窗口中,使能中断,单击OK完成配置。
Step5:单击添加IP按钮,添加两个逻辑门模块和一个concat IP。
Step6:双击逻辑门模块,将其配置为非功能。
Step7:按以下电路,完善整体电路。
Step8:右键单击Block文件,文件选择Generate the Output Products。
Step9:右键单击Block文件,选择Create a HDL wrapper,根据Block文件内容产生一个HDL 的顶层文件,并选择让vivado自动完成。
Step10:添加一个约束文件,打开对应自己硬件的原理图,查看按键部分引脚连接情况,完成约束。Miz702约束文件如下所示:
set_property PACKAGE_PIN T18 [get_ports {SW1[0]}] set_property IOSTANDARD LVCMOS33 [get_ports {SW1[0]}] set_property PACKAGE_PIN R18 [get_ports {SW2[0]}] set_property IOSTANDARD LVCMOS33 [get_ports {SW2[0]}] |
Step10:生成Bit文件。
7.3 加载到SDK
Step1:导出硬件。
Step2:新建一个空SDK工程,并添加一个main.c的文件。
Step3:在main.c文件中添加以下程序,按Ctrl+S保存后自动开始编译。
#include <stdio.h> #include "xscugic.h" #include "xil_exception.h" #define INT_CFG0_OFFSET 0x00000C00 // Parameter definitions #define SW1_INT_ID 61 #define SW2_INT_ID 62 #define INTC_DEVICE_ID XPAR_PS7_SCUGIC_0_DEVICE_ID #define INT_TYPE_RISING_EDGE 0x03 #define INT_TYPE_HIGHLEVEL 0x01 #define INT_TYPE_MASK 0x03 static XScuGic INTCInst; static void SW_intr_Handler(void *param); static int IntcInitFunction(u16 DeviceId); static void SW_intr_Handler(void *param) { int sw_id = (int)param; printf("SW%d int\n\r", sw_id); } void IntcTypeSetup(XScuGic *InstancePtr, int intId, int intType) { int mask; intType &= INT_TYPE_MASK; mask = XScuGic_DistReadReg(InstancePtr, INT_CFG0_OFFSET + (intId/16)*4); mask &= ~(INT_TYPE_MASK << (intId%16)*2); mask |= intType << ((intId%16)*2); XScuGic_DistWriteReg(InstancePtr, INT_CFG0_OFFSET + (intId/16)*4, mask); } int IntcInitFunction(u16 DeviceId) { XScuGic_Config *IntcConfig; int status; // Interrupt controller initialisation IntcConfig = XScuGic_LookupConfig(DeviceId); status = XScuGic_CfgInitialize(&INTCInst, IntcConfig, IntcConfig->CpuBaseAddress); if(status != XST_SUCCESS) return XST_FAILURE; // Call to interrupt setup Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, &INTCInst); Xil_ExceptionEnable(); // Connect SW1~SW3 interrupt to handler status = XScuGic_Connect(&INTCInst, SW1_INT_ID, (Xil_ExceptionHandler)SW_intr_Handler, (void *)1); if(status != XST_SUCCESS) return XST_FAILURE; status = XScuGic_Connect(&INTCInst, SW2_INT_ID, (Xil_ExceptionHandler)SW_intr_Handler, (void *)2); if(status != XST_SUCCESS) return XST_FAILURE; // Set interrupt type of SW1~SW3 to rising edge IntcTypeSetup(&INTCInst, SW1_INT_ID, INT_TYPE_RISING_EDGE); IntcTypeSetup(&INTCInst, SW2_INT_ID, INT_TYPE_RISING_EDGE); // Enable SW1~SW3 interrupts in the controller XScuGic_Enable(&INTCInst, SW1_INT_ID); XScuGic_Enable(&INTCInst, SW2_INT_ID); return XST_SUCCESS; } int main(void) { print("PL int test\n\r"); IntcInitFunction(INTC_DEVICE_ID); while(1); return 0; } |
Step4:右击工程,选择Debug as ->Debug configuration。
Step5:选中system Debugger,双击创建一个系统调试。
Step6:设置系统调试。
打开系统自带的窗口调试助手,点击运行按钮开始运行程序。
系统运行结果如下图所示:
7.4 程序分析
接下来,我们对本章节的程序做一个详细的分析。还是先从main函数开始分析。第一句打印标题我们略过,直接看到这一句,这个函数只带了一个参数,我们选中这个参数,直接按F3跟踪一下这个参数。
从上图可以看到,这个参数是系统的中断的设备ID基地址的宏定义,也就是中断的基地址。
我们返回main函数当中,选中这个函数,按F3对其跟踪,查看一下此函数的定义。
程序一开头还是定义了一些要用到的指针和变量。接下来是一个跟第二章讲过的相似的一个查找设备配置的程序,带的参数为设备ID,也就是看我们的中断向量是否存在,感兴趣的可以选中这个程序,按下F3查看其定义。
接下来依然是一个状态检测,这是xilinx初始化的老套路,当执行完这一句后,系统会对我们的中断做一些初始化,如果初始化成功,会返回一个XST_SUCCESS的标志。当未检测到返回到这个初始化成功的标志时,系统会返回一个XST_FAILURE标志。
接下来是一个中断注册函数Xil_ExceptionRegisterHandler,按照之前讲过的方法,查看其函数定义。
从上面可以看到这个函数是把中断的句柄和中断的参数放到了两个数组当中,选中这个数组按下F3来看看这个数组。
可以看到这个数组的结构如上图所示,它是由一个结构体定义的,这个结构体定义如下图所示:
接下来看到这段程序:
通过上图中的程序,可以连接到我们的中断,我们查看下其定义。
上图可以看到方框中的语句把我们的中断的句柄和一个指针变量传递了进来,也就是把XScuGic_Connect函数的最后两个函数传递了进来。此时我们返回继续查看XScuGic_Connect函数,我们发现中断的句柄其实是个指针函数,也就是说当程序被执行的时候,其实被调用的是这个指针函数,此时我们跟踪这个指针函数,查看它具体做了些什么。
通过程序开头xilinx给出的这个程序的注释可以知道:这个函数是基本的中断驱动函数。它必须连接到中断源,以便在中断控制器的中断激活时被调用。 它将解决哪些中断是活动的和启用的,并调用适当的中断处理程序。 它使用中断类型信息来确定何时确认中断。首先处理最高优先级的中断。此函数假定中断向量表已预先初始化。 它不会在调用中断处理程序之前验证表中的条目是否有效。
上面讲到的这个中断向量表其实也就是下图所示的部分。
这部分在刚才已经进行了讲解了,此时我们就可以清楚的知道这就是一个中断向量表了。
回到基本的中断驱动函数的分析,看到下面的一段程序:
通过注释我们知道了这个程序是读取int_ack寄存器以识别最高优先级的中断ID,并确保其有效。 读取Int_Ack将清除GIC中的中断。然后看看读出来的中断ID是否大于最大的中断值。查看下这个最大的中断值。
从上图中圈出的地方可以看到,当使用ZYNQ的时候,最大有95个中断可以供我们使用。当读出来的这个中断值大于95U的话,就直接跳转到异常处理程序部分:
这里的意思也就相当于恢复中断寄存器,相当于出栈。
当读出来的中断值是正常的话,就会查找这个中断的中断向量表,如果这个向量表不是非空的话,就开始处理这个中断,也就是开始执行之前的连接中断的函数。此部分程序如下:
上图中的Tableptr指向的CallBackRef其实就是我们连接中断函数定义的无符号的数字,如下图所示。
为了验证我们的猜想,我们可以把这里的数字改成其他的值进行验证。
回到主程序当中,接着看到这段函数:
这段程序把中断的触发类型设置为了上升沿触发。
这段程序使能了中断。
整段程序下来,那么主要是执行了哪个函数呢?通过上面的分析,我们可以判定其实是下面这个函数:
这个函数的方框部分其实是个指针函数,我们可以跟踪看一下其定义。
一开始,它将传递进来的指针传递给了sw_id,然后会打印哪个按钮初始化,其实也就是哪个中断被触发了。
接下来,我们再对中断的一些寄存器做一些分析。在中断设置里的一些寄存器是比较重要的,我们就来分析一下中断设置里的寄存器。
将鼠标停留在图上圈出的函数上,SDK会跳出关于这个函数的信息,在跳出的窗口中左边是我们圈出的这个函数的定义,右边则是在执行过程中实际运行的程序。我们拷贝出右边这个函数来分析一下:
((Xil_In32((((InstancePtr)->Config->DistBaseAddress)) + ((0x00000C00 + (intId/16)*4)))))
红色部分是一个指针,它调用了config里的一个基地址DisBaseAddress,后半部分我们可以断定这是一个寄存器地址,因为这个函数就是一个读取中断寄存器的函数。此时,我们跟踪一下这个函数。
此时,我们就知道了第一个参数是一个指向要处理的中断的指针,第二个是寄存器偏移。我们就来计算一下这个寄存器偏移。首先我们来看看中断的基地址是多少(也就是红色部分指向的基地址)。
在xparameters.h中,找到了中断的基地址,如图中方框部分,为F8F01000。IntId就是定义的哪个按钮将被初始化,此处以SW1为例,SW1的ID为,等于61,此时可以算出:寄存器的地址= F8F01000+((0x00000C00+(61/16)*4))= F8F01C0C。打开ug585,查看一下这个寄存器是什么功能。
从图中我们可以看出这是一个设置中断触发方式的寄存器,01的时候,高电平触发,11的时候,上升沿触发。从上表中可以看到每个中断ID都由两位表示,而寄存器又是32位数据,因此,可以算出总共我们可以设置16个中断ID,这也是程序中为什么要除以16的原因。接下来看到Intcsetup的下一句。当执行完这一句后,我们来计算一下寄存器地址变为了多少?在前面的定义中,我们找到INT_TYPE_MASK的值,,因此可以计算出此时寄存器的值为:F8F01C0C &(~(C000000))=F0F01C0C。下一句又是一个运算,这次我们直接计算:F0F01C0C | 3FFFFFF =F3FF1C0C。也就是说最终写入寄存器的值是这个值。可以对照ug585查看配置的信息。
其他的寄存器设置的分析方法与上面的一致,在此就不再反复讲解了。
7.5 本章小结
本章学习了外部中断,通过PL传递开发板按键的中断,然后在PS接受处理中断。
S02_CH07_ ZYNQ PL中断请求的更多相关文章
- 基于FPGA Manager的Zynq PL程序写入方案
本文主要描述了如何在Linux系统启动以后,在线将bitstream文件更新到ZYNQ PL的过程及方法.相关内容主要译自xilinx-wiki,其中官网给出了两种方法,分别为Device Tree ...
- Zynq-7000 FreeRTOS(二)中断:PL中断请求
总结Zynq-7000的PL发送给PS一个中断请求,为FreeRTOS中断做准备. UG585的P225显示了系统的中断框图,如下图所示. 图:ZYNQ器件的中断框图 UG585的P227画出来中断控 ...
- 第十三章 ZYNQ-MIZ702 PL中断请求
本篇文章主要介绍外设(PL)产生的中断请求,在PS端进行处理. 在PL端通过按键产生中断,PS接受到之后点亮相应的LED. 本文所使用的开发板是Miz702 PC 开发环境版本:Vivado 2015 ...
- 第十二章 ZYNQ-MIZ701 PL中断请求
本篇文章主要介绍外设(PL)产生的中断请求,在PS端进行处理. 在PL端通过按键产生中断,PS接受到之后点亮相应的LED. 本文所使用的开发板是Miz701 PC 开发环境版本:Vivado 20 ...
- ZYNQ SGI、PPI、SPI三种中断的实例(含代码)
ZYNQ中断分为3类: SGI(Software Generated Interrupts)软件中断 PPI(Private Peripheral Interrupts)私有外设中断 SPI(Shar ...
- 米尔XC7Z010开发板资源
关于XC7Z010开发板 详细介绍http://www.myir-tech.com/product/myc_C7Z010_20.htm Xilinx基于28nm工艺流程的Zynq-7000 All P ...
- 【第一季】CH08_FPGA_Button 按钮去抖动实验
[第一季]CH08_FPGA_Button 按钮去抖动实验 按键的消抖,是指按键在闭合或松开的瞬间伴随着一连串的抖动,这样的抖动将直接影响设计系统的稳定性,降低响应灵敏度.因此,必须对抖动进行处理,即 ...
- MiZ702学习笔记13——ZYNQ通过AXI-Lite与PL交互
在<MiZ702学习笔记7——尝试自制带总线IP>,我曾提到了AXI4-Lite的简单用法,驱动了下流水灯,只涉及到了写总线.今天,我想利用之前的VGA模块,将AXI4-Lite的读写都应 ...
- [原创]基于Zynq PS与PL之间寄存器映射 Standalone & Linux 例程
基于Zynq PS与PL之间寄存器映射 Standalone & Linux 例程 待添加完善中
随机推荐
- docker pull 报错Get https://xxx.xxx.xxx.xxx:5000/v1/_ping: http: server gave HTTP response
解决方法: vim /etc/docker/daemon.json { "insecure-registries":["xxx.xxx.xxx.xxx:5000" ...
- ie中打印的问题
一般正常的情况下使用window.print();各个浏览器都可以调用出打印功能来但是ie有个坑就是如果页面在iframe里的话打印出来就是错的页面所以在这里要这样写: var agent = nav ...
- Flask-login Question
1 未登录访问鉴权页面如何处理? 如果未登录访问了一个作了 login_required 限制的 view,那么 Flask-Login 会默认 flash一条消息,并且将重定向到login_view ...
- Qt数据库编程_基本
QtSql模块提供了一个平台无关且数据库无关的访问SQL数据库的接口. Qt中的每个数据库连接用一个QSqlDatabase对象来表示:Qt使用不同driver来和各种不同数据库的API进行通讯. Q ...
- 分组背包---P1757 通天之分组背包
P1757 通天之分组背包 题解 分组背包板子题 k组物品,每组之间相互矛盾,也就是一组里面只能选一个或者不选 分组背包其实和01背包差不多,就是多加一维枚举组数 f[k][j] 前k组中,体积不超过 ...
- Swift 基本语法
如果创建的是 OS X playground 需要引入 Cocoa : import Cocoa /* 我的第一个 Swift 程序 */ var myString = "Hello, Wo ...
- [maven]scope之test
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit ...
- OpenStack v.s. Kubernetes
目录 文章目录 目录 What are the differences with OpenStack and Kubernetes? Why OpenStack & Kubernetes? W ...
- 阶段5 3.微服务项目【学成在线】_day03 CMS页面管理开发_14-异常处理-异常处理的问题分析
这块代码没有异常处理.如果在Service出现了异常代码,在哪里捕获?要么在Servive内捕获,要么在调用service的地方也就是controller内捕获 每个调用service的地方都要去捕获 ...
- [转]c3p0学习-JdbcUtil工具类
原文:https://www.cnblogs.com/jonny-xu/p/6374163.html 一.需要jar包: c3p0-0.9.1.2.jar mysql-connector-java-5 ...