回顾

(1)ZYNQ中PS端MIO操作
(2)ZYNQ中PS端MIO中断
(3)ZYNQ中PS端UART通信(4)ZYNQ中PS端XADC读取(5)Zynq中PL读写PS端DDR数据


PS端对PL端进行小批量的数据交换,可以通过BRAM模块,也就是Block RAM实现此要求。通过ZynqGP Master接口读写PL端的BRAM,实现与PL的交互。

zynq中PS访问BRAM(一)_java

PS端通过AXI  BRAM Controller读取BRAM数据,CPU仅配置自定义的PL BRAM Controller的寄存器,不通过它读写数据。


PL端写数据进入BRAM,等待写入完成后产生一个GPIO中断通知PL端可以通过AXI BRAM Controller读写BRAM 

BRAM Controller设置

zynq中PS访问BRAM(一)_java_02

由于AXI4总线为字节询址,BRAM数据宽度设置也是32位,同样都是32位数据宽度,因此在映射到BRAM地址时,需要按4字节询址,即去掉最后两位,下图为BRAM控制器与BRAM的映射关系。

zynq中PS访问BRAM(一)_java_03

Address Editor中设置BRAM大小以及寄存器的地址。

zynq中PS访问BRAM(一)_java_04

硬件框图如下:

zynq中PS访问BRAM(一)_java_05

PL端读写RAM控制代码:

module ram_read_write

    (

        input              clk,

        input              rst_n,

        

     input      [31:0] din,      

        output reg [31:0]  dout,

        output reg         en,

        output reg [3:0]   we,

        output             rst,

        output reg [31:0]  addr,

        

        input              start,

        input     [31:0]  init_data,

        output reg         start_clr,

        output reg         write_end,

        input     [31:0]  len,

        input     [31:0]  start_addr

    );

 

 

assign rst = 1'b0 ;

      

localparam IDLE      = 3'd0 ;

localparam READ_RAM  = 3'd1 ;

localparam READ_END  = 3'd2 ;

localparam WRITE_RAM = 3'd3 ;

localparam WRITE_END = 3'd4 ;

 

reg [2:0] state ;

reg [31:0] len_tmp ;

reg [31:0] start_addr_tmp ;

 

//write part     

always @(posedge clk or negedge rst_n)

begin

  if (~rst_n)

  begin

    state      <= IDLE  ;

       dout       <= 32'd0 ;

       en         <= 1'b0  ;

       we         <= 4'd0  ;

       addr       <= 32'd0 ;

       write_end  <= 1'b0 ;

       start_clr  <= 1'b0 ;

       len_tmp    <= 32'd0 ;

       start_addr_tmp <=32'd0 ;

  end

      

  else

  begin

    case(state)

       IDLE            : begin

                                 if (start)

                                          begin

                                   state <= READ_RAM     ;

                                            addr <= start_addr   ;

                                            start_addr_tmp <= start_addr ;

                                            len_tmp <= len ;

                                            dout <= init_data ;

                                            en   <= 1'b1 ;

                                            start_clr <= 1'b1 ;

                                          end                 

                                    write_end <= 1'b0 ;

                               end

 

   

    READ_RAM        : begin

                           if ((addr - start_addr_tmp)== len_tmp - 4)

                                          begin

                                            state <= READ_END ;

                                            en   <= 1'b0     ;

                                          end

                                          else

                                          begin

                                            addr <= addr + 32'd4 ;                                    

                                          end

                                          start_clr<= 1'b0 ;

                                     end

                                    

    READ_END        : begin

                           addr  <= start_addr_tmp ;

                           en <= 1'b1 ;

                        we<= 4'hf ;

                                       state <= WRITE_RAM  ;                                    

                                     end

   

       WRITE_RAM       : begin

                           if ((addr - start_addr_tmp)== len_tmp - 4)

                                          begin

                                            state <= WRITE_END ;

                                            dout <= 32'd0 ;

                                            en   <= 1'b0  ;

                                            we   <= 4'd0  ;

                                          end

                                          else

                                          begin

                                            addr <= addr + 32'd4 ;

                                            dout <= dout + 32'd1 ;                                    

                                          end

                                     end

                                    

       WRITE_END       : begin

                           addr <= 32'd0 ;

                                          write_end<= 1'b1 ;

                                       state <= IDLE ;                                     

                                     end     

       default         : state <= IDLE ;

       endcase

  end

end 

      

endmodule