|
|
View previous topic :: View next topic |
Author |
Message |
dbotkin
Joined: 08 Sep 2003 Posts: 197 Location: Omaha NE USA
|
Changing baud rate on software UART? |
Posted: Tue Oct 29, 2013 10:00 am |
|
|
Is it possible to set or change the baud rate of a software UART at run time?
I've got a design that uses two serial ports, but the chip has only one hardware EUSART (it's a 16F1459). I'd like to be able to change the speed of the non-EUSART serial port at will. The set_uart_speed() function only works with hardware UARTs, according to the help file, and I verified that even if you specify the stream of the software UART, it sets the baud rate of the hardware UART (it would be nice to have an error message in that case).
Switching to a chip with two UARTs is not a viable option. |
|
|
stinky
Joined: 05 Mar 2012 Posts: 99 Location: Central Illinois
|
|
Posted: Tue Oct 29, 2013 11:46 am |
|
|
I haven't done this myself but I believe this will work. Obviously set you desired I/O pins and baud rate.
Code: | #use RS232(baud = 9600, RCV = PIN_A3, XMIT = PIN_A1, STREAM = A)
#use RS232(baud = 1200, RCV = PIN_A3, XMIT = PIN_A1, STREAM = B) |
Then use fprintf() to specify which stream to use:
Code: | fprintf(A, "9600 BAUD");
fprintf(B, "1200 BAUD"); |
|
|
|
dbotkin
Joined: 08 Sep 2003 Posts: 197 Location: Omaha NE USA
|
|
Posted: Tue Oct 29, 2013 12:34 pm |
|
|
Thanks for the reply. I had thought of that -- a separate stream for each baudrate -- but it would mean that every fprintf() would need to be duplicated with if() or case() wrapped around each one. I guess I could wrap a function around it.
Given that this is for GPS data, I suppose I could just make it a fixed 9600BPS and tell the users to make the GPS conform. I do like the idea of being able to set it to a different baud rate if needed, though.
Edit: Hmmm. tried it... it seems to only act on one of the streams.
Code: | .................... #use rs232(stream=GPS9600,baud=9600,parity=N,rcv=PIN_B6,xmit=PIN_B4,bits=8,restart_wdt,errors)
*
0809: MOVF 04,W
080A: MOVWF 78
080B: MOVLB 01
080C: BSF 0D.6
080D: CLRWDT
080E: MOVLB 00
080F: BTFSS 0D.6
0810: GOTO 013
0811: MOVLB 01
0812: GOTO 00D
0813: MOVLW 08
0814: MOVWF 77
0815: MOVLB 03
0816: CLRF 55
0817: BSF 77.7
0818: GOTO 02B
0819: BCF 77.7
081A: GOTO 02B
081B: BCF 03.0
081C: MOVLB 00
081D: BTFSC 0D.6
081E: BSF 03.0
081F: MOVLB 03
0820: RRF 55,F
0821: BSF 77.6
0822: GOTO 02B
0823: BCF 77.6
0824: DECFSZ 77,F
0825: GOTO 01B
0826: MOVF 78,W
0827: MOVWF 04
0828: MOVF 55,W
0829: MOVWF 78
082A: GOTO 040
082B: MOVLW 01
082C: MOVWF 04
082D: MOVLW 00
082E: BTFSC 77.7
082F: MOVLW 55
0830: MOVWF 78
0831: DECFSZ 78,F
0832: GOTO 031
0833: DECFSZ 04,F
0834: GOTO 02D
0835: MOVLW 98
0836: BTFSC 77.7
0837: MOVLW 29
0838: MOVWF 78
0839: DECFSZ 78,F
083A: GOTO 039
083B: BTFSC 77.7
083C: GOTO 019
083D: BTFSC 77.6
083E: GOTO 023
083F: GOTO 01B
.................... #use rs232(stream=GPS4800,baud=4800,parity=N,rcv=PIN_B6,xmit=PIN_B4,bits=8,restart_wdt,errors)
.................... #use rs232(stream=RPT,baud=9600,parity=N,rcv=PIN_B5,xmit=PIN_B7,bits=8,restart_wdt,RECEIVE_BUFFER=32,errors)
*
05AA: CLRWDT
05AB: MOVF 49,W
05AC: SUBWF 48,W
05AD: BTFSC 03.2
8< snip... |
|
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1349
|
|
Posted: Tue Oct 29, 2013 3:54 pm |
|
|
It'll only generate the assembly if you use the stream in your code. Did you make sure to make a call to getc for each stream? |
|
|
dbotkin
Joined: 08 Sep 2003 Posts: 197 Location: Omaha NE USA
|
|
Posted: Tue Oct 29, 2013 10:16 pm |
|
|
Yes, I did. |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1349
|
|
Posted: Tue Oct 29, 2013 10:32 pm |
|
|
I just tried the following test program in 5.010 and it generated code for each stream:
Code: |
#case
#include <16F1459.h>
#use delay(clock=22118400)
#use rs232(stream=GPS9600,baud=9600,parity=N,rcv=PIN_B6,xmit=PIN_B4,bits=8,restart_wdt,errors)
#use rs232(stream=GPS4800,baud=4800,parity=N,rcv=PIN_B6,xmit=PIN_B4,bits=8,restart_wdt,errors)
#use rs232(stream=RPT,baud=9600,parity=N,rcv=PIN_B5,xmit=PIN_B7,bits=8,restart_wdt,errors)
void main() {
char c;
enable_interrupts(GLOBAL);
c = fgetc(GPS9600);
c = fgetc(GPS4800);
c = fgetc(RPT);
fputc(c,GPS9600);
fputc(c,GPS4800);
fputc(c,RPT);
while(TRUE);
}
|
I wasn't able to include the buffer on the last stream (compiler error prevented it), but each #use gets its own code. You'll need to post your test program probably. |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
Re: Changing baud rate on software UART? |
Posted: Wed Oct 30, 2013 5:55 am |
|
|
dbotkin wrote: | I verified that even if you specify the stream of the software UART, it sets the baud rate of the hardware UART (it would be nice to have an error message in that case). | I consider this a bug. Would you please be so kind as to report this to CCS? It will help others in the future.
I don't like the CCS software UART. Simple, but limited in too many ways. Whenever possible I try to use a processor with hardware UART on every stream as it saves me from so many hard to find problems.
As you already discovered the CCS software UART can not change baud rates. Multiple streams are the only option here. Search the forum, this topic has been discussed many times. You can create a wrapper function that uses a global variable to switch between the different streams.
How many different baud rates do you want to support? Each baud rate requires it's own hard coded routines so this could get quiet large.
You want to connect to a GPS, that makes me assume this is for receive only?
Receiving with the software UART is tricky. Interrupts will be disabled during receiving, is that what you want? (1ms disabled for each character at 9600bps)
When the other (hardware) UART is transmit only, you could split the UART to receive from the GPS and transmit to the other. Different baud rates on both would be difficult though.
If you have some extra time it would be nice to create a software UART based on interrupts. This would be way more flexible than the CCS polling method and can support multiple baud rates too. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Wed Oct 30, 2013 7:06 am |
|
|
I did post a simple receive UART based on a a timer interrupt here some time ago.
It would be pretty easy to just change the values used in this, to give different baud rates, for a simple couple of rates as involved here.
A search should find it.
Best Wishes |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Wed Oct 30, 2013 4:16 pm |
|
|
seriously:
the software based serial routines are not reliable and can fail under many different circumstances that are hard to predict in advance.
No way to tell just how bad your risk is w/o seeing the whole program.
The hardware UART, when used with an RX interrupt driven buffer can be six sigma reliable, and very robust.
if this is a commercial product you are working on,
you are ill advised to use any form of software based serial datacom.
sooner or later it will fail.
the ONLY decently safe soft serial fucntion is for TX only ,
with NO Interrupts enabled. just my 2 cents |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9226 Location: Greensville,Ontario
|
|
Posted: Wed Oct 30, 2013 5:53 pm |
|
|
I'm assuming you're using the USB peripheral is that why you said using a PIC with 2 UARTs is not a viable option...but...would be the best solution. How about adding an I2C<>UART chip ? Is that possible?
Software UARTS, unless s...l....o....w will be real pain.
It might be worth 1/2 day R&D to source a better PIC or configuration to get real UARTs.In the long run it will save a LOT of grey hairs and wasted time.I always use a 'big' PIC,yeah 'overkill' but time is money and 'saving' a few pennies on a small PIC doesn't really work.An extra buck now, spread over say 1000 units is only $1000 compared to a week or more of R&D time used up on problems due to the software UART code.
To put it into perspective , these days the BOX costs a LOT more than the PICs do !
Just thinking of options for you.
hth
jay |
|
|
dbotkin
Joined: 08 Sep 2003 Posts: 197 Location: Omaha NE USA
|
|
Posted: Wed Oct 30, 2013 10:44 pm |
|
|
Thanks for the input, guys.
So here's the deal. One serial interface connects to another PIC based device on another board, and that link needs to be reliable, as in hardware UART.
The second interface is receive-only for a GPS, which may or may not be attached. If it is attached, I need to read the NMEA sentence and send it out the other serial port. The GPS data is extremely low priority. The only thing we care about is occasionally capturing a sentence that has valid time information. If we get one intact packet forwarded every few minutes, it's fine. Most of the time (like 99.999% of the time) the processor will have nothing to do but watch the GPS port.
Given the above facts, I'm OK with using the sucky software UART for receiving GPS data. When there is something else to do, I'll simply ignore it. Yes, I could have selected a PIC with two hardware UARTS, but it would have been a waste of board space, money and pins... a 28-pin PIC doing an 18-pin job.
Jay, I agree with you - up to a point. In this case, saving a buck per unit is worth a little "play time" during development. And as I mentioned, less than stellar reliability is not an issue as long as I can receive a packet at 9600 BPS once every few seconds -- or even every few minutes, really. It's just a feature to allow the use of a GPS receiver to set and occasionally sync a real-tine clock on another board. Most users won't have one attached, but I do want it to work right for the few who will.
I think most GPS receivers will support 9600. I know I can buy little $20 modules on Fleabay that run 9600. I'm going to write the firmware for 9600 BPS only. If there's enough program space left when I have everything else working, I'll wrap a function around the GPS side to support a couple of other choices... but I don't know that it's going to be worth sinking a whole lot of effort into. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Thu Oct 31, 2013 3:05 am |
|
|
There are still problems....
Key to understand is that when receiving a character, timings have to be accurate. Hence for non interrupt based software receive (or transmit), interrupts have to be disabled.
Now provided the other link is at the same baud rate _or slower_ than the software link, then using the disable_ints option is OK, since interrupts will be enabled momentarily between characters, allowing interrupt driven serial RX on the other channel to work reliably.
I've put the timer based serial I mentioned earlier, up into the code library.
This potentially could do what you need from the GPS, though you would need to enlarge the buffer, if you are not going to be able to parse the strings fairly often.
<http://www.ccsinfo.com/forum/viewtopic.php?p=180938>
Worth saying that the 'historic' rate for NME GPS strings is 4800bps.
Look up NMEA 0183.
Running at the lower rate, means you can do things slower (interrupt at lower frequency on the example given), and this is the default 'start up' rate on a lot of devices. It is the 9600bps rate that is 'less standard' speed, and for your application, I'd suggest using the slower rate.
Best Wishes |
|
|
dbotkin
Joined: 08 Sep 2003 Posts: 197 Location: Omaha NE USA
|
|
Posted: Thu Oct 31, 2013 11:15 pm |
|
|
Ttelmah wrote: | Worth saying that the 'historic' rate for NME GPS strings is 4800bps.
Look up NMEA 0183.
Running at the lower rate, means you can do things slower (interrupt at lower frequency on the example given), and this is the default 'start up' rate on a lot of devices. It is the 9600bps rate that is 'less standard' speed, and for your application, I'd suggest using the slower rate. |
Yeah, I'm aware of the "historical default" 4800 BPS rate. A lot (most?) of the inexpensive GPS receiver modules now available default to 9600, and lack any sort of documentation whatsoever. I shudder to think of even attempting to walk a customer through changing the baud rate, especially since they're not even RS232 devices (TTL level only). So I've got to be able to talk to the majority of the probable candidates with no user intervention at all.
What you said about disabling interrupts and such got me thinking, though. Really, when listening for GPS data I can afford to just do that and nothing else -- I'll get an external interrupt if the other task needs attention, at which time I can simply ignore the GPS data for as long as needed. So that got me thinking. I don't want to waste the space, pin count and expense of a device with two hardware UARTS... but hey!! I really need two UARTs, since I only have to actually use one at a time. How about a device whose UART pins I can MOVE at will? Bingo. 16F1827/1847. OK, so I can really only move the RX pin; there are three pins total that can be used for RX/TX. But I don't need to send data to the GPS, only to the other device. So TX to the host board stays on B5, and I can switch RX between pins B1 and B2 as needed. Seems like the compiler still doesn't support doing it -- #pin_select doesn't seem to work, nor does changing the pins with #use_rs232 from the looks of it, but I can change APFCON0 bit 7 on the fly.
And if I'm going to resort to that, I may as well set the SPBRGH:SPBRGL registers myself, too. |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Fri Nov 01, 2013 10:49 am |
|
|
dbotkin wrote: | How about a device whose UART pins I can MOVE at will? Bingo. 16F1827/1847. | There are even more PICs that can do this than the two models you reference here.
I'm surprised you consider changing processor as the PIC16F1459 has USB and you are dropping that feature now. From what we know for your project even the dirt cheap 8-pin PIC12F1822 might do the job. It has a hardware UART with switch-able pin configuration on the UART.
Quote: | And if I'm going to resort to that, I may as well set the SPBRGH:SPBRGL registers myself, too. | Well, yes, you can hard code everything if you want to, but what's wrong in using the set_uart_speed() function? That's doing exactly that for the hardware UART. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
Re: Changing baud rate on software UART? |
Posted: Fri Nov 01, 2013 12:17 pm |
|
|
ckielstra wrote: | I consider this a bug. Would you please be so kind as to report this to CCS? It will help others in the future.
I don't like the CCS software UART. Simple, but limited in too many ways. Whenever possible I try to use a processor with hardware UART on every stream as it saves me from so many hard to find problems.
|
It is worth pointing out that the manual for set_uart_speed, says:
"Changes the baud rate of the built-in hardware RS232 serial port at run-time. "
Couldn't really be much plainer.
Agree totally about the standard software UART.
Best Wishes |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|