PDA

View Full Version : I2CWRITE problem



Art
- 25th January 2010, 09:58
Hi Guys,
I seem to be able to READ ok with I2CREAD,
but I'm having difficulty with my program, and I've narrowed it down to I2CWRITE.

I'm using a 24LC512 EEPROM, and I've also tried 256.



W0 var byte
epin var word

W0 = 0
FOR cntr = 0 TO 2000 '
I2CWRITE porte.1,porte.2,%10100000,epin,[W0,W0,W0,W0,W0],error '
pause 10 '
epin = epin + 5 '
NEXT cntr '


It would seem this code should write a lot of zeros, but when I read back the chip
there are some missing.
I have erased the EEPROM with my programmer which sets all $FF values,
and then run this code, then I find when I read back the EEPROM with my
pic programmer (or with picbasic code) there are some zero bytes.

They appear to be in groups of 2 or 3 bytes at addresses like:
100h, 180h, 200h, 280h, 300h, 380h, and so on.

Any ideas on this? Anyone else seen the same problem?

I'm using a 16F877A and Port e 1&2 to do the I2C stuff.
Art.

Art
- 25th January 2010, 10:09
Oh, I should add that I can entirely write and verify both EEPROMs properly with my pic programmer.

Dave
- 25th January 2010, 12:01
Art, Do you have any interrupts going on in the program? I have seen in the past that if you are interrupted during a I2CWRITE to some eeproms you will write bad data to the locations...

Dave Purola,
N8NTA

mackrackit
- 25th January 2010, 12:12
Just a couple of things to check/try...

Check:
ADC turned off for E.1 and E.2

Try:
DEFINE I2C_SLOW

Art
- 25th January 2010, 12:38
ADC turned off for E.1 and E.2

Try:
DEFINE I2C_SLOW
Yep, I have all digital pins. The EEPROM works most of the time,
it just doesn't want to write some addresses.
DEFINE I2C_SLOW 1 made no difference.

No interrupts in this program either.

4.7K pullups, checked 5 Volt supply.

Gusse
- 25th January 2010, 16:12
Hi Art & All,

Thanks to Art, I noticed similar I2CWRITE problem with different PIC and EEPROM (I use 18F4520 and 24C64).
So far I haven't use external EEPROM for storing anything, just used I2CREAD and that has worked very well.

Below is my test code for WRITE/READ for EEPROM. Test will be passed if X=0 (LED blinking slowly), if X > 0 then it fails immediately (LED blinking fast).


<code><font color="#000000">OSCCON = $70 <font color="#000080"><i>'Int CLK 8MHz
</i></font>OSCTUNE.6 = 1 <font color="#000080"><i>'PLL 4x
</i></font>ADCON1= %00001111 <font color="#000080"><i>'$0F = disable A/D converter
</i></font>TRISD.0 = 0
TRISD.1 = 1
TRISD.3 = 0
TRISE.4 = 0

<b>DEFINE </b>OSC 32

X <b>VAR BYTE
</b>Y <b>VAR BYTE
</b>SCL <b>VAR </b>PortD.0
SDA <b>VAR </b>PortD.1
LED <b>VAR </b>PortD.3

I2CDeviceEEprom <b>VAR BYTE
</b>I2CAddressEEprom <b>VAR WORD
</b>I2CDeviceEEprom=$A0

X=0 <font color="#000080"><i>'OK if EEPROM content is 00h and X = 0, if X &gt; 0 then fails

</i></font><b>FOR </b>I2CAddressEEprom = 0 <b>TO </b>8191
<b>I2CWRITE </b>SDA, SCL, I2CDeviceEEprom, I2CAddressEEprom,[ X ], Error
<b>PAUSE </b>10
<b>I2CREAD </b>SDA, SCL, I2CDeviceEEprom, I2CAddressEEprom,[ Y ], Error
<b>IF </b>Y &lt;&gt; X <b>THEN GOTO </b>Error
<b>NEXT </b>I2CAddressEEprom

Blink:
<b>HIGH </b>LED
<b>PAUSE </b>1000
<b>LOW </b>LED
<b>PAUSE </b>1000
<b>GOTO </b>Blink

