Shop OBEX P1 Docs P2 Docs Learn Events
How to write to upper 32K of a AT24C512 eeprom?? — Parallax Forums

How to write to upper 32K of a AT24C512 eeprom??

radialrandyradialrandy Posts: 78
edited 2012-01-08 12:23 in Propeller 1
I'm trying to find the simplest way to write data to addresses in the upper 32K of the 62K eeprom. Cant I not directly write to the upper addresses because they are not part of main memory. FYI I really only know how to write in Spin. What I'm trying to do is datalog word sized data back to back in the memory and later read that data in word size. So lets say I want to start saveing word sized data at address $8000 and the next word at $8002 then next at $8004 and so on.
thanks
Randy
«1

Comments

  • PublisonPublison Posts: 12,366
    edited 2012-01-07 09:33
    Randy,

    Look at the bottom of the post for "Similar Threads". Should be what you need.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-01-07 09:46
    Randy,

    Use:
    Eeprom.FromRam(@myWord, @myWord + 1, eepromAddress)
    

    To write a word sized variable to EEPROM. Use addresses $8000 or more (up to $FFFF) for upper EEPROM.

    Use the ToRam method to take a value from EEPROM.

    There is an EEPROM datalogging link in the PEK sticky.

    Let me know if you need any clarification.
  • Mike GreenMike Green Posts: 23,101
    edited 2012-01-07 09:47
    Use the "Basic_I2C_Driver" object from the Propeller Object Exchange. This will let you write (and read) any location(s) in one or more EEPROMs attached to a Propeller. Look at the comments at the beginning of the Spin file as well as the comments for each method.
  • radialrandyradialrandy Posts: 78
    edited 2012-01-07 09:58
    Mike Green wrote: »
    Use the "Basic_I2C_Driver" object from the Propeller Object Exchange. This will let you write (and read) any location(s) in one or more EEPROMs attached to a Propeller. Look at the comments at the beginning of the Spin file as well as the comments for each method.

    I've looked at the Basic_I2C_Driver but I'm confused on how to use it. Is there any demo example on how to use it?
    Thanks
    Randy
  • Mike GreenMike Green Posts: 23,101
    edited 2012-01-07 10:11
    The ReadIt and WriteIt examples in the comments at the beginning are pretty straightforward, but you can use some of the other methods as well.

    To write a word $1234 to location $8004/5 if you declare the object as I2C:

    I2C.WriteWord( I2C#BootPin, I2C#EEPROM, $8004, $1234)
    repeat while I2C.WriteWait( I2C#BootPin, I2C#EEPROM, $8004)

    To read a word from location $8004/5:

    theWordValue := I2C.ReadWord( I2C#BootPin, I2C#EEPROM, $8004)

    Remember that the parameters to these methods (like $8004 and $1234) can be any expression, not just the constants shown.

    The "repeat while" loop will hang if there's no EEPROM at the specified address. See the WriteIt example in the object's comments for
    additional code that implements a timeout for this.
  • radialrandyradialrandy Posts: 78
    edited 2012-01-07 10:29
    Mike Green wrote: »
    The ReadIt and WriteIt examples in the comments at the beginning are pretty straightforward, but you can use some of the other methods as well.

    To write a word $1234 to location $8004/5 if you declare the object as I2C:

    I2C.WriteWord( I2C#BootPin, I2C#EEPROM, $8004, $1234)
    repeat while I2C.WriteWait( I2C#BootPin, I2C#EEPROM, $8004)

    To read a word from location $8004/5:

    theWordValue := I2C.ReadWord( I2C#BootPin, I2C#EEPROM, $8004)

    Remember that the parameters to these methods (like $8004 and $1234) can be any expression, not just the constants shown.

    The "repeat while" loop will hang if there's no EEPROM at the specified address. See the WriteIt example in the object's comments for
    additional code that implements a timeout for this.

    Would I write it like below? And what would go in devSel ?

    OBJ

    i2c : "Basic_I2C_Driver.spin"

    Main
    i2c.WriteWord(28, devSel, $8000, 1234)
    i2c.WriteWait(28, devSel, addrReg)
  • radialrandyradialrandy Posts: 78
    edited 2012-01-07 10:36
    does any of this have to be used?
    PUB Initialize(SCL) | SDA              ' An I2C device may be left in an
       SDA := SCL + 1                      '  invalid state and may need to be
       outa[SCL] := 1                       '   reinitialized.  Drive SCL high.
       dira[SCL] := 1
       dira[SDA] := 0                       ' Set SDA as input
       repeat 9
          outa[SCL] := 0                    ' Put out up to 9 clock pulses
          outa[SCL] := 1
          if ina[SDA]                      ' Repeat if SDA not driven high
             quit                          '  by the EEPROM
    
    PUB Start(SCL) | SDA                   ' SDA goes HIGH to LOW with SCL HIGH
       SDA := SCL + 1
       outa[SCL]~~                         ' Initially drive SCL HIGH
       dira[SCL]~~
       outa[SDA]~~                         ' Initially drive SDA HIGH
       dira[SDA]~~
       outa[SDA]~                          ' Now drive SDA LOW
       outa[SCL]~                          ' Leave SCL LOW
      
    PUB Stop(SCL) | SDA                    ' SDA goes LOW to HIGH with SCL High
       SDA := SCL + 1
       outa[SCL]~~                         ' Drive SCL HIGH
       outa[SDA]~~                         '  then SDA HIGH
       dira[SCL]~                          ' Now let them float
       dira[SDA]~                          ' If pullups present, they'll stay HIGH
    
  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-01-07 10:43
    I was just reading Mike's driver. I think I know this one.

    devSel is device select.

    He has:
    EEPROM   = $A0                      ' I2C EEPROM Device Address
    

    Up in the constant section.

    So you'd use "I2C#EEPROM" as your devSel parameter. Assuming you called the I2C object "I2C".

    The "#" lets you use constants in a child object.

    I hope Mike and Randy don't mind my interuption. I'm just excited to know the answer to this one.
  • radialrandyradialrandy Posts: 78
    edited 2012-01-07 10:49
    Duane Degn wrote: »
    I was just reading Mike's driver. I think I know this one.

    devSel is device select.

    He has:
    EEPROM   = $A0                      ' I2C EEPROM Device Address
    

    Up in the constant section.

    So you'd use "I2C#EEPROM" as your devSel parameter. Assuming you called the I2C object "I2C".

    The "#" lets you use constants in a child object.

    I hope Mike and Randy don't mind my interuption. I'm just excited to know the answer to this one.

    Where does $A0 come from?
  • jazzedjazzed Posts: 11,803
    edited 2012-01-07 11:00
    Practically speaking value $A0 is the device select code identifier given to EEPROM devices by Phillips.
    The least significant bit may be 1 or 0 in some I2C transactions: $A0 or $A1.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-01-07 11:03
    I believe it's the asigned address found in the datasheet. I think the the adress pins on the chip are also part of this number (or can modify the number).

    You can have multiple I2C devices on one I2C bus. The protocol uses addresses in order to identify the device you want to communicate with. You can have multiple EEPROMs on the same bus if you tie an address pin high (on the second EEPROM chip) in order to asign it a different address.

    Some 1024K chips use a different address to select a different portion of the EEPROM. With these chips one of the normal address pins is "not connected" internally. I believe the "not connected" pin can varry depending on the brand of EEPROM so you want to make sure and read the datasheet.

    I believe the "1" or "0" jazzed just mentioned are added by the driver so you don't need to worry about that part.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-01-07 11:14
    does any of this have to be used?

    Randy,

    I was just reading a bit more of Mike's driver. He explains about adressing in different EEPROM chips in the comments. I also noticed this in the comments:
    '' Initialize may have to be called once at the beginning of your
    '' program.  Sometimes an I2C device is left in an invalid state.  This
    '' will reset the device to a known state so it will respond to the I2C
    '' start transition (sent out by the i2cStart routine).
    

    So it looks like you normally wouldn't need to use the Initialize method.

    My guess is the Start method should be use. I doubt it would hurt anything to use it.

    I think the Stop method is used by other methods and I don't think you need to use it directly.

    If you're using other I2C drivers in the the same project you'll want to set all the pins used to inputs and set them to their "low" state so other cogs can use the pins. (I had this problem once when using a different driver to read a real time clock.)

    Edit: I hope Mike (or others) will correct me if I am incorrect about any of this.
  • radialrandyradialrandy Posts: 78
    edited 2012-01-07 12:11
    PUB Curve|time1,ticks
      
      repeat
        waitpne(|<tb,|<tb,0)      'buttom pressed
        waitcnt(800000+cnt)
        waitpeq(|<tb,|<tb,0)      'button released
        ticks := 0
        time1:=cnt
        repeat 500                'every 1/100 of a second i want it to write the varible liverpm to an address starting with $8000
                                  'and use ticks to store at the next word sized space afte $8000 and so on.                          
            i2c.WriteWord(28, 0, ($8000+ticks), liverpm)
            i2c.WriteWait(28, 0, ($8000+ticks))     
            waitcnt(time1+=800_000)
            ticks+=2
    
       ticks :=0
       FD.start(31, 30, 0, 250000)
       FD.tx(FD#CLS)
       repeat 500                    'im trying to use this just to see if it stored the data 
          waitcnt(clkfreq/100 +cnt)
          FD.str(String(13,"rpm= "))
          FD.dec(I2C.ReadWord(28, 0, ($8000+ticks)))
          ticks+=2
    


    Any Idea why this is not working?
    thanks
  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-01-07 13:15
    Why are you using zero as the device select value?

    i2c.WriteWord(28, [COLOR=#ff0000]0[/COLOR], ($8000+ticks), liverpm)
            i2c.WriteWait(28, [COLOR=#ff0000]0[/COLOR], ($8000+ticks))
    

    I'd think you'd want to follow Mike's examples and only change the EEPROM address and the value to write to the address.
  • radialrandyradialrandy Posts: 78
    edited 2012-01-07 13:29
    PUB Curve|time1,ticks
      
      repeat
        waitpne(|<tb,|<tb,0)      'buttom pressed
        waitcnt(800000+cnt)
        waitpeq(|<tb,|<tb,0)      'button released
        ticks := 0
        time1:=cnt
        repeat 500                'every 1/100 of a second i want it to write the varible liverpm to an address starting with $8000
                                  'and use ticks to store at the next word sized space afte $8000 and so on.                          
            i2c.WriteWord( i2c#BootPin, i2c#EEPROM, ($8000+ticks), liverpm)
            repeat while i2c.WriteWait( i2c#BootPin, i2c#EEPROM, ($8000+ticks))
            waitcnt(time1+=800_000)
            ticks+=2
    
       ticks :=0
       FD.start(31, 30, 0, 250000)
       FD.tx(FD#CLS)
       repeat 500                    'im trying to use this just to see if it stored the data 
          waitcnt(clkfreq/100 +cnt)
          FD.str(String(13,"rpm= "))
          FD.dec(i2c.ReadWord(i2c#BootPin, i2c#EEPROM, ($8000+ticks)))
          ticks+=2
    


    tried this and still no worky!
  • Mike GreenMike Green Posts: 23,101
    edited 2012-01-07 13:29
    I wrote those examples the way I did for a reason. When someone gives you examples, you really should start with them and begin to improvise once you have them working and understand what the various pieces do.

    The first parameter has to be the pin number of the first of two I/O pins as described in the comments in the object. The constant "BootPin" is there to simplify things when you're using the Propeller's boot EEPROM.

    The second parameter has to be the device's select code which is $A0 for most EEPROMs. The constant "EEPROM" is there to simplify things when you're using a common serial EEPROM.

    The Start and Stop routines are PUB methods instead of PRI because they might be useful for someone using a non-EEPROM device. They're otherwise used internally. The Initialize routine is there for the reasons described in the comments.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-01-07 13:47
    tried this and still no worky!

    Does your code output anything? If so what?

    For testing make your write delay longer and add a debug line to see what values are being written to the EEPROM.
  • radialrandyradialrandy Posts: 78
    edited 2012-01-07 13:59
    PUB Curve|time1,ticks
      
      repeat
        waitpne(|<tb,|<tb,0)      'buttom pressed
        waitcnt(800000+cnt)
        waitpeq(|<tb,|<tb,0)      'button released
        test1:=0
        FD.start(31, 30, 0, 250000)
        FD.tx(FD#CLS)
        i2c.WriteWord(i2c#BootPin, i2c#EEPROM, $8100, 100)
        repeat while i2c.WriteWait(i2c#BootPin, i2c#EEPROM, $8100)
        test1 := i2c.ReadWord(i2c#BootPin, i2c#EEPROM, $8100)
            
        FD.str(String(13,"rpm= "))
        FD.dec(test1)
    

    I simplified this to where all it does is save 100 to address $8100 then reads it to the terminal.
    It does nothing. actually the program stops at the "repeat while" line. If I remove just the repeat while and leave the rest I do get a reading on the terminal .it outputs 65535.
    Mike thanks for helping but I am trying. I'm just missing something.
    Can the A0 for the eeprom address not be right for some reason. Cause the program hangs up on the repeat loop. A0,A1,A2 on the eeprom chip are grounded.
  • radialrandyradialrandy Posts: 78
    edited 2012-01-07 20:07
    REALLY REALLY REALLY Need some help on this. I've only spent about 8 hours today trying to get anything to work. Please look at the code in my last post and help me understand why it wont work. im using the 64K eeprom that also the boot eeprom. The code above seems so simple but I cant get it to work. I even striped it down the just the

    test1 := i2c.ReadWord(i2c#BootPin, i2c#EEPROM, $8100)
    FD.str(String(13,"rpm= "))
    FD.dec(test1)

    and changed the $8100 to other address just to see if I could read anything. All I ever get is 65535 on the terminal. I dont know anything else to try. I just want to write and read data to addresses.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-01-07 20:26
    Randy,

    Sorry but I use the object Propeller Eeprom (I think that's what it's called) when I store stuff to EEPROM. The Propeller Education Kit sticky on the main Propeller forum page has a link to an EEPROM data logging lab. That's the code I used when I was first learning to use the Propeller. It worked so I haven't bothered to learn how to write to the EEPROM a different way.

    The line of code I wrote in post #3 will write a word to EEPROM.

    The @myWord part assumes you have a word variable declared named "myWord". The eepromAddress would be a value such as $8100.
  • radialrandyradialrandy Posts: 78
    edited 2012-01-07 20:54
    Duane Degn wrote: »
    Randy,

    Sorry but I use the object Propeller Eeprom (I think that's what it's called) when I store stuff to EEPROM. The Propeller Education Kit sticky on the main Propeller forum page has a link to an EEPROM data logging lab. That's the code I used when I was first learning to use the Propeller. It worked so I haven't bothered to learn how to write to the EEPROM a different way.

    The line of code I wrote in post #3 will write a word to EEPROM.

    The @myWord part assumes you have a word variable declared named "myWord". The eepromAddress would be a value such as $8100.

    I actually use that object for some of my data saves. But I have not got it to work to save to specific addresses in the upper 32K of the 64K eeprom.
    Works good for saving named varibles.
  • Mike GreenMike Green Posts: 23,101
    edited 2012-01-07 21:38
    The 65535 suggests that ReadWord is returning a -1 which indicates that it can't read the EEPROM. Are you sure you have an AT24C512 EEPROM or another type of 64K EEPROM? How about trying an address in the first 32K like $7FFE? That's not likely to be used by anything although it will get cleared when you download a new program to the EEPROM. What kind of board are you using?
  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-01-08 06:01
    Randy,

    The attached program will tell you if your EEPROM is 32K or 64K.

    When I run the program on my Demo board(which has 32K EEPROM) I get this.
      fileName = dwd_AssignId
     This program allows one to write an ID number to EEPROM
     Making sure EEPROM is at least 64K.
     Reading from EEPROM address $7FFF
     lastLowByte = $00
     Reading from EEPROM address $FFFF
     lastHighByte = $00
     Writing 1 to EEPROM address $FFFF
     Reading from EEPROM address $7FFF
     lastLowByte = $01
     This EEPROM is only 32K.
     You will not be able to store data in
     the upper section of EEPROM.
     Restoring original EEPROM value.
     **** End of Program ****
    

    When I run it on a board with 64K or EEPROM I get this output.
    fileName = dwd_AssignId
     This program allows one to write an ID number to EEPROM
     Making sure EEPROM is at least 64K.
     Reading from EEPROM address $7FFF
     lastLowByte = $00
     Reading from EEPROM address $FFFF
     lastHighByte = $FF
     Reading 16 bytes from EEPROM address $FFF0
     EEPROM $FFF0: $FF $FF $FF $FF $FF $FF $FF $FF $FF $FF $FF $FF $00 $FF $FF $FF
     These are the EEPROM options:
     Enter a single character to select menu option.
     x) Exit Program
     g) assign global ID (each Propeller should be different)
     s) assign system ID
     r) read a section of EEPROM
     f) fill each byte in a section of EEPROM with a single value
     l) change arbitrary address location
    

    The program uses a baud of 57,600. It gives you three seconds to open a terminal window before it starts sending information to the terminal window. You can either load into RAM(F10) or EEPROM(F11). (Of course if you load it to RAM, it will only run once.)

    This should let you know if your EEPROM is 32K or 64K.
  • radialrandyradialrandy Posts: 78
    edited 2012-01-08 09:36
    OBJ             
    
      LCD       : "Brilldea-LM9033A Driver-Ver002.spin"         
      Gr        : "graphics.spin"                              
      eeprom    : "Propeller Eeprom"
      FD        : "FullDuplexSerialPlus.spin"
      stringObj : "ASCII0_STREngine_1.spin"
      filter    : "filter_ma.spin"
      i2c       : "Basic_I2C_Driver.spin"
    
      '*************************************
    PUB main
      
      dira[tbout]~~
      outa[tbout]~
      save:=0
      'eeprom.VarRestore(@setpoint, @control[1500])           '<<<<<<<<<<<<<<<<THIS IS THE PROBLEM.
      coginit(1,buttons,@stack[0])
      coginit(2,delaytimer,@stack[50])
      coginit(3,curve,@stack[300])
      LCD.start(_LCD_cs, _LCD_rst, _LCD_rs, _LCD_sc, _LCD_sd, _LCD_bl)
      gr.start
      gr.setup(_xtiles, _ytiles, 0, 0, @VIDEOmemory)
      LCD.reset
      LCD.initialize(0, @LCDmemory)
    


    I found the problem. I'm using the propellor eeprom object and the i2c object in my program. and when this runs "eeprom.VarRestore(@setpoint, @control[1500])" then the i2c stuff does not work. Can I not have 2 different eeprom controlling objects in my program? Any input on why it does not work? When I remove the line "eeprom.VarRestore(@setpoint, @control[1500])" I can read and write with the i2c perfectly.
  • Mike GMike G Posts: 2,702
    edited 2012-01-08 10:17
    Can I not have 2 different eeprom controlling objects in my program? Any input on why it does not work?
    Why use two different I2C objects on the same bus? Anyway the I2C drivers can drive the IO pins. One of the drivers might be leaving an IO pin in a state that the other does not like. I'm not sure how Propeller Eeprom works but you have the source so take a look or post all your code.
  • radialrandyradialrandy Posts: 78
    edited 2012-01-08 10:24
    Mike G wrote: »
    Why use two different I2C objects on the same bus? Anyway the I2C drivers can drive the IO pins. I'm not sure how Propeller Eeprom works but you have the source so take a look.
    I was using propellor eeprom to backup some of my spin named variables which get reset when power is cycled. And when power is turned back on i use the VarRestore to copy them back into the variables. propellor eeprom is easy to use for this purpose but the Basic_I2C_Driver.spin works better for save data to the upper 32k.
  • Mike GreenMike Green Posts: 23,101
    edited 2012-01-08 10:27
    You can't use two objects at the same time to control the same I/O pins unless they're written in such a way as to allow this. Most objects initialize the I/O pins to some particular state and assume that they'll still be in that state the next time the object is called. If another object is called in-between, neither may work properly. This is also true if the two objects are used by two separate cogs. Each cog has its own set of I/O registers (DIRx, OUTx, INx) and they can interact. You can write objects so they "play nice" together, but that can be difficult and complicate things.

    You can also use Basic_I2C_Driver to do the same sort of thing as VarRestore. Just write the data (valueToSave) to the corresponding location for the variable (globalVariable) in EEPROM like:

    I2C.WriteWord( I2C#BootPin, I2C#EEPROM, @globalVariable, valueToSave)
    repeat while I2C.WriteWait( I2C#BootPin, I2C#EEPROM, @globalVariable)

    When the program restarts, globalVariable will be initialized to the value valueToSave. Obviously, use WriteByte or WriteLong if that's appropriate for the variable.
  • radialrandyradialrandy Posts: 78
    edited 2012-01-08 10:28
    once my program uses VarBackup or VarRestore from the propellor eeprom object then none of the Basic_I2C_Driver works. I'm wondering is something in the proprllor eeprom object disables something. I'd like to keep both og them working cause there great for the things I use them for . If not possible I will have to spend alot of time changing my program.
  • radialrandyradialrandy Posts: 78
    edited 2012-01-08 10:29
    I see what our saying. I guess I'll have to change up my program to use the Basic_I2C_Driver.spin only.
    thanks
  • Mike GreenMike Green Posts: 23,101
    edited 2012-01-08 10:36
    You could also try calling I2C.Initialize( I2C#BootPin ) after calling VarBackup or VarRestore and before calling one of the other I2C routines. This will reinitialize the I/O pins and the EEPROM to a known state.
Sign In or Register to comment.