Software Half Duplex UART For AVRs

If you have worked with very low cost microcontroller in the past, such as the ATtiny series from AVR, you’ve probably been stuck without a UART peripheral. The usual answer to this problem is to implement the UART in software. It’s not fast, but it works.

Lets say you’re even more limited on resources, and only have a single pin for UART. [Ralph] created a software library and a small circuit that enables half duplex UART using only one pin. With the above circuit, and a 62 byte Arduino compatible library, you can add UART to the tiniest of ATtinys.

In this circuit, the Tx/Rx pin is on the AVR, and the Tx and Rx pins are another device. The circuit relies on the idle state of UART being a logic high signal. When the Tx pin is idle, the transistor stays on. This allows the Tx/Rx pin to pull Rx low when the AVR sends a 0. When the Tx pin sends a 0, the Tx/Rx pin gets pulled low through the diode.

It’s a clever hack, and could definitely help add communication to your next tiny project.

57 thoughts on “Software Half Duplex UART For AVRs

  1. Aww, that nice. But when we throw away crazy AVR crippled with Arduino we can use better controller like 8051 from Silabs –
    5V tolerant IO,
    low price,
    on-chip debug with real IDE,
    flexible pinout – runtime swapable – RX/TX trick, accurate integrated xtal…


        1. Tiny smt parts aren’t as easy for breadboarding/prototyping for many folks. Many people also don’t need the power of such a device. More often than not, you want the device to fit the need. You don’t want to go too far above that as it’s a waste of the device and it’s abilities.

      1. LPC810, Cortex M0 in a DIP-8 package. No discrete components needed, just stick 1.8-3.6v on VCC and connect the ground and voila. Yet to find a use for a 30MHz ARM core with only 6 GPIO though, 1kb SRAM and 4kb flash.

  2. Possibly needs any overvoltage protection: right now, if connected to a ±12V RS232 line, it’ll use the overvoltage clamps of the microcontroller.

    Regardless, needs current limiting in case of collisions.

    1. The description doesn’t say if the other side is for EIA232 signal level
      or logic level. It doesn’t seem to invert logic level, so I am incline
      to assume this is for chip to chip.

      The old MC68HC908 uses a half duplex software UART for bootstrapping. I
      used a 2 stages of inverters connected in series. I use a 1K series
      resistor on the uC side to protect again logic contention. It is
      connected to the middle of the inverter chain so that it can read the
      EIA232 Rx signal. When the pin is set to output, it override the signal
      level and drives the 2nd stage to “EIA232” (5V) level.

    2. For a TTL to TTL level half duplex solution, all you need is a 1K
      connected between the Tx and Rx. Your uC is connected directly to the Rx
      pin. When the uC set its pin to output, it overrides the signal level
      coming from the 1K.

      1. The problem with that the Tx transmissions loop back to the Rx, and so will corrupt communications unless you change the software on the other side to ignore the loopback echo. My solution will work with unmodified bootloader downloads, etc.

    1. I wrote a UART using USI as well, but it used more code. The USI transmits the high bit first, so bit reversal code is needed. The only way I could get the code size within a few bytes of my bitbang serial was with 71N communication instead of 81N.

  3. The thing about this is that it is not worth in a real application. You are better off upgrading to a better micro and. Even if you don’t have enough pins it is better to implement it some other way in software, like 1 wire or even something simpler.

    1. I disagree Bogdan. I use ATTiny’s all the time when I only need a couple of IO pins. Having a UART is wildly useful during the development process (at least I love it). I can’t wait to try this on my next project. :D

      1. @Torque
        1. I challenge you to achieve the same functionality with only one resistor (that’s 3X less components for the additional functionality)
        2. If this were a commercial application, it will probably cost you more to add the three components than to upgrade the micro.
        3. If it is a hobby thing and space if of no concern, there is no justification for buying a 1 $/EUR tiny micro instead of one @2-3 much better and spending time worrying about all the pins and resources you don’t have and how to get around that.

        1. 1: implement in software, use as debug only, 1 test point is added, cheaper then 1 a resistor
          2: it would be able to be on a commercial product, allowing for debug, and concealing it for security.
          3: using a small micro, and exposing 1 test pad makes your device smaller. Maybe i want my package to be <1 square cm and have a bunch of sensors. I could use the single wire in the test fixture, and still have most of the pins open for sensors.

        2. #1, see my previous post.
          #2. Not always true. Parts volume can skew the result a bit. If there
          are other projects that uses jellbean components or that particular
          smaller uC, they would lower the price a lot. There are a lot of
          incensitives to use the common components. Also you buy BJT, diodes,
          resistors in Tape & Rells of 5K vs much lower volumes for uC.

        3. You can make bullet points all you like, unless you come up with something that negates the fact that you have indeed berated something inspired by the hacker mentality, as Torque so eloquently put it, you will remain the odd one out.
          I’m fairly sure that a good hack does not require to be cheaper or easier than any commercial alternative.

        4. Also, It does not necessarily mean that those three components need to be on each micro (if it were to be mass produced as a commercial product), since those components can be attached in-line with the UART cable/reader/whatever.

        1. Because avrdude is what the Arduino IDE uses, and what is part of avr-binutils.
          Part of the reason I wrote the soft serial code is I’m writing a small bootloader called picoboot, and one of the versions of it will use the stk500 protocol like the arduino bootloader and optiboot. However mine should come in under 256 bytes, or about half the size of optiboot. Use of the 1-wire mode will require no changes to avrdude, and it will not require writing a custom loader program.

          I agree that if you are already writing the code for what the AVR communicates with then it is easier to deal with the loopback echo in software.

          1. I could submit a patch for avrdude, but the effect is the same as requiring a custom loader program. Until the updated version of avrdude would get included in distributions like the Arduino IDE, there’s not much difference between installing a custom loader program and installing a new version of avrdude.

  4. Love it! Just outta curiosity what would be the benefits of using this over, say, a single 8-pin AVR running off its internal oscillator? More convenient trace routing is an obvious one, and I’m guessing power consumption might be another (yes? no?)…any others? Either way, great hack!

    1. Internal oscillators are known to limit the data rate of anything that relies on accurate timing, such as serial comms. It’s OK for hobby projects, if you’re lucky you’ll get 38400 bd; if you’re unlucky you’ll have problems above 2400 bd.

          1. Hi. Could you provide some background on your testing? The problems I’ve encountered is that a change in temperature (e.g. after running for a while in an enclosure) changes your error %. So I always end up reducing the rate to get back in the safe zone.

            Very handy site you posted!

          2. When running off the internal RC oscillator you will get some frequency changes with temperature (for the ATTiny85 see Figure 22-41 in the datasheet) I put comments in the code regarding the timing accuracy:
            “2%/1% Tx/Rx timing error for 230.4kbps@8Mhz”
            Any timing outside of 5% is likely to cause a framing error (by 10 bits you’re off 1/2 a bit), so the sum of the RC oscillator variation and timing error should never get near 5% if you want to avoid errors.
            The code using 19.2kbps@8Mhz has 0.3% timing on transmit and 0.2% timing on receive, so that will give you the best results when running on the RC oscillator.

Leave a Reply

Please be kind and respectful to help make the comments section excellent. (Comment Policy)

This site uses Akismet to reduce spam. Learn how your comment data is processed.