Cannot retrieve data from BMI270 using SPI on nRF52840

Hi,

I have the following problem.

I have a custom board where I have BMI270 connected with SPI.

I use the nrfx_spim library.

I get error codes as a success when I try to write and read to SPI, however, I always get 0x00.

So I assume the problem has to be with the configuration of the hardware. The board is professionally made by a manufacturer, so the problem is not here, but rather in my configuration.

Here is my dts file part with the configuration for SPI, I tried using BMI270 predefined profile, and also manually, but none of them worked for me.

On my board connections are:

BMI270 SDO/MISO -> P0.20

BMI270 SDI/MOSI -> P0.22

BMI270 SCK -> P0.24

BMI270 CS -> P1.00

&gpio0 {
	status = "okay";
};

&gpio1 {
	status = "okay";
};

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

	pinctrl-0 = <&spi1_default>;
	pinctrl-names = "default";
	cs-gpios = <&gpio1 0 (GPIO_ACTIVE_LOW)>; // P1.00 as CS, active low
};

&pinctrl {
	spi1_default: spi1_default {
		group1 {
			psels = <NRF_PSEL(SPIM_SCK, 0, 24)>,
		   <NRF_PSEL(SPIM_MOSI, 0, 22)>,
		   <NRF_PSEL(SPIM_MISO, 0, 20)>;
		};
	};
};

I also tried enabling and disabling those CONFIG flags

CONFIG_SPI=y
CONFIG_BMI270=y

and finally my main.c looks like this

#include <zephyr/kernel.h>
#include "SEGGER_RTT.h"
#include "SEGGER_RTT_printf.c"
#include "nrfx_spim.h"

// SPI instance index. You can have multiple instances for different peripherals.
#define SPI_INSTANCE_ID 0

#define SPI_CS_PIN 32

// Create an SPI configuration structure
nrfx_spim_config_t spi_config = NRFX_SPIM_DEFAULT_CONFIG(
    NRF_GPIO_PIN_MAP(0, 24),  // SCK pin
    NRF_GPIO_PIN_MAP(0, 22),  // MOSI pin
    NRF_GPIO_PIN_MAP(0, 20),  // MISO pin
    NRF_GPIO_PIN_MAP(1, 0)    // CS pin
);

nrfx_spim_t spi_instance = NRFX_SPIM_INSTANCE(SPI_INSTANCE_ID);

void spi_write(uint8_t *data, size_t length) {
    nrfx_spim_xfer_desc_t xfer_desc = NRFX_SPIM_XFER_TX(data, length);
    nrfx_spim_xfer(&spi_instance, &xfer_desc, 0);
}

void spi_read(uint8_t *command, size_t command_length, uint8_t *response, size_t response_length) {
    nrfx_spim_xfer_desc_t xfer_desc = NRFX_SPIM_XFER_TRX(command, command_length, response, response_length);
    nrfx_spim_xfer(&spi_instance, &xfer_desc, 0);
}

static uint8_t bmi270_read_register(uint8_t reg_addr) {
    // Assuming the sensor uses single-byte addresses
    uint8_t tx_buf[] = {0x80 | 0x00, 0x00}; // 0x80 for read, followed by dummy byte
    uint8_t rx_buf[2] = {0};

    // Prepare transfer
    nrfx_spim_xfer_desc_t xfer_desc_tx = NRFX_SPIM_XFER_TX(tx_buf, sizeof(tx_buf));
    nrfx_spim_xfer_desc_t xfer_desc_rx = NRFX_SPIM_XFER_RX(rx_buf, sizeof(rx_buf));

    // Transfer
    nrfx_err_t err_code = nrfx_spim_xfer(&spi_instance, &xfer_desc_tx, 0);

    if (err_code != NRFX_SUCCESS) 
    {
        // Initialization failed
        SEGGER_RTT_WriteString(0, "Sending failed!\n");
        return -1;
    }
    else
    {
        SEGGER_RTT_WriteString(0, "Sending has been done successfully!\n");

    }

    k_sleep(K_MSEC(2000));

    err_code = nrfx_spim_xfer(&spi_instance, &xfer_desc_rx, 0);


    if (err_code != NRFX_SUCCESS) 
    {
        // Initialization failed
        SEGGER_RTT_WriteString(0, "Reading failed!\n");
        return -1;
    }
    else
    {
        SEGGER_RTT_WriteString(0, "Reading has been done successfully!\n");

    }

    // The received data is in rx_buf[1]
    return rx_buf[1];
}

