Could someone please provide an example interfacing a PIC with a serial eeprom using I2C? I received some 24AA65's and I can't figure out how to begin using them with a PIC16.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I hope to implement built-in support for hardware I2C in GCBASIC at some stage in the near future, probably within the next couple of weeks. I'll post a link to the updated ssp.h as soon as I can.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Any luck with this? I've looked over the pdf file, but I cant get past page 62. It seems that my pic has a different SSPCON register and I can't set it to hardware master mode?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
sub I2C_read(RX)
'subroutine to read a byte, store it in RX
'set SDA as input
DIR SDA IN
FOR counter = 7 to 0
STEP -1
'take SCL high
SET SCL ON
'if SDA clear, set bit as 1
RX.counter = 0
IF (SDA = OFF) THEN RX.counter = 1
'delay 5microseconds
wait 5 us
'take SCL low
SET SCL OFF
'delay 5microseconds
wait 5 us
NEXT
'do this for all 8 bits
end sub
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
There are a couple of problems with the syntax of your program:
- It is not possible to set a different bit of a variable based on another variable
- So far, none of the released versions of GCBASIC allow a bit to be set or checked using the equals sign. This is fixed in the newest release of GCBASIC, which you can get at http://gcbasic.sourceforge.net/newfiles/update.zip
It also seems that for I2C, a start and stop "condition" are required. The I2C specification at http://www.nxp.com/acrobat_download/literature/9398/39340011.pdf has explanations of these, and some timing diagrams which may be of assistance. The datasheets for PIC chips with "MSSP" modules may also be of some help - I used the 18F4550 datasheet, and found that it helped quite a bit.
Here is the code that I have at the moment. It has not been tested, and may need to be altered:
'Initialise code
sub I2CInit
dir I2C_Clock In
dir I2C_Data In
end sub
sub I2CReceive(Address, Data)
'Take control of bus
Set I2C_Data On
set I2C_Clock On
dir I2C_Data Out
dir I2C_Clock out
'Start Condition
set I2C_Data off
'Send Address (7 bits)
For Temp = 1 to 7
Set I2C_Data Off
if Address.6 On Then Set I2C_Data On
Set I2C_Clock On
Wait I2C_HalfBitTime
Set I2C_Clock Off
Wait I2C_HalfBitTime
Rotate Address Left
next
'Send direction bit (read)
Set I2C_Data On
Set I2C_Clock On
Wait I2C_HalfBitTime
Set I2C_Clock Off
Wait I2C_HalfBitTime
Dir I2C_Data In
'Get Ack
Set I2C_Clock On
Wait I2C_HalfBitTime
Set I2C_Clock Off
Wait I2C_HalfBitTime
'Get Data (8 bits)
For Temp = 1 to 8
Set I2C_Clock On
Wait I2C_HalfBitTime
Set STATUS.C Off
if I2C_Data On Then Set STATUS.C On
Rotate Data Right
Set I2C_Clock Off
Wait I2C_HalfBitTime
Next
'Send Ack
Dir I2C_Data out
Set I2C_Data On
Set I2C_Clock On
Wait I2C_HalfBitTime
Set I2C_Clock Off
Wait I2C_HalfBitTime
'Stop condition
set I2C_Clock On
Wait I2C_HalfBitTime
Set I2C_Data on
Wait I2C_HalfBitTime
'Release control
Dir I2C_Data in
Dir I2C_Clock In
end sub
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I see the new routines added in the ssp.h file to support i2c mode.
Could I get a simple example of using a PIC that doesn't suppport master i2c mode to interface with something else?
Would these functions work?
I2CMode(Slave)
I2CSend(data) ' this one looks like it's empty in ssp.h ?
I2CReceive(data)
I really appreciate you providing this. I notice there are no functions to send start and stop bits? Should these be emulated in software, or will the SSPCON handle it?
Steve
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Here is the code I was working with to try to implement software i2c.
Steve
'Subs
' eeprom_send(prom_addr,addrh,addrl,info) Writes info to eeprom prom_addr and address addr
' sub eeprom_receive(prom_addr,addrh,addrl,info) Receives into info eeprom prom_addr and address addr
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
SET SCL ON
end sub
sub ICC_START
'subroutine to send start bit
DIR SDA OUT 'set SDA as output
SET SDA ON 'take SDA high
SET SCL ON 'take SCL high
wait waittime us 'delay
SET SDA OFF 'take SDA low while clock high for start bit
wait waittime us 'delay
SET SCL OFF 'take SCL low
end sub
sub ICC_stop
'subroutine to send a stop bit
SET SDA OFF 'take SDA low
SET SCL ON 'take SCL high
wait waittime us 'delay 1 micro second
SET SDA ON 'take SDA high while SCL high for stop bit
wait waittime us '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
for counter = 1 to 8
wait waittime us
SET SDA OFF 'clear SDA
ROTATE XMIT LEFT 'if bit of XMIT is 1, set SDA
IF STATUS.C ON THEN SET SDA ON
IF STATUS.C ON THEN number = 1
SET SCL ON 'take SCL high
wait waittime us 'delay 5micro second
SET SCL OFF 'take SCL low
wait waittime us
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 us 'delay 5microseconds
SET SCL OFF 'take SCL low
wait waittime us
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 us
Set STATUS.C ON
if SDA ON Then Set STATUS.C OFF
Rotate RX Left
wait waittime us 'delay 5microseconds
SET SCL OFF 'take SCL low
wait waittime us '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 us 'delay 5microsends
SET SCL ON 'take SCL high
wait waittime us 'delay 5microsends
SET SCL OFF 'take SCL low
wait waittime us '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 us 'delay 5microseconds
SET SCL ON 'take SCL high
wait waittime us 'delay 5microseconds
SET SCL OFF 'take SCL low
wait waittime us 'delay 5microseconds
end sub
sub eeprom_send(prom_addr,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(prom_addr) '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(prom_addr,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(prom_addr) 'send prom_addr
ICC_send(addr1) 'send high memory addr
ICC_send(addr0) 'send low memory addr
ICC_START
ICC_send(prom_addr) 'send prom_addr for read
eeprom_receive = ICC_read 'call subroutine read
ICC_send_no_ack 'call subroutine no_ack
DIR SDA OUT
DIR SCL 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:
The I2C routines in ssp.h aren't complete - I haven't touched them since I started adding 18F support to GCBASIC. I'll finish them once I have GCBASIC 0.9.3.0 debugged and uploaded.
Thanks for posting your I2C routines. Could I redistribute them with GCBASIC 0.9.4.0?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Could someone please provide an example interfacing a PIC with a serial eeprom using I2C? I received some 24AA65's and I can't figure out how to begin using them with a PIC16.
This link may be of some assistance:
http://ww1.microchip.com/downloads/en/DeviceDoc/i2c.pdf
I hope to implement built-in support for hardware I2C in GCBASIC at some stage in the near future, probably within the next couple of weeks. I'll post a link to the updated ssp.h as soon as I can.
Any luck with this? I've looked over the pdf file, but I cant get past page 62. It seems that my pic has a different SSPCON register and I can't set it to hardware master mode?
Will this example work? Here is a snippet:
'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
sub I2C_read(RX)
'subroutine to read a byte, store it in RX
'set SDA as input
DIR SDA IN
FOR counter = 7 to 0
STEP -1
'take SCL high
SET SCL ON
'if SDA clear, set bit as 1
RX.counter = 0
IF (SDA = OFF) THEN RX.counter = 1
'delay 5microseconds
wait 5 us
'take SCL low
SET SCL OFF
'delay 5microseconds
wait 5 us
NEXT
'do this for all 8 bits
end sub
There are a couple of problems with the syntax of your program:
- It is not possible to set a different bit of a variable based on another variable
- So far, none of the released versions of GCBASIC allow a bit to be set or checked using the equals sign. This is fixed in the newest release of GCBASIC, which you can get at http://gcbasic.sourceforge.net/newfiles/update.zip
It also seems that for I2C, a start and stop "condition" are required. The I2C specification at http://www.nxp.com/acrobat_download/literature/9398/39340011.pdf has explanations of these, and some timing diagrams which may be of assistance. The datasheets for PIC chips with "MSSP" modules may also be of some help - I used the 18F4550 datasheet, and found that it helped quite a bit.
Here is the code that I have at the moment. It has not been tested, and may need to be altered:
Code to put in main program:
#include "i2c.h"
#define I2C_Data PORTB.4
#define I2C_Clock PORTB.6
'Time for 100 us
#define I2C_HalfBitTime 5 us
Code to put in to "i2c.h":
#startup I2CInit
'Initialise code
sub I2CInit
dir I2C_Clock In
dir I2C_Data In
end sub
sub I2CReceive(Address, Data)
'Take control of bus
Set I2C_Data On
set I2C_Clock On
dir I2C_Data Out
dir I2C_Clock out
'Start Condition
set I2C_Data off
'Send Address (7 bits)
For Temp = 1 to 7
Set I2C_Data Off
if Address.6 On Then Set I2C_Data On
Set I2C_Clock On
Wait I2C_HalfBitTime
Set I2C_Clock Off
Wait I2C_HalfBitTime
Rotate Address Left
next
'Send direction bit (read)
Set I2C_Data On
Set I2C_Clock On
Wait I2C_HalfBitTime
Set I2C_Clock Off
Wait I2C_HalfBitTime
Dir I2C_Data In
'Get Ack
Set I2C_Clock On
Wait I2C_HalfBitTime
Set I2C_Clock Off
Wait I2C_HalfBitTime
'Get Data (8 bits)
For Temp = 1 to 8
Set I2C_Clock On
Wait I2C_HalfBitTime
Set STATUS.C Off
if I2C_Data On Then Set STATUS.C On
Rotate Data Right
Set I2C_Clock Off
Wait I2C_HalfBitTime
Next
'Send Ack
Dir I2C_Data out
Set I2C_Data On
Set I2C_Clock On
Wait I2C_HalfBitTime
Set I2C_Clock Off
Wait I2C_HalfBitTime
'Stop condition
set I2C_Clock On
Wait I2C_HalfBitTime
Set I2C_Data on
Wait I2C_HalfBitTime
'Release control
Dir I2C_Data in
Dir I2C_Clock In
end sub
Hugh --
I see the new routines added in the ssp.h file to support i2c mode.
Could I get a simple example of using a PIC that doesn't suppport master i2c mode to interface with something else?
Would these functions work?
I2CMode(Slave)
I2CSend(data) ' this one looks like it's empty in ssp.h ?
I2CReceive(data)
I really appreciate you providing this. I notice there are no functions to send start and stop bits? Should these be emulated in software, or will the SSPCON handle it?
Steve
Here is the code I was working with to try to implement software i2c.
Steve
'Subs
' eeprom_send(prom_addr,addrh,addrl,info) Writes info to eeprom prom_addr and address addr
' sub eeprom_receive(prom_addr,addrh,addrl,info) Receives into info eeprom prom_addr and address addr
'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 5
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
SET SCL ON
end sub
sub ICC_START
'subroutine to send start bit
DIR SDA OUT 'set SDA as output
SET SDA ON 'take SDA high
SET SCL ON 'take SCL high
wait waittime us 'delay
SET SDA OFF 'take SDA low while clock high for start bit
wait waittime us 'delay
SET SCL OFF 'take SCL low
end sub
sub ICC_stop
'subroutine to send a stop bit
SET SDA OFF 'take SDA low
SET SCL ON 'take SCL high
wait waittime us 'delay 1 micro second
SET SDA ON 'take SDA high while SCL high for stop bit
wait waittime us '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
for counter = 1 to 8
wait waittime us
SET SDA OFF 'clear SDA
ROTATE XMIT LEFT 'if bit of XMIT is 1, set SDA
IF STATUS.C ON THEN SET SDA ON
IF STATUS.C ON THEN number = 1
SET SCL ON 'take SCL high
wait waittime us 'delay 5micro second
SET SCL OFF 'take SCL low
wait waittime us
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 us 'delay 5microseconds
SET SCL OFF 'take SCL low
wait waittime us
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 us
Set STATUS.C ON
if SDA ON Then Set STATUS.C OFF
Rotate RX Left
wait waittime us 'delay 5microseconds
SET SCL OFF 'take SCL low
wait waittime us '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 us 'delay 5microsends
SET SCL ON 'take SCL high
wait waittime us 'delay 5microsends
SET SCL OFF 'take SCL low
wait waittime us '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 us 'delay 5microseconds
SET SCL ON 'take SCL high
wait waittime us 'delay 5microseconds
SET SCL OFF 'take SCL low
wait waittime us 'delay 5microseconds
end sub
sub eeprom_send(prom_addr,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(prom_addr) '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(prom_addr,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(prom_addr) 'send prom_addr
ICC_send(addr1) 'send high memory addr
ICC_send(addr0) 'send low memory addr
ICC_START
ICC_send(prom_addr) 'send prom_addr for read
eeprom_receive = ICC_read 'call subroutine read
ICC_send_no_ack 'call subroutine no_ack
DIR SDA OUT
DIR SCL OUT
ICC_STOP
end function
The I2C routines in ssp.h aren't complete - I haven't touched them since I started adding 18F support to GCBASIC. I'll finish them once I have GCBASIC 0.9.3.0 debugged and uploaded.
Thanks for posting your I2C routines. Could I redistribute them with GCBASIC 0.9.4.0?
Sure, that would be fine.
I would feel better about it if I could actually get them working!