c语言实现axi通信,AXI DMA详解与应用篇 | 第二讲、AXI DMA工程搭建及SDK代码分析

在上一篇中着重讲解了DMA的含义和AXI_DMA_IP,本次的重点就是搭建一个AXI_DMA环路工程,并从C语言角度分析其SDK代码

一、AXI_DMA工程设计

在工程设计中,DMA一般与产生数据或需求数据的IP相连,该IP core可以是带有AXI_Stream接口的高速AD或DA IP核,实验中使用AXI-Stream Data Fifo IP核作为该类IP进行DMA环回实验:

核心部分为:

在处理器系统中,PL侧的DMA通过HP接口从DDR中读取数据,AXI DMA核作为AXIS Data FIFO和AXI4内存映射之间提供高宽带直接存储访问。

二、SDK代码分析

在工程设计中,PL侧配置好IP core之后生成含有配置参数的比特流文件,将其导出到SDK中,PS侧通过对PL侧配置参数的查询,执行IP核的配置。

注意:位于PL侧的属于PS的可配置模块的配置是由PL完成的,但是执行是由PS实现的!

代码分析:

#include “xaxidma.h”

#include “xparameters.h”

#include “xil_exception.h”

#include “xscugic.h”

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

#define DMA_DEV_ID XPAR_AXIDMA_0_DEVICE_ID //位于PL侧的DMA,xparameters.h

// DMA接收与发送通道的中断ID

#define RX_INTR_ID XPAR_FABRIC_AXIDMA_0_S2MM_INTROUT_VEC_ID

#define TX_INTR_ID XPAR_FABRIC_AXIDMA_0_MM2S_INTROUT_VEC_ID

//定义设备

#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID

//定义DDR的基地址

#define DDR_BASE_ADDR XPAR_PS7_DDR_0_S_AXI_BASEADDR //0x00100000

//定义内存的地址

#define MEM_BASE_ADDR (DDR_BASE_ADDR + 0x1000000) //0x01100000

//定义发送缓冲区的基地址

#define TX_BUFFER_BASE (MEM_BASE_ADDR + 0x00100000) //0x01200000

//定义接收缓冲区的基地址

#define RX_BUFFER_BASE (MEM_BASE_ADDR + 0x00300000) //0x01400000

//定义一个复位时间计数器

#define RESET_TIMEOUT_COUNTER 10000 //复位时间

//定义一个测试的起始值

#define TEST_START_VALUE 0x0 //测试起始值

//定义测试长度

#define MAX_PKT_LEN 0x100 //发送包长度

/************************** Function Prototypes ******************************/

//数据核验函数

static int check_data(int length, u8 start_value);

//发送中断的处理函数

static void tx_intr_handler(void *callback);

//接收中断的处理函数

static void rx_intr_handler(void *callback);

//建立中断系统

static int setup_intr_system(XScuGic * int_ins_ptr, XAxiDma * axidma_ptr,

u16 tx_intr_id, u16 rx_intr_id);

//禁用中断函数

static void disable_intr_system(XScuGic * int_ins_ptr, u16 tx_intr_id,

u16 rx_intr_id);

/************************** Variable Definitions *****************************/

static XAxiDma axidma; //XAxiDma实例

static XScuGic intc; //中断控制器的实例

volatile int tx_done; //发送完成标志

volatile int rx_done; //接收完成标志

volatile int error; //传输出错标志

/************************** Function Definitions *****************************/

int main(void)

