;******************************************************************************
;* This file contains  the functions of 10  bit ADC library module for 
;* interrupt option
;******************************************************************************
;*File name:    ADCInt.asm
;*Dependencies: ADCInt.inc
;*Processors:   PIC18
;*Assembler:    MPASMWIN 02.70.02 or higher
;*Linker:       MPLINK 2.33.00 or Higher
;*Company:      Microchip Technology, Inc.
;*
;* Software License Agreement
;*
;* The software supplied herewith by Microchip Technology Incorporated
;* (the "Company") for its PICmicro Microcontroller is intended and
;* supplied to you, the Company's customer, for use solely and
;* exclusively on Microchip PICmicro Microcontroller products. The
;* software is owned by the Company and/or its supplier, and is
;* protected under applicable copyright laws. All rights are reserved.
;* Any use in violation of the foregoing restrictions may subject the
;* user to criminal sanctions under applicable laws, as well as to
;* civil liability for the breach of the terms and conditions of this
;* license.
;*
;* THIS SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION. NO WARRANTIES,
;* WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
;* TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
;* PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,
;* IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
;* CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
;*
;*
;*
;* Author               Date            Comment
;*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;* B.K. Anantha Ramu    May 13, 2003    Initial Release (V1.0)
;* 
;********************************************************************/
    #define A2D_10BIT_MODULE            ;With this definition, availability of
                                        ;module features will be known.
    #define _GEN_MODULE_ERROR           ;If ADC module is not available this 
                                        ;enables to generate error.
    #define _ADD_PROC_INC_FILE          ;This enables to include processor.inc file.


    #include    <P18xxx.INC>            ;This defines module features for different
                                        ;processors.
    #define ADCInt_Source               ;This definition is required where the variables
                                        ;are declared.

    #include <ADCInt.inc>               ;ADCInt.inc mainly contains macros of ADCInt
                                        ;library module


 
_ADCINTDATA1    UDATA_ACS

                       
vADCIntChannelNumber_A          RES     1 ;This location stores ADC channel number                              


_vADCIntAcquisitionCount_A      RES     1 ;This location is used in delay routine which is
                                        ;used to provide acquisition time

_ADCINTDATA2    UDATA

vADCIntStatus                   RES     1   ;This contains error & status flags.
  
vADCIntBufWrPtr                 RES     1   ;This points to the location where ADC
                                            ;result is to be written in the buffer.

vADCIntBufRdPtr                 RES     1   ;This points to the location where ADC
                                            ;result is to be read from the buffer

    IFDEF _ADCINT_8BITS
vADCIntResultHigh               RES     1   ;ADC  result is read to this location
    ENDIF

    IFDEF   _ADCINT_10BITS
vADCIntResultHigh               RES     1   ;ADC high byte result is read to this location
vADCIntResultLow                RES     1   ;ADC low byte result is read to this location
    ENDIF

vADCIntResultsCount             RES     1   ;This keeps track of the number of
                                            ;ADC results yet to be read.

_vSaveFSR0L                     RES     1   ;At the beginning of ADCIntISR, FSR0
_vSaveFSR0H                     RES     1   ;contents are stored in these
                                            ;locations and retrieved back at the 
                                            ;end of ADCIntISR.
    IFDEF   _ADCINT_8BITS                                           
vADCIntBuffer                   RES     _BUFFERSIZE ;Number of buffer locations 
    ENDIF                                           ;required is equal to buffer 
                                                    ;size selected by the user, 
                                                    ;when selected ADC resolution 
                                                    ;is 8 bits.

    IFDEF   _ADCINT_10BITS                                          
vADCIntBuffer                   RES     _BUFFERSIZE*2   ;Number of buffer locations                                            
    ENDIF                                               ;required is twice the 
                                                        ;the buffer size
                                                        ;selected, when selected
                                                        ;ADC resolution is 10
                                                        ;bits.
;-------------------------------------------------------------------------------

_ADCINTCODE    CODE
                     


