S03_CH01_AXI_DMA_LOOP 环路测试

1.1概述

本课程是本季课程里面最简单,也是后面DMA课程的基础,读者务必认真先阅读和学习。

本课程的设计原理分析。

本课程是设计一个最基本的DMA环路,实现DMA的环路测试,在SDK里面发送数据到DMA然后DMA在把数据发回到DDR里面,SDK读取内存地址里面的数据,对比接收的数据是否和发送出去的一致。DMA的接口部分使用了data_fifo IP链接。本课程会详细介绍创建工程的每个步骤,后面的课程将不再详细介绍创建工程的步骤。

1.2搭建硬件系统

1.2.1新建VIVADO工程

Step1:启动VIVADO,单击Create New Project

Step2:单击NEXT

Step3:创建名为Miz_sys的工程到对应的文件目录,之后单击NEXT

Step4:选择RTL Project并且勾选复选框,之后单击NEXT

Step5:选择芯片的型号和封装速度等级。

MIZ702/MIZ702N选择Zynq-7000-xc7z020clg484-1

MIZ701N-7010选择Zynq-7000-xc7z010clg400-1

MIZ701N-7020选择Zynq-7000-xc7z020clg400-2

Step:6 单机Finish完成工程创建。

1.2.2创建VIVADO硬件构架

Step1:单击 Create Block Design

Step2:命名为system 之后单击OK

Step3:创建完成后如下图所示

Step3:添加各个模块如图:

Step4双击ZYNQ IP 进行如下步骤配置

Step5: MIZ702和MIZ702N的输入时钟是333.333333MHZ

Step6:MIZ701N PS的输入时钟是50MHZ

Step7:MIZ702的开发板采用的是单片256MB的MT41K128M16JI-125

Step8:MIZ701N和MIZ702N的内存型号一样,都是单片512MB的MT41K256M16RE-125

Step9:PS的PLL提供本系统的时钟100MHZ

Step10:启动1路HP接口,HP接口是ZYNQ个高速数据接口

Step11:勾选PL到PS的中断资源(关于中断,在第二季的课程中有详细讲解,不熟悉的读者可以到第二季课程中温习一下)

Step12:设置完成后单击OK

Step13:双击DMA  IP 设置如下:

下图中,同时勾选读通道和写通道,另外设置,Wideh of buffer length register 为23bit 这个含义是2的23次方8,388,607bytes 8M大小,这里设置14bit 就够用了,长度越大需要的资源也就越多。

Step14:Data FIFO 设置

Step15:Concat IP设置

Concate IP实现了单个分散的信号,整合成总线信号。这里2个独立的中断信号,可以合并在一起介入到ZYNQ IP的中断信号上。

Step16:Run Automation 自动配置ZYNQ IP 如下图所示

Step17:单击Run Connection Automation 自动连线,只要软件提示你需要自动连线,一般都需要进行自动连线,除非自己知道如何连线,有特殊需求。

Step18:如果还有提示需要自动连线的继续让软件自动连线,直到出下如下。可以看到,还有未连线的模块。

Step19:把DMA收发中断信号,通过contact IP连接到ZYNQ

Step20:

连接FIFO的S_AXIS(写端口)到DMA的M_AXIS(DMA读端口);

连接FIFO的M_AXIS(读端口)到DMA的S_AXIS(DMA写端口);

连接FIFO 的a_axis_aresetn到 复位IP的peripheral aresetn ;

连接FIFO的s_axis_ack到ZYNQ  IP 的FCLK0;

连接完成后如下图

Step21:把OLED 模块的IO引出来,后面C代码部分会用OLED显示一些信息(MIZ701N需要配OLED模块)。连接完成后的工程如下图

Step22:未来调试的时候可以观察到中断信号的产生,添加ila 调试IP并且进行如下设置

Step23:把中断信号连接到 ila IP上,另外,把时钟信号也连接起来。

Step24:

以上就完成独立工程的创建。

之后的过程是Validate Design->Gerate Out products->Create wrappers->Generate Bitstream 产生完成后导入到SDK进行软件开发。

1.3 PS部分软件分析

1.3.1新建SDK工程

Step1:新建一个名为AXI_DMA_Test的空的软件工程

Step2:直接把源码复制过来,软件会自动编译


1.3.2 main.c源码的分析

init_intr_sys();是对中断资源的初始化,使能中断资源。这个函数里面调用的函数是笔者封装好的初始化函数,使用起来比较方便。一般只要给出中断对象,中断号,就可以对中断进行初始化。

DMA_Intr_Init(&AxiDma,0);中第一参数是DMA的对象,第二参数是硬件ID

