Electronic – Detecting start bit in software UART


I'm experimenting with writing a software UART on my microcontroller using GPIO pins. This is to temporarily add a UART channel on a project until we get the new design implemented that uses a uC with more UART ports.

What I'm having difficulty with is correctly detecting a start bit in a serial stream. The source of the stream is external and doesn't care when my device powers up. So it's very likely that my device will power on and start seeing data bits in the middle of a byte transmission. Undoubtedly, that will cause my software UART to read erroneous values, as it won't be able to tell the difference between a start bit and any other high-to-low transition.

Is this an inevitable issue with a UART channel? Or is there some clever trick that the uC manufacturers use in their hardware UARTs?

Best Answer

If you use a stop bit length that is easily discerned from the rest of the data stream, such as 1.5 bit time, then it should be easy to start receiving mid-transmission. However, this comes at a cost of increased overhead. Your total available data throughput will suffer as you increase the length of your stop bit.

If you're not using the bus that heavily, and frequently have gaps between frames, then it may just be a matter of waiting for one of these gaps to occur, and then picking up the first hi-lo transmission as the beginning of your next start bit.

Keep in mind that the number of data bits should be predictable, as should the frame size, so even if you're using 100% of the bus's capacity and your stop bit is a single bit time, you should still be able to find the start bit if you collect enough frames. Every frame is guaranteed to have a hi-lo transition in it. The stop bit is the one that is always high. The start bit is the one that is always low. Assuming your data is random (or random enough), you could do something as simple as creating a buffer the size of your frame, set every bit in it, and then keep collecting frames and ANDing them into this buffer until the buffer only has 1 bit set. This bit is your stop bit. The one after it is your start bit. Voila! You've found it. The downside of this approach is that finding the start bit takes a bit more time than the alternatives, but the advantage is that you can maximize throughput by minimizing your stop bit time and your bus's idle time.

If you're using a parity bit, another option would be to grab two frames worth of data, pick the first low bit as the start bit, and then calculate the checksum and compare to the parity bit. If it matches, then you've (probably) found the start bit. If it doesn't, pick the next low bit and repeat until you get a good checksum. If you can't find a bit in your two frames of data that checks out as a valid start bit, then your data was corrupted, and you'll need to grab two more frames.