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

18F4685 USART IRQ Problem

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







18F4685 USART IRQ Problem
PostPosted: Sun Jan 04, 2009 10:02 am     Reply with quote

Hi Folks,

Why do I always get the weird problems?? Rolling Eyes

I have a 18F4685 that is communicating with a wireless receiver device (also by co-incidence a PIC).

Basically I lower a wake pin on the processor, send a command to the device and receive either

<ACK> or <NAK>

so simple it's untrue!

However after 2 days of head scratching I've got to ask for help.

I have another pc monitoring the receive line via a max232 so I can verify that the processor is getting the data OK.

Using the standard CCS int_rda example I do not receive all the data from the wireless device, my usart buffer contains the first 2 characters and nothing else.


This code does not work

/* TURN ON INTERRUPTS */
enable_interrupts(GLOBAL);
enable_interrupts(INT_RDA);


for(;;)
{

if (COM1_kbhit)
{
printf(lcd_putc,"%c", COM1_bgetc());

}

}

I get about 2 characters

However - if I do not use interrupts. I can receive the entire message

This example works fine..

for(;;)

if (bit_test(USART_PIR1, 5))
{
Response[ResponsePosition++] = getc();
if (ResponsePosition == 5)
{
goto ExitLoop2;
}
}
ExitLoop2

This has got me completely perplexed, I've been thumbing through the microchip datasheet and got the above example working.

Using the ICD-2 debugger I can examine the registers and strangely some do not agree with what I think they should from the datasheet.

(I am running at 20MHZ and need a 9600 baud)

TXSTA = 0xA6
RCSTA = 0x90
BAUDCON = 0x00
SPBRG = 0 (This seems strange!)

Compiler version 4.073



I know that the receive interrupt code example dates back to the 16C74 days, is there something else I should be doing

Thanks

James
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Sun Jan 04, 2009 10:38 am     Reply with quote

I'm unable to recognize what's valid code in your post. Your enabling INT_RDA, but there's no #INT_RDA interrupt service routine. Please post a complete example to make the problem understandable.
dyeatman



Joined: 06 Sep 2003
Posts: 1937
Location: Norman, OK

View user's profile Send private message

PostPosted: Sun Jan 04, 2009 10:46 am     Reply with quote

And also use the CODE button for your code to make it readable...

Offhand it sounds like a buffer overrun to me. When we see the code it will be clearer.
asmallri



Joined: 12 Aug 2004
Posts: 1635
Location: Perth, Australia

View user's profile Send private message Send e-mail Visit poster's website

Re: 18F4685 USART IRQ Problem
PostPosted: Sun Jan 04, 2009 11:46 am     Reply with quote

JamesW, Kent, England wrote:


Using the standard CCS int_rda example I do not receive all the data from the wireless device, my usart buffer contains the first 2 characters and nothing else.


This is a pretty good indication that you are getting overrun errors. The UART receive buffer is not being process fast enough. It also indicates you have not included the "errors" directive in the #use RS232 statement

Quote:

This code does not work

/* TURN ON INTERRUPTS */
enable_interrupts(GLOBAL);
enable_interrupts(INT_RDA);


for(;;)
{

if (COM1_kbhit)
{
printf(lcd_putc,"%c", COM1_bgetc());

}

}


Is the for loop inside the int_rda interrup handler? If not then this is your problem, you have enabled interrupts but have no interrupt handler.

If it is in the interrupt handler then this is still a problem - you have used a slow printf ()inside the interrupt handler. If your incoming characters are close together then an overrun error may occur.

Quote:

BAUDCON = 0x00
SPBRG = 0 (This seems strange!)


If you are using a #use RS232 directive after setting these registers then the registers are being set by the #use directive.
_________________
Regards, Andrew

http://www.brushelectronics.com/software
Home of Ethernet, SD card and Encrypted Serial Bootloaders for PICs!!
Guest








PostPosted: Sun Jan 04, 2009 11:49 am     Reply with quote

Ahh - that code button, I've been looking for how do to that!!!!

Code:


/* ------------------------------------------------------------------------- */
/* SERIAL PORT DEFINITIONS */
#define COM1_BUFFER_SIZE 40

