11 - 基于BRAM的PS和PL的数据交互实验

1 实验任务

本实验任务是PS将数据写入BRAM,然后从BRAM中读出数据,并通过串口打印出来;与此同时,PS控制PL从BRAM中读出数据,并通过ILA来观察读出的数据与PS侧串口打印的数据是否一致。

2 系统框图

在这里插入图片描述

3 硬件设计

3.1 Block Design

  1. 添加ZYNQ7 Processing System IP核
    • (1)在PS-PL Configuration页面
      • 1)勾选FCLK_RESET0_N
      • 2)勾选M AXI GP0 interface
    • (2)在Peripheral I/O页面
      • 1)勾选UART
      • 2)正确选择Bank 0和Bank 1的电压
    • (3)在Clock Configuration页面
      • 1)勾选FCLK_CLK0
    • (4)在DDR Configuration页面
      • 1)DDR Controller Configuration下,合理配置Memory Type、Memory Part和Bus Width等参数
  2. 添加AXI BRAM Controller IP核
  3. 添加Block Memory Generator IP核
  4. 添加带有AXI4-Lite Slave接口的自定义AXI BRAM Read IP核
  5. 添加System ILA IP核
  6. 自动连线

在这里插入图片描述

3.2 IP核配置

  1. AXI BRAM Controller IP和Block Memory Generator IP配置
    • (1)AXI BRAM Controller作为主设备
      • 1)Data Width是可配置的
      • 2)Memory Depth是Auto的,由Address Editor中指定的Address Range和Data Width共同决定
        在这里插入图片描述
        在这里插入图片描述
    • (2)Block Memory Generator作为从设备
      • 1)只有Mode和Memory Type可配置
      • 2)其余参数都是在验证设计时通过参数传播自动设置的
        在这里插入图片描述
        在这里插入图片描述
        在这里插入图片描述

3.3 注意事项

  1. AXI BRAM Controller和Block Memory Generator地址位宽
    • (1)AXI BRAM Controller的S_AXI端口和BRAM_PORT A/B端口的地址位宽由Address Range决定(如下图所示,2^13=8KB)
    • (2)Block Memory Generator的BRAM_PORT A/B端口的地址位宽固定为32-bit
      在这里插入图片描述

3.4 自定义IP核源码

注意:Block Memory Generator在BRAM Controller模式下,其BRAM_PORT A/B端口的addra/addrb地址线上传输的是字节地址(所以,在bram_rd 模块中,数据位宽=32b=4B,地址以4为单位递增)。

