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 CCS Technical Support

Issue with <= statement

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



Joined: 08 Feb 2009
Posts: 11

View user's profile Send private message

Issue with <= statement
PostPosted: Wed Dec 22, 2010 11:59 pm     Reply with quote

Well I am trying to create a general timer array using TMR1 with a PIC18F2585. I config'd TMR1 with a 1ms interrupt and inc's a counter. So far so good as I scoped the TMR1 int at 1ms.

I toggled a LED every 500ms and made a cheap PWM routine to use this general timer routine, when I noticed every now and then the LED and PWM would have small timing clitches ( a pulse is missed or very short). I debug using MPLAB 8.60 and seems to have an issue with a <= in my the Check Timer routine.

The idea is to set a done bit once the TMR1 over flow counter reaches the calculated T2 value. I use <= in case my scan exceeds 1ms so I can still catch it as this is a cheap, general timer routine for debouncing, blinking LED's, a cheap PWM for dimming bulbs etc.

It works well if coded as ==. I set a break point once Check Timer thinks the DN=1, but with <=, it "randomly" evaluates as true even though TMR1_OF_Cnt is less than .T2. This occurs before TMR1_OF_Cnt overflows. Note I tried to buffer .T2 and the counter in the code presented to see if that was an issue.

I roll my own, even the header file. I stripped out code so that only relevant , compilable code is present, but it may still be a bit messy.

Code:


 /*****************************************************************************
 Cruise Control
   CCS Compiler ver 4.106
   PIC18F2585
Dec 10-2010
   Project started
   
******************************************************************************/
//#include <PIC18F2585.h> 
#device PIC18F2585
#device *=16 
#device   ICD=TRUE
//#device   HIGH_INTS=TRUE
#ifdef defined (__PCH__)
#fuses EC,NOPROTECT,NOLVP,NOWDT,NOMCLR,NODEBUG
#endif

#ignore_warnings  ALL
#fuses DEBUG
#Define OSC_20MHZ    0x1
#Define SysClk    OSC_20MHZ            //sets the oscillator speed

#if(SysClk==OSC_20MHZ)
#use delay(clock=20000000)
                        // Clk_Mult (for Over flow)=desired ms/Tosc*prescaler**ENSURE less than 16bit (65535)
#Define TMR0_Clk_Mult_ms 7500   // cyc for 2ms with x2 prescale
#Define TMR0_msCnt 65535-TMR0_Clk_Mult_ms+15 //50 to account for some ISR overhead

#Define TMR1_Clk_Mult_ms 5000   // cyc for 1ms with x1 prescale
#Define TMR1_msCnt 65535-TMR1_Clk_Mult_ms+15 //50 to account for some ISR overhead
#endif

//General Pupose timer config
#Define   MAXTIMERS   1
#Define   LED_Tim   0 //GP Timer[3] array

////// TIMER///////
#Define BITS_8   255
#Define BITS_16   65535
#Define BITS_32   4294967296

#Define ClkSize Bits_16
#Define TMRX_Prescale   1

#if(ClkSize==Bits_8)
#Define Tim_Size 255
#endif

#if(ClkSize==Bits_16)
#Define Tim_Size 65535
#endif

#if(ClkSize==Bits_32)
#Define Tim_Size 4294967296
#endif

struct Ports{
   unsigned char   B0:1;
   unsigned char   B1:1;
   unsigned char   B2:1;
   unsigned char   B3:1;
   unsigned char   B4:1;
   unsigned char   B5:1;
   unsigned char   B6:1;
   unsigned char   B7:1;
}PORTA_Bits;

struct Timer{
   INT16 T2;
   unsigned char    DN:1;    //done
   unsigned char   EN:1;   //enabled
   unsigned char   OF:1;   //OverFlow
   unsigned char   TT:1;   //timer timing
   unsigned char   SPARE1:1;
   unsigned char   SPARE2:1;
   unsigned char   SPARE3:1;
   unsigned char   SPARE4:1;
}Timer_Array[MAXTimers];