;******************************************************************************
; Function:     ADCIntISR
;
; PreCondition: To be used after invoking macro mADCIntInit.
;
; Overview:     This function checks AD interrupt flag. If flag is not set, control   
;               returns. Otherwise ADC result is written/ not written depending upon  
;               the ADCIntBufOverFlow flag & user option overwrite/no-overwrite
;               buffer. When buffer is written ADCIntBufEmpty flag is cleared.
;               The flag ADCIntBufFull is set, if all the locations of the 
;               buffer are written with ADC result but none is read using
;               ADCIntRead. ADCIntBufOverFlow flag is set when new ADC result
;               becomes available when ADCIntBufFull is set.
;
; Input:        ADRESH & ADRESL( 10 bit resolution), ADRESH (8 bit resolution)

; Output:       Buffer starting at vADCIntBuffer,vADCIntStatus,vADCIntBufWrPtr
;               vADCIntResultsCount     

; Side Effects: WREG,STATUS,BSR changes.
;
; Stack requirement: 1 level deep
;
; Maximum Instruction cycles:  49   
;****************************************************************************  
ADCIntISR:
    btfss   PIE1,ADIE                   ;Check whether AD interrupt is enabled
    return                              ;otherwise return. This check is 
                                        ;necessary because even if AD interrupt
                                        ;is disabled, because of interrupt other
                                        ;than ADC, control may come here.
    btfss   PIR1,ADIF                   ;Check whether ADC result is ready or not
    return                              ;If not return.


	bcf     PIR1,ADIF
    BANKSEL vADCIntStatus
    btfss   vADCIntStatus,ADCIntBufFull     ;Check whether buffer is full.
    bra     StoreData                       ;If not, store ADC result in buffer.
    bsf     vADCIntStatus,ADCIntBufOverFlow ;If buffer is full, set                  
                                            ;ADCIntBufOverFlow flag.
    IFDEF  _NOOVERWRITE                     ;Return, if user option is not to 
        return                              ;overwrite buffer after buffer full.
    ELSE                                    ;If user option is to overwrite
                                            ;buffer, advance vADCIntBufRdPtr.
        incf    vADCIntBufRdPtr,F           ;Wrap vADCIntBufRdPtr, when 
        IFDEF   _ADCINT_10BITS              ;reaching end of buffer.
            incf    vADCIntBufRdPtr,F
            movlw   2*_BUFFERSIZE           
        ENDIF  
        IFDEF    _ADCINT_8BITS
            movlw   _BUFFERSIZE
        ENDIF
        cpfslt  vADCIntBufRdPtr
        clrf    vADCIntBufRdPtr
    ENDIF
StoreData
	movff	FSR0L,_vSaveFSR0L               ;Save FSR0
	movff	FSR0H,_vSaveFSR0H
    bcf     vADCIntStatus,ADCIntBufEmpty    ;Buffer is written with new ADC
                                            ;result, hence clear ADCIntBufEmpty
                                            ;flag.
    IFDEF  _DONT_USE_LFSR                   ;If LFSR instruction is not
                                            ;supported
        movlw    LOW(vADCIntBuffer)         
        movwf   FSR0L
        movlw    HIGH(vADCIntBuffer)        ;Load FSR0 with buffer start address
        movwf   FSR0H
    ELSE                                    ;If LFSR instruction is supported
                                            
        lfsr    FSR0,vADCIntBuffer          ;Load FSR0 with buffer start address
    ENDIF

    movf       vADCIntBufWrPtr,W 
    IFDEF   _ADCINT_8BITS
        movff   ADRESH,PLUSW0               ;Write ADRESH contents to buffer.
        incf    vADCIntBufWrPtr,F           ;Update pointer for next write.
        movlw   _BUFFERSIZE
    ENDIF
    IFDEF   _ADCINT_10BITS                  ;If user option is 10 bits resolution
        movff   ADRESH,PLUSW0               ;two bytes(ADRESH & ADRESL) are 
        incf    WREG                        ;written to buffer.
        movff   ADRESL,PLUSW0
        incf    WREG
        movwf   vADCIntBufWrPtr             ;Update pointer for next write
        movlw   2*_BUFFERSIZE        
    ENDIF
    cpfslt      vADCIntBufWrPtr             ;Check to wrap vADCIntBufWrPtr.
    clrf        vADCIntBufWrPtr             ;Reset pointer to buffer start. 
    incf        vADCIntResultsCount,F       ;Update number of results to be read
    movlw       _BUFFERSIZE
    cpfslt      vADCIntResultsCount         ;Check of buffer full condition.
                                            ;If buffer full, set ADCIntBufFull
    IFDEF   _NOOVERWRITE                    ;flag.
        bsf vADCIntStatus,ADCIntBufFull     
                                            
    ELSE
        bra LimitCount
    ENDIF
RetrvReturn                                           
	movff	_vSaveFSR0L,FSR0L               ;Retrieve FSR0 stored at the
	movff	_vSaveFSR0H,FSR0H               ;beginning of this function.
    return 

LimitCount
    bsf vADCIntStatus,ADCIntBufFull 
    movwf   vADCIntResultsCount             ;In buffer over-write option 
    bra     RetrvReturn                     ;limit vADCIntResultsCount to
                                            ;_BUFFERSIZE.
;******************************************************************************
; Function:         ADCIntRead
;
; PreCondition:     To be used after invoking macro mADCIntInit.
;
; Overview:         This function reads the ADC results from the buffer.      
;                   In case of 10 bit ADC resolution, the result is read into  
;                   the locations vADCIntResultHigh & vADCIntResultLow.  
;                   In case of 8 bits resolution, result is read to 
;                   vADCIntResultHigh only. It sets ADCIntBufEmpty flag when 
;                   there is no new result to be read from the buffer.
;
;
; Input:            Buffer starting at location vADCIntBuffer.
;        
;
; Output:           vADCIntResultHigh & vADCIntResultLow (10 bits resolution)
;                   vADCIntResultHigh (8 bits resolution)
;                   ADCIntBufEmpty flag.          
;
; Side Effects:     WREG, STATUS, FSR0 & BSR changes. 
;
; Stack requirement: 1 level deep.
;
; Maximum instruction cycles: 27
;****************************************************************************
ADCIntRead:
    bcf     PIE1,ADIE                       ;ADC interrupt may alter pointers,
                                            ;hence prevent this by disbling the ADC interrupt
    BANKSEL vADCIntStatus
    btfsc   vADCIntStatus,ADCIntBufEmpty    
    bra Exit                                ;If buffer is empty return.
    bcf vADCIntStatus,ADCIntBufFull         ;Since result is read, clear ADCIntBufFull
                                            ;flag
    IFDEF  _DONT_USE_LFSR                   ;If LFSR instruction is not
                                            ;supported.
        movlw    LOW(vADCIntBuffer)         ;Load FSR0 with buffer start address
        movwf   FSR0L
        movlw    HIGH(vADCIntBuffer)
        movwf   FSR0H
    ELSE                                    ;If LFSR instruction is supported
        lfsr    FSR0,vADCIntBuffer          ;Load FSR0 with buffer start address          
    ENDIF
    movf       vADCIntBufRdPtr,W 
    IFDEF   _ADCINT_8BITS
        movff   PLUSW0,vADCIntResultHigh    ;Read result from buffer
        incf    vADCIntBufRdPtr,F           ;Update pointer for next read. 
        movlw   _BUFFERSIZE
    ENDIF
    IFDEF   _ADCINT_10BITS
        movff   PLUSW0,vADCIntResultHigh    ;Read high byte from buffer.
        incf    WREG                        ;Update pointer for next read. 
        movff   PLUSW0,vADCIntResultLow     ;Read low byte from buffer.
        incf    WREG                        ;Update pointer for next read. 
        movwf   vADCIntBufRdPtr
        movlw   2*_BUFFERSIZE        
    ENDIF
    cpfslt  vADCIntBufRdPtr                 ;Check to wrap vADCIntBufRdPtr.
    clrf    vADCIntBufRdPtr                 ;Pointer reset to buffer start.  
    dcfsnz    vADCIntResultsCount,F         ;Update number of results to be read
    bsf     vADCIntStatus,ADCIntBufEmpty    ;No results to be read, set ADCIntBufEmpty 
Exit
    bsf     PIE1,ADIE                       ;Reenable ADC interupt disabled at
                                            ;the beginning of this function.
    return    
