9
\$\begingroup\$

I'd like to interface my main microcontroller's hardware serial port to more than one device at the same time. My understanding is that UART on my microcontrollers is based on an active-low 5V TTL.

(I know what I'm explaining here can be technically achieved by using more suited protocols, such as SPI and I2C, but my project requires to be only implemented using UART.)

Here's a pseudo-schematics chart of what I'm trying to achieve:

schematic

simulate this circuit – Schematic created using CircuitLab

Please note that:

  1. I don't want to use a second UART interface on the master, or any of the slaves.

  2. Only one slave at a time is going to transmit or send data on the line to the master. (e.g. If the slave 1 is transmitting data, slave 2 and 3 should remain idle.)

  3. Whatever the master is transmitting can, and should be received by all of the slaves.

  4. All of the slaves should be hot-pluggable, meaning they could be removed or inserted at any time.

  5. The RX and TX wires to the master are parallel between each slave, so no daisy chaining.

So, my questions are as follows:

  1. Assuming the correct impedance is considered, I shouldn't need an additional circuit to transmit data from the master's TX line to any of the slave's RX line simultaneously. Is this correct?

  2. I understand that without current limiting resistors between slaves' TX line and the master's RX line, if any of the devices begin to broadcast data, the line between the devices will short circuit and I risk damaging them. Is this correct?

  3. Assuming the items 1 and 2 are correct:

    a) Would just some current limiting resistors be enough to use?

    b) Can I use 74-series logic gates instead of resistors?

  4. Between options a and b above, what route should I choose?

  5. For a reliable 115200 baud rate connection, will the switching frequency of a 74HC08 AND gate suffice to be incorporated?

EDIT: I'm well aware of other well-suited protocols such as SPI and I2C. There's a reason I'm using UART, and that's because the optiboot bootloader that is used on the master's mcu communicates over UART, albeit UART's obvious limitations.

Also, while daisy-chaining is definitely a clever approach, due to breaking the 4th requirement, it also breaks bootloader functionality.

The devices could also be USB-to-Serial chips, and using SPI-to-USB or I2C-to-USB would not be feasible in this project.

So, I'd appreciate if you could focus on the 6 questions listed here instead, and share your UART knowledge.

\$\endgroup\$
6
  • 3
    \$\begingroup\$ Just for 5, I dont imagine you'll have to worry about the 100ns propagation delay of that and gate \$\endgroup\$
    – BeB00
    Commented Apr 23, 2018 at 2:01
  • 1
    \$\begingroup\$ How do you ensure that no two devices are transmitting at the same time? \$\endgroup\$
    – JimmyB
    Commented Apr 24, 2018 at 11:30
  • 1
    \$\begingroup\$ @JimmyB Simple, the devices only respond on master's request, and the master ensures the previous transmission has ended before requesting a new one. Also, each client can now wether the line is busy or not, by probing the master's RX wire, and comparing it to LOW. \$\endgroup\$ Commented Apr 24, 2018 at 12:18
  • \$\begingroup\$ UART or RS-232? The best solution if RS-232 is available, is to implement CTS/RTS lines and use those for chip select purposes. Kind of like /SS in SPI if you will. And then you don't need any icky gates on the data lines. \$\endgroup\$
    – Lundin
    Commented Apr 24, 2018 at 12:53
  • 1
    \$\begingroup\$ Anyway, if you do end up switching the data lines, you probably don't want to use an AND gate but instead some analog switch/mux. \$\endgroup\$
    – Lundin
    Commented Apr 24, 2018 at 12:57

6 Answers 6

8
\$\begingroup\$
  1. For three devices no, for more, check the datasheet with regards to input capacitance.

  2. Not quite dangerous but certainly it won't work

  3. a) No b) yes. With few slaves it would be better with wired AND ( half connections needed) if your slaves are not on the same board.

  4. Obviously, the working one, b

  5. Yes

    Edited to give some details