///// REGISTERS //////Place after struct
#byte PORTA=0XF80
#byte TRISA=0xF92
#byte LATA=0xF89
#byte PORTB=0XF81
#byte TRISB=0XF93
#byte CMCON=0xFB4
#byte PORTA_Bits=0xF80
#byte INTCON=0XFF2
#byte INTCON2=0XFF1
#byte INTCON3=0XFF0
#byte TMR0H=0XFD7
#byte TMR0L=0XFD6
#byte TMR1H=0XFCF
#byte TMR1L=0XFCE
#byte T1CON=0XFCD
#byte ADCON0=0XFC2
#byte ADCON1=0XFC1
#byte ADCON2=0XFC0
#byte PIR3=0XFA4
#byte PIE3=0XFA3
#byte IPR2=0XFA2
#byte PIR2=0XFA1
#byte PIE2=0XFA0
#byte T1CON=0XFCD
#byte T0CON=0XFD5
#byte IPR1=0XF9F
#byte PIR1=0XF9E
#byte PIE1=0XF9D
#byte LATA=0XF89
#byte RCON=0XFD0
#byte BSR=0XFE0

////bits////////
 #bit GIE=INTCON.7
 #bit PEIE=INTCON.6
 #bit INT0IF=INTCON.1
 #bit INTEDG0=INTCON2.6
 #bit INTEDG1=INTCON2.5
 #bit INTEDG2=INTCON2.4
 #bit INT2IP=INTCON3.7
 #bit INT1IP=INTCON3.6
 #bit INT2IE=INTCON3.4
 #bit INT1IE=INTCON3.3
 #bit INT2IF=INTCON3.1
 #bit INT1IF=INTCON3.0
 #bit TMR1IF=PIR1.0
 #bit TMR1IE=PIE1.0
 #bit TMR1IP=IPR1.0
 #bit IPEN=RCON.7
 #bit TMR1ON=T1CON.0
 #bit INT0IE=INTCON.4
 #bit TMR0IF=INTCON.2
 #bit TMR0IE=INTCON.5
 #bit TMR0ON=T0CON.7
 #bit T08BIT=T0CON.6
 #bit TMR0IP=INTCON2.2

#Define      PWM_Pin      PORTA_Bits.B0   //
#Define      LED         PORTA_Bits.B1   //

///////////////////////// Prototypes ///////////////////////////
int16 TimSetup_ms(int16 Desired_ms,struct Timer *Timer_ms);
void CheckTimer(struct Timer *TA);
void TMR1_ISR();
////////////////// Defines /////////////////////////////////////

#define    BYTE int
#define   BOOLEAN short int
#define    FALSE   0

union PICReg{
   unsigned char    Ch[2];
   int16          I;
   }T1,T2,TMR1_msLoad,TMR0_msLoad;

int16 TMR1_OF_Cnt=0,TMR0_OF_Cnt=0;

/////////////// INTERUPTS //////////////////////////
/* High Priority (HP) INTS vector to 0x000008 if IPEN set and Each INT is set a HP
   Low Priority INTS vector to 0x000018 */
void TMR0_ISR();
void TMR1_ISR();
void INT_0_ISR();
//#Define HIGH 1

#DEFINE TMR0_PRIORITY 0 //LOW
#DEFINE TMR1_PRIORITY 1// HIGH

   int save_w;
   #locate save_w=0x80
   int save_status;
   #locate save_status=0x7F
   int bsr_temp;
   #locate save_bsr=0x7E

   int save_temp1;
   #locate save_temp1=0x7D
   int save_temp2;
   #locate save_temp2=0x7C
   int save_temp3;
   #locate save_temp3=0x7B
   int save_temp4;
   #locate save_temp4=0x7A
   
   #byte status = 0xFD8
   #bit zero_flag = status.2
       
