Shop OBEX P1 Docs P2 Docs Learn Events
I2Cmaster.spin - correct I2C implementation — Parallax Forums

I2Cmaster.spin - correct I2C implementation

shimniokshimniok Posts: 177
edited 2013-08-30 08:38 in Propeller 1
Wanted to share my I2Cmaster.spin in case it is of benefit to others using I2C. It's Spin/PASM and based off a couple other well known objects BUT it respects I2C open collector design and honors slave clock stretching (the reasons why this matter can be found within the object file). The source includes fairly extensive documentation about hardware, I2C protocol and such stuff, plus example code.

Another convenience, you specify any arbitrary SCL and SDA once at init time.

I'll post on obex with a nice description after I work out EEPROM support and do a bit more testing.

I've tested on LSM303DLH, HMC5843, L3G4200D -- example spin files are included in the zip -- and also my ATtiny-based Sharp Ranger I2C converter boards which was the motivation for writing this. :)

Thanks, all.

Michael

Comments

  • JonnyMacJonnyMac Posts: 9,107
    edited 2013-08-27 07:37
    Since you've take then time to write this in PASM, you may want to consider updating it so that it is clock speed agnostic. I -- and many others -- use 6.25 MHz crystals in some projects, and in a few of my 5 MHz boards I don't run the PLL at 16x. The code, as written, only works (as expected) at 80MHz.

    Also... you've got timing and _STACK parameters in your top objects and in your I2C child object. This could confuse newcomers. I try to keep that stuff in the top object. In fact, the manual says that _STACK is ignored if in a child object.
  • Oldbitcollector (Jeff)Oldbitcollector (Jeff) Posts: 8,091
    edited 2013-08-27 09:43
    Thank you for sharing this, Michael.
  • shimniokshimniok Posts: 177
    edited 2013-08-27 10:02
    @JohnnyMac - great input, thanks, will update accordingly, make clock agnostic, pull the example code out into a separate spin (as is the norm around here), etc.

    @Jeff - my pleasure
  • ChrisGaddChrisGadd Posts: 310
    edited 2013-08-27 13:20
    Your driver is currently hard-coded to use pins 16 and 17 by your PASM section, just requires a few edits to fix.

    It's a bit minimalist, requiring the user to call the start method, format the device code and call the write method, acks... and as you note that keeps the Spin routine waiting around. I guess I'm a bit lazy and prefer for the I2C driver to handle it all internally while the Spin routine continues about its business. I do like the way you encode the success/fail along with any returned bytes, I might have to borrow that.
  • tdlivingstdlivings Posts: 437
    edited 2013-08-27 14:00
    I tried it out using pins 13,14 and it does nothing. Had your example 1 uncommented.
    Not even a Start wiggle.

    Chris's post explains it.

    I like the minimalist approach, I can walk thru the datasheet step by step.
    I am not against higher level also.

    Tom
  • shimniokshimniok Posts: 177
    edited 2013-08-28 01:27
    Well, poop. :) I've fixed the hardcoded pins (geez I feel like an idiot now); zip updated in OP.

    While I do like having full control over every step of the I2C transaction (mbed provides this option)... there's something to be said for higher level routines (Arduino, mbed). Will dig into that.

    With your input I think we can make this thing quite a bit better.

    I really appreciate the input, everyone.
  • JonnyMacJonnyMac Posts: 9,107
    edited 2013-08-28 11:05
    I had started on my own PASM I2C master a while ago, but never really needed the speed so I didn't bother finishing. Inspired by your project, I may do that now. Like you, I keep in very simple handling the basics: start, write a byte, read a byte, stop. In addition to this, I have write a block and read a block. I use the upper 16 bits of the command value (a long) to specify the hub address to use for the call. In my mind, this is where time is saved; at least within the device block structure (e.g., with an EEPROM).
  • photomankcphotomankc Posts: 943
    edited 2013-08-30 08:38
    Just as a blind suggestion (I have not looked at the code yet). Make sure the object can handle a repeated start. Sounds like it could if just the primitives are supported anyway. From there you can build a SPIN interface to handle convenience functions for reading and writing bytes, words, and longs to a device address.

    I had a PASM object I worked on as well last year. It could get up to 400KHz. I left off at trying to make it multi-cog compatible with locks so that several cogs could be dedicated to their own device on a common I2C bus but that was all handled by SPIN code stringing together primitives and locking until the full transaction was complete. I did succumb to speed envy later and made some combinations in PASM that cut down the gaps induced by slow SPIN code execution between each primitive. Could get some really fast transactions that way.

    Mine was a hack of someone else's driver. I'll have to check yours out. It has the possibility to be much cleaner.
Sign In or Register to comment.