Subversion Repositories group.electronics

Rev

Blame | Last modification | View Log | RSS feed

    list        p=16F84A
    include    "p16F84a.inc"

;***** CONFIGURATION
           __CONFIG _PWRTE_ON & _HS_OSC & _WDT_OFF

; pin assignments
    #define SDA         0           ; Pin 0
    #define SCL         1           ; Pin 1
    #define TRIS_SDA    TRISB,SDA
    #define TRIS_SCL    TRISB,SCL
    #define I2C_SDA     PORTB,SDA
    #define I2C_SCL     PORTB,SCL
    #define LED         PORTB,2

    #define I2C_SLAVE1 0x27
    #define I2C_SLAVE2 0x26

    CBLOCK     0CH

        _I              ; Loop counter
        byte_send       ; Byte to send to i2c
        byte_read       ; Byte read from i2c
        byte_temp       ; Store byte while address send
        i2c_addr        ; Address to read/write
        i2c_ret         ; I2C Return Value

        dly_loop1       ; Loops for delays
        dly_loop2
    ENDC

    ORG 0
    goto start           ; jump over to main routine

;***** Initialisation
start
        ; configure ports
        clrw                    ; configure PORTB as all outputs
        tris    PORTB
        clrf    PORTB
        movlw   b'00001011'     ; RA0 - Input - Toggle SW, Mode Select
                                ; RA1 - Input - Pulse SW, Record
                                ; RA2 - Output - LED, Mode
                                ; RA3 - Input - Switch, Reset
        tris    PORTA

        clrf    byte_send
        clrf    byte_read

;***** Main loop
main_loop
        bsf     LED
        call    ReadByte        ; Read byte from SLAVE2
        bcf     LED
        
        movfw   byte_read       ; Copy the byte read
        ;movlw   b'10101010'
        movwf   byte_send       ;   into the byte to send

        call    Delay_Short

        bsf     LED
        call    SendByte       ; Send byte to SLAVE1
        bcf     LED

        call    Delay_Long
        goto    main_loop

ReadByte
        movlw   I2C_SLAVE2      ; Address of Slave2
        movwf   i2c_addr
        bsf     STATUS,C        ; Set mode to read
        call    I2C_Start       ; Send the address with mode
        call    ReadAck
        ;movf    i2c_ret
        ;btfss   STATUS,Z
        ;goto    SendErr
        call    I2C_Read        ; Read byte into byte_read
        call    ReadAck

        call    I2C_End

        return

 SendByte
        movfw   byte_send       ; Save the byte while sending address
        movwf   byte_temp
        movlw   I2C_SLAVE1      ; 7-bit address of dev
        movwf   i2c_addr        ; Set it in the address
        bcf     STATUS,C        ; Use Write mode ('0')
        call    I2C_Start       ; Start a transmission
        call    ReadAck         ; Wait for Ack from slave
        ;movf    i2c_ret         ; Check return value
        ;btfss   STATUS,Z        ; Goto SendEnd on NACK
        ;goto    SendErr
        movfw   byte_temp
        movwf   byte_send
        ;movfw   byte_send       ; Copy byte to write (counter) to w
        call    I2C_Write       ; Write the byte to the line
        call    ReadAck            ; Should read byte from bus here
                                ;  checking that its a Nack

        call    I2C_End         ; End the packet

        return

SendErr
        call    I2C_End

        return


I2C_Start
        rlf     i2c_addr,f      ; Attach mode (STATUS,C) to 1st bit
        call    Start           ; Start the Trans
        movfw   i2c_addr
        movwf   byte_send       ; Send the complete address
        call    I2C_Write       ; Write byte to port
        return

I2C_End
        call    Stop
        return

I2C_Write
        ;movwf   byte_send
        movlw   .8              ; 8 bits to send
        movwf    _I
_WriteBit
        rlf     byte_send,f        ; Move highest bit to C
        btfss   STATUS,C        ; If 'C' is clear
        call    SDA_Low         ;   -> Set data low
        btfsc   STATUS,C        ; If 'C' is set
        call    SDA_High        ;   -> Set data high

        call    SCL_Pulse
        
        decfsz  _I,f        ; Decrement counter, if not clear
        goto    _WriteBit         ;   -> Send next bit
        call    SDA_Low         ; Set low to allow slave to write
        return

I2C_Read
        movlw   .8              ; 8 bits to read
        movwf    _I
        clrf    byte_read       ; Clear the read byte
        bcf     STATUS,C
        call    SDA_High        ; Set high so slave can write
_ReadBit
        call    SCL_High       ; Pull Clock high, bit should arrive
        ;btfss   I2C_SDA        ; If sda is clear
        bcf     STATUS,C         ;   -> Set status 0
        btfsc   I2C_SDA        ; If sda is set
        bsf     STATUS,C
        call    SCL_Low         ; Send the clock low

        rlf     byte_read,f        ; Move highest bit to C

        decfsz  _I,f        ; Decrement counter, if not clear
        goto    _ReadBit         ;   -> Send next bit
        ;call    SDA_Low         ; Set low to allow slave to write
        return

Nack                            ; Clock a high SDA
        call    SDA_High
        call    SCL_Pulse
        return

Ack                            ; Clock a high SDA
        call    SDA_Low
        call    SCL_Pulse
        return

ReadAck
        call    SDA_High        ; SDA high to allow slave to write
        call    SCL_High
        clrf    i2c_ret
        btfsc   I2C_SDA
        bsf     i2c_ret,0
        call    SCL_Low
        return

Start
        call    SDA_High
        call    SCL_High
        call    SDA_Low
        call    SCL_Low
        return

Stop                            ; Bring SDA high while Clock high
        call    SCL_Low
        call    SDA_Low
        call    SCL_High
        call    SDA_High
        return

SCL_Pulse
        call  SCL_High
        call  SCL_Low
        return

SDA_High
        bsf     STATUS,RP0      ; Bank 1
        bsf     TRIS_SDA        ; Make SDA pin input
        bcf     STATUS,RP0      ; Back to bank 0
        call    Delay_Short
        return

SDA_Low
        bcf     I2C_SDA
        bsf     STATUS,RP0
        bcf     TRIS_SDA        ; Make SDA pin output
        bcf     STATUS,RP0
        call    Delay_Short
        return

SCL_High
        bsf     STATUS,RP0      ; Bank 1
        bsf     TRIS_SCL        ; Make SDA pin input
        bcf     STATUS,RP0      ; Back to bank 0
        call    Delay_Short
        return

SCL_Low
        bcf     I2C_SCL
        bsf     STATUS,RP0
        bcf     TRIS_SCL        ; Make SDA pin output
        bcf     STATUS,RP0
        call    Delay_Short
        return

Delay_Short                 ; 25us delay
        movlw   .5
        movwf   dly_loop2
Delay_Short_1
        nop
        decfsz  dly_loop2,f
        goto    Delay_Short_1
        return

Delay_Long
        movlw   .250        ; 250ms delay
        movwf   dly_loop1
Outer
        movlw   .110        ; Close to 1ms when set to .110
        movwf   dly_loop2
Inner
        nop
        nop
        nop
        nop
        nop
        nop
        decfsz  dly_loop2,f
        goto    Inner
        decfsz  dly_loop1,f
        goto    Outer
        return

END