Wire library problems

On an Arduino Pro Mini and Nano, 16MHz, 5V.

I am using a display (OLED SSD1306) and libaries which I wrote myself that use the Wire library which in turns uses the TWI.C file.

Frequently the program hangs, and then after 4 seconds the watchdog kicks in . I have traced the problem to the display and I believe it is interference on the 4 wires connecting the display to the motherboard.

Be that as it may, it would be better if the Wire library did not just hang but return some sort of error / abort the operation - anything is better than a hang.

So I took it to trace the issue, without much understanding how the TWI works, and I have spent just 2 minutes and I have come across this:


// wait until twi is ready, become master receiver
while(TWI_READY != twi_state){
continue;
}


This really seems like shoddy piece of code.

I am reading more now, but if you are familiar with the library (Wire + TWI) and have come across similar issues please let me know.

OK I have done more debugging. It seems there is a misunderstanding as to the use of TWBR in various libaries and also this documentation I believe is in error:

http://playground.arduino.cc/Main/WireLibraryDetailedReference

It says "TWBR=400000L should set it to 400kHz. "

I think this is wrong. TWBR is calculated based on the CPU frequency and on the desired TWI clock - the formula is:

/* twi bit rate formula from atmega128 manual pg 204
SCL Frequency = CPU Clock Frequency / (16 + (2 * TWBR))
note: TWBR should be 10 or higher for master mode
It is 72 for a 16mhz Wiring board with 100kHz TWI */


The Wire library has a public function "setClock(frequency)" and it sets the desired frequency. I believe this is the proper way of setting the desired frequency, and it should not be too fast or it will result in instabilities.

See: Gammon Forum : Electronics : Microprocessors : I2C - Two-Wire Peripheral Interface - for Arduino

I have some figures for TWBR there.

The problem with hangs is quite well-known. They assume they will get an interrupt, too bad if you don't.

There is an alternate library, mentioned on my page, that has a time-out. Also try putting in pull-up resistors if you don't have them already.

Thanks. I have read and have saved the whole page for reference.

TWBR seems to be misunderstood judging from some code I have seen as well as on the Arduino's official docs, it should be set as:

TWBR = ( ( CPU_F / SCL_F ) - 16 ) / 2

Therefore on a 16MHz Atmega if we want 400KHz TWI clock the value for TWBR would be 12. For a 100KHz clock the value would be 72.

In my case with 4" length wires, I was setting TWBR to 0, somehow, and that equates to a clock of 1MHz, so yes it works, but it is quite fragile from interference. As soon as I set it to 400KHz it has worked fine.

Therefore on a 16MHz Atmega if we want 400KHz TWI clock the value for TWBR would be 12. For a 100KHz clock the value would be 72.

Yes, I think my page said that.

Setting it to zero won't work.

TWBR   prescaler   Frequency
 
  12       1       400   kHz  (the maximum supported frequency)

Note the words: maximum supported frequency

If you operate outside the limits mentioned in the datasheet, yes it will appear to be "fragile". That's why they quote those limits.