基于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个地址依次存入102432位的数据。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个地址中读出 1PS写入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所对应的地址写入102432位整型数据,PS依次从 BRAM所对应的地址读出 1024 32位整型数据,并判断是否被加了2,若比对不一致则报错。

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

#defineZYNQ7K_BRAM_BASE            (0x40000000)

#defineZYNQ7K_BRAM_SIZE            (SZ_4K)

 

#defineZYNQ7K_XGPIO_BASE            (0x41200000)

#defineZYNQ7K_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关键代码如下:

#definePS_BRAM_MASK            0x00000001

 

inttest_bram(void)

{

 

    unsigned intwrite_data = 0;

    unsigned intread_data;

    inti = 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);

       }

 

    }

 

    return0;

}

 

下载到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

…….

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


版权声明:本文为CPUOS2010原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。