10 years ago.

i2c.write() i2c.read() is Stalling when either pin SDA or SCL is disconnected

I started using the I2C Master functionality using the I2C Class and I've got some questions about it.

I set up pins P28 and P27 for SDA and SCL. So far the interface is working fine.

However when I loose the I2C connection (either disconnected wire or Vcc lost) I noticed that function calls i2c.write() or i2c.read() would stall from about 5 seconds to a 30 seconds waiting for ACK from the slave IC. Well since my program can't wait forever for the ACK I'd like to know if there is a breakout feature from I2C interface so that if within one second I get no ACK I can stop either i2c.write() or i2c.read() function.

The next question is function frequency (int hz) in I2C class. If I want to change to 200Khz do I write i2.c.frequency (200) or i2.c.frequency (200000) .

It looks like the functions i2c.write() and i2c.read() incorporate START and STOP condition on the I2C bus.

Then what's the reason for the i2.c.start() and i2c.stop() functions for? When I used them with i2c.write() and i2c.read() the I2C interface would not work.

I would appreciate a lot if you answer my questions (especially about the stalling problem).

Question relating to:

2 Answers

9 years, 12 months ago.

He Elik,

(1) Waiting ACK from slave

If the I2C is working properly, an ACK or NACK will be returned from the slave immediately. In this case, you can check the status by return value of i2c.wirte() and i2c.read() functions.

    status  = i2c.write( I2C_SLAVE_ADDRESS, data, sizeof( data ) );
    printf( "  \"i2c.write()\" done. status = 0x%02X\r\n", status );

However, if the slave holds the SCL line LOW to let master wait the transfer (called "clock stretching"), you need to wait for a while.
Similar thing may be happened if the pull-up register is removed or does not exist. (The signal line got LOW)

I tried to make this situation on my environment but the timeout works fine.
Some old version of mbed-SDK (mbed library) doesn't have short timeout period. With those versions, you need to wait long time. But I believe current version of SDK may work with short period.
Please update the mbed library and try.

(2) SCL frequency setting

As Erik already answered, for 200kHz, it should be like i2c.frequency( 200 * 1000 );

(3) START and STOP functions

The i2c.start() and i2c.stop() functions are prepared for users who want to operate I2C manually.
Following two code samples are equivalent.

transfer_by_array

    /*
     *  4 bytes data transfer sample
     */
    char    data0[]  = { 0x80, 0x00, 0x05, 0x05 };

    i2c.write( I2C_SLAVE_ADDR, data0, sizeof( data0 ) );


transfer_byte_by_byte

    /*
     *  This is just a sample. Don't use this code for real transfer. 
     *  To be compliant to I2C specification, the code should be later sample in this topic.
     */
    i2c.start();
    i2c.write( I2C_SLAVE_ADDR );
    i2c.write( 0x80 );
    i2c.write( 0x00 );
    i2c.write( 0x05 );
    i2c.write( 0x05 );
    i2c.stop();


But please be careful when you write transfer in "byte by byte" manner. To make the code compliment to I2C specification, you need to check the status at each byte to abort the transfer when the ACK was not returned.
It can be seen like this.

    /*
     *  Sample code for using single byte transfer API function.  
     *  Checking ACK of each bytes because transfer should be aborted if no ACK.
     */
    char    data0[]  = { 0x80, 0x00, 0x05, 0x05 };

    i2c.start();
    if ( i2c.write( I2C_SLAVE_ADDR ) ) {
        for ( int i = 0; i < sizeof( data0 ); i++ ) {
            if ( !i2c.write( data0[ i ] ) )
                break;
        }
    }
    i2c.stop();

Accepted Answer
10 years ago.

frequency is in hertz, so you do 200000.

Start and stop can be used if you use single byte reads/writes (wouldn't advice you to do it though). But they are explained in i2c documentation. Same name for functions, different parameters.

Regarding the delay, I don't know if that has been implemented on the LPC1768 with a specific timeout. But it won't be waiting on an ACK, it is probably waiting on a line floating high, since otherwise the bus is busy (and some targets have timeouts for that, but i dont know if all got them). And I guess it randomly gets high again after 5-30 seconds. I guess your pull-ups also aren't available if your wire is disconnected? Options are either putting pull-ups at the mbed side, or what I think works, is enabling internal pull ups using pin_mode(p28, PullUp); (do that after the I2C is created, since it isn't supposed to be done). Now the pins should always go high when nothing is connected, and I expect it to not block, but instead just return a NACK.

Thanks Erik for the quick reply.

I did connected two pull-up resistors on SDA and SCL as was explained in i2c documentation.

But I didn't enabled internal pull ups using pin_mode(p28, PullUp) as you suggested.

So should I also do that too?

posted by Elianco S 21 Nov 2014

That would only help if those pull-up resistors are in the part of your setup which might get disconnected. If they aren't then it shouldn't ever stall anyway, unless your I2C device is doing something which it should not be doing.

posted by Erik - 21 Nov 2014