Shop OBEX P1 Docs P2 Docs Learn Events
EEPROM - SX/B Example (I2C) - modified & question — Parallax Forums

EEPROM - SX/B Example (I2C) - modified & question

John KauffmanJohn Kauffman Posts: 653
edited 2007-08-05 16:57 in General Discussion
EEPROM - SX/B Example (I2C) - modified & question

I’m starting with 24LC EEPROM and using the SX/B Help I2C example.
·
To demonstrate success, the help example uses a Watch in Debug mode.
I’d like to demonstrate a successful read/write outside of debug.
·
Here is how I want program to behave:
  1. Hardcode a byte value into the program
  2. Then run code to behave as follows:
  3. display the byte value in binary form on 8 LEDS for one second
  4. turn off LEDs for one second
  5. save that byte to EEPROM
  6. read the byte back from EEPROM
  7. Turn on a LED that flags “value read out”
  8. Display the byte in binary form on the 8 LEDs
·
I’ve built hardware as described in Help I2C example, with two additions:
8 LEDS connected to RB
One LED to designate display has been read: RC.0 named LedRead
·
I have modified the help example as attached, mainly:
··········Added PIN, CON for value to save, variables
Added a short sub to test the LEDs
Deleted FOR…NEXT that created, saved and read random values
Substituted saving the one hard-coded byte and read it back
Set retrieved value to the RB register.
I have not change any of the subs that deal with I2C or MEM_IN and MEM_OUT.
·
Results:
Test display of LEDs works
Display of byte value that was hard-coded works
But then nothing happens.
·
As I analyze the help example, I have a question.
The subroutine named MEM_OUT is listed in Sub declarations as expecting three parameters. But when the sub is called (following line) it seems only two parameters are sent.
Why?
·
' Subroutine Declarations
'

MEM_OUT········ SUB···· 3······················ ' write value to memory

...···'later in code:
MEM_OUT addr, outVal
·
Thanks.

