# Interrupt on change problem, PORTA

Status
Not open for further replies.

#### mjdeez

##### New Member
I have been at this for a few days, and I can't seem to get my PIC 16F690 to go to the ISR via the PORTA IOC on RA0. I'm using MPLAB and a pickit2 with the in-circuit debugger. Just for the heck of it, I was able to get into the ISR by adding some TMR1 code to get the TMR1 to overflow and cause an interrupt.

I do have INTCON, GIE; INTCON, RABIE; and IOCA, 0 all set. The thing I can't wrap my head around is that when I'm my main wait loop at the bottom of my code, I see that the INTCON register reads: 10001000 (GIE and RABIE set). Then when I step through in debug mode, and bring RA0 low, INTCON changes to 10001001, indicating that the RABIF gets set. Why at this point would it not go to ISR? I read that there are different logic levels for the interrupt (schmitt trigger) vs PORT inputs, but if RABIF gets set, I would think that would cause an INT.

Some comments about my code: I want to get the above issue straightened out (or at least understood) before cleaning up the program. This is my first attempt at programming a ucontroller, and now that I'm reading more about it, I realize I need to shorten that ISR and do the setup conditions at startup more efficiently.

Any insight would be very much appreciated.

Code:
;******************************************************************************
;  SOT doubler / tripler / quadrupler with EOT feedback
; *******************************************************************
; * BUGS *
;	1. ISR not working as an interrupt
;	2. Need to put some TMR1F checking to ensure no overflow in EOT / SOT
;	3. SOT / EOT times are backwards. To be swapped...
; *******************************************************************

#include <p16F690.inc>
__config (_INTRC_OSC_NOCLKOUT & _WDT_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _BOR_OFF & _IESO_OFF & _FCMEN_OFF)

cblock     0x20
Delay1               ; Assign an address to label Delay1
Delay2
SOT_Time
EOT_Time
Test_Cnt_i
endc

; Flag Definitions

cblock 0x70     ; put these up in unbanked RAM
W_Save
STATUS_Save
endc

org 0
goto      Start
nop
nop
nop
ISR:
movwf     W_Save
movf      STATUS,w
movwf     STATUS_Save

bcf		STATUS, RP0		; BANK0
bcf		STATUS, RP1		; BANK0
btfsc	PORTA, 0		; DETERMINE STATE OF RA0
goto	ExitISR			; if RB4 is still high, where should we go? Exit, no other INT Enabled

movf	PORTA, W		; clear IOCA INT
bcf		INTCON, RABIF	; clr INT flag
bcf		INTCON, RABIE	; CLR INT EN???????????????????
clrf	TMR1L			;start TMR1
clrf	TMR1H			;start TMR1

btfss	PORTA, 0		;has SOT_IN gone back high?
goto	$-1 ; if not, keep waiting movf TMR1H, W ;when gone back high, save tmr1h only movwf SOT_Time movlw 0x03 ;7000us / 8 = 875d = 36Bh ~= 0300h = 768d x 8 = 6144us subwf SOT_Time, W ;was SOT time roughly greater than 7ms? btfsc W, 7 ; bit 7 of W is set (1) if SOT time too low goto ExitISR ;pulse too short, return to start movlw 0x08 ;15000uS /8 = 1875d = 0753h ~= 0800h = 2048d x 8 = 16384us subwf SOT_Time, W ;was SOT time roughly less than 16ms? btfss W, 7 ; goto ExitISR ; if it is clear, go to start, pulse too long ;add a line here to check that TMR1F still low goto CountDownLoop ;here we know that we have received a genuine SOT signal, finally CountDownLoop: decfsz Test_Cnt_i, F goto SendEOT ; Count down complete, Send EOT and exit the ISR ;send 1 SOT to ATE bcf PORTA, 1 ; RA1 low bsf PORTC, 2 ; RC2 high (LED, TEST) movlw 0x0E ; 11ms passed to time wasting function call TimeWaste_w ; Low for 11ms bsf PORTA, 1 ; RA1 high bcf PORTC, 2 ; RC2 low (LED, TEST) goto EOT_Detect EOT_Detect: btfsc PORTA, 3 ;CHECK EOT FROM ATE goto$-1				; wait for it...

