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 support@ccsinfo.com

Sleep and Interrupts

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
plinder13



Joined: 16 Jul 2007
Posts: 2

View user's profile Send private message

Sleep and Interrupts
PostPosted: Fri Jul 20, 2007 8:13 am     Reply with quote

I have had a difficult time getting sleep to work with interrupts as expected on various PICs

I want to put a PIC to sleep using the sleep() function. But, before I put it to sleep, I want to enable global interrupts. As soon as it wakes up, I want to execute the ISR for any interrupts that occured and then immediately disable global interrupts so that background tasks can run. I have much experience with the MSP430 for which the following code works great:

while(1)
{
if (flags.sleep)
{
LPM0_EINT(); //(enter low power mode and enable global interrupts)
DINT(); //(disable low power mode and disable global interrupts
}
// Do background tasks and check flags
}

The reason I need global interrupts enabled immediately before sleeping is that I set various flags in ISRs that determine whether the MCU should sleep. I don't want those ISRs to run between the time I check the flags and the time I place the MCU into sleep (if an interrupt occured between the checking of the flags and the sleep instruction, the MCU could get "stuck" in sleep mode).

Here is the code I have tried which has not worked for me:

if (flags.sleep)
{
enable_interrupts(GLOBAL);
sleep();
delay_cycles(1);
disable_interrupts(GLOBAL);
}

In my specific project, the comparator does not seem to wake up the MCU. However, if I comment out the sleep() instruction the application works fine. But, I have had a hard time understanding how to do this in other applications as well. I also have tried inserting another delay_cycles(1); before the sleep instruction.

Thanks for any help.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Jul 20, 2007 12:10 pm     Reply with quote

Quote:

I have had a difficult time getting sleep to work with interrupts as
expected on various PICs

1. Post the PIC that you're most concerned about using.
Don't post a list of all of them -- just the most important one.

2. Also post your CCS compiler version.
Guest








PostPosted: Fri Jul 20, 2007 12:16 pm     Reply with quote

PIC16F883
CCS Version 4.044

Specifically, I am trying to use the comparator to wake up from sleep mode.
Bill Boucher



Joined: 04 Feb 2005
Posts: 34
Location: Chatham,ON,CA

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Fri Jul 20, 2007 12:46 pm     Reply with quote

Try copying the ISR controlled flags variable into a local variable in your main(). The value of this local copy will not be changed if an interrupt happens. Check the value of the copy and do your sleep thing based on that.

Code:

int8 flags_copy; //you might have to define the bit names as you did with flags.

disable_interrupts(GLOBAL);
flags_copy = flags;
if (flags_copy.sleep)
{
enable_interrupts(GLOBAL);
sleep();
delay_cycles(1);
disable_interrupts(GLOBAL);
}
else
{
enable_interrupts(GLOBAL);
}
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Jul 20, 2007 12:48 pm     Reply with quote

Before you execute the Sleep() function, you also need to do
these three things:

1. Clear the "mis-match" condition that causes the interrupt
by reading the CMxCON0 register for the comparator that
you're using. Use the #byte directive to declare the address
of the register, and then read it into a variable with a line of code.

2. Clear the comparator interrupt flag by calling the CCS
clear_interrupt() function, with INT_COMP as the parameter.

Doing items #1 and #2 will clear any pre-existing comparator
interrupt condition, prior to going to sleep.

3. Enable comparator interrupts by using enable_interrupts()
with INT_COMP as the parameter.

Then you can enable Global interrupts and go to sleep.
That's three additional lines of code that you need to add.


Also, inside the comparator isr, you should do item #1. This is in
the data sheet. In addition to that, if you don't want to get any more
comparator interrupts (for the time being), you should call
disable_interrupts(INT_COMP) inside the isr.


Last edited by PCM programmer on Fri Jul 20, 2007 12:49 pm; edited 1 time in total
SET



Joined: 15 Nov 2005
Posts: 161
Location: Glasgow, UK

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Fri Jul 20, 2007 12:49 pm     Reply with quote

If you want to execute the code after the sleep() when an interrupt occurs then you DONT want to set the GIE bit - just set the interrupt enable flag(s) for the interrupts that you want to happen. When the interrupt occurs the PIC will continue execution after the sleep instruction - if you have the GIE flag set it will jump to the interrupt handler.

Code:
if (flags.sleep)
{
  // PIC will halt here until an interrupt
  sleep();
  // clear interrupt flag here
  // do background tasks
}
plinder13



Joined: 16 Jul 2007
Posts: 2

View user's profile Send private message

