• Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

USART/UART data receiving problem

Status
Not open for further replies.

mbarren

New Member
I have a PIC project that I'm working on which involves making use of UART facilities of PIC16F628A to receive data from a GPS receiver (Holux GPSlim236 - *no* bluetooth).
The problem I'm facing right now seems to be that my PIC is receiving corrupt data. Here are the steps I've taken so far to figure out the cause:

1. Wrote a test program for the PIC to continuously send out a "AB" pattern. Connected the TX pin to an erricsson data cable (uses SIPEX SP232ACN chip level converter) and that to RS232 port on my PC and I could see the "AB" pattern on my linux serial terminal. Not a single gap or missing character!

1. Now, wrote a different test program for the PIC to send out any data it receive immediately. Connected the pic to RS232 port on my desktop through the same cable. If everything was to work properly, this setup would be same as a null modem. Not quite. Sometimes I got what I typed, most of the time I got garbage. I also set up a little debugging LED to light up if there was any error. It turns out Framing Errors occur right after the first few characters (sometimes the first).

Initially I thought the different voltage levels (TTL for the cable, CMOS for the PIC) was the problem, but after consulting the PIC's datasheet, found out that the Schmitt Trigger on the RX pin works from 0.8v to 5.0v for high signal. 3v of TTL falls in that range. Or am I wrong to assume this is how Schmitt Triggers work?

All I can deduce here is that there is some signal level/noise issue here. Yet again, connecting the GPS through the same cable works flawlessly.

So my questions:
1. Do I need to convert the TTL level to drive my RX pin?
2. If not, could you please give me a lead on how to go about solving this problem? (I've been trying to figure this out for over 2 days now)

Here're some info that might help you help me:
- using an external 20Mhz Crystal
- UART speed is 38400
- I have lots of programming background, not much electronics

If you think there is something might be wrong with the code, I'll post the code too.
Appreciate it if you could give me some advice on this.

I *have* read the sticky post for newcomers
 

Pommie

Well-Known Member
Most Helpful Member
My initial thought is that the baud rate is wrong. Not too far off but enough to cause problems. Post your setup code or try a slower baud rate (2400) to confirm it is software and not hardware.

Mike.
 

Sceadwian

Banned
Sounds like a baud rate mismatch to me. You should be able to do 9600 easily. If you require the full 38400 baud rate you may need to change crystals.
 

mbarren

New Member
Code:
list p=p16f628a
#include "p16f628a.inc"

; configurations

;__config _WDT_OFF & _INTOSC_OSC_NOCLKOUT
__config _WDT_OFF & _HS_OSC

; constants

MATCH_STR_LEN equ 7         ; length of the match string
FIX_IND_PIN   equ 0         ; fix indicator output pin on port B

; some labels for blocks of memory
cblock 0x20
  CUR_MATCH_P: 1            ; pointer to the current character of match
                            ; string
  MATCH_STR: MATCH_STR_LEN  ; match string - e.g. $GCDSS
  IN_BUFFER_LEN: 1          ; length of the input buffer
  IN_BUFFER: 40             ; start of the input buffer
  REC_TMP: 1                ; temporary location to store received byte
endc

  ; file intializers

  clrf IN_BUFFER_LEN
  clrf CUR_MATCH_P
  movlw "$"
  movwf MATCH_STR
  movlw "G"
  movwf MATCH_STR + 1
  movlw "P"
  movwf MATCH_STR + 2
  movlw "G"
  movwf MATCH_STR + 3
  movlw "G"
  movwf MATCH_STR + 4
  movlw "A"
  movwf MATCH_STR + 5
  movlw ","
  movwf MATCH_STR + 6


  ; uart initialization

  bsf STATUS, RP0 ; switch to bank 1

  ; set up UART receive interrupt

  ;bsf INTCON, GIE
  ;bsf INTCON, PEIE
  ;bsf PIE1, RCIE
  ;bcf INTCON, INTF

  ; set up the receiver

  bcf STATUS, RP0 ; switch to bank 0
  bsf RCSTA, SPEN
  bsf RCSTA, CREN

  ; set up RB1 and RB2 as input ports to allow
  ; UART module to use them for send/receive

  bsf STATUS, RP0 ; switch to bank 1
  bsf TRISB, 1 ; UART receive pin
  bsf TRISB, 2 ; UART transmit pin
  bcf TRISB, FIX_IND_PIN ; GPS fix indicator pin (output)

  ; set up the transmitter

  movlw 32         ; this should give us ~38K baud (37878 according to datasheet)
  movwf SPBRG
  bsf TXSTA, BRGH
  bsf TXSTA, TXEN
  bcf TXSTA, SYNC

  bcf STATUS, RP0 ; switch back to bank 0

  bcf PORTB, FIX_IND_PIN ; by default, the fix indicator pin is low

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; main program loop which waits for an incoming
; NMEA 0183 sentence
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

LOOP:

  btfss PIR1, RCIF
  goto LOOP

  movf RCREG, W ; read the character from buffer

  ; any errors

  btfsc RCSTA, OERR
  goto CLEAR_ERROR
  btfsc RCSTA, FERR
  goto FRAMING_ERROR

TXLOOP:

  btfss PIR1, TXIF
  goto TXLOOP

  movwf TXREG
  goto LOOP

FRAMING_ERROR:
  bsf PORTB, FIX_IND_PIN
  goto LOOP

CLEAR_ERROR:
  bcf RCSTA, CREN
  bsf RCSTA, CREN
  goto LOOP  

end
NOTES about the code:
- interrupt aren't used for RX (they're there from a different code)

