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

Interrupt delay on receiving serial data..

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







Interrupt delay on receiving serial data..
PostPosted: Fri Jun 27, 2003 10:36 am     Reply with quote

Hello..

I have a problem that I hope someone can sort out for me. I have an application where I'm transmitting data from a PC to a 16f877, using half duplex RS485. My problem is that when I'm sending a string of more than two characters (the characters are being sent without any delay between them), the UART buffer overflows (OERR is set high). I'm using serial interrupt to receive the string.

I'm aware that the UART has a two byte hardware buffer, but the problem seems to be that the PIC has an delay between the reception of the first character and the entering of the interrupt routine. I suspect (know?) this because if I send a single character and then send my string the reception works just fine.

If anyone could help me out here, I would be grateful. My code is under. (Its just a test code to illustrate my problem).


#include <16F877.H>

#fuses XT,NOWDT,NOPROTECT,NOCPD,NOLVP,NOWRT,NOBROWNOUT
#use delay(clock=3686400)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, parity=N, bits=8)

#define ANALOG_SUPPLY PIN_C0 // Turns on/off analog PS
#define RS485_DE PIN_B0 // DataEnable pin (RS485-tranc.)
#define RS485_RE PIN_B1 // RecEnable pin (RS485-tranc.)

// Recive() and transmit() is just for setting the
// Data enable and Recieve enable pins on the RS485 tranciever
// chip (MAX3082)

void recieve(){
output_low(RS485_DE);
output_low(RS485_RE);}

void transmit(){
output_high(RS485_DE);
output_high(RS485_RE);}


#int_RDA

isr(){

int i, j;
char buffer[20];


// Recieves incoming datastream untill
// enter is recieved, or OERR flag is set
i = 0;
while((buffer[i - 1] != 13) && !(bit_test(*0x18, 1))){
buffer[i] = getc();
i++;
}

transmit(); // Puts the RS485 tranciever in TX-mode


// Prints out an indication if the OERR flag is set
// The UART is also resat.
if (bit_test(*0x18, 1)){
printf("\r\n OERR high \r\n");
bit_clear(*0x18, 4);
bit_set(*0x18, 4);}

// Prints out the contents of the buffer

j = 0;
while (j < i){
putc(buffer[j]);
j++;}

printf("\r\n");

// Clears the buffer
for (j=0; j<20; j++)
buffer[j] = ' ';

delay_ms(5);
recieve();} // Puts the RS485 tranciever in RX-mode


main(){

enable_interrupts(int_rda);
enable_interrupts(global);

output_high(ANALOG_SUPPLY);
output_high(RS485_RE);
output_low(RS485_DE);

transmit();
printf("\r\nstart..\r\n");
delay_ms(3);


while(true){
recieve();
delay_ms(50);}

}
___________________________
This message was ported from CCS's old forum
Original Post ID: 144515609
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

Re: Interrupt delay on recieving serial data..
PostPosted: Fri Jun 27, 2003 1:15 pm     Reply with quote

<font face="Courier New" size=-1>:=I have a problem that I hope someone can sort out for me. I have an application where I'm transmitting data from a PC to a 16f877, using half duplex RS485. My problem is that when I'm sending a string of more than two characters (the characters are being sent without any delay between them), the UART buffer overflows (OERR is set high). I'm using serial interrupt to receive the string.
------------------------------------------------------------

There are a few micro-seconds of interrupt latency time,
because it takes some time to execute the CCS interrupt
dispatcher code. This code determines the cause of the
interrupt, and then jumps to the appropriate isr.
But's that not normally an issue for a properly designed
program.

I suggest that you remove most of the code that you have
in the int_rda routine. In the int_rda routine, you should
just receive one char, put it into a circular buffer, and exit.
Each time a new char comes into the hardware UART, you will
get an interrupt. Each interrupt will put the new char into
the circular buffer. That's all it does.
Handle the incoming characters in the main() code, by checking
a count variable, to see if there any chars available, and
then if so, read them from the circular buffer.

Also, add the ERRORS directive to the #use rs232 statement,
to clear any overrun errors that may occur.

A few recent posts on RS485:
How to get Julian Winpenny's code to compile for CCS:
<a href="http://www.pic-c.com/forum/general/posts/144515101.html" TARGET="_blank"> <a href="http://www.pic-c.com/forum/general/posts/144515101.html" TARGET="_blank">http://www.pic-c.com/forum/general/posts/144515101.html</a></a>
Darren Logan's comments on that code:
<a href="http://www.pic-c.com/forum/general/posts/144515155.html" TARGET="_blank"> <a href="http://www.pic-c.com/forum/general/posts/144515155.html" TARGET="_blank">http://www.pic-c.com/forum/general/posts/144515155.html</a></a>

