Xilinx ZYNQ 7000+Vivado2015.2系列(七)软硬件联合Debug观察AXI总线读、写时各信号的时序

前面一节我们学会了创建基于AXI总线的IP,但是对于AXI协议各信号的时序还不太了解。

这个实验就是通过SDK和Vivado联合调试观察AXI总线的信号。

由于我们创建的接口是基于AXI_Lite协议的,所以我们实际观察到是AXI_Lite协议的信号时序。

具体做法是创建一个基于AXI总线的加法器模块,在Vivado里将AXI总线添加到debug信号里,

实际上是用逻辑分析仪探测信号,在SDK端通过debug方式依次写入两个加数,由PL计算出和。

我们读出这个和打印到串口,这样AXI总线的读和写就都能观察到了。

板子使用的是zc702。

AXI是什么

在观察信号之前我们有必要简单了解AXI是个什么:

AXI总线是一种高性能、高带宽、低延迟的片内总线,AXI协议描述了主从设备数据传输的方式。

主设备和从设备通过握手信号建立连接,

握手信号包括:

主机发送的VALID信号,表示数据有效,

从机发送的READY信号,表示从机准备好了接收数据。

当VALID和READY都有效的时候传输开始。

Zynq使用的是AXI协议的4.0版本,由AMBA3.0协议发展而来:

20171210145550108

AXI的三种总线各有各的用途:

AXI4支持突发数据传输,主要用于CPU访问存储等需要高速数据交互的场合,相当于原来的AHB协议;

AXI_Lite一次传输单个数据,主要用于访问一些低速外设,相当于原来的APB;

AXI_Stream数据传输不需要地址,主设备直接连续读写数据,主要用于高速流数据的传输,使用起来类似FIFO。

AXI4总线和AXI4-Lite总线具有相同的组成部分:

(1) 读地址通道, 包含ARVALID, ARADDR, ARREADY信号;
(2) 读数据通道, 包含RVALID, RDATA, RREADY, RRESP信号;
(3) 写地址通道, 包含AWVALID, AWADDR, AWREADY信号;
(4) 写数据通道, 包含WVALID, WDATA, WSTRB, WREADY信号;
(5) 写应答通道, 包含BVALID, BRESP, BREADY信号;
(6) 系统通道, 包含: ACLK, ARESETN信号。

帮助记忆:

读地址信号都是以AR开头(A: address; R: read)
写地址信号都是以AW开头(A: address; W: write)
读数据信号都是以R开头(R: read)
写数据信号都是以W开头(W: write)
应答信号都是以B开头(B: back(answer back))

读时序:

20171210150954606

写时序:

20171210151012590

5个通道都有自己独立的握手机制,同时又相互协作,地址线分离后,读/写可以并行交互数据。

而且AXI支持地址pipeline、错位传输等模式,大大提高了数据通路的利用率。

关于AXI Interconnect模块:

AXI协议可以描述为主/从设备之间的点对点传输,可以有多个主机,也可以有多个从机。

这是进行数据交互时,需要一个管理中心确保信号发到对应的设备。

AXI Interconnect模块就是这样一个管理中心,也叫做AXI互联矩阵。

它类似于一个交换机,保证每个外设独享带宽,完成数据传输。

Xilinx公司为我们提供了AXI Interconnect的IP核。

介绍到此,理论部分已经掌握i一二了,下面就开始实际观察AXI的信号。

创建一个基于AXI_Lite总线的加法器IP

新建Vivado工程,依然,选择这个:

20171210153509201

修改名字和地址,我命名为AXI_Add,

地址最好选择工程路径下新建一个文件夹,这样就会自动把你创建的IP更新到IP库里,其他默认,

最后选择Edit IP,在Vivado给出的代码里添加上我们的加法器功能

注意这些代码就是定义AXI协议的工作方式的,里面有注释,可以去研究一下!

添加用户端口:

这里我们没有要输出的信号

20171210165300017

添加用户逻辑:

待会我们将两个加数写到寄存器0和1中,从寄存器2中读出和

20171210165425026

封装好后回到我们之前建的工程,

然后在工程里添加zynq核,添加刚才创建的IP,

点击自动连接,然后选中AXI总线,

右击选择Make Debug,出现两个绿色的小瓢虫

将总线加入Debug模式下。

如果你没有把刚才新建的IP放在该工程目录下,

先要把IP添加进库里,选择 Project Settings-->IP。

点击绿色的加号,选择到你的用户IP地址 :

20171211093953485

整个系统搭建完成是这样的:

20171210163529005

下面就是例行操作,

自动排版,检查,保存,复位,generate,产生顶层文件。

