ShellAddicted / BNO055ESP32

C++ Interface for the Bosch-Sensortec's BNO055 compatible with Espressif's ESP32 SoC running esp-idf.
MIT License
24 stars 9 forks source link

interrupt example not working #10

Closed josephpal closed 3 years ago

josephpal commented 3 years ago

Hi,

currently I try to get your example of enabling interrupts working. I am wondering about to correct wiring. To which pin of the ESP32 do i have to route the INT pin of the BNO055, because if i define e.g. GPIO_NUM_16, your example seems not working.

    /* setup I²C */
    i2c_config_t conf;
    conf.mode = I2C_MODE_MASTER;
    conf.sda_io_num = GPIO_NUM_21;
    conf.scl_io_num = GPIO_NUM_22;
    conf.sda_pullup_en = GPIO_PULLUP_DISABLE;
    conf.scl_pullup_en = GPIO_PULLUP_DISABLE;
    conf.master.clk_speed = 1000000;
    i2c_param_config(I2C_NUM_0, &conf);
    i2c_driver_install(I2C_NUM_0, I2C_MODE_MASTER, 0, 0, 0);
    i2c_set_timeout(I2C_NUM_0, 56000);

    /* BNO055 I2C Addr can be 0x28 or 0x29 (depends on your hardware) */
    ESP_LOGD(TAG, "start BNO055 I2C init");  // DEBUG
    bno = new BNO055((i2c_port_t) I2C_NUM_0, 0x29, GPIO_NUM_MAX, GPIO_NUM_16);

        ....

    /* setup sensor */
    try {
        /* BNO055 is in CONFIG_MODE until it is changed */
        bno->begin();
        bno->enableExternalCrystal();

        bno->setPwrModeNormal();
        bno->setAccelAnyMotionInterrupt(2, 2, true, true, true);  // configure the interrupt, see datasheet for more details.
        bno->setAccelNoMotionInterrupt(0, 0, true, true, true);
        bno->enableAccelAnyMotionInterrupt(true);  // you can disable it with disableAccelAnyMotionInterrupt();
        bno->enableAccelNoMotionInterrupt(true);
        bno->setOprModeNdof();

        ESP_LOGI(TAG, "Setup Done.");
    } catch (BNO055BaseException &ex) {
        ESP_LOGE(TAG, "Setup Failed, Error: %s", ex.what());
        return;
    } catch (std::exception &ex) {
        ESP_LOGE(TAG, "Setup Failed, Error: %s", ex.what());
        return;
    }

    int16_t sw = bno->getSWRevision();
    uint8_t bl_rev = bno->getBootloaderRevision();
    ESP_LOGI(TAG, "SW rev: %d, bootloader rev: %u", sw, bl_rev);

        ....

I am using the BNO055 Shuttle Board and my connection is the following:

/*
 * PS1 -> GND (LOW) -> Enables I²C protocol
 * SCL -> SCL (Default: GPIO_NUM_22)
 * SDA -> SDA (Default: GPIO_NUM_21)
 * INT  -> GPIO_NUM_16
*/
ShellAddicted commented 3 years ago

Hi, I've just tested the code and I can't replicate your problem, everything works as expcted. I've used BNO055 bno((i2c_port_t)I2C_NUM_0, 0x28, GPIO_NUM_MAX, GPIO_NUM_16); Anyway I suggest to use a less valuable pin like GPIO_NUM_35 for interrupts.

