基于Zynq7000平台VxWorks6.9开发应用——PS与PL通信 BRAM应用篇

 

 

   前言

     本篇文章主要讲解在Xilinx ZedBoard上开发PS与PL读写BRAM进行数据通信,从BRAM硬件平台设计、VxWorks6.9开发PS与PL的BRAM读写功能,力求讲述清楚开发流程,并配套完整的演示软件和相关代码进行验证。下面将从以下几个方面进行讲解。

  1. BRAM设计概述
  2. Xilinx Vivado BRAM设计与实现
  3. VxWorks6.9开发PSPLBRAM读写

开发使用工具说明:

  1. Xilinx Vivado2018.3
  2. Xilinx SDK2018.3
  3. WorkBench3.3

 

1、BRAM设计概述

本文介绍一种基于 PL BRAM 的方式,进行 PS PL之间的数据交互。适用于在 PS PL 之间传输少量,地址不连续且长度不规则的数据。

在本例中,在PL端设计了14KB(位宽 32,深度1024)的BRAM。首先, PS通过M_AXI_GP口向BRAM1024个地址依次存入1024 32位的数据。PS 每向BRAM完成写入 1 32 位数据后通过AXI GPIO输出 1 个上升沿信号, PL捕获上升沿后立即将 PS 写入的 32 位数据读出,然后加 2,再存入原地址中。PS主动从BRAM中读出数据,判断对应地址的数据是否被加了 2若不一致,则报错。

 

1.1 BRAM Vivado工程

BRAMFPGA工程框图如图1所示,需要说明的是VIVADO 2017.4 开始可以使用 axi_smc IP 这个 IP AXI_interconnect IP功能类似,但是没有 AXI_interconnect IP强大,在一些高带宽的要求下,还是要用AXI_interconnect IP 本文使用的VIVADO2018.3自动连线会优先使用axi_smcIP

图1 BRAM FPGA框图

(1)PS配置使能 M_AXI_GP0口,将FCLK_CLK0 设为100MHz。

 

(2)AXI BRAM Controller该IP核连接PSM_AXI_GP0口和BRAM,完成 AXI 接口至 BRAM接口的转换。设置如下图所示。

添加 BRAM,将 BRAM设置为双口RAM,将PORTAAXI BRAM Controller连接, PS 通过 PORTA读写BRAM,将 PORTB引出至外部模块, PL 通过 PORTB 读写 BRAM。如下图所示。

由于要与AXI BRAM Controller进行连接,BRAM接口的位宽固定为 32 位。BRAM的深度无法在该 IP 中进行设置,需要在所有模块连接完成后,在Address Editor里对AXI BRAM Controller 的地址范围进行设置,设置为 4KB。该地址范围即对应BRAM的深度,如下图所示。

(3)添加AXI GPIO,位宽设为 1,设置如下图所示。其中 GPIO0作为 PS PL 输出的 PS BRAM 写入完成信号,对于PL而言,上升沿有效。

 

1.2  BRAM逻辑设计

PL部分逻辑设计主要包括以下几个过程:检测AXI GPIO输出GPIO0的上升沿;若检测到 GPIO0 的上升沿,则从 BRAM 的某 1 个地址中读出 1 PS写入32位数据,然后加 2,存入原地址中;不断循环上述过程,依次遍历BRAM0~4092的地址范围。

逻辑代码如下:

module system_wrapper_BRAM(

   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 [31:0]BRAM_PORTB_addr;

  wire BRAM_PORTB_clk;

  wire [31:0]BRAM_PORTB_din;

  wire [31:0]BRAM_PORTB_dout;

  wire BRAM_PORTB_en;

  wire BRAM_PORTB_rst;

  wire [3:0]BRAM_PORTB_we;

  wire [0:0]GPIO_tri_i_0;

  wire [0:0]GPIO_tri_o_0;

  wire [0:0]aresetn;

 

   reg gpio_tri_o_0_reg;

   reg ps_bram_wr_done;

   reg bram_en;

   reg [3:0]  bram_we;

   reg [31:0] bram_addr;

   reg [31:0] bram_rd_data;

   reg [31:0] bram_wr_data;

   reg [2:0] state;

  

   localparam  BRAM_ADDRESS_HIGH = 32'd4096 - 32'd4;

  

   always@(posedge FCLK_CLK0)

     begin

         if(!aresetn)

             gpio_tri_o_0_reg <= 1'b0;

         else

             gpio_tri_o_0_reg <= GPIO_tri_o_0;

     end

  

   always@(posedge FCLK_CLK0)

     begin

         if(!aresetn)

             ps_bram_wr_done <= 1'b0;

         else if({gpio_tri_o_0_reg, GPIO_tri_o_0} == 2'b01) //gpio0 rising edge

             ps_bram_wr_done <= 1'b1;

         else

             ps_bram_wr_done <= 1'b0;

     end

    

   always@(posedge FCLK_CLK0)

     begin

         if(!aresetn) begin

             bram_we <= 4'd0;

             bram_en <= 1'b0;

             bram_addr <= 32'd0;

             bram_rd_data <= 32'd0;

             bram_wr_data <= 32'd0;

             state <= 3'd0;

         end

         else begin

             case(state)

             0: begin

                   if(ps_bram_wr_done) begin

                       bram_en <= 1'b1;

                         bram_we <= 4'd0;

                       state <= 1;

                   end

                   else begin

                       state <= 0;

                       bram_en <= 1'b0;

                         bram_we <= 4'd0;

                       bram_addr <= bram_addr;

                   end

                end

             1: begin

                   bram_en <= 1'b0;

                   state <= 2;

                end

             2: begin

                   bram_rd_data <= BRAM_PORTB_dout;

                   state <= 3;

                end           

             3: begin

                   bram_en <= 1'b1;

                   bram_we <= 4'hf;

                   bram_wr_data <= bram_rd_data + 2;

                   state <= 4;

                end

             4: begin

                   state <= 0;

                   bram_en <= 1'b0;

                   if(bram_addr == BRAM_ADDRESS_HIGH)

                      bram_addr <= 32'd0;

                   else

                      bram_addr <= bram_addr + 32'd4;

                end

             default: state <= 0;

             endcase

         end

     end

    

    

   assign BRAM_PORTB_en = bram_en;

   assign BRAM_PORTB_we = bram_we;

   assign BRAM_PORTB_rst = ~aresetn;

   assign BRAM_PORTB_clk = FCLK_CLK0;

   assign BRAM_PORTB_addr = bram_addr;

   assign BRAM_PORTB_din = bram_wr_data;

  

  system system_i

       (.BRAM_PORTB_addr(BRAM_PORTB_addr),

        .BRAM_PORTB_clk(BRAM_PORTB_clk),

        .BRAM_PORTB_din(BRAM_PORTB_din),

        .BRAM_PORTB_dout(BRAM_PORTB_dout),

        .BRAM_PORTB_en(BRAM_PORTB_en),

        .BRAM_PORTB_rst(BRAM_PORTB_rst),

        .BRAM_PORTB_we(BRAM_PORTB_we),

        .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),

        .FCLK_CLK0(FCLK_CLK0),

        .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),

        .GPIO_tri_i({GPIO_tri_i_0}),

        .GPIO_tri_o({GPIO_tri_o_0}),

        .GPIO_tri_t(),

        .aresetn(aresetn));

       

