xilinx DMA IP核(一) —— loop测试 代码注释
本篇笔记中的代码来自:米联科技的教程“第三季第一篇的DMA_LOOP环路测试”
硬件的连接如下图所示:
图:DMA Loop Block Design
橘色的线就是DMA加FIFO组成的一个LOOP循环,红色圈圈是AXI_LITE的控制和两个读写完成的中断。
米联科技教程提供的该测试代码文件是以下四个,我删除了其中关于OLED的部分。
图:DMA Loop 测试源码结构
1.重要的结构体
1.1.中断设备:static XScuGic Intc; //GIC
在main.c文件中,sataic用来修饰全局变量,形成静态全局变量,static修饰的函数/全局变量属于内链接,Intc可以在当前main.c文件内部范围内进行链接。
- /**
- * The XScuGic driver instance data. The user is required to allocate a
- * variable of this type for every intc device in the system. A pointer
- * to a variable of this type is then passed to the driver API functions.
- */
- typedef struct
- {
- XScuGic_Config *Config; /**< Configuration table entry */
- u32 IsReady; /**< Device is initialized and ready */
- u32 UnhandledInterrupts; /**< Intc Statistics */
- } XScuGic;
XScuGic结构体中包含了XScuGic_Config 结构体类型指针Config。XScuGic_Config 结构体如下:
- typedef struct
- {
- u16 DeviceId; /**< Unique ID of device */
- u32 CpuBaseAddress; /**< CPU Interface Register base address */
- u32 DistBaseAddress; /**< Distributor Register base address */
- XScuGic_VectorTableEntry HandlerTable[XSCUGIC_MAX_NUM_INTR_INPUTS];/**<
- Vector table of interrupt handlers */
- } XScuGic_Config;
1.2.DMA设备:static XAxiDma AxiDma;
- /**
- * The XAxiDma driver instance data. An instance must be allocated for each DMA
- * engine in use.
- */
- typedef struct XAxiDma {
- UINTPTR RegBase; /* Virtual base address of DMA engine */
- int HasMm2S; /* Has transmit channel */
- int HasS2Mm; /* Has receive channel */
- int Initialized; /* Driver has been initialized */
- int HasSg;
- XAxiDma_BdRing TxBdRing; /* BD container management for TX channel */
- XAxiDma_BdRing RxBdRing[]; /* BD container management for RX channel */
- int TxNumChannels;
- int RxNumChannels;
- int MicroDmaMode;
- int AddrWidth; /**< Address Width */
- } XAxiDma;
1.3.中断向量表
- typedef struct {
- Xil_ExceptionHandler Handler;
- void *Data;
- } XExc_VectorTableEntry;
2.代码结构
main()
|---- init_intr_sys();
|---- DMA_Intr_Init(); // 初始化DMA
|---- XAxiDma_LookupConfig(); // 查找DMA设备
|---- XAxiDma_CfgInitialize(); // 初始化DMA设备
|---- Init_Intr_System(); //初始化中断控制器
|---- XScuGic_LookupConfig(); // 查找中断控制器设备;带的参数为设备ID,查看中断向量是否存在
|---- XScuGic_CfgInitialize(); // 初始化中断控制器设备
|---- Setup_Intr_Exception();
|---- Xil_ExceptionInit(); // 使能硬件中断
|---- Xil_ExceptionRegisterHandler();
|---- Xil_ExceptionEnable();
|---- DMA_Setup_Intr_System(); // 设置DMA中断
|---- XScuGic_SetPriorityTriggerType();
|---- XScuGic_Connect(); // 连接中断源
|---- XScuGic_Enable();
|---- DMA_Intr_Enable();
|---- XAxiDma_IntrDisable();
|---- XAxiDma_IntrEnable();
|----axi_dma_test();
2.1.比较重要的函数
2.1.1.中断注册函数 Xil_ExceptionRegisterHandler:
- /*****************************************************************************/
- /**
- * @brief Register a handler for a specific exception. This handler is being
- * called when the processor encounters the specified exception.
- *
- * @param exception_id contains the ID of the exception source and should
- * be in the range of 0 to XIL_EXCEPTION_ID_LAST.
- * See xil_exception.h for further information.
- * @param Handler to the Handler for that exception.
- * @param Data is a reference to Data that will be passed to the
- * Handler when it gets called.
- *
- * @return None.
- *
- * @note None.
- *
- ****************************************************************************/
- void Xil_ExceptionRegisterHandler(u32 Exception_id,
- Xil_ExceptionHandler Handler,
- void *Data)
- {
- XExc_VectorTable[Exception_id].Handler = Handler;
- XExc_VectorTable[Exception_id].Data = Data;
- }
从上面可以看到Xil_ExceptionRegisterHandler()这个函数是把中断的句柄(第二个行参“Handler”)和中断的参数(第三个行参“Data”)放到了两个结构体XExc_VectorTableEntry类型的数组XExc_VectorTable当中 ,XExc_VectorTableEntry结构体类型如下:
- XExc_VectorTableEntry XExc_VectorTable[XIL_EXCEPTION_ID_LAST + ] =
- {
- {Xil_ExceptionNullHandler, NULL},
- {Xil_UndefinedExceptionHandler, NULL},
- {Xil_ExceptionNullHandler, NULL},
- {Xil_PrefetchAbortHandler, NULL},
- {Xil_DataAbortHandler, NULL},
- {Xil_ExceptionNullHandler, NULL},
- {Xil_ExceptionNullHandler, NULL},
- };
Xil_ExceptionRegisterHandler()函数的第二传参XScuGic_InterruptHandler,是一个函数指针,强制转化成了Xil_ExceptionHandler类型,XScuGic_InterruptHandler()函数如下。
- void XScuGic_InterruptHandler(XScuGic *InstancePtr)
- {
- u32 InterruptID;
- u32 IntIDFull;
- XScuGic_VectorTableEntry *TablePtr;
- /* Assert that the pointer to the instance is valid
- */
- Xil_AssertVoid(InstancePtr != NULL);
- /*
- * Read the int_ack register to identify the highest priority interrupt ID
- * and make sure it is valid. Reading Int_Ack will clear the interrupt in the GIC.
- * 读取 int_ack 寄存器以识别最高优先级的中断 ID, 并确保其有效。读取 Int_Ack 将清除 GIC 中的中断。
* 然后看看读出来的中断 ID 是否大于最大的中断值。- */
- IntIDFull = XScuGic_CPUReadReg(InstancePtr, XSCUGIC_INT_ACK_OFFSET);
- InterruptID = IntIDFull & XSCUGIC_ACK_INTID_MASK;
- if(XSCUGIC_MAX_NUM_INTR_INPUTS < InterruptID){
- goto IntrExit;
- }
- /*
- * Execute the ISR. Jump into the Interrupt service routine based on the
- * IRQSource. A software trigger is cleared by the ACK.
- */
- TablePtr = &(InstancePtr->Config->HandlerTable[InterruptID]);
- if(TablePtr != NULL) {
- TablePtr->Handler(TablePtr->CallBackRef);
- }
- IntrExit:
- /*
- * Write to the EOI register, we are all done here.
- * Let this function return, the boot code will restore the stack.
- */
- XScuGic_CPUWriteReg(InstancePtr, XSCUGIC_EOI_OFFSET, IntIDFull);
- }
通过程序开头 xilinx 给出的这个XScuGic_InterruptHandler()程序的注释可以知道: 这个函数是基本的中断驱动函数。 它必须 连接到中断源, 以便在中断控制器的中断激活时被调用。 它将解决哪些中断是活动的和启用的, 并调用适当的中断处理程序。 它使用中断类型信息来确定何时确认中断。 首先处理最高优先级的中断。 此函数假定中断向量表已预先初始化。 它不会在调用中断处理程序之前验证表中的条目是否有效。 当中断发生时,调用的就是上面的代码中的语句:TablePtr->Handler(TablePtr->CallBackRef)。那么这个Handler和CallBackRef到底是什么呢?也就是Handler和CallBackRef到底是和哪段要被执行的代码绑定在一起呢?
2.1.2.中断连接函数
我们在DMA_Setup_Intr_System()函数中调用了中断连接函数XScuGic_Connect();
- int DMA_Setup_Intr_System(XScuGic * IntcInstancePtr,XAxiDma * AxiDmaPtr, u16 TxIntrId, u16 RxIntrId)
- {
- <...>
- /*
- * Connect the device driver handler that will be called when an
- * interrupt for the device occurs, the handler defined above performs
- * the specific interrupt processing for the device.
- */
- Status = XScuGic_Connect(IntcInstancePtr, TxIntrId,
- (Xil_InterruptHandler)DMA_TxIntrHandler,
- AxiDmaPtr);
- if (Status != XST_SUCCESS) {
- return Status;
- }
- Status = XScuGic_Connect(IntcInstancePtr, RxIntrId,
- (Xil_InterruptHandler)DMA_RxIntrHandler,
- AxiDmaPtr);
- if (Status != XST_SUCCESS) {
- return Status;
- }
- <...>
- }
可以看到XScuGic_Connect()函数的第三个传参是一个Xil_InterruptHandler类型的函数指针DMA_TxIntrHandler。XScuGic_Connect()内容如下。
- s32 XScuGic_Connect(XScuGic *InstancePtr, u32 Int_Id,
- Xil_InterruptHandler Handler, void *CallBackRef)
- {
- /*
- * Assert the arguments
- */
- Xil_AssertNonvoid(InstancePtr != NULL);
- Xil_AssertNonvoid(Int_Id < XSCUGIC_MAX_NUM_INTR_INPUTS);
- Xil_AssertNonvoid(Handler != NULL);
- Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
- /*
- * The Int_Id is used as an index into the table to select the proper
- * handler
- */
- InstancePtr->Config->HandlerTable[Int_Id].Handler = Handler;
- InstancePtr->Config->HandlerTable[Int_Id].CallBackRef = CallBackRef;
- return XST_SUCCESS;
- }
可以看到XScuGic_Connect()函数将传进来的第三个参数,Xil_InterruptHandler类型的“Handler”,绑定到InstancePtr->Config->HandlerTable[Int_Id].Handler中,第四个参数同理绑定。这里的InstancePtr是函数XScuGic_Connect()传进来的XScuGic结构体类型的指针变量,前面讲过,XScuGic结构体中还包含XScuGic_Config结构体类型的指针Config,进一步来说,XScuGic_Connect()函数将传进来的第三个参数Handler就是绑定到XScuGic_Config结构体类型的指针Config中的HandlerTable变量。这个HandlerTable变量是一个XScuGic_VectorTableEntry类型的结构体变量。至此,中断的Handler就绑定到main.c文件开头定义的设备static XScuGic Intc当中,同时设备 XScuGic Intc也因为函数Setup_Intr_Exception()跟硬件的异常向量表绑定到一起了。前文提到“Handler和CallBackRef到底是和哪段要被执行的代码绑定在一起呢?”,那么答案就在这里了,要执行的代码就在这里被绑定到一起来。
所以接下来看看这个形参Handler(对应的是调用XScuGic_Connect()函数传进来的实参DMA_TxIntrHandler)指向了什么东西?
函数指针DMA_TxIntrHandler指向的内容如下。下面代码是DMA Tx的,Rx的也差不多。
- static void DMA_TxIntrHandler(void *Callback)
- {
- u32 IrqStatus;
- int TimeOut;
- XAxiDma *AxiDmaInst = (XAxiDma *)Callback;
- /* Read pending interrupts */
- IrqStatus = XAxiDma_IntrGetIrq(AxiDmaInst, XAXIDMA_DMA_TO_DEVICE);
- /* Acknowledge pending interrupts */
- XAxiDma_IntrAckIrq(AxiDmaInst, IrqStatus, XAXIDMA_DMA_TO_DEVICE);
- /*
- * If no interrupt is asserted, we do not do anything
- */
- if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) {
- return;
- }
- /*
- * If error interrupt is asserted, raise error flag, reset the
- * hardware to recover from the error, and return with no further
- * processing.
- */
- if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) {
- Error = ;
- /*
- * Reset should never fail for transmit channel
- */
- XAxiDma_Reset(AxiDmaInst);
- TimeOut = RESET_TIMEOUT_COUNTER;
- while (TimeOut) {
- if (XAxiDma_ResetIsDone(AxiDmaInst)) {
- break;
- }
- TimeOut -= ;
- }
- return;
- }
- /*
- * If Completion interrupt is asserted, then set the TxDone flag
- */
- if ((IrqStatus & XAXIDMA_IRQ_IOC_MASK)) {
- TxDone = ;
- }
- }
代码中,在dma_intr.h中声明了三个全局变量:TxDone,RxDone和Error。
dam_intr.h :
- extern volatile int TxDone;
- extern volatile int RxDone;
- extern volatile int Error;
在dma_intr.c文件的开头,定义了这三个全局变量。
- #include "dma_intr.h"
- volatile int TxDone;
- volatile int RxDone;
- volatile int Error;
可以看到用关键字volatile修饰,在此回顾一下朱有鹏老师在讲解C语言的时候,总结的volatile的用法:
(1)volatile的字面意思:可变的、易变的。C语言中volatile用来修饰一个变量,表示这个变量可以被编译器之外的东西改变。编译器之内的意思是变量的值的改变是代码的作用,编译器之外的改变就是这个改变不是代码造成的,或者不是当前代码造成的,编译器在编译当前代码时无法预知。譬如在中断处理程序isr中更改了这个变量的值,譬如多线程中在别的线程更改了这个变量的值,譬如硬件自动更改了这个变量的值(一般这个变量是一个寄存器的值)
(2)以上说的三种情况(中断isr中引用的变量,多线程中共用的变量,硬件会更改的变量)都是编译器在编译时无法预知的更改,此时应用使用volatile告诉编译器这个变量属于这种(可变的、易变的)情况。编译器在遇到volatile修饰的变量时就不会对改变量的访问进行优化,就不会出现错误。
(3)编译器的优化在一般情况下非常好,可以帮助提升程序效率。但是在特殊情况(volatile)下,变量会被编译器想象之外的力量所改变,此时如果编译器没有意识到而去优化则就会造成优化错误,优化错误就会带来执行时错误。而且这种错误很难被发现。
(4)volatile是程序员意识到需要volatile然后在定义变量时加上volatile,如果你遇到了应该加volatile的情况而没有加程序可能会被错误的优化。如果在不应该加volatile而加了的情况程序不会出错只是会降低效率。所以我们对于volatile的态度应该是:正确区分,该加的时候加不该加的时候不加,如果不能确定该不该加为了保险起见就加上。
计划在xilinx DMA IP loop测试(二)中结合DMA的AXI4总线时序,来记录一下DMA的数据收发。
xilinx DMA IP核(一) —— loop测试 代码注释的更多相关文章
- xilinx DMA IP核(二) —— 文档阅读
本笔记不记录DMA的Scatter/Gather特性.DMA上有三种总线:AXI4-LIte(对寄存器进行配置),AXI4-Memory Map(用于与内存交互)和AXI4 Stream(用于与外设交 ...
- 从Xilinx FFT IP核到OFDM
笔者在校的科研任务,需要用FPGA搭建OFDM通信系统,而OFDM的核心即是IFFT和FFT运算,因此本文通过Xilinx FFT IP核的使用总结给大家开个头,详细内容可查看官方文档PG109.关于 ...
- PCIE xilinx v5 IP核使用前的研究
外带一个月前啃的一个星期,加本星期心无旁骛,啃出些心得,广惠后人.但愿有用. trn信号是数据链路层的信号 TLP包是数据链路层传给transaction层的包 解包需要一个transaction的协 ...
- Xilinx DDR3 IP核使用问题汇总(持续更新)和感悟
一度因为DDR3的IP核使用而发狂. 后来因为解决问题,得一感悟.后面此贴会完整讲述ddr3 ip的使用.(XILINX K7) 感悟:对于有供应商支持的产品,遇到问题找官方的流程.按照官方的指导进行 ...
- 转:基于 xilinx vivado 的PCIE ip核设置与例程代码详解
连接:https://blog.csdn.net/u014586651/article/details/103826967#comments
- xilinx VDMA IP核使用
VDMA实用配置说明 VDMA是通过AXI Stream协议对视频数据在PS与PL端进行搬运,开发者无需关注AXI Stream协议,在BlockDesign设计中只需要把相应信号进行连接即可. VD ...
- aurora 64B/66B ip核设置与例程代码详解
见网页https://blog.csdn.net/u014586651/article/details/84349328 https://blog.csdn.net/u012135070/articl ...
- Xilinx FFT IP核缩放因子说明
以1024点FFT为例, reg [9:0] scale_sch = 10'b11_10_01_01_01; 流水线结构中,将每个基 2 的蝶形处理单元视为一个阶段. 每个阶段进行一次数据的缩减,缩减 ...
- Xilinx的IP核接口命名说明
s_axis中的s表示:slave(从); m_axis中的m表示:master(主). axis表示AXI(一种总线协议) Signal.
随机推荐
- jQuery动画中stop()与 finish()区别
stop():接受三个参数,(要停止的动画名称:是否清空队列中的动画:是否当前动画立即完成) stop()相当于stop(false,false)表示停止执行当前动画,后续动画接着进行 stop(tr ...
- UVa 10537 The Toll! Revisited (最短路)
题意:给定一个图,你要从 s 到达 t,当经过大写字母时,要交 ceil(x /20)的税,如果经过小写字母,那么交 1的税,问你到达 t 后还剩下 c 的,那么最少要带多少,并输出一个解,如果多个解 ...
- c# Brush、Color、String相互转换
using System.Windows.Media; 1.String转换成Color Color color = (Color)ColorConverter.ConvertFromString(s ...
- JVM GC 机制与性能优化
目录(?)[+] 1 背景介绍 与C/C++相比,JAVA并不要求我们去人为编写代码进行内存回收和垃圾清理.JAVA提供了垃圾回收器(garbage collector)来自动检测对象的作用域),可自 ...
- HDU1232 畅通工程 2017-04-12 19:20 53人阅读 评论(0) 收藏
畅通工程 Time Limit : 4000/2000ms (Java/Other) Memory Limit : 65536/32768K (Java/Other) Total Submissi ...
- 两段 PHP 代码比较优劣
// 代码一 public function getPCA($level = false) { $results = array(); $where = $level ? " where f ...
- mysql 主从日志文件mysql-bin文件清除方法
默认情况下mysql会一直保留mysql-bin文件,这样到一定时候,磁盘可能会被撑满,这时候是否可以删除这些文件呢,是否可以安全删除,是个问题,不建议使用rm命令删除,这样有可能会不安全,正确的方法 ...
- CheckBox使用记录
页面显示 页面代码 <div> <div><input type="checkbox" value="" class=" ...
- vim编辑后权限不够保存问题解决方案
常常忘记了sudo就直接用vim编辑/etc内的文件,等编辑好了,保存时候才发现没权限. 1.曲线救国:先保存个临时文件,退出后再sudo cp回去 2.可以直接用 :w !sudo tee % 查阅 ...
- 如何将JPG格式的图片转化为带地理坐标的TIFF格式
最近有个项目需要用到开源软件GeoServer,数据源是一张高分辨率的2.5维图片,格式是jpg的,由于GeoServer不支持jpg格式的发布,因此考虑到要进行格式转换,将其转换成tiff格式. 1 ...