Subversion Repositories group.electronics

Rev

Blame | Last modification | View Log | RSS feed

list        p=16F88
#include <p16f88.inc> ; Change to device that you are using.
        __CONFIG        _CONFIG1, _CP_OFF & _CCP1_RB0 & _DEBUG_OFF & _WRT_PROTECT_OFF & _CPD_OFF & _LVP_OFF & _BODEN_OFF & _MCLR_ON & _PWRTE_ON & _WDT_ON & _HS_OSC
        ERRORLEVEL -302
;---------------------------------------------------------------------
;Constant Definitions
;---------------------------------------------------------------------
#define NODE_ADDR 0x4e ; I2C address of this node
; Change this value to address that
; you wish to use.
;---------------------------------------------------------------------
; Buffer Length Definition
;---------------------------------------------------------------------
#define RX_BUF_LEN 8 ; Length of receive buffer
;---------------------------------------------------------------------
; Variable declarations
;---------------------------------------------------------------------
    udata_shr
    WREGsave    res 1
 
    udata
    STATUSsave  res 1
    FSRsave     res 1
    PCLATHsave  res 1
    Index       res 1           ; Index to receive buffer
    Temp        res 1           ;
    RXBuffer    res RX_BUF_LEN  ; Holds rec'd bytes from master
; device.
;---------------------------------------------------------------------
; Vectors
;---------------------------------------------------------------------
STARTUP code 0x00
    nop
    goto    Startup ;
    nop             ; 0x0002
    nop             ; 0x0003
    goto    ISR     ; 0x0004
PROG code
;---------------------------------------------------------------------
; Macros
;---------------------------------------------------------------------
memset macro Buf_addr,Value,Length
    movlw   Length      ; This macro loads a range of data memory
    movwf   Temp        ; with a specified value. The starting
    movlw   Buf_addr    ; address and number of bytes are also
    movwf   FSR         ; specified.
SetNext movlw Value
    movwf   INDF
    incf    FSR,F
    decfsz  Temp,F
    goto    SetNext
    endm
LFSR macro Address,Offset   ; This macro loads the correct value
    movlw   Address         ; into the FSR given an initial data
    movwf   FSR             ; memory address and offset value.
    movf    Offset,W
    addwf   FSR,F
    endm
;---------------------------------------------------------------------
; Main Code
;---------------------------------------------------------------------
Startup
    bcf     STATUS,RP1
    bsf     STATUS,RP0
    call    Setup
    banksel WREGsave
Main clrwdt ; Clear the watchdog timer.
    btfsc   RXBuffer,7
    bsf     PORTB,2
    btfss   RXBuffer,7
    bcf     PORTB,2
    goto    Main ; Loop forever.
;---------------------------------------------------------------------
; Interrupt Code
;---------------------------------------------------------------------
ISR
    movwf   WREGsave    ; Save WREG
    movf    STATUS,W    ; Get STATUS register
    banksel STATUSsave  ; Switch banks, if needed.
    movwf   STATUSsave  ; Save the STATUS register
    movf    PCLATH,W    ;
    movwf   PCLATHsave  ; Save PCLATH
    movf    FSR,W       ;
    movwf   FSRsave     ; Save FSR
    banksel PIR1
    btfss   PIR1,SSPIF  ; Is this a SSP interrupt?
    goto    $           ; No, just trap here.
    bcf     PIR1,SSPIF
    call    SSP_Handler ; Yes, service SSP interrupt.
    banksel FSRsave
    movf    FSRsave,W   ;
    movwf   FSR         ; Restore FSR
    movf    PCLATHsave,W;
    movwf   PCLATH      ; Restore PCLATH
    movf    STATUSsave,W;
    movwf   STATUS      ; Restore STATUS
    swapf   WREGsave,F  ;
    swapf   WREGsave,W  ; Restore WREG
    retfie              ; Return from interrupt.
;---------------------------------------------------------------------
Setup
;
; Initializes program variables and peripheral registers.
;---------------------------------------------------------------------
    banksel PCON
    bsf     PCON,NOT_POR
    bsf     PCON,NOT_BOR
    banksel ANSEL
    movlw   0x00
    movwf   ANSEL
    banksel Index       ; Clear various program variables
    clrf    Index
    clrf    PORTB
    clrf    PIR1
    banksel TRISB
    ;clrf    TRISB
    bsf     TRISB,4
    bsf     TRISB,6
    bsf     TRISB,1
    bcf     TRISB,2 
    movlw   0x36        ; Setup SSP module for 7-bit
    banksel SSPCON
    movwf   SSPCON      ; address, slave mode
    movlw   NODE_ADDR
    banksel SSPADD
    movwf   SSPADD
    clrf    SSPSTAT
    banksel PIE1        ; Enable interrupts
    bsf     PIE1,SSPIE
    bsf     INTCON,PEIE ; Enable all peripheral interrupts
    bsf     INTCON,GIE  ; Enable global interrupts
    bcf     STATUS,RP0
    return
;---------------------------------------------------------------------
SSP_Handler
 
;---------------------------------------------------------------------
; The I2C code below checks for 5 states:
;---------------------------------------------------------------------
; State 1: I2C write operation, last byte was an address byte.
; SSPSTAT bits: S = 1, D_A = 0, R_W = 0, BF = 1
;
; State 2: I2C write operation, last byte was a data byte.
; SSPSTAT bits: S = 1, D_A = 1, R_W = 0, BF = 1
;
; State 3: I2C read operation, last byte was an address byte.
; SSPSTAT bits: S = 1, D_A = 0, R_W = 1 (see Appendix C for more information)
;
; State 4: I2C read operation, last byte was a data byte.
; SSPSTAT bits: S = 1, D_A = 1, R_W = 1, BF = 0
;
; State 5: Slave I2C logic reset by NACK from master.
; SSPSTAT bits: S = 1, D_A = 1, BF = 0 (see Appendix C for more information)
;
; For convenience, WriteI2C and ReadI2C functions have been used.
;----------------------------------------------------------------------
    banksel SSPSTAT
    movf    SSPSTAT,W   ; Get the value of SSPSTAT
    andlw   b'00101101' ; Mask out unimportant bits in SSPSTAT.
    banksel Temp        ; Put masked value in Temp
    movwf   Temp        ; for comparision checking.
State1:                 ; Write operation, last byte was an   
    movlw   b'00001001' ; address, buffer is full.
    xorwf   Temp,W      ;
    btfss   STATUS,Z    ; Are we in State1?
    goto    State2      ; No, check for next state.....
    memset RXBuffer,0,RX_BUF_LEN ; Clear the receive buffer.
    clrf    Index       ; Clear the buffer index.
    banksel SSPBUF      ; Do a dummy read of the SSPBUF.
    movf    SSPBUF,W
    return
State2:                 ; Write operation, last byte was data,
    movlw   b'00101001' ; buffer is full.
    xorwf   Temp,W
    btfss   STATUS,Z    ; Are we in State2?
    goto    State3      ; No, check for next state.....
    LFSR RXBuffer,Index ; Point to the buffer.
    banksel SSPBUF      ; Get the byte from the SSP.
    movf    SSPBUF,W
    movwf   INDF        ; Put it in the buffer.
    incf    Index,F     ; Increment the buffer pointer.
    movf    Index,W     ; Get the current buffer index.
    sublw   RX_BUF_LEN  ; Subtract the buffer length.
    btfsc   STATUS,Z    ; Has the index exceeded the buffer length?
    clrf    Index       ; Yes, clear the buffer index.
    return
State3:                 ; Read operation, last byte was an address,
    movf    Temp,W ;
    andlw   b'00101100' ; Mask BF bit in SSPSTAT
    xorlw   b'00001100'
    btfss   STATUS,Z    ; Are we in State3?
    goto    State4      ; No, check for next state.....
    clrf    Index       ; Clear the buffer index.
    LFSR RXBuffer,Index ; Point to the buffer
    movf    INDF,W      ; Get the byte from buffer.
    call    WriteI2C    ; Write the byte to SSPBUF
    incf    Index,F     ; Increment the buffer index.
    return
State4:                 ; Read operation, last byte was data,
    banksel SSPCON      ; buffer is empty.
    btfsc   SSPCON, CKP
    goto    State5
 
    movlw   b'00101100'
    xorwf   Temp,W
    btfss   STATUS,Z    ; Are we in State4?
    goto    State5      ; No, check for next state....
    movf    Index,W     ; Get the current buffer index.
    sublw   RX_BUF_LEN  ; Subtract the buffer length.
    btfsc   STATUS,Z    ; Has the index exceeded the buffer length?
    clrf    Index       ; Yes, clear the buffer index.
    LFSR RXBuffer,Index ; Point to the buffer
    movf    INDF,W      ; Get the byte
    call    WriteI2C    ; Write to SSPBUF
    incf    Index,F     ; Increment the buffer index.
    return
 
State5:
    movf    Temp,W      ; NACK received when sending data to the master
    andlw   b'00101000' ; Mask RW bit in SSPSTAT
    xorlw   b'00101000' ;
    btfss   STATUS,Z    ;
    goto    I2CErr  ;
    return              ; If we aren’t in State5, then something is
                        ; wrong.
I2CErr nop
    banksel PORTB       ; Something went wrong! Set LED
    bsf     PORTB,2     ; and loop forever. WDT will reset
    goto    $           ; device, if enabled.
    return
;---------------------------------------------------------------------
; WriteI2C
;---------------------------------------------------------------------
WriteI2C
    banksel SSPSTAT
    btfsc   SSPSTAT,BF  ; Is the buffer full?
    goto    WriteI2C    ; Yes, keep waiting.
    banksel SSPCON      ; No, continue.
DoI2CWrite
    bcf     SSPCON,WCOL ; Clear the WCOL flag.
    movwf   SSPBUF      ; Write the byte in WREG
    btfsc   SSPCON,WCOL ; Was there a write collision?
    goto    DoI2CWrite
    bsf     SSPCON,CKP  ; Release the clock.
    return
 
end