View previous topic :: View next topic |
Author |
Message |
hansknec
Joined: 30 Sep 2004 Posts: 25 Location: Virginia, USA
|
Sleep_ulpwu() |
Posted: Wed Jan 02, 2008 10:48 am |
|
|
Can someone provide me with some insight as to what the Sleep_ulpwu() does differently than sleep()?
I ask this because my complier version is 3.249 and doesn't have the function. I spent several days over the holiday trying to get my PIC12F635 to sleep and wake using the ULPWU module, but nothing seemed to work. I have no code to post because I was on a different computer and had no internet access (Yikes!). I was trying to follow all recommendations in the datasheet, but of course their example is in assembly and assumed proper mapping of the registers.
Since ULPWU was not addressed in my compiler version I found myself directly writing to registers that were not defined in the include file. I also do not understand how to interpret the address of the INTCON register. The datasheet tells me that INTCON address is 0Bh/8Bh. Is this a high byte / low byte deal?
Perhaps someone has a working example of using the ULPWU module in an earlier complier version that did not use sleep_ulpwu()?
Thanks,
John |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jan 02, 2008 12:10 pm |
|
|
The easiest way to answer this is to show you the .LST file output
for vs. 4.064 and then you can use that as a guide to write your
own function for your version of the compiler. When you write
your code, compile it, and compare the .LST file to the one below.
Make sure that it's effectively doing the same thing.
Code: |
#include <12F635.h>
#fuses XT, NOWDT, NOMCLR, PUT, BROWNOUT
#use delay(clock=4000000)
//===========================
void main()
{
sleep_ulpwu(10);
while(1);
} |
Here's the .LST file code for that program.
Code: | .................... void main()
.................... {
0004: CLRF 04
0005: MOVLW 1F
0006: ANDWF 03,F
0007: CLRF 1A
0008: MOVLW 07
0009: MOVWF 19
....................
.................... sleep_ulpwu(10);
000A: MOVF 19,W
000B: MOVWF 40
000C: MOVLW 07
000D: MOVWF 19
000E: BSF 03.5
000F: BCF 1F.0
0010: BCF 05.0
0011: BCF 03.5
0012: BSF 05.0
0013: BSF 03.5
0014: BSF 05.0
0015: BCF 03.5
0016: BCF 0D.2
0017: MOVLW 03
0018: MOVWF 40
0019: DECFSZ 40,F
001A: GOTO 019
001B: BSF 03.5
001C: BSF 0E.5
001D: BCF 0D.2
001E: BSF 16.0
001F: BCF 03.5
0020: MOVF 0B,W
0021: MOVWF 41
0022: MOVLW 08
0023: MOVWF 0B
0024: SLEEP
0025: MOVF 41,W
0026: MOVWF 0B
0027: MOVF 40,W
0028: MOVWF 19
....................
.................... while(1);
0029: GOTO 029
.................... }
|
Same thing, but in Symbolic format:
Code: | .................... void main()
.................... {
0004: CLRF FSR
0005: MOVLW 1F
0006: ANDWF STATUS,F
0007: CLRF CMCON1
0008: MOVLW 07
0009: MOVWF CMCON0
....................
.................... sleep_ulpwu(10);
000A: MOVF CMCON0,W
000B: MOVWF @40
000C: MOVLW 07
000D: MOVWF CMCON0
000E: BSF STATUS.RP0
000F: BCF 09F.0
0010: BCF TRISO.TRISIO0
0011: BCF STATUS.RP0
0012: BSF GPIO.GP0
0013: BSF STATUS.RP0
0014: BSF TRISO.TRISIO0
0015: BCF STATUS.RP0
0016: BCF 00D.2
0017: MOVLW 03
0018: MOVWF @40
0019: DECFSZ @40,F
001A: GOTO 019
001B: BSF STATUS.RP0
001C: BSF PCON.ULPWUE
001D: BCF 08D.2
001E: BSF IOCA.IOCA0
001F: BCF STATUS.RP0
0020: MOVF INTCON,W
0021: MOVWF @41
0022: MOVLW 08
0023: MOVWF INTCON
0024: SLEEP
0025: MOVF @41,W
0026: MOVWF INTCON
0027: MOVF @40,W
0028: MOVWF CMCON0
....................
.................... while(1);
0029: GOTO 029
.................... } |
|
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Wed Jan 02, 2008 12:15 pm |
|
|
Quote: | Can someone provide me with some insight as to what the Sleep_ulpwu() does differently than sleep()? | Which part did you not understand from reading the manual? Even when you have v3.249, the latest manual is free for download from the CCS website.
Quote: | I also do not understand how to interpret the address of the INTCON register. The datasheet tells me that INTCON address is 0Bh/8Bh. Is this a high byte / low byte deal? | The PIC12 and PIC16 processors have the RAM addresses divided into banks of 0x80 bytes. Switching from one bank to the other takes a few instructions and because the INTCON register is used so often Microchip has decided to duplicate (mirror) the same register in both memory banks. So using either of the two mentioned addresses you are accessing exactly the same physical register. |
|
|
Humberto
Joined: 08 Sep 2003 Posts: 1215 Location: Buenos Aires, La Reina del Plata
|
|
Posted: Wed Jan 02, 2008 12:16 pm |
|
|
Quote: |
Can someone provide me with some insight as to what the Sleep_ulpwu() does differently than sleep()?
|
From:
http://www.ccsinfo.com/content.php?page=v4compiler
sleep_ulpwu(us) - Sets the ultra-low power wakeup pin high for the set micro-seconds (which will charge the user's capacitor), then put's the PIC® MCU to sleep. When the capacitor has discharged, the PIC® MCU will awaken (this time is determined by the user's RC time constant). Requires a PIC® MCU with the ultra-low power wakeup feature (see the GP0 on the PIC12F683).
Humberto |
|
|
hansknec
Joined: 30 Sep 2004 Posts: 25 Location: Virginia, USA
|
|
Posted: Wed Jan 02, 2008 12:24 pm |
|
|
Thanks all.
I didn't know I could access the latest manual, and that .LST file will be great for double checking my register assignments.
I'll give it another shot with this new info. |
|
|
hansknec
Joined: 30 Sep 2004 Posts: 25 Location: Virginia, USA
|
|
Posted: Wed Jan 02, 2008 12:39 pm |
|
|
So now I can see that:
sleep_ulpwu(10);
is exactly the same as:
output_high(PIN_A1);
delay_us(10); // charge cap for 10us
code to make A1 an input, enable the ULPWU bit, and enable the interrupt.
sleep(); |
|
|
hansknec
Joined: 30 Sep 2004 Posts: 25 Location: Virginia, USA
|
sleep_ulpwu problems. |
Posted: Wed Apr 30, 2008 8:02 pm |
|
|
I have a problem with the new sleep_ulpwu command.
Compiler version=PCWHD 4.071
I wrote the following code before getting an upgraded compiler that had the sleep_ulpwu command:
Code: | #include <12F635.h>
#FUSES NOMCLR,NOWDT,NOBROWNOUT,INTRC_IO
#use delay(clock=8000000)
#BIT ULPWU = 0x8E.5 // PCON bit 5 enables the ULPWU
#BYTE INTCON = 0x8b // entire INTCON register
#BYTE PIR1 = 0x0c // Peripheral interrupt flags (0 to clear)
#BIT WOC1 = 0x8b.1 // Wake up on change interrupt flag (0 to clear)
#BIT IOC0 = 0x96.0 // interrupt on change for pin A0 (1 to set)
#INT_DEFAULT // interrupt service routine for ULPWU sleep module
void isr_DEFAULT() {
PIR1 = 0; //clear the peripheral interrupt flags
WOC1 = 0; //clear the wake on change interrupt flag
}
void main() {
setup_comparator(NC_NC);
setup_vref(FALSE);
setup_oscillator(OSC_8MHZ);
while (1){
output_high(PIN_A4); // pulse high to show wakeup
delay_ms(4); // wait 4ms
output_low(PIN_A4); // back low
// begin setup of ULPWU module using a manual configuration
output_high(PIN_A0); // high on A1 to charge the cap
delay_us(10); // let it charge
set_tris_A(1); // Set all port A to inputs (high Z)
ULPWU = 1; // remember ULPWU = 0x8E.5 (PCON bit 5)
IOC0 = 1; // enable interrupt on change for pin A0
INTCON = 0b00001000; // enable the PortA change interrupt
sleep();
}
} |
I'm not quite sure if I handled the interrupt properly, but at least it worked. With .1uf cap and 100 ohms on A0 it would sleep for a couple seconds then wake up and pulse pin A4 to show the wakeup. I'm using the ULPWU for minimum current consumption in a project. So far so good.
Now, I got the new compiler that has the sleep_ulpwu function and here is my test code:
Code: | #include <12F635.h>
#FUSES NOMCLR,NOWDT,NOBROWNOUT,INTRC_IO
#use delay(clock=8000000)
void main() {
setup_comparator(NC_NC);
setup_vref(FALSE);
setup_oscillator(OSC_8MHZ);
while (1){
output_high(PIN_A4); // pulse high to show wakeup
delay_ms(4); // wait 4ms
output_low(PIN_A4); // back low
sleep_ulpwu(10); // Use the fancy new ulpwu command
}
} |
Note that everything is the same but I am using the new fancy sleep command. It should give me the same timing since in both cases I have commanded a 10us cap charge time, but when I run this code it only sleeps for 120 ms. Adding capacitance does nothing, when it should increase the sleep time. It is as if something else has overtaken the timing and wakes it every 120ms, because if increase my resistance, I can make it wake at a faster rate.
Any ideas? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu May 01, 2008 1:08 pm |
|
|
The sleep_ulpwu() code is buggy for the 12F635 with vs. 4.071.
You should report this to CCS support. See the comments in
the code below.
Code: |
.................... sleep_ulpwu(10);
003E: MOVF 19,W // Save CMCON0 register
003F: MOVWF 40
0040: MOVLW 07 // Then disable the comparator
0041: MOVWF 19
// This is a bug because there is no register at 0x9F
// on the 12F635. It's a bug but it's harmless here.
0042: BSF 03.5 // Bank 1
0043: BCF 1F.0 // Clear 0x9F.0 *** BUG ***
0044: BCF 05.0 // TRISIO.0 (pin A0) = output
0045: BCF 03.5 // Bank 0
0046: BSF 05.0 // Set Pin A0 = 1 to charge the cap
// This is a bug because pin A0 should not
// be set back to an input pin until after
// the 10 us delay, when the capacitor has
// been charged up. This code should really
// be placed below the 10 us delay routine
// that you can see a few lines below this point.
0047: BSF 03.5 // Bank 1
0048: BSF 05.0 // Set pin A0 = input *** BUG ***
// This is a bug because there is no register at 0x0D.
// on the 12F635. This code is applicable to the
// 16F887. It clears the ULPWUIF bit on those PICs.
// It's a bug to have this code in here for the 12F635,
// but it's harmless.
0049: BCF 03.5 // Bank 0
004A: BCF 0D.2 // Clear 0x0D.2 *** BUG ***
// 10 us delay
004B: MOVLW 06
004C: MOVWF 40
004D: DECFSZ 40,F
004E: GOTO 04D
004F: NOP
0050: BSF 03.5 // Bank 1
0051: BSF 0E.5 // PCON.ULPWUE bit = 1 to enable wakeup
// This is a bug because there is no register at 0x8D.
// on the 12F635. This code is applicable to the
// 16F887. It clears the ULPWUIE bit on those PICs.
// Actually, according to the 16F887 data sheet, it
// should set that bit, not clear it.
// It's a bug to have this code in here, but it's
// harmless for the 12F635.
0052: BCF 0D.2 // Clear 0x8D.2 *** BUG ***
0053: BSF 16.0 // ICOA.0 = 1, enable interrupt on A0
0054: BCF 03.5 // Bank 0
0055: MOVF 0B,W // Save INTCON register
0056: MOVWF 41
0057: MOVLW 08 // Enable PortA interrupts
0058: MOVWF 0B
0059: SLEEP
005A: MOVF 41,W // Restore INTCON
005B: MOVWF 0B
005C: MOVF 40,W // Restore CMCON0
005D: MOVWF 19
.................... }
005E: BSF 03.5
005F: GOTO 034 |
|
|
|
hansknec
Joined: 30 Sep 2004 Posts: 25 Location: Virginia, USA
|
|
Posted: Thu May 01, 2008 1:25 pm |
|
|
Wow! That's quite a few bugs! Thanks! We will report it to CCS. I guess I'll stick to my manual coding for now. I was hoping the new compiler would work for me because I was running into difficulty when trying to use the ULPWU and the int_ext. I need the PIC to wake on ULPWU and also if I see a change on my external interrupt pin. I know I'm not handling my interrupt service routines properly, but I haven't worked my way through it. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu May 01, 2008 1:32 pm |
|
|
CCS will probably fix it in the next release. If your maintenance has
run out before then, I think they will let you download the fixed version.
Make sure you give them your user reference number when you report
the bug. |
|
|
starbuck
Joined: 21 Jan 2009 Posts: 6
|
ULPWU_sleep on 16F886 |
Posted: Wed Jan 21, 2009 1:48 am |
|
|
I have been trying to get the ULPWU_sleep command to work on a 16F886 device. I have a 0.1uf cap in parallel with a 15K resistor and in series with a 200 ohm resistor attached to RA0. I have not been able to get the circuit to reliably trigger. I can see the cap being charged for a few cycles after startup using a scope, but then MPLAB and Real Ice report an error and stop execution after a few what appear to be randomly timed cycles.
The following is the code that I am trying to get to work. Eventually, I would like to have the ULPWU timer trigger an interrupt where I can check the state of a input and then either stop the ULPWU and go on with the rest of the code or reset the ULPWU_ sleep and go back to sleep for a few milliseconds until I am ready to check the input again.
Code: | #use delay ( clock = 20 000 000 )
//#use fast_io(a)
#use fast_io(b)
#use fast_io(c)
//#fuses HS,NOWDT,NOPROTECT,BROWNOUT,NOPUT,NOLVP,NOCPD,NOWRT
#fuses HS
#zero_ram
void main() {
set_tris_c(0x14); // C2 and C4 are Inputs, other pins are outputs
setup_vref(FALSE);
setup_adc_ports(NO_ANALOGS);
// all pins digital
setup_comparator(sAN0);
//a0 IS analog comparator input
//true when comparator output is high
while (1){
output_high(PIN_C1); // pulse high to show wakeup
delay_ms(4); // wait 4ms
output_low(PIN_C1); // back low
sleep_ulpwu(10); // Use the ulpwu command
}
} |
|
|
|
hansknec
Joined: 30 Sep 2004 Posts: 25 Location: Virginia, USA
|
|
Posted: Wed Jan 21, 2009 8:39 am |
|
|
I wish I could help, but I never did get the new "sleep_ulpwu()" function to work on my chip. I used the manual coding that I showed earlier in this thread and it works fine. Perhaps CCS has released an upgrade that fixes the function, because there were known bugs when I was playing with it. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jan 21, 2009 2:47 pm |
|
|
The ASM code generated for sleep_ulpwu() for the 16F886 is buggy.
I checked it for vs. 4.084. It has many of the same bugs as I reported
above. I don't know if this ever got reported to CCS. I'll write up the
bugs and send them into CCS support. |
|
|
starbuck
Joined: 21 Jan 2009 Posts: 6
|
|
Posted: Mon Jan 26, 2009 7:43 pm |
|
|
Here is my cut at the ULPWU for the 16F886, it is not optimized but it does work and my provide someone else with a starting point.
Code: | #include <16F886.h>
#device ICD = TRUE
#device *=16 ADC=8
#fuses HS,WDT,NOPROTECT,BROWNOUT,PUT,NOLVP,NOCPD,NOWRT
#use delay( clock=20 000 000, restart_wdt )
#bit ULPWUIF = 0x0D.2 // PIR2 bit 2 ULPWUIF: Ultra Low-Power Wake-up Interrupt Flag bit
// 1 = Wake-up condition has occurred (must be cleared in software)
// 0 = No Wake-up condition has occurred
#bit ULPWUE = 0x8E.5 // PCON bit 5 bit 5 ULPWUE: Ultra Low-Power Wake-up Enable bit
// 1 = Ultra Low-Power Wake-up enabled
// 0 = Ultra Low-Power Wake-up disabled
#BIT ULPWUIE = 0x8D.2 // PIE2 bit 2 ULPWUIE: Ultra Low-Power Wake-up Interrupt Enable bit
// 1 = Enables Ultra Low-Power Wake-up interrupt
// 0 = Disables Ultra Low-Power Wake-up interrupt
#BYTE INTCON = 0x8B // entire INTCON register
#BYTE PIR1 = 0x0c // Peripheral interrupt flags (0 to clear)
#BIT WOC1 = 0x8b.1 // Wake up on change interrupt flag (0 to clear)
#BIT IOC0 = 0x96.0 // interrupt on change for pin A0 (1 to set)
#INT_ULPWU // Ultra-low power wake up interrupt
// interrupt service routine for ULPWU sleep module
void isr_ULPWU() {
disable_interrupts(INT_ULPWU);
// ULPWUE = 0; // Disable Ultra Low-Power Wake-up interrupt
ULPWUIF = 0; //clear the peripheral interrupt flags
// ULPWUIE = 0; //clear the wake on change interrupt flag
// enable_interrupts(INT_ULPWU);
}
void main() {
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
disable_interrupts(INT_ULPWU);
enable_interrupts(GLOBAL);
while (1){
output_high(PIN_B5); // pulse high to show wakeup
delay_ms(4); // wait 4ms
output_low(PIN_B5); // back low
// begin setup of ULPWU module using a manual configuration
set_tris_A(0b00000000); // Set all port A0 to output
output_high(PIN_A0); // high on A0 to charge the cap
delay_us(50); // let it charge
set_tris_A(0b00000001); // Set all port A0 to input (high Z)
ULPWUIF = 0; // Clear the Ultra Low-Power Wake-up Interrupt Flag bit
ULPWUE = 1; // Enable Ultra Low-Power Wake-up interrupt on change for pin A0
ULPWUIE = 1; // Enable Ultra Low-Power Wake-up Interrupt Enable bit
enable_interrupts(INT_ULPWU);
sleep();
}
} |
|
|
|
|