Shop OBEX P1 Docs P2 Docs Learn Events
An i2c Object Question — Parallax Forums

An i2c Object Question

MasterCMasterC Posts: 39
edited 2009-09-03 23:00 in Propeller 1
Hi,

I·have been·starting in on making some higher level i2c objects to communicate with various devices.· I was going to base them around the use of a slightly modified version of Dave Custer's I2C Spin Object.· However, I got to wondering how well vetted this object is to use as a starting point.· I have no prior experience with I2C, so I might be missing a few things, but some of the stuff in there wasn't adding up for me.· If you wouldn't mind, please see the attached object.· I have added some questions to it, usually in comments like: "{*******Corey Q: ... *******}," or something like that.

Please note:· I was not intending to nitpick at the original author's code.· I am new to this stuff, so it is just as likely that I am confused--I'm only·seeking some clarification here to make sure I get this going on the right track.·

Thanks!

Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2009-08-28 20:26
    You'll have to e-mail the author to get a sense of who's using it. I believe James Burrow's i2cObjectV2 is more widely used. There's also an assembly driver that's part of FemtoBasic, but can be used by itself (sdspiFemto.spin) to access any kind of I2C device.

    The ability to directly handle 8, 16, 24, or 32 bit values at a low level is not as useful as you might think since they're all just multiples of bytes. Basic_I2C_Driver does its low level I/O in bytes and simply does multiple bytes at a higher level. Look at routines like ReadWord and ReadLong for examples.
  • JavalinJavalin Posts: 892
    edited 2009-08-29 15:54
    MasterC,

    Mikes basic_i2c_driver is truly excellent and its what i've based the version 2.x i2cObjects on. I'd look at that code for i2c routines.

    As to your comments in the code - just use Mike's driver instead - mine was very basic and not very good in some places. (but it did work!)

    james
  • Erik FriesenErik Friesen Posts: 1,071
    edited 2009-08-29 17:08
    I have used Javalins code for my projects. One reason I didn't use Mikes code was because it uses an extra cog, which I didn't have. However, I believe the performance would be much better with the assembly driver. I doubt Javalins code is reaching the 400khz milemark, but I haven't checked it out that close.
  • MasterCMasterC Posts: 39
    edited 2009-08-29 20:21
    Thanks guys.

    Well, aside from the ability to do·more than 1 byte at a time (which I understand isn't that useful),·there were a couple of other factors that drove me to use the object being discussed (javalin's object, apparently?) as a starting point.· For one, I liked being able to assign whatever pin I wanted for both SCL and SDA.· In addition, I liked that it had the framework to function as more of a standalone object that would remember its SDA and SCL pins and stuff, so I wouldn't have to send it every time.·

    However, now it occurs to me that a better place for that stuff might be in my device specific driver objects.· For instance, I envision making an ADS1100 object that has an init method where the device address and·IO pins are assgned.· From then on, I just have to say things like·object.read and object.write, or whatever.· That way, if I have several ADS1100 chips on my board (and I do), I can set ADC1, ADC2, ADC3, etc. all to the ADS1100 object.· Then I can say "ADC1.init(address1,SCL,SDA)", "ADC2.init(address2,SCL,SDA)", etc.· From then on, I can forget about who's at what address and what the SCL and SDA lines are.· I can just say things like·"ADC1.read", "ADC2.read, "ADC3.cfg(mode)", and etc.

    Does that make sense?· So, maybe Mike's basic_i2c_driver is a better starting point, and it can be a child of my ADS1100 object.· But in my ADS1100 object, I need to figure out what to do for the start, stop, init, etc.· I figured javalin's code was a good start for that, but then I got confused by what he was doing with some of it.· Hence the comments I left in his code, so it would still be helpful if somebody could straighten me out on my questions there.· smile.gif
  • JonnyMacJonnyMac Posts: 9,198
    edited 2009-08-29 20:43
    No long ago I wrote an I2C object that allows me to assign the pins independently. If you use it, just understand that it never drives the clock line high so you may have to add a pull-up on SCL for some Propeller boards (not all have them) if you want to use the Propeller's I2C buss pins. I think you'll find the implementation straightforward and easy-to-understand.

    [noparse][[/noparse]Edit] I see why you're having trouble. Most of the I2C libraries (mine, anyway) take care of the grunt level stuff without revealing it. The chip you're using doesn't use register addressing per se, so the mid-level code we wrote was confusing you. I freed my library by making the low-level stuff public so that those methods can be used in other objects. Have a look at jm_ads1100.spin and compare the code to the I2C diagrams in the documentation; I think you'll find this gets you started. Once you're successfully talking to the chip then you can port the code to an object for us in other programs.

    [noparse][[/noparse]Edit] Removed use of .wait(); changed to .start() -- still not tested by JM because I don't have an ADS1000

    Post Edited (JonnyMac) : 8/31/2009 11:17:53 PM GMT
  • Mike GreenMike Green Posts: 23,101
    edited 2009-08-29 21:07
    1) The Basic_I2C_Driver and the assembly driver both do multibyte operations like the routines you were using, they just organize the operation differently. The actual I2C transfer is a byte at a time with one or more bytes per transaction.

    2) Use James' objects as models for the devices you want to use. He has a whole variety of devices supported. Pick the one that's closest to what you need, then modify his object until it works for the device you want the way you want it.

    3) Although the Basic_I2C_Driver is written to use a pair of I/O pins for SCL and SDA, you could easily modify the routines to use a separate parameter to specify the SDA pin rather than using SCL+1. There's nothing magic in how the routines are written. The assembly routines would be harder to change to use unrelated I/O pins for SCL and SDA, but it could be done.
  • JavalinJavalin Posts: 892
    edited 2009-08-31 11:38
    >I figured javalin's code was a good start for that, but then I got confused by what he was doing with some of it. Hence the comments I left in his code, so it would still be helpful if somebody could straighten me out on my questions there.

    that i2c-code is dead. Use Mikes.

    James
  • MasterCMasterC Posts: 39
    edited 2009-08-31 18:32
    Thanks JonnyMac!· It's helpful to see another i2c implementation (from a quick look, it appears to be more or less the same as Mike's, but with slightly different function names and·syntax style choices, and with separate SDA and SCL assignments).· Where you really went above and beyond is in creating an ADS1100 object to get me started.· I'll see how it goes with that.
    Javalin said...
    that i2c-code is dead. Use Mikes.
    Ok, ok.· But what I'm really trying to get at with those questions is how to make a stand-alone object for my device that can be used from a parent program, with start() and stop() methods and all that.· Your·object sort of did that, but I wasn't sure about some·of it and was·trying to sort it out better in my head.· I guess I'll get the i2c part working·first and·move on·from there.

    Thanks again!
  • MasterCMasterC Posts: 39
    edited 2009-08-31 18:53
    So, I gave JohnnyMac's sample ADS1100 object a try to get started in talking to my device, but it doesn't immediately appear to be working.· I'll continue troubleshooting, but I decided to post here in case the problem is obvious to somebody.

    Basically, I·used JohnnyMac's code, adding the tv_text object and using the following for main:
    pub main
      text.start(12)
      
      i2c.init(26, 27)                                              ' SCL = 26, SDA = 27
      text.str(string(13,"   ADS1100 Demo...",13,13,$C,5," Test talking to the ADC ",$C,1))
      
      repeat
        text.str(string(13,13," Read Config. Register:  "))
        text.out(rdconfig)
            
        text.str(string(13,13," Read Conversion Result:  "))
        text.out(rdadc)  
    

    It hangs up as soon as I do rdconfig apparently in an infinite loop.
    [noparse][[/noparse]Edit:· OK, no it·doesn't--see next post.]

    Thanks for any insight!

    Post Edited (MasterC) : 8/31/2009 7:05:49 PM GMT
  • MasterCMasterC Posts: 39
    edited 2009-08-31 19:02
    Never mind the previous problem; I'm an idiot.· blush.gif·· I forgot to change the SDA and SCL lines to my actual lines (28 & 29).· So now it's not hanging up, but I have some new issues.

    1.· The results of rdconfig and rdadc are both·printing out as inifnity.· What am I doing wrong there?

    [noparse][[/noparse]Edit:· Never mind this one either--I should have used text.hex(rdconfig,2) and text.hex(rdadc,4) for these.]



    2.· Say there is a problem with my SCL and SDA lines--I'd rather not just hang up indefinitely.· How can I detect the problem and return an error instead?

    Thanks!

    Post Edited (MasterC) : 8/31/2009 7:12:48 PM GMT
  • JavalinJavalin Posts: 892
    edited 2009-08-31 19:09
    re (2) - i'd sorta tried that with my code - I think based on somebody else's - I forget...

    If you try to see if the two lines go to high (pulled by the 4.7k pull-up's) without the object started - so the lines are un-driven by the propeller - is one way.· Otherwise some form of timout code specific for your application/device might be the way forward.

    i.e. (pseudo code)

    repeat while SDA==high and SCL==high and highcount < 100
        highcount++
    if highcount=100
        ' is ok
    else
        ' fail.
    


    James
  • MasterCMasterC Posts: 39
    edited 2009-08-31 19:19
    Thanks for the tips, James.· I'll give something like that a try.
    OK, another issue.· The way things·have been·going, I'll probably figure it out myself again as soon as I post, but for the moment I'm stumped.· Using the code below for main in the jm_ADS1100 object, I get "FF" and "FFFF" as the results every time.· According to the device's datasheet, the default config. register value should be "8C."· So, it appears that something isn't quite working right with either the read routines or my hardware setup.
    pub main
      text.start(12)
      
      i2c.init(28, 29)                                              ' SCL = 28, SDA = 29
      text.str(string(13,"   ADS1100 Demo...",13,13,$C,5," Test talking to the ADC ",$C,1))
      
    '  repeat
        text.str(string(13,13," Read Config. Register:  "))
        text.hex(rdconfig,2)
            
        text.str(string(13,13," Read Conversion Result:  "))
        text.hex(rdadc,4)
    
  • JonnyMacJonnyMac Posts: 9,198
    edited 2009-08-31 20:07
    I know the core routines of my i2c object work -- I use them all the time. The code I wrote for you was not tested because I don't have the device; that said, I've done enough I2C stuff to be able to translate docs to code and there's not much to that device. I suggest you use a terminal output to keep things as simple as possible until you get essential device communications working.

    Did you check your device type versus what's in the code (see CON section)?
  • MasterCMasterC Posts: 39
    edited 2009-08-31 20:25
    Hmm...OK, well, I've got an ADS1100A0 and an ADS1100A1 hooked up right now, and I get the same results for both (i.e. for DEV_ID = %1001_0000·or DEV_ID =·%1001_0010), no matter what I use for printing the output.· Also, it hangs up for any invalid device address.· So, something appears·to be·working to at least get some response from correctly addressed devices, but then something else maybe isn't going right, because the response values·appear to be wrong.
  • MasterCMasterC Posts: 39
    edited 2009-08-31 22:48
    OK, I've got something now.· JonnyMac, you say your i2c object is well vetted and proven to work, but I found that, for my device anyway, the problem I was having was in your i2c.wait function.· Basically, you were always setting it to write mode, when for read mode you need to set the lsb of the address to 1.· For now, I made a separate wait function for reads and writes, with the one for reads having the line:
    ackbit := write(id | 1)
    

    instead of:

    ackbit := write(id & $FE)
    

    OK.· So I'm talking to my i2c device now, and it only took a full day's work.· tongue.gif
  • JonnyMacJonnyMac Posts: 9,198
    edited 2009-08-31 23:11
    Vetted for the devices I tend to use.... and you might have been nowhere had forum members not chimed in to assist you; at the beginning you were going nowhere very fast. tongue.gif

    If you have some fixed delay between reads I'd just use .start(). The .wait() method works really well with EEPROMs that might be busy writing when you attempt to access them.
  • MasterCMasterC Posts: 39
    edited 2009-08-31 23:28
    Yeah, don't get me wrong, I appreciate the forum and the helpful people here.· I didn't mean to imply otherwise.· By pointing out the minor issue I found in your code,·I was hoping to return the favor a little bit, in case·anyone else ever needs to use your wait function for something like this.
  • MasterCMasterC Posts: 39
    edited 2009-09-01 23:01
    Well, in case anyone is interested, I have attached what I ended up with for an ADS1100 i2c object.· I have also attached the now slightly modified lower-level i2c driver that I am using (thanks to JonnyMac and others I·borrowed from·for that, as well as to everyone else for the help!).· I'd gladly accept any constructive feedback.


    Post Edited (MasterC) : 9/2/2009 12:18:57 AM GMT
  • JonnyMacJonnyMac Posts: 9,198
    edited 2009-09-01 23:36
    I know this doesn't apply to others but I'd prefer that you take my name off of any code that you modify. If you're re-releasing it then you should take full credit for the code and any support issues that your version might create.
  • MasterCMasterC Posts: 39
    edited 2009-09-01 23:47
    OK...you're talking about the i2c object with your name as the author?· I changed so little of the code, it would have felt like stealing to claim that I was suddenly the author of the whole thing just because I added a couple small routines.· Just trying to give credit where it's due.·
  • JonnyMacJonnyMac Posts: 9,198
    edited 2009-09-02 00:09
    Again, this my personal thing, but I don't like my name on files edited by others. With my exposure via these forums and 10 years with Nuts & Volts I have a lot of code floating around, and far too frequently someone sends me a program that was modified by another programmer and is now broken having nothing to do with me. So... steal from me all you want, just take my name off any listing that you do. <grin> Thanks for understanding.
  • MasterCMasterC Posts: 39
    edited 2009-09-02 00:17
    OK, done.
  • MasterCMasterC Posts: 39
    edited 2009-09-03 17:08
    Hi Guys,

    If anyone is willing to take a peek at my ADS1100 object, I'm just hoping to get some idea if this is a decent way to make an object like this or not.· Did I do anything that is poor form, a waste of resources, confusing, or·a bad idea for some other reason?· The object seems to work fine, and I'm working on several other objects for·other i2c devices.

    Thanks!

    Corey
  • JonnyMacJonnyMac Posts: 9,198
    edited 2009-09-03 22:04
    This is purely a style/visual thing... don't be afraid of white space. The compiler doesn't care, a few extra CRs won't fill your hard drive, and your listings will be easier to read and update. Look at the original methods versus what you added; you'll see a distinct visual difference. The original methods use more white space and are easier on the eye.

    I'm probably different than other programmers because in my "other life" I write film scripts which have a very strict visual structure/look, especially here in Hollywood -- people won't ever read a script that doesn't look right. My point is that if you make your code listings visually appealing others are more likely to feel comfortable with them right away. A listing that is all run together is hard on the eyes and many won't look through and review for this reason.
  • MasterCMasterC Posts: 39
    edited 2009-09-03 23:00
    Thanks, I can see your point there! I have heard it argued the other way, that more spacing just means you can see less code at a time. However, I tend to agree with you. I'll try to space things out next time. I've got to say, you're probably the 1st programmer/actor/electronics guy/script writer/entrepreneur/technical writer·that I've come across.


    As far as the content of the ADS1100 object itself--anybody have any comments?
Sign In or Register to comment.