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

don't want the WATCHDOG to reset, but it does!
Goto page Previous  1, 2, 3  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Christophe



Joined: 10 May 2005
Posts: 323
Location: Belgium

View user's profile Send private message

PostPosted: Tue Jun 28, 2005 1:06 am     Reply with quote

Guys... my code/pic does not take the PIC into sleep.. The watchdog timer here just resets the PIC because it's timer has overflown. It shouldn't..
Christophe



Joined: 10 May 2005
Posts: 323
Location: Belgium

View user's profile Send private message

PostPosted: Tue Jun 28, 2005 1:47 am     Reply with quote

ckielstra wrote:
Just some thoughts:
1) You are restarting the watchdog after Meet_Vbat() and directly again before BUZZER(), so the second iteration has a total time of these two functions before restarting the watchdog again. How much time do the functions Meet_Vbat and BUZZER take together?

2) The CCS define WDT_2304MS gives the impression of being very accurate, but on most PIC devices the watchdog is specified with approximately a 50% margin. You didn't mention your processor type, but for example on the PIC16F688 the watchdog is typical 17ms, with a minimum of 10ms and a maximum of 30ms. Suppose your chip has the minimal value, then the watchdog doesn't trigger after 2304ms, but after 1280ms. Have you accounted for this?


Here they are:

/***********************Meten Batterijspanning*******************************//
//Vbat = 250/150*waarde*3/255
//3,9V = 197 decimaal gemeten
//3,6V = 182 decimaal gemeten
Meet_Vbat(float *f)
{
int8 waarde;

setup_adc_ports(AN0_AN1_AN3);
setup_adc(ADC_CLOCK_DIV_32);
set_adc_channel( 0 );
delay_us(20);
waarde = read_adc();
*f = waarde * (250.0 / 150.0) * (3.0 / 255.0);
setup_adc(ADC_OFF);
setup_adc_ports(NO_ANALOGS);
}


//********************************** BUZZER **********************************//
void BUZZER()
{
int8 i;
for (i = 0 ; i < 170 ; i++ )
{
output_high(BUZZ);
delay_us(200);
output_low(BUZZ);
delay_us(300);
}
}
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Jun 28, 2005 9:49 am     Reply with quote

This routine is the likely the problem. It doesn't have any restart_wdt()
statements in it, and I'll bet that you don't have a restart_wdt parameter
in your #use delay() statement.
Code:
void BUZZER()
{
int8 i;
for (i = 0 ; i < 170 ; i++ )
{
output_high(BUZZ);
delay_us(200);
output_low(BUZZ);
delay_us(300);
}
}


That's why I always ask people to post all those statements.
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Tue Jun 28, 2005 9:53 am     Reply with quote

The total time for both the functions Meet_Vbat and BUZZER is about 85ms, way less than the watchdog time-out, so this isn't the cause of your problems.

Christophe wrote:
Guys... my code/pic does not take the PIC into sleep.. The watchdog timer here just resets the PIC because it's timer has overflown. It shouldn't..
We have looked in the code you posted and so far nothing found. What makes you so sure that the problem is in the part of the code you posted? Maybe the battery check succeeds and the problem is somewhere else in your code?
Ttelmah
Guest







PostPosted: Wed Jun 29, 2005 2:49 am     Reply with quote

Christophe wrote:
Guys... my code/pic does not take the PIC into sleep.. The watchdog timer here just resets the PIC because it's timer has overflown. It shouldn't..

You are setting the watchdog to the units prescaler in the fuses statement shown. The watchdog timeout in this case will be just 18mSec (default), and may be as short as 7mSec. 85mSec in the buzzer routine, _will_ give a watchdog timeout.
You need to use a larger precaler on the watchdog to get the longer timeout period...

Best Wishes
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Wed Jun 29, 2005 4:06 am     Reply with quote

Ttelmah wrote:
Christophe wrote:
Guys... my code/pic does not take the PIC into sleep.. The watchdog timer here just resets the PIC because it's timer has overflown. It shouldn't..

