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 support@ccsinfo.com

Help: How to receive serial data without losses

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



Joined: 31 May 2007
Posts: 11

View user's profile Send private message

Help: How to receive serial data without losses
PostPosted: Tue Jul 17, 2007 12:30 pm     Reply with quote

Hi:

I'm working on an application that requires to receive serial data, process it (som XOR operations), and then send it back. Also, i need to send a synchrony sequence in between, but without losing any bytes. This is my attempt at coding:

Code:

#include <18F252.h>
#fuses HS,NOWDT,NOPROTECT
#use delay(clock=20000000)
#use rs232(baud=9600, parity=N, bits=8, xmit=PIN_C6, rcv=PIN_C7, ERRORS)

#define nop delay_cycles(1)   // nop;
#byte PORTB = 0x0F81

int sync = 0, fullb = 0;
int data = 0;
int i = 0, j = 0, k = 0;
int inbuff[4],outbuff[4];
int32 ctr = 0;

#INT_RDA
void serial_isr()
{
   inbuff[i] = getc();
   i++;
   
   if(i==4)
   {
      i = 0;

      outbuff[0] = inbuff[0];
      outbuff[1] = inbuff[1];
      outbuff[2] = inbuff[2];
      outbuff[3] = inbuff[3];

      fullb = 1;
   }
}

void main(void)
{
   enable_interrupts(GLOBAL);
   enable_interrupts(INT_RDA);   

   for(i=0;i<4;i++)
   {
      inbuff[i] = 0;
      outbuff[i] = 0;
   }

   i = 0;

   while(1)
   {

      nop;
   
      if(sync == 1)
      {
         k++;

         putc(0xFF);
         putc(0xFF);
         putc(0x00);               
         putc(k);

         sync = 0;
      }

      if(fullb == 1)
      {
         putc(outbuff[j] ^ 0x20);
         ctr++;
         j++;

         if(j==4)
         {
            j = 0;
            fullb = 0;
         }

         if(!(ctr%16))
            sync = 1;
      }

   }

}


·Basically, i should receive this sequence

Code:

A B C D E F G H I J K L M N O P Q R S T U V W X Y Z A B C D E F G H


and then send back this sequence:

Code:

a b c d e f g h i j k l m n o p (0xFF) (0xFF) (ctr1) (ctr2) q r s t u v w x y z a b c d e f (0xFF) (0xFF) (ctr1) (ctr2)


*Last 2 bytes (G,H) should be stored until another 2 bytes are received.

·I've got two problems:

*When i simulate in MPLAB, it starts alright, but suddenly it stops transmitting (TXREG registers does not update!).
*When programming a PIC and running a serial terminal, the 4 byte routine works just fine, but the 16 byte sync secuence causes to lose 4 bytes. This is specially true when sending a sequence longer than 16 bytes.

·If anyone can give me a hand at this, i'll really appreciate it. I need to put that sync sequence in between, but i can't lose data.

Best regards,
Foxtrot Mike
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Jul 17, 2007 4:01 pm     Reply with quote

Basic suggestion -- use a real receive buffer.
See the CCS example file, Ex_sisr.c. Here's the file location:
Quote:
c:\Program Files\PICC\Examples\Ex_sisr.c
FoxtrotMike



Joined: 31 May 2007
Posts: 11

View user's profile Send private message

PostPosted: Tue Jul 17, 2007 7:36 pm     Reply with quote

Thanks... I'll look it up
SET



Joined: 15 Nov 2005
Posts: 161
Location: Glasgow, UK

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

PostPosted: Wed Jul 18, 2007 11:54 am     Reply with quote

In general what your doing looks ok. But what happens if your the number of incoming bytes is not divisible by 4?. Then your 4 byte buffer will never be filled and you wont get those ones back - is this what you saw in the sim?
Bill Boucher



Joined: 04 Feb 2005
Posts: 34
Location: Chatham,ON,CA

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

PostPosted: Wed Jul 18, 2007 7:04 pm     Reply with quote

I was reading somewhere that the compiler will automatically disable interrupts while doing certain functions that are timing sensitive such as putc(). That said, when the program tries to transmit 4 bytes in a row using sequential putc() lines, could it be that interrupts are off throughout them and that the incoming data interrupt is not being immediately serviced and so the 2-byte receive buffer overflows?

I didn't look at the 18F252 datasheet to check the uart pin numbers but I assume you're using the hardware Tx & Rx pins. The Tx buffer is also 2 bytes deep so when the four putc() lines run, the first 2 execute very fast because all they do is load the bytes into the hardware buffer, but the next 2 putc() lines each have to wait until the buffer is ready to accept more data, that is until the first 2 bytes are done transmitting. That causes a couple ms delay. Could a byte or two being received during this time be dropped? I wonder.

If you create a r_buffer[] array var, and a t_buffer[] array var, then set up the int_rda and int_tbe interrupts with code that simply moves hardware-received data into r_buffer[] and data from the t_buffer[] to the hardware-transmit register (using putc) just one byte at a time when the interrupts occur, then you won't lose any data. Pointers are used to tell the ISR's where to read/write data from/to.

Example:
Code:


#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, Parity=N, Bits=8, ERRORS)
//-----------------------------------------------------
// constants and vars used for commport communications:
#define R_BUFFER_SIZE 32
byte r_buffer[R_BUFFER_SIZE];
byte r_next_in = 0;
byte r_next_out = 0;

#define T_BUFFER_SIZE 32
byte t_buffer[T_BUFFER_SIZE];
byte t_next_in = 0;
byte t_next_out = 0;

//-----------------------------------------------------
// commport communications: buffered, interrupt & hardware driven
#INT_TBE
void t_serial_isr() {
   putc(t_buffer[t_next_out]);
   t_next_out = (t_next_out + 1) % T_BUFFER_SIZE;
   if(t_next_in == t_next_out)
      {
    disable_interrupts(int_tbe);
   }
}

// bputc() modified to prevent lockups:
void bputc(char c) {
   short restart;
   int ni;
   restart = t_next_in == t_next_out;
   t_buffer[t_next_in] = c;
   ni=(t_next_in + 1) % T_BUFFER_SIZE;
   while(ni == t_next_out)
         {
         enable_interrupts(int_tbe); //make sure int_tbe is enabled to provide exit (assuming this triggers int)
         }
   t_next_in = ni;
   if(restart)
      {
      enable_interrupts(int_tbe);
      }
}

//original copy of bputc() below, modified above:
//void bputc(char c) {
//   short restart;
//   int ni;
//   restart = t_next_in == t_next_out;
//   t_buffer[t_next_in] = c;
//   ni=(t_next_in + 1) % T_BUFFER_SIZE;
//   while(ni == t_next_out);   //can this line freeze the system if int_tbe is off?
//   t_next_in = ni;
//   if(restart) enable_interrupts(int_tbe);   //original location
//}


#INT_RDA
void r_serial_isr() {
   int t;


   r_buffer[r_next_in] = getc();
   t = r_next_in;
   r_next_in = (r_next_in + 1) % R_BUFFER_SIZE;
   if(r_next_in == r_next_out)
   r_next_in = t;           // Buffer full !!

}

#define bkbhit (r_next_in != r_next_out)

BYTE bgetc() {
   BYTE c;

// The following line is not needed so long as bkbhit() is polled before calling bgetc().
//   while(!bkbhit) ;   //this line can freeze the system if called when no data exists and none is coming in.
   c = r_buffer[r_next_out];
   r_next_out = (r_next_out + 1) % R_BUFFER_SIZE;
   return(c);
}
//-----------------------------------------------------

somewhere in main()
int8 Temp_Data;
//if (bkbhit)  //or
while (bkbhit)
   {
   Temp_Data = bgetc();
   //blah blah blah I'm doing something with data here
   }

// and to send some data out...
   bputc(Temp_Data);



And the interrupts take care of getting the data in and out of the ram buffers and they can store up to the buffer size (in this example 32 bytes incoming and 32 outgoing).
temopic



Joined: 20 Feb 2008
Posts: 27
Location: mexico

View user's profile Send private message MSN Messenger

PostPosted: Thu Mar 06, 2008 10:03 pm     Reply with quote

Can I use similar buffers for SPI interrupts?

Ex_sisr.c
Douglas Kennedy



Joined: 07 Sep 2003
Posts: 755
Location: Florida

View user's profile Send private message AIM Address

PostPosted: Fri Mar 07, 2008 5:10 am     Reply with quote

Circular buffers are useful for any I/O both with and without flow control.
Flow control is always the complete answer.
The isr driven circular buffer is extremely useful and often the only way to get RS232 to work reliably. However the circular buffer is still no more than a shock absorber in that is smooths out bursts of Rs232 data both in and out(if you use it for output as well) and allows more flexiblity in that the PIC code doesn't need to be conformed to such a tight loop around kbhit(). Without flow control the PIC design must be able to do its work and not mess up the average ( no overflows of buffers on either input or output). Consider an example where for every character received two are sent out. If there is no flow control and the input is a continuous unbroken stream of characters then an output buffer overflow is guaranteed ( assuming input baud rate is equal to the output baud rate).
temopic



Joined: 20 Feb 2008
Posts: 27
Location: mexico

View user's profile Send private message MSN Messenger

PostPosted: Fri Mar 07, 2008 10:16 am     Reply with quote

Thank you Douglas
Could some body help make circular buffers for SPI in and out?

My code seems to get stucked after a SPI interrupt not allowing int_rda arrive
Douglas Kennedy



Joined: 07 Sep 2003
Posts: 755
Location: Florida

View user's profile Send private message AIM Address

PostPosted: Fri Mar 07, 2008 8:50 pm     Reply with quote

The examples above in this code show a circular buffer. I wouldn't use modulo % division. A simple test of the counter to see if it has reached the end of the buffer and a reset to zero if true is best practice. CCS has examples to look at that plus with the code above you should enable you to make progress.
temopic



Joined: 20 Feb 2008
Posts: 27
Location: mexico

View user's profile Send private message MSN Messenger

PostPosted: Sat Mar 08, 2008 1:33 pm     Reply with quote

thanks again douglas
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