The official Mbed 2 C/C++ SDK provides the software platform and libraries to build your applications.

Dependents:   hello SerialTestv11 SerialTestv12 Sierpinski ... more

Issue: i2c unintended write (Closed: Fixed)

I guess that I have found the root cause for the problem described in
https://mbed.org/forum/bugs-suggestions/topic/4128/
In the mbed-NXP library
in file i2c_api.c
in function int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop)
line 309 i2c_clear_SI(obj); should be deleted.
The clearing of the interrupt bit triggers an unintended write of an additional byte.
Usually this does not hurt, because in most cases this write is aborted by the STOP condition in the next line or a RESTART condition of a following read request. But if the task running the i2c sequence is interrupted e.g. by the rtos scheduler (see link above) or by a simple wait as in the referenced example code, the i2c HW will write the unintended byte and mess up the following i2c request.
The example program simply reads from an SRF08 ultra sonic ranger one data byte by first writing the register address to the device and then reading back the requested data. If one adds a short wait (23µs) in between the write and the read, the read request fails: Program serial dump:
wStat=0x00 rStat=0x00 rData=0x0A OK!
wStat=0x00 rStat=0x28 rData=0xFF OUCH!
The first attempt without the 23µs break works fine. The second one with the short pause fails and reports status "0x28 Data byte in I2DAT has been transmitted; ACK has been received." The effect is also visible on the bus: /media/uploads/humlet/i2c_fail_anno.png
If the the clearing of the serial interrupt bit in line 309 of i2c_api.c is removed, everything works fine.

Example program

14 comments:

11 Jun 2013

You are my hero! I had this Problem since the beginning of developing my quadrocopter... When updating the sensor data via I2C while the remote control gives me a PPM-Signal (which I measure with short interrupts) I realized some collisions. If the repeated flag isn't set the mbed stalls when the first collision occures. When I set the repeated flag (last parameter of the I2C routines) the mbed doesn't stall anymore but there are some extreme values randomly spread when reading the sensors.

Could you give me a hint how I can compile my program with the line you mentioned fixed until the fix is generally released? Is it possible with the Online-Compiler? I just compiled my program with LPCXpresso v4.3.0_1023 to give it a try but there the mbed library also is just an object file so I can't change anything...

Thanks in advance, looking forward to a stable flying quadrocopter :)

11 Jun 2013

Thanks Helmut, this is a brilliant bug report. We will reproduce and fix this issue in the mbed library.

Cheers, Emilio

11 Jun 2013

Hi Matthias,

yes, it is possible to build your project with your own modified mbed library. First you have to remove the precompiled mbed lib from your project. Then import the mbed-NXP and mbed-src libraries, apply the fix and rebuild your project. This works fine with the online-compiler. You can use program referenced in the issue report as an example.

cheers, Helmut

12 Jun 2013

Thx for your advice, I took your example program, copied my code into it, commented the line you mentioned but it was still not the solution for my problem. It showed the normal sensor values and i didn't have this random peeks everywhere but some rare peeks that were much higher... (don't ask me why, sadly i have no logic analyser)

I decided to try the MODI2C, which works perfectly when I initialised the control registers of the sonsors with the orgininal mbed I2C-library before. So my solution/hack/workaround is now to use the original I2C (untouched) to initialise the individual control registers (write one at a time) and to use MODI2C for the usual data getting method (get all the 6 regs of data at a time).

for code see here (line 30) : http://mbed.org/users/maetugr/code/FlyBed1/file/128c55793728/Sensors/I2C_Sensor.cpp

thx for publishing all the info, that really helps to find a solution :)

19 Jun 2013

Hi Matthias,

I don't have yet a good setup in place to reproduce your issue, but looking at the code I've found this in i2c_api.c/i2c_send_stop:

inline void i2c_stop(i2c_t *obj) {
    // write the stop bit
    i2c_conset(obj, 0, 1, 0, 0);
    i2c_clear_SI(obj); // --------------------> comment this line
    
    // wait for STO bit to reset
    while(I2C_CONSET(obj) & (1 << 4));
}

I can still see an i2c_clear_SI call in this function. Could you please comment that line and see if anything changes?

20 Jun 2013

OK, my previos suggestion doesn't work, so you can disregard it completely. I wrote a small test that writes a predefined value at a fixed address in an I2C 24LC256 EEPROM and then reads this value and compares it with the written value in a loop (for 100000 times). The loop looks like this:

    data[0] = data[1] = 0;
    if((status = i2c.write(addr, data, 2, true)) != 0)
    {
      printf("Test %d failed at write, status is %02X\r\n", i, status);
      fw ++;
      continue;
    }
    // wait_us(30);
    if((status = i2c.read(addr, data, 1)) != 0)
    {
      printf("Test %d failed at read, status is %02X\r\n", i, status);
      fr ++;
      continue; 
    }
    if(data[0] != mark)
    {
      printf("Test %d failed at data match\r\n", i);
      fc ++;
    }

