《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第二十章 AXI4接口之DDR读写实验​
  95kVyaJuybju 2023年11月13日 15 0

AXI4接口之DDR读写实验​

Xilinx从Spartan-6和Virtex-6系列开始使用AXI协议连接IP核。在ZYNQ MPSOC器件中Xilinx在IP核继续使用AXI协议。本章我们对AXI协议作一个简单介绍,并在Vivado实现一个AXI4接口IP核,用于对MPSOC PS端DDR4进行读写测试。

本章包括以下几个部分:

  1. 简介
  2. 实验任务
  3. 硬件设计
  4. 软件设计
  5. 下载验证


简介

MPSOC性能ARM Cotex-A系列处理器与性能FPGA芯片内紧密结合,为设计带来了如减小体积和功耗、降低设计风险,增加设计灵活性等诸多优点。在将不同工艺特征的处理器与FPGA融合在一个芯片上之后,内处理器与FPGA之间的互联通路就成了MPSOC芯片设计的之重。如果Cotex-A53与FPGA之间的数据交互为瓶颈,那么处理器与FPGA结合的性能优势就不能发挥出来。

们在前面的实验中介绍了一些MPSOC PS与PL交互所使用的接口,比如《EMIO按键控制LED实验》中EMIO,以及《AXI GPIO按键控制LED实验》中的AXI4-Lite接口等。其中AXI4-Lite接口属于AXI4总线协议,接下来我们将对该协议作一个具体的介绍。

AXI的英文全称是Advanced eXtensible Interface即高级可扩展接口,它ARM公司所提出的AMBA(Advanced Microcontroller Bus Architecture)协议的一部分。在介绍AXI协议之前,我们首先对通信协议有一个基本的概念。

简单来说,通信协议是指双方进行信息传递所遵循的规则和约定。其实我们的生活当中比如在打电话的时候,遵循着一些基本“通信协议为了更形象说明这一概念,我们首先来看个通话记录:

《少林寺的通话记录》

老方丈:下午张三丰和灭绝师太要来参观,你去机场接一下,我把他俩手机号给你//机发送控制信号

小和尚:好的,稍等,我找张纸记一下。

老方丈:嗯。 //主机等待

小和尚:我准备好了,您说吧。 //返回Ready信号

老方丈:张三丰的是“123-321-34567”,灭绝师太的是“123-456-56789”。 //机突发传输数据

小和尚:记下来了。 //返回响应信号

上面的通话记录一次完整的通信过程,传输信息是两个手机号。“老方丈”当成主机,“小和尚”当成从机,那么这一通信过程由主机发起,最终向从机写入两组数据(手机)。我们需要注意的是整个过程中二者的协调配合为了确保数据传输误,机需要等从机准备好之后才能发送数据另外机在接收数据完成后,会发送响应信号,表示传输完成。

然后再来看另外一个通话记录:

《武当山的通话记录》

张三丰:下午我要去趟少林寺,你把方丈的手机号找给我 //机发送控制信号

小道士:找到了,188-666…… //从机返回有效数据

张三丰:等一下,我找支笔。好了,你说吧 //主机发送Ready信号

小道士:188-666-66666,念完了 //返回有效数据,以及响应信号

张三丰:好的。

在武的通话记录中,张三丰是机,小道士是从机。通信过程同样是由主机发起,向从机请求数据。主机准备好之后发送Ready信号,接下来机开始发送数据。从机在数据送完成后给出响应信号表明本次传输结束

对比上述两个通话记录可以发现,少林寺的通话一次机向从机写数据的过程,而武当山的通话是主机向从机读数据的过程。在通信过程中,从之间会进行协调,接收准备好之后,才能开始数据传输,这种机制我们称之为握手”。

打电话的时候,通话双方能够理解彼此的语言,进而从中筛选有效信息。而在数字电路中,通信双方就没有那么智能了,设备和从设备需要按照约定好的数据传输方式发送和接收数据。AXI协议就是描述了主设备和从设备之间的数据传输方式,该协议设备和从设备之间通过握手信号建立连接

AXI协议是一种高性能、高带宽、低延迟的片内总线,具有如下特点
1总线的地址/控制数据通道是分离

2支持对齐的数据传输;

3、支持突发传输,突发传输过程只需要地址;

4、具有分离的读/数据通道;

5支持显著传输访问和乱序访问;

6更加容易进行时序收敛

数字电路中只能传输进制数0和1,因此可能需要一组信号才能高效地传输信息,组信号就组成接口。AXI4协议支持以下三种类型的接口:

  1. AXI4:高性能存储映射接口。
  2. AXI4-Lite:简化AXI4接口用于较少数据量的存储映射通信
  3. AXI4-Stream用于速数据流传输,非存储映射接口。

在这里我们首先解释一下存储映射(Meamory Map)这一概念。如果一协议是存储映射的,那么机所发出的会话(论读或写)会标明一个地址这个地址对应系统存储空间中的一个表明针对该存储空间读写操作

AXI4协议支持突发传输,主要用于处理器访问存储器等需要指定地址的高速数据传输场景AXI-Lite为外设提供单个数据传输,主要用于访问一些速外设的寄存器。而AXI-Stream接口则像FIFO一样,数据传输时不需要地址,在主从设备之间直接连续读写数据,主要用于视频、高速AD、PCIe、DMA接口等需要高速数据传输的场合。

我们重点介绍AXI4接口它由五个独立的通道构成

  1. 读地址
  2. 读数据
  3. 写地
  4. 写数据
  5. 写响应

下面是使用读地址和读数据通道实现读传输过程的示意图:

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第二十章 AXI4接口之DDR读写实验​_IP


20.1.1 传输过程示意图

20.1.1可以看到,一个读传输过程中,机首先读地址通道地址和控制信号然后从机读数据通道返回读出的数据。另外我们需要注意的是,这是一次突发读操作,主机给出一个地址,从该地址连续突发读出个数据

传输过程20.1.2示,用到了写地址、写数据和写响应三个通道。机在写地址通道地址和控制信号,然后在写数据通道连续突发写个数据。从机在接收数据之后,在写响应通道响应信号。

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第二十章 AXI4接口之DDR读写实验​_数据_02


20.1.2 写传输过程示意图

AXI总线中的每个通道都包含了一组信息信号,还有一个VALID和一个READY信号。VALID信号由(source)产生,表示当前地址或者数据线上的信息是有效的;而READY信号由目的destination)产生,则表示已经准备好接收地址、数据以及控制信息。VALID和READY信号提供了AXI总线中的握手机制,如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第二十章 AXI4接口之DDR读写实验​_自定义_03


20.1.3 VALID和READY握手机制

20.1.3ACLK为时钟信号,在AXI协议中,所有的输入信号都是在ACLK的上升沿采样,所有的输出信号必须在ACLK的上升沿之后才能改变。在T1之后端将VALID拉高,表明INFORMATION信号线上传输的是有效、数据或者控制信息。目的端在T2之后将READY拉高,表明它已经准备好接收数据,此时源端必须保持INFORMATION数据稳定到T3时刻进行数据传输。

需要注意的是,源不允许等目的端的READY信号拉高之后,才将VALID信号置为有效状态而且旦VALID拉高,源端必须保持其处于有效状态,成功握手(在时钟上升沿检测到VALID和READY时为有效状态)。

AXI协议五个通道都有各自VALID/READY握手信号,每个通道握手信号对的名称如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第二十章 AXI4接口之DDR读写实验​_自定义_04


20.1.4通道握手信号名

这里,我们已经简单介绍了AXI4协议的读写过程,以及握手协议。关于如何实现AXI4通信协议,以及如何在设计中使用该协议进行通信,我们将在硬件设计部分进行讲解。

实验任务

本章的实验任务是通过自定义一个AXI4接口IP核通过AXI_HP接口对PS端DDR4进行读写测试。

硬件设计

根据实验任务我们可以画出本次实验的系统框图,如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第二十章 AXI4接口之DDR读写实验​_自定义_05


20.3.1 系统框图

20.3.1中,DDR Test自定义的IP核,具有AXI4 Master端口,该端口通过AXI Smartconnect模块,最终连接到PS端Slave AXI_HP端口。输入的按键控制DDR Test模块对PS的DDR4进行读写测试,并在读写测试结束后,通过两个PL LED灯分别指示读写完成和读写错误。需要说明的是,DDR Test模块通过输入信号的上升沿作为对DDR4读写测试的触发信号,需要对输入的按键信号进行消抖,否则会导致读写错误。

