View previous topic :: View next topic |
Author |
Message |
heUAcyp
Joined: 16 Mar 2011 Posts: 33
|
Deep Sleep wake up on INT0 ! |
Posted: Sun Jun 05, 2011 7:37 am |
|
|
Hi all,
I want to control the deep sleep mode in the while(TRUE) loop. I am using:
PIC 18F25J11 ,
Compiler Version V 4.095
Basically , my PIC will keep RTCC while in deep sleep, then wake-up on a voltage change in pin 21(INT0) do some operation than will go back to sleep.
Before all I want to learn how to control deep sleep operation. I want my PIC to be in deep sleep mode, wake- up when I apply an external voltage at pin 21 (INT0) , light up LED connected at pin 3(A1) , then go back to sleep ( led should be turned off).
There is a problem in the code:
Code: | #include <18F25J11.h>
#device ADC=10
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#byte WDTCON = 0xFC0
#byte DSCONH = 0xF4D
#byte DSCONL = 0xF4C
#byte RTCCFG = 0xF3F
#byte DSWAKEH= 0xF4b
#byte DSWAKEL= 0xF4a
#byte OSCCON = 0xFD3
#byte INTCON = 0xFF2
//
#bit IDLEN=OSCCON.7 // used to set IDLE low-power mode ( will be set to zero for both deep-sleep and sleep modes)
#bit DSEN = DSCONH.7 // used to set deep sleep (1 for deep-sleep)
#bit REGSLP =WDTCON.7
#bit RELEASE = DSCONL.0
#bit RTCSYNC = RTCCFG.4
#bit DSINT0 = DSWAKEH.0 // bit for INT0 interrupt - change detection
//#bit DS_WAKEUP_BIT = WDTCON.3 // bit that detects wake up from deep sleep
#bit INT0IE = INTCON.4
#fuses HS,NOWDT,NOPROTECT
#use delay(clock=2000000)
void main()
{
enable_interrupts(GLOBAL);
INT0IE = 1 ; //enables INT0 Interrupt (for change detection)
while(TRUE)
{
//****************
//Entering Deep Sleep Mode
//****************
DSINT0 = 1 ; // Wake up when a change is detected at pin 21 (INT0)
REGSLP = 1 ; // On-chip regulator enters low-power operation when device enters Sleep mode
IDLEN = 0;// enable deep sleep
DSEN = 1;// Note: must be set just before executing Sleep();
Sleep();
//
RELEASE = 0;
output_high(PIN_A1) ;
delay_ms(2000) ;
REGSLP = 1 ;
IDLEN = 0;
DSEN = 1;
Sleep();
}
} |
will be glad if anyone can respond.
Regards |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Sun Jun 05, 2011 12:44 pm |
|
|
Unless I missed something obvious, you didn't report an actual problem observed with your code.ยด
I would however expect an instruction to turn of the LED and a single sleep() instruction rather than two. |
|
|
heUAcyp
Joined: 16 Mar 2011 Posts: 33
|
|
Posted: Sun Jun 05, 2011 1:18 pm |
|
|
Thanks for the reply FvM,
I am not getting any errors at all.
But the code is not doing what I want basically. I have tried with single sleep() as well but its not working |
|
|
heUAcyp
Joined: 16 Mar 2011 Posts: 33
|
|
Posted: Sun Jun 05, 2011 1:23 pm |
|
|
To make it clearer, the PIC is entering to sleep mode, but not waking up when I change the voltage level at INT0 (pin 21).
Datasheet states, INT0 pin should detect any change and wake the PIC up. |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Sun Jun 05, 2011 1:31 pm |
|
|
You don't have an INT0 interrupt service function. So the processor will try to execute a non-existing, most likely reset, but surely not performing the intended action. To enable INT0 wakeup without performing interrupt code, you have to disable the global interrupt. |
|
|
heUAcyp
Joined: 16 Mar 2011 Posts: 33
|
|
Posted: Sun Jun 05, 2011 2:03 pm |
|
|
Thanks a lot for your replies FvM,
Here is my new code, now PIC starts in sleep mode than detects a change turns the LED on but does not go back to sleep.
(Note: I am not quite sure if disabling interrupts global making any difference
Code: | #include <18F25J11.h>
#device ADC=10
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#byte WDTCON = 0xFC0
#byte DSCONH = 0xF4D
#byte DSCONL = 0xF4C
#byte RTCCFG = 0xF3F
#byte DSWAKEH= 0xF4b
#byte DSWAKEL= 0xF4a
#byte OSCCON = 0xFD3
#byte INTCON = 0xFF2
#byte INTCON2 = 0xFF1
//
#bit IDLEN=OSCCON.7 // used to set IDLE low-power mode ( will be set to zero for both deep-sleep and sleep modes)
#bit DSEN = DSCONH.7 // used to set deep sleep (1 for deep-sleep)
#bit REGSLP =WDTCON.7
#bit RELEASE = DSCONL.0
#bit RTCSYNC = RTCCFG.4
#bit DSINT0 = DSWAKEH.0 // bit for INT0 interrupt - change detection
#bit DS_WAKEUP_BIT = WDTCON.3 // bit that detects wake up from deep sleep
#bit INT0IE = INTCON.4
#bit INT0IF = INTCON.1
#bit INTEDG0 = INTCON2.6
#fuses HS,NOWDT,NOPROTECT, RTCOSC_T1
#use delay(clock=2000000)
#use rs232 (baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
void EnterDeepSleep()
{
REGSLP = 1 ;
IDLEN = 0;
DSEN = 1;
Sleep();
}
void EnableINT0()
{
INTEDG0 = 0; // 0 - interrupt on falling edge
INT0IF = 0; // clear INT0 interrupt flag
INT0IE = 1; // enable INT0 interrupt
}
void main()
{
disable_interrupts(GLOBAL);
if((DS_WAKEUP_BIT == 1) && (DSINT0 == 1))
{
//while(DSINT0 == 1)
RELEASE = 0;
output_high(PIN_A1) ;
delay_ms(500) ;
}
EnableINT0() ;
EnterDeepSleep() ;
while(TRUE)
{
}
} |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19540
|
|
Posted: Sun Jun 05, 2011 2:45 pm |
|
|
You don't need to have an INT0 handler. What you _must not_ do, is enable_interrupts(GLOBAL).
There are two flags for each interrupt. The one enabling/disabling the corresponding INT flag from being set (enable_interrupts(INT_EXT)), and the one that then allows and interrupt handler to be called (enable_interrupts(GLOBAL)). The chip will wake from sleep if the former is enabled, and if the latter is enabled, try to call the corresponding interrupt handler (which since it doesn't exist will then lead to unreliable operation...). You can _just_ enable the former flag, without the latter, and don't then need an interrupt handler. So:
Code: |
disable_interrupts(GLOBAL); //Make _absolutely_ sure this is off
clear_interrupts(INT_EXT); //Make sure the interrupt is clear
enable_interrupts(INT_EXT); //enable the interrupt you want to wake up
sleep(); //Using whatever sleep 'level' you want
delay_cycles(1); //Avoid problem with the next instruction being fetched
|
The instruction after the sleep is pre-fetched, and should generally be a NOP. The delay creates this.
Now if you want to use different sleep 'depths', use the sleep constants provided with the compiler - this is vital, since the order in which the sleep bits are set, is critical. Just use sleep(SLEEP_FULL), or sleep(SLEEP_IDLE) to leave the peripherals enabled or not.
Note also that it is vital to clear the interrupt before sleeping. Otherwise on the second loop, the interrupt _will_ already be set, and the chip _will not sleep_.
You then seem confused about INT0. INT0, does not support interrupt on change. It supports detection of _either_ a rising edge, or a falling edge, not the pin changing. Pin change, is the RB interrupt, and is only available on PortB4, to B7.
You don't need to do all the bit/byte declarations, use the compiler functions.
Best Wishes |
|
|
heUAcyp
Joined: 16 Mar 2011 Posts: 33
|
|
Posted: Sun Jun 05, 2011 3:37 pm |
|
|
Thanks a lot Ttelmah,
My input connected to pin 21 (INT0) is active high. Then I switch it to low to represent an interrupt. So I am actually using INT0 to detect high to low and not otherwise right?
Because, when I change it to low, PIC detects that and turns the LED on.
The reason why I am insisting on INT0, is that, its my only option to awake the PIC from deep sleep.
Quote: | (While in Deep Sleep mode, the device can be awakened
by a MCLR, POR, RTCC, INT0 I/O pin interrupt,
DSWDT or ULPWU event) |
My device will initially operate at high(3 V at pin 21(INT0) ).
I want to be in deep sleep mode.
Wake up at high to low. Do some operations. Go back to sleep (while it is low)
Then wake up at low to high as well. Do some operations. Go back to sleep (while it is high).
This is the basic process I want to achieve.
I really would be glad if you can help me on this, because rest of the code is working and this is a vital project for me.
Thank a lot |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Sun Jun 05, 2011 11:37 pm |
|
|
The present code stays in the while loop rather than going to sleep again. So as a first point, you have to correct the code flow.
If you want to utilize both INT0 edges, you have to reprogram the active edge and reset the interrupt flag before the new sleep instruction. |
|
|
heUAcyp
Joined: 16 Mar 2011 Posts: 33
|
|
Posted: Mon Jun 06, 2011 1:04 pm |
|
|
Thanks for the reply again FvM. I realise that code flow is wrong but I cannot fixed it.
I tried to add another if loop but its not working. Here is my code:
Code: |
#include <18F25J11.h>
#device ADC=10
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#byte WDTCON = 0xFC0
#byte DSCONH = 0xF4D
#byte DSCONL = 0xF4C
#byte RTCCFG = 0xF3F
#byte DSWAKEH= 0xF4b
#byte DSWAKEL= 0xF4a
#byte OSCCON = 0xFD3
#byte INTCON = 0xFF2
#byte INTCON2 = 0xFF1
//
#bit IDLEN=OSCCON.7 // used to set IDLE low-power mode ( will be set to zero for both deep-sleep and sleep modes)
#bit DSEN = DSCONH.7 // used to set deep sleep (1 for deep-sleep)
#bit REGSLP =WDTCON.7
#bit RELEASE = DSCONL.0
#bit RTCSYNC = RTCCFG.4
#bit DSINT0 = DSWAKEH.0 // bit for INT0 interrupt - change detection
#bit DS_WAKEUP_BIT = WDTCON.3 // bit that detects wake up from deep sleep
#bit INT0IE = INTCON.4
#bit INT0IF = INTCON.1
#bit INTEDG0 = INTCON2.6
#fuses HS,NOWDT,NOPROTECT, RTCOSC_T1
#use delay(clock=2000000)
#use rs232 (baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
void EnterDeepSleep()
{
REGSLP = 1 ;
IDLEN = 0;
DSEN = 1;
Sleep();
delay_cycles(1); //Avoid problem with the next instruction being fetched
}
void EnableINT0falling()
{
INTEDG0 = 0; // 0 - interrupt on falling edge (patch on to off)
INT0IF = 0; // clear INT0 interrupt flag
INT0IE = 1; // enable INT0 interrupt
}
void EnableINT0rising()
{
INTEDG0 = 1; // 0 - interrupt on rising edge (patch off to on)
INT0IF = 0; // clear INT0 interrupt flag
INT0IE = 1; // enable INT0 interrupt
}
void main()
{
disable_interrupts(GLOBAL);
if((DS_WAKEUP_BIT == 1) && (DSINT0 == 1) && (INTEDG0 == 1))
{
RELEASE = 0;
output_low(PIN_A1) ;
delay_ms(300) ;
output_high(PIN_A1) ;
delay_ms(1000) ;
clear_interrupt(INT_EXT);
EnableINT0rising() ;
EnterDeepSleep() ;
}
if((DS_WAKEUP_BIT == 1) && (DSINT0 == 1) && (INTEDG0 == 0))
{
RELEASE = 0;
output_high(PIN_A1) ;
delay_ms(5000) ;
clear_interrupt(INT_EXT);
EnableINT0falling() ;
EnterDeepSleep() ;
}
EnableINT0falling() ;
EnterDeepSleep() ;
while(TRUE)
{
}
} |
The second if loop if((DS_WAKEUP_BIT == 1) && (DSINT0 == 1) && (INTEDG0 == 0))
is not making any difference
What code is doing now is :
1. Initialise with sleep mode.
2. Wake up with falling edge at pin 21 (INT0). (and doesn't go back to sleep)
3. Detect the rising edge as well and turn the LED off and on again. (doesn't go back to sleep)
4. after that it detects only the rising edge without sleeping.
I want him to detect every change and go back to sleep after every change. Thats it, but I cannot do it!
can you please tell me how to arrange the code flow?
I could not manage to do it in the while(TRUE) loop as well.
Regards |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Jun 06, 2011 2:13 pm |
|
|
Your code assumes that the INTEDG0 bit in the INTCON2 register will
maintain its current state after a reset. But it does not.
Look in the 18F25J11 data sheet, at this table. It shows that INTCON2
will be all 1's. This is why your 2nd test is never executed. If you had
used diagnostic printf statements at the start of the program to display
the state of registers, you would have seen this.
Code: |
TABLE 5-2: INITIALIZATION CONDITIONS FOR ALL REGISTERS
Power-on Reset,
Brown-out Reset,
Wake From
Deep Sleep
INTCON2 1111 1111
|
So you need to re-think your test and re-write it. |
|
|
heUAcyp
Joined: 16 Mar 2011 Posts: 33
|
|
Posted: Mon Jun 06, 2011 2:53 pm |
|
|
Sir I have realised that and I am trying to set INTEDG0 bit to 0 after executing first if loop.
Why I cannot change it then?
and why device doesn't go back in to sleep even though I use enterdeepsleep() at the end of if loop?
these are question I could not answer actually |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Jun 06, 2011 3:09 pm |
|
|
What is your current compiler version ? |
|
|
heUAcyp
Joined: 16 Mar 2011 Posts: 33
|
|
Posted: Mon Jun 06, 2011 3:16 pm |
|
|
V4.095 .
Should I change to bank 1 using assembly code? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Jun 06, 2011 3:41 pm |
|
|
Put a printf statement at the beginning of the program and have it display
the state of all the bits. Try something like this:
Code: |
void main()
{
RELEASE = 0; // Activate i/o pins
delay_ms(10);
printf("\n\r\n\r");
printf("DS_WAKEUP_BIT: %x \n\r", DS_WAKEUP_BIT);
printf("DS_WAKEUP_BIT: %x \n\r", DS_INT0);
printf("DSWAKEH: %x \n\r", DSWAKEH);
printf("DSWAKEL: %x \n\r", DSWAKEL); |
Also you have to add a #use rs232() statement to the program,
and add a Max232-type chip to your board. Or, you could go direct
from the Tx pin to the PC's Rx pin (if you're careful in the connections)
and use the INVERT option. Use only that wire, and a ground wire
for the RS232 interface. |
|
|
|