ZYNQ linux下AXI_BRAM的使用方法,PS与PL端数据交互

2023-11-01 02:40

本文主要是介绍ZYNQ linux下AXI_BRAM的使用方法,PS与PL端数据交互,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1、AXI总线、AXI接口、AXI协议
总线是一组传输通道,是各种逻辑器件构成的传输数据的通道;接口是一种连接标准,又常被称为物理接口;协议是数据传输的规则。

PS与PL连接方式主要是通过AXI总线进行的。ZYNQ上的总线协议有AXI4, AXI4-Lite, AXI4-Stream三种总线协议。而PS与PL之间的接口(AXI-GP、AXI-HP、AXI-ACP)只支持AXI4与AXI4-Lite这两种总线协议。

2、BRAM简介
Block RAM是PL部分的存储器阵列,就相当于在PL中开辟一片空间来存储数据,通过端口来进行读写。
BRAM设置模式:
1、单端口:通过一个端口对BRAM进行读写。
2、简单双端口:有两个端口连接到BRAM,一个端口只读,一个端口只写
3、真双端口:两个端口都可以对BRAM进行读写。

3、vivado设计
前提:创建好了工程并导入了ZYNQ核

打开AXI GP0 和 AXI GP1的接口
在这里插入图片描述
在这里插入图片描述

将M_AXI_GP0_ACLK连接到FCLK_CLK0
在这里插入图片描述

导入两个BRAM 控制器
在这里插入图片描述

在这里插入图片描述
设置为单端口

在这里插入图片描述

导入一个BRAM
在这里插入图片描述

设置为真双端口模式

在这里插入图片描述
进行设计连接
在这里插入图片描述
进行1的时候需要修改主机从GP0 改为GP1
在这里插入图片描述
最终的生成图
在这里插入图片描述
可以在address editor中查看自动分配的BRAM控制器的地址,不要随意更改地址,因为其他地址可能被其他设备占用了。
axi_bram_ctrl_0 0x40000000
axi_bram_ctrl_1 0x80000000

在这里插入图片描述

接下来生成bit流,将硬件资源导入petlainux中,生成BOOT.BIN 和image.ub

将生成的BOOT.BIN和内核放到板子上,启动系统。

进行编程:


#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>#define BRAM_CTRL_0 0x40000000
#define BRAM_CTRL_1 0x80000000
#define DATA_LEN    10int main(int argc, char **argv)
{unsigned int *map_base0;unsigned int *map_base1;int fd = open("/dev/mem", O_RDWR | O_SYNC);if (fd < 0) {printf("can not open /dev/mem \n");return (-1);}   printf("/dev/mem is open \n");map_base0 = mmap(NULL, DATA_LEN * 4, PROT_READ | PROT_WRITE, MAP_SHARED, fd, BRAM_CTRL_0);map_base1 = mmap(NULL, DATA_LEN * 4, PROT_READ | PROT_WRITE, MAP_SHARED, fd, BRAM_CTRL_1);if (map_base0 == 0 || map_base1 == 0 ) { printf("NULL pointer\n");}   else {printf("mmap successful\n");}   unsigned long addr;unsigned int content;int i = 0;printf("\nwrite data to bram\n");for (i = 0; i < DATA_LEN; i++) {addr = (unsigned long)(map_base0 + i); content = i + 2;map_base0[i] = content;printf("%2dth data, address: 0x%lx data_write: 0x%x\t\t\n", i, addr, content);}   printf("\nread data from bram\n");for (i = 0; i< DATA_LEN; i++) {addr = (unsigned long)(map_base1 + i); content = map_base1[i];printf("%2dth data, address: 0x%lx data_read: 0x%x\t\t\n", i, addr, content);}   close(fd);munmap(map_base0, DATA_LEN);munmap(map_base1, DATA_LEN);return 0;
}

运行效果
在这里插入图片描述

