24C02 Serial Eeprom troubles

Go To Last Post
17 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey guys I have been trying to interface my atmega aTony system with an external serial atmel eeprom! its specs are:
2k - 256b x 8
Two Wire interface
datasheet

----

Im basicly trying to just write some data (hardcoded) into the eeprom then read it back threw RS232 USART, while searching for some helper code I came across this code:

void twiStart (void)
{
	TWCR = _BV(TWINT) | _BV(TWSTA) | _BV (TWEN);
}

void twiStop (void)
{
	TWCR = _BV(TWINT) | _BV(TWSTO) | _BV (TWEN);
}

void twiWait (void)
{
	while( !(TWCR & _BV(TWINT)));
}

void twiSendDataByte (uint8_t data)
{
	TWDR = data ;
	TWCR = _BV(TWINT) | _BV(TWEN);
}

uint8_t twiEEPROMReadByte (word adress)
{
	twiStart();
	twiWait();
	
	twiSendDataByte (AT24C64ADRESS);
	twiWait();
	
	twiSendDataByte (adress >> 8); // set eeprom adres high
	twiWait();
	
	twiSendDataByte (adress & 0xff); // set eeprom adres low
	twiWait();
	
	twiStart();
	twiWait();
	
	twiSendDataByte (AT24C64ADRESS+1); // LSB bit is responsible for read/write operation
	twiWait();
	
	TWCR = _BV(TWINT) | _BV(TWEN);
	twiWait();
	
	twiStop();
	
	return TWDR;
}


void twiEEPROMWriteByte (word adress, uint8_t data)
{

	twiStart();
	twiWait();
	
	twiSendDataByte (AT24C64ADRESS);
	twiWait();
	
	twiSendDataByte (adress >> 8); // set eeprom adres high
	twiWait();
	
	twiSendDataByte (adress & 0xff); // set eeprom adres low
	twiWait();
	
	twiSendDataByte (data);
	twiWait();
	
	twiStop();
	
	// wait for write operation finish. it can took up to 5ms
	// wait for stop condition
	while(!(TWCR & _BV(TWSTO)));
	while(!(PINC & 0x20));
	
	while(1)
	{
		twiStart();
		twiWait();
		twiSendDataByte (AT24C64ADRESS);
		twiWait();
		if (TWSR == 0x18) break;
	}
	
	twiStop();

}

void twiInit (void)
{

	// 400khz@16MHZ CPU CLOCK
	// TWBR MSUT BE >= 10
	TWBR = 12;
	TWSR = 0;
	/*
	TWSR=0x00;
	TWBR=0x00;
	TWAR=0x00;
	TWCR=0x04;
	*/
	
	PORTC |= 0x10 | 0x20;
	DDRC |= 0x10 | 0x20;
}
.........
//heres the code im trying to execute:
uint8_t valueToWrite = 133;
		uint8_t b;
		
		twiEEPROMWriteByte (0x0, valueToWrite);
		
		
		b =  twiEEPROMReadByte (0x0);
		printf_P(PSTR("\n\raTony>eeprom>value at address [0x%x] is '$i'\n\r"),valueToWrite,b);
.......

but when I try to use it, my terminal/avr just freezes! heres my terminal output:

Quote:
aTony> Please Enter a Command: ** User> cmd> \eeprom
aTony> Looking Up Command 'eeprom', Please Wait...
aTony> Writeing then Reading eeprom, please wait...
(now it feezes nothing else)

You can see the whole source file on my public pastebing @
http://www.ursrc.com/index.php?s...
or
http://post.ursrc.com/ph0rkeh

(not includeing my lcd and usart code, just the main file)
and
heres a simple shematic of the pins for the eeprom
http://post.ursrc.com/shematic.jpg
(like i said simple ;), where I got the source it said to ground all the pins exept SDA SCL and of course VCC)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

EDIT: Sorry forget this post, but not the first one! I really need help with that one ;)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I was reading about someone else asking about useing external serial eeprom, but it was from st... I belive it also used two wire... and that eeprom used data bits like lets say to read memory you send 0xEA and the address blah blah... I looked at its datasheet and it did have command bytes! inside the datasheet for this eeprom there is none!

I cant seem to figure it out! can anyone help me?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I just decided to try the twitest example that came with winAVR.. and I get the same result, when I try to read the eeprom the whole AVR freezes!! what could be causing this?

http://hubbard.engr.scu.edu/embe...

EDIT: I put a bunch of breaks inside my code to find where it was freezing and it is when sending the start command threw twi! Im guessing the AVR never gets it back from the eeprom

TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN); /* send start condition */
  while ((TWCR & _BV(TWINT)) == 0); <-- this is where it freezes in the loop! 

anyone know what its freezing there or had this problem before? mabye a dead eeprom chip? it was salvaged.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Whenever I've encountered this symptom it has been due to faulty wiring.

Are you using external pullups? The internal pullups may or may not be sufficient.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Im just straight up breadboard jumpers to my avr. I dident know I needed to use any sort of pullup for two wire.. doe! so what should I use then?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You were correct, I wasent using the pullups, So I just connected 100's to the avr, and 10k's to 5v.. is that what I should do? it works but I dont want to mess anything up!

it all works now, but a new question has comeup !! ok as I understand from the datasheet there is 8 sections of 256bytes on this eeprom. and the twitest example im useing read 256 bytes. so witch section is that from? or is it all one section? that I dont udnerstand. is there a way to switch sections im reading from or somthing?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ph0rkeh wrote:
I dident know I needed to use any sort of pullup for two wire.. doe! so what should I use then?

That'll be the very reason God invented datasheets! Don't know about your AVR but picking the Mega16 at random, almost at the top of the TWI section is a sub-section labelled "Electrical interconnection" with a diagram above and it has this to say on the subject:
Quote:
Electrical Interconnection
As depicted in Figure 76, both bus lines are connected to the positive supply voltage through pull-up resistors. The bus drivers of all TWI-compliant devices are open-drain or open-collector. This implements a wired-AND function which is essential to the operation of the interface. A low level on a TWI bus line is generated when one or more TWI devices output a zero. A high level is output when all TWI devices tri-state their outputs, allowing the pull-up resistors to pull the line high. Note that all AVR devices connected to the TWI bus must be powered in order to allow any bus operation.

Later on this appears:
Quote:
SCL and SDA Pins
Note that the internal pull-ups in the AVR pads can be enabled by setting the PORT bits corresponding to the SCL and SDA pins, as explained in the I/O Port section. The internal pull-ups can in
some systems eliminate the need for external ones.

It would be extremely unwise to try and use a function block in an AVR without reading (possibly several times!) and understanding the section on the block you are trying to use.

By the way, to answer your "which lot of 256?" question, the way it's written this program only access the very first 256 bytes in the device. When ee24xx_read_bytes is called one parameter is eeaddr which can take the value 0..2047 to access all 2K bytes in the device. Within the read routine it splits the top 3 bits of the address off from the bottom 8 to select the page using the E2/E1/E0 bits but as far as you, the user of the routine are concerned, you can ignore this complexity and just select any byte 0..2047. If, for example you tried to read at address 1928 then this (0x788 in hex) would be split into E2/E1/E0 bits to select page 7 and then access the byte at offset 0x88 (136) within that page. But you don't really care - you just know you have read the 1928th byte

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

the way it's written this program only access the very first 256 bytes in the device

The way the whole example is written or just the for 256 times command?

Quote:

for example you tried to read at address 1928 then this (0x788 in hex) would be split into E2/E1/E0 bits to select page 7 and then access the byte at offset 0x88 (136) within that page. But you don't really care - you just know you have read the 1928th byte

Cause I have tryed this

rv = eeprom_write_bytes(0x788, 4, "hello");
if (rv < 0)
		error();
	  printf_P(PSTR("\n\raTony> Wrote %d bytes."), rv);

and also using the EE_Write macro I get an error 20 from 2wire.

So are you saying the code in 'ee24xx_read_bytes' cannot go past 256? or am I still doing somthing wrong.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Both the read and write routines take the eeaddr as an 11 bit value then internally split it to 3 page bits and an 8 bit offset within the page. So that SHOULD have worked OK. The only thing you have to be wary of (according to their code) is a write that spans a page boundary but 4 bytes to 0x788 is all within page 7 of the device so it should have worked.

What kind of debug hardware do you have? Do you have a JTAG or a Dragon? If so can you not simply step this and see what's going on. Equally, for an external view what equipment do you have - for things like this a 'scope is invaluable so you can see what the commands you are doing in the software are actually causing to happen out on the wires.

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I figured out why I am getting that error, as I do not have a dragon or scope...

The code

sla = 0xa0 | (((eeaddr >> 8) & 0x07) << 1);

