Shop OBEX P1 Docs P2 Docs Learn Events
Spin code parameters for i2c method — Parallax Forums

Spin code parameters for i2c method

mickalmickal Posts: 75
edited 2010-12-30 15:42 in Propeller 1
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)

Comments

  • andrewsiandrewsi Posts: 59
    edited 2010-12-27 23:41
    mickal wrote: »
    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)

    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!
  • mickalmickal Posts: 75
    edited 2010-12-28 00:14
    thankyou, it is object to use the smart cards or eprom cards as sold by parallax. I do struggle with AND, OR , well this stuff so thanks for helping.

    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
  • mickalmickal Posts: 75
    edited 2010-12-28 18:16
    1010 0000 device address
    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.
  • andrewsiandrewsi Posts: 59
    edited 2010-12-28 18:40
    Not quite right. You want to leave the upper four bits alone (1010). So what you want is to take your page number (000) and shift left by 1 bit (remains the same - 0000) , then AND it with 1110 (still 0000!) and NOW you can OR it with your device address. So you still have 10100000 after all that. The purpose of all those parentheses is to put the operations in this exact order. If you were trying to write to page 1 instead, you would have 10100010 at the end of all those operations. (page 1 in bits 1-3 bit 0 is still 0 to indicate a write, and device address is still 1010.)

    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.
  • mickalmickal Posts: 75
    edited 2010-12-28 19:10
    thanks, i had pm'd you but posted here after
  • JonnyMacJonnyMac Posts: 9,208
    edited 2010-12-29 18:46
    I wrote an object for the Parallax Smart Card reader that you can find here:

    http://obex.parallax.com/objects/649/

    -- it should get you going in the right direction, if not provide all that you need.
  • mickalmickal Posts: 75
    edited 2010-12-30 00:01
    thanks jm. very happy to have that object.
  • mickalmickal Posts: 75
    edited 2010-12-30 13:46
    Hi JM

    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
                 3.3v                      
                  &#61463;         #32320      
                  &#9474;   &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
                  &#9474;   &#9474;     &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9508;
                  &#9474;   &#9474;     &#9474;         &#9474;
       dio  &#61626;&#61627;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9508; I/O &#9474;         &#9474;
       cd   &#61626;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9508; CD  &#9474;         &#9474;
       clk  &#61627;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9508; CLK &#9474;         &#9474;
                  &#9474;  &#9472;&#9508; RST &#9474;         &#9474;
                  &#9492;&#9472;&#9472;&#9472;&#9508; VCC &#9474;         &#9474;
                  &#9484;&#9472;&#9472;&#9472;&#9508; GND &#9474;         &#9474;
                  &#9474;   &#9474;     &#9474;         &#9474;
                  &#9474;   &#9474;     &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9508;
                  &#9474;   &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496; 
                  &#61464;
    
    
       Note: The #32320 has pull-ups on CLK and DIO; this suggests that the device could
             share a standard I2C buss with other devices (but not the boot EEPROM due to
             address conflicts).  
    
    pub write(b) | ackbit
    
    '' Write byte to (I2C) Smart Card 
    
      outa[clk] := 0
      dira[clk] := 1                                                ' clk low
    
      b <<= constant(32-8)                                          ' move msb (bit7) to bit31
      repeat 8                                                      ' output eight bits
        dira[dio] := ((b <-= 1) ^ 1)                                ' send msb first
        dira[clk] := 0                                              ' clk high (float to p/u
    
  • SapiehaSapieha Posts: 2,964
    edited 2010-12-30 14:17
    Hi mickal.

    Using DIRA[xx] after You set OUTA[xx] as 0 are for simulating --- OPEN Collector Output istead of LOW/HIGH



    mickal wrote: »
    Hi JM

    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
                 3.3v                      
                  &#61463;         #32320      
                  &#9474;   &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
                  &#9474;   &#9474;     &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9508;
                  &#9474;   &#9474;     &#9474;         &#9474;
       dio  &#61626;&#61627;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9508; I/O &#9474;         &#9474;
       cd   &#61626;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9508; CD  &#9474;         &#9474;
       clk  &#61627;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9508; CLK &#9474;         &#9474;
                  &#9474;  &#9472;&#9508; RST &#9474;         &#9474;
                  &#9492;&#9472;&#9472;&#9472;&#9508; VCC &#9474;         &#9474;
                  &#9484;&#9472;&#9472;&#9472;&#9508; GND &#9474;         &#9474;
                  &#9474;   &#9474;     &#9474;         &#9474;
                  &#9474;   &#9474;     &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9508;
                  &#9474;   &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496; 
                  &#61464;
    
    
       Note: The #32320 has pull-ups on CLK and DIO; this suggests that the device could
             share a standard I2C buss with other devices (but not the boot EEPROM due to
             address conflicts).  
    
    pub write(b) | ackbit
    
    '' Write byte to (I2C) Smart Card 
    
      outa[clk] := 0
      dira[clk] := 1                                                ' clk low
    
      b <<= constant(32-8)                                          ' move msb (bit7) to bit31
      repeat 8                                                      ' output eight bits
        dira[dio] := ((b <-= 1) ^ 1)                                ' send msb first
        dira[clk] := 0                                              ' clk high (float to p/u
    
  • JonnyMacJonnyMac Posts: 9,208
    edited 2010-12-30 15:42
    Since the cards are actually I2C memories and I2C IO lines are not meant to be driven high (only low), the code can be cryptic to newcomers. This line, for example:
    dira[dio] := ((b <-= 1) ^ 1)
    

    ... 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.
Sign In or Register to comment.