|
|
View previous topic :: View next topic |
Author |
Message |
jseidmann
Joined: 04 Nov 2004 Posts: 67
|
Faulty RS-485 Communication during processor intensive tasks |
Posted: Fri Feb 17, 2006 7:57 am |
|
|
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
|
|
Posted: Fri Feb 17, 2006 8:20 am |
|
|
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
|
|
Posted: Fri Feb 17, 2006 8:28 am |
|
|
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
|
|
Posted: Fri Feb 17, 2006 9:01 am |
|
|
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
|
|
Posted: Fri Feb 17, 2006 9:55 am |
|
|
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
|
|
Posted: Fri Feb 17, 2006 9:59 am |
|
|
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
|
|
Posted: Fri Feb 17, 2006 10:02 am |
|
|
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
|
|
Posted: Fri Feb 17, 2006 10:07 am |
|
|
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
|
|
Posted: Fri Feb 17, 2006 10:14 am |
|
|
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
|
|
Posted: Fri Feb 17, 2006 10:18 am |
|
|
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
|
|
Posted: Fri Feb 17, 2006 10:27 am |
|
|
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
|
|
Posted: Fri Feb 17, 2006 11:01 am |
|
|
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
|
|
Posted: Fri Feb 17, 2006 11:16 am |
|
|
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
|
|
Posted: Fri Feb 17, 2006 11:25 am |
|
|
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
|
Just add ERRORS |
Posted: Mon Apr 24, 2006 6:33 am |
|
|
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! |
|
|
|
|
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
|