is splitting up the 'device' address, witch should have nothing todo with the eeaddr, SLA should always be '1010000' witch is 1010 for eeprom and A0..2 pins witch are all grounded so thats the last 000 its just for the eeproms to know witch one is being called if you have multiple.

so with that out of the way, I still cannot write beyond 256 because the eeprom for 'word address' is only 8 bits, when I try to send say 0x88 to write Im giveing '10001000' as the word address, ok that works fine, its 8 bits and load into it fine, if I want to send 0x588 to read, im now sending '10110001000' now the device is only reading the last 8 witch is again '10001000' so its reading and writeing over the first 256 bytes...

if I shift the bytes over 3 to '00010110001' then it seems to write to anouther location fine as well... but now if I try to write to 0x88 or '10001000' when I shift it 3 im now trying to write to '00010001' witch is not correct.

I think that is the prob, but Im unsure.. so how would I be able to tell my code to not shift the bytes if its below 256, but to shift if its above? that is my problem.

simply put:
uint16[0x88] = uint8[0x88]
uint16[0x588] = uint8[0x88]

how do I fix that.

edit: this isent making any sence to me, a 8 bit cannot go beyond 256 can it? because FF witch is highest = 256!! so where do I tell the eeprom what page? this is killing me :)

edit2: i get it now, the reason why he split up the sla is because he is useing a 16k eeprom where im using a 2k.. the 2k uses the sla for finding witch eeprom to call like I said above, where the 16k uses those bits for page

Quote:
datasheet: The 16K does not use any device address bits but instead the 3 bits are used for memory
page addressing.

so in the datasheet it says there is 256b x 8, so why cant I read past the 1s 256k section?

final edit: ok I think i get it now, when I read the whole eeprom 256, im reading 8 bits for each 1.. so witch is 0xXX is the 8 bit value... so I am acctully reading 8bits time 256sections = 2048k or 2k... So this is all I am supposed to read, I was confused because this whole time I was thinking the bits were all 1 byte but there are 8bit bytes of course! Thansk for all your help guys! at least now if I update to a higher eeprom I will know how to use it :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ph0rkeh wrote:
so with that out of the way, I still cannot write beyond 256 because the eeprom for 'word address' is only 8 bits, when I try to send say 0x88 to write Im giveing '10001000' as the word address, ok that works fine, its 8 bits and load into it fine, if I want to send 0x588 to read, im now sending '10110001000' now the device is only reading the last 8 witch is again '10001000' so its reading and writeing over the first 256 bytes...

if I shift the bytes over 3 to '00010110001' then it seems to write to anouther location fine as well... but now if I try to write to 0x88 or '10001000' when I shift it 3 im now trying to write to '00010001' witch is not correct.


But this is the exact reason the code was splitting the top 3 bits off the 11 bit address and using that to set the A2,A1,A0 bits separately to pick the right page of 256. That IS the right way to do it. The changes you have made are simply throwing away this logic and does not make sense. I'd try and debug what's wrong with the existing code, not destroy it!

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
ph0rkeh wrote:
so with that out of the way, I still cannot write beyond 256 because the eeprom for 'word address' is only 8 bits, when I try to send say 0x88 to write Im giveing '10001000' as the word address, ok that works fine, its 8 bits and load into it fine, if I want to send 0x588 to read, im now sending '10110001000' now the device is only reading the last 8 witch is again '10001000' so its reading and writeing over the first 256 bytes...

if I shift the bytes over 3 to '00010110001' then it seems to write to anouther location fine as well... but now if I try to write to 0x88 or '10001000' when I shift it 3 im now trying to write to '00010001' witch is not correct.


But this is the exact reason the code was splitting the top 3 bits off the 11 bit address and using that to set the A2,A1,A0 bits separately to pick the right page of 256. That IS the right way to do it. The changes you have made are simply throwing away this logic and does not make sense. I'd try and debug what's wrong with the existing code, not destroy it!

Cliff

Yes that code is correct, I know this now as well, but the code was designed for a 16k eeprom, where the first 8 bits are '1010' (always) 'XXX' (page) 'X' (r/w), so it is correct to split up eeaddr to select page, if useing a larger eeprom. Im testing on a 2k eeprom and it has no page select, those 'XXX' bits are instead used for device addressing (if you have more then one on 2wire), I have orderd a couple of differnt size serial eeproms! so I can use this code again for those.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Nope you are still wrong but I do see your problem. In http://post.ursrc.com/shematic.jpg you show the A2, A1 and A0 pins tied to Ground - no wonder you can't address anything but page 0 as those three page selection bits are always going to be zero. The idea is that you run those three pins to thee PORT pins on the AVR then the write_bytes() and read_bytes() rouintes need to split off the top 3 bits and then use these to energise the 3 PORT pins that are driving A2, A1 and A0 on the device.