A thread on properly using the enable pin:
Scroll down to the bottom of this link, and click on all
the replies, to see useful tips.
<a href="http://www.pic-c.com/forum/general/posts/144514929.html" TARGET="_blank"> <a href="http://www.pic-c.com/forum/general/posts/144514929.html" TARGET="_blank">http://www.pic-c.com/forum/general/posts/144514929.html</a></a></font>
___________________________
This message was ported from CCS's old forum
Original Post ID: 144515613
rifyhn
Guest







Re: Interrupt delay on recieving serial data..
PostPosted: Fri Jun 27, 2003 1:58 pm     Reply with quote

:=<font face="Courier New" size=-1>:=I have a problem that I hope someone can sort out for me. I have an application where I'm transmitting data from a PC to a 16f877, using half duplex RS485. My problem is that when I'm sending a string of more than two characters (the characters are being sent without any delay between them), the UART buffer overflows (OERR is set high). I'm using serial interrupt to receive the string.
:=------------------------------------------------------------
:=
:=There are a few micro-seconds of interrupt latency time,
:=because it takes some time to execute the CCS interrupt
:=dispatcher code. This code determines the cause of the
:=interrupt, and then jumps to the appropriate isr.
:=But's that not normally an issue for a properly designed
:=program.
:=
:=I suggest that you remove most of the code that you have
:=in the int_rda routine. In the int_rda routine, you should
:=just receive one char, put it into a circular buffer, and exit.
:=Each time a new char comes into the hardware UART, you will
:=get an interrupt. Each interrupt will put the new char into
:=the circular buffer. That's all it does.
:=Handle the incoming characters in the main() code, by checking
:=a count variable, to see if there any chars available, and
:=then if so, read them from the circular buffer.
:=
:=Also, add the ERRORS directive to the #use rs232 statement,
:=to clear any overrun errors that may occur.
:=
:=A few recent posts on RS485:
:=How to get Julian Winpenny's code to compile for CCS:
:= <a href="http://www.pic-c.com/forum/general/posts/144515101.html" TARGET="_blank"> <a href="http://www.pic-c.com/forum/general/posts/144515101.html" TARGET="_blank"> <a href="http://www.pic-c.com/forum/general/posts/144515101.html" TARGET="_blank">http://www.pic-c.com/forum/general/posts/144515101.html</a></a></a>
:=Darren Logan's comments on that code:
:= <a href="http://www.pic-c.com/forum/general/posts/144515155.html" TARGET="_blank"> <a href="http://www.pic-c.com/forum/general/posts/144515155.html" TARGET="_blank"> <a href="http://www.pic-c.com/forum/general/posts/144515155.html" TARGET="_blank">http://www.pic-c.com/forum/general/posts/144515155.html</a></a></a>
:=
:=A thread on properly using the enable pin:
:=Scroll down to the bottom of this link, and click on all
:=the replies, to see useful tips.
:= <a href="http://www.pic-c.com/forum/general/posts/144514929.html" TARGET="_blank"> <a href="http://www.pic-c.com/forum/general/posts/144514929.html" TARGET="_blank"> <a href="http://www.pic-c.com/forum/general/posts/144514929.html" TARGET="_blank">http://www.pic-c.com/forum/general/posts/144514929.html</a></a></a></font>

First of all I would like to thank for your immidiate and good respons to my problem.

I worked out another version of my program, where I only recieved one character at a time in my interrupt program(like You said). And it really solved the recieving part, with the new code it was really no problem to recieve a large string of incomming characters.

But things arent supposed to be easy..

My reason for putting the reception of all the characters in the interrupt, was that my system will implemtent many pic-controllers attached to the RS485 bus. The controllers need to respond quicly to (addressed)commands given from a PC. I therefore thought it was a good idea to put the reception(of all the adress and command bytes thats beeing sent from the PC)and respond in the interrupt routine, as my main program is a regulation loop that may take up to about 500ms to execute.

Nevertheless I will work something out for that problem in the weekend, main thing now is that I solved my recieving problem.

Thanks again, and have a nice weekend :-)
___________________________
This message was ported from CCS's old forum
Original Post ID: 144515614
Neutone



Joined: 08 Sep 2003
Posts: 839
Location: Houston

