ZYNQ-基于BRAM的PS和PL数据交互

本文详细介绍了在Vivado 18.3 & SDK环境下,如何使用PYNQ-Z2开发板配合AXIBRAM控制器与BRAM进行数据交互。通过AXI接口,实现了对数据量少、地址不连续、长度不规则情况的高效处理。内容涵盖BRAM控制器配置、系统框图、硬件平台搭建、读写控制模块设计以及SDK中的软件部分,最后通过ILA验证了数据一致性。
摘要由CSDN通过智能技术生成

学习内容

本文介绍关于AXI BRAM控制器的相关内容,针对数据量较少、地址不连续、长度不规则的情况,通过 BRAM 来进行数据的交互。

开发环境

vivado 18.3&SDK,PYNQ-Z2开发板。

AXI BRAM控制器

简介

BRAM控制器可以用于与 AXI 互连和系统主设备的集成,以与本地块 RAM 进行通信。 内核支持到块 RAM 的单次和突发传输,并针对性能进行了优化。
AX14或AX14- lite控制器配置中,可以配置到BRAM块的单个端口或到BRAM块的两个端口。通过第二个AX14-Lite控制端口连接,AXI BRAM控制器IP可以在数据路径上配置ECC功能,并通过可用的外部ECC寄存器设置。AXI BRAM Controller IP核的顶级端口连接和主模块如下图所示。展示了AX14-Lite模式下,AXI BRAM核心与BRAM块的连接。可以利用BRAM块的单端口利用率或BRAM块的双端口模式(通过参数设置)。
在这里插入图片描述
下图展示了为支持AX14接口而生成的HDL核心。对BRAM块的单端口使用可以配置在双端口配置中增强的性能设置。,详细结构框图如下:
在这里插入图片描述
所有与axis主设备的通信都是通过一个5通道的axis接口进行的。所有写操作都在AXI总线的写地址通道(AW)上启动,该通道指定了写事务的类型和相应的地址信息。写数据通道(W)为单个或突发写操作通信所有写数据。写响应通道(B)用作写操作的握手或响应。

在读操作上,当AXI主程序请求读传输时,读地址通道(AR)通信所有地址和控制信息。当可以处理读操作时,AXI从AXI BRAM控制器IP响应读地址通道(AR)。当读取数据可用时,读数据通道®将转换操作的数据和状态。

支持内存大小

AXI BRAM Controller支持的内存最大为2mbytes(字节大小为8或9),支持的内存宽度和深度如表1-1所示。
在这里插入图片描述
AXI BRAM Controller IP支持的最小深度为512字节。任何小于512的深度都被调整为512字节。

系统框图与工程设计

工程功能设计为PS 将串口接收到的数据写入 BRAM,然后从 BRAM 中读出数据,并通过串口打印出来;与此同时, PL 从 BRAM 中同样读出数据,并通过 ILA 来观察读出的数据与串口打印的数据是否一致。
系统框图如下:
在这里插入图片描述

硬件平台搭建

新建工程,创建 block design。

配置ZYNQ7

添加ZYNQ7 IP,对zynq进行初始化配置,勾选配置uart资源,
在这里插入图片描述
使能clock复位和 M_GP0接口,
在这里插入图片描述
配置时钟,
在这里插入图片描述

配置BRAM控制器和BRAM

接着配置BRAM控制器,基本是默认配置。
在这里插入图片描述
配置BRAM
在这里插入图片描述
连接连线后系统如下,
在这里插入图片描述

设计读取控制模块

首先点击tools创建一个新的IP,
在这里插入图片描述
选择创建一个AXI4接口的IP。
在这里插入图片描述
编辑IP名称等信息,设计IP的接口信息,
在这里插入图片描述
点击finish,完成IP创建。
在这里插入图片描述
在IP目录下找到自己创建好的IP,右键进行IP的编辑。

在这里插入图片描述
在顶层进行例化ram接口。
在这里插入图片描述
在AXI总线协议实现的文件中添加IP的例化,实现AXI-Lite接口的功能进行参数的传递。
在这里插入图片描述
这里引用正点原子的BRAM的读取模块,
bram_rd.v

module bram_rd(
    input                clk        , //时钟信号
    input                rst_n      , //复位信号
    input                start_rd   , //读开始信号
    input        [31:0]  start_addr , //读开始地址  
    input        [31:0]  rd_len     , //读数据的长度
    //RAM端口
    output               ram_clk    , //RAM时钟
    input        [31:0]  ram_rd_data, //RAM中读出的数据
    output  reg          ram_en     , //RAM使能信号
    output  reg  [31:0]  ram_addr   , //RAM地址
    output  reg  [3:0]   ram_we     , //RAM读写控制信号
    output  reg  [31:0]  ram_wr_data, //RAM写数据
    output               ram_rst      //RAM复位信号,高电平有效
);

//reg define
reg  [1:0]   flow_cnt;
reg          start_rd_d0;
reg          start_rd_d1;

//wire define
wire         pos_start_rd;

//*****************************************************
//**                  main code
//*****************************************************

assign  ram_rst = 1'b0;
assign  ram_clk = clk ;
assign pos_start_rd = ~start_rd_d1 & start_rd_d0;

//延时两拍,采start_rd信号的上升沿
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        start_rd_d0 <= 1'b0;   
        start_rd_d1 <= 1'b0; 
    end
    else begin
        start_rd_d0 <= start_rd;   
        start_rd_d1 <= start_rd_d0;     
    end
end

