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

How can I tell how many bytes available while doing #int_rda

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



Joined: 13 Oct 2007
Posts: 53
Location: Texas

View user's profile Send private message Visit poster's website Yahoo Messenger

How can I tell how many bytes available while doing #int_rda
PostPosted: Fri Aug 27, 2010 2:11 pm     Reply with quote

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: 1611
Location: Central Illinois, USA

View user's profile Send private message

PostPosted: Fri Aug 27, 2010 2:25 pm     Reply with quote

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: 1611
Location: Central Illinois, USA

View user's profile Send private message

PostPosted: Fri Aug 27, 2010 2:29 pm     Reply with quote

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

View user's profile Send private message Visit poster's website Yahoo Messenger

PostPosted: Fri Aug 27, 2010 3:18 pm     Reply with quote

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: 1611
Location: Central Illinois, USA

View user's profile Send private message

PostPosted: Fri Aug 27, 2010 3:44 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Fri Aug 27, 2010 4:57 pm     Reply with quote

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: 1611
Location: Central Illinois, USA

View user's profile Send private message

PostPosted: Fri Aug 27, 2010 9:03 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Fri Aug 27, 2010 11:31 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Sat Aug 28, 2010 12:18 am     Reply with quote

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:
Quote:

Word 1
RCREG

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

View user's profile Send private message

PostPosted: Sat Aug 28, 2010 7:48 am     Reply with quote

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: 19221

View user's profile Send private message

PostPosted: Sat Aug 28, 2010 8:19 am     Reply with quote

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: 1611
Location: Central Illinois, USA

View user's profile Send private message

PostPosted: Sat Aug 28, 2010 9:23 am     Reply with quote

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

View user's profile Send private message Visit poster's website Yahoo Messenger

PostPosted: Sat Aug 28, 2010 11:22 am     Reply with quote

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

View user's profile Send private message Visit poster's website Yahoo Messenger

PostPosted: Sat Aug 28, 2010 2:28 pm     Reply with quote

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.
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