View user's profile Send private message

Re: Interrupt delay on recieving serial data..
PostPosted: Fri Jun 27, 2003 2:17 pm     Reply with quote

:=:=<font face="Courier New" size=-1>:=I have a problem that I hope someone can sort out for me. I have an application where I'm transmitting data from a PC to a 16f877, using half duplex RS485. My problem is that when I'm sending a string of more than two characters (the characters are being sent without any delay between them), the UART buffer overflows (OERR is set high). I'm using serial interrupt to receive the string.
:=:=------------------------------------------------------------
:=:=
:=:=There are a few micro-seconds of interrupt latency time,
:=:=because it takes some time to execute the CCS interrupt
:=:=dispatcher code. This code determines the cause of the
:=:=interrupt, and then jumps to the appropriate isr.
:=:=But's that not normally an issue for a properly designed
:=:=program.
:=:=
:=:=I suggest that you remove most of the code that you have
:=:=in the int_rda routine. In the int_rda routine, you should
:=:=just receive one char, put it into a circular buffer, and exit.
:=:=Each time a new char comes into the hardware UART, you will
:=:=get an interrupt. Each interrupt will put the new char into
:=:=the circular buffer. That's all it does.
:=:=Handle the incoming characters in the main() code, by checking
:=:=a count variable, to see if there any chars available, and
:=:=then if so, read them from the circular buffer.
:=:=
:=:=Also, add the ERRORS directive to the #use rs232 statement,
:=:=to clear any overrun errors that may occur.
:=:=
:=:=A few recent posts on RS485:
:=:=How to get Julian Winpenny's code to compile for CCS:
:=:= <a href="http://www.pic-c.com/forum/general/posts/144515101.html" TARGET="_blank"> <a href="http://www.pic-c.com/forum/general/posts/144515101.html" TARGET="_blank"> <a href="http://www.pic-c.com/forum/general/posts/144515101.html" TARGET="_blank"> <a href="http://www.pic-c.com/forum/general/posts/144515101.html" TARGET="_blank">http://www.pic-c.com/forum/general/posts/144515101.html</a></a></a></a>
:=:=Darren Logan's comments on that code:
:=:= <a href="http://www.pic-c.com/forum/general/posts/144515155.html" TARGET="_blank"> <a href="http://www.pic-c.com/forum/general/posts/144515155.html" TARGET="_blank"> <a href="http://www.pic-c.com/forum/general/posts/144515155.html" TARGET="_blank"> <a href="http://www.pic-c.com/forum/general/posts/144515155.html" TARGET="_blank">http://www.pic-c.com/forum/general/posts/144515155.html</a></a></a></a>
:=:=
:=:=A thread on properly using the enable pin:
:=:=Scroll down to the bottom of this link, and click on all
:=:=the replies, to see useful tips.
:=:= <a href="http://www.pic-c.com/forum/general/posts/144514929.html" TARGET="_blank"> <a href="http://www.pic-c.com/forum/general/posts/144514929.html" TARGET="_blank"> <a href="http://www.pic-c.com/forum/general/posts/144514929.html" TARGET="_blank"> <a href="http://www.pic-c.com/forum/general/posts/144514929.html" TARGET="_blank">http://www.pic-c.com/forum/general/posts/144514929.html</a></a></a></a></font>
:=
:=First of all I would like to thank for your immidiate and good respons to my problem.
:=
:=I worked out another version of my program, where I only recieved one character at a time in my interrupt program(like You said). And it really solved the recieving part, with the new code it was really no problem to recieve a large string of incomming characters.
:=
:=But things arent supposed to be easy..
:=
:=My reason for putting the reception of all the characters in the interrupt, was that my system will implemtent many pic-controllers attached to the RS485 bus. The controllers need to respond quicly to (addressed)commands given from a PC. I therefore thought it was a good idea to put the reception(of all the adress and command bytes thats beeing sent from the PC)and respond in the interrupt routine, as my main program is a regulation loop that may take up to about 500ms to execute.
:=
:=Nevertheless I will work something out for that problem in the weekend, main thing now is that I solved my recieving problem.
:=
:=Thanks again, and have a nice weekend :-)

Concider this. You have an loop in main that takes under 5 mS to complete. During each loop you check to see if a complete packet has been recieved by an interupt driven routine. If during main you find that a flag is set indicating a complete packet you decode it and create a reply. Decoding and creating a reply takes about 2 mS. A reply of 30 bytes at 9600 baud takes 30 mS. You keep running your loop and the reply is handeled by a transmit interupt. You never miss a beat with your process. Basicly think about how you can move code out of the interupts and into main.
___________________________
This message was ported from CCS's old forum
Original Post ID: 144515615
R.J.Hamlett
Guest