I (3174) BNO055ESP32Example: Self-Test Results: MCU: 1, GYR:1, MAG:1, ACC: 1
I (3184) BNO055ESP32Example: Euler: X: 0.0 Y: 0.0 Z: 0.0 || Calibration SYS: 0 GYRO: 0 ACC:0 MAG:0
I (3294) BNO055ESP32Example: Euler: X: 0.0 Y: 0.8 Z: -0.8 || Calibration SYS: 0 GYRO: 0 ACC:0 MAG:0
I (3394) BNO055ESP32Example: Euler: X: 0.1 Y: 0.8 Z: -0.8 || Calibration SYS: 0 GYRO: 0 ACC:0 MAG:0
<*Shaked the BNO0555*>
I (3494) BNO055ESP32Example: AccelAnyMotion Interrupt received.
I (3494) BNO055ESP32Example: Euler: X: 1.4 Y: 0.7 Z: -0.7 || Calibration SYS: 0 GYRO: 0 ACC:0 MAG:0
I (3594) BNO055ESP32Example: Euler: X: 6.1 Y: 0.6 Z: -0.4 || Calibration SYS: 0 GYRO: 0 ACC:0 MAG:0
I (3694) BNO055ESP32Example: Euler: X: 3.8 Y: 0.5 Z: -0.9 || Calibration SYS: 0 GYRO: 0 ACC:0 MAG:0
I (3794) BNO055ESP32Example: AccelAnyMotion Interrupt received.
I (3794) BNO055ESP32Example: Euler: X: 5.2 Y: 0.6 Z: -0.7 || Calibration SYS: 0 GYRO: 0 ACC:0 MAG:0
I (3894) BNO055ESP32Example: Euler: X: 5.1 Y: 0.8 Z: -3.1 || Calibration SYS: 0 GYRO: 0 ACC:0 MAG:0
I (3994) BNO055ESP32Example: Euler: X: 5.6 Y: 0.6 Z: -0.9 || Calibration SYS: 0 GYRO: 0 ACC:0 MAG:0
I (4094) BNO055ESP32Example: AccelAnyMotion Interrupt received.
I (4094) BNO055ESP32Example: Euler: X: 3.9 Y: 0.9 Z: -1.1 || Calibration SYS: 0 GYRO: 0 ACC:0 MAG:0
I (4194) BNO055ESP32Example: Euler: X: 3.9 Y: 0.9 Z: -1.1 || Calibration SYS: 0 GYRO: 0 ACC:0 MAG:0
I (4294) BNO055ESP32Example: Euler: X: 3.9 Y: 0.9 Z: -1.1 || Calibration SYS: 0 GYRO: 0 ACC:0 MAG:0
<*Stopped shaking*>
<.........>
I (8294) BNO055ESP32Example: accelNoSlowMotion Interrupt received.
I (8294) BNO055ESP32Example: Euler: X: 3.9 Y: 0.9 Z: -1.1 || Calibration SYS: 0 GYRO: 3 ACC:0 MAG:0
I (8394) BNO055ESP32Example: Euler: X: 3.9 Y: 0.9 Z: -1.1 || Calibration SYS: 0 GYRO: 3 ACC:0 MAG:0
I (8494) BNO055ESP32Example: Euler: X: 3.9 Y: 0.9 Z: -1.1 || Calibration SYS: 0 GYRO: 3 ACC:0 MAG:0

please provide more details.

josephpal commented 3 years ago

Thanks for your quick response. It looks like i had some issues with my wiring, now your example is working. Here is my full code:

#include "Arduino.h"
#include "libs/BNO055ESP32/src/BNO055ESP32.h"

