其他分享
首页 > 其他分享> > ZYNQ PS PL 数据交互 Bram

ZYNQ PS PL 数据交互 Bram

作者:互联网

文章目录


前言

关于zynq PS PL 数据交互的方式,本文搭建了一个基于Bram的数据交互方式


以下是本篇文章正文内容,下面案例可供参考

一、ZYNQ数据交互方式

AXI DMA
AXI DMA 主要进行大批量的数据交换,有两种模式Direct Register Mode和Scatter/Gather Mode,前者为传统的DMA方式,目标地址,源地址,长度,就可以完成一次连续的读/写,后者可以完成复杂一点读/写操作,按照设定的规则跳着读/写一段地址。
AXI BRAM
AXI BRAM主要进行少量的数据交换,与PL端例化双口RAM大小有关,本生借助AXI control ip 与PS端实现读/写,PL端读/写主要通过双口RAM的另一个口进行读/写,注意点在于,因为要满足AXI control ip的要求所以双口ram要设置成32bit的模式,考虑到PS PL读写不能冲突,所以直接双口ram设置成真双口ram。
网上及主流教程Bram的教程都是直接用两个AXI总线完成的,基本上都是PS控制的为主,本文主要不同之处在于搭建pl端读写的自制ip与ps端进行数据交互。

二、Create Block Design

1.创建硬件工程

截图如下(示例):

.bd文件右
.bd文件右
.bd文件左
.bd文件左
自己封装的ip
自己封装的ip,pl写入了512个数据进去,等会ps端读出来。
真双口ram配置
真双口ram配置
ram接口位宽配置
ram接口位宽配置

2.封装的ip代码

代码如下:

module Bram_rw_control(
    input    clk,
    input    rst_n,
    output [31:0]  addra  ,
    output  clka    ,
    output [31:0] dina   ,
    input [31:0] douta  ,
    output  ena    ,
    output  rsta   ,
    output[3:0]  wea    
    );
//wire [31:0] addra;
//wire        clka ;
//wire [31:0] dina ;
//wire [31:0] douta;
reg rsta_reg;
reg ena_reg;
assign        ena  = ena_reg ;
assign        rsta = rsta_reg ;

reg  [3:0]  wea_reg= 4'd0000;
//wire [3:0]  wea  ;
reg  [31:0] addra_reg = 'd0;
reg  [31:0] dina_reg = 'd0;
reg  [31:0] douta_reg = 'd0;
assign addra = addra_reg;
assign dina = dina_reg;
assign wea = wea_reg;
assign clka = clk;
reg data_val0 = 'd0;
reg data_val1 = 'd0;

// 状态空间定义
parameter  idle     =   2'b00;
parameter  read     =   2'b01;
parameter  write    =   2'b11;
parameter  stop     =   2'b10;
reg  [1:0]    state_current      ;
reg  [1:0]    state_next         ;
reg  [9:0]    count              ;