endmodule

 

2、VxWorks6.9开发BRAM读写功能

VxWorks6.9BRAM读写功能测试函数的完成的功能如下:PS配置 AXI GPIO控制GPIO0产生上升沿依次向 BRAM 所对应的地址写入1024 32 位整型数据,PS依次从 BRAM 所对应的地址读出 1024 32 位整型数据,并判断是否被加了2,若比对不一致则报错。

  1. 首先在sysLib.c中配置BRAM和AXI GPIO映射的内存配置。

#define ZYNQ7K_BRAM_BASE            (0x40000000)

#define ZYNQ7K_BRAM_SIZE            (SZ_4K)

 

#define ZYNQ7K_XGPIO_BASE            (0x41200000)

#define ZYNQ7K_XGPIO_SIZE           (SZ_64K)

 

{

    ZYNQ7K_BRAM_BASE,    /* bram axi address */

    ZYNQ7K_BRAM_BASE,

    SZ_4K,

    MMU_ATTR_VALID_MSK | MMU_ATTR_PROT_MSK | MMU_ATTR_DEVICE_SHARED_MSK,

    MMU_ATTR_VALID     | MMU_ATTR_SUP_RWX  | MMU_ATTR_DEVICE_SHARED

    }, 

   

    {

    ZYNQ7K_XGPIO_BASE,    /* xgpio axi address */

    ZYNQ7K_XGPIO_BASE,

    SZ_64K,

    MMU_ATTR_VALID_MSK | MMU_ATTR_PROT_MSK | MMU_ATTR_DEVICE_SHARED_MSK,

    MMU_ATTR_VALID     | MMU_ATTR_SUP_RWX  | MMU_ATTR_DEVICE_SHARED

    },  

  1. BSP包里面新建bram文件夹,新建AXI GPIO和BRAM操作的代码文件。如下图所示。

 

bram.c关键代码如下:

#define PS_BRAM_MASK            0x00000001

 

int test_bram(void)

{

 

    unsigned int write_data = 0;

    unsigned int read_data;

    int i = 0;

 

    while(1)

    {

       /*write 1024 32bit data to bram*/

       for(i = 0; 4*i < (XPAR_BRAM_0_HIGHADDR - XPAR_BRAM_0_BASEADDR); i++)

       {

           write_data = i;

   

           /*pull gpio0 high*/

           vxWritel(write_data, XPAR_BRAM_0_BASEADDR + 4*i);

           XGpio_DiscreteWrite(1, PS_BRAM_MASK);

           usleep(1);  //延时1US,等待PL修改数据完毕

           /*pull gpio0 low*/

           XGpio_DiscreteWrite(1, ~PS_BRAM_MASK);

       }

 

       /*read 1024 32bit data from bram*/

       for(i = 0; 4*i < (XPAR_BRAM_0_HIGHADDR - XPAR_BRAM_0_BASEADDR); i++)

       {

           read_data = vxReadl(XPAR_BRAM_0_BASEADDR + 4*i);

           printf("data at address %d is 0x%08x\r\n", 4*i, read_data);

           /*compare data read form bram if they are add by 2*/

           if(read_data != (i + 2))

              printf("error: data at address %d should be %d, but is 0x%08x\r\n", 4*i, (i + 2), read_data);

       }

 

    }

 

    return 0;

}

 

下载到ZedBoard测试结果部分如下所示,验证了PS与PL通过BRAM通信的正确性。

data at address 0 is 0x00000002

data at address 4 is 0x00000003

data at address 8 is 0x00000004

data at address 12 is 0x00000005

data at address 16 is 0x00000006

data at address 20 is 0x00000007

data at address 24 is 0x00000008

data at address 28 is 0x00000009

data at address 32 is 0x0000000a

data at address 36 is 0x0000000b

…….

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 2
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CPUOS2010

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值