void setup() {
    // Setup I²C
    i2c_config_t conf;
    conf.mode = I2C_MODE_MASTER;
    conf.sda_io_num = GPIO_NUM_21;
    conf.scl_io_num = GPIO_NUM_22;
    conf.sda_pullup_en = GPIO_PULLUP_DISABLE;
    conf.scl_pullup_en = GPIO_PULLUP_DISABLE;
    conf.master.clk_speed = 1000000;
    i2c_param_config(I2C_NUM_0, &conf);
    i2c_driver_install(I2C_NUM_0, I2C_MODE_MASTER, 0, 0, 0);
    i2c_set_timeout(I2C_NUM_0, 65000);

    //to use i²C leave the following line active
    BNO055 bno((i2c_port_t) I2C_NUM_0, 0x29, GPIO_NUM_25, GPIO_NUM_5);

    try {
        bno.begin();  // BNO055 is in CONFIG_MODE until it is changed
        bno.enableExternalCrystal();
        // bno.setSensorOffsets(storedOffsets);
        // bno.setAxisRemap(BNO055_REMAP_CONFIG_P1, BNO055_REMAP_SIGN_P1); // see datasheet, section 3.4
        /* you can specify a PoWeRMode using:
         - setPwrModeNormal(); (Default on startup)
         - setPwrModeLowPower();
         - setPwrModeSuspend(); (while suspended bno055 must remain in CONFIG_MODE)
         */
        bno.setAccelAnyMotionInterrupt(2, 2, true, true, true); // configure the interrupt, see datasheet for more details.
        bno.setAccelNoMotionInterrupt(0, 0, true, true, true);
        bno.enableAccelAnyMotionInterrupt(true); // you can disable it with disableAccelAnyMotionInterrupt();
        bno.enableAccelNoMotionInterrupt(true);
        bno.setOprModeNdof();
        ESP_LOGI(TAG, "Setup Done.");
    } catch (BNO055BaseException &ex) { // see BNO055ESP32.h for more details about exceptions
        ESP_LOGE(TAG, "Setup Failed, Error: %s", ex.what());
        return;
    } catch (std::exception &ex) {
        ESP_LOGE(TAG, "Setup Failed, Error: %s", ex.what());
        return;
    }

    try {
        int8_t temperature = bno.getTemp();
        ESP_LOGI(TAG, "TEMP: %d°C", temperature);

        int16_t sw = bno.getSWRevision();
        uint8_t bl_rev = bno.getBootloaderRevision();
        ESP_LOGI(TAG, "SW rev: %d, bootloader rev: %u", sw, bl_rev);

        bno055_self_test_result_t res = bno.getSelfTestResult();
        ESP_LOGI(TAG, "Self-Test Results: MCU: %u, GYR:%u, MAG:%u, ACC: %u",
                res.mcuState, res.gyrState, res.magState, res.accState);
    } catch (BNO055BaseException &ex) { // see BNO055ESP32.h for more details about exceptions
        ESP_LOGE(TAG, "Something bad happened: %s", ex.what());
        return;
    } catch (std::exception &ex) {
        ESP_LOGE(TAG, "Something bad happened: %s", ex.what());
        return;
    }

    while (1) {
        try {
            if (bno.interruptFlag == true) {
                // See bno055_interrupts_status_t for more details.
                bno055_interrupts_status_t ist = bno.getInterruptsStatus();
                // remember that multiple interrupts can be triggered at the same time. so you shouldn't use 'else if'
                if (ist.accelAnyMotion == 1) {
                    ESP_LOGI(TAG, "AccelAnyMotion Interrupt received.");
                }
                if (ist.accelNoSlowMotion == 1) {
                    ESP_LOGI(TAG, "accelNoSlowMotion Interrupt received.");
                }
                bno.clearInterruptPin();  // don't forget to place this.
            }
            // Calibration 3 = fully calibrated, 0 = not calibrated
            bno055_calibration_t cal = bno.getCalibration();
            bno055_vector_t v = bno.getVectorEuler();
            ESP_LOGI(TAG,
                    "Euler: X: %.1f Y: %.1f Z: %.1f || Calibration SYS: %u GYRO: %u ACC:%u MAG:%u",
                    v.x, v.y, v.z, cal.sys, cal.gyro, cal.accel, cal.mag);
        } catch (BNO055BaseException &ex) {
            ESP_LOGE(TAG, "Something bad happened: %s", ex.what());
            return;
        } catch (std::exception &ex) {
            ESP_LOGE(TAG, "Something bad happened: %s", ex.what());
        }
        vTaskDelay(100 / portTICK_PERIOD_MS); // in fusion mode max output rate is 100hz (actual rate: 100ms (10hz))
    }
}

void loop() {

}

The console output is also similar to the one you have posted. The only problem i have right now is that after some time it looks like the I2C communication isn't working anymore, and this problem occurs repeatedly.