Init_Intr_System(&Intc); 对象是中断对象

DMA_Setup_Intr_System(&Intc,&AxiDma,TX_INTR_ID,RX_INTR_ID); //注册中断函数,最后2个参数是中断号

DMA_Intr_Enable(&Intc,&AxiDma); 就是启动DMA传输

表1-3-2-1 init_intr_sys函数

int init_intr_sys(void)

{

DMA_Intr_Init(&AxiDma,0);//initial interrupt system

Init_Intr_System(&Intc); // initial DMA interrupt system

Setup_Intr_Exception(&Intc);

DMA_Setup_Intr_System(&Intc,&AxiDma,TX_INTR_ID,RX_INTR_ID);//setup dma interrpt system

DMA_Intr_Enable(&Intc,&AxiDma);

}

为了发送的数据是已知是确定数据,先对TxBufferPtr 发送缓冲进行初始化,初始化后用Xil_DCacheFlushRange 函数把数据全部刷到DDR中。

XAxiDma_SimpleTransfer 函数为启动一次DMA接收传输。

XAxiDma_SimpleTransfer 函数为启动一次DMA发送传输

DMA_CheckData 函数为对接收的数据进行校验和对比。

表1-3-2-1 DMA_CheckData

int axi_dma_test()

{

int Status;

TxDone = 0;

RxDone = 0;

Error = 0;

xil_printf("\r\n----DMA Test----\r\n");

print_message( "----DMA Test----",0);//oled print

xil_printf("PKT_LEN=%d\r\n",MAX_PKT_LEN);

sprintf(oled_str,"PKT_LEN=%d",MAX_PKT_LEN);

print_message(oled_str,1);//oled print

//while(1)

for(i = 0; i < Tries; i ++)

{

Value = TEST_START_VALUE + (i & 0xFF);

for(Index = 0; Index < MAX_PKT_LEN; Index ++) {

TxBufferPtr[Index] = Value;

Value = (Value + 1) & 0xFF;

}

/* Flush the SrcBuffer before the DMA transfer, in case the Data Cache

* is enabled

*/

Xil_DCacheFlushRange((u32)TxBufferPtr, MAX_PKT_LEN);

Status = XAxiDma_SimpleTransfer(&AxiDma,(u32) RxBufferPtr,

MAX_PKT_LEN, XAXIDMA_DEVICE_TO_DMA);

if (Status != XST_SUCCESS) {

return XST_FAILURE;

}

Status = XAxiDma_SimpleTransfer(&AxiDma,(u32) TxBufferPtr,

MAX_PKT_LEN, XAXIDMA_DMA_TO_DEVICE);

if (Status != XST_SUCCESS) {

return XST_FAILURE;

}

/*

* Wait TX done and RX done

*/

while (!TxDone || !RxDone) {

/* NOP */

}

success++;

TxDone = 0;

RxDone = 0;

if (Error) {

xil_printf("Failed test transmit%s done, "

"receive%s done\r\n", TxDone? "":" not",

RxDone? "":" not");

goto Done;

}

/*

* Test finished, check data

*/

Status = DMA_CheckData(MAX_PKT_LEN, (TEST_START_VALUE + (i & 0xFF)));

if (Status != XST_SUCCESS) {

xil_printf("Data check failed\r\n");

goto Done;

}

}

xil_printf("AXI DMA interrupt example test passed\r\n");

xil_printf("success=%d\r\n",success);

sprintf(oled_str,"success=%d",success);

print_message(oled_str,2);

/* Disable TX and RX Ring interrupts and return success */

DMA_DisableIntrSystem(&Intc, TX_INTR_ID, RX_INTR_ID);

Done:

xil_printf("--- Exiting Test --- \r\n");

print_message("--Exiting Test---",3);

return XST_SUCCESS;

}

int init_intr_sys(void)

{

DMA_Intr_Init(&AxiDma,0);//initial interrupt system

Init_Intr_System(&Intc); // initial DMA interrupt system

Setup_Intr_Exception(&Intc);

DMA_Setup_Intr_System(&Intc,&AxiDma,TX_INTR_ID,RX_INTR_ID);//setup dma interrpt system

DMA_Intr_Enable(&Intc,&AxiDma);

}

int main(void)

{

init_intr_sys();

oled_fresh_en();// enable oled

axi_dma_test();

}

1.3.3 dma_intr.c 源码分析

XAxiDma *AxiDmaInst = (XAxiDma *)Callback;这句代码是为了获取当前中断的对象。void *Callback是一个无符号的指针,传递进来的阐述可以强制转换成其他任何的对象,这里就是强制转换成 XAxiDma 对象了。

