1
\$\begingroup\$

I'm learning embedded programming (I'm not an Electrical Engineer). Sorry if this is not the right place or I'm asking this question incorrectly, but I had a very tough time trying to figure out a solution. I'm using a ATMega32 with a GPS module and a 16x2 LCD. I just want to read a NMEA sentence over UART and send the parsed data to the LCD. I read the sentence in a buffer and then spit it out to the display.But I get inconsistent data sometimes.. The GPS is always on and the AVR powers up in the middle and waits for the start of a sentence and then continues on receiving.

My question is: how can two devices sync if one is always sending (GPS sends data at 1 Hz rate) and the other receives at random times. How is UART synchronization achieved? I know about start and stop bits, but once the UART gets a bad packet (raising a framing error for example) how can it recover and synchronize?

please explain what happens at hardware level also or if you can,point me to some online resource, I can't find what I'm looking for.

Thanks so much!

Luca

\$\endgroup\$
6
\$\begingroup\$

Your intuition is correct -- UART hardware doesn't have any synchronization beyond the byte level. (It does synchronize at the byte level for you, via a special start bit as discussed here)

To synchronize "packets" longer than a byte, most high-level serial communication protocols have a special "preamble" of bytes that is guaranteed not to appear in the message. Then there are various strategies to signal the end of a packet: some protocols indicate the end of the message with a special "stop" sequence of bytes that is not allowed to appear in the message. Others use a fixed-length message header that states the precise length of the message.

I haven't used the NMEA protocol personally, but based on this guide it looks like they use '$' as a special character that signals the start of a packet. Is not allowed to appear inside the packet.

So, to receive this data in your program, I think you need to do something like this:

  1. Ignore all bytes until you see a '$'
  2. Then, record each byte to an array, starting from position 0. (Ensure your array is long enough to hold the longest possible valid message. If data exceeds your array length, go back to step 1.).
  3. Stop when you see 'CR' followed by 'LF' (this seems to signal the end of the NMEA packet)
  4. Calculate the checksum, and verify that it matches the transmitted checksum. If not, go back to step 1.
  5. Use the data from your array
  6. Go back to step 1.

This discussion has a lot of good links: https://stackoverflow.com/questions/1445387/how-do-you-design-a-serial-command-protocol-for-an-embedded-system

\$\endgroup\$
  • \$\begingroup\$ but what if I get in the middle of a sentence and in the middle of a byte? It would start sampling wrong bits,getting framing errors but presenting rubbish data? how would it re-synchronize? \$\endgroup\$ – Luca Apr 8 '16 at 11:54
  • \$\begingroup\$ because nmea data varies and has gaps between bursts, the hardware will sync, if you miss a few or a dozen or a hundred characters that is okay, you follow the state machine above, wait for the start of packet ($) and then gather data until you see an end of packet (CR, LF) then checksum the packet, discard it if it doesnt match, you dont care because you will get another in a second. \$\endgroup\$ – old_timer Apr 8 '16 at 12:07
  • \$\begingroup\$ I've had to interface to custom format serial data in a an old job. What we did on an error (any error including framing) you have to clear the error flags EVERY TIME and then go back to step 1. The micro we used had multiple registers with multiple flags to control the UART. Not every action clears the flags (especially error flags). It's in the documentation. \$\endgroup\$ – Spoon Apr 8 '16 at 12:15
  • \$\begingroup\$ @Luca the RS-232 protocol handles byte framing for you at the hardware level. So your AVR's UART will never give you data that starts in the middle of a transmitted byte. I'll add that to my explanation. (When a microcontroller UART gets turned on in the middle of a byte, it will typically discard the received bits and set an error flag as Spoon said) \$\endgroup\$ – Luke Apr 8 '16 at 20:11
1
\$\begingroup\$

If you look at the format of a NMEA message it has a defined start character ($) and an end character(s) CR+LF. Like this from Wikipedia:

$GPAAM,A,A,0.10,N,WPTNME*32

Your software needs to look for the $ character and save all of the following characters into a buffer until it receives CR+LF. It can then check if the message is valid by calculating the checksum and comparing it to the checksum in the message (the *32 is the checksum in the example). Only if the checksums match should the message be sent to the LCD.

\$\endgroup\$
  • \$\begingroup\$ in my software I wait for the dollar $ sign,and then start to store the characters (including the $) inside a array that acts like a buffer (of convenient size). But sometimes I get a $ followed by rubbish (only a couple of times randomly at the beginning of the communication), but if I hook up a serial link to my PC (RealTerm) I don't see it... \$\endgroup\$ – Luca Apr 8 '16 at 9:44
  • \$\begingroup\$ if the string after $ is garbage, simply discard the whole string and wait for another. \$\endgroup\$ – old_timer Apr 8 '16 at 12:08
  • \$\begingroup\$ if this is only on startup that is expected (that first $ was itself probably garbage) if this is something that happens regularly after booting but while running normally you probably have your divisor set wrong, or your clock is not accurate enough \$\endgroup\$ – old_timer Apr 8 '16 at 12:09
  • 1
    \$\begingroup\$ put a dumb terminal on the TX side of that uart. make some code that only computes checksums and do it for every string you find. print a 0 lets say for failed packets and a 1 for success. after booting and getting synced it shouldnt fail, if you are seeing a percentage of fails forever again probably your clock accuracy or divisor for the uart \$\endgroup\$ – old_timer Apr 8 '16 at 12:10
0
\$\begingroup\$

There are actually two questions involved in your post:

1) How is synchronization achieved? It is NOT. The only common factor the two devices have in common is time. This is what is specified by the Baudrate; specify a different baudrate for the two devices and you will receive garbage. Most hardware UARTs (and I hope you're using the dedicated hardware on your controller) provide decoding of Start/Stop bits as well as the actual data. So here we're talking about a single byte (a single ASCII letter in this case). The GPS will send a start bit, the data and a stop bit. This is some very simple and unreliable data checking but it's the only one you will actually have for a UART transmission. To be honest, if you have put your settings correct this will usually work all the time. I've had Megabytes transferred for testing without even a single bit error at 115200.

2) You state that you sometimes receive garbage. To me this can have two reasons: Either you receive your bytes already corrupted (you should see some errors in the microcontrollers UART error registers in that case) or you start missing characters because your main program cannot receive them so quickly. We would need a more detailed description of what you actually get. Since usually those GPS modules come pretty well tested, I would guess that the problem is on your side. After each received character, make sure to check the controllers error register to detect possible problems. Another approach to check your baudrate would be to hook up a scope to your TX line and check if the bit-times match what you have set up. Can you describe your scenario a bit better? Which controller do you use, do you use an external crystal, what speed do you run the controller at, what are your settings for the UART registers, do you see any errors during transfers?

\$\endgroup\$
0
\$\begingroup\$

How is UART synchronization achieved? I know about start and stop bits, but once the UART gets a bad packet (raising a framing error for example) how can it recover and synchronize

Reliable synchronization can be achieved by leaving a "dead time" of at least one character period between transmissions. If a receiving UART starts out (or becomes) desynchronized from the transmitter, it will resync when the transmission stops and starts again.

(In the context of NMEA, this should happen naturally, as the serial line speed should be high enough that the serial link is not always active. If it is not, your serial link is completely saturated, and some messages are probably being lost!)

A less reliable, but still effective, method of gaining reliable synchronization is to use 1.5 or 2 stop bits for the serial link. A receiving UART that becomes desynchronized is likely to start reading spaces within the transmission as single stop bits, and should eventually "drift" back into proper synchronization with the extended stop bits.

\$\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.