Error:
<b>HIGH </b>LED
<b>PAUSE </b>200
<b>LOW </b>LED
<b>PAUSE </b>200
<b>GOTO </b>error

<b>END</b>
</code>
No help from DEFINE I2C_SLOW or any other that I have tried so far (increasing PAUSE time between write and read, etc...).
Hardware is OK, because I have used it for other purpose and then PIC read only from EEPROM (same PIC and EEPROM). Pull-ups are 4.7k and very solid 5V (no dips). Data lines are quite short (~25mm). EEPROM is only device in I2C-bus. WP pin is grounded....
Sounds very similar problems as Art has.

BR,
-Gusse-

Archangel
- 25th January 2010, 18:18
Hi Gusse,
Your code does not loop, I am sitting here wondering if there is some latency in your hardware, causing your code to run ahead of the eeprom, so the code is finished before the eeprom has finished waking up . . . Maybe in Art's too . . BTW ART, I liked your talking clock, esp when it encounters an error :)

Gusse
- 25th January 2010, 18:56
My code is working well :)

I found a reason for problem and I must admit it is purely due to my own stupidity. I have two identical (home made) test boards and when I measured I2C voltage, I measured from wrong board. Board which had I2C test SW was not properly powered. Meaning that one of the PIC IO pin is supply for I2C and that pin was not set to "1". No power, no EEPROM. How stupid of me!

It might have something to do that this is my fourth day in flu and fever. Brains are not anymore working well...

BR,
-Gusse-

Archangel
- 25th January 2010, 19:12
My code is working well :)

I found a reason for problem and I must admit it is purely due to my own stupidity. I have two identical (home made) test boards and when I measured I2C voltage, I measured from wrong board. Board which had I2C test SW was not properly powered. Meaning that one of the PIC IO pin is supply for I2C and that pin was not set to "1". No power, no EEPROM. How stupid of me!

It might have something to do that this is my fourth day in flu and fever. Brains are not anymore working well...

BR,
-Gusse-Don't be so hard on yourself, people (especially sick ones) make mistakes.

Dave
- 25th January 2010, 23:53
Art, I have used external eeproms on most all of my projects and have never had any problems with bad data. I just make sure I dont have any interrupts during the write cycle and always use 2.2k resistors for the pullups. I am currently using 2 x 24LC1025's for about a months worth of data storage on a solar telemetery project and haven't had a bad bit all summer or winter. So far its been -5 degrees a couple of nights here.. I would suggest maybe using 2.2k resistors for the pullups and the I2C_SLOW command. I also never use more than 6 milliseconds of delay after the write... Good Luck...

Dave Purola,
N8NTA

MR2010
- 26th January 2010, 05:48
hi art im newbe but if im right i noticed an error in your code .sorry if its not.

W0 var byte
epin var word <<<<< i think this is address ?

W0 = 0
FOR cntr = 0 TO 2000 'should be( FOR epin= 0 TO 2000 )! or (cntr)should be var xxx
epin = epin + 5 '
I2CWRITE porte.1,porte.2,%10100000,epin,[W0,W0,W0,W0,W0],error
pause 10 '
'
NEXT cntr

hope this helps
see Gusse code moght it helps

MR2010
- 26th January 2010, 06:48
hi gusse guess SDA PORTD.1 is always input what will happens ? u did set SDA port input only read .u have to leave trisd alone and set portd = 0 , i can say trisd s gone to charge you lol



TRISD.0 = 0
TRISD.1 = 1 '<<<should be TRISD.1 = 0 or only PORTD = %0000
TRISD.3 = 0
TRISE.4 = 0

SCL VAR PortD.0
SDA VAR PortD.1
LED VAR PortD.3


END

im newbe hope this helps
hope u get better gusse
regards

Art
- 26th January 2010, 07:23
Hi Gusse,
Your code does not loop, I am sitting here wondering if there is some latency in your hardware, causing your code to run ahead of the eeprom, so the code is finished before the eeprom has finished waking up . . . Maybe in Art's too . . BTW ART, I liked your talking clock, esp when it encounters an error :)

Thanks for the comments :) , but I don't know what you mean by the code running ahead of the EEPROM.
The code is posted above. Writing a bunch of zeros is not exactly what I want to
achieve, but the code exhibits the problem I'm describing.

