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! :-)

Parents
  • Hi,

    The default configuration gives the I2C and SPI to the nRF9151. These buses can only be controlled by a single host.

    The thingy91x_no_buses.dtsi file shows how you can disable the buses on the nRF9151. You will also need to use a different partition layout since the secondary app partition is on the SPI flash by default. This is already done with this file. One way to apply that
     memory layout is by adding the following Kconfig symbol in sysbuild.conf:

    SB_CONFIG_THINGY91X_STATIC_PARTITIONS_NRF53_EXTERNAL_FLASH=y

    There is also a bug in NCS 3.1.1 where this symbol can only be selected on the nRF53 side. The quick fix is to remove this line. See this PR.

    Best regards,
    Benjamin
Reply
  • Hi,

    The default configuration gives the I2C and SPI to the nRF9151. These buses can only be controlled by a single host.

    The thingy91x_no_buses.dtsi file shows how you can disable the buses on the nRF9151. You will also need to use a different partition layout since the secondary app partition is on the SPI flash by default. This is already done with this file. One way to apply that
     memory layout is by adding the following Kconfig symbol in sysbuild.conf:

    SB_CONFIG_THINGY91X_STATIC_PARTITIONS_NRF53_EXTERNAL_FLASH=y

    There is also a bug in NCS 3.1.1 where this symbol can only be selected on the nRF53 side. The quick fix is to remove this line. See this PR.

    Best regards,
    Benjamin
Children
No Data
Related