|
|
View previous topic :: View next topic |
Author |
Message |
nurquhar
Joined: 05 Aug 2006 Posts: 149 Location: Redditch, UK
|
Why does my test for long==0 in timer interrupt not work ? |
Posted: Wed Sep 05, 2007 9:16 am |
|
|
I am having problems with 'if(!timerX)' in the following code.
For some reason testing the 16bit timerX value for zero in my interrupt sometimes gives the wrong result.
I have managed to fix it by reverting the timerX value back to an 8bit int x and then testing that. Indeed I can also solve the bug by changing the defanition of timerX to an 8bit int. But this limits the range for my app.
I am using PCM3.249, PIC16F877A 20mhz and have device *=16 enabled, so bank switching is in play.
Can anyone explain why the compiler is getting it wrong ?
I have included below the FIXED and BROKEN source and asm listings :-
Source BROKEN version
Code: |
//#define FIX_INT
unsigned long timerX = 0 ;
// When timer2 expires update
#int_timer2
void timer2_isr()
{
int x ;
// Update Timer
timerX-- ;
#ifdef FIX_INT
x = make8(timerX,0) + make8(timerX, 1) ;
if(!x) {
#else
if (!timerX) {
#endif
// Timer has run out
timerExpired = 1 ;
// Reload with the next period
timerX = para.timerPeriod ;
if(t0on) tn++ ;
}
if(t0on) tmr0ints++ ;
}
|
Listing BROKEN version
Code: |
663: //#define FIX_INT
664:
665: unsigned long timerX = 0 ;
073B 01F5 CLRF 0x75
073C 01F6 CLRF 0x76
666:
667: // When timer2 expires update
668: #int_timer2
669: void timer2_isr()
670: {
671: int x ;
672: // Update Timer
673: timerX-- ;
00C3 0875 MOVF 0x75, W
00C4 1903 BTFSC 0x3, 0x2
00C5 03F6 DECF 0x76, F
00C6 03F5 DECF 0x75, F
674: #ifdef FIX_INT
675: x = make8(timerX,0) + make8(timerX, 1) ;
676: if(!x) {
677: #else
678: if (!timerX) {
00C7 0875 MOVF 0x75, W
00C8 0476 IORWF 0x76, W
00C9 1D03 BTFSS 0x3, 0x2
00CA 28DA GOTO 0xda
679: #endif
680: // Timer has run out
681: timerExpired = 1 ;
00CB 1433 BSF 0x33, 0
682: // Reload with the next period
683: timerX = para.timerPeriod ;
00CC 0868 MOVF 0x68, W
00CD 00F6 MOVWF 0x76
00CE 0867 MOVF 0x67, W
00CF 00F5 MOVWF 0x75
684: if(t0on) tn++ ;
00D0 1CB3 BTFSS 0x33, 0x1
00D1 28DA GOTO 0xda
00D2 3001 MOVLW 0x1
00D3 07B9 ADDWF 0x39, F
00D4 1803 BTFSC 0x3, 0
00D5 0ABA INCF 0x3a, F
00D6 1903 BTFSC 0x3, 0x2
00D7 0ABB INCF 0x3b, F
00D8 1903 BTFSC 0x3, 0x2
00D9 0ABC INCF 0x3c, F
685: }
686: if(t0on) tmr0ints++ ;
00DA 1CB3 BTFSS 0x33, 0x1
00DB 28E4 GOTO 0xe4
00DC 3001 MOVLW 0x1
00DD 07B5 ADDWF 0x35, F
00DE 1803 BTFSC 0x3, 0
00DF 0AB6 INCF 0x36, F
00E0 1903 BTFSC 0x3, 0x2
00E1 0AB7 INCF 0x37, F
00E2 1903 BTFSC 0x3, 0x2
00E3 0AB8 INCF 0x38, F
687: }
688:
00E4 108C BCF 0xc, 0x1
00E5 118A BCF 0xa, 0x3
00E6 120A BCF 0xa, 0x4
00E7 2825 GOTO 0x25
|
Source FIXED version
Code: |
#define FIX_INT
unsigned long timerX = 0 ;
// When timer2 expires update
#int_timer2
void timer2_isr()
{
int x ;
// Update Timer
timerX-- ;
#ifdef FIX_INT
x = make8(timerX,0) + make8(timerX, 1) ;
if(!x) {
#else
if (!timerX) {
#endif
// Timer has run out
timerExpired = 1 ;
// Reload with the next period
timerX = para.timerPeriod ;
if(t0on) tn++ ;
}
if(t0on) tmr0ints++ ;
}
|
Listing FIXED version
Code: |
663: #define FIX_INT
664:
665: unsigned long timerX = 0 ;
0743 01F5 CLRF 0x75
0744 01F6 CLRF 0x76
666:
667: // When timer2 expires update
668: #int_timer2
669: void timer2_isr()
670: {
671: int x ;
672: // Update Timer
673: timerX-- ;
00C3 0875 MOVF 0x75, W
00C4 1903 BTFSC 0x3, 0x2
00C5 03F6 DECF 0x76, F
00C6 03F5 DECF 0x75, F
674: #ifdef FIX_INT
675: x = make8(timerX,0) + make8(timerX, 1) ;
00C7 0875 MOVF 0x75, W
00C8 1703 BSF 0x3, 0x6
00C9 00A6 MOVWF 0x26
00CA 0876 MOVF 0x76, W
00CB 0726 ADDWF 0x26, W
00CC 00A5 MOVWF 0x25
676: if(!x) {
00CD 08A5 MOVF 0x25, F
00CE 1D03 BTFSS 0x3, 0x2
00CF 28E1 GOTO 0xe1
677: #else
678: if (!timerX) {
679: #endif
680: // Timer has run out
681: timerExpired = 1 ;
00D0 1303 BCF 0x3, 0x6
00D1 1433 BSF 0x33, 0
682: // Reload with the next period
683: timerX = para.timerPeriod ;
00D2 0868 MOVF 0x68, W
00D3 00F6 MOVWF 0x76
00D4 0867 MOVF 0x67, W
00D5 00F5 MOVWF 0x75
684: if(t0on) tn++ ;
00D6 1CB3 BTFSS 0x33, 0x1
00D7 28E0 GOTO 0xe0
00D8 3001 MOVLW 0x1
00D9 07B9 ADDWF 0x39, F
00DA 1803 BTFSC 0x3, 0
00DB 0ABA INCF 0x3a, F
00DC 1903 BTFSC 0x3, 0x2
00DD 0ABB INCF 0x3b, F
00DE 1903 BTFSC 0x3, 0x2
00DF 0ABC INCF 0x3c, F
00E0 1703 BSF 0x3, 0x6
685: }
686: if(t0on) tmr0ints++ ;
00E1 1303 BCF 0x3, 0x6
00E2 1CB3 BTFSS 0x33, 0x1
00E3 28EC GOTO 0xec
00E4 3001 MOVLW 0x1
00E5 07B5 ADDWF 0x35, F
00E6 1803 BTFSC 0x3, 0
00E7 0AB6 INCF 0x36, F
00E8 1903 BTFSC 0x3, 0x2
00E9 0AB7 INCF 0x37, F
00EA 1903 BTFSC 0x3, 0x2
00EB 0AB8 INCF 0x38, F
687: }
688:
00EC 108C BCF 0xc, 0x1
00ED 118A BCF 0xa, 0x3
00EE 120A BCF 0xa, 0x4
00EF 2825 GOTO 0x25
|
|
|
|
Ttelmah Guest
|
|
Posted: Wed Sep 05, 2007 9:43 am |
|
|
The code should work.
You perhaps need to be aware that the 'make8' version, will test as '0', a lot more frequently than the 16bit version.
You are taking the upper byte, and the low byte, and adding them with an 8bit result. You will get 'zero' for this, when the high byte=1, and the low byte 255, then again when the high byte=2, and the low byte 254, etc. etc.. It'll actually give the zero result, every 254 counts, while the 16bit version will only give zero every 65536 counts.
The correct 8bit equivalent, is:
x = make8(timerX,0) | make8(timerX, 1) ;
If this behaves as the 16bit version does, then the problem is not in timerX, but in what you think it should do...
Best Wishes |
|
|
nurquhar
Joined: 05 Aug 2006 Posts: 149 Location: Redditch, UK
|
|
Posted: Wed Sep 05, 2007 9:55 am |
|
|
Dear Ttelmah
I will certainly try the OR make8 idea. But at the moment I am always testing with timerX being load with 0x64 (100) so 1 + 255 = 0 should not occur. Indeed I can also solve the problem by changing timerX to be an 8bit int.
I was wondering what happens if the interrupt occurs whilst an access to a variable in another bank was taking place. I did try clearing all the bank bits in STATUS at the begnining of the interrupt but this did not seem to help. |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Wed Sep 05, 2007 3:18 pm |
|
|
Both code versions look to me like correct C implementations.
The compiled code however for both versions looks incorrect. The broken version doesn't do any bank switches which could be OK, I don't have the symbol file, but the results you see are wrong.
The 'fixed' version does bank switching but is reading both bytes of the TimerX variable from different banks, this is wrong.
Something is screwing up your compiler. Forward your complete source code to CCS and/or have a look outside the ISR for errors. |
|
|
nurquhar
Joined: 05 Aug 2006 Posts: 149 Location: Redditch, UK
|
|
Posted: Thu Sep 06, 2007 12:59 am |
|
|
Having tried the make8() | make8() I now see what should have been obvious. I was setting up the interrupt with timerX initialy set to zero. Which is wrong because it first decrements the value and thus it rolls over to 0xFFFF. Which screws up the timings I was trying to achive.
I am curious about this bank switching during the interupt, or should I say the lack of it. I can only guess that CCS must be stacking the STATUS reg before/after my interrupt funct and that it only does a bank switch if and when it has varibles not in bank 0 that need to be accessed. |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Thu Sep 06, 2007 5:34 am |
|
|
Quote: | I can only guess that CCS must be stacking the STATUS reg before/after my interrupt funct and that it only does a bank switch if and when it has varibles not in bank 0 that need to be accessed. | This is true. Besides the status register about twenty other registers are saved as well (chip type dependend). |
|
|
Ttelmah Guest
|
|
Posted: Thu Sep 06, 2007 7:04 am |
|
|
nurquhar wrote: | Having tried the make8() | make8() I now see what should have been obvious. I was setting up the interrupt with timerX initialy set to zero. Which is wrong because it first decrements the value and thus it rolls over to 0xFFFF. Which screws up the timings I was trying to achive.
I am curious about this bank switching during the interupt, or should I say the lack of it. I can only guess that CCS must be stacking the STATUS reg before/after my interrupt funct and that it only does a bank switch if and when it has varibles not in bank 0 that need to be accessed. |
Which then gives the 65thousand count timeout I was expecting.
Read up about 'int_global'. What you see/write, as the 'interrupt handler', is only a subroutine called by the 'real' handler (the global routine). This saves _all_ the registers used by C (table pointers, status, etc. etc..), then tests the bits to find what interrupt has occured, and calls your handler. On return, it clears the corresponding interrupt flag, restores all the registers, and finally returns to the interrupt 'source',re-enabling the global interrupt as it does so.
This makes interrupt handling 'easy', but brings with it the cost, that at times more registers are saved, than are needed (if your routine is simple, then a smaller subset can be used). Hence people programming for fast interrupt handling, will go 'DIY' on this, and write their own 'global' handler.
Best Wishes |
|
|
|
|
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
|