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.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.

- 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

Comments

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.

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.

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.

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.

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.

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?

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!

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.

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 .

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!

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.

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

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!

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

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.

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.

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.

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.

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 regardsVaclav

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.

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

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.

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 microcontrollers 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.

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.

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 #endifAnd then all was good.

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 directoryIn 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 declaredC:\Users\Abdul Mughal\Desktop\ARDUINO SOFTWARE\arduino-1.0-windows\arduino-1.0\libraries\I2C/I2C.h:71: error: 'boolean' has not been declaredC:\Users\Abdul Mughal\Desktop\ARDUINO SOFTWARE\arduino-1.0-windows\arduino-1.0\libraries\I2C/I2C.h:101: error: 'boolean' has not been declared

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 directoryIn 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 declaredC:\Users\Abdul Mughal\Desktop\ARDUINO SOFTWARE\arduino-1.0-windows\arduino-1.0\libraries\I2C/I2C.h:71: error: 'boolean' has not been declaredC:\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

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.

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.

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.

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 EnableWhen this bit is written to one, and the I-bit in SREG is set, the TWI interrupt request will be activatedfor 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.

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 EnableWhen this bit is written to one, and the I-bit in SREG is set, the TWI interrupt request will be activatedfor 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.

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, 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.

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.

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.

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.

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.

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.

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.

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

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

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, andTWSR is updated with a status code indicating that the START condition has successfullybeen sent.3. The application software should now examine the value of TWSR, to make sure that theSTART condition was successfully transmitted. If TWSR indicates otherwise, the applicationsoftware might take some special action, like calling an error routine.

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.

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.

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.

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

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.

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

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.

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.

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.

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.

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?

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.

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.

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.

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'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.

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).

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.

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.

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.

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.

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.

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.

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.

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.

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.

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

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.

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.

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?

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.

….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.

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.

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.

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.

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.

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.

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.

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-driven I2C library for the Arduino (or write one myself- yikes!)

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.

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?

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.

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...

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()); }

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 ....

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-controller due to the 7-bit wire library limitation.

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!

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?

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

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'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(address, 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(address, registerAddress) followed by I2c.read(address, 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.

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...

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 scopeC:\Users\DELL\Documents\00프로그래밍자료\Work\libraries\I2C\I2C.cpp:95: error: 'TWSR' was not declared in this scopeC:\Users\DELL\Documents\00프로그래밍자료\Work\libraries\I2C\I2C.cpp:95: error: 'TWPS0' was not declared in this scopeC:\Users\DELL\Documents\00프로그래밍자료\Work\libraries\I2C\I2C.cpp:96: error: 'TWPS1' was not declared in this scopeC:\Users\DELL\Documents\00프로그래밍자료\Work\libraries\I2C\I2C.cpp:97: error: 'TWBR' was not declared in this scopeC:\Users\DELL\Documents\00프로그래밍자료\Work\libraries\I2C\I2C.cpp:99: error: 'TWCR' was not declared in this scopeC:\Users\DELL\Documents\00프로그래밍자료\Work\libraries\I2C\I2C.cpp:99: error: 'TWEN' was not declared in this scopeC:\Users\DELL\Documents\00프로그래밍자료\Work\libraries\I2C\I2C.cpp:99: error: 'TWEA' was not declared in this scopeC:\Users\DELL\Documents\00프로그래밍자료\Work\libraries\I2C\I2C.cpp: In member function 'void I2C::end()':.......

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) START2) B00001001 (this is expected: I’m using 4 as my slave address and 1 indicates a read)3) ACK4) 0x01 (expected: this is the first byte of my data payload. 4 in total…)5) ACK6) 0x047) ACK 0x029) ACK10) 0x00 (excpected: last bye of my data payload)11) ACK12) 0xff (???? This is NOT expected. I would expect a STOP. Was a clock pulse was missed maybe?)13) ACK14) 0xff (this and the ACK is repeated 15-20 times or so)15) NACK (yes, I finally get a NACK)16) STOP17) START18) 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?

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.

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.

Hi Mark,The problem has something to do with UARTIncomingPacketSize . 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.

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 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.

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?

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).

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.

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

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...

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.

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.

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.

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.

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?

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.

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.

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.

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".

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

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.

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.

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.

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.

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??

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.

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.

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.

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.

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 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 ?

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 ?

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

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.

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.

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.

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(address, 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!

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:

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.

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.

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.

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.

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.

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!

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.

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

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.

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

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.

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.

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...

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)

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.

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?

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.

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?

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..

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,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.

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.

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_I2C 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.

@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.

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?

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?

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.

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.

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.endTransmission(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.

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?

HiI have a problem with libraryI use Arduino IDE 1.5.2ok, when I try to compile the sketch i receive this errorC:\Users\Simone\Documents\Arduino\libraries\I2Cmaster/i2cmaster.h:88: fatal error: avr/io.h: No such file or directory

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).

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.

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.

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).

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.

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.

I just wanted to let you know that people, including myself, are still being saved from those unexplainable problems caused by Arduino-Wire, thanks to your brilliant work.You saved our project from having to use 2 mcu's (and potentially create more problems!)