;******************************************************************************
; Function:     _ADCIntChannelSelect
;
; PreCondition: None
;
; Overview:     This function sets the bits of ADCON0 according to the channel  
;               number supplied through WREG.
; Input:        WREG contains the channel number.

; Output:       ADCON0

; Side Effects: STATUS, WREG changes
;
; Stack requirement: 1 level deep
;
; Maximum instruction cycles: 11
;****************************************************************************
_ADCIntChannelSelect:
        movwf   vADCIntChannelNumber_A

    IFDEF _ADCINT_PIC181                ;10 bit ADC with ADCON0 & ADCON1
                                        ;registers. No ADCON2 register
        movlw   0xC7
        andwf   ADCON0,F                ;Channel bits in ADCON0 occupy bit
        rlncf   vADCIntChannelNumber_A,W  ;positions 3,4 & 5. Hence  value in vADCIntChannelNumber_A 
        rlncf   WREG                    ;is shifted left by 8.
        rlncf   WREG
        iorwf   ADCON0,F

    ENDIF

    IFDEF _ADCINT_PIC182                ;10 bit ADC with ADCON0, ADCON1 & ADCON2
                                        ;register.
        movlw   0xC3                    ;Channel bits in ADCON0 occupy bit
        andwf   ADCON0,F                ;positions 2,3,4 & 5. Hence value  in vADCIntChannelNumber_A  is                           
        rlncf   vADCIntChannelNumber_A,W  ;multiplied by 4.
        rlncf   WREG
        iorwf   ADCON0,F
    ENDIF

        return

;******************************************************************************
; Function:     ADCIntAcquisitionTime
;
; PreCondition: None
;
; Overview:     This function gives a delay of 
;               3*(_vADCIntAcquisitionCount_A-1)+2+4 instructions and  
;               it is  used to give acquisition delay time. 
;
; Input:        _vADCIntAcquisitionCount_A       
;
; Output:       None
;
; Side Effects: WREG
;
; Stack requirement: 1 level deep
;
; Maximum instruction cycles: (CLOCK_FREQ*_ACQTIME)/D'4000000'
;****************************************************************************

ADCIntAcquisitionTime:

_N2=(CLOCK_FREQ*_ACQTIME)/D'4000000'                ;Number of instructions for
                                                    ;_ACQTIME.

    IF  _N2>D'770'                                  ;This limits the maximum _N1
_N2=D'255'                                          ;value to D'255'(max 8 bit 
    ENDIF                                           ;value) to prevent error 
                                                    ;due to overflow. 
      
    IF _N2<D'8'                                     ;This ensures that _N1                                        
_N2=D'8'                                            ;never becomes negative
    ENDIF
        
_N1=(_N2-8)/D'3'+1                                  ;Count required for the routine
                                                    ;ADCIntAcquisitionTime to give 
        movlw   _N1                                 ;a delay of _ACQTIME.
        movwf   _vADCIntAcquisitionCount_A
Loop1         
        decfsz  _vADCIntAcquisitionCount_A,F
        bra     Loop1
        return


;*****************************************************************************
; Function:        ADCIntBufInit 
; 
; PreCondition:    None
;
; Overview:     This function clears ADCIntBufFull, ADCIntBufOverFlow flags, sets    
;               ADCIntBufEmpty flag, clears vADCIntBufWrPtr, vADCIntBufRdPtr 
;               vADCIntResultsCount.
; Input:        None
;
; Output:       vADCIntStatus, vADCIntBufWrPtr, vADCIntBufRdPtr, vADCIntResultsCount. 
;                            
; Side Effects: BSR, STATUS changes
;
; Stack requirement: 1 level deep
;
; Maximum instruction cycles: 10
;*****************************************************************************
ADCIntBufInit:     
            BANKSEL vADCIntStatus       
            clrf    vADCIntStatus               ;Clears ADCIntBufFull, 
                                                ;ADCIntBufOverFlow flags.
            bsf vADCIntStatus,ADCIntBufEmpty    ;sets ADCIntBufEmpty flag.
            clrf    vADCIntResultsCount 
            clrf    vADCIntBufRdPtr
            clrf    vADCIntBufWrPtr
            return
;*****************************************************************************
    END