{

int status;

u8 value;

/* 等价于

u8 tx_buffer_ptr[MAX_PKT_LEN]; //发送缓冲区指针,指针指向的数据为8bit无符 数

u8 rx_buffer_ptr[MAX_PKT_LEN]; //接受缓冲区指针,指针指向的数据为8bit无符 数

*/

u8* tx_buffer_ptr; //发送缓冲区指针,指针指向的数据为8bit无符 数

u8* rx_buffer_ptr; //接受缓冲区指针,指针指向的数据为8bit无符 数

/*

XAxiDma_Config是一个AXI_DMA配置的信息结构体,它里面包含需要配置的各种信息,

类似于一个空表,表里面有各种需要填的事项,

填表的方式是将AXI_DMA的设备 作为传入参数传递到XAxiDma_LookupConfig查找函数中,

如果传输的设备 和函数内部的设备 一样的话,就将根据PL侧的设计参数传递给查找表

*/

XAxiDma_Config *config;

/*

从C语言的角度看指针

TX_BUFFER_BASE与RX_BUFFER_BASE都是一个地址,在地址前面加上(u8 *)修饰符,

这样理解:

a=8’b1;

u8* p;

*p=(u8*)(&a);

p=就是a的地址

此处解释:

(u8 *) TX_BUFFER_BASE;

将TX_BUFFER_BASE转换成指向8位无符 数指针的内容

然后这个地址传递给tx_buffer_ptr

(u8*)的作用是指针该地址指向的数据为8bit无符 数,不可以多操作或者少操作

*/

tx_buffer_ptr = (u8 *) TX_BUFFER_BASE;

rx_buffer_ptr = (u8 *) RX_BUFFER_BASE;

xil_printf(“rn— Entering main() — rn”);

/*

进行DMA配置参数传递

通过调用DMA查找配置函数,传入设备ID,获取设备参数

需要注意的是,其中的参数是根据PL端的IP core的配置选项生成的参数

*/

config = XAxiDma_LookupConfig(DMA_DEV_ID);

if (!config) {

xil_printf(“No config found for %drn”, DMA_DEV_ID);

return XST_FAILURE;

}

/*

//初始化DMA引擎

根据PL端对DMA core的配置参数,PS对DMA进行真正的配置初始化过程,

axidma还存储在PS端的AXI——DMA配置表,根据对PL参数的读取,

PS运行对PL侧的DMA配置,这个配置过程是通过GP0接口对AXI_Lite4总线的控制完成的

*/

status = XAxiDma_CfgInitialize(&axidma, config);

if (status != XST_SUCCESS) {

xil_printf(“Initialization failed %drn”, status);

return XST_FAILURE;

}

/*

我们配置的是使用PL侧DMA的直接寄存器访问模式,所以数据传递也是通过该方式运行的,

为了以防万一,在这里运行一下SG查询函数看看是不是配置成了SG模式

*/

if (XAxiDma_HasSg(&axidma)) {

xil_printf(“Device configured as SG mode rn”);

return XST_FAILURE;

}

/*

//建立中断系统,详见函数定义

CallBackRef is the callback reference, usually the instance pointer of the connecting driver.

CallBackRef是回调引用,通常是连接驱动程序的实例指针。

axidma是这些传入参数里面最没用的东西,不过还是保留的

对于中断系统,分为PPI(私有外设中断)、SGI(软件生成中断)、SPI(共享外设中断)

我们在中断系统中根据AXI_DMA的接收发送中断 注册两种中断

axidma作用不大,起码没有直接感觉出来,解释中只是说axidma是回调引用,通常连接到驱动程序的实例指针,所以前面有一个取地址&

*/

status = setup_intr_system(&intc, &axidma, TX_INTR_ID, RX_INTR_ID);

if (status != XST_SUCCESS) {

xil_printf(“Failed intr setuprn”);

return XST_FAILURE;

}

//建立好中断系统后,初始化标志信

tx_done = 0;

rx_done = 0;

error = 0;

//对要写入的数据赋值

value = TEST_START_VALUE;

for (int i = 0; i CpuBaseAddress);

if (status != XST_SUCCESS) {

return XST_FAILURE;

}

//设置优先级和触发类型

XScuGic_SetPriorityTriggerType(int_ins_ptr, tx_intr_id, 0xA0, 0x3);

XScuGic_SetPriorityTriggerType(int_ins_ptr, rx_intr_id, 0xA0, 0x3);

//为中断设置中断处理函数

status = XScuGic_Connect(int_ins_ptr, tx_intr_id,

(Xil_InterruptHandler) tx_intr_handler, axidma_ptr);

if (status != XST_SUCCESS) {

return status;

}

status = XScuGic_Connect(int_ins_ptr, rx_intr_id,

(Xil_InterruptHandler) rx_intr_handler, axidma_ptr);

if (status != XST_SUCCESS) {

return status;

}

XScuGic_Enable(int_ins_ptr, tx_intr_id);

XScuGic_Enable(int_ins_ptr, rx_intr_id);

//启用来自硬件的中断

Xil_ExceptionInit();

Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,

(Xil_ExceptionHandler) XScuGic_InterruptHandler,

(void *) int_ins_ptr);

Xil_ExceptionEnable();

//使能DMA中断

XAxiDma_IntrEnable(&axidma, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DMA_TO_DEVICE);

XAxiDma_IntrEnable(&axidma, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA);

return XST_SUCCESS;

}

//此函数禁用DMA引擎的中断

static void disable_intr_system(XScuGic * int_ins_ptr, u16 tx_intr_id,

u16 rx_intr_id)

{

XScuGic_Disconnect(int_ins_ptr, tx_intr_id);

XScuGic_Disconnect(int_ins_ptr, rx_intr_id);

}

下一期预告:ZYNQ Cache一致性问题分析

文章知识点与官方知识档案匹配,可进一步学习相关知识C技能树首页概览114462 人正在系统学习中 相关资源:2012年下半年软件设计师上午试题及答案-软考等考文档类资源-CSDN…

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2021年4月18日
下一篇 2021年4月18日

相关推荐