PDA

View Full Version : help: TMR0 interrupts disabling PORTAchange interrupts???



xnihilo
- 18th August 2008, 11:50
Hello,

Once again, I will need some clever advise.

I'm using interrupts triggered by changes on PORTA pins. I also need to increment a timer for a 5 minutes countdown while leaving the interrupts for PORTA and having my main loop being a @SLEEP.
My problem is that when the countdown begins and I get back to the main loop (where I skip the @SLEEP because it would freeze my timer and use a loop with a 15Us pause instead), it does not react to PORTA interrupts anymore.
There is an LCDOUT in my main loop and the display seems to be refreshed very quicly and at a given period of time it jumps to the right routine in my INT handler to display the countdown (it updates the counter state avery 30s).

Below is the code, maybe if you have a look you will see what I don't see, probably an obvious error... Thanks for any help.




'-------------------------------------------------------------------------------

a = PORTA 'clear any mismatch with latched values


LCDOUT $fe,1,"1st A=",#a 'output ascii value of variable a: 47, %00|101|111
PAUSE 3000

'MEMO: GIE is handled by PBP !!! Don't enable GIE bit manually or expect troubles!
'Contribution from Darrel Taylor, www.picbasic.co.uk/forum/

INTCON = %00001000 'val=8, enable porta interrupts on change, clear interrupt flags, datasheet p13
' flag (bit0) for portA INT must be cleared by software after int occurs

'All A port pins trigger an int


IOCA = %111111 'enable interrupts on change individually (RA5 is used for handshaking with gun unit, default is 0v)
IOCB = %0000


'If enabling INT for RA3 and no WPU is used, it triggers ints!!!

'Do not leave input (high impedance) pins floating
'-------------------------------------------------------------------------------






'-------------------------------------------------------------------------------
ON INTERRUPT GOTO in_sig 'when interrupt occurs on any portA pin
'-------------------------------------------------------------------------------

loop1: 'main program is a stupid loop waiting for a int on change triggered by an ir signal on sensors or input on supply port
'put MCU to sleep in low power mode until an int awakens it
LCDOUT $fe,1,"crit=",#critical

IF (critical == 1) THEN 'we can't use "@sleep" when using TMR0 because when at sleep, TMR0 is frozen
PAUSEUS 15 'minimum pause length at 8MHz
'waits for a int of TMR0 or any other int
ELSE
@ SLEEP
ENDIF
GOTO loop1

'################################################# ##############################

DISABLE 'disable individual interrupts while executing the interrupt routine (do not put check interrupts calls after each instruction)


in_sig:

a = porta

IF ((critical == 1) && (INTCON.2 == 1)) THEN count_down 'if flag is set for interrupt because of TMR0 overflow








IF (damage >= 100) THEN '0-99% damage, player is alive, 100 and over means player is dead
IF (healed == 1) THEN 'if healed already, there will be no critical condition, player dies
dead = 1
WRITE dead_,dead
READ dead_,tempvar
IF (tempvar != dead) then
SOUND speaker,[100,200]
LCDOUT $fe,1,"RoR"
PAUSE 2000
ENDIF
ELSE 'if not already healed, player will enter critical condition for 5 minutes within which he can be patched and go back to 75% damage
LCDOUT $fe,1,"CritSts"
PAUSE 2000

critical = 1 'from now on, player will be in critical condition for 5min and can be patched and still be hit
countdown = 0 'clear the countdown timer
TMR0 = 98 'set the offset (for 10ms duration with 1:128 at 8MHz)
INTCON.2 = 0 'clear TMR0 overflow flag
INTCON.5 = 1 'enable TMR0 overflow INT (GIE will be set by PBP at the end of the int handler
HIGH speaker 'output sound on speaker or buzzer
'player won't send status back to gun, so if AC is enabled, gun cannot be operated
ENDIF
ENDIF












'--------------------------------------------------------------------------------------------------------------------------------------------
count_down:

'routine that increases the countdown when in critical condition
'the update/increment of the timer happen every 10ms

alert = (alert + 1)
IF (alert == 30000) THEN 'at every 30s
LCDOUT $fe,1,"countdown:"
LCDOUT $fe,$C0,#countdown
PAUSE 1000
countdown = (countdown + 1)
alert = 0
ENDIF
IF (countdown == 10) THEN 'if 30s elapsed, player dies
LCDOUT $fe,1,"CntDwnEND"
PAUSE 3000
INTCON.5 = 0 'disable TMR0 overflow int
TMR0 = 0 'stop tmr0
INTCON.2 = 0 'reset int flag
LOW speaker 'use a 5V piezzo buzzer, not a speaker
GOTO died
ENDIF

