Spin code parameters for i2c method
mickal
Posts: 75
PUB writeLocation(CLK, device_address, register, value)
start(CLK) ' Start condition
write(CLK, device_address) ' Send slace address (write)
write(CLK, register) ' Send starting address location
write(CLK, value) ' Send data to write
stop (CLK) ' Stop condition
above is the method , below its being used for i2c write. I am really struggling to understand what has
happened to the four parameters here. Am very confused by pipes ,brackets and %
I know @page hold the address of data entered
If you can help me understand, still new at Spin.
sc.writeLocation(CLK, DeviceAddr | ((debug.strtodec(@page) - 1) << 1) & %1110, MAddr, char)
start(CLK) ' Start condition
write(CLK, device_address) ' Send slace address (write)
write(CLK, register) ' Send starting address location
write(CLK, value) ' Send data to write
stop (CLK) ' Stop condition
above is the method , below its being used for i2c write. I am really struggling to understand what has
happened to the four parameters here. Am very confused by pipes ,brackets and %
I know @page hold the address of data entered
If you can help me understand, still new at Spin.
sc.writeLocation(CLK, DeviceAddr | ((debug.strtodec(@page) - 1) << 1) & %1110, MAddr, char)
Comments
In Spin, the "|" is a bitwise OR. "&" is a bitwise AND, and "%" denotes that the following number is in binary notation. (Similarly "$" is used to prefix a number in hex notation.) "<<" is a left shift by the number of digits that follows.
Most llikely, what's probably going on here is selecting one of several 256-byte pages from an NVRAM chip, which will then be written to or further reads. Also, the I2C convention is to use the least significant bit of the device address to tell the device whether you're reading from the device or writing to it, which is likely why the shift left of 1 is there.
So basically what I see is this:
CLK probably denotes the pin to use for the I2C communication, which is passed on inside the method with each individual sub-method call.
DeviceAddr is probably defined elsewhere as a constant in order to select the chip in question, most likely some specific high-nibble only value, leaving the lower four bits for page selection and read/write selection. This constant is being modified by or-ing bits 1-3 with "page" which represents a particular selected page of the NVRAM (0-7), where page is probably originally 1-8 (hence the "-1", to put it in the right range.), then left shifted by one to leave bit 0 to specify the read or write operation. This value is then being And'ed against binary 1110 (decimal 14) to set the low bit for the read or write operation. Assuming 0 means "write" to this device, all is well.
A possible bug I see here is that the | and the & are being evaluated left to right, so if the AND takes place last, the upper four bits will be assumed to be 0 (since only the lower four bits of 1110 are specified) and therefore the upper four bits which should contain the constant device address will be zeroed, which will probably result in not successfully selecting the device when this is all finally sent over the wire, unless its fixed address really is %0000. One more set of parentheses starting with "(((debug.." and ending with "... & %1110)" would force the evaluation order to ensure that the OR takes place last instead, thus preserving the upper four bits, if that's what's desired.
I don't really know what the purpose of the debug.strtodec call is in this context, except perhaps to take some value at address "page" and return the correct value for the I2C operation.
The other two params are expected to be the byte offset within the 256-byte page you want to write to, and finally, the actual value to write.
Hope that helps!
whew .....there is still 4 parameters :-)
your right it asks you to enter page number [1 - 8]
http://www.parallax.com/Store/Accessories/CommunicationRF/tabid/161/txtSearch/xbee/List/0/SortField/4/ProductID/686/Default.aspx
0000 0000 OR'd page number
becomes the same
1010 0000
shift left by 1
0100 0000
anded %1110
becomes
0100 0000 maybe this 0000 0000
which is nown the device address parameter
Have I got this right , because I need
to take a pill :-) ?
It gets worse when I look at the
actual write method wich only has two params, WRITE(CLCK, DATA)
data is a byte but gets <<=24 treatment
so if it was H for HELLO WORLD the byte
would be
0100 1000 then shift left 24 i guess
0100 1000 000000000000000000000000
then rotated bit by by bit 8 times
anded by 1 each time to send
I am not sure I should even be trying
to read this but if it helps take out the mystery it might be ok for later if
I want to write mny own i2c or use this one.
The write method just puts a byte out on the i2c bus, but you have to write multiple bytes to get a single operation to take place:
(Start) - which is a special case.
Write the device address byte (including the page selection and the read vs. write selection in bit 0.)
Write the offset byte into the page.
Write the data byte itself.
(Stop) - which is a special case.
Don't worry about all the <<=24 treatment and rotation the underlying method is doing, it needs to send full bytes across bit by bit, since this is a serial protocol with only one data line. The important thing is to ensure that you're sending a byte to the write routine and you're using the routine that knows you're only trying to send a single byte. Later you can worry about taking advantage of multi-byte writes and reads for efficiency.
http://obex.parallax.com/objects/649/
-- it should get you going in the right direction, if not provide all that you need.
I would really like to know about this line -->dira[dio] := ((b <-= 1) ^ 1) ' send msb first
because I am not sure why it works instead of OUTA[dio] similarly the line below
dira[clk] := 0 ' clk high (float to p/u) ---> sets [clk] to be an input so can you tell me why its high ? I thinks its got to do with pullups on the card ??
and just to be an annoyant what does XOR by 1 manage ? I think the least significant bit will be inversed so this has me going back to DIRA again.
but also if 1010000001 was XOR'd
with 0000000001 gives dira[dio] = 10100000000000 , well im not understanding , if you need a 1 or 0 what will happen.
To restate my interp, if you AND by 1 after rotating to LSB then only the LSB is able to be both 1 or 0 so you know the pin will be assigned the 1 or 0 but XOR will still have 1's in MSByte.
Thanks
Using DIRA[xx] after You set OUTA[xx] as 0 are for simulating --- OPEN Collector Output istead of LOW/HIGH
... is in fact controlling the DIRS bit for the pin instead of the OUTS bit for the pin (making it an open-drain output).
The reason for this is to prevent possible conflicts on an I2C buss -- that is, you could share the clock and data lines with another I2C device (other than memory). What this code is doing is taking the MSB bit (which was rotated around from bit31 of b) and XOR it with 1. This value is written to the DIRS bit for the data pin. When the bit is 1 the XOR will cause 0 to be written to the DIRS bit of the pin, making it an input, which causes the data line will be pulled to 3.3v through the onboard pull-up; this is what creates the "1" on the data line. When the bit is 0 the pin will be made an output and will go low because a 0 was previously written to the OUTS register.
Once you get a handle on this the rest will fall into place. It's standard I2C coding.