Wire Single Byte Read

So one day I was trying to interface to a Freescale MMA8451Q accelerometer, for a project I was working on, and I was having a difficult time getting data back from the registers.  After some investigating I found that this device is not compatible with the Arduino Wire library for I2C devices.  The reason being is that the Wire library does not support the use of the repeated start function as defined by the I2C protocol. 

 

 

For those of you that don't know what a "repeated start" is, it's basically when you issue another start after sending data to an I2C device and prior to requesting data back from a register.

 

A typical sequence used with the Arduino for requesting data from a device usually looks like this:

 

Wire.beginTransmission(I2C_deviceAddress); 

Wire.send(registerLocation);

Wire.endTransmission(); // This function sets the pointer to the registerLocation from where we want

                                                 to read the data

Wire.requestFrom(I2C_deviceAddress,howManyBytes);

 

The problem with the code above is that device address and register location are queued up in a buffer and everything is transmitted at once when the Wire.endTransmission() function is called.  What this means is that the I2C hardware sends a Start Bit, then sends the data and finally sends a Stop Bit.  After the Stop Bit is sent it then, using Wire.requestFrom(), sends another Start bit, reads the data back and finally sends a final Stop Bit.  99 times out of 100 this isn't a problem since most devices will work just fine using this setup.  Unfortunately when your device requires a repeated start instead of a stop then start you'll have to either use another IC or try and modify the Wire (actually the TWI) library to try and make it work. Unfortunately modifying the TWI library is a job in of itself so I just went ahead pulled bits and pieces from the library and also tried to incorporate many of the suggestions that seem to be floating around the message boards.

 

The new version of the I2C library has more flexibility, higher throughput and in some functions up to 40% reduction in code size.  The new library does not support Slave functions as of yet.  For those wanting to take advantage of the increased throughput and reduced code size but would like to use the same naming conventions, I've included most of the Wire library function names. Below is a list of the functions available in the library.

 

Function:         I2c.begin()  - enables the I2C hardware

Parameters:   none

Return:            none

 

Function:         I2c.end()  - disables the I2C hardware

Parameters:   none

Return:            none

 

Function:         I2c.setSpeed(fast) - enables high speed 400kHz

Parameters:   (boolean)fast:  1 - high speed, 0 - low speed(default)

Return:            none

 

Function:         I2c.pullup(activate) - enables/disables internal pullup resistors

Parameters:   (boolean)activate: 1 - enable internal pullup resistors(default), 0 - disable internal pullup

                          resistors

Return:             none

 

Function:         I2c.timeOut(timeOut) - Allows the user to program a time out limit to prevent

                        and recover from I2C bus lockups.  I2C bus lockups have a tendency to freeze

                        a program which typically requires a power cycle to restart your progrm. This

                        allows the user to define a time out in which the I2C will release itself and reinitialize

                        and continue on with the next function.  Setting the value to zero will disable the function.

                        On a side note, be careful with setting too low a value because some devices support clock

                        stretching which can increase the time before an acknowledgement is sent which could be

                        misconstrued as a lockup.

                        If a lock up occurs the returned parameters from Read and/or Writes will contain a 1.

Parameters:    (uint16_t)timeOut: 1 - 65535 milliseconds. (ie 1000 = 1 second time out), 0 - disabled (default)

Return:             none

 

Function:         I2c.scan() - scans the bus for I2C devices and reports back each 7 bit address.  The timeout

                        feature was implemented so if there is a problem with the bus during the scan, it will display

                        on Serial Monitor that there was a problem.

Parameters:     none

Return:             none

 

Function:         I2c.write(address, registerAddress) - initate an I2C write operation with no data sent.

                          Typically used to set the "pointer" to a register address

Parameters:   (uint8_t)address:  7 bit I2C slave address

                          (uint8_t)registerAddress: Address of the register as per the datasheet

Return:             0 - successful write

                          More details to come.  Returns actual error code per Atmel Datasheet

 

Function:         I2c.write(address, registerAddress, data) - initate an I2C write operation, single data byte.

                          Typically used to send a single byte of data to a register address

Parameters:   (uint8_t)address:  7 bit I2C slave address

                          (uint8_t)registerAddress: Address of the register as per the datasheet

                          (uint8_t)data: Single byte of data

Return:             0 - successful write

                          More details to come.  Returns actual error code per Atmel Datasheet

 

Function:         I2c.write(address, registerAddress, *data) - initate an I2C write operation, array of char.

                          Typically used to send an array of char starting at registerAddress location.  As a side

                          note there is no restriction on how many bytes may be sent unlike the Wire library

                          which has a 32 byte restriction

Parameters:   (uint8_t)address:  7 bit I2C slave address

                          (uint8_t)registerAddress: Address of the register as per the datasheet

                          (char)*data: array of characters

Return:             0 - successful write

                          More details to come.  Returns actual error code per Atmel Datasheet

 

Function:         I2c.write(address, registerAddress, *data, numberBytes) - initate an I2C write operation,

                          array of bytes. Typically used to send an array of bytes starting at registerAddress location. 

                          As a side note there is no restriction on how many bytes may be sent unlike the Wire library

                          which has a 32 byte restriction

Parameters:   (uint8_t)address:  7 bit I2C slave address

                          (uint8_t)registerAddress: Address of the register as per the datasheet

                          (uint8_t)*data: array of bytes

                          (uint8_t)numberBytes: The number of bytes in the array to be sent

Return:             0 - successful write

                          More details to come.  Returns actual error code per Atmel Datasheet

 

Function:          I2c.read(address, numberBytes) - initiate a read operation from the current position of

                           slave register pointer. The bytes will be stored in an internal buffer and will have the

                           32 byte size restriction.  Data can be read out of the buffer using I2c.receive().

Parameters:   (uint8_t)address:  7 bit I2C slave address

                          (uint8_t)numberBytes: The number of bytes to be read

Return:            More details to come.  Returns actual error code per Atmel Datasheet.  Unlike the Wire

                          library the read operation will not return the number of bytes read, instead it will return

                          the error code which can be used for debugging.

 

Function:          I2c.read(address, numberBytes, *dataBuffer) - initiate a read operation from the current

                           position of slave register pointer. The bytes will be stored in the dataBuffer. 

                           As a side note there is no restriction on how many bytes may be received unlike the Wire

                           library which has a 32 byte restriction

Parameters:   (uint8_t)address:  7 bit I2C slave address

                          (uint8_t)numberBytes: The number of bytes to be read

                          (uint8_t)*dataBuffer: array to store read data

Return:            More details to come.  Returns actual error code per Atmel Datasheet.  Unlike the Wire

                          library the read operation will not return the number of bytes read, instead it will return

                          the error code which can be used for debugging.

 

Function:          I2c.read(address, registerAddress, numberBytes) - initiate a write operation to set the

                           pointer to the registerAddress, then sending a repeated start (not a stop then start) and

                           store the number of bytes in an internal buffer.  The 32 byte size restriction is imposed

                           for this function.  Data can be read out of the buffer using I2c.receive().

Parameters:   (uint8_t)address:  7 bit I2C slave address

                          (uint8_t)registerAddress: Starting register address to read data from

                          (uint8_t)numberBytes: The number of bytes to be read

Return:            More details to come.  Returns actual error code per Atmel Datasheet.  Unlike the Wire

                          library the read operation will not return the number of bytes read, instead it will return

                          the error code which can be used for debugging.

 

Function:          I2c.read(address, registerAddress, numberBytes, *dataBuffer) -initiate a write operation

                           to set the pointer to the registerAddress, then sending a repeated start (not a stop then start)

                           and store the number of bytes in the dataBuffer.

                           As a side note there is no restriction on how many bytes may be received unlike the Wire

                           library which has a 32 byte restriction

Parameters:   (uint8_t)address:  7 bit I2C slave address

                          (uint8_t)registerAddress: Starting register address to read data from

                          (uint8_t)numberBytes: The number of bytes to be read

                          (uint8_t)*dataBuffer: array to store read data

Return:            More details to come.  Returns actual error code per Atmel Datasheet.  Unlike the Wire

                          library the read operation will not return the number of bytes read, instead it will return

                          the error code which can be used for debugging.

 

Function:         I2c.available()  - number of unread bytes stored in the internal 32 byte buffer

Parameters:   none

Return:            number of unread bytes

 

Function:         I2c.receive()  - returns the first unread byte of the internal buffer.

Parameters:   none

Return:           first unread byte of the internal buffer

 

CARRY OVER FUNCTIONS FROM WIRE LIBRARY

I decided to remove all the Wire legacy functions from the library

 

 

As mentioned above the I2C library has a faster throughput and a significantly smaller code size.  Below is a comparison of transfer speeds and compiled code size for a few of the most common functions. The original Wire library adds about 796 bytes to your sketch when included whereas the I2C library only adds 140 bytes. 

 

NOTE: I2C/Wire refers to the use of legacy Wire library functions in the I2C library. There is a also a link for each example that shows an actual timing diagram so you can see the differences. All times referenced below are in microseconds and code size is in bytes.

 

NOTE: The times listed below are no longer valid up to the latest Rev.  I will try and post updated times if I get a chance.

 

Single Byte Write Function (includes register location and 1 data byte)

  • Wire            - 1680 bytes, 3062 microseconds (image)
  • I2C/Wire     - 868 bytes, 2935 microseconds (image)
  • I2C               - 866 bytes, 2903 microseconds (image)

Single Byte Read Function (includes set pointer to register address and read 1 byte)

  • Wire             - 1826 bytes, 4324 microseconds (image)
  • I2C/Wire      - 1182 bytes, 4077 microseconds (image)
  • I2C               - 1082 bytes, 4067 microseconds (image)

Six Byte Read Function (reads 6 bytes instead of one, very common read function)

  • Wire             - 1826 bytes, 9131 microseconds (image)
  • I2C/Wire      - 1182 bytes, 8747 microseconds (image)
  • I2C               - 1082 bytes, 8614 microseconds (image)

Six Byte Read Function (reads 6 bytes but uses external buffer)

  • Wire              - not supported
  • I2C/Wire       - not supported
  • I2C                - 1060 bytes (code size is reduced further using external buffer)

 

Rev 5 Changes

- Removed the use of interrupts from the library so all TWI state changes are polled

- Added calls to lockup() function in most functions to combat arbitration problems

- Fixed scan() function which left timeout set to 80 msec when finished

- Changed address range in scan() function back to 0 - 0x7F

- Removed all Wire legacy functions

Rev 4 Changes

- Fixed problem to make it compatible with 8MHz clock speeds

Rev 3 Changes

- Compatible with Arduino 1.0

- new function called scan() which will scan the bus for all I2C devices and report back their

  7 bit addresses.  It will also monitor the bus for a timeout and will report back that there is a

  problem with the bus in Serial Monitor.  This is usually indicative of one of the lines shorted to ground

- return values for read() and write() functions will now return back where, in the communication sequence

  the timeout, if enabled, occurred.  These new return values do not apply to the legacy Wire functions.

return values for new functions that use the timeOut feature
will now return at what point in the transmission the timeout
occurred. Looking at a full communication sequence between a
master and slave (transmit data and then readback data) there
a total of 7 points in the sequence where a timeout can occur.
These are listed below and correspond to the returned value:
1 - Waiting for successful completion of a Start bit
2 - Waiting for ACK/NACK while addressing slave in transmit mode (MT)
3 - Waiting for ACK/NACK while sending data to the slave
4 - Waiting for successful completion of a Repeated Start
5 - Waiting for ACK/NACK while addressing slave in receiver mode (MR)
6 - Waiting for ACK/NACK while receiving data from the slave
7 - Waiting for successful completion of the Stop bit

All possible return values:
0:             Function executed with no errors
1 - 7:        Timeout occurred, see above list
8 - 0xFF   See datasheet for exact meaning

 

Rev 2 includes a user definable time out feature to prevent and recover I2C bus lockups.

The library is available for download HERE Rev5

  (previous revisions  Rev4  Rev3,  Rev2 , Rev1)

Please give it a try and let me know if you have any problems or suggestions....

 

 

Comments   

# Randy Glenn 2011-08-17 15:30
This looks like it'll be quite useful - though a write function that doesn't take a registerAddress might be nice. Some homebrew I2C devices don't seem to use a register address for writes (which confuses me), and other I2C devices (like the 24LC256 EEPROM) use multi-byte addresses. Maybe a I2c.write(addre ss, *registerAddres s, addressLength, *data, numberBytes) would help for the EEPROMs.

I think I'll have to play with this when I get home tonight!
# Wayne Truchsess 2011-08-18 15:39
Quoting Randy Glenn:
This looks like it'll be quite useful - though a write function that doesn't take a registerAddress might be nice. Some homebrew I2C devices don't seem to use a register address for writes (which confuses me), and other I2C devices (like the 24LC256 EEPROM) use multi-byte addresses. Maybe a I2c.write(address, *registerAddress, addressLength, *data, numberBytes) would help for the EEPROMs.

I think I'll have to play with this when I get home tonight!

Technically when sending bytes to a slave device there is no difference between data and an address. In other words let's say you have a three byte address and three bytes of data. You could use the write(address, regaddress, *data) by making the first byte of your multibyte address equal to regaddress and then combine the rest of the address and data together into *data.
# Jez Weston 2012-07-29 05:27
Hi All,

Does anyone have any working code for reading from an EEPROM using the I2C library. I've just spent a weekend failing to get this up and running.

The hardware itself is fine (Arduino Nano and a 32 kB EEPROM), using the EEPROM1024 and Wire libraries I can happily read and write.

However, using the I2C library, I'm getting stuck. I've tried both the approaches of setting the register address using write and then reading from that position, and the approach of using a long read and can't get anything to work.

So I've tried:
uint8_t MSB = (uint8_t)((read Address & 0xFF00) >> 8);
uint8_t LSB = (uint8_t)(readA ddress & 0xFF);
I2c.write( addressOfEEPROM , MSB, LSB );
followed by:
rdata = I2c.read( (uint8_t)addressOfEEPROM , (uint8_t)1);

and I've tried using Ruud Marten's extension to I2C to support 16-bit addresses:
I2c.read( (uint8_t)addressOfEEPROM , (uint16_t) readAddress, numberBytes, dataBuffer );

I get bytes, but not from the correct locations. So anyone done this before and willing to share working code, or any pointers where to look for where I am doing it wrong.
# Thomas Backman 2012-08-04 20:40
If you haven't solved it yet, you might be in luck! I just wrote and released (released minutes ago, I saved a link to this post) an Arduino library for the 24XX1025 I2C EEPROMs.
https://github.com/exscape/electronics/tree/master/Arduino/EEPROM

Note that the EEPROM library uses the "I2C16" library I have there, which is Rev 5 of Wayne's modified to use 16-bit register addresses and support acknowledge polling. If you get both the I2C16 and EEPROM_24XX1025 folders and unpack them both to the Arduino "libraries" folder, it should work... for those models, that is.
Still, you should be able to extract the tiny bit that does simple reads and modify it to fit.

/Thomas
# Jez Weston 2012-08-04 20:53
That's awesome!

At a first glance, it looks like exactly what I'm after. I'll dig into it this week (this weekend is already lost to untangling library dependencies).

Thanks very much indeed.
# Iouri Goussev 2011-08-24 03:35
Hi, GCC spits warnings when it see while(blah); you can probably safely replace it with while(blah) {}
# Wayne Truchsess 2011-08-25 13:18
Quoting Iouri Goussev:
Hi, GCC spits warnings when it see while(blah); you can probably safely replace it with while(blah) {}

Which IDE version are you running?
+1 # Steffen Frei 2011-08-27 18:20
Hi,

I tried your library with my Arduino UNO and an STM gyroscope, and it works out great.
There is one big issue I noticed though: When I request data from the sensors very often, the UNO randomly gets stuck. This does not happen to often, only like once per 10000 requests.
My apllication runs 2000 requests per second though, which means the Arduino almost instantly gets stuck. I tried to find the mistake and found the function it occured from:
I2C::read(uint8_t address, uint8_t registerAddress , uint8_t numberBytes)
I took a look at your library and found that the while-loop in recieveByte could be the reason.
Is there a way to trigger a timeout if no data is received in time? Or could it be the slave that has an error? As I said, it works like 10000 times and once it doesn't, which I can't explain to myself.
Anyways, this is a great piece of work and I'm glad I found it.
# Wayne Truchsess 2011-08-27 20:59
Quoting Steffen Frei:
Hi,

I tried your library with my Arduino UNO and an STM gyroscope, and it works out great.
There is one big issue I noticed though: When I request data from the sensors very often, the UNO randomly gets stuck. This does not happen to often, only like once per 10000 requests.
My apllication runs 2000 requests per second though, which means the Arduino almost instantly gets stuck. I tried to find the mistake and found the function it occured from:
I2C::read(uint8_t address, uint8_t registerAddress, uint8_t numberBytes)
I took a look at your library and found that the while-loop in recieveByte could be the reason.
Is there a way to trigger a timeout if no data is received in time? Or could it be the slave that has an error? As I said, it works like 10000 times and once it doesn't, which I can't explain to myself.
Anyways, this is a great piece of work and I'm glad I found it.

Glad to hear you like it. As for the delay I've been thinking about adding a user defined delay as a separate function. Unfortunately without a logic analyzer it's tough to narrow down where it is freezing.

You mentioned you're using an STM gyroscope, is it by any chance the L3G4200D? I ask because I'm waiting on my boards for that IC now and I can probably try and reproduce the problem and see where it occurs.

Are you having the same problem with the Wire library? If not can you try the separate read and write operations and let me know if the freeze is happening with the write or read?
# Steffen Frei 2011-08-28 08:48
Yes, it is the L3G4200D!
So this morning I rewrote the code using the Wire-library, and within 10 minutes of testing the error only occured twice. So this is not sure, but the error occured at the endTransmission ()-tag when sending the registeradress to the slave.
Apparently, the error occurs when sending something.
By the way, I noticed that calculating angles with the Wire-library is nearly impossible since it'S way slower than yours.
Do you want me to send you my source code?
I'm not a very advanced programmer, so maybe you could double-check that I didn't do a mistake.
Thanks!
# Wayne Truchsess 2011-08-28 11:57
Quoting Steffen Frei:
Yes, it is the L3G4200D!
So this morning I rewrote the code using the Wire-library, and within 10 minutes of testing the error only occured twice. So this is not sure, but the error occured at the endTransmission()-tag when sending the registeradress to the slave.
Apparently, the error occurs when sending something.
By the way, I noticed that calculating angles with the Wire-library is nearly impossible since it'S way slower than yours.
Do you want me to send you my source code?
I'm not a very advanced programmer, so maybe you could double-check that I didn't do a mistake.
Thanks!

By all means send the code along.
A few other things to check in the mean time are making sure your pull up resistors are sized appropriately and since this IC supports fast mode, try running it at 400kHz and see if it makes a difference.
# Steffen Frei 2011-08-28 13:53
Okay so the code is available here:

http://www.steffenbf.lima-city.de/

I already am using fast mode, and for the external pullups I chose 10 kΩ.
# Wayne Truchsess 2011-08-28 14:20
Quoting Steffen Frei:
Okay so the code is available here:

http://www.steffenbf.lima-city.de/

I already am using fast mode, and for the external pullups I chose 10 kΩ.

What kind of level translator are you using also because it's not a 5v tolerant device?

I took a quick look at your code and wanted to make a quick suggestion that will also help speed it up. There are six bytes total that comprise the data for X,Y and Z and you're using individual read commands (I2c.read(gyro, x,1), etc...) when you should read all 6 bytes at once (I2c.read(gyro, x,6)) since the gyro auto increments the address pointer. It should save you about another 100 microseconds through each iteration.

10k pullups may be lowering your overall bus speed because they're a little on the high side for 400kHz. You might want to try and drop it down to something like 4.7k or 3.3k .
# Steffen Frei 2011-08-28 14:33
I'm using the 3.3V output of the Arduino as a power supply.
Thanks for your suggestion, I will try it as soon as I can.
I'm also going to re-solder the pullups and replace them with 4.7k resistors. Do you think this had any effect on the protocol itself or that this maybe even led to the error?
Thanks for your help!
# Wayne Truchsess 2011-08-28 14:45
The I2C lines in the Arduino are internally pulled to 5V so you really should use some kind of level translation. At a minimum you should disable the internal pull up resistors using I2c.pullup(0).
# Steffen Frei 2011-08-28 15:14
Oh lol I remember me wondering why the 3.3V supply was unstable :oops:
I will also try that!
# Steffen Frei 2011-08-28 16:27
just for getting this right: is it possible that the arduino does not always read the 3.3V as HIGH, so the protocol gets messed up? What would you use as a level translation?
By the way, excuse my bad English, I'm from Germany.
# Wayne Truchsess 2011-08-28 16:49
Quoting Steffen Frei:
just for getting this right: is it possible that the arduino does not always read the 3.3V as HIGH, so the protocol gets messed up? What would you use as a level translation?
By the way, excuse my bad English, I'm from Germany.

Yes it is possible, especially when using 400kHz with improperly sized pullup resistors. Unfortunately the only way to tell is by putting an oscilloscope on the lines and reading the signals. You can see here www.dsscircuits.com/articles/effects-of-varying-i2c-pull-up-resistors.html of improperly sized pullups with respect to higher speeds. As for what to use for level translators there are several different available. I know Sparkfun has a logic level converter that uses MOSFETs and is sold at many different online sites. I also sell one that uses TI chip instead and removes the need for pullups www.dsscircuits.com/i2c-level-converter.html
# Steffen Frei 2011-08-28 17:06
Okay, thanks a lot I guess I will order one of those.
As for the reading of multiple bytes at the same time, I always get the same numbers for all six registers (they do change, but are all the same).
Sorry for spamming you with questions!
# Wayne Truchsess 2011-08-28 17:19
Quoting Steffen Frei:
Okay, thanks a lot I guess I will order one of those.
As for the reading of multiple bytes at the same time, I always get the same numbers for all six registers (they do change, but are all the same).
Sorry for spamming you with questions!

No problem, you caught me at a good time as I'm sitting here in a hurricane with no electricity so there really isn't anything else to do :lol:

