在之前的章节中,我们学习了高速通信的发送,接收等模块的设计, 同时展示了仿真程序的使用。这节课我们在FII-PRA006 Altera FPGA 开发板上做一个综合实验,验证高速通信的数据发送和接收。
之前的高速通信工程设计:

图1
在之前的工程设计中, 我们使用仿真程序来发送数据,检查算法的实现。 本节课程将对工程进行改造。
实验目的:
- 用FII-PRA006 FPGA开发板验证高速串行通信工程
- 学习IP核开发流程:分析需求,设计IP核,仿真验证,到真实的下板验证,最后封装
- 用示波器观察实际电路上的波形
- 使用SignalTap Logic Analyzer工具来抓取通信中的数据包
1.设计顶层模块
顶层模块是由前面工程的仿真文件tb_8b10b.v修改生成的,新添加了板载的时钟输入inclk,系统pll_rst 信号, 以及 tx,rx 的LVDS信号。使用宏在仿真和下板验证之间切换,详情见下列代码。

图2
重新设计的顶层模块,top.v 将包括hs_txrx.v 文件。
代码如下:
|
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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
`timescale 1 ns / 1 ps `define SIM module top #( parameter IDLE = 10'b1010_1010_10 ) `ifdef SIM (); parameter PERIOD = 20 ; //周期20 reg inclk ; // 模拟板级提供的输入时钟 initial begin inclk = 1'b0; #(PERIOD/2); forever #(PERIOD/2) inclk = ~inclk; end reg pll_rst; //实体模块PLL的rst信号 wire tx_rx; // 收发在testbench的回环信号 initial begin pll_rst=1'b1; #50 pll_rst=1'b0; #50000; $stop; end `else ( input inclk, output tx, input rx, input pll_rst ); `endif wire pll_locked; wire reset = !pll_locked; wire tx_rdy; reg [ 7: 0 ] tx_data; reg tx_en; reg tx_vld; wire tx_vld_ack; wire rx_data_vld; wire rx_data_rdy; wire ko; wire [ 7: 0 ] rx_data; wire clk_100M; localparam LEN = 16; reg [ 7: 0 ] frame_len; reg [ 2: 0 ] tx_st; always@( posedge clk_100M or posedge reset ) if ( reset ) begin tx_vld <= 1'b0; tx_en <= 1'b0; frame_len <= 0; tx_data <= 0; tx_st <= 0; end else begin case ( tx_st ) 0: begin tx_vld <= 1'b0; tx_en <= 1'b0; tx_data <= 0; frame_len <= 0; tx_st <= 1; end 1: begin tx_en <= 1'b0; tx_vld <= 1'b1; if ( frame_len == LEN ) begin tx_vld <= 1'b0; tx_st <= 3; end else if ( tx_rdy ) begin tx_en <= 1'b1; tx_st <= 2; end end 2: begin tx_en <= 1'b0; frame_len <= frame_len + 1; tx_data <= tx_data + 1; tx_st <= 1; end 3: begin frame_len <= 0; tx_vld <= 1'b0; tx_en <= 1'b0; if ( tx_vld_ack ) tx_st <= 1; end default: tx_st <= 0; endcase end hs_txrx #( .IDLE (IDLE) ) hs_txrx_inst ( .inclk (inclk), .pll_rst (pll_rst), .tx_rdy (tx_rdy), .tx_vld (tx_vld), .tx_data (tx_data), .tx_en (tx_en), .tx_vld_ack (tx_vld_ack), `ifdef SIM .tx (tx_rx), .rx (tx_rx), `else .tx (tx), .rx (rx), `endif .rx_data_vld(rx_data_vld), .rx_data_rdy(rx_data_rdy), .ko (ko), .rx_data (rx_data), .clk_100M (clk_100M), .pll_locked (pll_locked) ); endmodule |
打开SIM宏后,仿真结果如图3所示:

图3
图3中显示出修改后仿真结果和之前课程介绍的一致。
2.增加recv_data_link.v模块
之前的工程中PCS层的信号直接穿透到应用层。本节内容添加了接收端的数据链路层模块,代码如下:
|
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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
module recv_data_link #( parameter SYNC_START1 = 10'b0011111010, //K28.5 with dipin=0; parameter SYNC_START2 = 10'b1100000101, //K28.5 with dispin=1 parameter SYNC_END1 = 10'b0011111001, //K28.1 with dipin=0; parameter SYNC_END2 = 10'b1100000110 //K28.1 with dispin=1 ) ( input rst, input clk_100M , input clk_400M , input rx, output rx_ko, output [ 7: 0 ] rx_data, output rx_data_rdy, output rx_data_vld ); wire phy_rx_ko; wire [ 7: 0 ] phy_rx_data; wire phy_rx_data_rdy; wire phy_rx_data_vld; assign rx_ko = phy_rx_ko; assign rx_data = phy_rx_data; assign rx_data_rdy = phy_rx_data_rdy; assign rx_data_vld = phy_rx_data_vld; recv_data_pcs # ( .SYNC_START1 ( 10'b0011111010 ), //K28.5 with dipin=0; .SYNC_START2 ( 10'b1100000101 ), //K28.5 with dispin=1 .SYNC_END1 ( 10'b0011111001 ), //K28.1 with dipin=0; .SYNC_END2 ( 10'b1100000110 ) //K28.1 with dispin=1 ) recv_data_pcs_inst ( .rst ( rst ), .clk_100M ( clk_100M ), .clk_400M ( clk_400M ), .rx ( rx ), .pcs_rx_data_rdy ( phy_rx_data_rdy ), .pcs_ko ( phy_rx_ko ), .pcs_rx_data ( phy_rx_data ), .pcs_rx_data_vld ( phy_rx_data_vld ) ); endmodule |
3.hs_rxtx.v模块修改
因为接收端新添加了数据链路层,所以hs_txrx.v模块也需要做出相应的修改,代码如下:
|
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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
module hs_txrx #( parameter IDLE = 10'b1010_1010_10 ) ( input inclk, input pll_rst, output tx_rdy, input tx_vld, input [ 7: 0 ] tx_data, input tx_en, output tx_vld_ack, output tx, input rx, output rx_data_vld, output rx_data_rdy, output ko, output [ 7: 0 ] rx_data, output clk_100M, output pll_locked ); wire clk_400M; wire rst = !pll_locked; trans_data_link #( .IDLE ( IDLE ) ) trans_data_link_inst ( .rst ( rst ), .clk_100M ( clk_100M ), .tx_rdy ( tx_rdy ), .tx_vld ( tx_vld ), .tx_data ( tx_data ), .tx_en ( tx_en ), .tx_vld_ack ( tx_vld_ack ), .tx_out ( tx ) ); recv_data_link # ( .SYNC_START1 ( 10'b0011111010 ), //K28.5 with dipin=0; .SYNC_START2 ( 10'b1100000101 ), //K28.5 with dispin=1 .SYNC_END1 ( 10'b0011111001 ), //K28.1 with dipin=0; .SYNC_END2 ( 10'b1100000110 ) //K28.1 with dispin=1 ) recv_data_link_inst ( .rst ( rst ), .clk_100M ( clk_100M ), .clk_400M ( clk_400M ), .rx ( rx ), .rx_data_rdy ( rx_data_rdy ), .rx_ko ( ko ), .rx_data ( rx_data ), .rx_data_vld ( rx_data_vld ) ); pll1 pll1_inst ( .areset ( pll_rst ), //1'b0; .inclk0 ( inclk ), .c0 ( clk_100M ), .c1 ( clk_400M ), .locked ( pll_locked ) ); endmodule |
4.增加管脚约束

图4-1
注意图4-1中分配管脚时,tx和tx(n)的I/O Standard不是LVDS而是LVDS_E_3R。LVDS_E_3R中的“E”表示Emulated LVDS,“3R”指Emulated LVDS外接电阻网络。
The Intel Cyclone 10 LP left and right I/O banks (row I/Os) support true LVDS transmitters. The top and bottom I/O banks support emulated LVDS transmitters with external resistors.

图4-2
本工程使用的的LVDS输出,输入方式。 所以,我们需要对管脚进行约束。包括inclk, pll_rst, tx (txn), rx (rxn)。 其中tx , rx 为LVDS标准。
根据FII-PRA006 原理图,我们使用:
- FII-PRA006板载时钟,
- 开发板中的down key 作为pll_rst 信号。
- PMOD GPIO2 接口 IO8_p,IO8_n,作为tx 的LVDS
- PMOD GPIO2 接口 IO10_p,IO10_n,作为rx 的LVDS

图5
注意: 在选择LVDS的时候, 需要将FII-PRA006的硬件FPGA Bank 电压设置为2.5V。

图6

图7

图8
查看原理图,根据图5-图8 ,确定FPGA的输入输出管脚。
在板载实验中, 我们使用杜邦线,链接tx,rx LVDS对。在一块FPGA板上实现LVDS高速通信, 当然,也可以使用2块FPGA板,使用杜邦线链接。 注意, 在距离比较远的2个板子之间通信, 尽量使用双绞线。

图9
5.添加SignalTap Logic Analyzer

图10
在SignalTap 中增加我们需要测试的信号,包括:
- tx_rdy
- tx_vld
- tx_data[7:0]
- tx_en
- tx_vld_ack
- rx_data[7:0]
- rx_data_rdy
- ko
- rx_data_vld
- rx
- tx
同时设置trigger 条件为 tx_vld。

图11
在SignalTap 采样时, 我们使用clk_100M 时钟, 采样深度为1k。
6.板载测试结果
FII-PRA006 开发板回环实验

图12
根据图12,1)选择JTAG驱动,2)选择sof文件,3)下载sof文件。

图13
从实际实验的结果中, 可以看出, 发送端的数据被接收端正确的接收。 这一点和仿真程序中测试的结果相同。证明我们设计的整个算法是正确的。
板对板的LVDS高速通讯实验

图14

图15
图15 中可以看出, 在一个包结束的时候, k28.1 的结束标识,不同的包, 产生不同的k28.1 (正码,反码)。

图16
图16 为示波器抓取的LVDS差分信号当中的一根信号,可以看出所发送出来的数据流。
总结:
我们使用了开发板内的回环测试, 和板对板的高速串行通讯实验, 可以看出, 在不同的2个板子之间, 也是可以正常通讯的。有条件的同学可以试试逐步加长传输线的距离, 比如使用5m, 10m , 100m 的线长, 再次观察实验的结果。
Quartus工程下载(Quartus 20.1):
[content_control]
[/content_control]