View previous topic :: View next topic |
Author |
Message |
Can
Joined: 26 Feb 2012 Posts: 23
|
sleep() and watchdog timer |
Posted: Tue Mar 06, 2012 2:08 am |
|
|
Hello all,
I am trying to put the PIC to sleep under certain conditions and wake it up every once in a while. WDT seems to be a good choice to wake the PIC up from sleep however when it is not sleeping, it keeps resetting the PIC. I am using delays longer than the WDT overflow time so I need to disable the WDT when I don't want it to reset the PIC. For example when the USB is enumerated it should stay awake.
Here is my code:
Code: |
void main(){
SETUP_ADC(0x07); //internal clock
SETUP_ADC_PORTS(0x0B); //AN0->AN3
delay_ms(100);
ds1307_init();
init_ext_eeprom();
// Initialize USB CDC (this sets line coding and clears buffers).
usb_cdc_init();
// Initialize USB subsystem.
// Since we are not using sense pin, this will not wait indefinitely.
usb_init_cs(); //I've also tried usb_init() but no luck
delay_ms(1000);
output_high(PIN_B5); //Power up the RTC
output_high(PIN_B4); //Power up the EEPROM
while(true){
// Sense USB status.
usb_task();
//delay_ms(100);
setup_wdt(wdt_off);
if(usb_enumerated()){
setup_wdt(wdt_off);
output_low(pin_B6);
output_high(pin_B5);
// Get_Data();
if(usb_cdc_kbhit()){
getItem();
showSub();
}
} else{
output_low(pin_B5);
output_high(pin_B6);
//Put the PIC to sleep if no USB connection
setup_wdt(wdt_on);
restart_wdt();
sleep();
delay_cycles(1);
}
}
}
|
In my fuses I tried different things like WDT128, WDT, and since I read somewhere that setup_wdt(wdt_on) can only be used while #NOWDT is set (I can not remember where I've read it), I even tried the #NOWDT.
What I want the code to do is: If there is no USB connection do some stuff (which is going to be to read the adc and timestamp it and write it to EEPROM, yet to be implemented)-> go to sleep -> wake up -> check the USB connection -> if there is a connection, don't go to sleep...
I can't figure out what i am doing wrong. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19366
|
|
Posted: Tue Mar 06, 2012 2:33 am |
|
|
What PIC.....
The abilities of both the fuses and setup_wdt, vary with the PIC.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Tue Mar 06, 2012 2:46 am |
|
|
Watchdogs are intended to reset processors in the event that something goes wrong and normal processing stops. Its not a general purpose timer. Its a watch dog timer. If enabled, it resets the processor when it times out. You MUST keep resetting (kicking) during normal processing to keep the watchdog alive.
So, the watchdog is not an appropriate resource to use while the processor is sleeping.
What is? Any event that would generate an interrupt will bring the processor out of sleep. Apparently, interrupts don't even have to be enabled, but the cause of interrupt shuld be dealt with in the normal way (e.g. read port b if it was an "interrupt on change". It makes more sense if you think of an interrupt as a request for action, thereby forcing the processor out of sleep so that it can take the relevant action.
Its generally counter productive to consider sleep as sleeping for some particular time. Timers ARE useful for bringing the processor out of sleep, but because they produce known time intervals, but because they can bring the processor out of sleep periodically to poll for some state in case action is required. If it isn't you can aimply go back to sleep.
"I am trying to put the PIC to sleep under certain conditions and wake it up every once in a while. "
Instead of this, its probably better better to think of putting the PIC to sleep if there's nothing useful to do and wake it up when there is something (as indicated by an interrupt), or once in a while in case there's something to do (on a timer). In your case you need it to wake up any any USB activity.
One question: Do you really need it to sleep? Is this USB powered? What is your power source? Do you really need the power savings of sleep? If not, try to make things simpler: don't sleep.
RF Developer. |
|
![](templates/subSilver/images/spacer.gif) |
Can
Joined: 26 Feb 2012 Posts: 23
|
|
Posted: Tue Mar 06, 2012 3:10 am |
|
|
RF_Developer and Ttelmah thank you for your replies.
I am using an 18F2550.
My intention is to realize a datalogger. It is going to run on batteries so I need it to be power efficient. I want to gather data like every minute or every 5 minutes whatever.. So i need to get the PIC to sleep.
However I don't want it to go to sleep when I attach the USB for dumping the data to PC.
Thank you |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19366
|
|
Posted: Tue Mar 06, 2012 3:26 am |
|
|
Have you got a USB connection sense pin?.
If not, it is not going to work.
Problem is that USB _requires_ it's responses in a very limited time scale. Now if your system is asleep, and you then attach it to a PC, it'll probably still be asleep when the PC tries to enumerate. Problem.
However what you want can be done, with the connection sense pin. If this is connected to B0, you can program an interrupt on the rising edge of this to 'wake' you up, ready to service the enumeration request. The loop can then test for 'usb_is_attached', and remain awake so long as this is so.
If you need intermittent wake up while asleep, this should be available using the watchdog, but details will depend on your chip, so same comment at before 'what chip'.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19366
|
|
Posted: Tue Mar 06, 2012 3:27 am |
|
|
OK 18F2550. Will look up the details for this.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
Can
Joined: 26 Feb 2012 Posts: 23
|
|
Posted: Tue Mar 06, 2012 3:32 am |
|
|
Ttelmah, I wasn't using a USB connection sense pin. I will try to arrange it in the hardware and see if it works. So I suppose I have to program an external interrupt on pinB0. I have to figure out how to do it. I am a total stranger to the interrupts
Edit: The problem with using the pinB0 is that it is already utilized for i2c communications.. Is it possible to program another pin for the external interrupt?
Thank you, |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19366
|
|
Posted: Tue Mar 06, 2012 3:56 am |
|
|
OK. 2550.
From the fuses in the data sheet:
"WDTEN: Watchdog Timer Enable bit
1 = WDT enabled
0 = WDT disabled (control is placed on the SWDTEN bit)"
So the watchdog has to be disabled, for control in software.
However prescaler is in the fuses.
So:
Code: |
#include <18F2550.h>
#fuses NOWDT, WDT128 //Plus your clock settings etc..
//clock definitions etc here
#define USB_CON_SENSE_PIN PIN_B0
//Then the USB includes
#include <stdlib.h>
#define __USB_PIC_PERIF__ 1
#include <usb_cdc.h>
void main(void) {
SETUP_ADC(ADC_CLOCK_INTERNAL); //internal clock
//Are you really using this - are you aware of the accuracy limitations
//DATA sheet table 21-1 Note 3
SETUP_ADC_PORTS(AN0_TO_AN3); //AN0->AN3
delay_ms(100);
ds1307_init();
init_ext_eeprom();
// Initialize USB CDC (this sets line coding and clears buffers).
usb_cdc_init();
usb_init_cs(); //I've also tried usb_init() but no luck
delay_ms(1000);
output_high(PIN_B5); //Power up the RTC
output_high(PIN_B4); //Power up the EEPROM
while(true){
// Sense USB status.
if (usb_attached) {
usb_task();
if (usb_enumerated()) {
output_low(pin_B6);
output_high(pin_B5);
// Get_Data();
if(usb_cdc_kbhit()){
getItem();
showSub();
//Question at this point. Do these routines take longer than
//about 10mSec total?. usb_task _must_ be called regularly
}
}
}
else {
//Suspend code
output_low(pin_B5);
output_high(pin_B6);
//Put the PIC to sleep if no USB connection
restart_wdt();
setup_wdt(wdt_on);
disable_interrupts(global);
enable_interrupts(INT_EXT);
ext_int_edge(L_TO_H);
clear_interrupt(INT_EXT);
//Final check USB is not attached
if (!usb_attached()) {
sleep();
delay_cycles(1);
}
disable_interrupts(INT_EXT);
setup_wdt(WDT_OFF);
enable_interrupts(GLOBAL);
}
}
}
|
The key problem is that you need to wake ASAP if USB is attached. You _need_ the sense pin, and to generate a hardware interrupt when this goes true.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9173 Location: Greensville,Ontario
|
|
Posted: Tue Mar 06, 2012 6:28 am |
|
|
Hmm. Battery powered datalogger with USB...ok..
1) How much power are you actually using ? My 4550 version draws next to nothing on the 'reality scale' except when flashdrive is writing. Microchip has a great appnote about battey powered loggers (old but valid today). I use 4 high capacity Li-I batteries and should get years of continuous use.
You may not actually 'need' the make the PIC go to sleep.
2) "output_high(PIN_B5); //Power up the RTC "
I have to ask why ? Can we infer the RTC doesn't have battery backup and that the RTC doesn't really keep real time ?
3) Are you running 5 volt or 3 volt. Going 3 reduces power consumed but you can't go as fast. Clock speed ? Slower saves power. |
|
![](templates/subSilver/images/spacer.gif) |
Can
Joined: 26 Feb 2012 Posts: 23
|
|
Posted: Wed Mar 07, 2012 2:06 pm |
|
|
I am really sorry about the late reply, I forgot my codes at my workplace so I couldn't try anything
After your heads up, I measured the current consumption and it is like 50 mA. So i suppose with 3000 mAH batteries I can run 60 hours approximately?
"output_high(PIN_B5); //Power up the RTC " was a setup for reducing power consumption. Because the EEPROM, RTC and PIC is going to be running on the same power source. So there is no need for the EEPROM and RTC to be powered if the PIC is sleeping.
I am using 4x1,5 batteries passing through a 5 V regulator for the PIC. So it can run on batteries as well as USB power.
As for the clock speed I use
#use delay(clock=48000000).
As the Murphy laws kicked in in every single opportunity, I am not tampering with the code that is running too much.
I haven't tried the putting to sleep and waking up the PIC yet. I will inform as soon as I try.
Thank you. |
|
![](templates/subSilver/images/spacer.gif) |
Can
Joined: 26 Feb 2012 Posts: 23
|
|
Posted: Wed Mar 07, 2012 3:18 pm |
|
|
Well I mostly tried the sleep and wake up part.
My final code is like the following:
Code: |
#include <18F2550.h>
#DEVICE ADC=8
#fuses HSPLL,NOWDT,WDT4096,MCLR,NOPROTECT,NOLVP,NODEBUG,NOBROWNOUT,USBDIV,PLL5,CPUDIV1,VREGEN
#use delay(clock=48000000)
#define USB_CON_SENSE_PIN PIN_B2 //Because B0 and B1 are for SDA and SCL
#include "usb_cdc.h"
void main(){
SETUP_ADC(0x07); //Seems like I am using this and I couldn't figure out the accuracy limitation?! Man I suck at reading datasheet, my table 21-1 only has 2 notes.. Tad vs. device operating frequencies
SETUP_ADC_PORTS(0x0B); //AN0->AN3
delay_ms(100);
ds1307_init();
init_ext_eeprom();
// Initialize USB CDC (this sets line coding and clears buffers).
usb_cdc_init();
// Initialize USB subsystem.
// Since we are not using sense pin, this will not wait indefinitely.
usb_init_cs();
delay_ms(1000);
while(true){
usb_task();
if(usb_attached()){
if(usb_enumerated()){
// Get_Data();
if(usb_cdc_kbhit()){
getItem(); //Actually getItem receives an input from the user via the terminal but I don't have problems while using it
showSub();
}
}
output_high(pin_B6);
} else {
output_low(pin_B6);
//Suspend code
//Put the PIC to sleep if no USB connection
restart_wdt();
setup_wdt(wdt_on);
disable_interrupts(global);
enable_interrupts(INT_EXT);
ext_int_edge(L_TO_H);
clear_interrupt(INT_EXT);
//Final check USB is not attached
if (!usb_attached()) {
output_low(pin_b5);
sleep();
delay_cycles(1);
}
usb_task();
output_high(pin_b5);
disable_interrupts(INT_EXT);
setup_wdt(WDT_OFF);
enable_interrupts(GLOBAL);
}
}
}
|
The code puts PIC to sleep (with 4.5 mA of power consumption) and wakes it up every once in a while. However I couldn't figure out how to wake the PIC up on USB connect. I had to put the usb sense pin to B2 because B0 and B1 are already occupied. With this code I have to wait for PIC to wake up in order to have a usb connection. |
|
![](templates/subSilver/images/spacer.gif) |
Can
Joined: 26 Feb 2012 Posts: 23
|
|
Posted: Fri Mar 09, 2012 1:46 am |
|
|
I've managed to write data to the EEPROM after sleeping through WDT128. Data seems ok and there is no problem. When I try WDT32768, the PIC wakes up like every minute, writes some data and goes back to sleep, however when I look at the data, it is all nonsense gibberish. The readings from the RTC gets messed up, they are giving data like 197/89/52;12:06:53; 02/56/89;09:03:12; and 02/34/89;07:25:04.
I tried putting a ds1307_init(); after the sleep but no luck. Also I saw that there was data missing in my all-night test. So I thought after a sleep that long, the EEPROM and RTC needs to be initialized again. I put initialize commands after sleep but they caused more problems...What am I missing here? |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19366
|
|
Posted: Fri Mar 09, 2012 2:27 am |
|
|
To wake on B2, you need to use INT_EXT2_L2H, instead of INT_EXT.
Also get rid of the int edge setting.
How is the 1307 connected and powered?.
You show power being disconnected from the DS1307 - "Power up the RTC ".
What battery voltage are you using on the sustain battery (there can be problems if this is not in the range the chips requires).
4.5mA!... That is foul, Seriously I'd be expecting _uA_ sleep currents. You have something in your circuitry drawing power that should not be drawn. Key things are:
1) Ensure every line on the PIC is driven to the state which draws least power. Either by the chip itself (driving them as outputs), or by external circuitry (chips or resistors). Lines that float _will_ cause excess power to be drawn.
2) Make sure you are genuinely switching off the external parts when you sleep.
3) How is your supply generated?. A lot of traditional 5v regulators, have minimum consumptions that are very significant when asleep. Even worse, some can start oscillating when loads are low.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
Can
Joined: 26 Feb 2012 Posts: 23
|
|
Posted: Fri Mar 09, 2012 2:57 am |
|
|
I tried the configuration disconnecting the RTC and EEPROM but the power consumption was almost the same, so the RTC and EEPROM are connected to the regulator directly. I am using a 7805 as a regulator, I suppose some of the consumption is caused by that.
I suppose the pins for which I haven't defined the tris register stay floating. I will set them as outputs and see how it affects the consumption.
Best, |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19366
|
|
Posted: Fri Mar 09, 2012 3:14 am |
|
|
Seriously, _most_ of your consumption is from the 7805. This is not the regulator to use for low power applications. You want something like the LM2936 as a 'drop in' replacement for this (assuming 100mA is OK). The consumption of a 7805, with an output load under 5mA, is quoted as 6mA typical. It has 0.5mA quiescent, _once the load rises over 5mA_, but below this the current does not significantly drop. The 78L05 (100mA version), has 3 to 5mA typical quiescent as well....).
On the RTC, what battery are you using?. This _needs_ to be present, and the chip needs to have it's supply removed. It draws typically 1.5mA if left running, with the I2C bus still active (which means data could be corrupted), while switched off, the consumption drops to under 1uA.....
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
|