------Aurora协议是Xilinx公司提供的一个开放免费的链路层协议,可以用来进行点到点的串行数据传输,具有实现高性能数据传输系统的高效率、简单易用的特点。此协议分为两种编码方式,分别是Aurora 8b10b和Aurora 64b66b,两者的设计方法差不多,本次主要介绍8b10b协议的应用。本次将从IP配置到例化工程再进行仿真验证最后讲解实际应用技巧来详细介绍此IP。
------一般验证IP设计的正确性,可以通过看channel up的状态即可,如果高有效且长时间稳定,则表示链路建立成功,可以进行数据通信。再设计一个产生顺序数的模块和一个校验数据的模块用以验证数据收发的正确性。就可以了,下面就是详细设计的步骤。
本次选择的FPGA芯片是xc7vx690tffg1930-2,IP应用方法如下:
1. 首先是IP核中Core options页面设置:
------Lane width: 一般我们选择2 Bytes(1 Byte = 8bit),如果是4 Bytes那位宽更高,频率更小,同样可以有一样的传输速率。
Lane Rate: 3.125 Gbps线速率越高,那IP使用的用户时钟就越高,这对用户逻辑的时序要求更高;
------GT Refclk:125 MHz(硬件设计决定的,可以看看原理图);
------INIT clk:50 MHz(默认值就可以,这个时钟可以通过系统时钟通过PLL锁出来);
------DRP clk:50 Mhz(默认值就可以,,这个时钟可以通过系统时钟通过PLL锁出来);
------Dataflow Mode:Duplex(全双工,双向独立发送接收);
------Interface:Streaming(发送端不受接收端影响,有数就发)。
其他选项保持默认即可。。
------2. 在GT Selections页面中,设置Lanes数量,这个例程我们选择的是4X的,所以这里选择4 Lanes,在GT Refclk1中会自动选择GTHQ3,再在GTHQ3模块中任意选出1,2,3,4路就可以了。GTHQ应该根据原理图来选择,如果随便选,那可以disable掉IP的XDC文件,自己再约束bank。
-
在Shared Logic页面中,选择include Shared Logic in example design,这个可以将服务于IP的时钟模块和复位模块独立于IP核,方便我们更改里面的代码,或移植等。
-
IP设置好后直接生成,然后右键IP核生成IP的Example design。
-
打开Example design的顶层模块,原有的端口在实际应用中,除了系统时钟复位和接口时钟与数据接口外,都可以去掉,输出型端口改为wire型,输入的时钟可以用板上晶振过来的时钟用PLL锁出来,复位可以直接用板上硬复位。但这里为了方便应用Example design自带的testbench,所以端口没有修改,文章后半段会简述去掉某些端口的情形。
-
接着可以去掉除了IP例化的接口以外的部分,这些部分是为了测试接口用的,包括一些造数模块等,都去掉只要剩下如下图所示即可。除IP接口以外剩下的三个参数是IP接口复位和GT底层复位,还有就是IP接口回环控制位。
-
为了验证接口的正确性,我们可以设计一个线性的造数模块,代码如下所示:
module dat_gen(
clk,
rst,
tx_dat,
tx_dat_v,
tx_dat_start
);
input clk;
input rst;
output reg [63:0] tx_dat;
output reg tx_dat_v;
input tx_dat_start;
reg [15:0] tx_dat_cnt;
always@(posedge clk) begin
if(rst == 1'b1) begin
tx_dat <= 64'b0;
tx_dat_v <= 1'b0;
tx_dat_cnt <= 16'b0;
end
else begin
if(tx_dat_start == 1'b1) begin
tx_dat <= {(tx_dat_cnt + 16'h3),(tx_dat_cnt + 16'h2),(tx_dat_cnt + 16'h1),tx_dat_cnt};
tx_dat_v <= 1'b1;
tx_dat_cnt <= tx_dat_cnt + 16'h1;
end
else begin
tx_dat <= tx_dat;
tx_dat_v <= 1'b0;
tx_dat_cnt <= tx_dat_cnt;
end
end
end
endmodule
- 在造数模块产生的数据进入aurora接口之前我们应该用fifo做一个缓存,这样可以保证发送的数据不丢失、不混乱,如下所示(FIFO用法详解:https://blog.csdn.net/yt15751004322/article/details/107427940?spm=1001.2014.3001.5501)
dat_gen u_dat_gen(
.clk ( user_clk_i ),
.rst ( system_reset_i ),
.tx_dat ( tx_data_fifo ),
.tx_dat_v ( tx_tvalid_fifo ),
.tx_dat_start ( channel_up_i && !fifo_prog_full )//接口建立连接且fifo没满,可以产生数据
);
dat_check u_dat_check(
.clk ( user_clk_i ),
.rst ( system_reset_i ),
.rx_data ( rx_data_i ),
.rx_data_v ( rx_tvalid_i ),
.dat_che ( dat_che )
);
fifo_64w64r_256d u_fifo_64w64r_256d (
.clk ( user_clk_i ), // input wire clk
.srst ( system_reset_i ), // input wire srst
.din ( tx_data_fifo ), // input wire [63 : 0] din
.wr_en ( tx_tvalid_fifo ), // input wire wr_en
.rd_en ( tx_tready_i && !empty ), // input wire rd_en
.dout ( tx_data_i ), // output wire [63 : 0] dout
.full ( fifo_prog_full ), // output wire full
.empty ( empty ), // output wire empty
.valid ( tx_tvalid_i ) // output wire valid
);
- 为了验证接口接收到的数据与发送端造的数据的一致性,我们可以设计一个检验模块,用来查看收发数据的正确性,代码如下:
module dat_check(
clk,
rst,
rx_data,
rx_data_v,
dat_che
);
input clk;
input rst;
input [63:0] rx_data;
input rx_data_v;
output reg dat_che;
reg [15:0] dat_che_cnt;
always@(posedge clk) begin
if(rst == 1'b1) begin
dat_che <= 1'b0;
dat_che_cnt <= 16'b0;
end
else begin
if(rx_data_v == 1'b1) begin
dat_che_cnt <= dat_che_cnt + 16'b1;
if(rx_data != {(dat_che_cnt + 16'h3),(dat_che_cnt + 16'h2),(dat_che_cnt + 16'h1),dat_che_cnt} ) begin
dat_che <= 1'b1;
end
else begin
dat_che <= dat_che;
end
end
else begin
dat_che <= dat_che;
dat_che_cnt <= dat_che_cnt;
end
end
end
endmodule
- 接下来进行仿真测试。打开工程自带的testbench,进行接口测试。
打开testbench后可以看到主要例化了两个工程顶层,分为模块1和模块2,用这两个模块链路连接测试并进行数据的收发测试。
还给两个模块造了相应的时钟和复位。
并给两个模块的数据接口建立连接。
这个testbench可以直接使用,不需要任何更改,直接仿真。
- 下面是仿真结果图,可以看到错误检测结果一直没有拉高,说明发送端和接收端的数据是一致的,而且从接收端的数据看,数据是线性增加的,和造数模块的设计吻合,所以接口连接的线序也没问题。(注意:channel up为高需要等待一定的时间,这个时间和所选的芯片和电脑性能都有关系,主要是选择的芯片类型,我选择的这款芯片,在性能一般的笔记本上跑了30分钟才拉高的,所以需要一定的耐心等待,别以为自己逻辑有问题了)
12. 实际应用中可以将其他的顶层接口去掉,如下所示,只要剩下系统时钟输入和系统复位输入端口、GTX时钟和数据端口就可以了。
13. 接口需要的时钟我们可以用系统时钟通过PLL锁出来,系统复位可以用某个时钟域的同步复位,或者直接用系统复位,需要注意的是系统复位是低电平还是高电平复位。
------时钟修改部分:因为PLL锁出来的时钟已经经过BUFG,所以在需要赋时钟的地方将BUFG模块先去掉,然后直接赋值即可。
------复位修改部分:直接将系统复位连到接口复位就可以了。
------到此就算可以了,AURORA接口虽然不难,但是在实际应用中可能会遇到channel up起不来,数据发送线序不对、接收端丢数等等问题,一般情况下考虑以下几点就可以解决以上问题:
a. channel up起不来可能是硬件链路问题,有可能是硬件问题,或者逻辑约束问题,检查一下;如果硬件和约束都没啥问题,那就尝试复位端口,如果复位能起来,就可以利用channel up为低电平时造一个定时复位模块,只要channel up起不来就定时复位接口,知道链接建立起来为止;
b. 数据线序不对,可能是约束的链路顺序和硬件连接的顺序不对,可以更改了再试试;
c. 接收端丢数,先用上面提到的线性数造数模块来造数,再用检验模块来检验错误,看有没有丢数,如果丢数了,用ILA抓一下发送端的数据是否正确,如果发送端不正确,那就分析发送端的所有涉及的模块,尤其是FIFO设置的对不对;接收端一般比较被动,有数据就接收,一般IP底层接收到的数据不会有问题,可能应用层自己使用接收到的数据时,逻辑哪里出现了问题 ,最后可以降带宽试试。
最后。。。码字不易,是学习记录也是知识经验的分享,如果帮到你,帮忙点个赞。有问题的欢迎留言。。。