You are setting the watchdog to the units prescaler in the fuses statement shown. The watchdog timeout in this case will be just 18mSec (default), and may be as short as 7mSec. 85mSec in the buzzer routine, _will_ give a watchdog timeout.
You need to use a larger precaler on the watchdog to get the longer timeout period...

Ttelmah is right for a PIC18 processor, but the current configuration is correct for a PIC16 processor.
PIC16: Watchdog on/off by #fuses setting, timeout is set with the setup_wdt function.
PIC18: Watchdog on/off by #fuses seting or by calling setup_wdt(). Timeout is defined by #fuses setting.

One of the big questions remaining: Which processor is Christophe using?....

I totally agree with PCM Programmer: Please post a complete program! Would you have done so we would have known the processor type and all the other small details from the start.
Christophe



Joined: 10 May 2005
Posts: 323
Location: Belgium

View user's profile Send private message

PostPosted: Wed Jun 29, 2005 8:07 am     Reply with quote

OK I'm sorry!

uc: PIC16LF877A

Code:
#include <16F877A.h>
#device adc=8
#fuses XT, NOPUT, NOWDT, NOPROTECT, NOLVP, NOCPD, NOWRT, NOBROWNOUT
#use delay(clock=4000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8, ERRORS)
treitmey



Joined: 23 Jan 2004
Posts: 1094
Location: Appleton,WI USA

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

PostPosted: Wed Jun 29, 2005 8:12 am     Reply with quote

Please post a complete program!
Not just the first 5 lines.

We can fix it very quickly then.
Christophe



Joined: 10 May 2005
Posts: 323
Location: Belgium

View user's profile Send private message

PostPosted: Wed Jun 29, 2005 8:23 am     Reply with quote

Code:
#include <16F877A.h>
#device adc=8
#fuses XT, NOPUT, WDT, NOPROTECT, NOLVP, NOCPD, NOWRT, NOBROWNOUT
#use delay(clock=4000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8, ERRORS)

Code:
#include "C:\Documents and Settings\christophe.seyen\My Documents\Hardware\PIC\NEXTSCOPE\NS.h"
#include <string.h>
#include <functies.h>

//************* Algemene variabelen voor heel het programma ******************//
float Vbat,Vadap;
int16 teller = 0;
int1 Zoemer_aan, Laden_bezig, Adapter_in, sleep_mode, E3_OFF, E3_SLEEP;

//************************** Interrupt routines ******************************//

//***************************** RDA interrupt ********************************//
//Als een karakter wordt ontvangen door de UART
#int_RDA
RDA_isr()
{
   if (getc() == COMMANDO_BYTE)             // We krijgen een commando
   {
      char data[47];
      long timeout = 0;
      int8 datalengte, i;

      for (i = 0 ; i < 5 ; i++)  // 5 karakters inlezen van de PC
      {                    //
         while (!kbhit() && (++timeout<50000))
            delay_us(5);

            if (kbhit())
               data [i] = getc();

            else
               break;
      }

    datalengte = data [4];
    timeout = 0;

    if ( datalengte > 0 )         // data bufferen
    {
         for (i = 5 ; i < (datalengte+5) ; i++)
         {
            while (!kbhit() && (++timeout<50000))
               delay_us(5);

            if (kbhit())
               data [i] = getc();

            else
               break;
         }
    }

// Alle DATA is binnen gelezen
// Commando gaan toetsen:
   switch(Check_commando(data))
   {
   case VBAT_METEN:
      Meet_Vbat(&Vbat);
      Send_Vbat(Vbat);
      break;

   case VADAP_METEN:
      Meet_Vadap(&Vadap);
      Send_Vadap(Vadap);
      break;

   case ADAPTER_STATUS_VRAGEN:
      if (!input(POWER_GOOD))
         printf("%c%S%c",COMMANDO_BYTE, ADAPTER_IN_COMMANDO,0);
      else
         printf("%c%S%c",COMMANDO_BYTE, ADAPTER_UIT_COMMANDO,0);
      break;

   case LAAD_STATUS_VRAGEN:
      if (!input(CHARGE_ON))
         printf("%c%S%c",COMMANDO_BYTE, START_LADEN_COMMANDO,0);
      else
         printf("%c%S%c",COMMANDO_BYTE, EINDE_LADEN_COMMANDO,0);

   case SCHRIJF_NAAR_LEESREGEL:
      setup_spi(SPI_MASTER|SPI_L_TO_H|SPI_XMIT_L_TO_H|SPI_CLK_DIV_4);
      for (i = 5 ; i < datalengte+5 ; i++)
      {
         spi_write(data[i]);
      }
      output_high(BR_STROBE);       // STROBE PULS
      output_low(BR_STROBE);
      setup_spi(FALSE);
      break;

   case CLEAR_DISPLAY:
      BR_CLEAR(40);
      break;

   case ENABLE_200V:
      BR_WAKE();
      break;

   case DISABLE_200V:
      BR_SLAAP();
      break;

   case GA_IN_SLEEP:
      E3_SLEEP = TRUE;
      break;

   default:
      break;
 }

}    //if c == COM
   else{}                      // iets anders dan commando_byte binnengekregen?

}//RDA ISR

