Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Bidirectional LVDS at Altera Cyclone III

Status
Not open for further replies.

Saires

Newbie level 5
Joined
Jun 25, 2015
Messages
8
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
51
Hi, everyone.

Does there exist any correct example of implementing bidirectional LVDS on verilog for Altera Cyclone III? Regretfully, I didn't find any at the altera website. Regretfully, I didn't find any at the altera website.
I will be quite pleased for a piece of code.
 

In most cases these things have to be custom built, Altera Megafunactions (ALTLVDS_RX and ALTLVDS_TX) can be used to realize what you want. Quartus will generate the VHDL code from the block diagram you construct using these Megafuctions. HTH.
 

In most cases these things have to be custom built, Altera Megafunactions (ALTLVDS_RX and ALTLVDS_TX) can be used to realize what you want. Quartus will generate the VHDL code from the block diagram you construct using these Megafuctions. HTH.

Is tried to use ALT_IOBUF_DIFF for that purpose, but the following Altera's example code

Code:
module test(in1,in2,oe,out,bidir,bidir_n);

    input in1;

    input in2;

    input oe;

    inout bidir;

    inout bidir_n;

    output out;

    wire tmp1;

 

    and(tmp1,in1,in2);

 

    ALT_IOBUF_DIFF inst(

                                .i(tmp1),

                                .oe(oe),

                                .o(out),

                                .io(bidir),

                                .iobar(bidir_n)

                            );

 

    defparam inst.io_standard = "LVDS";
    

    defparam inst.current_strength = "12mA";

endmodule

replies me with

Error: Current Strength logic option is set to 12mA for pin bidir, but setting is not supported by I/O standard LVDS
 

In most cases these things have to be custom built, Altera Megafunactions (ALTLVDS_RX and ALTLVDS_TX) can be used to realize what you want. Quartus will generate the VHDL code from the block diagram you construct using these Megafuctions. HTH.

And do you have some code that demonstrates this functionality?
 

the error has something to do with settings in Quartus. Pasting code here would not help, I am attaching a pdf which basically uses the altlvdsrx to get data from an ADC with the help of an external pll, the serial data is fed into a custom block (gtzl) where the data is manipulated and churned into two 36 bit outputs.

View attachment altlvdsrx_expll.pdf
 
  • Like
Reactions: Saires

    Saires

    Points: 2
    Helpful Answer Positive Rating
You don't need to use low level primitives to implement BLVDS. For Cyclone III, it's sufficient to assign the BLVDS IO standard for the respective inout pin and connect the inout signal as you d with other biderectional signals. With other devices like Cyclone V that don't provide a BLVDS standard, you'll use Differential SSTL instead.

The quoted fitter error is caused by assigning an unsupported current strength, it's normally sufficient to use the default current strength for the respective IO-standard, otherwise review the device manual.
 

Problem with bidirectional BLVDS

While developing the folowing design in Verilog for Cyclone III

Code:
module Bi_dir_bus (data_to_from_bus, send_data, rcv_data); 
inout [15: 0] data_to_from_bus; 
input 		  send_data, rcv_data;
wire [15: 0]  ckt_to_bus;
wire [15: 0]  data_to_trom_bus, data_from_bus;


assign data_from_bus = (rcv_data) ? data_to_from_bus : 16'bz; 
assign data_to_from_bus = (send_data) ? ckt_to_bus : data_to_trom_bus; 


endmodule

receive the error

Error: Bidirectional pin data_to_from_bus[0] with a pseudo-differential I/O standard must use the output enable control signal on the output buffer

when I try to use BLVDS I/O standart for "data_to_from_bus".

What is the way to solve that problem?
 
Last edited by a moderator:

Seems like Quartus needs explicite low level primitives or special hints to configure the BLVDS standard. I'll check if there's a different way, for the time being I suggest to use the AN522 method.
 

Re: Problem with bidirectional BLVDS

While developing the folowing design in Verilog for Cyclone III

Code:
module Bi_dir_bus (data_to_from_bus, send_data, rcv_data); 
inout [15: 0] data_to_from_bus; 
input 		  send_data, rcv_data;
wire [15: 0]  ckt_to_bus;
wire [15: 0]  data_to_trom_bus, data_from_bus;


assign data_from_bus = (rcv_data) ? data_to_from_bus : 16'bz; 
assign data_to_from_bus = (send_data) ? ckt_to_bus : data_to_trom_bus; 


