Thingy:91X (nRF9151-NS) — can’t bring up BMI270 over SPIM3 (“Unexpected chip id 0”) while ADXL367 on I²C2 works

Hi everyone,

1) Hardware

  • Thingy:91X (the nRF9151 variant, HW rev 1.0.0)

  • On-board ADXL367 (I²C @ 0x1D) ← works

  • Extra BMI270 IMU on breakout board, wired to SPIM3

    • SCK → P0.14

    • MOSI → P0.13

    • MISO → P0.12

    • CS → P0.10 (active LOW)

    • VDD 3 V, VDDIO 1V8 (same rail as ADXL367)

    • GND common

2) Software

  • nRF Connect SDK v2.9.1 (Zephyr 3.7.99)

  • Building with west build -p always -b thingy91x/nrf9151/ns

  • Bootloader MCUboot enabled (default Thingy:91X sysbuild)

3) Device-tree overlay

/* thingy91x_bmi270.overlay */

&pinctrl {
    spi3_bmi270_default: spi3_bmi270_default {
        group1 {
            psels = <
                NRF_PSEL(SPIM_SCK,  0, 14)
                NRF_PSEL(SPIM_MOSI, 0, 13)
                NRF_PSEL(SPIM_MISO, 0, 12)
            >;
        };
    };

    spi3_bmi270_sleep: spi3_bmi270_sleep {
        group1 {
            psels = <
                NRF_PSEL(SPIM_SCK,  0, 14)
                NRF_PSEL(SPIM_MOSI, 0, 13)
                NRF_PSEL(SPIM_MISO, 0, 12)
            >;
            low-power-enable;
        };
    };
};

/* SPI-connected BMI270 -------------------------------------------------- */
&spi3 {
    status = "okay";

    pinctrl-0     = <&spi3_bmi270_default>;
    pinctrl-1     = <&spi3_bmi270_sleep>;
    pinctrl-names = "default", "sleep";

    cs-gpios = <&gpio0 10 GPIO_ACTIVE_LOW>;

    bmi270: bmi270@0 {
        compatible        = "bosch,bmi270";
        reg               = <0>;
        spi-max-frequency = <DT_FREQ_M(10)>;
        status            = "okay";
    };
};

/* keep the on-board ADXL367 on I²C2 “as is” ----------------------------- */
&i2c2 {
    accel: accelerometer_lp: adxl367@1d {
        status     = "okay";
        compatible = "adi,adxl367";
        reg        = <0x1d>;
        odr        = <3>;
    };
};

4) prj.conf

# Core + console
CONFIG_GPIO=y
CONFIG_SPI=y
CONFIG_I2C=y
CONFIG_SERIAL=y
CONFIG_UART_CONSOLE=y
CONFIG_PRINTK=y
CONFIG_LOG=y

# Sensors
CONFIG_SENSOR=y
CONFIG_ADXL367=y
CONFIG_BMI270=y
CONFIG_SENSOR_LOG_LEVEL_DBG=y      # verbose driver logs

# Toolchain / libc
CONFIG_CPP=y
CONFIG_GLIBCXX_LIBCPP=y
CONFIG_NEWLIB_LIBC=y
CONFIG_NEWLIB_LIBC_FLOAT_PRINTF=y
CONFIG_FPU=y
CONFIG_MAIN_STACK_SIZE=8192

# Drivers
CONFIG_I2C_NRFX=y
CONFIG_SPI_NRFX=y
CONFIG_GPIO_NRFX=y

# Boot
CONFIG_BOOTLOADER_MCUBOOT=y

5) Minimal main.c

#include <zephyr/kernel.h>
#include <zephyr/drivers/sensor.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(app, LOG_LEVEL_INF);

#define ADXL367_NODE DT_NODELABEL(accelerometer_lp)
#define BMI270_NODE  DT_NODELABEL(bmi270)

static const struct device *const adxl367_dev = DEVICE_DT_GET(ADXL367_NODE);
static const struct device *const bmi270_dev  = DEVICE_DT_GET(BMI270_NODE);

static void read_print(const struct device *dev, const char *name)
{
    struct sensor_value acc[3], gyr[3];

    if (sensor_sample_fetch(dev) < 0) { LOG_ERR("%s fetch", name); return; }
    sensor_channel_get(dev, SENSOR_CHAN_ACCEL_XYZ, acc);

    printk("%s ACC %d.%06d %d.%06d %d.%06d\n",
           name,
           acc[0].val1, abs(acc[0].val2),
           acc[1].val1, abs(acc[1].val2),
           acc[2].val1, abs(acc[2].val2));

    if (strcmp(name, "BMI270") == 0 &&
        sensor_channel_get(dev, SENSOR_CHAN_GYRO_XYZ, gyr) == 0) {
        printk("%s GYR %d.%06d %d.%06d %d.%06d\n",
               name,
               gyr[0].val1, abs(gyr[0].val2),
               gyr[1].val1, abs(gyr[1].val2),
               gyr[2].val1, abs(gyr[2].val2));
    }
}

void main(void)
{
    if (!device_is_ready(adxl367_dev) || !device_is_ready(bmi270_dev)) {
        LOG_ERR("Sensors not ready");
        return;
    }
    LOG_INF("Sensors OK. Reading…");

    while (1) {
        read_print(adxl367_dev, "ADXL367");
        read_print(bmi270_dev,  "BMI270");
        k_sleep(K_MSEC(1000));
    }
}

6) Logs

php-template
CopyEdit
<err> bmi270: Unexpected chip id (0). Expected (24) <err> app: BMI270 not ready

ADXL367 always works; BMI270 never gets past the chip-ID test.


What I have tried

  1. Scope on CS/SCK/MOSI/MISO
    CS stays low only during transfers, no obvious glitches.

  2. Verified 3 V supply and 1.8 V IO rail — both solid.

  3. Lowered spi-max-frequency down to 1 MHz → same result.

  4. Swapped breakout board (two different BMI270 modules).

  5. Confirmed pull-ups on INT pins disabled (left floating).


Questions to the community

  1. Does anyone have BMI270 working on a Thingy:91X (nRF9151) with NCS ≥ 2.9?

  2. Is there any extra GPIO/power sequencing needed (e.g. CS high > t_boot)?

  3. Am I missing a reset-gpio or bmi270,power-mode property in the DTS?

  4. Any gotchas with SPIM3 + external sensor while the on-board ADXL367 is
    enabled on I²C2?

Thanks a lot for any hints!

  • Hello, 

    Is there a reason for why you are not using the onboard BMI270 on the Thingy:91X?

    Does anyone have BMI270 working on a Thingy:91X (nRF9151) with NCS ≥ 2.9?

    I tested with your code and configured the onboard BMI270 using the following lines in main.c

    static const struct device *const adxl367_dev = DEVICE_DT_GET(DT_NODELABEL(accelerometer_lp));
    static const struct device *const bmi270_dev  =  DEVICE_DT_GET(DT_NODELABEL(accelerometer_hp));

    And this added to thingy91x_nrf9151_ns.overlay

    &spi3 {
        accelerometer_hp: bmi270@2 {
                compatible = "bosch,bmi270";
                status = "okay";
                reg = <2>;
                spi-max-frequency = <DT_FREQ_M(10)>;
            };
    };
    
    /* keep the on-board ADXL367 on I²C2 “as is” ----------------------------- */
    &i2c2 {
        accel: accelerometer_lp: adxl367@1d {
            status     = "okay";
            compatible = "adi,adxl367";
            reg        = <0x1d>;
            odr        = <3>;
        };
    };



    I also tried the BMI270 sample. Here is the output from your code vs the sample code:

    ADXL367 ACC 0.060270 0.054390 0.943495
    BMI270 ACC 0.000000 0.000000 0.000000
    BMI270 GYR 0.000000 0.000000 0.000000
    ADXL367 ACC 0.061740 0.053655 0.948395
    BMI270 ACC 0.000000 0.000000 0.000000
    BMI270 GYR 0.000000 0.000000 0.000000
    ADXL367 ACC 0.067865 0.055615 0.943495
    BMI270 ACC 0.000000 0.000000 0.000000
    BMI270 GYR 0.000000 0.000000 0.000000
    ADXL367 ACC 0.063700 0.051695 0.940555
    BMI270 ACC 0.000000 0.000000 0.000000
    BMI270 GYR 0.000000 0.000000 0.000000
    ADXL367 ACC 0.061005 0.050715 0.943740
    BMI270 ACC 0.000000 0.000000 0.000000
    BMI270 GYR 0.000000 0.000000 0.000000
    ADXL367 ACC 0.059780 0.056105 0.947415
    BMI270 ACC 0.000000 0.000000 0.000000
    BMI270 GYR 0.000000 0.000000 0.000000
    ADXL367 ACC 0.065905 0.054635 0.947660
    BMI270 ACC 0.000000 0.000000 0.000000
    BMI270 GYR 0.000000 0.000000 0.000000
    ADXL367 ACC 0.061495 0.052430 0.944720
    BMI270 ACC 0.000000 0.000000 0.000000
    BMI270 GYR 0.000000 0.000000 0.000000
    ADXL367 ACC 0.065905 0.055370 0.945700
    BMI270 ACC 0.000000 0.000000 0.000000
    BMI270 GYR 0.000000 0.000000 0.000000
    *** Booting nRF Connect SDK v2.9.1-60d0d6c8d42d ***
    *** Using Zephyr OS v3.7.99-ca954a6216c9 ***
    Attempting to boot slot 0.
    Attempting to boot from address 0x8200.
    I: Trying to get Firmware version
    I: Verifying signature against key 0.
    I: Hash: 0x3e...f9
    I: Firmware signature verified.
    Firmware version 2
    I: Setting monotonic counter (version: 2, slot: 0)
    *** Booting nRF Connect SDK v2.9.1-60d0d6c8d42d ***
    *** Using Zephyr OS v3.7.99-ca954a6216c9 ***
    Device 0x44fc4 name is bmi270@2
    AX: 0.000000; AY: 0.000000; AZ: 0.000000; GX: 0.000000; GY: 0.000000; GZ: 0.000000;
    AX: 0.000000; AY: 0.000000; AZ: 0.000000; GX: 0.000000; GY: 0.000000; GZ: 0.000000;
    AX: 0.781730; AY: 0.507586; AZ: 9.650722; GX: 0.000000; GY: 0.000000; GZ: 0.000000;
    AX: 0.789512; AY: 0.509381; AZ: 9.730332; GX: 0.000000; GY: 0.000000; GZ: 0.000000;
    AX: 0.779336; AY: 0.498607; AZ: 9.719558; GX: 0.-05060; GY: 0.003994; GZ: 0.-03195;
    AX: 0.782329; AY: 0.506987; AZ: 9.714769; GX: 0.-00266; GY: 0.-02130; GZ: 0.-00266;
    AX: 0.788314; AY: 0.516564; AZ: 9.712375; GX: 0.-00266; GY: 0.-01864; GZ: 0.000798;
    AX: 0.769160; AY: 0.514769; AZ: 9.726142; GX: 0.-01597; GY: 0.-01597; GZ: 0.001597;
    AX: 0.765569; AY: 0.502199; AZ: 9.726142; GX: 0.-01864; GY: 0.-01597; GZ: 0.000532;
    AX: 0.780533; AY: 0.498009; AZ: 9.732128; GX: 0.-01597; GY: 0.-03462; GZ: 0.-00532;
    AX: 0.773949; AY: 0.516564; AZ: 9.738113; GX: 0.-02130; GY: 0.-03462; GZ: 0.000798;
    AX: 0.779934; AY: 0.496213; AZ: 9.702798; GX: 0.-00798; GY: 0.-01597; GZ: 0.-00532;
    AX: 0.788314; AY: 0.505191; AZ: 9.739909; GX: 0.-02663; GY: 0.-03728; GZ: 0.001065;
    AX: 0.797293; AY: 0.499804; AZ: 9.719558; GX: 0.001065; GY: 0.-01864; GZ: 0.000000;
    AX: 0.785322; AY: 0.508783; AZ: 9.719558; GX: 0.-01065; GY: 0.-02396; GZ: 0.000000;
    AX: 0.791906; AY: 0.507586; AZ: 9.712974; GX: 0.-01864; GY: 0.-02663; GZ: 0.000266;
    AX: 0.781730; AY: 0.510579; AZ: 9.705791; GX: 0.000532; GY: 0.-02130; GZ: 0.000266;
    AX: 0.793702; AY: 0.512374; AZ: 9.729733; GX: 0.-03195; GY: 0.-03462; GZ: 0.-00532;
    AX: 0.783526; AY: 0.500403; AZ: 9.727339; GX: 0.-01065; GY: 0.-02663; GZ: 0.000000;
    AX: 0.783526; AY: 0.521353; AZ: 9.722551; GX: 0.000000; GY: 0.-02396; GZ: 0.002130;

    Only editing line 14 to this:

    const struct device *const dev = DEVICE_DT_GET(DT_NODELABEL(accelerometer_hp));

    Is there any extra GPIO/power sequencing needed (e.g. CS high > t_boot)?

    Not that I know of. 

    Am I missing a reset-gpio or bmi270,power-mode property in the DTS?

    From what I can see, everything looks good, but I don't have any external bmi270 modules to test with.

    Kind regards,
    Øyvind

Related