Electronic – arduino – Single wire two-way serial communication – hardware configuration

arduinohardwareserialuart

I have several servos that can give feedback data that I want to read. The servos use special protocol so I need to use Rx/Tx pin on my Arduino Mega to communicate with them. The problem is that a servo has only one serial communication pin so I cannot use the usual Rx/Tx wiring.

I have heard that there are some hardware configurations to properly convert UART signals to half duplex type. One is to use 2 resistors connected to Rx and Tx of Arduino and the pin of the servo. Another is to use a transistor. However, I could not find exact circuit drawings and rules to choose the values for the resistors or the transistor. Can somebody provide more information on that and explain in terms of hardware exactly how these configurations prevent the Tx writing to the Rx and the servo feedback writing to the Tx.

EDIT: The servo is Dynamixel XL-320 (http://support.robotis.com/en/product/dynamixel/xl-320/xl-320.htm). The communication is half-duplex serial: I can write to the servo, but I can also read values, e.g. load (therefore I need to use both Rx and Tx pins on my arduino). NOTE: the servo manual proposes using a multiplexer and a digital pin on the arduino as a select bit in order to covert uart to half-duplex. However, I am specifically asking for other, more passive alternatives.

Best Answer

You say you want to use an Arduino Mega, which has an ATmega1280 MCU.

On ATmega1280 (and ATmega in general, mostly) UART Tx/Rx units override normal port operation. So once the Tx unit is on, you cannot set the Tx pin to Hi-Z (tri-state) unless you deactivate the Tx unit first.

Timing shouldn't be that critical, because the baud rates are 1Mbps max, while the ATmega1280 runs at 16 MHz assuming CKDIV8 is not programmed.

So in theory you should have time to switch. However, if their equivalent circuit is any indication, they actually do drive the Tx line, so you might produce a short when things go wrong, i.e. either your code takes too long to disable the Tx unit or you write while the Dynamixel responds.

It's actually not clear if the dynamixel actually drives the Tx line or if they don't (the circuit picture says CM-5, which is a master controller, not a slave).

I suggest you don't muck around with disabling/enabling the Tx unit in the ATmega1280, because you have to code more and possibly account for interrupts. Instead, put a resistor between Tx and Rx lines, like so:

schematic

simulate this circuit – Schematic created using CircuitLab

A) Assuming the Dynamixels have an internal pull-up resistor Rpu = 10kΩ, and assuming maximum input Voltage for a logic '0' Vil_max = 0.8V (just to be sure), we need the following resistor value Rx to reliably drive a '0': Ohm's Law

   5V * Rx / (Rx + 10kΩ) <= 0.8V
->                    Rx <= 1.9kΩ

B) Assuming the Dynamixels do not have an internal pull-up, just use Rx = 10kΩ..100kΩ. Your Tx unit will drive a '1' on bus idle, which will conveniently pull the bus up to 5V when your state machine logic expects the Dynamixel to answer.

In any case, the resistor will prevent shorts in case the Dynamixel and your controller drive at the same time. It will also act as a pull-up for your own Rx unit, so you won't get spurious data input when the Dynamixel isn't connected.

I suggest you use a multimeter to determine which of the two cases your application falls in. When in doubt, start with 1.8kΩ, see that your code works. Then move on to 100kΩ. If your code fails, you can be sure they use an internal Rpu, so stay 1.8kΩ. If everything works with 100kΩ, then, well... it works.