FPGA - ZYNQ 基于Axi_Lite的PS和PL交互

前言

在FPGA - ZYNQ 基于EMIO的PS和PL交互中介绍了ZYNQ 中PS端和PL端交互的开发流程,接下来构建基于基于Axi_Lite的PS和PL交互。

开发流程

Axi_Lite从机

在FPGA - AXI4_Lite(实现用户端与axi4_lite之间的交互逻辑)中,详解介绍了AXI4总线,以及AXI_LITE端口信号及其功能,其中axi4_lite 读写过程框架图中介绍了axi4_lite主机搭建过程。

接下来构建axi4_lite从机

Axi4_lite端口信号及其功能

根据axi_lite读写信号分析:

在这里我们需要构建axi4lite_slaveuser_ram

axi4lite_slave:

`timescale 1ns / 1ps

module axilite_slave #(
	parameter USER_WR_DATA_WIDTH    = 32 , //用户写数据位宽和AXI4―Lite数据位宽保持一致
    parameter USER_RD_DATA_WIDTH    = 32 , //用户读数据位宽和AXI4―Lite数据位宽保持一致
	parameter AXI_DATA_WIDTH 		= 32,  //AXI4_LITE总线规定,数据位宽只支持32Bit或者64bit
	parameter AXI_ADDR_WIDTH        = 32	
)(

	input       								    axi_clk,    
	input       								    reset,

	output  reg								        s_wr_vld,
	output  reg    [USER_WR_DATA_WIDTH-1:0]	        s_wr_data,
	output  reg    [AXI_ADDR_WIDTH-1 :0]		    s_wr_addr,

	output  reg								        s_rd_addr_vld,
	output  reg    [AXI_ADDR_WIDTH-1 :0]		    s_rd_addr,
	input          [USER_RD_DATA_WIDTH-1:0]	        s_rd_data,
	input                                           s_rd_data_vld,

	input          [AXI_ADDR_WIDTH -1:0]  	        s_axi_awaddr, //axi write address channel
	input          [2:0] 				 	        s_axi_awprot, 
	input      		 				 	            s_axi_awvalid, 
	output reg    		 			 	            s_axi_awready,

	input          [AXI_DATA_WIDTH-1:0]	 	        s_axi_wdata,   //axi write data channel
	input          [AXI_DATA_WIDTH/8-1:0] 	        s_axi_wstrb,
	input           					 	        s_axi_wvalid,
	output  reg          					 	    s_axi_wready,

	output         [1:0]	         	            s_axi_bresp,  //axi wirte response channel
	output  reg	   			         	            s_axi_bvalid,
	input        			         	            s_axi_bready,

	input      		 							    s_axi_arvalid, // axi read address channel
	output  reg       		 					    s_axi_arready, 
	input          [AXI_ADDR_WIDTH-1:0] 			s_axi_araddr,
	input          [2:0] 							s_axi_arprot, 

	output  reg    [AXI_DATA_WIDTH-1:0]	    		s_axi_rdata,   // axi read data channel
	output         [1:0] 				    		s_axi_rresp,
	output  reg     					    		s_axi_rvalid,
	input        						   	 		s_axi_rready
    );

(* dont_touch="true" *) reg a_reset_sync_d0;
(* dont_touch="true" *) reg a_reset_sync_d1;
(* dont_touch="true" *) reg a_reset_sync;
/*------------------------------------------*\
               状态机信号定义
\*------------------------------------------*/
reg [1:0] wr_cur_status;
reg [1:0] wr_nxt_status;
reg [1:0] rd_cur_status;
reg [1:0] rd_nxt_status;

localparam WR_IDLE    = 3'b000;
localparam WE_DATA    = 3'b001;
localparam WR_BRESP   = 3'b010;

localparam RD_IDLE    = 3'b000;
localparam RD_PRE     = 3'b001;
localparam RD_DATA    = 3'b010;

/*------------------------------------------*\
                 assign
\*------------------------------------------*/
assign s_axi_bresp = 0;
assign s_axi_rresp  = 0;

/*------------------------------------------*\
                     CDC
\*------------------------------------------*/
always @(posedge axi_clk) begin
	a_reset_sync_d0 <= reset;
	a_reset_sync_d1 <= a_reset_sync_d0;
	a_reset_sync    <= a_reset_sync_d1;
end

/*------------------------------------------*\
             AXILITE从机写过程
\*------------------------------------------*/
always @(posedge axi_clk) begin
    if (a_reset_sync) 
        wr_cur_status <= WR_IDLE;
    else 
        wr_cur_status <= wr_nxt_status;
end

always @(*) begin
    if (a_reset_sync) 
        wr_nxt_status <= WR_IDLE;
    else 
    	case(wr_cur_status)
    		WR_IDLE : begin
    			if (s_axi_awvalid && s_axi_wvalid) 
    				wr_nxt_status <= WE_DATA;
    			else 
    				wr_nxt_status <= wr_cur_status;
    		end
    		WE_DATA : begin
    			wr_nxt_status <= WR_BRESP;
    		end
    		WR_BRESP : begin
    			if (s_axi_bvalid && s_axi_bready) 
    				wr_nxt_status <= WR_IDLE;
    			else 
    				wr_nxt_status <= wr_cur_status;
    		end
    	    default : wr_nxt_status <= WR_IDLE;
    	endcase    
end

always @(*) begin
    if (a_reset_sync) begin
    	s_axi_awready <= 0;
    	s_axi_wready  <= 0;
    end  
    else begin
    	s_axi_awready <= wr_cur_status == WE_DATA;
    	s_axi_wready  <= wr_cur_status == WE_DATA;    	
    end  
end

always @(posedge axi_clk) begin
    if (a_reset_sync) 
        s_axi_bvalid <= 0;
    else if (s_axi_bvalid && s_axi_bready) 
        s_axi_bvalid <= 0;
    else if (wr_cur_status == WR_BRESP)
        s_axi_bvalid <= 1'b1;
    else 
    	s_axi_bvalid <= s_axi_bvalid;
end

always @(posedge axi_clk) begin
    if (wr_cur_status == WE_DATA) begin
    	s_wr_vld  <= 1'b1;
    	s_wr_data <= s_axi_wdata;
    	s_wr_addr <= s_axi_awaddr;
    end
    else begin
    	s_wr_vld  <= 0;
    	s_wr_data <= s_wr_data;
    	s_wr_addr <= s_wr_addr;    	
    end    
end

/*------------------------------------------*\
             AXILITE从机读过程
\*------------------------------------------*/
always @(posedge axi_clk) begin
    if (a_reset_sync) 
        rd_cur_status <= RD_IDLE;
    else 
        rd_cur_status <= rd_nxt_status;
end

always @(*) begin
    if (a_reset_sync) 
        rd_nxt_status <= RD_IDLE;
    else 
    	case(rd_cur_status)
    		RD_IDLE : begin
    			if (s_axi_arvalid)
    				rd_nxt_status <= RD_PRE;
    			else 
    				rd_nxt_status <= rd_cur_status;
    		end
    		RD_PRE : begin
    			rd_nxt_status <= RD_DATA;
    		end
    		RD_DATA : begin
    			if (s_axi_rvalid && s_axi_rready) 
    				rd_nxt_status <= RD_IDLE;
    			else 
    				rd_nxt_status <= rd_cur_status;	
    		end

    	    default : rd_nxt_status <= RD_IDLE;
    	endcase    
end

always @(*) begin
    if (a_reset_sync) 
        s_axi_arready <= 0; 
    else 
        s_axi_arready <= rd_cur_status == RD_PRE;
end

always @(posedge axi_clk) begin
    if (rd_cur_status == RD_PRE) begin
    	s_rd_addr_vld <= 1'b1;
    	s_rd_addr     <= s_axi_araddr;
    end
    else begin
    	s_rd_addr_vld <= 0;   
    	s_rd_addr     <= s_rd_addr; 	
    end     
end

always @(posedge axi_clk) begin
    if (a_reset_sync) begin
 		s_axi_rdata  <= 0;
 		s_axi_rvalid <= 0;
    end
    else if (s_axi_rvalid && s_axi_rready) begin
		s_axi_rvalid <= 0;
    end
    else if (s_rd_data_vld) begin
    	s_axi_rvalid <= 1'b1;
    	s_axi_rdata  <= s_rd_data;
    end
    else begin
    	s_axi_rvalid <= s_axi_rvalid;
    	s_axi_rdata  <= s_axi_rdata;
    end    
end

endmodule

user_ram

`timescale 1ns / 1ps



