本文原文发布在: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;