Shop OBEX P1 Docs P2 Docs Learn Events
Saving to EEPROM — Parallax Forums

Saving to EEPROM

JomsJoms Posts: 279
edited 2010-03-24 13:35 in Propeller 1
OK, I have been trying to get this to work for awhile now, but don't think I have a complete understanding of how this is supposed to work. To get back to basics, I have been looking at some code that Terry @ Hitt Consulting wrote and it uses a I2C object that he wrote, but looks very similar to others.

I did search a few different topics with the search function, but did not come up with any concrete examples of how this works. So, if someone knows where to point me, that would be GREAT!...

So, to learn this, I modified these few parts of code that I can call on. Basically what I made is a public that when I write to the EEPROM it will take 1 serial input that is a 0-7 (memory slot), then 6 bytes to store a six digit number. Eventually I will try to do more then this, but this is just to help me get the understanding of how this works.

The EEPROM read part should just take the input of 0-7 for the memory slot and return the 6 bytes stored.

Can someone explain where I am going wrong? I am not exactly sure what the 'I2C.i2cWrite($A2 8) line does....if someone could explain what I am writing here?

PUB SaveToEEPROM | pos, addr, i

  pos:=Serial.GetChar                              'Set memory position  

  Repeat i from 0 to 5                             'Input 6 bytes of data
    tempStr[noparse][[/noparse]i][i] := Serial.GetChar                   'Store data to tempString
[/i]
[i][/i]

