CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Handling RS232 errors from incorrect baud rates

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
KTrenholm



Joined: 19 Dec 2012
Posts: 43
Location: Connecticut, USA

View user's profile Send private message

Handling RS232 errors from incorrect baud rates
PostPosted: Mon Aug 25, 2014 2:50 pm     Reply with quote

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.
temtronic



Joined: 01 Jul 2010
Posts: 9245
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Mon Aug 25, 2014 3:15 pm     Reply with quote

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
dyeatman



Joined: 06 Sep 2003
Posts: 1934
Location: Norman, OK

View user's profile Send private message

PostPosted: Mon Aug 25, 2014 3:32 pm     Reply with quote

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!!!!
Ttelmah



Joined: 11 Mar 2010
Posts: 19545

View user's profile Send private message

PostPosted: Mon Aug 25, 2014 11:02 pm     Reply with quote

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.
KTrenholm



Joined: 19 Dec 2012
Posts: 43
Location: Connecticut, USA

View user's profile Send private message

PostPosted: Tue Aug 26, 2014 7:02 am     Reply with quote

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.
ezflyr



Joined: 25 Oct 2010
Posts: 1019
Location: Tewksbury, MA

View user's profile Send private message

PostPosted: Tue Aug 26, 2014 7:46 am     Reply with quote

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
Ttelmah



Joined: 11 Mar 2010
Posts: 19545

View user's profile Send private message

PostPosted: Tue Aug 26, 2014 7:47 am     Reply with quote

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.
KTrenholm



Joined: 19 Dec 2012
Posts: 43
Location: Connecticut, USA

View user's profile Send private message

PostPosted: Tue Aug 26, 2014 8:03 am     Reply with quote

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.
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

Testing, testing, testing
PostPosted: Tue Aug 26, 2014 8:16 am     Reply with quote

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
KTrenholm



Joined: 19 Dec 2012
Posts: 43
Location: Connecticut, USA

View user's profile Send private message

PostPosted: Tue Aug 26, 2014 8:27 am     Reply with quote

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)
Ttelmah



Joined: 11 Mar 2010
Posts: 19545

View user's profile Send private message

PostPosted: Tue Aug 26, 2014 9:46 am     Reply with quote

Interesting.

I'd add an 'output toggle', and see where it gets to.
Ttelmah



Joined: 11 Mar 2010
Posts: 19545

View user's profile Send private message

PostPosted: Tue Aug 26, 2014 10:55 pm     Reply with quote

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
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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