基于Lemon ZYNQ的PS实验十三 PS与PL数据交互之 PS访问 PL端的reg 寄存器

PS端与PL端在硬件上是相互独立的,之前可以通过EMIO 和 AXI GPIO等方式 让ZYNQ PS 端的GPIO 口映射到PL端上,但是仅仅只能控制GPIO。 本文介绍一种新的方法,通过让PS端访问PL端寄存器的方式,来让ARM 和FPGA实现简单的数据交互(小数据量)

  • 此章节内容适用于Lemon ZYNQ主板,如是其他板子请看对应板子目录
  • 本文在 vivado2018.3版本上演示

一、工程创建

工程创建的过程可以参考试验一中的内容,这里不再详细描述了。基于Lemon ZYNQ的PS实验一 GPIO之用EMIO方式点亮LED(完整图文)(芯片型号选XC7Z020CLG400-1)

二、创建一个带AXI 接口的IP

1)创建并封装一个带AXI 接口的IP 具体过程如下 ,TOOLS->Create and Package New IP

    2)选择封装带AXI4总线的

    3)next,填写名称等信息,注意IP保存路径(保存到工程目录下就可)。这里给IP取名 PS_PL_REG 即 PS和PL的REG互相访问


    4)next,选择总线相关信息,这里AXI的 协议选择 LITE 轻型, 然后number of registers 根据需求选择,4即代表有四个32bit的寄存器 最小选择是4个

    5) 选择 下一步 EDIT IP 并点FINISH完成(这里一定要选择“Edit IP”,否则,软件只是生成了框架文件,而不会创建一个关于IP 核的工程)

    6)之后系统会自动生成一个该IP的工程。 这里我们双击打开系统默认生成的IP代码

    7)研究代码,可以看到 我们设置IP的时候 PL端的4个用于PS访问的寄存器分别是 slv_reg0,slv_reg1,slv_reg2,svl_reg3 ,这4个寄存器 通过AXI 接口,可供ARM PS端进行读和写的操作。

    8)为了让交互的过程更为直观,我们在原有的IP代码中添加一个LED指示灯用来观察交互的结果

    output reg LED;

    并在代码中增加以下代码用来将灯和数据进行对应

       always@(posedge S_AXI_ACLK)begin
            if(slv_reg0==32'd0)LED<=0;
            else if(slv_reg0<=32'd1)LED<=1;
        end

    代码解释 ,当slv_reg0等于32位的0时 LED 熄灭, 当slv_reg0等于32‘d1时,即十进制1时,LED点亮(slv_reg0后面可由ARM端的程序直接读写)

    9)对系统生成的IP的上层模块,也相应的增加LED 接口,并与内部的模块相连接

    10)编辑完后,保存修改,接下来是打包 修改完的IP(封装之前,先编译综合看看代码是否有报报错),回到Package IP页面设置IP,如下所示输入相关信息,也可以不修改

    11)在file Groups项中点击Merge changs from File Groups Wizard

    12)根据上面的操作,也将软件界面中没有打勾的 选项全部都merge了

    13)当除了最后一项,所有的选项都勾上更新后, 在最后一栏里点重新打包封装IP,完成IP的打包

    IP打包后,修改IP的工程会被系统自动关闭

    三、在vivado工程中增加ZYNQ模块

    1)增加ZYNQ 模块

    在Block Design 中 增加ZYNQ模块,并且在设置界面 将DDR选项设置成 MT41K256M16RE-125 位宽选择16bit

    2)因为Lemon ZYNQ主板的PS时钟是50M的晶振输入的,所以这里需要把默认的PS输入时钟33.33M改成50M

    3)选择 Run Block Automation 完成端口自动布线

    4)手动连接 FCLK_CLK0到 M_AXI_GP0_ACLK

    5)在block design 中添加我们刚才创建的PS_TO_PL_REG IP模块

    6) 如下图所示 我们添加的PS_PL_REG模块已经添加到设计中,再次点选run connection automation尝试自动连线

    如下图所示,系统为我们自动添加需要增加的模块,并自动连接好了各个模块

    7) 因为我们的演示 是需要通过LED 来观察结果的,所以这里右键LED 将LED窗口印出来

    这样我们的整个硬件系统就算布局完成了。

    8) 在design Sources中 右键我们刚刚设计的ZYNQ模块,然后点选 Create HDL Wrapper

    9)编译 RUN

    10)为LED 分配管脚

    11)综合并生成 bit文件

    三、PS部分工程创建

    1)File→Export→Export hardware…,在弹出的对话框中勾选“include bitstream”,点击“OK”确认,如下图所示。

    2)File→Lauch SDK,在弹出的对话框中,保存默认,点击“OK”,如下图所示。

    系统将自动打开SDK开发环境

    3)再创建一个LED 工程,负责LED 指示灯的闪烁

    a. 创建一个新的空工程,可以取名叫PS_PL_REG_TEST

    b.右键工程的SRC目录,然后新建一个SOURCE FILE

    c.取名 main.c

    四、PS端代码编写

    1.点开platform中的 system.hdf 这里所有的资源都会显示在这里, 找到我们之前创建的PS_PL_REG ,可以看到 这个外设的基地址是 0X43C00000 ,后面我们会用到这个地址

    2.在main .c中添加如下代码

    #include "xparameters.h"
    #include "xil_io.h"
    
    #define LED_BASE_ADDR 0x43c00000
    
    int main()
    {
    	volatile int Delay;
    
        while(1)
        {
    
        	Xil_Out32(LED_BASE_ADDR, 1);
        	for (Delay = 0; Delay < 10000000; Delay++);
        	Xil_Out32(LED_BASE_ADDR, 0);
        	for (Delay = 0; Delay < 10000000; Delay++);
        }
    
        return 0;
    }
    

    五、下载与验证

    1)新创建的工程最好先对Run as 进行配置:右键工程,并点选Run As -> Run Configurations

    2) 在弹出的窗口中对Reset entire system 和 Program FPGA两个选项进行勾选操作,这样就不会出现下载程序debug的时候概率性不工作的问题了。(这样操作后系统会自动对FPGA进行配置,不需要按之前工程手动对FPGA进行编程了)

    PS如果没有出现下图对话框,可以直接双击左侧的applicationo (System Debugger)。

    3)设置好之后,选择Run As -> Launch on Hardware (System Debugger) 进行调试。

    可以看到板子上的LED1灯在闪烁

    六、代码解读

    #define LED_BASE_ADDR 0x43c00000,这里的0X43C00000就是我们之前看到的 模块地址

    Xil_Out32(LED_BASE_ADDR, 1); 相当于向上面的模块地址写入1

    Xil_Out32(LED_BASE_ADDR,0) ; 相当于向模块的基地址写入0

    因为我们在PL端创建的模块中的4个寄存器,只有寄存器0对应了LED ,所以我们只要向基地址写入信息就可以控制LED 指示灯了

    如果要控制寄存器1,寄存器2 ,寄存器3 只需要在基地址的基础上+4就可以了 (+4是因为数据都是32bit的)

    另外我们也可以反向用PS 去读取PL端的寄存器值,具体过程不展开描述了, 实际PS访问 可以通过指令Xil_In32(LED_BASE_ADDR); (LED_BASE_ADDR 为我们定义的基地址 )来进行读取。

    通过上述方式 我们成功的实现了 PS和PL 通过寄存器方式的交互,这种方式相对比较简单 容易入手,当然交互的方式还有很多,后面 有时间再继续整理。

    AXI 的通讯也是个大课题,有时间会继续整理相关内容

    • 本文的完整工程下载:13_PS_TO_PL_REG
    • VIVADO的版本:2018.3
    • 工程创建目录: E:\Lemon_ZYNQ\SDK\13_PS_TO_PL_REG

    发表回复

    您的电子邮箱地址不会被公开。 必填项已用 * 标注