//************************** Timer0 interrupt ********************************//
//Timer wordt gestart als de Batterijspanning beneden een kritisch niveau zakt
#int_RTCC
RTCC_isr()
{
   teller++;
   if (teller == BATTERIJ_TIJD)         // NA 1 minuut: teller=920*255*256*1us
   {
      Meet_Vbat(&Vbat);       // Vbat meten
      if (!E3_SLEEP)        // Stuur de batterijspanning door naar E3 als deze
      {                     // niet in sleep staat
         if (Vbat < 3.60)
            Send_Vbat(Vbat);
      }
   teller = 0;
   }
}// TIMER0

//************************** EXTERNAL interrupt ******************************//
//Interrupt als de AAN/UIT schakelaar wordt bewogen
#INT_EXT
void ext_isr()
{
   int8 i;

   if (input(AAN_UIT))
      E3_SLEEP = FALSE;

   else
      E3_SLEEP = TRUE;

   if (E3_SLEEP)
   {
      printf("%c%S%c",COMMANDO_BYTE, SLEEP_COMMANDO,0);
      ext_int_edge(L_TO_H);
   }

   else
   {
      //setup_uart(TRUE);
      printf("%c%S%c",COMMANDO_BYTE, WAKE_COMMANDO,0);
      ext_int_edge(H_TO_L);
   }

   for (i = 0; i < 30; i++)         // Debounce
   {
      delay_us(999);
   }
}

//************************** RB_CHANGE interrupt *****************************//
//Interrupt als de AAN/UIT schakelaar wordt bewogen
#int_rb
void rb_change_isr()
{
   static int8 poortwaarde;
   poortwaarde = input_b(); // Poort B lezen om interrupt vlag te clearen
   putc('Z');
}