As for the reason your multibyte read isn't working is because this chip is weird! Almost every other I2C device I've seen that supports auto address increment does it automatically. This IC only does it if you tell it too. THe datasheet says to make the most significant bit of the first data address location (in this case X_L) a one to use auto increment. So in other words you need to change:
#define GYRO_OUT_X_L B0101000
to
#define GYRO_OUT_X_L B10101000

and then use I2c.read(GYRO,GYRO_OUT_X_L,6);
and everything should work fine.
+1 # Steffen Frei 2011-08-28 18:13
Okay so I ordered the level converter, and it'll be here in one or two weeks, I guess that'll fix the issue.
Thanks a lot and good luck for the hurricane!
-1 # elendal 2011-09-04 03:22
Quoting Wayne Truchsess:
Quoting Iouri Goussev:
Hi, GCC spits warnings when it see while(blah); you can probably safely replace it with while(blah) {}

Which IDE version are you running?


Eclipse with CrossPack-AVR-2 0100115. I just find it easier to manage multiple files plus it offers better navigation.
# Wayne Truchsess 2011-09-20 14:48
Rev 2 is now available. It contains an additional function for user definable time out to prevent and recover from bus lock ups. The "while" issue should also be resolved.
# Noah 2011-09-27 02:38
Hi, Nice i2c library! Its seems good solid fix for the buggy Wire library. I am going to use this in some projects, but it would be great if you post the code up on github, google code or something. Better for the community to contribute, or even fork it someday if you stop maintaining it.

Keep up the great work!
# Wayne Truchsess 2011-09-27 15:41
Quoting Noah:
Hi, Nice i2c library! Its seems good solid fix for the buggy Wire library. I am going to use this in some projects, but it would be great if you post the code up on github, google code or something. Better for the community to contribute, or even fork it someday if you stop maintaining it.

Keep up the great work!

Thanks Noah. Learning to use Github is on my to-do list, so I hope to get that going soon...need to find some good tutorials on it first.
# Eero af Heurlin 2011-10-13 18:49
Looks good, haven't yet tested it but will need it since I have some led drivers that (seem to) need repeated start to work properly with auto-incrementi ng register address.

Anyway, It would be good if you used a public version control system so we could track the work and possibly contribute in a sensible way.
# Eero af Heurlin 2011-10-13 21:24
And seems others have asked for the same, should have been more thorough in reading the comments... Well, count it as one more vote...

Anyway, github is super-easy to get started with (they basically walk you through the whole thing) and you can worry about the collaboration features later when someone actually sends a patch ("pull-request" ) your way.
+1 # Raider 2011-10-18 14:02
Thank you for the library. It worked great with the RX8025 clock on the Seeeduino Stalker V2.0 board. It will now replace Wire.
# waseg 2012-04-29 16:12
Hi!
I am trying to do the same...to make this library work on the same hardware with the same chip, because the wire library was crappy. Can you please share your code? I am a bit stuck.
Best regards
Vaclav
# Tim 2011-11-01 00:25
Hi Wayne
Tks for your new I2C library. I have been using it to work with an MCP3422 A/D converter for my quadcopter.
#define MCP3422_ADDRESS 0X68
I2c.read(MCP342 2_ADDRESS,3);
data =I2c.receive()
# Eero af Heurlin 2011-11-13 07:57
Needed to be able to use this as a git submodule so created a repo on Github, please let me know when you have your "official" repo up so I can start following that instead.

https://github.com/rambo/I2C
# dominic.storey 2011-11-21 01:39
Do you have working code for the MMA8451Q? I'm about to embark on writing a library - but if you have done it already.....

thanks Dominic
# Wayne Truchsess 2011-11-21 14:54
Quoting dominic.storey:
Do you have working code for the MMA8451Q? I'm about to embark on writing a library - but if you have done it already.....

thanks Dominic

Sorry Dominic, I didn't get very far with the accelerometer. I had some problems with the board layout which was affecting the sensor readings. I changed direction and went with the BMA180 for my project instead.

On a side note I can tell you that Freescale did a fantastic job with writing application notes for this family of sensors. They are probably the best app notes for accelerometers that I've seen with several examples included also. They can all be downloaded from their site if you're interested.
# Chris 2011-11-30 21:54
@Dominic

Here is the tested and working code for the MMA8453Q which should be similar if not identical to the MMA8451Q other than the odd register. Comment the code out and uncomment the WHO AM I section start of with once you get 0x58 then you're half way there as you can read registers. If you don't get the write result check the circuit.

Oh and many thanks Wayne Truchsess without this I would have been stuck great work. Sorry about the two comments but I couldn't put all the code in one.

Hope this helps,
Cheers,
Chris

#include
//I2c.h is available at:
//http://www.dsscircuits.com/articles/arduino-i2c-master-library.html
//or directley...
//http://dsscircuits.com/images/code/I2C_Rev2.zip

#define ACC 0x1D

void setup()
{
I2c.begin();
Serial.begin(9600);
}


}
# Chris 2011-11-30 21:56
Well I tried to post it in two but it wont let me :oops: so I'll upload it somewhere else and let you know where sorry,

Cheers
Chris
# Chris 2011-11-30 22:27
Hi,

I've posted the code on the Arduino forum it can be found here:

http://arduino.cc/forum/index.php/topic,80897.msg610939.html#msg610939

Many Thanks Chris
# Bill 2011-12-08 12:45
Thank you Wayne for this excellent library. Many of the needed I2C functions are now available. I tried using it but unfortunately it didn't fix a hardware issue I have.

This library and the Wire library both toggle the data immediately at the low going edge of SCL. For custom hardware and some chips, if SDA goes high while SCL is going low, the hardware thinks this is a STOP on the I2C bus because the timing margin is too small.

Is it possible for you to add some delay between the low going edge of SCL and the toggling of the SDA line? This would fix my timing issue and would probably end some weird I2C bugginess for a lot of other people.
# Wayne Truchsess 2011-12-08 15:13
Quoting Bill:
Thank you Wayne for this excellent library. Many of the needed I2C functions are now available. I tried using it but unfortunately it didn't fix a hardware issue I have.

This library and the Wire library both toggle the data immediately at the low going edge of SCL. For custom hardware and some chips, if SDA goes high while SCL is going low, the hardware thinks this is a STOP on the I2C bus because the timing margin is too small.

Is it possible for you to add some delay between the low going edge of SCL and the toggling of the SDA line? This would fix my timing issue and would probably end some weird I2C bugginess for a lot of other people.

Hi Bill,
If I'm understanding you correctly you're looking for a slight delay on each SCL cycle. If that's the case then I don't think it's possible. The microcontroller s used in the Arduino platform don't have access to lower level timing for individual signals. It's all handled internally by the hardware.

Just thinking out loud though I'm wondering if you could offset the timing between SDA and SCL by offsetting the pull up resistors.
# Bill 2011-12-13 05:01
Wayne, thanks for confirming what I thought was true. I was hoping there was a way to add a delay to the individual I2C signals for adjusting timing, but is hardware controlled. I can do this in hardware myself but it would be great if I could do it with software.

Changing the edge speed by changing the pull-up resistors can help, but sometimes not enough delay can be gained by this solution and it will not work.

One last suggestion for the library would be to add a flag that causes the ACK to be ignored. This can be very useful in debugging new designs.
# Jez Weston 2012-01-03 03:36
*phew*

Thanks for saving me from the grief that is the Wire library.

One minor note, for use with the new version of the Arduino IDE, I had to make minor changes to the I2C.cpp & I2C.h files, replacing the "#include WProgram.h" with:
#if (ARDUINO >= 100)
#include
#else
#include
#endif
And then all was good.
# Sami 2012-01-03 14:11
Hi Wayne,

I have been talking to you on the Arduino Forum about this website.

At the moment I am trying to implement your solution and even the example does not seem to work.

I am using Arduino IDE 1.0.

I installed Rev2.

I placed the folder in libraries, and it struggled.

I removed the I2C folder from that folder and placed it in the libraries folder. It still does not compile cleanly.

Giving me the following errors:

In file included from HMC5883L.cpp:9:
C:\Users\Abdul Mughal\Desktop\ ARDUINO SOFTWARE\arduin o-1.0-windows\a rduino-1.0\libr aries\I2C/I2C.h :34:22: error: WProgram.h: No such file or directory
In file included from HMC5883L.cpp:9:
C:\Users\Abdul Mughal\Desktop\ ARDUINO SOFTWARE\arduin o-1.0-windows\a rduino-1.0\libr aries\I2C/I2C.h :70: error: 'boolean' has not been declared
C:\Users\Abdul Mughal\Desktop\ ARDUINO SOFTWARE\arduin o-1.0-windows\a rduino-1.0\libr aries\I2C/I2C.h :71: error: 'boolean' has not been declared
C:\Users\Abdul Mughal\Desktop\ ARDUINO SOFTWARE\arduin o-1.0-windows\a rduino-1.0\libr aries\I2C/I2C.h :101: error: 'boolean' has not been declared
# Wayne Truchsess 2012-01-03 14:23
Quoting Sami:
Hi Wayne,

I have been talking to you on the Arduino Forum about this website.

At the moment I am trying to implement your solution and even the example does not seem to work.

I am using Arduino IDE 1.0.

I installed Rev2.

I placed the folder in libraries, and it struggled.

I removed the I2C folder from that folder and placed it in the libraries folder. It still does not compile cleanly.

Giving me the following errors:

In file included from HMC5883L.cpp:9:
C:\Users\Abdul Mughal\Desktop\ARDUINO SOFTWARE\arduino-1.0-windows\arduino-1.0\libraries\I2C/I2C.h:34:22: error: WProgram.h: No such file or directory
In file included from HMC5883L.cpp:9:
C:\Users\Abdul Mughal\Desktop\ARDUINO SOFTWARE\arduino-1.0-windows\arduino-1.0\libraries\I2C/I2C.h:70: error: 'boolean' has not been declared
C:\Users\Abdul Mughal\Desktop\ARDUINO SOFTWARE\arduino-1.0-windows\arduino-1.0\libraries\I2C/I2C.h:71: error: 'boolean' has not been declared
C:\Users\Abdul Mughal\Desktop\ARDUINO SOFTWARE\arduino-1.0-windows\arduino-1.0\libraries\I2C/I2C.h:101: error: 'boolean' has not been declared

Sorry Sami but the current library is not 1.0 compatible yet. If you look at the previous comment it looks like Jez shows the changes he made to get it to work with 1.0
# Sami 2012-01-03 14:29
Hi Wayne

Thanks for getting back so quickly (as usual!).

I would like to thank Jez out here as well for providing that solution.

Tried his solution, but it wasn't working, till I noticed he had missed out the file names in the code he provided.

So to re-iterate, if you change '#include ' with the following code:

#if defined(ARDUINO ) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

It should work.

The example code has now compiled. I will carry on and start changing my old code to your library, and should be able to report back telling you how well it works.

Kind Regards!
# Jez Weston 2012-01-03 20:42
Yup, sorry about that, but I only noticed this morning that the comment box on this website altered my code. My original text had the include file names in angle brackets and it seems anything in angle brackets is removed from the post. Putting the file names in double quotes works, as above.
# adumas 2012-01-09 15:26
Hi... I just came across your work... Looks great... Any chance it would work with an ATTiny85? If not, can it be modified? What would be involved?
# Wayne Truchsess 2012-01-09 15:47
Quoting adumas:
Hi... I just came across your work... Looks great... Any chance it would work with an ATTiny85? If not, can it be modified? What would be involved?

Unfortunately I don't have an ATTiny85 to test it on.
# Charles Kim 2012-05-03 15:44
Hi, Wayne.

It is realy good approach. I am also looking for a similar solution for Attiny85 or its cousins. As you know, ATtiny48/45/25 actually don't have I2C hardware built-in and , instead, they use USI for I2C communication. I am in need to make Attiny45 read from and write on an ISP(image signal processor) which has over 1000 register addresses inside. It requires a repeated start to read something from its internal registers. Your approach to start from repeated start seems very proper but I am not sure it will work with USI hardware of Attiny45.
# Wayne Truchsess 2012-01-10 18:00
Latest revision is out. The library is now compatible with Arduino 1.0 . I've also added a new function called scan() to scan the bus for I2C devices and report back their address. I modified the return values when using the timeout feature to return back where in the sequence the timeout actually happened. This should be helpful for people when troubleshooting lockup problems.
If anyone finds any problems please let me know. Thanks.
+1 # Wayne Truchsess 2012-01-15 01:26
...and Rev 4 is now online to fix the bug with 8MHz clock speed compatibility.
# Richard Baldwin 2012-01-19 21:00
Hi, Your library saved me a lot of work, but I found a problem. SIGNAL(TWI_vect ) never gets called as the interrupts are not enabled. TWIE is used for initialization but not in the functions.

e.g. In I2C::start

