[SPI] not device ready

Hi there,

SPI device is not ready.

What's wrong?

NCS version: v2.6.1

&spi1 {
    compatible = "nordic,nrf-spi";
    status = "okay";
    pinctrl-0 = <&spi1_default>;
    pinctrl-names = "default";
    max-frequency = <DT_FREQ_M(24)>;
    cs-gpios = <&gpio0 15 GPIO_ACTIVE_LOW>;
    
    icm42670p: icm42670p@0 {
        compatible = "invensense,icm42670";
        reg = <0>;
        spi-max-frequency = <DT_FREQ_M(24)>;
        accel-hz = <1600>;
        accel-fs = <16>;
        gyro-hz = <1600>;
        gyro-fs = <2000>;
    };
};


&pinctrl {
	uart0_default: uart0_default {
		group1 {
			psels = <NRF_PSEL(UART_TX, 0, 6)>, <NRF_PSEL(UART_RX, 0, 8)>;
		};
	};

	i2c0_default: i2c0_default {

		group1 {
			psels = <NRF_PSEL(TWIM_SCL, 0, 17)>, <NRF_PSEL(TWIM_SDA, 0, 18)>;
			nordic,invert;
			bias-pull-up;
		};
	};

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

#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/spi.h>

// #include <zephyr/drivers/gpio.h>
// #include <zephyr/logging/log.h>
// #include <zephyr/device.h>
// #include <zephyr/drivers/uart/cdc_acm.h>
// #include <zephyr/drivers/uart.h>

#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/hci.h>
#include <zephyr/settings/settings.h>

#include "lib/bluetooth_manager/bluetooth_manager.h"
#include "lib/gpio/gpio.h"
#include "lib/magneto/magneto.h"

#define ICM42670P_NODE DT_NODELABEL(icm42670p)
const struct device *icm42670p_spec = DEVICE_DT_GET(ICM42670P_NODE);

struct spi_config spi_cfg = {
    .frequency = DT_PROP(ICM42670P_NODE, spi_max_frequency),
    .operation = SPI_WORD_SET(8) | SPI_TRANSFER_MSB | SPI_MODE_CPOL | SPI_MODE_CPHA,
    .slave = DT_REG_ADDR(ICM42670P_NODE),
    .cs = NULL,
};

#define ICM42670P_WHO_AM_I_REG 0x75

void read_icm42670p_who_am_i(void)
{
    uint8_t tx_buffer[2] = {ICM42670P_WHO_AM_I_REG | 0x80, 0x00}; // 0x80 to set the read bit
    uint8_t rx_buffer[2] = {0};

    struct spi_buf tx_buf = {
        .buf = tx_buffer,
        .len = sizeof(tx_buffer),
    };
    struct spi_buf rx_buf = {
        .buf = rx_buffer,
        .len = sizeof(rx_buffer),
    };
    struct spi_buf_set tx = {
        .buffers = &tx_buf,
        .count = 1,
    };
    struct spi_buf_set rx = {
        .buffers = &rx_buf,
        .count = 1,
    };

    int ret = spi_transceive(icm42670p_spec, &spi_cfg, &tx, &rx);
    if (ret < 0)
    {
        printk("SPI transaction failed: %d\n", ret);
    }
    else
    {
        printk("ICM42670P WHO_AM_I: 0x%02x\n", rx_buffer[1]);
    }
}

int main(void) {
    int err;

    // Initialize the Bluetooth Subsystem
    err = bt_enable(NULL);
    if (err) {
        printk("Bluetooth init failed (err %d)\n", err);
        return 0;
    }

    printk("Bluetooth initialized\n");

    if (IS_ENABLED(CONFIG_SETTINGS)) {
        settings_load();
    }

    // Start advertising
    err = start_bluetooth_advertise();
    if (err) {
        printk("Advertising failed to start (err %d)\n", err);
        return 0;
    }

    printk("Advertising successfully started\n");

    // Check if the ICM42670P device is ready
    if (!device_is_ready(icm42670p_spec)) {
        printk("ICM42670P device not ready\n");
        return 0;
    }

    // Read WHO_AM_I register
    read_icm42670p_who_am_i();

    return 0;
}

Parents
  • Hi 

    Could you enable logging and build your application with optimized for debug and post the log?

    Could you also show me your overlay?

    Regards

    Runar

  • I solved the issue with nRF SPI master/slave example.

    But I faced another issue.

     I am using a sensor with its WHO AM I register value is 0x47.

    However, I keep receiving data from it 0x4C.

    To verify that the sensor unit has no issue, I tested with STM32.

    Please check it below oscilloscope waveform and decode value.

    [STM32]: sensor response with correct value

    [nRF52-DK]: sensor response with wrong value

    So we can conclude that the sensor has no problem. I used the same jumber cables and same oscilloscope setup.

    Here's the device tree and C code

    icm42670p: &spi2 {
    	compatible = "nordic,nrf-spi";
    	// compatible = "nordic,nrf-spim";
    	status = "okay";
    	pinctrl-0 = <&spi1_default>;
    	pinctrl-names = "default";
    	cs-gpios = <&gpio0 15 GPIO_ACTIVE_LOW>;
    	overrun-character = <1>;
    	reg_icm42670p: reg_icm42670p@0 {
    		reg = <0>;
    	};
    
    	max-frequency = <DT_FREQ_M(8)>;
    };

    /**
     * The first bit of the first byte contains the Read/Write bit and indicates the Read (1) operation
     * The first bit of the first byte contains the Read/Write bit and indicates the Write (0) operation.
     */
    int spi_read_register(const struct device *spi_dev, const struct spi_config *spi_cfg, uint8_t address, uint8_t *data, size_t len)
    {
        uint8_t tx_buf = REG_SPI_READ_BIT | address; // Set read bit
        printk("tx_buf: %x\n", tx_buf);
    
        struct spi_buf tx_bufs = {
            .buf = &tx_buf,
            .len = 1,
        };
    
        struct spi_buf_set tx = {
            .buffers = &tx_bufs,
            .count = 1
        };
        
        // size determined by tx buffer size
        struct spi_buf rx_buf[2] = {
            {
                .buf = NULL,
                // .len = 1,
                .len = sizeof(tx_buf),
            },
            {
                .buf = data,
                .len = len,
            }};
    
        const struct spi_buf_set rx = {
            .buffers = rx_buf,
            // .count = ARRAY_SIZE(rx_buf),
            .count = 2,
            .count = 2,
        };
    
        int ret = spi_transceive(spi_dev, spi_cfg, &tx, &rx);
        if (ret == 0)
        {
            printk("Read from address: 0x%x, received data: 0x%x\n", address, *data);
        }
        else
        {
            printk("SPI transceive error: %d\n", ret);
        }
    
        return ret;
    }

  • Hi

    I had a look in the datasheet. Are you sure you are using the ICM42670? I would expect whoami to be 0x67 according to both the driver and the datasheet. https://github.com/nrfconnect/sdk-zephyr/blob/main/drivers/sensor/tdk/icm42670/icm42670_reg.h#L259 

    Regards

    Runar

  • Sorry. I didn't mentioned that I used ICM42688 for testing before PCB arrive.
    So it's WHO AM I register value should be 0x47.

    When you see the waveform from STM32 MOSI line(=Green Colored) stay HIGH until next byte clock starts. Is it possible to have it in nRF?

    If yes, how to?

  • Ah that maks more sense. I would recommend that you change your application to use the ICM42688  while you test now. So that the correct driver is enabled. If you switch to ICM42688  in your application, do you see any difference in the result? 
    I will need to ask a colleage regarding the MOSI high until next byte

    Regards

    Runar

Reply Children
  • I followed your instruction to use zephyr official driver for icm-42688.

    Setting up the soft-reset and clear reset flag done successfully.

    Especially reading the reset flag is done through MISO pin and it's done properly.

    Hmm. Very interesting. I hope I am making a silly mistake but I can't figure it out. Please help Upside down

    #include <zephyr/types.h>
    #include <zephyr/drivers/gpio.h>0
    #include <zephyr/drivers/spi.h>
    #include <zephyr/sys/util.h>
    #include <zephyr/drivers/sensor.h> // sensor driver
    
    /* 1000 msec = 1 sec */
    #define SLEEP_TIME_MS 1000
    #define ICM42688P_SPI_NODE DT_NODELABEL(icm42688)
    #define ICM42670P_SPI_CS_DT_SPEC SPI_CS_GPIOS_DT_SPEC_GET(DT_NODELABEL(reg_icm42688))
    
    int main(void)
    {
    	printk("sensor: Hello.\n");
    
    	const struct device *spi_dev = DEVICE_DT_GET(ICM42688P_SPI_NODE);
    	const struct gpio_dt_spec spim_cs_gpio = ICM42670P_SPI_CS_DT_SPEC;
    	if (!device_is_ready(spi_dev))
    	{
    		printk("sensor: device not ready.\n");
    		return 0;
    	}
    	else
    	{
    		printk("sensor: device ready.\n");
    	}
    
    	// while (true)
    	// {
    
    	// 	k_sleep(K_MSEC(1000));
    	// }
    
    	return 0;
    }

  • Thank you. What is the gpio voltage you are running? I just noticed that it was lower then the STM you compared it to. 

    Regards

    Runar

  • As you mentioned, GPIO HIGH level Voltage of SPI Pins are
    nRF52-DK: 3.15V
    STM F301RB: 3.59V

    Hmm interesting. Do you think this can cause the issue?

  • Hi

    I had another look at our application. Instead of running with 2x buffers, could you try the implementation we did on SPI lesson on devacademy

    For some reason it looks like you are getting a "1" on the MOSI line after sending the register address 

    Regards

    Runar

Related