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

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

  • 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, Clock

  input           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-255

  output [2:0] M_AXI_AWSIZE,   // Burst Size:Fixed 2'b011

  output [1:0] M_AXI_AWBURST,  // Burst Type:Fixed 2'b01(Incremental Burst)

  output       M_AXI_AWLOCK,   // Lock: Fixed2'b00

  output [3:0] M_AXI_AWCACHE,  // Cache: Fiex2'b0011

  output [2:0] M_AXI_AWPROT,   // Protect: Fixed2'b000

  output [3:0] M_AXI_AWQOS,    // QoS: Fixed2'b0000

  output [0:0] M_AXI_AWUSER,   // User: Fixed32'd0

  output       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 Bus

  input        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)

begin

      if(!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;

end

always @(posedgeACLK or negedge ARESETN)

begin

      if(!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 State

  always @(posedge ACLK or negedge ARESETN)begin

    if(!ARESETN) begin

      wr_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 begin

    if(MASTER_RST) begin

      wr_state <= S_WR_IDLE;

    end else begin

      case(wr_state)

        S_WR_IDLE: begin

          if(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;

          end

          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;

        end

             //写地址等待

        S_WA_WAIT: begin

                    //外部FIFO不空或者长度为0则开始写地址

          if(!WR_FIFO_AEMPTY |(reg_wr_len[31:11] == 21'd0)) begin

            wr_state          <= S_WA_START;

          end

              rd_first_data <= 1'b0;

        end

             //写地址开始

        S_WA_START: begin

          wr_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) begin

            reg_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;

          end

        end

        S_WD_WAIT: begin

             //等待写总线READY,进入写数据状态

          if(M_AXI_AWREADY) begin

            wr_state        <= S_WD_PROC;

            reg_awvalid     <= 1'b0;

                    //开始写数据

            reg_wvalid      <= 1'b1;

          end

        end

             //写数据

        S_WD_PROC: begin

          if(M_AXI_WREADY & ~WR_FIFO_EMPTY)begin

              //一次突发写完成

            if(reg_w_len[7:0] == 8'd0) begin

              wr_state        <= S_WR_WAIT;

              reg_wvalid      <= 1'b0;

              reg_w_stb[7:0]  <= 8'h00;

            end else begin

              reg_w_len[7:0]  <= reg_w_len[7:0] -8'd1;

            end

          end

        end

             //写等待

        S_WR_WAIT: begin

                    //写响应完成

          if(M_AXI_BVALID) begin

            reg_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;

            end

          end

        end

        S_WR_DONE: begin

            wr_state <= S_WR_IDLE;

          end

        default: begin

          wr_state <= S_WR_IDLE;

        end

      endcase

      end

    end

  end

  assign 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 State

  always @(posedge ACLK or negedge ARESETN)begin

    if(!ARESETN) begin

      rd_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 begin

      case(rd_state)

        S_RD_IDLE: begin

             //读开始

          if(RD_START) begin

            rd_state          <= S_RA_WAIT;

            reg_rd_adrs[31:0] <=RD_ADRS[31:0];

            reg_rd_len[31:0]  <= RD_LEN[31:0] -32'd1;

          end

          reg_arvalid     <= 1'b0;

          reg_r_len[7:0]  <= 8'd0;

        end

             //读通道等待

        S_RA_WAIT: begin

          if(~RD_FIFO_AFULL) begin

            rd_state          <= S_RA_START;

          end

        end

             //读地址开始

        S_RA_START: begin

          rd_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) begin

            reg_r_last      <= 1'b0;

            reg_r_len[7:0]  <= 8'd255;

          end else begin

            reg_r_last      <= 1'b1;

            reg_r_len[7:0]  <= reg_rd_len[10:3];

          end

        end

             //读数据等待

        S_RD_WAIT: begin

          if(M_AXI_ARREADY) begin

            rd_state        <= S_RD_PROC;

            reg_arvalid     <= 1'b0;

          end

        end

             //读数据开始

        S_RD_PROC: begin

          if(M_AXI_RVALID) begin

            if(M_AXI_RLAST) begin

              if(reg_r_last) begin

                rd_state          <= S_RD_DONE;

              end else begin

                rd_state          <= S_RA_WAIT;

                reg_rd_adrs[31:0] <=reg_rd_adrs[31:0] + 32'd2048;

              end

            end else begin

              reg_r_len[7:0] <=reg_r_len[7:0] -8'd1;

            end

          end

        end

             S_RD_DONE:begin

                    rd_state          <= S_RD_IDLE;

             end

       endcase

    end

  end

  // Master Read Address

  assign 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 0X00000000

int 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.kler.cn/a/532613.html

相关文章:

  • 【零基础到精通】小白如何自学网络安全
  • 实战:如何利用网站外部链接提升收录?
  • 在Mac mini M4上部署DeepSeek R1本地大模型
  • C#方法作用
  • 将markdown文件和LaTex公式转为word
  • Vue3学习笔记-模板语法和属性绑定-2
  • ros 发布Topic
  • 【力扣】238.除自身以外数组的乘积
  • Rust HashMap :当储物袋遇上物品清单
  • 基于CY8CKIT-149 BLE HID设备实现及PC控制功能开发(BLE HID+CapSense)
  • ELF2开发板(飞凌嵌入式)搭建深度学习环境部署(RKNN环境部署)
  • 4种架构的定义和关联
  • 数据结构——并查集
  • 【单层神经网络】softmax回归的从零开始实现(图像分类)
  • gesp(C++六级)(8)洛谷:P10377:[GESP202403 六级] 好斗的牛
  • 【C++】泛型编程:吃透模板
  • 2023 年 12 月大学英语四级考试真题(第 3 套)——纯享题目版
  • 线性回归原理和算法
  • Verilog基础(四):组合逻辑
  • 深度求索DeepSeek横空出世
  • Swift语言的文件操作
  • 【JavaScript】《JavaScript高级程序设计 (第4版) 》笔记-Chapter1-什么是 JavaScript
  • 基于遗传算法的64QAM星座图的最优概率整形matlab仿真,对比优化前后整形星座图和误码率
  • Sumatra PDF:小巧免费,满足多样阅读需求
  • Java中的单例模式(如果想知道Java中有关单例模式的知识,那么只看这一篇就足够了!)
  • 【自然语言处理(NLP)】生成词向量:GloVe(Global Vectors for Word Representation)原理及应用