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

RS232 Questions : 18F452 38400 baud, data looks wrong
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
jemly



Joined: 13 May 2007
Posts: 34

View user's profile Send private message

RS232 Questions : 18F452 38400 baud, data looks wrong
PostPosted: Tue Oct 02, 2007 9:02 am     Reply with quote

I'm am trying to receive RS232 data being sent by a piece of software on the PC. The software sends the data out 50 times a second at a baud rate of 38400. I've started with the example file supplied with CCS and have modifed the settings for my needs so my use directive looks like this:

#use delay(clock=19660800)
#use rs232(baud=38400,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,errors,brgh1ok)


I am successfully receiving data in the #int_rda ISR and am watching the data as it arrives in the log window. We keep receiving values that we know are not being sent from the PC - is it possible that the data type is an issue here? Is there any other reason the data I am watching arrive seems completely wrong??
jecottrell



Joined: 16 Jan 2005
Posts: 559
Location: Tucson, AZ

View user's profile Send private message

PostPosted: Tue Oct 02, 2007 10:13 am     Reply with quote

How much data 50 times a second? (total bytes?)

What does your ISR look like?

Can you slow things down from the PC side for debugging?
jemly



Joined: 13 May 2007
Posts: 34

View user's profile Send private message

PostPosted: Tue Oct 02, 2007 11:27 am     Reply with quote

They send 44 bytes of data - 36 bytes of the info we need to use, followed by 4 bytes of checksum data, and finally 4 bytes of signal data to show the end of this section is reached.

We can't slow things down from the PC side at all unfortunately. What I'd like to see is a real time log of the data coming in - at the moment if I use the log window in CCS to log my breakpoint in the #int_rda ISR I see the buffer array (size 44) and I can see it filling up with numbers but the numbers are incorrect. What data type is shown in the log or watch window by default and how can I change it?

Or am I doing this the wrong way and is there a better way to check the data coming in? I'll post the ISR routine tmrw when I'm back in the office.
jecottrell



Joined: 16 Jan 2005
Posts: 559
Location: Tucson, AZ

View user's profile Send private message

PostPosted: Tue Oct 02, 2007 1:09 pm     Reply with quote

My math shows that is a nonstop data-stream. I'm not sure how much processor time will be left for doing anything other than receiving data.

Do you need every 44byte packet? (If not you can ignore some of them to regain some processor time.)

What is the format of the packet? Is there a fixed header that indicates the start of the packet?

Details... more details.
Ttelmah
Guest







PostPosted: Tue Oct 02, 2007 3:02 pm     Reply with quote

Obvious question for 'unexpected data'. How is the connection made?.

Best Wishes
jemly



Joined: 13 May 2007
Posts: 34

View user's profile Send private message

PostPosted: Wed Oct 03, 2007 2:22 am     Reply with quote

Thanks for the responses:

jecottrell - that is exactly what we are thinking - there is just so much data! Strangely they don't send a start byte they send 4 bytes of data as an end signal. Each packet is 36 bytes of data we need to use, then 4 bytes of checksum, then the 4 byte end signal.

How could we selectively ignore the incoming data to say only read every other packet?

Ttelmah - Sorry I'm not quite sure what you mean? Could you clarify (apologies for my ignorance!)

My ISR is like this:

Code:

#int_rda
void serial_isr() {
   int t;
   
   byte p;
   int i;
   foundPt = 0;
   
   p = getc();
   
   buffer[next_in]=p;
   
   if(next_in > 3)
   {
      if(buffer[next_in] == 127 & buffer[next_in - 1] == 128 & buffer[next_in - 2] == 0 & buffer[next_in - 3] == 0)
     {
         startSignalFound = true;
         foundPt = next_in +1;
     }
   }
   
   t=next_in;
   next_in=(next_in+1) % BUFFER_SIZE;
   if(next_in==next_out)
   {
      next_in=t;           // Buffer full !!
      for (i=0;i<16;i++) buffer[i]=' ';
   }
   
   // If any errors occur clear the rs232 buffer and reset the index.
      if((rs232_errors!=144)&&(rs232_errors!=0))
      {
         next_in=0;
         for (i=0;i<16;i++) buffer[i]=' ';
      }

   
}


My main is like this:

Code:


