|
|
View previous topic :: View next topic |
Author |
Message |
BLL
Joined: 11 Nov 2006 Posts: 181 Location: Birmingham, UK
|
UART receive buffer |
Posted: Fri Jul 08, 2016 9:26 am |
|
|
Hi all,
I am using the h/w uart uart1 on my 18LF4620 to receive data from a Raspberry Pi computer, at 9600Bd, using a pl2303 USB to serial converter.
I have found that declaring a receive buffer is helping to stop random lockups when receiving data and so I have the line
Code: | #use rs232(baud=9600,UART1,ERRORS,DISABLE_INTS,RECEIVE_BUFFER=512,stream=rpi) |
This definitely helps but I get a warning from the compiler (5.05d) :
"Variable never used: RCV_BUFFER_3".
I have read the help and it appears I need to do something to get rid of this warning, but I know not what!
the rda interrupt function I have is:
Code: | //-----------------------------------------------------------------------------
#int_rda
void serial_isr()
{
int t;
buffer[next_in] = fgetc(rpi);
t = next_in;
next_in = (next_in + 1) % BUFFER_SIZE;
if(next_in == next_out)
next_in = t; //buffer full!!
}
//----------------------------------------------------------------------------- |
When the pl2303 locks up, only unplugging it and then plugging it back in again clears the problem and you can continue!
Any help gratefully received!
Thanks
Brian |
|
|
SeeCwriter
Joined: 18 Nov 2013 Posts: 160
|
|
Posted: Fri Jul 08, 2016 10:14 am |
|
|
I don't see where RCV_BUFFER_3 is declared, so I can't say why the warning. I think you are doing too much in your ISR. Try using the following approach.
Code: |
#include <18LF4620
#use delay(clock=40000000,crystal=10000000,restart_wdt)
USE RS232(BAUD=9600,PARITY=N,XMIT=PIN_C6,RCV=PIN_C7,BITS=8,STREAM=COM1,RESTART_WDT)
#define RBLEN 128 // Must be power of 2.
#define MSGSIZE 64
typedef struct {
char ch[MSGSIZE];
char index;
int1 done;
int1 printable;
int1 last_char;
}MSGBUF;
// Ring buffer
typedef struct {
byte buf[RBLEN];
byte head;
byte tail;
}RB;
RB rxbuf1;
MSGBUF msg;
void main()
{
while( TRUE )
{
CheckCom1Port();
// Do other stuff
}
}
void CheckCom1Port()
{
// Is there 232 data waiting to be added to message?
while ( IsChar( &rxbuf1 ) ) {
AddToBuf( PopChar(&rxbuf1), &msg );
// Check for a complete 232 message.
if ( msg.done ) {
if ( IsValidCheckSum(&msg) ) {
ProcessMsg(&msg);
}
ResetMsg(&msg);
}
}
}
int IsChar( RB *p )
{
return( p->head!=p->tail );
}
void PushChar( byte cmd, RB *rxp )
{
rxp->buf[rxp->head++] = cmd;
rxp->head &= (RBLEN-1);
}
byte PopChar( RB *rxp )
{
byte cmd = rxp->buf[rxp->tail++];
rxp->tail &= (RBLEN-1);
return(cmd);
}
void ResetMsg( MSGBUF *m )
{
m->done = FALSE;
m->index = 0;
m->printable = FALSE;
m->last_char = FALSE;
}
#INT_RDA
void RDA_isr(void)
{
byte ch = fgetc(COM1);
PushChar( ch, &rxbuf1 );
}
|
[/code] |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9229 Location: Greensville,Ontario
|
|
Posted: Fri Jul 08, 2016 10:45 am |
|
|
real hard to figure out without seeing the complete program but...
...
#use rs232(baud=9600,UART1,ERRORS,DISABLE_INTS,RECEIVE_BUFFER=512,stream=rpi)
seems to suggest that the data will be stored in a buffer called 'RECEIVE_BUFFER'
yet
inside your ISR you do this..
buffer[next_in] = fgetc(rpi);
so at the very least the incoing data isn't being stored where I think it should be.
Please post your complete 'test program'.
I have used the CCS ex_sisr.c on the 46K22 at 100KB without any problems using BOTH HW UARTs...
Jay |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Jul 08, 2016 11:06 am |
|
|
He is attempting to combine two separate methods of doing a receive buffer:
1. Ex_Sisr.c
2. #use rs232() with RECEIVE_BUFFER.
This should not be done. Don't combine the two methods.
My advice is to use Ex_sisr.c only.
Reason: See Jeremiah's warning at the end of this thread about the
RECEIVE_BUFFER method:
http://www.ccsinfo.com/forum/viewtopic.php?t=55300 |
|
|
BLL
Joined: 11 Nov 2006 Posts: 181 Location: Birmingham, UK
|
|
Posted: Fri Jul 08, 2016 11:59 am |
|
|
Hi all,
Thanks for the replies. I will need to do some studying of your replies!
I'll report back later!!
Thanks again.
Brian |
|
|
BLL
Joined: 11 Nov 2006 Posts: 181 Location: Birmingham, UK
|
|
Posted: Fri Jul 08, 2016 1:34 pm |
|
|
Hi both
What I have at the moment is the same as ex_sisr, if I remove the RECEIVE_BUFFER from the #use line.
I have tried altering the buffer size but to no avail. It is absolutely hopeless!
I am trying to receive a line of comma delimited text, such as
!160707,16,1,0.35,10. Sometimes it arrives as sent, but most times it is corrupted either with bad characters or bits missing off the end.
I have set up a test program with the code you put in your post, but AddToBuf and IsValidChecksum are missing, so I can't compile and try it.
I can just comment out the IsValidCheckSum at the moment, but that still leaves AddToBuf.
Thanks
Brian |
|
|
SeeCwriter
Joined: 18 Nov 2013 Posts: 160
|
|
Posted: Fri Jul 08, 2016 2:25 pm |
|
|
I didn't include IsValidChecksum() and AddToBuf() because I they are specific to the message
format I use. You're welcome to use them. The message format is as follows:
1. All message bytes are ASCII characters.
2. Each message begins with a Start Character, STX (0x02).
3. Each message is terminated with an End Character, ETX (0x03).
4. Following the ETX character, is a checksum byte for the entire message. The checksum can be any
binary value. It's the only character of the message that is not strictly an ASCII character.
The checksum is optional, you don't have to use it. It does provide better error detection than
using just the parity bit. For testing purposes you may want to leave it off until you're satified
you are passing data reliably.
For example, to send the string in your post, the message would look like this:
<STX>!160707,16,1,0.35,10<EXT><CHK>
Code: |
#define isstx(c) (c==0x02)
#define isetx(c) (c==0x03)
int AddToBuf( byte c, MSGBUF *p )
{
if ( !p->done ) {
if ( p->last_char ) {
p->done = TRUE;
p->last_char = FALSE;
}
else if ( isstx(c) ) {
p->index = 0;
p->last_char = FALSE;
}
else if ( isetx(c) ) {
p->last_char = TRUE;
}
if ( c < MSGSIZE ) {
p->ch[p->index] = c;
p->index = (p->index+1) & (MSGSIZE-1); // Assumes MSGSIZE is a power of 2.
p->ch[p->index] = NUL; // aka, '\0'
return( 1 );
}
}
return(0);
}
// Returns true if checksum is valid.
byte IsValidCheckSum( MSGBUF *m )
{
byte CalcSum;
CalcSum = XorChecksum( m->ch, m->index - 1 );
return( CalcSum == m->ch[(m->index)-1] );
}
// Calculate checksum byte for the string 'packet' using the exclusive OR method
char XorChecksum( char *packet, byte packet_length )
{
byte checkbyte;
if (packet_length > (MSGSIZE-1) ) packet_length = MSGSIZE-1;
checkbyte = 0;
while (packet_length--) checkbyte ^= *packet++;
return( (byte)checkbyte );
}
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Fri Jul 08, 2016 2:35 pm |
|
|
If you use the 'RECEIVE_BUFFER=512' syntax, the compiler sets up it's own interrupt handler. Note _interrupt handler_. This is then called when INT_RDA triggers. It will then call your own INT_RDA if present, but the byte will already have been read, so this will not work properly.
These are either/or solutions. _Either_ let the compiler handle the receive buffer _or_ do it yourself with INT_RDA (there are advantages to the latter, especially if the buffer overflows).
DISABLE_INTS, is designed primarily to stop bytes being corrupted when using the software serial. The other use, is if you are using direct writing to the UART, in some parts of your code, while also using interrupt driven I/O at other times. Avoid this.
So use EX_SISR, and get rid of 'RECEIVE_BUFFER=xx', and 'DISABLE_INTS', or get rid of EX_SISR, and just use RECEIVE_BUFFER=xx.
If using SISR, make sure you either use binary buffer sizes (2,4,8,16 etc.), or make the changes published here to the overflow handling. Also be aware that the standard code only handles 256bytes max.
Now honestly why do you think you need such size?. The string you show is under 20 characters long. The key is how fast your code is then at handling what is in this string.
I'm currently using a PIC handling USB MSD, bluetooth, I2C, SPI, three serials, etc., and not one character has been lost at 57600bps, with buffers at just 64 bytes. The code never does anything like delay. All delays are done using countdown timers, and the code is continuously looping checking the incoming buffers for each device. I'd suspect your problem really is how your code is written. You need to understand that the code looking 'at' the received data, needs to be checking and processing this as soon as a string arrives, not delaying and relying on a buffer. |
|
|
BLL
Joined: 11 Nov 2006 Posts: 181 Location: Birmingham, UK
|
|
Posted: Sat Jul 09, 2016 5:22 am |
|
|
Hi, Thank you both for your input.
Ttelmah, I don't quite see what is going on. Lockup seems to happen if a number of requests are made, one after another, as though the buffer is not clearing or overwriting when the buffer is full. I agree that there shouldn't be a problem as I am only sending the PIC short strings occasionally. The PIOC sends a string in response to a command from the RasPi, about once a second and the data is always fine.
I will look at my decoding code again and see if I can improve it.
Thank you for the explanation of the "CCS" buffer versus ex_sisr.
I will also try the other code and see how I go. Time to play!
Thanks again both.
Brian |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Sat Jul 09, 2016 7:52 am |
|
|
Is it possible your code is not handling extra characters between the messages?. For instance are there possibly both a line feed and a carriage return?. If your PIC code only expects one, it might get confused when it sees both.... |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1349
|
|
Posted: Sat Jul 09, 2016 8:13 am |
|
|
What size are next_in (int8, int16, etc.), next_out (int8, int16, etc.), and BUFFER_SIZE (20, 32, 64, 512, etc.) in your test BLL? Also what method are you using to determine the serial is locking up? Are you printing from a software serial device? |
|
|
BLL
Joined: 11 Nov 2006 Posts: 181 Location: Birmingham, UK
|
|
Posted: Sat Jul 09, 2016 11:24 am |
|
|
Hi all, The string being sent is just "!160707,16,1,0.35,10", no more, no less.
I have found that if I slow down, drastically, the repeat loop within main, characters are not dropped, but anything less than 300ms causes dropped characters. Now, at 9600Bd/s, even allowing for overhead, it shouldn't take anything like 300ms to process this tiddly string, but with less than 300ms, I get anything from no items to the 7 I should get!
SeeCwriter, I can't get your code to go at all. I guess I am not understanding how to add <STX> and <EXT> to my string! Sorry to be so thick, but what do I do please?
Brian |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Sat Jul 09, 2016 11:46 am |
|
|
<STX> and <ETX> are characters 2, and 3, commonly used as flags for start of transmission and end of transmission.
I have to ask how you are 'processing' this data?.
Show us your decoding code.
For instance, if you use something like a string search, if you don't have a null terminator in the target, this could go off and search through most of the PIC's memory.... |
|
|
BLL
Joined: 11 Nov 2006 Posts: 181 Location: Birmingham, UK
|
|
Posted: Sat Jul 09, 2016 1:04 pm |
|
|
Hi SeeCwriter
My silliness - I had put a printf line under the if(IsValidChecksum), when I was not using a checksum to start with! However, with the code:
Code: | void CheckCom1Port()
{
// Is there 232 data waiting to be added to message?
while (IsChar(&rxbuf1))
{
AddToBuf(PopChar(&rxbuf1), &msg);
//Check for a complete 232 message.
if (msg.done)
{
printf(lcd_putc,"%s", msg.ch);
if(IsValidCheckSum(&msg))
{
//ProcessMsg(&msg);
}
ResetMsg(&msg);
}
}
} |
I get my string, but appended are 2 characters, a beta symbol and a £ sign, so 10.33 becomes 10.33ߣ. I don't see where they are coming from, but at least the string is all there.
To Ttelmah, all I am doing at the moment is a single printf statement as shown above.
Using the ex_sisr method, my processing was:
Code: | void get_data(char *p)
{
int i=0, j=0;
char rcvData[20][12];
while(*p != '\0')
{
if(*p != ',')
{
rcvData[j][i] = *p;
i++;
}//end if *p..
else
{
rcvData[j][i] = '\0';
i = 0;
j++;
}// end else
p++;
}//end while
lcd_putc("\f");
printf(lcd_putc,"items %u", j+1);
lcd_gotoxy(1,2);
for(i = 0; i < j;i++)
printf(lcd_putc,"%s,", rcvData[i]);
delay_ms(10000); //temporary so I can examine the LCD!
} |
p is a pointer to the string received. The printf line is just to see what arrives. Later, the array contents will be saved to eeprom locations.
Brian |
|
|
BLL
Joined: 11 Nov 2006 Posts: 181 Location: Birmingham, UK
|
|
Posted: Sat Jul 09, 2016 2:34 pm |
|
|
Please ignore last message - Murphy reigns! I suddenly realised that I have 3 special characters loaded into the LCD's CG RAM, a £, a € and a ß and printf is seeing the <STX> and <ETX> codes as the codes for the special characters!!
Brian |
|
|
|
|
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
|