Interrupt firing twice in a row???
ok guys,
I'm having trouble with an interrupt routine firing twice in a row.
The interrupt is an external interrupt, set on pin RB0.
The interrupt routine fires on RB.0 rising edge. The routine
is a simple routine, that sets Pin RC.1 High, runs a delay, and
then sets RC.1 Low before RETI.
If I debug the code, it runs as expected. However, if I run it at
50Mhz, with a square wave on RB.0, I see that the interrupt runs
twice in a row.
I'm not sure what is going on. Any suggestions?
Thanks,
-Dan
Here is an example code that displays this problem:
;
Program Start
··NOCASE···;No Case Sensitive ASM
··DEVICE·SX28L··;28 pin chip
··DEVICE· OSCHS2··;(OSC or External TTL OSC)
··DEVICE·STACKX··;Use the Extended Stack.
··DEVICE· IFBD··;Disable Internal Feedback.
··DEVICE· TURBO··;Turbo Mode
··IRC_CAL·IRC_FAST·;(Faster programming)
··FREQ·50_000_000 ·;START WITH A 50MHz Clock
··RESET ·ResetVector
;
CONSTANTS
;Setup ADC Pins.
DataIn EQU·RB.0
Debug0·EQU·RC.0
Debug1·EQU·RC.1
Debug2·EQU·RC.2
Debug3· EQU·RC.3
;Setup Bank Constants
Bank7·EQU ·$F0
;
VARIABLES
ORG·$08
Count1··DS·1··;Allocate 1 Byte.
Count2··DS·1··;Allocate 1 Byte.
··ORG·Bank7·;Byte·Start in Memory Bank 7
DataInCnt1·DS·1·; F0·Data In Counter 1
;
INTERRUPT ROUTINE
··ORG·0
··SetB·Debug1
··MOV·DataInCnt1,#10
··;Delay
DataReadLp1·DECSZ·DataInCnt1
··JMP·DataReadLp1
··CLRB·Debug1··;Test Debug Bit.
··;Clear the Pending Register to allow interrupts.
··MODE ·#09··;Set Mode for Pend reg Check.
··MOV ·!rb,#%00000000·;Clears the Pending Register.
··RETI···;Exit The Interrupt Routine
;
End INTERRUPT ROUTINE
;
Reset Vector is here
ORG··$1FE···;Reset on Page $00
ResetVector·JMP·@Page1··;Now Jump to Page $01
;
Start of Pogram on Page 01
ORG ··$200···;Start on Page 01
Page1
··CLRB·Debug0
··CLRB·Debug1
··CLRB·Debug2
··CLRB·Debug3
··;Disable RTCC Interrupts.
··MOV·!OPTION, #%01000000
··;Set Edge Detection Pins (Poat
.
··MODE·$0A··; 0 = Rising Edge, 1 = Falling Edge
··MOV·!rb,#%00000000·;
··;Setup Schmitt Trigger
··MODE ·$0C
··MOV·!rb,#%11111110·;0 = Schmitt, 1 = Normal
··MOV·!rc,#%11111111·;
··;Set Logic Levels
··MODE ·$0D
··MOV·!ra,··· #%1111·; 0 = CMOS, 1 = TTL
··MOV·!rb,#%11111111·;
··MOV·!rc,#%11111111·;
··;Set PULL-UP Resistors
··MODE·$0E
··MOV·!ra,··· #%1111·; 0 = pullup, 1 = Disabled
··MOV·!rb,#%11111111·;
··MOV·!rc,#%11111111·;
··;Set Directions
··MODE ·$0F··
··MOV·!ra,··· #%0000·; 0 = Output, 1 = Input
··MOV·!rb,#%00000001·;
··MOV·!rc,#%00000000·;
··;Clear the Pending Register to allow interrupts.
··MODE ·#09··;Set Mode for Pend reg Check.
··MOV ·!rb,#%00000000·;Clears the Pending Register.
··;Set Mode to allow Wakeup (Edge Interrupts).
··MODE·$0B··; 0 = WakeUp, 1 = Normal
··MOV·!rb,#%11111110·;
··JMP ·@MainProg
;
End of Initialization Routine.
;
Main Program
MainProg·;Main program Polling Loop
··NOP
··SETB ·Debug3
··NOP
··CLRB·Debug3
MainTestloop·NOP
··JMP ·MainProg
;
·End of Main Program Loop
·
I'm having trouble with an interrupt routine firing twice in a row.
The interrupt is an external interrupt, set on pin RB0.
The interrupt routine fires on RB.0 rising edge. The routine
is a simple routine, that sets Pin RC.1 High, runs a delay, and
then sets RC.1 Low before RETI.
If I debug the code, it runs as expected. However, if I run it at
50Mhz, with a square wave on RB.0, I see that the interrupt runs
twice in a row.
I'm not sure what is going on. Any suggestions?
Thanks,
-Dan
Here is an example code that displays this problem:
;
Program Start
··NOCASE···;No Case Sensitive ASM
··DEVICE·SX28L··;28 pin chip
··DEVICE· OSCHS2··;(OSC or External TTL OSC)
··DEVICE·STACKX··;Use the Extended Stack.
··DEVICE· IFBD··;Disable Internal Feedback.
··DEVICE· TURBO··;Turbo Mode
··IRC_CAL·IRC_FAST·;(Faster programming)
··FREQ·50_000_000 ·;START WITH A 50MHz Clock
··RESET ·ResetVector
;
CONSTANTS
;Setup ADC Pins.
DataIn EQU·RB.0
Debug0·EQU·RC.0
Debug1·EQU·RC.1
Debug2·EQU·RC.2
Debug3· EQU·RC.3
;Setup Bank Constants
Bank7·EQU ·$F0
;
VARIABLES
ORG·$08
Count1··DS·1··;Allocate 1 Byte.
Count2··DS·1··;Allocate 1 Byte.
··ORG·Bank7·;Byte·Start in Memory Bank 7
DataInCnt1·DS·1·; F0·Data In Counter 1
;
INTERRUPT ROUTINE
··ORG·0
··SetB·Debug1
··MOV·DataInCnt1,#10
··;Delay
DataReadLp1·DECSZ·DataInCnt1
··JMP·DataReadLp1
··CLRB·Debug1··;Test Debug Bit.
··;Clear the Pending Register to allow interrupts.
··MODE ·#09··;Set Mode for Pend reg Check.
··MOV ·!rb,#%00000000·;Clears the Pending Register.
··RETI···;Exit The Interrupt Routine
;
End INTERRUPT ROUTINE
;
Reset Vector is here
ORG··$1FE···;Reset on Page $00
ResetVector·JMP·@Page1··;Now Jump to Page $01
;
Start of Pogram on Page 01
ORG ··$200···;Start on Page 01
Page1
··CLRB·Debug0
··CLRB·Debug1
··CLRB·Debug2
··CLRB·Debug3
··;Disable RTCC Interrupts.
··MOV·!OPTION, #%01000000
··;Set Edge Detection Pins (Poat

··MODE·$0A··; 0 = Rising Edge, 1 = Falling Edge
··MOV·!rb,#%00000000·;
··;Setup Schmitt Trigger
··MODE ·$0C
··MOV·!rb,#%11111110·;0 = Schmitt, 1 = Normal
··MOV·!rc,#%11111111·;
··;Set Logic Levels
··MODE ·$0D
··MOV·!ra,··· #%1111·; 0 = CMOS, 1 = TTL
··MOV·!rb,#%11111111·;
··MOV·!rc,#%11111111·;
··;Set PULL-UP Resistors
··MODE·$0E
··MOV·!ra,··· #%1111·; 0 = pullup, 1 = Disabled
··MOV·!rb,#%11111111·;
··MOV·!rc,#%11111111·;
··;Set Directions
··MODE ·$0F··
··MOV·!ra,··· #%0000·; 0 = Output, 1 = Input
··MOV·!rb,#%00000001·;
··MOV·!rc,#%00000000·;
··;Clear the Pending Register to allow interrupts.
··MODE ·#09··;Set Mode for Pend reg Check.
··MOV ·!rb,#%00000000·;Clears the Pending Register.
··;Set Mode to allow Wakeup (Edge Interrupts).
··MODE·$0B··; 0 = WakeUp, 1 = Normal
··MOV·!rb,#%11111110·;
··JMP ·@MainProg
;
End of Initialization Routine.
;
Main Program
MainProg·;Main program Polling Loop
··NOP
··SETB ·Debug3
··NOP
··CLRB·Debug3
MainTestloop·NOP
··JMP ·MainProg
;
·End of Main Program Loop
·
Comments
Check for ringing at the input.
Bean.
Also, you should NEVER NEVER NEVER run a delay in an ISR.· Toggle the pin, if that will work.· Set a flag, and use the flag in your 'main' routine to pulse the pin.·
An ISR is an Interrupt.· It's something in the real-world saying 'notice me'.· Your ISR should be fast and quick -- do something simple to record the interrupt and return.· While you are in the ISR you are ignoring other things that could interrupt, which is not good.
Post Edited (allanlane5) : 10/29/2004 1:46:57 PM GMT
Just to answer a few questions right off the bat, I've scoped the input and there is no ringing on it. The test signal is a relatively slow rising edge signal from a TTL sig-gen coming down a 50Ohm coax. (It exponentially reaches the logic "high" several uS before the interrupt routine completes)
I did find a solution that I tried to post earlier, but my ISP died.
Basically, it seems that you can’t follow the MOV !rb,#%00000000 with the RETI instruction.
I placed a NOP between them, and the problem goes away. I wish I had my digital camera here at work... ...or my Scope from home (with FDD built in), I'd post a pic of the signal in both cases.
I think it's a glitch in the chip!
Try the code with a scope and sig gen...·· ...let me know what you think.
This code won't work correctly...· ...it runs the Interrupt twice in a row.
··MODE ·#09··;Set Mode for Pend reg Check.
··MOV ·!rb,#%00000000·;Clears the Pending Register.
··RETI···;Exit The Interrupt Routine
This one will fire only once...
··MODE ·#09··;Set Mode for Pend reg Check.
··MOV ·!rb,#%00000000·;Clears the Pending Register.
· NOP
··RETI···;Exit The Interrupt Routine
The instruction is executed, but the port doesn't change till further down the pipeline.
Bean.
actually,
MOV !rb, #%00000000 is a compound instruction which is replaced by
mov w, #%00000000
mov !rb, w
The mov !rb, w is not a "regular" move instruction here, as it actually exchanges the contents of w and the pending register, i.e. after this instruction w contains the current bit pattern in the pending register, and the pending register is zero.
Usually, w and the pending register are exchanged close to the entry of an ISR to determine which port B pin fired the interrupt. Of course, when you know that only pin can fire the interrupt only, there is no need to test it. like in your application.
The nop adds one more clock cycle which overcomes the instruction pipeline effect. On the other hand, you can also place the instruction somewhere at the beginning of the ISR. As clearing the pending bits does not mean that interrupts are enabled again (this is only done by the reti), it does not matter where you do the exchange.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Greetings from Germany,
G
I would have never figured that one out on my own.
Also, I didn't realize that the interrupts are disabled until RETI is run.
(Yep, there it is on page 99 of the manual v2.0!)
The problem is that I'm an analog guy, stuck working with these
MCU's...·· ...so I struggle with the simple stuff sometimes!
Thanks all!
-Dan
·
keep being an "analog guy" this is much more natural to us humans
Do you know the difference between an analog and a digital clock?
The digital clock tells you the time, and the analog clock tells you how late it is.
Have a great weekend!
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Greetings from Germany,
G