IrqStatus =XAxiDma_IntrGetIrq(AxiDmaInst, XAXIDMA_DMA_TO_DEVICE)这个函数获取当前中断号。

XAxiDma_IntrAckIrq(AxiDmaInst, IrqStatus, XAXIDMA_DMA_TO_DEVICE);这个函数是响应当前中断,通知CPU 当前中断已经被接收,并且清除中断标志位。

如果中断全部正确,TxDone将被置为1表示发送中断完成。

如果有错误,则复位DMA,并且设置超时参数

表1-3-3-1 DMA_TxIntrHandler函数

/*****************************************************************************/

/*

*

* This is the DMA TX Interrupt handler function.

*

* It gets the interrupt status from the hardware, acknowledges it, and if any

* error happens, it resets the hardware. Otherwise, if a completion interrupt

* is present, then sets the TxDone.flag

*

* @param Callback is a pointer to TX channel of the DMA engine.

*

* @return None.

*

* @note None.

*

******************************************************************************/

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 = 1;

/*

* Reset should never fail for transmit channel

*/

XAxiDma_Reset(AxiDmaInst);

TimeOut = RESET_TIMEOUT_COUNTER;

while (TimeOut) {

if (XAxiDma_ResetIsDone(AxiDmaInst)) {

break;

}

TimeOut -= 1;

}

return;

}

/*

* If Completion interrupt is asserted, then set the TxDone flag

*/

if ((IrqStatus & XAXIDMA_IRQ_IOC_MASK)) {

TxDone = 1;

}

}

接收中断函数的原理和发送一样

XAxiDma *AxiDmaInst = (XAxiDma *)Callback;这句代码是为了获取当前中断的对象。void *Callback是一个无符号的指针,传递进来的阐述可以强制转换成其他任何的对象,这里就是强制转换成 XAxiDma 对象了。

IrqStatus = XAxiDma_IntrGetIrq(AxiDmaInst, XAXIDMA_DEVICE_TO_DMA);这个函数是获取当前中断号。

XAxiDma_IntrAckIrq(AxiDmaInst, IrqStatus, XAXIDMA_DEVICE_TO_DMA);这个函数是响应当前中断,通知CPU 当前中断已经被接收,并且清除中断标志位。

如果中断全部正确,RxDone将被置为1表示接收中断完成。

如果有错误,则复位DMA,并且设置超时参数

表1-3-3-2 DMA_RxIntrHandler函数

/*****************************************************************************/

/*

*

* This is the DMA RX interrupt handler function

*

* It gets the interrupt status from the hardware, acknowledges it, and if any

* error happens, it resets the hardware. Otherwise, if a completion interrupt

* is present, then it sets the RxDone flag.

*

* @param Callback is a pointer to RX channel of the DMA engine.

*

* @return None.

*

* @note None.

*

******************************************************************************/

static void DMA_RxIntrHandler(void *Callback)

{

u32 IrqStatus;

int TimeOut;

XAxiDma *AxiDmaInst = (XAxiDma *)Callback;

/* Read pending interrupts */

IrqStatus = XAxiDma_IntrGetIrq(AxiDmaInst, XAXIDMA_DEVICE_TO_DMA);

/* Acknowledge pending interrupts */

XAxiDma_IntrAckIrq(AxiDmaInst, IrqStatus, XAXIDMA_DEVICE_TO_DMA);

/*

* 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 = 1;

/* Reset could fail and hang

* NEED a way to handle this or do not call it??

*/

XAxiDma_Reset(AxiDmaInst);

TimeOut = RESET_TIMEOUT_COUNTER;

while (TimeOut) {

if(XAxiDma_ResetIsDone(AxiDmaInst)) {

break;

}

TimeOut -= 1;

}

return;

}

/*

* If completion interrupt is asserted, then set RxDone flag

*/

if ((IrqStatus & XAXIDMA_IRQ_IOC_MASK)) {

RxDone = 1;

}

}

表1-3-3-3 DMA_CheckData函数

/*****************************************************************************/

/*

*

* This function checks data buffer after the DMA transfer is finished.

*

* We use the static tx/rx buffers.

*

* @param Length is the length to check

* @param StartValue is the starting value of the first byte

*

* @return

* - XST_SUCCESS if validation is successful

* - XST_FAILURE if validation is failure.

*

* @note None.

*

******************************************************************************/

int DMA_CheckData(int Length, u8 StartValue)