These are my findings:

  • no RTOS, using the standard mbed-NXP lib: no errors
  • with mbed-rtos added to the project. using the standard mbed-NXP lib: no errors
  • no RTOS, using the standard mbed-NXP lib and uncommenting the "wait_us" line above: lots of errors
  • no RTOS, using Helmut's fix and wait_us: no errors
  • RTOS, using Helmut's fix and wait_us: no errors

So Helmut's fix is obviousy right. That said, Matthias, I don't know why you're still getting errors. It seems that I can't reproduce this locally, not yet at least.

20 Jun 2013

Not sure if this will help or confuse matters but I had seen the same intermittent behavior (this was before the SDK source was available).

In my case, Tickers we're causing the problem during i2c transactions. Disabling global IRQ's during i2c read/write fixed this temporarily but is far from ideal.

Just a suggestion for your testing. I was using the LPC11U24, no RTOS. But I think your wait_us is a more reliable way of jamming this up.

21 Jun 2013

Hello Sam,

Thanks for your reply! A few questions below:

Sam Grove wrote:

Not sure if this will help or confuse matters but I had seen the same intermittent behavior (this was before the SDK source was available).

In my case, Tickers we're causing the problem during i2c transactions. Disabling global IRQ's during i2c read/write fixed this temporarily but is far from ideal.

Just a suggestion for your testing. I was using the LPC11U24, no RTOS. But I think your wait_us is a more reliable way of jamming this up.

  • When you were using tickers, was there some other part of you code that called I2C functions?
  • If you still have that code, would it be possible to apply Helmut's patch (and comment out the code that disables/enables global interrupts) and check if you still have this problem? That would be very helpful.

Thanks, Bogdan

21 Jun 2013

Bogdan Marinescu wrote:

When you were using tickers, was there some other part of you code that called I2C functions?

Yes - The Tickers just run state machines for diagnostic LED's and other state of health type of tasks (counters, events and such). The I2C calls were made from the main loop (or a few calls from it)

Bogdan Marinescu wrote:

If you still have that code, would it be possible to apply Helmut's patch (and comment out the code that disables/enables global interrupts) and check if you still have this problem? That would be very helpful.

Let me try and dig up some hardware. I'll get back to you by the end of the day either way.

22 Jun 2013

@ Bogdan Marinescu

I didn't have any luck finding hardware today (this is on a production PCB now using the LPC11U37 - 32k wasn't enough memory). I'll try to see if there is a failure PCB that can be resurrected next week.

25 Jun 2013

Thanks a lot for your help. I hope you find some hardware that you can test this on.

26 Jun 2013

Bogdan Marinescu wrote:

Thanks a lot for your help. I hope you find some hardware that you can test this on.

I was able modify hardware and get some further testing done. In my case the original symptom was intermittent but I was able to force a failure by adding wait_us(50);

void CAT5132::readWiperPosition( int8_t &position )
{
    // prepare the access control register
    writeACR();
    wait_us(50); // <- causes a failure at some point... not the first pass though
    position = read();
    return;
}

I had also gone back to creating transactions with using the start(), write(), start(), read(), stop() api methods which don't call int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) in ./hal/i2c_api.c and don't seem to have the same problem.

Anyways, commenting out line #261 i2c_clear_SI(obj); in /vendor/NXP/LPC11U24/hal/i2c_api.c does appear to be a fix. Here are a few pictures from my logic analyzer (in my project the failure appears to sit in an infinite loop at inline void i2c_stop(i2c_t *obj) only allowing IRQ context functions to run).

mbed-src revision 10 (Code Failing): /media/uploads/sam_grove/i2c_fail_pic.jpg

The hardware i'm working with doesn't have good debug hooks so getting more information (ie: register values) will be painful. I ran this through 500k+ transactions with Helmut's patch and no failures thus far.

27 Jun 2013

Looking at Matthias' response, am I correct that MODI2C doesn't suffer from the issue? (Otherwise I have to fix it :P)

18 Apr 2014

The reason the byte is rewritten to i2c bus is that in case of a repeated start the START flag should be set before SI flag is cleared. MBED libray did it the other way around. Deleting the i2c_clear_SI(obj); is not a proper fix.