module user_ram #(
	parameter USER_WR_DATA_WIDTH 	=   32 ,
	parameter USER_RD_DATA_WIDTH 	=   32 ,
	parameter AXI_DATA_WIDTH        =   32 , //注意AXI4的数据位宽只有32Bit或者64bit
	parameter AXI_ADDR_WIDTH        =   32	
)(
	input                                           clk          ,
	input                                           reset        ,
	input  								            s_wr_vld     ,
	input      [USER_WR_DATA_WIDTH-1:0]	            s_wr_data    ,
	input      [AXI_ADDR_WIDTH-1 :0]		        s_wr_addr    ,

	input  								            s_rd_addr_vld,
	input      [AXI_ADDR_WIDTH-1 :0]		        s_rd_addr    ,
	output reg [USER_RD_DATA_WIDTH-1:0]	            s_rd_data    ,
	output reg                                      s_rd_data_vld

    );
localparam SIZE = 1024;
reg [AXI_DATA_WIDTH-1:0] ram [SIZE - 1 : 0] ;


always @(posedge clk) begin
    if (s_wr_vld) 
    	ram[s_wr_addr] <= s_wr_data;
end

always @(posedge clk) begin
    if (reset) begin
        s_rd_data_vld <= 0;
        s_rd_data     <= 0;
    end
    else if (s_rd_addr_vld) begin
    	s_rd_data_vld <= 1'b1;
    	s_rd_data     <= ram[s_rd_addr];
    end   
    else begin
    	s_rd_data_vld <= 0;
    	s_rd_data     <= 0;
    end
        