PostPosted: Fri Jul 20, 2007 3:12 pm     Reply with quote

Let me ask my question a different way.

How do I force my ISRs to execute only at the sleep instruction? I have more than one interrupt that may occur (comparator, port b change, etc.).
SET



Joined: 15 Nov 2005
Posts: 161
Location: Glasgow, UK

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Fri Jul 20, 2007 4:42 pm     Reply with quote

Let me see if I understand - you want the PIC to be brought out of sleep by an interrupt (which could be from a number of sources), execute some code depending on the interrupt that happened and then go back to sleep? If so, then that is what my code fragment will do - just enable each relevant interrupt, and in the code following the sleep() test the flags to see which interrupt it was.


Code:
// enable interrupts here
if (flags.sleep)
{
  // PIC will halt here until an interrupt
  sleep();

  // test for interrupt - comparator, port b change etc..
  // clear interrupt flag here
  // do background tasks
}

Setting the GIE flag will do the same thing but in that case the PIC will execute the interrupt handler(s) first before carrying on from the sleep(). The compiler makes this appear to be a number of ISR's, but in fact there is just one ISR (or two if high priority is used) and the compiler puts in code to work out which interrupt happened.

As long as your interrupts are enabled before calling sleep() you wont get stuck in sleep mode. Even if an interrupting condition happened between you setting the enable and sleep, all that would happen is that the PIC would come out of sleep mode straight away. You wouldnt lose the interrupt, since you have to clear them explicitly.
Guest








PostPosted: Fri Jul 20, 2007 6:11 pm     Reply with quote

Quote:
Setting the GIE flag will do the same thing but in that case the PIC will execute the interrupt handler(s) first before carrying on from the sleep(). The compiler makes this appear to be a number of ISR's, but in fact there is just one ISR (or two if high priority is used) and the compiler puts in code to work out which interrupt happened.


In this scenario, if there are any instructions between the GIE flag being set, and the sleep instruction being executed, and the ISR executes between the GIE being set and the sleep instruction, and clears the interrupt condition, the processor will not exit sleep mode, correct?
SET



Joined: 15 Nov 2005
Posts: 161
Location: Glasgow, UK

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Mon Jul 30, 2007 8:57 am     Reply with quote

Sorry for delay in replying, back from weeks holiday..

In theory that might happen - the PIC really should have a single instruction that enables global interrupts and puts it to sleep atomically. In reality it probably wouldnt happen, the time difference between setting the GIE bit and then executing sleep would be 4 clocks, surely not enough for an interrupt to be recognised? Maybe..
RLScott



Joined: 10 Jul 2007
Posts: 465

View user's profile Send private message

PostPosted: Mon Jul 30, 2007 12:10 pm     Reply with quote

Anonymous wrote:
...if there are any instructions between the GIE flag being set, and the sleep instruction being executed, and the ISR executes between the GIE being set and the sleep instruction, and clears the interrupt condition, the processor will not exit sleep mode, correct?


No, you should not set the GIE flag before entering sleep mode. The first posting from SET gives the perfect solution. Leave GIE cleared upon calling sleep, then set the GIE bit _after_ waking up from sleep. If you don’t want to leave GIE enabled all the time, then just leave GIE set for a few instructions after the sleep and then clear it again. To cause a wake-up from sleep, all you need is to have an active interrupt enabled all the way up to, but not including, GIE.

Robert Scott
Real-Time Specialties
Ypsilanti, Michigan
Ttelmah
Guest







PostPosted: Mon Jul 30, 2007 12:14 pm     Reply with quote

SET wrote:
Sorry for delay in replying, back from weeks holiday..

In theory that might happen - the PIC really should have a single instruction that enables global interrupts and puts it to sleep atomically. In reality it probably wouldnt happen, the time difference between setting the GIE bit and then executing sleep would be 4 clocks, surely not enough for an interrupt to be recognised? Maybe..

Not necessary.
If you read the data-sheets, you will find that the manufacturers have thought of this. If the interrupt bit is set at the start of the sleep instruction, the instruction completes as a NOP. If it becomes set after this point, the behaviour is to reset things as if a sleep occured, but not actually sleep.

Best Wishes
SET



Joined: 15 Nov 2005
Posts: 161
Location: Glasgow, UK

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Mon Jul 30, 2007 12:32 pm     Reply with quote

Thanks for that Tlemah - I assumed that Microchip would have taken it into account but hadn't looked at the exact mechanism.

Yes RLScott, I agree - this is exactly what we do in a number of low-power designs and it works well.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
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