//count 计数 0-1023循环
always  @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
         count <= 'd0;
    end
    else if(count == 'd512)begin
         count <= 'd512;
    end
    else begin
         count <= count + 'd1;
    end
end 
// 状态的转移
always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
         state_current <= idle;
    end
    else begin
         state_current<=state_next;
    end
end 

// 状态转移条件
always  @(*)begin
    case(state_current)
       idle: begin
                state_next <= write   ;
       end
       read:begin
           if(count >= 'd512)
                state_next <= read    ;
           else
                state_next <= write   ;
       end
       write:begin
           if(count <= 'd511)
                state_next <= write    ; 
           else
                 state_next <= stop     ;
       end
       stop:begin
           if(count == 'd512)
                state_next <= stop    ; 
           else
                 state_next <= read     ;
       end
       default: state_next <= idle     ;
   endcase
end 

//第三段,产生输出
always @(posedge clk)
begin
      case(state_current)
           idle:
           begin                   
              wea_reg  <= 4'd0000;  
              ena_reg  <= 1'd1;   
              rsta_reg <= 1'd0;  
            end
           read:
           begin                   
              wea_reg  <= 4'b0000;//0011
              data_val0 <= 'd1;
              data_val1 <= data_val0;
              if(data_val1)douta_reg <= douta;
          //     dina_reg <= 'b0;
              addra_reg <= addra_reg - 'd4;    
            end
           write:
           begin                   
              wea_reg  <= 4'b1111;
              data_val0 <= 'd0;
              data_val1 <= 'd0;
              douta_reg <= 'd0;
              dina_reg <= dina_reg + 'd2; 
              addra_reg <= addra_reg + 'd4;
            end
            stop:
            begin                   
              wea_reg  <= 4'b1111;
              data_val0 <= 'd0;
              data_val1 <= 'd0;
              douta_reg <= 'd0;
              dina_reg <= 'd0; 
              addra_reg <= 'd0;
              ena_reg  <= 1'd0; 
             end
          //   default:;
      endcase
end


//blk_mem_gen_0 my_blk_mem_gen_0(
//  .addra      (addra          ), 
//  .clka       (clk           ),  
//  .dina       (dina           ), 
//  .douta      (douta          ), 
//  .ena        (ena         ), 
//  .rsta       (rsta          ), 
//  .wea        (wea            ) 
//);

endmodule

这是自己封装的一个测试ip用于pl端读写Bram

3.使用vitis写ps端程序

导入硬件工程,旧版的.hdf,新版的.xsa文件,编译一下,新建例程hello world,然后改一下helloworld.c。
代码如下

/*

* mai.c

*

*  Created on: 2016年6月26日

*      Author: Administrator

*/

#include <stdio.h>

#include "xil_io.h"   //这个头文件下面包含很重要的IO读写函数

#include "xparameters.h"  //这个头文件里把硬件的地址映射等参数都写成了宏定义方便使用

//void print(char *str);

int main()

{
       int num;
       int rev;
       for( num=0; num<500; num++ )
              {
                   ;
              }
    xil_printf("------The test is start...------\n\r");
    //XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR是axi_bram_ctrl_0的地址,Xil_Out32通过控制axi_bram_ctrl_0,向blk_mem_gen_0写数据
//    for( num=0; num<15; num++ )
//
//    {
//       Xil_Out32(XPAR_BRAM_0_BASEADDR + num*4, 0x10000000+num);     //
//
//    }
    //XPAR_AXI_BRAM_CTRL_1_S_AXI_BASEADDR是axi_bram_ctrl_1的地址,Xil_In32 通过控制axi_bram_ctrl_0,把blk_mem_gen_0里的数据读出来
    //PS和PL可以在blk_mem_gen_0里共享数据
   for( num=0; num<20; num++ )
       {
            rev = Xil_In32(XPAR_BRAM_0_BASEADDR + num*4);
            xil_printf( "The PL write data at %x is %x \n\r",XPAR_BRAM_0_BASEADDR + num*4,rev);
       }
   xil_printf("------PS read PL BrAM ok!------\n\r");
//    XPAR_AXI_BRAM_CTRL_0_S_AXI_BASEADDR是axi_bram_ctrl_0的地址,Xil_Out32通过控制axi_bram_ctrl_0,向blk_mem_gen_0写数据

    for( num=0; num<10; num++ )
    {
       Xil_Out32(XPAR_BRAM_0_BASEADDR + num*4, 0x10000000+num);    
    }
    xil_printf("------PS write BrAM ok!------\n\r");
    for( num=0; num<20; num++ )
        {
             rev = Xil_In32(XPAR_BRAM_0_BASEADDR + num*4);
             xil_printf( "The PS write data at %x is %x \n\r",XPAR_BRAM_0_BASEADDR + num*4,rev);
        }
    xil_printf("------The test is end!------\n\r");
    return 0;

}

输出效果

输出效果如图:
输出
PL端对RAM连续写入以2自增的数写入,每一个数32bit 一个字节8bit,所以基址偏移增量为32/8为4,所以左边的地址以4自增,最终程序读了20个pl端写入的值,写了10个值,又读20个值对比pl端写入ps端写入,现在的输出截图是最初版截图,现在没有实物板子不方便在跑一遍输出截个图。
工程版本是2019.2的,zynq7010,我放在我的资源里,0积分,可以下载一波。

标签:PS,num,ZYNQ,BRAM,AXI,reg,PL
来源: https://blog.csdn.net/z555hzl/article/details/119906471