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 support@ccsinfo.com

Why does my test for long==0 in timer interrupt not work ?

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



Joined: 05 Aug 2006
Posts: 149
Location: Redditch, UK

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

Why does my test for long==0 in timer interrupt not work ?
PostPosted: Wed Sep 05, 2007 9:16 am     Reply with quote

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







PostPosted: Wed Sep 05, 2007 9:43 am     Reply with quote

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

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

PostPosted: Wed Sep 05, 2007 9:55 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Sep 05, 2007 3:18 pm     Reply with quote

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

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

PostPosted: Thu Sep 06, 2007 12:59 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Sep 06, 2007 5:34 am     Reply with quote

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







PostPosted: Thu Sep 06, 2007 7:04 am     Reply with quote

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. Smile
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
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