当前位置:   article > 正文

LVDS学习笔记之 TX模块设计_lvds训练

lvds训练

系列文章目录

LVDS学习笔记之 IDELAYE2应用及仿真
LVDS学习笔记之 ISERDESE2应用及仿真
LVDS学习笔记之 RX模块设计及自动训练仿真
LVDS学习笔记之 OSERDESE2应用及仿真

前言

  感谢各位同学的关注,前一阵子工作较忙,没时间给各位带来好的作品,后续会继续努力。
  经过LVDS学习笔记之 OSERDESE2应用及仿真的学习,我们清楚了通过SelectIO创建的LVDS发送模块内部具体使用的原语,接下来本文编写一个LVDS发送模块,并仿真。

一、OSERDESE2内容回顾

  通过SelectIO创建的LVDS发送模块主要有OSERDESE2这个原语,生成的OSERDESE2配置如下:

     OSERDESE2
       # (
         .DATA_RATE_OQ   ("SDR"),
         .DATA_RATE_TQ   ("SDR"),
         .DATA_WIDTH     (8),
         .TRISTATE_WIDTH (1),
         .SERDES_MODE    ("MASTER"))
       oserdese2_master (
         .D1             (oserdes_d[13][pin_count]),
         .D2             (oserdes_d[12][pin_count]),
         .D3             (oserdes_d[11][pin_count]),
         .D4             (oserdes_d[10][pin_count]),
         .D5             (oserdes_d[9][pin_count]),
         .D6             (oserdes_d[8][pin_count]),
         .D7             (oserdes_d[7][pin_count]),
         .D8             (oserdes_d[6][pin_count]),
         .T1             (1'b0),
         .T2             (1'b0),
         .T3             (1'b0),
         .T4             (1'b0),
         .SHIFTIN1       (1'b0),
         .SHIFTIN2       (1'b0),
         .SHIFTOUT1      (),
         .SHIFTOUT2      (),
         .OCE            (clock_enable),
         .CLK            (clk_in),
         .CLKDIV         (clk_div_in),
         .OQ             (data_out_to_pins_predelay[pin_count]),
         .TQ             (),
         .OFB            (),
         .TFB            (),
         .TBYTEIN        (1'b0),
         .TBYTEOUT       (),
         .TCE            (1'b0),
         .RST            (io_reset));

  • 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

由此我们可以看出该OSERDESE2是工作在SDR模式下,并且数据位宽是8位。根据下图可得到突发长度位7CLK cycles。
在这里插入图片描述

三、LVDS发送模块仿真代码

1.工程代码

`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,
		output			fifo_wr_rst_busy,
		
		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			fifo_rd_rst_busy;
	wire [7:0]		tx_dout;
	wire 			data_mux;
	
				
	assign fifo_rden = ((~fifo_empty) & (~fifo_rd_rst_busy) & (~training_flag));
			
	
	fifo_generator_0
	lvds_send_fifo
   (
		.rst            (reset				),
		.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			),
		.wr_rst_busy    (fifo_wr_rst_busy	),
		.rd_rst_busy	(fifo_rd_rst_busy	)
	);
	
	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

  • 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

2.测试代码

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2022/01/18 22:54:53
// Design Name: 
// Module Name: lvds_tx_top_tb
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//
`define	clk_100preiod 10

module lvds_tx_top_tb();

	reg 		clk_in100           ;
	reg 		reset               ;
	reg			fifo_wren           ;
	reg [7:0] 	fifo_din            ;
	wire 		fifo_full           ;
	wire		fifo_wr_rst_busy    ;
	reg 		training_finish     ;
	wire 		lvds_clk_p          ;
	wire 		lvds_clk_n          ;
	wire  		lvds_tx_p           ;
	wire  		lvds_tx_n		    ;
	
	wire		clk_100m  ;
	wire		clk_25m   ;
	wire		clk_200m  ;
	wire		locked;
	
	
clk_wiz_0 
clk_inst(
	.clk_out100     (clk_100m),
	.clk_out200     (clk_200m),
	.clk_out25      (clk_25m),
	.reset          (reset),
	.locked         (locked),
	.clk_in100      (clk_in100	)
 );


lvds_tx_top	
lvds_tx_top_inst(
	.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),
	.fifo_wr_rst_busy    (fifo_wr_rst_busy),
	.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	)
);
	integer i;
	initial begin
		clk_in100 = 0;
	end
	
	always #(`clk_100preiod/2) clk_in100 = ~clk_in100;

	initial begin
	/******初始化********/
		reset = 1;
		fifo_wren = 0;
		fifo_din  = 0;
		training_finish = 0;	//手动模拟训练未结束
		#(`clk_100preiod * 2);
		reset = 0;
		@(posedge locked);
		#(`clk_100preiod * 100);
		
	/********模拟训练结束*****/
		training_finish = 1;	//手动模拟训练结束
		@(negedge lvds_tx_top_inst.training_flag);
		#(`clk_100preiod * 8);

		for(i = 0; i < 255; i = i + 1)begin
			fifo_wren = 1;
			fifo_din  = i;
			#(`clk_100preiod);
			fifo_wren = 0;
			#(`clk_100preiod * 10);
		end
		#(`clk_100preiod * 100);
		$stop;
	end


endmodule

  • 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

三、仿真截图

1.训练过程中截图

  训练初期,LVDS发送模块一致往LVDS接收模块发送partenr用于训练,本次训练的字为0x93(10010011),OSERDESE2会从低到高将数据传输出去,并且在8位宽,SDR模式下有7CLK的突发长度,但实际仿真只有6个clk的突发长度。这个是什么原因呢,在手册上有这样一句话,CLK、CLKDIV的时钟沿通常不是相位一致的。当这两个时钟的时钟沿相位一致时,延迟会存在一个周期的差异,因此有6个clk的突发长度。
在这里插入图片描述

请添加图片描述

2.训练结束后仿真

![在这里插入图片描述](https://img-blog.csdnimg.cn/cee3c8572e0f4ed3b922ab19b8d4dfd6.png
  训练结束后讲准备发送的数据放入FIFO中进行缓存,满足条件后启动FIFO的读,并将数据放入FIFO的发送端进行发送。
请添加图片描述
  从FIFO中逐个读取进行数据发送。

总结

  以上为LVDS的发送模块设计方案及方针。中间最主要这个突发长度与手册上对不上的原因也做了说明,后续可将笔者写的发送模块和接收模块整个到一个工程,可创建LVDS的收发器。
  内容可能有些写的不是太准确的地方,欢迎留言指正,共同进步。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小桥流水78/article/detail/858348
推荐阅读
相关标签
  

闽ICP备14008679号