{

u8 *RxPacket;

int Index = 0;

u8 Value;

RxPacket = (u8 *) RX_BUFFER_BASE;

Value = StartValue;

/* Invalidate the DestBuffer before receiving the data, in case the

* Data Cache is enabled

*/

#ifndef __aarch64__

Xil_DCacheInvalidateRange((u32)RxPacket, Length);

#endif

for(Index = 0; Index < Length; Index++) {

if (RxPacket[Index] != Value) {

xil_printf("Data error %d: %x/%x\r\n",

Index, RxPacket[Index], Value);

return XST_FAILURE;

}

Value = (Value + 1) & 0xFF;

}

return XST_SUCCESS;

}

1.3.4 dam_intr.h 文件分析

一般把DMA相关变量、常量、函数的声明或者定义放到头文件中,dam_intr.h比较关键的参数有

TX_BUFFER_BASE定义了DMA发送缓存的基地址

RX_BUFFER_BASE 定义了DMA接收缓存的基地址

MAX_PKT_LEN 表示每一包数据传输的长度

NUMBER_OF_TRANSFERS 用在连续测试的时候的测试次数

TEST_START_VALUE 用于 测试的起始参数

int  DMA_CheckData(int Length, u8 StartValue); 对数据进行对比

int  DMA_Setup_Intr_System(XScuGic * IntcInstancePtr,XAxiDma * AxiDmaPtr, u16 TxIntrId, u16 RxIntrId);DMA 中断注册

int  DMA_Intr_Enable(XScuGic * IntcInstancePtr,XAxiDma *DMAPtr); DMA中断使能

int  DMA_Intr_Init(XAxiDma *DMAPtr,u32 DeviceId);DMA中断初始化

表1-3-4 dam_intr.h

/*

*

* www.osrc.cn

* www.milinker.com

* copyright by nan jin mi lian dian zi www.osrc.cn

*/

#ifndef DMA_INTR_H

#define DMA_INTR_H

#include "xaxidma.h"

#include "xparameters.h"

#include "xil_exception.h"

#include "xdebug.h"

#include "xscugic.h"

/************************** Constant Definitions *****************************/

/*

* Device hardware build related constants.

*/

#define DMA_DEV_ID XPAR_AXIDMA_0_DEVICE_ID

#define MEM_BASE_ADDR 0x01000000

#define RX_INTR_ID XPAR_FABRIC_AXI_DMA_0_S2MM_INTROUT_INTR

#define TX_INTR_ID XPAR_FABRIC_AXI_DMA_0_MM2S_INTROUT_INTR

#define TX_BUFFER_BASE (MEM_BASE_ADDR + 0x00100000)

#define RX_BUFFER_BASE (MEM_BASE_ADDR + 0x00300000)

#define RX_BUFFER_HIGH (MEM_BASE_ADDR + 0x004FFFFF)

/* Timeout loop counter for reset

*/

#define RESET_TIMEOUT_COUNTER 10000

/* test start value

*/

#define TEST_START_VALUE 0xC

/*

* Buffer and Buffer Descriptor related constant definition

*/

#define MAX_PKT_LEN 256//4MB

/*

* transfer times

*/

#define NUMBER_OF_TRANSFERS 100000

extern volatile int TxDone;

extern volatile int RxDone;

extern volatile int Error;

int  DMA_CheckData(int Length, u8 StartValue);

int  DMA_Setup_Intr_System(XScuGic * IntcInstancePtr,XAxiDma * AxiDmaPtr, u16 TxIntrId, u16 RxIntrId);

int  DMA_Intr_Enable(XScuGic * IntcInstancePtr,XAxiDma *DMAPtr);

int  DMA_Intr_Init(XAxiDma *DMAPtr,u32 DeviceId);

#endif

1.4测试结果

Step1:在VIVADO工程中点击Open Target 然后点击Auto Connect(前面必须先启动SDK)

Step2:连接成功后入下图

Step3:设置中断条件,以及观察波形的偏移为500,当中断触发的时候,如下图所示

点击添加接收内存部分地址用于观察内存中的数据 地址为 0X01300000

为了观察到以下数据,设置断点,之让收发程序先跑一次,可以看到第一个数据是0X0C 后面是依次加1

