├── src ├── maincore.ucf ├── lvds_clockgen.v ├── video_lvds.v ├── serializer.v └── maincore.v ├── README.md └── LICENSE /src/maincore.ucf: -------------------------------------------------------------------------------- 1 | 2 | # PlanAhead Generated IO constraints 3 | NET "clk" IOSTANDARD = LVCMOS33; 4 | 5 | # PlanAhead Generated physical constraints 6 | NET "channel1_p" LOC = A5; 7 | NET "channel1_n" LOC = C5; 8 | NET "channel2_p" LOC = A6; 9 | NET "channel2_n" LOC = B6; 10 | NET "channel3_p" LOC = A7; 11 | NET "channel3_n" LOC = C7; 12 | NET "clock_p" LOC = D7; 13 | NET "clock_n" LOC = C6; 14 | 15 | NET "clk" LOC = C10; 16 | #Created by Constraints Editor (xa3s400a-ftg256-4) - 2013/07/05 17 | NET "clk" TNM_NET = clk; 18 | TIMESPEC TS_clk = PERIOD "clk" 62.5 ns HIGH 50%; 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | LVDS-7-to-1-Serializer 2 | ====================== 3 | 4 | An Verilog implementation of 7-to-1 LVDS Serializer. Which can be used for comunicating FPGAs with LVDS TFT Screens. 5 | Tested on Spartan 3A Evaluation Kit 6 | 7 | * Target Device: `xa3s400a-4ftg256` 8 | * Flip-flops used: 114 9 | * 4 Input LUTs used: 140 10 | * Slices used: 127 11 | * DCMs used: 2 12 | * ODDR2 used: 4 13 | 14 | The Serializer core is composed by `lvds_clockgen.v` and `serializer.v`. But I provided an example of how to use it with `maincore.v`, `video_lvds.v` that is both files for a Video Signal Generator to common notebook LVDS TFT Panels. 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Lucas Teske 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /src/lvds_clockgen.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Company: Teske Virtual System 4 | // Engineer: Lucas Teske 5 | // 6 | // Create Date: 19:14:43 07/04/2013 7 | // Design Name: LVDS 7-to-1 Serializer 8 | // Module Name: lvds_clockgen 9 | // GitHub: https://github.com/racerxdl/LVDS-7-to-1-Serializer 10 | ////////////////////////////////////////////////////////////////////////////////// 11 | 12 | module lvds_clockgen( 13 | input clk, 14 | output clk35, 15 | output nclk35, 16 | output rstclk, 17 | output dataclock, 18 | output lvdsclk 19 | ); 20 | 21 | 22 | // Clock: 1100011 23 | 24 | wire clk_lckd; 25 | wire clkdcm; 26 | wire clo; 27 | 28 | DCM_SP #(.CLKIN_PERIOD ("15.625"), 29 | .DESKEW_ADJUST ("0"), 30 | .CLKFX_MULTIPLY (7), 31 | .CLKFX_DIVIDE (2)) 32 | dcm_clk ( 33 | .CLKIN (clk), 34 | .CLKFB (clo), 35 | .RST (1'b0), 36 | .CLK0 (clkdcm), 37 | .CLKFX (clk35), 38 | .CLKFX180 (nclk35), 39 | .CLK180 (), 40 | .CLK270 (), 41 | .CLK2X (), 42 | .CLK2X180 (), 43 | .CLK90 (), 44 | .CLKDV (), 45 | .PSDONE (), 46 | .STATUS (), 47 | .DSSEN (1'b0), 48 | .PSINCDEC (1'b0), 49 | .PSEN (1'b0), 50 | .PSCLK (1'b0), 51 | .LOCKED (clk_lckd)) ; 52 | 53 | BUFG clk_bufg (.I(clkdcm), .O(clo) ) ; 54 | 55 | assign not_clk_lckd = ~clk_lckd ; 56 | 57 | FDP fd_rst_clk (.D(not_clk_lckd), .C(clo), .Q(rst_clk)) ; 58 | 59 | // The LVDS Clock is 4:3, if you need 3:4 you can use 7'b0011100 60 | serializer lvdsclkman ( 61 | .clk(clo), 62 | .clk35(clk35), 63 | .notclk35(nclk35), 64 | .data(7'b1100011), 65 | .rst(rst_clk), 66 | .out(lvdsclk) 67 | ); 68 | 69 | assign rstclk = rst_clk; 70 | assign dataclock = clo; 71 | endmodule 72 | -------------------------------------------------------------------------------- /src/video_lvds.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Company: Teske Virtual System 4 | // Engineer: Lucas Teske 5 | // 6 | // Create Date: 20:23:28 07/04/2013 7 | // Design Name: Video LVDS Serializer 8 | // Module Name: video_lvds 9 | // GitHub: https://github.com/racerxdl/LVDS-7-to-1-Serializer 10 | ////////////////////////////////////////////////////////////////////////////////// 11 | 12 | module video_lvds( 13 | input DotClock, 14 | input HSync, 15 | input VSync, 16 | input DataEnable, 17 | input [5:0] Red, 18 | input [5:0] Green, 19 | input [5:0] Blue, 20 | output channel1_p, 21 | output channel1_n, 22 | output channel2_p, 23 | output channel2_n, 24 | output channel3_p, 25 | output channel3_n, 26 | output clock_p, 27 | output clock_n 28 | ); 29 | 30 | wire clk35, notclk35, c1,c2,c3,lvdsclk, rst_clk, DataClock; 31 | wire [20:0] VideoData; 32 | 33 | OBUFDS #(.IOSTANDARD("LVDS_33")) lvds_channel1_obuf (.I(c1), .O(channel1_p), .OB(channel1_n) ); 34 | OBUFDS #(.IOSTANDARD("LVDS_33")) lvds_channel2_obuf (.I(c2), .O(channel2_p), .OB(channel2_n) ); 35 | OBUFDS #(.IOSTANDARD("LVDS_33")) lvds_channel3_obuf (.I(c3), .O(channel3_p), .OB(channel3_n) ); 36 | OBUFDS #(.IOSTANDARD("LVDS_33")) lvds_clock_obuf (.I(lvdsclk), .O(clock_p), .OB(clock_n) ); 37 | 38 | 39 | lvds_clockgen clockgenerator ( 40 | .clk(DotClock), 41 | .clk35(clk35), 42 | .nclk35(notclk35), 43 | .rstclk(rst_clk), 44 | .dataclock(DataClock), 45 | .lvdsclk(lvdsclk) 46 | ); 47 | 48 | serializer channel1_ser ( 49 | .clk(DataClock), 50 | .clk35(clk35), 51 | .notclk35(notclk35), 52 | .data(VideoData[6:0]), 53 | .rst(rst_clk), 54 | .out(c1) 55 | ); 56 | 57 | serializer channel2_ser ( 58 | .clk(DataClock), 59 | .clk35(clk35), 60 | .notclk35(notclk35), 61 | .data(VideoData[13:7]), 62 | .rst(rst_clk), 63 | .out(c2) 64 | ); 65 | 66 | serializer channel3_ser ( 67 | .clk(DataClock), 68 | .clk35(clk35), 69 | .notclk35(notclk35), 70 | .data(VideoData[20:14]), 71 | .rst(rst_clk), 72 | .out(c3) 73 | ); 74 | 75 | assign VideoData[20:14] = {Blue[2],Blue[3],Blue[4],Blue[5],HSync,VSync,DataEnable}; 76 | assign VideoData[13:7] = {Green[1],Green[2],Green[3],Green[4],Green[5],Blue[0],Blue[1]}; 77 | assign VideoData[6:0] = {Red[0],Red[1],Red[2],Red[3],Red[4],Red[5],Green[0]}; 78 | 79 | 80 | endmodule 81 | -------------------------------------------------------------------------------- /src/serializer.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Company: 4 | // Engineer: 5 | // 6 | // Create Date: 19:14:43 07/04/2013 7 | // Design Name: 8 | // Module Name: serializer 9 | // Project Name: 10 | // Target Devices: 11 | // Tool versions: 12 | // Description: 13 | // 14 | // Dependencies: 15 | // 16 | // Revision: 17 | // Revision 0.01 - File Created 18 | // Additional Comments: 19 | // 20 | ////////////////////////////////////////////////////////////////////////////////// 21 | module serializer( 22 | input clk, 23 | input clk35, 24 | input notclk35, 25 | input [6:0] data, 26 | input rst, 27 | output out 28 | ); 29 | 30 | reg [6:0] buffer [1:0]; // 14 bits buffer 31 | reg [1:0] shiftdata = 0; 32 | 33 | reg datacount = 0; 34 | reg [2:0] outcount = 0; 35 | 36 | reg DataInBuffer = 0; 37 | reg SendOK = 0; 38 | 39 | ODDR2 #( 40 | .DDR_ALIGNMENT("NONE") // Sets output alignment to "NONE", "C0" or "C1" 41 | ) clock_forward_inst ( 42 | .Q(out), // 1-bit DDR output data 43 | .C0(clk35), // 1-bit clock input 44 | .C1(notclk35), // 1-bit clock input 45 | .CE(1'b1), // 1-bit clock enable input 46 | .D0(shiftdata[0]), // 1-bit data input (associated with C0) 47 | .D1(shiftdata[1]), // 1-bit data input (associated with C1) 48 | .R(1'b0), // 1-bit reset input 49 | .S(1'b0) // 1-bit set input 50 | ); 51 | 52 | always @(posedge clk or posedge rst) 53 | begin 54 | if(rst == 1'b1) 55 | begin 56 | buffer[0] <= 7'b0000000; 57 | buffer[1] <= 7'b0000000; 58 | datacount <= 0; 59 | DataInBuffer <= 0; 60 | end 61 | else 62 | begin 63 | DataInBuffer <= 1; 64 | datacount <= datacount + 1; 65 | buffer[datacount] <= data; 66 | //buffer[datacount] <= {data[6],data[5],data[4],data[3],data[2],data[1],data[0]}; 67 | end 68 | end 69 | 70 | always @(posedge clk35 or posedge rst) 71 | begin 72 | if(rst == 1'b1) 73 | begin 74 | outcount <= 0; 75 | shiftdata <= 0; 76 | SendOK <= 0; 77 | end 78 | else 79 | begin 80 | if(outcount == 6) 81 | outcount <= 0; 82 | else 83 | outcount <= outcount + 1; 84 | 85 | if(DataInBuffer && outcount == 6) 86 | SendOK <= 1; 87 | 88 | if(SendOK) 89 | begin 90 | case (outcount) 91 | 0: shiftdata <= { buffer[0][0], buffer[0][1] }; 92 | 1: shiftdata <= { buffer[0][2], buffer[0][3] }; 93 | 2: shiftdata <= { buffer[0][4], buffer[0][5] }; 94 | 3: shiftdata <= { buffer[0][6], buffer[1][0] }; 95 | 4: shiftdata <= { buffer[1][1], buffer[1][2] }; 96 | 5: shiftdata <= { buffer[1][3], buffer[1][4] }; 97 | 6: shiftdata <= { buffer[1][5], buffer[1][6] }; 98 | endcase 99 | end 100 | end 101 | end 102 | 103 | endmodule 104 | -------------------------------------------------------------------------------- /src/maincore.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Company: Teske Virtual System 4 | // Engineer: Lucas Teske 5 | // 6 | // Create Date: 20:23:28 07/04/2013 7 | // Design Name: Video LVDS Serializer 8 | // Module Name: maincore 9 | // GitHub: https://github.com/racerxdl/LVDS-7-to-1-Serializer 10 | ////////////////////////////////////////////////////////////////////////////////// 11 | 12 | module maincore( 13 | input clk, 14 | output channel1_p, 15 | output channel1_n, 16 | output channel2_p, 17 | output channel2_n, 18 | output channel3_p, 19 | output channel3_n, 20 | output clock_p, 21 | output clock_n 22 | ); 23 | 24 | /* 25 | parameter ScreenX = 1024; 26 | parameter ScreenY = 768; 27 | parameter BlankingVertical = 35; 28 | parameter BlankingHorizontal = 280; 29 | */ 30 | 31 | parameter ScreenX = 1280; 32 | parameter ScreenY = 800; 33 | parameter BlankingVertical = 12; 34 | parameter BlankingHorizontal = 192; 35 | 36 | wire clo,clk4x,clk_lckd, clkdcm; 37 | 38 | reg [5:0] Red = 0; 39 | reg [5:0] Blue = 0; 40 | reg [5:0] Green = 0; 41 | 42 | reg HSync = 1, VSync = 1, DataEnable = 0; 43 | 44 | 45 | reg [10:0] ContadorX = 0; // Contador de colunas 46 | reg [10:0] ContadorY = 0; // Contador de linhas 47 | 48 | reg [7:0] SendFrames = 0; 49 | 50 | DCM_SP #( 51 | .CLKIN_PERIOD ("62.5ns"), // 64MHz Clock from 16MHz Input 52 | .CLKFX_MULTIPLY (4), 53 | .CLKFX_DIVIDE (1) 54 | ) 55 | dcm_main ( 56 | .CLKIN (clk), 57 | .CLKFB (clo), 58 | .RST (1'b0), 59 | .CLK0 (clkdcm), 60 | .CLKFX (clk4x), 61 | .LOCKED (clk_lckd) 62 | ); 63 | 64 | BUFG clk_bufg (.I(clkdcm), .O(clo) ) ; 65 | 66 | video_lvds videoencoder ( 67 | .DotClock(clk4x), 68 | .HSync(HSync), 69 | .VSync(VSync), 70 | .DataEnable(DataEnable), 71 | .Red(Red), 72 | .Green(Green), 73 | .Blue(Blue), 74 | .channel1_p(channel1_p), 75 | .channel1_n(channel1_n), 76 | .channel2_p(channel2_p), 77 | .channel2_n(channel2_n), 78 | .channel3_p(channel3_p), 79 | .channel3_n(channel3_n), 80 | .clock_p(clock_p), 81 | .clock_n(clock_n) 82 | ); 83 | 84 | reg [5:0] Parallax = 0; 85 | 86 | //Cycle Generator 87 | always @(posedge clk4x) 88 | begin 89 | //Sync Generator 90 | ContadorX <= ContadorX + 1; 91 | 92 | if(ContadorX == ScreenX) 93 | begin 94 | DataEnable <= 0; 95 | HSync <= 0; 96 | end 97 | 98 | if((ContadorX == 0) & (ContadorY < ScreenY)) 99 | DataEnable <= 1; 100 | 101 | if(ContadorX == (ScreenX+BlankingHorizontal)) 102 | HSync <= 1; 103 | 104 | if(ContadorX == (ScreenX+BlankingHorizontal)) 105 | begin 106 | if(ContadorY == ScreenY) 107 | begin 108 | VSync <= 0; 109 | DataEnable <= 0; 110 | end 111 | 112 | if(ContadorY == (ScreenY+BlankingVertical)) 113 | begin 114 | VSync <= 1; 115 | Parallax <= Parallax - 1; 116 | ContadorY <= 0; 117 | ContadorX <= 0; 118 | end 119 | else 120 | ContadorY <= ContadorY +1; 121 | end 122 | 123 | if(ContadorX == (ScreenX+BlankingHorizontal)) 124 | ContadorX <= 0; 125 | end 126 | //Video Generator 127 | always @(posedge clk4x) 128 | begin 129 | if(ContadorX == ScreenX) 130 | begin 131 | Blue <= 0; 132 | Red <= 0; 133 | Green <= 0; 134 | end 135 | else 136 | begin 137 | //Center 640x400 - Screen 640x480 -> Box: 640-320,400-240,640+320,400+240 138 | 139 | if( (ContadorX > 320 && ContadorY > 160) && ( ContadorX < 960 && ContadorY < 640) ) 140 | begin 141 | // ScreenBox 142 | Blue <= 0; 143 | Red <= 0; 144 | Green <= 0; 145 | end 146 | // 3px border: (317,160),(317,640),(319,640),(319,160) 147 | // 3px border: (317,157),(960,157),(960,160),(317,160) 148 | else if ( (ContadorX >= 317 && ContadorY >= 160 && ContadorY <= 640 && ContadorX <= 320) || 149 | (ContadorX >= 317 && ContadorY >= 157 && ContadorY <= 160 && ContadorX <= 963) || 150 | (ContadorX >= 960 && ContadorY >= 157 && ContadorY <= 640 && ContadorX <= 963) || 151 | (ContadorX >= 317 && ContadorY >= 640 && ContadorY <= 643 && ContadorX <= 963) ) 152 | begin 153 | Red <= 255; 154 | Green <= 0; 155 | Blue <= 0; 156 | end 157 | else 158 | begin 159 | Red <= ( ( (ContadorY[5:0]+Parallax) ^ (ContadorX[5:0]+Parallax) ) * 2 ); 160 | Blue <= ( ( (ContadorY[5:0]+Parallax) ^ (ContadorX[5:0]+Parallax) ) * 3 ); 161 | Green <= ( ( (ContadorY[5:0]+Parallax) ^ (ContadorX[5:0]+Parallax) ) * 4 ); 162 | end 163 | end 164 | end 165 | endmodule 166 | --------------------------------------------------------------------------------