PDA

View Full Version : Nap and sleep commands



rusty99
- 6th August 2010, 06:16
I have a project that is running a 16f689 off batteries, therefore iam trying to keep battery consumption to and absolute minimum. Using internal osc @ 8 mhz

i am currently using PBP sleep comand to put the micro to sleep and then wake up either after an interupt or the sleep period expiring. this works well and just as i expect. Trying to minimise my current consumption further i need to do another function that basicly flashes a led on for 50ms then off again aprox every second.

I tried the code using "sleep 1" i.e flash the led then sleep for 1 second, however the granularity of the sleep command means my led flashes once every 2.3 seconds. to bring this time down closer to the 1 second mark i have tried to substitute "sleep 1" with "Nap 6" . This is where my problems begin. with the nap command the interupts or the nap time seem to go haywire, as the program wont come out of nap.. I have read that the period of nap sets the prescaler for the WDT , do i need to change some osc settings to get this to work correctly ? Is there a way to make sleep - sleep for less than 1 sec, time dosent need to be exact just less than what it is now.. thats what i thought Nap would do...

mackrackit
- 6th August 2010, 13:41
This was about a different chip but it should help with NAPing.

http://www.picbasic.co.uk/forum/showthread.php?t=10203&page=1

Bruce
- 6th August 2010, 17:10
The watchdog timer runs on the internal 31kHz oscillator so it doesn't matter what oscillator speed the CPU runs at.

This PIC also has a WDTCON register you use to set the WDT period with. Take 1/31kHz (0.000032258) and multiply this times the prescaler value in WDTCON for the WDT time period.

If you insert WDTCON = %00010101 this sets bit 0, which enables the WDT, and loads a prescale vaule of 1:32768. This gives you 32768 * 0.000032258 for about a 1.057 second wakeup period.

This PIC allows you to set WDT to off in config, and turn it on/off using bit 0 in WDTCON, so you get even better power savings. I.E. you can enable the WDT only when you need it, then disable it when you don't to save power.

This gives you much better power savings than using the PBP SLEEP command since it sleeps for the whole period, it doesn't wakeup & loop until the timeout period expires, and you only need to enable WDT just before you enter sleep mode.

Here's an example:


@ __CONFIG _FCMEN_OFF & _INTRC_OSC_NOCLKOUT & _WDT_OFF & _MCLRE_OFF & _CP_OFF & _IESO_OFF & _BOR_OFF & _PWRTE_OFF

DEFINE OSC 8
DEFINE NO_CLRWDT 1 ' PBP doesn't clear WDT automatically

LED VAR PORTB.6 ' LED on RB6
LED = 0 ' LED off at POR

TRISB.6 = 0 ' Make pin an output
OPTION_REG = %10001000 ' Pull-ups off, 1:1 prescaler to WDT
OSCCON = %01110000 ' 8MHz internal osc

Main:
HIGH LED ' Turn on LED
PAUSE 50 ' LED on for ~50mS
LOW LED ' LED off
CLEARWDT
WDTCON = %00010101 ' WDT enabled with a period of 32768 * (1/31kHz)
@ SLEEP ' for a sleep period of about 1.057 seconds
@ NOP ' Execute a NOP on WDT or interrupt wakeup
WDTCON = 0 ' Disable WDT when not needed for power savings.
' WDT is only turned on just before entering sleep
GOTO Main ' Loop forever

END
With brown-out reset and power-up timer disabled you save even more power, but check to make sure your application works properly with both these disabled.

rusty99
- 12th August 2010, 05:02
Thanks Bruce ,
with a little playing around got that to work the way i need it to. The only thing to do now then is that this program has 2 "sleep" modes .
1 that sleeps for 1 second which using code Bruce helped with works fine, but i had the other sleep mode which runns for around 8 hrs using a PBP "Sleep 28800" i.e sleep for 28800 seconds = 8 hrs . Obviously i am trying to save as much power during this sleep as possible, so rather than use the PBP sleep command is there a more efficent way of doing this long sleep using ASM Sleep, do i have to set my watchdog prescaler for as big as it goes and count how many times it wakes up ? i belive the largest prescale time i can set is 65536 which would equate to 2.11 seconds , dosent seem logical to have it wake up every 2 seconds advance a counter then sleep again..
Am i better off just using the PBP sleep ? or am i missing something ?

Bruce
- 12th August 2010, 13:47
i need to do another function that basicly flashes a led on for 50ms then off again aprox every second.

This is what the code example above does.

If you need it to sleep longer just set the prescaler for the watchdog timeout period in WDTCON to 65536, then set the 2nd prescaler in OPTION_REG to 1:128.

Then it will sleep a lot longer, but it's not going to be able to blink your LED every 1 second. It will be sleeping for the entire 270 second period. If you need even longer, then you could let it sleep for ~270 seconds, wakeup, increment a variable, then go back to sleep.

FinchPJ
- 20th August 2010, 20:11
I am also trying to minimise power consumption on a 18F4550 which connects to a PC via USB, but for >24 hours I need it to sample the ADC and store to external I2C memory with lowest current on battery only (USB disconnected)- present setup uses 42 mA and only lasts 9 hours - not enough - I have tried to adapt your answer for the 18F4550:

Development:
DEFINE NO_CLRWDT 1
lcdout $FE, $C0, "USB Low Power "

T0CON.7 = 0 ' Disable USBservice interrupts TMR1 still running @ 25 Hz
' UCON.1 = 1 'UCON not defined in PBP 2.46
@ clrf UCON ; Disable USB & detach from bus
@ clrf UIE ; Mask all USB interrupts
@ movlw DETACHED_STATE
@ movwf usb_device_state

lowpower: IF dSecs = 1 THEN
dSecs = 0
lcdout $FE, $02, "Time ", dec2 Hours, ":", dec2 Minutes, ":", dec2 Seconds, " "
ENDIF
' Do all the other stuff here (read ADC, store to Mem)
CLEARWDT
'CONFIG2H = %00011111 ' WDT enabled with a period of 32768 * (1/31kHz) - PO default - cant access easily
WDTCON = 1
@ SLEEP ' for a sleep period of about 1.057 seconds
@ NOP ' Execute a NOP on WDT or interrupt wakeup
WDTCON = 0 ' Disable WDT when not needed for power savings.
goto lowpower
But no joy - sleeps but never wakes up!!!
I am (sadly) using PBP 2.46 (waiting for 2.60 to arrive) and am using DT_INTS with a 100 mSec interrupt to keep USBservice'd (on TMR0, turned off here) and a 40 mSec interrupt on TMR1 to update the clock (which I need))
I have tried using TMR1 to wake from sleep but no joy there either. OSC 48

Any help would seriously help my follicular challenge! TIA
Peter
ps I am running TMR1 at 25 Hz - the slowest I can go on the 18F4550 as max prescaler is 1:8 - Is this interfering with the WDT - I have never really got to grips with the WDT and I have read the manual but cant make head nor tail of it!

FinchPJ
- 20th August 2010, 23:01
Well, I carried on trying and reread the Datasheet - It states
The power-managed Sleep mode in the PIC18F2455/2550/4455/4550 devices is identical to the legacy Sleep mode offered in all other PIC devices. It is entered by clearing the IDLEN bit (the default state on device Reset) and executing the SLEEP instruction.
I tried making IDLEN = 0 which is what I understand by clearing it - no good, BUT making IDLEN = 1 does work - at least the RTC display is updated so the PIC must be coming out of sleep with Timer 1 and is sleeping (some) as the current consumption drops from 42 mA to 26 mA. Not sure it is definitely cracked but seems to be - now to try and eek out more power consumption. I would still value wiser PIC'ers opinion though?

Development:
lcdout $FE, $C0, "USB LP, SEC_IDLE"
T0CON.7 = 0 ' Disable USBservice interrupts
' UCON.1 = 1 ' UCON not defined in PBP 2.46
@ clrf UCON ; Disable USB & detach from bus
@ clrf UIE ; Mask all USB interrupts
lowpower: IF dSecs = 1 THEN
dSecs = 0
lcdout $FE, $02, "Time ", dec2 Hours, ":", dec2 Minutes, ":", dec2 Seconds, " "
ENDIF
OSCCON.7 = 1 '"Clear" IDLEN - Set surely?
@ SLEEP
@ NOP
goto lowpower
Any comments guys?

Bruce
- 20th August 2010, 23:13
WDT on the 4550 has a 4mS period. With the postscaler set to 32,768, you have about 2.18 minutes before it will wakeup.

Also Timer1/Timer0 will only operate from the internal clock during sleep if you're using a power managed mode that clocks peripherals while the CPU sleeps.

FinchPJ
- 20th August 2010, 23:29
OK - it IS late but I am now starting to understand the Datasheet - I am switching into an Idle state, not a sleep by using

OSCCON.7 = 1 'Set IDLEN - switch to SEC_IDLEif I use

OSCCON.7 = 0 'Clear IDLEN - switch to SLEEPthe PIC goes to sleep but wont wake up on Timer 1 interrupt. The consumption does drop to 15 mA.
Help please!!! How can I get Timer 1 to wake the Pic from sleep?

I am going to sleep now - hope my Timer 1 wakes me! My anaesthetist friends tell it is easy to put someone to sleep - the skill is in getting them to wake up afterwards - guess that is true of Pics too!

Peter

Bruce
- 20th August 2010, 23:35
If you don't want to use a power managed mode with peripherals clocked during sleep, use an external 32,768 watch crystal for Timer1.

FinchPJ
- 21st August 2010, 08:10
Thanks for your help Bruce - it has clarified my (mis)understanding - looks like an external Xtal for Timer 1 is the way to go.
BTW in case anyone is mislead by:

Also Timer1/Timer0 will only operate from the internal clock during sleep if you're using a power managed mode that clocks peripherals while the CPU sleeps into thinking Timer0 could be used to wake the 18F4550 from sleep, I noticed this in the datasheet:

Since Timer0 is shut down in Sleep mode, the TMR0 interrupt cannot awaken the processor from Sleep.
I would have preferred to use timer0 for my clock as I could get that down to 1 Hz with its 1:256 prescaler otherwise . I suppose this is probably also true of Timer1 (without external Xtal) and should have given me the answer Bruce so clearly gave!
Peter

Bruce
- 21st August 2010, 15:47
Sleep & Power managed modes can be a little confusing.

With IDLEN = 0 the SLEEP instruction shuts down everything except for the watchdog timer if it's enabled. This stops all internal clocks by stopping the main oscillator. The internal 31kHz that the WDT uses is still operating so the WDT can timeout and wake it from sleep.

PRI_RUN, SEC_RUN, and RC_RUN are the only 3 modes that don't require execution of the SLEEP command to enter.

These are selected by changing bits in the OSCCON register. These modes let you change the oscillator. SEC_RUN would switch to the oscillator on Timer1.

This keeps everything running, but on the lower power osc that's connected to the Timer1 osc pins.

RC_RUN switches to the internal RC oscillator. Both can consume less power than most external crystals. PRI_RUN operates from whatever oscillator you have selected in config.

The IDLE modes PRI_IDLE, SEC_IDLE, and RC_IDLE are entered by setting the IDLEN bit, then selecting the oscillator with OSCCON bits 1,0 then executing the SLEEP instruction. If you already have the oscillator selected for the idle mode you want, then just setting IDLEN before executing the SLEEP instruction is all that's required.

IDLE modes just put the CPU to sleep, but keep clocks available for all peripherals.

SEC_IDLE or RC_IDLE would normally be the lowest power options. It would run all peripherals from the LP oscillator on Timer1, or the internal RC oscillator "set for 31kHz".

Look in the Electrical Characteristics section of the datasheet under Power-Down and Supply Current for various modes & power consumption.

The key is the IDLEN bit. When this bit is clear, it doesn't matter what oscillator or mode is selected. The execution of a SLEEP instruction will shut everything down except for the WDT if enabled.

When the IDLEN bit is set, and the SLEEP instruction is executed, then it enters one of the 3 IDLE modes with the CPU shut down, and peripheral clocks provided by whatever osc you have selected in OSCCON bits 1,0.

FinchPJ
- 24th August 2010, 13:19
Thanks for all your help Bruce - this is a followup to report that an external 32 KHz crystal and two 33 pF caps have sorted my sleep problems - for the record this works a dream:

T1CON = %00001110 with a TMR1 interrupt (RTCupdate) of:

asm
TMR1Const = 8000h
ADD2_TMR1 macro
BCF T1CON,TMR1ON, 0 ; Timer OFF
MOVLW LOW(TMR1Const) ; +1
ADDWF TMR1L,F, 0 ; +1
BTFSC STATUS,C ; +1/2
INCF TMR1H,F, 0 ; +1
MOVLW HIGH(TMR1Const) ; +1
ADDWF TMR1H,F, 0 ; +1
endm
RELOAD_TMR1 macro
ADD2_TMR1
BSF T1CON,TMR1ON, 0 ; +1=7 cycles overhead before Timer ON
endm
LOAD_TMR1 macro
MOVE?CT 0, T1CON,TMR1ON
MOVE?CB 0, TMR1L
MOVE?CB 0, TMR1H
ADD2_TMR1
endm
endasm
RTCupdate:
@ RELOAD_TMR1
Seconds = Seconds + 1
dSecs = 1
if (Seconds < 60) then IHdone
Minutes = Minutes + 1
Seconds = 0
if (Minutes < 60) then IHdone
Hours = Hours + 1
Minutes = 0
if (Hours < 24) then IHdone
Days = Days + 1
Hours = 0
IHdone: 'Restore context and RETFIE
@ INT_RETURN
and a sleep inducing routine of:

gosleep:
lcdout $FE, $C0, "USB LP, SLEEP "
T0CON.7 = 0 ' Disable USBservice interrupts
@ INT_DISABLE TMR0_INT
@ clrf UCON ; Disable USB & detach from bus
@ clrf UIE ; Mask all USB interrupts
lowpower: IF dSecs = 1 THEN
dSecs = 0
lcdout $FE, $02, "Time ", dec2 Hours, ":", dec2 Minutes, ":", dec2 Seconds, " "
ENDIF
OSCCON.7 = 0 'Clear IDLEN - switch to SLEEP
@ SLEEP
@ NOP
goto lowpower
Peter

FinchPJ
- 25th August 2010, 21:26
Since our production circuit board has been professionally produced, there is not room for an extra Xtal and caps to drive TMR1 so I am trying to get the WDT to do the wake from sleep but with only partial success. In particular it doesnt seem to matter what I put as a postscaler value the WDT seems to cycle at a fixed period of around 578 mSec (suspiciously similar to Nap 5 frequency!). I am setting CONFIG2H by using this instead of the corresponding (commented out) line in 18F4550.INC:

asm
__CONFIG _CONFIG2H, _WDT_OFF_2H & _WDTPS_256_2H
;must comment out in 18F4550.INC, or change there, else duplicate error
endasmand then:

i = 0
lowpower: lcdout $FE, $02, "WDT ", hex2 i,
i = i + 1
' Do all the other stuff here (read ADC, store to Mem)
clearwdt
WDTCON = 1 'SWDTEN
' OSCCON.7 = 0 'Clear IDLEN - switch to SLEEP
OSCCON.7 = 1 'Set IDLEN - switch to SEC_IDLE
@ SLEEP
@ NOP
WDTCON = 0 ' WDT off
goto lowpowerand i increments 128 in 74 secs (period = 578mSec), but different values of _WDTPS_1024_2H etc. make no difference. What am I missing here? It makes no difference whether I make the CPU sleep or idle (except to the current consumption 3 or 15 mA - most of the 3 lost in the 9v voltage regulator).
DEFINE NO_CLRWDT 1 makes no difference and the CLEARWDT also seems to make no difference!

I would like to have the ability to control the frequency as expected and am thinking I can sleep for most of the 1 second I want and fine tune with another timer while awake - PAUSE would be the simplest. Any ideas gratefully received!

Peter

PS It just occurs to me that I am using a Bootloader - could this mean that the Postscaler is set by the bootloader and not changed by my program - if so can I do anything to change this ??edit the bootloader somehow.

Bruce
- 26th August 2010, 19:05
Most bootloaders will not allow you to change config settings, but the Microchip USB loader will, or you can change WDT config settings at runtime.

See these threads:

http://www.picbasic.co.uk/forum/showthread.php?t=4093

http://www.picbasic.co.uk/forum/showthread.php?t=4363&highlight=config

Or just open the loader .HEX file, make your changes, save it, and reprogram the PIC with the new loader firmware.

FinchPJ
- 27th August 2010, 08:16
http://www.picbasic.co.uk/forum/showthread.php?t=4093

http://www.picbasic.co.uk/forum/showthread.php?t=4363&highlight=config


Now that is seriously helpful - Sorry I didnt spot those earlier on my searches - thank you so much for your help Bruce (and Darrel) - you are amazing!

Peter