View previous topic :: View next topic |
Author |
Message |
jseidmann
Joined: 04 Nov 2004 Posts: 67
|
HIGH_INTS = TRUE |
Posted: Tue Feb 21, 2006 4:24 pm |
|
|
I am currently using the PCWH version 3.190 and I am considering upgrading to the newest compiler version, specifically to get access to the '#DEVICE HIGH_INTS = TRUE' command.
The reason is because I want to be able to have my INT_RDA a higher priority. I am having some problems with my RS-485 and believe that having a hardware interrupt (this is what HIGH_INTS does, no?) will help me out.
My question is: do I understand this correctly? Is that what HIGH_INTS does? If so, how do I implement it? Do I just add that one line? Do I need to add anything else?
Any comments are appreciated,
thanks |
|
|
treitmey
Joined: 23 Jan 2004 Posts: 1094 Location: Appleton,WI USA
|
|
Posted: Tue Feb 21, 2006 4:52 pm |
|
|
HIGH_INTS are beyond my scope.
They have to do with the stack and a high int breaking out of a low int.
BUT
Have you tried #priority? |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Tue Feb 21, 2006 5:56 pm |
|
|
Quote: | The reason is because I want to be able to have my INT_RDA a higher priority. I am having some problems with my RS-485 and believe that having a hardware interrupt (this is what HIGH_INTS does, no?) will help me out. | I'm not sure I understand this question correctly, it implies you are currently not using any hardware interrupts at all. Is that true?
From the readme.txt of v3.241: Quote: | PIC18 interrupts now allow the HIGH option to mark an interrupt as high priority.
A summary of the different kinds of PIC18 interupts:
#INT_xxxx
Normal (low priority) interrupt. Compiler saves/restores key registers.
This interrupt will not interrupt any interrupt in progress.
#INT_xxxx FAST
High priority interrupt. Compiler DOES NOT save/restore key registers.
This interrupt will interrupt any normal interrupt in progress.
Only one is allowed in a program.
#INT_xxxx HIGH
High priority interrupt. Compiler saves/restores key registers.
This interrupt will interrupt any normal interrupt in progress.
#INT_GLOBAL
Compiler generates no interrupt code. User function is located
at address 8 for user interrupt handling. |
All these options are available in v3.190 except for the HIGH keyword.
The PIC18 processor has two levels of hardware interrupts: normal and high priority. Normal interrupts are easy to implement using the #INT_xxx keywords. If you want to be able to interrupt an already active interrupt than you need to code that as an High priority interrupt.
The high priority interrupts can be used in v3.190 using the FAST keyword but you as the programmer will have to take care of saving and restoring all used registers. The new HIGH keyword takes this burden out of your hands but at the cost of saving all registers, not just the few you are actually using. Still, the HIGH keyword is usefull when you want a quick and sure implementation of an interrupt that can interrupt a lower priority interrupt.
Using the High priority interrupts caused many people headaches because they forgot to save a register. If you don't need the quality of an interrupt being interrupted by another interrupt then have a look at the easier to implement #priority keyword as Treitmey already pointed to. |
|
|
jseidmann
Joined: 04 Nov 2004 Posts: 67
|
|
Posted: Wed Feb 22, 2006 7:40 am |
|
|
To clear a few things up, here is my situation:
I am using a PIC18F252 on a fairly intensive data acquisition product. When this product is 'off' so to speak, that its only collecting some data, then the RS-485 works flawlessly for 72 hours (thats how long I ran a test for).
If I turn on all of the data acquisition capabilities, it 'drop's' some RS-485 commands. It drops roughly 25 commands an hour (running at 19200 baud).
The interrupts are never disabled at any time. Ever. My question is that since the RS-485 interrupt should ALWAYS be interrupting any routine that the main program is in, I should never be having this RS-485 problem, but for some reason this problem is happening.
I am currently using 2 interrupts, the INT_RDA, and the TIMER2 interrupt which executes every 1/2 a millisecond. INT_RDA has been made a higher priority on the #PRIORITY with no improvement in the RS-485 performance. I feel that perhaps by using the HIGH_INTS = TRUE and making the RDA a #INT_RDA HIGH will improve this. Does that make sense? I tried making the #INT_RDA FAST, but the data acquisition process that used the TIMER2 interrupt did not work at all.
I am certainly up for any suggestions, but remember I am using compiler 3.190
Thanks! |
|
|
MikeValencia
Joined: 04 Aug 2004 Posts: 238 Location: Chicago
|
|
Posted: Wed Feb 22, 2006 8:21 am |
|
|
I use
#priority EXT,TIMER3
in my code. Also, instead of using high priority interrupts (since the syntax overwhelms me!), i do the following:
Say i'm in the TIMER3 isr, then I check if the EXT interrupt flag is set. So I just call the function called by my INT_EXT isr. This way i avoid the latency of exiting the current isr, and then re-entering the pending isr.
There is still some latency, which depends on how soon you check for the pending interrupt flag while still in the current interrupt, but it is significantly reduced. |
|
|
jseidmann
Joined: 04 Nov 2004 Posts: 67
|
|
Posted: Wed Feb 22, 2006 8:31 am |
|
|
How do I check if the interrupt flag is set as you suggest? |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Wed Feb 22, 2006 8:48 am |
|
|
Another optimization that often is overlooked in the int_rda handling is that you can check for more characters to be waiting. The hardware UART can buffer up to three characters and you can read all of them in a loop instead of only reading a single character.
Code: | unsigned char RCREG;
#locate RCREG=0x0FAE
unsigned char RCSTA;
#locate RCSTA=0x0FAB
struct {
unsigned char RX9D:1;
unsigned char OERR:1;
unsigned char FERR:1;
unsigned char ADDEN:1;
unsigned char CREN:1;
unsigned char SREN:1;
unsigned char RX9:1;
unsigned char SPEN:1;
} RCSTAbits;
#locate RCSTAbits=0x0FAB
//-----------------------------------------------------------------------------
// Received data interrupt
//-----------------------------------------------------------------------------
#int_rda
void Rx_Isr(void)
{
char NewChar;
do
{
// Read the character from the UART buffer.
// Remember that even if OERR, was asserted, the data buffers
// will be full, and you must read the character, or the
// error will re-assert almost immediately...
NewChar = RCREG;
// Check for errors
if (RCSTAbits.OERR)
{
// Clear overrun error bit
RCSTAbits.CREN=0;
RCSTAbits.CREN=1;
// Optional: add a global error flag for error detection.
}
SaveToRxCircularbuffer(NewChar);
} while (kbhit()); // while (character is waiting);
} |
|
|
|
MikeValencia
Joined: 04 Aug 2004 Posts: 238 Location: Chicago
|
|
Posted: Wed Feb 22, 2006 12:42 pm |
|
|
jseidmann wrote: | How do I check if the interrupt flag is set as you suggest? |
Code: |
if (PIC_INTCON & PIC_INTCON_INT01F)
{
...
|
I just check the particular interrupt flag bit in the INTCON register. The snippet above shows me checking if the external interrupt flag bit (RB0) is set. |
|
|
Ttelmah Guest
|
|
Posted: Thu Feb 23, 2006 3:23 am |
|
|
As a comment, it is probably more efficient, to just declare the flag with a #bit declaration.So (for a PIC18):
Code: |
#byte INTCON = 0xFF2
#bit EXT0IF = INTCON.1
|
Then do your test as:
Code: |
do {
//Remember _you_ must clear this flag
EXT0IF=0;
//Receive code here
}while (EXT0IF);
|
If declared like this, the compiler just does a bit test (one instruction), while with the '&', it probably does generate the extra logic this entails (the latest optimisers may be good enough to not do this though...).
Declare the interrupt with the 'NOCLEAR' option, sice you are taking over control of the interrupt flag.
Best Wishes |
|
|
MikeValencia
Joined: 04 Aug 2004 Posts: 238 Location: Chicago
|
|
Posted: Thu Feb 23, 2006 8:49 am |
|
|
[code]
.................... if (PIC_INTCON & PIC_INTCON_INT01F)
03A4: BTFSS FF2.1
03A6: BRA 03B4
[/code
Actually the generated assembly is optimized with a one-line btfss statement. I totally agree though that using #bit to declare it is more readable and use-able. I remember in my past job that it irked some people maintaining my code that all my code looks like cryptic logical operations. |
|
|
asmallri
Joined: 12 Aug 2004 Posts: 1634 Location: Perth, Australia
|
|
Posted: Thu Feb 23, 2006 9:29 am |
|
|
Quote: | The interrupts are never disabled at any time. Ever. |
Are you sure? The compiler will disable interrupts itself under certain conditions.
[quote] I am using a PIC18F252 on a fairly intensive data acquisition product. When this product is 'off' so to speak, that its only collecting some data, then the RS-485 works flawlessly for 72 hours (thats how long I ran a test for).
If I turn on all of the data acquisition capabilities, it 'drop's' some RS-485 commands. It drops roughly 25 commands an hour (running at 19200 baud). [quote]
On one of my data acquisition systems based on a PIC18F252, I run a RS485 software UART at 56K, a RS232 SW FDX uart at 115200, and a HW FDX UART at 115200. The RS485 traffic rate in normal operation is 18,000 packets per hour without packet loss.
From your description, it sounds like you are spending too long in some other interrupt handler causing characters to be missed or the compiler is disabling interrupts in the main body of code. _________________ Regards, Andrew
http://www.brushelectronics.com/software
Home of Ethernet, SD card and Encrypted Serial Bootloaders for PICs!! |
|
|
EdWaugh
Joined: 07 Dec 2004 Posts: 127 Location: Southampton, UK
|
cheers |
Posted: Tue Aug 01, 2006 6:50 am |
|
|
Hi,
Just wanted to say cheers to ckielstra for his great tip on the hardware buffer being 3 bytes long, by reading all present instead of just one I fixed my code.
cheers
ed |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
Re: cheers |
Posted: Tue Aug 01, 2006 7:28 am |
|
|
EdWaugh wrote: | Just wanted to say cheers to ckielstra for his great tip on the hardware buffer being 3 bytes long, by reading all present instead of just one I fixed my code. | You're welcome. |
|
|
EdWaugh
Joined: 07 Dec 2004 Posts: 127 Location: Southampton, UK
|
actually... |
Posted: Tue Aug 01, 2006 8:01 am |
|
|
Hi,
My code is much better now with the previous suggestions but I've noticed a little bit of occasional data corruption. This wasn't present during some testing I did just transfering bytes from one serial port to another using my circular buffers but is now when I add the rest of my code.
Basically I have a rs232 device that throws a string at me at 8Hz. I use a high priority rda interrupt to read as many chars as are available and test OERR like ckielstra suggests. This just chucks these into a circular buffer.
There is also a 40Hz timed interrupt that amongst other (fast) things checks the circular buffer and once a full sentence is received writes it to the mmc card buffer using:
Code: | printf(mmc_add_to_buffer, "%s", str_compass); |
I'm guessing its a problem at the char receive level still, I'm gonna have a play around but as this seemed fairly well trodden ground I thought I would see if anyone had any suggestions. The errors are a few chars in length and occur intermitantly.
cheers
ed |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Tue Aug 01, 2006 11:55 am |
|
|
Use the error-flags of the UART to figure out if it is a framing error or an buffer overrun error.
In case of framing error the problem is most likely a timing error between the clock speed of the sender and receiver. Only about 5% total error margin for sender and receiver together is allowed. Some PC's are known to be terrible inaccurate.
In case of an overrun error you know you are reading too slow. Do you have other interrupts active? Also note that some of the compiler inbuilt functions will disable all interrupts, think of functions like memcpy and a software UART. |
|
|
|