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

Faulty RS-485 Communication during processor intensive tasks

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



Joined: 04 Nov 2004
Posts: 67

View user's profile Send private message Send e-mail

Faulty RS-485 Communication during processor intensive tasks
PostPosted: Fri Feb 17, 2006 7:57 am     Reply with quote

I am currently using the compiler version 3.19.

I have created a data acquisition product which has different "modes". One mode does very very little calculation, it just is in "standby" and calculates temperature. When in this mode, I can communicate to the PIC18F252 for over 72 hours without one dropped RS-485 command.

There is another mode, where the system is doing some processor intensive timing. There is a lot of computation during this task, and when I do continuous RS-485 communications during this time, I get a dropped command once every 5-10 minutes.

I have tried disabling ALL interrupts (Except the RS-485 interrupt) and this did not solve the problem. I have tried making the RS-485 interrupt the highest priority interrupt and that also did not solve the problem. I do not know why this is happening if this is run off of an interrupt and has the highest priority.

Could the intensive calculations be disabling (or delaying) the interrupt long enough to cause the PIC to miss some of the RS-485 commands?

Has anyone had a similar problem or point me in the right direction?
treitmey



Joined: 23 Jan 2004
Posts: 1094
Location: Appleton,WI USA

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

PostPosted: Fri Feb 17, 2006 8:20 am     Reply with quote

For a first stab in the dark, I'd try to increase the buffer 485 is using.
Getting data will always throw that IRQ. But if the buufer is too small the data may still get lost.
jseidmann



Joined: 04 Nov 2004
Posts: 67

View user's profile Send private message Send e-mail

PostPosted: Fri Feb 17, 2006 8:28 am     Reply with quote

The recieve buffer size is 128 characters. The command being sent to the PIC is 8 ASCII characters plus a CR+LF on both ends. This adds up to 12 total characters. 128 seems to be overkill, no?

I looked at some previous tests that I did, and it seems that replacing some of the computation with hardcoded values (e.g. values are not being calculated but are just being set) and that did not solve the problem, but the failures happenned less often.

Think I should extend the receive buffer from 128 to 256 and give that a shot? Does that make sense?
asmallri



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

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

PostPosted: Fri Feb 17, 2006 9:01 am     Reply with quote

From your description your buffer is big enough. Are you making any cals in your interrupt handler to functions that are also called in the main body? If this is the case it could be that the compiler is inserting a disable interrupt instruction in the main body.
_________________
Regards, Andrew

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



Joined: 04 Nov 2004
Posts: 67

View user's profile Send private message Send e-mail

PostPosted: Fri Feb 17, 2006 9:55 am     Reply with quote

Perhaps I am misunderstanding your message, but if I am calling a function in my interrupt service routine that is also called in the main body, why would the compiler insert a disable interrupt instruction at this point?
jseidmann



Joined: 04 Nov 2004
Posts: 67

View user's profile Send private message Send e-mail

PostPosted: Fri Feb 17, 2006 9:59 am     Reply with quote

As an update on the recieve buffer, I did a test:

I added to the code a line that would write to the EEPROM a value of 255 in a specific address when the current recieve buffer 'value' was greater than HALF of the size of the reieve buffer size. I had a few RS-485 "drops" and I looked in the EEPROM and the value was what it had been originally, so the size of the recieve buffer does not appear to be the problem.

I appreciate everyone's input and help, and I am very grateful!

Thanks.
Ttelmah
Guest







PostPosted: Fri Feb 17, 2006 10:02 am     Reply with quote

As Asmalli says, certain combinations can lead to disabled interrupts (some long threads about this, not that long ago). There are also a couple of commands, that in certain circumstances, will disable interrupts, even if not used in both locations. Obvious ones, are things like program memory writes, but also certain operations using table accesses, will do this 'by default'.
One thing that may help, is slightly modifying the RS232 receive code. If you use something like:
Code:

#int_RDA
void RDA_isr(void) {
     //Receive data
     do {
        buff[RSlocn]=getc();
        RSlocn = ((BSIZE-1) & RSlocn++)
     } while(kbhit());
}

