fpga系列 HDL:XILINX Vivado ZYNQ-7000 PS-PL数据交互 AXI4 实现笔记

ops/2025/2/5 6:12:16/
  • 12_PL读写PS端DDR数据.mp4

打开AXI HP0 interface

  • 参照HELLO WORLD新建Block Design,打开AXI HP0 interface,配置PL Fabric Clocks 时钟

在这里插入图片描述

在这里插入图片描述

添加转换模块

在这里插入图片描述
在这里插入图片描述

添加复位

在这里插入图片描述

添加时钟并进行连接

在这里插入图片描述
在这里插入图片描述

  • 配置端口属性
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 连接复位后保存:
    在这里插入图片描述

分配地址

在这里插入图片描述
在这里插入图片描述

代码

  • https://github.com/alinxalinx/AX7020_2023.1/blob/master/course_s2_vitis/12_pl_read_write_ps_ddr/Vivado/auto_create_project/src/design/aq_axi_master.v

  • https://gitee.com/wnagds/pl_read_write_ps_ddr/tree/master/pl_read_write_ps_ddr.srcs/sources_1注释掉top中的fifo_16x64和aq_axi_master

  • 外部master模块通过AXI FULL接口直接读取DDR数据

  • 【AXI-Master-Slave总结】

// https://cloud.tencent.com/developer/article/1532836
module aq_axi_master(// Reset, Clockinput           ARESETN,input           ACLK,// Master 写地址通道output [0:0] M_AXI_AWID,output [31:0] M_AXI_AWADDR,output [7:0] M_AXI_AWLEN,    // Burst Length:0-255output [2:0] M_AXI_AWSIZE,   // Burst Size:Fixed 2'b011output [1:0] M_AXI_AWBURST,  // Burst Type:Fixed 2'b01(Incremental Burst)output       M_AXI_AWLOCK,   // Lock: Fixed2'b00output [3:0] M_AXI_AWCACHE,  // Cache: Fiex2'b0011output [2:0] M_AXI_AWPROT,   // Protect: Fixed2'b000output [3:0] M_AXI_AWQOS,    // QoS: Fixed2'b0000output [0:0] M_AXI_AWUSER,   // User: Fixed32'd0output       M_AXI_AWVALID,input        M_AXI_AWREADY,// Master 写数据通道output [63:0] M_AXI_WDATA,output [7:0] M_AXI_WSTRB,output       M_AXI_WLAST,output [0:0] M_AXI_WUSER,output       M_AXI_WVALID,input        M_AXI_WREADY,// Master 写响应通道input [0:0]  M_AXI_BID,input [1:0]  M_AXI_BRESP,input [0:0]  M_AXI_BUSER,input        M_AXI_BVALID,output       M_AXI_BREADY,// Master 读地址通道output [0:0] M_AXI_ARID,output [31:0] M_AXI_ARADDR,output [7:0] M_AXI_ARLEN,output [2:0] M_AXI_ARSIZE,output [1:0] M_AXI_ARBURST,output [1:0] M_AXI_ARLOCK,output [3:0] M_AXI_ARCACHE,output [2:0] M_AXI_ARPROT,output [3:0] M_AXI_ARQOS,output [0:0] M_AXI_ARUSER,output       M_AXI_ARVALID,input        M_AXI_ARREADY,// Master 读数据通道input [0:0]  M_AXI_RID,input [63:0] M_AXI_RDATA,input [1:0]  M_AXI_RRESP,input        M_AXI_RLAST,input [0:0]  M_AXI_RUSER,input        M_AXI_RVALID,output       M_AXI_RREADY,// Local Businput        MASTER_RST,input        WR_START,input [31:0] WR_ADRS,input [31:0] WR_LEN,output       WR_READY,output       WR_FIFO_RE,input        WR_FIFO_EMPTY,input        WR_FIFO_AEMPTY,input [63:0] WR_FIFO_DATA,output       WR_DONE,input        RD_START,input [31:0] RD_ADRS,input [31:0] RD_LEN,output       RD_READY,output       RD_FIFO_WE,input        RD_FIFO_FULL,input        RD_FIFO_AFULL,output [63:0] RD_FIFO_DATA,output       RD_DONE,output [31:0] DEBUG);localparam S_WR_IDLE  = 3'd0;localparam S_WA_WAIT  = 3'd1;localparam S_WA_START = 3'd2;localparam S_WD_WAIT  = 3'd3;localparam S_WD_PROC  = 3'd4;localparam S_WR_WAIT  = 3'd5;localparam S_WR_DONE  = 3'd6;reg [2:0]  wr_state;reg [31:0] reg_wr_adrs;reg [31:0] reg_wr_len;reg        reg_awvalid, reg_wvalid, reg_w_last;reg [7:0]  reg_w_len;reg [7:0]  reg_w_stb;reg [1:0]  reg_wr_status;reg [3:0]  reg_w_count, reg_r_count;reg [7:0]  rd_chkdata, wr_chkdata;reg [1:0]  resp;reg rd_first_data;reg rd_fifo_enable;reg[31:0] rd_fifo_cnt;assign WR_DONE =(wr_state == S_WR_DONE);assignWR_FIFO_RE         = rd_first_data |(reg_wvalid & ~WR_FIFO_EMPTY & M_AXI_WREADY & rd_fifo_enable);always @(posedgeACLK or negedge ARESETN)beginif(!ARESETN)rd_fifo_cnt <= 32'd0;else if(WR_FIFO_RE)rd_fifo_cnt <= rd_fifo_cnt +32'd1;else if(wr_state == S_WR_IDLE)rd_fifo_cnt <= 32'd0;endalways @(posedgeACLK or negedge ARESETN)beginif(!ARESETN)rd_fifo_enable <= 1'b0;else if(wr_state == S_WR_IDLE &&WR_START)rd_fifo_enable <= 1'b1;else if(WR_FIFO_RE && (rd_fifo_cnt== RD_LEN[31:3] - 32'd1) )rd_fifo_enable <= 1'b0;          end// Write Statealways @(posedge ACLK or negedge ARESETN)beginif(!ARESETN) beginwr_state            <= S_WR_IDLE;reg_wr_adrs[31:0]   <= 32'd0;reg_wr_len[31:0]    <= 32'd0;reg_awvalid         <= 1'b0;reg_wvalid          <= 1'b0;reg_w_last          <= 1'b0;reg_w_len[7:0]      <= 8'd0;reg_w_stb[7:0]      <= 8'd0;reg_wr_status[1:0]  <= 2'd0;reg_w_count[3:0]    <= 4'd0;reg_r_count[3:0]  <= 4'd0;wr_chkdata          <= 8'd0;rd_chkdata <= 8'd0;resp <= 2'd0;rd_first_data <= 1'b0;end else beginif(MASTER_RST) beginwr_state <= S_WR_IDLE;end else begincase(wr_state)S_WR_IDLE: beginif(WR_START) begin              //外部开始写地址wr_state          <= S_WA_WAIT;reg_wr_adrs[31:0] <=WR_ADRS[31:0];//写地址reg_wr_len[31:0]  <= WR_LEN[31:0] -32'd1;//写长度rd_first_data <= 1'b1;endreg_awvalid         <= 1'b0;reg_wvalid          <= 1'b0;reg_w_last          <= 1'b0;reg_w_len[7:0]      <= 8'd0;reg_w_stb[7:0]      <= 8'd0;reg_wr_status[1:0]  <= 2'd0;end//写地址等待S_WA_WAIT: begin//外部FIFO不空或者长度为0则开始写地址if(!WR_FIFO_AEMPTY |(reg_wr_len[31:11] == 21'd0)) beginwr_state          <= S_WA_START;endrd_first_data <= 1'b0;end//写地址开始S_WA_START: beginwr_state            <= S_WD_WAIT;//写数据等待reg_awvalid         <= 1'b1;//写长度减一reg_wr_len[31:11]    <= reg_wr_len[31:11] - 21'd1;if(reg_wr_len[31:11] != 21'd0) beginreg_w_len[7:0]  <= 8'hFF;//每次写256个数据reg_w_last      <= 1'b0;reg_w_stb[7:0]  <= 8'hFF;end else begin//最后不足256个的数据写入reg_w_len[7:0]  <= reg_wr_len[10:3];reg_w_last      <= 1'b1;reg_w_stb[7:0]  <= 8'hFF;endendS_WD_WAIT: begin//等待写总线READY,进入写数据状态if(M_AXI_AWREADY) beginwr_state        <= S_WD_PROC;reg_awvalid     <= 1'b0;//开始写数据reg_wvalid      <= 1'b1;endend//写数据S_WD_PROC: beginif(M_AXI_WREADY & ~WR_FIFO_EMPTY)begin//一次突发写完成if(reg_w_len[7:0] == 8'd0) beginwr_state        <= S_WR_WAIT;reg_wvalid      <= 1'b0;reg_w_stb[7:0]  <= 8'h00;end else beginreg_w_len[7:0]  <= reg_w_len[7:0] -8'd1;endendend//写等待S_WR_WAIT: begin//写响应完成if(M_AXI_BVALID) beginreg_wr_status[1:0]  <= reg_wr_status[1:0] | M_AXI_BRESP[1:0];if(reg_w_last) begin//写完成wr_state          <= S_WR_DONE;end else begin//写未完成wr_state          <= S_WA_WAIT;//地址每次递增reg_wr_adrs[31:0] <=reg_wr_adrs[31:0] + 32'd2048;endendendS_WR_DONE: beginwr_state <= S_WR_IDLE;enddefault: beginwr_state <= S_WR_IDLE;endendcaseendendendassign M_AXI_AWID         = 1'b0;assign M_AXI_AWADDR[31:0] =reg_wr_adrs[31:0];assign M_AXI_AWLEN[7:0]   = reg_w_len[7:0];assign M_AXI_AWSIZE[2:0]  = 2'b011;assign M_AXI_AWBURST[1:0] = 2'b01;assign M_AXI_AWLOCK       = 1'b0;assign M_AXI_AWCACHE[3:0] = 4'b0011;assign M_AXI_AWPROT[2:0]  = 3'b000;assign M_AXI_AWQOS[3:0]   = 4'b0000;assign M_AXI_AWUSER[0]    = 1'b1;assign M_AXI_AWVALID      = reg_awvalid;assign M_AXI_WDATA[63:0]  = WR_FIFO_DATA[63:0];assign M_AXI_WSTRB[7:0]   = (reg_wvalid & ~WR_FIFO_EMPTY)?8'hFF:8'h00;assign M_AXI_WLAST        = (reg_w_len[7:0] == 8'd0)?1'b1:1'b0;assign M_AXI_WUSER        = 1;assign M_AXI_WVALID       = reg_wvalid & ~WR_FIFO_EMPTY;assign M_AXI_BREADY       = M_AXI_BVALID;assign WR_READY           = (wr_state == S_WR_IDLE)?1'b1:1'b0;localparam S_RD_IDLE  = 3'd0;localparam S_RA_WAIT  = 3'd1;localparam S_RA_START = 3'd2;localparam S_RD_WAIT  = 3'd3;localparam S_RD_PROC  = 3'd4;localparam S_RD_DONE  = 3'd5;reg [2:0]  rd_state;reg[31:0]  reg_rd_adrs;reg [31:0] reg_rd_len;reg        reg_arvalid, reg_r_last;reg [7:0]  reg_r_len;assign RD_DONE = (rd_state == S_RD_DONE) ;// Read Statealways @(posedge ACLK or negedge ARESETN)beginif(!ARESETN) beginrd_state          <= S_RD_IDLE;reg_rd_adrs[31:0] <= 32'd0;reg_rd_len[31:0]  <= 32'd0;reg_arvalid       <= 1'b0;reg_r_len[7:0]    <= 8'd0;end else begincase(rd_state)S_RD_IDLE: begin//读开始if(RD_START) beginrd_state          <= S_RA_WAIT;reg_rd_adrs[31:0] <=RD_ADRS[31:0];reg_rd_len[31:0]  <= RD_LEN[31:0] -32'd1;endreg_arvalid     <= 1'b0;reg_r_len[7:0]  <= 8'd0;end//读通道等待S_RA_WAIT: beginif(~RD_FIFO_AFULL) beginrd_state          <= S_RA_START;endend//读地址开始S_RA_START: beginrd_state          <= S_RD_WAIT;reg_arvalid       <= 1'b1;reg_rd_len[31:11] <=reg_rd_len[31:11] -21'd1;if(reg_rd_len[31:11] != 21'd0) beginreg_r_last      <= 1'b0;reg_r_len[7:0]  <= 8'd255;end else beginreg_r_last      <= 1'b1;reg_r_len[7:0]  <= reg_rd_len[10:3];endend//读数据等待S_RD_WAIT: beginif(M_AXI_ARREADY) beginrd_state        <= S_RD_PROC;reg_arvalid     <= 1'b0;endend//读数据开始S_RD_PROC: beginif(M_AXI_RVALID) beginif(M_AXI_RLAST) beginif(reg_r_last) beginrd_state          <= S_RD_DONE;end else beginrd_state          <= S_RA_WAIT;reg_rd_adrs[31:0] <=reg_rd_adrs[31:0] + 32'd2048;endend else beginreg_r_len[7:0] <=reg_r_len[7:0] -8'd1;endendendS_RD_DONE:beginrd_state          <= S_RD_IDLE;endendcaseendend// Master Read Addressassign M_AXI_ARID         = 1'b0;assign M_AXI_ARADDR[31:0] =reg_rd_adrs[31:0];assign M_AXI_ARLEN[7:0]   = reg_r_len[7:0];assign M_AXI_ARSIZE[2:0]  = 3'b011;assign M_AXI_ARBURST[1:0] = 2'b01;assign M_AXI_ARLOCK       = 1'b0;assign M_AXI_ARCACHE[3:0] = 4'b0011;assign M_AXI_ARPROT[2:0]  = 3'b000;assign M_AXI_ARQOS[3:0]   = 4'b0000;assign M_AXI_ARUSER[0]    = 1'b1;assignM_AXI_ARVALID      = reg_arvalid;assign M_AXI_RREADY       = M_AXI_RVALID & ~RD_FIFO_FULL;assign RD_READY           = (rd_state == S_RD_IDLE)?1'b1:1'b0;assign RD_FIFO_WE         = M_AXI_RVALID;assign RD_FIFO_DATA[63:0] = M_AXI_RDATA[63:0];assign DEBUG[31:0] = {reg_wr_len[31:8],1'd0, wr_state[2:0],1'd0, rd_state[2:0]};endmodule

添加约束

set_property IOSTANDARD LVCMOS33 [get_ports error]
set_property PACKAGE_PIN M14 [get_ports error]

在这里插入图片描述

综合

  • 将设计导出为HD Wrapper,然后进行综合
    在这里插入图片描述
  • 综合出现错误:需要修改源码或者设计中的名称
    在这里插入图片描述

添加逻辑分析仪(略)

在这里插入图片描述

进行综合、实现、生成bit流

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

然后直接编译与下载程序

在这里插入图片描述
在这里插入图片描述

进行ILA调试

  • 这个是教程中的截图:
    在这里插入图片描述

  • 这个是我的(我的数据没有改变,我在其他示例项目中进行了测试,当使用PLL作为参考时钟时,数据调试时不会发生变化,我参考这篇文章重新设置了外部的PL端时钟,作为参考时钟,在测试项目中成功了):
    在这里插入图片描述

  • 这里先直接读取一下试试,看看PL端有没有写入成功,PS端代码如下。

  • 代码来自http://www.hellofpga.com/index.php/2024/02/04/ebaz4205_pl_ddr_test/:

#include "stdio.h"
#include "xil_cache.h"
#include "xil_printf.h"
#include "xil_io.h"//#define DDR_BASEADDR 0X08000000 // 这里地址需要修改和mem_test中的地址相对应
#define DDR_BASEADDR 0X00000000int main() {int i;char A;Xil_DCacheDisable();print("AXI4 PL DDR TEST!\n\r");print("Please input A to start\n\r");while(1){scanf("%c",&A);if(A=='A'||A=='a'){printf("start\n\r");for(i=0;i<4096;i=i+4){printf("The data for the address %x is %d\n\r",DDR_BASEADDR+i,(int)Xil_In32(DDR_BASEADDR+i));}}}return 0;
}