BYTE COM1_buffer[COM1_BUFFER_SIZE];
BYTE COM1_next_in = 0;
BYTE COM1_next_out = 0;


unsigned int IrqCount = 0;


/* ------------------------------------------------------------------------- */
#int_rda
void serial_isr()
{
   int t;

   IrqCount++;

   COM1_buffer[COM1_next_in]=getc();

   t = COM1_next_in;
   COM1_next_in=(COM1_next_in+1) % COM1_BUFFER_SIZE;
   
   if(COM1_next_in==COM1_next_out)
     COM1_next_in=t;           // Buffer full !!
}
/* ------------------------------------------------------------------------- */
#define COM1_kbhit (COM1_next_in != COM1_next_out)


BYTE COM1_bgetc()
{
   BYTE c;

   while(!COM1_kbhit) ;
   c=COM1_buffer[COM1_next_out];
   COM1_next_out=(COM1_next_out+1) % COM1_BUFFER_SIZE;
   return(c);
}

/* ------------------------------------------------------------------------- */
/* ROUTINE TO RE-INITIALISE/INITIALISE THE USART */

void COM1_Initialise()
{

   unsigned int Junk;

   disable_interrupts(INT_RDA);

   set_uart_speed(9600);
   


#ifdef TRY_THIS
   bit_clear(USART_RXSTA,4);

   /* SET BAUD RATE TO 9600 */
   USART_SPBRG = 31;
   
   /* CLEAR SYNC */
   bit_clear(USART_TXSTA, 4);
   
   /* CLEAR BRGH */
   bit_clear(USART_TXSTA, 2);
   
   /* CLEAR BRG16 */
   bit_clear(USART_BAUDCON, 3);
   
   bit_set(USART_RXSTA,4);
#endif   


   delay_ms(100);
   

   if (COM1_kbhit)
   {
      Junk = COM1_bgetc();
   }

   IrqCount = 0;
   
   memset(COM1_buffer, 0, COM1_BUFFER_SIZE);

   COM1_next_in = 0;
   COM1_next_out = 0;
   
   enable_interrupts(INT_RDA);   
   

}

dyeatman



Joined: 06 Sep 2003
Posts: 1937
Location: Norman, OK

View user's profile Send private message

PostPosted: Sun Jan 04, 2009 1:11 pm     Reply with quote

At first glance your Int_RDA and handling buffer routines look basically OK .

The entire COM1_Initialize routine can be replaced with this line at the beginning of your program:

Code:
#use rs232(baud=9600, xmit=PIN_XX, rcv=PIN_XX, ERRORS)

(be sure to insert your xmit/recv pin numbers)
Don't enable/disable interrupts anywhere except just before entering your main loop. Let the compiler handle those things for you automatically.

Example:
Code:

void main()
{
   IrqCount = 0;
   COM1_next_in = 0;
   COM1_next_out = 0;
 
   enable_interrupts(INT_RDA);
   enable_interrupts(GLOBAL);

while(1)
  {   // poll the recv buffer here
   // NOTE: Take the "while (!COM1_KBHit)" line out of the COM1_BGetc
  // routine. It causes you to hang inside the routine which is
  //  not a good thing to do
  //
  if COM1_kbhit
       COM1_bgetc();


  }
}


See this topic for more info:
http://www.ccsinfo.com/forum/viewtopic.php?t=36039

Also, you reserve the buffer memory with this:
Code:
BYTE COM1_buffer[COM1_BUFFER_SIZE];

So you don't need the memset() line.
JamesW, Kent, England
Guest







PostPosted: Sun Jan 04, 2009 2:23 pm     Reply with quote

Cheers for the pointers.

I normally use the #USE RS232 line, but when I encountered the problems I started clutching at straws thinking that maybe the initialisation routines were playing up.

The memset is there purely to make it easier to use the debugger to find any data located in the buffer.

I've been delving a little deeper in this.

I have written the routine above that "works" into the code using a counter coming off the timer interrupt to exit the loop. - but this should really be working as an IRQ and seems like a complete bodge.

I have come to the following hypotheses.