end
endmodule

IP核生成

在ZYNQ开发中,要将构建的axi4lite_slave和user_ram打包为 IP核

首先,创建新工程,将axi4lite_slave和user_ram代码导入:

点击OK

点击Finish

可以看到在Sources界面中已经有axi4lite_slave和user_ram文件

可以看到axi4lite_slave 是顶层。

---------------------------------------------------------------------------------------------------------------------------------

然后开始打包创建IP核

点击NEXT

选择IP保存位置 点击Next

点击OK

点击Finish

然后会弹出一个新工程:

这里是IP配置信息:

保持默认 然后点击Review and Package , 点击Package IP:

点击Yes

然后打开IP保存位置文件夹,可以看到如下:

点击src文件夹里面是axilite_slave.v文件

点击xgui文件夹是axilite_slave_v1_0.tcl文件
这样axilite_slave IP核打包完成。

然后切换user_ram文件为顶层:

右击user_ram文件 点击Set as Top

然后重复axilite_slave打包过程,

打开IP核存放地址

至此,axi4lite_slave和user_ram文件打包ip核完成。

---------------------------------------------------------------------------------------------------------------------------------

硬件系统搭建

搭建硬件系统

具体构建过程可见:

FPGA - ZYNQ 基于EMIO的PS和PL交互icon-default.png?t=N7T8https://blog.csdn.net/weixin_46897065/article/details/137865852?spm=1001.2014.3001.5501如下:

---------------------------------------------------------------------------------------------------------------------------------

然后需要将上面打包的IP核,加载到IP库中:

点击Seting ,再点击IP,然后点Repository

找到上面axi4lite_slave和user_ram IP 核存放位置,点击Select:

点击ok

然后搜索axilite_slave和user_ram:

双击添加,点击Run Block Automation

然后点击RUN connection Automation

连线完成如下:

---------------------------------------------------------------------------------------------------------------------------------

由于axi4lite_slave和user_ram 是高复位,所以删除原来的低复位,重新连接高复位引脚:

删除重新连接:

复位连接完成如下:

然后将axilite_slave 引脚 和user_ram 引脚相连:

连接完成如下:

然后点击重新布局:

然后点击验证设计:

点击OK 

然后按照FPGA - ZYNQ 基于EMIO的PS和PL交互中的开发流程:

生成封装,生成底层和顶层文件,

然后生成比特流,导出硬件,启动SDK。

---------------------------------------------------------------------------------------------------------------------------------

SDK 程序设计

创建SDK工程

点击空工程  点击finish

添加source file 

---------------------------------------------------------------------------------------------------------------------------------

在硬件系统搭建中,我们看到,自动连线后,会出现一个AXI Interconnect。如下图:

这个模块在PS设计中,通过API接口实现axilite读写。

基于自定义AXI_lite 与 PS  API接口 之间的映射关系

PS端API函数  和 AXI4_lite  总线的映射关系 对应关系
写入数据  Xil_Out32()函数
读出数据  Xil_In32()   函数 

1,利用API接口函数实现读写axilite读写:


#include "xparameters.h"
#include "sleep.h"
#include "xil_io.h"

#define AXI_LITE_BASEADDR 0x40000000

 通过函数编写

int main()
{
	u32 rddata;

	Xil_Out32(AXI_LITE_BASEADDR,1000);
	Xil_Out32(AXI_LITE_BASEADDR + 4,500);

	Xil_Out32(AXI_LITE_BASEADDR + 8,800);


	rddata = Xil_In32(AXI_LITE_BASEADDR);
	rddata = Xil_In32(AXI_LITE_BASEADDR + 4);
	return 0;
}