Re: Interrupt delay on recieving serial data..
PostPosted: Fri Jun 27, 2003 3:52 pm     Reply with quote

:=:=<font face="Courier New" size=-1>:=I have a problem that I hope someone can sort out for me. I have an application where I'm transmitting data from a PC to a 16f877, using half duplex RS485. My problem is that when I'm sending a string of more than two characters (the characters are being sent without any delay between them), the UART buffer overflows (OERR is set high). I'm using serial interrupt to receive the string.
:=:=------------------------------------------------------------
:=:=
:=:=There are a few micro-seconds of interrupt latency time,
:=:=because it takes some time to execute the CCS interrupt
:=:=dispatcher code. This code determines the cause of the
:=:=interrupt, and then jumps to the appropriate isr.
:=:=But's that not normally an issue for a properly designed
:=:=program.
:=:=
:=:=I suggest that you remove most of the code that you have
:=:=in the int_rda routine. In the int_rda routine, you should
:=:=just receive one char, put it into a circular buffer, and exit.
:=:=Each time a new char comes into the hardware UART, you will
:=:=get an interrupt. Each interrupt will put the new char into
:=:=the circular buffer. That's all it does.
:=:=Handle the incoming characters in the main() code, by checking
:=:=a count variable, to see if there any chars available, and
:=:=then if so, read them from the circular buffer.
:=:=
:=:=Also, add the ERRORS directive to the #use rs232 statement,
:=:=to clear any overrun errors that may occur.
:=:=
:=:=A few recent posts on RS485:
:=:=How to get Julian Winpenny's code to compile for CCS:
:=:= <a href="http://www.pic-c.com/forum/general/posts/144515101.html" TARGET="_blank"> <a href="http://www.pic-c.com/forum/general/posts/144515101.html" TARGET="_blank"> <a href="http://www.pic-c.com/forum/general/posts/144515101.html" TARGET="_blank"> <a href="http://www.pic-c.com/forum/general/posts/144515101.html" TARGET="_blank">http://www.pic-c.com/forum/general/posts/144515101.html</a></a></a></a>
:=:=Darren Logan's comments on that code:
:=:= <a href="http://www.pic-c.com/forum/general/posts/144515155.html" TARGET="_blank"> <a href="http://www.pic-c.com/forum/general/posts/144515155.html" TARGET="_blank"> <a href="http://www.pic-c.com/forum/general/posts/144515155.html" TARGET="_blank"> <a href="http://www.pic-c.com/forum/general/posts/144515155.html" TARGET="_blank">http://www.pic-c.com/forum/general/posts/144515155.html</a></a></a></a>
:=:=
:=:=A thread on properly using the enable pin:
:=:=Scroll down to the bottom of this link, and click on all
:=:=the replies, to see useful tips.
:=:= <a href="http://www.pic-c.com/forum/general/posts/144514929.html" TARGET="_blank"> <a href="http://www.pic-c.com/forum/general/posts/144514929.html" TARGET="_blank"> <a href="http://www.pic-c.com/forum/general/posts/144514929.html" TARGET="_blank"> <a href="http://www.pic-c.com/forum/general/posts/144514929.html" TARGET="_blank">http://www.pic-c.com/forum/general/posts/144514929.html</a></a></a></a></font>
:=
:=First of all I would like to thank for your immidiate and good respons to my problem.
:=
:=I worked out another version of my program, where I only recieved one character at a time in my interrupt program(like You said). And it really solved the recieving part, with the new code it was really no problem to recieve a large string of incomming characters.
:=
:=But things arent supposed to be easy..
:=
:=My reason for putting the reception of all the characters in the interrupt, was that my system will implemtent many pic-controllers attached to the RS485 bus. The controllers need to respond quicly to (addressed)commands given from a PC. I therefore thought it was a good idea to put the reception(of all the adress and command bytes thats beeing sent from the PC)and respond in the interrupt routine, as my main program is a regulation loop that may take up to about 500ms to execute.
:=
:=Nevertheless I will work something out for that problem in the weekend, main thing now is that I solved my recieving problem.
:=
:=Thanks again, and have a nice weekend :-)
If the units are 'responding' to a code, consider a state machine inside the interrupt, which simply tests the received character, and changes state. The main code can check the condition of this, and send the responses.

