8
\$\begingroup\$

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?

\$\endgroup\$
  • \$\begingroup\$ Good question. Does your external device continiously send characters? If not, you should check if the start bit and stop bit are aligned. And if the data inbetween matches your check(sum/bit)? \$\endgroup\$ – Paul Oct 21 '15 at 18:04
  • \$\begingroup\$ Can you have the external UART stream send a preamble? Like a stream of a special data to indicate a stream is incoming that would be distinct from a start bit? If you could do that, then you'd be able to tell whether the data is erroneous should you power up in the middle of a transmission or not. \$\endgroup\$ – Funkyguy Oct 21 '15 at 18:13
  • 1
    \$\begingroup\$ If the serial stream does not contain any sufficiently long idle period - your youart is unlikely to recover from this. Partial solution can come in case you are not receiving the "stop" bit where expected. Then you would be able to reset the state and retry. \$\endgroup\$ – Eugene Sh. Oct 21 '15 at 18:35
  • 1
    \$\begingroup\$ You don't need a special preamble ... just an occasional rest longer than one character (inc.start,stop bits). Or, 10+ stop bits in a row, which is the same thing. \$\endgroup\$ – Brian Drummond Oct 21 '15 at 18:41
  • 2
    \$\begingroup\$ @Fuaze, the external device sends a long stream of characters continuously, but it does idle occasionally. Worst case, I can just ignore the input until the first time it idles. \$\endgroup\$ – Dan Laks Oct 21 '15 at 19:08
4
\$\begingroup\$

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.

\$\endgroup\$
  • \$\begingroup\$ Neat idea to AND together frames until just the start and stop bits survive. That'll be too much overhead for my specific application, but clever nonetheless. \$\endgroup\$ – Dan Laks Oct 21 '15 at 19:12
  • \$\begingroup\$ If the external device is something the OP has no control over (which he has stated in an earlier comment to the question), it is unlikely that he will be able to change the length of the stop bit. \$\endgroup\$ – tcrosley Oct 21 '15 at 20:13
  • \$\begingroup\$ That comment had not been made at the time I started writing this answer. However, the other three options I've listed still apply in the case that the stop bit length is fixed. \$\endgroup\$ – Dr. Funk Oct 21 '15 at 20:44
3
\$\begingroup\$

Hardware UARTs have the same problem. But it's usually one that solves itself in short order anyway. At the end of each frame, check the stop bit, and if it isn't high, discard the frame and wait for the next high-to-low transition. Assuming that the data from the source isn't totally pathological (e.g., long strings of "UUUU", or ASCII 0x55), the UART will eventually "walk" itself over to the real start bit.

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

Assuming 8N1 transmission.

You must wait for a string of 9 high or low bits in a row.

If high it will signify either a idle gap in the data or a 0xFF character and STOP bit
or
if low a START bit and a NULL 0x00 character .

Either one of these conditions will allow resynchronisation.

To speed it up: If you know certain characters that are not possible in the data you could parse the incoming data repeatedly (after the fact) for each bit and if you get a series of 7 characters that are nonsense (high bit set, lower case, control codes, punctuation or whatever) followed by a valid character you can be fairly sure you are resynchronised.

You will have the similar problems when you use a built-in UART peripheral and be unable to do bitwise evaluation and also have to remember to reset all framing error bits and such whenever they occur (especially on power up).

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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