I suppose at some point I'll run the same code on a breadboard and try adjusting things like clock speed, pull up resistor values, and see if that helps.
PBP should compensate for clock speed though.

MR2010
- 26th January 2010, 07:34
HI art IM JUST TESTING IT ON AN OLD PIC F84A WITH 24C08 ITS WORKING WELL
THIS MY CODE MODIFIED GUSSE CODE

PORTB = 0
TRISB = 0
X VAR BYTE
Y VAR BYTE
SCL VAR PortB.0
SDA VAR PortB.1
LED VAR PortB.3

I2CDeviceEEprom VAR BYTE
I2CAddressEEprom VAR WORD
I2CDeviceEEprom=$A0

X=0 'OK if EEPROM content is 00h and X = 0, if X > 0 then fails
MAIN:
FOR I2CAddressEEprom = 0 TO 1024
I2CWRITE SDA, SCL, I2CDeviceEEprom, I2CAddressEEprom,[ X ], Error
PAUSE 10
I2CREAD SDA, SCL, I2CDeviceEEprom, I2CAddressEEprom,[ Y ], Error
IF Y <> X THEN GOTO Error
IF I2CAddressEEprom = 1024 AND X = Y THEN BLINK
NEXT I2CAddressEEprom
GOTO MAIN
Blink:
HIGH LED
PAUSE 1000
LOW LED
PAUSE 1000
GOTO Blink

Error:
HIGH LED
PAUSE 200
LOW LED
PAUSE 200
GOTO error

END

YOU HAVE TO MAKE SURE ABOUT EEPROM PULLUPS AND TRIS AND PORT SET THEM TO 0 OUTPUT
JUST LOOK TO THIS CODE TO GET SOME IDEAS OR POST UR WHOLE CODE SO EVERYONES CAN HELP .
REGARDS

Gusse
- 26th January 2010, 08:01
hi gusse guess SDA PORTD.1 is always input what will happens ? u did set SDA port input only read .u have to leave trisd alone and set portd = 0 , i can say trisd s gone to charge you lol

im newbe hope this helps
hope u get better gusse
regards
To my understanding I2CWRITE and I2CREAD -functions take care of port settings. So basically, whatever user is pre-defining in SW, I2C-routine will over-write it.
- I2C clock is always coming from master (PIC) and it is output.
- I2C data is bi-directional, so port will change between input and output.

Please, somebody wiser correct if I'm totally wrong.


I2CAddressEEprom = 0 TO 1024
Value should be 1023. 0 + 1023 = 1024.

BR,
-Gusse-

PS. Getting better, little by little ...

Archangel
- 26th January 2010, 08:39
Thanks for the comments :) , but I don't know what you mean by the code running ahead of the EEPROM.
The code is posted above. Writing a bunch of zeros is not exactly what I want to
achieve, but the code exhibits the problem I'm describing.

I suppose at some point I'll run the same code on a breadboard and try adjusting things like clock speed, pull up resistor values, and see if that helps.
PBP should compensate for clock speed though.
Hi Art,
I was thinking, in Gusse's case, the pic might blather out a bunch of commands before his eprom was awake, since he is using an OFF PIC eprom, and maybe the eprom just missed it due to the difference in boot rates. I was thinking a short pause during initialization might allow eprom to catch up . . . as I said, I was just thinking.

Art
- 26th January 2010, 09:26
hi art im newbe but if im right i noticed an error in your code .sorry if its not.

W0 var byte
epin var word <<<<< i think this is address ?

W0 = 0
FOR cntr = 0 TO 2000 'should be( FOR epin= 0 TO 2000 )! or (cntr)should be var xxx
epin = epin + 5 '
I2CWRITE porte.1,porte.2,%10100000,epin,[W0,W0,W0,W0,W0],error
pause 10 '
'
NEXT cntr

hope this helps
see Gusse code moght it helps

Yes epin is an address word but it is incremented by the line:
epin = epin + 5 in the code I provided.
This is correct because the I2CWRITE command has written five addresses sequentially.
The cntr var should be declared at the top, I forgot that.



