Forum Index
ISR lockup

 
Author Message
pjc30943



Joined: 02 Dec 2005

Posted: 08 July 2008, 19:53 PM    Post subject: ISR lockup

The following code fragments seem to correctly set up an INT0 ISR:


Code:
   '~~~~~~~~  INTERRUPTS  ~~~~~~~~~
   Register.EICRA = Bx0101_0101            '0101_0101 = any edge of INT0,1,2,3
   Register.EICRB = Bx0101_0101            'any edge of INT4,5,6,7
   Register.EIMSK = Bx0000_0001   'enable INT0
   const INT_MASK as byte = Bx1000_0000   
   Register.SREG = Register.SREG Or INT_MASK   'enable interrupts
   '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


Code:
ISR INT0()
   'test of manual ISRs
   putpin loopTogglePin, zxOutputToggle
   'debug.print "0"
   're-enable interrupts:
   #asm
      reti   
   #endasm
      
End ISR



loopTogglePin follows the pulsetrain (250 Hz) fairly well, but after several seconds, fails to do so and flatlines.

Here is what the program's debug output looks like:
Code:
ZBasiZBaZBZBaZBZBaZBasic v2.5.2
ZBaZBZBaZBasic v2.5.2
ZBaZBasic ZBaZBZBZBaZBZBaZBZBaZBasic ZBaZBaZBZBaZBZBaZBZBaZBZBaZBZBaZBZBaZBZBaZBasic v2.5.2
ZBasiZBaZBZBaZBZBaZBZBaZBZBaZBZBaZBZBaZBZBaZBasiZBaZBZBaZBZBaZBZBaZBZBaZBZBaZBZBaZBZBaZBZBaZBasic v2.5.2ZBZBasic�ZBaZBZBaZBZBaZBZBaZBasic v2.5.2


Nothing else is running except for an infinite sleep loop. but clearly I'm getting some sort of reset or lockup (stack issues, etc.). Anyone have thoughts on how to debug this?
Back to top
dkinzer
Site Admin


Joined: 03 Sep 2005
Location: Portland, OR

Posted: 08 July 2008, 23:00 PM    Post subject: Re: ISR lockup

pjc30943 wrote:
The following code fragments seem to correctly set up an INT0 ISR:
The reti isn't necessary in the ISR because the compiler includes one automatically (unless you define the ISR with the Naked attribute). Secondly, interrupts are globally enabled by default; you don't need to enable interrupts globally unless you disable them. That said, you should always use an EnableInt() call to enable interrupts instead of trying to manipulate SREG directly.

I made some changes to the code as shown below. This runs with no problem on a ZX-1281n with a debounced switch attached to the INT0 input.
Code:
Const loopTogglePin   as Byte = B.7

ISR INT0()
   'test of manual ISRs
   Call PutPin(loopTogglePin, zxOutputToggle)
End ISR

Sub Main()
   Call PutPin(loopTogglePin, 0)

   '~~~~~~~~  INTERRUPTS  ~~~~~~~~~
   Register.EICRA = Bx0101_0101     '0101_0101 = any edge of INT0,1,2,3
   Register.EICRB = Bx0101_0101     'any edge of INT4,5,6,7
   Register.EIMSK = Bx0000_0001     'enable INT0
End Sub
Back to top
pjc30943



Joined: 02 Dec 2005

Posted: 08 July 2008, 23:36 PM    Post subject:

Thanks Don. It works fine now. [It's pretty darn nice how fast native-mode is.]

I'm curious though why this did not work:
Quote:
Register.SREG = Register.SREG Or INT_MASK
Back to top
dkinzer
Site Admin


Joined: 03 Sep 2005
Location: Portland, OR

Posted: 09 July 2008, 0:41 AM    Post subject:

pjc30943 wrote:
I'm curious though why this did not work:
Quote:
Register.SREG = Register.SREG Or INT_MASK
It's not that it didn't work - just that it is unnecessary (since interrupts are enabled by default). Moreover, if you want to unconditionally enable interrupts use this:
Code:
Call EnableInt(&H80)


More often, though, you'll be enabling interrupts after having disabled them. In that case, however, you want to conditionally re-enable interrupts like this:
Code:
Dim sreg as Byte

sreg = DisableInt()
[ do some stuff here that shouldn't be interrupted ]
Call EnableInt(sreg)

The beauty of this code is that interrupts are enabled only if they were initially enabled. This is important if this code in is a subroutine that is called from some code where interrupts have already been disabled and should remain so.

The real culprit in your original code was the reti that you inserted manually. With that present, the resulting AVR assembly language code for the ISR appeared as shown below, annotated with the original source code. The prologue and epilogue code is added automatically by the compiler to ensure that the integrity of the CPU registers is maintained across the execution of the ISR. The reti that you added manually caused the ISR to return prematurely, leaving 15 bytes on the stack and leaving registers modified. Moreover, the two bytes used for the return address were actually the values that should have been restored to r30 and r31. That is undoubtedly the proximate cause of the "resetting" behavior that you observed. In the unlikely case that the incorrectly used return address just happened to be the correct value, the stack imbalance would eventually cause a stack overflow, again leading to the "resetting" behavior.

Code:
'ISR INT0()

' prologue code
push   r1
push   r0
in   r0, 0x3f
push   r0
eor   r1, r1
push   r18
push   r19
push   r20
push   r21
push   r22
push   r23
push   r24
push   r25
push   r26
push   r27
push   r30
push   r31

'Call PutPin(loopTogglePin, zxOutputToggle)
ldi   r22, 0x04
ldi   r24, 0x07
call   putPin

'#asm
'  reti
'#endasm
reti         <--- this is the culprit

' epilogue code
pop   r31
pop   r30
pop   r27
pop   r26
pop   r25
pop   r24
pop   r23
pop   r22
pop   r21
pop   r20
pop   r19
pop   r18
pop   r0
out   0x3f, r0
pop   r0
pop   r1
reti

'End ISR
Back to top
pjc30943



Joined: 02 Dec 2005

Posted: 09 July 2008, 20:45 PM    Post subject:

That makes sense; thanks Don.
Back to top
Display posts from previous:   
Page 1 of 1

 



ZBasic Microcontrollers Home
All content Copyright © 2005, 2006, 2007, 2008 Elba Corp. All Rights Reserved.
Opinions expressed in posts are those of the author and not necessarily those of Elba Corp.
Powered by phpBB © 2001, 2005 phpBB Group