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

基于zynq7000平台的vxWorks6.9移植(上) 编写本文档的目的在于指导用户如何移植基于z7平台的vxWorks6.9系统。分上下两篇,帮助新手可以独立完成。 阅读详情

 

 

   前言

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

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

开发使用工具说明:

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

 

1、BRAM设计概述

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

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

 

1.1 BRAM Vivado工程

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

图1 BRAM FPGA框图

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

 

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

添加 BRAM,将 BRAM设置为双口RAM,将PORTA与AXI 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,存入原地址中;不断循环上述过程,依次遍历BRAM中0~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.9的BRAM读写功能测试函数的完成的功能如下: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

…….

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ZYNQ学习之路(二):PS与PL通过BRAM交互 在 ZYNQ SOC 开发过程中, PL 和 PS 之间经常需要做数据交互。对于传输速度要求较高、数据量大、地址连续的场合,可以通过AXI DMA 来完成。而对于数据量较少、地址不连续、长度不规则的情况,此时 AXI DMA 便不再适用了。针对这种情况,可以通过 BRAM 来进行数据的交互。 实验目的:将数据从PS端写入PL部分的BRAM,然后将数据从BRAM读出来与原数据进行比较,判断是否写入成功。 一、搭建硬件框图 首先添加ps处理器,只需添加UART串口并设置相应的DDR型号即可,虽然我们用不到 阅读详情

相关推荐

基于Zynq7000平台VxWorks6.9开发应用—组件开发应用篇

基于Zynq7000平台VxWorks6.9开发应用—组件开发应用篇 前言 本篇文章主要讲解在Workbench3.3的IDE开发工具上添加VxWorks6.9相关的shell、内存盘、FTP、Telnet和FTP等开发常用和必备的组件,同时配套完整的组件测试验证。 开发使用工具说明: WorkBench3.3 1 添加组件 1.1 Shell Command (1)打开“Kernel Configuration”,“development tool components”添加“k...

CPUOS2010的博客 4480

VxWorks在Zynq平台上的移植详细流程

详细介绍了VxWorks移植到Zynq平台,包括bootrom和内核(vxWorks、vxworks.sym),通过QSPI启动bootrom,文件系统(TFFS)挂载到EMMC中,以及调试EMMC驱动,以及应用程序的开发

基于zynq7000平台的vxWorks6.9移植(中)

本文档的目的在于指导用户如何移植基于z7平台的vxWorks6.9系统。移植之前首先感谢西安迅尔电子嵌入式工程师庞国强,本次是基于前者总结资料的基础上进行的完善,帮助新手可以以更少的指导掌握z7平台关于vxWorks的BSP移植。 vxWorks系统移植主要包括两部分,分别是==bootrom移植==和==vxWorks系统镜像移植==。==bootrom的作用类似于u-boot,主要是完成一些基本外设的初始化==,例如内存、串口和网口等...

m0_71550886的博客 3545

zynq-7z035实现PS对PL端的BRAM的读写实验

0、参考资料 原子哥网站的一些教学pdf 1、实验任务 通过PS的串口,向PS发送数据,PS将收到的数据给PL并且写入到BRAM中,然后同时,也能够读取BRAM中的数据返回到串口中。同时为了,实现ILA的在线的分析的功能,新增加手动的bram 控制模块,对bram 进行读写的控制。 2、实验结构图 具体的接口如下图所示 3、实验过程 3.1 建立vivado...

scottar的博客 2357

工控机移植vxWorks操作系统

vxworks 工控机

xu20151111的博客 772

【JokerのZYNQ7020】Vxworks 6.9。

软件环境:vivado 2017.4 硬件平台:XC7Z020 基本全程参考的官方xapp1158-zynq-7000-vxworks-bsp.pdf,但我感觉主要难度不在移植上,因为pdf里面写的已经非常详细了,而在于你是否有license能装vxworks,除了xapp1158之外,xapp1258-vxworks-7-bsp.pdf,也是一个相关的将vxworks移植到zyn...

Joker_是小王的博客 5719

vxWorks BSP 移植-zynq7010/zynq7020 bsp 移植

实现在zynq7020 demo 板上运行vxWorks

yhcs1213的专栏 2388

xilinx zynq ps端移植vxworks6.9系统

