View previous topic :: View next topic |
Author |
Message |
zonemikel
Joined: 13 Oct 2007 Posts: 53 Location: Texas
|
How can I tell how many bytes available while doing #int_rda |
Posted: Fri Aug 27, 2010 2:11 pm |
|
|
I have a #16f887
When I have a rx interrupt #int_rda, does that mean one byte is available or how many ? Is there a register I can read to find out ? I'm trying to read a *packet* and then set the state differently if i have a whole packet or just a few chars. I dont want to read the packet in my main loop unless I have the whole thing.
Code: |
#int_rda
void serial_isr() {
while(kbhit()){ // while there is data in the buffer
incPKT[pktIndex] = fgetc(wireless);
// finger smudging
if(pktIndex == ixDirection){
setSpeed(maxSpeed, incPKT[ixDirection]);
}
// if it is for us then start filling buffer, else we stay at 0
if(pktIndex == 0 && incPKT[pktIndex] == ID){
pktIndex++;}
// if it is from the server we want to lisetn too then continue
else if(pktIndex == 1 && incPKT[pktIndex] == serverID){
pktIndex++; }
// if its for us from the guy we want to listen too get it !
else if(pktIndex < incPKT_sz && pktIndex > 1){state = NEWPACKET;
pktIndex++; }
// if we are on 63 we have received 64 bytes our packet is done
else if(pktIndex >= incPKT_sz){
state = NEWPACKET; // set new packet to 1 so we process the packet
if(pktCount < 255){pktCount++;}else{pktCount = 0;} // int8 max = 255
pktIndex = 0; // reset our index
}else{
pktIndex = 0; // first two bytes were incorrect, start over
}// end if
}// end while
} |
_________________ Smart people know how stupid they are. |
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Fri Aug 27, 2010 2:25 pm |
|
|
It depends on the PIC in use.
Did you read the datasheet for the PIC16F887 yet?
Specifically the section on the UART that on page 158 states:
The Asynchronous mode is typically used in RS-232
systems. The receiver block diagram is shown in
Figure 12-2. The data is received on the RX/DT pin and
drives the data recovery block. The data recovery block
is actually a high-speed shifter operating at 16 times
the baud rate, whereas the serial Receive Shift
Register (RSR) operates at the bit rate. When all 8 or 9
bits of the character have been shifted in, they are
immediately transferred to a two character First-In-
First-Out (FIFO) memory. The FIFO buffering allows
reception of two complete characters and the start of a
third character before software must start servicing the
EUSART receiver. The FIFO and RSR registers are not
directly accessible by software. Access to the received
data is via the RCREG register.
Then it goes on to say (on the same page):
12.1.2.3 Receive Interrupts
The RCIF interrupt flag bit of the PIR1 register is set
whenever the EUSART receiver is enabled and there is
an unread character in the receive FIFO. The RCIF
interrupt flag bit is read-only, it cannot be set or cleared
by software.
Does this answer your question?
ALways make sure to read the datasheet...
The datasheet is your friend.
:D
-Ben _________________ Dazed and confused? I don't think so. Just "plain lost" will do. :D |
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Fri Aug 27, 2010 2:29 pm |
|
|
BTW,
when I write "packet receivers" (like for GPS, say), the whole packet usually doesn't fit in the PIC's FIFO (be it 1 or 8 chars).
So figure you will have a loop that gets chars and then tests the FIFO however it can be tested (in this case via the RCIF) to see if it's clear or the end of the packet is found to either exit the ISR or change the packet machine's state and then exit the ISR.
-Ben _________________ Dazed and confused? I don't think so. Just "plain lost" will do. :D |
|
|
zonemikel
Joined: 13 Oct 2007 Posts: 53 Location: Texas
|
|
Posted: Fri Aug 27, 2010 3:18 pm |
|
|
bkamen wrote: | BTW,
when I write "packet receivers" (like for GPS, say), the whole packet usually doesn't fit in the PIC's FIFO (be it 1 or 8 chars).
So figure you will have a loop that gets chars and then tests the FIFO however it can be tested (in this case via the RCIF) to see if it's clear or the end of the packet is found to either exit the ISR or change the packet machine's state and then exit the ISR.
-Ben |
Thanks, sometimes I don't know if I should read ccs help or the datasheet. I overlook the datasheet too much.
So I can be expecting about 2 chars each time the int trips, that should help. _________________ Smart people know how stupid they are. |
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Fri Aug 27, 2010 3:44 pm |
|
|
zonemikel wrote: |
Thanks, sometimes I don't know if I should read ccs help or the datasheet. I overlook the datasheet too much.
So I can be expecting about 2 chars each time the int trips, that should help. |
The datasheet is the rulebook for that PIC. It should be read.
You will find that "project" issues stem from 3 things:
* Items that do not conform to the datasheet (see Errata sheets if in doubt)
* Items that the compiler does for you that has a bug. (learn ASM and check .LST files)
* Something that does exactly as you coded, but wasn't what you want. (and we all do that occasionally)
But always read the datasheet.
And I would word it as:
When you have an IRQ, you have 2 chars (not about.. but absolutely) in the FIFO with possible one on the way.
Cheers,
-Ben _________________ Dazed and confused? I don't think so. Just "plain lost" will do. :D |
|
|
languer
Joined: 09 Jan 2004 Posts: 144 Location: USA
|
|
Posted: Fri Aug 27, 2010 4:57 pm |
|
|
minor correction, i think...
Quote: | When you have an IRQ, you have 2 chars (not about.. but absolutely) in the FIFO with possible one on the way. |
When you have an IRQ, you have a minimum of 1 character and a maximum of 2 characters on the FIFO - IRQ only guarantees that first character, it makes no assumption about the second character
The second character is to prevent a buffer overflow condition. So if you service the interrupt faster than the character rate (i.e. baudrate * #bits/character), you are guaranteed not to overflow the buffer. |
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Fri Aug 27, 2010 9:03 pm |
|
|
languer wrote: | minor correction, i think...
Quote: | When you have an IRQ, you have 2 chars (not about.. but absolutely) in the FIFO with possible one on the way. |
When you have an IRQ, you have a minimum of 1 character and a maximum of 2 characters on the FIFO - IRQ only guarantees that first character, it makes no assumption about the second character
The second character is to prevent a buffer overflow condition. So if you service the interrupt faster than the character rate (i.e. baudrate * #bits/character), you are guaranteed not to overflow the buffer. |
Normally, I would agree, but if you read carefully it has a FIFO that holds 2 and that's when the interrupt fires. There is a 3rd char that can shift into the receive register.
Regardless, I would test it thoroughly.
-Ben _________________ Dazed and confused? I don't think so. Just "plain lost" will do. :D |
|
|
languer
Joined: 09 Jan 2004 Posts: 144 Location: USA
|
|
Posted: Fri Aug 27, 2010 11:31 pm |
|
|
Still believe the ISR fires on the first one:
Quote: | Immediately after all data bits and the Stop bit have been received, the character in the RSR is transferred to the EUSART receive FIFO and the RCIF interrupt flag bit of the PIR1 register is set ... The RCIF interrupt flag bit of the PIR1 register is set whenever the EUSART receiver is enabled and there is an unread character in the receive FIFO. |
But I totally agree, testing it thoroughly is the way to go.
BTW, a read into circular buffers and a look into EX_SISR.C under the CCS examples folder will probably go a long way. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Aug 28, 2010 12:18 am |
|
|
Look in this section of the 16F887 data sheet on page 158 (page 160 in
the Acrobat reader):
Quote: |
FIGURE 12-5: ASYNCHRONOUS RECEPTION
|
http://ww1.microchip.com/downloads/en/DeviceDoc/41291F.pdf
It has a timing diagram that shows the reception of 3 bytes by the UART.
The interrupt flag (RCIF) goes high (True) just after the 1st byte is
received. At the same time, the byte is loaded into the 2-deep receive
buffer (fifo), where it can be read by your PIC program with getc().
This event is shown with a dotted vertical line in the middle of the
diagram. It has this label:
So the answer is, you get an interrupt after the 1st byte.
This thread has a test program which shows the PIC has a 2-deep
receive buffer. (The program demonstrates what the data sheet says).
http://www.ccsinfo.com/forum/viewtopic.php?t=40785 |
|
|
John P
Joined: 17 Sep 2003 Posts: 331
|
|
Posted: Sat Aug 28, 2010 7:48 am |
|
|
It couldn't be any other way. If a single character came in, you'd want to get the interrupt to tell you to go and read it, wouldn't you? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Sat Aug 28, 2010 8:19 am |
|
|
bkamen wrote: | zonemikel wrote: |
Thanks, sometimes I don't know if I should read ccs help or the datasheet. I overlook the datasheet too much.
So I can be expecting about 2 chars each time the int trips, that should help. |
The datasheet is the rulebook for that PIC. It should be read.
You will find that "project" issues stem from 3 things:
* Items that do not conform to the datasheet (see Errata sheets if in doubt)
* Items that the compiler does for you that has a bug. (learn ASM and check .LST files)
* Something that does exactly as you coded, but wasn't what you want. (and we all do that occasionally)
But always read the datasheet.
And I would word it as:
When you have an IRQ, you have 2 chars (not about.. but absolutely) in the FIFO with possible one on the way.
Cheers,
-Ben |
Think about this for a moment.
If the chip behaved like this, you would _never_ be able to receive single characters with interrupt driven receive code. It'd never trigger till another character came. This is simply 'wrong'.
The IRQ triggers when _one_ character has been assembled, and transferred to the FIFO. _If_ the data rate is high, and the code takes a long time to reach the IRQ handler, you may have two characters present, but it is not guaranteed.
The 'ideal' re-write of the INT_RDA, is:
Code: |
#int_rda
void serial_isr() {
int t;
do {
buffer[next_in]=getc();
if (++next_in >=BUFFER_SIZE) next_in=0;
if(next_in==next_out) {
if (++next_out >>BUFFER_SIZE) next_out=0;
// Buffer full, throw oldest character - opposite of CCS here
} while(kbhit());
}
|
This avoids the use of the modulus operation in the IRQ, which is silly design in the CCS example (works fine if buffer size is binary - 8,16,32), but otherwise introduces problems with using a division in the IRQ), and will check if a second character is waiting/has arrived, while the first is being serviced.
Also throws the oldest character in an 'overflow', which I prefer - YPYMATYC on this.....
Best Wishes |
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Sat Aug 28, 2010 9:23 am |
|
|
Ttelmah wrote: |
Think about this for a moment.
If the chip behaved like this, you would _never_ be able to recieve single characters with interrupt driven receive code. It'd never trigger till another character came. This is simply 'wrong'.
The IRQ triggers when _one_ character has been assembled, and transferred to the FIFO. _If_ the data rate is high, and the code takes a long time to reach the IRQ handler, you may have two characters present, but it is not guaranteed.
|
Yep - I agree. And with PCM looking at the graph (which I didn't take that long since I was trying to give the original poster a quick answer) shows that.
My apologies for missing on the IRQ part. _________________ Dazed and confused? I don't think so. Just "plain lost" will do. :D |
|
|
zonemikel
Joined: 13 Oct 2007 Posts: 53 Location: Texas
|
|
Posted: Sat Aug 28, 2010 11:22 am |
|
|
bkamen wrote: | Ttelmah wrote: |
Think about this for a moment.
If the chip behaved like this, you would _never_ be able to receive single characters with interrupt driven receive code. It'd never trigger till another character came. This is simply 'wrong'.
The IRQ triggers when _one_ character has been assembled, and transferred to the FIFO. _If_ the data rate is high, and the code takes a long time to reach the IRQ handler, you may have two characters present, but it is not guaranteed.
|
Yep - I agree. And with PCM looking at the graph (which I didn't take that long since I was trying to give the original poster a quick answer) shows that.
My apologies for missing on the IRQ part. |
Well thanks for the quick answer, at least i had some idea what was going on quickly. I thought maybe it was buffering the whole packet. Thanks its crystal clear now how the packets come in and when the int fires.
I think instead of searching for the header during the int i'm going to just buffer the packets and then when the buffer index is high enough I will search for a packet in the buffer.
I'm going to use this for my int, very nice thank you.
Code: |
void serial_isr() {
do {
buffer[buffer_index]=getc();
if (++buffer_index >=BUFFER_SIZE) buffer_index=0;
} while(kbhit());
}
|
_________________ Smart people know how stupid they are. |
|
|
zonemikel
Joined: 13 Oct 2007 Posts: 53 Location: Texas
|
|
Posted: Sat Aug 28, 2010 2:28 pm |
|
|
shortly after writing that post and starting to code I realized why you had a "next_in" and a "next_out" instead of just a index like me.
I ended up with this code, currently transmitting about 5 packets a second, each packet is 16 bytes.
Code: |
// the int
#int_rda
void serial_isr() {
do {
buffer[next_in]=getc();
if (++next_in >=BUFFER_SIZE) next_in=0;
if(next_in==next_out) {
if (++next_out >= BUFFER_SIZE) next_out=0;}
// Buffer full, throw oldest character - opposite of CCS here
} while(kbhit());
}
// my main loop , just the part that is relevant
if(getPacket()){
sendPacket(0);
}else{
delay_ms(100);
}
// getpacket, gets a packet from the buffer
int1 getPacket(){
while((next_in - next_out) >= incPKT_sz)
{
// if the next byte and the one after that are [ID],[ServerID]
if(buffer[next_out] == ID && buffer[next_out + 1] == serverID)
{
for(i = 0; i<incPKT_sz; i++)
{
incPKT[i] = buffer[next_out];
next_out++;
}
next_out = next_in; // erase the rest of the packet
return 1;
}
next_out++; // move forward in the buffer
}
return 0;
}
|
It was weird, before i started setting next_out=next_in (basically ignoring the rest of the buffer after I got a good packet), for each packet sent to the PIC it would send 3 back. This was causing all kinds of confusion for a while.
thanks greatly ! _________________ Smart people know how stupid they are. |
|
|
|