也可以将BRAM与socket进行联合使用,将PC端的数据发到PS端,PS端放在PL端,PL端再发给PS端,PS端发回PC端。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <fcntl.h>
#define PORT 3333#define BRAM_CTRL0 0x40000000
#define BRAM_CTRL1 0x80000000
#define DATA_LEN   100unsigned int *map_base0;
unsigned int *map_base1;void udp_server(int sockfd)
{socklen_t len;struct sockaddr_in server_addr;int n;int opt = 1;len = sizeof(server_addr);server_addr.sin_family = AF_INET;server_addr.sin_addr.s_addr = htonl(INADDR_ANY);server_addr.sin_port = htons(PORT);setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {printf("can not bind\n");exit(1);}   while (1) {printf("\n========wait for client's request========\n");n = recvfrom(sockfd, map_base0, 1024, 0, (struct sockaddr *)&server_addr, &len);char buf[1024];memcpy(buf, map_base0, 1024);printf("\nreceive client's data: %s\n", buf);sendto(sockfd, map_base0, n, 0, (struct sockaddr *)&server_addr, len);memcpy(buf, map_base1, 1024);printf("\nsend data to client: %s\n", buf);}close(sockfd);
}int main(int argc, char **argv)
{int sockfd, devfd;if ((sockfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {printf("create socket false\n");exit(1);}if ((devfd = open("/dev/mem", O_RDWR | O_SYNC)) < 0) {printf("can not open /dev/mem \n");return (-1);}printf("\nopen /dev/mem successful\n");map_base0 = mmap(NULL, DATA_LEN * 4, PROT_READ | PROT_WRITE, MAP_SHARED, devfd, BRAM_CTRL0);map_base1 = mmap(NULL, DATA_LEN * 4, PROT_READ | PROT_WRITE, MAP_SHARED, devfd, BRAM_CTRL1);if (map_base0 ==0 || map_base1 == 0) {printf("NULL pointer \n");}else {printf("mmap successful\n");}udp_server(sockfd);exit(0);
}

最终实现相关效果

在这里插入图片描述

这篇关于ZYNQ linux下AXI_BRAM的使用方法,PS与PL端数据交互的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/319908

相关文章

Java中的StringUtils.isBlank()方法解读

《Java中的StringUtils.isBlank()方法解读》:本文主要介绍Java中的StringUtils.isBlank()方法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑... 目录所在库及依赖引入方法签名方法功能示例代码代码解释与其他方法的对比总结StringUtils.isBl

使用Vue-ECharts实现数据可视化图表功能

《使用Vue-ECharts实现数据可视化图表功能》在前端开发中,经常会遇到需要展示数据可视化的需求,比如柱状图、折线图、饼图等,这类需求不仅要求我们准确地将数据呈现出来,还需要兼顾美观与交互体验,所... 目录前言为什么选择 vue-ECharts?1. 基于 ECharts,功能强大2. 更符合 Vue

如何合理使用Spring的事务方式

《如何合理使用Spring的事务方式》:本文主要介绍如何合理使用Spring的事务方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、介绍1.1、底层构造1.1.事务管理器1.2.事务定义信息1.3.事务状态1.4.联系1.2、特点1.3、原理2. Sprin

Vue中插槽slot的使用示例详解

《Vue中插槽slot的使用示例详解》:本文主要介绍Vue中插槽slot的使用示例详解,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录一、插槽是什么二、插槽分类2.1 匿名插槽2.2 具名插槽2.3 作用域插槽三、插槽的基本使用3.1 匿名插槽

使用WPF实现窗口抖动动画效果

《使用WPF实现窗口抖动动画效果》在用户界面设计中,适当的动画反馈可以提升用户体验,尤其是在错误提示、操作失败等场景下,窗口抖动作为一种常见且直观的视觉反馈方式,常用于提醒用户注意当前状态,本文将详细... 目录前言实现思路概述核心代码实现1、 获取目标窗口2、初始化基础位置值3、创建抖动动画4、动画完成后

PyQt5 QDate类的具体使用

《PyQt5QDate类的具体使用》QDate是PyQt5中处理日期的核心类,本文主要介绍了PyQt5QDate类的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价... 目录核心功能常用方法及代码示例​1. 创建日期对象​2. 获取日期信息​3. 日期计算与比较​4. 日

Java如何根据word模板导出数据

《Java如何根据word模板导出数据》这篇文章主要为大家详细介绍了Java如何实现根据word模板导出数据,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... pom.XML文件导入依赖 <dependency> <groupId>cn.afterturn</groupId>

Go语言使用slices包轻松实现排序功能

《Go语言使用slices包轻松实现排序功能》在Go语言开发中,对数据进行排序是常见的需求,Go1.18版本引入的slices包提供了简洁高效的排序解决方案,支持内置类型和用户自定义类型的排序操作,本... 目录一、内置类型排序:字符串与整数的应用1. 字符串切片排序2. 整数切片排序二、检查切片排序状态:

CentOS7增加Swap空间的两种方法

《CentOS7增加Swap空间的两种方法》当服务器物理内存不足时,增加Swap空间可以作为虚拟内存使用,帮助系统处理内存压力,本文给大家介绍了CentOS7增加Swap空间的两种方法:创建新的Swa... 目录在Centos 7上增加Swap空间的方法方法一:创建新的Swap文件(推荐)方法二:调整Sww

QT6中绘制UI的两种方法详解与示例代码

《QT6中绘制UI的两种方法详解与示例代码》Qt6提供了两种主要的UI绘制技术:​​QML(QtMeta-ObjectLanguage)​​和​​C++Widgets​​,这两种技术各有优势,适用于不... 目录一、QML 技术详解1.1 QML 简介1.2 QML 的核心概念1.3 QML 示例:简单按钮