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

Erratic behavior. Unexpected reset.

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



Joined: 27 Oct 2003
Posts: 6

View user's profile Send private message

Erratic behavior. Unexpected reset.
PostPosted: Sat Jan 17, 2004 7:14 pm     Reply with quote

Hi,

I ported my program from assembler to CCS and I'm experiencing some problems trying to make it run.
The program is the firmware of a PBX system.

Users of the PBX need to dial a PIN (Personal Identification Number) in order to use the lines.

The program is written as a state machine. The possible states are:

Code:

#define IDLE 1         //Idle state (phone is on-hook, no ring signal)
#define TONE 2         //Internal tone
#define LOGN 3         //Logging in
#define HUWT 4         //Waiting for hang-up
#define PUWT 5         //Waiting for pick-up
#define SSEL 6         //Start of selection
#define CSEL 7         //Completion of selection
#define ANWT 8         //Waiting for answer
#define OUTC 9         //Outgoing call
#define RING 10         //Ringing
#define INCC 11         //Incomming call
#define BUSY 12         //busy tone
#define COMM 13         //Communicating with PC


The main function is:

Code:

void main() {
   #bit tris_RLY = 0x85.0         //relay tris (PORTA<0>)
   #bit tris_HOOK = 0x86.5         //hook tris (PORTB<5>)
   #bit tris_RING = 0x86.6         //ring tris (PORTB<6>)
   #bit tris_PWR = 0x86.7         //power tris (PORTB<7>)
   #byte adcon1 = 0x9F            //A/D control

   int state = IDLE;            //current state of the system

   // initializations
   enable_interrupts(GLOBAL);      // global interrupts enabled
   init_I2C();                  // I2C initialization
   init_PWM();                  // PWM initialization
   init_timer();               // timer initialization
   init_DTMF();               // DTMF initialization
   init_clock();               // clock initialization
   tris_RLY = 0;               // relay pin as output
   tris_HOOK = 1;               // hook pin as input
   tris_RING = 1;               // ring pin as input
   tris_PWR = 1;               // power pin as input
   adcon1 = 0x18;               // PORTA pins as inputs

   #ifdef DEBUG_MAIN
   printf("\n\rQOK");
   #endif

   while(1) {
      if(state == IDLE) state = sIDLE();
      if(state == TONE) state = sTONE();
      if(state == LOGN) state = sLOGN();
      if(state == HUWT) state = sHUWT();
      if(state == PUWT) state = sPUWT();
      if(state == SSEL) state = sSSEL();
      if(state == CSEL) state = sCSEL();
      if(state == ANWT) state = sANWT();
      if(state == OUTC) state = sOUTC();
      if(state == RING) state = sRING();
      if(state == INCC) state = sINCC();
      if(state == BUSY) state = sBUSY();
      if(state == COMM) state = sCOMM();
   }
}


And here are some of the states (only four of them):

Code:

int sIDLE()   {
   #ifdef DEBUG_STATE
   printf("\n\rIDLE");
   #endif

   //state initialization
   relay_on = 0;
   stop_PWM();

   while(1) {
      update_clock();

      if(!on_hook) return TONE;      //if a user picks up the phone, jump to TONE state

      if(!ring_off) return RING;      //if ring signal is detected, jump to RING state

      if(kbhit()) return COMM;      //if a character is received, jump to COMM state
   }
}

int sTONE()   {
   #ifdef DEBUG_STATE
   printf("\n\rTONE");
   #endif

   //state initalizations
   start_timer(1500);         //set the timer to  15 seconds
   start_PWM(190);            //generate a continuous tone

   while(1) {
      update_clock();

      if(on_hook) return IDLE;      //if the user hungs up, jump back to the IDLE state

      if(DTMF_pressed()) {               //if the user presses a DTMF key, jump to LOGN state
         user = (read_DTMF() - 1) << 4;
         return LOGN;
      }

      if(timer_expired()) return BUSY;   //if the timer expires, jump to BUSY state
   }
}

int sLOGN()   {   //Login
   int keys[4];   //keys entered by the user
   int nkeys = 0;   //number of keys actually entered
   int PIN[4];      //user's Personal Identification Number

   #ifdef DEBUG_STATE
   printf("\n\rLOGN");
   #endif

   //state initializations
   start_timer(1000);      //set the timer to 10 seconds
   stop_PWM();            //mute the tone

   while(1) {

      update_clock();

      if(on_hook) return IDLE;         //if the user hungs up, jump back to the IDLE state

      if(timer_expired()) return BUSY;   //if the timer expires, jump to BUSY state

      if(DTMF_pressed()) {            //wait for 4 keys from the user
         keys[nkeys] = read_DTMF();
         nkeys ++;
         if(nkeys == 4) {
            read_ext_EEPROM(user + 12, PIN, 4);   //retrieve the user's PIN from the external EEPROM
            if(keys[0] == PIN[0] && keys[1] == PIN[1] && keys[2] == PIN[2] && keys[3] == PIN[3]) {
               beep(200);            //let the user know the PIN is OK
               return HUWT;         //jump to HUWT
            }
            else return BUSY;         //give busy tone (the PIN is not valid)
         }
      }
   }
}

