本帖最后由 FPGA课程 于 2024-9-29 13:15 编辑
软件版本: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接口的逻辑代码如下: - *TechWeb:https://www.uisrc.com
- *tmall-shop:https://milianke.tmall.com
- *jd-shop:https://milianke.jd.com
- *taobao-shop1: https://milianke.taobao.com
- *Create Date: 2021/10/15
- *Module Name:system_wrapper
- *File Name:system_wrapper.v
- *Description:
- *The reference demo provided by Milianke is only used for learning.
- *We cannot ensure that the demo itself is free of bugs, so users
- *should be responsible for the technical problems and consequences
- *caused by the use of their own products.
- *Copyright: Copyright (c) MiLianKe
- *All rights reserved.
- *Revision: 1.0
- *Signal description
- *1) _i input
- *2) _o output
- *3) _n activ low
- *4) _dg debug signal
- *5) _r delay or register
- *6) _s state mechine
- *********************************************************************/
- `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出现捕捉波形,如下图所示
在串口控制台输出结果:
|