|
|
View previous topic :: View next topic |
Author |
Message |
Christophe
Joined: 10 May 2005 Posts: 323 Location: Belgium
|
|
Posted: Tue Jun 28, 2005 1:06 am |
|
|
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
|
|
Posted: Tue Jun 28, 2005 1:47 am |
|
|
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
|
|
Posted: Tue Jun 28, 2005 9:49 am |
|
|
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
|
|
Posted: Tue Jun 28, 2005 9:53 am |
|
|
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
|
|
Posted: Wed Jun 29, 2005 2:49 am |
|
|
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
|
|
Posted: Wed Jun 29, 2005 4:06 am |
|
|
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
|
|
Posted: Wed Jun 29, 2005 8:07 am |
|
|
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
|
|
Posted: Wed Jun 29, 2005 8:12 am |
|
|
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
|
|
Posted: Wed Jun 29, 2005 8:23 am |
|
|
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
|
|
Posted: Wed Jun 29, 2005 8:24 am |
|
|
posting.php ignore pls |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jun 29, 2005 3:09 pm |
|
|
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
|
RDA_ISR |
Posted: Thu Oct 20, 2005 4:51 am |
|
|
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: 1907
|
Re: RDA_ISR |
Posted: Thu Oct 20, 2005 8:10 am |
|
|
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
|
|
Posted: Thu Oct 20, 2005 9:56 am |
|
|
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
|
Thanks! |
Posted: Fri Oct 21, 2005 7:59 am |
|
|
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. |
|
|
|
|
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
|