PIC Microcontoller Memory Method

24LC65 read/write

from Tsvetan Usunov [usunov at OLIMEX.COM]

PC_OFFSET                       equ     0x1A    ;EEPROM variables
EEADDRHI                        equ     0x1B    ;
EEADDRLO                        equ     0x1C    ;
EEDATA                          equ     0x1D    ;
EEBYTE                          equ     0x1E    ;
COUNTER                         equ     0x1F    ;

#define         SCL             port_c,6        ;EEPROM SCL
#define         SDA             port_c,7        ;EEPROM SDA

#define         SDAindef        b'10110100'     ;port_c
#define         SDAoutdef       b'00110100'     ;

#define         EE_OK                   PC_OFFSET,7     ;Bit 7 in PC_OFFSET used as OK flag for EE
#define         OK                      1               ;
#define         NO                      0               ;

;-----------------------------------------------
;               EEPROM PROCEDURES
;-----------------------------------------------

EE_readcurrent          movlw   b'10000101'     ;
                        movwf   PC_OFFSET       ;
                        goto    Init_read_control
EE_write                                        ;
                        movlw   b'10000000'     ;PC_OFFSET.7=OK, write sequence
                        goto    Init_write_control
EE_read                                         ;
                        movlw   b'10000100'     ;PC_OFFSET.7=OK, read sequence
Init_write_control      movwf   PC_OFFSET       ;
                        movlw   b'10100000'     ;control byte 1010 device 000 address 0(Write)
Start_bit               bcf     SDA             ;Start bit, SDA and SCL preset to '1'
Prep_transfer_byte      movwf   EEBYTE          ;
                        movlw   SDAoutdef       ;
                        tris    port_c          ;
                        movlw   .8              ;Counter to transfer 8 bits
                        movwf   COUNTER         ;
Output_byte             bcf     SCL             ;Set clock low during data set-up
                        rlf     EEBYTE,1        ;Rotate left, high order bit into carry bit
                        bcf     SDA             ;Set data low, if rotated carry bit is
                        SKPNC                   ;   a '1', then:
                        bsf     SDA             ;reset data pin to a one, otherwise leave low
                        bsf     SCL             ;clock data into EEPROM
                        goto    $+1             ;
                        goto    $+1             ;
                        decfsz  COUNTER,1       ;Repeat until entire byte is sent
                        goto    Output_byte     ;
                        movlw   SDAindef        ;
                        SKPNC                   ;if SDA=1 then tristate port to allow
                        tris    port_c          ;pullup to hold '1', avoiding bus contention
                                                ;if EEPROM acks in < 1us after clock goes low
                        bcf     SCL             ;Set SCL low, 0.5us < ack valid < 3us
                        tris    port_c          ;If SDA = '0' wait until SCL is low to set SDA to
                                                ;input. If done above, could have sent STOP bit
                        nop                     ;May be necessary for SCL Tlow  at low voltage,
                        goto    $+1             ;also give resistor time to pull up bus if last 
                        goto    $+1             ;bit written = '0' and there is no ack from slave
                        bsf     SCL             ;Raise SCL, EEPROM acknowledge still valid
                        btfsc   SDA             ;Check SDA for acknowledge (low)
                        bcf     EE_OK           ;If SDA not low (no ack), set error flag
                        bcf     SCL             ;Lower SCL, EEPROM release bus
                        btfss   EE_OK           ;If no error continue, else stop bit
                        goto    Stop_bit
                        movfw   PC_OFFSET
                        andlw   b'00001111'
                        addwf   pc,1
                        goto    Init_addressHi  ;PC offset=0, write control done, send address hi
                        goto    Init_addressLo  ;PC offset=1, write address low
                        goto    Init_write_data ;PC offset=2, write address done, send data
                        goto    Stop_bit        ;PC offset=3, write done, send stop bit
                        goto    Init_addressHi  ;PC offset=4, write control done, send address hi
                        goto    Init_addressLo  ;PC offset=5, write address low
                        goto    Init_read_control;PC offset=6, send read control
                        goto    Read_bit_counter;PC offset=7, set counter and read byte
                        goto    Stop_bit        ;PC offset=8, random read done, send stop
Init_addressHi          incf    PC_OFFSET,1     ;Increment PC offset to 2 (write) or to 4 (read)
                        movfw   EEADDRHI        ;Put EEPROM address in W, ready to send to EEPROM
                        goto    Prep_transfer_byte
Init_addressLo          incf    PC_OFFSET,1     ;Increment PC offset to 2 (write) or to 4 (read)
                        movfw   EEADDRLO        ;Put EEPROM address in W, ready to send to EEPROM
                        goto    Prep_transfer_byte
Init_write_data         incf    PC_OFFSET,1     ;Increment PC offset to go to STOP_BIT next
                        movfw   EEDATA          ;Put EEPROM data in W, ready to send to EEPROM
                        goto    Prep_transfer_byte
Init_read_control       bsf     SCL             ;Raise SCL
                        incf    PC_OFFSET,1     ;Increment PC offset to go to READ_BIT_COUNTER next
                        movlw   b'10100001'     ;Set up read control byte, ready to send to EEPROM
                        goto    Start_bit       ;bit 0 = '1' for read operation
Read_bit_counter        movlw   .8              ;Set counter so 8 bits will be read into EEDATA
                        movwf   COUNTER
Input_byte              bsf     SCL             ;Raise SCL, SDA valid.  SDA still input from ack
                        bsf     carryf          ;Assume bit to be read = 1
                        btfss   SDA             ;Check if SDA = 1
                        bcf     carryf          ;if SDA not = 1 then clear carry bit
                        rlf     EEDATA,1        ;rotate carry bit (=SDA) into EEDATA;
                        bcf     SCL             ;Lower SCL
                        decfsz  COUNTER,1       ;Decrement counter
                        goto    Input_byte      ;Read next bit if not finished reading byte
Stop_bit                bcf     SDA             ;SDA=0, on TRIS, to prepare for transition to '1' 
                        movlw   SDAoutdef       ;SDA and SCL set to outputs, Bit0 and Bit1 ' input
                        tris    port_c          ;
                        bsf     SCL             ;SCL = 1 to prepare for STOP bit
                        goto    $+1             ;4 NOPs neccessary for I2C spec Tsu:sto = 4.7us                  
                        goto    $+1
                        nop
                        bsf     SDA             ;Stop bit, SDA transition to '1' while SCL high
                        btfss   EE_OK           ;Check for error
                        retlw   NO              ;if error, send back NO 
                        retlw   OK              ;if no error, send back OK



Interested:

See:

Questions: