;; Pulse Generator
;;
;; Test gpsim's built in pulse generator module
list p=16f877a
include <p16f877a.inc>
include <coff.inc>
__CONFIG _WDT_OFF
errorlevel -302
radix dec
;----------------------------------------------------------------------
;----------------------------------------------------------------------
GPR_DATA UDATA
var1 RES 1
var2 RES 1
var3 RES 1
failures RES 1
status_temp RES 1
w_temp RES 1
interrupt_temp RES 1
GLOBAL var1,var2,var3,failures
GLOBAL done
;; The capTime 16-bit register is a working register that keeps track
;; of the capture edge.
capTimeH RES 1
capTimeL RES 1
capTimeHb RES 1
capTimeLb RES 1
GLOBAL capTimeH, capTimeL, capTimeHb, capTimeLb
temp1 RES 1
temp2 RES 1
t1 RES 1
t2 RES 1
t3 RES 1
kz RES 1
;----------------------------------------------------------------------
; ********************* RESET VECTOR LOCATION ********************
;----------------------------------------------------------------------
RESET_VECTOR CODE 0x000 ; processor reset vector
movlw high start ; load upper byte of 'start' label
movwf PCLATH ; initialize PCLATH
goto start ; go to beginning of program
;; Simulation Script
.sim "module lib libgpsim_modules"
.sim "module load pulsegen PG1"
.sim "node nRC2"
.sim "PG1.set = 0"
.sim "PG1.clear = 0x200"
.sim "PG1.period = 0x400"
.sim "attach nRC2 PG1.pin portc2"
;----------------------------------------------------------------------
; ******************* INTERRUPT VECTOR LOCATION ********************
;----------------------------------------------------------------------
INT_VECTOR CODE 0x004 ; interrupt vector location
;;
;; Interrupt
;;
movwf w_temp
swapf STATUS,W
movwf status_temp
;; Are peripheral interrupts enabled?
btfss INTCON,PEIE
goto exit_int
bsf STATUS,RP0
movf PIE1 ^ 0x80,W
bcf STATUS,RP0
movwf interrupt_temp
check_tmr1:
btfsc PIR1,TMR1IF
btfss interrupt_temp,TMR1IE
goto check_ccp1
;; tmr1 has rolled over
bcf PIR1,TMR1IF ; Clear the pending interrupt
bsf temp1,0 ; Set a flag to indicate rollover
check_ccp1:
btfsc PIR1,CCP1IF
btfss interrupt_temp,CCP1IE
goto exit_int
bcf PIR1,CCP1IF ; Clear the pending interrupt
bsf temp1,1 ; Set a flag to indicate match
exit_int:
swapf status_temp,w
movwf STATUS
swapf w_temp,F
swapf w_temp,W
retfie
;----------------------------------------------------------------------
; ******************* MAIN CODE START LOCATION ******************
;----------------------------------------------------------------------
MAIN CODE
start
clrf failures ;Assume success.
clrf kz ;kz == Known Zero.
;; disable (primarily) global and peripheral interrupts
clrf INTCON
;;
;; CCP test
;;
;; The CCP module is intricately intertwined with the TMR1
;; module. So first, let's initialize TMR1:
;; Clear all of the bits of the TMR1 control register:
;; this will:
;; Turn the tmr off
;; Select Fosc/4 as the clock source
;; Disable the External oscillator feedback circuit
;; Select a 1:1 prescale
;; In this mode, TMR1 will count instruction cycles.
clrf T1CON ;
clrf PIR1 ; Clear the interrupt/roll over flag
;; Zero TMR1
clrf TMR1L
clrf TMR1H
;; Start the timer
bsf T1CON,TMR1ON
ccp_test1:
movlw (1<<GIE) | (1<<PEIE)
movwf INTCON
bsf STATUS,RP0
bsf TRISC ^ 0x80, 2 ;CCP bit is an input
bsf TRISC ^ 0x80, 0 ;CCP bit is an input
bsf PIE1 ^ 0x80, CCP1IE
bcf STATUS,RP0
;;
;; Start the capture mode that captures every falling edge
;; (please refer to the mchip documentation on the details
;; of the various ccp modes.)
;; ccp = 4 <- capture every falling edge
;; ccp = 5 <- capture every rising edge
;; ccp = 6 <- capture every 4th rising edge
;; ccp = 7 <- capture every 16th rising edge
;;
;; Note, the capture only works if the stimulus is present
;; on the ccp pin!
call ccpWaitForPORTC2_high
movlw (1<<CM2) ;CCP1CON = 4 <- capture every falling edge
movwf CCP1CON
;; Start the timer
bsf T1CON,TMR1ON
call ccpWaitForPORTC2_high
call ccpCaptureTwoEvents
.assert "(capTimeL==0) && (capTimeH==4)"
clrf temp1 ;Clear the software interrupt flag.
incf CCP1CON,F ;Next mode --> 5
call ccpWaitForPORTC2_low
call ccpWaitForPORTC2_high
call ccpCaptureTwoEvents
.assert "(capTimeL==0) && (capTimeH==4)"
clrf temp1 ;Clear the software interrupt flag.
incf CCP1CON,F ;Next mode --> 6
call ccpWaitForPORTC2_high
call ccpCaptureTwoEvents
.assert "(capTimeL==0) && (capTimeH==0x10)"
clrf temp1 ;Clear the software interrupt flag.
incf CCP1CON,F ;Next mode --> 7
call ccpWaitForPORTC2_high
call ccpCaptureTwoEvents
.assert "(capTimeL==0) && (capTimeH==0x40)"
goto done
;------------------------------------------------------------------------
;ccpCaptureTwoEvents
;
; Capture two events for the current CCP setting and return the time
; difference between them
ccpCaptureTwoEvents:
call ccpWaitForCapture
movf CCPR1L,W
movwf capTimeLb
movf CCPR1H,W
movwf capTimeHb
call ccpWaitForCapture
movf CCPR1L,W
movwf capTimeL
movf CCPR1H,W
movwf capTimeH
; Subtract the time of the most recently captured edge from the previous one
movf capTimeLb,W
subwf capTimeL,F
movf capTimeHb,W
skpc
incfsz capTimeHb,W
subwf capTimeH,F
return
;------------------------------------------------------------------------
;ccpWaitForCapture
;
; Spin loop that polls an interrupt flag that is set whenever a capture
; interrupt triggers.
ccpWaitForCapture:
clrf t1 ;A 16-bit software timeout counter
clrf t2
ccpWaitLoop:
;; The watchdog counter ensures we don't loop forever!
call ccpWDCounter
;;
;; when an edge is captured, the interrupt routine will
;; set a flag:
;;
btfss temp1,1
goto ccpWaitLoop
bcf temp1,1
return
;------------------------------------------------------------------------
ccpWaitForPORTC2_high:
btfsc PORTC,2
return
call ccpWDCounter
goto ccpWaitForPORTC2_high
ccpWaitForPORTC2_low:
btfss PORTC,2
return
call ccpWDCounter
goto ccpWaitForPORTC2_high
;------------------------------------------------------------------------
; ccpWDCounter
; a 16bit watch dog counter is incremented by 1. If it rolls over then we failed.
ccpWDCounter:
incfsz t1,f
return
incfsz t2,f
return
goto failed ;If we get here then we haven't caught anything!
;Either a) there's a gpsim bug or b) the stimulus
;file is incorrect.
; movlw 1 ;This 16-bit software counter
; addwf t1,f ;will time out if there's something wrong,
; rlf kz,w
; addwf t2,f
; skpc
; return
;;
;; Compare
;;
;; Now for the compare mode.
ccp_test2:
goto done
;;##########################################
clrf T1CON
clrf TMR1L
clrf TMR1H
bsf STATUS,RP0
bcf PORTC,2 ;CCP bit is an output
bcf STATUS,RP0
;; Start off the compare mode by setting the output on a compare match
;;
;; ccp = 8 <- Set output on match
;; ccp = 9 <- Clear output on match
;; ccp = 10 <- Just set the ccp1if flag, but don't change the output
;; ccp = 11 <- Reset tmr1 on a match
movlw 0x8
movwf CCP1CON
;;
clrf PIR1
;; Initialize the 16-bit compare register:
movlw 0x34
movwf CCPR1L
movlw 0x12
movwf CCPR1H
;; Clear the interrupt flag
clrf temp1
tt3:
;; Stop and clear tmr1
clrf T1CON
clrf TMR1L
clrf TMR1H
;; Now start it
bsf T1CON,TMR1ON
;; Wait for the interrupt routine to set the flag:
btfss temp1,1
goto $-1
bcf temp1,1
;; Try the next capture mode
incf CCP1CON,F
;; If bit 2 of ccp1con is set then we're through with capture modes
;; (and are starting pwm modes)
btfsc CCP1CON,2
goto done
goto tt3
failed:
.assert "\"*** FAILED Pulse Generator test\""
incf failures,F
goto $
done:
.assert "\"*** PASSED Pulse Generator test\""
goto $
end
syntax highlighted by Code2HTML, v. 0.9.1