I2C EEPROM Question

General discussion on mikroBasic.
Post Reply
Author
Message
sparkz
Posts: 12
Joined: 23 Dec 2005 18:09
Location: UK

I2C EEPROM Question

#1 Post by sparkz » 04 Feb 2006 22:42

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

xor
Posts: 5465
Joined: 18 May 2005 00:59
Location: NYC
Contact:

#2 Post by xor » 04 Feb 2006 23:08

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
[color=darkred][b]xor[/b][/color]
[url=http://circuit-ed.com]CircuitED -[/url]

sparkz
Posts: 12
Joined: 23 Dec 2005 18:09
Location: UK

#3 Post by sparkz » 04 Feb 2006 23:47

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...

xor
Posts: 5465
Joined: 18 May 2005 00:59
Location: NYC
Contact:

#4 Post by xor » 05 Feb 2006 00:00

You might contact him and see if he has a section of working I2C code to share.
[color=darkred][b]xor[/b][/color]
[url=http://circuit-ed.com]CircuitED -[/url]

rackley
Posts: 550
Joined: 08 Aug 2005 17:47
Location: Livonia, MI
Contact:

#5 Post by rackley » 05 Feb 2006 04:29

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

sparkz
Posts: 12
Joined: 23 Dec 2005 18:09
Location: UK

#6 Post by sparkz » 05 Feb 2006 18:34

Much appreciated rackley! :) I'll give that a bash.

I hope mE sort those bugs out soon?

rackley
Posts: 550
Joined: 08 Aug 2005 17:47
Location: Livonia, MI
Contact:

#7 Post by rackley » 06 Feb 2006 05:04

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. :-)

sparkz
Posts: 12
Joined: 23 Dec 2005 18:09
Location: UK

#8 Post by sparkz » 06 Feb 2006 16:15

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.

rackley
Posts: 550
Joined: 08 Aug 2005 17:47
Location: Livonia, MI
Contact:

#9 Post by rackley » 06 Feb 2006 19:11

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.)

sparkz
Posts: 12
Joined: 23 Dec 2005 18:09
Location: UK

#10 Post by sparkz » 06 Feb 2006 23:04

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?

dAb
Posts: 124
Joined: 26 Oct 2005 10:36
Location: UK

#11 Post by dAb » 06 Feb 2006 23:19

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

rackley
Posts: 550
Joined: 08 Aug 2005 17:47
Location: Livonia, MI
Contact:

#12 Post by rackley » 07 Feb 2006 01:14

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.

okutkan
Posts: 249
Joined: 07 Sep 2005 18:13
Location: Istanbul

#13 Post by okutkan » 07 Feb 2006 12:36

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..

dAb
Posts: 124
Joined: 26 Oct 2005 10:36
Location: UK

#14 Post by dAb » 10 Feb 2006 11:05

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

Post Reply

Return to “mikroBasic General”