从手册上可以得知,Aurora的IP的复位需要关注的信号有reset,gt_reset等,在不同模式下,IP和生成的复位信号是不一样的。
模式 | 信号 |
---|---|
全双工 | reset : 系统复位 gt_reset :收发器复位 |
单工模式 | tx_system_reset :发送端口复位 rx_system_reset :接收端口复位 |
在设计复位的时候,是需要遵守相关的时序才可以的。
在全双工模式的复位下,reset信号必须保持断言6个user_clk的时钟周期,在reset取消断言后的三个时钟周期,channel_up就被置为无效。
gt_reset 必须保持6个init_clk时钟周期的断言,在一段时间后呢,这个user_clk就是停止,因为此时收发器已经被复位了,收发器不会向外提供时钟,从而导致channel_up被置为无效。
在全双工模式下,给FPGA上电时,gt_reset和reset信号都必须保持为高电平,与此同时收发器的参考时钟gt_clk和初始化时钟init_clk都必须保持稳定。这样才能上电成功。
复位操作的具体执行过程可以按照下面的时序图进行:
- 在gt_reset断言之前,reset信号必须稳定保持128个user_clk时钟周期的断言
- gt_reset断言保持一段时间(图中所示为1s)
- 在gt_reset取消断言一段时间后,reset取消断言
单工模式下的复位和全双工模式下的复位类似,具体可以参照数据手册,在这里不做过多介绍。
在ZYNQ7000系列FPGA中,含有一个QUAD的高速收发器,通过配置Aurora 8B10B IP可以使用到具体高速收发器的通道。首先,在IP Catalog中搜索 Aurora,然后双击该IP,进入到配置界面。
core option界面中按照如下配置:
参数(物理层) | 含义 |
---|---|
Lane Width | 表示高速收发器一个Lane传输的数据的位宽,这里选择4表示一个lane传输的数据位宽是32bit 若选择2表示igeLane传输的数据是16bit |
Line Rate | 线速率,是值高速收发器最大的传输速率由于Aurora采用了8B10B的编码,因此实际传输数据 的效率只有最大线速率的4/5以下 |
GT Refclk | 收发器的参考时钟,可以根据原理图上,光口所在收发器来确定其频率 |
INIT clk | 初始化时钟,选定的范围只能在后面标定的范围内,这里设置为50M,这个时钟在初始化阶段会 使用到 |
DRP clk | DRP总线上的时钟 |
参数(链路层) | 含义 |
---|---|
Data flow mode | 工作模式,可以配置为全双工模式,或者单工模式,单工模式下可以值配置为接收或者发送,在本次实验中选择全双工模式 |
Interface | 用户接口类型,可以是数据帧类型:framing也可以是数据流类型:streaming。在本次实验中选则framing |
Flow control | 流控接口,可以在数据传输的过程中插入一些控制字,可以选择UFC(User Flow Control Interface),或者其他类型接口(Native flow control )等。本次实验选择UFC |
Back Channel | 只有在单工模式下才可以选择 |
Scrambler/Descrambler | 添加加扰器或者解扰器,在本次实验中不选择 |
Little Endian Support | 选择该选项,数据将会以小印第安序的方式组成。在本次实验中不选择 |
CRC | 选项该选项,将会在接收数据时,对接收数据进行校验 |
本次实验的整体结构如下图所示,在顶层模块中需要设计如下三个模块,分别是用户数据发送模块,用户数据接收模块,和复位模块。
其中用户数据发送模块,使用AXI-stram接口将用户数据和UFC信号发送给Aurora IP,Aurora IP将这些信号通过高速串行接口发送出去。
用户数据接收模块,使用AXI-Stram接口从Aurora IP接收数据,并且判断接收回来的数据是否正确。
复位模块负责向Auroa 8B10B模块提供复位信号,使得高速收发器链路能够正常链接。
`timescale 1ns / 1ps
module gtp_reset_control(
input wire clk ,
input wire rst ,
input wire channel_link_up ,// 通道链接信号
input wire lane_link_up ,// lane 链接信号
output wire reset ,// 系统复位
output wire gt_reset // 收发器复位
);
//==========================================
//parameter define
//==========================================
parameter IDLE = 3'b001; //上电状态
parameter RESET = 3'b010; //GTP复位状态
parameter DETECT = 3'b100; //检测LINK状态
parameter RESET_MAX = 384 ;
parameter GT_RESET_MAX = 128 ;
//==========================================
//internal signals
//==========================================
reg [2:0] state ;
reg reset_r ;//系统复位信号
reg gt_reset_r ;//收发器复位信号
wire link_flag ;//用于判断当前是否链接
reg [1:0] link_flag_dd ;//link 延时信号
reg [10:0] cnt_rst ;//用于产生复位信号的计数器
wire add_cnt_rst ;
wire end_cnt_rst ;
assign link_flag = channel_link_up & lane_link_up;
assign reset = reset_r;
assign gt_reset = gt_reset_r;
//----------------state machine describe------------------
always @(posedge clk) begin
if (rst==1'b1) begin
state <= IDLE ;
end
else begin
case(state )
IDLE : begin
state <= RESET;
end
RESET : begin
if (end_cnt_rst == 1'b1) begin
state <= DETECT;
end
else begin
state <= RESET;
end
end
DETECT : begin
//检测到link状态出现下降沿
if (link_flag_dd[0] == 1'b0 && link_flag_dd[1] == 1'b1) begin
state <= RESET;
end
else begin
state <= DETECT;
end
end
default : begin
state <= IDLE ;
end
endcase
end
end
//----------------cnt_rst ------------------
always @(posedge clk) begin
if (rst == 1'b1) begin
cnt_rst <= 'd0;
end
else if (add_cnt_rst) begin
if(end_cnt_rst)
cnt_rst <= 'd0;
else
cnt_rst <= cnt_rst + 1'b1;
end
else begin
cnt_rst <= 'd0;
end
end
assign add_cnt_rst = state == RESET;
assign end_cnt_rst = add_cnt_rst && cnt_rst == RESET_MAX - 1;
//----------------link_flag_dd------------------
always @(posedge clk) begin
if (rst==1'b1) begin
link_flag_dd <= 'd0;
end
else begin
link_flag_dd <= {link_flag_dd[0], link_flag};
end
end
//----------------gt_reset_r------------------
always @(posedge clk) begin
if (rst==1'b1) begin
gt_reset_r <= 1'b1;
end
else if (link_flag_dd[0] == 1'b0 && link_flag_dd[1] == 1'b1) begin
gt_reset_r <= 1'b1;
end
else if (state == RESET && cnt_rst == GT_RESET_MAX - 1) begin
gt_reset_r <= 1'b0;
end
end
//----------------reset_r------------------
always @(posedge clk) begin
if (rst==1'b1) begin
reset_r <= 1'b1;
end
else if (link_flag_dd[0] == 1'b0 && link_flag_dd[1] == 1'b1) begin
reset_r <= 1'b1;
end
else if (state == RESET && cnt_rst == RESET_MAX - 1) begin
reset_r <= 1'b0;
end
end
endmodule
module gtp_tx(
input wire clk ,
input wire rst ,
output wire [0 : 31] s_axi_tx_tdata ,
output wire [0 : 3] s_axi_tx_tkeep ,
output wire s_axi_tx_tlast ,
output wire s_axi_tx_tvalid ,
input wire s_axi_tx_tready ,
output wire s_axi_ufc_tx_tvalid ,
output wire [0 : 2] s_axi_ufc_tx_tdata ,
input wire s_axi_ufc_tx_tready
);
//==========================================
//parameter defien
//==========================================
parameter STREAM_LEN = 1024 ;
reg [0:31] axi_tx_tdata ;
reg axi_tx_tlast ;
reg axi_tx_tvalid ;
reg axi_ufc_tx_tvalid ;
reg [15:0] cnt_burst ;
wire add_cnt_burst ;
wire end_cnt_burst ;
assign s_axi_tx_tdata = axi_tx_tdata;
assign s_axi_tx_tkeep = 4'hF;
assign s_axi_tx_tlast = axi_tx_tlast;
assign s_axi_tx_tvalid = axi_tx_tvalid;
assign s_axi_ufc_tx_tvalid = axi_ufc_tx_tvalid;
assign s_axi_ufc_tx_tdata = 3'b001;
//----------------cnt_burst ------------------
always @(posedge clk) begin
if (rst == 1'b1) begin
cnt_burst <= 'd0;
end
else if (add_cnt_burst) begin
if(end_cnt_burst)
cnt_burst <= 'd0;
else
cnt_burst <= cnt_burst + 1'b1;
end
end
assign add_cnt_burst = s_axi_tx_tready & axi_tx_tvalid;
assign end_cnt_burst = add_cnt_burst && cnt_burst == STREAM_LEN - 1;
//-----------------axi_tx_tlast-----------------
always @(*) begin
axi_tx_tlast = end_cnt_burst;
end
//----------------axi_tx_tvalid------------------
always @(posedge clk) begin
if (rst==1'b1) begin
axi_tx_tvalid <= 1'b0;
end
else if (end_cnt_burst == 1'b1) begin
axi_tx_tvalid <= 1'b0;
end
else if (axi_tx_tvalid == 1'b0 && s_axi_tx_tready == 1'b1) begin
axi_tx_tvalid <= 1'b1;
end
end
//----------------axi_tx_tdata------------------
always @(*) begin
axi_tx_tdata = cnt_burst;
end
//----------------axi_ufc_tx_tvalid------------------
always @(posedge clk) begin
if (rst==1'b1) begin
axi_ufc_tx_tvalid <= 1'b0;
end
else if (end_cnt_burst == 1'b1) begin
axi_ufc_tx_tvalid <= 1'b1;
end
else if (axi_ufc_tx_tvalid == 1'b1 && s_axi_ufc_tx_tready == 1'b1)begin
axi_ufc_tx_tvalid <= 1'b0;
end
end
wire [127:0] probe0;
assign probe0 = {
s_axi_tx_tdata ,
s_axi_tx_tkeep ,
s_axi_tx_tlast ,
s_axi_tx_tvalid ,
s_axi_tx_tready ,
s_axi_ufc_tx_tvalid ,
s_axi_ufc_tx_tdata ,
s_axi_ufc_tx_tready ,
cnt_burst
};
ila_0 inst_tx (
.clk(clk), // input wire clk
.probe0(probe0) // input wire [127:0] probe0
);
endmodule
`timescale 1ns / 1ps
module gtp_rx(
input wire clk ,
input wire rst ,
input wire [0 : 31] m_axi_rx_tdata ,
input wire [0 : 3] m_axi_rx_tkeep ,
input wire m_axi_rx_tlast ,
input wire m_axi_rx_tvalid ,
input wire [0 : 31] m_axi_ufc_rx_tdata ,
input wire [0 : 3] m_axi_ufc_rx_tkeep ,
input wire m_axi_ufc_rx_tlast ,
input wire m_axi_ufc_rx_tvalid ,
output wire error
);
//==========================================
//parameter define
//==========================================
parameter STREAM_LEN = 1024;
reg [15:0] cnt_burst ;
wire add_cnt_burst ;
wire end_cnt_burst ;
reg error_r ;
assign error = error_r;
always @(posedge clk) begin
if (rst == 1'b1) begin
cnt_burst <= 'd0;
end
else if (add_cnt_burst) begin
if(end_cnt_burst)
cnt_burst <= 'd0;
else
cnt_burst <= cnt_burst + 1'b1;
end
end
assign add_cnt_burst = m_axi_rx_tvalid;
assign end_cnt_burst = add_cnt_burst && cnt_burst == STREAM_LEN - 1;
//----------------error_r------------------
always @(posedge clk) begin
if (rst==1'b1) begin
error_r <= 1'b0;
end
else if (m_axi_rx_tvalid && (m_axi_rx_tdata != cnt_burst)) begin
error_r <= 1'b1;
end
end
wire [127:0] probe0;
assign probe0 = {
m_axi_rx_tdata ,
m_axi_rx_tkeep ,
m_axi_rx_tlast ,
m_axi_rx_tvalid ,
m_axi_ufc_rx_tdata ,
m_axi_ufc_rx_tkeep ,
m_axi_ufc_rx_tlast ,
m_axi_ufc_rx_tvalid ,
error_r,
cnt_burst
};
ila_0 inst_rx (
.clk(clk), // input wire clk
.probe0(probe0) // input wire [127:0] probe0
);
endmodule
`timescale 1ns / 1ps
module top_aurora_loop(
input wire clk ,
input wire rst_n ,
output wire led ,
output wire tx_dis ,
input wire REF_CLK_P ,
input wire REF_CLK_N ,
input wire RXP ,
input wire RXN ,
output wire TXP ,
output wire TXN
);
wire [0 : 31] s_axi_tx_tdata ;// 发送数据端口
wire [0 : 3] s_axi_tx_tkeep ;
wire s_axi_tx_tlast ;
wire s_axi_tx_tvalid ;
wire s_axi_tx_tready ;
wire s_axi_ufc_tx_tvalid ;// 发送流控端口
wire [0 : 2] s_axi_ufc_tx_tdata ;
wire s_axi_ufc_tx_tready ;
wire [0 : 31] m_axi_rx_tdata ;// 接收数据端口
wire [0 : 3] m_axi_rx_tkeep ;
wire m_axi_rx_tlast ;
wire m_axi_rx_tvalid ;
wire [0 : 31] m_axi_ufc_rx_tdata ;// 接收流控数据端口
wire [0 : 3] m_axi_ufc_rx_tkeep ;
wire m_axi_ufc_rx_tlast ;
wire m_axi_ufc_rx_tvalid ;
wire hard_err ;// 物理层错误
wire soft_err ;// 链路层错误
wire frame_err ;// 帧错误
wire reset ;// 复位信号,正确的复位才能使收发器正常工作
wire gt_reset ;
wire channel_up ;// 链接信号
wire [0 : 0] lane_up ;
wire crc_valid ;
wire crc_pass_fail_n ;
// GTP 收发通道
wire [0 : 0] txp ;
wire [0 : 0] txn ;
wire [0 : 0] rxp ;
wire [0 : 0] rxn ;
wire tx_lock ;
wire tx_resetdone_out ;
wire rx_resetdone_out ;
wire link_reset_out ;
wire init_clk_in ;// GTP初始化时钟
wire user_clk_out ;// 系统稳定的时钟
wire pll_not_locked_out ;
wire sys_reset_out ;// 系统复位信号
wire gt_refclk1_p ;// GTP 通道参考时钟
wire gt_refclk1_n ;
wire sync_clk_out ;
wire gt_reset_out ;
wire gt_refclk1_out ;
wire gt0_pll0refclklost_out ;
wire quad1_common_lock_out ;
wire gt0_pll0outclk_out ;
wire gt0_pll1outclk_out ;
wire gt0_pll0outrefclk_out ;
wire gt0_pll1outrefclk_out ;
wire sys_rst ;//用户模块复位信号(高有效),当前已经链接上,并且系统复位结束
wire rst ;
wire error ;
assign rst = ~rst_n;
assign led = ~error;
assign tx_dis = 1'b0;
assign {TXP, TXN} = {txp, txn};
assign {rxp, rxn} = {RXP, RXN};
assign {gt_refclk1_p, gt_refclk1_n} = {REF_CLK_P, REF_CLK_N};
assign sys_rst = ~(channel_up & lane_up & (~sys_reset_out));
assign init_clk_in = clk;
assign drpclk_in = clk;
gtp_reset_control inst_gtp_reset_control (
.clk (init_clk_in),
.rst (rst),
.channel_link_up (channel_up),
.lane_link_up (lane_up),
.reset (reset),
.gt_reset (gt_reset)
);
gtp_tx inst_gtp_tx (
.clk (user_clk_out),
.rst (sys_rst),
.s_axi_tx_tdata (s_axi_tx_tdata),
.s_axi_tx_tkeep (s_axi_tx_tkeep),
.s_axi_tx_tlast (s_axi_tx_tlast),
.s_axi_tx_tvalid (s_axi_tx_tvalid),
.s_axi_tx_tready (s_axi_tx_tready),
.s_axi_ufc_tx_tvalid (s_axi_ufc_tx_tvalid),
.s_axi_ufc_tx_tdata (s_axi_ufc_tx_tdata),
.s_axi_ufc_tx_tready (s_axi_ufc_tx_tready)
);
gtp_rx inst_gtp_rx (
.clk (user_clk_out),
.rst (sys_rst),
.m_axi_rx_tdata (m_axi_rx_tdata),
.m_axi_rx_tkeep (m_axi_rx_tkeep),
.m_axi_rx_tlast (m_axi_rx_tlast),
.m_axi_rx_tvalid (m_axi_rx_tvalid),
.m_axi_ufc_rx_tdata (m_axi_ufc_rx_tdata),
.m_axi_ufc_rx_tkeep (m_axi_ufc_rx_tkeep),
.m_axi_ufc_rx_tlast (m_axi_ufc_rx_tlast),
.m_axi_ufc_rx_tvalid (m_axi_ufc_rx_tvalid),
.error (error)
);
aurora inst_aurora (
.s_axi_tx_tdata(s_axi_tx_tdata), // input wire [0 : 31] s_axi_tx_tdata
.s_axi_tx_tkeep(s_axi_tx_tkeep), // input wire [0 : 3] s_axi_tx_tkeep
.s_axi_tx_tlast(s_axi_tx_tlast), // input wire s_axi_tx_tlast
.s_axi_tx_tvalid(s_axi_tx_tvalid), // input wire s_axi_tx_tvalid
.s_axi_tx_tready(s_axi_tx_tready), // output wire s_axi_tx_tready
.s_axi_ufc_tx_tvalid(s_axi_ufc_tx_tvalid), // input wire s_axi_ufc_tx_tvalid
.s_axi_ufc_tx_tdata(s_axi_ufc_tx_tdata), // input wire [0 : 2] s_axi_ufc_tx_tdata
.s_axi_ufc_tx_tready(s_axi_ufc_tx_tready), // output wire s_axi_ufc_tx_tready
.m_axi_rx_tdata(m_axi_rx_tdata), // output wire [0 : 31] m_axi_rx_tdata
.m_axi_rx_tkeep(m_axi_rx_tkeep), // output wire [0 : 3] m_axi_rx_tkeep
.m_axi_rx_tlast(m_axi_rx_tlast), // output wire m_axi_rx_tlast
.m_axi_rx_tvalid(m_axi_rx_tvalid), // output wire m_axi_rx_tvalid
.m_axi_ufc_rx_tdata(m_axi_ufc_rx_tdata), // output wire [0 : 31] m_axi_ufc_rx_tdata
.m_axi_ufc_rx_tkeep(m_axi_ufc_rx_tkeep), // output wire [0 : 3] m_axi_ufc_rx_tkeep
.m_axi_ufc_rx_tlast(m_axi_ufc_rx_tlast), // output wire m_axi_ufc_rx_tlast
.m_axi_ufc_rx_tvalid(m_axi_ufc_rx_tvalid), // output wire m_axi_ufc_rx_tvalid
.hard_err(hard_err), // output wire hard_err
.soft_err(soft_err), // output wire soft_err
.frame_err(frame_err), // output wire frame_err
.channel_up(channel_up), // output wire channel_up
.lane_up(lane_up), // output wire [0 : 0] lane_up
.txp(txp), // output wire [0 : 0] txp
.txn(txn), // output wire [0 : 0] txn
.reset(reset), // input wire reset
.gt_reset(gt_reset), // input wire gt_reset
.loopback(3'b000), // input wire [2 : 0] loopback
.rxp(rxp), // input wire [0 : 0] rxp
.rxn(rxn), // input wire [0 : 0] rxn
.crc_valid(crc_valid), // output wire crc_valid
.crc_pass_fail_n(crc_pass_fail_n), // output wire crc_pass_fail_n
.drpclk_in(drpclk_in), // input wire drpclk_in
.drpaddr_in('d0), // input wire [8 : 0] drpaddr_in
.drpen_in(1'b0), // input wire drpen_in
.drpdi_in('d0), // input wire [15 : 0] drpdi_in
.drprdy_out(drprdy_out), // output wire drprdy_out
.drpdo_out(drpdo_out), // output wire [15 : 0] drpdo_out
.drpwe_in(1'b0), // input wire drpwe_in
.power_down(1'b0 ), // input wire power_down
.tx_lock(tx_lock), // output wire tx_lock
.tx_resetdone_out(tx_resetdone_out), // output wire tx_resetdone_out
.rx_resetdone_out(rx_resetdone_out), // output wire rx_resetdone_out
.link_reset_out(link_reset_out), // output wire link_reset_out
.init_clk_in(init_clk_in), // input wire init_clk_in
.user_clk_out(user_clk_out), // output wire user_clk_out
.pll_not_locked_out(pll_not_locked_out), // output wire pll_not_locked_out
.sys_reset_out(sys_reset_out), // output wire sys_reset_out
.gt_refclk1_p(gt_refclk1_p), // input wire gt_refclk1_p
.gt_refclk1_n(gt_refclk1_n), // input wire gt_refclk1_n
.sync_clk_out(sync_clk_out), // output wire sync_clk_out
.gt_reset_out(gt_reset_out), // output wire gt_reset_out
.gt_refclk1_out(gt_refclk1_out), // output wire gt_refclk1_out
.gt0_pll0refclklost_out(gt0_pll0refclklost_out), // output wire gt0_pll0refclklost_out
.quad1_common_lock_out(quad1_common_lock_out), // output wire quad1_common_lock_out
.gt0_pll0outclk_out(gt0_pll0outclk_out), // output wire gt0_pll0outclk_out
.gt0_pll1outclk_out(gt0_pll1outclk_out), // output wire gt0_pll1outclk_out
.gt0_pll0outrefclk_out(gt0_pll0outrefclk_out), // output wire gt0_pll0outrefclk_out
.gt0_pll1outrefclk_out(gt0_pll1outrefclk_out) // output wire gt0_pll1outrefclk_out
);
endmodule
由于手上的光电转换模块,不是光纤,因此不能做一个单个的回环,那么手上有两块带光口的FPGA(别问,问就是老板的是),那么就可以使用这两块开发板来完成通信。
同样的板子,下载同样的程序,观察同样的现象。
可以看到用户发送模块正在发送数据。仔细康康可以发现,发送的是0~1023的递增数据。符合设计要求。
可以看到用户接收模块也接收到了数据,并且error信号为低,那么就说明传输的数据是正确的,接收到的数据,也是0~1023的递增数据哦。
如果把下载器接到另外一块板子上,同样也能观察到这个现象哦。
参考资料:
pg046-aurora-8b10b.pdf
Aurora8b10b IP example design