当前位置: 首页 > news >正文

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

本文转载自: 根究FPGA

在上一篇中着重讲解了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环回实验:

8b7977d5a2c6e64f3ef8e46337083293.png

处理器通过M_AXI_GP0接口和AXI_DMA通信,以设置、启动和监控数据传输。数据传输通过S_AXI_HP0接口。

BD框图:

7170225729a0b1f718ff28f1c86def5f.png

核心部分为:

f9f37debe6c6dac218d6d1f2529fd436.png

在处理器中含有之前的:

a4ca04a3ca032e99c086d300e4ee0d91.png

在处理器系统中,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("\r\n--- Entering main() --- \r\n");

/*

进行DMA配置参数传递

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

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

*/

config = XAxiDma_LookupConfig(DMA_DEV_ID);

if (!config) {

xil_printf("No config found for %d\r\n", 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 %d\r\n", status);

return XST_FAILURE;

}

/*

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

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

*/

if (XAxiDma_HasSg(&axidma)) {

xil_printf("Device configured as SG mode \r\n");

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 setup\r\n");

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语言,[转载]产生随机数源程序
  • linux lru cache,注解版spring实现LruCache存储数据
  • android ui组件 推荐,GitHub - zzti/XUI: 一个简洁而优雅的Android原生UI框架,解放你的双手!...
  • android 动画推动,android – 动画视图从另一个视图中滑出,推动下面的视图
  • Android10如何删除应用程序,谷歌安卓10新特性:应用卸载时可保留数据
  • android listview只显示一行数据,解决ScrollView中嵌套 listView只显示1行的问题
  • android file 4.4.1,vuejs文件在android低版本中(5.1,4.4)报错。导致页面空白
  • win7小米手机驱动安装是 其他设备内不显示android,win7系统连接小米4手机不显示“便捷式盘符”的解决方法...
  • 小米装android4.4,刷机之家教你设置小米MIUI/Android 4.4双系统(二)
  • android开源系统brvah,Brvah——一个强大的Adapter框架
  • html5改变窗口大小,js怎么改变窗口大小?js改变窗口大小方法
  • html网页设计需求分析,网页设计需求分析方法
  • 2021兰州三中高考成绩查询,2021兰州中考(初中学业水平测试)多少分考入高中 分数控制线预测分析...
  • 少数民族高考成绩查询2021,内蒙古2021高考民族汉考三级成绩查询时间及方法 什么时候查询...
  • 计算机专业英语考试题库,计算机专业英语-中国大学mooc-题库零氪
  • 【划重点】MySQL技术内幕:InnoDB存储引擎
  • Android交互
  • FastReport在线报表设计器工作原理
  • java第三方包学习之lombok
  • Js基础知识(一) - 变量
  • Linux gpio口使用方法
  • Nacos系列:Nacos的Java SDK使用
  • Spring思维导图,让Spring不再难懂(mvc篇)
  • 从伪并行的 Python 多线程说起
  • 关于使用markdown的方法(引自CSDN教程)
  • 诡异!React stopPropagation失灵
  • 微信端页面使用-webkit-box和绝对定位时,元素上移的问题
  • 吴恩达Deep Learning课程练习题参考答案——R语言版
  • 格斗健身潮牌24KiCK获近千万Pre-A轮融资,用户留存高达9个月 ...
  • %check_box% in rails :coditions={:has_many , :through}
  • (1)虚拟机的安装与使用,linux系统安装
  • (C语言)编写程序将一个4×4的数组进行顺时针旋转90度后输出。
  • (MATLAB)第五章-矩阵运算
  • (Note)C++中的继承方式
  • (solr系列:一)使用tomcat部署solr服务
  • (附源码)springboot码头作业管理系统 毕业设计 341654
  • (九)c52学习之旅-定时器
  • (每日持续更新)jdk api之FileFilter基础、应用、实战
  • (七)MySQL是如何将LRU链表的使用性能优化到极致的?
  • (三)mysql_MYSQL(三)
  • (转)EXC_BREAKPOINT僵尸错误
  • (转)利用ant在Mac 下自动化打包签名Android程序
  • (转载)Google Chrome调试JS
  • ***汇编语言 实验16 编写包含多个功能子程序的中断例程
  • ./include/caffe/util/cudnn.hpp: In function ‘const char* cudnnGetErrorString(cudnnStatus_t)’: ./incl
  • .net core 6 集成和使用 mongodb
  • .net6Api后台+uniapp导出Excel
  • .NET构架之我见
  • .secret勒索病毒数据恢复|金蝶、用友、管家婆、OA、速达、ERP等软件数据库恢复
  • /etc/sudoers (root权限管理)
  • /usr/local/nginx/logs/nginx.pid failed (2: No such file or directory)
  • ??javascript里的变量问题
  • [ai笔记9] openAI Sora技术文档引用文献汇总
  • [Android实例] 保持屏幕长亮的两种方法 [转]
  • [AUTOSAR][诊断管理][ECU][$37] 请求退出传输。终止数据传输的(上传/下载)