Skip to content

Constructing an I2C causes the next I2C operation to fail. #14004

@multiplemonomials

Description

@multiplemonomials

Description of defect

I have been upgrading some Mbed 2 code to Mbed OS 6, and have run into some issues with I2C drivers. Specifically, if multiple
I2C objects were created representing the same physical bus, then transactions would sometimes fail. I've attached an example program that demonstrates the issue.

I'm not entirely sure what's causing it, but it seems to be related to a bad interaction between the recover() function and the LPC1768's I2C peripheral. If I comment out the call to recover() in the I2C constructor, everything seems to work normally. And when I checked with the debugger, the failing I2C transaction seems to occur because the HAL i2c_start() function is reading a bad status value from chip registers. I'm not exactly an expert on LPC1768 I2C though so I'm not exactly sure how recover() is causing this problem.

Target(s) affected by this defect ?

LPC1768

Toolchain(s) (name and version) displaying this defect ?

GCC_ARM

What version of Mbed-os are you using (tag or sha) ?

mbed-os-6.5.0

What version(s) of tools are you using. List all that apply (E.g. mbed-cli)

mbed-cmake v1.4.2, but it should behave identically to mbed-cli.

How is this defect reproduced ?

I made a simple program that demonstrates the issue. All you need is to connect an LPC1768 to any valid I2C peripheral. Then fill in the correct pins and address for the peripheral in the #defines.

//
// Demonstration of Mbed 6 I2C bug
//

#include <mbed.h>

#define I2C_PART_ADDR 0xA0 // 8 bit address
#define SDA P0_27
#define SCL P0_28

int main()
{
	I2C i2c1(SDA, SCL);

	int retval1 = i2c1.write(I2C_PART_ADDR, nullptr, 0);

	printf("Retval of first write with i2c1: %d\n", retval1);

	I2C i2c2(SDA, SCL);

	retval1 = i2c1.write(I2C_PART_ADDR, nullptr, 0);
	int retval2 = i2c2.write(I2C_PART_ADDR, nullptr, 0);

	printf("Retval of second write with i2c1: %d\n", retval1);
	printf("Retval of second write with i2c2: %d\n", retval2);

	retval1 = i2c1.write(I2C_PART_ADDR, nullptr, 0);
	retval2 = i2c2.write(I2C_PART_ADDR, nullptr, 0);

	printf("Retval of third write with i2c1: %d\n", retval1);
	printf("Retval of third write with i2c2: %d\n", retval2);

	while(true) {}

	return 0;
}

On my LPC1768, this outputs:

Retval of first write with i2c1: 0
Retval of second write with i2c1: 1
Retval of second write with i2c2: 0
Retval of third write with i2c1: 0
Retval of third write with i2c2: 0

Clearly, constructing a second I2C should not cause a write that previously succeeded to fail, so it's a bug that the second line has a 1 retval.

If I comment out this line and rerun the test, all I2C writes succeed.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions