Shop OBEX P1 Docs P2 Docs Learn Events
I2c & Spin How to — Parallax Forums

I2c & Spin How to

JBWolfJBWolf Posts: 405
edited 2013-09-08 18:28 in Propeller 1
Hello,
I was hoping to find information on how to communicate & store returned data values with spin from an IC using I2c.
I am using an MPU6050 gyro, the registers & more can be found here: RM-MPU-6000A.pdf
And more info from here: http://www.i2cdevlib.com/devices/mpu6050#registers
I am more familiar with analog components and just do not understand how to go about this.

How do I request & store data from an I2c register using spin?
Thanks

Comments

  • JonnyMacJonnyMac Posts: 9,107
    edited 2013-09-02 07:46
    I2C is very straightforward, and many of use have offered up I2C objects for use with the Propeller; mine is attached.

    As a generalization, in I2C you tend to have the following event sequence

    Write:
    START
    WRITE Slave ID (write mode)
    WRITE Address
    WRITE Data
    STOP

    Note that in some devices you'll need two bytes for the address, and the writing data will also depend on how many bytes are to be written.

    Read:
    START
    WRITE Slave ID (write mode)
    WRITE Address
    START
    WRITE Slave ID (read mode)
    READ Data
    STOP

    The first part of the read process writes the address pointer into the device. The slave ID is re-written with the read bit (bit0) set and the reads commence after that. The Ack/Nak bit is set to ACK for all reads except the last, which is set to NAK.

    There are lots of I2C tutorials on the Internet. Between those and the attached object (or one of the others in ObEx) you'll be connected in short order. It's worth learning I2C if you'll take a bit of time
  • JonnyMacJonnyMac Posts: 9,107
    edited 2013-09-02 08:01
    The default Slave ID for that device seems to be $68, so you might try these routines.
    pub write_reg(reg, value)
      
      i2c.start
      i2c.write($68)
      i2c.write(reg)
      i2c.write(value)
      i2c.stop
    
    
    pub read_reg(reg) | value
    
      i2c.start
      i2c.write($68)
      i2c.write(reg)
      i2c.start
      i2c.write($68 | $01)
      value := i2c.read(i2c#NAK)
      i2c.stop
    
      return value
    
  • JBWolfJBWolf Posts: 405
    edited 2013-09-02 08:44
    I notice you have pins 28 & 29 assigned in the I2c code... Currently I have those connected to an eeprom, does it have to be those pins or can I use any others?
  • JonnyMacJonnyMac Posts: 9,107
    edited 2013-09-02 09:00
    You're misreading the code. The Propeller uses 28 and 29 for its EEPROM (hence I put the constants in my code as a reminder), and you should be able to share them. If you don't want to use those pins, you can use the .setupx() method which allows you to pass your own buss pins for the object.
  • JBWolfJBWolf Posts: 405
    edited 2013-09-02 09:17
    ok so it doesnt have to use those pins... or does it and it can just share them with the eeprom? not sure if you mean it has to be buss pins and 28/29 are the only default ones defined.
    I see, so I just pass the pins from the main routine call correct?
    i.e. i2c.setupx(sclpin, sdapin)

    Thanks for the help btw :)
  • JBWolfJBWolf Posts: 405
    edited 2013-09-02 09:53
    Also I'm trying to figure out how you got $68.... I looked through the pdf and cannot get this from anywhere.
    Is $68 a hex value? = 104 decimal = register name (SIGNAL_PATH_RESET)?

    So just trying to get around the very basics... the I2c uses pwm high/low bits to create hex values, these hex values correspond to the registers and it replies in kind? correct?

    How do I assign the 'value' variable for the register desired? Can I just do this:
    gyroxreg := $44
    
    I see a high & low bit register for the X-axis gyro which means 2 values (43 & 44).

    Sorry, I just do not understand this well enough to immediately utilize the i2c object.
    I sincerely appreciate you taking the time to help and look forward to any more you have to offer :)
    I am more than willing to study on this, just cannot find much about using i2c with spin.
  • JonnyMacJonnyMac Posts: 9,107
    edited 2013-09-02 14:44
    Also I'm trying to figure out how you got $68.... I looked through the pdf and cannot get this from anywhere.

    It was not easy to find. It's almost at the very end of the document: page 46, discussing the "Who Am I" register which contains the default I2C address of the device.


    Sorry, I just do not understand this well enough to immediately utilize the I2C object.

    The is a TON of information on using I2C available on the Internet -- as you have a working computer and Internet connection, a little research and reading is in order. To be honest, that document is not helpful. Have a look at an EEPROM data sheet and you'll get much more information vis-a-vis the I2C transaction process.

    Read this: http://ww1.microchip.com/downloads/en/devicedoc/21754m.pdf

    If you will take the time to study, you'll get a really good hand on using I2C with the 24LC512 (64K EEPROM that many of us use with the Propeller). You can even experiment with the EEPROM you have -- just make sure you don't write to an address where program data is being stored.

    I am more than willing to study on this, just cannot find much about using i2c with spin.

    You're not going to find a specific tutorial on I2C with Spin (unless it's from Parallax) -- nor should you, really. I2C is a process that is not language dependent; it can be implemented in any language that has hardware connection features. If you don't understand how to manipulate IO pins on the hardware and with the language you're using, you cannot implement I2C. It's all about bit twiddling, and you have to start with the bits. Luckily for you, many of us DO understand the bit twiddling and have written easy-to-use objects. It's up to you now to learn the basics of I2C so you can successfully put that code to work. I've used my I2C object in a number of commercial projects so I'm very confident in it. That said, others have come before and after me with I2C objects as you'll find with a quick search of ObEx.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2013-09-02 16:43
    ok so it doesnt have to use those pins... or does it and it can just share them with the eeprom?

    You can do either, but it is very convenient to use the existing P28 and P29 shared with the eeprom as that leaves more of the other propeller pins free for other things. All sorts of clever things can be added onto P28 and P29 - analog to digital, digital to analog, digital i/o ports, gyros, temp sensors, real time clocks, other memory chips. All shared on the one bus. The I2C bus is very useful.
  • JBWolfJBWolf Posts: 405
    edited 2013-09-02 18:07
    ok I read through the eeprom datasheet and am able to follow how it uses the high/low state for start bit, data and ack... now I'm just trying to figure out how to go about it.
    The data sheet seems to only have the raw/analog method for communicating (high/low states & timing), but I cannot correlate this information into a spin command(s) to generate a desired data set or how to receive a reply.
    The only way I can think of right now is to make a literal pwm pulse:
    outa[28..29] := %1000000
    but this wont work since the timing on the sda pin will not be in sync with the pulses on the scl pin right?

    So far I have learned I should use pins 28 & 29 for bus communication and the pulse format the data has to be packaged in.
    It seems as if the i2c object you attached above will produce the data packages for me, but I cannot use the information from the datasheet regarding pulse formatting to make any more sense out of using the object.
    what is the next step?
  • JonnyMacJonnyMac Posts: 9,107
    edited 2013-09-02 18:59
    I say this with intended kindness: you're over-thinking and making this WAY too difficult.

    With a tiny bit of effort you should be able to use the I2C object I provided to read bytes from the EEPROM. You can use F8 to determine an address and what's in it -- that way you'll know the read process worked. And here... I'll write a method for you to write to the EEPROM; try it and then see if you can create a complimentary write method. Programming is kind of like going to the gym: you have to do the workout to benefit from it; watching others is not enough.

    I've attached my starter program so that you don't have to type to see that it works.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2013-09-02 19:08
    ok I read through the eeprom datasheet and am able to follow how it uses the high/low state for start bit, data and ack... now I'm just trying to figure out how to go about it.

    To second what JonnyMac says, the good news is that someone else has already written the code for you. So instead of worrying about highs and lows, you can talk to an 'object' (code written by someone else). The 'object' has PUB methods, which is essentially public routines that you interact with. Say you want to print 'hello world' on the screen. Someone has already written a display object and called it 'Display'. So to interact with that you might write "Display.Print("Hello World")).

    I2C is similar. All I2C code is going to need a "start" to wake up the chip. So the code is "I2C.Start" Now it becomes much simpler because someone else has done the high / low code inside the i2c object. You can read the code if you like, and you can rewrite it if you really want, but generally it is ready to go and do just what you want.

    JonnyMac posted the code earlier with this and can be truly this simple (I once wrote a movie player for the propeller using objects written by someone else and it ended up being two lines of code!)
    pub write_reg(reg, value)
      
      i2c.start
      i2c.write($68)
      i2c.write(value)
      i2c.stop
    
  • JBWolfJBWolf Posts: 405
    edited 2013-09-02 19:21
    Thank you so much, I have to call it a night and will look it over tomorrow.
    I was worried you were going to consider me too far behind and give up, relieved to hear it's not as complicated as I worried it would be... feels like im just missing something basic thats throwing me off so far.
    Hopefully everything will be cleared up tomorrow when I get a chance to do more reading.
    Hope you guys had a good weekend :)
  • JonnyMacJonnyMac Posts: 9,107
    edited 2013-09-02 20:19
    It may take longer, so don't put pressure on yourself. If you're under a deadline, you can always hire one of us that has already put in the time! :)

    None of us learned this stuff in a day. Take it easy, it will come.
  • JBWolfJBWolf Posts: 405
    edited 2013-09-06 23:55
    One thing I'm curious about but having a little trouble following is the usage of the # sign.
    I have searched through the PE book but cannot find a reference to this other than min/max limiter... what is the # doing in the con sections?
    I will be working on this again over the weekend, looking forward to it :)
  • kuronekokuroneko Posts: 3,623
    edited 2013-09-07 00:00
    JBWolf wrote: »
    I have searched through the PE book but cannot find a reference to this other than min/max limiter... what is the # doing in the con sections?

    You mean enumerations?
    CON 'Declare modes of operation
      #0, RunTest, RunVerbose, RunBrief, RunFull
    
    Check the manual (v1.2) around page 87 (CON section & Co). Basically it lets you define a number of constants in a single line, optionally with gaps:
    CON
      #8, BS, TAB, LF, VT, FF, CR, ESC = 27
    
  • JBWolfJBWolf Posts: 405
    edited 2013-09-07 15:21
    I agree about your learning method, it is definitely easier to recall an experience than a paragraph.
    Unfortunately I got nowhere in the book regarding the enumerations.... there is no mention to the word enumeration in v1.2 of the PE book, p.87 is about variables called from dot notation methods and looking at memory.
    Was a good lesson to go back over, but I could not get anywhere regarding the enumerations.
    So I just tried to figure it out myself.... it looks as if you are associating those names with a number value? So a call to 'home' or 'gotoxy' returns a value of 1?

    Ok so let me see if I'm following:
    The 'main' method calls rd_byte and passes $004C.
    The main method then prints to PST the value in the variable unless it equals 0 where it would quit the loop and enter an endless null loop.
    The rd_byte method calls the 'write' method in jm_i2c and passes values ($004C, "JonnyMac's Propeller Programming Attack!") for (address.byte[0])


    what I dont get is why there is a ++ after the $004C... wouldnt that make it increment and equal $004D?
    I also dont understand about the msb ID write, is it basically a standard required for use or do I need to figure out how to identify ID's? i2c.write(address.byte[1]) ' write address (msb first)

    For some reason in PST I just get a repeating letter 'y' and nothing else. I have tried speeds 57600 and 115200 but get same results.
  • kuronekokuroneko Posts: 3,623
    edited 2013-09-07 17:57
    JBWolf wrote: »
    Unfortunately I got nowhere in the book regarding the enumerations.... there is no mention to the word enumeration in v1.2 of the PE book, p.87 is about variables called from dot notation methods and looking at memory.
    Apologies, I was referring to the Propeller Manual (available from the PropTool helpmenu).
    JBWolf wrote: »
    Was a good lesson to go back over, but I could not get anywhere regarding the enumerations.
    So I just tried to figure it out myself.... it looks as if you are associating those names with a number value? So a call to 'home' or 'gotoxy' returns a value of 1?
    con
    
       #1, HOME, GOTOXY, #8, BKSP, TAB, LF, CLREOL, CLRDN, CR       ' PST formmatting control
      #14, GOTOX, GOTOY, CLS
    
    Not quite, the value auto-increments, so HOME will be 1, GOTOXY is 2, then the enumeration is reset to 8 (BKSP), TAB will be 9, CLS finally 16. Does that make sense? In the PropTool (after a successful compile) you can place the cursor on a constant and see its value in the status line.
    JBWolf wrote: »
    The 'main' method calls rd_byte and passes $004C. ...
    For this to work you have to put the program into EEPROM because the loop only reads from there (the Msg string ends up at $4C in EEPROM). The loop itself reads one byte at a time which is why the address is post incremented (p_str++), i.e. for the first pass it will be $4C for the second $4D etc. As for talking to an I2C device, that's just the way it is. You send (write) a start condition, a device ID then an address (which may differ in length depending on the device). For a read you then change direction (another start followed by ID with the read bit set). Then you read one or more bytes and stop the transfer.
  • JBWolfJBWolf Posts: 405
    edited 2013-09-08 02:48
    ah I did not realize it was writing one byte at a time within an individually specified address... that certainly explains the post increment.
    I can see the text in memory starting at $004c after loading.
    memory.jpg

    I'm still getting a repeating letter 'y' in PST though.
    1024 x 741 - 134K
  • kuronekokuroneko Posts: 3,623
    edited 2013-09-08 03:15
    JBWolf wrote: »
    I'm still getting a repeating letter 'y' in PST though.
    Did you transfer to EEPROM (F11)? The program itself expects the string to be in EEPROM, not hub RAM. I tried and it just works as advertised.
  • JBWolfJBWolf Posts: 405
    edited 2013-09-08 12:34
    ah, no i did not... I loaded to ram.
    It seems to load to ram just fine... but when I try to load to eeprom, the propeller tool fails with "eeprom programming error on COM3".
    I wonder if this is because both the i2c device and the eeprom is on pins 28 & 29?

    ok I removed the i2c device from pins 28 & 29, the F11 eeprom load works fine now.... but I get nothing at all from PST.
    I have tried both 57600 & 115200 speeds, reset several tiemes, reloaded several times, added a 5-sec delay before the program starts... but still nothing on PST at all.
    do I need to re-connect the i2c device?
  • kuronekokuroneko Posts: 3,623
    edited 2013-09-08 18:13
    JBWolf wrote: »
    ok I removed the i2c device from pins 28 & 29, the F11 eeprom load works fine now.... but I get nothing at all from PST.
    I have tried both 57600 & 115200 speeds, reset several tiemes, reloaded several times, added a 5-sec delay before the program starts... but still nothing on PST at all.
    do I need to re-connect the i2c device?
    That's odd. Works just fine here (3s delay). The program in question only talks to the EEPROM so the other device isn't required for now. I'd suggest you get the PST link sorted first, i.e. no I2C stuff, just serial output from both RAM and EEPROM. Don't you even get the surrounding debug messages?
  • JBWolfJBWolf Posts: 405
    edited 2013-09-08 18:28
    aha! my bad.... I accidentally switched the wires when disco/reconnecting the i2c device.
    Fixed now and it does give a good readout in PST.
    sorry, my protoboard is setup for 3 different project so it's kinda a mess lol
Sign In or Register to comment.