int sBUSY() {   //busy tone
   short is_on = 1;
   #ifdef DEBUG_STATE
   printf("\n\rBUSY");
   #endif

   //state initializations
   start_timer(50);
   start_PWM(190);

   while(1) {
      update_clock();

      if(on_hook) return IDLE;

      if(timer_expired()) {
         if(is_on) {
            stop_PWM();
            is_on = 0;
         } else {
            start_PWM(190);
            is_on = 1;
         }
         start_timer(50);
      }
   }
}


The program starts in IDLE state: that means nobody is using a phone and there is no ring signal. When a user picks up the phone, the system jumps to TONE state, presenting the user a dial tone so he can dial his PIN. After the PIN has been entered (1 key for user number and 4 keys for PIN) the program verifies the correctness of the keys entered and then jumps either to BUSY tone state or the "waitng for hang-up" state.
The problem arrises during the login state (sLOGN), where erratic bahavior occurs. Depending on the speed with which I dial my PIN, the program may or may not arrive to the next state before a reset occurs.
As you may see, the main function as well as the states functions are really simple, so I don't have a clue on what is causing the erratic behavior.
Below are the rest of the functions called in main and the states involved. Note that among this functions is the timer0 interrupt handler.
I used version 3.150 to compile this code.
I will really apreciate the help from anyone who has the time to look at this code.
Let me know if you need any other info. Thanks in advance !

Code:

External EEPROM interface functions:

void init_I2C() {
   #bit tris_SCL = 0x87.3            //SCL tris (TRISC,3)
   #bit tris_SDA = 0x87.4            //SDA tris (TRISC,4)

   #byte sspcon = 0x14               //SSP control register
   #byte sspadd = 0x93               //SSP baud generator
   #byte sspstat = 0x94            //SSP state

   tris_SCL = 1;                  //SCL pin as input
   tris_SDA = 1;                  //SDA pin as input
   sspcon = 0x28;                  //SSP enabled as master
   sspadd = 0x09;                  //bus speed = 100KHz
   sspstat = 0x00;                  //slew rate control disabled
}

void read_ext_EEPROM(long address, int *data, int size) {
   #bit sspif = 0x0C.3               //SSP interrutp flag
   #bit sen = 0x91.0               //start bit enable
   #bit rsen = 0x91.1               //restart bit enable
   #bit pen = 0x91.2               //stop bit enable
   #bit rcen = 0x91.3               //receive bit enable
   #bit acken = 0x91.4               //ack bit enable
   #bit ackdt = 0x91.5               //ack data bit
   #bit ackstat = 0x91.6            //ack bit state

   #byte sspbuff = 0x13            //SSP send buffer

   int i = 0;                     //index for data reception

   sen = 1;                     //send start bit
   while(sen){}

   sspif = 0;                     //clear interrupt flag
   sspbuff = 0xA0;                  //send control byte
   while(!sspif){}                  //

   while(ackstat){}               //wait for ack from slave

   sspif = 0;                     //clear interrupt flag
   sspbuff = (int)(address >> 8);      //send address high byte
   while(!sspif){}

   while(ackstat){}               //wait for ack from slave

   sspif = 0;                     //clear interrupt flag
   sspbuff = (int)(address & 0xFF);   //send address low byte
   while(!sspif){}

   while(ackstat){}               //wait for ack from slave

   rsen = 1;                     //send restart bit
   while(rsen){}

   sspif = 0;                     //clear interrupt flag
   sspbuff = 0xA1;                  //send control byte
   while(!sspif){}                  //

   while(ackstat){}               //wait for ack from slave

   while(i < size) {
      rcen = 1;                  //enable receive mode
      while(rcen){}               //wait for data to arrive
      *(data + i) = sspbuff;         //save the data

      i ++;                     //increment the index

      if(i < size) ackdt = 0;         //if there are bytes left, send an ack
      else ackdt = 1;               //else send a nack
      acken = 1;
      while(acken){}
   }

   pen = 1;                     //send stop bit
   while(pen){}
}


PWM functions:

void init_PWM() {
   #bit tris_CCP = 0x87.2         //CPP tris (TRISC,2)

   #byte t2con = 0x12            //timer2 control
   #byte ccpr11 = 0x15            //CCP1 register 1

   tris_CCP = 0;               //PWM pin as output
   t2con = 6;                  //set prescaler to audible frequencies
   ccpr11 = 16;               //duty cycle = 50%
}

void start_PWM(int freq) {
   #byte ccp1con = 0x17         //CPP control
   #byte pr2 = 0x92            //PWM frequency

   pr2 = freq;                  //set the frequency
   ccp1con = 0xC;               //turn the module on
}

void stop_PWM() {
   #byte ccp1con = 0x17         //CPP control

   ccp1con = 0x00;               //turn the module off
}


Timer functions:

void init_timer() {
   setup_counters(RTCC_INTERNAL, RTCC_DIV_128);
}

void start_timer(long time) {
   while(timer_value != time) timer_value = time;
      set_rtcc(178);
   enable_interrupts(INT_RTCC);
}

short timer_expired() {
   if(timer_value == 0) return 1;
   else return 0;
}

#INT_RTCC      //timer0 interrupt
void timer0_handler() {
   if(timer_value > 0) {
      timer_value --;
      set_rtcc(178);            //overflow every 1/100s
   } else disable_interrupts(INT_RTCC);
}


DTMF functions:

void init_DTMF() {
   #bit tris_dtmf0 = 0x86.0
   #bit tris_dtmf1 = 0x86.1
   #bit tris_dtmf2 = 0x86.2
   #bit tris_dtmf3 = 0x86.3
   #bit tris_dtmfdet = 0x86.4

   //all DTMF pins as inputs (PORTB<0:4>)
   tris_dtmf0 = 1;
   tris_dtmf1 = 1;
   tris_dtmf2 = 1;
   tris_dtmf3 = 1;
   tris_dtmfdet = 1;
}

short DTMF_pressed() {
   #bit DTMF = 0x06.4         //DTMF signal actual state
   static short prev_DTMF;      //DTMF signal previous state

   //returns 1 on the negative edge
   if(prev_DTMF && !DTMF) {
      prev_DTMF = DTMF;
      return 1;
   }
   else {
      prev_DTMF = DTMF;
      return 0;
   }
}

int read_DTMF() {
   #byte PORTB = 0x06
   return PORTB & 0x0F;
}


Real Time Clock functions:

void init_clock() {
   #byte t1con = 0x10         //timer1 control
   t1con = 0x0F;              //timer1 enabled, ext oscilator, async, prescaler=1, on
}

void update_clock() {
   #bit timer1flag = 0x0C.0   //timer1 flag
   #byte tmr1h = 0x0F         //timer1 high byte

   if(!timer1flag) return;      //return if a second has not passed yet

   #ifdef DEBUG_TIC
   printf("\n\rTIC");
   #endif
   timer1flag = 0;            //clear timer1 interrupt flag
   tmr1h = 0x80;            //overflow every second
   time ++;               //update the time

   // hour of day
   hour_seconds ++;
   if(hour_seconds == 3600) {
      hour_seconds = 0;
      hours ++;
      if(hours == 24) {
         day_of_week ++;
         if(day_of_week == 7) day_of_week = 0;
         period_day ++;
         if(period_day == period_duration) {
            //renew_credits();
            period_day = 0;
         }
      }
      if((hours > 7 && hours < 20 && day_of_week > 0 && day_of_week < 6) || (hours > 7 && hours < 13 && day_of_week == 6))
         low_cost = 0;            // 2 minutes per credit
      else low_cost = 1;      // 4 minutes per credit
   }
}
Haplo



Joined: 06 Sep 2003
Posts: 659
Location: Sydney, Australia

View user's profile Send private message

PostPosted: Sun Jan 18, 2004 12:55 am     Reply with quote

I took a very fast look at your code and the first thing that came to my mind was the watchdog timer. Do you have NOWDT in your fuses settings?
You are not kicking the watchdog anywhere in the code. Maybe the PIC is resetting all the time but you can observe it only during sLOGN state? (If the code resets during IDLE or TONE state it will automatically go back to that state so everything will look 'normal'.)
sbayeta



Joined: 27 Oct 2003
Posts: 6

View user's profile Send private message

PostPosted: Sun Jan 18, 2004 7:20 am     Reply with quote

Thanks for your reply, but no, it's not the wdt. I'm using the configuration word 3D79, which I also used in the assembler version of this program.
The assembler version works great, although it's really hard to maintain and improve.
Any other thoughts ?
Ttelmah
Guest







PostPosted: Sun Jan 18, 2004 10:19 am     Reply with quote