TWCR = (1
# Wayne Truchsess 2012-01-19 23:36
Quoting Richard Baldwin:
Hi, Your library saved me a lot of work, but I found a problem. SIGNAL(TWI_vect) never gets called as the interrupts are not enabled. TWIE is used for initialization but not in the functions.

e.g. In I2C::start

TWCR = (1

Hey Richard. Glad it worked for you. The TWIE bit is once when I2c.begin() is called and, to the best of knowledge, stays set.
# Richard Baldwin 2012-01-20 09:34
Quoting Wayne Truchsess:
Quoting Richard Baldwin:
Hi, Your library saved me a lot of work, but I found a problem. SIGNAL(TWI_vect ) never gets called as the interrupts are not enabled. TWIE is used for initialization but not in the functions.

e.g. In I2C::start

TWCR = (1

Hey Richard. Glad it worked for you. The TWIE bit is once when I2c.begin() is called and, to the best of knowledge, stays set.

Hi Wayne,

I have the 'advantage' of having a system that suffers from regular arbitration failures, so it is easy for me to experiment.

Here is the important bit from the datasheet:

• Bit 0 – TWIE: TWI Interrupt Enable
When this bit is written to one, and the I-bit in SREG is set, the TWI interrupt request will be activated
for as long as the TWINT Flag is high. (21.9.2)

After experimenting, I now read this to mean that when TWINT goes low, the TWIE bit is cleared and remains cleared when TWINT goes high again. It makes sense, as otherwise there would be no way of turning the interrupts off.

Adding TWIE wherever the TWCR is set, works great (see example below). The returned status is F8h whenever the bus is reset, as no relevant state is information available (Table 21-6). I am in the process of saving the TWI status in SIGNAL(TWI_vect ) and providing an access member to return the saved value when F8h is returned following a reset.

uint8_t I2C::start()
{
unsigned long startingTime = millis();
TWCR = (1
# Wayne Truchsess 2012-01-20 14:34
Quoting Richard Baldwin:
Quoting Wayne Truchsess:
Quoting Richard Baldwin:
Hi, Your library saved me a lot of work, but I found a problem. SIGNAL(TWI_vect) never gets called as the interrupts are not enabled. TWIE is used for initialization but not in the functions.

e.g. In I2C::start

TWCR = (1

Hey Richard. Glad it worked for you. The TWIE bit is once when I2c.begin() is called and, to the best of knowledge, stays set.

Hi Wayne,

I have the 'advantage' of having a system that suffers from regular arbitration failures, so it is easy for me to experiment.

Here is the important bit from the datasheet:

• Bit 0 – TWIE: TWI Interrupt Enable
When this bit is written to one, and the I-bit in SREG is set, the TWI interrupt request will be activated
for as long as the TWINT Flag is high. (21.9.2)

After experimenting, I now read this to mean that when TWINT goes low, the TWIE bit is cleared and remains cleared when TWINT goes high again. It makes sense, as otherwise there would be no way of turning the interrupts off.

Adding TWIE wherever the TWCR is set, works great (see example below). The returned status is F8h whenever the bus is reset, as no relevant state is information available (Table 21-6). I am in the process of saving the TWI status in SIGNAL(TWI_vect) and providing an access member to return the saved value when F8h is returned following a reset.

uint8_t I2C::start()
{
unsigned long startingTime = millis();
TWCR = (1

Good catch Richard. I was under the impression it only needed to be set once. I'll scan the code and update it in all the right locations and have another rev posted later today. Thanks again!
-1 # Richard Baldwin 2012-01-20 15:20
Hi Wayne,

Whenever the TWI bus is reset, the status is also reset and is returned as F8h.

I've now added an access function called I2C.errno to get the TWI_STATUS that I've saved before the bus reset is done.

I've put my files at
www.s-tech.demon.co.uk so you can do a Windiff.

Let me know when you have the files and I will remove them.

Richard.
# Jim 2012-01-22 08:33
This looks like a very nice library. I am wondering, can it be used inside an ISR? I have a board with an NXP dual UART that uses I2C to talk to the CPU. The UART can generate an IRQ on the CPU when its buffer is full, and I would like to service this UART with a ring buffer. Same for sending.

The Arduino Wire library uses interrupts itself, so this was a fail. I was going to write my own library, but I ran across this one and am hoping I can spare myself the effort.

Thanks!
# D9W 2012-04-20 10:17
@Jim - Just wondering which NXP UART you are using?
# Jim 2012-04-20 11:36
Its an SC16IS752IPW,112

Digikey's part number is: 568-4016-5-ND
# D9W 2012-04-20 12:18
Thanks, I might have to look into this chip. I like how Wayne has done his •GPS - I2C GPS Shield - But I really would like to see if I can get my LS20031 from Sparkfun to work. I need something that will not tie up the Arduino RX pin 0 and TX pin 1 and has a large buffer. At least this chip would not tie up memory on the Arduino.
# Wayne Truchsess 2012-01-22 14:29
Quoting Richard Baldwin:
Hi Wayne,

Whenever the TWI bus is reset, the status is also reset and is returned as F8h.

I've now added an access function called I2C.errno to get the TWI_STATUS that I've saved before the bus reset is done.

I've put my files at
www.s-tech.demon.co.uk so you can do a Windiff.

Let me know when you have the files and I will remove them.

Richard.

After enabling the interrupts I found that the scan() function no longer worked. Digging deeper and after several modifications I started thinking that maybe using the ISR is the wrong approach. I found that addressing an unused address would lock the bus up, so I had to make changes to individual statuses inside the ISR to fix the problem. I then started to notice the code inside the ISR was starting to look more and more like the original Arduino Wire library which, at least to me, was starting to look like a band aid approach. At this point I took a step back and found that when it comes to arbitration problems, we may not need an ISR at all. Arbitration issues will only generate 1 of 4 status codes (0x38,68,78 or B0) in only two of the functions called (address and data). So I'm wondering if removing the ISR completely and simply comparing the status and executing the appropriate functions outside an ISR would be more beneficial. The original status for the arbitration error would be the return value so there would be no need for your additional function. The only trade off I see might be timing, is it slower to service the codes to free up the bus outside the ISR or inside the ISR. I have a feeling it might actually be faster outside the ISR and it may help others looking for a non interrupt driven library (see above comment). I'm going to do some speed testing now and see if there's a difference. Input from anyone on this is more than welcome.
# Wayne Truchsess 2012-01-22 14:32
Quoting Jim:
This looks like a very nice library. I am wondering, can it be used inside an ISR? I have a board with an NXP dual UART that uses I2C to talk to the CPU. The UART can generate an IRQ on the CPU when its buffer is full, and I would like to service this UART with a ring buffer. Same for sending.

The Arduino Wire library uses interrupts itself, so this was a fail. I was going to write my own library, but I ran across this one and am hoping I can spare myself the effort.

Thanks!

Hi Jim. Good question. See the reply comment I just made above regarding interrupts. I'm looking into the possibility of removing the interrupts completely. I'll know more later if this approach will work or not.
# Wayne Truchsess 2012-01-22 15:17
Quoting Wayne Truchsess:
Quoting Richard Baldwin:
Hi Wayne,

Whenever the TWI bus is reset, the status is also reset and is returned as F8h.

I've now added an access function called I2C.errno to get the TWI_STATUS that I've saved before the bus reset is done.

I've put my files at
www.s-tech.demon.co.uk so you can do a Windiff.

Let me know when you have the files and I will remove them.

Richard.

After enabling the interrupts I found that the scan() function no longer worked. Digging deeper and after several modifications I started thinking that maybe using the ISR is the wrong approach. I found that addressing an unused address would lock the bus up, so I had to make changes to individual statuses inside the ISR to fix the problem. I then started to notice the code inside the ISR was starting to look more and more like the original Arduino Wire library which, at least to me, was starting to look like a band aid approach. At this point I took a step back and found that when it comes to arbitration problems, we may not need an ISR at all. Arbitration issues will only generate 1 of 4 status codes (0x38,68,78 or B0) in only two of the functions called (address and data). So I'm wondering if removing the ISR completely and simply comparing the status and executing the appropriate functions outside an ISR would be more beneficial. The original status for the arbitration error would be the return value so there would be no need for your additional function. The only trade off I see might be timing, is it slower to service the codes to free up the bus outside the ISR or inside the ISR. I have a feeling it might actually be faster outside the ISR and it may help others looking for a non interrupt driven library (see above comment). I'm going to do some speed testing now and see if there's a difference. Input from anyone on this is more than welcome.

Looking a little more into it the valid arbitration state in Master mode is 0x38. The other three listed are only valid in Slave mode so it drops the compare statement down to one.
# Richard Baldwin 2012-01-22 18:17
The only downside of removing the ISR is that the user would have be perform any error handling.

One thing that would ease this would be to make the lockup function public (and maybe rename is to reset). Then if the library returns a non-timeout error, the user has something to call in the case of an arbitration error.

HTH
# Wayne Truchsess 2012-01-22 19:55
Quoting Richard Baldwin:
The only downside of removing the ISR is that the user would have be perform any error handling.

One thing that would ease this would be to make the lockup function public (and maybe rename is to reset). Then if the library returns a non-timeout error, the user has something to call in the case of an arbitration error.

HTH

Sorry Richard, I didn't understand the first statement. All the error handling is done internally and error code returned will be the error that caused the problem and the bus will be in a reset state and ready to use so there is no real need to call the lockup function.
Here is the link to the beta dsscircuits.com/images/code/I2C_beta.ziplibrary I'm testing now. I'm unable to simulate an arbitration condition so it's a little difficult to test that portion. The one thing that looks good so far is the multimaster aspect. I have two separate arduino's polling the same accelerometer at varying rates and so far there's no lockups and each one receives the data it has requested. When the fist one has the bus the second waits for the bus to free up and then initiates it's transaction. Whereas I repeated the same test with Wire and it would lockup frequently and swap returned data between the two masters.
# Richard Baldwin 2012-01-22 20:10
E.g In the start function, an error can occur without timing out. lockup is only called when a timeout occurs.

I.e If an arbitration 38h condition occurs TWSR is set and TWINT is set. The loop ends without timing out and the TWI-STATUS is returned.
# Wayne Truchsess 2012-01-22 20:19
Quoting Richard Baldwin:
E.g In the start function, an error can occur without timing out. lockup is only called when a timeout occurs.

I.e If an arbitration 38h condition occurs TWSR is set and TWINT is set. The loop ends without timing out and the TWI-STATUS is returned.
Hmmm...the datasheet eludes to the fact that arbitration errors only happen after the address and/or data no after a start condition. Unfortunately I can't repeat an arbitration issue at start. From what I'm seeing it's testing the bus before sending the start, it then sees it as busy (multi-master) and then waits for the bus to free up and then initiates it's transaction. Do you by chance have an easy way to simulate the arbitration issue you see? I'd love to test it on the beta library.
# Richard Baldwin 2012-01-22 20:52
I will run the beta library on my 'faulty' system and see what happens. I'll pay special attention to the start condition.

I had assumed that you couldn't lose arbitration on a start as you are transmitting a '0' and '0' always wins.

If a second master is already generating a clock and data, I'm not sure what happens if the clocks collide. At the point you are sending a start your clock will be a '1'. If the other clock is '0' have you already lost arbitration? TBH, I don't know
# Wayne Truchsess 2012-01-22 21:13
Quoting Richard Baldwin:
I will run the beta library on my 'faulty' system and see what happens. I'll pay special attention to the start condition.

I had assumed that you couldn't lose arbitration on a start as you are transmitting a '0' and '0' always wins.

If a second master is already generating a clock and data, I'm not sure what happens if the clocks collide. At the point you are sending a start your clock will be a '1'. If the other clock is '0' have you already lost arbitration? TBH, I don't know

If you have access to an analyzer you may want to look at the signals also. I overlayed the signals from the beta library and the changes with the interrupts enabled from your link and there seems to be a problem with the interrupts enabled (bottom half of picture). I'm not sure why but there is some serious clock stretching going on with the interrupts enabled.
www.dsscircuits.com/images/images/I2C_Comparison.jpg
# Richard Baldwin 2012-01-22 21:48
Whilst looking for something else in the datasheet, I found the following which suggest a start can fail without timing out.

In section 21.5.5

• When a bus error has occurred due to an illegal START or STOP condition.

AND

under Figure 21-10

2. When the START condition has been transmitted, the TWINT Flag in TWCR is set, and
TWSR is updated with a status code indicating that the START condition has successfully
been sent.
3. The application software should now examine the value of TWSR, to make sure that the
START condition was successfully transmitted. If TWSR indicates otherwise, the application
software might take some special action, like calling an error routine.

So maybe start just needs the following line added - no ISR required.

uint8_t I2C::start()
{
unsigned long startingTime = millis();
TWCR = (1
# Wayne Truchsess 2012-01-22 21:51
Quoting Wayne Truchsess:
Quoting Jim:
This looks like a very nice library. I am wondering, can it be used inside an ISR? I have a board with an NXP dual UART that uses I2C to talk to the CPU. The UART can generate an IRQ on the CPU when its buffer is full, and I would like to service this UART with a ring buffer. Same for sending.

The Arduino Wire library uses interrupts itself, so this was a fail. I was going to write my own library, but I ran across this one and am hoping I can spare myself the effort.

Thanks!

Hi Jim. Good question. See the reply comment I just made above regarding interrupts. I'm looking into the possibility of removing the interrupts completely. I'll know more later if this approach will work or not.

Hey Jim I have an update for you. I tried using Wire inside an ISR and it didn't work either. Using the beta library in the comments above I was able to use I2C inside an interrupt routine. While it's never a good idea to stay inside an ISR too long it does appear to be possible to transfer data.
# Jim 2012-01-23 08:39
Quoting Wayne Truchsess:
Quoting Wayne Truchsess:
Quoting Jim:
This looks like a very nice library. I am wondering, can it be used inside an ISR? I have a board with an NXP dual UART that uses I2C to talk to the CPU. The UART can generate an IRQ on the CPU when its buffer is full, and I would like to service this UART with a ring buffer. Same for sending.

The Arduino Wire library uses interrupts itself, so this was a fail. I was going to write my own library, but I ran across this one and am hoping I can spare myself the effort.

Thanks!

Hi Jim. Good question. See the reply comment I just made above regarding interrupts. I'm looking into the possibility of removing the interrupts completely. I'll know more later if this approach will work or not.

Hey Jim I have an update for you. I tried using Wire inside an ISR and it didn't work either. Using the beta library in the comments above I was able to use I2C inside an interrupt routine. While it's never a good idea to stay inside an ISR too long it does appear to be possible to transfer data.


Thanks Wayne that's fantastic! I agree that staying inside the ISR too long is extremely bad. It's standard practice for servicing a UART though. Polling the I2C UART to see if it needs data is a huge waste of time. If it turns out that its taking too long to fetch data from the UARTs 32 character buffer, I have a few options. Worst case I guess I could set a flag inside the ISR and poll the flag. That would suck but its better than polling across the I2C bus. I am servicing 4 UARTs at the same time, two inside my MPU and two on this external I2C device.

I ordered a logic analyzer yesterday. I am really going to be swamped this week but I need to prove this hardware is going to work, so I'll probably make time to try this.

Thanks very much!

Jim
# Wayne Truchsess 2012-01-23 12:58
Quoting Jim:
Quoting Wayne Truchsess:
Quoting Wayne Truchsess:
Quoting Jim:
This looks like a very nice library. I am wondering, can it be used inside an ISR? I have a board with an NXP dual UART that uses I2C to talk to the CPU. The UART can generate an IRQ on the CPU when its buffer is full, and I would like to service this UART with a ring buffer. Same for sending.

The Arduino Wire library uses interrupts itself, so this was a fail. I was going to write my own library, but I ran across this one and am hoping I can spare myself the effort.

Thanks!

Hi Jim. Good question. See the reply comment I just made above regarding interrupts. I'm looking into the possibility of removing the interrupts completely. I'll know more later if this approach will work or not.

Hey Jim I have an update for you. I tried using Wire inside an ISR and it didn't work either. Using the beta library in the comments above I was able to use I2C inside an interrupt routine. While it's never a good idea to stay inside an ISR too long it does appear to be possible to transfer data.


Thanks Wayne that's fantastic! I agree that staying inside the ISR too long is extremely bad. It's standard practice for servicing a UART though. Polling the I2C UART to see if it needs data is a huge waste of time. If it turns out that its taking too long to fetch data from the UARTs 32 character buffer, I have a few options. Worst case I guess I could set a flag inside the ISR and poll the flag. That would suck but its better than polling across the I2C bus. I am servicing 4 UARTs at the same time, two inside my MPU and two on this external I2C device.

I ordered a logic analyzer yesterday. I am really going to be swamped this week but I need to prove this hardware is going to work, so I'll probably make time to try this.

Thanks very much!

Jim

If time is an issue, there's always the option of using Fast Mode, if your UART supports it.
# Jim 2012-01-23 09:27
Well the scan() function works! It found the device on my board, plus each of the two shields I had stacked up. So far so good!
# Richard Baldwin 2012-01-23 20:05
Hi Wayne,

I ran the beta library all day and I can confirm that you can get a non-08h status when transmitting the start bit. In one case this was due someone putting a cellphone right next to the breadboard :sad:

I also used an open collector TTL chip on the clock line fed by a clock generator and also by a noise generator.

In a nutshell, collisions are detected on a multiple master system whilst transmitting the start and in the case of faults/interfer ence.

The ATmega chips seem quite good at filtering out noise but there are limits.

Using too large values of pull-up resistors not only degrade the shape but also the noise immunity (you knew this already).

Out of sync clock stretching, faults or poor implementation in slave devices can also cause collisions (my faulty system has a LTC6904 oscillator chip that randomly pulls the clock down).

RE: clock stretching with the ISR enabled...
I didn't have access to the Corelis today, so I used a storage scope. I didn't see the very large delays you were seeing but it is slower. I didn't have time to check but I think the ISR is being called even for successful status changes. I.e. 08h (start sent) calls the ISR.

I had another think about the ISR, and I think it's a good idea to remove it anyway. The ISR only comes into it's own in a true interrupt driven library. Including it has an overhead but because you are polling TWINT you have none of the advantages.

HTH
# Wayne Truchsess 2012-01-23 20:27
Quoting Richard Baldwin:
Hi Wayne,

I ran the beta library all day and I can confirm that you can get a non-08h status when transmitting the start bit. In one case this was due someone putting a cellphone right next to the breadboard :sad:

I also used an open collector TTL chip on the clock line fed by a clock generator and also by a noise generator.

In a nutshell, collisions are detected on a multiple master system whilst transmitting the start and in the case of faults/interference.

The ATmega chips seem quite good at filtering out noise but there are limits.

Using too large values of pull-up resistors not only degrade the shape but also the noise immunity (you knew this already).

Out of sync clock stretching, faults or poor implementation in slave devices can also cause collisions (my faulty system has a LTC6904 oscillator chip that randomly pulls the clock down).

RE: clock stretching with the ISR enabled...
I didn't have access to the Corelis today, so I used a storage scope. I didn't see the very large delays you were seeing but it is slower. I didn't have time to check but I think the ISR is being called even for successful status changes. I.e. 08h (start sent) calls the ISR.

I had another think about the ISR, and I think it's a good idea to remove it anyway. The ISR only comes into it's own in a true interrupt driven library. Including it has an overhead but because you are polling TWINT you have none of the advantages.

HTH

The ISR should be called anytime there is a change to TWI_STATUS (error or not) and should fall through the switch statement if it doesn't match any cases. From what I can tell the overhead from using ISR compared to polling shows no difference in execution time so I think I'm going to stick with polling.

You mentioned a non 08 return when sending the start bit, my question is did the bus free up and were you able to continue on or did you have to reinit anything? My primary concern is having the bus free up if there is some type of lockup situation. The problem with Wire was that there were several circumstances where it would just lockup.
# Richard Baldwin 2012-01-23 20:49
I think polling is marginally faster. Obviously if you do both it takes longer - as was the case when I added the TWIE (there was the overhead of calling and returning from the ISR AND the polling.

The non-08h status from start was a 38h and yes I did have to call lockup as I had lost arbitration. I've only ever seen 08h and 38h returned by start.

Adding the one line of code as in my post of 2012-01-22 16:48 solves this and then it never locks up - however much I abuse it and that's with a known faulty device too!
# Wayne Truchsess 2012-01-23 21:24
Quoting Richard Baldwin:
I think polling is marginally faster. Obviously if you do both it takes longer - as was the case when I added the TWIE (there was the overhead of calling and returning from the ISR AND the polling.

The non-08h status from start was a 38h and yes I did have to call lockup as I had lost arbitration. I've only ever seen 08h and 38h returned by start.

Adding the one line of code as in my post of 2012-01-22 16:48 solves this and then it never locks up - however much I abuse it and that's with a known faulty device too!

If you're referring to "TWCR = 1" then I can't add that code as it would enable the interrupts again. I just added a conditional statement to start() to run lockup() if the return value is 0x38. This is actually what the code was doing for you before when you added your line of code to start(), it jumped to the ISR and ran the two lines of code (same as lockup). I uploaded the new beta file to the same link as above so if you want to give it a try and let me know I would appreciate it. Apparently you're one of the few people that can reproduce these problems semi consistently. Thanks again Richard for all your help.
# Richard Baldwin 2012-01-23 21:57
Quoting Wayne Truchsess:
... I just added a conditional statement to start() to run lockup() if the return value is 0x38...

This is what I was talking about.

I'm trying to keep hold of my faulty system - it's just too useful to fix :D

From my experiments today, I'm sure this latest beta wlll run without errors. I had already added the lockup to start in the previous beta.

It ran for a good six hours, logged 270 38h errors and recovered every time.

With the wire library, the system would only work with for about 10 minutes at best and was impossible to recover intelligently. I.e. without resetting the I2C bus and slaves

This was with all the right retry/error handling outside the library.
# Richard Baldwin 2012-01-24 17:55
The beta library has been running all day without a problem and is still running.

I've had lost arbitration errors return during start (but not repeated start), SLA and data. The count for each was 41, 164 and 320 respectively.


In all cases the system was recovered and the correct error was returned.

I have to say that as it stands now, the library is not only fast and reliable but easy to integrate into existing I2C projects.

BTW, the overhead from calling the ISR on a succesful start status was about 30 clocks. As there was no 08h in the switch statement, it has to do all 7 compares and 7 branches.
# Wayne Truchsess 2012-01-24 18:02
Quoting Richard Baldwin:
The beta library has been running all day without a problem and is still running.

I've had lost arbitration errors return during start (but not repeated start), SLA and data. The count for each was 41, 164 and 320 respectively.


In all cases the system was recovered and the correct error was returned.

I have to say that as it stands now, the library is not only fast and reliable but easy to integrate into existing I2C projects.

BTW, the overhead from calling the ISR on a succesful start status was about 30 clocks. As there was no 08h in the switch statement, it has to do all 7 compares and 7 branches.

Awesome! I'll post the final beta as a Rev 5 shortly then. I hope others don't mind but I removed all references to the Wire legacy commands in the library. Again thanks for all the testing and follow ups.
# Jim 2012-01-24 21:26
Quoting Wayne Truchsess:
Quoting Richard Baldwin:
The beta library has been running all day without a problem and is still running.

I've had lost arbitration errors return during start (but not repeated start), SLA and data. The count for each was 41, 164 and 320 respectively.


In all cases the system was recovered and the correct error was returned.

I have to say that as it stands now, the library is not only fast and reliable but easy to integrate into existing I2C projects.

BTW, the overhead from calling the ISR on a succesful start status was about 30 clocks. As there was no 08h in the switch statement, it has to do all 7 compares and 7 branches.

Awesome! I'll post the final beta as a Rev 5 shortly then. I hope others don't mind but I removed all references to the Wire legacy commands in the library. Again thanks for all the testing and follow ups.


One thing I did notice last night, the scan() function hangs if there are two devices on the bus with the same address. I don;t know if that's a bug or a feature.
# Richard Baldwin 2012-01-24 23:00
Quoting Jim:
One thing I did notice last night, the scan() function hangs if there are two devices on the bus with the same address. I don;t know if that's a bug or a feature.


Hi Jim,
Hi Wayne,

I've just tried a scan with latest version on a system with three indentical expanders. They all have the same address and I don't get a hang.

All three ACK the SLA+W at the same time but this is not a problem as they are wire-anded.

Can I ask what devices they were?

HTH,
Richard
# Jim 2012-01-24 23:14
Well my main board has an NXP SC16IS752IPW,11 2. Then there is the multi-serial shield from Hackastrich, which has the same thing on it. Then there is the datalogger shield from Adafruit, which has a Maxim DS1307 on it.

Both of the UARTs were set to address 0x4D and scan() just sat there. Perhaps I didn;t wait long enough?
# Wayne Truchsess 2012-01-24 23:19
Quoting Jim:
Well my main board has an NXP SC16IS752IPW,112. Then there is the multi-serial shield from Hackastrich, which has the same thing on it. Then there is the datalogger shield from Adafruit, which has a Maxim DS1307 on it.

Both of the UARTs were set to address 0x4D and scan() just sat there. Perhaps I didn;t wait long enough?

That's odd because there is an 80ms timeout programmed into the scan function. If you're not using the Rev5 you may have been using the irst beta I uploaded that didn't have the lockup call in the start function. Try it with Rev 5.
# Richard Baldwin 2012-01-25 00:13
If one or more of the UARTS is not hardwired for I2C then that could be a problem. That's all I can think of.

In theory, you don't need a timeout for the scan as any ACK has to occur during the clock cycle following the W bit of the SLA+W.
# Jim 2012-01-27 16:51
A little off topic, I hop you guys don't mind my ignorance...

My brandy new logic 16 analyzer is here! I hooked it up, and am wondering what I should see on the bus while scan() is running?

What I see is a lot of frames that say "Setup write to [0x62] + NAK". It looks like scan() is just trying to write to every address, working its way from bottom to top. But it seems to skip some addresses. For example, it skipped 0x49 and 0x4D, which is where scan() finds my devices. I was hoping to see some data moving to and from those addresses.

Am in getting this right?
# Richard Baldwin 2012-01-27 17:01
You should see a start, a 7-bit slave address, a write bit, an ACK from a device if it exists and a stop.

The master generates an 'extra' clock immediately after the SLA+W. If the slave exists is generates the ACK during this 'extra' clock.
# Richard Baldwin 2012-01-27 17:52
I've just had a look at my notes.

I've this before where an analyser, sees the Start+SLA+W+NAC K+Stop as a complete frame but not the Start+SLA+W+ACK +Stop. It expects a data byte following the ACK.

If you look in 'scope mode' you will see the correct SDA bits.

Is there an option to show incomplete frames or frame fragments?

HTH
# Richard Baldwin 2012-01-27 18:10
Hi Wayne,

Ideally the stop() call in scan should be moved so that it immediately follows the SLA+W. At present, there is a delay in calling stop due to the Serial calls on finding a device.

HTH,
Richard

void I2C::scan()
{
uint16_t tempTime = timeOutDelay;
timeOut(80);
uint8_t totalDevicesFou nd = 0;
Serial.println( "Scanning for devices...pleas e wait");
Serial.println( );
for(uint8_t s = 0; s
# Wayne Truchsess 2012-01-28 13:45
Quoting Richard Baldwin:
Hi Wayne,

Ideally the stop() call in scan should be moved so that it immediately follows the SLA+W. At present, there is a delay in calling stop due to the Serial calls on finding a device.

HTH,
Richard

void I2C::scan()
{
uint16_t tempTime = timeOutDelay;
timeOut(80);
uint8_t totalDevicesFound = 0;
Serial.println("Scanning for devices...please wait");
Serial.println();
for(uint8_t s = 0; s

It shouldn't make that much of a difference but I'll post those changes in the next rev. There's a few more functions I'm thinking about adding so it will be a little while. Thanks for pointing that out.
# Jim 2012-01-28 12:54
Can someone help me figure this out please?

I'm trying to do something really, really simple. I am using an NXP UART, an SC16IS752, which has a scratch pad register one byte wide. All I am trying to do is to write a byte to it and read it back. When I do the read, I get 0 back instead of what I wrote.

I must be doing something really simple wrong. Here is my code:

#include

#define NXP_UART 0x49
#define SPR 0x07

void setup()
{
Serial.begin(96 00);
Serial.println( "Writing A to SPR...");

uint8_t buf[2];
buf[1] = NULL;

I2c.begin();

I2c.write(NXP_U ART, SPR, 'A');

delay(50);

I2c.read(NXP_UA RT, SPR, 1, buf);

Serial.print("R ead from SPR: ");
Serial.println( buf[0], HEX);
}

void loop() {}
# Wayne Truchsess 2012-01-28 13:34
Quoting Jim:
Can someone help me figure this out please?

I'm trying to do something really, really simple. I am using an NXP UART, an SC16IS752, which has a scratch pad register one byte wide. All I am trying to do is to write a byte to it and read it back. When I do the read, I get 0 back instead of what I wrote.

I must be doing something really simple wrong. Here is my code:

#include

#define NXP_UART 0x49
#define SPR 0x07

void setup()
{
Serial.begin(9600);
Serial.println("Writing A to SPR...");

uint8_t buf[2];
buf[1] = NULL;

I2c.begin();

I2c.write(NXP_UART, SPR, 'A');

delay(50);

I2c.read(NXP_UART, SPR, 1, buf);

Serial.print("Read from SPR: ");
Serial.println(buf[0], HEX);
}

void loop() {}

Hi Jim,
Try printing the return values from I2c.write and read to make sure there aren't any problems. Return values of zero mean everything is good. Also can you confirm 0x49 (A1 tied to VDD and A0 tied to GND) is the correct address you need and not 0x48 (A1 tied to VDD and A0 tied to VDD).
# Richard Baldwin 2012-01-28 13:33
The first thing I would do is print out the return values from I2c.write and I2c.read.
# Richard Baldwin 2012-01-28 15:02
Hi Jim,

I think I see the problem, try defining SPR as 0x38 and see if that works.

The Register address byte is not a simple number...
bit 7 - not used
bit 6:3 UART’s internal register
bit 2 - not used
bit 1 Channel select.
bit 0 - not used

HTH,
Richard
# Jim 2012-01-28 17:49
Thank you Richard and Wayne!! Yes, the problem was the incorrect definition for SPR. I'll review the data sheet and fix those up.

Do you mind some simple minded questions? I had my new Logic 16 hooked up and captured that whole thing.

The first thing I see is a green dot, followed by a write with he address of the device, followed by the register value and then the data byte, and finally a red square. Simple enough.

But to read it back, I then see another write, followed by the register address, then a green dot, then a setup to read and finally the data byte and a red square.

Why is there another write issued?

Also, I changed the code to have an end() call. Is that needed?

Thank you very much guys! Now I can write my test code to validate my prototype before I spend money on boards. This is the UART I want to service inside an ISR.

Code below,thanks again!

#include

#define NXP_UART 0x49
#define SPR 0x38

void setup()
{
Serial.begin(96 00);
Serial.println( "Writing to SPR...");

uint8_t buf[2];
buf[1] = NULL;

I2c.begin();
I2c.write(NXP_U ART, SPR, 0xAA);
I2c.end();

I2c.begin();
I2c.read(NXP_UA RT, SPR, 1, buf);
I2c.end();

Serial.print("R ead from SPR: ");
Serial.println( buf[0], HEX);
}

void loop() { }
# Wayne Truchsess 2012-01-28 18:20
Quoting Jim:
Thank you Richard and Wayne!! Yes, the problem was the incorrect definition for SPR. I'll review the data sheet and fix those up.

Do you mind some simple minded questions? I had my new Logic 16 hooked up and captured that whole thing.

The first thing I see is a green dot, followed by a write with he address of the device, followed by the register value and then the data byte, and finally a red square. Simple enough.

But to read it back, I then see another write, followed by the register address, then a green dot, then a setup to read and finally the data byte and a red square.

Why is there another write issued?

Also, I changed the code to have an end() call. Is that needed?

Thank you very much guys! Now I can write my test code to validate my prototype before I spend money on boards. This is the UART I want to service inside an ISR.

Code below,thanks again!

#include

#define NXP_UART 0x49
#define SPR 0x38

void setup()
{
Serial.begin(9600);
Serial.println("Writing to SPR...");

uint8_t buf[2];
buf[1] = NULL;

I2c.begin();
I2c.write(NXP_UART, SPR, 0xAA);
I2c.end();

I2c.begin();
I2c.read(NXP_UART, SPR, 1, buf);
I2c.end();

Serial.print("Read from SPR: ");
Serial.println(buf[0], HEX);
}

void loop() { }

That's because the read operation is actually a write and read operation. To read a value back from a register you need to set the address pointer to the register you want to read the data from. Basically the read operation you used goes like this. Start--> Slave Address Write --> Set Address Pointer (SPR) --> Repeated Start --> Slave Address Read --> Receive the Data Byte --> Stop.

And to answer your other question, you really don't need the stop() function.
# Jim 2012-01-28 20:03
Okay thanks again guys!!! You both have been a tremendous help! Thanks to your help, this library and my Logic 16, I was able to write my prototype code and test my hardware in pretty short time.

Basically, I have one of these UARTs tied to the INT2 pin of an ATMega 1284P. I needed to prove that when I pulled one of the GPIO pins to ground that I could trigger an ISR, and inside the ISR identify the cause of the interrupt and then clear the interrupt register.

The GPIO pin will be connected to some circuit that detects power went away, so while my big cap drains I'll have time to gracefully close files on an SD card.

So now I am confident I can do that and service two incoming serial streams inside an ISR.

This is all fantastic, thanks again!
# Wayne Truchsess 2012-01-28 21:21
Quoting Jim:
Okay thanks again guys!!! You both have been a tremendous help! Thanks to your help, this library and my Logic 16, I was able to write my prototype code and test my hardware in pretty short time.

Basically, I have one of these UARTs tied to the INT2 pin of an ATMega 1284P. I needed to prove that when I pulled one of the GPIO pins to ground that I could trigger an ISR, and inside the ISR identify the cause of the interrupt and then clear the interrupt register.

The GPIO pin will be connected to some circuit that detects power went away, so while my big cap drains I'll have time to gracefully close files on an SD card.

So now I am confident I can do that and service two incoming serial streams inside an ISR.

This is all fantastic, thanks again!

Glad to hear it Jim. If time is a concern you can always set it to fast mode, setSpeed(1) , which will decrease the transfer time by roughly a factor of 4.
# Jim 2012-01-28 22:52
Quoting Wayne Truchsess:

Glad to hear it Jim. If time is a concern you can always set it to fast mode, setSpeed(1) , which will decrease the transfer time by roughly a factor of 4.


Hm, I'll give that a try. Do I have to call it after each begin() call?

Come to think of it, do i need to call begin() more than once?
# Wayne Truchsess 2012-01-28 23:39
Quoting Jim:
Quoting Wayne Truchsess:

Glad to hear it Jim. If time is a concern you can always set it to fast mode, setSpeed(1) , which will decrease the transfer time by roughly a factor of 4.


Hm, I'll give that a try. Do I have to call it after each begin() call?

Come to think of it, do i need to call begin() more than once?

Functions like begin(), setSpeed() and pullUp() only need to be called once and are typically located in the setup() function.
# Jim 2012-01-29 00:39
Quoting Wayne Truchsess:
Functions like begin(), setSpeed() and pullUp() only need to be called once and are typically located in the setup() function.


Great! This is much easier than the wire library.
# Richard Baldwin 2012-01-28 23:48
Hi Jim,

Make sure you make full use of those FIFOs and then use multibyte reads whenever the threshold interrupt is triggered. It's many times more efficient that one byte at a time.
# Jim 2012-01-29 00:42
Quoting Richard Baldwin:
Make sure you make full use of those FIFOs and then use multibyte reads whenever the threshold interrupt is triggered. It's many times more efficient that one byte at a time.


Will do! I need to check the data sheet to see what my threshold options are. Ideally I'll probably want to trigger the interrupt at 75% or 80% full, empty it into a ring buffer, wash, rinse, repeat...

But those FIFOs are huge. They are bigger than the default ring buffer size in HardwareSerial library. If I didn't need the data to sit around a bit I might even get away without the ring buffer. But I have the RAM available in mky uC, so I'll probably make my life easy and use it.
# Mark Wilkie 2012-02-05 18:16
Hi Wayne,

This library looks like a life saver. Thanks so much Earlier, you mentioned the following:

"The one thing that looks good so far is the multimaster aspect. I have two separate arduino's polling the same accelerometer at varying rates and so far there's no lockups and each one receives the data it has requested. When the fist one has the bus the second waits for the bus to free up and then initiates it's transaction. Whereas I repeated the same test with Wire and it would lockup frequently and swap returned data between the two masters."

Do you have this code as a sample? I'm basically doing the same thing and would love a base reference.

Thanks!
# Wayne Truchsess 2012-02-05 18:33
Quoting Mark Wilkie:
Hi Wayne,

This library looks like a life saver. Thanks so much Earlier, you mentioned the following:

"The one thing that looks good so far is the multimaster aspect. I have two separate arduino's polling the same accelerometer at varying rates and so far there's no lockups and each one receives the data it has requested. When the fist one has the bus the second waits for the bus to free up and then initiates it's transaction. Whereas I repeated the same test with Wire and it would lockup frequently and swap returned data between the two masters."

Do you have this code as a sample? I'm basically doing the same thing and would love a base reference.

Thanks!

Hi Mark. Unfortunately no I deleted the sketches I was using however there wasn't really anything special about them. If memory serves they were extremely simple sketches. One sketch would request the 6 bytes of acceleration data and the other sketch would request a single byte from the Who Am I register. One sketch had a 2ms delay between requests and the other had a 3ms delay. I used the delays to help randomize the accesses a little. I used different registers between the two sketches so I could tell if one Master received the other Master's data (as was the case using Wire). I then hooked up an analyzer and reviewed all the signals. You could probably use serial prints also if you don't have an analyzer.
# Mark Wilkie 2012-02-05 18:43
Quoting Wayne Truchsess:

Hi Mark. Unfortunately no I deleted the sketches I was using however there wasn't really anything special about them. If memory serves they were extremely simple sketches. One sketch would request the 6 bytes of acceleration data and the other sketch would request a single byte from the Who Am I register. One sketch had a 2ms delay between requests and the other had a 3ms delay. I used the delays to help randomize the accesses a little. I used different registers between the two sketches so I could tell if one Master received the other Master's data (as was the case using Wire). I then hooked up an analyzer and reviewed all the signals. You could probably use serial prints also if you don't have an analyzer.


No worries at all. From looking at things, I agree that it appears straight forward. Thanks again for your quick response and tenacious work on the library.

Cheers
# Gutzy 2012-02-07 21:27
Hi. I thought I would try your library as I'm having some problems with I2C down long wires (100ft!).

I've made some mods I think are worthwhile:
Saved 62 bytes by removing the class member returnStatus and making it a local variable.
Saved 184 bytes by restructuring (reusing code blocks).
Added 466 bytes by introducing setFrequency to allow any frequency down to 500Hz. I run at about 50kHz on 100ft wires.
Added 122 bytes by adding Auto-Timeout feature - this optionally sets the timeout according to the frequency - saves getting long delays rather than error code on failures.
Added 414 bytes by adding re-try feature - useful in noisy environments. Retries a user-defined number of times before reporting a failure.
Added 520 bytes for speedTest - sets safe speed for 100 consecutive sucessful read/writes. (no added bytes if not used).

Let me know if you are interested and i'll send it to anyone who wants it.
# Frans 2013-04-20 08:05
Hello Gutzy,

I'm very interested in you mods. could you send it to me? frans at rampen dot com.

Thanks,

Frans
# Gutzy 2012-02-07 21:36
There appears to be a problem in I2C::sendByte(u int8_t i2cData)

I'm accessing a couple of MCP23009 8-bit I2C drivers. One of them gives Err 0x30 (out of sync) at the line
if (TWI_STATUS == MT_DATA_ACK) return(0);
However, the data is written correctly.

It gives no trouble using the standard wire library. Any idea what the problem / solution might be?
# Wayne Truchsess 2012-02-14 19:06
Quoting Gutzy:
There appears to be a problem in I2C::sendByte(uint8_t i2cData)

I'm accessing a couple of MCP23009 8-bit I2C drivers. One of them gives Err 0x30 (out of sync) at the line
if (TWI_STATUS == MT_DATA_ACK) return(0);
However, the data is written correctly.

It gives no trouble using the standard wire library. Any idea what the problem / solution might be?

Hi Gutzy. Send me a copy of the changes, I'd like to see it. I have a few more changes I need to make and new function I want to add.

As for the problem you're having, could it be timing related due to the different speeds you're using and length of cable? Do you have any plots to look at?
# Gutzy 2012-02-14 22:39
What email address should I send my modified library to?
I have also written a mod for zero-cross triggering which is not in my modified library, but I may add it, along with hardware instructions.
# Wayne Truchsess 2012-02-14 22:42
Quoting Gutzy:
What email address should I send my modified library to?
I have also written a mod for zero-cross triggering which is not in my modified library, but I may add it, along with hardware instructions.

you can send it to admin@dsscircuits.com
# Richard Baldwin 2012-02-14 19:57
Quoting Gutzy:
There appears to be a problem in I2C::sendByte(uint8_t i2cData)

I'm accessing a couple of MCP23009 8-bit I2C drivers. One of them gives Err 0x30 (out of sync) at the line
if (TWI_STATUS == MT_DATA_ACK) return(0);
However, the data is written correctly.

It gives no trouble using the standard wire library. Any idea what the problem / solution might be?


I use the 23009 and 23016 without a problem.

Even when using active pullups, the capacitance causes problems long before you get to 100ft.
# Gutzy 2012-02-16 12:18
I found the problem - it was my fault with an uninitialised data buffer.
I have no trouble using I2C over 100ft wires. I just run it slower - currently at 50000Hz. My modified library automatically adjusts the I2C frequency to get reliable communications.
# Mattias 2012-02-13 15:45
Hi! Nice work with the better code for i2c! I just looked for code for getting the i2c so it can handle the repeted start sequece, but I want it run as a slave. Have you any plans for implement it, or could you give me some ideas for getting that to work?
Br
/Mattias
# Wayne Truchsess 2012-02-14 19:10
Quoting Mattias:
Hi! Nice work with the better code for i2c! I just looked for code for getting the i2c so it can handle the repeted start sequece, but I want it run as a slave. Have you any plans for implement it, or could you give me some ideas for getting that to work?
Br
/Mattias

Hi Mattias. Unfortunately this library is for master only and does not support the slave functions. The Wire library also does not support repeated starts. I did bring this up on the developer's mailing list and I believe they are looking into fixing the repeated start issue in the Wire library.
# Jim 2012-02-19 06:03
Hi Wayne...

Does this library bring HardwareSerial. cpp/.h in?

I ask because I am using a templatized replacement for HardwareSerial, but something somewhere is bringing the Arduino HardwareSerial library in and causing a linker conflict.

Thanks...

Jim
# Jim 2012-02-19 07:10
So after a little experimenting, I learned that if I remove all references to I2c (the include file and the actual calls to the class) my app compiles and links.

If I just add back the I2c.h file, it then compiles and fails to link due to conflicts caused by bringing HardwareSerial. h in.

Then it gets strange. If I edit I2c.h to remove:

#if(ARDUINO >= 100)
#include
#else
#include
#endif

I still have the same link problem. I'm stumped. I checked inttypes.h and it is sure not bringing in hardwareSerial.cpp.

My plan was to see which include files I2c actually needed and maybe add those directly, bypassing Arduino.h. I expected compiler errors. Instead the entire app compiled and failed to link with the same errors.
# Jim 2012-02-19 11:22
Found it! They were, of course, in scan(). I should have thought of that right off. I just commented out the calls to Serial.print() in Scan and all is good now.
# Mat 2012-02-19 18:47
Very good library. Just one comment:
Maybe the pull up resistor should be disabled by default.
I'm using the I2C with a 3.3V device so I pull up the lines externaly to 3.3V.
Disabling the pull up resistor after a I2C.begin will still lead to a short time with the 5V pull up activated, so I modified the library. Maybe this change could benefit to others.
# Mike S. 2012-03-13 15:33
Hi,
Nice article - the library looks interesting. I have 2 questions:
  • What logic analyzer do you use? I just have a scope but a logic analyzer looks very powerful.
  • Why did you remove the use of interrupts and add polling? I saw that the Wire library uses a busy loop which seems counterproducti ve... ties up a 16MHz proc waiting for a 100khz communication. Can you explain?


Thanks.
# Wayne Truchsess 2012-03-13 16:40
Quoting Mike S.:
Hi,
Nice article - the library looks interesting. I have 2 questions:
  • What logic analyzer do you use? I just have a scope but a logic analyzer looks very powerful.
  • Why did you remove the use of interrupts and add polling? I saw that the Wire library uses a busy loop which seems counterproductive... ties up a 16MHz proc waiting for a 100khz communication. Can you explain?


Thanks.

Hi Mike,
I use the Saleae Logic 8 analyzer, it's a great little tool for the price. I think anyone that frequently uses any type communication protocol (Serial, I2C, SPI, etc...) should definitely have an analyzer.

Actually I started with interrupts but by dumb luck I forgot to enable interrupts in the beginning of the code and it was only using polling. Someone pointed out the error and when I turned them back on I started having all kinds of problems. I then started band aiding the problems and soon enough the library starting looking more an more like the Wire library so I abandoned the interrupts completely and as it turns out it appears to be a lot more stable than if it were interrupt driven.

I think the use of interrupts are only really required when using I2C in slave mode anyway. If anything I think the Wire library breaks one of the most important programming principles and that is don't spend too much time inside an ISR. From what I can see they spend a great deal of time inside the ISR, probably would explain some of the stability problems people experience.
# D9W 2012-04-20 11:54
Quoting Wayne Truchsess:

….
I think the use of interrupts are only really required when using I2C in slave mode anyway. If anything I think the Wire library breaks one of the most important programming principles and that is don't spend too much time inside an ISR. From what I can see they spend a great deal of time inside the ISR, probably would explain some of the stability problems people experience.


That might explain why I have been having problems with Mikal Hart’s TinyGPS. I was trying to display on one of Adafruit’s RGB LCDs the output of my LOCOSYS GPS LS20031 using their I2C Backpack for the RGB LCD. TinyGPS was reporting increase Checksum Fail if I used the I2C backpack, but I did not see the increase when I just sent the data to the monitor.

I was sending the data stream directly to the Arduino RX pin and reading the data directly into TinyGPS because the current version of SoftwareSerial has issues with the speed of the LS20031. For some reason Software Serial does not pass all the NMEA messages on to TinyGPS. I even went so far as using a Sparkfun’s NXP’s PCA9306 logic voltage converter and it had no effect on the problem. Sorry for getting off topic, but what you guys were talking about caught my attention about one of the weird things going on when I tired the I2C backpack.
# Jim 2012-04-20 12:06
#D9W

You're probably not going to get that to work. I use that same GPS receiver. First of all, I have seen it occasionally get a checksum wrong. Occasionally.

More importantly, if you're doing much with the data (and you probably are if you're bothering to read it) then you need to use a UART to read the data. Otherwise, you're going to miss characters. The UART has a buffer built in to it. When that buffer is mostly full, then an interrupt is fired off and the ISR comes along and empties the buffer into RAM. This is what Arduino's HardwareSerial. cpp (better known as Serial) does.

Arduino 1.0 has interrupt driven sending and receiving while earlier versions are interrupt driven receive only. There is also a templatized serial library which lets you set the size of teh RAM buffers differently for sending and receiving, and differently for different UARTs.

If you're serious about needing to collect and process the GPS data, then connect the GPS to one of the Arduino's UARTs and mak your life easier.
# D9W 2012-04-20 13:00
Actually I am just after the time for what I am doing (I may use more information when I finely get everything working correctly). As you know TIME only comes from the NMEA’s RMC message (sentences). As you hinted SoftwareSerial only passes GGA sentences and GLL sentences when connected to the LS20031.

I followed Sparkfun’s tutorial for the LS20031 and did a direct dump to the monitor and got 1000 perfect NMEA sentences (Yes, I did print all of them out) , then I used SoftwareSerial and did the same thing and got a mess. At least for TinyGPS to work, TinyGPS only requires GGA sentences and RMC Sentences to spit out all the information you may need. What caught my attention was there wasn’t even a part of the other four types of sentences (GSA, GSV, RMC, and VTG). SoftwareSerial seems only to pass RMC and GLL sentences. Logically SoftwareSerial should have passed something of the other 4 sentences out of 1000 messages. And from what I know of SoftwareSerial there is nothing that should prevent this from happening.

I thought it might be a voltage level issue that’s why I tired the PCA9603 (the LS20031 is a 3.0V part), and your right that didn’t work. Using the Hardware part of the Arduino UART works, but has issues with the check sum for the GPS (though that does not totally explain why when using I2C the check sum error jumps double digits, but when sending the data to the monitor it barley jumps). But what you said about how the Arduino old version was “interrupt driven receive only” might explain why I had the IDE ver 22 working and now under IDE 1.0 it does not. I am a believer in Dedicated Signal Processing, and from what I see Wayne’s GPS shield demonstrates this idea beautifully. Also his way you don’t have to worry about using all the memory for the UART buffer on your main Arduino board. But as I said in a previous post, I am thinking about maybe trying out your UART.

I forgot to add- the only problem with using the UART on board the Arduino is that it is used for programming the Arduino, plus communicating between the Arduino and your computer. So the Arduino’s UART does not lend itself too well for communication on RX Pin0 or TX Pin1 with the GPS.
# Jim 2012-04-22 05:28
With all due respect, I think you're on the wrong track with a bunch of stuff here. SoftwareSerial is just a library for making any pin on the Arduino send and/or receive serial data. It knows nothing about the content of the data. It will pass any data that comes out of the GPS receiver, regardless of why sentence it is. It never knows.

As for whether NMEA sentences are correct, you can't know that for sure without decoding the checksum. The checksum data is the two bytes at the end, after the * and before the carriage return. Unless you parse the NMEA sentence, compute the checksum and compare what you computed to what was received, you can't know the NMEA is correct. It may look correct, but you can't know for sure without actually checking.

Just like the SoftwareSerial library, the UART in the processor knows nothing about the format of the data it is receiving or sending. If there was a problem with the checksum, then this was a software issue and had nothing to do with the UART.

If you want to try out the NXP UART I am using, the easiest way to do that is to buy a "multi serial shield" from Hackastrich. She puts one on a shield that talks to the host Arduino using I2C. She has a library with it, or you can use this one.

As for the UART being used to talk to your PC, that is true. Some Arduinos have more than one UART. And if your GPS application does not need to talk to the PC, then you can use that UART.

But the bottom line when collecting async serial data (such as from that GPS module) is that the best way to do it is with a hardware UART. The NXP has a very big buffer, is a dual UART, has 8 general purpose IO pins and can support I2C and SPI. Its also about $4.50, so its really cheap.

Goos luck!
+1 # D9W 2012-04-22 09:35
Hi Jim,
No offence taken. I welcome your insight. You are correct that SoftwareSerial should not interfere with the data stream. Mikal Hart posted a way to generate what TinyGPS is seeing, which lead me to the conclusion that SoftwareSerial was having some major problems. What’s funny is if you use the hardware UART to feed TinyGPS, TinyGPS does not have as many problems (very few checksum problems), unless you’re using I2C, compared with SoftwareSerial. SoftwareSerial should act just like the Arduino hardware UART, but there is something inside of the program that’s not letting the other NMEA sentences through. It’s like if you went outside right now and found your car missing. You don’t need a check sum to notice your car gone ;-). That example is very close to what I am seeing when it comes to the output of SoftwareSerial.

And I totally agree with you on I might be forced to use a hardware UART. If you’re willing I would like to go through what I have found. I have no problems with sharing what I did. It never hurts to have a second pair of eyes on what I have been doing, and maybe I can learn something.

First, Do I understand correctly you have the LS20031 chip???

Second, is there a place where we can take this conversation so we are not taking up all of Wayne’s BBS? Or if Wayne does not mind then we can continue this conversation here or over on the forum? Because I am interested in what you’re saying.

Third, it might be helpful if I give you where I got the latest LOCOSYS datasheet Ver 1.3 for the LS20031 chip so I can follow your thought pattern. >> You can find it here >> http://www.locosystech.com/product.php?zln=en&id=20 . Look for the orange “LS20030~3 (MTK) Smart Antenna” under the words “Products & Download”, and click on the “Download” Tab. Then click on “Datasheet_v1.3 ”. You will have to pass a Security Check and then you will have access to the Datasheet.

Also Sparkfun’s tutorial can be found here >> http://www.sparkfun.com/tutorials/176 - you can find how to do a direct data dump from the LS20031 following the Quick Test.
# D9W 2012-04-22 09:36
And Mikal Hart’s TinyGPS can be found here >>
arduiniana.org/ libraries/tinyg ps/ And if you’re using the current Arduino’s IDE 1.0 then you already have SoftwareSerial.

It makes sense that you know where I am getting my information. And I am willing to show you both my data and the code that produced that data.

If I understand right, Mega is the only Arduino that has more than one UART, with the advantage they are not all hooked up (through the USB to the computer) to the IDE Monitor.
Thanks
David9W
# Jim 2012-04-24 20:25
Feel free to email me directly using jim at archer dot net. We should take this offline.

But in a nutshell, yes, I use that GPS module in a commercial product. I am very familiar with it. Its actually very easy to use. I think you probably have several relatively minor problems that are adding up to look like one confusing big one.

Email me and I'll help you make a plan to get on track.
# Jim 2012-03-13 15:37
That is at least partially my fault, I really need to be able to use the library from inside an ISR to service an I2C based UART. And it does work very well in that role.
# Mike S. 2012-03-13 16:44
Quoting Jim:
I really need to be able to use the library from inside an ISR to service an I2C based UART.


Why did it require you to use the library inside an ISR? IMHO, and I say this will due respect, the I2C system in Arduino is built to be interrupt-drive n, and that's a good idea as it enables an event-driven programming model.

Offhand I'd say the proper way to do things would be to set up data structures that would notify loop() of its state from within the ISRs. But then, I don't know your use case.

A major reason I'm interested in this is because I bumped into problems with the PinChangeInt library and using Serial.print(). Now I'm careful about what I put into ISRs and what I do not.

Again, like I mention, I don't understand how you need to use the library. I was hoping to be able to find an interrupt-drive n I2C library for the Arduino (or write one myself- yikes!)
# Jim 2012-03-13 15:39
Mike, just wondering, has there been an update? It works fine, I was just curious. I like to keep to the latest.
# Jim 2012-03-13 17:27
Quoting Mike S.:
Quoting Jim:
I really need to be able to use the library from inside an ISR to service an I2C based UART.


Why did it require you to use the library inside an ISR? IMHO, and I say this will due respect, the I2C system in Arduino is built to be interrupt-driven, and that's a good idea as it enables an event-driven programming model.


Well its a UART with an internal buffer, like all UARTs. When the internal buffer is near full, it fires off an interrupt. The ISR then comes along and empties the buffer from the UART and puts the data into a RAM buffer, like a ring buffer. This is the traditional way to service a UART.

If I understand you correctly, you suggest that the IRQ set a flag, then the code poll the flag as it goes round, and empties the buffer when the flag is set? Or maybe just poll the buffer?

Not ideal. The buffer could easily overflow before the loop got around to it.
# Donald Delmar Davis 2012-04-02 20:08
What is a good value or set of values for the timeout? or what is the domain of too small?
# Ruud Martens 2012-04-10 14:30
I've got a question, is it possible to adres 16 bit registers? I need to setup the following:
(this is a standard read operation for the ADE7953)
(start)|01110000|ACK|MSB register|ACK|LS B register|ACK
(start)|01110001|ACK|31-24 value|ACK|23-16 value|ACK|15-8 value|ACK|7-0 value|(STOP)

I think with your library i have to write the following code:
Code:
I2c.begin();
I2c.read(515,3);
int x = I2c.receive() << 16;
x |= I2c.receive() <<8;
x |= I2c.receive();
I2c.end();


But I'm not getting any reasonable values out of any register. Could you tell what's is going wrong?
# Wayne Truchsess 2012-04-10 19:35
Quoting Ruud Martens:
I've got a question, is it possible to adres 16 bit registers? I need to setup the following:
(this is a standard read operation for the ADE7953)
(start)|01110000|ACK|MSB register|ACK|LSB register|ACK
(start)|01110001|ACK|31-24 value|ACK|23-16 value|ACK|15-8 value|ACK|7-0 value|(STOP)

I think with your library i have to write the following code:
Code:
I2c.begin();
I2c.read(515,3);
int x = I2c.receive() << 16;
x |= I2c.receive() <<8;
x |= I2c.receive();
I2c.end();


But I'm not getting any reasonable values out of any register. Could you tell what's is going wrong?

Unfortunately the library (and the Arduino) does not support 16 bit addresses.
+1 # Richard Baldwin 2012-04-10 20:39
Hi Ruud,

You don't have a device address in your example. The device address for the ADE7953 is fixed at 0x38.

The library only supports 256 registers, so you will have to change it to send 2-byte registry addresses.

Your call would then be:

I2c.read(0x38,515,3);

HTH
# Ruud Martens 2012-04-11 09:08
Hey, thanks for your help! I've got a stable communication between the arduino and the ADE7953 right now.

I've modified your library so it can be used for chips with 16bit registers. Maybe some people are interested? You can download it here

Thanks once again for your great library!
# Peter Scargill 2012-04-11 16:09
I certainly AM interested - but I'm pulling my few remaining hairs out...

Both the original and your library show my 24c65 chip as address 0x50 which is correct, but no matter what I do I cannot read it - I've even tried another chip - it just sits there in available() doing nothing. Any ideas? I've tried diffreent combination including...

Serial.begin(57600);
I2c.begin();
I2c.pullup(1);
I2c.setSpeed(1);
I2c.scan();
Serial.println("Starting");
I2c.write(0x50,0);
I2c.read(0,8);
while (I2c.available())
{
Serial.print("> >"); Serial.println( I2c.receive());
}


Quoting Ruud Martens:
Hey, thanks for your help! I've got a stable communication between the arduino and the ADE7953 right now.

I've modified your library so it can be used for chips with 16bit registers. Maybe some people are interested? You can download it here

Thanks once again for your great library!
# Ruud Martens 2012-04-11 17:15
At first i recommend a hardware pull up. It's easy to connect.

SDA eeprom
sda____|____4,7k or 10k resitor____vcc

SCL eeprom
scl____|____4,7k or 10k resitor____vcc

Second, try using this code:
Code:
I2c.begin(); //If you put an adress here, the eeprom thinks you are an other slave.
I2c.setSpeed(1);
I2c.scan();
Serial.println("Starting...");
//If you're going to read a register the read function will be enough. The read function will work fine if you put the adress of the device (0x50), register adress (0xXX) and the amount of bytes you want to read.
I2c.read(0x50,0xXX,X);
Serial.println(I2c.available());
while (I2c.available())
{
Serial.print(">>");
Serial.println(I2c.receive());
}


I hope this will give more result.
# Peter Scargill 2012-04-11 17:26
Thanks for the speedy response - and your suggestion to wrap the AVAIABLE function in the printout - it's not coming back - ie I2c.available() doesn't return... I don't understand how SCAN can identify the chip is there, but the code can't appear to read ....

#include

#define HMC5883L 0x1E

void setup()
{
Serial.begin(57600);
I2c.begin();
I2c.setSpeed(1);
I2c.scan();
I2c.read(0x50,0,8);
Serial.println(I2c.available());
while (I2c.available())
{
Serial.print("> >"); Serial.println( I2c.receive());
}
}

void loop()
{
while(1){};
}
# Peter Scargill 2012-04-11 17:48
I should clarify... the 24c65 is connected to 5v and ground, the address lines are all grounded and the two lines are hooked to the arduino correctly.
# Andy 2013-02-20 00:00
made my day. thumbs up!


Quoting Ruud Martens:
Hey, thanks for your help! I've got a stable communication between the arduino and the ADE7953 right now.

I've modified your library so it can be used for chips with 16bit registers. Maybe some people are interested? You can download it here

Thanks once again for your great library!
# Peter 2013-07-11 17:06
Hello Ruud,

I am currently working on I2C communication between the ADE7880 and the Arduino Mega 2560. I am able to handshake with chip. When I attempt to read registers I always receive back a '0'. Would you happen to have sample code for a read operation off the chip? For example 'Phase A VRms'? I hope your library modification saves me from looking for a different micro-controlle r due to the 7-bit wire library limitation.

Thanks Ruud,

Regards,
# Ruud Martens 2012-04-12 10:23
Maybe you need to set the serial.begin to (9600) i'm using this setting always for my arduino.

And try to use the setup for setup only, everything else in void loop()

So:
Code:
#include

#define HMC5883L 0x1E

void setup()
{
Serial.begin(57600);
I2c.begin();
I2c.setSpeed(1);
I2c.scan();

}

void loop()
{
I2c.read(0x50,0,8);
Serial.println(I2c.available());
while (I2c.available())
{
Serial.print(">>"); Serial.println(I2c.receive());
}
}
# Peter Scargill 2012-04-12 11:08
Nope.. still dead..

#include

void setup()
{
Serial.begin(9600);
I2c.begin();
I2c.setSpeed(1);
I2c.scan();

}

void loop()
{
I2c.read(0x50,0,8);
Serial.println(I2c.available());
while (I2c.available())
{
Serial.print("> >"); Serial.println( I2c.receive());
}
}
# Richard Baldwin 2012-04-12 11:35
You are not configuring the device before trying to read from it and you are trying to read the data registers before the status is RDY.

e.g.

1. Write CRA (00) – send 0x3C 0x00 0x70 (8-average, 15 Hz default or any other rate, normal measurement)
2. Write CRB (01) – send 0x3C 0x01 0xA0 (Gain=5, or any other desired gain)
3. For each measurement query:
Write Mode (02) – send 0x3C 0x02 0x01 (Single-measure ment mode)
Wait 6 ms or monitor status register or DRDY hardware interrupt pin
Send 0x3D 0x06 (Read all 6 bytes. If gain is changed then this data set is using previous gain)
Convert three 16-bit 2’s compliment hex values to decimal values and assign to X, Z, Y, respectively.

The other problem you may have is this device is 3.3v whilst the Arduino is 5v. Any pullups must not exceed Vdd for this device.
# Peter Scargill 2012-04-12 12:15
This BBS is strange - makes it look as if you're responding to my query and of course you're not - the 24c65 is 5v.
# Richard Baldwin 2012-04-12 13:19
My Bad. I saw the code had

#define HMC5883L 0x1E

in it and replied on that basis.

My guess is that your code is not using

uint8_t read(uint8_t, uint16_t, uint8_t);

from Ruud's library.

Try
I2c.read(0x50,(uint16_t)0,8);
# Peter Scargill 2012-04-12 13:40
A very valid point... but sadly no.. I've altered slightly - it finds the unit - says it's starting then... sits there forever in i2c.available() ... I've tried the lower speed, too...


#include

void setup()
{
Serial.begin(9600);
I2c.begin();
I2c.setSpeed(1);
I2c.scan();

}

void loop()
{
Serial.println("Starting");
I2c.read((uint8_t)0x50,(uint16_t)0,(uint8_t)8);
while (I2c.available())
{
Serial.print("> >"); Serial.println( I2c.receive());
}
}
# Richard Baldwin 2012-04-12 13:59
Try printing out the return value for
I2C.Read
# Peter Scargill 2012-04-12 14:28
Sorry guys, after all that - rubbish chinese NANO - now in the bin..... the code works a treat - many thanks to the author for a tight library with 16-bit addresses.

#include

void setup()
{
Serial.begin(57600);
I2c.begin();
I2c.setSpeed(1);
I2c.write(0x50,1000,"Very good indeed");

}

void loop()
{
Serial.println("Starting");
I2c.read(0x50,1000,16);
while (I2c.available())
{
Serial.print((char)I2c.receive());
}
Serial.println("");
}
+1 # Dan 2012-04-22 04:52
Hello there, the library looks great replacement to wore I look forward to slave support.

Thanks for the great work so far!
# Jez 2012-04-24 20:17
Hi Wayne,

Just a note to say thanks for your hard work with this library! After pulling my hair out for two days with a DS1307 having the wire library hanging at Wire.requestFro m(), changing to the I2C library had it working first time!

Thank you!

BR Jez.
# Piotr 2012-06-20 08:29
Hi,

Quoting Jez:
After pulling my hair out for two days with a DS1307 having the wire library hanging at Wire.requestFrom(), changing to the I2C library had it working first time!


I've some strange issues with I2c master library and DS1307. Could you please show some working code?
# Piotr 2012-06-20 13:49
Quoting Piotr:

I've some strange issues with I2c master library and DS1307.

Fixed - hardware problem.
# Casper 2012-08-09 23:04
Hi Piotr,
Could you share your code with me for the DS1307? I am also pulling out my hair for more than two days now.
Thanks!
# Piotr 2012-08-10 06:42
Quoting Casper:

Could you share your code with me for the DS1307? I am also pulling out my hair for more than two days now.

Sure. Give me you email and I will send it to you.
# scott216 2013-06-22 21:36
Quoting Jez:
Hi Wayne,

Just a note to say thanks for your hard work with this library! After pulling my hair out for two days with a DS1307 having the wire library hanging at Wire.requestFrom(), changing to the I2C library had it working first time!

Thank you!

BR Jez.


Jez,
I want to use my DS1307 with this DSS's I2C.h library, but I'm having trouble finding example code. Could you post your code on pastebin.com or something so we can how you got this working?
# waseg 2012-04-30 17:45
Hi, I had some trouble making it work on Seeeduino Stalker v2.0 which has atmega 328 and 8mhz clock. It has on board temperature sensor and RX8025 real time clock. When I scanned the devices it didn't find the RX8025 on adres 0x32 but found the thermometer.
But it found it with the Wire library, so I tried the I2c.begin(); than Wire.begin(); and I2c.scan(); and it found it. So I guess there is some bug in the begin() function. I am not so good at coding but I hope that reporting this bug helps you to improove the library. Cheers and thanks a lot for the library which seems much more stable for me than the Wire. Cheers Vaclav
# Jim 2012-05-01 11:59
Hi again all!

I'm about to embark on a new project, which involves using an Arduino as an I2C slave. I know this library is master only, but I was wondering if anyone has tried to make it talk to another uC running the wire library as a slave?

I am thinking the 32 character limit in Wire is not an issue, as this library probably just sends multiple 32 byte messages. But there is that start/stop issue...

I guess I'll fool with it and see what happens...
# Wayne Truchsess 2012-05-01 12:30
Quoting Jim:
Hi again all!

I'm about to embark on a new project, which involves using an Arduino as an I2C slave. I know this library is master only, but I was wondering if anyone has tried to make it talk to another uC running the wire library as a slave?

I am thinking the 32 character limit in Wire is not an issue, as this library probably just sends multiple 32 byte messages. But there is that start/stop issue...

I guess I'll fool with it and see what happens...

Hey Jim. So it's a bit of a catch 22 with using this library to talk to Wire. My intent behind this library was to get the repeated start function to work with the Arduino because the current (at the time) Wire library did not support repeated starts. Well as luck wold have it the Wire library in slave mode will not acknowledge a repeated start either. This doesn't mean you can't communicate with Wire it just means you'll be restricted on which functions you can use. For instance, if you wanted to request data from a slave device, you'd normally use a function like such I2c.read(addres s, registerAddress , numberBytes) . Unfortunately this would not work communicating with Wire because this particular function uses a repeated start between write and read. Instead you'd have to use the functions I2c.write(addre ss, registerAddress ) followed by I2c.read(addres s, numberBytes). As for the 32 bytes, if you try to write more than 32 bytes to the slave device it will not break them up into multiples of 32, it will send them all at once, which Wire does not support. You'll need to break it up yourself. Just one more "gotcha" to look out for when using an Arduino as a slave. Sometimes you may request data from the slave and it won't respond to the request, from my experience, if this happens try inserting a 1ms delay between write and read. The reason is the Atmega328 chip has a minimum 4.7us delay that needs to take place between the stop bit and next start bit or else it will not respond. Sometimes the delay between stop and start are right on the hairy edge and the Atmega won't respond.
# Jim 2012-05-01 18:04
Okay Wayne, thanks very much. I'll try it that way. Ultimately I won't be using the ATMega328 but that's what I'll start experimenting with. Strangely enough, the slave will probably end up being a 32 bit uC running a web server. SO when that happens, I'll not be using Wire anyhow...
# Charles Kim 2012-05-08 07:47
Hi, Wayne.

I have tried your library with Arduino Uno and worked excellent.

However, I am seeing a series of compliling errors with attiny 45.

this is part of errors shown:

C:\Users\DELL\Documents\00프로그래밍자료\Work\libraries\I2C\I2C.cpp: In member function 'void I2C::begin()':
C:\Users\DELL\Documents\00프로그래밍자료\Work\libraries\I2C\I2C.cpp:91: error: 'PORTD' was not declared in this scope
C:\Users\DELL\Documents\00프로그래밍자료\Work\libraries\I2C\I2C.cpp:95: error: 'TWSR' was not declared in this scope
C:\Users\DELL\Documents\00프로그래밍자료\Work\libraries\I2C\I2C.cpp:95: error: 'TWPS0' was not declared in this scope
C:\Users\DELL\Documents\00프로그래밍자료\Work\libraries\I2C\I2C.cpp:96: error: 'TWPS1' was not declared in this scope
C:\Users\DELL\Documents\00프로그래밍자료\Work\libraries\I2C\I2C.cpp:97: error: 'TWBR' was not declared in this scope
C:\Users\DELL\Documents\00프로그래밍자료\Work\libraries\I2C\I2C.cpp:99: error: 'TWCR' was not declared in this scope
C:\Users\DELL\Documents\00프로그래밍자료\Work\libraries\I2C\I2C.cpp:99: error: 'TWEN' was not declared in this scope
C:\Users\DELL\Documents\00프로그래밍자료\Work\libraries\I2C\I2C.cpp:99: error: 'TWEA' was not declared in this scope
C:\Users\DELL\Documents\00프로그래밍자료\Work\libraries\I2C\I2C.cpp: In member function 'void I2C::end()':
.......

Can you help for this?

FYI, Attiny45 has USI, not an hardware I2C.
# Wayne Truchsess 2012-05-09 01:42
Sorry Charles, but the library does not support the Attiny's USI.
# Charles Kim 2012-05-09 06:10
Quoting Wayne Truchsess:
Sorry Charles, but the library does not support the Attiny's USI.

Well.. not good news.. Hopfully, you will try it in near future.. if successful, please inform me...
# Mark Wilkie 2012-05-10 19:47
First, thanks a ton Wayne for writing this library. It’s SOOO much better than the stock Arduino one.

I have a curious problem right now that I’m hoping you can shed some light on.

For whatever reason, I don’t seem to be getting a STOP bit. Basically, I’ve got two Arduino UNO’s talking to each other. The master is using your library, and the slave is using the stock Wire library. In looking at the bus using a logic analyzer, I get the following behavior when I have the master request data from the slave:

1) START
2) B00001001 (this is expected: I’m using 4 as my slave address and 1 indicates a read)
3) ACK
4) 0x01 (expected: this is the first byte of my data payload. 4 in total…)
5) ACK
6) 0x04
7) ACK
8) 0x02
9) ACK
10) 0x00 (excpected: last bye of my data payload)
11) ACK
12) 0xff (???? This is NOT expected. I would expect a STOP. Was a clock pulse was missed maybe?)
13) ACK
14) 0xff (this and the ACK is repeated 15-20 times or so)
15) NACK (yes, I finally get a NACK)
16) STOP
17) START
18) Rinse repeat…..

