1.项目背景和问题描述
项目背景
使用8B/10B编码在 GTH 和GTX 间进行通信,其中一个GTH作为数据接收端和指令发送端( 主机) ,四个GTX作为数据发送端和指令接收端( 从机) 。
问题描述
GTX进行数据和指令的自收自发,能够稳定接收指令。但是在GTH和GTX的板件测试中,接收端有误码。
GTH进行数据和指令的自收自发,能够稳定的接收数据和指令。GTH用通道0与GTX进行板件测试,接收端能稳定接收数据。但使用其他通道与GTX进行板间测试,接收端有误码。
2.问题原因
先解释一个概念:恢复时钟,在用gtx进行跨板子传输数据时,他们的参考时钟可能是不同的。因此,虽然参考时钟的频率是一样的,但是他们之间会存在一定的相位差。
为了解决这个问题,gtx/gth会使用参考时钟和接收到的数据流恢复出一个与发送端同步的时钟,也就是所谓的恢复时钟。
如果我们的接收端没有正确使用恢复时钟便会出现误码的问题。
3.解决问题
1)GTX
gtx IP核的第三项 Encoding and Clocking 的这个选项如果被勾选了,gtx 的数据接收端就会使用参考时钟而不是恢复时钟去接收数据,当接收端的参考时钟和发送端的参考时钟存在相位差时便会出现误码问题。
2)GTH
GTH IP核 的接收端只能选择恢复时钟。因此,GTH出现误码的问题点不是接收端的时钟选择上面。
问题点出在我们大多数情况下会直接使用GTH参考例程中的代码。
参考例程中四个通道的恢复时钟统一使用某一个通道的恢复时钟,因此出现了我上面问题描述的GTH只有通道0能够稳定接收数据。
个人认为这种设置适用于一主一从多通道的模式。因为在这种配置下,接收端的多个通道的恢复时钟都与发送端的时钟同步,也就是多个通道的恢复时钟彼此是同步的。这样只需要使用一个通道的恢复时钟即可,同时也节省了三个时钟BUFFER。
但是我们这个项目是一主多从模式,主机的四个通道分别各自对应一个发送端,因此主机接收端的恢复时钟各自不同。需要使用各自的恢复时钟,如下所示:
wire [3:0] rxusrclk_int;
wire [3:0] rxusrclk2_int;
wire [3:0] rxoutclk_int;
// Generate a single module instance which is driven by a clock source associated with the master receiver channel,
// and which drives RXUSRCLK and RXUSRCLK2 for all channels
// The source clock is RXOUTCLK from the master receiver channel
assign gtwiz_userclk_rx_srcclk_out = rxoutclk_int ;
// Instantiate a single instance of the receiver user clocking network helper block
Gth0_example_gtwiz_userclk_rx gtwiz_userclk_rx_inst0 (
.gtwiz_userclk_rx_srcclk_in (gtwiz_userclk_rx_srcclk_out[0]),
.gtwiz_userclk_rx_reset_in (gtwiz_userclk_rx_reset_in),
.gtwiz_userclk_rx_usrclk_out ( gtwiz_userclk_rx_usrclk_out[0]),
.gtwiz_userclk_rx_usrclk2_out (gtwiz_userclk_rx_usrclk2_out[0]),
.gtwiz_userclk_rx_active_out (gtwiz_userclk_rx_active_out[0])
);
Gth0_example_gtwiz_userclk_rx gtwiz_userclk_rx_inst1 (
.gtwiz_userclk_rx_srcclk_in (gtwiz_userclk_rx_srcclk_out[1]),
.gtwiz_userclk_rx_reset_in (gtwiz_userclk_rx_reset_in),
.gtwiz_userclk_rx_usrclk_out ( gtwiz_userclk_rx_usrclk_out[1]),
.gtwiz_userclk_rx_usrclk2_out (gtwiz_userclk_rx_usrclk2_out[1]),
.gtwiz_userclk_rx_active_out (gtwiz_userclk_rx_active_out[1])
);
Gth0_example_gtwiz_userclk_rx gtwiz_userclk_rx_inst2 (
.gtwiz_userclk_rx_srcclk_in (gtwiz_userclk_rx_srcclk_out[2]),
.gtwiz_userclk_rx_reset_in (gtwiz_userclk_rx_reset_in),
.gtwiz_userclk_rx_usrclk_out ( gtwiz_userclk_rx_usrclk_out[2]),
.gtwiz_userclk_rx_usrclk2_out (gtwiz_userclk_rx_usrclk2_out[2]),
.gtwiz_userclk_rx_active_out (gtwiz_userclk_rx_active_out[2])
);
Gth0_example_gtwiz_userclk_rx gtwiz_userclk_rx_inst3 (
.gtwiz_userclk_rx_srcclk_in (gtwiz_userclk_rx_srcclk_out[3]),
.gtwiz_userclk_rx_reset_in (gtwiz_userclk_rx_reset_in),
.gtwiz_userclk_rx_usrclk_out ( gtwiz_userclk_rx_usrclk_out[3]),
.gtwiz_userclk_rx_usrclk2_out (gtwiz_userclk_rx_usrclk2_out[3]),
.gtwiz_userclk_rx_active_out (gtwiz_userclk_rx_active_out[3])
);
// Drive RXUSRCLK and RXUSRCLK2 for all channels with the respective helper block outputs
assign rxusrclk_int = gtwiz_userclk_rx_usrclk_out ;
assign rxusrclk2_int = gtwiz_userclk_rx_usrclk2_out;