thingy91x nrf5340 bmi270 spi no communication

Dear community,

we're having trouble connecting our thingy91x to the BMI270 via the nRF5340 using SPI. We've tried many similar cases without success.

Here's our setup: Visual Studio Code (1.105) with nRF Connect SDK and Toolchain (V3.1.1)

The app.overlay:

&spi3 {
	status = "okay";
	
	bmi270@2 {
		status = "okay";
	};
};

the prj.conf:

# USB CDC ACM Configuration
CONFIG_USB_DEVICE_STACK=y
CONFIG_USB_DEVICE_PRODUCT="Thingy91x BMI270 Test"
CONFIG_USB_CDC_ACM=y

# Serial settings
CONFIG_SERIAL=y

# Interface Configuration
CONFIG_GPIO=y
CONFIG_SPI=y
#CONFIG_SPI_NRFX_RAM_BUFFER_SIZE=8
#CONFIG_SPI_ASYNC=n

# Sensor Configuration
CONFIG_SENSOR=y
CONFIG_BMI270=y
#CONFIG_BMI270_TRIGGER_NONE=y

# Console configuration
CONFIG_CONSOLE=y
# Logging Configuration
CONFIG_LOG=y
CONFIG_LOG_DEFAULT_LEVEL=4
CONFIG_STDOUT_CONSOLE=y
CONFIG_RTT_CONSOLE=y
CONFIG_USE_SEGGER_RTT=y
CONFIG_LOG_BACKEND_RTT=y

The main.c file was generated from the original bmi270 sample using the thingy91x/nrf5340/cpuapp template.

#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/sensor.h>
#include <zephyr/drivers/uart.h>
#include <zephyr/usb/usb_device.h>
#include <zephyr/drivers/uart/cdc_acm.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>

#define SLEEP_TIME_MS   500

/* USB CDC ACM device */
#define USB_DEVICE_NAME CONFIG_USB_DEVICE_PRODUCT
static const struct device *usb_dev;
static char data[128];

/* Helper function for formatted output to USB CDC ACM */
static void cdc_printf(const char *format, ...) {
    va_list args;
    va_start(args, format);
    vsnprintf(data, sizeof(data), format, args);
    va_end(args);
    
    for (int i = 0; i < strlen(data); i++) {
        uart_poll_out(usb_dev, data[i]);
    }
}

/* The devicetree node identifier for the "led0" alias. */
#define LED0_NODE DT_ALIAS(led0)
static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios);

