基于Smart ZYNQ(SP&SL 版)的PS实验十五 PS与PL数据交互之 PS访问 PL端的BRAM资源实现PS与PL数据交互

本章节将演示 PS 访问 PL 端的 BRAM 资源,从而实现FPGA端和PS端的简单数据交互。

  • 此章节内容适用于Smart ZYNQ SP SP2和 SL 版的板子 ( 不包含Smart ZYNQ 标准版 ),如是标准版或本站其他板子请看对应板子目录
  • 本文在 vivado2018.3版本上演示

PS端与PL端在硬件上是相互独立的,之前介绍过通过寄存器的方式以及通过DDR的方式来实现数据交互,两者各有优缺点,寄存器的方式较为灵活但是受限于FPGA的逻辑资源数量,所以仅适用于小数据量通讯(几个或者几十个字节),而DDR支持大容量的数据存储,但数据必须是连贯的(对不连贯的数据,读取会比较慢),而BRAM就是一种折中的方式,可以实现少量(7020有4.9Mbit 的BRAM )不连续数据的读取。

Block Ram (Bram)原本是PL 端的资源, 曾经我们在实验 基于Smart ZYNQ(SP&SL 版)的PS实验九 QSPI FLASH读写测试  中介绍过如何在FPGA端使用 BRAM。 PS本身并不能直接读写 BRAM 的数据。但是我们可以通过AXI BRAM Controller IP 核来控制BRAM资源。

下面将进行具体的演示

一. 创建工程

1)打开Vivado 新建一个项目, 新建一个VIVADO 工程,打开软件 选中Create Project, 如下图所示

2)点击NEXT ,在出现的第二个对话框“Project name”中输入工程名;在“Project location”中选择保存路径;勾选“Create project subdirectory”(默认),最后点击“Next” 备注,所有的路径均不能出现中文名称

3)点击 RTL PROJECT 选项,点击NEXT

4) 第四步Add Sources 选项直接留空,NEXT

5)第五步Add Constraints 选项直接留空,NEXT

6)选择芯片型号  板子的芯片型号为 XC7Z020 封装是CLG484 所以型号我们选择 xc7z020clg484-1

7)确认所选信息 点击“Finish”,完成vivado的工程创建

之后 工程就新建好了, vivado 进入到开发界面

二、Vivado 部分设计

Vivado 部分工程的创建和之前已经介绍过很多次了,所以这里仅仅介绍重点:

创建一个BLOCK设计

1)IP INTEGRATOR→Create Block Design,在弹出的对话框中输入设计名,最后点击“OK”,如下图所示

2)在右侧的窗口里 ,点击加号,在选择框里搜索ZYNQ,并找到ZYNQ7 PROCESSING SYSTEM ,双击并打开

3)软件自动生成了一个 zynq的block 如下图所示,接下来要做一些相应的设置,双击下图中的ZYNQ核

4)依次在弹窗里找到DDR Configuration→DDR Controller Configuration→DDR3,在Memory Part下拉菜单中根据自己板子上的DDR来选择相应的DDR3,本实验所用到型号:MT41K256M16RE-125,数据位宽选择16bit 最后点击“OK”,如下图所示。

5)在PS的MIO配置选项增加UART部分,使能UART 0 并在IO选项里选择EMIO方式

设置完后点OK 完成ZYNQ的设置,然后引出UART 信号,因为我们增加了EMIO 的UART,所以这里需要将UART的引脚引出 ,右键选择ZYNQ模块的UART_0,然后选择Make External

6) 搜索并添加 AXI BRAM Controller IP 核 ,实验本身分两部分,第一部分是对其中一个bram进行读写,另一部分是PS写 BRAM 然后 PL读BRAM。所以这里需要添加三个AXI BRAM Controller IP 核

打开 AXI BRAM Controller 的参数设置页, 如下图所示调整 Number of BRM Interface 为1 (这样一个IP 负责读,一个IP负责写 可以更好的进行演示) 备注:三个IP都需要进行设置

7)搜索并添加 AXI BRAM Controller IP 核(这个就是PL端的BRAM 了)备注:这里需要添加两个Bram

类型选择 真双口 RAM: True Dual Port RAM ,这里的BRAM 不能调整容量 位宽,所以 Port A 和Port B 的地方保留默认就好。

