; ***************************************************************
; * Copyright (C) 2005, Embed Inc (http://www.embedinc.com) *
; * *
; * Permission to copy this file is granted as long as this *
; * copyright notice is included in its entirety at the *
; * beginning of the file, whether the file is copied in whole *
; * or in part and regardless of whether other information is *
; * added to the copy. *
; * *
; * The contents of this file may be used in any way, *
; * commercial or otherwise. This file is provided "as is", *
; * and Embed Inc makes no claims of suitability for a *
; * particular purpose nor assumes any liability resulting from *
; * its use. *
; ***************************************************************
;
; ****************************************************************
; * ------ WARNING ------ *
; * THIS TEMPLATE IS FOR THE ORIGINAL PIC16 FAMILY. USE *
; * QQQ_INTR16E.ASPIC AS A TEMPLATE FOR THE ENHANCED 16F1xxx *
; * PICs, and QQQ_INTR18.ASPIC FOR THE PIC18 FAMILY. *
; ****************************************************************
;
; Interrupt service and related routines.
;
/include "qq2.ins.aspic"
extern_flags ;declare global flag bits EXTERN
;*******************************************************************************
;
; Configuration constants.
;
save_fsr equ true ;indicate whether ISR must save/restore FSR
niregs equ 0 ;num of IREGn private interrupt routine registers
;**********
;
; Derived constants.
;
;*******************************************************************************
;
; Global state.
;
; The following global state is in the normal register bank for global
; state. The bank is GBANK, and GBANKADR is an address guaranteed to
; be within this bank.
;
defram gbankadr
;*******************************************************************************
;
; Local state. This is always in the same register bank as the global
; state.
;
;
; The following state is private to the interrupt service routine, and
; must always be in bank 0.
;
defram 0
status_save res 1 ;saved copy of STATUS, nibbles swapped
if save_fsr
fsr_save res 1 ;saved copy of FSR (if FSR save enabled)
endif
if ncodepages > 1
pclath_save res 1 ;saved copy of PCLATH (if multiple code pages)
endif
;
; Define the IREGn general register for use during an interrupt. The
; general registers REGn must not be altered during an interrupt without
; being explicitly saved/restored, which usually makes them unusable.
; The IREGn registers are used instead, although these are in bank 0
; instead of global memory. The number of IREGn registers is defined
; by the constant NIREGS above. The first is IREG0, then IREG1, etc.
;
ii set 0
while ii < niregs ;once for each IREG register to define
ireg#v(ii) res 1 ;define this IREGn register
global ireg#v(ii) ;make is global for interrupt code in other modules
ii set ii + 1 ;advance to next IREG number
endw ;back to define next IREG
;
; This state is private to the interrupt service routine and must always
; be accessible regardless of the current direct register bank setting.
;
udata_shr
w_save res 1 ;saved W during interrupt, mapped to all banks
.intr code
;*******************************************************************************
;
; Subroutine INTR_INIT
;
; Initialize the interrupt system and other state managed by this module.
;
glbsub intr_init, noregs
;
; Initialize global state.
;
;
; Initialize local state.
;
;
; Enable interrupts. Any interrupts used have already been enabled
; individually, but interrupts are still disabled globally.
;
ifdef pir1
dbankif pir1
clrf pir1 ;clear any existing peripheral 1 intr condition
endif
ifdef pir2
dbankif pir2
clrf pir2 ;clear any existing peripheral 2 intr condition
endif
ifdef peie
bsf intcon, peie ;enable peripheral interrupts
endif
bsf intcon, gie ;globally enable interrupts
leaverest
;*******************************************************************************
;
; Interrupt service routine.
;
; The processor executes a call to location 4 on an interrupt, and in
; addition globally disables interrupts. These are re-enabled at the end
; of the ISR by the RETFIE instruction.
;
; Note that subroutine calls must be minimized or avoided in the ISR.
; Since an interrupt can come at any time in the main code, any additional
; call stack locations used here are not available anywhere else.
;
.intr_svc code 4 ;start at interrupt vector location
movwf w_save ;save W
swapf status, w ;make copy of status with nibbles swapped
clrf status ;select direct and indirect register banks 0
dbankis 0
ibankis 0
movwf status_save ;save old STATUS value with nibbles swapped
if save_fsr ;FSR needs to be saved ?
movf fsr, w ;save FSR
movwf fsr_save
endif
if ncodepages > 1 ;multiple code pages may be in use ?
movf pclath, w ;save PCLATH
movwf pclath_save
clrf pclath ;now definitely on code page 0
endif
;
; W, STATUS, FSR (if SAVE_FSR set), and PCLATH (if multiple code pages)
; have been saved. Direct and indirect register banks 0 are selected, and
; the bank assumptions have been set accordingly. Program memory page 0
; is selected.
;
;
; Check for UART receive interrupt.
;
extern uart_intr_recv ;receive interrupt routine in UART module
dbankif pir1
dbankif rcif_reg
btfss rcif_flag ;interrupt condition asserted ?
jump no_uart_recv ;no
gjump uart_intr_recv ;handle interrupt, will go to INTR_RET_UART on done
no_uart_recv dbankis rcif_reg
;
; Check for UART transmitter ready interrupt.
;
extern uart_intr_xmit ;transmit interrupt routine in UART module
dbankif txie_reg
btfss txie_flag ;this interrupt enabled ?
jump no_uart_xmit ;no
dbankif txif_reg
btfss txif_flag ;interrupt condition asserted ?
jump no_uart_xmit ;no
gjump uart_intr_xmit ;handle interrupt, will go to INTR_RET_UART on done
no_uart_xmit unbank
gjump 0 ;unexpected interrupt, should never happen
;********************
;
; Restore state to when the interrupt occurred and return from interrupt.
;
glbent intr_ret ;common interrupt exit point
glbent intr_ret_uart ;UART interrupts return here when done
clrf status ;register bank settings are now 0
dbankis 0
ibankis 0
if ncodepages > 1 ;multiple code pages may be in use ?
movf pclath_save, w ;restore PCLATH
movwf pclath
endif
if save_fsr ;FSR needs to be restored ?
movf fsr_save, w ;restore FSR
movwf fsr
endif
swapf status_save, w ;get old STATUS without changing status bits
movwf status ;restore STATUS, register banks now unknown
swapf w_save ;swap nibbles in saved copy of W
swapf w_save, w ;restore original W
retfie ;return from interrupt, re-enable interrupts
end