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