在 Other Options 中去掉 Enable Safety Circuit 选项

8) 至此,我们有2个BRAM 和 3个 AXI BRAM Controller IP 核

9)分别 点 Run Block Automation 和Run Connection Automation

此后,系统将自动帮我们把需要的连线以及缺少的模块给补充好, 从下图可以看到BRAM 0的 A口和B口分别接到axi_bram_ctrl_0 和axi_bram_ctrl_1上了, 而另一个BRAM 1的A口 接在了axi_bram_ctrl_2上, B口暂时留空,后面将引出以接FPGA的逻辑使用。

10)右键选择BRAM模块的PORTB口,然后选择Make External,引出BRAM口

下图是本次工程完整的 BD 图

11) 在source→Design Source ,右键我们创建的BLOCK工程,点击create HDL wrapper,打包BLOCK文件并生成.v代码

在弹出的菜单里直接点选OK

PL部分代码设计

添加ILA模块

1) 为了方便演示观察结果,这里我们添加一个ILA 模块

2) 修改ILA的参数 观察的探针设置成2个 ,两个探针的位宽都设置成32

添加顶层模块

1) 回到vivado 主界面, 点选Add_Sources ,点选 add or create design souces 创建一个新的.v文件

2)点选Create File 在弹出的对话框里输入要添加的 .V文件的文件名 (这里是 TOP_MODULE)

3)在下一个窗口点OK 完成

双击打开 我们刚刚创建的TOP_MODULE 顶层模块,添加下列代码