All that's going to happen if you order a 16K device and continue to tie the pins to Gnd is that you will still be limited to accessing just one page but in this case each of the 8 pages is 2048 bytes rather than the 256 bytes in your current device.

Just out of interest, when you designed the circut WHY did you tie the address pins to Gnd and not do as the datasheet suggests?

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Just out of interest, when you designed the circut WHY did you tie the address pins to Gnd and not do as the datasheet suggests?

because it is what it said todo in the datasheet. all I know is I tested that part of the code alot.. making sure that those pins where for device addressing, not page addressing, and I can tell you right now, if I take any of those pins away from ground my current code will not work at all, as the device will not respond.

Quote:

datasheet:
The 1K, 2K, 4K, 8K and 16K EEPROM devices all require an 8-bit device address word
following a start condition to enable the chip for a read or write operation (refer to Figure
7).
The device address word consists of a mandatory one, zero sequence for the first four
most significant bits as shown. This is common to all the EEPROM devices.
The next 3 bits are the A2, A1 and A0 device address bits for the 1K/2K EEPROM.
These 3 bits must compare to their corresponding hard-wired input pins.

I know you are much more knowledgable then me when it comes to AVR's sence I am extremly new, but trust me I tryed with those also, and all they did was make the device not respond, unless I changed the first 3-7 bits to match those pins, like if A0 and A2 are low, then it would be '1010010[0or1]' I just have them all tried down because my code is hardcoded for '1010000[0or1]' I completly understand what you are say.

such as if you look at this shematic:

the AT2C04 has the address pins A0..3 tried to VCC and im sure if you looked at some code to run that, it would work like this:

datasheet says 4k (whats in the shematic) uses only A1 and A2 for device addressing, and now instead of '1010XXX(device address)[0or1]'
its now
'1010XX[device address]X[page selection][0or1]' then communicating with the device!

If you would like to try testing something for you I will be glad to try it out and report as much information back to you, and I truly appreicate you taking your time to help me, but I feel like you are starting to get angry with me, and if you are feeling that way I dont mean to make you, I just dont think you understand that I have tryed all that before and im 100% sure those are not for page addressing (not in the 2k eeprom), but like i said, ask me to try somthing and I will. :)

edit: heres anouther 2 schematics this time it has also a AT24C02 like me; http://www.smsc.com/main/tools/e... on the second page, near the bottom center, and http://pdfserv.maxim-ic.com/en/a... - as you can see the A0..2 pins areall grounded as mine are.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sorry, my confusion. I was misguided by the datasheet that rather confusingly uses A2,A1,A0 in two contexts - one as device addressing pins and one as page addressing bits in the command protocol. I now see that it says:

Quote:
The next 3 bits are the A2, A1 and A0 device address bits for the 1K/2K EEPROM. These 3 bits must compare to their corresponding hard-wired input pins.

So obviously, if you have A2/A1/A0 pins wired to GND then these three bits also need to be 000 as part of the device address. So your first byte is going to be 1010000x where x is the R/W bit. x=0 for a read.

But a revelation has just struck me on re-reading the datasheet. It describes the 24C02 as having 2048 BITS organised as 256 BYTES and you've already demonstrated that you can read/write 256 BYTES in it. So I'm not sure what more you were hoping to achieve? Did you misread it as having 2048 BYTES rather than BITS ?? When it describes the 24C02 as a 2K device it means it is a 2Kb device and NOT a 2KB device!

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

I was misguided by the datasheet that rather confusingly uses A2,A1,A0 in two contexts

that was killing me for a while too :)

Quote:

It describes the 24C02 as having 2048 BITS organised as 256 BYTES and you've already demonstrated that you can read/write 256 BYTES in it. So I'm not sure what more you were hoping to achieve? Did you misread it as having 2048 BYTES rather than BITS ??

Exactly!! for some reason I was thinking 1 byte x 2000 not 1 bit x 2000 :)

and I hate not useing stuff for all its worth, so I kept trying and trying to get more space that was clearly (now ;)) not there to start with!