1) The usart itself is working fine, as by polling the PIR register for the "I have a character in the RX buffer! I see data and a complete packet.
2) The first interrupt works fine, it is interrupts later on in the data stream that are causing problems or being missed. This at least proves that the compiler is locating the interrupt handler in the right place, and off the right interrupt.

Therefore I "think" that there must be something that needs clearing/reseting in the IRQ service routine that is preventing it handling things correctly. I would normally assume that this is being done automatically by the compiler, but maybe not for the 18F processor.

I've been using the #USE_RS232 and the above interrupt service routine on various processors since about 1997 without a problem.
(Well nothing like this anyway!)

This may well link in with my other post about receive issues when using an 18F device in i2C slave mode.

What should be cleared when servicing an RS232 receive interrupt?

Thanks in advance

James
Ttelmah
Guest







PostPosted: Sun Jan 04, 2009 4:02 pm     Reply with quote

I'd try changing your buffer size.
I have warned in the past about this.
You buffer size should _either_ be a 'binary' value (16, 32, 64 bytes), or you should re-code the ISR as:
Code:

#int_rda
void serial_isr()
{
   int t;

   IrqCount++;

   COM1_buffer[COM1_next_in]=getc();

   t = COM1_next_in++;
   if (COM1_next_in == COM1_BUFFER_SIZE) COM1_next_in=0;
   
   
   if(COM1_next_in==COM1_next_out)
     COM1_next_in=t;           // Buffer full !!
}

The problem is that using '%', with a size other than a binary value, results in an integer division, and multiplication, being placed inside your interrupt handler, and interrupts being disabled round these same arithmetic routines in the 'main' code.
It may not be the problem, but it will massively reduce the potential performance of the serial code.
The same change should be added to the bgetc, but here it is less important.
There really ought to be a warning in the CCS examples about this....

Best Wishes
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Sun Jan 04, 2009 4:09 pm     Reply with quote

I think, the %40 operation, although time consuming, shouldn't be an issue at 9600 baud. I rather expect, that some considerably long interrupt disable occurs during lcd_putc(). But both assumptions should be checked.
JamesW, Kent, England
Guest







PostPosted: Sun Jan 04, 2009 4:21 pm     Reply with quote

I will give the buffer size change a try tomorrow morning.

The lcd_putc was put there purely for debug purposes. The original routine consisted of using kbhit to dump the characters in an array until a '>' (end of packet) character was found or a timeout occurred.

I've been reading from the microchip datasheet again. Does the interrupt priority have any effect on this (not that there are any other interrupts enabled at the moment)???

According to the datasheet, reading from the usart clears the IRQ automatically (it seems to be read only)- I'll check that this is clear as well and get back to you.

Cheers

James
dyeatman



Joined: 06 Sep 2003
Posts: 1937
Location: Norman, OK

View user's profile Send private message

PostPosted: Sun Jan 04, 2009 5:15 pm     Reply with quote

Using either getc() or reading the UART recv register directly clears the interrupt. Since you are using just one interrupt the priority makes no difference.

The inclusion of the ERRORS at the end of the #USE_RS232 line is designed to take care of any overrun errors that are encountered and is the likely culprit in my opinion. If the data source is slightly off baud rate wise it will definitely cause a problem.
JamesW, Kent, England
Guest







PostPosted: Wed Jan 07, 2009 4:44 am     Reply with quote

Well I'll damned!

Changing the buffer size to 64 and removing the ERRORS declaration has made it work!

Looking at the datasheet a baud rate of 9600 at 20MHz gives an error of about 1.7%

THANKS CHAPS!!!!!

One more small question, now I am not using the ERRORS directive - should I be checking any bits of the usart for errors?

Thanks again

James
Ttelmah
Guest







PostPosted: Wed Jan 07, 2009 5:06 am     Reply with quote

If you want to clear errors, use:
Code:

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

   //At the end of your serial routine
   while (OERR) {
      CREN=false;
      CREN=true;
   }

Have you tried with leaving ERRORS on though?. Normally the CCS code for this works OK, so it is sounding to me as if the problem may well relate to the buffer arithmetic. This can have unexpectedly 'major' effects, because of the way it leads to interrupts being disabled in the external code....

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