2 and 3a , even if you ignore "don't connect two outputs together" recommendation everyone agrees, the result of two ones and a zero will never be zero for cmos outputs with almost symmetrical characteristics.

3b You either have a wire from each slave to a N-input (star-like configuration) or at each slave you have an AND from it's output and the chain and use the And output for the next slave chain input.

schematic

simulate this circuit – Schematic created using CircuitLab

Obviously the chain configuration is not hot-plug.

Wired AND, you have two options depending on the slave capabilities.

If you have open drain/collector outputs for TX then you can connect them together and add a global pull-up resistor.

If not then a diode on each slave will act as a wired and as follows:

schematic

simulate this circuit

You also have a third option, simply to put the slave Tx output to HiZ after answering to a message, a pull up resistor is still needed.

\$\endgroup\$
3
  • \$\begingroup\$ This is the kind of answer I was hoping to get, so thank you! Wish you could elaborate on 2 and 3. Also, could diodes be used to form an AND gate? \$\endgroup\$ Commented Apr 23, 2018 at 11:14
  • \$\begingroup\$ @DRSDavidSoft Yes, this is a wired AND \$\endgroup\$
    – Dorian
    Commented Apr 24, 2018 at 6:17
  • 1
    \$\begingroup\$ Your second solution with a couple of BAT54C array shotkey diodes seems the way to go, and as such I mark your answer as the accepted one. Thanks for the explanations! \$\endgroup\$ Commented Apr 24, 2018 at 19:45
5
\$\begingroup\$

Are you married to UART? SPI would handle this better I think. The slave select would give you the multiplexing and you could prioritize one slave more than the other based on whatever the master is doing or expecting from the slaves. Speed should be at least as fast if not faster than UART. This example gets at the idea.

\$\endgroup\$
2
  • \$\begingroup\$ SPI is coincidentally my favorite protocol, the main issue is that my project requires UART; as I'm not the one married to UART, rather Arduino's bootloader is :) \$\endgroup\$ Commented Apr 23, 2018 at 11:04
  • 1
    \$\begingroup\$ SPI does not fit well into "Whatever the Arduino is transmitting can, and will be received by all 3 devices". Also, if there was some kind of slave select mechanism (line) available it would just as well work for the USART transmission and solve the problem. \$\endgroup\$
    – JimmyB
    Commented Apr 24, 2018 at 11:29
2
\$\begingroup\$

You have to ensure they don't transmit at the same time. For example by the master polling the slaves.

Use diodes to connect multiple TXD together, pull up R at master. You can just use firmware if you want, and turn the TXD to input when not transmitting also, but diodes are easier.

All RXD can just be connected.

\$\endgroup\$
7
  • \$\begingroup\$ I don't plan to transmit from more than one device at the same time, but other than Arduino possibly receiving a corrupted data sequence, would it damage my chips? \$\endgroup\$ Commented Apr 23, 2018 at 11:08
  • \$\begingroup\$ Also, does using diodes count as implementing a negative AND gate? \$\endgroup\$ Commented Apr 23, 2018 at 11:08
  • \$\begingroup\$ The function is logical OR of negative (0) values. It is nornmally called "wired OR". It is of course electrically same as using AND gate \$\endgroup\$
    – Henry Crun
    Commented Apr 23, 2018 at 22:59
  • 1
    \$\begingroup\$ You must only transmit from one at a time, otherwise data is corrupted. No other issue. My point being, you must have a way of ensuring it does not happen. Like asking each one for data in turn (polling) \$\endgroup\$
    – Henry Crun
    Commented Apr 23, 2018 at 23:00
  • 2
    \$\begingroup\$ A tip: put jumpers in the TX lines, so you can disconnect them. It can make debugging much easier when it goes wrong, or one fails \$\endgroup\$
    – Henry Crun
    Commented Apr 24, 2018 at 22:38
2
\$\begingroup\$

For the line which is driven by the master and received by the slaves, nothing particularly fancy should be required if capacitive loading isn't a problem.