clrf	TMR1L			;start TMR1 on EOT going low
clrf	TMR1H			;start TMR1
btfss	PORTA, 4		;has EOT_IN gone back high?
goto	$-1 ; if not, keep waiting movf TMR1H, W ;when gone back high, save tmr1h only movwf EOT_Time movlw 0xC3 ;50,000uS / 8 = 6250d = 186Ah ~= C300 subwf EOT_Time, W ;was EOT time roughly greater than 50ms? btfsc W, 7 ; bit 7 of W is set (1) if EOT time too low goto EOT_Detect ;pulse too short, return to EOT_start -- ok movlw 0x62 ;200,000uS/8 = 25kd = 61A8h ~= 6200h = 25088d*8 = 200704us subwf SOT_Time, W ;was SOT time roughly less than 200ms? btfss W, 7 ; goto$+1				; for now, just go to next step anyway

; add code here to verify TMR1F still low, or if high clear it and exit ISR

;here we know that we have received a genuine EOT signal
movlw	0x0E			; 11ms passed to time wasting function
call	TimeWaste_w		; waste time, go back to start of countdown loop
goto	CountDownLoop	; go back to start of ISR Count Down Loop
;END ISR

SendEOT:
;send 1 EOT back to ATE after the count down is complete, then exit ISR
bcf		PORTA, 1		; RA1 low
bsf		PORTC, 3		; RC3 high (LED, TEST)
call	TimeWaste_w		; Low for 150ms
bsf		PORTA, 2		; RA2 high
bcf		PORTC, 3		; RC3 low (LED, TEST)
goto	ExitISR

ExitISR:
bsf		INTCON, RABIE	;Enable Ints
movf	STATUS_Save,w
movwf	STATUS
swapf	W_Save,f
swapf	W_Save,w
retfie
; 	return

TimeWaste_w:
; Delay Subroutine.  Enter delays Wreg * 771uS + 5 uS including call and return
;	movlw	0x0E			; passed prior to calling this routine
movwf	Delay2         ;
DelayLoop:
decfsz    Delay1,f       ; Waste time.  Does this need to be initiallized?????????????????
goto      DelayLoop      ; The Inner loop takes 3 instructions per loop * 256 loopss = 768 instructions
decfsz    Delay2,f       ; The outer loop takes and additional 3 instructions per lap * 256 loops
goto      DelayLoop      ; (768+3) * 14 = 10,794 instructions / 1M instructions per second = 10.8mSec.
return

Start:

bcf		STATUS,RP1		;Bank0
bcf		STATUS,RP0		;Bank0
clrf	PORTB
clrf	PORTC

bsf		STATUS,RP0     ; select Register Page 1
clrf	TRISB          ; Make PortA all output
clrf	TRISC          ; Make PortC all output
bsf		TRISC, 0		;Make RC0 an input
bsf		TRISC, 1		;Make RC1 an input

;	movlw	0xFF
;	movwf	TRISA			; MAKE them all inputs first
;	bsf		TRISA, 0		; Make RA0 an input  (SOT_IN)
;	bcf		TRISA, 1		; Make RA1 an output (SOT_OUT)
;	bcf		TRISA, 2		; Make RA2 an output (EOT_OUT)
;	bsf		TRISA, 3		; Make RA3 an input  (EOT_IN)

;copy from DS on PORTA
bcf		STATUS,RP0 		;Bank 0
bcf		STATUS,RP1 		;
clrf	PORTA 			;Init PORTA
bsf		PORTA,0			;Init the INT of PortA (RA0 is set)
bsf		STATUS,RP1 		;Bank 2
clrf	ANSEL 			;digital I/O
bsf 	STATUS,RP0 		;Bank 1
bcf		STATUS,RP1 		;
movlw	09h 			;Set RA<0, 3> as inputs   00001001
movwf	TRISA 			;and set RA<1:2,4,5> as outputs
;end copy