int main(void)
{
        nrfx_err_t err_code = nrfx_spim_init(&spi_instance, &spi_config, NULL, NULL);
        if (err_code != NRFX_SUCCESS) 
        {
            // Initialization failed
            SEGGER_RTT_WriteString(0, "SPI init failed!\n");
            return -1;
        }
        else
        {
            SEGGER_RTT_WriteString(0, "SPI init performed successfully!\n");

        }
        
        uint8_t data_buffer_from_SPI = bmi270_read_register(0x00);
        //for(int i = 0; i < sizeof(data_buffer_from_SPI); i++)
        //{
            SEGGER_RTT_printf(0, "BMI270 data0: 0x%02X\n", data_buffer_from_SPI);
        //}
        
}

Everything looks good when checking error codes.

More from my trial and error:

-it didn't work below 125kH as it is not supported, so I got this exception

-when I added the CONFIG_SENSOR=y flag it didn't want to build

I think that's what I have now, I am pretty sure I have a problem with hardware configuration, but I don't know where.

When I ran this application on the nRF52840 DK board, I got the same output, even though there are no SPI devices connected, but the write and read were fine just 0xFF as well.

Thank you for any help :D

  • with or without MSB added in the send buffer, this is how the response look like

  • Hi,

    I do not know how the sensor you are using works, but note that the CS pin will go high between the TX and RX operations when the transfers are split into two separate operations. You should check the datasheet of the sensor to see if it will discard any received command when CS goes high, or if it can accept TX and RX to occur in separate transfers.

    You can either use NRFX_SPIM_XFER_TRX() to create one transfer for both TX and RX, or control the CS pin manually in application by setting ss_pin to NRF_SPIM_PIN_NOT_CONNECTED in the driver config. Remember that if you use TRX, you should set the RX buffer size to TX length + RX length if you expect response from slave after commands have been written, since SPI RX buffers starts to get filled when TX data is shifted out.

    Best regards,
    Jørgen

  • The TRX option handle completely the CS pin right?

    In my case when using it instead of reading and writing separately I get 0x255 all the time

    #include <zephyr/kernel.h>
    #include "SEGGER_RTT.h"
    #include "SEGGER_RTT_printf.c"
    #include "nrfx_spim.h"
    
    //#include "remote_service/remote.h"
    
    // SPI instance index. You can have multiple instances for different peripherals.
    #define SPI_INSTANCE_ID 0
    
    #define SPI_CS_PIN 32
    
    // Create an SPI configuration structure
    nrfx_spim_config_t spi_config = NRFX_SPIM_DEFAULT_CONFIG(
        NRF_GPIO_PIN_MAP(0, 24),  // SCK pin
        NRF_GPIO_PIN_MAP(0, 22),  // MOSI pin
        NRF_GPIO_PIN_MAP(0, 20),  // MISO pin
        NRF_GPIO_PIN_MAP(1, 0)    // CS pin
    );
    
    nrfx_spim_t spi_instance = NRFX_SPIM_INSTANCE(SPI_INSTANCE_ID);
    
    void spi_write(uint8_t *data, size_t length) {
        nrfx_spim_xfer_desc_t xfer_desc = NRFX_SPIM_XFER_TX(data, length);
        nrfx_spim_xfer(&spi_instance, &xfer_desc, 0);
    }
    
    void spi_read(uint8_t *command, size_t command_length, uint8_t *response, size_t response_length) {
        nrfx_spim_xfer_desc_t xfer_desc = NRFX_SPIM_XFER_TRX(command, command_length, response, response_length);
        nrfx_spim_xfer(&spi_instance, &xfer_desc, 0);
    }
    
    static uint8_t bmi270_read_register(uint8_t reg_addr) {
        // Assuming the sensor uses single-byte addresses
        uint8_t tx_buf[] = {0x00, 0x00}; // 0x80 for read, followed by dummy byte
        uint8_t rx_buf[4] = {};
    
        // Prepare transfer
        nrfx_spim_xfer_desc_t xfer_desc_tx = NRFX_SPIM_SINGLE_XFER(tx_buf, sizeof(tx_buf), rx_buf, sizeof(rx_buf));
        nrfx_spim_xfer_desc_t xfer_desc_rx = NRFX_SPIM_XFER_RX(rx_buf, sizeof(rx_buf));
    
        // Transfer
        nrfx_err_t err_code = nrfx_spim_xfer(&spi_instance, &xfer_desc_tx, 0);
    
        if (err_code != NRFX_SUCCESS) 
        {
            // Initialization failed
            SEGGER_RTT_WriteString(0, "Sending failed!\n");
            return 1;
        }
        else
        {
            SEGGER_RTT_WriteString(0, "Sending has been done successfully!\n");
    
        }
    
        //k_sleep(K_MSEC(2000));
    
        //err_code = nrfx_spim_xfer(&spi_instance, &xfer_desc_rx, 0);
    
    
        if (err_code != NRFX_SUCCESS) 
        {
            // Initialization failed
            SEGGER_RTT_WriteString(0, "Reading failed!\n");
            return -1;
        }
        else
        {
            SEGGER_RTT_WriteString(0, "Reading has been done successfully!\n");
    
        }
    
        // The received data is in rx_buf[1]
        return rx_buf[3];
    }
    
    int main(void)
    {
            nrfx_err_t err_code = nrfx_spim_init(&spi_instance, &spi_config, NULL, NULL);
            if (err_code != NRFX_SUCCESS) 
            {
                // Initialization failed
                SEGGER_RTT_WriteString(0, "SPI init failed!\n");
                return -1;
            }
            else
            {
                SEGGER_RTT_WriteString(0, "SPI init performed successfully!\n");
    
            }
            
            uint8_t data_buffer_from_SPI = bmi270_read_register(0x00);
            //for(int i = 0; i < sizeof(data_buffer_from_SPI); i++)
            //{
                SEGGER_RTT_printf(0, "BMI270 data0: 0x%02X\n", data_buffer_from_SPI);
            //}
            
    }

  • MatiM said:
    The TRX option handle completely the CS pin right?

    Yes, it should handle the toggling of CS pin as long as this is set in the config.

    MatiM said:
    In my case when using it instead of reading and writing separately I get 0x255 all the time

    I can't see how the function is used in the attached code. What is the input to spi_read()? NRFX_SPIM_SINGLE_XFER() should not be used, as stated in the documentation, this is for internal use only.

  • #include <zephyr/kernel.h>
    #include "SEGGER_RTT.h"
    #include "SEGGER_RTT_printf.c"
    #include "nrfx_spim.h"
    
    #define SPI_INSTANCE_ID 0
    
    #define SPI_CS_PIN 32
    
    // Create an SPI configuration structure
    nrfx_spim_config_t spi_config = NRFX_SPIM_DEFAULT_CONFIG(
        NRF_GPIO_PIN_MAP(0, 24),  // SCK pin
        NRF_GPIO_PIN_MAP(0, 22),  // MOSI pin
        NRF_GPIO_PIN_MAP(0, 20),  // MISO pin
        NRF_GPIO_PIN_MAP(1, 0)    // CS pin
    );
    
    nrfx_spim_t spi_instance = NRFX_SPIM_INSTANCE(SPI_INSTANCE_ID);
    
    static uint8_t bmi270_read_register(uint8_t reg_addr) {
        // Assuming the sensor uses single-byte addresses
        uint8_t tx_buf[] = {0x00, 0x00}; // 0x80 for read, followed by dummy byte
        uint8_t rx_buf[4] = {};
    
        // Prepare transfer
        nrfx_spim_xfer_desc_t xfer_desc_trx = NRFX_SPIM_XFER_TRX(tx_buf, sizeof(tx_buf), rx_buf, sizeof(rx_buf));
    
        // Transfer
        nrfx_err_t err_code = nrfx_spim_xfer(&spi_instance, &xfer_desc_trx, 0);
    
        if (err_code != NRFX_SUCCESS) 
        {
            // Initialization failed
            SEGGER_RTT_WriteString(0, "Sending failed!\n");
            return 1;
        }
        else
        {
            SEGGER_RTT_WriteString(0, "Sending has been done successfully!\n");
    
        }
    
        if (err_code != NRFX_SUCCESS) 
        {
            // Initialization failed
            SEGGER_RTT_WriteString(0, "Reading failed!\n");
            return -1;
        }
        else
        {
            SEGGER_RTT_WriteString(0, "Reading has been done successfully!\n");
    
        }
    
        // The received data is in rx_buf[1]
        return rx_buf[1];
    }
    
    int main(void)
    {
            nrfx_err_t err_code = nrfx_spim_init(&spi_instance, &spi_config, NULL, NULL);
            if (err_code != NRFX_SUCCESS) 
            {
                SEGGER_RTT_WriteString(0, "SPI init failed!\n");
                return -1;
            }
            else
            {
                SEGGER_RTT_WriteString(0, "SPI init performed successfully!\n");
            }
            
            uint8_t data_buffer_from_SPI = bmi270_read_register(0x00);
            SEGGER_RTT_printf(0, "BMI270 data0: 0x%02X\n", data_buffer_from_SPI);     
    }
    

    spi_read() is not used here, I am now trying just to run a simple request/response, here is the simplified version of my code, just config, and trx usage

Related