void main() {
   int i;
   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_OFF);
   setup_psp(PSP_DISABLED);
   setup_spi(SPI_SS_DISABLED);
   setup_wdt(WDT_OFF);
   setup_timer_0(RTCC_INTERNAL);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   
   enable_interrupts(global);
   enable_interrupts(int_rda);

   do {
      while(bkbhit)
      {
        output_bit(PIN_B3,1);
        putc(bgetc());
      }

      output_bit(PIN_B3,0);
     
      if(startSignalFound)
      {
         for (i=0;i<16;i++) data[i] = buffer[foundPt];
      }
   } while (TRUE);
}


and the only other bits of code are:

Code:

#define bkbhit (next_in!=next_out)

BYTE bgetc() {
   BYTE c;

   while(!bkbhit) ;
   c=buffer[next_out];
   next_out=(next_out+1) % BUFFER_SIZE;
   return(c);
}


This is all based on the PICC serial example.

Any help massively appreciated!
Foppie



Joined: 16 Sep 2005
Posts: 138
Location: The Netherlands

View user's profile Send private message Send e-mail Visit poster's website MSN Messenger

PostPosted: Wed Oct 03, 2007 4:15 am     Reply with quote

To selectively ingore incoming data you could try something like this:

Code:
#INT_RDA
void serial_isr()
{
   char c;

   c = getc();

   if (ready_to_receive)
   {
      buffer[index] = c;
      index++;

      if (index == 4) //4 bytes received
      {
         if (!((buffer[0] == 0) &&
               (buffer[1] == 0) &&
               (buffer[2] == 128) &&
               (buffer[3] == 127)))
         {
            buffer[0] = buffer[1];
            buffer[1] = buffer[2];
            buffer[2] = buffer[3];
            index--;
         }
      }

      if (index == 44)
      {
         ready_to_receive = false;
         data_received = true;
      }     
   }
}


this works with these globals:
Code:
int index = 0;
char buffer[44];
int1 ready_to_receive = false;
int1 data_received = false;


As you can see I use the 4 bytes end signal as the start of the packet.
You can now, in your code wait for data_received to go to 1 and then you know that a packet has been received that must be evaluated.

to start searching for the next data packet you need something like:
Code:
void search_again()
{
   data_received = false;
   index = 0;
   ready_to_receive = true; //must be last!
}


Note that buffer is -NOT- a string.
Ttelmah
Guest







PostPosted: Wed Oct 03, 2007 4:49 am     Reply with quote

How is the actual electical connection made to the pins?.
Have you simply tested sending a smaller, and slower message, from a terminal program on the PC, to verify that the wiring is working?.
Remember that the pins on the PIC expect to see 'logic level' (5v) serial data, that is level inverted from what is on the 'RS232' wires. A wrong connection, would result in garbage bing received...

Best Wishes
jemly



Joined: 13 May 2007
Posts: 34

View user's profile Send private message

PostPosted: Wed Oct 03, 2007 4:56 am     Reply with quote

Thanks foppie, I will give that a go. Ttelmah the wiring is absolutely fine and has been fully tested. It's definitely a speed and/or software problem.
SherpaDoug



Joined: 07 Sep 2003
Posts: 1640
Location: Cape Cod Mass USA

View user's profile Send private message

PostPosted: Wed Oct 03, 2007 7:33 am     Reply with quote

jecottrell wrote:
My math shows that is a nonstop data-stream. I'm not sure how much processor time will be left for doing anything other than receiving data.


10 bits/byte * 44 bytes * 50 messages / 38400 bits/sec = 0.573 seconds or 57% duty cycle. That is not too bad, far from non-stop. Am I missing something?
_________________
The search for better is endless. Instead simply find very good and get the job done.
Ttelmah
Guest







PostPosted: Wed Oct 03, 2007 7:34 am     Reply with quote

OK. Lets make some comments. First thing, change your buffer size to 64bytes. The problem is that a 44 byte buffer, implies that the function:

next_in=(next_in+1) % BUFFER_SIZE;