bcf		STATUS, RP0		;BANK0
movf	PORTA, 1		;COPY A TO ITSELF

bsf		STATUS, RP0		;BANK1
bsf		IOCA, 0			; enable IOCA bit 0 (RA0) for interupt OC

bcf		STATUS, RP0		;BACK TO BANK 0
clrf	INTCON
bsf		INTCON, GIE		; ENABLE INTERUPTS  (default)
bsf		INTCON, RABIE	; ENABLE IOC ON PORTA, PORTB

bcf		T1CON, TMR1CS	; SET THE CLOCK SOURCE TO FOSC / 4 (by def anyway)
bcf		T1CON, T1CKPS0	; SET THE T1 PRESCALER TO 1:8
bcf		T1CON, T1CKPS1	; SET THE T1 PRESCALER TO 1:8
bsf		T1CON, TMR1ON	; Turn on T1

movf	PORTC, W		; check portC for user input (switches)
addlw	0x02			; convert the 2-bit (0-3) to (2-5)
movwf	Test_Cnt_i		; This is the number of pulses sent to ATE
movf	PORTA, W		; TEST PORTA

MainWaitLoop:
goto	\$1			; WAIT FOR SOT, INTERUPT ON PORTA (RA0)

end

#### Pommie

##### Well-Known Member
I just tried your code in the simulator and it worked as expected. It did do repeated interrupt due to your ISR not clearing INTCON,RABIF but that is easily fixed.

All I added was the stimulus attached. As soon as I pressed the button the interrupt fired.

Mike.

#### Attachments

• Stimulus.png
20.3 KB · Views: 274

#### mjdeez

##### New Member
Thanks Mike. I really appreciate your help. I've spent at least 10 hours trying to track down this one problem. I suspect my issue has something to do with the ICD I'm using. It is the off the shelf ICD for Pickit2 and I don't know the inner workings of it.

I will change my code around to handle interrupts more cleanly, and I'll probably come back and ask for some suggestions for improvements. Thanks again.
-Mike

#### blueroomelectronics

##### Well-Known Member
IMO the PK2 is an excellent choice for programming & debugging PICs. BUT the 16F690 does not have the hardware debug (you need the AC162061 ICD header & AC164110 adapter) if you want debug. Another choice would be use the 16F88 or the advanced 18F1320 instead. Both have hardware debug.

#### mjdeez

##### New Member
I am using the header and adapter. Based on Pommie's simulations, the code works (as far as firing the interrupt). That's why I'm gathering it is HW related. When I get some more standard 16F690 devices (non -ICD, outside of debug mode), I will try it again. I bent all the leads getting the only 16F690 DIP I have when I was removing it from the PK2 socket.

I was considering a more advanced micro, but I wanted to start with something manageable. I'm basically starting by reading datasheets, posts, tutorials, etc. My biggest challenge, other than this IOC, has been figuring out what pin functionalities can be enabled depending on what other functions are being used. PORTB limitations with TMR1 enabled, for example.

I have MPLAB version 8.1 installed. Anyone know if it is bundled with a simulator, where I don't need a PIC target connected? I really am very new to this.

#### blueroomelectronics

##### Well-Known Member
Yes it has a simulator. Don't forget you need a 0.1uF cap near the PICs power pins.

#### mjdeez

##### New Member
Thanks. There are so many overviews, user guides, data sheets, product line manuals that it gets a little overwhelming. I didn't realize the SW included a sim tool.

I'll take a look and see if any caps need to be added. I don't recall if they are there.

-Mike

#### quqnuss

##### New Member
Hello there,
To the problem that RABIF bit is not cleared. Please read the paragraph 4.2.3 of 16F690's Datasheet.
In simple words, just read the port A or B, whatever is the target port, like:
Code:
banksel PORTA
movfw  PORTA
; and then ....
bcf      INTCON,RABIF
this should do the trick.

Last edited:
Status
Not open for further replies.

Replies
0
Views
2K
Replies
18
Views
2K
Replies
4
Views
1K
Replies
5
Views
2K
Replies
2
Views
2K