XMEGA32A4U external eeprom currupted data after power up

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

Hello everyone.

I am trying to use M24C08 from ST (http://datasheet.octopart.com/M2...). I need to save some variables addressed from 0x01 to 0x30 and an array (0x30-0x17E). I am using ATXmega32A4U and Atmel twi drivers, so i have written functions for read and write:

uint8_t read_eeprom(uint8_t sl_addr, unsigned int data_addr){
	
	uint8_t data2ret = 0;
	uint8_t addr_2 = (data_addr & 0xFF00)>>8;
	uint8_t addr[2];
	
	if(addr_2 == 0){
		PORTC.OUTCLR = PIN6_bm;		// A0 - 0
		PORTC.OUTCLR = PIN5_bm;		// A1 - 0
	}
	else if(addr_2 == 1){
		PORTC.OUTSET = PIN6_bm;		// A0 - 1
		PORTC.OUTCLR = PIN5_bm;		// A1 - 0
	}
	else if(addr_2 == 2){
		PORTC.OUTCLR = PIN6_bm;		// A0 - 0
		PORTC.OUTSET = PIN5_bm;		// A1 - 1
	}
	else if(addr_2 == 3){
		PORTC.OUTSET = PIN6_bm;		// A0 - 1
		PORTC.OUTSET = PIN5_bm;		// A1 - 1
	}
	_delay_us(1000);
	
	addr[0] = (data_addr & 0xFF);
	TWI_MasterWriteRead(&twiMaster,sl_addr,addr,1,1);
	while (twiMaster.status != TWIM_STATUS_READY);
	_delay_ms(10);
	data2ret = twiMaster.readData[0];
	return (data2ret);
}
void write_eeprom(uint8_t sl_addr, unsigned int	data_addr, uint8_t data){
	uint8_t data2send [4]={0};
	uint8_t addr_2 = (data_addr & 0xFF00)>>8;
	data2send[0] = (data_addr & 0xFF);
	data2send[1] = data;
	
	if(addr_2 == 0){
		PORTC.OUTCLR = PIN6_bm;		// A0 - 0
		PORTC.OUTCLR = PIN5_bm;		// A1 - 0
	}
	else if(addr_2 == 1){
		PORTC.OUTSET = PIN6_bm;		// A0 - 1
		PORTC.OUTCLR = PIN5_bm;		// A1 - 0
	}
	else if(addr_2 == 2){
		PORTC.OUTCLR = PIN6_bm;		// A0 - 0
		PORTC.OUTSET = PIN5_bm;		// A1 - 1
	}
	else if(addr_2 == 3){
		PORTC.OUTSET = PIN6_bm;		// A0 - 1
		PORTC.OUTSET = PIN5_bm;		// A1 - 1
	}
	_delay_ms(1);
	
	TWI_MasterWriteRead(&twiMaster,sl_addr,data2send,2,0);
	while (twiMaster.status != TWIM_STATUS_READY);
	_delay_ms(10);
}

Using AtmelICE and code in a cycle:

per_buff_x =  read_eeprom(0x50,iter_y);
if(per_buff_x != weekschd[sd][st][pr]){
    write_eeprom(0x50, iter_y, weekschd[sd][st][pr]);
    per_buff_x = read_eeprom(0x50, iter_y);
    weekschd[sd][st][pr] = per_buff_x;
    
}

I checked data after it was changed. Writing and reading worked, i get data i need. The part i do not understand that after power down and power on again the single data bytes are read correctly, but the array is corrupted, not all data gets corrupted in the array(there are bytes that save information). I have read posts about eeprom data corruption, I do not use address 0 and i have BOD at 3V, my circuit is powered by linear regulator(output 3.3V). In eeprom datasheet it is specified that one model Vcc min is 1.8V and other has Vcc min 2.5V(BOD is higher then both). If single bytes do not get corrupted why array gets corrupted? And why there are random parts that get saved?   

This topic has a solution.

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

Power down voltage monitored with oscilloscope.

Attachment(s): 

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

0x100, 0x10A and 0x10C addresses gets corrupted. Other data addresses work fine. Anyone?

 

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

There isn't much to go on, but I think that there is a clue in the corrupted addresses. The three addresses the you mention, all need more than eight bits addressing. I can't see in your code what you are setting in the twiMaster struct, nor how you set the "addr" variable.

 

According to the EEPROM datasheet, two of the bits in the 7-bit address value must be the two most significant bits of the byte address. However, it doesn't look like you are using them as such. Instead, I suspect that you are trying to set these bits by hardware – which will never ever work.

 

When you use I²C devices, any address pins should be kept at a fixed level. At least, I have never come across an I²C device that required me to change logic levels on pins for addressing purposes. You do that once, when you design the PCB.

 

Even if I've misunderstood what you are trying to do, you should have a close look at byte addressing.

You're absolutely right. This member is stupid. Please help.

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

It is a bit of a mystery why anyone would use a 24C08.    It only has 1kB of EEPROM (in 16-byte pages).

 

Your Xmega comes out of the box with 1kB of internal EEPROM.  (I think)

And it also has some USER-SIGNATURE area too.

 

Yes,   the 24Cxxx EEPROMs can write faster because they have larger pages.   e.g. 24C512 has 64kB in 128-byte pages.

 

If you want to use any 24Cxx type of chip,   you need to access the relevant page and write as required.    So if a block straddles a page boundary,   you need to write one page,   wait till not busy,  write the next page.

 

David.

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

It is a bit of a mystery why anyone would use a 24C08.

Agreed. Yes, the xmega32A4U does have 1kB EEPROM. Which, by the way, is much easier to access than an external EEPROM on the I²C bus.

 

But I don't think that the OP writes blocks. Seems that only single bytes are written. And with plenty of delays in between. I truly believe that the OP has misunderstood the address concept.

 

You're absolutely right. This member is stupid. Please help.

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

You can write single-bytes to a 24Cxx if you want.    The page buffers are managed automatically by the chip.

 

Of course,   it takes the same time to write one byte as a whole page.    And you will wear out the EEPROM faster.

 

David.

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

Of course,   it takes the same time to write one byte as a whole page.    And you will wear out the EEPROM faster.

You sure? Afaik, it is only the location that is actually erased and written that is worn. What you're describing sound more like flash.

You're absolutely right. This member is stupid. Please help.

Last Edited: Mon. Mar 23, 2015 - 02:42 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

No,  I am talking about a 24Cxxx or a 25Cxxx.    The wear mechanism is related to page writes.

AVR eeprom writes are byte-orientated.    So the wear mechanism is related to a byte writes.

 

In practice,   you seldom write excessively to EEPROM memory.   The more noticeable effect is the longer time involved in using byte writes than page writes. 

 

David.

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

ErikT wrote:

 

According to the EEPROM datasheet, two of the bits in the 7-bit address value must be the two most significant bits of the byte address. However, it doesn't look like you are using them as such. Instead, I suspect that you are trying to set these bits by hardware – which will never ever work.

 

 

One of my first guesses as well. Only few addresses do not respond. The rest works just fine, even with changing addresses pins by the MCU.

 

I am not using internal EEPROM because it has 100k write cycles and in data sheet i can only find "Write page", "Erase page" and "Atomic page erase and write" but there nothing said about write byte,  with i assume shortens eeprom life time while writing single bytes. Where most external eeproms have 1M write cycles.

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

At the moment i changed to AT24C08C, it needs 2 address bytes. Still same result. My application is not needed to run at real-time, so some delays are acceptable while saving changes.

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

Read the 24C08 data sheet.

 

With hardware A2 pin connected to GND:

It uses slave addresses (W/R) 0xA0/A1 for locations 0-255

It uses slave addresses (W/R) 0xA2/A3 for locations 256-511

It uses slave addresses (W/R) 0xA4/A5 for locations 512-767

It uses slave addresses (W/R) 0xA6/A7 for locations 768-1023

 

If A2 is at VCC,   you get slave addresses 0xA8 - 0xAF

 

I don't think that you have understood the concept of EEPROM endurance.

 

Say that you want to write to location 20.    This is in the second page of 0xA0.    You write 1000000 times to this location.

However location 21 is now worn out because you have used up all the writes to the second page.

 

With the Mega,   you can do 100k writes to 20, 21, 22, ...

If you intend to do 100k writes to every byte in a (16-byte) page,   this comes to 1600000 writes.    i.e. more than the 24C08

 

I know that you are using an Xmega.    It actually can do page-writes to its internal EEPROM.   You will need to read the endurance spec.

 

Do some sums.     I bet that most apps will never get anywhere near the 'maximum' eeprom writes.

In real life,   most eeproms will survive longer than the data sheet suggests.

 

The obvious optimisation for any type of eeprom is "eeprom_update" rather than "eeprom _write".

 

David.

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

david.prentice wrote:

 

With hardware A2 pin connected to GND:

It uses slave addresses (W/R) 0xA0/A1 for locations 0-255

It uses slave addresses (W/R) 0xA2/A3 for locations 256-511

It uses slave addresses (W/R) 0xA4/A5 for locations 512-767

It uses slave addresses (W/R) 0xA6/A7 for locations 768-1023

 

that part works.

 

david.prentice wrote:

With the Mega,   you can do 100k writes to 20, 21, 22, ...

If you intend to do 100k writes to every byte in a (16-byte) page,   this comes to 1600000 writes.    i.e. more than the 24C08

I was not aware that write cycles are meant for pages not bytes.

 

david.prentice wrote:

I know that you are using an Xmega.    It actually can do page-writes to its internal EEPROM.   You will need to read the endurance spec.

In xmega32a4u manual is written:

 

"The EEPROM page buffer is filled one byte at a time, and it must be erased before it can be loaded. When loading the

page buffer with new content, the result is a binary AND between the existing content of the page buffer location and the

new value. If the EEPROM page buffer is already loaded once after erase the location will most likely be corrupted.

EEPROM page buffer locations that are loaded will get tagged by the NVM controller. During a page write or page erase,

only target locations will be written or erased. Locations that are not target will not be written or erased, and the

corresponding EEPROM location will remain unchanged. This means that before an EEPROM page erase, data must be

loaded to the selected page buffer location to tag them. When performing an EEPROM page erase, the actual value of

the tagged location does not matter." page 409.

 

That is the reason why i chose external eeprom. Because it is unclear to me.

 

If i write one byte 100k times, do i damage only that byte or whole page in atxmega internal eeprom?(using ATMEL provided eeprom.h AS6.2)

Last Edited: Tue. Mar 24, 2015 - 11:09 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

With internal EEPROM everything works as it should. Only the matter of endurance left. Write limit counts for one byte(like in ATmega series MCU) or for page.

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

I would guess that the endurance is byte-oriented.    However,  I have not studied the data sheet.

 

Seriously,    most eeprom apps never get near the limit.   e.g. phone numbers or engine tuning parameters.

 

If you design with typical or worst case numbers,    you can calculate whether the AVR will die before you do.    e.g. I might expect to live for 10 years but I would hope that an AVR product should last for 20 years.

 

David.

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I was not aware that write cycles are meant for pages not bytes.

No. Write cycles are meant for bytes, as David said. He explained that in the case of the ST I2C EEPROM, the memory is written page by page, no matter what is inside. So if you write the 3rd byte in the 2nd page for 100k times, then the whole 2nd page get worn out. But in the case of XMEGA internal EEPROM, as said in the datasheet part you quoted, only the byte addresses that are modified inside the page buffer will get written inside the EEPROM. So if you load the 3rd byte of the page buffer then write the 2nd EEPROM page with this buffer for 100k times, only the 3rd byte of the second page will get worn out !

 

And on the tiny/mega parts, the eeprom_update_x() functions read first the location and only overwrite if the content does not match (as opposed to eeprom_write_x() which will overwrite no matter what).

Have a nice day,
Kraal

Last Edited: Tue. Mar 24, 2015 - 12:21 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kraal wrote:

. But in the case of XMEGA internal EEPROM, as said in the datasheet part you quoted, only the byte addresses that are modified inside the page buffer will get written inside the EEPROM. So if you load the 3rd byte of the page buffer then write the 2nd EEPROM page with this buffer for 100k times, only the 3rd byte of the second page will get worn out !

 

 

Thank you. I will trust that. Using internal EEPROM and hoping it wont die after a year.

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

You must do the sums first.

 

e.g. writing to the same eeprom location once a second will be ok for 1.15 days

e.g. writing to the same eeprom location once every 10 minutes will be ok for 690 days

e.g. writing to the same eeprom location once every hour will be ok for 11 years

 

In practice,   you may want to update a location every minute but the value is not changed every minute.

 

You may implement "wear levelling" so it is not always the same location that is updated.

You may store temporary information in SRAM.    Only update EEPROM when you detect the power is failing.

 

Bear in mind that the 24C08 'solution' can act like SRAM.   i.e. you update the page-buffer but only write to the page on power failure.    (or every hour)

 

David.

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

Hi again,

 

Well, my post was not really a solution to your initial problem with only a few bytes got corrupted.

Back to using the internal EEPROM: please note that any tagged location inside the page buffer will get written to the EEPROM. So if you want to limit the wear, you can first read the actual content of the EEPROM and update only the bytes (really at the byte level, even if the variable is a word or more) that need to be changed. Also regarding the time it takes to write a byte or a page, it is the same. So pay attention to that ! And I believe that the eeprom functions from avr-libc (eeprom.h) don't take the page buffer in account correctly for the XMEGAs, i.e. let say you have an array of n elements, even if it fits in one page, the eeprom_update or eeprom_write will take (n * page_write_delay) milliseconds instead of (1 * page_write_delay) milliseconds.

Have a nice day,
Kraal

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

Kraal wrote:

 So if you want to limit the wear, you can first read the actual content of the EEPROM and update only the bytes (really at the byte level, even if the variable is a word or more) that need to be changed.

It needs to run for a long time, and that is what i am doing. Reading, comparing and writing only if needed. Solution is that i can safely use internal EEPROM and everything works for now.