BMI160 w/ SPI 4wire on Raspi 4, IIO driver

Hi,

I have attached a BMI160 to a Raspberry PI4, SPI0 like in this schematic:

I wanted to use it with Linux IIO bmi160 driver (-> had to compile a custom RPI4 Linux kernel with this driver included because unfortunately the standard kernel has no bmi160 IIO driver). I have added a device tree overlay with this content:

/* add bmi160 spi device with CS=1*/
fragment@1 {
target = <&spi0>;
__overlay__ {
status = "okay";
#address-cells = <1>;
#size-cells = <0>;

bmi160@1 {
compatible = "bosch,bmi160";
reg = <1>;
spi-max-frequency = <1000000>;
};

};

};

 Now the driver gets loaded at Linux startup, but it never finds the BMI160. The driver prints out:

[ 9.978638] bmi160_spi spi0.1: supply vdd not found, using dummy regulator
[ 9.978827] bmi160_spi spi0.1: supply vddio not found, using dummy regulator
[ 9.978913] bmi160_spi spi0.1: mounting matrix not found: using identity...
[ 9.980262] bmi160_spi spi0.1: Wrong chip id, got 0 expected d1

I also checked with the Oscilloscope and never saw a signal on MISO :(. What the driver in its chip init sequence does is this (see https://elixir.bootlin.com/linux/v6.1.69/source/drivers/iio/imu/bmi160/bmi160_core.c#L719 )

1. SOFT RESET
2. Wait 1ms
3. Read register 0x7f (for switching to SPI mode)
4. Read CHIP ID
...

When reading the BMI160 data sheet, I wondered if this is correct, because already sending the SOFT RESET probably requires a switch to SPI mode, right? But also modifying the driver with an additional Read register 0x7f as step 0 did not change anything.

At this point I suspected there must probably be an electrical problem with my setup. But then I tried accessing the device not with the Linux IIO BMI160 driver, but with plain python3 spidev code - and the initial test code could read the CHIP ID 0xd1!

import spidev

spi = spidev.SpiDev()
spi.open(0,1)
spi.max_speed_hz = 1000000

# init SPI mode
ret = spi.xfer([0xff, 0x00])
# soft reset
ret = spi.xfer([0x7e, 0xb6])
# read id
ret = spi.xfer([0x80, 0x00])
print(f'chip id: {hex(ret[1])}')

On the Oscilloscope I did not see any difference in terms of signal polarity/phase - the shape of the signal looks the same. Only this time the MISO response signal of the chip ID was there. One difference of the Python code compared with the IIO driver was the 1ms delay of the driver before the Read of the CHIP ID. 

Now, the "funny" thing is: If I add this 1ms delay into the python code, I can *never* read the correct chip ID - it is always zero like the IIO driver reads it. That means, the BMI160 does not respond with the MISO signal, if I use a delay of 1ms after the SOFT RESET.

I am quite confused now - is there any explanation for this behavior? How long does the SOFT RESET take? How should an ideal initialization sequence look like?

Any support is appreciated.

Regards

Jörg

Best reply by jgrmpf

After some more tests I figured out the original soft reset timeout of 1ms is sufficient. And dropping the switch-to-SPI-mode timeout to 1ms is also sufficient. The sequence which works *for me* is now:

1. Read from 0x7f (-> switch to SPI mode)
2. Wait 1ms
3. Send SOFT_RESET
4. Wait 1ms
5. Read from 0x7f (-> switch to SPI mode required after softreset)
6. Wait 1ms
7. Read chip id

The Linux BMI160 IIO driver diff is now:

diff --git a/drivers/iio/imu/bmi160/bmi160_core.c b/drivers/iio/imu/bmi160/bmi160_core.c
index a77f1a834..a3ac3bd7d 100644
--- a/drivers/iio/imu/bmi160/bmi160_core.c
+++ b/drivers/iio/imu/bmi160/bmi160_core.c
@@ -94,6 +94,7 @@
 #define BMI160_ACCEL_PMU_MIN_USLEEP	3800
 #define BMI160_GYRO_PMU_MIN_USLEEP	80000
 #define BMI160_SOFTRESET_USLEEP		1000
+#define BMI160_SPI_MODE_CHANGE_USLEEP	1000
 
 #define BMI160_CHANNEL(_type, _axis, _index) {			\
 	.type = _type,						\
@@ -716,20 +717,29 @@ static int bmi160_chip_init(struct bmi160_data *data, bool use_spi)
 		return ret;
 	}
 
+	/*
+	 * CS rising edge is needed before starting SPI, so do a dummy read
+	 * See Section 3.2.1, page 86 of the datasheet
+	 */
+	if (use_spi) {
+		ret = regmap_read(data->regmap, BMI160_REG_DUMMY, &val);
+		if (ret)
+			goto disable_regulator;
+		usleep_range(BMI160_SPI_MODE_CHANGE_USLEEP, BMI160_SPI_MODE_CHANGE_USLEEP + 1);
+	}
+
 	ret = regmap_write(data->regmap, BMI160_REG_CMD, BMI160_CMD_SOFTRESET);
 	if (ret)
 		goto disable_regulator;
 
 	usleep_range(BMI160_SOFTRESET_USLEEP, BMI160_SOFTRESET_USLEEP + 1);
 
-	/*
-	 * CS rising edge is needed before starting SPI, so do a dummy read
-	 * See Section 3.2.1, page 86 of the datasheet
-	 */
+	/* After soft reset switch to SPI mode is required again */
 	if (use_spi) {
 		ret = regmap_read(data->regmap, BMI160_REG_DUMMY, &val);
 		if (ret)
 			goto disable_regulator;
+		usleep_range(BMI160_SPI_MODE_CHANGE_USLEEP, BMI160_SPI_MODE_CHANGE_USLEEP + 1);
 	}
 
 	ret = regmap_read(data->regmap, BMI160_REG_CHIP_ID, &val);
View original
2 replies
Resolved