problems Controlling eeprom#2
glentech
Posts: 35
I have been trying with some success to read and write to an eeprom. I am trying to load an array from memory. I am using the i2cobject created by james burrows with modifications in the readlocation method as follows.
i2cstart
ackbit :=(ackbit << 1) | i2cwrite(deviceaddress | 1,8)
repeat place from 1 to 11
byte[noparse][[/noparse]mydata][noparse][[/noparse]place]:=i2cread(_i2cack)
byte[noparse][[/noparse]mydata][noparse][[/noparse]12]:=i2cread(_i2cnak)
i2cstop
everything works great untill i try 14 or 15 read and then it makes the next read go haywire. I have had no problems with a similar multiwrite. Any ideas anyone?
i2cstart
ackbit :=(ackbit << 1) | i2cwrite(deviceaddress | 1,8)
repeat place from 1 to 11
byte[noparse][[/noparse]mydata][noparse][[/noparse]place]:=i2cread(_i2cack)
byte[noparse][[/noparse]mydata][noparse][[/noparse]12]:=i2cread(_i2cnak)
i2cstop
everything works great untill i try 14 or 15 read and then it makes the next read go haywire. I have had no problems with a similar multiwrite. Any ideas anyone?
Comments
As always, the problem is in the details. When I get to a place like this where things should work, but don't, I'll sometimes take my program, strip out everything but the part that seems to be the problem, add "instrumentation" to display the progress of things on a TV or VGA screen and see what's really happening. With the Propeller and SPIN, it's easy enough to add a little "debugger" to let me enter a byte count or specify read vs. write so I don't have to recompile every time I want to try something a little different.
Can you post the program - I cannot really see whats going on without
Thanks
the call from the main method goes something like this.
i2cObject.readLocation(EEPROM_ADDR, eepromlocation, 16, 8,@mydata)
I am using the propeller tv screen to debug this.
The top object is my own creation but has the necessary constants and variables as far as I know.
What do you mean by "reads go wild". What kind of data are you seeing? Can you tell what locations the data comes from? I used the random operator (?) with a known starting point to generate an EEPROM full of pseudo-random data, then used that for testing the multibyte read stuff. The data is close to random, yet you can go back in and determine where you are in the sequence. You could also just fill the EEPROM with pairs of bytes in sequential numeric order. When the "read goes wild" you might be able to determine where it read from and that way deduce what happened.
Mike
eeprom.read(addresstoread,30,@mydata)
I see you've posted code - that'll help me work out whats going wrong. I am about to go away for the weekend and will not be able to look at it until next Tuesday onwards - so please bear with me. If you have'nt heard anything send me another PM
James
1) The %10100001 and %10100000 are added in the assembly code just before they're transmitted
2) The I/O routines are in a separate cog because they're written in assembly language and all assembly language gets run
in its own cog. That's the way the Propeller works. The COGINIT instruction loads a block of 512 longs into a cog from
the HUB RAM and it starts executing at location zero of the cog's memory.
3) When you start an assembly cog, you can pass a single address to it as a parameter that appears in the PAR register.
The I/O routines periodically watch that location (2 longs) for a non-zero operation code to appear in the high order
byte of the first long. When that appears, the routines fetch both longs and execute the operation "requested".
When the I/O routines are done, they store the updated information back into the 2 longs including a zero in the
lower 4 bits of the high order byte. There are PUB routines in the "OS_loaderInit" object (readEEPROM and writeEEPROM)
that will manage this exchange for you. They wait for any previous operation to complete, set up the 2 longs, and
wait again for the operation to complete. They return TRUE if there were no NAKs received on write cycles and FALSE
otherwise. Both routine accept an EEPROM address, RAM address for the data, and a count of bytes to transfer.
The writeEEPROM routine does not wait for the EEPROM write cycle to complete, but you can either insert a 5ms
wait or attempt to read zero bytes from the EEPROM repeatedly until the readEEPROM succeeds (returns TRUE).
The EEPROM address is 23 bits with bits 22..19 containing a "pin pair" number (pins 28-SCL/29-SDA would be 14),
bits 18..16 containing the device address code (for bits 3..1 of the %10100000), and bits 15..0 containing the 64K
address within the EEPROM. In other words, if you had 8 - 24LC512 EEPROMs on each pair of I/O pins, you would
have a linear address space of 16 (pin pairs) x 8 (devices per I2C buss) x 64K (bytes per EEPROM) = 8MB.
If you want to check for errors, you could do something like "if not i2c.readEEPROM(....)"
Mike
Post Edited (Mike Green) : 8/24/2006 5:03:48 PM GMT
For the SCL pin, the routines check the I/O pin. If it's 28, the routines switch between output high and output low. If not,
they switch between input (high) and output low (low).
The first time any pin pair is used, the routines will do an I2C reset sequence where they'll put out up to 9 clocks until SDA is high while the clock is high. This should reset any I2C device that's in some indeterminate state (according to Philips).
Back from a great weekend!
Right a quick look at the modified i2cObject shows a few potential issues.·:
(1) mydata is not an array - or at least is not clear that it may point to an array.· If "mydata" is a pointer maybe a mydataPtr would be a better name.· This should point to a least 13 byte array, and the pointer should be "@mydatarray"
(2) Related to the above - the "repeat place..." loop the byte[noparse][[/noparse]mydata][noparse][[/noparse]place] won't work unless the mydata is a pointer to @mydataarray as at least a 13 byte array
(3) Otherwise - try having the "mydataarray" in the i2cObject and reading into it directly.· I.e declare the array in the i2cobject "byte· myDataArray[noparse][[/noparse]20]" then change the repeat loop to be "byte[noparse][[/noparse]@mydataarray][noparse][[/noparse]place]:=i2cread(_i2cack)".· Finally a small function to return the pointer to the array to other objects:
If this is no help - let me know and i'll try running it from home.
James
In your code segment: i2c.writeEEPROM(pinPair<<18+$7FF0,@writeBuffer,16)
What does the 18 represent?
Is it part of the chip address?
If it is, how dows it corrlate to the actual address of the chips address?
Also, do you or does the code take care of 'roll over' automatically?
(ie, you hit the end of one chip in a read/write, does it move to the next chip or go to 0 of the current chip?)
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Propeller + Hardware - extra bits for the bit bucket =· 1 Coffeeless KaosKidd
·
<< and >> are binary shift operators. So in that code I guess he is shifting pinPair left 18 places, then adding $7FFO
James
From the way the post is writtem and the statement, the chip address appeared to be part of the param, but I couldn't tell.
He's moving the pinpair over( like you said), and shifting in 0's for the boot prom address.
What I need to do is figure out how to shift in an chip address as well.
I think it would be something like: Address = Pinpair << 2 + chip address << 16 + $####
If this is the case, then a simple single sontinious address map could be derived by some simple math, assuming all the eeproms were the same size on the bus:
ChipArrayRead(GloabalAddress, BytesToGet, PinPair,@Destination) | ChipAddress, BaseAddress, WorkingAddress
ChipAddress = INT(GlobalAddress / NumberofChips)
BaseAddress = GlobalAddress - (ChipAddress * ChipSize)
WorkingAddress = PinPair << 2 + ChipAddress << 16 + BaseAddress
I2C.ReadEEPROM(WorkingAddress,@Destination,BitesToGet)
Is this about right? It's not. The Chipaddress needs to be decoded (??) before being shifted in... I'm not sure how that woud be done...
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Propeller + Hardware - extra bits for the bit bucket =· 1 Coffeeless KaosKidd
·
It can be done fairly easily as the addressing on the chips allows for 8 devices sequencially on the bus. With a bit of math you can use some of the device bus address and the register on the eeprom as single reference to a large block of eeprom!
James
THat's exactly what I'm trying to do... treat multipule eeproms on the same bus as a single block of memory.
Thats how I understand Mike Green's code to work... I think...
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Propeller + Hardware - extra bits for the bit bucket =· 1 Coffeeless KaosKidd
·
The EEPROM address is intended to be a continuous addressing space. The lower 16 bits (15..0) get sent to the EEPROM as two address bytes. The next 3 bits (18..16) are used to create the device addressing code (%1010xxx0). The remaining 4 bits (22..19) are used to select a pair of I/O pins with SCL on the even pin and SDA on the next odd pin. The left shift 18 bits is used to position the pin number of the SCL pin (always even) so that the high order bits fall into bits 22..19. This gives a theoretical space of 8MB. If you're transferring multiple bytes, the device is only addressed on the first byte. The device addresses wrap around at the end of the device, so don't try to transfer a block of data across a device boundary (usually 32K). In addition, the write routines do not wait for the write to complete. If you try to access the device too soon after a write, the read or write will get an error. If you keep retrying, the device will eventually respond and do what you want. This is the ideal way to do successive writes because the device responds when it's ready which may be sooner than a fixed time (like 5ms or 10ms). Multiple byte writes make use of a page which can be 64 or 128 bytes depending on the device size. If you try to write past the page boundary, the write address will wrap around in the page buffer. This is unlikely to be what you want! The best way to handle all this is to either write single bytes or blocks of 64 bytes on a 64 byte boundary. For reading, either read single bytes or never cross a 32K boundary.
32K devices ignore bit 15 of the address, so don't assume you have a 64K address space unless you know what chip is there! The file system in the OS checks to see if the second half of a 64K address space actually has a unique device there when you
use the "probe" command to see what's on an I2C bus.
If you're using a Ramtron FRAM device, you can ignore the paged write stuff. Writing works just like reading.
I hope this helps. Mike
Maybe I didn't make it clear or else I am not understanding something but I am using an array outside of the i2cobject named mydata. The call to the i2cobject has the pointer @mydata in the call. It may be a fluke that it works until I try to read 14 or more.
I guess'd that.
Perhaps I was being too subtle. How big is your array, and how is it declared in your calling object?
James
byte mydata[noparse][[/noparse]30]
Sorry about the silence. I'll get this tested tonight and let you know.
James
Attached is version 1.4 (beta) of i2cObject. I've added a pageRead and pageWrite with example in the i2cObject and i2cDemoApp respectivly.
Hopefully this will solve your issues.
(note that this is beta - thus will not go onto the object exchange yet)
James