LVDS学习笔记之 TX模块设计

系列文章目录

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));

由此我们可以看出该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

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.训练过程中截图

  训练初期,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的收发器。
  内容可能有些写的不是太准确的地方,欢迎留言指正,共同进步。

  • 5
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

郭郭的柳柳在学FPGA

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值