2,利用指针实现读写axilite读写:


#include "xparameters.h"
#include "sleep.h"
#include "xil_io.h"

#define AXI_LITE_BASEADDR 0x40000000

int main()
{
	u32* LitePtr  = (u32*)AXI_LITE_BASEADDR;  //强制转换 转为地址
	u32 wrdata = 0;
	u32 rddata = 0;

	int i = 0;

	//向PL写数据
	for (i = 0; i < 128; i++ )
	{
		*LitePtr++ = wrdata++;
	}

	LitePtr  = (u32*)AXI_LITE_BASEADDR;
	for (i = 0; i < 128; i++ )
	{
		rddata = *LitePtr++;
		printf("rddata= %d \n",rddata);
	}
	return 0;
}

最后,下载验证。

总结

        在这里,实现了基于Axi_Lite的PS和PL交互,和axilite_slave(axilite从机)的实现,以及自定义IP核的创建,并且在SDK程序中实现了2种axilite的读写。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/565173.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【学习笔记】Vue3源码解析:第五部分 - 实现渲染(3)

课程地址&#xff1a;【已完结】全网最详细Vue3源码解析&#xff01;&#xff08;一行行带你手写Vue3源码&#xff09; 第五部分-&#xff1a;&#xff08;对应课程的第36 - 37节&#xff09; 第36节&#xff1a;《处理proxy&#xff0c;方便取值》 1、执行组件中的 render 方…

BootstrapAdmin Net7:基于RBAC的后台管理框架,实现精细化权限管理与多站点单点登录

BootstrapAdmin Net7&#xff1a;基于RBAC的后台管理框架,实现精细化权限管理与多站点单点登录 摘要 随着企业信息化建设的不断深入&#xff0c;后台管理系统在企业运营中扮演着越来越重要的角色。本文介绍了一款基于RBAC&#xff08;Role-Based Access Control&#xff09;的…

腾讯云轻量2核2G4M服务器优惠价格99元一年,多配置报价单

腾讯云轻量2核2G4M服务器优惠价格99元一年&#xff0c;多配置报价单。腾讯云服务器价格表2024年最新价格&#xff0c;轻量2核2G3M服务器61元一年、2核2G4M服务器99元1年&#xff0c;三年560元、2核4G5M服务器165元一年、3年900元、轻量4核8M12M服务器646元15个月、4核16G10M配置…

WEB攻防-ASP安全-ASP后门植入连接

windows2003环境搭建&#xff0c;可参考上一篇WEB攻防-ASP安全-MDB下载-CSDN博客 将aspcms解压到C:\inetpub\wwwroot,创建网站并赋予internet来宾用户权限 配置启用父路径和主页指向 上一篇文章提到&#xff0c;数据库文件后缀为asp、asa会被执行解析&#xff0c;所以当进行访…

Redis中的慢查询日志和监视器

慢查询 添加新日志 在每次执行命令的之前和之后&#xff0c;程序都会记录微妙格式的当前UNIX时间戳&#xff0c;这两个时间戳之间的差就是服务器执行命令所耗费的时长&#xff0c;服务器会将这个时长作为参数之一传给slowlogPushEntryIfNeeded函数&#xff0c;而slowlogPushE…

每日算法之矩阵置零

题目描述 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,1,1],[1,0,1],[1,1,1]] 输出&#xff1a;[[1,0,1],[0,0,0],[1,0,1]] 示例 2&#xff1a; 输入&#x…

TQZC706开发板教程:编译zynq linux内核2019_R1

您需要下载对应版本的Linux系统文件以及IMG1.3.1镜像文件。为了方便您的操作&#xff0c;本文所使用的所有文件以及最终生成的文件&#xff0c;我都已经整理并放置在本文末尾提供的网盘链接中。您可以直接通过该链接进行下载&#xff0c;无需在其他地方单独搜索和获取。希望这能…

前端三剑客 HTML+CSS+JavaScript ③ HTML标准结构

生活没有任何意义&#xff0c;这就是活着的理由&#xff0c;而且是唯一的理由 —— 24.4.22 一、HTML注释 1.特点 注释的内容会被浏览器所忽略&#xff0c;不会呈现到页面中&#xff0c;但源代码中依然可见 2.作用 对代码进行解释和说明 3.写法 <!-- xxxxx --> <html&…

webgl canvas系列——animation中基本旋转、平移、缩放(模拟冒泡排序过程)

文章目录 ⭐前言⭐canvas绘制图片&#x1f496;状态保存和恢复&#x1f496;移动、旋转、缩放、变形&#x1f496;移动绘制一个渐变的box&#x1f496;旋转&#x1f496;缩放 ⭐模拟冒泡排序过程⭐结束 ⭐前言 大家好&#xff0c;我是yma16&#xff0c;本文分享webgl canvas系…

【MySQL 数据宝典】【磁盘结构】- 002 数据字典

一、数据字典 ( Data Dictionary ) 1.1 背景介绍 我们平时使用 INSERT 语句向表中插入的那些记录称之为用户数据&#xff0c;MySQL只是作为一个软件来为我们来保管这 些数据&#xff0c;提供方便的增删改查接口而已。但是每当我们向一个表中插入一条记录的时候&#xff0c;MyS…

周鸿祎和雷军、马化腾相逢一笑泯恩仇

关注卢松松&#xff0c;会经常给你分享一些我的经验和观点。 马云竟然没有到场&#xff0c;真是遗憾! 前两天工信部和互联网协会联合举办的中国互联网三十周年座谈会上。周鸿祎、雷军、马化腾相逢一笑泯恩仇。 第一条视频&#xff1a; 周鸿祎和马化腾握手言欢&#xff0c…

Mendix是谁?作为致力于企业低代码服务平台的领头羊,它解决了哪些问题?

一、Mendix 成立的背景 Mendix的成立是为了解决软件开发中最大的问题&#xff1a;业务和IT之间的脱节。这一挑战在各个行业和地区都很普遍&#xff0c;很简单&#xff1a;业务需求通常被描述为IT无法正确解释并转化为软件。业务和IT之间缺乏协作的原因是传统的代码将开发过程限…

Vue.js前端开发零基础教学(六)

学习目标 了解什么是路由&#xff0c;能够说出前端后端路由的原理 掌握多种路由的使用方法&#xff0c;能够实现路由的不同功能 掌握Vue Router的安装及基本使用方法 5.1 初始路由 提到路由&#xff08;Route),一般我们会联想到网络中常见的路由器&#xff08;Router),…

30 消息队列

原理 操作系统可以通过页表映射在共享区创建一块共享内存&#xff0c;也可以申请一个队列。A进程和B进程可以向这个队列发送数据块&#xff0c;两个进程接收数据块来通信 函数 申请数据块 参数中的key来自于ftok函数 删除消息队列 同样消息队列也有数据结构管理&#xff…

c#学习入门1

一、环境配置 颜色主题 字体设置 行号设置 二、第一个应用程序 1. 在解决方案下创建一个新项目 第一种注释&#xff1a;两杠注释 第二种注释&#xff1a;星号注释 第三种注释&#xff1a;三杠注释(只有在花括号后面输出才会自动补全&#xff09; 2.控制台输入打印基础语句 输…

java在线问卷调查系统的设计与实现(springboot+mysql源码+文档)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的在线问卷调查系统。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 基于java的在线问卷调查…

HBM:小贵但AI需要

即将推出的高带宽内存 high-bandwidth memory在散热方面还存在挑战&#xff0c;但可能即将得到改善。 高带宽内存 &#xff08;HBM&#xff09; 正在成为算力提供商的首选内存&#xff0c;由于 AI/ML 的需求&#xff0c;使用量也在继续增长&#xff0c;HBM 提供紧凑的 2.5D 外形…

P1024 [NOIP2001 提高组] 一元三次方程求解

题目描述&#xff1a; AC代码&#xff1a; #include<iostream>using namespace std;double a,b,c,d; int ans 0;double f(double x) {return a * x * x * x b * x * x c * x d; }int main() {scanf("%lf %lf %lf %lf",&a,&b,&c,&d);for…

钉钉报警的优势在哪里?如何配置钉钉机器人进行报警信息推送?

一、常见的报警方式 1、短信或者电话报警 这样的报警方式更适合高级别的报警提醒&#xff0c;用于处理紧急情况。出现级别不高而又频繁地发送短信会让人产生排斥感&#xff0c;而且电话或者短信的报警方式也存在一定的成本。 2、邮件报警 邮件报警更适用于工作时的提醒&…

DSSM 模型技术介绍

转自&#xff1a;git 本文属于新闻推荐实战-召回阶段-DSSM召回模型。区别于策略召回&#xff0c;基于向量召回也是目前工业界常用的一种召回方法。这里我们将介绍一个比较经典的召回模型DSSM&#xff0c;希望读者可以快速掌握模型原理以及细节&#xff0c;同时可以了解具体的实…