Saving Variables to EEPROM
eagletalontim
Posts: 1,399
I am attempting to understand how to write variable values to an eeprom based on user input and retrieve them upon reboot. What I am not quite understanding is how to write these variables reliably whether they be a value of 0 or 15000. I have used this code before :
The problem with the above code is I am unsure the address to start at and what address to go to next. The address * 4 part is confusing to me as well. I also believe I had an issue with saving a "0" and retrieving that "0". If I am saving a BUNCH of variables of all sorts of values, I need to make sure I don't mix anything up or overwrite anything accidentally in the eeprom. The string of variables that will be sent from my vb program, parsed, and saved to the eeprom will look something like this:
The EEPROM I will be using is a 256K and I will be using part of it to hopefully "flash" the first 32K to upgrade firmware. This is a whole other step though. Got to start with the basics.
PUB saveval(value, address) | startTime, addr addr := (address * 4) + 32768 if i2c.WriteByte( i2c#BootPin, i2c#EEPROM, addr, value) abort ' an error occured during the write startTime := cnt ' prepare to check for a timeout repeat while i2c.WriteWait( i2c#BootPin, i2c#EEPROM, addr) if cnt - startTime > clkfreq / 10 abort ' waited more than a 1/10 second for the write to finish return
The problem with the above code is I am unsure the address to start at and what address to go to next. The address * 4 part is confusing to me as well. I also believe I had an issue with saving a "0" and retrieving that "0". If I am saving a BUNCH of variables of all sorts of values, I need to make sure I don't mix anything up or overwrite anything accidentally in the eeprom. The string of variables that will be sent from my vb program, parsed, and saved to the eeprom will look something like this:
1:1:1:0:0:0:0:1:15:0:7000:1000:500:200:13000:1:1:0:635:10 'and a bunch more....
The EEPROM I will be using is a 256K and I will be using part of it to hopefully "flash" the first 32K to upgrade firmware. This is a whole other step though. Got to start with the basics.
Comments
Use of writewait is wrong; the intent is that you just call writewait and when it returns, you're safe to do another write. You can also do a simple delay since all available EEPROMs complete a write cycle in less than 5 milliseconds, so you could do WAITCNT(CNT + CLKFREQ / 200) to get past the write cycle.
If you are using a 32 Kbyte (24256) part there's no high EEPROM. You can, however, permanently save variables by just writing them to their original address, e.g. WRITELONG(device, @var, @var). When the Prop boots the modified value will be loaded by the boot loader. You can do this with both DAT and VAR type variables. But if you reload the program, VARS are reinitialized to zero and DATs to whatever they are declared in the source code.
I find that the Spin I2C routines are pretty robust and once the system is debugged and proven free of hardware problems you really don't need to check for the error every time you read or write.
Then, the index of each variable would be the "address" for the "addr := (address * 4) + 32768" code above. So, if the variable array coming from the VB program is too short, it will kick back an error, if it matches the length of what is on the prop, it will begin the save to the eeprom. Upon boot, the variables will then be read back from the eeprom and stored in the same sequence as they went in.
This requires no code to load them on boot up.
Use the following arrangement instead.
To save your "variables" just save the block from $7F00 to $7FFF
Each variable uses 4 bytes(1 long) so 64 variables are available with 256 bytes.
If you need more variable space lower the address ($7F00) to gain more space.
Buffer[32] and eepromAddress were declared in the Var section.
You don't have to write the whole EEPROM but do look at the data sheet for your EEPROM and the various options for writing sequentially or randomly.
Jeff T.
If these values were set by the pre programmed code, how would the eeprom data be loaded on boot if the user has changed these settings via the VB program? Also, I am still not quite understanding the "LONG". I thought since the Prop is a 32 bit processor, a WORD would be 4 bytes. 32 bits = 4 sets of 8 bits which is comes out to 4 bytes. Maybe I am thinking about this too hard?
It would be really nice to be able to save all variables that were named "User_Setting[x]" to the eeprom in one go and the prop automatically boots using the variables saved in the eeprom....not pre-programmed in by default.
Byte = 8 bits
Word = 2 Bytes (16 bits)
Long = 2 Words or 4 Bytes (32 bits)
If you write to the EEPROM at the same address of your variable (you need to know if that variable is one, two, or four bytes), then on the next reset that last saved value will be loaded into RAM. I've done this with many programs.
your initial default values. Then save all variables to eeprom and from then on the
the saved data will be restored every time the propeller boots.
If your values are never > 32767(signed) then used all WORD's.
How could you not figure it out? You have to declare a variable by type (byte, word, or long -- there is no bit type in Spin). A byte will hold values from 0 to 255, a word will hold values from 0 to 65535, a long will hold values between -2.14 billion to +2.14 billion. It's up to you. That said, as the long is the native type, I tend to use longs for simple variables.
Let's say you have a byte variable called ticks and you want to save its present value to EEPROM. Using my 24xx512 object (which is attached), you'd do something like this:
The first parameter, @ticks, tells the wr_byte method what address to write to. The method knows to write a single byte. The second parameter is the value to write. There are similar methods for words and longs, and master method (which is called by the others) that can write any value. There are also read methods, though you're not using them in your case.
I developed my 24xx512 object for the EFX-TEK EZ-8+ controller which uses a 64K EEPROM; the lower 32K holds the program, the upper 32K holds the user sequences.
And, yes, you can use the 24xx512 object with a 24LC256 EEPROM -- you just have to limit your addresses to $0000..$7FFF.
When I try to program this, I get an "Expected End of Line" error on this " if User_Setting[0] <> 0 ". I guess I can't simply call each value by "User_Setting[X]"?
VAR long variable1
then you save an initial value to it by doing
eeprom.wr_long(@variable1,initialValue)
eeprom.wait
where initialValue is the value or expression you want to save. If you're using a 16-bit word variable, then you use wr_word. If you have an 8-bit byte variable, then you use wr_byte.
The first run after a download is the only time you have to deal with presetting values. In one project, I created a variable called initialized, and after the objects were loaded I did something like this:
How it works: On the first run after startup all global variables will be zero, including initialized which will cause the ifnot clause to be true. I set the program variables to their default values (that method also writes them to EEPROM), and then change the EE value of initialized to true. On the next reset the value of initialized will cause the ifnot clause to fail -- the only time this ifnot clause runs is on the first execution after a download.
Something that you need to remember: Every time you update a RAM variable you have to update the EEPROM, too. If you don't that change will be lost on a reset/power-down.
You cannot default common variable values on the first boot (see post #19). You could setup a DAT table with values, and those can be modified on the fly. Still... you must save the values back to EEPROM when you change them. You were almost there in post #13 -- you made things a little harder for yourself than you needed to.