sbayeta wrote:
Thanks for your reply, but no, it's not the wdt. I'm using the configuration word 3D79, which I also used in the assembler version of this program.
The assembler version works great, although it's really hard to maintain and improve.
Any other thoughts ?

You do not show how the code every accesses the code for the states such as sLOGN. The main code will never go to this code, so the implication, is that these other states are probably reached using a process such as one of the interrupts.
If so, then the problem could well tie up with the compilers interrupt protection.
The next comment, is that you are accessing 'TRIS' directly, but there is no mention of #USE FAST_IO in the code posted. Unless this is done, the compiler will itself override TRIS settings, which might cause problems.
Finally, if the other states are accessed through interrupt code, then the state variable itself will need to be global. You have the variable declared in the main, and the functions you show return the new 'state', but there is no mention of how the return value gets transferred to the state variable.

Best Wishes
sbayeta



Joined: 27 Oct 2003
Posts: 6

View user's profile Send private message

PostPosted: Sun Jan 18, 2004 4:25 pm     Reply with quote

Ttelmah wrote:
You do not show how the code every accesses the code for the states such as sLOGN. The main code will never go to this code, so the implication, is that these other states are probably reached using a process such as one of the interrupts.
If so, then the problem could well tie up with the compilers interrupt protection.

I'm not shure I get what you're saying. All the states are only reached from another state. I didn't post all the cade just for brevity's sake (since the error appears before a user can reach the states not shown).
As for the interrupts, the only interrupt enabled is timer0's. The routines involved in enabling, disabling and handling that interrupt are the 'timer' functions I posted near the end of my code. Anyway, I don't know what "compilers interrupt protection" means. I'd preciate if you coul clarify this.

Ttelmah wrote:
The next comment, is that you are accessing 'TRIS' directly, but there is no mention of #USE FAST_IO in the code posted. Unless this is done, the compiler will itself override TRIS settings, which might cause problems.

OK, I didn't know that (I'm new to CCS). I will try using "#USE FAST_IO" an see what happens. Anyhow, if this is the problem, shouldn't it be consistent every time ?

Ttelmah wrote:
Finally, if the other states are accessed through interrupt code, then the state variable itself will need to be global. You have the variable declared in the main, and the functions you show return the new 'state', but there is no mention of how the return value gets transferred to the state variable.

Again here, the only interrupt used is timer0's. I't used for non-blocking delays in the code, so I don't think that may be causing problems. I'll check that out anyway to make shure though.

Thanks a lot for your reply, any other help will be really apreciated.
Thanks again.
sbayeta



Joined: 27 Oct 2003
Posts: 6

View user's profile Send private message

PostPosted: Mon Jan 19, 2004 8:34 am     Reply with quote

Well, I talked to a friend at work, and he told he has a similar problem with a program compiled with CCS.
He's program has also a while(1) block in the main function (without breaks) that is being exited sporadically.
As soon as I get the program I'll post it here.

Thanks in advance for any help.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Jan 19, 2004 12:44 pm     Reply with quote

You're using PCM vs. 3.150. That's a fairly old version. Check
this thread regarding a problem that probably affects your code.
http://www.ccsinfo.com/forum/viewtopic.php?t=4499&highlight=3+150
Also look at the fixes implemented in vs. 3.151, here:
http://www.ccsinfo.com/versions.shtml
I think the best solution would be to upgrade.
sbayeta



Joined: 27 Oct 2003
Posts: 6

View user's profile Send private message

PostPosted: Mon Jan 19, 2004 12:50 pm     Reply with quote

PCM programmer wrote:
You're using PCM vs. 3.150. That's a fairly old version. Check
this thread regarding a problem that probably affects your code.
http://www.ccsinfo.com/forum/viewtopic.php?t=4499&highlight=3+150
Also look at the fixes implemented in vs. 3.151, here:
http://www.ccsinfo.com/versions.shtml
I think the best solution would be to upgrade.


Thanks a lot for that reply. This friend of mine at work is using 3.182 version. I will try that and see what happens.

Thanks again.
Haplo



Joined: 06 Sep 2003
Posts: 659
Location: Sydney, Australia

View user's profile Send private message

PostPosted: Mon Jan 19, 2004 6:01 pm     Reply with quote

I remember now, version 3.150 was probably the worst one in the 3.xxx series! I remember I was working on a project and everything was fine. Then I installed 3.150 on the day it was released and everything stopped working. I checked the .LST file and found out some of the bank select code were wrong or completely missing. That caused the PIC to go on a ride to never never land on a one-way ticket during function calls.
There is a high chance that version 3.182 will solve your 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