If it’s helpful, I have a screen shots of sda and scl lines as well from my logic analyzer, let me know.

Mostly I don’t understand why there is not STOP bit after the last 0x00 of my four bytes of data. Any thoughts as to why this might be happening?

Thanks a ton,

Mark
# Wayne Truchsess 2012-05-10 19:53
Hi Mark. Can you post the snippet of code where the problem is? Also if you're requesting data from the other Arduino using the commands that write then read, it won't work because my library uses repeated starts (instead of stop then start) and the Wire library in slave mode does not support repeated starts.
# Mark Wilkie 2012-05-10 20:09
Hi Wayne,
So my initial request from the master is as follows:

void setup()
{
#ifdef DEBUG
Serial.begin(11 5200); // start serial for output
#endif

I2c.begin();
I2c.timeOut(TIM EOUT);
I2c.pullup(true );
I2c.setSpeed(tr ue); //true = fast
}

void loop()
{
//Request, and then blocking (for now) read message from slave
int retVal = i2cRead();

... code here to wait for, and then parse the reponse....

}

int i2cRead()
{
boolean waitingFlag = true;
int waitCount = 0;
int i2cPacketSize=0 ;
boolean timeout = false;

//Wait for a valid, usable packet
while(waitingFl ag)
{

//Loop until non error status returns
while(true)
{
//Request message from slave
DEBUG_PRINT("I2 C: Request packet (status) ");
int status=I2c.read (SLAVE_ADDRESS, I2C_BUFFER_SIZE );
DEBUG_PRINTHEX( status);
DEBUG_PRINTLN(" ");

if(status==0)
break;

delay(LONG_DELA Y);
}

... code which actually reads the response....BTW , this is working because I send the msg length in the packet and thus ignore all these extra characters
}


Then, for my slave code, it goes like this:

byte nakmsg[] = {0x01, 0x04, 0x02, 0x00};

void setup()
{

//setup i2c as a slave
Wire.begin(SLAV E_ADDRESS); // join i2c bus as slave
Wire.onRequest( requestWriteHan dler); // register write event
Wire.onReceive( receiveEventHan dler); // register read event
}

void requestWriteHandler()
{
if(incomingPack etReady)
{
Wire.write(pack etIncomingBuffe r,UARTIncomingP acketSize); // sends bytes

// Reset incoming packet flag
incomingPacketR eady = false;
}
else
{
Wire.write(nakm sg,4); //Write my own "NAK" message (nothing to do with i2c)
}

}

Basically, I just don't understand why I'm seeing 0xff on the wire and no STOP bit. Hopefully you can help shed some light on this mystery. I'm sure it's my deal, it's just that I don't know where.....grin.

Cheers
# Wayne Truchsess 2012-05-10 20:41
Hi Mark,
The problem has something to do with UARTIncomingPac ketSize . The size is a lot larger than what you think it is. Is it possible you need to put a NULL after the last byte so it knows when it's reached the end of the buffer? You won't get a STOP signal from the master until it receives the last byte which is indicated by the NACK which is sent by the slave.
# Mark Wilkie 2012-05-10 20:49
Ah, so the master will not send a STOP until sda is left high for a NACK by the slave?

When will the slave send a NACK? Are you saying that the i2c.read length determines when the slave sends the NACK? Somehow I thought that the requested read length from the master was the maximum - not a requirement....

Given what I'm understanding, how would I have the master request an unknown number of bytes from the slave? Would I need to work out some sort of handshaking or make all my slave->master message lengths the same?

This is a big help. Thanks Wayne.

Mark
# Mark Wilkie 2012-05-10 20:53
Sorry - clarification. The example I'm giving is my own fake message as noted by:

Wire.write(nakmsg,4) ; //Write my own "NAK" message (nothing to do with i2c) or '{0x01, 0x04, 0x02, 0x00}'

In other words, UARTIncomingPac ketSize is not even used in this scenario. (plus, I've verified in other debugging that this is the correct size)

I've verified that I'm sending the message I think by looking at the bus itself. See my original post to see the expected bytes.

Thanks
# Wayne Truchsess 2012-05-10 21:29
This is what I get for responding too fast! Sorry the Master sends the NACK after it receives the last byte it requested. So are you sure I2C_BUFFER_SIZE is the correct size? Also, I noticed you're using fast mode, what size pull up resistors are you using? It could be a timing issue if the pullups are not correctly sized in fast mode.
# Mark Wilkie 2012-05-10 21:44
Thanks Wayne - I2C_BUFFER_SIZE is just the default "max" in the i2c.h. Do I need to specify the expected size? If so, this implies that the master knows how many bytes it plans on getting from the slave.

I'm currently understanding from you that the master sends a NACK when it receives the # of bytes it requested in the i2c.read() call. The slave then sends a STOP after receiving that NACK from the master. Am I understanding this correctly?

Also, yes, there is a good chance I have the resistors incorrectly sized and am running into a timing issue. I'm getting a new DSO (really excited...) next week and will check the waveforms on that. Right now I'm using 3.2K, but am not disabling the internal pullups (which I strongly suspect I should do)

My goal is to really understand how i2c works so that any issues I run into do not simply "magically" go away after changing several somthings.

On that note, you're suggesting that if the resistor values are wrong, the timing could problems, which makes good sense. Do you have thoughts as to how this explains the NACK being late from the master and all the 0xff bytes in between? Is it simply that the bus is getting out of sync?

Thanks again for your help as I try and educate myself.

Cheers
# Wayne Truchsess 2012-05-11 00:05
Yup, the problem is the I2C_BUFFER_SIZE , you need to specify how many bytes you want to transfer. Once the last byte, that is requested, is received by the master, the master will generate a NACK and then the master sends the stop signal. In your case you're requesting more bytes then the slave is willing to send so the SDA line is just sitting high which is why you're reading in 0xFF bytes until the buffer fills up and the NACK signal is sent.

You're resistor values should be OK, they'll work but they could be reduced a little more. Actually, having the pull ups enabled helps a little bit. The pullup is a higher value but it's in parallel with your external pullups which reduces the total resistance value (a good thing).
# Mark Wilkie 2012-05-11 02:25
Thanks a ton Wayne. It does make sense now. Another read of the Philips I2C spec also helped clarify what's going on. The whole thing with the master sending a NAK so that the slave will release the sda line - thus allowing the master to issue a STOP - confused me for a while.

Thanks again!
# Charles Kim 2012-05-11 05:51
Hi, Wayne.

Me gain. I abandoned ATtiny series owing USI issues according to your advice.

Now, I am trying wiht ATmega 48 as I don't need more memory. I found your source file don't include ATmega48 although it is youngest brother of AtmegaXX8 family.

It there any reason for that?
# Wayne Truchsess 2012-05-11 15:29
Quoting Charles Kim:
Hi, Wayne.

Me gain. I abandoned ATtiny series owing USI issues according to your advice.

Now, I am trying wiht ATmega 48 as I don't need more memory. I found your source file don't include ATmega48 although it is youngest brother of AtmegaXX8 family.

It there any reason for that?

I've never used the Atmega48 so I don't have a way of testing it.
# Charles Kim 2012-05-13 04:38
Quoting Wayne Truchsess:
Quoting Charles Kim:
Hi, Wayne.

Me gain. I abandoned ATtiny series owing USI issues according to your advice.

Now, I am trying wiht ATmega 48 as I don't need more memory. I found your source file don't include ATmega48 although it is youngest brother of AtmegaXX8 family.

It there any reason for that?

I've never used the Atmega48 so I don't have a way of testing it.


Ok then. I wil try for test by adding __ATmega48__, and __Atmega88__ onto head file. Is there anything I have to do?
# Kristofer Hagbard 2012-05-17 22:22
Hi!

Thanks for a great library!

I have a question about speed: Am I right to think that everything I do in fast mode will take 1/4:th of the time of a standard speed operation?

For instance will a 0.29 ms (2903 microseconds is a typo right?!?)
write be ready in less than 0.1 ms?

Thanks in advance!

.kris
# Peter Wonder 2012-05-24 03:11
Wayne, very impressive work. We are trying to get data from a number of environmental sensors (~30) so your library will be exceptionally useful. However, we also would like to communicate between 2 Arduinos and it would seem that at least out of the box your library does not support that. I was wondering if there are any other users here that have used your library successfully and also implemented some means of communicating the data to another Arduino. Thanks for your kind help, Peter
+1 # Mark Wilkie 2012-05-24 15:35
Hi Peter,

Yes, I've used Wayne's library in conjunction with the "stock" Arduino wire library. There's really not much special to it. Mostly, use Wayne's library for the master side, and then Arduino's wire lib for the slave side. Just setup your two interrupt handlers on the slave side and you're off and running. The two libraries work together great...

If need be, I can share some code snippets to get you going.
# Peter Wonder 2012-05-25 06:38
Quoting Mark Wilkie:
Hi Peter,

If need be, I can share some code snippets to get you going.


Mark, if it is not too much trouble, would be great if you could share some code snippets. I think I got the gist from your message but being rather a greenhorn I prefer to ask for directions :-)

If you dont want to post it here, my private email is ppl4world (at} [yahoo} (com}

Thank you again for your kind help!

Peter


Peter
# Mark Wilkie 2012-05-26 13:59
Hi Peter,

I responded to you directly. Cheers
# jim 2012-07-07 19:39
Quoting Mark Wilkie:
If need be, I can share some code snippets to get you going.


If its not too much trouble, could you send me the code snippets as well? My email is jim at archer dot net.

Thank you!
# Mark Wilkie 2012-07-09 16:02
Jim, I responded to you directly. Cheers!
# Mike Schwager 2012-07-10 05:40
Quoting Mark Wilkie:

If need be, I can share some code snippets to get you going.

Hello Mark- Could you add my name to the chorus of users who would like a copy of your code snippets? Thanks! mschwage *at+ gmail dot com
# Mark Wilkie 2012-07-10 19:49
Mike, just sent you mail. Cheers
# Patrick Curley 2013-03-17 17:28
Quoting Mark Wilkie:

If need be, I can share some code snippets to get you going.


I would really like that example code, could you send it to me too? My email is curleyman at gmail dot com.

Thanks,
Patrick
# scott216 2013-03-30 19:54
I have 2 arduino's that need to communicate via I2C. I'd like to use this library for the master. Can you send me the code examples also?
# jim 2012-07-01 03:37
Hi All...

I realize this is a bit off topic, but I'm wondering if anyone has an idea that can point me in the right direction. I am trying to get my Arduino board (1284p) to talk via I2C to a Netduino board.

My board is already designed and coded to be an I2C master and I can't really change that. The Netduino uses an Atmel ARM processor that can not be an I2C slave.

Is there a way around this? I saw some chips that can interface an I2C to an SPI master, but that's not much help either... I don't have any free UARTs on the 1284p board, and I'm told that .NET does not make a good SPI slave environment.

Any ideas?

Thanks...
# Tom 2012-08-03 02:39
Hi Mark,
found your site while looking for a IC2 lib for my Arduino Uno that does not use interrupts. My sketch uses timer0 (for millis()), timer1 ISR, hardware int0 and int1, Serial Uart (pin0 and pin1) so only timer2 is available. I could recode my sketch to not use timer1 if necessary.
Does your IC2 lib use timer0 or timer1 and or timer2 and or the uart or hardware interrupts (uart, and hardware interrupts asked her only for completness).

I too would like to receive a copy of your code snippets.

It sure would be nice if the authors of the various libs for the arduino would document their usage or not of the features on the arduino such as timers, uart pins, ic2 pins, hardware interrupts, timer interrupts etc.

Thanks
Tom
# Tom 2012-08-05 17:50
Hi all, I'm just getting started with i2c interacing and want to use Waynes i2cmaster library. Anybody know if the SPI interface provided in the Wire lib is implemented in the i2cmaster lib?
I am moving all mode code away from Wire lib to i2cmaster lib and I have an adafruit microsd data logger breakout board and want to be sure I can still use it with the i2cmaster lib.

Thanks
# Nalgas Heladas 2012-09-09 08:16
Thanks for the I2C lib. Works great!
# Russell Cameron 2012-09-16 03:36
Thank you very much for the effort you put into this library. I had just created a new 3.3V controller and had been frustrated trying to get the Wire library to play nice with it. Your library solves all my problems.

I hope you do not mind that I have put a copy on my website so it can be more easily found by my customers.
# Russell Cameron 2012-09-16 05:32
After getting stuck for a while I discovered your library only lets me write char variables but not byte variables.

Am I doing something wrong or must I convert all my data to char variables?
# Wayne Truchsess 2012-09-17 02:27
Quoting Russell Cameron:
After getting stuck for a while I discovered your library only lets me write char variables but not byte variables.

Am I doing something wrong or must I convert all my data to char variables?

If you're using Arduino 1.0 or greater than byte won't work. The function calls are overloaded so you can use all uint8_t or ints but not a combination or else you'll get a compiler error.
# Russell Cameron 2012-09-17 03:21
G'day Wayne, thanks for the quick reply. I am using Arduino 0022 but rev5 still seems to dislike bytes. I get a compile error "ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second"

I am trying to read from an AD7998 8ch ADC and need to be able to read/write 16bit data. For now I am trying to use char variables but for future revisions would it be possible to write 16bit integers?
# Wayne Truchsess 2012-09-17 20:44
That error means you are trying to combine ints and bytes at the same time. If you have a variable declared as a byte and is used as one of the arguments and another argument is just a a number...say 0x08, you'll get that error because the compiler interprets the 0x08 as a 16 bit integer. If you want to post the line of code you're using I can take a look.

As for writing 16 bit integers, that probably won't be included because some devices want the MSB first while I've seen others that want the LSB transmitted first. It just really complicated.
# Russell Cameron 2012-09-18 03:13
Thanks for the reply, I'll check my code again.

In retrospect I see what you mean about the integers, I forgot that the data can be sent in either format. I retract the request.
# Russell Cameron 2012-09-17 12:26
Now I have a new problem.

Code for reading and writing to the NV RAM of a DS1307 works perfectly on a 5V @ 16MHz Arduino Nano but not on my 3.3V @ 8MHz Micro Magician.

Reading the time works fine no matter which controller I use. It seems to work for a short time and then crashes.

I have tried using the I2C timeout function with the time set to 500.

I have also added external 10K pullup resistors as well as your I2c.pullup command wich worked fine when just reading the time.
# Wayne Truchsess 2012-09-17 20:45
Quoting Russell Cameron:
Now I have a new problem.

Code for reading and writing to the NV RAM of a DS1307 works perfectly on a 5V @ 16MHz Arduino Nano but not on my 3.3V @ 8MHz Micro Magician.

Reading the time works fine no matter which controller I use. It seems to work for a short time and then crashes.

I have tried using the I2C timeout function with the time set to 500.

I have also added external 10K pullup resistors as well as your I2c.pullup command wich worked fine when just reading the time.

What's the return value when it crashes? Each read/write function has a return value that should make it easier to narrow down the problem.
# OddBot 2012-09-20 01:19
I'll have to get back to this project later. If the problem does not turn out to be my code or the controller I'll let you know.
# OddBot 2012-09-25 09:16
I did not get any software issues. It tuned out that an SMD capacitor had broken off of the power supply. The library is working fine now with the DS1307 and a Micro Magician 8MHz 3.3V robot controller.
# Randy Glenn 2012-09-18 21:22
Isn't the DS1307 a 5V-only part?
# OddBot 2012-09-20 00:33
The DS1307 is designed for a 5V supply. With a a backup battery voltage of 3V, Vcc must be 3.75V or higher otherwise the RTC goes into low power mode and communications cease.

That said, the DS1307 recognizes any input voltage over 2.2V to be a high signal and below 0.8V to be a low. This means you can have your pullup resistors go to a 3.3V rail without a problem.

My circuit provides 5V (currently from the USB port) to the DS1307 Vcc pin but all other logic is at 3.3V.

I did actually try using 10K pullup resistors to the 5V rail to see if this made a difference.

Technically you should not apply 5V to the ATmega168 pins when it is running on 3.3V but all input pins have protection diodes and the 10K pullup resistors limit the current through those protection diodes to about 170nA.

I am using the RTC in a robot to create timestamps for the A.I. memory.

You can read about my project here: letsmakerobots.com/node/34226
# OddBot 2012-09-20 01:17
I am now testing your library on an AD7998 eight channel, 12bit ADC. There are instances here where a "Stop by Master" is required since the next bit written is selects which register you want to access.

Looking through your library (which from the introduction is written for repeated start conditions) I cannot see how to generate a "Stop by Master".
-1 # Abhi91 2012-10-24 16:35
I recently have started work on atmega32u2 controller.the basic idea is to fly a quadcopter.A miniature helicopter with 4 motors.so,to fly it in a particular direction ,the corresponding motor's rmp is increased.I'm new to the arduino coding and i'm in urgent need for help in programming.It would be generous and greatful of you if you can come up with help.please
# Markus 2012-11-04 14:14
That library is exactly what I'm after. However its kind of odd that it has all bells and whistles, yet supports 8 bit addressing.

Is there a particular reason for that? If not, I'm sure an update to 16 bit addresses would make it even more interesting.

Regards,
Markus
# serenity 2012-11-04 14:19
Quoting Markus:
That library is exactly what I'm after. However its kind of odd that it has all bells and whistles, yet supports 8 bit addressing.

Is there a particular reason for that? If not, I'm sure an update to 16 bit addresses would make it even more interesting.

Regards,
Markus

If you're looking for the 16-bit version (16-bit *only* though), I put a mod up in an earlier post. It should still match the latest version.
# serenity 2012-11-04 14:22
Quoting serenity:
Quoting Markus:
That library is exactly what I'm after. However its kind of odd that it has all bells and whistles, yet supports 8 bit addressing.

Is there a particular reason for that? If not, I'm sure an update to 16 bit addresses would make it even more interesting.

Regards,
Markus

If you're looking for the 16-bit version (16-bit *only* though), I put a mod up in an earlier post. It should still match the latest version.

... and since there's a gazillion comments and I apparently used my real name last time, search for exscape instead to find the link.
# Markus 2012-11-04 17:31
Thanks, I've already seen your modified code including the 24XX1025 wrapper (incidentally exactly what I've done the last two days.. with Wired). Well, I was rather thinking about extending the original, since addressing 256 bytes is not really a lot.
# CBJamo 2012-11-13 06:49
How hard would it be to port this library to Maple ide? http://leaflabs.com/docs/ide.html#ide
# Mark 2012-11-14 23:14
Hi, I'm trying to use the accelerometer MMA8451Q, the same one you used, and I wasn't even able to get simple readings with it, neither using Wire.h, nor I2c.h. It seems not to accept the functions of the i2c.h (I did put the files on the arduino's library folder), and the Wire.h just doesn't work. Much problably, the problem is ME trying to make it work. Could you please send me a sample of the code you used with this accelerometer? It doesn't need to be the whole code, I guess a working one-axis reading is enough for me to go on.
# Mark 2012-11-14 23:20
If it is not asking much, I also would like you to confirm the pins I need to connect in the arduino and, if you know, its respectives inputs. (by the way, it's arduino nano i'm using)
# Mark 2012-11-16 00:37
Never mind, I finally did it all. thanks
# Karel 2012-11-15 12:18
Hello! I have a device which doesn't send an ACK bit after it receives the device address, and doesn't send ACK's in-between data words in a write command. Can I edit the library to support this behavior? I'm not sure how I would do that, if even possible.
# Wayne Truchsess 2012-11-16 00:51
Quoting Karel:
Hello! I have a device which doesn't send an ACK bit after it receives the device address, and doesn't send ACK's in-between data words in a write command. Can I edit the library to support this behavior? I'm not sure how I would do that, if even possible.

Doesn't sound like you're even using an I2C device. I don't think you can edit the library for this feature because the hardware is looking for the Acknowledge signal.
# Marco 2012-11-26 11:16
Hi, Thank You for your work! You've save me with my Freescale MPL3115A2 pressure sensor!!But I've one question to ask you. How can i change the device address (default is 0x60)? I need to use 2 MPL3115A2 sensor at the same time. Can you help me??
# Wayne Truchsess 2012-11-26 11:29
Quoting Marco:
Hi, Thank You for your work! You've save me with my Freescale MPL3115A2 pressure sensor!!But I've one question to ask you. How can i change the device address (default is 0x60)? I need to use 2 MPL3115A2 sensor at the same time. Can you help me??

The datasheet mentions something about consulting Freescale to get devices with different addresses which probably means customization will be needed ($$$). You can try using an I2C multiplexor http://dsscircuits.com/i2c-multiplexer.htmlwhich will allow you to hook up a maximum of 4 devices. Other than that you'd have to find a way to isolate the bus from one of the chips.
# Marco 2012-11-26 12:56
Quoting Wayne Truchsess:
Quoting Marco:
Hi, Thank You for your work! You've save me with my Freescale MPL3115A2 pressure sensor!!But I've one question to ask you. How can i change the device address (default is 0x60)? I need to use 2 MPL3115A2 sensor at the same time. Can you help me??

Other than that you'd have to find a way to isolate the bus from one of the chips.


Can You explain this way better to me?
# veseo 2013-01-17 16:57
Hi,

really useful library, I'm planning to use it in an open-source project for IoT called Souliss.

I need to drive an I/O board that use I2C.

Probably I will "downgrade" to a C code removing overload of the methods.

Thanks for sharing, I will be back in case of problems.

Regards,
Dario.
# Charly 2013-01-24 17:45
Wonderfull,

I'm using ADXL345 and had random lookup with wire Library, with this one, no more problem
Nice job, well coded, I love it !!!
# Monalisa Chandra 2013-01-27 10:10
I need someone who knows C, assembly, machine code, and things like that.

For my microcontroller , I have a nicely written code that is currently working fine. The toy consists of a 2x16 LCD screen, a temperature sensor, and then a simple output signal that controls whatever I have the PID controller wired to. The temperature sensor is providing an analog signal to the microcontroller . Like this: " Input = analogRead(0); "

I am switching to a temperature sensor that outputs temperature data in serial format. Using the I2C protocol (TWI). What I need is for someone to modify my code, probably by "refactoring", and make it so that the PID code I have uses the new serial data now instead of the analog signal. Thats all. So if you do a quick refactor and create and use a function that returns the input reading. That allows me to easily change how the input is obtained. It should also allow me to easily test reading and pre-processing the input. That's all I need... Just my code modified to work with a different type of supply to "Input"


I will upload my existing code for you to see. If you've got the knowledge to modify my code, specifically, the PID part AND some decent reviews, go ahead and bid.


Here is a sample code of what the new sensor runs with:

#include


void setup(){
Serial.begin(9600);
Serial.println("Setup...");

i2c_init(); //Initialise the i2c bus
PORTC = (1
# Monalisa Chandra 2013-01-27 10:12
the sample code is

#include


void setup(){
Serial.begin(9600);
Serial.println("Setup...");

i2c_init(); //Initialise the i2c bus
PORTC = (1
# Jeff 2013-01-28 14:46
Looks promising but I have a couple of questions...

I have some I2C code that is hanging up with the wire.h library so I am attempting to replace that code with the code required to use your I2C.h library.

So currently I would do the following to writing to an I2c device with the wire library:

Wire.beginTrans mission(I2C);
Wire.write(0xCA );
Wire.endTransmission();

and your commands to replace this is:

I2c.begin();
I2c.write(address, registerAddress , data)
I2c.end();

How do I find out the register address when I never needed this to send data to a device before?

Not sure where to find this in the data sheet for the part as simple parts don't seem to have register listings...

Currently with the wire.h library, when reading an I2c device I was using the following:

Wire.requestFrom(0x22, 1); // request 1 byte from 0x44h - revision

while(Wire.avai lable()) // slave may send less than requested
{
revlevel = Wire.read(); // receive a byte as character
}


and your commands to replace this is:

I2c.read(addres s, numberBytes)

Is anything else required to read this I2c device like a while loop for timing sakes?

How do I set up a timeout in case the data or device does not exist?

Thanks
# Wayne Truchsess 2013-01-30 00:10
Quoting Jeff:
Looks promising but I have a couple of questions...

I have some I2C code that is hanging up with the wire.h library so I am attempting to replace that code with the code required to use your I2C.h library.

So currently I would do the following to writing to an I2c device with the wire library:

Wire.beginTransmission(I2C);
Wire.write(0xCA);
Wire.endTransmission();

and your commands to replace this is:

I2c.begin();
I2c.write(addre ss, registerAddress , data)
I2c.end();

How do I find out the register address when I never needed this to send data to a device before?

Not sure where to find this in the data sheet for the part as simple parts don't seem to have register listings...

Currently with the wire.h library, when reading an I2c device I was using the following:

Wire.requestFrom(0x22, 1); // request 1 byte from 0x44h - revision

while(Wire.available()) // slave may send less than requested
{
revlevel = Wire.read(); // receive a byte as character
}


and your commands to replace this is:

I2c.read(address, numberBytes)

Is anything else required to read this I2c device like a while loop for timing sakes?

How do I set up a timeout in case the data or device does not exist?

Thanks

Hi Jeff,
You only need the I2c.begin() in setup (like Wire.begin) and you don't need I2c.end(). So the write command would simply be
I2c.write(addre ss, registerAddress , data)

as for the read (if your simply reading one byte from a know register address, you can accomplish it with one command)
I2c.read(address,regAddress,NumberBytes,&revlevel)
set NumBytes to 1 and it will read and store the byte in the revlevel variable.

and for the timeout just put I2c.timeOut(tim eOut) in your setup() with timeout in milliseconds.

Just an FYI, but you don't need the While statement in Wire when receiving data because the read command is blocking. In other words, the read command will not finish until the bytes are received so the while statement has nothing to do with timing.
# Jeff 2013-01-30 13:51
Quoting Wayne Truchsess:
Quoting Jeff:
Looks promising but I have a couple of questions...

I have some I2C code that is hanging up with the wire.h library so I am attempting to replace that code with the code required to use your I2C.h library.

So currently I would do the following to writing to an I2c device with the wire library:

Wire.beginTrans mission(I2C);
Wire.write(0xCA);
Wire.endTransmission();

and your commands to replace this is:

I2c.begin();
I2c.write(address, registerAddress, data)
I2c.end();

How do I find out the register address when I never needed this to send data to a device before?

Not sure where to find this in the data sheet for the part as simple parts don't seem to have register listings...

Currently with the wire.h library, when reading an I2c device I was using the following:

Wire.requestFrom(0x22, 1); // request 1 byte from 0x44h - revision

while(Wire.available()) // slave may send less than requested
{
revlevel = Wire.read(); // receive a byte as character
}


and your commands to replace this is:

I2c.read(address, numberBytes)

Is anything else required to read this I2c device like a while loop for timing sakes?

How do I set up a timeout in case the data or device does not exist?

Thanks

Hi Jeff,
You only need the I2c.begin() in setup (like Wire.begin) and you don't need I2c.end(). So the write command would simply be
I2c.write(address, registerAddress, data)

as for the read (if your simply reading one byte from a know register address, you can accomplish it with one command)
I2c.read(address,regAddress,NumberBytes,&revlevel)
set NumBytes to 1 and it will read and store the byte in the revlevel variable.

and for the timeout just put I2c.timeOut(timeOut) in your setup() with timeout in milliseconds.

Just an FYI, but you don't need the While statement in Wire when receiving data because the read command is blocking. In other words, the read command will not finish until the bytes are received so the while statement has nothing to do with timing.


Thanks for clearing that up for me Wayne...

How would i do the following with the I2c library?

Wire.beginTrans mission (i);
if (Wire.endTransm ission () == 0)
# PaulDriver 2013-01-29 13:59
Thank you.

I2C works much nicer then the wire library, and is quicker, solved my pesky little problems nicely, without forcing me into real C :)

Hosting this on a CVS, would be a boon.

Paul.
# Wayne Truchsess 2013-01-30 00:13
Quoting PaulDriver:
Thank you.

I2C works much nicer then the wire library, and is quicker, solved my pesky little problems nicely, without forcing me into real C :)

Hosting this on a CVS, would be a boon.

Paul.

I guess I should post the link to it on Github :-)
# Jean ROCH 2013-02-11 19:46
Hi Wayne,

Thanks for this nifty piece of code ! I've used it in my latest inertial guidance system. All the details are on my site. I was in rush so I credited DSS Circuits : do you want me to mention you specifically instead ?

Jean Roch
# Wayne Truchsess 2013-02-12 00:24
Quoting Jean ROCH:
Hi Wayne,

Thanks for this nifty piece of code ! I've used it in my latest inertial guidance system. All the details are on my site. I was in rush so I credited DSS Circuits : do you want me to mention you specifically instead ?

Jean Roch

Glad it worked for you! DSS Circuits is fine with me.
# Andy 2013-02-19 21:30
hi,

seems as if this lib just saved my back. thx a LOT.

just scratching my head about that... how do I access data on an address > 256?

in my case I need to read data from an eeprom from address 10000 and onwards

best regards,
andy
# ketamin 2013-02-26 18:13
I'm trying to use this library in arduino due with the IDE 1.5.2, but I'm getting some errors:

...\arduino-1.5.1r2\libraries\I2C\I2C.cpp: In member function 'void I2C::begin()':
...\arduino-1.5.1r2\libraries\I2C\I2C.cpp:91: error: 'PORTD' was not declared in this scope
...\arduino-1.5.1r2\libraries\I2C\I2C.cpp:91: error: '_SFR_BYTE' was not declared in this scope
...\arduino-1.5.1r2\libraries\I2C\I2C.cpp:91: error: '_BV' was not declared in this scope
...\arduino-1.5.1r2\libraries\I2C\I2C.cpp:95: error: 'TWSR' was not declared in this scope
...\arduino-1.5.1r2\libraries\I2C\I2C.cpp:95: error: 'TWPS0' was not declared in this scope

Someone could tell me how to fix this?
# Wayne Truchsess 2013-02-27 01:19
Quoting ketamin:
I'm trying to use this library in arduino due with the IDE 1.5.2, but I'm getting some errors:

...\arduino-1.5.1r2\libraries\I2C\I2C.cpp: In member function 'void I2C::begin()':
...\arduino-1.5.1r2\libraries\I2C\I2C.cpp:91: error: 'PORTD' was not declared in this scope
...\arduino-1.5.1r2\libraries\I2C\I2C.cpp:91: error: '_SFR_BYTE' was not declared in this scope
...\arduino-1.5.1r2\libraries\I2C\I2C.cpp:91: error: '_BV' was not declared in this scope
...\arduino-1.5.1r2\libraries\I2C\I2C.cpp:95: error: 'TWSR' was not declared in this scope
...\arduino-1.5.1r2\libraries\I2C\I2C.cpp:95: error: 'TWPS0' was not declared in this scope

Someone could tell me how to fix this?
It hasn't been tested with the Due, but it looks like the Due uses different registers.
# Lou Arnold 2013-02-26 19:29
Why did you remove the interrupt code. How did it improve your code? What drawbacks does it have without interrupt?
# Wayne Truchsess 2013-02-27 01:35
Quoting Lou Arnold:
Why did you remove the interrupt code. How did it improve your code? What drawbacks does it have without interrupt?

The best answer is, the system is more stable without the interrupts. I just the think the Wire library spends too much time servicing interrupts when it doesn't need too. Plus you only really need the interrupts when using it in slave mode, otherwise polling just seems to be more stable.
# scott216 2013-04-06 18:28
I created a couple sketches that enable I2C between two Arduinos. I had this working with the wire.h library, but I was running low on RAM on my Master Arduino, so I wanted to try the I2C library from DSS. This worked out well, DSS's RAM usage is about 168 bytes less then wire.h. The slave still uses wire.h.

In my test I pass 14 bytes from the slave to the master. The original variables are two bytes, two integers, a long integer and a float. I convert everything to a bytes array, send to the master then convert back again. I actually store the values in a typedef struct. Anyone can see the code here: https://github.com/Scott216/I2C-Examples

What I'd like to figure out next is how to have the master Arduino request specific data from the slave, not just a precanned array of 14 bytes. For example, lets day the slave has 3 temperature sensors connected to it. I'd like the master to be able to ask for the temp from sensor #2. I'd appreciate any suggestions on how to get started figuring that out.
# Wayne Truchsess 2013-04-07 00:58
Have the master send a byte that contains the information you want transmitted back. The slave can read the control byte and queue up the requested data.
# Edgar 2013-04-09 05:16
Hi Wayne!

Thanks for this great library!
I just tried to change my arduino-project code to get to work with this library instead of the stock version.

But I've run into a problem: I want to read and write an 32bit integer (uint32_t) to an i2c ram with the functions "I2c.write(addr ess, registerAddress , *data, numberBytes)" and the corresponding read function.

I just can't get it working. I tried it with " .. (uint8_t *)&val, uint8_t(sizeof (val))" in the funtion calls, where val is uint32_t. No luck - I always get back wrong values. I would be really thankful, if you could give me a hint or a short example!

Thanks in advance,
Edgar
# Frans 2013-04-19 18:15
Hello Wayne,

Your library looks very promising especially with multi-master configs. I have an existing i2c bus config with a P89V662 as master (i have no control over this device; it's a automatic dishpointing device). We want to read out a PCA9552 LED device which is controlled by this P89V662 (which is multi-master and arbitration compatible) with your library. The following code works:

#include
#define pca9552 0x67

int x = 0;
const int LED = 13;

void setup()
{
I2c.begin();
I2c.timeOut(80);
Serial.begin(115200);
pinMode(LED, OUTPUT);
}

void loop()
{
byte error;
int result;
error = I2c.read(pca955 2, 0x07,1);
if (error == 0)
{
x = I2c.receive()
# Frans 2013-04-19 18:19
x |= I2c.receive();
Serial.print(x);
Serial.print("\n");
}
digitalWrite(LED_BUILTIN,HIGH);
delay(50);
digitalWrite(LED_BUILTIN,LOW);
delay(1950);
}

But we often get i2c bus 'crashes'. we need to reset the master to get i2c traffic again. Can you point me in the correct direction how to prevent the arduino and the P89V662 from interfering?

Thanks and sorry fot the double post, didn't see the symbol limit at first..

Frans
# Wayne Truchsess 2013-04-20 14:36
Quoting Frans:
x |= I2c.receive();
Serial.print(x);
Serial.print("\n");
}
digitalWrite(LED_BUILTIN,HIGH);
delay(50);
digitalWrite(LED_BUILTIN,LOW);
delay(1950);
}

But we often get i2c bus 'crashes'. we need to reset the master to get i2c traffic again. Can you point me in the correct direction how to prevent the arduino and the P89V662 from interfering?

Thanks and sorry fot the double post, didn't see the symbol limit at first..

Frans

Are you looking at the signals on analyzer? At what point is it crashing? Have you tried enabling the timeout feature to release the bus?
# Frans 2013-04-20 15:21
Hello Wayne,

Yes i'm looking at a logic analyzer but don't know if it's fast enough / gives enough info (it's an oscium logiscope). I sent the current code by mail. I only read from the bus once every 5 seconds at the moment. The only time the bus hangs is when the satbox is searching; it sends a lot of updates through i2c for the display to see progress.

Couple of important things:

- i'm 'breaking' in on a cat5 cable between de satbox and display. This is a i2c bus with a P82B715 bus extender on both ends. So i'm sitting between those. Not sure if this is of any importance.

- the satbox and display communicate on ~54KHz but the arduino communicates on 100Khz. will this be a problem?

- The P89V662 microchip; is this always running in multimaster mode? I don't have enough experience to get this out of the datasheet.

I enabled the timeout and it does help some, but still the problem persists.

If you need more info let me know!
# Wayne Truchsess 2013-04-20 17:46
Quoting Frans:
Hello Wayne,

Yes i'm looking at a logic analyzer but don't know if it's fast enough / gives enough info (it's an oscium logiscope). I sent the current code by mail. I only read from the bus once every 5 seconds at the moment. The only time the bus hangs is when the satbox is searching; it sends a lot of updates through i2c for the display to see progress.

Couple of important things:

- i'm 'breaking' in on a cat5 cable between de satbox and display. This is a i2c bus with a P82B715 bus extender on both ends. So i'm sitting between those. Not sure if this is of any importance.

- the satbox and display communicate on ~54KHz but the arduino communicates on 100Khz. will this be a problem?

- The P89V662 microchip; is this always running in multimaster mode? I don't have enough experience to get this out of the datasheet.

