How to Save variables to onboard EEPROM on Proto Board
eagletalontim
Posts: 1,399
This is one area I get completely lost at and I hope to understand this a little better. I have one of the Prop Proto Boards with the standard EEPROM on it. I don't know what size it is, but I would like to use it to store roughly 20 to 30 numerical values all less than 255. The thing I don't understand is how EEPROMs work beside's their name (Electrically Erasable Programmable Read Only Memory). How can I tell where at on the EEPROM I am writing to or reading from? I have read about starting writing / reading values from $8000. What does that mean? Is the next writable area $8001? Thanks for any help!
Comments
In regard to the location on the EEPROM you are reading from/ or writing to, then your program needs to keep that location.
The first 32K of the EEPROM is transferred to the main RAM of the Prop chip after Boot-up so any location after $8000 is usable.
There are several objects in the OBEX for communicating via the I2C standard.
Basically what I am trying to do is take my menu system "ID" numbers :
MenuB]0[/B := string("Menu Item 1")
MenuB]1[/B := string("Menu Item 2")
And use them to store values on the EEPROM in specific spots for easy reading at a future time.
Example :
Save menu item 0 at address $8000
Save menu item 1 at address "whatever is after $8000"
Or :
Write Menu Item Value to EEPROM at address $8000 + Menu Item ID
Prop Proto Boards have 64K EEPROMs.
Some early QuickStart boards only have 32K EEPROMs. I wrote a program that will tell you if your EEPROM is 64K or 32K.
Most P1 boards have a 64K byte eeprom. the first 32K byte are used to boot the chip and overwritten by programming. The second 32K are usually unused and not overwritten by programming the prop.
Now the adress $8000 (=32768 decimal or 32 X 1024 aka 32K) is the adress of the first byte of the second 32K.
so $8000 is the first byte, $8001 the next.
Now - it depense as usual what you want to archive.
When you want to save some settings AND KEEP them even if you reprogram your prop then you shoud use the top half and start with adresses over $7FFF (32767).
On the other hand, if you want some settings saved and not care about beeing lost after reprogramming then You can use the lower part as well. But keep in mind this is basically what you load after reeboot. And the content of the lower 32K gets copyed into hub.
Now things get funny.
Imagine some program wher you have some variables in a DAT section.
Say - for example BackgroundColor of your screen. And you want the enduser to change that color. So somwhere in your code you give the user a choice between - say - 5 different colors. And save this into your long BGcolor (in HUB).
Everything is nice but after reboot the setting is gone and the old backgroundColor is used.
Here comes the use of writing the lower part of the eeprom. Since the HUB-ram contains a copy of the lower 32K of your eeprom the adresses used are the same in eeprom and HUB-ram.
so with a I2C.writeLong(@BGcolor,BGcolor) you can write the content of your long BGcolor into the eeprom at the adress of BGcolor. HUB and eeprom adress of BGcolor are the same!
after reboot prop reads the eeprom into hub and your long BGcolor has the new value, no the one you save with the prop-tool into it while programming, but the one choosen by the enduser.
As for your Menu-Items ... they are strings, aka usually more then a byte long and ending with a byte 0 (zero).
You will need to track the adresses by counting bytes.
Enjoy!
Mike
Enjoy!
Mike
Enjoy!
Mike
Enjoy!
Mike
i2c.ReadPage(i2c#BootPin, i2c#EEPROM, $8000 + value of Menu Item ID number, @buffer, 32)
I need to make this as "flexible" as I can incase I add more menu options at a later date.
You simply add a offset in decimal for each string
Since you have enough space in the eeprom build a Table with a common lengh for all strings.
in your example your buffer is 32 bytes long.
so start the first string at $8000 + 0
the next one at $8000 + 32
the next at $8000 + 64 and so on
then i2c.ReadPage(i2c#BootPin, i2c#EEPROM, $8000 + (value of Menu Item ID number) * 32, @buffer, 32)
will give you the right adress
Enjoy!
Mike
From a practical standpoint, you may want to limit your strings to 15 characters. With the 0 terminator this is 16 bytes which works nicely with EEPROM page sizes (read the docs). Knowing that each string will occupy no more than 16 bytes you can store them in memory with an index -- just multply the index by 16 and add this to the base (probably $8000). With the offset address you write the number of bytes in the string plus one (you must save the terminator!). To read back, simply read from the indexed address until you hit zero. I've done this and it does work. Again, the sticking point can be the page size; you don't want to write past a page boundary, this will cause big problems and corrupted data.
Managing menu items during run time (state) is a different story and takes a fair amount of planning. If the menu is inside an object the object itself can save the current state of the menu as well.
i2c.ReadPage( i2c#BootPin, i2c#EEPROM, <EEPROM address>, <HUB address>, <# bytes to read>)
i2c.WritePage( i2c#BootPin, i2c#EEPROM, <EEPROM address>, <HUB address>, <# bytes to write>)
i2c.WriteWait( i2c#BootPin, i2c#EEPROM, <EEPROM address>)
Instead of using ReadEEPROM(iloop), try using i2c.ReadByte( i2c#BootPin, i2c#EEPROM, (iloop * 32) + 32768)
Instead of using i2c.WritePage( i2c#BootPin, i2c#EEPROM, @addr, @value, 32), try using i2c.WriteByte( i2c#BootPin, i2c#EEPROM, addr, value)
Also change i2c.WriteWait( i2c#BootPin, i2c#EEPROM, @value) to i2c.WriteWait( i2c#BootPin, i2c#EEPROM, addr)
You'll have to change addr := 32767 + (address * 32) to addr := (address * 32) + 32768
Note that this will write the saved value to the EEPROM one byte at a time ... about 5ms per byte. You could go back to using .WritePage to take advantage of paged writes, but you'd have to pass in the address of the whole array of bytes to be written and the count of the number of bytes.
It still hangs for some reason while pulling 11 different variables from the EEPROM. It does appear to run code past this area as it loads, but nothing else works until the EEPROM is done loading. Is there a way to show a "Loading...." while the EEPROM reads everything?
I'd attach an LED or two to spare I/O pins to use as test indicators (like when the data is being read from the EEPROM). You may not be able to see a flash because the EEPROM read time is so short.
I understand the title of this thread is How to Save variables to onboard EEPROM on Proto Board but I think that you are using the wrong approach to solve a problem. The whole EEPROM thing is only confusing the issue.
MenuB]0[/B := string("What is less than 2") ' This will be shown on line 1 of the display
StoredB]0[/B := 1 ' This is the value for Menu[0] which will be stored in the eeprom at addr := (Menu ID number * 32) + 32768
EDIT * : This variable is changed by the user and stored in the eeprom when they exit the menu or switch to the next menu item.
Same would go for Menu[1]. the value for Menu [1] would be stored in the variable Stored[1] which would be stored on the eeprom in the next corresponding address number.
I suggest encapsulating the logic in a spin file (object). The following code snippet can display any of 5 menu items and keep track of the currently selected menu item.