[I][esp32_BNO055ESP32_Interrupts.ino:35] setup(): Setup Done.
[I][esp32_BNO055ESP32_Interrupts.ino:46] setup(): TEMP: 24°C
[I][esp32_BNO055ESP32_Interrupts.ino:50] setup(): SW rev: 800, bootloader rev: 21
[I][esp32_BNO055ESP32_Interrupts.ino:54] setup(): Self-Test Results: MCU: 1, GYR:1, MAG:1, ACC: 1
...
[I][esp32_BNO055ESP32_Interrupts.ino:73] setup(): accelNoSlowMotion Interrupt received.
[I][esp32_BNO055ESP32_Interrupts.ino:82] setup(): Euler: X: 359.9 Y: 0.0 Z: 4.3 || Calibration SYS: 0 GYRO: 3 ACC:0 MAG:0
[I][esp32_BNO055ESP32_Interrupts.ino:70] setup(): AccelAnyMotion Interrupt received.
[I][esp32_BNO055ESP32_Interrupts.ino:82] setup(): Euler: X: 359.7 Y: 0.0 Z: 4.3 || Calibration SYS: 0 GYRO: 3 ACC:0 MAG:0
[I][esp32_BNO055ESP32_Interrupts.ino:82] setup(): Euler: X: 359.8 Y: -0.1 Z: 4.3 || Calibration SYS: 0 GYRO: 3 ACC:0 MAG:0
[I][esp32_BNO055ESP32_Interrupts.ino:82] setup(): Euler: X: 0.1 Y: -0.2 Z: 4.7 || Calibration SYS: 0 GYRO: 3 ACC:0 MAG:0
[I][esp32_BNO055ESP32_Interrupts.ino:82] setup(): Euler: X: 359.9 Y: -0.6 Z: 5.7 || Calibration SYS: 0 GYRO: 3 ACC:0 MAG:0
[I][esp32_BNO055ESP32_Interrupts.ino:70] setup(): AccelAnyMotion Interrupt received.
[I][esp32_BNO055ESP32_Interrupts.ino:82] setup(): Euler: X: 0.3 Y: -2.5 Z: 4.3 || Calibration SYS: 0 GYRO: 3 ACC:0 MAG:0
[I][esp32_BNO055ESP32_Interrupts.ino:82] setup(): Euler: X: 0.2 Y: -4.7 Z: 4.1 || Calibration SYS: 0 GYRO: 3 ACC:0 MAG:0
[I][esp32_BNO055ESP32_Interrupts.ino:82] setup(): Euler: X: 0.2 Y: -6.6 Z: 3.5 || Calibration SYS: 0 GYRO: 3 ACC:0 MAG:0
[I][esp32_BNO055ESP32_Interrupts.ino:82] setup(): Euler: X: 0.5 Y: -7.2 Z: 2.0 || Calibration SYS: 0 GYRO: 3 ACC:0 MAG:0
[I][esp32_BNO055ESP32_Interrupts.ino:82] setup(): Euler: X: 1.1 Y: -7.6 Z: 1.1 || Calibration SYS: 0 GYRO: 3 ACC:0 MAG:0
...
[I][esp32_BNO055ESP32_Interrupts.ino:82] setup(): Euler: X: 3.9 Y: 0.0 Z: 4.2 || Calibration SYS: 0 GYRO: 3 ACC:0 MAG:0
E (3347527) BNO055: (i2c RL) Error: -1
[E][esp32_BNO055ESP32_Interrupts.ino:84] setup(): Something bad happened: I2CError: Check your wiring.
E (3347539) BNO055: (i2c WL) Error: -1

My current setup consists of an ESP32 (ESP-WROOM-32), a BNO055 Shuttle Board (HF 1717) and I am using your library in combination with the Arduino Sloebber plugin inside Eclipse, so my espressif idf version should be 3.2 (arduino-esp32 version 1.0.4).

The wiring (BNO055 Shuffle Board to -> ESP32) is the following:

grafik

I modified some parts of the I2C interface implementaion:

So i am wondering if this issue is related to a general problem with the I2C interface of the ESP32? Or is this caused by the old idf version i am using?

ShellAddicted commented 3 years ago

Hi, yes there are issues with I²C (even with the latest idf), that's why UART is suggested and I²C is reported as partially supported by this library (see the readme.md).

As far as I know there's no way to fix that. In case you find a solution: any help is appreciated.

falkoschindler commented 2 years ago

I noticed that with a large timeout like i2c_set_timeout(i2c_port, 1048575) (1048575 = 2**20 - 1 clock cycles at 80 MHz = approx. 13 ms) the communication seems to be working (tested for 3+ hours). Might this be a solution or do I just have to wait longer for a communication problem?