As I have indicated above, the clock line has two glitches where it should have a proper clock pulse. The master generates the clock but the slave is allowed to stretch it by extending the low portion. Normally it is hard to tell which device is driving the bus but in this case it is obvious because I got the pull up resistors too small for the MSP430. I forgot that the MSP430 is aimed at low power applications so has an unusually low drive capability.
I still wasn't sure which end was the problem so I coded the host end in software so I could see exactly what the slave was doing. It is relatively easy to do an I²C master in software because it does not have any strict timing deadlines. The slave does, so it is more difficult to implement purely in software.
It turns out the problem lies with the mask revision of the MSP430F2013s that I am using. Revision B has several I²C bugs such as pulling the clock low when it shouldn't and no workarounds. I have had my chips for some time, long before I started this project. Two are actually labeled with a mask revision of X which is undocumented. It seems to have at least all the bugs in mask B. The other is labeled as mask B, so none are of any use for I²C!
Very disappointing that these days a device has to have three or four mask revisions just to get something as simple as an I²C module working. This seems to be the way things are going: hardware is becoming just as buggy as software. I wasted some time at work recently discovering that the UART in a PIC18F65J10 occasionally inserts zero bytes in the middle of your packet. These things were lab exercises when I was an undergraduate, now big companies can't get them right.
Fortunately, I had some MSP430F2012s that were mask revision B and the I²C bugs were fixed one revision earlier on that chip. They are slightly different in that they have a 10 bit SAR ADC instead of a 16 bit sigma-delta ADC. This is actually more appropriate for my application but it has a completely different software interface and voltage range.
Once I had swapped to the MSP430F2012 and modified the firmware for the new ADC, the I²C bus sprang into life. That was until I started to run the motor whereupon I got occasional bus lockups. This is due to the massive amount of noise coming from the brushes of the DC motor. I get about 2.5V of noise on the I²C lines
Using I²C without buffers for anything other than inter IC comms is a really bad design decision, I am not sure what came over me. I normally use RS485 differential comms when linking boards that drive motors or other high current loads and have never had a problem with noise. I even think I have publicly criticized the RepRap design for converting the RS232 to 5V signals before sending it around the ring of control boards. It was tempting to give I²C a try because I already had micros that support it, and didn't have UARTs, and my screened cable is only about a foot long. I²C is particularly susceptible to noise though because it is only actively driven low and because it is edge sensitive. Also the data rate I chose is five times faster than RepRap uses and I am using 3.3V logic rather than 5V. I²C also has the nasty feature that corruption can cause the bus to lock up which doesn't happen with asynchronous comms.
One thing I noticed was that earthing the can of the motor made things a lot worse by coupling the noise onto the ground rail. I established that the noise is conducted rather than radiated by running the motor from a separate bench PSU. I also managed to get it to run reliably by adding some 2200pF capacitors to the I²C lines, but that is a horrible bodge! Other things I will try :-
- Change the pullup resistors from 1K to 2K2 so that the MSP430 can pull them fully low. That will increase the logic low noise immunity but make the logic high immunity worse.
- See if I can program the master to clear the bus lockup.
- Add a CRC and packet sequence flags so I can detect errors and do retries.
- See if I can suppress the motor better.