CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Deep Sleep wake up on INT0 !
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
heUAcyp



Joined: 16 Mar 2011
Posts: 33

View user's profile Send private message

Deep Sleep wake up on INT0 !
PostPosted: Sun Jun 05, 2011 7:37 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sun Jun 05, 2011 12:44 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Sun Jun 05, 2011 1:18 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Sun Jun 05, 2011 1:23 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Sun Jun 05, 2011 1:31 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Sun Jun 05, 2011 2:03 pm     Reply with quote

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: 19520

View user's profile Send private message

PostPosted: Sun Jun 05, 2011 2:45 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Sun Jun 05, 2011 3:37 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Sun Jun 05, 2011 11:37 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Jun 06, 2011 1:04 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Jun 06, 2011 2:13 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Jun 06, 2011 2:53 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Jun 06, 2011 3:09 pm     Reply with quote

What is your current compiler version ?
heUAcyp



Joined: 16 Mar 2011
Posts: 33

View user's profile Send private message

PostPosted: Mon Jun 06, 2011 3:16 pm     Reply with quote

V4.095 .

Should I change to bank 1 using assembly code?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Jun 06, 2011 3:41 pm     Reply with quote

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.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
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