SparkFun Forums 

Where electronics enthusiasts find answers.

Your source for all things Atmel.
By cosmicray
After reading the Atmel docs on the 32u4, and various comments concerning the use of BOD, I still have some questions.

I understand that EEPROM is written one byte at a time. If I want to store an int (2 consecutive bytes) I have to do two EEPROM writes (along with the shift and mask to disassemble the int). Beyond the BOD, are there any strategies to make sure that both writes, or no writes, actually happen ? Getting the first write, but having BOD stop the second write (for legitimate reasons, obviously) still leaves my written contents in an unexpected state.

To better explain what is happening here, I am writing a circular list of entries. The circular list is to spread the data being logged around, and to prevent hammering on certain EEPROM locations. It would helpful if I had a way of knowing that an entire entry (currently 2 bytes) is intact or not. The only thing I can think of is adding a CRC/checksum byte to each entry in the list. Better, but still leaves some exposure to a false positive.
By jremington
A checksum of some sort would greatly increase the chance of detecting a write failure, but there is no way of being 100% certain. There are only 65536 possible states of two bytes.
By cosmicray
After brainstorming this, I have an idea. It increases the number of write cycles, but I *think* it closes the door on not detecting corruption. Basically it involves doing the write as a two-step, and a presumption that a reserved value tells me something is amiss.

The first step is to write 0xFF to both locations. I could possibly only write it to the second location (still meditating on that one).

The second step is to write an encoded int, one where neither byte will ever contain 0xFF, but instead have a range of 0x00-0xFE. 254*254 gives me a possible value range of 0-64515, which for most usage situations will be acceptable.

This is some code I hacked together in a hurry, not yet tested (so BEWARE). :pray:
Code: Select all
#define maximum_encoded_int 64515
#define encoding_value 255

unsigned int encodeProtectedInt ( unsigned int val ) {
  unsigned int retVal;
  if (val <= maximum_encoded_int) {
    // the input value is acceptable for encoding
    unsigned int rightPart = val % encoding_value;
    unsigned int leftPart = val / encoding_value;
    retVal = (leftPart << 8) | rightPart;
  } else {
    // input value above what we can encode, reject
    retVal = 0xFFFF;
  return retVal;

// this reverses the encoding done by encodeProtectedInt
unsigned int decodeProtectedInt ( unsigned int val ) {
  unsigned int retVal;
  unsigned int leftPart = (val & 0xff00) >> 8;
  unsigned int rightPart = (val & 0x00ff);
  if (leftPart < encoding_value && rightPart < encoding_value) {
    // reassemble mathematically
    leftPart *= encoding_value;
    retVal = leftPart + rightPart;
  } else {
    // reject value, because one of the bytes has the write-fail indicator
     retVal = 0xFFFF; 
  return retVal;
The downside to this approach is that I just doubled my writes to the EEPROM, but that may be acceptable since I'm trying to spread them around anyway.

Would appreciate any thought about this approach.
By cosmicray
BTW, I think that approach could be expanded to 3-byte ints (0-16387063) and 4-byte ints (0-4162314255).

Losing some range on the upper end is the limiting factor.
By jremington
If BOD is the most likely source of failure, then the power supply is the weak link in your design. I would spend more time fixing that problem (or anticipating it with firmware) than worrying about detecting write failures.
By cosmicray
jremington wrote:If BOD is the most likely source of failure, then the power supply is the weak link in your design. I would spend more time fixing that problem (or anticipating it with firmware) than worrying about detecting write failures.
If you understand the application that I'm writing this code for, then you will see my concern.

The application is to supervise, monitor, and record, the charging of some deep-cycle flooded lead acid batteries (GC-2 golf cart style). The batteries are being used as a portable store of energy. When the charge cycle is complete, the batteries are disconnected from the charger, then moved to where the store of energy is used. The charger is also powered down. I would prefer that the controller not happen to be in the midst of a write cycle when that happens, or if it is, I can detect it next time I power up the controller. The EEPROM is being used to record a log of the charge progress, that I can read out later via USB.

In general, I think anything writing to EEPROM should have a method of detecting the non-completion of a multi-byte write sequence. BOD is merely going to protect me from trying to write at a voltage not compatible with the clock speed, nothing in the 32u4 is going to help me in a multi-byte write sequence.
By monkeyxpress
This is a very common situation in embedded systems where you have to expect the power to go off at any time. Sometimes it is better to just put a buffer capacitor and power loss interrupt to keep the chip alive until it can complete tidy ups, but if you don't care about losing the data record then this is an excessive solution to the problem.

The normal solution is basically to have a two step process: You write your data and then you add another byte to the record to indicate that it is now valid. The only issue with this is you waste one byte per record on the validity flag. With small records (such as your two bytes) this is quite wasteful.

You can fix this by having a special header block which stores the address of the last valid record, the record count, and has its own validity byte. You put a bunch of these header blocks into their own list and do the process described above. The number of headers you cycle through is set by how much wear levelling you need. Essentially you've moved the validity flags from the data records into the header sections to trade EEPROM wear for data efficiency.

Another even simpler solution is just to increase each record size - store two sets of samples per record. This means you lose more data if the update gets interrupted, but if this doesn't matter it is the simplest solution.
By monkeyxpress
re: cosmicray's solution.

This is a good approach provided you can afford to have the 'special value'. I would encourage you to have a look at the binary representation of what you're actually doing though. Essentially, you're just allocating the most-significant-bit of the value to be the validity flag instead of a whole byte. A good solution if you don't need that bit for data, but you should write your code to make this explicit, rather than dealing with the integers themselves. The reason for this is that the * / and % operators should be avoided at all cost on an embedded platform. They can be up to 100x slower than just doing the bit manipulations direction using the bitwise operators (|, &, ^).

Here are some thoughts:
Code: Select all
if (val <= maximum_encoded_int)

// replace with:
if ((val & 0x8000) == 0)

unsigned int rightPart = val % 255;
unsigned int leftPart = val / encoding_value;

// replace with:
typedef unsigned char uint8_t;
uint8_t rightPart = (uint8_t)val;		// the compiler will just take lower byte
uint8_t leftPart = (uint8_t)(val >> 8);	// the compiler will just take upper byte

// Also think carefully about your variable types - use an 8-bit where you only need an
// 8-bit. This saves memory and instruction significantly.
If you want to learn more about what is happening on the chip this online simulator and tutorials might be helpful:
long long title how many chars? lets see 123 ok more? yes 60

We have created lots of YouTube videos just so you can achieve [...]

Another post test yes yes yes or no, maybe ni? :-/

The best flat phpBB theme around. Period. Fine craftmanship and [...]

Do you need a super MOD? Well here it is. chew on this

All you need is right here. Content tag, SEO, listing, Pizza and spaghetti [...]

Lasagna on me this time ok? I got plenty of cash

this should be fantastic. but what about links,images, bbcodes etc etc? [...]