# Correctly Interfacing to a Bidirectional Signal

Background

I'm designing an interface in VHDL that connects to a bidirectional signal. However my experience in the dynamics of Hardware Design is limited. What I have at the moment is below:

Within the Red box is what's on the FPGA, outside of that are electrical components.

The RX module looks for a LOW signal for a start bit. To avoid interference between the TX module and the RX module: I placed a Mux controlled by the TX module to pass HIGH whenever it is transmitting.

The external circuitry ensures my TX never drives the line HIGH so to avoid shorts.

The Problem

When the RX and TX modules are separate, they function perfectly. The RX receives and reads the signal properly and the TX transmits (not into the bidirectional line; instead: my oscilloscope) perfectly. However, closing the switch to combine the two is a catastrophe. The RX Module just seems to become non responsive.

The Question

I'm not sure if this is an overall design problem, or something small and stupid with my VHDL.

So is this an acceptable method in interfacing to a bidirectional signal? I have the feeling there is something very wrong in my setup. I'm just looking for suggestions, criticisms, or overall ideas.

If this is indeed an alright setup, then at least I can have confidence in investigating the VHDL for the issue myself, and knowing that my efforts will not be in vain due to an inherently faulty overall design.

Googling: "Interfacing to a bidirectional bus" seems to suggest Tri-State buffers. Is this a better approach?

Extra

I feel obnoxious bugging you guys constantly due to lack in a conceptually understanding, so if I could get a suggestion on books or various research sources for conceptually designing hardware, then that would be fantastic.

• MCU datasheets usually have an equivalent schematic of their I/O pins. I find, in general, that they (MCU datasheets) are a great resource to discover how various interface bits are put together. Sep 3 '13 at 21:14
• Tri-state buffers would be a normal solution, at least for medium performance applications. But if you want to go with your external mux, use the scope to examine what is on the RX pin when you are connected, but in receive mode with something else transmitting - does the signal get to the RX pin or not? Sep 3 '13 at 21:14
• What FPGA family are you using? Internal debugging tools (e.g., Xilinx ChipScope, Altera SignalTap) can be very valuable tools in this sort of situation. If that isn't an option, do you have spare pins to which you can bring out key internal signals? Sep 3 '13 at 22:04
• @ChrisStratton I could break out that signal to a pin and measure it with the scope. This would effectively test whether or not my mux method is functional. Sep 3 '13 at 22:22
• @DaveTweed The FPGA is a Spartan 3A, I will have to investigate these tools you mention. Also I have plenty of spare pins! I've been breaking out some signals but I haven't delved too deep. Thanks! Sep 3 '13 at 22:25

Tristate is what you want. Or, as you have an external pull-up resistor, an open-drain drive. You'll also see open-collector meaning the same thing - it depends on the style of transistors used, but the fundamental idea is the same. ISO9141 (automotive diagnostics) operates this way for example.

Open-drain just means that the driver pin can only pull the external signal low, but cannot drive it high - the resistor will allow the line to "float" gently back up. It also means multiple devices can drive the communication line, so you have to ensure (eg. through higher level protocol or a sidechannel) that only one device chats at a time.

To implement this in VHDL:

In your entity you need a pin:

TxRx_pin : inout std_logic;


and in the architecture two signals:

signal tx_sig, rx_sig : std_logic;


Wire them up like this:

TxRx_pin <= '0' when tx_sig = '0' else 'Z';
rx_sig <= to_X01(TxRx_pin);


The first line copies 0s from the transmitter onto the pin, but doesn't drive 1s, instead using the Z state which means "disconnected", allowing the external resistor to pull the line up.

The second line ensures that whatever appears on the pin is copied onto rx_sig. The reason for the to_X01 call is to make the simulations work. In your testbench, the pullup resistor is modelled by driving an H (a so-called weak pullup) onto the TxRx signal:

TxRx_sig <= 'H';


Your FPGA logic will not be looking for Hs (in simulation) so will not work correctly - the to_X01 function converts H to 1 (amongst other things not relevant to this situation).

BTW, there is no need for a mux to turn off the reception in order to have a functional design, but you may want to keep it so you don't see the data you are transmitting.