Shop OBEX P1 Docs P2 Docs Learn Events
Non-volatile Vars? -> NVVar! — Parallax Forums

Non-volatile Vars? -> NVVar!

Nick MuellerNick Mueller Posts: 815
edited 2008-01-01 12:16 in Propeller 1
Hi!
Edit:
There's an "official" version 0.1 now.
It still doesn't support crash-proof storage, but it is considerably faster and has new features.
Be sure to read the doc in NVVar.spin

The uploaded version (end of this posting) is the current one
It is so sloooow*), and beta!

Wrote a save/restore to EEPROM for variables. I do know that a version exists (but can't find it).

The rationale behind my version is, that I need versioning of the variables to be stored in EEPROM and I do not want to arrange the vars to be stored in a sequence that is god-given.

So the vars can be written and read one at a time. They are accessed with tags. No matter where the var is in HUB-RAM or what name it has, it can be read and written by a tag (an unique ID *you* assigned).

Versioning is supported by a version number you assign to the whole block in EEPROM. When your software changes, you change your version number. Before trying to blindly read the vars back, retrieve the version of the NVVars. If it differs, you have a chance to react as you need.

** It is still beta! Be aware! **
** It is slower than a wombat, because of the current I2C-routines I used **

It is missing CRC and a save way to read/write that is crash-proof.

*)
I can't find a decend I2C driver. There should be one for the Parallax's SaveVariable/ReadVariable (or how it is named), but I can't find that. Can someone please show a mull where it is?

Attached is the object and a test-program (nor very well documented and not tidied up!)

Nick

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Never use force, just go for a bigger hammer!

The DIY Digital-Readout for mills, lathes etc.:
YADRO

