M
Mark Jones
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Rob wrote:
| I've got what I think is an interrupt problem with a simple optical
encoder
| / PIC 16F628 circuit.
|
| The PIC loops around and sends the encoder count values out when a
counter
| in the main loop expires. The encoder is read and the count updated
when the
| encoder input generates a falling edge interrupt on RBO. It all
works fine,
| however every now and again it will crash and cease sending out the
count
| data. This only seems to happen if the encoder is changing position.
I think
| the problem may be do do with my context saving.
|
| The encoder is a quadrature optical unit, which is powered up
intermittently
| at around 2kHz. Some glue logic grabs the status and presents it to
the PIC.
| A falling edge on RBO means a step has occurred, with the direction
| indicated by the second input on RB3. All of this works fine.
|
|
| Clock
| |
| Power switch
| |
| Encoder --> Glue Logic --> PIC - RB0 (Step) / RB3 (Dir)
|
|
|
| I've pasted the relevant code sections below - can anyone see where I am
| going wrong?
|
| Many thanks.
| rob
|
|
;##########################################################################
| ORG 04H ;INTERRUPT VECTOR
| ;SAVE CONTEXT BEFORE SERVICING INTERRUPT
| MOVWF W_TEMP ;COPY W TO W_TEMP REGISTER
| SWAPF STATUS,W ;COPY STATUS REG INTO W
| CLRF STATUS ;BANK ZERO
| MOVWF STATUS_TEMP ;SAVE STATUS IN STATUS_TEMP
|
| MOVF PCLATH,W ;COPY PCLATH INTO W
| MOVWF PCLATH_TEMP ;SAVE PCLATH IN PCLATH_TEMP
| CLRF PCLATH ;CLR PCLATH - GOTO PAGE 0, ONLY REQ IF USING PAGES 1,2
AND
| /OR 3
| MOVF FSR,W ;COPY FSR TO W
| MOVWF FSR_TEMP ;COPY FSR FROM W TO FSR_TEMP
| ;CONTEXT SAVED
|
| ;IDENTIFY INTERRUPT SOURCE
| ;BTFSC INTCON,INTF ;IS INT DUE TO A RB0 TRANSITION?
| BCF INTCON,INTE ;DISABLE RBO INTERRUPT
| CALL ISR_ENC ;YES - SO SERVICE ENCODER STEP INTERRUPT
|
| ;RE-ENABLE PORTB INTERRUPT AFTER SERVICING...........
| BCF INTCON,INTF
| BSF INTCON,INTE
| ;NO MORE INTERRUPTS
|
| ISR_DONE ;RESTORE CONTEXT PREVIOUSLY SAVED
| MOVF PCLATH_TEMP,W ;RESTORE PCLATH
| MOVWF PCLATH
| SWAPF STATUS_TEMP,W ;RESTORE STATUS
| MOVWF STATUS ;RESTORES TO ORIGINAL BANK
| SWAPF W_TEMP,F ;SWAP W_TEMP
| SWAPF W_TEMP,W ;W_TEMP INTO W
| MOVF FSR_TEMP,W ;RESTORE FSR
| MOVWF FSR
| RETFIE ;RETURN FROM INTERRUPT - ALSO RESETS GIE BIT CLEARED BY
INTERRUPT
|
;##########################################################################
|
| ;MAIN LOOP
|
|
| CALL INIT_INTERRUPTS
| HERE
| INCFSZ TX_CNT1,1 ;loop until ctr overflows and then send out
count data
| GOTO HERE
| INCFSZ TX_CNT2,1
| GOTO HERE
| CALL CNT2SER ;CONVERTS HEX COUNT TO ASCII & SENDS OUT SERIAL
| GOTO HERE
|
|
|
;##########################################################################
| ISR_ENC ;SERVICE ENCODER STEP INTERRUPT - ENCODER CHECK ROUTINE
|
;##########################################################################
| BTFSS DIR ;IS DIR HIGH?
| GOTO CCW ;DIR=0 SO STEP IS CCW
| GOTO CW ;DIR=1 SO STEP IS CW
|
|
| CW ;INCREMENT 24 BIT COUNTER
| ;/TEST
| LED2_PULSE ;PULSES LED2
| LED1_ON
| ;/END TEST
| INCFSZ CTR0,1
| RETURN
| INCF CTR1,1
| RETURN
|
| CCW ;DECREMENT 24 BIT COUNTER
| ;/TEST
| LED2_PULSE ;PULSES LED2
| LED1_OFF
| ;/END TEST
|
| DECF CTR0,1
| INCFSZ CTR0,0 ;TEST FOR FF 'UNDERFLOW'
| RETURN ;NO UNDERFLOW
| DECF CTR1,1
| RETURN ;NO UNDERFLOW
|
|
;##########################################################################
| INIT_INTERRUPTS
|
;##########################################################################
| GOBANK1 ;CONFIG RB0 EDGE ETC
| BCF OPTION_REG,INTEDG ;CLEARED FOR FALLING EDGE INTERRUPT
| GOBANK0
| BCF INTCON,INTF ;ENSURE EXT INT FLAG IS CLEAR
| BSF INTCON,INTE ;ENABLE RB0 INT
| CLRF PIR1 ;CLEAR INT FLAGS
| BSF INTCON,GIE ;ENABLE GIE <7>,
| RETURN
|
;##########################################################################
|
|
~ Your LED2_PULSE and LED1_OFF, what do they do?
~ The optical encoder, is it measuring something fast? Precise? Or is
it just being used as a knob? (100ms sample rate is much easier to
deal with than 2kHz.)
~ The general rule of thumb regarding ISR's & PICs is A) 95% of the
time they are not needed, B) they should be very short, and C) all
port activity has to be double-buffered. (Think, what happens if an
interrupt occurs while a port is being modified?)
~ That said, if the encoder is suppling a very fast interrupt, what
happens if another interrupt occurs before the line
~ BCF INTCON,INTE ;DISABLE RBO INTERRUPT
~ ?
- -- The answer is fractals. http://www.lilavois.com/nick/fractals/.
Chaos theory. http://www.softology.com.au/voc.htm. Infinite
complexity. Everything that we see around us is somehow related to an
infnitely complex, unbalanced dynamic. But what could that be?
~ Mark Jones / Helios Studios
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.0 (MingW32)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org
iD8DBQFB34RJUoq45ERxHvoRAvgKAJ42I9VHGwHJRixBgPiCbjE+B9TERwCfc2Wr
fWQ28XAUMRvoPfzP8utT3qk=
=YUFk
-----END PGP SIGNATURE-----
Hash: SHA1
Rob wrote:
| I've got what I think is an interrupt problem with a simple optical
encoder
| / PIC 16F628 circuit.
|
| The PIC loops around and sends the encoder count values out when a
counter
| in the main loop expires. The encoder is read and the count updated
when the
| encoder input generates a falling edge interrupt on RBO. It all
works fine,
| however every now and again it will crash and cease sending out the
count
| data. This only seems to happen if the encoder is changing position.
I think
| the problem may be do do with my context saving.
|
| The encoder is a quadrature optical unit, which is powered up
intermittently
| at around 2kHz. Some glue logic grabs the status and presents it to
the PIC.
| A falling edge on RBO means a step has occurred, with the direction
| indicated by the second input on RB3. All of this works fine.
|
|
| Clock
| |
| Power switch
| |
| Encoder --> Glue Logic --> PIC - RB0 (Step) / RB3 (Dir)
|
|
|
| I've pasted the relevant code sections below - can anyone see where I am
| going wrong?
|
| Many thanks.
| rob
|
|
;##########################################################################
| ORG 04H ;INTERRUPT VECTOR
| ;SAVE CONTEXT BEFORE SERVICING INTERRUPT
| MOVWF W_TEMP ;COPY W TO W_TEMP REGISTER
| SWAPF STATUS,W ;COPY STATUS REG INTO W
| CLRF STATUS ;BANK ZERO
| MOVWF STATUS_TEMP ;SAVE STATUS IN STATUS_TEMP
|
| MOVF PCLATH,W ;COPY PCLATH INTO W
| MOVWF PCLATH_TEMP ;SAVE PCLATH IN PCLATH_TEMP
| CLRF PCLATH ;CLR PCLATH - GOTO PAGE 0, ONLY REQ IF USING PAGES 1,2
AND
| /OR 3
| MOVF FSR,W ;COPY FSR TO W
| MOVWF FSR_TEMP ;COPY FSR FROM W TO FSR_TEMP
| ;CONTEXT SAVED
|
| ;IDENTIFY INTERRUPT SOURCE
| ;BTFSC INTCON,INTF ;IS INT DUE TO A RB0 TRANSITION?
| BCF INTCON,INTE ;DISABLE RBO INTERRUPT
| CALL ISR_ENC ;YES - SO SERVICE ENCODER STEP INTERRUPT
|
| ;RE-ENABLE PORTB INTERRUPT AFTER SERVICING...........
| BCF INTCON,INTF
| BSF INTCON,INTE
| ;NO MORE INTERRUPTS
|
| ISR_DONE ;RESTORE CONTEXT PREVIOUSLY SAVED
| MOVF PCLATH_TEMP,W ;RESTORE PCLATH
| MOVWF PCLATH
| SWAPF STATUS_TEMP,W ;RESTORE STATUS
| MOVWF STATUS ;RESTORES TO ORIGINAL BANK
| SWAPF W_TEMP,F ;SWAP W_TEMP
| SWAPF W_TEMP,W ;W_TEMP INTO W
| MOVF FSR_TEMP,W ;RESTORE FSR
| MOVWF FSR
| RETFIE ;RETURN FROM INTERRUPT - ALSO RESETS GIE BIT CLEARED BY
INTERRUPT
|
;##########################################################################
|
| ;MAIN LOOP
|
|
| CALL INIT_INTERRUPTS
| HERE
| INCFSZ TX_CNT1,1 ;loop until ctr overflows and then send out
count data
| GOTO HERE
| INCFSZ TX_CNT2,1
| GOTO HERE
| CALL CNT2SER ;CONVERTS HEX COUNT TO ASCII & SENDS OUT SERIAL
| GOTO HERE
|
|
|
;##########################################################################
| ISR_ENC ;SERVICE ENCODER STEP INTERRUPT - ENCODER CHECK ROUTINE
|
;##########################################################################
| BTFSS DIR ;IS DIR HIGH?
| GOTO CCW ;DIR=0 SO STEP IS CCW
| GOTO CW ;DIR=1 SO STEP IS CW
|
|
| CW ;INCREMENT 24 BIT COUNTER
| ;/TEST
| LED2_PULSE ;PULSES LED2
| LED1_ON
| ;/END TEST
| INCFSZ CTR0,1
| RETURN
| INCF CTR1,1
| RETURN
|
| CCW ;DECREMENT 24 BIT COUNTER
| ;/TEST
| LED2_PULSE ;PULSES LED2
| LED1_OFF
| ;/END TEST
|
| DECF CTR0,1
| INCFSZ CTR0,0 ;TEST FOR FF 'UNDERFLOW'
| RETURN ;NO UNDERFLOW
| DECF CTR1,1
| RETURN ;NO UNDERFLOW
|
|
;##########################################################################
| INIT_INTERRUPTS
|
;##########################################################################
| GOBANK1 ;CONFIG RB0 EDGE ETC
| BCF OPTION_REG,INTEDG ;CLEARED FOR FALLING EDGE INTERRUPT
| GOBANK0
| BCF INTCON,INTF ;ENSURE EXT INT FLAG IS CLEAR
| BSF INTCON,INTE ;ENABLE RB0 INT
| CLRF PIR1 ;CLEAR INT FLAGS
| BSF INTCON,GIE ;ENABLE GIE <7>,
| RETURN
|
;##########################################################################
|
|
~ Your LED2_PULSE and LED1_OFF, what do they do?
~ The optical encoder, is it measuring something fast? Precise? Or is
it just being used as a knob? (100ms sample rate is much easier to
deal with than 2kHz.)
~ The general rule of thumb regarding ISR's & PICs is A) 95% of the
time they are not needed, B) they should be very short, and C) all
port activity has to be double-buffered. (Think, what happens if an
interrupt occurs while a port is being modified?)
~ That said, if the encoder is suppling a very fast interrupt, what
happens if another interrupt occurs before the line
~ BCF INTCON,INTE ;DISABLE RBO INTERRUPT
~ ?
- -- The answer is fractals. http://www.lilavois.com/nick/fractals/.
Chaos theory. http://www.softology.com.au/voc.htm. Infinite
complexity. Everything that we see around us is somehow related to an
infnitely complex, unbalanced dynamic. But what could that be?
~ Mark Jones / Helios Studios
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.0 (MingW32)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org
iD8DBQFB34RJUoq45ERxHvoRAvgKAJ42I9VHGwHJRixBgPiCbjE+B9TERwCfc2Wr
fWQ28XAUMRvoPfzP8utT3qk=
=YUFk
-----END PGP SIGNATURE-----