The bit that Atmel forgot.

Go To Last Post
40 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It would be nice if there was a global bit that would be turned on whenever an interrupt occurred. If you use a simple main loop and want to sleep when there is nothing to do, such a bit can be used to insure all tasks "scheduled" by interrupts are run before sleeping. The bit would be cleared by the main loop after returning from sleep. It would be checked by the main loop after all tasks are checked and just before sleeping. If the bit is set, the sleep is skipped. Going around the loop again will enable all tasks to be run. The AVR keeps spinning around the loop until the bit is clear at the end of the loop, and only then it sleeps.

Of course if only one interrupt happens, it will awaken the CPU, the loop will run, and all will be well. But if a second interrupt occurs while executing the loop, and it "schedules" a task that has already been checked, the loop will sleep without running that task unless it checks this "interrupt happened" bit.

This bit can be implemented by the software but it's a pain and the AVR could do it easier.

If they wanted to make the programmer's work even easier, the sleep enable bit could be used. The loop would set it after returning from sleep. An interrupt would clear it. Thanks to Lee for dreaming that one up. Atmel won't do that though because they keep advising me to keep sleep disabled until just before sleeping. But I keep ignoring their advice because it doesn't make much sense to me.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't get the point.

You have a system that likes to go to sleep.

You have one or more sleep wakeup sources enabled.

When those fire, the ISRs for those events are invoked.

typically, it would only be one. But there could be multiple events in a close time frame. So, all the ISRs will be invoked at some point.

When all your work is done--you have processed all the "flags" and new data produced by the ISRs--you put your pajamas back on and prepare to return to bed.

[As I learned painfully] there is a proper sequence to use when racing to get into bed, so you don't miss something just before your head hits the pillow.

You could always construct a mask with the xxxIF bits that are important to you. You MUST use a mask, as some/many xxxIF bits that you aren't concerned about are going to be firing. Thus, the "global bit" would be on nearly all the time. One example is ICP. Another is UDRE.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

steve17 wrote:

If they wanted to make the programmer's work even easier,...
...they'd better switch to producing a beer instead of those AVRs :D :D :D

Warning: Grumpy Old Chuff. Reading this post may severely damage your mental health.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you have a main loop with various tasks that run when a corresponding interrupt sets a flag, won't all those flags need to be different, and won't all those flags do what you want? If your single bit were set, that still doesn't tell the main loop tasks which one(s) to run.

Maybe I'm just not understanding your point.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I too don't see the point. Isn't it up to you to determine whether or not your program has something to do? And there are several interrupt flags that get set regardless of whether or not that interrupt is enabled, so your universal interrupt flag might be set even though your program doesn't care about that particular interrupt. And if you only have this universal flag set if any enabled interrupts are set, then it becomes useless since your ISR will be run anyways.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I see no reason for such a flag.
Simple let every interrupt, which need skipping the sleep, disable sleep:

ISR( XXX_vect )
{
//  ... code
  sleep_disable();
}

And the main enable sleep atomic prior all handling:

int main( void )
{
//  ... init stuff
  for(;;){
    ATOMIC_BLOCK(ATOMIC_FORCEON){ // important !
      sleep_enable();
    }
//    ... handling stuff
    sleep_cpu();
  }
}

Peter

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

steve17 wrote:
Atmel won't do that though because they keep advising me to keep sleep disabled until just before sleeping. But I keep ignoring their advice because it doesn't make much sense to me.

You are right, this advising is pure nonsense. :!:

I asked Atmel, what's the meaning of this curious advise.
They telled me, that it would help against unwanted entering of the sleep mode.
But this was stupid, since it would only be true, if a sleep instruction occur alone.
But if you follow the advice, never any sleep occur alone, every sleep was preceded by sleep-enable.
So the behavior was really accurately exact the same, as if sleep-enable was done once after reset and only the sleep instruction, when you want to go into sleep.

They agreed with me, that this was true. :shock:

But in opposition, there was a big danger, if you follow this advice and make the sleep-enable prior sleep non atomic, that the CPU sleeps forever. :!:

So your application works more secure, if you disregard this advice.

Peter

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

But in opposition, there was a big danger, if you follow this advice and make the sleep-enable prior sleep non atomic, that the CPU sleeps forever.

Yes, I did get caught on this. I thought I had done an atomic sequence, but there was a small hole of a few AVR cycles. Interrupts can -- and WILL -- hit these small holes sometimes.

(In fact, the CodeVision sleep primitives are now modified a bit to allow me to close the hole with straight C.)

[If pertinent, I can dig up the thread on the above...]

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

kk6gm wrote:
If you have a main loop with various tasks that run when a corresponding interrupt sets a flag, won't all those flags need to be different, and won't all those flags do what you want? If your single bit were set, that still doesn't tell the main loop tasks which one(s) to run.

Maybe I'm just not understanding your point.

You do miss the point and I thought I did such a good job of explaining :)

You are correct but you are missing something. Each ISR sets a different flag to cause the main loop to run a particular task. But we also want an "OR" of all those flags which will cause the main loop to go around the loop once more without sleeping, if an interrupt occurs while the loop is running.

Let's say we have two interrupts and each one schedules a task by setting a bit or whatever. When an interrupt happens, the loop checks the first task and runs it if necessary. It then checks the second task and does the same, and then goes back to sleep.

Now lets say the interrupt that schedules the second task occurs. The loop awakens and checks the first task but there is nothing to do. Then it checks the second task. While checking the second task, an interrupt happens that schedules the first task. The main loop will be unaware. After servicing the second task it will go to sleep even though the first task has been scheduled. The scheduled first task won't run until another interrupt happens.

In many (most?) apps, this is probably acceptable. If interrupts are happening at a fast rate, it won't be long before the loop awakens and services the first task. If interrupts are happening at a slow rate, the chances of a second interrupt occurring while the main loop is running, is small.

A global flag would allow it to be done right. I could put it this way. Each ISR can set a particular bit that causes the main loop to run a particular task. In addition it could set the global bit that causes the main loop to go around again in case the main loop checked the particular task bit before the interrupt that set it occurred.

The main loop clears this bit immediately after waking and before checking the tasks. This bit will only have an effect if an interrupt occurs while the loop is running.

Here is another way to think about it. Do not assume that a particular interrupt will cause the main loop to awaken from sleep. Occasionally the main loop will be already running when the interrupt happens. This could cause a monkey wrench to be thrown into the machinery.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It sure is nice that everyone agrees with me. Smart thinking too. Those who disagree with me do so at their peril! :)

theusch wrote:
I don't get the point.
I can't argue with that. :)

theusch wrote:
the "global bit" would be on nearly all the time. One example is ICP. Another is UDRE.
I agree it would be nice if ISRs that don't schedule tasks don't set this bit. So it would be nice if you could enable this bit setting individually for each interrupt source. I assumed Atmel could figure that out. Are you suggesting I must tell Atmel every detail about how to design a microcontroller? :)

I disagree that the bit would be on nearly all the time. The main loop clears the bit immediately after waking. The only time it is on for long is when a second interrupt occurs while the loop is running. That is the only time it has an effect and that effect is just what is wanted. You can think of this bit as the "an interrupt occurred while the main loop was running" bit.

P.S. Just because the bit is there doesn't mean you have to use it. Or do you feel obliged to use every bit in every register in every peripheral device and every bit of flash and EEPROM, whenever you program an AVR? :)

Most mega and Xmega chips have lots of stuff that aren't used for most apps. But the "steve17" global bit could be used by all apps that have a simple main loop with sleep.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

The main loop will be unaware. After servicing the second task it will go to sleep even though the first task has been scheduled

You mean:

ISR(hw1_vect) {
 hw1=1;
}
ISR(hw2_vect) {
 hw2=1;
}

int main(void) {
 while(1) {
  while (hw1 | hw2) {
    if (hw1) {
      service_hw1();
      hw1=0;
    }
    if (hw2) { 
      service_hw2();
      hw2=0;
    }
  }
  go_to_sleep();
 }
}