I'm not sure but I think PIC16F628A runs at max 20MHz. Am I wrong? In fact the reason why it's running at 20Mhz now is because the baud mismatch was my first suspected cause too. I was running the PIC at 4Mhz prior to that.

I haven't yet re-programmed the pic for a lower baud (programming is rather an involved process on this side!) but assuming the problem *is* the baud, what options do I have? I have already chosen the best value that gives me the closest to 38K baud.

thanks for your replies btw.
 

Mike - K8LH

Well-Known Member
Do you have a "radix dec" statement in there somewhere or have you set the default radix to decimal? If so then setting SPBRG to a value of 32 (0x20) should be fine.

Mike
 

mbarren

New Member
Do you have a "radix dec" statement in there somewhere or have you set the default radix to decimal? If so then setting SPBRG to a value of 32 (0x20) should be fine.

Mike
MAAAAANNNN, as I read your post, I slapped myself on the forehead while feeling like an idiot :p

you're right, I was putting in 32 as in hexadecimal. Changed it to d'32' and it's working like a charm. Thank a lot, it would have taken me a *long* time to figure that out myself.
 

Sceadwian

Banned
I've done that a few times. When odd problems crop up it teaches you to check your syntax first pretty quickly, I've spent a long time staring at code wondering why it's not working because of a typo. I even had a whitespace charactor inserted in an ASM file somehow that the compiler kept choking on.

You might want to test a lot of long data strings though, according to my math that's still a 1.8% error in the baud rate. Might not crop up except on long tracts of information being sent, if you're sending smaller packets infrequently it may never occur. Depends on the device as to how sensitive to baud rate error it's going to be and how well it re-synchronizes during short delays.
 
Last edited:

mbarren

New Member
Yeh, I did think of that when writing up the code to set the baud rate for my PIC. I'm dealing with a burst of few hundred bytes every second (position fix info from GPS). Some visual testing so far shows it's working properly.
But assuming that even for those few hundred consecutive bytes, some are mis-read occasionally, what are my options to improve it?
I've read a little about big-banging and handling the whole communication layer manually. Is this the next sane step?
 

Mike - K8LH

Well-Known Member
One thing Sceadwian may not be taking into account is that the 1.8% bit rate error is only cumulative through the duration of each single byte. The UART hardware syncs' up on each start bit.
 

Sceadwian

Banned
No, next option would be to change your crystal frequency. There are some magic crystal frequencies that allow exact baudrate matches. I just looked on Google real fast and 18.432Mhz is the highest one I could find. You just have to recalculate your SPBRG value for the new crystal. Don't know if anything else you're doing relies on your clock being 20mhz. Basically, take a look at the 'weird' value crystals you can get access to and divide by 38400, if it divides evenly you'll get an exact baud rate match with some values SPBRG value.
 