int main(void)
{
	// Initialize and blink LED 3 times
	int ret;

	if (!gpio_is_ready_dt(&led)) {
		return 0;
	}

	ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
	if (ret < 0) {
		return 0;
	}

	int i = 7;
	while (i > 0) {
		ret = gpio_pin_toggle_dt(&led);
		if (ret < 0) {
			return 0;
		}

		k_msleep(SLEEP_TIME_MS);
		i--;
	}

	////////////////////
	/* Enable USB CDC */
	ret = usb_enable(NULL);
	if (ret != 0) {
		return 0;
	}

	/* Wait for USB CDC to be ready */
	k_sleep(K_MSEC(1000));

	/* Get USB CDC ACM device */
	usb_dev = DEVICE_DT_GET_ONE(zephyr_cdc_acm_uart);
	if (!device_is_ready(usb_dev)) {
		return 0;
	}

	/* Write initial test message */
	cdc_printf("\r\nUSB CDC ACM device ready.\r\n");
	
	
	/////////////////////////////////////////
	// Setup and read data from BMI270 sensor
	cdc_printf("\r\nChecking BMI270 device tree status...\r\n");
	cdc_printf("accelerometer_hp node exists: %d\r\n", DT_NODE_EXISTS(DT_NODELABEL(accelerometer_hp)));
	cdc_printf("accelerometer_hp node status: %d\r\n", DT_NODE_HAS_STATUS(DT_NODELABEL(accelerometer_hp), okay));
	cdc_printf("spi3 node exists: %d\r\n", DT_NODE_EXISTS(DT_NODELABEL(spi3)));
	cdc_printf("spi3 node status: %d\r\n", DT_NODE_HAS_STATUS(DT_NODELABEL(spi3), okay));

	// Get SPI device first
	const struct device *const spi = DEVICE_DT_GET(DT_NODELABEL(spi3));
	if (!device_is_ready(spi)) {
		cdc_printf("SPI3 is not ready!\r\n");
		return 0;
	}
	cdc_printf("SPI3 is ready\r\n");

	// Now try to get BMI270
	const struct device *const dev_bmi = DEVICE_DT_GET(DT_NODELABEL(accelerometer_hp));
	if (dev_bmi == NULL) {
		cdc_printf("Could not get BMI270 device!\r\n");
		return 0;
	}
	cdc_printf("Got BMI270 device: %s\r\n", dev_bmi->name);

	struct sensor_value acc[3], gyr[3], val;
	struct sensor_value full_scale, sampling_freq, oversampling;

	if (!device_is_ready(dev_bmi)) {
		int ret;
		cdc_printf("BMI270 is not ready, starting basic initialization...\r\n");
		
		// Power-up time - wait 2ms after power-up
		k_sleep(K_MSEC(2));
		cdc_printf("Power-up delay complete\r\n");
		
		// Step 1: Dummy read to switch from I²C to SPI
		struct sensor_value chip_id = {0};
		ret = sensor_attr_get(dev_bmi, SENSOR_CHAN_ALL,
				   SENSOR_ATTR_CONFIGURATION, &chip_id);
		cdc_printf("Dummy read: err=%d, ID=0x%02x\r\n", 
			ret, (uint8_t)chip_id.val1);
		
		// Step 2: Try to read Chip ID (should be 0x24)
		ret = sensor_attr_get(dev_bmi, SENSOR_CHAN_ALL,
				   SENSOR_ATTR_CONFIGURATION, &chip_id);
		cdc_printf("Chip ID read: err=%d, ID=0x%02x (should be 0x24)\r\n", 
			ret, (uint8_t)chip_id.val1);
	
		return 0;
	}

	cdc_printf("BMI270 is ready and initialized!\r\n");

The following Flash command was used with a jlink probe:

nrfutil device program --firmware .\merged.hex --traits jlink --x-family nrf53 --core Application

The Output is:

Checking BMI270 device tree status...
accelerometer_hp node exists: 1
accelerometer_hp node status: 1
spi3 node exists: 1
spi3 node status: 1
SPI3 is ready
Got BMI270 device: bmi270@2
BMI270 is not ready, starting basic initialization...
Power-up delay complete
Dummy read: err=-88, ID=0x00
Chip ID read: err=-88, ID=0x00 (should be 0x24)

We also tried a raw SPI transceive: timeout.

Any help getting the bmi270 working is greatly appreciated! :-)

  • Hi Martin,
    Thanks for writing us, I assume you are talking about the onboard BMI270 or an external one?

    Best regards,
    Benjamin

  • Hi Benjamin,

    yes, we are talking about the onboard BMI270. 

    We can read out the BMI270 from the nrf9151 side. However, if we flash a blinky sample on the 9151 and try to read out the BMI270 via the nrf5340, it is not accessible as described.

    Is there possibly a problem with the 5340 device tree?

    Best regards,
    Martin

  • What about the load switch for the bmi supply? How is it activated?

  • The VDD_BMI270 @SB4 is 1.734V when running the code.

  • I got similar problem on Thingy:53. With very similar settings and same internal BMI270. What I see is bmi270 fails to initialize way before my code tries to use it, it is back in driver initialization. When driver attempts to init this sensor it reads deviceId, and in my case it is always 0, not what driver code expects. After that game is over, any call to device_is_ready() just checks flag that was set during driver initialization and return false. I traced system calls before driver reads deviceId at the first time, and it seems that all SPI settings like mode, CS level, clock polarity, etc - are compatible with bmi270 specs. I had issues with other sensors because of that, but not in this case.

    I tried to find any Nordic sample that uses bmi270, nothing there. Edge Impulse firmware uses second internal accelerometer, not bmi270, it works for them, but I need gyro data.

    So my request is: nice people in Nordic Semi, could you provide a simple working sample, that successfully reads data from bmi270?

    It could be useful for us to see, how to enable this sensor in overlay, what kind of config settings to use. I understand that bmi270 is really funky beast -- it requires loading 6kb of code into the chip, it could do this and that -- but I have it failed on the very first access, before all this. If it is broken, I could appreciate that you will tell it and we will stop wasting time on fixing it.

    Thank you,

    Sergei

Related