Error in reading sensor I2c bus 1, pixhawk 4 mini

Hi,

I’m trying to read a pressure sensor on a pixhawk 4 mini I2c bus on GPS port.

It works nicely on UART&I2CB (i2c bus 2) starting the driver with “ms5611 start -T 5837”, but I cannot make it work on the GPS I2C bus (i2c bus 1).
In both cases, the sensor is properly detected when I run i2cdetect, here is the output:

  • on i2c bus 1

Scanning I2C bus: 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: – -- – -- – -- – -- – -- – -- – -- – --
10: – -- – -- – -- – -- – -- – -- – -- – --
20: – -- – -- – -- – -- – -- – -- – -- – --
30: – -- – -- – -- – -- – -- – -- – -- – --
40: – -- – -- – -- – -- – -- – -- – -- – --
50: – -- – -- – -- – -- – -- – -- – -- – --
60: – -- – -- – -- – -- – -- – -- – -- – --
70: – -- – -- – -- 76 – -- – -- – -- – -- –

  • on i2c bus 2

Scanning I2C bus: 2
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: – -- – -- – -- – -- – -- – -- – -- – --
10: – -- – -- – -- – -- – -- – -- – -- – --
20: – -- – -- – -- – -- – -- – -- – -- – --
30: – -- – -- – -- – -- – -- – -- – -- – --
40: – -- – -- – -- – -- – -- – -- – -- – --
50: – -- – -- – -- – -- – -- – -- – -- – --
60: – -- – -- – -- – -- – -- – -- – -- – --
70: – -- – -- – -- 76 – -- – -- – -- – -- –

Digging into the code with a debugger, I added a couple of printfs in the driver to check what happens:

  • file: ms5611.cpp

int
MS5611::measure()
{
int ret;

perf_begin(_measure_perf);

/*
 * In phase zero, request temperature; in other phases, request pressure.
 */
unsigned addr = (_measure_phase == 0) ? ADDR_CMD_CONVERT_D2 : ADDR_CMD_CONVERT_D1;
/*
 * Send the command to begin measuring.
 */

ret = _interface->ioctl(IOCTL_MEASURE, addr);
printf("ret:  %d \n", ret);
if (OK != ret) {
	perf_count(_comms_errors);
}

perf_end(_measure_perf);

return ret;

}

this function returns -125, instead of the OK code,

It comes from this function

  • file: ms5611_i2c.cpp

MS5611_I2C::ioctl(unsigned operation, unsigned &arg)
{
int ret;

switch (operation) {
case IOCTL_RESET:
	ret = _reset();
	printf("reset\n");
	break;

case IOCTL_MEASURE:
	ret = _measure(arg);;//<——HERE
	printf("ret ioctl:  %d \n", ret);
	break;

default:
	ret = EINVAL;
}

return ret;

}

  • then from this function (same file):

int
MS5611_I2C::_measure(unsigned addr)
{
/*
* Disable retries on this command; we can’t know whether failure
* means the device did or did not see the command.
*/
_retries = 0;

uint8_t cmd = addr;
return transfer(&cmd, 1, nullptr, 0);

}

  • then from transfer:

int I2C::transfer(const uint8_t *send, const unsigned send_len, uint8_t *recv, const unsigned recv_len)
{
px4_i2c_msg_t msgv[2];
unsigned msgs;
int ret = PX4_ERROR;
unsigned retry_count = 0;

if (_dev == nullptr) {
	PX4_ERR("I2C device not opened");
	return 1;
}

do {
	if (get_device_address() != 14)
	{
		/* code */
		printf("transfer out %p/%u  in %p/%u\n", send, send_len, recv, recv_len);
	}
	
	msgs = 0;
	//printf("transfer command %p \n",send);
	if (send_len > 0) {
		//printf("device clock %f \n",_bus_clocks[get_device_bus() - 1]);
		msgv[msgs].frequency = _bus_clocks[get_device_bus() - 1];
		msgv[msgs].addr = get_device_address();
		msgv[msgs].flags = 0;
		msgv[msgs].buffer = const_cast<uint8_t *>(send);
		msgv[msgs].length = send_len;
		msgs++;
	}

	if (recv_len > 0) {
		msgv[msgs].frequency = _bus_clocks[get_device_bus() - 1];
		msgv[msgs].addr = get_device_address();
		msgv[msgs].flags = I2C_M_READ;
		msgv[msgs].buffer = recv;
		msgv[msgs].length = recv_len;
		msgs++;
	}
	//printf("transfer command %d \n",get_device_address());

	if (msgs == 0) {
		return -EINVAL;
		printf("transfer error-------\n");
	}

	ret = I2C_TRANSFER(_dev, &msgv[0], msgs);

	/* success */
	if (ret == PX4_OK) {
		break;
	}

	/* if we have already retried once, or we are going to give up, then reset the bus */
	if ((retry_count >= 1) || (retry_count >= _retries)) {
		I2C_RESET(_dev);
	}

} while (retry_count++ < _retries);

return ret;

}

In both cases (bus i2c 1 and bus i2c 2), we send the same message:
transfer out 0x20030377/1 in 0/0
but in one case we get the error code, and in one case it works.

It seems that it comes from the ret = I2C_TRANSFER(_dev, &msgv[0], msgs);

Any idea on what could happen?

Thanks for the help!

Here are some traces of what happens on SDL and SCL when running the driver on both i2c buses:

  • i2c 1 (not working), with unzoom, and zoom on the first byte

  • i2c 2 (working), with unzoom, zoom on the first byte, and zoom on the data that comes

!

Found what the issue was:

In fact the first thing the buses do when probing is to read the PROM, it reads until 0xAE


But we read 8 values and there are only 6 to read


The bus 1 crashes when we try to read 0xAE, we never get a response

What I don’t understand though, is why it crashes on bus 1 and not bus 2, but reading only seven values solves the issues.