EEPROM write/read issues
Martin Hebel
Posts: 1,239
Hi all,
I'm making some additions to BS2_Functions, including write/read for EEPROM, both in code space and upper 32K. In theory I've seen on the board if you write to a variables EEPROM address,
on reboot it will hold that value. In testing, I use F11 to save the code without the write, use F10 to save with the write, then reload. In the code below neither X (reading the address from EEPROM) nor t1, the variable, holds my data (though the write then read does when F10ing)
Here is the actual methods, thanks for any help understanding or with code issues.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
StampPlot - GUI and Plotting Software
Southern Illinois University Carbondale, Electronic Systems Technologies
I'm making some additions to BS2_Functions, including write/read for EEPROM, both in code space and upper 32K. In theory I've seen on the board if you write to a variables EEPROM address,
on reboot it will hold that value. In testing, I use F11 to save the code without the write, use F10 to save with the write, then reload. In the code below neither X (reading the address from EEPROM) nor t1, the variable, holds my data (though the write then read does when F10ing)
VAR Long stack1[noparse][[/noparse]50] ' Stack for 2nd BS2 Cog long t1, x OBJ BS2 : "BS2_Functions" ' Create BS2 Object PUB Start BS2.start (31,30) ' Initialize BS2 Object timing, Rx and Tx pins for DEBUG BS2.Pause(2000) bs2.debug_str(string("Writing....",13)) ' BS2.write_CodeMem(@t1, 456_789, 4) BS2.Pause(1000) bs2.debug_str(string("Reading....",13)) x := BS2.Read_CodeMem(@t1, 4) BS2.Debug_Dec(t1) BS2.DEBUG_CR BS2.Debug_Dec(x) BS2.DEBUG_CR repeat
Here is the actual methods, thanks for any help understanding or with code issues.
Pub Write_CodeMem(address, value, size) write_Code(address,value, size, 1) Pri Write_Code(address, value, size, inc) | SDA, SCL, ack, i { Thanks to: Paul B. Voss Assistant Professor Picker Engineering Program Smtih College } SCL := 28 SDA := 29 size-- repeat i from 0 to size outa[noparse][[/noparse]SCL]~~ dira[noparse][[/noparse]SCL]~~ dira[noparse][[/noparse]SDA]~ outa[noparse][[/noparse]SDA]~ dira[noparse][[/noparse]SDA]~~ shiftout(SDA, SCL, %10100000, MSBFIRST, 8) dira[noparse][[/noparse]SDA]~ ack := shiftin(SDA, SCL, LSBPRE, 1) shiftout(SDA, SCL, address >> 8, MSBFIRST, 8) dira[noparse][[/noparse]SDA]~ ack := shiftin(SDA, SCL, LSBPRE, 1) shiftout(SDA, SCL, address, MSBFIRST, 8) dira[noparse][[/noparse]SDA]~ ack := shiftin(SDA, SCL, LSBPRE, 1) shiftout(SDA, SCL, value >> (i*8), MSBFIRST, 8) dira[noparse][[/noparse]SDA]~ ack := shiftin(SDA, SCL, LSBPRE, 1) outa[noparse][[/noparse]SDA]~ dira[noparse][[/noparse]SDA]~~ outa[noparse][[/noparse]SCL]~~ dira[noparse][[/noparse]SDA]~ address += inc waitcnt(clkfreq/200 + cnt) Pub Read_CodeMem(address, size) return read_Code(address, size,1) Pri Read_Code(address, size, inc) : value | SDA, SCL, ack, i, temp { Thanks to: Paul B. Voss Assistant Professor Picker Engineering Program Smtih College } SCL := 28 SDA := 29 size-- value~ repeat i from 0 to size dira[noparse][[/noparse]SCL]~~ outa[noparse][[/noparse]SCL]~~ dira[noparse][[/noparse]SDA]~ outa[noparse][[/noparse]SDA]~ dira[noparse][[/noparse]SDA]~~ shiftout(SDA, SCL, %10100000, MSBFIRST, 8) dira[noparse][[/noparse]SDA]~ ack := shiftin(SDA, SCL, LSBPRE, 1) shiftout(SDA, SCL, address >> 8, MSBFIRST, 8) dira[noparse][[/noparse]SDA]~ ack := shiftin(SDA, SCL, LSBPRE, 1) shiftout(SDA, SCL, address, MSBFIRST, 8) dira[noparse][[/noparse]SDA]~ ack := shiftin(SDA, SCL, LSBPRE, 1) dira[noparse][[/noparse]SCL]~~ outa[noparse][[/noparse]SCL]~~ dira[noparse][[/noparse]SDA]~ outa[noparse][[/noparse]SDA]~ dira[noparse][[/noparse]SDA]~~ shiftout(SDA, SCL, %10100001, MSBFIRST, 8) dira[noparse][[/noparse]SDA]~ ack := shiftin(SDA, SCL, LSBPRE, 1) dira[noparse][[/noparse]SDA]~ temp := shiftin(SDA, SCL, MSBPRE, 8) value := value + (temp << (i*8)) ack := shiftin(SDA, SCL, LSBPRE, 1) outa[noparse][[/noparse]SDA]~ dira[noparse][[/noparse]SDA]~~ outa[noparse][[/noparse]SCL]~~ dira[noparse][[/noparse]SDA]~ debug_ihex(address,4) debug_CR address += inc
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
StampPlot - GUI and Plotting Software
Southern Illinois University Carbondale, Electronic Systems Technologies
Comments
I would strongly suggest you incorporate an existing EEPROM package like the "Basic I2C Driver", either by including it as an object and exporting its useful public methods in some kind of "wrapper" or by incorporating its code directly. It's already debugged and documented and may be a little more efficient than the routines you posted since the code is specific to I2C and EEPROM access. For example, you re-address the EEPROM for every byte transferred while the "Basic I2C Driver" just sends an initial address, then uses the EEPROM's internal address counter for successive bytes. I'll have a more detailed look at this code and let you know what I see.
Mike
The best approach is to start with a proven and debugged I2C object as Mike suggests and get your code working with a single byte variable.
Then create your own I2C object, write your I2C Byte Write routine and get it debugged using the known working object ( any errors will be in your write routines ). Next add your own I2C Byte Read routine and get that working ( any errors will be in your read routine ).
Do it a step at a time and you will end up with a complete I2C object of your own. You can always fall back on using the proven object to verify as you go along.
I would take a closer look at your START/STOP conditions for the READ and WRITE functions.
First, the START conditions that you have for both READ and WRITE are different from one another.
Assuming that the SCL is driven, and the SDA uses a pull up (except through the shiftout) you should make sure that the lines after the SHIFTOUT's that read...
dira[noparse][[/noparse]SDA]~
... So that it reads...
dira[noparse][[/noparse]SDA]~
Outa[noparse][[/noparse]SDA]~
...This defaults them to a LOW when they are driven or made outputs, just in case the SHIFTOUT routine leaves them in an unpredictable state.
Edit
Outa[noparse][[/noparse]SDA]~··· ... Should also be initialized somewhere at the beginning of the I2C routines (within the START perhaps) as to pre define the I/O to be LOW when it is made an OUTPUT.
For a STOP condition, the i2c bus is basically looking for the SCL to make a
transition from LOW to HIGH followed by the SDA making a transition from LOW to HIGH.
I would change the STOP condition in both cases that currently reads...
outa[noparse][[/noparse]SDA]~
dira[noparse][[/noparse]SDA]~~
outa[noparse][[/noparse]SCL]~~
dira[noparse][[/noparse]SDA]~
...So that they read...
Edit ... Since the SDA line isn't Driven HIGH (uses a pullup resistor) the START code needed to change slightly.
'Note: The order is important here...
'····· We want the SCL to go LOW before the SDA otherwise we would generate a potential START condition when we want to generate a STOP.
outa[noparse][[/noparse]SCL]~······················· 'Make SCL LOW (driven)
dira[noparse][[/noparse]SDA]~~····················· 'Make SDA LOW (driven)
'····· Here is where we want the·STOP condition (after BOTH SDA and SCL are LOW)
outa[noparse][[/noparse]SCL]~~··················· 'Make SCL HIGH (driven)
dira[noparse][[/noparse]SDA]~······················ 'Make SDA HIGH (through pullup)
Similarly I would do the same for the START condition.
For a START condition, the i2c bus is basically looking for the SDA to make a
transition from HIGH to LOW followed by the SCL making a transition from HIGH to LOW.
I would change the START condition in both cases so that it reads...
Edit ... Since the SDA line isn't Driven HIGH (uses a pullup resistor) the STOP code needed to change slightly.
'Note: The order is important here...
····· We want the SDA to go HIGH before the SCL otherwise we would generate a potential STOP condition when we want to generate a START.
·
dira[noparse][[/noparse]SDA]~····················· 'Make SDA HIGH (through pullup)
outa[noparse][[/noparse]SCL]~~···················· 'Make SCL HIGH (driven)
'····· Here is where we want the·START condition (after BOTH SDA and SCL are HIGH)
dira[noparse][[/noparse]SDA]~~···················· 'Make SDA LOW (driven)
outa[noparse][[/noparse]SCL]~····················· 'Make SCL LOW (driven)
Good I2C reference...
http://www.esacademy.com/faq/i2c/index.htm
I2C Start/Stop Conditions...
http://www.esacademy.com/faq/i2c/busevents/i2cstast.htm
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe
IC Layout Engineer
Parallax, Inc.
Post Edited (Beau Schwabe (Parallax)) : 10/22/2007 7:56:21 PM GMT
Trying to keep the code all in one object, and working with someone else on this. It seemed to be all working fine except the variable write/read.
Beau, on the part below, could you look that over once, it's the same as the STOP, and I want to be sure it wasn't a copy/paste mishap.
Mike, understand it would be faster to stream the data once connected, but in one circumstance it has to write backwards in memory.
Thanks,
Martin
-Martin
The issues was the version on EEPROM to read the address was a little different than the one to write to it with f10, thus my address was changing. I watched the address being used for hours and didn't notice it.
Changing the test routing helped!!
One of those "oh Smile!" moments....
Martin
See my edit for the STOP, and why the Edit was necessary.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe
IC Layout Engineer
Parallax, Inc.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
StampPlot - GUI and Plotting Software
Southern Illinois University Carbondale, Electronic Systems Technologies
The timing for reading bits from the I2C device is not right in your code. The SHIFTIN routine reads the input pin, then puts out a clock pulse which is correct for SPI, but I2C requires the input pin to be sampled while the clock pulse is high. It may work with some devices to sample first, then clock the device, but it's not the way I read the I2C specs and examples in various datasheets and may not work in some circumstances.
Still integrating Beau's suggestions, but modified the code to stream on write/read (took care of the backwards issue by backing off by size) and adjusted the SHIFIN, though my clock times could be cleaner probably.
Also, on the repeat, tyring to figure out what should be in the repeat loop, seems to work as is, but having the stop in there makes me think it shouldn't be. I'll dig through the data sheets shortly.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
StampPlot - GUI and Plotting Software
Southern Illinois University Carbondale, Electronic Systems Technologies
Why not just use the Propeller Eeprom object?
http://forums.parallax.com/showthread.php?p=678271
Andy
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Andy Lindsay
Education Department
Parallax, Inc.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Andy Lindsay
Education Department
Parallax, Inc.
Thanks, Paul Voss had sent the code wondering if I'd like to incorporate it in the BS2_Functions, sounded like a good idea (and is to round out the library a little with some WRITE/READ functions), and except for my one big goof in extending and testing, it seemed good to go.
-Martin
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
StampPlot - GUI and Plotting Software
Southern Illinois University Carbondale, Electronic Systems Technologies