//根据读开始信号,从RAM中读出数据
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        flow_cnt <= 2'd0;
        ram_en <= 1'b0;
        ram_addr <= 32'd0;
        ram_we <= 4'd0;
    end
    else begin
        case(flow_cnt)
            2'd0 : begin
                if(pos_start_rd) begin
                    ram_en <= 1'b1;
                    ram_addr <= start_addr;
                    flow_cnt <= flow_cnt + 2'd1;
                end
            end
            2'd1 : begin
                if(ram_addr - start_addr == rd_len - 4) begin  //数据读完
                    ram_en <= 1'b0;
                    flow_cnt <= flow_cnt + 2'd1;
                end
                else
                    ram_addr <= ram_addr + 32'd4;              //地址累加4
            end
            2'd2 : begin
                ram_addr <= 32'd0; 
                flow_cnt <= 2'd0;
            end
        endcase    
    end
end

endmodule

创建引脚接口,选择任意一个BRAM引脚,创建封装
在这里插入图片描述
设置接口和名称,
在这里插入图片描述
完成接口映射。
在这里插入图片描述
然后点击完成IP封装。
在这里插入图片描述

完成系统设计

完成IP的创建后,添加IP,完成连线,整体设计如下图所示:
在这里插入图片描述
然后在完成综合后进行setup debug ,抓取b端口有关的信号。
在这里插入图片描述
完成添加DEDUG信号后,进行综合生成bit流,然后导出硬件,launch SDK。

SDK软件部分

新建应用工程,
main.c中输入以下代码:

#include "xil_printf.h"
#include "stdio.h"
#include "xbram_hw.h"
#include "ps_pl_rd_ip.h"
#include "xparameters.h"

#define PL_BRAM_START  PS_PL_RD_IP_S00_AXI_SLV_REG0_OFFSET
#define PL_BRAM_START_ADDR PS_PL_RD_IP_S00_AXI_SLV_REG1_OFFSET
#define PL_BRAM_LEN PS_PL_RD_IP_S00_AXI_SLV_REG2_OFFSET
#define PS_PL_BASEADDR XPAR_PS_PL_RD_IP_0_S00_AXI_BASEADDR

#define START_ADDR  0
#define BRAM_DATA_BYTE 4
char input_data[1024];
int len_input_data;
int main(){
	while(1){
		int i=0;
		int wr_cnt=0;
		printf("ps_pl_bram test\n");
		scanf("%s",input_data);
		len_input_data= strlen(input_data);
		for(i = START_ADDR*BRAM_DATA_BYTE;i<(START_ADDR + len_input_data)*BRAM_DATA_BYTE;i+=BRAM_DATA_BYTE)
		{
			PS_PL_RD_IP_mWriteReg(XPAR_BRAM_0_BASEADDR,i,input_data[wr_cnt]);
			wr_cnt++;
		}
		//配置起始地址
		PS_PL_RD_IP_mWriteReg(PS_PL_BASEADDR,PL_BRAM_START_ADDR,START_ADDR*BRAM_DATA_BYTE);
		//配置读取长度
		PS_PL_RD_IP_mWriteReg(PS_PL_BASEADDR,PL_BRAM_LEN,len_input_data*BRAM_DATA_BYTE);
		//使能脉冲
		PS_PL_RD_IP_mWriteReg(PS_PL_BASEADDR,PL_BRAM_START,1);
		PS_PL_RD_IP_mWriteReg(PS_PL_BASEADDR,PL_BRAM_START,0);
		for(i = START_ADDR*BRAM_DATA_BYTE;i<(START_ADDR + len_input_data)*BRAM_DATA_BYTE;i+=BRAM_DATA_BYTE)
		{
			printf("bram address : %d ,read data : %c\n",i/BRAM_DATA_BYTE,PS_PL_RD_IP_mReadReg(XPAR_BRAM_0_BASEADDR,i));
		}
	}
}

部分代码讲解

本次工程比较简单,在while循环中实现了对串口输入的存储和显示打印。

运行效果

在这里插入图片描述

ila抓取数据

通过ILA抓取的读取数据和发送写入的数据一致。
在这里插入图片描述

references

  1. 正点原子开发视频
  2. 正点原子嵌入式开发指南
  3. UG585
  4. PG078
Zynq-7000是由Xilinx公司生产的一款集成了ARM处理器和可编程逻辑(PL)的片上系统(SoC)。它的可编程逻辑部分可以通过重新配置(Reconfigure)来进行定制和优化。 Zynq-7000的可编程逻辑部分由一系列可编程逻辑单元(PLU)组成,可以通过Vivado开发环境进行配置和定制。重配置PL意味着可以改变PL中的逻辑电路,以满足不同的需求。 重配置PL过程大致分为三个步骤。首先,需要使用Vivado开发环境创建和配置逻辑电路。这可以通过使用硬件描述语言(如Verilog或VHDL)来实现,也可以通过使用硬件抽象层次语言(如C、C++或OpenCL)来实现。 其次,需要将配置好的逻辑电路编译成比特流(Bitstream)。比特流是一种描述逻辑电路的中间文件,可以被FPGA芯片理解和加载。 最后,将生成的比特流加载到Zynq-7000的可编程逻辑部分。这可以通过JTAG接口或SD卡等方式实现。一旦比特流被加载,Zynq-7000的可编程逻辑部分就被重新配置为新的逻辑电路。 通过重配置PL,可以实现许多应用场景,例如加速计算、优化算法、嵌入式系统的定制等。它提供了一种便捷的方式来优化和个性化Zynq-7000的使用。 总的来说,Zynq-7000的可编程逻辑部分可以通过Vivado开发环境进行重新配置,以满足不同的需求。这种重配置的过程包括创建和配置逻辑电路、生成比特流、加载比特流到Zynq-7000,并可以应用于各种应用场景。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Vuko-wxh

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

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

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

打赏作者

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

抵扣说明:

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

余额充值