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

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 3
Request group membership
By: Chris Gadd, created: 2013-07-27 | updated: 2015-03-28

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.zip102.52 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!


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