I2C PASM driver, I2C SPIN driver, I2C slave driver (PASM), lots of demos.

Warning message

The Propeller Object Exchange system is decommissioned and replaced with a GitHub repository to house the same existing and future Propeller objects. As of 12/5/2019, this site is read-only. You can continue to browse and download objects from here for a limited time; however, please begin using the Parallax Propeller repository for future reference.
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 3
Request group membership
By: created: 2013-07-27 | updated: 2019-03-16

Includes Spin-based and PASM-based open-drain and push-pull drivers, with methods for reading and writing any number of bytes, words, and longs in big-endian or little-endian format.  All drivers tested with the 24LC256 EEPROM, DS1307 real time clock, MMA7455L 3-axis accelerometer, L3G4200D gyroscope module, MS5607 altimeter module, and BMP085 pressure sensor.  Includes a demo programs for each.

Also includes a polling routine that displays the device address and name of everything on the I2C bus.

Also includes a slave object that runs in a PASM cog with a Spin handler, and provides 32 byte-sized registers for a master running on another device to write to and read from.  Tested okay up to 1Mbps (max speed of my PASM push-pull object).  Includes demo for the slave object.

Newly added multi-master object that can share the bus with other masters, provided of course that the other masters also allow sharing.

Original File Upload
Package icon I2C routines - Archive.zip110.14 KB


I may have found a bug in the I2C slave driver.

In the detect_st_or_sp subroutine in "I2C slave v1.0.spin" there are two occurances of the following:
         if_z          jmp       detect_st_or_sp_ret
I suspect those should actually be:
         if_z          jmp       #detect_st_or_sp_ret
I may be mistaken but my compiler (BST) did emit warnings on those two lines and the latter version also seems more correct to me.

BTW, I'm really impressed with the work you've done on the drivers.  It opens up a bunch of new possibilities for what one can do with the Prop.  Thanks!

Ordinarily you'd be right, but with ret instructions, the contents are the address so it does the same thing.  Only difference is that it saves one clock cycle, at the possible expense of making the code more difficult to read.  I learned that one from Phil Pilgrim's Propeller Tricks and Traps.  http://forums.parallax.com/attachment.php?attachmentid=49618

Interesting, I'll take another look at the code and Tricks and Traps.


How would I read 2-bytes from an I2C device that doesn't require registers to be addressed.

ie. the TI ADS1000 A/D chip just wants to be read and it sequentially sends the 2-byte converter value and optionally a 3rd byte configuration byte.

When I use the I2C.read(addr,0), it doesn't work because the PASM code is sending the register byte while the ADS1000 is expecting the low byte to be sent.

Am I using your code wrong?




Manufacturers never cease to amaze me with their inventive variations on I2C.

Having examined the datasheet, any byte written to the device will be interpreted as a configuration setting.  I would've thought that sending register address 0 would cause it to not start a conversion, remain in continuous conversion mode, with a gain of 1.  It should then have read bits 15 through 8 of the output register.

I2C.read_next(addr) only sends the address byte with read/write set, then reads a single byte, so that should give you the top byte.  Sending the same command a second time might give you the low byte, though I don't see any mention in the datasheet if this thing supports repeated reads.

If it doesn't support repeated reads, then the only way to get both bytes would be with a page_read.  You'll need to make a modification to the PASM section, under :read page, simply comment out the [b]call #send_start[/b] line.  The Send_Start subroutine is responsible for sending the device ID with write bit, then the register address, so this device should work without it.  It will require a two or three byte array to read the received bytes into, as read_page doesn't return an immediate value.

I'll have to consider making a non-standard method that writes and reads an arbitrary number of bytes for all of these edge cases.


Thank you for this great work! I'm now implementing an HTU21D humidity sensor and can't get it to return (other than abort) on writes.  The datasheet is here.  Any ideas or thoughts would help a lot!

Thank you,


Scratch that... Crummy datasheet, but all is well now. Appreciate your code!

- John

I have found a bug in the PASM 1.8od with regards to the eeprom read/write routines. It would never send two bytes for the address. I changed the code as shown below so that it would accept $50 OR $51 so that a 1Mbit eeprom could be accessed.

                        mov       t1,device_byte                                ' Determine if device code is for EEPROM (%101_0xxx)
                        and       t1,#%1111_1101                                ' Clear chip select bits
                        cmp       t1,#%1010_0000              wz                ' Z is set if device is an EEPROM (up to 1Mbit)