Will take a _lot_ of time. It involves performing a division by 44, and then taking the remainder of this. Typically something over 130 instruction times. The same function done with a 'binary multiple' buffer size (2,4,8,16 etc. bytes), takes only a couple of instructions (it is performed using a logical '&').
Now, the idea shown by Foppie, is another way of removing this problem, and speeding up the search in the buffer for the data you want.
Your 'rate', is not impossible. It only represents one character every 260uSec, and even at your clock rate, you have 1280 instruction times between interrupts. However thre is potential huge problem in the timing of the ISR. Array accesses are _slow_ Typically take anything from 10 to 20 machine instructions each. Each time round the ISR, you are performing five such accesses, to do the logic test for what data you have found. Think differently about this. Consider a 'state machine'.
Something like:
Code:

#int_rda
void serial_isr() {
   static int8 state=0;
   int t;
   byte p;
   int i;
   foundPt = 0;
   
   p = getc();
   buffer[next_in]=p;
   //increment 'next_in' _first_. Remember it needs to wrap
   t=next_in;
   next_in=(next_in+1) % BUFFER_SIZE;

   switch (state) {
   case 0:
      //Now, I am slightly 'worried' by your logic. Next_in, could perfectly
      //well be '0', with a legitimate packet received. Remember it _loops_
      if (p==0) state=1;
      break;
   case 1:
      if (p==0) state=2;
      else state=0;
      break;
   case 2:
      if (p==128) {
         state=3;
         break;
      else if (p==0) state=1;
      else state=0;
      break;
   case 3:
      if (p==127) {
         startSignalFound = true;
         foundPt = next_in; //This has already been incremented
         break;
      }
      else if (p==0) state=1;
      else state=0;
      break;
   }
}

Now, there are some real problems with your code. You are using a circular buffer, but at times are treating it as a linear buffer. remember if the address has wrapped at the top of the buffer, the _last_ address, would be right at the other end of the buffer, not one byte back. Also, why overwrite data on errors. This is taking far too long. just reset the pointers if needed.
jecottrell



Joined: 16 Jan 2005
Posts: 559
Location: Tucson, AZ

View user's profile Send private message

PostPosted: Wed Oct 03, 2007 8:37 am     Reply with quote

SherpaDoug wrote:
10 bits/byte * 44 bytes * 50 messages / 38400 bits/sec = 0.573 seconds or 57% duty cycle. That is not too bad, far from non-stop. Am I missing something?


Strangely enough, I used the exact same math, but came up with a result of just under 38400, repeatedly! Even, re-checked it just now while using your numbers and got the same result once. But after that always got the correct answer. I use a 20y/o TI solar calculator that I pull out of my desk drawer for quickie calcs. I'm starting to get the feeling it may be the culprit. (I know for a fact it can't do sin/cos/tan calcs correctly.... geez, that almost killed me trying to figure that one out.)

The nice thing is, when I try to help, it usually attracts all the pros to correct my crap and the OP gets quality help....quick.
jemly



Joined: 13 May 2007
Posts: 34

View user's profile Send private message

PostPosted: Wed Oct 03, 2007 10:49 am     Reply with quote

Wow thank you so much - that all makes great sense. I probably won't be able to post again until Tuesday unfortunately but many thanks for all the time you have put into this. I'll post questions and / or final solutions as and when I get them.
jemly



Joined: 13 May 2007
Posts: 34

View user's profile Send private message

PostPosted: Tue Oct 09, 2007 6:11 am     Reply with quote

Ok I firstly am now running my 18F452 at 39.3216 MHz by using a 9.830400 MHz oscillator and internal 4xPLL. At least I hope I have ! Here are my fuse settings:

Code:

#FUSES H4                       //High speed osc with HW enabled 4X PLL
#use delay(clock=39321600)


I have made some changes to the code but am still getting similar results - I have also realised that I do not fully understand how to use buffers and flags to ensure I never miss any received data.

Could someone give me an explanation - not necessarily code but just an overview of how it should happen? i.e. buffer[i] will be filled with up to 64 characters at any one time, when position 643 is filled it will strat being filled from position 0 again. Before anything gets overwritten I need to be able to ensure that I have taken out the data that I need. How do I ensure this happens?

Right now what I really need is a program that will receive all incoming data, each time the start condition is seen it should save the next 32 characters which will then be immediately sent out via RS232 on a different stream. I am sorry for asking for so much help but I do not seem to be making much headway...... many thanks.
jemly



Joined: 13 May 2007
Posts: 34

View user's profile Send private message

PostPosted: Tue Oct 09, 2007 6:11 am     Reply with quote

Sorry - where it says 'position 643' above, it should read 'position 63'.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
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