#INT_GLOBAL
void isr()  { //VECTOR ADX 0X08
   #asm
   //store current state of processor
  goto High; //0x08 Vector
   nop
   nop
   nop
   nop
   nop
   nop
   nop
  #endasm
   goto Low;   //0x18 Vector (low priority vector when high is enabled)
   #asm
High:  /// HIGH PRIORITY ///
  #endasm
  if(TMR1IE){//TMR1 INT enabled?
     if(TMR1IF)//TMR1 OF?
         TMR1IF=0;
         TMR1_ISR();
         goto Restore_Hi;
  } //end TMR1 check   
 
  if(INT0IE){//INT0 INT enabled?
     if(INT0IF)//INT0?
         INT0IF=0;
         INT_0_ISR();
         goto Restore_Hi;
  } //end TMR1 check   
  goto Restore_Hi;//default if not Hi priority INT detected

Low:  /// LOW PRIORITY ///
   #asm
   MOVWF save_w
   SWAPF status,W
   BCF   status,5
   BCF   status,6
   MOVWF save_status
   movff BSR, save_bsr;
   #endasm

if(TMR0IE){//TMR0 INT enabled?
     if(TMR0IF)//TMR0 OF?
         TMR0IF=0;
         TMR0_ISR();
   } //end TMR1 check
      
Restore_Low:
   #asm
   movff save_bsr,BSR
   SWAPF save_status,W
   MOVWF status
   SWAPF save_w,F
   SWAPF save_w,W
   #endasm

Restore_Hi:
   #asm
   nop
   #endasm
}
/// HIGH INTS ///
void INT_0_ISR(){ //deafualts as high priority
   TMR0_OF_Cnt++; //test
}//end TMR1 ISR

void TMR1_ISR(){ //set as high priority
   TMR1H=TMR1_msLoad.ch[1]; //1ms INT
   TMR1L=TMR1_msLoad.ch[0];
   TMR1_OF_Cnt++;
//   Test_2^=1;
}//end TMR1 ISR

