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 CCS Technical Support

serial interrupt help

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



Joined: 13 Sep 2003
Posts: 87

View user's profile Send private message

serial interrupt help
PostPosted: Sat Jan 17, 2004 1:47 am     Reply with quote

Mabuhay!

I need your help on serial interrupt, my code listed below:

Code:

#use rs232(baud=115200,parity=n,xmit=PIN_C6,rcv=PIN_C7,bits=8,stream=RS485Com,enable=PIN_B4)

int1 glSerialRXReady     = 0;   // RS485 ready flag bit
int1 glSerialRXDataReady = 0;   // RS485 data ready flag bit

#define RX_SIZE 64
byte rxbuffer[RX_SIZE];
byte rx_in  = 0;
byte rx_out = 0;


#int_rda
void rs485_rx_isr()
{
     int ch;

     if (glSerialRXReady)   // prevent multi-trigger of packets
     {
          if (kbhit(RS485Com))   // check if data is available from buffer
          {
               ch = fgetc(RS485Com);   // get incoming byte from buffer
               rxbuffer[rx_in] = ch;   // place incoming byte in rxbuffer
               rx_in++;      // increment data IN index
               rx_out++;   // increment data OUT index

               if (bit_test(rx_in,6))   // if rx_in larger than RX_SIZE (64)
               {
                    rx_in  = 0;   // zero rx_in value
                    rx_out = 0;   // zero rx_out value
               }
          }

          if (!kbhit(RS485Com))   // no incoming byte from buffer
          {
               glSerialRXReady = 0;   // prevent multi-trigger of packets
               glSerialRXDataReady = 1;   // set rx data ready
          }
     }

     else fgetc(RS485Com);  // prevent buffer overflow
}

main()
{
     glSerialRXReady = 1;
     glSerialRXDataReady = 0;

     while (1)
     {
          if (glSerialRXDataReady)
          {
              .... I process my rxbuffer here ......
              ....
              ....
              glSerialRXReady = 1;   // capture new packets
              glSerialRXDataReady = 0; // set data ready flag
          }

          ......
          ......
     }
}




I notice that I can't get the packet correctly from a computer.

For clarification, the #int_rda will only interrupt when it receive a byte ? Am I correct? if so, the rs485_rx_isr() routine will only be executed during serial interrupt?

if that would be the case I place the condition if (!kbhit(RS485Com)) in a wrong place... this condition is responsible to detect that their is no incoming byte from a computer and by this it will trigger a flag bit to process the receive packets.

I put this condition for the reason that I am receiving data from a computer of variable lenght but it will not exceeds the 64bytes buffer size allocated. In addition, the packet does not have an end of transmission character.

I need your comments on this code or any help that I could re-phrase this code such it can detect that their is no incoming data.

Thank you.
Ttelmah
Guest







Re: serial interrupt help
PostPosted: Sat Jan 17, 2004 3:46 am     Reply with quote

ritchie wrote:
Mabuhay!

I need your help on serial interrupt, my code listed below:

Code:

#use rs232(baud=115200,parity=n,xmit=PIN_C6,rcv=PIN_C7,bits=8,stream=RS485Com,enable=PIN_B4)

int1 glSerialRXReady     = 0;   // RS485 ready flag bit
int1 glSerialRXDataReady = 0;   // RS485 data ready flag bit

#define RX_SIZE 64
byte rxbuffer[RX_SIZE];
byte rx_in  = 0;
byte rx_out = 0;


#int_rda
void rs485_rx_isr()
{
     int ch;

     if (glSerialRXReady)   // prevent multi-trigger of packets
     {
          if (kbhit(RS485Com))   // check if data is available from buffer
          {
               ch = fgetc(RS485Com);   // get incoming byte from buffer
               rxbuffer[rx_in] = ch;   // place incoming byte in rxbuffer
               rx_in++;      // increment data IN index
               rx_out++;   // increment data OUT index

               if (bit_test(rx_in,6))   // if rx_in larger than RX_SIZE (64)
               {
                    rx_in  = 0;   // zero rx_in value
                    rx_out = 0;   // zero rx_out value
               }
          }

          if (!kbhit(RS485Com))   // no incoming byte from buffer
          {
               glSerialRXReady = 0;   // prevent multi-trigger of packets
               glSerialRXDataReady = 1;   // set rx data ready
          }
     }

     else fgetc(RS485Com);  // prevent buffer overflow
}

main()
{
     glSerialRXReady = 1;
     glSerialRXDataReady = 0;

     while (1)
     {
          if (glSerialRXDataReady)
          {
              .... I process my rxbuffer here ......
              ....
              ....
              glSerialRXReady = 1;   // capture new packets
              glSerialRXDataReady = 0; // set data ready flag
          }

          ......
          ......
     }
}




I notice that I can't get the packet correctly from a computer.

For clarification, the #int_rda will only interrupt when it receive a byte ? Am I correct? if so, the rs485_rx_isr() routine will only be executed during serial interrupt?

if that would be the case I place the condition if (!kbhit(RS485Com)) in a wrong place... this condition is responsible to detect that their is no incoming byte from a computer and by this it will trigger a flag bit to process the receive packets.