//*********************************** Main ***********************************//
//*********************************** Main ***********************************//
void main()
{

//**************************** Variablelen declareren ************************//
   int8 i,temp;
   int16 key;
   int1 Pressed, Alles_los, signaal_gegeven = FALSE;
   char buffer[9];
   Zoemer_aan = TRUE;
   setup_wdt(2304_MS);
//******* Batterijspanning controleren; indien te laag: niet opstarten *******//
   do
   {
      //restart_wdt();
      Meet_Vbat(&Vbat);
      putc(signaal_gegeven);

      if ((Vbat < 3.5) && (signaal_gegeven == FALSE))
      {
         //restart_wdt();
         signaal_gegeven = TRUE;
      }
   }
   while (Vbat < 3.5);


//************** Status van de Aan/uit switch opvragen ***********************//
   if (input(AAN_UIT))
   {
      E3_SLEEP = FALSE;
      ext_int_edge(H_TO_L);
   }

   else
   {
      E3_SLEEP = TRUE;
      ext_int_edge(L_TO_H);
   }

//*************************** Status van het laden ***************************//
   if (!input(CHARGE_ON))
      Laden_bezig = TRUE;
   else
      Laden_bezig = FALSE;

//*************************** Status van de adapter **************************//
   if (!input(POWER_GOOD))
      Adapter_in = TRUE;
   else
      Adapter_in = FALSE;

//***************************** Initialisaties *******************************//
   set_tris_b(0x11);                // B0 en B4 zijn inputs

   setup_adc_ports(NO_ANALOGS);     // ADC UIT
   setup_adc(ADC_OFF);

   SETUP_TIMER_1(T1_DISABLED);      // T1 uit

   SETUP_TIMER_2(T2_DISABLED,0,1);  // T2 uit

   setup_psp(PSP_DISABLED);         // PSP UIT

   setup_comparator(NC_NC_NC_NC);   // COMPARATOR UIT
   setup_vref(FALSE);

   output_High(BR_SLEEP);        // 200V UIT
   output_high(E3_uit);          // E3-Lijn op hoog plaatsen
   output_low(BUZZ);             // Buzz laag

   setup_timer_0( RTCC_INTERNAL | RTCC_DIV_256 ); // Start de Timer0

   enable_interrupts(INT_RB);    // Poort B interrupt
   enable_interrupts(INT_RTCC);  // TIMER0 interrupt
   enable_interrupts(INT_RDA);   // RDA interrupt enable
   enable_interrupts(INT_EXT);   // EXT interrupt enable
   enable_interrupts(GLOBAL);    // GLOBAL interrupt enable

//*********************************** LOOP ***********************************//

   while (TRUE)
   {
//*************************** BATTERY MANAGEMENT *****************************//
//Als power ok EN laden is niet bezig of POWER_GOOD is LAAG en CHARGE_ON is HOOG
//Controleer dan als Vbat groter is dan 4.1V. Indien JA, zet LTC4060 in shutdown,
//indien NEE: laadt de batterijen op.
//Timer0 loopt continu; elke 10 seconden wordt de batterijspanning gemeten; als
//deze lager dan 3.60V komt, wordt deze doorgestuurd naar de E3

         if (!input(POWER_GOOD) && input(CHARGE_ON))
         {
            Meet_Vbat(&Vbat);

            If (Vbat > GRENSSPANNING)
            {
               output_low(ENABLE_CHARGING);  // LADEN DISABLE
            }

            else
               output_high(ENABLE_CHARGING);
         }

/*         if (sleep_mode)
         {

            setup_adc_ports(NO_ANALOGS);   // ADC UIT
            setup_adc(ADC_OFF);

            SETUP_TIMER_1(T1_DISABLED);// T1 uit

            SETUP_TIMER_2(T2_DISABLED,0,1);   // T2 uit

            setup_uart(FALSE);            // UART uit

            setup_psp(PSP_DISABLED);      // PSP UIT

            setup_spi(FALSE);

            setup_comparator(NC_NC_NC_NC);// COMPARATOR UIT
            setup_vref(FALSE);

            input(PIN_A0);
            input(PIN_A1);
            input(PIN_A2);
            input(PIN_A3);
            output_high(PIN_A4);
            input(PIN_A5);

            input(PIN_E1);
            output_low(PIN_E2);

            output_high(PIN_B1);
            output_high(PIN_B2);
            output_high(PIN_B3);
            output_high(PIN_B4);
            output_high(PIN_B5);
            output_high(PIN_B6);
            output_high(PIN_B7);
            input(AAN_UIT);

            output_high(PIN_C0);
            output_high(PIN_C1);
            output_high(PIN_C2); //BR_SLEEP
            output_low(PIN_C3); //CLK
            output_high(PIN_C4); //STROBE
            output_low(PIN_C5); //DATA

            //output_C(0b11100000);
            output_D(255);
            //output_E(255);
            //restart_wdt();

            sleep();
            delay_cycles(1);
         }
 */
//*************************** ADAPTER CONTROL ********************************//
// Geeft commando/detecteert wanneer de adapter is ingestoken en en wanneer deze
// wordt uitgetrokken.  Als de NS in sleep_mode staat, wordt wel gedetecteerd
// maar niet verzonden.

         if (!input(POWER_GOOD) && !Adapter_in)
            {
            Adapter_in = TRUE;
            if (!E3_SLEEP)
               printf("%c%S%c",COMMANDO_BYTE, ADAPTER_IN_COMMANDO,0);
            }

         if (input(POWER_GOOD) && Adapter_in)
            {
            Adapter_in = FALSE;
            if (!E3_SLEEP)
               printf("%c%S%c",COMMANDO_BYTE, ADAPTER_UIT_COMMANDO,0);
            }

//*************************** OPLADEN CONTROL ********************************//
// Geeft commando/detecteert wanneer de batterijen beginnen te laden en wanneer ze
// volledig opgeladen zijn. Als de NS in sleep_mode staat, wordt wel gedetecteerd
// maar niet verzonden.

         if (!input(CHARGE_ON) && !laden_bezig)
            {
            laden_bezig = TRUE;
            if ((!E3_SLEEP) && adapter_in)
               printf("%c%S%c",COMMANDO_BYTE, START_LADEN_COMMANDO,0);
            }

         if (input(CHARGE_ON) && laden_bezig)
            {
            laden_bezig = FALSE;
            if ((!E3_SLEEP) && adapter_in)
               printf("%c%S%c",COMMANDO_BYTE, EINDE_LADEN_COMMANDO,0);
            }

//***************************** KEYBOARD SCAN ********************************//
// 1 = niets ingedrukt, 0 = ingedrukt
// Er wordt enkel gescand als het E3 device niet in sleep mode staat

         Alles_los = TRUE;
         Pressed = FALSE;
         //E3_SLEEP = TRUE;

         if (!E3_SLEEP)
         {
         // RIJ 1
         Output_low(R1);
         temp = input_d();       // Lees de waarde van de poort
         Output_float(R1);
         if ((buffer[0] & temp) != buffer[0])   // er is gedrukt
            Pressed = TRUE;
         buffer[0] = buffer [0] & temp;   // Onthoud dat er ingedrukt is
         if (temp != 255)
            Alles_los = FALSE;

          // RIJ 2
         Output_low(R2);
         temp = input_d();
         Output_float(R2);
         if ((buffer[1] & temp) != buffer[1])
            Pressed = TRUE;
         buffer[1] = buffer [1] & temp;
         if (temp != 255)
            Alles_los = FALSE;

         // RIJ 3
         Output_low(R3);
         temp = input_d();
         Output_float(R3);
         if ((buffer[2] & temp) != buffer[2])
            Pressed = TRUE;
         buffer[2] = buffer [2] & temp;
         if (temp != 255)
            Alles_los = FALSE;

         // RIJ 4
         Output_low(R4);
         temp = input_d();
         Output_float(R4);
         if ((buffer[3] & temp) != buffer[3])
            Pressed = TRUE;
         buffer[3] = buffer [3] & temp;
         if (temp != 255)
            Alles_los = FALSE;

         // RIJ 5
         Output_low(R5);
         temp = input_d();
         Output_float(R5);
         if ((buffer[4] & temp) != buffer[4])
            Pressed = TRUE;
         buffer[4] = buffer [4] & temp;
         if (temp != 255)
            Alles_los = FALSE;

         // RIJ 6
         Output_low(R6);
         temp = input_d();
         Output_float(R6);
         if ((buffer[5] & temp) != buffer[5])
            Pressed = TRUE;
         buffer[5] = buffer [5] & temp;
         if (temp != 255)
            Alles_los = FALSE;

         // RIJ 7
         Output_low(R7);
         temp = input_d();
         Output_float(R7);
         if ((buffer[6] & temp) != buffer[6])
            Pressed = TRUE;
         buffer[6] = buffer [6] & temp;
         if (temp != 255)
            Alles_los = FALSE;

         // RIJ 8
         Output_low(R8);
         temp = input_d();
         Output_float(R8);
         if ((buffer[7] & temp) != buffer[7])
            Pressed = TRUE;
         buffer[7] = buffer [7] & temp;
         if (temp != 255)
            Alles_los = FALSE;

         // RIJ 9
         Output_low(R9);
         temp = input_d();
         Output_float(R9);
         if ((buffer[8] & temp) != buffer[8])
            Pressed = TRUE;
         buffer[8] = buffer [8] & temp;
         if (temp != 255)
             Alles_los = FALSE;

         delay_ms(30);  //debounce

         if (Pressed)
         {
            if (Zoemer_aan)                  // Buzz
            {
               BUZZER();
            }// Zoemer aan

            Printf("%c%S%c",COMMANDO_BYTE,DRUK_COMMANDO,0);
         }// Pressed

         // Er is een toetsencombinatie ingedrukt:
         if ((Alles_los) && (

              (buffer[0] != 0xFF) ||
               (buffer[1] != 0xFF) ||
               (buffer[2] != 0xFF) ||
               (buffer[3] != 0xFF) ||
               (buffer[4] != 0xFF) ||
               (buffer[5] != 0xFF) ||
               (buffer[6] != 0xFF) ||
               (buffer[7] != 0xFF) ||
               (buffer[8] != 0xFF)
          )
         )
         {

            key = GetKeyToSend(buffer);      // Decodeer toetsencombinatie

            Printf("%c%S%c%c%c",COMMANDO_BYTE,TOETS_COMMANDO,sizeof(key),make8(key,0),make8(key,1));

            for ( i = 0 ; i < 9 ; i++)
               {
               buffer[i] = 0xFF;
               }
            } // if losgelaten

         }//if niet in slaap
   } //while
} //main
Christophe



Joined: 10 May 2005
Posts: 323
Location: Belgium

View user's profile Send private message

PostPosted: Wed Jun 29, 2005 8:24 am     Reply with quote

posting.php ignore pls
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Jun 29, 2005 3:09 pm     Reply with quote

Make the changes shown in bold below. See if that fixes your problem.

#use delay(clock=4000000, restart_wdt)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, restart_wdt, ERRORS)
neil



Joined: 08 Sep 2003
Posts: 128

View user's profile Send private message

RDA_ISR
PostPosted: Thu Oct 20, 2005 4:51 am     Reply with quote

There also appears to be rather too much code in the Receive ISR. They need to be kept short!!

I always buffer the incoming data inside the ISR and flag that data has arrived (usually by the fact that the incoming buffer pointer is not equal to the outgoing pointer) and 'use' the buffer contents when possible from the main code. I do the command decoding here, rather than inside the ISR. If you get another interrupt (eg. timer1) while in the receive interrupt, the timer1 interrupt will never be serviced as interrupts are disabled for the duration of a service.
Here is an example of the length of my RDA_ISR:
Code:
#int_RDA
RS232_RX() {
   if(FERR) LED1=ON;  // Framing Error - LED1 ON.
   RX_buff[in_ptr] = RCREG; // Move receive register to buffer.   in_ptr++;   // Increment pointer
   in_ptr &= 7;  // Roll pointer around when it reaches end
   if(RX_free-- < 3) RTS=DENY;   // If there are less than 3 bytes available in buffer, inhibit data reception!
}


In this code I am using handshaking, hence the last line. This can be omitted. The buffer is 8 bytes long, hence using in_ptr&=7; you can have any length and use "in_ptr % BUFF_SIZE-1;" but using '&' for binary sized lengths is mode code efficient.

I once wrote a very long ISR and this caused the processor to continually reset. It was Ttelmah & Mark which helped me out with it about 2 years ago.

Not sure if this will be of any help, and I realise the last post in this thread was back in June. I found this thread when I was looking for some good wdt kicking practise. can anyone help on that? I basically know when to kick the watchdog, eg in running loops, but when is a *bad* time to kick it? I know if I put too many kick commands in, it will never do its job when it needs to. I am wary of just sprinkling resets everywhere!

Neil.
newguy



Joined: 24 Jun 2004
Posts: 1903

View user's profile Send private message

Re: RDA_ISR
PostPosted: Thu Oct 20, 2005 8:10 am     Reply with quote

neil wrote:
I found this thread when I was looking for some good wdt kicking practise. can anyone help on that? I basically know when to kick the watchdog, eg in running loops, but when is a *bad* time to kick it? I know if I put too many kick commands in, it will never do its job when it needs to. I am wary of just sprinkling resets everywhere!


In my experience, there is no bad time to "pet" the watchdog. My main loop always looks like this:

Code:
while (TRUE) {
   restart_wdt();
   if (data_received) {
      data_received = FALSE;
      analyze_data();
   }
   etc.
}


If there is a particular function that takes a lot of time to execute, for instance writing to the PIC's internal data EEPROM, then I will insert extra restart_wdt()'s just to be sure.

Restart the watchdog as often as you wish - if your program somehow goes off into "lala" land, trust me, it WON'T be doing what it's supposed to, and it won't be petting the watchdog. The watchdog will bring it back. For this reason, I prefer to set the watchdog to timeout about every 18 ms or so, as opposed to the longer times that are available (i.e. 2.3 seconds or more). That way I know that if something goes wrong, the reset will occur very quickly.
Ttelmah
Guest







PostPosted: Thu Oct 20, 2005 9:56 am     Reply with quote

It depends what you want the watchdog to do.
For certain types of application, writing a good watchdog handler can be a vital part of ensuring recovery if the code manages to jump somewhere it shouldn't. If there are too many 'restart_wdt' statements, the possibility exists that such runaway code can still reach the restart, and the gain from using a watchdog is degraded.
If you want to really have a 'safe' watchdog, then you generate a seperate function to restart the watchdog, and put in front of it, a 'trap' function, that will prevent a program that is running out of control reaching this. Then at the points that do call this function, test for a status flag at the call, and only go to the restart if this is in a state it'll only reach if the code is 'working'.
So as a cort of 'psuedo' example, have the watchdog reset like this:
Code:

int1 is_good_flag;
//at the 'calling' point, have:

if (is_good_flag) trapped_restart();
is_good_flag=false;

//Then use an org statement, to locate the 'blocker', and the trap
#org 0x1F00,0x1FFF
void trap(void) {
   delay_ms(250);
}

#org 0x1F00
void trapped_restart(void) {
   restart_wdt();
}


Then have the code that sets the 'is_good' flag, dependant on the chip having succesfully done the tasks it is meant to be doing.
The key here is that if the code runs 'wild', and happens to run through the memory and reach the area where the restart is located, it'll hit the long delay first, and the watchdog will timeout. If it reaches the branch to the watchdog, it'll only get to the actual routine, if the status 'is_good' gets set. Even if this is true the first time, since the flag is cleared on exit, and unless the code is doing what it is meant to be doing, the flag will be clear on the next pass.
You can use the watchdog to recover from various types of fault. The simple 'pepper restarts everywhere' approach, will still help for brownout recovery, and code actually hanging. However if you want to handle code taking an unexpected route, more careful design is needed. Designing a good watchdog handler is quite hard, and an analysis of the failure modes and recoveries, is a requirement for some types of mission critical software. However the same types of software also require a similar analysis of the chip hardware, and this is only available for a couple of the PICs...

Best Wishes
neil



Joined: 08 Sep 2003
Posts: 128

View user's profile Send private message

Thanks!
PostPosted: Fri Oct 21, 2005 7:59 am     Reply with quote

Thanks for the replies. Ttelmah, this is exactly the kind of answer I was after, although I will have to read through a few times and digest that one!!
These are the very reasons I asked when is the 'best' time to kick (pet) the watchdog. I have a good example in my old university embedded systems notes, but they're in my loft in boxes!

For the time being, I've just put one kick command at the top of my main loop which is all flag driven, so things should never get caught up in long delays. It appears to work.

Another question now, I am doing some messy button polling in my timer interrupt triggered loop. I need to debounce the buttons, but I don't want to get tied up in an andless while() or sit in a debounce delay, wasting CPU time. The only successful ones I have written before do it this way!

This is something I've coded before, got working and is in use, but the code is ugly and not in the slightest bit re-usable! Do you have any elegant solutions?!

Neil.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page Previous  1, 2, 3  Next
Page 2 of 3

 
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