Shop OBEX P1 Docs P2 Docs Learn Events
Need feedback on Wear leveling code — Parallax Forums

Need feedback on Wear leveling code

lardomlardom Posts: 1,659
edited 2010-10-05 18:50 in General Discussion
I'm trying to come up with a way to write to my eeprom so it lasts longer so I wrote some pseudo code to look for obvious flaws in my logic. I want to use array variables for the five programmable variables in my project. The following code will not run. My purpose is to get feedback from experienced programmers. If it makes sense I will write a second method that reads the value-containing element.
The idea is for one array element at a time to contain a value. It will require two operations on a physical address per loop. One will erase and the other will write.

PUB Pseudo_Code | ptr

  if distance[ptr] > 10
    distance[1] := Some_Data

  repeat until distance[ptr] <> 0
    distance[ptr] := distance[ptr]++
  distance[ptr] := 0
  EEPROM :=  distance[ptr]
  distance[ptr] := distance[ptr]++
  distance[ptr] := Some_Data
  EEPROM :=  distance[ptr]

Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2010-10-03 10:50
    Don't write "distance[ptr] := distance[ptr]++". It increments distance[ptr], then copies the incremented value to itself. Just use "distance[ptr]++".

    Your code is very confusing and just doesn't make sense. I think you're confusing the use of ptr with distance[ptr]. How about just carefully describing what you're trying to accomplish at each step?
  • lardomlardom Posts: 1,659
    edited 2010-10-03 11:41
    This time I put comments after each line.
    I also attached a graphic to illustrate my idea.
    PUB Pseudo_Code | ptr        'Wear-leveling way to write new data to the eeprom
    
      if MyVarArray[ptr] > 10                   '10 element array
        MyVarArray[1] := Some_Data
    
      repeat until MyVarArray[ptr] > 0       'Only one element should contain data
          MyVarArray[ptr]++                     'check variables [1] through [10]
      MyVarArray[ptr] := 0                      'clear old data in RAM
      EEPROM :=  MyVarArray[ptr]            'update eeprom
      MyVarArray[ptr]++                         'Move to the next element
      MyVarArray[ptr] := Some_Data         'write data to RAM
      EEPROM :=  MyVarArray[ptr]            'update eeprom
    
    663 x 277 - 32K
  • Mike GreenMike Green Posts: 23,101
    edited 2010-10-03 11:58
    Like I said, you're confusing "ptr" with "MyVarArray[ptr]". I think you want to use "MyVarArray[ptr++]" rather than "MyVarArray[ptr]++" because you want to increment "ptr" to point to the next array element.

    I think you're unnecessarily complicating what you want to do.

    You don't say what range of values you want to store. Maybe you need one byte per value, maybe you need four. It isn't clear.

    You need some way to tell where the data begins and ends in the EEPROM and this needs to be part of the data. One easy way is to use an odd number of bytes or words and to set aside a single bit in each byte or word that gets toggled for each value. With an odd number of entries, there will always be two adjacent entries with the same bit and all the other pairs of entries will have opposite bit values. The only time this won't be true is during the first use of the EEPROM area and that can be addressed by initializing the area.

    When you start up your program, the EEPROM area gets searched for the first pair of entries with the same marker bit. The first of the pair is the last entry stored and the second of the pair is the oldest entry in the EEPROM area and the next to be overwritten.
  • lardomlardom Posts: 1,659
    edited 2010-10-03 12:43
    Mike, I'm sitting here with a smile on my face because you have answered my question. I'm smiling because I feel about as bright as a night light. I need to learn about 'marker' bits.
    All of the values are word sized. [ptr++] <-- That was helpful. I had planned to use a prewritten object to write to the eeprom but I see now that it is essential that I understand the process myself.
    (I have yet to understand why the address of an eeprom is $A0.) You are the best. Thanks.
  • Mike GreenMike Green Posts: 23,101
    edited 2010-10-03 13:16
    By "marker bits" I just mean that you're using some bit in the stored value for some other meaning. You could use the sign bit and just negate the stored value to mean that the word was marked. That would require that zero is not a valid value since there's no minus zero in 2's complement arithmetic. You could use the least significant bit for the marker and shift your stored values left one bit before storing them (and OR in the marker bit).

    The address of the EEPROM is $A0 because of the way the select byte is arranged. Look at the datasheet for any I2C EEPROM and you'll see a diagram that shows how the bits of the select byte are allocated and it should be obvious why the address is the way it is.
  • localrogerlocalroger Posts: 3,452
    edited 2010-10-03 16:02
    lardom, like Mike I don't quite get where you're going with your pseudocode, but I'll describe an approach I've taken which works well.

    In your EEPROM object you will have a routine that reads bytes and a routine that writes them. In the i2cdemoapp these are:

    i2cObject.WriteLong(i2cSCL, EEPROMAddr, eepromLocation, eepromData)
    eepromData := i2cObject.ReadLong(i2cSCL, EEPROMAddr, eepromLocation)

    Your basic strategy is this. First, determine a range of EEPROM addresses you want to use; if you have a 64K eeprom such as on a proto- or demoboard, you can start at $8000 and ignore application downloads. And the more EEPROM you decide to use the slower you'll wear it out, but the more EEPROM you'll need.

    Your strategy:

    Start at the base of your range and search for a non-all-ones entry. (All 1's is blank EEPROM. This scheme depends on that not being a valid value; you might need to assign an always-zero marker byte or bit to make sure this is the case.)

    If you find a non-all-ones entry, write ones to it to clear it and advance your counter to the next entry beyond it. If you advance past the end of your range, set it to the start of your range. Now write the new value at the pointer.

    If you don't find a non-all-ones entry, just start at the beginning of your range.

    If you are updating often you can remember the pointer instead of searching for it on subsequent updates. You really only need to do the search on power-up.

    This gives you averaged out wear without the problem of updating a pointer that will itself wear out at full speed.
  • lardomlardom Posts: 1,659
    edited 2010-10-03 21:57
    localroger, If I understand correctly 'all ones' is the default state of eeprom addresses. That helps a lot.
  • lardomlardom Posts: 1,659
    edited 2010-10-04 08:56
    I uploaded a couple of photos of my controller. It controls a stepper on a linear actuator. It is programmable and it works wonderfully. I decided to tweak it because it writes to the same memory address. Wear leveling will make it even better.
    451 x 644 - 52K
    455 x 627 - 51K
  • localrogerlocalroger Posts: 3,452
    edited 2010-10-05 18:50
    That's a nice looking piece of kit, lardom. Good luck optimizing your EE access.
Sign In or Register to comment.