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.创建硬件工程

截图如下(示例):

ZYNQ PS PL 数据交互 Bram
.bd文件右
ZYNQ PS PL 数据交互 Bram
.bd文件左
ZYNQ PS PL 数据交互 Bram
自己封装的ip,pl写入了512个数据进去,等会ps端读出来。
ZYNQ PS PL 数据交互 Bram
真双口ram配置
ZYNQ PS PL 数据交互 Bram
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;

}

输出效果

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

上一篇:正则表达式


下一篇:【IC】Verilog(1):基本概念