endmodule

receive the error



when I try to use BLVDS I/O standart for "data_to_from_bus".

What is the way to solve that problem?

why is this assignment being used for data_to_from_bus?
Code:
assign data_to_from_bus = (send_data) ? ckt_to_bus : data_to_trom_bus;
that isn't a inout type assignment, there is nothing controlling any kind of output enable to output a hi-Z state when used as an input.
I think you screwed up which assignment is which. This is a classic case of poorly named signals allowing you to mess up simple stuff like which single connects to what.


This is the typical way you would infer a bi-directional I/O.
Code:
...
inout  bidir_pin,
...
wire direction;
wire signal_out;
wire signal_in;

// using bidir_pin as an output.
assign bidir_pin = direction ? signal_out : 1'bz;

// using the bidir_pin as an input.
assign signal_in = bidir_pin;
 

Re: Problem with bidirectional BLVDS

However there still appeares error

Code:
Error: Bidirectional pin bidir_pin with a pseudo-differential I/O standard must use the output enable control signal on the output buffer

after compiling your part of code and assigning "BLVDS" to
Code:
bidir_pin
.
 

See below a BLVDS port implemented according to AN522. I copied the low level primitives from the Megafuncton generated code to the design. The pseudo_diff_out primitive is used to assure that the signal inversion takes place in the output buffer and isn't necessarily required.


Code VHDL - [expand]
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
library ieee;
use ieee.std_logic_1164.all;
 
LIBRARY cycloneiii;
USE cycloneiii.all;
 
entity blvds_test2 is
 
    port 
    (
        b      : inout std_logic;
        b_bar : inout std_logic;
        bi     : in std_logic;
        be     : in std_logic;
        bo     : out std_logic
    );
 
end entity;
 
architecture rtl of blvds_test2 is
     COMPONENT  cycloneiii_io_ibuf
     GENERIC 
     (
        bus_hold    :   STRING := "false";
        differential_mode   :   STRING := "false";
        simulate_z_as   :   STRING := "Z";
        lpm_type    :   STRING := "cycloneiii_io_ibuf"
     );
     PORT
     ( 
        i   :   IN STD_LOGIC := '0';
        ibar    :   IN STD_LOGIC := '0';
        o   :   OUT STD_LOGIC
     ); 
     END COMPONENT;
     COMPONENT  cycloneiii_io_obuf
     GENERIC 
     (
        bus_hold    :   STRING := "false";
        open_drain_output   :   STRING := "false";
        lpm_type    :   STRING := "cycloneiii_io_obuf"
     );
     PORT
     ( 
        i   :   IN STD_LOGIC := '0';
        o   :   OUT STD_LOGIC;
        obar    :   OUT STD_LOGIC;
        oe  :   IN STD_LOGIC := '1';
        seriesterminationcontrol    :   IN STD_LOGIC_VECTOR(15 DOWNTO 0) := (OTHERS => '0')
     ); 
     END COMPONENT;
     COMPONENT  cycloneiii_pseudo_diff_out
     PORT
     ( 
        i   :   IN STD_LOGIC := '0';
        o   :   OUT STD_LOGIC;
        obar    :   OUT STD_LOGIC
     ); 
     END COMPONENT;
 
     signal b_wire      :   std_logic;
     signal b_bar_wire  :   std_logic;
begin
 
    ibufa :  cycloneiii_io_ibuf
      GENERIC MAP (
        bus_hold => "false",
        differential_mode => "true"
      )
      PORT MAP ( 
        i => b,
        ibar => b_bar,
        o => bo
      );
    obuf_ba :  cycloneiii_io_obuf
      GENERIC MAP (
        bus_hold => "false",
        open_drain_output => "false"
      )
      PORT MAP ( 
        i => b_bar_wire,
        o => b_bar,
        oe => be
      );
    obufa :  cycloneiii_io_obuf
      GENERIC MAP (
        bus_hold => "false",
        open_drain_output => "false"
      )
      PORT MAP ( 
        i => b_wire,
        o => b,
        oe => be
      );
    pseudo_diffa :  cycloneiii_pseudo_diff_out
      PORT MAP ( 
        i => bi,
        o => b_wire,
        obar => b_bar_wire
      );
end rtl;

 

While debuging the project I found out that the code
Code:
module starter_3 (led_5, led_6, clk_2  /*25 MHz*/, 
                                    out, out_n);


reg trans, trans_n;
output out, out_n;

reg  T_5;
reg [25:0] COUNT_clk_2;
output reg    led_5, led_6; 
input wire clk_2;
					

					
					
ALT_OUTBUF_DIFF inst1( 
						.i(T_5), //indicates with led_5
						
						.o(out), 
						
						.obar(out_n)
					);
					

defparam inst1.io_standard = "LVDS";

defparam inst1.weak_pull_up_resistor = "off";

defparam inst1.enable_bus_hold = "off"; 

					
ALT_INBUF_DIFF inst2(
						.i(trans),
						
						.ibar(trans_n),
						
						.o(inp_dif_2)  // indicates with led_6
					);
 
defparam inst2.io_standard = "LVDS";

defparam inst2.weak_pull_up_resistor = "off";

defparam inst2.enable_bus_hold = "off"; 


initial
	begin
	
	T_5<=0;
	COUNT_clk_2<=0;
	
	end
	
always @(posedge clk_2)
		begin
				COUNT_clk_2<=(COUNT_clk_2+1'b1);
				
				if (COUNT_clk_2[25]==1)
					begin
							COUNT_clk_2<=0;
							T_5<=!T_5;
					end		
					
		end
		
			
always @(inp_dif_2)
			begin
					led_6<=!led_6;
			end		
			
				
always @(negedge T_5)
		        begin
				
				         led_5<=!led_5;
				
		        end
		
					
always @(out)
			begin
					trans<=out;
					trans_n<=out_n;	
			end
endmodule

where out, out_n are BLVDS
is not working as planned.
Particularly oscilloscope shows a clock signal as LVDS at output pins of out, out_n, but neither inp_dif_2, nor led_6 didn't not change.
Maybe somebody could give a good advice about this problem?:grin:
 

Logic generated clocks, bad, bad, bad. It's a big no, no in FPGA designs.
a) clock buffers tend to have limited access.
b) writing the correct constraints for the design becomes more complex and difficult.
c) PAR tools have a much more difficult time closing timing and tend to take a lot longer to run.
d) clock insertion delay is uncompensated and can vary from build to build, and is highly dependent on placement.
e) other reasons that are rooted in the above a-d.

Generate a clock enable and use clk_2 everywhere and only enable registers, with a reduced frequency enable pulse, when you need to.

The only benefit is the reduced clock tree power consumption, but that is usually only a small fraction of the overall power consumption in an FPGA and is usually dwarfed by the leakage current.

Also you are not using always @(*) but are using always @(dout), which is missing the dout_n. This is why you should always use @* or @(*) so you don't miss an input.

You should probably learn to not use defparam, they added redefining parameters to the module instance along with the C like module port naming back in 2001. In the past 14 years every tool vendor has at least added in Verilog 2001 support.

Code Verilog - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// so this....
ALT_OUTBUF_DIFF inst1( 
            .i(T_5), //indicates with led_5
            .o(out), 
            .obar(out_n)
          );
          
defparam inst1.io_standard = "LVDS";
defparam inst1.weak_pull_up_resistor = "off";
defparam inst1.enable_bus_hold = "off"; 
 
// becomes this...
ALT_OUTBUF_DIFF #(
  .io_standard            ("LVDS"),
  .weak_pull_up_resistor  ("off"),
  .enable_bus_hold        ("off")
) inst1 ( 
  .i    (T_5), //indicates with led_5
  .o    (out), 
  .obar (out_n)
);



- - - Updated - - -

BTW the defacto standard isn't called Bidirectional LVDS, it's actually **broken link removed** and was developed by National Semiconductor, which is now part of TI.

The link points to the current 4th edition of the LVDS designers guide (Owner's Manual).
 

ads-ee
First of all I use CYC3 DevBoard, so clk_2 is a Pletronics's crystal oscillator, and is not a logically generated clock.
The reason for using counter in the design is to ease debugging.
And of course, no matter that I am a newbie to FPGA design, I know what is BLVDS. If you read the previous messages in the thread you may find out that I was advised to use Bus LVDS in pin assignment for my purposes of implementing bidirectional modules.

Secondary,
Also you are not using always @(*) but are using always @(dout)
-- was experimentally checked if always @(*) works more properly than always @(out), with a negative result. Moreover, I don't catch a thing, why I should add sensitivity of changing out_n in always if out_n and out are changing simultaneously?
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top