本文原文发布在:https://mp.weixin.qq.com/s/iShpn-AIf95a1pmyvHeRBg
欢迎大家关注公众号:信号与FPGA

ZYNQ平台PL端向BRAM写数据,PS端读取BRAM数据的异常问题记录

系统需要PL端的一些数据传输到PS端,数据量大概几百个字节,然后PS端读取数据分析。

功能实现方案

由于数据量小,读取速度要求不高,采用PS-PL之间的GP接口传输。

打开Block design,插入axi_bram_controller IP 以及 Block memory generator。 BlockRAM采用两个端口,端口A与axi_bram_controller连接,用于PS端读取BlockRAM内容,端口B用于PL端向BlockRAM写入数据。

当写入数据完成后,PL产生中断通知PS处理。

BlockDesign设计过程

  • axi_bram_controller IP 与 Block memory generator之间的连接如下图
  • 通过make external 命令使能blk_mem_gen_0的端口B, 用作PL写入数据接口
  • 通过Address Editor 设置auto assign address
  • 分配好地址后,保存block design,并导出HDF,用于PS端 BSP生成。

    PL向BlockRAM写入数据,地址问题

    片内blk_mem_gen_0的端口P接口如下

  input [31:0]BRAM_PORTB_0_addr;
  input BRAM_PORTB_0_clk;
  input [31:0]BRAM_PORTB_0_din;
  output [31:0]BRAM_PORTB_0_dout;
  input BRAM_PORTB_0_en;
  input BRAM_PORTB_0_rst;
  input [3:0]BRAM_PORTB_0_we;

PL对向BlockRAM写入数据如下方式

module xxxxxxxxxxxx (
   input       clk,     
   input       rst_n, 
   input       addr_reset,
   input        pl_vld,
   input [31:0] pl_data

);
reg [31:0]   BRAM_PORTB_0_addr;
reg31:0]    BRAM_PORTB_0_din;
reg          BRAM_PORTB_0_en;
reg [3:0]    BRAM_PORTB_0_we;
//
always @(posedge clk ornegedge rst_n) 
begin
   BRAM_PORTB_0_din <= pl_data;
end
//
always @(posedge clk ornegedge rst_n) 
begin
   if (!rst_n)
    begin
      BRAM_PORTB_0_en <=  4'b0000; 
      BRAM_PORTB_0_we <= 1'b0; 
    end
    else
    begin
      BRAM_PORTB_0_en <= pl_vld; 
      if(pl_vld)
         BRAM_PORTB_0_we <= 4'b1111; 
      else
         BRAM_PORTB_0_we <= 4'b0000; 
    end
end
//
always @(posedge clk ornegedge rst_n) 
begin
   if (!rst_n)
      BRAM_PORTB_0_addr <=  0
   else
   begin
      if(addr_reset)
         BRAM_PORTB_0_addr <= 'd0;
      elseif(pl_vld)
         BRAM_PORTB_0_addr <= BRAM_PORTB_0_addr + 1'b1;  //error
   end
end

endmodule

正常情况下,向blockRAM每写入一次,地址加1。在Blockdesign中,这样处理存在问题,实际需要增加4.

always @(posedge clk ornegedge rst_n) 
begin
   if (!rst_n)
      BRAM_PORTB_0_addr <=  0;
   else
   begin
      if(addr_reset)
         BRAM_PORTB_0_addr <= 'd0;
      elseif(pl_vld)
         BRAM_PORTB_0_addr <= BRAM_PORTB_0_addr + 4; //right 
   end
end 

PS端读取BlockRAM数据方式

根据HDF生成的BSP,我们可以看到BlockRAM分配的地址。在头文件xparameters.h可以找到XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR:

在PS中,可以根据该地址直接读取数据内容,比如

 char *bram_ptr = (char *)XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR;