Page 1 of 1

I2C EEPROM Question

Posted: 04 Feb 2006 22:42
by sparkz
I've been trying to get a 24LC256 working with a 16F877A on a EasyPIC3 without much luck. As far as I can tell I have the wiring correct with pullups on SDA and SCL. I have chip address pins set correctly. I've tried different chips (sizes and make) with the same result. It always on the first write operation.

I tried a I2C and software I2C examples with equal lack of success (from the basic examples directories).

Is there something fundamental, which I may have missed, to getting these working? Is there an issue with the EasyPIC3 and external EEPROMs?

Thanks for any help.

Mark

Posted: 04 Feb 2006 23:08
by xor
Take a look at the posts here. I believe that Rackley got it working in the end.
http://www.mikroe.com/forum/viewtopic.p ... ht=24lc256

Posted: 04 Feb 2006 23:47
by sparkz
Thanks, not too sure if I looked at that one.

Looks like they may be some issue although I'm not too sure I fully understand the implications. Losing timing or something getting corrupted?

Anyhow putting in extra initialisations seems like the thing to do. Worth a go...

Posted: 05 Feb 2006 00:00
by xor
You might contact him and see if he has a section of working I2C code to share.

Posted: 05 Feb 2006 04:29
by rackley
Please bear in mind this is MUCH more complicated than it should be due to bugs in hi() and lo() when dealing with byref variables and also bugs with compound statements. BUT, they work around the bugs and all the subs work.


Code: Select all

const EECtrlRead     = %10100001       ' Control bytes to address the chip
const EECtrlWrite     = %10100000

'------------------------------------------------------
' Reads a 20-char string from eeprom at Addr location.
' Modifies an array sent to it by reference as a return
'------------------------------------------------------

sub procedure I2C_ReadString(Dim Addr as Word, Dim ByRef Arr as String[20])
    Dim i as byte

    I2C_init(100000)
    Delay_ms(10)
    I2C_Start
    I2C_Wr(EECtrlWrite) ' Issue write just to set the working address in EEPROM
    I2C_Wr(hi(Addr))
    I2C_Wr(lo(Addr))
    I2C_Repeated_Start  ' Terminate write and issue start of new operation
    I2C_Wr(EECtrlRead)  ' Issue read command
    for i=0 to 18
      Arr[i] = I2C_rd(1)  ' Issue ACK so we get another byte
    next i
    Arr[19] = I2C_rd(0)  ' Do not issue ACK since we're done reading and will send stop
    
    I2C_Stop            ' Send stop
end sub

'------------------------------------------------------
' Writes a 20-char string from eeprom at Addr location.
' Calling function must be sure not to write over a page boundry
'------------------------------------------------------

sub procedure I2C_WriteString(Dim Addr as Word, Dim ByRef Arr as String[20])
    Dim i as byte
    I2C_init(100000)
    Delay_ms(10)
    I2C_Start
    I2C_Wr(EECtrlWrite) ' Issue write just to set the working address in EEPROM
    I2C_Wr(hi(Addr))
    I2C_Wr(lo(Addr))
    for i=0 to 19
      I2C_Wr(Arr[i])
    next i
    I2C_Stop            ' Send stop
    delay_ms(40)
end sub

'------------------------------------------------------
' Reads a byte from eeprom at Addr location.
' Returns a byte.
' Increments Addr by 64 automatically to advance to the next page
'------------------------------------------------------

sub function I2C_ReadByte(Dim ByRef Addr as word) as Byte
    Dim tmpWord as Word
    Dim tmpByte as Byte
    Dim tmpByteStr as String[3]
    I2C_init(100000)
    Delay_ms(10)
    I2C_Start
    I2C_Wr(EECtrlWrite) ' Issue write just to set the working address in EEPROM
    
    tmpWord = Addr      ' Do some shuffling to get hi and lo without using functions
    tmpWord = tmpWord >> 8
    tmpByte = byte(tmpWord) ' Move high to low and clip off high to get our high
    I2C_Wr(tmpByte)
    
    tmpWord = Addr
    tmpByte = byte(tmpWord)      ' Clip off high to get our low
    I2C_Wr(tmpByte)

    I2C_Repeated_Start  ' Terminate write and issue start of new operation
    I2C_Wr(EECtrlRead)  ' Issue read command
    result = I2C_rd(0)  ' Do not issue ACK since we're done reading and will send stop
    I2C_Stop            ' Send stop
    Addr = Addr + 64
end sub

'------------------------------------------------------
' Reads a word from eeprom at Addr location.
' Returns a word.
' Increments Addr by 64 automatically.
'------------------------------------------------------

sub function I2C_ReadWord(Dim ByRef Addr as word) as Word
    Dim tmpWord as Word
    Dim tmpByte as Byte
    
    I2C_init(100000)
    Delay_ms(10)
    I2C_Start
    I2C_Wr(EECtrlWrite) ' Issue write just to set the working address in EEPROM
    
    ' Send address in byte chunks
    tmpWord = Addr      ' Do some shuffling to get hi and lo without using functions
    tmpWord = tmpWord >> 8
    tmpByte = tmpWord ' Move high to low and clip off high to get our high
    I2C_Wr(tmpByte)
    
    tmpWord = Addr
    tmpByte = tmpWord      ' Clip off high to get our low
    I2C_Wr(tmpByte)

    I2C_Repeated_Start  ' Terminate write and issue start of new operation
    I2C_Wr(EECtrlRead)  ' Issue read command

    tmpWord = I2C_rd(1)
    tmpWord = tmpWord << 8
    tmpWord = tmpWord + I2C_rd(0)
    result = tmpWord
    'result = word(I2C_rd(1) << 8) ' Issue ACK so we get another byte, shift first byte to upper byte
    'result = result + I2C_rd(0) ' Do not issue ACK since we're done reading and will send stop and
                             ' add lower byte with AND operation
    I2C_Stop            ' Send stop
    Addr = Addr + 64
end sub

'------------------------------------------------------
' Writes a byte to eeprom at Addr location.
' Returns nothing.
' Increments Addr by 64 automatically.
'------------------------------------------------------

sub procedure I2C_WriteByte(Dim ByRef Addr as word, Dim Data as Byte)
    Dim tmpWord as Word
    Dim tmpByte as Byte
    
    I2C_init(100000)
    Delay_ms(10)
    I2C_Start
    I2C_Wr(EECtrlWrite) ' Issue write just to set the working address in EEPROM
    
    ' Send address in byte chunks
    tmpWord = Addr      ' Do some shuffling to get hi and lo without using functions
    tmpWord = tmpWord >> 8
    tmpByte = byte(tmpWord) ' Move high to low and clip off high to get our high
    I2C_Wr(tmpByte)
    
    tmpWord = Addr
    tmpByte = byte(tmpWord)      ' Clip off high to get our low
    I2C_Wr(tmpByte)
    
    I2C_Wr(Data)
    I2C_Stop            ' Send stop
    delay_ms(10)
    Addr = Addr + 64
end sub

'------------------------------------------------------
' Writes a word to eeprom at Addr location.
' Returns nothing.
' Increments Addr by 64 automatically.
'------------------------------------------------------

sub procedure I2C_WriteWord(Dim ByRef Addr as word, Dim Data as Word)
    Dim tmpWord as Word
    Dim tmpByte as Byte
    
    I2C_init(100000)
    Delay_ms(10)
    I2C_Start
    I2C_Wr(EECtrlWrite) ' Issue write just to set the working address in EEPROM

    ' Send address in byte chunks
    tmpWord = Addr      ' Do some shuffling to get hi and lo without using functions
    tmpWord = tmpWord >> 8
    tmpByte = tmpWord ' Move high to low and clip off high to get our high
    I2C_Wr(tmpByte)
    
    tmpWord = Addr
    tmpByte = tmpWord      ' Clip off high to get our low
    I2C_Wr(tmpByte)

    ' Send data in byte chunks
    tmpWord = Data      ' Do some shuffling to get hi and lo without using functions
    tmpWord = tmpWord >> 8
    tmpByte = tmpWord ' Move high to low and clip off high to get our high
    I2C_Wr(tmpByte)
    
    tmpWord = Data
    tmpByte = tmpWord      ' Clip off high to get our low
    I2C_Wr(tmpByte)

    I2C_Stop            ' Send stop
    delay_ms(40)
    Addr = Addr + 64
end sub

Posted: 05 Feb 2006 18:34
by sparkz
Much appreciated rackley! :) I'll give that a bash.

I hope mE sort those bugs out soon?

Posted: 06 Feb 2006 05:04
by rackley
They've been brought to mE's attention so I certainly hope they're all fixed in this next release. It will certainly clean up the functions :-)

Next step is to write a set that will work on internal eeprom for the 18F's. :-)

Posted: 06 Feb 2006 16:15
by sparkz
Well I've sort of made some progress with this although I've discovered something which confuses me even more! Wouldn't take much actually :)

I can get it to half work if I cycle the power - it does a write but fails on a read. If I just do a reset (or after programming) it hangs on the first write (according the leds)?

What's even more confusing though is if I put a delay, before any code at the start, it doesn't work at all!? Also, putting extra delay elsewhere (not between a start and stop) gives different results.

Is there an issue with the EasyPIC3? Or is this a devlish timing problem?

I saw another example for I2C and EEPROMs which I might have a look at. Unfortunately it's written in assembler so it isn't going to be easy to quickly throw in a few routines. It would be interesting to find out at a low level where the problem is though.

Posted: 06 Feb 2006 19:11
by rackley
sparkz wrote:Well I've sort of made some progress with this although I've discovered something which confuses me even more! Wouldn't take much actually :)

I can get it to half work if I cycle the power - it does a write but fails on a read. If I just do a reset (or after programming) it hangs on the first write (according the leds)?

What's even more confusing though is if I put a delay, before any code at the start, it doesn't work at all!? Also, putting extra delay elsewhere (not between a start and stop) gives different results.

Is there an issue with the EasyPIC3? Or is this a devlish timing problem?

I saw another example for I2C and EEPROMs which I might have a look at. Unfortunately it's written in assembler so it isn't going to be easy to quickly throw in a few routines. It would be interesting to find out at a low level where the problem is though.
I can't really speculate, but I had problems with I2C as well. Specifically, I have to reinitialize the I2C bus for every function, even though I follow the datasheet specifications for I2C communications exactly. There is something going on with the I2C communications that isn't right that made me need to reinit for each function, and it seems to be something in the closing or starting of the communication (for me at least.)

Posted: 06 Feb 2006 23:04
by sparkz
Hmm, I've been playing around with another compiler (sorry not mE!). I managed to get it working fine there. Standard out of the book stuff - no special timings or adjustments needed. Which is a relief. Glad to know I hadn't messed up and the EasyPIC and other hardware is ok.

Wonder why the mB routines are so temporamental? Is it just down to certain suspect code generation or is there an issue with the core routines?

Posted: 06 Feb 2006 23:19
by dAb
Following works for me on the IC2:

ConFigHi = I2C_Rd(Acknowledge)
IC2PauseOnBusy
ConFigLo = I2C_Rd(DontAcknowledge)

Where IC2PauseOnBusy is following routine

Sub procedure IC2PauseOnBusy
' ---------------------------------------------------------
' Pause until I2C bus is avaliable
' used on writes to bus only
' ---------------------------------------------------------
while I2C_Is_Idle = FALSE
nop
wend
end sub


dab

Posted: 07 Feb 2006 01:14
by rackley
sparkz wrote:Hmm, I've been playing around with another compiler (sorry not mE!). I managed to get it working fine there. Standard out of the book stuff - no special timings or adjustments needed. Which is a relief. Glad to know I hadn't messed up and the EasyPIC and other hardware is ok.

Wonder why the mB routines are so temporamental? Is it just down to certain suspect code generation or is there an issue with the core routines?
I don't know where the problem lies (which makes me very hesitant to use other I2C technologies with mikroBasic), but just like your experience, I have never had any problems whatsoever in other compilers.

Posted: 07 Feb 2006 12:36
by okutkan
rackley wrote: I can't really speculate, but I had problems with I2C as well. Specifically, I have to reinitialize the I2C bus for every function, even though I follow the datasheet specifications for I2C communications exactly. There is something going on with the I2C communications that isn't right that made me need to reinit for each function, and it seems to be something in the closing or starting of the communication (for me at least.)
Yes there should be bug.
I tried this 2 weeks ago and i2c library did not function as it should do.

You have to init i2c very time.

and you should add delay between all commands.
I think mE should consider revising i2c library..

Posted: 10 Feb 2006 11:05
by dAb
Yes there should be bug.
I tried this 2 weeks ago and i2c library did not function as it should do.

You have to init i2c very time.

and you should add delay between all commands.
I think mE should consider revising i2c library..
Make sure you check to see that the i2c bus is free before using, I've used it on different chips and found it to work on all Ok

dab