http://www.ppmy.cn/ops/155790.html

相关文章

c++ 一个类模拟黑盒测试!!

在软件开发中&#xff0c;我们经常需要对程序的输出进行验证&#xff0c;以确保其符合预期。为了实现这一目的&#xff0c;我们可以设计一个专门的类来封装输入、预期输出和实际输出的比较逻辑。本文将介绍一个经过修改的test类&#xff0c;它能够有效地用于程序的最终检查&…

手写单例模式

饿汉式加载模式&#xff08;线程安全&#xff09; 类一加载就创建对象&#xff0c;这种方式比较常用 优点&#xff1a;线程安全&#xff0c;没有加锁&#xff0c;执行效率高 缺点&#xff1a;不是懒加载&#xff0c;类初始化的时候就加载&#xff0c;浪费内存空间 package …

2024年终总结来了

忘记发CSDN的年度总结了&#xff0c;今天补上吧 说实话&#xff0c;今年过得不是特别好&#xff0c;感觉遇到了瓶颈&#xff0c;人生变得迷茫起来。不知道大家有没有同样的感受 刚毕业的时候人生充满了憧憬&#xff0c;慢慢的随着年龄变大后&#xff0c;就会觉得一事无成&…

【PyQt】keyPressEvent键盘按压事件无响应

问题描述 通过load ui 文件加载程序时&#xff0c;keyPressEvent键盘按压事件无响应 原因 主要是由于事件处理的方式和窗口的显示方式不正确所导致的。 解决代码 self&#xff1a;这里的self作为loadUi函数的第二个参数&#xff0c;意味着加载的界面将被设置为当前类实例&…

基于场景图的零样本目标导航

参考论文&#xff1a;SG-Nav&#xff1a;Online 3D Scene Graph Prompting for LLM-based Zero-shot Object Navigation 0 前言 基于现成的视觉基础模型VFMs和大语言模型LLM构建了无需任何训练的零样本物体巡航框架SG-Nav。 通过VLMs将机器人对场景的观测构建为在线的3D场景图…

【Go - 小顶堆/大顶堆】

在 Go 语言中&#xff0c;标准库 container/heap 提供了堆&#xff08;Heap&#xff09;的实现。可以使用 container/heap 包来实现自己的大顶堆或小顶堆。 小顶堆示例 以下是一个使用 container/heap 包实现的小顶堆示例&#xff1a; package mainimport ("container/…

结构体和类

结构体和类 C结构体中的所有默认成员函数&#xff08;如&#xff1a;构造函数&#xff09;里面可以写一切合法的代码 不单单只可eg:初始化变量{}可以用来划定变量的使用范围 eg: int main() {{int a 0;//则a只能在这个{}里面使用}return 0 ;}<<输出运算符能够直接打印C…

牛客周赛 Round 79

题目目录 A 小红的合数寻找解题思路参考代码 B 小红的小球染色解题思路参考代码 C 小红的二叉树解题思路参考代码 D 小红的“质数”寻找解题思路参考代码 E 小红的好排列解题思路参考代码 F 小红的小球染色期望解题思路参考代码 A 小红的合数寻找 \hspace{15pt} 小红拿到了一个…