`timescale 1ns/1ps

module bram_rd (
   //
   input		wire				i_clk,
   input		wire				i_rst_n,
   input		wire				i_bram_rd_ena,
   input		wire	[31:0]	i_bram_rd_adr,
   input		wire	[31:0]	i_bram_rd_len,
   //
   output	wire				o_bram_clk,
   output	wire				o_bram_rst,   
   output	wire				o_bram_en,
   output	wire	[ 3:0]	o_bram_we,
   output	wire	[31:0]	o_bram_addr,   
   output	wire	[31:0]	o_bram_din,
   input		wire	[31:0]	i_bram_dout   
);
//***********************************************************************************************
// Constant Functions
//***********************************************************************************************

//***********************************************************************************************
// Parameter Definitions
//***********************************************************************************************
localparam BRAM_RD_IDL = 3'b001;
localparam BRAM_RD_JDG = 3'b010;
localparam BRAM_RD_ACT = 3'b100;
//***********************************************************************************************
// Signal Declarations
//***********************************************************************************************
                           reg				bram_rd_ena_r1;
(* MARK_DEBUG = "TRUE" *)  reg				bram_rd_ena_r2;
(* MARK_DEBUG = "TRUE" *)  reg				bram_rd_ena_pos;
                           reg	[31:0]	bram_rd_adr_r1;
(* MARK_DEBUG = "TRUE" *)  reg	[31:0]	bram_rd_adr_r2;
                           reg	[31:0]	bram_rd_len_r1;
(* MARK_DEBUG = "TRUE" *)  reg	[31:0]	bram_rd_len_r2;

(* MARK_DEBUG = "TRUE" *)  reg	[ 1:0]	flow_cnt;

(* MARK_DEBUG = "TRUE" *)  reg            bram_en;
(* MARK_DEBUG = "TRUE" *)  reg	[31:0]	bram_addr;
(* MARK_DEBUG = "TRUE" *)  reg	[31:0]	bram_din;
(* MARK_DEBUG = "TRUE" *)  reg	[31:0]	bram_dout;

(* MARK_DEBUG = "TRUE" *)  reg	[ 2:0]	bram_rd_st;
//***********************************************************************************************
// Pipeline Inputs
//***********************************************************************************************
always @ (posedge i_clk or negedge i_rst_n) begin
   if (i_rst_n == 1'b0) begin
      bram_rd_ena_r1 <= 1'b0;
      bram_rd_ena_r2 <= 1'b0;
      bram_rd_adr_r1 <= 32'd0;
      bram_rd_adr_r2 <= 32'd0;
      bram_rd_len_r1 <= 32'd0;
      bram_rd_len_r2 <= 32'd0;
   end
   else begin
      bram_rd_ena_r1 <= i_bram_rd_ena;
      bram_rd_ena_r2 <= bram_rd_ena_r1;
      bram_rd_adr_r1 <= i_bram_rd_adr;
      bram_rd_adr_r2 <= bram_rd_adr_r1;
      bram_rd_len_r1 <= i_bram_rd_len;
      bram_rd_len_r2 <= bram_rd_len_r1;
   end      
end

always @ (posedge i_clk or negedge i_rst_n) begin
   if (i_rst_n == 1'b0)
      bram_dout <= 32'd0;
   else
      bram_dout <= i_bram_dout;
end   
//***********************************************************************************************
// Code
//***********************************************************************************************
///=== bram_rd_ena_pos
always @ (posedge i_clk or negedge i_rst_n) begin
   if (i_rst_n == 1'b0)
      bram_rd_ena_pos <= 1'b0;
   else if (bram_rd_ena_r2 == 1'b0 && bram_rd_ena_r1 == 1'b1)
      bram_rd_ena_pos <= 1'b1;
   else
      bram_rd_ena_pos <= 1'b0;      
end

///=== bram_rd_st
always @ (posedge i_clk or negedge i_rst_n) begin
   if (i_rst_n == 1'b0)
      bram_rd_st <= BRAM_RD_IDL;
   else begin
      case (bram_rd_st)
         BRAM_RD_IDL : begin
            bram_rd_st <= BRAM_RD_JDG;
         end

         BRAM_RD_JDG : begin
            if (bram_rd_ena_pos == 1'b1)
               bram_rd_st <= BRAM_RD_ACT;
            else
               bram_rd_st <= BRAM_RD_JDG;     
         end

         BRAM_RD_ACT : begin
            if((bram_addr - bram_rd_adr_r2) == (bram_rd_len_r2 - 4))
               bram_rd_st <= BRAM_RD_IDL;
            else
               bram_rd_st <= BRAM_RD_ACT;
         end

         default : begin
            bram_rd_st <= BRAM_RD_IDL;
         end
      endcase
   end   
end   

///=== bram_en
always @ (posedge i_clk or negedge i_rst_n) begin
   if (i_rst_n == 1'b0) 
      bram_en <= 1'b0;
   else if(bram_rd_st == BRAM_RD_JDG && bram_rd_ena_pos == 1'b1)
      bram_en <= 1'b1;
   else if (bram_rd_st == BRAM_RD_ACT && (bram_addr - bram_rd_adr_r2) == (bram_rd_len_r2 - 4))
      bram_en <= 1'b0;
   else
      bram_en <= bram_en;
end

///=== bram_addr
always @ (posedge i_clk or negedge i_rst_n) begin
   if (i_rst_n == 1'b0)
      bram_addr <= 32'd0;
   else if(bram_rd_st == BRAM_RD_JDG && bram_rd_ena_pos == 1'b1)
      bram_addr <= bram_rd_adr_r2;
   else if(bram_rd_st == BRAM_RD_ACT)
      bram_addr <= bram_addr + 4;
   else
      bram_addr <= 32'd0;
end
//***********************************************************************************************
// Outputs
//***********************************************************************************************
assign o_bram_clk = i_clk;
assign o_bram_rst = 1'b0;

assign o_bram_en   = bram_en;
assign o_bram_we   = 4'd0;
assign o_bram_addr = bram_addr;
assign o_bram_din  = 32'd0;

endmodule

4 软件设计

4.1 注意事项

无。

4.2 工程源码

/***************************** Include Files *********************************/

#include "stdio.h"
#include "xbram_hw.h"
#include "xparameters.h"
#include "axi_bram_rd.h"

/************************** Constant Definitions *****************************/

#define AXI_BRAM_RD_ENA			AXI_BRAM_RD_S00_AXI_SLV_REG0_OFFSET
#define AXI_BRAM_RD_ADR			AXI_BRAM_RD_S00_AXI_SLV_REG1_OFFSET
#define AXI_BRAM_RD_LEN			AXI_BRAM_RD_S00_AXI_SLV_REG2_OFFSET
#define AXI_BRAM_RD_BASEADDR	XPAR_AXI_BRAM_RD_0_S00_AXI_BASEADDR

#define AXI_BRAM_CTRL_BASEADDR	XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR

/**************************** Type Definitions *******************************/

/***************** Macros (Inline Functions) Definitions *********************/

/************************** Function Prototypes ******************************/

/************************** Variable Definitions *****************************/

/*****************************************************************************/

int main()
{
	//
	u32 TxDataBuffer[1024] = { 0 };
	u32 RxDataBuffer[1024] = { 0 };

	//
	for(int i = 0; i < 1024; i++)
	{
		TxDataBuffer[i] = 0x400 + i;
	}

	//
	while(1)
	{
		//
		char Ch = 0;
		int CmpErrFlag = 0;

		//
		printf("是否启动BRAM写数据操作:>\n");
		scanf(" %c", &Ch);

		//
		if(Ch == 'c')
		{
			// PS写BRAM
			for(int i = 0; i < 1024; i++)
			{
				XBram_WriteReg(AXI_BRAM_CTRL_BASEADDR,  i * 4, TxDataBuffer[i]);
			}

			// PS读BRAM
			for(int i = 0; i < 1024; i++)
			{
				RxDataBuffer[i] = XBram_ReadReg(AXI_BRAM_CTRL_BASEADDR,  i * 4);
			}

			// 比较读写数据
			for(int i = 0; i < 1024; i++)
			{
				if(TxDataBuffer[i]!=RxDataBuffer[i])
				{
					CmpErrFlag = 1;
					break;
				}
			}

			if(CmpErrFlag==0)
			{
				printf("BRAM read and write test succeeded!\n");
			}
			else
			{
				printf("BRAM read and write test failed!\n");
			}

			// PL读BRAM
			AXI_BRAM_RD_mWriteReg(AXI_BRAM_RD_BASEADDR, AXI_BRAM_RD_ADR, 1024);
			AXI_BRAM_RD_mWriteReg(AXI_BRAM_RD_BASEADDR, AXI_BRAM_RD_LEN, 1024);
			AXI_BRAM_RD_mWriteReg(AXI_BRAM_RD_BASEADDR, AXI_BRAM_RD_ENA, 1);
			AXI_BRAM_RD_mWriteReg(AXI_BRAM_RD_BASEADDR, AXI_BRAM_RD_ENA, 0);
		}
		else
		{
			break;
		}
	}

	//
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值