I enabled the timeout and it does help some, but still the problem persists.

If you need more info let me know!

The problem is you really need to capture the signal when it locks up to get more information. For instance, you need to know if the other master is using repeated starts or not between write and read operations which will make a difference in multimaster configurations. You also need to verify the signals with the extenders are not too noisy and locking up the bus. A capture of both those signals would really help diagnose the isue further.
# Frans Rampen 2013-04-29 13:11
Hello Wayne,

I got my logic16 analyzer and did a analyze during the problem. As i'm a newbie in this could i email the log to you so you can have a look at it?

Regards,

Frans
# Frans Rampen 2013-04-22 12:38
Thanks wayne i bought a logic16 so i can capture all signals when the lock up happens. Will let you know when done.
# Frans Rampen 2013-04-29 14:09
Wayne,

I think i found something; looking at this screenshot:
It looks like the clock signal used is changed during a message. After this the clocksignal is pulled to ground permanently...

Frans
# Wayne Truchsess 2013-04-30 00:08
Quoting Frans Rampen:
Wayne,

I think i found something; looking at this screenshot:
It looks like the clock signal used is changed during a message. After this the clocksignal is pulled to ground permanently...

Frans
Hmmm...I'm not so sure you're other master (non Arduino) supports multi-master. From what I can see, the Arduino attempts to communicate with the slave device and then the other master tries to send a data byte. As you can see in the second setup write, the address receives a NAK which means it's probably trying to send a data byte when it thinks it already addressed the slave device. Hard to tell what's going on just from the screenshot so if you want to send me the file go ahead and I'll take another look.
# Frans Rampen 2013-04-30 09:11
Hello Wayne,

