; *************************************************************** ; * 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 PIC18 FAMILY. USE QQQ_INTR.ASPIC * ; * AS A TEMPLATE FOR THE PIC16 FAMILY. * ; *************************************************************** ; ; Interrupt service and related routines. ; /include "qq2.ins.aspic" extern_flags ;declare global flag bits EXTERN ;******************************************************************************* ; ; Configuration constants. ; intr_priorities equ false ;disable multiple interrupt priorities ; ; Indicate which FSRs are to be saved by the single/high and low priority ; interrupt routines. ; ; FSR0 is used by the FIFO_xxx macros, and must be saved if FIFOs are accessed ; from interrupt code. Note that the UART interrupt routines use FIFOs. ; ; FSR1 has no dedicated purpose in the general PIC development environment. ; ; FSR2 is reserved as the software stack pointer. This stack will be used to ; save state during an interrupt. FSR2 must therefore not be explicitly ; saved. It will automatically be restored if the same number of bytes are ; popped from the stack as are pushed to the stack. ; save_fsr0 equ true ;indicate whether save/restore FSR0 in sgl/high intr save_fsr1 equ false ;indicate whether save/restore FSR1 in sgl/high intr save_fsr0l equ false ;indicate whether save/restore FSR0 in low prio intr save_fsr1l equ false ;indicate whether save/restore FSR1 in low prio intr ;********** ; ; 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 iregs_define ;define registers exclusively for interrupt routines ;******************************************************************************* ; ; Local state. This is always in the same register bank as the global ; state. ; .intr code ;******************************************************************************* ; ; Subroutine INTR_INIT ; ; Initialize the interrupt system and other state managed by this module. ; intr_init glbsub ; ; Initialize global state. ; ; ; Initialize local state. ; ; ; Enable interrupts. The interrupt system was reset at startup to all ; interrupts disabled, single interrupt priority, and all interrupt priorities ; set to the lowest. Any interrupts that are needed have been individually ; configured, but interrupts are still globally disabled. ; if intr_priorities ;using multiple priority interrupts ? dbankif rcon bsf rcon, ipen ;configure for multiple interrupt priorities bsf intcon, gieh ;enable high priority interrupts bsf intcon, giel ;enable low priority interrupts else ;using a single interrupt priority bsf intcon, peie ;enable the peripheral interrupts bsf intcon, gie ;globally enable interrupts endif leaverest ;******************************************************************************* ; ; High priority or single interrupt service routine. ; ; The processor executes a call to location 8 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. ; ; The fast register stack is used to save/restore W, STATUS, and BSR for this ; interrupt. ; if intr_priorities .intr_high code h'8' ;high priority interrupt vector else .intr_svc code h'8' ;single priority interrupt vector endif unbank ;indicate the bank setting is unknown ; ; W, STATUS, and BSR have been automatically saved onto the fast register ; stack by the interrupt hardware. ; if save_fsr0 ;need to save FSR0 ? pushreg fsr0l pushreg fsr0h endif if save_fsr1 ;need to save FSR1 ? pushreg fsr1l pushreg fsr1h endif ;******************************************************************************* ;******************************************************************************* ; ; Low priority interrupt service routine. ; ; This section of code gets inserted if multiple priority interrupts are ; enabled. The high priority interrupt vector is at 8, and the low priority ; vector at 18h. We assume that the interrupt service routine requires more ; than the 8 instructions between the two vectors, so the high priority ; service routine must jump to a different location to avoid colliding with ; the low priority interrupt vector. In that case, the high priority ; interrupt handler continues immediately after the low priority interrupt ; handler code. ; ; If multiple interrupt priorites are disabled, then there is nothing special ; about location 18h and the interrupt handler can continue right over it ; without harm. ; if intr_priorities ;multiple interrupt priorities in use ? jump intr_high_cont ;continue after low priority handler ; ; Low priority interrupt service routine. This routine can not use the fast ; call stack and must save/restore W, STATUS, and BSR explicitly. ; .intr_low code h'18' ;low priority interrupt vector unbank ;indicate the bank setting is unknown movwf preinc2 ;save W onto the software stack swapf indf2 ;swap so that can be read with SWAPF on restore pushreg status ;save STATUS onto the software stack pushreg bsr ;save BSR onto the software stack if save_fsr0l ;need to save FSR0 ? pushreg fsr0l pushreg fsr0h endif if save_fsr1l ;need to save FSR1 ? pushreg fsr1l pushreg fsr1h endif ; ; W, STATUS, BSR, and the general FSRs (if enabled) have been saved. Now ; determine the interrupt condition and service it. ; reset ;unexpected interrupt, should never happen ; ; Done servicing the low priority interrupt condition. Now restore to the ; state at the start of the interrupt and return from the interrupt. ; intr_retl unbank ;common low priority interrupt exit point if save_fsr1l ;need to restore FSR1 ? popreg fsr1h popreg fsr1l endif if save_fsr0l ;need to restore FSR0 ? popreg fsr0h popreg fsr0l endif popreg bsr ;pop BSR from software stack to restore it popreg status ;pop STATUS from software stack to restore it swapf postdec2, w ;pop W from software stack to restore it retfie ;return from the interrupt ; ; Continue the high priority interrupt service routine here. ; intr_high_cont unbank unbank endif ;end of multiple interrupt priorities in use case ; ; End of code inserted only if multiple interrupt priorities are in use. ; ;******************************************************************************* ;******************************************************************************* ; ; The high or single interrupt priority routine continues here. ; ; W, STATUS, BSR, and the general FSRs (if enabled) have been saved. Now ; determine the interrupt condition and service it. ; ; ; Check for UART receive interrupt. ; extern uart_intr_recv ;receive interrupt routine in UART module dbankif pir1 btfss pir1, rcif jump no_uart_recv gjump uart_intr_recv ;handle interrupt, will go to INTR_RET_UART on done no_uart_recv dbankis pir1 ; ; Check for UART transmitter ready interrupt. The interrupt being enabled is ; also checked. This is because the UART interrupt routines enable/disable ; the interrupt on the fly. ; extern uart_intr_xmit ;receive interrupt routine in UART module dbankif pie1 btfss pie1, txie ;UART transmit interrupt is enabled ? jump no_uart_xmit ;no, skip this section dbankif pir1 btfss pir1, txif ;UART transmit interrupt is signalled ? jump no_uart_xmit ;no gjump uart_intr_xmit ;handle interrupt, will go to INTR_RET_UART on done no_uart_xmit dbankis pir1 reset ;unexpected interrupt, should never happen ;**************************************** ; ; Done servicing the high priority or single interrupt. Now restore to the ; state at the start of the interrupt and return from the interrupt. W, ; STATUS, and BSR have been saved on the hardware fast register stack and will ; be restored as part of the RETFIE FAST instruction. ; intr_ret unbank ;common high/single priority interrupt exit point glbent intr_ret_uart ;UART interrupt routines return here when done if save_fsr1 ;need to restore FSR1 ? popreg fsr1h popreg fsr1l endif if save_fsr0 ;need to restore FSR0 ? popreg fsr0h popreg fsr0l endif retfie fast ;return from interrupt, restore W, STATUS, and BSR end