PDA

View Full Version : External EEPROM can't read/write



coyotegd
- 8th May 2008, 05:18
I am using a 16F877 with a 24LC256 in an effort to display a logo on a graphic LCD. The following code should write the logo to the 24LC256 and read 10 of the written addresses from the 24LC256. However, the read retrieves FFH for each address.

The 24LC256 has pins 1, 2, 3, 4, and 7 at gnd. Pin 8 is 5V. Pin 5 to PORTC.4 with a 4.7k pull-up to 5V. Pin 6 to PORTC.3 with a 4.7k pull-up to 5V. I've tried multiple 24LC256's and other resistor values to no avail.

Any suggestions? Thank you.



@ DEVICE HS_OSC, WDT_OFF, LVP_OFF, BOD_OFF, PWRT_ON, PROTECT_OFF

DEFINE LOADER_USED 1
DEFINE OSC 20

ADCON1 = 7

sda var PORTC.4 'I2C SDA for ext eeprom
scl var PORTC.3 'I2C SCL for ext eeprom
ctl con 160 'EEPROM control code
addr var WORD 'eeprom word address
i var byte 'Index counter

edata var BYTE 'Data byte to be written and read
out_pin var PORTC.6 'TX pin of 16F877
ser_baud con 32 '19200

addr = 0
edata = 0
pause 100
serout2 out_pin,ser_baud,["Writing to EEPROM . . .",10,13]
for i = 0 to 249
lookup i,[_
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_
$00,$00,$00,$00,$00,$3F,$C0,$00,$00,$00,_
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_
$00,$00,$00,$00,$0F,$FA,$60,$00,$00,$00,_
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_
$00,$00,$00,$00,$7C,$04,$38,$00,$00,$00,_
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_
$00,$00,$00,$00,$D2,$60,$C8,$00,$00,$00,_
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_
$00,$00,$00,$01,$D0,$22,$1C,$00,$00,$00,_
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_
$00,$00,$00,$03,$A2,$80,$0C,$00,$00,$00],edata
I2CWRITE sda,scl,ctl,addr.highbyte,addr.lowbyte,[edata]
pause 10
addr = addr + 1
next

. . .

for i = 0 to 249
lookup i,[_
$00,$00,$00,$01,$FE,$1F,$9F,$E0,$7C,$07,_
$FE,$3C,$1F,$03,$80,$3F,$C0,$3C,$E0,$00,_
$7F,$DF,$FC,$14,$97,$1D,$FD,$77,$00,$1C,_
$00,$00,$00,$03,$0F,$03,$E1,$F0,$FC,$0E,_
$1E,$38,$0E,$03,$80,$61,$E0,$FD,$E0,$00,_
$77,$CD,$FC,$80,$95,$8D,$EF,$7B,$80,$1C,_
$00,$00,$00,$00,$07,$01,$C0,$F0,$1C,$1C,_
$04,$38,$0E,$03,$80,$00,$E0,$1E,$00,$00,_
$7F,$DF,$6E,$2E,$BC,$CE,$FF,$BE,$80,$1C,_
$00,$00,$00,$00,$07,$01,$C0,$70,$1C,$18,_
$00,$38,$0E,$03,$80,$00,$E0,$1C,$00,$00,_
$7D,$4F,$FF,$81,$37,$3B,$FB,$F8,$80,$1C,_
$00,$00,$00,$00,$07,$01,$C0,$70,$1C,$38,_
$00,$38,$0E,$03,$80,$00,$E0,$1C,$00,$00,_
$5F,$E5,$BB,$CA,$2F,$FE,$FF,$F4,$80,$1E,_
$00,$00,$00,$00,$3F,$01,$C0,$70,$1C,$38,_
$00,$38,$0E,$03,$80,$07,$E0,$1C,$00,$00,_
$6F,$AF,$FF,$C1,$7E,$FE,$BF,$C7,$00,$0E,_
$00,$00,$00,$01,$E7,$01,$C0,$70,$1C,$38,_
$00,$38,$0E,$03,$80,$3C,$E0,$1C,$00,$00,_
$3D,$E3,$F7,$E0,$6B,$57,$F7,$C3,$00,$0F,_
$00,$00,$00,$43,$07,$01,$C0,$70,$1C,$38,_
$00,$38,$0E,$03,$80,$60,$E0,$1C,$00,$00,_
$2F,$EA,$DD,$FE,$D9,$BF,$BD,$F3,$00,$07,_ '1231 to 1240
$80,$00,$01,$CE,$07,$01,$C0,$70,$1C,$3C],edata
I2CWRITE sda,scl,ctl,addr.highbyte,addr.lowbyte,[edata]
pause 10
addr = addr + 1
if addr > 1230 and addr < 1241 then
serout2 out_pin,ser_baud,[dec addr,44,32,hex2 edata,72,10,13]
endif
next

. . .

