Writing data to EEPROM

JBWolfJBWolf Posts: 334
edited 2011-11-22 - 16:24:18 in Propeller 1
-=UPDATE=-
Solved! See last posts for example code.
Works with the 24LC256 that comes with the PEKit




Hello,
I am having a little trouble figuring out how to write data to eeprom for the first time.
I have the 32k included with the PEKit, I only need to write maybe four variables of byte length.
I would like to keep these values so the program will 'remember' settings after being turned off.
Not sure how I write the data, or how to make sure there is enough room.

All help is appreciated :)
J
«1

Comments

  • Mike GreenMike Green Posts: 22,869
    edited 2011-11-02 - 06:35:57
    Using the "Basic_I2C_Driver" object from the ObEx, you'd write a value to the variable X as follows: (from the comments in Basic_I2C_Driver)
    PRI writeIt( value ) | startTime
       if i2c.WritePage(i2c#BootPin, i2c#EEPROM, @X, @value, 1)
         abort ' an error occured during the write
       startTime := cnt ' prepare to check for a timeout
       repeat while i2c.WriteWait(i2c#BootPin, i2c#EEPROM, @X)
         if cnt - startTime > clkfreq / 10
           abort ' waited more than a 1/10 second for the write to finish
    
  • JBWolfJBWolf Posts: 334
    edited 2011-11-02 - 10:25:46
    Is that object compatible with this eeprom? In the description is listed several eeprom model numbers, none of which match the one included with the PE kit.
    http://www.parallax.com/Store/Components/AllIntegratedCircuits/tabid/154/CategoryID/18/List/0/SortField/0/Level/a/ProductID/400/Default.aspx

    Here is the object I think you are referring to:
    http://obex.parallax.com/objects/251/
  • Bobb FwedBobb Fwed Posts: 1,115
    edited 2011-11-02 - 10:28:27
    It's this object: http://obex.parallax.com/objects/672/

    That object is compatible with (just about) any EEPROM that works with the Propeller.
    "Humanity is not yet sufficiently advanced to be willingly led by the discoverer's keen searching sense." – Nikola Tesla

    Some of my objects:
    MCP3X0X ADC Driver - Programmable Schmitt inputs, frequency reading, and more!
    Propeller-based Database (SPD-LW) - Making life easier and more readable for all your EEPROM storage needs.
    Check out my website (unrelated to this forum): NimonPro.com
  • RaymanRayman Posts: 9,297
    edited 2011-11-02 - 10:54:36
    Maybe something like this is what you want:
    http://forums.parallax.com/showthrea...ogging-and-I2C
    Prop Info and Apps: http://www.rayslogic.com/
  • 4x5n4x5n Posts: 716
    edited 2011-11-02 - 13:40:55
    Rayman wrote: »
    Maybe something like this is what you want:
    http://forums.parallax.com/showthrea...ogging-and-I2C

    I had to spend some time thinking about how to use it but Mike's Basic_I2C_driver works great and is nice and small. I put together a short program to demo reading and writing to eeprom using his driver. I selected an address beyond 32K so be sure to change the start address so the data will fit.
    ''This my first attempt at writing a program to use
    ''the Basic_I2C_Driver to read and write to an eeprom
    ''above the 32KB boundary Since it's only a test I made
    ''no attempt to prompt for the data to write.
    ''The constant EEPROMaddress is the start address
    ''The constant Writechar is the data to be written to the eeprom
    
    
    CON
            _clkmode = xtal1 + pll16x     'Standard clock mode * crystal frequency = 80 MHz
            _xinfreq = 5_000_000
    
            EEPROM = %1010_0000
            EEPROMaddress = $9000
            I2cSCL = 28
    
            Writechar = $ff
    
    VAR
      long   eaddr, eeval
       
    OBJ
      ee            : "Basic_I2C_Driver"
      pst           : "Parallax Serial Terminal"
      
    PUB main
    
    ' Initialize serial terminal and i2c driver
      pst.Start(115200)
      ee.Initialize(I2cSCL)
    
    ' Delay for five seconds
      repeat 10
    
        pst.char(".")
        waitcnt(clkfreq/2+cnt)
    
      pst.NewLine
      
    ' Read 16 bytes of data and output to serial terminal
      readee
      
      pst.Newline
    
    ' Write 16 bytes of data don't bother outputing to serial terminal
      writeee
    
    ' Read data just written. Hopefully it will have the proper data
      readee
    
    ' Announce completion :-)  
      pst.str(string("quiting now"))
    
    
    PUB readee
    
      eaddr := EEPROMaddress
      pst.str(string("Reading eeprom"))
      pst.NewLine
      
      repeat 16
    
        pst.str(string("Reading address: 0x"))
        pst.Hex(eaddr, 4)
        eeval := ee.ReadByte(I2cSCL, EEPROM, eaddr)
        pst.str(string(" - "))
        pst.Hex(eeval, 2)
        pst.NewLine
        eaddr++
    
    PUB writeee
    
      eaddr := EEPROMaddress
      
      pst.str(string("Writing to eeprom"))
      pst.NewLine
      pst.NewLine
    
       repeat 16
    
        ee.WriteByte(I2cSCL, EEPROM, eaddr, Writechar)
        eaddr++
    
    [
    
    Finding the space to put it is up to you but you could use the propeller spin tool to find unused eeprom space. Keep in mind that if you use eeprom space in the lower 32K space the data will be overwritten every time you use the propeller tool to program the eeprom.
  • Bobb FwedBobb Fwed Posts: 1,115
    edited 2011-11-02 - 13:47:58
    If you don't care about using up a fair bit of memory (doing something pretty simple), I have something that will handle everything for you and manage any size and type of values: Memory Storage Management Lightweight (or the larger, more flexible Memory Storage Management).
    "Humanity is not yet sufficiently advanced to be willingly led by the discoverer's keen searching sense." – Nikola Tesla

    Some of my objects:
    MCP3X0X ADC Driver - Programmable Schmitt inputs, frequency reading, and more!
    Propeller-based Database (SPD-LW) - Making life easier and more readable for all your EEPROM storage needs.
    Check out my website (unrelated to this forum): NimonPro.com
  • JBWolfJBWolf Posts: 334
    edited 2011-11-19 - 03:29:54
    Thanks for the replies, Sorry for the delay in responding.

    Ok I just spent a few hours trying to get one to work...
    First I tried:
    http://forums.parallax.com/showthread.php?97625-PE-Kit-Lab-Applications-%96-EEPROM-Datalogging-and-I2C
    This seemed like a simple to use object, but everytime I try to use VarBackup, the whole program locks up.
    I tried the most simple approach I could think of...
    program starts, VAR long value[31], initialize 'value' to 0.
    Use pushbutton to increase value.
    eeprom.varbackup(@value, @value[31] + 3)
    program locks

    Next I took a look at:
    Memory Storage Management Lightweight
    But I couldnt even figure out what commands to use for backing up and restoring, that and the memory addresses were so confusing that I gave up.

    Tomorrow I will take a look at:
    http://obex.parallax.com/objects/672/

    If I cannot get anything going from that either, I will post some code and hopefully someone will have the time to walk me through
    I appreciate the help!
  • JBWolfJBWolf Posts: 334
    edited 2011-11-19 - 03:42:30
    Ok I went ahead and took a peek at the basic I2C and couldnt get past here:
    This will work with the boot EEPROM and does not require a pull-up
    resistor on the SCL line (but does on the SDA line ... about 4.7K to
    +3.3V)

    Does this mean I need to add a resistor?
    Sorry, I have absolutely no previous knowledge in this area at all.... Very confusing to me.
  • lardomlardom Posts: 1,524
    edited 2011-11-19 - 10:01:15
    Martin Hebel has an object called "BS2_Functions" in the OBEX which I find easy to use. One useful insight is that variables occupy the same address in ROM as they do in RAM. This means you can store a new value in a variable then write to and read from the eeprom by the variable name as opposed to a hex address. "variablename @variablename". The object has several 'read' and 'write' methods which you might find helpful.
    Larry

    If the grass is greener on the other side...it's time to water your lawn.
  • Mike GreenMike Green Posts: 22,869
    edited 2011-11-19 - 10:28:05
    All I2C devices require that there be a pull-up resistor on the SDA and SCL lines, usually near the "bus master" which, in this case, is the Propeller. If you don't use certain features of the I2C specification (like multiple bus masters) you can get away with only one pull-up on the SDA line. Most Propeller boards only provide the pull-up resistor on the SDA line. The I/O driver has to be written to support this and the Basic_I2C object supports this. It will also work with an I2C bus with a pull-up on both lines.
  • Duane DegnDuane Degn Posts: 10,002
    edited 2011-11-19 - 13:51:46
    Mike Green wrote: »
    Most Propeller boards only provide the pull-up resistor on the SDA line.

    Mike,

    I disagree. I think the norm is for Propeller boards to use pull-ups on both the data and clock lines. I recently looked through some of my Propeller boards to note which boards use a pull-up on the clock and which don't.

    I found three boards without pull-ups on both lines.

    The Propeller Professional Development board
    Propeller Demo Board
    Jazzed's TetraProp board (He says leaving off the clock pull-up was an oversight.)

    These are the boards with pull-ups on both lines.

    Propeller Protoboards
    QuickStart boards
    GG Propeller Platform
    Spinneret
    Laser Range Finder
    Propeller Backpack
    Hydra
    Tubular's UN3RB3LLY

    Kye's real time clock object assumes there are pull-ups on both lines.

    Duane
  • localrogerlocalroger Posts: 3,174
    edited 2011-11-19 - 14:38:40
    Both the PPDB and DemoBoard are first generation products where a little short-sighted thinking, later corrected, might have applied.
  • JBWolfJBWolf Posts: 334
    edited 2011-11-19 - 16:07:59
    I am using the PEkit 40-pin dip... just the bare parts on one of my protoboards (model 203a).

    So to use any of these objects, do I need to add a special resistor?
    How do I identify which resistor I need to purchase and how exactly should I connect it? (i typically purchase through digikey)

    I need this in lamens terms with walkthrough... I did not get any useable info from posts 10-13

    Something simple like... to write to eeprom for the first time, you will first need to purchase one of these and place it here orientated like this.
    Then download this object. Here is a simple example of how to use this object. here are the commands for this object and how to use them.

    I need a very clear and formal learning method. I am getting nothing but bits and pieces with lots of assumed stuff.
    I havent really learned a single thing yet about how to do this properly, and do not feel any closer... I'm amazed this hasnt been addressed yet
  • lardomlardom Posts: 1,524
    edited 2011-11-19 - 21:40:02
    You begin with a parts list and a schematic. If you have the PE kit chapter three will show you how to connect the eeprom.
    Larry

    If the grass is greener on the other side...it's time to water your lawn.
  • Duane DegnDuane Degn Posts: 10,002
    edited 2011-11-19 - 22:08:56
    JBWolf wrote: »
    do I need to add a special resistor?
    How do I identify which resistor I need to purchase and how exactly should I connect it? (i typically purchase through digikey)

    I need this in lamens terms with walkthrough... I did not get any useable info from posts 10-13


    . . .

    and do not feel any closer... I'm amazed this hasnt been addressed yet

    The sticky thread at the top of the Propeller Forum titled "Propeller Education Kit, Labs, Tools and Applications" list additional labs, tools and applications to use with the PEK. One lab is "EEPROM Datalogging". Here's the thread.

    A 10K resistor has the color bands brown, black, orange and either gold or silver.

    Most of the schematics of the boards listed in post #12 (one without useful information) are available to download. They will show how the resistors are connected (the Hydra schematic is a bit different than the rest).
  • JBWolfJBWolf Posts: 334
    edited 2011-11-19 - 22:55:00
    I do have a working propeller as per the PEkit instructions along with a working program.
    I need to backup several long variables, they are to be restored after power is turned back on.

    I have tried using Here's the thread. but it does not mention anything about needing an extra pull-up resistor.
    As there is no mention to changing hardware, and says it is designed to work with the 24LC256 that comes with the PEKit, I tried using the program as is.
    I only used the 'propeller eeprom.spin' object as I do not need hyperterminal.
    I used the code as illustrated, but my program immediately locks up when it reaches the eeprom.varbackup call.
    I will post my code below in a bit
  • JBWolfJBWolf Posts: 334
    edited 2011-11-20 - 00:04:39
    Ok I had to improvise as my code is way way too long to post in here just for the sake of debugging the databackup.
    I basically cut and revised to make it as basic as possible.

    General program structure:
    One cog monitors buttons, other works with LED.
    pushing button increases speed of blinking led.

    One problem that I am trying to address by creating a 'databackup' indicator... is when the program is run for the first time, there will be nothing to restore.
    So I put an IF statement in to create default variables if the databackup value is < 1
    Everytime either the speed or counter variable is changed, it needs to set the databackup variable to 1 and backup both.
    On next reboot, the system should start by recovering the 'databackup' variable first, then recover both the speed & counter variable
    {{
    
    mem backup test
    
    }}
    
    
    CON
    
       Button1 = 21
       Button2 = 20
       LED = 26
    
    
    OBJ
       eeprom : "Propeller Eeprom"   
    
    VAR
    
      long stack[50]
      byte cog[5]
      long counter[31] 
      long speed[31]
      long databackup[31]
      
    
    
    PUB Main
    
    eeprom.VarRestore(@databackup, @databackup[31] + 3)      ' restore databackup indicator
     
     if databackup < 1
       speed := 100                                          ' set defaults if databackup < 1
       counter := 5
     else
       eeprom.VarRestore(@counter, @counter[31] + 3)         ' restore variables if databackup = 1
       eeprom.VarRestore(@speed, @speed[31] + 3) 
    
     launch2cogs
       repeat
    
    
    PUB Launch2cogs
    
    coginit(3, Buttons(@counter, @databackup), @stack[10])
    coginit(4, Blink(@speed, @counter, @databackup), @stack[20])
    
    
    PUB Buttons(CounterAddress, dbackup) | tmp
    dira[button1]~
    dira[button2]~   
    
                   
    tmp := long[CounterAddress]                                          ' temp counter variable
    
    repeat
      if button1 == 1 and button2 == 1                                   ' hold both buttons for system reset with default variables
         long[dbackup] := 0                                              ' turn off backup indicator
         eeprom.VarBackup(@dbackup, @dbackup[31] + 3)                    ' backup the indicator value
         REBOOT                                                          ' restart prop
    
      if button1 == 1 and button2 == 0
         tmp := ++tmp // 4                                               ' if button pressed, increment temp counter
         long[counteraddress] := tmp                                     ' write new counter value
         long[dbackup] := 1                                              ' write databackup indicator
          eeprom.VarBackup(@counteraddress, @counteraddress[31] + 3)     ' backup new counter variable
          eeprom.VarBackup(@dbackup, @dbackup[31] + 3)                   ' backup the indicator
      waitcnt(clkfreq + cnt)                                             ' wait 1 sec
    
    
    
    
    PUB Blink(SpeedAddress, counteraddress, dbackup) | tmp1, tmp2
    dira[LED]~~
    outa[LED]~~
    tmp1 := 0                                                            ' temp counter variable
    tmp2 := 0                                                            ' temp speed variable
    
    repeat
      if long[counteraddress] <> tmp1                                    ' if counter variable has changed since last loop
         tmp1 := long[counteraddress]                                    ' tmp1 grabs new counter value
        repeat tmp1                                                      ' loop 'counter' many times
            case tmp1                                                    ' set speed variable based on counter value
              0 :  tmp2 := 100
              1 :  tmp2 := 200
              2 :  tmp2 := 300
              3 :  tmp2 := 400
              4 :  tmp2 := 500       
          !outa[LED]                                                     ' flop the LED outa condition
          waitcnt(clkfreq / tmp2 + cnt)                                  ' wait 1 sec / speed
          !outa[LED]                                                     ' flop the LED outa condition
    
       long[speedaddress] := tmp2                                         ' write new speed value
       eeprom.VarBackup(@speedaddress, @speedaddress[31] + 3)             ' backup new speed variable
       eeprom.VarBackup(@dbackup, @dbackup[31] + 3)                       ' create backup indicator      
       waitcnt(clkfreq + cnt)    
      
     
    

    The program will not run, it locks up immediately
  • lardomlardom Posts: 1,524
    edited 2011-11-20 - 08:19:33
    This is the logic in one of my working methods. I use a 4x4 keypad and I programmed the letter "D" to make a method call;

    PUB NewDistance hypothetical method
    keypad := 0 clear the keypad so I can use it for other operations
    IF (some conditional statement)
    Distance := 0 reset the value so I can change it
    Distance := New value input from keypad PRI method
    (display the new value on my lcd)
    BS2.Write_CodeMem(@Distance,Distance,2) Martin Hebel's object writes to the eeprom
    New value := 0 clear the variable so I can use it for other operations

    I hope this helps.
    Larry

    If the grass is greener on the other side...it's time to water your lawn.
  • Mike GreenMike Green Posts: 22,869
    edited 2011-11-20 - 08:38:45
    I suspect that your program is locking up because you're calling eeprom.VarBackup from two cogs at the same time. The routines involved wait for various conditions to occur and, because both cogs are trying to access the EEPROM (and the I/O pins involved) at the same time, one of them is hanging up and maybe causing the other to hang up as well.

    Any time two different cogs can access a shared resource, like specific I/O pins or the same hub variables, at the same time, you have to use a lock or semaphore. In Spin, these are provided with the LOCKxxx statements. Somewhere in your program's initialization, you have to get a lock id with:

    lockId := LOCKNEW ' lockId is a global long variable

    Before each call to eeprom.VarBackup, you need to have a

    REPEAT UNTIL NOT LOCKSET(lockId)

    After each call to eeprom.VarBackup, you need to have a

    LOCKCLR(lockId)
  • JBWolfJBWolf Posts: 334
    edited 2011-11-20 - 15:00:53
    Mike, I tried exactly as you instructed... same result, locks up
    I added some debugging to the LED so I can generally tell where it is locking up by having the LED flash at the beginning of the cogs being launched.
    It does blink the LED indicating the cogs have been launched.
    In the program, the Buttons routine backs up 2 variables after a button is pressed. In the Blink routine it is supposed to blink the LED depending on the button being pressed... it never gets this far.
    So it must be locking up while trying to write the variables in the Buttons routine.

    Here is my attempt at your instructions:
    Can you correct my code? I normally dont ask for others to write my code as it skips the learning step... but I would LOVE to see a working example.
    I am just getting so frustrated with this
    {{
    
    mem backup test
    
    }}
    
    
    CON
    
       Button1 = 21
       Button2 = 20
       LED = 26
    
    
    OBJ
       eeprom : "Eeprom"   
    
    VAR
    
      long stack[50]
      byte cog[5]
      long counter[31] 
      long speed[31]
      long databackup[31]
      long lockid
    
    
    PUB Main
    dira[26]~~
    outa[26] := 1
    waitcnt(clkfreq + cnt)
    
    lockId := LOCKNEW
    
    eeprom.VarRestore(@databackup, @databackup[31] + 3)      ' restore databackup indicator
     
     if databackup < 1
       speed := 100                                          ' set defaults if databackup < 1
       counter := 5
     else
       eeprom.VarRestore(@counter, @counter[31] + 3)         ' restore variables if databackup = 1
       eeprom.VarRestore(@speed, @speed[31] + 3) 
     outa[26] := 0
     waitcnt(clkfreq + cnt)
     launch2cogs
       repeat
    
    
    PUB Launch2cogs
    
    coginit(3, Buttons(@counter, @databackup), @stack[10])
    coginit(4, Blink(@speed, @counter, @databackup), @stack[20])
    
    
    PUB Buttons(CounterAddress, dbackup) | tmp
    dira[button1]~
    dira[button2]~   
    
                   
    tmp := long[CounterAddress]                                          ' temp counter variable
    
    repeat
      if ina[button1] == 1 and ina[button2] == 1                                   ' hold both buttons for system reset with default variables
         long[dbackup] := 0                                              ' turn off backup indicator
         REPEAT UNTIL NOT LOCKSET(lockId)
           eeprom.VarBackup(@dbackup, @dbackup[31] + 3)                    ' backup the indicator value
         LOCKCLR(lockId) 
         REBOOT                                                          ' restart prop
    
      if ina[button1] == 1 and ina[button2] == 0
         tmp := ++tmp // 4                                               ' if button pressed, increment temp counter
         long[counteraddress] := tmp                                     ' write new counter value
         long[dbackup] := 1                                              ' write databackup indicator
         REPEAT UNTIL NOT LOCKSET(lockId)  
           eeprom.VarBackup(@counteraddress, @counteraddress[31] + 3)     ' backup new counter variable
         LOCKCLR(lockId)
         REPEAT UNTIL NOT LOCKSET(lockId)    
           eeprom.VarBackup(@dbackup, @dbackup[31] + 3)                   ' backup the indicator
         LOCKCLR(lockId)     
      waitcnt(clkfreq + cnt)                                             ' wait 1 sec
    
    
    
    
    PUB Blink(SpeedAddress, counteraddress, dbackup) | tmp1, tmp2
    dira[LED]~~
    outa[LED]~~
    waitcnt(clkfreq /2 + cnt)
    outa[LED]~
    waitcnt(clkfreq /2 + cnt)
    tmp1 := 0                                                            ' temp counter variable
    tmp2 := 0                                                            ' temp speed variable
    
    repeat
      if long[counteraddress] <> tmp1                                    ' if counter variable has changed since last loop
         tmp1 := long[counteraddress]                                    ' tmp1 grabs new counter value
        repeat tmp1                                                      ' loop 'counter' many times
            case tmp1                                                    ' set speed variable based on counter value
              0 :  tmp2 := 100
              1 :  tmp2 := 200
              2 :  tmp2 := 300
              3 :  tmp2 := 400
              4 :  tmp2 := 500       
          !outa[LED]                                                     ' flop the LED outa condition
          waitcnt(clkfreq / tmp2 + cnt)                                  ' wait 1 sec / speed
          !outa[LED]                                                     ' flop the LED outa condition
    
        long[speedaddress] := tmp2                                         ' write new speed value
        REPEAT UNTIL NOT LOCKSET(lockId)   
          eeprom.VarBackup(@speedaddress, @speedaddress[31] + 3)             ' backup new speed variable
        LOCKCLR(lockId)
        REPEAT UNTIL NOT LOCKSET(lockId) 
          eeprom.VarBackup(@dbackup, @dbackup[31] + 3)                       ' create backup indicator
        LOCKCLR(lockId)         
       waitcnt(clkfreq + cnt)    
      
      
    
  • kuronekokuroneko Posts: 3,623
    edited 2011-11-20 - 16:07:43
    @JBWolf: FWIW, your first restore operation basically kills your lockid. databackup is defined as having 31 longs (0..30) but you restore 32 longs. If you go back to the PE Kit thread you'll notice that they actually use 32 longs for their data arrays. Other arrays suffer from the same issue. Also, 10 longs for a SPIN stack (@stack[10]..@stack[20]) is rather small. I'd suggest - given that you reserve 50 longs initially - @stack{0} and @stack[25] respectively.

    re: lock usage, don't indent your to-be-protected code under the lockset line. This (indentation) simply means it's called until the lock is required which is what you want to avoid. Have a look at the manual (v1.2, p.126) LOCKSET + examples.
    repeat while lockset(ID)
    write(parameter)              ' don't indent this code
    lockclr(ID)
    
  • lardomlardom Posts: 1,524
    edited 2011-11-20 - 20:11:44
    I hope I'm seeing this correctly. Your led goes out after "outa[26] := 0". Two lines below that you write "launch2cogs" and then "repeat" is indented below that. I would comment that last command out.
    One of the debugging techniques that I use is to add code that displays values or strings to the PST. A debug statement that will display the values in "speed" and "counter" at any given point is more conclusive than an led.
    Larry

    If the grass is greener on the other side...it's time to water your lawn.
  • JBWolfJBWolf Posts: 334
    edited 2011-11-21 - 21:28:07
    Larry, yes I understand adding a PST would reveal more information than an LED. But the problem is the program locks up when it reaches the VarBackup.... so knowing the value isn't going to help me. If I remove the VarBackup, everything works fine, so I'm not very concerned about the values so much as finding where exactly in the program it locks up at. Right now it is locking up in the Button method when it reaches the VarBackup command. If I can get the VarBackup & VarRestore to work, the LED should blink the number of times the variable value is, basically providing me the same debugging as a pst. But if you think it will help, I will certainly add a pst

    Kuro:
    Ok I will increase the stack. What should I do about the arrays?

    One thing I dont understand about the 'propeller eeprom.spin' object is the start address and end address.
    I used value[31] as demonstrated in their documentation, I was assuming that was to get an end value, i.e. - VarBackup(@value, @value[31])
    In other words, if there is only one variable without an array, the beginning address would be the same as the end address... therefore nothing.
    Am I assuming this wrong? Can I simply use a VarBackup(@value, @value) so properly backup the value?
  • kuronekokuroneko Posts: 3,623
    edited 2011-11-21 - 21:44:01
    JBWolf wrote: »
    What should I do about the arrays?

    One thing I dont understand about the 'propeller eeprom.spin' object is the start address and end address.
    I used value[31] as demonstrated in their documentation, I was assuming that was to get an end value, i.e. - VarBackup(@value, @value[31])
    In other words, if there is only one variable without an array, the beginning address would be the same as the end address... therefore nothing.
    Am I assuming this wrong? Can I simply use a VarBackup(@value, @value) so properly backup the value?

    They define the array with 32 longs (you only used 31). Meaning the last element of this (32 long) array is value[31] (first being value[0]). Getting its address will effectively return the address of its first byte which is where the +3 comes in. So if you want to save a single long you'd call
    eeprom.VarBackup(@value, @value+3)
    

    Did you adjust your lock code?

    Just noticed something else. You should get your address/value contexts sorted out. E.g. you pass the address of the speed (array) to your blink method but in there you use the address of the parameter (@speedaddress). In this case you just want speedaddress. It would also be a good idea to keep the reboot command inside the lock.

    FWIW, I came up with a minimal test case but it locks up for some reason.
  • kuronekokuroneko Posts: 3,623
    edited 2011-11-21 - 22:56:06
    FWIW, I came up with a minimal test case but it locks up for some reason.
    This EEPROM object doesn't play nicely with multiple cogs regardless of whether you use locks or not. Once e.g. a VarRestore finishes it pulls the clock line high (I2cStop method) in the context of the current cog. Which means another cog can never control the clock line. A solution would be to delegate the EEPROM handling to a single cog (and let other cogs talk to it). Does that fit into your plans?
  • JBWolfJBWolf Posts: 334
    edited 2011-11-21 - 23:16:20
    Ok yes I think I can do that... since the main cog0 is not doing anything after launching the other cogs, I can have this monitor a variable that tells it to backup to eeprom.

    I decided to make it even more simple for the sake of learning:
    {{
    
    mem backup test
    
    }}
    
    
    CON
    
       Button1 = 21
       Button2 = 20
       LED = 26
    
    
    OBJ
       eeprom : "Eeprom"   
    
    VAR
    
      long stack[300]
      byte cog[5]
      long counter
      long speed     
    
    
    PUB Main
    
    counter := 0
    speed := 0      
    
    launch2cogs
    repeat
    
    
    PUB Launch2cogs
    
    coginit(3, Buttons(@counter, @speed), @stack[50])
    coginit(4, Blink(@counter, @speed), @stack[100])
    
    
    PUB Buttons(count, spd) | tmp1, tmp2
    dira[button1]~
    dira[button2]~   
    
                   
    tmp1 := 4                                        ' temp counter variable
    tmp2 := 4
    
    repeat
      if ina[button1] == 1
         tmp1 := ++tmp1 //5
         long[count] := tmp1
         
      if ina[button2] == 1
         tmp2 := ++tmp2 //5
         long[spd] := tmp2
      waitcnt(clkfreq /5 + cnt) 
    
    
    
    
    PUB Blink(count, spd) | tmp1, tmp2, tmp3
    dira[LED]~~
    outa[LED]~~
    tmp1 := 0                                                            ' temp counter variable
    tmp2 := 0                                                            ' temp speed variable
    tmp3 := 0
     
    
    repeat              
        tmp1 := long[count]
        tmp2 := long[spd]
        tmp3 := tmp2 * 2 + 2
        repeat (tmp1 + 1 * 2)
          !outa[LED]
          waitcnt(clkfreq / tmp3 + cnt)
          !outa[LED]
          waitcnt(clkfreq / tmp3 + cnt)
       waitcnt(clkfreq + cnt)
    

    Ill edit this in a bit to try to get a backup to work.
    do I need to include the locks?
    Do I need to have a 31 array variable for varbackup to find the end address?
  • kuronekokuroneko Posts: 3,623
    edited 2011-11-21 - 23:24:13
    JBWolf wrote: »
    do I need to include the locks?
    Do I need to have a 31 array variable for varbackup to find the end address?
    Locks, yes, because you still have multiple users. Delegating the EEPROM handling to a single cog just sidesteps the pin contention.

    If you only want to backup single long variables then you don't need an array. Just use @value and @value + 3 or - assuming a function takes its address - value_addr and value_addr + 3. Array backup works like before - assuming value[N] - @value[0] and @value[N-1] + 3.

    re: the array thing, a single long is equivalent to using long value[1] which means you'd end up with @value[0] for the start address and @value[1-1] + 3 for the end address. Both address () expressions are @value[0] which is the same as @value.

    Update: Also note that data transfer between RAM and EEPROM is byte oriented. So you should be careful re: reading/updating variables while they are being restored/backed up. For example bytes 0 and 1 of a given long are written to EEPROM then another cog updates said long (atomic op) and then we finish with bytes 2 and 3 (of the new value). Which isn't necessarily what you want.
  • JBWolfJBWolf Posts: 334
    edited 2011-11-22 - 00:11:34
    ITS ALIVE!
    This code works, remembers settings even after powerdown
    {{
    
    mem backup test
    2 buttons, 1 led
    button 1 increases blink speed
    button 2 increases blink amount
    
    }}
    
    
    CON
    
       Button1 = 21
       Button2 = 20
       LED = 26
    
    
    OBJ
       eeprom : "Eeprom"   
    
    VAR
    
      long stack[300]
      byte cog[2]
      long counter
      long speed
      long databackup
      long indicator
      long blank[0]  
    
    
    PUB Main
    
    
    eeprom.VarRestore(@counter, @blank - 1)        
    waitcnt(clkfreq / 2 + cnt)   
    
    if indicator < 1
      counter := 0
      speed := 0
      indicator := 0
      databackup := 0
          
    
    launch2cogs
    
    repeat
      if databackup := 1
          databackup := 0
          indicator := 1
          eeprom.VarBackup(@counter, @blank - 1)         ' restore variables if databackup = 1
          waitcnt(clkfreq / 5 + cnt)
    
    
    PUB Launch2cogs
    
    coginit(3, Buttons(@counter, @speed, @databackup), @stack[50])
    coginit(4, Blink(@counter, @speed), @stack[100])
    
    
    PUB Buttons(count, spd, dbackup) | tmp1, tmp2
    dira[button1]~
    dira[button2]~   
    
    
      tmp1 := long[count]
      tmp2 := long[spd]
    
    
    repeat
      if ina[button1] == 1
         tmp1 := ++tmp1 //5
         long[count] := tmp1
         long[dbackup] := 1
         
      if ina[button2] == 1
         tmp2 := ++tmp2 //5
         long[spd] := tmp2
         long[dbackup] := 1
      waitcnt(clkfreq /4 + cnt) 
    
    
    
    
    PUB Blink(count, spd) | tmp1, tmp2, tmp3
    dira[LED]~~
    outa[LED]~~
    tmp1 := 0                                                            ' temp counter variable
    tmp2 := 0                                                            ' temp speed variable
    tmp3 := 0
     
    
    repeat              
        tmp1 := long[count]
        tmp2 := long[spd]
        tmp3 := tmp2 * 2 + 2
        repeat (tmp1 + 1 * 2)
          !outa[LED]
          waitcnt(clkfreq / tmp3 + cnt)
          !outa[LED]
          waitcnt(clkfreq / tmp3 + cnt)
       waitcnt(clkfreq + cnt)
        
    
    



    For anyone else trying to use the eeprom for the first time... im using this object from Andy Lindsay, only the 'propeller eeprom.spin'.
    Thread - EEPROM Datalogging and I2C
    Object - EEPROM Datalogging and I2C
    This code can be used in a public sticky or added to the propeller eeprom docs.spin for first timers like myself.
    If this code came as an example with the object, I woulda been sooo happy!
  • kuronekokuroneko Posts: 3,623
    edited 2011-11-22 - 00:21:14
    JBWolf wrote: »
    ... and try working with single longs.
    Backing up a range of variables like you just introduced is perfectly OK. Two minor things, the end address is one too high (use @blank - 1) and you could define it as long blank[0] so it doesn't take up space.
  • JBWolfJBWolf Posts: 334
    edited 2011-11-22 - 00:33:11
    Ok I edited the previous code.
    The program still works :)

    How much of a delay should I have after a VarBackup or VarRestore command before using again?
    Thank you so much for helping me :)
Sign In or Register to comment.