Also consider interrupt driven transmit as well.
I use this code:

/* These are the RS232 I/O functions */
/* ----------------------------------------------------------------------------------- */

//Buffer tests and handling
#define isempty(buff,free,in,out,size) (free>=size)
#define isfull(buff,free,in,out,size) (free<2)
#define tobuff(buff,free,in,out,size,chr) {buff[in++]=chr;\
--free;\
in=(in & (size-1));}
/* note seperate 'in, out, size' values, allow the handling to be fast */

void tchar(unsigned int chr)
{
/* routine to send one character on the RS232.
This puts the specified character into the software transmit buffer (if data is allready
being transmitted), or else sends the single character to the RS232 UART. */
/* First check if the interrupt is enabled, and if not, write directly */
if ((BIT_TEST(PIE1,4)==0) && (isempty(RSTbuff,RSTcount,RSTin,RSTout,STBUFF)))
{
/* Wait if the TX buffer has not cleared */
while (BIT_TEST(PIR1,TXIF)==0) ;
/* send character */
TXREG=chr;
}
else
{
/* Hold transmission if the buffer is full */
while (isfull(RSTbuff,RSTcount,RSTin,RSTout,STBUFF)) {
if (BIT_TEST(PIR1,TXIF)==1) {
/* Here the transmit hardware buffer is empty */
TXREG=RSTfrom();
}
}
/* put character into the output buffer */
tobuff(RSTbuff,RSTcount,RSTin,RSTout,STBUFF,chr);
}
/* Enable interrupts */
enable_interrupts(INT_TBE);
}

#ifdef INTSTD
#INT_TBE /* Transmit buffer empty interrupt */
#endif
void TXINT(void)
{
/* If characters are waiting in the buffer, the next one is transferred to the UART
otherwise the interrupt is disabled, waiting for the next transmission. */
if (!isempty(RSTbuff,RSTcount,RSTin,RSTout,STBUFF))
{
TXREG=RSTfrom();
}
else
DISABLE_INTERRUPTS(INT_TBE); /* RS232 TX */
}

Now with this, you can send characters from inside the receive routine, using 'tchar(chr)', which will only take a very few uSec to add the character to the buffer. Even with this, don't use printf, inside the receive handler (it is suprising how slow formatting data can be)...
I'd get rid of the delays in the main code!. Though it is perfectly logical to delay between (say) one transmission and the next, have the main code looping as fast as possible, and responding to the changes in the state machine.
Now the 'state machine' coding, will run something like:
#define IDLE (0)
#define OK (20)
#define RXERROR (1)
#define CXERROR (2)

#bit CREN=0x18.4
#bit OERR=0x18.1
#byte RCREG=0x1A
#bit RCIF=0xC.5
int state=0;
int flag=IDLE;
union {
int8 bt[4];
float value;
} rebuild;

#int_rda
void rx(void) {
int chr;
static int csum;
static int ctr;
if (OERR) {
CREN=0;
CREN=1;
}
//Remember that even if OERR, was asserted, the data buffers
//will be full, and you must read the character, or the
//error will re-assert allmost immediately...
chr=RCREG;
switch (state) {
case 0:
//here you are looking for a 'first character'
if (chr=='somechar') {
csum=chr;
state=1;
}
break;
case 1:
//here you saw the first character last time
if (chr=='nextchar') {
csum^=chr;
state=2;
}
//handle the error
else recover();
break;
case 2:
//here you are at the third character
//Imagine here is has to be the checksum, and then data
if (csum==chr) {
csum^=chr;
state=3;
ctr=0;
}
else csrecover();
break;
case 3:
case 4:
case 5:
case 6:
//here you have the LSB of some data
rebuild.bt[ctr++]=chr;
csum^=chr;
++state;
break;
case 7:
if (chr==csum) {
//Here the byte was received with the right
//checksum, so set a flag to tell the main loop
//to respond. The other flag values for errors
//could also have been set in the earlier handlers
flag=OK;
state=0;
}
else daterror();
break;
default:
state=0;
break;
}
}

Done like this, the interrupt handler, only ever has to handle fetching the byte, the 'state' branch, and the tests inside the one state.
You have to be careful, that the code doesn't get too long, but by adding branches, it is possible to decode quite complex messages. Remember (for instance), that you could branch to different states for the second byte, depending on the value of the first byte, allowing complex decisions to be made with only small tests at the time.

Best Wishes
___________________________
This message was ported from CCS's old forum
Original Post ID: 144515616
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