GOTO finish














finish:

a = porta 'mirror porta and clear the mismatch, refresh latches
INTCON.0 = 0

resume 'end int routine

enable 'REENABLING GIE, PBP lame instruction


END 'end of program




I read my code again and again and the following line just at the begining of my interrupts handler may cause a problem:


IF ((critical == 1) && (INTCON.2 == 1)) THEN count_down 'if flag is set for interrupt because of TMR0 overflow

because when entering the interrupts handler, if the "critical" called variable is set and the flag for TMR0 overflow interrupt is set (what will probably be the case if I'm stupid enough not to clear it before leaving the int handler routine) then it will jump to the code that handles the interrupt that occured because of the TMR0 overflow, and I guess that if an int occurs because of a change on PORTA, it will be kinda ignored because the conditions are met for TMR0 overflow interrupt before it is even checked for PORTA change ??? ...

I should probably use:


IF ((INTCON.0 == 0) && (critical == 1) && (INTCON.2 == 1)) THEN count_down 'if flag is set for interrupt because of TMR0 overflow
instead and check that I reset the flag for TMR0 overflow interrupt everytime this INT occurs


count_down:

'routine that increases the countdown when in critical condition
'the update/increment of the timer happen every 10ms

INTCON.2 = 0 'reset int flag <<<<<<--- Reset the flag for TMR0 overflow before leaving the INT handler

alert = (alert + 1)
IF (alert == 30000) THEN 'at every 30s
LCDOUT $fe,1,"countdown:"
LCDOUT $fe,$C0,#countdown
PAUSE 1000
countdown = (countdown + 1)
alert = 0
ENDIF

skimask
- 18th August 2008, 18:08
ENABLE
doesn't reenable GIE. It's a compiler directive that tells PBP to start checking again for interrupts.
As far as I know, there's only 2 ways to reenable GIE...RESUME, in PBP, (RETFIE in assembly), which sets it automatically upon execution, and manually setting the bit.

xnihilo
- 19th August 2008, 08:49
Reseting the TMR0 ovf flag and the TMR0 preload value before leaving handler and checking what int flag are set upon entering the int handler did the trick.
More funny, the int period is now all right (about 10ms)... What is strange is that I did not change a lot of things besides setting the preload for TMR0 before leaving the int handler...

Skimask: yes, the code comments were a bit wrong I agree.
RESUME, ENABLE. I changed the comments in my program :)
As you may have noticed I'm not very strict when I write my code and my comments. I should be more cautious because other people may/will read and use the code...
My brother always tells me that my code is a mess... He's right :)

This forum is such a great place.
I have to reference it in my code so people reading it will know that if I could finish my projects it is because many people on this forum guided me and even sometimes gave me the answers.

Cool forum!

Archangel
- 19th August 2008, 10:37
Reseting the TMR0 ovf flag and the TMR0 preload value before leaving handler and checking what int flag are set upon entering the int handler did the trick.
More funny, the int period is now all right (about 10ms)... What is strange is that I did not change a lot of things besides setting the preload for TMR0 before leaving the int handler...

Skimask: yes, the code comments were a bit wrong I agree.
RESUME, ENABLE. I changed the comments in my program :)
As you may have noticed I'm not very strict when I write my code and my comments. I should be more cautious because other people may/will read and use the code...
My brother always tells me that my code is a mess... He's right :)

This forum is such a great place.
I have to reference it in my code so people reading it will know that if I could finish my projects it is because many people on this forum guided me and even sometimes gave me the answers.

Cool forum!
More Importantly, You will come back to your code, long after you have forgotten the details
and will have to wade through it and try to remember . . . whereas, properly commented code will be easy, sensible, and readable. Spend a little time now or a lot later.
Happy you got it working! Zot! Tag, you're it! :)

skimask
- 19th August 2008, 15:10
Reseting the TMR0 ovf flag and the TMR0 preload value before leaving handler and checking what int flag are set upon entering the int handler did the trick.
More funny, the int period is now all right (about 10ms)... What is strange is that I did not change a lot of things besides setting the preload for TMR0 before leaving the int handler...

I guess my main point about ENABLE was that if you ENABLE'd while still processing the interrupt, it'll 'interrupt' right there and you could get stuck in that same loop until you just happen to get lucky and can get out.