If hw1 gets set while hw2 is being serviced why do you think hw1 doesn't then get service before sleep?

Cliff (not totally following your argument)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Koshchi wrote:
I too don't see the point.
Sorry I didn't make my case very well.

The bit I'm talking about is a bit that is set when an ISR runs. It's even better if this bit is set only when an ISR runs that schedules a task. This bit is cleared immediately by the main loop after waking from sleep. To be precise, it must be cleared before checking tasks.

This bit could be used by the main loop to go around the loop again without sleeping if, and only if, an interrupt occurred while the loop was running.

When an interrupt wakes the main loop, everything works according to plan. But when another interrupt happens and schedules a task while the main loop is running and after the main loop has checked that task, that task won't be run before the loop sleeps. Checking this bit before sleeping, and going around again if set, fixes that.

Steve

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Checking this bit before sleeping, and going around again if set, fixes that.

Not needed. Have the ISRs do "sleep disable". The go-to-sleep sequence that is racing the ISR events will indeed commit to sleep and get to the sleep instruction, but sleep will be enabled--thus it is like a sleep and wakeup.

And the proper "atomic" SLEEP eliminates the "sleep with the fishes forever" mentioned above.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I didn't mean to talk about sleep enable, but I should have known it would stir up a hornet's nest. I have no problem with keeping sleep disabled until sleep is wanted, but I don't do that. As far as I know, I've not had an AVR die unexpectedly.

It seems to me if a sleep is executed when not wanted, the code must have branched out into the wild blue yonder. I can think of worse things the AVR can do than sleep. The sleep would awaken eventually anyway unless interrupts were disabled. But isn't that what the watchdog is for?

Steve

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Since micros can deal with both bits and bytes, you get your global flag automatically. Individual ISRs set separate bits in an ISR flag byte (or even word). Then your global flag is just

if (ISR_flags != 0)
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

but I don't do that.

It ain't a hornet's nest. The point is that there is a very simple way to do what you desire. And I outlined it--probably badly. You've got a sleep-enable "bit"--use it. To not use it for your needs would be like having the watchdog timer enabled and doing a WDR in every part of your program.

I can hunt up my posted sequence, that I developed myself for my first sleeping app. Given responses and other threads on sleep, I'm not too far off. My posted ISR(s) for the wakeup source(s) just blindly disable sleep. This is exactly what you described as "scheduling a task to be executed". Now, you may have some qualification in that ISR but the idea is the same. My "task" is that I know that a wakeup source has triggered, therefore there is something further to do. If I'm not yet ready for sleep then normal flow takes care of it. If during that race the mainline doesn't know whether it actually went to sleep or not. If it really mattered the ISR could figure that out.

Redux:

if (nothing further to do)
   {
   // Commit to sleeping--assume wakeup sources are enabled
   sleep_enable();

   // We are now in no-man's land per your desires--racing to go to sleep.
   // No biggie...
   shutdown_adc();
   set_prr_bits();
   do_whatever_else();

   // Go to sleep--but do it properly!!! ("atomic")
   power_down();

   // Awakened.  Or never went to sleep!
   clear_prr_bits();
   startup_adc();
   do_other_stuff();

   // Look for something to do...
   ...
   
   state = STATE_AWAKE;
   }
...
ISR my_isr()
{
   sleep_disable();
   do_other_isr_stuff();
}   

For your described situation, sleep-enable >>is<< the bit that Atmel didn't forget.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I understand not, why all the awkward flag setting and testing should be done. :?

See my example above.
The sleep enable bit was ideally suited to do the job perfectly.
No testing was needed, the sleep instruction itself do the test.

You must only follow the order, given in my example above:
The sleep enable bit must be set prior all handling events. :!:
Then if an interrupt occur during handling, the sleep was skipped by the sleep_disable() inside the interrupt handler and a next turn of the mainloop take place.

Peter

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes Cliff, that code would work but to have it work 100% of the time, you would need to disable interrupts before checking all the flags. If there was nothing to do and you want to sleep, you would need to re-enable interrupts immediately before sleep.

