We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
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.
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
Hi Michael, There are some problems with the code you have posted, your routine ?enter_idle does things in the wrong order, the POP PSW and POP ACC will NEVER be executed because the processor is in idle mode so obviously? the stack will eventually overflow and may cause problems in other parts of your program. You also need to remove the Timer0 ISR return address off the stack so if you modify your code from where timer is reloaded to be as follows it should work better for you.
MOV TH0,#TIMER0_ACTIVE_H ; set Timer0 counters MOV TL0,#TIMER0_ACTIVE_L 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: POP PSW POP ACC DEC SP ;remove original 'return from interrupt' address DEC SP 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 ; RET ; Can never be executed! END