org h'0004'
ISR_Vector
;
; save main program context
;
movwf W_ISR ; save W-reg |B?
swapf STATUS,W ; doesn't change STATUS bits |B?
movwf S_ISR ; save STATUS reg |B?
clrf STATUS ; force bank 0 |B0
movf FSR,W ; |B0
movwf F_ISR ; save FSR |B0
bcf PIR1,TMR2IF ; clear TMR2 interrupt flag |B0
;
; setup 74HCT238 address lines to select this periods active
; Servo (duty cycle was set in previous PWM interrupt cycle).
;
; a minimum 96-usec window at the beginning of each interrupt
; where PWM is high and the 74HCT238 outputs are low provides
; more than enough time to setup the address lines before the
; PWM output goes active low.
;
movf PORTA,W ; read PORTA |B0
andlw b'11111000' ; preserve PORTA b7..b3 bits |B0
iorwf Servo,W ; Servo b2..b0 bits are used as |B0
movwf PORTA ; 74HCT238 a2..a0 address bits |B0
;
; increment Servo [0..7] for next PWM cycle
;
incf Servo,f ; increment servo |B0
bcf Servo,3 ; mod(Servo/8), [0..7] |B0
;
; we use the PWM off-time to drive the 74HCT238 E1 gate so
; we invert the PWM duty cycle by subtracting the servo duty
; cycle value of 50..300 (8-usec ticks) from the PWM period
; value of 312 (2496-usec PWM period / 8-usec).
;
; calculate inverse duty cycle for next PWM cycle
;
movf Servo,W ; servo number [0..7] |B0
addlw SArray ; add to array address |B0
movwf FSR ; setup indirect address |B0
clrf DutyHi ; |B0
movf INDF,W ; the Servo PWM value [000..250] |B0
addlw d'50' ; add 0.4-msec offset [050..300] |B0
skpnc ; carry? no, skip, else |B0
incf DutyHi,f ; increment duty cycle hi |B0
sublw low d'312' ; subtract from PWM period |B0
movwf DutyLo ; save inverse duty cycle lo |B0
movf DutyHi,W ; |B0
skpc ; borrow? |B0
incf DutyHi,W ; |B0
sublw high d'312' ; |B0
movwf DutyHi ; save inverse duty cycle hi |B0
;
; inverse duty cycle result is a value between 12 (PWM hi for
; 96-usecs and active low for 2400-usecs) and 262 (PWM hi for
; 2096-usecs and active low for 400-usecs).
;
; setup duty cycle registers for next PWM cycle
;
rrf DutyHi,f ; shift result |B0
rrf DutyLo,W ; |B0
movwf CCPR1L ; set 006..131 (16-usec ticks) |B0
bcf CCP1CON,CCP1X ; |B0
skpnc ; odd 8-us tick? no, skip, else |B0
bsf CCP1CON,CCP1X ; set the odd 8-usec tick |B0
;
; restore main program context
;
movf F_ISR,W ; |B0
movwf FSR ; restore FSR |B0
swapf S_ISR,W ; |B0
movwf STATUS ; restore STATUS |B?
swapf W_ISR,f ; don't screw up STATUS |B?
swapf W_ISR,W ; restore W-reg |B?
retfie ; return from interrupt |B?