diff --git a/README.md b/README.md index 479cee8..885361e 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,33 @@ [![Clang Format](https://github.com/m5stack/M5Module-GNSS/actions/workflows/clang-format-check.yml/badge.svg)](https://github.com/m5stack/M5Module-GNSS/actions/workflows/clang-format-check.yml) +## BMI270 I2C access (Arduino core 3.2+ / ESP-IDF 5.4+) + +`BMI270` now talks I2C through the Arduino `TwoWire` (`Wire`) API instead of calling the +ESP-IDF legacy `driver/i2c.h` functions directly. Since Arduino core 3.2.0, `Wire` is built on +the new `i2c_master` driver (`driver_ng`), and linking the legacy driver into the same firmware +aborts at startup with: + +``` +E (1057) i2c: CONFLICT! driver_ng is not allowed to be used with this old driver +abort() was called at PC 0x4204ef83 on core 0 +``` + +Since `BMI270` no longer references the legacy driver, this conflict can no longer occur. Arduino +core 2.x and 3.0/3.1 keep working as before. + +`BMI270::init()` now takes a `TwoWire&`: + +```cpp +Wire.begin(21, 22, 100000); // the library does not call Wire.begin() itself +bmi270.init(Wire, BIM270_SENSOR_ADDR); +``` + +The old `init(i2c_port_t, uint8_t)` signature is kept for source compatibility +(`I2C_NUM_0` maps to `Wire`, `I2C_NUM_1` maps to `Wire1` on chips with a second I2C controller +such as ESP32 / ESP32-S3) but is deprecated — prefer the `TwoWire&` overload in new code. + + ## License - [M5Module-GNSS - MIT](LICENSE) diff --git a/examples/getSensorData/getSensorData.ino b/examples/getSensorData/getSensorData.ino index 93c9e44..3ff4cd2 100644 --- a/examples/getSensorData/getSensorData.ino +++ b/examples/getSensorData/getSensorData.ino @@ -40,7 +40,7 @@ void setup() { while (1) delay(10); } - bmi270.init(I2C_NUM_0, BIM270_SENSOR_ADDR); + bmi270.init(Wire, BIM270_SENSOR_ADDR); } void loop() { diff --git a/library.json b/library.json index 28c8a99..6275bfe 100644 --- a/library.json +++ b/library.json @@ -10,7 +10,7 @@ "type": "git", "url": "https://github.com/m5stack/M5Module-GNSS.git" }, - "version": "1.0.1", + "version": "1.0.3", "frameworks": "arduino", "platforms": "espressif32", "headers": "M5Module_GNSS.h" diff --git a/library.properties b/library.properties index 78fafce..6747fb1 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=M5Module-GNSS -version=1.0.1 +version=1.0.3 author=M5Stack maintainer=M5Stack sentence=Library for M5Stack GNSS Module diff --git a/src/BMI270.cpp b/src/BMI270.cpp index 529a885..f06abbf 100644 --- a/src/BMI270.cpp +++ b/src/BMI270.cpp @@ -48,11 +48,39 @@ static bmi2_dev* _bmi2_dev_ptr = nullptr; +// arduino-esp32 declares Wire1 on every 2.x target, but on 3.x only where it exists (the condition +// differs per 3.x release); a second HP I2C controller implies Wire1 in every release. +#if ESP_IDF_VERSION_MAJOR < 5 +#define BMI270_HAS_WIRE1 1 +#elif defined(SOC_HP_I2C_NUM) +#define BMI270_HAS_WIRE1 (SOC_HP_I2C_NUM > 1) +#else +#define BMI270_HAS_WIRE1 (SOC_I2C_NUM > 1) +#endif + + namespace BMI270 { int BMI270::init(i2c_port_t i2c_port, uint8_t bmiAddr) { - _i2c_port = i2c_port; +#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_WIRE) + if (i2c_port == 0) { + return init(Wire, bmiAddr); + } +#if BMI270_HAS_WIRE1 + if (i2c_port == 1) { + return init(Wire1, bmiAddr); + } +#endif +#endif + ESP_LOGE(TAG, "No global TwoWire for I2C port %d (addr 0x%02X), use init(TwoWire&, uint8_t)", (int)i2c_port, bmiAddr); + return false; + } + + + int BMI270::init(TwoWire& wire, uint8_t bmiAddr) + { + _wire = &wire; /* BMI270 init */ @@ -67,7 +95,7 @@ namespace BMI270 { bmi2.read_write_len = 30; // Limitation of the Wire library bmi2.config_file_ptr = NULL; // Use the default BMI270 config file - accel_gyro_dev_info.i2c_port = _i2c_port; + accel_gyro_dev_info.wire = _wire; accel_gyro_dev_info.dev_addr = bmi2.chip_id; int8_t rslt = bmi270_init(&bmi2); @@ -143,7 +171,7 @@ namespace BMI270 { bmm1.intf = BMM150_I2C_INTF; bmm1.intf_ptr = &mag_dev_info; - mag_dev_info.i2c_port = _i2c_port; + mag_dev_info.wire = _wire; mag_dev_info.dev_addr = bmm1.chip_id; @@ -629,26 +657,34 @@ namespace BMI270 { - /* I2C W/R buffer */ - static uint8_t _data_buffer[32]; - static esp_err_t _i2c_ret; - struct dev_info* _dev_info; - - + /* I2C register R/W, 32 bytes max per transaction (bmi2.read_write_len above) */ int8_t BMI270::bmi2_i2c_read(uint8_t reg_addr, uint8_t *reg_data, uint32_t len, void *intf_ptr) { if ((reg_data == NULL) || (len == 0) || (len > 32)) { return -1; } - _dev_info = (struct dev_info*)intf_ptr; + struct dev_info* dev_info = (struct dev_info*)intf_ptr; + TwoWire* wire = dev_info->wire; + + wire->beginTransmission(dev_info->dev_addr); + wire->write(reg_addr); + uint8_t tx_ret = wire->endTransmission(false); // repeated start, no stop before the read + if (tx_ret != 0) { + ESP_LOGE(TAG, "A:%02X R %02X endTransmission:%d", dev_info->dev_addr, reg_addr, tx_ret); + return -1; + } - _i2c_ret = i2c_master_write_read_device(_dev_info->i2c_port, _dev_info->dev_addr, ®_addr, 1, reg_data, len, portMAX_DELAY); - if (_i2c_ret != ESP_OK) { - ESP_LOGE(TAG, "P:%d R %02X %02X E:%d", _dev_info->i2c_port, _dev_info->dev_addr, reg_addr, _i2c_ret); + size_t received = wire->requestFrom((uint8_t)dev_info->dev_addr, (uint8_t)len); + if (received != len) { + ESP_LOGE(TAG, "A:%02X R %02X requestFrom got:%u want:%lu", dev_info->dev_addr, reg_addr, (unsigned)received, (unsigned long)len); return -1; } + for (uint32_t i = 0; i < len; i++) { + reg_data[i] = (uint8_t)wire->read(); + } + return 0; } @@ -659,16 +695,15 @@ namespace BMI270 { return -1; } - _dev_info = (struct dev_info *)intf_ptr; - - _data_buffer[0] = reg_addr; - for (int i = 0; i < len; i++) { - _data_buffer[i + 1] = reg_data[i]; - } + struct dev_info* dev_info = (struct dev_info*)intf_ptr; + TwoWire* wire = dev_info->wire; - _i2c_ret = i2c_master_write_to_device(_dev_info->i2c_port, _dev_info->dev_addr, _data_buffer, (len + 1), portMAX_DELAY); - if (_i2c_ret != ESP_OK) { - ESP_LOGE(TAG, "P:%d W %02X %02X E:%d", _dev_info->i2c_port, _dev_info->dev_addr, reg_addr, _i2c_ret); + wire->beginTransmission(dev_info->dev_addr); + wire->write(reg_addr); + wire->write(reg_data, len); + uint8_t tx_ret = wire->endTransmission(true); + if (tx_ret != 0) { + ESP_LOGE(TAG, "A:%02X W %02X endTransmission:%d", dev_info->dev_addr, reg_addr, tx_ret); return -1; } diff --git a/src/BMI270.h b/src/BMI270.h index a1b49b0..1191276 100644 --- a/src/BMI270.h +++ b/src/BMI270.h @@ -28,7 +28,15 @@ */ #include "utilities/BMI270-Sensor-API/bmi270.h" #include "utilities/BMM150-Sensor-API/bmm150.h" -#include +#include +#include +// i2c_port_t / I2C_NUM_x for the deprecated init(i2c_port_t, ...) overload only. Nothing from the +// legacy I2C driver is called, so its i2c.c object (and the driver_ng conflict check) is not linked. +#if ESP_IDF_VERSION_MAJOR >= 5 +#include +#else +#include // IDF 4.x defines I2C_NUM_x here; it has no driver_ng to conflict with +#endif #include #include @@ -36,14 +44,14 @@ namespace BMI270 { struct dev_info { - i2c_port_t i2c_port = I2C_NUM_0; + TwoWire* wire = nullptr; uint8_t dev_addr; }; class BMI270 { private: - i2c_port_t _i2c_port; + TwoWire* _wire = nullptr; bool _initialized = false; int _interrupts = 0; @@ -81,6 +89,10 @@ namespace BMI270 { void setContinuousMode(); void oneShotMode(); + int init(TwoWire& wire, uint8_t bmiAddr); + + // Deprecated, kept for source compatibility: I2C_NUM_0 -> Wire, I2C_NUM_1 -> Wire1 + // (Wire1 only on chips with two HP I2C controllers). Prefer init(TwoWire&, uint8_t). int init(i2c_port_t i2c_port, uint8_t bmiAddr);