Here you go: support.yodahosting.nl/downloads/teleco.zip

I also included the datasheet of the i2c bus extenders used. I have ordered one so i can use it in star-config (see page 5) and use the arduino on a separate extender instead right on the buffered bus.
# Frans Rampen 2013-04-30 09:14
Oh i forgot to mention: arduino reads 0x67 register 0x16 every 5 seconds. the rest of the traffic is the teleco satbox (P89V662 chip)
# Wayne Truchsess 2013-05-01 01:04
Quoting Frans Rampen:
Hello Wayne,

Here you go: support.yodahosting.nl/downloads/teleco.zip

I also included the datasheet of the i2c bus extenders used. I have ordered one so i can use it in star-config (see page 5) and use the arduino on a separate extender instead right on the buffered bus.

It looks as though the other master is not waiting for the bus to free up before trying to communicate with the slave device. Basically the I2C master should not initiate a start condition when another device has the bus (this would be indicated by a stop bit). Since you're using the I2C.read function, you are doing a write followed by a read, and using a repeated start between the two operations. This is supposed to be the benefit of using a repeated start between operations (as compared to a stop then start) so the bus does not free up and you are able to finish your request. The other master however is not adhering to this and is trying to start between your write and read operations. Unfortunately I can't tell you which of the two (actually three devices if the slave supports clock stretching) is holding the SCL line low after it locks up (kind of the draw back to an open drain setup). You may have to implement some kind of tiing operation to only send the request when you know the bus will be free for a given time period.
# Frans 2013-05-01 18:40
Well i have no idea how to do that. Maybe it's best to so a software sampling of the i2c messages, like in this post: https://billgrundmann.wordpress.com/2009/03/03/sniffing-the-i2c-traffic-of-a-nunchuk/. This way it should be possible to capture the update messages from the existing master to the display and act on the data values. But unfortunately my c and i2c knowledge is too limited to convert this sample code to do so.. Anyway many thanks for your responses!
# Jim 2013-05-20 09:23
Hi Wayne and all...

I was just wondering if anyone has had any problems using:

I2c.write(addr, reg, pBuf)

I find that my device becomes unstable when I use it unless I limit the length of pBuf to 32 characters. I have not experimented to see exactly what the magic number is.

Also, I have found that I need to disable interrupts when I call it, although I suspect this is specific to the dual UART I am using. My guess is that when an interrupt triggers due to data coming in on port A, if I am in the process of sending data on port B is becomes unhappy.

Oh, I'm using it in slow speed, at least for my current testing.

Thanks!
# Peter 2013-05-20 11:01
Hi Wayne,

I am trying to make an xy-laser projector.
For that I use an Arduino and 2 DACs MCP4725. (I2C Digital Analog Converter)

The problem with the wire library is that the DACS are update one at a time.

It means I cannot draw diagonal lines.
It first finishes the X-movement and then the Y-movement.

So I get a horizontal and a vertical line.

I am not so familiar with bits and bytes programming.

Using the wire library, I use the following code:

Where "valx" is the position of the x-coordinate. It is the value I send to the DAC

In the top:

#define DACX 0x63


