赞
踩
LVDS学习笔记之 IDELAYE2应用及仿真
LVDS学习笔记之 ISERDESE2应用及仿真
LVDS学习笔记之 RX模块设计及自动训练仿真
LVDS学习笔记之 OSERDESE2应用及仿真
感谢各位同学的关注,前一阵子工作较忙,没时间给各位带来好的作品,后续会继续努力。
经过LVDS学习笔记之 OSERDESE2应用及仿真的学习,我们清楚了通过SelectIO创建的LVDS发送模块内部具体使用的原语,接下来本文编写一个LVDS发送模块,并仿真。
通过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。
`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
`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
训练初期,LVDS发送模块一致往LVDS接收模块发送partenr用于训练,本次训练的字为0x93(10010011),OSERDESE2会从低到高将数据传输出去,并且在8位宽,SDR模式下有7CLK的突发长度,但实际仿真只有6个clk的突发长度。这个是什么原因呢,在手册上有这样一句话,CLK、CLKDIV的时钟沿通常不是相位一致的。当这两个时钟的时钟沿相位一致时,延迟会存在一个周期的差异,因此有6个clk的突发长度。
训练结束后讲准备发送的数据放入FIFO中进行缓存,满足条件后启动FIFO的读,并将数据放入FIFO的发送端进行发送。
从FIFO中逐个读取进行数据发送。
以上为LVDS的发送模块设计方案及方针。中间最主要这个突发长度与手册上对不上的原因也做了说明,后续可将笔者写的发送模块和接收模块整个到一个工程,可创建LVDS的收发器。
内容可能有些写的不是太准确的地方,欢迎留言指正,共同进步。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。