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.
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)
movlw 0x49 ; about 150ms
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