/// LOW INTS ///   
void TMR0_ISR(){ //set as low priority
   TMR0H=TMR0_msLoad.ch[1]; //1ms INT
   TMR0L=TMR0_msLoad.ch[0];;
   TMR0_OF_Cnt++;
}//end TMR0 ISR
/******************************************************************************

   MAIN
******************************************************************************/
void main(void){
   int16 Counter=0;
   
   PORTA=0x00;
   TRISA=0x00;
   PORTB=0x00;
   TRISB=0xFF;
   TMR1_msLoad.I=TMR1_msCnt;
   TMR0_msLoad.I=TMR0_msCnt;

   T0CON=0b00000000;
   TMR0ON=1;    //TURN ON TMR0
   T08BIT=0;   // 0 is 16bit mode for TMRO (1 is 16 bit read/write TMR1 & TMR3)
   T1CON=0b10000000; //ENABLE 16 BIT MODE TMR1, NO PRESCALE
   TMR1ON=1;   //TURN ON TMR1
         
   PIR1=0b00000000;
      
   TMR0IE=1;    //enable TMR0 INT
   TMR1IE=1;   //enable TMR1 INT
   INT0IE=0;   //ENABLE INT0
   TMR0IP=TMR0_PRIORITY;   
   TMR1IP=TMR1_PRIORITY;   
   IPEN=1;      // high priority ints enabled

   IPEN=1;   //ENABLE HIGH PRIORITY INTS
   PEIE=1;   //ENABLE ALL UNMASKED INTS
   GIE=1;//ENABLE GLOBAL INTS
   
   ADCON0=0x00;
   ADCON1=0x0F; //digital I/O
   
   while(1){
   
   Timer_Array[LED_Tim].EN=1;
   if(Timer_Array[LED_Tim].DN){
      if(!LED)
         LED=1;
      else
         LED=0;
   }
   if(!Timer_Array[LED_Tim].TT && Timer_Array[LED_Tim].EN)
      TimSetup_ms(500,&Timer_Array[LED_Tim]);
      
   CheckTimer(&Timer_Array);
   
   }// end while loop
}// end Main   
//////////////////////////////////////////////
int16 TimSetup_ms(int16 Desired_ms,struct Timer *Timer_ms){
   int16 TempA;
   TempA=Bits_16-TMR1_OF_Cnt;
   
   if(Desired_ms>TempA){ //OF will occur
      Timer_ms->T2=Desired_ms-TempA-1;// 1 to account for zero on OF
      Timer_ms->OF=1;
   }
   else{//no OF
      Timer_ms->T2=Desired_ms+TMR1_OF_Cnt;
   }
   Timer_ms->DN=0; //ensire DN cleared
   Timer_ms->TT=1;
//   Timer_ms->EN=1;
}   
//////////////////////////////////
//   CheckTimer
//   Timer array passed where if enabled
//
// DN set when timer times out
// Expect test (done elsewhere) to clear EN & DV
////////////////////////////////
void CheckTimer(struct Timer *TA){
   int Count;
   int16 Temp_Cnt_OF,Temp_T2;// buffer counter

   for(Count=0;Count<MAXTIMERS;Count++){
      Temp_Cnt_OF=TMR1_OF_Cnt;///TEST
      Temp_T2=TA[Count].T2;
      if(TA[Count].OF){
         if(TMR1_OF_Cnt<=TA[Count].T2)//wait until OFCounter OF's
            TA[Count].OF=0;
      }
      if(   TA[Count].DN && !TA[Count].TT) //.TT=0 from previous scan in CheckTimer
         TA[Count].DN=0; //clear .DN after one DN=1 scan in main
   
      if( Temp_T2<=Temp_Cnt_OF && !TA[Count].OF && !TA[Count].DN && TA[Count].EN && TA[Count].TT){
         TA[Count].DN=1; //allow main logic one scan to test .DN
         TA[Count].TT=0; //timer done, allows for next setup
         if(TMR1_OF_Cnt!=TA[Count].T2)//TEST
            Temp_T2=1;
      }//end if
      if(!TA[Count].EN){ //clear bits if not enabled
         TA[Count].DN=0;
         TA[Count].TT=0;
      }//end if
   }//end for
}//end fn
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Thu Dec 23, 2010 12:22 am     Reply with quote

There may be other issues with your code, but one is this:

Your updating 16-Bit variables in the timer ISR and reading them in the main loop. Accesses to 16 Bit variables are splitted
into multiple machine instructions on a 8-Bit processor, they can't be expected to be consistent across ISR calls.
For a save variable access, you have to disable interrupts temporarily.
RayJones



Joined: 20 Aug 2008
Posts: 30
Location: Melbourne, Australia

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

PostPosted: Sun Dec 26, 2010 2:05 pm     Reply with quote

I think more importantly you should only be reading the timer value once, and work from the stored value in your timer test routine.

The way I am reading the code in the source as published is you are reading the timer counter several times to make logical decisions upon its value.
The problem is the counter is continuing to count irrespective of disabling interrupts so this value is very volatile.

Read it once at the start, then only work with the "shadow" copy and see how you go...
5440



Joined: 08 Feb 2009
Posts: 11

View user's profile Send private message

PostPosted: Sun Dec 26, 2010 8:03 pm     Reply with quote

RayJones wrote:
I think more importantly you should only be reading the timer value once, and work from the stored value in your timer test routine.

The way I am reading the code in the source as published is you are reading the timer counter several times to make logical decisions upon its value.
The problem is the counter is continuing to count irrespective of disabling interrupts so this value is very volatile.

Read it once at the start, then only work with the "shadow" copy and see how you go...


I changed code to read it once, which is a good point, but still same issues with it randomly thinking the <= statement is true when the value is less than.
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Mon Dec 27, 2010 2:39 am     Reply with quote

Only caring for the so called "more important" issue means getting occasional code failure for sure. So you better think about the mentioned 16 bit variable consistency problem.
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