I put this condition for the reason that I am receiving data from a computer of variable lenght but it will not exceeds the 64bytes buffer size allocated. In addition, the packet does not have an end of transmission character.

I need your comments on this code or any help that I could re-phrase this code such it can detect that their is no incoming data.

Thank you.

Basically, you should only get an interrupt when a character is available. There is a 'caveat' though, in that the overrun error bit may be set at this time, and if so, unless cleared, the UART will stop receiving data.
The 'ERRORS' directive will clear this for you, but I prefer to go 'DIY', since I can then add other code to flag that this has happened.

Adding code like this to the 'tail' of the interrupt handler (after receiving the character), removes this problem (the defines are for an 18Fxx2, and will need to be modified for other chips).

Code:

#bit OERR=0xFAB.1
#bit CREN=0xFAB.4


   if (OERR) {
      CREN=false;
      CREN=true;
      //Add any 'warning flag', or other handler here
   }


Now the second comment, relates to the buffer handler itself. Normally, only the 'data in' pointer should be incremented for the addition of a character. The 'data out' pointer would only move when the character is removed. Hence the handler would look something like:

Code:

   
#define RX_SIZE (64)
byte rxbuffer[RX_SIZE];
byte rx_in  = 0;
byte rx_out = 0;
byte rx_free = 0;
//Note I am using a seperate 'count' here. This requires one more
//byte of storage, but speeds certain tests.

byte RSTfrom()
{
    /* Get character from the RS232 RX buffer */
    byte temp;
    temp=rx_out;
    rx_out=(++rx_out) & (RX_SIZE-1);
    temp=(rxbuffer[temp]);
    rx_free++;
    return(temp);
}

#define LIM (2)
#define isempty(buff,free,in,out,size) (free>=size)
#define isfull(buff,free,in,out,size) (free<LIM)
#define tobuff(buff,free,in,out,size,chr) {buff[in++]=chr;\
    --free;\
   in=(in & (size-1));}

#int_rda
void rs485_rx_isr()
{
   tobuff(rxbuffer,rx_free,rx_in,rx_out,RX_SIZE,getchar());
   if (OERR) {
      CREN=false;
      CREN=true;
      //Add any 'warning flag', or other handler here
   }
}

//You can check that the buffer is empty at any time with:
   isempty(rxbuffer,rx_free,rx_in,rx_out,RX_SIZE)
//or that the buffer is full at any time with:
   isfull(rxbuffer,rx_free,rx_in,rx_out,RX_SIZE) 
//and get a character from the buffer with:
   RSTfrom()


Notice that the use of the seperate 'free counter', allows me to check for the buffer having filled to a 'point' (here just two characters clear), without extra arithmetic. Also that the main buffer functions, can all be used for multiple buffers, accepting all the variables concerned with the buffer, but (since they are done as 'defines'), only the variables that are needed are used for each function. I have also at times used a similar generic 'from' function, but then you have to be careful of the implications of multiple routines wanting to use the same function, if some are in interrupts (my RS232 'extraction', is done in a timer interrupt, rather than in the main code).

Best Wishes
ritchie



Joined: 13 Sep 2003
Posts: 87

View user's profile Send private message

Re: serial interrupt help
PostPosted: Sat Jan 17, 2004 6:09 am     Reply with quote

Mabuhay!

There is a 'caveat' though, in that the overrun error bit may be set at this time, and if so, unless cleared, the UART will stop receiving data. ----> what do you mean by this? Can you elaborate this further regarding error directive?

The 'ERRORS' directive will clear this for you, but I prefer to go 'DIY', since I can then add other code to flag that this has happened. ----> what does this mean error directive will clear this 4u?

One of my concern on the code listed above is? how can I be able to determine that the UART has no incoming character? can I use the error directive by utilizing or adding an additional flag at the error directive condition?

Need your help such that I could make it work.

Thank u.
Ttelmah
Guest







Re: serial interrupt help
PostPosted: Sat Jan 17, 2004 11:57 am     Reply with quote

ritchie wrote:
Mabuhay!

There is a 'caveat' though, in that the overrun error bit may be set at this time, and if so, unless cleared, the UART will stop receiving data. ----> what do you mean by this? Can you elaborate this further regarding error directive?

The 'ERRORS' directive will clear this for you, but I prefer to go 'DIY', since I can then add other code to flag that this has happened. ----> what does this mean error directive will clear this 4u?

One of my concern on the code listed above is? how can I be able to determine that the UART has no incoming character? can I use the error directive by utilizing or adding an additional flag at the error directive condition?

Need your help such that I could make it work.

Thank u.

The UART will allways have a character on the interrupt The problem is that if you read it, and then exit the routine, without clearing the overrun error, the interrupt will not happen again. If the overrun error is set, then it is probable that the character is corrupted. For high baud rates, you should consider something like (in a sort of 'pseudo code'):


do {
read character
if (overrun) clear error
} while (character is waiting)

This way, if a second character has been received between the interrupt being generated, and arriving inside the routine, this too will be fetched, without having to go through the massive overhead of the interrupt handler...

Best Wishes

Best Wishes
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