| 
	
	|  |  |  
	
		| View previous topic :: View next topic |  
		| Author | Message |  
		| valemike Guest
 
 
 
 
 
 
 
			
			
			
			
			
			
			
			
			
 
 | 
			
				| ISR and Sleep |  
				|  Posted: Sun Aug 29, 2004 12:48 pm |   |  
				| 
 |  
				| If i have the following code in my isr: 
 
  	  | Code: |  	  | #int_ext
 void my_isr(void)
 {
 flag = 1;
 }
 
 | 
 
 and somewhere in my code, i have:
 
 
  	  | Code: |  	  | while (1)
 {
 .....
 sleep();
 if (flag)
 {
 do_something();
 flag = 0;
 }
 else
 {
 //Why is flag not set????
 }
 }
 
 | 
 
 Well I have a mechanical switch connected to my RB0 pin, H_to_L edge interrupt enabled. If i hit the switch, sleep() wakes up, 'flag' gets set in the isr, then my "if (flag)" statement us guaranteed to always be true after a wakeup from sleep, right??
 
 Many times, the PIC wake up, and the if-statment fails, so the else-statement runs instead.
 
 Am I not guaranteed then that the ISR will not run immediately upon a wakeup?
 |  |  
		|  |  
		| PCM programmer 
 
 
 Joined: 06 Sep 2003
 Posts: 21708
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Sun Aug 29, 2004 1:32 pm |   |  
				| 
 |  
				| From section 12.13 of the 16F877 data sheet: Power-down Mode (SLEEP):
 "When the SLEEP instruction is being executed, the next instruction
 (PC + 1) is pre-fetched."  (This is the key point).
 "If the GIE bit is set (enabled), the device executes the instruction
 after the SLEEP instruction and then branches to the interrupt
 address (0004h)."   (When you pressed your switch, the GIE bit got set)
 "In cases where the execution of the instruction following SLEEP is not
 desirable, the user should have a NOP after the SLEEP instruction".
 
 So, looking at the .LST file for your code, you see that the assembly
 language instruction that updates the Z flag based on the value of 'flag'
 is being pre-fetched and executed before 'flag' is actually updated in
 your isr.   The solution is to put a NOP after the Sleep() function.
 You can use inline assembly for this, or define a macro and make the
 nop look like a function call:
 
 #define nop()   #asm  nop  #endasm
 
 sleep();
 nop();
 
 .................... while (1)
 .................... {
 ....................     sleep();
 *
 0012:  SLEEP
 ....................     if (flag)
 ....................     {
 0013:  MOVF   flag,F   // This instruction is pre-fetched !
 0014:  BTFSC  STATUS.2
 0015:  GOTO   018
 ....................        flag = 0;
 0016:  CLRF   flag
 ....................    }
 ....................    else
 ....................    {
 |  |  
		|  |  
		| MikeValencia 
 
 
 Joined: 04 Aug 2004
 Posts: 238
 Location: Chicago
 
 
			        
 
 | 
			
				|  |  
				|  Posted: Tue Aug 31, 2004 7:50 am |   |  
				| 
 |  
				| Thanks PCM. You saved me a lot of time scratching my head. 
 What would happen would be, at the first wakeup from sleep, my else{} stuff would run, then at the next interrupt, the if{} stuff would run. It would happen every other interrupt. That's exactly the effect of what you described.
 
 It should work fine now.
 By the way, I don't think i need to use inline assembly to get a NOP. delay_cycles() should do the trick, i think.
 |  |  
		|  |  
		|  |  
  
	| 
 
 | 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
 
 |