SPI communication with Lis3dh sensor (nrfConnect SDK)

Hello,

I'm encountering an issue while configuring the SPI bus to communicate with a LIS3DH sensor using nrf52832. I'm working with Visual Studio Code using nrfConnect SDK (Zephyr).

Here's the Device Tree Source (DTS):

// Copyright (c) 2024 Nordic Semiconductor ASA
// SPDX-License-Identifier: Apache-2.0

/dts-v1/;
#include <nordic/nrf52832_qfaa.dtsi>

/ {
    model = "xxx";
    compatible = "xxx";

    aliases {
        led0 = &led0;
        led1 = &led1;
        led2 = &led2;
    };

    chosen {
        zephyr,sram = &sram0;
        zephyr,flash = &flash0;
        zephyr,code-partition = &slot0_partition;
    };

    leds{
        compatible = "gpio-leds";
        led0: led_0{
            gpios = <&gpio0 10 GPIO_ACTIVE_LOW>;
            label = "Blue LED 0";
        };
        led1: led_1{
            gpios = <&gpio0 9 GPIO_ACTIVE_LOW>;
            label = "Green LED 1";
        };
        led2: led_2{
            gpios = <&gpio0 8 GPIO_ACTIVE_LOW>;
            label = "Red LED 2";
        };
    };
};

&flash0 {
    partitions {
        compatible = "fixed-partitions";
        #address-cells = <1>;
        #size-cells = <1>;

        boot_partition: partition@0 {
            label = "mcuboot";
            reg = <0x0 0xc000>;
        };
        slot0_partition: partition@c000 {
            label = "image-0";
            reg = <0xc000 0x32000>;
        };
        slot1_partition: partition@3e000 {
            label = "image-1";
            reg = <0x3e000 0x32000>;
        };
        scratch_partition: partition@70000 {
            label = "image-scratch";
            reg = <0x70000 0xa000>;
        };
        storage_partition: partition@7a000 {
            label = "storage";
            reg = <0x7a000 0x6000>;
        };
    };
};


&gpio0 {
    status = "okay";
};

&gpiote {
    status = "okay";
};



lis3dh_spi_master: &spi0 {
    compatible = "nordic,nrf-spi";
    status = "okay";
    pinctrl-0 = <&spi0_default>;
    pinctrl-1 = <&spi0_sleep>;
    pinctrl-names = "default","sleep";
    cs-gpios = <&gpio0 18 GPIO_ACTIVE_LOW>;
   
    reg_lis3dh: lis3dh@0{
        compatible = "st,lis2dh";
        reg = <0>;
        irq-gpios = <&gpio0 16 GPIO_ACTIVE_HIGH>, <&gpio0 17 GPIO_ACTIVE_HIGH>;
        spi-max-frequency = <8000000>;
    };
};

&pinctrl {
    spi0_default: spi0_default {
        group1 {
            psels = <NRF_PSEL(SPIM_SCK, 0, 15)>,
                    <NRF_PSEL(SPIM_MOSI, 0, 20)>,
                    <NRF_PSEL(SPIM_MISO, 0, 19)>;

        };
    };
    spi0_sleep: spi0_sleep {
        group1 {
            psels = <NRF_PSEL(SPIM_SCK, 0, 15)>,
                    <NRF_PSEL(SPIM_MOSI, 0, 20)>,
                    <NRF_PSEL(SPIM_MISO, 0, 19)>;
            low-power-enable;
        };  

    };
};



The spi_file is : 

#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/spi.h>

#define LIS3DH_OUT_X_L                  0x28
#define LIS3DH_OUT_X_H                  0x29


#define LIS3DH_SPI_MASTER DT_NODELABEL(lis3dh_spi_master)

// SPI master functionality
const struct device *spi_dev;

struct spi_cs_control spim_cs = {
    .gpio = SPI_CS_GPIOS_DT_SPEC_GET(DT_NODELABEL(reg_lis3dh)),
    .delay = 0,
};


static const struct spi_config spi_cfg = {
    .operation = SPI_OP_MODE_MASTER | SPI_WORD_SET(8) | SPI_TRANSFER_MSB,
    .frequency = 8000000,
    .slave = 0,
    .cs = &spim_cs,
};