然后先综合(Synthesis)一下,综合好后,打开Synthesis Design下的Set Up Debug,

将显示为红色的无用信号删除(选中,点击红色的减号),

20171210164357528

设置采样深度为1024,

20171211095738860

其他默认,然后生成比特流文件。

软件端的设计

Lanch到SDK,

新建一个空的applicaton工程,

添加一个c源文件,

我们在xparameters.h文件中找到我们添加的加法器AXI_ADD的寄存器首地址,

待会我们就是要通过地址对寄存器进行读、写:

20171210170303167

这个案例里我们计算16进制下的24+12=36,为了方便SDK端的断点调试,加了while循环,注释我写在后面了:

#include <stdio.h>
#include "xparameters.h"
#include "xil_io.h"
#include "xil_types.h"


#define AXI_ADD_REG0 0  //寄存器0的偏移地址为0
#define AXI_ADD_REG1 4  //寄存器1的偏移地址为4
#define AXI_ADD_REG2 8  //寄存器2的偏移地址为8

int main(){	
	while(1){
	        u8 value = 0;
		Xil_Out32(XPAR_AXI_ADD_V1_0_0_BASEADDR+AXI_ADD_REG0,0x24); //向寄存器0写入第一个加数 
		Xil_Out32(XPAR_AXI_ADD_V1_0_0_BASEADDR+AXI_ADD_REG1,0x12); //向寄存器1写入第二个加数
		value = Xil_In32(XPAR_AXI_ADD_V1_0_0_BASEADDR+AXI_ADD_REG2); //从寄存器3中读出和
		xil_printf("value = %x",value);
	}
	return 0;
}

软硬件联合调试

右键工程 Debug as-->Debug Configrations:

20171210174134143

进入Debug界面后,在AXI总线读、写的地方添加断点:

20171211102638092

打开串口:

20171211104349561

然后回到Vivado界面,连接到Device,就会自动打开调试界面:

20171210174340092

接下来是设置触发位置,添加触发条件:

20171210174906488

我们的采样深度是默认的1024,在500的位置触发,

20171211100708466

触发条件设置成WVALID信号为高时,AWVALID信号为高时:

20171211110216340

右键逻辑分析仪,选中Enable Auto Re-trigger,设置成自动进入下一次触发:

20171211102034806

点击运行触发,点击完之后ila进入等待触发状态:

20171211102237322

在SDK点击运行:

20171211102802267

首先写入24:

20171211111025827

有一点要注意,这里的写地址VALID和READY信号是下一个地址的,

这里就是对应WDATA的4,而对应地址0,

也就是我们观察的数据24地址的VALID和READY信号在前面已经有效过了,

我们设置写数据有效时触发,而地址有效在前面就没有捕捉到了。

然后写入12:

20171211111123555

然后串口打印出36:

20171211111907807

等到第二轮写入的时候,我们看到读数据通道上出现36:

20171211112038407

我们可以换一下触发信号,换成读VALID,读READY拉高时触发:

20171211120439537

就可以看到,读VALID和READY信号都高时,读出36,读地址线上是8:

20171211112533184

这里可以看到读READY信号一直为高,读VALID信号拉高时36读入。

但是由于ILA捕捉的是触发时刻信号,所以它将读有效之前的读数据都显示为36了。

大家要注意,触发设置里,添加的信号默认是AND的,

如果你一开始就把读有效为高,写有效为高都添加到触发列表里。

会观察不到信号,因为这两个信号在本例子;里不会同时出现:

20171211113857481

我们可以添加读VALID为1,写VALID为1,然后选择OR

20171211114044512

SDK那边一步步Debug,先是写入24:

20171211114523355

然后写入12:

20171211115128376

然后读到36:

20171211115253830

这里也是由于RREADY先于RVALID信号拉高,ILA捕捉不到READY是什么高的,就把之前都显示为高。

如果没有按你设置的运行,

可以在SDK重新Debug as或者在Vivado重新连接一下Target,

或者多点几次Run Trigger,

这软件有时候不灵敏,比如说你虽然设置了自动进入下一次触发,但是它不一定就进入,

这时候手动点一下触发,进入等待模式,再点击下一次Debug。

小结

到这里,AXI信号读写时序就全部观察完了,这时候可以再去看一看AXI协议的理论部分,

把封装基于AX总线的IP时生成的例化代码捋一遍,就能更好的理解AXI总线的工作原理了。

提一句,我们目前观察的都是简化版的AXI_Lite协议的时序。

posted @ 2024-03-27 17:52  L707  阅读(180)  评论(0编辑  收藏  举报