当前位置:   article > 正文

ZYNQ 利用EMIF进行PS与PL间数据交互_fpga实现emif总线与arm通信

fpga实现emif总线与arm通信

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测试结果

写波形

读波形

串口打印输出

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/680815
推荐阅读
相关标签
  

闽ICP备14008679号