`timescale 1ns / 1ps

module TOP_MODULE(
    input  CLK_50M,
    input  UART_0_0_rxd,
    output UART_0_0_txd
);
  
reg  [31:0]BRAM_addr;
wire [31:0]BRAM_dout;
reg  [31:0]BRAM_addr_Lag;
     
always@(posedge CLK_50M)begin
    BRAM_addr_Lag<=BRAM_addr;


    if(BRAM_addr>=32'd19)
         BRAM_addr<=32'd0;
    else 
         BRAM_addr<=BRAM_addr+1'b1; 
end

ila_0  u_test(
   .clk(CLK_50M),
   .probe0(BRAM_addr_Lag),
   .probe1(BRAM_dout)
);        
    
ZYNQ_CORE_wrapper u_zynq( 
    .BRAM_PORTB_0_addr(BRAM_addr),
    .BRAM_PORTB_0_clk(CLK_50M),
    .BRAM_PORTB_0_din(32'd0),
    .BRAM_PORTB_0_dout(BRAM_dout),
    .BRAM_PORTB_0_en(1'b1),
    .BRAM_PORTB_0_rst(1'b0),
    .BRAM_PORTB_0_we(4'd0),
    
    .UART_0_0_rxd(UART_0_0_rxd),
    .UART_0_0_txd(UART_0_0_txd)
);    
   
endmodule

代码中例化了 ZYNQ 核,以及我们刚刚创建的ILA模块, 并且定义了一个 从0-19自增的地址BRAM_addr。 备注,这里除了定义了BRAM_addr 之外,另外还定义了一个地址BRAM_addr_Lag, 这个地址较BRAM_addr 将滞后一拍,用来和BRAM输出的数据对齐用(因为BRAM输出的数据会滞后一个CLK)

4) 点击绿色箭头RUN 对代码进行编译

5) 增加UART管脚定义,点击RTL 中的SCHEMATIC , 并选择右边出现的 IO Ports 来增加UART 0 EMIO部分的管脚定义(这一步也可以在约束文件中定义, 可看之前的例子) 因为ZYNQ DDR之类的脚没有完全引出到TOP模块,所以可能会报警,无视就好了 将 UART 部分的 TX RX 分别设置成 L17,M17 电压属性设置成 LVCMOS33, 之后保存

6) 生成bit文件 :按下Generate Bitstream 完成综合以及生成bit文件,等待弹出综合完成的窗口

三、SDK部分设计

1)File→Export→Export hardware…在弹出的对话框中勾选“include bitstream”,点击“OK”确认,如下图所示。

2)File→Lauch SDK,在弹出的对话框中,保存默认,点击“OK”,如下图所示。

系统将自动打开SDK开发环境

3)新建一个工程 file→new→Application Project,来新建一个“Application Project”,如下图所示。

4)在新建工程名中输入自己的工程名称,点击NEXT

5)选择空工程,点击完成FINISH

6)右键工程的SRC目录,然后新建一个SOURCE FILE

取名 main.c

7) 在main .c中添加如下代码

#include <stdio.h>
#include "xil_io.h"
#include "xparameters.h"
#include "xbram.h"

#define BRAM_CTRL_0_BASE      XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR
#define BRAM_CTRL_1_BASE      XPAR_AXI_BRAM_CTRL_1_S_AXI_BASEADDR
#define BRAM_CTRL_2_BASE      XPAR_AXI_BRAM_CTRL_2_S_AXI_BASEADDR

char test_string[]="Hello FPGA";
int main(){

    int num,str_len;
    int str_rev;
    xil_printf("test start\n\r");
    str_len=strlen(test_string);
    for( num=0; num<str_len; num++ ){
        XBram_WriteReg(BRAM_CTRL_0_BASE , num*4, test_string[num]);
    }

    for( num=0; num<str_len; num++ ){
        str_rev = XBram_ReadReg( BRAM_CTRL_1_BASE, num*4);
        printf("The data for the address %x is %c\n\r",BRAM_CTRL_1_BASE+num*4,str_rev);
    }

    xil_printf("test over!\n\r");
    xil_printf("\n\r");


    for( num=0; num<5; num++ ){
	   XBram_WriteReg(BRAM_CTRL_2_BASE , num*4, num+1 );
    }

   return 0;
}

程序功能介绍: BRAM_CTRL_0_BASE,BRAM_CTRL_1_BASE,BRAM_CTRL_2_BASE 分别对应的三个BRAM控制器的基地址,其中BRAM_CTRL_0和BRAM_CTRL_1两个控制器分别接在同一个BRAM0的 A口和B口, 而BRAM_CTRL_2 则是接在另一个BRAM1上,这个BRAM的B口将与PL端的逻辑连接。

程序运行过程

  • 通过 BRAM_CTRL_0 对 BRAM0 写入字符串 “Hello FPGA”
  • 通过 BRAM_CTRL_1 从 BRAM0 中读出对应地址的数据,并通过串口进行打印,如果之前的内容写入成功,则这里读出的数据也将是 “Hello FPGA”
  • 通过 BRAM_CTRL_2 对 BRAM1 写入顺序的0 ,1,2,3,4 (这里的验证将通过 PL端的 ILA来演示)

这里有个地方要注意 由于在ZYNQ中最小可寻址单元为字节,因此1个32位数据需占用4个地址,每次写入的地址都需要加4

四、下载程序到板子上验证 

1) 先提前打开串口助手 波特率115200(也可用vivado SDK 自带的),本文演示用的是putty

2) 打开Run as -> Run Configurations

如果是第一次打开此页面,之前没有debug过,则双击system debugger选项

3 ) 在右侧 的窗口勾选 Reset entire system ,以及Program FPGA, 这样每次debug 的时候都会预先加载并配置FPGA。

4 ) 之后系统就会自动运行了(fpga也会被自动加载) 。 如果修改程序后 再次要debug,就可以直接点绿色箭头,或者选 Run As –>Launch on Hardware (system debugger即可)

5) 程序工作后, 结果如下图所示,可以看到串口显示下列信息,证明 从BRAM_CTRL_0写入的数据,从BRAM_CTRL_1顺利读出,证明存储成功。

 6) 接下来我们看下PL端 ILA 读取到的信息

点选 Open Hardware Manager -> Auto Connect

执行完之前的下载操作后,系统如果运行没问题会自动弹出一个ila调试窗口, 入下图所示 点选箭头(Run trigger for this ILA core)开始采样

可以看到 ,从PL端读出来的数据和PS端写入的数据相同

  • 本文的完整工程下载:15_PS_BRAM_TEST
  • VIVADO的版本:2018.3
  • 工程创建目录:E:\Smart_ZYNQ_SP_SL\SDK\15_PS_BRAM_TEST
  • 工程适用主板: Smart ZYNQ (SP / SP2 / SL) (不适用于Smart ZYNQ 标准版 

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注