Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion examples/getSensorData/getSensorData.ino
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
2 changes: 1 addition & 1 deletion library.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
@@ -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
Expand Down
79 changes: 57 additions & 22 deletions src/BMI270.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -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);
Expand Down Expand Up @@ -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;


Expand Down Expand Up @@ -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, &reg_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;
}

Expand All @@ -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;
}

Expand Down
18 changes: 15 additions & 3 deletions src/BMI270.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,22 +28,30 @@
*/
#include "utilities/BMI270-Sensor-API/bmi270.h"
#include "utilities/BMM150-Sensor-API/bmm150.h"
#include <driver/i2c.h>
#include <Wire.h>
#include <esp_idf_version.h>
// 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 <hal/i2c_types.h>
#else
#include <driver/i2c.h> // IDF 4.x defines I2C_NUM_x here; it has no driver_ng to conflict with
#endif
#include <iostream>
#include <string>


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;
Expand Down Expand Up @@ -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);


Expand Down
Loading