S03_CH01_AXI_DMA_LOOP 环路测试的更多相关文章

  1. 利用ZYNQ SOC快速打开算法验证通路(4)——AXI DMA使用解析及环路测试

    一.AXI DMA介绍 本篇博文讲述AXI DMA的一些使用总结,硬件IP子系统搭建与SDK C代码封装参考米联客ZYNQ教程.若想让ZYNQ的PS与PL两部分高速数据传输,需要利用PS的HP(高性能 ...

  2. 转:(WIN)S04-CH01 PCIE XDMA开发环境搭建以及环路测试

    摘要: 这一章开始主要介绍 XILINX FPGA PICE IP XDMA IP的使用.XDMA IP使用部分教程分LINUX 篇和WINDOWS篇两个部分.通过实战,面向应用,提供给大家 XILI ...

  3. S03_CH09_DMA_4_Video_Switch视频切换系统

    S03_CH09_DMA_4_Video_Switch视频切换系统 9.1概述 本例程详细创建过程和本季课程第一课<S03_CH01_AXI_DMA_LOOP 环路测试>非常类似,因此如果 ...

  4. S03_CH08_DMA_LWIP以太网传输

    S03_CH08_DMA_LWIP以太网传输 8.1概述 本例程详细创建过程和本季课程第一课<S03_CH01_AXI_DMA_LOOP 环路测试>非常类似,因此如果读者不清楚如何创建工程 ...

  5. S03_CH02_AXI_DMA PL发送数据到PS

    S03_CH02_AXI_DMA PL发送数据到PS 1.1概述 本课程的设计原理分析. 本课程循序渐进,承接<S03_CH01_AXI_DMA_LOOP 环路测试>这一课程,在DATA ...

  6. xilinx DMA IP核(一) —— loop测试 代码注释

    本篇笔记中的代码来自:米联科技的教程“第三季第一篇的DMA_LOOP环路测试” 硬件的连接如下图所示: 图:DMA Loop Block Design 橘色的线就是DMA加FIFO组成的一个LOOP循 ...

  7. 单片机设计与KeilC编程总结

    1基本原则    质量是关键.没有人会对很差的工作感到满足.当完成高质量的工作时,你会为此而感到骄傲.不管你是否知道,你都会因为你的高质量工作而得到信誉.因此,要想为自己所做的事感到骄傲,就需要建立个 ...

  8. 那些年,用C#调用过的外部Dll

    经常有人找到我咨询以前在csdn资源里分享的dll调用.算算也写过N多接口程序.翻一翻试试写篇随笔. 明华IC读写器DLL 爱迪尔门锁接口DLL 通用OPOS指令打印之北洋pos打印机dll 明泰非接 ...

  9. Linux系统声卡问题

    问题:Linux系统中有声卡设备,但是听不到声音 一.声卡驱动没有安装 1.通过插拔声卡查出声卡驱动 2.在相应的kernel中编译内核 修改保存.config文件,然后进行编译 make -j ma ...

随机推荐

  1. 使用axios请求的坑

    配置axios在vue-cli中的使用: 在main.js中配置 import axios from "axios" Vue.config.productionTip = fals ...

  2. springmvc返回json对象

    1.引入jackson的依赖 <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -- ...

  3. javascript中稀疏数组和密集数组

    密集数组 数组是一片连续的存储空间,有着固定的长度.加入数组其实位置是address,长度为n,那么占用的存储空间是address[0],address[1],address[2].......add ...

  4. 网络文件共享服务—NFS服务

    NFS服务 NFS:Network File System 网络文件系统,基于内核的文件系统: Sun公司开发,通过使用NFS,用户和程序可以像访问本地文件一样访问远端系统上的文件,基于RPC(Rem ...

  5. Flutter移动电商实战 --(37)路由_Fluro引入和商品详细页建立

    https://github.com/theyakka/fluro pages/details_page.dart新建页面 使用路由 先添加路由插件的引用 fluro: ^1.4.0 如果网络上下载不 ...

  6. Flutter移动电商实战 --(22)JSON解析和复杂数据模型转换技巧

    json转Model类 创建model文件夹,在里面新建category.dart类 主要根据这个json来分析我们要做成类的样子 { "code": "0", ...

  7. kotlin标准委托之可观察属性

    所谓可观察属性就是当属性变化时可以拦截其变化,实现观察属性值变化的委托函数是Delegates.observable.该函数接受二个参数,第一个是初始化值,第2个属性值变化事件的响应器.每次我们向属性 ...

  8. centos7.4出现yum command not found

    购买的云服务器运行yum命令出现yum command not found. 通过将云主机自带的yum和python卸载掉,并且同时需要关注/usr/bin/yum文件的首行解释.我定义其为" ...

  9. 生产者-消费者问题与quene模块

    生产者-消费者问题与quene模块 下面使用线程锁以及队列来模拟一个典型的案例:生产者-消费者模型.在这个场景下,商品或服务的生产者生产商品,然后将其放到类似队列的数据结构中,生产商品的时间是不确定的 ...

  10. CockroachDB学习笔记——[译]Scaling Raft

    原文链接:https://www.cockroachlabs.com/blog/scaling-raft/ 原作者:Ben Darnell 原文日期:Jun 11, 2015 译:zifeiy 在Co ...