void spi_init(void)
{
    spi_dev = DEVICE_DT_GET(LIS3DH_SPI_MASTER);
    if(!device_is_ready(spi_dev)) {
        printk("SPI master device not ready!\n");
    }
    if(!device_is_ready(spim_cs.gpio.port)){
        printk("SPI master chip select device not ready!\n");
    }
}

uint8_t test_spi(void)
{
    int err;
    static uint8_t tx_buf[1];
    static uint8_t rx_buf[1];

    const struct spi_buf_set tx = {
        .buffers = &tx_buf,
        .count = 1
    };
    const struct spi_buf_set rx = {
        .buffers = &rx_buf,
        .count = 1
    };

    tx_buf[0] = LIS3DH_OUT_X_L;
    err = spi_transceive(spi_dev, &spi_cfg, &tx, &rx);
    if (err < 0) {
        printk("spi_transceive_dt() failed, err: %d", err);
        return err;
    }
    printk("\nTx data : %d, Tx data : %d",tx_buf[0], rx_buf[0]);
}

And the main calls spi_init() and test_spi().

I'm encountering this error during spi_transceive() function :

Bluetooth initialized
Advertising successfully started
BEACON START
[00:00:01.005,676] <err> os: ***** Reserved Exception ( -16) *****
[00:00:01.005,706] <err> os: r0/a1: 0x20006f00 r1/a2: 0x00016a0d r2/a3: 0x0002e2bf
[00:00:01.005,706] <err> os: r3/a4: 0x000169f9 r12/ip: 0x000169f9 r14/lr: 0x000169f9
[00:00:01.005,737] <err> os: xpsr: 0x00000000
[00:00:01.005,737] <err> os: s[ 0]: 0x00000000 s[ 1]: 0x00000000 s[ 2]: 0x00000000 s[ 3]: 0x00016c09
[00:00:01.005,767] <err> os: s[ 4]: 0x000169f9 s[ 5]: 0x00000000 s[ 6]: 0x00016b69 s[ 7]: 0x000169f9
[00:00:01.005,767] <err> os: s[ 8]: 0x00016f15 s[ 9]: 0x00031ed3 s[10]: 0x00016f15 s[11]: 0x00016f15
[00:00:01.005,798] <err> os: s[12]: 0x00016f15 s[13]: 0x00016f15 s[14]: 0x00016f15 s[15]: 0x00016f15
[00:00:01.005,798] <err> os: fpscr: 0x00031e89
[00:00:01.005,798] <err> os: Faulting instruction address (r15/pc): 0x000169f9
[00:00:01.005,859] <err> os: >>> ZEPHYR FATAL ERROR 0: CPU exception on CPU 0
[00:00:01.005,889] <err> os: Current thread: 0x20003030 (unknown)
[00:00:01.391,052] <err> fatal_error: Resetting system

Thank for you help

