系列文章目录
LVDS学习笔记之 IDELAYE2应用及仿真
LVDS学习笔记之 ISERDESE2应用及仿真
LVDS学习笔记之 RX模块设计及自动训练仿真
LVDS学习笔记之 OSERDESE2应用及仿真
LVDS学习笔记之 TX模块设计
文章目录
前言
经过前面几章的学习,我们已经有了LVDS的接收模块和发送模块例程,本章节会将两者结合成一个工程,设计一个LVDS收发模块。
一、设计顶层
设计的顶层如上图所示。
- clk_manager模块
用于产生系统时钟,LVDS所需时钟,系统复位等信号;
- lvds_rx_top模块
与上期发布的LVDS学习笔记之 RX模块设计及自动训练仿真基本相同,做了简单的修改,一方面用于上电后的上电,另一方面用于接收LVDS数据;
- lvds_tx_top模块
同样与LVDS学习笔记之 TX模块设计类似,做了简单的修改,用于产生上电后的训练字,以及训练完成后产生所欲要的控制字。
不懂的同学可看下前面的文章。
二、工程代码
工程代码只放了工程顶层,和部分模块的顶层程序,如需需要其他工程代码程序,可下载本章的工程源代码。
代码说明:
顶层包含了lvds接口,以及准备下发数据的缓存fifo接口,接收的数据会由recv_fifo_dout输出。
训练完成后,仅需控制fifo,将需要传输的数据写入到fifo中,lvds就会启动发送模块,完成发送功能。
1.lvds_top顶层
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2022/08/17 22:48:43
// Design Name:
// Module Name: lvds_top
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module lvds_top(
input sys_clk_in,//50M,
//lvds rx
input lvds_rx_p,
input lvds_rx_n,
//lvds tx
output lvds_clk_p,
output lvds_clk_n,
output lvds_tx_p,
output lvds_tx_n,
input fifo_wren,
input [7:0] fifo_din,
output fifo_full,
output[7:0] recv_fifo_dout
);
wire clk_100m;
wire clk_200m;
wire clk_25m;
wire reset;
wire training_finish;
clk_manager clk_manager_inst(
.clk_in ( sys_clk_in ), //50M,
.clk_100m ( clk_100m ),
.clk_200m ( clk_200m ),
.clk_25m ( clk_25m ),
.sys_reset ( reset )
);
lvds_rx_top u_lvds_rx_top(
.clk_100m ( clk_100m ),
.clk_200m ( clk_200m ),
.clk_25m ( clk_25m ),
.reset ( reset ),
.lvds_rx_p ( lvds_rx_p ),
.lvds_rx_n ( lvds_rx_n ),
.training_finish ( training_finish ),
.recv_fifo_dout ( recv_fifo_dout )
);
lvds_tx_top u_lvds_tx_top(
.clk_100m ( clk_100m ),
.clk_25m ( clk_25m ),
.clk_200m ( clk_200m ),
.reset ( reset ),
.fifo_wren ( fifo_wren ),
.fifo_din ( fifo_din ),
.fifo_full ( fifo_full ),
.training_finish ( training_finish ),
.lvds_clk_p ( lvds_clk_p ),
.lvds_clk_n ( lvds_clk_n ),
.lvds_tx_p ( lvds_tx_p ),
.lvds_tx_n ( lvds_tx_n )
);
endmodule
2.clk_manager模块
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2021/12/30 22:31:46
// Design Name:
// Module Name: clk_manager
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module clk_manager(
input clk_in, //50M,
output clk_100m,
output clk_200m,
output clk_25m,
output reg sys_reset
);
wire pll_locked;
reg [7:0] locked_r = 8'b0;
clk_wiz_0
clk_wiz_0_inst
(
.clk_100m(clk_100m), // output clk_100m
.clk_200m(clk_200m), // output clk_200m
.clk_25m(clk_25m), // output clk_25m
.locked(pll_locked), // output locked
.clk_in(clk_in)); // input clk_in
always @ (posedge clk_100m)
begin
locked_r <= {locked_r[6:0], pll_locked};
if (&locked_r)
sys_reset <= 1'b0;
else
sys_reset <= 1'b1;
end
endmodule
3.lvds_tx_top模块
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2022/01/18 22:24:08
// Design Name:
// Module Name: lvds_tx_top
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module lvds_tx_top(
input clk_100m,
input clk_25m,
input clk_200m,
input reset,
input fifo_wren,
input [7:0] fifo_din,
output fifo_full,
input training_finish,
output lvds_clk_p,
output lvds_clk_n,
output lvds_tx_p,
output lvds_tx_n
);
reg io_reset;
reg training_flag;
reg [19:0] timer_count;
wire fifo_rden;
wire [7:0] fifo_dout;
wire fifo_empty;
wire [7:0] tx_dout;
wire data_mux;
assign fifo_rden = ((~fifo_empty) & (~training_flag));
fifo_generator_0
lvds_send_fifo
(
.wr_clk (clk_100m ),
.rd_clk (clk_25m ),
.din (fifo_din ),
.wr_en (fifo_wren ),
.rd_en (fifo_rden ),
.dout (fifo_dout ),
.full (fifo_full ),
.empty (fifo_empty )
);
always @(posedge clk_25m)
if(reset)
timer_count <= 20'd0;
else if (~training_finish)
timer_count <= 20'd0;
else if (timer_count < 20'hFFFF0)
timer_count <= timer_count + 1'b1;
`define SIM //仿真时为了加快仿真速度定义SIM,正式使用时注释掉
always @(posedge clk_25m)
if(reset)
training_flag <= 1'b0;
`ifdef SIM
else if (timer_count < 20'd100)
training_flag <= 1'b1;
`else
else if (timer_count < 20'd100000)
training_flag <= 1'b1;
`endif
else
training_flag <= 1'b0;
assign data_mux = fifo_rden & (~fifo_empty);
assign tx_dout = training_flag ? 8'h93 : (data_mux ? fifo_dout : 8'h0000);
always @(posedge clk_25m)
if (reset)
io_reset <= 1'b1;
else
io_reset <= 1'b0;
lvds_tx
lvds_tx_inst
(
.data_out_from_device (tx_dout ),
.data_out_to_pins_p (lvds_tx_p ),
.data_out_to_pins_n (lvds_tx_n ),
.clk_to_pins_p (lvds_clk_p ),
.clk_to_pins_n (lvds_clk_n ),
.clk_in (clk_200m ),
.clk_div_in (clk_25m ),
.clk_reset (io_reset ),
.io_reset (io_reset )
);
endmodule
4.lvds_rx_top模块
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2021/12/30 22:33:26
// Design Name:
// Module Name: lvds_rx_top
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module lvds_rx_top(
input clk_100m,
input clk_200m,
input clk_25m,
input reset,
input lvds_rx_p,
input lvds_rx_n,
output training_finish,
output[7:0] recv_fifo_dout
);
wire recv_fifo_empty;
wire delay_locked;
wire[7:0] rx_data;
wire delay_ld;
wire[4:0] delay_tap;
wire bitslip;
reg recv_fifo_rden;
lvds_rx_recv
lvds_rx_recv_inst(
.clk_100m(clk_100m),
.clk_200m(clk_200m),
.reset(reset),
.clk_ser(clk_200m), //200m
.clk_div(clk_25m), //25m
.fifo_rden(recv_fifo_rden),
.fifo_dout(recv_fifo_dout),
.fifo_empty(recv_fifo_empty),
.delay_locked(delay_locked),
.rx_dout(rx_data),
.delay_ld(delay_ld),
.delay_tap(delay_tap),
.bitslip(bitslip),
.training_finish(training_finish),
.lvds_rx_p(lvds_rx_p),
.lvds_rx_n(lvds_rx_n)
);
lvds_rx_training
lvds_rx_training_inst
(
.clk_div(clk_25m),
.reset(reset),
.delay_locked(delay_locked),
.rx_din(rx_data),
.delay_ld(delay_ld),
.delay_tap(delay_tap),
.bitslip(bitslip),
.training_finish(training_finish)
);
always@(posedge clk_100m)begin
if(!recv_fifo_empty )begin
recv_fifo_rden <= 1'b1;
end
else begin
recv_fifo_rden <= 1'b0;
end
end
endmodule
三、仿真tb代码
代码说明:
等待训练完成后,控制fifo写入带发送的数据,观察接收端口的数据。
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2021/12/30 22:54:53
// Design Name:
// Module Name: lvds_rx_top_tb
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
`define clk_period 20
module lvds_top_tb();
reg sys_clk_in = 0;//50M;
//lvds rx
reg lvds_rx_p;
reg lvds_rx_n;
//lvds tx
wire lvds_clk_p;
wire lvds_clk_n;
wire lvds_tx_p;
wire lvds_tx_n;
reg fifo_wren;
reg [7:0] fifo_din;
wire fifo_full;
wire[7:0] recv_fifo_dout;
lvds_top u_lvds_top(
.sys_clk_in ( sys_clk_in ),
.lvds_rx_p ( lvds_rx_p ),
.lvds_rx_n ( lvds_rx_n ),
.lvds_clk_p ( lvds_clk_p ),
.lvds_clk_n ( lvds_clk_n ),
.lvds_tx_p ( lvds_tx_p ),
.lvds_tx_n ( lvds_tx_n ),
.fifo_wren ( fifo_wren ),
.fifo_din ( fifo_din ),
.fifo_full ( fifo_full ),
.recv_fifo_dout ( recv_fifo_dout )
);
always @(posedge lvds_clk_p ) begin
lvds_rx_p <= lvds_tx_p;
lvds_rx_n <= lvds_tx_n;
end
always #(`clk_period/2) sys_clk_in = ~sys_clk_in;
initial begin
fifo_wren = 0;
fifo_din = 0;
@(posedge u_lvds_top.training_finish);
#200;
lvds_wr(8'h01);
lvds_wr(8'h02);
lvds_wr(8'h03);
lvds_wr(8'h04);
lvds_wr(8'h05);
lvds_wr(8'h06);
lvds_wr(8'h07);
lvds_wr(8'h08);
#200;
lvds_wr(8'h09);
$stop;
end
task lvds_wr;
input [7:0] data;
begin
fifo_wren = 1;
fifo_din = data;
#10;
fifo_wren = 0;
#10;
end
endtask
endmodule
四、仿真截图
1.训练过程
上电完成后会启动训练,tx模块持续发送8'h93,待接收数据为8'h93后训练完成
2.写入待发送的数据
训练完成后分别往fifo中写入8'h01、8'h02、8'h03、8'h04、8'h05、8'h06、8'h07、8'h08
3.接收到的数据
接收到的数据与写入的数据相同
4.耗时
发送到接收传输耗时
单个字节传输耗时
由lvds的特性,单个字节耗时为25m时钟耗时,即40ns,可见是非常快。
总结
本文将前期编写的接收模块和发送模块进行整合,形成了lvds的收发器,经过仿真能够正确的接收发送端传输来的数据。但可发现并没有传输完成的标志信号,数据只是在lvds总线上进行传输而已。因此还需要进行发送接收协议的设计,在这里作者大致的讲解一下设计方法。
设计思想:
需要设计一个校验方式,如CRC校验
需要设计一个数据帧头,如接收到0x55aa即为数据帧头
接收到帧头后接收需要传输的数据
也可接收数据帧头后,接收数据长度,然后根据数据长度进行接收数据
lvds的发送可能会受到外界干扰,因此还需要设计重发机制
一帧数据的发送:
数据的发送帧大致为{帧头,数据长度,数据,校验},或者{帧头,数据,校验};
校验不通过后启动重发机制,若连续3次还为正常接收到数据,认定传输错误。
最后附上文章工程文件地址https://download.csdn.net/download/weixin_45372778/86405548
下期将会对本工程上板调试
欢迎各位同学,老师进行批评指正,共同进步,谢谢。