软件版本:VIVADO2017.4
操作系统:WIN10 64bit
硬件平台:适用米联客 ZYNQ系列开发板
米联客(MSXBO)论坛:www.osrc.cn答疑解惑专栏开通,欢迎大家给我提问!!
20.1 概述
AXI-EMC IP是一个可以可以支持各种内存型号的控制器,利用这个IP可以非常方便地模拟各种类型的内存或者FLASH接口实现数据的交互和通信。以下是AXI-EMC IP的功能特性:
1、支持AXI4 Slave Memory Map接口,数据宽度为32位和64位
2、支持写入/读取寄存器的可选AXI4-Lite Slave数据宽度为32位
3、支持AXI4增量和包传输
4、支持AXI4窄带和非对齐传输
5、最多支持四个外部存储器组
6、支持具有可配置字节奇偶校验和流水线级的同步SRAM
7、支持的内存类型
° 同步SRAM
° 异步SRAM
° 线性闪存(或并行NOR闪存)
° PSRAM(或蜂窝RAM)
8、提供配置寄存器,动态更改PSRAM和Micron®闪存的访问机制
9、为同步SRAM存储器提供奇偶校验错误状态寄存器
本课程中,利用EMC实现异步SRAM的功能,实现数据的读写操作。
20.2 FPGA BD工程
以下是搭建好的FPGA BD工程,搭建工程如果不熟悉的用户请参考“CH01 HelloWold/DDR/网口测试及固化”这一节课。
在本课程中主要用到了AXI_EMC这个IP,下面我们看下这个IP的设置,双击这个IP
下图中的的位宽设置为32bit其他参数默认,其中Base Address 和High Address 是AXI_EMC IP在ZYNQ 4GB地址空间中的分配的地址。
下图中,设置Memory Type 为Async SRAM ,也就是异步SRAM。这种SRAM读写起来比较方便。位宽设置为32bit。Timing Parameters是AXI系统时钟为100M的情况下的时间参数,如果采用其他时钟可能要修改时间参数。
下图设置为默认
下图是信息总汇
以下是AXI_EMC IP在ZYNQ 4GB地址空间中的分配的地址
20.3 修改FPGA代码
修改调用BD工程的顶层代码,增加异步SRAM的读写接口,控制逻辑。在以下FPGA代码中,我们的SDK代码会写入4个数据,之后再读出来。
module system_top( 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 clk_100m; wire [31:0]mem_a; wire [0 :0]mem_cen; reg [31:0]mem_dq_i; wire [31:0]mem_dq_o; wire [0 :0]mem_oen; wire mem_wen; //************************************************************************* reg [31:0] data_reg1; reg [31:0] data_reg2; reg [31:0] data_reg3; reg [31:0] data_reg4;
always @ (posedge clk_100m) if(mem_wen==1'b0)begin case(mem_a) 16'h0:begin data_reg1<=mem_dq_o; end 16'h1:begin data_reg2<=mem_dq_o; end 16'h3:begin data_reg3<=mem_dq_o; end 16'h4:begin data_reg4<=mem_dq_o; end default : begin end endcase end
always @ (posedge clk_100m) if(mem_oen==1'b0)begin case(mem_a) 16'h0:begin mem_dq_i<=data_reg1; end 16'h1:begin mem_dq_i<=data_reg2; end 16'h3:begin mem_dq_i<=data_reg3; end 16'h4:begin mem_dq_i<=data_reg4; end default : begin end endcase end
//************************************************************************* wire [131:0] probe0; ila_core ila_core_uut ( .clk(clk_100m), // input wire clk .probe0(probe0) // input wire [99:0] probe0 ); assign probe0[31:0]=mem_a; assign probe0[63:32]=mem_dq_o; assign probe0[95:64]=mem_dq_i; assign probe0[96]=mem_cen; assign probe0[97]=mem_oen; assign probe0[98]=mem_wen;
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), .clk_100m(clk_100m), .mem_a(mem_a), .mem_cen(mem_cen), .mem_dq_i(mem_dq_i), .mem_dq_o(mem_dq_o), .mem_oen(mem_oen), .mem_wen(mem_wen)); |
20.4 SDK代码
/* * main.c * * Created on: 2019年5月21日 * Author: Administrator */
#include <stdio.h> #include "sleep.h"
u32 data[4]; u32 i; int main() { for(i=0;i<4;i++) { Xil_Out32(XPAR_EMC_0_S_AXI_MEM0_BASEADDR+i*4,i); } sleep(1); for(i=0;i<4;i++) { data[i]=Xil_In32(XPAR_EMC_0_S_AXI_MEM0_BASEADDR+i*4); }
for(i=0;i<4;i++) xil_printf("read %d = %d\n\r", i,data[i]);
return 0; } |
以上代码中先写入4个数据,之后在读出来,这里需要注意,ZYNQ是32bit的数据总线所以地址每次要增加4.
20.5测试结果
写波形
读波形
串口打印输出