If calling the routine has been delayed a significant time, and the code is called, and a second character arrives while the (suprisingly slow) array access takes place, then this will retrieve the character. Using the binary '&', is quicker than using the mod function, to generate the new buffer address (provided the buffer size is a binary multiple), and leaving out overflow tests, may also be acceptable, with a relatively oversized buffer.
A search through the list file, for the interrupts being disabled, may be the only solution toactually finding the problem. It is possible that once found, a simple 'splitting up' of the operation, may result in the interrupts only being disabled for a shorter time.

Best Wishes
Ttelmah
Guest







PostPosted: Fri Feb 17, 2006 10:07 am     Reply with quote

jseidmann wrote:
Perhaps I am misunderstanding your message, but if I am calling a function in my interrupt service routine that is also called in the main body, why would the compiler insert a disable interrupt instruction at this point?


This is the critical thing to understand. The PIC, does not have any variable stack. As such, it is very difficult indeed, to write code that is 're-entrant' (multiple copies can run inside other copies of the same routine). Hence if a function exists in the interrupt handler, and does not have seperate code, interrupts have to be disabled at any time the same function is used in the main code.
Now you can with care, in many cases, force the compiler to generate seperate versions of the code for such functions, but by default it does not.

Best Wishes
jseidmann



Joined: 04 Nov 2004
Posts: 67

View user's profile Send private message Send e-mail

PostPosted: Fri Feb 17, 2006 10:14 am     Reply with quote

Thank you for your explanation tTelmah. Looking at my code, in my TIMER2 interrupt (the interrupt which is HIGHER priority than the RS-485), there is:

1 READ_EEPROM command
25 OUTPUT_BIT commands

Would either of these cause the compiler to add a disable_interrupt?

You may be thinking that the TIMER2 interrupt is causing the RS-485 problems, but I have tried making the INT_RDA interrupt higher priority than the TIMER2 with no effect.

Thanks
jseidmann



Joined: 04 Nov 2004
Posts: 67

View user's profile Send private message Send e-mail

PostPosted: Fri Feb 17, 2006 10:18 am     Reply with quote

Looking at the code for both TIMER2 and INT_RDA interrupt routines, there is no command in those interrupt routines that is being called from anywhere other than those routines (with the exception of read_eeprom and output_bit commands).
Ttelmah
Guest







PostPosted: Fri Feb 17, 2006 10:27 am     Reply with quote

jseidmann wrote:
Thank you for your explanation tTelmah. Looking at my code, in my TIMER2 interrupt (the interrupt which is HIGHER priority than the RS-485), there is:

1 READ_EEPROM command
25 OUTPUT_BIT commands

Would either of these cause the compiler to add a disable_interrupt?

You may be thinking that the TIMER2 interrupt is causing the RS-485 problems, but I have tried making the INT_RDA interrupt higher priority than the TIMER2 with no effect.

Thanks