Wire.beginTrans mission(DACX);
Wire.send(64); // cmd to update the DAC
Wire.send(valx >> 4); // the 8 most significant bits...
Wire.send((valx & 15)
# Peter 2013-05-20 11:07
Hi Wayne,

I am trying to make an xy-laser projector. For that I use an Arduino and 2 DACs MCP4725. (I2C Digital Analog Converter)

The problem with the wire library is that the DACS are update one at a time.

It means I cannot draw diagonal lines.
It first finishes the X-movement and then the Y-movement. So I get a horizontal and a vertical line.

I am not so familiar with bits and bytes programming.

Using the wire library, I use the following code:

Where "valx" is the position of the x-coordinate. It is the value I send to the DAC

In the top:

#define DACX 0x63
Then
Wire.beginTrans mission(DACX);
Wire.send(64); // cmd to update the DAC
Wire.send(valx >> 4); // the 8 most significant bits...
Wire.send((valx & 15)
# Peter 2013-05-20 14:31
#define DACX 0x63

Then

Wire.beginTrans mission(DACX);
Wire.send(64); // cmd to update the DAC
Wire.send(valx >> 4); // the 8 most significant bits...
Wire.send((valx & 15)
# b0153n 2013-06-04 01:34
Hi all,

Please excuse me if this question is a bit noob... Thats because I am...

I am wanting to use an Omron LED driver (W2RF002RF) with an ATMega328p.
This is a proof of concept project and eventually I would like to add multiple W2RF002RF devices to the same i2c buss.
I have a reasonable amount of experience writing fairly basic programs for the 328p in the Arduino IDE.

The communications specification W2RF002RF calls for a particular bit sequence.

It says "When the START signal, '111111111' is detected, the communication circuit takes in data as new serial data... etc..."

As I understand i2c, it will send a 'start bit' followed by the address, followed by a register address, followed by the data.
In the case of the W2RF002RF, should I be setting the dummy address of 0xFF and a register address of the next 8 bits in the required stream, followed by the remaining data?

To understand my question you would first need to view the communication diagram on page 4 of the datasheet:
http://www.components.omron.com/components/web/pdflib.nsf/0/1894EFFD54A7C10686257A5D0077B2ED/$file/W2RF002RF_0812.pdf

Many thanks in advance.

Kent.
# Pat Erley 2013-06-07 23:16
Hooray for necro-bump.

I added support for this library to the i2cdevlib project. Can see what I did here:

https://github.com/s0be/i2cdevlib

Could someone double check that I got stuff straight? It 'Works for me', but my use case is pretty simple.
# b0153n 2013-06-09 20:18
Thanks Pat,
Now I just need to work out how to use you lib with the W2RF002RF...

Many thanks

Kent.
# Pat Erley 2013-06-09 20:44
Thanks. To be clear though, i2cdevlib isn't mine, but it's a pretty decent starting point for drivers for a lot of different i2c sensors. I added this i2c-master lib to it because I kept having my Arduino wire setup crash thanks to using i2c in a horribly noisy (electrically) environment.
# scott216 2013-06-14 00:26
I want to use I2C.h library with MMA8452 accelerometer I got from Sparkfun. The example library (bit.ly/12JW5fm ) doesn't work with Leonardo and I'm hoping I2C.h will. I'm not sure if I made the correct changes going from wire.h to I2C.h. Can you take a quick look at the last three functions (readRegisters, readRegister, & writeRegister) to see if they look right. I pasted the code here:
http://pastebin.com/3K58YXg7

Code in question starts at line 147
# sph 2013-06-30 11:24
Hi Wayne,

Are there any plans to port this library to Arduino Due?

Many thanks,
Stephan
# Wayne Truchsess 2013-07-02 12:49
Quoting sph:
Hi Wayne,

Are there any plans to port this library to Arduino Due?

Many thanks,
Stephan
I guess it really depends on how well the existing Wire library is working with the Due. This library was born more from necessity and frustration.I only recently acquired a Due and haven't had a chance to play around with it yet.
# sph 2013-07-02 19:05
Quoting Wayne Truchsess:
Quoting sph:
Hi Wayne,

Are there any plans to port this library to Arduino Due?

Many thanks,
Stephan
I guess it really depends on how well the existing Wire library is working with the Due. This library was born more from necessity and frustration.I only recently acquired a Due and haven't had a chance to play around with it yet.


According to the bug https://github.com/arduino/Arduino/issues/1251: Quote:
It appears to me the devs at one point realized the work ahead of them was not trivial, and decided to supply a base-line functionality (below current standards). This is not a meant as a dig, just reality.
A properly working I2C implementation would be great!

That said up to now my I2C devices (PCA9685, DS1307, BMP085) are working. I ran into problems with the MMA8451Q accelerometer (which led me to this implementation in the first place). To be honest I cannot say if it the sensor or me messing around with the breakout board...

What I certainly miss are that Wire.endTransmission() always returns non-zero (https://github.com/arduino/Arduino/issues/1251) and that Wire.available() always returns the number of bytes requested (https://github.com/arduino/Arduino/issues/1311) which renders the I2CScanner useless.

So to have Quote:
a software i2c lib that works on Due
(as leszekru put it in the above mentioned bug report) would be a really big gain!

Stephan
# scott216 2013-07-14 22:20
Quoting sph:

...That said up to now my I2C devices (PCA9685, DS1307, BMP085) are working. I ran into problems with the MMA8451Q accelerometer (which led me to this implementation in the first place).


Stephan,
I'd like to use this library with a MMA8452 accelerometer. Can you post your code for the MMA8451Q accelerometer? I'm hoping it's close enough to the MMA8452 to get me started.
--Scott
# sph 2013-07-14 22:46
Quoting scott216:


Stephan,
I'd like to use this library with a MMA8452 accelerometer. Can you post your code for the MMA8451Q accelerometer? I'm hoping it's close enough to the MMA8452 to get me started.
--Scott


Hi Scott,

I got myself a MMA8452Q because the MMA8451Q just did not work at all. I could get it working on Due with the following library: https://github.com/akafugu/MMA845XQ. At the moment I try to convert it to I2Cdevlib (https://github.com/jrowberg/i2cdevlib)...

Stephan
# Bilbolodz 2013-07-15 07:32
My working NNA8551Q version:
https://github.com/bilbolodz/MMA8451
# Jim Mooney 2013-07-02 20:46
Existing library does not work with DUE, has the same problem with the Accelerometer chip.
# daniel 2013-07-04 11:08
Hi, I tried the library with an arduino Leonardo, it works great, Thank you !
the saved space makes it a winner
# Brian K 2013-07-12 03:12
Hi Wayne and other guys. I just got started with Arduino a couple of months back and am trying to communicate with a Microchip MCP23017 IO expander. First, I tried the library from Adafruit for that chip and it locked up. I traced it down to the wire library. I then tried your library and the scan() method built into it. I get the message "There is a problem with the bus, could not complete scan". It looks like the hardware of the chip is never indicating that it has clocked out the address. What would prevent my AtMega329P (on a breadboard) from clocking the data out and going ready? Its on a breadboard. I bought it pre-programmed with the Arduiono loader. I have to select "Arduino Duemilanove w/ Atmega328" for board type when I upload sketches. Could the type of bootloader it has be interfering with the i2c port? Not sure what bootloader it is, but it's not optiboot. It has a bootloader that takes 2k. For chips with optiboot, I have select "Uno" for the board type (I programmed some blank chips)
# Brian K 2013-07-12 03:13
Meant to post my code:
#include

void setup()
{
I2c.begin();
Serial.begin(96 00);
Serial.write("W elcome to the scanner\n");
}

void loop()
{
// note: timeout is built in to scan function
I2c.scan();
while(true); // halt
}
# Wayne Truchsess 2013-07-12 12:41
Quoting Brian K:
Meant to post my code:
#include

void setup()
{
I2c.begin();
Serial.begin(9600);
Serial.write("Welcome to the scanner\n");
}

void loop()
{
// note: timeout is built in to scan function
I2c.scan();
while(true); // halt
}

Hi Brian. That message pops up when the ATMega times out waiting for either the start bit to complete or waiting for the slave address to successfully transmit. In either case this is most likely due to a hardware problem or miswiring problem. If the SCL or SDA lines are being pulled to ground constantly this message will pop up. Try removing the slave device and all wiring completely and rerun the scanner. If you get the same message, then there is something wrong with the Atmega or a short on the board. If you have a meter you can check the idle voltage on the SCL and SDA lines and they should be 5 volts (or Vcc). If that test says no devices found, reconnect your slave and measure the voltage again on the SDA and SCL lines and verify they are again 5v. You can also check the voltage on the slave SCL and SDA lines without hooking the I2C (still need power though) and make sure they are not shorting to ground either.
# Brian K 2013-07-12 19:11
Thanks Wayne, dropping in another chip solved the problem. It must be a bad chip. I havent researched enough to learn if it could be the config of the chip set by the bootloader
# scott216 2013-07-16 22:14
Anyone know where I can find code to use this I2C.h library with a DS1307 Real Time Clock?
# daniel 2013-07-17 07:07
You probably wont beable to use teh existing Arduino DS1307 RTC library ( that is built on the wire library)

but you should be able to speak with the DS1307 with this library ( correct clock rate and if you send the right address and valid data)

have a look at the DS1307 datasheet to see what to say to it and how to say it and you should be fine
# daniel 2013-07-17 07:10
or have a look at the adafruit DS1307 library and replicate those commands with IIC library
# scott216 2013-07-18 01:38
I'm not sure if I'm on the right track or not. Would the following be the right way to get starting making the switch from from Wire to I2C for the RS1307? BTW i is an integer with zero value.

void RTC_DS1307::adj ust(const DateTime& dt) {
// New I2C.h code
I2C.write(DS130 7_ADDRESS, i);
I2C.write(DS130 7_ADDRESS, bin2bcd(dt.seco nd()));
I2C.write(DS130 7_ADDRESS, bin2bcd(dt.minu te()));
I2C.write(DS130 7_ADDRESS, bin2bcd(dt.hour ()));
I2C.write(DS130 7_ADDRESS, bin2bcd(0));
I2C.write(DS130 7_ADDRESS, bin2bcd(dt.day( )));
I2C.write(DS130 7_ADDRESS, bin2bcd(dt.mont h()));
I2C.write(DS130 7_ADDRESS, bin2bcd(dt.year () - 2000));
I2C.write(DS130 7_ADDRESS, i);

/* Orig wire code
Wire.beginTrans mission(DS1307_ ADDRESS);
Wire.write(i);
Wire.write(bin2bcd(dt.seco nd()));
Wire.write(bin2bcd(dt.minu te()));
Wire.write(bin2bcd(dt.hour ()));
Wire.write(bin2 bcd(0));
Wire.write(bin2bcd(dt.day( )));
Wire.write(bin2bcd(dt.mont h()));
Wire.write(bin2bcd(dt.year () - 2000));
Wire.write(i);
Wire.endTransmi ssion(); */
}

Here's a function that's using receive/read:

DateTime RTC_DS1307::now () {

// New I2C.h code
I2C.write(DS130 7_ADDRESS, i);
I2C.requestFrom (DS1307_ADDRESS , 7);
uint8_t ss = bcd2bin(I2C.rec eive() & 0x7F);
uint8_t mm = bcd2bin(I2C.rec eive());
uint8_t hh = bcd2bin(I2C.rec eive());
I2C.receive();
uint8_t d = bcd2bin(I2C.rec eive());
uint8_t m = bcd2bin(I2C.rec eive());
uint16_t y = bcd2bin(I2C.rec eive()) + 2000;

/* Orig wire code
Wire.beginTrans mission(DS1307_ ADDRESS);
Wire.write(i);
Wire.endTransmi ssion();
Wire.requestFro m(DS1307_ADDRES S, 7);
uint8_t ss = bcd2bin(Wire.re ad() & 0x7F);
uint8_t mm = bcd2bin(Wire.re ad());
uint8_t hh = bcd2bin(Wire.re ad());
Wire.read();
uint8_t d = bcd2bin(Wire.re ad());
uint8_t m = bcd2bin(Wire.re ad());
uint16_t y = bcd2bin(Wire.re ad()) + 2000;
*/

return DateTime (y, m, d, hh, mm, ss);
}
# daniel 2013-07-18 06:44
That looks like it will work. :)

you might need to change
" RTC_DS1307::isr unning(void)" too-

so that all the examples will work seamlessly

and remeber to call
I2c.begin(); in "Setup" , or you may add it to the Ds1307 library :

uint8_t RTC_DS1307::beg in(void) {
I2c.begin();
return 1;
}

otherwise the I2C never starts and nothing will get said ( these silly things happen at 4 in the morning programs :) )
# scott216 2013-07-18 13:29
I only posted part of the code, I wanted to make sure I was at least thinking about this the right way. I'll post the whole thing then I'm done.

I'm assuming that when using I2C verses wire, these two code snippets do the same thing:

// wire.h library
Wire.beginTransmission(DS1307_ADDRESS);
Wire.write(i);
Wire.endTransmission();


// I2C.h library
I2C.write(DS1307_ADDRESS, i);


What has me confused is I don't really understand is how the DS1307 is interpreting the repeated write commands. The write command isn't specifying a register, so how does the DS1307 know what to do with the data?
# scott216 2013-07-19 01:04
I got the DS1307 working with the I2C.h library!! I posted the files on GitHub:

http://github.com/Scott216/RTCLib_wo_wire
# daniel 2013-07-19 05:26
I think the DS1307 auto increments the register if it gets more data before getting a stop condition- will have to look in the datasheet to confirm,

I'm happy that your port of the DS1307 works :)
# scott216 2013-07-19 11:42
Quoting daniel:
I think the DS1307 auto increments the register if it gets more data before getting a stop condition- will have to look in the datasheet to confirm.


I took a look at the data sheet and it seems like that's what's it's doing.
# scott216 2013-07-30 03:11
How would you convert this code from wire to DSS's I2C? I'm having trouble getting it to work with Adafruit's 128x32 OLED display.

for (uint16_t i = 0; i < 512; i++) {
// send a bunch of data in one xmission
Wire.beginTrans mission(_i2cadd r);
Wire.write(0x40 );
for (uint8_t x = 0; x < 16; x++) {
Wire.write(buffer);
i++;
}
i--;
Wire.endTransmi ssion();
}
# Charly 2013-07-30 08:11
void Adafruit_SSD130 6::display(void )
{
ssd1306_command (SSD1306_SETLOW COLUMN | 0x0); // low col = 0
ssd1306_command (SSD1306_SETHIG HCOLUMN | 0x0); // hi col = 0
ssd1306_command (SSD1306_SETSTA RTLINE | 0x0); // line #0

// I2C
for (uint16_t i=0; i
# Charly 2013-07-30 08:13
=0; i
# Charly 2013-07-30 08:15
for (uint16_t i=0; i
# scott216 2013-08-05 04:29
After a lot of trail and error and several hours I finally got the SSD1306 OLED display to work with this library.
Code is on Github:
http://github.com/adafruit/Adafruit_SSD1306
# Charly 2013-07-30 08:07
Scott
you're a lucky guy, I already using the Adafruit Display with the new I2C library, works fine.
Let me find the code and I will post it on this forom
# Charly 2013-07-30 08:14
Seems I have problem to post code on the forum, let me your email, I will drop you the full working files
# scott216 2013-07-30 13:55
Quoting Charly:
Seems I have problem to post code on the forum, let me your email, I will drop you the full working files


I had this problem also, that's why I didn't post the the code I was experimenting with. But I figured out why the comment wasn't posting, you need a space before and after the < symbol. I noticed it would have problems with an if() statement, so I put spaces before and after = and < symbols.
# Sergi Valls 2013-08-21 22:20
Hi,

The library is brilliant. However as a newbie I am, I maybe miss something.
I want to configure a system with 4 Arduinos.
Each can talk to each other anytime.
So to achieve this the best approach is the multimaster approach. No problem since I2C admits it.
But I can not configure the address of any Arduino with this library, or I am missing something?
# Wayne Truchsess 2013-08-22 00:31
Quoting Sergi Valls:
Hi,

The library is brilliant. However as a newbie I am, I maybe miss something.
I want to configure a system with 4 Arduinos.
Each can talk to each other anytime.
So to achieve this the best approach is the multimaster approach. No problem since I2C admits it.
But I can not configure the address of any Arduino with this library, or I am missing something?

Unfortunately the library only works as a Master. To take advantage of Slave mode you would have to use the Wire library..
# scott216 2013-08-22 00:51
Wayne,
Do you have any plans on writing a slave version? I use your I2C library all the time. I just finished a project where I have an accelerometer, RTC, 7-segment display and 32x128 OLED display (adafruit) that all use I2C and your library with a Leonardo. Everything works great. I had to fiddle with the libraries of these devices, but I got it figured out.
# Wayne Truchsess 2013-08-22 01:02
Quoting scott216:
Wayne,
Do you have any plans on writing a slave version? I use your I2C library all the time. I just finished a project where I have an accelerometer, RTC, 7-segment display and 32x128 OLED display (adafruit) that all use I2C and your library with a Leonardo. Everything works great. I had to fiddle with the libraries of these devices, but I got it figured out.

No plans for a slave version. Honestly I've never had any issues with Wire when it comes to using it on the slave side. The only issue is that it lacks the ability to acknowledge a repeated start but that's an easy fix.
# Sergi Valls 2013-08-22 06:21
Quoting Wayne Truchsess:
Quoting Sergi Valls:
Hi,

The library is brilliant. However as a newbie I am, I maybe miss something.
I want to configure a system with 4 Arduinos.
Each can talk to each other anytime.
So to achieve this the best approach is the multimaster approach. No problem since I2C admits it.
But I can not configure the address of any Arduino with this library, or I am missing something?

Unfortunately the library only works as a Master. To take advantage of Slave mode you would have to use the Wire library..


Hi Wayne, thanks for your fast reply.
I do not want to use it as a slave. I want to use it as a Multimaster, but in order to be able to send messages to each other I need every arduino with an address.
# Dan S 2013-09-14 08:48
Hi Wayne,

So I ran across your library, and hoped it would help with my issue. (It's helped a little on one of the AVRs but not the other).. My situation is this.. I have one AVR doing a bunch of work (main master), I need it to pull data from a 2nd AVR (due to some of hte stuff on the 1st AVR being time sensitive, plus just sheer code size, I didn't design the first AVR setup). Software Serial was flakey at best.. So i went to I2C.. Here's the problem... AVR1 asks for data from AVR2, AVR2 has to get data periodically from an i2c EEPROM (as well as it updates an i2c LCD).. it would seem that when the AVR2 is running this way. I can talk to the LCD _until_ it's been contacted by AVR1. After that, AVR2 can only respond to AVR1, it can't talk to it's own devices. The LCD is using the LiquidCrystal_I 2C library (so it's not even using Wire, so i'm thinking that's part of the collision). Without the _master_ talking to it, the lcd and the eeprom of course coexist. Any ideas/thoughts? Thanks.
# D9W 2013-09-15 02:37
@Dan S -this is somewhat off topic but There is a better LCD library over at Adafruit.com- it cleans up some of the problems of LiquidCrystal_I 2C's library but like so many things it has a catch 22, it is tied to print library. As long as LiquidTWI could be untied from Wire then I could see Wayne's library working with this faster library.

Mark is the guy that started this library and you can find his explanation of the library here >> http://forums.adafruit.com/viewtopic.php?f=19&t=21586

Stephanie followed up with her version that works with Arduino 1.0+ and you can read what she added to the library here >> http://forums.adafruit.com/viewtopic.php?f=22&t=25656.

The GitHub for the LiquidTWI can be found here >> https://github.com/Stephanie-Maks/Arduino-LiquidTWI .

I know this might not help, but I thought you could look at it and see if any of that code could help with your issue.
# Paul D 2013-09-18 19:33
Wayne,

I'm trying to work with a (up to) 1 mhz Fm+ LED controller, the PCA9685. Any simple way to go beyond 400mhz with your library? The long data byte transmission (>32) is essential to controlling this IC. Any idea what's the highest speed I2C transmission the Arduino UNO can do?
# Chris L 2013-11-16 02:17
Can I2C be slowed down using this library? I'm trying to extend the distance of I2C beyond a few meters and my understanding is that slowing the clock down will help with that. I've tried altering the code to read like so:
TWBR = ((F_CPU / 500) - 16) / 2;
Yet it doesn't seem to affect anything. Am I missing something with how clock speed is set?

Thanks!
# Wayne Truchsess 2013-11-27 14:03
Quoting Chris L:
Can I2C be slowed down using this library? I'm trying to extend the distance of I2C beyond a few meters and my understanding is that slowing the clock down will help with that. I've tried altering the code to read like so:
TWBR = ((F_CPU / 500) - 16) / 2;
Yet it doesn't seem to affect anything. Am I missing something with how clock speed is set?

Thanks!

Try using something like 50000 instead of 500. I haven't really played around with it enough on the low end to know if there are any lower limits or certain multiples allowed.
# Vijay Patil 2013-11-27 12:38
is there any plan to port this library to work on Due.
Because wire.endTransmi ssion() is returning non zero value.
It will be very usefull if we port this library to work on Due.
# Wayne Truchsess 2013-11-27 14:11
Quoting Vijay Patil:
is there any plan to port this library to work on Due.
Because wire.endTransmission() is returning non zero value.
It will be very usefull if we port this library to work on Due.

UGGGHHHH!!!! I feel your pain with the DUE and Wire. There's actually even more issues that I've stumbled upon. If you interrupt communication between the master and slave before the stop bit is sent (like when you recompile and upload the code again) and the SDA is still low, the DUE can not recover no matter how many times you hit the reset button. It takes a power cycle to reset the bus. The UNO has no issues with recovering from this situation (even with the default Wire library). They also didn't enable the functionality for repeated start. I would like to start working on this, time permitting ofcourse, but I'd like to see some of the programming examples from Atmel first on implementation as the datasheet is kind of lacking in it's write up of Two Wire. There is a software package on Atmel's site but the link appears to be broken so I can download anything.
# JP Miller 2013-12-02 05:55
I am trying to use an MCP4662 digital pot. It works with an non-Arduino I2C controller. With Wire I can get some functions to work but not the reads that use repeated start.

So I tried I2C Master Library. I am having difficulty just getting it to work.

The sketch increments the wiper then decrements the wiper.

#include

void setup() {

I2c.begin();
Serial.begin(96 00);
while(Serial.av ailable() == 0);
while (Serial.read() >= 0) {};
}

void loop() {
Serial.println( "loop");
int ix=0;
while(ix < 256){
int a = I2c.write(0x2C,0x04);
//increment
Serial.println( a);
ix=ix+1;
}
ix = 0;
while(ix < 256){
int a = I2c.write(0x2C,0x08);
//decrement
Serial.println( a);
ix=ix+1;
}
}

In various diagnostic attempts I can verify the I2C just hangs. This works if I use
Wire.beginTransmission(0x2c);
Wire.write(0x04);
Wire.endTransmission();

What am I doing wrong?
# JP Miller 2013-12-02 06:01
Sorry I don't know how to format.
The include had the when I entered the file and it was properly indented. JP
# Reuti 2013-12-04 10:37
While looking around how to interface several I2C devices with the Arduino I came across this page. Being new to Arduino I read the reference of the wire library and found that it accepts an argument to Wire.endTransmi ssion(false) to send a restart condition instead of a stop too.

But I ended up here due to a different problem and would appreciate any hint whether it's solvable at all with a different library instead of Wire. Connecting a Microchip 24LC65 to an Arduino is quite easy. But on page 12 in http://ww1.microchip.com/downloads/en/DeviceDoc/21073k.pdf they have a command to "read while being in write mode" ("Security Read" and "High Endurance Block Read"). After having a look at the datasheets of the ATtiny 85 and ATmega328p I get the impression, that such a mode isn't supported by the AVRs at all. Do I get it right - is it in the spec of I2C to read while writing? I also had a look at the spec myself in http://www.nxp.com/documents/user_manual/UM10204.pdf but couldn't spot anything whether it's allowed or forbidden.

NB: Normal operation of the 24LC65 is working as expected. Also the "security block" and "high endurance" blocks can be defined and work as expected. It's just impossible to read back which blocks were assigned to these functions.
# Guest 2013-12-26 16:51
Greets! Love the idea of your lib - trying use I2C to create a class to replace the Adafruit 7-segment lib which I'm calling SevenSegMgr.cpp and .h.

I'm also working in Visual Studio 2012 with Visual Micro addon. As far I know I've set up the files for the class correctly, but can't seem to get I2c functions to be properly recognized, and getting 'ambiguous overload' errors. Is I2c set up to be used as part of another class or is it intended to be simply included in a .ino sketch?

=Alan R.
# scott216 2013-12-27 06:12
I modified Adafruit's LED Backpack library to work with the I2C.h library. I've used it with their 7-segment display only. You can find my version on GitHub:

https://github.com/Scott216/Adafruit-LED-Backpack-Library-I2C
# Guest 2014-01-01 12:37
Hi
I have a problem with library
I use Arduino IDE 1.5.2
ok, when I try to compile the sketch i receive this error
C:\Users\Simone\Documents\Arduino\libraries\I2Cmaster/i2cmaster.h:88: fatal error: avr/io.h: No such file or directory

How can I resolve it?

Thanks
Simone
# Guest 2014-01-07 20:45
I am trying to use this library with my arduino leonardo and i would like some help. i am trying to read/write at an 24lc256 EEPROM with the following skecth

#include
#define ADDRESS 0x50

int test;

void setup()
{
Serial.begin(96 00);
I2c.begin();
I2c.write(ADDRE SS,0x00,0x00,35 );
test = I2c.read(ADDRES S,0x00,1);
delay(5000);
Serial.println( test);

}

void loop()
{

}


but all i get at the serial monitor is 32 and not the number i am trying to write at the eeprom
# Guest 2014-01-08 10:13
After writing it’s necessary to put a delay of 5 ms (datasheet page 4: “Write cycle time (byte or page)”). To avoid unnecessary writes it’s also good to write always in bunches of pages (better than writing 64 individual bytes, where always the complete page will be rewritten).
# electroschematics 2014-04-12 06:47
Hi, What is the best way to read data from registers? Inside the loop() or where? I am asking this because I am trying to build a small car fm transmitter and although I managed to transmit there is a small noise (pop) every time (5 sec) I read the registers inside the loop() where I have a 5 seconds delay; Based on the readings if something is not correct I make some writtings in the registers.
# iyab 2014-07-31 02:08


**Unable to read the register using I2C**


Hi Guys,

http://i.imgur.com/ZqqD8I3.jpg?1

I have shared an image of my bus activity when my my Arduino Uno tries to talk to one of my Bosch IMU. I want to implement I2C.
I am trying to READ the STATUS register to check whether my accelerometer is in the NORMAL mode. And to READ the data from the STATUS register, I am first sending the REG ADDRESS (0x03) through a WRITE operation on the slave (0x69) and then READ the same register. As shown in the image, it initiates the write operation, sends the address and initiates the read operation. Everything's good so far, but after that it activates 5 clock pulses (marked with red pen in the image) following the read operation which makes no sense to me. It should have given me 9 clock pulses after the Setup Read in which I would have received the data on that register. On top of it, the sensor which is suppose to be passive and act only when the clock pulses are received goes high in the SDA line even when there is no pulse. How do I extend this clock in the SCL line to receive and read what my sensor is giving me?
Since you said, there are problems with the WIRE library, I tried your I2c library but the problem persists.

Code:

#include

#define IMU 0x69


void setup()
{
Serial.begin(96 00);
I2c.begin();
I2c.write(IMU, 0x7E,0x11);
delay(100);
}

void loop()
{
I2c.read(IMU,0x 03,1);
x = I2c.receive();
Serial.println( x, HEX);
}

Please let me know about what could be the problem here?
# Wayne Truchsess 2014-07-31 02:50
Your picture is actually incomplete as it does not show what happens after the setup to read is acknowledged. The next sequence should be to receive the byte however that is cut off.

As for the gap in the SCL pulse that can be the slave device stretching the clock. Some slave devices support clock stretching so even though it may be a passive device it can hold the SCL line low to halt the transfer if it's not ready to send the data yet. (i.e. collecting data or crunching numbers).
# iyab 2014-07-31 20:37
Thanks for the reply. Yes, even I am expecting the data to come up next but it doesn't happen.

So, after the Ack signal, the SDA line is low for 2.6ms and there are no clock pulses in the SCK line. I am expecting a 0x01 during this time but I am having a hard time finding what is going wrong with it.

I am attaching three images showing the same timing diagram with different zooms. Please let me know about your comments.

overall scene:

Zoom in:

Zoom in more:
# Wayne Truchsess 2014-08-01 01:52
My best guess is something is wrong with your IMU. What is the part number of the IMU you are using, I'd like to take a look at the datasheet.

Something is pulling the SCL line low and I doubt very much it's the Arduino. There really is no way to implement low level code to try and extend the clock. During a read operation the SCL line will continue to try and clock data in on the SDA line until it receives the last byte from the slave which is denoted by the slave generating a NACK after the last byte is sent.

It would be interesting to see if you have the same problem sending multiple bytes of data to a configuration register.

I still think the IMU is holding the SCL line low. You could try and program in a Timeout to release the line before the 2.5ms elapses and see if both SDA and SCL lines go high.
# iyab 2014-07-31 20:53
Quoting Wayne Truchsess:


As for the gap in the SCL pulse that can be the slave device stretching the clock. .


No, I consulted the company and even the datasheet and they said the slave does not have clock stretching.

Login

Go to top