首先创建Vivado工程,程名为“axi4_ddr_rw”,然后创建Block Design设计design_1.bd添加Zynq UltraScale+ MPSOC模块。接下来按照《“Hello World”实验》步骤2-7、2-8分别配置PSUART和DDR控制器。需要特别注意的是,在《“Hello World”实验》的步骤2-10,移除了PS中PL端交互的接口信号,在我们本次实验中要保留时钟“PL Fabric Clocks”和复位“Fabric Reset Enable”信号

由于本次实验用PS端的HP接口此在Zynq UltraScale+ MPSOC模块的配置界面左侧点击“PS-PL Configuration”标签,然后依次展开右侧界面中PS-PL Interfaces-> Slave Interface->AXI HP,勾选“AXI如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第二十章 AXI4接口之DDR读写实验​_数据_06


20.3.2 PS-PL接口配置

最后点击右下角的“OK”,本次实验Zynq UltraScale+ MPSOC模块就配置完成了

Zynq UltraScale+ MPSOC模块配置完成接口下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第二十章 AXI4接口之DDR读写实验​_自定义_07


20.3.3 Zynq UltraScale+ MPSOC模块接口

20.3.3中,S_AXI_HP0_FPD是PS端的AXI高性能接口,是一个从接口,连接到PS内的存储器互联,用于PL访问PS内的存储设备,包括OCM和DDR。

在本次实验PS内的数据通路如20.3.4。我们在PL内自定义的DDR Test IP作为主设备,通过PS Slave AXI_HP0接口与DDR控制器进行通信,最终DDR4存储器进行读写操作。

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第二十章 AXI4接口之DDR读写实验​_数据_08


20.3.4 PS数据通路

下来我们要在Block Design添加PL端的自定义IP核。

添加该IP之前,我们需要先自定义一个带有AXI4 Master端口IP核,并将其添加到的IP库中。我《自定义IP核-呼吸灯实验》中介绍了如何定义一个带有AXI-Lite Slave接口IP核,在本次实验中定义IP的方法与之相同只是这次们要选择AXI4 Master接口。

在菜单栏中点击“Tools”,然后在下拉列表中选择“Create and Package New IP”,如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第二十章 AXI4接口之DDR读写实验​_自定义_09


20.3.5 创建IP

在弹出的对话框中直接点击“Next”,如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第二十章 AXI4接口之DDR读写实验​_数据_10


20.3.6 创建和封装IP

在下图所示的界面中选择“Create a new AXI4 peripheral”,点击“Next”:

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第二十章 AXI4接口之DDR读写实验​_数据_11


接下来设置IP核的名称为“axi4_rw_test”,并将IP的路径修改为当前工程路径下的“ip_repo”文件夹,最后点击“Next”,如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第二十章 AXI4接口之DDR读写实验​_自定义_12


20.3.7 设置IP名称和路径

在“Add Interfaces”界面中修改接口名称为“M_AXI”,选择接口类型为“Full”,接口模式为“Master”,数据位宽为“32”。如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第二十章 AXI4接口之DDR读写实验​_数据_13


20.3.8 自定义IP核接口配置

20.3.8中对IP核接口的配置与《自定义IP核——呼吸灯实验》不同,在这里我们新建的IP核作为主机(Master),除此之外我们使用的接口类型变成了AXI-Full,而不再是AXI-Lite

设置完成后点击上图中右下角的“Next”。

接下来在20.3.9选择“Edit IP”,最后点击“Finish”,如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第二十章 AXI4接口之DDR读写实验​_自定义_14


20.3.9 创建外设

在上图中点击“Finish”后自动打开一个新的Vivado,工程名为“edit_ axi4_rw_test_v1_0”,如20.3.10所示。我们可以在这个工程中对创建的IP核——AXI4_RW_TEST进行编辑

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第二十章 AXI4接口之DDR读写实验​_数据_15


20.3.10 Edit IP

AXI4接口共有五个独立通道,每个通道又有少则几个多则十几个信号,如果让我们自己实现这一个接口还是比较复杂的。不过大家不用担心,们在20.3.8创建AXI4接口IP时Vivado提供IP封装工已经自动我们实现了这样一个接口并提供了个示例程序。