The input, and output functions are generated as 'inline' (hence don't have this problem). Do you have any eeprom reads in the main code?. If so, the interrupts will be disabled for these anyway. However only for about 10 instruction times. Do you have any eeprom writes?. These are much more of a problem (take a lot longer...).
It is perhaps important to understand, that 'priority', does not actually do very much. All it specifies is the order in which the routines are polled, in the global interrupt handler. Setting INT_RDA to a higher priority, will have no effect, if the timer2 interrupt handler itself, takes longer than one character tie to complete. If it does, and a character arrives immediately after it is called, then this will not be handled in time.
Use #INT_RDA HIGH, in combination with the 'high_ints = true' definition, to make INT_RDA, switch to using the hardware high priority, which will allow it to interupt the timer interrupt.

Best Wishes
jseidmann



Joined: 04 Nov 2004
Posts: 67

View user's profile Send private message Send e-mail

PostPosted: Fri Feb 17, 2006 11:01 am     Reply with quote

In the main code, there are about 25 'read_eeprom' commands, with another probably an extra 30-40 'read_eeprom' in functions CALLED from the main code.

There are no 'write_eeprom' commands from the main loop, although the program I am using to test how many commands are being "dropped" by the RS-485 continuously reads and writes to the EEPROM. I'm not sure this is a problem because when my system is in "standby" mode, it is still performing the RS-485 communication and reading/writing to the EEPROM flawlessly.

I am not sure I can use the #INT_RDA HIGH and 'high_ints = true' because my compiler version is 3.190 and does not have this feature. Any other possibilities?
Ttelmah
Guest







PostPosted: Fri Feb 17, 2006 11:16 am     Reply with quote

Do it yourself. The HIGH option should work (you don't need the device option on the older compilers), but will generate a handler, with no register saving. Since you will only have one interrupt source, look through the LST file, and find what registers are changed in the interrupt, save these, then execute your interrupt code, clear the interrupt, restore the registers, and exit. Something possibly like:
Code:

#int_RDA FAST
dum() {
   //Interrupt handler
   static int INT_scratch[15];
   #ASM
   MOVFF   FSR0L,INT_scratch
   MOVFF   FSR0H,INT_scratch+1
   MOVFF   FSR1L,INT_scratch+2
   MOVFF   FSR1H,INT_scratch+3
   MOVFF   FSR2L,INT_scratch+4
   MOVFF   FSR2H,INT_scratch+5
   MOVFF   scratch1,INT_scratch+7
   MOVFF   scratch2,INT_scratch+8
   MOVFF   scratch3,INT_scratch+9
                MOVFF TBLPTRL,INT_scratch+10
                MOVFF TBLPTRH,INT_scratch+11
                MOVFF TBLPTRU,INT_scratch+12
                MOVFF scratch,INT_scratch+13
                MOVFF scratch0,INT_scratch+14
#endasm
   rxint();
#asm
EXIT:
                MOVFF      INT_scratch,FSR0L
   MOVFF   INT_scratch+1,FSR0H
   MOVFF   INT_scratch+2,FSR1L
   MOVFF   INT_scratch+3,FSR1H
   MOVFF   INT_scratch+4,FSR2L
   MOVFF   INT_scratch+5,FSR2H
   MOVFF   INT_scratch+6,scratch
   MOVFF   INT_scratch+7,scratch1
   MOVFF   INT_scratch+8,scratch2
   MOVFF   INT_scratch+9,scratch3
                MOVFF INT_scratch+10,TBLPTRL
                MOVFF INT_scratch+11,TBLPTRH
                MOVFF INT_scratch+12,TBLPTRU
   MOVFF INT_scratch+13,scratch
                MOVFF INT_scratch+14,scratch0
#ENDASM
}

Make sure to clear the interrupt flag at the end of the rxint routine.
I'm not sure whether your version supports 'FAST'. If not, you have to code this as 'high', and manually add a retfie 1 at the end of the routine. If your compiler doesn't support RETFIE 1, then you have to use a #ROM statement to insert the code for this. On the even older compilers, you have to write this at a seperate address, and jump to it, since the HIGH interrupt vector doesn't leave space for the code...
I had 'high' interrupts, working in some form or other, from a very early point in the V3 compilers. It is possible, it just takes a bit more work...

Best Wishes
jseidmann



Joined: 04 Nov 2004
Posts: 67

View user's profile Send private message Send e-mail

PostPosted: Fri Feb 17, 2006 11:25 am     Reply with quote

tTelmah,

I think this register work is a bit beyond my expertise. I think I will just have to bite the bullet and upgrade the compiler and use the HIGH interrupt as you suggested before. I will let you all know how it goes.

BTW, Once I update the compiler, is there any advantage in using the RTOS for this type of stuff? Will it help matters?
guy



Joined: 21 Oct 2005
Posts: 297

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

Just add ERRORS
PostPosted: Mon Apr 24, 2006 6:33 am     Reply with quote

Probably you don't need it anymore, but in the #use rs232 add the option ERRORS. This is extremely important since if an error occurs (including hardware-buffer full) the software will simply not receive any more characters!
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