Entering IDLE mode within Timer0

To keep very accurate timing during ACTIVE and IDLE modes I would like to push the core into IDLE mode and pull it out within Timer0. When I try to do this the system hangs. If I simply set a flag and have the main loop set PCON.IDLE it works fine. It is written in assembler and I am checking the push/pop stuff. I think the problem is in RETI. What happens to the hardware with RETI? Any help or pointers would be great.

Parents
  • I found a way. Simply push a new address onto the stack and run RETI. The new address is popped and at that point you can enter idle.

    Thanks.

    TIMER_0_ISR:
    	PUSH 	ACC
    	PUSH 	PSW
    	MOV  	PSW,#00H
    	PUSH 	AR6
    	PUSH 	AR7
    	USING	0
    	ANL		RFMAIN,#0F8H			; power up the main osc
    
    ;wait at least 5 mS for 14.7456MHz clock to start
    	MOV  	R7,#09H
    loop:
    	MOV  	R6,AR7
    	DEC  	R7
    	MOV  	A,R6
    	JNZ  	loop
    
    	ANL  	X32CON,#0FEH			; switch clock to main osc
    	NOP								; wait 3 clock periods (3/4 of a instruction cycle)
    									; for glitch free operation, Datasheet p33
    
    	MOV  	TH0,#TIMER0_ACTIVE_H	; set Timer0 counters
    	MOV  	TL0,#TIMER0_ACTIVE_L
    
            PUSH 	B						; push remaining registers now that we are running at 14MHz
    	PUSH 	DPH
    	PUSH 	DPL
    	PUSH 	AR0
    	PUSH 	AR1
    	PUSH 	AR2
    	PUSH 	AR3
    	PUSH 	AR4
    	PUSH 	AR5
    	USING	0
    	LCALL	TIMER_0_c_ISR
    	POP  	AR5
    	POP  	AR4
    	POP  	AR3
    	POP  	AR2
    	POP  	AR1
    	POP  	AR0
    	POP  	DPL
    	POP  	DPH
    	POP  	B
    	POP  	AR7
    	POP  	AR6
    ; Put return address to code on stack
    	MOV     A, #LOW(?enter_idle)
    	PUSH    ACC
    	MOV     A, #HIGH(?enter_idle)
    	PUSH    ACC
    	RETI
    
    ?enter_idle:
    	ORL  	X32CON,#01H		; switch to 32kHz clock
    
    ; wait 3 clock periods (3/4 of a instruction cycle) for glitch
    ; free operation, Datasheet p33
    	NOP
    	MOV  	RFMAIN,#03EH	; power down the RF and main osc
    	ORL     PCON, #0x01                     ; Enter idle mode
    	NOP                                     ; For safety
    	POP  	PSW
    	POP  	ACC
    	RETI
    	END
    
    

Reply
  • I found a way. Simply push a new address onto the stack and run RETI. The new address is popped and at that point you can enter idle.

    Thanks.

    TIMER_0_ISR:
    	PUSH 	ACC
    	PUSH 	PSW
    	MOV  	PSW,#00H
    	PUSH 	AR6
    	PUSH 	AR7
    	USING	0
    	ANL		RFMAIN,#0F8H			; power up the main osc
    
    ;wait at least 5 mS for 14.7456MHz clock to start
    	MOV  	R7,#09H
    loop:
    	MOV  	R6,AR7
    	DEC  	R7
    	MOV  	A,R6
    	JNZ  	loop
    
    	ANL  	X32CON,#0FEH			; switch clock to main osc
    	NOP								; wait 3 clock periods (3/4 of a instruction cycle)
    									; for glitch free operation, Datasheet p33
    
    	MOV  	TH0,#TIMER0_ACTIVE_H	; set Timer0 counters
    	MOV  	TL0,#TIMER0_ACTIVE_L
    
            PUSH 	B						; push remaining registers now that we are running at 14MHz
    	PUSH 	DPH
    	PUSH 	DPL
    	PUSH 	AR0
    	PUSH 	AR1
    	PUSH 	AR2
    	PUSH 	AR3
    	PUSH 	AR4
    	PUSH 	AR5
    	USING	0
    	LCALL	TIMER_0_c_ISR
    	POP  	AR5
    	POP  	AR4
    	POP  	AR3
    	POP  	AR2
    	POP  	AR1
    	POP  	AR0
    	POP  	DPL
    	POP  	DPH
    	POP  	B
    	POP  	AR7
    	POP  	AR6
    ; Put return address to code on stack
    	MOV     A, #LOW(?enter_idle)
    	PUSH    ACC
    	MOV     A, #HIGH(?enter_idle)
    	PUSH    ACC
    	RETI
    
    ?enter_idle:
    	ORL  	X32CON,#01H		; switch to 32kHz clock
    
    ; wait 3 clock periods (3/4 of a instruction cycle) for glitch
    ; free operation, Datasheet p33
    	NOP
    	MOV  	RFMAIN,#03EH	; power down the RF and main osc
    	ORL     PCON, #0x01                     ; Enter idle mode
    	NOP                                     ; For safety
    	POP  	PSW
    	POP  	ACC
    	RETI
    	END
    
    

Children
More questions in this forum