I managed to get this working with a 16F690 and a 24AA65 eeprom. The 24AA65 takes a high address and an low address, so the eeprom read and write may have to be re-done to suit your particular eeprom. I also had to back the delays off to 1ms. The datasheet for the 24AA65 call for 5us delays, but I don't think my pic is that accurate.
To use this, set these constants
#define I2CPORT PORTB
#define SDA_PORT 4
#define SCL_PORT 6
#define waittime 1 ms
#define chipwrite b'10100000'
#define chipread b'10100001'
i2c.h starts here
*****************************
'Subs
' eeprom_send(addrh,addrl,info) Writes info to eeprom prom_addr and address addr
' eeprom_receive(addrh,addrl) Reads from addrh and addrl
sub ICC_initialize
ADOff 'make port digital
DIR I2CPORT b'00000000' 'make SCL and SDA outputs
DIR SDA OUT
DIR SCL OUT
SET SDA ON 'bring both SCL and SDA high
wait waittime
SET SCL ON
wait waittime
end sub
sub ICC_START
'subroutine to send start bit
DIR SDA OUT 'set SDA as output
wait waittime
SET SDA ON 'take SDA high
wait waittime
SET SCL ON 'take SCL high
wait waittime 'delay
SET SDA OFF 'take SDA low while clock high for start bit
wait waittime 'delay
SET SCL OFF 'take SCL low
end sub
sub ICC_stop
'subroutine to send a stop bit
SET SCL OFF
wait waittime
DIR SDA OUT 'set SDA as output
SET SDA OFF 'take SDA low
SET SCL ON 'take SCL high
wait waittime 'delay 1 micro second
SET SDA ON 'take SDA high while SCL high for stop bit
wait waittime 'delay 5 micro second
end sub
sub ICC_send(XMIT)
'subroutine to send 8 bits
DIR SDA OUT 'set SDA as output
SET SCL OFF
wait waittime
for counter = 1 to 8
SET SDA OFF 'clear SDA
ROTATE XMIT LEFT 'if bit of XMIT is 1, set SDA
IF STATUS.C ON THEN SET SDA ON
SET SCL ON 'take SCL high
wait waittime 'delay 5micro second
SET SCL OFF 'take SCL low
wait waittime
NEXT 'proceed with rest of bits in XMIT
'NOW acknowledge send
DIR SDA IN 'set SDA as input
SET SCL ON 'take SCL high
wait waittime 'delay 5microseconds
SET SCL OFF 'take SCL low
wait waittime
DIR SDA OUT 'set SDA as output
end sub
function ICC_read
'subroutine to read a byte
'set SDA as input
DIR SDA IN
RX = 0
for counter = 1 to 8
SET SCL ON 'take SCL high
wait waittime
SET STATUS.C OFF
if SDA ON Then SET STATUS.C ON
Rotate RX Left
SET SCL OFF 'take SCL low
wait waittime 'delay 5microseconds
NEXT 'do this for all 8 bits
ICC_read = RX
end function
sub ICC_send_ack
'subroutine to send the acknowledge bit
DIR SDA OUT 'set SDA as output
SET SDA OFF 'take SDA low
wait waittime 'delay 5microsends
SET SCL ON 'take SCL high
wait waittime 'delay 5microsends
SET SCL OFF 'take SCL low
wait waittime 'delay 5microsends
end sub
sub ICC_send_no_ack
'subroutine to send neg ack
DIR SDA OUT 'set SDA as output
SET SDA ON 'take SDA high
wait waittime 'delay 5microseconds
SET SCL ON 'take SCL high
wait waittime 'delay 5microseconds
SET SCL OFF 'take SCL low
wait waittime 'delay 5microseconds
end sub
sub eeprom_send(addr1,addr0,info)
DIR SDA OUT 'set SCL and SDA as outputs
DIR SCL OUT
ICC_initialize 'call init and start subroutine
ICC_START
ICC_send(chipwrite) 'send prom_addr
ICC_send(addr1) 'send high memory addr
ICC_send(addr0) 'send low memory addr
ICC_send(info) 'send data
ICC_STOP 'call stop subroutine
end sub
function eeprom_receive(addr1, addr0)
DIR SDA OUT 'set SCL and SDA as outputs
DIR SCL OUT
ICC_initialize 'call init and start subroutine
ICC_START
ICC_send(chipwrite) 'send prom_addr
ICC_send(addr1) 'send high memory addr
ICC_send(addr0) 'send low memory addr
ICC_STOP
ICC_START
ICC_send(chipread) 'send prom_addr for read
eeprom_receive = ICC_read 'call subroutine read
ICC_send_no_ack 'call subroutine no_ack
DIR SDA OUT
ICC_STOP
end function
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I managed to get this working with a 16F690 and a 24AA65 eeprom. The 24AA65 takes a high address and an low address, so the eeprom read and write may have to be re-done to suit your particular eeprom. I also had to back the delays off to 1ms. The datasheet for the 24AA65 call for 5us delays, but I don't think my pic is that accurate.
To use this, set these constants
#define I2CPORT PORTB
#define SDA_PORT 4
#define SCL_PORT 6
#define waittime 1 ms
#define chipwrite b'10100000'
#define chipread b'10100001'
i2c.h starts here
*****************************
'Subs
' eeprom_send(addrh,addrl,info) Writes info to eeprom prom_addr and address addr
' eeprom_receive(addrh,addrl) Reads from addrh and addrl
'Software I2C mode constants
#define I2CPORT PORTB
#define SDA_PORT 4
#define SCL_PORT 6
#define SDA I2CPORT.SDA_PORT
#define SCL I2CPORT.SCL_PORT
#define waittime 1 ms
#define chipwrite b'10100000'
#define chipread b'10100001'
sub ICC_initialize
ADOff 'make port digital
DIR I2CPORT b'00000000' 'make SCL and SDA outputs
DIR SDA OUT
DIR SCL OUT
SET SDA ON 'bring both SCL and SDA high
wait waittime
SET SCL ON
wait waittime
end sub
sub ICC_START
'subroutine to send start bit
DIR SDA OUT 'set SDA as output
wait waittime
SET SDA ON 'take SDA high
wait waittime
SET SCL ON 'take SCL high
wait waittime 'delay
SET SDA OFF 'take SDA low while clock high for start bit
wait waittime 'delay
SET SCL OFF 'take SCL low
end sub
sub ICC_stop
'subroutine to send a stop bit
SET SCL OFF
wait waittime
DIR SDA OUT 'set SDA as output
SET SDA OFF 'take SDA low
SET SCL ON 'take SCL high
wait waittime 'delay 1 micro second
SET SDA ON 'take SDA high while SCL high for stop bit
wait waittime 'delay 5 micro second
end sub
sub ICC_send(XMIT)
'subroutine to send 8 bits
DIR SDA OUT 'set SDA as output
SET SCL OFF
wait waittime
for counter = 1 to 8
SET SDA OFF 'clear SDA
ROTATE XMIT LEFT 'if bit of XMIT is 1, set SDA
IF STATUS.C ON THEN SET SDA ON
SET SCL ON 'take SCL high
wait waittime 'delay 5micro second
SET SCL OFF 'take SCL low
wait waittime
NEXT 'proceed with rest of bits in XMIT
'NOW acknowledge send
DIR SDA IN 'set SDA as input
SET SCL ON 'take SCL high
wait waittime 'delay 5microseconds
SET SCL OFF 'take SCL low
wait waittime
DIR SDA OUT 'set SDA as output
end sub
function ICC_read
'subroutine to read a byte
'set SDA as input
DIR SDA IN
RX = 0
for counter = 1 to 8
SET SCL ON 'take SCL high
wait waittime
SET STATUS.C OFF
if SDA ON Then SET STATUS.C ON
Rotate RX Left
SET SCL OFF 'take SCL low
wait waittime 'delay 5microseconds
NEXT 'do this for all 8 bits
ICC_read = RX
end function
sub ICC_send_ack
'subroutine to send the acknowledge bit
DIR SDA OUT 'set SDA as output
SET SDA OFF 'take SDA low
wait waittime 'delay 5microsends
SET SCL ON 'take SCL high
wait waittime 'delay 5microsends
SET SCL OFF 'take SCL low
wait waittime 'delay 5microsends
end sub
sub ICC_send_no_ack
'subroutine to send neg ack
DIR SDA OUT 'set SDA as output
SET SDA ON 'take SDA high
wait waittime 'delay 5microseconds
SET SCL ON 'take SCL high
wait waittime 'delay 5microseconds
SET SCL OFF 'take SCL low
wait waittime 'delay 5microseconds
end sub
sub eeprom_send(addr1,addr0,info)
DIR SDA OUT 'set SCL and SDA as outputs
DIR SCL OUT
ICC_initialize 'call init and start subroutine
ICC_START
ICC_send(chipwrite) 'send prom_addr
ICC_send(addr1) 'send high memory addr
ICC_send(addr0) 'send low memory addr
ICC_send(info) 'send data
ICC_STOP 'call stop subroutine
end sub
function eeprom_receive(addr1, addr0)
DIR SDA OUT 'set SCL and SDA as outputs
DIR SCL OUT
ICC_initialize 'call init and start subroutine
ICC_START
ICC_send(chipwrite) 'send prom_addr
ICC_send(addr1) 'send high memory addr
ICC_send(addr0) 'send low memory addr
ICC_STOP
ICC_START
ICC_send(chipread) 'send prom_addr for read
eeprom_receive = ICC_read 'call subroutine read
ICC_send_no_ack 'call subroutine no_ack
DIR SDA OUT
ICC_STOP
end function