在使用Xilinx提供的GT Wizard IP核时例化了多个两个收发通道,前期测试时只接了通道0,测试正常。但后期接入通道1时出现问题。当我断开通道0,只连接通道1时,数据接收错乱了。多方查询后发现是使用Vivado生成的仿真例程有问题,修改例程文件中的时钟连接逻辑即可解决例化多通道时只使用单通道有可能出现数据时钟错乱的问题。

环境

  • Vivado 2021.2.1
  • VScode Portable

分析解决

问题定位

右键IP核生成IP仿真例程后,可以在工程列表中找到类似gtwizard_0_GT_USRCLK_SOURCE。v的文件,这是用于配置GTX时钟资源的文件,其中在末尾的发送与接收时钟输出的语句可以看到问题所在,例程在仿真时输出的时钟全部采用通道0的时钟,因此在综合后上板子调试后,若通道0空载,则输出的恢复时钟混乱造成数据处理时序混乱。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
    // Instantiate a MMCM module to divide the reference clock. Uses internal feedback
// for improved jitter performance, and to avoid consuming an additional BUFG

BUFG txoutclk_bufg0_i
(
.I (gt0_txoutclk_i),
.O (gt0_txusrclk_i)
);


BUFG rxoutclk_bufg1_i
(
.I (gt0_rxoutclk_i),
.O (gt0_rxusrclk_i)
);

assign GT0_TXUSRCLK_OUT = gt0_txusrclk_i;
assign GT0_TXUSRCLK2_OUT = gt0_txusrclk_i;
assign GT0_RXUSRCLK_OUT = gt0_rxusrclk_i;
assign GT0_RXUSRCLK2_OUT = gt0_rxusrclk_i;

assign GT1_TXUSRCLK_OUT = gt0_txusrclk_i;
assign GT1_TXUSRCLK2_OUT = gt0_txusrclk_i;
assign GT1_RXUSRCLK_OUT = gt0_rxusrclk_i;
assign GT1_RXUSRCLK2_OUT = gt0_rxusrclk_i;

问题定位

因此,需要将通道1的时钟源修改回其原本的内部恢复/发送时钟。需要增加一些两个BUFG的资源,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
    // Instantiate a MMCM module to divide the reference clock. Uses internal feedback
// for improved jitter performance, and to avoid consuming an additional BUFG

BUFG txoutclk_bufg0_i0
(
.I (gt0_txoutclk_i),
.O (gt0_txusrclk_i)
);


BUFG rxoutclk_bufg1_i0
(
.I (gt0_rxoutclk_i),
.O (gt0_rxusrclk_i)
);

BUFG txoutclk_bufg0_i1
(
.I (gt1_txoutclk_i),
.O (gt1_txusrclk_i)
);


BUFG rxoutclk_bufg1_i1
(
.I (gt1_rxoutclk_i),
.O (gt1_rxusrclk_i)
);

assign GT0_TXUSRCLK_OUT = gt0_txusrclk_i;
assign GT0_TXUSRCLK2_OUT = gt0_txusrclk_i;
assign GT0_RXUSRCLK_OUT = gt0_rxusrclk_i;
assign GT0_RXUSRCLK2_OUT = gt0_rxusrclk_i;

assign GT1_TXUSRCLK_OUT = gt1_txusrclk_i;
assign GT1_TXUSRCLK2_OUT = gt1_txusrclk_i;
assign GT1_RXUSRCLK_OUT = gt1_rxusrclk_i;
assign GT1_RXUSRCLK2_OUT = gt1_rxusrclk_i;

修改之后,通道0与通道1的时钟域相互独立,接收数据后使用FIFO或RAM将数据同步到FPGA内部时钟域下进行进一步处理,发送也同理。