Post Edited (Nick Mueller) : 1/1/2008 12:05:40 PM GMT

Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2007-12-29 21:37
    There are several I2C drivers in the Object Exchange. There is also one written in assembly that's part of FemtoBasic (also in the Object Exchange), but is designed to be used separately.

    Often I2C EEPROM write routines are slow because of the write time of the EEPROM (about 5ms per location). This can be sped up somewhat by using paged writes, but the minimum write time is the roughly 5ms time.
  • Nick MuellerNick Mueller Posts: 815
    edited 2007-12-29 21:47
    > There are several I2C drivers in the Object Exchange.

    Found only two and they are both in Spin. Or I am always looking at the wrong place.
    I currently have waitcnt's with some guessworked ticks. But this is *more* than crude.
    As the storage is a linked list, it takes some time to traverse it. This really needs a speedup (before I introduce caching out of despair).

    > There is also one written in assembly that's part of FemtoBasic (also in the Object Exchange), ...

    I had a look at it, but it is too much integrated into FemtoBasic to be extracted in short time.

    > but is designed to be used separately.

    Sorry? Did you miss a "not" after the "is"?

    Nick

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Never use force, just go for a bigger hammer!

    The DIY Digital-Readout for mills, lathes etc.:
    YADRO
  • Mike GreenMike Green Posts: 23,101
    edited 2007-12-29 22:09
    The I2C assembly routine is indeed designed for use separate from FemtoBasic. You may not feel that the actual implementation succeeds in this goal, but it has been used separately by others.
  • deSilvadeSilva Posts: 2,967
    edited 2007-12-29 23:21
    There was an interesting discussion the other day concerning this topic..
    http://forums.parallax.com/showthread.php?p=696845
    I posted the EEPROM Backup/Restore code there, which is part of a forthcoming Parallax Tutorial..
    Note that there is asmall bug there when doing backup...

    I wonder what has come out of my little code suggestion I also posted in that link.....
    Nothing so advanced as Nick's; but took just 15 minutes smile.gif
  • Nick MuellerNick Mueller Posts: 815
    edited 2007-12-30 00:23
    > There was an interesting discussion the other day concerning this topic..

    OK, I answered there, but lost track of the thread. At least, I maybe found some promising references I2C code there.
    If not, I'll try to surgically extract Mike's routines (I once had a look at them, but under a different aspect).


    > I posted the EEPROM Backup/Restore code there, which is part of a forthcoming Parallax Tutorial..

    I got noticed there, that some code does exist for that problem. But as always, it didn't solve mine. wink.gif

    > Nothing so advanced as Nick's; but took just 15 minutes

    Took me longer. But just because of the I2C-stuff.
    Anyhow, had a beer right now and think I found a robust way to handle power downs during writes.
    But that will require changes in the layout of data... Next release will be stable under the aspect of memory-layout.


    If I would only have a sizeof-operator! <LOL>

    Nick

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Never use force, just go for a bigger hammer!

    The DIY Digital-Readout for mills, lathes etc.:
    YADRO
  • PatMPatM Posts: 72
    edited 2007-12-30 08:09
    EEProms are slow period. If you need EEProm functionality but want speed, try a ferric ram. The FM24C256 is almost identical to the regular 24C256 eeprom in operation but one heck of a lot faster. It can handle up to a 1mhz bus speed (I2C is typically 100 or 400 khz) and it writes at the bus speed. There is no page buffer (except on the FM24C512 but its page is 32kbytes, not 32 bytes) so you really can do multibyte writes of arbitrary lengths to random locations.

    Oh, and its write life is 10 billion instead of the 24CXXX norm of 1 million.

    The only gotcha is that they don't come in DIP packages. Well worth buying a breadboard·adapter if you can't make one yourself.
    ·
  • deSilvadeSilva Posts: 2,967
    edited 2007-12-30 09:22
    Of course you are right, but it would be just nice to transfer with 100 kHz.... The SPIN drivers don't do that smile.gif
    And the price tag is still different...

    Post Edited (deSilva) : 12/30/2007 9:27:17 AM GMT
  • Nick MuellerNick Mueller Posts: 815
    edited 2007-12-30 11:03
    I'll make it faster today.
    Got the idea that it could be used for virtual memory (as soon as it is faster) to store huge arrays. Either individual elements accessed by the tag that serves as index, or blocks with several elements.

    Or swapping RAM.

    If someone finds out where code is in RAM, he could also use it for overlays.


    Nick

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Never use force, just go for a bigger hammer!

    The DIY Digital-Readout for mills, lathes etc.:
    YADRO
  • Nick MuellerNick Mueller Posts: 815
    edited 2007-12-30 17:47
    @Mike

    I simply don't get sdspiFemto.spin working.

    Can't be that complicated!? Leaving your code untouched, I do:

    VAR
      long ctrl[noparse][[/noparse] 2 ]
      byte by
    ...
      i2c.start(@ctrl) 'returns true
      i2c.checkPresence(0) 'returns true
      i2c.checkPresence($8000) 'returns true I have a 25xx512, so that must work
      
      by:= $FF
      i2c.writeEEPROM(0, @by, 1) 'returns 0
      i2c.readEEPROM(0, @by, 1) 'returns 0
    
    



    but "by" is 0 -> it doesn't write.
    all reads return 0. That shoudn't be the case starting from address 0. I'd expect some "garbage-code" there.

    EEPROM is a 25xx512 at the standard-address for booting. But it has both SDA and SCL with a pullup (shouldn't make a difference) and there is a second I2C-device on the bus (which works, as the EEPROM does).

    I'm completely clueless what might be the cause.

    Edit: fixed the "[noparse][[/noparse] 2 ]"-problem
    Nick

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Never use force, just go for a bigger hammer!

    The DIY Digital-Readout for mills, lathes etc.:
    YADRO

    Post Edited (Nick Mueller) : 12/31/2007 3:50:19 PM GMT
  • deSilvadeSilva Posts: 2,967
    edited 2007-12-30 18:14
    Have you tried a writeWait or checkPresence between writing and reading?
  • Mike GreenMike Green Posts: 23,101
    edited 2007-12-30 18:55
    Nick,
    I immediately notice that the control block in your fragment is only a single long. It must be two longs (8 bytes - long aligned). Your variable "by" is getting overwritten.
  • Nick MuellerNick Mueller Posts: 815
    edited 2007-12-30 19:22
    > I immediately notice that the control block in your fragment is only a single long.

    Sorry! Was a typo. I has always been a "long ctrl[noparse][[/noparse] 2 ]"

    Edit:
    To clarify that: The real program does have a "long ctrl[noparse][[/noparse] 2 ]". I only made the error in the snipped posted here.

    Edit2:
    Fixed the "[noparse][[/noparse] 2 ]"

    Nick

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Never use force, just go for a bigger hammer!

    The DIY Digital-Readout for mills, lathes etc.:
    YADRO

    Post Edited (Nick Mueller) : 12/31/2007 3:51:09 PM GMT
  • Mike GreenMike Green Posts: 23,101
    edited 2007-12-30 19:45
    The forum formatting software eats small numbers in brackets. You have to insert spaces around the number like "ctrl[noparse][[/noparse] 2 ]".

    I think deSilva is correct. You need to put a call to writeWait between the write and the read to allow the EEPROM to complete its cycle.
    It's a little odd because the readEEPROM call should be indicating an error from when the driver attempts to send the address to the EEPROM and the EEPROM doesn't respond because it's still busy with the previous write.

    It's not clear from your description just where the EEPROM is connected. Your code fragment uses addresses from $0000 to $FFFF which corresponds to an EEPROM on I/O pins 0 (SCL) and 1 (SDA).
  • Nick MuellerNick Mueller Posts: 815
    edited 2007-12-30 20:16
    > The forum formatting software eats small numbers in brackets. You have to insert spaces around the number like "ctrl[noparse][[/noparse] 2 ]".

    **GNAGNAGNA** I forgot and didn't proofread the posting.

    > I think deSilva is correct. You need to put a call to writeWait between the write and the read to allow the EEPROM to complete
    > its cycle.

    I think your code does that. But maybe I'm wrong.
    I'll try that tomorrow (have to leave now).

    > It's not clear from your description just where the EEPROM is connected.

    standard EEPROM address. The one and only EEPROM connected. Nicely detected and programmed by the Propellertool.

    > Your code fragment uses addresses from $0000 to $FFFF which corresponds to an EEPROM on I/O pins 0 (SCL) and 1 (SDA).

    Did you want to say that the controlBlock needs some values? Looking at your code, the controllblock is initialized to zero.
    The SDA/SCL pins for an EEPROM are hardcoded in your code (I didn't change anything there) to be the pins 28 & 29 (-> readEEPROM). I'm not using the controllblock to communicate, but the procedures readEEPROM/writeEEPROM.


    Thanks for now ...
    Nick

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Never use force, just go for a bigger hammer!

    The DIY Digital-Readout for mills, lathes etc.:
    YADRO
  • Mike GreenMike Green Posts: 23,101
    edited 2007-12-30 20:58
    Nick,
    These routines are designed to accommodate I2C busses on any even(SCL)/odd(SDA) set of pins with the pin pair number supplied as part of the 24 bit address. There's a constant "bootAddr" which contains the information for the boot EEPROM I2C bus (pins 28/29). In your code fragment, you should use "i2c#bootAddr+0" or "i2c#bootAddr+$8000".

    What you wrote should work for EEPROMs on I/O pins 0 and 1.
  • Nick MuellerNick Mueller Posts: 815
    edited 2007-12-31 12:02
    > you should use "i2c#bootAddr+0" or "i2c#bootAddr+$8000".

    Oh my god! I didn't realize that, sorry!

    I'm the type of human who needs examples.

    Now it works. Faster, but not that much (maybe 2..3 times faster). Still far away from blindingly fast.
    I reduced operations within loops with post-increments, precomputing constants etc. but that also didn't make such a difference.
    If the block-read and block-write ops wouldn't be so dangerous ... I'll have to think about them.
    Real block read and paged writes implemented. Faster now!


    I'll come back with a crash-proof version ...


    Nick

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Never use force, just go for a bigger hammer!

    The DIY Digital-Readout for mills, lathes etc.:
    YADRO

    Post Edited (Nick Mueller) : 12/31/2007 3:52:44 PM GMT
  • Mike GreenMike Green Posts: 23,101
    edited 2007-12-31 15:56
    Nick,
    1) Have a look at the first couple of lines of assembly. You'll see that there's a loop that waits for an operation to be requested and it has a WAITCNT which waits for 10us to reduce power consumption of the cog when it's idle. You could change the WAITCNT to a NOP.

    2) Paged writes are much better than single byte writes in that the whole block of data is written at once with only one write cycle delay. You have to be careful about page boundaries (usually 128 bytes or 256 bytes in the larger EEPROMs) though. Block reads are also faster per byte since the setup and completion overhead is amortized over a block of data. The EEPROM also doesn't have to be readdressed for each byte (4 bytes of overhead per transaction).

    3) You could also buffer information and do double buffering. The existing Spin interface routines wait for any previous operation to complete before starting a new one and they wait afterwards for the operation to complete before returning, but you could add a new interface routine that initiates an operation and a separate routine that waits for completion and use those to implement double buffering.
  • Nick MuellerNick Mueller Posts: 815
    edited 2007-12-31 16:16
    @Mike
    Thanks for your tips!

    Re 1):
    Will try

    Re 2):
    Already implemented (I edited my previous posting). Paging works and makes a big difference. My EEPROM (25xx512) only has a pagesize of 64, and testing was done with vars of 4 bytes. Tested with different offsets to get page-misalignments.

    Re 3):
    Will have a closer look at it.

    It just came to my mind, that I'm using the 100kHz. ... hackhackhack <G> Now I can read a list of 100 longs in 2 seconds. Also 1) commented out.

    It's getting closer to something usable. Crash-proofing still missing. That will make it a bit slower.


    Thanks for your comments and a happy new year
    Nick
    PS: The uploaded version is still the slow one.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Never use force, just go for a bigger hammer!

    The DIY Digital-Readout for mills, lathes etc.:
    YADRO
  • Mike GreenMike Green Posts: 23,101
    edited 2007-12-31 16:51
    When I was originally testing these routines, I first tried 400kHz and it wasn't reliable. I looked carefully at the timing in the low level routines and couldn't figure out what was happening from just the code and I don't have a 'scope. It has always worked fine at 100kHz and I have to assume that there was some marginal timing issue at 400kHz. Feel free to experiment and do let me know if you find out anything.

    If you haven't noticed, there's a bit in the control block that chooses between 100kHz and 400kHz. The Spin interface routines always use the 100kHz setting.
  • Nick MuellerNick Mueller Posts: 815
    edited 2008-01-01 12:16
    > When I was originally testing these routines, I first tried 400kHz and it wasn't reliable.

    Didn't get the impression. When there were problems, I used 100kHz, but they remained. smile.gif

    OK, here's the official version 0.1 (original's posting uploaded file is up to date now):
    * crash-proof stuff still missing. I'm running out of time (read: I'm already behind) and need to do other things.
    I'll add that later.
    * Great speed-improvment! reading 300 longs in 0.5 seconds. There shouldn't be such a big difference with bigger data
    * For normal usage (with less than 50 entries as a magnitude) you don't have to care that much about ...
    * Caching. Optimized for reading in the sequence the vars were written the first time. Caching can be switched on/off
    * If you want to abuse NVVar (with hundreds of entries) you need to read about how to use the cache. I added the functions
    GetCacheHint, SetCacheHint and ResetCache. You can get *tremendous* speed improvement by using them cleverly
    But still, as a general rule, if you try to get the entries in exactly the reverse order they were written, you'll have to pay a price.

    Oh, by using the word "caching", I'm stretching it a bit. I wanted to use as little memory as possible, so caching is in fact only remembering the cursor within the linked list in EEPROM.


    The i2c driver in the ZIP is by Mike Green. I just removed a bit of the SD-card-stuff. It still is quite big, because of all the features the code has. I do not suggest to use the i2cDriver written in Spin (but I have left the statements for it as comments). It is really slow!


    Any comments welcome!
    Nick

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Never use force, just go for a bigger hammer!

    The DIY Digital-Readout for mills, lathes etc.:
    YADRO

    Post Edited (Nick Mueller) : 1/1/2008 12:26:31 PM GMT
Sign In or Register to comment.