软件版本:VIVADO2021.1
操作系统:WIN10 64bit
硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA
实验平台:米联客-MLK-H3-CZ08-7100开发板
板卡获取平台:https://milianke.tmall.com/
登录“米联客”FPGA社区 http://www.uisrc.com 视频课程、答疑解惑!
1概述AXI BRAM Controler 是一个可以和AXI4-FULL 或者AXI4-LITE接口互联到ZYNQ IP系统的IP CORE。使用该IP CORE可以用于BRAM数据缓存,通过BRAM和PL数据交互,或者直接使用AXI BRAM Controler的控制逻辑完成PL数据交互。 实验目的: 1:掌握基于图形化设计编程,完成AXI BRAM Controler控制器的FPGA编程 2:直接使用AXI BRAM Controler控制器的控制逻辑完成8个寄存器数据的读写操作 2系统框图ZYNQ PS ARM端写入8个32bit数据到AXI BRAM Controller IP分配的基地址,这8个数据会出现在AXI BRAM Controller IP 的接口。PL读写逻辑根据地址,读取数据,并且保存到8个寄存器中。 当ZYNQ PS ARM端读数据的时候,PL读写逻辑把之前寄存器的数据加1。
3搭建SOC系统工程详细的搭建过程这里不再重复,对于初学读者如果还不清楚如何创建SOC工程的,请学习“3-1-01米联客2024版ZynqSocSDK入门篇”中第一个工程 “01Vitis Soc开发入门”这个实验。 3.1Zynq IP PS部分设置本文中的PS设置内容是新增加的配置部分,关于DDR、MIO、CPU时钟等设置请参考“米联客2024版ZynqSocSDK入门篇”中第一个工程 “01Vitis Soc开发入门”这个实验。 1:PS复位设置
2:设置 PS GT Master 接口
3:设置PL的时钟勾选FCLK_CLK0,设置为100,即PS的PLL提供本系统的时钟100MHZ。
4:ZYNQ IP设置完成后
3.2添加IP单击添加IP按钮“
编辑”,输入如下模块IP名字的关键词,并双击添加。
3.3图形连线设计分别选择Run Connection Automation
弹出的设置窗口分别全部勾选,如下设置
由于我们这里只想用BRAM Controller 控制器读写数据,不需要用BRAM缓存数据,所以删除自动产生的Block Memory
删除后如下
之后引出必要 时钟信号,复位信号,完成后如下:
双击 AXI BRAM Controller IP 参数设置如下:
3.4PL端读写逻辑接口BRAM Controller支持AXI-LITE接口也支持AXI4-FULL接口。而且支持多种数据传输方式,我们这里仅仅以Burst Write 和Burst Read说明如何利用BRAM Controller进行数据的交互控制。 本方案中,BRAM Controller是挂到了AXI4-FULL接口,传输效率更高,支持Burst传输。 Burst Write写时序:
Burst Read读时序:
编写PL端读写BRAM Controller接口的逻辑代码如下: `timescale 1 ps / 1 ps
module system_wrapper
(
inout [14:0]DDR_addr,
inout [2:0]DDR_ba,
inout DDR_cas_n,
inout DDR_ck_n,
inout DDR_ck_p,
inout DDR_cke,
inout DDR_cs_n,
inout [3:0]DDR_dm,
inout [31:0]DDR_dq,
inout [3:0]DDR_dqs_n,
inout [3:0]DDR_dqs_p,
inout DDR_odt,
inout DDR_ras_n,
inout DDR_reset_n,
inout DDR_we_n,
inout FIXED_IO_ddr_vrn,
inout FIXED_IO_ddr_vrp,
inout [53:0]FIXED_IO_mio,
inout FIXED_IO_ps_clk,
inout FIXED_IO_ps_porb,
inout FIXED_IO_ps_srstb
);
wire [11:0] BRAM_PORTA_0_addr;
wire [31:0] BRAM_PORTA_0_din;
reg [31:0] BRAM_PORTA_0_dout;
wire BRAM_PORTA_0_en;
wire BRAM_PORTA_0_rst;
wire [3 :0] BRAM_PORTA_0_we;
wire pl_rstn;
wire pl_clk;
reg [31:0] reg32_0 = 0;
reg [31:0] reg32_1 = 0;
reg [31:0] reg32_2 = 0;
reg [31:0] reg32_3 = 0;
reg [31:0] reg32_4 = 0;
reg [31:0] reg32_5 = 0;
reg [31:0] reg32_6 = 0;
reg [31:0] reg32_7 = 0;
//添加在线逻辑分析仪信号查看数据
ila_0 ila_dg (
.clk(pl_clk), // input wire clk
.probe0({reg32_0,reg32_1,reg32_2,reg32_3,reg32_4,reg32_5,reg32_6,reg32_7}), // input wire [255:0] probe0
.probe1(BRAM_PORTA_0_din), // input wire [31:0] probe1
.probe2(BRAM_PORTA_0_dout), // input wire [31:0] probe2
.probe3(BRAM_PORTA_0_addr), // input wire [7:0] probe3
.probe4({BRAM_PORTA_0_en,BRAM_PORTA_0_rst,BRAM_PORTA_0_we[3:0]}) // input wire [2:0] probe4
);
always@(posedge pl_clk)begin
if((pl_rstn==1'b0) || (BRAM_PORTA_0_rst == 1'b1))begin
reg32_0 <= 32'b0;
reg32_1 <= 32'b0;
reg32_2 <= 32'b0;
reg32_3 <= 32'b0;
reg32_4 <= 32'b0;
reg32_5 <= 32'b0;
reg32_6 <= 32'b0;
reg32_7 <= 32'b0;
end
else if((BRAM_PORTA_0_en==1'b1)&(BRAM_PORTA_0_we==4'hF))begin//ps write to pl reg
case(BRAM_PORTA_0_addr[7:0]) //PS 写 PL 寄存器,以下地址为 4 字节对齐
8'h00:reg32_0 <= BRAM_PORTA_0_din; //PS 写 PL 偏移地址 8’h00 寄存器
8'h04:reg32_1 <= BRAM_PORTA_0_din; //PS 写 PL 偏移地址 8’h04 寄存器
8'h08:reg32_2 <= BRAM_PORTA_0_din; //PS 写 PL 偏移地址 8’h08 寄存器
8'h0C:reg32_3 <= BRAM_PORTA_0_din; //PS 写 PL 偏移地址 8’h0C 寄存器
8'h10:reg32_4 <= BRAM_PORTA_0_din; //PS 写 PL 偏移地址 8’h10 寄存器
8'h14:reg32_5 <= BRAM_PORTA_0_din; //PS 写 PL 偏移地址 8’h14 寄存器
8'h18:reg32_6 <= BRAM_PORTA_0_din; //PS 写 PL 偏移地址 8’h18 寄存器
8'h1C:reg32_7 <= BRAM_PORTA_0_din; //PS 写 PL 偏移地址 8’h1C 寄存器
default: reg32_0 <= BRAM_PORTA_0_din;
endcase
end
else if(BRAM_PORTA_0_en==1'b1)begin//ps read pl reg
case(BRAM_PORTA_0_addr[7:0]) //PS 读 PL 寄存器,以下地址为 4 字节对齐
8'h00:BRAM_PORTA_0_dout <= reg32_0 + 1'b1; //PS 读 PL 偏移地址 8’h00,读会结果为寄存器 reg32_0 加 1
8'h04:BRAM_PORTA_0_dout <= reg32_1 + 1'b1; //PS 读 PL 偏移地址 8’h04,读会结果为寄存器 reg32_1 加 1
8'h08:BRAM_PORTA_0_dout <= reg32_2 + 1'b1; //PS 读 PL 偏移地址 8’h08,读会结果为寄存器 reg32_2 加 1
8'h0C:BRAM_PORTA_0_dout <= reg32_3 + 1'b1; //PS 读 PL 偏移地址 8’h0C,读会结果为寄存器 reg32_3 加 1
8'h10:BRAM_PORTA_0_dout <= reg32_4 + 1'b1; //PS 读 PL 偏移地址 8’h10,读会结果为寄存器 reg32_4 加 1
8'h14:BRAM_PORTA_0_dout <= reg32_5 + 1'b1; //PS 读 PL 偏移地址 8’h14,读会结果为寄存器 reg32_5 加 1
8'h18:BRAM_PORTA_0_dout <= reg32_6 + 1'b1; //PS 读 PL 偏移地址 8’h18,读会结果为寄存器 reg32_6 加 1
8'h1C:BRAM_PORTA_0_dout <= reg32_7 + 1'b1; //PS 读 PL 偏移地址 8’h1C,读会结果为寄存器 reg32_7 加 1
default: BRAM_PORTA_0_dout <= reg32_0 + 1'b1;
endcase
end
end
//以下调用图形化 PL 图形化 BD 模块,这里也可以看出对于 SOC 工程,图形化编程的实质也是 FPGA 编程
system system_i
(
.DDR_addr(DDR_addr),
.DDR_ba(DDR_ba),
.DDR_cas_n(DDR_cas_n),
.DDR_ck_n(DDR_ck_n),
.DDR_ck_p(DDR_ck_p),
.DDR_cke(DDR_cke),
.DDR_cs_n(DDR_cs_n),
.DDR_dm(DDR_dm),
.DDR_dq(DDR_dq),
.DDR_dqs_n(DDR_dqs_n),
.DDR_dqs_p(DDR_dqs_p),
.DDR_odt(DDR_odt),
.DDR_ras_n(DDR_ras_n),
.DDR_reset_n(DDR_reset_n),
.DDR_we_n(DDR_we_n),
.FIXED_IO_ddr_vrn(FIXED_IO_ddr_vrn),
.FIXED_IO_ddr_vrp(FIXED_IO_ddr_vrp),
.FIXED_IO_mio(FIXED_IO_mio),
.FIXED_IO_ps_clk(FIXED_IO_ps_clk),
.FIXED_IO_ps_porb(FIXED_IO_ps_porb),
.FIXED_IO_ps_srstb(FIXED_IO_ps_srstb),
.BRAM_PORTA_0_addr(BRAM_PORTA_0_addr),
.BRAM_PORTA_0_clk(BRAM_PORTA_0_clk),
.BRAM_PORTA_0_din(BRAM_PORTA_0_din),
.BRAM_PORTA_0_dout(BRAM_PORTA_0_dout),
.BRAM_PORTA_0_en(BRAM_PORTA_0_en),
.BRAM_PORTA_0_rst(BRAM_PORTA_0_rst),
.BRAM_PORTA_0_we(BRAM_PORTA_0_we),
.pl_clk(pl_clk),
.pl_rstn(pl_rstn)
);
endmodule
|
3.5地址空间分配初学者需要注意,这个地址分配非常重要,PL端的寄存器空间即是根据这个地址做偏移计算得出
3.6编译并导出平台文件1:单击Block文件à右键àGenerate the Output ProductsàGlobalàGenerate。 2:单击Block文件à右键à Create a HDL wrapper(生成HDL顶层文件)àLet vivado manager wrapper and auto-update(自动更新)。 3:生成Bit文件。 4:导出到硬件: FileàExport HardwareàInclude bitstream 5:导出完成后,对应工程路径的soc_hw路径下有硬件平台文件:system_wrapper.xsa的文件。根据硬件平台文件system_wrapper.xsa来创建需要Platform平台。
4搭建Vitis-sdk工程创建soc_base sdk platform和APP工程。 4.1创建SDK Platform工程启动Vitis-Sdk
设置好路径
米联客资料中的路径规范如下图: soc_prj里面是基于SOC的硬件工程源码 soc_hw里面是xsa格式文件,soc_prj编译会导出system_wrapper.xsa到这个路径 soc_sdk里面是裸机的sdk工程,sdk工程创建依赖soc_hw中的system_wrapper.xsa
单击Create Platform Project 创建基于开发平台的工程
添加之前导出的system_wrapper.xsa文件
创建完成后
最后,右击soc_base完成编译
4.2创建bram_controller_test APP工程首选创建一个空的工程
复制soc_prj/uisrc/07_sdk_src路径下已经编写好的源码到src路径下
之后对工程编译
5程序分析连续写入8个数据到PL的BRAM Controller,然后读出,并且打印出来。
6方案演示
6.1硬件准备本实验需要用到 JTAG 下载器、USB 转串口外设,另外需要把核心板上的 2P 模式开关设置到 JTAG 模式,即 ON ON (注意新版本的 MLK-H3-CZ08-7100FC(米联客 7X 系列),支持 JTAG 模式,对于老版本的核心板,JTAG 调试 的时候一定要拔掉 TF 卡,并且设置模式开关为 OFF OFF)
6.2实验结果
Debug程序,单程序停止main函数处,打开VIVADO,扫描芯片,这个时候会自动之前添加的在线逻辑分析仪IP核。如下红框的按键先不要单击
具体步骤如下: 在VIVADO工程中点击Open Target 然后点击Auto Connect
连接成功后入下图
设置触发条件、观察信号。设置波形偏移500。 Settings -->Trigger position in window:500 Trigger Setup -->添加触发信号BRAM_PORTA_0_en,设置Value为R。如图所示。
启动波形捕捉
SDK中点击继续运行
当信号触发的时,VIVAIDO中Hardware Manager出现捕捉波形,如下图所示
在串口控制台输出结果:
|