RobTillaart / MS5611

Arduino library for MS5611 temperature and pressure sensor
MIT License
17 stars 5 forks source link

NANO 33 BLE can not see device on I2C bus - isConnected() #31

Closed RobTillaart closed 2 years ago

RobTillaart commented 2 years ago

(this is a summary of an earlier discussion by e-mail, better to archive the essence here) The NANO 33 BLE is an processor using MBED toolchain.

Problem

The MS5611 cannot be seen on the I2C bus

This prevents to check if the device is connected in the device.begin() call during the setup of the project. Note that the device will work as it should if one ignores the return value of begin().

Analysis

The isConnected() call and I2C scanners just put addresses on the I2C bus and expect an ACK when a device recognizes its address. The MS5611 does this well on AVR and ESP but not on MBED.

Note that on the internet there were similar an related problems mentioned without a solution.

(many tests and mails later a possible cause is found in the endTransmission() code of MBED ....Arduino15\packages\arduino\hardware\mbed_nano\2.7.2\libraries\Wire\Wire.cpp

uint8_t arduino::MbedI2C::endTransmission(bool stopBit) {
  #ifndef TARGET_PORTENTA_H7
  if (usedTxBuffer == 0) {
    // we are scanning, return 0 if the addresed device responds with an ACK
    char buf[1];
    int ret = master->read(_address, buf, 1, !stopBit);
    return ret;
  }
  #endif
  if (master->write(_address, (const char *) txBuffer, usedTxBuffer, !stopBit) == 0) return 0;
  return 2;
}

If there are no bytes in the transmitBuffer the MBED returns the value of read() If there are bytes in the transmitBuffer the MBED returns the value of write()

Other endTransmission() implementations known - AVR / ESP - always use the write() even if the transmitBuffer is empty (usedTxBuffer == 0)

The rationale why MBED does this differently is unknown.

Patch / workaround

The library is patched so if an NANO 33 BLE is addressed it adds an write(0) in the isConnected() code (0.3.5)

https://github.com/RobTillaart/MS5611/blob/master/MS5611.cpp

bool MS5611::isConnected()
{
  _wire->beginTransmission(_address);
   #ifdef ARDUINO_ARCH_NRF52840
   //  needed for NANO 33 BLE
  _wire->write(0);                            // <<< extra byte forces code to select the write path in endTransmission()
   #endif
  return (_wire->endTransmission() == 0);
}

This forces the write path in endTransmission() and the device returns the ACK expected.

WARNING: Although this works it is not a solution as it is unknown how devices in general will react on this extra byte,

Thoughts about a solution

The patch above is a workaround that is not the right solution so more investigations / discussions are needed to solve this.

A generic solution could be that the Wire library is extended with a call, which returns if the address exist on the I2C bus.

ratio-x commented 2 years ago

Problem reported/discussed here:

https://forum.arduino.cc/t/nano-33-ble-i2c-problems-caused-in-mbed-wire-cpp-read-write-bit-on-i2c-scan/964676

RobTillaart commented 2 years ago

TODO

Fix the code patch when MBED endTransmission() is updated. If not patch will stay until better solution is available.

RobTillaart commented 2 years ago

@ratio-x I'm closing this issue as it can take a long/unknown time before it is fixed in MBED. The MS5611 library works with the patch so there are no actual problems anymore. When fixed in MBED, it needs to be verified before patch can be removed. (probably the patch becomes MBED version dependent first)

Feel free to post new insights (even if closed) or reopen if needed.