|
|
View previous topic :: View next topic |
Author |
Message |
sergioigel
Joined: 13 Aug 2010 Posts: 26 Location: RJ/Brazil
|
WDT - Watchdog Timer |
Posted: Mon Jun 29, 2015 9:36 am |
|
|
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: 19559
|
|
Posted: Mon Jun 29, 2015 10:50 am |
|
|
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
|
|
Posted: Mon Jun 29, 2015 12:10 pm |
|
|
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
|
|
Posted: Mon Jun 29, 2015 12:55 pm |
|
|
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: 19559
|
|
Posted: Mon Jun 29, 2015 1:59 pm |
|
|
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
|
|
Posted: Tue Jun 30, 2015 6:58 am |
|
|
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: 19559
|
|
Posted: Wed Jul 01, 2015 2:05 am |
|
|
Now gets more complex, and raises a question.
Had an 'oddity' pointed out by PCM_programmer.
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.
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
|
|
Posted: Mon Jul 13, 2015 6:26 am |
|
|
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.
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.
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: 9250 Location: Greensville,Ontario
|
|
Posted: Mon Jul 13, 2015 6:56 am |
|
|
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 |
|
|
|
|
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
|