; *************************************************************** ; * 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