Comments

  • BeanBean Posts: 8,129
    edited 2007-08-02 12:08
    You have the line "MEM_OUT addr, outVal", but you haven't set outVal to anything.
    Put "outVal = ValueToStore" just before "MEM_OUT addr, outVal"

    "MEM_OUT SUB 3" means that three BYTES will be send, in this case it is a WORD for the address and a BYTE for the value.

    Bean.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Teacher: What is the difference between ignorance and apathy ?
    Student: I don't know and I don't care
    Teacher: Correct !
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    www.hittconsulting.com


    Post Edited (Bean (Hitt Consulting)) : 8/2/2007 12:15:10 PM GMT
  • John KauffmanJohn Kauffman Posts: 653
    edited 2007-08-02 12:20
    Help uses the term "parameters" which sounded to me like arguements, or seperate values. But for bytes it makes sense.
  • John KauffmanJohn Kauffman Posts: 653
    edited 2007-08-02 12:22
    I tried following two alternate lines and program still will not display after read (and no display of Read LED flag)


    original:
    MEM_OUT addr, outVal ' send to 24LC16

    Alternates:
    MEM_OUT addr, ValueToStore ' send to 24LC16
    MEM_OUT addr, %00001111 ' send to 24LC16
  • JonnyMacJonnyMac Posts: 9,216
    edited 2007-08-02 13:32
    John,

    You seem to be writing to the EEPROM and then attempting to immediately read back. The EEPROM is probably busy while you're attempting to read back so you're not getting the correct value. You can either insert a PAUSE after the MEM_OUT line, or update the MEM_OUT subroutine so that it doesn't return to the program until the write cycle is complete.
  • JonnyMacJonnyMac Posts: 9,216
    edited 2007-08-02 14:32
    I found a 24LC16B in my stash and updated the program from the help file so that MEM_OUT does not return until the write-cycle is complete. Here's the update:

    ' Use: MEM_OUT address, value
    ' -- writes 'value' to 24LC16B location at 'address'
    ' -- "address" is a word (two bytes required)
    ' -- "value" is a byte
    
    MEM_OUT:
      tmpW1 = __WPARAM12                            ' copy address
      tmpB1 = __PARAM3                              ' copy value
    
      I2CSTART SDA
      tmpW1_MSB = tmpW1_MSB & $03                   ' get block value
      tmpW1_MSB = tmpW1_MSB << 1
      tmpW1_MSB = tmpW1_MSB | SlaveID               ' create control byte
      tmpW1_MSB.0 = 0                               ' set RW bit for write
      I2CSEND SDA, tmpW1_MSB                        ' send slave ID
      I2CSEND SDA, tmpW1_LSB                        ' send word address
      I2CSEND SDA, tmpB1                            ' send data byte
      I2CSTOP SDA                                   ' finish
      DO                                            ' let write cycle finish
        I2CSTART SDA
        I2CSEND SDA, tmpW1_MSB, ackBit              ' resend slave ID
      LOOP UNTIL ackBit = Ack
      RETURN
    



    Note that you have to define a bit variable, ackBit, for the update.

    You could use conditional compilation to disable the write-delay, and if you're going to be using I2C is a large application its a good idea to encapsulate the core I2C commands in custom subroutines and functions; I2C has a timing element to is and, therefore, generates a bit of code.
  • JonnyMacJonnyMac Posts: 9,216
    edited 2007-08-02 14:51
    I've attached an updated version of the help file program that encapsulates all SX/B I2C instructions so that they only get compiled once (saves code space) and added a conditional switch to disable the write-cycle delay.
  • John KauffmanJohn Kauffman Posts: 653
    edited 2007-08-02 15:05
    Adding delay between write and read sounded good:
    ···· I replaced code as posted (and added bit VAR named ackbit)
    ···· For good measure, added a Rip van Winkle-sized pause between write & read.
    New version (-02) attached.

    Still same result: initial display of value works, then nothing.

    I tried another address $0A0A in case %0000 was reserved - no change.

    What really has me stymied is that the LedReadFlag does not even come on. It seems that the read part of the code is never executed.

    I don't have a second 24LC32A to swap for IC check.·Can I try swapping in 24LC256?

    Basics:
    Independent check of LedReadFlag circuit·is OK.
    EEPROM Pins 1-3 (A0-A2) and pin 7 (WP) are grounded, like in SX/B Help Example wiring diagram.
    EEPROM pins 5 & 6 have pull-ups (1k instead of 4.7 k of diagram).
    I'm using a Murata 400 resonator. I program, then remove the key, then reset to test.
  • Dave HeinDave Hein Posts: 6,347
    edited 2007-08-02 15:35
    I normally use assembly, and I have forgotten some of the SXB syntax. I noticed that you jump back to the Main entry point with a "GoSub Main". Shouldn't this be "GoTo Main"? A gosub will generate a call, which will add the return address to the stack. The stack would eventually overflow.

    Dave
  • John KauffmanJohn Kauffman Posts: 653
    edited 2007-08-02 15:43
    Thanks Dave. I Revised:

    GoSub Main

    to

    GoTo Main


    No change in behavior.
  • JonnyMacJonnyMac Posts: 9,216
    edited 2007-08-02 15:52
    You're displaying ValueToStore on the LEDs but then writing outVal to the EEPROM -- without copying ValueToStore to it. I built up your demo on my PDB and am running the attached program; it works as I think you want it to, though I removed some of the delays. What you'll see is a value on RB that doesn't change when the ReadLED on RC.0 lights.

    Post Edited (JonnyMac) : 8/2/2007 4:00:00 PM GMT
  • Dave HeinDave Hein Posts: 6,347
    edited 2007-08-02 16:33
    John,

    It's not clear which device you started with in your initial post. It looks like you may have started with a 24LC32 and then switched to 24LC16. The addressing on these two devices is different. The 24LC16 requires a device address followed by a single memory address byte. The device address includes the 3 most significant memory address bits. Your code suports this format.

    The 24LC32 and larger devices requires an extra address byte. You would need to send the device address, followed by the MSB and LSB memory address bits. In this case, the 3 address bits in the device address are actually chip select bits. They need to match the way the pins are wired on the chip. For a single chip this is normally all zeros.

    Dave
  • John KauffmanJohn Kauffman Posts: 653
    edited 2007-08-02 16:57
    Jon:

    I studied your version. I expected:
    The 8 LEDs show the value one for half second, then LEDReadFLag comes on while 8 LED still displays 1 (because it read one from EEPROM) for another half second.
    Then pause 1.5 seconds
    Then repeat for two, etc., changing about every 2.5 seconds up to 255

    On several tries no luck, it shows one LED continiously. LedReadFlag is not coming on at all.
    It is late here, I am going to recheck all hardware in morning and test section by section.

    My first instinct to troubleshooting is to break down the parts and test each. I have not come up with a more basic code to test the EEPROM. LEDs can be reduced down to a simple HIGH LOW. For the EEPROM all the parts have to work immediately (addressing, timing, read, write, etc.) If anyone can think of a way to divide out those functions I could break down the troubleshooting.

    Also tomorrow I will try Jon's code with just one read and write rather than a loop.

    Two question for testing tomorrow:
    Will same code work with 24LC256? I want to test by swap out the EEPROM & don't have another '32 .
    Can I use internal 4Mhz or must stick with 4 Mhz Murata?

    Thanks.
  • JonnyMacJonnyMac Posts: 9,216
    edited 2007-08-02 17:46
    Do check your hardware, John; I promise, that program is running -- as you would expect from examining the code -- on my PDB.

    Actually, the 24LC256 is easier to use as there's no messing around with the slave ID byte, and you can use up to eight of them in a project (not the case with the 24LC16B). I've attached my 24LC512 demo which will in fact work with the 24LC256, 24LC128, 24LC64, and 24LC32 (you just have to limit the EE address for the respective device). Note that this program can write a byte or word to a given address; when a word is written it is stored Little-Endian. There are two functions for reading back: GET_EE and GET_EE2; the latter is for reading back a word value. The address must always be a word. If you want to specify a constant address you can do it like this:

    PUT_EE 0, 0, $FEDC
    



    Where two bytes are used for the address: low byte, then high byte. The value that follows can be a byte or word. The same addressing structure exists with GET_EE and GET_EE2.

    As I2C is a synchronous protocol you can use the internal oscillator.

    Post Edited (JonnyMac) : 8/2/2007 5:56:20 PM GMT
  • John KauffmanJohn Kauffman Posts: 653
    edited 2007-08-05 16:46
    I swore I wouldn't eat another pizza until I got this solved.· Three pounds lost, but got it. As usual, Jon had it right & I thank him, along with comments from Bean & Dave Hein.

    I have attached a file which is Jon's work that I·sliced & diced to get a "For Dummies" version.·My goal was the absolute first program a person should try with an EEPROM. Features:
    • Keep most of code in SUBs
    • Limit to only one byte saved (no words, no arrays, address is hard coded)
    • Users hard-codes the value into the code
    • Output is by eight LEDs rather then through BREAK / WATCH
    • Code displays the byte the user hard-coded, writes it, reads it and displays what was read
    • An extra LED is a flag that the byte on the display was read
    • Commented to the max
    I know this will be of little use to the hotshots on this forum (go straight to Jon's code posted above), but hopefully it will be found & used by someone that wants a first·try with an EEPROM.

    I'm planning to write & post programs for the next few learning steps:
    • savings words
    • saving·byte arrays
    • multiple EEPROMs
    • batch save in EEPROM page mode?
  • JonnyMacJonnyMac Posts: 9,216
    edited 2007-08-05 16:57
    Glad you go it working, John! For your future work here are some suggestions:

    Saving words:
    -- GET_EE2 in my program does this

    Saving arrays:
    -- GET_EE2 could be used as a starter; I would pass a pointer to the array and the number of bytes to write

    Multiple EEPROMs:
    -- you'll need to make the slave ID a variable, and include a variable for the device address

    Batch saving:
    -- that's essentially what GET_EE2 does, just with two bytes
Sign In or Register to comment.