EDIT - ADDED Debug tempStr here for testing, and working properly to this point.[i][/i]

  addr:=32528 + (pos) * 16                         'Set address position
                                                   
  I2C.Init(28, 29, $A0)                            'Init I2C Object using EEPROM pins
  I2C.i2cStart                                     'Start the I2C Object 

  IF addr < 65536                                  
    I2C.i2cWrite($A0, 8)                           
  ELSE                                             
    I2C.i2cWrite($A2, 8)                           
      
  I2C.i2cWrite((addr / 256), 8) 
  I2C.i2cWrite((addr // 256), 8)
  
  REPEAT i FROM 0 TO 5
    I2C.i2cWrite(tempStr[noparse][[/noparse]i][i], 8)
    tempStr[noparse][[/noparse]i][i]:=tempStr[noparse][[/noparse]i][i] ^ 255
    IF (addr & $FF) == $FF
      I2C.i2cStop
      WAITCNT(400000 + cnt)                        'Wait 5mSec
      I2C.i2cStart
      IF (addr+1) < 65536
        I2C.i2cWrite($A0, 8)
      ELSE
        I2C.i2cWrite($A2, 8)  
      I2C.i2cWrite(((addr+1) / 256), 8)
      I2C.i2cWrite(((addr+1) // 256), 8)
    addr+=1
  I2C.i2cStop
  WAITCNT(400000 + cnt)                            'Wait 5mSec
  REPEAT i FROM 0 TO 5
    tempStr[noparse][[/noparse]i][i]:=tempStr[noparse][[/noparse]i][i] ^ 255

    

PUB LoadFromEEPROM(pos) | addr, i

  addr:=32528 + (pos) * 16                         'Set address position
                                                   
  I2C.Init(28, 29, $A0)                            'Init I2C Object using EEPROM pins
  I2C.i2cStart                                     'Start the I2C Object 

  IF addr < 65536
    I2C.i2cWrite($A0, 8)
  ELSE
    I2C.i2cWrite($A2, 8)  
  I2C.i2cWrite(addr / 256, 8)
  I2C.i2cWrite(addr // 256, 8)
  I2C.i2cStart
  I2C.i2cWrite($A1, 8)
  REPEAT i FROM 0 TO 5
    tempStr[noparse][[/noparse]i][i]:=I2C.i2cRead(0, 8)
  I2C.i2cStop
  
[/i][/i][/i][/i][/i][/i]

Post Edited (Joms) : 3/23/2010 7:36:25 PM GMT

Comments

  • JomsJoms Posts: 279
    edited 2010-03-23 16:47
    OK, Sorry for the long confusing post....but have some more questions. I dont think this is as hard as I am making it, but not working because I don't have a complete understanding of what is going on. So, this brings me to a few questions I am having problems figuring out.

    1. 32528 address space. This would be the same as 7F10 in hex, so, does that directly relate to the memory map on the RAM usage? My program only takes up 1450 longs, so I just went down the list a ways a picked something near the end and thats how I arrived at this number. I assume that 7FF0 (32752) would be the limit of 32K EEPROM. (I am using the prop demo board eeprom.) Is this a correct statement to make? Am I correct in saying it is only a few bytes from the limit, but should allow me to store around 30 bytes of data?

    2. Does that number directly correspond to a byte? Basically I could store a byte in 32528, another one in 32529, another one in 32530, and so on?

    3. Is there a basic guide on how to write to an EEProm? What I am wondering is a sheet the better describes in what order to write the data and in what format. Like first send a $A0, assuming this is an address for the IC memory, then byte address, then data, and so on. Does anything like this exist?

    Sorry for so many questions about this. It just seems like every time I try to write something to the EEPROM I am always pulling my hair out figuring out what is going on. I am looking to get a complete understanding and maybe put together a guide to make this easier for people to learn, as I cant seem to find anything about this...

    Thanks for the help in advance...
  • hairymnstrhairymnstr Posts: 107
    edited 2010-03-23 18:12
    Hi Joms,

    I've taken a look at your code and I'm not entirely sure what's wrong here, there are a lot of 'suspect' bits but without knowing what you're trying to do I can't say they're wrong.

    Some things to note:
    1. If you're using a 24LC256 (32KB) chip the data sheet is here www.microchip.com/wwwproducts/Devices.aspx?dDocName=en010823, this covers all the byte transitions etc. Google for 24LC512 if you're using a 64KB chip.

    2. Have you really got two 64KB i2c eeproms in your circuit?

    3. I think you may be right about the top of RAM being at 32752 (top 4 longs are locks??) since 2^15 = 32KB = 32768 bytes. But the top of RAM in prop is used for the spin stack so even if you are loading the image from eeprom to these locations, chances are the stack will have overwritten it by the time you've got to reading it.

    4. Did you try the read/write location functions in the example object you posted.

    (Just in case, I doubt this is the problem: 5. Finally, there's no chance the eeprom is write protected? Probably not if you're booting from it as you would then not be able to program it.)

    EDIT:

    I don't think you need to call the Init subroutine twice, you should do that in your main spin start pub and not in each of the read/write ones.
  • JomsJoms Posts: 279
    edited 2010-03-23 19:27
    Thanks for the reply!

    Basically what I am trying to do is just get this little program working before implementing it into my other program. All I am trying to do is store like 6-8 different bytes to the eeprom then read them after a power cycle. I can attach the entire code, but there really isn't much more then the two publics that I already posted. Basically I am just calling to save a byte with the write public, then reading it and debugging it with the read public. I do have a 1 second delay between write/read, but all I receive is a 'zero' in return when I attempt to read.

    1. I have been looking at a sheet very close to that, just not completely sure I understand it. From what I am gathering, the $A0 is the Control Byte, then the two address bytes, then the data byte. I am using the 32kb ic that is on the prop demo board.

    2. Nope, just one 32k eeprom, the one that is already on the prop demo board. Since I only need to store 8 bytes of data, I figured I could find a little extra room on there to store the data.

    3. I know I am about to ask this without reading the prop manual, but I will pull that out right after I post this and update you if I find any new info. I am hoping to find a memory map of what is free in the 32k memory for general use.

    4. I did try that read/write with the example I have posted. I also have been playing around with different addresses with no luck. Actually I picked address 1 knowing it would over-write part of my program, but just thought I would give it a try.

    5. I don't think the EEProm is write protected as I am loading it with F11 from the prop tool. I assume there is a pin that sets that, but again, I will check the data sheet for that.

    Im not good at explaining things with few words, lol, but hopefully you understand what Im trying to do...
  • JomsJoms Posts: 279
    edited 2010-03-23 19:49
    OK, I think I got it... This is about as bad as forgeting to put the frequency at the top of the program, but I will explain what I did so others can learn. I have pulled my hair out with this one, but...

    When I am inputing the serial data, it will input as a charactor, not a decimal like I should have been inputing. Basically where I screwed up, is I needed to put ' - "0" ' behind any input to convert it to a decimal.

    This has caught me many times before, but I completely overlooked the simple problems in this oops. Guess I can overcomplicate anything...lol

    So, that leaves me with this question...

    Where is the best place on the included 32k EEPROM to store a few bits of data where it won't get over-written or in the way of other programming? I am assuming the highest available spot right below stack? If so, where is that?
  • hairymnstrhairymnstr Posts: 107
    edited 2010-03-23 20:19
    Excellent, glad you've found the problem, easy mistakes are hard to spot.

    If you're only using one 32K eeprom you shouldn't need the IF addr < 65536 statements, only the first will ever be true, the else statement writing $A2 is addressing a second EEPROM chip on the i2c bus, it won't really hurt if you never let addr be bigger than 32767 but it will slow your code down a bit.

    I believe if you declare a variable in spin, then the hub address of that variable can be used as an address for accessing the eeprom. The content of that location will be loaded to that part of HUB at boot as there is a one-to-one relationship between bytes in the EEPROM and HUB.

    So if you want to save 8 bytes, declare a variable in your vars section as byte something[noparse][[/noparse]8], then find the address with the @ operator. So;

    VAR
      byte a
      byte b
      byte c
    
    PUB start
      a := 5
      write_eeprom(@a, a)
    
    PUB write_eeprom(addr, data)
      ' do the setup stuff
      i2c.Start()
      i2c.write($A0, 8)
      i2c.write(addr/256)
      i2c.write(addr//256)
      i2c.write(data)
      i2c.stop()
    
    



    So you are effectively initialising a for the next boot of the chip. Of course you can always read it back by passing the address of a to the read function.

    Note, I've been really bad here and posted untested code, absolutely no guarantee this will work at all, I don't have a prop handy to test it right now.
  • hairymnstrhairymnstr Posts: 107
    edited 2010-03-23 20:37
    Okay, so I did have a propeller around, just found by old proto-board and it even had a TV connector and everything. Here's a demo I did with the i2c code you posted earlier.

    CON
    
            _clkmode        = xtal1 + pll16x
            _xinfreq        = 5_000_000
    
    OBJ
    
            term    : "tv_text_pal"
            i2c     : "HITT_BOOT_EEPROM_010"
    
    VAR
    
      byte  incb
      byte  decb
      
    PUB start
    
      'start the tv terminal
      term.start(12)
      term.str(string("i2c experiments",13))
    
      term.str(string("incb is "))
      term.dec(incb)
      term.str(string(13,"decb is "))
      term.dec(decb)
    
      term.str(string(13,"updating eeprom",13))
    
      incb += 1
      decb -= 1
    
      i2c.Init(28,29,$A0)
    
      i2c.WriteLocation(@incb,incb)
      i2c.WriteLocation(@decb,decb)
    
      term.str(string("Done, now reboot and see what they are.", 13))     
    
    



    So every time you reset the propeller, or turn off and on again the value of incb will increment and decb will decrement. Note, because you're using a memory address in the 32K map they are loaded automatically at boot time, no need to read them back manually.

    Hope this helps.

    P.S. you'll probably need to change the tv object name, it's the standard tv_text object from Parallax, but I live in the UK so switched it to PAL and renamed it.
  • JomsJoms Posts: 279
    edited 2010-03-24 05:57
    WOW! I have never really understood it was this easy, but think I have a complete grasp on it now. I can not thank you enough for taking the time to go thru and make this working explanation for me. [noparse]:)[/noparse]

    I didn't really understand the writelocation fuction until I seen how you were using it.

    Thanks again and I hope someone else can also learn from this example too. I was WAY over complicating writing to the EEProm...
  • MagIO2MagIO2 Posts: 2,243
    edited 2010-03-24 13:35
    One more thing about the fuctionality of EEPROM .. as far as I know EEPROMs are organized in pages. This means whenever you write to it, it will erase a complete page and then write it back with the changed data. What I expect in your case now (when using WriteLocation)·is, that the same page will be erased several times, as you don't write continuously then. Each WriteLocation will start a new write cycle. This will wear out the EEPROM much faster.

    So, if you have continuous data to write you should write pages or at least all bytes in a row (like in the first post) without starting a new write cycle.
    I think the problem in the first post is that paging is done with a wrong page-size.
    "if adr & $ff" is for detecting the page wrap. But this only works if the page is really 256 bytes in size. I'd expect something like 32 or 64 bytes. What the page-size of your EEPROM is can be found in the datasheet of the EEPROM you use.

    You could have a look at femtoBASIC. This includes a SimpleI2C object and has some code which writes pages.

    Post Edited (MagIO2) : 3/24/2010 1:45:05 PM GMT
Sign In or Register to comment.