![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
KTrenholm
Joined: 19 Dec 2012 Posts: 43 Location: Connecticut, USA
|
Handling RS232 errors from incorrect baud rates |
Posted: Mon Aug 25, 2014 2:50 pm |
|
|
Hi all,
I've got a bit of a strange situation that I'm not entirely sure how to handle.
I am using PCWHD v4.132
the PIC is a PIC24FV32KA304
What I'm looking to do is to "protect" my RS232 RX routines from any bytes received at an incorrect baud rate. I'm writing a windows application that looks to detect 2 different PICs automatically. One is running RS232 at 9600 and the other at 115200. I iterate through each COM port connected to the PC and send it my query string and await a response. If I get a proper response, I know the PIC is connected at that port.
The issue comes about when I query for one controller (at 115200), the other controller (at 9600) goes non-responsive over RS232 until AFTER I send it a string (terminated with a return and line feed, as my ISR specifies) at the correct baud rate. The same behavior is seen if I query for the controller at 9600 (the PIC at 115200 goes non-responsive).
I.E. for the controller running at 115200:
1) Query for controller @ 9600 - No Response (as expected)
2) Query for controller @ 115200 - No Response (I suspect a framing error from previously sent string preventing proper response? Is there a way I can confirm this?)
3) Query controller @ 115200 - Correct Response
Essentially, when I switch from 9600 to 115200 (or from 115200 to 9600), I have to send my query twice in order to get a response.
The code for both controllers rs232 configuration and RDA Interrupt are identical. I included the configuration for the PIC running at 115200 below.:
Code: |
#USE RS232 (STREAM=PCCTRL, BAUD=115200, BITS=8, PARITY=N, XMIT=PIN_B0, RCV=PIN_B1, ERRORS)
#INT_RDA
void RDA_isr(void)
{
#USE FAST_IO(A)
#USE FAST_IO(B)
long timeout = 0;
char c;
restart_wdt();
while (kbhit(PCCTRL) &&(++timeout<50000)) {
//Get String until encounter <CR><LF>
c = fgetc(PCCTRL);
if (c != 13) {
if (c!= 10) {
if(rs232DataByte < BUFFER_DATA_SIZE) {
rs232MsgInBuff[rs232DataByte++] = toupper(c);
}
}
}
else {
//Only copy over complete messages for processing
memcpy(rs232MsgInBuff2,rs232MsgInBuff,BUFFER_DATA_SIZE);
memset(rs232MsgInBuff, '\0', sizeof(rs232MsgInBuff));
rs232DataByte = 0;
RS232_Msg = TRUE;
}
}
}
|
From my understanding having ERRORS in my RS232 configuration should automatically reset the UART on a framing error? I had thought that would automatically reset the UART and prevent any issues of this sort.
I hope I explained what I'm seeing clearly enough. It's a bit of a strange condition. Let me know if I can clarify anything. |
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9172 Location: Greensville,Ontario
|
|
Posted: Mon Aug 25, 2014 3:15 pm |
|
|
Though I haven't done this... you should be able to read the 'ERRORS' variable that CCS creates and figure out why the UART 'failed'. I'll assume that a 'framing error' sets a particular bit in the 'ERRORS' variable.
Those who program everyday will/should know. Perhaps the help file has a 'map' of the errors and their setting in the ERRORS variable.
worst case...cause one yourself and display the result...
hth
jay |
|
![](templates/subSilver/images/spacer.gif) |
dyeatman
Joined: 06 Sep 2003 Posts: 1924 Location: Norman, OK
|
|
Posted: Mon Aug 25, 2014 3:32 pm |
|
|
Defined on page 131 of the PCD manual
The STA bits are defined on page 21-6 of the datasheet.
A search in the forum on rs232_errors finds a lot more
info including a handler routine.
In this one the user sets up a Framing Error macro in his RDA2 routine
that might be useful.
https://ccsinfo.com/forum/viewtopic.php?t=50886 _________________ Google and Forum Search are some of your best tools!!!! |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19365
|
|
Posted: Mon Aug 25, 2014 11:02 pm |
|
|
Also, realise that the RDA interrupt means _one_ character is ready to be read. The ISR should read just this character. Look at ex_sisr.
As it stands _your_ handler could receive hundreds of characters, and never exit (since it'll never see a carriage return/line feed).......
Your 'timeout', will make it occasionally exit, but it'll then loop back again when the next garbage character is seen, and wait for timeout again.
Your approach to the ISR is flawed.
The code should receive _one_ character, and possibly use a state machine to decide when a message is complete, but exit immediately after each character. |
|
![](templates/subSilver/images/spacer.gif) |
KTrenholm
Joined: 19 Dec 2012 Posts: 43 Location: Connecticut, USA
|
|
Posted: Tue Aug 26, 2014 7:02 am |
|
|
Ttelmah wrote: | Also, realise that the RDA interrupt means _one_ character is ready to be read. The ISR should read just this character. Look at ex_sisr.
As it stands _your_ handler could receive hundreds of characters, and never exit (since it'll never see a carriage return/line feed).......
Your 'timeout', will make it occasionally exit, but it'll then loop back again when the next garbage character is seen, and wait for timeout again.
Your approach to the ISR is flawed.
The code should receive _one_ character, and possibly use a state machine to decide when a message is complete, but exit immediately after each character. |
Did you take into account that I'm triggering the while loop off the kbhit() function? Additional characters should only be read into the software buffer in the same ISR if there are additional characters already waiting in the hardware buffer. It won't simply loop until a carriage return/line feed is seen. It will only loop back if there are characters left in the hardware buffer. I wasn't aware if there was something wrong with this approach.
Anyway, that's really not at issue at the moment. Reading bit 2 of UART_ERRORS for a framing error should be no problem. I'm thinking perhaps the buffer is getting loaded with bad characters when something is sent at an incorrect rate. In theory I should just be able to wipe the buffer whenever this happens to leave it clean for when a proper message comes in. |
|
![](templates/subSilver/images/spacer.gif) |
ezflyr
Joined: 25 Oct 2010 Posts: 1019 Location: Tewksbury, MA
|
|
Posted: Tue Aug 26, 2014 7:46 am |
|
|
Hi,
I'm sure he noticed it, in fact it's probably one of the reasons he concluded your code was 'flawed'.....
Trust Ttelmah, and look at example 'ex_sisr.c' to see how a proper serial interrupt routine is implemented!
John |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19365
|
|
Posted: Tue Aug 26, 2014 7:47 am |
|
|
Problem is that it won't do a getc, unless kbhit is set. Now the getc, is what triggers the error clearing code. As such there is the potential to sit looping, depending on how the CCS code sets things when an error occurs. Does kbhit consider that a character has arrived?....
Also why have 'fast_io' 'mid code'. These are pre-processor directives, and should be right up the top with the use RS232.
I'd prefer a simpler approach:
Code: |
#INT_RDA
void RDA_isr(void)
{
char c;
c = fgetc(PCCTRL); //This way the character is always read
//If you want to test for an error now test rs232_errors
if ((rs232_errors & 0xE) !=0)
return; //immediate exit if error
if (c == 13)
{
//Only copy over complete messages for processing
memcpy(rs232MsgInBuff2,rs232MsgInBuff,BUFFER_DATA_SIZE);
memset(rs232MsgInBuff, '\0', sizeof(rs232MsgInBuff));
rs232DataByte = 0;
RS232_Msg = TRUE;
return;
}
if (c != 10)
{
if(rs232DataByte < BUFFER_DATA_SIZE)
{
rs232MsgInBuff[rs232DataByte++] = toupper(c);
}
}
}
|
No guarantees, but you may well find the code then recovers when it sees an error. |
|
![](templates/subSilver/images/spacer.gif) |
KTrenholm
Joined: 19 Dec 2012 Posts: 43 Location: Connecticut, USA
|
|
Posted: Tue Aug 26, 2014 8:03 am |
|
|
heh, as far at the fast IO is concerned, I have no idea why that's there. I inherited a bunch of PIC code that all have their RDA ISRs configured in this way and the way the guy did things I'm decently anxious about touching something where I have no clue why he put it there.
I had no idea that the fgetc is what triggers the error, but it makes total sense. That would explain why it wasn't triggering anything when I placed the error checking code at the beginning of the ISR.
I'll play around and see what I find. |
|
![](templates/subSilver/images/spacer.gif) |
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
Testing, testing, testing |
Posted: Tue Aug 26, 2014 8:16 am |
|
|
I see two scenarios which have to be dealt with.
1) How the 9600 receiver deals with 11500 signals.
2) How the 11500 receiver deals with 9600 signals.
Simply force both types of signals into the system and look at registers etc to see what happens.
Test with all the different messages you are likely to use.
Then some..............
Mike |
|
![](templates/subSilver/images/spacer.gif) |
KTrenholm
Joined: 19 Dec 2012 Posts: 43 Location: Connecticut, USA
|
|
Posted: Tue Aug 26, 2014 8:27 am |
|
|
Ttelmah wrote: | Problem is that it won't do a getc, unless kbhit is set. Now the getc, is what triggers the error clearing code. As such there is the potential to sit looping, depending on how the CCS code sets things when an error occurs. Does kbhit consider that a character has arrived?....
Also why have 'fast_io' 'mid code'. These are pre-processor directives, and should be right up the top with the use RS232.
I'd prefer a simpler approach:
Code: |
#INT_RDA
void RDA_isr(void)
{
char c;
c = fgetc(PCCTRL); //This way the character is always read
//If you want to test for an error now test rs232_errors
if ((rs232_errors & 0xE) !=0)
return; //immediate exit if error
if (c == 13)
{
//Only copy over complete messages for processing
memcpy(rs232MsgInBuff2,rs232MsgInBuff,BUFFER_DATA_SIZE);
memset(rs232MsgInBuff, '\0', sizeof(rs232MsgInBuff));
rs232DataByte = 0;
RS232_Msg = TRUE;
return;
}
if (c != 10)
{
if(rs232DataByte < BUFFER_DATA_SIZE)
{
rs232MsgInBuff[rs232DataByte++] = toupper(c);
}
}
}
|
No guarantees, but you may well find the code then recovers when it sees an error. |
I just now gave this a shot and found this this actually never recovers from being sent "bad" bytes until I power cycle the board (however this may have more to do with the handler of complete messages outside the ISR rather than the ISR, I'll have to have a further look) |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19365
|
|
Posted: Tue Aug 26, 2014 9:46 am |
|
|
Interesting.
I'd add an 'output toggle', and see where it gets to. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19365
|
|
Posted: Tue Aug 26, 2014 10:55 pm |
|
|
Try something a bit 'radical'.
Do a #bit definition on the FERR bit, and a register definition for the receive register.
Change the loop to a do..while (this way it'll always execute _before_ testing).
Then in the loop, immediately in front of where you read the character, add:
Code: |
if (FERR)
{
c=RXREG;
FERR=FALSE;
continue;
}
|
This way, the test is always executed before getc is called. It should then throw away any character in the RXREG, and clear the error, if FERR is set.
Problem is that as it stands, we are dependent on how kbhit does behave when FERR is set, and whether getc, does actually clear this error. This should avoid this dependence. ![Smile](images/smiles/icon_smile.gif) |
|
![](templates/subSilver/images/spacer.gif) |
|
|
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
|