Art, I have used external eeproms on most all of my projects and have never had any problems with bad data.

Hi Dave,
Solar electricity rules, and if you use it to run a fridge it slaps nature in the face :)
I'll try a paralel resistor value to equal 2.2K, and retry the DEFINE I2C_SLOW 1.
Normally I don't have problems with EEPROMS either.

One other thing.
I have introduced five new byte vars, and done a readback of the five
written bytes so the program can verify what was read from the EEPROM is
the same as what was written 10ms ago.
If the results don't match, it goes back to rewrite the original (correct) values.

When it gets to one of the addresses in question, it just hangs there
rewriting all the time, and never getting the data right.

MR2010
- 26th January 2010, 09:52
I JUST DESCOVERED THE BLOODY PROBLEM IS

I2CAddressEEprom VAR WORD


WHEN U PUT VAR BYTE IT WORKS GREAT BUT WHEN U PUT VAR WORD IT DOESNT IT WRITES ONLY 4TH BYTE .IM CONFUSED THE PROBLEM IS IN THE ADRESS OR THE DATA X,

HOPE U CAN FIND IT GUYS
GOOD LUCK ..!

Art
- 26th January 2010, 10:06
Whether you use a word or byte address depends on the EEPROM device.
It's in the manual for I2CREAD.

Gusse
- 26th January 2010, 10:15
Address size depends on EEPROM size (see table)
PicBasic Manual I2C -part (http://melabs.com/resources/pbpmanual/5_30-5_31.htm)
(2 bytes = 1 word)

Manual is Your friend ;)

BR,
-Gusse-

MR2010
- 26th January 2010, 10:16
whether you use a word or byte address depends on the eeprom device.
It's in the manual for i2cread.


yeah but when u use xxx var byte

for xxx = 0 to 255 it works
THE PROBLEM IS WHEN IT COUNT FROM 0 TO 1023 IN WORD VAR IT DOES SOMETHING WRONG IM OUT FOR JOB WILL TRY LATER TAKE CARE EVERYONES I KNOW U WILL FINDOUT


try it out

Paul
- 26th January 2010, 11:59
I have been reading this discussion with interest as I have had a similiar problem to yours.

What I tried to do was to write 32 words in a word array to a 24LC256. Initially my micro was the 18F452, but I have moved over to the 18F4680. Both devices gave the same problem. My line of code was:

DATA var WORD [31]
AA var WORD
I2WR var byte
I2ADDR var WORD

I2CWRITE PORTC.4, PORTC.3, I2WR, I2ADDR, [ STR DATA\32 ], I2C_ERR

I would then read the data back as single words:

I2CREAD PORTC.4, PORTC.3, I2RD, I2ADDR, [ AA ], I2C_ERR


When I read the data back, I would repeatedly read some correct data, a bunch of $FFFF, more correct data, then the data would appear to 'move' and would not be at the designated eprom address. All very strange, but whats more it was repeatable within locations of the device.

The device data sheet specifiies that it can read and write a page of 64 bytes, (32 words).

I over came the problem by writing each word in the word array individually, pausing 5 ms between each word write. Not the best solution but it work. This way wastes 160ms of processing time.

I am still trying to find a way to solve my problem as I really need to write the data block in one hit. I might try using the hardware I2C technique next as I2CWRITE ... [ STR DATA\32] didn't work for me.


Paul.

Dave
- 26th January 2010, 12:15
Paul, I notice that you have only declared 31 WORDS but you are loading the eeprom with 32 BYTES. You can only load individual BYTES into the eeprom even if they are in an array. You would be loading the LOWBYTE of each of the words in the DATA array into the eeprom. Even then, you have only declared 31 words and not 32.

Dave Purola,
N8NTA

Paul
- 26th January 2010, 13:00
Paul, I notice that you have only declared 31 WORDS but you are loading the eeprom with 32 BYTES. You can only load individual BYTES into the eeprom even if they are in an array. You would be loading the LOWBYTE of each of the words in the DATA array into the eeprom. Even then, you have only declared 31 words and not 32.

Dave Purola,
N8NTA


Hi Dave,

That is correct, the 1st element in the array, DATA[0], the second element DATA[1], the 32nd DATA[31].

The STR command counts the elements in an array, [ STR DATA\1] would send element DATA[0]. PBPro knows if I am using WORDS or BYTES and counts them appropriately.

In this section of the PBPro manual (http://www.melabs.com/resources/pbpmanual/5_30-5_31.htm#531), it clearly states that WORD variable arrays can be sent.

Paul.

Gusse
- 26th January 2010, 13:23
Hi Dave,

That is correct, the 1st element in the array, DATA[0], the second element DATA[1], the 32nd DATA[31].

The STR command counts the elements in an array, [ STR DATA\1] would send element DATA[0]. PBPro knows if I am using WORDS or BYTES and counts them appropriately.

In this section of the PBPro manual (http://www.melabs.com/resources/pbpmanual/5_30-5_31.htm#531), it clearly states that WORD variable arrays can be sent.

Paul.
Hi Paul,

Check from manual about Arrays (http://www.melabs.com/resources/pbpmanual/4_0.htm#45) ;)

It is two different things:
- Number of elements (array; 1,2,3,... )
- Location of element (string; 0,1,2,... )

BR,
-Gusse-

Art
- 26th January 2010, 13:52
Just to elaborate on the problem,
The middle part of this video shows the function that writes to EEPROM.
The messages are short because I can only type about 15 letters before
the first one stuffs up.
Each letter requires 6 bytes because they are stored as mono bitmaps,
and there is some lead in space written with zeros.

http://www.youtube.com/watch?v=tIhrOQJ8j5g

Art.

Gusse
- 26th January 2010, 14:42
Hi Art,

Couple of things came to my mind:

What is your oscillator speed?
- I didn't see any DEFINE OSC parameter.

Is EEPROM only load in I2C bus?
- Capacitive loading below 400pF per signal line (I2C spec)

How long wires you have between PIC and EEPROM?
- Timing CLK & data (this should not be a problem for I2C)

Write control pin in EEPROM?
- Grounded? Don't know if floating pin could do something like this?

De-coupling of PIC and EEPROM?
- How many caps and sizes

Crosstalk
- Any nearby signals that could cause coupling?

Grounding
- How is the grounding done? Ground bounce due to common impedance with some high current part of the system (Power supply, PIC, etc...).

Errors in write mode seems to be very systematic so it can't be just noise, which is causing the problem.

BR,
-Gusse-

Dave
- 26th January 2010, 18:33
Paul, Yes I understand that the base element number starts at 0 but, you are DECLARING only 31 elements in the array and not 32. Your declaration of the array size has to be the actual number of elements NOT the last element index. RTFM..... Also think about this statement from the manual...(While a single I2CWRITE statement may be used to write multiple bytes at once, doing so may violate the above write timing requirement for serial EEPROMs. Some serial EEPROMS let you write multiple bytes into a single page before necessitating the wait. Check the data sheet for the specific device you are using for these details. The multiple byte write feature may also be useful with I2C devices other than serial EEPROMs that don=t have to wait between writes.) Thats why I always use the page mode.....

Dave Purola,
N8NTA

Art
- 27th January 2010, 00:10
DATA var WORD [31]
It's the same in any programming language.
You declare the number of elements as a Human would say it
"there are 31 elements in the array" (not correct in this case).

Man I tried everything..
2.2K resistors, even shortened the clock and data wired to about six cm each.
it's really time for a new circuit to do the same test,
but I don't know what else I could change.

Dave
- 27th January 2010, 14:29
Art, Have you tried the page write mode for storing your data? True, you need a shadow array the size of the page you are trying to write but it is much faster to write a full page than individual bytes if you have any quanity.. Try these subroutines that I wrote a long time ago for an analog waveform generator using a single 24LC512 utilizing the page mode. This routine will store 7 diferent files, made up of 64 blocks of 128 bytes each. I hope this helps...

CNTRL_BYTE CON $A0 'CONTROL BYTE FOR I2C EEPROM MEMORY (A0/A1 USED FOR CHIP SELECT)
BLOCK VAR BYTE '64 BLOCK ADDRESS BYTE
ADDRESS VAR WORD 'ADDRESS WORD FOR SERIAL EEPROM
CNTROL_BYTE VAR BYTE 'CONTROL BYTE TO SEND TO SERIAL EEPROM
STOR_DATA VAR BYTE[128]'STORAGE DATA ARRAY
FILE VAR BYTE 'FILE STORAGE NUMBER 0 to 7

'************************************************* ********************
WRITE_EEPROM512: 'WRITE TO SERIAL EEPROM
'************************************************* ********************
ADDRESS = FILE << 13 'CALCULATE 12C ADDRESS TO STORE DATA TO
ADDRESS = ADDRESS + (BLOCK << 7) 'CALCULATE 12C ADDRESS TO STORE DATA TO
CNTROL_BYTE = CNTRL_BYTE 'COPY CONTROL BYTE
CNTROL_BYTE.1 = 0' 'SET LSB OF HARDWARE ADDRESS
CNTROL_BYTE.2 = 0' 'SET MSB-1 OF HARDWARE ADDRESS
CNTROL_BYTE.3 = 0' 'SET MSB OF HARDWARE ADDRESS
I2CWRITE SDA,SCL,CNTROL_BYTE,ADDRESS,[STR STOR_DATA\128] 'SAVE DATA TO 12C
PAUSE 6 'ALLOW TIME FOR I2C WRITE ~5Ms.
BLOCK = BLOCK + 1 'INCREMENT BLOCK NUMBER
RETURN

'************************************************* ********************
READ_EEPROM512: 'READ FROM SERIAL EEPROM
'************************************************* ********************
ADDRESS = FILE << 13 'CALCULATE 12C ADDRESS TO STORE DATA TO
ADDRESS = ADDRESS + (BLOCK << 7) 'CALCULATE 12C ADDRESS TO STORE DATA TO
CNTROL_BYTE = CNTRL_BYTE 'COPY CONTROL BYTE
CNTROL_BYTE.1 = 0' 'SET LSB OF HARDWARE ADDRESS
CNTROL_BYTE.2 = 0' 'SET MSB-1 OF HARDWARE ADDRESS
CNTROL_BYTE.3 = 0' 'SET MSB OF HARDWARE ADDRESS
I2CREAD SDA,SCL,CNTROL_BYTE,ADDRESS,[STR STOR_DATA\128] 'LOAD IN ENTIRE BLOCK
RETURN

Dave Purola,
N8NTA

Paul
- 28th January 2010, 03:18
Hi Paul,

Check from manual about Arrays (http://www.melabs.com/resources/pbpmanual/4_0.htm#45) ;)

It is two different things:
- Number of elements (array; 1,2,3,... )
- Location of element (string; 0,1,2,... )

BR,
-Gusse-


I had read this section of the manual sometime ago, and have obviously forgotten. Thank you Gusse, Art and Dave. It is good to be corrected and shown your error. Even with the change in array declaration, my page write I2C routine still will not work and exhibit the previously described problem. I will look at the physical aspects of the design (hardware), failing that attempt the hardware I2C routine. I have found some examples of code in the forums.

Paul

Art
- 28th January 2010, 03:50
Dave,
I can't really use page write because I only want to write 6 bytes at a time.
The code in the first post only writes zeros, but it isn't really what I want in my application... it's just a simplified code that exhibits the problem.

I'm duplicating the hardware today, so this will be interesting.

Dave
- 28th January 2010, 11:42
Art, Are you accumulating the data or just re-writing the values at the same locations? If you are accumulating the values (data logger style (appending)) then just wait till you have 64,128 or so on (eeprom page dependent) , readings stored in the shadow ram then dump them to the eeprom.

Dave Purola,
N8NTA

Art
- 28th January 2010, 16:34
That's a lot of bytes of RAM for the 16F877.
I think you get 368 bytes RAM, and PBP consumes some of that.

Dave
- 28th January 2010, 18:20
Art, Like I said, you can use a smaller eeprom like the 24LC256 or 24LC128 which has a 64 byte page write size or as small as a 24LC01B which has an 8 byte page write.

Dave Purola,
N8NTA

Art
- 29th January 2010, 03:01
Ah, I get you, sorry. A 24LC256 would be ok.
I will give it a shot when I'm finished my current hardware stuff and get back, it would be a nice improvement for my program.