![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
E_Blue
Joined: 13 Apr 2011 Posts: 417
|
Questions about int_global |
Posted: Mon Jul 20, 2015 9:08 am |
|
|
I'm struggling with High and Low interrupts in a PIC18F67J50, time to time, the CCS interrupt dispatcher make a mess with FSR and BSR registers, specially with FSR in delay routines and with the BSR with USB stack.
So, I wonder if there an example about how to, and what register take in account when we do our own interrupt dispatcher.
I know how to handle interrupts, I start with ASM in 1999, so I'm familiar with those procedures but I'm dubious about all those temporary registers that CCS compiler uses to pass data from one function to another, for example.
I don't know their RAM addresses and how many they are. _________________ Electric Blue |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19369
|
|
Posted: Mon Jul 20, 2015 10:30 am |
|
|
ex_glint.c with the compiler.
On what registers to save, this is completely dependent on what _your_ code does in the interrupts.
Ideally you look through the assembler for every routine in the interrupt, and then save every register these use.
CCS's approach is to save everything, and should be totally OK.
You don't say what compiler version?.
With the current releases, I've not seen a single problem with BSR or FSR. Thing that _will_ cause problems are where any variable is 16bit or larger, and is accessed inside the ISR, and in the main code. Two solutions:
Code: |
float int16 etc., variable_used; //global variable used
//both inside and outside the ISR.
float int16 etc. local_copy.
//Then to read a variable:
{
local_copy=variable_used
} while (local_variable!=variable_used;
//Or
disable_interrupts(GLOBAL);
local_variable=variable_used;
enable_interrupts(GLOBAL);
|
To write a variable used in the ISR, you basically have to use the disable_interrupts approach.
This is vital for any variable where values pass to/from the ISR. I have a macro defined which you give the local name, and the global name, and it handles the transfer.
The same would be needed even if you use the INT_GLOBAL approach.
Are you declaring the high priority interrupt as HIGH or FAST?. _FAST_ is equivalent to INT_GLOBAL for the high priority interrupts. The compiler does not save the registers. If you are using this, then this would explain your problems. You can only declare one handler as FAST, and this will be called for all high priority interrupts, and you have to write your own saving routine and dispatcher in this. Normally you should use HIGH.
Edited to add one other comment.
A thing that is commonly 'forgotten', is that INT_EXT does not have a priority bit on most PIC's. If interrupt priorities are enabled, INT_EXT is always 'HIGH'. Needs to be remembered. |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
![](templates/subSilver/images/spacer.gif) |
E_Blue
Joined: 13 Apr 2011 Posts: 417
|
|
Posted: Tue Jul 21, 2015 7:37 am |
|
|
I'm using V5.048
I was using
Code: | #DEVICE HIGH_INTS=TRUE |
I'm not using INT_EXT
I tried declaring that struct as volatile, same result, a mess with the FSR
I tried disabling the interrupts during the delay routine, it works ok.
I tried using only one level of interrupts for all interrupts and work to.
So, I think that the problem is in the context saving of High Interrupts.
@PCM thanks for the links I will read it. _________________ Electric Blue |
|
![](templates/subSilver/images/spacer.gif) |
jeremiah
Joined: 20 Jul 2010 Posts: 1329
|
|
Posted: Tue Jul 21, 2015 9:23 am |
|
|
Perhaps someone with 5.048 (preferably the OP, but either way I don't have that version currently) can generate a small test program so we can take a look at the assembly and see what is going on (and hopefully generate a bug report for CCS for someone to email).
It would just need the basics:
device include
fuses
clock settings
interrupt handler
main
They don't have to do anything particularly interesting since all we care about is seeing the context save process CCS generates. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19369
|
|
Posted: Tue Jul 21, 2015 2:21 pm |
|
|
So how do you declare the actual interrupt you are using as high priority?.
You do understand that _two_ things are needed before an interrupt is high priority?.
First 'HIGH_INTS=TRUE', and then the interrupt that you want to be high priority has to be declared as:
Code: |
#INT_xxxx HIGH //Note the 'HIGH'
void handler_for_whateverinterrupt_it_is(void)
{
......
}
|
Until both these are done, no interrupt is high priority......
However the normal interrupts will respond _slower_. as soon as HIGH_INTS=TRUE is used, since the compiler then reserves the RETFIE 1 for the high interrupts.
There is also a problem is you add HIGH_INTS=TRUE, and do _not_ declare any interrupt as high, and INT_EXT is used.
What happens here is that if any interrupt is declared as 'HIGH' the compiler knows about INT_EXT, and will automatically add this to the HIGH interrupt handler. However if the HIGH_INTS=TRUE is used and no interrupt is declared as HIGH, then the compiler does not generate a HIGH handler, and INT_EXT, will jump into the existing LOW handler, missing the first few instructions, and corrupting the registers saved in the first four instructions. Exactly what is being described....
So, though you assure us INT_EXT is not being used. Triple check that something is not using this....
The register saving does work correctly on the current compilers, if it is used correctly. |
|
![](templates/subSilver/images/spacer.gif) |
E_Blue
Joined: 13 Apr 2011 Posts: 417
|
|
Posted: Fri Jul 24, 2015 3:49 pm |
|
|
Yes I'm using, or was using, both 'HIGH_INTS=TRUE' and #INT_RDA2 HIGH .
I'm dubious about #priority
It's ok to use
Code: | #priority INT_RDA2,INT_RDA,INT_TBE,INT_CCP1,INT_AD |
if only RDA2 is used as HIGH?
I'm using USB stack by interrupt but I think that is used in LOW PRIORITY INT because I see at the disassembly code and high int only check RDA2 int.
Quote: | 00008: GOTO 0116
0000C: NOP
0000E: NOP
00010: NOP
00012: NOP
00014: NOP
00016: NOP
00018: MOVWF 04
0001A: MOVFF FD8,05 //STATUS
0001E: MOVFF FE0,06 //BSR
00022: MOVLB 0
00024: MOVFF FE9,0C //FSR0
00028: MOVFF FEA,07 //FSR0
0002C: MOVFF FE1,08 //FSR1
00030: MOVFF FE2,09 //FSR1
00034: MOVFF FD9,0A //FSR2
00038: MOVFF FDA,0B //FSR2
0003C: MOVFF FF3,12 //PRODL
00040: MOVFF FF4,13 //PRODH
00044: MOVFF FFA,14 //PCLATH
00048: MOVFF FF5,15 //TABLAT
0004C: MOVFF FF6,16 //TBLPTRL
00050: MOVFF FF7,17 //TBLPTRH
00054: MOVFF FF8,18 //TBLPTRU
00058: MOVFF FFB,19 //PCLATU
0005C: MOVFF 00,0E
00060: MOVFF 01,0F
00064: MOVFF 02,10
00068: MOVFF 03,11
0006C: BTFSS F9D.5
0006E: GOTO 0078
00072: BTFSC F9E.5
00074: GOTO 9D62
00078: BTFSS F9D.2
0007A: GOTO 0084
0007E: BTFSC F9E.2
00080: GOTO F6AA
00084: BTFSS F9D.6
00086: GOTO 0090
0008A: BTFSC F9E.6
0008C: GOTO F962
00090: BTFSS F9D.0
00092: GOTO 009C
00096: BTFSC F9E.0
00098: GOTO FBA0
0009C: BTFSS F9D.4
0009E: GOTO 00A8
000A2: BTFSC F9E.4
000A4: GOTO 50AE
000A8: BTFSS FA0.0
000AA: GOTO 00B4
000AE: BTFSC FA1.0
000B0: GOTO E146
000B4: BTFSS FA0.4
000B6: GOTO 00C0
000BA: BTFSC FA1.4
000BC: GOTO 134A
000C0: MOVFF 0E,00
000C4: MOVFF 0F,01
000C8: MOVFF 10,02
000CC: MOVFF 11,03
000D0: MOVFF 0C,FE9
000D4: MOVFF 07,FEA
000D8: BSF 07.7
000DA: MOVFF 08,FE1
000DE: MOVFF 09,FE2
000E2: MOVFF 0A,FD9
000E6: MOVFF 0B,FDA
000EA: MOVFF 12,FF3
000EE: MOVFF 13,FF4
000F2: MOVFF 14,FFA
000F6: MOVFF 15,FF5
000FA: MOVFF 16,FF6
000FE: MOVFF 17,FF7
00102: MOVFF 18,FF8
00106: MOVFF 19,FFB
0010A: MOVF 04,W
0010C: MOVFF 06,FE0
00110: MOVFF 05,FD8
00114: RETFIE 0
//High dispatcher IN
00116: MOVLB 0
00118: MOVFF FE9,21
0011C: MOVFF FEA,1C
00120: MOVFF FE1,1D
00124: MOVFF FE2,1E
00128: MOVFF FD9,1F
0012C: MOVFF FDA,20
00130: MOVFF FF3,27
00134: MOVFF FF4,28
00138: MOVFF FFA,29
0013C: MOVFF FF5,2A
00140: MOVFF FF6,2B
00144: MOVFF FF7,2C
00148: MOVFF FF8,2D
0014C: MOVFF FFB,2E
00150: MOVFF 00,23
00154: MOVFF 01,24
00158: MOVFF 02,25
0015C: MOVFF 03,26
00160: BTFSS FA3.5
00162: GOTO 016C
00166: BTFSC FA4.5
00168: GOTO B40A
//High distpacher OUT
0016C: MOVFF 23,00
00170: MOVFF 24,01
00174: MOVFF 25,02
00178: MOVFF 26,03
0017C: MOVFF 21,FE9
00180: MOVFF 1C,FEA
00184: BSF 1C.7
00186: MOVFF 1D,FE1
0018A: MOVFF 1E,FE2
0018E: MOVFF 1F,FD9
00192: MOVFF 20,FDA
00196: MOVFF 27,FF3
0019A: MOVFF 28,FF4
0019E: MOVFF 29,FFA
001A2: MOVFF 2A,FF5
001A6: MOVFF 2B,FF6
001AA: MOVFF 2C,FF7
001AE: MOVFF 2D,FF8
001B2: MOVFF 2E,FFB
001B6: RETFIE 1 |
_________________ Electric Blue |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19369
|
|
Posted: Sat Jul 25, 2015 1:04 am |
|
|
#PRIORITY has nothing to do with the priority of interrupts!.....
It dates from before PIC's had any form of hardware priority. It sets the order that the interrupt flags are polled in the CCS global handler. So if two interrupts occur 'together', the one set first in this, will be the one seen. This will then be handled, and followed by the second interrupt.
In fact though by default the order is the order the interrupt handlers are declared if this is omitted. I prefer to use this, since then the order in the code, is the order the handlers are dealt with.
So, get rid of #priority, or only include interrupts using the standard handler.
Or preferably just declare your interrupt handlers in the order you want them to be checked.
What on earth are you using INT_AD for?.
Understand that getting into and out of an interrupt handler usually takes longer than the ADC takes to perform a conversion (or a very similar time). INT_AD should only be used, where you are using an 'event' to trigger the ADC (CCP). Otherwise this is extra unwanted complexity.
Just amended this.
Have you looked at the errata sheet?.
Add 'delay_cycles(1); delay_cycles(1)' after any instruction that enables the UART (setup_uart), or make sure you disable the interrupts before this is done.
There is also a problem if using timer1 or 3 in async mode. |
|
![](templates/subSilver/images/spacer.gif) |
E_Blue
Joined: 13 Apr 2011 Posts: 417
|
|
Posted: Mon Jul 27, 2015 6:33 am |
|
|
If I use only one interrupt level the programs runs ok, so I'm running the program that way now.
So, I think, the problem is in the interrupt dispatcher.
I use INT_AD because the program must process two USART at 19200bps, USB data and one SPI at 3MHZ, all running from an state machine on CCP1 and CCP2 interrupts.
The CCP1 INT have a lot of work to do, so when start an AD conversion continues with rest of the tasks.
Plus the A/D is running slow on purpose because is running on high noisy environment. _________________ Electric Blue |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19369
|
|
Posted: Mon Jul 27, 2015 7:39 am |
|
|
So, don't have a CCP1 interrupt.
Program the CCP with a special event trigger to start the ADC.
Then use the ADC interrupt to read the ADC, and do the tasks you want from the CCP.
The more interrupts you have, the longer the latency in the worst case.
Separately, if there is an SPI slave, this is the one that needs to be high priority. SPI has no margin at all, _requiring_ the data to be loaded before the next transaction starts. The UART has a whole character time of buffering.
It's almost certainly when you enable the high priority UART interrupt it is delaying the SPI too much, hence your problems....
It sounds as if you are doing much too much inside interrupts.
Running the ADC slower does not help it reject noise. It makes it's overall accuracy worse. Once the internal capacitor is disconnected from the external pin, it starts charging or discharging according to leakages in the chip. By the time the last bit is read, this becomes significant. Microchip generally recommend that the Tad is as close to their minimum specified as possible.
In fact the data sheet for your chip says:
"For correct A/D conversions, the A/D conversion clock
(TAD) must be as short as possible but greater than the
minimum TAD". |
|
![](templates/subSilver/images/spacer.gif) |
E_Blue
Joined: 13 Apr 2011 Posts: 417
|
|
Posted: Mon Jul 27, 2015 8:10 am |
|
|
I'm using CCP1 this way
Code: |
SETUP_TIMER_1(0b00001010);
CCP_1=8192;
SETUP_CCP1(CCP_COMPARE_RESET_TIMER); |
_________________ Electric Blue |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19369
|
|
Posted: Mon Jul 27, 2015 8:26 am |
|
|
So, don't enable INT_CCP1.
Just use INT_AD.
Get rid of the extra interrupt.
It'll arrive at INT_AD automatically after the CCP event has triggered _and_ the ADC has converted. As setup, this is already starting an ADC conversion. Speed the ADC up. I think you misunderstand, and think that the ADC will integrate while converting if you run it slower. It doesn't. It's a successive approximation ADC and the capacitor is disconnected during conversion. |
|
![](templates/subSilver/images/spacer.gif) |
E_Blue
Joined: 13 Apr 2011 Posts: 417
|
|
Posted: Mon Jul 27, 2015 9:26 am |
|
|
Yes I have both interrupts running CCP1 and A/D besides the other ones(USART2,USB,CCP2 and Timer1)
The program doesn't run at same speed all the time, have 3 clock speeds, 48MHZ full running, 8MHz in low power mode, and 32KHz during sleep mode. _________________ Electric Blue |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19369
|
|
Posted: Mon Jul 27, 2015 2:29 pm |
|
|
Understand, that the CCP1 interrupt triggers on it's event, and then the INT_AD interrupt will trigger after the ADC has done the conversion. Using both interrupts here is just wasting the seventy or so cycles it takes to get into and out of the first interrupt. Just use INT_AD, and handle the CCP events in this.
Then how can you have INT_TIMER1?. This will never trigger. INT_TIMER1 triggers when timer1, wraps from FFFF to 0000. You are resetting timer1, when it matches the CCP, so it never does this wrap.
Interrupts need to be thought about, not just used 'willy nilly'. |
|
![](templates/subSilver/images/spacer.gif) |
E_Blue
Joined: 13 Apr 2011 Posts: 417
|
|
Posted: Wed Jul 29, 2015 11:30 am |
|
|
Timer1 INT only runs when is in sleep mode, so, before get into sleep mode I change the Timer1 and CCP setup.
In sleep mode the program runs a 32768Hz every 2 seconds. _________________ Electric Blue |
|
![](templates/subSilver/images/spacer.gif) |
|
|
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
|