|
|
View previous topic :: View next topic |
Author |
Message |
NeedleinHaystack Guest
|
Searching for cause of processor reset on PIC16F648A |
Posted: Wed Mar 22, 2006 9:53 am |
|
|
Hello all,
I'm utilizing the pIC16F648A processor and am happily programming away when I noticed that every once in a while.. I mean like once in a 24 hour period, sometimes 2-3 times in a 24 hour period. Somes times once in a 48 hour period my system seems to reset. Other than that my entire code runs perfectly
I'm running on battery power.. and I'm not doing much special.
I am using interrupts and based upon the description in the reference manual I do not need to save any registers etc. I am not using FAST or anything like that.
I have the watchdog timer enabled, brownout detection disabled and I do use SLEEP.
My .lst shows the following..
Code: | CCS PCM C Compiler, Version 3.239, 31556 22-Mar-06 09:23
Filename: BestTimer.lst
ROM used: 3316 words (81%)
Largest free fragment is 767
RAM used: 86 (49%) at main() level
104 (59%) worst case
Stack: 7 worst case (6 in main + 1 for interrupts)
|
So it seems that I am not having a stack problem.
I'll admit this it my first project using the this compiler so I might have missed something.
Any suggestions, hints, etc. are greatly appreciated. Thanks in advance
Here are some snipets of my code.. Setup, Main and Interrupts incase anyone needs them.. If you need to see anything else.. let me know.
Code: |
#include "16F628A.h"
#pragma fuses INTRC_IO,WDT,PUT,NOPROTECT,NOBROWNOUT,MCLR, NOLVP, NOCPD
#pragma use fast_io(B) //Compiler DOES NOT SET Data Direction Bits
#pragma use standard_io(A) //Compiler DOES set Data Direction Bits
//Basic asm instruction and Customer Compiler Support
#define global_int_enable() enable_interrupts(GLOBAL) /* Authorize Interrupts */
#define global_int_disable() disable_interrupts(GLOBAL) /* Disable all Interrupts */
#define NOP() #asm nop #endasm /* NOP Instruction */
//Reset COP Resets internal Watchdog Timer.
#define Reset_COP() restart_wdt()
/******************************************
Initialization routine
Call Various Initializations for the application.
******************************************/
void Initialize(void)
{
//Setup Watchdog Timer. (~ 1 second.)
setup_wdt(WDT_1152MS);
//Reset Watchdog Timer.
Reset_COP();
//Init basic Variables.
MyFlags.byte = 0; //All Flag Bits..FALSE.
MyFlags1.byte = 0;
Ports_Init(); //Initialize Ports
menu_Menu_Init(); //Setup Main Menu.
lcd_LCD_Init(); //Initialize LCD
timer_RTC_Init(); //Initialize RTC
timer_Timer_Init(); //Initialize Timer
button_Button_Init(); //Initialize button
analog_Analog_Init(); //Initialize analog comparator
eeprom_Eeprom_Init(); //Initialize EEPROM.
}//end Initialize
/******************************************
Main Program
Setup Processor Specific Registers
Call Initlizations.
Perform Main Loop
******************************************/
void main()
{
//*******************
//Local Variables..
//*******************
//Disable Global Interrupts
global_int_disable();
RestartCause = restart_cause();
PCON |= 0x03;
//Reset COP
Reset_COP();
//Run Application specific initializations
Initialize();
//Enable Global Interrupts
global_int_enable();
//Begin Embedded Processing Loop
//This runs forever...
while (1)
{
//Reset the COP..
Reset_COP();
//Check Battery
//Well this is automatic now..
//We have a BatteryCheck_isr routine it interrupts us
//any time our comparator changes state.. And that sets our
//LowBattery Flag.
//REAL CODE..
/*
.
. THERE is code here. but to keep this short I removed it.
.
.
.
*/
//Should the Display be Sleeping?
if (InactiveMinutes == 0)
{ //YES it should be sleeping..
//Is the display alsleep already?
if (DisplayOn==TRUE)
{ //NO. Sleep the Display and clear our menu's
//NOTE: Anything not completed will not be finished.. and will be lost.
menu_ClearMenuStates();
MainMenuState = DISPLAY_SLEEP;
lcd_Turn_Off_Display();
} //END - Yes we need to turn off the display
//Since the display is asleep also put us to sleep
//Our Second interrupt will wake up us.. and that will
//Allow us to WAKEUP whenever necessary.. and this will
//put us back to sleep once we are INACTIVE again.
enable_interrupts(INT_RB);
sleep();
} //END = YES We Should be Sleeping
else
{ //Nope we should not be sleeping... So.
//Update the Display
lcd_Update_Display();
} //END - Else.. Display Awake.. So Show Display.
} /* end of while forever */
} /* end of main */
#INT_RB
void rb_isr(void)
{
//We woke up.. Now we are done with this..
disable_interrupts(INT_RB);
}
#INT_DEFAULT
void default_isr(void)
{
NOP();
}
#INT_TIMER1
void timer_RTCISR(void)
{
//Setup Timer1 for 1 second NOT Two (Timer for 1/2 the designated time)
//??OR Should I just set TMR1H (0x80)
set_timer1(T1RESET); //??0x7FFF
//Reset Timer Interrupt.
//This is done automatically by the PIC compiler.
//Increment Counter ..
TimerSecondCounts--;
//Check if Seconds Should be incremented
if (TimerSecondCounts == 0)
{
//Reset TimerSecondCounts
TimerSecondCounts = TICKS_PER_SEC;
//Signal that we need to increment our seconds timer.
SecondsInc = TRUE;
} //END TimerTicks Wrap.
} //END - isr routine.
#INT_TIMER2
void timer_TIMER2ISR(void)
{
//Decrement Counter
BlinkCounts--;
//Check for Counter Finished
if (BlinkCounts==0)
{
//Reset our Counter
BlinkCounts = TICKS_PER_BLINK;
//Toggle our BlinkTime Bit
//Using the know fact that b0 toggles on each increment.
//Cheap, but uses little program memory..
BlinkTime.byte++;
}
//TO.. Add ButtonTimers in here too..
//But keep short and sweet.
if (Timer_Next_Action != 0)
Timer_Next_Action--;
if (Timer_Accelerate !=0)
Timer_Accelerate--;
}
#INT_COMP
//Interrupt happens any time a change is seen from
//the compartor output from high to low.
void BatteryCheck_isr(void)
{
//If C2Out is High -> C2In+ > CIn- A2>A1 9vDivider > 3.3V Divider
//This means BATTERY_OK
//If C2Out is LOW C2VIN+ < CIn0 A2 < A1 9VDivider < 3.3V Divider.
//This means the BATTERY_IS_LOW
if (C2OUT == 1)
LowBattery = FALSE;
else
LowBattery = TRUE;
}//end BatteryCheck
|
|
|
|
Ttelmah Guest
|
|
Posted: Wed Mar 22, 2006 11:02 am |
|
|
Handle the sleep/wake up slightly differently.
You do not actually 'need' an interrupt handler for the interrupt that wakes you up. Instead,disable the other interrupt sources, disable the global interrupt, then enable this, and clear it, then go to sleep. The code will waken on the next line, and you can then disable this interrupt, and re-enable the rest. The problem is that _any_ enabled interrupt will cause a wake-up. Also, if an interrupt triggers 'on' the sleep instruction, the chip will not actually go to sleep.
However this is 'cosmetic', since it should just result in a premature 'wake up'. I suspect the real problem is the watchdog.
Now the watchdog, at a nominal 1152mSec, is too close to your 1 second wake up time, for comfort. The watchdog timer is _not_ accurate. The default watchdog time, is 18mSec (without divider), but can range through supply voltage, and temperature variations, from 7mSec, to 33mSec. This corresponds to your version with the /64 prescaler, triggering at between 448, and 2113 mSec. I suspect what is happening, is that at times, this just drifts far enough, to trigger _before_the wake-up, hence the reset.
Best Wishes |
|
|
NeedleinHaystack Guest
|
|
Posted: Wed Mar 22, 2006 11:39 am |
|
|
Thanks for the quick response..
I did not realize that there was that much play in the WDT values. I'm actually trying to confirm now with some DEBUG code to show the restart cause upon any resets and hopefully sometime today that will happen. But when it does, then what..
Is there a good way to handle a WDT for a processor that I'd like to
"SLEEP" most of the time and only wake up once per second
for Timekeeping purposes?
Should I make myself wake up more often?
Or are you suggesting that I should I just disable the WDT all together?
I will be searching the forum incase any other posts have covered this already.. Thanks again.
Quote: | Handle the sleep/wake up slightly differently.
You do not actually 'need' an interrupt handler for the interrupt that wakes you up. Instead,disable the other interrupt sources, disable the global interrupt, then enable this, and clear it, then go to sleep. The code will waken on the next line, and you can then disable this interrupt, and re-enable the rest. The problem is that _any_ enabled interrupt will cause a wake-up. Also, if an interrupt triggers 'on' the sleep instruction, the chip will not actually go to sleep.
However this is 'cosmetic', since it should just result in a premature 'wake up' |
I see your point here.. I will modify the wakeup, but I have a few questions on your implementation. First you say to disable the global interrupt, does that not disable all interrupts in which case it won't WAKE-UP. Also, In terms of disabeling the non-wakeup sources I only have ONE which is TIMER2, and timer2 does not run during SLEEP so would it still be advisable to disable it? I also noticed that you suggest clearing the interrupt after I enable it. Is that a common practice to clear after enabling. I would think that
once enabled if it was set.. it would go off right away. Maybe it should be cleared before enabling?
Thanks again for your assistance |
|
|
Ttelmah Guest
|
|
Posted: Wed Mar 22, 2006 3:30 pm |
|
|
Wake up from sleep, is independant of actual interrupting. Read the data sheet about this. Quote:
"Wake-up, is regardless of the state of the GIE bit. If the GIE bit is clear (disabled), the device continues execution at the instruction after the SLEEP instruction. If the GIE bit is set (enabled), the device executes the instruction after the SLEEP instruction, and then branches to the interrupt address".
Wake up occurs, when the interrupt flag gets set, even if the global interrupt is disabled. :-)
The problem is that the RB interrupt, may already be set, since it has been disabled, and something may have triggered it. Any interrupt where this is true, should be cleared 'before use', or you will get an extra trigger. Now in your case, what will happen if it is set, is exactly what you describe. You enable the interrupt. Since the global interrupt is already set, if the interrupt is set, the code will jump to the handler, and disable the interrupt, leaving the interrupt turned off!...
You can clear it after enabling, if the global interrupt is disabled. If you clear it before enabling, there is still a risk, that it may trigger in the instruction between clearing it, and turning it on.
Best Wishes |
|
|
NeedleinHaystack Guest
|
|
Posted: Wed Mar 22, 2006 3:59 pm |
|
|
Quote: | Wake up from sleep, is independant of actual interrupting. Read the data sheet about this. Quote:
"Wake-up, is regardless of the state of the GIE bit. If the GIE bit is clear (disabled), the device continues execution at the instruction after the SLEEP instruction. If the GIE bit is set (enabled), the device executes the instruction after the SLEEP instruction, and then branches to the interrupt address". |
I read this in the data sheet shortly after I posted, and I decided that I want to be able to wakeup on my timer1 (clock) interrupt or on the comparator interrupt and I want to go to the interrupt routine in those cases, so I do need global interrupts on once I go to sleep. But I did see that it was possible to disable the global interrupts, and have them wake you up. (Didn't know that before)
My real concern at this point though is how do I tackle the Watchdog (resetting) problem? Looking at the datasheet I do see the extremes in the watchdog timeouts. Even if I use the \128 I can still have a range of 894mS to 4224ms. Which is less than my timer timeout of 1 second.
So what would be the best method of correcting this?
1) Change my timer to timeout every 500ms so that it definately times out before the watchdog does? (Hopefully this wont effect my long term timing which needs to be accurate)
2) Remove the watchdog altogether?
3) Is this even the problem at all.. When the system goes to Sleep and the watchdog times out it is supposed to be just a wakeup from sleep watchdog, which does not re-set the processor.? So is there some other reason that I'm getting these random resets.
I'm still waiting for my DEBUG code to give me a reset yet so I do not have the exact restart_cause() just yet. |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Wed Mar 22, 2006 5:23 pm |
|
|
As a side note, for a really accurate time clock don't adjust the timer value with Code: | set_timer1(T1RESET); //??0x7FFF |
Because of interrupt handler overhead some time will have past before you execute this instruction, this can be corrected by adding to the current timer value: Code: | set_timer1( get_timer1() + T1RESET ) |
This still has a small error caused by the delay between reading and setting the timer values.
The most accurate Real Time Clock implementation I've seen can be found in the code section: http://www.ccsinfo.com/forum/viewtopic.php?t=26177 |
|
|
NeedleinHaystack Guest
|
|
Posted: Wed Mar 22, 2006 6:11 pm |
|
|
Thanks for the info on the timer..
I looked at that code earlier today and thought it was cool. Though I'm using a 32.768KHz crystal directly into timer1 to try to keep it accurate.. It has actually been pretty good so far even with that delay. My reason for choosing the 1 second, instead of the 2 seconds the timer gives to me was so that I could be shorter than the WDT timeout.. but if it turns out that I don't need, cant use, the watchdog timer.. Than I will take that set_timer1 out. Otherwise.. I will definately incorporate that get_timer, into my set_timer. |
|
|
NeedleinHaystack Guest
|
MCLR_from_RUN Reset? |
Posted: Thu Mar 23, 2006 7:31 pm |
|
|
Well I finally got my first reset on the system after about a day and a half. And I think it was ESD related. I was moving the board around and suddenly it reset.
The reset code I received was 27. Which is a MCLR_from_RUN reset..
I'm assuming this was caused by an ESD event since I do not have any method of causing MCLR to change levels. Does anyone have any suggestions on how to prevent this, Has anyone ever seen this before?
Also.. On powerup I'm not received the normal 24 restart_cause value I'm received 25. I contacted CCS but have not received a reply yet. Anyone else seen this.
I'm using the PIC16F648A and my compiler is Version 3.239
Thanks in advance for all your help. |
|
|
|
|
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
|