本篇文章给大家带来AXI-Full的兄弟协议,AXI-stream。该协议在AMBA4中推出,AMBA4中总共有以下三种跟AXI相关的协议:
- AXI-FULL:或者直接简称AXI,我们之前的文章讲的都是这种协议;
- AXI-Lite:简化版本的AXI协议,少了很多特性,如果对之前的AXI文章都理解了话,该协议非常简单,不用特地去学,看一下接口信号就知道是怎么回事了;
- AXI-Stream:用于高速数据流传输,非存储映射接口;
在这里我们首先解释一下存储映射 (Memory Map)这 一概念。如果一个协议是存储映射的,那么主机所发出的会话(无论读或写)就会标明一个地址。这个地址对应系统存储空间中的一个地址,标明是针对该存储空间的读写操作。这个非常好理解,前面我们讲解AXI协议的时候,都是针对某个地址进行读写,那它就是存储映射的。
1、AXI-Stream典型应用场景
而本篇文章所要讲解的AXI-Stream接口,其数据传输时不需要地址,在主从设备之间直接连续读写数据,主要用于如高速视频、高速 AD 、PCIe、DMA接口等需要高速数据传输的场合。我们通常把源端即数据发送的一方称为上游,另一方称为下游。
下图是两个典型的应用实例,本人做过一些信号处理和视频图像处理的模块,模块之间的传输均采用AXI-stream,为什么AXI-stream应用如此广泛呢?那自然是因为有自己独到的设计之处,既简单又能覆盖绝大部分应用场景,下面为大家讲解该协议的细节。
我们看一下一个结合了各种AXI协议的SoC系统,这是一个典型的图像采集处理显示的系统,很多FPGA开发板的教学文档,实际上都会有该项目,这个DataMover可以用VDMA代替,更加适配图像相关的应用场景。
这个系统通过Camera采集视频信号,将RGB之类的RAW格式转换为AXI-stream,然后在各级之间进行处理,模块与模块之间均采用AXI-stream协议,然后通过DataMover这个模块,将Stream流数据搬运到指定的地址空间。再通过另外一个AXI DataMover将该地址空间的数据搬运出来,进行后处理,最后输出HDMI显示。为什么需要写到地址空间再读回来呢?这种情况一般是帧率不匹配,所以需要借助DDR存储数据。
2、AXI-Stream接口信号
接下来我们看一下AXI-Stream的接口信号,如下图所示,AXI-Stream是点对点的接口,包括Master一方和Slave一方。同样的,其也采用握手协议,这里握手成功则代表数据成功传输,相应的可以更新下一组数据。
2.1、AXI-Stream握手机制
其握手也可以分为三种情况:
- TVALID在TREADY之前拉高:这也是最常见的一种情况,后级因为种种原因暂时处理不了新的数据,因此会反压住前级模块,前级必须维持住VALID和INFORMATION不变,直到握手成功才允许更新,当握手成功也就意味着下级模块拿到了前级传的数据。
实际上在很多情况下,是不允许反压的。比如DSP系统,要求实时的源源不断的处理数据,这种情况下一旦反压,新的数又来了,就会丢数。一般这种系统出现这种情况是因为工作异常导致的,会直接报中断处理。
- TREADY在TVALID之前拉高:这种情况后级模块随时可以接收数据,一直在等着前级模块给数,比如前级模块还未开始工作,刚对其进行配置允许其采集数据,便是这样的情况。
- TVALID和TREADY同时拉高:拉高当拍直接握手成功。
同样的,VALID的逻辑生成,一定不能够依赖于READY,否则很有可能会造成死锁。但是反过来READY是可以依赖于VALID的,可以看到VALID拉高READY再拉高,不过现在一般也不这么做了,基本都是完全解耦的。
2.2、AXI-Stream数据流
首先给大家解释几个名词:
- Transfer:一次握手成功就是一次Transfer,代表一笔最小粒度的数据传输发生;
- Packet:一组信息传输成功,所谓的Packet可能包含一个Transfer也有可能是多个Transfers。这个概念类似于之前的一次Burst传输即Transaction;
- Frame:AXI-Stream中最高层次的一组数据,代表了多个Packet。用的很少,一般只在视频图像传输中使用,代表一帧图像,其他时候可以不管;
理解了上述概念以后,我们看AXI-Stream数据流相关的信号。
首先是TDATA,这个没什么好解释的,就是一次transfer传输的数据,一般强制要求为8的整数倍,以和其他信号相对应。
然后是TSTRB,所谓的Strobe就是闸门,其每一个bit和DATA的每一个字节相对应,用来表示DATA的数据是否有效。
然后是TLAST,由于AXI-Stream在传输之前,也不知道你要传输多少笔数据,因此需要TLAST这个信号作为标志,它用来表示一组数据即Packet的最后一笔Transfer,当TLAST拉高,则代表整个的传输结束了。
比较难以理解的是TKEEP信号,其也是说明总线上的数据是不是有效的。每一个bit和DATA的每一个字节相对应,大家可能会疑惑了,这和TSTRB有什么区别呢?我们先来看几个名词解释:
- Data byte:代表这个字节的数据是需要传输且有效的;
- Position byte:代表这个字节的数据是需要传输的,实际上是无效的,只不过需要用来占位置,大家就理解成补0那种操作即可;
- Null byte:完全没用,可以丢弃;
然后我们再看一下,实际上TKEEP和TSTRB是要组合在一起使用的,其共有三种含义:
我们再看两个图加深下理解:
第一个是NULL Byte:可以看到Null Byte啥作用都没有,直接没用上,传完第0Byte,传了个Null Byte,再传了个第1Byte,下游是知道应该怎么处理这个DATA信息的。
第二个是Position Byte:可以看到Position实际上是占据了这个位置的,相当于作为第二Byte来使用,虽然里面的数据是无效的。这种情况一般是传输队形要求固定,但每一组数据的某个Byte可以不看,就用以下的Position Byte。
以下说明一下Position byte具体应用场景:
- Data Mark:比如在视频处理当中,可以使用Position Byte当做一帧的开头;
- Error Detection:每过多少比特插入一个Position Byte用于检测错误。如果不符合规律说明丢数之类的问题;
- Data Group:就比如上图中,一次传4个Byte的数据,但是有一组或者两组数据是无效的,这样就可以用Position Byte。让数据的Group是规律的,同时Slave也可以感知到某个数据是无效的。
我们看下面这样的一个例子,该例子对应于上面的Data Mark。我们有这样的一个图片,总共16个Pixel,一共是4行4列。我们希望发过去,Slave那边知道这是一次传输的开始,因为它那边可能也不知道这是无用数据还是真正要用的数据。
这种情况下我们就可以在起始加入一个Position Byte。这样Slave一看,就知道一帧图开始了。然后正常的收数据,当第五次Transfer的时候(W4),后面3个Byte都是可以丢弃的,即设置为Null Byte。就这样五次Transfer作为一次循环。相比原始图像而言,可能浪费了一个周期,但是某些应用场景下Slave就是需要感知一帧图像的开始,使用这种方式就非常的合适。
最后我们再看一下TID信号,这个信号一般是用来当分组使用。本人之前使用该信号,是因为接收的数据是三路数据,类似于三相电路的机制,所以要分为0、1、2三组,通过TID进行区分,以方便后级的处理。大家也可以根据自己的应用场景,灵活的使用该信号。
TDEST为数据流提供路由信息,比如下面的例子,通过TDEST信号,就可以知道是发到哪个Slave。实际上该信号用的很少很少,因为AXI-stream基本上是点对点的,很少有Interconnect的说法。
TUSER其实跟TID差不多,实际上都是附带一些额外想传输的信息而已,该信号更加的灵活,用户可以附带自己想要传输的额外信息。
本篇文章就给大家讲解这么多,AXI-Stream协议实际上非常简单,但其简单的信号又能够覆盖大部分流数据处理的应用场景,这也是为什么该协议这么流行吧。大家以后如果做视频图像处理、数字信号处理等相关的设计,我也推荐大家使用该协议做外部接口。感兴趣的朋友可以去VIVADO软件看看XADC、FIR、FFT等模块,都可以选择以AXI-Stream作为对外接口,基于调用IP,就可以实现一个简单的信号处理系统。如果大家感兴趣,后面可以写两篇文章讲一下DDS、FIR、FFT等VIVADO IP模块的调用以及设计实例。
下一篇文章给大家带来AXI协议设计的关键问题,如如何仲裁、如何做Outstanding、如何提高性能等。这些内容在中文博客中几乎没有讲解,都是我自己的一些设计经验,欢迎大家关注。
欢迎和我一起学习AMBA总线,完整的专栏在这里: