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

WDT - Watchdog Timer

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



Joined: 13 Aug 2010
Posts: 26
Location: RJ/Brazil

View user's profile Send private message Visit poster's website Yahoo Messenger MSN Messenger

WDT - Watchdog Timer
PostPosted: Mon Jun 29, 2015 9:36 am     Reply with quote

I am involved in a very small project using a battery. It is supposed to maintain a loop, in which it blinks a led, then goes into Sleep and wakes up after a few seconds with the time-out of the WDT timer. Blinks again and returns to Sleep and so on.
This is the code I’ve written:

Code:
void main(){
                OPTION_REG    = 0x8E;//1000 1110 prescaler WDT 1:64
    enable_interrupts(INT_RTCC);
    enable_interrupts(INT_RA3);
    enable_interrupts(GLOBAL);
                while (true){
                               SLEEP();
                               delay_cycles(1);//nop
                               a = restart_cause();//11 = WDT_TIMEOUT ; 3 = WDT_FROM_SLEEP
                               LED=~LED;
                }
}

When I simulate the code, I receive the following warning:
"CORE-W0004: Watchdog Timer has generated a wakeup signal"
restart_cause() return a 3 code : WDT_FROM_SLEEP

passed 200 cycles, the simulator generates an error:
"MAXIMUM number of warnings/errors exceeded 200, program execution halted."

As I understand, the time-out from the WDT timer simply wakes up the unit and does not generate a Restart. Why doesn't it work?

Can you help me with that?
Ttelmah



Joined: 11 Mar 2010
Posts: 19498

View user's profile Send private message

PostPosted: Mon Jun 29, 2015 10:50 am     Reply with quote

First of all, what PIC?.

Then you should not need to fiddle with the option register yourself. This is what the CCS commands are for.

Then you have interrupts enabled, and don't show handlers.
You have the RTCC interrupt enabled, but no code to configure this timer.

Interrupts will wake the chip as well as the WDT.

You don't show your fuses (which affect how the watchdog works).
sergioigel



Joined: 13 Aug 2010
Posts: 26
Location: RJ/Brazil

View user's profile Send private message Visit poster's website Yahoo Messenger MSN Messenger

PostPosted: Mon Jun 29, 2015 12:10 pm     Reply with quote

Hello,

PIC = PIC12F675
FUSES =
Code:
#FUSES INTRC_IO     
#FUSES NOMCLR       
#FUSES WDT          
#FUSES PUT          
#FUSES NOBROWNOUT     

#int_rtcc
void interrupt_wdt(void){
   char a,i,QTD;
   a = restart_cause();//11 = WDT_TIMEOUT ; 3 = WDT_FROM_SLEEP
   if ((a==3)||(a==11)){
      restart_wdt();
      if (!DETECTOR){
         QTD = 5;
      }else{
         QTD = iTIME;
      }
      for (i=1;i<=QTD;++i){
         SLEEP();
         delay_cycles(1);
         restart_wdt();
      }
   }else{
      SLEEP();
      delay_cycles(1);
      restart_wdt();
   }
}

Ttelmah wrote:
First of all, what PIC?.

Then you should not need to fiddle with the option register yourself. This is what the CCS commands are for.

Then you have interrupts enabled, and don't show handlers.
You have the RTCC interrupt enabled, but no code to configure this timer.

Interrupts will wake the chip as well as the WDT.

You don't show your fuses (which affect how the watchdog works).
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Mon Jun 29, 2015 12:55 pm     Reply with quote

Your use of the sleep command inside the TIMER ISR that is triggered by
waking up from sleep makes me very uneasy.

better that sleep be called from MAIN() and only be tasked to set a flag for main to do the rest off the work you want to do.

then let main call the sleep at the point you want to resume foreground execution.

but worse than that is you never show how or where you enable the wake from sleep ISR handler ==
you need to show more code still to convince me that your code is not fundamentally flawed beyond help.
Pay more attention to Ttelmah's suggestions.
You are only a tiny bit of the way to showing what he asked for.......

its a small pic - why not just show ALL your code from top to bottom.
Ttelmah



Joined: 11 Mar 2010
Posts: 19498

View user's profile Send private message

PostPosted: Mon Jun 29, 2015 1:59 pm     Reply with quote

There is another one I didn't mention, which is that restart_cause is _only_ valid at the start of the code, before any settings change the registers. Using it anywhere else will not give a legitimate value.

As shown (in the interrupt code), the processor won't actually go to sleep. Because the interrupt flag will be set (inside an interrupt handler), the sleep will not happen. Not surprising the code does not do what is expected....

There is another severe 'misunderstanding' of the chip that appears to be happening in the bits of code shown. This chip does not support 'wake' from sleep with the watchdog. A watchdog on this chip always triggers a reset. What happens is that the chip resets and the reset is flagged as a watchdog from sleep. The code will never reach the instructions after the sleep, unless it wakes for another reason (the external interrupt).

On this chip to use watchdog 'wake', you have to code as:
Code:


int a_variable; //use global variables for everything that must
//be used after the watchdog

void main(void)
{
    if (restart_cause() != WDT_FROM_SLEEP)
    {
        //Here initialise variables
        a_variable=0; //for example
        //setup interrupts. peripherals etc..
    }
    //Now when you arrive here you have the peripherals and variables
    //either initialised or as they were before the watchdog or setup
    //from boot.
    //now do your code

}
sergioigel



Joined: 13 Aug 2010
Posts: 26
Location: RJ/Brazil

View user's profile Send private message Visit poster's website Yahoo Messenger MSN Messenger

PostPosted: Tue Jun 30, 2015 6:58 am     Reply with quote

here the full code:
Code:

#include <\drivers\12F675.h>
#include "\hexa\main.h"
/*
#include "\hexa\functions.h"
#include "\hexa\config_inicial.h"
#include "\hexa\detector.h"
#include "\functions\interrupts.c"
*/

void CONFIG_INICIAL(void){
   delay_ms(1000);

    PORT_A_PULLUPS(False);
   ADCON0 = 0x00;//A/D CONTROL REGISTER
   ANSEL  = 0x50;//ANALOG SELECT REGISTER( A/D Conversion Clock Select bits Fosc/16 )
   set_tris_a(TRISA);

   IO_LED_VERMELHO =0;
   IO_LED_VERDE    =0;
   IO_FOTO_CELULA   =1;

   OPTION_REG    = 0x87;//1000 1110 pull up desligado / wdt prescale = 1:64
   
   Bit_Set(PCON,1);//No Power-on Reset occurred
 
    enable_interrupts(INT_RA3);

   enable_interrupts(GLOBAL);

      while (true){
      SLEEP();
      restart_wdt();
   }
}

void MARCA_TEMPO_ENTRAR_SLEEP(void){
   char i,QTDE;

   if ((!DETECTOR_COM_AGUA)|(FALHA_DETECTOR)){
      QTDE = 5;
   }else{
      QTDE = HORA;
   }
   for (i=1;i<=QTDE;++i){
      SLEEP();
      restart_wdt();
   }
}

void PISCA_LED(char LED,QTDE,TEMPO){
   char i;
   int1 alternar=0;
   restart_wdt();
   
   if (FALHA_DETECTOR){
      for (i=0;i<=QTDE*2;++i){
         restart_wdt();
         if (alternar){
            IO_LED_VERMELHO=1;
            delay_ms(TEMPO);
            IO_LED_VERMELHO=0;
            delay_ms(TEMPO*5);
         }else{
            IO_LED_VERDE=1;
            delay_ms(TEMPO);
            IO_LED_VERDE=0;
            delay_ms(TEMPO*5);
         }
         alternar = ~alternar;
      }
   }

   if (LED == 1){
      IO_LED_VERDE=1;
      delay_ms(TEMPO);
      IO_LED_VERDE=0;
    }else{
      for (i=1;i<=QTDE;++i){
         restart_wdt();
         IO_LED_VERMELHO=1;
         delay_ms(TEMPO);
         IO_LED_VERMELHO=0;
         delay_ms(TEMPO*5);
      }
   }
}

void VERIF_CODIGO_FOTOCELULA(void){
   if (IO_FOTO_CELULA==0){
      LIGOU_EQUIPAMENTO=1;
   }
}


int1 VERIF_AGUA_DETECTOR(void){
   int1 RETORNO;
   IO_ALIMENTACAO_DETECTOR=1;
   delay_us(100);
   T1CON    = 0x06;//00000110;external clock
   Bit_Clear(PIR1,0);//TMR1IF
   TMR1L   =0;
   TMR1H   =0;
   Bit_Set(T1CON,0);
   delay_ms(100);
      Bit_Clear(T1CON,0);
   IO_ALIMENTACAO_DETECTOR=0;

   if ((TMR1H==0)&&(TMR1L <= 35)){
      RETORNO=1;
   }else{
      RETORNO=0;
   }

   FALHA_DETECTOR=((TMR1H==0)&&(TMR1L == 0));

   return(RETORNO);
}

int1 DETECTOR_TEM_AGUA(void){
   int1 TEM_AGUA;
   int1 temp1,temp2;

   temp1 = VERIF_AGUA_DETECTOR();
   temp2 = VERIF_AGUA_DETECTOR();
   if (temp1 == temp2){
      TEM_AGUA=(temp1==1);
   }
   return(TEM_AGUA);
}


void main() {
   CONFIG_INICIAL();
   //LIGOU_EQUIPAMENTO=1;
   while(true){
      restart_wdt();
      if (LIGOU_EQUIPAMENTO){
         while(true){
   //         VERIF_CODIGO_FOTOCELULA();
            restart_wdt();
            if (!DETECTOR_COM_AGUA){
               DETECTOR_COM_AGUA = DETECTOR_TEM_AGUA();
               TEMPO_LER_DETECTOR=0;
            }else{
               if ((TEMPO_LER_DETECTOR+HORA)>=5){
                  TEMPO_LER_DETECTOR=0;
                  DETECTOR_COM_AGUA = DETECTOR_TEM_AGUA();
               }            
               ++TEMPO_LER_DETECTOR;
            }
   
            if (!DETECTOR_COM_AGUA){
               TEMPO_SEG=0;
               TEMPO_MIN=0;
            }else{
               ++TEMPO_SEG;
               if (TEMPO_SEG>=60){
                  TEMPO_SEG=0;
                  ++TEMPO_MIN;
                  if (TEMPO_MIN>=60){
                     TEMPO_MIN=0;
                     ++HORA;
                     if (HORA > 5)   HORA=5;
                  }
               }
            }
            PISCA_LED(!DETECTOR_COM_AGUA,HORA,100);
            MARCA_TEMPO_ENTRAR_SLEEP();
         }
      }else{
         //VERIF_CODIGO_FOTOCELULA();
      }
   }
}


#int_ra
void interrupt_on_change(void){
   long long i;
   if (!LIGOU_EQUIPAMENTO){
      if (IO_FOTO_CELULA==0){
         for (i=0;i<=90000;++i){
            restart_wdt();
            //delay_ms(2000);
         }
         if (IO_FOTO_CELULA==0){
            LIGOU_EQUIPAMENTO=1;
             enable_interrupts(INT_RTCC);
             disable_interrupts(INT_RA3);
         }
      }
   }
   Bit_Clear(INTCON,0);
}


#int_rtcc
void interrupt_wdt(void){
   char a,i,QTDE;
   if (!LIGOU_EQUIPAMENTO){
      SLEEP();
      delay_cycles(1);
      restart_wdt();
   }else{
      a = restart_cause();//11 = WDT_TIMEOUT ; 3 = WDT_FROM_SLEEP
      if ((a==3)||(a==11)){
         restart_wdt();
         if (!DETECTOR_COM_AGUA){
            QTDE = 5;
         }else{
            QTDE = HORA;                         
         }
         for (i=1;i<=QTDE;++i){
            SLEEP();
            delay_cycles(1);//nop
         }
      }else{
         SLEEP();
         delay_cycles(1);//nop
      }
   }
}

asmboy wrote:
Your use of the sleep commad inside the TIMER ISR that is triggered by
waking up from sleep makes me very uneasy.

better that sleep be called from MAIN() and only be tasked to set a flag for main to do the rest off the work you want to do.

then let main call the sleep at the point you want to resume foreground execution.

but worse than that is you never show how or where you enable the wake from sleep ISR handler ==
you need to show more code still to convince me that your code is not fundamentally flawed beyond help.
Pay more attention to TTelmahs suggestions.
You are only a tiny bit of the way to showing what he asked for.......

its a small pic - why not just show ALL your code from top to bottom.
Ttelmah



Joined: 11 Mar 2010
Posts: 19498

View user's profile Send private message

PostPosted: Wed Jul 01, 2015 2:05 am     Reply with quote

Now gets more complex, and raises a question.

Had an 'oddity' pointed out by PCM_programmer. Smile

What is the date/version number of your 675?....

Have two data sheets for this chip. The original paper version (2002) and the 2010 version. The 2002 version says that the chip will always restart from a watchdog. The 2010 version says a watchdog while asleep, will wake the chip.

Interestingly, no 'erratum' about this, but the current errata sheet only mentions revisions A9, and B0. The 675's I had from this time were A2....

So, depending on the date of the chip, things _will_ behave completely differently.....

So my comment here is wrong if you have a current chip. However if somehow you have an old chip, then the current data sheet is wrong. Crying or Very sad

Aaargh!.

Now tried this experiment:
Code:

#include <12F675.h>
#device ADC=10
#FUSES WDT                      //Watch Dog Timer enabled
#FUSES NOMCLR                //No MCLR
#use delay(internal=4000000)

#define LED PIN_A0

void main()
{
   int8 cause;
   setup_wdt(WDT_1152MS);      //1152mSec nominal
   while(TRUE)
   {
      cause=restart_cause();
      sleep();
      delay_cycles(1);
      output_toggle(LED);
   }
}

Bought in a couple of new '675' chips, and took one out of my stock (we always hold old chips for every board made).
Programmed both.
Added an LED and resistor, and powered them up.

Note one other important thing. The delay_cycles(1) after the sleep. The instruction after a sleep, is 'pre-fetched' when you go to sleep. It is generally advised therefore to ensure this is a NOP. The delay_cycles, gives this.

The current chip flashes the LED, the old (2003) chip, doesn't.

Added some diagnostics. The restart_cause call in the loop, works correctly on the new chip _but only if it has been called before_ You need to access restart_cause 'on boot', this sets the PD bit, which is then unchanged the next time this is called, and allows the code to distinguish a watchdog reset from watchdog from sleep.

Now the code as posted, shows the sort of basic layout needed to get the chip working. No fiddling with option, this toggles the LED about every 1.5 seconds on my chip (remember the watchdog times are _very_ nominal).

So the first thing to do, is check with your device programmer what revision chip you actually have.....
sergioigel



Joined: 13 Aug 2010
Posts: 26
Location: RJ/Brazil

View user's profile Send private message Visit poster's website Yahoo Messenger MSN Messenger

PostPosted: Mon Jul 13, 2015 6:26 am     Reply with quote

Thanks a lot for your effort, Ttelmah

I decided not to use the sleep command in this project with this PIC, although I lost a little battery autonomy.
I will use a larger battery.




Ttelmah wrote:
Now gets more complex, and raises a question.

Had an 'oddity' pointed out by PCM_programmer. Smile

What is the date/version number of your 675?....

Have two data sheets for this chip. The original paper version (2002) and the 2010 version. The 2002 version says that the chip will always restart from a watchdog. The 2010 version says a watchdog while asleep, will wake the chip.

Interestingly, no 'erratum' about this, but the current errata sheet only mentions revisions A9, and B0. The 675's I had from this time were A2....

So, depending on the date of the chip, things _will_ behave completely differently.....

So my comment here is wrong if you have a current chip. However if somehow you have an old chip, then the current data sheet is wrong. Crying or Very sad

Aaargh!.

Now tried this experiment:
Code:

#include <12F675.h>
#device ADC=10
#FUSES WDT                      //Watch Dog Timer enabled
#FUSES NOMCLR                //No MCLR
#use delay(internal=4000000)

#define LED PIN_A0

void main()
{
   int8 cause;
   setup_wdt(WDT_1152MS);      //1152mSec nominal
   while(TRUE)
   {
      cause=restart_cause();
      sleep();
      delay_cycles(1);
      output_toggle(LED);
   }
}

Bought in a couple of new '675' chips, and took one out of my stock (we always hold old chips for every board made).
Programmed both.
Added an LED and resistor, and powered them up.

Note one other important thing. The delay_cycles(1) after the sleep. The instruction after a sleep, is 'pre-fetched' when you go to sleep. It is generally advised therefore to ensure this is a NOP. The delay_cycles, gives this.

The current chip flashes the LED, the old (2003) chip, doesn't.

Added some diagnostics. The restart_cause call in the loop, works correctly on the new chip _but only if it has been called before_ You need to access restart_cause 'on boot', this sets the PD bit, which is then unchanged the next time this is called, and allows the code to distinguish a watchdog reset from watchdog from sleep.

Now the code as posted, shows the sort of basic layout needed to get the chip working. No fiddling with option, this toggles the LED about every 1.5 seconds on my chip (remember the watchdog times are _very_ nominal).

So the first thing to do, is check with your device programmer what revision chip you actually have.....
temtronic



Joined: 01 Jul 2010
Posts: 9221
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Mon Jul 13, 2015 6:56 am     Reply with quote

I, for one, am HAPPY you used a bigger battery ! It's a simple cheap solution. I've never understood the 'need' for ultra small devices, I prefer 'man sized' components. 'old school'. I have a LCD clock module running on 2 AA cells in parallel for the past 20 years ! Proof that bigger is better.
These days you can get a HUGE amount of energy from a regular AA sized battery for $2 so I can't see why anyone uses 'coin' cells.

You could add a 'supercap' in parallel to the battery to help 'smooth' the power demands when a 'heavy' load turns on. Just an idea.

Jay
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