EDIT: The last sentence wasn't clear. The enable interrupts instruction should be immediately followed by the sleep instruction. Otherwise an interrupt could happen and a task scheduled before sleeping.

Last Edited: Fri. Jan 29, 2010 - 11:14 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes Peter and Lee, your use of the sleep enable/disable looks good. But you are failing to heed Atmel's advice to keep sleep disabled until immediately before sleeping. That's okay with me, I don't heed that advice either.

I was thinking of a bit that would be automatically set by hardware, but maybe that's impractical. To be most useful it would have to be enabled independently for each potential interrupt source.

Another use for it would be when the ADC is set up to do the conversion after the CPU sleeps. That's the way I do it and it works well. I'm kidding myself though to think the conversion will always be done when the CPU is sleeping because another interrupt could happen during the conversion. To test for that happening, all other ISRs would have to set a bit. Then when the conversion completes, the ADC driver could test the bit to see if another interrupt happened. In this case all potential interrupts except the ADC interrupt would have to set the bit.

Of course another way would be to disable all other interrupts until the conversion completes, but I prefer the bit setting approach.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:

And the proper "atomic" SLEEP eliminates the "sleep with the fishes forever" mentioned above.
I like your code, but I don't understand the "atomic" SLEEP thing.

If I understand correctly, you are running with sleep enabled. Atmel, but not me, says not to do that.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

If I understand correctly, you are running with sleep enabled.

Sigh. Do you see my fragment above? I'm NOT "running with sleep enabled". I set sleep enable when I'm preparing to sleep.

Quote:

I don't understand the "atomic" SLEEP thing.

There is a race with the SLEEP instruction itself. It doesn't directly concern the topic here, but rather ensuring that an atomic always-correct sequence is used. CV's sequence that I used had a window of about a microsecond that could cause problems. It has since been corrected.

https://www.avrfreaks.net/index.p...

is the thread. danni figgered it out for me. As Cliff implies at the end, it should be required reading for all sleepers, at least to ensure that the sequence used, from the toolchain or home-built, is bulletproof.

But again, it is not directly pertinent to this thread. Except that it does show my sequence that I reproduced in pseudocode above.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well Lee, I guess I'll never understand. Apparently you are running for only a short time with sleep enabled.
If I understand correctly you do the shutdown_adc() etc. with sleep enabled. Naughty boy.

I don't see any disabling of interrupts. What happens if the ISR runs between:

if (nothing further to do) 