For the line which is driven by slaves, I would suggest that if capacitive loading wouldn't be a problem, you have connect each slave's TX line to the bus through a series resistor, and then set each state's TX pin to float when idle. Make the resistance as low as it can be without allowing an unacceptable or damaging level of current to flow in case of bus conflict.

If the required series resistance to prevent damage, combined with the parasitic capacitance, would limit speeds to be unacceptably slow, then I would suggest using a current-based approach where the slaves source current if they want to transmit. Something like:

schematic

simulate this circuit – Schematic created using CircuitLab

The left half is the transmitter, and the right half is the receiver. Note that if the Schottky diode is omitted (or if a non-Schottky diode is substituted) the receiver circuit will not operate nearly as well, since Q2 will be driven into saturation and will take awhile to come out of it. Adding the Schottky diode will prevent Q2 from turning on fully, thus allowing it to turn off faster.

\$\endgroup\$
1
\$\begingroup\$

As a practical suggestion, take a look at I2C: it uses the same number of wires as a UART, has similar data rate and implements the bus functionality you need, plus you'll have SW libraries already written for you.

Another protocol which is even more similar to what you're trying to do is LIN, which is basically a UART-based bus with higher signal voltage. If you have 12V available, you could simply plug LIN transceivers in your diagram between each node and the bus, and it would work. You'd have to write your own software though.

Edit: you can also implement pseudo-LIN with your own voltage levels, e.g. 5V. For example:

schematic

simulate this circuit – Schematic created using CircuitLab

\$\endgroup\$
4
  • \$\begingroup\$ Thanks for the suggestion, however using UART is not a matter of wires count limitation, but rather a constraint of the project requirement (see EDIT). Though LIN seems promising, unfortunately I won't be able to interface it with 12V, but I'd like to implement the same functionality with 5V TTL level. \$\endgroup\$ Commented Apr 23, 2018 at 11:11
  • \$\begingroup\$ @DRSDavidSoft Hi, I've edited my answer to add an example of a serial-to-bus with arbitrary voltage levels (e.g. 5V) \$\endgroup\$ Commented Apr 23, 2018 at 13:23
  • \$\begingroup\$ Is the bus actually a single wire? This LIN protocol seems very promising for some of my other projects, it could enable me to send and receive both data and power using only two wires. Thanks for introducing it to me! \$\endgroup\$ Commented Apr 24, 2018 at 19:41
  • \$\begingroup\$ @DRSDavidSoft You need common ground of course, so it will be 3 wires in total. Nevertheless, LIN is a good option for low data rates (20 kB/s or so). You can get higher data rates with your own transceivers (e.g. what my schematic shows), but you will lose the low EM emission property of LIN. \$\endgroup\$ Commented Apr 25, 2018 at 7:20
1
\$\begingroup\$

If you want to stick to one UART port you can simply daisy chain them (output of one UART go to input of another one). With this approach you don't need any extra hardware, but you need to add code to forward communication from one Arduino to next one.

EDIT I missed hot-swappable requirement so this couldn't work. But if you can guarantee that you wont swap in middle of communication or you can tolerate loss of some packets then you can just short place where you put one of Arduino's UART interface and after swap you remove short for normal operation.

\$\endgroup\$
3
  • \$\begingroup\$ So you want to transform UART to SPI? Because that's how daisy chained SPI works. \$\endgroup\$ Commented Apr 23, 2018 at 10:15
  • \$\begingroup\$ That's a clever way to handle it, but unfortunately it breaks the requested notes, and certainly won't work with rule 4 (see question). Still a smart and simple way to do it! \$\endgroup\$ Commented Apr 23, 2018 at 11:12
  • \$\begingroup\$ The workaround is also an interesting way to make this work, I'm sure I can use your method in some of my new projects. Thanks! \$\endgroup\$ Commented Apr 24, 2018 at 12:24

Not the answer you're looking for? Browse other questions tagged or ask your own question.