Mike - K8LH

Well-Known Member
A 1.8% bit rate error shouldn't be a problem but if you think it might be then as an alternative to using a special crystal frequency you might consider using one of the newer PIC devices which have a 16 bit SPBRG clock divider chain instead of the 8 bit clock divider chain in the '628A. Using one of these devices with a 20 MHz clock, with BRG16 = 1, and BRGH = 1 yields a whopping 0.16% bit rate error for 38400 baud.

Mike

 

Attachments

Last edited:

Sceadwian

Banned
Mike is right, the hardware is not however guaranteed to precisely sync on every byte. It's good practice to use a baud dividable crystal if you can, then you don't have to worry about it at all. And it depends on the UART in the GPS module as well and how much error is in it's clock. If it's -2% and you're +2% that's 4% cumulative error. Most sites say 2% or so is acceptable, but there is no standard for what baud error is going to cause problems, some recommend 1.5% I've seen some recommend no more than .5% error. If you don't want errors shoot for 0 and hope the engineer of the product you're interfacing with did too. It's really a trivial thing to use a crystal divisible by the baud rate. Again though it depends on if you require that exact 20mhz clock for other features.
 
Last edited:

mbarren

New Member
Mike: for my next project, I will look into the more recent PICs. This is my first time using a microcontroller.

Sceadwian: I kept thinking you meant a faster crystal. My only requirement is to communicate with a GSM modem and a GPS - GSM runs at 9600 and GPS runs at 38400. And I just realised all the standard baud rates have a common divisor!
Just searched RS electronics, and 18.432 is there. I'm all set.

and you guys are awesome, hopefully i'll get to contribute to this place sometime.
 

Sceadwian

Banned
The sync can't be 100% perfect every time if the baud rate isn't the same, when the error is high enough and the two clocks are at their worst sync point is where the errors occur, once the bit error occurs in a stream synchronization is lost and can't be regained until there's a break in the transmition because it won't be reading the start and stop bits properly anymore.

I've observed this with hardware uarts before with high baud error percentage where if you send bytes in small packets transmition is fine, but if a true stream is being sent at some point the stream desyncs, and if the receiving uart misinterprets a data bit as a start or stop bit all of a sudden all you get is bit shifted garbage, sometimes it resyncs by itself because different bit patterns in the data sync better than others, I've observed this directly where certain bytes in a low range would transmit fine and other bytes would come through as the wrong charactor.

Didn't say it was going to happen in his case, but it is possible. In his case it's a simple matter of changing crystals to guarantee it can't happen.
 
Last edited:

Nigel Goodwin

Super Moderator
Most Helpful Member
The sync can't be 100% perfect every time if the baud rate isn't the same, when the error is high enough and the two clocks are at their worst sync point is where the errors occur, once the bit error occurs in a stream synchronization is lost and can't be regained until there's a break in the transmition because it won't be reading the start and stop bits properly anymore.
But you're talking about a baud rate error larger than a single byte, if the baud error is smaller than that, then it can't lose synchronisation, because the stop bit and subsequent start bit resyncronise at every byte.
 

Sceadwian

Banned
Not sure how to do the math on that, so what baud error are you saying is required for it to no longer sync?
 

Pommie

Well-Known Member
Most Helpful Member
The error has to be less than half a bit width which works out about 5%. I have found that if I only have 1 stop bit the bit error does become accumulative. Two stop bits allows enough time for the start bit to cause a resync.

Mike.
 

Sceadwian

Banned
Okay you stated some numbers Pommie, how'd you come up with them? :D Cause I've had corrupted data at around 3%
 

Pommie

Well-Known Member
Most Helpful Member
Think about when the signal is sampled. After the (leading edge of the) start bit is received there is a wait of 1½ bits before the first data bit is sampled. Errors will occur if the sample is ½ a bit either way when the 8th bit is received. So, from the start bit to the final sample is 9½ bit lengths. One half in nine and a half is around 5%.

Some software routines don't sample as often and so miss the start of the start bit and thus the acceptable error is smaller.

Mike.
 
Last edited:
Status
Not open for further replies.

Latest threads

EE World Online Articles

Loading
Top