for i = 0 to 169
lookup i,[_
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_
$00,$00,$03,$C0,$00,$00,$00,$00,$00,$00,_
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,_
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00],edata
I2CWRITE sda,scl,ctl,addr.highbyte,addr.lowbyte,[edata]
pause 10
addr = addr + 1
next
serout2 out_pin,ser_baud,["Reading EEPROM . . .",10,13]
for addr = 1231 to 1240
i2cread sda,scl,ctl,addr.highbyte,addr.lowbyte,[edata]
serout2 out_pin,ser_baud,[dec addr,44,32,hex2 edata,72,10,13]
next
serout2 out_pin,ser_baud,["Finished",10,13]
end

skimask
- 8th May 2008, 05:50
First thoughts... Get rid of the fat...
Break it down...Make it as simple as possible.
Read and write a single value to a single location, then build your way up to the final result.
Then try this:


eepromaddress var word
eepromdata var byte
i2cd var portc.0
i2cc var portc.1
eepromctrl var byte
eepromctrl = $a0
i2cread i2cd , i2cc , eepromctrl , eepromaddress , [ eepromdata ]
i2cwrite i2cd , i2cc , $a0 , eepromaddress , [ eepromdata ]

Notice anything different?


(besides the fact that there isn't a single colon up there :D )
(I could've done this:)


a var word:d var byte:c var portc.0:k var portc.1:n var byte:n=160:i2cread c,k,n,a,[d]:i2cwrite c,k,n,a,[d]

Jerson
- 8th May 2008, 06:07
I am using a 16F877 with a 24LC256 in an effort to display a logo on a graphic LCD. The following code should write the logo to the 24LC256 and read 10 of the written addresses from the 24LC256. However, the read retrieves FFH for each address.


addr = 0
write 0+(0..249)
write 249+(0..249)
write 498+(0..169)

read 1231 ????

You seem to write somewhere and read elsewhere. No wonder it reads FF

skimask
- 8th May 2008, 06:18
You seem to write somewhere and read elsewhere. No wonder it reads FF
Which is why I said to 'break it down'.
You know why it doesn't work, I know why it doesn't work...
Hopefully, now the O/P knows why it doesn't work...

coyotegd
- 8th May 2008, 08:13
I don't mean to be rude but the ". . ." means that I omitted code from the post or did you want three pages of the same thing over and over?

I also have no idea what colons have to do with anything.

skimask
- 8th May 2008, 14:52
I don't mean to be rude but the ". . ." means that I omitted code from the post or did you want three pages of the same thing over and over?
But have you tried the above suggestions at all?


I also have no idea what colons have to do with anything.
That's sort of a semi-inside-joke. Don't worry about it. (I have a tendency to write code with a load of colons in it to make more of it fit on each screen)

Bruce
- 8th May 2008, 17:34
Instead of using addr.highbyte,addr.lowbyte in your I2CREAD / I2CWRITE lines, try using
just addr. PBP already knows addr is a word and will handle both high & low bytes of the
address for you.

coyotegd
- 8th May 2008, 17:38
I wrote a very simple program but with the same output result:

5, 57
5, 255



DEFINE LOADER_USED 1
DEFINE OSC 20

edata var BYTE

pause 100
i2cwrite portc.4,portc.3,160,5,[57]
pause 10
serout2 portc.6,32,[dec 5,44,32,dec 57,10,13]
i2cread portc.4,portc.3,160,5,[edata]
serout2 portc.6,32,[dec 5,44,32,dec edata,10,13]
end


I tried using portc.0 as SDA and portc.1 at SCL with the same result. I used a different 16F877. It just doesn't make any sense to me anymore. I've checked the datasheets and my circuit many, many times.

Jerson
- 8th May 2008, 18:05
Have you tried scoping the SCL and SDA lines to see if it is really communicating? I2C is a no-brainer - if you get it working the first time.

The address should be declared in a WORD sized variable for the 24LC256. You then use this variable to hold the addresses for access.



Address var Word ' this will hold the 16 bit word address
EData var Byte ' Eprom data byte for read/write

Address = 5 ' address to access
Edata = $55 ' data to write
I2Cwrite SCL,SDA,$A0, Address, [EData] ' write it
Edata = 0 ' destroy the value before read
I2Cread SCL,SDA,$A0, Address , [EData] ' read it back
if Edata = $55 then Success ' if it compares, You Succeeded

coyotegd
- 11th May 2008, 21:47
It's the fact that this should be a "no brainer" that is so baffling. I've breadboarded much more complicated circuits, yet this simple EEPROM circuit won't work. I thought perhaps someone else had encountered this type of problem before and knew of a solution or could identify a source for troubleshooting.

A digital probe pulses away on both SCL and SDA during read/write ops.

BTW, I scoped portc.4 and c.3 outputs and SDA and SCL appear to be working. See Scope.jpg with data on top and clock on bottom. Both high prior to write/read operation and data high, clock low after write/read op. However, after a couple minutes, the clock goes high. I have no idea why.

The write-data signal doesn't change thoughout the write process and it's the same for the read-data signal, but the read signal is not the same as the write signal. See Scope2.jpg.

Darrel Taylor
- 12th May 2008, 01:05
Those waveforms look pretty bad.

For sure you need a lower pull-up resistance. 2KΩ is recommended for 400khz operation.
<br>

Jerson
- 12th May 2008, 04:34
Must have something to do with the multiplexed peripherals on RC3/4. I couldn't identify what could be the cause, but you could try to load the TRISC register yourself and define I2C_INTERNAL in case you want to use the internal I2C engine. There is something about the SSPSTAT reg too. Maybe you should look at those. I cannot comment since I havent used the 877 yet.

coyotegd
- 12th May 2008, 20:17
Darrel, I've tried 1k, 2k, 4.7k and 10k. I get a more well-defined square-wave with a 1 or 2k, but I still have the same result. I don't think the 24LC256 is being written to or read.

Jerson, I've looked at the 16F877 datasheet and found the first six bits of the SSPCON register and the first seven bits of the SSPCON2 register. Also, the requirement to set C.3 and C.4 as inputs with TRISC.

A lot of pages of the datasheet are devoted to I2C. Although PIC Basic Pro makes I2C a "no brainer", the data sheet suggests using assembler isn't so easy. I only have a small amount of assembler experience with an 8051.

I'll try configuring registers with PBP, but once I use the I2CWRITE and READ commands, won't PBP do it's own configuration, changing prior configurations?

Darrel Taylor
- 12th May 2008, 20:33
Don't bother playing with the SSP registers.
PBP's I2C commands are "bit-banged", and they do not use the Hardware I2C (SSP module).

I2C_INTERNAL is only for a small group of Very OLD pic's that have Internal I2C memory. It doesn't apply to PBP's I2CWRITE/READ commands.

coyotegd,

You still haven't responded to the previous suggestions regarding the Word sized Address.
Can't go any further without that result.
<br>

coyotegd
- 13th May 2008, 03:41
Darrel, I started this mess with a word sized address without highbyte, lowbyte. I found in another thread that the high-low byte addressing worked for someone, and when it didn't work for me, I made my first post in this tread with my code at the time.

However, I changed the 16F877 a third time and it's working! Is it possible that some PICs just don't work with I2C? Prior to finding a working 16F877, I tried two other 16F877's and a 16F876A. All failed to work properly.

Is it possible I had the circuit wrong? I can't go back and try a PIC that failed because they are all in their respective parts' bins with others of the same type. The most complicated part of my circuit is the MAX233, and it worked properly the first time. The 24LC256 is simple: Pins 1 to 4, and 7 to gnd, pin 8 to 5V, pin 5 pulled-up and to c.4, and pin 6 pulled-up and to c.3.

Anyway, thank you all. You kept me motivated to keep trying. All I can say to anyone reading this tread with a similar problem is just keep trying different components, and periodically, start your breadboarding all over again. As stated above I tried four different PICs, and I re-wired my circuit at least four times. This is the code that works:



@ DEVICE HS_OSC, WDT_OFF, LVP_OFF, BOD_OFF, PWRT_OFF, PROTECT_OFF

DEFINE LOADER_USED 1
DEFINE OSC 20
addr var word
edata var BYTE
addr = 0
edata = 50
pause 100
for addr = 5 to 10
I2CWRITE portc.4,portc.3,$A0,addr,[edata],Nowriteack
pause 10
serout2 portc.6,32,[dec addr,44,32,dec edata,10,13]
edata = edata + 10
next
for addr = 5 to 10
i2cread portc.4,portc.3,$A0,addr,[edata],NoREADAck
serout2 portc.6,32,[dec addr,44,32,dec edata,10,13]
next
end
NoWriteAck:
serout2 portc.6,32,["No Write Acknowledgement",10,13]
return
NoReadAck:
serout2 portc.6,32,["No Read Acknowledgement",10,13]
return


I've attached a picture, which was the objective of this exercise. It's rough, but at least I can move on to improvements and new challenges.

Darrel Taylor
- 13th May 2008, 04:15
... I tried two other 16F877's and a 16F876A. All failed to work properly. ...
I can't go back and try a PIC that failed because they are all in their respective parts' bins with others of the same type.

Is it possible that some PICs just don't work with I2C?
I doubt that very strongly.

But, I would imagine that putting parts that have had problems back in the bin with the new chips, would enhance the probability considerably. :eek:

Anyhow, glad it's working.

Cheers,

Added: Woohoo! Nice picture.

Michael Wakileh
- 16th May 2008, 22:13
In the past I've had a lot of sporadic problems with i2c and breadboards as well...I suspect your problem was solved somehow when rewiring the breadboard... My problems always went away when soldering my prototypes... Hope this helps...