and

   { 
   // Commit to sleeping--assume wakeup sources are enabled 
   sleep_enable(); 

Anyway, I think my way is simpler.

Cliff's way is basically my way but arranged differently. He's effectively oring together all the flags when he tests them. But as I mentioned earlier, it's only bulletproof if interrupts are disabled between the time the flags are tested when none are set, and the sleep instruction is executed.

I don't know what your "atomic" powerdown() is, but I dare not ask. :}

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

steve17 wrote:
Yes Peter and Lee, your use of the sleep enable/disable looks good. But you are failing to heed Atmel's advice to keep sleep disabled until immediately before sleeping. That's okay with me, I don't heed that advice either.

It's your choice, if you insist on a suggestion, which was obviously absurd.
Especially, since it was not only absurd, it was dangerous also, as already described.

But I see no reason to ignore it and use the sleep enable bit in a useful manner.

There are also some other things in the data sheets, which are not correct.
Since the Atmel people are no gods.
They are also people only, which can make mistakes.

Again, I asked Atmel support and they telled me, that there is absolutely no problem, if the enable bit was set earlier.

The state of the enable bit was only evaluated on the sleep instruction but nowhere else.
So the state was fully irrelevant on every other instruction.
And there was no hardware bug known, that sleep may be entered without the sleep instruction, only by setting the enable bit alone.

Peter

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

If I understand correctly you do the shutdown_adc() etc. with sleep enabled. Naughty boy.


Don't start picking at me--we are starting to work on taxes and I'm even more surly than usual. The point of your thread is having a facility available--the "bit"--to meet your desires.

My pseudo-code may not meet your exacting needs, and is unrelated to your desire. It >>is<< related to my note that the go-to-sleep sequence had to be proper and "atomic" for bullet-proof operation.

Do you want to see my work-around for the CV problem? Take a peek and then tell me how long I have SE:

#if 1
	// Alternate sleep sequence
	// Enable interrupts just before the actual sleep instruction
		#asm ("cli")

// Enable the "wake up" interrupt
		EIFR = 2;
		EIMSK = 2;

		SMCR = 0x01 | 0x04;	// SE + SM1 (power-down)
		#asm ("sei")
		#asm ("sleep")
// One instruction after SEI is executed

#endif

I'm out.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Yes Cliff, that code would work but to have it work 100% of the time, you would need to disable interrupts before checking all the flags. If there was nothing to do and you want to sleep, you would need to re-enable interrupts immediately before sleep.

Not if you do as someone suggested earlier in this thread and keep all the i-flags in a single, atomically accessed 8 bit variable (OK, if you have more than 8 ISRs I can see a problem - but that's maybe unusual?)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I agree you don't need the "bit that Atmel forgot", but I think you still need to disable interrupts when checking the flags.

Even if all flags are in one byte I think an interrupt can occur after the flag is tested and before the sleep instruction is executed. If any ISRs run after you check the flags but before the AVR sleeps, the AVR will sleep without running any tasks that are scheduled by those ISRs. Because these ISRs run before sleep, they won't awaken the AVR.

If you disable interrupts before testing the flags and re-enable interrupts with the instruction immediately preceeding "sleep", you force any pending interrupt to occur after the CPU enters the sleep state and thus cause the sleep to end.

By the way, the mega datasheet makes it clear that the SEI instruction enables interrupts after the next instruction is executed. In this case that would be "sleep". I don't think the Xmega A datasheet states that, but I guess it's still true.

Steve

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Even if all flags are in one byte I think an interrupt can occur after the flag is tested and before the sleep instruction is executed. If any ISRs run after you check the flags but before the AVR sleeps, the AVR will sleep without running any tasks that are scheduled by those ISRs. Because these ISRs run before sleep, they won't awaken the AVR.


I don't see that problem--IF your ISRs that "schedule a task" disable sleep. then the event that occurs in the race just before sleep looks to your app like one that happend after you went to sleep.

That is a narrow window; say, a few microseconds. It has to be made watertight, but you have exactly the same response to the event no matter when it occurred.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I haven't read all this thread, but I go to sleep like this:

sip3:   ldi r16, 0xb0                   ;SRE|SE|SM1
        rjmp sip2

sip1:   ldi r16, 0xa0                   ;SRE|SE

sip2:   out MCUCR, r16                  ;set up sleep mode
        ldi r16, low(sleep_pointer)
        push r16
        ldi r16, high(sleep_pointer)
        push r16
        reti                            ;control passes to the next
                                        ;instruction, interrupts are
                                        ;enabled
sleep_pointer:
        sleep                           ;this instruction is guaranteed to be
                                        ;executed after the reti

        ;we are now asleep, with interrupts enabled. When an external level

Any flag checks and decisions are made with interrupts disabled, and if I then want to go to sleep I enter the above code. There are no windows for problems.
Aplologies if I am deviating from the main point of the thread.

Roger

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@Roger

Nice trick, but fully superfluous. :roll:

The better trick: read the AVR instruction set.

Quote:
SEI – Set Global Interrupt Flag
Description:
Sets the Global Interrupt Flag (I) in SREG (Status Register). The instruction following SEI will be executed before any pending
interrupts.

Thus:

SEI
SLEEP

does exact the same. :!:

Peter

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It is a nice trick, though, if you call your generic or often-used sleep-setup routine just before the sleep. It could be called with interrupts disabled, or disable them in the routine. Then replace the RET of that routine with RETI.

I think the most SLEEPs I have in a single app is three, and the sleep preparation and context varies widely among power-down, power-save, and idle. Most apps have only one SLEEP context so I generally wouldn't do a sequence like that instead of the shorter one, nor call a routine for one invocation. Save a few words here; a few words there; ... ;)

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@danni

Yes, well, with all the up-to-date documentation that we have these days, I agree :? . But in 1998 my copy of doc0856 made no mention of such subtleties...

But RETI did the job, so that piece of code remains to this day.

Interestingly enough, the current revision still makes no mention of the guaranteed 1-instruction execution in the RETI description.

Oh well, one day, perhaps...

Roger

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:
I don't see that problem--IF your ISRs that "schedule a task" disable sleep.
It's not a problem. Of course for some people, programming a computer is always a problem. :)

Yes, having the ISRs disable sleep should work. But for the disable to do anything you must be running with sleep enabled. I thought if I did that, I would suffer a horrible fate. :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

laserman wrote:
Aplologies if I am deviating from the main point of the thread.

Roger

There's a point to this thread?

Actually that's interesting that you use the return from interrupt to sleep, and thereby delay any interrupts until the CPU sleeps.

Yes, Atmel's documentation could sometimes be improved. :)

The Xmega docs could use a lot of improvement. I see no mention of the one instruction delay following SEI there. I guess the Xmega is a work in progress and when they figure out how it really works, they'll fix the docs. :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

The Xmega docs could use a lot of improvement. I see no mention of the one instruction delay following SEI there.

Eh? The 07/09 copy of the opcode manual caters for BOTH old AVRs and Xmega (confusingly in places!) but under SEI for all cores it says:
Quote:
The instruction following SEI will be executed before any pending interrupts.

Interestingly the Example given is:

Example:
   sei   ; set global interrupt enable
   sleep ; enter sleep, waiting for interrupt
         ; note: will enter sleep before any pending interrupt(s)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

But for the disable to do anything you must be running with sleep enabled. I thought if I did that, I would suffer a horrible fate.

I will say this once more, with my caps-lock stuck:

JUST BECAUSE YOUR ISR IS DOING A SLEEP-DISABLE, THAT DOES NOT MEAN THAT YOU ARE "RUNNING WITH SLEEP ENABLED". At some point in the program before you go to sleep, you must enable sleep. There may be 0 to a few AVR instructions between that sleep enable and the actual go-to-sleep sequence. It depends on how you write your code; primarily how long you are going to run with interrupts disabled.

If you have interrupts disabled, then you might get all the way to the sleep with the ISR for the event held off. You go to sleep, then wake up. Depending on the sleep mode and the clock source, that could take many clock cycles or even milliseconds.

If you structure the sequence differently, the ISR might run when sleep is enabled but before you get to sleep. The ISR disables sleep, and you slide right through without actually going to sleep.

I guess I just don't understand the topic. I'm going to sleep now, if there is nothing important to do.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:
There may be 0 to a few AVR instructions between that sleep enable and the actual go-to-sleep sequence.

Again, 0 was no valid option !

You must disregard this Atmel suggestion, otherwise you are in big trouble. :!:

Only if you follow the right order, you awake secure.
One possible order may be:

1. enable sleep
2. enable wakeup interrupt source
3. do SLEEP

Exchanging step 1 and 2 cause sleeping forever.
So at least one instruction must be in between sleep enable and the sleep itself.

Peter

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hers's the way I see it. Two ways that always work, and one way that allows the CPU to sleep while tasks are ready to run.

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
Eh? The 07/09 copy of the opcode manual caters for BOTH old AVRs and Xmega (confusingly in places!) but under SEI for all cores it says:
Quote:
The instruction following SEI will be executed before any pending interrupts.

Thanks Cliff. All I did was search for SEI. That worked for the mega datasheet but not for the Xmega. I was thinking of adding a caveat to my previous post that I didn't plow through all the literature.

I figured someone would do my homework for me. :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Again, 0 was no valid option !

But Lee did not say "0 instructions between enable sleep and sleep", he said "0 instructions between enable sleep and the sleep sequence". He then went on to describe that sequence.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Atmel gave us extra bits. You can e.g use the PINx/RESET bit when using RESET (in the tiny2313 and mega88 you can toggle bits in ports with sbi PINx.) You can set/clear (R/W) bits on the features (like timers, ADC) when keep them disabled.

RES