Parents
  • Hello, 

    Thanks, i don't have issue for the compilation with this code:

    /*
     * Copyright (c) 2016 Intel Corporation
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    #include <zephyr/kernel.h>
    #include <zephyr/device.h>
    #include <zephyr/devicetree.h>
    #include <zephyr/drivers/gpio.h>
    #include <zephyr/drivers/spi.h>
    
    /* 1000 msec = 1 sec */
    #define SLEEP_TIME_MS   1000
    
    #define LIS3DH_OUT_X_L                  0x28
    #define LIS3DH_OUT_X_H                  0x29
    
    #define MY_SPI_MASTER DT_NODELABEL(lis3dh_spi_master)
    #define MY_SPI_MASTER_CS_DT_SPEC SPI_CS_GPIOS_DT_SPEC_GET(DT_NODELABEL(reg_lis3dh_master))
    
    // SPI master functionality
    const struct device *spi_dev;
    static struct k_poll_signal spi_done_sig = K_POLL_SIGNAL_INITIALIZER(spi_done_sig);
    
    static void spi_init(void)
    {
        spi_dev = DEVICE_DT_GET(MY_SPI_MASTER);
        if(!device_is_ready(spi_dev)) {
            printk("SPI master device not ready!\n");
        }
        struct gpio_dt_spec spim_cs_gpio = MY_SPI_MASTER_CS_DT_SPEC;
        if(!device_is_ready(spim_cs_gpio.port)){
            printk("SPI master chip select device not ready!\n");
        }
    }
    
    static struct spi_config spi_cfg = {
        .operation = SPI_WORD_SET(8) | SPI_TRANSFER_MSB | SPI_MODE_CPOL | SPI_MODE_CPHA,
        .frequency = 8000000,
        .slave = 0,
        .cs = {.gpio = MY_SPI_MASTER_CS_DT_SPEC, .delay = 0},
    };
    
    static int spi_write_test_msg(void)
    {
        static uint8_t counter = 0;
        static uint8_t tx_buffer[2];
        static uint8_t rx_buffer[2];
    
        const struct spi_buf tx_buf = {
            .buf = tx_buffer,
            .len = sizeof(tx_buffer)
        };
        const struct spi_buf_set tx = {
            .buffers = &tx_buf,
            .count = 1
        };
    
        struct spi_buf rx_buf = {
            .buf = rx_buffer,
            .len = sizeof(rx_buffer),
        };
        const struct spi_buf_set rx = {
            .buffers = &rx_buf,
            .count = 1
        };
    
        // Update the TX buffer with a rolling counter
        tx_buffer[0] = LIS3DH_OUT_X_L;
        printk("SPI TX: 0x%.2x, 0x%.2x\n", tx_buffer[0], tx_buffer[1]);
    
        // Reset signal
        k_poll_signal_reset(&spi_done_sig);
       
        // Start transaction
        int error = spi_transceive_signal(spi_dev, &spi_cfg, &tx, &rx, &spi_done_sig);
        if(error != 0){
            printk("SPI transceive error: %i\n", error);
            return error;
        }
    
        // Wait for the done signal to be raised and log the rx buffer
        int spi_signaled, spi_result;
        do{
            k_poll_signal_check(&spi_done_sig, &spi_signaled, &spi_result);
        } while(spi_signaled == 0);
        printk("SPI RX: 0x%.2x, 0x%.2x\n", rx_buffer[0], rx_buffer[1]);
        return 0;
    }
    
    
    int test_spi(void)
    {
        int ret;
    
        spi_init();
    
        printk("\n SPI master example started\n");
    
            while (1) {
            spi_write_test_msg();
            if (ret < 0) {
                return 0;
            }
            k_msleep(SLEEP_TIME_MS);
        }
    
        return 0;
    }
    
    

    But I only received 0xFF on the RX SPI buffer. 

    My tag works with nrf5_sdk with Segger and we would like to use Visual Studio Code to use Edge Impulse. (i need to get the accelerometer data to feed the ML.)

    I don't see anything with the PicoScope. Do you have some idea ? The DTS seem good ... 

    Best regards, 

    EDIT by Helsing: Embedding code using Insert->Code for readability.

  • Hi Guillaume,

    Guillaume said:
    I don't see anything with the PicoScope.

    Are you not seeing any communication at all?

    Would you be alble to share the .dts file? Or a snippet of your code demonstrating this?

    Best regards,

    HĂĄkon

  • Hi Helsing, 

    Yes of course. Here the .dts file : 

    // Copyright (c) 2024 Nordic Semiconductor ASA
    // SPDX-License-Identifier: Apache-2.0
    
    /dts-v1/;
    #include <nordic/nrf52832_qfaa.dtsi>
    
    / {
    	model = "xxx";
    	compatible = "xxx,xxx";
    
    	aliases {
    		led0 = &led0;
    		led1 = &led1;
    		led2 = &led2;
    	};
    
    	chosen {
    		zephyr,sram = &sram0;
    		zephyr,flash = &flash0;
    		zephyr,code-partition = &slot0_partition;
    	};
    
    	leds{
    		compatible = "gpio-leds"; 
    		led0: led_0{
    			gpios = <&gpio0 10 GPIO_ACTIVE_LOW>;
    			label = "Blue LED 0"; 
    	    };
    		led1: led_1{
    			gpios = <&gpio0 9 GPIO_ACTIVE_LOW>;
    			label = "Green LED 1"; 
    	    };
    		led2: led_2{
    			gpios = <&gpio0 8 GPIO_ACTIVE_LOW>;
    			label = "Red LED 2"; 
    	    };
    	};
    };
    
    &flash0 {
    	partitions {
    		compatible = "fixed-partitions";
    		#address-cells = <1>;
    		#size-cells = <1>;
    
    		boot_partition: partition@0 {
    			label = "mcuboot";
    			reg = <0x0 0xc000>;
    		};
    		slot0_partition: partition@c000 {
    			label = "image-0";
    			reg = <0xc000 0x32000>;
    		};
    		slot1_partition: partition@3e000 {
    			label = "image-1";
    			reg = <0x3e000 0x32000>;
    		};
    		scratch_partition: partition@70000 {
    			label = "image-scratch";
    			reg = <0x70000 0xa000>;
    		};
    		storage_partition: partition@7a000 {
    			label = "storage";
    			reg = <0x7a000 0x6000>;
    		};
    	};
    };
    
    
    &gpio0 {
    	status = "okay";
    };
    
    &gpiote {
        status = "okay";
    };
    
    
    &pinctrl {
    	spi_master_default: spi_master_default {
    		group1 {
                psels = <NRF_PSEL(SPIM_SCK, 0, 15)>,
    					<NRF_PSEL(SPIM_MOSI, 0, 20)>,
    					<NRF_PSEL(SPIM_MISO, 0, 19)>;
    		};
    	};
    
    	spi_master_sleep: spi_master_sleep {
    		group1 {
                psels = <NRF_PSEL(SPIM_SCK, 0, 15)>,
    					<NRF_PSEL(SPIM_MOSI, 0, 20)>,
    					<NRF_PSEL(SPIM_MISO, 0, 19)>;
    			low-power-enable;
    		};
    	};
    };
    
    lis3dh_spi_master: &spi1 {
    	compatible = "nordic,nrf-spi";
        status = "okay";
    	pinctrl-0 = <&spi_master_default>;
    	pinctrl-1 = <&spi_master_sleep>;
        pinctrl-names = "default","sleep";
        cs-gpios = <&gpio0 18 GPIO_ACTIVE_LOW>;
        
        reg_lis3dh_master: lis3dh@0{
            compatible = "st,lis2dh";
            reg = <0>;
            irq-gpios = <&gpio0 16 GPIO_ACTIVE_HIGH>, <&gpio0 17 GPIO_ACTIVE_HIGH>;
            spi-max-frequency = <4000000>;
        };
    };

    And here the spi file : 

    /*
     * Copyright (c) 2016 Intel Corporation
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    #include <zephyr/kernel.h>
    #include <zephyr/device.h>
    #include <zephyr/devicetree.h>
    #include <zephyr/drivers/gpio.h>
    #include <zephyr/drivers/spi.h>
    
    /* 1000 msec = 1 sec */
    #define SLEEP_TIME_MS   1000
    
    #define LIS3DH_OUT_X_L                  0x28
    #define LIS3DH_OUT_X_H                  0x29
    
    #define MY_SPI_MASTER DT_NODELABEL(lis3dh_spi_master)
    #define MY_SPI_MASTER_CS_DT_SPEC SPI_CS_GPIOS_DT_SPEC_GET(DT_NODELABEL(reg_lis3dh_master))
    
    // SPI master functionality
    const struct device *spi_dev;
    static struct k_poll_signal spi_done_sig = K_POLL_SIGNAL_INITIALIZER(spi_done_sig);
    
    static void spi_init(void)
    {
    	spi_dev = DEVICE_DT_GET(MY_SPI_MASTER);
    	if(!device_is_ready(spi_dev)) {
    		printk("SPI master device not ready!\n");
    	}
    	struct gpio_dt_spec spim_cs_gpio = MY_SPI_MASTER_CS_DT_SPEC;
    	if(!device_is_ready(spim_cs_gpio.port)){
    		printk("SPI master chip select device not ready!\n");
    	}
    }
    
    static struct spi_config spi_cfg = {
    	.operation = SPI_WORD_SET(8) | SPI_TRANSFER_MSB | SPI_MODE_CPOL | SPI_MODE_CPHA,
    	.frequency = 8000000,
    	.slave = 0,
    	.cs = {.gpio = MY_SPI_MASTER_CS_DT_SPEC, .delay = 0},
    };
    
    static int spi_write_test_msg(void)
    {
    	static uint8_t counter = 0;
    	static uint8_t tx_buffer[2];
    	static uint8_t rx_buffer[2];
    
    	const struct spi_buf tx_buf = {
    		.buf = tx_buffer,
    		.len = sizeof(tx_buffer)
    	};
    	const struct spi_buf_set tx = {
    		.buffers = &tx_buf,
    		.count = 1
    	};
    
    	struct spi_buf rx_buf = {
    		.buf = rx_buffer,
    		.len = sizeof(rx_buffer),
    	};
    	const struct spi_buf_set rx = {
    		.buffers = &rx_buf,
    		.count = 1
    	};
    
    	// Update the TX buffer with a rolling counter
    	tx_buffer[0] = LIS3DH_OUT_X_L ;
    	printk("SPI TX: 0x%.2x, 0x%.2x\n", tx_buffer[0], tx_buffer[1]);
    
    	// Reset signal
    	k_poll_signal_reset(&spi_done_sig);
    	
    	// Start transaction
    	int error = spi_transceive_signal(spi_dev, &spi_cfg, &tx, &rx, &spi_done_sig);
    	if(error != 0){
    		printk("SPI transceive error: %i\n", error);
    		return error;
    	}
    
    	// Wait for the done signal to be raised and log the rx buffer
    	int spi_signaled, spi_result;
    	do{
    		k_poll_signal_check(&spi_done_sig, &spi_signaled, &spi_result);
    	} while(spi_signaled == 0);
    	printk("SPI RX: 0x%.2x, 0x%.2x\n", rx_buffer[0], rx_buffer[1]);
    	return 0;
    }
    
    
    int test_spi(void)
    {
    	int ret;
    
    	spi_init();
    
    	printk("\n SPI master example started\n");
    
    		while (1) {
    		spi_write_test_msg();
    		if (ret < 0) {
    			return 0;
    		}
    		k_msleep(SLEEP_TIME_MS);
    	}
    
    	return 0;
    }

    For information, I'm using Nrf52832, with lis3dh on SPI communication. It works on SDK5.

    Guillaume

  • Hi Guillaume, here are some things to try:

    • The frequency in spi_cfg is set to 8000000 (8 MHz), whereas in the device tree it is set to 4000000 (4 MHz) in the spi-max-frequency for the lis3dh@0 node. Try to make these two match and see if it improves anything.
    • Check the return value of spi_transceive(): The spi_transceive() function returns a negative error code if there's a problem with the SPI transfer. You can check this return value to get more information about the error.
    • Could you try to set the PicoScope to analog and record the output from the SPI pins? Are you not seeing any signals changing/toggeling at all?
    • Ensure the SPI driver for NRF52832 is enabled in your prj.conf file with CONFIG_SPI=y.

    Which nRF Connect SDK version are you using?

Reply
  • Hi Guillaume, here are some things to try:

    • The frequency in spi_cfg is set to 8000000 (8 MHz), whereas in the device tree it is set to 4000000 (4 MHz) in the spi-max-frequency for the lis3dh@0 node. Try to make these two match and see if it improves anything.
    • Check the return value of spi_transceive(): The spi_transceive() function returns a negative error code if there's a problem with the SPI transfer. You can check this return value to get more information about the error.
    • Could you try to set the PicoScope to analog and record the output from the SPI pins? Are you not seeing any signals changing/toggeling at all?
    • Ensure the SPI driver for NRF52832 is enabled in your prj.conf file with CONFIG_SPI=y.

    Which nRF Connect SDK version are you using?

Children
No Data
Related