基于a board support package,选择xlnx_zynq7k BSP,编译工具链选择diab,勾选Enable WDB Target Agent,选择next下一步,VxWorks Image Project Multipage Wizard就配置完成。从the New VxWorks Image Project中,profile选择PROFILE_DEVELOPMENT,单击finish。project中选择open development shell打开vxworks脚本编译窗口。

wangjie36的博客 5594

ZYNQMP_XAZU3EG_VxWorks7 添加GEM 千兆网卡

1.修改设备树文件 &gem3 { status = "okay"; phy-handle = <&phy3>; phy3: ethernet-phy@12 { compatible = "genericPhy"; reg = <12>; rgmii-delay = <0x3>; rx-internal-delay = <0x8>...

u014689277的博客 1259

ZYNQ移植vxworks6.9

zynq移植Vxworks6.9 1.串口更改 2.网口更改 3.建立BSP工程 4.建立VIP镜像工程 5.生成并烧录BOOT.bin 6.配置FTP服务器

生命的精灵的博客 5264

makefile语法步骤总结

# $(wildcard 指定文件类型) 用于查找指定目录下指定类型的文件 # 这条规则表示,找到目录./src下所有后缀为.c的文件,并赋值给变量SRC。命令执行完,SRC变量的值:./src/ask.c ./src/100.c SRC = $(wildcard ./src/*.c) # $(patsubst 原模式, 目标模式, 文件列表) 用于匹配替换 # 这条规则表示,把变量 SRC 中所有后缀为.c的文件替换为.o。 命令执行完,OBJ变量的值:./src/ask.o ./src/100.

wangjie36的博客 4712

zynq7020 vxWorks移植问题笔记:网卡无法ping通,phy无法识别

一、问题描述 1. KSZ9031 在vxWorks移植过程中无法被识别,网卡无法在vxWorks 中显示且不能ping通 2. 网卡能在vxWorks 显示后,无法ping通,打开驱动调试信息,报错hresp not ok 二、解决办法 1.phy识别:研究原理图,发现phy芯片连接方式计算的phy地址错误,改变后,phy能正确识别 修改hwconf文件中网卡资源定义 2.hre...

Surest的博客 7224

实时系统vxWorks - zynq7020移植vxWorks

概述关于zynq的启动方式,网上百度有一大堆,这里就不详细阐述了,小编整理了一下主要流程大致为:上电->bootRom->FSBL->操作系统。BootRom:硬件固化,...

不只会拍照的程序猿 1万+

vxworks6.9 应用程序以太网不通,

最近在移植xilinx zynq7000 以太网驱动时候,boot以太网没问题,应用起来不行,经过测试发现,在mii总线上系统在调用 LOCAL void miiBusDevInstConnect()函数时候有个互斥信号量 判断 if (miiBusMutex != NULL) return; 当检测到miiBusMutex !=NULL,终止调用了循环扫描函数。因此判断没有插入网线,不能联网。 ...

harhy的专栏 1200

听说Zynq-通过tftp加载镜像

本文主要介绍在linux中如果通过tftp加载启动镜像,以及将启动方式固话到uboot程序中。

不只会拍照的程序猿 1760

ZYNQ通过PS访问PL端BRAM例程

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

Zynq 7000 PL和PS通信——使用BRAM

Zynq 7000 PL和PS通信——使用BRAM介绍1 准备工作2 PL搭建BRAM3 下载PL程序4 编写Linux应用程序5 问题5.1 BRAM的寻址的问题5.2 PS地址映射 介绍 Xilinx公司的Zynq 7000系列SoC除了有功能强大的FPGA,还集成了双PS。在协同使用PS和PL时,就不免需要PS和PL之间进行数据交互。本文主要讲述安装了linux操作系统的PS如何与PL进行数...

STR618的博客 1万+

ZYNQ PS响应PL中断例程

ZYNQ PS和PL如何同步?演示ZYNQ的ARM端响应FPGA端的中断请求。 工程对应的演示视频:https://www.ixigua.com/6878487931313455619/

上一篇: 基于Zynq7000平台VxWorks6.9开发应用——FPGA动态加载篇
下一篇: 基于Zynq7000平台VxWorks6.9开发应用——SMP多核任务篇
CPUOS2010
博客等级 码龄5年 88粉丝 33原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

打赏作者

CPUOS2010

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

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

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

打赏作者

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

抵扣说明:

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

余额充值