20.3.10箭头所指示的文件实现AXI4协议下的读写测试模块我们甚至都不用对代码作任何修改,即可实现对DDR的读写测试功能。虽然该模块的代码上去比较长(900多),但是多是一些注释非常详尽。大家可以通过阅读代码及注释,来学习AXI4协议主机的实现方式。

这里我们只出部分代码:

735  //implement master command interface state machine  ​
736 ​
737 always @ ( posedge M_AXI_ACLK) ​
738 begin ​
739 if (M_AXI_ARESETN == 1'b0 ) ​
740 begin ​
741 // reset condition ​
742 // All the signals are assigned default values under reset condition ​
743 mst_exec_state <= IDLE; ​
744 start_single_burst_write <= 1'b0; ​
745 start_single_burst_read <= 1'b0; ​
746 compare_done <= 1'b0; ​
747 ERROR <= 1'b0; ​
748 end ​
749 else ​
750 begin ​
751 ​
752 // state transition ​
753 case (mst_exec_state) ​
754 ​
755 IDLE: ​
756 // This state is responsible to wait for user defined C_M_START_COUNT ​
757 // number of clock cycles. ​
758 if ( init_txn_pulse == 1'b1) ​
759 begin ​
760 mst_exec_state <= INIT_WRITE; ​
761 ERROR <= 1'b0;​
762 compare_done <= 1'b0;​
763 end ​
764 else ​
765 begin ​
766 mst_exec_state <= IDLE; ​
767 end ​
768 ​
769 INIT_WRITE: ​
770 // This state is responsible to issue start_single_write pulse to ​
771 // initiate a write transaction. Write transactions will be ​
772 // issued until burst_write_active signal is asserted. ​
773 // write controller ​
774 if (writes_done) ​
775 begin ​
776 mst_exec_state <= INIT_READ; ​
777 end ​
778 else ​
779 begin ​
780 mst_exec_state <= INIT_WRITE; ​
781 ​
782 if (~axi_awvalid && ~start_single_burst_write && ~burst_write_active) ​
783 begin ​
784 start_single_burst_write <= 1'b1; ​
785 end ​
786 else ​
787 begin ​
788 start_single_burst_write <= 1'b0; //Negate to generate a pulse ​
789 end ​
790 end ​
791 ​
792 INIT_READ: ​
793 // This state is responsible to issue start_single_read pulse to ​
794 // initiate a read transaction. Read transactions will be ​
795 // issued until burst_read_active signal is asserted. ​
796 // read controller ​
797 if (reads_done) ​
798 begin ​
799 mst_exec_state <= INIT_COMPARE; ​
800 end ​
801 else ​
802 begin ​
803 mst_exec_state <= INIT_READ; ​
804 ​
805 if (~axi_arvalid && ~burst_read_active && ~start_single_burst_read) ​
806 begin ​
807 start_single_burst_read <= 1'b1; ​
808 end ​
809 else ​
810 begin ​
811 start_single_burst_read <= 1'b0; //Negate to generate a pulse ​
812 end ​
813 end ​
814 ​
815 INIT_COMPARE: ​
816 // This state is responsible to issue the state of comparison ​
817 // of written data with the read data. If no error flags are set, ​
818 // compare_done signal will be asseted to indicate success. ​
819 //if (~error_reg) ​
820 begin ​
821 ERROR <= error_reg;​
822 mst_exec_state <= IDLE; ​
823 compare_done <= 1'b1; ​
824 end ​
825 default : ​
826 begin ​
827 mst_exec_state <= IDLE; ​
828 end ​
829 endcase ​
830 end ​
831 end //MASTER_EXECUTION_PROC

面的代码实现了一个状态机,状态转换图如下所示

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第二十章 AXI4接口之DDR读写实验​_数据_16


20.3.11 状态转换图

系统复位后,状态机处于初始状态,在该状态下等待外部输入的启动传输脉冲init_txn_pulse。一检测到init_txn_pulse高电平,状态机跳转到INIT_WRITE状态

INIT_WRITE状态下,状态高start_single_burst_write信号,来不断启动AXI4 Master接口对Slave端大小4KB的存储空间进行突发写操作。写操作完成,write_done信号会拉高,状机进入INIT_READ状态。

INIT_READ状态下,状态机拉高start_single_burst_read信号,不断地启动AXI4 Master接口对Slave同一存储空间进行突发读操作同时读出数据数据进行对比。读操作完成,read_done信号拉高,状态进入INIT_COMPARE状态

在INIT_COMPARE状态下判断AXI4接口在读写过程否发生错误,将错误状态赋值给ERROR信号然后compare_done信号拉高,表示一次读写测试完成。最后跳转IDLE状态,等待下一次读写操作的启动信号。

我们在查看了20.3.10中箭头所指示的IP核源码后,不需要再对IP作任何修改,直接关闭名为edit_AXI4_RW_TEST_v1_0的工程。最终我创建IP将通过AXI4 Master端口Slave端指定的4K存储空间中连续写入1024个数据,写入数值从1累加1024,每个数据占32bit。

IP核创建完成后,我们在工程目录下的ip_repo文件夹中可以找到IP相关的文件,如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第二十章 AXI4接口之DDR读写实验​_自定义_17


20.3.12 IP核相关的文件

需要注意的是,在20.3.12中我们只需要保留红色方框中的文件夹即可,其余文件及文件夹是用于对IP进行编辑的工程文件,我们可以直接删除。

回到axi4_ddr_rw工程界面,在左侧“Flow Navigator”一栏点击“IP Catalog”,然后在右侧的IP目录中可以看到我们前面所创建的IP核——AXI4_RW_TEST,该IP已经自动添加到了当前工程的IP库中。

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第二十章 AXI4接口之DDR读写实验​_数据_18


20.3.13 IP目录

接下来在Diagram窗口中给设计添加自定义的IPAXI4_RW_TEST,添加完成后如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第二十章 AXI4接口之DDR读写实验​_IP_19


20.3.14 添加AXI4_RW_TEST IP

20.3.14中,M_AXI是AXI-Full类型的主机接口,我们将通过这个接口对PS端的DDR4进行读写操作。AXI4_RW_TEST IP核在检测到m_axi_init_axi_txn端口的上升沿后会启动读写过程,并将读出的数据与写入的数据作比较,比较完成后m_axi_txn_done输出高电平。另外,在比较完成后,m_axi_error信号会指示整个过程是否出错。如果在读写过程中出错,或者在比较的过程中发现读出的数据与写入的数据不一致,那么m_axi_error将会拉高。

添加完自定义IP核之后,双击IP核对其进行配置,如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第二十章 AXI4接口之DDR读写实验​_数据_20


20.3.15 配置AXI4_RW_TEST IP

20.3.15,我们将变量C M AXI TARGET SLAVE BASE ADDR的修改0x1000_0000,位于DDR4存储器的地址空间,是AXI4_RW_TEST IP核进行读写操作的起始地址我们该地址之前的存储空间预留下来,用于运行PS中软件程序

下来,我们还要添加Utility Vector Logic IP核。然后将其配置成非门,位宽1,作为反向器使用,如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第二十章 AXI4接口之DDR读写实验​_自定义_21


20.3.16 Utility Vector Logic IP核设置

因为我们需要使用PL端的按键来作为AXI4_RW_TEST IP核启动信号MPSOC开发板上的按键在按下的时候为低电平因此我们通过添加一个反向器,将其修改为按下时输出高电平。

接下来为按键添加消抖模块,用于消除按键的抖动。添加的方法是先将《MPSOC之FPGA开发指南》中“按键控制蜂鸣器”里的按键消抖模块(key_debounce.v)添加至工程,然后再添加至框图设计中即可。下面开始具体操作,我们在工程目录.\axi4_ddr_rw\axi4_ddr_rw.srcs\sources_1下创建一个文件夹new,将key_debounce.v拷贝至new文件夹下,如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第二十章 AXI4接口之DDR读写实验​_数据_22


20.3.17 key_debounce路径

接下来将key_debounce.v模块添加至工程中,右击Design Sources下的design_1(design_1.bd),选择“Add Sources..”,如下图所示。

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第二十章 AXI4接口之DDR读写实验​_IP_23


20.3.18 添加源文件

在弹出的页面中选择第二个“Add or create design sources”,点击“NEXT”。

然后点击页面中的“Add Files”,在弹出的页面中选择“key_debounce.v”,如下图所示。

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第二十章 AXI4接口之DDR读写实验​_自定义_24


20.3.19 添加“key_debounce.v

最后点击“Finish”完成代码的添加,如下图所示。

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第二十章 AXI4接口之DDR读写实验​_自定义_25


20.3.20 点击“Finish”

此时在Design Sources界面下,可以看到刚刚添加的文件,如下图所示。

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第二十章 AXI4接口之DDR读写实验​_数据_26


20.3.21 添加完成界面

接下来在Diagram界面空白处右击,选择“Add Module”,如下图所示。

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第二十章 AXI4接口之DDR读写实验​_自定义_27


20.3.22 点击“Add Module”

此时会弹出工程中添加的.v文件,将key_debounce.v添加进来,如下图所示。

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第二十章 AXI4接口之DDR读写实验​_自定义_28


20.3.23 添加“key_debounce.v”至BD

需要说明的是,如果上图的界面中,没有出现按键消抖模块,可能是软件界面还没有更新刚刚添加的设计文件,可以稍作等待后再添加,添加完成后如下图所示。

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第二十章 AXI4接口之DDR读写实验​_自定义_29


20.3.24 消抖模块成功添加至BD界面中

IP核添加完成后使用具的自动连接功能,对设计进行连线,连线后如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第二十章 AXI4接口之DDR读写实验​_IP_30


20.3.25 自动连接

以上是使用Vivado软件的自动连线,接下来还需要手动进行消抖模块、反向器、AXI4_RW_TEST IP核之间的连接。连接完成后,在Diagram窗口空白处右击,然后选择“Regenerate Layout”对设计进行重新布局,局后的界面如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第二十章 AXI4接口之DDR读写实验​_自定义_31


20.3.26 重新布局后的设计界面

上图中可以看到,在执行了自动连接之后,工具自动添加了两个IP核,分别是AXI智能互联(AXI Smartconnect)和处理器系统复位(Processor System Reseet)。接下来需要将消抖模块key端口引出,用于连接开发板PL端按键,并重命名为key_int,命名方法参考AXI GPIO按键LED实验;还需要将AXI4读写测试模块的m_axi_txn_done和m_axi_error两个端口引出,用于连接PL端LED灯,并分别重命名为compare_done和error_flag,如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第二十章 AXI4接口之DDR读写实验​_数据_32


20.3.27 引出管脚

20.3.27中橙色的连线标注出了本设计中AXI4总线的连接,其中AXI4_RW_TEST IP核的M_AXI作为主机接口,Zynq UltraScale+ MPSOC的S_AXI_HP0_FPD为从机接口,中间经过了AXI SmartconnectAXI Smartconnect的功能与AXI Interconnect IP核类似,都是用于将AXI存储器映射的主器件连接到存储器映射的从器件。

这里我们的Block Design设计完成了,在Diagram窗口空白处右击,然后选择Validate Design”验证设计。验证完成后弹出对框提示Validation Successful”表明设计无误点击“OK”确认。最后按快捷键Ctrl + S”保存设计

下来在Source窗口中右键点击Block Design设计文件“design_1.bd”,然后依次执行“Generate Output Products”和“Create HDL Wrapper”。

左侧Flow Navigator导航栏中找到RTL ANALYSIS,点击该选项中的“Open Elaborated Design”,在弹出的窗口中点击“OK”。或者在菜单栏中点击 Layout,在下拉列表中选择I/O Planning以打开I/O Ports窗口。我们将在 I/O Ports 窗口中对key_init等接口进行管脚分配,如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第二十章 AXI4接口之DDR读写实验​_数据_33


20.3.28 管脚分配

在图20.3.28中,我们将key_init分配到了AD11引脚上该引脚最终与MPSOC开发板上的按键PL_KEY0相连接;compare_done和error_flag分别连接到开发板上的LED:PL_LED0和PL_LED1。管脚分配完成后快捷键Ctrl+S保存管脚约束,并在弹出的保存约束窗口中输入文件名“axi4_ddr_rw”。

最后在左侧Flow Navigator导航栏中找到PROGRAM AND DEBUG,点击该选项中的“Generate Bitstream”,对设计进行综合、实现、并生成Bitstream文件。

在生成Bitstream之后菜单栏中选择 File > Export > Export hardware导出硬件,并在弹出的对话框中,勾选“Include bitstream”。将导出的“design_1_wrapper.xsa”文件放到vitis文件夹,然后在菜单栏选择File > Launch Vitis,启动VITIS软件。

软件设计

VITIS软件建一个空的应用工程,应用工程名为“axi4_ddr_rw”。然后为应用工程新建一源文件“main.c”,我们在新建的main.c文件中输入本次实验的代码

1 #include "stdio.h"​
2 #include "xil_cache.h"​
3 #include "xil_printf.h"​
4 #include "xil_io.h"​
5 ​
6 int main()​
7 {​
8 int i;​
9 char c;​
10 ​
11 Xil_DCacheDisable();​
12 printf("AXI4 PL DDR TEST!\n\r");​
13 ​
14 while(1)​
15 {​
16 scanf("%c",&c);​
17 if(c == 'c'){​
18 printf("start\r\n");​
19 for(i=0;i<4096;i=i+4)​
20 {​
21 printf("%d is %d\n",i,(int)(Xil_In32(0x10000000+i)));​
22 }​
23 }​
24 }​
25 return 0;​
26 }

可以看出,我们的软件程序特别简单。在代码的第14行至24行,通过一个while(1)循环,连续判断用户输入的字符输入字符c”时,程序通过一个for循环开始从地址0x1000_0000DDR存储器中的数据,读取的存储空间大小为4KB。需要注意的是,变量i每次累加4,因为我们调用了函数Xil_In32( )读取内存数据,每次32bit。而内存地址是以字节(1字节==8bit为单位的,那么操作完成后地址应该累加4

以看出,我们在软件中读取的内存地址与硬件设计过程中DDR Test IP核入的地址一致的。我软件读出的数据通过串口打印出来,与DDR Test写入的数据进行对比,即可验证我们通过AXI4接口DDR进行的读写操作是否成功。

另外,在代码的第11行,我们通过调用函数Xil_DCacheDisable( )来关闭数据缓存(Data Cache),以避免从缓存中读取数据。这是因为在对同一地址进行读操作时,读出的有可能是Data Cache中缓存的数据,而不是DDR中真正的数据。

下载验证

首先我将下载器与开发板上的JTAG接口连接,下载器另外一端与电脑连接然后使用USB连接线将USB_UART(开发板PS PORT)接口与电脑连接,用于口通信。最后连接开发板的电源,给开发板上电。

打开Vitis Terminal终端,设置连接串口。然后下载本次实验程序下载完成后,在下方的Vitis Terminal中可以看到应用程序打印的信息AXI4 PL DDR TEST!”。

然后在Vitis Terminal窗口中输入字符“c”,然后按回车键发送。程序会打印从DDR中的数据,如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第二十章 AXI4接口之DDR读写实验​_自定义_34


《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第二十章 AXI4接口之DDR读写实验​_IP_35


20.5.1 第一次从DDR4中读出的数据

20.5.1示,串口打印出了DDR存储空间中从地址0x1000_0000开始的1024个数据,每个数据占4个字节。从图中可以看出,开发板上电后,在没对该地址空间进行写操作之前,DDR中的数据是随机的。

们按下开发板上的按键PL_KEY1然后释放,该动作会启动AXI4_RW_TEST IP核对DDR的读写操作。然后开发板上的PL_LED1会点亮,表示读写操作完成。如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第二十章 AXI4接口之DDR读写实验​_自定义_36


20.5.2 MPSOC开发板实物图

20.5.2中,如果旁边的PL_LED2也点亮了,这表明在对DDR进行读写操作过程中出现了错误。但是这个错误指示灯点亮的原因并不唯一,通过分析AXI4_RW_TEST IP核的源码可以看出,在AXI4通信过程中写响应出错、读响应出错、以及读出与写入的数据不一致均会导致错误指示灯点亮。

笔者最早在实现本次实验功能的时候,旁边的PL_LED2偶尔也会亮,是由于没有对按键进行消抖处理所致,添加按键消抖模块后,没有再出现读写错误的情况。

在Vitis Terminal窗口中重新输入字符“c”并发送,程序会再次打印从DDR中的数据,如下图所示:

《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第二十章 AXI4接口之DDR读写实验​_IP_37


《DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南》第二十章 AXI4接口之DDR读写实验​_数据_38


20.5.3 第二次从DDR4中读出的数据

可以看出,PS端软件从DDR中指定的4KB存储空间中读出的数据依次为1到1024,AXI4_RW_TEST IP核写入的数据一致说明次实验在MPSOC开下载验证成功。


【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月13日 0

暂无评论

推荐阅读
95kVyaJuybju